CUBRID Engine  latest
query_executor.c
Go to the documentation of this file.
1 /*
2  * Copyright 2008 Search Solution Corporation
3  * Copyright 2016 CUBRID Corporation
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */
18 
19 /*
20  * query_executor.c - Query evaluator module
21  */
22 
23 #ident "$Id$"
24 
25 
26 #include "config.h"
27 
28 #include <stdio.h>
29 #include <string.h>
30 #include <math.h>
31 #include <search.h>
32 #include <sys/timeb.h>
33 
34 #include "query_executor.h"
35 
36 #include "binaryheap.h"
37 #include "porting.h"
38 #include "error_manager.h"
39 #include "partition_sr.h"
40 #include "query_aggregate.hpp"
41 #include "query_analytic.hpp"
42 #include "query_opfunc.h"
43 #include "fetch.h"
44 #include "dbtype.h"
45 #include "object_primitive.h"
46 #include "object_representation.h"
47 #include "list_file.h"
48 #include "extendible_hash.h"
49 #include "xasl_cache.h"
50 #include "stream_to_xasl.h"
51 #include "query_manager.h"
52 #include "query_reevaluation.hpp"
53 #include "extendible_hash.h"
54 #include "replication.h"
55 #include "elo.h"
56 #include "db_elo.h"
57 #include "locator_sr.h"
58 #include "log_lsa.hpp"
59 #include "log_volids.hpp"
60 #include "xserver_interface.h"
61 #include "tz_support.h"
62 #include "session.h"
63 #include "tz_support.h"
64 #include "db_date.h"
65 #include "btree_load.h"
66 #include "query_dump.h"
67 #if defined (SERVER_MODE)
68 #include "jansson.h"
69 #endif /* defined (SERVER_MODE) */
70 #if defined(ENABLE_SYSTEMTAP)
71 #include "probes.h"
72 #endif /* ENABLE_SYSTEMTAP */
73 #include "db_json.hpp"
74 #include "dbtype.h"
75 #include "string_regex.hpp"
76 #include "thread_entry.hpp"
77 #include "regu_var.hpp"
78 #include "xasl.h"
79 #include "xasl_aggregate.hpp"
80 #include "xasl_analytic.hpp"
81 #include "xasl_predicate.hpp"
82 
83 #include <vector>
84 
85 // XASL_STATE
86 typedef struct xasl_state XASL_STATE;
87 struct xasl_state
88 {
89  VAL_DESCR vd; /* Value Descriptor */
90  QUERY_ID query_id; /* Query associated with XASL */
91  int qp_xasl_line; /* Error line */
92 };
93 
94 #define GOTO_EXIT_ON_ERROR \
95  do \
96  { \
97  qexec_failure_line (__LINE__, xasl_state); \
98  goto exit_on_error; \
99  } \
100  while (0)
101 
102 /* Page buffer int keep free ratios: for the cases of
103  * client/server - minimal page buffer pool
104  * client/server - large page buffer pool
105  * standalone - minimal page buffer pool
106  * standalone - large page buffer pool
107  * respectively,
108  */
109 
110 /* Keep the scans grouped only for that many classes scans for join queries.*/
111 #define QPROC_MAX_GROUPED_SCAN_CNT (4)
112 
113 /* if 1, single class query scans are done in a grouped manner. */
114 #define QPROC_SINGLE_CLASS_GROUPED_SCAN (0)
115 
116 /* used for tuple string id */
117 #define CONNECTBY_TUPLE_INDEX_STRING_MEM 64
118 
119 /* default number of hash entries */
120 #define HASH_AGGREGATE_DEFAULT_TABLE_SIZE 1000
121 
122 /* minimum amount of tuples that have to be hashed before deciding if
123  selectivity is very high */
124 #define HASH_AGGREGATE_VH_SELECTIVITY_TUPLE_THRESHOLD 200
125 
126 /* maximum selectivity allowed for hash aggregate evaluation */
127 #define HASH_AGGREGATE_VH_SELECTIVITY_THRESHOLD 0.5f
128 
129 
130 #define QEXEC_CLEAR_AGG_LIST_VALUE(agg_list) \
131  do \
132  { \
133  AGGREGATE_TYPE *agg_ptr; \
134  for (agg_ptr = (agg_list); agg_ptr; agg_ptr = agg_ptr->next) \
135  { \
136  if (agg_ptr->function == PT_GROUPBY_NUM) \
137  continue; \
138  pr_clear_value (agg_ptr->accumulator.value); \
139  } \
140  } \
141  while (0)
142 
143 #define QEXEC_EMPTY_ACCESS_SPEC_SCAN(specp) \
144  ((specp)->type == TARGET_CLASS \
145  && ((ACCESS_SPEC_HFID((specp)).vfid.fileid == NULL_FILEID || ACCESS_SPEC_HFID((specp)).vfid.volid == NULL_VOLID)))
146 
147 #define QEXEC_IS_MULTI_TABLE_UPDATE_DELETE(xasl) \
148  (xasl->upd_del_class_cnt > 1 || (xasl->upd_del_class_cnt == 1 && xasl->scan_ptr != NULL))
149 
150 #define QEXEC_SEL_UPD_USE_REEVALUATION(xasl) \
151  ((xasl) && ((xasl)->spec_list) && ((xasl)->spec_list->next == NULL) \
152  && ((xasl)->spec_list->pruning_type == DB_NOT_PARTITIONED_CLASS) \
153  && ((xasl)->aptr_list == NULL) && ((xasl)->scan_ptr == NULL))
154 
155 #if 0
156 /* Note: the following macro is used just for replacement of a repetitive
157  * text in order to improve the readability.
158  */
159 
160 #if !defined(SERVER_MODE)
161 #define pthread_mutex_init(a, b)
162 #define pthread_mutex_destroy(a)
163 #define pthread_mutex_lock(a) 0
164 #define pthread_mutex_unlock(a)
165 #endif
166 #endif
167 
168 /* XASL scan block function */
170 
171 /* pointer to XASL scan function */
173 
175 {
181 };
183 
186 {
187  GROUPBY_DIMENSION_FLAG d_flag; /* dimension info */
188  AGGREGATE_TYPE *d_agg_list; /* aggregation colunms list */
189 };
190 
193 {
194  int state;
195 
198 #if 0 /* SortCache */
199  VPID fixed_vpid; /* current fixed page info of */
200  PAGE_PTR fixed_page; /* input list file */
201 #endif
203 
216 
222 
224  GROUPBY_DIMENSION *g_dim; /* dimensions for Data Cube */
225  int g_dim_levels; /* dimensions size */
226 
228 
230 
234 };
235 
238 {
241 
242  /* result list files */
243  QFILE_LIST_ID *group_list_id; /* file containing group headers */
244  QFILE_LIST_ID *value_list_id; /* file containing group values */
245  QFILE_LIST_SCAN_ID group_scan_id; /* scan on group_list_id */
246  QFILE_LIST_SCAN_ID value_scan_id; /* scan on value_list_id */
247 
250 
251  DB_VALUE cgtc_dbval; /* linked to curr_group_tuple_count */
252  DB_VALUE cgtc_nn_dbval; /* linked to curr_group_tuple_count_nn */
253  DB_VALUE csktc_dbval; /* linked to curr_sort_key_tuple_count */
254  int curr_group_tuple_count; /* tuples in current group */
255  int curr_group_tuple_count_nn; /* tuples in current group with non-NULL values */
256  int curr_sort_key_tuple_count; /* tuples sharing current sort key */
257 
258  int group_tuple_position; /* position of value_scan_id in current group */
259  int group_tuple_position_nn; /* position of value_scan_id in current group, ignoring NULL values */
260  int sort_key_tuple_position; /* position of value_scan_id in current sort key */
261 
262  int group_consumed_tuples; /* number of consumed tuples from current group */
263 };
264 
267 {
268  int state;
270 
273 
276 
281 
286 
290 
291  struct
292  {
295  } curr_sort_page;
296 
298 
301 };
302 
303 /*
304  * Information required for processing the ORDBY_NUM() function. See
305  * qexec_eval_ordbynum_pred ().
306  */
309 {
316  int reserved[2];
317 };
318 
319 /* parent pos info stack */
322 {
325 };
326 
327 /* used for deleting lob files */
328 typedef struct del_lob_info DEL_LOB_INFO;
330 {
331  OID *class_oid; /* OID of the class that has lob attributes */
332  HFID *class_hfid; /* class hfid */
333 
334  HEAP_CACHE_ATTRINFO attr_info; /* attribute cache info */
335 
336  DEL_LOB_INFO *next; /* next DEL_LOB_INFO in a list */
337 };
338 
339 /* used for internal update/delete execution */
342 {
343  int subclass_idx; /* active subclass index */
344  OID *oid; /* instance oid of current class */
345  OID *class_oid; /* oid of current class */
346  HFID *class_hfid; /* hfid of current class */
348 
349  OID prev_class_oid; /* previous class oid */
350  HEAP_CACHE_ATTRINFO attr_info; /* attribute cache info */
351  bool is_attr_info_inited; /* true if attr_info has valid data */
352  int needs_pruning; /* partition pruning information */
353  PRUNING_CONTEXT context; /* partition pruning context */
354  int num_lob_attrs; /* number of lob attributes */
355  int *lob_attr_ids; /* lob attribute ids */
356  DEL_LOB_INFO *crt_del_lob_info; /* DEL_LOB_INFO for current class_oid */
360  int extra_assign_reev_cnt; /* size of mvcc_extra_assign_reev in elements */
361  UPDDEL_MVCC_COND_REEVAL **mvcc_extra_assign_reev; /* classes in the select list that are referenced in
362  * assignments to the attributes of current class and are not
363  * referenced in conditions */
365 };
366 
368 {
371 };
373 
374 #define QEXEC_GET_BH_TOPN_TUPLE(heap, index) (*(TOPN_TUPLE **) BH_ELEMENT (heap, index))
375 
376 typedef enum
377 {
381 } TOPN_STATUS;
382 
384 static int qexec_add_composite_lock (THREAD_ENTRY * thread_p, REGU_VARIABLE_LIST reg_var_list, XASL_STATE * xasl_state,
385  LK_COMPOSITE_LOCK * composite_lock, int upd_del_cls_cnt, OID * default_cls_oid);
387  VALPTR_LIST * outptr_list, VAL_DESCR * vd);
389 static int qexec_end_one_iteration (THREAD_ENTRY * thread_p, XASL_NODE * xasl, XASL_STATE * xasl_state,
390  QFILE_TUPLE_RECORD * tplrec);
391 static void qexec_failure_line (int line, XASL_STATE * xasl_state);
392 static void qexec_reset_regu_variable (REGU_VARIABLE * var);
394 static void qexec_reset_pred_expr (PRED_EXPR * pred);
395 static int qexec_clear_xasl_head (THREAD_ENTRY * thread_p, XASL_NODE * xasl);
396 static int qexec_clear_arith_list (THREAD_ENTRY * thread_p, XASL_NODE * xasl_p, ARITH_TYPE * list, bool is_final);
397 static int qexec_clear_regu_var (THREAD_ENTRY * thread_p, XASL_NODE * xasl_p, REGU_VARIABLE * regu_var, bool is_final);
398 static int qexec_clear_regu_list (THREAD_ENTRY * thread_p, XASL_NODE * xasl_p, REGU_VARIABLE_LIST list, bool is_final);
399 static int qexec_clear_regu_value_list (THREAD_ENTRY * thread_p, XASL_NODE * xasl_p, REGU_VALUE_LIST * list,
400  bool is_final);
402 static void qexec_clear_sort_list (XASL_NODE * xasl_p, SORT_LIST * list, bool is_final);
403 static void qexec_clear_pos_desc (XASL_NODE * xasl_p, QFILE_TUPLE_VALUE_POSITION * position_descr, bool is_final);
404 static int qexec_clear_pred (THREAD_ENTRY * thread_p, XASL_NODE * xasl_p, PRED_EXPR * pr, bool is_final);
405 static int qexec_clear_access_spec_list (THREAD_ENTRY * thread_p, XASL_NODE * xasl_p, ACCESS_SPEC_TYPE * list,
406  bool is_final);
407 static int qexec_clear_analytic_function_list (THREAD_ENTRY * thread_p, XASL_NODE * xasl_p, ANALYTIC_EVAL_TYPE * list,
408  bool is_final);
409 static int qexec_clear_agg_list (THREAD_ENTRY * thread_p, XASL_NODE * xasl_p, AGGREGATE_TYPE * list, bool is_final);
410 static void qexec_clear_head_lists (THREAD_ENTRY * thread_p, XASL_NODE * xasl_list);
411 static void qexec_clear_scan_all_lists (THREAD_ENTRY * thread_p, XASL_NODE * xasl_list);
412 static void qexec_clear_all_lists (THREAD_ENTRY * thread_p, XASL_NODE * xasl_list);
413 static int qexec_clear_update_assignment (THREAD_ENTRY * thread_p, XASL_NODE * xasl_p, UPDATE_ASSIGNMENT * assignment,
414  bool is_final);
415 static DB_LOGICAL qexec_eval_ordbynum_pred (THREAD_ENTRY * thread_p, ORDBYNUM_INFO * ordby_info);
416 static int qexec_ordby_put_next (THREAD_ENTRY * thread_p, const RECDES * recdes, void *arg);
417 static int qexec_orderby_distinct (THREAD_ENTRY * thread_p, XASL_NODE * xasl, QUERY_OPTIONS option,
421 static DB_LOGICAL qexec_eval_grbynum_pred (THREAD_ENTRY * thread_p, GROUPBY_STATE * gbstate);
422 static GROUPBY_STATE *qexec_initialize_groupby_state (GROUPBY_STATE * gbstate, SORT_LIST * groupby_list,
423  PRED_EXPR * having_pred, PRED_EXPR * grbynum_pred,
424  DB_VALUE * grbynum_val, int grbynum_flag, XASL_NODE * eptr_list,
425  AGGREGATE_TYPE * g_agg_list, REGU_VARIABLE_LIST g_regu_list,
426  VAL_LIST * g_val_list, OUTPTR_LIST * g_outptr_list,
427  REGU_VARIABLE_LIST g_hk_regu_list, bool with_rollup,
428  int hash_eligible, AGGREGATE_HASH_CONTEXT * agg_hash_context,
429  XASL_NODE * xasl, XASL_STATE * xasl_state,
430  QFILE_TUPLE_VALUE_TYPE_LIST * type_list,
431  QFILE_TUPLE_RECORD * tplrec);
432 static void qexec_clear_groupby_state (THREAD_ENTRY * thread_p, GROUPBY_STATE * gbstate);
433 static int qexec_clear_agg_orderby_const_list (THREAD_ENTRY * thread_p, XASL_NODE * xasl, bool is_final);
434 static int qexec_gby_init_group_dim (GROUPBY_STATE * gbstate);
435 static void qexec_gby_clear_group_dim (THREAD_ENTRY * thread_p, GROUPBY_STATE * gbstate);
436 static void qexec_gby_agg_tuple (THREAD_ENTRY * thread_p, GROUPBY_STATE * gbstate, QFILE_TUPLE tpl, int peek);
437 static int qexec_hash_gby_agg_tuple (THREAD_ENTRY * thread_p, XASL_NODE * xasl, XASL_STATE * xasl_state,
438  BUILDLIST_PROC_NODE * proc, QFILE_TUPLE_RECORD * tplrec,
439  QFILE_TUPLE_DESCRIPTOR * tpldesc, QFILE_LIST_ID * groupby_list,
440  bool * output_tuple);
441 static void qexec_gby_start_group_dim (THREAD_ENTRY * thread_p, GROUPBY_STATE * gbstate, const RECDES * recdes);
442 static void qexec_gby_start_group (THREAD_ENTRY * thread_p, GROUPBY_STATE * gbstate, const RECDES * recdes, int N);
443 static void qexec_gby_finalize_group_val_list (THREAD_ENTRY * thread_p, GROUPBY_STATE * gbstate, int N);
444 static int qexec_gby_finalize_group_dim (THREAD_ENTRY * thread_p, GROUPBY_STATE * gbstate, const RECDES * recdes);
445 static void qexec_gby_finalize_group (THREAD_ENTRY * thread_p, GROUPBY_STATE * gbstate, int N, bool keep_list_file);
446 static SORT_STATUS qexec_hash_gby_get_next (THREAD_ENTRY * thread_p, RECDES * recdes, void *arg);
447 static int qexec_hash_gby_put_next (THREAD_ENTRY * thread_p, const RECDES * recdes, void *arg);
448 static SORT_STATUS qexec_gby_get_next (THREAD_ENTRY * thread_p, RECDES * recdes, void *arg);
449 static int qexec_gby_put_next (THREAD_ENTRY * thread_p, const RECDES * recdes, void *arg);
450 static int qexec_groupby (THREAD_ENTRY * thread_p, XASL_NODE * xasl, XASL_STATE * xasl_state,
451  QFILE_TUPLE_RECORD * tplrec);
452 static int qexec_groupby_index (THREAD_ENTRY * thread_p, XASL_NODE * xasl, XASL_STATE * xasl_state,
453  QFILE_TUPLE_RECORD * tplrec);
455  ANALYTIC_TYPE * func_p, XASL_STATE * xasl_state);
457  ANALYTIC_TYPE * a_func_list, SORT_LIST * sort_list,
458  REGU_VARIABLE_LIST a_regu_list, VAL_LIST * a_val_list,
459  OUTPTR_LIST * a_outptr_list, OUTPTR_LIST * a_outptr_list_interm,
460  bool is_last_run, XASL_NODE * xasl, XASL_STATE * xasl_state,
461  QFILE_TUPLE_VALUE_TYPE_LIST * type_list,
462  QFILE_TUPLE_RECORD * tplrec);
463 static SORT_STATUS qexec_analytic_get_next (THREAD_ENTRY * thread_p, RECDES * recdes, void *arg);
464 static int qexec_analytic_put_next (THREAD_ENTRY * thread_p, const RECDES * recdes, void *arg);
466  ANALYTIC_STAGE stage);
468  ANALYTIC_FUNCTION_STATE * func_state, const RECDES * key, bool reinit);
470  ANALYTIC_FUNCTION_STATE * func_state, bool is_same_group);
472  int peek);
473 static void qexec_clear_analytic_function_state (THREAD_ENTRY * thread_p, ANALYTIC_FUNCTION_STATE * func_state);
479  ANALYTIC_FUNCTION_STATE * func_state);
481 static int qexec_analytic_sort_key_header_load (ANALYTIC_FUNCTION_STATE * func_state, bool load_value);
482 static int qexec_analytic_value_advance (THREAD_ENTRY * thread_p, ANALYTIC_FUNCTION_STATE * func_state, int amount,
483  int max_group_changes, bool ignore_nulls);
484 static int qexec_analytic_value_lookup (THREAD_ENTRY * thread_p, ANALYTIC_FUNCTION_STATE * func_state, int position,
485  bool ignore_nulls);
486 static int qexec_analytic_group_header_next (THREAD_ENTRY * thread_p, ANALYTIC_FUNCTION_STATE * func_state);
488 static int qexec_collection_has_null (DB_VALUE * colval);
490  QFILE_TUPLE * rght_tval, TP_DOMAIN ** rght_dom, int tval_cnt);
491 static long qexec_size_remaining (QFILE_TUPLE_RECORD * tplrec1, QFILE_TUPLE_RECORD * tplrec2,
492  QFILE_LIST_MERGE_INFO * merge_info, int k);
493 static int qexec_merge_tuple (QFILE_TUPLE_RECORD * tplrec1, QFILE_TUPLE_RECORD * tplrec2,
494  QFILE_LIST_MERGE_INFO * merge_info, QFILE_TUPLE_RECORD * tplrec);
495 static int qexec_merge_tuple_add_list (THREAD_ENTRY * thread_p, QFILE_LIST_ID * list_id, QFILE_TUPLE_RECORD * tplrec1,
496  QFILE_TUPLE_RECORD * tplrec2, QFILE_LIST_MERGE_INFO * merge_info,
497  QFILE_TUPLE_RECORD * tplrec);
498 static QFILE_LIST_ID *qexec_merge_list (THREAD_ENTRY * thread_p, QFILE_LIST_ID * outer_list_idp,
499  QFILE_LIST_ID * inner_list_idp, QFILE_LIST_MERGE_INFO * merge_infop,
500  int ls_flag);
501 static QFILE_LIST_ID *qexec_merge_list_outer (THREAD_ENTRY * thread_p, SCAN_ID * outer_sid, SCAN_ID * inner_sid,
502  QFILE_LIST_MERGE_INFO * merge_infop, PRED_EXPR * other_outer_join_pred,
503  XASL_STATE * xasl_state, int ls_flag);
504 static int qexec_merge_listfiles (THREAD_ENTRY * thread_p, XASL_NODE * xasl, XASL_STATE * xasl_state);
505 static int qexec_open_scan (THREAD_ENTRY * thread_p, ACCESS_SPEC_TYPE * curr_spec, VAL_LIST * val_list, VAL_DESCR * vd,
506  bool force_select_lock, int fixed, int grouped, bool iscan_oid_order, SCAN_ID * s_id,
507  QUERY_ID query_id, SCAN_OPERATION_TYPE scan_op_type, bool scan_immediately_stop,
508  bool * p_mvcc_select_lock_needed);
509 static void qexec_close_scan (THREAD_ENTRY * thread_p, ACCESS_SPEC_TYPE * curr_spec);
510 static void qexec_end_scan (THREAD_ENTRY * thread_p, ACCESS_SPEC_TYPE * curr_spec);
512 static SCAN_CODE qexec_next_scan_block (THREAD_ENTRY * thread_p, XASL_NODE * xasl);
515  QFILE_TUPLE_RECORD * ignore, XASL_SCAN_FNC_PTR next_scan_fnc);
517  QFILE_TUPLE_RECORD * tplrec, XASL_SCAN_FNC_PTR next_scan_fnc);
519  QFILE_TUPLE_RECORD * tplrec, XASL_SCAN_FNC_PTR ignore);
520 static int qexec_setup_list_id (THREAD_ENTRY * thread_p, XASL_NODE * xasl);
521 static int qexec_init_upddel_ehash_files (THREAD_ENTRY * thread_p, XASL_NODE * buildlist);
522 static void qexec_destroy_upddel_ehash_files (THREAD_ENTRY * thread_p, XASL_NODE * buildlist);
523 static int qexec_execute_update (THREAD_ENTRY * thread_p, XASL_NODE * xasl, bool has_delete, XASL_STATE * xasl_state);
524 static int qexec_execute_delete (THREAD_ENTRY * thread_p, XASL_NODE * xasl, XASL_STATE * xasl_state);
525 static int qexec_execute_insert (THREAD_ENTRY * thread_p, XASL_NODE * xasl, XASL_STATE * xasl_state, bool skip_aptr);
526 static int qexec_execute_merge (THREAD_ENTRY * thread_p, XASL_NODE * xasl, XASL_STATE * xasl_state);
527 static int qexec_execute_build_indexes (THREAD_ENTRY * thread_p, XASL_NODE * xasl, XASL_STATE * xasl_state);
528 static int qexec_execute_obj_fetch (THREAD_ENTRY * thread_p, XASL_NODE * xasl, XASL_STATE * xasl_state,
529  SCAN_OPERATION_TYPE scan_operation_type);
530 static int qexec_execute_increment (THREAD_ENTRY * thread_p, const OID * oid, const OID * class_oid,
531  const HFID * class_hfid, ATTR_ID attrid, int n_increment, int pruning_type);
532 static int qexec_execute_selupd_list (THREAD_ENTRY * thread_p, XASL_NODE * xasl, XASL_STATE * xasl_state);
533 static int qexec_execute_selupd_list_find_class (THREAD_ENTRY * thread_p, XASL_NODE * xasl, VAL_DESCR * vd, OID * oid,
534  SELUPD_LIST * selupd, OID * class_oid, HFID * class_hfid,
535  DB_CLASS_PARTITION_TYPE * needs_pruning, bool * found);
536 static int qexec_start_connect_by_lists (THREAD_ENTRY * thread_p, XASL_NODE * xasl, XASL_STATE * xasl_state);
538  QFILE_TUPLE_RECORD * tplrec);
539 static void qexec_end_connect_by_lists (THREAD_ENTRY * thread_p, XASL_NODE * xasl);
540 static void qexec_clear_connect_by_lists (THREAD_ENTRY * thread_p, XASL_NODE * xasl);
541 static int qexec_execute_connect_by (THREAD_ENTRY * thread_p, XASL_NODE * xasl, XASL_STATE * xasl_state,
542  QFILE_TUPLE_RECORD * tplrec);
544  QFILE_TUPLE_RECORD * tplrec);
545 static int qexec_check_for_cycle (THREAD_ENTRY * thread_p, OUTPTR_LIST * outptr_list, QFILE_TUPLE tpl,
546  QFILE_TUPLE_VALUE_TYPE_LIST * type_list, QFILE_LIST_ID * list_id_p, int *iscycle);
547 static int qexec_compare_valptr_with_tuple (OUTPTR_LIST * outptr_list, QFILE_TUPLE tpl,
548  QFILE_TUPLE_VALUE_TYPE_LIST * type_list, int *are_equal);
549 static int qexec_listfile_orderby (THREAD_ENTRY * thread_p, XASL_NODE * xasl, QFILE_LIST_ID * list_file,
550  SORT_LIST * orderby_list, XASL_STATE * xasl_state, OUTPTR_LIST * outptr_list);
552  QFILE_TUPLE_RECORD * tplrec);
554  QFILE_TUPLE_RECORD * tplrec);
555 static void qexec_clear_mainblock_iterations (THREAD_ENTRY * thread_p, XASL_NODE * xasl);
556 static int qexec_execute_analytic (THREAD_ENTRY * thread_p, XASL_NODE * xasl, XASL_STATE * xasl_state,
557  ANALYTIC_EVAL_TYPE * analytic_eval, QFILE_TUPLE_RECORD * tplrec, bool is_last);
559  const HEAP_SCANCACHE * scan_cache);
560 static int qexec_prune_spec (THREAD_ENTRY * thread_p, ACCESS_SPEC_TYPE * spec, VAL_DESCR * vd,
561  SCAN_OPERATION_TYPE scan_op_type);
562 static int qexec_process_partition_unique_stats (THREAD_ENTRY * thread_p, PRUNING_CONTEXT * pcontext);
563 static int qexec_process_unique_stats (THREAD_ENTRY * thread_p, const OID * class_oid,
564  UPDDEL_CLASS_INFO_INTERNAL * class_);
566 
567 static int qexec_check_limit_clause (THREAD_ENTRY * thread_p, XASL_NODE * xasl, XASL_STATE * xasl_state,
568  bool * empty_result);
570  UPDDEL_CLASS_INSTANCE_LOCK_INFO * p_class_instance_lock_info);
572  UPDDEL_CLASS_INFO_INTERNAL * class_info);
574  UPDDEL_CLASS_INFO_INTERNAL * class_info,
575  DEL_LOB_INFO ** del_lob_info_list_ptr);
576 static void qexec_free_delete_lob_info_list (THREAD_ENTRY * thread_p, DEL_LOB_INFO ** del_lob_info_list_ptr);
577 static const char *qexec_schema_get_type_name_from_id (DB_TYPE id);
578 static int qexec_schema_get_type_desc (DB_TYPE id, TP_DOMAIN * domain, DB_VALUE * result);
579 static int qexec_execute_build_columns (THREAD_ENTRY * thread_p, XASL_NODE * xasl, XASL_STATE * xasl_state);
580 static int qexec_execute_cte (THREAD_ENTRY * thread_p, XASL_NODE * xasl, XASL_STATE * xasl_state);
581 
582 #if defined(SERVER_MODE)
583 #if defined (ENABLE_UNUSED_FUNCTION)
584 static int tranid_compare (const void *t1, const void *t2); /* TODO: put to header ?? */
585 #endif
586 #endif
587 static REGU_VARIABLE *replace_null_arith (REGU_VARIABLE * regu_var, DB_VALUE * set_dbval);
588 static REGU_VARIABLE *replace_null_dbval (REGU_VARIABLE * regu_var, DB_VALUE * set_dbval);
589 static void qexec_replace_prior_regu_vars (THREAD_ENTRY * thread_p, REGU_VARIABLE * regu, XASL_NODE * xasl);
590 static void qexec_replace_prior_regu_vars_pred (THREAD_ENTRY * thread_p, PRED_EXPR * pred, XASL_NODE * xasl);
591 static int qexec_init_index_pseudocolumn_strings (THREAD_ENTRY * thread_p, char **father_index, int *len_father_index,
592  char **son_index, int *len_son_index);
593 static int qexec_set_pseudocolumns_val_pointers (XASL_NODE * xasl, DB_VALUE ** level_valp, DB_VALUE ** isleaf_valp,
594  DB_VALUE ** iscycle_valp, DB_VALUE ** parent_pos_valp,
595  DB_VALUE ** index_valp);
596 static void qexec_reset_pseudocolumns_val_pointers (DB_VALUE * level_valp, DB_VALUE * isleaf_valp,
597  DB_VALUE * iscycle_valp, DB_VALUE * parent_pos_valp,
598  DB_VALUE * index_valp);
600  DB_VALUE ** index_valp, char **index_value, int *index_len);
601 static int qexec_recalc_tuples_parent_pos_in_list (THREAD_ENTRY * thread_p, QFILE_LIST_ID * list_id_p);
602 static int qexec_remove_duplicates_for_replace (THREAD_ENTRY * thread_p, HEAP_SCANCACHE * scan_cache,
603  HEAP_CACHE_ATTRINFO * attr_info, HEAP_CACHE_ATTRINFO * index_attr_info,
604  const HEAP_IDX_ELEMENTS_INFO * idx_info, int op_type, int pruning_type,
605  PRUNING_CONTEXT * pcontext, int *removed_count);
606 static int qexec_oid_of_duplicate_key_update (THREAD_ENTRY * thread_p, HEAP_SCANCACHE ** pruned_partition_scan_cache,
607  HEAP_SCANCACHE * scan_cache, HEAP_CACHE_ATTRINFO * attr_info,
608  HEAP_CACHE_ATTRINFO * index_attr_info,
609  const HEAP_IDX_ELEMENTS_INFO * idx_info, int needs_pruning,
610  PRUNING_CONTEXT * pcontext, OID * unique_oid, int op_type);
611 static int qexec_execute_duplicate_key_update (THREAD_ENTRY * thread_p, ODKU_INFO * odku, HFID * hfid, VAL_DESCR * vd,
612  int op_type, HEAP_SCANCACHE * scan_cache,
613  HEAP_CACHE_ATTRINFO * attr_info, HEAP_CACHE_ATTRINFO * index_attr_info,
614  HEAP_IDX_ELEMENTS_INFO * idx_info, int pruning_type,
615  PRUNING_CONTEXT * pcontext, int *force_count);
616 static int qexec_execute_do_stmt (THREAD_ENTRY * thread_p, XASL_NODE * xasl, XASL_STATE * xasl_state);
617 
618 static int bf2df_str_son_index (THREAD_ENTRY * thread_p, char **son_index, char *father_index, int *len_son_index,
619  int cnt);
620 static DB_VALUE_COMPARE_RESULT bf2df_str_compare (const unsigned char *s0, int l0, const unsigned char *s1, int l1);
621 static DB_VALUE_COMPARE_RESULT bf2df_str_cmpdisk (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion,
622  int total_order, int *start_colp);
623 static DB_VALUE_COMPARE_RESULT bf2df_str_cmpval (DB_VALUE * value1, DB_VALUE * value2, int do_coercion, int total_order,
624  int *start_colp, int collation);
625 static void qexec_resolve_domains_on_sort_list (SORT_LIST * order_list, REGU_VARIABLE_LIST reference_regu_list);
626 static void qexec_resolve_domains_for_group_by (BUILDLIST_PROC_NODE * buildlist, OUTPTR_LIST * reference_out_list);
629  REGU_VARIABLE_LIST regu_list, int *resolved);
630 static int query_multi_range_opt_check_set_sort_col (THREAD_ENTRY * thread_p, XASL_NODE * xasl);
632 static int qexec_init_instnum_val (XASL_NODE * xasl, THREAD_ENTRY * thread_p, XASL_STATE * xasl_state);
633 static int qexec_set_class_locks (THREAD_ENTRY * thread_p, XASL_NODE * aptr_list, UPDDEL_CLASS_INFO * query_classes,
634  int query_classes_count, UPDDEL_CLASS_INFO_INTERNAL * internal_classes);
635 static int qexec_for_update_set_class_locks (THREAD_ENTRY * thread_p, XASL_NODE * scan_list);
636 static int qexec_create_internal_classes (THREAD_ENTRY * thread_p, UPDDEL_CLASS_INFO * classes_info, int count,
637  UPDDEL_CLASS_INFO_INTERNAL ** classes);
638 static int qexec_create_mvcc_reev_assignments (THREAD_ENTRY * thread_p, XASL_NODE * aptr, bool should_delete,
639  UPDDEL_CLASS_INFO_INTERNAL * classes, int num_classes,
640  int num_assignments, UPDATE_ASSIGNMENT * assignments,
641  UPDATE_MVCC_REEV_ASSIGNMENT ** mvcc_reev_assigns);
642 static int prepare_mvcc_reev_data (THREAD_ENTRY * thread_p, XASL_NODE * aptr, XASL_STATE * xasl_state,
643  int num_reev_classes, int *cond_reev_indexes, MVCC_UPDDEL_REEV_DATA * reev_data,
644  int num_classes, UPDDEL_CLASS_INFO * classes,
645  UPDDEL_CLASS_INFO_INTERNAL * internal_classes, int num_assigns,
646  UPDATE_ASSIGNMENT * assigns, PRED_EXPR * cons_pred,
647  UPDDEL_MVCC_COND_REEVAL ** mvcc_reev_classes,
648  UPDATE_MVCC_REEV_ASSIGNMENT ** mvcc_reev_assigns, bool has_delete);
650  UPDDEL_MVCC_COND_REEVAL * reev_classes,
651  int num_reev_classes, UPDDEL_CLASS_INFO * classes,
652  int num_classes);
653 static void qexec_clear_internal_classes (THREAD_ENTRY * thread_p, UPDDEL_CLASS_INFO_INTERNAL * classes, int count);
654 static int qexec_upddel_setup_current_class (THREAD_ENTRY * thread_p, UPDDEL_CLASS_INFO * class_,
655  UPDDEL_CLASS_INFO_INTERNAL * class_info, int op_type, OID * current_oid);
656 static int qexec_upddel_mvcc_set_filters (THREAD_ENTRY * thread_p, XASL_NODE * aptr_list,
657  UPDDEL_MVCC_COND_REEVAL * mvcc_reev_class, OID * class_oid);
658 static int qexec_init_agg_hierarchy_helpers (THREAD_ENTRY * thread_p, ACCESS_SPEC_TYPE * spec,
659  AGGREGATE_TYPE * aggregate_list, HIERARCHY_AGGREGATE_HELPER ** helpers,
660  int *helpers_countp);
661 static int qexec_evaluate_aggregates_optimize (THREAD_ENTRY * thread_p, AGGREGATE_TYPE * agg_list,
662  ACCESS_SPEC_TYPE * spec, bool * is_scan_needed);
664  AGGREGATE_TYPE * agg_list, bool * is_scan_needed);
665 
666 static int qexec_setup_topn_proc (THREAD_ENTRY * thread_p, XASL_NODE * xasl, VAL_DESCR * vd);
667 static BH_CMP_RESULT qexec_topn_compare (const void *left, const void *right, BH_CMP_ARG arg);
668 static BH_CMP_RESULT qexec_topn_cmpval (DB_VALUE * left, DB_VALUE * right, SORT_LIST * sort_spec);
669 static TOPN_STATUS qexec_add_tuple_to_topn (THREAD_ENTRY * thread_p, TOPN_TUPLES * sort_stop,
670  QFILE_TUPLE_DESCRIPTOR * tpldescr);
672  bool is_final);
673 static void qexec_clear_topn_tuple (THREAD_ENTRY * thread_p, TOPN_TUPLE * tuple, int count);
674 static int qexec_get_orderbynum_upper_bound (THREAD_ENTRY * tread_p, PRED_EXPR * pred, VAL_DESCR * vd,
675  DB_VALUE * ubound);
677  ANALYTIC_FUNCTION_STATE * func_state);
678 
679 static int qexec_clear_regu_variable_list (THREAD_ENTRY * thread_p, XASL_NODE * xasl_p, REGU_VARIABLE_LIST list,
680  bool is_final);
681 static void qexec_clear_pred_xasl (THREAD_ENTRY * thread_p, PRED_EXPR * pred);
682 
683 #if defined(SERVER_MODE)
684 static void qexec_set_xasl_trace_to_session (THREAD_ENTRY * thread_p, XASL_NODE * xasl);
685 #endif /* SERVER_MODE */
686 
688 static void qexec_free_agg_hash_context (THREAD_ENTRY * thread_p, BUILDLIST_PROC_NODE * proc);
689 static int qexec_build_agg_hkey (THREAD_ENTRY * thread_p, XASL_STATE * xasl_state, REGU_VARIABLE_LIST regu_list,
690  QFILE_TUPLE tpl, AGGREGATE_HASH_KEY * key);
692  AGGREGATE_HASH_KEY * key, bool * found);
693 static int qexec_get_attr_default (THREAD_ENTRY * thread_p, OR_ATTRIBUTE * attr, DB_VALUE * default_val);
694 
695 /*
696  * Utility routines
697  */
698 
699 /*
700  * qexec_eval_instnum_pred () -
701  * return:
702  * xasl(in) :
703  * xasl_state(in) :
704  */
705 static DB_LOGICAL
707 {
708  DB_LOGICAL ev_res;
709 
710  /* instant numbering; increase the value of inst_num() by 1 */
711  if (xasl->instnum_val)
712  {
713  xasl->instnum_val->data.bigint++;
714  }
715  if (xasl->save_instnum_val)
716  {
717  xasl->save_instnum_val->data.bigint++;
718  }
719 
721  {
722  PRED_EXPR *pr = xasl->instnum_pred;
723 
724  /* this case is for: select * from table limit 3, or select * from table where rownum <= 3 and we can change
725  * operator <= to < and reevaluate last condition. (to stop scan at this time) */
730  {
732  /* evaluate predicate */
733  ev_res = eval_pred (thread_p, xasl->instnum_pred, &xasl_state->vd, NULL);
734 
736 
737  if (ev_res != V_TRUE)
738  {
739  ev_res = eval_pred (thread_p, xasl->instnum_pred, &xasl_state->vd, NULL);
740 
741  if (ev_res == V_TRUE)
742  {
744  }
745  }
746  }
747  else
748  {
749  /* evaluate predicate */
750  ev_res = eval_pred (thread_p, xasl->instnum_pred, &xasl_state->vd, NULL);
751  }
752 
753  switch (ev_res)
754  {
755  case V_FALSE:
756  /* evaluation is false; if check flag was set, stop scan */
758  {
760  }
761  break;
762  case V_TRUE:
763  /* evaluation is true; if not continue scan mode, set scan check flag */
766  {
768  }
769  break;
770  case V_ERROR:
771  break;
772  default: /* V_UNKNOWN */
773  break;
774  }
775  }
776  else
777  {
778  /* no predicate; always true */
779  ev_res = V_TRUE;
780  }
781 
782  return ev_res;
783 }
784 
785 /*
786  * qexec_add_composite_lock () -
787  * return: NO_ERROR or ER_code
788  * thread_p(in) :
789  * reg_var_list(in/out) : list of regu variables to be fetched. First
790  * upd_del_cls_cnt pairs of variables will be loaded. Each pair will
791  * contain instance OID and class OID.
792  * xasl_state(in) : xasl state. Needed for fetch_peek_dbval.
793  * composite_lock(in/out) : structure that will be filled with composite
794  * locks.
795  * upd_del_cls_cnt(in): number of classes for which rows will be updated or
796  * deleted.
797  * default_cls_oid(in): default class oid
798  */
799 static int
801  LK_COMPOSITE_LOCK * composite_lock, int upd_del_cls_cnt, OID * default_cls_oid)
802 {
803  int ret = NO_ERROR, idx;
804  DB_VALUE *dbval, element;
805  DB_TYPE typ;
806  OID instance_oid, class_oid;
807 
808  /* By convention, the first upd_del_class_cnt pairs of values must be: instance OID - class OID */
809 
810  idx = 0;
811  while (reg_var_list && idx < upd_del_cls_cnt)
812  {
813  if (reg_var_list->next == NULL && default_cls_oid == NULL)
814  {
816  }
817  ret = fetch_peek_dbval (thread_p, &reg_var_list->value, &xasl_state->vd, NULL, NULL, NULL, &dbval);
818  if (ret != NO_ERROR)
819  {
821  }
822 
823  reg_var_list = reg_var_list->next;
824 
825  if (!DB_IS_NULL (dbval))
826  {
827  typ = DB_VALUE_DOMAIN_TYPE (dbval);
828  if (typ == DB_TYPE_VOBJ)
829  {
830  /* grab the real oid */
831  ret = db_seq_get (db_get_set (dbval), 2, &element);
832  if (ret != NO_ERROR)
833  {
835  }
836  dbval = &element;
837  typ = DB_VALUE_DOMAIN_TYPE (dbval);
838  }
839 
840  if (typ != DB_TYPE_OID)
841  {
843  }
844 
845  SAFE_COPY_OID (&instance_oid, db_get_oid (dbval));
846 
847  if (default_cls_oid != NULL)
848  {
849  COPY_OID (&class_oid, default_cls_oid);
850  }
851  else
852  {
853  ret = fetch_peek_dbval (thread_p, &reg_var_list->value, &xasl_state->vd, NULL, NULL, NULL, &dbval);
854  if (ret != NO_ERROR)
855  {
857  }
858 
859  typ = DB_VALUE_DOMAIN_TYPE (dbval);
860  if (typ == DB_TYPE_VOBJ)
861  {
862  /* grab the real oid */
863  ret = db_seq_get (db_get_set (dbval), 2, &element);
864  if (ret != NO_ERROR)
865  {
867  }
868  dbval = &element;
869  typ = DB_VALUE_DOMAIN_TYPE (dbval);
870  }
871 
872  if (typ != DB_TYPE_OID)
873  {
875  }
876 
877  SAFE_COPY_OID (&class_oid, db_get_oid (dbval));
878  }
879 
880  ret = lock_add_composite_lock (thread_p, composite_lock, &instance_oid, &class_oid);
881  if (ret != NO_ERROR)
882  {
884  }
885  }
886 
887  idx++;
888  if (reg_var_list)
889  {
890  reg_var_list = reg_var_list->next;
891  }
892  }
893 
894  return ret;
895 
896 exit_on_error:
897 
898  return (ret == NO_ERROR && (ret = er_errid ()) == NO_ERROR) ? ER_FAILED : ret;
899 }
900 
901 /*
902  * qexec_generate_tuple_descriptor () -
903  * return: status
904  * thread_p(in) :
905  * list_id(in/out) :
906  * outptr_list(in) :
907  * vd(in) :
908  *
909  */
912  VAL_DESCR * vd)
913 {
914  QPROC_TPLDESCR_STATUS status;
915  size_t size;
916  int i;
917 
918  status = QPROC_TPLDESCR_FAILURE; /* init */
919 
920  /* make f_valp array */
921  if (list_id->tpl_descr.f_valp == NULL && list_id->type_list.type_cnt > 0)
922  {
923  size = list_id->type_list.type_cnt * DB_SIZEOF (DB_VALUE *);
924 
925  list_id->tpl_descr.f_valp = (DB_VALUE **) malloc (size);
926  if (list_id->tpl_descr.f_valp == NULL)
927  {
929  goto exit_on_error;
930  }
931 
932  size = list_id->type_list.type_cnt * sizeof (bool);
933  list_id->tpl_descr.clear_f_val_at_clone_decache = (bool *) malloc (size);
935  {
937  goto exit_on_error;
938  }
939  for (i = 0; i < list_id->type_list.type_cnt; i++)
940  {
941  list_id->tpl_descr.clear_f_val_at_clone_decache[i] = false;
942  }
943  }
944 
945  /* build tuple descriptor */
946  status = qdata_generate_tuple_desc_for_valptr_list (thread_p, outptr_list, vd, &(list_id->tpl_descr));
947  if (status == QPROC_TPLDESCR_FAILURE)
948  {
949  goto exit_on_error;
950  }
951 
952  if (list_id->is_domain_resolved == false)
953  {
954  /* Resolve DB_TYPE_VARIABLE domains. It will be done when generating the first tuple. */
955  if (qfile_update_domains_on_type_list (thread_p, list_id, outptr_list) != NO_ERROR)
956  {
957  goto exit_on_error;
958  }
959  }
960 
961  return status;
962 
963 exit_on_error:
964 
965  return QPROC_TPLDESCR_FAILURE;
966 }
967 
968 /*
969  * qexec_upddel_add_unique_oid_to_ehid () -
970  * return: error code (<0) or the number of removed OIDs (>=0).
971  * thread_p(in) :
972  * xasl(in) : The XASL node of the generated SELECT statement for UPDATE or
973  * DELETE. It must be a BUILDLIST_PROC and have the temporary hash
974  * files already created (upddel_oid_locator_ehids).
975  * xasl_state(in) :
976  *
977  * Note: This function is used only for the SELECT queries generated for UPDATE
978  * or DELETE statements. It sets each instance OID from the outptr_list
979  * to null if the OID already exists in the hash file associated with the
980  * source table of the OID. (It eliminates duplicate OIDs in order to not
981  * UPDATE/DELETE them more than once). The function returns the number of
982  * removed OIDs so that the caller can remove the entire row from
983  * processing (SELECT list) if all OIDs were removed. Otherwise only the
984  * null instance OIDs will be skipped from UPDATE/DELETE processing.
985  */
986 static int
988 {
989  REGU_VARIABLE_LIST reg_var_list = NULL;
990  DB_VALUE *dbval = NULL, *orig_dbval = NULL, element;
991  DB_TYPE typ;
992  int ret = NO_ERROR, idx, rem_cnt = 0;
993  EHID *ehid = NULL;
994  OID oid, key_oid;
995  EH_SEARCH eh_search;
996 
997  if (xasl == NULL || xasl->type != BUILDLIST_PROC || xasl->proc.buildlist.upddel_oid_locator_ehids == NULL)
998  {
999  return NO_ERROR;
1000  }
1001 
1002  idx = 0;
1003  reg_var_list = xasl->outptr_list->valptrp;
1004  while (reg_var_list != NULL && idx < xasl->upd_del_class_cnt)
1005  {
1006  ret = fetch_peek_dbval (thread_p, &reg_var_list->value, &xasl_state->vd, NULL, NULL, NULL, &dbval);
1007  if (ret != NO_ERROR)
1008  {
1010  }
1011 
1012  if (!DB_IS_NULL (dbval))
1013  {
1014  orig_dbval = dbval;
1015 
1016  typ = DB_VALUE_DOMAIN_TYPE (dbval);
1017  if (typ == DB_TYPE_VOBJ)
1018  {
1019  /* grab the real oid */
1020  ret = db_seq_get (db_get_set (dbval), 2, &element);
1021  if (ret != NO_ERROR)
1022  {
1024  }
1025  dbval = &element;
1026  typ = DB_VALUE_DOMAIN_TYPE (dbval);
1027  }
1028 
1029  if (typ != DB_TYPE_OID)
1030  {
1031  pr_clear_value (dbval);
1033  }
1034 
1035  /* Get the appropriate hash file and check if the OID exists in the file */
1036  ehid = &xasl->proc.buildlist.upddel_oid_locator_ehids[idx];
1037 
1038  SAFE_COPY_OID (&key_oid, db_get_oid (dbval));
1039 
1040  eh_search = ehash_search (thread_p, ehid, &key_oid, &oid);
1041  switch (eh_search)
1042  {
1043  case EH_KEY_FOUND:
1044  /* Make it null because it was already processed */
1045  pr_clear_value (orig_dbval);
1046  rem_cnt++;
1047  break;
1048  case EH_KEY_NOTFOUND:
1049  /* The OID was not processed so insert it in the hash file */
1050  if (ehash_insert (thread_p, ehid, &key_oid, &key_oid) == NULL)
1051  {
1053  }
1054  break;
1055  case EH_ERROR_OCCURRED:
1056  default:
1058  }
1059  }
1060  else
1061  {
1062  rem_cnt++;
1063  }
1064 
1065  reg_var_list = reg_var_list->next;
1066  if (reg_var_list != NULL)
1067  {
1068  /* Skip class oid and move to next instance oid */
1069  reg_var_list = reg_var_list->next;
1070  }
1071  idx++;
1072  }
1073 
1074  return rem_cnt;
1075 
1076 exit_on_error:
1077 
1078  if (ret == NO_ERROR)
1079  {
1080  assert (er_errid () != NO_ERROR);
1081  ret = er_errid ();
1082  if (ret == NO_ERROR)
1083  {
1084  return ER_FAILED;
1085  }
1086  }
1087 
1088  return ret;
1089 }
1090 
1091 /*
1092  * qexec_end_one_iteration () -
1093  * return: NO_ERROR or ER_code
1094  * xasl(in) :
1095  * xasl_state(in) :
1096  * tplrec(in) :
1097  *
1098  * Note: Processing to be accomplished when a candidate row has been qualified.
1099  */
1100 static int
1102  QFILE_TUPLE_RECORD * tplrec)
1103 {
1104  QPROC_TPLDESCR_STATUS tpldescr_status;
1105  TOPN_STATUS topn_stauts = TOPN_SUCCESS;
1106  int ret = NO_ERROR;
1107  bool output_tuple = true;
1108 
1111  {
1112  /* Remove OIDs already processed */
1113  ret = qexec_upddel_add_unique_oid_to_ehid (thread_p, xasl, xasl_state);
1114  if (ret < 0)
1115  {
1117  }
1118  if (ret == xasl->upd_del_class_cnt)
1119  {
1120  return NO_ERROR;
1121  }
1122  ret = NO_ERROR;
1123 
1124 #if defined (ENABLE_COMPOSITE_LOCK)
1125  /* At this moment composite locking is not used, but it can be activated at some point in the future. So we leave
1126  * it as it is. */
1127  if (false)
1128  {
1129  OID *class_oid = NULL;
1130 
1131  XASL_NODE *aptr = xasl->aptr_list;
1132  if (aptr)
1133  {
1134  for (XASL_NODE * crt = aptr->next; crt; crt = crt->next, aptr = aptr->next)
1135  ;
1136  }
1137  if (aptr && aptr->type == BUILDLIST_PROC && aptr->proc.buildlist.push_list_id)
1138  {
1139  class_oid = &ACCESS_SPEC_CLS_OID (aptr->spec_list);
1140  }
1141 
1142  ret =
1143  qexec_add_composite_lock (thread_p, xasl->outptr_list->valptrp, xasl_state, &xasl->composite_lock,
1144  xasl->upd_del_class_cnt, class_oid);
1145  if (ret != NO_ERROR)
1146  {
1148  }
1149  }
1150 #endif /* defined (ENABLE_COMPOSITE_LOCK) */
1151  }
1152 
1153  if (xasl->type == BUILDLIST_PROC || xasl->type == BUILD_SCHEMA_PROC)
1154  {
1155  if (xasl->selected_upd_list != NULL && xasl->list_id->tuple_cnt > 0)
1156  {
1160  }
1161 
1162  tpldescr_status = qexec_generate_tuple_descriptor (thread_p, xasl->list_id, xasl->outptr_list, &xasl_state->vd);
1163  if (tpldescr_status == QPROC_TPLDESCR_FAILURE)
1164  {
1166  }
1167 
1168  /* update aggregation domains */
1169  if (xasl->type == BUILDLIST_PROC && xasl->proc.buildlist.g_agg_list != NULL
1171  {
1172  if (qexec_resolve_domains_for_aggregation (thread_p, xasl->proc.buildlist.g_agg_list, xasl_state, tplrec,
1175  {
1177  }
1178  }
1179 
1180  /* process tuple */
1181  switch (tpldescr_status)
1182  {
1184  if (xasl->topn_items != NULL)
1185  {
1186  topn_stauts = qexec_add_tuple_to_topn (thread_p, xasl->topn_items, &xasl->list_id->tpl_descr);
1187  if (topn_stauts == TOPN_SUCCESS)
1188  {
1189  /* successfully added tuple */
1190  break;
1191  }
1192  else if (topn_stauts == TOPN_FAILURE)
1193  {
1194  /* error while adding tuple */
1196  }
1197  /* The new tuple overflows the topn size. Dump current results to list_id and continue with normal
1198  * execution. The current tuple (from tpl_descr) was not added to the list yet, it will be added below. */
1199  if (qfile_generate_tuple_into_list (thread_p, xasl->list_id, T_NORMAL) != NO_ERROR)
1200  {
1202  }
1203  if (qexec_topn_tuples_to_list_id (thread_p, xasl, xasl_state, false) != NO_ERROR)
1204  {
1206  }
1207  output_tuple = false;
1208  assert (xasl->topn_items == NULL);
1209  }
1210 
1211  if (xasl->type == BUILDLIST_PROC && xasl->proc.buildlist.g_hash_eligible
1212  && xasl->proc.buildlist.agg_hash_context->state != HS_REJECT_ALL)
1213  {
1214  /* aggregate using hash table */
1215  if (qexec_hash_gby_agg_tuple (thread_p, xasl, xasl_state, &xasl->proc.buildlist, tplrec,
1216  &xasl->list_id->tpl_descr, xasl->list_id, &output_tuple) != NO_ERROR)
1217  {
1219  }
1220  }
1221 
1222  if (output_tuple)
1223  {
1224  /* generate tuple into list file page */
1225  if (qfile_generate_tuple_into_list (thread_p, xasl->list_id, T_NORMAL) != NO_ERROR)
1226  {
1228  }
1229  }
1230  break;
1231 
1234  /* BIG QFILE_TUPLE or a SET-field is included */
1235  if (tplrec->tpl == NULL)
1236  {
1237  /* allocate tuple descriptor */
1238  tplrec->size = DB_PAGESIZE;
1239  tplrec->tpl = (QFILE_TUPLE) db_private_alloc (thread_p, DB_PAGESIZE);
1240  if (tplrec->tpl == NULL)
1241  {
1243  }
1244  }
1245 
1246  if ((qdata_copy_valptr_list_to_tuple (thread_p, xasl->outptr_list, &xasl_state->vd, tplrec) != NO_ERROR))
1247  {
1249  }
1250 
1251  if ((qfile_add_tuple_to_list (thread_p, xasl->list_id, tplrec->tpl) != NO_ERROR))
1252  {
1254  }
1255  break;
1256 
1257  default:
1258  break;
1259  }
1260 
1261  if (xasl->topn_items != NULL && tpldescr_status != QPROC_TPLDESCR_SUCCESS)
1262  {
1263  /* abandon top-n processing */
1264  if (qexec_topn_tuples_to_list_id (thread_p, xasl, xasl_state, false) != NO_ERROR)
1265  {
1267  }
1268  assert (xasl->topn_items == NULL);
1269  }
1270  }
1271  else if (xasl->type == BUILDVALUE_PROC)
1272  {
1273  if (xasl->proc.buildvalue.agg_list != NULL)
1274  {
1275  AGGREGATE_TYPE *agg_node = NULL;
1276  REGU_VARIABLE_LIST out_list_val = NULL;
1277 
1279  {
1280  if (qexec_resolve_domains_for_aggregation (thread_p, xasl->proc.buildvalue.agg_list, xasl_state, tplrec,
1282  {
1284  }
1285  }
1286 
1287  if (qdata_evaluate_aggregate_list (thread_p, xasl->proc.buildvalue.agg_list, &xasl_state->vd, NULL) !=
1288  NO_ERROR)
1289  {
1291  }
1292 
1293  /* resolve domains for aggregates */
1294  for (out_list_val = xasl->outptr_list->valptrp; out_list_val != NULL; out_list_val = out_list_val->next)
1295  {
1296  assert (out_list_val->value.domain != NULL);
1297 
1298  /* aggregates corresponds to CONSTANT regu vars in outptr_list */
1299  if (out_list_val->value.type != TYPE_CONSTANT
1300  || (TP_DOMAIN_TYPE (out_list_val->value.domain) != DB_TYPE_VARIABLE
1301  && TP_DOMAIN_COLLATION_FLAG (out_list_val->value.domain) == TP_DOMAIN_COLL_NORMAL))
1302  {
1303  continue;
1304  }
1305 
1306  /* search in aggregate list by comparing DB_VALUE pointers */
1307  for (agg_node = xasl->proc.buildvalue.agg_list; agg_node != NULL; agg_node = agg_node->next)
1308  {
1309  if (out_list_val->value.value.dbvalptr == agg_node->accumulator.value
1310  && TP_DOMAIN_TYPE (agg_node->domain) != DB_TYPE_NULL)
1311  {
1312  assert (agg_node->domain != NULL);
1314  out_list_val->value.domain = agg_node->domain;
1315  }
1316  }
1317 
1318  }
1319  }
1320  }
1321 
1322  return ret;
1323 
1324 exit_on_error:
1325 
1326  return (ret == NO_ERROR && (ret = er_errid ()) == NO_ERROR) ? ER_FAILED : ret;
1327 }
1328 
1329 /*
1330  * Clean_up processing routines
1331  */
1332 
1333 /*
1334  * qexec_failure_line () -
1335  * return: int
1336  * line(in) :
1337  * xasl_state(in) :
1338  */
1339 static void
1341 {
1342  if (!xasl_state->qp_xasl_line)
1343  {
1344  xasl_state->qp_xasl_line = line;
1345  }
1346 }
1347 
1348 /*
1349  * qexec_clear_xasl_head () -
1350  * return: int
1351  * xasl(in) : XASL Tree procedure block
1352  *
1353  * Note: Clear XASL head node by destroying the resultant list file,
1354  * if any, and also resultant single values, if any. Return the
1355  * number of total pages deallocated.
1356  */
1357 static int
1359 {
1360  int pg_cnt = 0;
1361  VAL_LIST *single_tuple;
1362  QPROC_DB_VALUE_LIST value_list;
1363  int i;
1364 
1365  if (xasl->list_id)
1366  { /* destroy list file */
1367  (void) qfile_close_list (thread_p, xasl->list_id);
1368  qfile_destroy_list (thread_p, xasl->list_id);
1369  }
1370 
1371  single_tuple = xasl->single_tuple;
1372  if (single_tuple)
1373  {
1374  /* clear result value */
1375  for (value_list = single_tuple->valp, i = 0; i < single_tuple->val_cnt; value_list = value_list->next, i++)
1376  {
1377  pr_clear_value (value_list->val);
1378  }
1379  }
1380 
1381  if (XASL_IS_FLAGED (xasl, XASL_HAS_CONNECT_BY))
1382  {
1383  qexec_clear_xasl_head (thread_p, xasl->connect_by_ptr);
1384  }
1385 
1386  if (xcache_uses_clones ())
1387  {
1388  if (XASL_IS_FLAGED (xasl, XASL_DECACHE_CLONE))
1389  {
1390  xasl->status = XASL_CLEARED;
1391  }
1392  else
1393  {
1394  /* The values allocated during execution will be cleared and the xasl is reused. */
1395  xasl->status = XASL_INITIALIZED;
1396  }
1397 
1398  }
1399  else
1400  {
1401  xasl->status = XASL_CLEARED;
1402  }
1403 
1404  return pg_cnt;
1405 }
1406 
1407 /*
1408  * qexec_clear_arith_list () - clear the db_values in the db_val list
1409  * return:
1410  * xasl_p(in) :
1411  * list(in) :
1412  * is_final(in) :
1413  */
1414 static int
1415 qexec_clear_arith_list (THREAD_ENTRY * thread_p, XASL_NODE * xasl_p, ARITH_TYPE * list, bool is_final)
1416 {
1417  int pg_cnt = 0;
1418 
1419  if (list == NULL)
1420  {
1421  return NO_ERROR;
1422  }
1423 
1424  /* restore the original domain, in order to avoid coerce when the XASL clones will be used again */
1425  list->domain = list->original_domain;
1426  pr_clear_value (list->value);
1427  pg_cnt += qexec_clear_regu_var (thread_p, xasl_p, list->leftptr, is_final);
1428  pg_cnt += qexec_clear_regu_var (thread_p, xasl_p, list->rightptr, is_final);
1429  pg_cnt += qexec_clear_regu_var (thread_p, xasl_p, list->thirdptr, is_final);
1430  pg_cnt += qexec_clear_pred (thread_p, xasl_p, list->pred, is_final);
1431 
1432  if (list->rand_seed != NULL)
1433  {
1434  free_and_init (list->rand_seed);
1435  }
1436 
1437  return pg_cnt;
1438 }
1439 
1440 /*
1441  * qexec_clear_regu_var () - clear the db_values in the regu_variable
1442  * return:
1443  * xasl_p(in) :
1444  * regu_var(in) : :
1445  * final(in) :
1446  */
1447 static int
1448 qexec_clear_regu_var (THREAD_ENTRY * thread_p, XASL_NODE * xasl_p, REGU_VARIABLE * regu_var, bool is_final)
1449 {
1450  int pg_cnt;
1451 
1452  pg_cnt = 0;
1453  if (!regu_var)
1454  {
1455  return pg_cnt;
1456  }
1457 
1458  /* restore the original domain, in order to avoid coerce when the XASL clones will be used again */
1459  regu_var->domain = regu_var->original_domain;
1460 
1461 #if !defined(NDEBUG)
1463  {
1465  }
1467  {
1469  }
1470 #endif
1471 
1472  /* clear run-time setting info */
1475 
1476  switch (regu_var->type)
1477  {
1478  case TYPE_ATTR_ID: /* fetch object attribute value */
1479  case TYPE_SHARED_ATTR_ID:
1480  case TYPE_CLASS_ATTR_ID:
1481  regu_var->value.attr_descr.cache_dbvalp = NULL;
1482  break;
1483  case TYPE_CONSTANT:
1484 #if 0 /* TODO - */
1485  case TYPE_ORDERBY_NUM:
1486 #endif
1487  if (XASL_IS_FLAGED (xasl_p, XASL_DECACHE_CLONE))
1488  {
1490  {
1491  /* clear the value since we decache the XASL clone. */
1492  (void) pr_clear_value (regu_var->value.dbvalptr);
1493  }
1494  }
1495  else
1496  {
1498  {
1499  /* clear the value since we decache the XASL (not a clone). */
1500  (void) pr_clear_value (regu_var->value.dbvalptr);
1501  }
1502  }
1503  /* Fall through */
1504  case TYPE_LIST_ID:
1505  if (regu_var->xasl != NULL)
1506  {
1507  if (xcache_uses_clones ())
1508  {
1509  if (XASL_IS_FLAGED (xasl_p, XASL_DECACHE_CLONE) && regu_var->xasl->status != XASL_CLEARED)
1510  {
1511  /* regu_var->xasl not cleared yet. Set flag to clear the values allocated at unpacking. */
1512  XASL_SET_FLAG (regu_var->xasl, XASL_DECACHE_CLONE);
1513  pg_cnt += qexec_clear_xasl (thread_p, regu_var->xasl, is_final);
1514  }
1515  else if (!XASL_IS_FLAGED (xasl_p, XASL_DECACHE_CLONE) && regu_var->xasl->status != XASL_INITIALIZED)
1516  {
1517  /* regu_var->xasl not cleared yet. Clear the values allocated during execution. */
1518  pg_cnt += qexec_clear_xasl (thread_p, regu_var->xasl, is_final);
1519  }
1520  }
1521  else if (regu_var->xasl->status != XASL_CLEARED)
1522  {
1523  pg_cnt += qexec_clear_xasl (thread_p, regu_var->xasl, is_final);
1524  }
1525  }
1526  break;
1527  case TYPE_INARITH:
1528  case TYPE_OUTARITH:
1529  pg_cnt += qexec_clear_arith_list (thread_p, xasl_p, regu_var->value.arithptr, is_final);
1530  break;
1531  case TYPE_FUNC:
1532  pr_clear_value (regu_var->value.funcp->value);
1533  pg_cnt += qexec_clear_regu_list (thread_p, xasl_p, regu_var->value.funcp->operand, is_final);
1534 
1535  if (regu_var->value.funcp->tmp_obj != NULL)
1536  {
1537  switch (regu_var->value.funcp->ftype)
1538  {
1539  case F_REGEXP_COUNT:
1540  case F_REGEXP_INSTR:
1541  case F_REGEXP_LIKE:
1542  case F_REGEXP_REPLACE:
1543  case F_REGEXP_SUBSTR:
1544  {
1545  delete regu_var->value.funcp->tmp_obj->compiled_regex;
1546  }
1547  break;
1548  default:
1549  // any member of union func_tmp_obj may have been erased
1550  assert (false);
1551  break;
1552  }
1553 
1554  delete regu_var->value.funcp->tmp_obj;
1555  regu_var->value.funcp->tmp_obj = NULL;
1556  }
1557 
1558  break;
1559  case TYPE_REGUVAL_LIST:
1560  pg_cnt += qexec_clear_regu_value_list (thread_p, xasl_p, regu_var->value.reguval_list, is_final);
1561  break;
1562  case TYPE_DBVAL:
1563  if (XASL_IS_FLAGED (xasl_p, XASL_DECACHE_CLONE))
1564  {
1566  {
1567  /* clear the value since we decache the XASL clone. */
1568  (void) pr_clear_value (&regu_var->value.dbval);
1569  }
1570  }
1571  else
1572  {
1574  {
1575  /* clear the value since we decache the XASL (not a clone). */
1576  (void) pr_clear_value (&regu_var->value.dbval);
1577  }
1578  }
1579  break;
1580  case TYPE_REGU_VAR_LIST:
1581  qexec_clear_regu_variable_list (thread_p, xasl_p, regu_var->value.regu_var_list, is_final);
1582  break;
1583 #if 0 /* TODO - */
1584  case TYPE_LIST_ID:
1585 #endif
1586  case TYPE_POSITION:
1587  qexec_clear_pos_desc (xasl_p, &regu_var->value.pos_descr, is_final);
1588  break;
1589  default:
1590  break;
1591  }
1592 
1593  if (regu_var->vfetch_to != NULL)
1594  {
1595  pr_clear_value (regu_var->vfetch_to);
1596  }
1597 
1598  return pg_cnt;
1599 }
1600 
1601 
1602 /*
1603  * qexec_clear_regu_list () - clear the db_values in the regu list
1604  * return:
1605  * xasl_p(in) :
1606  * list(in) :
1607  * is_final(in) :
1608  */
1609 static int
1610 qexec_clear_regu_list (THREAD_ENTRY * thread_p, XASL_NODE * xasl_p, REGU_VARIABLE_LIST list, bool is_final)
1611 {
1613  int pg_cnt;
1614 
1615  pg_cnt = 0;
1616  for (p = list; p; p = p->next)
1617  {
1618  pg_cnt += qexec_clear_regu_var (thread_p, xasl_p, &p->value, is_final);
1619  }
1620 
1621  return pg_cnt;
1622 }
1623 
1624 /*
1625  * qexec_clear_regu_value_list () - clear the db_values in the regu value list
1626  * return:
1627  * xasl_p(in) :
1628  * list(in) :
1629  * is_final(in) :
1630  */
1631 static int
1632 qexec_clear_regu_value_list (THREAD_ENTRY * thread_p, XASL_NODE * xasl_p, REGU_VALUE_LIST * list, bool is_final)
1633 {
1634  REGU_VALUE_ITEM *list_node;
1635  int pg_cnt = 0;
1636 
1637  assert (list != NULL);
1638 
1639  for (list_node = list->regu_list; list_node; list_node = list_node->next)
1640  {
1641  pg_cnt += qexec_clear_regu_var (thread_p, xasl_p, list_node->value, is_final);
1642  }
1643 
1644  return pg_cnt;
1645 }
1646 
1647 /*
1648  * qexec_clear_db_val_list () - clear the db_values in the db_val list
1649  * return:
1650  * list(in) :
1651  */
1652 static void
1654 {
1656 
1657  for (p = list; p; p = p->next)
1658  {
1659  pr_clear_value (p->val);
1660  }
1661 }
1662 
1663 /*
1664  * qexec_clear_sort_list () - clear position desc
1665  * return: void
1666  * xasl_p(in) : xasl
1667  * position_descr(in) : position desc
1668  * is_final(in) : true, if finalize needed
1669  */
1670 static void
1671 qexec_clear_pos_desc (XASL_NODE * xasl_p, QFILE_TUPLE_VALUE_POSITION * position_descr, bool is_final)
1672 {
1673  position_descr->dom = position_descr->original_domain;
1674 }
1675 
1676 /*
1677  * qexec_clear_sort_list () - clear the sort list
1678  * return: void
1679  * xasl_p(in) : xasl
1680  * list(in) : the sort list
1681  * is_final(in) : true, if finalize needed
1682  */
1683 static void
1684 qexec_clear_sort_list (XASL_NODE * xasl_p, SORT_LIST * list, bool is_final)
1685 {
1686  SORT_LIST *p;
1687 
1688  for (p = list; p; p = p->next)
1689  {
1690  /* restores the original domain */
1691  qexec_clear_pos_desc (xasl_p, &p->pos_descr, is_final);
1692  }
1693 }
1694 
1695 /*
1696  * qexec_clear_pred () - clear the db_values in a predicate
1697  * return:
1698  * xasl_p(in) :
1699  * pr(in) :
1700  * is_final(in) :
1701  */
1702 static int
1703 qexec_clear_pred (THREAD_ENTRY * thread_p, XASL_NODE * xasl_p, PRED_EXPR * pr, bool is_final)
1704 {
1705  int pg_cnt;
1706  PRED_EXPR *expr;
1707 
1708  pg_cnt = 0;
1709 
1710  if (pr == NULL)
1711  {
1712  return pg_cnt;
1713  }
1714 
1715  switch (pr->type)
1716  {
1717  case T_PRED:
1718  pg_cnt += qexec_clear_pred (thread_p, xasl_p, pr->pe.m_pred.lhs, is_final);
1719  for (expr = pr->pe.m_pred.rhs; expr && expr->type == T_PRED; expr = expr->pe.m_pred.rhs)
1720  {
1721  pg_cnt += qexec_clear_pred (thread_p, xasl_p, expr->pe.m_pred.lhs, is_final);
1722  }
1723  pg_cnt += qexec_clear_pred (thread_p, xasl_p, expr, is_final);
1724  break;
1725  case T_EVAL_TERM:
1726  switch (pr->pe.m_eval_term.et_type)
1727  {
1728  case T_COMP_EVAL_TERM:
1729  {
1730  COMP_EVAL_TERM *et_comp = &pr->pe.m_eval_term.et.et_comp;
1731 
1732  pg_cnt += qexec_clear_regu_var (thread_p, xasl_p, et_comp->lhs, is_final);
1733  pg_cnt += qexec_clear_regu_var (thread_p, xasl_p, et_comp->rhs, is_final);
1734  }
1735  break;
1736  case T_ALSM_EVAL_TERM:
1737  {
1738  ALSM_EVAL_TERM *et_alsm = &pr->pe.m_eval_term.et.et_alsm;
1739 
1740  pg_cnt += qexec_clear_regu_var (thread_p, xasl_p, et_alsm->elem, is_final);
1741  pg_cnt += qexec_clear_regu_var (thread_p, xasl_p, et_alsm->elemset, is_final);
1742  }
1743  break;
1744  case T_LIKE_EVAL_TERM:
1745  {
1746  LIKE_EVAL_TERM *et_like = &pr->pe.m_eval_term.et.et_like;
1747 
1748  pg_cnt += qexec_clear_regu_var (thread_p, xasl_p, et_like->src, is_final);
1749  pg_cnt += qexec_clear_regu_var (thread_p, xasl_p, et_like->pattern, is_final);
1750  pg_cnt += qexec_clear_regu_var (thread_p, xasl_p, et_like->esc_char, is_final);
1751  }
1752  break;
1753  case T_RLIKE_EVAL_TERM:
1754  {
1755  RLIKE_EVAL_TERM *et_rlike = &pr->pe.m_eval_term.et.et_rlike;
1756 
1757  pg_cnt += qexec_clear_regu_var (thread_p, xasl_p, et_rlike->src, is_final);
1758  pg_cnt += qexec_clear_regu_var (thread_p, xasl_p, et_rlike->pattern, is_final);
1759  pg_cnt += qexec_clear_regu_var (thread_p, xasl_p, et_rlike->case_sensitive, is_final);
1760 
1761  /* free memory of compiled regex */
1762  cubregex::clear (et_rlike->compiled_regex, et_rlike->compiled_pattern);
1763  }
1764  break;
1765  }
1766  break;
1767  case T_NOT_TERM:
1768  pg_cnt += qexec_clear_pred (thread_p, xasl_p, pr->pe.m_not_term, is_final);
1769  break;
1770  }
1771 
1772  return pg_cnt;
1773 }
1774 
1775 /*
1776  * qexec_clear_access_spec_list () - clear the db_values in the access spec list
1777  * return:
1778  * xasl_p(in) :
1779  * list(in) :
1780  * is_final(in) :
1781  */
1782 static int
1783 qexec_clear_access_spec_list (THREAD_ENTRY * thread_p, XASL_NODE * xasl_p, ACCESS_SPEC_TYPE * list, bool is_final)
1784 {
1785  ACCESS_SPEC_TYPE *p = NULL;
1786  HEAP_SCAN_ID *hsidp = NULL;
1787  HEAP_PAGE_SCAN_ID *hpsidp = NULL;
1788  INDX_SCAN_ID *isidp = NULL;
1789  INDEX_NODE_SCAN_ID *insidp = NULL;
1790  int pg_cnt;
1791 
1792  /* I'm not sure this access structure could be anymore complicated (surely some of these dbvalues are redundant) */
1793 
1794  pg_cnt = 0;
1795  for (p = list; p; p = p->next)
1796  {
1797  memset (&p->s_id.scan_stats, 0, sizeof (SCAN_STATS));
1798 
1799  if (p->parts != NULL)
1800  {
1801  db_private_free (thread_p, p->parts);
1802  p->parts = NULL;
1803  p->curent = NULL;
1804  p->pruned = false;
1805  }
1806 
1807  if (XASL_IS_FLAGED (xasl_p, XASL_DECACHE_CLONE))
1808  {
1809  if (p->clear_value_at_clone_decache)
1810  {
1811  /* clear the value since we decache the XASL clone. */
1812  pr_clear_value (p->s_dbval);
1813  }
1814  }
1815  else
1816  {
1817  if (!p->clear_value_at_clone_decache)
1818  {
1819  /* clear the value since we decache the XASL (not a clone). */
1820  pr_clear_value (p->s_dbval);
1821  }
1822  }
1823 
1824  pg_cnt += qexec_clear_pred (thread_p, xasl_p, p->where_pred, is_final);
1825  pg_cnt += qexec_clear_pred (thread_p, xasl_p, p->where_key, is_final);
1826  pg_cnt += qexec_clear_pred (thread_p, xasl_p, p->where_range, is_final);
1827  pr_clear_value (p->s_id.join_dbval);
1828  switch (p->s_id.type)
1829  {
1830  case S_HEAP_SCAN:
1832  case S_CLASS_ATTR_SCAN:
1833  pg_cnt += qexec_clear_regu_list (thread_p, xasl_p, p->s_id.s.hsid.scan_pred.regu_list, is_final);
1834  pg_cnt += qexec_clear_regu_list (thread_p, xasl_p, p->s_id.s.hsid.rest_regu_list, is_final);
1835 
1836  pg_cnt += qexec_clear_regu_list (thread_p, xasl_p, p->s_id.s.hsid.recordinfo_regu_list, is_final);
1837 
1838  hsidp = &p->s_id.s.hsid;
1839  if (hsidp->caches_inited)
1840  {
1841  int i;
1842  heap_attrinfo_end (thread_p, hsidp->pred_attrs.attr_cache);
1843  heap_attrinfo_end (thread_p, hsidp->rest_attrs.attr_cache);
1844  if (hsidp->cache_recordinfo != NULL)
1845  {
1846  for (i = 0; i < HEAP_RECORD_INFO_COUNT; i++)
1847  {
1848  pr_clear_value (hsidp->cache_recordinfo[i]);
1849  }
1850  }
1851  hsidp->caches_inited = false;
1852  }
1853  break;
1854  case S_HEAP_PAGE_SCAN:
1855  hpsidp = &p->s_id.s.hpsid;
1856  if (hpsidp->cache_page_info != NULL)
1857  {
1858  int i;
1859  for (i = 0; i < HEAP_PAGE_INFO_COUNT; i++)
1860  {
1861  pr_clear_value (hpsidp->cache_page_info[i]);
1862  }
1863  }
1864  break;
1865 
1866  case S_INDX_SCAN:
1867  pg_cnt += qexec_clear_regu_list (thread_p, xasl_p, p->s_id.s.isid.key_pred.regu_list, is_final);
1868  pg_cnt += qexec_clear_regu_list (thread_p, xasl_p, p->s_id.s.isid.scan_pred.regu_list, is_final);
1869  pg_cnt += qexec_clear_regu_list (thread_p, xasl_p, p->s_id.s.isid.rest_regu_list, is_final);
1870  if (p->s_id.s.isid.indx_cov.regu_val_list != NULL)
1871  {
1872  pg_cnt += qexec_clear_regu_list (thread_p, xasl_p, p->s_id.s.isid.indx_cov.regu_val_list, is_final);
1873  }
1874 
1875  if (p->s_id.s.isid.indx_cov.output_val_list != NULL)
1876  {
1877  pg_cnt +=
1878  qexec_clear_regu_list (thread_p, xasl_p, p->s_id.s.isid.indx_cov.output_val_list->valptrp, is_final);
1879  }
1880 
1881  isidp = &p->s_id.s.isid;
1882  if (isidp->caches_inited)
1883  {
1884  if (isidp->range_pred.regu_list != NULL)
1885  {
1886  heap_attrinfo_end (thread_p, isidp->range_attrs.attr_cache);
1887  }
1888  if (isidp->key_pred.regu_list)
1889  {
1890  heap_attrinfo_end (thread_p, isidp->key_attrs.attr_cache);
1891  }
1892  heap_attrinfo_end (thread_p, isidp->pred_attrs.attr_cache);
1893  heap_attrinfo_end (thread_p, isidp->rest_attrs.attr_cache);
1894  isidp->caches_inited = false;
1895  }
1896  break;
1897  case S_INDX_KEY_INFO_SCAN:
1898  isidp = &p->s_id.s.isid;
1899  pg_cnt += qexec_clear_regu_list (thread_p, xasl_p, isidp->key_info_regu_list, is_final);
1900  if (isidp->caches_inited)
1901  {
1902  int i;
1903  for (i = 0; i < BTREE_KEY_INFO_COUNT; i++)
1904  {
1905  pr_clear_value (isidp->key_info_values[i]);
1906  }
1907  isidp->caches_inited = false;
1908  }
1909  break;
1910  case S_INDX_NODE_INFO_SCAN:
1911  insidp = &p->s_id.s.insid;
1912  pg_cnt += qexec_clear_regu_list (thread_p, xasl_p, insidp->node_info_regu_list, is_final);
1913  if (insidp->caches_inited)
1914  {
1915  int i;
1916  for (i = 0; i < BTREE_NODE_INFO_COUNT; i++)
1917  {
1918  pr_clear_value (insidp->node_info_values[i]);
1919  }
1920  insidp->caches_inited = false;
1921  }
1922  break;
1923  case S_LIST_SCAN:
1924  pg_cnt += qexec_clear_regu_list (thread_p, xasl_p, p->s_id.s.llsid.scan_pred.regu_list, is_final);
1925  pg_cnt += qexec_clear_regu_list (thread_p, xasl_p, p->s_id.s.llsid.rest_regu_list, is_final);
1926  pg_cnt += qexec_clear_regu_list (thread_p, xasl_p, p->s_id.s.llsid.hlsid.build_regu_list, is_final);
1927  pg_cnt += qexec_clear_regu_list (thread_p, xasl_p, p->s_id.s.llsid.hlsid.probe_regu_list, is_final);
1928  break;
1929  case S_SET_SCAN:
1930  pg_cnt += qexec_clear_regu_list (thread_p, xasl_p, p->s_id.s.ssid.scan_pred.regu_list, is_final);
1931  break;
1932  case S_JSON_TABLE_SCAN:
1933  {
1934  bool jt_clear_default_values =
1935  XASL_IS_FLAGED (xasl_p, XASL_DECACHE_CLONE) == p->clear_value_at_clone_decache;
1936  p->s_id.s.jtid.clear (xasl_p, is_final, jt_clear_default_values);
1937  }
1938  break;
1939  case S_SHOWSTMT_SCAN:
1940  break;
1941  case S_METHOD_SCAN:
1942  break;
1943  case S_VALUES_SCAN:
1944  break;
1945  }
1946  if (p->s_id.val_list)
1947  {
1948  qexec_clear_db_val_list (p->s_id.val_list->valp);
1949  }
1950  switch (p->type)
1951  {
1952  case TARGET_CLASS:
1953  case TARGET_CLASS_ATTR:
1954  pg_cnt += qexec_clear_regu_list (thread_p, xasl_p, p->s.cls_node.cls_regu_list_key, is_final);
1955  pg_cnt += qexec_clear_regu_list (thread_p, xasl_p, p->s.cls_node.cls_regu_list_pred, is_final);
1956  pg_cnt += qexec_clear_regu_list (thread_p, xasl_p, p->s.cls_node.cls_regu_list_rest, is_final);
1957  if (p->access == ACCESS_METHOD_INDEX)
1958  {
1960 
1961  indx_info = p->indexptr;
1962  if (indx_info)
1963  {
1964  int i, N;
1965 
1966  N = indx_info->key_info.key_cnt;
1967  for (i = 0; i < N; i++)
1968  {
1969  pg_cnt +=
1970  qexec_clear_regu_var (thread_p, xasl_p, indx_info->key_info.key_ranges[i].key1, is_final);
1971  pg_cnt +=
1972  qexec_clear_regu_var (thread_p, xasl_p, indx_info->key_info.key_ranges[i].key2, is_final);
1973  }
1974  if (indx_info->key_info.key_limit_l)
1975  {
1976  pg_cnt += qexec_clear_regu_var (thread_p, xasl_p, indx_info->key_info.key_limit_l, is_final);
1977  }
1978  if (indx_info->key_info.key_limit_u)
1979  {
1980  pg_cnt += qexec_clear_regu_var (thread_p, xasl_p, indx_info->key_info.key_limit_u, is_final);
1981  }
1982 
1983  /* Restore the BTID for future usages (needed for partition cases). */
1984  /* XASL comes from the client with the btid set to the root class of the partitions hierarchy.
1985  * Scan begins and starts with the rootclass, then jumps to a partition and sets the btid in the
1986  * XASL to the one of the partition. Execution ends and the next identical statement comes and uses
1987  * the XASL previously generated. However, the BTID was not cleared from the INDEX_INFO structure
1988  * so the execution will fail.
1989  * We need to find a better solution so that we do not write on the XASL members during execution.
1990  */
1991 
1992  /* TODO: Fix me!! */
1993  BTID_COPY (&indx_info->btid, &p->btid);
1994  }
1995  }
1996  break;
1997  case TARGET_LIST:
1998  pg_cnt += qexec_clear_regu_list (thread_p, xasl_p, p->s.list_node.list_regu_list_pred, is_final);
1999  pg_cnt += qexec_clear_regu_list (thread_p, xasl_p, p->s.list_node.list_regu_list_rest, is_final);
2000  pg_cnt += qexec_clear_regu_list (thread_p, xasl_p, p->s.list_node.list_regu_list_build, is_final);
2001  pg_cnt += qexec_clear_regu_list (thread_p, xasl_p, p->s.list_node.list_regu_list_probe, is_final);
2002 
2003  if (p->s.list_node.xasl_node && p->s.list_node.xasl_node->status != XASL_CLEARED
2004  && XASL_IS_FLAGED (xasl_p, XASL_DECACHE_CLONE))
2005  {
2007  pg_cnt += qexec_clear_xasl (thread_p, p->s.list_node.xasl_node, is_final);
2008  }
2009  break;
2010  case TARGET_SHOWSTMT:
2011  pg_cnt += qexec_clear_regu_list (thread_p, xasl_p, p->s.showstmt_node.arg_list, is_final);
2012  break;
2013  case TARGET_SET:
2014  pg_cnt += qexec_clear_regu_list (thread_p, xasl_p, ACCESS_SPEC_SET_REGU_LIST (p), is_final);
2015  pg_cnt += qexec_clear_regu_var (thread_p, xasl_p, ACCESS_SPEC_SET_PTR (p), is_final);
2016 
2017  pg_cnt += qexec_clear_regu_var (thread_p, xasl_p, p->s_id.s.ssid.set_ptr, is_final);
2018  pr_clear_value (&p->s_id.s.ssid.set);
2019  break;
2020  case TARGET_JSON_TABLE:
2021  pg_cnt += qexec_clear_regu_var (thread_p, xasl_p, p->s.json_table_node.m_json_reguvar, is_final);
2022  break;
2023  case TARGET_METHOD:
2024  pg_cnt += qexec_clear_regu_list (thread_p, xasl_p, p->s.method_node.method_regu_list, is_final);
2025  break;
2026  case TARGET_REGUVAL_LIST:
2027  break;
2028  }
2029  }
2030 
2031  return pg_cnt;
2032 }
2033 
2034 /*
2035  * qexec_clear_analytic_function_list () -
2036  * return:
2037  * xasl_p(in) :
2038  * list(in) :
2039  * is_final(in) :
2040  */
2041 static int
2043  bool is_final)
2044 {
2045  ANALYTIC_EVAL_TYPE *e;
2046  ANALYTIC_TYPE *p;
2047  int pg_cnt;
2048 
2049  pg_cnt = 0;
2050 
2051  for (e = list; e; e = e->next)
2052  {
2053  for (p = e->head; p; p = p->next)
2054  {
2055  (void) pr_clear_value (p->value);
2056  (void) pr_clear_value (p->value2);
2057  (void) pr_clear_value (&p->part_value);
2058  p->domain = p->original_domain;
2060  pg_cnt += qexec_clear_regu_var (thread_p, xasl_p, &p->operand, is_final);
2061  p->init ();
2062  }
2063  }
2064 
2065  return pg_cnt;
2066 }
2067 
2068 /*
2069  * qexec_clear_agg_list () - clear the db_values in the agg list
2070  * return:
2071  * xasl_p(in) :
2072  * list(in) :
2073  * is_final(in) :
2074  */
2075 static int
2076 qexec_clear_agg_list (THREAD_ENTRY * thread_p, XASL_NODE * xasl_p, AGGREGATE_TYPE * list, bool is_final)
2077 {
2078  AGGREGATE_TYPE *p;
2079  int pg_cnt;
2080 
2081  pg_cnt = 0;
2082  for (p = list; p; p = p->next)
2083  {
2084  if (XASL_IS_FLAGED (xasl_p, XASL_DECACHE_CLONE))
2085  {
2087  {
2088  /* clear the value since we decache the XASL clone. */
2090  }
2091 
2093  {
2094  /* clear the value since we decache the XASL (not a clone). */
2096  }
2097  }
2098  else
2099  {
2101  {
2103  }
2104 
2106  {
2108  }
2109  }
2110 
2111  pg_cnt += qexec_clear_regu_variable_list (thread_p, xasl_p, p->operands, is_final);
2112  p->domain = p->original_domain;
2114  }
2115 
2116  return pg_cnt;
2117 }
2118 
2119 /*
2120  * qexec_clear_xasl () -
2121  * return: int
2122  * xasl(in) : XASL Tree procedure block
2123  * is_final(in) : true if DB_VALUES, etc should be whacked (i.e., if this XASL tree will ***NEVER*** be used again)
2124  *
2125  * Note: Destroy all the list files (temporary or result list files)
2126  * created during interpretation of XASL Tree procedure block
2127  * and return the number of total pages deallocated.
2128  */
2129 int
2130 qexec_clear_xasl (THREAD_ENTRY * thread_p, xasl_node * xasl, bool is_final)
2131 {
2132  int pg_cnt;
2133  int query_save_state;
2134  unsigned int decache_clone_flag = 0;
2135 
2136  pg_cnt = 0;
2137  if (xasl == NULL)
2138  {
2139  return pg_cnt;
2140  }
2141 
2142  decache_clone_flag = xasl->flag & XASL_DECACHE_CLONE;
2143 
2144  /*
2145  ** We set this because in some M paths (e.g. when a driver crashes)
2146  ** the function qexec_clear_xasl() can be called recursively. By setting
2147  ** the query_in_progress flag, we prevent qmgr_clear_trans_wakeup() from
2148  ** clearing the xasl structure; thus preventing a core at the
2149  ** primary calling level.
2150  */
2151  query_save_state = xasl->query_in_progress;
2152 
2153  xasl->query_in_progress = true;
2154 
2155  /* clear the head node */
2156  pg_cnt += qexec_clear_xasl_head (thread_p, xasl);
2157 
2158 #if defined (ENABLE_COMPOSITE_LOCK)
2159  /* free alloced memory for composite locking */
2160  assert (xasl->composite_lock.lockcomp.class_list == NULL);
2161  lock_abort_composite_lock (&xasl->composite_lock);
2162 #endif /* defined (ENABLE_COMPOSITE_LOCK) */
2163 
2164  /* clear the body node */
2165  if (xasl->aptr_list)
2166  {
2167  XASL_SET_FLAG (xasl->aptr_list, decache_clone_flag);
2168  pg_cnt += qexec_clear_xasl (thread_p, xasl->aptr_list, is_final);
2169  }
2170  if (xasl->bptr_list)
2171  {
2172  XASL_SET_FLAG (xasl->bptr_list, decache_clone_flag);
2173  pg_cnt += qexec_clear_xasl (thread_p, xasl->bptr_list, is_final);
2174  }
2175  if (xasl->dptr_list)
2176  {
2177  XASL_SET_FLAG (xasl->dptr_list, decache_clone_flag);
2178  pg_cnt += qexec_clear_xasl (thread_p, xasl->dptr_list, is_final);
2179  }
2180  if (xasl->fptr_list)
2181  {
2182  XASL_SET_FLAG (xasl->fptr_list, decache_clone_flag);
2183  pg_cnt += qexec_clear_xasl (thread_p, xasl->fptr_list, is_final);
2184  }
2185  if (xasl->scan_ptr)
2186  {
2187  XASL_SET_FLAG (xasl->scan_ptr, decache_clone_flag);
2188  pg_cnt += qexec_clear_xasl (thread_p, xasl->scan_ptr, is_final);
2189  }
2190 
2191  /* clear the CONNECT BY node */
2192  if (XASL_IS_FLAGED (xasl, XASL_HAS_CONNECT_BY))
2193  {
2194  assert (xasl->connect_by_ptr != NULL);
2195  XASL_SET_FLAG (xasl->connect_by_ptr, decache_clone_flag);
2196  pg_cnt += qexec_clear_xasl (thread_p, xasl->connect_by_ptr, is_final);
2197  }
2198 
2199  /* clean up the order-by const list used for CUME_DIST and PERCENT_RANK */
2200  if (xasl->type == BUILDVALUE_PROC)
2201  {
2202  pg_cnt += qexec_clear_agg_orderby_const_list (thread_p, xasl, is_final);
2203  }
2204 
2205 
2206  if (is_final)
2207  {
2208  /* clear the db_values in the tree */
2209  if (xasl->outptr_list)
2210  {
2211  pg_cnt += qexec_clear_regu_list (thread_p, xasl, xasl->outptr_list->valptrp, is_final);
2212  }
2213  pg_cnt += qexec_clear_access_spec_list (thread_p, xasl, xasl->spec_list, is_final);
2214  pg_cnt += qexec_clear_access_spec_list (thread_p, xasl, xasl->merge_spec, is_final);
2215  if (xasl->val_list)
2216  {
2218  }
2219  if (xasl->merge_val_list)
2220  {
2222  }
2223  pg_cnt += qexec_clear_pred (thread_p, xasl, xasl->after_join_pred, is_final);
2224  pg_cnt += qexec_clear_pred (thread_p, xasl, xasl->if_pred, is_final);
2225  if (xasl->instnum_val)
2226  {
2227  pr_clear_value (xasl->instnum_val);
2228  }
2229 
2230  pg_cnt += qexec_clear_pred (thread_p, xasl, xasl->instnum_pred, is_final);
2231  if (xasl->ordbynum_val)
2232  {
2233  pr_clear_value (xasl->ordbynum_val);
2234  }
2235 
2236  if (xasl->after_iscan_list)
2237  {
2238  qexec_clear_sort_list (xasl, xasl->after_iscan_list, is_final);
2239  }
2240 
2241  if (xasl->orderby_list)
2242  {
2243  qexec_clear_sort_list (xasl, xasl->orderby_list, is_final);
2244  }
2245  pg_cnt += qexec_clear_pred (thread_p, xasl, xasl->ordbynum_pred, is_final);
2246 
2247  if (xasl->orderby_limit)
2248  {
2249  pg_cnt += qexec_clear_regu_var (thread_p, xasl, xasl->orderby_limit, is_final);
2250  }
2251 
2252  if (xasl->limit_offset)
2253  {
2254  pg_cnt += qexec_clear_regu_var (thread_p, xasl, xasl->limit_offset, is_final);
2255  }
2256 
2257  if (xasl->limit_offset)
2258  {
2259  pg_cnt += qexec_clear_regu_var (thread_p, xasl, xasl->limit_offset, is_final);
2260  }
2261 
2262  if (xasl->limit_row_count)
2263  {
2264  pg_cnt += qexec_clear_regu_var (thread_p, xasl, xasl->limit_row_count, is_final);
2265  }
2266 
2267  if (xasl->level_val)
2268  {
2269  pr_clear_value (xasl->level_val);
2270  }
2271  if (xasl->isleaf_val)
2272  {
2273  pr_clear_value (xasl->isleaf_val);
2274  }
2275  if (xasl->iscycle_val)
2276  {
2277  pr_clear_value (xasl->iscycle_val);
2278  }
2279  if (xasl->topn_items != NULL)
2280  {
2281  int i;
2282  BINARY_HEAP *heap;
2283 
2284  heap = xasl->topn_items->heap;
2285  for (i = 0; i < heap->element_count; i++)
2286  {
2287  qexec_clear_topn_tuple (thread_p, QEXEC_GET_BH_TOPN_TUPLE (heap, i), xasl->topn_items->values_count);
2288  }
2289 
2290  if (heap != NULL)
2291  {
2292  bh_destroy (thread_p, heap);
2293  }
2294 
2295  if (xasl->topn_items->tuples != NULL)
2296  {
2297  db_private_free_and_init (thread_p, xasl->topn_items->tuples);
2298  }
2299 
2300  db_private_free_and_init (thread_p, xasl->topn_items);
2301  }
2302 
2303  // clear trace stats
2304  memset (&xasl->orderby_stats, 0, sizeof (ORDERBY_STATS));
2305  memset (&xasl->groupby_stats, 0, sizeof (GROUPBY_STATS));
2306  memset (&xasl->xasl_stats, 0, sizeof (XASL_STATS));
2307  }
2308 
2309  switch (xasl->type)
2310  {
2311  case CONNECTBY_PROC:
2312  {
2313  CONNECTBY_PROC_NODE *connect_by = &xasl->proc.connect_by;
2314 
2315  pg_cnt += qexec_clear_pred (thread_p, xasl, connect_by->start_with_pred, is_final);
2316  pg_cnt += qexec_clear_pred (thread_p, xasl, connect_by->after_connect_by_pred, is_final);
2317 
2318  pg_cnt += qexec_clear_regu_list (thread_p, xasl, connect_by->regu_list_pred, is_final);
2319  pg_cnt += qexec_clear_regu_list (thread_p, xasl, connect_by->regu_list_rest, is_final);
2320 
2321  if (connect_by->prior_val_list)
2322  {
2324  }
2325  if (connect_by->prior_outptr_list)
2326  {
2327  pg_cnt += qexec_clear_regu_list (thread_p, xasl, connect_by->prior_outptr_list->valptrp, is_final);
2328  }
2329 
2330  pg_cnt += qexec_clear_regu_list (thread_p, xasl, connect_by->prior_regu_list_pred, is_final);
2331  pg_cnt += qexec_clear_regu_list (thread_p, xasl, connect_by->prior_regu_list_rest, is_final);
2332  pg_cnt += qexec_clear_regu_list (thread_p, xasl, connect_by->after_cb_regu_list_pred, is_final);
2333  pg_cnt += qexec_clear_regu_list (thread_p, xasl, connect_by->after_cb_regu_list_rest, is_final);
2334  }
2335  break;
2336 
2337  case BUILDLIST_PROC:
2338  {
2339  BUILDLIST_PROC_NODE *buildlist = &xasl->proc.buildlist;
2340 
2341  if (buildlist->eptr_list)
2342  {
2343  XASL_SET_FLAG (buildlist->eptr_list, decache_clone_flag);
2344  pg_cnt += qexec_clear_xasl (thread_p, buildlist->eptr_list, is_final);
2345  }
2346 
2347  if (buildlist->groupby_list)
2348  {
2349  qexec_clear_sort_list (xasl, buildlist->groupby_list, is_final);
2350  }
2351  if (buildlist->after_groupby_list)
2352  {
2353  qexec_clear_sort_list (xasl, buildlist->after_groupby_list, is_final);
2354  }
2355 
2356  if (xasl->curr_spec)
2357  {
2358  scan_end_scan (thread_p, &xasl->curr_spec->s_id);
2359  scan_close_scan (thread_p, &xasl->curr_spec->s_id);
2360  }
2361  if (xasl->merge_spec)
2362  {
2363  scan_end_scan (thread_p, &xasl->merge_spec->s_id);
2364  scan_close_scan (thread_p, &xasl->merge_spec->s_id);
2365  }
2366  if (buildlist->upddel_oid_locator_ehids != NULL)
2367  {
2368  qexec_destroy_upddel_ehash_files (thread_p, xasl);
2369  }
2370  if (is_final)
2371  {
2372  if (buildlist->g_outptr_list)
2373  {
2374  pg_cnt += qexec_clear_regu_list (thread_p, xasl, buildlist->g_outptr_list->valptrp, is_final);
2375  }
2376  pg_cnt += qexec_clear_regu_list (thread_p, xasl, buildlist->g_regu_list, is_final);
2377  if (buildlist->g_val_list)
2378  {
2379  qexec_clear_db_val_list (buildlist->g_val_list->valp);
2380  }
2381  pg_cnt += qexec_clear_agg_list (thread_p, xasl, buildlist->g_agg_list, is_final);
2382  pg_cnt += qexec_clear_pred (thread_p, xasl, buildlist->g_having_pred, is_final);
2383  pg_cnt += qexec_clear_pred (thread_p, xasl, buildlist->g_grbynum_pred, is_final);
2384  if (buildlist->g_grbynum_val)
2385  {
2386  pr_clear_value (buildlist->g_grbynum_val);
2387  }
2388 
2389  /* analytic functions */
2390  pg_cnt += qexec_clear_analytic_function_list (thread_p, xasl, buildlist->a_eval_list, is_final);
2391  pg_cnt += qexec_clear_regu_list (thread_p, xasl, buildlist->a_regu_list, is_final);
2392 
2393  /* group by regu list */
2394  if (buildlist->g_scan_regu_list)
2395  {
2396  pg_cnt += qexec_clear_regu_list (thread_p, xasl, buildlist->g_scan_regu_list, is_final);
2397  }
2398  if (buildlist->g_hk_scan_regu_list)
2399  {
2400  pg_cnt += qexec_clear_regu_list (thread_p, xasl, buildlist->g_hk_scan_regu_list, is_final);
2401  }
2402  if (buildlist->g_hk_sort_regu_list)
2403  {
2404  pg_cnt += qexec_clear_regu_list (thread_p, xasl, buildlist->g_hk_sort_regu_list, is_final);
2405  }
2406 
2407  if (buildlist->a_outptr_list)
2408  {
2409  pg_cnt += qexec_clear_regu_list (thread_p, xasl, buildlist->a_outptr_list->valptrp, is_final);
2410  }
2411  if (buildlist->a_outptr_list_ex)
2412  {
2413  pg_cnt += qexec_clear_regu_list (thread_p, xasl, buildlist->a_outptr_list_ex->valptrp, is_final);
2414  }
2415  if (buildlist->a_outptr_list_interm)
2416  {
2417  pg_cnt += qexec_clear_regu_list (thread_p, xasl, buildlist->a_outptr_list_interm->valptrp, is_final);
2418  }
2419  if (buildlist->a_val_list)
2420  {
2421  qexec_clear_db_val_list (buildlist->a_val_list->valp);
2422  }
2423  if (buildlist->g_hash_eligible)
2424  {
2425  qexec_free_agg_hash_context (thread_p, buildlist);
2426  }
2427  }
2428  }
2429  break;
2430 
2431  case OBJFETCH_PROC:
2432  if (is_final)
2433  {
2434  FETCH_PROC_NODE *fetch = &xasl->proc.fetch;
2435 
2436  pg_cnt += qexec_clear_pred (thread_p, xasl, fetch->set_pred, is_final);
2437  pr_clear_value (fetch->arg);
2438  }
2439  break;
2440 
2441  case BUILDVALUE_PROC:
2442  {
2443  BUILDVALUE_PROC_NODE *buildvalue = &xasl->proc.buildvalue;
2444 
2445  if (xasl->curr_spec)
2446  {
2447  scan_end_scan (thread_p, &xasl->curr_spec->s_id);
2448  scan_close_scan (thread_p, &xasl->curr_spec->s_id);
2449  }
2450  if (xasl->merge_spec)
2451  {
2452  scan_end_scan (thread_p, &xasl->merge_spec->s_id);
2453  scan_close_scan (thread_p, &xasl->merge_spec->s_id);
2454  }
2455  if (is_final)
2456  {
2457  pg_cnt += qexec_clear_agg_list (thread_p, xasl, buildvalue->agg_list, is_final);
2458  pg_cnt += qexec_clear_arith_list (thread_p, xasl, buildvalue->outarith_list, is_final);
2459  pg_cnt += qexec_clear_pred (thread_p, xasl, buildvalue->having_pred, is_final);
2460  if (buildvalue->grbynum_val)
2461  {
2462  pr_clear_value (buildvalue->grbynum_val);
2463  }
2464  }
2465  }
2466  break;
2467 
2468  case SCAN_PROC:
2469  if (xasl->curr_spec)
2470  {
2471  scan_end_scan (thread_p, &xasl->curr_spec->s_id);
2472  scan_close_scan (thread_p, &xasl->curr_spec->s_id);
2473  }
2474  break;
2475 
2476  case MERGE_PROC:
2477  if (xasl->proc.merge.update_xasl)
2478  {
2479  XASL_SET_FLAG (xasl->proc.merge.update_xasl, decache_clone_flag);
2480  pg_cnt += qexec_clear_xasl (thread_p, xasl->proc.merge.update_xasl, is_final);
2481  }
2482  if (xasl->proc.merge.insert_xasl)
2483  {
2484  XASL_SET_FLAG (xasl->proc.merge.insert_xasl, decache_clone_flag);
2485  pg_cnt += qexec_clear_xasl (thread_p, xasl->proc.merge.insert_xasl, is_final);
2486  }
2487  break;
2488 
2489  case UPDATE_PROC:
2490  {
2491  int i;
2492  UPDATE_ASSIGNMENT *assignment = NULL;
2493 
2494  pg_cnt += qexec_clear_pred (thread_p, xasl, xasl->proc.update.cons_pred, is_final);
2495 
2496  for (i = 0; i < xasl->proc.update.num_assigns; i++)
2497  {
2498  assignment = &(xasl->proc.update.assigns[i]);
2499  pg_cnt += qexec_clear_update_assignment (thread_p, xasl, assignment, is_final);
2500  }
2501  }
2502  break;
2503 
2504  case INSERT_PROC:
2505  if (xasl->proc.insert.odku != NULL)
2506  {
2507  int i;
2508  UPDATE_ASSIGNMENT *assignment = NULL;
2509 
2510  pg_cnt += qexec_clear_pred (thread_p, xasl, xasl->proc.insert.odku->cons_pred, is_final);
2511 
2512  for (i = 0; i < xasl->proc.insert.odku->num_assigns; i++)
2513  {
2514  assignment = &(xasl->proc.insert.odku->assignments[i]);
2515  pg_cnt += qexec_clear_update_assignment (thread_p, xasl, assignment, is_final);
2516  }
2517  }
2518  if (xasl->proc.insert.valptr_lists != NULL && xasl->proc.insert.num_val_lists > 0)
2519  {
2520  int i;
2521  VALPTR_LIST *valptr_list = NULL;
2522  REGU_VARIABLE_LIST regu_list = NULL;
2523 
2524  for (i = 0; i < xasl->proc.insert.num_val_lists; i++)
2525  {
2526  valptr_list = xasl->proc.insert.valptr_lists[i];
2527  for (regu_list = valptr_list->valptrp; regu_list != NULL; regu_list = regu_list->next)
2528  {
2529  pg_cnt += qexec_clear_regu_var (thread_p, xasl, &regu_list->value, is_final);
2530  }
2531  }
2532  }
2533  break;
2534 
2535  case CTE_PROC:
2536  if (xasl->proc.cte.non_recursive_part)
2537  {
2538  if (xasl->proc.cte.non_recursive_part->list_id)
2539  {
2541  }
2542 
2543  if (XASL_IS_FLAGED (xasl, XASL_DECACHE_CLONE) && xasl->proc.cte.non_recursive_part->status != XASL_CLEARED)
2544  {
2545  /* non_recursive_part not cleared yet. Set flag to clear the values allocated at unpacking. */
2547  pg_cnt += qexec_clear_xasl (thread_p, xasl->proc.cte.non_recursive_part, is_final);
2548  }
2549  else if (!XASL_IS_FLAGED (xasl, XASL_DECACHE_CLONE)
2550  && xasl->proc.cte.non_recursive_part->status != XASL_INITIALIZED)
2551  {
2552  /* non_recursive_part not cleared yet. Set flag to clear the values allocated at unpacking. */
2553  pg_cnt += qexec_clear_xasl (thread_p, xasl->proc.cte.non_recursive_part, is_final);
2554  }
2555  }
2556  if (xasl->proc.cte.recursive_part)
2557  {
2558  if (xasl->proc.cte.recursive_part->list_id)
2559  {
2561  }
2562 
2563  if (XASL_IS_FLAGED (xasl, XASL_DECACHE_CLONE) && xasl->proc.cte.recursive_part->status != XASL_CLEARED)
2564  {
2565  /* recursive_part not cleared yet. Set flag to clear the values allocated at unpacking. */
2567  pg_cnt += qexec_clear_xasl (thread_p, xasl->proc.cte.recursive_part, is_final);
2568  }
2569  else if (!XASL_IS_FLAGED (xasl, XASL_DECACHE_CLONE)
2570  && xasl->proc.cte.recursive_part->status != XASL_INITIALIZED)
2571  {
2572  /* recursive_part not cleared yet. Set flag to clear the values allocated at unpacking. */
2573  pg_cnt += qexec_clear_xasl (thread_p, xasl->proc.cte.recursive_part, is_final);
2574  }
2575  }
2576  if (xasl->list_id)
2577  {
2578  qfile_clear_list_id (xasl->list_id);
2579  }
2580  break;
2581 
2582  default:
2583  break;
2584  } /* switch */
2585 
2586  /* Note: Here reset the current pointer to access specification nodes. This is needed because this XASL tree may be
2587  * used again if this thread is suspended and restarted. */
2588  xasl->curr_spec = NULL;
2589 
2590  /* clear the next xasl node */
2591 
2592  if (xasl->next)
2593  {
2594  XASL_SET_FLAG (xasl->next, decache_clone_flag);
2595  pg_cnt += qexec_clear_xasl (thread_p, xasl->next, is_final);
2596  }
2597 
2598  xasl->query_in_progress = query_save_state;
2599 
2600  return pg_cnt;
2601 }
2602 
2603 /*
2604  * qexec_clear_head_lists () -
2605  * return:
2606  * xasl_list(in) : List of XASL procedure blocks
2607  *
2608  * Note: Traverse through the given list of XASL procedure blocks and
2609  * clean/destroy results generated by interpretation of these
2610  * blocks such as list files generated.
2611  */
2612 static void
2614 {
2615  XASL_NODE *xasl;
2616 
2617  for (xasl = xasl_list; xasl != NULL; xasl = xasl->next)
2618  {
2620  {
2621  /* skip out zero correlation-level uncorrelated subquery */
2622  continue;
2623  }
2624  /* clear XASL head node */
2625  (void) qexec_clear_xasl_head (thread_p, xasl);
2626  }
2627 }
2628 
2629 /*
2630  * qexec_clear_scan_all_lists () -
2631  * return:
2632  * xasl_list(in) :
2633  */
2634 static void
2636 {
2637  XASL_NODE *xasl;
2638 
2639  for (xasl = xasl_list; xasl != NULL; xasl = xasl->scan_ptr)
2640  {
2641  if (xasl->bptr_list)
2642  {
2643  qexec_clear_head_lists (thread_p, xasl->bptr_list);
2644  }
2645  if (xasl->fptr_list)
2646  {
2647  qexec_clear_head_lists (thread_p, xasl->fptr_list);
2648  }
2649  if (xasl->dptr_list)
2650  {
2651  qexec_clear_head_lists (thread_p, xasl->dptr_list);
2652  }
2653  }
2654 }
2655 
2656 /*
2657  * qexec_clear_all_lists () -
2658  * return:
2659  * xasl_list(in) :
2660  */
2661 static void
2663 {
2664  XASL_NODE *xasl;
2665 
2666  for (xasl = xasl_list; xasl != NULL; xasl = xasl->next)
2667  {
2668  /* check for NULL pointers before doing pointless procedure calls. This procedure is called once per row, and
2669  * typically will have many or all of these xasl sublists NULL. In the limiting case of scanning rows as fast as
2670  * possible, these empty procedure calls amounted to several percent of the cpu time. */
2671  if (xasl->bptr_list)
2672  {
2673  qexec_clear_all_lists (thread_p, xasl->bptr_list);
2674  }
2675  if (xasl->fptr_list)
2676  {
2677  qexec_clear_all_lists (thread_p, xasl->fptr_list);
2678  }
2679 
2680  /* Note: Dptr lists are only procedure blocks (other than aptr_list) which can produce a LIST FILE. Therefore, we
2681  * are trying to clear all the dptr_list result LIST FILES in the XASL tree per iteration. */
2682  if (xasl->dptr_list)
2683  {
2684  qexec_clear_head_lists (thread_p, xasl->dptr_list);
2685  }
2686 
2687  if (xasl->scan_ptr)
2688  {
2689  qexec_clear_scan_all_lists (thread_p, xasl->scan_ptr);
2690  }
2691  }
2692 }
2693 
2694 /*
2695  * qexec_clear_update_assignment () - clear update assignement
2696  * return: clear count
2697  * thread_p(in) : thread entry
2698  * assignment(in) : the assignment
2699  * is_final(in) : true, if finalize needed
2700  */
2701 static int
2703  bool is_final)
2704 {
2705  int pg_cnt;
2706 
2707  pg_cnt = 0;
2708  if (XASL_IS_FLAGED (xasl_p, XASL_DECACHE_CLONE))
2709  {
2710  if (assignment->clear_value_at_clone_decache)
2711  {
2712  /* clear the value since we decache the XASL clone. */
2713  (void) pr_clear_value (assignment->constant);
2714  }
2715  }
2716  else
2717  {
2718  if (!assignment->clear_value_at_clone_decache)
2719  {
2720  /* clear the value since we decache the XASL (not a clone). */
2721  (void) pr_clear_value (assignment->constant);
2722  }
2723  }
2724 
2725  if (assignment->regu_var != NULL)
2726  {
2727  pg_cnt += qexec_clear_regu_var (thread_p, xasl_p, assignment->regu_var, is_final);
2728  }
2729 
2730  return pg_cnt;
2731 }
2732 
2733 /*
2734  * qexec_get_xasl_list_id () -
2735  * return: QFILE_LIST_ID *, or NULL
2736  * xasl(in) : XASL Tree procedure block
2737  *
2738  * Note: Extract the list file identifier from the head node of the
2739  * specified XASL tree procedure block. This represents the
2740  * result of the interpretation of the block.
2741  */
2742 qfile_list_id *
2744 {
2745  QFILE_LIST_ID *list_id = (QFILE_LIST_ID *) NULL;
2746  VAL_LIST *single_tuple;
2747  QPROC_DB_VALUE_LIST value_list;
2748  int i;
2749 
2750  if (xasl->list_id)
2751  {
2752  /* allocate region for list file identifier */
2753  list_id = (QFILE_LIST_ID *) malloc (sizeof (QFILE_LIST_ID));
2754  if (list_id == NULL)
2755  {
2756  return (QFILE_LIST_ID *) NULL;
2757  }
2758 
2759  QFILE_CLEAR_LIST_ID (list_id);
2760  if (qfile_copy_list_id (list_id, xasl->list_id, true) != NO_ERROR)
2761  {
2762  QFILE_FREE_AND_INIT_LIST_ID (list_id);
2763  return (QFILE_LIST_ID *) NULL;
2764  }
2765  qfile_clear_list_id (xasl->list_id);
2766  }
2767 
2768  single_tuple = xasl->single_tuple;
2769  if (single_tuple)
2770  {
2771  /* clear result value */
2772  for (value_list = single_tuple->valp, i = 0; i < single_tuple->val_cnt; value_list = value_list->next, i++)
2773  {
2774  pr_clear_value (value_list->val);
2775  }
2776  }
2777 
2778  return list_id;
2779 }
2780 
2781 /*
2782  * qexec_eval_ordbynum_pred () -
2783  * return:
2784  * ordby_info(in) :
2785  */
2786 static DB_LOGICAL
2788 {
2789  DB_LOGICAL ev_res;
2790 
2791  if (ordby_info->ordbynum_val)
2792  {
2793  /* Increment the value of orderby_num() used for "order by" numbering */
2794  ordby_info->ordbynum_val->data.bigint++;
2795  }
2796 
2797  if (ordby_info->ordbynum_pred)
2798  {
2799  /*
2800  * Evaluate the predicate.
2801  * CUBRID does not currently support such predicates in WHERE condition
2802  * lists but might support them in future versions (see the usage of
2803  * MSGCAT_SEMANTIC_ORDERBYNUM_SELECT_LIST_ERR). Currently such
2804  * predicates must only be used with the "order by [...] for [...]"
2805  * syntax.
2806  * Sample query:
2807  * select * from participant
2808  * order by silver for orderby_num() between 1 and 10;
2809  * Invalid query (at present):
2810  * select * from participant where orderby_num() between 1 and 10
2811  * order by silver;
2812  */
2813  ev_res = eval_pred (thread_p, ordby_info->ordbynum_pred, &ordby_info->xasl_state->vd, NULL);
2814  switch (ev_res)
2815  {
2816  case V_FALSE:
2817  if (ordby_info->ordbynum_flag & XASL_ORDBYNUM_FLAG_SCAN_CHECK)
2818  {
2819  /* If in the "scan check" mode then signal that the scan should stop, as there will be no more tuples to
2820  * return. */
2822  }
2823  break;
2824  case V_TRUE:
2825  /* The predicate evaluated as true. It is possible that we are in the "continue scan" mode, indicated by
2826  * XASL_ORDBYNUM_FLAG_SCAN_CONTINUE. This mode means we should continue evaluating the predicate for all the
2827  * other tuples because the predicate is complex and we cannot predict its vale. If the predicate is very
2828  * simple we can predict that it will be true for a single range of tuples, like the range in the following
2829  * example: Tuple1 Tuple2 Tuple3 Tuple4 Tuple5 Tuple6 Tuple7 Tuple8 Tuple9 False False False True True True
2830  * True False False When we find the first true predicate we set the "scan check" mode. */
2831  if (!(ordby_info->ordbynum_flag & XASL_ORDBYNUM_FLAG_SCAN_CONTINUE)
2832  && !(ordby_info->ordbynum_flag & XASL_ORDBYNUM_FLAG_SCAN_CHECK))
2833  {
2835  }
2836  break;
2837  case V_ERROR:
2838  break;
2839  case V_UNKNOWN:
2840  default:
2841  break;
2842  }
2843  }
2844  else
2845  {
2846  /* No predicate was given so no filtering is required. */
2847  ev_res = V_TRUE;
2848  }
2849 
2850  return ev_res;
2851 }
2852 
2853 /*
2854  * qexec_ordby_put_next () -
2855  * return:
2856  * recdes(in) :
2857  * arg(in) :
2858  */
2859 static int
2860 qexec_ordby_put_next (THREAD_ENTRY * thread_p, const RECDES * recdes, void *arg)
2861 {
2862  SORT_INFO *info;
2863  SORT_REC *key;
2864  char *data, *tvalhp;
2865  int tval_size;
2866  ORDBYNUM_INFO *ordby_info;
2867  PAGE_PTR page;
2868  VPID ovfl_vpid;
2869  DB_LOGICAL ev_res;
2870  int error;
2871  int i;
2872  VPID vpid;
2873  QFILE_LIST_ID *list_idp;
2874  QFILE_TUPLE_RECORD tplrec;
2875 
2876  error = NO_ERROR;
2877 
2878  info = (SORT_INFO *) arg;
2879  ordby_info = (ORDBYNUM_INFO *) info->extra_arg;
2880 
2881  /* Traverse next link */
2882  for (key = (SORT_REC *) recdes->data; key && error == NO_ERROR; key = key->next)
2883  {
2884  ev_res = V_TRUE;
2885  if (ordby_info != NULL && ordby_info->ordbynum_val)
2886  {
2887  /* evaluate orderby_num predicates */
2888  ev_res = qexec_eval_ordbynum_pred (thread_p, ordby_info);
2889  if (ev_res == V_ERROR)
2890  {
2891  assert (er_errid () != NO_ERROR);
2892  return er_errid ();
2893  }
2894  if (ordby_info->ordbynum_flag & XASL_ORDBYNUM_FLAG_SCAN_STOP)
2895  {
2896  /* reset ordbynum_val for next use */
2897  db_make_bigint (ordby_info->ordbynum_val, 0);
2898  /* setting SORT_PUT_STOP will make 'sr_in_sort()' stop processing; the caller, 'qexec_gby_put_next()',
2899  * returns 'gbstate->state' */
2900  return SORT_PUT_STOP;
2901  }
2902  }
2903 
2904  if (ordby_info != NULL && ev_res == V_TRUE)
2905  {
2906  if (info->key_info.use_original)
2907  { /* P_sort_key */
2908  /* We need to consult the original file for the bonafide tuple. The SORT_REC only kept the keys that we
2909  * needed so that we wouldn't have to drag them around while we were sorting. */
2910 
2911  list_idp = &(info->s_id->s_id->list_id);
2912  vpid.pageid = key->s.original.pageid;
2913  vpid.volid = key->s.original.volid;
2914 
2915 #if 0 /* SortCache */
2916  /* check if page is already fixed */
2917  if (VPID_EQ (&(info->fixed_vpid), &vpid))
2918  {
2919  /* use cached page pointer */
2920  page = info->fixed_page;
2921  }
2922  else
2923  {
2924  /* free currently fixed page */
2925  if (info->fixed_page != NULL)
2926  {
2927  qmgr_free_old_page_and_init (info->fixed_page, list_idp->tfile_vfid);
2928  }
2929 
2930  /* fix page and cache fixed vpid */
2931  page = qmgr_get_old_page (&vpid, list_idp->tfile_vfid);
2932  if (page == NULL)
2933  {
2934  assert (er_errid () != NO_ERROR);
2935  return er_errid ();
2936  }
2937 
2938  /* cache page pointer */
2939  info->fixed_vpid = vpid;
2940  info->fixed_page = page;
2941  } /* else */
2942 #else
2943  page = qmgr_get_old_page (thread_p, &vpid, list_idp->tfile_vfid);
2944  if (page == NULL)
2945  {
2946  assert (er_errid () != NO_ERROR);
2947  return er_errid ();
2948  }
2949 #endif
2950 
2951  QFILE_GET_OVERFLOW_VPID (&ovfl_vpid, page);
2952 
2953  if (ovfl_vpid.pageid == NULL_PAGEID)
2954  {
2955  /* This is the normal case of a non-overflow tuple. We can use the page image directly, since we know
2956  * that the tuple resides entirely on that page. */
2957  data = page + key->s.original.offset;
2958 
2959  /* update orderby_num() in the tuple */
2960  for (i = 0; ordby_info && i < ordby_info->ordbynum_pos_cnt; i++)
2961  {
2962  QFILE_GET_TUPLE_VALUE_HEADER_POSITION (data, ordby_info->ordbynum_pos[i], tvalhp);
2963  (void) qdata_copy_db_value_to_tuple_value (ordby_info->ordbynum_val, true, tvalhp, &tval_size);
2964  }
2965 
2966  error = qfile_add_tuple_to_list (thread_p, info->output_file, data);
2967  }
2968  else
2969  {
2970  assert (NULL_PAGEID < ovfl_vpid.pageid); /* should not be NULL_PAGEID_IN_PROGRESS */
2971 
2972  /* Rats; this tuple requires overflow pages. We need to copy all of the pages from the input file to
2973  * the output file. */
2974  if (ordby_info && ordby_info->ordbynum_pos_cnt > 0)
2975  {
2976  /* I think this way is very inefficient. */
2977  tplrec.size = 0;
2978  tplrec.tpl = NULL;
2979  qfile_get_tuple (thread_p, page, page + key->s.original.offset, &tplrec, list_idp);
2980  data = tplrec.tpl;
2981  /* update orderby_num() in the tuple */
2982  for (i = 0; ordby_info && i < ordby_info->ordbynum_pos_cnt; i++)
2983  {
2984  QFILE_GET_TUPLE_VALUE_HEADER_POSITION (data, ordby_info->ordbynum_pos[i], tvalhp);
2985  (void) qdata_copy_db_value_to_tuple_value (ordby_info->ordbynum_val, true, tvalhp,
2986  &tval_size);
2987  }
2988  error = qfile_add_tuple_to_list (thread_p, info->output_file, data);
2989  db_private_free_and_init (thread_p, tplrec.tpl);
2990  }
2991  else
2992  {
2993  error = qfile_add_overflow_tuple_to_list (thread_p, info->output_file, page, list_idp);
2994  }
2995  }
2996 #if 1 /* SortCache */
2997  qmgr_free_old_page_and_init (thread_p, page, list_idp->tfile_vfid);
2998 #endif
2999  }
3000  else
3001  { /* A_sort_key */
3002  /* We didn't record the original vpid, and we should just reconstruct the original record from this sort
3003  * key (rather than pressure the page buffer pool by reading in the original page to get the original
3004  * tuple) */
3005 
3006  if (qfile_generate_sort_tuple (&info->key_info, key, &info->output_recdes) == NULL)
3007  {
3008  error = ER_FAILED;
3009  }
3010  else
3011  {
3012  data = info->output_recdes.data;
3013  /* update orderby_num() in the tuple */
3014  for (i = 0; ordby_info && i < ordby_info->ordbynum_pos_cnt; i++)
3015  {
3016  QFILE_GET_TUPLE_VALUE_HEADER_POSITION (data, ordby_info->ordbynum_pos[i], tvalhp);
3017  (void) qdata_copy_db_value_to_tuple_value (ordby_info->ordbynum_val, true, tvalhp, &tval_size);
3018  }
3019  error = qfile_add_tuple_to_list (thread_p, info->output_file, data);
3020  }
3021  }
3022 
3023  } /* if (ev_res == V_TRUE) */
3024 
3025  } /* for (key = (SORT_REC *) recdes->data; ...) */
3026 
3027  return (error == NO_ERROR) ? NO_ERROR : er_errid ();
3028 }
3029 
3030 
3031 /*
3032  * qexec_fill_sort_limit () - gets the ordbynum max and saves it to the XASL
3033  * return: NO_ERROR or error code on failure
3034  * thread_p(in) :
3035  * xasl(in) :
3036  * xasl_state(in):
3037  * limit_ptr(in) : pointer to an integer which will store the max
3038  *
3039  * Note: The "LIMIT 10" from a query gets translated into a pred expr
3040  * like ordby_num < ?. At xasl generation we save the "?" as a
3041  * regu-var, defining the maximum. The regu var is most likely
3042  * to contain host variables, so we can only interpret it at
3043  * runtime. This is the function's purpose: get an integer from
3044  * the XASL to represent the upper bound for the sorted results.
3045  */
3046 static int
3047 qexec_fill_sort_limit (THREAD_ENTRY * thread_p, XASL_NODE * xasl, XASL_STATE * xasl_state, int *limit_ptr)
3048 {
3049  DB_VALUE *dbvalp = NULL;
3051  DB_TYPE orig_type;
3052  int error = NO_ERROR;
3053 
3054  if (limit_ptr == NULL)
3055  {
3057  return ER_FAILED;
3058  }
3059 
3060  *limit_ptr = NO_SORT_LIMIT;
3061 
3062  /* If this option is disabled, keep the limit negative (NO_SORT_LIMIT). */
3064  {
3065  return NO_ERROR;
3066  }
3067 
3068  if (fetch_peek_dbval (thread_p, xasl->orderby_limit, &xasl_state->vd, NULL, NULL, NULL, &dbvalp) != NO_ERROR)
3069  {
3070  return ER_FAILED;
3071  }
3072 
3073  orig_type = DB_VALUE_DOMAIN_TYPE (dbvalp);
3074 
3075  if (orig_type != DB_TYPE_INTEGER)
3076  {
3077  TP_DOMAIN_STATUS dom_status;
3078 
3079  dom_status = tp_value_coerce (dbvalp, dbvalp, domainp);
3080  if (dom_status != DOMAIN_COMPATIBLE)
3081  {
3082  if (dom_status == DOMAIN_OVERFLOW)
3083  {
3084  /* The limit is too bog to fit an integer. However, since this limit is used to keep the sort run flushes
3085  * small (for instance only keep the first 10 elements of each run if ORDER BY LIMIT 10 is specified),
3086  * there is no conceivable way this limit would be useful if it is larger than 2.147 billion: such a
3087  * large run is infeasible anyway. So if it does not fit into an integer, discard it. */
3088  return NO_ERROR;
3089  }
3090  else
3091  {
3092  error = tp_domain_status_er_set (dom_status, ARG_FILE_LINE, dbvalp, domainp);
3093  return error;
3094  }
3095  }
3096 
3097  if (DB_VALUE_DOMAIN_TYPE (dbvalp) != DB_TYPE_INTEGER)
3098  {
3100  return ER_FAILED;
3101  }
3102  }
3103 
3104  *limit_ptr = db_get_int (dbvalp);
3105  if (*limit_ptr < 0)
3106  {
3107  /* If the limit is below 0, set it to 0 and still return success. */
3108  *limit_ptr = 0;
3109  }
3110 
3111  return NO_ERROR;
3112 }
3113 
3114 /*
3115  * qexec_orderby_distinct () -
3116  * return: NO_ERROR, or ER_code
3117  * xasl(in) :
3118  * option(in) : Distinct/All indication flag
3119  * xasl_state(in) : Ptr to the XASL_STATE for this tree
3120  *
3121  */
3122 static int
3124 {
3125  int error = NO_ERROR;
3126 
3127  TSC_TICKS start_tick, end_tick;
3128  TSCTIMEVAL tv_diff;
3129 
3130  UINT64 old_sort_pages = 0, old_sort_ioreads = 0;
3131 
3132  if (thread_is_on_trace (thread_p))
3133  {
3134  tsc_getticks (&start_tick);
3135 
3136  if (xasl->orderby_stats.orderby_filesort)
3137  {
3138  old_sort_pages = perfmon_get_from_statistic (thread_p, PSTAT_SORT_NUM_DATA_PAGES);
3139  old_sort_ioreads = perfmon_get_from_statistic (thread_p, PSTAT_SORT_NUM_IO_PAGES);
3140  }
3141  }
3142 
3143  if (xasl->topn_items != NULL)
3144  {
3145  /* already sorted, just dump tuples to list */
3146  error = qexec_topn_tuples_to_list_id (thread_p, xasl, xasl_state, true);
3147  }
3148  else
3149  {
3150  error = qexec_orderby_distinct_by_sorting (thread_p, xasl, option, xasl_state);
3151  }
3152 
3153  if (thread_is_on_trace (thread_p))
3154  {
3155  tsc_getticks (&end_tick);
3156  tsc_elapsed_time_usec (&tv_diff, end_tick, start_tick);
3157  TSC_ADD_TIMEVAL (xasl->orderby_stats.orderby_time, tv_diff);
3158 
3159  if (xasl->orderby_stats.orderby_filesort)
3160  {
3161  xasl->orderby_stats.orderby_pages = (perfmon_get_from_statistic (thread_p, PSTAT_SORT_NUM_DATA_PAGES)
3162  - old_sort_pages);
3163  xasl->orderby_stats.orderby_ioreads = (perfmon_get_from_statistic (thread_p, PSTAT_SORT_NUM_IO_PAGES)
3164  - old_sort_ioreads);
3165  }
3166  }
3167 
3168  return error;
3169 }
3170 
3171 /*
3172  * qexec_orderby_distinct_by_sorting () -
3173  * return: NO_ERROR, or ER_code
3174  * xasl(in) :
3175  * option(in) : Distinct/All indication flag
3176  * xasl_state(in) : Ptr to the XASL_STATE for this tree
3177  *
3178  * Note: Depending on the indicated set of sorting items and the value
3179  * of the distinct/all option, the given list file is sorted on
3180  * several columns and/or duplications are eliminated. If only
3181  * duplication elimination is specified and all the columns of the
3182  * list file contains orderable types (non-sets), first the list
3183  * file is sorted on all columns and then duplications are
3184  * eliminated on the fly, thus causing and ordered-distinct list file output.
3185  */
3186 static int
3189 {
3190  QFILE_LIST_ID *list_id = xasl->list_id;
3191  SORT_LIST *order_list = xasl->orderby_list;
3192  PRED_EXPR *ordbynum_pred = xasl->ordbynum_pred;
3193  DB_VALUE *ordbynum_val = xasl->ordbynum_val;
3194  int ordbynum_flag = xasl->ordbynum_flag;
3195  OUTPTR_LIST *outptr_list;
3196  SORT_LIST *orderby_ptr, *order_ptr, *orderby_list;
3197  SORT_LIST *order_ptr2, temp_ord;
3198  bool orderby_alloc = false;
3199  int k, n, i, ls_flag;
3200  ORDBYNUM_INFO ordby_info;
3201  REGU_VARIABLE_LIST regu_list;
3202  SORT_PUT_FUNC *put_fn;
3203  int limit;
3204  int error = NO_ERROR;
3205 
3206  xasl->orderby_stats.orderby_filesort = true;
3207 
3208  if (xasl->type == BUILDLIST_PROC)
3209  {
3210  /* choose appropriate list */
3211  if (xasl->proc.buildlist.groupby_list != NULL)
3212  {
3213  outptr_list = xasl->proc.buildlist.g_outptr_list;
3214  }
3215  else if (xasl->proc.buildlist.a_eval_list != NULL)
3216  {
3217  outptr_list = xasl->proc.buildlist.a_outptr_list;
3218  }
3219  else
3220  {
3221  outptr_list = xasl->outptr_list;
3222  }
3223  }
3224  else
3225  {
3226  outptr_list = xasl->outptr_list;
3227  }
3228 
3229  /* late binding : resolve sort list */
3230  if (outptr_list != NULL)
3231  {
3232  qexec_resolve_domains_on_sort_list (order_list, outptr_list->valptrp);
3233  }
3234 
3235  if (order_list == NULL && option != Q_DISTINCT)
3236  {
3237  return NO_ERROR;
3238  }
3239 
3240  memset (&ordby_info, 0, sizeof (ORDBYNUM_INFO));
3241 
3242  /* sort the result list file */
3243  /* form the linked list of sort type items */
3244  if (option != Q_DISTINCT)
3245  {
3246  orderby_list = order_list;
3247  orderby_alloc = false;
3248  }
3249  else
3250  {
3251  /* allocate space for sort list */
3252  orderby_list = qfile_allocate_sort_list (thread_p, list_id->type_list.type_cnt);
3253  if (orderby_list == NULL)
3254  {
3255  error = ER_FAILED;
3257  }
3258 
3259  /* form an order_by list including all list file positions */
3260  orderby_alloc = true;
3261  for (k = 0, order_ptr = orderby_list; k < list_id->type_list.type_cnt; k++, order_ptr = order_ptr->next)
3262  {
3263  /* sort with descending order if we have the use_desc hint and no order by */
3264  if (order_list == NULL && xasl->spec_list && xasl->spec_list->indexptr
3265  && xasl->spec_list->indexptr->use_desc_index)
3266  {
3267  order_ptr->s_order = S_DESC;
3268  order_ptr->s_nulls = S_NULLS_LAST;
3269  }
3270  else
3271  {
3272  order_ptr->s_order = S_ASC;
3273  order_ptr->s_nulls = S_NULLS_FIRST;
3274  }
3275  order_ptr->pos_descr.dom = list_id->type_list.domp[k];
3276  order_ptr->pos_descr.pos_no = k;
3277  } /* for */
3278 
3279  /* put the original order_by specifications, if any, to the beginning of the order_by list. */
3280  for (orderby_ptr = order_list, order_ptr = orderby_list; orderby_ptr != NULL;
3281  orderby_ptr = orderby_ptr->next, order_ptr = order_ptr->next)
3282  {
3283  /* save original content */
3284  temp_ord.s_order = order_ptr->s_order;
3285  temp_ord.s_nulls = order_ptr->s_nulls;
3286  temp_ord.pos_descr.dom = order_ptr->pos_descr.dom;
3287  temp_ord.pos_descr.pos_no = order_ptr->pos_descr.pos_no;
3288 
3289  /* put original order_by node */
3290  order_ptr->s_order = orderby_ptr->s_order;
3291  order_ptr->s_nulls = orderby_ptr->s_nulls;
3292  order_ptr->pos_descr.dom = orderby_ptr->pos_descr.dom;
3293  order_ptr->pos_descr.pos_no = orderby_ptr->pos_descr.pos_no;
3294 
3295  /* put temporary node into old order_by node position */
3296  for (order_ptr2 = order_ptr->next; order_ptr2 != NULL; order_ptr2 = order_ptr2->next)
3297  {
3298  if (orderby_ptr->pos_descr.pos_no == order_ptr2->pos_descr.pos_no)
3299  {
3300  order_ptr2->s_order = temp_ord.s_order;
3301  order_ptr2->s_nulls = temp_ord.s_nulls;
3302  order_ptr2->pos_descr.dom = temp_ord.pos_descr.dom;
3303  order_ptr2->pos_descr.pos_no = temp_ord.pos_descr.pos_no;
3304  break; /* immediately exit inner loop */
3305  }
3306  }
3307  }
3308 
3309  } /* if-else */
3310 
3311  /* sort the list file */
3312  ordby_info.ordbynum_pos_cnt = 0;
3313  ordby_info.ordbynum_pos = ordby_info.reserved;
3314  if (outptr_list)
3315  {
3316  for (n = 0, regu_list = outptr_list->valptrp; regu_list; regu_list = regu_list->next)
3317  {
3318  if (regu_list->value.type == TYPE_ORDERBY_NUM)
3319  {
3320  n++;
3321  }
3322  }
3323  ordby_info.ordbynum_pos_cnt = n;
3324  if (n > 2)
3325  {
3326  ordby_info.ordbynum_pos = (int *) db_private_alloc (thread_p, sizeof (int) * n);
3327  if (ordby_info.ordbynum_pos == NULL)
3328  {
3329  error = ER_FAILED;
3331  }
3332  }
3333 
3334  for (n = 0, i = 0, regu_list = outptr_list->valptrp; regu_list; regu_list = regu_list->next, i++)
3335  {
3336  if (regu_list->value.type == TYPE_ORDERBY_NUM)
3337  {
3338  ordby_info.ordbynum_pos[n++] = i;
3339  }
3340  }
3341  }
3342 
3343  ordby_info.xasl_state = xasl_state;
3344  ordby_info.ordbynum_pred = ordbynum_pred;
3345  ordby_info.ordbynum_val = ordbynum_val;
3346  ordby_info.ordbynum_flag = ordbynum_flag;
3347  put_fn = (ordbynum_val) ? &qexec_ordby_put_next : NULL;
3348 
3349  if (ordbynum_val == NULL && orderby_list && qfile_is_sort_list_covered (list_id->sort_list, orderby_list) == true
3350  && option != Q_DISTINCT)
3351  {
3352  /* no need to sort here */
3353  }
3354  else
3355  {
3356  ls_flag = ((option == Q_DISTINCT) ? QFILE_FLAG_DISTINCT : QFILE_FLAG_ALL);
3357  /* If this is the top most XASL, then the list file to be open will be the last result file. (Note that 'order
3358  * by' is the last processing.) */
3360  {
3362  }
3363 
3364  limit = NO_SORT_LIMIT;
3365  if (qexec_fill_sort_limit (thread_p, xasl, xasl_state, &limit) != NO_ERROR)
3366  {
3367  error = ER_FAILED;
3369  }
3370 
3371  list_id =
3372  qfile_sort_list_with_func (thread_p, list_id, orderby_list, option, ls_flag, NULL, put_fn, NULL, &ordby_info,
3373  limit, true);
3374  if (list_id == NULL)
3375  {
3376  error = ER_FAILED;
3378  }
3379  }
3380 
3381 exit_on_error:
3382  if (ordby_info.ordbynum_pos && ordby_info.ordbynum_pos != ordby_info.reserved)
3383  {
3384  db_private_free_and_init (thread_p, ordby_info.ordbynum_pos);
3385  }
3386 
3387  /* free temporarily allocated areas */
3388  if (orderby_alloc == true)
3389  {
3390  qfile_free_sort_list (thread_p, orderby_list);
3391  }
3392 
3393  return error;
3394 }
3395 
3396 /*
3397  * qexec_eval_grbynum_pred () -
3398  * return:
3399  * gbstate(in) :
3400  */
3401 static DB_LOGICAL
3403 {
3404  DB_LOGICAL ev_res;
3405 
3406  /* groupby numbering; increase the value of groupby_num() by 1 */
3407  if (gbstate->grbynum_val)
3408  {
3409  gbstate->grbynum_val->data.bigint++;
3410  }
3411 
3412  if (gbstate->grbynum_pred)
3413  {
3414  /* evaluate predicate */
3415  ev_res = eval_pred (thread_p, gbstate->grbynum_pred, &gbstate->xasl_state->vd, NULL);
3416  switch (ev_res)
3417  {
3418  case V_FALSE:
3419  /* evaluation is false; if check flag was set, stop scan */
3421  {
3423  }
3424  break;
3425 
3426  case V_TRUE:
3427  /* evaluation is true; if not continue scan mode, set scan check flag */
3430  {
3432  }
3433  break;
3434 
3435  case V_ERROR:
3436  break;
3437 
3438  case V_UNKNOWN:
3439  default:
3440  break;
3441  }
3442  }
3443  else
3444  {
3445  /* no predicate; always true */
3446  ev_res = V_TRUE;
3447  }
3448 
3449  return ev_res;
3450 }
3451 
3452 /*
3453  * qexec_initialize_groupby_state () -
3454  * return:
3455  * gbstate(in) :
3456  * groupby_list(in) : Group_by sorting list specification
3457  * having_pred(in) : Having predicate expression
3458  * grbynum_pred(in) :
3459  * grbynum_val(in) :
3460  * grbynum_flag(in) :
3461  * eptr_list(in) : Having subquery list
3462  * g_agg_list(in) : Group_by aggregation list
3463  * g_regu_list(in) : Regulator Variable List
3464  * g_val_list(in) : Value List
3465  * g_outptr_list(in) : Output pointer list
3466  * g_hk_regu_list(in) : hash key regu list
3467  * g_with_rollup(in) : Has WITH ROLLUP clause
3468  * hash_eligible(in) : hash aggregate evaluation eligibility
3469  * agg_hash_context(in): aggregate hash context
3470  * xasl_state(in) : XASL tree state information
3471  * type_list(in) :
3472  * tplrec(out) : Tuple record descriptor to store result tuples
3473  */
3474 static GROUPBY_STATE *
3475 qexec_initialize_groupby_state (GROUPBY_STATE * gbstate, SORT_LIST * groupby_list, PRED_EXPR * having_pred,
3476  PRED_EXPR * grbynum_pred, DB_VALUE * grbynum_val, int grbynum_flag,
3477  XASL_NODE * eptr_list, AGGREGATE_TYPE * g_agg_list, REGU_VARIABLE_LIST g_regu_list,
3478  VAL_LIST * g_val_list, OUTPTR_LIST * g_outptr_list, REGU_VARIABLE_LIST g_hk_regu_list,
3479  bool with_rollup, int hash_eligible, AGGREGATE_HASH_CONTEXT * agg_hash_context,
3481  QFILE_TUPLE_RECORD * tplrec)
3482 {
3483  assert (groupby_list != NULL);
3484 
3485  gbstate->state = NO_ERROR;
3486 
3487  gbstate->input_scan = NULL;
3488 #if 0 /* SortCache */
3489  VPID_SET_NULL (&(gbstate->fixed_vpid));
3490  gbstate->fixed_page = NULL;
3491 #endif
3492  gbstate->output_file = NULL;
3493 
3494  gbstate->having_pred = having_pred;
3495  gbstate->grbynum_pred = grbynum_pred;
3496  gbstate->grbynum_val = grbynum_val;
3497  gbstate->grbynum_flag = grbynum_flag;
3498  gbstate->eptr_list = eptr_list;
3499  gbstate->g_output_agg_list = g_agg_list;
3500  gbstate->g_regu_list = g_regu_list;
3501  gbstate->g_val_list = g_val_list;
3502  gbstate->g_outptr_list = g_outptr_list;
3503  gbstate->xasl = xasl;
3504  gbstate->xasl_state = xasl_state;
3505 
3506  gbstate->current_key.area_size = 0;
3507  gbstate->current_key.length = 0;
3508  gbstate->current_key.type = 0; /* Unused */
3509  gbstate->current_key.data = NULL;
3510  gbstate->gby_rec.area_size = 0;
3511  gbstate->gby_rec.length = 0;
3512  gbstate->gby_rec.type = 0; /* Unused */
3513  gbstate->gby_rec.data = NULL;
3514  gbstate->output_tplrec = NULL;
3515  gbstate->input_tpl.size = 0;
3516  gbstate->input_tpl.tpl = 0;
3517  gbstate->input_recs = 0;
3518 
3519  gbstate->g_hk_regu_list = g_hk_regu_list;
3520  gbstate->hash_eligible = hash_eligible;
3521  gbstate->agg_hash_context = agg_hash_context;
3522 
3523  if (qfile_initialize_sort_key_info (&gbstate->key_info, groupby_list, type_list) == NULL)
3524  {
3525  return NULL;
3526  }
3527 
3528  gbstate->current_key.data = (char *) db_private_alloc (NULL, DB_PAGESIZE);
3529  if (gbstate->current_key.data == NULL)
3530  {
3531  return NULL;
3532  }
3533  gbstate->current_key.area_size = DB_PAGESIZE;
3534 
3535  gbstate->output_tplrec = tplrec;
3536 
3537  gbstate->with_rollup = with_rollup;
3538 
3539  /* initialize aggregate lists */
3540  if (qexec_gby_init_group_dim (gbstate) != NO_ERROR)
3541  {
3542  return NULL;
3543  }
3544 
3545  gbstate->composite_lock = NULL;
3546  gbstate->upd_del_class_cnt = 0;
3547 
3548  if (hash_eligible)
3549  {
3550  SORT_LIST *sort_list, *sort_col, *gby_col;
3551  BUILDLIST_PROC_NODE *proc;
3553  int i;
3554 
3555  assert (xasl && xasl->type == BUILDLIST_PROC);
3556 
3557  plist = &agg_hash_context->part_list_id->type_list;
3558  proc = &xasl->proc.buildlist;
3559  gby_col = groupby_list;
3560  sort_list = sort_col = qfile_allocate_sort_list (NULL, proc->g_hkey_size);
3561  if (sort_list == NULL)
3562  {
3563  gbstate->state = ER_FAILED;
3564  return gbstate;
3565  }
3566 
3567  for (i = 0; i < proc->g_hkey_size; i++)
3568  {
3569  sort_col->pos_descr.dom = plist->domp[i];
3570  sort_col->pos_descr.pos_no = i;
3571  sort_col->s_order = gby_col->s_order;
3572  sort_col->s_nulls = gby_col->s_nulls;
3573 
3574  sort_col = sort_col->next;
3575  gby_col = gby_col->next;
3576  }
3577 
3578  if (qfile_initialize_sort_key_info (&agg_hash_context->sort_key, sort_list, plist) == NULL)
3579  {
3580  gbstate->state = ER_FAILED;
3581  }
3582  qfile_free_sort_list (NULL, sort_list);
3583  }
3584 
3585  return gbstate;
3586 }
3587 
3588 /*
3589  * qexec_clear_groupby_state () -
3590  * return:
3591  * gbstate(in) :
3592  */
3593 static void
3595 {
3596  int i;
3597 #if 0 /* SortCache */
3598  QFILE_LIST_ID *list_idp;
3599 #endif
3600 
3601  for (i = 0; i < gbstate->g_dim_levels; i++)
3602  {
3604  }
3605  if (gbstate->eptr_list)
3606  {
3607  qexec_clear_head_lists (thread_p, gbstate->eptr_list);
3608  }
3609  if (gbstate->current_key.data)
3610  {
3611  db_private_free_and_init (thread_p, gbstate->current_key.data);
3612  gbstate->current_key.area_size = 0;
3613  }
3614  if (gbstate->gby_rec.data)
3615  {
3616  db_private_free_and_init (thread_p, gbstate->gby_rec.data);
3617  gbstate->gby_rec.area_size = 0;
3618  }
3619  gbstate->output_tplrec = NULL;
3620  /*
3621  * Don't cleanup gbstate->input_tpl; the memory it points to was
3622  * managed by the listfile manager (via input_scan), and it's not
3623  * ours to free.
3624  */
3625 #if 0 /* SortCache */
3626  list_idp = &(gbstate->input_scan->list_id);
3627  /* free currently fixed page */
3628  if (gbstate->fixed_page != NULL)
3629  {
3630  qmgr_free_old_page_and_init (gbstate->fixed_page, list_idp->tfile_vfid);
3631  }
3632 #endif
3633 
3634  qfile_clear_sort_key_info (&gbstate->key_info);
3635  if (gbstate->input_scan)
3636  {
3637  qfile_close_scan (thread_p, gbstate->input_scan);
3638  gbstate->input_scan = NULL;
3639  }
3640  if (gbstate->output_file)
3641  {
3642  qfile_close_list (thread_p, gbstate->output_file);
3644  }
3645 
3646  /* destroy aggregates lists */
3647  qexec_gby_clear_group_dim (thread_p, gbstate);
3648 
3649  if (gbstate->composite_lock)
3650  {
3651  /* TODO - return error handling */
3652  (void) lock_finalize_composite_lock (thread_p, gbstate->composite_lock);
3653  }
3654 }
3655 
3656 /*
3657  * qexec_gby_agg_tuple () -
3658  * return:
3659  * gbstate(in) :
3660  * tpl(in) :
3661  * peek(in) :
3662  */
3663 static void
3664 qexec_gby_agg_tuple (THREAD_ENTRY * thread_p, GROUPBY_STATE * gbstate, QFILE_TUPLE tpl, int peek)
3665 {
3666  XASL_STATE *xasl_state = gbstate->xasl_state;
3667  int i;
3668 
3669  if (gbstate->state != NO_ERROR)
3670  {
3671  return;
3672  }
3673 
3674  /* Read the incoming tuple into DB_VALUEs and do the necessary aggregation... */
3675  if (fetch_val_list (thread_p, gbstate->g_regu_list, &gbstate->xasl_state->vd, NULL, NULL, tpl, peek) != NO_ERROR)
3676  {
3678  }
3679 
3680  /* evaluate aggregates lists */
3681  for (i = 0; i < gbstate->g_dim_levels; i++)
3682  {
3683  assert (gbstate->g_dim[i].d_flag != GROUPBY_DIM_FLAG_NONE);
3684 
3685  if (qdata_evaluate_aggregate_list (thread_p, gbstate->g_dim[i].d_agg_list, &gbstate->xasl_state->vd, NULL) !=
3686  NO_ERROR)
3687  {
3689  }
3690  }
3691 
3692 wrapup:
3693  return;
3694 
3695 exit_on_error:
3696  assert (er_errid () != NO_ERROR);
3697  gbstate->state = er_errid ();
3698  goto wrapup;
3699 }
3700 
3701 /*
3702  * qexec_hash_gby_agg_tuple () - aggregate tuple using hash table
3703  * return: error code or NO_ERROR
3704  * thread_p(in): thread
3705  * xasl_state(in): XASL state
3706  * proc(in): BUILDLIST proc node
3707  * tplrec(in): input tuple record
3708  * tpldesc(in): output tuple descriptor
3709  * groupby_list(in): listfile containing tuples for sort-based aggregation
3710  * output_tuple(out): set if tuple should be output to list file
3711  */
3712 static int
3715  QFILE_LIST_ID * groupby_list, bool * output_tuple)
3716 {
3717  AGGREGATE_HASH_CONTEXT *context = proc->agg_hash_context;
3718  AGGREGATE_HASH_KEY *key = context->temp_key;
3719  AGGREGATE_HASH_VALUE *value;
3721  UINT64 mem_limit = prm_get_bigint_value (PRM_ID_MAX_AGG_HASH_SIZE);
3722  int rc = NO_ERROR;
3723  TSC_TICKS start_tick, end_tick;
3724  TSCTIMEVAL tv_diff;
3725 
3726  if (context->state == HS_REJECT_ALL)
3727  {
3728  /* no tuples should be allowed */
3729  return NO_ERROR;
3730  }
3731 
3732  if (thread_is_on_trace (thread_p))
3733  {
3734  tsc_getticks (&start_tick);
3735  }
3736 
3737  /* build key */
3738  rc = qexec_build_agg_hkey (thread_p, xasl_state, proc->g_hk_scan_regu_list, NULL, key);
3739  if (rc != NO_ERROR)
3740  {
3741  return rc;
3742  }
3743 
3744  /* probe hash table */
3745  value = (AGGREGATE_HASH_VALUE *) mht_get (context->hash_table, (void *) key);
3746  if (value == NULL)
3747  {
3748  AGGREGATE_HASH_KEY *new_key;
3749  AGGREGATE_HASH_VALUE *new_value;
3750 
3751  /* create new key */
3752  new_key = qdata_copy_agg_hkey (thread_p, key);
3753  if (new_key == NULL)
3754  {
3755  assert (er_errid () != NO_ERROR);
3756  return er_errid ();
3757  }
3758 
3759  /* create new value */
3760  new_value = qdata_alloc_agg_hvalue (thread_p, proc->g_func_count, proc->g_agg_list);
3761  if (new_value == NULL)
3762  {
3763  qdata_free_agg_hkey (thread_p, new_key);
3764 
3765  assert (er_errid () != NO_ERROR);
3766  return er_errid ();
3767  }
3768  else if (!proc->g_output_first_tuple)
3769  {
3770  int tuple_size = tpldesc->tpl_size;
3771 
3772  /* alloc tuple space */
3773  new_value->first_tuple.size = tuple_size;
3774  new_value->first_tuple.tpl = (QFILE_TUPLE) db_private_alloc (thread_p, tuple_size);
3775  if (new_value->first_tuple.tpl == NULL)
3776  {
3777  qdata_free_agg_hkey (thread_p, new_key);
3778  qdata_free_agg_hvalue (thread_p, new_value);
3779  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, sizeof (tuple_size));
3780  return ER_FAILED;
3781  }
3782 
3783  /* save output tuple */
3784  if (qfile_save_tuple (tpldesc, T_NORMAL, new_value->first_tuple.tpl, &tuple_size) != NO_ERROR)
3785  {
3786  qdata_free_agg_hkey (thread_p, new_key);
3787  qdata_free_agg_hvalue (thread_p, new_value);
3788 
3789  return ER_FAILED;
3790  }
3791 
3792  /* no need to output it, we're storing it in the hash table */
3793  *output_tuple = false;
3794  }
3795 
3796  /* add to hash table */
3797  mht_put (context->hash_table, (void *) new_key, (void *) new_value);
3798 
3799  /* count new group and tuple; we're not aggregating the tuple just yet but the count is used for statistic
3800  * computations */
3801  context->tuple_count++;
3802  context->group_count++;
3803 
3804  /* compute hash table size */
3805  context->hash_size += qdata_get_agg_hkey_size (new_key);
3806  context->hash_size += qdata_get_agg_hvalue_size (new_value, false);
3807  }
3808  else
3809  {
3810  /* no need to output tuple */
3811  *output_tuple = false;
3812 
3813  /* count new tuple */
3814  value->tuple_count++;
3815  context->tuple_count++;
3816 
3817  /* fetch values */
3818  rc = fetch_val_list (thread_p, proc->g_scan_regu_list, &xasl_state->vd, NULL, NULL, tplrec->tpl, true);
3819 
3820  /* eval aggregate functions */
3821  if (rc == NO_ERROR)
3822  {
3823  rc = qdata_evaluate_aggregate_list (thread_p, proc->g_agg_list, &xasl_state->vd, value->accumulators);
3824  }
3825 
3826  /* compute size */
3827  context->hash_size += qdata_get_agg_hvalue_size (value, true);
3828 
3829  /* check for error */
3830  if (rc != NO_ERROR)
3831  {
3832  return rc;
3833  }
3834  }
3835 
3836  /* keep hash table within memory limit */
3837  while (context->hash_size > (int) mem_limit)
3838  {
3839  /* get least recently used entry */
3840  hentry = context->hash_table->lru_head;
3841  if (hentry == NULL)
3842  {
3843  /* should not get here */
3844  return ER_FAILED;
3845  }
3846  key = (AGGREGATE_HASH_KEY *) hentry->key;
3847  value = (AGGREGATE_HASH_VALUE *) hentry->data;
3848 
3849  /* add key/accumulators to partial list */
3850  rc = qdata_save_agg_hentry_to_list (thread_p, key, value, context->temp_dbval_array, context->part_list_id);
3851  if (rc != NO_ERROR)
3852  {
3853  return rc;
3854  }
3855 
3856  /* add first tuple of group to groupby list */
3857  if (value->first_tuple.tpl != NULL)
3858  {
3859  rc = qfile_add_tuple_to_list (thread_p, groupby_list, value->first_tuple.tpl);
3860  if (rc != NO_ERROR)
3861  {
3862  return rc;
3863  }
3864  }
3865 
3866 #if !defined(NDEBUG)
3867  er_log_debug (ARG_FILE_LINE, "hash aggregation overflow: dumped %.2fKB entry",
3868  (qdata_get_agg_hkey_size (key) + qdata_get_agg_hvalue_size (value, false)) / 1024.0f);
3869 #endif
3870 
3871  /* remove entry */
3872  context->hash_size -= qdata_get_agg_hkey_size (key);
3873  context->hash_size -= qdata_get_agg_hvalue_size (value, false);
3874  mht_rem (context->hash_table, key, qdata_free_agg_hentry, NULL);
3875  }
3876 
3877  /* check very high selectivity case */
3879  {
3880  float selectivity = (float) context->group_count / context->tuple_count;
3882  {
3883  /* very high selectivity, abort hash aggregation */
3884  context->state = HS_REJECT_ALL;
3885 
3886  /* dump hash table to list file, no need to keep it in memory */
3887  qdata_save_agg_htable_to_list (thread_p, context->hash_table, groupby_list, context->part_list_id,
3888  context->temp_dbval_array);
3889 
3890 #if !defined(NDEBUG)
3891  er_log_debug (ARG_FILE_LINE, "hash aggregation abandoned: very high selectivity");
3892 #endif
3893  }
3894  }
3895 
3896  if (thread_is_on_trace (thread_p))
3897  {
3898  tsc_getticks (&end_tick);
3899  tsc_elapsed_time_usec (&tv_diff, end_tick, start_tick);
3900  TSC_ADD_TIMEVAL (xasl->groupby_stats.groupby_time, tv_diff);
3901  xasl->groupby_stats.groupby_hash = context->state;
3902  }
3903 
3904  /* all ok */
3905  return NO_ERROR;
3906 }
3907 
3908 /*
3909  * qexec_hash_gby_get_next () - get next tuple in partial list
3910  * return: sort status
3911  * recdes(in): record descriptor
3912  * arg(in): hash context
3913  */
3914 static SORT_STATUS
3916 {
3917  GROUPBY_STATE *state = (GROUPBY_STATE *) arg;
3918  AGGREGATE_HASH_CONTEXT *context = state->agg_hash_context;
3919 
3920  return qfile_make_sort_key (thread_p, &context->sort_key, recdes, &context->part_scan_id, &context->input_tuple);
3921 }
3922 
3923 /*
3924  * qexec_hash_gby_put_next () - put next tuple in sorted list file
3925  * return: error code or NO_ERROR
3926  * recdes(in): record descriptor
3927  * arg(in): hash context
3928  */
3929 static int
3930 qexec_hash_gby_put_next (THREAD_ENTRY * thread_p, const RECDES * recdes, void *arg)
3931 {
3932  GROUPBY_STATE *state = (GROUPBY_STATE *) arg;
3933  AGGREGATE_HASH_CONTEXT *context = state->agg_hash_context;
3934  SORT_REC *key;
3935  char *data;
3936  int rc, peek;
3937 
3938  peek = COPY;
3939  for (key = (SORT_REC *) recdes->data; key; key = key->next)
3940  {
3941  /* read tuple */
3942  if (context->sort_key.use_original)
3943  {
3944  QFILE_LIST_ID *list_idp = context->part_list_id;
3945  QFILE_TUPLE_RECORD dummy;
3946  PAGE_PTR page;
3947  VPID vpid;
3948  int status;
3949 
3950  /* retrieve original tuple */
3951  vpid.pageid = key->s.original.pageid;
3952  vpid.volid = key->s.original.volid;
3953 
3954  page = qmgr_get_old_page (thread_p, &vpid, list_idp->tfile_vfid);
3955  if (page == NULL)
3956  {
3957  return ER_FAILED;
3958  }
3959 
3960  QFILE_GET_OVERFLOW_VPID (&vpid, page);
3961  data = page + key->s.original.offset;
3962  if (vpid.pageid != NULL_PAGEID)
3963  {
3964  /*
3965  * This sucks; why do we need two different structures to
3966  * accomplish exactly the same goal?
3967  */
3968  dummy.size = context->tuple_recdes.area_size;
3969  dummy.tpl = context->tuple_recdes.data;
3970  status = qfile_get_tuple (thread_p, page, data, &dummy, list_idp);
3971 
3972  if (dummy.tpl != context->tuple_recdes.data)
3973  {
3974  /*
3975  * DON'T FREE THE BUFFER! qfile_get_tuple() already did
3976  * that, and what you have here in gby_rec is a dangling
3977  * pointer.
3978  */
3979  context->tuple_recdes.area_size = dummy.size;
3980  context->tuple_recdes.data = dummy.tpl;
3981  }
3982  if (status != NO_ERROR)
3983  {
3984  qmgr_free_old_page_and_init (thread_p, page, list_idp->tfile_vfid);
3985  return ER_FAILED;
3986  }
3987 
3988  data = context->tuple_recdes.data;
3989  }
3990  else
3991  {
3992  peek = PEEK; /* avoid unnecessary COPY */
3993  }
3994  qmgr_free_old_page_and_init (thread_p, page, list_idp->tfile_vfid);
3995  }
3996  else
3997  {
3998  /*
3999  * sorting over all columns (i.e. no aggregate functions); build
4000  * tuple from sort key.
4001  */
4002  if (qfile_generate_sort_tuple (&context->sort_key, key, &context->tuple_recdes) == NULL)
4003  {
4004  return ER_FAILED;
4005  }
4006  data = context->tuple_recdes.data;
4007  }
4008 
4009  /* read tuple into value */
4010  if (qdata_load_agg_hentry_from_tuple (thread_p, data, context->temp_part_key, context->temp_part_value,
4011  context->key_domains, context->accumulator_domains) != NO_ERROR)
4012  {
4013  return ER_FAILED;
4014  }
4015 
4016  /* aggregate */
4017  if (qdata_agg_hkey_eq (context->curr_part_key, context->temp_part_key) && context->sorted_count > 0)
4018  {
4019  AGGREGATE_TYPE *agg_list = state->g_output_agg_list;
4020  int i = 0;
4021 
4022  /* same key, compose accumulators */
4023  while (agg_list != NULL)
4024  {
4025  rc =
4027  &agg_list->accumulator_domain, agg_list->function,
4028  agg_list->domain,
4029  &context->temp_part_value->accumulators[i]);
4030  if (rc != NO_ERROR)
4031  {
4032  return rc;
4033  }
4034 
4035  agg_list = agg_list->next;
4036  i++;
4037  }
4038  }
4039  else
4040  {
4041  AGGREGATE_HASH_KEY *swap_key;
4042  AGGREGATE_HASH_VALUE *swap_value;
4043 
4044  if (context->sorted_count > 0)
4045  {
4046  /* different key, write current accumulators */
4047  if (qdata_save_agg_hentry_to_list (thread_p, context->curr_part_key, context->curr_part_value,
4048  context->temp_dbval_array, context->sorted_part_list_id) != NO_ERROR)
4049  {
4050  return ER_FAILED;
4051  }
4052  }
4053 
4054  /* swap keys; we keep new key/value as current key/value; old pair will be cleared and used for the next
4055  * iteration as temp */
4056  swap_key = context->curr_part_key;
4057  swap_value = context->curr_part_value;
4058  context->curr_part_key = context->temp_part_key;
4059  context->curr_part_value = context->temp_part_value;
4060  context->temp_part_key = swap_key;
4061  context->temp_part_value = swap_value;
4062  }
4063 
4064  /* sorted a group */
4065  context->sorted_count++;
4066  }
4067 
4068  /* all ok */
4069  return NO_ERROR;
4070 }
4071 
4072 /*
4073  * qexec_gby_get_next () -
4074  * return:
4075  * recdes(in) :
4076  * arg(in) :
4077  */
4078 static SORT_STATUS
4079 qexec_gby_get_next (THREAD_ENTRY * thread_p, RECDES * recdes, void *arg)
4080 {
4081  GROUPBY_STATE *gbstate;
4082 
4083  gbstate = (GROUPBY_STATE *) arg;
4084 
4085  return qfile_make_sort_key (thread_p, &gbstate->key_info, recdes, gbstate->input_scan, &gbstate->input_tpl);
4086 }
4087 
4088 /*
4089  * qexec_gby_put_next () -
4090  * return:
4091  * recdes(in) :
4092  * arg(in) :
4093  */
4094 static int
4095 qexec_gby_put_next (THREAD_ENTRY * thread_p, const RECDES * recdes, void *arg)
4096 {
4097  GROUPBY_STATE *info;
4098  SORT_REC *key;
4099  char *data;
4100  PAGE_PTR page;
4101  VPID vpid;
4102  int peek, i, rollup_level;
4103  QFILE_LIST_ID *list_idp;
4104 
4105  QFILE_TUPLE_RECORD dummy;
4106  int status;
4107 
4108  info = (GROUPBY_STATE *) arg;
4109  list_idp = &(info->input_scan->list_id);
4110 
4111  data = NULL;
4112  page = NULL;
4113 
4114  /* Traverse next link */
4115  for (key = (SORT_REC *) recdes->data; key; key = key->next)
4116  {
4117  if (info->state != NO_ERROR)
4118  {
4119  goto exit_on_error;
4120  }
4121 
4122  peek = COPY; /* default */
4123  if (info->key_info.use_original)
4124  { /* P_sort_key */
4125  /*
4126  * Retrieve the original tuple. This will be the case if the
4127  * original tuple had more fields than we were sorting on.
4128  */
4129  vpid.pageid = key->s.original.pageid;
4130  vpid.volid = key->s.original.volid;
4131 
4132 #if 0 /* SortCache */
4133  /* check if page is already fixed */
4134  if (VPID_EQ (&(info->fixed_vpid), &vpid))
4135  {
4136  /* use cached page pointer */
4137  page = info->fixed_page;
4138  }
4139  else
4140  {
4141  /* free currently fixed page */
4142  if (info->fixed_page != NULL)
4143  {
4144  qmgr_free_old_page_and_init (info->fixed_page, list_idp->tfile_vfid);
4145  }
4146 
4147  /* fix page and cache fixed vpid */
4148  page = qmgr_get_old_page (&vpid, list_idp->tfile_vfid);
4149  if (page == NULL)
4150  {
4151  goto exit_on_error;
4152  }
4153 
4154  /* save page pointer */
4155  info->fixed_vpid = vpid;
4156  info->fixed_page = page;
4157  } /* else */
4158 #else
4159  page = qmgr_get_old_page (thread_p, &vpid, list_idp->tfile_vfid);
4160  if (page == NULL)
4161  {
4162  goto exit_on_error;
4163  }
4164 #endif
4165 
4166  QFILE_GET_OVERFLOW_VPID (&vpid, page);
4167  data = page + key->s.original.offset;
4168  if (vpid.pageid != NULL_PAGEID)
4169  {
4170  /*
4171  * This sucks; why do we need two different structures to
4172  * accomplish exactly the same goal?
4173  */
4174  dummy.size = info->gby_rec.area_size;
4175  dummy.tpl = info->gby_rec.data;
4176  status = qfile_get_tuple (thread_p, page, data, &dummy, list_idp);
4177 
4178  if (dummy.tpl != info->gby_rec.data)
4179  {
4180  /*
4181  * DON'T FREE THE BUFFER! qfile_get_tuple() already did
4182  * that, and what you have here in gby_rec is a dangling
4183  * pointer.
4184  */
4185  info->gby_rec.area_size = dummy.size;
4186  info->gby_rec.data = dummy.tpl;
4187  }
4188  if (status != NO_ERROR)
4189  {
4190  goto exit_on_error;
4191  }
4192 
4193  data = info->gby_rec.data;
4194  }
4195  else
4196  {
4197  peek = PEEK; /* avoid unnecessary COPY */
4198  }
4199  }
4200  else
4201  { /* A_sort_key */
4202  /*
4203  * We didn't record the original vpid, and we should just
4204  * reconstruct the original record from this sort key (rather
4205  * than pressure the page buffer pool by reading in the original
4206  * page to get the original tuple).
4207  */
4208  if (qfile_generate_sort_tuple (&info->key_info, key, &info->gby_rec) == NULL)
4209  {
4210  goto exit_on_error;
4211  }
4212  data = info->gby_rec.data;
4213  }
4214 
4215  if (info->input_recs == 0)
4216  {
4217  /*
4218  * First record we've seen; put it out and set up the group
4219  * comparison key(s).
4220  */
4221  qexec_gby_start_group_dim (thread_p, info, recdes);
4222 
4223  /* check partial list file */
4224  if (info->hash_eligible && info->agg_hash_context->part_scan_code == S_SUCCESS)
4225  {
4227  bool found = false;
4228 
4229  /* build key for current */
4230  if (qexec_build_agg_hkey (thread_p, info->xasl_state, info->g_hk_regu_list, data,
4231  info->agg_hash_context->temp_key) != NO_ERROR)
4232  {
4233  goto exit_on_error;
4234  }
4235 
4236  /* search in partial list */
4238  &found) != NO_ERROR)
4239  {
4240  goto exit_on_error;
4241  }
4242 
4243  /* if found, load it */
4244  if (found)
4245  {
4246  /* increment record count */
4247  info->input_recs += hvalue->tuple_count;
4248 
4249  /* replace aggregate accumulators */
4250  qdata_load_agg_hvalue_in_agg_list (hvalue, info->g_dim[0].d_agg_list, false);
4251 
4252  if (info->with_rollup)
4253  {
4254  for (i = 1; i < info->g_dim_levels; i++)
4255  {
4256  /* replace accumulators for restarted rollup groups */
4257  qdata_load_agg_hvalue_in_agg_list (hvalue, info->g_dim[i].d_agg_list, true);
4258  }
4259  }
4260  }
4261  }
4262  }
4263  else if ((*info->cmp_fn) (&info->current_key.data, &key, &info->key_info) == 0)
4264  {
4265  /*
4266  * Still in the same group; accumulate the tuple and proceed,
4267  * leaving the group key the same.
4268  */
4269  }
4270  else
4271  {
4272  /*
4273  * We got a new group; finalize the group we were accumulating,
4274  * and start a new group using the current key as the group key.
4275  */
4276  rollup_level = qexec_gby_finalize_group_dim (thread_p, info, recdes);
4277  if (info->state == SORT_PUT_STOP)
4278  {
4279  goto wrapup;
4280  }
4281 
4282  /* check partial list file */
4283  if (info->hash_eligible && info->agg_hash_context->part_scan_code == S_SUCCESS)
4284  {
4286  bool found = false;
4287 
4288  /* build key for current */
4289  if (qexec_build_agg_hkey (thread_p, info->xasl_state, info->g_hk_regu_list, data,
4290  info->agg_hash_context->temp_key) != NO_ERROR)
4291  {
4292  goto exit_on_error;
4293  }
4294 
4295  /* search in partial list */
4297  &found) != NO_ERROR)
4298  {
4299  goto exit_on_error;
4300  }
4301 
4302  /* if found, load it */
4303  if (found)
4304  {
4305  /* increment record count */
4306  info->input_recs += hvalue->tuple_count;
4307 
4308  /* replace aggregate accumulators */
4309  qdata_load_agg_hvalue_in_agg_list (hvalue, info->g_dim[0].d_agg_list, false);
4310 
4311  if (info->with_rollup)
4312  {
4313  /* replace accumulators for restarted rollup groups */
4314  for (i = rollup_level; i < info->g_dim_levels; i++)
4315  {
4316  qdata_load_agg_hvalue_in_agg_list (hvalue, info->g_dim[i].d_agg_list, true);
4317  }
4318 
4319  /* compose accumulators for active rollup groups */
4320  for (i = 1; i < rollup_level; i++)
4321  {
4322  AGGREGATE_ACCUMULATOR *acc = hvalue->accumulators;
4323  AGGREGATE_TYPE *ru_agg_list = info->g_dim[i].d_agg_list;
4324  int j = 0;
4325 
4326  while (ru_agg_list)
4327  {
4328  if (qdata_aggregate_accumulator_to_accumulator (thread_p, &ru_agg_list->accumulator,
4329  &ru_agg_list->accumulator_domain,
4330  ru_agg_list->function,
4331  ru_agg_list->domain, &acc[j]) != NO_ERROR)
4332  {
4333  goto exit_on_error;
4334  }
4335 
4336  ru_agg_list = ru_agg_list->next;
4337  j++;
4338  }
4339  }
4340  }
4341  }
4342  }
4343  }
4344 
4345  /* aggregate tuple */
4346  qexec_gby_agg_tuple (thread_p, info, data, peek);
4347 
4348  info->input_recs++;
4349 
4350 #if 1 /* SortCache */
4351  if (page)
4352  {
4353  qmgr_free_old_page_and_init (thread_p, page, list_idp->tfile_vfid);
4354  }
4355 #endif
4356 
4357  } /* for (key = (SORT_REC *) recdes->data; ...) */
4358 
4359 wrapup:
4360 #if 1 /* SortCache */
4361  if (page)
4362  {
4363  qmgr_free_old_page_and_init (thread_p, page, list_idp->tfile_vfid);
4364  }
4365 #endif
4366 
4367  return info->state;
4368 
4369 exit_on_error:
4370  assert (er_errid () != NO_ERROR);
4371  info->state = er_errid ();
4372  goto wrapup;
4373 }
4374 
4375 /*
4376  * qexec_groupby () -
4377  * return: NO_ERROR, or ER_code
4378  * xasl(in) :
4379  * xasl_state(in) : XASL tree state information
4380  * tplrec(out) : Tuple record descriptor to store result tuples
4381  *
4382  * Note: Apply the group_by clause to the given list file to group it
4383  * using the specified group_by parameters.
4384  */
4385 static int
4387 {
4388  QFILE_LIST_ID *list_id = xasl->list_id;
4389  BUILDLIST_PROC_NODE *buildlist = &xasl->proc.buildlist;
4390  GROUPBY_STATE gbstate;
4391  QFILE_LIST_SCAN_ID input_scan_id;
4392  int ls_flag = 0;
4393  int estimated_pages;
4394 
4395  TSC_TICKS start_tick, end_tick;
4396  TSCTIMEVAL tv_diff;
4397 
4398  UINT64 old_sort_pages = 0, old_sort_ioreads = 0;
4399 
4400  if (buildlist->groupby_list == NULL)
4401  {
4402  return NO_ERROR;
4403  }
4404 
4405  if (thread_is_on_trace (thread_p))
4406  {
4407  tsc_getticks (&start_tick);
4408  xasl->groupby_stats.run_groupby = true;
4409  xasl->groupby_stats.rows = 0;
4410  }
4411 
4412  /* initialize groupby_num() value */
4413  if (buildlist->g_grbynum_val && DB_IS_NULL (buildlist->g_grbynum_val))
4414  {
4415  db_make_bigint (buildlist->g_grbynum_val, 0);
4416  }
4417 
4418  /* clear group by limit flags when skip group by is not used */
4420  {
4422  }
4424  {
4426  }
4427 
4428  /* late binding : resolve group_by (buildlist) */
4429  if (xasl->outptr_list != NULL)
4430  {
4432  }
4433 
4434  if (qexec_initialize_groupby_state (&gbstate, buildlist->groupby_list, buildlist->g_having_pred,
4435  buildlist->g_grbynum_pred, buildlist->g_grbynum_val, buildlist->g_grbynum_flag,
4436  buildlist->eptr_list, buildlist->g_agg_list, buildlist->g_regu_list,
4437  buildlist->g_val_list, buildlist->g_outptr_list, buildlist->g_hk_sort_regu_list,
4438  buildlist->g_with_rollup != 0, buildlist->g_hash_eligible,
4439  buildlist->agg_hash_context, xasl, xasl_state, &list_id->type_list,
4440  tplrec) == NULL)
4441  {
4443  }
4444 
4445  /*
4446  * Create a new listfile to receive the results.
4447  */
4448  {
4449  QFILE_TUPLE_VALUE_TYPE_LIST output_type_list;
4450  QFILE_LIST_ID *output_list_id;
4451 
4452  if (qdata_get_valptr_type_list (thread_p, buildlist->g_outptr_list, &output_type_list) != NO_ERROR)
4453  {
4455  }
4456  /* If it does not have 'order by'(xasl->orderby_list), then the list file to be open at here will be the last one.
4457  * Otherwise, the last list file will be open at qexec_orderby_distinct(). (Note that only one that can have 'group
4458  * by' is BUILDLIST_PROC type.) And, the top most XASL is the other condition for the list file to be the last
4459  * result file. */
4460 
4461  QFILE_SET_FLAG (ls_flag, QFILE_FLAG_ALL);
4463  && (xasl->orderby_list == NULL || XASL_IS_FLAGED (xasl, XASL_SKIP_ORDERBY_LIST)) && xasl->option != Q_DISTINCT)
4464  {
4466  }
4467 
4468  output_list_id =
4469  qfile_open_list (thread_p, &output_type_list, buildlist->after_groupby_list, xasl_state->query_id, ls_flag);
4470  if (output_list_id == NULL)
4471  {
4472  if (output_type_list.domp)
4473  {
4474  db_private_free_and_init (thread_p, output_type_list.domp);
4475  }
4476 
4478  }
4479 
4480  if (output_type_list.domp)
4481  {
4482  db_private_free_and_init (thread_p, output_type_list.domp);
4483  }
4484 
4485  gbstate.output_file = output_list_id;
4486  }
4487 
4488  /* check for quick finalization scenarios */
4489  if (list_id->tuple_cnt == 0)
4490  {
4491  if (!gbstate.hash_eligible || gbstate.agg_hash_context->tuple_count == 0)
4492  {
4493  /* no tuples hash aggregated and empty unsorted list; no reason to continue */
4494  qfile_destroy_list (thread_p, list_id);
4495  qfile_close_list (thread_p, gbstate.output_file);
4496  qfile_copy_list_id (list_id, gbstate.output_file, true);
4497  qexec_clear_groupby_state (thread_p, &gbstate);
4498 
4499  return NO_ERROR;
4500  }
4501  else if (gbstate.agg_hash_context->part_list_id->tuple_cnt == 0
4503  {
4505  AGGREGATE_HASH_VALUE *value = NULL;
4506 
4507  /* empty unsorted list and empty partial list; we can generate the output from the hash table */
4508  while (head)
4509  {
4510  /* load entry into aggregate list */
4511  value = (AGGREGATE_HASH_VALUE *) head->data;
4512  if (value == NULL)
4513  {
4514  /* should not happen */
4516  }
4517 
4518  if (value->first_tuple.tpl == NULL)
4519  {
4520  /* empty unsorted list and no first tuple? this should not happen ... */
4522  }
4523 
4524  /* start new group and aggregate tuple; since unsorted list is empty we don't have rollup groups */
4525  qexec_gby_start_group_dim (thread_p, &gbstate, NULL);
4526 
4527  /* load values in list and aggregate first tuple */
4528  qdata_load_agg_hvalue_in_agg_list (value, gbstate.g_dim[0].d_agg_list, false);
4529  qexec_gby_agg_tuple (thread_p, &gbstate, value->first_tuple.tpl, PEEK);
4530 
4531  /* finalize */
4532  qexec_gby_finalize_group_dim (thread_p, &gbstate, NULL);
4533 
4534  /* next entry */
4535  head = head->act_next;
4536  gbstate.input_recs += value->tuple_count + 1;
4537  }
4538 
4539  /* output generated; finalize */
4540  qfile_destroy_list (thread_p, list_id);
4541  qfile_close_list (thread_p, gbstate.output_file);
4542  qfile_copy_list_id (list_id, gbstate.output_file, true);
4543 
4544  goto wrapup;
4545  }
4546  }
4547 
4548  if (thread_is_on_trace (thread_p))
4549  {
4550  xasl->groupby_stats.groupby_sort = true;
4551  old_sort_pages = perfmon_get_from_statistic (thread_p, PSTAT_SORT_NUM_DATA_PAGES);
4552  old_sort_ioreads = perfmon_get_from_statistic (thread_p, PSTAT_SORT_NUM_IO_PAGES);
4553  }
4554 
4555  /* unsorted list is not empty; dump hash table to partial list */
4556  if (gbstate.hash_eligible && gbstate.agg_hash_context->tuple_count > 0
4557  && mht_count (gbstate.agg_hash_context->hash_table) > 0)
4558  {
4559  /* reopen unsorted list to accept new tuples */
4560  if (qfile_reopen_list_as_append_mode (thread_p, list_id) != NO_ERROR)
4561  {
4563  }
4564 
4565  /* save hash table */
4566  if (qdata_save_agg_htable_to_list (thread_p, gbstate.agg_hash_context->hash_table, list_id,
4567  gbstate.agg_hash_context->part_list_id,
4569  {
4571  }
4572 
4573  /* close unsorted list */
4574  qfile_close_list (thread_p, list_id);
4575  }
4576 
4577  /* sort partial list and open a scan on it */
4578  if (gbstate.hash_eligible && gbstate.agg_hash_context->part_list_id->tuple_cnt > 0)
4579  {
4580  SORT_CMP_FUNC *cmp_fn;
4581 
4582  /* open scan on partial list */
4584  NO_ERROR)
4585  {
4587  }
4588 
4589  estimated_pages =
4591  &gbstate.agg_hash_context->sort_key);
4592 
4593  /* choose appripriate sort function */
4594  if (gbstate.agg_hash_context->sort_key.use_original)
4595  {
4597  }
4598  else
4599  {
4601  }
4602 
4603  /* sort and aggregate partial results */
4604  if (sort_listfile (thread_p, NULL_VOLID, estimated_pages, &qexec_hash_gby_get_next, &gbstate,
4605  &qexec_hash_gby_put_next, &gbstate, cmp_fn, &gbstate.agg_hash_context->sort_key, SORT_DUP,
4607  {
4609  }
4610 
4611  /* write last group */
4612  if (gbstate.agg_hash_context->sorted_count > 0)
4613  {
4614  /* different key, write current accumulators */
4619  {
4621  }
4622  }
4623 
4624  /* close scan */
4625  qfile_close_scan (thread_p, &gbstate.agg_hash_context->part_scan_id);
4626 
4627  /* partial list is no longer necessary */
4628  qfile_close_list (thread_p, gbstate.agg_hash_context->part_list_id);
4629  qfile_destroy_list (thread_p, gbstate.agg_hash_context->part_list_id);
4631  gbstate.agg_hash_context->part_list_id = NULL;
4632 
4633  /* reopen scan on newly sorted list */
4635  != NO_ERROR)
4636  {
4638  }
4639 
4640  /* load first key */
4641  gbstate.agg_hash_context->part_scan_code =
4645  gbstate.agg_hash_context->key_domains,
4647  }
4648  else
4649  {
4650  /* empty partial list; probably set types or big records */
4652  }
4653 
4654  /*
4655  * Open a scan on the unsorted input file
4656  */
4657  if (qfile_open_list_scan (list_id, &input_scan_id) != NO_ERROR)
4658  {
4660  }
4661  gbstate.input_scan = &input_scan_id;
4662 
4663  /*
4664  * Now load up the sort module and set it off...
4665  */
4666  gbstate.key_info.use_original = (gbstate.key_info.nkeys != list_id->type_list.type_cnt);
4667  gbstate.cmp_fn =
4669 
4671  {
4672 #if defined (ENABLE_COMPOSITE_LOCK)
4673  gbstate.composite_lock = &xasl->composite_lock;
4674 #endif /* defined (ENABLE_COMPOSITE_LOCK) */
4675  gbstate.upd_del_class_cnt = xasl->upd_del_class_cnt;
4676  }
4677  else
4678  {
4679  gbstate.composite_lock = NULL;
4680  gbstate.upd_del_class_cnt = 0;
4681  }
4682 
4683  estimated_pages = qfile_get_estimated_pages_for_sorting (list_id, &gbstate.key_info);
4684 
4685  if (sort_listfile (thread_p, NULL_VOLID, estimated_pages, &qexec_gby_get_next, &gbstate, &qexec_gby_put_next,
4686  &gbstate, gbstate.cmp_fn, &gbstate.key_info, SORT_DUP, NO_SORT_LIMIT,
4688  {
4690  }
4691 
4692  /*
4693  * There may be one unfinished group in the output, since the sort_listfile
4694  * interface doesn't include a finalization function. If so, finish
4695  * off that group.
4696  */
4697  if (gbstate.input_recs != 0)
4698  {
4699  qexec_gby_finalize_group_dim (thread_p, &gbstate, NULL);
4700  }
4701 
4702  /* close output file */
4703  qfile_close_list (thread_p, gbstate.output_file);
4704 #if 0 /* SortCache */
4705  /* free currently fixed page */
4706  if (gbstate.fixed_page != NULL)
4707  {
4708  QFILE_LIST_ID *list_idp;
4709 
4710  list_idp = &(gbstate.input_scan->list_id);
4711  qmgr_free_old_page_and_init (gbstate.fixed_page, list_idp->tfile_vfid);
4712  }
4713 #endif
4714  qfile_destroy_list (thread_p, list_id);
4715  qfile_copy_list_id (list_id, gbstate.output_file, true);
4716  /* qexec_clear_groupby_state() will free gbstate.output_file */
4717 
4718 wrapup:
4719  {
4720  int result;
4721 
4722  /* SORT_PUT_STOP set by 'qexec_gby_finalize_group_dim ()' isn't error */
4723  result = (gbstate.state == NO_ERROR || gbstate.state == SORT_PUT_STOP) ? NO_ERROR : ER_FAILED;
4724 
4725  /* check merge result */
4726  if (result == NO_ERROR && XASL_IS_FLAGED (xasl, XASL_IS_MERGE_QUERY) && list_id->tuple_cnt != gbstate.input_recs)
4727  {
4729  result = ER_FAILED;
4730  }
4731 
4732  /* cleanup */
4733  qexec_clear_groupby_state (thread_p, &gbstate);
4734 
4735  if (thread_is_on_trace (thread_p))
4736  {
4737  tsc_getticks (&end_tick);
4738  tsc_elapsed_time_usec (&tv_diff, end_tick, start_tick);
4739  TSC_ADD_TIMEVAL (xasl->groupby_stats.groupby_time, tv_diff);
4740 
4741  if (xasl->groupby_stats.groupby_sort == true)
4742  {
4743  xasl->groupby_stats.groupby_pages = (perfmon_get_from_statistic (thread_p, PSTAT_SORT_NUM_DATA_PAGES)
4744  - old_sort_pages);
4745  xasl->groupby_stats.groupby_ioreads = (perfmon_get_from_statistic (thread_p, PSTAT_SORT_NUM_IO_PAGES)
4746  - old_sort_ioreads);
4747  }
4748  }
4749 
4750  return result;
4751  }
4752 
4753 exit_on_error:
4754 
4755  assert (er_errid () != NO_ERROR);
4756  gbstate.state = er_errid ();
4757  if (gbstate.state == NO_ERROR || gbstate.state == SORT_PUT_STOP)
4758  {
4759  gbstate.state = ER_FAILED;
4760  }
4761 
4762  goto wrapup;
4763 }
4764 
4765 /*
4766  * qexec_collection_has_null () -
4767  * return: 1 iff collection has an element with a NULL in it
4768  * colval(in) : DB_VALUE of a collection
4769  */
4770 static int
4772 {
4773  DB_VALUE elem;
4774  DB_COLLECTION *col;
4775  long i;
4776  int result = 0;
4777 
4778  col = db_get_set (colval);
4779  for (i = 0; i < db_set_size (col) && !result; i++)
4780  {
4781  if (db_set_get (col, i, &elem) < NO_ERROR)
4782  {
4783  return 1;
4784  /* flag an error as a NULL, DON'T clear elem with unknown state */
4785  }
4786  if (DB_IS_NULL (&elem))
4787  {
4788  return 1; /* found a NULL, can stop looking, clear unecessary */
4789  }
4790 
4792  {
4793  /* this is for nested set types, need to fall thru to clear */
4794  result = 1;
4795  }
4796 
4797  pr_clear_value (&elem);
4798  }
4799 
4800  return 0;
4801 }
4802 
4803 /*
4804  * qexec_cmp_tpl_vals_merge () -
4805  * return:
4806  * DB_UNK: return error
4807  * left_tval(in) : left tuple values
4808  * left_dom(in) : Domains of left_tval
4809  * rght_tval(in) : right tuple values
4810  * rght_dom(in) : Domains of rght_tval
4811  * tval_cnt(in) : tuple values count
4812  *
4813  * Note: This routine checks if two tuple values are equal. Coercion
4814  * is done if necessary. This must give a totally
4815  * ordered result, but never return equal for
4816  * a NULL comparison. The result of this comparison
4817  * will tell the merge routine whether to advance the
4818  * left or right file to the next tuple. DB_UNK
4819  * cannot be returned because it is ambiguous as
4820  * to which side is collated later. If two
4821  * NULL's or two collections both containing NULL
4822  * are encountered, then it may pick either side
4823  * as the lessor side, that tuple will be discarded,
4824  * then the next comparison will discard the other side.
4825  */
4827 qexec_cmp_tpl_vals_merge (QFILE_TUPLE * left_tval, TP_DOMAIN ** left_dom, QFILE_TUPLE * rght_tval,
4828  TP_DOMAIN ** rght_dom, int tval_cnt)
4829 {
4830  OR_BUF buf;
4831  DB_VALUE left_dbval, right_dbval;
4832  int i, cmp, left_len, right_len;
4833  bool left_is_set, right_is_set;
4834 
4835  cmp = DB_UNK; /* init */
4836 
4837  for (i = 0; i < tval_cnt; i++)
4838  {
4839  PRIM_SET_NULL (&left_dbval);
4840  PRIM_SET_NULL (&right_dbval);
4841 
4842  /* get tpl values into db_values for the comparison */
4843 
4844  /* zero length means NULL */
4845  left_len = QFILE_GET_TUPLE_VALUE_LENGTH (left_tval[i]);
4846  if (left_len == 0)
4847  {
4848  cmp = DB_LT;
4849  break;
4850  }
4851  right_len = QFILE_GET_TUPLE_VALUE_LENGTH (rght_tval[i]);
4852  if (right_len == 0)
4853  {
4854  cmp = DB_GT;
4855  break;
4856  }
4857 
4858  or_init (&buf, (char *) (left_tval[i] + QFILE_TUPLE_VALUE_HEADER_SIZE), left_len);
4859  /* Do not copy the string--just use the pointer. The pr_ routines for strings and sets have different semantics
4860  * for length. */
4861  left_is_set = pr_is_set_type (TP_DOMAIN_TYPE (left_dom[i])) ? true : false;
4862  if (left_dom[i]->type->data_readval (&buf, &left_dbval, left_dom[i], -1, left_is_set, NULL, 0) != NO_ERROR)
4863  {
4864  cmp = DB_UNK; /* is error */
4865  break;
4866  }
4867  if (DB_IS_NULL (&left_dbval))
4868  {
4869  cmp = DB_LT;
4870  break;
4871  }
4872 
4873  or_init (&buf, (char *) (rght_tval[i] + QFILE_TUPLE_VALUE_HEADER_SIZE), right_len);
4874  /* Do not copy the string--just use the pointer. The pr_ routines for strings and sets have different semantics
4875  * for length. */
4876  right_is_set = pr_is_set_type (TP_DOMAIN_TYPE (rght_dom[i])) ? true : false;
4877  if (rght_dom[i]->type->data_readval (&buf, &right_dbval, rght_dom[i], -1, right_is_set, NULL, 0) != NO_ERROR)
4878  {
4879  cmp = DB_UNK; /* is error */
4880  goto clear;
4881  }
4882  if (DB_IS_NULL (&right_dbval))
4883  {
4884  cmp = DB_GT;
4885  goto clear;
4886  }
4887 
4888  /* both left_dbval, right_dbval is non-null */
4889  cmp = tp_value_compare (&left_dbval, &right_dbval, 1, 0);
4890 
4891  if (left_is_set && cmp == DB_UNK && qexec_collection_has_null (&left_dbval))
4892  {
4893  cmp = DB_LT;
4894  }
4895  if (right_is_set && cmp == DB_UNK && qexec_collection_has_null (&right_dbval))
4896  {
4897  cmp = DB_GT;
4898  }
4899 
4900  clear:
4901  if (left_is_set || DB_NEED_CLEAR (&left_dbval))
4902  {
4903  pr_clear_value (&left_dbval);
4904  }
4905 
4906  if (right_is_set || DB_NEED_CLEAR (&right_dbval))
4907  {
4908  pr_clear_value (&right_dbval);
4909  }
4910 
4911  if (cmp == DB_EQ)
4912  {
4913  continue; /* step into the next tval */
4914  }
4915 
4916  if (cmp == DB_LT || cmp == DB_GT)
4917  {
4918  ; /* OK */
4919  }
4920  else
4921  { /* is error */
4922  cmp = DB_UNK;
4923  }
4924 
4925  /* at here, immediately return */
4926  break;
4927  }
4928 
4929  return (DB_VALUE_COMPARE_RESULT) cmp;
4930 }
4931 
4932 /*
4933  * qexec_size_remaining () -
4934  * return: int
4935  * tplrec1(in) : First tuple descriptor
4936  * tplrec2(in) : Second tuple descriptor
4937  * merge_info(in) : Tuple merge information
4938  * k(in) : column to start at
4939  *
4940  * Note: This routine calculates the size needed to store the
4941  * remaining tuple to copy.
4942  * If either tuple is a NULL pointer, assume that the space
4943  * for an UNBOUND (header) will be needed.
4944  */
4945 static long
4947  int k)
4948 {
4949  int i, tpl_size;
4950  char *t_valhp;
4951 
4952  tpl_size = 0;
4953  for (i = k; i < merge_info->ls_pos_cnt; i++)
4954  {
4955  tpl_size += QFILE_TUPLE_VALUE_HEADER_SIZE;
4956  if (merge_info->ls_outer_inner_list[i] == QFILE_OUTER_LIST)
4957  {
4958  if (tplrec1)
4959  {
4960  QFILE_GET_TUPLE_VALUE_HEADER_POSITION (tplrec1->tpl, merge_info->ls_pos_list[i], t_valhp);
4961  tpl_size += QFILE_GET_TUPLE_VALUE_LENGTH (t_valhp);
4962  }
4963  }
4964  else
4965  {
4966  if (tplrec2)
4967  {
4968  QFILE_GET_TUPLE_VALUE_HEADER_POSITION (tplrec2->tpl, merge_info->ls_pos_list[i], t_valhp);
4969  tpl_size += QFILE_GET_TUPLE_VALUE_LENGTH (t_valhp);
4970  }
4971  }
4972  }
4973 
4974  return tpl_size;
4975 }
4976 
4977 /*
4978  * qexec_merge_tuple () -
4979  * return: NO_ERROR, or ER_code
4980  * tplrec1(in) : First tuple descriptor
4981  * tplrec2(in) : Second tuple descriptor
4982  * merge_info(in) : Tuple merge information
4983  * tplrec(in) : Result tuple descriptor
4984  *
4985  * Note: This routine merges the given two list files tuples using
4986  * the given list merge information and stores the result into
4987  * result tuple descriptor.
4988  */
4989 static int
4991  QFILE_TUPLE_RECORD * tplrec)
4992 {
4993  QFILE_TUPLE tplp;
4994  char *t_valhp;
4995  int t_val_size;
4996  int tpl_size, offset;
4997  int k;
4998  INT32 ls_unbound[2] = { 0, 0 };
4999 
5000  /* merge two tuples, and form a new tuple */
5001  tplp = tplrec->tpl;
5002  offset = 0;
5003  QFILE_PUT_TUPLE_LENGTH (tplp, QFILE_TUPLE_LENGTH_SIZE); /* set tuple length */
5004  tplp += QFILE_TUPLE_LENGTH_SIZE;
5005  offset += QFILE_TUPLE_LENGTH_SIZE;
5006 
5007  QFILE_PUT_TUPLE_VALUE_FLAG ((char *) ls_unbound, V_UNBOUND);
5008  QFILE_PUT_TUPLE_VALUE_LENGTH ((char *) ls_unbound, 0);
5009 
5010  /* copy tuple values from the first and second list file tuples */
5011  for (k = 0; k < merge_info->ls_pos_cnt; k++)
5012  {
5013 
5014  if (merge_info->ls_outer_inner_list[k] == QFILE_OUTER_LIST)
5015  {
5016  if (tplrec1)
5017  {
5018  QFILE_GET_TUPLE_VALUE_HEADER_POSITION (tplrec1->tpl, merge_info->ls_pos_list[k], t_valhp);
5019  }
5020  else
5021  {
5022  t_valhp = (char *) ls_unbound;
5023  }
5024  }
5025  else
5026  { /* copy from the second tuple */
5027  if (tplrec2)
5028  {
5029  QFILE_GET_TUPLE_VALUE_HEADER_POSITION (tplrec2->tpl, merge_info->ls_pos_list[k], t_valhp);
5030  }
5031  else
5032  {
5033  t_valhp = (char *) ls_unbound;
5034  }
5035  }
5036 
5038  if ((tplrec->size - offset) < t_val_size)
5039  { /* no space left */
5040  tpl_size = offset + qexec_size_remaining (tplrec1, tplrec2, merge_info, k);
5041  if (qfile_reallocate_tuple (tplrec, tpl_size) != NO_ERROR)
5042  {
5043  return ER_FAILED;
5044  }
5045  tplp = (QFILE_TUPLE) tplrec->tpl + offset;
5046  }
5047 
5048  memcpy (tplp, t_valhp, t_val_size);
5049  tplp += t_val_size;
5050  offset += t_val_size;
5051  } /* for */
5052 
5053  /* set tuple length */
5054  QFILE_PUT_TUPLE_LENGTH (tplrec->tpl, offset);
5055 
5056  return NO_ERROR;
5057 }
5058 
5059 /*
5060  * qexec_merge_tuple_add_list () - Merge a tuple, and add it to the list file
5061  * return: NO_ERROR, or ER_code
5062  * list_id(in) : List file to insert into
5063  * tplrec1(in) : First tuple descriptor
5064  * tplrec2(in) : Second tuple descriptor
5065  * merge_info(in) : Tuple merge information
5066  * tplrec(in) : Result tuple descriptor
5067  */
5068 static int
5070  QFILE_TUPLE_RECORD * tplrec2, QFILE_LIST_MERGE_INFO * merge_info,
5071  QFILE_TUPLE_RECORD * tplrec)
5072 {
5073  int ret;
5075  int tplrec1_max_size;
5076  int tplrec2_max_size;
5077 
5078  /* get tuple descriptor */
5079  tdp = &(list_id->tpl_descr);
5080 
5081  if (tplrec1)
5082  {
5083  tplrec1_max_size = QFILE_GET_TUPLE_LENGTH (tplrec1->tpl);
5084  }
5085  else
5086  {
5087  tplrec1_max_size = QFILE_TUPLE_VALUE_HEADER_SIZE * (merge_info->ls_pos_cnt);
5088  }
5089 
5090  if (tplrec2)
5091  {
5092  tplrec2_max_size = QFILE_GET_TUPLE_LENGTH (tplrec2->tpl);
5093  }
5094  else
5095  {
5096  tplrec2_max_size = QFILE_TUPLE_VALUE_HEADER_SIZE * (merge_info->ls_pos_cnt);
5097  }
5098 
5099  tdp->tpl_size = DB_ALIGN (tplrec1_max_size + tplrec2_max_size, MAX_ALIGNMENT);
5100 
5102  { /* SMALL QFILE_TUPLE */
5103  /* set tuple descriptor */
5104  tdp->tplrec1 = tplrec1;
5105  tdp->tplrec2 = tplrec2;
5106  tdp->merge_info = merge_info;
5107 
5108  /* build merged tuple into the list file page */
5109  ret = qfile_generate_tuple_into_list (thread_p, list_id, T_MERGE);
5110  }
5111  else
5112  { /* BIG QFILE_TUPLE */
5113  /* merge two tuples, and form a new tuple */
5114  ret = qexec_merge_tuple (tplrec1, tplrec2, merge_info, tplrec);
5115  if (ret != NO_ERROR)
5116  {
5117  return ret;
5118  }
5119 
5120  /* add merged tuple to the resultant list file */
5121  ret = qfile_add_tuple_to_list (thread_p, list_id, tplrec->tpl);
5122  }
5123 
5124  return ret;
5125 }
5126 
5127 /* pre-defined vars: list_idp,
5128  * merge_infop,
5129  * nvals
5130  * tplrec
5131  * indp
5132  * valp
5133  * scan
5134  * sid
5135  */
5136 /****************************** COMMON MACRO ********************************/
5137 #define QEXEC_MERGE_ADD_MERGETUPLE(thread_p, t1, t2) \
5138  do { \
5139  if (qexec_merge_tuple_add_list((thread_p), list_idp, (t1), (t2), \
5140  merge_infop, &tplrec) != NO_ERROR) { \
5141  goto exit_on_error; \
5142  } \
5143  } while (0)
5144 
5145 #define QEXEC_MERGE_PVALS(pre) \
5146  do { \
5147  int _v; \
5148  for (_v = 0; _v < nvals; _v++) { \
5149  do { \
5150  QFILE_GET_TUPLE_VALUE_HEADER_POSITION((pre##_tplrec).tpl, \
5151  (pre##_indp)[_v], \
5152  (pre##_valp)[_v]); \
5153  } while (0); \
5154  } \
5155  } while (0)
5156 
5157 /**************************** INNER MERGE MACRO *****************************/
5158 #define QEXEC_MERGE_NEXT_SCAN(thread_p, pre, e) \
5159  do { \
5160  pre##_scan = qfile_scan_list_next((thread_p), &(pre##_sid), &(pre##_tplrec), PEEK); \
5161  if ((e) && pre##_scan == S_END) \
5162  goto exit_on_end; \
5163  if (pre##_scan == S_ERROR) \
5164  goto exit_on_error; \
5165  } while (0)
5166 
5167 #define QEXEC_MERGE_PREV_SCAN(thread_p, pre) \
5168  do { \
5169  pre##_scan = qfile_scan_list_prev((thread_p), &(pre##_sid), &(pre##_tplrec), PEEK); \
5170  if (pre##_scan == S_ERROR) \
5171  goto exit_on_error; \
5172  } while (0)
5173 
5174 #define QEXEC_MERGE_NEXT_SCAN_PVALS(thread_p, pre, e) \
5175  do { \
5176  QEXEC_MERGE_NEXT_SCAN((thread_p), pre, e); \
5177  if (pre##_scan == S_SUCCESS) { \
5178  QEXEC_MERGE_PVALS(pre); \
5179  } \
5180  } while (0)
5181 
5182 #define QEXEC_MERGE_REV_SCAN_PVALS(thread_p, pre) \
5183  do { \
5184  QEXEC_MERGE_PREV_SCAN((thread_p), pre); \
5185  if (pre##_scan == S_SUCCESS) { \
5186  QEXEC_MERGE_PVALS(pre); \
5187  } \
5188  } while (0)
5189 
5190 /**************************** OUTER MERGE MACRO *****************************/
5191 #define QEXEC_MERGE_OUTER_NEXT_SCAN(thread_p, pre, e) \
5192  do { \
5193  pre##_sid->qualification = QPROC_QUALIFIED_OR_NOT; /* init */ \
5194  pre##_scan = scan_next_scan((thread_p), pre##_sid); \
5195  if ((e) && pre##_scan == S_END) \
5196  goto exit_on_end; \
5197  if (pre##_scan == S_ERROR) \
5198  goto exit_on_error; \
5199  } while (0)
5200 
5201 #define QEXEC_MERGE_OUTER_PREV_SCAN(thread_p, pre) \
5202  do { \
5203  pre##_sid->qualification = QPROC_QUALIFIED_OR_NOT; /* init */ \
5204  pre##_scan = scan_prev_scan((thread_p), pre##_sid); \
5205  if (pre##_scan == S_ERROR) \
5206  goto exit_on_error; \
5207  } while (0)
5208 
5209 #define QEXEC_MERGE_OUTER_NEXT_SCAN_PVALS(thread_p, pre, e) \
5210  do { \
5211  QEXEC_MERGE_OUTER_NEXT_SCAN((thread_p), pre, e); \
5212  if (pre##_scan == S_SUCCESS) { \
5213  QEXEC_MERGE_PVALS(pre); \
5214  } \
5215  } while (0)
5216 
5217 #define QEXEC_MERGE_OUTER_PREV_SCAN_PVALS(thread_p, pre) \
5218  do { \
5219  QEXEC_MERGE_OUTER_PREV_SCAN((thread_p), pre); \
5220  if (pre##_scan == S_SUCCESS) { \
5221  QEXEC_MERGE_PVALS(pre); \
5222  } \
5223  } while (0)
5224 
5225 /*
5226  * qexec_merge_list () -
5227  * return: QFILE_LIST_ID *, or NULL
5228  * outer_list_idp(in) : First (left) list file to be merged
5229  * inner_list_idp(in) : Second (right) list file to be merged
5230  * merge_infop(in) : List file merge information
5231  * ls_flag(in) :
5232  *
5233  * Note: This routine merges the given two sorted list files using
5234  * the given list file merge information and returns the result
5235  * list file identifier.
5236  *
5237  * Note: The routine assumes that the join column data types for both list
5238  * files are same.
5239  */
5240 static QFILE_LIST_ID *
5241 qexec_merge_list (THREAD_ENTRY * thread_p, QFILE_LIST_ID * outer_list_idp, QFILE_LIST_ID * inner_list_idp,
5242  QFILE_LIST_MERGE_INFO * merge_infop, int ls_flag)
5243 {
5244  /* outer -> left scan, inner -> right scan */
5245 
5246  /* pre-defined vars: */
5247  QFILE_LIST_ID *list_idp = NULL;
5248  int nvals;
5249  QFILE_TUPLE_RECORD tplrec = { NULL, 0 };
5250  QFILE_TUPLE_RECORD outer_tplrec = { NULL, 0 };
5251  QFILE_TUPLE_RECORD inner_tplrec = { NULL, 0 };
5252  int *outer_indp, *inner_indp;
5253  char **outer_valp = NULL, **inner_valp = NULL;
5254  SCAN_CODE outer_scan = S_END, inner_scan = S_END;
5255  QFILE_LIST_SCAN_ID outer_sid, inner_sid;
5256 
5257  TP_DOMAIN **outer_domp = NULL, **inner_domp = NULL;
5258  QFILE_TUPLE_VALUE_TYPE_LIST type_list;
5259  int k, cnt, group_cnt, already_compared;
5260  SCAN_DIRECTION direction;
5261  QFILE_TUPLE_POSITION inner_tplpos;
5262  DB_VALUE_COMPARE_RESULT val_cmp;
5263 
5264  /* get merge columns count */
5265  nvals = merge_infop->ls_column_cnt;
5266 
5267  /* get indicator of merge columns */
5268  outer_indp = merge_infop->ls_outer_column;
5269  inner_indp = merge_infop->ls_inner_column;
5270 
5271  /* form the typelist for the resultant list file */
5272  type_list.type_cnt = merge_infop->ls_pos_cnt;
5273  type_list.domp = (TP_DOMAIN **) malloc (type_list.type_cnt * sizeof (TP_DOMAIN *));
5274  if (type_list.domp == NULL)
5275  {
5276  goto exit_on_error;
5277  }
5278 
5279  for (k = 0; k < type_list.type_cnt; k++)
5280  {
5281  type_list.domp[k] = ((merge_infop->ls_outer_inner_list[k] == QFILE_OUTER_LIST)
5282  ? outer_list_idp->type_list.domp[merge_infop->ls_pos_list[k]]
5283  : inner_list_idp->type_list.domp[merge_infop->ls_pos_list[k]]);
5284  }
5285 
5286  outer_sid.status = S_CLOSED;
5287  inner_sid.status = S_CLOSED;
5288 
5289  /* open a scan on the outer(inner) list file */
5290  if (qfile_open_list_scan (outer_list_idp, &outer_sid) != NO_ERROR
5291  || qfile_open_list_scan (inner_list_idp, &inner_sid) != NO_ERROR)
5292  {
5293  goto exit_on_error;
5294  }
5295 
5296  /* open the result list file; same query id with outer(inner) list file */
5297  list_idp = qfile_open_list (thread_p, &type_list, NULL, outer_list_idp->query_id, ls_flag);
5298  if (list_idp == NULL)
5299  {
5300  goto exit_on_error;
5301  }
5302 
5303  if (outer_list_idp->tuple_cnt == 0 || inner_list_idp->tuple_cnt == 0)
5304  {
5305  goto exit_on_end;
5306  }
5307 
5308  /* allocate the area to store the merged tuple */
5309  if (qfile_reallocate_tuple (&tplrec, DB_PAGESIZE) != NO_ERROR)
5310  {
5311  goto exit_on_error;
5312  }
5313 
5314  /* merge column domain info */
5315  outer_domp = (TP_DOMAIN **) db_private_alloc (thread_p, nvals * sizeof (TP_DOMAIN *));
5316  if (outer_domp == NULL)
5317  {
5318  goto exit_on_error;
5319  }
5320 
5321  inner_domp = (TP_DOMAIN **) db_private_alloc (thread_p, nvals * sizeof (TP_DOMAIN *));
5322  if (inner_domp == NULL)
5323  {
5324  goto exit_on_error;
5325  }
5326 
5327  for (k = 0; k < nvals; k++)
5328  {
5329  outer_domp[k] = outer_list_idp->type_list.domp[merge_infop->ls_outer_column[k]];
5330  inner_domp[k] = inner_list_idp->type_list.domp[merge_infop->ls_inner_column[k]];
5331  }
5332 
5333  /* merge column val pointer */
5334  outer_valp = (char **) db_private_alloc (thread_p, nvals * sizeof (char *));
5335  if (outer_valp == NULL)
5336  {
5337  goto exit_on_error;
5338  }
5339 
5340  inner_valp = (char **) db_private_alloc (thread_p, nvals * sizeof (char *));
5341  if (inner_valp == NULL)
5342  {
5343  goto exit_on_error;
5344  }
5345 
5346  /* When a list file is sorted on a column, all the NULL values appear at the beginning of the list. So, we know that
5347  * all the following values in the inner/outer column are BOUND(not NULL) values. Depending on the join type, we must
5348  * skip or join with a NULL opposite row, when a NULL is encountered. */
5349 
5350  /* move the outer(left) scan to the first tuple */
5351  while (1)
5352  {
5353  /* move to the next outer tuple and position tuple values (to merge columns) */
5354  QEXEC_MERGE_NEXT_SCAN_PVALS (thread_p, outer, true);
5355 
5356  for (k = 0; k < nvals; k++)
5357  {
5358  if (QFILE_GET_TUPLE_VALUE_FLAG (outer_valp[k]) == V_UNBOUND)
5359  {
5360  break;
5361  }
5362  }
5363  if (k >= nvals)
5364  { /* not found V_UNBOUND. exit loop */
5365  break;
5366  }
5367  }
5368 
5369  /* move the inner(right) scan to the first tuple */
5370  while (1)
5371  {
5372  /* move to the next inner tuple and position tuple values (to merge columns) */
5373  QEXEC_MERGE_NEXT_SCAN_PVALS (thread_p, inner, true);
5374 
5375  for (k = 0; k < nvals; k++)
5376  {
5377  if (QFILE_GET_TUPLE_VALUE_FLAG (inner_valp[k]) == V_UNBOUND)
5378  {
5379  break;
5380  }
5381  }
5382  if (k >= nvals)
5383  { /* not found V_UNBOUND. exit loop */
5384  break;
5385  }
5386 
5387  }
5388 
5389  /* set the comparison function to be called */
5390  direction = S_FORWARD;
5391  group_cnt = 0;
5392  already_compared = false;
5393  val_cmp = DB_UNK;
5394 
5395  while (1)
5396  {
5397  /* compare two tuple values, if they have not been compared yet */
5398  if (!already_compared)
5399  {
5400  val_cmp = qexec_cmp_tpl_vals_merge (outer_valp, outer_domp, inner_valp, inner_domp, nvals);
5401  if (val_cmp == DB_UNK)
5402  { /* is error */
5403  goto exit_on_error;
5404  }
5405  }
5406  already_compared = false; /* re-init */
5407 
5408  /* value of the outer is less than value of the inner */
5409  if (val_cmp == DB_LT)
5410  {
5411  /* move the outer(left) scan to the next tuple and position tuple values (to merge columns) */
5412  QEXEC_MERGE_NEXT_SCAN_PVALS (thread_p, outer, true);
5413  direction = S_FORWARD;
5414  group_cnt = 0;
5415 
5416  continue;
5417  }
5418 
5419  /* value of the outer is greater than value of the inner */
5420  if (val_cmp == DB_GT)
5421  {
5422  /* move the inner(right) scan to the next tuple and position tuple values (to merge columns) */
5423  QEXEC_MERGE_NEXT_SCAN_PVALS (thread_p, inner, true);
5424  direction = S_FORWARD;
5425  group_cnt = 0;
5426 
5427  continue;
5428  }
5429 
5430  if (val_cmp != DB_EQ)
5431  { /* error ? */
5432  goto exit_on_error;
5433  }
5434 
5435  /* values of the outer and inner are equal, do a scan group processing */
5436  if (direction == S_FORWARD)
5437  {
5438  /* move forwards within a group */
5439  cnt = 0;
5440  /* group_cnt has the number of tuples in the group */
5441  while (1)
5442  {
5443  /* merge the fetched tuples(left and right) */
5444  QEXEC_MERGE_ADD_MERGETUPLE (thread_p, &outer_tplrec, &inner_tplrec);
5445 
5446  cnt++; /* increase the counter of processed tuples */
5447 
5448  /* if the group is formed for the first time */
5449  if (group_cnt == 0)
5450  {
5451  /* move the inner(right) scan to the next tuple and position tuple values (to merge columns) */
5452  QEXEC_MERGE_NEXT_SCAN_PVALS (thread_p, inner, false /* do not exit */ );
5453  if (inner_scan == S_END)
5454  {
5455  break;
5456  }
5457 
5458  /* and compare */
5459  val_cmp = qexec_cmp_tpl_vals_merge (outer_valp, outer_domp, inner_valp, inner_domp, nvals);
5460  if (val_cmp != DB_EQ)
5461  {
5462  if (val_cmp == DB_UNK)
5463  { /* is error */
5464  goto exit_on_error;
5465  }
5466 
5467  break; /* found the bottom of the group */
5468  }
5469  }
5470  else
5471  { /* group_cnt > 0 */
5472  if (cnt >= group_cnt)
5473  {
5474  break; /* reached the bottom of the group */
5475  }
5476 
5477  /* move the inner(right) scan to the next tuple */
5478  QEXEC_MERGE_NEXT_SCAN (thread_p, inner, true);
5479  }
5480  } /* while (1) */
5481 
5482  /* move the outer to the next tuple and position tuple values */
5483  QEXEC_MERGE_NEXT_SCAN_PVALS (thread_p, outer, true);
5484 
5485  /* if the group is formed for the first time */
5486  if (group_cnt == 0)
5487  {
5488  /* save the position of inner scan; it is the bottom of the group */
5489  qfile_save_current_scan_tuple_position (&inner_sid, &inner_tplpos);
5490 
5491  if (inner_scan == S_END)
5492  {
5493  /* move the inner to the previous tuple and position tuple values */
5494  QEXEC_MERGE_REV_SCAN_PVALS (thread_p, inner);
5495 
5496  /* set group count and direction */
5497  group_cnt = cnt;
5498  direction = S_BACKWARD;
5499  }
5500  else
5501  {
5502  /* and compare */
5503  val_cmp = qexec_cmp_tpl_vals_merge (outer_valp, outer_domp, inner_valp, inner_domp, nvals);
5504  if (val_cmp == DB_UNK)
5505  { /* is error */
5506  goto exit_on_error;
5507  }
5508 
5509  if (val_cmp == DB_LT)
5510  {
5511  /* move the inner to the previous tuple and position tuple values */
5512  QEXEC_MERGE_REV_SCAN_PVALS (thread_p, inner);
5513 
5514  /* and compare */
5515  val_cmp = qexec_cmp_tpl_vals_merge (outer_valp, outer_domp, inner_valp, inner_domp, nvals);
5516  if (val_cmp == DB_UNK)
5517  { /* is error */
5518  goto exit_on_error;
5519  }
5520 
5521  if (val_cmp == DB_EQ)
5522  {
5523  /* next value is the same, so prepare for further group scan operations */
5524 
5525  /* set group count and direction */
5526  group_cnt = cnt;
5527  direction = S_BACKWARD;
5528  }
5529  else
5530  {
5531  /* move the inner to the current tuple and position tuple values */
5532  QEXEC_MERGE_NEXT_SCAN_PVALS (thread_p, inner, true);
5533 
5534  val_cmp = DB_LT; /* restore comparison */
5535  }
5536  }
5537 
5538  /* comparison has already been done */
5539  already_compared = true;
5540  }
5541  }
5542  else
5543  {
5544  /* set further scan direction */
5545  direction = S_BACKWARD;
5546  }
5547  }
5548  else
5549  { /* (direction == S_BACKWARD) */
5550  /* move backwards within a group */
5551  cnt = group_cnt;
5552  /* group_cnt has the number of tuples in the group */
5553  while (1)
5554  {
5555  /* merge the fetched tuples(left and right) */
5556  QEXEC_MERGE_ADD_MERGETUPLE (thread_p, &outer_tplrec, &inner_tplrec);
5557 
5558  cnt--; /* decrease the counter of the processed tuples */
5559 
5560  if (cnt <= 0)
5561  {
5562  break; /* finish the group */
5563  }
5564 
5565  /* if not yet reached the top of the group */
5566  /* move the inner(right) scan to the previous tuple */
5567  QEXEC_MERGE_PREV_SCAN (thread_p, inner);
5568 
5569  /* all of the inner tuples in the group have the same value at the merge column, so we don't need to
5570  * compare with the value of the outer one; just count the number of the tuples in the group */
5571  } /* while (1) */
5572 
5573  /* position tuple values (to merge columns) */
5574  QEXEC_MERGE_PVALS (inner);
5575 
5576  /* move the outer(left) scan to the next tuple and position tuple values */
5577  QEXEC_MERGE_NEXT_SCAN_PVALS (thread_p, outer, true);
5578 
5579  /* and compare */
5580  val_cmp = qexec_cmp_tpl_vals_merge (outer_valp, outer_domp, inner_valp, inner_domp, nvals);
5581  if (val_cmp == DB_UNK)
5582  { /* is error */
5583  goto exit_on_error;
5584  }
5585 
5586  if (val_cmp != DB_EQ)
5587  {
5588  /* jump to the previously set scan position */
5589  inner_scan = qfile_jump_scan_tuple_position (thread_p, &inner_sid, &inner_tplpos, &inner_tplrec, PEEK);
5590  /* is saved position the end of scan? */
5591  if (inner_scan == S_END)
5592  {
5593  goto exit_on_end;
5594  }
5595 
5596  /* and position tuple values */
5597  QEXEC_MERGE_PVALS (inner);
5598 
5599  /* reset group count */
5600  group_cnt = 0;
5601  }
5602  else
5603  {
5604  /* comparison has already been done */
5605  already_compared = true;
5606  }
5607 
5608  /* set further scan direction */
5609  direction = S_FORWARD;
5610 
5611  } /* (direction == S_BACKWARD) */
5612 
5613  } /* while (1) */
5614 
5615 exit_on_end:
5616  free_and_init (type_list.domp);
5617  qfile_close_scan (thread_p, &outer_sid);
5618  qfile_close_scan (thread_p, &inner_sid);
5619 
5620  if (tplrec.tpl)
5621  {
5622  db_private_free_and_init (thread_p, tplrec.tpl);
5623  }
5624 
5625  if (outer_domp)
5626  {
5627  db_private_free_and_init (thread_p, outer_domp);
5628  }
5629  if (outer_valp)
5630  {
5631  db_private_free_and_init (thread_p, outer_valp);
5632  }
5633 
5634  if (inner_domp)
5635  {
5636  db_private_free_and_init (thread_p, inner_domp);
5637  }
5638  if (inner_valp)
5639  {
5640  db_private_free_and_init (thread_p, inner_valp);
5641  }
5642 
5643  if (list_idp)
5644  {
5645  qfile_close_list (thread_p, list_idp);
5646  }
5647 
5648  return list_idp;
5649 
5650 exit_on_error:
5651  if (list_idp)
5652  {
5653  qfile_close_list (thread_p, list_idp);
5654  QFILE_FREE_AND_INIT_LIST_ID (list_idp);
5655  }
5656 
5657  list_idp = NULL;
5658  goto exit_on_end;
5659 }
5660 
5661 /*
5662  * qexec_merge_list_outer () -
5663  * return:
5664  * outer_sid(in) :
5665  * inner_sid(in) :
5666  * merge_infop(in) :
5667  * other_outer_join_pred(in) :
5668  * xasl_state(in) :
5669  * ls_flag(in) :
5670  */
5671 static QFILE_LIST_ID *
5672 qexec_merge_list_outer (THREAD_ENTRY * thread_p, SCAN_ID * outer_sid, SCAN_ID * inner_sid,
5673  QFILE_LIST_MERGE_INFO * merge_infop, PRED_EXPR * other_outer_join_pred, XASL_STATE * xasl_state,
5674  int ls_flag)
5675 {
5676  /* outer -> left scan, inner -> right scan */
5677 
5678  /* pre-defined vars: */
5679  QFILE_LIST_ID *list_idp = NULL;
5680  int nvals;
5681  QFILE_TUPLE_RECORD tplrec = { NULL, 0 };
5682  QFILE_TUPLE_RECORD outer_tplrec = { NULL, 0 };
5683  QFILE_TUPLE_RECORD inner_tplrec = { NULL, 0 };
5684  int *outer_indp, *inner_indp;
5685  char **outer_valp = NULL, **inner_valp = NULL;
5686  SCAN_CODE outer_scan = S_END, inner_scan = S_END;
5687 
5688  TP_DOMAIN **outer_domp = NULL, **inner_domp = NULL;
5689  QFILE_LIST_ID *outer_list_idp, *inner_list_idp;
5690  QFILE_TUPLE_VALUE_TYPE_LIST type_list;
5691  int k, cnt, group_cnt, merge_cnt, already_compared;
5692  SCAN_DIRECTION direction;
5693  SCAN_POS inner_scanpos;
5694  bool all_lefts, all_rghts;
5695  DB_LOGICAL ev_res;
5696  DB_VALUE_COMPARE_RESULT val_cmp;
5697 
5698  direction = S_FORWARD; /* init */
5699  val_cmp = DB_NE; /* init - mark as not yet compared */
5700 
5701  /* determine all lefts or all rights option depending on join type */
5702  all_lefts = (merge_infop->join_type == JOIN_LEFT || merge_infop->join_type == JOIN_OUTER) ? true : false;
5703  all_rghts = (merge_infop->join_type == JOIN_RIGHT || merge_infop->join_type == JOIN_OUTER) ? true : false;
5704 
5705  /* QFILE_LIST_ID pointer from SCAN_ID */
5706  outer_list_idp = outer_sid->s.llsid.list_id;
5707  inner_list_idp = inner_sid->s.llsid.list_id;
5708 
5709  /* get merge columns count */
5710  nvals = merge_infop->ls_column_cnt;
5711 
5712  /* get indicator of merge columns */
5713  outer_indp = merge_infop->ls_outer_column;
5714  inner_indp = merge_infop->ls_inner_column;
5715 
5716  /* form the typelist for the resultant list file */
5717  type_list.type_cnt = merge_infop->ls_pos_cnt;
5718  type_list.domp = (TP_DOMAIN **) malloc (type_list.type_cnt * sizeof (TP_DOMAIN *));
5719  if (type_list.domp == NULL)
5720  {
5722  }
5723 
5724  for (k = 0; k < type_list.type_cnt; k++)
5725  {
5726  type_list.domp[k] = ((merge_infop->ls_outer_inner_list[k] == QFILE_OUTER_LIST)
5727  ? outer_list_idp->type_list.domp[merge_infop->ls_pos_list[k]]
5728  : inner_list_idp->type_list.domp[merge_infop->ls_pos_list[k]]);
5729  }
5730 
5731  /* open the result list file; same query id with outer(inner) list file */
5732  list_idp = qfile_open_list (thread_p, &type_list, NULL, outer_list_idp->query_id, ls_flag);
5733  if (list_idp == NULL)
5734  {
5735  goto exit_on_error;
5736  }
5737 
5738  if (all_lefts && outer_list_idp->tuple_cnt == 0)
5739  {
5740  all_lefts = false;
5741  goto exit_on_end;
5742  }
5743  if (all_rghts && inner_list_idp->tuple_cnt == 0)
5744  {
5745  all_rghts = false;
5746  goto exit_on_end;
5747  }
5748 
5749  /* allocate the area to store the merged tuple */
5750  if (qfile_reallocate_tuple (&tplrec, DB_PAGESIZE) != NO_ERROR)
5751  {
5752  goto exit_on_error;
5753  }
5754 
5755  /* merge column domain info */
5756  outer_domp = (TP_DOMAIN **) db_private_alloc (thread_p, nvals * sizeof (TP_DOMAIN *));
5757  if (outer_domp == NULL)
5758  {
5759  goto exit_on_error;
5760  }
5761 
5762  inner_domp = (TP_DOMAIN **) db_private_alloc (thread_p, nvals * sizeof (TP_DOMAIN *));
5763  if (inner_domp == NULL)
5764  {
5765  goto exit_on_error;
5766  }
5767 
5768  for (k = 0; k < nvals; k++)
5769  {
5770  outer_domp[k] = outer_list_idp->type_list.domp[merge_infop->ls_outer_column[k]];
5771  inner_domp[k] = inner_list_idp->type_list.domp[merge_infop->ls_inner_column[k]];
5772  }
5773 
5774  /* merge column val pointer */
5775  outer_valp = (char **) db_private_alloc (thread_p, nvals * sizeof (char *));
5776  if (outer_valp == NULL)
5777  {
5778  goto exit_on_error;
5779  }
5780 
5781  inner_valp = (char **) db_private_alloc (thread_p, nvals * sizeof (char *));
5782  if (inner_valp == NULL)
5783  {
5784  goto exit_on_error;
5785  }
5786 
5787  /* start scans */
5788  if (scan_start_scan (thread_p, outer_sid) != NO_ERROR || scan_start_scan (thread_p, inner_sid) != NO_ERROR)
5789  {
5790  goto exit_on_error;
5791  }
5792 
5793  /* set tuple record pointer in QFILE_LIST_SCAN_ID */
5794  outer_sid->s.llsid.tplrecp = &outer_tplrec;
5795  inner_sid->s.llsid.tplrecp = &inner_tplrec;
5796 
5797 
5798  /* When a list file is sorted on a column, all the NULL value appear at the beginning of the list. So, we know that
5799  * all the following values in the outer/inner column are BOUND(not NULL) value. And we can process all NULL values
5800  * before the merging process. */
5801 
5802  /* move the outer(left) scan to the first tuple */
5803  while (1)
5804  {
5805  /* fetch a next tuple from outer(left) list file and position tuple values (to merge columns) */
5806  QEXEC_MERGE_OUTER_NEXT_SCAN_PVALS (thread_p, outer, true);
5807 
5808  if (outer_sid->qualification == QPROC_QUALIFIED)
5809  {
5810  for (k = 0; k < nvals; k++)
5811  {
5812  if (QFILE_GET_TUPLE_VALUE_FLAG (outer_valp[k]) == V_UNBOUND)
5813  {
5814  break;
5815  }
5816  }
5817  if (k >= nvals)
5818  { /* not found V_UNBOUND */
5819  break; /* found valid tuple. exit loop */
5820  }
5821  }
5822 
5823  /* depending on the join type, join with a NULL opposite row when a NULL or a not-qualified is encountered, or
5824  * skip it. */
5825  if (all_lefts)
5826  {
5827  QEXEC_MERGE_ADD_MERGETUPLE (thread_p, &outer_tplrec, NULL);
5828  }
5829  }
5830 
5831  /* move the inner(right) scan to the first tuple */
5832  while (1)
5833  {
5834  /* move the inner(right) scan to the first tuple and position tuple values (to merge columns) */
5835  QEXEC_MERGE_OUTER_NEXT_SCAN_PVALS (thread_p, inner, true);
5836 
5837  if (inner_sid->qualification == QPROC_QUALIFIED)
5838  {
5839  for (k = 0; k < nvals; k++)
5840  {
5841  if (QFILE_GET_TUPLE_VALUE_FLAG (inner_valp[k]) == V_UNBOUND)
5842  {
5843  break;
5844  }
5845  }
5846  if (k >= nvals)
5847  { /* not found V_UNBOUND */
5848  break; /* found valid tuple. exit loop */
5849  }
5850  }
5851 
5852  /* depending on the join type, join with a NULL opposite row when a NULL is encountered, or skip it. */
5853  if (all_rghts)
5854  {
5855  QEXEC_MERGE_ADD_MERGETUPLE (thread_p, NULL, &inner_tplrec);
5856  }
5857  }
5858 
5859  /* set the comparison function to be called */
5860  direction = S_FORWARD;
5861  group_cnt = 0;
5862  already_compared = false;
5863  val_cmp = DB_UNK;
5864 
5865  while (1)
5866  {
5867  /* compare two tuple values, if they have not been compared yet */
5868  if (!already_compared)
5869  {
5870  val_cmp = qexec_cmp_tpl_vals_merge (outer_valp, outer_domp, inner_valp, inner_domp, nvals);
5871  if (val_cmp == DB_UNK)
5872  { /* is error */
5873  goto exit_on_error;
5874  }
5875  }
5876  already_compared = false; /* re-init */
5877 
5878  /* value of the outer is less than value of the inner */
5879  if (val_cmp == DB_LT)
5880  {
5881  /* if the group is not yet formed */
5882  if (group_cnt == 0)
5883  {
5884  /* depending on the join type, join with a NULL opposite row when it does not match */
5885  if (all_lefts)
5886  {
5887  /* merge the fetched tuple(left) and NULL tuple(right) */
5888  QEXEC_MERGE_ADD_MERGETUPLE (thread_p, &outer_tplrec, NULL);
5889  }
5890  }
5891 
5892  /* move the outer(left) scan to the next tuple and position tuple values (to merge columns) */
5893  QEXEC_MERGE_OUTER_NEXT_SCAN_PVALS (thread_p, outer, true);
5894  direction = S_FORWARD;
5895  group_cnt = 0;
5896 
5897  continue;
5898  }
5899 
5900  /* value of the outer is greater than value of the inner */
5901  if (val_cmp == DB_GT)
5902  {
5903  /* if the group is not yet formed */
5904  if (group_cnt == 0)
5905  {
5906  /* depending on the join type, join with a NULL opposite row when a NULL is encountered, or skip it. */
5907  if (all_rghts)
5908  {
5909  /* merge the fetched tuple(right) and NULL tuple(left) */
5910  QEXEC_MERGE_ADD_MERGETUPLE (thread_p, NULL, &inner_tplrec);
5911  }
5912  }
5913 
5914  /* move the inner(right) scan to the next tuple and position tuple values (to merge columns) */
5915  QEXEC_MERGE_OUTER_NEXT_SCAN_PVALS (thread_p, inner, true);
5916  direction = S_FORWARD;
5917  group_cnt = 0;
5918 
5919  continue;
5920  }
5921 
5922  if (val_cmp != DB_EQ)
5923  { /* error ? */
5924  goto exit_on_error;
5925  }
5926 
5927  /* values of the outer and inner are equal, do a scan group processing */
5928  merge_cnt = 0;
5929  if (direction == S_FORWARD)
5930  {
5931  /* move forwards within a group */
5932  cnt = 0;
5933  /* group_cnt has the number of tuples in the group */
5934  while (1)
5935  {
5936  /* evaluate other outer join predicate */
5937  ev_res = V_UNKNOWN;
5938  if (other_outer_join_pred != NULL)
5939  {
5940  ev_res = eval_pred (thread_p, other_outer_join_pred, &xasl_state->vd, NULL);
5941  if (ev_res == V_ERROR)
5942  {
5943  goto exit_on_error;
5944  }
5945  }
5946 
5947  /* is qualified */
5948  if (other_outer_join_pred == NULL || ev_res == V_TRUE)
5949  {
5950  /* merge the fetched tuples(left and right) */
5951  QEXEC_MERGE_ADD_MERGETUPLE (thread_p, &outer_tplrec, &inner_tplrec);
5952 
5953  merge_cnt++; /* increase the counter of merged tuples */
5954 
5955  /* if scan works in a single_fetch mode and first qualified scan item has now been fetched, return
5956  * immediately. */
5957  if (merge_infop->single_fetch == QPROC_SINGLE_OUTER)
5958  {
5959  goto exit_on_end;
5960  }
5961  }
5962 
5963  cnt++; /* increase the counter of processed tuples */
5964 
5965  /* if the group is formed for the first time */
5966  if (group_cnt == 0)
5967  {
5968  /* not qualified */
5969  if (!(other_outer_join_pred == NULL || ev_res == V_TRUE))
5970  {
5971  /* depending on the join type, join with a NULL opposite row when a NULL or a not-qualified is
5972  * encountered, or skip it. */
5973  if (all_rghts)
5974  {
5975  /* merge the fetched tuple(right) and NULL tuple(left) */
5976  QEXEC_MERGE_ADD_MERGETUPLE (thread_p, NULL, &inner_tplrec);
5977  }
5978  }
5979 
5980  /* move the inner(right) scan to the next tuple and position tuple values (to merge columns) */
5981  QEXEC_MERGE_OUTER_NEXT_SCAN_PVALS (thread_p, inner, false /* do not exit */
5982  );
5983  if (inner_scan == S_END)
5984  {
5985  if (merge_cnt == 0)
5986  { /* not merged */
5987  /* depending on the join type, join with a NULL opposite row when a NULL or a not-qualified
5988  * is encountered, or skip it. */
5989  if (all_lefts)
5990  {
5991  /* merge the fetched tuple(left) and NULL tuple(right) */
5992  QEXEC_MERGE_ADD_MERGETUPLE (thread_p, &outer_tplrec, NULL);
5993  }
5994  }
5995  break;
5996  }
5997 
5998  /* and compare */
5999  val_cmp = qexec_cmp_tpl_vals_merge (outer_valp, outer_domp, inner_valp, inner_domp, nvals);
6000  if (val_cmp != DB_EQ)
6001  {
6002  if (val_cmp == DB_UNK)
6003  { /* is error */
6004  goto exit_on_error;
6005  }
6006 
6007  if (merge_cnt == 0)
6008  { /* not merged */
6009  /* depending on the join type, join with a NULL opposite row when a NULL or a not-qualified
6010  * is encountered, or skip it. */
6011  if (all_lefts)
6012  {
6013  /* merge the fetched tuple(left) and NULL tuple(right) */
6014  QEXEC_MERGE_ADD_MERGETUPLE (thread_p, &outer_tplrec, NULL);
6015  }
6016  }
6017 
6018  break; /* found the bottom of the group */
6019  }
6020  }
6021  else
6022  { /* group_cnt > 0 */
6023  if (cnt >= group_cnt)
6024  {
6025  if (merge_cnt == 0)
6026  { /* not merged */
6027  /* depending on the join type, join with a NULL opposite row when a NULL or a not-qualified
6028  * is encountered, or skip it. */
6029  if (all_lefts)
6030  {
6031  /* merge the fetched tuple(left) and NULL tuple(right) */
6032  QEXEC_MERGE_ADD_MERGETUPLE (thread_p, &outer_tplrec, NULL);
6033  }
6034  }
6035  break; /* reached the bottom of the group */
6036  }
6037 
6038  /* move the inner(right) scan to the next tuple */
6039  QEXEC_MERGE_OUTER_NEXT_SCAN (thread_p, inner, true);
6040  }
6041  } /* while (1) */
6042 
6043  /* move the outer to the next tuple and position tuple values */
6044  QEXEC_MERGE_OUTER_NEXT_SCAN_PVALS (thread_p, outer, true);
6045 
6046  /* if the group is formed for the first time */
6047  if (group_cnt == 0)
6048  {
6049  /* save the position of inner scan; it is the bottom of the group */
6050  scan_save_scan_pos (inner_sid, &inner_scanpos);
6051 
6052  if (inner_scan == S_END)
6053  {
6054  /* move the inner to the previous tuple and position tuple values */
6055  QEXEC_MERGE_OUTER_PREV_SCAN_PVALS (thread_p, inner);
6056 
6057  /* set group count and direction */
6058  group_cnt = cnt;
6059  direction = S_BACKWARD;
6060  }
6061  else
6062  {
6063  /* and compare */
6064  val_cmp = qexec_cmp_tpl_vals_merge (outer_valp, outer_domp, inner_valp, inner_domp, nvals);
6065  if (val_cmp == DB_UNK)
6066  { /* is error */
6067  goto exit_on_error;
6068  }
6069 
6070  if (val_cmp == DB_LT)
6071  {
6072  /* move the inner to the previous tuple and position tuple values */
6073  QEXEC_MERGE_OUTER_PREV_SCAN_PVALS (thread_p, inner);
6074 
6075  /* and compare */
6076  val_cmp = qexec_cmp_tpl_vals_merge (outer_valp, outer_domp, inner_valp, inner_domp, nvals);
6077  if (val_cmp == DB_UNK)
6078  { /* is error */
6079  goto exit_on_error;
6080  }
6081 
6082  if (val_cmp == DB_EQ)
6083  {
6084  /* next value is the same, so prepare for further group scan operations */
6085 
6086  /* set group count and direction */
6087  group_cnt = cnt;
6088  direction = S_BACKWARD;
6089  }
6090  else
6091  {
6092  /* move the inner to the current tuple and position tuple values */
6093  QEXEC_MERGE_OUTER_NEXT_SCAN_PVALS (thread_p, inner, true);
6094 
6095  val_cmp = DB_LT; /* restore comparison */
6096  }
6097  }
6098 
6099  /* comparison has already been done */
6100  already_compared = true;
6101  }
6102  }
6103  else
6104  {
6105  /* set further scan direction */
6106  direction = S_BACKWARD;
6107  }
6108  }
6109  else
6110  { /* (direction == S_BACKWARD) */
6111  /* move backwards within a group */
6112  cnt = group_cnt;
6113  /* group_cnt has the number of tuples in the group */
6114  while (1)
6115  {
6116  /* evaluate other outer join predicate */
6117  ev_res = V_UNKNOWN;
6118  if (other_outer_join_pred != NULL)
6119  {
6120  ev_res = eval_pred (thread_p, other_outer_join_pred, &xasl_state->vd, NULL);
6121  if (ev_res == V_ERROR)
6122  {
6123  goto exit_on_error;
6124  }
6125  }
6126 
6127  /* is qualified */
6128  if (other_outer_join_pred == NULL || ev_res == V_TRUE)
6129  {
6130  /* merge the fetched tuples(left and right) */
6131  QEXEC_MERGE_ADD_MERGETUPLE (thread_p, &outer_tplrec, &inner_tplrec);
6132 
6133  merge_cnt++; /* increase the counter of merged tuples */
6134  }
6135 
6136  cnt--; /* decrease the counter of the processed tuples */
6137 
6138  if (cnt <= 0)
6139  {
6140  if (merge_cnt == 0)
6141  { /* not merged */
6142  /* depending on the join type, join with a NULL opposite row when a NULL or a not-qualified is
6143  * encountered, or skip it. */
6144  if (all_lefts)
6145  {
6146  /* merge the fetched tuple(left) and NULL tuple(right) */
6147  QEXEC_MERGE_ADD_MERGETUPLE (thread_p, &outer_tplrec, NULL);
6148  }
6149  }
6150  break; /* finish the group */
6151  }
6152 
6153  /* if not yet reached the top of the group */
6154  /* move the inner(right) scan to the previous tuple */
6155  QEXEC_MERGE_OUTER_PREV_SCAN (thread_p, inner);
6156 
6157  /* all of the inner tuples in the group have the same value at the merge column, so we don't need to
6158  * compare with the value of the outer one; just count the number of the tuples in the group */
6159  } /* while (1) */
6160 
6161  /* position tuple values (to merge columns) */
6162  QEXEC_MERGE_PVALS (inner);
6163 
6164  /* move the outer(left) scan to the next tuple and position tuple values */
6165  QEXEC_MERGE_OUTER_NEXT_SCAN_PVALS (thread_p, outer, true);
6166 
6167  /* and compare */
6168  val_cmp = qexec_cmp_tpl_vals_merge (outer_valp, outer_domp, inner_valp, inner_domp, nvals);
6169  if (val_cmp == DB_UNK)
6170  { /* is error */
6171  goto exit_on_error;
6172  }
6173 
6174  if (val_cmp != DB_EQ)
6175  {
6176  /* jump to the previously set scan position */
6177  inner_scan = scan_jump_scan_pos (thread_p, inner_sid, &inner_scanpos);
6178  /* is saved position the end of scan? */
6179  if (inner_scan == S_END)
6180  {
6181  goto exit_on_end; /* inner(right) is exhausted */
6182  }
6183 
6184  /* and position tuple values */
6185  QEXEC_MERGE_PVALS (inner);
6186 
6187  /* reset group count */
6188  group_cnt = 0;
6189  }
6190  else
6191  {
6192  /* comparison has already been done */
6193  already_compared = true;
6194  }
6195 
6196  /* set further scan direction */
6197  direction = S_FORWARD;
6198 
6199  } /* (direction == S_BACKWARD) */
6200 
6201  } /* while (1) */
6202 
6203 exit_on_end:
6204  /* inner(right) is at the end. is there more to the outer(left) ? */
6205  if (all_lefts)
6206  {
6207  while (outer_scan != S_END)
6208  {
6209  /* merge the fetched tuple(left) and NULL tuple(right) */
6210  QEXEC_MERGE_ADD_MERGETUPLE (thread_p, &outer_tplrec, NULL);
6211 
6212  /* move the outer to the next tuple */
6213  QEXEC_MERGE_OUTER_NEXT_SCAN (thread_p, outer, false /* do not exit */ );
6214  }
6215  } /* if (all_lefts) */
6216 
6217  /* outer(left) is at the end. is there more to the inner(right) ? */
6218  if (all_rghts)
6219  {
6220  if (direction == S_FORWARD)
6221  {
6222  if (val_cmp == DB_NE)
6223  { /* mark as not yet compared */
6224  val_cmp = DB_UNK; /* clear */
6225 
6226  /* move the inner(right) scan to the first tuple and position tuple values (to merge columns) */
6227  QEXEC_MERGE_OUTER_NEXT_SCAN_PVALS (thread_p, inner, true);
6228  }
6229  else if (val_cmp == DB_EQ)
6230  { /* outer scan END */
6231  val_cmp = DB_UNK; /* clear */
6232 
6233  /* move the inner(right) scan to the next tuple and position tuple values */
6234  QEXEC_MERGE_OUTER_NEXT_SCAN_PVALS (thread_p, inner, true);
6235  }
6236  }
6237  else
6238  { /* direction == S_BACKWARD */
6239  inner_scan = scan_jump_scan_pos (thread_p, inner_sid, &inner_scanpos);
6240  }
6241  while (inner_scan != S_END)
6242  {
6243  /* merge the fetched tuple(right) and NULL tuple(left) */
6244  QEXEC_MERGE_ADD_MERGETUPLE (thread_p, NULL, &inner_tplrec);
6245 
6246  /* move the inner to the next tuple */
6247  QEXEC_MERGE_OUTER_NEXT_SCAN (thread_p, inner, false /* do not exit */ );
6248  }
6249  } /* if (all_rghts) */
6250 
6251  free_and_init (type_list.domp);
6252  scan_end_scan (thread_p, outer_sid);
6253  scan_end_scan (thread_p, inner_sid);
6254  outer_sid->s.llsid.tplrecp = NULL;
6255  inner_sid->s.llsid.tplrecp = NULL;
6256 
6257  if (tplrec.tpl)
6258  {
6259  db_private_free_and_init (thread_p, tplrec.tpl);
6260  }
6261 
6262  if (outer_domp)
6263  {
6264  db_private_free_and_init (thread_p, outer_domp);
6265  }
6266  if (outer_valp)
6267  {
6268  db_private_free_and_init (thread_p, outer_valp);
6269  }
6270 
6271  if (inner_domp)
6272  {
6273  db_private_free_and_init (thread_p, inner_domp);
6274  }
6275  if (inner_valp)
6276  {
6277  db_private_free_and_init (thread_p, inner_valp);
6278  }
6279 
6280  if (list_idp)
6281  {
6282  qfile_close_list (thread_p, list_idp);
6283  }
6284 
6285  return list_idp;
6286 
6287 exit_on_error:
6288  if (list_idp)
6289  {
6290  qfile_close_list (thread_p, list_idp);
6291  QFILE_FREE_AND_INIT_LIST_ID (list_idp);
6292  }
6293 
6294  list_idp = NULL;
6295 
6296  direction = S_FORWARD;
6297  val_cmp = DB_UNK; /* mark as error */
6298  all_lefts = all_rghts = false;
6299 
6300  goto exit_on_end;
6301 }
6302 
6303 /*
6304  * qexec_merge_listfiles () -
6305  * return: NO_ERROR, or ER_code
6306  * xasl(in) : XASL Tree pointer
6307  * xasl_state(in) :
6308  *
6309  * Note: This function is used for a direct merge of two LIST files
6310  * during XASL tree interpretation.
6311  *
6312  * Note: For a direct list file merge, currently the outer and inner columns
6313  * should have the same data type.
6314  */
6315 static int
6317 {
6318  QFILE_LIST_ID *list_id = NULL;
6319  ACCESS_SPEC_TYPE *outer_spec = NULL; /* left */
6320  ACCESS_SPEC_TYPE *inner_spec = NULL; /* right */
6321  QFILE_LIST_MERGE_INFO *merge_infop = &(xasl->proc.mergelist.ls_merge);
6322  XASL_NODE *outer_xasl, *inner_xasl;
6323  int ls_flag = 0;
6324 
6325  outer_xasl = xasl->proc.mergelist.outer_xasl;
6326  inner_xasl = xasl->proc.mergelist.inner_xasl;
6327 
6328  /* open the empty list file if not already open */
6329 
6330  if (outer_xasl->list_id->type_list.type_cnt == 0)
6331  {
6332  /* start main block iterations */
6333  if (qexec_start_mainblock_iterations (thread_p, outer_xasl, xasl_state) != NO_ERROR)
6334  {
6336  }
6337  }
6338  if (inner_xasl->list_id->type_list.type_cnt == 0)
6339  {
6340  /* start main block iterations */
6341  if (qexec_start_mainblock_iterations (thread_p, inner_xasl, xasl_state) != NO_ERROR)
6342  {
6344  }
6345  }
6346 
6347  /* If MERGELIST_PROC does not have 'order by' (xasl->orderby_list), then the list file to be open at here will be the
6348  * last one. Otherwise, the last list file will be open at qexec_orderby_distinct(). (Note that only one that can
6349  * have 'group by' is BUILDLIST_PROC type.) And, the top most XASL is the other condition for the list file to be the
6350  * last result file. */
6351 
6352  QFILE_SET_FLAG (ls_flag, QFILE_FLAG_ALL);
6354  && (xasl->orderby_list == NULL || XASL_IS_FLAGED (xasl, XASL_SKIP_ORDERBY_LIST)) && xasl->option != Q_DISTINCT)
6355  {
6357  }
6358 
6359  if (merge_infop->join_type == JOIN_INNER)
6360  {
6361  /* call list file merge routine */
6362  list_id = qexec_merge_list (thread_p, outer_xasl->list_id, inner_xasl->list_id, merge_infop, ls_flag);
6363  }
6364  else
6365  {
6366  outer_spec = xasl->proc.mergelist.outer_spec_list;
6367  inner_spec = xasl->proc.mergelist.inner_spec_list;
6368 
6369  assert (xasl->scan_op_type == S_SELECT);
6370  if (qexec_open_scan (thread_p, outer_spec, xasl->proc.mergelist.outer_val_list, &xasl_state->vd, false,
6371  outer_spec->fixed_scan, outer_spec->grouped_scan, true, &outer_spec->s_id,
6372  xasl_state->query_id, S_SELECT, false, NULL) != NO_ERROR)
6373  {
6375  }
6376 
6377  if (qexec_open_scan (thread_p, inner_spec, xasl->proc.mergelist.inner_val_list, &xasl_state->vd, false,
6378  inner_spec->fixed_scan, inner_spec->grouped_scan, true, &inner_spec->s_id,
6379  xasl_state->query_id, S_SELECT, false, NULL) != NO_ERROR)
6380  {
6382  }
6383 
6384  /* call outer join merge routine */
6385  list_id =
6386  qexec_merge_list_outer (thread_p, &outer_spec->s_id, &inner_spec->s_id, merge_infop, xasl->after_join_pred,
6387  xasl_state, ls_flag);
6388 
6389  qexec_close_scan (thread_p, outer_spec);
6390  outer_spec = NULL;
6391 
6392  qexec_close_scan (thread_p, inner_spec);
6393  inner_spec = NULL;
6394  }
6395 
6396  if (list_id == NULL)
6397  {
6399  }
6400 
6401  /* make this the resultant list file */
6402  qfile_copy_list_id (xasl->list_id, list_id, true);
6403  QFILE_FREE_AND_INIT_LIST_ID (list_id);
6404 
6405  return NO_ERROR;
6406 
6407 exit_on_error:
6408 
6409  if (outer_spec)
6410  {
6411  qexec_close_scan (thread_p, outer_spec);
6412  }
6413  if (inner_spec)
6414  {
6415  qexec_close_scan (thread_p, inner_spec);
6416  }
6417 
6418  return ER_FAILED;
6419 }
6420 
6421 /*
6422  * Interpreter routines
6423  */
6424 
6425 /*
6426  * qexec_open_scan () -
6427  * return: NO_ERROR, or ER_code
6428  * curr_spec(in) : Access Specification Node
6429  * val_list(in) : Value list pointer
6430  * vd(in) : Value descriptor
6431  * force_select_lock(in) :
6432  * fixed(in) : Fixed scan flag
6433  * grouped(in) : Grouped scan flag
6434  * iscan_oid_order(in) :
6435  * s_id(out) : Set to the scan identifier
6436  * p_mvcc_select_lock_needed(out): true, whether instance lock needed at select
6437  *
6438  * Note: This routine is used to open a scan on an access specification
6439  * node. A scan identifier is created with the given parameters.
6440  */
6441 static int
6442 qexec_open_scan (THREAD_ENTRY * thread_p, ACCESS_SPEC_TYPE * curr_spec, VAL_LIST * val_list, VAL_DESCR * vd,
6443  bool force_select_lock, int fixed, int grouped, bool iscan_oid_order, SCAN_ID * s_id,
6444  QUERY_ID query_id, SCAN_OPERATION_TYPE scan_op_type, bool scan_immediately_stop,
6445  bool * p_mvcc_select_lock_needed)
6446 {
6447  SCAN_TYPE scan_type;
6449  QFILE_LIST_ID *list_id;
6450  bool mvcc_select_lock_needed = false;
6451  int error_code = NO_ERROR;
6452 
6453  if (curr_spec->pruning_type == DB_PARTITIONED_CLASS && !curr_spec->pruned)
6454  {
6455  error_code = qexec_prune_spec (thread_p, curr_spec, vd, scan_op_type);
6456  if (error_code != NO_ERROR)
6457  {
6458  ASSERT_ERROR ();
6459  goto exit_on_error;
6460  }
6461  }
6462 
6463  if (curr_spec->type == TARGET_CLASS && mvcc_is_mvcc_disabled_class (&ACCESS_SPEC_CLS_OID (curr_spec)))
6464  {
6465  assert (!force_select_lock);
6466 
6467  /* We expect to update or delete a non MVCC objects via a scan are only db_serial, db_ha_apply_info and
6468  * _db_collation objects. */
6469  assert ((scan_op_type != S_DELETE && scan_op_type != S_UPDATE) || oid_is_serial (&ACCESS_SPEC_CLS_OID (curr_spec))
6472  }
6473  else
6474  {
6475  if (force_select_lock)
6476  {
6477  mvcc_select_lock_needed = true;
6478  }
6479  else
6480  {
6481  mvcc_select_lock_needed = (curr_spec->flags & ACCESS_SPEC_FLAG_FOR_UPDATE);
6482  }
6483  }
6484 
6485  switch (curr_spec->type)
6486  {
6487  case TARGET_CLASS:
6488  if (curr_spec->access == ACCESS_METHOD_SEQUENTIAL)
6489  {
6490  /* open a sequential heap file scan */
6491  scan_type = S_HEAP_SCAN;
6492  indx_info = NULL;
6493  }
6494  else if (curr_spec->access == ACCESS_METHOD_SEQUENTIAL_RECORD_INFO)
6495  {
6496  /* open a sequential heap file scan that reads record info */
6497  scan_type = S_HEAP_SCAN_RECORD_INFO;
6498  indx_info = NULL;
6499  }
6500  else if (curr_spec->access == ACCESS_METHOD_SEQUENTIAL_PAGE_SCAN)
6501  {
6502  /* open a sequential heap file scan that reads page info */
6503  scan_type = S_HEAP_PAGE_SCAN;
6504  indx_info = NULL;
6505  }
6506  else if (curr_spec->access == ACCESS_METHOD_INDEX)
6507  {
6508  /* open an indexed heap file scan */
6509  scan_type = S_INDX_SCAN;
6510  indx_info = curr_spec->indexptr;
6511  }
6512  else if (curr_spec->access == ACCESS_METHOD_INDEX_KEY_INFO)
6513  {
6514  scan_type = S_INDX_KEY_INFO_SCAN;
6515  indx_info = curr_spec->indexptr;
6516  }
6517  else if (curr_spec->access == ACCESS_METHOD_INDEX_NODE_INFO)
6518  {
6519  scan_type = S_INDX_NODE_INFO_SCAN;
6520  indx_info = curr_spec->indexptr;
6521  }
6522  else
6523  {
6526  } /* if */
6527 
6528  if (scan_type == S_HEAP_SCAN || scan_type == S_HEAP_SCAN_RECORD_INFO)
6529  {
6530  error_code = scan_open_heap_scan (thread_p, s_id, mvcc_select_lock_needed, scan_op_type, fixed, grouped,
6531  curr_spec->single_fetch, curr_spec->s_dbval, val_list, vd,
6532  &ACCESS_SPEC_CLS_OID (curr_spec), &ACCESS_SPEC_HFID (curr_spec),
6533  curr_spec->s.cls_node.cls_regu_list_pred, curr_spec->where_pred,
6534  curr_spec->s.cls_node.cls_regu_list_rest,
6535  curr_spec->s.cls_node.num_attrs_pred,
6536  curr_spec->s.cls_node.attrids_pred, curr_spec->s.cls_node.cache_pred,
6537  curr_spec->s.cls_node.num_attrs_rest, curr_spec->s.cls_node.attrids_rest,
6538  curr_spec->s.cls_node.cache_rest, scan_type,
6539  curr_spec->s.cls_node.cache_reserved,
6540  curr_spec->s.cls_node.cls_regu_list_reserved);
6541  if (error_code != NO_ERROR)
6542  {
6543  ASSERT_ERROR ();
6544  goto exit_on_error;
6545  }
6546  }
6547  else if (scan_type == S_HEAP_PAGE_SCAN)
6548  {
6549  error_code = scan_open_heap_page_scan (thread_p, s_id, val_list, vd, &ACCESS_SPEC_CLS_OID (curr_spec),
6550  &ACCESS_SPEC_HFID (curr_spec), curr_spec->where_pred, scan_type,
6551  curr_spec->s.cls_node.cache_reserved,
6552  curr_spec->s.cls_node.cls_regu_list_reserved);
6553  if (error_code != NO_ERROR)
6554  {
6555  ASSERT_ERROR ();
6556  goto exit_on_error;
6557  }
6558  }
6559  else if (scan_type == S_INDX_KEY_INFO_SCAN)
6560  {
6561  error_code =
6562  scan_open_index_key_info_scan (thread_p, s_id, val_list, vd, indx_info, &ACCESS_SPEC_CLS_OID (curr_spec),
6563  &ACCESS_SPEC_HFID (curr_spec), curr_spec->where_pred,
6564  curr_spec->s.cls_node.cls_output_val_list, iscan_oid_order, query_id,
6565  curr_spec->s.cls_node.cache_reserved,
6566  curr_spec->s.cls_node.cls_regu_list_reserved);
6567  if (error_code != NO_ERROR)
6568  {
6569  ASSERT_ERROR ();
6570  goto exit_on_error;
6571  }
6572  /* monitor */
6574  }
6575  else if (scan_type == S_INDX_NODE_INFO_SCAN)
6576  {
6577  error_code = scan_open_index_node_info_scan (thread_p, s_id, val_list, vd, indx_info, curr_spec->where_pred,
6578  curr_spec->s.cls_node.cache_reserved,
6579  curr_spec->s.cls_node.cls_regu_list_reserved);
6580  if (error_code != NO_ERROR)
6581  {
6582  ASSERT_ERROR ();
6583  goto exit_on_error;
6584  }
6585  /* monitor */
6587  }
6588  else /* S_INDX_SCAN */
6589  {
6590  error_code = scan_open_index_scan (thread_p, s_id, mvcc_select_lock_needed, scan_op_type, fixed, grouped,
6591  curr_spec->single_fetch, curr_spec->s_dbval, val_list, vd, indx_info,
6592  &ACCESS_SPEC_CLS_OID (curr_spec), &ACCESS_SPEC_HFID (curr_spec),
6593  curr_spec->s.cls_node.cls_regu_list_key, curr_spec->where_key,
6594  curr_spec->s.cls_node.cls_regu_list_pred, curr_spec->where_pred,
6595  curr_spec->s.cls_node.cls_regu_list_rest, curr_spec->where_range,
6596  curr_spec->s.cls_node.cls_regu_list_range,
6597  curr_spec->s.cls_node.cls_output_val_list,
6598  curr_spec->s.cls_node.cls_regu_val_list,
6599  curr_spec->s.cls_node.num_attrs_key, curr_spec->s.cls_node.attrids_key,
6600  curr_spec->s.cls_node.cache_key, curr_spec->s.cls_node.num_attrs_pred,
6601  curr_spec->s.cls_node.attrids_pred, curr_spec->s.cls_node.cache_pred,
6602  curr_spec->s.cls_node.num_attrs_rest, curr_spec->s.cls_node.attrids_rest,
6603  curr_spec->s.cls_node.cache_rest, curr_spec->s.cls_node.num_attrs_range,
6604  curr_spec->s.cls_node.attrids_range, curr_spec->s.cls_node.cache_range,
6605  iscan_oid_order, query_id);
6606  if (error_code != NO_ERROR)
6607  {
6608  ASSERT_ERROR ();
6609  goto exit_on_error;
6610  }
6611  /* monitor */
6613  }
6614  break;
6615 
6616  case TARGET_CLASS_ATTR:
6617  error_code =
6618  scan_open_class_attr_scan (thread_p, s_id, grouped, curr_spec->single_fetch, curr_spec->s_dbval, val_list, vd,
6619  &ACCESS_SPEC_CLS_OID (curr_spec), &ACCESS_SPEC_HFID (curr_spec),
6620  curr_spec->s.cls_node.cls_regu_list_pred, curr_spec->where_pred,
6621  curr_spec->s.cls_node.cls_regu_list_rest, curr_spec->s.cls_node.num_attrs_pred,
6622  curr_spec->s.cls_node.attrids_pred, curr_spec->s.cls_node.cache_pred,
6623  curr_spec->s.cls_node.num_attrs_rest, curr_spec->s.cls_node.attrids_rest,
6624  curr_spec->s.cls_node.cache_rest);
6625  if (error_code != NO_ERROR)
6626  {
6627  ASSERT_ERROR ();
6628  goto exit_on_error;
6629  }
6630  break;
6631 
6632  case TARGET_LIST:
6633  /* open a list file scan */
6634  if (ACCESS_SPEC_XASL_NODE (curr_spec) && ACCESS_SPEC_XASL_NODE (curr_spec)->spec_list == curr_spec)
6635  {
6636  /* if XASL of access spec for list scan is itself then this is for HQ */
6637  list_id = ACCESS_SPEC_CONNECT_BY_LIST_ID (curr_spec);
6638  }
6639  else
6640  {
6641  list_id = ACCESS_SPEC_LIST_ID (curr_spec);
6642  }
6643  error_code =
6644  scan_open_list_scan (thread_p, s_id, grouped, curr_spec->single_fetch, curr_spec->s_dbval, val_list, vd,
6645  list_id, curr_spec->s.list_node.list_regu_list_pred,
6646  curr_spec->where_pred, curr_spec->s.list_node.list_regu_list_rest,
6648  curr_spec->s.list_node.hash_list_scan_yn);
6649  if (error_code != NO_ERROR)
6650  {
6651  ASSERT_ERROR ();
6652  goto exit_on_error;
6653  }
6654  break;
6655 
6656  case TARGET_SHOWSTMT:
6657  /* open a showstmt scan */
6658  error_code =
6659  scan_open_showstmt_scan (thread_p, s_id, grouped, curr_spec->single_fetch, curr_spec->s_dbval, val_list, vd,
6660  curr_spec->where_pred, curr_spec->s.showstmt_node.show_type,
6661  curr_spec->s.showstmt_node.arg_list);
6662  if (error_code != NO_ERROR)
6663  {
6664  ASSERT_ERROR ();
6665  goto exit_on_error;
6666  }
6667  break;
6668 
6669  case TARGET_REGUVAL_LIST:
6670  /* open a regu value list scan */
6671  error_code =
6672  scan_open_values_scan (thread_p, s_id, grouped, curr_spec->single_fetch, curr_spec->s_dbval, val_list, vd,
6673  ACCESS_SPEC_RLIST_VALPTR_LIST (curr_spec));
6674  if (error_code != NO_ERROR)
6675  {
6676  ASSERT_ERROR ();
6677  goto exit_on_error;
6678  }
6679  break;
6680 
6681  case TARGET_SET:
6682  /* open a set based derived table scan */
6683  error_code =
6684  scan_open_set_scan (thread_p, s_id, grouped, curr_spec->single_fetch, curr_spec->s_dbval, val_list, vd,
6685  ACCESS_SPEC_SET_PTR (curr_spec), ACCESS_SPEC_SET_REGU_LIST (curr_spec),
6686  curr_spec->where_pred);
6687  if (error_code != NO_ERROR)
6688  {
6689  ASSERT_ERROR ();
6690  goto exit_on_error;
6691  }
6692  break;
6693 
6694  case TARGET_JSON_TABLE:
6695  /* open a json table based derived table scan */
6696  error_code =
6697  scan_open_json_table_scan (thread_p, s_id, grouped, curr_spec->single_fetch, curr_spec->s_dbval, val_list,
6698  vd, curr_spec->where_pred);
6699  if (error_code != NO_ERROR)
6700  {
6701  ASSERT_ERROR ();
6702  goto exit_on_error;
6703  }
6704  break;
6705 
6706  case TARGET_METHOD:
6707  error_code =
6708  scan_open_method_scan (thread_p, s_id, grouped, curr_spec->single_fetch, curr_spec->s_dbval, val_list, vd,
6709  ACCESS_SPEC_METHOD_LIST_ID (curr_spec), ACCESS_SPEC_METHOD_SIG_LIST (curr_spec));
6710  if (error_code != NO_ERROR)
6711  {
6712  ASSERT_ERROR ();
6713  goto exit_on_error;
6714  }
6715  break;
6716 
6717  default:
6719  error_code = ER_QPROC_INVALID_XASLNODE;
6720  goto exit_on_error;
6721  } /* switch */
6722 
6723  s_id->scan_immediately_stop = scan_immediately_stop;
6724 
6725  if (p_mvcc_select_lock_needed)
6726  {
6727  *p_mvcc_select_lock_needed = mvcc_select_lock_needed;
6728  }
6729 
6730  return NO_ERROR;
6731 
6732 exit_on_error:
6733 
6734  if (curr_spec->pruning_type == DB_PARTITIONED_CLASS && curr_spec->parts != NULL)
6735  {
6736  /* reset pruning info */
6737  db_private_free (thread_p, curr_spec->parts);
6738  curr_spec->parts = NULL;
6739  curr_spec->curent = NULL;
6740  curr_spec->pruned = false;
6741  }
6742 
6743  ASSERT_ERROR_AND_SET (error_code);
6744  return error_code;
6745 }
6746 
6747 /*
6748  * qexec_close_scan () -
6749  * return:
6750  * curr_spec(in) : Access Specification Node
6751  *
6752  * Note: This routine is used to close the access specification node scan.
6753  */
6754 static void
6756 {
6757  if (curr_spec == NULL)
6758  {
6759  return;
6760  }
6761 
6762  /* monitoring */
6763  switch (curr_spec->type)
6764  {
6765  case TARGET_CLASS:
6767  || curr_spec->access == ACCESS_METHOD_SEQUENTIAL_PAGE_SCAN)
6768  {
6770  }
6771  else if (IS_ANY_INDEX_ACCESS (curr_spec->access))
6772  {
6774  }
6775 
6776  if (curr_spec->parts != NULL)
6777  {
6778  /* reset pruning info */
6779  db_private_free (thread_p, curr_spec->parts);
6780  curr_spec->parts = NULL;
6781  curr_spec->curent = NULL;
6782  curr_spec->pruned = false;
6783  }
6784  break;
6785 
6786  case TARGET_CLASS_ATTR:
6787  break;
6788 
6789  case TARGET_LIST:
6791  break;
6792 
6793  case TARGET_SHOWSTMT:
6794  /* do nothing */
6795  break;
6796 
6797  case TARGET_REGUVAL_LIST:
6798  /* currently do nothing */
6799  break;
6800 
6801  case TARGET_SET:
6803  break;
6804 
6805  case TARGET_JSON_TABLE:
6806  /* currently do nothing
6807  todo: check if here need to add something
6808  */
6809  break;
6810 
6811  case TARGET_METHOD:
6813  break;
6814  }
6815 
6816  scan_close_scan (thread_p, &curr_spec->s_id);
6817 }
6818 
6819 /*
6820  * qexec_end_scan () -
6821  * return:
6822  * curr_spec(in) : Access Specification Node
6823  *
6824  * Note: This routine is used to end the access specification node scan.
6825  *
6826  * Note: This routine is called for ERROR CASE scan end operation.
6827  */
6828 static void
6830 {
6831  if (curr_spec)
6832  {
6833  scan_end_scan (thread_p, &curr_spec->s_id);
6834  }
6835 }
6836 
6837 /*
6838  * qexec_next_merge_block () -
6839  * return:
6840  * spec(in) :
6841  */
6842 static SCAN_CODE
6844 {
6845  SCAN_CODE sb_scan;
6846 
6847  if (scan_start_scan (thread_p, &(*spec)->s_id) != NO_ERROR)
6848  {
6849  return S_ERROR;
6850  }
6851 
6852  do
6853  {
6854  sb_scan = scan_next_scan_block (thread_p, &(*spec)->s_id);
6855  if (sb_scan == S_SUCCESS)
6856  {
6857  return S_SUCCESS;
6858  }
6859  else if (sb_scan == S_END)
6860  {
6861  /* close old scan */
6862  scan_end_scan (thread_p, &(*spec)->s_id);
6863 
6864  /* move to the following access specifications left */
6865  *spec = (*spec)->next;
6866 
6867  /* check for and skip the case of empty heap files */
6868  while (*spec != NULL && QEXEC_EMPTY_ACCESS_SPEC_SCAN (*spec))
6869  {
6870  *spec = (*spec)->next;
6871  }
6872 
6873  if (*spec == NULL)
6874  {
6875  return S_END;
6876  }
6877 
6878  /* initialize scan */
6879  if (scan_start_scan (thread_p, &(*spec)->s_id) != NO_ERROR)
6880  {
6881  return S_ERROR;
6882  }
6883  }
6884  else
6885  {
6886  return S_ERROR;
6887  }
6888 
6889  }
6890  while (1);
6891 }
6892 
6893 /*
6894  * qexec_next_scan_block () -
6895  * return: SCAN_CODE (S_SUCCESS, S_END, S_ERROR)
6896  * xasl(in) : XASL Tree pointer
6897  *
6898  * Note: This function is used to move the current access specification
6899  * node scan identifier for the given XASL block to the next
6900  * scan block. If there are no more scan blocks for the current
6901  * access specfication node, it moves to the next access
6902  * specification, if any, and starts the new scan block for that
6903  * node. If there are no more access specification nodes left,
6904  * it returns S_END.
6905  */
6906 static SCAN_CODE
6908 {
6909  SCAN_CODE sb_scan;
6910  OID *class_oid;
6911  HFID *class_hfid;
6912 
6913  if (xasl->curr_spec == NULL)
6914  {
6915  /* initialize scan id */
6916  xasl->curr_spec = xasl->spec_list;
6917 
6918  /* check for and skip the case of empty heap file cases */
6919  while (xasl->curr_spec != NULL && QEXEC_EMPTY_ACCESS_SPEC_SCAN (xasl->curr_spec))
6920  {
6921  xasl->curr_spec = xasl->curr_spec->next;
6922  }
6923 
6924  if (xasl->curr_spec == NULL)
6925  {
6926  return S_END;
6927  }
6928 
6929  assert (xasl->curr_spec != NULL);
6930 
6931  /* initialize scan */
6932  if ((xasl->curr_spec->type == TARGET_CLASS || xasl->curr_spec->type == TARGET_CLASS_ATTR)
6933  && xasl->curr_spec->parts != NULL && xasl->curr_spec->curent == NULL
6935  {
6936  /* initialize the scan_id for partitioned classes */
6939  {
6940  class_oid = &xasl->curr_spec->s_id.s.hsid.cls_oid;
6941  class_hfid = &xasl->curr_spec->s_id.s.hsid.hfid;
6942  }
6944  {
6945  class_oid = &xasl->curr_spec->s_id.s.hpsid.cls_oid;
6946  class_hfid = &xasl->curr_spec->s_id.s.hpsid.hfid;
6947  }
6948  else if (xasl->curr_spec->access == ACCESS_METHOD_INDEX
6950  {
6951  class_oid = &xasl->curr_spec->s_id.s.isid.cls_oid;
6952  class_hfid = &xasl->curr_spec->s_id.s.isid.hfid;
6953  }
6954  else
6955  {
6956  assert (false);
6957  return S_ERROR;
6958  }
6959 
6960  COPY_OID (class_oid, &ACCESS_SPEC_CLS_OID (xasl->curr_spec));
6961  HFID_COPY (class_hfid, &ACCESS_SPEC_HFID (xasl->curr_spec));
6962  }
6963 
6964  if (scan_start_scan (thread_p, &xasl->curr_spec->s_id) != NO_ERROR)
6965  {
6966  return S_ERROR;
6967  }
6968  }
6969 
6970  do
6971  {
6972  sb_scan = scan_next_scan_block (thread_p, &xasl->curr_spec->s_id);
6973  if (sb_scan == S_SUCCESS)
6974  {
6975  return S_SUCCESS;
6976  }
6977  else if (sb_scan == S_END)
6978  {
6979  /* if curr_spec is a partitioned class, do not move to the next spec unless we went through all partitions */
6980  SCAN_CODE s_parts = qexec_init_next_partition (thread_p, xasl->curr_spec);
6981  if (s_parts == S_SUCCESS)
6982  {
6983  /* successfully moved to the next partition */
6984  continue;
6985  }
6986  else if (s_parts == S_ERROR)
6987  {
6988  return S_ERROR;
6989  }
6990 
6991  /* close old scan */
6992  scan_end_scan (thread_p, &xasl->curr_spec->s_id);
6993 
6994  /* move to the following access specifications left */
6995  xasl->curr_spec = xasl->curr_spec->next;
6996 
6997  /* check for and skip the case of empty heap files */
6998  while (xasl->curr_spec != NULL && QEXEC_EMPTY_ACCESS_SPEC_SCAN (xasl->curr_spec))
6999  {
7000  xasl->curr_spec = xasl->curr_spec->next;
7001  }
7002 
7003  if (xasl->curr_spec == NULL)
7004  {
7005  return S_END;
7006  }
7007 
7008  /* initialize scan */
7009  if (scan_start_scan (thread_p, &xasl->curr_spec->s_id) != NO_ERROR)
7010  {
7011  return S_ERROR;
7012  }
7013  }
7014  else
7015  {
7016  return S_ERROR;
7017  }
7018  }
7019  while (1);
7020 
7021 }
7022 
7023 /*
7024  * qexec_next_scan_block_iterations () -
7025  * return: SCAN_CODE (S_SUCCESS, S_END, S_ERROR)
7026  * xasl(in) : XASL Tree pointer
7027  *
7028  */
7029 static SCAN_CODE
7031 {
7032  SCAN_CODE sb_next;
7033  SCAN_CODE xs_scan;
7034  SCAN_CODE xs_scan2;
7035  XASL_NODE *last_xptr;
7036  XASL_NODE *prev_xptr;
7037  XASL_NODE *xptr2, *xptr3;
7038 
7039  /* first find the last scan block to be moved */
7040  for (last_xptr = xasl; last_xptr->scan_ptr; last_xptr = last_xptr->scan_ptr)
7041  {
7042  if (!last_xptr->next_scan_block_on
7043  || (last_xptr->curr_spec && last_xptr->curr_spec->s_id.status == S_STARTED
7044  && !last_xptr->curr_spec->s_id.qualified_block))
7045  {
7046  break;
7047  }
7048  }
7049 
7050  /* move the last scan block and reset further scans */
7051 
7052  /* if there are no qualified items in the current scan block, this scan block will make no contribution with other
7053  * possible scan block combinations from following classes. Thus, directly move to the next scan block in this class. */
7054  if (last_xptr->curr_spec && last_xptr->curr_spec->s_id.status == S_STARTED
7055  && !last_xptr->curr_spec->s_id.qualified_block)
7056  {
7057  if ((xs_scan = qexec_next_scan_block (thread_p, last_xptr)) == S_END)
7058  {
7059  /* close following scan procedures if they are still active */
7060  for (xptr2 = last_xptr; xptr2; xptr2 = xptr2->scan_ptr)
7061  {
7062  if (xptr2->scan_ptr && xptr2->next_scan_block_on)
7063  {
7064  if (xptr2->scan_ptr->curr_spec)
7065  {
7066  scan_end_scan (thread_p, &xptr2->scan_ptr->curr_spec->s_id);
7067  }
7068  xptr2->scan_ptr->curr_spec->curent = NULL;
7069  xptr2->scan_ptr->curr_spec = NULL;
7070  xptr2->next_scan_block_on = false;
7071  }
7072  }
7073  }
7074  else if (xs_scan == S_ERROR)
7075  {
7076  return S_ERROR;
7077  }
7078  }
7079  else if ((xs_scan = qexec_next_scan_block (thread_p, last_xptr)) == S_SUCCESS)
7080  { /* reset all the futher scans */
7081  for (xptr2 = last_xptr; xptr2; xptr2 = xptr2->scan_ptr)
7082  {
7083  if (xptr2->scan_ptr)
7084  {
7085  sb_next = qexec_next_scan_block (thread_p, xptr2->scan_ptr);
7086  if (sb_next == S_SUCCESS)
7087  {
7088  xptr2->next_scan_block_on = true;
7089  }
7090  else if (sb_next == S_END)
7091  {
7092  /* close all preceding scan procedures and return */
7093  for (xptr3 = xasl; xptr3 && xptr3 != xptr2->scan_ptr; xptr3 = xptr3->scan_ptr)
7094  {
7095  if (xptr3->curr_spec)
7096  {
7097  scan_end_scan (thread_p, &xptr3->curr_spec->s_id);
7098  }
7099  xptr3->curr_spec->curent = NULL;
7100  xptr3->curr_spec = NULL;
7101  xptr3->next_scan_block_on = false;
7102  }
7103  return S_END;
7104  }
7105  else
7106  {
7107  return S_ERROR;
7108  }
7109  }
7110  }
7111  }
7112  else if (xs_scan == S_ERROR)
7113  {
7114  return S_ERROR;
7115  }
7116 
7117  /* now move backwards, resetting all the previous scans */
7118  while (last_xptr != xasl)
7119  {
7120 
7121  /* find the previous to last xptr */
7122  for (prev_xptr = xasl; prev_xptr->scan_ptr != last_xptr; prev_xptr = prev_xptr->scan_ptr)
7123  ;
7124 
7125  /* set previous scan according to the last scan status */
7126  if (last_xptr->curr_spec == NULL)
7127  { /* last scan ended */
7128  prev_xptr->next_scan_block_on = false;
7129 
7130  /* move the scan block of the previous scan */
7131  xs_scan2 = qexec_next_scan_block (thread_p, prev_xptr);
7132  if (xs_scan2 == S_SUCCESS)
7133  {
7134  /* move all the further scan blocks */
7135  for (xptr2 = prev_xptr; xptr2; xptr2 = xptr2->scan_ptr)
7136  {
7137  if (xptr2->scan_ptr)
7138  {
7139  sb_next = qexec_next_scan_block (thread_p, xptr2->scan_ptr);
7140  if (sb_next == S_SUCCESS)
7141  {
7142  xptr2->next_scan_block_on = true;
7143  }
7144  else if (sb_next == S_END)
7145  {
7146  /* close all preceding scan procedures and return */
7147  for (xptr3 = xasl; xptr3 && xptr3 != xptr2->scan_ptr; xptr3 = xptr3->scan_ptr)
7148  {
7149  if (xptr3->curr_spec)
7150  {
7151  scan_end_scan (thread_p, &xptr3->curr_spec->s_id);
7152  }
7153  xptr3->curr_spec->curent = NULL;
7154  xptr3->curr_spec = NULL;
7155  xptr3->next_scan_block_on = false;
7156  }
7157  return S_END;
7158  }
7159  else
7160  {
7161  return S_ERROR;
7162  }
7163  }
7164  }
7165  }
7166  else if (xs_scan2 == S_ERROR)
7167  {
7168  return S_ERROR;
7169  }
7170 
7171  }
7172  else /* last scan successfully moved */
7173  {
7174  if (scan_reset_scan_block (thread_p, &prev_xptr->curr_spec->s_id) == S_ERROR)
7175  {
7176  return S_ERROR;
7177  }
7178  }
7179 
7180  /* make previous scan the last scan ptr */
7181  last_xptr = prev_xptr;
7182  } /* while */
7183 
7184  /* return the status of the first XASL block */
7185  return (xasl->curr_spec) ? S_SUCCESS : S_END;
7186 }
7187 
7188 /*
7189  * qexec_execute_scan () -
7190  * return: SCAN_CODE (S_SUCCESS, S_END, S_ERROR)
7191  * xasl(in) : XASL Tree block
7192  * xasl_state(in) : XASL tree state information
7193  * next_scan_fnc(in) : Function to interpret following scan block
7194  *
7195  * Note: This routine executes one iteration on a scan operation on
7196  * the given XASL tree block. If end_of_scan is reached, it
7197  * return S_END. If an error occurs, it returns
7198  * S_ERROR. Each scan procedure block may have its own scan
7199  * procedures forming a path of scan procedure blocks. Thus, for
7200  * each scan procedure block interpretation, if there are already
7201  * active scan procedures started from that block, first their
7202  * execution is requested. Only if all of the following scan
7203  * procedures come to an end returning S_END, then the
7204  * current scan procedure scan item is advanced. When this scan
7205  * procedure too come to an end, it returns S_END to the
7206  * caller, indicating that there are no more scan items in the
7207  * path of the scan procedure blocks.
7208  *
7209  * Note: This function is the general scan block interpretation function.
7210  */
7211 static SCAN_CODE
7213  XASL_SCAN_FNC_PTR next_scan_fnc)
7214 {
7215  XASL_NODE *xptr;
7216  SCAN_CODE sc_scan;
7217  SCAN_CODE xs_scan;
7218  DB_LOGICAL ev_res;
7219  int qualified;
7220  SCAN_OPERATION_TYPE scan_operation_type;
7221 
7222  /* check if further scan procedure are still active */
7223  if (xasl->scan_ptr && xasl->next_scan_on)
7224  {
7225  xs_scan = (*next_scan_fnc) (thread_p, xasl->scan_ptr, xasl_state, ignore, next_scan_fnc + 1);
7226  if (xs_scan != S_END)
7227  {
7228  return xs_scan;
7229  }
7230 
7231  xasl->next_scan_on = false;
7232  }
7233 
7234  do
7235  {
7236  sc_scan = scan_next_scan (thread_p, &xasl->curr_spec->s_id);
7237  if (sc_scan != S_SUCCESS)
7238  {
7239  return sc_scan;
7240  }
7241 
7242  /* set scan item as qualified */
7243  qualified = true;
7244 
7245  if (qualified)
7246  {
7247  /* clear bptr subquery list files */
7248  if (xasl->bptr_list)
7249  {
7250  qexec_clear_head_lists (thread_p, xasl->bptr_list);
7252  {
7253  scan_operation_type = S_UPDATE;
7254  }
7255  else
7256  {
7257  scan_operation_type = S_SELECT;
7258  }
7259  }
7260  /* evaluate bptr list */
7261  for (xptr = xasl->bptr_list; qualified && xptr != NULL; xptr = xptr->next)
7262  {
7263  if (qexec_execute_obj_fetch (thread_p, xptr, xasl_state, scan_operation_type) != NO_ERROR)
7264  {
7265  return S_ERROR;
7266  }
7267  else if (xptr->proc.fetch.fetch_res == false)
7268  {
7269  qualified = false;
7270  }
7271  }
7272  } /* if (qualified) */
7273 
7274  if (qualified)
7275  {
7276  /* evaluate dptr list */
7277  for (xptr = xasl->dptr_list; xptr != NULL; xptr = xptr->next)
7278  {
7279  /* clear correlated subquery list files */
7280  qexec_clear_head_lists (thread_p, xptr);
7282  {
7283  /* skip if linked to regu var */
7284  continue;
7285  }
7286  if (qexec_execute_mainblock (thread_p, xptr, xasl_state, NULL) != NO_ERROR)
7287  {
7288  return S_ERROR;
7289  }
7290  }
7291  } /* if (qualified) */
7292 
7293  if (qualified)
7294  {
7295  /* evaluate after join predicate */
7296  ev_res = V_UNKNOWN;
7297  if (xasl->after_join_pred != NULL)
7298  {
7299  ev_res = eval_pred (thread_p, xasl->after_join_pred, &xasl_state->vd, NULL);
7300  if (ev_res == V_ERROR)
7301  {
7302  return S_ERROR;
7303  }
7304  }
7305  qualified = (xasl->after_join_pred == NULL || ev_res == V_TRUE);
7306  } /* if (qualified) */
7307 
7308  if (qualified)
7309  {
7310  /* evaluate if predicate */
7311  ev_res = V_UNKNOWN;
7312  if (xasl->if_pred != NULL)
7313  {
7314  ev_res = eval_pred (thread_p, xasl->if_pred, &xasl_state->vd, NULL);
7315  if (ev_res == V_ERROR)
7316  {
7317  return S_ERROR;
7318  }
7319  }
7320  qualified = (xasl->if_pred == NULL || ev_res == V_TRUE);
7321  } /* if (qualified) */
7322 
7323  if (qualified)
7324  {
7325  /* clear fptr subquery list files */
7326  if (xasl->fptr_list)
7327  {
7328  qexec_clear_head_lists (thread_p, xasl->fptr_list);
7330  {
7331  scan_operation_type = S_UPDATE;
7332  }
7333  else
7334  {
7335  scan_operation_type = S_SELECT;
7336  }
7337  }
7338  /* evaluate fptr list */
7339  for (xptr = xasl->fptr_list; qualified && xptr != NULL; xptr = xptr->next)
7340  {
7341  if (qexec_execute_obj_fetch (thread_p, xptr, xasl_state, scan_operation_type) != NO_ERROR)
7342  {
7343  return S_ERROR;
7344  }
7345  else if (xptr->proc.fetch.fetch_res == false)
7346  {
7347  qualified = false;
7348  }
7349  }
7350  } /* if (qualified) */
7351 
7352  if (qualified)
7353  {
7354  if (!xasl->scan_ptr)
7355  {
7356  /* no scan procedure block */
7357  return S_SUCCESS;
7358  }
7359  else
7360  {
7361  /* current scan block has at least one qualified item */
7362  xasl->curr_spec->s_id.qualified_block = true;
7363 
7364  /* start following scan procedure */
7365  xasl->scan_ptr->next_scan_on = false;
7366  if (scan_reset_scan_block (thread_p, &xasl->scan_ptr->curr_spec->s_id) == S_ERROR)
7367  {
7368  return S_ERROR;
7369  }
7370 
7371  xasl->next_scan_on = true;
7372 
7373  /* execute following scan procedure */
7374  xs_scan = (*next_scan_fnc) (thread_p, xasl->scan_ptr, xasl_state, ignore, next_scan_fnc + 1);
7375  if (xs_scan == S_END)
7376  {
7377  xasl->next_scan_on = false;
7378  }
7379  else
7380  {
7381  return xs_scan;
7382  }
7383  }
7384  } /* if (qualified) */
7385 
7386  }
7387  while (1);
7388 
7389 }
7390 
7391 /*
7392  * qexec_reset_regu_variable_list () - reset value cache for a list of regu
7393  * variables
7394  * return : void
7395  * list (in) : regu variable list
7396  */
7397 static void
7399 {
7400  REGU_VARIABLE_LIST var = list;
7401 
7402  while (var != NULL)
7403  {
7405  var = var->next;
7406  }
7407 }
7408 
7409 /*
7410  * qexec_reset_pred_expr () - reset value cache for a pred expr
7411  * return : void
7412  * pred (in) : pred expr
7413  */
7414 static void
7416 {
7417  if (pred == NULL)
7418  {
7419  return;
7420  }
7421  switch (pred->type)
7422  {
7423  case T_PRED:
7426  break;
7427  case T_EVAL_TERM:
7428  switch (pred->pe.m_eval_term.et_type)
7429  {
7430  case T_COMP_EVAL_TERM:
7431  {
7432  COMP_EVAL_TERM *et_comp = &pred->pe.m_eval_term.et.et_comp;
7433 
7434  qexec_reset_regu_variable (et_comp->lhs);
7435  qexec_reset_regu_variable (et_comp->rhs);
7436  }
7437  break;
7438  case T_ALSM_EVAL_TERM:
7439  {
7440  ALSM_EVAL_TERM *et_alsm = &pred->pe.m_eval_term.et.et_alsm;
7441 
7442  qexec_reset_regu_variable (et_alsm->elem);
7444  }
7445  break;
7446  case T_LIKE_EVAL_TERM:
7447  {
7448  LIKE_EVAL_TERM *et_like = &pred->pe.m_eval_term.et.et_like;
7449 
7450  qexec_reset_regu_variable (et_like->src);
7453  }
7454  break;
7455  case T_RLIKE_EVAL_TERM:
7456  {
7457  RLIKE_EVAL_TERM *et_rlike = &pred->pe.m_eval_term.et.et_rlike;
7459  qexec_reset_regu_variable (et_rlike->pattern);
7460  qexec_reset_regu_variable (et_rlike->src);
7461  }
7462  }
7463  break;
7464  case T_NOT_TERM:
7466  break;
7467  }
7468 }
7469 
7470 /*
7471  * qexec_reset_regu_variable () - reset the cache for a regu variable
7472  * return : void
7473  * var (in) : regu variable
7474  */
7475 static void
7477 {
7478  if (var == NULL)
7479  {
7480  return;
7481  }
7482 
7483  switch (var->type)
7484  {
7485  case TYPE_ATTR_ID:
7486  case TYPE_SHARED_ATTR_ID:
7487  case TYPE_CLASS_ATTR_ID:
7488  var->value.attr_descr.cache_dbvalp = NULL;
7489  break;
7490  case TYPE_INARITH:
7491  case TYPE_OUTARITH:
7492  qexec_reset_regu_variable (var->value.arithptr->leftptr);
7493  qexec_reset_regu_variable (var->value.arithptr->rightptr);
7494  qexec_reset_regu_variable (var->value.arithptr->thirdptr);
7495  /* use arithptr */
7496  break;
7497  case TYPE_FUNC:
7498  /* use funcp */
7499  qexec_reset_regu_variable_list (var->value.funcp->operand);
7500  break;
7501  default:
7502  break;
7503  }
7504 }
7505 
7506 /*
7507  * qexec_prune_spec () - perform partition pruning on an access spec
7508  * return : error code or NO_ERROR
7509  * thread_p (in) :
7510  * spec (in) :
7511  * vd (in) :
7512  * scan_op_type (in) :
7513  */
7514 static int
7516 {
7517  PARTITION_SPEC_TYPE *partition_spec = NULL;
7518  LOCK lock = NULL_LOCK;
7519  int granted;
7520  int error = NO_ERROR;
7521 
7522  if (spec == NULL || spec->pruned)
7523  {
7524  return NO_ERROR;
7525  }
7526  else if (spec->pruning_type != DB_PARTITIONED_CLASS)
7527  {
7528  spec->pruned = true;
7529  return NO_ERROR;
7530  }
7531 
7532  error = partition_prune_spec (thread_p, vd, spec);
7533  if (error != NO_ERROR)
7534  {
7535  ASSERT_ERROR ();
7536  return error;
7537  }
7538 
7539  if (!COMPOSITE_LOCK (scan_op_type) && !(spec->flags & ACCESS_SPEC_FLAG_FOR_UPDATE))
7540  {
7541  lock = IS_LOCK;
7542  }
7543  else
7544  {
7545  /* MVCC use IX_LOCK on class at update/delete */
7546  lock = IX_LOCK;
7547  }
7548 
7549  for (partition_spec = spec->parts; partition_spec != NULL; partition_spec = partition_spec->next)
7550  {
7551  granted = lock_subclass (thread_p, &partition_spec->oid, &ACCESS_SPEC_CLS_OID (spec), lock, LK_UNCOND_LOCK);
7552  if (granted != LK_GRANTED)
7553  {
7554  ASSERT_ERROR_AND_SET (error);
7555  return error;
7556  }
7557  }
7558 
7559  return NO_ERROR;
7560 }
7561 
7562 /*
7563  * qexec_init_next_partition () - move to the next partition in the list
7564  * return : S_END if there are no more partitions, S_SUCCESS on success,
7565  * S_ERROR on error
7566  * thread_p (in) :
7567  * spec (in) : spec for which to move to the next partition
7568  */
7569 static SCAN_CODE
7571 {
7572  int error = NO_ERROR;
7573  SCAN_OPERATION_TYPE scan_op_type = spec->s_id.scan_op_type;
7574  bool mvcc_select_lock_needed = spec->s_id.mvcc_select_lock_needed;
7575  int fixed = spec->s_id.fixed;
7576  int grouped = spec->s_id.grouped;
7577  QPROC_SINGLE_FETCH single_fetch = spec->s_id.single_fetch;
7578  VAL_LIST *val_list = spec->s_id.val_list;
7579  VAL_DESCR *vd = spec->s_id.vd;
7580  bool iscan_oid_order = spec->s_id.s.isid.iscan_oid_order;
7581  INDX_INFO *idxptr = NULL;
7582  QUERY_ID query_id = spec->s_id.s.isid.indx_cov.query_id;
7583  OID class_oid;
7584  HFID class_hfid;
7585  BTID btid;
7586 
7587  if (spec->type != TARGET_CLASS && spec->type != TARGET_CLASS_ATTR)
7588  {
7589  return S_END;
7590  }
7591 
7592  if (spec->parts == NULL)
7593  {
7594  return S_END;
7595  }
7596 
7597  if (spec->curent == NULL)
7598  {
7599  spec->curent = spec->parts;
7600  }
7601  else
7602  {
7603  if (spec->curent->next == NULL)
7604  {
7605  /* no more partitions */
7606  spec->curent = NULL;
7607  }
7608  else
7609  {
7610  spec->curent = spec->curent->next;
7611  }
7612  }
7613  /* close current scan and open a new one on the next partition */
7614  scan_end_scan (thread_p, &spec->s_id);
7615  scan_close_scan (thread_p, &spec->s_id);
7616 
7617  /* we also need to reset caches for attributes */
7623 
7624  if (spec->curent == NULL)
7625  {
7626  /* reset back to root class */
7627  COPY_OID (&class_oid, &ACCESS_SPEC_CLS_OID (spec));
7628  HFID_COPY (&class_hfid, &ACCESS_SPEC_HFID (spec));
7629  if (IS_ANY_INDEX_ACCESS (spec->access))
7630  {
7631  btid = spec->btid;
7632  }
7633  }
7634  else
7635  {
7636  COPY_OID (&class_oid, &spec->curent->oid);
7637  HFID_COPY (&class_hfid, &spec->curent->hfid);
7638  if (IS_ANY_INDEX_ACCESS (spec->access))
7639  {
7640  btid = spec->curent->btid;
7641  }
7642  }
7643  if (spec->type == TARGET_CLASS
7645  {
7646  HEAP_SCAN_ID *hsidp = &spec->s_id.s.hsid;
7648  int i = 0;
7649  if (hsidp->caches_inited)
7650  {
7651  heap_attrinfo_end (thread_p, hsidp->pred_attrs.attr_cache);
7652  heap_attrinfo_end (thread_p, hsidp->rest_attrs.attr_cache);
7653  if (hsidp->cache_recordinfo != NULL)
7654  {
7655  for (i = 0; i < HEAP_RECORD_INFO_COUNT; i++)
7656  {
7657  pr_clear_value (hsidp->cache_recordinfo[i]);
7658  }
7659  }
7660  hsidp->caches_inited = false;
7661  }
7662  hsidp->scancache_inited = false;
7663 
7664  error =
7665  scan_open_heap_scan (thread_p, &spec->s_id, mvcc_select_lock_needed, scan_op_type, fixed, grouped, single_fetch,
7666  spec->s_dbval, val_list, vd, &class_oid, &class_hfid, spec->s.cls_node.cls_regu_list_pred,
7667  spec->where_pred, spec->s.cls_node.cls_regu_list_rest,
7670  spec->s.cls_node.attrids_rest, spec->s.cls_node.cache_rest,
7671  scan_type, spec->s.cls_node.cache_reserved, spec->s.cls_node.cls_regu_list_reserved);
7672  }
7673  else if (spec->type == TARGET_CLASS && spec->access == ACCESS_METHOD_SEQUENTIAL_PAGE_SCAN)
7674  {
7675  HEAP_PAGE_SCAN_ID *hpsidp = &spec->s_id.s.hpsid;
7676  SCAN_TYPE scan_type = S_HEAP_PAGE_SCAN;
7677  int i = 0;
7678 
7679  if (hpsidp->cache_page_info != NULL)
7680  {
7681  for (i = 0; i < HEAP_PAGE_INFO_COUNT; i++)
7682  {
7683  pr_clear_value (hpsidp->cache_page_info[i]);
7684  }
7685  }
7686  error =
7687  scan_open_heap_page_scan (thread_p, &spec->s_id, val_list, vd, &class_oid, &class_hfid, spec->where_pred,
7688  scan_type, spec->s.cls_node.cache_reserved, spec->s.cls_node.cls_regu_list_reserved);
7689  }
7690  else if (spec->type == TARGET_CLASS && spec->access == ACCESS_METHOD_INDEX)
7691  {
7692  INDX_SCAN_ID *isidp = &spec->s_id.s.isid;
7693  if (isidp->caches_inited)
7694  {
7695  if (isidp->range_pred.regu_list)
7696  {
7697  heap_attrinfo_end (thread_p, isidp->range_attrs.attr_cache);
7698 
7699  /* some attributes might remain also cached in pred_expr
7700  * (lhs|rhs).value.attr_descr.cache_dbvalp might point to attr_cache values
7701  * see fetch_peek_dbval for example */
7703  }
7704  if (isidp->key_pred.regu_list)
7705  {
7706  heap_attrinfo_end (thread_p, isidp->key_attrs.attr_cache);
7707  }
7708  heap_attrinfo_end (thread_p, isidp->pred_attrs.attr_cache);
7709  heap_attrinfo_end (thread_p, isidp->rest_attrs.attr_cache);
7710  isidp->caches_inited = false;
7711  }
7712  idxptr = spec->indexptr;
7713  idxptr->btid = btid;
7714  spec->s_id.s.isid.scancache_inited = false;
7715  spec->s_id.s.isid.caches_inited = false;
7716 
7717  error =
7718  scan_open_index_scan (thread_p, &spec->s_id, mvcc_select_lock_needed, scan_op_type, fixed, grouped,
7719  single_fetch, spec->s_dbval, val_list, vd, idxptr, &class_oid, &class_hfid,
7721  spec->where_pred, spec->s.cls_node.cls_regu_list_rest, spec->where_range,
7727  spec->s.cls_node.attrids_rest, spec->s.cls_node.cache_rest,
7729  spec->s.cls_node.cache_range, iscan_oid_order, query_id);
7730 
7731  }
7732  else if (spec->type == TARGET_CLASS_ATTR)
7733  {
7734  if (spec->s_id.s.hsid.caches_inited)
7735  {
7736  heap_attrinfo_end (thread_p, spec->s_id.s.hsid.pred_attrs.attr_cache);
7737  heap_attrinfo_end (thread_p, spec->s_id.s.hsid.rest_attrs.attr_cache);
7738  spec->s_id.s.hsid.caches_inited = false;
7739  }
7740 
7741  error =
7742  scan_open_class_attr_scan (thread_p, &spec->s_id, grouped, spec->single_fetch, spec->s_dbval, val_list, vd,
7743  &class_oid, &class_hfid, spec->s.cls_node.cls_regu_list_pred, spec->where_pred,
7745  spec->s.cls_node.attrids_pred, spec->s.cls_node.cache_pred,
7747  spec->s.cls_node.cache_rest);
7748  }
7749  if (error != NO_ERROR)
7750  {
7751  return S_ERROR;
7752  }
7753 
7754  if (spec->curent == NULL)
7755  {
7756  return S_END;
7757  }
7758 
7759  error = scan_start_scan (thread_p, &spec->s_id);
7760  if (error != NO_ERROR)
7761  {
7762  return S_ERROR;
7763  }
7764  return S_SUCCESS;
7765 }
7766 
7767 /*
7768  * qexec_intprt_fnc () -
7769  * return: scan code
7770  * xasl(in) : XASL Tree pointer
7771  * xasl_state(in) : XASL Tree state information
7772  * tplrec(out) : Tuple record descriptor to store result tuples
7773  * next_scan_fnc(in) : Function to interpret following XASL scan block
7774  *
7775  * Note: This function is the main function used to interpret an XASL
7776  * tree block. That is, it assumes a general format XASL block
7777  * with all possible representations.
7778  */
7779 static SCAN_CODE
7781  XASL_SCAN_FNC_PTR next_scan_fnc)
7782 {
7783 #define CTE_CURRENT_SCAN_READ_TUPLE(node) \
7784  ((((node)->curr_spec->type == TARGET_LIST && (node)->curr_spec->s_id.type == S_LIST_SCAN)) \
7785  ? ((node)->curr_spec->s_id.s.llsid.lsid.curr_tplno) : -1)
7786 #define CTE_CURR_ITERATION_LAST_TUPLE(node) \
7787  ((((node)->curr_spec->type == TARGET_LIST && (node)->curr_spec->s_id.type == S_LIST_SCAN)) \
7788  ? ((node)->curr_spec->s_id.s.llsid.list_id->tuple_cnt - 1) : -1)
7789 
7790  XASL_NODE *xptr = NULL;
7791  SCAN_CODE xs_scan;
7792  SCAN_CODE xb_scan;
7793  SCAN_CODE ls_scan;
7794  DB_LOGICAL ev_res;
7795  int qualified;
7796  AGGREGATE_TYPE *agg_ptr = NULL;
7797  bool count_star_with_iscan_opt = false;
7798  SCAN_OPERATION_TYPE scan_operation_type;
7799  int curr_iteration_last_cursor = 0;
7800  int recursive_iterations = 0;
7801  bool max_recursive_iterations_reached = false;
7802  bool cte_start_new_iteration = false;
7803 
7804  if (xasl->type == BUILDVALUE_PROC)
7805  {
7806  BUILDVALUE_PROC_NODE *buildvalue = &xasl->proc.buildvalue;
7807  if (buildvalue->agg_list != NULL)
7808  {
7809  int error = NO_ERROR;
7810  bool is_scan_needed = false;
7811  if (!buildvalue->is_always_false)
7812  {
7813  error =
7814  qexec_evaluate_aggregates_optimize (thread_p, buildvalue->agg_list, xasl->spec_list, &is_scan_needed);
7815  if (error != NO_ERROR)
7816  {
7817  is_scan_needed = true;
7818  }
7819  }
7820 
7822  {
7823  is_scan_needed = true;
7824  }
7825 
7826  if (!is_scan_needed)
7827  {
7828  return S_SUCCESS;
7829  }
7830 
7831  agg_ptr = buildvalue->agg_list;
7832  if (!xasl->scan_ptr /* no scan procedure */
7833  && !xasl->fptr_list /* no path expressions */
7834  && !xasl->if_pred /* no if predicates */
7835  && !xasl->instnum_pred /* no instnum predicate */
7836  && agg_ptr->next == NULL /* no other aggregate functions */
7837  && agg_ptr->function == PT_COUNT_STAR)
7838  {
7839  /* only one count(*) function */
7840  ACCESS_SPEC_TYPE *specp = xasl->spec_list;
7841  if (specp->next == NULL && specp->access == ACCESS_METHOD_INDEX
7842  && specp->s.cls_node.cls_regu_list_pred == NULL && specp->where_pred == NULL
7843  && !specp->indexptr->use_iss && !SCAN_IS_INDEX_MRO (&specp->s_id.s.isid)
7844  && !SCAN_IS_INDEX_COVERED (&specp->s_id.s.isid))
7845  {
7846  /* count(*) query will scan an index but does not have a data-filter */
7847  specp->s_id.s.isid.need_count_only = true;
7848  count_star_with_iscan_opt = true;
7849  }
7850  }
7851  }
7852  }
7853  else if (xasl->type == BUILDLIST_PROC)
7854  {
7855  /* If it is BUILDLIST, do not optimize aggregation */
7856  if (xasl->proc.buildlist.g_agg_list != NULL)
7857  {
7858  for (agg_ptr = xasl->proc.buildlist.g_agg_list; agg_ptr; agg_ptr = agg_ptr->next)
7859  {
7860  agg_ptr->flag_agg_optimize = false;
7861  }
7862  }
7863  }
7864 
7865  while ((xb_scan = qexec_next_scan_block_iterations (thread_p, xasl)) == S_SUCCESS)
7866  {
7867  int cte_offset_read_tuple = 0;
7868  int cte_curr_scan_tplno = -1;
7869 
7870  if (xasl->max_iterations != -1)
7871  {
7872  assert (xasl->curr_spec->type == TARGET_LIST);
7873  assert (xasl->curr_spec->s_id.type == S_LIST_SCAN);
7874 
7875  cte_start_new_iteration = true;
7876  recursive_iterations = 1;
7877  }
7878 
7879  while ((ls_scan = scan_next_scan (thread_p, &xasl->curr_spec->s_id)) == S_SUCCESS)
7880  {
7881  if (xasl->max_iterations != -1)
7882  {
7883  /* the scan tuple number resets when when a new page is fetched
7884  * cte_offset_read_tuple keeps of the global tuple number across the entire list */
7885  if (CTE_CURRENT_SCAN_READ_TUPLE (xasl) < cte_curr_scan_tplno)
7886  {
7887  cte_offset_read_tuple += cte_curr_scan_tplno + 1;
7888  }
7889 
7890  cte_curr_scan_tplno = CTE_CURRENT_SCAN_READ_TUPLE (xasl);
7891 
7892  if (cte_start_new_iteration)
7893  {
7894  recursive_iterations++;
7895  if (recursive_iterations >= xasl->max_iterations)
7896  {
7897  max_recursive_iterations_reached = true;
7898  break;
7899  }
7900 
7901  curr_iteration_last_cursor = CTE_CURR_ITERATION_LAST_TUPLE (xasl);
7902  assert (curr_iteration_last_cursor >= 0);
7903  cte_start_new_iteration = false;
7904  }
7905 
7906  if (cte_curr_scan_tplno + cte_offset_read_tuple == curr_iteration_last_cursor)
7907  {
7908  cte_start_new_iteration = true;
7909  }
7910  }
7911 
7912  if (count_star_with_iscan_opt)
7913  {
7914  xasl->proc.buildvalue.agg_list->accumulator.curr_cnt += (&xasl->curr_spec->s_id)->s.isid.oids_count;
7915  /* may have more scan ranges */
7916  continue;
7917  }
7918  /* set scan item as qualified */
7919  qualified = true;
7920 
7921  if (xasl->bptr_list)
7922  {
7924  {
7925  scan_operation_type = S_UPDATE;
7926  }
7927  else
7928  {
7929  scan_operation_type = S_SELECT;
7930  }
7931  }
7932 
7933  /* evaluate bptr list */
7934  /* if path expression fetch fails, this instance disqualifies */
7935  for (xptr = xasl->bptr_list; qualified && xptr != NULL; xptr = xptr->next)
7936  {
7937  if (qexec_execute_obj_fetch (thread_p, xptr, xasl_state, scan_operation_type) != NO_ERROR)
7938  {
7939  return S_ERROR;
7940  }
7941  else if (xptr->proc.fetch.fetch_res == false)
7942  {
7943  qualified = false;
7944  }
7945  }
7946 
7947  if (qualified)
7948  {
7949  /* evaluate dptr list */
7950  for (xptr = xasl->dptr_list; xptr != NULL; xptr = xptr->next)
7951  {
7952  /* clear correlated subquery list files */
7953  qexec_clear_head_lists (thread_p, xptr);
7955  {
7956  /* skip if linked to regu var */
7957  continue;
7958  }
7959  if (qexec_execute_mainblock (thread_p, xptr, xasl_state, NULL) != NO_ERROR)
7960  {
7961  return S_ERROR;
7962  }
7963  }
7964 
7965  /* evaluate after join predicate */
7966  ev_res = V_UNKNOWN;
7967  if (xasl->after_join_pred != NULL)
7968  {
7969  ev_res = eval_pred (thread_p, xasl->after_join_pred, &xasl_state->vd, NULL);
7970  if (ev_res == V_ERROR)
7971  {
7972  return S_ERROR;
7973  }
7974  }
7975  qualified = (xasl->after_join_pred == NULL || ev_res == V_TRUE);
7976 
7977  if (qualified)
7978  {
7979  /* evaluate if predicate */
7980  ev_res = V_UNKNOWN;
7981  if (xasl->if_pred != NULL)
7982  {
7983  ev_res = eval_pred (thread_p, xasl->if_pred, &xasl_state->vd, NULL);
7984  if (ev_res == V_ERROR)
7985  {
7986  return S_ERROR;
7987  }
7988  }
7989  qualified = (xasl->if_pred == NULL || ev_res == V_TRUE);
7990  }
7991 
7992  if (qualified)
7993  {
7994  /* evaluate fptr list */
7995  if (xasl->fptr_list)
7996  {
7998  {
7999  scan_operation_type = S_UPDATE;
8000  }
8001  else
8002  {
8003  scan_operation_type = S_SELECT;
8004  }
8005  }
8006 
8007  for (xptr = xasl->fptr_list; qualified && xptr != NULL; xptr = xptr->next)
8008  {
8009  if (qexec_execute_obj_fetch (thread_p, xptr, xasl_state, scan_operation_type) != NO_ERROR)
8010  {
8011  return S_ERROR;
8012  }
8013  else if (xptr->proc.fetch.fetch_res == false)
8014  {
8015  qualified = false;
8016  }
8017  }
8018 
8019  if (qualified)
8020  {
8021 
8022  if (!xasl->scan_ptr)
8023  { /* no scan procedure block */
8024 
8025  /* if hierarchical query do special processing */
8026  if (XASL_IS_FLAGED (xasl, XASL_HAS_CONNECT_BY))
8027  {
8028  if (qexec_update_connect_by_lists (thread_p, xasl->connect_by_ptr, xasl_state, tplrec) !=
8029  NO_ERROR)
8030  {
8031  return S_ERROR;
8032  }
8033  }
8034  else
8035  {
8036  /* evaluate inst_num predicate */
8037  if (xasl->instnum_val)
8038  {
8039  ev_res = qexec_eval_instnum_pred (thread_p, xasl, xasl_state);
8040  if (ev_res == V_ERROR)
8041  {
8042  return S_ERROR;
8043  }
8044 
8045 
8047  {
8048  if (qexec_end_one_iteration (thread_p, xasl, xasl_state, tplrec) != NO_ERROR)
8049  {
8050  return S_ERROR;
8051  }
8052 
8053  return S_SUCCESS;
8054  }
8055 
8057  {
8058  return S_SUCCESS;
8059  }
8060  }
8061 
8062  qualified = (xasl->instnum_pred == NULL || ev_res == V_TRUE);
8063  if (qualified)
8064  {
8065  /* one iteration successfully completed */
8066  if (qexec_end_one_iteration (thread_p, xasl, xasl_state, tplrec) != NO_ERROR)
8067  {
8068  return S_ERROR;
8069  }
8070  /* only one row is need for exists OP */
8072  {
8073  return S_SUCCESS;
8074  }
8075  }
8076  }
8077  }
8078  else
8079  { /* handle the scan procedure */
8080  /* current scan block has at least one qualified item */
8081  xasl->curr_spec->s_id.qualified_block = true;
8082 
8083  /* handle the scan procedure */
8084  xasl->scan_ptr->next_scan_on = false;
8085  if (scan_reset_scan_block (thread_p, &xasl->scan_ptr->curr_spec->s_id) == S_ERROR)
8086  {
8087  return S_ERROR;
8088  }
8089 
8090  xasl->next_scan_on = true;
8091 
8092 
8093  while ((xs_scan = (*next_scan_fnc) (thread_p, xasl->scan_ptr, xasl_state, tplrec,
8094  next_scan_fnc + 1)) == S_SUCCESS)
8095  {
8096 
8097  /* if hierarchical query do special processing */
8098  if (XASL_IS_FLAGED (xasl, XASL_HAS_CONNECT_BY))
8099  {
8100  if (qexec_update_connect_by_lists (thread_p, xasl->connect_by_ptr, xasl_state, tplrec)
8101  != NO_ERROR)
8102  {
8103  return S_ERROR;
8104  }
8105  }
8106  else
8107  {
8108  /* evaluate inst_num predicate */
8109  if (xasl->instnum_val)
8110  {
8111  ev_res = qexec_eval_instnum_pred (thread_p, xasl, xasl_state);
8112  if (ev_res == V_ERROR)
8113  {
8114  return S_ERROR;
8115  }
8116 
8118  {
8119  if (qexec_end_one_iteration (thread_p, xasl, xasl_state, tplrec) != NO_ERROR)
8120  {
8121  return S_ERROR;
8122  }
8123 
8124  return S_SUCCESS;
8125  }
8126 
8128  {
8129  return S_SUCCESS;
8130  }
8131  }
8132 
8133  qualified = (xasl->instnum_pred == NULL || ev_res == V_TRUE);
8134  if (qualified)
8135  {
8136  /* one iteration successfully completed */
8137  if (qexec_end_one_iteration (thread_p, xasl, xasl_state, tplrec) != NO_ERROR)
8138  {
8139  return S_ERROR;
8140  }
8141  /* only one row is need for exists OP */
8143  {
8144  return S_SUCCESS;
8145  }
8146  }
8147  }
8148  }
8149 
8150  if (xs_scan != S_END) /* an error happened */
8151  {
8152  return S_ERROR;
8153  }
8154  }
8155  }
8156  }
8157  }
8158 
8159  qexec_clear_all_lists (thread_p, xasl);
8160  }
8161 
8162  if (max_recursive_iterations_reached)
8163  {
8164  xb_scan = S_ERROR;
8166  break;
8167  }
8168 
8169  if (ls_scan != S_END) /* an error happened */
8170  {
8171  return S_ERROR;
8172  }
8173  }
8174 
8175  if (xb_scan != S_END) /* an error happened */
8176  {
8177  return S_ERROR;
8178  }
8179 
8180  return S_SUCCESS;
8181 
8182 #undef CTE_CURRENT_SCAN_READ_TUPLE
8183 #undef CTE_CURR_ITERATION_LAST_TUPLE
8184 }
8185 
8186 /*
8187  * qexec_merge_fnc () -
8188  * return: scan code
8189  * xasl(in) : XASL Tree pointer
8190  * xasl_state(in) : XASL Tree state information
8191  * tplrec(out) : Tuple record descriptor to store result tuples
8192  *
8193  * Note: This function is used to interpret an XASL merge command
8194  * tree block. It assumes a general format XASL block
8195  * with all possible representations.
8196  */
8197 static SCAN_CODE
8199  XASL_SCAN_FNC_PTR ignore)
8200 {
8201  XASL_NODE *xptr;
8202  DB_LOGICAL ev_res;
8203  int qualified;
8204  SCAN_CODE ls_scan1; /* first list file scan counter */
8205  SCAN_CODE ls_scan2; /* second list file scan counter */
8206  SCAN_ID *s_id1; /* first list file scan identifier */
8207  SCAN_ID *s_id2; /* second list file scan identifier */
8208  ACCESS_SPEC_TYPE *spec;
8209 
8210  /* set first scan parameters */
8211  s_id1 = &xasl->spec_list->s_id;
8212  /* set second scan parameters */
8213  s_id2 = &xasl->merge_spec->s_id;
8214 
8215  if ((!s_id1)
8216  || ((s_id1->type == S_LIST_SCAN)
8217  && ((!s_id1->s.llsid.list_id) || (s_id1->s.llsid.list_id->type_list.type_cnt == 0))))
8218  {
8220  }
8221 
8222  if ((!s_id2)
8223  || ((s_id2->type == S_LIST_SCAN)
8224  && ((!s_id2->s.llsid.list_id) || (s_id2->s.llsid.list_id->type_list.type_cnt == 0))))
8225  {
8227  }
8228 
8229  spec = xasl->merge_spec;
8230  if (qexec_next_merge_block (thread_p, &spec) != S_SUCCESS)
8231  {
8233  }
8234 
8235  while ((ls_scan1 = qexec_next_scan_block (thread_p, xasl)) == S_SUCCESS)
8236  {
8237  while ((ls_scan1 = scan_next_scan (thread_p, s_id1)) == S_SUCCESS)
8238  {
8239  ls_scan2 = scan_next_scan (thread_p, s_id2);
8240  if (ls_scan2 == S_ERROR)
8241  {
8243  }
8244 
8245  if (ls_scan2 == S_END)
8246  {
8247  if (qexec_next_merge_block (thread_p, &spec) != S_SUCCESS)
8248  {
8250  }
8251 
8252  ls_scan2 = scan_next_scan (thread_p, s_id2);
8253  if (ls_scan2 == S_ERROR)
8254  {
8256  }
8257  }
8258 
8259  /* set scan item as qualified */
8260  qualified = true;
8261 
8262  /* evaluate bptr list */
8263  /* if path expression fetch fails, this instance disqualifies */
8264  for (xptr = xasl->bptr_list; qualified && xptr != NULL; xptr = xptr->next)
8265  {
8266  if (qexec_execute_obj_fetch (thread_p, xptr, xasl_state, S_SELECT) != NO_ERROR)
8267  {
8269  }
8270  else if (xptr->proc.fetch.fetch_res == false)
8271  {
8272  qualified = false;
8273  }
8274  }
8275 
8276  if (qualified)
8277  {
8278  /* evaluate dptr list */
8279  for (xptr = xasl->dptr_list; xptr != NULL; xptr = xptr->next)
8280  {
8281  /* clear correlated subquery list files */
8282  qexec_clear_head_lists (thread_p, xptr);
8284  {
8285  /* skip if linked to regu var */
8286  continue;
8287  }
8288  if (qexec_execute_mainblock (thread_p, xptr, xasl_state, NULL) != NO_ERROR)
8289  {
8291  }
8292  }
8293 
8294  /* evaluate if predicate */
8295  ev_res = V_UNKNOWN;
8296  if (xasl->if_pred != NULL)
8297  {
8298  ev_res = eval_pred (thread_p, xasl->if_pred, &xasl_state->vd, NULL);
8299  if (ev_res == V_ERROR)
8300  {
8302  }
8303  }
8304 
8305  qualified = (xasl->if_pred == NULL || ev_res == V_TRUE);
8306  if (qualified)
8307  {
8308  /* evaluate fptr list */
8309  for (xptr = xasl->fptr_list; qualified && xptr != NULL; xptr = xptr->next)
8310  {
8311  if (qexec_execute_obj_fetch (thread_p, xptr, xasl_state, S_SELECT) != NO_ERROR)
8312  {
8314  }
8315  else if (xptr->proc.fetch.fetch_res == false)
8316  {
8317  qualified = false;
8318  }
8319  }
8320 
8321  if (qualified)
8322  {
8323  if (!xasl->scan_ptr)
8324  { /* no scan procedure block */
8325  /* evaluate inst_num predicate */
8326  if (xasl->instnum_val)
8327  {
8328  ev_res = qexec_eval_instnum_pred (thread_p, xasl, xasl_state);
8329  if (ev_res == V_ERROR)
8330  {
8331  return S_ERROR;
8332  }
8334  {
8335  scan_end_scan (thread_p, s_id1);
8336  scan_end_scan (thread_p, s_id2);
8337  return S_SUCCESS;
8338  }
8339  } /* if (xasl->instnum_val) */
8340  qualified = (xasl->instnum_pred == NULL || ev_res == V_TRUE);
8341 
8342  if (qualified && qexec_end_one_iteration (thread_p, xasl, xasl_state, tplrec) != NO_ERROR)
8343  {
8344  return S_ERROR;
8345  }
8346  } /* handle the scan procedure */
8347  }
8348  }
8349  }
8350  }
8351 
8352  if (ls_scan1 == S_ERROR)
8353  {
8355  }
8356  }
8357 
8358  if (ls_scan1 == S_ERROR)
8359  {
8361  }
8362 
8363  scan_end_scan (thread_p, s_id1);
8364  scan_end_scan (thread_p, s_id2);
8365  return S_SUCCESS;
8366 
8367 exit_on_error:
8368  scan_end_scan (thread_p, s_id1);
8369  scan_end_scan (thread_p, s_id2);
8370  scan_close_scan (thread_p, s_id1);
8371  scan_close_scan (thread_p, s_id2);
8372  return S_ERROR;
8373 }
8374 
8375 /*
8376  * qexec_setup_list_id () -
8377  * return: NO_ERROR, or ER_code
8378  * xasl(in) : XASL Tree block
8379  *
8380  * Note: This routine is used by update/delete/insert to set up a
8381  * type_list. Copying a list_id structure fails unless it has a type list.
8382  */
8383 static int
8385 {
8386  QFILE_LIST_ID *list_id;
8387 
8388  list_id = xasl->list_id;
8389  list_id->tuple_cnt = 0;
8390  list_id->page_cnt = 0;
8391 
8392  /* For streaming queries, set last_pgptr->next_vpid to NULL */
8393  if (list_id->last_pgptr != NULL)
8394  {
8396  }
8397 
8398  list_id->last_pgptr = NULL; /* don't want qfile_close_list() to free this bogus listid */
8399  list_id->type_list.type_cnt = 1;
8400  list_id->type_list.domp = (TP_DOMAIN **) malloc (list_id->type_list.type_cnt * sizeof (TP_DOMAIN *));
8401  if (list_id->type_list.domp == NULL)
8402  {
8404  list_id->type_list.type_cnt * sizeof (TP_DOMAIN *));
8405  return ER_OUT_OF_VIRTUAL_MEMORY;
8406  }
8407  /* set up to return object domains in case we want to return the updated/inserted/deleted oid's */
8408  list_id->type_list.domp[0] = &tp_Object_domain;
8409 
8411  {
8412  list_id->tfile_vfid = qmgr_create_new_temp_file (thread_p, list_id->query_id, TEMP_FILE_MEMBUF_NORMAL);
8413  if (list_id->tfile_vfid == NULL)
8414  {
8415  return ER_FAILED;
8416  }
8417  VFID_COPY (&(list_id->temp_vfid), &(list_id->tfile_vfid->temp_vfid));
8418  }
8419 
8420  assert (list_id->type_list.type_cnt == 1);
8421  qfile_update_qlist_count (thread_p, list_id, 1);
8422 
8423  return NO_ERROR;
8424 }
8425 
8426 /*
8427  * qexec_init_upddel_ehash_files () - Initializes the hash files used for
8428  * duplicate OIDs elimination.
8429  * return: NO_ERROR, or ER_code
8430  * thread_p(in):
8431  * buildlist(in): BUILDLIST_PROC XASL
8432  *
8433  * Note: The function is used only for SELECT statement generated for
8434  * UPDATE/DELETE. The case of SINGLE-UPDATE/SINGLE-DELETE is skipped.
8435  */
8436 static int
8438 {
8439  int idx;
8440  EHID *hash_list = NULL;
8441 
8442  if (buildlist == NULL || buildlist->type != BUILDLIST_PROC)
8443  {
8444  return NO_ERROR;
8445  }
8446 
8447  hash_list = (EHID *) db_private_alloc (thread_p, buildlist->upd_del_class_cnt * sizeof (EHID));
8448  if (hash_list == NULL)
8449  {
8450  goto exit_on_error;
8451  }
8452 
8453  for (idx = 0; idx < buildlist->upd_del_class_cnt; idx++)
8454  {
8455  hash_list[idx].vfid.volid = LOG_DBFIRST_VOLID;
8456  if (xehash_create (thread_p, &hash_list[idx], DB_TYPE_OBJECT, -1, NULL, 0, true) == NULL)
8457  {
8458  goto exit_on_error;
8459  }
8460  }
8461  buildlist->proc.buildlist.upddel_oid_locator_ehids = hash_list;
8462 
8463  return NO_ERROR;
8464 
8465 exit_on_error:
8466  if (hash_list != NULL)
8467  {
8468  for (--idx; idx >= 0; idx--)
8469  {
8470  xehash_destroy (thread_p, &hash_list[idx]);
8471  }
8472  db_private_free (thread_p, hash_list);
8473  }
8474 
8475  return ER_FAILED;
8476 }
8477 
8478 /*
8479  * qexec_destroy_upddel_ehash_files () - Destroys the hash files used for
8480  * duplicate rows elimination in
8481  * UPDATE/DELETE.
8482  * return: void
8483  * thread_p(in):
8484  * buildlist(in): BUILDLIST_PROC XASL
8485  *
8486  * Note: The function is used only for SELECT statement generated for
8487  * UPDATE/DELETE.
8488  */
8489 static void
8491 {
8492  int idx;
8493  bool save_interrupted;
8494  EHID *hash_list = buildlist->proc.buildlist.upddel_oid_locator_ehids;
8495 
8496  save_interrupted = logtb_set_check_interrupt (thread_p, false);
8497 
8498  for (idx = 0; idx < buildlist->upd_del_class_cnt; idx++)
8499  {
8500  if (xehash_destroy (thread_p, &hash_list[idx]) != NO_ERROR)
8501  {
8502  /* should not fail or we'll leak reserved sectors */
8503  assert (false);
8504  }
8505  }
8506  db_private_free (thread_p, hash_list);
8507  buildlist->proc.buildlist.upddel_oid_locator_ehids = NULL;
8508 
8509  (void) logtb_set_check_interrupt (thread_p, save_interrupted);
8510 }
8511 
8512 /*
8513  * qexec_mvcc_cond_reev_set_scan_order () - link classes for condition
8514  * reevaluation in scan order (from
8515  * outer to inner)
8516  * return: list head
8517  * aptr(in): XASL for generated SELECT statement for UPDATE
8518  * buildlist(in): BUILDLIST_PROC XASL
8519  * reev_classes(in): array of classes for reevaluation
8520  * num_reev_classes(in): no of classes for reevaluation
8521  * classes(in): classes to be updated
8522  * num_classes(in): no of classes to be updated
8523  */
8524 static UPDDEL_MVCC_COND_REEVAL *
8525 qexec_mvcc_cond_reev_set_scan_order (XASL_NODE * aptr, UPDDEL_MVCC_COND_REEVAL * reev_classes, int num_reev_classes,
8526  UPDDEL_CLASS_INFO * classes, int num_classes)
8527 {
8528  int idx, idx2, idx3;
8529  ACCESS_SPEC_TYPE *access_spec = NULL;
8530  UPDDEL_MVCC_COND_REEVAL *scan_elem = NULL, *scan_start = NULL;
8531  int *mvcc_extra_assign_reev = NULL;
8532 
8533  if (reev_classes == NULL || num_reev_classes <= 0)
8534  {
8535  return NULL;
8536  }
8537  for (; aptr != NULL; aptr = aptr->scan_ptr)
8538  {
8539  for (access_spec = aptr->spec_list; access_spec != NULL; access_spec = access_spec->next)
8540  {
8541  for (idx = num_reev_classes - 1; idx >= 0; idx--)
8542  {
8543  if (OID_EQ (&access_spec->s.cls_node.cls_oid, &reev_classes[idx].cls_oid))
8544  {
8545  /* check that this class is not an assignment reevaluation class */
8546  for (idx2 = 0; idx2 < num_classes; idx2++)
8547  {
8548  mvcc_extra_assign_reev = classes[idx2].mvcc_extra_assign_reev;
8549  for (idx3 = classes[idx2].num_extra_assign_reev - 1; idx3 >= 0; idx3--)
8550  {
8551  if (mvcc_extra_assign_reev[idx3] == reev_classes[idx].class_index)
8552  {
8553  break;
8554  }
8555  }
8556  if (idx3 >= 0)
8557  {
8558  break;
8559  }
8560  }
8561  if (idx2 < num_classes)
8562  {
8563  continue;
8564  }
8565 
8566  /* if this class is not an assignment reevaluation class then add to the list */
8567  if (scan_elem == NULL)
8568  {
8569  scan_elem = scan_start = &reev_classes[idx];
8570  }
8571  else
8572  {
8573  scan_elem->next = &reev_classes[idx];
8574  scan_elem = scan_elem->next;
8575  }
8576  break;
8577  }
8578  }
8579  if (idx >= 0)
8580  {
8581  break;
8582  }
8583  }
8584  }
8585 
8586  return scan_start;
8587 }
8588 
8589 /*
8590  * prepare_mvcc_reev_data () - create and initialize structures for MVCC
8591  * condition and assignments reevaluation
8592  * return : error code or NO_ERROR
8593  * thread_p (in) :
8594  * aptr (in): XASL for generated SELECT statement for UPDATE
8595  * num_reev_classes (in): no of indexes for classes used in reevaluation
8596  * mvcc_reev_indexes (in) : array of indexes for classes used in reevaluation
8597  * reev_data (in) : MVCC reevaluation data for a specific class
8598  * num_classes (in) : no. of assignments 'classes' elements
8599  * classes(in): array of classes to be updated
8600  * internal_classes (in) : array of information for each class that will be
8601  * updated
8602  * cons_pred(in): NOT NULL contraints predicate
8603  * mvcc_reev_classes(in/out): array of classes information used in MVCC
8604  * reevaluation
8605  * mvcc_reev_assigns(in/out): array of assignments information used in
8606  * reevaluation
8607  * has_delete (in):
8608  */
8609 static int
8610 prepare_mvcc_reev_data (THREAD_ENTRY * thread_p, XASL_NODE * aptr, XASL_STATE * xasl_state, int num_reev_classes,
8611  int *mvcc_reev_indexes, MVCC_UPDDEL_REEV_DATA * reev_data, int num_classes,
8612  UPDDEL_CLASS_INFO * classes, UPDDEL_CLASS_INFO_INTERNAL * internal_classes, int num_assigns,
8613  UPDATE_ASSIGNMENT * assigns, PRED_EXPR * cons_pred,
8614  UPDDEL_MVCC_COND_REEVAL ** mvcc_reev_classes, UPDATE_MVCC_REEV_ASSIGNMENT ** mvcc_reev_assigns,
8615  bool has_delete)
8616 {
8617  UPDDEL_MVCC_COND_REEVAL *cond_reev_classes = NULL, *cond_reev_class = NULL;
8618  UPDDEL_CLASS_INFO *cls = NULL;
8619  UPDDEL_CLASS_INFO_INTERNAL *int_cls = NULL;
8620  int idx, idx2, idx3;
8621 
8622  if (reev_data == NULL)
8623  {
8624  assert (0);
8625  return ER_FAILED;
8626  }
8627 
8628  /* Make sure reev data is initialized, or else it will crash later */
8629  memset (reev_data, 0, sizeof (MVCC_UPDDEL_REEV_DATA));
8630 
8631  if (num_reev_classes == 0)
8632  {
8633  return NO_ERROR;
8634  }
8635 
8636  if (mvcc_reev_classes == NULL)
8637  {
8639  }
8640 
8641  /* allocate and initialize classes for reevaluation */
8642  cond_reev_classes =
8643  (UPDDEL_MVCC_COND_REEVAL *) db_private_alloc (thread_p, sizeof (UPDDEL_MVCC_COND_REEVAL) * num_reev_classes);
8644  if (cond_reev_classes == NULL)
8645  {
8647  }
8648  /* init information for reevaluation */
8649  for (idx = 0; idx < num_reev_classes; idx++)
8650  {
8651  cond_reev_class = &cond_reev_classes[idx];
8652  cond_reev_class->class_index = mvcc_reev_indexes[idx];
8653  OID_SET_NULL (&cond_reev_class->cls_oid);
8654  cond_reev_class->inst_oid = NULL;
8655  cond_reev_class->rest_attrs = NULL;
8656  cond_reev_class->rest_regu_list = NULL;
8657  cond_reev_class->next = NULL;
8658  }
8659  for (idx = 0; idx < num_classes; idx++)
8660  {
8661  cls = &classes[idx];
8662  int_cls = &internal_classes[idx];
8663  if (cls->num_extra_assign_reev > 0)
8664  {
8665  int_cls->mvcc_extra_assign_reev =
8668  * sizeof (UPDDEL_MVCC_COND_REEVAL *));
8669  if (int_cls->mvcc_extra_assign_reev == NULL)
8670  {
8672  }
8673  for (idx2 = cls->num_extra_assign_reev - 1; idx2 >= 0; idx2--)
8674  {
8675  for (idx3 = 0; idx3 < num_reev_classes; idx3++)
8676  {
8677  if (cond_reev_classes[idx3].class_index == cls->mvcc_extra_assign_reev[idx2])
8678  {
8679  int_cls->mvcc_extra_assign_reev[idx2] = &cond_reev_classes[idx3];
8680  break;
8681  }
8682  }
8683  }
8685  }
8686  }
8687  reev_data->mvcc_cond_reev_list = NULL;
8688  reev_data->curr_extra_assign_cnt = 0;
8689  reev_data->curr_extra_assign_reev = NULL;
8690  reev_data->curr_assigns = NULL;
8691  reev_data->curr_attrinfo = NULL;
8692  reev_data->copyarea = NULL;
8693  reev_data->cons_pred = cons_pred;
8694  reev_data->vd = &xasl_state->vd;
8695 
8696  if (qexec_create_mvcc_reev_assignments (thread_p, aptr, has_delete, internal_classes, num_classes, num_assigns,
8697  assigns, mvcc_reev_assigns) != NO_ERROR)
8698  {
8700  }
8701 
8702  *mvcc_reev_classes = cond_reev_classes;
8703  return NO_ERROR;
8704 
8705 exit_on_error:
8706 
8707  if (cond_reev_classes != NULL)
8708  {
8709  db_private_free (thread_p, cond_reev_classes);
8710  }
8711  for (idx = 0; idx < num_classes; idx++)
8712  {
8713  int_cls = &internal_classes[idx];
8714  if (int_cls->mvcc_extra_assign_reev != NULL)
8715  {
8716  db_private_free_and_init (thread_p, int_cls->mvcc_extra_assign_reev);
8717  }
8718  }
8719  *mvcc_reev_classes = NULL;
8720 
8721  return ER_FAILED;
8722 }
8723 
8724 /*
8725  * qexec_execute_update () -
8726  * return: NO_ERROR, or ER_code
8727  * xasl(in): XASL Tree block
8728  * has_delete(in): update/delete
8729  * xasl_state(in):
8730  */
8731 static int
8732 qexec_execute_update (THREAD_ENTRY * thread_p, XASL_NODE * xasl, bool has_delete, XASL_STATE * xasl_state)
8733 {
8734  UPDATE_PROC_NODE *update = &xasl->proc.update;
8735  UPDDEL_CLASS_INFO *upd_cls = NULL;
8736  UPDATE_ASSIGNMENT *assign = NULL;
8737  SCAN_CODE xb_scan;
8738  SCAN_CODE ls_scan;
8739  XASL_NODE *aptr = NULL;
8740  DB_VALUE *valp = NULL;
8741  QPROC_DB_VALUE_LIST vallist;
8742  int assign_idx = 0;
8743  int rc;
8744  int attr_id;
8745  OID *oid = NULL;
8746  OID *class_oid = NULL;
8747  UPDDEL_CLASS_INFO_INTERNAL *internal_classes = NULL, *internal_class = NULL;
8748  ACCESS_SPEC_TYPE *specp = NULL;
8749  SCAN_ID *s_id = NULL;
8750  LOG_LSA lsa;
8751  int savepoint_used = 0;
8752  int satisfies_constraints;
8753  int force_count;
8754  int op_type = SINGLE_ROW_UPDATE;
8755  int s = 0;
8756  int tuple_cnt, error = NO_ERROR;
8758  int class_oid_cnt = 0, class_oid_idx = 0;
8759  int mvcc_reev_class_cnt = 0, mvcc_reev_class_idx = 0;
8760  bool scan_open = false;
8761  int should_delete = 0;
8762  int current_op_type = SINGLE_ROW_UPDATE;
8763  PRUNING_CONTEXT *pcontext = NULL;
8764  DEL_LOB_INFO *del_lob_info_list = NULL;
8765  MVCC_UPDDEL_REEV_DATA mvcc_upddel_reev_data;
8766  MVCC_REEV_DATA mvcc_reev_data;
8767  UPDDEL_MVCC_COND_REEVAL *mvcc_reev_classes = NULL, *mvcc_reev_class = NULL;
8768  UPDATE_MVCC_REEV_ASSIGNMENT *mvcc_reev_assigns = NULL;
8769  bool need_locking;
8770  UPDDEL_CLASS_INSTANCE_LOCK_INFO class_instance_lock_info, *p_class_instance_lock_info = NULL;
8771 
8772  thread_p->no_logging = (bool) update->no_logging;
8773 
8774  /* get the snapshot, before acquiring locks, since the transaction may be blocked and we need the snapshot when
8775  * update starts, not later */
8776  (void) logtb_get_mvcc_snapshot (thread_p);
8777 
8778  mvcc_upddel_reev_data.copyarea = NULL;
8779  mvcc_reev_data.set_update_reevaluation (mvcc_upddel_reev_data);
8780  class_oid_cnt = update->num_classes;
8781  mvcc_reev_class_cnt = update->num_reev_classes;
8782 
8783  /* Allocate memory for oids, hfids and attributes cache info of all classes used in update */
8784  error = qexec_create_internal_classes (thread_p, update->classes, class_oid_cnt, &internal_classes);
8785  if (error != NO_ERROR)
8786  {
8788  }
8789 
8790  /* lock classes which this query will update */
8791  aptr = xasl->aptr_list;
8792  error = qexec_set_class_locks (thread_p, aptr, update->classes, update->num_classes, internal_classes);
8793  if (error != NO_ERROR)
8794  {
8796  }
8797 
8798  error =
8799  prepare_mvcc_reev_data (thread_p, aptr, xasl_state, mvcc_reev_class_cnt, update->mvcc_reev_classes,
8800  &mvcc_upddel_reev_data, update->num_classes, update->classes, internal_classes,
8801  update->num_assigns, update->assigns, update->cons_pred, &mvcc_reev_classes,
8802  &mvcc_reev_assigns, has_delete);
8803  if (error != NO_ERROR)
8804  {
8806  }
8807 
8808  if (class_oid_cnt == 1 && update->classes->num_subclasses == 1)
8809  {
8810  /* We update instances of only one class. We expect to lock the instances at select phase. However this not
8811  * happens in all situations. The qexec_execute_mainblock function will set instances_locked of
8812  * p_class_instance_lock_info to true in case that current class instances are locked at select phase. */
8813  COPY_OID (&class_instance_lock_info.class_oid, (*((*update).classes)).class_oid);
8814  class_instance_lock_info.instances_locked = false;
8815  p_class_instance_lock_info = &class_instance_lock_info;
8816  }
8817 
8818  if (qexec_execute_mainblock (thread_p, aptr, xasl_state, p_class_instance_lock_info) != NO_ERROR)
8819  {
8821  }
8822 
8823  if (p_class_instance_lock_info && p_class_instance_lock_info->instances_locked)
8824  {
8825  /* already locked in select phase. Avoid locking again the same instances at update phase */
8826  need_locking = false;
8827  }
8828  else
8829  {
8830  /* not locked in select phase, need locking at update phase */
8831  need_locking = true;
8832  }
8833 
8834  /* This guarantees that the result list file will have a type list. Copying a list_id structure fails unless it has a
8835  * type list. */
8836  if (qexec_setup_list_id (thread_p, xasl) != NO_ERROR)
8837  {
8839  }
8840 
8841  if (aptr->list_id->tuple_cnt > 1)
8842  {
8843  /* When multiple instances are updated, statement level uniqueness checking should be performed. In this case,
8844  * uniqueness checking is performed by using statistical information generated by the execution of UPDATE
8845  * statement. */
8846  op_type = MULTI_ROW_UPDATE;
8847  }
8848  else
8849  { /* tuple_cnt <= 1 */
8850  /* When single instance is updated, instance level uniqueness checking is performed. In this case, uniqueness
8851  * checking is performed by the server when the key of the instance is inserted into an unique index. */
8852  op_type = SINGLE_ROW_UPDATE;
8853  }
8854 
8855  /* need to start a topop to ensure statement atomicity. One update statement might update several disk images. For
8856  * example, one row update might update zero or more index keys, one heap record, and other things. So, the update
8857  * statement must be performed atomically. */
8858  if (xtran_server_start_topop (thread_p, &lsa) != NO_ERROR)
8859  {
8861  }
8862  savepoint_used = 1;
8863 
8864  specp = xasl->spec_list;
8865  /* force_select_lock = false */
8866  assert (xasl->scan_op_type == S_SELECT);
8867  if (qexec_open_scan (thread_p, specp, xasl->val_list, &xasl_state->vd, false, specp->fixed_scan, specp->grouped_scan,
8868  true, &specp->s_id, xasl_state->query_id, S_SELECT, false, NULL) != NO_ERROR)
8869  {
8871  }
8872 
8873  scan_open = true;
8874 
8875  tuple_cnt = 1;
8876  while ((xb_scan = qexec_next_scan_block_iterations (thread_p, xasl)) == S_SUCCESS)
8877  {
8878  s_id = &xasl->curr_spec->s_id;
8879  while ((ls_scan = scan_next_scan (thread_p, s_id)) == S_SUCCESS)
8880  {
8881  if (op_type == MULTI_ROW_UPDATE)
8882  {
8883  if (tuple_cnt == 1)
8884  {
8885  repl_info = REPL_INFO_TYPE_RBR_START;
8886  }
8887  else if (tuple_cnt == aptr->list_id->tuple_cnt)
8888  {
8889  repl_info = REPL_INFO_TYPE_RBR_END;
8890  }
8891  else
8892  {
8893  repl_info = REPL_INFO_TYPE_RBR_NORMAL;
8894  }
8895  }
8896  else
8897  {
8898  repl_info = REPL_INFO_TYPE_RBR_NORMAL;
8899  }
8900  tuple_cnt++;
8901 
8902  /* evaluate constraint predicate */
8903  satisfies_constraints = V_UNKNOWN;
8904  if (update->cons_pred != NULL)
8905  {
8906  satisfies_constraints = eval_pred (thread_p, update->cons_pred, &xasl_state->vd, NULL);
8907  if (satisfies_constraints == V_ERROR)
8908  {
8910  }
8911  }
8912 
8913  if (update->cons_pred != NULL && satisfies_constraints != V_TRUE)
8914  {
8915  /* currently there are only NOT NULL constraints */
8918  }
8919 
8920  /* should delete? */
8921  current_op_type = op_type;
8922  if (has_delete)
8923  {
8924  vallist = s_id->val_list->valp;
8925  for (class_oid_idx = 0; class_oid_idx < class_oid_cnt; vallist = vallist->next->next, class_oid_idx++)
8926  {
8927  ; /* advance */
8928  }
8929  valp = vallist->val;
8930  if (valp == NULL)
8931  {
8933  }
8934 
8935  /* We may get NULL as an expr value. See pt_to_merge_update_query(...). */
8936  if (DB_IS_NULL (valp))
8937  {
8938  should_delete = 0;
8939  }
8940  else
8941  {
8942  should_delete = db_get_int (valp);
8943  }
8944 
8945  if (should_delete)
8946  {
8947  if (op_type == SINGLE_ROW_UPDATE)
8948  {
8949  current_op_type = SINGLE_ROW_DELETE;
8950  }
8951  else
8952  {
8953  current_op_type = MULTI_ROW_DELETE;
8954  }
8955  }
8956  }
8957 
8958  /* for each class calc. OID, HFID, attributes cache info and statistical information only if class has
8959  * changed */
8960  vallist = s_id->val_list->valp;
8961  for (class_oid_idx = 0, mvcc_reev_class_idx = 0; class_oid_idx < class_oid_cnt;
8962  vallist = vallist->next->next, class_oid_idx++)
8963  {
8964  upd_cls = &update->classes[class_oid_idx];
8965  internal_class = &internal_classes[class_oid_idx];
8966 
8967  if (mvcc_reev_class_cnt && mvcc_reev_classes[mvcc_reev_class_idx].class_index == class_oid_idx)
8968  {
8969  mvcc_reev_class = &mvcc_reev_classes[mvcc_reev_class_idx++];
8970  }
8971  else
8972  {
8973  mvcc_reev_class = NULL;
8974  }
8975 
8976  /* instance OID */
8977  valp = vallist->val;
8978  if (valp == NULL)
8979  {
8981  }
8982  if (DB_IS_NULL (valp))
8983  {
8984  internal_class->oid = NULL;
8985  continue;
8986  }
8987  internal_class->oid = db_get_oid (valp);
8988  if (mvcc_reev_class != NULL)
8989  {
8990  mvcc_reev_class->inst_oid = internal_class->oid;
8991  }
8992 
8993  /* class OID */
8994  valp = vallist->next->val;
8995  if (valp == NULL)
8996  {
8998  }
8999  if (DB_IS_NULL (valp))
9000  {
9001  continue;
9002  }
9003  class_oid = db_get_oid (valp);
9004 
9005  /* class has changed to a new subclass */
9006  if (class_oid
9007  && (!OID_EQ (&internal_class->prev_class_oid, class_oid)
9008  || (!should_delete && BTREE_IS_MULTI_ROW_OP (op_type) && upd_cls->has_uniques
9009  && internal_class->scan_cache != NULL && internal_class->scan_cache->m_index_stats == NULL)))
9010  {
9011  /* Load internal_class object with information for class_oid */
9012  error =
9013  qexec_upddel_setup_current_class (thread_p, upd_cls, internal_class, current_op_type, class_oid);
9014  if (error != NO_ERROR || internal_class->class_hfid == NULL)
9015  {
9016  /* matching class oid does not exist... error */
9017  er_log_debug (ARG_FILE_LINE, "qexec_execute_update: class OID is not correct\n");
9019  }
9020 
9021  /* temporary disable set filters when needs prunning */
9022  if (mvcc_reev_class != NULL)
9023  {
9024  error = qexec_upddel_mvcc_set_filters (thread_p, aptr, mvcc_reev_class, class_oid);
9025  if (error != NO_ERROR)
9026  {
9028  }
9029  }
9030 
9031  /* clear attribute cache information if valid old subclass */
9032  if (!OID_ISNULL (&internal_class->prev_class_oid) && internal_class->is_attr_info_inited)
9033  {
9034  (void) heap_attrinfo_end (thread_p, &internal_class->attr_info);
9035  internal_class->is_attr_info_inited = false;
9036  }
9037  /* start attribute cache information for new subclass */
9038  if (heap_attrinfo_start (thread_p, class_oid, -1, NULL, &internal_class->attr_info) != NO_ERROR)
9039  {
9041  }
9042  internal_class->is_attr_info_inited = true;
9043 
9044  if (should_delete)
9045  {
9046  if (internal_class->num_lob_attrs)
9047  {
9048  internal_class->crt_del_lob_info =
9049  qexec_change_delete_lob_info (thread_p, xasl_state, internal_class, &del_lob_info_list);
9050  if (internal_class->crt_del_lob_info == NULL)
9051  {
9053  }
9054  }
9055  else
9056  {
9057  internal_class->crt_del_lob_info = NULL;
9058  }
9059  }
9060  }
9061 
9062  /* don't update, just delete */
9063  if (should_delete)
9064  {
9065  /* handle lobs first */
9066  if (internal_class->crt_del_lob_info)
9067  {
9068  /* delete lob files */
9069  DEL_LOB_INFO *crt_del_lob_info = internal_class->crt_del_lob_info;
9070  SCAN_CODE scan_code;
9071  int error;
9072  int i;
9074 
9075  /* read lob attributes */
9076  scan_code =
9077  heap_get_visible_version (thread_p, oid, class_oid, &recdes, internal_class->scan_cache, PEEK,
9078  NULL_CHN);
9079  if (scan_code == S_ERROR)
9080  {
9082  }
9083  if (scan_code == S_SUCCESS)
9084  {
9085  error =
9086  heap_attrinfo_read_dbvalues (thread_p, oid, &recdes, NULL, &crt_del_lob_info->attr_info);
9087  if (error != NO_ERROR)
9088  {
9090  }
9091  for (i = 0; i < internal_class->num_lob_attrs; i++)
9092  {
9093  DB_VALUE *attr_valp = &crt_del_lob_info->attr_info.values[i].dbvalue;
9094  if (!db_value_is_null (attr_valp))
9095  {
9096  DB_ELO *elo;
9097  error = NO_ERROR;
9098 
9099  assert (db_value_type (attr_valp) == DB_TYPE_BLOB
9100  || db_value_type (attr_valp) == DB_TYPE_CLOB);
9101  elo = db_get_elo (attr_valp);
9102  if (elo)
9103  {
9104  error = db_elo_delete (elo);
9105  }
9106  if (error != NO_ERROR)
9107  {
9109  }
9110  }
9111  }
9112  }
9113  }
9114 
9115  force_count = 0;
9116  error =
9117  locator_attribute_info_force (thread_p, internal_class->class_hfid, internal_class->oid, NULL, NULL,
9118  0, LC_FLUSH_DELETE, current_op_type, internal_class->scan_cache,
9119  &force_count, false, REPL_INFO_TYPE_RBR_NORMAL,
9120  DB_NOT_PARTITIONED_CLASS, NULL, NULL, &mvcc_reev_data,
9121  UPDATE_INPLACE_NONE, NULL, need_locking);
9122 
9124  {
9125  error = NO_ERROR;
9126  }
9127  else if (error != NO_ERROR)
9128  {
9130  }
9131  else if (force_count)
9132  {
9133  xasl->list_id->tuple_cnt++;
9134  }
9135  }
9136 
9137  if (heap_attrinfo_clear_dbvalues (&internal_class->attr_info) != NO_ERROR)
9138  {
9140  }
9141 
9142  if (should_delete)
9143  {
9144  goto continue_scan;
9145  }
9146  }
9147 
9148  /* Get info for MVCC condition reevaluation */
9149  for (; mvcc_reev_class_idx < mvcc_reev_class_cnt; mvcc_reev_class_idx++)
9150  {
9151  mvcc_reev_class = &mvcc_reev_classes[mvcc_reev_class_idx];
9152 
9153  /* instance OID */
9154  valp = vallist->val;
9155  if (valp == NULL)
9156  {
9158  }
9159  /* FIXME: Function version of db_get_oid returns (probably) NULL_OID when the value is NULL,
9160  * while macro version returns NULL pointer. This may cause different behavior.
9161  * As a quick fix, I'm going to add DB_IS_NULL block to keep the existing behavior.
9162  * We need to investigate and get rid of differences of two implementation.
9163  * Inlining would be a good choice.
9164  */
9165  if (DB_IS_NULL (valp))
9166  {
9167  OID_SET_NULL (mvcc_reev_class->inst_oid);
9168  }
9169  else
9170  {
9171  mvcc_reev_class->inst_oid = db_get_oid (valp);
9172  }
9173 
9174  /* class OID */
9175  valp = vallist->next->val;
9176  if (valp == NULL)
9177  {
9179  }
9180 
9181  /* FIXME: please see above FIXME */
9182  if (DB_IS_NULL (valp))
9183  {
9184  OID_SET_NULL (class_oid);
9185  }
9186  else
9187  {
9188  class_oid = db_get_oid (valp);
9189  }
9190 
9191  /* class has changed to a new subclass */
9192  if (class_oid && !OID_EQ (&mvcc_reev_class->cls_oid, class_oid))
9193  {
9194  error = qexec_upddel_mvcc_set_filters (thread_p, aptr, mvcc_reev_class, class_oid);
9195  if (error != NO_ERROR)
9196  {
9198  }
9199  }
9200  vallist = vallist->next->next;
9201  }
9202 
9203  if (mvcc_upddel_reev_data.mvcc_cond_reev_list == NULL && mvcc_reev_class_cnt > 0)
9204  {
9205  /* If scan order was not set then do it. This operation must be run only once. We do it here and not at
9206  * the beginning of this function because the class OIDs must be set for classes involved in reevaluation
9207  * (in mvcc_reev_classes) prior to this operation */
9208  mvcc_upddel_reev_data.mvcc_cond_reev_list =
9209  qexec_mvcc_cond_reev_set_scan_order (aptr, mvcc_reev_classes, mvcc_reev_class_cnt, update->classes,
9210  update->num_classes);
9211  }
9212  if (has_delete)
9213  {
9214  vallist = vallist->next; /* skip should_delete */
9215  }
9216 
9217  /* perform assignments */
9218  for (assign_idx = 0; assign_idx < update->num_assigns; assign_idx++)
9219  {
9220  HEAP_CACHE_ATTRINFO *attr_info;
9221 
9222  assign = &update->assigns[assign_idx];
9223  class_oid_idx = assign->cls_idx;
9224  internal_class = &internal_classes[class_oid_idx];
9225  attr_info = &internal_class->attr_info;
9226  upd_cls = &update->classes[class_oid_idx];
9227  oid = internal_class->oid;
9228  if (oid == NULL)
9229  {
9230  /* nothing to update */
9231  if (assign->constant == NULL)
9232  {
9233  vallist = vallist->next;
9234  }
9235  continue;
9236  }
9237  attr_id = upd_cls->att_id[internal_class->subclass_idx * upd_cls->num_attrs + assign->att_idx];
9238  if (mvcc_reev_assigns != NULL)
9239  {
9240  mvcc_reev_assigns[assign_idx].att_id = attr_id;
9241  }
9242 
9243  if (assign->constant != NULL)
9244  {
9245  rc = heap_attrinfo_set (oid, attr_id, assign->constant, attr_info);
9246  }
9247  else
9248  {
9249  rc = heap_attrinfo_set (oid, attr_id, vallist->val, attr_info);
9250  vallist = vallist->next;
9251  }
9252  if (rc != NO_ERROR)
9253  {
9255  }
9256  }
9257 
9258  /* Flush new values for each class. The class list was built from right to left during XASL generation, so in
9259  * order to maintain the correct update order specified in the query, we must iterate from right to left as
9260  * well; this makes a difference only when we update the same attribute of the same class more than once. */
9261  for (class_oid_idx = class_oid_cnt - 1, mvcc_reev_class_idx = mvcc_reev_class_cnt - 1; class_oid_idx >= 0;
9262  class_oid_idx--)
9263  {
9264  internal_class = &internal_classes[class_oid_idx];
9265  upd_cls = &update->classes[class_oid_idx];
9266 
9267  if (mvcc_reev_class_cnt && mvcc_reev_classes[mvcc_reev_class_idx].class_index == class_oid_idx)
9268  {
9269  mvcc_reev_class = &mvcc_reev_classes[mvcc_reev_class_idx++];
9270  }
9271  else
9272  {
9273  mvcc_reev_class = NULL;
9274  }
9275  mvcc_upddel_reev_data.curr_upddel = mvcc_reev_class;
9276 
9277  force_count = 0;
9278  oid = internal_class->oid;
9279  if (oid == NULL)
9280  {
9281  continue;
9282  }
9283 
9284  if (upd_cls->needs_pruning)
9285  {
9286  pcontext = &internal_class->context;
9287  }
9288  else
9289  {
9290  pcontext = NULL;
9291  }
9292 
9293  mvcc_upddel_reev_data.curr_extra_assign_reev = internal_class->mvcc_extra_assign_reev;
9294  mvcc_upddel_reev_data.curr_extra_assign_cnt = internal_class->extra_assign_reev_cnt;
9295  mvcc_upddel_reev_data.curr_assigns = internal_class->mvcc_reev_assigns;
9296  mvcc_upddel_reev_data.curr_attrinfo = &internal_class->attr_info;
9297  error =
9298  locator_attribute_info_force (thread_p, internal_class->class_hfid, oid, &internal_class->attr_info,
9299  &upd_cls->att_id[internal_class->subclass_idx * upd_cls->num_attrs],
9300  upd_cls->num_attrs, LC_FLUSH_UPDATE, op_type, internal_class->scan_cache,
9301  &force_count, false, repl_info, internal_class->needs_pruning, pcontext,
9302  NULL, &mvcc_reev_data, UPDATE_INPLACE_NONE, NULL, need_locking);
9304  {
9305  error = NO_ERROR;
9306  }
9307  else if (error == ER_HEAP_UNKNOWN_OBJECT)
9308  {
9309  /* TODO: This is a very dangerous. A different way of handling it must be found.
9310  * This may not even be necessary. I guess this is legacy code from READ COMMITTED
9311  * re-evaluation made under locator_attribute_info_force. I think currently locking object
9312  * is done on select phase. However, I am not removing this code yet until more investigation
9313  * is done.
9314  */
9315  er_clear ();
9316  error = NO_ERROR;
9317  }
9318  else if (error != NO_ERROR)
9319  {
9321  }
9322  else
9323  {
9324  /* Successful update. */
9325  force_count = 1;
9326  }
9327 
9328  /* Instances are not put into the result list file, but are counted. */
9329  if (force_count)
9330  {
9331  xasl->list_id->tuple_cnt++;
9332  }
9333  }
9334  continue_scan:
9335  ;
9336  }
9337  if (ls_scan != S_END)
9338  {
9340  }
9341  }
9342  if (xb_scan != S_END)
9343  {
9345  }
9346 
9347  for (s = 0; s < class_oid_cnt; s++)
9348  {
9349  internal_class = &internal_classes[s];
9350  upd_cls = &update->classes[s];
9351 
9352  if (upd_cls->has_uniques)
9353  {
9354  if (internal_class->needs_pruning)
9355  {
9356  error = qexec_process_partition_unique_stats (thread_p, &internal_class->context);
9357  }
9358  else
9359  {
9360  error = qexec_process_unique_stats (thread_p, upd_cls->class_oid, internal_class);
9361  }
9362  if (error != NO_ERROR)
9363  {
9365  }
9366  }
9367  }
9368 
9369  qexec_close_scan (thread_p, specp);
9370 
9371  if (has_delete)
9372  {
9373  qexec_free_delete_lob_info_list (thread_p, &del_lob_info_list);
9374  }
9375 
9376  if (internal_classes)
9377  {
9378  qexec_clear_internal_classes (thread_p, internal_classes, class_oid_cnt);
9379  db_private_free_and_init (thread_p, internal_classes);
9380  }
9381 
9382  if (mvcc_reev_classes != NULL)
9383  {
9384  db_private_free (thread_p, mvcc_reev_classes);
9385  mvcc_reev_classes = NULL;
9386  }
9387  if (mvcc_reev_assigns != NULL)
9388  {
9389  db_private_free (thread_p, mvcc_reev_assigns);
9390  mvcc_reev_assigns = NULL;
9391  }
9392  if (mvcc_upddel_reev_data.copyarea != NULL)
9393  {
9394  locator_free_copy_area (mvcc_upddel_reev_data.copyarea);
9395  mvcc_upddel_reev_data.copyarea = NULL;
9396  }
9397 
9398  if (savepoint_used)
9399  {
9401  {
9402  qexec_failure_line (__LINE__, xasl_state);
9403  return ER_FAILED;
9404  }
9405  }
9406 
9407 #if 0 /* yaw */
9408  /* remove query result cache entries which are relevant with this class */
9409  class_oid = update->class_oid;
9410  if (!QFILE_IS_LIST_CACHE_DISABLED && class_oid)
9411  {
9412  for (s = 0; s < update->num_classes; s++, class_oid++)
9413  {
9414  if (qexec_clear_list_cache_by_class (class_oid) != NO_ERROR)
9415  {
9417  "qexec_execute_update: qexec_clear_list_cache_by_class failed for class { %d %d %d }\n",
9418  class_oid->pageid, class_oid->slotid, class_oid->volid);
9419  }
9420  }
9421  qmgr_add_modified_class (class_oid);
9422  }
9423 #endif
9424 
9425  return NO_ERROR;
9426 
9427 exit_on_error:
9428 
9429  if (scan_open)
9430  {
9431  qexec_end_scan (thread_p, specp);
9432  qexec_close_scan (thread_p, specp);
9433  }
9434 
9435  if (del_lob_info_list != NULL)
9436  {
9437  qexec_free_delete_lob_info_list (thread_p, &del_lob_info_list);
9438  }
9439 
9440  if (mvcc_reev_classes != NULL)
9441  {
9442  db_private_free (thread_p, mvcc_reev_classes);
9443  mvcc_reev_classes = NULL;
9444  }
9445  if (mvcc_reev_assigns != NULL)
9446  {
9447  db_private_free (thread_p, mvcc_reev_assigns);
9448  mvcc_reev_assigns = NULL;
9449  }
9450  if (mvcc_upddel_reev_data.copyarea != NULL)
9451  {
9452  locator_free_copy_area (mvcc_upddel_reev_data.copyarea);
9453  mvcc_upddel_reev_data.copyarea = NULL;
9454  }
9455 
9456  if (savepoint_used)
9457  {
9459  }
9460 
9461  if (internal_classes)
9462  {
9463  qexec_clear_internal_classes (thread_p, internal_classes, class_oid_cnt);
9464  db_private_free_and_init (thread_p, internal_classes);
9465  }
9466 
9467  return ER_FAILED;
9468 }
9469 
9470 /*
9471  * qexec_update_btree_unique_stats_info () - updates statistical information structure
9472  * return: NO_ERROR or ER_code
9473  * thread_p(in) :
9474  * info(in) : structure to update
9475  */
9476 static void
9478  const HEAP_SCANCACHE * scan_cache)
9479 {
9480  assert (info != NULL && scan_cache != NULL);
9481 
9482  if (scan_cache->m_index_stats != NULL)
9483  {
9484  (*info) += (*scan_cache->m_index_stats);
9485  }
9486 }
9487 
9488 /*
9489  * qexec_process_unique_stats () - verify unique statistic information for
9490  * a class hierarchy and update index
9491  * return : error code or NO_ERROR
9492  * thread_p (in) :
9493  * class_oid (in) :
9494  * internal_class (in) :
9495  */
9496 static int
9497 qexec_process_unique_stats (THREAD_ENTRY * thread_p, const OID * class_oid, UPDDEL_CLASS_INFO_INTERNAL * internal_class)
9498 {
9499  assert (class_oid != NULL && internal_class != NULL);
9500 
9501  int error = NO_ERROR;
9502 
9503  if (internal_class->m_inited_scancache)
9504  {
9505  /* Accumulate current statistics */
9506  qexec_update_btree_unique_stats_info (thread_p, &internal_class->m_unique_stats, &internal_class->m_scancache);
9507  }
9508 // *INDENT-OFF*
9509 for (const auto & it:internal_class->m_unique_stats.get_map ())
9510  {
9511  if (!it.second.is_unique ())
9512  {
9513  BTREE_SET_UNIQUE_VIOLATION_ERROR (thread_p, NULL, NULL, class_oid, &it.first, NULL);
9514  return ER_BTREE_UNIQUE_FAILED;
9515  }
9516  error = logtb_tran_update_unique_stats (thread_p, it.first, it.second, true);
9517  if (error != NO_ERROR)
9518  {
9519  ASSERT_ERROR ();
9520  return error;
9521  }
9522  }
9523 // *INDENT-ON*
9524  return NO_ERROR;
9525 }
9526 
9527 /*
9528  * qexec_process_partition_unique_stats () - process unique statistics on a partitioned class
9529  * return : error code or NO_ERROR
9530  * thread_p (in) :
9531  * pcontext (in) :
9532  *
9533  * Note: Since unique indexes for partitioned classes are either local or
9534  * global, it's to expensive to use the validation made on normal class
9535  * hierarchies. This function just reflects the unique statistics to the
9536  * index header
9537  */
9538 static int
9540 {
9541  assert (pcontext != NULL);
9542 
9543  PRUNING_SCAN_CACHE *pruned_scan_cache = NULL;
9544  SCANCACHE_LIST *node = NULL;
9545  int error = NO_ERROR;
9546 
9547  for (node = pcontext->scan_cache_list; node != NULL; node = node->next)
9548  {
9549  // *INDENT-OFF*
9550  pruned_scan_cache = &node->scan_cache;
9551  if (!pruned_scan_cache->is_scan_cache_started)
9552  {
9553  continue;
9554  }
9555 
9556  HEAP_SCANCACHE &scan_cache = pruned_scan_cache->scan_cache;
9557  if (scan_cache.m_index_stats != NULL)
9558  {
9559  for (const auto &it : scan_cache.m_index_stats->get_map ())
9560  {
9561  if (!it.second.is_unique ())
9562  {
9563  char *index_name = NULL;
9564  error = heap_get_indexinfo_of_btid (thread_p, &scan_cache.node.class_oid, &it.first, NULL, NULL, NULL,
9565  NULL, &index_name, NULL);
9566  if (error != NO_ERROR)
9567  {
9568  ASSERT_ERROR ();
9569  return error;
9570  }
9571 
9572  BTREE_SET_UNIQUE_VIOLATION_ERROR (thread_p, NULL, NULL, &scan_cache.node.class_oid, &it.first,
9573  index_name);
9574 
9575  if (index_name != NULL)
9576  {
9577  free_and_init (index_name);
9578  }
9579  return ER_BTREE_UNIQUE_FAILED;
9580  }
9581 
9582  error = logtb_tran_update_unique_stats (thread_p, it.first, it.second, true);
9583  if (error != NO_ERROR)
9584  {
9585  ASSERT_ERROR ();
9586  return error;
9587  }
9588  }
9589  }
9590  // *INDENT-ON*
9591  }
9592 
9593  return NO_ERROR;
9594 }
9595 
9596 /*
9597  * qexec_execute_delete () -
9598  * return: NO_ERROR or ER_code
9599  * xasl(in) : XASL Tree block
9600  * xasl_state(in) :
9601  */
9602 static int
9604 {
9605 #define MIN_NUM_ROWS_FOR_MULTI_DELETE 20
9606 
9607  DELETE_PROC_NODE *delete_ = &xasl->proc.delete_;
9608  SCAN_CODE xb_scan = S_END;
9609  SCAN_CODE ls_scan = S_END;
9610  XASL_NODE *aptr = NULL;
9611  DB_VALUE *valp = NULL;
9612  OID *oid = NULL;
9613  OID *class_oid = NULL;
9614  ACCESS_SPEC_TYPE *specp = NULL;
9615  SCAN_ID *s_id = NULL;
9616  LOG_LSA lsa;
9617  int savepoint_used = 0;
9618  int class_oid_cnt = 0, class_oid_idx = 0;
9619  int force_count = 0;
9620  int op_type = SINGLE_ROW_DELETE;
9621  int s = 0, error = NO_ERROR;
9622  int mvcc_reev_class_cnt = 0, mvcc_reev_class_idx = 0;
9623  QPROC_DB_VALUE_LIST val_list = NULL;
9624  bool scan_open = false;
9625  UPDDEL_CLASS_INFO *query_class = NULL;
9626  UPDDEL_CLASS_INFO_INTERNAL *internal_classes = NULL, *internal_class = NULL;
9627  DEL_LOB_INFO *del_lob_info_list = NULL;
9628  MVCC_REEV_DATA mvcc_reev_data;
9629  MVCC_UPDDEL_REEV_DATA mvcc_upddel_reev_data;
9630  UPDDEL_MVCC_COND_REEVAL *mvcc_reev_classes = NULL, *mvcc_reev_class = NULL;
9631  bool need_locking;
9632  UPDDEL_CLASS_INSTANCE_LOCK_INFO class_instance_lock_info, *p_class_instance_lock_info = NULL;
9633 
9634  thread_p->no_logging = (bool) delete_->no_logging;
9635 
9636  /* get the snapshot, before acquiring locks, since the transaction may be blocked and we need the snapshot when
9637  * delete starts, not later */
9638  (void) logtb_get_mvcc_snapshot (thread_p);
9639 
9640  class_oid_cnt = delete_->num_classes;
9641  mvcc_reev_class_cnt = delete_->num_reev_classes;
9642  mvcc_reev_data.set_update_reevaluation (mvcc_upddel_reev_data);
9643 
9644  mvcc_upddel_reev_data.copyarea = NULL;
9645 
9646  /* Allocate memory for oids, hfids and attributes cache info of all classes used in update */
9647  error = qexec_create_internal_classes (thread_p, delete_->classes, class_oid_cnt, &internal_classes);
9648  if (error != NO_ERROR)
9649  {
9651  }
9652 
9653  /* lock classes from which this query will delete */
9654  aptr = xasl->aptr_list;
9655  error = qexec_set_class_locks (thread_p, aptr, delete_->classes, delete_->num_classes, internal_classes);
9656  if (error != NO_ERROR)
9657  {
9659  }
9660 
9661  error =
9662  prepare_mvcc_reev_data (thread_p, aptr, xasl_state, mvcc_reev_class_cnt, delete_->mvcc_reev_classes,
9663  &mvcc_upddel_reev_data, delete_->num_classes, delete_->classes, internal_classes, 0, NULL,
9664  NULL, &mvcc_reev_classes, NULL, 0);
9665  if (error != NO_ERROR)
9666  {
9668  }
9669 
9670  if (class_oid_cnt == 1 && delete_->classes->num_subclasses == 1)
9671  {
9672  /* We delete instances of only one class. We expect to lock the instances at select phase. However this not
9673  * happens in all situations. The qexec_execute_mainblock function will set instances_locked of
9674  * p_class_instance_lock_info to true in case that current class instances are locked at select phase. */
9675  COPY_OID (&class_instance_lock_info.class_oid, (*((*delete_).classes)).class_oid);
9676  class_instance_lock_info.instances_locked = false;
9677  p_class_instance_lock_info = &class_instance_lock_info;
9678  }
9679 
9680  if (qexec_execute_mainblock (thread_p, aptr, xasl_state, p_class_instance_lock_info) != NO_ERROR)
9681  {
9683  }
9684 
9685  if (p_class_instance_lock_info && p_class_instance_lock_info->instances_locked)
9686  {
9687  /* already locked in select phase. Avoid locking again the same instances at delete phase. */
9688  need_locking = false;
9689  }
9690  else
9691  {
9692  /* not locked in select phase, need locking at update phase */
9693  need_locking = true;
9694  }
9695 
9696  /* This guarantees that the result list file will have a type list. Copying a list_id structure fails unless it has a
9697  * type list. */
9698  if ((qexec_setup_list_id (thread_p, xasl) != NO_ERROR)
9699  /* it can be > 2 || (aptr->list_id->type_list.type_cnt != 2) */ )
9700  {
9702  }
9703 
9704 
9705  /* Allocate and init structures for statistical information */
9707  {
9708  op_type = MULTI_ROW_DELETE;
9709  }
9710  else
9711  {
9712  /* When the number of instances to be deleted is small, SINGLE_ROW_DELETE operation would be better, I guess.. */
9713  op_type = SINGLE_ROW_DELETE;
9714  }
9715 
9716  /* need to start a topop to ensure statement atomicity. One delete statement might update several disk images. For
9717  * example, one row delete might update zero or more index keys, one heap record, catalog info of object count, and
9718  * other things. So, the delete statement must be performed atomically. */
9719  if (xtran_server_start_topop (thread_p, &lsa) != NO_ERROR)
9720  {
9722  }
9723 
9724  savepoint_used = 1;
9725 
9726  specp = xasl->spec_list;
9727  assert (xasl->scan_op_type == S_SELECT);
9728  /* force_select_lock = false */
9729  if (qexec_open_scan (thread_p, specp, xasl->val_list, &xasl_state->vd, false, specp->fixed_scan, specp->grouped_scan,
9730  true, &specp->s_id, xasl_state->query_id, S_SELECT, false, NULL) != NO_ERROR)
9731  {
9733  }
9734 
9735  scan_open = true;
9736 
9737  while ((xb_scan = qexec_next_scan_block_iterations (thread_p, xasl)) == S_SUCCESS)
9738  {
9739  s_id = &xasl->curr_spec->s_id;
9740 
9741  while ((ls_scan = scan_next_scan (thread_p, s_id)) == S_SUCCESS)
9742  {
9743  val_list = s_id->val_list->valp;
9744 
9745  /* Get info for MVCC condition reevaluation */
9746  for (class_oid_idx = 0, mvcc_reev_class_idx = 0;
9747  class_oid_idx < class_oid_cnt || mvcc_reev_class_idx < mvcc_reev_class_cnt;
9748  val_list = val_list->next->next, class_oid_idx++)
9749  {
9750  if (mvcc_reev_class_idx < mvcc_reev_class_cnt
9751  && mvcc_reev_classes[mvcc_reev_class_idx].class_index == class_oid_idx)
9752  {
9753  mvcc_reev_class = &mvcc_reev_classes[mvcc_reev_class_idx++];
9754  }
9755  else
9756  {
9757  mvcc_reev_class = NULL;
9758  }
9759 
9760  valp = val_list->val;
9761  if (valp == NULL)
9762  {
9764  }
9765  if (DB_IS_NULL (valp))
9766  {
9767  if (class_oid_idx < class_oid_cnt)
9768  {
9769  internal_class = &internal_classes[class_oid_idx];
9770  internal_class->class_oid = NULL;
9771  internal_class->oid = NULL;
9772  }
9773  continue;
9774  }
9775  oid = db_get_oid (valp);
9776 
9777  /* class OID */
9778  valp = val_list->next->val;
9779  if (valp == NULL)
9780  {
9782  }
9783  if (DB_IS_NULL (valp))
9784  {
9785  if (class_oid_idx < class_oid_cnt)
9786  {
9787  internal_classes[class_oid_idx].class_oid = NULL;
9788  }
9789  continue;
9790  }
9791  class_oid = db_get_oid (valp);
9792 
9793  if (class_oid_idx < class_oid_cnt)
9794  {
9795  internal_class = &internal_classes[class_oid_idx];
9796 
9797  internal_class->oid = oid;
9798 
9799  if (class_oid
9800  && (internal_class->class_oid == NULL || !OID_EQ (internal_class->class_oid, class_oid)))
9801  {
9802  query_class = &delete_->classes[class_oid_idx];
9803 
9804  /* find class HFID */
9805  error =
9806  qexec_upddel_setup_current_class (thread_p, query_class, internal_class, op_type, class_oid);
9807  if (error != NO_ERROR)
9808  {
9809  /* matching class oid does not exist... error */
9810  er_log_debug (ARG_FILE_LINE, "qexec_execute_delete: class OID is not correct\n");
9812  }
9813 
9814  if (internal_class->num_lob_attrs)
9815  {
9816  internal_class->crt_del_lob_info =
9817  qexec_change_delete_lob_info (thread_p, xasl_state, internal_class, &del_lob_info_list);
9818  if (internal_class->crt_del_lob_info == NULL)
9819  {
9821  }
9822  }
9823  else
9824  {
9825  internal_class->crt_del_lob_info = NULL;
9826  }
9827  }
9828  }
9829 
9830  if (mvcc_reev_class != NULL)
9831  {
9832  /* class has changed to a new subclass */
9833  if (class_oid && !OID_EQ (&mvcc_reev_class->cls_oid, class_oid))
9834  {
9835  error = qexec_upddel_mvcc_set_filters (thread_p, aptr, mvcc_reev_class, class_oid);
9836  if (error != NO_ERROR)
9837  {
9839  }
9840  }
9841  }
9842  }
9843 
9844  if (mvcc_upddel_reev_data.mvcc_cond_reev_list == NULL)
9845  {
9846  /* If scan order was not set then do it. This operation must be run only once. We do it here and not at
9847  * the beginning of this function because the class OIDs must be set for classes involved in reevaluation
9848  * (in mvcc_reev_classes) prior to this operation */
9849  mvcc_upddel_reev_data.mvcc_cond_reev_list =
9850  qexec_mvcc_cond_reev_set_scan_order (aptr, mvcc_reev_classes, mvcc_reev_class_cnt, delete_->classes,
9851  class_oid_cnt);
9852  }
9853 
9854  for (class_oid_idx = 0, mvcc_reev_class_idx = 0; class_oid_idx < class_oid_cnt; class_oid_idx++)
9855  {
9856  internal_class = &internal_classes[class_oid_idx];
9857  oid = internal_class->oid;
9858  class_oid = internal_class->class_oid;
9859 
9860  if (mvcc_reev_class_cnt && mvcc_reev_classes[mvcc_reev_class_idx].class_index == class_oid_idx)
9861  {
9862  mvcc_reev_class = &mvcc_reev_classes[mvcc_reev_class_idx++];
9863  }
9864  else
9865  {
9866  mvcc_reev_class = NULL;
9867  }
9868  mvcc_upddel_reev_data.curr_upddel = mvcc_reev_class;
9869 
9870  if (oid == NULL)
9871  {
9872  continue;
9873  }
9874 
9875  if (internal_class->crt_del_lob_info)
9876  {
9877  /* delete lob files */
9878  DEL_LOB_INFO *crt_del_lob_info = internal_class->crt_del_lob_info;
9879  SCAN_CODE scan_code;
9880  int error;
9881  int i;
9883 
9884  /* read lob attributes */
9885  scan_code =
9886  heap_get_visible_version (thread_p, oid, class_oid, &recdes, internal_class->scan_cache, PEEK,
9887  NULL_CHN);
9888  if (scan_code == S_ERROR)
9889  {
9891  }
9892  if (scan_code == S_SUCCESS)
9893  {
9894  error = heap_attrinfo_read_dbvalues (thread_p, oid, &recdes, NULL, &crt_del_lob_info->attr_info);
9895  if (error != NO_ERROR)
9896  {
9898  }
9899  for (i = 0; i < internal_class->num_lob_attrs; i++)
9900  {
9901  DB_VALUE *attr_valp = &crt_del_lob_info->attr_info.values[i].dbvalue;
9902  if (!db_value_is_null (attr_valp))
9903  {
9904  DB_ELO *elo;
9905  error = NO_ERROR;
9906 
9907  assert (db_value_type (attr_valp) == DB_TYPE_BLOB
9908  || db_value_type (attr_valp) == DB_TYPE_CLOB);
9909  elo = db_get_elo (attr_valp);
9910  if (elo)
9911  {
9912  error = db_elo_delete (elo);
9913  }
9914  if (error != NO_ERROR)
9915  {
9917  }
9918  }
9919  }
9920  }
9921  }
9922 
9923  force_count = 0;
9924  error =
9925  locator_attribute_info_force (thread_p, internal_class->class_hfid, oid, NULL, NULL, 0, LC_FLUSH_DELETE,
9926  op_type, internal_class->scan_cache, &force_count, false,
9928  &mvcc_reev_data, UPDATE_INPLACE_NONE, NULL, need_locking);
9930  {
9931  error = NO_ERROR;
9932  }
9933  else if (error != NO_ERROR)
9934  {
9936  }
9937  else if (force_count)
9938  {
9939  xasl->list_id->tuple_cnt++;
9940  }
9941  }
9942 
9943  while (val_list)
9944  {
9945  valp = val_list->val;
9946  if (!db_value_is_null (valp))
9947  {
9948  DB_ELO *elo;
9949  int error = NO_ERROR;
9950 
9951  assert (db_value_type (valp) == DB_TYPE_BLOB || db_value_type (valp) == DB_TYPE_CLOB);
9952  elo = db_get_elo (valp);
9953  if (elo)
9954  {
9955  error = db_elo_delete (elo);
9956  }
9957  pr_clear_value (valp);
9958  if (error < NO_ERROR)
9959  {
9961  }
9962  }
9963 
9964  val_list = val_list->next;
9965  }
9966  }
9967  if (ls_scan != S_END)
9968  {
9970  }
9971  }
9972  if (xb_scan != S_END)
9973  {
9975  }
9976 
9977  /* reflect local statistical information into transaction's statistical information */
9978  for (s = 0; s < class_oid_cnt; s++)
9979  {
9980  internal_class = internal_classes + s;
9981  query_class = delete_->classes + s;
9982  if (internal_classes[s].needs_pruning)
9983  {
9984  error = qexec_process_partition_unique_stats (thread_p, &internal_class->context);
9985  }
9986  else
9987  {
9988  error = qexec_process_unique_stats (thread_p, query_class->class_oid, internal_class);
9989  }
9990  if (error != NO_ERROR)
9991  {
9993  }
9994  }
9995 
9996  qexec_close_scan (thread_p, specp);
9997 
9998  qexec_free_delete_lob_info_list (thread_p, &del_lob_info_list);
9999 
10000  if (internal_classes)
10001  {
10002  qexec_clear_internal_classes (thread_p, internal_classes, class_oid_cnt);
10003  db_private_free_and_init (thread_p, internal_classes);
10004  }
10005 
10006  if (mvcc_reev_classes != NULL)
10007  {
10008  db_private_free (thread_p, mvcc_reev_classes);
10009  mvcc_reev_classes = NULL;
10010  }
10011  if (mvcc_upddel_reev_data.copyarea != NULL)
10012  {
10013  locator_free_copy_area (mvcc_upddel_reev_data.copyarea);
10014  mvcc_upddel_reev_data.copyarea = NULL;
10015  }
10016 
10017  if (savepoint_used)
10018  {
10020  {
10021  qexec_failure_line (__LINE__, xasl_state);
10022  return ER_FAILED;
10023  }
10024  }
10025 
10026 #if 0 /* yaw */
10027  /* remove query result cache entries which are relevant with this class */
10028  class_oid = XASL_DELETE_CLASS_OID (xasl);
10029  if (!QFILE_IS_LIST_CACHE_DISABLED && class_oid)
10030  {
10031  for (s = 0; s < XASL_DELETE_NO_CLASSES (xasl); s++, class_oid++)
10032  {
10033  if (qexec_clear_list_cache_by_class (class_oid) != NO_ERROR)
10034  {
10036  "qexec_execute_delete: qexec_clear_list_cache_by_class failed for class { %d %d %d }\n",
10037  class_oid->pageid, class_oid->slotid, class_oid->volid);
10038  }
10039  }
10040  qmgr_add_modified_class (class_oid);
10041  }
10042 #endif
10043 
10044  return NO_ERROR;
10045 
10046 exit_on_error:
10047  if (scan_open)
10048  {
10049  qexec_end_scan (thread_p, specp);
10050  qexec_close_scan (thread_p, specp);
10051  }
10052 
10053  if (del_lob_info_list != NULL)
10054  {
10055  qexec_free_delete_lob_info_list (thread_p, &del_lob_info_list);
10056  }
10057 
10058  if (internal_classes)
10059  {
10060  qexec_clear_internal_classes (thread_p, internal_classes, class_oid_cnt);
10061  db_private_free_and_init (thread_p, internal_classes);
10062  }
10063 
10064  if (mvcc_reev_classes != NULL)
10065  {
10066  db_private_free (thread_p, mvcc_reev_classes);
10067  mvcc_reev_classes = NULL;
10068  }
10069  if (mvcc_upddel_reev_data.copyarea != NULL)
10070  {
10071  locator_free_copy_area (mvcc_upddel_reev_data.copyarea);
10072  mvcc_upddel_reev_data.copyarea = NULL;
10073  }
10074 
10075  if (savepoint_used)
10076  {
10078  }
10079 
10080  return ER_FAILED;
10081 }
10082 
10083 /*
10084  * qexec_create_delete_lob_info () - creates a new DEL_LOB_INFO object using
10085  * data from class_info
10086  *
10087  * thread_p (in) :
10088  * xasl_state (in) :
10089  * class_info (in) :
10090  *
10091  * return : new DEL_LOB_INFO object
10092  */
10093 static DEL_LOB_INFO *
10095 {
10097 
10098  del_lob_info = (DEL_LOB_INFO *) db_private_alloc (thread_p, sizeof (DEL_LOB_INFO));
10099  if (!del_lob_info)
10100  {
10101  qexec_failure_line (__LINE__, xasl_state);
10102  goto error;
10103  }
10104 
10105  del_lob_info->class_oid = class_info->class_oid;
10106  del_lob_info->class_hfid = class_info->class_hfid;
10107 
10108  if (heap_attrinfo_start (thread_p, class_info->class_oid, class_info->num_lob_attrs, class_info->lob_attr_ids,
10109  &del_lob_info->attr_info) != NO_ERROR)
10110  {
10111  goto error;
10112  }
10113 
10114  del_lob_info->next = NULL;
10115 
10116  return del_lob_info;
10117 
10118 error:
10119  if (del_lob_info)
10120  {
10121  db_private_free (thread_p, del_lob_info);
10122  }
10123  return NULL;
10124 }
10125 
10126 /*
10127  * qexec_change_delete_lob_info () - When the class_oid of the tuple that
10128  * needs to be deleted changes, also the current DEL_LOB_INFO
10129  * needs to be changed. This can also be used to initialize
10130  * the list
10131  *
10132  * thread_p (in) :
10133  * xasl_state (in) :
10134  * class_info (in) :
10135  * del_lob_info_list_ptr : pointer to current list of DEL_LOB_INFO
10136  *
10137  * return : DEL_LOB_INFO object specific to current class_info
10138  */
10139 static DEL_LOB_INFO *
10141  DEL_LOB_INFO ** del_lob_info_list_ptr)
10142 {
10143  DEL_LOB_INFO *del_lob_info_list = *del_lob_info_list_ptr;
10145 
10146  assert (del_lob_info_list_ptr != NULL);
10147  del_lob_info_list = *del_lob_info_list_ptr;
10148 
10149  if (del_lob_info_list == NULL)
10150  {
10151  /* create new DEL_LOB_INFO */
10152  del_lob_info_list = qexec_create_delete_lob_info (thread_p, xasl_state, class_info);
10153  *del_lob_info_list_ptr = del_lob_info_list;
10154  return del_lob_info_list;
10155  }
10156 
10157  /* verify if a DEL_LOB_INFO for current class_oid already exists */
10158  for (del_lob_info = del_lob_info_list; del_lob_info; del_lob_info = del_lob_info->next)
10159  {
10160  if (del_lob_info->class_oid == class_info->class_oid)
10161  {
10162  /* found */
10163  return del_lob_info;
10164  }
10165  }
10166 
10167  /* create a new DEL_LOB_INFO */
10168  del_lob_info = qexec_create_delete_lob_info (thread_p, xasl_state, class_info);
10169  if (!del_lob_info)
10170  {
10171  return NULL;
10172  }
10173  del_lob_info->next = del_lob_info_list;
10174  del_lob_info_list = del_lob_info;
10175  *del_lob_info_list_ptr = del_lob_info_list;
10176 
10177  return del_lob_info_list;
10178 }
10179 
10180 /*
10181  * qexec_free_delete_lob_info_list () - frees the list of DEL_LOB_INFO
10182  * created for deleting lob files.
10183  *
10184  * thread_p (in) :
10185  * del_lob_info_list_ptr : pointer to the list of DEL_LOB_INFO structures
10186  *
10187  * NOTE: also all HEAP_CACHE_ATTRINFO must be ended
10188  */
10189 static void
10190 qexec_free_delete_lob_info_list (THREAD_ENTRY * thread_p, DEL_LOB_INFO ** del_lob_info_list_ptr)
10191 {
10192  DEL_LOB_INFO *del_lob_info_list;
10193  DEL_LOB_INFO *del_lob_info, *next_del_lob_info;
10194 
10195  if (!del_lob_info_list_ptr)
10196  {
10197  /* invalid pointer, nothing to free */
10198  return;
10199  }
10200 
10201  del_lob_info_list = *del_lob_info_list_ptr;
10202  if (!del_lob_info_list)
10203  {
10204  /* no item in the list, nothing to free */
10205  return;
10206  }
10207 
10208  del_lob_info = del_lob_info_list;
10209  while (del_lob_info)
10210  {
10211  next_del_lob_info = del_lob_info->next;
10212  /* end HEAP_CACHE_ATTRINFO first */
10213  heap_attrinfo_end (thread_p, &del_lob_info->attr_info);
10214 
10215  db_private_free (thread_p, del_lob_info);
10216  del_lob_info = next_del_lob_info;
10217  }
10218  *del_lob_info_list_ptr = NULL;
10219 }
10220 
10221 
10222 /*
10223  * qexec_remove_duplicates_for_replace () - Removes the objects that would
10224  * generate unique index violations when inserting the given attr_info
10225  * (This is used for executing REPLACE statements)
10226  * return: NO_ERROR or ER_code
10227  * scan_cache(in):
10228  * attr_info(in/out): The attribute information that will be inserted
10229  * index_attr_info(in/out):
10230  * idx_info(in):
10231  * op_type (in): operation type
10232  * pruning_type (in): one of DB_NOT_PARTITIONED_CLASS, DB_PARTITIONED_CLASS,
10233  * DB_PARTITION_CLASS
10234  * pcontext (in): pruning context
10235  * removed_count (in/out):
10236  */
10237 static int
10239  HEAP_CACHE_ATTRINFO * attr_info, HEAP_CACHE_ATTRINFO * index_attr_info,
10240  const HEAP_IDX_ELEMENTS_INFO * idx_info, int op_type, int pruning_type,
10241  PRUNING_CONTEXT * pcontext, int *removed_count)
10242 {
10243  LC_COPYAREA *copyarea = NULL;
10244  RECDES new_recdes;
10245  int i = 0;
10246  int error_code = NO_ERROR;
10247  char buf[DBVAL_BUFSIZE + MAX_ALIGNMENT];
10248  char *const aligned_buf = PTR_ALIGN (buf, MAX_ALIGNMENT);
10249  DB_VALUE dbvalue;
10250  DB_VALUE *key_dbvalue = NULL;
10251  int force_count = 0;
10252  OR_INDEX *index = NULL;
10253  OID unique_oid;
10254  OID class_oid, pruned_oid;
10255  BTID btid;
10256  bool is_global_index;
10257  HFID class_hfid, pruned_hfid;
10258  int local_op_type = SINGLE_ROW_DELETE;
10259  HEAP_SCANCACHE *local_scan_cache = NULL;
10260  BTREE_SEARCH r;
10261 
10262  *removed_count = 0;
10263 
10264  db_make_null (&dbvalue);
10265 
10266  if (heap_attrinfo_clear_dbvalues (index_attr_info) != NO_ERROR)
10267  {
10268  goto error_exit;
10269  }
10270 
10271  copyarea = locator_allocate_copy_area_by_attr_info (thread_p, attr_info, NULL, &new_recdes, -1, LOB_FLAG_EXCLUDE_LOB);
10272  if (copyarea == NULL)
10273  {
10274  goto error_exit;
10275  }
10276 
10277  if (idx_info->has_single_col)
10278  {
10279  error_code = heap_attrinfo_read_dbvalues (thread_p, &oid_Null_oid, &new_recdes, NULL, index_attr_info);
10280  if (error_code != NO_ERROR)
10281  {
10282  goto error_exit;
10283  }
10284  }
10285  assert_release (index_attr_info->last_classrepr != NULL);
10286 
10287  HFID_COPY (&class_hfid, &scan_cache->node.hfid);
10288  COPY_OID (&class_oid, &attr_info->class_oid);
10289 
10290  local_scan_cache = scan_cache;
10291  local_op_type = BTREE_IS_MULTI_ROW_OP (op_type) ? MULTI_ROW_DELETE : SINGLE_ROW_DELETE;
10292 
10293  for (i = 0; i < idx_info->num_btids; ++i)
10294  {
10295  is_global_index = false;
10296  index = &(index_attr_info->last_classrepr->indexes[i]);
10297  if (!btree_is_unique_type (index->type))
10298  {
10299  continue;
10300  }
10301 
10303  {
10304  /* Skip for online index in loading phase. */
10305  continue;
10306  }
10307 
10308  COPY_OID (&pruned_oid, &class_oid);
10309  HFID_COPY (&pruned_hfid, &class_hfid);
10310  BTID_COPY (&btid, &index->btid);
10311  key_dbvalue =
10312  heap_attrvalue_get_key (thread_p, i, index_attr_info, &new_recdes, &btid, &dbvalue, aligned_buf, NULL, NULL);
10313  /* TODO: unique with prefix length */
10314  if (key_dbvalue == NULL)
10315  {
10316  goto error_exit;
10317  }
10318 
10319  if (pruning_type != DB_NOT_PARTITIONED_CLASS)
10320  {
10321  if (pcontext == NULL)
10322  {
10323  assert (false);
10324  goto error_exit;
10325  }
10326  error_code = partition_prune_unique_btid (pcontext, key_dbvalue, &pruned_oid, &pruned_hfid, &btid);
10327  if (error_code != NO_ERROR)
10328  {
10329  goto error_exit;
10330  }
10331  }
10332 
10333  OID_SET_NULL (&unique_oid);
10334 
10335  r = xbtree_find_unique (thread_p, &btid, S_DELETE, key_dbvalue, &pruned_oid, &unique_oid, is_global_index);
10336 
10337  if (r == BTREE_KEY_FOUND)
10338  {
10339  if (pruning_type != DB_NOT_PARTITIONED_CLASS)
10340  {
10341  COPY_OID (&attr_info->inst_oid, &unique_oid);
10342  }
10343 
10344  if (pruning_type && BTREE_IS_MULTI_ROW_OP (op_type))
10345  {
10346  /* need to provide appropriate scan_cache to locator_delete_force in order to correctly compute
10347  * statistics */
10348  PRUNING_SCAN_CACHE *pruning_cache;
10349 
10350  pruning_cache =
10351  locator_get_partition_scancache (pcontext, &pruned_oid, &pruned_hfid, local_op_type, false);
10352  if (pruning_cache == NULL)
10353  {
10354  assert (er_errid () != NO_ERROR);
10355 
10356  error_code = er_errid ();
10357  if (error_code == NO_ERROR)
10358  {
10359  error_code = ER_FAILED;
10360  }
10361  goto error_exit;
10362  }
10363 
10364  local_scan_cache = &pruning_cache->scan_cache;
10365  }
10366 
10367  /* last version was already locked and returned by xbtree_find_unique() */
10368  error_code = locator_delete_lob_force (thread_p, &pruned_oid, &unique_oid, NULL);
10369  if (error_code != NO_ERROR)
10370  {
10371  goto error_exit;
10372  }
10373 
10374  force_count = 0;
10375  /* The object was locked during find unique */
10376  error_code =
10377  locator_attribute_info_force (thread_p, &pruned_hfid, &unique_oid, NULL, NULL, 0, LC_FLUSH_DELETE,
10378  local_op_type, local_scan_cache, &force_count, false,
10380  UPDATE_INPLACE_NONE, NULL, false);
10381 
10382  if (error_code == ER_MVCC_NOT_SATISFIED_REEVALUATION)
10383  {
10384  error_code = NO_ERROR;
10385  }
10386  else if (error_code != NO_ERROR)
10387  {
10388  goto error_exit;
10389  }
10390  else if (force_count != 0)
10391  {
10392  assert (force_count == 1);
10393  *removed_count += force_count;
10394  force_count = 0;
10395  }
10396  }
10397  else if (r == BTREE_ERROR_OCCURRED)
10398  {
10399  if (!OID_ISNULL (&unique_oid))
10400  {
10401  /* more than one OID has been found */
10402  BTREE_SET_UNIQUE_VIOLATION_ERROR (thread_p, key_dbvalue, &unique_oid, &class_oid, &btid, NULL);
10403  }
10404  goto error_exit;
10405  }
10406  else
10407  {
10408  /* BTREE_KEY_NOTFOUND */
10409  ; /* just go to the next one */
10410  }
10411 
10412  if (key_dbvalue == &dbvalue)
10413  {
10414  pr_clear_value (&dbvalue);
10415  key_dbvalue = NULL;
10416  }
10417  }
10418 
10419  if (copyarea != NULL)
10420  {
10421  locator_free_copy_area (copyarea);
10422  copyarea = NULL;
10423  new_recdes.data = NULL;
10424  new_recdes.area_size = 0;
10425  }
10426 
10427  return NO_ERROR;
10428 
10429 error_exit:
10430  if (key_dbvalue == &dbvalue)
10431  {
10432  pr_clear_value (&dbvalue);
10433  key_dbvalue = NULL;
10434  }
10435 
10436  if (copyarea != NULL)
10437  {
10438  locator_free_copy_area (copyarea);
10439  copyarea = NULL;
10440  new_recdes.data = NULL;
10441  new_recdes.area_size = 0;
10442  }
10443 
10444  return ER_FAILED;
10445 }
10446 
10447 /*
10448  * qexec_oid_of_duplicate_key_update () - Finds an OID of an object that would
10449  * generate unique index violations when inserting the given attr_info
10450  * (This is used for executing INSERT ON DUPLICATE KEY UPDATE
10451  * statements)
10452  * return: NO_ERROR or ER_code
10453  * thread_p(in):
10454  * pruned_partition_scan_cache(out): the real scan_cache for this oid
10455  * scan_cache(in):
10456  * attr_info(in/out): The attribute information that will be inserted
10457  * index_attr_info(in/out):
10458  * idx_info(in):
10459  * pruning_type(in):
10460  * pcontext(in):
10461  * unique_oid_p(out): the OID of one object to be updated or a NULL OID if
10462  * there are no potential unique index violations
10463  * op_type(int):
10464  * Note: A single OID is returned even if there are several objects that would
10465  * generate unique index violations (this can only happen if there are
10466  * several unique indexes).
10467  */
10468 static int
10469 qexec_oid_of_duplicate_key_update (THREAD_ENTRY * thread_p, HEAP_SCANCACHE ** pruned_partition_scan_cache,
10470  HEAP_SCANCACHE * scan_cache, HEAP_CACHE_ATTRINFO * attr_info,
10471  HEAP_CACHE_ATTRINFO * index_attr_info, const HEAP_IDX_ELEMENTS_INFO * idx_info,
10472  int pruning_type, PRUNING_CONTEXT * pcontext, OID * unique_oid_p, int op_type)
10473 {
10474  LC_COPYAREA *copyarea = NULL;
10475  RECDES recdes;
10476  int i = 0;
10477  int error_code = NO_ERROR;
10478  char buf[DBVAL_BUFSIZE + MAX_ALIGNMENT];
10479  char *const aligned_buf = PTR_ALIGN (buf, MAX_ALIGNMENT);
10480  DB_VALUE dbvalue;
10481  DB_VALUE *key_dbvalue = NULL;
10482  bool found_duplicate = false;
10483  BTID btid;
10484  OR_INDEX *index;
10485  OID unique_oid;
10486  OID class_oid;
10487  HFID class_hfid;
10488  bool is_global_index = false;
10489  int local_op_type = SINGLE_ROW_UPDATE;
10490  BTREE_SEARCH r;
10491 
10492  assert (pruned_partition_scan_cache != NULL);
10493 
10494  db_make_null (&dbvalue);
10495  OID_SET_NULL (unique_oid_p);
10496  OID_SET_NULL (&unique_oid);
10497 
10498  if (BTREE_IS_MULTI_ROW_OP (op_type))
10499  {
10500  local_op_type = MULTI_ROW_UPDATE;
10501  }
10502 
10503  if (heap_attrinfo_clear_dbvalues (index_attr_info) != NO_ERROR)
10504  {
10505  goto error_exit;
10506  }
10507 
10508  copyarea = locator_allocate_copy_area_by_attr_info (thread_p, attr_info, NULL, &recdes, -1, LOB_FLAG_INCLUDE_LOB);
10509  if (copyarea == NULL)
10510  {
10511  goto error_exit;
10512  }
10513 
10514  if (idx_info->has_single_col)
10515  {
10516  error_code = heap_attrinfo_read_dbvalues (thread_p, &oid_Null_oid, &recdes, NULL, index_attr_info);
10517  if (error_code != NO_ERROR)
10518  {
10519  goto error_exit;
10520  }
10521  }
10522  assert (index_attr_info->last_classrepr != NULL);
10523 
10524  for (i = 0; i < idx_info->num_btids && !found_duplicate; ++i)
10525  {
10526  index = &(index_attr_info->last_classrepr->indexes[i]);
10527  if (!btree_is_unique_type (index->type))
10528  {
10529  continue;
10530  }
10531 
10533  {
10534  /* Skip for online index in loading phase. */
10535  continue;
10536  }
10537 
10538  COPY_OID (&class_oid, &attr_info->class_oid);
10539  is_global_index = false;
10540 
10541  key_dbvalue =
10542  heap_attrvalue_get_key (thread_p, i, index_attr_info, &recdes, &btid, &dbvalue, aligned_buf, NULL, NULL);
10543  if (key_dbvalue == NULL)
10544  {
10545  goto error_exit;
10546  }
10547 
10548  if (pruning_type != DB_NOT_PARTITIONED_CLASS)
10549  {
10550  if (pcontext == NULL)
10551  {
10552  assert (false);
10553  goto error_exit;
10554  }
10555 
10556  error_code = partition_prune_unique_btid (pcontext, key_dbvalue, &class_oid, &class_hfid, &btid);
10557  if (error_code != NO_ERROR)
10558  {
10559  goto error_exit;
10560  }
10561  }
10562 
10563  r = xbtree_find_unique (thread_p, &btid, S_UPDATE, key_dbvalue, &class_oid, &unique_oid, is_global_index);
10564 
10565  if (r == BTREE_KEY_FOUND)
10566  {
10567  if (pruning_type != DB_NOT_PARTITIONED_CLASS)
10568  {
10569  COPY_OID (&attr_info->inst_oid, &unique_oid);
10570  }
10571 
10572  if (pruning_type != DB_NOT_PARTITIONED_CLASS && BTREE_IS_MULTI_ROW_OP (op_type))
10573  {
10574  /* need to provide appropriate scan_cache to locator_delete_force in order to correctly compute
10575  * statistics */
10576  PRUNING_SCAN_CACHE *pruning_cache;
10577 
10578  pruning_cache = locator_get_partition_scancache (pcontext, &class_oid, &class_hfid, local_op_type, false);
10579  if (pruning_cache == NULL)
10580  {
10581  assert (er_errid () != NO_ERROR);
10582 
10583  error_code = er_errid ();
10584  if (error_code == NO_ERROR)
10585  {
10586  error_code = ER_FAILED;
10587  }
10588  goto error_exit;
10589  }
10590 
10591  *pruned_partition_scan_cache = &pruning_cache->scan_cache;
10592  }
10593 
10594  /* We now hold an U_LOCK on the instance. It will be upgraded to an X_LOCK when the update is executed. */
10595  if (pruning_type == DB_PARTITION_CLASS)
10596  {
10597  if (!OID_EQ (&class_oid, &pcontext->selected_partition->class_oid))
10598  {
10599  /* found a duplicate OID but not in the right partition */
10601  goto error_exit;
10602  }
10603  }
10604 
10605  found_duplicate = true;
10606  COPY_OID (unique_oid_p, &unique_oid);
10607  }
10608  else if (r == BTREE_ERROR_OCCURRED)
10609  {
10610  if (!OID_ISNULL (&unique_oid))
10611  {
10612  /* more than one OID has been found */
10613  BTREE_SET_UNIQUE_VIOLATION_ERROR (thread_p, key_dbvalue, &unique_oid, &class_oid, &btid, NULL);
10614  }
10615  goto error_exit;
10616  }
10617  else
10618  {
10619  /* BTREE_KEY_NOTFOUND */
10620  ; /* just go to the next one */
10621  }
10622 
10623  if (key_dbvalue == &dbvalue)
10624  {
10625  pr_clear_value (&dbvalue);
10626  key_dbvalue = NULL;
10627  }
10628  }
10629 
10630  if (copyarea != NULL)
10631  {
10632  locator_free_copy_area (copyarea);
10633  copyarea = NULL;
10634  recdes.data = NULL;
10635  recdes.area_size = 0;
10636  }
10637 
10638  return NO_ERROR;
10639 
10640 error_exit:
10641  if (key_dbvalue == &dbvalue)
10642  {
10643  pr_clear_value (&dbvalue);
10644  key_dbvalue = NULL;
10645  }
10646 
10647  if (copyarea != NULL)
10648  {
10649  locator_free_copy_area (copyarea);
10650  copyarea = NULL;
10651  recdes.data = NULL;
10652  recdes.area_size = 0;
10653  }
10654 
10655  return ER_FAILED;
10656 }
10657 
10658 /*
10659  * qexec_execute_duplicate_key_update () - Executes an update on a given OID
10660  * (required by INSERT ON DUPLICATE KEY UPDATE processing)
10661  * return: NO_ERROR or ER_code
10662  * thread_p(in) :
10663  * odku(in) : on duplicate key update clause info
10664  * hfid(in) : class HFID
10665  * vd(in) : values descriptor
10666  * op_type(in): operation type
10667  * scan_cache(in): scan cache
10668  * attr_info(in): attribute cache info
10669  * index_attr_info(in): attribute info cache for indexes
10670  * idx_info(in): index info
10671  * pruning_type(in): pruning type
10672  * pcontext(in): pruning context
10673  * force_count(out): the number of objects that have been updated; it should
10674  * always be 1 on success and 0 on error
10675  */
10676 static int
10678  HEAP_SCANCACHE * scan_cache, HEAP_CACHE_ATTRINFO * attr_info,
10679  HEAP_CACHE_ATTRINFO * index_attr_info, HEAP_IDX_ELEMENTS_INFO * idx_info,
10680  int pruning_type, PRUNING_CONTEXT * pcontext, int *force_count)
10681 {
10682  int satisfies_constraints;
10683  int assign_idx;
10684  UPDATE_ASSIGNMENT *assign;
10685  RECDES rec_descriptor = { 0, -1, REC_HOME, NULL };
10686  SCAN_CODE scan_code;
10687  DB_VALUE *val = NULL;
10689  int error = NO_ERROR;
10690  bool need_clear = 0;
10691  OID unique_oid;
10692  int local_op_type = SINGLE_ROW_UPDATE;
10693  HEAP_SCANCACHE *local_scan_cache = NULL;
10694  int ispeeking;
10695 
10696  OID_SET_NULL (&unique_oid);
10697 
10698  local_scan_cache = scan_cache;
10699 
10700  error =
10701  qexec_oid_of_duplicate_key_update (thread_p, &local_scan_cache, scan_cache, attr_info, index_attr_info, idx_info,
10702  pruning_type, pcontext, &unique_oid, op_type);
10703  if (error != NO_ERROR)
10704  {
10705  ASSERT_ERROR ();
10706  goto exit_on_error;
10707  }
10708 
10709  if (OID_ISNULL (&unique_oid))
10710  {
10711  *force_count = 0;
10712  return NO_ERROR;
10713  }
10714 
10715  /* get attribute values */
10716  ispeeking = ((local_scan_cache != NULL && local_scan_cache->cache_last_fix_page) ? PEEK : COPY);
10717 
10718  scan_code =
10719  heap_get_visible_version (thread_p, &unique_oid, NULL, &rec_descriptor, local_scan_cache, ispeeking, NULL_CHN);
10720  if (scan_code != S_SUCCESS)
10721  {
10722  assert (er_errid () == ER_INTERRUPTED);
10723  error = ER_FAILED;
10724  goto exit_on_error;
10725  }
10726 
10727  /* setup operation type and handle partition representation id */
10728  if (pruning_type == DB_PARTITIONED_CLASS)
10729  {
10730  /* modify rec_descriptor representation id to that of attr_info */
10731  assert (OID_EQ (&attr_info->class_oid, &pcontext->root_oid));
10732 
10733  if (OID_ISNULL (&attr_info->inst_oid))
10734  {
10735  or_set_rep_id (&rec_descriptor, pcontext->root_repr_id);
10736  }
10737 
10738  local_op_type = (BTREE_IS_MULTI_ROW_OP (op_type) ? MULTI_ROW_UPDATE : SINGLE_ROW_UPDATE);
10739  }
10740 
10741  error = heap_attrinfo_read_dbvalues (thread_p, &unique_oid, &rec_descriptor, local_scan_cache, odku->attr_info);
10742  if (error != NO_ERROR)
10743  {
10744  ASSERT_ERROR ();
10745  goto exit_on_error;
10746  }
10747 
10748  need_clear = true;
10749 
10750  /* evaluate constraint predicate */
10751  satisfies_constraints = V_UNKNOWN;
10752  if (odku->cons_pred != NULL)
10753  {
10754  satisfies_constraints = eval_pred (thread_p, odku->cons_pred, vd, NULL);
10755  if (satisfies_constraints == V_ERROR)
10756  {
10757  ASSERT_ERROR_AND_SET (error);
10758  goto exit_on_error;
10759  }
10760 
10761  if (satisfies_constraints != V_TRUE)
10762  {
10763  /* currently there are only NOT NULL constraints */
10766  goto exit_on_error;
10767  }
10768  }
10769 
10770  /* set values for object */
10771  heap_attrinfo_clear_dbvalues (attr_info);
10772  for (assign_idx = 0; assign_idx < odku->num_assigns && error == NO_ERROR; assign_idx++)
10773  {
10774  assign = &odku->assignments[assign_idx];
10775  if (assign->constant)
10776  {
10777  error = heap_attrinfo_set (&unique_oid, odku->attr_ids[assign_idx], assign->constant, attr_info);
10778  if (error != NO_ERROR)
10779  {
10780  ASSERT_ERROR ();
10781  goto exit_on_error;
10782  }
10783  }
10784  else
10785  {
10786  assert_release (assign->regu_var != NULL);
10787  error = fetch_peek_dbval (thread_p, assign->regu_var, vd, NULL, NULL, NULL, &val);
10788  if (error != NO_ERROR)
10789  {
10790  ASSERT_ERROR ();
10791  goto exit_on_error;
10792  }
10793 
10794  error = heap_attrinfo_set (&unique_oid, odku->attr_ids[assign_idx], val, attr_info);
10795  if (error != NO_ERROR)
10796  {
10797  ASSERT_ERROR ();
10798  goto exit_on_error;
10799  }
10800  }
10801  }
10802 
10803  /* unique_oid already locked in qexec_oid_of_duplicate_key_update */
10804  error =
10805  locator_attribute_info_force (thread_p, hfid, &unique_oid, attr_info, odku->attr_ids, odku->num_assigns,
10806  LC_FLUSH_UPDATE, local_op_type, local_scan_cache, force_count, false, repl_info,
10807  pruning_type, pcontext, NULL, NULL, UPDATE_INPLACE_NONE, &rec_descriptor, false);
10809  {
10810  er_clear ();
10811  error = NO_ERROR;
10812  }
10813  else if (error != NO_ERROR)
10814  {
10815  ASSERT_ERROR ();
10816  goto exit_on_error;
10817  }
10818 
10819  heap_attrinfo_clear_dbvalues (attr_info);
10821 
10822  return error;
10823 
10824 exit_on_error:
10825 
10826  if (need_clear)
10827  {
10829  }
10830 
10831  assert (error != NO_ERROR);
10832 
10833  return error;
10834 }
10835 
10836 static int
10837 qexec_get_attr_default (THREAD_ENTRY * thread_p, OR_ATTRIBUTE * attr, DB_VALUE * default_val)
10838 {
10839  assert (attr != NULL && default_val != NULL);
10840 
10841  OR_BUF buf;
10842  PR_TYPE *pr_type = pr_type_from_id (attr->type);
10843  bool copy = (pr_is_set_type (attr->type)) ? true : false;
10844  if (pr_type != NULL)
10845  {
10846  or_init (&buf, (char *) attr->current_default_value.value, attr->current_default_value.val_length);
10847  buf.error_abort = 1;
10848  switch (_setjmp (buf.env))
10849  {
10850  case 0:
10851  return pr_type->data_readval (&buf, default_val, attr->domain, attr->current_default_value.val_length, copy,
10852  NULL, 0);
10853  default:
10854  return ER_FAILED;
10855  }
10856  }
10857  else
10858  {
10859  db_make_null (default_val);
10860  }
10861  return NO_ERROR;
10862 }
10863 
10864 /*
10865  * qexec_execute_insert () -
10866  * return: NO_ERROR or ER_code
10867  * xasl(in) : XASL Tree block
10868  * xasl_state(in) :
10869  */
10870 static int
10871 qexec_execute_insert (THREAD_ENTRY * thread_p, XASL_NODE * xasl, XASL_STATE * xasl_state, bool skip_aptr)
10872 {
10873  INSERT_PROC_NODE *insert = &xasl->proc.insert;
10874  SCAN_CODE xb_scan;
10875  SCAN_CODE ls_scan;
10876  XASL_NODE *aptr = NULL;
10877  DB_VALUE *valp = NULL;
10878  QPROC_DB_VALUE_LIST vallist;
10879  int i, k;
10880  int val_no;
10881  int rc;
10882  OID oid;
10883  OID class_oid;
10884  HFID class_hfid;
10885  ACCESS_SPEC_TYPE *specp = NULL;
10886  SCAN_ID *s_id = NULL;
10887  HEAP_CACHE_ATTRINFO attr_info;
10888  HEAP_CACHE_ATTRINFO index_attr_info;
10889  HEAP_IDX_ELEMENTS_INFO idx_info;
10890  bool attr_info_inited = false;
10891  volatile bool index_attr_info_inited = false;
10892  volatile bool odku_attr_info_inited = false;
10893  LOG_LSA lsa;
10894  int savepoint_used = 0;
10895  int satisfies_constraints;
10896  HEAP_SCANCACHE scan_cache;
10897  bool scan_cache_inited = false;
10898  int scan_cache_op_type = 0;
10899  int force_count = 0;
10900  int num_default_expr = 0;
10902  PRUNING_CONTEXT context, *volatile pcontext = NULL;
10903  FUNC_PRED_UNPACK_INFO *func_indx_preds = NULL;
10904  volatile int n_indexes = 0;
10905  int error = 0;
10906  ODKU_INFO *odku_assignments = insert->odku;
10907  DB_VALUE oid_val;
10908  int is_autoincrement_set = 0;
10909  int month, day, year, hour, minute, second, millisecond;
10910  DB_VALUE insert_val, format_val, lang_val;
10911  char *lang_str = NULL;
10912  int flag;
10913  TP_DOMAIN *result_domain;
10914  bool has_user_format;
10915 
10916  thread_p->no_logging = (bool) insert->no_logging;
10917 
10918  aptr = xasl->aptr_list;
10919  val_no = insert->num_vals;
10920 
10921  if (!skip_aptr)
10922  {
10923  if (aptr && qexec_execute_mainblock (thread_p, aptr, xasl_state, NULL) != NO_ERROR)
10924  {
10925  qexec_failure_line (__LINE__, xasl_state);
10926  return ER_FAILED;
10927  }
10928  }
10929 
10930  if (XASL_IS_FLAGED (xasl, XASL_RETURN_GENERATED_KEYS) && xasl->list_id)
10931  {
10932  xasl->list_id->query_id = xasl_state->query_id;
10933  }
10934 
10935  /* This guarantees that the result list file will have a type list. Copying a list_id structure fails unless it has a
10936  * type list. */
10937  if (qexec_setup_list_id (thread_p, xasl) != NO_ERROR)
10938  {
10939  qexec_failure_line (__LINE__, xasl_state);
10940  return ER_FAILED;
10941  }
10942 
10943  /* We might not hold a strong enough lock on the class yet. */
10945  {
10946  assert (er_errid () != NO_ERROR);
10947  error = er_errid ();
10948  if (error != NO_ERROR)
10949  {
10950  error = ER_FAILED;
10951  }
10952  qexec_failure_line (__LINE__, xasl_state);
10953  return error;
10954  }
10955 
10956  /* need to start a topop to ensure statement atomicity. One insert statement might update several disk images. For
10957  * example, one row insert might update one heap record, zero or more index keys, catalog info of object count, and
10958  * other things. So, the insert statement must be performed atomically. */
10959  if (xtran_server_start_topop (thread_p, &lsa) != NO_ERROR)
10960  {
10961  qexec_failure_line (__LINE__, xasl_state);
10962  return ER_FAILED;
10963  }
10964  savepoint_used = 1;
10965 
10966  (void) session_begin_insert_values (thread_p);
10967 
10968  COPY_OID (&class_oid, &insert->class_oid);
10969  HFID_COPY (&class_hfid, &insert->class_hfid);
10970  if (insert->pruning_type != DB_NOT_PARTITIONED_CLASS)
10971  {
10972  /* initialize the pruning context here */
10973  pcontext = &context;
10974  partition_init_pruning_context (pcontext);
10975  error = partition_load_pruning_context (thread_p, &insert->class_oid, insert->pruning_type, pcontext);
10976  if (error != NO_ERROR)
10977  {
10979  }
10980  }
10981 
10982  if (insert->has_uniques && (insert->do_replace || odku_assignments != NULL))
10983  {
10984  if (heap_attrinfo_start_with_index (thread_p, &class_oid, NULL, &index_attr_info, &idx_info) < 0)
10985  {
10987  }
10988  index_attr_info_inited = true;
10989  if (odku_assignments != NULL)
10990  {
10991  error = heap_attrinfo_start (thread_p, &insert->class_oid, -1, NULL, odku_assignments->attr_info);
10992  if (error != NO_ERROR)
10993  {
10995  }
10996  odku_attr_info_inited = true;
10997  }
10998  }
10999 
11000  if (heap_attrinfo_start (thread_p, &class_oid, -1, NULL, &attr_info) != NO_ERROR)
11001  {
11003  }
11004  attr_info_inited = true;
11005  n_indexes = attr_info.last_classrepr->n_indexes;
11006 
11007  /* first values should be the results of default expressions */
11008  num_default_expr = insert->num_default_expr;
11009  if (num_default_expr < 0)
11010  {
11011  num_default_expr = 0;
11012  }
11013 
11014  db_make_null (&insert_val);
11015  for (k = 0; k < num_default_expr; k++)
11016  {
11017  OR_ATTRIBUTE *attr;
11018  DB_VALUE *new_val;
11019  int error = NO_ERROR;
11021 
11022  attr = heap_locate_last_attrepr (insert->att_id[k], &attr_info);
11023  if (attr == NULL)
11024  {
11026  }
11027  new_val = (DB_VALUE *) db_private_alloc (thread_p, sizeof (DB_VALUE));
11028  if (new_val == NULL)
11029  {
11031  }
11032  db_make_null (new_val);
11033  insert->vals[k] = new_val;
11034 
11036  {
11037  case DB_DEFAULT_SYSTIME:
11038  db_datetime_decode (&xasl_state->vd.sys_datetime, &month, &day, &year, &hour, &minute, &second, &millisecond);
11039  db_make_time (&insert_val, hour, minute, second);
11040  break;
11041 
11043  {
11044  DB_TIME cur_time, db_time;
11045  const char *t_source, *t_dest;
11046  int len_source, len_dest;
11047 
11048  t_source = tz_get_system_timezone ();
11049  t_dest = tz_get_session_local_timezone ();
11050  len_source = (int) strlen (t_source);
11051  len_dest = (int) strlen (t_dest);
11052  db_time = xasl_state->vd.sys_datetime.time / 1000;
11053  error = tz_conv_tz_time_w_zone_name (&db_time, t_source, len_source, t_dest, len_dest, &cur_time);
11054  db_value_put_encoded_time (&insert_val, &cur_time);
11055  }
11056  break;
11057 
11058  case DB_DEFAULT_SYSDATE:
11059  db_datetime_decode (&xasl_state->vd.sys_datetime, &month, &day, &year, &hour, &minute, &second, &millisecond);
11060  db_make_date (&insert_val, month, day, year);
11061  break;
11062 
11064  {
11065  TZ_REGION system_tz_region, session_tz_region;
11066  DB_DATETIME dest_dt;
11067 
11068  tz_get_system_tz_region (&system_tz_region);
11069  tz_get_session_tz_region (&session_tz_region);
11070  error =
11071  tz_conv_tz_datetime_w_region (&xasl_state->vd.sys_datetime, &system_tz_region, &session_tz_region,
11072  &dest_dt, NULL, NULL);
11073  db_value_put_encoded_date (&insert_val, &dest_dt.date);
11074  }
11075  break;
11076 
11078  db_make_datetime (&insert_val, &xasl_state->vd.sys_datetime);
11079  break;
11080 
11082  db_make_datetime (&insert_val, &xasl_state->vd.sys_datetime);
11083  error = db_datetime_to_timestamp (&insert_val, &insert_val);
11084  break;
11085 
11087  {
11088  TZ_REGION system_tz_region, session_tz_region;
11089  DB_DATETIME dest_dt;
11090 
11091  tz_get_system_tz_region (&system_tz_region);
11092  tz_get_session_tz_region (&session_tz_region);
11093  error =
11094  tz_conv_tz_datetime_w_region (&xasl_state->vd.sys_datetime, &system_tz_region, &session_tz_region,
11095  &dest_dt, NULL, NULL);
11096  db_make_datetime (&insert_val, &dest_dt);
11097  }
11098  break;
11099 
11101  {
11102  DB_DATE tmp_date;
11103  DB_TIME tmp_time;
11104  DB_TIMESTAMP tmp_timestamp;
11105 
11106  tmp_date = xasl_state->vd.sys_datetime.date;
11107  tmp_time = xasl_state->vd.sys_datetime.time / 1000;
11108  db_timestamp_encode_sys (&tmp_date, &tmp_time, &tmp_timestamp, NULL);
11109  db_make_timestamp (&insert_val, tmp_timestamp);
11110  }
11111  break;
11112 
11114  db_make_datetime (&insert_val, &xasl_state->vd.sys_datetime);
11115  error = db_unix_timestamp (&insert_val, &insert_val);
11116  break;
11117 
11118  case DB_DEFAULT_USER:
11119  {
11120  int tran_index = LOG_FIND_THREAD_TRAN_INDEX (thread_p);
11121  LOG_TDES *tdes = NULL;
11122  char *temp = NULL;
11123 
11124  tdes = LOG_FIND_TDES (tran_index);
11125  if (tdes)
11126  {
11127  size_t len = tdes->client.db_user.length () + tdes->client.host_name.length () + 2;
11128  temp = (char *) db_private_alloc (thread_p, len);
11129  if (temp == NULL)
11130  {
11133  }
11134  else
11135  {
11136  strcpy (temp, tdes->client.get_db_user ());
11137  strcat (temp, "@");
11138  strcat (temp, tdes->client.get_host_name ());
11139  }
11140  }
11141 
11142  db_make_string (&insert_val, temp);
11143  insert_val.need_clear = true;
11144  }
11145  break;
11146 
11147  case DB_DEFAULT_CURR_USER:
11148  {
11149  int tran_index = LOG_FIND_THREAD_TRAN_INDEX (thread_p);
11150  LOG_TDES *tdes = NULL;
11151  char *temp = NULL;
11152 
11153  tdes = LOG_FIND_TDES (tran_index);
11154  if (tdes != NULL)
11155  {
11156  temp = CONST_CAST (char *, tdes->client.get_db_user ()); // will not be modified
11157  }
11158  db_make_string (&insert_val, temp);
11159  }
11160  break;
11161 
11162  case DB_DEFAULT_NONE:
11163  if (attr->current_default_value.val_length <= 0)
11164  {
11165  /* leave default value as NULL */
11166  break;
11167  }
11168  else
11169  {
11170  error = qexec_get_attr_default (thread_p, attr, &insert_val);
11171  if (error != NO_ERROR)
11172  {
11174  }
11175  }
11176  break;
11177 
11178  default:
11179  assert (0);
11180  error = ER_FAILED;
11182  break;
11183  }
11184 
11186  {
11189  {
11191  has_user_format = 1;
11192  }
11193  else
11194  {
11195  db_make_null (&format_val);
11196  has_user_format = 0;
11197  }
11198 
11200  lang_set_flag_from_lang (lang_str, has_user_format, 0, &flag);
11201  db_make_int (&lang_val, flag);
11202 
11203  if (!TP_IS_CHAR_TYPE (TP_DOMAIN_TYPE (attr->domain)))
11204  {
11205  /* TO_CHAR returns a string value, we need to pass an expected domain of the result */
11206  if (TP_IS_CHAR_TYPE (DB_VALUE_TYPE (&insert_val)))
11207  {
11208  result_domain = NULL;
11209  }
11210  else if (DB_IS_NULL (&format_val))
11211  {
11212  result_domain = tp_domain_resolve_default (DB_TYPE_STRING);
11213  }
11214  else
11215  {
11216  result_domain = tp_domain_resolve_value (&format_val, NULL);
11217  }
11218  }
11219  else
11220  {
11221  result_domain = attr->domain;
11222  }
11223 
11224  error = db_to_char (&insert_val, &format_val, &lang_val, insert->vals[k], result_domain);
11225 
11226  if (has_user_format)
11227  {
11228  pr_clear_value (&format_val);
11229  }
11230  }
11231  else
11232  {
11233  pr_clone_value (&insert_val, insert->vals[k]);
11234  }
11235 
11236  pr_clear_value (&insert_val);
11237 
11238  if (error != NO_ERROR)
11239  {
11241  }
11242 
11244  {
11245  /* skip the value cast */
11246  continue;
11247  }
11248 
11249  status = tp_value_cast (insert->vals[k], insert->vals[k], attr->domain, false);
11250  if (status != DOMAIN_COMPATIBLE)
11251  {
11252  (void) tp_domain_status_er_set (status, ARG_FILE_LINE, insert->vals[k], attr->domain);
11254  }
11255  }
11256 
11257  specp = xasl->spec_list;
11258  if (specp != NULL || ((insert->do_replace || (xasl->dptr_list != NULL)) && insert->has_uniques)
11259  || insert->num_val_lists > 1)
11260  {
11261  scan_cache_op_type = MULTI_ROW_INSERT;
11262  }
11263  else
11264  {
11265  scan_cache_op_type = SINGLE_ROW_INSERT;
11266  }
11267 
11268  if (specp)
11269  {
11270  /* we are inserting multiple values ... ie. insert into foo select ... */
11271 
11272  /* if the class has at least one function index, the function expressions will be cached */
11273  if (heap_init_func_pred_unpack_info (thread_p, &attr_info, &class_oid, &func_indx_preds) != NO_ERROR)
11274  {
11276  }
11277 
11278  if (locator_start_force_scan_cache (thread_p, &scan_cache, &insert->class_hfid, &class_oid,
11279  scan_cache_op_type) != NO_ERROR)
11280  {
11282  }
11283  scan_cache_inited = true;
11284 
11285  assert (xasl->scan_op_type == S_SELECT);
11286 
11287  /* force_select_lock = false */
11288  if (qexec_open_scan (thread_p, specp, xasl->val_list, &xasl_state->vd, false, specp->fixed_scan,
11289  specp->grouped_scan, true, &specp->s_id, xasl_state->query_id, S_SELECT, false,
11290  NULL) != NO_ERROR)
11291  {
11292  if (savepoint_used)
11293  {
11295  }
11296  qexec_failure_line (__LINE__, xasl_state);
11298  }
11299 
11300  while ((xb_scan = qexec_next_scan_block_iterations (thread_p, xasl)) == S_SUCCESS)
11301  {
11302  s_id = &xasl->curr_spec->s_id;
11303  while ((ls_scan = scan_next_scan (thread_p, s_id)) == S_SUCCESS)
11304  {
11305  for (k = num_default_expr, vallist = s_id->val_list->valp; k < val_no; k++, vallist = vallist->next)
11306  {
11307  if (vallist == NULL || vallist->val == NULL)
11308  {
11309  assert (0);
11311  }
11312 
11313  insert->vals[k] = vallist->val;
11314  }
11315 
11316  /* evaluate constraint predicate */
11317  satisfies_constraints = V_UNKNOWN;
11318  if (insert->cons_pred != NULL)
11319  {
11320  satisfies_constraints = eval_pred (thread_p, insert->cons_pred, &xasl_state->vd, NULL);
11321  if (satisfies_constraints == V_ERROR)
11322  {
11324  }
11325  }
11326 
11327  if (insert->cons_pred != NULL && satisfies_constraints != V_TRUE)
11328  {
11329  /* currently there are only NOT NULL constraints */
11332  }
11333 
11334  if (heap_attrinfo_clear_dbvalues (&attr_info) != NO_ERROR)
11335  {
11337  }
11338  for (k = 0; k < val_no; ++k)
11339  {
11340  if (DB_IS_NULL (insert->vals[k]))
11341  {
11342  OR_ATTRIBUTE *attr = heap_locate_last_attrepr (insert->att_id[k], &attr_info);
11343 
11344  if (attr == NULL)
11345  {
11347  }
11348 
11349  if (attr->is_autoincrement)
11350  {
11351  continue;
11352  }
11353  }
11354 
11355 
11356  rc = heap_attrinfo_set (NULL, insert->att_id[k], insert->vals[k], &attr_info);
11357  if (rc != NO_ERROR)
11358  {
11360  }
11361  }
11362 
11363  if (heap_set_autoincrement_value (thread_p, &attr_info, &scan_cache, &is_autoincrement_set) != NO_ERROR)
11364  {
11366  }
11367 
11368  if (insert->do_replace && insert->has_uniques)
11369  {
11370  int removed_count = 0;
11371 
11372  assert (index_attr_info_inited == true);
11373 
11374  if (qexec_remove_duplicates_for_replace (thread_p, &scan_cache, &attr_info, &index_attr_info,
11375  &idx_info, scan_cache_op_type, insert->pruning_type,
11376  pcontext, &removed_count) != NO_ERROR)
11377  {
11379  }
11380  xasl->list_id->tuple_cnt += removed_count;
11381  }
11382 
11383  if (odku_assignments && insert->has_uniques)
11384  {
11385  force_count = 0;
11386  error =
11387  qexec_execute_duplicate_key_update (thread_p, insert->odku, &insert->class_hfid, &xasl_state->vd,
11388  scan_cache_op_type, &scan_cache, &attr_info, &index_attr_info,
11389  &idx_info, insert->pruning_type, pcontext, &force_count);
11390  if (error != NO_ERROR)
11391  {
11393  }
11394 
11395  if (force_count != 0)
11396  {
11397  assert (force_count == 1);
11398 
11399  xasl->list_id->tuple_cnt += force_count * 2;
11400  continue;
11401  }
11402  }
11403 
11404  force_count = 0;
11405  /* when insert in heap, don't care about instance locking */
11406  if (locator_attribute_info_force (thread_p, &insert->class_hfid, &oid, &attr_info, NULL, 0, operation,
11407  scan_cache_op_type, &scan_cache, &force_count, false,
11408  REPL_INFO_TYPE_RBR_NORMAL, insert->pruning_type, pcontext,
11409  func_indx_preds, NULL, UPDATE_INPLACE_NONE, NULL, false) != NO_ERROR)
11410  {
11412  }
11413 
11414  /* restore class oid and hfid that might have changed in the call above */
11415  HFID_COPY (&insert->class_hfid, &class_hfid);
11416  COPY_OID (&(attr_info.class_oid), &class_oid);
11417 
11418  /* Instances are not put into the result list file, but are counted. */
11419  if (force_count)
11420  {
11421  assert (force_count == 1);
11422 
11424  && is_autoincrement_set > 0)
11425  {
11426  db_make_oid (&oid_val, &oid);
11427  if (qfile_fast_val_tuple_to_list (thread_p, xasl->list_id, &oid_val) != NO_ERROR)
11428  {
11430  }
11431  }
11432  else
11433  {
11434  xasl->list_id->tuple_cnt += force_count;
11435  }
11436  }
11437  }
11438 
11439  if (ls_scan != S_END)
11440  {
11442  }
11443  }
11444 
11445  if (xb_scan != S_END)
11446  {
11448  }
11449  qexec_close_scan (thread_p, specp);
11450  }
11451  else
11452  {
11453  /* we are inserting a single row ie. insert into foo values(...) */
11454  REGU_VARIABLE_LIST regu_list = NULL;
11455 
11456  if (locator_start_force_scan_cache (thread_p, &scan_cache, &insert->class_hfid, &class_oid, scan_cache_op_type) !=
11457  NO_ERROR)
11458  {
11460  }
11461  scan_cache_inited = true;
11462 
11464  {
11465  /* do not allow references to reusable oids in sub-inserts. this is a safety check and should have been
11466  * detected at semantic level */
11469  }
11470 
11471  for (i = 0; i < insert->num_val_lists; i++)
11472  {
11473  for (regu_list = insert->valptr_lists[i]->valptrp, vallist = xasl->val_list->valp, k = num_default_expr;
11474  k < val_no; k++, regu_list = regu_list->next, vallist = vallist->next)
11475  {
11476  regu_list->value.flags |= REGU_VARIABLE_STRICT_TYPE_CAST;
11477  if (fetch_peek_dbval (thread_p, &regu_list->value, &xasl_state->vd, &class_oid, NULL, NULL, &valp) !=
11478  NO_ERROR)
11479  {
11481  }
11482  if (!qdata_copy_db_value (vallist->val, valp))
11483  {
11485  }
11486  insert->vals[k] = valp;
11487  }
11488 
11489  /* evaluate constraint predicate */
11490  satisfies_constraints = V_UNKNOWN;
11491  if (insert->cons_pred != NULL)
11492  {
11493  satisfies_constraints = eval_pred (thread_p, insert->cons_pred, &xasl_state->vd, NULL);
11494  if (satisfies_constraints == V_ERROR)
11495  {
11497  }
11498  }
11499 
11500  if (insert->cons_pred != NULL && satisfies_constraints != V_TRUE)
11501  {
11502  /* currently there are only NOT NULL constraints */
11505  }
11506 
11507  if (heap_attrinfo_clear_dbvalues (&attr_info) != NO_ERROR)
11508  {
11510  }
11511 
11512  for (k = 0; k < val_no; ++k)
11513  {
11514  if (DB_IS_NULL (insert->vals[k]))
11515  {
11516  OR_ATTRIBUTE *attr = heap_locate_last_attrepr (insert->att_id[k], &attr_info);
11517  if (attr == NULL)
11518  {
11520  }
11521 
11522  if (attr->is_autoincrement)
11523  {
11524  continue;
11525  }
11526  }
11527  rc = heap_attrinfo_set (NULL, insert->att_id[k], insert->vals[k], &attr_info);
11528  if (rc != NO_ERROR)
11529  {
11531  }
11532  }
11533 
11534  if (heap_set_autoincrement_value (thread_p, &attr_info, &scan_cache, &is_autoincrement_set) != NO_ERROR)
11535  {
11537  }
11538 
11539  if (insert->do_replace && insert->has_uniques)
11540  {
11541  int removed_count = 0;
11542  assert (index_attr_info_inited == true);
11543  error =
11544  qexec_remove_duplicates_for_replace (thread_p, &scan_cache, &attr_info, &index_attr_info, &idx_info,
11545  scan_cache_op_type, insert->pruning_type, pcontext,
11546  &removed_count);
11547  if (error != NO_ERROR)
11548  {
11550  }
11551  xasl->list_id->tuple_cnt += removed_count;
11552  }
11553 
11554  force_count = 0;
11555  if (odku_assignments && insert->has_uniques)
11556  {
11557  error =
11558  qexec_execute_duplicate_key_update (thread_p, insert->odku, &insert->class_hfid, &xasl_state->vd,
11559  scan_cache_op_type, &scan_cache, &attr_info, &index_attr_info,
11560  &idx_info, insert->pruning_type, pcontext, &force_count);
11561  if (error != NO_ERROR)
11562  {
11564  }
11565 
11566  if (force_count)
11567  {
11568  assert (force_count == 1);
11569  xasl->list_id->tuple_cnt += force_count * 2;
11570  }
11571  }
11572 
11573  if (force_count == 0)
11574  {
11575  if (locator_attribute_info_force (thread_p, &insert->class_hfid, &oid, &attr_info, NULL, 0, operation,
11576  scan_cache_op_type, &scan_cache, &force_count, false,
11577  REPL_INFO_TYPE_RBR_NORMAL, insert->pruning_type, pcontext, NULL, NULL,
11578  UPDATE_INPLACE_NONE, NULL, false) != NO_ERROR)
11579  {
11581  }
11582 
11583  /* Instances are not put into the result list file, but are counted. */
11584  if (force_count)
11585  {
11586  assert (force_count == 1);
11588  && is_autoincrement_set > 0)
11589  {
11590  db_make_oid (&oid_val, &oid);
11591  if (qfile_fast_val_tuple_to_list (thread_p, xasl->list_id, &oid_val) != NO_ERROR)
11592  {
11594  }
11595  }
11596  else
11597  {
11598  xasl->list_id->tuple_cnt += force_count;
11599  }
11600  }
11601  }
11602 
11604  {
11605  /* this must be a sub-insert, and the inserted OID must be saved to obj_oid in insert_proc */
11606  assert (force_count == 1);
11607  if (force_count != 1)
11608  {
11610  }
11611  db_make_oid (insert->obj_oid, &oid);
11612  /* Clear the list id */
11613  qfile_clear_list_id (xasl->list_id);
11614  }
11615  }
11616  }
11617 
11618  /* check uniques */
11619  /* In this case, consider only single class. Therefore, uniqueness checking is performed based on the local
11620  * statistical information kept in scan_cache. And then, it is reflected into the transaction's statistical
11621  * information. */
11622  if (pcontext != NULL)
11623  {
11624  error = qexec_process_partition_unique_stats (thread_p, pcontext);
11625  if (error != NO_ERROR)
11626  {
11628  }
11629  }
11630  else
11631  {
11632  // *INDENT-OFF*
11633  if (scan_cache.m_index_stats != NULL)
11634  {
11635  for (const auto &it : scan_cache.m_index_stats->get_map ())
11636  {
11637  if (!it.second.is_unique ())
11638  {
11639  // set no error?
11641  }
11642 
11643  error = logtb_tran_update_unique_stats (thread_p, it.first, it.second, true);
11644  if (error != NO_ERROR)
11645  {
11646  ASSERT_ERROR ();
11648  }
11649  }
11650  }
11651  // *INDENT-ON*
11652  }
11653 
11654  if (func_indx_preds)
11655  {
11656  heap_free_func_pred_unpack_info (thread_p, n_indexes, func_indx_preds, NULL);
11657  }
11658  if (index_attr_info_inited)
11659  {
11660  (void) heap_attrinfo_end (thread_p, &index_attr_info);
11661  }
11662  if (attr_info_inited)
11663  {
11664  (void) heap_attrinfo_end (thread_p, &attr_info);
11665  }
11666  if (scan_cache_inited)
11667  {
11668  (void) locator_end_force_scan_cache (thread_p, &scan_cache);
11669  }
11670  if (pcontext != NULL)
11671  {
11673  pcontext = NULL;
11674  }
11675 
11676  if (savepoint_used)
11677  {
11679  {
11680  qexec_failure_line (__LINE__, xasl_state);
11682  }
11683  }
11684 
11685 #if 0 /* yaw */
11686  /* remove query result cache entries which are relevant with this class */
11687  COPY_OID (&class_oid, &XASL_INSERT_CLASS_OID (xasl));
11688  if (!QFILE_IS_LIST_CACHE_DISABLED && !OID_ISNULL (&class_oid))
11689  {
11690  if (qexec_clear_list_cache_by_class (&class_oid) != NO_ERROR)
11691  {
11693  "qexec_execute_insert: qexec_clear_list_cache_by_class failed for class { %d %d %d }\n",
11694  class_oid.pageid, class_oid.slotid, class_oid.volid);
11695  }
11696  qmgr_add_modified_class (&class_oid);
11697  }
11698 #endif
11699 
11700  for (k = 0; k < num_default_expr; k++)
11701  {
11702  pr_clear_value (insert->vals[k]);
11703  db_private_free_and_init (thread_p, insert->vals[k]);
11704  }
11705 
11706  if (odku_assignments && insert->has_uniques)
11707  {
11708  heap_attrinfo_end (thread_p, odku_assignments->attr_info);
11709  }
11710 
11711  return NO_ERROR;
11712 
11713 exit_on_error:
11714  (void) session_reset_cur_insert_id (thread_p);
11715  for (k = 0; k < num_default_expr; k++)
11716  {
11717  pr_clear_value (insert->vals[k]);
11718  db_private_free_and_init (thread_p, insert->vals[k]);
11719  }
11720  qexec_end_scan (thread_p, specp);
11721  qexec_close_scan (thread_p, specp);
11722  if (func_indx_preds)
11723  {
11724  heap_free_func_pred_unpack_info (thread_p, n_indexes, func_indx_preds, NULL);
11725  }
11726  if (index_attr_info_inited)
11727  {
11728  (void) heap_attrinfo_end (thread_p, &index_attr_info);
11729  }
11730  if (attr_info_inited)
11731  {
11732  (void) heap_attrinfo_end (thread_p, &attr_info);
11733  }
11734  if (odku_attr_info_inited)
11735  {
11736  (void) heap_attrinfo_end (thread_p, odku_assignments->attr_info);
11737  }
11738  if (scan_cache_inited)
11739  {
11740  (void) locator_end_force_scan_cache (thread_p, &scan_cache);
11741  }
11742 
11743  if (savepoint_used)
11744  {
11746  }
11747  if (pcontext != NULL)
11748  {
11750  pcontext = NULL;
11751  }
11753  && xasl->list_id != NULL)
11754  {
11755  qfile_clear_list_id (xasl->list_id);
11756  }
11757 
11758  return ER_FAILED;
11759 }
11760 
11761 /*
11762  * qexec_execute_obj_fetch () -
11763  * return: NO_ERROR or ER_code
11764  * xasl(in) : XASL Tree pointer
11765  * xasl_state(in) : XASL tree state information
11766  * scan_operation_type(in) : scan operation type
11767  *
11768  * Note: This routines interpretes an XASL procedure block that denotes
11769  * an object fetch operation, one of the basic operations
11770  * of a path expression evaluation. A path expression evaluation
11771  * consists of fetching the objects linked in a path expression
11772  * and performing value fetch or predicate evalution operations
11773  * on them. A path expression evaluation successfully completes
11774  * if all the objects in the path are succesfully fetched and
11775  * qualified imposed predicates. Some of the objects in a path
11776  * expression may be non-existent. If that
11777  * happens, path expression evaluation succeeds and the value
11778  * list for the procedure block is filled with NULLs. A path
11779  * evaluation may consist of an ordered list of object_fetch operations.
11780  * To conform to the above mentioned semantics,
11781  * an object fetch may succeed or fail
11782  * depending whether the objects succesfully fetched and/or
11783  * qualified. The result of the object fetch operation is
11784  * indicated by setting a flag in the procedure block head node.
11785  * The objects to be fetched are indicated by object identifiers
11786  * already set in the procedure block head node.
11787  */
11788 static int
11790  SCAN_OPERATION_TYPE scan_operation_type)
11791 {
11792  XASL_NODE *xptr;
11793  DB_LOGICAL ev_res;
11794  DB_LOGICAL ev_res2;
11795  RECDES oRec = RECDES_INITIALIZER;
11796  HEAP_SCANCACHE scan_cache;
11797  ACCESS_SPEC_TYPE *specp = NULL;
11798  OID cls_oid = OID_INITIALIZER;
11799  int dead_end = false;
11800  int unqualified_dead_end = false;
11801  FETCH_PROC_NODE *fetch = &xasl->proc.fetch;
11802  OID dbvaloid = OID_INITIALIZER;
11803 
11804  /* the fetch_res represents whether current node in a path expression is successfully completed to the end, or failed */
11805  fetch->fetch_res = false;
11806 
11807  /* object is non_existent ? */
11808  if (DB_IS_NULL (fetch->arg))
11809  {
11810  dead_end = true;
11811  }
11812  else
11813  {
11814  /* check for virtual objects */
11815  if (DB_VALUE_DOMAIN_TYPE (fetch->arg) != DB_TYPE_VOBJ)
11816  {
11817  SAFE_COPY_OID (&dbvaloid, db_get_oid (fetch->arg));
11818  }
11819  else
11820  {
11821  DB_SET *setp = db_get_set (fetch->arg);
11822  DB_VALUE dbval, dbval1;
11823 
11824  if ((db_set_size (setp) == 3) && (db_set_get (setp, 1, &dbval) == NO_ERROR)
11825  && (db_set_get (setp, 2, &dbval1) == NO_ERROR)
11826  && (DB_IS_NULL (&dbval)
11827  || ((DB_VALUE_DOMAIN_TYPE (&dbval) == DB_TYPE_OID) && OID_ISNULL (db_get_oid (&dbval))))
11828  && (DB_VALUE_DOMAIN_TYPE (&dbval1) == DB_TYPE_OID))
11829  {
11830  SAFE_COPY_OID (&dbvaloid, db_get_oid (&dbval1));
11831  }
11832  else
11833  {
11834  return ER_FAILED;
11835  }
11836  }
11837 
11838  /* object is non_existent ? */
11839  if (OID_ISNULL (&dbvaloid))
11840  {
11841  dead_end = true;
11842  }
11843  }
11844 
11845  /*
11846  * Pre_processing
11847  */
11848 
11849  /* evaluate aptr list */
11850  for (xptr = xasl->aptr_list; xptr != NULL; xptr = xptr->next)
11851  {
11853  {
11854  /* skip if linked to regu var */
11855  continue;
11856  }
11857 
11858  if (xptr->status == XASL_CLEARED || xptr->status == XASL_INITIALIZED)
11859  {
11860  if (qexec_execute_mainblock (thread_p, xptr, xasl_state, NULL) != NO_ERROR)
11861  {
11863  }
11864  }
11865  else
11866  { /* already executed. success or failure */
11867  if (xptr->status != XASL_SUCCESS)
11868  {
11870  }
11871  }
11872  }
11873 
11874  /*
11875  * Processing
11876  */
11877 
11878  if (!dead_end)
11879  {
11880  int cache_pred_end_needed = false;
11881  int cache_rest_end_needed = false;
11882  int scan_cache_end_needed = false;
11883  int status = NO_ERROR;
11885  SCAN_CODE scan;
11886  LOCK lock_mode;
11887 
11888  /* Start heap file scan operation */
11889  /* A new argument(is_indexscan = false) is appended */
11890 
11891  mvcc_snapshot = logtb_get_mvcc_snapshot (thread_p);
11892  if (mvcc_snapshot == NULL)
11893  {
11895  }
11896 
11897  if (heap_scancache_start (thread_p, &scan_cache, NULL, NULL, true, false, mvcc_snapshot) != NO_ERROR)
11898  {
11900  }
11901  scan_cache_end_needed = true;
11902 
11903  /* must choose corresponding lock_mode for scan_operation_type.
11904  * for root classes the lock_mode is considered, not the operation type */
11905  lock_mode = locator_get_lock_mode_from_op_type (scan_operation_type);
11906 
11907  /* fetch the object and the class oid */
11908  scan = locator_get_object (thread_p, &dbvaloid, &cls_oid, &oRec, &scan_cache, scan_operation_type, lock_mode,
11909  PEEK, NULL_CHN);
11910  if (scan != S_SUCCESS)
11911  {
11912  /* setting ER_HEAP_UNKNOWN_OBJECT error for deleted or invisible objects should be replaced by a more clear
11913  * way of handling the return code; it is imposible to decide at low level heap get functions if it is
11914  * expected to reach a deleted object and also it is difficult to propagate the NON_EXISTENT_HANDLING
11915  * argument through all the callers; this system can currently generate some irrelevant error log that is
11916  * hard to eliminate */
11917  if (scan == S_DOESNT_EXIST || scan == S_SNAPSHOT_NOT_SATISFIED)
11918  {
11919  /* dangling object reference */
11920  dead_end = true;
11921  er_clear (); /* probably ER_HEAP_UNKNOWN_OBJECT is set */
11922  }
11923  else if (er_errid () == ER_HEAP_NODATA_NEWADDRESS)
11924  {
11925  dead_end = true;
11926  unqualified_dead_end = true;
11927  er_clear (); /* clear ER_HEAP_NODATA_NEWADDRESS */
11928  }
11929  else if (er_errid () == ER_HEAP_UNKNOWN_OBJECT)
11930  {
11931  /* where is this from? */
11932  assert (false);
11933  dead_end = true;
11934  er_clear (); /* clear ER_HEAP_UNKOWN_OBJECT */
11935  }
11936  else
11937  {
11938  status = ER_FAILED;
11939  goto wrapup;
11940  }
11941  }
11942  else
11943  {
11944  /* check to see if the object is one of the classes that we are interested in. This can only fail if there
11945  * was a selector variable in the query. we can optimize this further to pass from the compiler whether this
11946  * check is necessary or not. */
11947  bool found = false;
11948 
11949  for (specp = xasl->spec_list;
11950  specp && specp->type == TARGET_CLASS && !XASL_IS_FLAGED (xasl, XASL_OBJFETCH_IGNORE_CLASSOID);
11951  specp = specp->next)
11952  {
11953  PARTITION_SPEC_TYPE *current = NULL;
11954 
11955  if (OID_EQ (&ACCESS_SPEC_CLS_OID (specp), &cls_oid))
11956  {
11957  /* found it */
11958  break;
11959  }
11960 
11961  if (!specp->pruned && specp->type == TARGET_CLASS)
11962  {
11963  /* cls_oid might still refer to this spec through a partition. See if we already pruned this spec and
11964  * search through partitions for the appropriate class */
11965  PARTITION_SPEC_TYPE *partition_spec = NULL;
11966  int granted;
11967 
11968  if (partition_prune_spec (thread_p, &xasl_state->vd, specp) != NO_ERROR)
11969  {
11970  status = ER_FAILED;
11971  goto wrapup;
11972  }
11973  for (partition_spec = specp->parts; partition_spec != NULL; partition_spec = partition_spec->next)
11974  {
11975  granted =
11976  lock_subclass (thread_p, &partition_spec->oid, &ACCESS_SPEC_CLS_OID (specp), IS_LOCK,
11977  LK_UNCOND_LOCK);
11978  if (granted != LK_GRANTED)
11979  {
11980  status = ER_FAILED;
11981  goto wrapup;
11982  }
11983  }
11984  }
11985 
11986  current = specp->parts;
11987  found = false;
11988  while (current != NULL)
11989  {
11990  if (OID_EQ (&current->oid, &cls_oid))
11991  {
11992  found = true;
11993  break;
11994  }
11995  current = current->next;
11996  }
11997 
11998  if (found)
11999  {
12000  break;
12001  }
12002  }
12003 
12004  if (specp == NULL)
12005  {
12006  /* no specification contains the class oid, this is a possible situation for object domain definitions.
12007  * It just causes the object fetch result to fail. */
12008  fetch->fetch_res = false;
12009  dead_end = true;
12010  unqualified_dead_end = true;
12011  }
12012  }
12013 
12014  if (!dead_end)
12015  {
12016  /* set up the attribute cache info */
12017  status =
12018  heap_attrinfo_start (thread_p, &cls_oid, specp->s.cls_node.num_attrs_pred, specp->s.cls_node.attrids_pred,
12019  specp->s.cls_node.cache_pred);
12020  if (status != NO_ERROR)
12021  {
12022  goto wrapup;
12023  }
12024  cache_pred_end_needed = true;
12025 
12026  status =
12027  heap_attrinfo_start (thread_p, &cls_oid, specp->s.cls_node.num_attrs_rest, specp->s.cls_node.attrids_rest,
12028  specp->s.cls_node.cache_rest);
12029  if (status != NO_ERROR)
12030  {
12031  goto wrapup;
12032  }
12033  cache_rest_end_needed = true;
12034 
12037 
12038  /* read the predicate values from the heap into the scancache */
12039  status = heap_attrinfo_read_dbvalues (thread_p, &dbvaloid, &oRec, &scan_cache, specp->s.cls_node.cache_pred);
12040  if (status != NO_ERROR)
12041  {
12042  goto wrapup;
12043  }
12044 
12045  /* fetch the values for the predicate from the object */
12046  if (xasl->val_list != NULL)
12047  {
12048  status =
12049  fetch_val_list (thread_p, specp->s.cls_node.cls_regu_list_pred, &xasl_state->vd, NULL, &dbvaloid, NULL,
12050  COPY);
12051  if (status != NO_ERROR)
12052  {
12053  goto wrapup;
12054  }
12055  }
12056 
12057  /* evaluate where predicate, if any */
12058  ev_res = V_UNKNOWN;
12059  if (specp->where_pred)
12060  {
12061  ev_res = eval_pred (thread_p, specp->where_pred, &xasl_state->vd, &dbvaloid);
12062  if (ev_res == V_ERROR)
12063  {
12064  status = ER_FAILED;
12065  goto wrapup;
12066  }
12067  }
12068 
12069  if (specp->where_pred != NULL && ev_res != V_TRUE)
12070  {
12071  /* the object is a disqualified one */
12072  fetch->fetch_res = false;
12073  }
12074  else
12075  {
12076  /* the object is a qualified */
12077  fetch->fetch_res = true;
12078  /* read the rest of the values from the heap */
12079  status =
12080  heap_attrinfo_read_dbvalues (thread_p, &dbvaloid, &oRec, &scan_cache, specp->s.cls_node.cache_rest);
12081  if (status != NO_ERROR)
12082  {
12083  goto wrapup;
12084  }
12085 
12086  /* fetch the rest of the values from the object */
12087  if (xasl->val_list != NULL)
12088  {
12089  status =
12090  fetch_val_list (thread_p, specp->s.cls_node.cls_regu_list_rest, &xasl_state->vd, NULL, &dbvaloid,
12091  NULL, COPY);
12092  if (status != NO_ERROR)
12093  {
12094  goto wrapup;
12095  }
12096  }
12097  }
12098  }
12099 
12100  wrapup:
12101  if (cache_pred_end_needed)
12102  {
12103  heap_attrinfo_end (thread_p, specp->s.cls_node.cache_pred);
12104  }
12105  if (cache_rest_end_needed)
12106  {
12107  heap_attrinfo_end (thread_p, specp->s.cls_node.cache_rest);
12108  }
12109  if (scan_cache_end_needed)
12110  {
12111  (void) heap_scancache_end (thread_p, &scan_cache);
12112  }
12113  if (status == ER_FAILED)
12114  {
12115  return ER_FAILED;
12116  }
12117  } /* if !dead_end */
12118 
12119  if (dead_end)
12120  {
12121  /* set values to null */
12122  if (unqualified_dead_end || fetch->ql_flag == true)
12123  {
12124  /* the object is unqualified */
12125  fetch->fetch_res = false;
12126  }
12127  else
12128  {
12130  fetch->fetch_res = true; /* the object is qualified */
12131  }
12132  }
12133 
12134  if (fetch->fetch_res)
12135  {
12136  /* evaluate bptr list */
12137  for (xptr = xasl->bptr_list; fetch->fetch_res == true && xptr != NULL; xptr = xptr->next)
12138  {
12139  if (qexec_execute_obj_fetch (thread_p, xptr, xasl_state, scan_operation_type) != NO_ERROR)
12140  {
12142  }
12143  else if (xptr->proc.fetch.fetch_res == false)
12144  {
12145  fetch->fetch_res = false;
12146  }
12147  }
12148 
12149  if (fetch->fetch_res)
12150  {
12151 
12152  /* evaluate dptr list */
12153  for (xptr = xasl->dptr_list; xptr != NULL; xptr = xptr->next)
12154  {
12155  /* clear correlated subquery list files */
12156  qexec_clear_head_lists (thread_p, xptr);
12158  {
12159  /* skip if linked to regu var */
12160  continue;
12161  }
12162  if (qexec_execute_mainblock (thread_p, xptr, xasl_state, NULL) != NO_ERROR)
12163  {
12165  }
12166  }
12167 
12168  /* evaluate constant (if) predicate */
12169  if (fetch->fetch_res && xasl->if_pred != NULL)
12170  {
12171  ev_res2 = eval_pred (thread_p, xasl->if_pred, &xasl_state->vd, NULL);
12172  if (ev_res2 == V_ERROR)
12173  {
12175  }
12176  else if (ev_res2 != V_TRUE)
12177  {
12178  fetch->fetch_res = false;
12179  }
12180  } /* if */
12181 
12182  if (fetch->fetch_res)
12183  {
12184  /* evaluate fptr list */
12185  for (xptr = xasl->fptr_list; fetch->fetch_res == true && xptr != NULL; xptr = xptr->next)
12186  {
12187  if (qexec_execute_obj_fetch (thread_p, xptr, xasl_state, scan_operation_type) != NO_ERROR)
12188  {
12190  }
12191  else if (xptr->proc.fetch.fetch_res == false)
12192  {
12193  fetch->fetch_res = false;
12194  }
12195  }
12196 
12197  /* NO SCAN PROCEDURES are supported for these blocks! */
12198  } /* if */
12199 
12200  } /* if */
12201 
12202  } /* if */
12203 
12204  /* clear uncorrelated subquery list files */
12205  if (xasl->aptr_list)
12206  {
12207  qexec_clear_head_lists (thread_p, xasl->aptr_list);
12208  }
12209 
12210  return NO_ERROR;
12211 
12212 exit_on_error:
12213 
12214  /* clear uncorrelated subquery list files */
12215  if (xasl->aptr_list)
12216  {
12217  qexec_clear_head_lists (thread_p, xasl->aptr_list);
12218  }
12219 
12220  return ER_FAILED;
12221 }
12222 
12223 /*
12224  * qexec_execute_increment () -
12225  * return:
12226  * oid(in) :
12227  * class_oid(in) :
12228  * class_hfid(in) :
12229  * attrid(in) :
12230  * n_increment(in) :
12231  * pruning_type(in) :
12232  * need_locking(in) : true, if need locking
12233  */
12234 static int
12235 qexec_execute_increment (THREAD_ENTRY * thread_p, const OID * oid, const OID * class_oid, const HFID * class_hfid,
12236  ATTR_ID attrid, int n_increment, int pruning_type)
12237 {
12238  HEAP_CACHE_ATTRINFO attr_info;
12239  int attr_info_inited = 0;
12240  HEAP_SCANCACHE scan_cache;
12241  bool scan_cache_inited = false;
12242  HEAP_ATTRVALUE *value = NULL;
12243  int force_count;
12244  int error = NO_ERROR;
12245  int op_type = SINGLE_ROW_UPDATE;
12247 
12248  error = heap_attrinfo_start (thread_p, class_oid, -1, NULL, &attr_info);
12249  if (error != NO_ERROR)
12250  {
12251  goto wrapup;
12252  }
12253  attr_info_inited = 1;
12254 
12255 
12256  error = locator_start_force_scan_cache (thread_p, &scan_cache, class_hfid, class_oid, op_type);
12257  if (error != NO_ERROR)
12258  {
12259  goto wrapup;
12260  }
12261  scan_cache_inited = true;
12262 
12263  if (!class_hfid)
12264  {
12265  error = ER_FAILED;
12266  goto wrapup;
12267  }
12268 
12269  if (!HFID_IS_NULL (class_hfid))
12270  {
12271  if (heap_attrinfo_clear_dbvalues (&attr_info) != NO_ERROR)
12272  {
12273  error = ER_FAILED;
12274  goto wrapup;
12275  }
12276 
12277  /* set increment operation for the attr */
12278  value = heap_attrvalue_locate (attrid, &attr_info);
12279  if (value == NULL)
12280  {
12281  error = ER_FAILED;
12282  goto wrapup;
12283  }
12284 
12285  value->do_increment = n_increment;
12286 
12287  force_count = 0;
12288  /* oid was already locked in select phase */
12289  OID copy_oid = *oid;
12290  error =
12291  locator_attribute_info_force (thread_p, class_hfid, &copy_oid, &attr_info, &attrid, 1, area_op, op_type,
12292  &scan_cache, &force_count, false, REPL_INFO_TYPE_RBR_NORMAL, pruning_type, NULL,
12293  NULL, NULL, UPDATE_INPLACE_NONE, NULL, false);
12295  {
12296  assert (force_count == 0);
12297  error = NO_ERROR;
12298  }
12299  else if (error != NO_ERROR)
12300  {
12301  error = ER_FAILED;
12302  goto wrapup;
12303  }
12304  }
12305 
12306 #if 0 /* yaw */
12307  /* remove query result cache entries which are relevant with this class */
12309  {
12310  if (qexec_clear_list_cache_by_class (class_oid) != NO_ERROR)
12311  {
12312  OID *o = class_oid;
12314  "qexec_execute_increment: qexec_clear_list_cache_by_class failed for class { %d %d %d }\n",
12315  o->pageid, o->slotid, o->volid);
12316  }
12317  qmgr_add_modified_class (class_oid);
12318  }
12319 #endif
12320 
12321 wrapup:
12322 
12323  if (attr_info_inited)
12324  {
12325  (void) heap_attrinfo_end (thread_p, &attr_info);
12326  }
12327 
12328  if (scan_cache_inited)
12329  {
12330  (void) locator_end_force_scan_cache (thread_p, &scan_cache);
12331  }
12332 
12333  return error;
12334 }
12335 
12336 /*
12337  * qexec_execute_selupd_list_find_class () -
12338  * Helper function used by qexec_execute_selupd_list to find class oid/hfid
12339  *
12340  * return: NO_ERROR or a error code
12341  * thread_p(in) : thread entry
12342  * xasl(in) : XASL Tree
12343  * vd(in) : Value Descriptor (from XASL State)
12344  * oid(in) : oid of the column used in click counter function
12345  * selupd(in) : select update list
12346  * class_oid(out) : corresponding class oid
12347  * class_hfid(out) : corresponding class hfid
12348  * needs_pruning(out) : type of pruning that should be performed later
12349  * found(out) : true if class oid/hfid was found, false otherwise
12350  */
12351 static int
12353  SELUPD_LIST * selupd, OID * class_oid, HFID * class_hfid,
12354  DB_CLASS_PARTITION_TYPE * needs_pruning, bool * found)
12355 {
12356 
12357  OID class_oid_buf;
12358  XASL_NODE *scan_ptr = xasl;
12359 
12360  *found = false;
12361  *needs_pruning = DB_NOT_PARTITIONED_CLASS;
12362 
12363  if (!OID_EQ (&selupd->class_oid, &oid_Null_oid))
12364  {
12365  *class_oid = selupd->class_oid;
12366  *class_hfid = selupd->class_hfid;
12367  *found = true;
12368  return NO_ERROR;
12369  }
12370 
12371  if (heap_get_class_oid (thread_p, oid, &class_oid_buf) != S_SUCCESS)
12372  {
12373  ASSERT_ERROR ();
12374  return er_errid ();
12375  }
12376  *class_oid = class_oid_buf;
12377 
12378  for (; scan_ptr != NULL; scan_ptr = scan_ptr->scan_ptr)
12379  {
12380  ACCESS_SPEC_TYPE *specp = NULL;
12381  for (specp = scan_ptr->spec_list; specp; specp = specp->next)
12382  {
12383  if (specp->type == TARGET_CLASS && OID_EQ (&specp->s.cls_node.cls_oid, class_oid))
12384  {
12385  *found = true;
12386  *class_hfid = specp->s.cls_node.hfid;
12387  *needs_pruning = (DB_CLASS_PARTITION_TYPE) specp->pruning_type;
12388  return NO_ERROR;
12389  }
12390  else if (specp->pruning_type)
12391  {
12392  if (!specp->pruned)
12393  {
12394  /* perform pruning */
12395  int error_code = qexec_prune_spec (thread_p, specp, vd, scan_ptr->scan_op_type);
12396  if (error_code != NO_ERROR)
12397  {
12398  return error_code;
12399  }
12400  }
12401 
12402  PARTITION_SPEC_TYPE *part_spec = NULL;
12403  for (part_spec = specp->parts; part_spec != NULL; part_spec = part_spec->next)
12404  {
12405  if (OID_EQ (&part_spec->oid, class_oid))
12406  {
12407  *found = true;
12408  *class_hfid = part_spec->hfid;
12409  *needs_pruning = (DB_CLASS_PARTITION_TYPE) specp->pruning_type;
12410  return NO_ERROR;
12411  }
12412  }
12413  }
12414  }
12415 
12416  if (specp == NULL)
12417  {
12418  specp = scan_ptr->spec_list;
12419  if (specp != NULL && specp->pruning_type == DB_PARTITION_CLASS && specp->next == NULL
12420  && specp->s_id.mvcc_select_lock_needed)
12421  {
12422  /* the object may be updated to other partition */
12425  }
12426  }
12427  }
12428 
12429  return NO_ERROR;
12430 }
12431 
12432 /*
12433  * qexec_execute_selupd_list () -
12434  * return: NO_ERROR, or ER_code
12435  * xasl(in) : XASL Tree
12436  * xasl_state(in) :
12437  * Note: This routine executes update for a selected tuple
12438  */
12439 static int
12441 {
12442  SELUPD_LIST *list = NULL, *selupd = NULL;
12443  REGU_VARLIST_LIST outptr = NULL;
12444  REGU_VARIABLE *varptr = NULL;
12445  DB_VALUE *rightvalp = NULL, *thirdvalp = NULL;
12446  bool subtransaction_started = false;
12447  OID last_cached_class_oid;
12448  int tran_index;
12449  int err = NO_ERROR;
12450  HEAP_SCANCACHE scan_cache;
12451  bool scan_cache_inited = false;
12452  SCAN_CODE scan_code;
12453  LOG_TDES *tdes = NULL;
12454  UPDDEL_MVCC_COND_REEVAL upd_reev;
12455  MVCC_SCAN_REEV_DATA mvcc_sel_reev_data;
12456  MVCC_REEV_DATA mvcc_reev_data, *p_mvcc_reev_data = NULL;
12457  bool clear_list_id = false;
12459  bool need_ha_replication = !LOG_CHECK_LOG_APPLIER (thread_p) && log_does_allow_replication () == true;
12460  bool sysop_started = false;
12461  bool in_instant_lock_mode;
12462 
12463  // *INDENT-OFF*
12464  struct incr_info
12465  {
12466  OID m_oid;
12467  OID m_class_oid;
12468  HFID m_class_hfid;
12469  int m_attrid;
12470  int m_n_increment;
12471  DB_CLASS_PARTITION_TYPE m_ptype;
12472 
12473  incr_info () = default;
12474  incr_info (const incr_info & other) = default;
12475  };
12476  std::vector<incr_info> all_incr_info;
12477  std::vector<bool> all_skipped;
12478  size_t incr_info_index = 0;
12479  size_t skipped_index = 0;
12480  // *INDENT-ON*
12481 
12482  assert (xasl->list_id->tuple_cnt == 1);
12483  OID_SET_NULL (&last_cached_class_oid);
12484 
12485  tran_index = LOG_FIND_THREAD_TRAN_INDEX (thread_p);
12486 
12487  if (QEXEC_SEL_UPD_USE_REEVALUATION (xasl))
12488  {
12489  /* need reevaluation in this function */
12490  upd_reev.init (xasl->spec_list->s_id);
12491  mvcc_sel_reev_data.set_filters (upd_reev);
12492  mvcc_sel_reev_data.qualification = &xasl->spec_list->s_id.qualification;
12493  mvcc_reev_data.set_scan_reevaluation (mvcc_sel_reev_data);
12494  p_mvcc_reev_data = &mvcc_reev_data;
12495 
12496  /* clear list id if all reevaluations result is false */
12497  clear_list_id = true;
12498 
12499  /* need lock & reevaluation */
12500  lock_start_instant_lock_mode (tran_index);
12501  in_instant_lock_mode = true;
12502  }
12503  else
12504  {
12505  // locking and evaluation is done at scan phase
12506  in_instant_lock_mode = lock_is_instant_lock_mode (tran_index);
12507  }
12508 
12509  list = xasl->selected_upd_list;
12510 
12511  /* do increment operation */
12512  for (selupd = list; selupd; selupd = selupd->next)
12513  {
12514  for (outptr = selupd->select_list; outptr; outptr = outptr->next)
12515  {
12516  incr_info crt_incr_info;
12517 
12518  if (outptr->list == NULL)
12519  {
12520  goto exit_on_error;
12521  }
12522 
12523  /* pointer to the regu variable */
12524  varptr = &(outptr->list->value);
12525 
12526  /* check something */
12527  if (!((varptr->type == TYPE_INARITH || varptr->type == TYPE_OUTARITH)
12528  && (varptr->value.arithptr->opcode == T_INCR || varptr->value.arithptr->opcode == T_DECR)))
12529  {
12530  goto exit_on_error;
12531  }
12532  if (varptr->value.arithptr->leftptr->type != TYPE_CONSTANT
12533  || varptr->value.arithptr->rightptr->type != TYPE_CONSTANT)
12534  {
12535  goto exit_on_error;
12536  }
12537 
12538  /* get oid and attrid to be fetched last at scan */
12539  rightvalp = varptr->value.arithptr->value;
12540 
12541  if (db_get_oid (rightvalp) == NULL)
12542  {
12543  /* Probably this would be INCR(NULL). When the source value is NULL, INCR/DECR expression is also NULL. */
12544  clear_list_id = false;
12545  all_skipped.push_back (true);
12546  continue;
12547  }
12548  crt_incr_info.m_oid = *db_get_oid (rightvalp);
12549  if (OID_ISNULL (&crt_incr_info.m_oid))
12550  {
12551  /* in some cases, a query returns no result even if it should have an result on dirty read mode. it may
12552  * be caused by index scan failure for index to be updated frequently (hot spot index). if this case is
12553  * fixed, it does not need to be checked */
12554  er_log_debug (ARG_FILE_LINE, "qexec_execute_selupd_list: OID is null\n");
12555  clear_list_id = false;
12556  all_skipped.push_back (true);
12557  continue;
12558  }
12559 
12560  /* we also need attribute id to perform increment */
12561  if (fetch_peek_dbval (thread_p, varptr->value.arithptr->thirdptr, NULL, NULL, NULL, NULL, &thirdvalp) !=
12562  NO_ERROR)
12563  {
12564  goto exit_on_error;
12565  }
12566  crt_incr_info.m_attrid = db_get_int (thirdvalp);
12567 
12568  crt_incr_info.m_n_increment = (varptr->value.arithptr->opcode == T_INCR ? 1 : -1);
12569 
12570  /* check if class oid/hfid does not set, find class oid/hfid to access */
12571  bool found = false;
12572  err = qexec_execute_selupd_list_find_class (thread_p, xasl, &xasl_state->vd, &crt_incr_info.m_oid, selupd,
12573  &crt_incr_info.m_class_oid, &crt_incr_info.m_class_hfid,
12574  &crt_incr_info.m_ptype, &found);
12575  if (err != NO_ERROR)
12576  {
12577  goto exit_on_error;
12578  }
12579  if (!found)
12580  {
12581  /* not found hfid */
12582  er_log_debug (ARG_FILE_LINE, "qexec_execute_selupd_list: class hfid to access is null\n");
12583  assert (false);
12584  goto exit_on_error;
12585  }
12586 
12587  if (p_mvcc_reev_data != NULL)
12588  {
12589  /* need locking and reevaluation */
12590  if (!OID_EQ (&last_cached_class_oid, &crt_incr_info.m_class_oid) && scan_cache_inited == true)
12591  {
12592  (void) heap_scancache_end (thread_p, &scan_cache);
12593  scan_cache_inited = false;
12594  }
12595 
12596  if (scan_cache_inited == false)
12597  {
12598  if (heap_scancache_start (thread_p, &scan_cache, &crt_incr_info.m_class_hfid,
12599  &crt_incr_info.m_class_oid, false, false, mvcc_snapshot) != NO_ERROR)
12600  {
12601  goto exit_on_error;
12602  }
12603  scan_cache_inited = true;
12604  COPY_OID (&last_cached_class_oid, &crt_incr_info.m_class_oid);
12605  }
12606  /* need to handle reevaluation */
12607  scan_code =
12608  locator_lock_and_get_object_with_evaluation (thread_p, &crt_incr_info.m_oid, &crt_incr_info.m_class_oid,
12609  NULL, &scan_cache, COPY, NULL_CHN, p_mvcc_reev_data,
12611  if (scan_code != S_SUCCESS)
12612  {
12613  int er_id = er_errid ();
12615  {
12616  /* error, deadlock or something */
12617  goto exit_on_error;
12618  }
12621  {
12622  /* ignore lock timeout for click counter, and skip this increment operation */
12624  "qexec_execute_selupd_list: lock(X_LOCK) timed out "
12625  "for OID { %d %d %d } class OID { %d %d %d }\n", OID_AS_ARGS (&crt_incr_info.m_oid),
12626  OID_AS_ARGS (&crt_incr_info.m_class_oid));
12627  er_clear ();
12628  all_skipped.push_back (true);
12629  continue;
12630  }
12631  else
12632  {
12633  if (er_id != NO_ERROR)
12634  {
12635  er_clear ();
12636  }
12637  /* simply, skip this increment operation */
12639  "qexec_execute_selupd_list: skip for OID "
12640  "{ %d %d %d } class OID { %d %d %d } error_id %d\n",
12641  OID_AS_ARGS (&crt_incr_info.m_oid), OID_AS_ARGS (&crt_incr_info.m_class_oid),
12642  er_id);
12643  all_skipped.push_back (true);
12644  continue;
12645  }
12646  }
12647  else if (p_mvcc_reev_data->filter_result != V_TRUE)
12648  {
12649  /* simply, skip this increment operation */
12651  "qexec_execute_selupd_list: skip for OID "
12652  "{ %d %d %d } class OID { %d %d %d } error_id %d\n", OID_AS_ARGS (&crt_incr_info.m_oid),
12653  OID_AS_ARGS (&crt_incr_info.m_class_oid), NO_ERROR);
12654  all_skipped.push_back (true);
12655  continue;
12656  }
12657  else
12658  {
12659  /* one tuple successfully reevaluated, do not clear list file */
12660  clear_list_id = false;
12661  }
12662  }
12663  else
12664  {
12665  /* already locked during scan phase */
12666  assert ((lock_get_object_lock (&crt_incr_info.m_oid, &crt_incr_info.m_class_oid) == X_LOCK)
12667  || lock_get_object_lock (&crt_incr_info.m_class_oid, oid_Root_class_oid) >= X_LOCK);
12668  }
12669 
12670  all_incr_info.push_back (crt_incr_info);
12671  all_skipped.push_back (false);
12672  }
12673  }
12674 
12675  log_sysop_start (thread_p);
12676  sysop_started = true;
12677 
12678  if (lock_is_instant_lock_mode (tran_index))
12679  {
12680  assert (in_instant_lock_mode);
12681 
12682  /* in this function, several instances can be updated, so it need to be atomic */
12683  if (need_ha_replication)
12684  {
12685  repl_start_flush_mark (thread_p);
12686  }
12687 
12688  /* Subtransaction case. Locks and MVCCID are acquired/released by subtransaction. */
12689  tdes = LOG_FIND_TDES (LOG_FIND_THREAD_TRAN_INDEX (thread_p));
12690  assert (tdes != NULL);
12691  logtb_get_new_subtransaction_mvccid (thread_p, &tdes->mvccinfo);
12692  subtransaction_started = true;
12693  }
12694 
12695  for (selupd = list; selupd; selupd = selupd->next)
12696  {
12697  for (outptr = selupd->select_list; outptr; outptr = outptr->next)
12698  {
12699  if (all_skipped[skipped_index++])
12700  {
12701  // skip this increment
12702  continue;
12703  }
12704  const incr_info & crt_incr_info = all_incr_info[incr_info_index++];
12705  if (qexec_execute_increment (thread_p, &crt_incr_info.m_oid, &crt_incr_info.m_class_oid,
12706  &crt_incr_info.m_class_hfid, crt_incr_info.m_attrid, crt_incr_info.m_n_increment,
12707  crt_incr_info.m_ptype) != NO_ERROR)
12708  {
12709  goto exit_on_error;
12710  }
12711  }
12712  }
12713  assert (skipped_index == all_skipped.size ());
12714  assert (incr_info_index == all_incr_info.size ());
12715 
12716  if (scan_cache_inited == true)
12717  {
12718  (void) heap_scancache_end (thread_p, &scan_cache);
12719  scan_cache_inited = false;
12720  }
12721 
12722  if (subtransaction_started && need_ha_replication)
12723  {
12724  /* Ends previously started marker. */
12725  repl_end_flush_mark (thread_p, false);
12726  }
12727 
12728  /* Here we need to check instant lock mode, since it may be reseted by qexec_execute_increment. */
12729  if (lock_is_instant_lock_mode (tran_index))
12730  {
12731  /* Subtransaction case. */
12732  assert (subtransaction_started);
12733  log_sysop_commit (thread_p);
12734 
12735  assert (in_instant_lock_mode);
12736  }
12737  else
12738  {
12739  /* Transaction case. */
12740  log_sysop_attach_to_outer (thread_p);
12741 
12742  in_instant_lock_mode = false;
12743  }
12744 
12745 exit:
12746  /* Release subtransaction resources. */
12747  if (subtransaction_started)
12748  {
12749  /* Release subtransaction MVCCID. */
12750  logtb_complete_sub_mvcc (thread_p, tdes);
12751  }
12752 
12753  if (in_instant_lock_mode)
12754  {
12755  /* Release instant locks, if not already released. */
12756  lock_stop_instant_lock_mode (thread_p, tran_index, true);
12757  in_instant_lock_mode = false;
12758  }
12759 
12760  // not hold instant locks any more.
12761  assert (!in_instant_lock_mode && !lock_is_instant_lock_mode (tran_index));
12762 
12763  if (err != NO_ERROR)
12764  {
12765  qexec_failure_line (__LINE__, xasl_state);
12766  return ER_FAILED;
12767  }
12768 
12769  if (clear_list_id)
12770  {
12771  /* can't reevaluate any data, clear list file */
12772  qfile_clear_list_id (xasl->list_id);
12773  }
12774 
12775  return NO_ERROR;
12776 
12777 exit_on_error:
12778 
12779  if (scan_cache_inited == true)
12780  {
12781  (void) heap_scancache_end (thread_p, &scan_cache);
12782  scan_cache_inited = false;
12783  }
12784 
12785  if (subtransaction_started && need_ha_replication)
12786  {
12787  /* Ends previously started marker. */
12788  repl_end_flush_mark (thread_p, true);
12789  }
12790 
12791  if (sysop_started)
12792  {
12793  log_sysop_abort (thread_p);
12794  sysop_started = false;
12795  }
12796 
12797  /* clear some kinds of error code; it's click counter! */
12798  ASSERT_ERROR_AND_SET (err);
12802  {
12803  er_log_debug (ARG_FILE_LINE, "qexec_execute_selupd_list: ignore error %d\n", err);
12804 
12805  lock_clear_deadlock_victim (tran_index);
12806  qfile_close_list (thread_p, xasl->list_id);
12807  qfile_destroy_list (thread_p, xasl->list_id);
12808  er_clear ();
12809  err = NO_ERROR;
12810  }
12811 
12812  goto exit;
12813 }
12814 
12815 /*
12816  * qexec_init_instnum_val () -
12817  * return: NO_ERROR, or ER_code
12818  * xasl(in) : XASL Tree pointer
12819  * thread_p : Thread entry pointer
12820  * xasl_state(in) : XASL tree state information
12821  *
12822  * Note: This routine initializes the instnum value used in execution
12823  * to evaluate rownum() predicates.
12824  * Usually the value is set to 0, so that the first row number will be 1,
12825  * but for single table index scans that have a keylimit with a lower
12826  * value, we initialize instnum_val with keylimit's low value.
12827  * Otherwise, keylimit would skip some rows and instnum will start
12828  * counting from 1, which is wrong.
12829  */
12830 static int
12832 {
12834  DB_TYPE orig_type;
12835  REGU_VARIABLE *key_limit_l;
12836  DB_VALUE *dbvalp;
12837  int error = NO_ERROR;
12838  TP_DOMAIN_STATUS dom_status;
12839 
12840  assert (xasl && xasl->instnum_val);
12841  db_make_bigint (xasl->instnum_val, 0);
12842 
12843  if (xasl->save_instnum_val)
12844  {
12845  db_make_bigint (xasl->save_instnum_val, 0);
12846  }
12847 
12848  /* Single table, index scan, with keylimit that has lower value */
12849  if (xasl->scan_ptr == NULL && xasl->spec_list != NULL && xasl->spec_list->next == NULL
12850  && xasl->spec_list->access == ACCESS_METHOD_INDEX && xasl->spec_list->indexptr
12852  {
12853  key_limit_l = xasl->spec_list->indexptr->key_info.key_limit_l;
12854  if (fetch_peek_dbval (thread_p, key_limit_l, &xasl_state->vd, NULL, NULL, NULL, &dbvalp) != NO_ERROR)
12855  {
12856  goto exit_on_error;
12857  }
12858 
12859  orig_type = DB_VALUE_DOMAIN_TYPE (dbvalp);
12860  if (orig_type != DB_TYPE_BIGINT)
12861  {
12862  dom_status = tp_value_coerce (dbvalp, dbvalp, domainp);
12863  if (dom_status != DOMAIN_COMPATIBLE)
12864  {
12865  error = tp_domain_status_er_set (dom_status, ARG_FILE_LINE, dbvalp, domainp);
12866  assert_release (error != NO_ERROR);
12867 
12868  goto exit_on_error;
12869  }
12870 
12871  if (DB_VALUE_DOMAIN_TYPE (dbvalp) != DB_TYPE_BIGINT)
12872  {
12874  goto exit_on_error;
12875  }
12876  }
12877 
12878  if (pr_clone_value (dbvalp, xasl->instnum_val) != NO_ERROR)
12879  {
12880  goto exit_on_error;
12881  }
12882 
12883  if (xasl->save_instnum_val && pr_clone_value (dbvalp, xasl->save_instnum_val) != NO_ERROR)
12884  {
12885  goto exit_on_error;
12886  }
12887  }
12888 
12891 
12892  return NO_ERROR;
12893 
12894 exit_on_error:
12895  return ER_FAILED;
12896 }
12897 
12898 /*
12899  * qexec_start_mainblock_iterations () -
12900  * return: NO_ERROR, or ER_code
12901  * xasl(in) : XASL Tree pointer
12902  * xasl_state(in) : XASL tree state information
12903  *
12904  * Note: This routines performs the start-up operations for a main
12905  * procedure block iteration. The main procedure block nodes can
12906  * be of type BUILDLIST_PROC, BUILDVALUE, UNION_PROC,
12907  * DIFFERENCE_PROC and INTERSECTION_PROC.
12908  */
12909 int
12911 {
12912  QFILE_TUPLE_VALUE_TYPE_LIST type_list;
12913  QFILE_LIST_ID *t_list_id = NULL;
12914  int ls_flag = 0;
12915 
12916  switch (xasl->type)
12917  {
12918  case CONNECTBY_PROC:
12919  {
12920  if (xasl->list_id->type_list.type_cnt == 0)
12921  {
12922  if (qdata_get_valptr_type_list (thread_p, xasl->outptr_list, &type_list) != NO_ERROR)
12923  {
12924  if (type_list.domp)
12925  {
12926  db_private_free_and_init (thread_p, type_list.domp);
12927  }
12929  }
12930 
12931  QFILE_SET_FLAG (ls_flag, QFILE_FLAG_ALL);
12932  t_list_id = qfile_open_list (thread_p, &type_list, NULL, xasl_state->query_id, ls_flag);
12933  if (t_list_id == NULL)
12934  {
12935  if (type_list.domp)
12936  {
12937  db_private_free_and_init (thread_p, type_list.domp);
12938  }
12939  if (t_list_id)
12940  {
12941  QFILE_FREE_AND_INIT_LIST_ID (t_list_id);
12942  }
12944  }
12945 
12946  if (type_list.domp)
12947  {
12948  db_private_free_and_init (thread_p, type_list.domp);
12949  }
12950 
12951  if (qfile_copy_list_id (xasl->list_id, t_list_id, true) != NO_ERROR)
12952  {
12953  QFILE_FREE_AND_INIT_LIST_ID (t_list_id);
12955  } /* if */
12956  QFILE_FREE_AND_INIT_LIST_ID (t_list_id);
12957  }
12958  }
12959  break;
12960 
12961  case BUILDLIST_PROC: /* start BUILDLIST_PROC iterations */
12962  {
12963  BUILDLIST_PROC_NODE *buildlist = &xasl->proc.buildlist;
12964 
12965  /* Initialize extendible hash files for SELECT statement generated for multi UPDATE/DELETE */
12967  {
12968  if (qexec_init_upddel_ehash_files (thread_p, xasl) != NO_ERROR)
12969  {
12971  }
12972  }
12973  else
12974  {
12975  buildlist->upddel_oid_locator_ehids = NULL;
12976  }
12977 
12978  /* initialize groupby_num() value for BUILDLIST_PROC */
12979  if (buildlist->g_grbynum_val)
12980  {
12981  db_make_bigint (buildlist->g_grbynum_val, 0);
12982  }
12983 
12984  if (xasl->list_id->type_list.type_cnt == 0)
12985  {
12986  if (qdata_get_valptr_type_list (thread_p, xasl->outptr_list, &type_list) != NO_ERROR)
12987  {
12988  if (type_list.domp)
12989  {
12990  db_private_free_and_init (thread_p, type_list.domp);
12991  }
12993  }
12994 
12995 
12996  QFILE_SET_FLAG (ls_flag, QFILE_FLAG_ALL);
12998  && buildlist->groupby_list == NULL && buildlist->a_eval_list == NULL
12999  && (xasl->orderby_list == NULL || XASL_IS_FLAGED (xasl, XASL_SKIP_ORDERBY_LIST))
13000  && xasl->option != Q_DISTINCT)
13001  {
13003  }
13004 
13005  t_list_id = qfile_open_list (thread_p, &type_list, xasl->after_iscan_list, xasl_state->query_id, ls_flag);
13006  if (t_list_id == NULL)
13007  {
13008  if (type_list.domp)
13009  {
13010  db_private_free_and_init (thread_p, type_list.domp);
13011  }
13012  if (t_list_id)
13013  {
13014  QFILE_FREE_AND_INIT_LIST_ID (t_list_id);
13015  }
13017  }
13018 
13019  if (type_list.domp)
13020  {
13021  db_private_free_and_init (thread_p, type_list.domp);
13022  }
13023 
13024  if (qfile_copy_list_id (xasl->list_id, t_list_id, true) != NO_ERROR)
13025  {
13026  QFILE_FREE_AND_INIT_LIST_ID (t_list_id);
13028  } /* if */
13029 
13030  QFILE_FREE_AND_INIT_LIST_ID (t_list_id);
13031 
13032  if (xasl->orderby_list != NULL)
13033  {
13034  if (qexec_setup_topn_proc (thread_p, xasl, &xasl_state->vd) != NO_ERROR)
13035  {
13037  }
13038  }
13039  }
13040  break;
13041  }
13042 
13043  case BUILD_SCHEMA_PROC: /* start BUILDSCHEMA_PROC iterations */
13044  {
13045  if (xasl->list_id->type_list.type_cnt == 0)
13046  {
13047  if (qdata_get_valptr_type_list (thread_p, xasl->outptr_list, &type_list) != NO_ERROR)
13048  {
13049  if (type_list.domp)
13050  {
13051  db_private_free_and_init (thread_p, type_list.domp);
13052  }
13054  }
13055 
13056  QFILE_SET_FLAG (ls_flag, QFILE_FLAG_ALL);
13057  t_list_id = qfile_open_list (thread_p, &type_list, NULL, xasl_state->query_id, ls_flag);
13058  if (t_list_id == NULL)
13059  {
13060  if (type_list.domp)
13061  {
13062  db_private_free_and_init (thread_p, type_list.domp);
13063  }
13064  if (t_list_id)
13065  {
13066  qfile_free_list_id (t_list_id);
13067  }
13069  }
13070 
13071  if (type_list.domp)
13072  {
13073  db_private_free_and_init (thread_p, type_list.domp);
13074  }
13075 
13076  if (qfile_copy_list_id (xasl->list_id, t_list_id, true) != NO_ERROR)
13077  {
13078  qfile_free_list_id (t_list_id);
13080  } /* if */
13081 
13082  qfile_free_list_id (t_list_id);
13083  }
13084 
13085  qexec_clear_regu_list (thread_p, xasl, xasl->outptr_list->valptrp, true);
13086  break;
13087  }
13088 
13089  case BUILDVALUE_PROC: /* start BUILDVALUE_PROC iterations */
13090  {
13091  BUILDVALUE_PROC_NODE *buildvalue = &xasl->proc.buildvalue;
13092 
13093  /* set groupby_num() value as 1 for BUILDVALUE_PROC */
13094  if (buildvalue->grbynum_val)
13095  {
13096  db_make_bigint (buildvalue->grbynum_val, 1);
13097  }
13098 
13099  /* initialize aggregation list */
13100  if (qdata_initialize_aggregate_list (thread_p, buildvalue->agg_list, xasl_state->query_id) != NO_ERROR)
13101  {
13103  }
13104  break;
13105  }
13106 
13107  case MERGELIST_PROC:
13108  case UNION_PROC:
13109  case DIFFERENCE_PROC:
13110  case INTERSECTION_PROC: /* start SET block iterations */
13111  break;
13112 
13113  case CTE_PROC:
13114  break;
13115 
13116  default:
13119  } /* switch */
13120 
13121  /* initialize inst_num() value, instnum_flag */
13122  if (xasl->instnum_val && qexec_init_instnum_val (xasl, thread_p, xasl_state) != NO_ERROR)
13123  {
13124  goto exit_on_error;
13125  }
13126 
13127  /* initialize orderby_num() value */
13128  if (xasl->ordbynum_val)
13129  {
13130  db_make_bigint (xasl->ordbynum_val, 0);
13131  }
13132 
13133  if (XASL_IS_FLAGED (xasl, XASL_HAS_CONNECT_BY))
13134  {
13135  /* initialize level_val value */
13136  if (xasl->level_val)
13137  {
13138  db_make_int (xasl->level_val, 0);
13139  }
13140  /* initialize isleaf_val value */
13141  if (xasl->isleaf_val)
13142  {
13143  db_make_int (xasl->isleaf_val, 0);
13144  }
13145  /* initialize iscycle_val value */
13146  if (xasl->iscycle_val)
13147  {
13148  db_make_int (xasl->iscycle_val, 0);
13149  }
13150  }
13151 
13152  return NO_ERROR;
13153 
13154 exit_on_error:
13155 
13156  if (xasl->type == BUILDLIST_PROC)
13157  {
13158  if (xasl->proc.buildlist.upddel_oid_locator_ehids != NULL)
13159  {
13160  qexec_destroy_upddel_ehash_files (thread_p, xasl);
13161  }
13162  }
13163  return ER_FAILED;
13164 }
13165 
13166 /*
13167  * qexec_end_buildvalueblock_iterations () -
13168  * return: NO_ERROR or ER_code
13169  * xasl(in) : XASL Tree pointer
13170  * xasl_state(in) : XASL tree state information
13171  * tplrec(out) : Tuple record descriptor to store result tuples
13172  *
13173  * Note: This routines performs the finish-up operations for BUILDVALUE
13174  * block iteration.
13175  */
13176 static int
13178  QFILE_TUPLE_RECORD * tplrec)
13179 {
13180  QFILE_LIST_ID *t_list_id = NULL;
13181  int status = NO_ERROR;
13182  int ls_flag = 0;
13183  QPROC_TPLDESCR_STATUS tpldescr_status;
13184  DB_LOGICAL ev_res = V_UNKNOWN;
13185  QFILE_LIST_ID *output = NULL;
13186  QFILE_TUPLE_VALUE_TYPE_LIST type_list;
13187  BUILDVALUE_PROC_NODE *buildvalue = &xasl->proc.buildvalue;
13188 
13189  /* make final pass on aggregate list nodes */
13190  if (buildvalue->agg_list && qdata_finalize_aggregate_list (thread_p, buildvalue->agg_list, false) != NO_ERROR)
13191  {
13193  }
13194 
13195  /* evaluate having predicate */
13196  if (buildvalue->having_pred != NULL)
13197  {
13198  ev_res = eval_pred (thread_p, buildvalue->having_pred, &xasl_state->vd, NULL);
13199  if (ev_res == V_ERROR)
13200  {
13202  }
13203  else if (ev_res != V_TRUE
13204  && qdata_set_valptr_list_unbound (thread_p, xasl->outptr_list, &xasl_state->vd) != NO_ERROR)
13205  {
13207  }
13208  }
13209 
13210  /* a list of one tuple with a single value needs to be produced */
13211  if (qdata_get_valptr_type_list (thread_p, xasl->outptr_list, &type_list) != NO_ERROR)
13212  {
13214  }
13215 
13216  /* If BUILDVALUE_PROC does not have 'order by'(xasl->orderby_list), then the list file to be open at here will be the
13217  * last one. Otherwise, the last list file will be open at qexec_orderby_distinct(). (Note that only one that can
13218  * have 'group by' is BUILDLIST_PROC type.) And, the top most XASL is the other condition for the list file to be the
13219  * last result file. */
13220  QFILE_SET_FLAG (ls_flag, QFILE_FLAG_ALL);
13222  && (xasl->orderby_list == NULL || XASL_IS_FLAGED (xasl, XASL_SKIP_ORDERBY_LIST)) && xasl->option != Q_DISTINCT)
13223  {
13225  }
13226  t_list_id = qfile_open_list (thread_p, &type_list, NULL, xasl_state->query_id, ls_flag);
13227  if (t_list_id == NULL)
13228  {
13229  if (type_list.domp)
13230  {
13231  db_private_free_and_init (thread_p, type_list.domp);
13232  }
13234  }
13235 
13236  /***** WHAT IN THE WORLD IS THIS? *****/
13237  if (type_list.domp)
13238  {
13239  db_private_free_and_init (thread_p, type_list.domp);
13240  }
13241 
13242  if (qfile_copy_list_id (xasl->list_id, t_list_id, true) != NO_ERROR)
13243  {
13245  }
13246 
13247  output = xasl->list_id;
13248  QFILE_FREE_AND_INIT_LIST_ID (t_list_id);
13249 
13250  if (buildvalue->having_pred == NULL || ev_res == V_TRUE)
13251  {
13252  tpldescr_status = qexec_generate_tuple_descriptor (thread_p, xasl->list_id, xasl->outptr_list, &xasl_state->vd);
13253  if (tpldescr_status == QPROC_TPLDESCR_FAILURE)
13254  {
13256  }
13257 
13258  switch (tpldescr_status)
13259  {
13261  /* build tuple into the list file page */
13262  if (qfile_generate_tuple_into_list (thread_p, xasl->list_id, T_NORMAL) != NO_ERROR)
13263  {
13265  }
13266  break;
13267 
13270  if (tplrec->tpl == NULL)
13271  {
13272  /* allocate tuple descriptor */
13273  tplrec->size = DB_PAGESIZE;
13274  tplrec->tpl = (QFILE_TUPLE) db_private_alloc (thread_p, DB_PAGESIZE);
13275  if (tplrec->tpl == NULL)
13276  {
13278  }
13279  }
13280  if (qdata_copy_valptr_list_to_tuple (thread_p, xasl->outptr_list, &xasl_state->vd, tplrec) != NO_ERROR)
13281  {
13283  }
13284  if (qfile_add_tuple_to_list (thread_p, xasl->list_id, tplrec->tpl) != NO_ERROR)
13285  {
13287  }
13288  break;
13289 
13290  default:
13291  break;
13292  }
13293  }
13294 
13295 end:
13296 
13297  QEXEC_CLEAR_AGG_LIST_VALUE (buildvalue->agg_list);
13298  if (t_list_id)
13299  {
13300  QFILE_FREE_AND_INIT_LIST_ID (t_list_id);
13301  }
13302  if (output)
13303  {
13304  qfile_close_list (thread_p, output);
13305  }
13306 
13307  return status;
13308 
13309 exit_on_error:
13310 
13311  status = ER_FAILED;
13312  goto end;
13313 }
13314 
13315 /*
13316  * qexec_end_mainblock_iterations () -
13317  * return: NO_ERROR, or ER_code
13318  * xasl(in) : XASL Tree pointer
13319  * xasl_state(in) : XASL tree state information
13320  * tplrec(out) : Tuple record descriptor to store result tuples
13321  *
13322  * Note: This routines performs the finish-up operations for a main
13323  * procedure block iteration. The main procedure block nodes can
13324  * be of type BUILDLIST_PROC, BUILDVALUE, UNION_PROC,
13325  * DIFFERENCE_PROC and INTERSECTION_PROC.
13326  */
13327 static int
13329  QFILE_TUPLE_RECORD * tplrec)
13330 {
13331  QFILE_LIST_ID *t_list_id = NULL;
13332  int status = NO_ERROR;
13333  bool distinct_needed;
13334  int ls_flag = 0;
13335 
13336  distinct_needed = (xasl->option == Q_DISTINCT) ? true : false;
13337 
13338 #if defined (ENABLE_COMPOSITE_LOCK)
13339  /* Acquire the lockset if composite locking is enabled. */
13341  && (!XASL_IS_FLAGED (xasl, XASL_MULTI_UPDATE_AGG)))
13342  {
13343  if (lock_finalize_composite_lock (thread_p, &xasl->composite_lock) != LK_GRANTED)
13344  {
13345  return ER_FAILED;
13346  }
13347  }
13348 #endif /* defined (ENABLE_COMPOSITE_LOCK) */
13349 
13350  switch (xasl->type)
13351  {
13352 
13353  case BUILDLIST_PROC: /* end BUILDLIST_PROC iterations */
13354  /* Destroy the extendible hash files for SELECT statement generated for UPDATE/DELETE */
13355  if (xasl->proc.buildlist.upddel_oid_locator_ehids != NULL)
13356  {
13357  qexec_destroy_upddel_ehash_files (thread_p, xasl);
13358  }
13359  /* fall through */
13360  case CONNECTBY_PROC:
13361  case BUILD_SCHEMA_PROC:
13362  /* close the list file */
13363  qfile_close_list (thread_p, xasl->list_id);
13364  break;
13365 
13366  case MERGELIST_PROC:
13367  /* do a direct list file merge to generate resultant list file */
13368  if (qexec_merge_listfiles (thread_p, xasl, xasl_state) != NO_ERROR)
13369  {
13371  }
13372  break;
13373 
13374  case BUILDVALUE_PROC: /* end BUILDVALUE_PROC iterations */
13375  status = qexec_end_buildvalueblock_iterations (thread_p, xasl, xasl_state, tplrec);
13376  break;
13377 
13378  case UNION_PROC:
13379  case DIFFERENCE_PROC:
13380  case INTERSECTION_PROC:
13381  if (xasl->type == UNION_PROC)
13382  {
13383  QFILE_SET_FLAG (ls_flag, QFILE_FLAG_UNION);
13384  }
13385  else if (xasl->type == DIFFERENCE_PROC)
13386  {
13388  }
13389  else
13390  {
13392  }
13393 
13394  if (distinct_needed)
13395  {
13397  }
13398  else
13399  {
13400  QFILE_SET_FLAG (ls_flag, QFILE_FLAG_ALL);
13401  }
13402 
13403  /* For UNION_PROC, DIFFERENCE_PROC, and INTERSECTION_PROC, if they do not have 'order by'(xasl->orderby_list),
13404  * then the list file to be open at here will be the last one. Otherwise, the last list file will be open at
13405  * qexec_groupby() or qexec_orderby_distinct(). (Note that only one that can have 'group by' is BUILDLIST_PROC
13406  * type.) And, the top most XASL is the other condition for the list file to be the last result file. */
13407 
13409  && (xasl->orderby_list == NULL || XASL_IS_FLAGED (xasl, XASL_SKIP_ORDERBY_LIST)))
13410  {
13412  }
13413 
13414  t_list_id =
13415  qfile_combine_two_list (thread_p, xasl->proc.union_.left->list_id, xasl->proc.union_.right->list_id, ls_flag);
13416  distinct_needed = false;
13417  if (!t_list_id)
13418  {
13420  }
13421  if (qfile_copy_list_id (xasl->list_id, t_list_id, true) != NO_ERROR)
13422  {
13424  }
13425  QFILE_FREE_AND_INIT_LIST_ID (t_list_id);
13426  break;
13427 
13428  case CTE_PROC:
13429  /* close the list file */
13430  qfile_close_list (thread_p, xasl->list_id);
13431  break;
13432 
13433  default:
13436  } /* switch */
13437 
13438  /* DISTINCT processing (i.e, duplicates elimination) is performed at qexec_orderby_distinct() after GROUP BY
13439  * processing */
13440 
13441 success:
13442  if (t_list_id)
13443  {
13444  QFILE_FREE_AND_INIT_LIST_ID (t_list_id);
13445  }
13446  return status;
13447 
13448 exit_on_error:
13449  status = ER_FAILED;
13450  goto success;
13451 
13452 }
13453 
13454 /*
13455  * qexec_clear_mainblock_iterations () -
13456  * return:
13457  * xasl(in) : XASL Tree pointer
13458  */
13459 static void
13461 {
13462  AGGREGATE_TYPE *agg_p;
13463 
13464  switch (xasl->type)
13465  {
13466  case BUILDLIST_PROC:
13467  /* Destroy the extendible hash files for SELECT statement generated for UPDATE/DELETE */
13468  if (xasl->proc.buildlist.upddel_oid_locator_ehids != NULL)
13469  {
13470  qexec_destroy_upddel_ehash_files (thread_p, xasl);
13471  }
13472  /* fall through */
13473  case CONNECTBY_PROC:
13474  qfile_close_list (thread_p, xasl->list_id);
13475  break;
13476 
13477  case BUILDVALUE_PROC:
13478  for (agg_p = xasl->proc.buildvalue.agg_list; agg_p != NULL; agg_p = agg_p->next)
13479  {
13480  qfile_close_list (thread_p, agg_p->list_id);
13481  qfile_destroy_list (thread_p, agg_p->list_id);
13482  }
13483  break;
13484 
13485  case UNION_PROC:
13486  case DIFFERENCE_PROC:
13487  case INTERSECTION_PROC:
13488  case OBJFETCH_PROC:
13489  case SCAN_PROC:
13490  case MERGELIST_PROC:
13491  case UPDATE_PROC:
13492  case DELETE_PROC:
13493  case INSERT_PROC:
13494  case DO_PROC:
13495  case MERGE_PROC:
13496  case BUILD_SCHEMA_PROC:
13497  case CTE_PROC:
13498  break;
13499 
13500  default:
13502  break;
13503  }
13504 
13505  return;
13506 }
13507 
13508 /*
13509  * qexec_execute_mainblock () -
13510  * return: NO_ERROR, or ER_code
13511  * xasl(in) : XASL Tree pointer
13512  * xasl_state(in) : XASL state information
13513  * p_class_instance_lock_info(in/out): class instance lock info
13514  *
13515  */
13516 int
13518  UPDDEL_CLASS_INSTANCE_LOCK_INFO * p_class_instance_lock_info)
13519 {
13520  int error = NO_ERROR;
13521  bool on_trace;
13522  TSC_TICKS start_tick, end_tick;
13523  TSCTIMEVAL tv_diff;
13524  UINT64 old_fetches = 0, old_ioreads = 0;
13525 
13527  {
13530  return error;
13531  }
13532  thread_inc_recursion_depth (thread_p);
13533 
13534  on_trace = thread_is_on_trace (thread_p);
13535  if (on_trace)
13536  {
13537  tsc_getticks (&start_tick);
13538 
13539  old_fetches = perfmon_get_from_statistic (thread_p, PSTAT_PB_NUM_FETCHES);
13540  old_ioreads = perfmon_get_from_statistic (thread_p, PSTAT_PB_NUM_IOREADS);
13541  }
13542 
13543  error = qexec_execute_mainblock_internal (thread_p, xasl, xstate, p_class_instance_lock_info);
13544 
13545  if (on_trace)
13546  {
13547  tsc_getticks (&end_tick);
13548  tsc_elapsed_time_usec (&tv_diff, end_tick, start_tick);
13549  TSC_ADD_TIMEVAL (xasl->xasl_stats.elapsed_time, tv_diff);
13550 
13551  xasl->xasl_stats.fetches += perfmon_get_from_statistic (thread_p, PSTAT_PB_NUM_FETCHES) - old_fetches;
13552  xasl->xasl_stats.ioreads += perfmon_get_from_statistic (thread_p, PSTAT_PB_NUM_IOREADS) - old_ioreads;
13553  }
13554 
13555  thread_dec_recursion_depth (thread_p);
13556 
13557  return error;
13558 }
13559 
13560 /*
13561  * qexec_check_limit_clause () - checks validity of limit clause
13562  * return: NO_ERROR, or ER_code
13563  * xasl(in): XASL Tree pointer
13564  * xasl_state(in): XASL state information
13565  * empty_result(out): true if no result will be generated
13566  *
13567  */
13568 static int
13569 qexec_check_limit_clause (THREAD_ENTRY * thread_p, XASL_NODE * xasl, XASL_STATE * xasl_state, bool * empty_result)
13570 {
13571  DB_VALUE *limit_valp;
13572  DB_VALUE zero_val;
13573  DB_VALUE_COMPARE_RESULT cmp_with_zero;
13574 
13575  /* init output */
13576  *empty_result = false;
13577 
13578  db_make_int (&zero_val, 0);
13579 
13580  if (xasl->limit_offset != NULL)
13581  {
13582  /* limit_offset should be greater than 0. Otherwise, raises an error. */
13583  if (fetch_peek_dbval (thread_p, xasl->limit_offset, &xasl_state->vd, NULL, NULL, NULL, &limit_valp) != NO_ERROR)
13584  {
13585  return ER_FAILED;
13586  }
13587 
13588  cmp_with_zero = tp_value_compare (limit_valp, &zero_val, 1, 0);
13589  if (cmp_with_zero != DB_GT && cmp_with_zero != DB_EQ)
13590  {
13591  /* still want better error code */
13593  return ER_FAILED;
13594  }
13595  }
13596 
13597  if (xasl->limit_row_count != NULL)
13598  {
13599  /* When limit_row_count is
13600  * > 0, go to execute the query.
13601  * = 0, no result will be generated. stop execution for optimization.
13602  * < 0, raise an error.
13603  */
13604  if (fetch_peek_dbval (thread_p, xasl->limit_row_count, &xasl_state->vd, NULL, NULL, NULL, &limit_valp) !=
13605  NO_ERROR)
13606  {
13607  return ER_FAILED;
13608  }
13609 
13610  cmp_with_zero = tp_value_compare (limit_valp, &zero_val, 1, 0);
13611  if (cmp_with_zero == DB_GT)
13612  {
13613  /* validated */
13614  return NO_ERROR;
13615  }
13616  else if (cmp_with_zero == DB_EQ)
13617  {
13618  *empty_result = true;
13619  return NO_ERROR;
13620  }
13621  else
13622  {
13623  /* still want better error code */
13625  return ER_FAILED;
13626  }
13627  }
13628 
13629  return NO_ERROR;
13630 }
13631 
13632 /*
13633  * qexec_execute_mainblock_internal () -
13634  * return: NO_ERROR, or ER_code
13635  * xasl(in) : XASL Tree pointer
13636  * xasl_state(in) : XASL state information
13637  * p_class_instance_lock_info(in/out): class instance lock info
13638  *
13639  */
13640 static int
13642  UPDDEL_CLASS_INSTANCE_LOCK_INFO * p_class_instance_lock_info)
13643 {
13644  XASL_NODE *xptr, *xptr2;
13645  QFILE_TUPLE_RECORD tplrec = { NULL, 0 };
13646  SCAN_CODE qp_scan;
13647  int level;
13648  int spec_level;
13649  ACCESS_SPEC_TYPE *spec_ptr[2];
13650  ACCESS_SPEC_TYPE *specp;
13651  XASL_SCAN_FNC_PTR func_vector = (XASL_SCAN_FNC_PTR) NULL;
13652  int multi_upddel = false;
13653  QFILE_LIST_MERGE_INFO *merge_infop;
13654  XASL_NODE *outer_xasl = NULL, *inner_xasl = NULL;
13655  XASL_NODE *fixed_scan_xasl = NULL;
13656  bool iscan_oid_order, force_select_lock = false;
13657  bool has_index_scan = false;
13658  int old_wait_msecs, wait_msecs;
13659  int error;
13660  bool empty_result = false;
13661  bool scan_immediately_stop = false;
13662  int tran_index = LOG_FIND_THREAD_TRAN_INDEX (thread_p);
13663  bool instant_lock_mode_started = false;
13664  bool mvcc_select_lock_needed;
13665  bool old_no_logging;
13666 
13667  /*
13668  * Pre_processing
13669  */
13670 
13671  if (xasl->limit_offset != NULL || xasl->limit_row_count != NULL)
13672  {
13673  if (qexec_check_limit_clause (thread_p, xasl, xasl_state, &empty_result) != NO_ERROR)
13674  {
13675  goto exit_on_error;
13676  }
13677 
13678  if (empty_result == true)
13679  {
13680  if (XASL_IS_FLAGED (xasl, XASL_TOP_MOST_XASL))
13681  {
13682  er_log_debug (ARG_FILE_LINE, "This statement has no record by 'limit 0' clause.\n");
13683  return NO_ERROR;
13684  }
13685  else
13686  {
13687  scan_immediately_stop = true;
13688  }
13689  }
13690  }
13691 
13692  switch (xasl->type)
13693  {
13694  case CONNECTBY_PROC:
13695  break;
13696 
13697  case UPDATE_PROC:
13698  CHECK_MODIFICATION_NO_RETURN (thread_p, error);
13699  if (error != NO_ERROR)
13700  {
13701  return error;
13702  }
13703 
13704  old_wait_msecs = XASL_WAIT_MSECS_NOCHANGE;
13706  {
13707  old_wait_msecs = xlogtb_reset_wait_msecs (thread_p, xasl->proc.update.wait_msecs);
13708  }
13709  error = qexec_execute_update (thread_p, xasl, false, xasl_state);
13710  if (old_wait_msecs != XASL_WAIT_MSECS_NOCHANGE)
13711  {
13712  (void) xlogtb_reset_wait_msecs (thread_p, old_wait_msecs);
13713  }
13714  if (error != NO_ERROR)
13715  {
13716  return error;
13717  }
13718  /* monitor */
13720  break;
13721 
13722  case DELETE_PROC:
13723  CHECK_MODIFICATION_NO_RETURN (thread_p, error);
13724  if (error != NO_ERROR)
13725  {
13726  return error;
13727  }
13728 
13729  old_wait_msecs = XASL_WAIT_MSECS_NOCHANGE;
13731  {
13732  old_wait_msecs = xlogtb_reset_wait_msecs (thread_p, xasl->proc.delete_.wait_msecs);
13733  }
13734  error = qexec_execute_delete (thread_p, xasl, xasl_state);
13735  if (old_wait_msecs != XASL_WAIT_MSECS_NOCHANGE)
13736  {
13737  (void) xlogtb_reset_wait_msecs (thread_p, old_wait_msecs);
13738  }
13739  if (error != NO_ERROR)
13740  {
13741  return error;
13742  }
13743  /* monitor */
13745  break;
13746 
13747  case INSERT_PROC:
13748  CHECK_MODIFICATION_NO_RETURN (thread_p, error);
13749  if (error != NO_ERROR)
13750  {
13751  return error;
13752  }
13753 
13754  old_wait_msecs = XASL_WAIT_MSECS_NOCHANGE;
13756  {
13757  old_wait_msecs = xlogtb_reset_wait_msecs (thread_p, xasl->proc.insert.wait_msecs);
13758  }
13759 
13760  old_no_logging = thread_p->no_logging;
13761 
13762  error = qexec_execute_insert (thread_p, xasl, xasl_state, false);
13763 
13764  thread_p->no_logging = old_no_logging;
13765 
13766  if (old_wait_msecs != XASL_WAIT_MSECS_NOCHANGE)
13767  {
13768  (void) xlogtb_reset_wait_msecs (thread_p, old_wait_msecs);
13769  }
13770  if (error != NO_ERROR)
13771  {
13772  return error;
13773  }
13774  /* monitor */
13776  break;
13777 
13778  case DO_PROC:
13779  error = qexec_execute_do_stmt (thread_p, xasl, xasl_state);
13780  if (error != NO_ERROR)
13781  {
13782  return error;
13783  }
13784  break;
13785 
13786  case MERGE_PROC:
13787  CHECK_MODIFICATION_NO_RETURN (thread_p, error);
13788  if (error != NO_ERROR)
13789  {
13790  return error;
13791  }
13792 
13793  /* setup waiting time */
13794  old_wait_msecs = wait_msecs = XASL_WAIT_MSECS_NOCHANGE;
13795  if (xasl->proc.merge.update_xasl)
13796  {
13797  wait_msecs = xasl->proc.merge.update_xasl->proc.update.wait_msecs;
13798  }
13799  else if (xasl->proc.merge.insert_xasl)
13800  {
13801  wait_msecs = xasl->proc.merge.insert_xasl->proc.insert.wait_msecs;
13802  }
13803 
13804  if (wait_msecs != XASL_WAIT_MSECS_NOCHANGE)
13805  {
13806  old_wait_msecs = xlogtb_reset_wait_msecs (thread_p, wait_msecs);
13807  }
13808 
13809  /* execute merge */
13810  error = qexec_execute_merge (thread_p, xasl, xasl_state);
13811 
13812  if (old_wait_msecs != XASL_WAIT_MSECS_NOCHANGE)
13813  {
13814  (void) xlogtb_reset_wait_msecs (thread_p, old_wait_msecs);
13815  }
13816 
13817  if (error != NO_ERROR)
13818  {
13819  return error;
13820  }
13821  break;
13822 
13823  case BUILD_SCHEMA_PROC:
13824  switch (xasl->spec_list->s.cls_node.schema_type)
13825  {
13826  case INDEX_SCHEMA:
13827  error = qexec_execute_build_indexes (thread_p, xasl, xasl_state);
13828  if (error != NO_ERROR)
13829  {
13830  return error;
13831  }
13832  break;
13833 
13834  case COLUMNS_SCHEMA:
13835  case FULL_COLUMNS_SCHEMA:
13836  error = qexec_execute_build_columns (thread_p, xasl, xasl_state);
13837  if (error != NO_ERROR)
13838  {
13839  return error;
13840  }
13841  break;
13842 
13843  default:
13844  assert (false);
13845  return ER_FAILED;
13846  }
13847  break;
13848 
13849  default:
13850  /* check for push list query */
13851  if (xasl->type == BUILDLIST_PROC && xasl->proc.buildlist.push_list_id)
13852  {
13853  if (qfile_copy_list_id (xasl->list_id, xasl->proc.buildlist.push_list_id, false) != NO_ERROR)
13854  {
13856  }
13857  xasl->status = XASL_SUCCESS;
13858  return NO_ERROR;
13859  }
13860 
13861  /* click counter check */
13862  if (xasl->selected_upd_list)
13863  {
13864  CHECK_MODIFICATION_NO_RETURN (thread_p, error);
13865  if (error != NO_ERROR)
13866  {
13867  return error;
13868  }
13869 
13870  if (!QEXEC_SEL_UPD_USE_REEVALUATION (xasl))
13871  {
13872  /* Reevaluate at select since can't reevaluate in execute_selupd_list. Need to start instant lock mode. */
13873  lock_start_instant_lock_mode (tran_index);
13874  instant_lock_mode_started = true;
13875  force_select_lock = true;
13876  }
13877  }
13878 
13879  if (xasl->type == BUILDLIST_PROC)
13880  {
13881  AGGREGATE_TYPE *agg_p;
13882 
13883  /* prepare hash table for aggregate evaluation */
13884  if (xasl->proc.buildlist.g_hash_eligible)
13885  {
13886  if (xasl->spec_list && xasl->spec_list->indexptr && xasl->spec_list->indexptr->groupby_skip)
13887  {
13888  /* disable hash aggregate evaluation when group by skip is possible */
13889  xasl->proc.buildlist.g_hash_eligible = 0;
13890  }
13891  else if (qexec_alloc_agg_hash_context (thread_p, &xasl->proc.buildlist, xasl_state) != NO_ERROR)
13892  {
13894  }
13895  }
13896 
13897  /* nullify domains */
13898  for (agg_p = xasl->proc.buildlist.g_agg_list; agg_p != NULL; agg_p = agg_p->next)
13899  {
13900  agg_p->accumulator_domain.value_dom = NULL;
13901  agg_p->accumulator_domain.value2_dom = NULL;
13902  }
13903 
13904  /* domains not resolved */
13906  }
13907  else if (xasl->type == BUILDVALUE_PROC)
13908  {
13909  AGGREGATE_TYPE *agg_p;
13910 
13911  /* nullify domains */
13912  for (agg_p = xasl->proc.buildvalue.agg_list; agg_p != NULL; agg_p = agg_p->next)
13913  {
13914  agg_p->accumulator_domain.value_dom = NULL;
13915  agg_p->accumulator_domain.value2_dom = NULL;
13916  }
13917 
13918  /* domains not resolved */
13920  }
13921 
13922  multi_upddel = QEXEC_IS_MULTI_TABLE_UPDATE_DELETE (xasl);
13923 #if defined (ENABLE_COMPOSITE_LOCK)
13924  if (COMPOSITE_LOCK (xasl->scan_op_type) || multi_upddel)
13925  {
13926  if (lock_initialize_composite_lock (thread_p, &xasl->composite_lock) != NO_ERROR)
13927  {
13928  qexec_failure_line (__LINE__, xasl_state);
13930  }
13931  }
13932 #endif /* defined (ENABLE_COMPOSITE_LOCK) */
13933 
13934  if (qexec_for_update_set_class_locks (thread_p, xasl) != NO_ERROR)
13935  {
13937  }
13938 
13939  /* evaluate all the aptr lists in all scans */
13940  for (xptr = xasl; xptr; xptr = xptr->scan_ptr)
13941  {
13942 
13943  merge_infop = NULL; /* init */
13944 
13945  if (xptr->type == MERGELIST_PROC)
13946  {
13947  merge_infop = &(xptr->proc.mergelist.ls_merge);
13948 
13949  outer_xasl = xptr->proc.mergelist.outer_xasl;
13950  inner_xasl = xptr->proc.mergelist.inner_xasl;
13951  }
13952 
13953  for (xptr2 = xptr->aptr_list; xptr2; xptr2 = xptr2->next)
13954  {
13955  if (merge_infop)
13956  {
13957  if (merge_infop->join_type == JOIN_INNER || merge_infop->join_type == JOIN_LEFT)
13958  {
13959  if (outer_xasl->list_id->type_list.type_cnt > 0 && outer_xasl->list_id->tuple_cnt == 0)
13960  {
13961  /* outer is empty; skip inner */
13962  if (inner_xasl == xptr2)
13963  {
13964  continue;
13965  }
13966  }
13967  }
13968 
13969  if (merge_infop->join_type == JOIN_INNER || merge_infop->join_type == JOIN_RIGHT)
13970  {
13971  if (inner_xasl->list_id->type_list.type_cnt > 0 && inner_xasl->list_id->tuple_cnt == 0)
13972  {
13973  /* inner is empty; skip outer */
13974  if (outer_xasl == xptr2)
13975  {
13976  continue;
13977  }
13978  }
13979  }
13980  }
13981 
13983  {
13984  /* skip if linked to regu var */
13985  continue;
13986  }
13987 
13988  if (xptr2->status == XASL_CLEARED || xptr2->status == XASL_INITIALIZED)
13989  {
13990  if (qexec_execute_mainblock (thread_p, xptr2, xasl_state, NULL) != NO_ERROR)
13991  {
13992  if (tplrec.tpl)
13993  {
13994  db_private_free_and_init (thread_p, tplrec.tpl);
13995  }
13996  qexec_failure_line (__LINE__, xasl_state);
13998  }
13999  }
14000  else
14001  { /* already executed. success or failure */
14002  if (xptr2->status != XASL_SUCCESS)
14003  {
14004  if (tplrec.tpl)
14005  {
14006  db_private_free_and_init (thread_p, tplrec.tpl);
14007  }
14008  qexec_failure_line (__LINE__, xasl_state);
14010  }
14011  }
14012  }
14013  }
14014 
14015 
14016  /* start main block iterations */
14017  if (qexec_start_mainblock_iterations (thread_p, xasl, xasl_state) != NO_ERROR)
14018  {
14020  }
14021 
14022  /*
14023  * Processing
14024  */
14025  /* Block out main part of query processing for performance profiling of JDBC driver and CAS side. Main purpose of
14026  * this modification is to pretend that the server's scan time is very fast so that it affect only little portion
14027  * of whole turnaround time in the point of view of the JDBC driver. */
14028 
14029  /* iterative processing is done only for XASL blocks that has access specification list blocks. */
14030  if (xasl->spec_list)
14031  {
14032  /* Decide which scan will use fixed flags and which won't. There are several cases here: 1. Do not use fixed
14033  * scans if locks on objects are required. 2. Disable all fixed scans if any index scan is used (this is
14034  * legacy and should be reconsidered). 3. Disable fixed scan for outer scans. Fixed cannot be allowed while
14035  * new scans start which also need to fix pages. This may lead to page deadlocks. NOTE: Only the innermost
14036  * scans are allowed fixed scans. */
14037  if (COMPOSITE_LOCK (xasl->scan_op_type))
14038  {
14039  /* Do locking on each instance instead of composite locking */
14040  /* Fall through */
14041  }
14042  else
14043  {
14044  for (xptr = xasl; xptr; xptr = xptr->scan_ptr)
14045  {
14046  specp = xptr->spec_list;
14047  for (; specp; specp = specp->next)
14048  {
14049  if (specp->type == TARGET_CLASS)
14050  {
14051  /* Update fixed scan XASL */
14052  fixed_scan_xasl = xptr;
14053  if (IS_ANY_INDEX_ACCESS (specp->access))
14054  {
14055  has_index_scan = true;
14056  break;
14057  }
14058  }
14059  }
14060  if (has_index_scan)
14061  {
14062  /* Stop search */
14063  break;
14064  }
14065  specp = xptr->merge_spec;
14066  if (specp)
14067  {
14068  if (specp->type == TARGET_CLASS)
14069  {
14070  /* Update fixed scan XASL */
14071  fixed_scan_xasl = xptr;
14072  if (IS_ANY_INDEX_ACCESS (specp->access))
14073  {
14074  has_index_scan = true;
14075  break;
14076  }
14077  }
14078  }
14079  }
14080  }
14081  if (has_index_scan)
14082  {
14083  /* Index found, no fixed is allowed */
14084  fixed_scan_xasl = NULL;
14085  }
14086  if (XASL_IS_FLAGED (xasl, XASL_NO_FIXED_SCAN))
14087  {
14088  /* no fixed scan if it was decided so during compilation */
14089  fixed_scan_xasl = NULL;
14090  }
14091  if (xasl->dptr_list != NULL)
14092  {
14093  /* correlated subquery found, no fixed is allowed */
14094  fixed_scan_xasl = NULL;
14095  }
14096  if (xasl->type == BUILDLIST_PROC && xasl->proc.buildlist.eptr_list != NULL)
14097  {
14098  /* subquery in HAVING clause, can't have fixed scan */
14099  fixed_scan_xasl = NULL;
14100  }
14101  for (xptr = xasl->aptr_list; xptr != NULL; xptr = xptr->next)
14102  {
14104  {
14105  /* uncorrelated query that is not pre-executed, but evaluated in a reguvar; no fixed scan in this
14106  * case */
14107  fixed_scan_xasl = NULL;
14108  }
14109  }
14110 
14111  /* open all the scans that are involved within the query, for SCAN blocks */
14112  for (xptr = xasl, level = 0; xptr; xptr = xptr->scan_ptr, level++)
14113  {
14114  /* consider all the access specification nodes */
14115  spec_ptr[0] = xptr->spec_list;
14116  spec_ptr[1] = xptr->merge_spec;
14117  for (spec_level = 0; spec_level < 2; ++spec_level)
14118  {
14119  for (specp = spec_ptr[spec_level]; specp; specp = specp->next)
14120  {
14121  specp->fixed_scan = (xptr == fixed_scan_xasl);
14122 
14123  /* set if the scan will be done in a grouped manner */
14124  if ((level == 0 && xptr->scan_ptr == NULL) && (QPROC_MAX_GROUPED_SCAN_CNT > 0))
14125  {
14126  /* single class query */
14127  specp->grouped_scan = ((QPROC_SINGLE_CLASS_GROUPED_SCAN == 1) ? true : false);
14128  }
14129  else
14130  {
14131  specp->grouped_scan = false;
14132  }
14133 
14134  /* a class attribute scan cannot be grouped */
14135  if (specp->grouped_scan && specp->type == TARGET_CLASS_ATTR)
14136  {
14137  specp->grouped_scan = false;
14138  }
14139 
14140  /* an index scan currently can be grouped, only if it contains only constant key values */
14141  if (specp->grouped_scan && specp->type == TARGET_CLASS && IS_ANY_INDEX_ACCESS (specp->access)
14142  && specp->indexptr->key_info.is_constant == false)
14143  {
14144  specp->grouped_scan = false;
14145  }
14146 
14147  /* inner scan of outer join cannot be grouped */
14148  if (specp->grouped_scan && specp->single_fetch == QPROC_NO_SINGLE_OUTER)
14149  {
14150  specp->grouped_scan = false;
14151  }
14152 
14153  if (specp->grouped_scan && specp->fixed_scan == false)
14154  {
14155  specp->grouped_scan = false;
14156  }
14157 
14158  iscan_oid_order = xptr->iscan_oid_order;
14159 
14160  /* open the scan for this access specification node */
14161  if (level == 0 && spec_level == 1)
14162  {
14163  if (qexec_open_scan (thread_p, specp, xptr->merge_val_list, &xasl_state->vd,
14164  force_select_lock, specp->fixed_scan, specp->grouped_scan,
14165  iscan_oid_order, &specp->s_id, xasl_state->query_id, xasl->scan_op_type,
14166  scan_immediately_stop, &mvcc_select_lock_needed) != NO_ERROR)
14167  {
14168  qexec_clear_mainblock_iterations (thread_p, xasl);
14170  }
14171 
14172  if (p_class_instance_lock_info && specp->type == TARGET_CLASS
14173  && OID_EQ (&specp->s.cls_node.cls_oid, &p_class_instance_lock_info->class_oid)
14174  && mvcc_select_lock_needed)
14175  {
14176  /* the instances are locked at select phase */
14177  p_class_instance_lock_info->instances_locked = true;
14178  }
14179  }
14180  else
14181  {
14182  if (specp->type == TARGET_CLASS && IS_ANY_INDEX_ACCESS (specp->access)
14184  {
14185  specp->grouped_scan = false;
14186  iscan_oid_order = false;
14187  }
14188 
14189  if (qexec_open_scan (thread_p, specp, xptr->val_list, &xasl_state->vd, force_select_lock,
14190  specp->fixed_scan, specp->grouped_scan, iscan_oid_order, &specp->s_id,
14191  xasl_state->query_id, xptr->scan_op_type, scan_immediately_stop,
14192  &mvcc_select_lock_needed) != NO_ERROR)
14193  {
14194  qexec_clear_mainblock_iterations (thread_p, xasl);
14196  }
14197 
14198  if (p_class_instance_lock_info && specp->type == TARGET_CLASS
14199  && OID_EQ (&specp->s.cls_node.cls_oid, &p_class_instance_lock_info->class_oid)
14200  && mvcc_select_lock_needed)
14201  {
14202  /* the instances are locked at select phase */
14203  p_class_instance_lock_info->instances_locked = true;
14204  }
14205  }
14206  }
14207  }
14208  }
14209 
14210  /* allocate xasl scan function vector */
14211  func_vector = (XASL_SCAN_FNC_PTR) db_private_alloc (thread_p, level * sizeof (XSAL_SCAN_FUNC));
14212  if (func_vector == NULL)
14213  {
14214  qexec_clear_mainblock_iterations (thread_p, xasl);
14216  }
14217 
14218  /* determine the type of XASL block associated functions */
14219  if (xasl->merge_spec)
14220  {
14221  func_vector[0] = (XSAL_SCAN_FUNC) qexec_merge_fnc;
14222  /* monitor */
14224  }
14225  else
14226  {
14227  for (xptr = xasl, level = 0; xptr; xptr = xptr->scan_ptr, level++)
14228  {
14229 
14230  /* set all the following scan blocks to off */
14231  xasl->next_scan_block_on = false;
14232 
14233  /* set the associated function with the scan */
14234 
14235  /* Having more than one interpreter function was a bad idea, so I've removed the specialized ones.
14236  * dkh. */
14237  if (level == 0)
14238  {
14239  func_vector[level] = (XSAL_SCAN_FUNC) qexec_intprt_fnc;
14240  }
14241  else
14242  {
14243  func_vector[level] = (XSAL_SCAN_FUNC) qexec_execute_scan;
14244  /* monitor */
14246  }
14247  }
14248  }
14249 
14250  if (XASL_IS_FLAGED (xasl, XASL_HAS_CONNECT_BY))
14251  {
14252  if (xasl->connect_by_ptr == NULL)
14253  {
14254  qexec_clear_mainblock_iterations (thread_p, xasl);
14256  }
14257 
14258  /* initialize CONNECT BY internal lists */
14259  if (qexec_start_connect_by_lists (thread_p, xasl->connect_by_ptr, xasl_state) != NO_ERROR)
14260  {
14261  qexec_clear_mainblock_iterations (thread_p, xasl);
14263  }
14264  }
14265 
14266  if (query_multi_range_opt_check_set_sort_col (thread_p, xasl) != NO_ERROR)
14267  {
14268  qexec_clear_mainblock_iterations (thread_p, xasl);
14270  }
14271 
14272  /* call the first xasl interpreter function */
14273  qp_scan = (*func_vector[0]) (thread_p, xasl, xasl_state, &tplrec, &func_vector[1]);
14274 
14275  if (XASL_IS_FLAGED (xasl, XASL_HAS_CONNECT_BY))
14276  {
14277  /* close CONNECT BY internal lists */
14278  qexec_end_connect_by_lists (thread_p, xasl->connect_by_ptr);
14279  }
14280 
14281  /* free the function vector */
14282  db_private_free_and_init (thread_p, func_vector);
14283 
14284  /* close all the scans that are involved within the query */
14285  for (xptr = xasl, level = 0; xptr; xptr = xptr->scan_ptr, level++)
14286  {
14287  spec_ptr[0] = xptr->spec_list;
14288  spec_ptr[1] = xptr->merge_spec;
14289  for (spec_level = 0; spec_level < 2; ++spec_level)
14290  {
14291  for (specp = spec_ptr[spec_level]; specp; specp = specp->next)
14292  {
14293  qexec_end_scan (thread_p, specp);
14294  qexec_close_scan (thread_p, specp);
14295  }
14296  }
14297  if (xptr->curr_spec != NULL)
14298  {
14299  xptr->curr_spec->curent = NULL;
14300  xptr->curr_spec = NULL;
14301  }
14302  }
14303 
14304  if (qp_scan != S_SUCCESS) /* error case */
14305  {
14306  qexec_clear_mainblock_iterations (thread_p, xasl);
14308  }
14309 
14310  /* process CONNECT BY xasl */
14311  if (XASL_IS_FLAGED (xasl, XASL_HAS_CONNECT_BY))
14312  {
14313  TSC_TICKS start_tick, end_tick;
14314  TSCTIMEVAL tv_diff;
14315 
14316  UINT64 old_fetches = 0, old_ioreads = 0;
14317  XASL_STATS *xasl_stats;
14318  bool on_trace;
14319 
14320  on_trace = thread_is_on_trace (thread_p);
14321  if (on_trace)
14322  {
14323  tsc_getticks (&start_tick);
14324 
14325  old_fetches = perfmon_get_from_statistic (thread_p, PSTAT_PB_NUM_FETCHES);
14326  old_ioreads = perfmon_get_from_statistic (thread_p, PSTAT_PB_NUM_IOREADS);
14327  }
14328 
14329  if (qexec_execute_connect_by (thread_p, xasl->connect_by_ptr, xasl_state, &tplrec) != NO_ERROR)
14330  {
14331  qexec_clear_mainblock_iterations (thread_p, xasl);
14333  }
14334 
14335  /* scan CONNECT BY results, apply WHERE, add to xasl->list_id */
14336  if (qexec_iterate_connect_by_results (thread_p, xasl, xasl_state, &tplrec) != NO_ERROR)
14337  {
14338  qexec_clear_mainblock_iterations (thread_p, xasl);
14340  }
14341 
14342  /* clear CONNECT BY internal lists */
14343  qexec_clear_connect_by_lists (thread_p, xasl->connect_by_ptr);
14344 
14345  if (on_trace)
14346  {
14347  xasl_stats = &xasl->connect_by_ptr->xasl_stats;
14348 
14349  tsc_getticks (&end_tick);
14350  tsc_elapsed_time_usec (&tv_diff, end_tick, start_tick);
14351  TSC_ADD_TIMEVAL (xasl_stats->elapsed_time, tv_diff);
14352 
14353  xasl_stats->fetches = perfmon_get_from_statistic (thread_p, PSTAT_PB_NUM_FETCHES) - old_fetches;
14354  xasl_stats->ioreads = perfmon_get_from_statistic (thread_p, PSTAT_PB_NUM_IOREADS) - old_ioreads;
14355  }
14356  }
14357  }
14358 
14359  if (xasl->type == CTE_PROC)
14360  {
14361  if (qexec_execute_cte (thread_p, xasl, xasl_state) != NO_ERROR)
14362  {
14364  }
14365  }
14366 
14367  if (xasl->selected_upd_list)
14368  {
14369  if (xasl->list_id->tuple_cnt > 1)
14370  {
14372  qexec_clear_mainblock_iterations (thread_p, xasl);
14374  }
14375  else if (xasl->list_id->tuple_cnt == 1)
14376  {
14377  old_wait_msecs = XASL_WAIT_MSECS_NOCHANGE;
14379  {
14380  old_wait_msecs = xlogtb_reset_wait_msecs (thread_p, xasl->selected_upd_list->wait_msecs);
14381  }
14382 
14383  error = qexec_execute_selupd_list (thread_p, xasl, xasl_state);
14384  if (old_wait_msecs != XASL_WAIT_MSECS_NOCHANGE)
14385  {
14386  (void) xlogtb_reset_wait_msecs (thread_p, old_wait_msecs);
14387  }
14388 
14389  assert (lock_is_instant_lock_mode (tran_index) == false);
14390  instant_lock_mode_started = false;
14391 
14392  if (error != NO_ERROR)
14393  {
14394  qexec_clear_mainblock_iterations (thread_p, xasl);
14396  }
14397  }
14398  else
14399  {
14400  if (instant_lock_mode_started == true)
14401  {
14402  lock_stop_instant_lock_mode (thread_p, tran_index, true);
14403  instant_lock_mode_started = false;
14404  }
14405  }
14406  }
14407 
14408  /* end main block iterations */
14409  if (qexec_end_mainblock_iterations (thread_p, xasl, xasl_state, &tplrec) != NO_ERROR)
14410  {
14411  qexec_clear_mainblock_iterations (thread_p, xasl);
14413  }
14414 
14415  /*
14416  * Post_processing
14417  */
14418 
14419  /*
14420  * DISTINCT processing caused by statement set operators(UNION,
14421  * DIFFERENCE, INTERSECTION) has already taken place now.
14422  * But, in the other cases, DISTINCT are not processed yet.
14423  * qexec_orderby_distinct() will handle it.
14424  */
14425 
14426  /* GROUP BY processing */
14427 
14428  /* if groupby skip, we compute group by from the already sorted list */
14429  if (xasl->spec_list && xasl->spec_list->indexptr && xasl->spec_list->indexptr->groupby_skip)
14430  {
14431  if (qexec_groupby_index (thread_p, xasl, xasl_state, &tplrec) != NO_ERROR)
14432  {
14434  }
14435  }
14436  else if (xasl->type == BUILDLIST_PROC /* it is SELECT query */
14437  && xasl->proc.buildlist.groupby_list) /* it has GROUP BY clause */
14438  {
14439  if (qexec_groupby (thread_p, xasl, xasl_state, &tplrec) != NO_ERROR)
14440  {
14442  }
14443  }
14444 
14445  /* process analytic functions */
14446  if (xasl->type == BUILDLIST_PROC && xasl->proc.buildlist.a_eval_list)
14447  {
14448  ANALYTIC_EVAL_TYPE *eval_list;
14449  for (eval_list = xasl->proc.buildlist.a_eval_list; eval_list; eval_list = eval_list->next)
14450  {
14451  if (qexec_execute_analytic (thread_p, xasl, xasl_state, eval_list, &tplrec, (eval_list->next == NULL)) !=
14452  NO_ERROR)
14453  {
14455  }
14456  }
14457  }
14458 
14459 #if defined (ENABLE_COMPOSITE_LOCK)
14462  {
14463  if (lock_finalize_composite_lock (thread_p, &xasl->composite_lock) != LK_GRANTED)
14464  {
14466  }
14467  }
14468 #endif /* defined (ENABLE_COMPOSITE_LOCK) */
14469 
14470 #if 0 /* DO NOT DELETE ME !!! - yaw: for future work */
14471  if (xasl->list_id->tuple_cnt == 0)
14472  {
14473  /* skip post processing for empty list file */
14474 
14475  /* monitor */
14477  break;
14478  }
14479 #endif
14480 
14481 
14482  /* ORDER BY and DISTINCT processing */
14483  if (xasl->type == UNION_PROC || xasl->type == DIFFERENCE_PROC || xasl->type == INTERSECTION_PROC)
14484  {
14485  /* DISTINCT was already processed in these cases. Consider only ORDER BY */
14486  if (xasl->orderby_list /* it has ORDER BY clause */
14487  && (xasl->list_id->tuple_cnt > 1 /* the result has more than one tuple */
14488  || xasl->ordbynum_val != NULL)) /* ORDERBY_NUM() is used */
14489  {
14490  /* It has ORDER BY clause and the result has more than one tuple. We cannot skip the processing some
14491  * cases such as 'orderby_num() < 1', for example. */
14492  if (qexec_orderby_distinct (thread_p, xasl, Q_ALL, xasl_state) != NO_ERROR)
14493  {
14495  }
14496  }
14497  }
14498  else
14499  {
14500  /* DISTINCT & ORDER BY check orderby_list flag for skipping order by */
14501  if ((xasl->orderby_list /* it has ORDER BY clause */
14502  && (!XASL_IS_FLAGED (xasl, XASL_SKIP_ORDERBY_LIST) /* cannot skip */
14503  || XASL_IS_FLAGED (xasl, XASL_USES_MRO)) /* MRO must go on */
14504  && (xasl->list_id->tuple_cnt > 1 /* the result has more than one tuple */
14505  || xasl->ordbynum_val != NULL /* ORDERBY_NUM() is used */
14506  || xasl->topn_items != NULL)) /* used internal sort */
14507  || (xasl->option == Q_DISTINCT)) /* DISTINCT must be go on */
14508  {
14509  if (qexec_orderby_distinct (thread_p, xasl, xasl->option, xasl_state) != NO_ERROR)
14510  {
14512  }
14513  }
14514  }
14515 
14516  /* monitor */
14518  break;
14519  }
14520 
14521  if (xasl->is_single_tuple)
14522  {
14523  if (xasl->list_id->tuple_cnt > 1)
14524  {
14527  }
14528 
14529  if (xasl->single_tuple
14530  && (qdata_get_single_tuple_from_list_id (thread_p, xasl->list_id, xasl->single_tuple) != NO_ERROR))
14531  {
14533  }
14534  }
14535 
14536 
14537  /*
14538  * Cleanup and Exit processing
14539  */
14540  if (instant_lock_mode_started == true)
14541  {
14542  assert (lock_is_instant_lock_mode (tran_index) == false);
14543  /* a safe guard */
14544  lock_stop_instant_lock_mode (thread_p, tran_index, true);
14545  }
14546 
14547  /* destroy hash table */
14548  if (xasl->type == BUILDLIST_PROC)
14549  {
14550  qexec_free_agg_hash_context (thread_p, &xasl->proc.buildlist);
14551  }
14552 
14553  /* clear only non-zero correlation-level uncorrelated subquery list files */
14554  for (xptr = xasl; xptr; xptr = xptr->scan_ptr)
14555  {
14556  if (xptr->aptr_list)
14557  {
14558  qexec_clear_head_lists (thread_p, xptr->aptr_list);
14559  }
14560  }
14561  if (tplrec.tpl)
14562  {
14563  db_private_free_and_init (thread_p, tplrec.tpl);
14564  }
14565 
14566  xasl->status = XASL_SUCCESS;
14567 
14568  return NO_ERROR;
14569 
14570  /*
14571  * Error processing
14572  */
14573 exit_on_error:
14574 #if defined(SERVER_MODE)
14575  /* query execution error must be set up before qfile_close_list(). */
14576  if (er_errid () < 0)
14577  {
14578  qmgr_set_query_error (thread_p, xasl_state->query_id);
14579  }
14580 #endif
14581 
14582  if (instant_lock_mode_started == true)
14583  {
14584  lock_stop_instant_lock_mode (thread_p, tran_index, true);
14585  }
14586  qfile_close_list (thread_p, xasl->list_id);
14587  if (func_vector)
14588  {
14589  db_private_free_and_init (thread_p, func_vector);
14590  }
14591 
14592  /* close all the scans that are involved within the query */
14593  for (xptr = xasl, level = 0; xptr; xptr = xptr->scan_ptr, level++)
14594  {
14595  spec_ptr[0] = xptr->spec_list;
14596  spec_ptr[1] = xptr->merge_spec;
14597  for (spec_level = 0; spec_level < 2; ++spec_level)
14598  {
14599  for (specp = spec_ptr[spec_level]; specp; specp = specp->next)
14600  {
14601  qexec_end_scan (thread_p, specp);
14602  qexec_close_scan (thread_p, specp);
14603  }
14604  }
14605  if (xptr->curr_spec != NULL)
14606  {
14607  xptr->curr_spec->curent = NULL;
14608  xptr->curr_spec = NULL;
14609  }
14610  }
14611 
14612  if (tplrec.tpl)
14613  {
14614  db_private_free_and_init (thread_p, tplrec.tpl);
14615  }
14616 
14617  if (XASL_IS_FLAGED (xasl, XASL_HAS_CONNECT_BY))
14618  {
14619  qexec_clear_connect_by_lists (thread_p, xasl->connect_by_ptr);
14620  }
14621 
14622  /* destroy hash table */
14623  if (xasl->type == BUILDLIST_PROC)
14624  {
14625  qexec_free_agg_hash_context (thread_p, &xasl->proc.buildlist);
14626  }
14627 
14628 #if defined (ENABLE_COMPOSITE_LOCK)
14629  /* free alloced memory for composite locking */
14630  lock_abort_composite_lock (&xasl->composite_lock);
14631 #endif /* defined (ENABLE_COMPOSITE_LOCK) */
14632 
14633  xasl->status = XASL_FAILURE;
14634 
14635  qexec_failure_line (__LINE__, xasl_state);
14636  return ER_FAILED;
14637 }
14638 
14639 /*
14640  * qexec_execute_query () -
14641  * return: Query result list file identifier, or NULL
14642  * xasl(in) : XASL Tree pointer
14643  * dbval_cnt(in) : Number of positional values (0 or more)
14644  * dbval_ptr(in) : List of positional values (optional)
14645  * query_id(in) : Query Associated with the XASL tree
14646  *
14647  * Note: This routine executes the query represented by the given XASL
14648  * tree. The XASL tree may be associated with a set of positional
14649  * values (coming from esql programs positional values) which
14650  * may be used during query execution. The query result file
14651  * identifier is returned. if an error occurs during execution,
14652  * NULL is returned.
14653  */
14654 
14655 #if 0
14656 #define QP_MAX_RE_EXECUTES_UNDER_DEADLOCKS 10
14657 #endif
14658 
14659 qfile_list_id *
14660 qexec_execute_query (THREAD_ENTRY * thread_p, xasl_node * xasl, int dbval_cnt, const DB_VALUE * dbval_ptr,
14661  QUERY_ID query_id)
14662 {
14663  int re_execute;
14664  int stat = NO_ERROR;
14665  QFILE_LIST_ID *list_id = NULL;
14667  struct tm *c_time_struct, tm_val;
14668  int tran_index;
14669 
14670 #if defined(CUBRID_DEBUG)
14671  static int trace = -1;
14672  static FILE *fp = NULL;
14673 
14674  TSC_TICKS start_tick, end_tick;
14675  TSCTIMEVAL tv_diff;
14676 #endif /* CUBRID_DEBUG */
14677 
14678  struct drand48_data *rand_buf_p;
14679 
14680 #if defined (SERVER_MODE)
14681  int qlist_enter_count;
14682 #endif // SERVER_MODE
14683 
14684 #if defined(ENABLE_SYSTEMTAP)
14685  const char *query_str = NULL;
14686  int client_id = -1;
14687  const char *db_user = NULL;
14688  LOG_TDES *tdes = NULL;
14689 
14690  tran_index = LOG_FIND_THREAD_TRAN_INDEX (thread_p);
14691  tdes = LOG_FIND_TDES (tran_index);
14692  if (tdes != NULL)
14693  {
14694  client_id = tdes->client_id;
14695  db_user = tdes->client.get_db_user ();
14696  }
14697 #endif /* ENABLE_SYSTEMTAP */
14698 
14699 #if defined(CUBRID_DEBUG)
14700  /* check the consistency of the XASL tree */
14701  if (!qdump_check_xasl_tree (xasl))
14702  {
14703  if (xasl)
14704  {
14705  qdump_print_xasl (xasl);
14706  }
14707  else
14708  {
14709  printf ("<NULL XASL tree>\n");
14710  }
14711  }
14712 
14713  if (trace == -1)
14714  {
14715  char *file;
14716 
14717  file = envvar_get ("QUERY_TRACE_FILE");
14718  if (file)
14719  {
14720  trace = 1;
14721  if (!strcmp (file, "stdout"))
14722  {
14723  fp = stdout;
14724  }
14725  else if (!strcmp (file, "stderr"))
14726  {
14727  fp = stderr;
14728  }
14729  else
14730  {
14731  fp = fopen (file, "a");
14732  if (!fp)
14733  {
14734  fprintf (stderr, "Error: QUERY_TRACE_FILE '%s'\n", file);
14735  trace = 0;
14736  }
14737  }
14738  }
14739  else
14740  {
14741  trace = 0;
14742  }
14743  }
14744 
14745  if (trace && fp)
14746  {
14747  time_t loc;
14748  char str[19];
14749 
14750  time (&loc);
14751  strftime (str, 19, "%x %X", localtime_r (&loc, &tm_val));
14752  fprintf (fp, "start %s tid %d qid %ld query %s\n", str, LOG_FIND_THREAD_TRAN_INDEX (thread_p), query_id,
14753  (xasl->sql_hash_text ? xasl->sql_hash_text : "<NULL>"));
14754 
14755  tsc_getticks (&start_tick);
14756  }
14757 #endif /* CUBRID_DEBUG */
14758 
14759 #if defined (SERVER_MODE)
14760  qlist_enter_count = thread_p->m_qlist_count;
14762  {
14763  er_print_callstack (ARG_FILE_LINE, "starting query execution with qlist_count = %d\n", qlist_enter_count);
14764  }
14765 #endif // SERVER_MODE
14766 
14767  /* this routine should not be called if an outstanding error condition already exists. */
14768  er_clear ();
14769 
14770 #if defined(ENABLE_SYSTEMTAP)
14771  tran_index = LOG_FIND_THREAD_TRAN_INDEX (thread_p);
14772  query_str = qmgr_get_query_sql_user_text (thread_p, query_id, tran_index);
14773 
14774  query_str = (query_str ? query_str : "unknown");
14775  db_user = (db_user ? db_user : "unknown");
14776 
14777  CUBRID_QUERY_EXEC_START (query_str, query_id, client_id, db_user);
14778 #endif /* ENABLE_SYSTEMTAP */
14779 
14780  /* form the value descriptor to represent positional values */
14781  xasl_state.vd.dbval_cnt = dbval_cnt;
14782  xasl_state.vd.dbval_ptr = (DB_VALUE *) dbval_ptr;
14783  time_t sec;
14784  int millisec;
14785  util_get_second_and_ms_since_epoch (&sec, &millisec);
14786  c_time_struct = localtime_r (&sec, &tm_val);
14787 
14788  xasl_state.vd.sys_epochtime = (DB_TIMESTAMP) sec;
14789 
14790  if (c_time_struct != NULL)
14791  {
14792  db_datetime_encode (&xasl_state.vd.sys_datetime, c_time_struct->tm_mon + 1, c_time_struct->tm_mday,
14793  c_time_struct->tm_year + 1900, c_time_struct->tm_hour, c_time_struct->tm_min,
14794  c_time_struct->tm_sec, millisec);
14795  }
14796 
14797  rand_buf_p = qmgr_get_rand_buf (thread_p);
14798  lrand48_r (rand_buf_p, &xasl_state.vd.lrand);
14799  drand48_r (rand_buf_p, &xasl_state.vd.drand);
14800  xasl_state.vd.xasl_state = &xasl_state;
14801 
14802  /* save the query_id into the XASL state struct */
14803  xasl_state.query_id = query_id;
14804 
14805  /* initialize error line */
14806  xasl_state.qp_xasl_line = 0;
14807 
14808  tran_index = LOG_FIND_THREAD_TRAN_INDEX (thread_p);
14809  if (logtb_find_current_isolation (thread_p) >= TRAN_REP_READ)
14810  {
14811  /* We need to be sure we have a snapshot. Insert ... values execution might not get any snapshot. Then next
14812  * select may obtain weird results (since things that changed after executing insert will be visible). */
14813  (void) logtb_get_mvcc_snapshot (thread_p);
14814  }
14815 
14816  do
14817  {
14818  re_execute = false;
14819 
14820  /* execute the query set the query in progress flag so that qmgr_clear_trans_wakeup() will not remove our XASL
14821  * tree out from under us in the event the transaction is unilaterally aborted during query execution. */
14822 
14823  xasl->query_in_progress = true;
14824  stat = qexec_execute_mainblock (thread_p, xasl, &xasl_state, NULL);
14825  xasl->query_in_progress = false;
14826 
14827 #if defined(SERVER_MODE)
14828  if (thread_is_on_trace (thread_p))
14829  {
14830  qexec_set_xasl_trace_to_session (thread_p, xasl);
14831  }
14832 #endif
14833 
14834  if (stat != NO_ERROR)
14835  {
14836  switch (er_errid ())
14837  {
14838  case NO_ERROR:
14839  {
14840  char buf[512];
14841 
14842  /* Make sure this does NOT return error indication without setting an error message and code. If we
14843  * get here, we most likely have a system error. qp_xasl_line is the first line to set an error
14844  * condition. */
14845  snprintf (buf, 511, "Query execution failure #%d.", xasl_state.qp_xasl_line);
14847  break;
14848  }
14849  case ER_INTERRUPTED:
14850  /*
14851  * Most of the cleanup that's about to happen will get screwed up if the interrupt is still in effect
14852  * (e.g., someone will do a pb_fetch, which will quit early, and so they'll bail without actually
14853  * finishing their cleanup), so disable it.
14854  */
14855  xlogtb_set_interrupt (thread_p, false);
14856  break;
14857  }
14858 
14859  qmgr_set_query_error (thread_p, query_id); /* propagate error */
14860 
14861  if (xasl->list_id)
14862  {
14863  qfile_close_list (thread_p, xasl->list_id);
14864  }
14865 
14866  list_id = qexec_get_xasl_list_id (xasl);
14867 
14868  (void) qexec_clear_xasl (thread_p, xasl, true);
14869 
14870  /* caller will detect the error condition and free the listid */
14871  goto end;
14872  }
14873  /* for async query, clean error */
14874  else
14875  {
14876  /* async query executed successfully */
14877  er_clear ();
14878  }
14879 
14880  }
14881  while (re_execute);
14882 
14883  list_id = qexec_get_xasl_list_id (xasl);
14884 
14885  /* set last_pgptr->next_vpid to NULL */
14886  if (list_id && list_id->last_pgptr != NULL)
14887  {
14889  }
14890 
14891 #if defined(SERVER_MODE)
14892  if (thread_need_clear_trace (thread_p))
14893  {
14894  (void) session_clear_trace_stats (thread_p);
14895  }
14896 #endif
14897 
14898  /* clear XASL tree */
14899  (void) qexec_clear_xasl (thread_p, xasl, true);
14900 
14901 #if defined(CUBRID_DEBUG)
14902  if (trace && fp)
14903  {
14904  time_t loc;
14905  char str[19];
14906  float elapsed;
14907 
14908  tsc_getticks (&end_tick);
14909  tsc_elapsed_time_usec (&tv_diff, end_tick, start_tick);
14910  elapsed = (float) (tv_diff.tv_sec) * 1000000;
14911  elapsed += (float) tv_diff.tv_usec;
14912  elapsed /= 1000000;
14913 
14914  time (&loc);
14915  strftime (str, 19, "%x %X", localtime_r (&loc, &tm_val));
14916  fprintf (fp, "end %s tid %d qid %d elapsed %.6f\n", str, LOG_FIND_THREAD_TRAN_INDEX (thread_p), query_id,
14917  elapsed);
14918  fflush (fp);
14919  }
14920 #endif /* CUBRID_DEBUG */
14921 
14922 end:
14923 
14924 #if defined (SERVER_MODE)
14926  {
14927  er_print_callstack (ARG_FILE_LINE, "ending query execution with qlist_count = %d\n", thread_p->m_qlist_count);
14928  }
14929  if (list_id && list_id->type_list.type_cnt != 0)
14930  {
14931  // one new list file
14932  assert (thread_p->m_qlist_count == qlist_enter_count + 1);
14933  }
14934  else
14935  {
14936  // no new list files
14937  assert (thread_p->m_qlist_count == qlist_enter_count);
14938  }
14939 #endif // SERVER_MODE
14940 
14941 #if defined(ENABLE_SYSTEMTAP)
14942  CUBRID_QUERY_EXEC_END (query_str, query_id, client_id, db_user, (er_errid () != NO_ERROR));
14943 #endif /* ENABLE_SYSTEMTAP */
14944  return list_id;
14945 }
14946 
14947 #if defined(CUBRID_DEBUG)
14948 /*
14949  * get_xasl_dumper_linked_in () -
14950  * return:
14951  */
14952 void
14953 get_xasl_dumper_linked_in ()
14954 {
14955  XASL_NODE *xasl = NULL;
14956 
14957  qdump_print_xasl (xasl);
14958 }
14959 #endif
14960 
14961 #if defined(SERVER_MODE)
14962 #if defined (ENABLE_UNUSED_FUNCTION)
14963 /*
14964  * tranid_compare () -
14965  * return:
14966  * t1(in) :
14967  * t2(in) :
14968  */
14969 static int
14970 tranid_compare (const void *t1, const void *t2)
14971 {
14972  return *((int *) t1) - *((int *) t2);
14973 }
14974 #endif /* ENABLE_UNUSED_FUNCTION */
14975 #endif
14976 
14977 /*
14978  * qexec_clear_list_cache_by_class () - Clear the list cache entries of the XASL
14979  * by class OID
14980  * return: NO_ERROR, or ER_code
14981  * class_oid(in) :
14982  */
14983 int
14984 qexec_clear_list_cache_by_class (THREAD_ENTRY * thread_p, const OID * class_oid)
14985 {
14986 #if 0
14987  /* TODO: Update this in xasl_cache.c */
14988  XASL_CACHE_ENTRY *ent;
14989  void *last;
14990 
14991  /* for all entries in the class oid hash table Note that mht_put2() allows mutiple data with the same key, so we have
14992  * to use mht_get2() */
14993 
14994  last = NULL;
14995  do
14996  {
14997  /* look up the hash table with the key */
14998  ent = (XASL_CACHE_ENTRY *) mht_get2 (xasl_ent_cache.oid_ht, class_oid, &last);
14999  if (ent && ent->list_ht_no >= 0)
15000  {
15001  (void) qfile_clear_list_cache (thread_p, ent->list_ht_no, false);
15002  }
15003  }
15004  while (ent);
15005 #endif /* 0 */
15006 
15007  return NO_ERROR;
15008 }
15009 
15010 /*
15011  * replace_null_arith () -
15012  * return:
15013  * regu_var(in) :
15014  * set_dbval(in) :
15015  */
15016 static REGU_VARIABLE *
15017 replace_null_arith (REGU_VARIABLE * regu_var, DB_VALUE * set_dbval)
15018 {
15019  REGU_VARIABLE *ret;
15020 
15021  if (!regu_var || !regu_var->value.arithptr)
15022  {
15023  return NULL;
15024  }
15025 
15026  ret = replace_null_dbval (regu_var->value.arithptr->leftptr, set_dbval);
15027  if (ret)
15028  {
15029  return ret;
15030  }
15031 
15032  ret = replace_null_dbval (regu_var->value.arithptr->rightptr, set_dbval);
15033  if (ret)
15034  {
15035  return ret;
15036  }
15037 
15038  ret = replace_null_dbval (regu_var->value.arithptr->thirdptr, set_dbval);
15039  if (ret)
15040  {
15041  return ret;
15042  }
15043 
15044  return NULL;
15045 }
15046 
15047 /*
15048  * replace_null_dbval () -
15049  * return:
15050  * regu_var(in) :
15051  * set_dbval(in) :
15052  */
15053 static REGU_VARIABLE *
15054 replace_null_dbval (REGU_VARIABLE * regu_var, DB_VALUE * set_dbval)
15055 {
15056  if (!regu_var)
15057  {
15058  return NULL;
15059  }
15060 
15061  if (regu_var->type == TYPE_DBVAL)
15062  {
15063  regu_var->value.dbval = *set_dbval;
15064  return regu_var;
15065  }
15066  else if (regu_var->type == TYPE_INARITH || regu_var->type == TYPE_OUTARITH)
15067  {
15068  return replace_null_arith (regu_var, set_dbval);
15069  }
15070 
15071  return NULL;
15072 }
15073 
15074 /*
15075  * qexec_execute_connect_by () - CONNECT BY execution main function
15076  * return:
15077  * xasl(in):
15078  * xasl_state(in):
15079  */
15080 static int
15082  QFILE_TUPLE_RECORD * tplrec)
15083 {
15084  QFILE_LIST_ID *listfile0 = NULL, *listfile1 = NULL, *listfile2 = NULL;
15085  QFILE_LIST_ID *listfile2_tmp = NULL; /* for order siblings by */
15086  QFILE_TUPLE_VALUE_TYPE_LIST type_list = { NULL, 0 };
15087  QFILE_TUPLE_POSITION parent_pos;
15088  QFILE_LIST_SCAN_ID lfscan_id_lst2tmp, input_lfscan_id;
15089  QFILE_TUPLE_RECORD tpl_lst2tmp = { (QFILE_TUPLE) NULL, 0 };
15090  QFILE_TUPLE_RECORD temp_tuple_rec = { (QFILE_TUPLE) NULL, 0 };
15091 
15092  SCAN_CODE qp_lfscan_lst2tmp;
15093  SORT_LIST bf2df_sort_list;
15094  CONNECTBY_PROC_NODE *connect_by;
15095 
15096  DB_VALUE *level_valp = NULL, *isleaf_valp = NULL, *iscycle_valp = NULL;
15097  DB_VALUE *parent_pos_valp = NULL, *index_valp = NULL;
15098  REGU_VARIABLE_LIST regu_list;
15099 
15100  int level_value = 0, isleaf_value = 0, iscycle_value = 0;
15101  char *son_index = NULL, *father_index = NULL; /* current index and father */
15102  int len_son_index = 0, len_father_index = 0;
15103  int index = 0, index_father = 0;
15104  int has_order_siblings_by;
15105 
15106  int j, key_ranges_cnt;
15107  KEY_INFO *key_info_p;
15108 
15109  /* scanners vars */
15110  QFILE_LIST_SCAN_ID lfscan_id;
15111  QFILE_TUPLE_RECORD tuple_rec;
15112  QFILE_TUPLE_RECORD input_tuple_rec;
15113  SCAN_CODE qp_lfscan, qp_input_lfscan;
15114 
15115  DB_LOGICAL ev_res;
15116  bool parent_tuple_added;
15117  int cycle;
15118 
15119  has_order_siblings_by = xasl->orderby_list ? 1 : 0;
15120  connect_by = &xasl->proc.connect_by;
15121  lfscan_id_lst2tmp.status = S_CLOSED;
15122  input_lfscan_id.status = S_CLOSED;
15123  lfscan_id.status = S_CLOSED;
15124 
15125  if (qexec_init_index_pseudocolumn_strings (thread_p, &father_index, &len_father_index, &son_index,
15126  &len_son_index) != NO_ERROR)
15127  {
15129  }
15130 
15131  if (qexec_set_pseudocolumns_val_pointers (xasl, &level_valp, &isleaf_valp, &iscycle_valp, &parent_pos_valp,
15132  &index_valp) != NO_ERROR)
15133  {
15135  }
15136 
15137  /* create the node's output list file */
15138  if (qexec_start_mainblock_iterations (thread_p, xasl, xasl_state) != NO_ERROR)
15139  {
15141  }
15142 
15143  /* replace PRIOR argument constant regu vars values pointers in if_pred with the ones from the current parents list
15144  * scan */
15145  qexec_replace_prior_regu_vars_pred (thread_p, xasl->if_pred, xasl);
15146 
15147  /* replace PRIOR constant regu vars values pointers with the ones from the prior val list */
15148  assert (xasl->spec_list->s_id.status == S_CLOSED);
15149  qexec_replace_prior_regu_vars_pred (thread_p, xasl->spec_list->where_pred, xasl);
15150  qexec_replace_prior_regu_vars_pred (thread_p, xasl->spec_list->where_key, xasl);
15151 
15153  {
15154  regu_list = xasl->spec_list->s.list_node.list_regu_list_probe;
15155  while (regu_list)
15156  {
15157  qexec_replace_prior_regu_vars (thread_p, &regu_list->value, xasl);
15158  regu_list = regu_list->next;
15159  }
15160  }
15161 
15162  if (xasl->spec_list->access == ACCESS_METHOD_INDEX && xasl->spec_list->indexptr)
15163  {
15164  key_info_p = &xasl->spec_list->indexptr->key_info;
15165  key_ranges_cnt = key_info_p->key_cnt;
15166 
15167  for (j = 0; j < key_ranges_cnt; j++)
15168  {
15169  qexec_replace_prior_regu_vars (thread_p, key_info_p->key_ranges[j].key1, xasl);
15170  qexec_replace_prior_regu_vars (thread_p, key_info_p->key_ranges[j].key2, xasl);
15171  }
15172  }
15173 
15174  /* get the domains for the list files */
15175  if (qdata_get_valptr_type_list (thread_p, xasl->outptr_list, &type_list) != NO_ERROR)
15176  {
15178  }
15179 
15180  /* listfile0: output list */
15181  listfile0 = xasl->list_id;
15182  if (listfile0 == NULL)
15183  {
15185  }
15186 
15187  /* listfile1: current parents list, initialized with START WITH list */
15188  listfile1 = connect_by->start_with_list_id;
15189  if (listfile1 == NULL)
15190  {
15192  }
15193 
15194  /* listfile2: current children list */
15195  listfile2 = qfile_open_list (thread_p, &type_list, NULL, xasl_state->query_id, 0);
15196  if (listfile2 == NULL)
15197  {
15199  }
15200 
15201  if (has_order_siblings_by)
15202  {
15203  /* listfile2_tmp: current children list temporary (to apply order siblings by) */
15204  listfile2_tmp = qfile_open_list (thread_p, &type_list, NULL, xasl_state->query_id, 0);
15205  if (listfile2_tmp == NULL)
15206  {
15208  }
15209  }
15210 
15211  /* sort the start with according to order siblings by */
15212  if (has_order_siblings_by)
15213  {
15214  if (qexec_listfile_orderby (thread_p, xasl, listfile1, xasl->orderby_list, xasl_state, xasl->outptr_list) !=
15215  NO_ERROR)
15216  {
15218  }
15219  }
15220 
15221  /* start the scanner on "input" */
15222  if (qexec_open_scan (thread_p, xasl->spec_list, xasl->val_list, &xasl_state->vd, false, true, false,
15223  false, &xasl->spec_list->s_id, xasl_state->query_id, S_SELECT, false, NULL) != NO_ERROR)
15224  {
15226  }
15227 
15228  /* we have all list files, let's begin */
15229 
15230  while (listfile1->tuple_cnt > 0)
15231  {
15232  tuple_rec.tpl = (QFILE_TUPLE) NULL;
15233  tuple_rec.size = 0;
15234 
15235  input_tuple_rec.tpl = (QFILE_TUPLE) NULL;
15236  input_tuple_rec.size = 0;
15237 
15238  qp_input_lfscan = S_ERROR;
15239 
15240  /* calculate LEVEL pseudocolumn value */
15241  level_value++;
15242  db_make_int (level_valp, level_value);
15243 
15244  /* start parents list scanner */
15245  if (qfile_open_list_scan (listfile1, &lfscan_id) != NO_ERROR)
15246  {
15248  }
15249 
15250  while (1)
15251  {
15252  isleaf_value = 1;
15253  iscycle_value = 0;
15254 
15255  qp_lfscan = qfile_scan_list_next (thread_p, &lfscan_id, &tuple_rec, PEEK);
15256  if (qp_lfscan != S_SUCCESS)
15257  {
15258  break;
15259  }
15260 
15261  parent_tuple_added = false;
15262 
15263  /* reset parent tuple position pseudocolumn value */
15264  db_make_bit (parent_pos_valp, DB_DEFAULT_PRECISION, NULL, 8);
15265 
15266  /* fetch regu_variable values from parent tuple; obs: prior_regu_list was split into pred and rest for
15267  * possible future optimizations. */
15268  if (fetch_val_list (thread_p, connect_by->prior_regu_list_pred, &xasl_state->vd, NULL, NULL, tuple_rec.tpl,
15269  PEEK) != NO_ERROR)
15270  {
15272  }
15273  if (fetch_val_list (thread_p, connect_by->prior_regu_list_rest, &xasl_state->vd, NULL, NULL, tuple_rec.tpl,
15274  PEEK) != NO_ERROR)
15275  {
15277  }
15278 
15279  /* if START WITH list, we don't have the string index in the tuple so we create a fictional one with
15280  * index_father. The column in the START WITH list will be written afterwards, when we insert tuples from
15281  * list1 to list0. */
15282  if (listfile1 == connect_by->start_with_list_id) /* is START WITH list? */
15283  {
15284  index_father++;
15285  father_index[0] = 0;
15286  if (bf2df_str_son_index (thread_p, &father_index, NULL, &len_father_index, index_father) != NO_ERROR)
15287  {
15289  }
15290  }
15291  else
15292  {
15293  /* not START WITH tuples but a previous generation of children, now parents. They have the index string
15294  * column written. */
15295  if (!DB_IS_NULL (index_valp) && index_valp->need_clear == true)
15296  {
15297  pr_clear_value (index_valp);
15298  }
15299 
15300  if (qexec_get_index_pseudocolumn_value_from_tuple (thread_p, xasl, tuple_rec.tpl, &index_valp,
15301  &father_index, &len_father_index) != NO_ERROR)
15302  {
15304  }
15305  }
15306 
15307  xasl->next_scan_block_on = false;
15308  index = 0;
15309  qp_input_lfscan = qexec_next_scan_block_iterations (thread_p, xasl);
15310 
15311  while (1)
15312  {
15313  if (qp_input_lfscan != S_SUCCESS)
15314  {
15315  break;
15316  }
15317 
15318  qp_input_lfscan = scan_next_scan (thread_p, &xasl->curr_spec->s_id);
15319  if (qp_input_lfscan != S_SUCCESS)
15320  {
15321  break;
15322  }
15323 
15324  /* evaluate CONNECT BY predicate */
15325  if (xasl->if_pred != NULL)
15326  {
15327  if (xasl->level_val)
15328  {
15329  /* set level_val to children's level */
15330  db_make_int (xasl->level_val, level_value + 1);
15331  }
15332  ev_res = eval_pred (thread_p, xasl->if_pred, &xasl_state->vd, NULL);
15333  if (ev_res == V_ERROR)
15334  {
15336  }
15337  else if (ev_res != V_TRUE)
15338  {
15339  continue;
15340  }
15341  }
15342 
15343  cycle = 0;
15344  /* we found a qualified tuple; now check for cycle */
15345  if (qexec_check_for_cycle (thread_p, xasl->outptr_list, tuple_rec.tpl, &type_list, listfile0, &cycle)
15346  != NO_ERROR)
15347  {
15349  }
15350 
15351  if (cycle == 0)
15352  {
15353  isleaf_value = 0;
15354  }
15355 
15356  /* found ISLEAF, and we already know LEVEL; we need to add the parent tuple into result list ASAP,
15357  * because we need the information about its position into the list to be kept into each child tuple */
15358  if (!parent_tuple_added)
15359  {
15360  if (listfile1 == connect_by->start_with_list_id)
15361  {
15362  if (!DB_IS_NULL (index_valp) && index_valp->need_clear == true)
15363  {
15364  pr_clear_value (index_valp);
15365  }
15366 
15367  /* set index string pseudocolumn value to tuples from START WITH list */
15368  db_make_string (index_valp, father_index);
15369  }
15370 
15371  /* set CONNECT_BY_ISLEAF pseudocolumn value; this is only for completion, we don't know its final
15372  * value yet */
15373  db_make_int (isleaf_valp, isleaf_value);
15374 
15375  /* preserve the parent position pseudocolumn value */
15377  (tuple_rec.tpl, (xasl->outptr_list->valptr_cnt - PCOL_PARENTPOS_TUPLE_OFFSET), parent_pos_valp,
15378  &tp_Bit_domain) != NO_ERROR)
15379  {
15381  }
15382 
15383  /* make the "final" parent tuple */
15384  tuple_rec = temp_tuple_rec;
15385  if (qdata_copy_valptr_list_to_tuple (thread_p, connect_by->prior_outptr_list, &xasl_state->vd,
15386  &tuple_rec) != NO_ERROR)
15387  {
15389  }
15390  temp_tuple_rec = tuple_rec;
15391 
15392  /* add parent tuple to output list file, and get its position into the list */
15393  if (qfile_add_tuple_get_pos_in_list (thread_p, listfile0, tuple_rec.tpl, &parent_pos) != NO_ERROR)
15394  {
15396  }
15397 
15398  /* set parent tuple position pseudocolumn value */
15399  db_make_bit (parent_pos_valp, DB_DEFAULT_PRECISION, REINTERPRET_CAST (DB_C_BIT, &parent_pos),
15400  sizeof (parent_pos) * 8);
15401 
15402  parent_tuple_added = true;
15403  }
15404 
15405  /* only add a child if it doesn't create a cycle or if cycles should be ignored */
15406  if (cycle == 0 || XASL_IS_FLAGED (xasl, XASL_IGNORE_CYCLES))
15407  {
15408  if (has_order_siblings_by)
15409  {
15410  if (qexec_insert_tuple_into_list (thread_p, listfile2_tmp, xasl->outptr_list, &xasl_state->vd,
15411  tplrec) != NO_ERROR)
15412  {
15414  }
15415  }
15416  else
15417  {
15418  index++;
15419  son_index[0] = 0;
15420  if (bf2df_str_son_index (thread_p, &son_index, father_index, &len_son_index, index) != NO_ERROR)
15421  {
15423  }
15424 
15425  if (!DB_IS_NULL (index_valp) && index_valp->need_clear == true)
15426  {
15427  pr_clear_value (index_valp);
15428  }
15429 
15430  db_make_string (index_valp, son_index);
15431  if (qexec_insert_tuple_into_list (thread_p, listfile2, xasl->outptr_list, &xasl_state->vd,
15432  tplrec) != NO_ERROR)
15433  {
15435  }
15436  }
15437  }
15438  else if (!XASL_IS_FLAGED (xasl, XASL_HAS_NOCYCLE))
15439  {
15442  }
15443  else
15444  {
15445  iscycle_value = 1;
15446  }
15447  }
15448  xasl->curr_spec = NULL;
15449 
15450  if (qp_input_lfscan != S_END)
15451  {
15453  }
15454  qexec_end_scan (thread_p, xasl->spec_list);
15455 
15456  if (has_order_siblings_by)
15457  {
15458  qfile_close_list (thread_p, listfile2_tmp);
15459  }
15460 
15461  if (!parent_tuple_added)
15462  {
15463  /* this parent node wasnt added above because it's a leaf node */
15464 
15465  if (listfile1 == connect_by->start_with_list_id)
15466  {
15467  if (!DB_IS_NULL (index_valp) && index_valp->need_clear == true)
15468  {
15469  pr_clear_value (index_valp);
15470  }
15471 
15472  db_make_string (index_valp, father_index);
15473  }
15474 
15475  db_make_int (isleaf_valp, isleaf_value);
15476 
15477  if (qexec_get_tuple_column_value (tuple_rec.tpl,
15479  parent_pos_valp, &tp_Bit_domain) != NO_ERROR)
15480  {
15482  }
15483 
15484  tuple_rec = temp_tuple_rec;
15485  if (qdata_copy_valptr_list_to_tuple (thread_p, connect_by->prior_outptr_list, &xasl_state->vd, &tuple_rec)
15486  != NO_ERROR)
15487  {
15489  }
15490  temp_tuple_rec = tuple_rec;
15491 
15492  if (qfile_add_tuple_get_pos_in_list (thread_p, listfile0, tuple_rec.tpl, &parent_pos) != NO_ERROR)
15493  {
15495  }
15496  }
15497 
15498  /* set CONNECT_BY_ISCYCLE pseudocolumn value */
15499  db_make_int (iscycle_valp, iscycle_value);
15500  /* it is fixed size data, so we can set it in this fashion */
15501  if (qfile_set_tuple_column_value (thread_p, listfile0, NULL, &parent_pos.vpid, parent_pos.tpl,
15502  (xasl->outptr_list->valptr_cnt - PCOL_ISCYCLE_TUPLE_OFFSET), iscycle_valp,
15504  {
15506  }
15507 
15508  /* set CONNECT_BY_ISLEAF pseudocolumn value */
15509  db_make_int (isleaf_valp, isleaf_value);
15510  if (qfile_set_tuple_column_value (thread_p, listfile0, NULL, &parent_pos.vpid, parent_pos.tpl,
15511  (xasl->outptr_list->valptr_cnt - PCOL_ISLEAF_TUPLE_OFFSET), isleaf_valp,
15513  {
15515  }
15516 
15517  if (has_order_siblings_by)
15518  {
15519  /* sort the listfile2_tmp according to orderby lists */
15520  index = 0;
15521  if (qexec_listfile_orderby (thread_p, xasl, listfile2_tmp, xasl->orderby_list, xasl_state,
15522  xasl->outptr_list) != NO_ERROR)
15523  {
15525  }
15526 
15527  /* scan listfile2_tmp and add indexes to tuples, then add them to listfile2 */
15528  if (qfile_open_list_scan (listfile2_tmp, &lfscan_id_lst2tmp) != NO_ERROR)
15529  {
15531  }
15532 
15533  while (1)
15534  {
15535  qp_lfscan_lst2tmp = qfile_scan_list_next (thread_p, &lfscan_id_lst2tmp, &tpl_lst2tmp, PEEK);
15536  if (qp_lfscan_lst2tmp != S_SUCCESS)
15537  {
15538  break;
15539  }
15540 
15541  index++;
15542  son_index[0] = 0;
15543  if (bf2df_str_son_index (thread_p, &son_index, father_index, &len_son_index, index) != NO_ERROR)
15544  {
15546  }
15547 
15548  if (!DB_IS_NULL (index_valp) && index_valp->need_clear == true)
15549  {
15550  pr_clear_value (index_valp);
15551  }
15552 
15553  db_make_string (index_valp, son_index);
15554 
15555  if (fetch_val_list (thread_p, connect_by->prior_regu_list_pred, &xasl_state->vd, NULL, NULL,
15556  tpl_lst2tmp.tpl, PEEK) != NO_ERROR)
15557  {
15559  }
15560  if (fetch_val_list (thread_p, connect_by->prior_regu_list_rest, &xasl_state->vd, NULL, NULL,
15561  tpl_lst2tmp.tpl, PEEK) != NO_ERROR)
15562  {
15564  }
15565 
15566  /* preserve iscycle, isleaf and parent_pos pseudocolumns */
15567  if (qexec_get_tuple_column_value (tpl_lst2tmp.tpl,
15569  iscycle_valp, &tp_Integer_domain) != NO_ERROR)
15570  {
15572  }
15573  if (qexec_get_tuple_column_value (tpl_lst2tmp.tpl,
15575  isleaf_valp, &tp_Integer_domain) != NO_ERROR)
15576  {
15578  }
15579  if (qexec_get_tuple_column_value (tpl_lst2tmp.tpl,
15581  parent_pos_valp, &tp_Bit_domain) != NO_ERROR)
15582  {
15584  }
15585 
15586  if (qexec_insert_tuple_into_list (thread_p, listfile2, connect_by->prior_outptr_list,
15587  &xasl_state->vd, tplrec) != NO_ERROR)
15588  {
15590  }
15591  }
15592 
15593  qfile_close_scan (thread_p, &lfscan_id_lst2tmp);
15594  qfile_close_list (thread_p, listfile2_tmp);
15595  qfile_destroy_list (thread_p, listfile2_tmp);
15596  QFILE_FREE_AND_INIT_LIST_ID (listfile2_tmp);
15597 
15598  listfile2_tmp = qfile_open_list (thread_p, &type_list, NULL, xasl_state->query_id, 0);
15599  }
15600  }
15601 
15602  qfile_close_scan (thread_p, &lfscan_id);
15603 
15604  if (qp_lfscan != S_END)
15605  {
15607  }
15608 
15609  if (listfile1 != connect_by->start_with_list_id)
15610  {
15611  qfile_close_list (thread_p, listfile1);
15612  qfile_destroy_list (thread_p, listfile1);
15613  QFILE_FREE_AND_INIT_LIST_ID (listfile1);
15614  }
15615  listfile1 = listfile2;
15616 
15617  listfile2 = qfile_open_list (thread_p, &type_list, NULL, xasl_state->query_id, 0);
15618  }
15619 
15620  qexec_end_scan (thread_p, xasl->spec_list);
15621  qexec_close_scan (thread_p, xasl->spec_list);
15622 
15623  if (listfile1 != connect_by->start_with_list_id)
15624  {
15625  qfile_close_list (thread_p, listfile1);
15626  qfile_destroy_list (thread_p, listfile1);
15627  QFILE_FREE_AND_INIT_LIST_ID (listfile1);
15628  }
15629 
15630  qfile_close_list (thread_p, listfile2);
15631  qfile_destroy_list (thread_p, listfile2);
15632  QFILE_FREE_AND_INIT_LIST_ID (listfile2);
15633 
15634  if (has_order_siblings_by)
15635  {
15636  qfile_close_scan (thread_p, &lfscan_id_lst2tmp);
15637  qfile_close_list (thread_p, listfile2_tmp);
15638  qfile_destroy_list (thread_p, listfile2_tmp);
15639  QFILE_FREE_AND_INIT_LIST_ID (listfile2_tmp);
15640  }
15641 
15642  if (type_list.domp)
15643  {
15644  db_private_free_and_init (thread_p, type_list.domp);
15645  }
15646 
15647  if (qexec_end_mainblock_iterations (thread_p, xasl, xasl_state, tplrec) != NO_ERROR)
15648  {
15650  }
15651 
15652  if (son_index)
15653  {
15654  db_private_free_and_init (thread_p, son_index);
15655  }
15656  if (father_index)
15657  {
15658  db_private_free_and_init (thread_p, father_index);
15659  }
15660 
15661  /* sort resulting list file BF to DF */
15662  {
15663  /* make a special domain for custom compare of paths strings */
15664  TP_DOMAIN bf2df_str_domain = tp_String_domain;
15665  PR_TYPE bf2df_str_type = tp_String;
15666 
15667  bf2df_str_domain.type = &bf2df_str_type;
15669  bf2df_str_type.set_cmpval_function (bf2df_str_cmpval);
15670 
15671  /* init sort list */
15672  bf2df_sort_list.next = NULL;
15673  bf2df_sort_list.s_order = S_ASC;
15674  bf2df_sort_list.s_nulls = S_NULLS_FIRST;
15676  bf2df_sort_list.pos_descr.dom = &bf2df_str_domain;
15677 
15678  /* sort list file */
15679  if (qexec_listfile_orderby (thread_p, xasl, xasl->list_id, &bf2df_sort_list, xasl_state, xasl->outptr_list) !=
15680  NO_ERROR)
15681  {
15683  }
15684  }
15685 
15686  /* after sort, parent_pos doesnt indicate the correct position of the parent any more; recalculate the parent
15687  * positions */
15688  if (qexec_recalc_tuples_parent_pos_in_list (thread_p, xasl->list_id) != NO_ERROR)
15689  {
15691  }
15692 
15693  if (temp_tuple_rec.tpl)
15694  {
15695  db_private_free_and_init (thread_p, temp_tuple_rec.tpl);
15696  }
15697 
15698  if (xasl->list_id->sort_list)
15699  {
15700  qfile_free_sort_list (thread_p, xasl->list_id->sort_list);
15701  xasl->list_id->sort_list = NULL;
15702  }
15703 
15704  if (has_order_siblings_by)
15705  {
15706  if (connect_by->start_with_list_id->sort_list)
15707  {
15708  qfile_free_sort_list (thread_p, connect_by->start_with_list_id->sort_list);
15709  connect_by->start_with_list_id->sort_list = NULL;
15710  }
15711  }
15712 
15713  qexec_reset_pseudocolumns_val_pointers (level_valp, isleaf_valp, iscycle_valp, parent_pos_valp, index_valp);
15714 
15715  xasl->status = XASL_SUCCESS;
15716 
15717  return NO_ERROR;
15718 
15719 exit_on_error:
15720 
15721  qexec_end_scan (thread_p, xasl->spec_list);
15722  qexec_close_scan (thread_p, xasl->spec_list);
15723 
15724  if (type_list.domp)
15725  {
15726  db_private_free_and_init (thread_p, type_list.domp);
15727  }
15728 
15729  if (listfile1 && (listfile1 != connect_by->start_with_list_id))
15730  {
15731  if (lfscan_id.list_id.tfile_vfid == listfile1->tfile_vfid)
15732  {
15733  if (lfscan_id.curr_pgptr != NULL)
15734  {
15735  qmgr_free_old_page_and_init (thread_p, lfscan_id.curr_pgptr, lfscan_id.list_id.tfile_vfid);
15736  }
15737 
15738  lfscan_id.list_id.tfile_vfid = NULL;
15739  }
15740 
15741  qfile_close_list (thread_p, listfile1);
15742  qfile_destroy_list (thread_p, listfile1);
15743  QFILE_FREE_AND_INIT_LIST_ID (listfile1);
15744  }
15745 
15746  if (listfile2)
15747  {
15748  if (lfscan_id.list_id.tfile_vfid == listfile2->tfile_vfid)
15749  {
15750  if (lfscan_id.curr_pgptr != NULL)
15751  {
15752  qmgr_free_old_page_and_init (thread_p, lfscan_id.curr_pgptr, lfscan_id.list_id.tfile_vfid);
15753  }
15754 
15755  lfscan_id.list_id.tfile_vfid = NULL;
15756  }
15757 
15758  qfile_close_list (thread_p, listfile2);
15759  qfile_destroy_list (thread_p, listfile2);
15760  QFILE_FREE_AND_INIT_LIST_ID (listfile2);
15761  }
15762 
15763  if (listfile2_tmp)
15764  {
15765  qfile_close_scan (thread_p, &lfscan_id_lst2tmp);
15766  qfile_close_list (thread_p, listfile2_tmp);
15767  qfile_destroy_list (thread_p, listfile2_tmp);
15768  QFILE_FREE_AND_INIT_LIST_ID (listfile2_tmp);
15769  }
15770 
15771  if (son_index)
15772  {
15773  db_private_free_and_init (thread_p, son_index);
15774  }
15775 
15776  if (father_index)
15777  {
15778  db_private_free_and_init (thread_p, father_index);
15779  }
15780 
15781  if (temp_tuple_rec.tpl)
15782  {
15783  db_private_free_and_init (thread_p, temp_tuple_rec.tpl);
15784  }
15785 
15786  if (xasl->list_id->sort_list)
15787  {
15788  qfile_free_sort_list (thread_p, xasl->list_id->sort_list);
15789  xasl->list_id->sort_list = NULL;
15790  }
15791 
15792  if (has_order_siblings_by)
15793  {
15794  if (connect_by->start_with_list_id->sort_list)
15795  {
15796  qfile_free_sort_list (thread_p, connect_by->start_with_list_id->sort_list);
15797  connect_by->start_with_list_id->sort_list = NULL;
15798  }
15799  }
15800 
15801  if (!index_valp && !DB_IS_NULL (index_valp) && index_valp->need_clear == true)
15802  {
15803  pr_clear_value (index_valp);
15804  }
15805 
15806  qfile_close_scan (thread_p, &lfscan_id);
15807 
15808  xasl->status = XASL_FAILURE;
15809 
15810  return ER_FAILED;
15811 }
15812 
15813 /*
15814  * qexec_execute_cte () - CTE execution
15815  * return:
15816  * xasl(in):
15817  * xasl_state(in):
15818  */
15819 static int
15821 {
15822  XASL_NODE *non_recursive_part = xasl->proc.cte.non_recursive_part;
15823  XASL_NODE *recursive_part = xasl->proc.cte.recursive_part;
15824  QFILE_LIST_ID *save_recursive_list_id = NULL;
15825  QFILE_LIST_ID *t_list_id = NULL;
15826  int ls_flag = 0;
15827  bool first_iteration = true;
15828 
15829  QFILE_SET_FLAG (ls_flag, QFILE_FLAG_UNION);
15830  QFILE_SET_FLAG (ls_flag, QFILE_FLAG_ALL);
15831 
15832  if (non_recursive_part == NULL)
15833  {
15834  /* non_recursive_part may have false where, so it is null */
15835  return NO_ERROR;
15836  }
15837 
15838  if (non_recursive_part->list_id == NULL)
15839  {
15841  }
15842 
15843  if (xasl->status == XASL_SUCCESS)
15844  {
15845  /* early exit, CTEs should be executed only once */
15846  return NO_ERROR;
15847  }
15848 
15849  /* first the non recursive part from the CTE shall be executed */
15850  if (non_recursive_part->status == XASL_CLEARED || non_recursive_part->status == XASL_INITIALIZED)
15851  {
15852  if (qexec_execute_mainblock (thread_p, non_recursive_part, xasl_state, NULL) != NO_ERROR)
15853  {
15854  qexec_failure_line (__LINE__, xasl_state);
15856  }
15857  }
15858  else
15859  {
15860  qexec_failure_line (__LINE__, xasl_state);
15862  }
15863 
15864  if (recursive_part && non_recursive_part->list_id->tuple_cnt == 0)
15865  {
15866  // status needs to be changed to XASL_SUCCESS to enable proper cleaning in qexec_clear_xasl
15867  recursive_part->status = XASL_SUCCESS;
15868  }
15869  else if (recursive_part && non_recursive_part->list_id->tuple_cnt > 0)
15870  {
15871  bool common_list_optimization = false;
15872  int recursive_iterations = 0;
15873  int sys_prm_cte_max_recursions = prm_get_integer_value (PRM_ID_CTE_MAX_RECURSIONS);
15874 
15875  if (recursive_part->type == BUILDVALUE_PROC)
15876  {
15879  }
15880 
15881  /* the recursive part XASL is executed totally (all iterations)
15882  * and the results will be inserted in non_recursive_part->list_id
15883  */
15884 
15885  while (non_recursive_part->list_id->tuple_cnt > 0)
15886  {
15887  if (common_list_optimization == true)
15888  {
15889  recursive_part->max_iterations = sys_prm_cte_max_recursions;
15890  }
15891  else
15892  {
15893  if (recursive_iterations++ >= sys_prm_cte_max_recursions)
15894  {
15896  sys_prm_cte_max_recursions);
15898  }
15899  }
15900  if (qexec_execute_mainblock (thread_p, recursive_part, xasl_state, NULL) != NO_ERROR)
15901  {
15902  qexec_failure_line (__LINE__, xasl_state);
15904  }
15905 
15906  if (first_iteration)
15907  {
15908  /* unify list_id types after the first execution of the recursive part */
15909  if (qfile_unify_types (non_recursive_part->list_id, recursive_part->list_id) != NO_ERROR)
15910  {
15912  }
15913 
15914  qfile_clear_list_id (xasl->list_id);
15915  if (qfile_copy_list_id (xasl->list_id, non_recursive_part->list_id, true) != NO_ERROR)
15916  {
15918  }
15919  }
15920  else
15921  {
15922  /* copy non_rec_part->list_id to xasl->list_id (final results) */
15923  t_list_id = qfile_combine_two_list (thread_p, xasl->list_id, non_recursive_part->list_id, ls_flag);
15924  if (t_list_id == NULL)
15925  {
15927  }
15928 
15929  /* what's the purpose of t_list_id?? */
15930  qfile_clear_list_id (xasl->list_id);
15931  if (qfile_copy_list_id (xasl->list_id, t_list_id, true) != NO_ERROR)
15932  {
15934  }
15935  QFILE_FREE_AND_INIT_LIST_ID (t_list_id);
15936  }
15937 
15938  qfile_clear_list_id (non_recursive_part->list_id);
15939  if (recursive_part->list_id->tuple_cnt > 0
15940  && qfile_copy_list_id (non_recursive_part->list_id, recursive_part->list_id, true) != NO_ERROR)
15941  {
15942  QFILE_FREE_AND_INIT_LIST_ID (non_recursive_part->list_id);
15944  }
15945  qfile_clear_list_id (recursive_part->list_id);
15946 
15947  if (first_iteration && non_recursive_part->list_id->tuple_cnt > 0)
15948  {
15949  first_iteration = false;
15950  if (recursive_part->proc.buildlist.groupby_list || recursive_part->orderby_list
15951  || recursive_part->instnum_val != NULL || recursive_part->proc.buildlist.a_eval_list != NULL)
15952  {
15953  /* future specific optimizations, changes, etc */
15954  }
15955  else if (recursive_part->spec_list->s.list_node.xasl_node == non_recursive_part)
15956  {
15957  /* optimization: use non-recursive list id for both reading and writing
15958  * the recursive xasl will iterate through this list id while appending new results at its end
15959  * note: this works only if the cte(actually the non_recursive_part link) is the first spec used
15960  * for scanning during recursive iterations
15961  */
15962  save_recursive_list_id = recursive_part->list_id;
15963  recursive_part->list_id = non_recursive_part->list_id;
15964  qfile_reopen_list_as_append_mode (thread_p, recursive_part->list_id);
15965  common_list_optimization = true;
15966  }
15967  }
15968  }
15969 
15970  /* copy all results back to non_recursive_part list id; other CTEs from the same WITH clause have access only to
15971  * non_recursive_part; see how pt_to_cte_table_spec_list works for interdependent CTEs.
15972  */
15973  if (qfile_copy_list_id (non_recursive_part->list_id, xasl->list_id, true) != NO_ERROR)
15974  {
15975  QFILE_FREE_AND_INIT_LIST_ID (non_recursive_part->list_id);
15977  }
15978 
15979  if (save_recursive_list_id != NULL)
15980  {
15981  /* restore recursive list_id */
15982  recursive_part->list_id = save_recursive_list_id;
15983  }
15984  }
15985  /* copy list id from non-recursive part to CTE XASL (even if no tuples are in non recursive part) to get domain types
15986  * into CTE xasl's main list (this also executes if we have a recursive part but no tuples in non recursive part
15987  * (no results at all)
15988  */
15989  else if (qfile_copy_list_id (xasl->list_id, non_recursive_part->list_id, true) != NO_ERROR)
15990  {
15993  }
15994 
15995  xasl->status = XASL_SUCCESS;
15996 
15997  if (recursive_part != NULL)
15998  {
15999  recursive_part->max_iterations = -1;
16000  }
16001 
16002  return NO_ERROR;
16003 
16004 exit_on_error:
16005  if (save_recursive_list_id != NULL)
16006  {
16007  /* restore recursive list_id */
16008  recursive_part->list_id = save_recursive_list_id;
16009  }
16010 
16011  if (recursive_part != NULL)
16012  {
16013  recursive_part->max_iterations = -1;
16014  }
16015 
16016  xasl->status = XASL_FAILURE;
16017  return ER_FAILED;
16018 }
16019 
16020 /*
16021  * qexec_replace_prior_regu_vars_prior_expr () - replaces values of the
16022  * constant regu vars (these are part of the PRIOR argument) with values
16023  * fetched from the parent tuple
16024  * return:
16025  * regu(in):
16026  * xasl(in):
16027  */
16028 void
16030  xasl_node * connect_by_ptr)
16031 {
16032  if (regu == NULL)
16033  {
16034  return;
16035  }
16036 
16037  switch (regu->type)
16038  {
16039  case TYPE_CONSTANT:
16040  {
16041  int i;
16042  QPROC_DB_VALUE_LIST vl, vl_prior;
16043 
16044  for (i = 0, vl = xasl->val_list->valp, vl_prior = connect_by_ptr->proc.connect_by.prior_val_list->valp;
16045  i < xasl->val_list->val_cnt && i < connect_by_ptr->proc.connect_by.prior_val_list->val_cnt;
16046  i++, vl = vl->next, vl_prior = vl_prior->next)
16047  {
16048  if (regu->value.dbvalptr == vl->val)
16049  {
16050  regu->value.dbvalptr = vl_prior->val;
16051  }
16052  }
16053  }
16054  break;
16055 
16056  case TYPE_INARITH:
16057  case TYPE_OUTARITH:
16058  qexec_replace_prior_regu_vars_prior_expr (thread_p, regu->value.arithptr->leftptr, xasl, connect_by_ptr);
16059  qexec_replace_prior_regu_vars_prior_expr (thread_p, regu->value.arithptr->rightptr, xasl, connect_by_ptr);
16060  qexec_replace_prior_regu_vars_prior_expr (thread_p, regu->value.arithptr->thirdptr, xasl, connect_by_ptr);
16061  break;
16062 
16063  case TYPE_FUNC:
16064  {
16066  while (r)
16067  {
16068  qexec_replace_prior_regu_vars_prior_expr (thread_p, &r->value, xasl, connect_by_ptr);
16069  r = r->next;
16070  }
16071  }
16072  break;
16073 
16074  default:
16075  break;
16076  }
16077 }
16078 
16079 /*
16080  * qexec_replace_prior_regu_vars () - looks for the PRIOR argument, and replaces
16081  * the constant regu vars values with values fetched from the parent tuple
16082  * return:
16083  * regu(in):
16084  * xasl(in):
16085  */
16086 static void
16088 {
16089  if (regu == NULL)
16090  {
16091  return;
16092  }
16093 
16094  switch (regu->type)
16095  {
16096  case TYPE_INARITH:
16097  case TYPE_OUTARITH:
16098  if (regu->value.arithptr->opcode == T_PRIOR)
16099  {
16100  qexec_replace_prior_regu_vars_prior_expr (thread_p, regu->value.arithptr->rightptr, xasl, xasl);
16101  }
16102  else
16103  {
16104  qexec_replace_prior_regu_vars (thread_p, regu->value.arithptr->leftptr, xasl);
16105  qexec_replace_prior_regu_vars (thread_p, regu->value.arithptr->rightptr, xasl);
16106  qexec_replace_prior_regu_vars (thread_p, regu->value.arithptr->thirdptr, xasl);
16107  }
16108  break;
16109 
16110  case TYPE_FUNC:
16111  {
16112  REGU_VARIABLE_LIST r = regu->value.funcp->operand;
16113  while (r)
16114  {
16115  qexec_replace_prior_regu_vars (thread_p, &r->value, xasl);
16116  r = r->next;
16117  }
16118  }
16119  break;
16120 
16121  default:
16122  break;
16123  }
16124 }
16125 
16126 /*
16127  * qexec_replace_prior_regu_vars_pred () - replaces the values of constant
16128  * regu variables which are part of PRIOR arguments within the predicate,
16129  * with values fetched from the parent tuple
16130  * return:
16131  * pred(in):
16132  * xasl(in):
16133  */
16134 static void
16136 {
16137  if (pred == NULL)
16138  {
16139  return;
16140  }
16141 
16142  switch (pred->type)
16143  {
16144  case T_PRED:
16145  qexec_replace_prior_regu_vars_pred (thread_p, pred->pe.m_pred.lhs, xasl);
16146  qexec_replace_prior_regu_vars_pred (thread_p, pred->pe.m_pred.rhs, xasl);
16147  break;
16148 
16149  case T_EVAL_TERM:
16150  switch (pred->pe.m_eval_term.et_type)
16151  {
16152  case T_COMP_EVAL_TERM:
16153  qexec_replace_prior_regu_vars (thread_p, pred->pe.m_eval_term.et.et_comp.lhs, xasl);
16154  qexec_replace_prior_regu_vars (thread_p, pred->pe.m_eval_term.et.et_comp.rhs, xasl);
16155  break;
16156 
16157  case T_ALSM_EVAL_TERM:
16158  qexec_replace_prior_regu_vars (thread_p, pred->pe.m_eval_term.et.et_alsm.elem, xasl);
16160  break;
16161 
16162  case T_LIKE_EVAL_TERM:
16164  qexec_replace_prior_regu_vars (thread_p, pred->pe.m_eval_term.et.et_like.src, xasl);
16165  break;
16166  case T_RLIKE_EVAL_TERM:
16168  qexec_replace_prior_regu_vars (thread_p, pred->pe.m_eval_term.et.et_rlike.src, xasl);
16169  break;
16170  }
16171  break;
16172 
16173  case T_NOT_TERM:
16174  qexec_replace_prior_regu_vars_pred (thread_p, pred->pe.m_not_term, xasl);
16175  break;
16176  }
16177 }
16178 
16179 /*
16180  * qexec_insert_tuple_into_list () - helper function for inserting a tuple
16181  * into a list file
16182  * return:
16183  * list_id(in/out):
16184  * xasl(in):
16185  * vd(in):
16186  * tplrec(in):
16187  */
16188 int
16190  val_descr * vd, qfile_tuple_record * tplrec)
16191 {
16192  QPROC_TPLDESCR_STATUS tpldescr_status;
16193 
16194  tpldescr_status = qexec_generate_tuple_descriptor (thread_p, list_id, outptr_list, vd);
16195  if (tpldescr_status == QPROC_TPLDESCR_FAILURE)
16196  {
16197  return ER_FAILED;
16198  }
16199 
16200  switch (tpldescr_status)
16201  {
16203  /* generate tuple into list file page */
16204  if (qfile_generate_tuple_into_list (thread_p, list_id, T_NORMAL) != NO_ERROR)
16205  {
16206  return ER_FAILED;
16207  }
16208  break;
16209 
16212  /* BIG QFILE_TUPLE or a SET-field is included */
16213  if (tplrec->tpl == NULL)
16214  {
16215  /* allocate tuple descriptor */
16216  tplrec->size = DB_PAGESIZE;
16217  tplrec->tpl = (QFILE_TUPLE) db_private_alloc (thread_p, DB_PAGESIZE);
16218  if (tplrec->tpl == NULL)
16219  {
16220  return ER_FAILED;
16221  }
16222  }
16223  if ((qdata_copy_valptr_list_to_tuple (thread_p, outptr_list, vd, tplrec) != NO_ERROR)
16224  || (qfile_add_tuple_to_list (thread_p, list_id, tplrec->tpl) != NO_ERROR))
16225  {
16226  return ER_FAILED;
16227  }
16228  break;
16229 
16230  default:
16231  break;
16232  }
16233 
16234  return NO_ERROR;
16235 }
16236 
16237 /*
16238  * qexec_get_tuple_column_value () - helper function for reading a column
16239  * value from a tuple
16240  * return:
16241  * tpl(in):
16242  * index(in):
16243  * valp(out):
16244  * domain(in):
16245  */
16246 int
16248 {
16250  char *ptr;
16251  int length;
16252  PR_TYPE *pr_type;
16253  OR_BUF buf;
16254 
16255  flag = (QFILE_TUPLE_VALUE_FLAG) qfile_locate_tuple_value (tpl, index, &ptr, &length);
16256  if (flag == V_BOUND)
16257  {
16258  pr_type = domain->type;
16259  if (pr_type == NULL)
16260  {
16261  return ER_FAILED;
16262  }
16263 
16264  OR_BUF_INIT (buf, ptr, length);
16265 
16266  if (pr_type->data_readval (&buf, valp, domain, -1, false, NULL, 0) != NO_ERROR)
16267  {
16268  return ER_FAILED;
16269  }
16270  }
16271  else
16272  {
16273  db_make_null (valp);
16274  }
16275 
16276  return NO_ERROR;
16277 }
16278 
16279 /*
16280  * qexec_check_for_cycle () - check the tuple described by the outptr_list
16281  * to see if it is ancestor of tpl
16282  * return:
16283  * outptr_list(in):
16284  * tpl(in):
16285  * type_list(in):
16286  * list_id_p(in):
16287  * iscycle(out):
16288  */
16289 static int
16291  QFILE_TUPLE_VALUE_TYPE_LIST * type_list, QFILE_LIST_ID * list_id_p, int *iscycle)
16292 {
16293  DB_VALUE p_pos_dbval;
16294  QFILE_LIST_SCAN_ID s_id;
16295  QFILE_TUPLE_RECORD tuple_rec = { (QFILE_TUPLE) NULL, 0 };
16296  const QFILE_TUPLE_POSITION *bitval = NULL;
16297  QFILE_TUPLE_POSITION p_pos;
16298  int length;
16299 
16300  if (qfile_open_list_scan (list_id_p, &s_id) != NO_ERROR)
16301  {
16302  return ER_FAILED;
16303  }
16304 
16305  /* we start with tpl itself */
16306  tuple_rec.tpl = tpl;
16307 
16308  do
16309  {
16310  if (qexec_compare_valptr_with_tuple (outptr_list, tuple_rec.tpl, type_list, iscycle) != NO_ERROR)
16311  {
16312  qfile_close_scan (thread_p, &s_id);
16313  return ER_FAILED;
16314  }
16315 
16316  if (*iscycle)
16317  {
16318  break;
16319  }
16320 
16321  /* get the parent node */
16322  if (qexec_get_tuple_column_value (tuple_rec.tpl,
16323  (outptr_list->valptr_cnt - PCOL_PARENTPOS_TUPLE_OFFSET), &p_pos_dbval,
16324  &tp_Bit_domain) != NO_ERROR)
16325  {
16326  qfile_close_scan (thread_p, &s_id);
16327  return ER_FAILED;
16328  }
16329 
16330  bitval = REINTERPRET_CAST (const QFILE_TUPLE_POSITION *, db_get_bit (&p_pos_dbval, &length));
16331 
16332  if (bitval)
16333  {
16334  p_pos.status = s_id.status;
16335  p_pos.position = S_ON;
16336  p_pos.vpid = bitval->vpid;
16337  p_pos.offset = bitval->offset;
16338  p_pos.tpl = NULL;
16339  p_pos.tplno = bitval->tplno;
16340 
16341  if (qfile_jump_scan_tuple_position (thread_p, &s_id, &p_pos, &tuple_rec, PEEK) != S_SUCCESS)
16342  {
16343  qfile_close_scan (thread_p, &s_id);
16344  return ER_FAILED;
16345  }
16346  }
16347  }
16348  while (bitval); /* the parent tuple pos is null for the root node */
16349 
16350  qfile_close_scan (thread_p, &s_id);
16351 
16352  return NO_ERROR;
16353 
16354 }
16355 
16356 /*
16357  * qexec_compare_valptr_with_tuple () - compare the tuple described by
16358  * outptr_list to see if it is equal to tpl; ignore pseudo-columns
16359  * return:
16360  * outptr_list(in):
16361  * tpl(in):
16362  * type_list(in):
16363  * are_equal(out):
16364  */
16365 static int
16367  int *are_equal)
16368 {
16369  REGU_VARIABLE_LIST regulist;
16370  QFILE_TUPLE tuple;
16371  OR_BUF buf;
16372  DB_VALUE dbval1, *dbvalp2;
16373  PR_TYPE *pr_type_p;
16374  DB_TYPE type;
16375  TP_DOMAIN *domp;
16376  int length1, length2, equal, i;
16377  bool copy = false;
16378 
16379  *are_equal = 1;
16380 
16381  tuple = tpl + QFILE_TUPLE_LENGTH_SIZE;
16382  regulist = outptr_list->valptrp;
16383  i = 0;
16384 
16385  while (regulist && i < outptr_list->valptr_cnt - PCOL_FIRST_TUPLE_OFFSET)
16386  {
16387  /* compare regulist->value.value.dbvalptr to the DB_VALUE from tuple */
16388 
16389  dbvalp2 = regulist->value.value.dbvalptr;
16390  length2 = (dbvalp2->domain.general_info.is_null != 0) ? 0 : -1;
16391 
16392  domp = type_list->domp[i];
16393  type = TP_DOMAIN_TYPE (domp);
16394  copy = pr_is_set_type (type);
16395  pr_type_p = domp->type;
16396 
16397  length1 = QFILE_GET_TUPLE_VALUE_LENGTH (tuple);
16398 
16399  /* zero length means NULL */
16400  if (length1 == 0)
16401  {
16402  db_make_null (&dbval1);
16403  }
16404  else
16405  {
16406  or_init (&buf, (char *) tuple + QFILE_TUPLE_VALUE_HEADER_SIZE, length1);
16407  if (pr_type_p->data_readval (&buf, &dbval1, domp, -1, copy, NULL, 0) != NO_ERROR)
16408  {
16409  return ER_FAILED;
16410  }
16411  }
16412 
16413  if (length1 == 0 && length2 == 0)
16414  {
16415  equal = 1;
16416  }
16417  else if (length1 == 0)
16418  {
16419  equal = 0;
16420  }
16421  else if (length2 == 0)
16422  {
16423  equal = 0;
16424  }
16425  else
16426  {
16427  equal = pr_type_p->cmpval (&dbval1, dbvalp2, 0, 1, NULL, domp->collation_id) == DB_EQ;
16428  }
16429 
16430  if (copy || DB_NEED_CLEAR (&dbval1))
16431  {
16432  pr_clear_value (&dbval1);
16433  }
16434 
16435  if (!equal)
16436  {
16437  *are_equal = 0;
16438  break;
16439  }
16440 
16442  regulist = regulist->next;
16443  i++;
16444  }
16445 
16446  if (i < outptr_list->valptr_cnt - PCOL_FIRST_TUPLE_OFFSET)
16447  {
16448  *are_equal = 0;
16449  }
16450 
16451  return NO_ERROR;
16452 }
16453 
16454 /*
16455  * qexec_init_index_pseudocolumn () - index pseudocolumn strings initialization
16456  * return:
16457  * father_index(out): father index string
16458  * len_father_index(out): father index string allocation length
16459  * son_index(out): son index string
16460  * len_son_index(out): son index string allocation length
16461  */
16462 static int
16463 qexec_init_index_pseudocolumn_strings (THREAD_ENTRY * thread_p, char **father_index, int *len_father_index,
16464  char **son_index, int *len_son_index)
16465 {
16466  *len_father_index = CONNECTBY_TUPLE_INDEX_STRING_MEM;
16467  *father_index = (char *) db_private_alloc (thread_p, *len_father_index);
16468 
16469  if ((*father_index) == NULL)
16470  {
16471  return ER_OUT_OF_VIRTUAL_MEMORY;
16472  }
16473 
16474  memset (*father_index, 0, *len_father_index);
16475 
16476  *len_son_index = CONNECTBY_TUPLE_INDEX_STRING_MEM;
16477  *son_index = (char *) db_private_alloc (thread_p, *len_son_index);
16478 
16479  if ((*son_index) == NULL)
16480  {
16481  return ER_OUT_OF_VIRTUAL_MEMORY;
16482  }
16483 
16484  memset (*son_index, 0, *len_son_index);
16485 
16486  return NO_ERROR;
16487 }
16488 
16489 /*
16490  * bf2df_str_son_index () -
16491  * return:
16492  * son_index(out): son index string which will be father_index + "." + cnt
16493  * father_index(in): father's index string
16494  * len_son_index(in/out): current son's index string allocation length
16495  * cnt(in):
16496  */
16497 static int
16498 bf2df_str_son_index (THREAD_ENTRY * thread_p, char **son_index, char *father_index, int *len_son_index, int cnt)
16499 {
16500  char counter[32];
16501  size_t size, n = father_index ? strlen (father_index) : 0;
16502 
16503  snprintf (counter, 32, "%d", cnt);
16504  size = strlen (counter) + n + 2;
16505 
16506  /* more space needed? */
16507  if ((*len_son_index > 0) && (size > ((size_t) (*len_son_index))))
16508  {
16509  do
16510  {
16511  *len_son_index += CONNECTBY_TUPLE_INDEX_STRING_MEM;
16512  }
16513  while (size > ((size_t) (*len_son_index)));
16514 
16515  db_private_free_and_init (thread_p, *son_index);
16516  *son_index = (char *) db_private_alloc (thread_p, *len_son_index);
16517  if ((*son_index) == NULL)
16518  {
16519  return ER_OUT_OF_VIRTUAL_MEMORY;
16520  }
16521 
16522  memset (*son_index, 0, *len_son_index);
16523  }
16524 
16525  if (father_index)
16526  {
16527  strcpy (*son_index, father_index);
16528  }
16529  else
16530  {
16531  (*son_index)[0] = 0;
16532  }
16533  if (n > 0)
16534  {
16535  strcat (*son_index, "."); /* '.' < '0'...'9' */
16536  }
16537  strcat (*son_index, counter);
16538 
16539  return NO_ERROR;
16540 }
16541 
16542 /*
16543  * qexec_listfile_orderby () - sorts a listfile according to a orderby list
16544  * return: NO_ERROR, or ER_code
16545  * list_file(in): listfile to sort
16546  * orderby_list(in): orderby list with sort columns
16547  * xasl_state(in): xasl state
16548  * outptr_list(in): xasl outptr list
16549  */
16550 static int
16551 qexec_listfile_orderby (THREAD_ENTRY * thread_p, XASL_NODE * xasl, QFILE_LIST_ID * list_file, SORT_LIST * orderby_list,
16552  XASL_STATE * xasl_state, OUTPTR_LIST * outptr_list)
16553 {
16554  QFILE_LIST_ID *list_id = list_file;
16555  int n, i;
16556  ORDBYNUM_INFO ordby_info;
16557  REGU_VARIABLE_LIST regu_list;
16558 
16559  TSC_TICKS start_tick, end_tick;
16560  TSCTIMEVAL tv_diff;
16561 
16562  UINT64 old_sort_pages = 0, old_sort_ioreads = 0;
16563 
16564  if (orderby_list != NULL)
16565  {
16566  if (orderby_list && qfile_is_sort_list_covered (list_id->sort_list, orderby_list) == true)
16567  {
16568  /* no need to sort here */
16569  }
16570  else
16571  {
16572  if (thread_is_on_trace (thread_p))
16573  {
16574  tsc_getticks (&start_tick);
16575 
16576  old_sort_pages = perfmon_get_from_statistic (thread_p, PSTAT_SORT_NUM_DATA_PAGES);
16577  old_sort_ioreads = perfmon_get_from_statistic (thread_p, PSTAT_SORT_NUM_IO_PAGES);
16578  }
16579 
16580  /* sort the list file */
16581  ordby_info.ordbynum_pos_cnt = 0;
16582  ordby_info.ordbynum_pos = ordby_info.reserved;
16583  if (outptr_list)
16584  {
16585  for (n = 0, regu_list = outptr_list->valptrp; regu_list; regu_list = regu_list->next)
16586  {
16587  if (regu_list->value.type == TYPE_ORDERBY_NUM)
16588  {
16589  n++;
16590  }
16591  }
16592  ordby_info.ordbynum_pos_cnt = n;
16593  if (n > 2)
16594  {
16595  ordby_info.ordbynum_pos = (int *) db_private_alloc (thread_p, sizeof (int) * n);
16596  if (ordby_info.ordbynum_pos == NULL)
16597  {
16599  }
16600  }
16601  for (n = 0, i = 0, regu_list = outptr_list->valptrp; regu_list; regu_list = regu_list->next, i++)
16602  {
16603  if (regu_list->value.type == TYPE_ORDERBY_NUM)
16604  {
16605  ordby_info.ordbynum_pos[n++] = i;
16606  }
16607  }
16608  }
16609 
16610  ordby_info.xasl_state = xasl_state;
16611  ordby_info.ordbynum_pred = NULL;
16612  ordby_info.ordbynum_val = NULL;
16613  ordby_info.ordbynum_flag = 0;
16614 
16615  list_id =
16616  qfile_sort_list_with_func (thread_p, list_id, orderby_list, Q_ALL, QFILE_FLAG_ALL, NULL, NULL, NULL,
16617  &ordby_info, NO_SORT_LIMIT, true);
16618 
16619  if (ordby_info.ordbynum_pos != ordby_info.reserved)
16620  {
16621  db_private_free_and_init (thread_p, ordby_info.ordbynum_pos);
16622  }
16623 
16624  if (list_id == NULL)
16625  {
16627  }
16628 
16629  if (thread_is_on_trace (thread_p))
16630  {
16631  tsc_getticks (&end_tick);
16632  tsc_elapsed_time_usec (&tv_diff, end_tick, start_tick);
16633  TSC_ADD_TIMEVAL (xasl->orderby_stats.orderby_time, tv_diff);
16634 
16635  xasl->orderby_stats.orderby_filesort = true;
16636 
16637  xasl->orderby_stats.orderby_pages += (perfmon_get_from_statistic (thread_p, PSTAT_SORT_NUM_DATA_PAGES)
16638  - old_sort_pages);
16639  xasl->orderby_stats.orderby_ioreads += (perfmon_get_from_statistic (thread_p, PSTAT_SORT_NUM_IO_PAGES)
16640  - old_sort_ioreads);
16641  }
16642  }
16643  }
16644 
16645  return NO_ERROR;
16646 
16647 exit_on_error:
16648 
16649  return ER_FAILED;
16650 }
16651 
16652 /*
16653  * qexec_set_pseudocolumns_val_pointers () - setup pseudocolumns value pointers
16654  * return:
16655  * xasl(in):
16656  * level_valp(out):
16657  * isleaf_valp(out):
16658  * iscycle_valp(out):
16659  * parent_pos_valp(out):
16660  * index_valp(out):
16661  */
16662 static int
16663 qexec_set_pseudocolumns_val_pointers (XASL_NODE * xasl, DB_VALUE ** level_valp, DB_VALUE ** isleaf_valp,
16664  DB_VALUE ** iscycle_valp, DB_VALUE ** parent_pos_valp, DB_VALUE ** index_valp)
16665 {
16666  REGU_VARIABLE_LIST regulist;
16667  int i, n, error;
16668 
16669  i = 0;
16670  n = xasl->outptr_list->valptr_cnt;
16671  regulist = xasl->outptr_list->valptrp;
16672 
16673  while (regulist)
16674  {
16675  if (i == n - PCOL_PARENTPOS_TUPLE_OFFSET)
16676  {
16677  *parent_pos_valp = regulist->value.value.dbvalptr;
16678  error = db_value_domain_init (*parent_pos_valp, DB_TYPE_BIT, DB_DEFAULT_PRECISION, 0);
16679  if (error != NO_ERROR)
16680  {
16681  return error;
16682  }
16683  }
16684  if (i == n - PCOL_LEVEL_TUPLE_OFFSET)
16685  {
16686  *level_valp = regulist->value.value.dbvalptr;
16687  error = db_value_domain_init (*level_valp, DB_TYPE_VARCHAR, DB_DEFAULT_PRECISION, 0);
16688  if (error != NO_ERROR)
16689  {
16690  return error;
16691  }
16692  }
16693  if (i == n - PCOL_ISLEAF_TUPLE_OFFSET)
16694  {
16695  *isleaf_valp = regulist->value.value.dbvalptr;
16696  db_make_int (*isleaf_valp, 0);
16697  }
16698  if (i == n - PCOL_ISCYCLE_TUPLE_OFFSET)
16699  {
16700  *iscycle_valp = regulist->value.value.dbvalptr;
16701  db_make_int (*iscycle_valp, 0);
16702  }
16703  if (i == n - PCOL_INDEX_STRING_TUPLE_OFFSET)
16704  {
16705  *index_valp = regulist->value.value.dbvalptr;
16706  db_make_int (*index_valp, 0);
16707  }
16708  regulist = regulist->next;
16709  i++;
16710  }
16711 
16712  i = 0;
16714  regulist = xasl->proc.connect_by.prior_outptr_list->valptrp;
16715 
16716  while (regulist)
16717  {
16718  if (i == n - PCOL_PARENTPOS_TUPLE_OFFSET)
16719  {
16720  regulist->value.value.dbvalptr = *parent_pos_valp;
16721  }
16722  if (i == n - PCOL_LEVEL_TUPLE_OFFSET)
16723  {
16724  regulist->value.value.dbvalptr = *level_valp;
16725  }
16726  if (i == n - PCOL_ISLEAF_TUPLE_OFFSET)
16727  {
16728  regulist->value.value.dbvalptr = *isleaf_valp;
16729  }
16730  if (i == n - PCOL_ISCYCLE_TUPLE_OFFSET)
16731  {
16732  regulist->value.value.dbvalptr = *iscycle_valp;
16733  }
16734  if (i == n - PCOL_INDEX_STRING_TUPLE_OFFSET)
16735  {
16736  regulist->value.value.dbvalptr = *index_valp;
16737  }
16738  regulist = regulist->next;
16739  i++;
16740  }
16741 
16742  return NO_ERROR;
16743 }
16744 
16745 /*
16746  * qexec_reset_pseudocolumns_val_pointers () - reset pseudocolumns value pointers
16747  * return:
16748  * level_valp(in/out):
16749  * isleaf_valp(in/out):
16750  * iscycle_valp(in/out):
16751  * parent_pos_valp(in/out):
16752  * index_valp(in/out):
16753  */
16754 static void
16755 qexec_reset_pseudocolumns_val_pointers (DB_VALUE * level_valp, DB_VALUE * isleaf_valp, DB_VALUE * iscycle_valp,
16756  DB_VALUE * parent_pos_valp, DB_VALUE * index_valp)
16757 {
16758  (void) pr_clear_value (level_valp);
16759  (void) pr_clear_value (parent_pos_valp);
16760  (void) pr_clear_value (isleaf_valp);
16761  (void) pr_clear_value (iscycle_valp);
16762  (void) pr_clear_value (index_valp);
16763 }
16764 
16765 /*
16766  * qexec_get_index_pseudocolumn_value_from_tuple () -
16767  * return:
16768  * xasl(in):
16769  * tpl(in):
16770  * index_valp(out):
16771  * index_value(out):
16772  * index_len(out):
16773  */
16774 static int
16776  DB_VALUE ** index_valp, char **index_value, int *index_len)
16777 {
16779  *index_valp, &tp_String_domain) != NO_ERROR)
16780  {
16781  return ER_FAILED;
16782  }
16783 
16784  if (!db_value_is_null (*index_valp))
16785  {
16786  /* increase the size if more space needed */
16787  while ((int) strlen ((*index_valp)->data.ch.medium.buf) + 1 > *index_len)
16788  {
16789  (*index_len) += CONNECTBY_TUPLE_INDEX_STRING_MEM;
16790  db_private_free_and_init (thread_p, *index_value);
16791  *index_value = (char *) db_private_alloc (thread_p, *index_len);
16792 
16793  if ((*index_value) == NULL)
16794  {
16795  return ER_OUT_OF_VIRTUAL_MEMORY;
16796  }
16797  }
16798 
16799  strcpy (*index_value, (*index_valp)->data.ch.medium.buf);
16800  }
16801 
16802  return NO_ERROR;
16803 }
16804 
16805 /*
16806  * qexec_recalc_tuples_parent_pos_in_list () - recalculate the parent position
16807  * in list for each tuple and update the parent_pos pseudocolumn
16808  * return:
16809  * list_id_p(in): The list file.
16810  *
16811  * Note: We need the parent positions for:
16812  * - supporting PRIOR operator in SELECT list
16813  * - SYS_CONNECT_BY_PATH()
16814  * - CONNECT_BY_ROOT
16815  */
16816 static int
16818 {
16819  PARENT_POS_INFO *pos_info_p, *prev_pos_info_p;
16820  DB_VALUE level_dbval, parent_pos_dbval;
16821  QFILE_LIST_SCAN_ID s_id, prev_s_id;
16822  QFILE_TUPLE_RECORD tuple_rec = { (QFILE_TUPLE) NULL, 0 };
16823  QFILE_TUPLE_RECORD prev_tuple_rec = { (QFILE_TUPLE) NULL, 0 };
16824  SCAN_CODE scan, prev_scan;
16825  int level, prev_level, i;
16826  bool started;
16827 
16828  prev_s_id.status = S_CLOSED;
16829 
16830  /* always empty bottom of the stack, just to be there */
16831  pos_info_p = (PARENT_POS_INFO *) db_private_alloc (thread_p, sizeof (PARENT_POS_INFO));
16832  if (pos_info_p == NULL)
16833  {
16834  goto exit_on_error;
16835  }
16836  memset ((void *) pos_info_p, 0, sizeof (PARENT_POS_INFO));
16837 
16838  if (qfile_open_list_scan (list_id_p, &s_id) != NO_ERROR)
16839  {
16840  goto exit_on_error;
16841  }
16842  if (qfile_open_list_scan (list_id_p, &prev_s_id) != NO_ERROR)
16843  {
16844  goto exit_on_error;
16845  }
16846 
16847  prev_level = 1;
16848  started = false;
16849  prev_scan = S_END;
16850 
16851  while (1)
16852  {
16853  scan = qfile_scan_list_next (thread_p, &s_id, &tuple_rec, PEEK);
16854  if (scan != S_SUCCESS)
16855  {
16856  break;
16857  }
16858 
16859  if (started)
16860  {
16861  prev_scan = qfile_scan_list_next (thread_p, &prev_s_id, &prev_tuple_rec, PEEK);
16862  if (prev_scan != S_SUCCESS)
16863  {
16864  break;
16865  }
16866  }
16867  else
16868  {
16869  started = true;
16870  }
16871 
16873  &level_dbval, &tp_Integer_domain) != NO_ERROR)
16874  {
16875  goto exit_on_error;
16876  }
16877 
16878  level = db_get_int (&level_dbval);
16879 
16880  if (level == prev_level)
16881  {
16882  /* the tuple is on the same level as the prev tuple */
16883 
16884  if (!pos_info_p)
16885  {
16886  goto exit_on_error;
16887  }
16888 
16889  if (level > 1)
16890  {
16891  /* set parent position pseudocolumn value */
16892  db_make_bit (&parent_pos_dbval, DB_DEFAULT_PRECISION, REINTERPRET_CAST (DB_C_BIT, &pos_info_p->tpl_pos),
16893  sizeof (pos_info_p->tpl_pos) * 8);
16894 
16895  if (qfile_set_tuple_column_value (thread_p, list_id_p, s_id.curr_pgptr, &s_id.curr_vpid, tuple_rec.tpl,
16897  &parent_pos_dbval, &tp_Bit_domain) != NO_ERROR)
16898  {
16899  goto exit_on_error;
16900  }
16901  }
16902  }
16903  else if (level > prev_level)
16904  {
16905  /* the tuple is child of the previous one */
16906 
16907  if (prev_scan == S_END)
16908  {
16909  goto exit_on_error; /* this should not be possible */
16910  }
16911 
16912  prev_pos_info_p = pos_info_p;
16913  pos_info_p = (PARENT_POS_INFO *) db_private_alloc (thread_p, sizeof (PARENT_POS_INFO));
16914  if (pos_info_p == NULL)
16915  {
16916  pos_info_p = prev_pos_info_p;
16917  goto exit_on_error;
16918  }
16919  pos_info_p->stack = prev_pos_info_p;
16920 
16921  qfile_save_current_scan_tuple_position (&prev_s_id, &pos_info_p->tpl_pos);
16922 
16923  db_make_bit (&parent_pos_dbval, DB_DEFAULT_PRECISION, REINTERPRET_CAST (DB_C_BIT, &pos_info_p->tpl_pos),
16924  sizeof (pos_info_p->tpl_pos) * 8);
16925 
16926  if (qfile_set_tuple_column_value (thread_p, list_id_p, s_id.curr_pgptr, &s_id.curr_vpid, tuple_rec.tpl,
16928  &parent_pos_dbval, &tp_Bit_domain) != NO_ERROR)
16929  {
16930  goto exit_on_error;
16931  }
16932  }
16933  else
16934  {
16935  /* level < prev_level */
16936 
16937  for (i = level; i < prev_level; i++)
16938  {
16939  if (pos_info_p)
16940  {
16941  prev_pos_info_p = pos_info_p->stack;
16942  db_private_free_and_init (thread_p, pos_info_p);
16943  pos_info_p = prev_pos_info_p;
16944  }
16945  else
16946  {
16947  goto exit_on_error;
16948  }
16949  }
16950 
16951  if (pos_info_p == NULL)
16952  {
16953  goto exit_on_error;
16954  }
16955 
16956  if (level > 1)
16957  {
16958  db_make_bit (&parent_pos_dbval, DB_DEFAULT_PRECISION, REINTERPRET_CAST (DB_C_BIT, &pos_info_p->tpl_pos),
16959  sizeof (pos_info_p->tpl_pos) * 8);
16960 
16961  if (qfile_set_tuple_column_value (thread_p, list_id_p, s_id.curr_pgptr, &s_id.curr_vpid, tuple_rec.tpl,
16963  &parent_pos_dbval, &tp_Bit_domain) != NO_ERROR)
16964  {
16965  goto exit_on_error;
16966  }
16967  }
16968  }
16969 
16970  prev_level = level;
16971  }
16972 
16973  if (scan != S_END)
16974  {
16975  goto exit_on_error;
16976  }
16977  if (prev_scan != S_END && prev_scan != S_SUCCESS)
16978  {
16979  goto exit_on_error;
16980  }
16981 
16982  qfile_close_scan (thread_p, &s_id);
16983  qfile_close_scan (thread_p, &prev_s_id);
16984 
16985  while (pos_info_p)
16986  {
16987  prev_pos_info_p = pos_info_p->stack;
16988  db_private_free_and_init (thread_p, pos_info_p);
16989  pos_info_p = prev_pos_info_p;
16990  }
16991 
16992  return NO_ERROR;
16993 
16994 exit_on_error:
16995 
16996  qfile_close_scan (thread_p, &s_id);
16997  qfile_close_scan (thread_p, &prev_s_id);
16998 
16999  while (pos_info_p)
17000  {
17001  prev_pos_info_p = pos_info_p->stack;
17002  db_private_free_and_init (thread_p, pos_info_p);
17003  pos_info_p = prev_pos_info_p;
17004  }
17005 
17006  return ER_FAILED;
17007 }
17008 
17009 /*
17010  * qexec_start_connect_by_lists () - initializes the START WITH list file and
17011  * the CONNECT BY input list file
17012  * return:
17013  * xasl(in): CONNECT BY xasl
17014  * xasl_state(in):
17015  */
17016 static int
17018 {
17019  QFILE_TUPLE_VALUE_TYPE_LIST type_list;
17020  QFILE_LIST_ID *t_list_id = NULL;
17021  CONNECTBY_PROC_NODE *connect_by = &xasl->proc.connect_by;
17022 
17023  if (qdata_get_valptr_type_list (thread_p, xasl->outptr_list, &type_list) != NO_ERROR)
17024  {
17025  goto exit_on_error;
17026  }
17027 
17028  if (connect_by->start_with_list_id->type_list.type_cnt == 0)
17029  {
17030  t_list_id = qfile_open_list (thread_p, &type_list, NULL, xasl_state->query_id, 0);
17031  if (t_list_id == NULL)
17032  {
17033  goto exit_on_error;
17034  }
17035 
17036  if (qfile_copy_list_id (connect_by->start_with_list_id, t_list_id, true) != NO_ERROR)
17037  {
17038  goto exit_on_error;
17039  }
17040 
17041  QFILE_FREE_AND_INIT_LIST_ID (t_list_id);
17042  }
17043 
17044  if (connect_by->input_list_id->type_list.type_cnt == 0)
17045  {
17046  t_list_id = qfile_open_list (thread_p, &type_list, NULL, xasl_state->query_id, 0);
17047  if (t_list_id == NULL)
17048  {
17049  goto exit_on_error;
17050  }
17051 
17052  if (qfile_copy_list_id (connect_by->input_list_id, t_list_id, true) != NO_ERROR)
17053  {
17054  goto exit_on_error;
17055  }
17056 
17057  QFILE_FREE_AND_INIT_LIST_ID (t_list_id);
17058  }
17059 
17060  if (type_list.domp)
17061  {
17062  db_private_free_and_init (thread_p, type_list.domp);
17063  }
17064 
17065  return NO_ERROR;
17066 
17067 exit_on_error:
17068 
17069  if (type_list.domp)
17070  {
17071  db_private_free_and_init (thread_p, type_list.domp);
17072  }
17073 
17074  if (t_list_id)
17075  {
17076  QFILE_FREE_AND_INIT_LIST_ID (t_list_id);
17077  }
17078 
17079  return ER_FAILED;
17080 }
17081 
17082 /*
17083  * qexec_update_connect_by_lists () - updates the START WITH list file and
17084  * the CONNECT BY input list file with new data
17085  * return:
17086  * xasl(in): CONNECT BY xasl
17087  * xasl_state(in):
17088  * tplrec(in):
17089  */
17090 static int
17092  QFILE_TUPLE_RECORD * tplrec)
17093 {
17094  DB_LOGICAL ev_res;
17095  CONNECTBY_PROC_NODE *connect_by = &xasl->proc.connect_by;
17096 
17097  /* evaluate START WITH predicate */
17098  ev_res = V_UNKNOWN;
17099  if (connect_by->start_with_pred != NULL)
17100  {
17101  ev_res = eval_pred (thread_p, connect_by->start_with_pred, &xasl_state->vd, NULL);
17102  if (ev_res == V_ERROR)
17103  {
17104  return ER_FAILED;
17105  }
17106  }
17107 
17108  if (connect_by->start_with_pred == NULL || ev_res == V_TRUE)
17109  {
17110  /* create tuple and add it to both input_list_id and start_with_list_id */
17111  if (qdata_copy_valptr_list_to_tuple (thread_p, xasl->outptr_list, &xasl_state->vd, tplrec) != NO_ERROR)
17112  {
17113  return ER_FAILED;
17114  }
17115 
17116  if (!connect_by->single_table_opt)
17117  {
17118  if (qfile_add_tuple_to_list (thread_p, connect_by->input_list_id, tplrec->tpl) != NO_ERROR)
17119  {
17120  return ER_FAILED;
17121  }
17122  }
17123 
17124  if (qfile_add_tuple_to_list (thread_p, connect_by->start_with_list_id, tplrec->tpl) != NO_ERROR)
17125  {
17126  return ER_FAILED;
17127  }
17128  }
17129  else
17130  {
17131  /* create tuple only in input_list_id */
17132  if (qexec_insert_tuple_into_list (thread_p, connect_by->input_list_id, xasl->outptr_list, &xasl_state->vd, tplrec)
17133  != NO_ERROR)
17134  {
17135  return ER_FAILED;
17136  }
17137  }
17138 
17139  return NO_ERROR;
17140 }
17141 
17142 /*
17143  * qexec_end_connect_by_lists () - closes the START WITH list file and
17144  * the CONNECT BY input list file
17145  * return:
17146  * xasl(in): CONNECT BY xasl
17147  */
17148 static void
17150 {
17151  CONNECTBY_PROC_NODE *connect_by = &xasl->proc.connect_by;
17152 
17153  qfile_close_list (thread_p, connect_by->start_with_list_id);
17154  qfile_close_list (thread_p, connect_by->input_list_id);
17155 }
17156 
17157 /*
17158  * qexec_clear_connect_by_lists () - clears the START WITH list file and
17159  * the CONNECT BY input list file
17160  * return:
17161  * xasl(in): CONNECT BY xasl
17162  */
17163 static void
17165 {
17166  CONNECTBY_PROC_NODE *connect_by = &xasl->proc.connect_by;
17167 
17168  qfile_close_list (thread_p, connect_by->start_with_list_id);
17169  qfile_destroy_list (thread_p, connect_by->start_with_list_id);
17170 
17171  qfile_close_list (thread_p, connect_by->input_list_id);
17172  qfile_destroy_list (thread_p, connect_by->input_list_id);
17173 }
17174 
17175 /*
17176  * qexec_iterate_connect_by_results () - scan CONNECT BY results, apply WHERE,
17177  * add to xasl->list_id
17178  * return:
17179  * xasl(in): SELECT xasl
17180  * xasl_state(in):
17181  */
17182 static int
17184  QFILE_TUPLE_RECORD * tplrec)
17185 {
17186  CONNECTBY_PROC_NODE *connect_by = &xasl->connect_by_ptr->proc.connect_by;
17187  QFILE_LIST_SCAN_ID s_id;
17188  QFILE_TUPLE_RECORD tuple_rec = { (QFILE_TUPLE) NULL, 0 };
17189  SCAN_CODE scan;
17190  DB_VALUE *dbvalp;
17191  DB_LOGICAL ev_res;
17192  bool qualified;
17193  XASL_NODE *xptr, *last_xasl;
17194 
17195  if (qfile_open_list_scan (xasl->connect_by_ptr->list_id, &s_id) != NO_ERROR)
17196  {
17197  return ER_FAILED;
17198  }
17199 
17200  while (1)
17201  {
17202  scan = qfile_scan_list_next (thread_p, &s_id, &tuple_rec, PEEK);
17203  if (scan != S_SUCCESS)
17204  {
17205  break;
17206  }
17207 
17208  connect_by->curr_tuple = tuple_rec.tpl;
17209 
17210  /* fetch LEVEL pseudocolumn value */
17211  if (xasl->level_val)
17212  {
17213  if (fetch_peek_dbval (thread_p, xasl->level_regu, &xasl_state->vd, NULL, NULL, tuple_rec.tpl,
17214  &dbvalp) != NO_ERROR)
17215  {
17216  goto exit_on_error;
17217  }
17218  }
17219 
17220  /* fetch CONNECT_BY_ISLEAF pseudocolumn value */
17221  if (xasl->isleaf_val)
17222  {
17223  if (fetch_peek_dbval (thread_p, xasl->isleaf_regu, &xasl_state->vd, NULL, NULL, tuple_rec.tpl,
17224  &dbvalp) != NO_ERROR)
17225  {
17226  goto exit_on_error;
17227  }
17228  }
17229 
17230  /* fetch CONNECT_BY_ISCYCLE pseudocolumn value */
17231  if (xasl->iscycle_val)
17232  {
17233  if (fetch_peek_dbval (thread_p, xasl->iscycle_regu, &xasl_state->vd, NULL, NULL, tuple_rec.tpl,
17234  &dbvalp) != NO_ERROR)
17235  {
17236  goto exit_on_error;
17237  }
17238  }
17239 
17240  /* fetch pred part of xasl->connect_by_ptr->val_list from the tuple */
17241  if (fetch_val_list (thread_p, connect_by->after_cb_regu_list_pred, &xasl_state->vd, NULL, NULL, tuple_rec.tpl,
17242  PEEK) != NO_ERROR)
17243  {
17244  goto exit_on_error;
17245  }
17246 
17247  /* fetch the rest of xasl->connect_by_ptr->val_list from the tuple */
17248  if (fetch_val_list (thread_p, connect_by->after_cb_regu_list_rest, &xasl_state->vd, NULL, NULL, tuple_rec.tpl,
17249  PEEK) != NO_ERROR)
17250  {
17251  goto exit_on_error;
17252  }
17253 
17254  /* evaluate after_connect_by predicate */
17255  ev_res = V_UNKNOWN;
17256  if (connect_by->after_connect_by_pred != NULL)
17257  {
17258  ev_res = eval_pred (thread_p, connect_by->after_connect_by_pred, &xasl_state->vd, NULL);
17259  if (ev_res == V_ERROR)
17260  {
17261  goto exit_on_error;
17262  }
17263  /* clear correlated subqueries linked within the predicate */
17264  qexec_clear_pred_xasl (thread_p, connect_by->after_connect_by_pred);
17265  }
17266  qualified = (connect_by->after_connect_by_pred == NULL || ev_res == V_TRUE);
17267 
17268  if (qualified)
17269  {
17270  /* evaluate inst_num predicate */
17271  if (xasl->instnum_val)
17272  {
17273  ev_res = qexec_eval_instnum_pred (thread_p, xasl, xasl_state);
17274  if (ev_res == V_ERROR)
17275  {
17276  goto exit_on_error;
17277  }
17278 
17280  {
17281  qfile_close_scan (thread_p, &s_id);
17282  return NO_ERROR;
17283  }
17284  }
17285  qualified = (xasl->instnum_pred == NULL || ev_res == V_TRUE);
17286 
17287  if (qualified)
17288  {
17289  if (qexec_end_one_iteration (thread_p, xasl, xasl_state, tplrec) != NO_ERROR)
17290  {
17291  goto exit_on_error;
17292  }
17293  }
17294  }
17295 
17296  /* clear correlated subquery list files; the list of correlated subqueries reside on the last scan proc or fetch
17297  * proc */
17298  last_xasl = xasl;
17299  while (last_xasl)
17300  {
17301  if (last_xasl->scan_ptr)
17302  {
17303  last_xasl = last_xasl->scan_ptr;
17304  }
17305  else if (last_xasl->fptr_list)
17306  {
17307  last_xasl = last_xasl->fptr_list;
17308  }
17309  else
17310  {
17311  break;
17312  }
17313  }
17314  for (xptr = last_xasl->dptr_list; xptr != NULL; xptr = xptr->next)
17315  {
17316  qexec_clear_head_lists (thread_p, xptr);
17317  }
17318  }
17319 
17320  if (scan != S_END)
17321  {
17322  goto exit_on_error;
17323  }
17324 
17325  qfile_close_scan (thread_p, &s_id);
17326 
17327  return NO_ERROR;
17328 
17329 exit_on_error:
17330  qfile_close_scan (thread_p, &s_id);
17331  return ER_FAILED;
17332 }
17333 
17334 
17335 /*
17336  * qexec_gby_finalize_group_val_list () -
17337  * return:
17338  * gbstate(in):
17339  * N(in):
17340  */
17341 static void
17343 {
17344  int i;
17345  QPROC_DB_VALUE_LIST gby_vallist;
17346 
17347  if (gbstate->state != NO_ERROR)
17348  {
17349  return;
17350  }
17351 
17352  if (gbstate->g_dim == NULL || N >= gbstate->g_dim_levels)
17353  {
17354  assert (false);
17355  return;
17356  }
17357 
17358  if (gbstate->g_dim[N].d_flag & GROUPBY_DIM_FLAG_GROUP_BY)
17359  {
17360  assert (N == 0);
17361  return; /* nop */
17362  }
17363 
17364  /* set to NULL (in the summary tuple) the columns that failed comparison */
17365  if (gbstate->g_val_list)
17366  {
17367  assert (N > 0);
17368  assert (gbstate->g_dim[N].d_flag & GROUPBY_DIM_FLAG_ROLLUP);
17369 
17370  i = 0;
17371  gby_vallist = gbstate->g_val_list->valp;
17372 
17373  while (gby_vallist)
17374  {
17375  if (i >= N - 1)
17376  {
17377  (void) pr_clear_value (gby_vallist->val);
17378  db_make_null (gby_vallist->val);
17379  }
17380  i++;
17381  gby_vallist = gby_vallist->next;
17382  }
17383  }
17384 }
17385 
17386 /*
17387  * qexec_gby_finalize_group_dim () -
17388  * return:
17389  * gbstate(in):
17390  * recdes(in):
17391  */
17392 static int
17394 {
17395  int i, j, nkeys, level = 0;
17396 
17397  qexec_gby_finalize_group (thread_p, gbstate, 0, gbstate->with_rollup);
17398  if (gbstate->state == SORT_PUT_STOP)
17399  {
17400  goto wrapup;
17401  }
17402 
17403  /* handle the rollup groups */
17404  if (gbstate->with_rollup)
17405  {
17406  if (recdes)
17407  {
17408  SORT_REC *key;
17409 
17410  key = (SORT_REC *) recdes->data;
17411  assert (key != NULL);
17412 
17413  level = gbstate->g_dim_levels;
17414  nkeys = gbstate->key_info.nkeys; /* save */
17415 
17416  /* find the first key that fails comparison; the rollup level will be key number */
17417  for (i = 1; i < nkeys; i++)
17418  {
17419  gbstate->key_info.nkeys = i;
17420 
17421  if ((*gbstate->cmp_fn) (&gbstate->current_key.data, &key, &gbstate->key_info) != 0)
17422  {
17423  /* finalize rollup groups */
17424  for (j = gbstate->g_dim_levels - 1; j > i; j--)
17425  {
17426  assert (gbstate->g_dim[j].d_flag & GROUPBY_DIM_FLAG_ROLLUP);
17427 
17428  qexec_gby_finalize_group (thread_p, gbstate, j, true);
17429 #if 0 /* TODO - sus-11454 */
17430  if (gbstate->state == SORT_PUT_STOP)
17431  {
17432  goto wrapup;
17433  }
17434 #endif
17435  qexec_gby_start_group (thread_p, gbstate, NULL, j);
17436  }
17437  level = i + 1;
17438  break;
17439  }
17440  }
17441 
17442  gbstate->key_info.nkeys = nkeys; /* restore */
17443  }
17444  else
17445  {
17446  for (j = gbstate->g_dim_levels - 1; j > 0; j--)
17447  {
17448  assert (gbstate->g_dim[j].d_flag & GROUPBY_DIM_FLAG_ROLLUP);
17449 
17450  qexec_gby_finalize_group (thread_p, gbstate, j, true);
17451 #if 0 /* TODO - sus-11454 */
17452  if (gbstate->state == SORT_PUT_STOP)
17453  {
17454  goto wrapup;
17455  }
17456 #endif
17457 
17458  qexec_gby_start_group (thread_p, gbstate, NULL, j);
17459  }
17460  level = gbstate->g_dim_levels;
17461  }
17462 
17463  if (gbstate->g_dim != NULL && gbstate->g_dim[0].d_agg_list != NULL)
17464  {
17465  qfile_close_list (thread_p, gbstate->g_dim[0].d_agg_list->list_id);
17466  qfile_destroy_list (thread_p, gbstate->g_dim[0].d_agg_list->list_id);
17467  }
17468  }
17469 
17470  qexec_gby_start_group (thread_p, gbstate, recdes, 0);
17471 
17472 wrapup:
17473  return level;
17474 
17475 }
17476 
17477 /*
17478  * qexec_gby_finalize_group () -
17479  * return:
17480  * gbstate(in):
17481  * N(in):
17482  * keep_list_file(in) : whether keep the list file for reuse
17483  */
17484 static void
17485 qexec_gby_finalize_group (THREAD_ENTRY * thread_p, GROUPBY_STATE * gbstate, int N, bool keep_list_file)
17486 {
17487  QPROC_TPLDESCR_STATUS tpldescr_status;
17488  XASL_NODE *xptr;
17489  DB_LOGICAL ev_res;
17490  XASL_STATE *xasl_state = gbstate->xasl_state;
17491  int error_code = NO_ERROR;
17492 
17493  if (gbstate->state != NO_ERROR)
17494  {
17495  return;
17496  }
17497 
17498  if (gbstate->g_dim == NULL || N >= gbstate->g_dim_levels)
17499  {
17500  assert (false);
17502  }
17503 
17504  assert (gbstate->g_dim[N].d_flag != GROUPBY_DIM_FLAG_NONE);
17505 
17506  error_code = qdata_finalize_aggregate_list (thread_p, gbstate->g_dim[N].d_agg_list, keep_list_file);
17507  if (error_code != NO_ERROR)
17508  {
17509  ASSERT_ERROR ();
17511  }
17512 
17513  /* evaluate subqueries in HAVING predicate */
17514  for (xptr = gbstate->eptr_list; xptr; xptr = xptr->next)
17515  {
17516  error_code = qexec_execute_mainblock (thread_p, xptr, xasl_state, NULL);
17517  if (error_code != NO_ERROR)
17518  {
17519  ASSERT_ERROR ();
17521  }
17522  }
17523 
17524  /* move aggregate values in aggregate list for predicate evaluation and possibly insertion in list file */
17525  if (gbstate->g_dim[N].d_agg_list != NULL)
17526  {
17527  AGGREGATE_TYPE *g_outp = gbstate->g_output_agg_list;
17528  AGGREGATE_TYPE *d_aggp = gbstate->g_dim[N].d_agg_list;
17529 
17530  while (g_outp != NULL && d_aggp != NULL)
17531  {
17532  if (g_outp->function != PT_GROUPBY_NUM)
17533  {
17534  if (d_aggp->accumulator.value != NULL && g_outp->accumulator.value != NULL)
17535  {
17536  pr_clear_value (g_outp->accumulator.value);
17537  *g_outp->accumulator.value = *d_aggp->accumulator.value;
17538  /* Don't use db_make_null here to preserve the type information. */
17539 
17540  PRIM_SET_NULL (d_aggp->accumulator.value);
17541  }
17542 
17543  /* should not touch d_aggp->value2 */
17544  }
17545 
17546  g_outp = g_outp->next;
17547  d_aggp = d_aggp->next;
17548  }
17549  }
17550 
17551  /* set to NULL (in the summary tuple) the columns that failed comparison */
17552  if (!(gbstate->g_dim[N].d_flag & GROUPBY_DIM_FLAG_GROUP_BY))
17553  {
17554  assert (N > 0);
17555  (void) qexec_gby_finalize_group_val_list (thread_p, gbstate, N);
17556  }
17557 
17558  /* evaluate HAVING predicates */
17559  ev_res = V_TRUE;
17560  if (gbstate->having_pred)
17561  {
17562  ev_res = eval_pred (thread_p, gbstate->having_pred, &xasl_state->vd, NULL);
17563  if (ev_res == V_ERROR)
17564  {
17565  ASSERT_ERROR_AND_SET (error_code);
17567  }
17568  else if (ev_res != V_TRUE)
17569  {
17570  goto wrapup;
17571  }
17572  }
17573 
17574  assert (ev_res == V_TRUE);
17575 
17576  if (gbstate->grbynum_val)
17577  {
17578  /* evaluate groupby_num predicates */
17579  ev_res = qexec_eval_grbynum_pred (thread_p, gbstate);
17580  if (ev_res == V_ERROR)
17581  {
17582  ASSERT_ERROR_AND_SET (error_code);
17584  }
17585  if (ev_res == V_TRUE)
17586  {
17588  {
17591  }
17592  }
17593  else
17594  {
17596  {
17598  }
17599  }
17601  {
17602  /* reset grbynum_val for next use */
17603  db_make_bigint (gbstate->grbynum_val, 0);
17604  /* setting SORT_PUT_STOP will make 'sr_in_sort()' stop processing; the caller, 'qexec_gby_put_next()',
17605  * returns 'gbstate->state' */
17606  gbstate->state = SORT_PUT_STOP;
17607  }
17608  }
17609 
17610  if (ev_res != V_TRUE)
17611  {
17612  goto wrapup;
17613  }
17614 
17615  if (N == 0)
17616  {
17617  if (gbstate->composite_lock != NULL)
17618  {
17619  /* At this moment composite locking is not used, but it can be activated at some point in the future. So we
17620  * leave it as it is. */
17621  if (false)
17622  {
17623  error_code = qexec_add_composite_lock (thread_p, gbstate->g_outptr_list->valptrp, xasl_state,
17624  gbstate->composite_lock, gbstate->upd_del_class_cnt, NULL);
17625  if (error_code != NO_ERROR)
17626  {
17627  ASSERT_ERROR ();
17629  }
17630  }
17631  }
17632  }
17633 
17634  assert (ev_res == V_TRUE);
17635 
17636  tpldescr_status =
17637  qexec_generate_tuple_descriptor (thread_p, gbstate->output_file, gbstate->g_outptr_list, &xasl_state->vd);
17638  if (tpldescr_status == QPROC_TPLDESCR_FAILURE)
17639  {
17640  ASSERT_ERROR_AND_SET (error_code);
17642  }
17643 
17644  switch (tpldescr_status)
17645  {
17647  /* generate tuple into list file page */
17648  error_code = qfile_generate_tuple_into_list (thread_p, gbstate->output_file, T_NORMAL);
17649  if (error_code != NO_ERROR)
17650  {
17651  ASSERT_ERROR ();
17653  }
17654  break;
17655 
17658  /* BIG QFILE_TUPLE or a SET-field is included */
17659  if (gbstate->output_tplrec->tpl == NULL)
17660  {
17661  /* allocate tuple descriptor */
17662  gbstate->output_tplrec->size = DB_PAGESIZE;
17663  gbstate->output_tplrec->tpl = (QFILE_TUPLE) db_private_alloc (thread_p, DB_PAGESIZE);
17664  if (gbstate->output_tplrec->tpl == NULL)
17665  {
17666  assert (false);
17668  }
17669  }
17670  error_code = qdata_copy_valptr_list_to_tuple (thread_p, gbstate->g_outptr_list, &xasl_state->vd,
17671  gbstate->output_tplrec);
17672  if (error_code != NO_ERROR)
17673  {
17674  ASSERT_ERROR ();
17676  }
17677 
17678  error_code = qfile_add_tuple_to_list (thread_p, gbstate->output_file, gbstate->output_tplrec->tpl);
17679  if (error_code != NO_ERROR)
17680  {
17681  ASSERT_ERROR ();
17683  }
17684  break;
17685 
17686  default:
17687  break;
17688  }
17689 
17690  gbstate->xasl->groupby_stats.rows++;
17691 
17692 wrapup:
17693  /* clear agg_list, since we moved aggregate values here beforehand */
17695  return;
17696 
17697 exit_on_error:
17698  ASSERT_ERROR_AND_SET (gbstate->state);
17699  goto wrapup;
17700 }
17701 
17702 /*
17703  * qexec_gby_start_group_dim () -
17704  * return:
17705  * gbstate(in):
17706  * recdes(in):
17707  */
17708 static void
17710 {
17711  int i;
17712 
17713  /* start all groups */
17714  for (i = 1; i < gbstate->g_dim_levels; i++)
17715  {
17716  qexec_gby_start_group (thread_p, gbstate, NULL, i);
17717  }
17718  qexec_gby_start_group (thread_p, gbstate, recdes, 0);
17719 
17720  return;
17721 }
17722 
17723 /*
17724  * qexec_gby_start_group () -
17725  * return:
17726  * gbstate(in):
17727  * recdes(in):
17728  * N(in): dimension ID
17729  */
17730 static void
17731 qexec_gby_start_group (THREAD_ENTRY * thread_p, GROUPBY_STATE * gbstate, const RECDES * recdes, int N)
17732 {
17733  XASL_STATE *xasl_state = gbstate->xasl_state;
17734  int error;
17735 
17736  if (gbstate->state != NO_ERROR)
17737  {
17738  return;
17739  }
17740 
17741  if (gbstate->g_dim == NULL || N >= gbstate->g_dim_levels)
17742  {
17743  assert (false);
17745  }
17746 
17747  assert (gbstate->g_dim[N].d_flag != GROUPBY_DIM_FLAG_NONE);
17748 
17749  if (N == 0)
17750  {
17751  /*
17752  * Record the new key; keep it in SORT_KEY format so we can continue
17753  * to use the SORTKEY_INFO version of the comparison functions.
17754  *
17755  * WARNING: the sort module doesn't seem to set recdes->area_size
17756  * reliably, so the only thing we can rely on is recdes->length.
17757  */
17758 
17759  /* when group by skip, we do not use the RECDES because the list is already sorted */
17760  if (recdes)
17761  {
17762  if (gbstate->current_key.area_size < recdes->length)
17763  {
17764  void *tmp;
17765 
17766  tmp = db_private_realloc (thread_p, gbstate->current_key.data, recdes->area_size);
17767  if (tmp == NULL)
17768  {
17770  }
17771  gbstate->current_key.data = (char *) tmp;
17772  gbstate->current_key.area_size = recdes->area_size;
17773  }
17774  memcpy (gbstate->current_key.data, recdes->data, recdes->length);
17775  gbstate->current_key.length = recdes->length;
17776  }
17777  }
17778 
17779  /* (Re)initialize the various accumulator variables... */
17781  error = qdata_initialize_aggregate_list (thread_p, gbstate->g_dim[N].d_agg_list, gbstate->xasl_state->query_id);
17782  if (error != NO_ERROR)
17783  {
17785  }
17786 
17787 wrapup:
17788  return;
17789 
17790 exit_on_error:
17791  assert (er_errid () != NO_ERROR);
17792  gbstate->state = er_errid ();
17793  goto wrapup;
17794 }
17795 
17796 /*
17797  * qexec_gby_init_group_dim () - initialize Data Set dimentions
17798  * return:
17799  * gbstate(in):
17800  */
17801 static int
17803 {
17804  int i;
17805  AGGREGATE_TYPE *agg, *aggp, *aggr;
17806 
17807  if (gbstate == NULL) /* sanity check */
17808  {
17809  assert (false);
17810  return ER_FAILED;
17811  }
17812 
17813 #if 1 /* TODO - create Data Set; rollup, cube, grouping set */
17814  gbstate->g_dim_levels = 1;
17815  if (gbstate->with_rollup)
17816  {
17817  gbstate->g_dim_levels += gbstate->key_info.nkeys;
17818  }
17819 #endif
17820 
17821  assert (gbstate->g_dim_levels > 0);
17822 
17823  gbstate->g_dim = (GROUPBY_DIMENSION *) db_private_alloc (NULL, gbstate->g_dim_levels * sizeof (GROUPBY_DIMENSION));
17824  if (gbstate->g_dim == NULL)
17825  {
17826  return ER_FAILED;
17827  }
17828 
17829 
17830  /* set aggregation colunms */
17831  for (i = 0; i < gbstate->g_dim_levels; i++)
17832  {
17833  gbstate->g_dim[i].d_flag = GROUPBY_DIM_FLAG_NONE;
17834 
17835  if (i == 0)
17836  {
17838  }
17839 #if 1 /* TODO - set dimension flag */
17840  if (gbstate->with_rollup)
17841  {
17843  }
17844 #endif
17845  gbstate->g_dim[i].d_flag = (GROUPBY_DIMENSION_FLAG) (gbstate->g_dim[i].d_flag | GROUPBY_DIM_FLAG_CUBE);
17846 
17847  if (gbstate->g_output_agg_list)
17848  {
17849  agg = gbstate->g_output_agg_list;
17850  gbstate->g_dim[i].d_agg_list = aggp = (AGGREGATE_TYPE *) db_private_alloc (NULL, sizeof (AGGREGATE_TYPE));
17851  if (aggp == NULL)
17852  {
17853  return ER_FAILED;
17854  }
17855  memcpy (gbstate->g_dim[i].d_agg_list, agg, sizeof (AGGREGATE_TYPE));
17858 
17859  while ((agg = agg->next))
17860  {
17861  aggr = (AGGREGATE_TYPE *) db_private_alloc (NULL, sizeof (AGGREGATE_TYPE));
17862  if (aggr == NULL)
17863  {
17864  return ER_FAILED;
17865  }
17866  memcpy (aggr, agg, sizeof (AGGREGATE_TYPE));
17869  aggp->next = aggr;
17870  aggp = aggr;
17871  }
17872  }
17873  else
17874  {
17875  gbstate->g_dim[i].d_agg_list = NULL;
17876  }
17877  }
17878 
17879  return NO_ERROR;
17880 }
17881 
17882 /*
17883  * qexec_gby_clear_group_dim() - destroy aggregates lists
17884  * return:
17885  * gbstate(in):
17886  */
17887 static void
17889 {
17890  int i;
17891  AGGREGATE_TYPE *agg, *next_agg;
17892 
17893  assert (gbstate != NULL);
17894  assert (gbstate->g_dim != NULL);
17895 
17896  if (gbstate && gbstate->g_dim)
17897  {
17898  for (i = 0; i < gbstate->g_dim_levels; i++)
17899  {
17900  agg = gbstate->g_dim[i].d_agg_list;
17901  while (agg)
17902  {
17903  next_agg = agg->next;
17904 
17907  if (agg->list_id)
17908  {
17909  /* close and destroy temporary list files */
17910  qfile_close_list (thread_p, agg->list_id);
17911  qfile_destroy_list (thread_p, agg->list_id);
17912  }
17913 
17914  db_private_free (NULL, agg);
17915 
17916  agg = next_agg;
17917  }
17918  }
17919  db_private_free_and_init (NULL, gbstate->g_dim);
17920  }
17921 }
17922 
17923 /*
17924  * qexec_execute_do_stmt () - Execution function for DO statement
17925  * return:
17926  * xasl(in):
17927  * xasl_state(in):
17928  */
17929 static int
17931 {
17932  REGU_VARIABLE_LIST valptr_p = xasl->outptr_list->valptrp;
17933  DB_VALUE *dbval_p;
17934  int error = NO_ERROR;
17935 
17936  while (valptr_p)
17937  {
17938  error = fetch_peek_dbval (thread_p, &valptr_p->value, &xasl_state->vd, NULL, NULL, NULL, &dbval_p);
17939  if (error != NO_ERROR)
17940  {
17941  break;
17942  }
17943  else
17944  {
17945  if (dbval_p)
17946  {
17947  pr_clear_value (dbval_p);
17948  }
17949  valptr_p = valptr_p->next;
17950  }
17951  }
17952 
17953  return error;
17954 }
17955 
17956 /*
17957  * bf2df_str_compare () - compare paths strings by integer groups
17958  * between dot characters
17959  * return: DB_LT, DB_EQ, or DB_GT
17960  * s0(in): first string
17961  * l0(in): length of first string
17962  * s1(in): second string
17963  * l1(in): length of second string
17964  */
17966 bf2df_str_compare (const unsigned char *s0, int l0, const unsigned char *s1, int l1)
17967 {
17968  DB_BIGINT b0, b1;
17969  const unsigned char *e0 = s0 + l0;
17970  const unsigned char *e1 = s1 + l1;
17971 
17972  if (!s0 || !s1)
17973  {
17974  return DB_UNK;
17975  }
17976 
17977  while (s0 < e0 && s1 < e1)
17978  {
17979  b0 = b1 = 0;
17980 
17981  /* find next dot in s0 */
17982  while (s0 < e0 && *s0 != '.')
17983  {
17984  if (*s0 >= '0' && *s0 <= '9')
17985  {
17986  b0 = b0 * 10 + (*s0 - '0');
17987  }
17988  s0++;
17989  }
17990 
17991  /* find next dot in s1 */
17992  while (s1 < e1 && *s1 != '.')
17993  {
17994  if (*s1 >= '0' && *s1 <= '9')
17995  {
17996  b1 = b1 * 10 + (*s1 - '0');
17997  }
17998  s1++;
17999  }
18000 
18001  /* compare integers */
18002  if (b0 > b1)
18003  {
18004  return DB_GT;
18005  }
18006  if (b0 < b1)
18007  {
18008  return DB_LT;
18009  }
18010 
18011  /* both equal in this group, find next one */
18012  if (*s0 == '.')
18013  {
18014  s0++;
18015  }
18016  if (*s1 == '.')
18017  {
18018  s1++;
18019  }
18020  }
18021 
18022  /* one or both strings finished */
18023  if (s0 == e0 && s1 == e1)
18024  {
18025  /* both equal */
18026  return DB_EQ;
18027  }
18028  else if (s0 == e0)
18029  {
18030  return DB_LT;
18031  }
18032  else if (s1 == e1)
18033  {
18034  return DB_GT;
18035  }
18036  return DB_UNK;
18037 }
18038 
18039 /*
18040  * bf2df_str_cmpdisk () -
18041  * return: DB_LT, DB_EQ, or DB_GT
18042  */
18044 bf2df_str_cmpdisk (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion, int total_order, int *start_colp)
18045 {
18047  char *str1, *str2;
18048  int str_length1, str1_compressed_length = 0, str1_decompressed_length = 0;
18049  int str_length2, str2_compressed_length = 0, str2_decompressed_length = 0;
18050  OR_BUF buf1, buf2;
18051  int rc = NO_ERROR;
18052  char *string1 = NULL, *string2 = NULL;
18053  bool alloced_string1 = false, alloced_string2 = false;
18054 
18055  str1 = (char *) mem1;
18056  str2 = (char *) mem2;
18057 
18058  /* generally, data is short enough */
18059  str_length1 = OR_GET_BYTE (str1);
18060  str_length2 = OR_GET_BYTE (str2);
18062  {
18063  str1 += OR_BYTE_SIZE;
18064  str2 += OR_BYTE_SIZE;
18065  return bf2df_str_compare ((unsigned char *) str1, str_length1, (unsigned char *) str2, str_length2);
18066  }
18067 
18069  || str_length2 == OR_MINIMUM_STRING_LENGTH_FOR_COMPRESSION);
18070 
18071  /* String 1 */
18072  or_init (&buf1, str1, 0);
18073  if (str_length1 == OR_MINIMUM_STRING_LENGTH_FOR_COMPRESSION)
18074  {
18075  rc = or_get_varchar_compression_lengths (&buf1, &str1_compressed_length, &str1_decompressed_length);
18076  if (rc != NO_ERROR)
18077  {
18078  goto cleanup;
18079  }
18080 
18081  string1 = (char *) db_private_alloc (NULL, str1_decompressed_length + 1);
18082  if (string1 == NULL)
18083  {
18084  /* Error report */
18085  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, str1_decompressed_length);
18086  goto cleanup;
18087  }
18088 
18089  alloced_string1 = true;
18090 
18091  rc = pr_get_compressed_data_from_buffer (&buf1, string1, str1_compressed_length, str1_decompressed_length);
18092  if (rc != NO_ERROR)
18093  {
18094  goto cleanup;
18095  }
18096 
18097  str_length1 = str1_decompressed_length;
18098  string1[str_length1] = '\0';
18099  }
18100  else
18101  {
18102  /* Skip the size byte */
18103  string1 = str1 + OR_BYTE_SIZE;
18104  }
18105 
18106  if (rc != NO_ERROR)
18107  {
18108  ASSERT_ERROR ();
18109  goto cleanup;
18110  }
18111 
18112  /* String 2 */
18113  or_init (&buf2, str2, 0);
18114  if (str_length2 == OR_MINIMUM_STRING_LENGTH_FOR_COMPRESSION)
18115  {
18116  rc = or_get_varchar_compression_lengths (&buf2, &str2_compressed_length, &str2_decompressed_length);
18117  if (rc != NO_ERROR)
18118  {
18119  goto cleanup;
18120  }
18121 
18122  string2 = (char *) db_private_alloc (NULL, str2_decompressed_length + 1);
18123  if (string2 == NULL)
18124  {
18125  /* Error report */
18126  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, str2_decompressed_length);
18127  goto cleanup;
18128  }
18129 
18130  alloced_string2 = true;
18131 
18132  rc = pr_get_compressed_data_from_buffer (&buf2, string2, str2_compressed_length, str2_decompressed_length);
18133  if (rc != NO_ERROR)
18134  {
18135  goto cleanup;
18136  }
18137 
18138  str_length2 = str2_decompressed_length;
18139  string2[str_length2] = '\0';
18140  }
18141  else
18142  {
18143  /* Skip the size byte */
18144  string2 = str2 + OR_BYTE_SIZE;
18145  }
18146 
18147  if (rc != NO_ERROR)
18148  {
18149  ASSERT_ERROR ();
18150  goto cleanup;
18151  }
18152 
18153  /* Compare the strings */
18154  c = bf2df_str_compare ((unsigned char *) string1, str_length1, (unsigned char *) string2, str_length2);
18155  /* Clean up the strings */
18156  if (string1 != NULL && alloced_string1 == true)
18157  {
18158  db_private_free_and_init (NULL, string1);
18159  }
18160 
18161  if (string2 != NULL && alloced_string2 == true)
18162  {
18163  db_private_free_and_init (NULL, string2);
18164  }
18165 
18166  return c;
18167 
18168 cleanup:
18169  if (string1 != NULL && alloced_string1 == true)
18170  {
18171  db_private_free_and_init (NULL, string1);
18172  }
18173 
18174  if (string2 != NULL && alloced_string2 == true)
18175  {
18176  db_private_free_and_init (NULL, string2);
18177  }
18178 
18179  return DB_UNK;
18180 }
18181 
18182 /*
18183  * bf2df_str_cmpval () -
18184  * return: DB_LT, DB_EQ, or DB_GT
18185  */
18187 bf2df_str_cmpval (DB_VALUE * value1, DB_VALUE * value2, int do_coercion, int total_order, int *start_colp,
18188  int collation)
18189 {
18190  const unsigned char *string1 = REINTERPRET_CAST (const unsigned char *, db_get_string (value1));
18191  const unsigned char *string2 = REINTERPRET_CAST (const unsigned char *, db_get_string (value2));
18192 
18193  if (string1 == NULL || string2 == NULL)
18194  {
18195  return DB_UNK;
18196  }
18197 
18198  return bf2df_str_compare (string1, (int) db_get_string_size (value1), string2, (int) db_get_string_size (value2));
18199 }
18200 
18201 /*
18202  * qexec_resolve_domains_on_sort_list () - checks if the domains in the
18203  * 'order_list' are all solved, and if any is still unresolved (VARIABLE)
18204  * it will be replaced with the domain of corresponding element from
18205  * 'reference_regu_list'
18206  * order_list(in/out): sort list to be checked, may be empty (NULL)
18207  * reference_regu_list(in): reference list of regu variable with concrete
18208  * domains
18209  */
18210 static void
18212 {
18213  int ref_curr_pos = 0;
18214  SORT_LIST *orderby_ptr = NULL;
18215  REGU_VARIABLE_LIST regu_list;
18216 
18217  assert (reference_regu_list != NULL);
18218 
18219  if (order_list == NULL)
18220  {
18221  /* nothing to check */
18222  return;
18223  }
18224 
18225  for (orderby_ptr = order_list; orderby_ptr != NULL; orderby_ptr = orderby_ptr->next)
18226  {
18227  if (TP_DOMAIN_TYPE (orderby_ptr->pos_descr.dom) == DB_TYPE_VARIABLE
18229  {
18230  ref_curr_pos = orderby_ptr->pos_descr.pos_no;
18231  regu_list = reference_regu_list;
18232  while (ref_curr_pos > 0 && regu_list)
18233  {
18234  regu_list = regu_list->next;
18235  ref_curr_pos--;
18236  }
18237  if (regu_list)
18238  {
18239  orderby_ptr->pos_descr.dom = regu_list->value.domain;
18240  }
18241  }
18242  }
18243 }
18244 
18245 /*
18246  * qexec_resolve_domains_for_group_by () - checks if the domains in the
18247  * various lists of 'buildlist' node are all solved, and if any is still
18248  * unresolved (VARIABLE), it will be replaced with the domain of
18249  * corresponding element from 'reference_regu_list'
18250  *
18251  * buildlist(in/out): buildlist for GROUP BY
18252  * reference_out_list(in): reference output list of regu variable with
18253  * concrete domains
18254  *
18255  * Note : this function is used for statements with GROUP BY clause
18256  */
18257 static void
18259 {
18260  int ref_index = 0;
18261  REGU_VARIABLE_LIST group_regu = NULL;
18262  REGU_VARIABLE_LIST reference_regu_list = reference_out_list->valptrp;
18263  AGGREGATE_TYPE *agg_p;
18264 
18265  assert (buildlist != NULL && reference_regu_list != NULL);
18266 
18267  /* domains in GROUP BY list (this is a SORT_LIST) */
18268  qexec_resolve_domains_on_sort_list (buildlist->groupby_list, reference_regu_list);
18269 
18270  /* following code aims to resolve VARIABLE domains in GROUP BY lists: g_regu_list, g_agg_list, g_outprr_list,
18271  * g_hk_regu_list; pointer values are used to match the REGU VARIABLES */
18272  for (group_regu = buildlist->g_regu_list; group_regu != NULL; group_regu = group_regu->next)
18273  {
18274  int pos_in_ref_list = 0;
18275  QPROC_DB_VALUE_LIST g_val_list = NULL;
18276  AGGREGATE_TYPE *group_agg = NULL;
18277  bool val_in_g_val_list_found = false;
18278  bool g_agg_val_found = false;
18279  DB_VALUE *val_list_ref_dbvalue = NULL;
18280  TP_DOMAIN *ref_domain = NULL;
18281  REGU_VARIABLE_LIST ref_regu = NULL;
18282  REGU_VARIABLE_LIST group_out_regu = NULL;
18283  REGU_VARIABLE_LIST hk_regu = NULL;
18284 
18285  if (group_regu->value.domain == NULL
18286  || (TP_DOMAIN_TYPE (group_regu->value.domain) != DB_TYPE_VARIABLE
18287  && TP_DOMAIN_COLLATION_FLAG (group_regu->value.domain) == TP_DOMAIN_COLL_NORMAL))
18288  {
18289  continue;
18290  }
18291 
18292  pos_in_ref_list = (group_regu->value.type == TYPE_POSITION) ? group_regu->value.value.pos_descr.pos_no : -1;
18293 
18294  if (pos_in_ref_list < 0)
18295  {
18296  continue;
18297  }
18298 
18299  assert (pos_in_ref_list < reference_out_list->valptr_cnt);
18300 
18301  /* goto position */
18302  for (ref_regu = reference_regu_list, ref_index = 0; ref_regu != NULL && ref_index < pos_in_ref_list;
18303  ref_regu = ref_regu->next, ref_index++)
18304  {
18305  ;
18306  }
18307 
18308  assert (ref_index == pos_in_ref_list);
18309 
18310  ref_domain = ref_regu->value.domain;
18311  if (TP_DOMAIN_TYPE (ref_domain) == DB_TYPE_VARIABLE
18313  {
18314  /* next GROUP BY item */
18315  continue;
18316  }
18317 
18318  /* update domain in g_regu_list */
18319  group_regu->value.domain = ref_domain;
18320 
18321  assert (group_regu->value.type == TYPE_POSITION);
18322  group_regu->value.value.pos_descr.dom = ref_domain;
18323 
18324  if (buildlist->g_hash_eligible)
18325  {
18326  /* all reguvars in g_hk_regu_list are also in g_regu_list; match them by position and update g_hk_regu_list */
18327  for (hk_regu = buildlist->g_hk_sort_regu_list; hk_regu != NULL; hk_regu = hk_regu->next)
18328  {
18329  if (hk_regu->value.type == TYPE_POSITION && hk_regu->value.value.pos_descr.pos_no == pos_in_ref_list)
18330  {
18331  hk_regu->value.value.pos_descr.dom = ref_domain;
18332  hk_regu->value.domain = ref_domain;
18333  }
18334  }
18335  }
18336 
18337  /* find value in g_val_list pointed to by vfetch_to ; also find in g_agg_list (if any), the same value
18338  * indentified by pointer value in operand */
18339  for (g_val_list = buildlist->g_val_list->valp; g_val_list != NULL; g_val_list = g_val_list->next)
18340  {
18341  if (g_val_list->val == group_regu->value.vfetch_to)
18342  {
18343  val_in_g_val_list_found = true;
18344  val_list_ref_dbvalue = g_val_list->val;
18345  break;
18346  }
18347  }
18348 
18349  /* search for corresponding aggregate, by matching the operands REGU VAR update the domains for aggregate and
18350  * aggregate's operand */
18351  for (group_agg = buildlist->g_agg_list; group_agg != NULL; group_agg = group_agg->next)
18352  {
18353  if (group_agg->opr_dbtype != DB_TYPE_VARIABLE && !TP_TYPE_HAS_COLLATION (group_agg->opr_dbtype))
18354  {
18355  continue;
18356  }
18357 
18358  REGU_VARIABLE operand = group_agg->operands->value;
18359 
18360  assert (operand.type == TYPE_CONSTANT);
18361 
18362  if ((TP_DOMAIN_TYPE (operand.domain) == DB_TYPE_VARIABLE
18363  || TP_DOMAIN_COLLATION_FLAG (operand.domain) != TP_DOMAIN_COLL_NORMAL)
18364  && operand.value.dbvalptr == val_list_ref_dbvalue)
18365  {
18366  /* update domain of aggregate's operand */
18367  operand.domain = ref_domain;
18368  group_agg->opr_dbtype = TP_DOMAIN_TYPE (ref_domain);
18369 
18370  if (TP_DOMAIN_TYPE (group_agg->domain) == DB_TYPE_VARIABLE
18372  {
18373  /* set domain at run-time for MEDIAN, PERCENTILE funcs */
18374  if (QPROC_IS_INTERPOLATION_FUNC (group_agg))
18375  {
18376  continue;
18377  }
18378  else if (group_agg->function == PT_GROUP_CONCAT)
18379  {
18380  /* result of GROUP_CONCAT is always string */
18381  if (!TP_TYPE_HAS_COLLATION (TP_DOMAIN_TYPE (ref_domain)))
18382  {
18384  }
18385  group_agg->domain = ref_domain;
18386 
18387  db_value_domain_init (group_agg->accumulator.value, TP_DOMAIN_TYPE (ref_domain),
18390  TP_DOMAIN_COLLATION (ref_domain));
18391 
18392  g_agg_val_found = true;
18393  break;
18394  }
18395 
18396  assert (group_agg->function == PT_MIN || group_agg->function == PT_MAX
18397  || group_agg->function == PT_SUM);
18398 
18399  group_agg->domain = ref_domain;
18403  {
18405  TP_DOMAIN_COLLATION (ref_domain));
18406  }
18407  }
18408  else
18409  {
18410  /* these aggregates have 'group_agg->domain' and 'group_agg->value' already initialized */
18411  assert (group_agg->function == PT_GROUP_CONCAT || group_agg->function == PT_AGG_BIT_AND
18412  || group_agg->function == PT_AGG_BIT_OR || group_agg->function == PT_AGG_BIT_XOR
18413  || group_agg->function == PT_COUNT || group_agg->function == PT_AVG
18414  || group_agg->function == PT_STDDEV || group_agg->function == PT_VARIANCE
18415  || group_agg->function == PT_STDDEV_POP || group_agg->function == PT_VAR_POP
18416  || group_agg->function == PT_STDDEV_SAMP || group_agg->function == PT_VAR_SAMP
18417  || group_agg->function == PT_JSON_ARRAYAGG || group_agg->function == PT_JSON_OBJECTAGG);
18418  }
18419 
18420  g_agg_val_found = true;
18421  break;
18422  }
18423  }
18424 
18425  if (!g_agg_val_found)
18426  {
18427  continue;
18428  }
18429 
18430  /* search in g_outptr_list for the same value pointer as the value in g_agg_list->value , and update it with the
18431  * same domain */
18432  for (group_out_regu = buildlist->g_outptr_list->valptrp; group_out_regu != NULL;
18433  group_out_regu = group_out_regu->next)
18434  {
18435  assert (group_agg != NULL);
18436  if (group_out_regu->value.type == TYPE_CONSTANT
18437  && group_out_regu->value.value.dbvalptr == group_agg->accumulator.value)
18438  {
18439  if (TP_DOMAIN_TYPE (group_out_regu->value.domain) == DB_TYPE_VARIABLE
18440  || TP_DOMAIN_COLLATION_FLAG (group_out_regu->value.domain) != TP_DOMAIN_COLL_NORMAL)
18441  {
18442  group_out_regu->value.domain = ref_domain;
18443  }
18444  /* aggregate found in g_outptr_list, end */
18445  break;
18446  }
18447  }
18448  }
18449 
18450  /* treat case with only NULL values */
18451  for (agg_p = buildlist->g_agg_list; agg_p; agg_p = agg_p->next)
18452  {
18453  if (agg_p->accumulator_domain.value_dom == NULL)
18454  {
18455  agg_p->accumulator_domain.value_dom = &tp_Null_domain;
18456  }
18457 
18458  if (agg_p->accumulator_domain.value2_dom == NULL)
18459  {
18460  agg_p->accumulator_domain.value2_dom = &tp_Null_domain;
18461  }
18462  }
18463 
18464  /* update hash aggregation domains */
18465  if (buildlist->g_hash_eligible)
18466  {
18467  AGGREGATE_HASH_CONTEXT *context = buildlist->agg_hash_context;
18468  int i, index;
18469 
18470  /* update key domains */
18471  group_regu = buildlist->g_hk_sort_regu_list;
18472  for (i = 0; i < buildlist->g_hkey_size && group_regu != NULL; i++, group_regu = group_regu->next)
18473  {
18474  if (TP_DOMAIN_TYPE (context->key_domains[i]) == DB_TYPE_VARIABLE
18476  {
18477  context->key_domains[i] = group_regu->value.domain;
18478  }
18479  }
18480 
18481  /* update type lists of list files */
18482  for (i = 0; i < buildlist->g_hkey_size; i++)
18483  {
18484  /* partial list */
18485  context->part_list_id->type_list.domp[i] = context->key_domains[i];
18486 
18487  /* sorted partial list */
18488  context->sorted_part_list_id->type_list.domp[i] = context->key_domains[i];
18489  }
18490 
18491  for (i = 0; i < buildlist->g_func_count; i++)
18492  {
18493  index = buildlist->g_hkey_size + i * 3;
18494 
18495  /* partial list */
18496  context->part_list_id->type_list.domp[index] = context->accumulator_domains[i]->value_dom;
18497  context->part_list_id->type_list.domp[index + 1] = context->accumulator_domains[i]->value2_dom;
18498  context->part_list_id->type_list.domp[index + 2] = &tp_Integer_domain;
18499 
18500  /* sorted partial list */
18501  context->sorted_part_list_id->type_list.domp[index] = context->accumulator_domains[i]->value_dom;
18502  context->sorted_part_list_id->type_list.domp[index + 1] = context->accumulator_domains[i]->value2_dom;
18503  context->sorted_part_list_id->type_list.domp[index + 2] = &tp_Integer_domain;
18504  }
18505  }
18506 }
18507 
18508 /*
18509  * qexec_resolve_domains_for_aggregation () - update domains of aggregate
18510  * functions and accumulators
18511  * returns: error code or NO_ERROR
18512  * thread_p(in): current thread
18513  * agg_p(in): aggregate node
18514  * xasl_state(in): XASL state
18515  * tplrec(in): tuple record used for fetching of value
18516  * regu_list(in): regulist (NULL for none)
18517  * resolved(out): true if all domains are resolved, false otherwise
18518  */
18519 static int
18521  QFILE_TUPLE_RECORD * tplrec, REGU_VARIABLE_LIST regu_list, int *resolved)
18522 {
18523  TP_DOMAIN *tmp_domain_p;
18524  TP_DOMAIN_STATUS status;
18525  DB_VALUE *dbval;
18526  int error;
18527  HL_HEAPID save_heapid = 0;
18528 
18529  /* fetch values */
18530  if (regu_list != NULL)
18531  {
18532  if (fetch_val_list (thread_p, regu_list, &xasl_state->vd, NULL, NULL, tplrec->tpl, true) != NO_ERROR)
18533  {
18534  return ER_FAILED;
18535  }
18536  }
18537 
18538  /* start off as resolved */
18539  *resolved = 1;
18540 
18541  /* iterate functions */
18542  for (; agg_p != NULL; agg_p = agg_p->next)
18543  {
18544  if (agg_p->function == PT_CUME_DIST || agg_p->function == PT_PERCENT_RANK)
18545  {
18546  /* operands for CUME_DIST and PERCENT_RANK are of no interest here */
18547  continue;
18548  }
18549 
18550  if (agg_p->function == PT_COUNT || agg_p->function == PT_COUNT_STAR)
18551  {
18552  /* COUNT and COUNT(*) always have the same signature */
18553  agg_p->accumulator_domain.value_dom = &tp_Integer_domain;
18554  agg_p->accumulator_domain.value2_dom = &tp_Null_domain;
18555 
18556  continue;
18557  }
18558 
18559  if (agg_p->function == PT_JSON_ARRAYAGG || agg_p->function == PT_JSON_OBJECTAGG)
18560  {
18561  /* PT_JSON_ARRAYAGG and PT_JSON_OBJECTAGG always have the same signature */
18562  agg_p->accumulator_domain.value_dom = &tp_Json_domain;
18563  agg_p->accumulator_domain.value2_dom = &tp_Null_domain;
18564  continue;
18565  }
18566 
18567  DB_VALUE benchmark_dummy_dbval;
18568  db_make_double (&benchmark_dummy_dbval, 0);
18569  if (agg_p->operands->value.type == TYPE_FUNC && agg_p->operands->value.value.funcp != NULL
18570  && agg_p->operands->value.value.funcp->ftype == F_BENCHMARK)
18571  {
18572  // In case we have a benchmark function we want ot avoid the usual superflous function evaluation
18573  dbval = &benchmark_dummy_dbval;
18574  }
18575  else
18576  {
18577  /* fetch function operand */
18578  if (fetch_peek_dbval (thread_p, &agg_p->operands->value, &xasl_state->vd, NULL, NULL, NULL, &dbval) !=
18579  NO_ERROR)
18580  {
18581  return ER_FAILED;
18582  }
18583  }
18584 
18585  /* handle NULL value */
18586  if (dbval == NULL || DB_IS_NULL (dbval))
18587  {
18588  if (agg_p->opr_dbtype == DB_TYPE_VARIABLE || agg_p->accumulator_domain.value_dom == NULL
18589  || agg_p->accumulator_domain.value2_dom == NULL)
18590  {
18591  /* domains will not be resolved at this time */
18592  *resolved = 0;
18593  }
18594 
18595  /* no need to continue */
18596  continue;
18597  }
18598 
18599  /* update variable domain of function */
18601  {
18603  && (agg_p->function == PT_SUM || agg_p->function == PT_AVG))
18604  {
18606  }
18607  else if (!TP_IS_CHAR_TYPE (DB_VALUE_DOMAIN_TYPE (dbval)) && agg_p->function == PT_GROUP_CONCAT)
18608  {
18610  }
18611  else
18612  {
18613  agg_p->domain = tp_domain_resolve_value (dbval, NULL);
18614  }
18615  agg_p->opr_dbtype = TP_DOMAIN_TYPE (agg_p->domain);
18616  }
18617 
18618  /* set up domains of accumulator */
18619  if (agg_p->domain != NULL && agg_p->opr_dbtype != DB_TYPE_VARIABLE
18620  && (agg_p->accumulator_domain.value_dom == NULL || agg_p->accumulator_domain.value2_dom == NULL))
18621  {
18622  switch (agg_p->function)
18623  {
18624  case PT_AGG_BIT_AND:
18625  case PT_AGG_BIT_OR:
18626  case PT_AGG_BIT_XOR:
18627  case PT_MIN:
18628  case PT_MAX:
18629  agg_p->accumulator_domain.value_dom = agg_p->domain;
18630  agg_p->accumulator_domain.value2_dom = &tp_Null_domain;
18631  break;
18632 
18633  case PT_AVG:
18634  case PT_SUM:
18635  if (TP_IS_NUMERIC_TYPE (DB_VALUE_TYPE (dbval)))
18636  {
18637  if (TP_DOMAIN_TYPE (agg_p->domain) == DB_TYPE_NUMERIC)
18638  {
18639  agg_p->accumulator_domain.value_dom =
18641  0);
18642  }
18643  else if (DB_VALUE_TYPE (dbval) == DB_TYPE_NUMERIC)
18644  {
18645  agg_p->accumulator_domain.value_dom =
18647  NULL, 0);
18648  }
18649  else if (DB_VALUE_TYPE (dbval) == DB_TYPE_FLOAT)
18650  {
18651  agg_p->accumulator_domain.value_dom =
18653  NULL, 0);
18654  }
18655  else
18656  {
18657  agg_p->accumulator_domain.value_dom = tp_domain_resolve_default (DB_VALUE_TYPE (dbval));
18658  }
18659  }
18660  else
18661  {
18662  agg_p->accumulator_domain.value_dom = agg_p->domain;
18663  }
18664  agg_p->accumulator_domain.value2_dom = &tp_Null_domain;
18665  break;
18666 
18667  case PT_STDDEV:
18668  case PT_STDDEV_POP:
18669  case PT_STDDEV_SAMP:
18670  case PT_VARIANCE:
18671  case PT_VAR_POP:
18672  case PT_VAR_SAMP:
18673  agg_p->accumulator_domain.value_dom = &tp_Double_domain;
18674  agg_p->accumulator_domain.value2_dom = &tp_Double_domain;
18675  break;
18676 
18677  case PT_GROUPBY_NUM:
18678  agg_p->accumulator_domain.value_dom = &tp_Null_domain;
18679  agg_p->accumulator_domain.value2_dom = &tp_Null_domain;
18680  break;
18681 
18682  case PT_GROUP_CONCAT:
18683  agg_p->accumulator_domain.value_dom = agg_p->domain;
18684  agg_p->accumulator_domain.value2_dom = &tp_Null_domain;
18685  break;
18686 
18687  case PT_MEDIAN:
18688  case PT_PERCENTILE_CONT:
18689  case PT_PERCENTILE_DISC:
18690  switch (agg_p->opr_dbtype)
18691  {
18692  case DB_TYPE_SHORT:
18693  case DB_TYPE_INTEGER:
18694  case DB_TYPE_BIGINT:
18695  case DB_TYPE_FLOAT:
18696  case DB_TYPE_DOUBLE:
18697  case DB_TYPE_MONETARY:
18698  case DB_TYPE_NUMERIC:
18699  case DB_TYPE_DATE:
18700  case DB_TYPE_DATETIME:
18701  case DB_TYPE_DATETIMETZ:
18702  case DB_TYPE_DATETIMELTZ:
18703  case DB_TYPE_TIMESTAMP:
18704  case DB_TYPE_TIMESTAMPTZ:
18705  case DB_TYPE_TIMESTAMPLTZ:
18706  case DB_TYPE_TIME:
18707  break;
18708 
18709  default:
18710  assert (agg_p->operands->value.type == TYPE_CONSTANT || agg_p->operands->value.type == TYPE_DBVAL
18711  || agg_p->operands->value.type == TYPE_INARITH);
18712 
18713  /* try to cast dbval to double, datetime then time */
18714  tmp_domain_p = tp_domain_resolve_default (DB_TYPE_DOUBLE);
18715 
18717  {
18718  save_heapid = db_change_private_heap (thread_p, 0);
18719  }
18720 
18721  status = tp_value_cast (dbval, dbval, tmp_domain_p, false);
18722  if (status != DOMAIN_COMPATIBLE)
18723  {
18724  /* try datetime */
18726 
18727  status = tp_value_cast (dbval, dbval, tmp_domain_p, false);
18728  }
18729 
18730  /* try time */
18731  if (status != DOMAIN_COMPATIBLE)
18732  {
18733  tmp_domain_p = tp_domain_resolve_default (DB_TYPE_TIME);
18734 
18735  status = tp_value_cast (dbval, dbval, tmp_domain_p, false);
18736  }
18737 
18738  if (save_heapid != 0)
18739  {
18740  (void) db_change_private_heap (thread_p, save_heapid);
18741  save_heapid = 0;
18742  }
18743  else
18744  {
18745  if (status != DOMAIN_COMPATIBLE)
18746  {
18747  pr_clear_value (dbval);
18748  }
18749  }
18750 
18751  if (status != DOMAIN_COMPATIBLE)
18752  {
18755  "DOUBLE, DATETIME or TIME");
18756 
18757  return error;
18758  }
18759 
18760  /* update domain */
18761  agg_p->domain = tmp_domain_p;
18762  agg_p->accumulator_domain.value_dom = tmp_domain_p;
18763  agg_p->accumulator_domain.value2_dom = &tp_Null_domain;
18764  }
18765  break;
18766  default:
18767  break;
18768  }
18769 
18770  /* initialize accumulators */
18771  if (agg_p->accumulator.value != NULL && agg_p->accumulator_domain.value_dom != NULL
18773  {
18774  if (db_value_domain_init (agg_p->accumulator.value, TP_DOMAIN_TYPE (agg_p->accumulator_domain.value_dom),
18776  {
18777  return ER_FAILED;
18778  }
18779  }
18780 
18781  if (agg_p->accumulator.value2 != NULL && agg_p->accumulator_domain.value2_dom != NULL
18783  {
18785  TP_DOMAIN_TYPE (agg_p->accumulator_domain.value2_dom),
18787  {
18788  return ER_FAILED;
18789  }
18790  }
18791  }
18792  }
18793 
18794  /* all ok */
18795  return NO_ERROR;
18796 }
18797 
18798 /*
18799  * qexec_groupby_index() - computes group by on the fly from the index list
18800  * return: NO_ERROR, or ER_code
18801  * xasl(in) :
18802  * xasl_state(in) : XASL tree state information
18803  * tplrec(out) : Tuple record descriptor to store result tuples
18804  *
18805  * Note: Apply the group_by clause to the given list file to group it
18806  * using the specified group_by parameters.
18807  */
18808 int
18810 {
18811  QFILE_LIST_ID *list_id = xasl->list_id;
18812  BUILDLIST_PROC_NODE *buildlist = &xasl->proc.buildlist;
18813  GROUPBY_STATE gbstate;
18814  QFILE_LIST_SCAN_ID input_scan_id;
18815  int result = 0, ls_flag = 0;
18816  DB_VALUE *list_dbvals = NULL;
18817  int i, ncolumns = 0;
18818  SORT_LIST *sort_col = NULL;
18819  bool all_cols_equal = false;
18820  SCAN_CODE scan_code;
18821  QFILE_TUPLE_RECORD tuple_rec = { NULL, 0 };
18822  REGU_VARIABLE_LIST regu_list;
18823  int tuple_cnt = 0;
18824  DB_VALUE val;
18825 
18826  TSC_TICKS start_tick, end_tick;
18827  TSCTIMEVAL tv_diff;
18828 
18829  db_make_null (&val);
18830 
18831  if (buildlist->groupby_list == NULL)
18832  {
18833  return NO_ERROR;
18834  }
18835 
18836  if (thread_is_on_trace (thread_p))
18837  {
18838  tsc_getticks (&start_tick);
18839  xasl->groupby_stats.run_groupby = true;
18840  xasl->groupby_stats.groupby_sort = false;
18841  xasl->groupby_stats.groupby_hash = HS_NONE;
18842  xasl->groupby_stats.rows = 0;
18843  }
18844 
18845  assert (buildlist->g_with_rollup == 0);
18846 
18847  if (qexec_initialize_groupby_state (&gbstate, buildlist->groupby_list, buildlist->g_having_pred,
18848  buildlist->g_grbynum_pred, buildlist->g_grbynum_val, buildlist->g_grbynum_flag,
18849  buildlist->eptr_list, buildlist->g_agg_list, buildlist->g_regu_list,
18850  buildlist->g_val_list, buildlist->g_outptr_list, NULL,
18851  buildlist->g_with_rollup != 0, 0, NULL, xasl, xasl_state, &list_id->type_list,
18852  tplrec) == NULL)
18853  {
18855  }
18856 
18857  assert (gbstate.g_dim_levels == 1);
18858  assert (gbstate.with_rollup == false);
18859 
18860  /*
18861  * Create a new listfile to receive the results.
18862  */
18863  {
18864  QFILE_TUPLE_VALUE_TYPE_LIST output_type_list;
18865  QFILE_LIST_ID *output_list_id;
18866 
18867  if (qdata_get_valptr_type_list (thread_p, buildlist->g_outptr_list, &output_type_list) != NO_ERROR)
18868  {
18870  }
18871  /* If it does not have 'order by'(xasl->orderby_list), then the list file to be open at here will be the last one.
18872  * Otherwise, the last list file will be open at qexec_orderby_distinct(). (Note that only one that can have 'group
18873  * by' is BUILDLIST_PROC type.) And, the top most XASL is the other condition for the list file to be the last
18874  * result file. */
18875 
18876  QFILE_SET_FLAG (ls_flag, QFILE_FLAG_ALL);
18877 
18878  output_list_id =
18879  qfile_open_list (thread_p, &output_type_list, buildlist->after_groupby_list, xasl_state->query_id, ls_flag);
18880 
18881  if (output_type_list.domp)
18882  {
18883  db_private_free_and_init (thread_p, output_type_list.domp);
18884  }
18885 
18886  if (output_list_id == NULL)
18887  {
18889  }
18890 
18891  gbstate.output_file = output_list_id;
18892  }
18893 
18894  if (list_id->tuple_cnt == 0)
18895  {
18896  /* empty unsorted list file, no need to proceed */
18897  qfile_destroy_list (thread_p, list_id);
18898  qfile_close_list (thread_p, gbstate.output_file);
18899  qfile_copy_list_id (list_id, gbstate.output_file, true);
18900  qexec_clear_groupby_state (thread_p, &gbstate); /* will free gbstate.output_file */
18901 
18902  return NO_ERROR;
18903  }
18904  else
18905  {
18906  tuple_cnt = list_id->tuple_cnt;
18907  }
18908 
18909  /*
18910  * Open a scan on the unsorted input file
18911  */
18912  if (qfile_open_list_scan (list_id, &input_scan_id) != NO_ERROR)
18913  {
18915  }
18916  gbstate.input_scan = &input_scan_id;
18917 
18918  /* ... go through all records and identify groups */
18919 
18920  /* count the number of columns in group by */
18921  for (sort_col = xasl->proc.buildlist.groupby_list; sort_col != NULL; sort_col = sort_col->next)
18922  {
18923  ncolumns++;
18924  }
18925 
18926  /* alloc an array to store db_values */
18927  list_dbvals = (DB_VALUE *) db_private_alloc (thread_p, ncolumns * sizeof (DB_VALUE));
18928 
18929  if (list_dbvals == NULL)
18930  {
18932  }
18933 
18934  while (1)
18935  {
18936  if (gbstate.state == SORT_PUT_STOP)
18937  {
18938  break;
18939  }
18940  scan_code = qfile_scan_list_next (thread_p, gbstate.input_scan, &tuple_rec, PEEK);
18941  if (scan_code != S_SUCCESS)
18942  {
18943  break;
18944  }
18945 
18946  /* fetch the values from the tuple according to outptr format check the result in xasl->outptr_list->valptrp */
18947  all_cols_equal = true;
18948 
18949  regu_list = xasl->outptr_list->valptrp;
18950  for (i = 0; i < ncolumns; i++)
18951  {
18952  if (regu_list == NULL)
18953  {
18954  gbstate.state = ER_FAILED;
18955  goto exit_on_error;
18956  }
18957 
18958  if (qexec_get_tuple_column_value (tuple_rec.tpl, i, &val, regu_list->value.domain) != NO_ERROR)
18959  {
18960  gbstate.state = ER_FAILED;
18961  goto exit_on_error;
18962  }
18963 
18964  if (gbstate.input_recs > 0)
18965  {
18966  /* compare old value with current total_order is 1. Then NULLs are equal. */
18967  int c = tp_value_compare (&list_dbvals[i], &val, 1, 1);
18968 
18969  if (c != DB_EQ)
18970  {
18971  /* must be DB_LT or DB_GT */
18972  if (c != DB_LT && c != DB_GT)
18973  {
18974  assert_release (false);
18975  gbstate.state = ER_FAILED;
18976 
18978  }
18979 
18980  /* new group should begin, check code below */
18981  all_cols_equal = false;
18982  }
18983 
18984  pr_clear_value (&list_dbvals[i]);
18985  }
18986 
18987  pr_clone_value (&val, &list_dbvals[i]);
18988 
18989  if (DB_NEED_CLEAR (&val))
18990  {
18991  pr_clear_value (&val);
18992  }
18993 
18994  regu_list = regu_list->next;
18995  }
18996 
18997  if (gbstate.input_recs == 0)
18998  {
18999  /* First record we've seen; put it out and set up the group comparison key(s). */
19000  qexec_gby_start_group_dim (thread_p, &gbstate, NULL);
19001  }
19002  else if (all_cols_equal)
19003  {
19004  /* Still in the same group; accumulate the tuple and proceed, leaving the group key the same. */
19005  }
19006  else
19007  {
19008  assert (gbstate.g_dim_levels == 1);
19009  assert (gbstate.with_rollup == false);
19010 
19011  /* We got a new group; finalize the group we were accumulating, and start a new group using the current key
19012  * as the group key. */
19013  qexec_gby_finalize_group_dim (thread_p, &gbstate, NULL);
19014  }
19015 
19016  qexec_gby_agg_tuple (thread_p, &gbstate, tuple_rec.tpl, COPY);
19017 
19018  gbstate.input_recs++;
19019  }
19020 
19021  /* ... finish grouping */
19022 
19023  /* There may be one unfinished group in the output. If so, finish it */
19024  if (gbstate.input_recs != 0)
19025  {
19026  qexec_gby_finalize_group_dim (thread_p, &gbstate, NULL);
19027  }
19028 
19029  qfile_close_list (thread_p, gbstate.output_file);
19030 
19031  if (gbstate.input_scan)
19032  {
19033  qfile_close_scan (thread_p, gbstate.input_scan);
19034  gbstate.input_scan = NULL;
19035  }
19036  qfile_destroy_list (thread_p, list_id);
19037  qfile_copy_list_id (list_id, gbstate.output_file, true);
19038 
19039  if (XASL_IS_FLAGED (xasl, XASL_IS_MERGE_QUERY) && list_id->tuple_cnt != tuple_cnt)
19040  {
19042  result = ER_FAILED;
19043  }
19044 
19045  if (thread_is_on_trace (thread_p))
19046  {
19047  tsc_getticks (&end_tick);
19048  tsc_elapsed_time_usec (&tv_diff, end_tick, start_tick);
19049  TSC_ADD_TIMEVAL (xasl->groupby_stats.groupby_time, tv_diff);
19050  }
19051 
19052 exit_on_error:
19053 
19054  if (list_dbvals)
19055  {
19056  for (i = 0; i < ncolumns; i++)
19057  {
19058  pr_clear_value (&(list_dbvals[i]));
19059  }
19060  db_private_free (thread_p, list_dbvals);
19061  }
19062 
19063  if (DB_NEED_CLEAR (&val))
19064  {
19065  pr_clear_value (&val);
19066  }
19067 
19068  /* SORT_PUT_STOP set by 'qexec_gby_finalize_group_dim ()' isn't error */
19069  result = (gbstate.state == NO_ERROR || gbstate.state == SORT_PUT_STOP) ? NO_ERROR : ER_FAILED;
19070 
19071  qexec_clear_groupby_state (thread_p, &gbstate);
19072 
19073  return result;
19074 }
19075 
19076 /*
19077  * query_multi_range_opt_check_set_sort_col () - scans the SPEC nodes in the
19078  * XASL and resolves the sorting
19079  * info required for multiple
19080  * range search optimization
19081  *
19082  * return : error code
19083  * thread_p (in) : thread entry
19084  * xasl (in) : xasl node
19085  */
19086 static int
19088 {
19089  DB_VALUE **sort_col_out_val_ref = NULL;
19090  int i = 0, count = 0, index = 0, att_id, sort_index_pos;
19091  REGU_VARIABLE_LIST regu_list = NULL;
19092  SORT_LIST *orderby_list = NULL;
19093  int error = NO_ERROR;
19095  ACCESS_SPEC_TYPE *spec = NULL;
19096 
19097  if (xasl == NULL || xasl->type != BUILDLIST_PROC || xasl->orderby_list == NULL || xasl->spec_list == NULL)
19098  {
19099  return NO_ERROR;
19100  }
19101 
19102  /* find access spec using multi range optimization */
19103  spec = query_multi_range_opt_check_specs (thread_p, xasl);
19104  if (spec == NULL)
19105  {
19106  /* no scan with multi range search optimization was found */
19107  return NO_ERROR;
19108  }
19109  multi_range_opt = &spec->s_id.s.isid.multi_range_opt;
19110  /* initialize sort info for multi range search optimization */
19111  orderby_list = xasl->orderby_list;
19112  while (orderby_list)
19113  {
19114  count++;
19115  orderby_list = orderby_list->next;
19116  }
19117 
19118  /* find the addresses contained in REGU VAR for values used in sorting */
19119  sort_col_out_val_ref = (DB_VALUE **) db_private_alloc (thread_p, count * sizeof (DB_VALUE *));
19120  if (sort_col_out_val_ref == NULL)
19121  {
19123  return ER_OUT_OF_VIRTUAL_MEMORY;
19124  }
19125  for (orderby_list = xasl->orderby_list; orderby_list != NULL; orderby_list = orderby_list->next)
19126  {
19127  i = 0;
19128  /* get sort column from 'outptr_list' */
19129  for (regu_list = xasl->outptr_list->valptrp; regu_list != NULL; regu_list = regu_list->next)
19130  {
19132  {
19133  continue;
19134  }
19135  if (i == orderby_list->pos_descr.pos_no)
19136  {
19137  if (regu_list->value.type == TYPE_CONSTANT)
19138  {
19139  sort_col_out_val_ref[index++] = regu_list->value.value.dbvalptr;
19140  }
19141  break;
19142  }
19143  i++;
19144  }
19145  }
19146  if (index != count)
19147  {
19148  /* this is not supposed to happen */
19149  assert (0);
19150  goto exit_on_error;
19151  }
19152 
19153  if (multi_range_opt->num_attrs == 0)
19154  {
19155  multi_range_opt->num_attrs = count;
19156  multi_range_opt->is_desc_order = (bool *) db_private_alloc (thread_p, count * sizeof (bool));
19157  if (multi_range_opt->is_desc_order == NULL)
19158  {
19160  goto exit_on_error;
19161  }
19162  multi_range_opt->sort_att_idx = (int *) db_private_alloc (thread_p, count * sizeof (int));
19163  if (multi_range_opt->sort_att_idx == NULL)
19164  {
19166  goto exit_on_error;
19167  }
19168  }
19169  else
19170  {
19171  /* is multi_range_opt already initialized? */
19172  assert (0);
19173  }
19174 
19175  for (index = 0, orderby_list = xasl->orderby_list; index < count; index++, orderby_list = orderby_list->next)
19176  {
19177  const DB_VALUE *valp = sort_col_out_val_ref[index];
19178 
19179  att_id = -1;
19180  sort_index_pos = -1;
19181  /* search the ATTR_ID regu 'fetching to' the output list regu used for sorting */
19182  for (regu_list = spec->s_id.s.isid.rest_regu_list; regu_list != NULL; regu_list = regu_list->next)
19183  {
19184  if (regu_list->value.type == TYPE_ATTR_ID && regu_list->value.vfetch_to == valp)
19185  {
19186  att_id = regu_list->value.value.attr_descr.id;
19187  break;
19188  }
19189  }
19190  /* search the attribute in the index attributes */
19191  if (att_id != -1)
19192  {
19193  for (i = 0; i < spec->s_id.s.isid.bt_num_attrs; i++)
19194  {
19195  if (att_id == spec->s_id.s.isid.bt_attr_ids[i])
19196  {
19197  sort_index_pos = i;
19198  break;
19199  }
19200  }
19201  }
19202  if (sort_index_pos == -1)
19203  {
19204  /* REGUs didn't match, at least disable the optimization */
19205  multi_range_opt->use = false;
19206  goto exit;
19207  }
19208  multi_range_opt->is_desc_order[index] = (orderby_list->s_order == S_DESC) ? true : false;
19209  multi_range_opt->sort_att_idx[index] = sort_index_pos;
19210  }
19211 
19212  /* disable order by in XASL for this execution */
19213  if (xasl->option != Q_DISTINCT && xasl->scan_ptr == NULL)
19214  {
19216  XASL_SET_FLAG (xasl, XASL_USES_MRO);
19217  }
19218 
19219 exit:
19220  if (sort_col_out_val_ref)
19221  {
19222  db_private_free_and_init (thread_p, sort_col_out_val_ref);
19223  }
19224  return error;
19225 
19226 exit_on_error:
19227  error = ER_FAILED;
19228  goto exit;
19229 }
19230 
19231 /*
19232  * query_multi_range_opt_check_specs () - searches the XASL tree for the
19233  * enabled multiple range search
19234  * optimized index scan
19235  *
19236  * return : ACCESS_SPEC_TYPE if an index scan with multiple
19237  * range search enabled is found, NULL otherwise
19238  * thread_p (in) : thread entry
19239  * spec_list (in/out) : access spec list
19240  */
19241 static ACCESS_SPEC_TYPE *
19243 {
19244  ACCESS_SPEC_TYPE *spec_list;
19245  for (; xasl != NULL; xasl = xasl->scan_ptr)
19246  {
19247  for (spec_list = xasl->spec_list; spec_list != NULL; spec_list = spec_list->next)
19248  {
19249  if (spec_list->access != ACCESS_METHOD_INDEX || spec_list->type != TARGET_CLASS
19250  || spec_list->s_id.type != S_INDX_SCAN)
19251  {
19252  continue;
19253  }
19254  if (spec_list->s_id.s.isid.multi_range_opt.use)
19255  {
19256  return spec_list;
19257  }
19258  }
19259  }
19260  return NULL;
19261 }
19262 
19263 /*
19264  * qexec_execute_analytic () -
19265  * return: NO_ERROR, or ER_code
19266  * xasl(in) :
19267  * xasl_state(in) : XASL tree state information
19268  * analytic_func_p(in): Analytic function pointer
19269  * tplrec(out) : Tuple record descriptor to store result tuples
19270  * next_func(out) : next unprocessed function
19271  */
19272 static int
19274  ANALYTIC_EVAL_TYPE * analytic_eval, QFILE_TUPLE_RECORD * tplrec, bool is_last)
19275 {
19276  QFILE_LIST_ID *list_id = xasl->list_id;
19277  BUILDLIST_PROC_NODE *buildlist = &xasl->proc.buildlist;
19279  QFILE_LIST_SCAN_ID input_scan_id, interm_scan_id;
19280  OUTPTR_LIST *a_outptr_list;
19281  int ls_flag = 0;
19282  int estimated_pages;
19283  bool finalized = false;
19284  int i = 0;
19285  ANALYTIC_TYPE *func_p = NULL;
19286 
19287  /* fetch regulist and outlist */
19288  a_outptr_list = (is_last ? buildlist->a_outptr_list : buildlist->a_outptr_list_interm);
19289 
19290  /* resolve late bindings in analytic sort list */
19292 
19293  /* initialized analytic functions state structure */
19294  if (qexec_initialize_analytic_state (thread_p, &analytic_state, analytic_eval->head, analytic_eval->sort_list,
19295  buildlist->a_regu_list, buildlist->a_val_list, a_outptr_list,
19296  buildlist->a_outptr_list_interm, is_last, xasl, xasl_state, &list_id->type_list,
19297  tplrec) == NULL)
19298  {
19300  }
19301 
19302  if (analytic_state.is_last_run)
19303  {
19304  if (xasl->instnum_val != NULL)
19305  {
19306  /* initialize counter to zero */
19307  (void) db_make_bigint (xasl->instnum_val, 0);
19308  }
19309  }
19310 
19311  /* create intermediary and output list files */
19312  {
19313  QFILE_TUPLE_VALUE_TYPE_LIST interm_type_list, output_type_list;
19314  QFILE_LIST_ID *interm_list_id;
19315  QFILE_LIST_ID *output_list_id;
19316 
19317  /* open intermediate file */
19318  if (qdata_get_valptr_type_list (thread_p, buildlist->a_outptr_list_interm, &interm_type_list) != NO_ERROR)
19319  {
19321  }
19322 
19323  interm_list_id = qfile_open_list (thread_p, &interm_type_list, NULL, xasl_state->query_id, ls_flag);
19324 
19325  if (interm_type_list.domp)
19326  {
19327  db_private_free_and_init (thread_p, interm_type_list.domp);
19328  }
19329 
19330  if (interm_list_id == NULL)
19331  {
19333  }
19334 
19335  analytic_state.interm_file = interm_list_id;
19336 
19337  /* last iteration results in xasl result file */
19338  if (is_last)
19339  {
19340  QFILE_SET_FLAG (ls_flag, QFILE_FLAG_ALL);
19342  && (xasl->orderby_list == NULL || XASL_IS_FLAGED (xasl, XASL_SKIP_ORDERBY_LIST))
19343  && xasl->option != Q_DISTINCT)
19344  {
19346  }
19347  }
19348 
19349  /* open output file */
19350  if (qdata_get_valptr_type_list (thread_p, a_outptr_list, &output_type_list) != NO_ERROR)
19351  {
19353  }
19354 
19355  output_list_id = qfile_open_list (thread_p, &output_type_list, NULL, xasl_state->query_id, ls_flag);
19356 
19357  if (output_type_list.domp)
19358  {
19359  db_private_free_and_init (thread_p, output_type_list.domp);
19360  }
19361 
19362  if (output_list_id == NULL)
19363  {
19365  }
19366 
19367  analytic_state.output_file = output_list_id;
19368  }
19369 
19370  if (list_id->tuple_cnt == 0)
19371  {
19372  /* empty list files, no need to proceed */
19373  analytic_state.state = NO_ERROR;
19374  goto wrapup;
19375  }
19376 
19377  /*
19378  * Open a scan on the unsorted input file
19379  */
19380  if (qfile_open_list_scan (list_id, &input_scan_id) != NO_ERROR)
19381  {
19383  }
19384  analytic_state.input_scan = &input_scan_id;
19385 
19386  /*
19387  * open a scan on the intermediate file
19388  */
19389  if (qfile_open_list_scan (analytic_state.interm_file, &interm_scan_id) != NO_ERROR)
19390  {
19392  }
19393  interm_scan_id.keep_page_on_finish = 1;
19394  analytic_state.interm_scan = &interm_scan_id;
19395 
19396  /*
19397  * Now load up the sort module and set it off...
19398  */
19399 
19400  estimated_pages = qfile_get_estimated_pages_for_sorting (list_id, &analytic_state.key_info);
19401 
19402  /* number of sort keys is always less than list file column count, as sort columns are included */
19403  analytic_state.key_info.use_original = 1;
19404  analytic_state.cmp_fn = &qfile_compare_partial_sort_record;
19405 
19406  if (sort_listfile (thread_p, NULL_VOLID, estimated_pages, &qexec_analytic_get_next, &analytic_state,
19407  &qexec_analytic_put_next, &analytic_state, analytic_state.cmp_fn, &analytic_state.key_info,
19409  {
19411  }
19412 
19413  /* check sort error */
19414  if (analytic_state.key_info.error != NO_ERROR)
19415  {
19417  {
19419  fcode_get_uppercase_name (analytic_eval->head->function), "DOUBLE, DATETIME or TIME");
19420  }
19421 
19423  }
19424 
19425  /*
19426  * There may be one unfinished group in the output, since the sort_listfile
19427  * interface doesn't include a finalization function. If so, finish
19428  * off that group.
19429  */
19430  if (analytic_state.input_recs != 0)
19431  {
19432  for (i = 0; i < analytic_state.func_count; i++)
19433  {
19434  if (qexec_analytic_finalize_group (thread_p, analytic_state.xasl_state, &analytic_state.func_state_list[i],
19435  false) != NO_ERROR)
19436  {
19438  }
19439  }
19440 
19441  finalized = true;
19442 
19443  /* reiterate intermediate file and write output using function result files */
19444  if (qexec_analytic_update_group_result (thread_p, &analytic_state) != NO_ERROR)
19445  {
19447  }
19448  }
19449 
19450 wrapup:
19451  if (analytic_state.state == NO_ERROR)
19452  {
19453  /* clear current input: sort items and input scan */
19454  if (analytic_state.curr_sort_page.page_p != NULL)
19455  {
19456  qmgr_free_old_page_and_init (thread_p, analytic_state.curr_sort_page.page_p,
19457  analytic_state.input_scan->list_id.tfile_vfid);
19458  analytic_state.curr_sort_page.vpid.pageid = NULL_PAGEID;
19459  analytic_state.curr_sort_page.vpid.volid = NULL_VOLID;
19460  }
19461  if (analytic_state.input_scan)
19462  {
19463  qfile_close_scan (thread_p, analytic_state.input_scan);
19464  analytic_state.input_scan = NULL;
19465  }
19466 
19467  /* replace current input with output */
19468  qfile_close_list (thread_p, analytic_state.output_file);
19469  qfile_destroy_list (thread_p, list_id);
19470  qfile_copy_list_id (list_id, analytic_state.output_file, true);
19471 
19472  qfile_free_list_id (analytic_state.output_file);
19473  analytic_state.output_file = NULL;
19474  }
19475 
19476  /* clear internal processing items */
19477  qexec_clear_analytic_state (thread_p, &analytic_state);
19478 
19479  return (analytic_state.state == NO_ERROR) ? NO_ERROR : ER_FAILED;
19480 
19481 exit_on_error:
19482  ASSERT_ERROR_AND_SET (analytic_state.state);
19483 
19484  if (!finalized)
19485  {
19486  /* make sure all the list_files are destroyed correctly */
19487  for (i = 0; i < analytic_state.func_count; i++)
19488  {
19489  func_p = analytic_state.func_state_list[i].func_p;
19490  if (func_p != NULL && func_p->option == Q_DISTINCT && func_p->list_id != NULL)
19491  {
19492  qfile_close_list (thread_p, func_p->list_id);
19493  qfile_destroy_list (thread_p, func_p->list_id);
19494  }
19495  }
19496  }
19497 
19498  goto wrapup;
19499 }
19500 
19501 /*
19502  * qexec_initialize_analytic_function_state () - initialize a function state
19503  * returns: error code or NO_ERROR
19504  * thread_p(in): thread entry
19505  * func_state(in/out): function state
19506  * func_p(in): function to initialize state for
19507  */
19508 static int
19510  ANALYTIC_TYPE * func_p, XASL_STATE * xasl_state)
19511 {
19512  QFILE_TUPLE_VALUE_TYPE_LIST group_type_list, value_type_list;
19513 
19514  assert (func_state != NULL);
19515 
19516  /* register function */
19517  func_state->func_p = func_p;
19518 
19519  /* initialize function state */
19520  func_state->current_key.data = (char *) db_private_alloc (thread_p, DB_PAGESIZE);
19521  if (func_state->current_key.data == NULL)
19522  {
19524  return ER_FAILED;
19525  }
19526  func_state->current_key.area_size = DB_PAGESIZE;
19527  func_state->current_key.length = 0;
19528  func_state->current_key.type = 0;
19529 
19530  /* zero input recs */
19531  func_state->curr_group_tuple_count = 0;
19532  func_state->curr_group_tuple_count_nn = 0;
19533  func_state->curr_sort_key_tuple_count = 0;
19534 
19535  /* initialize tuple record */
19536  func_state->group_tplrec.size = 0;
19537  func_state->group_tplrec.tpl = NULL;
19538  func_state->value_tplrec.size = 0;
19539  func_state->value_tplrec.tpl = NULL;
19540 
19541  /* initialize dbvals */
19542  db_make_null (&func_state->csktc_dbval);
19543  db_make_null (&func_state->cgtc_dbval);
19544  db_make_null (&func_state->cgtc_nn_dbval);
19545 
19546  /* initialize group header listfile */
19547  group_type_list.type_cnt = 2;
19548  group_type_list.domp = (TP_DOMAIN **) db_private_alloc (thread_p, sizeof (TP_DOMAIN *) * 2);
19549  if (group_type_list.domp == NULL)
19550  {
19552  return ER_FAILED;
19553  }
19554  group_type_list.domp[0] = &tp_Integer_domain;
19555  group_type_list.domp[1] = &tp_Integer_domain;
19556 
19557  func_state->group_list_id = qfile_open_list (thread_p, &group_type_list, NULL, xasl_state->query_id, 0);
19558 
19559  db_private_free_and_init (thread_p, group_type_list.domp);
19560 
19561  func_state->group_list_id->tpl_descr.f_cnt = 2;
19562  func_state->group_list_id->tpl_descr.f_valp = (DB_VALUE **) malloc (sizeof (DB_VALUE *) * 2);
19563  if (func_state->group_list_id->tpl_descr.f_valp == NULL)
19564  {
19566  return ER_FAILED;
19567  }
19568  func_state->group_list_id->tpl_descr.f_valp[0] = &func_state->cgtc_dbval;
19569  func_state->group_list_id->tpl_descr.f_valp[1] = &func_state->cgtc_nn_dbval;
19570 
19571  func_state->group_list_id->tpl_descr.clear_f_val_at_clone_decache = (bool *) malloc (sizeof (bool) * 2);
19573  {
19575  return ER_FAILED;
19576  }
19578  func_state->group_list_id->tpl_descr.clear_f_val_at_clone_decache[1] = false;
19579 
19580  /* initialize group value listfile */
19581  value_type_list.type_cnt = 2;
19582  value_type_list.domp = (TP_DOMAIN **) db_private_alloc (thread_p, sizeof (TP_DOMAIN *) * 2);
19583  if (value_type_list.domp == NULL)
19584  {
19586  return ER_FAILED;
19587  }
19588  value_type_list.domp[0] = &tp_Integer_domain;
19589  value_type_list.domp[1] = func_state->func_p->domain;
19590 
19591  func_state->value_list_id = qfile_open_list (thread_p, &value_type_list, NULL, xasl_state->query_id, 0);
19592 
19593  db_private_free_and_init (thread_p, value_type_list.domp);
19594 
19595  func_state->value_list_id->tpl_descr.f_cnt = 2;
19596  func_state->value_list_id->tpl_descr.f_valp = (DB_VALUE **) malloc (sizeof (DB_VALUE *) * 2);
19597  if (func_state->value_list_id->tpl_descr.f_valp == NULL)
19598  {
19600  return ER_FAILED;
19601  }
19602  func_state->value_list_id->tpl_descr.f_valp[0] = &func_state->csktc_dbval;
19603  func_state->value_list_id->tpl_descr.f_valp[1] = func_p->value;
19604 
19605  func_state->value_list_id->tpl_descr.clear_f_val_at_clone_decache = (bool *) malloc (sizeof (bool) * 2);
19607  {
19609  return ER_FAILED;
19610  }
19612  func_state->value_list_id->tpl_descr.clear_f_val_at_clone_decache[1] = false;
19613 
19614  return NO_ERROR;
19615 }
19616 
19617 /*
19618  * qexec_initialize_analytic_state () -
19619  * return:
19620  * analytic_state(in) :
19621  * a_func_list(in) : Analytic functions list
19622  * a_regu_list(in) : Regulator variable list
19623  * a_regu_list_ex(in) : Extended regulator variable list
19624  * a_val_list(in) : Value list
19625  * a_outptr_list(in) : Output pointer list
19626  * xasl_state(in) : XASL tree state information
19627  * type_list(in) :
19628  * tplrec(out) : Tuple record descriptor to store result tuples
19629  */
19630 static ANALYTIC_STATE *
19632  SORT_LIST * sort_list, REGU_VARIABLE_LIST a_regu_list, VAL_LIST * a_val_list,
19633  OUTPTR_LIST * a_outptr_list, OUTPTR_LIST * a_outptr_list_interm, bool is_last_run,
19635  QFILE_TUPLE_RECORD * tplrec)
19636 {
19637  REGU_VARIABLE_LIST regu_list = NULL;
19638  ANALYTIC_TYPE *func_p;
19639  bool has_interpolation_func = false;
19640  SUBKEY_INFO *subkey = NULL;
19641  int i;
19642  int interpolation_func_sort_prefix_len = 0;
19643 
19644  analytic_state->state = NO_ERROR;
19645 
19646  analytic_state->input_scan = NULL;
19647  analytic_state->interm_scan = NULL;
19648  analytic_state->interm_file = NULL;
19649  analytic_state->output_file = NULL;
19650 
19651  analytic_state->a_regu_list = a_regu_list;
19652  analytic_state->a_outptr_list = a_outptr_list;
19653  analytic_state->a_outptr_list_interm = a_outptr_list_interm;
19654 
19655  analytic_state->xasl = xasl;
19656  analytic_state->xasl_state = xasl_state;
19657 
19658  analytic_state->is_last_run = is_last_run;
19659 
19660  analytic_state->analytic_rec.area_size = 0;
19661  analytic_state->analytic_rec.length = 0;
19662  analytic_state->analytic_rec.type = 0; /* Unused */
19663  analytic_state->analytic_rec.data = NULL;
19664  analytic_state->output_tplrec = NULL;
19665  analytic_state->input_tplrec.size = 0;
19666  analytic_state->input_tplrec.tpl = 0;
19667  analytic_state->input_recs = 0;
19668 
19669  analytic_state->curr_sort_page.vpid.pageid = NULL_PAGEID;
19670  analytic_state->curr_sort_page.vpid.volid = NULL_VOLID;
19671  analytic_state->curr_sort_page.page_p = NULL;
19672  analytic_state->output_tplrec = tplrec;
19673 
19674  if (sort_list)
19675  {
19676  if (qfile_initialize_sort_key_info (&analytic_state->key_info, sort_list, type_list) == NULL)
19677  {
19678  return NULL;
19679  }
19680  }
19681  else
19682  {
19683  analytic_state->key_info.nkeys = 0;
19684  analytic_state->key_info.use_original = 1;
19685  analytic_state->key_info.key = NULL;
19686  analytic_state->key_info.error = NO_ERROR;
19687  }
19688 
19689  /* build function states */
19690  for (analytic_state->func_count = 0, func_p = a_func_list; func_p != NULL;
19691  analytic_state->func_count++, func_p = func_p->next)
19692  {
19693  ; /* count analytic functions */
19694  }
19695 
19696  analytic_state->func_state_list =
19698  sizeof (ANALYTIC_FUNCTION_STATE) * analytic_state->func_count);
19699  if (analytic_state->func_state_list == NULL)
19700  {
19701  return NULL;
19702  }
19703 
19704  memset (analytic_state->func_state_list, 0, analytic_state->func_count * sizeof (ANALYTIC_FUNCTION_STATE));
19705  for (i = 0, func_p = a_func_list; i < analytic_state->func_count; i++, func_p = func_p->next)
19706  {
19707  if (qexec_initialize_analytic_function_state (thread_p, &analytic_state->func_state_list[i], func_p, xasl_state)
19708  != NO_ERROR)
19709  {
19710  return NULL;
19711  }
19712  }
19713 
19714  /* initialize runtime structure */
19715  for (func_p = a_func_list; func_p != NULL; func_p = func_p->next)
19716  {
19717  if (QPROC_IS_INTERPOLATION_FUNC (func_p))
19718  {
19719  has_interpolation_func = true;
19720 
19721  if (interpolation_func_sort_prefix_len == 0)
19722  {
19723  interpolation_func_sort_prefix_len = func_p->sort_prefix_size;
19724  }
19725  else
19726  {
19727  assert (interpolation_func_sort_prefix_len == func_p->sort_prefix_size);
19728  }
19729  }
19730  }
19731 
19732  /* set SUBKEY_INFO.cmp_dom */
19733  if (has_interpolation_func)
19734  {
19735  for (i = 0, subkey = analytic_state->key_info.key; i < analytic_state->key_info.nkeys && subkey != NULL;
19736  ++i, ++subkey)
19737  {
19738  if (i >= interpolation_func_sort_prefix_len && TP_IS_STRING_TYPE (TP_DOMAIN_TYPE (subkey->col_dom)))
19739  {
19740  subkey->use_cmp_dom = true;
19741  }
19742  }
19743  }
19744 
19745  /* resolve domains in regulist */
19746  for (regu_list = a_regu_list; regu_list; regu_list = regu_list->next)
19747  {
19748  /* if it's position, resolve domain */
19749  if (regu_list->value.type == TYPE_POSITION
19750  && (TP_DOMAIN_TYPE (regu_list->value.value.pos_descr.dom) == DB_TYPE_VARIABLE
19751  || TP_DOMAIN_COLLATION_FLAG (regu_list->value.value.pos_descr.dom) != TP_DOMAIN_COLL_NORMAL))
19752  {
19753  int pos = regu_list->value.value.pos_descr.pos_no;
19754  if (pos <= type_list->type_cnt)
19755  {
19756  regu_list->value.value.pos_descr.dom = type_list->domp[pos];
19757  regu_list->value.domain = type_list->domp[pos];
19758  }
19759  }
19760  }
19761 
19762  return analytic_state;
19763 }
19764 
19765 /*
19766  * qexec_analytic_get_next () -
19767  * return:
19768  * recdes(in) :
19769  * arg(in) :
19770  */
19771 static SORT_STATUS
19773 {
19775 
19776  analytic_state = (ANALYTIC_STATE *) arg;
19777 
19778  return qfile_make_sort_key (thread_p, &analytic_state->key_info, recdes, analytic_state->input_scan,
19779  &analytic_state->input_tplrec);
19780 }
19781 
19782 /*
19783  * qexec_analytic_put_next () -
19784  * return:
19785  * recdes(in) :
19786  * arg(in) :
19787  */
19788 static int
19789 qexec_analytic_put_next (THREAD_ENTRY * thread_p, const RECDES * recdes, void *arg)
19790 {
19792  SORT_REC *key;
19793  char *data;
19794  VPID vpid;
19795  int peek, i;
19796  QFILE_LIST_ID *list_idp;
19797 
19798  QFILE_TUPLE_RECORD dummy;
19799  int status;
19800 
19801  analytic_state = (ANALYTIC_STATE *) arg;
19802  list_idp = &(analytic_state->input_scan->list_id);
19803 
19804  data = NULL;
19805 
19806  /* Traverse next link */
19807  for (key = (SORT_REC *) recdes->data; key; key = key->next)
19808  {
19809  if (analytic_state->state != NO_ERROR)
19810  {
19811  goto exit_on_error;
19812  }
19813 
19814  peek = COPY; /* default */
19815 
19816  /* evaluate inst_num() predicate */
19817  if (qexec_analytic_eval_instnum_pred (thread_p, analytic_state, ANALYTIC_INTERM_PROC) != NO_ERROR)
19818  {
19819  goto exit_on_error;
19820  }
19821 
19822  /*
19823  * Retrieve the original tuple. This will be the case if the
19824  * original tuple had more fields than we were sorting on.
19825  */
19826  vpid.pageid = key->s.original.pageid;
19827  vpid.volid = key->s.original.volid;
19828 
19829  if (analytic_state->curr_sort_page.vpid.pageid != vpid.pageid
19830  || analytic_state->curr_sort_page.vpid.volid != vpid.volid)
19831  {
19832  if (analytic_state->curr_sort_page.page_p != NULL)
19833  {
19834  qmgr_free_old_page_and_init (thread_p, analytic_state->curr_sort_page.page_p, list_idp->tfile_vfid);
19835  }
19836 
19837  analytic_state->curr_sort_page.page_p = qmgr_get_old_page (thread_p, &vpid, list_idp->tfile_vfid);
19838  if (analytic_state->curr_sort_page.page_p == NULL)
19839  {
19840  goto exit_on_error;
19841  }
19842  else
19843  {
19844  analytic_state->curr_sort_page.vpid = vpid;
19845  }
19846  }
19847 
19848  QFILE_GET_OVERFLOW_VPID (&vpid, analytic_state->curr_sort_page.page_p);
19849  data = analytic_state->curr_sort_page.page_p + key->s.original.offset;
19850  if (vpid.pageid != NULL_PAGEID)
19851  {
19852  /*
19853  * This sucks; why do we need two different structures to
19854  * accomplish exactly the same goal?
19855  */
19856  dummy.size = analytic_state->analytic_rec.area_size;
19857  dummy.tpl = analytic_state->analytic_rec.data;
19858  status = qfile_get_tuple (thread_p, analytic_state->curr_sort_page.page_p, data, &dummy, list_idp);
19859 
19860  if (dummy.tpl != analytic_state->analytic_rec.data)
19861  {
19862  /*
19863  * DON'T FREE THE BUFFER! qfile_get_tuple() already did
19864  * that, and what you have here in gby_rec is a dangling
19865  * pointer.
19866  */
19867  analytic_state->analytic_rec.area_size = dummy.size;
19868  analytic_state->analytic_rec.data = dummy.tpl;
19869  }
19870  if (status != NO_ERROR)
19871  {
19872  goto exit_on_error;
19873  }
19874 
19875  data = analytic_state->analytic_rec.data;
19876  }
19877  else
19878  {
19879  peek = PEEK; /* avoid unnecessary COPY */
19880  }
19881 
19882  /*
19883  * process current sorted tuple
19884  */
19885  if (analytic_state->input_recs == 0)
19886  {
19887  /* first input record, initialize everything */
19888  for (i = 0; i < analytic_state->func_count; i++)
19889  {
19890  qexec_analytic_start_group (thread_p, analytic_state->xasl_state, &analytic_state->func_state_list[i],
19891  recdes, true);
19892  }
19893  }
19894  else
19895  {
19896  for (i = 0; i < analytic_state->func_count; i++)
19897  {
19898  ANALYTIC_FUNCTION_STATE *func_state = &analytic_state->func_state_list[i];
19899  bool is_same_group = false;
19900  int nkeys;
19901 
19902  /* check group finish */
19903  nkeys = analytic_state->key_info.nkeys;
19904  analytic_state->key_info.nkeys = func_state->func_p->sort_list_size;
19905  if (((*analytic_state->cmp_fn) (&func_state->current_key.data, &key, &analytic_state->key_info) == 0)
19906  || analytic_state->key_info.nkeys == 0)
19907  {
19908  /* keep rank within same sort key */
19909  analytic_state->key_info.nkeys = nkeys;
19911 
19912  if (QPROC_ANALYTIC_IS_OFFSET_FUNCTION (func_state->func_p))
19913  {
19914  /* offset functions will treat all tuples in a group as having a different sort key regardless if
19915  * this is true or not; this is done in order to have a distinct value for each tuple in the
19916  * group (whereas normally tuples sharing a sort key will also share a value) */
19917  is_same_group = true;
19918  }
19919  else
19920  {
19921  /* same sort key, move on */
19922  continue;
19923  }
19924  }
19925  analytic_state->key_info.nkeys = nkeys;
19926 
19927  /* find out if it's the same group */
19928  if (!is_same_group)
19929  {
19930  if (func_state->func_p->sort_prefix_size == 0)
19931  {
19932  /* no groups, only ordering */
19933  is_same_group = true;
19934  }
19935  else
19936  {
19937  nkeys = analytic_state->key_info.nkeys;
19938  analytic_state->key_info.nkeys = func_state->func_p->sort_prefix_size;
19939  if ((*analytic_state->cmp_fn) (&func_state->current_key.data, &key,
19940  &analytic_state->key_info) == 0)
19941  {
19942  is_same_group = true;
19943  }
19944  analytic_state->key_info.nkeys = nkeys;
19945  }
19946  }
19947 
19948  if (!is_same_group)
19949  {
19950  if (qexec_analytic_finalize_group (thread_p, analytic_state->xasl_state, func_state, false) !=
19951  NO_ERROR)
19952  {
19953  goto exit_on_error;
19954  }
19955  pr_clear_value (func_state->func_p->value);
19956  qexec_analytic_start_group (thread_p, analytic_state->xasl_state, func_state, recdes, true);
19957  }
19958  else if (func_state->func_p->function != PT_NTILE
19959  && (!QPROC_IS_INTERPOLATION_FUNC (func_state->func_p) || func_state->func_p->option == Q_ALL))
19960  {
19961  if (qexec_analytic_finalize_group (thread_p, analytic_state->xasl_state, func_state, true) !=
19962  NO_ERROR)
19963  {
19964  goto exit_on_error;
19965  }
19966  qexec_analytic_start_group (thread_p, analytic_state->xasl_state, func_state, recdes, false);
19967  }
19968  }
19969  }
19970 
19971  /* aggregate tuple across all functions */
19972  qexec_analytic_add_tuple (thread_p, analytic_state, data, peek);
19973 
19974  /* one more input record of beer on the wall */
19975  analytic_state->input_recs++;
19976  } /* for (key = (SORT_REC *) recdes->data; ...) */
19977 
19978 wrapup:
19979  return analytic_state->state;
19980 
19981 exit_on_error:
19982  assert (er_errid () != NO_ERROR);
19983  analytic_state->state = er_errid ();
19984  goto wrapup;
19985 }
19986 
19987 /*
19988  * qexec_analytic_eval_instnum_pred () - evaluate inst_num() predicate
19989  * returns: error code or NO_ERROR
19990  * thread_p(in): current thread
19991  * analytic_state(in): analytic state
19992  * func_p(in): analytic function chain
19993  * stage(in): stage from within function is called
19994  *
19995  * NOTE: this function sets the analytic state's "is_output_rec" flag
19996  */
19997 static int
19999 {
20000  ANALYTIC_STAGE instnum_stage = ANALYTIC_INTERM_PROC;
20001  DB_LOGICAL is_output_rec;
20002  int instnum_flag, i;
20003 
20004  /* get flag from buildlist */
20005  instnum_flag = analytic_state->xasl->instnum_flag;
20006 
20007  /* by default, it's an output record */
20008  analytic_state->is_output_rec = true;
20009 
20010  if (!analytic_state->is_last_run
20011  || (analytic_state->xasl->instnum_pred == NULL && !(instnum_flag & XASL_INSTNUM_FLAG_EVAL_DEFER)))
20012  {
20013  /* inst_num() is evaluated only for last function, when an INST_NUM() predicate is present or when INST_NUM() is
20014  * selected */
20015  return NO_ERROR;
20016  }
20017 
20018  for (i = 0; i < analytic_state->func_count; i++)
20019  {
20020  ANALYTIC_TYPE *func_p = analytic_state->func_state_list[i].func_p;
20021 
20022  if (QPROC_ANALYTIC_IS_OFFSET_FUNCTION (func_p) || func_p->function == PT_NTILE
20023  || func_p->function == PT_FIRST_VALUE || func_p->function == PT_LAST_VALUE)
20024  {
20025  /* inst_num() predicate is evaluated at group processing for these functions, as the result is computed at
20026  * this stage using all group values */
20027  instnum_stage = ANALYTIC_GROUP_PROC;
20028  }
20029 
20030  if (instnum_flag & XASL_INSTNUM_FLAG_EVAL_DEFER)
20031  {
20032  /* we're selecting INST_NUM() so we must evaluate it when writing the output file */
20033  instnum_stage = ANALYTIC_GROUP_PROC;
20034  }
20035  }
20036 
20037  if (stage != instnum_stage)
20038  {
20039  /* we're not at the required stage */
20040  return NO_ERROR;
20041  }
20042 
20044  /* evaluate inst_num() */
20045  is_output_rec = qexec_eval_instnum_pred (thread_p, analytic_state->xasl, analytic_state->xasl_state);
20046  if (instnum_flag & XASL_INSTNUM_FLAG_SCAN_STOP_AT_ANALYTIC)
20047  {
20049  }
20050 
20051  if (is_output_rec == V_ERROR)
20052  {
20053  return ER_FAILED;
20054  }
20055  else
20056  {
20057  analytic_state->is_output_rec = (is_output_rec == V_TRUE);
20058  }
20059 
20060  /* all ok */
20061  return NO_ERROR;
20062 }
20063 
20064 /*
20065  * qexec_analytic_start_group () -
20066  * return:
20067  * analytic_state(in):
20068  * key(in):
20069  * reinit(in):
20070  */
20071 static int
20073  const RECDES * key, bool reinit)
20074 {
20075  int error;
20076 
20077  /*
20078  * Record the new key; keep it in SORT_KEY format so we can continue
20079  * to use the SORTKEY_INFO version of the comparison functions.
20080  *
20081  * WARNING: the sort module doesn't seem to set key->area_size
20082  * reliably, so the only thing we can rely on is key->length.
20083  */
20084 
20085  if (key)
20086  {
20087  if (func_state->current_key.area_size < key->length)
20088  {
20089  void *tmp;
20090 
20091  tmp = db_private_realloc (thread_p, func_state->current_key.data, key->area_size);
20092  if (tmp == NULL)
20093  {
20095  }
20096  func_state->current_key.data = (char *) tmp;
20097  func_state->current_key.area_size = key->area_size;
20098  }
20099  memcpy (func_state->current_key.data, key->data, key->length);
20100  func_state->current_key.length = key->length;
20101  }
20102 
20103  /*
20104  * (Re)initialize the various accumulator variables...
20105  */
20106  if (reinit)
20107  {
20108  /* starting a new group */
20109  error = qdata_initialize_analytic_func (thread_p, func_state->func_p, xasl_state->query_id);
20110  if (error != NO_ERROR)
20111  {
20113  }
20114 
20115  /* reinitialize counters */
20116  func_state->curr_group_tuple_count = 0;
20117  func_state->curr_group_tuple_count_nn = 0;
20118  func_state->curr_sort_key_tuple_count = 0;
20119  }
20120  else
20121  {
20122  /* starting a new partition; reinstate acumulator */
20123  qdata_copy_db_value (func_state->func_p->value, &func_state->func_p->part_value);
20124  pr_clear_value (&func_state->func_p->part_value);
20125 
20126  /* reinitialize counters */
20127  func_state->curr_sort_key_tuple_count = 0;
20128  }
20129 
20130  return NO_ERROR;
20131 
20132 exit_on_error:
20133  assert (er_errid () != NO_ERROR);
20134  return er_errid ();
20135 }
20136 
20137 /*
20138  * qexec_analytic_finalize_group () - finish analytic function and dump result to file
20139  * return: error code or NO_ERROR
20140  * xasl_state(in): XASL state
20141  * func_state(in): function state
20142  * is_same_group(in): true if we're finalizing a sort key, false if a group
20143  */
20144 static int
20146  bool is_same_group)
20147 {
20148  QFILE_TUPLE_RECORD tplrec;
20149  int rc = NO_ERROR;
20150 
20151  /* initialize tuple record */
20152  tplrec.tpl = NULL;
20153  tplrec.size = 0;
20154 
20155  /* finalize function */
20156  if (qdata_finalize_analytic_func (thread_p, func_state->func_p, is_same_group) != NO_ERROR)
20157  {
20158  rc = ER_FAILED;
20159  goto cleanup;
20160  }
20161 
20162  if (!DB_IS_NULL (func_state->func_p->value))
20163  {
20164  /* keep track of non-NULL values */
20165  func_state->curr_group_tuple_count_nn += func_state->curr_sort_key_tuple_count;
20166  }
20167 
20168  /* write current counts to dbvalues */
20169  db_make_int (&func_state->cgtc_dbval, func_state->curr_group_tuple_count);
20170  db_make_int (&func_state->cgtc_nn_dbval, func_state->curr_group_tuple_count_nn);
20171  db_make_int (&func_state->csktc_dbval, func_state->curr_sort_key_tuple_count);
20172 
20173  /* dump group */
20174  if (!is_same_group)
20175  {
20176  if (qfile_fast_intint_tuple_to_list (thread_p, func_state->group_list_id, func_state->curr_group_tuple_count,
20177  func_state->curr_group_tuple_count_nn) != NO_ERROR)
20178  {
20179  rc = ER_FAILED;
20180  goto cleanup;
20181  }
20182  }
20183 
20184  /* dump sort key header */
20185  rc =
20186  qfile_fast_intval_tuple_to_list (thread_p, func_state->value_list_id, func_state->curr_sort_key_tuple_count,
20187  func_state->func_p->value);
20188  if (rc > 0)
20189  {
20190  rc = NO_ERROR;
20191  /* big tuple */
20192  if (qfile_copy_tuple_descr_to_tuple (thread_p, &func_state->value_list_id->tpl_descr, &tplrec) != NO_ERROR)
20193  {
20194  rc = ER_FAILED;
20195  goto cleanup;
20196  }
20197  if (qfile_add_tuple_to_list (thread_p, func_state->value_list_id, tplrec.tpl) != NO_ERROR)
20198  {
20199  rc = ER_FAILED;
20200  goto cleanup;
20201  }
20202  }
20203 
20204 cleanup:
20205 
20206  if (tplrec.tpl != NULL)
20207  {
20208  db_private_free (thread_p, tplrec.tpl);
20209  }
20210 
20211  return rc;
20212 }
20213 
20214 /*
20215  * qexec_analytic_add_tuple () -
20216  * return:
20217  * analytic_state(in):
20218  * tpl(in):
20219  * peek(in):
20220  */
20221 static void
20223 {
20224  XASL_STATE *xasl_state = analytic_state->xasl_state;
20225  QFILE_LIST_ID *list_id = analytic_state->interm_file;
20226  int i;
20227 
20228  if (analytic_state->state != NO_ERROR)
20229  {
20230  return;
20231  }
20232 
20233  if (fetch_val_list (thread_p, analytic_state->a_regu_list, &xasl_state->vd, NULL, NULL, tpl, peek) != NO_ERROR)
20234  {
20236  }
20237 
20238  for (i = 0; i < analytic_state->func_count; i++)
20239  {
20240  if (qdata_evaluate_analytic_func (thread_p, analytic_state->func_state_list[i].func_p, &xasl_state->vd) !=
20241  NO_ERROR)
20242  {
20244  }
20245 
20246  /* account for tuple */
20247  analytic_state->func_state_list[i].curr_group_tuple_count++;
20248  analytic_state->func_state_list[i].curr_sort_key_tuple_count++;
20249  }
20250 
20251  /* check if output */
20252  if (analytic_state->is_output_rec)
20253  {
20254  /* records that did not pass the instnum() predicate evaluation are used for computing the function value, but
20255  * are not included in the intermediate file */
20256  if (qexec_insert_tuple_into_list (thread_p, list_id, analytic_state->a_outptr_list_interm, &xasl_state->vd,
20257  analytic_state->output_tplrec) != NO_ERROR)
20258  {
20260  }
20261  }
20262 
20263 wrapup:
20264  return;
20265 
20266 exit_on_error:
20267  assert (er_errid () != NO_ERROR);
20268  analytic_state->state = er_errid ();
20269  goto wrapup;
20270 }
20271 
20272 /*
20273  * qexec_clear_analytic_function_state () - clear function state
20274  * thread_p(in): thread entry
20275  * func_state(in): function state to free
20276  */
20277 static void
20279 {
20280  assert (func_state != NULL);
20281 
20282  /* clear db_values */
20283  pr_clear_value (func_state->func_p->value);
20284  pr_clear_value (&func_state->cgtc_dbval);
20285  pr_clear_value (&func_state->cgtc_nn_dbval);
20286  pr_clear_value (&func_state->csktc_dbval);
20287 
20288  /* free buffers */
20289  if (func_state->current_key.data)
20290  {
20291  db_private_free_and_init (thread_p, func_state->current_key.data);
20292  func_state->current_key.area_size = 0;
20293  }
20294 
20295  /* dealloc files */
20296  qfile_close_list (thread_p, func_state->group_list_id);
20297  qfile_close_list (thread_p, func_state->value_list_id);
20298  qfile_destroy_list (thread_p, func_state->group_list_id);
20299  qfile_destroy_list (thread_p, func_state->value_list_id);
20300  qfile_free_list_id (func_state->group_list_id);
20301  qfile_free_list_id (func_state->value_list_id);
20302 }
20303 
20304 /*
20305  * qexec_clear_analytic_state () -
20306  * return:
20307  * analytic_state(in):
20308  */
20309 static void
20311 {
20312  int i;
20313 
20314  for (i = 0; i < analytic_state->func_count; i++)
20315  {
20316  qexec_clear_analytic_function_state (thread_p, &analytic_state->func_state_list[i]);
20317  }
20318  if (analytic_state->func_state_list != NULL)
20319  {
20320  db_private_free_and_init (thread_p, analytic_state->func_state_list);
20321  }
20322 
20323  if (analytic_state->analytic_rec.data)
20324  {
20325  db_private_free_and_init (thread_p, analytic_state->analytic_rec.data);
20326  analytic_state->analytic_rec.area_size = 0;
20327  }
20328  analytic_state->output_tplrec = NULL;
20329 
20330  qfile_clear_sort_key_info (&analytic_state->key_info);
20331 
20332  if (analytic_state->curr_sort_page.page_p != NULL)
20333  {
20334  qmgr_free_old_page_and_init (thread_p, analytic_state->curr_sort_page.page_p,
20335  analytic_state->input_scan->list_id.tfile_vfid);
20336  analytic_state->curr_sort_page.vpid.pageid = NULL_PAGEID;
20337  analytic_state->curr_sort_page.vpid.volid = NULL_VOLID;
20338  }
20339 
20340  if (analytic_state->input_scan)
20341  {
20342  qfile_close_scan (thread_p, analytic_state->input_scan);
20343  analytic_state->input_scan = NULL;
20344  }
20345 
20346  if (analytic_state->interm_scan)
20347  {
20348  qfile_close_scan (thread_p, analytic_state->interm_scan);
20349  analytic_state->interm_scan = NULL;
20350  }
20351 
20352  if (analytic_state->interm_file)
20353  {
20354  qfile_close_list (thread_p, analytic_state->interm_file);
20355  qfile_destroy_list (thread_p, analytic_state->interm_file);
20356  qfile_free_list_id (analytic_state->interm_file);
20357  analytic_state->interm_file = NULL;
20358  }
20359  if (analytic_state->output_file)
20360  {
20361  qfile_close_list (thread_p, analytic_state->output_file);
20362  qfile_free_list_id (analytic_state->output_file);
20363  analytic_state->output_file = NULL;
20364  }
20365 }
20366 
20367 /*
20368  * qexec_analytic_evaluate_ntile_function () - evaluate NTILE function
20369  * returns: error code or NO_ERROR
20370  * thread_p(in): current thread
20371  * func_p(in): analytic function
20372  * analytic_state(in): analytic state
20373  * tuple_idx(in): current tuple index
20374  */
20375 static int
20377 {
20378  if (func_state == NULL || func_state->func_p == NULL || func_state->func_p->function != PT_NTILE)
20379  {
20380  /* nothing to do */
20381  return NO_ERROR;
20382  }
20383 
20384  if (!func_state->func_p->info.ntile.is_null)
20385  {
20386  int recs_in_bucket = func_state->curr_group_tuple_count / func_state->func_p->info.ntile.bucket_count;
20387  int compensate = func_state->curr_group_tuple_count % func_state->func_p->info.ntile.bucket_count;
20388 
20389  /* get bucket of current tuple */
20390  if (recs_in_bucket == 0)
20391  {
20392  /* more buckets than tuples, this is identity */
20393  db_make_int (func_state->func_p->value, func_state->group_tuple_position + 1);
20394  }
20395  else if (compensate == 0)
20396  {
20397  /* perfect division, straightforward */
20398  db_make_int (func_state->func_p->value, func_state->group_tuple_position / recs_in_bucket + 1);
20399  }
20400  else
20401  {
20402  int xcount = (recs_in_bucket + 1) * compensate;
20403 
20404  /* account for remainder */
20405  if (func_state->group_tuple_position < xcount)
20406  {
20407  db_make_int (func_state->func_p->value, func_state->group_tuple_position / (recs_in_bucket + 1) + 1);
20408  }
20409  else
20410  {
20411  db_make_int (func_state->func_p->value,
20412  (func_state->group_tuple_position - compensate) / recs_in_bucket + 1);
20413  }
20414  }
20415  }
20416  else
20417  {
20418  /* null output */
20419  db_make_null (func_state->func_p->value);
20420  }
20421 
20422  /* all ok */
20423  return NO_ERROR;
20424 }
20425 
20426 /*
20427  * qexec_analytic_evaluate_offset_function () - process analytic offset functions
20428  * (i.e. lead/lag)
20429  * returns: error code or NO_ERROR
20430  * thread_p(in): current thread
20431  * func_p(in): analytic function
20432  * analytic_state(in): analytic state
20433  * val_desc(in): value descriptor
20434  * tuple_idx(in): current position of main scan in group
20435  */
20436 static int
20439 {
20440  ANALYTIC_TYPE *func_p;
20441  REGU_VARIABLE_LIST regulist;
20442  DB_VALUE *default_val_p;
20443  DB_VALUE offset_val;
20444  DB_VALUE default_val;
20445  int regu_idx;
20446  int target_idx;
20447  int group_tuple_count;
20448  int error = NO_ERROR;
20449  TP_DOMAIN_STATUS dom_status;
20450  double nth_idx = 0.0;
20451  char buf[64];
20452  bool put_default = false;
20453 
20454  if (func_state == NULL)
20455  {
20456  /* nothing to do */
20457  return NO_ERROR;
20458  }
20459  else
20460  {
20461  func_p = func_state->func_p;
20462  assert (func_p);
20463  }
20464 
20465  if (!QPROC_ANALYTIC_IS_OFFSET_FUNCTION (func_p))
20466  {
20467  /* nothing to do */
20468  return NO_ERROR;
20469  }
20470 
20471  /* determine which tuple count to use */
20472  if (func_p->ignore_nulls)
20473  {
20474  group_tuple_count = func_state->curr_group_tuple_count_nn;
20475  }
20476  else
20477  {
20478  group_tuple_count = func_state->curr_group_tuple_count;
20479  }
20480 
20481  /* find offset reguvar and get int value */
20482  regulist = analytic_state->a_regu_list;
20483  regu_idx = func_p->offset_idx;
20484  while (regu_idx > 0 && regulist != NULL)
20485  {
20486  regulist = regulist->next;
20487  regu_idx--;
20488  }
20489  if (regulist == NULL)
20490  {
20492  return ER_FAILED;
20493  }
20494 
20495  /* get target tuple index */
20496  switch (func_p->function)
20497  {
20498  case PT_LEAD:
20499  case PT_LAG:
20500  dom_status = tp_value_coerce (regulist->value.vfetch_to, &offset_val, &tp_Integer_domain);
20501  if (dom_status != DOMAIN_COMPATIBLE)
20502  {
20503  error = tp_domain_status_er_set (dom_status, ARG_FILE_LINE, regulist->value.vfetch_to, &tp_Integer_domain);
20504  if (error == NO_ERROR)
20505  {
20507  return ER_FAILED;
20508  }
20509  return error;
20510  }
20511 
20512  /* guard against NULL */
20513  if (!DB_IS_NULL (&offset_val))
20514  {
20515  target_idx = offset_val.data.i;
20516  }
20517  else
20518  {
20519  target_idx = 0;
20520  }
20521 
20522  /* done with offset dbval */
20523  pr_clear_value (&offset_val);
20524 
20525  if (func_p->function == PT_LEAD)
20526  {
20527  target_idx = func_state->group_consumed_tuples + target_idx;
20528  }
20529  else
20530  {
20531  /* PT_LAG */
20532  target_idx = func_state->group_consumed_tuples - target_idx;
20533  }
20534  break;
20535 
20536  case PT_NTH_VALUE:
20537  dom_status = tp_value_coerce (regulist->value.vfetch_to, &offset_val, &tp_Double_domain);
20538  if (dom_status != DOMAIN_COMPATIBLE)
20539  {
20540  error = tp_domain_status_er_set (dom_status, ARG_FILE_LINE, regulist->value.vfetch_to, &tp_Double_domain);
20541  return error;
20542  }
20543 
20544  if (DB_IS_NULL (&offset_val))
20545  {
20547  return ER_FAILED;
20548  }
20549 
20550  nth_idx = db_get_double (&offset_val);
20551 
20552  if (nth_idx < 1.0 || nth_idx > DB_INT32_MAX)
20553  {
20554  sprintf (buf, "%.15g", nth_idx);
20556  return ER_FAILED;
20557  }
20558 
20559  target_idx = (int) floor (nth_idx);
20560  target_idx--; /* SQL defines this index as starting with one */
20561 
20562  if (target_idx >= 0 && target_idx < group_tuple_count)
20563  {
20564  if (func_p->from_last)
20565  {
20566  target_idx = group_tuple_count - target_idx;
20567  }
20568  }
20569  else
20570  {
20571  target_idx = -1;
20572  }
20573  break;
20574 
20575  default:
20576  /* switch should cover all cases */
20578  return ER_FAILED;
20579  }
20580 
20581  /* clean up */
20582  pr_clear_value (&offset_val);
20583 
20584  /* find defaultvalue reguvar and get dbvalue pointer */
20585  regulist = analytic_state->a_regu_list;
20586  regu_idx = func_p->default_idx;
20587  while (regu_idx > 0 && regulist != NULL)
20588  {
20589  regulist = regulist->next;
20590  regu_idx--;
20591  }
20592  if (regulist == NULL)
20593  {
20595  return ER_FAILED;
20596  }
20597  default_val_p = regulist->value.vfetch_to;
20598 
20599  /* put value */
20600  if (target_idx >= 0 && target_idx < group_tuple_count)
20601  {
20602  if (qexec_analytic_value_lookup (thread_p, func_state, target_idx, func_p->ignore_nulls) != NO_ERROR)
20603  {
20604  return ER_FAILED;
20605  }
20606 
20607  if (func_p->function == PT_NTH_VALUE)
20608  {
20609  /* when using ORDER BY on NTH_VALUE, value will be NULL until that value is reached */
20610  if ((func_p->sort_prefix_size != func_p->sort_list_size)
20611  && (func_state->group_consumed_tuples < func_state->group_tuple_position))
20612  {
20613  put_default = true;
20614  }
20615  }
20616  }
20617  else
20618  {
20619  put_default = true;
20620  }
20621 
20622  if (put_default)
20623  {
20624  /* coerce value to default domain */
20625  dom_status = tp_value_coerce (default_val_p, &default_val, func_p->domain);
20626  if (dom_status != DOMAIN_COMPATIBLE)
20627  {
20628  error = tp_domain_status_er_set (dom_status, ARG_FILE_LINE, default_val_p, func_p->domain);
20629  if (error == NO_ERROR)
20630  {
20631  return ER_FAILED;
20632  }
20633  return error;
20634  }
20635 
20636  /* put default value and clean up */
20637  pr_clear_value (func_p->value);
20638  pr_clone_value (&default_val, func_p->value);
20639  pr_clear_value (&default_val);
20640  }
20641 
20642  /* all ok */
20643  return error;
20644 }
20645 
20646 /*
20647  * qexec_analytic_evaluate_cume_dist_percent_rank_function () -
20648  * evaluate CUME_DIST and PERCENT_RANK
20649  * returns: error code or NO_ERROR
20650  * thread(in):
20651  * func_p(in/out):
20652  * analytic_state(in):
20653  * tuple_idx(in):
20654  */
20655 static int
20657 {
20658  int start_of_group = func_state->group_tuple_position - func_state->sort_key_tuple_position;
20659  int end_of_group =
20660  func_state->group_tuple_position - func_state->sort_key_tuple_position + func_state->curr_sort_key_tuple_count;
20661 
20662  switch (func_state->func_p->function)
20663  {
20664  case PT_CUME_DIST:
20665  db_make_double (func_state->func_p->value, (double) end_of_group / func_state->curr_group_tuple_count);
20666  break;
20667 
20668  case PT_PERCENT_RANK:
20669  if (func_state->curr_group_tuple_count <= 1)
20670  {
20671  db_make_double (func_state->func_p->value, 0.0f);
20672  }
20673  else
20674  {
20675  db_make_double (func_state->func_p->value,
20676  (double) start_of_group / (func_state->curr_group_tuple_count - 1));
20677  }
20678  break;
20679 
20680  default:
20681  return ER_FAILED;
20682  }
20683 
20684  return NO_ERROR;
20685 }
20686 
20687 /*
20688  * qexec_analytic_evaluate_interpolation_function () -
20689  *
20690  * returns: error code or NO_ERROR
20691  * thread_p(in): current thread
20692  * func_p(in): analytic function
20693  * analytic_state(in): analytic state
20694  * tuple_idx(in): current position of main scan in group
20695  */
20696 static int
20698 {
20699  ANALYTIC_TYPE *func_p = NULL;
20700  double f_row_num_d, c_row_num_d, row_num_d, percentile_d;
20701  int error = NO_ERROR;
20702  DB_VALUE *peek_value_p = NULL;
20703 
20704  assert (func_state != NULL && func_state->func_p != NULL);
20705  func_p = func_state->func_p;
20707 
20708  /* MEDIAN function is evaluated at the start of the group */
20709  if (func_state->group_tuple_position_nn > 0)
20710  {
20711  return NO_ERROR;
20712  }
20713 
20714  /* constant operand case */
20715  if (func_p->is_const_operand)
20716  {
20717  /* if constant operand, value has been established during evaluation and was fetched from intermediate file */
20718  return NO_ERROR;
20719  }
20720 
20721  /* zero non-NULL values in group */
20722  if (func_state->curr_group_tuple_count_nn == 0)
20723  {
20724  return NO_ERROR;
20725  }
20726 
20727  /* get target row */
20728  if (func_p->function == PT_MEDIAN)
20729  {
20730  percentile_d = 0.5;
20731  }
20732  else
20733  {
20734  error =
20735  fetch_peek_dbval (thread_p, func_p->info.percentile.percentile_reguvar, NULL, NULL, NULL, NULL, &peek_value_p);
20736  if (error != NO_ERROR)
20737  {
20738  assert (er_errid () != NO_ERROR);
20739 
20740  return error;
20741  }
20742 
20743  assert (DB_VALUE_TYPE (peek_value_p) == DB_TYPE_DOUBLE);
20744 
20745  percentile_d = db_get_double (peek_value_p);
20746 
20747  if (func_p->function == PT_PERCENTILE_DISC)
20748  {
20749  percentile_d =
20750  ceil (percentile_d * func_state->curr_group_tuple_count_nn) / func_state->curr_group_tuple_count_nn;
20751  }
20752  }
20753 
20754  row_num_d = ((double) (func_state->curr_group_tuple_count_nn - 1)) * percentile_d;
20755  f_row_num_d = floor (row_num_d);
20756 
20757  if (func_p->function == PT_PERCENTILE_DISC)
20758  {
20759  c_row_num_d = f_row_num_d;
20760  }
20761  else
20762  {
20763  c_row_num_d = ceil (row_num_d);
20764  }
20765 
20766  /* compute value */
20767  if (f_row_num_d == c_row_num_d)
20768  {
20769  /* we have an odd number of rows, median is middle row's value; fetch it */
20770  if (qexec_analytic_value_lookup (thread_p, func_state, (int) f_row_num_d, true) != NO_ERROR)
20771  {
20772  return ER_FAILED;
20773  }
20774 
20775  /* coerce accordingly */
20776  error =
20777  qdata_apply_interpolation_function_coercion (func_p->value, &func_p->domain, func_p->value, func_p->function);
20778  if (error != NO_ERROR)
20779  {
20780  return error;
20781  }
20782  }
20783  else
20784  {
20785  DB_VALUE c_value, f_value;
20786  db_make_null (&c_value);
20787  db_make_null (&f_value);
20788 
20789  if (qexec_analytic_value_lookup (thread_p, func_state, (int) f_row_num_d, true) != NO_ERROR)
20790  {
20791  return ER_FAILED;
20792  }
20793  else
20794  {
20795  pr_clone_value (func_p->value, &f_value);
20796  }
20797 
20798  if (qexec_analytic_value_lookup (thread_p, func_state, (int) c_row_num_d, true) != NO_ERROR)
20799  {
20800  return ER_FAILED;
20801  }
20802  else
20803  {
20804  pr_clone_value (func_p->value, &c_value);
20805  }
20806 
20807  pr_clear_value (func_p->value);
20808  error =
20809  qdata_interpolation_function_values (&f_value, &c_value, row_num_d, f_row_num_d, c_row_num_d, &func_p->domain,
20810  func_p->value, func_p->function);
20811  if (error != NO_ERROR)
20812  {
20813  return error;
20814  }
20815  }
20816 
20817  /* all ok */
20818  return NO_ERROR;
20819 }
20820 
20821 /*
20822  * qexec_analytic_group_header_load () - load group information from group list
20823  * file
20824  * returns: error code or NO_ERROR
20825  * func_state(in): function state
20826  */
20827 static int
20829 {
20830  QFILE_TUPLE tuple_p;
20831 
20832  assert (func_state != NULL);
20833 
20834  tuple_p = func_state->group_tplrec.tpl + QFILE_TUPLE_LENGTH_SIZE;
20835 
20836  /* deserialize tuple count */
20837  if (QFILE_GET_TUPLE_VALUE_FLAG (tuple_p) != V_BOUND)
20838  {
20839  return ER_FAILED;
20840  }
20841  tuple_p += QFILE_TUPLE_VALUE_HEADER_SIZE;
20842  func_state->curr_group_tuple_count = OR_GET_INT (tuple_p);
20843  tuple_p += DB_ALIGN (tp_Integer.disksize, MAX_ALIGNMENT);
20844 
20845  /* deserialize not-null tuple count */
20846  if (QFILE_GET_TUPLE_VALUE_FLAG (tuple_p) != V_BOUND)
20847  {
20848  return ER_FAILED;
20849  }
20850  tuple_p += QFILE_TUPLE_VALUE_HEADER_SIZE;
20851  func_state->curr_group_tuple_count_nn = OR_GET_INT (tuple_p);
20852 
20853  /* all ok */
20854  return NO_ERROR;
20855 }
20856 
20857 /*
20858  * qexec_analytic_sort_key_header_load () - load sort key header from sort key
20859  * list file
20860  * returns: error code or NO_ERROR
20861  * func_state(in): function state
20862  * load_value(in): if true, will load the actual value into func_p->value
20863  *
20864  * NOTE: if repeated often, loading the actual value can be expensive, so make
20865  * sure you only set load_value when necessary.
20866  */
20867 static int
20869 {
20870  QFILE_TUPLE tuple_p;
20871  OR_BUF buf;
20872  int length, rc = NO_ERROR;
20873 
20874  assert (func_state != NULL);
20875 
20876  tuple_p = func_state->value_tplrec.tpl + QFILE_TUPLE_LENGTH_SIZE;
20877 
20878  /* deserialize tuple count */
20879  if (QFILE_GET_TUPLE_VALUE_FLAG (tuple_p) != V_BOUND)
20880  {
20881  return ER_FAILED;
20882  }
20883  tuple_p += QFILE_TUPLE_VALUE_HEADER_SIZE;
20884  func_state->curr_sort_key_tuple_count = OR_GET_INT (tuple_p);
20885  tuple_p += DB_ALIGN (tp_Integer.disksize, MAX_ALIGNMENT);
20886 
20887  if (!load_value && !func_state->func_p->ignore_nulls && !QPROC_IS_INTERPOLATION_FUNC (func_state->func_p))
20888  {
20889  /* we're not counting NULLs and we're not using the value */
20890  return NO_ERROR;
20891  }
20892 
20893  /* clear current value */
20894  pr_clear_value (func_state->func_p->value);
20895 
20896  /* deserialize value */
20897  if (QFILE_GET_TUPLE_VALUE_FLAG (tuple_p) == V_BOUND)
20898  {
20899  length = QFILE_GET_TUPLE_VALUE_LENGTH (tuple_p);
20900  tuple_p += QFILE_TUPLE_VALUE_HEADER_SIZE;
20901  OR_BUF_INIT (buf, tuple_p, length);
20902 
20903  rc =
20904  func_state->func_p->domain->type->data_readval (&buf, func_state->func_p->value, func_state->func_p->domain, -1,
20905  false, NULL, 0);
20906  if (rc != NO_ERROR)
20907  {
20908  return ER_FAILED;
20909  }
20910  }
20911  else
20912  {
20913  db_make_null (func_state->func_p->value);
20914  }
20915 
20916  /* all ok */
20917  return NO_ERROR;
20918 }
20919 
20920 /*
20921  * qexec_analytic_value_advance () - advance position in group/sort key list
20922  * files and load headers
20923  * returns: error code or NO_ERROR
20924  * thread_p(in): thread
20925  * func_state(in): function state
20926  * amount(in): amount to advance (can also be negative)
20927  * max_group_changes(in): maximum number of group changes
20928  * ignore_nulls(in): if true, execution will skip NULL values
20929  */
20930 static int
20932  int max_group_changes, bool ignore_nulls)
20933 {
20934  SCAN_CODE sc = S_SUCCESS;
20935 
20936  while (sc == S_SUCCESS && amount != 0)
20937  {
20938  /* compute new position */
20939  if (amount > 0)
20940  {
20941  if (max_group_changes <= 0 && func_state->group_tuple_position >= func_state->curr_group_tuple_count - 1)
20942  {
20943  /* already at end of group */
20944  break;
20945  }
20946 
20947  func_state->sort_key_tuple_position++;
20948  func_state->group_tuple_position++;
20949  }
20950  else
20951  {
20952  if (max_group_changes <= 0 && func_state->group_tuple_position <= 0)
20953  {
20954  /* already at beginning of group */
20955  break;
20956  }
20957 
20958  func_state->sort_key_tuple_position--;
20959  func_state->group_tuple_position--;
20960  }
20961 
20962  /* check for sort key header change */
20963  if (func_state->sort_key_tuple_position < 0)
20964  {
20965  /* load previous sort key header */
20966  sc = qfile_scan_list_prev (thread_p, &func_state->value_scan_id, &func_state->value_tplrec, PEEK);
20967  if (sc != S_SUCCESS)
20968  {
20969  return ER_FAILED;
20970  }
20971  if (qexec_analytic_sort_key_header_load (func_state, (-1 <= amount) && (amount <= 1)) != NO_ERROR)
20972  {
20973  return ER_FAILED;
20974  }
20975 
20976  /* initialize position to last */
20977  func_state->sort_key_tuple_position = func_state->curr_sort_key_tuple_count - 1;
20978  }
20979  else if (func_state->sort_key_tuple_position >= func_state->curr_sort_key_tuple_count)
20980  {
20981  /* load next sort key header */
20982  sc = qfile_scan_list_next (thread_p, &func_state->value_scan_id, &func_state->value_tplrec, PEEK);
20983  if (sc != S_SUCCESS)
20984  {
20985  return ER_FAILED;
20986  }
20987  if (qexec_analytic_sort_key_header_load (func_state, (-1 <= amount) && (amount <= 1)) != NO_ERROR)
20988  {
20989  return ER_FAILED;
20990  }
20991 
20992  /* reset position to first */
20993  func_state->sort_key_tuple_position = 0;
20994  }
20995 
20996  /* check for group header change */
20997  if (func_state->group_tuple_position < 0)
20998  {
20999  /* load previous sort key header */
21000  sc = qfile_scan_list_prev (thread_p, &func_state->group_scan_id, &func_state->group_tplrec, PEEK);
21001  if (sc != S_SUCCESS)
21002  {
21003  return ER_FAILED;
21004  }
21005  if (qexec_analytic_group_header_load (func_state) != NO_ERROR)
21006  {
21007  return ER_FAILED;
21008  }
21009 
21010  /* initialize position to last */
21011  func_state->group_tuple_position = func_state->curr_group_tuple_count - 1;
21012  func_state->group_tuple_position_nn = func_state->curr_group_tuple_count;
21013 
21014  /* decrement group change counter */
21015  max_group_changes--;
21016  }
21017  else if (func_state->group_tuple_position >= func_state->curr_group_tuple_count)
21018  {
21019  /* load next sort key header */
21020  sc = qfile_scan_list_next (thread_p, &func_state->group_scan_id, &func_state->group_tplrec, PEEK);
21021  if (sc != S_SUCCESS)
21022  {
21023  return ER_FAILED;
21024  }
21025  if (qexec_analytic_group_header_load (func_state) != NO_ERROR)
21026  {
21027  return ER_FAILED;
21028  }
21029 
21030  /* reset position to first */
21031  func_state->group_tuple_position = 0;
21032  func_state->group_tuple_position_nn = -1;
21033 
21034  /* decrement group change counter */
21035  max_group_changes--;
21036  }
21037 
21038  /* adjust amount */
21039  if (amount > 0)
21040  {
21041  if (!DB_IS_NULL (func_state->func_p->value))
21042  {
21043  func_state->group_tuple_position_nn++;
21044  amount--;
21045  }
21046  else
21047  {
21048  if (!ignore_nulls)
21049  {
21050  amount--;
21051  }
21052  }
21053  }
21054  else
21055  {
21056  if (!DB_IS_NULL (func_state->func_p->value))
21057  {
21058  func_state->group_tuple_position_nn--;
21059  amount++;
21060  }
21061  else
21062  {
21063  if (!ignore_nulls)
21064  {
21065  amount++;
21066  }
21067  }
21068  }
21069  }
21070 
21071  if (amount != 0)
21072  {
21073  /* target was not hit */
21074  if (func_state->curr_group_tuple_count_nn == 0 && ignore_nulls)
21075  {
21076  /* current group has only NULL values, so result will be NULL */
21077  return NO_ERROR;
21078  }
21079  else
21080  {
21081  /* true failure */
21082  return ER_FAILED;
21083  }
21084  }
21085  else
21086  {
21087  /* target was hit */
21088  return NO_ERROR;
21089  }
21090 }
21091 
21092 /*
21093  * qexec_analytic_value_lookup () - seek a position within the group and
21094  * load sort key headers
21095  * returns: error code or NO_ERROR
21096  * thread_p(in): thread
21097  * func_state(in): function state
21098  * position(in): position to seek
21099  * ignore_nulls(in): if true, execution will skip NULL values
21100  */
21101 static int
21102 qexec_analytic_value_lookup (THREAD_ENTRY * thread_p, ANALYTIC_FUNCTION_STATE * func_state, int position,
21103  bool ignore_nulls)
21104 {
21105  int offset = position;
21106 
21107  if (ignore_nulls)
21108  {
21109  offset -= func_state->group_tuple_position_nn;
21110  }
21111  else
21112  {
21113  offset -= func_state->group_tuple_position;
21114  }
21115 
21116  if (offset != 0)
21117  {
21118  return qexec_analytic_value_advance (thread_p, func_state, offset, 0, ignore_nulls);
21119  }
21120  else
21121  {
21122  /* even if we didn't move the position, make sure value is there */
21123  return qexec_analytic_sort_key_header_load (func_state, true);
21124  }
21125 }
21126 
21127 /*
21128  * qexec_analytic_group_header_next () - advance to next group
21129  * returns: error code or NO_ERROR
21130  * thread_p(in): thread
21131  * func_state(in): function state
21132  */
21133 static int
21135 {
21136  int pos, count;
21137 
21138  assert (func_state != NULL);
21139 
21140  pos = func_state->group_tuple_position;
21141  count = func_state->curr_group_tuple_count;
21142 
21143  return qexec_analytic_value_advance (thread_p, func_state, count - pos, 1, false);
21144 }
21145 
21146 /*
21147  * qexec_analytic_update_group_result () - update group result and add to
21148  * output file
21149  * return:
21150  * analytic_state(in):
21151  *
21152  * Note: Scan the last group from intermediary file and add up to date
21153  * analytic result into output file
21154  */
21155 static int
21157 {
21158  QFILE_TUPLE_RECORD tplrec_scan, tplrec_write;
21159  QFILE_LIST_SCAN_ID interm_scan_id;
21160  XASL_STATE *xasl_state = analytic_state->xasl_state;
21161  SCAN_CODE sc = S_SUCCESS;
21162  int i, rc = NO_ERROR;
21163 
21164  assert (analytic_state != NULL);
21165 
21166  /* open scans on all result files */
21167  for (i = 0; i < analytic_state->func_count; i++)
21168  {
21169  if (qfile_open_list_scan (analytic_state->func_state_list[i].group_list_id,
21170  &analytic_state->func_state_list[i].group_scan_id) != NO_ERROR)
21171  {
21172  return ER_FAILED;
21173  }
21174  if (qfile_open_list_scan (analytic_state->func_state_list[i].value_list_id,
21175  &analytic_state->func_state_list[i].value_scan_id) != NO_ERROR)
21176  {
21177  qfile_close_scan (thread_p, &analytic_state->func_state_list[i].group_scan_id);
21178  return ER_FAILED;
21179  }
21180 
21181  /* initialize tuple counter so we do a result read right away */
21182  analytic_state->func_state_list[i].curr_group_tuple_count = 0;
21183  analytic_state->func_state_list[i].curr_group_tuple_count_nn = 0;
21184  analytic_state->func_state_list[i].curr_sort_key_tuple_count = 0;
21185  analytic_state->func_state_list[i].group_tuple_position = -1;
21186  analytic_state->func_state_list[i].group_tuple_position_nn = -1;
21187  analytic_state->func_state_list[i].sort_key_tuple_position = -1;
21188  analytic_state->func_state_list[i].group_consumed_tuples = 0;
21189  }
21190 
21191  /* open scan on intermediate file */
21192  if (qfile_open_list_scan (analytic_state->interm_file, &interm_scan_id) != NO_ERROR)
21193  {
21194  qfile_close_scan (thread_p, &analytic_state->func_state_list[i].group_scan_id);
21195  qfile_close_scan (thread_p, &analytic_state->func_state_list[i].value_scan_id);
21196  return ER_FAILED;
21197  }
21198 
21199  /* we will use each func_state->value as a buffer to read values from the sort key headers, so make sure it points to
21200  * the vallist in order to correctly output values */
21201  for (i = 0; i < analytic_state->func_count; i++)
21202  {
21203  REGU_VARIABLE_LIST regu_list_p;
21204  ANALYTIC_TYPE *func_p = analytic_state->func_state_list[i].func_p;
21205  DB_VALUE *swap;
21206 
21207  if (func_p->function != PT_ROW_NUMBER)
21208  {
21209  swap = func_p->value;
21210  func_p->value = func_p->out_value;
21211  func_p->out_value = swap;
21212 
21213  /* also, don't fetch into value */
21214  for (regu_list_p = analytic_state->a_regu_list; regu_list_p != NULL; regu_list_p = regu_list_p->next)
21215  {
21216  if (regu_list_p->value.vfetch_to == func_p->value)
21217  {
21218  regu_list_p->value.vfetch_to = func_p->out_value;
21219  break;
21220  }
21221  }
21222  }
21223  }
21224 
21225  /* initialize tuple record */
21226  tplrec_scan.size = 0;
21227  tplrec_scan.tpl = NULL;
21228  tplrec_write.size = 0;
21229  tplrec_write.tpl = NULL;
21230 
21231  /* iterate files */
21232  while (sc == S_SUCCESS)
21233  {
21234  /* read one tuple from intermediate file */
21235  sc = qfile_scan_list_next (thread_p, &interm_scan_id, &tplrec_scan, PEEK);
21236  if (sc == S_END)
21237  {
21238  break;
21239  }
21240  else if (sc == S_ERROR)
21241  {
21242  rc = ER_FAILED;
21243  goto cleanup;
21244  }
21245 
21246  /* fetch values from intermediate file */
21247  rc = fetch_val_list (thread_p, analytic_state->a_regu_list, &xasl_state->vd, NULL, NULL, tplrec_scan.tpl, PEEK);
21248  if (rc != NO_ERROR)
21249  {
21250  goto cleanup;
21251  }
21252 
21253  /* evaluate inst_num() predicate */
21254  rc = qexec_analytic_eval_instnum_pred (thread_p, analytic_state, ANALYTIC_GROUP_PROC);
21255  if (rc != NO_ERROR)
21256  {
21257  goto cleanup;
21258  }
21259 
21260  /* handle functions */
21261  for (i = 0; i < analytic_state->func_count; i++)
21262  {
21263  ANALYTIC_FUNCTION_STATE *func_state = &analytic_state->func_state_list[i];
21264  ANALYTIC_TYPE *func_p = analytic_state->func_state_list[i].func_p;
21265 
21266  if (func_p->function == PT_ROW_NUMBER)
21267  {
21268  /* row number has already been computed and value was fetched from the intermediate file; nothing to do
21269  * here */
21270  }
21271  else if (QPROC_ANALYTIC_IS_OFFSET_FUNCTION (func_p))
21272  {
21273  if (func_state->group_tuple_position == -1 && func_state->sort_key_tuple_position == -1)
21274  {
21275  /* first scan, load first value */
21276  rc = qexec_analytic_value_advance (thread_p, func_state, 1, 1, func_p->ignore_nulls);
21277  if (rc != NO_ERROR)
21278  {
21279  goto cleanup;
21280  }
21281  }
21282  else if (func_state->group_consumed_tuples >= func_state->curr_group_tuple_count)
21283  {
21284  /* advance to next group */
21285  rc = qexec_analytic_group_header_next (thread_p, func_state);
21286  if (rc != NO_ERROR)
21287  {
21288  goto cleanup;
21289  }
21290  func_state->group_consumed_tuples = 0;
21291  }
21292  }
21293  else if (QPROC_IS_INTERPOLATION_FUNC (func_state->func_p))
21294  {
21295  /* MEDIAN, check for group end */
21296  if (func_state->group_consumed_tuples >= func_state->curr_group_tuple_count)
21297  {
21298  /* advance to next group */
21299  rc = qexec_analytic_group_header_next (thread_p, func_state);
21300  if (rc != NO_ERROR)
21301  {
21302  goto cleanup;
21303  }
21304  func_state->group_consumed_tuples = 0;
21305  }
21306  }
21307  else
21308  {
21309  bool ignore_nulls = func_p->ignore_nulls;
21310 
21311  if (func_p->function == PT_FIRST_VALUE || func_p->function == PT_LAST_VALUE)
21312  {
21313  /* for FIRST_VALUE and LAST_VALUE, the IGNORE NULLS logic resides at evaluation time */
21314  ignore_nulls = false;
21315  }
21316 
21317  /* if the function does not seek results in the list file, we are in charge of advancing */
21318  rc = qexec_analytic_value_advance (thread_p, func_state, 1, 1, ignore_nulls);
21319  if (rc != NO_ERROR)
21320  {
21321  goto cleanup;
21322  }
21323  }
21324 
21325  /* special behavior */
21326  switch (func_p->function)
21327  {
21328  case PT_LEAD:
21329  case PT_LAG:
21330  case PT_NTH_VALUE:
21331  if (analytic_state->is_output_rec)
21332  {
21333  rc = qexec_analytic_evaluate_offset_function (thread_p, func_state, analytic_state);
21334  if (rc != NO_ERROR)
21335  {
21336  goto cleanup;
21337  }
21338  }
21339  break;
21340 
21341  case PT_NTILE:
21342  if (analytic_state->is_output_rec)
21343  {
21344  rc = qexec_analytic_evaluate_ntile_function (thread_p, func_state);
21345  if (rc != NO_ERROR)
21346  {
21347  goto cleanup;
21348  }
21349  }
21350  break;
21351 
21352  case PT_CUME_DIST:
21353  case PT_PERCENT_RANK:
21354  rc = qexec_analytic_evaluate_cume_dist_percent_rank_function (thread_p, func_state);
21355  if (rc != NO_ERROR)
21356  {
21357  goto cleanup;
21358  }
21359  break;
21360 
21361  case PT_MEDIAN:
21362  case PT_PERCENTILE_CONT:
21363  case PT_PERCENTILE_DISC:
21364  rc = qexec_analytic_evaluate_interpolation_function (thread_p, func_state);
21365  if (rc != NO_ERROR)
21366  {
21367  goto cleanup;
21368  }
21369  break;
21370 
21371  default:
21372  /* nothing to do */
21373  break;
21374  }
21375 
21376  /* advance tuple index */
21377  func_state->group_consumed_tuples++;
21378  }
21379 
21380  if (analytic_state->is_output_rec)
21381  {
21382  /* add tuple to output file */
21383  rc =
21384  qexec_insert_tuple_into_list (thread_p, analytic_state->output_file, analytic_state->a_outptr_list,
21385  &xasl_state->vd, &tplrec_write);
21386  if (rc != NO_ERROR)
21387  {
21388  goto cleanup;
21389  }
21390  }
21391  }
21392 
21393 cleanup:
21394  /* undo the pointer swap we've done before */
21395  for (i = 0; i < analytic_state->func_count; i++)
21396  {
21397  ANALYTIC_TYPE *func_p = analytic_state->func_state_list[i].func_p;
21398  REGU_VARIABLE_LIST regu_list_p;
21399  DB_VALUE *swap;
21400 
21401  if (func_p->function != PT_ROW_NUMBER)
21402  {
21403  swap = func_p->value;
21404  func_p->value = func_p->out_value;
21405  func_p->out_value = swap;
21406  }
21407 
21408  for (regu_list_p = analytic_state->a_regu_list; regu_list_p != NULL; regu_list_p = regu_list_p->next)
21409  {
21410  if (regu_list_p->value.vfetch_to == func_p->value)
21411  {
21412  regu_list_p->value.vfetch_to = func_p->out_value;
21413  break;
21414  }
21415  }
21416  }
21417 
21418  /* free write tuple record */
21419  if (tplrec_write.tpl != NULL)
21420  {
21421  db_private_free_and_init (thread_p, tplrec_write.tpl);
21422  tplrec_write.size = 0;
21423  }
21424 
21425  /* close all scans */
21426  qfile_close_scan (thread_p, &interm_scan_id);
21427  for (i = 0; i < analytic_state->func_count; i++)
21428  {
21429  qfile_close_scan (thread_p, &analytic_state->func_state_list[i].group_scan_id);
21430  qfile_close_scan (thread_p, &analytic_state->func_state_list[i].value_scan_id);
21431  }
21432 
21433  /* all ok */
21434  return rc;
21435 }
21436 
21437 /*
21438  * qexec_clear_pred_context () - clear the predicate
21439  * return: int
21440  * pred_filter(in) : The filter predicate
21441  * dealloc_dbvalues(in): Deallocate db values from dbvalue regu variable
21442  *
21443  * Note: Use an XASL_NODE to clear allocated memmory.
21444  */
21445 
21446 int
21447 qexec_clear_pred_context (THREAD_ENTRY * thread_p, pred_expr_with_context * pred_filter, bool dealloc_dbvalues)
21448 {
21450 
21451  memset (&xasl_node, 0, sizeof (XASL_NODE));
21452 
21453  if (dealloc_dbvalues)
21454  {
21455  XASL_SET_FLAG (&xasl_node, XASL_DECACHE_CLONE);
21456  }
21457 
21458  qexec_clear_pred (thread_p, &xasl_node, pred_filter->pred, true);
21459 
21460  return NO_ERROR;
21461 }
21462 
21463 /*
21464  * qexec_clear_func_pred () - clear the predicate
21465  * return: int
21466  * func_pred(in) : The function predicate
21467  *
21468  * Note: Use an XASL_NODE to clear allocated memmory.
21469  */
21470 
21471 int
21473 {
21475 
21476  memset (&xasl_node, 0, sizeof (XASL_NODE));
21477 
21478  (void) qexec_clear_regu_var (thread_p, &xasl_node, fpr->func_regu, true);
21479 
21480  return NO_ERROR;
21481 }
21482 
21483 /*
21484  * qexec_clear_partition_expression () - clear partition expression
21485  * return : cleared count or error code
21486  * thread_p (in) :
21487  * expr (in) :
21488  */
21489 int
21491 {
21493 
21494  memset (&xasl_node, 0, sizeof (XASL_NODE));
21495  qexec_clear_regu_var (thread_p, &xasl_node, expr, true);
21496 
21497  return NO_ERROR;
21498 }
21499 
21500 /*
21501  * qexec_for_update_set_class_locks () - set X_LOCK on classes which will be
21502  * updated and are accessed sequentially
21503  * return : error code or NO_ERROR
21504  * thread_p (in) :
21505  * scan_list (in) :
21506  *
21507  * Note: Used in SELECT ... FOR UPDATE
21508  */
21509 static int
21511 {
21512  XASL_NODE *scan = NULL;
21513  ACCESS_SPEC_TYPE *specp = NULL;
21514  OID *class_oid = NULL;
21515  int error = NO_ERROR;
21516  LOCK class_lock = IX_LOCK; /* MVCC use IX_LOCK on class at update/delete */
21517 
21518  for (scan = scan_list; scan != NULL; scan = scan->scan_ptr)
21519  {
21520  for (specp = scan->spec_list; specp; specp = specp->next)
21521  {
21522  if (specp->type == TARGET_CLASS && (specp->flags & ACCESS_SPEC_FLAG_FOR_UPDATE))
21523  {
21524  class_oid = &specp->s.cls_node.cls_oid;
21525 
21526  /* lock the class */
21527  if (lock_object (thread_p, class_oid, oid_Root_class_oid, class_lock, LK_UNCOND_LOCK) != LK_GRANTED)
21528  {
21529  assert (er_errid () != NO_ERROR);
21530  error = er_errid ();
21531  if (error == NO_ERROR)
21532  {
21533  error = ER_FAILED;
21534  }
21535  return error;
21536  }
21537  }
21538  }
21539  }
21540 
21541  return error;
21542 }
21543 
21544 /*
21545  * qexec_set_class_locks () - set X_LOCK on classes which will be updated and
21546  * are accessed sequentially and IX_LOCK on updated
21547  * classes which are accessed through an index
21548  *
21549  * return : error code or NO_ERROR
21550  * thread_p (in) :
21551  * xasl (in) :
21552  * query_classes (in) : query classes
21553  * internal_classes (in) : internal classes
21554  * count (in) :
21555  */
21556 static int
21557 qexec_set_class_locks (THREAD_ENTRY * thread_p, XASL_NODE * aptr_list, UPDDEL_CLASS_INFO * query_classes,
21558  int query_classes_count, UPDDEL_CLASS_INFO_INTERNAL * internal_classes)
21559 {
21560  XASL_NODE *aptr = NULL;
21561  ACCESS_SPEC_TYPE *specp = NULL;
21562  OID *class_oid = NULL;
21563  int i, j, error = NO_ERROR;
21564  UPDDEL_CLASS_INFO *query_class = NULL;
21565  bool found = false;
21566  LOCK class_lock = IX_LOCK; /* MVCC use IX_LOCK on class at update/delete */
21567 
21568  for (aptr = aptr_list; aptr != NULL; aptr = aptr->scan_ptr)
21569  {
21570  for (specp = aptr->spec_list; specp; specp = specp->next)
21571  {
21572  if (specp->type == TARGET_SET)
21573  {
21574  /* lock all update classes */
21575 
21577 
21578  for (i = 0; i < query_classes_count; i++)
21579  {
21580  query_class = &query_classes[i];
21581 
21582  /* search class_oid through subclasses of a query class */
21583  for (j = 0; j < query_class->num_subclasses; j++)
21584  {
21585  class_oid = &query_class->class_oid[j];
21586 
21587  if (lock_object (thread_p, class_oid, oid_Root_class_oid, class_lock, LK_UNCOND_LOCK) !=
21588  LK_GRANTED)
21589  {
21590  assert (er_errid () != NO_ERROR);
21591  error = er_errid ();
21592  if (error == NO_ERROR)
21593  {
21594  error = ER_FAILED;
21595  }
21596  return error;
21597  }
21598  }
21599  }
21600 
21601  return error;
21602  }
21603 
21604  if (specp->type == TARGET_CLASS)
21605  {
21606  class_oid = &specp->s.cls_node.cls_oid;
21607  found = false;
21608 
21609  /* search through query classes */
21610  for (i = 0; i < query_classes_count && !found; i++)
21611  {
21612  query_class = &query_classes[i];
21613 
21614  /* search class_oid through subclasses of a query class */
21615  for (j = 0; j < query_class->num_subclasses; j++)
21616  {
21617  if (OID_EQ (&query_class->class_oid[j], class_oid))
21618  {
21619  /* lock the class */
21620  if (lock_object (thread_p, class_oid, oid_Root_class_oid, class_lock, LK_UNCOND_LOCK) !=
21621  LK_GRANTED)
21622  {
21623  assert (er_errid () != NO_ERROR);
21624  error = er_errid ();
21625  if (error == NO_ERROR)
21626  {
21627  error = ER_FAILED;
21628  }
21629  return error;
21630  }
21631 
21632  found = true;
21633  break;
21634  }
21635  }
21636  }
21637  }
21638  }
21639  }
21640 
21641  return error;
21642 }
21643 
21644 /*
21645  * qexec_execute_build_indexes () - Execution function for BUILD SCHEMA proc
21646  * return: NO_ERROR, or ER_code
21647  * xasl(in): XASL tree
21648  * xasl_state(in): XASL state
21649  */
21650 static int
21652 {
21653  QFILE_TUPLE_RECORD tplrec = { NULL, 0 };
21654  int idx_incache = -1;
21655  REPR_ID class_repr_id = NULL_REPRID;
21656  OR_CLASSREP *rep = NULL;
21657  OR_INDEX *index = NULL;
21658  OR_ATTRIBUTE *index_att = NULL;
21659  int att_id = 0;
21660  char *attr_name = NULL, *string = NULL;
21661  OR_ATTRIBUTE *attrepr = NULL;
21662  DB_VALUE **out_values = NULL;
21663  REGU_VARIABLE_LIST regu_var_p;
21664  char **attr_names = NULL;
21665  int *attr_ids = NULL;
21666  int function_asc_desc;
21667  HEAP_SCANCACHE scan;
21668  bool scancache_inited = false;
21669  RECDES class_record;
21670  DISK_REPR *disk_repr_p = NULL;
21671  char *class_name = NULL;
21672  int non_unique;
21673  int cardinality;
21674  OID *class_oid = NULL;
21675  OID dir_oid;
21676  int i, j, k;
21677  int error = NO_ERROR;
21678  int function_index_pos = -1;
21679  int index_position = 0, size_values = 0;
21680  int num_idx_att = 0;
21681  char *comment = NULL;
21682  int alloced_string = 0;
21683  HL_HEAPID save_heapid = 0;
21685 
21686  assert (xasl != NULL && xasl_state != NULL);
21687 
21688  for (regu_var_p = xasl->outptr_list->valptrp, i = 0; regu_var_p; regu_var_p = regu_var_p->next, i++)
21689  {
21691  {
21692  save_heapid = db_change_private_heap (thread_p, 0);
21693  break;
21694  }
21695  }
21696  if (qexec_start_mainblock_iterations (thread_p, xasl, xasl_state) != NO_ERROR)
21697  {
21699  }
21700 
21701  assert (xasl_state != NULL);
21702  class_oid = &(xasl->spec_list->s.cls_node.cls_oid);
21703 
21704  /* get class disk representation */
21705  if (catalog_get_dir_oid_from_cache (thread_p, class_oid, &dir_oid) != NO_ERROR)
21706  {
21707  ASSERT_ERROR_AND_SET (error);
21709  }
21710 
21711  catalog_access_info.class_oid = class_oid;
21712  catalog_access_info.dir_oid = &dir_oid;
21713  if (catalog_start_access_with_dir_oid (thread_p, &catalog_access_info, S_LOCK) != NO_ERROR)
21714  {
21715  ASSERT_ERROR_AND_SET (error);
21716  (void) catalog_end_access_with_dir_oid (thread_p, &catalog_access_info, error);
21718  }
21719 
21720  error = catalog_get_last_representation_id (thread_p, class_oid, &class_repr_id);
21721  if (error != NO_ERROR)
21722  {
21723  (void) catalog_end_access_with_dir_oid (thread_p, &catalog_access_info, error);
21725  }
21726 
21727  disk_repr_p = catalog_get_representation (thread_p, class_oid, class_repr_id, &catalog_access_info);
21728  if (disk_repr_p == NULL)
21729  {
21730  ASSERT_ERROR_AND_SET (error);
21731  (void) catalog_end_access_with_dir_oid (thread_p, &catalog_access_info, error);
21733  }
21734 
21735  (void) catalog_end_access_with_dir_oid (thread_p, &catalog_access_info, NO_ERROR);
21736 
21737  /* read heap class record, get class representation */
21738  heap_scancache_quick_start_root_hfid (thread_p, &scan);
21739  scancache_inited = true;
21740 
21741  if (heap_get_class_record (thread_p, class_oid, &class_record, &scan, PEEK) != S_SUCCESS)
21742  {
21744  }
21745 
21746  rep = heap_classrepr_get (thread_p, class_oid, &class_record, class_repr_id, &idx_incache);
21747  if (rep == NULL)
21748  {
21750  }
21751 
21752  size_values = xasl->outptr_list->valptr_cnt;
21753  assert (size_values == 14);
21754  out_values = (DB_VALUE **) malloc (size_values * sizeof (DB_VALUE *));
21755  if (out_values == NULL)
21756  {
21757  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, size_values * sizeof (DB_VALUE *));
21758  error = ER_OUT_OF_VIRTUAL_MEMORY;
21760  }
21761 
21762  for (regu_var_p = xasl->outptr_list->valptrp, i = 0; regu_var_p; regu_var_p = regu_var_p->next, i++)
21763  {
21764  out_values[i] = &(regu_var_p->value.value.dbval);
21765  pr_clear_value (out_values[i]);
21766  }
21767 
21768  attr_names = (char **) malloc (rep->n_attributes * sizeof (char *));
21769  if (attr_names == NULL)
21770  {
21772  }
21773 
21774  attr_ids = (int *) malloc (rep->n_attributes * sizeof (int));
21775  if (attr_ids == NULL)
21776  {
21778  }
21779 
21780  for (i = 0; i < rep->n_attributes; i++)
21781  {
21782  attr_names[i] = NULL;
21783  attr_ids[i] = -1;
21784  }
21785 
21786  for (i = 0, attrepr = rep->attributes; i < rep->n_attributes; i++, attrepr++)
21787  {
21788  string = NULL;
21789  alloced_string = 0;
21790 
21791  error = or_get_attrname (&class_record, attrepr->id, &string, &alloced_string);
21792  if (error != NO_ERROR)
21793  {
21794  ASSERT_ERROR ();
21796  }
21797 
21798  attr_name = string;
21799  if (attr_name == NULL)
21800  {
21801  continue;
21802  }
21803 
21804  attr_names[i] = strdup (attr_name);
21805  attr_ids[i] = attrepr->id;
21806 
21807  if (string != NULL && alloced_string == 1)
21808  {
21809  db_private_free_and_init (thread_p, string);
21810  }
21811  }
21812 
21813  class_name = or_class_name (&class_record);
21814  for (i = 0; i < rep->n_indexes; i++)
21815  {
21816  /* class name */
21817  db_make_string (out_values[0], class_name);
21818 
21819  /* packed */
21820  db_make_null (out_values[8]);
21821 
21822  /* index type */
21823  db_make_string (out_values[10], "BTREE");
21824 
21825  index = rep->indexes + i;
21826  /* Non_unique */
21827  non_unique = btree_is_unique_type (index->type) ? 0 : 1;
21828  db_make_int (out_values[1], non_unique);
21829 
21830  /* Key_name */
21831  db_make_string (out_values[2], index->btname);
21832 
21833  /* Func */
21834  db_make_null (out_values[11]);
21835 
21836  /* Comment */
21837  comment = (char *) or_get_constraint_comment (&class_record, index->btname);
21838  db_make_string (out_values[12], comment);
21839 
21840  /* Visible */
21841  db_make_string (out_values[13], (index->index_status == OR_NORMAL_INDEX) ? "YES" : "NO");
21842 
21843  if (index->func_index_info == NULL)
21844  {
21845  function_index_pos = -1;
21846  num_idx_att = index->n_atts;
21847  }
21848  else
21849  {
21850  function_index_pos = index->func_index_info->col_id;
21851  /* do not count function attributes function attributes are positioned after index attributes at the end of
21852  * index->atts array */
21853  num_idx_att = index->func_index_info->attr_index_start;
21854  }
21855 
21856  /* index attributes */
21857  index_position = 0;
21858  for (j = 0; j < num_idx_att; j++)
21859  {
21860  index_att = index->atts[j];
21861  att_id = index_att->id;
21862  assert (att_id >= 0);
21863 
21864  if (index_position == function_index_pos)
21865  {
21866  /* function position in index founded, compute attribute position in index */
21867  index_position++;
21868  }
21869 
21870  /* Seq_in_index */
21871  db_make_int (out_values[3], index_position + 1);
21872 
21873  /* Collation */
21874  if (index->asc_desc[j])
21875  {
21876  db_make_string (out_values[5], "D");
21877  }
21878  else
21879  {
21880  db_make_string (out_values[5], "A");
21881  }
21882 
21883  /* Cardinality */
21884  if (catalog_get_cardinality (thread_p, class_oid, disk_repr_p, &index->btid, index_position, &cardinality) !=
21885  NO_ERROR)
21886  {
21888  }
21889 
21890  if (cardinality < 0)
21891  {
21892  db_make_null (out_values[6]);
21893  }
21894  else
21895  {
21896  db_make_int (out_values[6], cardinality);
21897  }
21898 
21899  /* Sub_part */
21900  if (index->attrs_prefix_length && index->attrs_prefix_length[j] > -1)
21901  {
21902  db_make_int (out_values[7], index->attrs_prefix_length[j]);
21903  }
21904  else
21905  {
21906  db_make_null (out_values[7]);
21907  }
21908 
21909  /* [Null] */
21910  if (index_att->is_notnull)
21911  {
21912  db_make_string (out_values[9], "NO");
21913  }
21914  else
21915  {
21916  db_make_string (out_values[9], "YES");
21917  }
21918 
21919  /* Column_name */
21920  for (k = 0; k < rep->n_attributes; k++)
21921  {
21922  if (att_id == attr_ids[k])
21923  {
21924  db_make_string (out_values[4], attr_names[k]);
21925  qexec_end_one_iteration (thread_p, xasl, xasl_state, &tplrec);
21926  break;
21927  }
21928  }
21929 
21930  /* clear alloced DB_VALUEs */
21931  pr_clear_value (out_values[5]);
21932  pr_clear_value (out_values[9]);
21933 
21934  index_position++;
21935  }
21936 
21937  /* function index */
21938  if (function_index_pos >= 0)
21939  {
21940  /* Func */
21941  db_make_string (out_values[11], index->func_index_info->expr_string);
21942 
21943  /* Collation */
21944  if (btree_get_asc_desc (thread_p, &index->btid, function_index_pos, &function_asc_desc) != NO_ERROR)
21945  {
21947  }
21948 
21949  if (function_asc_desc)
21950  {
21951  db_make_string (out_values[5], "D");
21952  }
21953  else
21954  {
21955  db_make_string (out_values[5], "A");
21956  }
21957 
21958  /* Seq_in_index */
21959  db_make_int (out_values[3], function_index_pos + 1);
21960 
21961  /* Cardinality */
21962  if (catalog_get_cardinality (thread_p, class_oid, disk_repr_p, &index->btid, function_index_pos, &cardinality)
21963  != NO_ERROR)
21964  {
21966  }
21967 
21968  if (cardinality < 0)
21969  {
21970  db_make_null (out_values[6]);
21971  }
21972  else
21973  {
21974  db_make_int (out_values[6], cardinality);
21975  }
21976 
21977  /* Sub_part */
21978  db_make_null (out_values[7]);
21979 
21980  /* [Null] */
21981  db_make_string (out_values[9], "YES");
21982 
21983  /* Column_name */
21984  db_make_null (out_values[4]);
21985  qexec_end_one_iteration (thread_p, xasl, xasl_state, &tplrec);
21986  }
21987 
21988  if (comment != NULL)
21989  {
21990  free_and_init (comment);
21991  }
21992 
21993  /* needs to clear db_value content if is allocated during qexec_end_one_iteration */
21994  for (j = 0; j < size_values; j++)
21995  {
21996  pr_clear_value (out_values[j]);
21997  }
21998  }
21999 
22000  for (i = 0; i < rep->n_attributes; i++)
22001  {
22002  if (attr_names[i] != NULL)
22003  {
22004  free_and_init (attr_names[i]);
22005  }
22006  }
22007 
22008  free_and_init (out_values);
22009  free_and_init (attr_ids);
22010  free_and_init (attr_names);
22011 
22013  heap_classrepr_free_and_init (rep, &idx_incache);
22014  if (heap_scancache_end (thread_p, &scan) != NO_ERROR)
22015  {
22017  }
22018  scancache_inited = false;
22019 
22020  if (qexec_end_mainblock_iterations (thread_p, xasl, xasl_state, &tplrec) != NO_ERROR)
22021  {
22023  }
22024 
22025  if ((xasl->orderby_list /* it has ORDER BY clause */
22026  && (!XASL_IS_FLAGED (xasl, XASL_SKIP_ORDERBY_LIST) /* cannot skip */
22027  || XASL_IS_FLAGED (xasl, XASL_USES_MRO)) /* MRO must go on */
22028  && (xasl->list_id->tuple_cnt > 1 /* the result has more than one tuple */
22029  || xasl->ordbynum_val != NULL)) /* ORDERBY_NUM() is used */
22030  || (xasl->option == Q_DISTINCT)) /* DISTINCT must go on */
22031  {
22032  if (qexec_orderby_distinct (thread_p, xasl, xasl->option, xasl_state) != NO_ERROR)
22033  {
22035  }
22036  }
22037 
22038  if (tplrec.tpl)
22039  {
22040  db_private_free_and_init (thread_p, tplrec.tpl);
22041  }
22042 
22043  if (save_heapid != 0)
22044  {
22045  (void) db_change_private_heap (thread_p, save_heapid);
22046  save_heapid = 0;
22047  }
22048 
22049  return NO_ERROR;
22050 
22051 exit_on_error:
22052 
22053  if (out_values)
22054  {
22055  for (i = 0; i < size_values; i++)
22056  {
22057  pr_clear_value (out_values[i]);
22058  }
22059 
22060  free_and_init (out_values);
22061  }
22062  if (attr_ids)
22063  {
22064  free_and_init (attr_ids);
22065  }
22066  if (attr_names)
22067  {
22068  for (i = 0; i < rep->n_attributes; i++)
22069  {
22070  if (attr_names[i] != NULL)
22071  {
22072  free_and_init (attr_names[i]);
22073  }
22074  }
22075  free_and_init (attr_names);
22076  }
22077 
22078  if (disk_repr_p)
22079  {
22081  }
22082 
22083  if (rep)
22084  {
22085  heap_classrepr_free_and_init (rep, &idx_incache);
22086  }
22087 
22088  if (scancache_inited)
22089  {
22090  heap_scancache_end (thread_p, &scan);
22091  scancache_inited = false;
22092  }
22093 
22094 #if defined(SERVER_MODE)
22095  /* query execution error must be set up before qfile_close_list(). */
22096  if (er_errid () < 0)
22097  {
22098  qmgr_set_query_error (thread_p, xasl_state->query_id);
22099  }
22100 #endif
22101 
22102  qfile_close_list (thread_p, xasl->list_id);
22103 
22104  if (tplrec.tpl)
22105  {
22106  db_private_free_and_init (thread_p, tplrec.tpl);
22107  }
22108 
22109  if (save_heapid != 0)
22110  {
22111  (void) db_change_private_heap (thread_p, save_heapid);
22112  save_heapid = 0;
22113  }
22114 
22115  xasl->status = XASL_FAILURE;
22116 
22117  qexec_failure_line (__LINE__, xasl_state);
22118 
22119  return (error == NO_ERROR && (error = er_errid ()) == NO_ERROR) ? ER_FAILED : error;
22120 }
22121 
22122 /*
22123  * qexec_schema_get_type_name_from_id() - returns string form of t's datatype
22124  * for build schema
22125  * return: character string denoting datatype dt
22126  * id(in): a DB_TYPE
22127  */
22128 static const char *
22130 {
22131  switch (id)
22132  {
22133  case DB_TYPE_INTEGER:
22134  return "INTEGER";
22135 
22136  case DB_TYPE_BIGINT:
22137  return "BIGINT";
22138 
22139  case DB_TYPE_SMALLINT:
22140  return "SHORT";
22141 
22142  case DB_TYPE_NUMERIC:
22143  return "NUMERIC";
22144 
22145  case DB_TYPE_FLOAT:
22146  return "FLOAT";
22147 
22148  case DB_TYPE_DOUBLE:
22149  return "DOUBLE";
22150 
22151  case DB_TYPE_DATE:
22152  return "DATE";
22153 
22154  case DB_TYPE_TIME:
22155  return "TIME";
22156 
22157  case DB_TYPE_TIMESTAMP:
22158  return "TIMESTAMP";
22159 
22160  case DB_TYPE_TIMESTAMPTZ:
22161  return "TIMESTAMPTZ";
22162 
22163  case DB_TYPE_TIMESTAMPLTZ:
22164  return "TIMESTAMPLTZ";
22165 
22166  case DB_TYPE_DATETIME:
22167  return "DATETIME";
22168 
22169  case DB_TYPE_DATETIMETZ:
22170  return "DATETIMETZ";
22171 
22172  case DB_TYPE_DATETIMELTZ:
22173  return "DATETIMELTZ";
22174 
22175  case DB_TYPE_MONETARY:
22176  return "MONETARY";
22177 
22178 
22179  case DB_TYPE_VARCHAR:
22180  return "VARCHAR";
22181 
22182  case DB_TYPE_CHAR:
22183  return "CHAR";
22184 
22185  case DB_TYPE_OID:
22186  case DB_TYPE_OBJECT:
22187  return "OBJECT";
22188 
22189  case DB_TYPE_SET:
22190  return "SET";
22191 
22192  case DB_TYPE_MULTISET:
22193  return "MULTISET";
22194 
22195  case DB_TYPE_SEQUENCE:
22196  return "SEQUENCE";
22197 
22198  case DB_TYPE_NCHAR:
22199  return "NCHAR";
22200 
22201  case DB_TYPE_VARNCHAR:
22202  return "NCHAR VARYING";
22203 
22204  case DB_TYPE_BIT:
22205  return "BIT";
22206 
22207  case DB_TYPE_VARBIT:
22208  return "BIT VARYING";
22209 
22210  case DB_TYPE_BLOB:
22211  return "BLOB";
22212 
22213  case DB_TYPE_CLOB:
22214  return "CLOB";
22215 
22216  case DB_TYPE_ENUMERATION:
22217  return "ENUM";
22218  case DB_TYPE_JSON:
22219  return "JSON";
22220  default:
22221  return "UNKNOWN DATA_TYPE";
22222  }
22223 }
22224 
22225 
22226 /*
22227  * qexec_schema_get_type_desc() - returns string form of t's datatype
22228  * return: character string denoting datatype dt
22229  * ie(in): a DB_TYPE
22230  */
22231 static int
22233 {
22234  const char *name = NULL;
22235  int precision = -1;
22236  int scale = -1;
22237  DB_ENUM_ELEMENT *enum_elements = NULL;
22238  int enum_elements_count = 0;
22239  TP_DOMAIN *setdomain = NULL;
22240  const char *set_of_string = NULL;
22241  JSON_VALIDATOR *validator = NULL;
22242 
22243  assert (domain != NULL && result != NULL);
22244 
22245  db_make_null (result);
22246 
22247  switch (id)
22248  {
22249  case DB_TYPE_NUMERIC:
22250  scale = domain->scale;
22251  /* fall through */
22252 
22253  case DB_TYPE_VARCHAR:
22254  case DB_TYPE_CHAR:
22255  case DB_TYPE_NCHAR:
22256  case DB_TYPE_VARNCHAR:
22257  case DB_TYPE_BIT:
22258  case DB_TYPE_VARBIT:
22259  precision = domain->precision;
22260  break;
22261 
22262  case DB_TYPE_SET:
22263  setdomain = domain->setdomain;
22264  if (setdomain == NULL)
22265  {
22266  return NO_ERROR;
22267  }
22268  set_of_string = "SET OF ";
22269  break;
22270  case DB_TYPE_MULTISET:
22271  setdomain = domain->setdomain;
22272  if (setdomain == NULL)
22273  {
22274  return NO_ERROR;
22275  }
22276  set_of_string = "MULTISET OF ";
22277  break;
22278  case DB_TYPE_SEQUENCE:
22279  setdomain = domain->setdomain;
22280  if (setdomain == NULL)
22281  {
22282  return NO_ERROR;
22283  }
22284  set_of_string = "SEQUENCE OF ";
22285  break;
22286 
22287  case DB_TYPE_ENUMERATION:
22288  enum_elements = domain->enumeration.elements;
22289  enum_elements_count = domain->enumeration.count;
22290  break;
22291  case DB_TYPE_JSON:
22292  validator = domain->json_validator;
22293  break;
22294  default:
22295  break;
22296  }
22297 
22299 
22300  if (enum_elements)
22301  {
22302  DB_VALUE enum_arg1, enum_arg2, enum_result, *penum_arg1, *penum_arg2, *penum_result, *penum_temp;
22303  DB_DATA_STATUS data_stat;
22304  DB_VALUE quote, quote_comma_space, enum_;
22305  DB_VALUE braket;
22306  int i;
22307 
22308  assert (enum_elements_count >= 0);
22309 
22310  penum_arg1 = &enum_arg1;
22311  penum_arg2 = &enum_arg2;
22312  penum_result = &enum_result;
22313 
22314  db_make_string (&quote, "\'");
22315  db_make_string (&quote_comma_space, "\', ");
22316  db_make_string (&braket, ")");
22317  db_make_string (&enum_, "ENUM(");
22318 
22319  pr_clone_value (&enum_, penum_result);
22320  for (i = 0; i < enum_elements_count; i++)
22321  {
22322  penum_temp = penum_arg1;
22323  penum_arg1 = penum_result;
22324  penum_result = penum_temp;
22325  if ((db_string_concatenate (penum_arg1, &quote, penum_result, &data_stat) != NO_ERROR)
22326  || (data_stat != DATA_STATUS_OK))
22327  {
22328  pr_clear_value (penum_arg1);
22329  goto exit_on_error;
22330  }
22331  pr_clear_value (penum_arg1);
22332 
22333  penum_temp = penum_arg1;
22334  penum_arg1 = penum_result;
22335  penum_result = penum_temp;
22336 
22337  db_make_string (penum_arg2, enum_elements[i].str_val.medium.buf);
22338  if ((db_string_concatenate (penum_arg1, penum_arg2, penum_result, &data_stat) != NO_ERROR)
22339  || (data_stat != DATA_STATUS_OK))
22340  {
22341  pr_clear_value (penum_arg1);
22342  pr_clear_value (penum_arg2);
22343  goto exit_on_error;
22344  }
22345  pr_clear_value (penum_arg1);
22346 
22347  penum_temp = penum_arg1;
22348  penum_arg1 = penum_result;
22349  penum_result = penum_temp;
22350  if (i < enum_elements_count - 1)
22351  {
22352  if ((db_string_concatenate (penum_arg1, &quote_comma_space, penum_result, &data_stat) != NO_ERROR)
22353  || (data_stat != DATA_STATUS_OK))
22354  {
22355  pr_clear_value (penum_arg1);
22356  pr_clear_value (penum_arg2);
22357  goto exit_on_error;
22358  }
22359  }
22360  else
22361  {
22362  if ((db_string_concatenate (penum_arg1, &quote, penum_result, &data_stat) != NO_ERROR)
22363  || (data_stat != DATA_STATUS_OK))
22364  {
22365  pr_clear_value (penum_arg1);
22366  pr_clear_value (penum_arg2);
22367  goto exit_on_error;
22368  }
22369  }
22370  pr_clear_value (penum_arg1);
22371  pr_clear_value (penum_arg2);
22372  }
22373 
22374  penum_temp = penum_arg1;
22375  penum_arg1 = penum_result;
22376  penum_result = penum_temp;
22377  if ((db_string_concatenate (penum_arg1, &braket, penum_result, &data_stat) != NO_ERROR)
22378  || (data_stat != DATA_STATUS_OK))
22379  {
22380  goto exit_on_error;
22381  }
22382  pr_clear_value (penum_arg1);
22383  pr_clone_value (penum_result, result);
22384  pr_clear_value (penum_result);
22385 
22386  return NO_ERROR;
22387  }
22388  else if (setdomain != NULL)
22389  {
22390  /* process sequence */
22391  DB_VALUE set_arg1, set_arg2, set_result, *pset_arg1, *pset_arg2, *pset_result, *pset_temp;
22392  DB_DATA_STATUS data_stat;
22393  DB_VALUE comma;
22394  char **ordered_names = NULL, *min, *temp;
22395  int count_names = 0, i, j, idx_min;
22396 
22397  for (setdomain = domain->setdomain; setdomain; setdomain = setdomain->next)
22398  {
22399  count_names++;
22400  }
22401 
22402  ordered_names = (char **) malloc (count_names * sizeof (char *));
22403  if (ordered_names == NULL)
22404  {
22405  return ER_OUT_OF_VIRTUAL_MEMORY;
22406  }
22407 
22408  for (setdomain = domain->setdomain, i = 0; setdomain; setdomain = setdomain->next, i++)
22409  {
22410  ordered_names[i] = (char *) qexec_schema_get_type_name_from_id (setdomain->type->id);
22411  }
22412 
22413  for (i = 0; i < count_names - 1; i++)
22414  {
22415  idx_min = i;
22416  min = ordered_names[i];
22417  for (j = i + 1; j < count_names; j++)
22418  {
22419  if (strcmp (ordered_names[i], ordered_names[j]) > 0)
22420  {
22421  min = ordered_names[j];
22422  idx_min = j;
22423  }
22424  }
22425 
22426  if (idx_min != i)
22427  {
22428  temp = ordered_names[i];
22429  ordered_names[i] = ordered_names[idx_min];
22430  ordered_names[idx_min] = temp;
22431  }
22432  }
22433 
22434  pset_arg1 = &set_arg1;
22435  pset_arg2 = &set_arg2;
22436  pset_result = &set_result;
22437 
22438  db_make_string (&comma, ",");
22439  db_make_string (pset_result, set_of_string);
22440 
22441  for (setdomain = domain->setdomain, i = 0; setdomain; setdomain = setdomain->next, i++)
22442  {
22443  pset_temp = pset_arg1;
22444  pset_arg1 = pset_result;
22445  pset_result = pset_temp;
22446  db_make_string (pset_arg2, ordered_names[i]);
22447  if ((db_string_concatenate (pset_arg1, pset_arg2, pset_result, &data_stat) != NO_ERROR)
22448  || (data_stat != DATA_STATUS_OK))
22449  {
22450  free_and_init (ordered_names);
22451  pr_clear_value (pset_arg1);
22452  pr_clear_value (pset_arg2);
22453  goto exit_on_error;
22454  }
22455  pr_clear_value (pset_arg1);
22456  pr_clear_value (pset_arg2);
22457 
22458  if (setdomain->next != NULL)
22459  {
22460  pset_temp = pset_arg1;
22461  pset_arg1 = pset_result;
22462  pset_result = pset_temp;
22463  if ((db_string_concatenate (pset_arg1, &comma, pset_result, &data_stat) != NO_ERROR)
22464  || (data_stat != DATA_STATUS_OK))
22465  {
22466  free_and_init (ordered_names);
22467  pr_clear_value (pset_arg1);
22468  goto exit_on_error;
22469  }
22470  pr_clear_value (pset_arg1);
22471  }
22472  }
22473 
22474  pr_clone_value (pset_result, result);
22475  pr_clear_value (pset_result);
22476  free_and_init (ordered_names);
22477  return NO_ERROR;
22478  }
22479  else if (precision >= 0)
22480  {
22481  DB_VALUE db_int_scale, db_str_scale;
22482  DB_VALUE db_int_precision, db_str_precision;
22483  DB_VALUE prec_scale_result, prec_scale_arg1, *pprec_scale_arg1, *pprec_scale_result, *pprec_scale_temp;
22484  DB_VALUE comma, bracket1, bracket2;
22485  DB_DATA_STATUS data_stat;
22486 
22487  db_make_int (&db_int_precision, precision);
22488  db_make_null (&db_str_precision);
22489  if (tp_value_cast (&db_int_precision, &db_str_precision, &tp_String_domain, false) != DOMAIN_COMPATIBLE)
22490  {
22491  goto exit_on_error;
22492  }
22493  pprec_scale_arg1 = &prec_scale_arg1;
22494  pprec_scale_result = &prec_scale_result;
22495  db_make_string (&comma, ",");
22496  db_make_string (&bracket1, "(");
22497  db_make_string (&bracket2, ")");
22498  db_make_string (pprec_scale_arg1, name);
22499 
22500  if ((db_string_concatenate (pprec_scale_arg1, &bracket1, pprec_scale_result, &data_stat) != NO_ERROR)
22501  || (data_stat != DATA_STATUS_OK))
22502  {
22503  pr_clear_value (pprec_scale_arg1);
22504  goto exit_on_error;
22505  }
22506  pr_clear_value (pprec_scale_arg1);
22507 
22508  pprec_scale_temp = pprec_scale_arg1;
22509  pprec_scale_arg1 = pprec_scale_result;
22510  pprec_scale_result = pprec_scale_temp;
22511  if ((db_string_concatenate (pprec_scale_arg1, &db_str_precision, pprec_scale_result, &data_stat) != NO_ERROR)
22512  || (data_stat != DATA_STATUS_OK))
22513  {
22514  pr_clear_value (pprec_scale_arg1);
22515  goto exit_on_error;
22516  }
22517  pr_clear_value (&db_str_precision);
22518  pr_clear_value (pprec_scale_arg1);
22519 
22520  if (scale >= 0)
22521  {
22522  db_make_int (&db_int_scale, scale);
22523  db_make_null (&db_str_scale);
22524  if (tp_value_cast (&db_int_scale, &db_str_scale, &tp_String_domain, false) != DOMAIN_COMPATIBLE)
22525  {
22526  pr_clear_value (pprec_scale_result);
22527  goto exit_on_error;
22528  }
22529 
22530  pprec_scale_temp = pprec_scale_arg1;
22531  pprec_scale_arg1 = pprec_scale_result;
22532  pprec_scale_result = pprec_scale_temp;
22533  if ((db_string_concatenate (pprec_scale_arg1, &comma, pprec_scale_result, &data_stat) != NO_ERROR)
22534  || (data_stat != DATA_STATUS_OK))
22535  {
22536  pr_clear_value (pprec_scale_arg1);
22537  goto exit_on_error;
22538  }
22539  pr_clear_value (pprec_scale_arg1);
22540 
22541  pprec_scale_temp = pprec_scale_arg1;
22542  pprec_scale_arg1 = pprec_scale_result;
22543  pprec_scale_result = pprec_scale_temp;
22544  if ((db_string_concatenate (pprec_scale_arg1, &db_str_scale, pprec_scale_result, &data_stat) != NO_ERROR)
22545  || (data_stat != DATA_STATUS_OK))
22546  {
22547  pr_clear_value (pprec_scale_arg1);
22548  goto exit_on_error;
22549  }
22550  pr_clear_value (&db_str_scale);
22551  pr_clear_value (pprec_scale_arg1);
22552  }
22553 
22554  pprec_scale_temp = pprec_scale_arg1;
22555  pprec_scale_arg1 = pprec_scale_result;
22556  pprec_scale_result = pprec_scale_temp;
22557  if ((db_string_concatenate (pprec_scale_arg1, &bracket2, pprec_scale_result, &data_stat) != NO_ERROR)
22558  || (data_stat != DATA_STATUS_OK))
22559  {
22560  pr_clear_value (pprec_scale_arg1);
22561  goto exit_on_error;
22562  }
22563  pr_clear_value (pprec_scale_arg1);
22564 
22565  pr_clone_value (pprec_scale_result, result);
22566  pr_clear_value (pprec_scale_result);
22567 
22568  return NO_ERROR;
22569  }
22570  else if (validator != NULL)
22571  {
22572  DB_DATA_STATUS data_stat;
22573  DB_VALUE bracket1, bracket2, schema;
22574  bool err = false;
22575 
22576  if (db_json_get_schema_raw_from_validator (validator) != NULL)
22577  {
22578  db_make_string (result, name);
22580  db_make_string (&bracket1, "(\'");
22581  db_make_string (&bracket2, "\')");
22582 
22583  if (db_string_concatenate (result, &bracket1, result, &data_stat) != NO_ERROR
22584  || (data_stat != DATA_STATUS_OK)
22585  || db_string_concatenate (result, &schema, result, &data_stat) != NO_ERROR
22586  || (data_stat != DATA_STATUS_OK)
22587  || db_string_concatenate (result, &bracket2, result, &data_stat) != NO_ERROR
22588  || (data_stat != DATA_STATUS_OK))
22589  {
22590  err = true;
22591  }
22592 
22593  pr_clear_value (&schema);
22594 
22595  if (err)
22596  {
22597  pr_clear_value (result);
22598  goto exit_on_error;
22599  }
22600  }
22601  return NO_ERROR;
22602  }
22603  else
22604  {
22605  db_make_string (result, name);
22606  return NO_ERROR;
22607  }
22608 
22609 exit_on_error:
22610  return ER_FAILED;
22611 }
22612 
22613 /*
22614  * qexec_execute_build_columns () - Execution function for BUILD SCHEMA proc
22615  * return: NO_ERROR, or ER_code
22616  * xasl(in): XASL tree
22617  * xasl_state(in): XASL state
22618  */
22619 static int
22621 {
22622  QFILE_TUPLE_RECORD tplrec = { NULL, 0 };
22623  int idx_incache = -1;
22624  OR_CLASSREP *rep = NULL;
22625  OR_INDEX *index = NULL;
22626  char *attr_name = NULL, *default_value_string = NULL;
22627  const char *default_expr_type_string = NULL, *default_expr_format = NULL;
22628  char *attr_comment = NULL;
22629  OR_ATTRIBUTE *volatile attrepr = NULL;
22630  DB_VALUE **out_values = NULL;
22631  REGU_VARIABLE_LIST regu_var_p;
22632  HEAP_SCANCACHE scan;
22633  bool scancache_inited = false;
22634  RECDES class_record;
22635  OID *class_oid = NULL;
22636  volatile int idx_val;
22637  volatile int error = NO_ERROR;
22638  int i, j, k, idx_all_attr, size_values, found_index_type = -1;
22639  bool search_index_type = true;
22640  BTID *btid;
22641  int index_type_priorities[] = { 1, 0, 1, 0, 2, 0 };
22642  int index_type_max_priority = 2;
22643  DB_VALUE def_order, attr_class_type;
22644  OR_ATTRIBUTE *all_class_attr[3];
22645  int all_class_attr_lengths[3];
22646  bool full_columns = false;
22647  char *string = NULL;
22648  int alloced_string = 0;
22649  HL_HEAPID save_heapid = 0;
22650 
22651  if (xasl == NULL || xasl_state == NULL)
22652  {
22653  return ER_FAILED;
22654  }
22655 
22656  for (regu_var_p = xasl->outptr_list->valptrp, i = 0; regu_var_p; regu_var_p = regu_var_p->next, i++)
22657  {
22659  {
22660  save_heapid = db_change_private_heap (thread_p, 0);
22661  break;
22662  }
22663  }
22664 
22665  if (qexec_start_mainblock_iterations (thread_p, xasl, xasl_state) != NO_ERROR)
22666  {
22668  }
22669 
22670  heap_scancache_quick_start_root_hfid (thread_p, &scan);
22671  scancache_inited = true;
22672 
22673  assert (xasl_state != NULL);
22674  class_oid = &(xasl->spec_list->s.cls_node.cls_oid);
22675 
22676  if (heap_get_class_record (thread_p, class_oid, &class_record, &scan, PEEK) != S_SUCCESS)
22677  {
22679  }
22680 
22681  rep = heap_classrepr_get (thread_p, class_oid, &class_record, NULL_REPRID, &idx_incache);
22682  if (rep == NULL)
22683  {
22685  }
22686 
22687  size_values = xasl->outptr_list->valptr_cnt;
22688  out_values = (DB_VALUE **) malloc (size_values * sizeof (DB_VALUE *));
22689  if (out_values == NULL)
22690  {
22692  }
22693 
22694  for (regu_var_p = xasl->outptr_list->valptrp, i = 0; regu_var_p; regu_var_p = regu_var_p->next, i++)
22695  {
22696  out_values[i] = &(regu_var_p->value.value.dbval);
22697  pr_clear_value (out_values[i]);
22698  }
22699 
22700  all_class_attr[0] = rep->attributes;
22701  all_class_attr_lengths[0] = rep->n_attributes;
22702  all_class_attr[1] = rep->class_attrs;
22703  all_class_attr_lengths[1] = rep->n_class_attrs;
22704  all_class_attr[2] = rep->shared_attrs;
22705  all_class_attr_lengths[2] = rep->n_shared_attrs;
22706 
22708  {
22709  full_columns = true;
22710  }
22711 
22712  for (idx_all_attr = 0; idx_all_attr < 3; idx_all_attr++)
22713  {
22714  /* attribute class type */
22715  db_make_int (&attr_class_type, idx_all_attr);
22716  error = db_value_coerce (&attr_class_type, out_values[0], db_type_to_db_domain (DB_TYPE_VARCHAR));
22717  if (error != NO_ERROR)
22718  {
22720  }
22721 
22722  for (i = 0, attrepr = all_class_attr[idx_all_attr]; i < all_class_attr_lengths[idx_all_attr]; i++, attrepr++)
22723  {
22724  idx_val = 1;
22725  /* attribute def order */
22726  db_make_int (&def_order, attrepr->def_order);
22727  error = db_value_coerce (&def_order, out_values[idx_val++], db_type_to_db_domain (DB_TYPE_VARCHAR));
22728  if (error != NO_ERROR)
22729  {
22731  }
22732 
22733  /* attribute name */
22734  string = NULL;
22735  alloced_string = 0;
22736 
22737  error = or_get_attrname (&class_record, attrepr->id, &string, &alloced_string);
22738  if (error != NO_ERROR)
22739  {
22740  ASSERT_ERROR ();
22742  }
22743 
22744  attr_name = string;
22745  db_make_string (out_values[idx_val], attr_name);
22746  if (string != NULL && alloced_string == 1)
22747  {
22748  out_values[idx_val]->need_clear = true;
22749  }
22750  idx_val++;
22751 
22752  /* attribute type */
22753  (void) qexec_schema_get_type_desc (attrepr->type, attrepr->domain, out_values[idx_val++]);
22754 
22755  /* collation */
22756  if (full_columns)
22757  {
22758  switch (attrepr->type)
22759  {
22760  case DB_TYPE_VARCHAR:
22761  case DB_TYPE_CHAR:
22762  case DB_TYPE_NCHAR:
22763  case DB_TYPE_VARNCHAR:
22764  case DB_TYPE_ENUMERATION:
22765  db_make_string (out_values[idx_val], lang_get_collation_name (attrepr->domain->collation_id));
22766  break;
22767  default:
22768  db_make_null (out_values[idx_val]);
22769  }
22770  idx_val++;
22771  }
22772 
22773  /* attribute can store NULL ? */
22774  if (attrepr->is_notnull == 0)
22775  {
22776  db_make_string (out_values[idx_val], "YES");
22777  }
22778  else
22779  {
22780  db_make_string (out_values[idx_val], "NO");
22781  }
22782  idx_val++;
22783 
22784  /* attribute has index or not */
22785  found_index_type = -1;
22786  search_index_type = true;
22787  for (j = 0; j < attrepr->n_btids && search_index_type; j++)
22788  {
22789  btid = attrepr->btids + j;
22790 
22791  for (k = 0; k < rep->n_indexes; k++)
22792  {
22793  index = rep->indexes + k;
22794  if (BTID_IS_EQUAL (btid, &index->btid))
22795  {
22796  if (found_index_type == -1
22797  || index_type_priorities[index->type] > index_type_priorities[found_index_type])
22798  {
22799  found_index_type = index->type;
22800  if (index_type_priorities[found_index_type] == index_type_max_priority)
22801  {
22802  /* stop searching */
22803  search_index_type = false;
22804  }
22805  }
22806  break;
22807  }
22808  }
22809  }
22810 
22811  switch (found_index_type)
22812  {
22813  case BTREE_UNIQUE:
22814  case BTREE_REVERSE_UNIQUE:
22815  db_make_string (out_values[idx_val], "UNI");
22816  break;
22817 
22818  case BTREE_INDEX:
22819  case BTREE_REVERSE_INDEX:
22820  case BTREE_FOREIGN_KEY:
22821  db_make_string (out_values[idx_val], "MUL");
22822  break;
22823 
22824  case BTREE_PRIMARY_KEY:
22825  db_make_string (out_values[idx_val], "PRI");
22826  break;
22827 
22828  default:
22829  db_make_string (out_values[idx_val], "");
22830  break;
22831  }
22832  idx_val++;
22833 
22834  /* default values */
22835  alloced_string = 0;
22837  {
22838  const char *default_expr_op_string = NULL;
22839 
22840  default_expr_type_string =
22842 
22844  {
22845  size_t len;
22846 
22847  default_expr_op_string = qdump_operator_type_string (T_TO_CHAR);
22848  default_expr_format = attrepr->default_value.default_expr.default_expr_format;
22849 
22850  len = ((default_expr_op_string ? strlen (default_expr_op_string) : 0)
22851  + 6 /* parenthesis, a comma, a blank and quotes */ + strlen (default_expr_type_string)
22852  + (default_expr_format ? strlen (default_expr_format) : 0));
22853 
22854  default_value_string = (char *) malloc (len + 1);
22855  if (default_value_string == NULL)
22856  {
22858  }
22859 
22860  strcpy (default_value_string, default_expr_op_string);
22861  strcat (default_value_string, "(");
22862  strcat (default_value_string, default_expr_type_string);
22863  if (default_expr_format)
22864  {
22865  strcat (default_value_string, ", \'");
22866  strcat (default_value_string, default_expr_format);
22867  strcat (default_value_string, "\'");
22868  }
22869 
22870  strcat (default_value_string, ")");
22871 
22872  db_make_string (out_values[idx_val], default_value_string);
22873  out_values[idx_val]->need_clear = true;
22874  }
22875  else
22876  {
22877  if (default_expr_type_string)
22878  {
22879  db_make_string (out_values[idx_val], default_expr_type_string);
22880  }
22881  }
22882  idx_val++;
22883  }
22884  else if (attrepr->current_default_value.value == NULL || attrepr->current_default_value.val_length <= 0)
22885  {
22886  db_make_null (out_values[idx_val]);
22887  idx_val++;
22888  }
22889  else
22890  {
22891  error = qexec_get_attr_default (thread_p, attrepr, out_values[idx_val]);
22892  if (error != NO_ERROR)
22893  {
22895  }
22896  if (!DB_IS_NULL (out_values[idx_val]))
22897  {
22898  valcnv_convert_value_to_string (out_values[idx_val]);
22899  }
22900  idx_val++;
22901  }
22902 
22903  /* attribute has auto_increment or not */
22904  if (attrepr->is_autoincrement == 0)
22905  {
22906  db_make_string (out_values[idx_val], "");
22907  }
22908  else
22909  {
22910  db_make_string (out_values[idx_val], "auto_increment");
22911  }
22912 
22913  if (attrepr->on_update_expr != DB_DEFAULT_NONE)
22914  {
22915  const char *saved = db_get_string (out_values[idx_val]);
22916  size_t len = strlen (saved);
22917 
22918  const char *default_expr_op_string = db_default_expression_string (attrepr->on_update_expr);
22919  if (default_expr_op_string == NULL)
22920  {
22922  }
22923 
22924  /* add whitespace character if saved is not an empty string */
22925  const char *on_update_string = "ON UPDATE ";
22926  size_t str_len = len + strlen (on_update_string) + strlen (default_expr_op_string) + 1;
22927  if (len != 0)
22928  {
22929  str_len += 1; // append space before
22930  }
22931  char *str_val = (char *) db_private_alloc (thread_p, str_len);
22932 
22933  if (str_val == NULL)
22934  {
22936  }
22937 
22938  strcpy (str_val, saved);
22939  if (len != 0)
22940  {
22941  strcat (str_val, " ");
22942  }
22943  strcat (str_val, on_update_string);
22944  strcat (str_val, default_expr_op_string);
22945 
22946  if (default_expr_op_string)
22947  {
22948  pr_clear_value (out_values[idx_val]);
22949  db_make_string (out_values[idx_val], str_val);
22950  out_values[idx_val]->need_clear = true;
22951  }
22952  }
22953  idx_val++;
22954 
22955  /* attribute's comment */
22956  if (full_columns)
22957  {
22958  int alloced_string = 0;
22959  char *string = NULL;
22960 
22961  error = or_get_attrcomment (&class_record, attrepr->id, &string, &alloced_string);
22962  if (error != NO_ERROR)
22963  {
22964  ASSERT_ERROR ();
22965  return error;
22966  }
22967 
22968  attr_comment = string;
22969  db_make_string (out_values[idx_val], attr_comment);
22970  if (string != NULL && alloced_string == 1)
22971  {
22972  out_values[idx_val]->need_clear = true;
22973  }
22974  idx_val++;
22975  }
22976 
22977  qexec_end_one_iteration (thread_p, xasl, xasl_state, &tplrec);
22978 
22979  for (j = 1; j < size_values; j++)
22980  {
22981  pr_clear_value (out_values[j]);
22982  }
22983  }
22984  pr_clear_value (out_values[0]);
22985  }
22986 
22987  free_and_init (out_values);
22988 
22989  heap_classrepr_free_and_init (rep, &idx_incache);
22990  if (heap_scancache_end (thread_p, &scan) != NO_ERROR)
22991  {
22993  }
22994  scancache_inited = false;
22995 
22996  if (qexec_end_mainblock_iterations (thread_p, xasl, xasl_state, &tplrec) != NO_ERROR)
22997  {
22999  }
23000 
23001  if (tplrec.tpl)
23002  {
23003  db_private_free_and_init (thread_p, tplrec.tpl);
23004  }
23005 
23006  if (save_heapid != 0)
23007  {
23008  (void) db_change_private_heap (thread_p, save_heapid);
23009  save_heapid = 0;
23010  }
23011 
23012  return NO_ERROR;
23013 
23014 exit_on_error:
23015 
23016  if (out_values)
23017  {
23018  for (i = 0; i < size_values; i++)
23019  {
23020  pr_clear_value (out_values[i]);
23021  }
23022 
23023  free_and_init (out_values);
23024  }
23025 
23026  if (rep)
23027  {
23028  heap_classrepr_free_and_init (rep, &idx_incache);
23029  }
23030 
23031  if (scancache_inited)
23032  {
23033  heap_scancache_end (thread_p, &scan);
23034  }
23035 
23036 #if defined(SERVER_MODE)
23037  /* query execution error must be set up before qfile_close_list(). */
23038  if (er_errid () < 0)
23039  {
23040  qmgr_set_query_error (thread_p, xasl_state->query_id);
23041  }
23042 #endif
23043 
23044  qfile_close_list (thread_p, xasl->list_id);
23045 
23046  if (tplrec.tpl)
23047  {
23048  db_private_free_and_init (thread_p, tplrec.tpl);
23049  }
23050 
23051  if (save_heapid != 0)
23052  {
23053  (void) db_change_private_heap (thread_p, save_heapid);
23054  save_heapid = 0;
23055  }
23056 
23057  xasl->status = XASL_FAILURE;
23058 
23059  qexec_failure_line (__LINE__, xasl_state);
23060 
23061  return (error == NO_ERROR && (error = er_errid ()) == NO_ERROR) ? ER_FAILED : error;
23062 }
23063 
23064 /*
23065  * qexec_create_internal_classes () - create internal classes used for
23066  * internal update / delete execution
23067  * return : error code or NO_ERROR
23068  * thread_p (in) :
23069  * query_classes (in): query classes
23070  * count (in) : number of query classes
23071  * internal_classes (in/out) : internal classes array
23072  */
23073 static int
23076 {
23077  UPDDEL_CLASS_INFO_INTERNAL *class_ = NULL, *classes = NULL;
23078  UPDDEL_CLASS_INFO *query_class = NULL;
23079  size_t size;
23080  int i = 0, error = NO_ERROR;
23081 
23082  if (internal_classes == NULL)
23083  {
23084  assert (false);
23085  return ER_FAILED;
23086  }
23087  *internal_classes = NULL;
23088 
23089  size = count * sizeof (UPDDEL_CLASS_INFO_INTERNAL);
23090  classes = (UPDDEL_CLASS_INFO_INTERNAL *) db_private_alloc (thread_p, size);
23091  if (classes == NULL)
23092  {
23093  return ER_FAILED;
23094  }
23095 
23096  /* initialize internal structures */
23097  for (i = 0; i < count; i++)
23098  {
23099  query_class = query_classes + i;
23100  class_ = &(classes[i]);
23101  class_->oid = NULL;
23102  class_->class_hfid = NULL;
23103  class_->class_oid = NULL;
23105  class_->subclass_idx = -1;
23106  class_->scan_cache = NULL;
23107  OID_SET_NULL (&class_->prev_class_oid);
23108  class_->is_attr_info_inited = 0;
23109 
23110  class_->num_lob_attrs = 0;
23111  class_->lob_attr_ids = NULL;
23112  class_->crt_del_lob_info = NULL;
23113  class_->m_unique_stats.construct ();
23114  class_->extra_assign_reev_cnt = 0;
23115  class_->mvcc_extra_assign_reev = NULL;
23116  class_->mvcc_reev_assigns = NULL;
23117 
23119 
23120  class_->m_inited_scancache = false;
23121 
23122  if (query_class->needs_pruning)
23123  {
23124  /* set partition information here */
23125  class_->needs_pruning = query_class->needs_pruning;
23126  error =
23127  partition_load_pruning_context (thread_p, &query_class->class_oid[0], class_->needs_pruning,
23128  &class_->context);
23129  if (error != NO_ERROR)
23130  {
23131  goto exit_on_error;
23132  }
23133  }
23134  }
23135 
23136  *internal_classes = classes;
23137 
23138  return NO_ERROR;
23139 
23140 exit_on_error:
23141  if (classes)
23142  {
23143  qexec_clear_internal_classes (thread_p, classes, i + 1);
23144  db_private_free (thread_p, classes);
23145  }
23146 
23147  return (error == NO_ERROR) ? NO_ERROR : er_errid ();
23148 
23149 }
23150 
23151 /*
23152  * qexec_create_internal_assignments () - create and initialize structures for
23153  * MVCC assignments reevaluation
23154  * return : error code or NO_ERROR
23155  * thread_p (in) :
23156  * aptr (in): XASL for generated SELECT statement for UPDATE
23157  * should_delete (in):
23158  * classes (in) : internal classes array
23159  * num_classes (in) : count internal classes array elements
23160  * num_assignments (in) : no of assignments
23161  * assignments(in): array of assignments received from client
23162  * mvcc_reev_assigns (in/out) : allocated array of assignments used in
23163  * reevaluation
23164  */
23165 static int
23166 qexec_create_mvcc_reev_assignments (THREAD_ENTRY * thread_p, XASL_NODE * aptr, bool should_delete,
23167  UPDDEL_CLASS_INFO_INTERNAL * classes, int num_classes, int num_assignments,
23168  UPDATE_ASSIGNMENT * assignments, UPDATE_MVCC_REEV_ASSIGNMENT ** mvcc_reev_assigns)
23169 {
23170  int idx, new_assign_idx, count;
23172  UPDATE_ASSIGNMENT *assign = NULL;
23173  UPDATE_MVCC_REEV_ASSIGNMENT *new_assigns = NULL, *new_assign = NULL, *prev_new_assign = NULL;
23174  REGU_VARIABLE_LIST regu_var = NULL;
23175  OUTPTR_LIST *outptr_list = NULL;
23176 
23177  if (mvcc_reev_assigns == NULL || !num_assignments)
23178  {
23179  return NO_ERROR;
23180  }
23181 
23182  outptr_list = aptr->outptr_list;
23183 
23184  count = aptr->upd_del_class_cnt + aptr->mvcc_reev_extra_cls_cnt;
23185  /* skip OID - CLASS OID pairs and should_delete */
23186  for (idx = 0, regu_var = outptr_list->valptrp; idx < count; idx++, regu_var = regu_var->next->next)
23187  ;
23188 
23189  if (should_delete)
23190  {
23191  regu_var = regu_var->next;
23192  }
23193 
23194  new_assigns =
23195  (UPDATE_MVCC_REEV_ASSIGNMENT *) db_private_alloc (thread_p, sizeof (UPDATE_MVCC_REEV_ASSIGNMENT) * num_assignments);
23196  if (new_assigns == NULL)
23197  {
23198  return ER_FAILED;
23199  }
23200 
23201  for (idx = 0, new_assign_idx = 0; idx < num_assignments; idx++)
23202  {
23203  assign = &assignments[idx];
23204  claz = &classes[assign->cls_idx];
23205 
23206  new_assign = &new_assigns[new_assign_idx++];
23207  new_assign->constant = assign->constant;
23208  if (new_assign->constant == NULL)
23209  {
23210  new_assign->regu_right = &regu_var->value;
23211  regu_var = regu_var->next;
23212  }
23213  else
23214  {
23215  new_assign->regu_right = NULL;
23216  }
23217  new_assign->next = NULL;
23218  if (claz->mvcc_reev_assigns == NULL)
23219  {
23220  claz->mvcc_reev_assigns = new_assign;
23221  }
23222  else
23223  {
23224  prev_new_assign = claz->mvcc_reev_assigns;
23225  while (prev_new_assign->next != NULL)
23226  {
23227  prev_new_assign = prev_new_assign->next;
23228  }
23229  prev_new_assign->next = new_assign;
23230  }
23231  }
23232 
23233  *mvcc_reev_assigns = new_assigns;
23234 
23235  return NO_ERROR;
23236 }
23237 
23238 /*
23239  * qexec_clear_internal_classes () - clear memory allocated for classes
23240  * return : void
23241  * thread_p (in) :
23242  * classes (in) : classes array
23243  * count (in) : number of elements in the array
23244  */
23245 static void
23247 {
23248  int i;
23249  UPDDEL_CLASS_INFO_INTERNAL *cls_int = NULL;
23250 
23251  for (i = 0; i < count; i++)
23252  {
23253  cls_int = &classes[i];
23254  if (cls_int->m_inited_scancache)
23255  {
23256  locator_end_force_scan_cache (thread_p, &cls_int->m_scancache);
23257  }
23258  cls_int->m_unique_stats.clear ();
23259  if (cls_int->is_attr_info_inited)
23260  {
23261  heap_attrinfo_end (thread_p, &cls_int->attr_info);
23262  }
23263  if (cls_int->needs_pruning)
23264  {
23266  }
23267  if (cls_int->mvcc_extra_assign_reev != NULL)
23268  {
23269  db_private_free_and_init (thread_p, cls_int->mvcc_extra_assign_reev);
23270  }
23271  cls_int->m_unique_stats.destruct ();
23272  }
23273 }
23274 
23275 /*
23276  * qexec_upddel_mvcc_set_filters () - setup current class filters
23277  * in a class hierarchy
23278  * return : error code or NO_ERROR
23279  * thread_p (in) :
23280  * aptr_list (in) :
23281  * mvcc_data_filter (in) : filter info
23282  * class_oid (in) : class oid
23283  *
23284  * Note: this function is used only in MVCC
23285  */
23286 static int
23288  UPDDEL_MVCC_COND_REEVAL * mvcc_reev_class, OID * class_oid)
23289 {
23290  ACCESS_SPEC_TYPE *curr_spec = NULL;
23291 
23292  while (aptr_list != NULL && curr_spec == NULL)
23293  {
23294  curr_spec = aptr_list->spec_list;
23295  while (curr_spec != NULL && !OID_EQ (&(curr_spec->s.cls_node.cls_oid), class_oid))
23296  {
23297  curr_spec = curr_spec->next;
23298  }
23299  aptr_list = aptr_list->scan_ptr;
23300  }
23301 
23302  if (curr_spec == NULL)
23303  {
23304  return ER_FAILED;
23305  }
23306 
23307  mvcc_reev_class->init (curr_spec->s_id);
23308  mvcc_reev_class->cls_oid = *class_oid;
23309 
23310  return NO_ERROR;
23311 }
23312 
23313 /*
23314  * qexec_upddel_setup_current_class () - setup current class info in a class
23315  * hierarchy
23316  * return : error code or NO_ERROR
23317  * thread_p (in) :
23318  * query_class (in) : query class information
23319  * internal_class (in) : internal class
23320  * op_type (in) : operation type
23321  * current_oid (in): class oid
23322  *
23323  * Note: this function is used for update and delete to find class hfid when
23324  * the operation is performed on a class hierarchy
23325  */
23326 static int
23328  UPDDEL_CLASS_INFO_INTERNAL * internal_class, int op_type, OID * current_oid)
23329 {
23330  int i = 0;
23331  int error = NO_ERROR;
23332 
23333  internal_class->class_oid = NULL;
23334  internal_class->class_hfid = NULL;
23335 
23336  /* Find class HFID */
23337  if (internal_class->needs_pruning)
23338  {
23339  /* test root class */
23340  if (OID_EQ (&query_class->class_oid[0], current_oid))
23341  {
23342  internal_class->class_oid = &query_class->class_oid[0];
23343  internal_class->class_hfid = &query_class->class_hfid[0];
23344  internal_class->subclass_idx = 0;
23345 
23346  internal_class->num_lob_attrs = 0;
23347  internal_class->lob_attr_ids = NULL;
23348  }
23349  else
23350  {
23351  /* look through the class partitions for the current_oid */
23352  for (i = 0; i < internal_class->context.count; i++)
23353  {
23354  if (OID_EQ (&internal_class->context.partitions[i].class_oid, current_oid))
23355  {
23356  internal_class->class_oid = &internal_class->context.partitions[i].class_oid;
23357  internal_class->class_hfid = &internal_class->context.partitions[i].class_hfid;
23358  internal_class->subclass_idx = 0;
23359 
23360  internal_class->num_lob_attrs = 0;
23361  internal_class->lob_attr_ids = NULL;
23362  break;
23363  }
23364  }
23365  }
23366  }
23367  else
23368  {
23369  /* look through subclasses */
23370  for (i = 0; i < query_class->num_subclasses; i++)
23371  {
23372  if (OID_EQ (&query_class->class_oid[i], current_oid))
23373  {
23374  internal_class->class_oid = &query_class->class_oid[i];
23375  internal_class->class_hfid = &query_class->class_hfid[i];
23376  internal_class->subclass_idx = i;
23377 
23378  if (query_class->num_lob_attrs && query_class->lob_attr_ids)
23379  {
23380  internal_class->num_lob_attrs = query_class->num_lob_attrs[i];
23381  internal_class->lob_attr_ids = query_class->lob_attr_ids[i];
23382  }
23383  else
23384  {
23385  internal_class->num_lob_attrs = 0;
23386  internal_class->lob_attr_ids = NULL;
23387  }
23388  break;
23389  }
23390  }
23391  }
23392 
23393  if (internal_class->class_hfid == NULL)
23394  {
23395  return ER_FAILED;
23396  }
23397 
23398  /* Start a HEAP_SCANCACHE object on the new class. Partitioned classes and class hierarchies are handled differently */
23399  if (internal_class->needs_pruning)
23400  {
23401  /* Get a scan_cache object from the pruning context. We don't close the previous one here, it will be closed when
23402  * the pruning context is cleared. */
23403  PRUNING_SCAN_CACHE *pcache = NULL;
23404  pcache =
23405  locator_get_partition_scancache (&internal_class->context, internal_class->class_oid,
23406  internal_class->class_hfid, op_type, false);
23407  if (pcache == NULL)
23408  {
23409  return ER_FAILED;
23410  }
23411  internal_class->scan_cache = &pcache->scan_cache;
23412  }
23413  else
23414  {
23415  if (internal_class->m_inited_scancache)
23416  {
23417  if (query_class->has_uniques && BTREE_IS_MULTI_ROW_OP (op_type))
23418  {
23419  /* In this case, consider class hierarchy as well as single class. Therefore, construct the local
23420  * statistical information by collecting the statistical information during scanning on each class of
23421  * class hierarchy. */
23422  qexec_update_btree_unique_stats_info (thread_p, &internal_class->m_unique_stats,
23423  &internal_class->m_scancache);
23424  }
23425  (void) locator_end_force_scan_cache (thread_p, &internal_class->m_scancache);
23426  internal_class->m_inited_scancache = false;
23427  }
23428  error =
23429  locator_start_force_scan_cache (thread_p, &internal_class->m_scancache, internal_class->class_hfid,
23430  internal_class->class_oid, op_type);
23431  if (error != NO_ERROR)
23432  {
23433  return error;
23434  }
23435  internal_class->m_inited_scancache = true;
23436  internal_class->scan_cache = &internal_class->m_scancache;
23437  internal_class->scan_cache->mvcc_snapshot = logtb_get_mvcc_snapshot (thread_p);
23438 
23439  }
23440  COPY_OID (&internal_class->prev_class_oid, current_oid);
23441 
23442  return NO_ERROR;
23443 }
23444 
23445 /*
23446  * qexec_execute_merge () - Execution function for MERGE proc
23447  * return: NO_ERROR, or ER_code
23448  * xasl(in): XASL tree
23449  * xasl_state(in): XASL state
23450  */
23451 static int
23453 {
23454  int error = NO_ERROR;
23455  int savepoint_used = 0;
23456  LOG_LSA lsa;
23457 
23458  /* start a topop */
23459  error = xtran_server_start_topop (thread_p, &lsa);
23460  if (error != NO_ERROR)
23461  {
23463  }
23464  savepoint_used = 1;
23465 
23466  /* execute insert aptr */
23467  if (xasl->proc.merge.insert_xasl)
23468  {
23469  XASL_NODE *xptr = xasl->proc.merge.insert_xasl;
23470  if (xptr && xptr->aptr_list)
23471  {
23472  error = qexec_execute_mainblock (thread_p, xptr->aptr_list, xasl_state, NULL);
23473  }
23474  }
23475  /* execute update */
23476  if (error == NO_ERROR && xasl->proc.merge.update_xasl)
23477  {
23478  error = qexec_execute_update (thread_p, xasl->proc.merge.update_xasl, xasl->proc.merge.has_delete, xasl_state);
23479  }
23480  /* execute insert */
23481  if (error == NO_ERROR && xasl->proc.merge.insert_xasl)
23482  {
23483  error = qexec_execute_insert (thread_p, xasl->proc.merge.insert_xasl, xasl_state, true);
23484  }
23485 
23486  /* check error */
23487  if (error != NO_ERROR)
23488  {
23490  }
23491 
23492  /* setup list file for result count */
23493  error = qexec_setup_list_id (thread_p, xasl);
23494  if (error != NO_ERROR)
23495  {
23497  }
23498 
23499  xasl->list_id->tuple_cnt = 0;
23500 
23501  /* set result count */
23502  if (xasl->proc.merge.update_xasl)
23503  {
23505  /* monitor */
23507  }
23508 
23509  if (xasl->proc.merge.insert_xasl)
23510  {
23512  /* monitor */
23514  }
23515 
23516  /* end topop */
23518  {
23520  }
23521 
23522  return NO_ERROR;
23523 
23524 exit_on_error:
23525 
23526  if (savepoint_used)
23527  {
23529  }
23530 
23531  return error;
23532 }
23533 
23534 /*
23535  * qexec_init_agg_hierarchy_helpers () - initialize aggregate helpers for
23536  * evaluating aggregates in a class
23537  * hierarchy
23538  * return : error code or NO_ERROR
23539  * thread_p (in) : thread entry
23540  * spec (in) : spec on which the aggregates are to be evaluated
23541  * aggregate_list (in) : aggregates
23542  * helpersp (in/out) : evaluation helpers
23543  */
23544 static int
23546  HIERARCHY_AGGREGATE_HELPER ** helpersp, int *helpers_countp)
23547 {
23548  int agg_count = 0, part_count = 0, i;
23549  AGGREGATE_TYPE *agg = NULL;
23550  HIERARCHY_AGGREGATE_HELPER *helpers = NULL;
23551  PRUNING_CONTEXT context;
23552  int error = NO_ERROR;
23553  PARTITION_SPEC_TYPE *part = NULL;
23554 
23555  /* count aggregates */
23556  agg = aggregate_list;
23557  agg_count = 0;
23558  while (agg)
23559  {
23560  if (!agg->flag_agg_optimize)
23561  {
23562  agg = agg->next;
23563  continue;
23564  }
23565  agg = agg->next;
23566  agg_count++;
23567  }
23568 
23569  if (agg_count == 0)
23570  {
23571  *helpersp = NULL;
23572  *helpers_countp = 0;
23573  return NO_ERROR;
23574  }
23575 
23576  partition_init_pruning_context (&context);
23577 
23578  helpers = (HIERARCHY_AGGREGATE_HELPER *) db_private_alloc (thread_p, agg_count * sizeof (HIERARCHY_AGGREGATE_HELPER));
23579  if (helpers == NULL)
23580  {
23582  agg_count * sizeof (HIERARCHY_AGGREGATE_HELPER));
23583  error = ER_OUT_OF_VIRTUAL_MEMORY;
23584  goto error_return;
23585  }
23586 
23587  for (i = 0; i < agg_count; i++)
23588  {
23589  helpers[i].btids = NULL;
23590  helpers[i].hfids = NULL;
23591  }
23592 
23593  /* count pruned partitions */
23594  for (part_count = 0, part = spec->parts; part != NULL; part_count++, part = part->next);
23595  if (part_count == 0)
23596  {
23597  error = NO_ERROR;
23598  goto error_return;
23599  }
23600 
23601  error = partition_load_pruning_context (thread_p, &ACCESS_SPEC_CLS_OID (spec), spec->pruning_type, &context);
23602  if (error != NO_ERROR)
23603  {
23604  goto error_return;
23605  }
23606 
23607  agg = aggregate_list;
23608  i = 0;
23609  while (agg != NULL)
23610  {
23611  if (!agg->flag_agg_optimize)
23612  {
23613  agg = agg->next;
23614  continue;
23615  }
23616  error = partition_load_aggregate_helper (&context, spec, part_count, &agg->btid, &helpers[i]);
23617  if (error != NO_ERROR)
23618  {
23619  goto error_return;
23620  }
23621  agg = agg->next;
23622  i++;
23623  }
23624 
23626  *helpersp = helpers;
23627  *helpers_countp = agg_count;
23628  return NO_ERROR;
23629 
23630 error_return:
23631  if (helpers != NULL)
23632  {
23633  for (i = 0; i < agg_count; i++)
23634  {
23635  if (helpers[i].btids != NULL)
23636  {
23637  db_private_free (thread_p, helpers[i].btids);
23638  }
23639  if (helpers[i].hfids != NULL)
23640  {
23641  db_private_free (thread_p, helpers[i].hfids);
23642  }
23643  }
23644  db_private_free (thread_p, helpers);
23645  }
23646 
23648 
23649  *helpersp = NULL;
23650  *helpers_countp = 0;
23651  return error;
23652 }
23653 
23654 /*
23655  * qexec_evaluate_partition_aggregates () - optimized aggregate evaluation
23656  * on a partitioned class
23657  * return : error code or NO_ERROR
23658  * thread_p (in) : thread entry
23659  * spec (in) : access spec of the partitioned class
23660  * agg_list (in) : aggregate list
23661  * is_scan_needed (in/out) : whether or not scan is still needed after
23662  * evaluation
23663  */
23664 static int
23666  bool * is_scan_needed)
23667 {
23668  int error = NO_ERROR;
23669  int i = 0, helpers_count = 0;
23670  HIERARCHY_AGGREGATE_HELPER *helpers = NULL;
23671  AGGREGATE_TYPE *agg_ptr = NULL;
23672  BTID root_btid;
23673  error = qexec_init_agg_hierarchy_helpers (thread_p, spec, agg_list, &helpers, &helpers_count);
23674  if (error != NO_ERROR)
23675  {
23676  *is_scan_needed = true;
23677  goto cleanup;
23678  }
23679  i = 0;
23680  for (agg_ptr = agg_list; agg_ptr; agg_ptr = agg_ptr->next)
23681  {
23682  if (!agg_ptr->flag_agg_optimize)
23683  {
23684  continue;
23685  }
23686 
23687  if (agg_ptr->function == PT_COUNT_STAR && *is_scan_needed)
23688  {
23689  agg_ptr->flag_agg_optimize = false;
23690  i++;
23691  continue;
23692  }
23693  BTID_COPY (&root_btid, &agg_ptr->btid);
23694  error = qdata_evaluate_aggregate_hierarchy (thread_p, agg_ptr, &ACCESS_SPEC_HFID (spec), &root_btid, &helpers[i]);
23695  if (error != NO_ERROR)
23696  {
23697  agg_ptr->flag_agg_optimize = false;
23698  *is_scan_needed = true;
23699  goto cleanup;
23700  }
23701  i++;
23702  }
23703 
23704 cleanup:
23705  if (helpers != NULL)
23706  {
23707  for (i = 0; i < helpers_count; i++)
23708  {
23709  if (helpers[i].btids != NULL)
23710  {
23711  db_private_free (thread_p, helpers[i].btids);
23712  }
23713  if (helpers[i].hfids != NULL)
23714  {
23715  db_private_free (thread_p, helpers[i].hfids);
23716  }
23717  }
23718  db_private_free (thread_p, helpers);
23719  }
23720  return error;
23721 }
23722 
23723 /*
23724  * qexec_evaluate_aggregates_optimize () - optimize aggregate evaluation
23725  * return : error code or NO_ERROR
23726  * thread_p (in) : thread entry
23727  * agg_list (in) : aggregate list to be evaluated
23728  * spec (in) : access spec
23729  * is_scan_needed (in/out) : true if scan is still needed after evaluation
23730  */
23731 static int
23733  bool * is_scan_needed)
23734 {
23735  AGGREGATE_TYPE *agg_ptr;
23736  int error = NO_ERROR;
23737  OID super_oid;
23738 
23739  OID_SET_NULL (&super_oid);
23740 
23741  for (agg_ptr = agg_list; agg_ptr; agg_ptr = agg_ptr->next)
23742  {
23743  if (!agg_ptr->flag_agg_optimize)
23744  {
23745  /* scan is needed for this aggregate */
23746  *is_scan_needed = true;
23747  break;
23748  }
23749 
23750  /* Temporary disable count optimization. To enable it just remove these lines and also restore the condition in
23751  * pt_find_lck_classes and also enable load global statistics in logtb_get_mvcc_snapshot_data. */
23752  if (agg_ptr->function == PT_COUNT_STAR)
23753  {
23754  *is_scan_needed = true;
23755  break;
23756  }
23757 
23758  /* If we deal with a count optimization and the snapshot wasn't already taken then prepare current class for
23759  * optimization and force a snapshot */
23760  if (!*is_scan_needed && agg_ptr->function == PT_COUNT_STAR)
23761  {
23762  LOG_TDES *tdes = LOG_FIND_TDES (LOG_FIND_THREAD_TRAN_INDEX (thread_p));
23763  LOG_TRAN_CLASS_COS *class_cos = logtb_tran_find_class_cos (thread_p, &ACCESS_SPEC_CLS_OID (spec),
23764  true);
23765  if (class_cos == NULL)
23766  {
23767  agg_ptr->flag_agg_optimize = false;
23768  *is_scan_needed = true;
23769  break;
23770  }
23771  if (tdes->mvccinfo.snapshot.valid)
23772  {
23773  if (class_cos->count_state != COS_LOADED)
23774  {
23775  agg_ptr->flag_agg_optimize = false;
23776  *is_scan_needed = true;
23777  break;
23778  }
23779  }
23780  else
23781  {
23782  if (logtb_tran_find_btid_stats (thread_p, &agg_ptr->btid, true) == NULL)
23783  {
23784  agg_ptr->flag_agg_optimize = false;
23785  *is_scan_needed = true;
23786  break;
23787  }
23788  class_cos->count_state = COS_TO_LOAD;
23789 
23790  if (logtb_get_mvcc_snapshot (thread_p) == NULL)
23791  {
23792  error = er_errid ();
23793  return (error == NO_ERROR ? ER_FAILED : error);
23794  }
23795  }
23796  }
23797  }
23798 
23799  if (spec->pruning_type == DB_PARTITIONED_CLASS)
23800  {
23801  /* evaluate aggregate across partition hierarchy */
23802  return qexec_evaluate_partition_aggregates (thread_p, spec, agg_list, is_scan_needed);
23803  }
23804  else if (spec->pruning_type == DB_PARTITION_CLASS)
23805  {
23806  error = partition_find_root_class_oid (thread_p, &ACCESS_SPEC_CLS_OID (spec), &super_oid);
23807  if (error != NO_ERROR)
23808  {
23809  *is_scan_needed = true;
23810  return error;
23811  }
23812  }
23813 
23814  for (agg_ptr = agg_list; agg_ptr; agg_ptr = agg_ptr->next)
23815  {
23816  if (agg_ptr->flag_agg_optimize)
23817  {
23818  if (agg_ptr->function == PT_COUNT_STAR && *is_scan_needed)
23819  {
23820  /* If scan is needed, do not optimize PT_COUNT_STAR. */
23821  agg_ptr->flag_agg_optimize = false;
23822  continue;
23823  }
23824  if (qdata_evaluate_aggregate_optimize (thread_p, agg_ptr, &ACCESS_SPEC_HFID (spec), &super_oid) != NO_ERROR)
23825  {
23826  agg_ptr->flag_agg_optimize = false;
23827  *is_scan_needed = true;
23828  }
23829  }
23830  }
23831 
23832  return error;
23833 }
23834 
23835 /*
23836  * qexec_setup_topn_proc () - setup a top-n object
23837  * return : error code or NO_ERROR
23838  * thread_p (in) :
23839  * xasl (in) :
23840  * vd (in) :
23841  */
23842 static int
23844 {
23845  BINARY_HEAP *heap = NULL;
23846  DB_VALUE ubound_val;
23847  REGU_VARIABLE_LIST var_list = NULL;
23848  TOPN_TUPLES *top_n = NULL;
23849  int error = NO_ERROR, ubound = 0, count = 0;
23850  UINT64 estimated_size = 0, max_size = 0;
23851 
23852  if (xasl->type != BUILDLIST_PROC)
23853  {
23854  return NO_ERROR;
23855  }
23856 
23857  if (xasl->orderby_list == NULL)
23858  {
23859  /* Not ordered */
23860  return NO_ERROR;
23861  }
23862  if (xasl->ordbynum_pred == NULL)
23863  {
23864  /* No limit specified */
23865  return NO_ERROR;
23866  }
23867 
23868  if (xasl->option == Q_DISTINCT)
23869  {
23870  /* We cannot handle distinct ordering */
23871  return NO_ERROR;
23872  }
23873 
23875  || XASL_IS_FLAGED (xasl, XASL_USES_MRO))
23876  {
23877  return NO_ERROR;
23878  }
23879 
23880  if (xasl->proc.buildlist.groupby_list != NULL || xasl->proc.buildlist.a_eval_list != NULL)
23881  {
23882  /* Cannot handle group by and analytics with order by */
23883  return NO_ERROR;
23884  }
23885 
23886  db_make_null (&ubound_val);
23887  error = qexec_get_orderbynum_upper_bound (thread_p, xasl->ordbynum_pred, vd, &ubound_val);
23888  if (error != NO_ERROR)
23889  {
23890  return error;
23891  }
23892  if (DB_IS_NULL (&ubound_val))
23893  {
23894  return NO_ERROR;
23895  }
23896  if (DB_VALUE_TYPE (&ubound_val) != DB_TYPE_INTEGER)
23897  {
23898  TP_DOMAIN_STATUS status;
23899  status = tp_value_cast (&ubound_val, &ubound_val, &tp_Integer_domain, 1);
23900  if (status != DOMAIN_COMPATIBLE)
23901  {
23902  pr_clear_value (&ubound_val);
23903  return NO_ERROR;
23904  }
23905  }
23906 
23907  ubound = db_get_int (&ubound_val);
23908  pr_clear_value (&ubound_val);
23909 
23910  if (ubound == 0)
23911  {
23912  return NO_ERROR;
23913  }
23914 
23915  estimated_size = 0;
23916  count = 0;
23917  var_list = xasl->outptr_list->valptrp;
23918  while (var_list)
23919  {
23920  if (var_list->value.domain == NULL)
23921  {
23922  /* probably an error but just abandon top-n */
23923  return NO_ERROR;
23924  }
23925  if (TP_IS_SET_TYPE (TP_DOMAIN_TYPE (var_list->value.domain)))
23926  {
23927  /* do not apply this to collections */
23928  return NO_ERROR;
23929  }
23931  {
23932  /* skip hidden values */
23933  var_list = var_list->next;
23934  continue;
23935  }
23936 
23937  if (var_list->value.domain->precision != TP_FLOATING_PRECISION_VALUE)
23938  {
23939  /* Ignore floating point precision domains for now. We will decide whether or not to continue with top-N
23940  * whenever we add/replace a tuple. */
23941  estimated_size += tp_domain_memory_size (var_list->value.domain);
23942  }
23943  count++;
23944  var_list = var_list->next;
23945  }
23946 
23947  if (estimated_size >= (UINT64) QFILE_MAX_TUPLE_SIZE_IN_PAGE)
23948  {
23949  /* Do not keep these values in memory */
23950  return NO_ERROR;
23951  }
23952 
23953  /* At any time, we will handle at most ubound tuples */
23954  estimated_size *= ubound;
23955  max_size = (UINT64) prm_get_integer_value (PRM_ID_SR_NBUFFERS) * IO_PAGESIZE;
23956  if (estimated_size > max_size)
23957  {
23958  /* Do not use more than the sort buffer size. Using the entire sort buffer is possible because this is the only
23959  * sort operation which is being executed for this transaction at this time. */
23960  return NO_ERROR;
23961  }
23962 
23963 
23964  top_n = (TOPN_TUPLES *) db_private_alloc (thread_p, sizeof (TOPN_TUPLES));
23965  if (top_n == NULL)
23966  {
23967  error = ER_FAILED;
23968  goto error_return;
23969  }
23970 
23971  top_n->max_size = max_size;
23972  top_n->total_size = 0;
23973 
23974  top_n->tuples = (TOPN_TUPLE *) db_private_alloc (thread_p, ubound * sizeof (TOPN_TUPLE));
23975  if (top_n->tuples == NULL)
23976  {
23977  error = ER_FAILED;
23978  goto error_return;
23979  }
23980  memset (top_n->tuples, 0, ubound * sizeof (TOPN_TUPLE));
23981 
23982  heap = bh_create (thread_p, ubound, sizeof (TOPN_TUPLE *), qexec_topn_compare, top_n);
23983  if (heap == NULL)
23984  {
23985  error = ER_FAILED;
23986  goto error_return;
23987  }
23988 
23989  top_n->heap = heap;
23990  top_n->sort_items = xasl->orderby_list;
23991  top_n->values_count = count;
23992 
23993  xasl->topn_items = top_n;
23994 
23995  return NO_ERROR;
23996 
23997 error_return:
23998  if (heap != NULL)
23999  {
24000  bh_destroy (thread_p, heap);
24001  }
24002  if (top_n != NULL)
24003  {
24004  if (top_n->tuples != NULL)
24005  {
24006  db_private_free (thread_p, top_n->tuples);
24007  }
24008  db_private_free (thread_p, top_n);
24009  }
24010 
24011  return error;
24012 }
24013 
24014 /*
24015  * qexec_topn_compare () - comparison function for top-n heap
24016  * return : comparison result
24017  * left (in) :
24018  * right (in) :
24019  * arg (in) :
24020  */
24021 static BH_CMP_RESULT
24022 qexec_topn_compare (const void *left, const void *right, BH_CMP_ARG arg)
24023 {
24024  int pos;
24025  SORT_LIST *key = NULL;
24026  TOPN_TUPLES *proc = (TOPN_TUPLES *) arg;
24027  TOPN_TUPLE *left_tuple = *((TOPN_TUPLE **) left);
24028  TOPN_TUPLE *right_tuple = *((TOPN_TUPLE **) right);
24030 
24031  for (key = proc->sort_items; key != NULL; key = key->next)
24032  {
24033  pos = key->pos_descr.pos_no;
24034  cmp = qexec_topn_cmpval (&left_tuple->values[pos], &right_tuple->values[pos], key);
24035  if (cmp == BH_EQ)
24036  {
24037  continue;
24038  }
24039  return cmp;
24040  }
24041 
24042  return BH_EQ;
24043 }
24044 
24045 /*
24046  * qexec_topn_cmpval () - compare two values
24047  * return : comparison result
24048  * left (in) : left value
24049  * right (in) : right value
24050  * sort_spec (in): sort spec for left and right
24051  *
24052  * Note: tp_value_compare is too complex for our case
24053  */
24054 static BH_CMP_RESULT
24055 qexec_topn_cmpval (DB_VALUE * left, DB_VALUE * right, SORT_LIST * sort_spec)
24056 {
24057  int cmp;
24058  if (DB_IS_NULL (left))
24059  {
24060  if (DB_IS_NULL (right))
24061  {
24062  return BH_EQ;
24063  }
24064  cmp = DB_LT;
24065  if ((sort_spec->s_order == S_ASC && sort_spec->s_nulls == S_NULLS_LAST)
24066  || (sort_spec->s_order == S_DESC && sort_spec->s_nulls == S_NULLS_FIRST))
24067  {
24068  cmp = -cmp;
24069  }
24070  }
24071  else if (DB_IS_NULL (right))
24072  {
24073  cmp = DB_GT;
24074  if ((sort_spec->s_order == S_ASC && sort_spec->s_nulls == S_NULLS_LAST)
24075  || (sort_spec->s_order == S_DESC && sort_spec->s_nulls == S_NULLS_FIRST))
24076  {
24077  cmp = -cmp;
24078  }
24079  }
24080  else
24081  {
24082  if (TP_DOMAIN_TYPE (sort_spec->pos_descr.dom) == DB_TYPE_VARIABLE
24084  {
24085  /* In cases like order by val + ?, the domain of the expression is not known at compile time */
24086  cmp = tp_value_compare (left, right, 1, 1);
24087  }
24088  else
24089  {
24090  cmp =
24091  sort_spec->pos_descr.dom->type->cmpval (left, right, 1, 1, NULL, sort_spec->pos_descr.dom->collation_id);
24092  }
24093  }
24094  if (sort_spec->s_order == S_DESC)
24095  {
24096  cmp = -cmp;
24097  }
24098 
24099  switch (cmp)
24100  {
24101  case DB_GT:
24102  return BH_GT;
24103 
24104  case DB_LT:
24105  return BH_LT;
24106 
24107  case DB_EQ:
24108  return BH_EQ;
24109 
24110  default:
24111  break;
24112  }
24113 
24114  return BH_CMP_ERROR;
24115 }
24116 
24117 /*
24118  * qexec_add_tuple_to_topn () - add a new tuple to top-n tuples
24119  * return : TOPN_SUCCESS if tuple was successfully processed, TOPN_OVERFLOW if
24120  * the new tuple does not fit into memory or TOPN_FAILURE on error
24121  * thread_p (in) :
24122  * topn_items (in): topn items
24123  * tpldescr (in) : new tuple
24124  *
24125  * Note: We only add a tuple here if the top-n heap has fewer than n elements
24126  * or if the new tuple can replace one of the existing tuples
24127  */
24128 static TOPN_STATUS
24129 qexec_add_tuple_to_topn (THREAD_ENTRY * thread_p, TOPN_TUPLES * topn_items, QFILE_TUPLE_DESCRIPTOR * tpldescr)
24130 {
24131  int error = NO_ERROR;
24132  BH_CMP_RESULT res = BH_EQ;
24133  SORT_LIST *key = NULL;
24134  int pos = 0;
24135  TOPN_TUPLE *heap_max = NULL;
24136 
24137  assert (topn_items != NULL && tpldescr != NULL);
24138 
24139  if (!bh_is_full (topn_items->heap))
24140  {
24141  /* Add current tuple to heap. We haven't reached top-N yet */
24142  TOPN_TUPLE *tpl = NULL;
24143  int idx = topn_items->heap->element_count;
24144 
24145  if (topn_items->total_size + tpldescr->tpl_size > topn_items->max_size)
24146  {
24147  /* abandon top-N */
24148  return TOPN_OVERFLOW;
24149  }
24150 
24151  tpl = &topn_items->tuples[idx];
24152 
24153  /* tpl must be unused */
24154  assert_release (tpl->values == NULL);
24155 
24156  error = qdata_tuple_to_values_array (thread_p, tpldescr, &tpl->values);
24157  if (error != NO_ERROR)
24158  {
24159  return TOPN_FAILURE;
24160  }
24161 
24162  tpl->values_size = tpldescr->tpl_size;
24163  topn_items->total_size += tpldescr->tpl_size;
24164 
24165  (void) bh_insert (topn_items->heap, &tpl);
24166 
24167  return TOPN_SUCCESS;
24168  }
24169 
24170  /* We only add a tuple to the heap if it is "smaller" than the current root. Rather than allocating memory for a new
24171  * tuple and testing it, we test the heap root directly on the outptr list and replace it if we have to. */
24172  if (!bh_peek_max (topn_items->heap, &heap_max))
24173  {
24174  assert (false);
24175  }
24176  assert (heap_max != NULL);
24177 
24178  for (key = topn_items->sort_items; key != NULL; key = key->next)
24179  {
24180  pos = key->pos_descr.pos_no;
24181  res = qexec_topn_cmpval (&heap_max->values[pos], tpldescr->f_valp[pos], key);
24182  if (res == BH_EQ)
24183  {
24184  continue;
24185  }
24186  if (res == BH_LT)
24187  {
24188  /* skip this tuple */
24189  return TOPN_SUCCESS;
24190  }
24191  break;
24192  }
24193  if (res == BH_EQ)
24194  {
24195  return TOPN_SUCCESS;
24196  }
24197 
24198  /* Test if we can accommodate the new tuple */
24199  if (topn_items->total_size - heap_max->values_size + tpldescr->tpl_size > topn_items->max_size)
24200  {
24201  /* Abandon top-N */
24202  return TOPN_OVERFLOW;
24203  }
24204 
24205  /* Replace heap root. We don't need the heap_max object anymore so we will use it for the new tuple. */
24206  topn_items->total_size -= heap_max->values_size;
24207  qexec_clear_topn_tuple (thread_p, heap_max, tpldescr->f_cnt);
24208 
24209  error = qdata_tuple_to_values_array (thread_p, tpldescr, &heap_max->values);
24210  if (error != NO_ERROR)
24211  {
24212  return TOPN_FAILURE;
24213  }
24214 
24215  heap_max->values_size = tpldescr->tpl_size;
24216  topn_items->total_size += tpldescr->tpl_size;
24217 
24218  (void) bh_down_heap (topn_items->heap, 0);
24219 
24220  return TOPN_SUCCESS;
24221 }
24222 
24223 /*
24224  * qexec_topn_tuples_to_list_id () - put tuples from the internal heap to the
24225  * output listfile
24226  * return : error code or NO_ERROR
24227  * xasl (in) : xasl node
24228  */
24229 static int
24231 {
24232  QFILE_LIST_ID *list_id = NULL;
24233  QFILE_TUPLE_DESCRIPTOR *tpl_descr = NULL;
24234  TOPN_TUPLES *topn = NULL;
24235  BINARY_HEAP *heap = NULL;
24236  REGU_VARIABLE_LIST varp = NULL;
24237  TOPN_TUPLE *tuple = NULL;
24238  int row = 0, i, value_size, values_count, error = NO_ERROR;
24239  ORDBYNUM_INFO ordby_info;
24240  DB_LOGICAL res = V_FALSE;
24241 
24242  /* setup ordby_info so that we can evaluate the orderby_num() predicate */
24243  ordby_info.xasl_state = xasl_state;
24244  ordby_info.ordbynum_pred = xasl->ordbynum_pred;
24245  ordby_info.ordbynum_flag = xasl->ordbynum_flag;
24246  ordby_info.ordbynum_pos_cnt = 0;
24247  ordby_info.ordbynum_val = xasl->ordbynum_val;
24248  db_make_bigint (ordby_info.ordbynum_val, 0);
24249 
24250  list_id = xasl->list_id;
24251  topn = xasl->topn_items;
24252  heap = topn->heap;
24253  tpl_descr = &list_id->tpl_descr;
24254  values_count = topn->values_count;
24255  xasl->orderby_stats.orderby_topnsort = true;
24256 
24257  /* convert binary heap to sorted array */
24258  bh_to_sorted_array (heap);
24259 
24260  /* dump all items in heap to listfile */
24261  if (tpl_descr->f_valp == NULL && list_id->type_list.type_cnt > 0)
24262  {
24263  size_t size = values_count * DB_SIZEOF (DB_VALUE *);
24264 
24265  tpl_descr->f_valp = (DB_VALUE **) malloc (size);
24266  if (tpl_descr->f_valp == NULL)
24267  {
24269  error = ER_FAILED;
24270  goto cleanup;
24271  }
24272 
24273  tpl_descr->clear_f_val_at_clone_decache = (bool *) malloc (sizeof (bool) * values_count);
24274  if (tpl_descr->clear_f_val_at_clone_decache == NULL)
24275  {
24276  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, sizeof (bool) * values_count);
24277  goto cleanup;
24278  }
24279 
24280  for (i = 0; i < values_count; i++)
24281  {
24282  tpl_descr->clear_f_val_at_clone_decache[i] = false;
24283  }
24284  }
24285 
24286  varp = xasl->outptr_list->valptrp;
24287  for (row = 0; row < heap->element_count; row++)
24288  {
24289  tuple = QEXEC_GET_BH_TOPN_TUPLE (heap, row);
24290 
24291  /* evaluate orderby_num predicate */
24292  res = qexec_eval_ordbynum_pred (thread_p, &ordby_info);
24293  if (res != V_TRUE)
24294  {
24295  if (res == V_ERROR)
24296  {
24297  error = ER_FAILED;
24298  goto cleanup;
24299  }
24300 
24301  if (is_final)
24302  {
24303  /* skip this tuple */
24304  qexec_clear_topn_tuple (thread_p, tuple, values_count);
24305  QEXEC_GET_BH_TOPN_TUPLE (heap, row) = NULL;
24306  continue;
24307  }
24308  }
24309 
24310  tuple = QEXEC_GET_BH_TOPN_TUPLE (heap, row);
24311  tpl_descr->tpl_size = QFILE_TUPLE_LENGTH_SIZE;
24312 
24313  tpl_descr->f_cnt = 0;
24314 
24315  for (varp = xasl->outptr_list->valptrp; varp != NULL; varp = varp->next)
24316  {
24318  {
24319  continue;
24320  }
24321 
24322  if (varp->value.type == TYPE_ORDERBY_NUM)
24323  {
24324  pr_clone_value (ordby_info.ordbynum_val, &tuple->values[tpl_descr->f_cnt]);
24325  }
24326 
24327  tpl_descr->f_valp[tpl_descr->f_cnt] = &tuple->values[tpl_descr->f_cnt];
24328 
24329  value_size = qdata_get_tuple_value_size_from_dbval (&tuple->values[tpl_descr->f_cnt]);
24330  if (value_size == ER_FAILED)
24331  {
24332  error = value_size;
24333  goto cleanup;
24334  }
24335 
24336  tpl_descr->tpl_size += value_size;
24337  tpl_descr->f_cnt++;
24338  }
24339 
24340  error = qfile_generate_tuple_into_list (thread_p, list_id, T_NORMAL);
24341  if (error != NO_ERROR)
24342  {
24343  goto cleanup;
24344  }
24345  /* clear tuple values */
24346  qexec_clear_topn_tuple (thread_p, tuple, values_count);
24347  QEXEC_GET_BH_TOPN_TUPLE (heap, row) = NULL;
24348  }
24349 
24350 cleanup:
24351  if (tuple != NULL)
24352  {
24353  qexec_clear_topn_tuple (thread_p, tuple, values_count);
24354  }
24355 
24356  for (i = row; i < heap->element_count; i++)
24357  {
24358  if (QEXEC_GET_BH_TOPN_TUPLE (heap, i) != NULL)
24359  {
24360  tuple = QEXEC_GET_BH_TOPN_TUPLE (heap, i);
24361  qexec_clear_topn_tuple (thread_p, tuple, values_count);
24362  QEXEC_GET_BH_TOPN_TUPLE (heap, i) = NULL;
24363  }
24364  }
24365 
24366  if (heap != NULL)
24367  {
24368  bh_destroy (thread_p, heap);
24369  }
24370 
24371  if (xasl->topn_items != NULL)
24372  {
24373  if (xasl->topn_items->tuples != NULL)
24374  {
24375  db_private_free (thread_p, xasl->topn_items->tuples);
24376  }
24377  db_private_free (thread_p, xasl->topn_items);
24378  xasl->topn_items = NULL;
24379  }
24380 
24381  if (is_final)
24382  {
24383  qfile_close_list (thread_p, list_id);
24384  }
24385  else
24386  {
24387  /* reset ORDERBY_NUM value */
24389  db_make_bigint (xasl->ordbynum_val, 0);
24390  }
24391  return error;
24392 }
24393 
24394 /*
24395  * qexec_clear_topn_tuple () - clear values of a top-n tuple
24396  * return : void
24397  * thread_p (in) :
24398  * tuple (in/out) : top-N tuple
24399  * count (in) : number of values
24400  */
24401 static void
24402 qexec_clear_topn_tuple (THREAD_ENTRY * thread_p, TOPN_TUPLE * tuple, int count)
24403 {
24404  int i;
24405  if (tuple == NULL)
24406  {
24407  return;
24408  }
24409 
24410  if (tuple->values != NULL)
24411  {
24412  for (i = 0; i < count; i++)
24413  {
24414  pr_clear_value (&tuple->values[i]);
24415  }
24416  db_private_free_and_init (thread_p, tuple->values);
24417  }
24418  tuple->values_size = 0;
24419 }
24420 
24421 /*
24422  * qexec_get_orderbynum_upper_bound - get upper bound for orderby_num
24423  * predicate
24424  * return: error code or NO_ERROR
24425  * thread_p : thread entry
24426  * pred (in) : orderby_num predicate
24427  * vd (in) : value descriptor
24428  * ubound (in/out) : upper bound
24429  */
24430 static int
24432 {
24433  int error = NO_ERROR;
24434  REGU_VARIABLE *lhs, *rhs;
24435  REL_OP op;
24436  DB_VALUE *val;
24437  int cmp;
24438  DB_VALUE left_bound, right_bound;
24439 
24440  assert_release (pred != NULL);
24441  assert_release (ubound != NULL);
24442 
24443  db_make_null (ubound);
24444  db_make_null (&left_bound);
24445  db_make_null (&right_bound);
24446 
24447  if (pred->type == T_PRED && pred->pe.m_pred.bool_op == B_AND)
24448  {
24449  error = qexec_get_orderbynum_upper_bound (thread_p, pred->pe.m_pred.lhs, vd, &left_bound);
24450  if (error != NO_ERROR)
24451  {
24452  goto error_return;
24453  }
24454 
24455  error = qexec_get_orderbynum_upper_bound (thread_p, pred->pe.m_pred.rhs, vd, &right_bound);
24456  if (error != NO_ERROR)
24457  {
24458  goto error_return;
24459  }
24460 
24461  if (DB_IS_NULL (&left_bound) && DB_IS_NULL (&right_bound))
24462  {
24463  /* no valid bounds */
24464  goto cleanup;
24465  }
24466 
24467  cmp = tp_value_compare (&left_bound, &right_bound, 1, 1);
24468  if (cmp == DB_GT)
24469  {
24470  error = pr_clone_value (&left_bound, ubound);
24471  }
24472  else
24473  {
24474  error = pr_clone_value (&right_bound, ubound);
24475  }
24476 
24477  if (error != NO_ERROR)
24478  {
24479  goto error_return;
24480  }
24481 
24482  goto cleanup;
24483  }
24484 
24485  if (pred->type == T_EVAL_TERM)
24486  {
24487  /* This should be TYPE_CONSTANT comp TYPE_VALUE. If not, we bail out */
24488  lhs = pred->pe.m_eval_term.et.et_comp.lhs;
24489  rhs = pred->pe.m_eval_term.et.et_comp.rhs;
24490  op = pred->pe.m_eval_term.et.et_comp.rel_op;
24491  if (lhs->type != TYPE_CONSTANT)
24492  {
24493  if (lhs->type != TYPE_POS_VALUE && lhs->type != TYPE_DBVAL)
24494  {
24495  goto cleanup;
24496  }
24497 
24498  if (rhs->type != TYPE_CONSTANT)
24499  {
24500  goto cleanup;
24501  }
24502 
24503  /* reverse comparison */
24504  rhs = lhs;
24505  lhs = pred->pe.m_eval_term.et.et_comp.rhs;
24506  switch (op)
24507  {
24508  case R_GT:
24509  op = R_LT;
24510  break;
24511  case R_GE:
24512  op = R_LE;
24513  break;
24514  case R_LT:
24515  op = R_GT;
24516  break;
24517  case R_LE:
24518  op = R_GE;
24519  break;
24520  default:
24521  goto cleanup;
24522  }
24523  }
24524  if (rhs->type != TYPE_POS_VALUE && rhs->type != TYPE_DBVAL)
24525  {
24526  goto cleanup;
24527  }
24528 
24529  if (op != R_LT && op != R_LE)
24530  {
24531  /* we're only interested in orderby_num less than value */
24532  goto cleanup;
24533  }
24534 
24535  error = fetch_peek_dbval (thread_p, rhs, vd, NULL, NULL, NULL, &val);
24536  if (error != NO_ERROR)
24537  {
24538  goto error_return;
24539  }
24540 
24541  if (op == R_LT)
24542  {
24543  /* add 1 so we can use R_LE */
24544  DB_VALUE one_val;
24545  db_make_int (&one_val, 1);
24546  error = qdata_subtract_dbval (val, &one_val, ubound, rhs->domain);
24547  }
24548  else
24549  {
24550  error = pr_clone_value (val, ubound);
24551  }
24552 
24553  if (error != NO_ERROR)
24554  {
24555  goto error_return;
24556  }
24557  goto cleanup;
24558  }
24559 
24560  return error;
24561 
24562 error_return:
24563  db_make_null (ubound);
24564 
24565 cleanup:
24566  pr_clear_value (&left_bound);
24567  pr_clear_value (&right_bound);
24568 
24569  return error;
24570 }
24571 
24572 /*
24573  * qexec_clear_agg_orderby_const_list () -
24574  * return:
24575  * xasl(in) :
24576  */
24577 static int
24578 qexec_clear_agg_orderby_const_list (THREAD_ENTRY * thread_p, XASL_NODE * xasl, bool is_final)
24579 {
24580  AGGREGATE_TYPE *agg_list, *agg_p;
24581  int pg_cnt = 0;
24582  assert (xasl != NULL);
24583 
24584  agg_list = xasl->proc.buildvalue.agg_list;
24585  for (agg_p = agg_list; agg_p; agg_p = agg_p->next)
24586  {
24587  if ((agg_p->function == PT_CUME_DIST || agg_p->function == PT_PERCENT_RANK)
24588  && agg_p->info.dist_percent.const_array != NULL)
24589  {
24590  db_private_free_and_init (thread_p, agg_p->info.dist_percent.const_array);
24591  agg_p->info.dist_percent.list_len = 0;
24592  }
24593 
24594  if (agg_p->function == PT_PERCENTILE_CONT || agg_p->function == PT_PERCENTILE_DISC)
24595  {
24596  if (agg_p->info.percentile.percentile_reguvar != NULL)
24597  {
24598  pg_cnt += qexec_clear_regu_var (thread_p, xasl, agg_p->info.percentile.percentile_reguvar, is_final);
24599  }
24600  }
24601  }
24602 
24603  return pg_cnt;
24604 }
24605 
24606 /*
24607  * qexec_clear_regu_variable_list () - clear the db_values in the regu variable list
24608  * return:
24609  * xasl_p(in) :
24610  * list(in) :
24611  * is_final(in) :
24612  */
24613 static int
24615 {
24616  REGU_VARIABLE_LIST list_node;
24617  int pg_cnt = 0;
24618 
24619  assert (list != NULL);
24620 
24621  for (list_node = list; list_node; list_node = list_node->next)
24622  {
24623  pg_cnt += qexec_clear_regu_var (thread_p, xasl_p, &list_node->value, is_final);
24624  }
24625 
24626  return pg_cnt;
24627 }
24628 
24629 #if defined(SERVER_MODE)
24630 /*
24631  * qexec_set_xasl_trace_to_session() - save query trace to session
24632  * return:
24633  * xasl(in): sort direction ascending or descending
24634  */
24635 static void
24636 qexec_set_xasl_trace_to_session (THREAD_ENTRY * thread_p, XASL_NODE * xasl)
24637 {
24638  size_t sizeloc;
24639  char *trace_str = NULL;
24640  FILE *fp;
24641  json_t *trace;
24642 
24643  if (thread_p->trace_format == QUERY_TRACE_TEXT)
24644  {
24645  fp = port_open_memstream (&trace_str, &sizeloc);
24646  if (fp)
24647  {
24648  qdump_print_stats_text (fp, xasl, 0);
24649  port_close_memstream (fp, &trace_str, &sizeloc);
24650  }
24651  }
24652  else if (thread_p->trace_format == QUERY_TRACE_JSON)
24653  {
24654  trace = json_object ();
24655  qdump_print_stats_json (xasl, trace);
24656  trace_str = json_dumps (trace, JSON_INDENT (2) | JSON_PRESERVE_ORDER);
24657 
24658  json_object_clear (trace);
24659  json_decref (trace);
24660  }
24661 
24662  if (trace_str != NULL)
24663  {
24664  session_set_trace_stats (thread_p, trace_str, thread_p->trace_format);
24665  }
24666 }
24667 #endif /* SERVER_MODE */
24668 
24669 /*
24670  * qexec_clear_pred_xasl () - Clear XASLs linked by regu variables
24671  * return:
24672  * pred(in):
24673  */
24674 static void
24676 {
24677  PRED_EXPR *pr;
24678 
24679  if (pred == NULL)
24680  {
24681  return;
24682  }
24683 
24684  switch (pred->type)
24685  {
24686  case T_PRED:
24687  qexec_clear_pred_xasl (thread_p, pred->pe.m_pred.lhs);
24688  for (pr = pred->pe.m_pred.rhs; pr && pr->type == T_PRED; pr = pr->pe.m_pred.rhs)
24689  {
24690  qexec_clear_pred_xasl (thread_p, pr->pe.m_pred.lhs);
24691  }
24692  qexec_clear_pred_xasl (thread_p, pr);
24693  break;
24694  case T_EVAL_TERM:
24695  /* operands of type TYPE_LIST_ID are the XASLs we need to clear list files for */
24696  if (pred->pe.m_eval_term.et_type == T_COMP_EVAL_TERM)
24697  {
24698  COMP_EVAL_TERM *et_comp = &pred->pe.m_eval_term.et.et_comp;
24699  if (et_comp->rel_op == R_EXISTS && et_comp->lhs->type == TYPE_LIST_ID)
24700  {
24701  qexec_clear_head_lists (thread_p, et_comp->lhs->xasl);
24702  }
24703  }
24704  else if (pred->pe.m_eval_term.et_type == T_ALSM_EVAL_TERM)
24705  {
24706  ALSM_EVAL_TERM *et_alsm = &pred->pe.m_eval_term.et.et_alsm;
24707  if (et_alsm->elemset->type == TYPE_LIST_ID)
24708  {
24709  qexec_clear_head_lists (thread_p, et_alsm->elemset->xasl);
24710  }
24711  }
24712  /* no need to check into eval terms of type T_LIKE_EVAL_TERM and T_RLIKE_EVAL_TERM since they don't have
24713  * TYPE_LIST_ID operands */
24714  break;
24715  case T_NOT_TERM:
24716  qexec_clear_pred_xasl (thread_p, pred->pe.m_not_term);
24717  break;
24718  }
24719 }
24720 
24721 /*
24722  * qexec_alloc_agg_hash_context () - allocate hash aggregate evaluation related
24723  * structures used at runtime
24724  * returns: error code or NO_ERROR
24725  * thread_p(in): thread
24726  * proc(in): buildlist
24727  * xasl_state(in): XASL state
24728  */
24729 static int
24731 {
24732  QFILE_TUPLE_VALUE_TYPE_LIST type_list;
24733  REGU_VARIABLE_LIST regu_list;
24734  AGGREGATE_TYPE *agg_list;
24735  int value_count = 0, i = 0, error_code = NO_ERROR;
24736 
24737  if (!proc->g_hash_eligible)
24738  {
24739  return NO_ERROR;
24740  }
24741  assert (proc->agg_hash_context != NULL);
24742 
24743  /* clear fields (in case of error, things will get properly disposed) */
24744  proc->agg_hash_context->key_domains = NULL;
24745  proc->agg_hash_context->accumulator_domains = NULL;
24746  proc->agg_hash_context->temp_dbval_array = NULL;
24747  proc->agg_hash_context->part_list_id = NULL;
24748  proc->agg_hash_context->sorted_part_list_id = NULL;
24749  proc->agg_hash_context->hash_table = NULL;
24750  proc->agg_hash_context->temp_key = NULL;
24751  proc->agg_hash_context->temp_part_key = NULL;
24752  proc->agg_hash_context->curr_part_key = NULL;
24753  proc->agg_hash_context->temp_part_value = NULL;
24754  proc->agg_hash_context->curr_part_value = NULL;
24755  proc->agg_hash_context->sort_key.key = NULL;
24756  proc->agg_hash_context->sort_key.nkeys = 0;
24757 
24758  /*
24759  * create temporary dbvalue array
24760  */
24761  if (proc->g_func_count > 0)
24762  {
24763  proc->agg_hash_context->temp_dbval_array =
24764  (DB_VALUE *) db_private_alloc (thread_p, sizeof (DB_VALUE) * proc->g_func_count);
24765  if (proc->agg_hash_context->temp_dbval_array == NULL)
24766  {
24768  sizeof (DB_VALUE) * proc->g_func_count);
24769  goto exit_on_error;
24770  }
24771  }
24772 
24773  /*
24774  * keep key domains
24775  */
24776  proc->agg_hash_context->key_domains =
24777  (TP_DOMAIN **) db_private_alloc (thread_p, sizeof (TP_DOMAIN *) * proc->g_hkey_size);
24778  if (proc->agg_hash_context->key_domains == NULL)
24779  {
24781  goto exit_on_error;
24782  }
24783 
24784  regu_list = proc->g_hk_scan_regu_list;
24785  for (i = 0; i < proc->g_hkey_size; i++, regu_list = regu_list->next)
24786  {
24787  assert (regu_list);
24788  proc->agg_hash_context->key_domains[i] = regu_list->value.domain;
24789  }
24790 
24791  /*
24792  * keep accumulator domains
24793  */
24794  if (proc->g_func_count > 0)
24795  {
24796  proc->agg_hash_context->accumulator_domains =
24797  (AGGREGATE_ACCUMULATOR_DOMAIN **) db_private_alloc (thread_p,
24798  sizeof (AGGREGATE_ACCUMULATOR_DOMAIN *) *
24799  proc->g_func_count);
24800  if (proc->agg_hash_context->accumulator_domains == NULL)
24801  {
24803  sizeof (AGGREGATE_ACCUMULATOR_DOMAIN *) * proc->g_func_count);
24804  goto exit_on_error;
24805  }
24806 
24807  agg_list = proc->g_agg_list;
24808  for (i = 0; i < proc->g_func_count; i++, agg_list = agg_list->next)
24809  {
24810  assert (agg_list);
24811  proc->agg_hash_context->accumulator_domains[i] = &agg_list->accumulator_domain;
24812  }
24813  }
24814 
24815  /*
24816  * create partial list file
24817  */
24818 
24819  /* compute number of values and alloc type list */
24820  type_list.type_cnt = proc->g_hkey_size + proc->g_func_count * 3 + 1;
24821  type_list.domp = (TP_DOMAIN **) db_private_alloc (thread_p, sizeof (TP_DOMAIN *) * type_list.type_cnt);
24822  if (type_list.domp == NULL)
24823  {
24825  goto exit_on_error;
24826  }
24827 
24828  /* register key domains */
24829  regu_list = proc->g_hk_scan_regu_list;
24830  value_count = 0;
24831  while (regu_list)
24832  {
24833  type_list.domp[value_count++] = regu_list->value.domain;
24834  regu_list = regu_list->next;
24835  }
24836 
24837  /* register accumulator domains */
24838  for (i = 0; i < proc->g_func_count; i++)
24839  {
24840  /* value and value2 are variable */
24841  type_list.domp[value_count++] = &tp_Variable_domain;
24842  type_list.domp[value_count++] = &tp_Variable_domain;
24843 
24844  /* third one is integer counter */
24845  type_list.domp[value_count++] = &tp_Integer_domain;
24846  }
24847 
24848  /* register counter domain */
24849  type_list.domp[value_count++] = &tp_Integer_domain;
24850 
24851  /* create sort key */
24852  proc->agg_hash_context->sort_key.key = NULL;
24853  proc->agg_hash_context->sort_key.nkeys = 0;
24854 
24855  /* create list files */
24856  proc->agg_hash_context->part_list_id = qfile_open_list (thread_p, &type_list, NULL, xasl_state->query_id, 0);
24857  proc->agg_hash_context->sorted_part_list_id = qfile_open_list (thread_p, &type_list, NULL, xasl_state->query_id, 0);
24858 
24859  /* create tuple descriptor for partial list files */
24860  proc->agg_hash_context->part_list_id->tpl_descr.f_cnt = type_list.type_cnt;
24861  proc->agg_hash_context->part_list_id->tpl_descr.f_valp =
24862  (DB_VALUE **) malloc (sizeof (DB_VALUE) * type_list.type_cnt);
24863  if (proc->agg_hash_context->part_list_id->tpl_descr.f_valp == NULL)
24864  {
24866  goto exit_on_error;
24867  }
24868  proc->agg_hash_context->part_list_id->tpl_descr.clear_f_val_at_clone_decache =
24869  (bool *) malloc (sizeof (bool) * type_list.type_cnt);
24870  if (proc->agg_hash_context->part_list_id->tpl_descr.clear_f_val_at_clone_decache == NULL)
24871  {
24872  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, sizeof (bool) * type_list.type_cnt);
24873  goto exit_on_error;
24874  }
24875  for (i = 0; i < type_list.type_cnt; i++)
24876  {
24877  proc->agg_hash_context->part_list_id->tpl_descr.clear_f_val_at_clone_decache[i] = false;
24878  }
24879 
24880  proc->agg_hash_context->sorted_part_list_id->tpl_descr.f_cnt = type_list.type_cnt;
24881  proc->agg_hash_context->sorted_part_list_id->tpl_descr.f_valp =
24882  (DB_VALUE **) malloc (sizeof (DB_VALUE) * type_list.type_cnt);
24883  if (proc->agg_hash_context->sorted_part_list_id->tpl_descr.f_valp == NULL)
24884  {
24886  goto exit_on_error;
24887  }
24888  proc->agg_hash_context->sorted_part_list_id->tpl_descr.clear_f_val_at_clone_decache =
24889  (bool *) malloc (sizeof (bool) * type_list.type_cnt);
24890  if (proc->agg_hash_context->sorted_part_list_id->tpl_descr.clear_f_val_at_clone_decache == NULL)
24891  {
24892  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, sizeof (bool) * type_list.type_cnt);
24893  goto exit_on_error;
24894  }
24895  for (i = 0; i < type_list.type_cnt; i++)
24896  {
24897  proc->agg_hash_context->sorted_part_list_id->tpl_descr.clear_f_val_at_clone_decache[i] = false;
24898  }
24899 
24900  /* initialize scan; this way we can call qfile_close_scan on an unopened scan without repercussions */
24901  proc->agg_hash_context->part_scan_id.status = S_CLOSED;
24902 
24903  /* free memory */
24904  db_private_free (thread_p, type_list.domp);
24905 
24906  /*
24907  * create hash table
24908  */
24909  proc->agg_hash_context->hash_table =
24911  if (proc->agg_hash_context->hash_table == NULL)
24912  {
24913  goto exit_on_error;
24914  }
24915  else
24916  {
24917  /* we need the least recently used list */
24918  proc->agg_hash_context->hash_table->build_lru_list = true;
24919  }
24920 
24921  /*
24922  * create temp keys
24923  */
24924  proc->agg_hash_context->temp_key = qdata_alloc_agg_hkey (thread_p, proc->g_hkey_size, false);
24925  proc->agg_hash_context->temp_part_key = qdata_alloc_agg_hkey (thread_p, proc->g_hkey_size, true);
24926  proc->agg_hash_context->curr_part_key = qdata_alloc_agg_hkey (thread_p, proc->g_hkey_size, true);
24927 
24928  if (proc->agg_hash_context->temp_key == NULL || proc->agg_hash_context->temp_part_key == NULL
24929  || proc->agg_hash_context->curr_part_key == NULL)
24930  {
24931  goto exit_on_error;
24932  }
24933 
24934  /*
24935  * create temp values
24936  */
24937  proc->agg_hash_context->temp_part_value = qdata_alloc_agg_hvalue (thread_p, proc->g_func_count, proc->g_agg_list);
24938  proc->agg_hash_context->curr_part_value = qdata_alloc_agg_hvalue (thread_p, proc->g_func_count, proc->g_agg_list);
24939 
24940  if (proc->agg_hash_context->temp_part_value == NULL || proc->agg_hash_context->curr_part_value == NULL)
24941  {
24942  goto exit_on_error;
24943  }
24944 
24945  /*
24946  * initialize recdes
24947  */
24948  proc->agg_hash_context->tuple_recdes.data = 0;
24949  proc->agg_hash_context->tuple_recdes.type = 0;
24950  proc->agg_hash_context->tuple_recdes.length = 0;
24951  proc->agg_hash_context->tuple_recdes.area_size = 0;
24952 
24953  /*
24954  * initialize sort input tuple
24955  */
24956  proc->agg_hash_context->input_tuple.size = 0;
24957  proc->agg_hash_context->input_tuple.tpl = NULL;
24958 
24959  /*
24960  * initialize remaining fields
24961  */
24962  proc->agg_hash_context->hash_size = 0;
24963  proc->agg_hash_context->group_count = 0;
24964  proc->agg_hash_context->tuple_count = 0;
24965  proc->agg_hash_context->sorted_count = 0;
24966  proc->agg_hash_context->state = HS_ACCEPT_ALL;
24967 
24968  /* all ok */
24969  return NO_ERROR;
24970 
24971 exit_on_error:
24972 
24973  qexec_free_agg_hash_context (thread_p, proc);
24974  return (error_code == NO_ERROR && (error_code = er_errid ()) == NO_ERROR) ? ER_FAILED : error_code;
24975 }
24976 
24977 /*
24978  * qexec_alloc_agg_hash_context () - dispose hash aggregate evaluation related
24979  * structures used at runtime
24980  * thread_p(in): thread
24981  * proc(in): buildlist
24982  */
24983 static void
24985 {
24986  if (!proc->g_hash_eligible)
24987  {
24988  return;
24989  }
24990 
24991  /* clear group by regular var list */
24992  for (REGU_VARIABLE_LIST p = proc->g_regu_list; p; p = p->next)
24993  {
24994  if (p->value.vfetch_to != NULL)
24995  {
24996  pr_clear_value (p->value.vfetch_to);
24997  }
24998  }
24999 
25000  /* free value array */
25001  if (proc->agg_hash_context->temp_dbval_array != NULL)
25002  {
25003  db_private_free (thread_p, proc->agg_hash_context->temp_dbval_array);
25004  proc->agg_hash_context->temp_dbval_array = NULL;
25005  }
25006 
25007  /* free domain lists */
25008  if (proc->agg_hash_context->accumulator_domains != NULL)
25009  {
25010  db_private_free (thread_p, proc->agg_hash_context->accumulator_domains);
25011  proc->agg_hash_context->accumulator_domains = NULL;
25012  }
25013 
25014  if (proc->agg_hash_context->key_domains != NULL)
25015  {
25016  db_private_free (thread_p, proc->agg_hash_context->key_domains);
25017  proc->agg_hash_context->key_domains = NULL;
25018  }
25019 
25020  /* free sort key */
25021  qfile_clear_sort_key_info (&proc->agg_hash_context->sort_key);
25022 
25023  /* free entries and hash table */
25024  if (proc->agg_hash_context->hash_table != NULL)
25025  {
25026  (void) mht_clear (proc->agg_hash_context->hash_table, qdata_free_agg_hentry, (void *) thread_p);
25027  mht_destroy (proc->agg_hash_context->hash_table);
25028 
25029  proc->agg_hash_context->hash_table = NULL;
25030  }
25031 
25032  /* close scan */
25033  qfile_close_scan (thread_p, &proc->agg_hash_context->part_scan_id);
25034 
25035  /* free partial lists */
25036  if (proc->agg_hash_context->part_list_id != NULL)
25037  {
25038  qfile_close_list (thread_p, proc->agg_hash_context->part_list_id);
25039  qfile_destroy_list (thread_p, proc->agg_hash_context->part_list_id);
25040  qfile_free_list_id (proc->agg_hash_context->part_list_id);
25041  proc->agg_hash_context->part_list_id = NULL;
25042  }
25043 
25044  if (proc->agg_hash_context->sorted_part_list_id != NULL)
25045  {
25046  qfile_close_list (thread_p, proc->agg_hash_context->sorted_part_list_id);
25047  qfile_destroy_list (thread_p, proc->agg_hash_context->sorted_part_list_id);
25048  qfile_free_list_id (proc->agg_hash_context->sorted_part_list_id);
25049  proc->agg_hash_context->sorted_part_list_id = NULL;
25050  }
25051 
25052  /* free temp keys and values */
25053  if (proc->agg_hash_context->temp_key != NULL)
25054  {
25055  qdata_free_agg_hkey (thread_p, proc->agg_hash_context->temp_key);
25056  proc->agg_hash_context->temp_key = NULL;
25057  }
25058 
25059  if (proc->agg_hash_context->temp_part_key != NULL)
25060  {
25061  qdata_free_agg_hkey (thread_p, proc->agg_hash_context->temp_part_key);
25062  proc->agg_hash_context->temp_part_key = NULL;
25063  }
25064 
25065  if (proc->agg_hash_context->curr_part_key != NULL)
25066  {
25067  qdata_free_agg_hkey (thread_p, proc->agg_hash_context->curr_part_key);
25068  proc->agg_hash_context->curr_part_key = NULL;
25069  }
25070 
25071  if (proc->agg_hash_context->temp_part_value != NULL)
25072  {
25073  qdata_free_agg_hvalue (thread_p, proc->agg_hash_context->temp_part_value);
25074  proc->agg_hash_context->temp_part_value = NULL;
25075  }
25076 
25077  if (proc->agg_hash_context->curr_part_value != NULL)
25078  {
25079  qdata_free_agg_hvalue (thread_p, proc->agg_hash_context->curr_part_value);
25080  proc->agg_hash_context->curr_part_value = NULL;
25081  }
25082 
25083  /* free recdes area */
25084  if (proc->agg_hash_context->tuple_recdes.data != NULL)
25085  {
25086  db_private_free (thread_p, proc->agg_hash_context->tuple_recdes.data);
25087  proc->agg_hash_context->tuple_recdes.data = NULL;
25088  proc->agg_hash_context->tuple_recdes.area_size = 0;
25089  }
25090 
25091  /* reinit counters */
25092  proc->agg_hash_context->hash_size = 0;
25093  proc->agg_hash_context->group_count = 0;
25094  proc->agg_hash_context->tuple_count = 0;
25095 }
25096 
25097 /*
25098  * qexec_build_agg_hkey () - build aggregate key structure from reguvar list
25099  * returns: NO_ERROR or error code
25100  * thread_p(in): thread
25101  * key(out): aggregate key
25102  * regu_list(in): reguvar list for fetching values
25103  *
25104  * NOTE: the DB_VALUEs in the key structure are transient. If key will be
25105  * stored for later use, a deep copy of DB_VALUEs must be performed using
25106  * qexec_copy_agg_key().
25107  */
25108 static int
25110  AGGREGATE_HASH_KEY * key)
25111 {
25112  int rc = NO_ERROR;
25113 
25114  /* build key */
25115  key->free_values = false; /* references precreated DB_VALUES */
25116  key->val_count = 0;
25117  while (regu_list != NULL)
25118  {
25119  rc =
25120  fetch_peek_dbval (thread_p, &regu_list->value, &xasl_state->vd, NULL, NULL, tpl, &key->values[key->val_count]);
25121  if (rc != NO_ERROR)
25122  {
25123  return rc;
25124  }
25125 
25126  /* next */
25127  regu_list = regu_list->next;
25128  key->val_count++;
25129  }
25130 
25131  /* all ok */
25132  return NO_ERROR;
25133 }
25134 
25135 /*
25136  * qexec_locate_agg_hentry_in_list () - find the next hash entry with the
25137  * provided key
25138  * return: error code or NO_ERROR
25139  * thread_p(in): thread
25140  * context(in): hash context
25141  * key(in): desired key
25142  * found(out): true if found, false otherwise
25143  */
25144 static int
25146  bool * found)
25147 {
25148  DB_VALUE_COMPARE_RESULT result;
25149  bool done = false;
25150  int diff_pos;
25151 
25152  while (!done)
25153  {
25154  /* stop on last scan (or error) */
25155  done = (context->part_scan_code != S_SUCCESS);
25156 
25157  /* compare keys and invert if necessary */
25158  result = qdata_agg_hkey_compare (context->curr_part_key, key, &diff_pos);
25159  if (diff_pos >= 0 && result != DB_EQ)
25160  {
25161  if (context->sort_key.key[diff_pos].is_desc)
25162  {
25163  if (result == DB_GT)
25164  {
25165  result = DB_LT;
25166  }
25167  else if (result == DB_LT)
25168  {
25169  result = DB_GT;
25170  }
25171  }
25172  }
25173 
25174  /* decide based on comparison result */
25175  if (result == DB_UNK || result == DB_NE)
25176  {
25177  /* incomparable types or null value; should not get here */
25178  return ER_FAILED;
25179  }
25180  else if (result == DB_EQ)
25181  {
25182  /* found key */
25183  *found = true;
25184  return NO_ERROR;
25185  }
25186  else if (result == DB_GT)
25187  {
25188  /* current key in partial list is greater than provided key */
25189  *found = false;
25190  return NO_ERROR;
25191  }
25192  else if (!done)
25193  {
25194  /* scan for next */
25195  context->part_scan_code =
25196  qdata_load_agg_hentry_from_list (thread_p, &context->part_scan_id, context->curr_part_key,
25197  context->curr_part_value, context->key_domains,
25198  context->accumulator_domains);
25199  }
25200  }
25201 
25202  /* reached end of scan, no match */
25203  *found = false;
25204  return (context->part_scan_code == S_ERROR ? ER_FAILED : NO_ERROR);
25205 }
#define QFILE_TUPLE_VALUE_HEADER_SIZE
Definition: query_list.h:229
QPROC_QUALIFICATION qualification
Definition: scan_manager.h:346
static int qexec_execute_insert(THREAD_ENTRY *thread_p, XASL_NODE *xasl, XASL_STATE *xasl_state, bool skip_aptr)
QPROC_SINGLE_FETCH single_fetch
Definition: query_list.h:339
AGGREGATE_HASH_CONTEXT * agg_hash_context
TP_DOMAIN tp_String_domain
pred_expr * lhs
int qfile_reallocate_tuple(QFILE_TUPLE_RECORD *tuple_record_p, int tuple_size)
Definition: list_file.c:3010
regu_variable_node * key1
Definition: access_spec.hpp:67
char * PAGE_PTR
#define OID_INITIALIZER
Definition: oid.h:36
static QFILE_LIST_ID * qexec_merge_list_outer(THREAD_ENTRY *thread_p, SCAN_ID *outer_sid, SCAN_ID *inner_sid, QFILE_LIST_MERGE_INFO *merge_infop, PRED_EXPR *other_outer_join_pred, XASL_STATE *xasl_state, int ls_flag)
static int qexec_check_for_cycle(THREAD_ENTRY *thread_p, OUTPTR_LIST *outptr_list, QFILE_TUPLE tpl, QFILE_TUPLE_VALUE_TYPE_LIST *type_list, QFILE_LIST_ID *list_id_p, int *iscycle)
static int qexec_analytic_eval_instnum_pred(THREAD_ENTRY *thread_p, ANALYTIC_STATE *analytic_state, ANALYTIC_STAGE stage)
aggregate_hash_key * qdata_copy_agg_hkey(cubthread::entry *thread_p, aggregate_hash_key *key)
#define QFILE_CLEAR_LIST_ID(list_id)
Definition: query_list.h:445
int * mvcc_extra_assign_reev
Definition: xasl.h:243
HENTRY_PTR act_next
Definition: memory_hash.h:44
union SORT_REC::@159 s
#define ER_LK_UNILATERALLY_ABORTED
Definition: error_code.h:130
int qfile_generate_tuple_into_list(THREAD_ENTRY *thread_p, QFILE_LIST_ID *list_id_p, QFILE_TUPLE_TYPE tuple_type)
Definition: list_file.c:1749
OUTPTR_LIST * outptr_list
Definition: xasl.h:968
#define XASL_WAIT_MSECS_NOCHANGE
Definition: xasl.h:454
int data_readval(struct or_buf *buf, DB_VALUE *value, const tp_domain *domain, int size, bool copy, char *copy_buf, int copy_buf_len) const
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)
static DB_OBJLIST * internal_classes
aggregate_hash_value * qdata_alloc_agg_hvalue(cubthread::entry *thread_p, int func_cnt, cubxasl::aggregate_list_node *g_agg_list)
int qdata_get_valptr_type_list(THREAD_ENTRY *thread_p, valptr_list_node *valptr_list_p, qfile_tuple_value_type_list *type_list_p)
REGU_VARIABLE_LIST prior_regu_list_pred
Definition: xasl.h:427
int num_extra_assign_reev
Definition: xasl.h:242
static int qexec_gby_init_group_dim(GROUPBY_STATE *gbstate)
SORT_LIST * orderby_list
Definition: xasl.h:957
#define ACCESS_SPEC_HFID(ptr)
Definition: xasl.h:803
static void qexec_reset_pseudocolumns_val_pointers(DB_VALUE *level_valp, DB_VALUE *isleaf_valp, DB_VALUE *iscycle_valp, DB_VALUE *parent_pos_valp, DB_VALUE *index_valp)
SORTKEY_INFO * qfile_initialize_sort_key_info(SORTKEY_INFO *key_info_p, SORT_LIST *list_p, QFILE_TUPLE_VALUE_TYPE_LIST *types)
Definition: list_file.c:3728
OR_ATTRIBUTE * shared_attrs
TP_DOMAIN_STATUS tp_value_coerce(const DB_VALUE *src, DB_VALUE *dest, const TP_DOMAIN *desired_domain)
DB_VALUE * heap_attrvalue_get_key(THREAD_ENTRY *thread_p, int btid_index, HEAP_CACHE_ATTRINFO *idx_attrinfo, RECDES *recdes, BTID *btid, DB_VALUE *db_value, char *buf, FUNC_PRED_UNPACK_INFO *func_indx_pred, TP_DOMAIN **key_domain)
Definition: heap_file.c:12802
REGU_VALUE_ITEM * regu_list
Definition: regu_var.hpp:105
#define QFILE_GET_TUPLE_VALUE_HEADER_POSITION(tpl, ind, valp)
Definition: query_list.h:262
OID * oid_Root_class_oid
Definition: oid.c:73
XASL_NODE * eptr_list
int db_make_datetime(DB_VALUE *value, const DB_DATETIME *datetime)
analytic_ntile_function_info ntile
int db_value_coerce(const DB_VALUE *src, DB_VALUE *dest, const DB_DOMAIN *desired_domain)
Definition: db_macro.c:1779
#define NO_ERROR
Definition: error_code.h:46
static void qexec_clear_connect_by_lists(THREAD_ENTRY *thread_p, XASL_NODE *xasl)
aggregate_specific_function_info info
SORTKEY_INFO key_info
static int qexec_analytic_evaluate_interpolation_function(THREAD_ENTRY *thread_p, ANALYTIC_FUNCTION_STATE *func_state)
int area_size
PRED_EXPR * set_pred
Definition: xasl.h:298
static int qexec_hash_gby_put_next(THREAD_ENTRY *thread_p, const RECDES *recdes, void *arg)
static int qexec_build_agg_hkey(THREAD_ENTRY *thread_p, XASL_STATE *xasl_state, REGU_VARIABLE_LIST regu_list, QFILE_TUPLE tpl, AGGREGATE_HASH_KEY *key)
QFILE_TUPLE_RECORD * output_tplrec
VAL_LIST * prior_val_list
Definition: xasl.h:425
bool caches_inited
Definition: scan_manager.h:219
DB_COLLECTION * db_get_set(const DB_VALUE *value)
int qfile_save_tuple(QFILE_TUPLE_DESCRIPTOR *tuple_descr_p, QFILE_TUPLE_TYPE tuple_type, char *page_p, int *tuple_length_p)
Definition: list_file.c:1705
MVCC_SNAPSHOT * logtb_get_mvcc_snapshot(THREAD_ENTRY *thread_p)
HEAP_CACHE_ATTRINFO * cache_pred
Definition: xasl.h:733
int mht_clear(MHT_TABLE *ht, int(*rem_func)(const void *key, void *data, void *args), void *func_args)
Definition: memory_hash.c:1180
static SORT_STATUS qexec_gby_get_next(THREAD_ENTRY *thread_p, RECDES *recdes, void *arg)
XASL_NODE * fptr_list
Definition: xasl.h:984
DB_VALUE ** key_info_values
Definition: scan_manager.h:227
QUERY_ID query_id
SCANCACHE_LIST * next
Definition: partition_sr.h:62
void qmgr_set_query_error(THREAD_ENTRY *thread_p, QUERY_ID query_id)
key_range * key_ranges
Definition: access_spec.hpp:75
static int qexec_iterate_connect_by_results(THREAD_ENTRY *thread_p, XASL_NODE *xasl, XASL_STATE *xasl_state, QFILE_TUPLE_RECORD *tplrec)
REGU_VARIABLE_LIST operand
Definition: regu_var.hpp:143
static void qexec_clear_groupby_state(THREAD_ENTRY *thread_p, GROUPBY_STATE *gbstate)
DB_VALUE * save_instnum_val
Definition: xasl.h:981
#define IO_PAGESIZE
LLIST_SCAN_ID llsid
Definition: scan_manager.h:353
STATIC_INLINE int or_get_varchar_compression_lengths(OR_BUF *buf, int *compressed_size, int *decompressed_size) __attribute__((ALWAYS_INLINE))
static int qexec_analytic_finalize_group(THREAD_ENTRY *thread_p, XASL_STATE *xasl_state, ANALYTIC_FUNCTION_STATE *func_state, bool is_same_group)
REPL_INFO_TYPE
Definition: replication.h:43
ACCESS_SPEC_TYPE * merge_spec
Definition: xasl.h:971
DB_VALUE_COMPARE_RESULT tp_value_compare(const DB_VALUE *value1, const DB_VALUE *value2, int allow_coercion, int total_order)
static int qexec_clear_access_spec_list(THREAD_ENTRY *thread_p, XASL_NODE *xasl_p, ACCESS_SPEC_TYPE *list, bool is_final)
TP_DOMAIN tp_Variable_domain
DB_VALUE * grbynum_val
struct qmgr_temp_file * tfile_vfid
Definition: query_list.h:440
update_mvcc_reev_assignment * curr_assigns
OR_FUNCTION_INDEX * func_index_info
regu_variable_node * key_limit_u
Definition: access_spec.hpp:81
static int qexec_ordby_put_next(THREAD_ENTRY *thread_p, const RECDES *recdes, void *arg)
#define ASSERT_ERROR()
SCAN_CODE
SCAN_ATTRS pred_attrs
Definition: scan_manager.h:102
ANALYTIC_TYPE * func_p
int qdata_get_single_tuple_from_list_id(THREAD_ENTRY *thread_p, qfile_list_id *list_id_p, val_list_node *single_tuple_p)
QFILE_TUPLE_VALUE_TYPE_LIST type_list
Definition: query_list.h:428
bool caches_inited
Definition: scan_manager.h:105
REGU_DATATYPE type
Definition: regu_var.hpp:172
QUERY_ID query_id
Definition: query_list.h:438
#define XASL_TO_BE_CACHED
Definition: xasl.h:481
REGU_VARIABLE_LIST cls_regu_list_key
Definition: xasl.h:719
QFILE_LIST_SCAN_ID value_scan_id
REGU_VARIABLE * rightptr
Definition: regu_var.hpp:129
PAGE_PTR last_pgptr
Definition: query_list.h:434
VAL_LIST * a_val_list
Definition: xasl.h:327
int g_hash_eligible
Definition: xasl.h:330
QFILE_LIST_ID * list_id
Definition: scan_manager.h:249
static void qexec_clear_analytic_state(THREAD_ENTRY *thread_p, ANALYTIC_STATE *analytic_state)
multi_index_unique_stats m_unique_stats
REGU_VARIABLE * value
Definition: regu_var.hpp:96
OUTPTR_LIST * a_outptr_list_interm
Definition: xasl.h:326
static int qexec_analytic_sort_key_header_load(ANALYTIC_FUNCTION_STATE *func_state, bool load_value)
#define ER_MVCC_SERIALIZABLE_CONFLICT
Definition: error_code.h:1484
#define QFILE_PUT_TUPLE_VALUE_FLAG(ptr, val)
Definition: query_list.h:256
#define QFILE_FREE_AND_INIT_LIST_ID(list_id)
Definition: list_file.h:56
static void qexec_reset_regu_variable_list(REGU_VARIABLE_LIST list)
bool cache_last_fix_page
Definition: heap_file.h:148
int partition_load_aggregate_helper(PRUNING_CONTEXT *pcontext, access_spec_node *spec, int pruned_count, BTID *root_btid, HIERARCHY_AGGREGATE_HELPER *helper)
Definition: partition.c:3639
SCAN_TYPE type
Definition: scan_manager.h:332
PRED_EXPR * if_pred
Definition: xasl.h:978
regu_variable_node * m_json_reguvar
int locator_start_force_scan_cache(THREAD_ENTRY *thread_p, HEAP_SCANCACHE *scan_cache, const HFID *hfid, const OID *class_oid, int op_type)
Definition: locator_sr.c:3985
QFILE_LIST_ID * output_file
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
DB_CONST_C_BIT db_get_bit(const DB_VALUE *value, int *length)
int needs_pruning
Definition: xasl.h:236
int qexec_clear_list_cache_by_class(THREAD_ENTRY *thread_p, const OID *class_oid)
#define TP_IS_SET_TYPE(typenum)
void locator_free_copy_area(LC_COPYAREA *copyarea)
Definition: locator.c:534
BUILDVALUE_PROC_NODE buildvalue
Definition: xasl.h:1020
#define ER_LK_OBJECT_DL_TIMEOUT_CLASS_MSG
Definition: error_code.h:1204
int qfile_get_tuple(THREAD_ENTRY *thread_p, PAGE_PTR first_page_p, QFILE_TUPLE tuple, QFILE_TUPLE_RECORD *tuple_record_p, QFILE_LIST_ID *list_id_p)
Definition: list_file.c:4211
unsigned int qdata_hash_agg_hkey(const void *key, unsigned int ht_size)
static int qexec_analytic_value_advance(THREAD_ENTRY *thread_p, ANALYTIC_FUNCTION_STATE *func_state, int amount, int max_group_changes, bool ignore_nulls)
void bh_down_heap(BINARY_HEAP *heap, int index)
Definition: binaryheap.c:79
int session_clear_trace_stats(THREAD_ENTRY *thread_p)
Definition: session.c:2916
GROUPBY_DIMENSION * g_dim
#define XASL_HAS_CONNECT_BY
Definition: xasl.h:483
int db_seq_get(DB_SET *set, int index, DB_VALUE *value)
Definition: db_set.c:712
int db_get_int(const DB_VALUE *value)
int db_make_bigint(DB_VALUE *value, const DB_BIGINT num)
analytic_list_node * head
QPROC_SINGLE_FETCH
Definition: query_list.h:326
static void qexec_clear_sort_list(XASL_NODE *xasl_p, SORT_LIST *list, bool is_final)
static REGU_VARIABLE * replace_null_arith(REGU_VARIABLE *regu_var, DB_VALUE *set_dbval)
int partition_load_pruning_context(THREAD_ENTRY *thread_p, const OID *class_oid, int pruning_type, PRUNING_CONTEXT *pinfo)
Definition: partition.c:2249
ATTR_ID * attrids_key
Definition: xasl.h:728
#define ER_HEAP_NODATA_NEWADDRESS
Definition: error_code.h:107
int thread_get_recursion_depth(cubthread::entry *thread_p)
#define XASL_G_GRBYNUM_FLAG_SCAN_CONTINUE
Definition: xasl.h:471
#define ER_REFERENCE_TO_NON_REFERABLE_NOT_ALLOWED
Definition: error_code.h:1231
#define CONNECTBY_TUPLE_INDEX_STRING_MEM
FILE_TYPE file_type
Definition: heap_file.h:152
int qdata_get_tuple_value_size_from_dbval(DB_VALUE *dbval_p)
DB_TYPE
Definition: dbtype_def.h:670
regu_variable_node * src
PAGE_PTR qmgr_get_old_page(THREAD_ENTRY *thread_p, VPID *vpid_p, QMGR_TEMP_FILE *tfile_vfid_p)
static int qexec_execute_cte(THREAD_ENTRY *thread_p, XASL_NODE *xasl, XASL_STATE *xasl_state)
unsigned short count
Definition: dbtype_def.h:1033
static int qexec_execute_do_stmt(THREAD_ENTRY *thread_p, XASL_NODE *xasl, XASL_STATE *xasl_state)
INDX_INFO * indexptr
Definition: xasl.h:927
static int qexec_initialize_analytic_function_state(THREAD_ENTRY *thread_p, ANALYTIC_FUNCTION_STATE *func_state, ANALYTIC_TYPE *func_p, XASL_STATE *xasl_state)
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)
DB_C_DOUBLE db_get_double(const DB_VALUE *value)
DB_VALUE ** cache_reserved
Definition: xasl.h:738
#define ER_FAILED
Definition: error_code.h:47
TYPE_EVAL_TERM et_type
REGU_VARIABLE_LIST next
Definition: regu_var.hpp:221
bool ql_flag
Definition: xasl.h:300
const int REGU_VARIABLE_HIDDEN_COLUMN
Definition: regu_var.hpp:156
int wait_msecs
Definition: xasl.h:224
int db_datetime_decode(const DB_DATETIME *datetime, int *month, int *day, int *year, int *hour, int *minute, int *second, int *millisecond)
Definition: db_date.c:4574
OR_ATTRIBUTE * class_attrs
int * mvcc_reev_classes
Definition: xasl.h:412
void qdata_free_agg_hvalue(cubthread::entry *thread_p, aggregate_hash_value *value)
bool mvcc_is_mvcc_disabled_class(const OID *class_oid)
Definition: mvcc.c:616
UPDDEL_CLASS_INFO * classes
Definition: xasl.h:407
SORT_STATUS qfile_make_sort_key(THREAD_ENTRY *thread_p, SORTKEY_INFO *key_info_p, RECDES *key_record_p, QFILE_LIST_SCAN_ID *input_scan_p, QFILE_TUPLE_RECORD *tuple_record_p)
Definition: list_file.c:3090
int pr_get_compressed_data_from_buffer(struct or_buf *buf, char *data, int compressed_size, int expected_decompressed_size)
static void qexec_clear_all_lists(THREAD_ENTRY *thread_p, XASL_NODE *xasl_list)
static int qexec_setup_topn_proc(THREAD_ENTRY *thread_p, XASL_NODE *xasl, VAL_DESCR *vd)
#define ER_LK_OBJECT_TIMEOUT_SIMPLE_MSG
Definition: error_code.h:131
void bh_to_sorted_array(BINARY_HEAP *heap)
Definition: binaryheap.c:378
QFILE_SORT_SCAN_ID * s_id
REGU_VARIABLE * limit_row_count
Definition: xasl.h:983
struct analytic_state::@148 curr_sort_page
int SORT_PUT_FUNC(THREAD_ENTRY *thread_p, const RECDES *, void *)
Definition: external_sort.h:60
struct tp_domain * setdomain
Definition: object_domain.h:82
PRED_EXPR * grbynum_pred
static int qexec_analytic_update_group_result(THREAD_ENTRY *thread_p, ANALYTIC_STATE *analytic_state)
int mht_rem(MHT_TABLE *ht, const void *key, int(*rem_func)(const void *key, void *data, void *args), void *func_args)
Definition: memory_hash.c:1952
#define QEXEC_EMPTY_ACCESS_SPEC_SCAN(specp)
union xasl_node::@155 proc
#define MIN_NUM_ROWS_FOR_MULTI_DELETE
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
static void qexec_replace_prior_regu_vars_pred(THREAD_ENTRY *thread_p, PRED_EXPR *pred, XASL_NODE *xasl)
QFILE_LIST_ID * qfile_sort_list_with_func(THREAD_ENTRY *thread_p, QFILE_LIST_ID *list_id_p, SORT_LIST *sort_list_p, QUERY_OPTIONS option, int flag, SORT_GET_FUNC *get_func, SORT_PUT_FUNC *put_func, SORT_CMP_FUNC *cmp_func, void *extra_arg, int limit, bool do_close)
Definition: list_file.c:3912
#define SCAN_IS_INDEX_COVERED(iscan_id_p)
Definition: scan_manager.h:369
XASL_STATE * xasl_state
QFILE_LIST_ID * output_file
static int qexec_execute_increment(THREAD_ENTRY *thread_p, const OID *oid, const OID *class_oid, const HFID *class_hfid, ATTR_ID attrid, int n_increment, int pruning_type)
void set_filters(upddel_mvcc_cond_reeval &ureev)
bool has_delete
Definition: xasl.h:440
bool * is_desc_order
Definition: scan_manager.h:156
int qdata_evaluate_aggregate_optimize(cubthread::entry *thread_p, cubxasl::aggregate_list_node *agg_p, HFID *hfid_p, OID *super_oid)
#define OR_BUF_INIT(buf, data, size)
bool xcache_uses_clones(void)
Definition: xasl_cache.c:2468
REGU_VARIABLE * leftptr
Definition: regu_var.hpp:128
#define ER_QPROC_INVALID_XASLNODE
Definition: error_code.h:532
int no_logging
Definition: xasl.h:410
static int qexec_analytic_start_group(THREAD_ENTRY *thread_p, XASL_STATE *xasl_state, ANALYTIC_FUNCTION_STATE *func_state, const RECDES *key, bool reinit)
QFILE_LIST_MERGE_INFO ls_merge
Definition: xasl.h:363
int qdata_set_valptr_list_unbound(THREAD_ENTRY *thread_p, valptr_list_node *valptr_list_p, val_descr *val_desc_p)
Definition: query_opfunc.c:622
multi_index_unique_stats * m_index_stats
Definition: heap_file.h:151
static void qexec_clear_pos_desc(XASL_NODE *xasl_p, QFILE_TUPLE_VALUE_POSITION *position_descr, bool is_final)
OR_PARTITION * selected_partition
Definition: partition_sr.h:77
SHOWSTMT_TYPE show_type
Definition: xasl.h:758
static int qexec_start_connect_by_lists(THREAD_ENTRY *thread_p, XASL_NODE *xasl, XASL_STATE *xasl_state)
const void * mht_put(MHT_TABLE *ht, const void *key, void *data)
Definition: memory_hash.c:1778
regu_variable_node * elem
void qexec_replace_prior_regu_vars_prior_expr(THREAD_ENTRY *thread_p, regu_variable_node *regu, xasl_node *xasl, xasl_node *connect_by_ptr)
#define NO_SORT_LIMIT
Definition: external_sort.h:40
#define ASSERT_ERROR_AND_SET(error_code)
SCAN_ATTRS range_attrs
Definition: scan_manager.h:212
analytic_eval_type * next
XASL_NODE * xasl
ANALYTIC_FUNCTION_STATE * func_state_list
int xehash_destroy(THREAD_ENTRY *thread_p, EHID *ehid)
PRED_EXPR * g_grbynum_pred
Definition: xasl.h:316
OUTPTR_LIST * g_outptr_list
void * extra_arg
int num_val_lists
Definition: xasl.h:399
static int qexec_clear_arith_list(THREAD_ENTRY *thread_p, XASL_NODE *xasl_p, ARITH_TYPE *list, bool is_final)
bool thread_need_clear_trace(cubthread::entry *thread_p)
static int qexec_add_composite_lock(THREAD_ENTRY *thread_p, REGU_VARIABLE_LIST reg_var_list, XASL_STATE *xasl_state, LK_COMPOSITE_LOCK *composite_lock, int upd_del_cls_cnt, OID *default_cls_oid)
#define XASL_G_GRBYNUM_FLAG_LIMIT_GT_LT
Definition: xasl.h:475
void tz_get_session_tz_region(TZ_REGION *tz_region)
Definition: tz_support.c:767
PARENT_POS_INFO * stack
#define assert_release(e)
Definition: error_manager.h:96
QFILE_LIST_SCAN_ID * input_scan
#define LOG_CHECK_LOG_APPLIER(thread_p)
Definition: log_impl.h:240
int xtran_server_start_topop(THREAD_ENTRY *thread_p, LOG_LSA *topop_lsa)
TARGET_TYPE type
Definition: xasl.h:925
static GROUPBY_STATE * qexec_initialize_groupby_state(GROUPBY_STATE *gbstate, SORT_LIST *groupby_list, PRED_EXPR *having_pred, PRED_EXPR *grbynum_pred, DB_VALUE *grbynum_val, int grbynum_flag, XASL_NODE *eptr_list, AGGREGATE_TYPE *g_agg_list, REGU_VARIABLE_LIST g_regu_list, VAL_LIST *g_val_list, OUTPTR_LIST *g_outptr_list, REGU_VARIABLE_LIST g_hk_regu_list, bool with_rollup, int hash_eligible, AGGREGATE_HASH_CONTEXT *agg_hash_context, XASL_NODE *xasl, XASL_STATE *xasl_state, QFILE_TUPLE_VALUE_TYPE_LIST *type_list, QFILE_TUPLE_RECORD *tplrec)
const char * get_host_name() const
ATTR_ID * attrids_pred
Definition: xasl.h:732
#define QEXEC_CLEAR_AGG_LIST_VALUE(agg_list)
static void qexec_failure_line(int line, XASL_STATE *xasl_state)
int qfile_get_estimated_pages_for_sorting(QFILE_LIST_ID *list_id_p, SORTKEY_INFO *key_info_p)
Definition: list_file.c:3689
#define QEXEC_MERGE_OUTER_PREV_SCAN_PVALS(thread_p, pre)
union regu_variable_node::regu_data_value value
static int qexec_listfile_orderby(THREAD_ENTRY *thread_p, XASL_NODE *xasl, QFILE_LIST_ID *list_file, SORT_LIST *orderby_list, XASL_STATE *xasl_state, OUTPTR_LIST *outptr_list)
DB_VALUE_COMPARE_RESULT cmpval(const DB_VALUE *value, const DB_VALUE *value2, int do_coercion, int total_order, int *start_colp, int collation) const
XASL_NODE * inner_xasl
Definition: xasl.h:359
#define CTE_CURR_ITERATION_LAST_TUPLE(node)
REGU_VARIABLE * orderby_limit
Definition: xasl.h:960
int lock_object(THREAD_ENTRY *thread_p, const OID *oid, const OID *class_oid, LOCK lock, int cond_flag)
static int qexec_execute_connect_by(THREAD_ENTRY *thread_p, XASL_NODE *xasl, XASL_STATE *xasl_state, QFILE_TUPLE_RECORD *tplrec)
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
void log_sysop_start(THREAD_ENTRY *thread_p)
Definition: log_manager.c:3578
#define HASH_AGGREGATE_VH_SELECTIVITY_THRESHOLD
static SCAN_CODE qexec_next_scan_block(THREAD_ENTRY *thread_p, XASL_NODE *xasl)
int heap_scancache_quick_start_root_hfid(THREAD_ENTRY *thread_p, HEAP_SCANCACHE *scan_cache)
Definition: heap_file.c:19255
void lock_abort_composite_lock(LK_COMPOSITE_LOCK *comp_lock)
int agg_domains_resolved
Definition: xasl.h:350
QUERY_OPTIONS option
Definition: xasl.h:967
#define XASL_LINK_TO_REGU_VARIABLE
Definition: xasl.h:477
int num_default_expr
Definition: xasl.h:389
UNION_PROC_NODE union_
Definition: xasl.h:1017
PRED_EXPR * ordbynum_pred
void set_scan_reevaluation(mvcc_scan_reev_data &scan)
int * mvcc_reev_classes
Definition: xasl.h:379
int db_make_date(DB_VALUE *value, const int month, const int day, const int year)
bool oid_is_serial(const OID *oid)
Definition: oid.c:159
struct timeval TSCTIMEVAL
Definition: tsc_timer.h:40
static DB_LOGICAL qexec_eval_instnum_pred(THREAD_ENTRY *thread_p, XASL_NODE *xasl, XASL_STATE *xasl_state)
#define OID_SET_NULL(oidp)
Definition: oid.h:85
ANALYTIC_EVAL_TYPE * a_eval_list
Definition: xasl.h:322
static int qexec_clear_regu_variable_list(THREAD_ENTRY *thread_p, XASL_NODE *xasl_p, REGU_VARIABLE_LIST list, bool is_final)
VALPTR_LIST ** valptr_lists
Definition: xasl.h:400
QFILE_TUPLE_RECORD value_tplrec
TP_DOMAIN tp_Object_domain
TP_DOMAIN * tp_domain_resolve_value(const DB_VALUE *val, TP_DOMAIN *dbuf)
DB_VALUE ** cache_recordinfo
Definition: scan_manager.h:108
void logtb_get_new_subtransaction_mvccid(THREAD_ENTRY *thread_p, MVCC_INFO *curr_mvcc_info)
char * data
int qdata_agg_hkey_eq(const void *key1, const void *key2)
#define TP_IS_STRING_TYPE(typeid)
LOG_TDES * LOG_FIND_TDES(int tran_index)
Definition: log_impl.h:1095
static void qexec_gby_finalize_group(THREAD_ENTRY *thread_p, GROUPBY_STATE *gbstate, int N, bool keep_list_file)
static void qexec_clear_pred_xasl(THREAD_ENTRY *thread_p, PRED_EXPR *pred)
void tsc_elapsed_time_usec(TSCTIMEVAL *tv, TSC_TICKS end_tick, TSC_TICKS start_tick)
Definition: tsc_timer.c:101
const char * db_default_expression_string(DB_DEFAULT_EXPR_TYPE default_expr_type)
Definition: db_macro.c:4947
aggregate_hash_key * qdata_alloc_agg_hkey(cubthread::entry *thread_p, int val_cnt, bool alloc_vals)
#define QEXEC_IS_MULTI_TABLE_UPDATE_DELETE(xasl)
static int qexec_compare_valptr_with_tuple(OUTPTR_LIST *outptr_list, QFILE_TUPLE tpl, QFILE_TUPLE_VALUE_TYPE_LIST *type_list, int *are_equal)
bool REGU_VARIABLE_IS_FLAGED(const regu_variable_node *regu, int flag)
Definition: regu_var.hpp:253
aggregate_accumulator accumulator
int has_uniques
Definition: xasl.h:237
#define OR_GET_BYTE(ptr)
bool valid
Definition: mvcc.h:178
int32_t pageid
Definition: dbtype_def.h:879
static int qexec_orderby_distinct(THREAD_ENTRY *thread_p, XASL_NODE *xasl, QUERY_OPTIONS option, XASL_STATE *xasl_state)
void set_cmpval_function(cmpval_function_type cmpval_arg)
int element_count
Definition: binaryheap.h:71
PR_TYPE tp_Integer
int tz_conv_tz_time_w_zone_name(const DB_TIME *time_source, const char *source_zone, int len_source, const char *dest_zone, int len_dest, DB_TIME *time_dest)
Definition: tz_support.c:1528
static int qexec_set_pseudocolumns_val_pointers(XASL_NODE *xasl, DB_VALUE **level_valp, DB_VALUE **isleaf_valp, DB_VALUE **iscycle_valp, DB_VALUE **parent_pos_valp, DB_VALUE **index_valp)
XASL_NODE * update_xasl
Definition: xasl.h:438
MERGELIST_PROC_NODE mergelist
Definition: xasl.h:1021
static void qexec_clear_db_val_list(QPROC_DB_VALUE_LIST list)
METHOD_SPEC_TYPE method_node
Definition: xasl.h:788
XASL_NODE * aptr_list
Definition: xasl.h:974
#define MULTI_ROW_DELETE
Definition: btree.h:57
#define BTID_IS_EQUAL(b1, b2)
TP_DOMAIN tp_Integer_domain
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
int qdata_save_agg_hentry_to_list(cubthread::entry *thread_p, aggregate_hash_key *key, aggregate_hash_value *value, DB_VALUE *temp_dbval_array, qfile_list_id *list_id)
PROC_TYPE type
Definition: xasl.h:953
static int qexec_execute_analytic(THREAD_ENTRY *thread_p, XASL_NODE *xasl, XASL_STATE *xasl_state, ANALYTIC_EVAL_TYPE *analytic_eval, QFILE_TUPLE_RECORD *tplrec, bool is_last)
void qdata_set_value_list_to_null(val_list_node *val_list_p)
Definition: query_opfunc.c:280
int btree_get_asc_desc(THREAD_ENTRY *thread_p, BTID *btid, int col_idx, int *asc_desc)
Definition: btree.c:18408
REL_OP
#define QPROC_IS_INTERPOLATION_FUNC(func_p)
Definition: xasl.h:531
OID class_oid
Definition: xasl.h:386
void scan_end_scan(THREAD_ENTRY *thread_p, SCAN_ID *scan_id)
#define QEXEC_MERGE_OUTER_PREV_SCAN(thread_p, pre)
void qfile_clear_list_id(QFILE_LIST_ID *list_id_p)
Definition: list_file.c:526
UPDDEL_CLASS_INFO * classes
Definition: xasl.h:370
REGU_VARIABLE_LIST g_regu_list
OUTPTR_LIST * a_outptr_list_interm
#define bool
Definition: dbi_compat.h:31
int bh_insert(BINARY_HEAP *heap, void *elem)
Definition: binaryheap.c:209
void * BH_CMP_ARG
Definition: binaryheap.h:40
#define PTR_ALIGN(addr, boundary)
Definition: memory_alloc.h:77
int no_logging
Definition: xasl.h:375
static int qexec_process_unique_stats(THREAD_ENTRY *thread_p, const OID *class_oid, UPDDEL_CLASS_INFO_INTERNAL *class_)
#define ER_QPROC_CYCLE_DETECTED
Definition: error_code.h:1224
#define MULTI_ROW_INSERT
Definition: btree.h:56
int qfile_update_domains_on_type_list(THREAD_ENTRY *thread_p, QFILE_LIST_ID *list_id_p, valptr_list_node *valptr_list_p)
Definition: list_file.c:6078
int tz_conv_tz_datetime_w_region(const DB_DATETIME *src_dt, const TZ_REGION *src_tz_region, const TZ_REGION *dest_tz_region, DB_DATETIME *dest_dt, TZ_ID *src_tz_id_out, TZ_ID *dest_tz_id_out)
Definition: tz_support.c:3812
bool * clear_f_val_at_clone_decache
Definition: query_list.h:373
#define OID_AS_ARGS(oidp)
Definition: oid.h:39
#define QEXEC_MERGE_OUTER_NEXT_SCAN_PVALS(thread_p, pre, e)
DB_VALUE * arg
Definition: xasl.h:297
int session_reset_cur_insert_id(THREAD_ENTRY *thread_p)
Definition: session.c:1473
static int qexec_analytic_group_header_load(ANALYTIC_FUNCTION_STATE *func_state)
int num_reev_classes
Definition: xasl.h:411
BUILDLIST_PROC_NODE buildlist
Definition: xasl.h:1019
static int qexec_merge_listfiles(THREAD_ENTRY *thread_p, XASL_NODE *xasl, XASL_STATE *xasl_state)
PRUNING_SCAN_CACHE * locator_get_partition_scancache(PRUNING_CONTEXT *pcontext, const OID *class_oid, const HFID *hfid, int op_type, bool has_function_indexes)
Definition: locator_sr.c:12259
#define ER_MAX_RECURSION_SQL_DEPTH
Definition: error_code.h:1453
QFILE_TUPLE_DESCRIPTOR tpl_descr
Definition: query_list.h:441
bool thread_is_on_trace(cubthread::entry *thread_p)
TP_DOMAIN tp_Null_domain
enum tp_domain_status TP_DOMAIN_STATUS
#define er_log_debug(...)
int db_timestamp_encode_sys(const DB_DATE *date, const DB_TIME *timeval, DB_TIMESTAMP *utime, TZ_ID *dest_tz_id)
Definition: db_date.c:617
int qdata_subtract_dbval(DB_VALUE *dbval1_p, DB_VALUE *dbval2_p, DB_VALUE *result_p, tp_domain *domain_p)
Definition: xasl.h:189
int lock_initialize_composite_lock(THREAD_ENTRY *thread_p, LK_COMPOSITE_LOCK *comp_lock)
HL_HEAPID db_change_private_heap(THREAD_ENTRY *thread_p, HL_HEAPID heap_id)
Definition: memory_alloc.c:337
int * attr_ids
Definition: xasl.h:266
regu_variable_node operand
#define ACCESS_SPEC_SET_PTR(ptr)
Definition: xasl.h:836
#define ACCESS_SPEC_SET_REGU_LIST(ptr)
Definition: xasl.h:839
cub_regex_object * compiled_regex
int * att_id
Definition: xasl.h:390
QFILE_LIST_SCAN_ID group_scan_id
void * mht_get2(const MHT_TABLE *ht, const void *key, void **last)
Definition: memory_hash.c:1496
HYBRID_NODE s
Definition: xasl.h:932
int heap_scancache_end(THREAD_ENTRY *thread_p, HEAP_SCANCACHE *scan_cache)
Definition: heap_file.c:7195
UPDATE_PROC_NODE update
Definition: xasl.h:1022
REPR_ID root_repr_id
Definition: partition_sr.h:71
aggregate_hash_value * temp_part_value
regu_variable_node * lhs
ACCESS_SPEC_TYPE * inner_spec_list
Definition: xasl.h:360
void qfile_clear_sort_key_info(SORTKEY_INFO *key_info_p)
Definition: list_file.c:3826
static int qexec_clear_update_assignment(THREAD_ENTRY *thread_p, XASL_NODE *xasl_p, UPDATE_ASSIGNMENT *assignment, bool is_final)
TP_DOMAIN tp_Json_domain
static DB_VALUE_COMPARE_RESULT bf2df_str_cmpdisk(void *mem1, void *mem2, TP_DOMAIN *domain, int do_coercion, int total_order, int *start_colp)
#define ER_NULL_CONSTRAINT_VIOLATION
Definition: error_code.h:762
static int qexec_hash_gby_agg_tuple(THREAD_ENTRY *thread_p, XASL_NODE *xasl, XASL_STATE *xasl_state, BUILDLIST_PROC_NODE *proc, QFILE_TUPLE_RECORD *tplrec, QFILE_TUPLE_DESCRIPTOR *tpldesc, QFILE_LIST_ID *groupby_list, bool *output_tuple)
DELETE_PROC_NODE delete_
Definition: xasl.h:1024
char * DB_C_BIT
Definition: dbtype_def.h:1158
#define MAX_ALIGNMENT
Definition: memory_alloc.h:70
static void qexec_analytic_add_tuple(THREAD_ENTRY *thread_p, ANALYTIC_STATE *analytic_state, QFILE_TUPLE tpl, int peek)
#define CATALOG_ACCESS_INFO_INITIALIZER
const int REGU_VARIABLE_FETCH_NOT_CONST
Definition: regu_var.hpp:164
static int qexec_prune_spec(THREAD_ENTRY *thread_p, ACCESS_SPEC_TYPE *spec, VAL_DESCR *vd, SCAN_OPERATION_TYPE scan_op_type)
DB_VALUE * g_grbynum_val
Definition: xasl.h:317
int qdata_evaluate_aggregate_hierarchy(cubthread::entry *thread_p, cubxasl::aggregate_list_node *agg_p, HFID *root_hfid, BTID *root_btid, hierarchy_aggregate_helper *helper)
int heap_attrinfo_start_with_index(THREAD_ENTRY *thread_p, OID *class_oid, RECDES *class_recdes, HEAP_CACHE_ATTRINFO *attr_info, HEAP_IDX_ELEMENTS_INFO *idx_info)
Definition: heap_file.c:11997
#define COPY_OID(dest_oid_ptr, src_oid_ptr)
Definition: oid.h:63
static int qexec_locate_agg_hentry_in_list(THREAD_ENTRY *thread_p, AGGREGATE_HASH_CONTEXT *context, AGGREGATE_HASH_KEY *key, bool *found)
QFILE_TUPLE_VALUE_FLAG qfile_locate_tuple_value(QFILE_TUPLE tuple, int index, char **tuple_value_p, int *value_size_p)
Definition: list_file.c:905
SORT_ORDER s_order
Definition: query_list.h:417
LOCK lock_get_object_lock(const OID *oid, const OID *class_oid)
static SCAN_CODE qexec_merge_fnc(THREAD_ENTRY *thread_p, XASL_NODE *xasl, XASL_STATE *xasl_state, QFILE_TUPLE_RECORD *tplrec, XASL_SCAN_FNC_PTR ignore)
static DEL_LOB_INFO * qexec_create_delete_lob_info(THREAD_ENTRY *thread_p, XASL_STATE *xasl_state, UPDDEL_CLASS_INFO_INTERNAL *class_info)
#define DBVAL_BUFSIZE
Definition: btree.h:449
DB_DOMAIN_INFO domain
Definition: dbtype_def.h:1082
int is_single_tuple
Definition: xasl.h:965
SELUPD_LIST * selected_upd_list
Definition: xasl.h:969
#define DB_VALUE_SCALE(value)
Definition: dbtype.h:74
DB_ELO * db_get_elo(const DB_VALUE *value)
#define XASL_ORDBYNUM_FLAG_SCAN_STOP
Definition: xasl.h:458
static DB_VALUE_COMPARE_RESULT qexec_cmp_tpl_vals_merge(QFILE_TUPLE *left_tval, TP_DOMAIN **left_dom, QFILE_TUPLE *rght_tval, TP_DOMAIN **rght_dom, int tval_cnt)
int xlogtb_reset_wait_msecs(THREAD_ENTRY *thread_p, int wait_msecs)
VAL_LIST * val_list
Definition: xasl.h:972
PRED_EXPR * ordbynum_pred
Definition: xasl.h:958
REGU_VARIABLE_LIST list_regu_list_probe
Definition: xasl.h:751
static int qexec_groupby(THREAD_ENTRY *thread_p, XASL_NODE *xasl, XASL_STATE *xasl_state, QFILE_TUPLE_RECORD *tplrec)
bool iscan_oid_order
Definition: xasl.h:1041
#define QEXEC_MERGE_NEXT_SCAN_PVALS(thread_p, pre, e)
REGU_VARIABLE_LIST list_regu_list_build
Definition: xasl.h:750
int catalog_start_access_with_dir_oid(THREAD_ENTRY *thread_p, CATALOG_ACCESS_INFO *catalog_access_info, LOCK lock_mode)
int db_elo_delete(DB_ELO *elo)
Definition: db_elo.c:115
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)
int qdata_get_agg_hvalue_size(aggregate_hash_value *value, bool ret_delta)
static int qexec_init_index_pseudocolumn_strings(THREAD_ENTRY *thread_p, char **father_index, int *len_father_index, char **son_index, int *len_son_index)
REGU_VARIABLE_LIST g_hk_regu_list
QFILE_LIST_ID * value_list_id
void THREAD_ENTRY
void xlogtb_set_interrupt(THREAD_ENTRY *thread_p, int set)
#define NULL_PAGEID
HEAP_SCANCACHE_NODE node
Definition: heap_file.h:144
DB_VALUE * val
Definition: xasl.h:196
int no_logging
Definition: xasl.h:396
#define QEXEC_MERGE_PREV_SCAN(thread_p, pre)
#define REINTERPRET_CAST(dest_type, expr)
Definition: porting.h:1080
void qdata_free_agg_hkey(cubthread::entry *thread_p, aggregate_hash_key *key)
TP_DOMAIN tp_Double_domain
DB_DEFAULT_EXPR_TYPE default_expr_type
Definition: dbtype_def.h:1204
static int qexec_orderby_distinct_by_sorting(THREAD_ENTRY *thread_p, XASL_NODE *xasl, QUERY_OPTIONS option, XASL_STATE *xasl_state)
TP_DOMAIN * original_domain
Definition: regu_var.hpp:126
int ATTR_ID
void set_data_cmpdisk_function(data_cmpdisk_function_type data_cmpdisk_arg)
HEAP_CACHE_ATTRINFO * attr_info
Definition: xasl.h:265
LOCK
QFILE_LIST_ID * output_file
const char * lang_get_collation_name(const int coll_id)
#define XASL_NEED_SINGLE_TUPLE_SCAN
Definition: xasl.h:492
KEY_INFO key_info
Definition: access_spec.hpp:91
static void qexec_gby_agg_tuple(THREAD_ENTRY *thread_p, GROUPBY_STATE *gbstate, QFILE_TUPLE tpl, int peek)
BTREE_SEARCH xbtree_find_unique(THREAD_ENTRY *thread_p, BTID *btid, SCAN_OPERATION_TYPE scan_op_type, DB_VALUE *key, OID *class_oid, OID *oid, bool is_all_class_srch)
Definition: btree.c:23990
#define ACCESS_SPEC_CONNECT_BY_LIST_ID(ptr)
Definition: xasl.h:827
ACCESS_METHOD access
Definition: xasl.h:926
int db_make_string(DB_VALUE *value, DB_CONST_C_CHAR str)
SCAN_OPERATION_TYPE scan_op_type
Definition: xasl.h:1005
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
static int qexec_analytic_put_next(THREAD_ENTRY *thread_p, const RECDES *recdes, void *arg)
static SCAN_CODE qexec_init_next_partition(THREAD_ENTRY *thread_p, ACCESS_SPEC_TYPE *spec)
UINT64 prm_get_bigint_value(PARAM_ID prm_id)
DB_LOGICAL eval_pred(THREAD_ENTRY *thread_p, const PRED_EXPR *pr, val_descr *vd, OID *obj_oid)
void port_close_memstream(FILE *fp, char **ptr, size_t *sizeloc)
Definition: porting.c:2220
int sort_listfile(THREAD_ENTRY *thread_p, INT16 volid, int est_inp_pg_cnt, SORT_GET_FUNC *get_fn, void *get_arg, SORT_PUT_FUNC *put_fn, void *put_arg, SORT_CMP_FUNC *cmp_fn, void *cmp_arg, SORT_DUP_OPTION option, int limit, bool includes_tde_class)
XASL_NODE * next
Definition: xasl.h:952
DB_BIGINT bigint
Definition: dbtype_def.h:1051
void mht_destroy(MHT_TABLE *ht)
Definition: memory_hash.c:1140
COUNT_OPTIM_STATE count_state
Definition: log_impl.h:407
SORT_LIST * qfile_allocate_sort_list(THREAD_ENTRY *thread_p, int count)
Definition: list_file.c:613
#define QFILE_GET_TUPLE_VALUE_FLAG(ptr)
Definition: query_list.h:250
bool pr_is_set_type(DB_TYPE type)
DB_DATA data
Definition: dbtype_def.h:1083
SORTKEY_INFO key_info
#define QFILE_MAX_TUPLE_SIZE_IN_PAGE
Definition: query_list.h:217
void partition_clear_pruning_context(PRUNING_CONTEXT *pinfo)
Definition: partition.c:2380
HEAP_CACHE_ATTRINFO * cache_rest
Definition: xasl.h:735
bool single_table_opt
Definition: xasl.h:431
GROUPBY_DIMENSION_FLAG d_flag
DB_VALUE * s_dbval
Definition: xasl.h:934
DB_DEFAULT_EXPR_TYPE on_update_expr
#define ACCESS_SPEC_METHOD_SIG_LIST(ptr)
Definition: xasl.h:854
int flag
Definition: xasl.h:954
QFILE_TUPLE_RECORD input_tplrec
PRED_EXPR * having_pred
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
unsigned int DB_TIMESTAMP
Definition: dbtype_def.h:759
PR_TYPE * pr_type_from_id(DB_TYPE id)
XASL_NODE * recursive_part
Definition: xasl.h:447
bool bh_is_full(BINARY_HEAP *heap)
Definition: binaryheap.c:469
int db_unix_timestamp(const DB_VALUE *src_date, DB_VALUE *result_timestamp)
DEL_LOB_INFO * crt_del_lob_info
EHID * xehash_create(THREAD_ENTRY *thread_p, EHID *ehid, DB_TYPE key_type, int exp_num_entries, OID *class_oid, int attr_id, bool is_tmp)
#define RECDES_INITIALIZER
AGGREGATE_TYPE * g_output_agg_list
int client_id
Definition: log_impl.h:481
TP_DOMAIN * tp_domain_resolve_default(DB_TYPE type)
int db_string_concatenate(const DB_VALUE *string1, const DB_VALUE *string2, DB_VALUE *result, DB_DATA_STATUS *data_status)
void er_set(int severity, const char *file_name, const int line_no, int err_id, int num_args,...)
int catalog_end_access_with_dir_oid(THREAD_ENTRY *thread_p, CATALOG_ACCESS_INFO *catalog_access_info, int error)
SCAN_CODE scan_reset_scan_block(THREAD_ENTRY *thread_p, SCAN_ID *s_id)
ACCESS_SPEC_TYPE * next
Definition: xasl.h:935
Definition: db_set.h:35
static int qexec_execute_obj_fetch(THREAD_ENTRY *thread_p, XASL_NODE *xasl, XASL_STATE *xasl_state, SCAN_OPERATION_TYPE scan_operation_type)
QPROC_QUALIFICATION * qualification
TOPN_STATUS
PRED_EXPR * start_with_pred
Definition: xasl.h:419
cubxasl::pred_expr * pred
Definition: regu_var.hpp:133
QFILE_TUPLE curr_tuple
Definition: xasl.h:432
int num_assigns
Definition: xasl.h:372
static void qexec_clear_mainblock_iterations(THREAD_ENTRY *thread_p, XASL_NODE *xasl)
analytic_percentile_function_info percentile
int db_set_get(DB_SET *set, int index, DB_VALUE *value)
Definition: db_set.c:508
static void qexec_replace_prior_regu_vars(THREAD_ENTRY *thread_p, REGU_VARIABLE *regu, XASL_NODE *xasl)
XASL_NODE * outer_xasl
Definition: xasl.h:356
void bh_destroy(THREAD_ENTRY *thread_p, BINARY_HEAP *heap)
Definition: binaryheap.c:157
#define XASL_SET_FLAG(x, f)
Definition: xasl.h:496
#define ACCESS_SPEC_METHOD_LIST_ID(ptr)
Definition: xasl.h:857
LOCK locator_get_lock_mode_from_op_type(SCAN_OPERATION_TYPE op_type)
Definition: locator_sr.c:13688
int db_value_put_encoded_time(DB_VALUE *value, const DB_TIME *time)
Definition: db_macro.c:1357
#define ER_QPROC_INVALID_PARAMETER
Definition: error_code.h:963
#define ACCESS_SPEC_RLIST_VALPTR_LIST(ptr)
Definition: xasl.h:830
#define DB_MAX_NUMERIC_PRECISION
Definition: dbtype_def.h:522
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
const char * or_get_constraint_comment(RECDES *record, const char *constraint_name)
#define assert(x)
QFILE_LIST_ID * qfile_combine_two_list(THREAD_ENTRY *thread_p, QFILE_LIST_ID *lhs_file_p, QFILE_LIST_ID *rhs_file_p, int flag)
Definition: list_file.c:2576
ACCESS_SPEC_TYPE * curr_spec
Definition: xasl.h:996
static int qexec_get_orderbynum_upper_bound(THREAD_ENTRY *tread_p, PRED_EXPR *pred, VAL_DESCR *vd, DB_VALUE *ubound)
QFILE_TUPLE_RECORD * tplrec1
Definition: query_list.h:380
REGU_VARIABLE * func_regu
Definition: xasl.h:277
bool qdump_print_xasl(xasl_node *xasl_p)
Definition: query_dump.c:2294
#define DB_NEED_CLEAR(v)
Definition: dbtype.h:83
int ordbynum_flag
Definition: xasl.h:961
const VOLID LOG_DBFIRST_VOLID
Definition: log_volids.hpp:38
#define XASL_TOP_MOST_XASL
Definition: xasl.h:480
QPROC_TPLDESCR_STATUS qdata_generate_tuple_desc_for_valptr_list(THREAD_ENTRY *thread_p, valptr_list_node *valptr_list_p, val_descr *val_desc_p, qfile_tuple_descriptor *tuple_desc_p)
Definition: query_opfunc.c:538
static BH_CMP_RESULT qexec_topn_cmpval(DB_VALUE *left, DB_VALUE *right, SORT_LIST *sort_spec)
CONNECTBY_PROC_NODE connect_by
Definition: xasl.h:1025
static SCAN_CODE qexec_intprt_fnc(THREAD_ENTRY *thread_p, XASL_NODE *xasl, XASL_STATE *xasl_state, QFILE_TUPLE_RECORD *tplrec, XASL_SCAN_FNC_PTR next_scan_fnc)
static int qexec_clear_pred(THREAD_ENTRY *thread_p, XASL_NODE *xasl_p, PRED_EXPR *pr, bool is_final)
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)
int use_desc_index
Definition: access_spec.hpp:94
SCAN_ATTRS pred_attrs
Definition: scan_manager.h:210
#define XASL_G_GRBYNUM_FLAG_SCAN_CHECK
Definition: xasl.h:472
regu_variable_list_node * key_info_regu_list
Definition: scan_manager.h:228
static int qexec_upddel_mvcc_set_filters(THREAD_ENTRY *thread_p, XASL_NODE *aptr_list, UPDDEL_MVCC_COND_REEVAL *mvcc_reev_class, OID *class_oid)
void fetch_init_val_list(regu_variable_list_node *regu_list)
Definition: fetch.c:4605
XASL_NODE * dptr_list
Definition: xasl.h:976
REGU_VARIABLE_LIST after_cb_regu_list_rest
Definition: xasl.h:430
#define DB_DOUBLE_DECIMAL_PRECISION
Definition: dbtype_def.h:592
int qfile_add_overflow_tuple_to_list(THREAD_ENTRY *thread_p, QFILE_LIST_ID *list_id_p, PAGE_PTR ovf_tuple_page_p, QFILE_LIST_ID *input_list_id_p)
Definition: list_file.c:2032
static int qexec_end_buildvalueblock_iterations(THREAD_ENTRY *thread_p, XASL_NODE *xasl, XASL_STATE *xasl_state, QFILE_TUPLE_RECORD *tplrec)
int prm_get_integer_value(PARAM_ID prm_id)
#define XASL_G_GRBYNUM_FLAG_SCAN_STOP
Definition: xasl.h:473
#define XASL_ORDBYNUM_FLAG_SCAN_CHECK
Definition: xasl.h:457
QPROC_TPLDESCR_STATUS
Definition: query_opfunc.h:47
PRUNING_SCAN_CACHE scan_cache
Definition: partition_sr.h:63
PRED_EXPR * where_range
Definition: xasl.h:931
PRED_EXPR * cons_pred
Definition: xasl.h:392
int num_vals
Definition: xasl.h:388
OR_DEFAULT_VALUE default_value
static UPDDEL_MVCC_COND_REEVAL * qexec_mvcc_cond_reev_set_scan_order(XASL_NODE *aptr, UPDDEL_MVCC_COND_REEVAL *reev_classes, int num_reev_classes, UPDDEL_CLASS_INFO *classes, int num_classes)
bool scan_immediately_stop
Definition: scan_manager.h:366
#define ER_BUILDVALUE_IN_REC_CTE
Definition: error_code.h:1543
int partition_find_root_class_oid(THREAD_ENTRY *thread_p, const OID *class_oid, OID *super_oid)
Definition: partition.c:2199
#define XASL_INSTNUM_FLAG_SCAN_LAST_STOP
Definition: xasl.h:463
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)
QFILE_LIST_SCAN_ID * interm_scan
QFILE_TUPLE_RECORD * output_tplrec
INSERT_PROC_NODE insert
Definition: xasl.h:1023
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
int qfile_set_tuple_column_value(THREAD_ENTRY *thread_p, QFILE_LIST_ID *list_id_p, PAGE_PTR curr_page_p, VPID *vpid_p, QFILE_TUPLE tuple_p, int col_num, DB_VALUE *value_p, TP_DOMAIN *domain_p)
Definition: list_file.c:6170
static ANALYTIC_STATE * qexec_initialize_analytic_state(THREAD_ENTRY *thread_p, ANALYTIC_STATE *analytic_state, ANALYTIC_TYPE *a_func_list, SORT_LIST *sort_list, REGU_VARIABLE_LIST a_regu_list, VAL_LIST *a_val_list, OUTPTR_LIST *a_outptr_list, OUTPTR_LIST *a_outptr_list_interm, bool is_last_run, XASL_NODE *xasl, XASL_STATE *xasl_state, QFILE_TUPLE_VALUE_TYPE_LIST *type_list, QFILE_TUPLE_RECORD *tplrec)
int partition_prune_unique_btid(PRUNING_CONTEXT *pcontext, DB_VALUE *key, OID *class_oid, HFID *class_hfid, BTID *btid)
Definition: partition.c:3553
OR_ATTRIBUTE * heap_locate_last_attrepr(ATTR_ID attrid, HEAP_CACHE_ATTRINFO *attr_info)
Definition: heap_file.c:10637
regu_variable_list_node * regu_list
int qfile_compare_all_sort_record(const void *pk0, const void *pk1, void *arg)
Definition: list_file.c:3586
static int qexec_merge_tuple(QFILE_TUPLE_RECORD *tplrec1, QFILE_TUPLE_RECORD *tplrec2, QFILE_LIST_MERGE_INFO *merge_info, QFILE_TUPLE_RECORD *tplrec)
struct sort_list * next
Definition: query_list.h:415
#define ER_OUT_OF_VIRTUAL_MEMORY
Definition: error_code.h:50
comp_eval_term et_comp
XSAL_SCAN_FUNC * XASL_SCAN_FNC_PTR
PAGE_PTR curr_pgptr
Definition: query_list.h:501
int qdata_finalize_aggregate_list(cubthread::entry *thread_p, cubxasl::aggregate_list_node *agg_list_p, bool keep_list_file)
static int qexec_fill_sort_limit(THREAD_ENTRY *thread_p, XASL_NODE *xasl, XASL_STATE *xasl_state, int *limit_ptr)
REGU_VARIABLE value
Definition: regu_var.hpp:222
int or_get_attrcomment(RECDES *record, int attrid, char **string, int *alloced_string)
int qdata_evaluate_analytic_func(cubthread::entry *thread_p, ANALYTIC_TYPE *func_p, VAL_DESCR *val_desc_p)
DB_TYPE db_value_type(const DB_VALUE *value)
bool clear_value_at_clone_decache
Definition: xasl.h:255
const char * db_json_get_schema_raw_from_validator(JSON_VALIDATOR *val)
Definition: db_json.cpp:2310
HEAP_CACHE_ATTRINFO attr_info
const char * qdump_operator_type_string(OPERATOR_TYPE optype)
Definition: query_dump.c:1016
static int qexec_recalc_tuples_parent_pos_in_list(THREAD_ENTRY *thread_p, QFILE_LIST_ID *list_id_p)
#define ANALYTIC_FUNC_SET_FLAG(x, f)
static int qexec_evaluate_partition_aggregates(THREAD_ENTRY *thread_p, ACCESS_SPEC_TYPE *spec, AGGREGATE_TYPE *agg_list, bool *is_scan_needed)
QFILE_LIST_ID * list_id
Definition: xasl.h:955
REGU_VARIABLE_LIST list_regu_list_pred
Definition: xasl.h:748
TRAN_ISOLATION logtb_find_current_isolation(THREAD_ENTRY *thread_p)
HEAP_CACHE_ATTRINFO * cache_range
Definition: xasl.h:742
#define SINGLE_ROW_UPDATE
Definition: btree.h:54
static ACCESS_SPEC_TYPE * query_multi_range_opt_check_specs(THREAD_ENTRY *thread_p, XASL_NODE *xasl)
const int REGU_VARIABLE_CLEAR_AT_CLONE_DECACHE
Definition: regu_var.hpp:165
static void qexec_resolve_domains_on_sort_list(SORT_LIST *order_list, REGU_VARIABLE_LIST reference_regu_list)
XASL_STATE * xasl_state
union cubxasl::pred_expr::@185 pe
int qdata_load_agg_hentry_from_tuple(cubthread::entry *thread_p, QFILE_TUPLE tuple, aggregate_hash_key *key, aggregate_hash_value *value, tp_domain **key_dom, cubxasl::aggregate_accumulator_domain **acc_dom)
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
BTREE_SEARCH
QFILE_TUPLE_RECORD input_tpl
OID class_oid
Definition: xasl.h:220
#define DB_VALUE_DOMAIN_TYPE(value)
Definition: dbtype.h:70
int db_value_free(DB_VALUE *value)
Definition: db_macro.c:1610
#define DB_INT32_MAX
Definition: dbtype_def.h:633
regu_variable_node * percentile_reguvar
static int qexec_gby_finalize_group_dim(THREAD_ENTRY *thread_p, GROUPBY_STATE *gbstate, const RECDES *recdes)
ACCESS_SPEC_FLAG flags
Definition: xasl.h:937
static void qexec_clear_scan_all_lists(THREAD_ENTRY *thread_p, XASL_NODE *xasl_list)
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)
#define ER_QUERY_EXECUTION_ERROR
Definition: error_code.h:1430
PRED_EXPR * pred_expr
UPDATE_ASSIGNMENT * assigns
Definition: xasl.h:373
struct function_node * funcp
Definition: regu_var.hpp:190
void * ehash_insert(THREAD_ENTRY *thread_p, EHID *ehid_p, void *key_p, OID *value_p)
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
#define TP_DOMAIN_COLLATION(dom)
static DB_LOGICAL qexec_eval_ordbynum_pred(THREAD_ENTRY *thread_p, ORDBYNUM_INFO *ordby_info)
#define TP_IS_NUMERIC_TYPE(typeid)
static void qexec_clear_topn_tuple(THREAD_ENTRY *thread_p, TOPN_TUPLE *tuple, int count)
struct upddel_class_info_internal UPDDEL_CLASS_INFO_INTERNAL
static int qexec_get_attr_default(THREAD_ENTRY *thread_p, OR_ATTRIBUTE *attr, DB_VALUE *default_val)
QMGR_TEMP_FILE * qmgr_create_new_temp_file(THREAD_ENTRY *thread_p, QUERY_ID query_id, QMGR_TEMP_FILE_MEMBUF_TYPE membuf_type)
REGU_VARIABLE_LIST cls_regu_val_list
Definition: xasl.h:725
struct drand48_data * rand_seed
Definition: regu_var.hpp:136
json_table_spec_node json_table_node
Definition: xasl.h:790
#define XASL_OBJFETCH_IGNORE_CLASSOID
Definition: xasl.h:486
#define IS_ANY_INDEX_ACCESS(access_)
Definition: xasl.h:699
int next_scan_on
Definition: xasl.h:998
#define VPID_EQ(vpid_ptr1, vpid_ptr2)
Definition: dbtype_def.h:915
int qdata_aggregate_accumulator_to_accumulator(cubthread::entry *thread_p, cubxasl::aggregate_accumulator *acc, cubxasl::aggregate_accumulator_domain *acc_dom, FUNC_TYPE func_type, tp_domain *func_domain, cubxasl::aggregate_accumulator *new_acc)
HEAP_ATTRVALUE * heap_attrvalue_locate(ATTR_ID attrid, HEAP_CACHE_ATTRINFO *attr_info)
Definition: heap_file.c:10590
#define min(a, b)
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)
REGU_VARIABLE_LIST method_regu_list
Definition: xasl.h:770
MVCC_INFO mvccinfo
Definition: log_impl.h:463
static int qexec_execute_merge(THREAD_ENTRY *thread_p, XASL_NODE *xasl, XASL_STATE *xasl_state)
REGU_VARIABLE * level_regu
Definition: xasl.h:989
SHOWSTMT_SPEC_TYPE showstmt_node
Definition: xasl.h:786
std::string db_user
int qexec_insert_tuple_into_list(THREAD_ENTRY *thread_p, qfile_list_id *list_id, valptr_list_node *outptr_list, val_descr *vd, qfile_tuple_record *tplrec)
short volid
Definition: dbtype_def.h:880
ARITH_TYPE * outarith_list
Definition: xasl.h:348
OUTPTR_LIST * a_outptr_list
TRAN_STATE xtran_server_end_topop(THREAD_ENTRY *thread_p, LOG_RESULT_TOPOP result, LOG_LSA *topop_lsa)
QFILE_TUPLE qfile_generate_sort_tuple(SORTKEY_INFO *key_info_p, SORT_REC *sort_record_p, RECDES *output_recdes_p)
Definition: list_file.c:3226
REGU_VARIABLE_LIST a_regu_list
Definition: xasl.h:323
TP_DOMAIN * col_dom
static void qexec_clear_internal_classes(THREAD_ENTRY *thread_p, UPDDEL_CLASS_INFO_INTERNAL *classes, int count)
#define PCOL_FIRST_TUPLE_OFFSET
Definition: xasl.h:542
#define OID_EQ(oidp1, oidp2)
Definition: oid.h:92
static QFILE_LIST_ID * qexec_merge_list(THREAD_ENTRY *thread_p, QFILE_LIST_ID *outer_list_idp, QFILE_LIST_ID *inner_list_idp, QFILE_LIST_MERGE_INFO *merge_infop, int ls_flag)
static void qexec_close_scan(THREAD_ENTRY *thread_p, ACCESS_SPEC_TYPE *curr_spec)
int qdata_get_agg_hkey_size(aggregate_hash_key *key)
static int qexec_execute_delete(THREAD_ENTRY *thread_p, XASL_NODE *xasl, XASL_STATE *xasl_state)
int db_string_put_cs_and_collation(DB_VALUE *value, const int codeset, const int collation_id)
Definition: db_macro.c:4164
#define heap_classrepr_free_and_init(class_repr, idxp)
Definition: heap_file.h:91
DB_VALUE * db_value_copy(DB_VALUE *value)
Definition: db_macro.c:1537
REGU_VALUE_ITEM * next
Definition: regu_var.hpp:97
SCAN_CODE scan_next_scan_block(THREAD_ENTRY *thread_p, SCAN_ID *s_id)
int qexec_clear_xasl(THREAD_ENTRY *thread_p, xasl_node *xasl, bool is_final)
TP_DOMAIN_STATUS tp_value_cast(const DB_VALUE *src, DB_VALUE *dest, const TP_DOMAIN *desired_domain, bool implicit_coercion)
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
static long qexec_size_remaining(QFILE_TUPLE_RECORD *tplrec1, QFILE_TUPLE_RECORD *tplrec2, QFILE_LIST_MERGE_INFO *merge_info, int k)
int locator_attribute_info_force(THREAD_ENTRY *thread_p, const HFID *hfid, OID *oid, HEAP_CACHE_ATTRINFO *attr_info, ATTR_ID *att_id, int n_att_id, LC_COPYAREA_OPERATION operation, int op_type, HEAP_SCANCACHE *scan_cache, int *force_count, bool not_check_fk, REPL_INFO_TYPE repl_info, int pruning_type, PRUNING_CONTEXT *pcontext, FUNC_PRED_UNPACK_INFO *func_preds, MVCC_REEV_DATA *mvcc_reev_data, UPDATE_INPLACE_STYLE force_update_inplace, RECDES *rec_descriptor, bool need_locking)
Definition: locator_sr.c:7311
#define TP_DOMAIN_TYPE(dom)
int pruning_type
Definition: xasl.h:398
REGU_VARIABLE * iscycle_regu
Definition: xasl.h:994
PRED_EXPR * after_connect_by_pred
Definition: xasl.h:420
aggregate_hash_value * curr_part_value
int db_datetime_to_timestamp(const DB_VALUE *src_datetime, DB_VALUE *result_timestamp)
update_mvcc_reev_assignment * next
#define ACCESS_SPEC_CLS_OID(ptr)
Definition: xasl.h:806
#define DB_SIZEOF(val)
Definition: memory_alloc.h:54
#define COMPOSITE_LOCK(scan_op_type)
#define PCOL_ISLEAF_TUPLE_OFFSET
Definition: xasl.h:538
#define XASL_NO_FIXED_SCAN
Definition: xasl.h:491
#define HASH_AGGREGATE_VH_SELECTIVITY_TUPLE_THRESHOLD
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
int qexec_clear_partition_expression(THREAD_ENTRY *thread_p, regu_variable_node *expr)
static int qexec_init_agg_hierarchy_helpers(THREAD_ENTRY *thread_p, ACCESS_SPEC_TYPE *spec, AGGREGATE_TYPE *aggregate_list, HIERARCHY_AGGREGATE_HELPER **helpers, int *helpers_countp)
#define XASL_HAS_NOCYCLE
Definition: xasl.h:482
#define XASL_MULTI_UPDATE_AGG
Definition: xasl.h:484
static void cleanup(int signo)
Definition: broker.c:717
int qexec_get_tuple_column_value(QFILE_TUPLE tpl, int index, DB_VALUE *valp, tp_domain *domain)
int qexec_start_mainblock_iterations(THREAD_ENTRY *thread_p, xasl_node *xasl, xasl_state *xasl_state)
#define QFILE_GET_TUPLE_VALUE_LENGTH(ptr)
Definition: query_list.h:253
void * mht_get(MHT_TABLE *ht, const void *key)
Definition: memory_hash.c:1419
SORT_LIST * sort_list
Definition: query_list.h:429
AGGREGATE_TYPE * d_agg_list
void lock_stop_instant_lock_mode(THREAD_ENTRY *thread_p, int tran_index, bool need_unlock)
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)
int g_agg_domains_resolved
Definition: xasl.h:339
int wait_msecs
Definition: xasl.h:374
DB_VALUE * isleaf_val
Definition: xasl.h:991
XASL_NODE * xasl
xasl_node * xasl
Definition: regu_var.hpp:178
#define NULL
Definition: freelistheap.h:34
int next_scan_block_on
Definition: xasl.h:999
static void qexec_destroy_upddel_ehash_files(THREAD_ENTRY *thread_p, XASL_NODE *buildlist)
#define HASH_AGGREGATE_DEFAULT_TABLE_SIZE
LIST_SPEC_TYPE list_node
Definition: xasl.h:785
int qfile_reopen_list_as_append_mode(THREAD_ENTRY *thread_p, QFILE_LIST_ID *list_id_p)
Definition: list_file.c:1284
int * att_id
Definition: xasl.h:235
ATTR_ID * attrids_rest
Definition: xasl.h:734
void qfile_free_sort_list(THREAD_ENTRY *thread_p, SORT_LIST *sort_list_p)
Definition: list_file.c:580
#define QFILE_TUPLE_LENGTH_SIZE
Definition: query_list.h:224
#define XASL_IS_FLAGED(x, f)
Definition: xasl.h:495
static int qexec_execute_duplicate_key_update(THREAD_ENTRY *thread_p, ODKU_INFO *odku, HFID *hfid, VAL_DESCR *vd, int op_type, HEAP_SCANCACHE *scan_cache, HEAP_CACHE_ATTRINFO *attr_info, HEAP_CACHE_ATTRINFO *index_attr_info, HEAP_IDX_ELEMENTS_INFO *idx_info, int pruning_type, PRUNING_CONTEXT *pcontext, int *force_count)
int ** lob_attr_ids
Definition: xasl.h:240
XASL_NODE * connect_by_ptr
Definition: xasl.h:987
int groupby_skip
Definition: access_spec.hpp:96
static SCAN_CODE qexec_next_merge_block(THREAD_ENTRY *thread_p, ACCESS_SPEC_TYPE **spec)
int heap_attrinfo_clear_dbvalues(HEAP_CACHE_ATTRINFO *attr_info)
Definition: heap_file.c:10022
upddel_mvcc_cond_reeval * mvcc_cond_reev_list
struct pr_type * type
Definition: object_domain.h:76
REGU_VARIABLE_LIST regu_list_rest
Definition: xasl.h:424
ACCESS_SCHEMA_TYPE schema_type
Definition: xasl.h:737
REGU_VARIABLE_LIST regu_list_pred
Definition: xasl.h:423
static void qexec_end_scan(THREAD_ENTRY *thread_p, ACCESS_SPEC_TYPE *curr_spec)
#define QFILE_GET_TUPLE_LENGTH(tpl)
Definition: query_list.h:238
int session_set_trace_stats(THREAD_ENTRY *thread_p, char *stats, int format)
Definition: session.c:2888
void tz_get_system_tz_region(TZ_REGION *tz_region)
Definition: tz_support.c:758
#define QPROC_SINGLE_CLASS_GROUPED_SCAN
OUTPTR_LIST * a_outptr_list_ex
Definition: xasl.h:325
UPDATE_MVCC_REEV_ASSIGNMENT * mvcc_reev_assigns
VAL_LIST * single_tuple
Definition: xasl.h:963
void * data
Definition: memory_hash.h:50
void tsc_getticks(TSC_TICKS *tck)
Definition: tsc_timer.c:81
Definition: btree.h:536
if(extra_options)
Definition: dynamic_load.c:958
bool bh_peek_max(BINARY_HEAP *heap, void *peek_elem)
Definition: binaryheap.c:357
static int qexec_clear_xasl_head(THREAD_ENTRY *thread_p, XASL_NODE *xasl)
int num_assigns
Definition: xasl.h:263
REGU_VARIABLE_LIST after_cb_regu_list_pred
Definition: xasl.h:429
#define XASL_DECACHE_CLONE
Definition: xasl.h:489
regu_variable_node * rhs
int lock_subclass(THREAD_ENTRY *thread_p, const OID *subclass_oid, const OID *superclass_oid, LOCK lock, int cond_flag)
int lock_add_composite_lock(THREAD_ENTRY *thread_p, LK_COMPOSITE_LOCK *comp_lock, const OID *oid, const OID *class_oid)
QFILE_TUPLE_VALUE_POSITION pos_descr
Definition: query_list.h:416
#define SCAN_IS_INDEX_MRO(iscan_id_p)
Definition: scan_manager.h:371
static int qexec_get_index_pseudocolumn_value_from_tuple(THREAD_ENTRY *thread_p, XASL_NODE *xasl, QFILE_TUPLE tpl, DB_VALUE **index_valp, char **index_value, int *index_len)
static int success()
static void qexec_gby_clear_group_dim(THREAD_ENTRY *thread_p, GROUPBY_STATE *gbstate)
HFID class_hfid
Definition: xasl.h:221
static void qexec_gby_finalize_group_val_list(THREAD_ENTRY *thread_p, GROUPBY_STATE *gbstate, int N)
int qfile_fast_intval_tuple_to_list(THREAD_ENTRY *thread_p, QFILE_LIST_ID *list_id_p, int v1, DB_VALUE *v2)
Definition: list_file.c:1862
#define SINGLE_ROW_DELETE
Definition: btree.h:53
static int qexec_schema_get_type_desc(DB_TYPE id, TP_DOMAIN *domain, DB_VALUE *result)
void qfile_update_qlist_count(THREAD_ENTRY *thread_p, const QFILE_LIST_ID *list_p, int inc)
Definition: list_file.c:6471
VAL_LIST * g_val_list
Definition: xasl.h:314
void locator_end_force_scan_cache(THREAD_ENTRY *thread_p, HEAP_SCANCACHE *scan_cache)
Definition: locator_sr.c:3999
static const char * qexec_schema_get_type_name_from_id(DB_TYPE id)
static int qexec_analytic_evaluate_ntile_function(THREAD_ENTRY *thread_p, ANALYTIC_FUNCTION_STATE *func_state)
#define ANALYTIC_KEEP_RANK
aggregate_list_node * next
int qdata_finalize_analytic_func(cubthread::entry *thread_p, ANALYTIC_TYPE *func_p, bool is_same_group)
static void qexec_resolve_domains_for_group_by(BUILDLIST_PROC_NODE *buildlist, OUTPTR_LIST *reference_out_list)
#define err(fd,...)
Definition: porting.h:431
#define db_private_free_and_init(thrd, ptr)
Definition: memory_alloc.h:141
int db_value_put_encoded_date(DB_VALUE *value, const DB_DATE *date)
Definition: db_macro.c:1383
void PRIM_SET_NULL(DB_VALUE *value)
static void qexec_free_agg_hash_context(THREAD_ENTRY *thread_p, BUILDLIST_PROC_NODE *proc)
static int qexec_init_instnum_val(XASL_NODE *xasl, THREAD_ENTRY *thread_p, XASL_STATE *xasl_state)
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)
MHT_TABLE * mht_create(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:894
XASL_NODE * insert_xasl
Definition: xasl.h:439
void partition_init_pruning_context(PRUNING_CONTEXT *pinfo)
Definition: partition.c:2164
#define QEXEC_MERGE_PVALS(pre)
REGU_VARIABLE_LIST list_regu_list_rest
Definition: xasl.h:749
int catalog_get_dir_oid_from_cache(THREAD_ENTRY *thread_p, const OID *class_id_p, OID *dir_oid_p)
int logtb_tran_update_unique_stats(THREAD_ENTRY *thread_p, const BTID *btid, int n_keys, int n_oids, int n_nulls, bool write_to_log)
#define db_private_free(thrd, ptr)
Definition: memory_alloc.h:229
void or_init(OR_BUF *buf, char *data, int length)
SCAN_OPERATION_TYPE
HENTRY_PTR act_head
Definition: memory_hash.h:61
DB_VALUE * value
Definition: regu_var.hpp:127
AGGREGATE_TYPE * agg_list
Definition: xasl.h:347
regu_variable_node * src
VFID vfid
SORT_CMP_FUNC * cmp_fn
enum groupby_dimension_flag GROUPBY_DIMENSION_FLAG
bool is_domain_resolved
Definition: query_list.h:442
#define XASL_USES_MRO
Definition: xasl.h:488
#define db_private_alloc(thrd, size)
Definition: memory_alloc.h:227
bool fetch_res
Definition: xasl.h:299
#define CONST_CAST(dest_type, expr)
Definition: porting.h:1060
SCAN_CODE scan_jump_scan_pos(THREAD_ENTRY *thread_p, SCAN_ID *s_id, SCAN_POS *scan_pos)
OR_PARTITION * partitions
Definition: partition_sr.h:76
static int qexec_resolve_domains_for_aggregation(THREAD_ENTRY *thread_p, AGGREGATE_TYPE *agg_p, XASL_STATE *xasl_state, QFILE_TUPLE_RECORD *tplrec, REGU_VARIABLE_LIST regu_list, int *resolved)
const OID oid_Null_oid
Definition: oid.c:68
QFILE_LIST_ID * push_list_id
Definition: xasl.h:311
LOG_TRAN_CLASS_COS * logtb_tran_find_class_cos(THREAD_ENTRY *thread_p, const OID *class_oid, bool create)
int query_in_progress
Definition: xasl.h:1002
static void qexec_reset_pred_expr(PRED_EXPR *pred)
SORT_REC * next
Definition: external_sort.h:70
need_clear_type need_clear
Definition: dbtype_def.h:1084
#define XASL_INSTNUM_FLAG_SCAN_STOP_AT_ANALYTIC
Definition: xasl.h:465
int or_set_rep_id(RECDES *record, int repid)
UPDDEL_MVCC_COND_REEVAL ** mvcc_extra_assign_reev
static int query_multi_range_opt_check_set_sort_col(THREAD_ENTRY *thread_p, XASL_NODE *xasl)
SORT_STATUS
Definition: external_sort.h:45
bool logtb_set_check_interrupt(THREAD_ENTRY *thread_p, bool flag)
static SORT_STATUS qexec_analytic_get_next(THREAD_ENTRY *thread_p, RECDES *recdes, void *arg)
static int qexec_create_internal_classes(THREAD_ENTRY *thread_p, UPDDEL_CLASS_INFO *classes_info, int count, UPDDEL_CLASS_INFO_INTERNAL **classes)
CLIENTIDS client
Definition: log_impl.h:484
int num_attrs_key
Definition: xasl.h:730
int db_set_size(DB_SET *set)
Definition: db_set.c:557
int qdata_evaluate_aggregate_list(cubthread::entry *thread_p, cubxasl::aggregate_list_node *agg_list_p, val_descr *val_desc_p, cubxasl::aggregate_accumulator *alt_acc_list)
OR_CLASSREP * heap_classrepr_get(THREAD_ENTRY *thread_p, const OID *class_oid, RECDES *class_recdes, REPR_ID reprid, int *idx_incache)
Definition: heap_file.c:2299
#define QFILE_PUT_TUPLE_VALUE_LENGTH(ptr, val)
Definition: query_list.h:259
int count(int &result, const cub_regex_object &reg, const std::string &src, const int position, const INTL_CODESET codeset)
#define cmp
Definition: mprec.h:351
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
int qdata_initialize_analytic_func(cubthread::entry *thread_p, ANALYTIC_TYPE *func_p, QUERY_ID query_id)
void qmgr_add_modified_class(THREAD_ENTRY *thread_p, const OID *class_oid_p)
HEAP_CACHE_ATTRINFO attr_info
#define XASL_G_GRBYNUM_FLAG_LIMIT_LT
Definition: xasl.h:474
DB_DOMAIN * db_type_to_db_domain(const DB_TYPE type)
Definition: db_macro.c:1710
#define PCOL_INDEX_STRING_TUPLE_OFFSET
Definition: xasl.h:540
DB_VALUE_COMPARE_RESULT qdata_agg_hkey_compare(aggregate_hash_key *ckey1, aggregate_hash_key *ckey2, int *diff_pos)
int db_make_time(DB_VALUE *value, const int hour, const int minute, const int second)
SCAN_CODE qdata_load_agg_hentry_from_list(cubthread::entry *thread_p, qfile_list_scan_id *list_scan_id, aggregate_hash_key *key, aggregate_hash_value *value, tp_domain **key_dom, cubxasl::aggregate_accumulator_domain **acc_dom)
OID * class_oid
Definition: xasl.h:232
#define VFID_COPY(vfid_ptr1, vfid_ptr2)
Definition: file_manager.h:69
#define DB_DEFAULT_SCALE
Definition: dbtype_def.h:561
int qexec_execute_mainblock(THREAD_ENTRY *thread_p, xasl_node *xasl, xasl_state *xstate, UPDDEL_CLASS_INSTANCE_LOCK_INFO *p_class_instance_lock_info)
void log_sysop_abort(THREAD_ENTRY *thread_p)
Definition: log_manager.c:4017
FETCH_PROC_NODE fetch
Definition: xasl.h:1018
#define NULL_REPRID
static int bf2df_str_son_index(THREAD_ENTRY *thread_p, char **son_index, char *father_index, int *len_son_index, int cnt)
AGGREGATE_TYPE * g_agg_list
Definition: xasl.h:318
static int qexec_collection_has_null(DB_VALUE *colval)
static int qexec_setup_list_id(THREAD_ENTRY *thread_p, XASL_NODE *xasl)
static int qexec_alloc_agg_hash_context(THREAD_ENTRY *thread_p, BUILDLIST_PROC_NODE *proc, XASL_STATE *xasl_state)
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)
#define ER_PT_EXECUTE
Definition: error_code.h:582
struct db_domain_info::general_info general_info
int64_t DB_BIGINT
Definition: dbtype_def.h:751
int num_attrs_rest
Definition: xasl.h:736
#define QFILE_SET_FLAG(var, flag)
Definition: query_list.h:522
#define PCOL_PARENTPOS_TUPLE_OFFSET
Definition: xasl.h:541
static int qexec_topn_tuples_to_list_id(THREAD_ENTRY *thread_p, XASL_NODE *xasl, XASL_STATE *xasl_state, bool is_final)
struct SORT_REC::@159::@160 original
analytic_stage
bool scancache_inited
Definition: scan_manager.h:106
PRED_EXPR * where_pred
Definition: xasl.h:930
PRED_EXPR * after_join_pred
Definition: xasl.h:977
HENTRY_PTR lru_head
Definition: memory_hash.h:65
void util_get_second_and_ms_since_epoch(time_t *secs, int *msec)
Definition: util_func.c:829
CTE_PROC_NODE cte
Definition: xasl.h:1027
XASL_NODE * eptr_list
Definition: xasl.h:308
static int qexec_merge_tuple_add_list(THREAD_ENTRY *thread_p, QFILE_LIST_ID *list_id, QFILE_TUPLE_RECORD *tplrec1, QFILE_TUPLE_RECORD *tplrec2, QFILE_LIST_MERGE_INFO *merge_info, QFILE_TUPLE_RECORD *tplrec)
DB_VALUE * dbval_ptr
void lock_start_instant_lock_mode(int tran_index)
static int qexec_execute_update(THREAD_ENTRY *thread_p, XASL_NODE *xasl, bool has_delete, XASL_STATE *xasl_state)
DB_ENUMERATION enumeration
Definition: object_domain.h:84
const char * envvar_get(const char *name)
#define TP_IS_CHAR_TYPE(typeid)
#define ER_BTREE_UNIQUE_FAILED
Definition: error_code.h:811
QFILE_LIST_ID * interm_file
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
LC_COPYAREA * locator_allocate_copy_area_by_attr_info(THREAD_ENTRY *thread_p, HEAP_CACHE_ATTRINFO *attr_info, RECDES *old_recdes, RECDES *new_recdes, const int copyarea_length_hint, int lob_create_flag)
Definition: locator_sr.c:7210
static int qexec_clear_regu_list(THREAD_ENTRY *thread_p, XASL_NODE *xasl_p, REGU_VARIABLE_LIST list, bool is_final)
#define MULTI_ROW_UPDATE
Definition: btree.h:58
void scan_close_scan(THREAD_ENTRY *thread_p, SCAN_ID *scan_id)
SCANCACHE_LIST * scan_cache_list
Definition: partition_sr.h:79
PRED_EXPR * cons_pred
Definition: xasl.h:371
#define XASL_SKIP_ORDERBY_LIST
Definition: xasl.h:478
int g_grbynum_flag
Definition: xasl.h:328
static int qexec_gby_put_next(THREAD_ENTRY *thread_p, const RECDES *recdes, void *arg)
static int rc
Definition: serial.c:50
static int qexec_remove_duplicates_for_replace(THREAD_ENTRY *thread_p, HEAP_SCANCACHE *scan_cache, HEAP_CACHE_ATTRINFO *attr_info, HEAP_CACHE_ATTRINFO *index_attr_info, const HEAP_IDX_ELEMENTS_INFO *idx_info, int op_type, int pruning_type, PRUNING_CONTEXT *pcontext, int *removed_count)
#define DB_DEFAULT_PRECISION
Definition: dbtype_def.h:558
STATIC_INLINE void perfmon_inc_stat(THREAD_ENTRY *thread_p, PERF_STAT_ID psid) __attribute__((ALWAYS_INLINE))
#define ER_INTERRUPTED
Definition: error_code.h:51
#define PCOL_ISCYCLE_TUPLE_OFFSET
Definition: xasl.h:537
void qfile_close_scan(THREAD_ENTRY *thread_p, QFILE_LIST_SCAN_ID *scan_id_p)
Definition: list_file.c:4774
SCAN_CODE heap_get_class_oid(THREAD_ENTRY *thread_p, const OID *oid, OID *class_oid)
Definition: heap_file.c:9285
aggregate_hash_key * curr_part_key
DB_VALUE * ordbynum_val
void qfile_free_list_id(QFILE_LIST_ID *list_id_p)
Definition: list_file.c:563
#define LOG_FIND_THREAD_TRAN_INDEX(thrd)
Definition: perf_monitor.h:158
#define TP_TYPE_HAS_COLLATION(typeid)
int g_output_first_tuple
Definition: xasl.h:331
static int qexec_execute_build_columns(THREAD_ENTRY *thread_p, XASL_NODE *xasl, XASL_STATE *xasl_state)
#define HFID_IS_NULL(hfid)
int catalog_get_last_representation_id(THREAD_ENTRY *thread_p, OID *class_oid_p, REPR_ID *repr_id_p)
SCAN_CODE locator_get_object(THREAD_ENTRY *thread_p, const OID *oid, OID *class_oid, RECDES *recdes, HEAP_SCANCACHE *scan_cache, SCAN_OPERATION_TYPE op_type, LOCK lock_mode, int ispeeking, int chn)
Definition: locator_sr.c:13175
char * or_class_name(RECDES *record)
bool db_value_is_null(const DB_VALUE *value)
val_list_node * val_list
Definition: scan_manager.h:349
#define ACCESS_SPEC_XASL_NODE(ptr)
Definition: xasl.h:821
EH_SEARCH
DB_DATETIME sys_datetime
LC_COPYAREA_OPERATION
Definition: locator.h:106
#define ARG_FILE_LINE
Definition: error_manager.h:44
PR_TYPE tp_String
bool qfile_is_sort_list_covered(SORT_LIST *covering_list_p, SORT_LIST *covered_list_p)
Definition: list_file.c:705
#define TSC_ADD_TIMEVAL(total, diff)
Definition: tsc_timer.h:31
VAL_LIST * g_val_list
#define XASL_INSTNUM_FLAG_SCAN_CONTINUE
Definition: xasl.h:460
static REGU_VARIABLE * replace_null_dbval(REGU_VARIABLE *regu_var, DB_VALUE *set_dbval)
analytic_function_info info
void set_update_reevaluation(mvcc_update_reev_data &urd)
#define OR_BYTE_SIZE
QFILE_TUPLE_RECORD * tplrecp
Definition: scan_manager.h:253
static DB_LOGICAL qexec_eval_grbynum_pred(THREAD_ENTRY *thread_p, GROUPBY_STATE *gbstate)
QFILE_LIST_ID list_id
Definition: query_list.h:507
static int qexec_create_mvcc_reev_assignments(THREAD_ENTRY *thread_p, XASL_NODE *aptr, bool should_delete, UPDDEL_CLASS_INFO_INTERNAL *classes, int num_classes, int num_assignments, UPDATE_ASSIGNMENT *assignments, UPDATE_MVCC_REEV_ASSIGNMENT **mvcc_reev_assigns)
void er_print_callstack(const char *file_name, const int line_no, const char *fmt,...)
XASL_NODE * left
Definition: xasl.h:289
int pr_clone_value(const DB_VALUE *src, DB_VALUE *dest)
VAL_LIST * outer_val_list
Definition: xasl.h:358
const int REGU_VARIABLE_STRICT_TYPE_CAST
Definition: regu_var.hpp:167
static const bool COPY
OID * db_get_oid(const DB_VALUE *value)
int valcnv_convert_value_to_string(DB_VALUE *value)
Definition: db_macro.c:4901
QFILE_TUPLE_VALUE_FLAG
Definition: query_list.h:291
const char * default_expr_format
Definition: dbtype_def.h:1206
cubxasl::aggregate_accumulator * accumulators
#define OR_MINIMUM_STRING_LENGTH_FOR_COMPRESSION
XASL_NODE * right
Definition: xasl.h:290
SCAN_STATUS status
Definition: query_list.h:483
OUTPTR_LIST * prior_outptr_list
Definition: xasl.h:426
regu_variable_node * key2
Definition: access_spec.hpp:68
unsigned int DB_TIME
Definition: dbtype_def.h:754
int instnum_flag
Definition: xasl.h:997
QFILE_TUPLE_RECORD * tplrec2
Definition: query_list.h:381
void REGU_VARIABLE_CLEAR_FLAG(regu_variable_node *regu, int flag)
Definition: regu_var.hpp:265
DB_VALUE * level_val
Definition: xasl.h:988
static int qexec_for_update_set_class_locks(THREAD_ENTRY *thread_p, XASL_NODE *scan_list)
qfile_list_id * qexec_execute_query(THREAD_ENTRY *thread_p, xasl_node *xasl, int dbval_cnt, const DB_VALUE *dbval_ptr, QUERY_ID query_id)
SCAN_POSITION position
Definition: query_list.h:484
#define BTREE_IS_MULTI_ROW_OP(op)
Definition: btree.h:60
unsigned int DB_DATE
Definition: dbtype_def.h:771
MVCC_SNAPSHOT * mvcc_snapshot
Definition: heap_file.h:154
#define OR_GET_INT(ptr)
unsigned int mht_count(const MHT_TABLE *ht)
Definition: memory_hash.c:2260
OUTPTR_LIST * g_outptr_list
Definition: xasl.h:312
XASL_NODE * xasl_node
Definition: xasl.h:753
static void qexec_end_connect_by_lists(THREAD_ENTRY *thread_p, XASL_NODE *xasl)
SCAN_CODE(* XSAL_SCAN_FUNC)(THREAD_ENTRY *thread_p, XASL_NODE *, XASL_STATE *, QFILE_TUPLE_RECORD *, void *)
PRED_EXPR * having_pred
Definition: xasl.h:345
static QPROC_TPLDESCR_STATUS qexec_generate_tuple_descriptor(THREAD_ENTRY *thread_p, QFILE_LIST_ID *list_id, VALPTR_LIST *outptr_list, VAL_DESCR *vd)
#define ACCESS_SPEC_LIST_ID(ptr)
Definition: xasl.h:824
regu_variable_node * elemset
DB_VALUE * ordbynum_val
Definition: xasl.h:959
DB_DATA_STATUS
static int qexec_open_scan(THREAD_ENTRY *thread_p, ACCESS_SPEC_TYPE *curr_spec, VAL_LIST *val_list, VAL_DESCR *vd, bool force_select_lock, int fixed, int grouped, bool iscan_oid_order, SCAN_ID *s_id, QUERY_ID query_id, SCAN_OPERATION_TYPE scan_op_type, bool scan_immediately_stop, bool *p_mvcc_select_lock_needed)
const char * get_db_user() const
SCAN_PRED range_pred
Definition: scan_manager.h:211
SORTKEY_INFO key_info
#define ER_ARG_OUT_OF_RANGE
Definition: error_code.h:1412
int qfile_fast_val_tuple_to_list(THREAD_ENTRY *thread_p, QFILE_LIST_ID *list_id_p, DB_VALUE *val)
Definition: list_file.c:1949
void thread_dec_recursion_depth(cubthread::entry *thread_p)
XASL_NODE * scan_ptr
Definition: xasl.h:985
#define free_and_init(ptr)
Definition: memory_alloc.h:147
REGU_VARIABLE_LIST list
Definition: regu_var.hpp:229
SORT_LIST * after_groupby_list
Definition: xasl.h:310
#define DB_ALIGN(offset, align)
Definition: memory_alloc.h:84
ACCESS_SPEC_TYPE * spec_list
Definition: xasl.h:970
#define strlen(s1)
Definition: intl_support.c:43
#define BTID_COPY(btid_ptr1, btid_ptr2)
int db_datetime_encode(DB_DATETIME *datetime, int month, int day, int year, int hour, int minute, int second, int millisecond)
Definition: db_date.c:4597
int or_get_attrname(RECDES *record, int attrid, char **string, int *alloced_string)
ODKU_INFO * odku
Definition: xasl.h:393
char * prm_get_string_value(PARAM_ID prm_id)
SELUPD_LIST * next
Definition: xasl.h:219
int num_subclasses
Definition: xasl.h:231
DB_ENUM_ELEMENT * elements
Definition: dbtype_def.h:1031
TP_DOMAIN tp_Bit_domain
#define XASL_IS_MERGE_QUERY
Definition: xasl.h:487
static BH_CMP_RESULT qexec_topn_compare(const void *left, const void *right, BH_CMP_ARG arg)
const void * key
Definition: memory_hash.h:49
DB_TIMESTAMP sys_epochtime
const char * tz_get_system_timezone(void)
Definition: tz_support.c:749
OUTPTR_LIST * a_outptr_list
Definition: xasl.h:324
SCAN_ATTRS rest_attrs
Definition: scan_manager.h:214
#define XASL_INSTNUM_FLAG_SCAN_STOP
Definition: xasl.h:462
int num_classes
Definition: xasl.h:408
int mvcc_reev_extra_cls_cnt
Definition: xasl.h:1008
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
#define GOTO_EXIT_ON_ERROR
#define QFILE_GET_OVERFLOW_VPID(des, ptr)
Definition: query_list.h:112
SCAN_STATUS status
Definition: query_list.h:498
static int qexec_upddel_setup_current_class(THREAD_ENTRY *thread_p, UPDDEL_CLASS_INFO *class_, UPDDEL_CLASS_INFO_INTERNAL *class_info, int op_type, OID *current_oid)
unsigned int date
Definition: dbtype_def.h:776
#define QFILE_IS_LIST_CACHE_DISABLED
Definition: list_file.h:54
int hash_list_scan_yn
Definition: xasl.h:752
#define ER_HEAP_UNKNOWN_OBJECT
Definition: error_code.h:102
static int qexec_groupby_index(THREAD_ENTRY *thread_p, XASL_NODE *xasl, XASL_STATE *xasl_state, QFILE_TUPLE_RECORD *tplrec)
QPROC_DB_VALUE_LIST valp
Definition: xasl.h:207
int qfile_copy_tuple_descr_to_tuple(THREAD_ENTRY *thread_p, QFILE_TUPLE_DESCRIPTOR *tpl_descr, QFILE_TUPLE_RECORD *tplrec)
Definition: list_file.c:2846
QFILE_LIST_ID * input_list_id
Definition: xasl.h:421
REGU_VARIABLE_LIST g_hk_scan_regu_list
Definition: xasl.h:319
char * qmgr_get_query_sql_user_text(THREAD_ENTRY *thread_p, QUERY_ID query_id, int tran_index)
char * QFILE_TUPLE
Definition: query_list.h:281
#define QEXEC_MERGE_NEXT_SCAN(thread_p, pre, e)
MVCC_SNAPSHOT snapshot
Definition: mvcc.h:194
#define QEXEC_SEL_UPD_USE_REEVALUATION(xasl)
DB_LOGICAL
Definition: dbtype_def.h:1218
#define CTE_CURRENT_SCAN_READ_TUPLE(node)
int lang_set_flag_from_lang(const char *lang_str, bool has_user_format, bool has_user_lang, int *flag)
QFILE_TUPLE_RECORD group_tplrec
RECDES output_recdes
bool prm_get_bool_value(PARAM_ID prm_id)
static SORT_STATUS qexec_hash_gby_get_next(THREAD_ENTRY *thread_p, RECDES *recdes, void *arg)
VAL_DESCR vd
#define QPROC_ANALYTIC_IS_OFFSET_FUNCTION(func_p)
BINARY_HEAP * bh_create(THREAD_ENTRY *thread_p, int max_capacity, int elem_size, bh_key_comparator cmp_func, BH_CMP_ARG cmp_arg)
Definition: binaryheap.c:114
OUTPTR_LIST * cls_output_val_list
Definition: xasl.h:724
static int qexec_process_partition_unique_stats(THREAD_ENTRY *thread_p, PRUNING_CONTEXT *pcontext)
int * num_lob_attrs
Definition: xasl.h:239
JSON_VALIDATOR * json_validator
aggregate_hash_key * temp_part_key
class regu_variable_node REGU_VARIABLE
Definition: regu_var.hpp:64
int qfile_copy_list_id(QFILE_LIST_ID *dest_list_id_p, const QFILE_LIST_ID *src_list_id_p, bool is_include_sort_list)
Definition: list_file.c:433
int catalog_get_cardinality(THREAD_ENTRY *thread_p, OID *class_oid, DISK_REPR *rep, BTID *btid, const int key_pos, int *cardinality)
int db_get_string_size(const DB_VALUE *value)
REGU_VARIABLE_LIST g_hk_sort_regu_list
Definition: xasl.h:320
PRED_EXPR * where_key
Definition: xasl.h:929
union scan_id_struct::@153 s
int locator_delete_lob_force(THREAD_ENTRY *thread_p, OID *class_oid, OID *oid, RECDES *recdes)
Definition: locator_sr.c:6311
#define QFILE_PUT_NEXT_VPID_NULL(ptr)
Definition: query_list.h:181
UPDATE_ASSIGNMENT * assignments
Definition: xasl.h:264
struct drand48_data * qmgr_get_rand_buf(THREAD_ENTRY *thread_p)
SCAN_TYPE
Definition: scan_manager.h:75
void er_clear(void)
int upd_del_class_cnt
Definition: xasl.h:1006
#define SAFE_COPY_OID(dest_oid_ptr, src_oid_ptr)
Definition: oid.h:70
REGU_VARIABLE_LIST cls_regu_list_pred
Definition: xasl.h:720
SUBKEY_INFO * key
static int qexec_execute_selupd_list(THREAD_ENTRY *thread_p, XASL_NODE *xasl, XASL_STATE *xasl_state)
DB_VALUE * grbynum_val
Definition: xasl.h:346
cubxasl::aggregate_accumulator_domain ** accumulator_domains
REGU_VARIABLE * regu_var
Definition: xasl.h:254
void log_sysop_attach_to_outer(THREAD_ENTRY *thread_p)
Definition: log_manager.c:4076
#define SINGLE_ROW_INSERT
Definition: btree.h:52
const char * tz_get_session_local_timezone(void)
Definition: tz_support.c:739
XASL_STATE * xasl_state
void log_sysop_commit(THREAD_ENTRY *thread_p)
Definition: log_manager.c:3895
static int prepare_mvcc_reev_data(THREAD_ENTRY *thread_p, XASL_NODE *aptr, XASL_STATE *xasl_state, int num_reev_classes, int *cond_reev_indexes, MVCC_UPDDEL_REEV_DATA *reev_data, int num_classes, UPDDEL_CLASS_INFO *classes, UPDDEL_CLASS_INFO_INTERNAL *internal_classes, int num_assigns, UPDATE_ASSIGNMENT *assigns, PRED_EXPR *cons_pred, UPDDEL_MVCC_COND_REEVAL **mvcc_reev_classes, UPDATE_MVCC_REEV_ASSIGNMENT **mvcc_reev_assigns, bool has_delete)
int scan_start_scan(THREAD_ENTRY *thread_p, SCAN_ID *scan_id)
PRED_EXPR * cons_pred
Definition: xasl.h:262
#define TP_FLOATING_PRECISION_VALUE
static DB_VALUE_COMPARE_RESULT bf2df_str_compare(const unsigned char *s0, int l0, const unsigned char *s1, int l1)
static void qexec_clear_analytic_function_state(THREAD_ENTRY *thread_p, ANALYTIC_FUNCTION_STATE *func_state)
static int qexec_execute_selupd_list_find_class(THREAD_ENTRY *thread_p, XASL_NODE *xasl, VAL_DESCR *vd, OID *oid, SELUPD_LIST *selupd, OID *class_oid, HFID *class_hfid, DB_CLASS_PARTITION_TYPE *needs_pruning, bool *found)
int REPR_ID
PRED_EXPR * pred
Definition: xasl.h:1058
#define ER_INVALID_DATA_FOR_PARTITION
Definition: error_code.h:1402
upddel_mvcc_cond_reeval ** curr_extra_assign_reev
OR_DEFAULT_VALUE current_default_value
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
#define CHECK_MODIFICATION_NO_RETURN(error)
Definition: db.h:135
const container_type & get_map() const
int i
Definition: dynamic_load.c:954
QFILE_LIST_SCAN_ID * s_id
Definition: query_list.h:541
OID cls_oid
Definition: xasl.h:727
#define XASL_INSTNUM_FLAG_EVAL_DEFER
Definition: xasl.h:464
double drand
int db_to_char(const DB_VALUE *src_value, const DB_VALUE *format_or_length, const DB_VALUE *lang_str, DB_VALUE *result_str, const TP_DOMAIN *domain)
int db_make_null(DB_VALUE *value)
EH_SEARCH ehash_search(THREAD_ENTRY *thread_p, EHID *ehid_p, void *key_p, OID *value_p)
static void qexec_clear_head_lists(THREAD_ENTRY *thread_p, XASL_NODE *xasl_list)
void qfile_close_list(THREAD_ENTRY *thread_p, QFILE_LIST_ID *list_id_p)
Definition: list_file.c:1263
HFID * class_hfid
Definition: xasl.h:233
DB_TYPE id
std::string host_name
static int qexec_clear_regu_var(THREAD_ENTRY *thread_p, XASL_NODE *xasl_p, REGU_VARIABLE *regu_var, bool is_final)
bool oid_check_cached_class_oid(const int cache_id, const OID *oid)
Definition: oid.c:327
#define QEXEC_MERGE_ADD_MERGETUPLE(thread_p, t1, t2)
int partition_prune_spec(THREAD_ENTRY *thread_p, val_descr *vd, access_spec_node *spec)
Definition: partition.c:2841
#define DB_IS_NULL(value)
Definition: dbtype.h:63
#define PCOL_LEVEL_TUPLE_OFFSET
Definition: xasl.h:539
REGU_VARIABLE_LIST cls_regu_list_rest
Definition: xasl.h:721
HEAP_SCANCACHE * scan_cache
XASL_STATE * xasl_state
static DEL_LOB_INFO * qexec_change_delete_lob_info(THREAD_ENTRY *thread_p, XASL_STATE *xasl_state, UPDDEL_CLASS_INFO_INTERNAL *class_info, DEL_LOB_INFO **del_lob_info_list_ptr)
int has_uniques
Definition: xasl.h:394
struct tp_domain * next
Definition: object_domain.h:74
int qfile_unify_types(QFILE_LIST_ID *list_id1_p, const QFILE_LIST_ID *list_id2_p)
Definition: list_file.c:826
for(p=libs;*p;p++)
Definition: dynamic_load.c:968
PRED_EXPR * instnum_pred
Definition: xasl.h:979
static int qexec_oid_of_duplicate_key_update(THREAD_ENTRY *thread_p, HEAP_SCANCACHE **pruned_partition_scan_cache, HEAP_SCANCACHE *scan_cache, HEAP_CACHE_ATTRINFO *attr_info, HEAP_CACHE_ATTRINFO *index_attr_info, const HEAP_IDX_ELEMENTS_INFO *idx_info, int needs_pruning, PRUNING_CONTEXT *pcontext, OID *unique_oid, int op_type)
static SCAN_CODE qexec_execute_scan(THREAD_ENTRY *thread_p, XASL_NODE *xasl, XASL_STATE *xasl_state, QFILE_TUPLE_RECORD *ignore, XASL_SCAN_FNC_PTR next_scan_fnc)
int qexec_clear_pred_context(THREAD_ENTRY *thread_p, pred_expr_with_context *pred_filter, bool dealloc_dbvalues)
QPROC_DB_VALUE_LIST next
Definition: xasl.h:195
REGU_VARIABLE_LIST prior_regu_list_rest
Definition: xasl.h:428
qfile_list_id * qexec_get_xasl_list_id(xasl_node *xasl)
REGU_VARIABLE_LIST a_regu_list
#define ER_LK_OBJECT_DL_TIMEOUT_CLASSOF_MSG
Definition: error_code.h:1205
int db_make_double(DB_VALUE *value, const DB_C_DOUBLE num)
static int qexec_end_mainblock_iterations(THREAD_ENTRY *thread_p, XASL_NODE *xasl, XASL_STATE *xasl_state, QFILE_TUPLE_RECORD *tplrec)
VAL_LIST * merge_val_list
Definition: xasl.h:973
int wait_msecs
Definition: xasl.h:409
int wait_msecs
Definition: xasl.h:395
static int qexec_clear_agg_orderby_const_list(THREAD_ENTRY *thread_p, XASL_NODE *xasl, bool is_final)
LK_COMPOSITE_LOCK * composite_lock
INT16 type
TP_DOMAIN * tp_domain_resolve(DB_TYPE domain_type, DB_OBJECT *class_obj, int precision, int scale, TP_DOMAIN *setdomain, int collation)
#define ER_ARG_CAN_NOT_BE_CASTED_TO_DESIRED_DOMAIN
Definition: error_code.h:1419
bool qdata_copy_db_value(DB_VALUE *dest_p, const DB_VALUE *src_p)
Definition: query_opfunc.c:310
char * strdup(const char *str)
Definition: porting.c:901
SORT_CMP_FUNC * cmp_fn
heap_cache_attrinfo * attr_cache
#define NULL_VOLID
ATTR_ID * attrids_range
Definition: xasl.h:741
TYPE_PRED_EXPR type
SORT_LIST * groupby_list
Definition: xasl.h:309
DB_VALUE ** node_info_values
Definition: scan_manager.h:242
const int REGU_VARIABLE_FETCH_ALL_CONST
Definition: regu_var.hpp:163
SCAN_PRED key_pred
Definition: scan_manager.h:207
HFID hfid
Definition: xasl.h:726
REGU_VARIABLE_LIST cls_regu_list_range
Definition: xasl.h:722
analytic_list_node * next
int qdata_apply_interpolation_function_coercion(DB_VALUE *f_value, tp_domain **result_dom, DB_VALUE *result, FUNC_TYPE function)
REGU_VARIABLE_LIST arg_list
Definition: xasl.h:759
int session_begin_insert_values(THREAD_ENTRY *thread_p)
Definition: session.c:1506
#define XASL_ORDBYNUM_FLAG_SCAN_CONTINUE
Definition: xasl.h:456
static int qexec_end_one_iteration(THREAD_ENTRY *thread_p, XASL_NODE *xasl, XASL_STATE *xasl_state, QFILE_TUPLE_RECORD *tplrec)
int db_make_timestamp(DB_VALUE *value, const DB_C_TIMESTAMP timeval)
int db_make_int(DB_VALUE *value, const int num)
void heap_attrinfo_end(THREAD_ENTRY *thread_p, HEAP_CACHE_ATTRINFO *attr_info)
Definition: heap_file.c:9979
int qdata_tuple_to_values_array(THREAD_ENTRY *thread_p, qfile_tuple_descriptor *tuple, DB_VALUE **values)
OR_INDEX_STATUS index_status
void qdata_load_agg_hvalue_in_agg_list(aggregate_hash_value *value, cubxasl::aggregate_list_node *agg_list, bool copy_vals)
REGU_VARIABLE * thirdptr
Definition: regu_var.hpp:130
#define QFILE_OUTER_LIST
Definition: query_list.h:491
short volid
Definition: dbtype_def.h:887
int heap_init_func_pred_unpack_info(THREAD_ENTRY *thread_p, HEAP_CACHE_ATTRINFO *attr_info, const OID *class_oid, FUNC_PRED_UNPACK_INFO **func_indx_preds)
Definition: heap_file.c:17493
#define SORT_PUT_STOP
Definition: external_sort.h:38
#define ER_CTE_MAX_RECURSION_REACHED
Definition: error_code.h:1544
alsm_eval_term et_alsm
static int qexec_clear_analytic_function_list(THREAD_ENTRY *thread_p, XASL_NODE *xasl_p, ANALYTIC_EVAL_TYPE *list, bool is_final)
static int qexec_clear_regu_value_list(THREAD_ENTRY *thread_p, XASL_NODE *xasl_p, REGU_VALUE_LIST *list, bool is_final)
int db_make_oid(DB_VALUE *value, const OID *oid)
static int qexec_upddel_add_unique_oid_to_ehid(THREAD_ENTRY *thread_p, XASL_NODE *xasl, XASL_STATE *xasl_state)
int qdata_free_agg_hentry(const void *key, void *data, void *args)
REGU_VARIABLE * limit_offset
Definition: xasl.h:982
SCAN_CODE scan_next_scan(THREAD_ENTRY *thread_p, SCAN_ID *s_id)
regu_variable_node * pattern
union cubxasl::eval_term::@184 et
QFILE_LIST_ID * start_with_list_id
Definition: xasl.h:422
void thread_inc_recursion_depth(cubthread::entry *thread_p)
#define OID_ISNULL(oidp)
Definition: oid.h:81
SORT_NULLS s_nulls
Definition: query_list.h:418
like_eval_term et_like
bool log_does_allow_replication(void)
Definition: log_comm.c:270
#define TP_DOMAIN_CODESET(dom)
int qdata_save_agg_htable_to_list(cubthread::entry *thread_p, mht_table *hash_table, qfile_list_id *tuple_list_id, qfile_list_id *partial_list_id, db_value *temp_dbval_array)
int collation_id
Definition: object_domain.h:92
int qdata_copy_db_value_to_tuple_value(DB_VALUE *dbval_p, bool clear_compressed_string, char *tuple_val_p, int *tuple_val_size)
Definition: query_opfunc.c:353
static int qexec_set_class_locks(THREAD_ENTRY *thread_p, XASL_NODE *aptr_list, UPDDEL_CLASS_INFO *query_classes, int query_classes_count, UPDDEL_CLASS_INFO_INTERNAL *internal_classes)
static void qexec_reset_regu_variable(REGU_VARIABLE *var)
#define XASL_ZERO_CORR_LEVEL
Definition: xasl.h:479
int qexec_clear_func_pred(THREAD_ENTRY *thread_p, func_pred *fpr)
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
static int qexec_analytic_evaluate_cume_dist_percent_rank_function(THREAD_ENTRY *thread_p, ANALYTIC_FUNCTION_STATE *func_state)
#define ER_QPROC_INVALID_DATATYPE
Definition: error_code.h:534
int lock_finalize_composite_lock(THREAD_ENTRY *thread_p, LK_COMPOSITE_LOCK *comp_lock)
int qdata_initialize_aggregate_list(cubthread::entry *thread_p, cubxasl::aggregate_list_node *agg_list_p, QUERY_ID query_id)
regu_variable_node * pattern
int heap_attrinfo_set(const OID *inst_oid, ATTR_ID attrid, DB_VALUE *attr_val, HEAP_CACHE_ATTRINFO *attr_info)
Definition: heap_file.c:11239
static void qexec_gby_start_group_dim(THREAD_ENTRY *thread_p, GROUPBY_STATE *gbstate, const RECDES *recdes)
REGU_VARIABLE_LIST g_regu_list
Definition: xasl.h:313
QPROC_SINGLE_FETCH single_fetch
Definition: xasl.h:933
OR_ATTRIBUTE * attributes
pred_expr * rhs
PRED_EXPR * g_having_pred
Definition: xasl.h:315
REGU_VARIABLE_LIST g_scan_regu_list
Definition: xasl.h:321
XASL_NODE * bptr_list
Definition: xasl.h:975
ACCESS_SPEC_TYPE * outer_spec_list
Definition: xasl.h:357
DB_VALUE_COMPARE_RESULT
Definition: dbtype_def.h:199
QFILE_TUPLE_POSITION tpl_pos
static int qexec_analytic_group_header_next(THREAD_ENTRY *thread_p, ANALYTIC_FUNCTION_STATE *func_state)
QFILE_LIST_SCAN_ID * input_scan
groupby_dimension_flag
static int qexec_update_connect_by_lists(THREAD_ENTRY *thread_p, XASL_NODE *xasl, XASL_STATE *xasl_state, QFILE_TUPLE_RECORD *tplrec)
REGU_VARLIST_LIST next
Definition: regu_var.hpp:228
static int qexec_analytic_value_lookup(THREAD_ENTRY *thread_p, ANALYTIC_FUNCTION_STATE *func_state, int position, bool ignore_nulls)
#define db_private_realloc(thrd, ptr, size)
Definition: memory_alloc.h:231
HEAP_CACHE_ATTRINFO * cache_key
Definition: xasl.h:729
regu_variable_node * esc_char
#define ER_LK_OBJECT_TIMEOUT_CLASSOF_MSG
Definition: error_code.h:133
int max_iterations
Definition: xasl.h:1043
static void qexec_free_delete_lob_info_list(THREAD_ENTRY *thread_p, DEL_LOB_INFO **del_lob_info_list_ptr)
#define PEEK
Definition: file_io.h:74
LOG_TRAN_BTID_UNIQUE_STATS * logtb_tran_find_btid_stats(THREAD_ENTRY *thread_p, const BTID *btid, bool create)
int SORT_CMP_FUNC(const void *, const void *, void *)
Definition: external_sort.h:61
#define ER_QPROC_INVALID_QRY_SINGLE_TUPLE
Definition: error_code.h:539
Definition: xasl.h:186
#define QFILE_PUT_TUPLE_LENGTH(tpl, val)
Definition: query_list.h:244
SCAN_DIRECTION
VAL_LIST * inner_val_list
Definition: xasl.h:361
static int qexec_execute_mainblock_internal(THREAD_ENTRY *thread_p, XASL_NODE *xasl, XASL_STATE *xasl_state, UPDDEL_CLASS_INSTANCE_LOCK_INFO *p_class_instance_lock_info)
#define VPID_SET_NULL(vpid_ptr)
Definition: dbtype_def.h:906
static void qexec_gby_start_group(THREAD_ENTRY *thread_p, GROUPBY_STATE *gbstate, const RECDES *recdes, int N)
#define QEXEC_MERGE_REV_SCAN_PVALS(thread_p, pre)
static int qexec_analytic_evaluate_offset_function(THREAD_ENTRY *thread_p, ANALYTIC_FUNCTION_STATE *func_state, ANALYTIC_STATE *analytic_state)
int pruning_type
Definition: xasl.h:936
DB_VALUE * iscycle_val
Definition: xasl.h:993
upddel_mvcc_cond_reeval * curr_upddel
#define XASL_INSTNUM_FLAG_SCAN_CHECK
Definition: xasl.h:461
MERGE_PROC_NODE merge
Definition: xasl.h:1026
DB_DEFAULT_EXPR default_expr
bool btree_is_unique_type(BTREE_TYPE type)
Definition: btree.c:6046
int db_make_bit(DB_VALUE *value, const int bit_length, DB_CONST_C_BIT bit_str, const int bit_str_bit_size)
int qfile_fast_intint_tuple_to_list(THREAD_ENTRY *thread_p, QFILE_LIST_ID *list_id_p, int v1, int v2)
Definition: list_file.c:1802
static SCAN_CODE qexec_next_scan_block_iterations(THREAD_ENTRY *thread_p, XASL_NODE *xasl)
REGU_VARIABLE_LIST valptrp
Definition: regu_var.hpp:116
OR_ATTRIBUTE ** atts
static int qexec_evaluate_aggregates_optimize(THREAD_ENTRY *thread_p, AGGREGATE_TYPE *agg_list, ACCESS_SPEC_TYPE *spec, bool *is_scan_needed)
static void qexec_update_btree_unique_stats_info(THREAD_ENTRY *thread_p, multi_index_unique_stats *info, const HEAP_SCANCACHE *scan_cache)
#define HFID_COPY(hfid_ptr1, hfid_ptr2)
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)
QFILE_LIST_ID * group_list_id
DB_VALUE * instnum_val
Definition: xasl.h:980
rlike_eval_term et_rlike
bool lock_is_instant_lock_mode(int tran_index)
static TOPN_STATUS qexec_add_tuple_to_topn(THREAD_ENTRY *thread_p, TOPN_TUPLES *sort_stop, QFILE_TUPLE_DESCRIPTOR *tpldescr)
SORT_LIST * after_iscan_list
Definition: xasl.h:956
int num_classes
Definition: xasl.h:369
regu_variable_list_node * node_info_regu_list
Definition: scan_manager.h:243
int num_attrs_pred
Definition: xasl.h:731
BH_CMP_RESULT
Definition: binaryheap.h:42
DB_CLASS_PARTITION_TYPE
static int qexec_check_limit_clause(THREAD_ENTRY *thread_p, XASL_NODE *xasl, XASL_STATE *xasl_state, bool *empty_result)
#define qmgr_free_old_page_and_init(thread_p, page_p, tfile_vfidp)
Definition: query_manager.h:42
int num_attrs_range
Definition: xasl.h:743
SCAN_ATTRS rest_attrs
Definition: scan_manager.h:104
QFILE_LIST_MERGE_INFO * merge_info
Definition: query_list.h:382
const char ** p
Definition: dynamic_load.c:945
#define catalog_free_representation_and_init(repr_p)
HFID class_hfid
Definition: xasl.h:387
DB_CONST_C_CHAR db_get_string(const DB_VALUE *value)
#define XASL_IGNORE_CYCLES
Definition: xasl.h:485
REGU_VARIABLE * isleaf_regu
Definition: xasl.h:992
const char * fcode_get_uppercase_name(FUNC_TYPE ftype)
REGU_VARIABLE_LIST cls_regu_list_reserved
Definition: xasl.h:740
static int qexec_init_upddel_ehash_files(THREAD_ENTRY *thread_p, XASL_NODE *buildlist)
DEL_LOB_INFO * next
XASL_NODE * non_recursive_part
Definition: xasl.h:446
unsigned int time
Definition: dbtype_def.h:777
int qfile_clear_list_cache(THREAD_ENTRY *thread_p, int list_ht_no)
Definition: list_file.c:5053
void lock_clear_deadlock_victim(int tran_index)
int num_reev_classes
Definition: xasl.h:378
static int qexec_clear_agg_list(THREAD_ENTRY *thread_p, XASL_NODE *xasl_p, AGGREGATE_TYPE *list, bool is_final)
regu_variable_list_node * operands
int qfile_compare_partial_sort_record(const void *pk0, const void *pk1, void *arg)
Definition: list_file.c:3508
HEAP_SCANCACHE scan_cache
Definition: partition_sr.h:52
int heap_set_autoincrement_value(THREAD_ENTRY *thread_p, HEAP_CACHE_ATTRINFO *attr_info, HEAP_SCANCACHE *scan_cache, int *is_set)
Definition: heap_file.c:16507
void heap_free_func_pred_unpack_info(THREAD_ENTRY *thread_p, int n_indexes, FUNC_PRED_UNPACK_INFO *func_indx_preds, int *attr_info_started)
Definition: heap_file.c:17621
#define ER_LK_OBJECT_DL_TIMEOUT_SIMPLE_MSG
Definition: error_code.h:1203
DB_VALUE ** vals
Definition: xasl.h:391
static int qexec_execute_build_indexes(THREAD_ENTRY *thread_p, XASL_NODE *xasl, XASL_STATE *xasl_state)
#define QPROC_MAX_GROUPED_SCAN_CNT
static DB_VALUE_COMPARE_RESULT bf2df_str_cmpval(DB_VALUE *value1, DB_VALUE *value2, int do_coercion, int total_order, int *start_colp, int collation)
#define BTREE_SET_UNIQUE_VIOLATION_ERROR(THREAD, KEY, OID, C_OID, BTID, BTNM)
Definition: btree.h:96
#define XASL_RETURN_GENERATED_KEYS
Definition: xasl.h:490
#define ER_MVCC_NOT_SATISFIED_REEVALUATION
Definition: error_code.h:1480
void logtb_complete_sub_mvcc(THREAD_ENTRY *thread_p, LOG_TDES *tdes)
int tp_domain_memory_size(TP_DOMAIN *domain)
#define QEXEC_MERGE_OUTER_NEXT_SCAN(thread_p, pre, e)
bool g_with_rollup
Definition: xasl.h:329
int db_value_domain_init(DB_VALUE *value, const DB_TYPE type, const int precision, const int scale)
Definition: db_macro.c:153
DB_VALUE * constant
Definition: xasl.h:253
#define ER_MERGE_TOO_MANY_SOURCE_ROWS
Definition: error_code.h:1396
#define TP_DOMAIN_COLLATION_FLAG(dom)
int do_replace
Definition: xasl.h:397
regu_variable_node * case_sensitive
DB_VALUE * obj_oid
Definition: xasl.h:401
void clear(cub_regex_object *&regex, char *&pattern)
FILE * port_open_memstream(char **ptr, size_t *sizeloc)
Definition: porting.c:2198
int qdata_interpolation_function_values(DB_VALUE *f_value, DB_VALUE *c_value, double row_num_d, double f_row_num_d, double c_row_num_d, tp_domain **result_dom, DB_VALUE *result, FUNC_TYPE function)
bool is_constant
Definition: access_spec.hpp:77
enum analytic_stage ANALYTIC_STAGE
int qfile_add_tuple_to_list(THREAD_ENTRY *thread_p, QFILE_LIST_ID *list_id_p, QFILE_TUPLE tuple)
Definition: list_file.c:1511
regu_variable_node * key_limit_l
Definition: access_spec.hpp:80
int qfile_add_tuple_get_pos_in_list(THREAD_ENTRY *thread_p, QFILE_LIST_ID *list_id_p, QFILE_TUPLE tuple, QFILE_TUPLE_POSITION *tuple_pos)
Definition: list_file.c:5989
SCAN_CODE heap_get_class_record(THREAD_ENTRY *thread_p, const OID *class_oid, RECDES *recdes_p, HEAP_SCANCACHE *scan_cache, int ispeeking)
Definition: heap_file.c:24780
CLS_SPEC_TYPE cls_node
Definition: xasl.h:784
#define QEXEC_GET_BH_TOPN_TUPLE(heap, index)
DISK_REPR * catalog_get_representation(THREAD_ENTRY *thread_p, OID *class_id_p, REPR_ID repr_id, CATALOG_ACCESS_INFO *catalog_access_info_p)
QUERY_OPTIONS
TP_DOMAIN * domain
Definition: regu_var.hpp:125