CUBRID Engine  latest
list_file.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  * list_file.c - Query List File Manager
21  */
22 
23 #ident "$Id$"
24 
25 #include "config.h"
26 
27 #include <stdio.h>
28 #include <string.h>
29 #include <math.h>
30 #include <search.h>
31 #include <stddef.h>
32 #include <assert.h>
33 
34 #include "list_file.h"
35 
36 #include "binaryheap.h"
37 #include "db_value_printer.hpp"
38 #include "dbtype.h"
39 #include "error_manager.h"
40 #include "log_append.hpp"
41 #include "object_primitive.h"
42 #include "object_representation.h"
43 #include "query_manager.h"
44 #include "query_opfunc.h"
45 #include "stream_to_xasl.h"
46 #include "thread_entry.hpp"
47 #include "thread_manager.hpp" // for thread_sleep
48 #include "xasl.h"
49 #include "xasl_cache.h"
50 
51 /* TODO */
52 #if !defined (SERVER_MODE)
53 #define pthread_mutex_init(a, b)
54 #define pthread_mutex_destroy(a)
55 #define pthread_mutex_lock(a) 0
56 #define pthread_mutex_unlock(a)
57 static int rv;
58 
59 #define thread_sleep(a)
60 #endif /* not SERVER_MODE */
61 
62 #define QFILE_CHECK_LIST_FILE_IS_CLOSED(list_id)
63 
64 #define QFILE_DEFAULT_PAGES 4
65 
66 #if defined (SERVER_MODE)
67 #define LS_PUT_NEXT_VPID(ptr) \
68  do \
69  { \
70  OR_PUT_INT ((ptr) + QFILE_NEXT_PAGE_ID_OFFSET, NULL_PAGEID_IN_PROGRESS); \
71  OR_PUT_SHORT ((ptr) + QFILE_NEXT_VOL_ID_OFFSET, NULL_VOLID); \
72  } \
73  while (0)
74 #else
75 #define LS_PUT_NEXT_VPID(ptr) \
76  do \
77  { \
78  OR_PUT_INT ((ptr) + QFILE_NEXT_PAGE_ID_OFFSET, NULL_PAGEID); \
79  OR_PUT_SHORT ((ptr) + QFILE_NEXT_VOL_ID_OFFSET, NULL_VOLID); \
80  } \
81  while (0)
82 #endif
83 
86 {
88  INT64 weight;
89 };
90 
93 
94 /* query result(list file) cache related things */
97 {
98  MHT_TABLE **list_hts; /* array of memory hash tables for list cache; pool for list_ht of XASL_CACHE_ENTRY */
99  unsigned int n_hts; /* number of elements of list_hts */
100  int n_entries; /* total number of cache entries */
101  int n_pages; /* total number of pages used by the cache */
102  unsigned int lookup_counter; /* counter of cache lookup */
103  unsigned int hit_counter; /* counter of cache hit */
104  unsigned int miss_counter; /* counter of cache miss */
105  unsigned int full_counter; /* counter of cache full & replacement */
106 };
107 
110 {
111  int total_num; /* total number of cache entries */
112  int num_candidates; /* number of candidates */
113  int num_victims; /* number of victims */
114  int selcnt;
115  QFILE_LIST_CACHE_ENTRY **time_candidates; /* candidates who are old aged */
116  QFILE_LIST_CACHE_ENTRY **ref_candidates; /* candidates who are recently used */
117  QFILE_LIST_CACHE_ENTRY **victims; /* victims; cache entries to be deleted */
118  int c_idx;
119  int v_idx;
121 };
122 
123 /* list cache entry pooling */
124 #define FIXED_SIZE_OF_POOLED_LIST_CACHE_ENTRY 4096
125 #define ADDITION_FOR_POOLED_LIST_CACHE_ENTRY offsetof(QFILE_POOLED_LIST_CACHE_ENTRY, s.entry)
126 
127 #define POOLED_LIST_CACHE_ENTRY_FROM_LIST_CACHE_ENTRY(p) \
128  ((QFILE_POOLED_LIST_CACHE_ENTRY *) ((char*) p - ADDITION_FOR_POOLED_LIST_CACHE_ENTRY))
129 
132 {
133  struct
134  {
135  int next; /* next entry in the free list */
136  QFILE_LIST_CACHE_ENTRY entry; /* list cache entry data */
137  } s;
139  /*
140  * 4K size including list cache entry itself
141  * and reserved spaces for list_cache_ent.param_values
142  */
143 };
144 
147 
150 {
151  QFILE_POOLED_LIST_CACHE_ENTRY *pool; /* pre-allocated array */
152  int n_entries; /* number of entries in the pool */
153  int free_list; /* the head(first entry) of the free list */
154 };
155 
156 /*
157  * query result(list file) cache related things
158  */
159 
160 /* list cache and related information */
161 static QFILE_LIST_CACHE qfile_List_cache = { NULL, 0, 0, 0, 0, 0, 0, 0 };
162 
163 /* information of candidates to be removed from XASL cache */
164 static QFILE_LIST_CACHE_CANDIDATE qfile_List_cache_candidate = { 0, 0, 0, 0, NULL, NULL, NULL, 0, 0, false };
165 
166 /* list cache entry pool */
168 
169 /* sort list freelist */
171 
172 static void *qfile_alloc_sort_list (void);
173 static int qfile_dealloc_sort_list (void *sort_list);
174 
176  offsetof (SORT_LIST, local_next),
177  offsetof (SORT_LIST, next),
178  offsetof (SORT_LIST, del_id),
179  0, /* does not have a key, not used in a hash table */
180  0, /* does not have a mutex */
184  NULL,
185  NULL,
186  NULL, NULL, NULL, /* no key */
187  NULL /* no inserts */
188 };
189 
190 /*
191  * Query File Manager Constants/Global Variables
192  */
194 
196 
198 static int qfile_compare_tuple_values (QFILE_TUPLE tplp1, QFILE_TUPLE tplp2, TP_DOMAIN * domain, int *cmp);
199 #if defined (CUBRID_DEBUG)
200 static void qfile_print_tuple (QFILE_TUPLE_VALUE_TYPE_LIST * type_list, QFILE_TUPLE tpl);
201 #endif
202 static void qfile_initialize_page_header (PAGE_PTR page_p);
203 static void qfile_set_dirty_page_and_skip_logging (THREAD_ENTRY * thread_p, PAGE_PTR page_p, VFID * vfid_p,
204  int free_page);
205 static bool qfile_is_first_tuple (QFILE_LIST_ID * list_id_p);
206 static bool qfile_is_last_page_full (QFILE_LIST_ID * list_id_p, int tuple_length, const bool is_ovf_page);
207 static void qfile_set_dirty_page (THREAD_ENTRY * thread_p, PAGE_PTR page_p, int free_page, QMGR_TEMP_FILE * vfid_p);
208 static PAGE_PTR qfile_allocate_new_page (THREAD_ENTRY * thread_p, QFILE_LIST_ID * list_id_p, PAGE_PTR page_p,
209  bool is_ovf_page);
210 static PAGE_PTR qfile_allocate_new_ovf_page (THREAD_ENTRY * thread_p, QFILE_LIST_ID * list_id_p, PAGE_PTR page_p,
211  PAGE_PTR prev_page_p, int tuple_length, int offset,
212  int *tuple_page_size_p);
213 static int qfile_allocate_new_page_if_need (THREAD_ENTRY * thread_p, QFILE_LIST_ID * list_id_p, PAGE_PTR * page_p,
214  int tuple_length, bool is_ovf_page);
215 static void qfile_add_tuple_to_list_id (QFILE_LIST_ID * list_id_p, PAGE_PTR page_p, int tuple_length,
216  int written_tuple_length);
217 static int qfile_save_single_bound_item_tuple (QFILE_TUPLE_DESCRIPTOR * tuple_descr_p, char *tuple_p, char *page_p,
218  int tuple_length);
219 static int qfile_save_normal_tuple (QFILE_TUPLE_DESCRIPTOR * tuple_descr_p, char *tuple_p, char *page_p,
220  int tuple_length);
221 static int qfile_save_sort_key_tuple (QFILE_TUPLE_DESCRIPTOR * tuple_descr_p, char *tuple_p, char *page_p,
222  int tuple_length);
223 static int qfile_save_merge_tuple (QFILE_TUPLE_DESCRIPTOR * tuple_descr_p, char *tuple_p, char *page_p,
224  int *tuple_length_p);
225 
227 static SCAN_CODE qfile_advance_single (THREAD_ENTRY * thread_p, QFILE_LIST_SCAN_ID * next_scan,
228  QFILE_TUPLE_RECORD * next_tpl, QFILE_LIST_SCAN_ID * last_scan,
229  QFILE_TUPLE_RECORD * last_tpl, QFILE_TUPLE_VALUE_TYPE_LIST * types);
230 static SCAN_CODE qfile_advance_group (THREAD_ENTRY * thread_p, QFILE_LIST_SCAN_ID * next_scan,
231  QFILE_TUPLE_RECORD * next_tpl, QFILE_LIST_SCAN_ID * last_scan,
232  QFILE_TUPLE_RECORD * last_tpl, QFILE_TUPLE_VALUE_TYPE_LIST * types);
233 static int qfile_add_one_tuple (THREAD_ENTRY * thread_p, QFILE_LIST_ID * dst, QFILE_TUPLE lhs, QFILE_TUPLE rhs);
234 static int qfile_add_two_tuple (THREAD_ENTRY * thread_p, QFILE_LIST_ID * dst, QFILE_TUPLE lhs, QFILE_TUPLE rhs);
235 static int qfile_advance (THREAD_ENTRY * thread_p, ADVANCE_FUCTION advance_func, QFILE_TUPLE_RECORD * side_p,
236  QFILE_TUPLE_RECORD * last_side_p, QFILE_LIST_SCAN_ID * scan_p,
237  QFILE_LIST_SCAN_ID * last_scan_p, QFILE_LIST_ID * side_file_p, int *have_side_p);
238 static int qfile_copy_tuple (THREAD_ENTRY * thread_p, QFILE_LIST_ID * to_list_id_p, QFILE_LIST_ID * from_list_id_p);
239 static void qfile_close_and_free_list_file (THREAD_ENTRY * thread_p, QFILE_LIST_ID * list_id);
240 
241 static QFILE_LIST_ID *qfile_union_list (THREAD_ENTRY * thread_p, QFILE_LIST_ID * list_id1, QFILE_LIST_ID * list_id2,
242  int flag);
243 
244 static SORT_STATUS qfile_get_next_sort_item (THREAD_ENTRY * thread_p, RECDES * recdes, void *arg);
245 static int qfile_put_next_sort_item (THREAD_ENTRY * thread_p, const RECDES * recdes, void *arg);
247 static void qfile_clear_sort_info (SORT_INFO * info);
248 static int qfile_copy_list_pages (THREAD_ENTRY * thread_p, VPID * old_first_vpidp, QMGR_TEMP_FILE * old_tfile_vfidp,
249  VPID * new_first_vpidp, VPID * new_last_vpidp, QMGR_TEMP_FILE * new_tfile_vfidp);
250 static int qfile_get_tuple_from_current_list (THREAD_ENTRY * thread_p, QFILE_LIST_SCAN_ID * scan_id_p,
251  QFILE_TUPLE_RECORD * tuple_record_p);
252 
253 static SCAN_CODE qfile_scan_next (THREAD_ENTRY * thread_p, QFILE_LIST_SCAN_ID * s_id);
254 static SCAN_CODE qfile_scan_prev (THREAD_ENTRY * thread_p, QFILE_LIST_SCAN_ID * s_id);
255 static SCAN_CODE qfile_retrieve_tuple (THREAD_ENTRY * thread_p, QFILE_LIST_SCAN_ID * scan_id_p,
256  QFILE_TUPLE_RECORD * tuple_record_p, int peek);
257 static SCAN_CODE qfile_scan_list (THREAD_ENTRY * thread_p, QFILE_LIST_SCAN_ID * scan_id_p,
258  SCAN_CODE (*scan_func) (THREAD_ENTRY * thread_p, QFILE_LIST_SCAN_ID *),
259  QFILE_TUPLE_RECORD * tuple_record_p, int peek);
260 
261 #if defined(SERVER_MODE)
262 static int qfile_compare_tran_id (const void *t1, const void *t2);
263 #endif /* SERVER_MODE */
264 static unsigned int qfile_hash_db_value_array (const void *key, unsigned int htsize);
265 static int qfile_compare_equal_db_value_array (const void *key1, const void *key2);
266 
267 /* for list cache */
268 static int qfile_assign_list_cache (void);
270 static int qfile_free_list_cache_entry (THREAD_ENTRY * thread_p, void *data, void *args);
271 static int qfile_print_list_cache_entry (THREAD_ENTRY * thread_p, FILE * fp, const void *key, void *data, void *args);
272 static void qfile_add_uncommitted_list_cache_entry (int tran_index, QFILE_LIST_CACHE_ENTRY * lent);
273 static void qfile_delete_uncommitted_list_cache_entry (int tran_index, QFILE_LIST_CACHE_ENTRY * lent);
274 static int qfile_delete_list_cache_entry (THREAD_ENTRY * thread_p, void *data);
275 static int qfile_end_use_of_list_cache_entry_local (THREAD_ENTRY * thread_p, void *data, void *args);
276 static bool qfile_is_early_time (struct timeval *a, struct timeval *b);
277 
278 static int qfile_get_list_cache_entry_size_for_allocate (int nparam);
279 #if defined(SERVER_MODE)
280 static int *qfile_get_list_cache_entry_tran_index_array (QFILE_LIST_CACHE_ENTRY * ent);
281 #endif /* SERVER_MODE */
283 static int qfile_compare_with_null_value (int o0, int o1, SUBKEY_INFO key_info);
284 static int qfile_compare_with_interpolation_domain (char *fp0, char *fp1, SUBKEY_INFO * subkey,
286 
287 #if defined(SERVER_MODE)
288 static BH_CMP_RESULT
289 qfile_compare_cleanup_candidates (const void *left, const void *right, BH_CMP_ARG ignore_arg)
290 {
291  INT64 left_weight = ((QFILE_CACHE_CLEANUP_CANDIDATE *) left)->weight;
292  INT64 right_weight = ((QFILE_CACHE_CLEANUP_CANDIDATE *) right)->weight;
293 
294  if (left_weight < right_weight)
295  {
296  return BH_LT;
297  }
298  else if (left_weight == right_weight)
299  {
300  return BH_EQ;
301  }
302  else
303  {
304  return BH_GT;
305  }
306 }
307 
308 static int
309 qfile_list_cache_cleanup (THREAD_ENTRY * thread_p)
310 {
311  BINARY_HEAP *bh = NULL;
313  int candidate_index;
314  unsigned int i, n;
315 
316  struct timeval current_time;
317  int cleanup_count = prm_get_integer_value (PRM_ID_LIST_MAX_QUERY_CACHE_ENTRIES) * 8 / 10;
318  int cleanup_pages = prm_get_integer_value (PRM_ID_LIST_MAX_QUERY_CACHE_PAGES) * 8 / 10;
319 
320  if (cleanup_count < 1)
321  {
322  cleanup_count = 1;
323  }
324 
325  if (cleanup_pages < 1)
326  {
327  cleanup_pages = 1;
328  }
329 
330  bh =
331  bh_create (thread_p, cleanup_count, sizeof (QFILE_CACHE_CLEANUP_CANDIDATE), qfile_compare_cleanup_candidates, NULL);
332 
333  if (bh == NULL)
334  {
335  return ER_FAILED;
336  }
337 
338  gettimeofday (&current_time, NULL);
339 
340  /* Collect candidates for cleanup. */
341  for (n = 0; n < qfile_List_cache.n_hts; n++)
342  {
343  MHT_TABLE *ht;
344  HENTRY_PTR *hvector;
346  INT64 page_ref;
347  INT64 lru_sec;
348  INT64 clr_cnt;
349 
350  ht = qfile_List_cache.list_hts[n];
351  for (hvector = ht->table, i = 0; i < ht->size; hvector++, i++)
352  {
353  if (*hvector != NULL)
354  {
355  /* Go over the linked list */
356  for (hentry = *hvector; hentry != NULL; hentry = hentry->next)
357  {
358  candidate.qcache = (QFILE_LIST_CACHE_ENTRY *) hentry->data;
359  assert (candidate.qcache);
360  assert (candidate.qcache->xcache_entry);
361  if (candidate.qcache->last_ta_idx > 0)
362  {
363  // exclude in-transaction
364  continue;
365  }
366  page_ref = candidate.qcache->list_id.page_cnt / (candidate.qcache->ref_count + 1);
367  lru_sec = current_time.tv_sec - candidate.qcache->time_last_used.tv_sec;
368  clr_cnt = candidate.qcache->xcache_entry->clr_count + 1;
369  candidate.weight = page_ref * lru_sec * clr_cnt;
370  (void) bh_try_insert (bh, &candidate, NULL);
371  }
372  }
373  }
374  }
375 
376  for (candidate_index = 0; candidate_index < bh->element_count; candidate_index++)
377  {
378  bh_element_at (bh, candidate_index, &candidate);
379  qfile_delete_list_cache_entry (thread_p, candidate.qcache);
380  if (qfile_List_cache.n_entries <= cleanup_count)
381  {
382  if (qfile_List_cache.n_pages <= cleanup_pages)
383  {
384  break;
385  }
386  }
387  }
388 
389  bh_destroy (thread_p, bh);
390 
391  return NO_ERROR;
392 }
393 #endif
394 
395 /* qfile_modify_type_list () -
396  * return:
397  * type_list(in):
398  * list_id(out):
399  */
400 int
402 {
403  size_t type_list_size;
404 
405  list_id_p->type_list.type_cnt = type_list_p->type_cnt;
406 
407  list_id_p->type_list.domp = NULL;
408  if (list_id_p->type_list.type_cnt != 0)
409  {
410  type_list_size = list_id_p->type_list.type_cnt * DB_SIZEOF (TP_DOMAIN *);
411  list_id_p->type_list.domp = (TP_DOMAIN **) malloc (type_list_size);
412  if (list_id_p->type_list.domp == NULL)
413  {
414  return ER_FAILED;
415  }
416 
417  memcpy (list_id_p->type_list.domp, type_list_p->domp, type_list_size);
418  }
419 
420  list_id_p->tpl_descr.f_valp = NULL;
422  return NO_ERROR;
423 }
424 
425 /*
426  * qfile_copy_list_id - Copy contents of source list_id into destination list_id
427  * return: NO_ERROR or ER_FAILED
428  * dest_list_id(out): destination list_id
429  * src_list_id(in): source list_id
430  * include_sort_list(in):
431  */
432 int
433 qfile_copy_list_id (QFILE_LIST_ID * dest_list_id_p, const QFILE_LIST_ID * src_list_id_p, bool is_include_sort_list)
434 {
435  size_t type_list_size;
436 
437  memcpy (dest_list_id_p, src_list_id_p, DB_SIZEOF (QFILE_LIST_ID));
438 
439  /* copy domain info of type list */
440  dest_list_id_p->type_list.domp = NULL;
441  if (dest_list_id_p->type_list.type_cnt > 0)
442  {
443  type_list_size = dest_list_id_p->type_list.type_cnt * sizeof (TP_DOMAIN *);
444  dest_list_id_p->type_list.domp = (TP_DOMAIN **) malloc (type_list_size);
445 
446  if (dest_list_id_p->type_list.domp == NULL)
447  {
448  return ER_FAILED;
449  }
450 
451  memcpy (dest_list_id_p->type_list.domp, src_list_id_p->type_list.domp, type_list_size);
452  }
453 
454  /* copy sort list */
455  dest_list_id_p->sort_list = NULL;
456  if (is_include_sort_list && src_list_id_p->sort_list)
457  {
458  SORT_LIST *src, *dest = NULL;
459  int len;
460 
461  len = qfile_get_sort_list_size (src_list_id_p->sort_list);
462  if (len > 0)
463  {
464  dest = qfile_allocate_sort_list (NULL, len);
465  if (dest == NULL)
466  {
467  free_and_init (dest_list_id_p->type_list.domp);
468  return ER_FAILED;
469  }
470  }
471 
472  /* copy sort list item */
473  for (src = src_list_id_p->sort_list, dest_list_id_p->sort_list = dest; src != NULL && dest != NULL;
474  src = src->next, dest = dest->next)
475  {
476  dest->s_order = src->s_order;
477  dest->s_nulls = src->s_nulls;
478  dest->pos_descr.dom = src->pos_descr.dom;
479  dest->pos_descr.pos_no = src->pos_descr.pos_no;
480  }
481  }
482  else
483  {
484  dest_list_id_p->sort_list = NULL;
485  }
486 
487  memset (&dest_list_id_p->tpl_descr, 0, sizeof (QFILE_TUPLE_DESCRIPTOR));
488 
490 
491  return NO_ERROR;
492 }
493 
494 /*
495  * qfile_clone_list_id () - Clone (allocate and copy) the list_id
496  * return: cloned list id
497  * list_id(in): source list id
498  * incluse_sort_list(in):
499  */
501 qfile_clone_list_id (const QFILE_LIST_ID * list_id_p, bool is_include_sort_list)
502 {
503  QFILE_LIST_ID *cloned_id_p;
504 
505  /* allocate new LIST_ID to be returned */
506  cloned_id_p = (QFILE_LIST_ID *) malloc (DB_SIZEOF (QFILE_LIST_ID));
507  if (cloned_id_p)
508  {
509  if (qfile_copy_list_id (cloned_id_p, list_id_p, is_include_sort_list) != NO_ERROR)
510  {
511  free_and_init (cloned_id_p);
512  }
513  }
514 
515  return cloned_id_p;
516 }
517 
518 /*
519  * qfile_clear_list_id () -
520  * list_id(in/out): List identifier
521  *
522  * Note: The allocated areas inside the area pointed by the list_id is
523  * freed and the area pointed by list_id is set to null values.
524  */
525 void
527 {
529 
530  if (list_id_p->tpl_descr.f_valp)
531  {
532  free_and_init (list_id_p->tpl_descr.f_valp);
533  }
534 
536  {
538  }
539 
540  if (list_id_p->sort_list)
541  {
542  qfile_free_sort_list (NULL, list_id_p->sort_list);
543  list_id_p->sort_list = NULL;
544  }
545 
546  if (list_id_p->type_list.domp != NULL)
547  {
548  free_and_init (list_id_p->type_list.domp);
549  }
550 
551  QFILE_CLEAR_LIST_ID (list_id_p);
552 }
553 
554 /*
555  * qfile_free_list_id () -
556  * return:
557  * list_id(in/out): List identifier
558  *
559  * Note: The allocated areas inside the area pointed by the list_id and
560  * the area itself pointed by the list_id are freed.
561  */
562 void
564 {
565  /* This function is remained for debugging purpose. Do not call this function directly. Use
566  * QFILE_FREE_AND_INIT_LIST_ID macro. */
567  qfile_clear_list_id (list_id_p);
568  free (list_id_p);
569 }
570 
571 
572 /*
573  * qfile_free_sort_list () -
574  * return:
575  * sort_list(in): Sort item list pointer
576  *
577  * Note: The area allocated for sort_list is freed.
578  */
579 void
580 qfile_free_sort_list (THREAD_ENTRY * thread_p, SORT_LIST * sort_list_p)
581 {
582  LF_TRAN_ENTRY *t_entry;
583  SORT_LIST *tmp;
584 
585  /* get tran entry */
586  t_entry = thread_get_tran_entry (thread_p, THREAD_TS_FREE_SORT_LIST);
587 
588  while (sort_list_p != NULL)
589  {
590  tmp = sort_list_p;
591  sort_list_p = sort_list_p->next;
592  tmp->next = NULL;
593 
594  if (lf_freelist_retire (t_entry, &qfile_sort_list_Freelist, tmp) != NO_ERROR)
595  {
596  assert (false);
597  return;
598  }
599  }
600 }
601 
602 /*
603  * qfile_allocate_sort_list () -
604  * return: sort item list, or NULL
605  * cnt(in): Number of nodes in the list
606  *
607  * Note: A linked list of cnt sort structure nodes is allocated and returned.
608  *
609  * Note: Only qfile_free_sort_list function should be used to free the area
610  * since the linked list is allocated in a contigous region.
611  */
612 SORT_LIST *
614 {
615  LF_TRAN_ENTRY *t_entry;
616  SORT_LIST *head = NULL, *tail = NULL, *tmp;
617 
618  if (count <= 0)
619  {
620  return NULL;
621  }
622 
623  /* fetch tran entry */
624  t_entry = thread_get_tran_entry (thread_p, THREAD_TS_FREE_SORT_LIST);
625 
626  /* allocate complete list */
627  while (count > 0)
628  {
629  tmp = (SORT_LIST *) lf_freelist_claim (t_entry, &qfile_sort_list_Freelist);
630  if (tmp == NULL)
631  {
632  assert (false);
633  return NULL;
634  }
635 
636  if (head == NULL)
637  {
638  head = tmp;
639  tail = tmp;
640  }
641  else
642  {
643  tail->next = tmp;
644  tail = tmp;
645  }
646 
647  count--;
648  }
649 
650  return head;
651 }
652 
653 /*
654  * qfile_alloc_sort_list () - allocate a sort list
655  * returns: new sort list
656  */
657 static void *
659 {
660  return malloc (sizeof (SORT_LIST));
661 }
662 
663 /*
664  * qfile_dealloc_sort_list () - deallocate a sort list
665  * returns: error code or NO_ERROR
666  * sort_list(in): sort list to free
667  */
668 static int
670 {
671  free (sort_list);
672  return NO_ERROR;
673 }
674 
675 /*
676  * qfile_get_sort_list_size () -
677  * return: the number of sort_list item
678  * sort_list(in): sort item list pointer
679  *
680  */
681 static int
683 {
684  SORT_LIST *s;
685  int len = 0;
686 
687  for (s = sort_list_p; s; s = s->next)
688  {
689  ++len;
690  }
691 
692  return len;
693 }
694 
695 /*
696  * qfile_is_sort_list_covered () -
697  * return: true or false
698  * covering_list(in): covering sort item list pointer
699  * covered_list(in): covered sort item list pointer
700  *
701  * Note: if covering_list covers covered_list returns true.
702  * otherwise, returns false.
703  */
704 bool
705 qfile_is_sort_list_covered (SORT_LIST * covering_list_p, SORT_LIST * covered_list_p)
706 {
707  SORT_LIST *s1, *s2;
708 
709  if (covered_list_p == NULL)
710  {
711  return false;
712  }
713 
714  for (s1 = covering_list_p, s2 = covered_list_p; s1 && s2; s1 = s1->next, s2 = s2->next)
715  {
716  if (s1->s_order != s2->s_order || s1->s_nulls != s2->s_nulls || s1->pos_descr.pos_no != s2->pos_descr.pos_no)
717  {
718  return false;
719  }
720  }
721 
722  if (s1 == NULL && s2)
723  {
724  return false;
725  }
726  else
727  {
728  return true;
729  }
730 }
731 
732 /*
733  * qfile_compare_tuple_values () -
734  * return: NO_ERROR or error code
735  * tpl1(in): First tuple value
736  * tpl2(in): Second tuple value
737  * domain(in): both tuple values must be of the same domain
738  *
739  * Note: This routine checks if two tuple values are equal.
740  * Coercion is not done.
741  * If both values are UNBOUND, the values are treated as equal.
742  */
743 static int
744 qfile_compare_tuple_values (QFILE_TUPLE tuple1, QFILE_TUPLE tuple2, TP_DOMAIN * domain_p, int *compare_result)
745 {
746  OR_BUF buf;
747  DB_VALUE dbval1, dbval2;
748  int length1, length2;
749  PR_TYPE *pr_type_p;
750  bool is_copy;
751  DB_TYPE type = TP_DOMAIN_TYPE (domain_p);
752  int rc;
753 
754  pr_type_p = domain_p->type;
755  is_copy = false;
756  is_copy = pr_is_set_type (type) ? true : false;
757  length1 = QFILE_GET_TUPLE_VALUE_LENGTH (tuple1);
758 
759  /* zero length means NULL */
760  if (length1 == 0)
761  {
762  db_make_null (&dbval1);
763  }
764  else
765  {
766  or_init (&buf, (char *) tuple1 + QFILE_TUPLE_VALUE_HEADER_SIZE, length1);
767  rc = pr_type_p->data_readval (&buf, &dbval1, domain_p, -1, is_copy, NULL, 0);
768  if (rc != NO_ERROR)
769  {
770  return ER_FAILED;
771  }
772  }
773 
774  length2 = QFILE_GET_TUPLE_VALUE_LENGTH (tuple2);
775 
776  /* zero length means NULL */
777  if (length2 == 0)
778  {
779  db_make_null (&dbval2);
780  }
781  else
782  {
783  or_init (&buf, (char *) tuple2 + QFILE_TUPLE_VALUE_HEADER_SIZE, length2);
784  rc = pr_type_p->data_readval (&buf, &dbval2, domain_p, -1, is_copy, NULL, 0);
785  if (rc != NO_ERROR)
786  {
787  pr_clear_value (&dbval1);
788  return ER_FAILED;
789  }
790  }
791 
792  if (length1 == 0 && length2 == 0)
793  {
794  *compare_result = DB_EQ; /* NULL values compare equal in this routine */
795  }
796  else if (length1 == 0)
797  {
798  *compare_result = DB_LT;
799  }
800  else if (length2 == 0)
801  {
802  *compare_result = DB_GT;
803  }
804  else
805  {
806  *compare_result = pr_type_p->cmpval (&dbval1, &dbval2, 0, 1, NULL, domain_p->collation_id);
807  }
808 
809  pr_clear_value (&dbval1);
810  pr_clear_value (&dbval2);
811 
812  return NO_ERROR;
813 }
814 
815 /*
816  * qfile_unify_types () -
817  * return:
818  * list_id1(in/out): Destination list identifier
819  * list_id2(in): Source list identifier
820  *
821  * Note: For every destination type which is DB_TYPE_NULL,
822  * set it to the source type.
823  * This should probably set an error for non-null mismatches.
824  */
825 int
826 qfile_unify_types (QFILE_LIST_ID * list_id1_p, const QFILE_LIST_ID * list_id2_p)
827 {
828  int i;
829  int max_count = list_id1_p->type_list.type_cnt;
830  DB_TYPE type1, type2;
831 
832  if (max_count != list_id2_p->type_list.type_cnt)
833  {
834  /* error, but is ignored for now. */
835  if (max_count > list_id2_p->type_list.type_cnt)
836  {
837  max_count = list_id2_p->type_list.type_cnt;
838  }
839  }
840 
841  for (i = 0; i < max_count; i++)
842  {
843  type1 = TP_DOMAIN_TYPE (list_id1_p->type_list.domp[i]);
844  type2 = TP_DOMAIN_TYPE (list_id2_p->type_list.domp[i]);
845 
846  if (type1 == DB_TYPE_VARIABLE)
847  {
848  /* The domain of list1 is not resolved, because there is no tuple. */
849  assert_release (list_id1_p->tuple_cnt == 0);
850  list_id1_p->type_list.domp[i] = list_id2_p->type_list.domp[i];
851  continue;
852  }
853  else if (type2 == DB_TYPE_VARIABLE)
854  {
855  /* The domain of list2 is not resolved, because there is no tuple. */
856  assert_release (list_id2_p->tuple_cnt == 0);
857  continue;
858  }
859 
860  if (type1 == DB_TYPE_NULL)
861  {
862  list_id1_p->type_list.domp[i] = list_id2_p->type_list.domp[i];
863  }
864  else
865  {
866  if (type2 != DB_TYPE_NULL && (list_id1_p->type_list.domp[i] != list_id2_p->type_list.domp[i]))
867  {
868  if (type1 == type2
869  && ((pr_is_string_type (type1) && pr_is_variable_type (type1)) || (type1 == DB_TYPE_JSON)))
870  {
871  /* OK for variable string types with different precision or json types */
872  }
873  else
874  {
877  }
878  }
879  }
880 
883  {
886  }
887  }
888 
889  return NO_ERROR;
890 }
891 
892 /*
893  * qfile_locate_tuple_value () -
894  * return: V_BOUND/V_UNBOUND
895  * tpl(in): tuple
896  * index(in): value position number
897  * tpl_val(out): set to point to the specified value
898  * val_size(out): set to the value size
899  *
900  * Note: Sets the tpl_val pointer to the specified value.
901  *
902  * Note: The index validity check must be done by the caller.
903  */
905 qfile_locate_tuple_value (QFILE_TUPLE tuple, int index, char **tuple_value_p, int *value_size_p)
906 {
907  tuple += QFILE_TUPLE_LENGTH_SIZE;
908  return qfile_locate_tuple_value_r (tuple, index, tuple_value_p, value_size_p);
909 }
910 
911 /*
912  * qfile_locate_tuple_value_r () -
913  * return: V_BOUND/V_UNBOUND
914  * tpl(in): tuple
915  * index(in): value position number
916  * tpl_val(out): set to point to the specified value
917  * val_size(out): set to the value size
918  *
919  * Note: The index validity check must be done by the caller.
920  */
922 qfile_locate_tuple_value_r (QFILE_TUPLE tuple, int index, char **tuple_value_p, int *value_size_p)
923 {
924  int i;
925 
926  for (i = 0; i < index; i++)
927  {
929  }
930 
931  *tuple_value_p = tuple + QFILE_TUPLE_VALUE_HEADER_SIZE;
932  *value_size_p = QFILE_GET_TUPLE_VALUE_LENGTH (tuple);
933 
934  if (QFILE_GET_TUPLE_VALUE_FLAG (tuple) == V_UNBOUND)
935  {
936  return V_UNBOUND;
937  }
938  else
939  {
940  return V_BOUND;
941  }
942 }
943 
944 /*
945  * qfile_locate_tuple_next_value () -
946  * return: error code or no error
947  * iterator(in): OR_BUF for iterating tuple values
948  * buf(out): output OR_BUF to be positioned on next tuple value
949  * flag(out): V_BOUND/V_UNBOUND
950  */
951 int
953 {
954  int value_size = QFILE_GET_TUPLE_VALUE_LENGTH (iterator->ptr);
955  *flag = QFILE_GET_TUPLE_VALUE_FLAG (iterator->ptr);
956 
957  /* initialize output buffer */
958  OR_BUF_INIT ((*buf), iterator->ptr + QFILE_TUPLE_VALUE_HEADER_SIZE, value_size);
959 
960  /* advance iterator */
961  return or_advance (iterator, QFILE_TUPLE_VALUE_HEADER_SIZE + value_size);
962 }
963 
964 #if defined (CUBRID_DEBUG)
965 /*
966  * qfile_print_tuple () - Prints the tuple content associated with the type list
967  * return: none
968  * type_list(in): type list
969  * tpl(in): tuple
970  * Note: Each tuple start is aligned with MAX_ALIGNMENT
971  * Each tuple value header is aligned with MAX_ALIGNMENT,
972  * Each tuple value is aligned with MAX_ALIGNMENT
973  */
974 static void
975 qfile_print_tuple (QFILE_TUPLE_VALUE_TYPE_LIST * type_list_p, QFILE_TUPLE tuple)
976 {
977  DB_VALUE dbval;
978  PR_TYPE *pr_type_p;
979  int i;
980  char *tuple_p;
981  OR_BUF buf;
982 
983  db_make_null (&dbval);
984 
985  if (type_list_p == NULL || type_list_p->type_cnt <= 0)
986  {
987  return;
988  }
989 
990  fprintf (stdout, "\n{ ");
991  tuple_p = (char *) tuple + QFILE_TUPLE_LENGTH_SIZE;
992 
993  for (i = 0; i < type_list_p->type_cnt; i++)
994  {
995  if (QFILE_GET_TUPLE_VALUE_FLAG (tuple_p) == V_BOUND)
996  {
997  pr_type_p = type_list_p->domp[i]->type;
999  (*(pr_type_p->readval)) (&buf, &dbval, type_list_p->domp[i], -1, true, NULL, 0);
1000 
1001  db_fprint_value (stdout, &dbval);
1002  if (pr_is_set_type (pr_type_p->id))
1003  {
1004  pr_clear_value (&dbval);
1005  }
1006  }
1007  else
1008  {
1009  fprintf (stdout, "VALUE_UNBOUND");
1010  }
1011 
1012  if (i != type_list_p->type_cnt - 1)
1013  {
1014  fprintf (stdout, " , ");
1015  }
1016 
1018  }
1019 
1020  fprintf (stdout, " }\n");
1021 }
1022 #endif
1023 
1024 static void
1026 {
1027  OR_PUT_INT (page_p + QFILE_TUPLE_COUNT_OFFSET, 0);
1030  OR_PUT_INT (page_p + QFILE_LAST_TUPLE_OFFSET, 0);
1035 #if !defined(NDEBUG)
1036  /* suppress valgrind UMW error */
1038 #endif
1039 }
1040 
1041 static void
1042 qfile_set_dirty_page_and_skip_logging (THREAD_ENTRY * thread_p, PAGE_PTR page_p, VFID * vfid_p, int free_page)
1043 {
1044  LOG_DATA_ADDR addr;
1045 
1046  addr.vfid = vfid_p;
1047  addr.pgptr = page_p;
1048  addr.offset = -1;
1049  log_skip_logging (thread_p, &addr);
1050 
1051  pgbuf_set_dirty (thread_p, page_p, free_page);
1052 }
1053 
1054 /*
1055  * qfile_load_xasl_node_header () - Load XASL node header from xasl stream
1056  *
1057  * return : void
1058  * thread_p (in) : thread entry
1059  * xasl_stream (in) : XASL stream
1060  * xasl_header_p (out) : pointer to XASL node header
1061  */
1062 void
1064 {
1065  if (xasl_header_p == NULL)
1066  {
1067  /* cannot save XASL node header */
1068  return;
1069  }
1070  /* initialize XASL node header */
1071  INIT_XASL_NODE_HEADER (xasl_header_p);
1072 
1073  if (xasl_stream == NULL)
1074  {
1075  /* cannot obtain XASL stream */
1076  return;
1077  }
1078 
1079  /* get XASL node header from stream */
1080  if (stx_map_stream_to_xasl_node_header (thread_p, xasl_header_p, xasl_stream) != NO_ERROR)
1081  {
1082  assert (false);
1083  }
1084 }
1085 
1086 /*
1087  * qfile_initialize () -
1088  * return: int (true : successful initialization,
1089  * false: unsuccessful initialization)
1090  *
1091  * Note: This routine initializes the query file manager structures
1092  * and global variables.
1093  */
1094 int
1096 {
1101 
1103 
1104  if (lf_freelist_init (&qfile_sort_list_Freelist, 10, 100, &qfile_sort_list_entry_desc, &free_sort_list_Ts) !=
1105  NO_ERROR)
1106  {
1107  return ER_FAILED;
1108  }
1109 
1110  return true;
1111 }
1112 
1113 /* qfile_finalize () -
1114  * return:
1115  */
1116 void
1118 {
1119  lf_freelist_destroy (&qfile_sort_list_Freelist);
1120 }
1121 
1122 /*
1123  * qfile_open_list () -
1124  * return: QFILE_LIST_ID *, or NULL
1125  * type_list(in/out): type list for the list file to be created
1126  * sort_list(in): sort info for the list file to be created
1127  * query_id(in): query id associated with this list file
1128  * flag(in): {QFILE_FLAG_RESULT_FILE, QFILE_FLAG_DISTINCT, QFILE_FLAG_ALL}
1129  * whether to do 'all' or 'distinct' operation
1130  *
1131  * Note: A list file is created by using the specified type list and
1132  * the list file identifier is set. The first page of the list
1133  * file is allocated only when the first tuple is inserted to
1134  * list file, if any.
1135  * A 'SORT_LIST' is associated to the output list file according to
1136  * 'sort_list_p' input argument (if not null), or created if the
1137  * QFILE_FLAG_DISTINCT flag is specified; if neither QFILE_FLAG_DISTINCT
1138  * or 'sort_list_p' are supplied, no SORT_LIST is associated.
1139  *
1140  */
1141 QFILE_LIST_ID *
1142 qfile_open_list (THREAD_ENTRY * thread_p, QFILE_TUPLE_VALUE_TYPE_LIST * type_list_p, SORT_LIST * sort_list_p,
1143  QUERY_ID query_id, int flag)
1144 {
1145  QFILE_LIST_ID *list_id_p;
1146  int len, i;
1147  SORT_LIST *src_sort_list_p, *dest_sort_list_p;
1148  size_t type_list_size;
1149 
1150  list_id_p = (QFILE_LIST_ID *) malloc (sizeof (QFILE_LIST_ID));
1151  if (list_id_p == NULL)
1152  {
1153  return NULL;
1154  }
1155 
1156  QFILE_CLEAR_LIST_ID (list_id_p);
1157  list_id_p->tuple_cnt = 0;
1158  list_id_p->page_cnt = 0;
1159  list_id_p->type_list.type_cnt = type_list_p->type_cnt;
1160  list_id_p->query_id = query_id;
1161 
1163  {
1164  list_id_p->tfile_vfid = qmgr_create_result_file (thread_p, query_id);
1165  }
1167  {
1168  list_id_p->tfile_vfid = qmgr_create_new_temp_file (thread_p, query_id, TEMP_FILE_MEMBUF_KEY_BUFFER);
1169  }
1170  else
1171  {
1172  list_id_p->tfile_vfid = qmgr_create_new_temp_file (thread_p, query_id, TEMP_FILE_MEMBUF_NORMAL);
1173  }
1174 
1175  if (list_id_p->tfile_vfid == NULL)
1176  {
1177  free_and_init (list_id_p);
1178  return NULL;
1179  }
1180 
1181  VFID_COPY (&(list_id_p->temp_vfid), &(list_id_p->tfile_vfid->temp_vfid));
1182  list_id_p->type_list.domp = NULL;
1183 
1184  if (list_id_p->type_list.type_cnt != 0)
1185  {
1186  type_list_size = list_id_p->type_list.type_cnt * DB_SIZEOF (TP_DOMAIN *);
1187  list_id_p->type_list.domp = (TP_DOMAIN **) malloc (type_list_size);
1188  if (list_id_p->type_list.domp == NULL)
1189  {
1190  free_and_init (list_id_p);
1191  return NULL;
1192  }
1193 
1194  memcpy (list_id_p->type_list.domp, type_list_p->domp, type_list_size);
1195  }
1196 
1197  /* build sort_list */
1199  {
1200  len = list_id_p->type_list.type_cnt;
1201  if (len > 0)
1202  {
1203  dest_sort_list_p = qfile_allocate_sort_list (thread_p, len);
1204  if (dest_sort_list_p == NULL)
1205  {
1206  free_and_init (list_id_p->type_list.domp);
1207  free_and_init (list_id_p);
1208  return NULL;
1209  }
1210 
1211  for (i = 0, list_id_p->sort_list = dest_sort_list_p; i < len; i++, dest_sort_list_p = dest_sort_list_p->next)
1212  {
1213  dest_sort_list_p->s_order = S_ASC;
1214  dest_sort_list_p->s_nulls = S_NULLS_FIRST;
1215  dest_sort_list_p->pos_descr.dom = list_id_p->type_list.domp[i];
1216  dest_sort_list_p->pos_descr.pos_no = i;
1217  }
1218  }
1219  }
1220  else if (sort_list_p != NULL)
1221  {
1222  len = qfile_get_sort_list_size (sort_list_p);
1223  if (len > 0)
1224  {
1225  dest_sort_list_p = qfile_allocate_sort_list (thread_p, len);
1226  if (dest_sort_list_p == NULL)
1227  {
1228  free_and_init (list_id_p->type_list.domp);
1229  free_and_init (list_id_p);
1230  return NULL;
1231  }
1232 
1233  for (src_sort_list_p = sort_list_p, list_id_p->sort_list = dest_sort_list_p; src_sort_list_p;
1234  src_sort_list_p = src_sort_list_p->next, dest_sort_list_p = dest_sort_list_p->next)
1235  {
1236  dest_sort_list_p->s_order = src_sort_list_p->s_order;
1237  dest_sort_list_p->s_nulls = src_sort_list_p->s_nulls;
1238  dest_sort_list_p->pos_descr.dom = src_sort_list_p->pos_descr.dom;
1239  dest_sort_list_p->pos_descr.pos_no = src_sort_list_p->pos_descr.pos_no;
1240  }
1241  }
1242  }
1243  else
1244  {
1245  /* no DISTINCT and no source SORT_LIST supplied */
1246  list_id_p->sort_list = NULL;
1247  }
1248 
1249  qfile_update_qlist_count (thread_p, list_id_p, 1);
1250 
1251  return list_id_p;
1252 }
1253 
1254 /*
1255  * qfile_close_list () -
1256  * return: none
1257  * list_id(in/out): List file identifier
1258  *
1259  * Note: The specified list file is closed and memory buffer for the
1260  * list file is freed.
1261  */
1262 void
1264 {
1265  if (list_id_p)
1266  {
1267  if (list_id_p->last_pgptr != NULL)
1268  {
1269  QFILE_PUT_NEXT_VPID_NULL (list_id_p->last_pgptr);
1270 
1271  qmgr_free_old_page_and_init (thread_p, list_id_p->last_pgptr, list_id_p->tfile_vfid);
1272  }
1273  }
1274 }
1275 
1276 /*
1277  * qfile_reopen_list_as_append_mode () -
1278  * thread_p(in) :
1279  * list_id_p(in):
1280  *
1281  * Note:
1282  */
1283 int
1285 {
1286  PAGE_PTR last_page_ptr;
1287  QMGR_TEMP_FILE *temp_file_p;
1288 
1289  if (list_id_p->tfile_vfid == NULL)
1290  {
1291  /* Invalid list_id_p. list_id_p might be cleared or not be opened. list_id_p must have valid QMGR_TEMP_FILE to
1292  * reopen. */
1293  assert_release (0);
1294  return ER_FAILED;
1295  }
1296 
1297  if (VPID_ISNULL (&list_id_p->first_vpid))
1298  {
1299  assert_release (VPID_ISNULL (&list_id_p->last_vpid));
1300  assert_release (list_id_p->last_pgptr == NULL);
1301 
1302  return NO_ERROR;
1303  }
1304 
1305  if (list_id_p->last_pgptr != NULL)
1306  {
1307  return NO_ERROR;
1308  }
1309 
1310  temp_file_p = list_id_p->tfile_vfid;
1311 
1312  if (temp_file_p->membuf && list_id_p->last_vpid.volid == NULL_VOLID)
1313  {
1314  /* The last page is in the membuf */
1315  assert_release (temp_file_p->membuf_last >= list_id_p->last_vpid.pageid);
1316  /* The page of last record in the membuf */
1317  last_page_ptr = temp_file_p->membuf[list_id_p->last_vpid.pageid];
1318  }
1319  else
1320  {
1321  assert_release (!VPID_ISNULL (&list_id_p->last_vpid));
1322  last_page_ptr =
1324  if (last_page_ptr == NULL)
1325  {
1326  return ER_FAILED;
1327  }
1328 
1329  (void) pgbuf_check_page_ptype (thread_p, last_page_ptr, PAGE_QRESULT);
1330 
1331  }
1332 
1333  list_id_p->last_pgptr = last_page_ptr;
1334 
1335  return NO_ERROR;
1336 }
1337 
1338 static bool
1340 {
1341  return VPID_ISNULL (&list_id_p->first_vpid);
1342 }
1343 
1344 static bool
1345 qfile_is_last_page_full (QFILE_LIST_ID * list_id_p, int tuple_length, const bool is_ovf_page)
1346 {
1347  assert (tuple_length >= 0 && list_id_p->last_offset >= 0);
1348  assert ((tuple_length + list_id_p->last_offset) >= 0);
1349  assert (list_id_p->last_offset <= DB_PAGESIZE);
1350 
1351  if (!is_ovf_page && list_id_p->last_offset <= QFILE_PAGE_HEADER_SIZE)
1352  {
1353  /* empty page - it must have at least one tuple record. */
1354  assert (list_id_p->last_offset == QFILE_PAGE_HEADER_SIZE);
1355  return false;
1356  }
1357 
1358  return (tuple_length + list_id_p->last_offset) > DB_PAGESIZE;
1359 }
1360 
1361 static void
1362 qfile_set_dirty_page (THREAD_ENTRY * thread_p, PAGE_PTR page_p, int free_page, QMGR_TEMP_FILE * vfid_p)
1363 {
1364  LOG_DATA_ADDR addr;
1365 
1366  addr.vfid = NULL;
1367  addr.pgptr = page_p;
1368  addr.offset = -1;
1369 
1370  qmgr_set_dirty_page (thread_p, page_p, free_page, &addr, vfid_p);
1371 }
1372 
1373 static PAGE_PTR
1374 qfile_allocate_new_page (THREAD_ENTRY * thread_p, QFILE_LIST_ID * list_id_p, PAGE_PTR page_p, bool is_ovf_page)
1375 {
1376  PAGE_PTR new_page_p;
1377  VPID new_vpid;
1378 
1379 #if defined (SERVER_MODE)
1380  if (qmgr_is_query_interrupted (thread_p, list_id_p->query_id) == true)
1381  {
1383  return NULL;
1384  }
1385 #endif /* SERVER_MODE */
1386 
1387  new_page_p = qmgr_get_new_page (thread_p, &new_vpid, list_id_p->tfile_vfid);
1388  if (new_page_p == NULL)
1389  {
1390  return NULL;
1391  }
1392 
1393  QFILE_PUT_TUPLE_COUNT (new_page_p, 0);
1394  QFILE_PUT_PREV_VPID (new_page_p, &list_id_p->last_vpid);
1395 
1396  /*
1397  * For streaming query support, set next_vpid differently
1398  */
1399  if (is_ovf_page)
1400  {
1401  QFILE_PUT_NEXT_VPID_NULL (new_page_p);
1402  }
1403  else
1404  {
1405  LS_PUT_NEXT_VPID (new_page_p);
1406  }
1407 
1409  QFILE_PUT_OVERFLOW_VPID_NULL (new_page_p);
1410 
1411  if (page_p)
1412  {
1413  QFILE_PUT_NEXT_VPID (page_p, &new_vpid);
1414  }
1415 
1416  list_id_p->page_cnt++;
1417 
1418  if (page_p)
1419  {
1420  qfile_set_dirty_page (thread_p, page_p, FREE, list_id_p->tfile_vfid);
1421  }
1422  else
1423  {
1424  /* first list file tuple */
1425  QFILE_COPY_VPID (&list_id_p->first_vpid, &new_vpid);
1426  }
1427  QFILE_COPY_VPID (&list_id_p->last_vpid, &new_vpid);
1428  list_id_p->last_pgptr = new_page_p;
1429  list_id_p->last_offset = QFILE_PAGE_HEADER_SIZE;
1430 
1431  return new_page_p;
1432 }
1433 
1434 static PAGE_PTR
1435 qfile_allocate_new_ovf_page (THREAD_ENTRY * thread_p, QFILE_LIST_ID * list_id_p, PAGE_PTR page_p, PAGE_PTR prev_page_p,
1436  int tuple_length, int offset, int *tuple_page_size_p)
1437 {
1438  PAGE_PTR new_page_p;
1439  VPID new_vpid;
1440 
1441  *tuple_page_size_p = MIN (tuple_length - offset, qfile_Max_tuple_page_size);
1442 
1443  new_page_p = qmgr_get_new_page (thread_p, &new_vpid, list_id_p->tfile_vfid);
1444  if (new_page_p == NULL)
1445  {
1446  return NULL;
1447  }
1448 
1449  list_id_p->page_cnt++;
1450 
1451  QFILE_PUT_NEXT_VPID_NULL (new_page_p);
1453  QFILE_PUT_OVERFLOW_TUPLE_PAGE_SIZE (new_page_p, *tuple_page_size_p);
1454  QFILE_PUT_OVERFLOW_VPID_NULL (new_page_p);
1455 
1456  /*
1457  * connect the previous page to this page and free,
1458  * if it is not the first page
1459  */
1460  QFILE_PUT_OVERFLOW_VPID (prev_page_p, &new_vpid);
1461  if (prev_page_p != page_p)
1462  {
1463  qfile_set_dirty_page (thread_p, prev_page_p, FREE, list_id_p->tfile_vfid);
1464  }
1465 
1466  return new_page_p;
1467 }
1468 
1469 static int
1471  int tuple_length, bool is_ovf_page)
1472 {
1473  PAGE_PTR new_page_p;
1474 
1475  if (qfile_is_first_tuple (list_id_p) || qfile_is_last_page_full (list_id_p, tuple_length, is_ovf_page))
1476  {
1477  new_page_p = qfile_allocate_new_page (thread_p, list_id_p, *page_p, is_ovf_page);
1478  if (new_page_p == NULL)
1479  {
1480  return ER_FAILED;
1481  }
1482 
1483  *page_p = new_page_p;
1484  }
1485 
1486  QFILE_PUT_TUPLE_COUNT (*page_p, QFILE_GET_TUPLE_COUNT (*page_p) + 1);
1487  QFILE_PUT_LAST_TUPLE_OFFSET (*page_p, list_id_p->last_offset);
1488 
1489  return NO_ERROR;
1490 }
1491 
1492 static void
1493 qfile_add_tuple_to_list_id (QFILE_LIST_ID * list_id_p, PAGE_PTR page_p, int tuple_length, int written_tuple_length)
1494 {
1495  QFILE_PUT_PREV_TUPLE_LENGTH (page_p, list_id_p->lasttpl_len);
1496 
1497  list_id_p->tuple_cnt++;
1498  list_id_p->lasttpl_len = tuple_length;
1499  list_id_p->last_offset += written_tuple_length;
1500  assert (list_id_p->last_offset <= DB_PAGESIZE);
1501 }
1502 
1503 /*
1504  * qfile_add_tuple_to_list () - The given tuple is added to the end of the list file
1505  * return: int (NO_ERROR or ER_FAILED)
1506  * list_id(in): List File Identifier
1507  * tpl(in): Tuple to be added
1508  *
1509  */
1510 int
1512 {
1513  PAGE_PTR cur_page_p, new_page_p, prev_page_p;
1514  int tuple_length;
1515  char *page_p, *tuple_p;
1516  int offset, tuple_page_size;
1517 
1518  if (list_id_p == NULL)
1519  {
1520  return ER_FAILED;
1521  }
1522 
1523  QFILE_CHECK_LIST_FILE_IS_CLOSED (list_id_p);
1524 
1525  cur_page_p = list_id_p->last_pgptr;
1526  tuple_length = QFILE_GET_TUPLE_LENGTH (tuple);
1527 
1528  if (qfile_allocate_new_page_if_need (thread_p, list_id_p, &cur_page_p, tuple_length, false) != NO_ERROR)
1529  {
1530  return ER_FAILED;
1531  }
1532 
1533  page_p = (char *) cur_page_p + list_id_p->last_offset;
1534  tuple_page_size = MIN (tuple_length, qfile_Max_tuple_page_size);
1535  assert ((list_id_p->last_offset + tuple_page_size) <= DB_PAGESIZE);
1536  memcpy (page_p, tuple, tuple_page_size);
1537 
1538  qfile_add_tuple_to_list_id (list_id_p, page_p, tuple_length, tuple_page_size);
1539 
1540  prev_page_p = cur_page_p;
1541  for (offset = tuple_page_size, tuple_p = (char *) tuple + offset; offset < tuple_length;
1542  offset += tuple_page_size, tuple_p += tuple_page_size)
1543  {
1544  new_page_p =
1545  qfile_allocate_new_ovf_page (thread_p, list_id_p, cur_page_p, prev_page_p, tuple_length, offset,
1546  &tuple_page_size);
1547  if (new_page_p == NULL)
1548  {
1549  if (prev_page_p != cur_page_p)
1550  {
1551  qfile_set_dirty_page (thread_p, prev_page_p, FREE, list_id_p->tfile_vfid);
1552  }
1553  return ER_FAILED;
1554  }
1555 
1556  memcpy ((char *) new_page_p + QFILE_PAGE_HEADER_SIZE, tuple_p, tuple_page_size);
1557 
1558  prev_page_p = new_page_p;
1559  }
1560 
1561  if (prev_page_p != cur_page_p)
1562  {
1563  QFILE_PUT_OVERFLOW_VPID_NULL (prev_page_p);
1564  qfile_set_dirty_page (thread_p, prev_page_p, FREE, list_id_p->tfile_vfid);
1565  }
1566 
1567  qfile_set_dirty_page (thread_p, cur_page_p, DONT_FREE, list_id_p->tfile_vfid);
1568 
1569  return NO_ERROR;
1570 }
1571 
1572 static int
1573 qfile_save_single_bound_item_tuple (QFILE_TUPLE_DESCRIPTOR * tuple_descr_p, char *tuple_p, char *page_p,
1574  int tuple_length)
1575 {
1576  int align;
1577 
1578  align = DB_ALIGN (tuple_descr_p->item_size, MAX_ALIGNMENT);
1579 
1581  QFILE_PUT_TUPLE_VALUE_LENGTH (tuple_p, align);
1582 
1583  tuple_p += QFILE_TUPLE_VALUE_HEADER_SIZE;
1584  memcpy (tuple_p, tuple_descr_p->item, tuple_descr_p->item_size);
1585 #if !defined(NDEBUG)
1586  /* suppress valgrind UMW error */
1587  memset (tuple_p + tuple_descr_p->item_size, 0, align - tuple_descr_p->item_size);
1588 #endif
1589 
1590  QFILE_PUT_TUPLE_LENGTH (page_p, tuple_length);
1591 
1592  return NO_ERROR;
1593 }
1594 
1595 static int
1596 qfile_save_normal_tuple (QFILE_TUPLE_DESCRIPTOR * tuple_descr_p, char *tuple_p, char *page_p, int tuple_length)
1597 {
1598  int i, tuple_value_size;
1599 
1600  for (i = 0; i < tuple_descr_p->f_cnt; i++)
1601  {
1602  if (qdata_copy_db_value_to_tuple_value (tuple_descr_p->f_valp[i],
1603  !(tuple_descr_p->clear_f_val_at_clone_decache[i]),
1604  tuple_p, &tuple_value_size) != NO_ERROR)
1605  {
1606  return ER_FAILED;
1607  }
1608  tuple_p += tuple_value_size;
1609  }
1610 
1611  QFILE_PUT_TUPLE_LENGTH (page_p, tuple_length);
1612  return NO_ERROR;
1613 }
1614 
1615 static int
1616 qfile_save_sort_key_tuple (QFILE_TUPLE_DESCRIPTOR * tuple_descr_p, char *tuple_p, char *page_p, int tuple_length)
1617 {
1618  SORTKEY_INFO *key_info_p;
1619  SORT_REC *sort_rec_p;
1620  int i, c, nkeys, len;
1621  char *src_p;
1622 
1623  key_info_p = (SORTKEY_INFO *) (tuple_descr_p->sortkey_info);
1624  nkeys = key_info_p->nkeys;
1625  sort_rec_p = (SORT_REC *) (tuple_descr_p->sort_rec);
1626 
1627  for (i = 0; i < nkeys; i++)
1628  {
1629  c = key_info_p->key[i].permuted_col;
1630 
1631  if (sort_rec_p->s.offset[c] == 0)
1632  {
1634  QFILE_PUT_TUPLE_VALUE_LENGTH (tuple_p, 0);
1635  }
1636  else
1637  {
1638  src_p = (char *) sort_rec_p + sort_rec_p->s.offset[c] - QFILE_TUPLE_VALUE_HEADER_SIZE;
1639  len = QFILE_GET_TUPLE_VALUE_LENGTH (src_p);
1640  memcpy (tuple_p, src_p, len + QFILE_TUPLE_VALUE_HEADER_SIZE);
1641  tuple_p += len;
1642  }
1643 
1644  tuple_p += QFILE_TUPLE_VALUE_HEADER_SIZE;
1645  }
1646 
1647  QFILE_PUT_TUPLE_LENGTH (page_p, tuple_length);
1648  return NO_ERROR;
1649 }
1650 
1651 static int
1652 qfile_save_merge_tuple (QFILE_TUPLE_DESCRIPTOR * tuple_descr_p, char *tuple_p, char *page_p, int *tuple_length_p)
1653 {
1654  QFILE_TUPLE_RECORD *tuple_rec1_p, *tuple_rec2_p;
1655  QFILE_LIST_MERGE_INFO *merge_info_p;
1656  char *src_p;
1657  int i, tuple_value_size;
1658  INT32 ls_unbound[2] = { 0, 0 };
1659 
1660  QFILE_PUT_TUPLE_VALUE_FLAG ((char *) ls_unbound, V_UNBOUND);
1661  QFILE_PUT_TUPLE_VALUE_LENGTH ((char *) ls_unbound, 0);
1662 
1663  tuple_rec1_p = tuple_descr_p->tplrec1;
1664  tuple_rec2_p = tuple_descr_p->tplrec2;
1665  merge_info_p = tuple_descr_p->merge_info;
1666 
1667  *tuple_length_p = QFILE_TUPLE_LENGTH_SIZE;
1668 
1669  for (i = 0; i < merge_info_p->ls_pos_cnt; i++)
1670  {
1671  if (merge_info_p->ls_outer_inner_list[i] == QFILE_OUTER_LIST)
1672  {
1673  if (tuple_rec1_p)
1674  {
1675  QFILE_GET_TUPLE_VALUE_HEADER_POSITION (tuple_rec1_p->tpl, merge_info_p->ls_pos_list[i], src_p);
1676  }
1677  else
1678  {
1679  src_p = (char *) ls_unbound;
1680  }
1681  }
1682  else
1683  {
1684  if (tuple_rec2_p)
1685  {
1686  QFILE_GET_TUPLE_VALUE_HEADER_POSITION (tuple_rec2_p->tpl, merge_info_p->ls_pos_list[i], src_p);
1687  }
1688  else
1689  {
1690  src_p = (char *) ls_unbound;
1691  }
1692  }
1693 
1694  tuple_value_size = QFILE_TUPLE_VALUE_HEADER_SIZE + QFILE_GET_TUPLE_VALUE_LENGTH (src_p);
1695  memcpy (tuple_p, src_p, tuple_value_size);
1696  tuple_p += tuple_value_size;
1697  *tuple_length_p += tuple_value_size;
1698  }
1699 
1700  QFILE_PUT_TUPLE_LENGTH (page_p, *tuple_length_p);
1701  return NO_ERROR;
1702 }
1703 
1704 int
1705 qfile_save_tuple (QFILE_TUPLE_DESCRIPTOR * tuple_descr_p, QFILE_TUPLE_TYPE tuple_type, char *page_p,
1706  int *tuple_length_p)
1707 {
1708  char *tuple_p;
1709 
1710  tuple_p = (char *) page_p + QFILE_TUPLE_LENGTH_SIZE;
1711 
1712  switch (tuple_type)
1713  {
1714  case T_SINGLE_BOUND_ITEM:
1715  (void) qfile_save_single_bound_item_tuple (tuple_descr_p, tuple_p, page_p, *tuple_length_p);
1716  break;
1717 
1718  case T_NORMAL:
1719  if (qfile_save_normal_tuple (tuple_descr_p, tuple_p, page_p, *tuple_length_p) != NO_ERROR)
1720  {
1721  return ER_FAILED;
1722  }
1723  break;
1724 
1725  case T_SORTKEY:
1726  (void) qfile_save_sort_key_tuple (tuple_descr_p, tuple_p, page_p, *tuple_length_p);
1727  break;
1728 
1729  case T_MERGE:
1730  (void) qfile_save_merge_tuple (tuple_descr_p, tuple_p, page_p, tuple_length_p);
1731  break;
1732 
1733  default:
1734  return ER_FAILED;
1735  }
1736 
1737  return NO_ERROR;
1738 }
1739 
1740 /*
1741  * qfile_generate_tuple_into_list () -
1742  * return: int (NO_ERROR or ER_FAILED)
1743  * list_id(in/out): List File Identifier
1744  * tpl_type(in): tuple descriptor type
1745  * - single bound field tuple or multi field tuple
1746  *
1747  */
1748 int
1750 {
1751  QFILE_TUPLE_DESCRIPTOR *tuple_descr_p;
1752  PAGE_PTR cur_page_p;
1753  int tuple_length;
1754  char *page_p;
1755 
1756  if (list_id_p == NULL)
1757  {
1758  return ER_FAILED;
1759  }
1760 
1761  QFILE_CHECK_LIST_FILE_IS_CLOSED (list_id_p);
1762 
1763  cur_page_p = list_id_p->last_pgptr;
1764  tuple_descr_p = &(list_id_p->tpl_descr);
1765  tuple_length = tuple_descr_p->tpl_size;
1766 
1767  assert (tuple_length <= qfile_Max_tuple_page_size);
1768 
1769  if (qfile_allocate_new_page_if_need (thread_p, list_id_p, &cur_page_p, tuple_length, false) != NO_ERROR)
1770  {
1771  return ER_FAILED;
1772  }
1773 
1774  page_p = (char *) cur_page_p + list_id_p->last_offset;
1775  if (qfile_save_tuple (tuple_descr_p, tuple_type, page_p, &tuple_length) != NO_ERROR)
1776  {
1777  return ER_FAILED;
1778  }
1779 
1780  assert ((page_p + tuple_length - cur_page_p) <= DB_PAGESIZE);
1781 
1782  qfile_add_tuple_to_list_id (list_id_p, page_p, tuple_length, tuple_length);
1783 
1784  qfile_set_dirty_page (thread_p, cur_page_p, DONT_FREE, list_id_p->tfile_vfid);
1785  return NO_ERROR;
1786 }
1787 
1788 /*
1789  * qfile_fast_intint_tuple_to_list () - generate a two integer value tuple into a listfile
1790  * return: int (NO_ERROR or ER_FAILED)
1791  * list_id(in/out): List File Identifier
1792  * v1(in): first int value
1793  * v2(in): second int value
1794  *
1795  * NOTE: This function is meant to skip usual validation od DB_VALUES and
1796  * disk size computation in order to generate the tuple as fast as possible.
1797  * Also, it must write tuples identical to tuples generated by
1798  * qfile_generate_tuple_into_list via the built tuple descriptor. Generated
1799  * tuples must be readable and scanable via usual qfile routines.
1800  */
1801 int
1802 qfile_fast_intint_tuple_to_list (THREAD_ENTRY * thread_p, QFILE_LIST_ID * list_id_p, int v1, int v2)
1803 {
1804  PAGE_PTR cur_page_p;
1805  int tuple_length, tuple_value_length, tuple_value_size;
1806  char *page_p, *tuple_p;
1807 
1808  if (list_id_p == NULL)
1809  {
1810  return ER_FAILED;
1811  }
1812 
1813  QFILE_CHECK_LIST_FILE_IS_CLOSED (list_id_p);
1814 
1815  /* compute sizes */
1816  tuple_value_size = DB_ALIGN (tp_Integer.disksize, MAX_ALIGNMENT);
1817  tuple_value_length = QFILE_TUPLE_VALUE_HEADER_SIZE + tuple_value_size;
1818  tuple_length = QFILE_TUPLE_LENGTH_SIZE + tuple_value_length * 2;
1819 
1820  /* fetch page or alloc if necessary */
1821  cur_page_p = list_id_p->last_pgptr;
1822  if (qfile_allocate_new_page_if_need (thread_p, list_id_p, &cur_page_p, tuple_length, false) != NO_ERROR)
1823  {
1824  return ER_FAILED;
1825  }
1826  page_p = (char *) cur_page_p + list_id_p->last_offset;
1827  tuple_p = page_p + QFILE_TUPLE_LENGTH_SIZE;
1828 
1829  /* write the two not-null integers */
1830  QFILE_PUT_TUPLE_LENGTH (page_p, tuple_length);
1831 
1833  QFILE_PUT_TUPLE_VALUE_LENGTH (tuple_p, tuple_value_size);
1834  OR_PUT_INT (tuple_p + QFILE_TUPLE_VALUE_HEADER_SIZE, v1);
1835  tuple_p += tuple_value_length;
1836 
1838  QFILE_PUT_TUPLE_VALUE_LENGTH (tuple_p, tuple_value_size);
1839  OR_PUT_INT (tuple_p + QFILE_TUPLE_VALUE_HEADER_SIZE, v2);
1840 
1841  /* list_id maintainance stuff */
1842  qfile_add_tuple_to_list_id (list_id_p, page_p, tuple_length, tuple_length);
1843 
1844  qfile_set_dirty_page (thread_p, cur_page_p, DONT_FREE, list_id_p->tfile_vfid);
1845  return NO_ERROR;
1846 }
1847 
1848 /*
1849  * qfile_fast_intval_tuple_to_list () - generate a two value tuple into a file
1850  * return: int (NO_ERROR, error code or positive overflow tuple size)
1851  * list_id(in/out): List File Identifier
1852  * v1(in): integer value
1853  * v2(in): generic value
1854  *
1855  * NOTE: This function is meant to partially skip usual validation of DB_VALUES
1856  * and disk size computation in order to generate the tuple as fast as
1857  * possible. Also, it must write tuples identical to tuples generated by
1858  * qfile_generate_tuple_into_list via the built tuple descriptor. Generated
1859  * tuples must be readable and scanable via usual qfile routines.
1860  */
1861 int
1863 {
1864  PAGE_PTR cur_page_p;
1865  int tuple_length, tuple_int_value_size, tuple_int_value_length;
1866  int tuple_value_size, tuple_value_length;
1867  char *page_p, *tuple_p;
1868 
1869  if (list_id_p == NULL)
1870  {
1871  return ER_FAILED;
1872  }
1873 
1874  QFILE_CHECK_LIST_FILE_IS_CLOSED (list_id_p);
1875 
1876  /* compute sizes */
1877  tuple_int_value_size = DB_ALIGN (tp_Integer.disksize, MAX_ALIGNMENT);
1878  tuple_int_value_length = QFILE_TUPLE_VALUE_HEADER_SIZE + tuple_int_value_size;
1879  tuple_value_size = DB_ALIGN (pr_data_writeval_disk_size (v2), MAX_ALIGNMENT);
1880  tuple_value_length = QFILE_TUPLE_VALUE_HEADER_SIZE + tuple_value_size;
1881  tuple_length = QFILE_TUPLE_LENGTH_SIZE + tuple_int_value_length + tuple_value_length;
1882 
1883  /* register tuple size and see if we can write it or not */
1884  list_id_p->tpl_descr.tpl_size = tuple_length;
1885  if (tuple_length > QFILE_MAX_TUPLE_SIZE_IN_PAGE)
1886  {
1887  /* can't write it here */
1888  return tuple_length;
1889  }
1890 
1891  /* fetch page or alloc if necessary */
1892  cur_page_p = list_id_p->last_pgptr;
1893  if (qfile_allocate_new_page_if_need (thread_p, list_id_p, &cur_page_p, tuple_length, false) != NO_ERROR)
1894  {
1895  return ER_FAILED;
1896  }
1897  page_p = (char *) cur_page_p + list_id_p->last_offset;
1898  tuple_p = page_p + QFILE_TUPLE_LENGTH_SIZE;
1899 
1900  /* write the two not-null integers */
1901  QFILE_PUT_TUPLE_LENGTH (page_p, tuple_length);
1902 
1904  QFILE_PUT_TUPLE_VALUE_LENGTH (tuple_p, tuple_int_value_size);
1905  OR_PUT_INT (tuple_p + QFILE_TUPLE_VALUE_HEADER_SIZE, v1);
1906  tuple_p += tuple_int_value_length;
1907 
1908  if (DB_IS_NULL (v2))
1909  {
1911  QFILE_PUT_TUPLE_VALUE_LENGTH (tuple_p, 0);
1912  }
1913  else
1914  {
1915  DB_TYPE dbval_type = DB_VALUE_DOMAIN_TYPE (v2);
1916  PR_TYPE *pr_type = pr_type_from_id (dbval_type);
1917  OR_BUF buf;
1918 
1920  QFILE_PUT_TUPLE_VALUE_LENGTH (tuple_p, tuple_value_size);
1921 
1922  OR_BUF_INIT (buf, tuple_p + QFILE_TUPLE_VALUE_HEADER_SIZE, tuple_value_size);
1923  if (pr_type == NULL || pr_type->data_writeval (&buf, v2) != NO_ERROR)
1924  {
1925  return ER_FAILED;
1926  }
1927  }
1928 
1929  /* list_id maintainance stuff */
1930  qfile_add_tuple_to_list_id (list_id_p, page_p, tuple_length, tuple_length);
1931 
1932  qfile_set_dirty_page (thread_p, cur_page_p, DONT_FREE, list_id_p->tfile_vfid);
1933  return NO_ERROR;
1934 }
1935 
1936 /*
1937  * qfile_fast_val_tuple_to_list () - generate a one value tuple into a file
1938  * return: int (NO_ERROR, error code or positive overflow tuple size)
1939  * list_id(in/out): List File Identifier
1940  * val(in): integer value
1941  *
1942  * NOTE: This function is meant to partially skip usual validation of DB_VALUES
1943  * and disk size computation in order to generate the tuple as fast as
1944  * possible. Also, it must write tuples identical to tuples generated by
1945  * qfile_generate_tuple_into_list via the built tuple descriptor. Generated
1946  * tuples must be readable and scanable via usual qfile routines.
1947  */
1948 int
1950 {
1951  PAGE_PTR cur_page_p;
1952  int tuple_length;
1953  int tuple_value_size, tuple_value_length;
1954  char *page_p, *tuple_p;
1955 
1956  if (list_id_p == NULL)
1957  {
1958  return ER_FAILED;
1959  }
1960 
1961  QFILE_CHECK_LIST_FILE_IS_CLOSED (list_id_p);
1962 
1963  tuple_value_size = DB_ALIGN (pr_data_writeval_disk_size (val), MAX_ALIGNMENT);
1964  tuple_value_length = QFILE_TUPLE_VALUE_HEADER_SIZE + tuple_value_size;
1965  tuple_length = QFILE_TUPLE_LENGTH_SIZE + tuple_value_length;
1966 
1967  /* register tuple size and see if we can write it or not */
1968  list_id_p->tpl_descr.tpl_size = tuple_length;
1969  if (tuple_length > QFILE_MAX_TUPLE_SIZE_IN_PAGE)
1970  {
1971  /* can't write it here */
1972  return tuple_length;
1973  }
1974 
1975  /* fetch page or alloc if necessary */
1976  cur_page_p = list_id_p->last_pgptr;
1977  if (qfile_allocate_new_page_if_need (thread_p, list_id_p, &cur_page_p, tuple_length, false) != NO_ERROR)
1978  {
1979  return ER_FAILED;
1980  }
1981  page_p = (char *) cur_page_p + list_id_p->last_offset;
1982  tuple_p = page_p + QFILE_TUPLE_LENGTH_SIZE;
1983 
1984  /* write the two not-null integers */
1985  QFILE_PUT_TUPLE_LENGTH (page_p, tuple_length);
1986 
1987  if (DB_IS_NULL (val))
1988  {
1990  QFILE_PUT_TUPLE_VALUE_LENGTH (tuple_p, 0);
1991  }
1992  else
1993  {
1994  DB_TYPE dbval_type = DB_VALUE_DOMAIN_TYPE (val);
1995  PR_TYPE *pr_type = pr_type_from_id (dbval_type);
1996  OR_BUF buf;
1997 
1999  QFILE_PUT_TUPLE_VALUE_LENGTH (tuple_p, tuple_value_size);
2000 
2001  OR_BUF_INIT (buf, tuple_p + QFILE_TUPLE_VALUE_HEADER_SIZE, tuple_value_size);
2002  if (pr_type == NULL || pr_type->data_writeval (&buf, val) != NO_ERROR)
2003  {
2004  return ER_FAILED;
2005  }
2006  }
2007 
2008  /* list_id maintainance stuff */
2009  qfile_add_tuple_to_list_id (list_id_p, page_p, tuple_length, tuple_length);
2010 
2011  qfile_set_dirty_page (thread_p, cur_page_p, DONT_FREE, list_id_p->tfile_vfid);
2012  return NO_ERROR;
2013 }
2014 
2015 
2016 /*
2017  * qfile_add_overflow_tuple_to_list () -
2018  * return: int (NO_ERROR or ER_FAILED)
2019  * list_id(in/out): List File Identifier
2020  * ovfl_tpl_pg(in): First page of the overflow tuple to be added
2021  * input_list_id(in):
2022  *
2023  * Note: The indicated overflow tuple is added to the end of the list
2024  * file. The given page contains the initial portion of the
2025  * tuple and the rest of the tuple is formed from following
2026  * overflow pages.
2027  *
2028  * Note: This routine is a specific routine of qfile_add_tuple_to_list used by list file
2029  * sorting mechanism.
2030  */
2031 int
2032 qfile_add_overflow_tuple_to_list (THREAD_ENTRY * thread_p, QFILE_LIST_ID * list_id_p, PAGE_PTR ovf_tuple_page_p,
2033  QFILE_LIST_ID * input_list_id_p)
2034 {
2035  PAGE_PTR cur_page_p, new_page_p = NULL, prev_page_p, ovf_page_p;
2036  int tuple_length;
2037  char *page_p;
2038  int offset, tuple_page_size;
2039  QFILE_TUPLE tuple;
2040  VPID ovf_vpid;
2041 
2042  QFILE_CHECK_LIST_FILE_IS_CLOSED (list_id_p);
2043 
2044  tuple = (char *) ovf_tuple_page_p + QFILE_PAGE_HEADER_SIZE;
2045  cur_page_p = list_id_p->last_pgptr;
2046  tuple_length = QFILE_GET_TUPLE_LENGTH (tuple);
2047 
2048  if (qfile_allocate_new_page_if_need (thread_p, list_id_p, &cur_page_p, tuple_length, true) != NO_ERROR)
2049  {
2050  return ER_FAILED;
2051  }
2052 
2053  page_p = (char *) cur_page_p + list_id_p->last_offset;
2054  tuple_page_size = MIN (tuple_length, qfile_Max_tuple_page_size);
2055  memcpy (page_p, tuple, tuple_page_size);
2056 
2057  qfile_add_tuple_to_list_id (list_id_p, page_p, tuple_length, tuple_page_size);
2058 
2059  prev_page_p = cur_page_p;
2060  QFILE_GET_OVERFLOW_VPID (&ovf_vpid, ovf_tuple_page_p);
2061 
2062  for (offset = tuple_page_size; offset < tuple_length; offset += tuple_page_size)
2063  {
2064  ovf_page_p = qmgr_get_old_page (thread_p, &ovf_vpid, input_list_id_p->tfile_vfid);
2065  if (ovf_page_p == NULL)
2066  {
2067  if (new_page_p)
2068  {
2069  qfile_set_dirty_page (thread_p, new_page_p, FREE, list_id_p->tfile_vfid);
2070  }
2071  return ER_FAILED;
2072  }
2073 
2074  QFILE_GET_OVERFLOW_VPID (&ovf_vpid, ovf_page_p);
2075 
2076  new_page_p =
2077  qfile_allocate_new_ovf_page (thread_p, list_id_p, cur_page_p, prev_page_p, tuple_length, offset,
2078  &tuple_page_size);
2079  if (new_page_p == NULL)
2080  {
2081  if (prev_page_p != cur_page_p)
2082  {
2083  qfile_set_dirty_page (thread_p, prev_page_p, FREE, list_id_p->tfile_vfid);
2084  }
2085  qmgr_free_old_page_and_init (thread_p, ovf_page_p, input_list_id_p->tfile_vfid);
2086  return ER_FAILED;
2087  }
2088 
2089  memcpy ((char *) new_page_p + QFILE_PAGE_HEADER_SIZE, (char *) ovf_page_p + QFILE_PAGE_HEADER_SIZE,
2090  tuple_page_size);
2091 
2092  qmgr_free_old_page_and_init (thread_p, ovf_page_p, input_list_id_p->tfile_vfid);
2093  prev_page_p = new_page_p;
2094  }
2095 
2096  if (prev_page_p != cur_page_p)
2097  {
2098  QFILE_PUT_OVERFLOW_VPID_NULL (prev_page_p);
2099  qfile_set_dirty_page (thread_p, prev_page_p, FREE, list_id_p->tfile_vfid);
2100  }
2101 
2102  qfile_set_dirty_page (thread_p, cur_page_p, DONT_FREE, list_id_p->tfile_vfid);
2103  return NO_ERROR;
2104 }
2105 
2106 /*
2107  * qfile_get_first_page () -
2108  * return: int (NO_ERROR or ER_FAILED)
2109  * list_id(in): List File Identifier
2110  */
2111 int
2113 {
2114  PAGE_PTR new_page_p;
2115  VPID new_vpid;
2116 
2117  if (list_id_p->tfile_vfid == NULL)
2118  {
2119  list_id_p->tfile_vfid = qmgr_create_new_temp_file (thread_p, list_id_p->query_id, TEMP_FILE_MEMBUF_NORMAL);
2120  if (list_id_p->tfile_vfid == NULL)
2121  {
2122  return ER_FAILED;
2123  }
2124  }
2125 
2126  new_page_p = qmgr_get_new_page (thread_p, &new_vpid, list_id_p->tfile_vfid);
2127  if (new_page_p == NULL)
2128  {
2129  return ER_FAILED;
2130  }
2131 
2132  list_id_p->page_cnt++;
2133 
2134  QFILE_PUT_TUPLE_COUNT (new_page_p, 0);
2135  QFILE_PUT_PREV_VPID (new_page_p, &list_id_p->last_vpid);
2136  LS_PUT_NEXT_VPID (new_page_p);
2137 
2138  QFILE_COPY_VPID (&list_id_p->first_vpid, &new_vpid);
2139  QFILE_COPY_VPID (&list_id_p->last_vpid, &new_vpid);
2140 
2141  list_id_p->last_pgptr = new_page_p;
2142  list_id_p->last_offset = QFILE_PAGE_HEADER_SIZE;
2143  QFILE_PUT_OVERFLOW_VPID_NULL (new_page_p);
2144 
2145  list_id_p->lasttpl_len = 0;
2146  list_id_p->last_offset += ((0 + list_id_p->last_offset > DB_PAGESIZE) ? DB_PAGESIZE : 0);
2147 
2148  qfile_set_dirty_page (thread_p, new_page_p, DONT_FREE, list_id_p->tfile_vfid);
2149  return NO_ERROR;
2150 }
2151 
2152 /*
2153  * qfile_destroy_list () -
2154  * return: int
2155  * list_id(in): List File Identifier
2156  *
2157  * Note: All the pages of the list file are deallocated from the query
2158  * file, the memory areas for the list file identifier are freed
2159  * and the number of pages deallocated is returned. This routine
2160  * is basically called for temporarily created list files.
2161  */
2162 void
2164 {
2165  if (list_id_p)
2166  {
2167  if (list_id_p->tfile_vfid)
2168  {
2169  qmgr_free_list_temp_file (thread_p, list_id_p->query_id, list_id_p->tfile_vfid);
2170  }
2171  else
2172  {
2173  /* because qmgr_free_list_temp_file() destroy only FILE_TEMP file */
2174  if (!VFID_ISNULL (&list_id_p->temp_vfid))
2175  {
2176  file_temp_retire (thread_p, &list_id_p->temp_vfid);
2177  }
2178  }
2179 
2180  qfile_clear_list_id (list_id_p);
2181  }
2182 }
2183 
2184 /*
2185  * xqfile_get_list_file_page () -
2186  * return: NO_ERROR or ER_ code
2187  * query_id(in):
2188  * volid(in): List file page volume identifier
2189  * pageid(in): List file page identifier
2190  * page_bufp(out): Buffer to contain list file page content
2191  * page_sizep(out):
2192  *
2193  * Note: This routine is basically called by the C/S communication
2194  * routines to fetch and copy the indicated list file page to
2195  * the buffer area. The area pointed by the buffer must have
2196  * been allocated by the caller and should be big enough to
2197  * store a list file page.
2198  */
2199 int
2200 xqfile_get_list_file_page (THREAD_ENTRY * thread_p, QUERY_ID query_id, VOLID vol_id, PAGEID page_id, char *page_buf_p,
2201  int *page_size_p)
2202 {
2203  QMGR_QUERY_ENTRY *query_entry_p = NULL;
2204  QFILE_LIST_ID *list_id_p;
2205  QMGR_TEMP_FILE *tfile_vfid_p;
2206  VPID vpid, next_vpid;
2207  PAGE_PTR page_p;
2208  int one_page_size = DB_PAGESIZE;
2209  int tran_index;
2210 
2211  assert (NULL_PAGEID < page_id);
2212  VPID_SET (&vpid, vol_id, page_id);
2213 
2214  *page_size_p = 0;
2215 
2216  if (query_id == NULL_QUERY_ID)
2217  {
2218  assert (false);
2219  return ER_QPROC_UNKNOWN_QUERYID;
2220  }
2221  else if (query_id >= SHRT_MAX)
2222  {
2223  tfile_vfid_p = (QMGR_TEMP_FILE *) query_id;
2224  goto get_page;
2225  }
2226  else
2227  {
2228  tran_index = LOG_FIND_THREAD_TRAN_INDEX (thread_p);
2229 
2230  query_entry_p = qmgr_get_query_entry (thread_p, query_id, tran_index);
2231  if (query_entry_p == NULL)
2232  {
2233  return ER_QPROC_UNKNOWN_QUERYID;
2234  }
2235 
2236  assert (query_entry_p->errid == NO_ERROR);
2237  assert (query_entry_p->query_status == QUERY_COMPLETED);
2238 
2239  if (query_entry_p->list_id == NULL)
2240  {
2241  assert (query_entry_p->list_id != NULL);
2242  *page_size_p = 0;
2243  return NO_ERROR;
2244  }
2245 
2246  assert (NULL_PAGEID < query_entry_p->list_id->first_vpid.pageid);
2247 
2248  /* unexpected no result */
2249  if (vol_id == NULL_VOLID && page_id == NULL_PAGEID)
2250  {
2251  assert (vol_id != NULL_VOLID || page_id != NULL_PAGEID);
2252  *page_size_p = 0;
2253  return NO_ERROR;
2254  }
2255 
2256  list_id_p = query_entry_p->list_id;
2257  tfile_vfid_p = list_id_p->tfile_vfid;
2258  }
2259 
2260 get_page:
2261  /* append pages until a network page is full */
2262  while ((*page_size_p + DB_PAGESIZE) <= IO_MAX_PAGE_SIZE)
2263  {
2264  page_p = qmgr_get_old_page (thread_p, &vpid, tfile_vfid_p);
2265  if (page_p == NULL)
2266  {
2267  assert (er_errid () != NO_ERROR);
2268  return er_errid ();
2269  }
2270 
2271  /* find next page to append */
2272  QFILE_GET_OVERFLOW_VPID (&next_vpid, page_p);
2273  if (next_vpid.pageid == NULL_PAGEID)
2274  {
2275  QFILE_GET_NEXT_VPID (&next_vpid, page_p);
2276  }
2277 
2278  assert (next_vpid.pageid != NULL_PAGEID_IN_PROGRESS);
2279 
2281  || QFILE_GET_OVERFLOW_PAGE_ID (page_p) != NULL_PAGEID)
2282  {
2283  one_page_size = DB_PAGESIZE;
2284  }
2285  else
2286  {
2287  one_page_size = (QFILE_GET_LAST_TUPLE_OFFSET (page_p)
2288  + QFILE_GET_TUPLE_LENGTH (page_p + QFILE_GET_LAST_TUPLE_OFFSET (page_p)));
2289  if (one_page_size < QFILE_PAGE_HEADER_SIZE)
2290  {
2291  one_page_size = QFILE_PAGE_HEADER_SIZE;
2292  }
2293 
2294  if (one_page_size > DB_PAGESIZE)
2295  {
2296  one_page_size = DB_PAGESIZE;
2297  }
2298  }
2299 
2300  memcpy ((page_buf_p + *page_size_p), page_p, one_page_size);
2301  qmgr_free_old_page_and_init (thread_p, page_p, tfile_vfid_p);
2302 
2303  *page_size_p += DB_PAGESIZE;
2304 
2305  /* next page to append does not exists, stop appending */
2306  if (next_vpid.pageid == NULL_PAGEID)
2307  {
2308  break;
2309  }
2310 
2311  vpid = next_vpid;
2312  }
2313 
2314  *page_size_p += one_page_size - DB_PAGESIZE;
2315 
2316  return NO_ERROR;
2317 }
2318 
2319 /*
2320  * qfile_add_item_to_list () -
2321  * return: int (NO_ERROR or ER_FAILED)
2322  * item(in): Value in disk representation form
2323  * item_size(in): Size of the value
2324  * list_id(in): List File Identifier
2325  *
2326  * Note: The given item is added to the end of the given list file.
2327  * The list file must be of a single column.
2328  */
2329 int
2330 qfile_add_item_to_list (THREAD_ENTRY * thread_p, char *item_p, int item_size, QFILE_LIST_ID * list_id_p)
2331 {
2332  QFILE_TUPLE tuple;
2333  int tuple_length, align;
2334  char *tuple_p;
2335 
2336  tuple_length = QFILE_TUPLE_LENGTH_SIZE + QFILE_TUPLE_VALUE_HEADER_SIZE + item_size;
2337 
2338  align = DB_ALIGN (item_size, MAX_ALIGNMENT) - item_size;
2339  tuple_length += align;
2340 
2341  if (tuple_length < QFILE_MAX_TUPLE_SIZE_IN_PAGE)
2342  {
2343  /* SMALL_TUPLE */
2344 
2345  list_id_p->tpl_descr.item = item_p;
2346  list_id_p->tpl_descr.item_size = item_size;
2347  list_id_p->tpl_descr.tpl_size = tuple_length;
2348 
2349  if (qfile_generate_tuple_into_list (thread_p, list_id_p, T_SINGLE_BOUND_ITEM) != NO_ERROR)
2350  {
2351  return ER_FAILED;
2352  }
2353  }
2354  else
2355  {
2356  /* BIG_TUPLE */
2357 
2358  tuple = (QFILE_TUPLE) malloc (tuple_length);
2359  if (tuple == NULL)
2360  {
2361  return ER_FAILED;
2362  }
2363 
2364  QFILE_PUT_TUPLE_LENGTH (tuple, tuple_length);
2365  tuple_p = (char *) tuple + QFILE_TUPLE_LENGTH_SIZE;
2367  QFILE_PUT_TUPLE_VALUE_LENGTH (tuple_p, item_size + align);
2368  tuple_p += QFILE_TUPLE_VALUE_HEADER_SIZE;
2369  memcpy (tuple_p, item_p, item_size);
2370 #if !defined(NDEBUG)
2371  /* suppress valgrind UMW error */
2372  memset (tuple_p + item_size, 0, align);
2373 #endif
2374 
2375  if (qfile_add_tuple_to_list (thread_p, list_id_p, tuple) != NO_ERROR)
2376  {
2377  free_and_init (tuple);
2378  return ER_FAILED;
2379  }
2380 
2381  free_and_init (tuple);
2382  }
2383 
2384  return NO_ERROR;
2385 }
2386 
2387 /*
2388  * qfile_compare_tuple_helper () -
2389  * return:
2390  * lhs(in):
2391  * rhs(in):
2392  * types(in):
2393  */
2394 static int
2396 {
2397  char *lhs_tuple_p, *rhs_tuple_p;
2398  int i, result;
2399 
2400  lhs_tuple_p = (char *) lhs + QFILE_TUPLE_LENGTH_SIZE;
2401  rhs_tuple_p = (char *) rhs + QFILE_TUPLE_LENGTH_SIZE;
2402 
2403  for (i = 0; i < types->type_cnt; i++)
2404  {
2405  result = qfile_compare_tuple_values (lhs_tuple_p, rhs_tuple_p, types->domp[i], cmp);
2406  if (result != NO_ERROR)
2407  {
2408  return result;
2409  }
2410 
2411  if (*cmp != 0)
2412  {
2413  return NO_ERROR;
2414  }
2415 
2416  lhs_tuple_p += QFILE_TUPLE_VALUE_HEADER_SIZE + QFILE_GET_TUPLE_VALUE_LENGTH (lhs_tuple_p);
2417  rhs_tuple_p += QFILE_TUPLE_VALUE_HEADER_SIZE + QFILE_GET_TUPLE_VALUE_LENGTH (rhs_tuple_p);
2418  }
2419 
2420  *cmp = 0;
2421  return NO_ERROR;
2422 }
2423 
2424 /*
2425  * qfile_advance_single () -
2426  * return:
2427  * next_scan(in):
2428  * next_tpl(in):
2429  * last_scan(in):
2430  * last_tpl(in):
2431  * types(in):
2432  */
2433 static SCAN_CODE
2434 qfile_advance_single (THREAD_ENTRY * thread_p, QFILE_LIST_SCAN_ID * next_scan_p, QFILE_TUPLE_RECORD * next_tuple_p,
2435  QFILE_LIST_SCAN_ID * last_scan_p, QFILE_TUPLE_RECORD * last_tuple_p,
2437 {
2438  if (next_scan_p == NULL)
2439  {
2440  return S_END;
2441  }
2442 
2443  return qfile_scan_list_next (thread_p, next_scan_p, next_tuple_p, PEEK);
2444 }
2445 
2446 /*
2447  * qfile_advance_group () -
2448  * return:
2449  * next_scan(in/out):
2450  * next_tpl(out):
2451  * last_scan(in/out):
2452  * last_tpl(out):
2453  * types(in):
2454  */
2455 static SCAN_CODE
2456 qfile_advance_group (THREAD_ENTRY * thread_p, QFILE_LIST_SCAN_ID * next_scan_p, QFILE_TUPLE_RECORD * next_tuple_p,
2457  QFILE_LIST_SCAN_ID * last_scan_p, QFILE_TUPLE_RECORD * last_tuple_p,
2459 {
2460  SCAN_CODE status;
2461  int error_code, cmp;
2462 
2463  if (next_scan_p == NULL)
2464  {
2465  return S_END;
2466  }
2467 
2468  status = S_SUCCESS;
2469 
2470  switch (last_scan_p->position)
2471  {
2472  case S_BEFORE:
2473  status = qfile_scan_list_next (thread_p, next_scan_p, next_tuple_p, PEEK);
2474  break;
2475 
2476  case S_ON:
2477  do
2478  {
2479  status = qfile_scan_list_next (thread_p, next_scan_p, next_tuple_p, PEEK);
2480  if (status != S_SUCCESS)
2481  {
2482  break;
2483  }
2484 
2485  error_code = qfile_compare_tuple_helper (last_tuple_p->tpl, next_tuple_p->tpl, types, &cmp);
2486  }
2487  while (error_code == NO_ERROR && cmp == 0);
2488  break;
2489 
2490  case S_AFTER:
2491  default:
2492  status = S_END;
2493  break;
2494  }
2495 
2496  if (status == S_SUCCESS)
2497  {
2498  QFILE_TUPLE_POSITION next_pos;
2499 
2500  qfile_save_current_scan_tuple_position (next_scan_p, &next_pos);
2501  status = qfile_jump_scan_tuple_position (thread_p, last_scan_p, &next_pos, last_tuple_p, PEEK);
2502  }
2503 
2504  return status;
2505 }
2506 
2507 /*
2508  * qfile_add_one_tuple () -
2509  * return:
2510  * dst(in/out):
2511  * lhs(in):
2512  * rhs(in):
2513  */
2514 static int
2516 {
2517  return qfile_add_tuple_to_list (thread_p, dest_list_p, lhs);
2518 }
2519 
2520 /*
2521  * qfile_add_two_tuple () -
2522  * return:
2523  * dst(in):
2524  * lhs(in):
2525  * rhs(in):
2526  */
2527 static int
2529 {
2530  int error;
2531 
2532  error = qfile_add_tuple_to_list (thread_p, dest_list_p, lhs);
2533  if (error == NO_ERROR)
2534  {
2535  error = qfile_add_tuple_to_list (thread_p, dest_list_p, rhs);
2536  }
2537 
2538  return error;
2539 }
2540 
2541 static int
2542 qfile_advance (THREAD_ENTRY * thread_p, ADVANCE_FUCTION advance_func, QFILE_TUPLE_RECORD * side_p,
2543  QFILE_TUPLE_RECORD * last_side_p, QFILE_LIST_SCAN_ID * scan_p, QFILE_LIST_SCAN_ID * last_scan_p,
2544  QFILE_LIST_ID * side_file_p, int *have_side_p)
2545 {
2546  SCAN_CODE scan_result;
2547 
2548  scan_result = (*advance_func) (thread_p, scan_p, side_p, last_scan_p, last_side_p, &side_file_p->type_list);
2549  switch (scan_result)
2550  {
2551  case S_SUCCESS:
2552  *have_side_p = 1;
2553  break;
2554  case S_END:
2555  *have_side_p = 0;
2556  break;
2557  default:
2558  return ER_FAILED;
2559  }
2560 
2561  return NO_ERROR;
2562 }
2563 
2564 /*
2565  * qfile_combine_two_list () -
2566  * return: QFILE_LIST_ID *, or NULL
2567  * lhs_file(in): pointer to a QFILE_LIST_ID for one of the input files
2568  * rhs_file(in): pointer to a QFILE_LIST_ID for the other input file, or NULL
2569  * flag(in): {QFILE_FLAG_UNION, QFILE_FLAG_DIFFERENCE, QFILE_FLAG_INTERSECT,
2570  * QFILE_FLAG_ALL, QFILE_FLAG_DISTINCT}
2571  * the kind of combination desired (union, diff, or intersect) and
2572  * whether to do 'all' or 'distinct'
2573  *
2574  */
2575 QFILE_LIST_ID *
2576 qfile_combine_two_list (THREAD_ENTRY * thread_p, QFILE_LIST_ID * lhs_file_p, QFILE_LIST_ID * rhs_file_p, int flag)
2577 {
2578  QFILE_LIST_ID *dest_list_id_p = NULL;
2579  QFILE_LIST_SCAN_ID lhs_scan_id, rhs_scan_id, last_lhs_scan_id, last_rhs_scan_id;
2580  QFILE_LIST_SCAN_ID *lhs_scan_p = NULL, *rhs_scan_p = NULL;
2581  QFILE_LIST_SCAN_ID *last_lhs_scan_p = NULL, *last_rhs_scan_p = NULL;
2582  int have_lhs = 0, have_rhs = 0, cmp;
2583  QFILE_TUPLE_RECORD lhs = { NULL, 0 };
2584  QFILE_TUPLE_RECORD rhs = { NULL, 0 };
2585  QFILE_TUPLE_RECORD last_lhs = { NULL, 0 };
2586  QFILE_TUPLE_RECORD last_rhs = { NULL, 0 };
2587  QUERY_OPTIONS distinct_or_all;
2588 
2589  ADVANCE_FUCTION advance_func;
2590  int (*act_left_func) (THREAD_ENTRY * thread_p, QFILE_LIST_ID *, QFILE_TUPLE);
2591  int (*act_right_func) (THREAD_ENTRY * thread_p, QFILE_LIST_ID *, QFILE_TUPLE);
2592  int (*act_both_func) (THREAD_ENTRY * thread_p, QFILE_LIST_ID *, QFILE_TUPLE, QFILE_TUPLE);
2593 
2594  advance_func = NULL;
2595  act_left_func = NULL;
2596  act_right_func = NULL;
2597  act_both_func = NULL;
2598 
2600  {
2601  return qfile_union_list (thread_p, lhs_file_p, rhs_file_p, flag);
2602  }
2603 
2605  {
2606  distinct_or_all = Q_DISTINCT;
2607  }
2608  else
2609  {
2610  distinct_or_all = Q_ALL;
2611  }
2612 
2613  if (lhs_file_p->tuple_cnt > 1)
2614  {
2615  lhs_file_p = qfile_sort_list (thread_p, lhs_file_p, NULL, distinct_or_all, true);
2616  if (lhs_file_p == NULL)
2617  {
2618  goto error;
2619  }
2620  }
2621 
2622  if (qfile_open_list_scan (lhs_file_p, &lhs_scan_id) != NO_ERROR)
2623  {
2624  goto error;
2625  }
2626  lhs_scan_p = &lhs_scan_id;
2627 
2628  if (rhs_file_p)
2629  {
2630  if (rhs_file_p->tuple_cnt > 1)
2631  {
2632  rhs_file_p = qfile_sort_list (thread_p, rhs_file_p, NULL, distinct_or_all, true);
2633  if (rhs_file_p == NULL)
2634  {
2635  goto error;
2636  }
2637  }
2638 
2639  if (qfile_open_list_scan (rhs_file_p, &rhs_scan_id) != NO_ERROR)
2640  {
2641  goto error;
2642  }
2643 
2644  rhs_scan_p = &rhs_scan_id;
2645  }
2646 
2647  dest_list_id_p = qfile_open_list (thread_p, &lhs_file_p->type_list, NULL, lhs_file_p->query_id, flag);
2648  if (dest_list_id_p == NULL)
2649  {
2650  goto error;
2651  }
2652 
2653  if (rhs_file_p && qfile_unify_types (dest_list_id_p, rhs_file_p) != NO_ERROR)
2654  {
2655  goto error;
2656  }
2657 
2659  {
2660  act_left_func = NULL;
2661  act_right_func = NULL;
2662  act_both_func = qfile_add_one_tuple;
2663  }
2664  else if (QFILE_IS_FLAG_SET (flag, QFILE_FLAG_DIFFERENCE))
2665  {
2666  act_left_func = qfile_add_tuple_to_list;
2667  act_right_func = NULL;
2668  act_both_func = NULL;
2669  }
2670  else
2671  {
2672  /* QFILE_FLAG_UNION */
2673  act_left_func = qfile_add_tuple_to_list;
2674  act_right_func = qfile_add_tuple_to_list;
2675  act_both_func = qfile_add_one_tuple;
2676  }
2677 
2679  {
2680  advance_func = qfile_advance_group;
2681  if (qfile_open_list_scan (lhs_file_p, &last_lhs_scan_id) != NO_ERROR)
2682  {
2683  goto error;
2684  }
2685 
2686  last_lhs_scan_p = &last_lhs_scan_id;
2687  if (rhs_file_p)
2688  {
2689  if (qfile_open_list_scan (rhs_file_p, &last_rhs_scan_id) != NO_ERROR)
2690  {
2691  goto error;
2692  }
2693  last_rhs_scan_p = &last_rhs_scan_id;
2694  }
2695  }
2696  else
2697  {
2698  /* QFILE_FLAG_ALL */
2699  advance_func = qfile_advance_single;
2700  if (QFILE_IS_FLAG_SET (flag, QFILE_FLAG_UNION))
2701  {
2702  act_both_func = qfile_add_two_tuple;
2703  }
2704  }
2705 
2706  while (1)
2707  {
2708  if (!have_lhs)
2709  {
2710  if (qfile_advance (thread_p, advance_func, &lhs, &last_lhs, lhs_scan_p, last_lhs_scan_p, lhs_file_p,
2711  &have_lhs) != NO_ERROR)
2712  {
2713  goto error;
2714  }
2715  }
2716 
2717  if (!have_rhs)
2718  {
2719  if (qfile_advance (thread_p, advance_func, &rhs, &last_rhs, rhs_scan_p, last_rhs_scan_p, rhs_file_p,
2720  &have_rhs) != NO_ERROR)
2721  {
2722  goto error;
2723  }
2724  }
2725 
2726  if (!have_lhs || !have_rhs)
2727  {
2728  break;
2729  }
2730 
2731  if (qfile_compare_tuple_helper (lhs.tpl, rhs.tpl, &lhs_file_p->type_list, &cmp) != NO_ERROR)
2732  {
2733  goto error;
2734  }
2735 
2736  if (cmp < 0)
2737  {
2738  if (act_left_func && act_left_func (thread_p, dest_list_id_p, lhs.tpl) != NO_ERROR)
2739  {
2740  goto error;
2741  }
2742 
2743  have_lhs = 0;
2744  }
2745  else if (cmp == 0)
2746  {
2747  if (act_both_func && act_both_func (thread_p, dest_list_id_p, lhs.tpl, rhs.tpl) != NO_ERROR)
2748  {
2749  goto error;
2750  }
2751 
2752  have_lhs = 0;
2753  have_rhs = 0;
2754  }
2755  else
2756  {
2757  if (act_right_func && act_right_func (thread_p, dest_list_id_p, rhs.tpl) != NO_ERROR)
2758  {
2759  goto error;
2760  }
2761  have_rhs = 0;
2762  }
2763  }
2764 
2765  while (have_lhs)
2766  {
2767  if (act_left_func && act_left_func (thread_p, dest_list_id_p, lhs.tpl) != NO_ERROR)
2768  {
2769  goto error;
2770  }
2771 
2772  if (qfile_advance (thread_p, advance_func, &lhs, &last_lhs, lhs_scan_p, last_lhs_scan_p, lhs_file_p, &have_lhs) !=
2773  NO_ERROR)
2774  {
2775  goto error;
2776  }
2777  }
2778 
2779  while (have_rhs)
2780  {
2781  if (act_right_func && act_right_func (thread_p, dest_list_id_p, rhs.tpl) != NO_ERROR)
2782  {
2783  goto error;
2784  }
2785 
2786  if (qfile_advance (thread_p, advance_func, &rhs, &last_rhs, rhs_scan_p, last_rhs_scan_p, rhs_file_p, &have_rhs) !=
2787  NO_ERROR)
2788  {
2789  goto error;
2790  }
2791  }
2792 
2793 success:
2794  if (lhs_scan_p)
2795  {
2796  qfile_close_scan (thread_p, lhs_scan_p);
2797  }
2798  if (rhs_scan_p)
2799  {
2800  qfile_close_scan (thread_p, rhs_scan_p);
2801  }
2802  if (last_lhs_scan_p)
2803  {
2804  qfile_close_scan (thread_p, last_lhs_scan_p);
2805  }
2806  if (last_rhs_scan_p)
2807  {
2808  qfile_close_scan (thread_p, last_rhs_scan_p);
2809  }
2810  if (lhs_file_p)
2811  {
2812  qfile_close_list (thread_p, lhs_file_p);
2813  }
2814  if (rhs_file_p)
2815  {
2816  qfile_close_list (thread_p, rhs_file_p);
2817  }
2818  if (dest_list_id_p)
2819  {
2820  qfile_close_list (thread_p, dest_list_id_p);
2821  }
2822 
2823  return dest_list_id_p;
2824 
2825 error:
2826  if (dest_list_id_p)
2827  {
2828  qfile_close_list (thread_p, dest_list_id_p);
2829  QFILE_FREE_AND_INIT_LIST_ID (dest_list_id_p);
2830  }
2831  goto success;
2832 }
2833 
2834 /*
2835  * qfile_copy_tuple_descr_to_tuple () - generate a tuple into a tuple record
2836  * structure from a tuple descriptor
2837  * return: NO_ERROR or error code
2838  * thread_p(in): thread
2839  * tpl_descr(in): tuple descriptor
2840  * tpl_rec(in): tuple record
2841  *
2842  * NOTE: tpl_rec's fields will be private_alloc'd by this function and it's the
2843  * caller's resposability to properly dispose the memory
2844  */
2845 int
2847  QFILE_TUPLE_RECORD * tplrec)
2848 {
2849  char *tuple_p;
2850  int i, size;
2851 
2852  assert (tpl_descr != NULL && tplrec != NULL);
2853 
2854  /* alloc tuple record with tuple descriptor footprint */
2855  tplrec->size = tpl_descr->tpl_size;
2856  tplrec->tpl = (char *) db_private_alloc (thread_p, tplrec->size);
2857  if (tplrec->tpl == NULL)
2858  {
2859  return ER_FAILED;
2860  }
2861 
2862  /* put length */
2863  QFILE_PUT_TUPLE_LENGTH (tplrec->tpl, tplrec->size);
2864  tuple_p = tplrec->tpl + QFILE_TUPLE_LENGTH_SIZE;
2865 
2866  /* build tuple */
2867  for (i = 0; i < tpl_descr->f_cnt; i++)
2868  {
2869  if (qdata_copy_db_value_to_tuple_value (tpl_descr->f_valp[i], !(tpl_descr->clear_f_val_at_clone_decache[i]),
2870  tuple_p, &size) != NO_ERROR)
2871  {
2872  /* error has already been set */
2873  db_private_free_and_init (thread_p, tplrec->tpl);
2874  return ER_FAILED;
2875  }
2876  tuple_p += size;
2877 
2878  assert (tuple_p <= tplrec->tpl + tplrec->size);
2879  }
2880 
2881  /* all ok */
2882  return NO_ERROR;
2883 }
2884 
2885 static int
2886 qfile_copy_tuple (THREAD_ENTRY * thread_p, QFILE_LIST_ID * to_list_id_p, QFILE_LIST_ID * from_list_id_p)
2887 {
2888  QFILE_LIST_SCAN_ID scan_id;
2889  QFILE_TUPLE_RECORD tuple_record = { NULL, 0 };
2890  SCAN_CODE qp_scan;
2891 
2892  /* scan through the first list file and add the tuples to the result list file. */
2893  if (qfile_open_list_scan (from_list_id_p, &scan_id) != NO_ERROR)
2894  {
2895  return ER_FAILED;
2896  }
2897 
2898  while (true)
2899  {
2900  qp_scan = qfile_scan_list_next (thread_p, &scan_id, &tuple_record, PEEK);
2901  if (qp_scan != S_SUCCESS)
2902  {
2903  break;
2904  }
2905 
2906  if (qfile_add_tuple_to_list (thread_p, to_list_id_p, tuple_record.tpl) != NO_ERROR)
2907  {
2908  qfile_close_scan (thread_p, &scan_id);
2909  return ER_FAILED;
2910  }
2911  }
2912 
2913  qfile_close_scan (thread_p, &scan_id);
2914 
2915  if (qp_scan != S_END)
2916  {
2917  return ER_FAILED;
2918  }
2919 
2920  return NO_ERROR;
2921 }
2922 
2923 static void
2925 {
2926  qfile_close_list (thread_p, list_id);
2927  QFILE_FREE_AND_INIT_LIST_ID (list_id);
2928 }
2929 
2930 /*
2931  * qfile_union_list () -
2932  * return: IST_ID *, or NULL
2933  * list_id1(in): First list file identifier
2934  * list_id2(in): Second list file identifier
2935  * flag(in):
2936  *
2937  * Note: This routine takes the union of two list files by getting the
2938  * tuples of the both list files and generates a new list file.
2939  * The source list files are not affected.
2940  */
2941 static QFILE_LIST_ID *
2942 qfile_union_list (THREAD_ENTRY * thread_p, QFILE_LIST_ID * list_id1_p, QFILE_LIST_ID * list_id2_p, int flag)
2943 {
2944  QFILE_LIST_ID *result_list_id_p, *base, *tail;
2945 
2946  if (list_id1_p->tuple_cnt == 0)
2947  {
2948  base = list_id2_p;
2949  tail = NULL;
2950  }
2951  else if (list_id2_p->tuple_cnt == 0)
2952  {
2953  base = list_id1_p;
2954  tail = NULL;
2955  }
2956  else
2957  {
2958  base = list_id1_p;
2959  tail = list_id2_p;
2960  }
2961 
2962  result_list_id_p = qfile_clone_list_id (base, false);
2963  if (result_list_id_p == NULL)
2964  {
2965  return NULL;
2966  }
2967 
2968  if (tail != NULL)
2969  {
2970  if (qfile_reopen_list_as_append_mode (thread_p, result_list_id_p) != NO_ERROR)
2971  {
2972  goto error;
2973  }
2974 
2975  if (qfile_unify_types (result_list_id_p, tail) != NO_ERROR)
2976  {
2977  goto error;
2978  }
2979 
2980  if (qfile_copy_tuple (thread_p, result_list_id_p, tail) != NO_ERROR)
2981  {
2982  goto error;
2983  }
2984 
2985  qfile_close_list (thread_p, result_list_id_p);
2986  }
2987 
2988  /* clear base list_id to prevent double free of tfile_vfid */
2989  qfile_clear_list_id (base);
2990 
2991  return result_list_id_p;
2992 
2993 error:
2994  qfile_close_list (thread_p, result_list_id_p);
2995  qfile_free_list_id (result_list_id_p);
2996  return NULL;
2997 }
2998 
2999 /*
3000  * qfile_reallocate_tuple () - reallocates a tuple to the desired size.
3001  * If it cant, it sets an error and returns 0
3002  * return: nt 1 succes, 0 failure
3003  * tplrec(in): tuple descriptor
3004  * tpl_size(in): desired size
3005  * file(in):
3006  * line(in):
3007  *
3008  */
3009 int
3010 qfile_reallocate_tuple (QFILE_TUPLE_RECORD * tuple_record_p, int tuple_size)
3011 {
3012  QFILE_TUPLE tuple;
3013 
3014  if (tuple_record_p->size == 0)
3015  {
3016  tuple_record_p->tpl = (QFILE_TUPLE) db_private_alloc (NULL, tuple_size);
3017  }
3018  else
3019  {
3020  /*
3021  * Don't leak the original tuple if we get a malloc failure!
3022  */
3023  tuple = (QFILE_TUPLE) db_private_realloc (NULL, tuple_record_p->tpl, tuple_size);
3024  if (tuple == NULL)
3025  {
3026  db_private_free_and_init (NULL, tuple_record_p->tpl);
3027  }
3028  tuple_record_p->tpl = tuple;
3029  }
3030 
3031  if (tuple_record_p->tpl == NULL)
3032  {
3033  return ER_FAILED;
3034  }
3035 
3036  tuple_record_p->size = tuple_size;
3037 
3038  return NO_ERROR;
3039 }
3040 
3041 #if defined (CUBRID_DEBUG)
3042 /*
3043  * qfile_print_list () - Dump the content of the list file to the standard output
3044  * return: none
3045  * list_id(in): List File Identifier
3046  */
3047 void
3048 qfile_print_list (THREAD_ENTRY * thread_p, QFILE_LIST_ID * list_id_p)
3049 {
3050  QFILE_LIST_SCAN_ID scan_id;
3051  QFILE_TUPLE_RECORD tuple_record = { NULL, 0 };
3052 
3053  if (!list_id_p || list_id_p->type_list.type_cnt < 0)
3054  {
3055  fprintf (stdout, "\n <invalid tuple list> ");
3056  return;
3057  }
3058  if (list_id_p->type_list.type_cnt == 0)
3059  {
3060  fprintf (stdout, "\n <empty tuple list> ");
3061  return;
3062  }
3063 
3064  if (qfile_open_list_scan (list_id_p, &scan_id) != NO_ERROR)
3065  {
3066  return;
3067  }
3068 
3069  while (qfile_scan_list_next (thread_p, &scan_id, &tuple_record, PEEK) == S_SUCCESS)
3070  {
3071  qfile_print_tuple (&list_id_p->type_list, tuple_record.tpl);
3072  }
3073 
3074  qfile_close_scan (thread_p, &scan_id);
3075 }
3076 #endif
3077 
3078 /*
3079  * Sorting Related Routines
3080  */
3081 
3082 /* qfile_make_sort_key () -
3083  * return:
3084  * info(in):
3085  * key(in):
3086  * input_scan(in):
3087  * tplrec(in):
3088  */
3090 qfile_make_sort_key (THREAD_ENTRY * thread_p, SORTKEY_INFO * key_info_p, RECDES * key_record_p,
3091  QFILE_LIST_SCAN_ID * input_scan_p, QFILE_TUPLE_RECORD * tuple_record_p)
3092 {
3093  int i, nkeys, length;
3094  SORT_REC *sort_record_p;
3095  char *data;
3096  SCAN_CODE scan_status;
3097  char *field_data;
3098  int field_length, offset;
3099  SORT_STATUS status;
3100 
3101  scan_status = qfile_scan_list_next (thread_p, input_scan_p, tuple_record_p, PEEK);
3102  if (scan_status != S_SUCCESS)
3103  {
3104  return ((scan_status == S_END) ? SORT_NOMORE_RECS : SORT_ERROR_OCCURRED);
3105  }
3106 
3107  nkeys = key_info_p->nkeys;
3108  sort_record_p = (SORT_REC *) key_record_p->data;
3109  sort_record_p->next = NULL;
3110 
3111  if (key_info_p->use_original)
3112  {
3113  /* P_sort_key */
3114 
3115  /* get sort_key body start position, align data to 8 bytes boundary */
3116  data = &(sort_record_p->s.original.body[0]);
3117  data = PTR_ALIGN (data, MAX_ALIGNMENT);
3118 
3119  length = CAST_BUFLEN (data - key_record_p->data); /* i.e, 12 */
3120 
3121  /* STEP 1: build header(tuple_ID) */
3122  if (length <= key_record_p->area_size)
3123  {
3124  sort_record_p->s.original.pageid = input_scan_p->curr_vpid.pageid;
3125  sort_record_p->s.original.volid = input_scan_p->curr_vpid.volid;
3126  sort_record_p->s.original.offset = input_scan_p->curr_offset;
3127  }
3128 
3129  /* STEP 2: build body */
3130  for (i = 0; i < nkeys; i++)
3131  {
3132  /* Position ourselves at the next field, and find out its length */
3133  QFILE_GET_TUPLE_VALUE_HEADER_POSITION (tuple_record_p->tpl, key_info_p->key[i].col, field_data);
3134  field_length =
3135  ((QFILE_GET_TUPLE_VALUE_FLAG (field_data) == V_BOUND) ? QFILE_GET_TUPLE_VALUE_LENGTH (field_data) : 0);
3136 
3137  length += QFILE_TUPLE_VALUE_HEADER_SIZE + field_length;
3138 
3139  if (length <= key_record_p->area_size)
3140  {
3141  memcpy (data, field_data, QFILE_TUPLE_VALUE_HEADER_SIZE + field_length);
3142  }
3143 
3144  /*
3145  * Always pretend that we copied the data, even if we didn't.
3146  * That will allow us to find out how big the record really needs
3147  * to be.
3148  */
3149  data += QFILE_TUPLE_VALUE_HEADER_SIZE + field_length;
3150  }
3151  }
3152  else
3153  {
3154  /* A_sort_key */
3155 
3156  /* get sort_key body start position, align data to 8 bytes boundary */
3157  data = (char *) &sort_record_p->s.offset[nkeys];
3158  data = PTR_ALIGN (data, MAX_ALIGNMENT);
3159 
3160  length = CAST_BUFLEN (data - key_record_p->data); /* i.e, 4 + 4 * (n - 1) */
3161 
3162  /* STEP 1: build header(offset_MAP) - go on with STEP 2 */
3163 
3164  /* STEP 2: build body */
3165 
3166  for (i = 0; i < nkeys; i++)
3167  {
3168  /* Position ourselves at the next field, and find out its length */
3169  QFILE_GET_TUPLE_VALUE_HEADER_POSITION (tuple_record_p->tpl, key_info_p->key[i].col, field_data);
3170  field_length =
3171  ((QFILE_GET_TUPLE_VALUE_FLAG (field_data) == V_BOUND) ? QFILE_GET_TUPLE_VALUE_LENGTH (field_data) : 0);
3172 
3173  if (field_length)
3174  {
3175  /* non-NULL value */
3176 
3177  offset = CAST_BUFLEN (data - key_record_p->data + QFILE_TUPLE_VALUE_HEADER_SIZE);
3178  length = offset + field_length;
3179 
3180  if (length <= key_record_p->area_size)
3181  {
3182  sort_record_p->s.offset[i] = offset;
3183  memcpy (data, field_data, QFILE_TUPLE_VALUE_HEADER_SIZE + field_length);
3184  }
3185  /*
3186  * Always pretend that we copied the data, even if we didn't.
3187  * That will allow us to find out how big the record really
3188  * needs to be.
3189  */
3190  data += QFILE_TUPLE_VALUE_HEADER_SIZE + field_length;
3191  }
3192  else
3193  {
3194  /* do not copy NULL-value field */
3195 
3196  if (length <= key_record_p->area_size)
3197  {
3198  sort_record_p->s.offset[i] = 0;
3199  }
3200  }
3201  }
3202  }
3203 
3204  key_record_p->length = CAST_BUFLEN (data - key_record_p->data);
3205 
3206  if (key_record_p->length <= key_record_p->area_size)
3207  {
3208  status = SORT_SUCCESS;
3209  }
3210  else
3211  {
3212  scan_status = qfile_scan_prev (thread_p, input_scan_p);
3213  status = ((scan_status == S_ERROR) ? SORT_ERROR_OCCURRED : SORT_REC_DOESNT_FIT);
3214  }
3215 
3216  return status;
3217 }
3218 
3219 /* qfile_generate_sort_tuple () -
3220  * return:
3221  * info(in):
3222  * sort_rec(in):
3223  * output_recdes(out):
3224  */
3226 qfile_generate_sort_tuple (SORTKEY_INFO * key_info_p, SORT_REC * sort_record_p, RECDES * output_recdes_p)
3227 {
3228  int nkeys, size, i;
3229  char *tuple_p, *field_p;
3230  char *p;
3231  int c;
3232  char *src;
3233  int len;
3234 
3235  nkeys = key_info_p->nkeys;
3236  size = QFILE_TUPLE_LENGTH_SIZE;
3237 
3238  for (i = 0; i < nkeys; i++)
3239  {
3241  if (sort_record_p->s.offset[i] != 0)
3242  {
3243  p = (char *) sort_record_p + sort_record_p->s.offset[i] - QFILE_TUPLE_VALUE_HEADER_SIZE;
3244  size += QFILE_GET_TUPLE_VALUE_LENGTH (p);
3245  }
3246  }
3247 
3248  if (output_recdes_p->area_size < size)
3249  {
3250  if (output_recdes_p->area_size == 0)
3251  {
3252  tuple_p = (char *) db_private_alloc (NULL, size);
3253  }
3254  else
3255  {
3256  tuple_p = (char *) db_private_realloc (NULL, output_recdes_p->data, size);
3257  }
3258 
3259  if (tuple_p == NULL)
3260  {
3261  return NULL;
3262  }
3263 
3264  output_recdes_p->data = tuple_p;
3265  output_recdes_p->area_size = size;
3266  }
3267 
3268  tuple_p = output_recdes_p->data;
3269  field_p = tuple_p + QFILE_TUPLE_LENGTH_SIZE;
3270 
3271  for (i = 0; i < nkeys; i++)
3272  {
3273  c = key_info_p->key[i].permuted_col;
3274 
3275  if (sort_record_p->s.offset[c] == 0)
3276  {
3278  QFILE_PUT_TUPLE_VALUE_LENGTH (field_p, 0);
3279  }
3280  else
3281  {
3282  src = (char *) sort_record_p + sort_record_p->s.offset[c] - QFILE_TUPLE_VALUE_HEADER_SIZE;
3283  len = QFILE_GET_TUPLE_VALUE_LENGTH (src);
3284  memcpy (field_p, src, len + QFILE_TUPLE_VALUE_HEADER_SIZE);
3285  field_p += len;
3286  }
3287 
3288  field_p += QFILE_TUPLE_VALUE_HEADER_SIZE;
3289  }
3290 
3291  QFILE_PUT_TUPLE_LENGTH (tuple_p, field_p - tuple_p);
3292  return tuple_p;
3293 }
3294 
3295 /*
3296  * qfile_get_next_sort_item () -
3297  * return: SORT_STATUS
3298  * recdes(in): Temporary record descriptor
3299  * arg(in): Scan identifier
3300  *
3301  * Note: This routine is called by the sorting module to get the next
3302  * input item to sort. The scan identifier opened on the list file
3303  * is used to get the next list file tuple and return it to the sorting module
3304  * within the record descriptor. If the record descriptor area is not big
3305  * enough to hold the tuple, it is indicated to the sorting module and
3306  * scan position remains unchanged. The routine is supposed to be called again
3307  * with a bigger record descriptor. If there are no more tuples left
3308  * in the list file, or if an error occurs, the sorting module is informed with
3309  * necessary return codes.
3310  */
3311 static SORT_STATUS
3312 qfile_get_next_sort_item (THREAD_ENTRY * thread_p, RECDES * recdes_p, void *arg)
3313 {
3314  SORT_INFO *sort_info_p;
3315  QFILE_SORT_SCAN_ID *scan_id_p;
3316 
3317  sort_info_p = (SORT_INFO *) arg;
3318  scan_id_p = sort_info_p->s_id;
3319 
3320  return qfile_make_sort_key (thread_p, &sort_info_p->key_info, recdes_p, scan_id_p->s_id, &scan_id_p->tplrec);
3321 }
3322 
3323 /*
3324  * qfile_put_next_sort_item () -
3325  * return: SORT_STATUS
3326  * recdes(in): Temporary record descriptor
3327  * arg(in): Scan identifier
3328  *
3329  * Note: This routine is called by the sorting module to output the next sorted
3330  * item.
3331  *
3332  * We have two versions of the put_next function:
3333  * ls_sort_put_next_long and ls_sort_put_next_short. The long version
3334  * is building sort keys from records that hold more fields than sort keys.
3335  * It optimizes by simply keeping a pointer to the original record, and
3336  * when the sort keys are delivered back from the sort module, it uses
3337  * the pointer to retrieve the original record with all of the fields and
3338  * delivers that record to the output listfile.
3339  *
3340  * The short version is used when we we're sorting on all of the fields of
3341  * the record. In that case there's no point in remembering the original record,
3342  * and we save the space occupied by the pointer. We also avoid the relatively
3343  * random traversal of the input file when rendering the output file,
3344  * since we can reconstruct the input records without actually consulting
3345  * the input file.
3346  */
3347 static int
3348 qfile_put_next_sort_item (THREAD_ENTRY * thread_p, const RECDES * recdes_p, void *arg)
3349 {
3350  SORT_INFO *sort_info_p;
3351  SORT_REC *key_p;
3352  int error;
3353  QFILE_TUPLE_DESCRIPTOR *tuple_descr_p;
3354  int nkeys, i;
3355  char *p;
3356  PAGE_PTR page_p;
3357  VPID vpid;
3358  QFILE_LIST_ID *list_id_p;
3359  char *data;
3360 
3361  error = NO_ERROR;
3362  sort_info_p = (SORT_INFO *) arg;
3363 
3364  for (key_p = (SORT_REC *) recdes_p->data; key_p && error == NO_ERROR; key_p = key_p->next)
3365  {
3366  if (sort_info_p->key_info.use_original)
3367  {
3368  /* P_sort_key */
3369 
3370  list_id_p = &(sort_info_p->s_id->s_id->list_id);
3371 
3372  vpid.pageid = key_p->s.original.pageid;
3373  vpid.volid = key_p->s.original.volid;
3374 
3375 #if 0 /* SortCache */
3376  /* check if page is already fixed */
3377  if (VPID_EQ (&(sort_info_p->fixed_vpid), &vpid))
3378  {
3379  /* use cached page pointer */
3380  page_p = sort_info_p->fixed_page;
3381  }
3382  else
3383  {
3384  /* free currently fixed page */
3385  if (sort_info_p->fixed_page != NULL)
3386  {
3387  qmgr_free_old_page_and_init (thread_p, sort_info_p->fixed_page, list_id_p->tfile_vfid);
3388  }
3389 
3390  /* fix page and cache fixed vpid */
3391  page_p = qmgr_get_old_page (thread_p, &vpid, list_id_p->tfile_vfid);
3392  if (page_p == NULL)
3393  {
3394  assert (er_errid () != NO_ERROR);
3395  return er_errid ();
3396  }
3397 
3398  /* cache page pointer */
3399  sort_info_p->fixed_vpid = vpid;
3400  sort_info_p->fixed_page = page_p;
3401  }
3402 #else /* not SortCache */
3403  page_p = qmgr_get_old_page (thread_p, &vpid, list_id_p->tfile_vfid);
3404  if (page_p == NULL)
3405  {
3406  assert (er_errid () != NO_ERROR);
3407  return er_errid ();
3408  }
3409 #endif /* not SortCache */
3410 
3411  QFILE_GET_OVERFLOW_VPID (&vpid, page_p);
3412  if (vpid.pageid == NULL_PAGEID)
3413  {
3414  /*
3415  * This is the normal case of a non-overflow tuple. We can use
3416  * the page image directly, since we know that the tuple resides
3417  * entirely on that page.
3418  */
3419  data = page_p + key_p->s.original.offset;
3420  error = qfile_add_tuple_to_list (thread_p, sort_info_p->output_file, data);
3421  }
3422  else
3423  {
3424  assert (NULL_PAGEID < vpid.pageid); /* should not be NULL_PAGEID_IN_PROGRESS */
3425 
3426  /*
3427  * Rats; this tuple requires overflow pages. We need to copy
3428  * all of the pages from the input file to the output file.
3429  */
3430  error = qfile_add_overflow_tuple_to_list (thread_p, sort_info_p->output_file, page_p, list_id_p);
3431  }
3432 #if 1 /* not SortCache */
3433  qmgr_free_old_page_and_init (thread_p, page_p, list_id_p->tfile_vfid);
3434 #endif /* not SortCache */
3435  }
3436  else
3437  {
3438  /* A_sort_key */
3439 
3440  nkeys = sort_info_p->key_info.nkeys; /* get sort_key field number */
3441 
3442  /* generate tuple descriptor */
3443  tuple_descr_p = &(sort_info_p->output_file->tpl_descr);
3444 
3445  /* determine how big a tuple we'll need */
3446  tuple_descr_p->tpl_size = QFILE_TUPLE_LENGTH_SIZE + (QFILE_TUPLE_VALUE_HEADER_SIZE * nkeys);
3447  for (i = 0; i < nkeys; i++)
3448  {
3449  if (key_p->s.offset[i] != 0)
3450  {
3451  /*
3452  * Remember, the offset[] value points to the start of the
3453  * value's *data* (i.e., after the valflag/vallen nonsense),
3454  * and is measured from the start of the sort_rec.
3455  */
3456  p = (char *) key_p + key_p->s.offset[i] - QFILE_TUPLE_VALUE_HEADER_SIZE;
3457  tuple_descr_p->tpl_size += QFILE_GET_TUPLE_VALUE_LENGTH (p);
3458  }
3459  }
3460 
3461  if (tuple_descr_p->tpl_size < QFILE_MAX_TUPLE_SIZE_IN_PAGE)
3462  {
3463  /* SMALL QFILE_TUPLE */
3464 
3465  /* set tuple descriptor */
3466  tuple_descr_p->sortkey_info = (void *) (&sort_info_p->key_info);
3467  tuple_descr_p->sort_rec = (void *) key_p;
3468 
3469  /* generate sort_key driven tuple into list file page */
3470  error = qfile_generate_tuple_into_list (thread_p, sort_info_p->output_file, T_SORTKEY);
3471  }
3472  else
3473  {
3474  /* BIG QFILE_TUPLE */
3475 
3476  /*
3477  * We didn't record the original vpid, and we should just
3478  * reconstruct the original record from this sort key (rather
3479  * than pressure the page buffer pool by reading in the original
3480  * page to get the original tuple).
3481  */
3482  if (qfile_generate_sort_tuple (&sort_info_p->key_info, key_p, &sort_info_p->output_recdes) == NULL)
3483  {
3484  error = ER_FAILED;
3485  }
3486  else
3487  {
3488  error = qfile_add_tuple_to_list (thread_p, sort_info_p->output_file, sort_info_p->output_recdes.data);
3489  }
3490  }
3491  }
3492  }
3493 
3494  return (error == NO_ERROR) ? NO_ERROR : er_errid ();
3495 }
3496 
3497 /*
3498  * qfile_compare_partial_sort_record () -
3499  * return: -1, 0, or 1, strcmp-style
3500  * pk0(in): Pointer to pointer to first sort record
3501  * pk1(in): Pointer to pointer to second sort record
3502  * arg(in): Pointer to sort info
3503  *
3504  * Note: These routines are used for relative comparisons of two sort
3505  * records during sorting.
3506  */
3507 int
3508 qfile_compare_partial_sort_record (const void *pk0, const void *pk1, void *arg)
3509 {
3510  SORTKEY_INFO *key_info_p;
3511  SORT_REC *k0, *k1;
3512  int i, n;
3513  int o0, o1;
3514  int order;
3515  char *d0, *d1;
3516  char *fp0, *fp1; /* sort_key field pointer */
3517 
3518  key_info_p = (SORTKEY_INFO *) arg;
3519  n = key_info_p->nkeys;
3520  order = 0;
3521 
3522  k0 = *(SORT_REC **) pk0;
3523  k1 = *(SORT_REC **) pk1;
3524 
3525  /* get body start position of k0, k1 */
3526  fp0 = &(k0->s.original.body[0]);
3527  fp0 = PTR_ALIGN (fp0, MAX_ALIGNMENT);
3528 
3529  fp1 = &(k1->s.original.body[0]);
3530  fp1 = PTR_ALIGN (fp1, MAX_ALIGNMENT);
3531 
3532  for (i = 0; i < n; i++)
3533  {
3534  if (QFILE_GET_TUPLE_VALUE_FLAG (fp0) == V_BOUND)
3535  {
3536  o0 = 1;
3537  }
3538  else
3539  {
3540  o0 = 0; /* NULL */
3541  }
3542 
3543  if (QFILE_GET_TUPLE_VALUE_FLAG (fp1) == V_BOUND)
3544  {
3545  o1 = 1;
3546  }
3547  else
3548  {
3549  o1 = 0; /* NULL */
3550  }
3551 
3552  if (o0 && o1)
3553  {
3554  if (key_info_p->key[i].use_cmp_dom)
3555  {
3556  order = qfile_compare_with_interpolation_domain (fp0, fp1, &key_info_p->key[i], key_info_p);
3557  }
3558  else
3559  {
3562 
3563  order = (*key_info_p->key[i].sort_f) (d0, d1, key_info_p->key[i].col_dom, 0, 1, NULL);
3564  }
3565 
3566  order = key_info_p->key[i].is_desc ? -order : order;
3567  }
3568  else
3569  {
3570  order = qfile_compare_with_null_value (o0, o1, key_info_p->key[i]);
3571  }
3572 
3573  if (order != 0)
3574  {
3575  break;
3576  }
3577 
3580  }
3581 
3582  return order;
3583 }
3584 
3585 int
3586 qfile_compare_all_sort_record (const void *pk0, const void *pk1, void *arg)
3587 {
3588  SORTKEY_INFO *key_info_p;
3589  SORT_REC *k0, *k1;
3590  int i, n;
3591  int order;
3592  int o0, o1;
3593  char *d0, *d1;
3594 
3595  key_info_p = (SORTKEY_INFO *) arg;
3596  n = key_info_p->nkeys;
3597  order = 0;
3598 
3599  k0 = *(SORT_REC **) pk0;
3600  k1 = *(SORT_REC **) pk1;
3601 
3602  for (i = 0; i < n; i++)
3603  {
3604  o0 = k0->s.offset[i];
3605  o1 = k1->s.offset[i];
3606 
3607  if (o0 && o1)
3608  {
3609  d0 = (char *) k0 + o0;
3610  d1 = (char *) k1 + o1;
3611 
3612  order = (*key_info_p->key[i].sort_f) (d0, d1, key_info_p->key[i].col_dom, 0, 1, NULL);
3613  order = key_info_p->key[i].is_desc ? -order : order;
3614  }
3615  else
3616  {
3617  order = qfile_compare_with_null_value (o0, o1, key_info_p->key[i]);
3618  }
3619 
3620  if (order != 0)
3621  {
3622  break;
3623  }
3624  }
3625 
3626  return order;
3627 }
3628 
3629 /*
3630  * qfile_compare_with_null_value () -
3631  * return: -1, 0, or 1, strcmp-style
3632  * o0(in): The first value
3633  * o1(in): The second value
3634  * key_info(in): Sub-key info
3635  *
3636  * Note: These routines are internally used for relative comparisons
3637  * of two values which include NULL value.
3638  */
3639 static int
3641 {
3642  /* At least one of the values sholud be NULL */
3643  assert (o0 == 0 || o1 == 0);
3644 
3645  if (o0 == 0 && o1 == 0)
3646  {
3647  /* both are unbound */
3648  return 0;
3649  }
3650  else if (o0 == 0)
3651  {
3652  /* NULL compare_op !NULL */
3653  assert (o1 != 0);
3654  if (key_info.is_nulls_first)
3655  {
3656  return -1;
3657  }
3658  else
3659  {
3660  return 1;
3661  }
3662  }
3663  else
3664  {
3665  /* !NULL compare_op NULL */
3666  assert (o1 == 0);
3667  if (key_info.is_nulls_first)
3668  {
3669  return 1;
3670  }
3671  else
3672  {
3673  return -1;
3674  }
3675  }
3676 }
3677 
3678 /* qfile_get_estimated_pages_for_sorting () -
3679  * return:
3680  * listid(in):
3681  * info(in):
3682  *
3683  * Note: Make an estimate of input page count to be passed to the sorting
3684  * module. We want this to be an upper bound, because the sort
3685  * package already has a limit on sort buffer size, and sorting
3686  * proceeds faster with larger in-memory use.
3687  */
3688 int
3690 {
3691  int prorated_pages, sort_key_size, sort_key_overhead;
3692 
3693  prorated_pages = (int) list_id_p->page_cnt;
3694  if (key_info_p->use_original == 1)
3695  {
3696  /* P_sort_key */
3697 
3698  /*
3699  * Every Part sort key record will have one int of overhead
3700  * per field in the key (for the offset vector).
3701  */
3702  sort_key_size = (int) offsetof (SORT_REC, s.original.body[0]);
3703  sort_key_overhead = (int) ceil (((double) (list_id_p->tuple_cnt * sort_key_size)) / DB_PAGESIZE);
3704  }
3705  else
3706  {
3707  /* A_sort_key */
3708 
3709  /*
3710  * Every Part sort key record will have one int of overhead
3711  * per field in the key (for the offset vector).
3712  */
3713  sort_key_size =
3714  (int) offsetof (SORT_REC, s.offset[0]) + sizeof (((SORT_REC *) 0)->s.offset[0]) * key_info_p->nkeys;
3715  sort_key_overhead = (int) ceil (((double) (list_id_p->tuple_cnt * sort_key_size)) / DB_PAGESIZE);
3716  }
3717 
3718  return prorated_pages + sort_key_overhead;
3719 }
3720 
3721 /* qfile_initialize_sort_key_info () -
3722  * return:
3723  * info(in):
3724  * list(in):
3725  * types(in):
3726  */
3727 SORTKEY_INFO *
3729 {
3730  int i, n;
3731  SUBKEY_INFO *subkey;
3732 
3733  if (types == NULL)
3734  {
3736  return NULL;
3737  }
3738 
3739  if (list_p)
3740  {
3741  n = qfile_get_sort_list_size (list_p);
3742  }
3743  else
3744  {
3745  n = types->type_cnt;
3746  }
3747 
3748  key_info_p->nkeys = n;
3749  key_info_p->use_original = (n != types->type_cnt);
3750  key_info_p->error = NO_ERROR;
3751 
3752  if (n <= (int) DIM (key_info_p->default_keys))
3753  {
3754  key_info_p->key = key_info_p->default_keys;
3755  }
3756  else
3757  {
3758  key_info_p->key = (SUBKEY_INFO *) db_private_alloc (NULL, n * sizeof (SUBKEY_INFO));
3759  if (key_info_p->key == NULL)
3760  {
3761  return NULL;
3762  }
3763  }
3764 
3765  if (list_p)
3766  {
3767  SORT_LIST *p;
3768  for (i = 0, p = list_p; p; i++, p = p->next)
3769  {
3770  assert_release (p->pos_descr.pos_no >= 0);
3771  assert_release (p->pos_descr.dom != NULL);
3772 
3773  subkey = &key_info_p->key[i];
3774  subkey->col = p->pos_descr.pos_no;
3775  subkey->col_dom = p->pos_descr.dom;
3776  subkey->cmp_dom = NULL;
3777  subkey->use_cmp_dom = false;
3778 
3779  if (p->pos_descr.dom->type->id == DB_TYPE_VARIABLE)
3780  {
3781  subkey->sort_f = types->domp[i]->type->get_data_cmpdisk_function ();
3782  }
3783  else
3784  {
3785  subkey->sort_f = p->pos_descr.dom->type->get_data_cmpdisk_function ();
3786  }
3787 
3788  subkey->is_desc = (p->s_order == S_ASC) ? 0 : 1;
3789  subkey->is_nulls_first = (p->s_nulls == S_NULLS_LAST) ? 0 : 1;
3790 
3791  if (key_info_p->use_original)
3792  {
3793  key_info_p->key[i].permuted_col = i;
3794  }
3795  else
3796  {
3797  key_info_p->key[p->pos_descr.pos_no].permuted_col = i;
3798  }
3799  }
3800  }
3801  else
3802  {
3803  for (i = 0; i < n; i++)
3804  {
3805  SUBKEY_INFO *subkey;
3806  subkey = &key_info_p->key[i];
3807  subkey->col = i;
3808  subkey->permuted_col = i;
3809  subkey->col_dom = types->domp[i];
3810  subkey->cmp_dom = NULL;
3811  subkey->use_cmp_dom = false;
3812  subkey->sort_f = types->domp[i]->type->get_data_cmpdisk_function ();
3813  subkey->is_desc = 0;
3814  subkey->is_nulls_first = 1;
3815  }
3816  }
3817 
3818  return key_info_p;
3819 }
3820 
3821 /* qfile_clear_sort_key_info () -
3822  * return:
3823  * info(in):
3824  */
3825 void
3827 {
3828  if (!key_info_p)
3829  {
3830  return;
3831  }
3832 
3833  if (key_info_p->key && key_info_p->key != key_info_p->default_keys)
3834  {
3835  db_private_free_and_init (NULL, key_info_p->key);
3836  }
3837 
3838  key_info_p->key = NULL;
3839  key_info_p->nkeys = 0;
3840 }
3841 
3842 /* qfile_initialize_sort_info () -
3843  * return:
3844  * info(in):
3845  * listid(in):
3846  * sort_list(in):
3847  */
3848 static SORT_INFO *
3849 qfile_initialize_sort_info (SORT_INFO * sort_info_p, QFILE_LIST_ID * list_id_p, SORT_LIST * sort_list_p)
3850 {
3851  sort_info_p->key_info.key = NULL;
3852 #if 0 /* SortCache */
3853  VPID_SET_NULL (&(sort_info_p->fixed_vpid));
3854  sort_info_p->fixed_page = NULL;
3855 #endif /* SortCache */
3856  sort_info_p->output_recdes.data = NULL;
3857  sort_info_p->output_recdes.area_size = 0;
3858  if (qfile_initialize_sort_key_info (&sort_info_p->key_info, sort_list_p, &list_id_p->type_list) == NULL)
3859  {
3860  return NULL;
3861  }
3862 
3863  return sort_info_p;
3864 }
3865 
3866 /* qfile_clear_sort_info () -
3867  * return: none
3868  * info(in): Pointer to info block to be initialized
3869  *
3870  * Note: Free all internal structures in the given SORT_INFO block.
3871  */
3872 static void
3874 {
3875 #if 0 /* SortCache */
3876  QFILE_LIST_ID *list_idp;
3877 
3878  list_idp = &(sort_info_p->s_id->s_id->list_id);
3879 
3880  if (sort_info_p->fixed_page != NULL)
3881  {
3882  qmgr_free_old_page_and_init (thread_p, sort_info_p->fixed_page, list_idp->tfile_vfid);
3883  }
3884 #endif /* SortCache */
3885 
3886  qfile_clear_sort_key_info (&sort_info_p->key_info);
3887 
3888  if (sort_info_p->output_recdes.data)
3889  {
3891  }
3892 
3893  sort_info_p->output_recdes.data = NULL;
3894  sort_info_p->output_recdes.area_size = 0;
3895 }
3896 
3897 /*
3898  * qfile_sort_list_with_func () -
3899  * return: QFILE_LIST_ID *, or NULL
3900  * list_id(in): Source list file identifier
3901  * sort_list(in): List of comparison items
3902  * option(in):
3903  * ls_flag(in):
3904  * get_fn(in):
3905  * put_fn(in):
3906  * cmp_fn(in):
3907  * extra_arg(in):
3908  * limit(in):
3909  * do_close(in):
3910  */
3911 QFILE_LIST_ID *
3912 qfile_sort_list_with_func (THREAD_ENTRY * thread_p, QFILE_LIST_ID * list_id_p, SORT_LIST * sort_list_p,
3913  QUERY_OPTIONS option, int flag, SORT_GET_FUNC * get_func, SORT_PUT_FUNC * put_func,
3914  SORT_CMP_FUNC * cmp_func, void *extra_arg, int limit, bool do_close)
3915 {
3916  QFILE_LIST_ID *srlist_id;
3917  QFILE_LIST_SCAN_ID t_scan_id;
3918  QFILE_SORT_SCAN_ID s_scan_id;
3919  SORT_INFO info;
3920  int sort_result, estimated_pages;
3921  SORT_DUP_OPTION dup_option;
3922 
3923  srlist_id = qfile_open_list (thread_p, &list_id_p->type_list, sort_list_p, list_id_p->query_id, flag);
3924  if (srlist_id == NULL)
3925  {
3926  return NULL;
3927  }
3928 
3929  /* open a scan on the unsorted list file */
3930  if (qfile_open_list_scan (list_id_p, &t_scan_id) != NO_ERROR)
3931  {
3932  qfile_close_and_free_list_file (thread_p, srlist_id);
3933  return NULL;
3934  }
3935 
3936  if (qfile_initialize_sort_info (&info, list_id_p, sort_list_p) == NULL)
3937  {
3938  qfile_close_scan (thread_p, &t_scan_id);
3939  qfile_close_and_free_list_file (thread_p, srlist_id);
3940  return NULL;
3941  }
3942 
3943  info.s_id = &s_scan_id;
3944  info.output_file = srlist_id;
3945  info.extra_arg = extra_arg;
3946 
3947  if (get_func == NULL)
3948  {
3949  get_func = &qfile_get_next_sort_item;
3950  }
3951 
3952  if (put_func == NULL)
3953  {
3954  put_func = &qfile_put_next_sort_item;
3955  }
3956 
3957  if (cmp_func == NULL)
3958  {
3959  if (info.key_info.use_original == 1)
3960  {
3962  }
3963  else
3964  {
3965  cmp_func = &qfile_compare_all_sort_record;
3966  }
3967  }
3968 
3969  s_scan_id.s_id = &t_scan_id;
3970  s_scan_id.tplrec.size = 0;
3971  s_scan_id.tplrec.tpl = (char *) NULL;
3972 
3973  estimated_pages = qfile_get_estimated_pages_for_sorting (list_id_p, &info.key_info);
3974 
3975  dup_option = ((option == Q_DISTINCT) ? SORT_ELIM_DUP : SORT_DUP);
3976 
3977  sort_result =
3978  sort_listfile (thread_p, NULL_VOLID, estimated_pages, get_func, &info, put_func, &info, cmp_func, &info.key_info,
3979  dup_option, limit, srlist_id->tfile_vfid->tde_encrypted);
3980 
3981  if (sort_result < 0)
3982  {
3983 #if 0 /* SortCache */
3984  qfile_clear_sort_info (&info);
3985  qfile_close_scan (&t_scan_id);
3986 #else /* not SortCache */
3987  qfile_close_scan (thread_p, &t_scan_id);
3988  qfile_clear_sort_info (&info);
3989 #endif /* not SortCache */
3990  qfile_close_list (thread_p, list_id_p);
3991  qfile_destroy_list (thread_p, list_id_p);
3992  qfile_close_and_free_list_file (thread_p, srlist_id);
3993  return NULL;
3994  }
3995 
3996  if (do_close)
3997  {
3998  qfile_close_list (thread_p, srlist_id);
3999  }
4000 
4001 #if 0 /* SortCache */
4002  qfile_clear_sort_info (&info);
4003  qfile_close_scan (&t_scan_id);
4004 #else /* not SortCache */
4005  qfile_close_scan (thread_p, &t_scan_id);
4006  qfile_clear_sort_info (&info);
4007 #endif /* not SortCache */
4008 
4009  qfile_close_list (thread_p, list_id_p);
4010  qfile_destroy_list (thread_p, list_id_p);
4011  qfile_copy_list_id (list_id_p, srlist_id, true);
4012  QFILE_FREE_AND_INIT_LIST_ID (srlist_id);
4013 
4014  return list_id_p;
4015 }
4016 
4017 /*
4018  * qfile_sort_list () -
4019  * return: QFILE_LIST_ID *, or NULL
4020  * list_id(in): Source list file identifier
4021  * sort_list(in): List of comparison items
4022  * option(in):
4023  * do_close(in);
4024  *
4025  * Note: This routine sorts the specified list file tuples according
4026  * to the list of comparison items and generates a sorted list
4027  * file. The source list file is not affected by the routine.
4028  */
4029 QFILE_LIST_ID *
4030 qfile_sort_list (THREAD_ENTRY * thread_p, QFILE_LIST_ID * list_id_p, SORT_LIST * sort_list_p, QUERY_OPTIONS option,
4031  bool do_close)
4032 {
4033  int ls_flag;
4034 
4035  if (sort_list_p && qfile_is_sort_list_covered (list_id_p->sort_list, sort_list_p) == true)
4036  {
4037  /* no need to sort here */
4038  return list_id_p;
4039  }
4040 
4041  ls_flag = (option == Q_DISTINCT) ? QFILE_FLAG_DISTINCT : QFILE_FLAG_ALL;
4042 
4043  return qfile_sort_list_with_func (thread_p, list_id_p, sort_list_p, option, ls_flag, NULL, NULL, NULL, NULL,
4044  NO_SORT_LIMIT, do_close);
4045 }
4046 
4047 /*
4048  * qfile_copy_list_pages () -
4049  * return:
4050  * old_first_vpidp(in) :
4051  * old_tfile_vfidp(in) :
4052  * new_first_vpidp(in) :
4053  * new_last_vpidp(in) :
4054  * new_tfile_vfidp(in) :
4055  */
4056 static int
4057 qfile_copy_list_pages (THREAD_ENTRY * thread_p, VPID * old_first_vpid_p, QMGR_TEMP_FILE * old_tfile_vfid_p,
4058  VPID * new_first_vpid_p, VPID * new_last_vpid_p, QMGR_TEMP_FILE * new_tfile_vfid_p)
4059 {
4060  PAGE_PTR old_page_p, old_ovfl_page_p, prev_page_p, new_page_p, new_ovfl_page_p;
4061  VPID old_next_vpid, old_ovfl_vpid, prev_vpid, new_ovfl_vpid;
4062 
4063  old_page_p = qmgr_get_old_page (thread_p, old_first_vpid_p, old_tfile_vfid_p);
4064  if (old_page_p == NULL)
4065  {
4066  return ER_FAILED;
4067  }
4068 
4069  new_page_p = qmgr_get_new_page (thread_p, new_first_vpid_p, new_tfile_vfid_p);
4070  if (new_page_p == NULL)
4071  {
4072  qmgr_free_old_page_and_init (thread_p, old_page_p, old_tfile_vfid_p);
4073  return ER_FAILED;
4074  }
4075 
4076  *new_last_vpid_p = *new_first_vpid_p;
4077 
4078  while (true)
4079  {
4080  (void) memcpy (new_page_p, old_page_p, DB_PAGESIZE);
4081 
4082  QFILE_GET_OVERFLOW_VPID (&old_ovfl_vpid, old_page_p);
4083  prev_page_p = new_page_p;
4084  new_ovfl_page_p = NULL;
4085 
4086  while (!VPID_ISNULL (&old_ovfl_vpid))
4087  {
4088  old_ovfl_page_p = qmgr_get_old_page (thread_p, &old_ovfl_vpid, old_tfile_vfid_p);
4089  if (old_ovfl_page_p == NULL)
4090  {
4091  qmgr_free_old_page_and_init (thread_p, old_page_p, old_tfile_vfid_p);
4092  qfile_set_dirty_page (thread_p, new_page_p, FREE, new_tfile_vfid_p);
4093  return ER_FAILED;
4094  }
4095 
4096  new_ovfl_page_p = qmgr_get_new_page (thread_p, &new_ovfl_vpid, new_tfile_vfid_p);
4097 
4098  if (new_ovfl_page_p == NULL)
4099  {
4100  qmgr_free_old_page_and_init (thread_p, old_ovfl_page_p, old_tfile_vfid_p);
4101  qmgr_free_old_page_and_init (thread_p, old_page_p, old_tfile_vfid_p);
4102  qfile_set_dirty_page (thread_p, new_page_p, FREE, new_tfile_vfid_p);
4103  return ER_FAILED;
4104  }
4105 
4106  (void) memcpy (new_ovfl_page_p, old_ovfl_page_p, DB_PAGESIZE);
4107 
4108  QFILE_GET_OVERFLOW_VPID (&old_ovfl_vpid, old_ovfl_page_p);
4109  qmgr_free_old_page_and_init (thread_p, old_ovfl_page_p, old_tfile_vfid_p);
4110 
4111  QFILE_PUT_OVERFLOW_VPID (prev_page_p, &new_ovfl_vpid);
4112  qfile_set_dirty_page (thread_p, prev_page_p, FREE, new_tfile_vfid_p);
4113 
4114  prev_page_p = new_ovfl_page_p;
4115  }
4116 
4117  if (new_ovfl_page_p)
4118  {
4119  qfile_set_dirty_page (thread_p, new_ovfl_page_p, FREE, new_tfile_vfid_p);
4120  }
4121 
4122  QFILE_GET_NEXT_VPID (&old_next_vpid, old_page_p);
4123  qmgr_free_old_page_and_init (thread_p, old_page_p, old_tfile_vfid_p);
4124 
4125  if (VPID_ISNULL (&old_next_vpid))
4126  {
4127  qfile_set_dirty_page (thread_p, new_page_p, FREE, new_tfile_vfid_p);
4128  new_page_p = NULL;
4129  break;
4130  }
4131 
4132  old_page_p = qmgr_get_old_page (thread_p, &old_next_vpid, old_tfile_vfid_p);
4133  prev_page_p = new_page_p;
4134  prev_vpid = *new_last_vpid_p;
4135 
4136  if (old_page_p == NULL)
4137  {
4138  qfile_set_dirty_page (thread_p, prev_page_p, FREE, new_tfile_vfid_p);
4139  return ER_FAILED;
4140  }
4141 
4142  new_page_p = qmgr_get_new_page (thread_p, new_last_vpid_p, new_tfile_vfid_p);
4143  if (new_page_p == NULL)
4144  {
4145  qmgr_free_old_page_and_init (thread_p, old_page_p, old_tfile_vfid_p);
4146  qfile_set_dirty_page (thread_p, prev_page_p, FREE, new_tfile_vfid_p);
4147  return ER_FAILED;
4148  }
4149 
4150  QFILE_PUT_PREV_VPID (new_page_p, &prev_vpid);
4151  QFILE_PUT_NEXT_VPID (prev_page_p, new_last_vpid_p);
4152 
4153  qfile_set_dirty_page (thread_p, prev_page_p, FREE, new_tfile_vfid_p);
4154  }
4155 
4156  if (new_page_p)
4157  {
4158  qfile_set_dirty_page (thread_p, prev_page_p, FREE, new_tfile_vfid_p);
4159  }
4160 
4161  return NO_ERROR;
4162 }
4163 
4164 /*
4165  * qfile_duplicate_list () -
4166  * return:
4167  * list_id(in):
4168  * flag(in):
4169  *
4170  * Note: This routine duplicates the specified list file.
4171  * The source list file is not affected by the routine.
4172  */
4173 QFILE_LIST_ID *
4174 qfile_duplicate_list (THREAD_ENTRY * thread_p, QFILE_LIST_ID * list_id_p, int flag)
4175 {
4176  QFILE_LIST_ID *dup_list_id_p;
4177 
4178  dup_list_id_p = qfile_open_list (thread_p, &list_id_p->type_list, NULL, list_id_p->query_id, flag);
4179  if (dup_list_id_p == NULL)
4180  {
4181  return NULL;
4182  }
4183 
4184  if (qfile_copy_list_pages (thread_p, &list_id_p->first_vpid, list_id_p->tfile_vfid, &dup_list_id_p->first_vpid,
4185  &dup_list_id_p->last_vpid, dup_list_id_p->tfile_vfid) != NO_ERROR)
4186  {
4187  qfile_destroy_list (thread_p, dup_list_id_p);
4188  QFILE_FREE_AND_INIT_LIST_ID (dup_list_id_p);
4189  return NULL;
4190  }
4191 
4192  dup_list_id_p->tuple_cnt = list_id_p->tuple_cnt;
4193  dup_list_id_p->page_cnt = list_id_p->page_cnt;
4194 
4195  return dup_list_id_p;
4196 }
4197 
4198 /*
4199  * List File Scan Routines
4200  */
4201 
4202 /*
4203  * qfile_get_tuple () -
4204  * return:
4205  * first_page(in):
4206  * tuplep(in):
4207  * tplrec(in):
4208  * list_idp(in):
4209  */
4210 int
4211 qfile_get_tuple (THREAD_ENTRY * thread_p, PAGE_PTR first_page_p, QFILE_TUPLE tuple, QFILE_TUPLE_RECORD * tuple_record_p,
4212  QFILE_LIST_ID * list_id_p)
4213 {
4214  VPID ovfl_vpid;
4215  char *tuple_p;
4216  int offset;
4217  int tuple_length, tuple_page_size;
4218  int max_tuple_page_size;
4219  PAGE_PTR page_p;
4220 
4221  page_p = first_page_p;
4222  tuple_length = QFILE_GET_TUPLE_LENGTH (tuple);
4223 
4224  if (tuple_record_p->size < tuple_length)
4225  {
4226  if (qfile_reallocate_tuple (tuple_record_p, tuple_length) != NO_ERROR)
4227  {
4228  return ER_FAILED;
4229  }
4230  }
4231 
4232  tuple_p = (char *) tuple_record_p->tpl;
4233 
4235  {
4236  /* tuple is inside the page */
4237  memcpy (tuple_p, tuple, tuple_length);
4238  return NO_ERROR;
4239  }
4240  else
4241  {
4242  /* tuple has overflow pages */
4243  offset = 0;
4244  max_tuple_page_size = qfile_Max_tuple_page_size;
4245 
4246  do
4247  {
4248  QFILE_GET_OVERFLOW_VPID (&ovfl_vpid, page_p);
4249  tuple_page_size = MIN (tuple_length - offset, max_tuple_page_size);
4250 
4251  memcpy (tuple_p, (char *) page_p + QFILE_PAGE_HEADER_SIZE, tuple_page_size);
4252 
4253  tuple_p += tuple_page_size;
4254  offset += tuple_page_size;
4255 
4256  if (page_p != first_page_p)
4257  {
4258  qmgr_free_old_page_and_init (thread_p, page_p, list_id_p->tfile_vfid);
4259  }
4260 
4261  if (ovfl_vpid.pageid != NULL_PAGEID)
4262  {
4263  page_p = qmgr_get_old_page (thread_p, &ovfl_vpid, list_id_p->tfile_vfid);
4264  if (page_p == NULL)
4265  {
4266  return ER_FAILED;
4267  }
4268  }
4269  }
4270  while (ovfl_vpid.pageid != NULL_PAGEID);
4271  }
4272 
4273  return NO_ERROR;
4274 }
4275 
4276 /*
4277  * qfile_get_tuple_from_current_list () -
4278  * return: int (NO_ERROR or ER_FAILED)
4279  * s_id(in): Scan identifier
4280  * tplrec(in): Tuple record descriptor
4281  *
4282  * Note: Fetch the current tuple of the given scan identifier into the
4283  * tuple descriptor.
4284  */
4285 static int
4287  QFILE_TUPLE_RECORD * tuple_record_p)
4288 {
4289  PAGE_PTR page_p;
4290  QFILE_TUPLE tuple;
4291 
4292  page_p = scan_id_p->curr_pgptr;
4293  tuple = (char *) page_p + scan_id_p->curr_offset;
4294 
4295  return qfile_get_tuple (thread_p, page_p, tuple, tuple_record_p, &scan_id_p->list_id);
4296 }
4297 
4298 /*
4299  * qfile_scan_next () -
4300  * return: SCAN_CODE (S_SUCCESS, S_END, S_ERROR)
4301  * s_id(in/out): Scan identifier
4302  *
4303  * Note: The scan is moved to the next scan item. If there are no more
4304  * scan items, S_END is returned. If an error occurs,
4305  * S_ERROR is returned.
4306  *
4307  * Note: The scan identifier must be of type LIST FILE scan identifier.
4308  */
4309 static SCAN_CODE
4311 {
4312  PAGE_PTR page_p, next_page_p;
4313  VPID next_vpid;
4314 
4315  if (scan_id_p->position == S_BEFORE)
4316  {
4317  if (scan_id_p->list_id.tuple_cnt > 0)
4318  {
4319  page_p = qmgr_get_old_page (thread_p, &scan_id_p->list_id.first_vpid, scan_id_p->list_id.tfile_vfid);
4320  if (page_p == NULL)
4321  {
4322  return S_ERROR;
4323  }
4324 
4325  QFILE_COPY_VPID (&scan_id_p->curr_vpid, &scan_id_p->list_id.first_vpid);
4326  scan_id_p->curr_pgptr = page_p;
4327  scan_id_p->curr_offset = QFILE_PAGE_HEADER_SIZE;
4328  scan_id_p->curr_tpl = (char *) scan_id_p->curr_pgptr + QFILE_PAGE_HEADER_SIZE;
4329  scan_id_p->curr_tplno = 0;
4330  scan_id_p->position = S_ON;
4331  return S_SUCCESS;
4332  }
4333  else
4334  {
4335  return S_END;
4336  }
4337  }
4338  else if (scan_id_p->position == S_ON)
4339  {
4340  if (scan_id_p->curr_tplno < QFILE_GET_TUPLE_COUNT (scan_id_p->curr_pgptr) - 1)
4341  {
4342  scan_id_p->curr_offset += QFILE_GET_TUPLE_LENGTH (scan_id_p->curr_tpl);
4343  scan_id_p->curr_tpl += QFILE_GET_TUPLE_LENGTH (scan_id_p->curr_tpl);
4344  scan_id_p->curr_tplno++;
4345  return S_SUCCESS;
4346  }
4347  else if (qfile_has_next_page (scan_id_p->curr_pgptr))
4348  {
4349  QFILE_GET_NEXT_VPID (&next_vpid, scan_id_p->curr_pgptr);
4350  next_page_p = qmgr_get_old_page (thread_p, &next_vpid, scan_id_p->list_id.tfile_vfid);
4351  if (next_page_p == NULL)
4352  {
4353  return S_ERROR;
4354  }
4355 
4356  qmgr_free_old_page_and_init (thread_p, scan_id_p->curr_pgptr, scan_id_p->list_id.tfile_vfid);
4357  QFILE_COPY_VPID (&scan_id_p->curr_vpid, &next_vpid);
4358  scan_id_p->curr_pgptr = next_page_p;
4359  scan_id_p->curr_tplno = 0;
4360  scan_id_p->curr_offset = QFILE_PAGE_HEADER_SIZE;
4361  scan_id_p->curr_tpl = (char *) scan_id_p->curr_pgptr + QFILE_PAGE_HEADER_SIZE;
4362  return S_SUCCESS;
4363  }
4364  else
4365  {
4366  scan_id_p->position = S_AFTER;
4367 
4368  if (!scan_id_p->keep_page_on_finish)
4369  {
4370  scan_id_p->curr_vpid.pageid = NULL_PAGEID;
4371  qmgr_free_old_page_and_init (thread_p, scan_id_p->curr_pgptr, scan_id_p->list_id.tfile_vfid);
4372  }
4373 
4374  return S_END;
4375  }
4376  }
4377  else if (scan_id_p->position == S_AFTER)
4378  {
4379  return S_END;
4380  }
4381  else
4382  {
4384  return S_ERROR;
4385  }
4386 }
4387 
4388 /*
4389  * qfile_scan_prev () -
4390  * return: SCAN_CODE (S_SUCCESS, S_END, S_ERROR)
4391  * s_id(in/out): Scan identifier
4392  *
4393  * Note: The scan is moved to previous scan item. If there are no more
4394  * scan items, S_END is returned. If an error occurs,
4395  * S_ERROR is returned.
4396  */
4397 static SCAN_CODE
4399 {
4400  PAGE_PTR page_p, prev_page_p;
4401  VPID prev_vpid;
4402 
4403  if (scan_id_p->position == S_BEFORE)
4404  {
4405  return S_END;
4406  }
4407  else if (scan_id_p->position == S_ON)
4408  {
4409  if (scan_id_p->curr_tplno > 0)
4410  {
4411  scan_id_p->curr_offset -= QFILE_GET_PREV_TUPLE_LENGTH (scan_id_p->curr_tpl);
4412  scan_id_p->curr_tpl -= QFILE_GET_PREV_TUPLE_LENGTH (scan_id_p->curr_tpl);
4413  scan_id_p->curr_tplno--;
4414  return S_SUCCESS;
4415  }
4416  else if (QFILE_GET_PREV_PAGE_ID (scan_id_p->curr_pgptr) != NULL_PAGEID)
4417  {
4418  QFILE_GET_PREV_VPID (&prev_vpid, scan_id_p->curr_pgptr);
4419  prev_page_p = qmgr_get_old_page (thread_p, &prev_vpid, scan_id_p->list_id.tfile_vfid);
4420  if (prev_page_p == NULL)
4421  {
4422  return S_ERROR;
4423  }
4424 
4425  qmgr_free_old_page_and_init (thread_p, scan_id_p->curr_pgptr, scan_id_p->list_id.tfile_vfid);
4426  QFILE_COPY_VPID (&scan_id_p->curr_vpid, &prev_vpid);
4427  scan_id_p->curr_pgptr = prev_page_p;
4428  scan_id_p->curr_tplno = QFILE_GET_TUPLE_COUNT (prev_page_p) - 1;
4429  scan_id_p->curr_offset = QFILE_GET_LAST_TUPLE_OFFSET (prev_page_p);
4430  scan_id_p->curr_tpl = (char *) scan_id_p->curr_pgptr + scan_id_p->curr_offset;
4431  return S_SUCCESS;
4432  }
4433  else
4434  {
4435  scan_id_p->position = S_BEFORE;
4436  scan_id_p->curr_vpid.pageid = NULL_PAGEID;
4437  qmgr_free_old_page_and_init (thread_p, scan_id_p->curr_pgptr, scan_id_p->list_id.tfile_vfid);
4438  return S_END;
4439  }
4440  }
4441  else if (scan_id_p->position == S_AFTER)
4442  {
4443 
4444  if (VPID_ISNULL (&scan_id_p->list_id.first_vpid))
4445  {
4446  return S_END;
4447  }
4448  page_p = qmgr_get_old_page (thread_p, &scan_id_p->list_id.last_vpid, scan_id_p->list_id.tfile_vfid);
4449  if (page_p == NULL)
4450  {
4451  return S_ERROR;
4452  }
4453 
4454  scan_id_p->position = S_ON;
4455  QFILE_COPY_VPID (&scan_id_p->curr_vpid, &scan_id_p->list_id.last_vpid);
4456  scan_id_p->curr_pgptr = page_p;
4457  scan_id_p->curr_tplno = QFILE_GET_TUPLE_COUNT (page_p) - 1;
4458  scan_id_p->curr_offset = QFILE_GET_LAST_TUPLE_OFFSET (page_p);
4459  scan_id_p->curr_tpl = (char *) scan_id_p->curr_pgptr + scan_id_p->curr_offset;
4460  return S_SUCCESS;
4461  }
4462  else
4463  {
4465  return S_ERROR;
4466  }
4467 }
4468 
4469 /*
4470  * qfile_save_current_scan_tuple_position () -
4471  * return:
4472  * s_id(in): Scan identifier
4473  * ls_tplpos(in/out): Set to contain current scan tuple position
4474  *
4475  * Note: Save current scan tuple position information.
4476  */
4477 void
4479 {
4480  tuple_position_p->status = scan_id_p->status;
4481  tuple_position_p->position = scan_id_p->position;
4482  tuple_position_p->vpid.pageid = scan_id_p->curr_vpid.pageid;
4483  tuple_position_p->vpid.volid = scan_id_p->curr_vpid.volid;
4484  tuple_position_p->offset = scan_id_p->curr_offset;
4485  tuple_position_p->tpl = scan_id_p->curr_tpl;
4486  tuple_position_p->tplno = scan_id_p->curr_tplno;
4487 }
4488 
4489 static SCAN_CODE
4490 qfile_retrieve_tuple (THREAD_ENTRY * thread_p, QFILE_LIST_SCAN_ID * scan_id_p, QFILE_TUPLE_RECORD * tuple_record_p,
4491  int peek)
4492 {
4493  int tuple_size;
4494 
4496  {
4497  if (peek)
4498  {
4499  tuple_record_p->tpl = scan_id_p->curr_tpl;
4500  }
4501  else
4502  {
4503  tuple_size = QFILE_GET_TUPLE_LENGTH (scan_id_p->curr_tpl);
4504  if (tuple_record_p->size < tuple_size)
4505  {
4506  if (qfile_reallocate_tuple (tuple_record_p, tuple_size) != NO_ERROR)
4507  {
4508  return S_ERROR;
4509  }
4510  }
4511  memcpy (tuple_record_p->tpl, scan_id_p->curr_tpl, tuple_size);
4512  }
4513  }
4514  else
4515  {
4516  /* tuple has overflow pages */
4517  if (peek)
4518  {
4519  if (qfile_get_tuple_from_current_list (thread_p, scan_id_p, &scan_id_p->tplrec) != NO_ERROR)
4520  {
4521  return S_ERROR;
4522  }
4523  tuple_record_p->tpl = scan_id_p->tplrec.tpl;
4524  }
4525  else
4526  {
4527  if (qfile_get_tuple_from_current_list (thread_p, scan_id_p, tuple_record_p) != NO_ERROR)
4528  {
4529  return S_ERROR;
4530  }
4531  }
4532  }
4533 
4534  return S_SUCCESS;
4535 }
4536 
4537 /*
4538  * qfile_jump_scan_tuple_position() -
4539  * return: SCAN_CODE (S_SUCCESS, S_END, S_ERROR)
4540  * s_id(in/out): Scan identifier
4541  * ls_tplpos(in): Scan tuple position
4542  * tplrec(in/out): Tuple record descriptor
4543  * peek(in): Peek or Copy Tuple
4544  *
4545  * Note: Jump to the given list file scan position and fetch the tuple
4546  * to the given tuple descriptor, either by peeking or by
4547  * copying depending on the value of the peek parameter.
4548  *
4549  * Note: Saved scan can only be on "ON" or "AFTER" positions.
4550  */
4551 SCAN_CODE
4553  QFILE_TUPLE_POSITION * tuple_position_p, QFILE_TUPLE_RECORD * tuple_record_p, int peek)
4554 {
4555  PAGE_PTR page_p;
4556 
4557  if (tuple_position_p->position == S_ON)
4558  {
4559  if (scan_id_p->position == S_ON)
4560  {
4561  if (scan_id_p->curr_vpid.pageid != tuple_position_p->vpid.pageid
4562  || scan_id_p->curr_vpid.volid != tuple_position_p->vpid.volid)
4563  {
4564  page_p = qmgr_get_old_page (thread_p, &tuple_position_p->vpid, scan_id_p->list_id.tfile_vfid);
4565  if (page_p == NULL)
4566  {
4567  return S_ERROR;
4568  }
4569 
4570  qmgr_free_old_page_and_init (thread_p, scan_id_p->curr_pgptr, scan_id_p->list_id.tfile_vfid);
4571 
4572  QFILE_COPY_VPID (&scan_id_p->curr_vpid, &tuple_position_p->vpid);
4573  scan_id_p->curr_pgptr = page_p;
4574  }
4575  }
4576  else
4577  {
4578  page_p = qmgr_get_old_page (thread_p, &tuple_position_p->vpid, scan_id_p->list_id.tfile_vfid);
4579  if (page_p == NULL)
4580  {
4581  return S_ERROR;
4582  }
4583 
4584  QFILE_COPY_VPID (&scan_id_p->curr_vpid, &tuple_position_p->vpid);
4585  scan_id_p->curr_pgptr = page_p;
4586  }
4587  }
4588  else
4589  {
4590  if (scan_id_p->position == S_ON)
4591  {
4592  qmgr_free_old_page_and_init (thread_p, scan_id_p->curr_pgptr, scan_id_p->list_id.tfile_vfid);
4593  }
4594  }
4595 
4596  scan_id_p->status = tuple_position_p->status;
4597  scan_id_p->position = tuple_position_p->position;
4598  scan_id_p->curr_offset = tuple_position_p->offset;
4599  scan_id_p->curr_tpl = (char *) scan_id_p->curr_pgptr + scan_id_p->curr_offset;
4600  scan_id_p->curr_tplno = tuple_position_p->tplno;
4601 
4602  if (scan_id_p->position == S_ON)
4603  {
4604  return qfile_retrieve_tuple (thread_p, scan_id_p, tuple_record_p, peek);
4605  }
4606  else if (scan_id_p->position == S_BEFORE || scan_id_p->position == S_AFTER)
4607  {
4608  return S_END;
4609  }
4610  else
4611  {
4613  return S_ERROR;
4614  }
4615 }
4616 
4617 /*
4618  * qfile_start_scan_fix () -
4619  * return: int (NO_ERROR or ER_FAILED)
4620  * s_id(in/out): Scan identifier
4621  *
4622  * Note: Start a scan operation which will keep the accessed list file
4623  * pages fixed in the buffer pool. The routine starts the scan
4624  * operation either from the beginning or from the last point
4625  * scan fix ended.
4626  */
4627 int
4629 {
4630  if (scan_id_p->position == S_ON && !scan_id_p->curr_pgptr)
4631  {
4632  scan_id_p->curr_pgptr = qmgr_get_old_page (thread_p, &scan_id_p->curr_vpid, scan_id_p->list_id.tfile_vfid);
4633  if (scan_id_p->curr_pgptr == NULL)
4634  {
4635  return ER_FAILED;
4636  }
4637 
4638  scan_id_p->curr_tpl = (char *) scan_id_p->curr_pgptr + scan_id_p->curr_offset;
4639  }
4640  else
4641  {
4642  scan_id_p->status = S_STARTED;
4643  scan_id_p->position = S_BEFORE;
4644  }
4645 
4646  return NO_ERROR;
4647 }
4648 
4649 /*
4650  * qfile_open_list_scan () -
4651  * return: int (NO_ERROR or ER_FAILED)
4652  * list_id(in): List identifier
4653  * s_id(in/out): Scan identifier
4654  *
4655  * Note: A scan identifier is created to scan through the given list of tuples.
4656  */
4657 int
4659 {
4660  scan_id_p->status = S_OPENED;
4661  scan_id_p->position = S_BEFORE;
4662  scan_id_p->keep_page_on_finish = 0;
4663  scan_id_p->curr_vpid.pageid = NULL_PAGEID;
4664  scan_id_p->curr_vpid.volid = NULL_VOLID;
4665  QFILE_CLEAR_LIST_ID (&scan_id_p->list_id);
4666 
4667  if (qfile_copy_list_id (&scan_id_p->list_id, list_id_p, true) != NO_ERROR)
4668  {
4669  return ER_FAILED;
4670  }
4671 
4672  scan_id_p->tplrec.size = 0;
4673  scan_id_p->tplrec.tpl = NULL;
4674 
4675  return NO_ERROR;
4676 }
4677 
4678 /*
4679  * qfile_scan_list () -
4680  * return: SCAN_CODE (S_SUCCESS, S_END, S_ERROR)
4681  * s_id(in): Scan identifier
4682  * tplrec(in/out): Tuple record descriptor
4683  * peek(in): Peek or Copy Tuple
4684  *
4685  * Note: The regular LIST FILE scan is moved to the next scan tuple and
4686  * the tuple is fetched to the tuple record descriptor. If there
4687  * are no more scan items(tuples), S_END is returned. If
4688  * an error occurs, S_ERROR is returned. If peek is true,
4689  * the tplrec->tpl pointer is directly set to point to scan list
4690  * file page, otherwise the tuple content is copied to the
4691  * tplrec tuple area. If the area inside the tplrec is not enough
4692  * it is reallocated by this routine.
4693  *
4694  * Note1: The pointer set by a PEEK operation is valid until another scan
4695  * operation on the list file or until scan is closed.
4696  *
4697  * Note2: When the PEEK is specified, the area pointed by the tuple must not
4698  * be modified by the caller.
4699  */
4700 static SCAN_CODE
4702  SCAN_CODE (*scan_func) (THREAD_ENTRY * thread_p, QFILE_LIST_SCAN_ID *),
4703  QFILE_TUPLE_RECORD * tuple_record_p, int peek)
4704 {
4705  SCAN_CODE qp_scan;
4706 
4707  qp_scan = (*scan_func) (thread_p, scan_id_p);
4708  if (qp_scan == S_SUCCESS)
4709  {
4710  qp_scan = qfile_retrieve_tuple (thread_p, scan_id_p, tuple_record_p, peek);
4711  }
4712 
4713  return qp_scan;
4714 }
4715 
4716 /*
4717  * qfile_scan_list_next () -
4718  * return: SCAN_CODE (S_SUCCESS, S_END, S_ERROR)
4719  * s_id(in): Scan identifier
4720  * tplrec(in/out): Tuple record descriptor
4721  * peek(in): Peek or Copy Tuple
4722  */
4723 SCAN_CODE
4724 qfile_scan_list_next (THREAD_ENTRY * thread_p, QFILE_LIST_SCAN_ID * scan_id_p, QFILE_TUPLE_RECORD * tuple_record_p,
4725  int peek)
4726 {
4727  return qfile_scan_list (thread_p, scan_id_p, qfile_scan_next, tuple_record_p, peek);
4728 }
4729 
4730 /*
4731  * qfile_scan_list_prev () -
4732  * return: SCAN_CODE (S_SUCCESS, S_END, S_ERROR)
4733  * s_id(in): Scan identifier
4734  * tplrec(in/out): Tuple record descriptor
4735  * peek(in): Peek or Copy Tuple
4736  */
4737 SCAN_CODE
4738 qfile_scan_list_prev (THREAD_ENTRY * thread_p, QFILE_LIST_SCAN_ID * scan_id_p, QFILE_TUPLE_RECORD * tuple_record_p,
4739  int peek)
4740 {
4741  return qfile_scan_list (thread_p, scan_id_p, qfile_scan_prev, tuple_record_p, peek);
4742 }
4743 
4744 /*
4745  * qfile_end_scan_fix () -
4746  * return:
4747  * s_id(in/out) : Scan identifier
4748  *
4749  * Note: End a scan fix operation by freeing the current scan page pointer.
4750  */
4751 void
4753 {
4754  if (scan_id_p->position == S_ON && scan_id_p->curr_pgptr)
4755  {
4756  qmgr_free_old_page_and_init (thread_p, scan_id_p->curr_pgptr, scan_id_p->list_id.tfile_vfid);
4757  }
4758  else
4759  {
4760  scan_id_p->status = S_ENDED;
4761  scan_id_p->position = S_AFTER;
4762  }
4763 }
4764 
4765 /*
4766  * qfile_close_scan () -
4767  * return:
4768  * s_id(in) : Scan identifier
4769  *
4770  * Note: The scan identifier is closed and allocated areas and page
4771  * buffers are freed.
4772  */
4773 void
4775 {
4776  if (scan_id_p->status == S_CLOSED)
4777  {
4778  return;
4779  }
4780 
4781  if ((scan_id_p->position == S_ON || (scan_id_p->position == S_AFTER && scan_id_p->keep_page_on_finish))
4782  && scan_id_p->curr_pgptr)
4783  {
4784  qmgr_free_old_page_and_init (thread_p, scan_id_p->curr_pgptr, scan_id_p->list_id.tfile_vfid);
4785  }
4786 
4787  if (scan_id_p->tplrec.tpl != NULL)
4788  {
4789  db_private_free_and_init (thread_p, scan_id_p->tplrec.tpl);
4790  scan_id_p->tplrec.size = 0;
4791  }
4792 
4793  qfile_clear_list_id (&scan_id_p->list_id);
4794 
4795  scan_id_p->status = S_CLOSED;
4796 }
4797 
4798 #if defined(SERVER_MODE)
4799 /*
4800  * qfile_compare_tran_id () -
4801  * return:
4802  * t1(in) :
4803  * t2(in) :
4804  */
4805 static int
4806 qfile_compare_tran_id (const void *t1, const void *t2)
4807 {
4808  return *((int *) t1) - *((int *) t2);
4809 }
4810 #endif /* SERVER_MODE */
4811 
4812 /*
4813  * qfile_hash_db_value_array () - Hash an array of DB_VALUE (DB_VALUE_ARRAY type)
4814  * return:
4815  * key(in) :
4816  * htsize(in) :
4817  */
4818 static unsigned int
4819 qfile_hash_db_value_array (const void *key, unsigned int htsize)
4820 {
4821  unsigned int hash = 0;
4822  int i;
4823  const DB_VALUE_ARRAY *array = (DB_VALUE_ARRAY *) key;
4824  const DB_VALUE *val;
4825 
4826  if (key != NULL && array->size > 0)
4827  {
4828  for (i = 0, val = array->vals; i < array->size; i++, val++)
4829  {
4830  hash |= mht_valhash (val, htsize);
4831  hash <<= 8;
4832  }
4833  hash |= array->size;
4834  }
4835 
4836  return (hash % htsize);
4837 }
4838 
4839 /*
4840  * qfile_compare_equal_db_value_array () - Compare two arrays of DB_VALUE
4841  * (DB_VALUE_ARRAY type)
4842  * return:
4843  * key1(in) :
4844  * key2(in) :
4845  */
4846 static int
4847 qfile_compare_equal_db_value_array (const void *key1, const void *key2)
4848 {
4849  int i;
4850  const DB_VALUE_ARRAY *array1 = (DB_VALUE_ARRAY *) key1, *array2 = (DB_VALUE_ARRAY *) key2;
4851  const DB_VALUE *val1, *val2;
4852 
4853  if (key1 == key2 || (array1->size == 0 && array2->size == 0))
4854  {
4855  return true;
4856  }
4857 
4858  if (key1 == NULL || key2 == NULL || array1->size != array2->size)
4859  {
4860  return false;
4861  }
4862 
4863  for (i = 0, val1 = array1->vals, val2 = array2->vals; i < array1->size; i += 3, val1 += 3, val2 += 3)
4864  {
4865  if (mht_compare_dbvalues_are_equal (val1, val2) == false)
4866  {
4867  return false;
4868  }
4869  }
4870 
4871  for (i = 1, val1 = array1->vals + 1, val2 = array2->vals + 1; i < array1->size; i += 3, val1 += 3, val2 += 3)
4872  {
4873  if (mht_compare_dbvalues_are_equal (val1, val2) == false)
4874  {
4875  return false;
4876  }
4877  }
4878 
4879  for (i = 2, val1 = array1->vals + 2, val2 = array2->vals + 2; i < array1->size; i += 3, val1 += 3, val2 += 3)
4880  {
4881  if (mht_compare_dbvalues_are_equal (val1, val2) == false)
4882  {
4883  return false;
4884  }
4885  }
4886 
4887  return true;
4888 }
4889 
4890 /*
4891  * qfile_initialize_list_cache () - Initialize list cache
4892  * return:
4893  */
4894 int
4896 {
4897  unsigned int i;
4898  int n;
4900 
4902  {
4903  return NO_ERROR;
4904  }
4905 
4907  {
4908  return ER_FAILED;
4909  }
4910 
4911  /* array of memory hash tables for list cache; pool for list_ht of QFILE_LIST_CACHE_ENTRY */
4912  if (qfile_List_cache.list_hts)
4913  {
4914  /* if the hash table already exist, clear it out */
4915  for (i = 0; i < qfile_List_cache.n_hts; i++)
4916  {
4917  (void) mht_map_no_key (thread_p, qfile_List_cache.list_hts[i], qfile_free_list_cache_entry,
4918  qfile_List_cache.list_hts[i]);
4919  (void) mht_clear (qfile_List_cache.list_hts[i], NULL, NULL);
4920  }
4921  }
4922  else
4923  {
4924  /* create */
4925  qfile_List_cache.n_hts = prm_get_integer_value (PRM_ID_XASL_CACHE_MAX_ENTRIES) + 10;
4926  qfile_List_cache.list_hts = (MHT_TABLE **) calloc (qfile_List_cache.n_hts, sizeof (MHT_TABLE *));
4927  if (qfile_List_cache.list_hts == NULL)
4928  {
4929  goto error;
4930  }
4931 
4932  for (i = 0; i < qfile_List_cache.n_hts; i++)
4933  {
4934  qfile_List_cache.list_hts[i] =
4935  mht_create ("list file cache (DB_VALUE list)", prm_get_integer_value (PRM_ID_LIST_MAX_QUERY_CACHE_ENTRIES),
4937  if (qfile_List_cache.list_hts[i] == NULL)
4938  {
4939  goto error;
4940  }
4941  }
4942  }
4943 
4944  qfile_List_cache.n_entries = 0;
4945  qfile_List_cache.n_pages = 0;
4946  qfile_List_cache.lookup_counter = 0;
4947  qfile_List_cache.hit_counter = 0;
4948  qfile_List_cache.miss_counter = 0;
4949  qfile_List_cache.full_counter = 0;
4950 
4951  /* list cache entry pool */
4952  if (qfile_List_cache_entry_pool.pool)
4953  {
4954  free_and_init (qfile_List_cache_entry_pool.pool);
4955  }
4956 
4957  qfile_List_cache_entry_pool.n_entries = prm_get_integer_value (PRM_ID_LIST_MAX_QUERY_CACHE_ENTRIES) + 10;
4958  qfile_List_cache_entry_pool.pool =
4959  (QFILE_POOLED_LIST_CACHE_ENTRY *) calloc (qfile_List_cache_entry_pool.n_entries,
4961  if (qfile_List_cache_entry_pool.pool == NULL)
4962  {
4963  goto error;
4964  }
4965 
4966  qfile_List_cache_entry_pool.free_list = 0;
4967  for (pent = qfile_List_cache_entry_pool.pool, n = 0; pent && n < qfile_List_cache_entry_pool.n_entries - 1;
4968  pent++, n++)
4969  {
4970  pent->s.next = n + 1;
4971  }
4972 
4973  if (pent != NULL)
4974  {
4975  pent->s.next = -1;
4976  }
4977 
4978  csect_exit (thread_p, CSECT_QPROC_LIST_CACHE);
4979 
4980  return NO_ERROR;
4981 
4982 error:
4983  if (qfile_List_cache_entry_pool.pool)
4984  {
4985  free_and_init (qfile_List_cache_entry_pool.pool);
4986  }
4987  qfile_List_cache_entry_pool.n_entries = 0;
4988  qfile_List_cache_entry_pool.free_list = -1;
4989 
4990  if (qfile_List_cache.list_hts)
4991  {
4992  for (i = 0; i < qfile_List_cache.n_hts && qfile_List_cache.list_hts[i]; i++)
4993  {
4994  mht_destroy (qfile_List_cache.list_hts[i]);
4995  }
4996  free_and_init (qfile_List_cache.list_hts);
4997  }
4998  qfile_List_cache.n_hts = 0;
4999 
5000  csect_exit (thread_p, CSECT_QPROC_LIST_CACHE);
5001 
5002  return ER_FAILED;
5003 }
5004 
5005 /*
5006  * qfile_finalize_list_cache () - Finalize list cache
5007  * return:
5008  */
5009 int
5011 {
5012  unsigned int i;
5013 
5015  {
5016  return NO_ERROR;
5017  }
5018 
5020  {
5021  return ER_FAILED;
5022  }
5023 
5024  /* array of memory hash tables for list cache; pool for list_ht of QFILE_LIST_CACHE_ENTRY */
5025  if (qfile_List_cache.list_hts)
5026  {
5027  for (i = 0; i < qfile_List_cache.n_hts; i++)
5028  {
5029  bool del = true;
5030  (void) mht_map_no_key (thread_p, qfile_List_cache.list_hts[i], qfile_end_use_of_list_cache_entry_local, &del);
5031  mht_destroy (qfile_List_cache.list_hts[i]);
5032  }
5033  free_and_init (qfile_List_cache.list_hts);
5034  }
5035 
5036  /* list cache entry pool */
5037  if (qfile_List_cache_entry_pool.pool)
5038  {
5039  free_and_init (qfile_List_cache_entry_pool.pool);
5040  }
5041 
5042  csect_exit (thread_p, CSECT_QPROC_LIST_CACHE);
5043 
5044  return NO_ERROR;
5045 }
5046 
5047 /*
5048  * qfile_clear_list_cache () - Clear out list cache hash table
5049  * return:
5050  * list_ht_no(in) :
5051  */
5052 int
5053 qfile_clear_list_cache (THREAD_ENTRY * thread_p, int list_ht_no)
5054 {
5055  int rc;
5056  bool del = true;
5057  int cnt;
5058 
5060  {
5061  return ER_FAILED;
5062  }
5063 
5064  if (qfile_List_cache.n_hts == 0)
5065  {
5066  return ER_FAILED;
5067  }
5068 
5070  {
5071  return ER_FAILED;
5072  }
5073 
5074  cnt = 0;
5075  do
5076  {
5077  rc =
5078  mht_map_no_key (thread_p, qfile_List_cache.list_hts[list_ht_no], qfile_end_use_of_list_cache_entry_local, &del);
5079  if (rc != NO_ERROR)
5080  {
5081  csect_exit (thread_p, CSECT_QPROC_LIST_CACHE);
5082  thread_sleep (10); /* 10 msec */
5084  {
5085  return ER_FAILED;
5086  }
5087  }
5088  }
5089  while (rc != NO_ERROR && cnt++ < 10);
5090 
5091  if (rc != NO_ERROR)
5092  {
5093  /* unhappy condition; if this happens, memory leak will occurrs */
5094  er_log_debug (ARG_FILE_LINE, "ls_clear_list_cache: failed to delete all entries\n");
5095  }
5096 
5097  if (qfile_get_list_cache_number_of_entries (list_ht_no) == 0)
5098  {
5099  (void) mht_clear (qfile_List_cache.list_hts[list_ht_no], NULL, NULL);
5100  }
5101 
5102  csect_exit (thread_p, CSECT_QPROC_LIST_CACHE);
5103 
5104  return NO_ERROR;
5105 }
5106 
5107 /*
5108  * qfile_allocate_list_cache_entry () - Allocate the entry or get one from the pool
5109  * return:
5110  * req_size(in) :
5111  */
5112 static QFILE_LIST_CACHE_ENTRY *
5114 {
5115  /* this function should be called within CSECT_QPROC_LIST_CACHE */
5117 
5118  if (req_size > RESERVED_SIZE_FOR_LIST_CACHE_ENTRY || qfile_List_cache_entry_pool.free_list == -1)
5119  {
5120  /* malloc from the heap if required memory size is bigger than reserved, or the pool is exhausted */
5122  if (pent != NULL)
5123  {
5124  /* mark as to be freed rather than returning back to the pool */
5125  pent->s.next = -2;
5126  }
5127  else
5128  {
5129  er_log_debug (ARG_FILE_LINE, "ls_alloc_list_cache_ent: allocation failed\n");
5130  }
5131  }
5132  else
5133  {
5134  /* get one from the pool */
5135  assert ((qfile_List_cache_entry_pool.free_list <= qfile_List_cache_entry_pool.n_entries)
5136  && (qfile_List_cache_entry_pool.free_list >= 0));
5137  pent = &qfile_List_cache_entry_pool.pool[qfile_List_cache_entry_pool.free_list];
5138 
5139  assert (pent->s.next <= qfile_List_cache_entry_pool.n_entries && pent->s.next >= -1);
5140  qfile_List_cache_entry_pool.free_list = pent->s.next;
5141  pent->s.next = -1;
5142  }
5143 
5144  /* initialize */
5145  if (pent)
5146  {
5147  assert (sizeof (pent->s.entry) >= sizeof (QFILE_LIST_CACHE_ENTRY));
5148 
5149  (void) memset ((void *) &pent->s.entry, 0, sizeof (QFILE_LIST_CACHE_ENTRY));
5150  }
5151  else
5152  {
5153  return NULL;
5154  }
5155 
5156  return &pent->s.entry;
5157 }
5158 
5159 /*
5160  * qfile_free_list_cache_entry () - Remove the entry from the hash and free it
5161  * Can be used by mht_map_no_key() function
5162  * return:
5163  * data(in) :
5164  * args(in) :
5165  */
5166 static int
5167 qfile_free_list_cache_entry (THREAD_ENTRY * thread_p, void *data, void *args)
5168 {
5169  /* this function should be called within CSECT_QPROC_LIST_CACHE */
5172  HL_HEAPID old_pri_heap_id;
5173  int i;
5174 #if !defined (NDEBUG)
5175  int idx;
5176 #endif
5177 
5178  if (data == NULL)
5179  {
5180  return ER_FAILED;
5181  }
5182 
5183  /*
5184  * Clear out parameter values. (DB_VALUE containers)
5185  * Remind that the parameter values are cloned in global heap context(0)
5186  */
5187  old_pri_heap_id = db_change_private_heap (thread_p, 0);
5188  for (i = 0; i < lent->param_values.size; i++)
5189  {
5190  (void) pr_clear_value (&lent->param_values.vals[i]);
5191  }
5192  (void) db_change_private_heap (thread_p, old_pri_heap_id);
5193 
5194  /* if this entry is from the pool return it, else free it */
5196  if (pent->s.next == -2)
5197  {
5198  free_and_init (pent);
5199  }
5200  else
5201  {
5202  /* return it back to the pool */
5203  (void) memset (&pent->s.entry, 0, sizeof (QFILE_LIST_CACHE_ENTRY));
5204  pent->s.next = qfile_List_cache_entry_pool.free_list;
5205 
5206 #if !defined (NDEBUG)
5207  idx = (int) (pent - qfile_List_cache_entry_pool.pool);
5208  assert (idx <= qfile_List_cache_entry_pool.n_entries && idx >= 0);
5209 #endif
5210 
5211  qfile_List_cache_entry_pool.free_list = CAST_BUFLEN (pent - qfile_List_cache_entry_pool.pool);
5212  }
5213 
5214  return NO_ERROR;
5215 }
5216 
5217 /*
5218  * qfile_print_list_cache_entry () - Print the entry
5219  * Will be used by mht_dump() function
5220  * return:
5221  * fp(in) :
5222  * key(in) :
5223  * data(in) :
5224  * args(in) :
5225  */
5226 static int
5227 qfile_print_list_cache_entry (THREAD_ENTRY * thread_p, FILE * fp, const void *key, void *data, void *args)
5228 {
5230  int i;
5231  char str[20];
5232  TP_DOMAIN **d;
5233  time_t tmp_time;
5234  struct tm *c_time_struct, tm_val;
5235 
5236  if (!ent)
5237  {
5238  return false;
5239  }
5240  if (fp == NULL)
5241  {
5242  fp = stdout;
5243  }
5244 
5245  fprintf (fp, "LIST_CACHE_ENTRY (%p) {\n", data);
5246  fprintf (fp, " param_values = [");
5247 
5248  for (i = 0; i < ent->param_values.size; i++)
5249  {
5250  fprintf (fp, " ");
5251  db_fprint_value (fp, &ent->param_values.vals[i]);
5252  }
5253 
5254  fprintf (fp, " ]\n");
5255  fprintf (fp, " list_id = { type_list { %d", ent->list_id.type_list.type_cnt);
5256 
5257  for (i = 0, d = ent->list_id.type_list.domp; i < ent->list_id.type_list.type_cnt && d && *d; i++, d++)
5258  {
5259  fprintf (fp, " %s/%d", (*d)->type->name, TP_DOMAIN_TYPE ((*d)));
5260  }
5261 
5262  fprintf (fp,
5263  " } tuple_cnt %d page_cnt %d first_vpid { %d %d } last_vpid { %d %d } lasttpl_len %d query_id %lld "
5264  " temp_vfid { %d %d } }\n", ent->list_id.tuple_cnt, ent->list_id.page_cnt, ent->list_id.first_vpid.pageid,
5266  ent->list_id.lasttpl_len, (long long) ent->list_id.query_id, ent->list_id.temp_vfid.fileid,
5267  ent->list_id.temp_vfid.volid);
5268 
5269 #if defined(SERVER_MODE)
5270  fprintf (fp, " tran_isolation = %d\n", ent->tran_isolation);
5271  fprintf (fp, " tran_index_array = [");
5272 
5273  for (i = 0; (unsigned int) i < ent->last_ta_idx; i++)
5274  {
5275  fprintf (fp, " %d", ent->tran_index_array[i]);
5276  }
5277 
5278  fprintf (fp, " ]\n");
5279  fprintf (fp, " last_ta_idx = %lld\n", (long long) ent->last_ta_idx);
5280 #endif /* SERVER_MODE */
5281 
5282  fprintf (fp, " query_string = %s\n", ent->query_string);
5283 
5284  tmp_time = ent->time_created.tv_sec;
5285  c_time_struct = localtime_r (&tmp_time, &tm_val);
5286  if (c_time_struct == NULL)
5287  {
5288  fprintf (fp, " ent->time_created.tv_sec is invalid (%ld)\n", ent->time_last_used.tv_sec);
5289  }
5290  else
5291  {
5292  (void) strftime (str, sizeof (str), "%x %X", c_time_struct);
5293  fprintf (fp, " time_created = %s.%d\n", str, (int) ent->time_created.tv_usec);
5294  }
5295 
5296  tmp_time = ent->time_last_used.tv_sec;
5297  c_time_struct = localtime_r (&tmp_time, &tm_val);
5298  if (c_time_struct == NULL)
5299  {
5300  fprintf (fp, " ent->time_last_used.tv_sec is invalid (%ld)\n", ent->time_last_used.tv_sec);
5301  }
5302  else
5303  {
5304  (void) strftime (str, sizeof (str), "%x %X", c_time_struct);
5305  fprintf (fp, " time_last_used = %s.%d\n", str, (int) ent->time_last_used.tv_usec);
5306 
5307  fprintf (fp, " ref_count = %d\n", ent->ref_count);
5308  fprintf (fp, " deletion_marker = %s\n", (ent->deletion_marker) ? "true" : "false");
5309  fprintf (fp, "}\n");
5310  }
5311 
5312  return true;
5313 }
5314 
5315 /*
5316  * qfile_dump_list_cache_internal () -
5317  * return:
5318  * fp(in) :
5319  */
5320 int
5322 {
5323  unsigned int i;
5324 
5326  {
5327  return ER_FAILED;
5328  }
5329 
5330  if (!fp)
5331  {
5332  fp = stdout;
5333  }
5334 
5335  fprintf (fp,
5336  "LIST_CACHE {\n n_hts %d\n n_entries %d n_pages %d\n"
5337  " lookup_counter %d\n hit_counter %d\n miss_counter %d\n full_counter %d\n}\n",
5338  qfile_List_cache.n_hts, qfile_List_cache.n_entries, qfile_List_cache.n_pages,
5339  qfile_List_cache.lookup_counter, qfile_List_cache.hit_counter, qfile_List_cache.miss_counter,
5340  qfile_List_cache.full_counter);
5341 
5342  for (i = 0; i < qfile_List_cache.n_hts; i++)
5343  {
5344  if (mht_count (qfile_List_cache.list_hts[i]) > 0)
5345  {
5346  fprintf (fp, "\nlist_hts[%d] %p\n", i, (void *) qfile_List_cache.list_hts[i]);
5347  (void) mht_dump (thread_p, fp, qfile_List_cache.list_hts[i], true, qfile_print_list_cache_entry, NULL);
5348  }
5349  }
5350 
5351  csect_exit (thread_p, CSECT_QPROC_LIST_CACHE);
5352 
5353  return NO_ERROR;
5354 }
5355 
5356 #if defined (CUBRID_DEBUG)
5357 /*
5358  * qfile_dump_list_cache () -
5359  * return:
5360  * fname(in) :
5361  */
5362 int
5363 qfile_dump_list_cache (THREAD_ENTRY * thread_p, const char *fname)
5364 {
5365  int rc;
5366  FILE *fp;
5367 
5369  {
5370  return ER_FAILED;
5371  }
5372 
5373  if (qfile_List_cache.n_hts == 0 || !qfile_List_cache.list_hts)
5374  {
5375  return ER_FAILED;
5376  }
5377 
5378  fp = (fname) ? fopen (fname, "a") : stdout;
5379  if (!fp)
5380  {
5381  fp = stdout;
5382  }
5383 
5384  rc = qfile_dump_list_cache_internal (thread_p, fp);
5385 
5386  if (fp != stdout)
5387  {
5388  fclose (fp);
5389  }
5390 
5391  return rc;
5392 }
5393 #endif
5394 
5395 /*
5396  * qfile_delete_list_cache_entry () - Delete a list cache entry
5397  * Can be used by mht_map_no_key() function
5398  * return:
5399  * data(in/out) :
5400  * args(in) :
5401  */
5402 static int
5404 {
5405  /* this function should be called within CSECT_QPROC_LIST_CACHE */
5407  int error_code = ER_FAILED;
5408 
5409  if (data == NULL || lent->list_ht_no < 0)
5410  {
5411  return ER_FAILED;
5412  }
5413 
5414  /* update counter */
5415  qfile_List_cache.n_entries--;
5416  qfile_List_cache.n_pages -= lent->list_id.page_cnt;
5417 
5418  /* remove the entry from the hash table */
5419  if (mht_rem2 (qfile_List_cache.list_hts[lent->list_ht_no], &lent->param_values, lent, NULL, NULL) != NO_ERROR)
5420  {
5421  if (!lent->deletion_marker)
5422  {
5423  char *s = NULL;
5424 
5425  if (lent->param_values.size > 0)
5426  {
5427  s = pr_valstring (&lent->param_values.vals[0]);
5428  }
5429 
5431  "ls_delete_list_cache_ent: mht_rem failed for param_values { %d %s ...}\n",
5432  lent->param_values.size, s ? s : "(null)");
5433  if (s)
5434  {
5435  db_private_free (thread_p, s);
5436  }
5437  }
5438  }
5439 
5440  /* destroy the temp file of XASL_ID */
5441  if (!VFID_ISNULL (&lent->list_id.temp_vfid)
5442  && file_temp_retire_preserved (thread_p, &lent->list_id.temp_vfid) != NO_ERROR)
5443  {
5444  er_log_debug (ARG_FILE_LINE, "ls_delete_list_cache_ent: fl_destroy failed for vfid { %d %d }\n",
5446  }
5447 
5448  /* clear list_id */
5449  qfile_update_qlist_count (thread_p, &lent->list_id, 1);
5450  qfile_clear_list_id (&lent->list_id);
5451 
5452  error_code = qfile_free_list_cache_entry (thread_p, lent, NULL);
5453 
5454  return error_code;
5455 }
5456 
5457 /*
5458  * qfile_end_use_of_list_cache_entry_local () -
5459  * return:
5460  * data(in) :
5461  * args(in) :
5462  */
5463 static int
5464 qfile_end_use_of_list_cache_entry_local (THREAD_ENTRY * thread_p, void *data, void *args)
5465 {
5466  return qfile_end_use_of_list_cache_entry (thread_p, (QFILE_LIST_CACHE_ENTRY *) data, *((bool *) args));
5467 }
5468 
5469 /*
5470  * qfile_lookup_list_cache_entry () - Lookup the list cache with the parameter
5471  * values (DB_VALUE array) bound to the query
5472  * return:
5473  * list_ht_no(in) :
5474  * params(in) :
5475  *
5476  * Note: Look up the hash table to get the cached result with the parameter
5477  * values as the key.
5478  */
5480 qfile_lookup_list_cache_entry (THREAD_ENTRY * thread_p, int list_ht_no, const DB_VALUE_ARRAY * params,
5481  bool * result_cached)
5482 {
5483  QFILE_LIST_CACHE_ENTRY *lent;
5484  int tran_index;
5485 #if defined(SERVER_MODE)
5486  TRAN_ISOLATION tran_isolation;
5487 #if defined(WINDOWS)
5488  unsigned int num_elements;
5489 #else
5490  size_t num_elements;
5491 #endif
5492 #endif /* SERVER_MODE */
5493 #if defined (SERVER_MODE) && !defined (NDEBUG)
5494  size_t i_idx, num_active_users;
5495 #endif
5496 
5497  bool new_tran = true;
5498 
5499  *result_cached = false;
5500 
5502  {
5503  return NULL;
5504  }
5505  if (qfile_List_cache.n_hts == 0 || list_ht_no < 0)
5506  {
5507  return NULL;
5508  }
5509 
5511  {
5512  return NULL;
5513  }
5514 
5515  tran_index = LOG_FIND_THREAD_TRAN_INDEX (thread_p);
5516 
5517  /* look up the hash table with the key */
5518  lent = (QFILE_LIST_CACHE_ENTRY *) mht_get (qfile_List_cache.list_hts[list_ht_no], params);
5519  qfile_List_cache.lookup_counter++; /* counter */
5520 
5521  if (lent)
5522  {
5523  unsigned int i;
5524 
5525  /* check if it is marked to be deleted */
5526  if (lent->deletion_marker)
5527  {
5528 #if defined(SERVER_MODE)
5529  if (lent->last_ta_idx == 0)
5530 #endif
5531  {
5532  qfile_delete_list_cache_entry (thread_p, lent);
5533  }
5534  goto end;
5535  }
5536 
5537  *result_cached = true;
5538 
5539 #if defined(SERVER_MODE)
5540  /* check if the cache is owned by me */
5541  for (i = 0; i < lent->last_ta_idx; i++)
5542  {
5543  if (lent->tran_index_array[i] == tran_index)
5544  {
5545  new_tran = false;
5546  break;
5547  }
5548  }
5549 
5550  /* finally, we found an useful cache entry to reuse */
5551  if (new_tran)
5552  {
5553  /* record my transaction id into the entry and adjust timestamp and reference counter */
5554  lent->uncommitted_marker = true;
5555  if (lent->last_ta_idx < (size_t) MAX_NTRANS)
5556  {
5557  num_elements = (int) lent->last_ta_idx;
5558  (void) lsearch (&tran_index, lent->tran_index_array, &num_elements, sizeof (int), qfile_compare_tran_id);
5559  lent->last_ta_idx = num_elements;
5560  }
5561 #if !defined (NDEBUG)
5562  for (i_idx = 0, num_active_users = 0; i_idx < lent->last_ta_idx; i_idx++)
5563  {
5564  if (lent->tran_index_array[i_idx] > 0)
5565  {
5566  num_active_users++;
5567  }
5568  }
5569  assert (lent->last_ta_idx == num_active_users);
5570 #endif
5571  }
5572 #endif /* SERVER_MODE */
5573 
5574  (void) gettimeofday (&lent->time_last_used, NULL);
5575  lent->ref_count++;
5576  }
5577 
5578 end:
5579 
5580  if (*result_cached)
5581  {
5582  qfile_List_cache.hit_counter++; /* counter */
5583  }
5584  else
5585  {
5586  qfile_List_cache.miss_counter++; /* counter */
5587  }
5588 
5589  csect_exit (thread_p, CSECT_QPROC_LIST_CACHE);
5590 
5591  if (*result_cached)
5592  {
5593  return lent;
5594  }
5595 
5596  return NULL;
5597 }
5598 
5599 static bool
5600 qfile_is_early_time (struct timeval *a, struct timeval *b)
5601 {
5602  if (a->tv_sec == b->tv_sec)
5603  {
5604  return a->tv_usec < b->tv_usec;
5605  }
5606  else
5607  {
5608  return a->tv_sec < b->tv_sec;
5609  }
5610 }
5611 
5612 /*
5613  * qfile_update_list_cache_entry () - Update list cache entry if exist or create new
5614  * one
5615  * return:
5616  * list_ht_no_ptr(in/out) :
5617  * params(in) :
5618  * list_id(in) :
5619  * query_string(in) :
5620  *
5621  * Note: Put the query result into the proper hash table with the key of
5622  * the parameter values (DB_VALUE array) and the data of LIST ID.
5623  * If there already exists the entry with the same key, update its data.
5624  * As a side effect, the given 'list_hash_no' will be change if it was -1.
5625  */
5627 qfile_update_list_cache_entry (THREAD_ENTRY * thread_p, int list_ht_no, const DB_VALUE_ARRAY * params,
5628  const QFILE_LIST_ID * list_id, XASL_CACHE_ENTRY * xasl)
5629 {
5630  QFILE_LIST_CACHE_ENTRY *lent, *old, **p, **q, **r;
5631  MHT_TABLE *ht;
5632  int tran_index;
5633 #if defined(SERVER_MODE)
5634  TRAN_ISOLATION tran_isolation;
5635 #if defined(WINDOWS)
5636  unsigned int num_elements;
5637 #else
5638  size_t num_elements;
5639 #endif
5640 #if !defined (NDEBUG)
5641  size_t i_idx, num_active_users;
5642 #endif
5643 #endif /* SERVER_MODE */
5644  unsigned int n;
5645  HL_HEAPID old_pri_heap_id;
5646  int i, j, k;
5647  int alloc_size;
5648 
5650  {
5651  return NULL;
5652  }
5653  if (qfile_List_cache.n_hts == 0)
5654  {
5655  return NULL;
5656  }
5657 
5659  {
5660  return NULL;
5661  }
5662 
5663  tran_index = LOG_FIND_THREAD_TRAN_INDEX (thread_p);
5664 #if defined(SERVER_MODE)
5665  tran_isolation = logtb_find_isolation (tran_index);
5666 #endif /* SERVER_MODE */
5667 
5668  /*
5669  * The other competing thread which is running the same query
5670  * already updated this entry after that this and the thread had failed
5671  * to find the query in the cache.
5672  * The other case is that the query could be marked not to look up
5673  * the cache but update the cache with its result.
5674  * Then, try to delete the previous one and insert new one.
5675  * If fail to delete, leave the cache without touch.
5676  */
5677 
5678  ht = qfile_List_cache.list_hts[list_ht_no];
5679  do
5680  {
5681  /* check again whether the entry is in the cache */
5682  lent = (QFILE_LIST_CACHE_ENTRY *) mht_get (ht, params);
5683  if (lent == NULL)
5684  {
5685  break;
5686  }
5687 
5688 #if defined(SERVER_MODE)
5689  /* check in-use by other transaction */
5690  if (lent->last_ta_idx > 0)
5691  {
5692  csect_exit (thread_p, CSECT_QPROC_LIST_CACHE);
5693  return lent;
5694  }
5695 
5696  /* the entry that is in the cache is same with mine; do not duplicate the cache entry */
5697  /* record my transaction id into the entry and adjust timestamp and reference counter */
5698  if (lent->last_ta_idx < (size_t) MAX_NTRANS)
5699  {
5700  num_elements = (int) lent->last_ta_idx;
5701  (void) lsearch (&tran_index, lent->tran_index_array, &num_elements, sizeof (int), qfile_compare_tran_id);
5702  lent->last_ta_idx = num_elements;
5703  }
5704 
5705 #if !defined (NDEBUG)
5706  for (i_idx = 0, num_active_users = 0; i_idx < lent->last_ta_idx; i_idx++)
5707  {
5708  if (lent->tran_index_array[i_idx] > 0)
5709  {
5710  num_active_users++;
5711  }
5712  }
5713 
5714  assert (lent->last_ta_idx == num_active_users);
5715 #endif
5716 
5717  (void) gettimeofday (&lent->time_last_used, NULL);
5718  lent->ref_count++;
5719 
5720 #endif /* SERVER_MODE */
5721  }
5722  while (0);
5723 
5724  /* return with the one from the cache */
5725  if (lent != NULL)
5726  {
5727  goto end;
5728  }
5729 
5730 #if defined(SERVER_MODE)
5731  /* check the number of list cache entries */
5734  {
5735  if (qfile_list_cache_cleanup (thread_p) != NO_ERROR)
5736  {
5737  goto end;
5738  }
5739  }
5740 #endif
5741 
5742  /* make new QFILE_LIST_CACHE_ENTRY */
5743 
5744  /* get new entry from the QFILE_LIST_CACHE_ENTRY_POOL */
5745  alloc_size = qfile_get_list_cache_entry_size_for_allocate (params->size);
5746  lent = qfile_allocate_list_cache_entry (alloc_size);
5747  if (lent == NULL)
5748  {
5749  goto end;
5750  }
5751 
5752  lent->list_ht_no = list_ht_no;
5753 #if defined(SERVER_MODE)
5754  lent->uncommitted_marker = true;
5755  lent->tran_isolation = tran_isolation;
5756  lent->last_ta_idx = 0;
5757  lent->tran_index_array =
5758  (int *) memset (qfile_get_list_cache_entry_tran_index_array (lent), 0, MAX_NTRANS * sizeof (int));
5759 #endif /* SERVER_MODE */
5760  lent->param_values.size = params->size;
5762 
5763  /*
5764  * Copy parameter values. (DB_VALUE containers)
5765  * Changing private heap to the global one (0, malloc/free) is
5766  * needed because cloned db values last beyond request processing time
5767  * boundary.
5768  */
5769  old_pri_heap_id = db_change_private_heap (thread_p, 0);
5770  for (i = 0; i < lent->param_values.size; i++)
5771  {
5772  /* (void) pr_clear_value(&(lent->param_values.vals[i])); */
5773  (void) pr_clone_value (&params->vals[i], &lent->param_values.vals[i]);
5774  }
5775  (void) db_change_private_heap (thread_p, old_pri_heap_id);
5776 
5777  /* copy the QFILE_LIST_ID */
5778  if (qfile_copy_list_id (&lent->list_id, list_id, false) != NO_ERROR)
5779  {
5780  qfile_delete_list_cache_entry (thread_p, lent);
5781  lent = NULL;
5782  goto end;
5783  }
5784  lent->list_id.tfile_vfid = NULL;
5785  lent->query_string = xasl->sql_info.sql_hash_text;
5786  (void) gettimeofday (&lent->time_created, NULL);
5787  (void) gettimeofday (&lent->time_last_used, NULL);
5788  lent->ref_count = 0;
5789  lent->deletion_marker = false;
5790  lent->xcache_entry = xasl;
5791 
5792  /* record my transaction id into the entry */
5793 #if defined(SERVER_MODE)
5794  if (lent->last_ta_idx < (size_t) MAX_NTRANS)
5795  {
5796  num_elements = (int) lent->last_ta_idx;
5797  (void) lsearch (&tran_index, lent->tran_index_array, &num_elements, sizeof (int), qfile_compare_tran_id);
5798  lent->last_ta_idx = num_elements;
5799  }
5800 
5801 #if !defined (NDEBUG)
5802  for (i_idx = 0, num_active_users = 0; i_idx < lent->last_ta_idx; i_idx++)
5803  {
5804  if (lent->tran_index_array[i_idx] > 0)
5805  {
5806  num_active_users++;
5807  }
5808  }
5809 
5810  assert (lent->last_ta_idx == num_active_users);
5811 #endif
5812 
5813 #endif /* SERVER_MODE */
5814 
5815  /* insert (or update) the entry into the hash table */
5816  if (mht_put_new (ht, &lent->param_values, lent) == NULL)
5817  {
5818  char *s;
5819 
5820  s = ((lent->param_values.size > 0) ? pr_valstring (&lent->param_values.vals[0]) : NULL);
5821  er_log_debug (ARG_FILE_LINE, "ls_update_list_cache_ent: mht_rem failed for param_values { %d %s ...}\n",
5822  lent->param_values.size, s ? s : "(null)");
5823  if (s)
5824  {
5825  db_private_free (thread_p, s);
5826  }
5827  qfile_delete_list_cache_entry (thread_p, lent);
5828  lent = NULL;
5829  goto end;
5830  }
5831 
5832  /* update counter */
5833  qfile_List_cache.n_entries++;
5834  qfile_List_cache.n_pages += lent->list_id.page_cnt;
5835 
5836 end:
5837  csect_exit (thread_p, CSECT_QPROC_LIST_CACHE);
5838 
5839  return lent;
5840 }
5841 
5842 /*
5843  * qfile_end_use_of_list_cache_entry () - End use of list cache entry
5844  * return:
5845  * lent(in/out) :
5846  * marker(in) :
5847  */
5848 int
5850 {
5851  int tran_index;
5852 #if defined(SERVER_MODE)
5853  int *p, *r;
5854 #if defined(WINDOWS)
5855  unsigned int num_elements;
5856 #else
5857  size_t num_elements;
5858 #endif
5859 #endif /* SERVER_MODE */
5860 #if defined (SERVER_MODE) && !defined (NDEBUG)
5861  size_t i_idx, num_active_users;
5862 #endif
5863 
5865  {
5866  return ER_FAILED;
5867  }
5868  if (lent == NULL || qfile_List_cache.n_hts == 0)
5869  {
5870  return ER_FAILED;
5871  }
5872 
5874  {
5875  return ER_FAILED;
5876  }
5877 
5878 #if defined(SERVER_MODE)
5879  /* remove my transaction id from the entry and do compaction */
5880  tran_index = LOG_FIND_THREAD_TRAN_INDEX (thread_p);
5881  r = &lent->tran_index_array[lent->last_ta_idx];
5882  do
5883  {
5884  /* find my tran_id */
5885  num_elements = (int) lent->last_ta_idx;
5886  p = (int *) lfind (&tran_index, lent->tran_index_array, &num_elements, sizeof (int), qfile_compare_tran_id);
5887  lent->last_ta_idx = num_elements;
5888  if (p)
5889  {
5890  *p = 0;
5891  /* do compaction */
5892  if (p + 1 < r)
5893  {
5894  (void) memcpy (p, p + 1, sizeof (int) * (r - p - 1));
5895  }
5896  lent->last_ta_idx--;
5897  r--;
5898  }
5899  }
5900  while (p && p < r);
5901 
5902  if (lent->last_ta_idx == 0)
5903  {
5904  lent->uncommitted_marker = false;
5905  }
5906 
5907 #if !defined (NDEBUG)
5908  for (i_idx = 0, num_active_users = 0; i_idx < lent->last_ta_idx; i_idx++)
5909  {
5910  if (lent->tran_index_array[i_idx] > 0)
5911  {
5912  num_active_users++;
5913  }
5914  }
5915 
5916  assert (lent->last_ta_idx == num_active_users);
5917 #endif
5918 
5919 #endif /* SERVER_MODE */
5920 
5921  /* if this entry will be deleted */
5922 #if defined(SERVER_MODE)
5923  if (lent->last_ta_idx == 0)
5924 #endif
5925  {
5926  /* to check if it's the last transaction using the lent */
5927  if (marker || lent->deletion_marker)
5928  {
5929  qfile_delete_list_cache_entry (thread_p, lent);
5930  }
5931  }
5932 #if defined(SERVER_MODE)
5933  else
5934  {
5935  /* to avoid resetting the deletion_marker
5936  * that has already been set by other transaction */
5937  if (lent->deletion_marker == false)
5938  {
5939  lent->deletion_marker = marker;
5940  }
5941  }
5942 #endif
5943 
5944  csect_exit (thread_p, CSECT_QPROC_LIST_CACHE);
5945 
5946  return NO_ERROR;
5947 }
5948 
5949 static int
5951 {
5952 #if defined(SERVER_MODE)
5953  return sizeof (QFILE_LIST_CACHE_ENTRY) /* space for structure */
5954  + sizeof (int) * MAX_NTRANS /* space for tran_index_array */
5955  + sizeof (DB_VALUE) * nparam; /* space for param_values.vals */
5956 #else /* SERVER_MODE */
5957  return sizeof (QFILE_LIST_CACHE_ENTRY) /* space for structure */
5958  + sizeof (DB_VALUE) * nparam; /* space for param_values.vals */
5959 #endif /* SERVER_MODE */
5960 }
5961 
5962 #if defined(SERVER_MODE)
5963 static int *
5964 qfile_get_list_cache_entry_tran_index_array (QFILE_LIST_CACHE_ENTRY * ent)
5965 {
5966  return (int *) ((char *) ent + sizeof (QFILE_LIST_CACHE_ENTRY));
5967 }
5968 #endif /* SERVER_MODE */
5969 
5970 static DB_VALUE *
5972 {
5973 #if defined(SERVER_MODE)
5974  return (DB_VALUE *) ((char *) ent + sizeof (QFILE_LIST_CACHE_ENTRY) + sizeof (TRANID) * MAX_NTRANS);
5975 #else /* SERVER_MODE */
5976  return (DB_VALUE *) ((char *) ent + sizeof (QFILE_LIST_CACHE_ENTRY));
5977 #endif /* SERVER_MODE */
5978 }
5979 
5980 /*
5981  * qfile_add_tuple_get_pos_in_list () - The given tuple is added to the end of
5982  * the list file. The position in the list file is returned.
5983  * return:
5984  * list_id(in):
5985  * tuple(in):
5986  * tuple_pos(out):
5987  */
5988 int
5990  QFILE_TUPLE_POSITION * tuple_pos)
5991 {
5992  PAGE_PTR cur_page_p, new_page_p, prev_page_p;
5993  int tuple_length;
5994  char *page_p, *tuple_p;
5995  int offset, tuple_page_size;
5996 
5997  if (list_id_p == NULL)
5998  {
5999  return ER_FAILED;
6000  }
6001 
6002  QFILE_CHECK_LIST_FILE_IS_CLOSED (list_id_p);
6003 
6004  cur_page_p = list_id_p->last_pgptr;
6005  tuple_length = QFILE_GET_TUPLE_LENGTH (tuple);
6006 
6007  if (qfile_allocate_new_page_if_need (thread_p, list_id_p, &cur_page_p, tuple_length, false) != NO_ERROR)
6008  {
6009  return ER_FAILED;
6010  }
6011 
6012  page_p = (char *) cur_page_p + list_id_p->last_offset;
6013  tuple_page_size = MIN (tuple_length, qfile_Max_tuple_page_size);
6014  memcpy (page_p, tuple, tuple_page_size);
6015 
6016  /* get the information for our QFILE_TUPLE_POSITION */
6017  if (tuple_pos)
6018  {
6019  tuple_pos->offset = list_id_p->last_offset;
6020  tuple_pos->tpl = page_p;
6021  tuple_pos->tplno = list_id_p->tuple_cnt;
6022  tuple_pos->vpid = list_id_p->last_vpid;
6023  }
6024 
6025  qfile_add_tuple_to_list_id (list_id_p, page_p, tuple_length, tuple_page_size);
6026 
6027  prev_page_p = cur_page_p;
6028  for (offset = tuple_page_size, tuple_p = (char *) tuple + offset; offset < tuple_length;
6029  offset += tuple_page_size, tuple_p += tuple_page_size)
6030  {
6031  new_page_p =
6032  qfile_allocate_new_ovf_page (thread_p, list_id_p, cur_page_p, prev_page_p, tuple_length, offset,
6033  &tuple_page_size);
6034  if (new_page_p == NULL)
6035  {
6036  if (prev_page_p != cur_page_p)
6037  {
6038  qfile_set_dirty_page (thread_p, prev_page_p, FREE, list_id_p->tfile_vfid);
6039  }
6040  return ER_FAILED;
6041  }
6042 
6043  memcpy ((char *) new_page_p + QFILE_PAGE_HEADER_SIZE, tuple_p, tuple_page_size);
6044 
6045  prev_page_p = new_page_p;
6046  }
6047 
6048  if (prev_page_p != cur_page_p)
6049  {
6050  QFILE_PUT_OVERFLOW_VPID_NULL (prev_page_p);
6051  qfile_set_dirty_page (thread_p, prev_page_p, FREE, list_id_p->tfile_vfid);
6052  }
6053 
6054  qfile_set_dirty_page (thread_p, cur_page_p, DONT_FREE, list_id_p->tfile_vfid);
6055 
6056  return NO_ERROR;
6057 }
6058 
6059 /*
6060  * qfile_has_next_page() - returns whether the page has the next page or not.
6061  * If false, that means the page is the last page of the list file.
6062  * return: true/false
6063  * page_p(in):
6064  */
6065 bool
6067 {
6069 }
6070 
6071 /*
6072  * qfile_update_domains_on_type_list() - Update domain pointers belongs to
6073  * type list of a given list file
6074  * return: error code
6075  *
6076  */
6077 int
6079 {
6080  REGU_VARIABLE_LIST reg_var_p;
6081  int i, count = 0;
6082 
6083  assert (list_id_p != NULL);
6084 
6085  list_id_p->is_domain_resolved = true;
6086 
6087  reg_var_p = valptr_list_p->valptrp;
6088 
6089  for (i = 0; i < valptr_list_p->valptr_cnt; i++, reg_var_p = reg_var_p->next)
6090  {
6091  if (REGU_VARIABLE_IS_FLAGED (&reg_var_p->value, REGU_VARIABLE_HIDDEN_COLUMN))
6092  {
6093  continue;
6094  }
6095 
6096  if (count >= list_id_p->type_list.type_cnt)
6097  {
6098  assert (false);
6100  goto exit_on_error;
6101  }
6102 
6103  if (TP_DOMAIN_TYPE (list_id_p->type_list.domp[count]) == DB_TYPE_VARIABLE)
6104  {
6105  if (TP_DOMAIN_TYPE (reg_var_p->value.domain) == DB_TYPE_VARIABLE)
6106  {
6107  /* In this case, we cannot resolve the value's domain. We will try to do for the next tuple. */
6108  if (list_id_p->is_domain_resolved)
6109  {
6110  list_id_p->is_domain_resolved = false;
6111  }
6112  }
6113  else
6114  {
6115  list_id_p->type_list.domp[count] = reg_var_p->value.domain;
6116  }
6117  }
6118 
6119  if (list_id_p->type_list.domp[count]->collation_flag != TP_DOMAIN_COLL_NORMAL)
6120  {
6121  if (reg_var_p->value.domain->collation_flag != TP_DOMAIN_COLL_NORMAL)
6122  {
6123  /* In this case, we cannot resolve the value's domain. We will try to do for the next tuple. */
6124  if (list_id_p->is_domain_resolved)
6125  {
6126  list_id_p->is_domain_resolved = false;
6127  }
6128  }
6129  else
6130  {
6131  list_id_p->type_list.domp[count] = reg_var_p->value.domain;
6132  }
6133  }
6134 
6135  count++;
6136  }
6137 
6138  /* The number of columns should be same. */
6139  if (count != list_id_p->type_list.type_cnt)
6140  {
6141  assert (false);
6143  goto exit_on_error;
6144  }
6145 
6146  return NO_ERROR;
6147 
6148 exit_on_error:
6149 
6150  list_id_p->is_domain_resolved = false;
6151  return ER_FAILED;
6152 }
6153 
6154 /*
6155  * qfile_set_tuple_column_value() - Set column value for a fixed size column
6156  * of a tuple inside a list file (in-place)
6157  * return: error code
6158  * list_id_p(in): list file id
6159  * curr_page_p(in): use this only with curr_pgptr of your open scanner!
6160  * vpid_p(in): real VPID
6161  * tuple_p(in): pointer to the tuple inside the page
6162  * col_num(in): column number
6163  * value_p(in): new column value
6164  * domain_p(in): column domain
6165  *
6166  * Note: Caller is responsible to ensure that the size of the column data
6167  * is fixed!
6168  */
6169 int
6170 qfile_set_tuple_column_value (THREAD_ENTRY * thread_p, QFILE_LIST_ID * list_id_p, PAGE_PTR curr_page_p, VPID * vpid_p,
6171  QFILE_TUPLE tuple_p, int col_num, DB_VALUE * value_p, TP_DOMAIN * domain_p)
6172 {
6173  PAGE_PTR page_p;
6175  QFILE_TUPLE_RECORD tuple_rec = { NULL, 0 };
6176  PR_TYPE *pr_type;
6177  OR_BUF buf;
6178  char *ptr;
6179  int length;
6180  int error = NO_ERROR;
6181 
6182  pr_type = domain_p->type;
6183  if (pr_type == NULL)
6184  {
6185  return ER_FAILED;
6186  }
6187 
6188  /* get a pointer to the page */
6189  if (curr_page_p != NULL)
6190  {
6191  page_p = curr_page_p;
6192  }
6193  else
6194  {
6195  page_p = qmgr_get_old_page (thread_p, vpid_p, list_id_p->tfile_vfid);
6196  }
6197  if (page_p == NULL)
6198  {
6199  return ER_FAILED;
6200  }
6201 
6202  /* locate and update tuple value inside the page or in overflow pages */
6203  if (QFILE_GET_OVERFLOW_PAGE_ID (page_p) == NULL_PAGEID)
6204  {
6205  /* tuple is inside the page, locate column and set the new value */
6206  flag = (QFILE_TUPLE_VALUE_FLAG) qfile_locate_tuple_value (tuple_p, col_num, &ptr, &length);
6207  if (flag == V_BOUND)
6208  {
6209  OR_BUF_INIT (buf, ptr, length);
6210 
6211  if (pr_type->data_writeval (&buf, value_p) != NO_ERROR)
6212  {
6213  error = ER_FAILED;
6214  goto cleanup;
6215  }
6216  }
6217  else
6218  {
6219  error = ER_FAILED;
6220  goto cleanup;
6221  }
6222  qfile_set_dirty_page (thread_p, page_p, DONT_FREE, list_id_p->tfile_vfid);
6223  }
6224  else
6225  {
6226  /* tuple is in overflow pages */
6227  if (curr_page_p)
6228  {
6229  /* tuple_p is not a tuple pointer inside the current page, it is a copy made by qfile_scan_list_next(), so
6230  * avoid fetching it twice, and make sure it doesn't get freed at cleanup stage of this function. For
6231  * reference see how qfile_retrieve_tuple() handles overflow pages. */
6232  tuple_rec.tpl = tuple_p;
6233  tuple_rec.size = QFILE_GET_TUPLE_LENGTH (tuple_p);
6234  }
6235  else
6236  {
6237  if (qfile_get_tuple (thread_p, page_p, tuple_p, &tuple_rec, list_id_p) != NO_ERROR)
6238  {
6239  error = ER_FAILED;
6240  goto cleanup;
6241  }
6242  }
6243 
6244  /* locate column and set the new value */
6245  flag = (QFILE_TUPLE_VALUE_FLAG) qfile_locate_tuple_value (tuple_rec.tpl, col_num, &ptr, &length);
6246  if (flag == V_BOUND)
6247  {
6248  OR_BUF_INIT (buf, ptr, length);
6249 
6250  if (pr_type->data_writeval (&buf, value_p) != NO_ERROR)
6251  {
6252  error = ER_FAILED;
6253  goto cleanup;
6254  }
6255  }
6256  else
6257  {
6258  error = ER_FAILED;
6259  goto cleanup;
6260  }
6261 
6262  /* flush the tuple back into overflow pages */
6263  if (qfile_overwrite_tuple (thread_p, page_p, tuple_p, &tuple_rec, list_id_p) != NO_ERROR)
6264  {
6265  error = ER_FAILED;
6266  goto cleanup;
6267  }
6268  qfile_set_dirty_page (thread_p, page_p, DONT_FREE, list_id_p->tfile_vfid);
6269  }
6270 
6271 cleanup:
6272  /* free the tuple record if used */
6273  if (tuple_rec.tpl != NULL && tuple_rec.tpl != tuple_p)
6274  {
6275  db_private_free_and_init (NULL, tuple_rec.tpl);
6276  }
6277  /* free the page */
6278  if (page_p != curr_page_p)
6279  {
6280  qmgr_free_old_page_and_init (thread_p, page_p, list_id_p->tfile_vfid);
6281  }
6282 
6283  return error;
6284 }
6285 
6286 /*
6287  * qfile_overwrite_tuple () - Overwrite a tuple inside a list file with a tuple
6288  * record of the same size
6289  * return: error code
6290  * first_page_p(in): pointer to the first page where the tuple is located
6291  * tuple(in): pointer to the tuple to be overwritten
6292  * tuple_record_p(in): tuple record to overwrite with
6293  * list_id_p(in): list file id
6294  *
6295  * Note: The caller should use responsibly this function!
6296  */
6297 int
6298 qfile_overwrite_tuple (THREAD_ENTRY * thread_p, PAGE_PTR first_page_p, QFILE_TUPLE tuple,
6299  QFILE_TUPLE_RECORD * tuple_record_p, QFILE_LIST_ID * list_id_p)
6300 {
6301  VPID ovfl_vpid;
6302  char *tuple_p;
6303  int offset;
6304  int tuple_length, tuple_page_size;
6305  int max_tuple_page_size;
6306  PAGE_PTR page_p;
6307 
6308  page_p = first_page_p;
6309  tuple_length = QFILE_GET_TUPLE_LENGTH (tuple);
6310 
6311  /* sanity check */
6312  if (tuple_length != tuple_record_p->size)
6313  {
6314  assert (false);
6315  return ER_FAILED;
6316  }
6317 
6318  tuple_p = (char *) tuple_record_p->tpl;
6319 
6321  {
6322  /* tuple is inside the page */
6323  memcpy (tuple, tuple_p, tuple_length);
6324  return NO_ERROR;
6325  }
6326  else
6327  {
6328  /* tuple has overflow pages */
6329  offset = 0;
6330  max_tuple_page_size = qfile_Max_tuple_page_size;
6331 
6332  do
6333  {
6334  QFILE_GET_OVERFLOW_VPID (&ovfl_vpid, page_p);
6335  tuple_page_size = MIN (tuple_length - offset, max_tuple_page_size);
6336 
6337  memcpy ((char *) page_p + QFILE_PAGE_HEADER_SIZE, tuple_p, tuple_page_size);
6338 
6339  tuple_p += tuple_page_size;
6340  offset += tuple_page_size;
6341 
6342  if (page_p != first_page_p)
6343  {
6344  qfile_set_dirty_page (thread_p, page_p, FREE, list_id_p->tfile_vfid);
6345  }
6346 
6347  if (ovfl_vpid.pageid != NULL_PAGEID)
6348  {
6349  page_p = qmgr_get_old_page (thread_p, &ovfl_vpid, list_id_p->tfile_vfid);
6350  if (page_p == NULL)
6351  {
6352  return ER_FAILED;
6353  }
6354  }
6355  }
6356  while (ovfl_vpid.pageid != NULL_PAGEID);
6357  }
6358 
6359  return NO_ERROR;
6360 }
6361 
6362 /*
6363  * qfile_compare_with_interpolation_domain () -
6364  * return: compare result
6365  * fp0(in):
6366  * fp1(in):
6367  * subkey(in):
6368  *
6369  * NOTE: median analytic function sort string in different domain
6370  */
6371 static int
6373 {
6374  int order = 0;
6375  DB_VALUE val0, val1;
6376  OR_BUF buf0, buf1;
6377  TP_DOMAIN *cast_domain = NULL;
6379  int error = NO_ERROR;
6380  char *d0, *d1;
6381 
6382  assert (fp0 != NULL && fp1 != NULL && subkey != NULL && key_info != NULL);
6383 
6384  db_make_null (&val0);
6385  db_make_null (&val1);
6386 
6389 
6390  if (subkey->cmp_dom == NULL)
6391  {
6392  /* get the proper domain NOTE: col_dom is string type. See qexec_initialize_analytic_state */
6393  pr_clear_value (&val0);
6394 
6395  OR_BUF_INIT (buf0, d0, QFILE_GET_TUPLE_VALUE_LENGTH (fp0));
6396  error =
6397  subkey->col_dom->type->data_readval (&buf0, &val0, subkey->col_dom, QFILE_GET_TUPLE_VALUE_LENGTH (fp0), false,
6398  NULL, 0);
6399  if (error != NO_ERROR || DB_IS_NULL (&val0))
6400  {
6401  goto end;
6402  }
6403 
6404  error = qdata_update_interpolation_func_value_and_domain (&val0, &val0, &cast_domain);
6405  if (error != NO_ERROR)
6406  {
6407  subkey->cmp_dom = NULL;
6408  goto end;
6409  }
6410  else
6411  {
6412  subkey->cmp_dom = cast_domain;
6413  }
6414  }
6415 
6416  /* cast to proper domain, then compare */
6417  pr_clear_value (&val0);
6418  pr_clear_value (&val1);
6419 
6420  OR_BUF_INIT (buf0, d0, QFILE_GET_TUPLE_VALUE_LENGTH (fp0));
6421  OR_BUF_INIT (buf1, d1, QFILE_GET_TUPLE_VALUE_LENGTH (fp1));
6422  error =
6423  subkey->col_dom->type->data_readval (&buf0, &val0, subkey->col_dom, QFILE_GET_TUPLE_VALUE_LENGTH (fp0), false,
6424  NULL, 0);
6425  if (error != NO_ERROR)
6426  {
6427  goto end;
6428  }
6429 
6430  error =
6431  subkey->col_dom->type->data_readval (&buf1, &val1, subkey->col_dom, QFILE_GET_TUPLE_VALUE_LENGTH (fp1), false,
6432  NULL, 0);
6433  if (error != NO_ERROR)
6434  {
6435  goto end;
6436  }
6437 
6438  cast_domain = subkey->cmp_dom;
6439  status = tp_value_cast (&val0, &val0, cast_domain, false);
6440  if (status != DOMAIN_COMPATIBLE)
6441  {
6443  goto end;
6444  }
6445 
6446  status = tp_value_cast (&val1, &val1, cast_domain, false);
6447  if (status != DOMAIN_COMPATIBLE)
6448  {
6450  goto end;
6451  }
6452 
6453  /* compare */
6454  order = cast_domain->type->cmpval (&val0, &val1, 0, 1, NULL, cast_domain->collation_id);
6455 
6456 end:
6457 
6458  pr_clear_value (&val0);
6459  pr_clear_value (&val1);
6460 
6461  /* record error */
6462  if (error != NO_ERROR)
6463  {
6464  key_info->error = error;
6465  }
6466 
6467  return order;
6468 }
6469 
6470 void
6471 qfile_update_qlist_count (THREAD_ENTRY * thread_p, const QFILE_LIST_ID * list_p, int inc)
6472 {
6473 #if defined (SERVER_MODE)
6474  if (list_p != NULL && list_p->type_list.type_cnt != 0)
6475  {
6476  thread_p->m_qlist_count += inc;
6478  {
6479  er_print_callstack (ARG_FILE_LINE, "update qlist_count by %d to %d\n", inc, thread_p->m_qlist_count);
6480  }
6481  }
6482 #endif // SERVER_MODE
6483 }
6484 
6485 int
6487 {
6488  assert_release (ht_no >= 0);
6489 
6490  return (qfile_List_cache.list_hts[ht_no]->nentries);
6491 }
6492 
6493 bool
6495 {
6496  return (qfile_List_cache.n_entries == 0);
6497 }
#define QFILE_TUPLE_VALUE_HEADER_SIZE
Definition: query_list.h:229
int qfile_reallocate_tuple(QFILE_TUPLE_RECORD *tuple_record_p, int tuple_size)
Definition: list_file.c:3010
static int qfile_compare_equal_db_value_array(const void *key1, const void *key2)
Definition: list_file.c:4847
#define QFILE_LAST_TUPLE_OFFSET
Definition: query_list.h:53
char * PAGE_PTR
#define QFILE_CLEAR_LIST_ID(list_id)
Definition: query_list.h:445
int stx_map_stream_to_xasl_node_header(THREAD_ENTRY *thread_p, xasl_node_header *xasl_header_p, char *xasl_stream)
union SORT_REC::@159 s
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
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
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
struct db_value DB_VALUE
Definition: dbtype_def.h:1079
int qfile_Is_list_cache_disabled
Definition: list_file.c:193
QFILE_TUPLE_RECORD tplrec
Definition: query_list.h:506
#define QFILE_GET_TUPLE_VALUE_HEADER_POSITION(tpl, ind, valp)
Definition: query_list.h:262
int file_temp_retire(THREAD_ENTRY *thread_p, const VFID *vfid)
static int qfile_save_sort_key_tuple(QFILE_TUPLE_DESCRIPTOR *tuple_descr_p, char *tuple_p, char *page_p, int tuple_length)
Definition: list_file.c:1616
static SORT_STATUS qfile_get_next_sort_item(THREAD_ENTRY *thread_p, RECDES *recdes, void *arg)
Definition: list_file.c:3312
QFILE_LIST_ID * list_id
cubthread::entry * thread_get_thread_entry_info(void)
#define NO_ERROR
Definition: error_code.h:46
int mht_map_no_key(THREAD_ENTRY *thread_p, const MHT_TABLE *ht, int(*map_func)(THREAD_ENTRY *thread_p, void *data, void *args), void *func_args)
Definition: memory_hash.c:2231
int area_size
static SCAN_CODE qfile_advance_single(THREAD_ENTRY *thread_p, QFILE_LIST_SCAN_ID *next_scan, QFILE_TUPLE_RECORD *next_tpl, QFILE_LIST_SCAN_ID *last_scan, QFILE_TUPLE_RECORD *last_tpl, QFILE_TUPLE_VALUE_TYPE_LIST *types)
Definition: list_file.c:2434
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
int pr_data_writeval_disk_size(DB_VALUE *value)
int mht_clear(MHT_TABLE *ht, int(*rem_func)(const void *key, void *data, void *args), void *func_args)
Definition: memory_hash.c:1180
#define LF_EM_NOT_USING_MUTEX
Definition: lock_free.h:59
#define QFILE_OVERFLOW_PAGE_ID_OFFSET
Definition: query_list.h:54
static int qfile_save_merge_tuple(QFILE_TUPLE_DESCRIPTOR *tuple_descr_p, char *tuple_p, char *page_p, int *tuple_length_p)
Definition: list_file.c:1652
int qfile_end_use_of_list_cache_entry(THREAD_ENTRY *thread_p, QFILE_LIST_CACHE_ENTRY *lent, bool marker)
Definition: list_file.c:5849
struct qmgr_temp_file * tfile_vfid
Definition: query_list.h:440
DB_VALUE * vals
Definition: dbtype_def.h:1100
SCAN_CODE
unsigned int miss_counter
Definition: list_file.c:104
bool qfile_has_next_page(PAGE_PTR page_p)
Definition: list_file.c:6066
#define QFILE_PREV_PAGE_ID_OFFSET
Definition: query_list.h:51
QFILE_TUPLE_VALUE_TYPE_LIST type_list
Definition: query_list.h:428
QUERY_ID query_id
Definition: query_list.h:438
#define thread_sleep(a)
Definition: list_file.c:59
int data_writeval(struct or_buf *buf, const DB_VALUE *value) const
int TRANID
PAGE_PTR last_pgptr
Definition: query_list.h:434
#define ADDITION_FOR_POOLED_LIST_CACHE_ENTRY
Definition: list_file.c:125
int errid
#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
int n_entries
Definition: list_file.c:152
#define d0
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
QFILE_LIST_CACHE_ENTRY * qfile_lookup_list_cache_entry(THREAD_ENTRY *thread_p, int list_ht_no, const DB_VALUE_ARRAY *params, bool *result_cached)
Definition: list_file.c:5480
data_cmpdisk_function_type get_data_cmpdisk_function() const
unsigned int full_counter
Definition: list_file.c:105
size_t align(size_t v)
Definition: align.h:19
static void qfile_clear_sort_info(SORT_INFO *info)
Definition: list_file.c:3873
DB_TYPE
Definition: dbtype_def.h:670
QFILE_TUPLE_VALUE_FLAG qfile_locate_tuple_value_r(QFILE_TUPLE tuple, int index, char **tuple_value_p, int *value_size_p)
Definition: list_file.c:922
PAGE_PTR qmgr_get_old_page(THREAD_ENTRY *thread_p, VPID *vpid_p, QMGR_TEMP_FILE *tfile_vfid_p)
static SCAN_CODE qfile_scan_next(THREAD_ENTRY *thread_p, QFILE_LIST_SCAN_ID *s_id)
Definition: list_file.c:4310
#define ER_FAILED
Definition: error_code.h:47
void qfile_load_xasl_node_header(THREAD_ENTRY *thread_p, char *xasl_stream, xasl_node_header *xasl_header_p)
Definition: list_file.c:1063
REGU_VARIABLE_LIST next
Definition: regu_var.hpp:221
const int REGU_VARIABLE_HIDDEN_COLUMN
Definition: regu_var.hpp:156
static SCAN_CODE qfile_scan_prev(THREAD_ENTRY *thread_p, QFILE_LIST_SCAN_ID *s_id)
Definition: list_file.c:4398
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
#define csect_enter(a, b, c)
Definition: cnv.c:138
static LF_ENTRY_DESCRIPTOR qfile_sort_list_entry_desc
Definition: list_file.c:175
QFILE_SORT_SCAN_ID * s_id
void bh_element_at(BINARY_HEAP *heap, int index, void *elem)
Definition: binaryheap.c:442
int SORT_PUT_FUNC(THREAD_ENTRY *thread_p, const RECDES *, void *)
Definition: external_sort.h:60
#define QFILE_GET_NEXT_PAGE_ID(ptr)
Definition: query_list.h:73
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
int qfile_overwrite_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:6298
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
QFILE_LIST_ID * output_file
#define QFILE_PUT_TUPLE_COUNT(ptr, val)
Definition: query_list.h:120
static int qfile_Max_tuple_page_size
Definition: list_file.c:195
#define OR_BUF_INIT(buf, data, size)
#define ER_QPROC_INCOMPATIBLE_TYPES
Definition: error_code.h:536
static int qfile_save_normal_tuple(QFILE_TUPLE_DESCRIPTOR *tuple_descr_p, char *tuple_p, char *page_p, int tuple_length)
Definition: list_file.c:1596
#define QFILE_GET_PREV_TUPLE_LENGTH(tpl)
Definition: query_list.h:241
static bool qfile_is_last_page_full(QFILE_LIST_ID *list_id_p, int tuple_length, const bool is_ovf_page)
Definition: list_file.c:1345
static SCAN_CODE qfile_retrieve_tuple(THREAD_ENTRY *thread_p, QFILE_LIST_SCAN_ID *scan_id_p, QFILE_TUPLE_RECORD *tuple_record_p, int peek)
Definition: list_file.c:4490
#define NO_SORT_LIMIT
Definition: external_sort.h:40
int pr_is_variable_type(DB_TYPE id)
void * extra_arg
Definition: lock_free.h:63
#define QFILE_PUT_OVERFLOW_VPID_NULL(ptr)
Definition: query_list.h:189
#define assert_release(e)
Definition: error_manager.h:96
static int qfile_advance(THREAD_ENTRY *thread_p, ADVANCE_FUCTION advance_func, QFILE_TUPLE_RECORD *side_p, QFILE_TUPLE_RECORD *last_side_p, QFILE_LIST_SCAN_ID *scan_p, QFILE_LIST_SCAN_ID *last_scan_p, QFILE_LIST_ID *side_file_p, int *have_side_p)
Definition: list_file.c:2542
void pgbuf_set_dirty(THREAD_ENTRY *thread_p, PAGE_PTR pgptr, bool free_page)
Definition: page_buffer.c:4280
Definition: lock_free.h:120
int qfile_locate_tuple_next_value(OR_BUF *iterator, OR_BUF *buf, QFILE_TUPLE_VALUE_FLAG *flag)
Definition: list_file.c:952
int qfile_get_estimated_pages_for_sorting(QFILE_LIST_ID *list_id_p, SORTKEY_INFO *key_info_p)
Definition: list_file.c:3689
QFILE_LIST_CACHE_ENTRY ** victims
Definition: list_file.c:117
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
INT16 VOLID
static PAGE_PTR qfile_allocate_new_ovf_page(THREAD_ENTRY *thread_p, QFILE_LIST_ID *list_id_p, PAGE_PTR page_p, PAGE_PTR prev_page_p, int tuple_length, int offset, int *tuple_page_size_p)
Definition: list_file.c:1435
INT16 offset
Definition: external_sort.h:78
QFILE_TUPLE_TYPE
Definition: query_list.h:352
SCAN_CODE(* ADVANCE_FUCTION)(THREAD_ENTRY *thread_p, QFILE_LIST_SCAN_ID *, QFILE_TUPLE_RECORD *, QFILE_LIST_SCAN_ID *, QFILE_TUPLE_RECORD *, QFILE_TUPLE_VALUE_TYPE_LIST *)
Definition: list_file.c:91
#define QFILE_PREV_VOL_ID_OFFSET
Definition: query_list.h:55
Definition: list_file.c:131
char * data
bool REGU_VARIABLE_IS_FLAGED(const regu_variable_node *regu, int flag)
Definition: regu_var.hpp:253
static void qfile_set_dirty_page(THREAD_ENTRY *thread_p, PAGE_PTR page_p, int free_page, QMGR_TEMP_FILE *vfid_p)
Definition: list_file.c:1362
int32_t pageid
Definition: dbtype_def.h:879
int element_count
Definition: binaryheap.h:71
int qdata_update_interpolation_func_value_and_domain(DB_VALUE *src_val, DB_VALUE *dest_val, TP_DOMAIN **domain)
PR_TYPE tp_Integer
#define MAX_NTRANS
int er_errid(void)
void * lf_freelist_claim(LF_TRAN_ENTRY *tran_entry, LF_FREELIST *freelist)
Definition: lock_free.c:751
TP_DOMAIN * cmp_dom
void qfile_clear_list_id(QFILE_LIST_ID *list_id_p)
Definition: list_file.c:526
static LF_FREELIST qfile_sort_list_Freelist
Definition: list_file.c:170
void * BH_CMP_ARG
Definition: binaryheap.h:40
#define PTR_ALIGN(addr, boundary)
Definition: memory_alloc.h:77
#define QFILE_PUT_NEXT_VPID(ptr, vpid)
Definition: query_list.h:157
static void qfile_delete_uncommitted_list_cache_entry(int tran_index, QFILE_LIST_CACHE_ENTRY *lent)
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
bool * clear_f_val_at_clone_decache
Definition: query_list.h:373
DB_VALUE_ARRAY param_values
Definition: list_file.h:85
TRAN_ISOLATION logtb_find_isolation(int tran_index)
QFILE_TUPLE_DESCRIPTOR tpl_descr
Definition: query_list.h:441
enum tp_domain_status TP_DOMAIN_STATUS
#define er_log_debug(...)
HL_HEAPID db_change_private_heap(THREAD_ENTRY *thread_p, HL_HEAPID heap_id)
Definition: memory_alloc.c:337
static void qfile_set_dirty_page_and_skip_logging(THREAD_ENTRY *thread_p, PAGE_PTR page_p, VFID *vfid_p, int free_page)
Definition: list_file.c:1042
void qfile_clear_sort_key_info(SORTKEY_INFO *key_info_p)
Definition: list_file.c:3826
static QFILE_LIST_ID * qfile_union_list(THREAD_ENTRY *thread_p, QFILE_LIST_ID *list_id1, QFILE_LIST_ID *list_id2, int flag)
Definition: list_file.c:2942
#define MAX_ALIGNMENT
Definition: memory_alloc.h:70
unsigned int n_hts
Definition: list_file.c:99
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
SUBKEY_INFO default_keys[8]
#define VFID_ISNULL(vfid_ptr)
Definition: file_manager.h:72
void THREAD_ENTRY
#define NULL_PAGEID
QMGR_TEMP_FILE * qmgr_create_result_file(THREAD_ENTRY *thread_p, QUERY_ID query_id)
XASL_CACHE_ENTRY * xcache_entry
Definition: list_file.h:95
struct qfile_pooled_list_cache_entry::@144 s
static int qfile_end_use_of_list_cache_entry_local(THREAD_ENTRY *thread_p, void *data, void *args)
Definition: list_file.c:5464
unsigned int nentries
Definition: memory_hash.h:70
#define FREE(PTR)
Definition: cas_common.h:56
MHT_TABLE ** list_hts
Definition: list_file.c:98
QFILE_POOLED_LIST_CACHE_ENTRY * pool
Definition: list_file.c:151
int qfile_get_first_page(THREAD_ENTRY *thread_p, QFILE_LIST_ID *list_id_p)
Definition: list_file.c:2112
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)
int free_list
Definition: list_file.c:153
void mht_destroy(MHT_TABLE *ht)
Definition: memory_hash.c:1140
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)
SORTKEY_INFO key_info
#define QFILE_MAX_TUPLE_SIZE_IN_PAGE
Definition: query_list.h:217
static SORT_INFO * qfile_initialize_sort_info(SORT_INFO *info, QFILE_LIST_ID *listid, SORT_LIST *sort_list)
Definition: list_file.c:3849
static void qfile_initialize_page_header(PAGE_PTR page_p)
Definition: list_file.c:1025
static int qfile_put_next_sort_item(THREAD_ENTRY *thread_p, const RECDES *recdes, void *arg)
Definition: list_file.c:3348
void qfile_end_scan_fix(THREAD_ENTRY *thread_p, QFILE_LIST_SCAN_ID *scan_id_p)
Definition: list_file.c:4752
PR_TYPE * pr_type_from_id(DB_TYPE id)
#define QFILE_OVERFLOW_VOL_ID_OFFSET
Definition: query_list.h:57
#define VPID_SET(vpid_ptr, volid_value, pageid_value)
Definition: dbtype_def.h:899
SCAN_POSITION position
Definition: query_list.h:499
void er_set(int severity, const char *file_name, const int line_no, int err_id, int num_args,...)
void bh_destroy(THREAD_ENTRY *thread_p, BINARY_HEAP *heap)
Definition: binaryheap.c:157
#define QFILE_NEXT_PAGE_ID_OFFSET
Definition: query_list.h:52
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
#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
void log_skip_logging(THREAD_ENTRY *thread_p, LOG_DATA_ADDR *addr)
Definition: log_manager.c:3244
QFILE_TUPLE_RECORD * tplrec1
Definition: query_list.h:380
const char * query_string
Definition: list_file.h:96
QFILE_LIST_CACHE_ENTRY ** ref_candidates
Definition: list_file.c:116
static int qfile_delete_list_cache_entry(THREAD_ENTRY *thread_p, void *data)
Definition: list_file.c:5403
int ref_count
Definition: list_file.h:99
int32_t fileid
Definition: dbtype_def.h:886
bool pgbuf_check_page_ptype(THREAD_ENTRY *thread_p, PAGE_PTR pgptr, PAGE_TYPE ptype)
static QFILE_LIST_CACHE_ENTRY_POOL qfile_List_cache_entry_pool
Definition: list_file.c:167
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
int prm_get_integer_value(PARAM_ID prm_id)
#define ER_GENERIC_ERROR
Definition: error_code.h:49
QMGR_QUERY_STATUS query_status
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 int qfile_print_list_cache_entry(THREAD_ENTRY *thread_p, FILE *fp, const void *key, void *data, void *args)
Definition: list_file.c:5227
int qfile_compare_all_sort_record(const void *pk0, const void *pk1, void *arg)
Definition: list_file.c:3586
struct sort_list * next
Definition: query_list.h:415
PAGE_PTR curr_pgptr
Definition: query_list.h:501
#define QFILE_PAGE_HEADER_SIZE
Definition: query_list.h:47
#define QFILE_CHECK_LIST_FILE_IS_CLOSED(list_id)
Definition: list_file.c:62
static PAGE_PTR qfile_allocate_new_page(THREAD_ENTRY *thread_p, QFILE_LIST_ID *list_id_p, PAGE_PTR page_p, bool is_ovf_page)
Definition: list_file.c:1374
static int qfile_dealloc_sort_list(void *sort_list)
Definition: list_file.c:669
lf_tran_entry * thread_get_tran_entry(cubthread::entry *thread_p, int entry_idx)
#define QFILE_GET_PREV_PAGE_ID(ptr)
Definition: query_list.h:70
#define ER_QPROC_UNKNOWN_QUERYID
Definition: error_code.h:529
QFILE_LIST_ID * qfile_duplicate_list(THREAD_ENTRY *thread_p, QFILE_LIST_ID *list_id_p, int flag)
Definition: list_file.c:4174
#define DB_VALUE_DOMAIN_TYPE(value)
Definition: dbtype.h:70
QFILE_LIST_CACHE_ENTRY * qfile_update_list_cache_entry(THREAD_ENTRY *thread_p, int list_ht_no, const DB_VALUE_ARRAY *params, const QFILE_LIST_ID *list_id, XASL_CACHE_ENTRY *xasl)
Definition: list_file.c:5627
#define QFILE_PUT_OVERFLOW_VPID(ptr, vpid)
Definition: query_list.h:165
int lf_freelist_retire(LF_TRAN_ENTRY *tran_entry, LF_FREELIST *freelist, void *entry)
Definition: lock_free.c:864
Definition: list_file.h:82
QFILE_LIST_ID list_id
Definition: list_file.h:86
static int qfile_add_one_tuple(THREAD_ENTRY *thread_p, QFILE_LIST_ID *dst, QFILE_TUPLE lhs, QFILE_TUPLE rhs)
Definition: list_file.c:2515
#define QFILE_GET_PREV_VPID(des, ptr)
Definition: query_list.h:96
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
DB_TRAN_ISOLATION
Definition: dbtran_def.h:26
QMGR_TEMP_FILE * qmgr_create_new_temp_file(THREAD_ENTRY *thread_p, QUERY_ID query_id, QMGR_TEMP_FILE_MEMBUF_TYPE membuf_type)
#define QFILE_RESERVED_OFFSET
Definition: query_list.h:58
static const int RESERVED_SIZE_FOR_LIST_CACHE_ENTRY
Definition: list_file.c:145
#define VPID_EQ(vpid_ptr1, vpid_ptr2)
Definition: dbtype_def.h:915
int qmgr_free_list_temp_file(THREAD_ENTRY *thread_p, QUERY_ID query_id, QMGR_TEMP_FILE *tfile_vfid_p)
short volid
Definition: dbtype_def.h:880
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
TP_DOMAIN * col_dom
unsigned int mht_valhash(const void *key, const unsigned int ht_size)
Definition: memory_hash.c:561
TP_DOMAIN_STATUS tp_value_cast(const DB_VALUE *src, DB_VALUE *dest, const TP_DOMAIN *desired_domain, bool implicit_coercion)
#define QFILE_NEXT_VOL_ID_OFFSET
Definition: query_list.h:56
#define TP_DOMAIN_TYPE(dom)
static unsigned int qfile_hash_db_value_array(const void *key, unsigned int htsize)
Definition: list_file.c:4819
QFILE_TUPLE_RECORD tplrec
Definition: query_list.h:542
#define DB_SIZEOF(val)
Definition: memory_alloc.h:54
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
static void cleanup(int signo)
Definition: broker.c:717
static void qfile_add_uncommitted_list_cache_entry(int tran_index, QFILE_LIST_CACHE_ENTRY *lent)
#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
#define NULL
Definition: freelistheap.h:34
int qfile_reopen_list_as_append_mode(THREAD_ENTRY *thread_p, QFILE_LIST_ID *list_id_p)
Definition: list_file.c:1284
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 ER_QPROC_UNKNOWN_CRSPOS
Definition: error_code.h:522
struct pr_type * type
Definition: object_domain.h:76
#define QFILE_COPY_VPID(ptr1, ptr2)
Definition: query_list.h:197
static int qfile_allocate_new_page_if_need(THREAD_ENTRY *thread_p, QFILE_LIST_ID *list_id_p, PAGE_PTR *page_p, int tuple_length, bool is_ovf_page)
Definition: list_file.c:1470
#define QFILE_GET_TUPLE_LENGTH(tpl)
Definition: query_list.h:238
#define QFILE_IS_FLAG_SET_BOTH(var, flag1, flag2)
Definition: query_list.h:525
void * data
Definition: memory_hash.h:50
if(extra_options)
Definition: dynamic_load.c:958
static SCAN_CODE qfile_scan_list(THREAD_ENTRY *thread_p, QFILE_LIST_SCAN_ID *scan_id_p, SCAN_CODE(*scan_func)(THREAD_ENTRY *thread_p, QFILE_LIST_SCAN_ID *), QFILE_TUPLE_RECORD *tuple_record_p, int peek)
Definition: list_file.c:4701
const VFID * vfid
Definition: log_append.hpp:56
QFILE_TUPLE_VALUE_POSITION pos_descr
Definition: query_list.h:416
int qfile_dump_list_cache_internal(THREAD_ENTRY *thread_p, FILE *fp)
Definition: list_file.c:5321
static int success()
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
void qfile_update_qlist_count(THREAD_ENTRY *thread_p, const QFILE_LIST_ID *list_p, int inc)
Definition: list_file.c:6471
int next
Definition: list_file.c:135
#define QFILE_TUPLE_VALUE_HEADER_LENGTH
Definition: query_list.h:228
static void * qfile_alloc_sort_list(void)
Definition: list_file.c:658
PAGE_PTR pgptr
Definition: log_append.hpp:57
#define db_private_free_and_init(thrd, ptr)
Definition: memory_alloc.h:141
int lf_freelist_init(LF_FREELIST *freelist, int initial_blocks, int block_size, LF_ENTRY_DESCRIPTOR *edesc, LF_TRAN_SYSTEM *tran_system)
Definition: lock_free.c:666
#define pgbuf_fix(thread_p, vpid, fetch_mode, requestmode, condition)
Definition: page_buffer.h:255
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
HENTRY_PTR * table
Definition: memory_hash.h:60
#define QFILE_PUT_PREV_VPID(ptr, vpid)
Definition: query_list.h:149
#define csect_exit(a, b)
Definition: cnv.c:139
#define db_private_free(thrd, ptr)
Definition: memory_alloc.h:229
void or_init(OR_BUF *buf, char *data, int length)
QFILE_TUPLE curr_tpl
Definition: query_list.h:502
bool is_domain_resolved
Definition: query_list.h:442
#define db_private_alloc(thrd, size)
Definition: memory_alloc.h:227
static int qfile_get_list_cache_entry_size_for_allocate(int nparam)
Definition: list_file.c:5950
int xqfile_get_list_file_page(THREAD_ENTRY *thread_p, QUERY_ID query_id, VOLID vol_id, PAGEID page_id, char *page_buf_p, int *page_size_p)
Definition: list_file.c:2200
SORT_REC * next
Definition: external_sort.h:70
int file_temp_retire_preserved(THREAD_ENTRY *thread_p, const VFID *vfid)
static bool qfile_is_early_time(struct timeval *a, struct timeval *b)
Definition: list_file.c:5600
#define OR_PUT_SHORT(ptr, val)
SORT_STATUS
Definition: external_sort.h:45
static int qfile_free_list_cache_entry(THREAD_ENTRY *thread_p, void *data, void *args)
Definition: list_file.c:5167
#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)
int pr_clear_value(DB_VALUE *value)
#define cmp
Definition: mprec.h:351
int qfile_open_list_scan(QFILE_LIST_ID *list_id_p, QFILE_LIST_SCAN_ID *scan_id_p)
Definition: list_file.c:4658
EXECUTION_INFO sql_info
Definition: xasl_cache.h:103
offset_type offset
Definition: log_append.hpp:58
#define VFID_COPY(vfid_ptr1, vfid_ptr2)
Definition: file_manager.h:69
#define d1
struct SORT_REC::@159::@160 original
void qmgr_set_dirty_page(THREAD_ENTRY *thread_p, PAGE_PTR page_p, int free_page, LOG_DATA_ADDR *addr_p, QMGR_TEMP_FILE *tfile_vfid_p)
static int qfile_copy_list_pages(THREAD_ENTRY *thread_p, VPID *old_first_vpidp, QMGR_TEMP_FILE *old_tfile_vfidp, VPID *new_first_vpidp, VPID *new_last_vpidp, QMGR_TEMP_FILE *new_tfile_vfidp)
Definition: list_file.c:4057
QFILE_LIST_CACHE_ENTRY entry
Definition: list_file.c:136
struct timeval time_created
Definition: list_file.h:97
#define CAST_BUFLEN
Definition: porting.h:471
#define QFILE_PUT_OVERFLOW_TUPLE_PAGE_SIZE(ptr, val)
Definition: query_list.h:212
TP_DOMAIN_COLL_ACTION collation_flag
Definition: object_domain.h:94
static void error(const char *msg)
Definition: gencat.c:331
#define VPID_ISNULL(vpid_ptr)
Definition: dbtype_def.h:925
static int rc
Definition: serial.c:50
#define ER_INTERRUPTED
Definition: error_code.h:51
void qfile_close_scan(THREAD_ENTRY *thread_p, QFILE_LIST_SCAN_ID *scan_id_p)
Definition: list_file.c:4774
int mht_dump(THREAD_ENTRY *thread_p, FILE *out_fp, const MHT_TABLE *ht, const int print_id_opt, int(*print_func)(THREAD_ENTRY *thread_p, FILE *fp, const void *key, void *data, void *args), void *func_args)
Definition: memory_hash.c:1299
void qfile_free_list_id(QFILE_LIST_ID *list_id_p)
Definition: list_file.c:563
static int qfile_get_tuple_from_current_list(THREAD_ENTRY *thread_p, QFILE_LIST_SCAN_ID *scan_id_p, QFILE_TUPLE_RECORD *tuple_record_p)
Definition: list_file.c:4286
int list_ht_no
Definition: list_file.h:84
#define LOG_FIND_THREAD_TRAN_INDEX(thrd)
Definition: perf_monitor.h:158
static void qfile_close_and_free_list_file(THREAD_ENTRY *thread_p, QFILE_LIST_ID *list_id)
Definition: list_file.c:2924
#define QFILE_OVERFLOW_TUPLE_COUNT_FLAG
Definition: query_list.h:275
bool qfile_has_no_cache_entries()
Definition: list_file.c:6494
#define ARG_FILE_LINE
Definition: error_manager.h:44
bool qfile_is_sort_list_covered(SORT_LIST *covering_list_p, SORT_LIST *covered_list_p)
Definition: list_file.c:705
PAGE_PTR * membuf
Definition: query_manager.h:83
QFILE_LIST_ID list_id
Definition: query_list.h:507
void er_print_callstack(const char *file_name, const int line_no, const char *fmt,...)
HENTRY_PTR next
Definition: memory_hash.h:48
int pr_clone_value(const DB_VALUE *src, DB_VALUE *dest)
QFILE_TUPLE_VALUE_FLAG
Definition: query_list.h:291
SCAN_STATUS status
Definition: query_list.h:483
int qfile_start_scan_fix(THREAD_ENTRY *thread_p, QFILE_LIST_SCAN_ID *scan_id_p)
Definition: list_file.c:4628
int qfile_add_item_to_list(THREAD_ENTRY *thread_p, char *item_p, int item_size, QFILE_LIST_ID *list_id_p)
Definition: list_file.c:2330
QFILE_TUPLE_RECORD * tplrec2
Definition: query_list.h:381
const void * mht_put_new(MHT_TABLE *ht, const void *key, void *data)
Definition: memory_hash.c:1723
SCAN_POSITION position
Definition: query_list.h:484
SORT_DUP_OPTION
Definition: external_sort.h:53
int pr_is_string_type(DB_TYPE type)
unsigned int mht_count(const MHT_TABLE *ht)
Definition: memory_hash.c:2260
char * sql_hash_text
Definition: xasl_cache.h:76
static int qfile_save_single_bound_item_tuple(QFILE_TUPLE_DESCRIPTOR *tuple_descr_p, char *tuple_p, char *page_p, int tuple_length)
Definition: list_file.c:1573
bool deletion_marker
Definition: list_file.h:100
QFILE_LIST_ID * qfile_clone_list_id(const QFILE_LIST_ID *list_id_p, bool is_include_sort_list)
Definition: list_file.c:501
void db_fprint_value(FILE *fp, const db_value *value)
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
#define free_and_init(ptr)
Definition: memory_alloc.h:147
static int qfile_compare_with_null_value(int o0, int o1, SUBKEY_INFO key_info)
Definition: list_file.c:3640
#define DB_ALIGN(offset, align)
Definition: memory_alloc.h:84
PAGE_PTR qmgr_get_new_page(THREAD_ENTRY *thread_p, VPID *vpid_p, QMGR_TEMP_FILE *tfile_vfid_p)
static QFILE_LIST_CACHE_CANDIDATE qfile_List_cache_candidate
Definition: list_file.c:164
static DB_VALUE * qfile_get_list_cache_entry_param_values(QFILE_LIST_CACHE_ENTRY *ent)
Definition: list_file.c:5971
BH_TRY_INSERT_RESULT bh_try_insert(BINARY_HEAP *heap, void *elem, void *replaced)
Definition: binaryheap.c:249
#define LS_PUT_NEXT_VPID(ptr)
Definition: list_file.c:75
int qfile_get_list_cache_number_of_entries(int ht_no)
Definition: list_file.c:6486
static int qfile_compare_with_interpolation_domain(char *fp0, char *fp1, SUBKEY_INFO *subkey, SORTKEY_INFO *key_info)
Definition: list_file.c:6372
static QFILE_LIST_CACHE qfile_List_cache
Definition: list_file.c:161
#define DB_PAGESIZE
#define QFILE_GET_OVERFLOW_VPID(des, ptr)
Definition: query_list.h:112
SCAN_STATUS status
Definition: query_list.h:498
#define QFILE_IS_LIST_CACHE_DISABLED
Definition: list_file.h:54
QFILE_LIST_CACHE_ENTRY ** time_candidates
Definition: list_file.c:115
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
#define FIXED_SIZE_OF_POOLED_LIST_CACHE_ENTRY
Definition: list_file.c:124
void lf_freelist_destroy(LF_FREELIST *freelist)
Definition: lock_free.c:711
char * QFILE_TUPLE
Definition: query_list.h:281
static int qfile_get_sort_list_size(SORT_LIST *sort_list)
Definition: list_file.c:682
int mht_rem2(MHT_TABLE *ht, const void *key, const void *data, int(*rem_func)(const void *key, void *data, void *args), void *func_args)
Definition: memory_hash.c:2078
int qfile_initialize_list_cache(THREAD_ENTRY *thread_p)
Definition: list_file.c:4895
RECDES output_recdes
bool prm_get_bool_value(PARAM_ID prm_id)
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
unsigned int hit_counter
Definition: list_file.c:103
#define OR_PUT_INT(ptr, val)
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
#define QFILE_PUT_PREV_TUPLE_LENGTH(tpl, val)
Definition: query_list.h:247
static void qfile_add_tuple_to_list_id(QFILE_LIST_ID *list_id_p, PAGE_PTR page_p, int tuple_length, int written_tuple_length)
Definition: list_file.c:1493
#define QFILE_IS_FLAG_SET(var, flag)
Definition: query_list.h:524
struct timeval time_last_used
Definition: list_file.h:98
#define QFILE_PUT_NEXT_VPID_NULL(ptr)
Definition: query_list.h:181
SUBKEY_INFO * key
static int qfile_compare_tuple_helper(QFILE_TUPLE lhs, QFILE_TUPLE rhs, QFILE_TUPLE_VALUE_TYPE_LIST *types, int *cmp)
Definition: list_file.c:2395
static int rv
Definition: list_file.c:57
struct qfile_list_cache_entry QFILE_LIST_CACHE_ENTRY
Definition: list_file.h:81
#define ER_QSTR_INCOMPATIBLE_COLLATIONS
Definition: error_code.h:1472
#define QFILE_PUT_LAST_TUPLE_OFFSET(ptr, val)
Definition: query_list.h:129
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
int i
Definition: dynamic_load.c:954
QFILE_LIST_SCAN_ID * s_id
Definition: query_list.h:541
int db_make_null(DB_VALUE *value)
QFILE_LIST_ID * qfile_sort_list(THREAD_ENTRY *thread_p, QFILE_LIST_ID *list_id_p, SORT_LIST *sort_list_p, QUERY_OPTIONS option, bool do_close)
Definition: list_file.c:4030
int qfile_modify_type_list(QFILE_TUPLE_VALUE_TYPE_LIST *type_list_p, QFILE_LIST_ID *list_id_p)
Definition: list_file.c:401
char * pr_valstring(const DB_VALUE *val)
void qfile_close_list(THREAD_ENTRY *thread_p, QFILE_LIST_ID *list_id_p)
Definition: list_file.c:1263
DB_TYPE id
static SCAN_CODE qfile_advance_group(THREAD_ENTRY *thread_p, QFILE_LIST_SCAN_ID *next_scan, QFILE_TUPLE_RECORD *next_tpl, QFILE_LIST_SCAN_ID *last_scan, QFILE_TUPLE_RECORD *last_tpl, QFILE_TUPLE_VALUE_TYPE_LIST *types)
Definition: list_file.c:2456
#define QFILE_TUPLE_COUNT_OFFSET
Definition: query_list.h:50
#define DB_IS_NULL(value)
Definition: dbtype.h:63
static int qfile_compare_tuple_values(QFILE_TUPLE tplp1, QFILE_TUPLE tplp2, TP_DOMAIN *domain, int *cmp)
Definition: list_file.c:744
int qfile_unify_types(QFILE_LIST_ID *list_id1_p, const QFILE_LIST_ID *list_id2_p)
Definition: list_file.c:826
void qfile_finalize(void)
Definition: list_file.c:1117
#define ER_ARG_CAN_NOT_BE_CASTED_TO_DESIRED_DOMAIN
Definition: error_code.h:1419
#define QFILE_GET_LAST_TUPLE_OFFSET(ptr)
Definition: query_list.h:76
#define NULL_VOLID
int qfile_initialize(void)
Definition: list_file.c:1095
#define IO_MAX_PAGE_SIZE
static QFILE_LIST_CACHE_ENTRY * qfile_allocate_list_cache_entry(int req_size)
Definition: list_file.c:5113
#define POOLED_LIST_CACHE_ENTRY_FROM_LIST_CACHE_ENTRY(p)
Definition: list_file.c:127
#define QFILE_OUTER_LIST
Definition: query_list.h:491
short volid
Definition: dbtype_def.h:887
INT32 PAGEID
#define INIT_XASL_NODE_HEADER(X)
Definition: xasl.h:98
SORT_NULLS s_nulls
Definition: query_list.h:418
#define DONT_FREE
Definition: page_buffer.h:41
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 bool qfile_is_first_tuple(QFILE_LIST_ID *list_id_p)
Definition: list_file.c:1339
static int qfile_copy_tuple(THREAD_ENTRY *thread_p, QFILE_LIST_ID *to_list_id_p, QFILE_LIST_ID *from_list_id_p)
Definition: list_file.c:2886
Definition: list_file.c:149
#define QFILE_GET_TUPLE_COUNT(ptr)
Definition: query_list.h:67
#define QFILE_GET_NEXT_VPID(des, ptr)
Definition: query_list.h:104
int qfile_finalize_list_cache(THREAD_ENTRY *thread_p)
Definition: list_file.c:5010
#define NULL_PAGEID_IN_PROGRESS
Definition: query_manager.h:50
QFILE_LIST_CACHE_ENTRY * qcache
Definition: list_file.c:87
#define db_private_realloc(thrd, ptr, size)
Definition: memory_alloc.h:231
#define PEEK
Definition: file_io.h:74
int SORT_CMP_FUNC(const void *, const void *, void *)
Definition: external_sort.h:61
#define QFILE_PUT_TUPLE_LENGTH(tpl, val)
Definition: query_list.h:244
#define VPID_SET_NULL(vpid_ptr)
Definition: dbtype_def.h:906
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
REGU_VARIABLE_LIST valptrp
Definition: regu_var.hpp:116
static int qfile_assign_list_cache(void)
DB_VALUE_COMPARE_RESULT(* sort_f)(void *tplp1, void *tplp2, TP_DOMAIN *dom, int do_coercion, int total_order, int *start_col)
unsigned int lookup_counter
Definition: list_file.c:102
BH_CMP_RESULT
Definition: binaryheap.h:42
SORT_STATUS SORT_GET_FUNC(THREAD_ENTRY *thread_p, RECDES *, void *)
Definition: external_sort.h:59
#define qmgr_free_old_page_and_init(thread_p, page_p, tfile_vfidp)
Definition: query_manager.h:42
QFILE_LIST_MERGE_INFO * merge_info
Definition: query_list.h:382
const char ** p
Definition: dynamic_load.c:945
int or_advance(OR_BUF *buf, int offset)
int qfile_clear_list_cache(THREAD_ENTRY *thread_p, int list_ht_no)
Definition: list_file.c:5053
int qfile_compare_partial_sort_record(const void *pk0, const void *pk1, void *arg)
Definition: list_file.c:3508
static int qfile_add_two_tuple(THREAD_ENTRY *thread_p, QFILE_LIST_ID *dst, QFILE_TUPLE lhs, QFILE_TUPLE rhs)
Definition: list_file.c:2528
LF_TRAN_SYSTEM free_sort_list_Ts
Definition: lock_free.c:51
#define QFILE_GET_OVERFLOW_PAGE_ID(ptr)
Definition: query_list.h:79
QMGR_QUERY_ENTRY * qmgr_get_query_entry(THREAD_ENTRY *thread_p, QUERY_ID query_id, int tran_index)
int mht_compare_dbvalues_are_equal(const void *key1, const void *key2)
Definition: memory_hash.c:791
#define TP_DOMAIN_COLLATION_FLAG(dom)
int qfile_add_tuple_to_list(THREAD_ENTRY *thread_p, QFILE_LIST_ID *list_id_p, QFILE_TUPLE tuple)
Definition: list_file.c:1511
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
QUERY_OPTIONS