CUBRID Engine  latest
partition.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  * partition_sr.c - partition pruning on server
21  */
22 
23 #include <assert.h>
24 #include "partition_sr.h"
25 
26 #include "dbtype.h"
27 #include "fetch.h"
28 #include "heap_file.h"
29 #include "object_primitive.h"
30 #include "object_representation.h"
31 #include "query_aggregate.hpp"
32 #include "query_executor.h"
33 #include "query_opfunc.h"
34 #include "stream_to_xasl.h"
35 #include "xasl.h"
36 #include "xasl_predicate.hpp"
37 #include "xasl_unpack_info.hpp"
38 
39 typedef enum match_status
40 {
41  MATCH_OK, /* no partitions contain usable data */
42  MATCH_NOT_FOUND /* search condition does not refer partition expression */
43 } MATCH_STATUS;
44 
45 typedef enum pruning_op
46 {
57 } PRUNING_OP;
58 
59 #define NELEMENTS 1024 /* maximum number of partitions */
60 #define _WORDSIZE 8 * sizeof(int)
61 
62 #define MAX_ELEMENTS 1024
63 #define BITSET_WORD_SIZE sizeof (unsigned int)
64 #define BITS_IN_WORD (8 * BITSET_WORD_SIZE)
65 #define BITSET_WORD_COUNT (MAX_ELEMENTS / BITS_IN_WORD)
66 #define BITSET_LENGTH(s) ((((s)->count - 1) / BITS_IN_WORD)+1)
67 
70 {
71  unsigned int set[BITSET_WORD_COUNT];
72  int count;
73 };
74 
77 {
78  const PRUNING_BITSET *set;
79  int next;
80 };
81 
82 #define PARTITIONS_COUNT(pinfo) (((pinfo) == NULL) ? 0 : (pinfo)->count - 1)
83 
84 #define PARTITION_CACHE_NAME "Partitions_Cache"
85 #define PARTITION_CACHE_SIZE 200
86 
87 /* partition cache hash table */
89 
90 #define PARTITION_IS_CACHE_INITIALIZED() (db_Partition_Ht != NULL)
91 
94 {
95  OID class_oid; /* root class OID */
96 
97  OR_PARTITION *partitions; /* partitions information */
98  int count; /* number of partitions */
99 
100  ATTR_ID attr_id; /* attribute id of the partitioning key */
101 };
102 
103 /* PRUNING_BITSET operations */
104 static void pruningset_init (PRUNING_BITSET *, int);
105 static void pruningset_set_all (PRUNING_BITSET *);
106 static void pruningset_copy (PRUNING_BITSET *, const PRUNING_BITSET *);
107 static void pruningset_add (PRUNING_BITSET *, int);
108 static void pruningset_remove (PRUNING_BITSET *, int);
109 static void pruningset_intersect (PRUNING_BITSET *, const PRUNING_BITSET *);
110 static void pruningset_union (PRUNING_BITSET *, const PRUNING_BITSET *);
111 static bool pruningset_is_set (const PRUNING_BITSET *, int);
112 static int pruningset_popcount (const PRUNING_BITSET *);
115 static int pruningset_to_spec_list (PRUNING_CONTEXT * pinfo, const PRUNING_BITSET * pruned);
116 
117 /* pruning operations */
118 static int partition_free_cache_entry_kv (const void *key, void *data, void *args);
120 static int partition_cache_pruning_context (PRUNING_CONTEXT * pinfo, bool * already_exists);
121 static bool partition_load_context_from_cache (PRUNING_CONTEXT * pinfo, bool * is_modified);
127 static void partition_set_specified_partition (PRUNING_CONTEXT * pinfo, const OID * partition_oid);
130 static void partition_set_cache_info_for_expr (REGU_VARIABLE * regu_var, ATTR_ID attr_id, HEAP_CACHE_ATTRINFO * info);
131 static MATCH_STATUS partition_match_pred_expr (PRUNING_CONTEXT * pinfo, const PRED_EXPR * pr, PRUNING_BITSET * pruned);
132 static MATCH_STATUS partition_match_index_key (PRUNING_CONTEXT * pinfo, const KEY_INFO * key, RANGE_TYPE range_type,
133  PRUNING_BITSET * pruned);
134 static MATCH_STATUS partition_match_key_range (PRUNING_CONTEXT * pinfo, const KEY_RANGE * range,
135  PRUNING_BITSET * pruned);
136 static bool partition_do_regu_variables_match (PRUNING_CONTEXT * pinfo, const REGU_VARIABLE * left,
137  const REGU_VARIABLE * right);
138 static MATCH_STATUS partition_prune (PRUNING_CONTEXT * pinfo, const REGU_VARIABLE * arg, const PRUNING_OP op,
139  PRUNING_BITSET * pruned);
140 static MATCH_STATUS partition_prune_db_val (PRUNING_CONTEXT * pinfo, const DB_VALUE * val, const PRUNING_OP op,
141  PRUNING_BITSET * pruned);
142 static int partition_get_value_from_key (PRUNING_CONTEXT * pinfo, const REGU_VARIABLE * key, DB_VALUE * attr_key,
143  bool * is_present);
144 static int partition_get_value_from_inarith (PRUNING_CONTEXT * pinfo, const REGU_VARIABLE * src, DB_VALUE * value_p,
145  bool * is_present);
146 static int partition_get_value_from_regu_var (PRUNING_CONTEXT * pinfo, const REGU_VARIABLE * key, DB_VALUE * value_p,
147  bool * is_value);
148 static MATCH_STATUS partition_prune_range (PRUNING_CONTEXT * pinfo, const DB_VALUE * val, const PRUNING_OP op,
149  PRUNING_BITSET * pruned);
150 static MATCH_STATUS partition_prune_list (PRUNING_CONTEXT * pinfo, const DB_VALUE * val, const PRUNING_OP op,
151  PRUNING_BITSET * pruned);
152 static MATCH_STATUS partition_prune_hash (PRUNING_CONTEXT * pinfo, const DB_VALUE * val, const PRUNING_OP op,
153  PRUNING_BITSET * pruned);
154 static int partition_find_partition_for_record (PRUNING_CONTEXT * pinfo, const OID * class_oid, RECDES * recdes,
155  OID * partition_oid, HFID * partition_hfid);
156 static int partition_prune_heap_scan (PRUNING_CONTEXT * pinfo);
157 
158 static int partition_prune_index_scan (PRUNING_CONTEXT * pinfo);
159 
160 static int partition_find_inherited_btid (THREAD_ENTRY * thread_p, OID * src_class, OID * dest_class, BTID * src_btid,
161  BTID * dest_btid);
162 static int partition_attrinfo_get_key (THREAD_ENTRY * thread_p, PRUNING_CONTEXT * pcontext, DB_VALUE * curr_key,
163  OID * class_oid, BTID * btid, DB_VALUE * partition_key);
164 
165 /* misc pruning functions */
166 static bool partition_decrement_value (DB_VALUE * val);
167 
168 
169 /* PRUNING_BITSET manipulation functions */
170 
171 /*
172  * pruningset_init () - initialize a PRUNING_BITSET object
173  * return : void
174  * s (in/out) : PRUNING_BITSET object
175  * count (in) : number of elements
176  */
177 static void
179 {
180  s->count = count;
181  memset (s->set, 0, BITSET_WORD_COUNT * BITSET_WORD_SIZE);
182 }
183 
184 /*
185  * pruningset_set_all () - set all bits in in a PRUNING_BITSET
186  * return : void
187  * set (in/out) : PRUNING_BITSET object
188  */
189 static void
191 {
192  memset (set->set, (~0), BITSET_WORD_COUNT * BITSET_WORD_SIZE);
193 }
194 
195 /*
196  * pruningset_copy () - copy a PRUNING_BITSET
197  * return : void
198  * dest (in/out) : destination
199  * src (in) : source
200  */
201 static void
203 {
204  unsigned int i;
205 
206  pruningset_init (dest, src->count);
207 
208  for (i = 0; i < BITSET_LENGTH (dest); i++)
209  {
210  dest->set[i] = src->set[i];
211  }
212 }
213 
214 /*
215  * pruningset_add () - add an element
216  * return : void
217  * s (in/out) : PRUNING_BITSET object
218  * i (in) : element to add
219  */
220 static void
222 {
223  s->set[i / BITS_IN_WORD] |= (1 << (i % BITS_IN_WORD));
224 }
225 
226 /*
227  * pruningset_remove () - remove an element
228  * return : void
229  * s (in/out) : PRUNING_BITSET object
230  * i (in) : element to remove
231  */
232 static void
234 {
235  s->set[i / BITS_IN_WORD] &= ~(1 << (i % BITS_IN_WORD));
236 }
237 
238 /*
239  * pruningset_intersect () - perform intersection on two PRUNING_BITSET
240  * objects
241  * return : void
242  * left (in/out) :
243  * right (in) :
244  */
245 static void
247 {
248  unsigned int i;
249 
250  for (i = 0; i < BITSET_LENGTH (left); i++)
251  {
252  left->set[i] &= right->set[i];
253  }
254 }
255 
256 /*
257  * pruningset_union () - perform intersection on two PRUNING_BITSET objects
258  * return : void
259  * left (in/out) :
260  * right (in) :
261  */
262 static void
264 {
265  unsigned int max, i;
266 
267  max = BITSET_LENGTH (left);
268  if (BITSET_LENGTH (left) > BITSET_LENGTH (right))
269  {
270  max = BITSET_LENGTH (right);
271  }
272 
273  for (i = 0; i < max; i++)
274  {
275  left->set[i] |= right->set[i];
276  }
277 }
278 
279 /*
280  * pruningset_is_set () - test if an element is set
281  * return : true if the element is set
282  * s (in) : PRUNING_BITSET object
283  * idx (in) : index to test
284  */
285 static bool
286 pruningset_is_set (const PRUNING_BITSET * s, int idx)
287 {
288  return ((s->set[idx / BITS_IN_WORD] & (1 << (idx % BITS_IN_WORD))) != 0);
289 }
290 
291 /*
292  * pruningset_popcount () - return the number of elements which are set in a
293  * PRUNING_BITSET object
294  * return : number of elements set
295  * s (in) : PRUNING_BITSET object
296  */
297 static int
299 {
300  /* we expect to have only a few bits set, so the Brian Kernighan algorithm should be the fastest. */
301  int count = 0;
302  unsigned i, v;
303 
304  for (i = 0; i < BITSET_LENGTH (s); i++)
305  {
306  v = s->set[i];
307  for (; v != 0; count++)
308  {
309  v &= v - 1;
310  }
311  }
312 
313  if (count > s->count)
314  {
315  return s->count;
316  }
317 
318  return count;
319 }
320 
321 /*
322  * pruningset_iterator_init () - initialize an iterator
323  * return : void
324  * set (in) :
325  * i (in/out) :
326  */
327 static void
329 {
330  i->set = set;
331  i->next = 0;
332 }
333 
334 /*
335  * pruningset_iterator_next () - advance the iterator
336  * return : next element
337  * it (in/out) : iterator
338  */
339 static int
341 {
342  unsigned int i, j;
343  unsigned int word;
344  int pos = 0;
345 
346  if (it->next >= it->set->count)
347  {
348  it->next = -1;
349  return -1;
350  }
351 
352  for (i = it->next / BITS_IN_WORD; i < BITSET_LENGTH (it->set); i++)
353  {
354  if (it->set->set[i] == 0)
355  {
356  continue;
357  }
358 
359  word = it->set->set[i];
360  pos = it->next % BITS_IN_WORD;
361 
362  for (j = pos; j < BITS_IN_WORD; j++)
363  {
364  if ((word & (1 << j)) != 0)
365  {
366  it->next = i * BITS_IN_WORD + j + 1;
367  return (i * BITS_IN_WORD + j);
368  }
369  }
370 
371  it->next = (i + 1) * BITS_IN_WORD;
372  }
373 
374  it->next = -1;
375 
376  return -1;
377 }
378 
379 /*
380  * partition_free_cache_entry_kv () - A callback function to free memory
381  * allocated for a cache entry key and value.
382  * return : error code or NO_ERROR
383  * key (in) :
384  * data (in) :
385  * args (in) :
386  *
387  */
388 static int
389 partition_free_cache_entry_kv (const void *key, void *data, void *args)
390 {
392 }
393 
394 /*
395  * partition_free_cache_entry () - free memory allocated for a cache entry
396  * return : error code or NO_ERROR
397  * entry (in) :
398  *
399  * Note: Since cache entries are not allocated in the private heaps used
400  * by threads, this function changes the private heap of the calling thread
401  * to the '0' heap (to use malloc/free) before actually freeing the memory
402  * and sets it back after it finishes
403  */
404 static int
406 {
407  HL_HEAPID old_heap;
408 
409  /* change private heap */
410  old_heap = db_change_private_heap (NULL, 0);
411 
412  if (entry != NULL)
413  {
414  if (entry->partitions != NULL)
415  {
416  int i;
417 
418  for (i = 0; i < entry->count; i++)
419  {
420  db_seq_free (entry->partitions[i].values);
421  }
422  free_and_init (entry->partitions);
423  }
424 
425  free_and_init (entry);
426  }
427 
428  db_change_private_heap (NULL, old_heap);
429 
430  return NO_ERROR;
431 }
432 
433 /*
434  * partition_cache_entry_to_pruning_context () - create a pruning context from
435  * a cache entry
436  * return : error code or NO_ERROR
437  * pinfo (in/out) : pruning context
438  * entry_p (in) : cache entry
439  *
440  * Note: The cached information is not copied into the curent context, it is
441  * just referenced. This is because the cached information for partitions
442  * represents only schema information and this information cannot be changed
443  * unless the changer has exclusive access to this class. In this case,
444  * other callers do not have access to this area.
445  */
446 static int
448 {
449  assert (pinfo != NULL);
450  assert (entry_p != NULL);
451 
452  pinfo->count = entry_p->count;
453  if (pinfo->count == 0)
454  {
455  assert (false);
457  pinfo->error_code = ER_FAILED;
458  return ER_FAILED;
459  }
460 
461  pinfo->partitions = entry_p->partitions;
462 
463  pinfo->attr_id = entry_p->attr_id;
464 
466 
467  return NO_ERROR;
468 }
469 
470 /*
471  * partition_pruning_context_to_cache_entry () - create a cache entry from
472  * a pruning context
473  * return : cache entry object
474  * pinfo (in) : pruning context
475  */
476 static PARTITION_CACHE_ENTRY *
478 {
479  PARTITION_CACHE_ENTRY *entry_p = NULL;
480  int i = 0;
481  HL_HEAPID old_heap_id = 0;
482 
483  assert (pinfo != NULL);
484 
485  entry_p = (PARTITION_CACHE_ENTRY *) malloc (sizeof (PARTITION_CACHE_ENTRY));
486  if (entry_p == NULL)
487  {
489  pinfo->error_code = ER_FAILED;
490  goto error_return;
491  }
492  entry_p->partitions = NULL;
493  entry_p->count = 0;
494 
495  COPY_OID (&entry_p->class_oid, &pinfo->root_oid);
496  entry_p->attr_id = pinfo->attr_id;
497 
498  entry_p->count = pinfo->count;
499 
500  entry_p->partitions = (OR_PARTITION *) malloc (entry_p->count * sizeof (OR_PARTITION));
501  if (entry_p->partitions == NULL)
502  {
504  entry_p->count * sizeof (PARTITION_CACHE_ENTRY));
505  pinfo->error_code = ER_FAILED;
506  goto error_return;
507  }
508 
509  /* Change private heap to 0 to use malloc/free for entry_p allocated values. These values outlast the current thread
510  * heap */
511  old_heap_id = db_change_private_heap (pinfo->thread_p, 0);
512  for (i = 0; i < entry_p->count; i++)
513  {
514  COPY_OID (&entry_p->partitions[i].class_oid, &pinfo->partitions[i].class_oid);
515 
516  HFID_COPY (&entry_p->partitions[i].class_hfid, &pinfo->partitions[i].class_hfid);
517 
519 
520  entry_p->partitions[i].rep_id = pinfo->partitions[i].rep_id;
521 
522  if (pinfo->partitions[i].values != NULL)
523  {
524  entry_p->partitions[i].values = db_seq_copy (pinfo->partitions[i].values);
525  if (entry_p->partitions[i].values == NULL)
526  {
527  pinfo->error_code = ER_FAILED;
528  goto error_return;
529  }
530  }
531  }
532 
533  /* restore heap id */
534  db_change_private_heap (pinfo->thread_p, old_heap_id);
535 
536  return entry_p;
537 
538 error_return:
539  if (entry_p != NULL)
540  {
541  if (entry_p->partitions != NULL)
542  {
543  int j;
544 
545  for (j = 0; j < i; j++)
546  {
547  if (entry_p->partitions[j].values != NULL)
548  {
549  db_seq_free (entry_p->partitions[j].values);
550  }
551  }
552 
553  free_and_init (entry_p->partitions);
554  }
555 
556  free_and_init (entry_p);
557  }
558 
559  if (old_heap_id != 0)
560  {
561  db_change_private_heap (pinfo->thread_p, old_heap_id);
562  }
563 
564  return NULL;
565 }
566 
567 /*
568  * partition_cache_pruning_context () - cache a pruning context
569  * return : error code or NO_ERROR
570  * pinfo (in) : pruning context
571  * exists (out) : return true if put into cache success,
572  * return false if the key already exists in hash map.
573  */
574 static int
575 partition_cache_pruning_context (PRUNING_CONTEXT * pinfo, bool * already_exists)
576 {
577  PARTITION_CACHE_ENTRY *entry_p = NULL;
578  OID *oid_key = NULL;
579  const void *val;
580 
582  {
583  return NO_ERROR;
584  }
585 
586  assert (pinfo != NULL);
587 
588  /* Check if this class is being modified by this transaction. If this is the case, we can't actually use this cache
589  * entry because the next request might have already modified the partitioning schema and we won't know it */
590  if (log_is_class_being_modified (pinfo->thread_p, &pinfo->root_oid))
591  {
592  return NO_ERROR;
593  }
594 
596  if (entry_p == NULL)
597  {
598  return ER_FAILED;
599  }
600 
601  oid_key = &entry_p->class_oid;
603  {
604  return ER_FAILED;
605  }
606 
607  val = mht_put_if_not_exists (db_Partition_Ht, oid_key, entry_p);
608  if (val == NULL)
609  {
611  return ER_FAILED;
612  }
613 
614  if (val != entry_p)
615  {
616  partition_free_cache_entry (entry_p);
617  *already_exists = true;
618  }
619  else
620  {
621  *already_exists = false;
622  }
623 
625 
626  return NO_ERROR;
627 }
628 
629 /*
630  * partition_load_context_from_cache () - load pruning info from cache
631  * return : true if the pruning context was found in cache, false otherwise
632  * pinfo (in/out) : pruning context
633  * is_modfied (in/out) : true if the class schema is being modified
634  *
635  * Note: If the class schema is being modified by the current transaction, the
636  * cache info is not used since it might not reflect the latest changes.
637  * There is no way that the class schema is being modified by another
638  * transaction than the one which is requesting the current pruning context.
639  * Any schema changes place a X_LOCK on the class and the transaction
640  * performing the operation has exclusive access to it (and implicitly to the
641  * entry in the cache). Because of this, we only have to look for the class
642  * in the modified list of the current transaction. If this changes (classes
643  * are no longer exclusively locked for alter), we have to review this
644  * function.
645  */
646 static bool
648 {
649  PARTITION_CACHE_ENTRY *entry_p = NULL;
650 
652  {
653  return false;
654  }
655 
656  assert (pinfo != NULL);
657 
658  /* Check if this class is being modified by this transaction. If this is the case, we can't actually use this cache
659  * entry because the next request might have already modified the partitioning schema and we won't know it */
660  if (log_is_class_being_modified (pinfo->thread_p, &pinfo->root_oid))
661  {
662  if (is_modfied != NULL)
663  {
664  *is_modfied = true;
665  }
666 
667  return false;
668  }
669 
670  if (is_modfied != NULL)
671  {
672  *is_modfied = false;
673  }
674 
676  {
677  pinfo->error_code = ER_FAILED;
678  return false;
679  }
680 
681  entry_p = (PARTITION_CACHE_ENTRY *) mht_get (db_Partition_Ht, &pinfo->root_oid);
682  if (entry_p == NULL)
683  {
685  return false;
686  }
687 
688  if (partition_cache_entry_to_pruning_context (pinfo, entry_p) != NO_ERROR)
689  {
691  return false;
692  }
693 
695 
696  pinfo->is_from_cache = true;
697 
698  return true;
699 }
700 
701 /*
702  * partition_cache_init () - Initialize partition cache area
703  * return: NO_ERROR or error code
704  * thread_p (in) : thread entry
705  *
706  * Note: Creates and initializes a main memory hash table that will be
707  * used by pruning operations. This routine should only be called once during
708  * server boot.
709  */
710 int
712 {
713  int error = NO_ERROR;
714 
715  er_log_debug (ARG_FILE_LINE, "creating partition cache\n");
716 
718  {
719  return ER_FAILED;
720  }
722  {
723  /* nothing to do */
724  goto cleanup;
725  }
726 
728  if (db_Partition_Ht == NULL)
729  {
730  error = ER_FAILED;
731  goto cleanup;
732  }
733 
734 cleanup:
735  csect_exit (thread_p, CSECT_PARTITION_CACHE);
736 
737  return error;
738 }
739 
740 /*
741  * partition_cache_finalize () - cleanup the partition cache
742  * thread_p (in) : thread entry
743  *
744  * Note: This function deletes the partition cache.
745  * This function should be called only during server shutdown
746  */
747 void
749 {
750  er_log_debug (ARG_FILE_LINE, "deleting partition cache\n");
751 
753  {
754  return;
755  }
756 
758  {
759  (void) mht_map (db_Partition_Ht, partition_free_cache_entry_kv, NULL);
760  mht_destroy (db_Partition_Ht);
761  db_Partition_Ht = NULL;
762  }
763 
764  csect_exit (thread_p, CSECT_PARTITION_CACHE);
765 }
766 
767 /*
768  * partition_decache_class () - remove a class from the partition hash
769  * return : void
770  * thread_p (in) : thread entry
771  * class_oid (in) : class OID
772  *
773  */
774 void
775 partition_decache_class (THREAD_ENTRY * thread_p, const OID * class_oid)
776 {
778  {
779  return;
780  }
781 
783  {
784  return;
785  }
786 
787  (void) mht_rem (db_Partition_Ht, class_oid, partition_free_cache_entry_kv, NULL);
788 
789  csect_exit (thread_p, CSECT_PARTITION_CACHE);
790 }
791 
792 /*
793  * partition_rel_op_to_pruning_op () - convert REL_OP to PRUNING_OP
794  * return : pruning operator
795  * op (in) :
796  */
797 static PRUNING_OP
799 {
800  switch (op)
801  {
802  case R_EQ:
803  case R_EQ_TORDER:
804  case R_NULLSAFE_EQ:
805  return PO_EQ;
806 
807  case R_NE:
808  return PO_NE;
809 
810  case R_GT:
811  return PO_GT;
812 
813  case R_GE:
814  return PO_GE;
815 
816  case R_LT:
817  return PO_LT;
818 
819  case R_LE:
820  return PO_LE;
821 
822  case R_EQ_SOME:
823  return PO_IN;
824 
825  case R_NE_ALL:
826  return PO_NOT_IN;
827 
828  case R_NULL:
829  return PO_IS_NULL;
830 
831  case R_EXISTS:
832  case R_NE_SOME:
833  case R_GT_SOME:
834  case R_GE_SOME:
835  case R_LT_SOME:
836  case R_LE_SOME:
837  case R_EQ_ALL:
838  case R_GT_ALL:
839  case R_GE_ALL:
840  case R_LT_ALL:
841  case R_LE_ALL:
842  case R_SUPERSETEQ:
843  case R_SUBSETEQ:
844  case R_SUPERSET:
845  case R_SUBSET:
846  return PO_INVALID;
847 
848  case R_LIKE:
849  default:
850  return PO_INVALID;
851  }
852 
853  return PO_INVALID;
854 }
855 
856 /*
857  * pruningset_to_spec_list () - convert a pruningset to an array of
858  * PARTITION_SPEC_TYPE elements
859  * return : error code or NO_ERROR
860  * pinfo (in) : pruning context
861  * pruned (in) : pruned partitions
862  */
863 static int
865 {
866  int cnt = 0, i = 0, pos = 0, error = NO_ERROR;
867  PARTITION_SPEC_TYPE *spec = NULL;
868  bool is_index = false;
869  char *btree_name = NULL;
870  OID *master_oid = NULL;
871  BTID *master_btid = NULL;
873 
874  cnt = pruningset_popcount (pruned);
875  if (cnt == 0)
876  {
877  /* pruning did not find any partition, just return */
878  error = NO_ERROR;
879  goto cleanup;
880  }
881 
883  {
884  /* we have to load information about the index used so we can duplicate it for each partition */
885  is_index = true;
886  master_oid = &ACCESS_SPEC_CLS_OID (pinfo->spec);
887  master_btid = &pinfo->spec->indexptr->btid;
888  error =
889  heap_get_indexinfo_of_btid (pinfo->thread_p, master_oid, master_btid, NULL, NULL, NULL, NULL, &btree_name,
890  NULL);
891  if (error != NO_ERROR)
892  {
893  ASSERT_ERROR ();
894  goto cleanup;
895  }
896  }
897 
898  spec = (PARTITION_SPEC_TYPE *) db_private_alloc (pinfo->thread_p, cnt * sizeof (PARTITION_SPEC_TYPE));
899  if (spec == NULL)
900  {
901  assert (false);
902  error = ER_FAILED;
903  goto cleanup;
904  }
905 
906  pruningset_iterator_init (pruned, &it);
907 
908  pos = 0;
909  for (i = 0, pos = pruningset_iterator_next (&it); i < cnt && pos >= 0; i++, pos = pruningset_iterator_next (&it))
910  {
911  COPY_OID (&spec[i].oid, &pinfo->partitions[pos + 1].class_oid);
912  HFID_COPY (&spec[i].hfid, &pinfo->partitions[pos + 1].class_hfid);
913 
914  if (i == cnt - 1)
915  {
916  spec[i].next = NULL;
917  }
918  else
919  {
920  spec[i].next = &spec[i + 1];
921  }
922 
923  if (is_index)
924  {
925  error = heap_get_index_with_name (pinfo->thread_p, &spec[i].oid, btree_name, &spec[i].btid);
926 
927  if (error != NO_ERROR)
928  {
929  ASSERT_ERROR ();
930  goto cleanup;
931  }
932  }
933  }
934 
935 cleanup:
936  if (btree_name != NULL)
937  {
938  /* heap_get_indexinfo_of_btid calls strdup on the index name so we have to free it with free_and_init */
939  free_and_init (btree_name);
940  }
941 
942  pinfo->spec->curent = NULL;
943 
944  if (error != NO_ERROR)
945  {
946  if (spec != NULL)
947  {
948  db_private_free (pinfo->thread_p, spec);
949  }
950  pinfo->spec->parts = NULL;
951  }
952  else
953  {
954  pinfo->spec->parts = spec;
955  }
956 
957  return error;
958 }
959 
960 /*
961  * partition_do_regu_variables_match () - check if two regu variables match
962  * return :
963  * pinfo (in) :
964  * left (in) :
965  * right (in) :
966  */
967 static bool
969 {
970  if (left == NULL || right == NULL)
971  {
972  return left == right;
973  }
974 
975  if (left->type != right->type)
976  {
977  return false;
978  }
979 
980  switch (left->type)
981  {
982  case TYPE_DBVAL:
983  /* use dbval */
984  if (tp_value_compare (&left->value.dbval, &right->value.dbval, 1, 0) != DB_EQ)
985  {
986  return false;
987  }
988  else
989  {
990  return true;
991  }
992 
993  case TYPE_CONSTANT:
994  /* use varptr */
995  if (tp_value_compare (left->value.dbvalptr, right->value.dbvalptr, 1, 1) != DB_EQ)
996  {
997  return false;
998  }
999  else
1000  {
1001  return true;
1002  }
1003 
1004  case TYPE_POS_VALUE:
1005  {
1006  /* use val_pos for host variable references */
1007  DB_VALUE *val_left, *val_right;
1008 
1009  val_left = (DB_VALUE *) pinfo->vd->dbval_ptr + left->value.val_pos;
1010  val_right = (DB_VALUE *) pinfo->vd->dbval_ptr + right->value.val_pos;
1011 
1012  if (tp_value_compare (val_left, val_right, 1, 1) != DB_EQ)
1013  {
1014  return false;
1015  }
1016  else
1017  {
1018  return true;
1019  }
1020  }
1021 
1022  case TYPE_INARITH:
1023  case TYPE_OUTARITH:
1024  /* use arithptr */
1025  if (left->value.arithptr->opcode != right->value.arithptr->opcode)
1026  {
1027  /* different operations */
1028  return false;
1029  }
1030 
1031  /* check misc_operand for EXTRACT, etc */
1032  if (left->value.arithptr->misc_operand != right->value.arithptr->misc_operand)
1033  {
1034  return false;
1035  }
1036 
1037  /* check left operand */
1038  if (!partition_do_regu_variables_match (pinfo, left->value.arithptr->leftptr, right->value.arithptr->leftptr))
1039  {
1040  return false;
1041  }
1042 
1043  /* check right operand */
1044  if (!partition_do_regu_variables_match (pinfo, left->value.arithptr->rightptr, right->value.arithptr->rightptr))
1045  {
1046  return false;
1047  }
1048 
1049  /* check third operand */
1050  if (!partition_do_regu_variables_match (pinfo, left->value.arithptr->thirdptr, right->value.arithptr->thirdptr))
1051  {
1052  return false;
1053  }
1054 
1055  return true;
1056 
1057  case TYPE_ATTR_ID:
1058  /* use attr_descr */
1059  return left->value.attr_descr.id == right->value.attr_descr.id;
1060 
1061  default:
1062  return false;
1063  }
1064 
1065  return false;
1066 }
1067 
1068 /*
1069  * partition_prune_list () - Perform pruning for LIST type partitions
1070  * return : match status
1071  * pinfo (in) : pruning context
1072  * val (in) : the value to which the partition expression is compared
1073  * op (in) : operator to apply
1074  * pruned (in/out): pruned partitions
1075  */
1076 static MATCH_STATUS
1077 partition_prune_list (PRUNING_CONTEXT * pinfo, const DB_VALUE * val, const PRUNING_OP op, PRUNING_BITSET * pruned)
1078 {
1079  OR_PARTITION *part;
1080  int size = 0, i = 0, j;
1081  DB_SEQ *part_collection = NULL;
1082  DB_COLLECTION *val_collection = NULL;
1083  MATCH_STATUS status = MATCH_NOT_FOUND;
1084 
1085  for (i = 0; i < PARTITIONS_COUNT (pinfo); i++)
1086  {
1087  part = &pinfo->partitions[i + 1];
1088  part_collection = part->values;
1089 
1090  size = db_set_size (part_collection);
1091  if (size < 0)
1092  {
1093  return MATCH_NOT_FOUND;
1094  }
1095 
1096  switch (op)
1097  {
1098  case PO_IN:
1099  {
1100  DB_VALUE col;
1101  bool found = false;
1102 
1103  /* Perform intersection on part_values and val. If the result is not empty then this partition should be
1104  * added to the pruned list */
1105  if (!db_value_type_is_collection (val))
1106  {
1107  return MATCH_NOT_FOUND;
1108  }
1109 
1110  val_collection = db_get_set (val);
1111  for (j = 0; j < size; j++)
1112  {
1113  db_set_get (part_collection, j, &col);
1114  if (db_set_ismember (val_collection, &col))
1115  {
1116  pr_clear_value (&col);
1117  found = true;
1118  break;
1119  }
1120  pr_clear_value (&col);
1121  }
1122 
1123  if (found)
1124  {
1125  /* add this partition */
1126  pruningset_add (pruned, i);
1127  }
1128 
1129  status = MATCH_OK;
1130  break;
1131  }
1132 
1133  case PO_NOT_IN:
1134  {
1135  DB_VALUE col;
1136  bool found = false;
1137 
1138  /* Perform intersection on part_values and val. If the result is empty then this partition should be added
1139  * to the pruned list */
1140  if (!db_value_type_is_collection (val))
1141  {
1142  status = MATCH_NOT_FOUND;
1143  }
1144 
1145  val_collection = db_get_set (val);
1146  for (j = 0; j < size; j++)
1147  {
1148  db_set_get (part_collection, j, &col);
1149  if (db_set_ismember (val_collection, &col))
1150  {
1151  pr_clear_value (&col);
1152  found = true;
1153  break;
1154  }
1155  pr_clear_value (&col);
1156  }
1157 
1158  if (!found)
1159  {
1160  /* add this partition */
1161  pruningset_add (pruned, i);
1162  }
1163 
1164  status = MATCH_OK;
1165  break;
1166  }
1167 
1168  case PO_IS_NULL:
1169  /* Add this partition if part_values contains val. */
1170  if (db_set_has_null (part_collection))
1171  {
1172  /* add this partition */
1173  pruningset_add (pruned, i);
1174  /* Since partition values are disjoint sets this is the only possible result */
1175  return MATCH_OK;
1176  }
1177  break;
1178 
1179  case PO_EQ:
1180  /* Add this partition if part_values contains val. */
1181  if (db_set_ismember (part_collection, (DB_VALUE *) val))
1182  {
1183  /* add this partition */
1184  pruningset_add (pruned, i);
1185  /* Since partition values are disjoint sets this is the only possible result */
1186  return MATCH_OK;
1187  }
1188  break;
1189 
1190  case PO_NE:
1191  case PO_LT:
1192  case PO_LE:
1193  case PO_GT:
1194  case PO_GE:
1195  default:
1196  return status = MATCH_NOT_FOUND;
1197  }
1198  }
1199 
1200  return status;
1201 }
1202 
1203 /*
1204  * partition_prune_hash () - Perform pruning for HASH type partitions
1205  * return : match status
1206  * pinfo (in) : pruning context
1207  * val (in) : the value to which the partition expression is compared
1208  * op (in) : operator to apply
1209  * pruned (in/out): pruned partitions
1210  */
1211 static MATCH_STATUS
1212 partition_prune_hash (PRUNING_CONTEXT * pinfo, const DB_VALUE * val_p, const PRUNING_OP op, PRUNING_BITSET * pruned)
1213 {
1214  int idx = 0;
1215  int hash_size = PARTITIONS_COUNT (pinfo);
1216  TP_DOMAIN *col_domain = NULL;
1217  DB_VALUE val;
1218  MATCH_STATUS status = MATCH_NOT_FOUND;
1219 
1220  db_make_null (&val);
1221 
1222  col_domain = pinfo->partition_pred->func_regu->domain;
1223  switch (op)
1224  {
1225  case PO_EQ:
1226  if (TP_DOMAIN_TYPE (col_domain) != DB_VALUE_TYPE (val_p))
1227  {
1228  /* We have a problem here because type checking might not have coerced val to the type of the column. If this
1229  * is the case, we have to do it here */
1230  if (tp_value_cast (val_p, &val, col_domain, false) == DOMAIN_INCOMPATIBLE)
1231  {
1232  /* We cannot set an error here because this is not considered to be an error when scanning regular
1233  * tables. We can consider this predicate to be always false so status to MATCH_OK to simulate the case
1234  * when no appropriate partition was found. */
1235  er_clear ();
1236  status = MATCH_OK;
1237  }
1238  }
1239  else
1240  {
1241  pr_clone_value (val_p, &val);
1242  }
1243 
1244  idx = mht_get_hash_number (hash_size, &val);
1245 
1246  /* Start from 1 because we're using position 0 for the master class */
1247  pruningset_add (pruned, idx);
1248 
1249  status = MATCH_OK;
1250  break;
1251 
1252  case PO_IN:
1253  {
1254  DB_COLLECTION *values = NULL;
1255  int size = 0, i, idx;
1256 
1257  if (!db_value_type_is_collection (val_p))
1258  {
1259  /* This is an error and it should be handled outside of the pruning environment */
1260  status = MATCH_NOT_FOUND;
1261  goto cleanup;
1262  }
1263 
1264  values = db_get_set (val_p);
1265  size = db_set_size (values);
1266  if (size < 0)
1267  {
1268  pinfo->error_code = ER_FAILED;
1269  status = MATCH_NOT_FOUND;
1270  goto cleanup;
1271  }
1272 
1273  for (i = 0; i < size; i++)
1274  {
1275  DB_VALUE col;
1276 
1277  if (db_set_get (values, i, &col) != NO_ERROR)
1278  {
1279  pinfo->error_code = ER_FAILED;
1280  status = MATCH_NOT_FOUND;
1281  goto cleanup;
1282  }
1283 
1284  if (TP_DOMAIN_TYPE (col_domain) != DB_VALUE_TYPE (&col))
1285  {
1286  /* A failed coercion is not an error in this case, we should just skip over it */
1287  if (tp_value_cast (val_p, &val, col_domain, false) == DOMAIN_INCOMPATIBLE)
1288  {
1289  pr_clear_value (&col);
1290  er_clear ();
1291  continue;
1292  }
1293  }
1294 
1295  idx = mht_get_hash_number (hash_size, &col);
1296  pruningset_add (pruned, idx);
1297 
1298  pr_clear_value (&col);
1299  }
1300 
1301  status = MATCH_OK;
1302  break;
1303  }
1304 
1305  case PO_IS_NULL:
1306  /* first partition */
1307  pruningset_add (pruned, 0);
1308  status = MATCH_OK;
1309  break;
1310 
1311  default:
1312  status = MATCH_NOT_FOUND;
1313  break;
1314  }
1315 
1316 cleanup:
1317  pr_clear_value (&val);
1318 
1319  return status;
1320 }
1321 
1322 /*
1323  * partition_prune_range () - Perform pruning for RANGE type partitions
1324  * return : match status
1325  * pinfo (in) : pruning context
1326  * val(in) : the value to which the partition expression is compared
1327  * op (in) : operator to apply
1328  * pruned (in/out) : pruned partitions
1329  */
1330 static MATCH_STATUS
1331 partition_prune_range (PRUNING_CONTEXT * pinfo, const DB_VALUE * val, const PRUNING_OP op, PRUNING_BITSET * pruned)
1332 {
1333  int i = 0, error = NO_ERROR;
1334  int added = 0;
1335  OR_PARTITION *part;
1336  DB_VALUE min, max;
1337  int rmin = DB_UNK, rmax = DB_UNK;
1338  MATCH_STATUS status;
1339 
1340  db_make_null (&min);
1341  db_make_null (&max);
1342 
1343  for (i = 0; i < PARTITIONS_COUNT (pinfo); i++)
1344  {
1345  part = &pinfo->partitions[i + 1];
1346 
1347  pr_clear_value (&min);
1348  pr_clear_value (&max);
1349 
1350  error = db_set_get (part->values, 0, &min);
1351  if (error != NO_ERROR)
1352  {
1353  pinfo->error_code = error;
1354  status = MATCH_NOT_FOUND;
1355  goto cleanup;
1356  }
1357 
1358  error = db_set_get (part->values, 1, &max);
1359  if (error != NO_ERROR)
1360  {
1361  pinfo->error_code = error;
1362  status = MATCH_NOT_FOUND;
1363  goto cleanup;
1364  }
1365 
1366  if (DB_IS_NULL (&min))
1367  {
1368  /* MINVALUE */
1369  rmin = DB_LT;
1370  }
1371  else
1372  {
1373  rmin = tp_value_compare (&min, val, 1, 1);
1374  }
1375 
1376  if (DB_IS_NULL (&max))
1377  {
1378  /* MAXVALUE */
1379  rmax = DB_LT;
1380  }
1381  else
1382  {
1383  if (op == PO_GT)
1384  {
1385  /* Partitioning interval is stored as [min, max). Try to convert it to [min, max--] in order to handle
1386  * some limit cases like val > max-- which should not match any partition */
1387  (void) partition_decrement_value (&max);
1388  }
1389  rmax = tp_value_compare (val, &max, 1, 1);
1390  }
1391 
1392  status = MATCH_OK;
1393  switch (op)
1394  {
1395  case PO_EQ:
1396  /* Filter is part_expr = value. Find the *only* partition for which min <= value < max */
1397  if ((rmin == DB_EQ || rmin == DB_LT) && rmax == DB_LT)
1398  {
1399  pruningset_add (pruned, i);
1400  ++added;
1401  /* no need to look any further */
1402  goto cleanup;
1403  }
1404  break;
1405 
1406  case PO_LT:
1407  /* Filter is part_expr < value. All partitions for which min < value qualify */
1408  if (rmin == DB_LT)
1409  {
1410  pruningset_add (pruned, i);
1411  ++added;
1412  }
1413  break;
1414 
1415  case PO_LE:
1416  /* Filter is part_expr <= value. All partitions for which min <= value qualify */
1417  if (rmin == DB_EQ)
1418  {
1419  /* this is the only partition than can qualify */
1420  pruningset_add (pruned, i);
1421  ++added;
1422  goto cleanup;
1423  }
1424  else if (rmin == DB_LT)
1425  {
1426  pruningset_add (pruned, i);
1427  ++added;
1428  }
1429  break;
1430 
1431  case PO_GT:
1432  /* Filter is part_expr > value. All partitions for which value < max qualify */
1433  if (rmax == DB_LT)
1434  {
1435  pruningset_add (pruned, i);
1436  ++added;
1437  }
1438  break;
1439 
1440  case PO_GE:
1441  /* Filter is part_expr > value. All partitions for which value < max qualify */
1442  if (rmax == DB_LT)
1443  {
1444  pruningset_add (pruned, i);
1445  ++added;
1446  }
1447  break;
1448 
1449  case PO_IS_NULL:
1450  if (DB_IS_NULL (&min))
1451  {
1452  pruningset_add (pruned, i);
1453  ++added;
1454  /* no need to look any further */
1455  goto cleanup;
1456  }
1457  break;
1458 
1459  default:
1460  status = MATCH_NOT_FOUND;
1461  goto cleanup;
1462  }
1463  }
1464 
1465 cleanup:
1466  pr_clear_value (&min);
1467  pr_clear_value (&max);
1468 
1469  if (status == MATCH_OK && added == 0)
1470  {
1471  status = MATCH_NOT_FOUND;
1472  }
1473 
1474  return status;
1475 }
1476 
1477 /*
1478  * partition_prune_db_val () - prune partitions using the given DB_VALUE
1479  * return : match status
1480  * pinfo (in) : pruning context
1481  * val (in) : value to use for pruning
1482  * op (in) : operation to be applied for value
1483  * pruned (in/out) : pruned partitions
1484  */
1485 static MATCH_STATUS
1487 {
1488  switch (pinfo->partition_type)
1489  {
1490  case DB_PARTITION_HASH:
1491  return partition_prune_hash (pinfo, val, op, pruned);
1492 
1493  case DB_PARTITION_RANGE:
1494  return partition_prune_range (pinfo, val, op, pruned);
1495 
1496  case DB_PARTITION_LIST:
1497  return partition_prune_list (pinfo, val, op, pruned);
1498 
1499  default:
1500  return MATCH_NOT_FOUND;
1501  }
1502 
1503  return MATCH_NOT_FOUND;
1504 }
1505 
1506 /*
1507  * partition_prune () - perform pruning on the specified partitions list
1508  * return : match status
1509  * pinfo (in) : pruning context
1510  * val (in) : the value to which the partition expression is compared
1511  * op (in) : operator to apply
1512  * pruned (in/out): pruned partitions
1513  */
1514 static MATCH_STATUS
1515 partition_prune (PRUNING_CONTEXT * pinfo, const REGU_VARIABLE * arg, const PRUNING_OP op, PRUNING_BITSET * pruned)
1516 {
1517  MATCH_STATUS status = MATCH_NOT_FOUND;
1518  DB_VALUE val;
1519  bool is_value = false;
1520 
1521  if (arg == NULL && op != PO_IS_NULL)
1522  {
1523  return MATCH_NOT_FOUND;
1524  }
1525 
1526  if (op == PO_IS_NULL)
1527  {
1528  db_make_null (&val);
1529  is_value = true;
1530  }
1531  else if (partition_get_value_from_regu_var (pinfo, arg, &val, &is_value) != NO_ERROR)
1532  {
1533  /* pruning failed */
1534  pinfo->error_code = ER_FAILED;
1535  return MATCH_NOT_FOUND;
1536  }
1537 
1538  if (!is_value)
1539  {
1540  /* cannot perform pruning */
1541  return MATCH_NOT_FOUND;
1542  }
1543 
1544  status = partition_prune_db_val (pinfo, &val, op, pruned);
1545 
1546  pr_clear_value (&val);
1547 
1548  return status;
1549 }
1550 
1551 /*
1552  * partition_get_value_from_regu_var () - get a DB_VALUE from a REGU_VARIABLE
1553  * return : error code or NO_ERROR
1554  * pinfo (in) : pruning context
1555  * regu (in) : regu variable
1556  * value_p (in/out) : holder for the value of regu
1557  * is_value (in/out): true if the conversion was successful
1558  */
1559 static int
1561  bool * is_value)
1562 {
1563  /* we cannot use fetch_peek_dbval here because we're not inside a scan yet. */
1564  if (regu == NULL)
1565  {
1566  assert (false);
1567  goto error;
1568  }
1569 
1570  switch (regu->type)
1571  {
1572  case TYPE_DBVAL:
1573  if (pr_clone_value (&regu->value.dbval, value_p) != NO_ERROR)
1574  {
1575  goto error;
1576  }
1577  *is_value = true;
1578  break;
1579 
1580  case TYPE_POS_VALUE:
1581  {
1582  DB_VALUE *arg_val = (DB_VALUE *) pinfo->vd->dbval_ptr + regu->value.val_pos;
1583  if (pr_clone_value (arg_val, value_p) != NO_ERROR)
1584  {
1585  goto error;
1586  }
1587  *is_value = true;
1588  break;
1589  }
1590 
1591  case TYPE_FUNC:
1592  {
1593  if (regu->value.funcp->ftype != F_MIDXKEY)
1594  {
1595  *is_value = false;
1596  db_make_null (value_p);
1597  return NO_ERROR;
1598  }
1599  if (partition_get_value_from_key (pinfo, regu, value_p, is_value) != NO_ERROR)
1600  {
1601  goto error;
1602  }
1603  break;
1604  }
1605 
1606  case TYPE_INARITH:
1607  /* We can't evaluate the general form of TYPE_INARITH but we can handle "pseudo constants" (SYS_DATE, SYS_TIME,
1608  * etc) and the CAST operator applied to constants. Eventually, it would be great if we could evaluate all pseudo
1609  * constant here (like cast ('1' as int) + 1) */
1610  if (partition_get_value_from_inarith (pinfo, regu, value_p, is_value) != NO_ERROR)
1611  {
1612  goto error;
1613  }
1614  break;
1615 
1616  default:
1617  db_make_null (value_p);
1618  *is_value = false;
1619  return NO_ERROR;
1620  }
1621 
1622  return NO_ERROR;
1623 
1624 error:
1625  db_make_null (value_p);
1626  *is_value = false;
1627 
1628  return ER_FAILED;
1629 }
1630 
1631 /*
1632  * partition_is_reguvar_const () - test if a regu_variable is a constant
1633  * return : true if constant, false otherwise
1634  * regu_var (in) :
1635  */
1636 static bool
1638 {
1639  if (regu_var == NULL)
1640  {
1641  return false;
1642  }
1643  switch (regu_var->type)
1644  {
1645  case TYPE_DBVAL:
1646  case TYPE_POS_VALUE:
1647  case TYPE_REGUVAL_LIST:
1648  return true;
1649  case TYPE_INARITH:
1650  case TYPE_OUTARITH:
1651  {
1652  ARITH_TYPE *arithptr = regu_var->value.arithptr;
1653  if (arithptr->leftptr != NULL && !partition_is_reguvar_const (arithptr->leftptr))
1654  {
1655  return false;
1656  }
1657  if (arithptr->rightptr != NULL && !partition_is_reguvar_const (arithptr->rightptr))
1658  {
1659  return false;
1660  }
1661 
1662  if (arithptr->thirdptr != NULL && !partition_is_reguvar_const (arithptr->thirdptr))
1663  {
1664  return false;
1665  }
1666  /* either all arguments are constants of this is an expression with no arguments */
1667  return true;
1668  }
1669  default:
1670  return false;
1671  }
1672 }
1673 
1674 /*
1675  * partition_get_value_from_key () - get a value from an index key
1676  * return : error code or NO_ERROR
1677  * pinfo (in) : pruning context
1678  * key (in) : index key
1679  * attr_key (in/out) : the requested value
1680  * is_present (in/out) : set to true if the value was successfully fetched
1681  */
1682 static int
1684  bool * is_present)
1685 {
1686  int error = NO_ERROR;
1687  assert (attr_key != NULL);
1688 
1689  switch (key->type)
1690  {
1691  case TYPE_DBVAL:
1692  pr_clone_value (&key->value.dbval, attr_key);
1693 
1694  *is_present = true;
1695  break;
1696 
1697  case TYPE_POS_VALUE:
1698  {
1699  /* use val_pos for host variable references */
1700  DB_VALUE *val = (DB_VALUE *) pinfo->vd->dbval_ptr + key->value.val_pos;
1701  error = pr_clone_value (val, attr_key);
1702 
1703  *is_present = true;
1704  break;
1705  }
1706 
1707  case TYPE_FUNC:
1708  {
1709  /* this is a F_MIDXKEY function and the value we're interested in is in the operands */
1710  REGU_VARIABLE_LIST regu_list = NULL;
1711  int i;
1712 
1713  if (key->value.funcp->ftype != F_MIDXKEY)
1714  {
1715  assert (false);
1717  return ER_FAILED;
1718  }
1719 
1720  /* loop through arguments of the function and get the MIDX_KEY */
1721  regu_list = key->value.funcp->operand;
1722  for (i = 0; i < pinfo->attr_position; i++)
1723  {
1724  if (regu_list == NULL)
1725  {
1726  /* partition key not referenced in range */
1727  break;
1728  }
1729  regu_list = regu_list->next;
1730  }
1731 
1732  if (regu_list == NULL)
1733  {
1734  db_make_null (attr_key);
1735  error = NO_ERROR;
1736 
1737  *is_present = false;
1738  }
1739  else
1740  {
1741  error = partition_get_value_from_key (pinfo, &regu_list->value, attr_key, is_present);
1742  }
1743  break;
1744  }
1745 
1746  case TYPE_INARITH:
1747  error = partition_get_value_from_regu_var (pinfo, key, attr_key, is_present);
1748  break;
1749 
1750  case TYPE_CONSTANT:
1751  /* TYPE_CONSTANT comes from an index join. Since we haven't actually scanned anything yet, this value is not set
1752  * so we cannot use it here */
1753  db_make_null (attr_key);
1754  error = NO_ERROR;
1755  *is_present = false;
1756  break;
1757 
1758  default:
1759  assert (false);
1760 
1761  db_make_null (attr_key);
1762 
1764  error = ER_FAILED;
1765 
1766  *is_present = false;
1767  break;
1768  }
1769 
1770  return error;
1771 }
1772 
1773 /*
1774  * partition_get_value_from_key () - get a value from a reguvariable of type
1775  * INARITH
1776  * return : error code or NO_ERROR
1777  * pinfo (in) : pruning context
1778  * src (in) : source reguvariable
1779  * value_p (in/out) : the requested value
1780  * is_value (in/out) : set to true if the value was successfully fetched
1781  *
1782  */
1783 static int
1785  bool * is_value)
1786 {
1787  int error = NO_ERROR;
1788  DB_VALUE *peek_val = NULL;
1789 
1790  assert_release (src != NULL);
1791  assert_release (value_p != NULL);
1792  assert_release (src->type == TYPE_INARITH);
1793 
1794  *is_value = false;
1795  db_make_null (value_p);
1796 
1797  if (!partition_is_reguvar_const (src))
1798  {
1799  return NO_ERROR;
1800  }
1801 
1802  error = fetch_peek_dbval (pinfo->thread_p, (REGU_VARIABLE *) src, pinfo->vd, NULL, NULL, NULL, &peek_val);
1803  if (error != NO_ERROR)
1804  {
1805  return error;
1806  }
1807 
1808  /* peek_val will be cleared when scanning is performed on this REGU_VAR */
1809  error = pr_clone_value (peek_val, value_p);
1810  if (error != NO_ERROR)
1811  {
1812  return error;
1813  }
1814 
1815  *is_value = true;
1816 
1817  return NO_ERROR;
1818 }
1819 
1820 /*
1821  * partition_match_pred_expr () - get partitions matching a predicate
1822  * expression
1823  * return : match status
1824  * pinfo (in) : pruning context
1825  * pr (in) : predicate expression
1826  * pruned (in/out): pruned partitions
1827  */
1828 static MATCH_STATUS
1830 {
1831  MATCH_STATUS status = MATCH_NOT_FOUND;
1832  REGU_VARIABLE *part_expr = pinfo->partition_pred->func_regu;
1833 
1834  if (pr == NULL)
1835  {
1836  assert (false);
1837  return MATCH_NOT_FOUND;
1838  }
1839 
1840  switch (pr->type)
1841  {
1842  case T_PRED:
1843  {
1844  /* T_PRED contains conjunctions and disjunctions of PRED_EXPR. Get partitions matching the left PRED_EXPR and
1845  * partitions matching the right PRED_EXPR and merge or intersect the lists */
1846  PRUNING_BITSET left_set, right_set;
1847  MATCH_STATUS lstatus, rstatus;
1848  BOOL_OP op = pr->pe.m_pred.bool_op;
1849 
1850  if (op != B_AND && op != B_OR)
1851  {
1852  /* only know how to handle AND/OR predicates */
1853  status = MATCH_NOT_FOUND;
1854  break;
1855  }
1856 
1857  pruningset_init (&left_set, PARTITIONS_COUNT (pinfo));
1858  pruningset_init (&right_set, PARTITIONS_COUNT (pinfo));
1859 
1860  lstatus = partition_match_pred_expr (pinfo, pr->pe.m_pred.lhs, &left_set);
1861  rstatus = partition_match_pred_expr (pinfo, pr->pe.m_pred.rhs, &right_set);
1862 
1863  if (op == B_AND)
1864  {
1865  /* do intersection between left and right */
1866  if (lstatus == MATCH_NOT_FOUND)
1867  {
1868  /* pr->pe.m_pred.lhs does not refer part_expr so return right */
1869  pruningset_copy (pruned, &right_set);
1870  status = rstatus;
1871  }
1872  else if (rstatus == MATCH_NOT_FOUND)
1873  {
1874  /* pr->pe.m_pred.rhs does not refer part_expr so return right */
1875  pruningset_copy (pruned, &left_set);
1876  status = lstatus;
1877  }
1878  else
1879  {
1880  status = MATCH_OK;
1881  pruningset_intersect (&left_set, &right_set);
1882  pruningset_copy (pruned, &left_set);
1883  }
1884  }
1885  else
1886  {
1887  /* this is the OR operator so union the two sets */
1888  if (lstatus == MATCH_NOT_FOUND || rstatus == MATCH_NOT_FOUND)
1889  {
1890  status = MATCH_NOT_FOUND;
1891  }
1892  else
1893  {
1894  pruningset_union (&left_set, &right_set);
1895  pruningset_copy (pruned, &left_set);
1896 
1897  status = MATCH_OK;
1898  }
1899  }
1900  break;
1901  }
1902 
1903  case T_EVAL_TERM:
1904  switch (pr->pe.m_eval_term.et_type)
1905  {
1906  case T_COMP_EVAL_TERM:
1907  {
1908  /* see if part_expr matches right or left */
1909  REGU_VARIABLE *left, *right;
1910  PRUNING_OP op;
1911 
1912  left = pr->pe.m_eval_term.et.et_comp.lhs;
1913  right = pr->pe.m_eval_term.et.et_comp.rhs;
1915 
1916  status = MATCH_NOT_FOUND;
1917  if (partition_do_regu_variables_match (pinfo, left, part_expr))
1918  {
1919  status = partition_prune (pinfo, right, op, pruned);
1920  }
1921  else if (partition_do_regu_variables_match (pinfo, right, part_expr))
1922  {
1923  status = partition_prune (pinfo, left, op, pruned);
1924  }
1925  break;
1926  }
1927 
1928  case T_ALSM_EVAL_TERM:
1929  {
1930  REGU_VARIABLE *regu, *list;
1931  PRUNING_OP op;
1932 
1933  regu = pr->pe.m_eval_term.et.et_alsm.elem;
1934  list = pr->pe.m_eval_term.et.et_alsm.elemset;
1936  /* adjust rel_op based on the QL_FLAG of the alsm eval node */
1937  if (pr->pe.m_eval_term.et.et_alsm.eq_flag == F_SOME)
1938  {
1939  if (op == PO_EQ)
1940  {
1941  op = PO_IN;
1942  }
1943  else if (op == PO_NE)
1944  {
1945  op = PO_NOT_IN;
1946  }
1947  }
1948  if (partition_do_regu_variables_match (pinfo, regu, part_expr))
1949  {
1950  status = partition_prune (pinfo, list, op, pruned);
1951  }
1952  }
1953  break;
1954 
1955  case T_LIKE_EVAL_TERM:
1956  case T_RLIKE_EVAL_TERM:
1957  /* Don't know how to work with LIKE/RLIKE expressions yet. There are some cases in which we can deduce a
1958  * range from the like pattern. */
1959  status = MATCH_NOT_FOUND;
1960  break;
1961  }
1962  break;
1963 
1964  case T_NOT_TERM:
1965  status = MATCH_NOT_FOUND;
1966  break;
1967  }
1968 
1969  return status;
1970 }
1971 
1972 /*
1973  * partition_match_key_range () - perform pruning using a key_range
1974  * return : pruned list
1975  * pinfo (in) : pruning context
1976  * partitions (in) : partitions to prune
1977  * key_range (in) : key range
1978  * status (in/out) : pruning status
1979  */
1980 static MATCH_STATUS
1982 {
1983  PRUNING_OP lop = PO_INVALID, rop = PO_INVALID;
1984  MATCH_STATUS lstatus, rstatus;
1985  PRUNING_BITSET left, right;
1986 
1987  switch (key_range->range)
1988  {
1989  case NA_NA:
1990  /* v1 and v2 are N/A, so that no range is defined */
1991  return MATCH_NOT_FOUND;
1992 
1993  case GE_LE:
1994  /* v1 <= key <= v2 */
1995  lop = PO_GE;
1996  rop = PO_LE;
1997  break;
1998 
1999  case GE_LT:
2000  /* v1 <= key < v2 */
2001  lop = PO_GE;
2002  rop = PO_LT;
2003  break;
2004 
2005  case GT_LE:
2006  /* v1 < key <= v2 */
2007  lop = PO_GT;
2008  rop = PO_LE;
2009  break;
2010 
2011  case GT_LT:
2012  /* v1 < key < v2 */
2013  lop = PO_GT;
2014  rop = PO_LT;
2015  break;
2016 
2017  case GE_INF:
2018  /* v1 <= key (<= the end) */
2019  lop = PO_GE;
2020  rop = PO_INVALID;
2021  break;
2022 
2023  case GT_INF:
2024  /* v1 < key (<= the end) */
2025  lop = PO_GT;
2026  rop = PO_INVALID;
2027  break;
2028 
2029  case INF_LE:
2030  /* (the beginning <=) key <= v2 */
2031  lop = PO_INVALID;
2032  rop = PO_LE;
2033  break;
2034 
2035  case INF_LT:
2036  /* (the beginning <=) key < v2 */
2037  lop = PO_INVALID;
2038  rop = PO_LT;
2039  break;
2040 
2041  case INF_INF:
2042  /* the beginning <= key <= the end */
2043  lop = PO_INVALID;
2044  rop = PO_INVALID;
2045  break;
2046 
2047  case EQ_NA:
2048  /* key = v1, v2 is N/A */
2049  lop = PO_EQ;
2050  rop = PO_INVALID;
2051  break;
2052 
2053  case LE_GE:
2054  case LE_GT:
2055  case LT_GE:
2056  case LT_GT:
2057  case NEQ_NA:
2058  lop = PO_INVALID;
2059  rop = PO_INVALID;
2060  break;
2061  }
2062 
2063  pruningset_init (&left, PARTITIONS_COUNT (pinfo));
2064  pruningset_init (&right, PARTITIONS_COUNT (pinfo));
2065 
2066  /* prune left */
2067  if (lop == PO_INVALID)
2068  {
2069  lstatus = MATCH_NOT_FOUND;
2070  }
2071  else
2072  {
2073  lstatus = partition_prune (pinfo, key_range->key1, lop, &left);
2074  if (pinfo->error_code != NO_ERROR)
2075  {
2076  return MATCH_NOT_FOUND;
2077  }
2078  }
2079 
2080  /* prune right */
2081  if (rop == PO_INVALID)
2082  {
2083  rstatus = MATCH_NOT_FOUND;
2084  }
2085  else
2086  {
2087  rstatus = partition_prune (pinfo, key_range->key2, rop, &right);
2088  if (pinfo->error_code != NO_ERROR)
2089  {
2090  return MATCH_NOT_FOUND;
2091  }
2092  }
2093 
2094  if (lstatus == MATCH_NOT_FOUND)
2095  {
2096  pruningset_copy (pruned, &right);
2097  return rstatus;
2098  }
2099 
2100  if (rstatus == MATCH_NOT_FOUND)
2101  {
2102  pruningset_copy (pruned, &left);
2103  return lstatus;
2104  }
2105 
2106  pruningset_copy (pruned, &left);
2107  pruningset_intersect (pruned, &right);
2108 
2109  return MATCH_OK;
2110 }
2111 
2112 /*
2113  * partition_match_index_key () - get the list of partitions that fit into the
2114  * index key
2115  * return : match status
2116  * pinfo (in) : pruning context
2117  * key (in) : index key info
2118  * range_type (in) : range type
2119  * partitions (in/out): pruned partitions
2120  */
2121 static MATCH_STATUS
2123  PRUNING_BITSET * pruned)
2124 {
2125  int i;
2126  PRUNING_BITSET key_pruned;
2127  MATCH_STATUS status;
2128 
2129  if (pinfo->partition_pred->func_regu->type != TYPE_ATTR_ID)
2130  {
2131  return MATCH_NOT_FOUND;
2132  }
2133 
2134  status = MATCH_OK;
2135 
2136  /* We do not care which range_type this index scan is supposed to perform. Each key range produces a list of
2137  * partitions and we will merge those lists to get the full list of partitions that contains information for our
2138  * search */
2139  for (i = 0; i < key->key_cnt; i++)
2140  {
2141  pruningset_init (&key_pruned, PARTITIONS_COUNT (pinfo));
2142 
2143  status = partition_match_key_range (pinfo, &key->key_ranges[i], &key_pruned);
2144  if (status == MATCH_NOT_FOUND)
2145  {
2146  /* For key ranges we have to find a match for all ranges. If we get a MATCH_NOT_FOUND then we have to assume
2147  * that all partitions have to be scanned for the result */
2148  pruningset_set_all (pruned);
2149  break;
2150  }
2151 
2152  pruningset_union (pruned, &key_pruned);
2153  }
2154 
2155  return status;
2156 }
2157 
2158 /*
2159  * partition_init_pruning_context () - initialize pruning context
2160  * return : void
2161  * pinfo (in/out) : pruning context
2162  */
2163 void
2165 {
2166  if (pinfo == NULL)
2167  {
2168  assert (false);
2169  return;
2170  }
2171 
2172  OID_SET_NULL (&pinfo->root_oid);
2173  pinfo->thread_p = NULL;
2174  pinfo->partitions = NULL;
2175  pinfo->selected_partition = NULL;
2176  pinfo->spec = NULL;
2177  pinfo->vd = NULL;
2178  pinfo->count = 0;
2179  pinfo->fp_cache_context = NULL;
2180  pinfo->partition_pred = NULL;
2181  pinfo->attr_position = -1;
2182  pinfo->error_code = NO_ERROR;
2183  pinfo->scan_cache_list = NULL;
2185  pinfo->is_attr_info_inited = false;
2186  pinfo->is_from_cache = false;
2187 }
2188 
2189 /*
2190  * partition_find_root_class_oid () - Find the OID of the root partitioned
2191  * class
2192  * return : error code or NO_ERROR
2193  * thread_p (in) : thread entry
2194  * class_oid (in) : either the OID of the partitioned class or the OID of
2195  * one of the partitions
2196  * super_oid (in/out) : OID of the partitioned class
2197  */
2198 int
2199 partition_find_root_class_oid (THREAD_ENTRY * thread_p, const OID * class_oid, OID * super_oid)
2200 {
2201  int error = NO_ERROR, super_count = 0;
2202  OID *super_classes = NULL;
2203 
2204  error = heap_get_class_supers (thread_p, class_oid, &super_classes, &super_count);
2205  if (error != NO_ERROR)
2206  {
2207  ASSERT_ERROR ();
2208  if (super_classes != NULL)
2209  {
2210  free_and_init (super_classes);
2211  }
2212 
2213  return error;
2214  }
2215 
2216  if (super_count > 1)
2217  {
2218  OID_SET_NULL (super_oid);
2219  }
2220  else if (super_count != 1)
2221  {
2222  /* class_oid has no superclasses which means that it is not a partition of a partitioned class. However,
2223  * class_oid might still point to a partitioned class so we're trying this bellow */
2224  COPY_OID (super_oid, class_oid);
2225  }
2226  else if (super_count == 1)
2227  {
2228  COPY_OID (super_oid, super_classes);
2229  }
2230 
2231  if (super_classes != NULL)
2232  {
2233  free_and_init (super_classes);
2234  }
2235 
2236  return NO_ERROR;
2237 }
2238 
2239 /*
2240  * partition_load_pruning_context () - load pruning context
2241  * return : error code or NO_ERROR
2242  * thread_p (in) :
2243  * class_oid (in) : oid of the class for which the context should be loaded
2244  * pruning_type(in) : DB_CLASS_PARTITION_TYPE specifying if this class is a
2245  * partition or the actual partitioned class
2246  * pinfo (in/out) : pruning context
2247  */
2248 int
2249 partition_load_pruning_context (THREAD_ENTRY * thread_p, const OID * class_oid, int pruning_type,
2250  PRUNING_CONTEXT * pinfo)
2251 {
2252  int error = NO_ERROR;
2253  OR_PARTITION *master = NULL;
2254  bool is_modified = false;
2255  bool already_exists = false;
2256 
2257  if (pinfo == NULL)
2258  {
2259  assert (false);
2260  return ER_FAILED;
2261  }
2262  assert_release (pruning_type == DB_PARTITIONED_CLASS || pruning_type == DB_PARTITION_CLASS);
2263 
2264  (void) partition_init_pruning_context (pinfo);
2265 
2266  pinfo->pruning_type = pruning_type;
2267  pinfo->thread_p = thread_p;
2268  if (pruning_type == DB_PARTITIONED_CLASS)
2269  {
2270  COPY_OID (&pinfo->root_oid, class_oid);
2271  }
2272  else
2273  {
2274  error = partition_find_root_class_oid (thread_p, class_oid, &pinfo->root_oid);
2275  if (error != NO_ERROR)
2276  {
2277  ASSERT_ERROR ();
2278  goto error_return;
2279  }
2280  }
2281 
2282 reload_from_cache:
2283 
2284  /* try to get info from the cache first */
2285  if (partition_load_context_from_cache (pinfo, &is_modified))
2286  {
2287  master = &pinfo->partitions[0];
2288  pinfo->root_repr_id = master->rep_id;
2289  /* load the partition predicate which is not deserialized in the cache */
2290  error = partition_load_partition_predicate (pinfo, master);
2291  if (error != NO_ERROR)
2292  {
2293  ASSERT_ERROR ();
2294  goto error_return;
2295  }
2296  if (pruning_type == DB_PARTITION_CLASS)
2297  {
2298  partition_set_specified_partition (pinfo, class_oid);
2299  }
2300  return NO_ERROR;
2301  }
2302 
2303  if (pinfo->error_code != NO_ERROR)
2304  {
2305  error = pinfo->error_code;
2306  ASSERT_ERROR ();
2307  goto error_return;
2308  }
2309 
2310  error = heap_get_class_partitions (pinfo->thread_p, &pinfo->root_oid, &pinfo->partitions, &pinfo->count);
2311  if (error != NO_ERROR)
2312  {
2313  ASSERT_ERROR ();
2314  goto error_return;
2315  }
2316 
2317  if (pinfo->partitions == NULL)
2318  {
2319  /* Class is not partitioned, just return */
2320  return NO_ERROR;
2321  }
2322 
2323  master = &pinfo->partitions[0];
2324  error = partition_load_partition_predicate (pinfo, master);
2325  if (error != NO_ERROR)
2326  {
2327  ASSERT_ERROR ();
2328  goto error_return;
2329  }
2330 
2331  pinfo->partition_type = (DB_PARTITION_TYPE) master->partition_type;
2332  pinfo->root_repr_id = master->rep_id;
2333 
2335  pinfo->is_from_cache = false;
2336 
2337  if (!is_modified)
2338  {
2339  /* Cache the loaded info. If the call below is successful, pinfo will be returned holding the cached information */
2340  partition_cache_pruning_context (pinfo, &already_exists);
2341 
2342  /* Multiple thread can reach here synchronously. In this case redo the action of load from cache. */
2343  if (already_exists)
2344  {
2345  heap_clear_partition_info (pinfo->thread_p, pinfo->partitions, pinfo->count);
2346  pinfo->partitions = NULL;
2347  pinfo->count = 0;
2348 
2350 
2351  goto reload_from_cache;
2352  }
2353  }
2354 
2355  if (pruning_type == DB_PARTITION_CLASS)
2356  {
2357  partition_set_specified_partition (pinfo, class_oid);
2358  }
2359 
2360  return NO_ERROR;
2361 
2362 error_return:
2363  if (pinfo != NULL)
2364  {
2366 
2367  pinfo->error_code = error;
2368  }
2369 
2370  return error;
2371 }
2372 
2373 /*
2374  * partition_clear_pruning_context () - free memory allocated for pruning
2375  * context
2376  * return : void
2377  * pinfo (in) : pruning context
2378  */
2379 void
2381 {
2382  SCANCACHE_LIST *list, *next;
2383 
2384  if (pinfo == NULL)
2385  {
2386  assert (false);
2387  return;
2388  }
2389 
2390  if (!pinfo->is_from_cache)
2391  {
2392  if (pinfo->partitions != NULL)
2393  {
2394  heap_clear_partition_info (pinfo->thread_p, pinfo->partitions, pinfo->count);
2395  }
2396  }
2397 
2398  pinfo->partitions = NULL;
2399  pinfo->selected_partition = NULL;
2400  pinfo->count = 0;
2401 
2403 
2404  if (pinfo->is_attr_info_inited)
2405  {
2406  heap_attrinfo_end (pinfo->thread_p, &(pinfo->attr_info));
2407  pinfo->is_attr_info_inited = false;
2408  }
2409 
2410  list = pinfo->scan_cache_list;
2411  while (list != NULL)
2412  {
2413  next = list->next;
2415  {
2417  }
2418  if (list->scan_cache.func_index_pred != NULL)
2419  {
2422  }
2423  db_private_free (pinfo->thread_p, list);
2424  list = next;
2425  }
2426 
2427  pinfo->scan_cache_list = NULL;
2428 }
2429 
2430 /*
2431  * partition_load_partition_predicate () - load partition predicate
2432  * return :
2433  * pinfo (in) : pruning context
2434  * master (in) : master partition information
2435  */
2436 static int
2438 {
2439  int error = NO_ERROR, stream_len = 0;
2440  DB_VALUE val;
2441  char *expr_stream = NULL;
2442 
2443  if (db_set_size (master->values) < 3)
2444  {
2445  /* internal storage error */
2447  return ER_FAILED;
2448  }
2449 
2450  /* get expr stream */
2451  error = db_set_get (master->values, 2, &val);
2452  if (error != NO_ERROR)
2453  {
2454  ASSERT_ERROR ();
2455  return error;
2456  }
2457 
2458  assert (DB_VALUE_TYPE (&val) == DB_TYPE_CHAR);
2459  // use const_cast since of a limitation of or_unpack_* functions which do not accept const
2460  expr_stream = CONST_CAST (char *, db_get_string (&val));
2461  stream_len = db_get_string_size (&val);
2462 
2463  /* unpack partition expression */
2464  error = stx_map_stream_to_func_pred (pinfo->thread_p, &pinfo->partition_pred, expr_stream, stream_len,
2465  &pinfo->fp_cache_context);
2466  if (error != NO_ERROR)
2467  {
2468  ASSERT_ERROR ();
2469  }
2470  pr_clear_value (&val);
2471 
2472  return error;
2473 }
2474 
2475 /*
2476  * partition_free_partition_predicate () - free partition predicate
2477  * return :
2478  * pinfo (in) : pruning context
2479  */
2480 static void
2482 {
2483  if (pinfo->partition_pred != NULL && pinfo->partition_pred->func_regu != NULL)
2484  {
2486  pinfo->partition_pred = NULL;
2487  }
2488 
2489  if (pinfo->fp_cache_context != NULL)
2490  {
2492  }
2493 }
2494 
2495 /*
2496  * partition_set_specified_partition () - find OR_PARTITION object for
2497  * specified partition and set it
2498  * in the pruning context
2499  * return : void
2500  * pinfo (in) : pruning context
2501  * partition_oid (in) : partition oid
2502  */
2503 static void
2505 {
2506  int i = 0;
2507  for (i = 0; i < PARTITIONS_COUNT (pinfo); i++)
2508  {
2509  if (OID_EQ (partition_oid, &(pinfo->partitions[i + 1].class_oid)))
2510  {
2511  pinfo->selected_partition = &pinfo->partitions[i + 1];
2512  break;
2513  }
2514  }
2516 }
2517 
2518 /*
2519  * partition_set_cache_info_for_expr () - set attribute info cache for the
2520  * partition expression
2521  * return : true if attribute cache info was set, false otherwise
2522  * var (in/out) : partition expression
2523  * attr_id (in) : partition attribute id
2524  * attr_info (in) : attribute cache info
2525  */
2526 static void
2528 {
2529  assert (attr_info != NULL);
2530 
2531  if (var == NULL)
2532  {
2533  /* nothing to do */
2534  return;
2535  }
2536 
2537  if (attr_id == NULL_ATTRID)
2538  {
2539  /* nothing to do */
2540  return;
2541  }
2542 
2543  switch (var->type)
2544  {
2545  case TYPE_ATTR_ID:
2546  if (var->value.attr_descr.id == attr_id)
2547  {
2548  var->value.attr_descr.cache_attrinfo = attr_info;
2549  }
2550  break;
2551 
2552  case TYPE_INARITH:
2553  case TYPE_OUTARITH:
2554  (void) partition_set_cache_info_for_expr (var->value.arithptr->leftptr, attr_id, attr_info);
2555  (void) partition_set_cache_info_for_expr (var->value.arithptr->rightptr, attr_id, attr_info);
2556  (void) partition_set_cache_info_for_expr (var->value.arithptr->thirdptr, attr_id, attr_info);
2557  break;
2558 
2559  case TYPE_FUNC:
2560  {
2561  REGU_VARIABLE_LIST op = var->value.funcp->operand;
2562 
2563  while (op != NULL)
2564  {
2565  (void) partition_set_cache_info_for_expr (&op->value, attr_id, attr_info);
2566  op = op->next;
2567  }
2568  break;
2569  }
2570 
2571  default:
2572  break;
2573  }
2574 }
2575 
2576 /*
2577  * partition_get_attribute_id () - get the id of the attribute of the
2578  * partition expression
2579  * return : attribute id
2580  * var (in) : partition expression
2581  */
2582 static ATTR_ID
2584 {
2585  ATTR_ID attr_id = NULL_ATTRID;
2586 
2587  assert (var != NULL);
2588  switch (var->type)
2589  {
2590  case TYPE_ATTR_ID:
2591  return var->value.attr_descr.id;
2592 
2593  case TYPE_INARITH:
2594  case TYPE_OUTARITH:
2595  if (var->value.arithptr->leftptr != NULL)
2596  {
2597  attr_id = partition_get_attribute_id (var->value.arithptr->leftptr);
2598  if (attr_id != NULL_ATTRID)
2599  {
2600  return attr_id;
2601  }
2602  }
2603 
2604  if (var->value.arithptr->rightptr != NULL)
2605  {
2606  attr_id = partition_get_attribute_id (var->value.arithptr->rightptr);
2607  if (attr_id != NULL_ATTRID)
2608  {
2609  return attr_id;
2610  }
2611  }
2612 
2613  if (var->value.arithptr->thirdptr != NULL)
2614  {
2615  attr_id = partition_get_attribute_id (var->value.arithptr->thirdptr);
2616  if (attr_id != NULL_ATTRID)
2617  {
2618  return attr_id;
2619  }
2620  }
2621 
2622  return attr_id;
2623 
2624  case TYPE_FUNC:
2625  {
2626  REGU_VARIABLE_LIST op = var->value.funcp->operand;
2627 
2628  while (op != NULL)
2629  {
2630  attr_id = partition_get_attribute_id (&op->value);
2631  if (attr_id != NULL_ATTRID)
2632  {
2633  return attr_id;
2634  }
2635  op = op->next;
2636  }
2637 
2638  return attr_id;
2639  }
2640 
2641  default:
2642  return NULL_ATTRID;
2643  }
2644 
2645  return attr_id;
2646 }
2647 
2648 /*
2649  * partition_get_position_in_key () - get the position of the partition column
2650  * in a multicolumn key
2651  * return : error code or NO_ERROR
2652  * pinfo (in) : pruning context
2653  * btid (in) : btid for which to get the position
2654  */
2655 static int
2657 {
2658  int i = 0;
2659  int error = NO_ERROR;
2660  ATTR_ID part_attr_id = -1;
2661  ATTR_ID *keys = NULL;
2662  int key_count = 0;
2663 
2664  pinfo->attr_position = -1;
2665 
2666  if (pinfo->partition_pred->func_regu->type != TYPE_ATTR_ID)
2667  {
2668  /* In the case of index keys, we will only apply pruning if the partition expression is actually an attribute.
2669  * This is because we will not have expressions in the index key, only attributes (except for function and filter
2670  * indexes which are not handled yet) */
2671  pinfo->attr_position = -1;
2672  return NO_ERROR;
2673  }
2674 
2675  part_attr_id = pinfo->partition_pred->func_regu->value.attr_descr.id;
2676 
2677  error =
2678  heap_get_indexinfo_of_btid (pinfo->thread_p, &pinfo->root_oid, btid, NULL, &key_count, &keys, NULL, NULL, NULL);
2679  if (error != NO_ERROR)
2680  {
2681  ASSERT_ERROR ();
2682  return error;
2683  }
2684 
2685  for (i = 0; i < key_count; i++)
2686  {
2687  if (part_attr_id == keys[i])
2688  {
2689  /* found the attribute */
2690  pinfo->attr_position = i;
2691  break;
2692  }
2693  }
2694 
2695  if (keys != NULL)
2696  {
2697  db_private_free (pinfo->thread_p, keys);
2698  }
2699 
2700  return NO_ERROR;
2701 }
2702 
2703 /*
2704  * partition_prune_heap_scan () - prune a access spec for heap scan
2705  * return : error code or NO_ERROR
2706  * pinfo (in) : pruning context
2707  */
2708 static int
2710 {
2711  int error = NO_ERROR;
2712  PRUNING_BITSET pruned;
2713  MATCH_STATUS status = MATCH_NOT_FOUND;
2714 
2715  assert (pinfo != NULL);
2716  assert (pinfo->partitions != NULL);
2717 
2718  pruningset_init (&pruned, PARTITIONS_COUNT (pinfo));
2719 
2720  if (pinfo->spec->where_pred == NULL)
2721  {
2722  status = MATCH_NOT_FOUND;
2723  }
2724  else
2725  {
2726  status = partition_match_pred_expr (pinfo, pinfo->spec->where_pred, &pruned);
2727  if (pinfo->error_code != NO_ERROR)
2728  {
2729  ASSERT_ERROR ();
2730  return pinfo->error_code;
2731  }
2732  }
2733 
2734  if (status != MATCH_NOT_FOUND)
2735  {
2736  error = pruningset_to_spec_list (pinfo, &pruned);
2737  if (error != NO_ERROR)
2738  {
2739  ASSERT_ERROR ();
2740  }
2741  }
2742  else
2743  {
2744  /* consider all partitions */
2745  pruningset_set_all (&pruned);
2746  error = pruningset_to_spec_list (pinfo, &pruned);
2747  if (error != NO_ERROR)
2748  {
2749  ASSERT_ERROR ();
2750  }
2751  }
2752 
2753  return error;
2754 }
2755 
2756 /*
2757  * partition_prune_index_scan () - perform partition pruning on an index scan
2758  * return : error code or NO_ERROR
2759  * pinfo (in) : pruning context
2760  */
2761 static int
2763 {
2764  int error = NO_ERROR;
2765  PRUNING_BITSET pruned;
2766  MATCH_STATUS status = MATCH_NOT_FOUND;
2767 
2768  assert (pinfo != NULL);
2769  assert (pinfo->partitions != NULL);
2770  assert (pinfo->spec != NULL);
2771  assert (pinfo->spec->indexptr != NULL);
2772 
2773  pruningset_init (&pruned, PARTITIONS_COUNT (pinfo));
2774  if (pinfo->spec->where_pred != NULL)
2775  {
2776  status = partition_match_pred_expr (pinfo, pinfo->spec->where_pred, &pruned);
2777  }
2778 
2779  if (pinfo->spec->where_key != NULL)
2780  {
2781  status = partition_match_pred_expr (pinfo, pinfo->spec->where_key, &pruned);
2782  }
2783 
2784  if (pinfo->attr_position != -1)
2785  {
2786  if (pinfo->spec->indexptr->use_iss && pinfo->attr_position == 0)
2787  {
2788  /* The first position is missing in ISS and we're dealing with a virtual predicate key = NULL. In this case,
2789  * all partitions qualify for the search */
2790  pruningset_set_all (&pruned);
2791  status = MATCH_OK;
2792  }
2793  else if (pinfo->spec->indexptr->func_idx_col_id != -1)
2794  {
2795  /* We are dealing with a function index, so all partitions qualify for the search. */
2796  pruningset_set_all (&pruned);
2797  status = MATCH_OK;
2798  }
2799  else
2800  {
2801  status =
2803  &pruned);
2804  }
2805  }
2806  if (status == MATCH_NOT_FOUND)
2807  {
2808  if (pinfo->error_code != NO_ERROR)
2809  {
2810  return pinfo->error_code;
2811  }
2812  else
2813  {
2814  pruningset_set_all (&pruned);
2815  error = pruningset_to_spec_list (pinfo, &pruned);
2816  if (error != NO_ERROR)
2817  {
2818  ASSERT_ERROR ();
2819  }
2820  }
2821  }
2822  else
2823  {
2824  error = pruningset_to_spec_list (pinfo, &pruned);
2825  if (error != NO_ERROR)
2826  {
2827  ASSERT_ERROR ();
2828  }
2829  }
2830 
2831  return error;
2832 }
2833 
2834 /*
2835  * partition_prune_spec () - perform pruning on an access spec.
2836  * return : error code or NO_ERROR
2837  * thread_p (in) :
2838  * access_spec (in) : access spec to prune
2839  */
2840 int
2842 {
2843  int error = NO_ERROR;
2844  PRUNING_CONTEXT pinfo;
2845 
2846  if (spec == NULL)
2847  {
2848  assert (false);
2849 
2851  return ER_FAILED;
2852  }
2853  if (spec->pruning_type != DB_PARTITIONED_CLASS)
2854  {
2855  /* nothing to prune */
2856  spec->pruned = true;
2857  return NO_ERROR;
2858  }
2859  if (spec->type != TARGET_CLASS && spec->type != TARGET_CLASS_ATTR)
2860  {
2861  /* nothing to prune */
2862  spec->pruned = true;
2863  return NO_ERROR;
2864  }
2865 
2866  (void) partition_init_pruning_context (&pinfo);
2867 
2868  spec->curent = NULL;
2869  spec->parts = NULL;
2870 
2871  error = partition_load_pruning_context (thread_p, &ACCESS_SPEC_CLS_OID (spec), spec->pruning_type, &pinfo);
2872  if (error != NO_ERROR)
2873  {
2874  ASSERT_ERROR ();
2875  return error;
2876  }
2877 
2878  if (pinfo.partitions == NULL)
2879  {
2880  /* no partitions */
2881  spec->pruned = true;
2882  return NO_ERROR;
2883  }
2884 
2885  pinfo.spec = spec;
2886  pinfo.vd = vd;
2887 
2890  {
2891  error = partition_prune_heap_scan (&pinfo);
2892  if (error != NO_ERROR)
2893  {
2894  ASSERT_ERROR ();
2895  }
2896  }
2897  else
2898  {
2899  if (spec->indexptr == NULL)
2900  {
2901  assert (false);
2902 
2905  return ER_FAILED;
2906  }
2907 
2908  if (pinfo.partition_pred->func_regu->type != TYPE_ATTR_ID)
2909  {
2910  /* In the case of index keys, we will only apply pruning if the partition expression is actually an
2911  * attribute. This is because we will not have expressions in the index key, only attributes (except for
2912  * function and filter indexes which are not handled yet) */
2913  pinfo.attr_position = -1;
2914  }
2915  else
2916  {
2917  BTID *btid = &spec->indexptr->btid;
2918  error = partition_get_position_in_key (&pinfo, btid);
2919  if (error != NO_ERROR)
2920  {
2921  ASSERT_ERROR ();
2923  return error;
2924  }
2925  }
2926  error = partition_prune_index_scan (&pinfo);
2927  if (error != NO_ERROR)
2928  {
2929  ASSERT_ERROR ();
2930  }
2931  }
2932 
2934 
2935  if (error == NO_ERROR)
2936  {
2937  spec->pruned = true;
2938  }
2939 
2940  return error;
2941 }
2942 
2943 /*
2944  * partition_find_partition_for_record () - find the partition in which a
2945  * record should be placed
2946  * return : error code or NO_ERROR
2947  * pinfo (in) : pruning context
2948  * class_oid (in) : OID of the root class
2949  * recdes (in) : record descriptor
2950  * partition_oid (in/out) : OID of the partition in which the record fits
2951  * partition_hfid (in/out): HFID of the partition in which the record fits
2952  */
2953 static int
2955  OID * partition_oid, HFID * partition_hfid)
2956 {
2957  PRUNING_BITSET pruned;
2959  bool clear_dbvalues = false;
2960  DB_VALUE *result = NULL;
2961  MATCH_STATUS status = MATCH_NOT_FOUND;
2962  int error = NO_ERROR, count = 0, pos;
2963  PRUNING_OP op = PO_EQ;
2964  REPR_ID repr_id = NULL_REPRID;
2965 
2966  assert (partition_oid != NULL);
2967  assert (partition_hfid != NULL);
2968 
2969  pruningset_init (&pruned, PARTITIONS_COUNT (pinfo));
2970 
2971  if (pinfo->is_attr_info_inited == false)
2972  {
2973  error = heap_attrinfo_start (pinfo->thread_p, &pinfo->root_oid, 1, &pinfo->attr_id, &pinfo->attr_info);
2974  if (error != NO_ERROR)
2975  {
2976  goto cleanup;
2977  }
2978 
2980  pinfo->is_attr_info_inited = true;
2981  }
2982 
2983  /* set root representation id to the recdes so that we can read the value as belonging to the partitioned table */
2984  repr_id = or_rep_id (recdes);
2985  or_set_rep_id (recdes, pinfo->root_repr_id);
2986 
2987  error = heap_attrinfo_read_dbvalues (pinfo->thread_p, &pinfo->attr_info.inst_oid, recdes, NULL, &pinfo->attr_info);
2988 
2989  or_set_rep_id (recdes, repr_id);
2990  if (error != NO_ERROR)
2991  {
2992  goto cleanup;
2993  }
2994  clear_dbvalues = true;
2995 
2996  error =
2997  fetch_peek_dbval (pinfo->thread_p, pinfo->partition_pred->func_regu, NULL, (OID *) class_oid,
2998  &pinfo->attr_info.inst_oid, NULL, &result);
2999  if (error != NO_ERROR)
3000  {
3001  goto cleanup;
3002  }
3003 
3004  assert (result != NULL);
3005 
3006  if (db_value_is_null (result))
3007  {
3008  /* use IS_NULL comparison when pruning NULL DB_VALUEs */
3009  op = PO_IS_NULL;
3010  }
3011 
3012  status = partition_prune_db_val (pinfo, result, op, &pruned);
3013  count = pruningset_popcount (&pruned);
3014  if (status != MATCH_OK)
3015  {
3017  error = ER_PARTITION_NOT_EXIST;
3018  goto cleanup;
3019  }
3020 
3021  if (count != 1)
3022  {
3023  /* At this stage we should absolutely have a result. If we don't then something went wrong (either some internal
3024  * error (e.g. allocation failed) or the inserted value cannot be placed in any partition */
3025  if (pinfo->error_code == NO_ERROR)
3026  {
3027  /* no appropriate partition found */
3029  error = ER_PARTITION_NOT_EXIST;
3030  }
3031  else
3032  {
3033  /* This is an internal *error (allocation, etc). Error was set by the calls above, just set *error code */
3034  error = pinfo->error_code;
3035  }
3036  goto cleanup;
3037  }
3038 
3039  pruningset_iterator_init (&pruned, &it);
3040 
3041  pos = pruningset_iterator_next (&it);
3042  assert_release (pos >= 0);
3043 
3044  COPY_OID (partition_oid, &pinfo->partitions[pos + 1].class_oid);
3045  HFID_COPY (partition_hfid, &pinfo->partitions[pos + 1].class_hfid);
3046 
3047  if (!OID_EQ (class_oid, partition_oid))
3048  {
3049  /* Update representation id of the record to that of the pruned partition. For any other operation than pruning,
3050  * the new representation id should be obtained by constructing a new HEAP_ATTRIBUTE_INFO structure for the new
3051  * class, copying values from this record to that structure and then transforming it to disk. Since we're working
3052  * with partitioned tables, we can guarantee that, except for the actual representation id bits, the new record
3053  * will be exactly the same. Because of this, we can take a shortcut here and only update the bits from the
3054  * representation id */
3055 
3056  repr_id = pinfo->partitions[pos + 1].rep_id;
3057  error = or_set_rep_id (recdes, repr_id);
3058  }
3059 
3060 cleanup:
3061  if (clear_dbvalues)
3062  {
3064  }
3065 
3066  return error;
3067 }
3068 
3069 /*
3070  * partition_prune_insert () - perform pruning for insert
3071  * return : error code or NO_ERROR
3072  * thread_p (in) : thread entry
3073  * class_oid (in) : OID of the root class
3074  * recdes (in) : Record describing the new object
3075  * scan_cache (in): Heap scan cache
3076  * pcontext (in) : pruning context
3077  * pruning_type (in) : pruning type
3078  * pruned_class_oid (in/out) : partition to insert into
3079  * pruned_hfid (in/out) : HFID of the partition
3080  * superclass_oid (in/out) : OID of the partitioned class
3081  *
3082  * Note: The pruning context argument may be null, in which case, this
3083  * function loads the pruning context internally. If the pcontext argument
3084  * is not null, this function uses that context to perform internal
3085  * operations.
3086  * If the INSERT operation is repetitive (e.g: for INSERT...SELECT), the
3087  * caller should initialize a PRUNING_CONTEXT object (by calling
3088  * partition_init_pruning_context) and pass it to this function for each
3089  * insert operation in the query.
3090  */
3091 int
3092 partition_prune_insert (THREAD_ENTRY * thread_p, const OID * class_oid, RECDES * recdes, HEAP_SCANCACHE * scan_cache,
3093  PRUNING_CONTEXT * pcontext, int pruning_type, OID * pruned_class_oid, HFID * pruned_hfid,
3094  OID * superclass_oid)
3095 {
3096  PRUNING_CONTEXT pinfo;
3097  bool keep_pruning_context = false;
3098  int error = NO_ERROR;
3099 
3100  assert (pruned_class_oid != NULL);
3101  assert (pruned_hfid != NULL);
3102 
3103  if (superclass_oid != NULL)
3104  {
3105  OID_SET_NULL (superclass_oid);
3106  }
3107 
3108  if (pruning_type == DB_NOT_PARTITIONED_CLASS)
3109  {
3110  assert (false);
3111  return NO_ERROR;
3112  }
3113 
3114  if (pcontext == NULL)
3115  {
3116  /* set it to point to pinfo so that we use the same variable */
3117  pcontext = &pinfo;
3118  keep_pruning_context = false;
3119 
3120  (void) partition_init_pruning_context (pcontext);
3121  error = partition_load_pruning_context (thread_p, class_oid, pruning_type, pcontext);
3122  if (error != NO_ERROR)
3123  {
3124  return error;
3125  }
3126  }
3127  else
3128  {
3129  keep_pruning_context = true;
3130 
3131  if (pcontext->partitions == NULL)
3132  {
3133  error = partition_load_pruning_context (thread_p, class_oid, pruning_type, pcontext);
3134  if (error != NO_ERROR)
3135  {
3136  return error;
3137  }
3138  }
3139  }
3140 
3141  if (pcontext->partitions == NULL)
3142  {
3143  /* no partitions, cleanup and exit */
3144  goto cleanup;
3145  }
3146 
3147  error = partition_find_partition_for_record (pcontext, class_oid, recdes, pruned_class_oid, pruned_hfid);
3148  if (error != NO_ERROR)
3149  {
3150  goto cleanup;
3151  }
3152 
3153  if (pruning_type == DB_PARTITION_CLASS)
3154  {
3155  if (!OID_EQ (pruned_class_oid, &pcontext->selected_partition->class_oid))
3156  {
3159  goto cleanup;
3160  }
3161  }
3162  if (superclass_oid != NULL)
3163  {
3164  COPY_OID (superclass_oid, &pcontext->root_oid);
3165  }
3166 
3167 cleanup:
3168  if (keep_pruning_context && error == NO_ERROR)
3169  {
3170  return NO_ERROR;
3171  }
3172 
3173  (void) partition_clear_pruning_context (pcontext);
3174 
3175  return error;
3176 }
3177 
3178 /*
3179  * partition_prune_update () - perform pruning on update statements
3180  * return : error code or NO_ERROR
3181  * thread_p (in) : thread entry
3182  * class_oid (in) : OID of the root class
3183  * recdes (in) : Record describing the new object
3184  * pcontext (in) : pruning context
3185  * pruning_type (in) : pruning type
3186  * pruned_class_oid (in/out) : partition to insert into
3187  * pruned_hfid (in/out) : HFID of the partition
3188  * superclass_oid (in/out) : OID of the partitioned class
3189  *
3190  * Note: The pruning context argument may be null, in which case, this
3191  * function loads the pruning context internally. If the pcontext argument
3192  * is not null, this function uses that context to perform internal
3193  * operations.
3194  * If the UPDATE operation is repetitive (e.g: for server side UPDATE), the
3195  * caller should initialize a PRUNING_CONTEXT object (by calling
3196  * partition_init_pruning_context) and pass it to this function.
3197  */
3198 int
3199 partition_prune_update (THREAD_ENTRY * thread_p, const OID * class_oid, RECDES * recdes, PRUNING_CONTEXT * pcontext,
3200  int pruning_type, OID * pruned_class_oid, HFID * pruned_hfid, OID * superclass_oid)
3201 {
3202  PRUNING_CONTEXT pinfo;
3203  int error = NO_ERROR;
3204  OID super_class;
3205  bool keep_pruning_context = false;
3206 
3207  if (OID_IS_ROOTOID (class_oid))
3208  {
3209  /* nothing to do here */
3210  COPY_OID (pruned_class_oid, class_oid);
3211  return NO_ERROR;
3212  }
3213 
3214  if (pruning_type == DB_NOT_PARTITIONED_CLASS)
3215  {
3216  assert (false);
3217  return NO_ERROR;
3218  }
3219 
3220  OID_SET_NULL (&super_class);
3221  if (superclass_oid != NULL)
3222  {
3223  OID_SET_NULL (superclass_oid);
3224  }
3225 
3226  if (pcontext == NULL)
3227  {
3228  /* set it to point to pinfo so that we use the same variable */
3229  pcontext = &pinfo;
3230 
3231  keep_pruning_context = false;
3232  if (pruning_type == DB_PARTITION_CLASS)
3233  {
3234  error = partition_load_pruning_context (thread_p, class_oid, pruning_type, pcontext);
3235  }
3236  else
3237  {
3238  /* UPDATE operation is always performed on an instance of a partition (since the top class holds no data).
3239  * Even if pruning_type is DB_PARTITIONED_CLASS, class_oid will still hold the OID of the partition. Find the
3240  * OID of the root class before loading pruning context. The function which loads the pruning context will
3241  * get confused if we tell it that class_oid holds the partitioned class. */
3242  (void) partition_init_pruning_context (pcontext);
3243 
3244  error = partition_find_root_class_oid (thread_p, class_oid, &super_class);
3245  if (error != NO_ERROR)
3246  {
3247  return error;
3248  }
3249 
3250  if (OID_ISNULL (&super_class))
3251  {
3252  /* not a partitioned class */
3253  return NO_ERROR;
3254  }
3255 
3256  error = partition_load_pruning_context (thread_p, &super_class, pruning_type, pcontext);
3257  }
3258  }
3259  else
3260  {
3261  keep_pruning_context = true;
3262 
3263  if (pcontext->partitions == NULL)
3264  {
3265  /* this context should have been loaded before */
3266  assert (false);
3267 
3269  error = ER_FAILED;
3270  }
3271  }
3272 
3273 
3274  if (error != NO_ERROR || pcontext->partitions == NULL)
3275  {
3276  /* Error while initializing pruning context or there are no partitions, cleanup and exit */
3277  goto cleanup;
3278  }
3279 
3280  error = partition_find_partition_for_record (pcontext, class_oid, recdes, pruned_class_oid, pruned_hfid);
3281  if (error != NO_ERROR)
3282  {
3283  goto cleanup;
3284  }
3285 
3286  if (pcontext->pruning_type == DB_PARTITION_CLASS)
3287  {
3288  if (!OID_EQ (pruned_class_oid, &pcontext->selected_partition->class_oid))
3289  {
3292  goto cleanup;
3293  }
3294  }
3295 
3296  if (superclass_oid != NULL)
3297  {
3298  COPY_OID (superclass_oid, &pcontext->root_oid);
3299  }
3300 
3301 cleanup:
3302  if (keep_pruning_context && error == NO_ERROR)
3303  {
3304  return NO_ERROR;
3305  }
3306 
3307  (void) partition_clear_pruning_context (pcontext);
3308  pcontext = NULL;
3309 
3310  return error;
3311 }
3312 
3313 /*
3314  * partition_get_scancache () - get scan_cache for a partition
3315  * return : cached object or NULL
3316  * pcontext (in) : pruning context
3317  * partition_oid (in) : partition
3318  */
3320 partition_get_scancache (PRUNING_CONTEXT * pcontext, const OID * partition_oid)
3321 {
3322  SCANCACHE_LIST *node = NULL;
3323 
3324  if (partition_oid == NULL || pcontext == NULL)
3325  {
3326  assert_release (partition_oid != NULL);
3327  assert_release (pcontext == NULL);
3328  return NULL;
3329  }
3330 
3331  node = pcontext->scan_cache_list;
3332  while (node != NULL)
3333  {
3334  if (OID_EQ (&node->scan_cache.scan_cache.node.class_oid, partition_oid))
3335  {
3336  return &node->scan_cache;
3337  }
3338  node = node->next;
3339  }
3340 
3341  return NULL;
3342 }
3343 
3344 /*
3345  * partition_new_scancache () - create a new scan_cache object
3346  * return : scan_cache entry or NULL
3347  * pcontext (in) : pruning context
3348  */
3351 {
3352  SCANCACHE_LIST *node = NULL;
3353 
3354  node = (SCANCACHE_LIST *) db_private_alloc (pcontext->thread_p, sizeof (SCANCACHE_LIST));
3355  if (node == NULL)
3356  {
3357  return NULL;
3358  }
3359 
3360  node->scan_cache.is_scan_cache_started = false;
3361  node->scan_cache.n_indexes = 0;
3363 
3364  /* add it at the beginning */
3365  node->next = pcontext->scan_cache_list;
3366  pcontext->scan_cache_list = node;
3367 
3368  return &node->scan_cache;
3369 }
3370 
3371 /*
3372  * partition_get_partition_oids () - get OIDs of partition classes
3373  * return : error code or NO_ERROR
3374  * thread_p (in) :
3375  * class_oid (in) : partitioned class OID
3376  * partition_oids (in/out) : partition OIDs
3377  * count (in/out) : number of partitions
3378  */
3379 int
3380 partition_get_partition_oids (THREAD_ENTRY * thread_p, const OID * class_oid, OID ** partition_oids, int *count)
3381 {
3382  int error = NO_ERROR;
3383  PRUNING_CONTEXT context;
3384  int i;
3385  OID *oids = NULL;
3386  OR_CLASSREP *classrepr = NULL;
3387  int classrepr_cacheindex = -1;
3388  bool clear_pcontext = false;
3389 
3390  assert_release (class_oid != NULL);
3391  assert_release (partition_oids != NULL);
3392  assert_release (count != NULL);
3393 
3394  /* get class representation to find partition information */
3395  classrepr = heap_classrepr_get (thread_p, class_oid, NULL, NULL_REPRID, &classrepr_cacheindex);
3396  if (classrepr == NULL)
3397  {
3398  goto cleanup;
3399  }
3400 
3401  if (classrepr->has_partition_info > 0)
3402  {
3403  partition_init_pruning_context (&context);
3404  clear_pcontext = true;
3405 
3406  error = partition_load_pruning_context (thread_p, class_oid, DB_PARTITIONED_CLASS, &context);
3407  if (error != NO_ERROR)
3408  {
3409  goto cleanup;
3410  }
3411 
3412  if (context.count == 0)
3413  {
3414  *count = 0;
3415  *partition_oids = NULL;
3416  goto cleanup;
3417  }
3418  }
3419  else
3420  {
3421  *count = 0;
3422  *partition_oids = NULL;
3423  goto cleanup;
3424  }
3425  oids = (OID *) db_private_alloc (thread_p, PARTITIONS_COUNT (&context) * sizeof (OID));
3426  if (oids == NULL)
3427  {
3428  error = ER_FAILED;
3429  goto cleanup;
3430  }
3431  for (i = 0; i < PARTITIONS_COUNT (&context); i++)
3432  {
3433  COPY_OID (&oids[i], &context.partitions[i + 1].class_oid);
3434  }
3435  *count = PARTITIONS_COUNT (&context);
3436  *partition_oids = oids;
3437 
3438 cleanup:
3439  if (clear_pcontext == true)
3440  {
3442  }
3443  if (classrepr != NULL)
3444  {
3445  heap_classrepr_free_and_init (classrepr, &classrepr_cacheindex);
3446  }
3447  if (error != NO_ERROR)
3448  {
3449  if (oids != NULL)
3450  {
3451  db_private_free (thread_p, oids);
3452  }
3453  *partition_oids = NULL;
3454  *count = 0;
3455  }
3456  return error;
3457 }
3458 
3459 /*
3460  * partition_decrement_value () - decrement a DB_VALUE
3461  * return : true if value was decremented, false otherwise
3462  * val (in) : value to decrement
3463  */
3464 static bool
3466 {
3467  if (DB_IS_NULL (val))
3468  {
3469  return false;
3470  }
3471 
3472  switch (DB_VALUE_TYPE (val))
3473  {
3474  case DB_TYPE_INTEGER:
3475  val->data.i--;
3476  return true;
3477 
3478  case DB_TYPE_BIGINT:
3479  val->data.bigint--;
3480  return true;
3481 
3482  case DB_TYPE_SHORT:
3483  val->data.i--;
3484  return true;
3485 
3486  case DB_TYPE_TIME:
3487  val->data.time--;
3488  return true;
3489 
3490  case DB_TYPE_TIMESTAMP:
3491  case DB_TYPE_TIMESTAMPLTZ:
3492  val->data.utime--;
3493  return true;
3494 
3495  case DB_TYPE_TIMESTAMPTZ:
3496  val->data.timestamptz.timestamp--;
3497  return true;
3498 
3499  case DB_TYPE_DATETIME:
3500  case DB_TYPE_DATETIMELTZ:
3501  if (val->data.datetime.time == 0)
3502  {
3503  val->data.datetime.date--;
3505  }
3506  else
3507  {
3508  val->data.datetime.time--;
3509  }
3510  return true;
3511 
3512  case DB_TYPE_DATETIMETZ:
3513  if (val->data.datetimetz.datetime.time == 0)
3514  {
3515  val->data.datetimetz.datetime.date--;
3517  }
3518  else
3519  {
3520  val->data.datetimetz.datetime.time--;
3521  }
3522  return true;
3523 
3524  case DB_TYPE_DATE:
3525  if (val->data.date == 0)
3526  {
3527  return false;
3528  }
3529  val->data.date--;
3530  return true;
3531 
3532  default:
3533  return false;
3534  }
3535 
3536  return false;
3537 }
3538 
3539 /*
3540  * partition_prune_unique_btid () - prune an UNIQUE BTID key search
3541  * return : error code or NO_ERROR
3542  * pcontext (in) : pruning context
3543  * key (in) : search key
3544  * class_oid (in/out) : class OID
3545  * class_hfid (in/out): class HFID
3546  * btid (in/out) : class BTID
3547  *
3548  * Note: this function search for the partition which could contain the key
3549  * value and places the corresponding partition oid and btid in class_oid and
3550  * btid arguments
3551  */
3552 int
3553 partition_prune_unique_btid (PRUNING_CONTEXT * pcontext, DB_VALUE * key, OID * class_oid, HFID * class_hfid,
3554  BTID * btid)
3555 {
3556  int error = NO_ERROR, pos = 0;
3557  OID partition_oid;
3558  HFID partition_hfid;
3559  BTID partition_btid;
3560 
3561  error = partition_prune_partition_index (pcontext, key, class_oid, btid, &pos);
3562 
3563  if (error != NO_ERROR)
3564  {
3565  return error;
3566  }
3567 
3568  COPY_OID (&partition_oid, &pcontext->partitions[pos + 1].class_oid);
3569  HFID_COPY (&partition_hfid, &pcontext->partitions[pos + 1].class_hfid);
3570 
3571  error =
3572  partition_find_inherited_btid (pcontext->thread_p, &pcontext->root_oid, &partition_oid, btid, &partition_btid);
3573  if (error != NO_ERROR)
3574  {
3575  return error;
3576  }
3577 
3578  COPY_OID (class_oid, &partition_oid);
3579  HFID_COPY (class_hfid, &partition_hfid);
3580  BTID_COPY (btid, &partition_btid);
3581 
3582  return error;
3583 }
3584 
3585 /*
3586  * partition_find_inherited_btid () - find the inherited BTID for a class
3587  * return : error code or NO_ERROR
3588  * thread_p(in) : thread entry
3589  * src_class (in) : class which owns src_btid
3590  * dest_class (in) : class in which to search matching BTID
3591  * src_btid (in) : BTID to search for
3592  * dest_btid (in/out) : matching BTID
3593  */
3594 static int
3595 partition_find_inherited_btid (THREAD_ENTRY * thread_p, OID * src_class, OID * dest_class, BTID * src_btid,
3596  BTID * dest_btid)
3597 {
3598  char *btree_name = NULL;
3599  int error = NO_ERROR;
3600  error = heap_get_indexinfo_of_btid (thread_p, src_class, src_btid, NULL, NULL, NULL, NULL, &btree_name, NULL);
3601  if (error != NO_ERROR)
3602  {
3603  goto cleanup;
3604  }
3605  error = heap_get_index_with_name (thread_p, dest_class, btree_name, dest_btid);
3606  if (error != NO_ERROR)
3607  {
3608  goto cleanup;
3609  }
3610 
3611  if (BTID_IS_NULL (dest_btid))
3612  {
3613  assert (false);
3615  src_btid->vfid.volid, src_btid->root_pageid);
3616  error = ER_BTREE_INVALID_INDEX_ID;
3617  }
3618 
3619 cleanup:
3620  if (btree_name != NULL)
3621  {
3622  /* heap_get_indexinfo_of_btid calls strdup on the index name so we have to free it with free_and_init */
3623  free_and_init (btree_name);
3624  }
3625  return error;
3626 }
3627 
3628 /*
3629  * partition_load_aggregate_helper () - setup the members of an aggregate
3630  * helper
3631  * return : error code or NO_ERROR
3632  * pcontext (in) : pruning context
3633  * spec (in) : spec on which aggregates will be evaluated
3634  * pruned_count (in) : number of pruned partitions
3635  * root_btid (in) : BTID of the index in the partitioned class
3636  * helper (in/out) : aggregate helper
3637  */
3638 int
3640  BTID * root_btid, HIERARCHY_AGGREGATE_HELPER * helper)
3641 {
3642  int error = NO_ERROR, i = 0;
3643  char *btree_name = NULL;
3644  BTREE_TYPE btree_type;
3645  PARTITION_SPEC_TYPE *part = NULL;
3646 
3647  assert_release (helper != NULL);
3648 
3649  helper->btids = NULL;
3650  helper->hfids = NULL;
3651  helper->count = 0;
3652 
3653  if (spec->pruning_type != DB_PARTITIONED_CLASS || !spec->pruned)
3654  {
3655  return NO_ERROR;
3656  }
3657 
3658  /* setup pruned HFIDs */
3659  helper->hfids = (HFID *) db_private_alloc (pcontext->thread_p, pruned_count * sizeof (HFID));
3660  if (helper->hfids == NULL)
3661  {
3662  error = ER_OUT_OF_VIRTUAL_MEMORY;
3663  goto cleanup;
3664  }
3665 
3666  for (i = 0, part = spec->parts; part != NULL; i++, part = part->next)
3667  {
3668  HFID_COPY (&helper->hfids[i], &part->hfid);
3669  }
3670 
3671  assert (i == pruned_count);
3672  helper->count = pruned_count;
3673 
3674  if (BTID_IS_NULL (root_btid))
3675  {
3676  /* no BTID specified */
3677  return NO_ERROR;
3678  }
3679 
3680  error =
3681  heap_get_indexinfo_of_btid (pcontext->thread_p, &pcontext->root_oid, root_btid, &btree_type, NULL, NULL, NULL,
3682  &btree_name, NULL);
3683  if (error != NO_ERROR)
3684  {
3685  goto cleanup;
3686  }
3687 
3688  /* get local BTIDs for pruned partitions */
3689  helper->btids = (BTID *) db_private_alloc (pcontext->thread_p, pruned_count * sizeof (BTID));
3690  if (helper->btids == NULL)
3691  {
3692  error = ER_OUT_OF_VIRTUAL_MEMORY;
3693  goto cleanup;
3694  }
3695 
3696  for (i = 0, part = spec->parts; part != NULL; i++, part = part->next)
3697  {
3698  error = heap_get_index_with_name (pcontext->thread_p, &part->oid, btree_name, &helper->btids[i]);
3699  if (error != NO_ERROR)
3700  {
3701  goto cleanup;
3702  }
3703  }
3704 
3705 cleanup:
3706  if (error != NO_ERROR)
3707  {
3708  if (helper->btids != NULL)
3709  {
3710  db_private_free_and_init (pcontext->thread_p, helper->btids);
3711  }
3712  if (helper->hfids != NULL)
3713  {
3714  db_private_free_and_init (pcontext->thread_p, helper->hfids);
3715  }
3716  helper->count = 0;
3717  }
3718 
3719  if (btree_name != NULL)
3720  {
3721  free_and_init (btree_name);
3722  }
3723  return error;
3724 }
3725 
3726 #if 0
3727 /*
3728  * partition_is_global_index () - check if an index is global for a partitioned
3729  * class
3730  * return : error code or NO_ERROR
3731  * thread_p (in) :
3732  * class_oid (in) : partitioned class OID
3733  * contextp (in) : pruning context, NULL if it is unknown
3734  * btid (in) : btree ID of the index
3735  * btree_typep (in) : btree type of the index, NULL if it is unknown
3736  * is_global_index(out) :
3737  */
3738 int
3739 partition_is_global_index (THREAD_ENTRY * thread_p, PRUNING_CONTEXT * contextp, OID * class_oid, BTID * btid,
3740  BTREE_TYPE * btree_typep, int *is_global_index)
3741 {
3742  PRUNING_CONTEXT context;
3743  BTREE_TYPE btree_type;
3744  int error = NO_ERROR;
3745 
3746  assert (class_oid != NULL);
3747  assert (btid != NULL);
3748 
3749  *is_global_index = 0;
3750 
3751  if (contextp == NULL)
3752  {
3753  /* PRUNING_CONTEXT is unknown */
3754  contextp = &context;
3755 
3756  partition_init_pruning_context (contextp);
3757 
3758  error = partition_load_pruning_context (thread_p, class_oid, DB_PARTITIONED_CLASS, contextp);
3759  if (error != NO_ERROR)
3760  {
3761  goto cleanup;
3762  }
3763  }
3764 
3765  if (contextp->count == 0)
3766  {
3767  goto cleanup;
3768  }
3769 
3770  if (btree_typep == NULL)
3771  {
3772  /* btree_type is unknown */
3773  btree_typep = &btree_type;
3774 
3775  error = heap_get_indexinfo_of_btid (thread_p, class_oid, btid, btree_typep, NULL, NULL, NULL, NULL, NULL);
3776  if (error != NO_ERROR)
3777  {
3778  goto cleanup;
3779  }
3780  }
3781 
3782  if (*btree_typep == BTREE_PRIMARY_KEY)
3783  {
3784  *is_global_index = 1;
3785  goto cleanup;
3786  }
3787 
3788  if (btree_is_unique_type (*btree_typep))
3789  {
3790  error = partition_get_position_in_key (contextp, btid);
3791  if (error != NO_ERROR)
3792  {
3793  goto cleanup;
3794  }
3795 
3796  if (contextp->attr_position == -1)
3797  {
3798  *is_global_index = 1;
3799  goto cleanup;
3800  }
3801  }
3802 
3803 cleanup:
3804  if (contextp == &context)
3805  {
3807  }
3808 
3809  return error;
3810 }
3811 #endif
3812 
3813 /*
3814  * partition_attrinfo_get_key () - retrieves the appropiate partitioning key
3815  * from a given index key, by which pruning will be
3816  * performed.
3817  * return : error code or NO_ERROR
3818  * thread_p (in) :
3819  * pcontext (in) : pruning context, NULL if it is unknown
3820  * curr_key (in) : index key to be searched
3821  * class_oid (in) : partitioned class OID
3822  * btid (in) : btree ID of the index
3823  * partition_key(out) : value holding the extracted partition key
3824  */
3825 static int
3826 partition_attrinfo_get_key (THREAD_ENTRY * thread_p, PRUNING_CONTEXT * pcontext, DB_VALUE * curr_key, OID * class_oid,
3827  BTID * btid, DB_VALUE * partition_key)
3828 {
3829  PRUNING_CONTEXT context;
3830  int error = NO_ERROR;
3831  ATTR_ID *btree_attr_ids = NULL;
3832  int btree_num_attr = 0;
3833 
3834  if (pcontext == NULL)
3835  {
3836  /* PRUNING_CONTEXT is unknown */
3837  pcontext = &context;
3838 
3839  partition_init_pruning_context (pcontext);
3840 
3841  error = partition_load_pruning_context (thread_p, class_oid, DB_PARTITIONED_CLASS, pcontext);
3842  if (error != NO_ERROR)
3843  {
3844  goto cleanup;
3845  }
3846  }
3847 
3848  /* read partition attribute information */
3849  if (pcontext->is_attr_info_inited == false)
3850  {
3851  error = heap_attrinfo_start (thread_p, &pcontext->root_oid, 1, &pcontext->attr_id, &pcontext->attr_info);
3852  if (error != NO_ERROR)
3853  {
3854  goto cleanup;
3855  }
3856 
3857  partition_set_cache_info_for_expr (pcontext->partition_pred->func_regu, pcontext->attr_id, &pcontext->attr_info);
3858  pcontext->is_attr_info_inited = true;
3859  }
3860 
3861  /* read btree information */
3862  error =
3863  heap_get_indexinfo_of_btid (thread_p, class_oid, btid, NULL, &btree_num_attr, &btree_attr_ids, NULL, NULL, NULL);
3864  if (error != NO_ERROR)
3865  {
3866  goto cleanup;
3867  }
3868 
3869  if (DB_VALUE_TYPE (curr_key) == DB_TYPE_MIDXKEY)
3870  {
3871  curr_key->data.midxkey.domain = btree_read_key_type (thread_p, btid);
3872  if (curr_key->data.midxkey.domain == NULL)
3873  {
3874  error = ER_FAILED;
3875  goto cleanup;
3876  }
3877  }
3878  error = btree_attrinfo_read_dbvalues (thread_p, curr_key, btree_attr_ids, btree_num_attr, &pcontext->attr_info, -1);
3879  if (error != NO_ERROR)
3880  {
3881  goto cleanup;
3882  }
3883 
3884  /* just use the corresponding db_value from attribute information */
3885  if (pcontext->attr_info.values[0].state == HEAP_UNINIT_ATTRVALUE)
3886  {
3887  error = ER_FAILED;
3888  goto cleanup;
3889  }
3890  error = pr_clone_value (&pcontext->attr_info.values[0].dbvalue, partition_key);
3891  if (error != NO_ERROR)
3892  {
3893  goto cleanup;
3894  }
3895 
3896 cleanup:
3897  if (pcontext == &context)
3898  {
3900  }
3901  if (btree_attr_ids)
3902  {
3903  db_private_free_and_init (thread_p, btree_attr_ids);
3904  }
3905 
3906  return error;
3907 }
3908 
3909 /*
3910  * partition_prune_partition_index (): - Gets the index of the partition where the key resides.
3911  *
3912  * return : - NO_ERROR or error code.
3913  *
3914  * pcontext (in) - Context of the partitions.
3915  * key(in) - The key to be located.
3916  * class_oid(in/out) - The correct OID of the object that contains the key.
3917  * btid(in/out) - The correct BTID of the tree that contains the key.
3918  * position(out) - The number of the partition that holds the key.
3919  *
3920  * NOTE:
3921  * - At the entry of the function, btid and class_oid should refer to the btid and oid, respectively,
3922  * of the root table on which the partitions are created. This ensures the correctness of the btid,
3923  * and class_oid on function exit.
3924  */
3925 int
3926 partition_prune_partition_index (PRUNING_CONTEXT * pcontext, DB_VALUE * key, OID * class_oid, BTID * btid,
3927  int *position)
3928 {
3929  int error = NO_ERROR;
3930  int pos = 0;
3931  DB_VALUE partition_key;
3932  PRUNING_BITSET pruned;
3934  MATCH_STATUS status = MATCH_NOT_FOUND;
3935 
3936  if (pcontext == NULL)
3937  {
3938  assert_release (pcontext != NULL);
3939  return ER_FAILED;
3940  }
3941 
3942  if (pcontext->pruning_type == DB_PARTITION_CLASS)
3943  {
3944  /* btid is the BTID of the index corresponding to the partition. Find the BTID of the root class and use that one */
3945  error = partition_find_inherited_btid (pcontext->thread_p, class_oid, &pcontext->root_oid, btid, btid);
3946 
3947  if (error != NO_ERROR)
3948  {
3949  return error;
3950  }
3951  }
3952 
3953  error = partition_attrinfo_get_key (pcontext->thread_p, pcontext, key, &pcontext->root_oid, btid, &partition_key);
3954  if (error != NO_ERROR)
3955  {
3956  return error;
3957  }
3958 
3959  pruningset_init (&pruned, PARTITIONS_COUNT (pcontext));
3960  status = partition_prune_db_val (pcontext, &partition_key, PO_EQ, &pruned);
3961  pr_clear_value (&partition_key);
3962 
3963  if (status == MATCH_NOT_FOUND)
3964  {
3965  /* This can happen only if there's no partition that can hold the key value (for example, if this is called by ON
3966  * DUPLICATE KEY UPDATE but the value that is being inserted will throw an error anyway) */
3967  return NO_ERROR;
3968  }
3969  else if (pruningset_popcount (&pruned) != 1)
3970  {
3971  /* a key value should always return at most one partition */
3972  assert (false);
3973  OID_SET_NULL (class_oid);
3974  return NO_ERROR;
3975  }
3976 
3977  pruningset_iterator_init (&pruned, &it);
3978  pos = pruningset_iterator_next (&it);
3979 
3980  *position = pos;
3981  return error;
3982 }
pred_expr * lhs
regu_variable_node * key1
Definition: access_spec.hpp:67
static MATCH_STATUS partition_prune_hash(PRUNING_CONTEXT *pinfo, const DB_VALUE *val, const PRUNING_OP op, PRUNING_BITSET *pruned)
Definition: partition.c:1212
DB_TIME time
Definition: dbtype_def.h:1056
static int partition_free_cache_entry(PARTITION_CACHE_ENTRY *entry)
Definition: partition.c:405
void partition_decache_class(THREAD_ENTRY *thread_p, const OID *class_oid)
Definition: partition.c:775
static int partition_cache_pruning_context(PRUNING_CONTEXT *pinfo, bool *already_exists)
Definition: partition.c:575
#define NO_ERROR
Definition: error_code.h:46
HEAP_CACHE_ATTRINFO attr_info
Definition: partition_sr.h:86
static MATCH_STATUS partition_prune(PRUNING_CONTEXT *pinfo, const REGU_VARIABLE *arg, const PRUNING_OP op, PRUNING_BITSET *pruned)
Definition: partition.c:1515
int or_rep_id(RECDES *record)
DB_COLLECTION * db_get_set(const DB_VALUE *value)
SCANCACHE_LIST * next
Definition: partition_sr.h:62
key_range * key_ranges
Definition: access_spec.hpp:75
DB_VALUE_COMPARE_RESULT tp_value_compare(const DB_VALUE *value1, const DB_VALUE *value2, int allow_coercion, int total_order)
bool db_value_type_is_collection(const DB_VALUE *value)
Definition: db_macro.c:1144
#define ASSERT_ERROR()
static int partition_prune_heap_scan(PRUNING_CONTEXT *pinfo)
Definition: partition.c:2709
REGU_VARIABLE * rightptr
Definition: regu_var.hpp:129
RANGE_TYPE
int partition_load_aggregate_helper(PRUNING_CONTEXT *pcontext, access_spec_node *spec, int pruned_count, BTID *root_btid, HIERARCHY_AGGREGATE_HELPER *helper)
Definition: partition.c:3639
enum pruning_op PRUNING_OP
static MATCH_STATUS partition_match_index_key(PRUNING_CONTEXT *pinfo, const KEY_INFO *key, RANGE_TYPE range_type, PRUNING_BITSET *pruned)
Definition: partition.c:2122
DB_TIMESTAMP timestamp
Definition: dbtype_def.h:766
int partition_load_pruning_context(THREAD_ENTRY *thread_p, const OID *class_oid, int pruning_type, PRUNING_CONTEXT *pinfo)
Definition: partition.c:2249
INDX_INFO * indexptr
Definition: xasl.h:927
#define ER_FAILED
Definition: error_code.h:47
TYPE_EVAL_TERM et_type
REGU_VARIABLE_LIST next
Definition: regu_var.hpp:221
#define csect_enter(a, b, c)
Definition: cnv.c:138
int partition_get_partition_oids(THREAD_ENTRY *thread_p, const OID *class_oid, OID **partition_oids, int *count)
Definition: partition.c:3380
BTREE_TYPE
const void * mht_put_if_not_exists(MHT_TABLE *ht, const void *key, void *data)
Definition: memory_hash.c:1749
int mht_rem(MHT_TABLE *ht, const void *key, int(*rem_func)(const void *key, void *data, void *args), void *func_args)
Definition: memory_hash.c:1952
DB_DATETIME datetime
Definition: dbtype_def.h:1060
REGU_VARIABLE * leftptr
Definition: regu_var.hpp:128
static void pruningset_union(PRUNING_BITSET *, const PRUNING_BITSET *)
Definition: partition.c:263
OR_PARTITION * selected_partition
Definition: partition_sr.h:77
static void partition_set_specified_partition(PRUNING_CONTEXT *pinfo, const OID *partition_oid)
Definition: partition.c:2504
regu_variable_node * elem
int btree_attrinfo_read_dbvalues(THREAD_ENTRY *thread_p, DB_VALUE *curr_key, int *btree_att_ids, int btree_num_att, HEAP_CACHE_ATTRINFO *attr_info, int func_index_col_id)
Definition: btree.c:15938
ATTR_ID attr_id
Definition: partition.c:100
#define assert_release(e)
Definition: error_manager.h:96
TARGET_TYPE type
Definition: xasl.h:925
val_descr * vd
Definition: partition_sr.h:73
#define ER_PARTITION_NOT_EXIST
Definition: error_code.h:1110
func_pred * partition_pred
Definition: partition_sr.h:83
xasl_unpack_info * fp_cache_context
Definition: partition_sr.h:82
#define OID_SET_NULL(oidp)
Definition: oid.h:85
#define ER_BTREE_INVALID_INDEX_ID
Definition: error_code.h:482
int count
Definition: partition.c:98
static bool pruningset_is_set(const PRUNING_BITSET *, int)
Definition: partition.c:286
static bool partition_is_reguvar_const(const REGU_VARIABLE *regu_var)
Definition: partition.c:1637
static PARTITION_CACHE_ENTRY * partition_pruning_context_to_cache_entry(PRUNING_CONTEXT *pinfo)
Definition: partition.c:477
static bool partition_decrement_value(DB_VALUE *val)
Definition: partition.c:3465
INT32 root_pageid
REL_OP
#define er_log_debug(...)
static MATCH_STATUS partition_prune_db_val(PRUNING_CONTEXT *pinfo, const DB_VALUE *val, const PRUNING_OP op, PRUNING_BITSET *pruned)
Definition: partition.c:1486
HL_HEAPID db_change_private_heap(THREAD_ENTRY *thread_p, HL_HEAPID heap_id)
Definition: memory_alloc.c:337
int heap_scancache_end(THREAD_ENTRY *thread_p, HEAP_SCANCACHE *scan_cache)
Definition: heap_file.c:7195
REPR_ID root_repr_id
Definition: partition_sr.h:71
static MATCH_STATUS partition_prune_range(PRUNING_CONTEXT *pinfo, const DB_VALUE *val, const PRUNING_OP op, PRUNING_BITSET *pruned)
Definition: partition.c:1331
regu_variable_node * lhs
enum match_status MATCH_STATUS
#define COPY_OID(dest_oid_ptr, src_oid_ptr)
Definition: oid.h:63
static void partition_free_partition_predicate(PRUNING_CONTEXT *pinfo)
Definition: partition.c:2481
static int partition_get_value_from_key(PRUNING_CONTEXT *pinfo, const REGU_VARIABLE *key, DB_VALUE *attr_key, bool *is_present)
Definition: partition.c:1683
#define PARTITION_CACHE_SIZE
Definition: partition.c:85
static void pruningset_set_all(PRUNING_BITSET *)
Definition: partition.c:190
void THREAD_ENTRY
HEAP_SCANCACHE_NODE node
Definition: heap_file.h:144
#define BITSET_WORD_COUNT
Definition: partition.c:65
int ATTR_ID
RANGE range
Definition: access_spec.hpp:69
static MATCH_STATUS partition_prune_list(PRUNING_CONTEXT *pinfo, const DB_VALUE *val, const PRUNING_OP op, PRUNING_BITSET *pruned)
Definition: partition.c:1077
KEY_INFO key_info
Definition: access_spec.hpp:91
static int partition_free_cache_entry_kv(const void *key, void *data, void *args)
Definition: partition.c:389
ACCESS_METHOD access
Definition: xasl.h:926
DB_BIGINT bigint
Definition: dbtype_def.h:1051
void mht_destroy(MHT_TABLE *ht)
Definition: memory_hash.c:1140
DB_DATA data
Definition: dbtype_def.h:1083
void partition_clear_pruning_context(PRUNING_CONTEXT *pinfo)
Definition: partition.c:2380
TP_DOMAIN * btree_read_key_type(THREAD_ENTRY *thread_p, BTID *btid)
Definition: btree.c:9079
int heap_attrinfo_start(THREAD_ENTRY *thread_p, const OID *class_oid, int requested_num_attrs, const ATTR_ID *attrids, HEAP_CACHE_ATTRINFO *attr_info)
Definition: heap_file.c:9427
void er_set(int severity, const char *file_name, const int line_no, int err_id, int num_args,...)
bool is_attr_info_inited
Definition: partition_sr.h:91
static int pruningset_iterator_next(PRUNING_BITSET_ITERATOR *)
Definition: partition.c:340
Definition: db_set.h:35
DB_TIMESTAMP utime
Definition: dbtype_def.h:1058
int db_set_get(DB_SET *set, int index, DB_VALUE *value)
Definition: db_set.c:508
#define assert(x)
REGU_VARIABLE * func_regu
Definition: xasl.h:277
static bool partition_do_regu_variables_match(PRUNING_CONTEXT *pinfo, const REGU_VARIABLE *left, const REGU_VARIABLE *right)
Definition: partition.c:968
static void pruningset_remove(PRUNING_BITSET *, int)
Definition: partition.c:233
int32_t fileid
Definition: dbtype_def.h:886
PRUNING_SCAN_CACHE scan_cache
Definition: partition_sr.h:63
#define ER_GENERIC_ERROR
Definition: error_code.h:49
#define OID_IS_ROOTOID(oidp)
Definition: oid.h:82
int partition_find_root_class_oid(THREAD_ENTRY *thread_p, const OID *class_oid, OID *super_oid)
Definition: partition.c:2199
DB_IDENTIFIER OID
Definition: dbtype_def.h:967
int partition_prune_unique_btid(PRUNING_CONTEXT *pcontext, DB_VALUE *key, OID *class_oid, HFID *class_hfid, BTID *btid)
Definition: partition.c:3553
comp_eval_term et_comp
#define ER_OUT_OF_VIRTUAL_MEMORY
Definition: error_code.h:50
THREAD_ENTRY * thread_p
Definition: partition_sr.h:69
REGU_VARIABLE value
Definition: regu_var.hpp:222
DB_DATETIME datetime
Definition: dbtype_def.h:783
union cubxasl::pred_expr::@185 pe
DB_SEQ * db_seq_copy(DB_SEQ *source)
Definition: db_set.c:428
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
static MATCH_STATUS partition_match_key_range(PRUNING_CONTEXT *pinfo, const KEY_RANGE *range, PRUNING_BITSET *pruned)
Definition: partition.c:1981
static int partition_attrinfo_get_key(THREAD_ENTRY *thread_p, PRUNING_CONTEXT *pcontext, DB_VALUE *curr_key, OID *class_oid, BTID *btid, DB_VALUE *partition_key)
Definition: partition.c:3826
#define BITSET_LENGTH(s)
Definition: partition.c:66
#define min(a, b)
static int partition_get_value_from_inarith(PRUNING_CONTEXT *pinfo, const REGU_VARIABLE *src, DB_VALUE *value_p, bool *is_present)
Definition: partition.c:1784
access_spec_node * spec
Definition: partition_sr.h:72
int stx_map_stream_to_func_pred(THREAD_ENTRY *thread_p, func_pred **xasl, char *xasl_stream, int xasl_stream_size, XASL_UNPACK_INFO **xasl_unpack_info_ptr)
#define OID_EQ(oidp1, oidp2)
Definition: oid.h:92
#define heap_classrepr_free_and_init(class_repr, idxp)
Definition: heap_file.h:91
void partition_cache_finalize(THREAD_ENTRY *thread_p)
Definition: partition.c:748
TP_DOMAIN_STATUS tp_value_cast(const DB_VALUE *src, DB_VALUE *dest, const TP_DOMAIN *desired_domain, bool implicit_coercion)
int heap_attrinfo_read_dbvalues(THREAD_ENTRY *thread_p, const OID *inst_oid, RECDES *recdes, HEAP_SCANCACHE *scan_cache, HEAP_CACHE_ATTRINFO *attr_info)
Definition: heap_file.c:10337
static int pruningset_to_spec_list(PRUNING_CONTEXT *pinfo, const PRUNING_BITSET *pruned)
Definition: partition.c:864
#define TP_DOMAIN_TYPE(dom)
#define ACCESS_SPEC_CLS_OID(ptr)
Definition: xasl.h:806
#define PARTITIONS_COUNT(pinfo)
Definition: partition.c:82
int qexec_clear_partition_expression(THREAD_ENTRY *thread_p, regu_variable_node *expr)
static void cleanup(int signo)
Definition: broker.c:717
void * mht_get(MHT_TABLE *ht, const void *key)
Definition: memory_hash.c:1419
#define NULL
Definition: freelistheap.h:34
int db_set_has_null(DB_COLLECTION *set)
Definition: db_set.c:644
int heap_attrinfo_clear_dbvalues(HEAP_CACHE_ATTRINFO *attr_info)
Definition: heap_file.c:10022
if(extra_options)
Definition: dynamic_load.c:958
DB_DATE date
Definition: dbtype_def.h:1057
regu_variable_node * rhs
VFID vfid
static MHT_TABLE * db_Partition_Ht
Definition: partition.c:88
DB_TIMESTAMPTZ timestamptz
Definition: dbtype_def.h:1059
static bool partition_load_context_from_cache(PRUNING_CONTEXT *pinfo, bool *is_modified)
Definition: partition.c:647
#define MILLISECONDS_OF_ONE_DAY
int db_seq_free(DB_SEQ *seq)
Definition: db_set.c:323
#define db_private_free_and_init(thrd, ptr)
Definition: memory_alloc.h:141
static void pruningset_add(PRUNING_BITSET *, int)
Definition: partition.c:221
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
static int partition_cache_entry_to_pruning_context(PRUNING_CONTEXT *pinfo, PARTITION_CACHE_ENTRY *entry_p)
Definition: partition.c:447
void partition_init_pruning_context(PRUNING_CONTEXT *pinfo)
Definition: partition.c:2164
#define csect_exit(a, b)
Definition: cnv.c:139
#define db_private_free(thrd, ptr)
Definition: memory_alloc.h:229
DB_VALUE * value
Definition: regu_var.hpp:127
static void partition_set_cache_info_for_expr(REGU_VARIABLE *regu_var, ATTR_ID attr_id, HEAP_CACHE_ATTRINFO *info)
Definition: partition.c:2527
unsigned int oid_hash(const void *key_oid, unsigned int htsize)
Definition: oid.c:294
#define db_private_alloc(thrd, size)
Definition: memory_alloc.h:227
#define CONST_CAST(dest_type, expr)
Definition: porting.h:1060
OR_PARTITION * partitions
Definition: partition_sr.h:76
int func_idx_col_id
Definition: access_spec.hpp:98
const PRUNING_BITSET * set
Definition: partition.c:78
int or_set_rep_id(RECDES *record, int repid)
int partition_prune_partition_index(PRUNING_CONTEXT *pcontext, DB_VALUE *key, OID *class_oid, BTID *btid, int *position)
Definition: partition.c:3926
int db_set_size(DB_SET *set)
Definition: db_set.c:557
OR_CLASSREP * heap_classrepr_get(THREAD_ENTRY *thread_p, const OID *class_oid, RECDES *class_recdes, REPR_ID reprid, int *idx_incache)
Definition: heap_file.c:2299
int pr_clear_value(DB_VALUE *value)
DB_PARTITION_TYPE partition_type
Definition: partition_sr.h:74
DB_PARTITION_TYPE
#define NULL_REPRID
#define max(a, b)
static int pruningset_popcount(const PRUNING_BITSET *)
Definition: partition.c:298
int oid_compare_equals(const void *key_oid1, const void *key_oid2)
Definition: oid.c:310
static int partition_prune_index_scan(PRUNING_CONTEXT *pinfo)
Definition: partition.c:2762
PRED_EXPR * where_pred
Definition: xasl.h:930
DB_VALUE * dbval_ptr
static MATCH_STATUS partition_match_pred_expr(PRUNING_CONTEXT *pinfo, const PRED_EXPR *pr, PRUNING_BITSET *pruned)
Definition: partition.c:1829
void free_xasl_unpack_info(THREAD_ENTRY *thread_p, REFPTR(XASL_UNPACK_INFO, xasl_unpack_info))
int heap_get_index_with_name(THREAD_ENTRY *thread_p, OID *class_oid, const char *index_name, BTID *btid)
Definition: heap_file.c:13092
static void error(const char *msg)
Definition: gencat.c:331
SCANCACHE_LIST * scan_cache_list
Definition: partition_sr.h:79
OR_PARTITION * partitions
Definition: partition.c:97
PRUNING_SCAN_CACHE * partition_new_scancache(PRUNING_CONTEXT *pcontext)
Definition: partition.c:3350
static void pruningset_intersect(PRUNING_BITSET *, const PRUNING_BITSET *)
Definition: partition.c:246
bool db_value_is_null(const DB_VALUE *value)
#define ARG_FILE_LINE
Definition: error_manager.h:44
static int partition_find_partition_for_record(PRUNING_CONTEXT *pinfo, const OID *class_oid, RECDES *recdes, OID *partition_oid, HFID *partition_hfid)
Definition: partition.c:2954
#define PARTITION_CACHE_NAME
Definition: partition.c:84
unsigned int mht_get_hash_number(const int ht_size, const DB_VALUE *val)
Definition: memory_hash.c:2275
int db_set_ismember(DB_SET *set, DB_VALUE *value)
Definition: db_set.c:598
int pr_clone_value(const DB_VALUE *src, DB_VALUE *dest)
regu_variable_node * key2
Definition: access_spec.hpp:68
regu_variable_node * elemset
#define csect_enter_as_reader(a, b, c)
RANGE_TYPE range_type
Definition: access_spec.hpp:90
#define free_and_init(ptr)
Definition: memory_alloc.h:147
#define BTID_COPY(btid_ptr1, btid_ptr2)
int heap_get_class_partitions(THREAD_ENTRY *thread_p, const OID *class_oid, OR_PARTITION **parts, int *parts_count)
Definition: heap_file.c:11016
#define PARTITION_IS_CACHE_INITIALIZED()
Definition: partition.c:90
DB_DOMAIN * domain
Definition: dbtype_def.h:865
#define BITS_IN_WORD
Definition: partition.c:64
unsigned int date
Definition: dbtype_def.h:776
class regu_variable_node REGU_VARIABLE
Definition: regu_var.hpp:64
int db_get_string_size(const DB_VALUE *value)
PRED_EXPR * where_key
Definition: xasl.h:929
void er_clear(void)
static PRUNING_OP partition_rel_op_to_pruning_op(REL_OP op)
Definition: partition.c:798
int REPR_ID
static void pruningset_init(PRUNING_BITSET *, int)
Definition: partition.c:178
#define ER_INVALID_DATA_FOR_PARTITION
Definition: error_code.h:1402
#define DB_VALUE_TYPE(value)
Definition: dbtype.h:72
int i
Definition: dynamic_load.c:954
int mht_map(const MHT_TABLE *ht, int(*map_func)(const void *key, void *data, void *args), void *func_args)
Definition: memory_hash.c:2199
int db_make_null(DB_VALUE *value)
int partition_prune_spec(THREAD_ENTRY *thread_p, val_descr *vd, access_spec_node *spec)
Definition: partition.c:2841
#define DB_IS_NULL(value)
Definition: dbtype.h:63
static int partition_load_partition_predicate(PRUNING_CONTEXT *pinfo, OR_PARTITION *master)
Definition: partition.c:2437
#define NULL_ATTRID
int partition_prune_insert(THREAD_ENTRY *thread_p, const OID *class_oid, RECDES *recdes, HEAP_SCANCACHE *scan_cache, PRUNING_CONTEXT *pcontext, int pruning_type, OID *pruned_class_oid, HFID *pruned_hfid, OID *superclass_oid)
Definition: partition.c:3092
static int partition_find_inherited_btid(THREAD_ENTRY *thread_p, OID *src_class, OID *dest_class, BTID *src_btid, BTID *dest_btid)
Definition: partition.c:3595
TYPE_PRED_EXPR type
pruning_op
Definition: partition.c:45
#define BTID_IS_NULL(btid)
static void pruningset_copy(PRUNING_BITSET *, const PRUNING_BITSET *)
Definition: partition.c:202
DB_MIDXKEY midxkey
Definition: dbtype_def.h:1065
#define BITSET_WORD_SIZE
Definition: partition.c:63
void heap_attrinfo_end(THREAD_ENTRY *thread_p, HEAP_CACHE_ATTRINFO *attr_info)
Definition: heap_file.c:9979
unsigned int set[BITSET_WORD_COUNT]
Definition: partition.c:71
REGU_VARIABLE * thirdptr
Definition: regu_var.hpp:130
short volid
Definition: dbtype_def.h:887
alsm_eval_term et_alsm
OID class_oid
Definition: partition.c:95
int heap_get_class_supers(THREAD_ENTRY *thread_p, const OID *class_oid, OID **super_oids, int *count)
Definition: heap_file.c:11153
union cubxasl::eval_term::@184 et
#define OID_ISNULL(oidp)
Definition: oid.h:81
int heap_get_indexinfo_of_btid(THREAD_ENTRY *thread_p, const OID *class_oid, const BTID *btid, BTREE_TYPE *type, int *num_attrs, ATTR_ID **attr_ids, int **attrs_prefix_length, char **btnamepp, int *func_index_col_id)
Definition: heap_file.c:13134
void heap_clear_partition_info(THREAD_ENTRY *thread_p, OR_PARTITION *parts, int parts_count)
Definition: heap_file.c:11126
pred_expr * rhs
PRUNING_SCAN_CACHE * partition_get_scancache(PRUNING_CONTEXT *pcontext, const OID *partition_oid)
Definition: partition.c:3320
static int partition_get_value_from_regu_var(PRUNING_CONTEXT *pinfo, const REGU_VARIABLE *key, DB_VALUE *value_p, bool *is_value)
Definition: partition.c:1560
match_status
Definition: partition.c:39
Definition: partition.c:93
int pruning_type
Definition: xasl.h:936
static ATTR_ID partition_get_attribute_id(REGU_VARIABLE *regu_var)
Definition: partition.c:2583
bool btree_is_unique_type(BTREE_TYPE type)
Definition: btree.c:6046
#define HFID_COPY(hfid_ptr1, hfid_ptr2)
static int partition_get_position_in_key(PRUNING_CONTEXT *pinfo, BTID *btid)
Definition: partition.c:2656
DB_CONST_C_CHAR db_get_string(const DB_VALUE *value)
int partition_cache_init(THREAD_ENTRY *thread_p)
Definition: partition.c:711
unsigned int time
Definition: dbtype_def.h:777
bool log_is_class_being_modified(THREAD_ENTRY *thread_p, const OID *class_oid)
Definition: log_manager.c:4786
HEAP_SCANCACHE scan_cache
Definition: partition_sr.h:52
void heap_free_func_pred_unpack_info(THREAD_ENTRY *thread_p, int n_indexes, FUNC_PRED_UNPACK_INFO *func_indx_preds, int *attr_info_started)
Definition: heap_file.c:17621
func_pred_unpack_info * func_index_pred
Definition: partition_sr.h:54
int partition_prune_update(THREAD_ENTRY *thread_p, const OID *class_oid, RECDES *recdes, PRUNING_CONTEXT *pcontext, int pruning_type, OID *pruned_class_oid, HFID *pruned_hfid, OID *superclass_oid)
Definition: partition.c:3199
static void pruningset_iterator_init(const PRUNING_BITSET *, PRUNING_BITSET_ITERATOR *)
Definition: partition.c:328
BOOL_OP
DB_DATETIMETZ datetimetz
Definition: dbtype_def.h:1061