CUBRID Engine  latest
query_hash_scan.c
Go to the documentation of this file.
1 /*
2  * Copyright 2016 CUBRID Corporation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17 
18 //
19 // query_hash_scan - implementation of hash list scan during queries
20 //
21 
22 #include "fetch.h"
23 #include "memory_alloc.h"
24 #include "memory_hash.h"
25 #include "object_domain.h"
26 #include "object_primitive.h"
27 #include "object_representation.h"
28 #include "query_opfunc.h"
29 #include "string_opfunc.h"
30 #include "query_hash_scan.h"
31 #include "db_value_printer.hpp"
32 #include "dbtype.h"
33 
34 static bool safe_memcpy (void *data, void *source, int size);
35 static DB_VALUE_COMPARE_RESULT qdata_hscan_key_compare (HASH_SCAN_KEY * ckey1, HASH_SCAN_KEY * ckey2, int *diff_pos);
36 
37 /*
38  * qdata_alloc_hscan_key () - allocate new hash key
39  * returns: pointer to new structure or NULL on error
40  * thread_p(in): thread
41  * val_cnt(in): size of key
42  * alloc_vals(in): if true will allocate dbvalues
43  */
45 qdata_alloc_hscan_key (cubthread::entry * thread_p, int val_cnt, bool alloc_vals)
46 {
47  HASH_SCAN_KEY *key;
48  int i;
49 
50  key = (HASH_SCAN_KEY *) db_private_alloc (thread_p, sizeof (HASH_SCAN_KEY));
51  if (key == NULL)
52  {
54  return NULL;
55  }
56 
57  key->values = (DB_VALUE **) db_private_alloc (thread_p, sizeof (DB_VALUE *) * val_cnt);
58  if (key->values == NULL)
59  {
60  db_private_free (thread_p, key);
62  return NULL;
63  }
64 
65  if (alloc_vals)
66  {
67  for (i = 0; i < val_cnt; i++)
68  {
69  key->values[i] = pr_make_value ();
70  if (key->values[i] == NULL)
71  {
72  key->free_values = true;
73  qdata_free_hscan_key (thread_p, key, i);
75  return NULL;
76  }
77  }
78  }
79 
80  key->val_count = val_cnt;
81  key->free_values = alloc_vals;
82  return key;
83 }
84 
85 /*
86  * qdata_free_hscan_key () - free hash key
87  * thread_p(in): thread
88  * key(in): hash key
89  */
90 void
91 qdata_free_hscan_key (cubthread::entry * thread_p, HASH_SCAN_KEY * key, int val_count)
92 {
93  if (key == NULL)
94  {
95  return;
96  }
97 
98  if (key->values != NULL)
99  {
100  if (key->free_values)
101  {
102  for (int i = 0; i < val_count; i++)
103  {
104  if (key->values[i])
105  {
106  pr_free_value (key->values[i]);
107  }
108  }
109  }
110 
111  /* free values array */
112  db_private_free (thread_p, key->values);
113  }
114 
115  /* free structure */
116  db_private_free (thread_p, key);
117 }
118 
119 /*
120  * qdata_hash_scan_key () - compute hash of aggregate key
121  * returns: hash value
122  * key(in): key
123  * ht_size(in): hash table size (in buckets)
124  */
125 unsigned int
126 qdata_hash_scan_key (const void *key, unsigned int ht_size)
127 {
128  HASH_SCAN_KEY *ckey = (HASH_SCAN_KEY *) key;
129  unsigned int hash_val = 0, tmp_hash_val;
130  int i;
131 
132  /* build hash value */
133  for (i = 0; i < ckey->val_count; i++)
134  {
135  tmp_hash_val = mht_get_hash_number (ht_size, ckey->values[i]);
136  hash_val = hash_val ^ tmp_hash_val;
137  if (hash_val == 0)
138  {
139  hash_val = tmp_hash_val;
140  }
141  }
142 
143  return hash_val;
144 }
145 
146 /*
147  * qdata_hscan_key_compare () - compare two aggregate keys
148  * returns: comparison result
149  * key1(in): first key
150  * key2(in): second key
151  * diff_pos(out): if not equal, position of difference, otherwise -1
152  */
154 qdata_hscan_key_compare (HASH_SCAN_KEY * ckey1, HASH_SCAN_KEY * ckey2, int *diff_pos)
155 {
157  int i;
158 
159  assert (diff_pos);
160  *diff_pos = -1;
161 
162  if (ckey1 == ckey2)
163  {
164  /* same pointer, same values */
165  return DB_EQ;
166  }
167 
168  if (ckey1->val_count != ckey2->val_count)
169  {
170  /* can't compare keys of different sizes; shouldn't get here */
171  assert (false);
172  return DB_UNK;
173  }
174 
175  for (i = 0; i < ckey1->val_count; i++)
176  {
177  result = tp_value_compare (ckey1->values[i], ckey2->values[i], 0, 1);
178  if (result != DB_EQ)
179  {
180  *diff_pos = i;
181  return result;
182  }
183  }
184 
185  /* if we got this far, it's equal */
186  return DB_EQ;
187 }
188 
189 /*
190  * qdata_hscan_key_eq () - check equality of two aggregate keys
191  * returns: true if equal, false otherwise
192  * key1(in): first key
193  * key2(in): second key
194  */
195 int
196 qdata_hscan_key_eq (const void *key1, const void *key2)
197 {
198  int decoy;
199 
200  /* compare for equality */
201  return (qdata_hscan_key_compare ((HASH_SCAN_KEY *) key1, (HASH_SCAN_KEY *) key2, &decoy) == DB_EQ);
202 }
203 
204 /*
205  * qdata_build_hscan_key () - build aggregate key structure from reguvar list
206  * returns: NO_ERROR or error code
207  * thread_p(in): thread
208  * key(out): aggregate key
209  * regu_list(in): reguvar list for fetching values
210  */
211 int
213 {
214  int rc = NO_ERROR;
215 
216  /* build key */
217  key->free_values = false; /* references precreated DB_VALUES */
218  key->val_count = 0;
219  while (regu_list != NULL)
220  {
221  rc = fetch_peek_dbval (thread_p, &regu_list->value, vd, NULL, NULL, NULL, &key->values[key->val_count]);
222  if (rc != NO_ERROR)
223  {
224  return rc;
225  }
226 
227  /* next */
228  regu_list = regu_list->next;
229  key->val_count++;
230  }
231 
232  /* all ok */
233  return NO_ERROR;
234 }
235 
236 /*
237  * qdata_print_hash_scan_entry () - Print the entry
238  * Will be used by mht_dump() function
239  * return:
240  * fp(in) :
241  * key(in) :
242  * data(in) :
243  * args(in) :
244  */
245 int
246 qdata_print_hash_scan_entry (THREAD_ENTRY * thread_p, FILE * fp, const void *data, void *args)
247 {
248  HASH_SCAN_VALUE *data2 = (HASH_SCAN_VALUE *) data;
249  int hash_list_scan_yn = args ? *((int *) args) : 0;
250 
251  if (data2 == NULL || args == NULL)
252  {
253  return false;
254  }
255  if (fp == NULL)
256  {
257  fp = stdout;
258  }
259 
260  fprintf (fp, "LIST_CACHE_ENTRY (%p) {\n", data);
261  if (hash_list_scan_yn == HASH_METH_IN_MEM)
262  {
263  fprintf (fp, "data_size = [%d] data = [%.*s]\n", QFILE_GET_TUPLE_LENGTH (data2->tuple),
264  QFILE_GET_TUPLE_LENGTH (data2->tuple), data2->tuple);
265  }
266  else if (hash_list_scan_yn == HASH_METH_HYBRID)
267  {
268  fprintf (fp, "pageid = [%d] volid = [%d] offset = [%d]\n", data2->pos->vpid.pageid,
269  data2->pos->vpid.volid, data2->pos->offset);
270  }
271 
272  fprintf (fp, "\n}");
273 
274  return true;
275 }
276 
277 /*
278  * qdata_copy_hscan_key () - deep copy hash key
279  * returns: pointer to new hash key
280  * thread_p(in): thread
281  * key(in): source key
282  */
285  val_descr * vd)
286 {
287  HASH_SCAN_KEY *new_key = NULL;
288  int i = 0;
289  DB_TYPE vtype1, vtype2;
291 
292  if (key)
293  {
294  /* make a copy */
295  new_key = qdata_alloc_hscan_key (thread_p, key->val_count, false);
296  }
297 
298  if (new_key)
299  {
300  /* copy values */
301  new_key->val_count = key->val_count;
302  new_key->free_values = true;
303  for (i = 0; i < key->val_count; i++)
304  {
305  vtype1 = REGU_VARIABLE_GET_TYPE (&probe_regu_list->value);
306  vtype2 = DB_VALUE_DOMAIN_TYPE (key->values[i]);
307 
308  if (vtype1 != vtype2)
309  {
310  new_key->values[i] = pr_make_value ();
311  if (new_key->values[i] == NULL)
312  {
313  qdata_free_hscan_key (thread_p, new_key, i);
315  return NULL;
316  }
317 
318  status = tp_value_coerce (key->values[i], new_key->values[i], probe_regu_list->value.domain);
319  if (status != DOMAIN_COMPATIBLE)
320  {
321  qdata_free_hscan_key (thread_p, new_key, ++i);
323  pr_type_name (vtype1));
324  return NULL;
325  }
326  }
327  else
328  {
329  new_key->values[i] = pr_copy_value (key->values[i]);
330  if (new_key->values[i] == NULL)
331  {
332  qdata_free_hscan_key (thread_p, new_key, i);
334  return NULL;
335  }
336  }
337  probe_regu_list = probe_regu_list->next;
338  }
339  }
340 
341  return new_key;
342 }
343 
344 /*
345  * qdata_copy_hscan_key_without_alloc () - deep copy hash key
346  * returns: pointer to new hash key
347  * thread_p(in): thread
348  * key(in): source key
349  */
352  HASH_SCAN_KEY * new_key)
353 {
354  DB_TYPE vtype1, vtype2;
356 
357  if (key == NULL)
358  {
359  return NULL;
360  }
361  if (new_key)
362  {
363  /* copy values */
364  new_key->val_count = key->val_count;
365  for (int i = 0; i < key->val_count; i++)
366  {
367  vtype1 = REGU_VARIABLE_GET_TYPE (&probe_regu_list->value);
368  vtype2 = DB_VALUE_DOMAIN_TYPE (key->values[i]);
369 
370  if (vtype1 != vtype2)
371  {
372  pr_clear_value (new_key->values[i]);
373  status = tp_value_coerce (key->values[i], new_key->values[i], probe_regu_list->value.domain);
374  if (status != DOMAIN_COMPATIBLE)
375  {
377  pr_type_name (vtype1));
378  return NULL;
379  }
380  }
381  else
382  {
383  pr_clear_value (new_key->values[i]);
384  if (pr_clone_value (key->values[i], new_key->values[i]) != NO_ERROR)
385  {
387  return NULL;
388  }
389  }
390  probe_regu_list = probe_regu_list->next;
391  }
392  }
393 
394  return new_key;
395 }
396 
397 /*
398  * qdata_alloc_hscan_value () - allocate new hash value
399  * returns: pointer to new structure or NULL on error
400  * thread_p(in): thread
401  */
404 {
405  HASH_SCAN_VALUE *value;
406  int tuple_size = QFILE_GET_TUPLE_LENGTH (tpl);
407 
408  /* alloc structure */
409  value = (HASH_SCAN_VALUE *) db_private_alloc (thread_p, sizeof (HASH_SCAN_VALUE));
410  if (value == NULL)
411  {
413  return NULL;
414  }
415 
416  value->tuple = (QFILE_TUPLE) db_private_alloc (thread_p, tuple_size);
417  if (value->tuple == NULL)
418  {
419  qdata_free_hscan_value (thread_p, value);
421  return NULL;
422  }
423  /* save tuple */
424  if (!safe_memcpy (value->tuple, tpl, tuple_size))
425  {
426  qdata_free_hscan_value (thread_p, value);
427  return NULL;
428  }
429  return value;
430 }
431 
432 /*
433  * qdata_alloc_hscan_value_OID () - allocate new hash OID value
434  * returns: pointer to new structure or NULL on error
435  * thread_p(in): thread
436  */
439 {
440  HASH_SCAN_VALUE *value;
441 
442  /* alloc structure */
443  value = (HASH_SCAN_VALUE *) db_private_alloc (thread_p, sizeof (HASH_SCAN_VALUE));
444  if (value == NULL)
445  {
447  return NULL;
448  }
449 
450  value->pos = (QFILE_TUPLE_SIMPLE_POS *) db_private_alloc (thread_p, sizeof (QFILE_TUPLE_SIMPLE_POS));
451  if (value->pos == NULL)
452  {
453  qdata_free_hscan_value (thread_p, value);
455  return NULL;
456  }
457 
458  /* save position */
459  value->pos->offset = scan_id_p->curr_offset;
460  value->pos->vpid = scan_id_p->curr_vpid;
461 
462  return value;
463 }
464 
465 static bool
466 safe_memcpy (void *data, void *source, int size)
467 {
468  if (size < 0)
469  {
470  return false;
471  }
472  memcpy (data, source, (size_t) size);
473  return true;
474 }
475 
476 /*
477  * qdata_free_hscan_value () - free hash value
478  * thread_p(in): thread
479  * key(in): hash value
480  */
481 void
483 {
484  if (value == NULL)
485  {
486  return;
487  }
488 
489  /* free values */
490  if (value->data != NULL)
491  {
492  db_private_free_and_init (thread_p, value->data);
493  }
494  /* free structure */
495  db_private_free_and_init (thread_p, value);
496 }
497 
498 /*
499  * qdata_free_agg_hentry () - free key-value pair of hash entry
500  * returns: error code or NO_ERROR
501  * key(in): key pointer
502  * data(in): value pointer
503  * args(in): args passed by mht_rem (should be null)
504  */
505 int
506 qdata_free_hscan_entry (const void *key, void *data, void *args)
507 {
508  /* free key */
510  key ? ((HASH_SCAN_KEY *) key)->val_count : 0);
511 
512  /* free tuple */
514 
515  /* all ok */
516  return NO_ERROR;
517 }
unsigned int qdata_hash_scan_key(const void *key, unsigned int ht_size)
HASH_SCAN_VALUE * qdata_alloc_hscan_value(cubthread::entry *thread_p, QFILE_TUPLE tpl)
TP_DOMAIN_STATUS tp_value_coerce(const DB_VALUE *src, DB_VALUE *dest, const TP_DOMAIN *desired_domain)
DB_TYPE REGU_VARIABLE_GET_TYPE(const regu_variable_node *regu)
Definition: regu_var.hpp:271
#define ER_TP_CANT_COERCE
Definition: error_code.h:250
#define NO_ERROR
Definition: error_code.h:46
HASH_SCAN_KEY * qdata_alloc_hscan_key(cubthread::entry *thread_p, int val_cnt, bool alloc_vals)
DB_VALUE_COMPARE_RESULT tp_value_compare(const DB_VALUE *value1, const DB_VALUE *value2, int allow_coercion, int total_order)
db_value ** values
DB_VALUE * pr_make_value(void)
void qdata_free_hscan_value(cubthread::entry *thread_p, HASH_SCAN_VALUE *value)
HASH_SCAN_KEY * qdata_copy_hscan_key_without_alloc(cubthread::entry *thread_p, HASH_SCAN_KEY *key, REGU_VARIABLE_LIST probe_regu_list, HASH_SCAN_KEY *new_key)
HASH_SCAN_VALUE * qdata_alloc_hscan_value_OID(cubthread::entry *thread_p, QFILE_LIST_SCAN_ID *scan_id_p)
QFILE_TUPLE_SIMPLE_POS * pos
static bool safe_memcpy(void *data, void *source, int size)
void qdata_free_hscan_key(cubthread::entry *thread_p, HASH_SCAN_KEY *key, int val_count)
DB_TYPE
Definition: dbtype_def.h:670
REGU_VARIABLE_LIST next
Definition: regu_var.hpp:221
HASH_SCAN_KEY * qdata_copy_hscan_key(cubthread::entry *thread_p, HASH_SCAN_KEY *key, REGU_VARIABLE_LIST probe_regu_list, val_descr *vd)
int32_t pageid
Definition: dbtype_def.h:879
int qdata_free_hscan_entry(const void *key, void *data, void *args)
enum tp_domain_status TP_DOMAIN_STATUS
void THREAD_ENTRY
int pr_free_value(DB_VALUE *value)
void er_set(int severity, const char *file_name, const int line_no, int err_id, int num_args,...)
#define assert(x)
int qdata_print_hash_scan_entry(THREAD_ENTRY *thread_p, FILE *fp, const void *data, void *args)
#define ER_OUT_OF_VIRTUAL_MEMORY
Definition: error_code.h:50
REGU_VARIABLE value
Definition: regu_var.hpp:222
int fetch_peek_dbval(THREAD_ENTRY *thread_p, REGU_VARIABLE *regu_var, val_descr *vd, OID *class_oid, OID *obj_oid, QFILE_TUPLE tpl, DB_VALUE **peek_dbval)
Definition: fetch.c:3773
#define DB_VALUE_DOMAIN_TYPE(value)
Definition: dbtype.h:70
short volid
Definition: dbtype_def.h:880
DB_VALUE * pr_copy_value(DB_VALUE *value)
#define NULL
Definition: freelistheap.h:34
#define QFILE_GET_TUPLE_LENGTH(tpl)
Definition: query_list.h:238
const char * pr_type_name(DB_TYPE id)
#define db_private_free_and_init(thrd, ptr)
Definition: memory_alloc.h:141
#define db_private_free(thrd, ptr)
Definition: memory_alloc.h:229
#define db_private_alloc(thrd, size)
Definition: memory_alloc.h:227
int pr_clear_value(DB_VALUE *value)
static DB_VALUE_COMPARE_RESULT qdata_hscan_key_compare(HASH_SCAN_KEY *ckey1, HASH_SCAN_KEY *ckey2, int *diff_pos)
static int rc
Definition: serial.c:50
#define ARG_FILE_LINE
Definition: error_manager.h:44
unsigned int mht_get_hash_number(const int ht_size, const DB_VALUE *val)
Definition: memory_hash.c:2275
int pr_clone_value(const DB_VALUE *src, DB_VALUE *dest)
char * QFILE_TUPLE
Definition: query_list.h:281
int qdata_hscan_key_eq(const void *key1, const void *key2)
int i
Definition: dynamic_load.c:954
DB_VALUE_COMPARE_RESULT
Definition: dbtype_def.h:199
int qdata_build_hscan_key(THREAD_ENTRY *thread_p, val_descr *vd, REGU_VARIABLE_LIST regu_list, HASH_SCAN_KEY *key)
QFILE_TUPLE tuple