CUBRID Engine  latest
locator_sr.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  * locator_sr.c : Transaction object locator (at server)
21  */
22 
23 #ident "$Id$"
24 
25 #include "config.h"
26 
27 #include <algorithm>
28 
29 #include <stdlib.h>
30 #include <string.h>
31 #include <fcntl.h>
32 #include <assert.h>
33 #include <cstring> // for std::memcpy
34 
35 #include "locator_sr.h"
36 
37 #include "boot_sr.h"
38 #include "btree_load.h"
39 #include "critical_section.h"
40 #include "dbtype.h"
41 #if defined(DMALLOC)
42 #include "dmalloc.h"
43 #endif /* DMALLOC */
44 #include "error_manager.h"
45 #include "fetch.h"
46 #include "filter_pred_cache.h"
47 #include "heap_file.h"
48 #include "list_file.h"
49 #include "log_lsa.hpp"
50 #include "lock_manager.h"
51 #include "object_primitive.h"
52 #include "object_representation.h"
54 #include "query_executor.h"
55 #include "query_manager.h"
56 #include "query_reevaluation.hpp"
57 #if defined(ENABLE_SYSTEMTAP)
58 #include "probes.h"
59 #endif /* ENABLE_SYSTEMTAP */
60 #include "record_descriptor.hpp"
61 #include "slotted_page.h"
62 #include "xasl_cache.h"
63 #include "xasl_predicate.hpp"
64 #include "thread_manager.hpp" // for thread_get_thread_entry_info
66 #include "xserver_interface.h"
67 
68 /* TODO : remove */
69 extern bool catcls_Enable;
70 
71 static const int LOCATOR_GUESS_NUM_NESTED_REFERENCES = 100;
72 #define LOCATOR_GUESS_HT_SIZE LOCATOR_GUESS_NUM_NESTED_REFERENCES * 2
73 
74 #define CLASSNAME_CACHE_SIZE 1024
75 
76 /* flag for INSERT/UPDATE/DELETE statement */
77 typedef enum
78 {
79  FOR_INSERT_OR_DELETE, /* It is an delete or insert statement, not update statement */
80  FOR_MOVE /* It is an update statement on partitioned table, move a record from one partition to
81  * another */
83 
84 extern int catcls_insert_catalog_classes (THREAD_ENTRY * thread_p, RECDES * record);
85 extern int catcls_delete_catalog_classes (THREAD_ENTRY * thread_p, const char *name, OID * class_oid);
86 extern int catcls_update_catalog_classes (THREAD_ENTRY * thread_p, const char *name, RECDES * record, OID * class_oid_p,
87  UPDATE_INPLACE_STYLE force_in_place);
88 extern int catcls_remove_entry (THREAD_ENTRY * thread_p, OID * class_oid);
89 
92 {
93  LC_FIND_CLASSNAME action; /* The transient operation, delete or reserve name */
94  OID oid; /* The class identifier of classname */
95  LOG_LSA savep_lsa; /* A top action LSA address (likely a savepoint) for return NULL is for current */
96  LOCATOR_CLASSNAME_ACTION *prev; /* To previous top action */
97 };
98 
101 {
102  char *e_name; /* Name of the class */
103  int e_tran_index; /* Transaction of entry */
104  LOCATOR_CLASSNAME_ACTION e_current; /* The most current action */
105 };
106 
109 { /* Location of next object to return in communication (fetch) area */
110  LC_COPYAREA *comm_area; /* Communication area where objects are returned and described */
111  LC_COPYAREA_MANYOBJS *mobjs; /* Location in the communication area where all objects to be returned are described. */
112  LC_COPYAREA_ONEOBJ *obj; /* Location in the communication area where the next object to return is described. */
113  HEAP_SCANCACHE *ptr_scancache; /* Scan cache used for fetching purposes */
114  HEAP_SCANCACHE area_scancache; /* Scan cache used for fetching purposes */
115  RECDES recdes; /* Location in the communication area where the content of the next object to return is
116  * placed. */
117  int area_offset; /* Relative offset to recdes->data in the communication area */
118 };
119 
121 
123 
124 static const HFID NULL_HFID = { {-1, -1}, -1 };
125 
126 /* Pseudo pageid used to generate pseudo OID for reserved class names. */
127 static const INT32 locator_Pseudo_pageid_first = -2;
128 static const INT32 locator_Pseudo_pageid_last = -0x7FFF;
129 static INT32 locator_Pseudo_pageid_crt = -2;
130 
131 static int locator_permoid_class_name (THREAD_ENTRY * thread_p, const char *classname, const OID * class_oid);
132 static int locator_defence_drop_class_name_entry (const void *name, void *ent, void *args);
133 static int locator_force_drop_class_name_entry (const void *name, void *ent, void *args);
134 static int locator_drop_class_name_entry (THREAD_ENTRY * thread_p, const char *classname, LOG_LSA * savep_lsa);
135 static int locator_savepoint_class_name_entry (const char *classname, LOG_LSA * savep_lsa);
136 static int locator_print_class_name (THREAD_ENTRY * thread_p, FILE * outfp, const void *key, void *ent, void *args);
137 static int locator_check_class_on_heap (const void *name, void *ent, void *args);
139  OID * class_oid, OID * oid, int chn, LOCK lock_mode,
140  SCAN_OPERATION_TYPE op_type);
141 static int locator_find_lockset_missing_class_oids (THREAD_ENTRY * thread_p, LC_LOCKSET * lockset);
142 static SCAN_CODE locator_return_object_assign (THREAD_ENTRY * thread_p, LOCATOR_RETURN_NXOBJ * assign, OID * class_oid,
143  OID * oid, int chn, int guess_chn, SCAN_CODE scan, int tran_index);
144 static LC_LOCKSET *locator_all_reference_lockset (THREAD_ENTRY * thread_p, OID * oid, int prune_level, LOCK inst_lock,
145  LOCK class_lock, bool quit_on_errors);
146 static bool locator_notify_decache (const OID * class_oid, const OID * oid, void *notify_area);
148 static int locator_repl_prepare_force (THREAD_ENTRY * thread_p, LC_COPYAREA_ONEOBJ * obj, RECDES * old_recdes,
149  RECDES * recdes, DB_VALUE * key_value, HEAP_SCANCACHE * force_scancache);
150 static int locator_repl_get_key_value (DB_VALUE * key_value, LC_COPYAREA * force_area, LC_COPYAREA_ONEOBJ * obj);
152  DB_VALUE * key_value, int err_code, const char *err_msg);
153 static int locator_update_force (THREAD_ENTRY * thread_p, HFID * hfid, OID * class_oid, OID * oid, RECDES * ikdrecdes,
154  RECDES * recdes, int has_index, ATTR_ID * att_id, int n_att_id, int op_type,
155  HEAP_SCANCACHE * scan_cache, int *force_count, bool not_check_fk,
156  REPL_INFO_TYPE repl_info_type, int pruning_type, PRUNING_CONTEXT * pcontext,
157  MVCC_REEV_DATA * mvcc_reev_data, UPDATE_INPLACE_STYLE force_in_place,
158  bool need_locking);
159 static int locator_move_record (THREAD_ENTRY * thread_p, HFID * old_hfid, OID * old_class_oid, OID * obj_oid,
160  OID * new_class_oid, HFID * new_class_hfid, RECDES * recdes,
161  HEAP_SCANCACHE * scan_cache, int op_type, int has_index, int *force_count,
162  PRUNING_CONTEXT * context, MVCC_REEV_DATA * mvcc_reev_data, bool need_locking);
163 static int locator_delete_force_for_moving (THREAD_ENTRY * thread_p, HFID * hfid, OID * oid, int has_index, int op_type,
164  HEAP_SCANCACHE * scan_cache, int *force_count,
165  MVCC_REEV_DATA * mvcc_reev_data, OID * new_obj_oid, OID * partition_oid,
166  bool need_locking);
167 static int locator_delete_force_internal (THREAD_ENTRY * thread_p, HFID * hfid, OID * oid, int has_index, int op_type,
168  HEAP_SCANCACHE * scan_cache, int *force_count,
169  MVCC_REEV_DATA * mvcc_reev_data, LOCATOR_INDEX_ACTION_FLAG idx_action_flag,
170  OID * new_obj_oid, OID * partition_oid, bool need_locking);
171 static int locator_force_for_multi_update (THREAD_ENTRY * thread_p, LC_COPYAREA * force_area);
172 
173 #if defined(ENABLE_UNUSED_FUNCTION)
174 static void locator_increase_catalog_count (THREAD_ENTRY * thread_p, OID * cls_oid);
175 static void locator_decrease_catalog_count (THREAD_ENTRY * thread_p, OID * cls_oid);
176 #endif
177 
178 static int locator_add_or_remove_index_for_moving (THREAD_ENTRY * thread_p, RECDES * recdes, OID * inst_oid,
179  OID * class_oid, int is_insert, int op_type,
180  HEAP_SCANCACHE * scan_cache, bool datayn, bool need_replication,
181  HFID * hfid, FUNC_PRED_UNPACK_INFO * func_preds, bool has_BU_lock);
182 static int locator_add_or_remove_index_internal (THREAD_ENTRY * thread_p, RECDES * recdes, OID * inst_oid,
183  OID * class_oid, int is_insert, int op_type,
184  HEAP_SCANCACHE * scan_cache, bool datayn, bool replyn, HFID * hfid,
185  FUNC_PRED_UNPACK_INFO * func_preds,
186  LOCATOR_INDEX_ACTION_FLAG idx_action_flag, bool has_BU_lock,
187  bool skip_checking_fk);
188 static int locator_check_foreign_key (THREAD_ENTRY * thread_p, HFID * hfid, OID * class_oid, OID * inst_oid,
189  RECDES * recdes, RECDES * new_recdes, bool * is_cached, LC_COPYAREA ** copyarea);
190 static int locator_check_primary_key_delete (THREAD_ENTRY * thread_p, OR_INDEX * index, DB_VALUE * key);
191 static int locator_check_primary_key_update (THREAD_ENTRY * thread_p, OR_INDEX * index, DB_VALUE * key);
192 #if defined(ENABLE_UNUSED_FUNCTION)
193 static TP_DOMAIN *locator_make_midxkey_domain (OR_INDEX * index);
194 #endif
196  RECDES * classrec, ATTR_ID * attr_ids, const char *btname,
197  bool repair);
198 static int locator_eval_filter_predicate (THREAD_ENTRY * thread_p, BTID * btid, OR_PREDICATE * or_pred, OID * class_oid,
199  OID ** inst_oids, int num_insts, RECDES ** recs, DB_LOGICAL * results);
200 static bool locator_was_index_already_applied (HEAP_CACHE_ATTRINFO * index_attrinfo, BTID * btid, int pos);
201 static LC_FIND_CLASSNAME xlocator_reserve_class_name (THREAD_ENTRY * thread_p, const char *classname, OID * class_oid);
202 
203 static int locator_filter_errid (THREAD_ENTRY * thread_p, int num_ignore_error_count, int *ignore_error_list);
205 
206 static int locator_prefetch_index_page (THREAD_ENTRY * thread_p, OID * class_oid, RECDES * classrec, RECDES * recdes,
207  int btid_index, HEAP_CACHE_ATTRINFO * attr_info);
208 static int locator_prefetch_index_page_internal (THREAD_ENTRY * thread_p, BTID * btid, OID * class_oid,
209  RECDES * classrec, RECDES * recdes);
210 
211 static void locator_incr_num_transient_classnames (int tran_index);
212 static void locator_decr_num_transient_classnames (int tran_index);
213 static int locator_get_num_transient_classnames (int tran_index);
215 
216 static DISK_ISVALID locator_repair_btree_by_delete (THREAD_ENTRY * thread_p, OID * class_oid, BTID * btid,
217  OID * inst_oid);
218 
219 static void locator_generate_class_pseudo_oid (THREAD_ENTRY * thread_p, OID * class_oid);
220 
221 static int redistribute_partition_data (THREAD_ENTRY * thread_p, OID * class_oid, int no_oids, OID * oid_list);
223  LOCK lock_mode);
224 static DB_LOGICAL locator_mvcc_reev_cond_assigns (THREAD_ENTRY * thread_p, OID * class_oid, const OID * oid,
225  HEAP_SCANCACHE * scan_cache, RECDES * recdes,
226  MVCC_UPDDEL_REEV_DATA * mvcc_reev_data);
228  HEAP_SCANCACHE * scan_cache, RECDES * recdes,
229  UPDDEL_MVCC_COND_REEVAL * mvcc_cond_reeval, bool is_upddel);
231  const OID * oid, RECDES * recdes);
233  MVCC_REEV_DATA * mvcc_reev_data_p,
234  MVCC_REC_HEADER * mvcc_header_p,
235  const OID * curr_row_version_oid_p, RECDES * recdes);
236 
237 /*
238  * locator_initialize () - Initialize the locator on the server
239  *
240  * return: NO_ERROR if all OK, ER_ status otherwise
241  *
242  * Note: Initialize the server transaction object locator.
243  * Currently, only the classname memory hash table is initialized.
244  */
245 int
247 {
248  RECDES peek = RECDES_INITIALIZER; /* Record descriptor for peeking object */
249  HFID root_hfid;
250  OID class_oid;
251  char *classname = NULL;
252  HEAP_SCANCACHE scan_cache;
254 
256  {
257  /* Some kind of failure. We must notify the error to the caller. */
258  assert (false);
259  return DISK_ERROR;
260  }
261 
262  if (csect_enter (thread_p, CSECT_CT_OID_TABLE, INF_WAIT) != NO_ERROR)
263  {
264  assert (false);
266  return DISK_ERROR;
267  }
268 
269  if (locator_Mht_classnames != NULL)
270  {
271  (void) mht_map (locator_Mht_classnames, locator_force_drop_class_name_entry, NULL);
272  }
273  else
274  {
275  locator_Mht_classnames =
277  }
278 
279  if (locator_Mht_classnames == NULL)
280  {
281  assert (false);
282  goto error;
283  }
284 
285  /* Find every single class */
286 
287  if (boot_find_root_heap (&root_hfid) != NO_ERROR || HFID_IS_NULL (&root_hfid))
288  {
289  goto error;
290  }
291 
292  if (heap_scancache_start (thread_p, &scan_cache, &root_hfid, NULL, true, false, NULL) != NO_ERROR)
293  {
294  goto error;
295  }
296 
297  OID_SET_NULL (&class_oid);
298 
299  while (heap_next (thread_p, &root_hfid, NULL, &class_oid, &peek, &scan_cache, PEEK) == S_SUCCESS)
300  {
301  assert (!OID_ISNULL (&class_oid));
302 
303  classname = or_class_name (&peek);
304  assert (classname != NULL);
305  assert (strlen (classname) < 255);
306 
307  entry = ((LOCATOR_CLASSNAME_ENTRY *) malloc (sizeof (*entry)));
308  if (entry == NULL)
309  {
311  goto error;
312  }
313 
314  entry->e_name = strdup ((char *) classname);
315  if (entry->e_name == NULL)
316  {
317  free_and_init (entry);
318  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, (size_t) (strlen (classname) + 1));
319  goto error;
320  }
321 
322  entry->e_tran_index = NULL_TRAN_INDEX;
323 
325  COPY_OID (&entry->e_current.oid, &class_oid);
326  LSA_SET_NULL (&entry->e_current.savep_lsa);
327  entry->e_current.prev = NULL;
328 
329  assert (locator_is_exist_class_name_entry (thread_p, entry));
330 
331  (void) mht_put (locator_Mht_classnames, entry->e_name, entry);
332  }
333 
334  /* End the scan cursor */
335  if (heap_scancache_end (thread_p, &scan_cache) != NO_ERROR)
336  {
337  goto error;
338  }
339 
340  csect_exit (thread_p, CSECT_CT_OID_TABLE);
341 
343 
344  return NO_ERROR;
345 
346 error:
347 
348  csect_exit (thread_p, CSECT_CT_OID_TABLE);
349 
351 
352  return DISK_ERROR;
353 }
354 
355 /*
356  * locator_finalize () - Terminates the locator on the server
357  *
358  * return: nothing
359  *
360  * Note:Terminate the object locator on the server. Currently, only
361  * the classname memory hash table is removed.
362  */
363 void
365 {
367  {
368  /* Some kind of failure. We will leak resources. */
369  assert (false);
370  return;
371  }
372 
373  if (locator_Mht_classnames == NULL)
374  {
376  return;
377  }
378 
379  if (csect_enter (thread_p, CSECT_CT_OID_TABLE, INF_WAIT) != NO_ERROR)
380  {
381  assert (false);
383  return;
384  }
385 
386  (void) mht_map (locator_Mht_classnames, locator_force_drop_class_name_entry, NULL);
387 
388  mht_destroy (locator_Mht_classnames);
389  locator_Mht_classnames = NULL;
390 
391  csect_exit (thread_p, CSECT_CT_OID_TABLE);
392 
394 }
395 
396 /*
397  * xlocator_reserve_class_names () - Reserve several classnames
398  *
399  * return: LC_FIND_CLASSNAME
400  * (either of LC_CLASSNAME_RESERVED,
401  * LC_CLASSNAME_EXIST,
402  * LC_CLASSNAME_ERROR)
403  *
404  * num_classes(in): Number of classes
405  * classnames(in): Names of the classes
406  * class_oids(in/out): Object identifiers of the classes
407  */
409 xlocator_reserve_class_names (THREAD_ENTRY * thread_p, const int num_classes, const char **classnames, OID * class_oids)
410 {
411  int i = 0;
413 
414  for (i = 0; i < num_classes; ++i)
415  {
416  assert (classnames[i] != NULL);
417  assert (strlen (classnames[i]) < 255);
418 
419  result = xlocator_reserve_class_name (thread_p, classnames[i], &class_oids[i]);
420  if (result != LC_CLASSNAME_RESERVED)
421  {
422  /* We could potentially revert the reservation but the transient entries should be properly cleaned up by the
423  * rollback so we don't really need to do this here. */
424  break;
425  }
426  }
427 
428  return result;
429 }
430 
431 /*
432  * xlocator_reserve_class_name () - Reserve a classname
433  *
434  * return: LC_FIND_CLASSNAME
435  * (either of LC_CLASSNAME_RESERVED,
436  * LC_CLASSNAME_EXIST,
437  * LC_CLASSNAME_ERROR)
438  *
439  * classname(in): Name of class
440  * class_oid(in/out): Object identifier of the class
441  *
442  * Note: Reserve the name of a class.
443  * If there is an entry on the memory classname table,
444  * we can proceed if the entry belongs to the current
445  * transaction, otherwise, we must wait until the transaction
446  * holding the entry terminates since the fate of the classname
447  * entry cannot be predicted. If the entry belongs to
448  * the current transaction, we can reserve the name only if the
449  * entry indicates that a class with such a name has been
450  * deleted or reserved. If there is not a entry with such a name,
451  * the classname is reserved or an error is returned.
452  */
453 static LC_FIND_CLASSNAME
454 xlocator_reserve_class_name (THREAD_ENTRY * thread_p, const char *classname, OID * class_oid)
455 {
457  LOCATOR_CLASSNAME_ACTION *old_action;
459  OID tmp_classoid;
460  int tran_index;
461 
462  if (classname == NULL)
463  {
464  return LC_CLASSNAME_ERROR;
465  }
466 
467  assert (classname != NULL);
468  assert (strlen (classname) < 255);
469 
470  tran_index = LOG_FIND_THREAD_TRAN_INDEX (thread_p);
471 
472 start:
473  reserve = LC_CLASSNAME_RESERVED;
474 
476  {
477  /* Some kind of failure. We must notify the error to the caller. */
478  assert (false);
479  return LC_CLASSNAME_ERROR;
480  }
481 
482  /* Is there any entries on the classname hash table ? */
483  entry = (LOCATOR_CLASSNAME_ENTRY *) mht_get (locator_Mht_classnames, classname);
484 
485  if (locator_is_exist_class_name_entry (thread_p, entry))
486  {
487  /* There is a class with such a name on the classname cache. */
488  reserve = LC_CLASSNAME_EXIST;
489  }
490  else if (entry != NULL)
491  {
493 
494  /*
495  * We can only proceed if the entry belongs to the current transaction,
496  * otherwise, we must lock the class associated with the classname and
497  * retry the operation once the lock is granted.
498  */
499  if (entry->e_tran_index == tran_index)
500  {
501  /*
502  * The name can be reserved only if it has been deleted or
503  * previously reserved. We allow double reservations in order for
504  * multiple table renaming to properly reserve all the names
505  * involved.
506  */
509  {
510  /*
511  * The entry can be changed.
512  * Do we need to save the old action...just in case we do a
513  * partial rollback ?
514  */
515  if (!LSA_ISNULL (&entry->e_current.savep_lsa))
516  {
517  /*
518  * There is a possibility of returning to this top LSA
519  * (savepoint). Save the action.. just in case
520  */
521  old_action = (LOCATOR_CLASSNAME_ACTION *) malloc (sizeof (*old_action));
522 
523  if (old_action == NULL)
524  {
525  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, sizeof (*old_action));
527  return LC_CLASSNAME_ERROR;
528  }
529 
530  *old_action = entry->e_current;
531  LSA_SET_NULL (&entry->e_current.savep_lsa);
532  entry->e_current.prev = old_action;
533  }
534 
536  if (OID_ISNULL (class_oid))
537  {
538  locator_generate_class_pseudo_oid (thread_p, class_oid);
539  }
540  COPY_OID (&entry->e_current.oid, class_oid);
541 
542  /* Add dummy log to make sure we can revert transient state change. See comment in
543  * xlocator_rename_class_name. Since reserve has been moved before any change (or flush) is done, same
544  * scenario can happen here. */
546  }
547  else
548  {
551 
552  reserve = LC_CLASSNAME_EXIST;
553  }
554  }
555  else
556  {
557  COPY_OID (&tmp_classoid, &entry->e_current.oid);
558 
559  /*
560  * The fate of this entry is known when the transaction holding
561  * this entry either commits or aborts. Get the lock and try again.
562  */
563 
564  /*
565  * Exit from critical section since we are going to be suspended and
566  * then retry again.
567  */
569 
570  if (lock_object (thread_p, &tmp_classoid, oid_Root_class_oid, SCH_M_LOCK, LK_UNCOND_LOCK) != LK_GRANTED)
571  {
572  /*
573  * Unable to acquired lock
574  */
575  return LC_CLASSNAME_ERROR;
576  }
577  else
578  {
579  /*
580  * Try again
581  * Remove the lock.. since the above was a dirty read
582  */
583  lock_unlock_object (thread_p, &tmp_classoid, oid_Root_class_oid, SCH_M_LOCK, true);
584  goto start;
585  }
586  }
587  }
588  else
589  {
590  entry = (LOCATOR_CLASSNAME_ENTRY *) malloc (sizeof (*entry));
591  if (entry == NULL)
592  {
595  return LC_CLASSNAME_ERROR;
596  }
597 
598  entry->e_name = strdup ((char *) classname);
599  if (entry->e_name == NULL)
600  {
601  free_and_init (entry);
602  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, (size_t) (strlen (classname) + 1));
604  return LC_CLASSNAME_ERROR;
605  }
606 
607  entry->e_tran_index = tran_index;
608 
610  if (OID_ISNULL (class_oid))
611  {
612  locator_generate_class_pseudo_oid (thread_p, class_oid);
613  }
614  COPY_OID (&entry->e_current.oid, class_oid);
615  LSA_SET_NULL (&entry->e_current.savep_lsa);
616  entry->e_current.prev = NULL;
617 
618  /* Add dummy log to make sure we can revert transient state change. See comment in xlocator_rename_class_name.
619  * Since reserve has been moved before any change (or flush) is done, same scenario can happen here. */
621 
622  assert (locator_is_exist_class_name_entry (thread_p, entry) == false);
623 
624  (void) mht_put (locator_Mht_classnames, entry->e_name, entry);
625 
627  }
628 
629  /*
630  * Note that the index has not been made permanently into the database.
631  * That is, it has not been inserted onto extendible hash.
632  */
633 
635 
636  /*
637  * Get the lock on the class if we were able to reserve the name
638  */
639  if (reserve == LC_CLASSNAME_RESERVED && entry != NULL)
640  {
641  assert (entry->e_tran_index == tran_index);
642 
643  if (lock_object (thread_p, class_oid, oid_Root_class_oid, SCH_M_LOCK, LK_UNCOND_LOCK) != LK_GRANTED)
644  {
645  /*
646  * Something wrong. Remove the entry from hash table.
647  */
649  {
650  assert (false);
651  return LC_CLASSNAME_ERROR;
652  }
653 
654  if (entry->e_current.prev == NULL)
655  {
657 
658  (void) mht_rem (locator_Mht_classnames, entry->e_name, NULL, NULL);
659 
660  free_and_init (entry->e_name);
661  free_and_init (entry);
662  }
663  else
664  {
665  old_action = entry->e_current.prev;
666  entry->e_current = *old_action;
667  free_and_init (old_action);
668  }
669 
671 
672  reserve = LC_CLASSNAME_ERROR;
673  }
674  }
675 
676  return reserve;
677 }
678 
679 /*
680  * xlocator_get_reserved_class_name_oid () - Is class name reserved by this
681  * transaction?
682  *
683  * return : Error code.
684  * thread_p (in) : Thread entry.
685  * classname (in) : Class name.
686  * class_oid (out) : Class OID.
687  */
688 int
689 xlocator_get_reserved_class_name_oid (THREAD_ENTRY * thread_p, const char *classname, OID * class_oid)
690 {
691  int tran_index;
693 
694  tran_index = LOG_FIND_THREAD_TRAN_INDEX (thread_p);
695 
697  {
698  assert (false);
699  return ER_FAILED;
700  }
701  entry = (LOCATOR_CLASSNAME_ENTRY *) mht_get (locator_Mht_classnames, classname);
702  if (entry == NULL)
703  {
704  assert (false);
705  goto error;
706  }
707 
708  if (entry->e_current.action != LC_CLASSNAME_RESERVED)
709  {
710  assert (false);
711  goto error;
712  }
713 
714  if (entry->e_tran_index != tran_index)
715  {
716  assert (false);
717  goto error;
718  }
719 
720  COPY_OID (class_oid, &entry->e_current.oid);
721 
723 
724  return NO_ERROR;
725 
726 error:
729  return ER_FAILED;
730 }
731 
732 /*
733  * xlocator_delete_class_name () - Remove a classname
734  *
735  * return: LC_FIND_CLASSNAME (either of LC_CLASSNAME_DELETED,
736  * LC_CLASSNAME_ERROR)
737  *
738  * classname(in): Name of the class to delete
739  *
740  * Note: Indicate that a classname has been deleted.
741  * A classname to OID entry is created in memory to indicate the
742  * deletion.
743  * If there is an entry on the memory classname table,
744  * we can proceed if the entry belongs to the current
745  * transaction, otherwise, we must wait until the transaction
746  * holding the entry terminates since the fate of the classname
747  * entry cannot be predicted. If the entry belongs to
748  * the current transaction, we can delete the name only if the
749  * entry indicates that a class with such a name has been
750  * reserved. If there is not a entry with such a namek,
751  * the deleted class is locked and a entry is created informing
752  * of the deletion.
753  */
755 xlocator_delete_class_name (THREAD_ENTRY * thread_p, const char *classname)
756 {
758  LOCATOR_CLASSNAME_ACTION *old_action;
759  LC_FIND_CLASSNAME classname_delete = LC_CLASSNAME_DELETED;
760  OID tmp_classoid;
761  int tran_index;
762 
763  if (classname == NULL)
764  {
765  return LC_CLASSNAME_ERROR;
766  }
767 
768  assert (classname != NULL);
769  assert (strlen (classname) < 255);
770 
771  tran_index = LOG_FIND_THREAD_TRAN_INDEX (thread_p);
772 
773 start:
774  classname_delete = LC_CLASSNAME_DELETED;
775 
777  {
778  /* Some kind of failure. We must notify the error to the caller. */
779  assert (false);
780  return LC_CLASSNAME_ERROR;
781  }
782 
783  entry = (LOCATOR_CLASSNAME_ENTRY *) mht_get (locator_Mht_classnames, classname);
784  if (entry != NULL)
785  {
786  assert (entry->e_tran_index == NULL_TRAN_INDEX || entry->e_tran_index == tran_index);
787 
788  COPY_OID (&tmp_classoid, &entry->e_current.oid);
789  }
790 
791  if (locator_is_exist_class_name_entry (thread_p, entry))
792  {
793  /* There is a class with such a name on the classname cache. We should convert it to transient one. */
794  entry->e_tran_index = tran_index;
796 
798  }
799  else if (entry != NULL)
800  {
802  assert (entry->e_tran_index == tran_index);
803 
804  /*
805  * We can only proceed if the entry belongs to the current transaction,
806  * otherwise, we must lock the class associated with the classname and
807  * retry the operation once the lock is granted.
808  */
809  if (entry->e_tran_index == tran_index)
810  {
811  /*
812  * The name can be deleted only if it has been reserved by current
813  * transaction
814  */
816  {
817  classname_delete = LC_CLASSNAME_ERROR;
818  goto error;
819  }
820 
823 
824  /*
825  * The entry can be changed.
826  * Do we need to save the old action...just in case we do a partial
827  * rollback ?
828  */
829  if (!LSA_ISNULL (&entry->e_current.savep_lsa))
830  {
831  /*
832  * There is a possibility of returning to this top LSA (savepoint).
833  * Save the action.. just in case
834  */
835  old_action = (LOCATOR_CLASSNAME_ACTION *) malloc (sizeof (*old_action));
836  if (old_action == NULL)
837  {
838  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, sizeof (*old_action));
839  classname_delete = LC_CLASSNAME_ERROR;
840  goto error;
841  }
842 
843  *old_action = entry->e_current;
844  LSA_SET_NULL (&entry->e_current.savep_lsa);
845  entry->e_current.prev = old_action;
846  }
847 
849  }
850  else
851  {
852  /*
853  * Do not know the fate of this entry until the transaction holding
854  * this entry either commits or aborts. Get the lock and try again.
855  */
856 
857  /*
858  * Exit from critical section since we are going to be suspended and
859  * then retry again.
860  */
861 
863 
864  if (lock_object (thread_p, &tmp_classoid, oid_Root_class_oid, SCH_M_LOCK, LK_UNCOND_LOCK) != LK_GRANTED)
865  {
866  /*
867  * Unable to acquired lock
868  */
869  return LC_CLASSNAME_ERROR;
870  }
871  else
872  {
873  /*
874  * Try again
875  * Remove the lock.. since the above was a dirty read
876  */
877  lock_unlock_object (thread_p, &tmp_classoid, oid_Root_class_oid, SCH_M_LOCK, true);
878  goto start;
879  }
880  }
881  }
882  else
883  {
884  /* Some kind of failure. We must notify the error to the caller. */
885  classname_delete = LC_CLASSNAME_ERROR;
886  }
887 
888 error:
890 
891  /*
892  * We do not need to lock the entry->oid since it has already been locked
893  * in exclusive mode when the class was deleted or renamed. Avoid duplicate
894  * calls.
895  */
896 
897  /* Note that the index has not been dropped permanently from the database */
898  return classname_delete;
899 }
900 
901 /*
902  * xlocator_rename_class_name () - Rename a classname
903  *
904  * return: LC_FIND_CLASSNAME
905  * (either of LC_CLASSNAME_RESERVED_RENAME,
906  * LC_CLASSNAME_EXIST,
907  * LC_CLASSNAME_ERROR)
908  *
909  * oldname(in): Old name of class
910  * newname(in): New name of class
911  * class_oid(in/out): Object identifier of the class
912  *
913  * Note: Rename a class in transient form.
914  */
916 xlocator_rename_class_name (THREAD_ENTRY * thread_p, const char *oldname, const char *newname, OID * class_oid)
917 {
919  LC_FIND_CLASSNAME renamed;
920  int tran_index;
921 
922  if (oldname == NULL || newname == NULL)
923  {
924  return LC_CLASSNAME_ERROR;
925  }
926 
927  assert (oldname != NULL);
928  assert (strlen (oldname) < 255);
929  assert (newname != NULL);
930  assert (strlen (newname) < 255);
931  assert (!OID_ISNULL (class_oid));
932 
933  tran_index = LOG_FIND_THREAD_TRAN_INDEX (thread_p);
934 
935  renamed = xlocator_reserve_class_name (thread_p, newname, class_oid);
936  if (renamed != LC_CLASSNAME_RESERVED)
937  {
938  return renamed;
939  }
940 
942  {
943  /* Some kind of failure. We must notify the error to the caller. */
944  assert (false);
945  return LC_CLASSNAME_ERROR;
946  }
947 
948  entry = (LOCATOR_CLASSNAME_ENTRY *) mht_get (locator_Mht_classnames, newname);
949  if (entry != NULL)
950  {
952 
954  renamed = xlocator_delete_class_name (thread_p, oldname);
955  entry = (LOCATOR_CLASSNAME_ENTRY *) mht_get (locator_Mht_classnames, oldname);
956  if (renamed == LC_CLASSNAME_DELETED && entry != NULL)
957  {
960 
961  /* Add new name to modified list, to correctly restore in case of abort. */
962  if (log_add_to_modified_class_list (thread_p, newname, class_oid) != NO_ERROR)
963  {
965  return LC_CLASSNAME_ERROR;
966  }
967 
968  /* We need to add a dummy log here. If rename is the first clause of alter statement, there will be no log
969  * entries between parent system savepoint and next flush. Next flush will start a system operation which
970  * will mark the delete action of old class name with same LSA as parent system savepoint. Therefore, the
971  * delete action is not removed when alter statement is aborted and a new table with the same name may be
972  * created. */
974  }
975  else
976  {
977  entry = ((LOCATOR_CLASSNAME_ENTRY *) mht_get (locator_Mht_classnames, newname));
978  if (entry == NULL)
979  {
980  renamed = LC_CLASSNAME_ERROR;
981  goto error;
982  }
983 
984  assert (locator_is_exist_class_name_entry (thread_p, entry) == false);
985  assert (entry->e_tran_index == tran_index);
986 
987  if (csect_enter (thread_p, CSECT_CT_OID_TABLE, INF_WAIT) != NO_ERROR)
988  {
989  assert (false);
990  renamed = LC_CLASSNAME_ERROR;
991  goto error;
992  }
993 
994  if (locator_drop_class_name_entry (thread_p, newname, NULL) != NO_ERROR)
995  {
996  csect_exit (thread_p, CSECT_CT_OID_TABLE);
997  renamed = LC_CLASSNAME_ERROR;
998  goto error;
999  }
1000 
1001  csect_exit (thread_p, CSECT_CT_OID_TABLE);
1002  }
1003  }
1004 
1005 error:
1006 
1008 
1009  return renamed;
1010 }
1011 
1012 /*
1013  * xlocator_find_class_oid () - Find oid of a classname
1014  *
1015  * return: LC_FIND_CLASSNAME
1016  * (either of LC_CLASSNAME_EXIST,
1017  * LC_CLASSNAME_DELETED,
1018  * LC_CLASSNAME_ERROR)
1019  *
1020  * classname(in): Name of class to find
1021  * class_oid(out): Set as a side effect
1022  * lock(in): Lock to acquire for the class
1023  *
1024  * Note: Find the class identifier of the given class name and lock the
1025  * class with the given mode.
1026  * If there is an entry on the memory classname table,
1027  * we can proceed if the entry belongs to the current
1028  * transaction, otherwise, we must wait until the transaction
1029  * holding the entry terminates since the fate of the classname
1030  * entry cannot be predicted.
1031  */
1033 xlocator_find_class_oid (THREAD_ENTRY * thread_p, const char *classname, OID * class_oid, LOCK lock)
1034 {
1035  int tran_index;
1036  LOCATOR_CLASSNAME_ENTRY *entry;
1037  LOCK tmp_lock;
1039 
1040  tran_index = LOG_FIND_THREAD_TRAN_INDEX (thread_p);
1041 
1042 start:
1043  find = LC_CLASSNAME_EXIST;
1044 
1046  {
1047  assert (false);
1048  return LC_CLASSNAME_ERROR;
1049  }
1050 
1051  entry = (LOCATOR_CLASSNAME_ENTRY *) mht_get (locator_Mht_classnames, classname);
1052 
1053  if (entry != NULL)
1054  {
1055  COPY_OID (class_oid, &entry->e_current.oid);
1056  assert (find == LC_CLASSNAME_EXIST);
1057  }
1058 
1059  if (locator_is_exist_class_name_entry (thread_p, entry))
1060  {
1061  assert (find == LC_CLASSNAME_EXIST); /* OK, go ahead */
1062  }
1063  else if (entry != NULL)
1064  {
1066 
1067  /*
1068  * We can only proceed if the entry belongs to the current transaction,
1069  * otherwise, we must lock the class associated with the classname and
1070  * retry the operation once the lock is granted.
1071  */
1072  assert (find == LC_CLASSNAME_EXIST);
1073 
1074  if (entry->e_tran_index == tran_index)
1075  {
1077  {
1078  OID_SET_NULL (class_oid); /* clear */
1079  find = LC_CLASSNAME_DELETED;
1080  }
1081  else
1082  {
1083  assert (find == LC_CLASSNAME_EXIST); /* OK, go ahead */
1084  }
1085  }
1086  else
1087  {
1088  /*
1089  * Do not know the fate of this entry until the transaction is
1090  * committed or aborted. Get the lock and try again.
1091  */
1093 
1094  if (lock != NULL_LOCK)
1095  {
1096  tmp_lock = lock;
1097  }
1098  else
1099  {
1100  tmp_lock = IS_LOCK;
1101  }
1102 
1103  if (lock_object (thread_p, class_oid, oid_Root_class_oid, tmp_lock, LK_UNCOND_LOCK) != LK_GRANTED)
1104  {
1105  /*
1106  * Unable to acquired lock
1107  */
1108  OID_SET_NULL (class_oid); /* clear */
1109  return LC_CLASSNAME_ERROR;
1110  }
1111  else
1112  {
1113  /*
1114  * Try again
1115  * Remove the lock.. since the above was a dirty read
1116  */
1117  lock_unlock_object (thread_p, class_oid, oid_Root_class_oid, tmp_lock, true);
1118  goto start;
1119  }
1120  }
1121  }
1122  else
1123  {
1124  find = LC_CLASSNAME_DELETED;
1125  }
1126 
1128 
1129  if (lock != NULL_LOCK && find == LC_CLASSNAME_EXIST)
1130  {
1131  /* Now acquired the desired lock */
1132  if (lock_object (thread_p, class_oid, oid_Root_class_oid, lock, LK_UNCOND_LOCK) != LK_GRANTED)
1133  {
1134  /*
1135  * Unable to acquired lock
1136  */
1137  OID_SET_NULL (class_oid); /* clear */
1138  find = LC_CLASSNAME_ERROR;
1139  }
1140  else
1141  {
1142  lock_unlock_object (thread_p, class_oid, oid_Root_class_oid, lock, false);
1143  }
1144  }
1145 
1146 #if !defined(NDEBUG)
1147  if (find == LC_CLASSNAME_EXIST)
1148  {
1149  assert (!OID_ISNULL (class_oid));
1150  }
1151  else if (find == LC_CLASSNAME_ERROR)
1152  {
1153  assert (OID_ISNULL (class_oid));
1154  }
1155 #endif
1156 
1157  return find;
1158 }
1159 
1160 /*
1161  * locator_permoid_class_name () - Change reserve name with permanent oid
1162  *
1163  * return: NO_ERROR if all OK, ER_ status otherwise
1164  *
1165  * classname(in): Name of class
1166  * class_oid(in): New OID
1167  *
1168  * Note: Update the entry for the given classname with the
1169  * given class identifier. The entry must belong to the
1170  * current transaction.
1171  */
1172 static int
1173 locator_permoid_class_name (THREAD_ENTRY * thread_p, const char *classname, const OID * class_oid)
1174 {
1175  LOCATOR_CLASSNAME_ENTRY *entry;
1176  LOCATOR_CLASSNAME_ACTION *old_action;
1177  int error_code = NO_ERROR;
1178 
1179  /* Is there any entries on the classname hash table ? */
1181  {
1182  assert (false);
1183  return ER_FAILED;
1184  }
1185 
1186  entry = (LOCATOR_CLASSNAME_ENTRY *) mht_get (locator_Mht_classnames, classname);
1187  if (entry == NULL || entry->e_tran_index != LOG_FIND_THREAD_TRAN_INDEX (thread_p))
1188  {
1189  assert (false);
1190  error_code = ER_FAILED;
1191  goto error; /* should be impossible */
1192  }
1193 
1194  assert (locator_is_exist_class_name_entry (thread_p, entry) == false);
1195  assert (entry->e_tran_index == LOG_FIND_THREAD_TRAN_INDEX (thread_p));
1196 
1197  if (entry->e_current.action != LC_CLASSNAME_EXIST)
1198  {
1199  /*
1200  * Remove the old lock entry. The new entry has already been acquired by
1201  * the caller
1202  */
1203  lock_unlock_object (thread_p, &entry->e_current.oid, oid_Root_class_oid, X_LOCK, true);
1204 
1205  /*
1206  * Do we need to save the old action...just in case we do a partial
1207  * rollback ?
1208  */
1209  if (!LSA_ISNULL (&entry->e_current.savep_lsa))
1210  {
1211  /*
1212  * There is a possibility of returning to this top LSA (savepoint).
1213  * Save the action.. just in case
1214  */
1215  old_action = (LOCATOR_CLASSNAME_ACTION *) malloc (sizeof (*old_action));
1216  if (old_action == NULL)
1217  {
1218  error_code = ER_OUT_OF_VIRTUAL_MEMORY;
1219  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error_code, 1, sizeof (*old_action));
1220  goto error;
1221  }
1222 
1223  *old_action = entry->e_current;
1224  LSA_SET_NULL (&entry->e_current.savep_lsa);
1225  entry->e_current.prev = old_action;
1226  }
1227 
1228  COPY_OID (&entry->e_current.oid, class_oid);
1229  }
1230 
1232 
1233  assert (error_code == NO_ERROR);
1234 
1235  return NO_ERROR;
1236 
1237 error:
1238 
1240 
1241  assert (error_code != NO_ERROR);
1242 
1243  return error_code;
1244 }
1245 
1246 /*
1247  * locator_drop_transient_class_name_entries () - Drop transient classname entries
1248  *
1249  * return: NO_ERROR if all OK, ER_ status otherwise
1250  *
1251  * savep_lsa(in): up to given LSA
1252  *
1253  * Note: Remove all the classname transient entries of the given
1254  * transaction up to the given savepoint.
1255  * This is done when the transaction terminates.
1256  */
1257 int
1259 {
1260  int tran_index;
1261  LOG_TDES *tdes; /* Transaction descriptor */
1262  int error_code = NO_ERROR;
1263 
1264  tran_index = LOG_FIND_THREAD_TRAN_INDEX (thread_p);
1265 
1266  if (tran_index != NULL_TRAN_INDEX)
1267  {
1268  if (locator_get_num_transient_classnames (tran_index) <= 0)
1269  {
1270  return NO_ERROR;
1271  }
1272  }
1273 
1274  tdes = LOG_FIND_TDES (tran_index);
1275 
1277  {
1278  /* Some kind of failure. We must notify the error to the caller. */
1279  assert (false);
1280  return ER_FAILED;
1281  }
1282 
1283  if (csect_enter (thread_p, CSECT_CT_OID_TABLE, INF_WAIT) != NO_ERROR)
1284  {
1285  assert (false);
1287  return ER_FAILED;
1288  }
1289 
1290  // *INDENT-OFF*
1291  const auto lambda_func = [&error_code, &thread_p, &savep_lsa] (const tx_transient_class_entry & t, bool & stop)
1292  {
1293  error_code = locator_drop_class_name_entry (thread_p, t.get_classname (), savep_lsa);
1294  if (error_code != NO_ERROR)
1295  {
1296  assert (false);
1297  stop = true;
1298  }
1299  };
1300  // *INDENT-ON*
1301  tdes->m_modified_classes.map (lambda_func);
1302  assert (locator_get_num_transient_classnames (tran_index) >= 0);
1303 
1304  /* defence for commit or rollback; include partial rollback */
1305  if (tran_index != NULL_TRAN_INDEX)
1306  {
1307  if (locator_get_num_transient_classnames (tran_index) > 0)
1308  {
1309  (void) mht_map (locator_Mht_classnames, locator_defence_drop_class_name_entry, savep_lsa);
1310  }
1311  }
1312 
1313  if (error_code == NO_ERROR)
1314  {
1315  /* defence for commit or rollback; exclude partial rollback */
1316  if (savep_lsa == NULL)
1317  {
1318  if (locator_get_num_transient_classnames (tran_index) != 0)
1319  {
1320  assert (false); /* something wrong */
1321  error_code = ER_FAILED;
1322  }
1323  }
1324  }
1325 
1326  csect_exit (thread_p, CSECT_CT_OID_TABLE);
1327 
1329 
1330  return error_code;
1331 }
1332 
1333 /*
1334  * locator_drop_class_name_entry () - Remove one transient entry
1335  *
1336  * return: NO_ERROR or error code
1337  *
1338  * thread_p(in):
1339  * classname(in): The classname (key)
1340  * savep_lsa(in): up to given LSA
1341  *
1342  * Note: Remove transient entry if it belongs to current transaction.
1343  */
1344 static int
1345 locator_drop_class_name_entry (THREAD_ENTRY * thread_p, const char *classname, LOG_LSA * savep_lsa)
1346 {
1347  int tran_index;
1348  LOG_TDES *tdes; /* Transaction descriptor */
1349  LOCATOR_CLASSNAME_ENTRY *entry;
1350  LOCATOR_CLASSNAME_ACTION *old_action;
1351 
1352  tran_index = LOG_FIND_THREAD_TRAN_INDEX (thread_p);
1353 
1354  tdes = LOG_FIND_TDES (tran_index);
1355 
1356  assert (csect_check_own (thread_p, CSECT_CT_OID_TABLE) == 1);
1358 
1359  entry = (LOCATOR_CLASSNAME_ENTRY *) mht_get (locator_Mht_classnames, classname);
1360  if (entry == NULL)
1361  {
1362  /* table is dropped by myself; not exist */
1363  return NO_ERROR; /* do nothing */
1364  }
1365 
1366  if (!(entry->e_tran_index == NULL_TRAN_INDEX || entry->e_tran_index == tran_index))
1367  {
1368  /* table is dropped by myself and reserved by other tranx */
1369  return NO_ERROR;
1370  }
1371 
1372  assert (entry->e_name != NULL);
1373  assert (!OID_ISNULL (&entry->e_current.oid));
1374 
1375 #if !defined(NDEBUG)
1376  if (entry->e_current.action == LC_CLASSNAME_EXIST)
1377  {
1378  assert (locator_is_exist_class_name_entry (thread_p, entry));
1379  }
1380 #endif
1381 
1382  assert (savep_lsa == NULL || !LSA_ISNULL (savep_lsa));
1383 
1384  if (locator_is_exist_class_name_entry (thread_p, entry) == false)
1385  {
1386  assert (entry->e_tran_index == tran_index);
1387 
1388  if (savep_lsa == NULL && tdes->state != TRAN_UNACTIVE_ABORTED)
1389  {
1390  /* is commit; get current */
1391  while (entry->e_current.prev != NULL)
1392  {
1393  old_action = entry->e_current.prev;
1394  entry->e_current.prev = old_action->prev;
1395  free_and_init (old_action);
1396  }
1397  assert (entry->e_current.prev == NULL);
1398 
1400 
1401  if (entry->e_current.action == LC_CLASSNAME_RESERVED
1403  {
1404  entry->e_tran_index = NULL_TRAN_INDEX;
1405 
1407  LSA_SET_NULL (&entry->e_current.savep_lsa);
1408 
1409  assert (locator_is_exist_class_name_entry (thread_p, entry));
1410  }
1411  else
1412  {
1415 
1416  (void) locator_force_drop_class_name_entry (entry->e_name, entry, NULL);
1417  entry = NULL; /* clear */
1418  }
1419  }
1420  else
1421  {
1422  /* is rollback or partial rollback; get prev */
1423  while (savep_lsa == NULL /* is rollback */
1424  || LSA_ISNULL (&entry->e_current.savep_lsa) || LSA_LT (savep_lsa, &entry->e_current.savep_lsa))
1425  {
1426  if (entry->e_current.prev == NULL)
1427  {
1428  break;
1429  }
1430 
1431  old_action = entry->e_current.prev;
1432  entry->e_current = *old_action;
1433  free_and_init (old_action);
1434  }
1435 
1436  if (savep_lsa == NULL /* is rollback */
1437  || LSA_ISNULL (&entry->e_current.savep_lsa) || LSA_LT (savep_lsa, &entry->e_current.savep_lsa))
1438  {
1439  assert (entry->e_current.prev == NULL);
1440 
1442 
1443  if (entry->e_current.action == LC_CLASSNAME_DELETED
1445  {
1446  entry->e_tran_index = NULL_TRAN_INDEX;
1447 
1449  LSA_SET_NULL (&entry->e_current.savep_lsa);
1450 
1451  assert (locator_is_exist_class_name_entry (thread_p, entry));
1452  }
1453  else
1454  {
1457 
1458  (void) locator_force_drop_class_name_entry (entry->e_name, entry, NULL);
1459  entry = NULL; /* clear */
1460  }
1461  }
1462  } /* else */
1463  }
1464 
1465 #if !defined(NDEBUG)
1466  /* check iff permanent entry */
1467  if (locator_is_exist_class_name_entry (thread_p, entry))
1468  {
1469  OID class_oid;
1470 
1471  COPY_OID (&class_oid, &entry->e_current.oid);
1472 
1473  if (class_oid.slotid <= 0 || class_oid.volid < 0 || class_oid.pageid < 0)
1474  {
1475  assert (false);
1476  }
1477 
1478  if (disk_is_page_sector_reserved_with_debug_crash (thread_p, class_oid.volid, class_oid.pageid, true)
1479  != DISK_VALID)
1480  {
1481  assert (false);
1482  }
1483  }
1484 #endif
1485 
1486  return NO_ERROR;
1487 }
1488 
1489 /*
1490  * locator_defence_drop_class_name_entry () - Remove one transient entry
1491  *
1492  * return: NO_ERROR or error code
1493  *
1494  * name(in):
1495  * ent(in):
1496  * args(in):
1497  *
1498  * Note: Remove transient entry if it belongs to current transaction.
1499  */
1500 static int
1501 locator_defence_drop_class_name_entry (const void *name, void *ent, void *args)
1502 {
1504  LOG_LSA *savep_lsa = (LOG_LSA *) args;
1505  THREAD_ENTRY *thread_p;
1506  int tran_index;
1507 
1508  thread_p = thread_get_thread_entry_info ();
1509 
1510  assert (csect_check_own (thread_p, CSECT_CT_OID_TABLE) == 1);
1512 
1513  tran_index = LOG_FIND_THREAD_TRAN_INDEX (thread_p);
1514  assert (tran_index != NULL_TRAN_INDEX);
1515 
1516 #if !defined(NDEBUG)
1517  if (locator_is_exist_class_name_entry (thread_p, entry))
1518  {
1519  OID class_oid;
1520 
1521  COPY_OID (&class_oid, &entry->e_current.oid);
1522 
1523  assert (heap_does_exist (thread_p, oid_Root_class_oid, &class_oid));
1524 
1525  /* check class_oid */
1526  if (class_oid.slotid <= 0 || class_oid.volid < 0 || class_oid.pageid < 0)
1527  {
1528  assert (false);
1529  }
1530 
1531  if (disk_is_page_sector_reserved_with_debug_crash (thread_p, class_oid.volid, class_oid.pageid, true)
1532  != DISK_VALID)
1533  {
1534  assert (false);
1535  }
1536  }
1537 #endif
1538 
1539  /* check iff uncleared entry */
1540  if (entry->e_tran_index == tran_index)
1541  {
1542  assert (entry->e_tran_index != NULL_TRAN_INDEX);
1543 
1544  (void) locator_drop_class_name_entry (thread_p, entry->e_name, savep_lsa);
1545  }
1546 
1547  return NO_ERROR;
1548 }
1549 
1550 /*
1551  * locator_force_drop_class_name_entry () -
1552  *
1553  * return:
1554  *
1555  * name(in):
1556  * ent(in):
1557  * args(in): Not used
1558  */
1559 static int
1560 locator_force_drop_class_name_entry (const void *name, void *ent, void *args)
1561 {
1562  THREAD_ENTRY *thread_p;
1564  LOCATOR_CLASSNAME_ACTION *old_action;
1565  OID class_oid;
1566 
1567  thread_p = thread_get_thread_entry_info ();
1568 
1569  assert (csect_check_own (thread_p, CSECT_CT_OID_TABLE) == 1);
1571 
1572  COPY_OID (&class_oid, &entry->e_current.oid);
1573 
1574  while (entry->e_current.prev != NULL)
1575  {
1576  old_action = entry->e_current.prev;
1577  entry->e_current = *old_action;
1578  free_and_init (old_action);
1579  }
1580 
1581  (void) mht_rem (locator_Mht_classnames, name, NULL, NULL);
1582 
1583  free_and_init (entry->e_name);
1584  free_and_init (entry);
1585 
1586  (void) catcls_remove_entry (thread_p, &class_oid);
1587 
1588  return NO_ERROR;
1589 }
1590 
1591 /*
1592  * locator_savepoint_transient_class_name_entries () - Reset savepoint of
1593  * classname entries
1594  *
1595  * return: NO_ERROR if all OK, ER_ status otherwise
1596  *
1597  * savep_lsa(in): LSA of a possible rollback point
1598  *
1599  * Note: Reset the classname entries of the current
1600  * transaction with the given LSA address. This is done when a
1601  * new savepoint is taken or top system operations is started
1602  */
1603 int
1605 {
1606  int tran_index;
1607  LOG_TDES *tdes; /* Transaction descriptor */
1608  int error_code = NO_ERROR;
1609 
1610  tran_index = LOG_FIND_THREAD_TRAN_INDEX (thread_p);
1611 
1612  if (tran_index != NULL_TRAN_INDEX)
1613  {
1614  if (locator_get_num_transient_classnames (tran_index) <= 0)
1615  {
1616  return NO_ERROR;
1617  }
1618  }
1619 
1620  tdes = LOG_FIND_TDES (tran_index);
1621 
1622  if (tdes->m_modified_classes.empty ())
1623  {
1624  /* We may have new transient classnames or dropping classnames whose heap files have not yet been updated; Then,
1625  * Those classnames have not been added to the modifed list Refer locator_defence_drop_class_name_entry () */
1626  return NO_ERROR; /* do nothing */
1627  }
1628 
1630  {
1631  /* Some kind of failure. We must notify the error to the caller. */
1632  assert (false);
1633  return ER_FAILED;
1634  }
1635 
1636  // *INDENT-OFF*
1637  const auto lambda_func = [&error_code, &savep_lsa] (const tx_transient_class_entry & t, bool & stop)
1638  {
1639  error_code = locator_savepoint_class_name_entry (t.get_classname (), savep_lsa);
1640  if (error_code != NO_ERROR)
1641  {
1642  assert (false);
1643  stop = true;
1644  }
1645  };
1646  // *INDENT-ON*
1647  tdes->m_modified_classes.map (lambda_func);
1648 
1650 
1651  return error_code;
1652 }
1653 
1654 /*
1655  * locator_savepoint_class_name_entry () - Savepoint one transient entry
1656  *
1657  * return: NO_ERROR
1658  *
1659  * classname(in): The classname
1660  * savep_lsa(in): LSA of a possible rollback point
1661  *
1662  * Note: Savepoint a transient entry if it belongs to current
1663  * transaction and it does not have a savepoint as the last
1664  * modified point.
1665  */
1666 static int
1668 {
1669  THREAD_ENTRY *thread_p;
1670  int tran_index;
1671  LOCATOR_CLASSNAME_ENTRY *entry;
1672 
1673  thread_p = thread_get_thread_entry_info ();
1674 
1675  tran_index = LOG_FIND_THREAD_TRAN_INDEX (thread_p);
1676 
1678 
1679  entry = (LOCATOR_CLASSNAME_ENTRY *) mht_get (locator_Mht_classnames, classname);
1680  if (entry == NULL)
1681  {
1682  /* table is dropped by myself; not exist */
1683  return NO_ERROR; /* do nothing */
1684  }
1685 
1686  if (!(entry->e_tran_index == NULL_TRAN_INDEX || entry->e_tran_index == tran_index))
1687  {
1688  /* table is dropped by myself and reserved by other tranx */
1689  return NO_ERROR; /* do nothing */
1690  }
1691 
1692  assert (entry->e_name != NULL);
1693  assert (!OID_ISNULL (&entry->e_current.oid));
1694 
1695  /* check iff need to savepoint */
1696  if (locator_is_exist_class_name_entry (thread_p, entry) == false)
1697  {
1698  assert (entry->e_tran_index == tran_index);
1699 
1700  if (LSA_ISNULL (&entry->e_current.savep_lsa))
1701  {
1702  LSA_COPY (&entry->e_current.savep_lsa, savep_lsa);
1703  }
1704  }
1705 
1706  return NO_ERROR;
1707 }
1708 
1709 /*
1710  * locator_print_class_name () - Print an entry of classname memory hash table
1711  *
1712  * return: always return true
1713  *
1714  * outfp(in): FILE stream where to dump the entry
1715  * key(in): Classname
1716  * ent(in): The entry associated with classname
1717  * args(in): class No
1718  *
1719  * Note:Print an entry of the classname memory hash table.
1720  */
1721 static int
1722 locator_print_class_name (THREAD_ENTRY * thread_p, FILE * outfp, const void *key, void *ent, void *args)
1723 {
1725  int *class_no_p = (int *) args;
1727  const char *str_action;
1728  size_t i;
1729  size_t key_size;
1730 
1731  assert (class_no_p != NULL);
1732 
1733  fprintf (outfp, " %2d %s ", *class_no_p, (char *) key);
1734  (*class_no_p)++;
1735  key_size = strlen ((char *) key);
1736  for (i = 0; i < (29 - key_size); i++)
1737  {
1738  fprintf (outfp, " ");
1739  }
1740  fprintf (outfp, "TRAN_INDEX = %d\n", entry->e_tran_index);
1741 
1742  action = &entry->e_current;
1743  while (action != NULL)
1744  {
1745  switch (action->action)
1746  {
1747  case LC_CLASSNAME_RESERVED:
1748  str_action = "LC_CLASSNAME_RESERVE";
1749  break;
1750  case LC_CLASSNAME_DELETED:
1751  str_action = "LC_CLASSNAME_DELETED";
1752  break;
1753  case LC_CLASSNAME_EXIST:
1754  str_action = "LC_CLASSNAME_EXIST";
1755  break;
1757  str_action = "LC_CLASSNAME_RESERVED_RENAME";
1758  break;
1760  str_action = "LC_CLASSNAME_DELETED_RENAME";
1761  break;
1762  default:
1763  assert (action->action == LC_CLASSNAME_ERROR);
1764  str_action = "UNKNOWN";
1765  break;
1766  }
1767  fprintf (outfp, " action = %s, OID = %d|%d|%d, Save_Lsa = %lld|%d\n", str_action, action->oid.volid,
1768  action->oid.pageid, action->oid.slotid, LSA_AS_ARGS (&action->savep_lsa));
1769  action = action->prev;
1770  }
1771 
1772  return (true);
1773 }
1774 
1775 /*
1776  * locator_dump_class_names () - Dump all classname entries
1777  *
1778  * return:
1779  *
1780  * out_fp(in): output file
1781  *
1782  * Note:Dump all names of classes and their corresponding OIDs.
1783  * This function is used for debugging purposes.
1784  */
1785 void
1786 locator_dump_class_names (THREAD_ENTRY * thread_p, FILE * out_fp)
1787 {
1788  int class_no;
1789 
1790 #if defined(NDEBUG) /* skip at debug build */
1792  {
1793  assert (false);
1794  return;
1795  }
1796 #endif
1797 
1798  class_no = 1; /* init */
1799  (void) mht_dump (thread_p, out_fp, locator_Mht_classnames, false, locator_print_class_name, &class_no);
1800 
1801 #if defined(NDEBUG) /* skip at debug build */
1803 #endif
1804 }
1805 
1806 /*
1807  * locator_generate_class_pseudo_oid () - Generate a pseudo-OID to be used
1808  * by reserved class name until a
1809  * permanent one is provided.
1810  *
1811  * return :
1812  * thread_p (in) :
1813  * class_oid (in) :
1814  */
1815 static void
1817 {
1819 
1820  class_oid->volid = -2;
1821  class_oid->slotid = -2;
1822  class_oid->pageid = locator_Pseudo_pageid_crt;
1823 
1825  {
1827  }
1828  else
1829  {
1831  }
1832 }
1833 
1834 /*
1835  * locator_check_class_on_heap () - Check the classname on the heap object
1836  *
1837  * return: NO_ERROR continue checking, error code stop checking, bad error
1838  *
1839  * name(in): The expected class name
1840  * ent(in):
1841  * args(out): Could be set as a side effect to either: DISK_INVALID,
1842  * DISK_ERROR when an inconsistency is found. Otherwise, it is
1843  * left in touch. The caller should initialize it to DISK_VALID
1844  *
1845  * Note: Check if the classname of the class associated with ent
1846  * is the same as the given class name.
1847  * If class does not exist, or its name is different from the
1848  * given one, isvalid is set to DISK_INVALID. In the case of other
1849  * kind of error, isvalid is set to DISK_ERROR.
1850  * If isvalid is set to DISK_ERROR, we return false to stop
1851  * the map hash, otherwise, we return true to continue.
1852  */
1853 static int
1854 locator_check_class_on_heap (const void *name, void *ent, void *args)
1855 {
1856  THREAD_ENTRY *thread_p;
1858  DISK_ISVALID *isvalid = (DISK_ISVALID *) args;
1859  const char *classname;
1860  char *heap_classname;
1861  OID *class_oid;
1862 
1863  thread_p = thread_get_thread_entry_info ();
1864 
1866 
1867  if (entry->e_current.action != LC_CLASSNAME_EXIST)
1868  {
1869  /* is not permanent classname */
1870  return NO_ERROR;
1871  }
1872 
1873  classname = (char *) name;
1874  class_oid = &entry->e_current.oid;
1875 
1876  if (heap_get_class_name_alloc_if_diff (thread_p, class_oid, (char *) classname, &heap_classname) != NO_ERROR
1877  || heap_classname == NULL)
1878  {
1879  if (er_errid () == ER_HEAP_UNKNOWN_OBJECT)
1880  {
1882  class_oid->volid, class_oid->pageid, class_oid->slotid);
1883  *isvalid = DISK_INVALID;
1884  }
1885  else
1886  {
1887  *isvalid = DISK_ERROR;
1888  }
1889 
1890  goto error;
1891  }
1892 
1893  /* Compare the classname pointers. If the same pointers classes are the same since the class was no malloc */
1894  if (heap_classname != classname)
1895  {
1896  /* Different names */
1898  class_oid->pageid, class_oid->slotid, classname, heap_classname);
1899  *isvalid = DISK_INVALID;
1900  free_and_init (heap_classname);
1901  }
1902 
1903 error:
1904  if (*isvalid == DISK_ERROR)
1905  {
1906  return ER_FAILED;
1907  }
1908  else
1909  {
1910  return NO_ERROR;
1911  }
1912 }
1913 
1914 /*
1915  * locator_check_class_names () - Check classname consistency
1916  *
1917  * return: DISK_ISVALID
1918  *
1919  * Note: Check the consistency of the classname_to_oid and the heap of
1920  * classes and vice versa.
1921  */
1924 {
1925  DISK_ISVALID isvalid;
1926  RECDES peek = RECDES_INITIALIZER; /* Record descriptor for peeking object */
1927  HFID root_hfid;
1928  OID class_oid;
1929  char *classname = NULL;
1930  HEAP_SCANCACHE scan_cache;
1932  LOCATOR_CLASSNAME_ENTRY *entry;
1933 
1934  mvcc_snapshot = logtb_get_mvcc_snapshot (thread_p);
1935  if (mvcc_snapshot == NULL)
1936  {
1937  return DISK_ERROR;
1938  }
1939 
1941  {
1942  /* Some kind of failure. We must notify the error to the caller. */
1943  assert (false);
1944  return DISK_ERROR;
1945  }
1946 
1947  /*
1948  * CHECK 1: Each class that is found by scanning the heap of classes, must
1949  * be part of the permanent classname_to_oid table.
1950  */
1951 
1952  /* Find the heap for the classes */
1953 
1954  /* Find every single class */
1955 
1956  if (boot_find_root_heap (&root_hfid) != NO_ERROR || HFID_IS_NULL (&root_hfid))
1957  {
1958  goto error;
1959  }
1960 
1961  if (heap_scancache_start (thread_p, &scan_cache, &root_hfid, oid_Root_class_oid, true, false, mvcc_snapshot) !=
1962  NO_ERROR)
1963  {
1964  goto error;
1965  }
1966 
1967  class_oid.volid = root_hfid.vfid.volid;
1968  class_oid.pageid = NULL_PAGEID;
1969  class_oid.slotid = NULL_SLOTID;
1970 
1971  isvalid = DISK_VALID;
1972  while (heap_next (thread_p, &root_hfid, oid_Root_class_oid, &class_oid, &peek, &scan_cache, PEEK) == S_SUCCESS)
1973  {
1974  classname = or_class_name (&peek);
1975  assert (classname != NULL);
1976  assert (strlen (classname) < 255);
1977 
1978  /*
1979  * Make sure that this class exists in classname_to_OID table and that
1980  * the OIDS matches
1981  */
1982  entry = (LOCATOR_CLASSNAME_ENTRY *) mht_get (locator_Mht_classnames, classname);
1983  if (entry == NULL)
1984  {
1985  isvalid = DISK_INVALID;
1987  class_oid.pageid, class_oid.slotid);
1988  }
1989  else
1990  {
1991  /* Are OIDs the same ? */
1992  if (!OID_EQ (&class_oid, &entry->e_current.oid))
1993  {
1995  entry->e_current.oid.volid, entry->e_current.oid.pageid, entry->e_current.oid.slotid,
1996  class_oid.volid, class_oid.pageid, class_oid.slotid);
1997  isvalid = DISK_INVALID;
1998  }
1999  }
2000  } /* while (...) */
2001 
2002  /* End the scan cursor */
2003  if (heap_scancache_end (thread_p, &scan_cache) != NO_ERROR)
2004  {
2005  isvalid = DISK_ERROR;
2006  }
2007 
2008  /*
2009  * CHECK 2: Same that check1 but from classname_to_OID to existance of class
2010  */
2011  (void) mht_map (locator_Mht_classnames, locator_check_class_on_heap, &isvalid);
2012 
2014 
2015  return isvalid;
2016 
2017 error:
2019 
2020  return DISK_ERROR;
2021 }
2022 
2023 /*
2024  * Functions related to fetching and flushing
2025  */
2026 
2027 /*
2028  * xlocator_assign_oid () - Assign a permanent oid
2029  *
2030  * return: NO_ERROR if all OK, ER_ status otherwise
2031  *
2032  * hfid(in): Heap where the object will be stored
2033  * perm_oid(in/out): Object identifier.. (set as a side effect)
2034  * expected_length(in): Expected length of the object
2035  * class_oid(in): The class of the instance
2036  * classname(in): Optional... classname for classes
2037  *
2038  * Note: A permanent oid is assigned, the object associated with that
2039  * OID is locked through the new OID. If the object is a class
2040  * the classname to OID entry is updated to reflect the
2041  * newly assigned OID.
2042  */
2043 int
2044 xlocator_assign_oid (THREAD_ENTRY * thread_p, const HFID * hfid, OID * perm_oid, int expected_length, OID * class_oid,
2045  const char *classname)
2046 {
2047  int error_code = NO_ERROR;
2048 
2049  if (heap_assign_address (thread_p, hfid, class_oid, perm_oid, expected_length) != NO_ERROR)
2050  {
2051  return ER_FAILED;
2052  }
2053 
2054  if (classname != NULL)
2055  {
2056  error_code = locator_permoid_class_name (thread_p, classname, perm_oid);
2057  assert (error_code == NO_ERROR);
2058  }
2059 
2060  return error_code;
2061 }
2062 
2063 /*
2064  * locator_find_lockset_missing_class_oids () - Find missing class oids
2065  *
2066  * return: NO_ERROR if all OK, ER_ status otherwise
2067  *
2068  * lockset(in): Request for finding missing classes
2069  *
2070  * Note: Find missing class oids in requested area.
2071  * The function does not quit when an error is found if the value
2072  * of lockset->quit_on_errors is false. In this case the
2073  * object with the error is set to a NULL_OID. For example, when
2074  * a class of an object does not exist.
2075  * Note: There must be enough space in the lockset area to define all
2076  * missing classes.
2077  */
2078 static int
2080 {
2081  LC_LOCKSET_REQOBJ *reqobjs; /* Description of one instance to fetch */
2082  LC_LOCKSET_CLASSOF *reqclasses; /* Description of one class of a requested object */
2083  OID class_oid; /* Uses to hold the class_oid when it is unknown */
2084  int i, j;
2085  int error_code = NO_ERROR;
2086 
2087  /* Locate array of objects and array of classes */
2088 
2089  reqobjs = lockset->objects;
2090  reqclasses = lockset->classes;
2091 
2092 #if defined(CUBRID_DEBUG)
2093  i = (sizeof (*lockset) + (lockset->num_reqobjs * (sizeof (*reqclasses) + sizeof (*reqobjs))));
2094 
2095  if (lockset->length < i || lockset->classes != ((LC_LOCKSET_CLASSOF *) (lockset->mem + sizeof (*lockset)))
2096  || lockset->objects < ((LC_LOCKSET_REQOBJ *) (lockset->classes + lockset->num_reqobjs)))
2097  {
2099  "locator_find_lockset_missing_class_oids: *** SYSTEM ERROR. Requesting area is incorrect,\n"
2100  " either area is too small %d (expect at least %d),\n pointer to classes %p (expected %p), or\n"
2101  " pointer to objects %p (expected >= %p) are incorrect\n", lockset->length, i, lockset->classes,
2102  ((LC_LOCKSET_CLASSOF *) (lockset->mem + sizeof (*lockset))), lockset->objects,
2103  ((LC_LOCKSET_REQOBJ *) (lockset->classes + lockset->num_reqobjs)));
2105 
2106  error_code = ER_GENERIC_ERROR;
2107  goto error;
2108  }
2109 #endif /* CUBRID_DEBUG */
2110 
2111 
2112  /*
2113  * All class identifiers of requested objects must be known. Find the ones
2114  * that the caller is unaware
2115  */
2116 
2117  for (i = 0; i < lockset->num_reqobjs; i++)
2118  {
2119  if (reqobjs[i].class_index != -1 || OID_ISNULL (&reqobjs[i].oid))
2120  {
2121  continue;
2122  }
2123  /*
2124  * Caller does not know the class identifier of the requested object.
2125  * Get the class identifier from disk
2126  */
2127  if (heap_get_class_oid (thread_p, &reqobjs[i].oid, &class_oid) != S_SUCCESS)
2128  {
2129  /*
2130  * Unable to find the class of the object. Remove the object from
2131  * the list of requested objects.
2132  */
2133  OID_SET_NULL (&reqobjs[i].oid);
2134  if (lockset->quit_on_errors != false)
2135  {
2136  error_code = ER_FAILED;
2137  goto error;
2138  }
2139  continue;
2140  }
2141 
2142  /*
2143  * Insert this class in the list of classes of requested objects.
2144  * Make sure that the class is not already present in the list.
2145  */
2146 
2147  for (j = 0; j < lockset->num_classes_of_reqobjs; j++)
2148  {
2149  if (OID_EQ (&class_oid, &reqclasses[j].oid))
2150  {
2151  /* OID is already in the list */
2152  reqobjs[i].class_index = j;
2153  break;
2154  }
2155  }
2156  if (j >= lockset->num_classes_of_reqobjs)
2157  {
2158  /* OID is not in the list */
2159  COPY_OID (&reqclasses[lockset->num_classes_of_reqobjs].oid, &class_oid);
2160  reqclasses[lockset->num_classes_of_reqobjs].chn = CHN_UNKNOWN_ATCLIENT;
2161  reqobjs[i].class_index = lockset->num_classes_of_reqobjs;
2162  lockset->num_classes_of_reqobjs++;
2163  }
2164  }
2165 
2166 error:
2167  return error_code;
2168 }
2169 
2170 static SCAN_CODE
2172  int chn, int guess_chn, SCAN_CODE scan, int tran_index)
2173 {
2174  int round_length; /* Length of object rounded to integer alignment */
2175 
2176  switch (scan)
2177  {
2178  case S_SUCCESS:
2179  /*
2180  * The cached object was obsolete.
2181  */
2182  round_length = DB_ALIGN (assign->recdes.length, MAX_ALIGNMENT);
2183  if (assign->recdes.area_size < (round_length + (int) sizeof (*assign->obj)))
2184  {
2185  assign->recdes.area_size -= (round_length + sizeof (*assign->obj));
2186  scan = S_DOESNT_FIT;
2187  }
2188  else
2189  {
2190  if (OID_IS_ROOTOID (class_oid))
2191  {
2192  if (tran_index == NULL_TRAN_INDEX)
2193  {
2194  tran_index = LOG_FIND_THREAD_TRAN_INDEX (thread_p);
2195  }
2196  (void) heap_chnguess_put (thread_p, oid, tran_index, or_chn (&assign->recdes));
2197  }
2198  assign->mobjs->num_objs++;
2199 
2200  COPY_OID (&assign->obj->class_oid, class_oid);
2201  COPY_OID (&assign->obj->oid, oid);
2202 
2203  /* Set object flag */
2204  assign->obj->flag = 0;
2205 
2206  assign->obj->hfid = NULL_HFID;
2207  assign->obj->length = assign->recdes.length;
2208  assign->obj->offset = assign->area_offset;
2209  assign->obj->operation = LC_FETCH;
2210  assign->obj = LC_NEXT_ONEOBJ_PTR_IN_COPYAREA (assign->obj);
2211 
2212 #if !defined(NDEBUG)
2213  /* suppress valgrind UMW error */
2214  memset (assign->recdes.data + assign->recdes.length, 0,
2215  MIN (round_length - assign->recdes.length, assign->recdes.area_size - assign->recdes.length));
2216 #endif
2217  assign->recdes.length = round_length;
2218  assign->area_offset += round_length;
2219  assign->recdes.data += round_length;
2220  assign->recdes.area_size -= round_length + sizeof (*assign->obj);
2221  }
2222 
2223  break;
2224 
2226  /*
2227  * the cached object was on the right state
2228  */
2229  scan = S_SUCCESS;
2230 
2231  if (guess_chn == CHN_UNKNOWN_ATCLIENT)
2232  {
2233  if (assign->recdes.area_size < (int) sizeof (*assign->obj))
2234  {
2235  assign->recdes.area_size -= sizeof (*assign->obj);
2236  scan = S_DOESNT_FIT;
2237  }
2238  else
2239  {
2240  assign->mobjs->num_objs++;
2241 
2242  /* Indicate to the caller that the object does not exist any longer */
2243  COPY_OID (&assign->obj->class_oid, class_oid);
2244  COPY_OID (&assign->obj->oid, oid);
2245  assign->obj->flag = 0;
2246  assign->obj->hfid = NULL_HFID;
2247  assign->obj->length = -chn;
2248  assign->obj->offset = -1;
2249  assign->obj->operation = LC_FETCH_VERIFY_CHN;
2250  assign->obj = LC_NEXT_ONEOBJ_PTR_IN_COPYAREA (assign->obj);
2251  assign->recdes.area_size -= sizeof (*assign->obj);
2252  }
2253  }
2254  break;
2255 
2256  case S_DOESNT_EXIST:
2257  /*
2258  * The object does not exist
2259  */
2260  if (assign->recdes.area_size < (int) sizeof (*assign->obj))
2261  {
2262  assign->recdes.area_size -= sizeof (*assign->obj);
2263  scan = S_DOESNT_FIT;
2264  }
2265  else
2266  {
2267  assign->mobjs->num_objs++;
2268 
2269  /* Indicate to the caller that the object does not exist any longer */
2270  COPY_OID (&assign->obj->class_oid, class_oid);
2271  COPY_OID (&assign->obj->oid, oid);
2272  assign->obj->flag = 0;
2273  assign->obj->hfid = NULL_HFID;
2274  assign->obj->length = -1;
2275  assign->obj->offset = -1;
2276  assign->obj->operation = LC_FETCH_DELETED;
2277  assign->obj = LC_NEXT_ONEOBJ_PTR_IN_COPYAREA (assign->obj);
2278  assign->recdes.area_size -= sizeof (*assign->obj);
2279  }
2280 
2281  break;
2282 
2283  default:
2284  break;
2285 
2286  }
2287 
2288  return scan;
2289 }
2290 
2291 /*
2292  * locator_lock_and_return_object () - Lock object, get its data and place it
2293  * in communication area.
2294  *
2295  * return : SCAN_CODE
2296  * (Either of S_SUCCESS,
2297  * S_DOESNT_FIT,
2298  * S_DOESNT_EXIST,
2299  * S_ERROR)
2300  * thread_p (in) : Thread entry.
2301  * assign (in/out) : Locator structure to store object data.
2302  * class_oid (in) : Class OID.
2303  * oid (in) : Object OID.
2304  * chn (in) : Known object CHN (or NULL_CHN if not known).
2305  * lock_mode (in) : Require lock on object.
2306  *
2307  * Note: The desired object is placed in the assigned return area when the
2308  * state of the object(chn) in the client workspace is different from
2309  * the one on disk. If the object does not fit in assigned return area,
2310  * the length of the object is returned as a negative value in the area
2311  * recdes length.
2312  */
2313 static SCAN_CODE
2315  int chn, LOCK lock_mode, SCAN_OPERATION_TYPE op_type)
2316 {
2317  SCAN_CODE scan; /* Scan return value for next operation */
2318  int guess_chn = chn;
2319  int tran_index = NULL_TRAN_INDEX;
2320 
2321  /*
2322  * The next object is placed in the assigned recdes area if the cached
2323  * object is obsolete and the object fits in the recdes
2324  */
2325  assert (oid != NULL);
2326  if (chn == CHN_UNKNOWN_ATCLIENT)
2327  {
2328  tran_index = LOG_FIND_THREAD_TRAN_INDEX (thread_p);
2329  chn = heap_chnguess_get (thread_p, oid, tran_index);
2330  }
2331 
2332  scan = locator_get_object (thread_p, oid, class_oid, &assign->recdes, assign->ptr_scancache, op_type, lock_mode, COPY,
2333  chn);
2334  if (scan == S_ERROR || scan == S_SNAPSHOT_NOT_SATISFIED || scan == S_END || scan == S_DOESNT_EXIST)
2335  {
2336  return scan;
2337  }
2338 
2339  scan = locator_return_object_assign (thread_p, assign, class_oid, oid, chn, guess_chn, scan, tran_index);
2340 
2341  return scan;
2342 }
2343 
2344 /*
2345  * xlocator_fetch () - Lock and fetch an object, and prefetch some other objects
2346  *
2347  * return: NO_ERROR if all OK, ER_ status otherwise
2348  *
2349  * thread_p(in):
2350  * oid(in): Object identifier of requested object
2351  * chn(in): Cache coherence number of object
2352  * lock(in): Lock to acquire before the object is fetched
2353  * fetch_version_type(in): fetch version type
2354  * initial_fetch_version_type(in): initial fetch version type
2355  * class_oid(in): Class identifier of the object
2356  * class_chn(in): Cache coherence number of the class of the object
2357  * prefetching(in): true when prefetching of neighbors is desired
2358  * fetch_area(in/out): Pointer to area where the objects are placed
2359  (set to point to fetching area)
2360  *
2361  * Note: This function locks and fetches the object associated with the
2362  * given oid. The object is only placed in the fetch area when
2363  * the state of the object (chn) in the workspace (client) is
2364  * different from the one on disk. The class along with several
2365  * other neighbors of the object may also be included in the
2366  * fetch area. It is up to the caller if the additional objects
2367  * are cached. Fetch_area is set to NULL when there is an error
2368  * or when there is not a need to send any object back since the
2369  * cache coherent numbers were the same as those on disk. The
2370  * caller must check the return value of the function to find out
2371  * if there was any error.
2372  * The returned fetch area should be freed by the caller.
2373  */
2374 int
2375 xlocator_fetch (THREAD_ENTRY * thread_p, OID * oid, int chn, LOCK lock,
2376  LC_FETCH_VERSION_TYPE fetch_version_type, LC_FETCH_VERSION_TYPE initial_fetch_version_type,
2377  OID * class_oid, int class_chn, int prefetching, LC_COPYAREA ** fetch_area)
2378 {
2379  OID tmp_oid; /* Uses to hold the class_oid when it is not know by the caller */
2380  LC_COPYAREA_DESC prefetch_des;
2381  LOCATOR_RETURN_NXOBJ nxobj; /* Description to return next obj */
2382  int copyarea_length;
2383  SCAN_CODE scan = S_ERROR;
2384  int error_code = NO_ERROR;
2386  MVCC_SNAPSHOT mvcc_snapshot_dirty;
2387  SCAN_OPERATION_TYPE operation_type;
2388  OID *p_oid = oid;
2389  bool object_locked = false;
2390  int is_mvcc_disabled_class = -1;
2391  LOCK class_lock;
2392  /* We assume that the object have to be locked; after it is locked or we determine that this is not necessary,
2393  * object_need_locking will be set to false; */
2394  bool object_need_locking = true;
2395  bool skip_fetch_version_type_check = false;
2396 
2397  if (fetch_version_type == LC_FETCH_CURRENT_VERSION_NO_CHECK)
2398  {
2399  /* The purpose was to fetch the current version. Avoid checks. */
2400  fetch_version_type = LC_FETCH_CURRENT_VERSION;
2401  skip_fetch_version_type_check = true;
2402  }
2403 
2404  if (LC_FETCH_IS_MVCC_VERSION_NEEDED (initial_fetch_version_type))
2405  {
2406  skip_fetch_version_type_check = true;
2407  }
2408 
2409  switch (fetch_version_type)
2410  {
2411  case LC_FETCH_MVCC_VERSION:
2412  mvcc_snapshot = logtb_get_mvcc_snapshot (thread_p);
2413  if (mvcc_snapshot == NULL)
2414  {
2415  error_code = er_errid ();
2416  return (error_code == NO_ERROR ? ER_FAILED : error_code);
2417  }
2418  break;
2419 
2421  mvcc_snapshot_dirty.snapshot_fnc = mvcc_satisfies_dirty;
2422  mvcc_snapshot = &mvcc_snapshot_dirty;
2423  break;
2424 
2426  mvcc_snapshot = NULL;
2427  break;
2428 
2429  default:
2430  /* no usage at this point */
2431  assert (0);
2432  break;
2433  }
2434 
2435  /* Compute operation type */
2436  operation_type = locator_decide_operation_type (lock, fetch_version_type);
2437 
2438  if (class_oid == NULL)
2439  {
2440  /* The class_oid is not known by the caller. */
2441  class_oid = &tmp_oid;
2442  OID_SET_NULL (class_oid);
2443  }
2444 
2445 #if !defined (NDEBUG)
2446  if (OID_ISNULL (class_oid))
2447  {
2448  /*
2449  * Caller does not know the class of the object. Get the class
2450  * identifier from disk
2451  */
2452  scan = heap_get_class_oid (thread_p, oid, class_oid);
2453  if (scan != S_SUCCESS)
2454  {
2455  /* Unable to find the class of the object.. return */
2456  *fetch_area = NULL;
2457 
2458  error_code = ER_HEAP_UNKNOWN_OBJECT;
2459  if (er_errid () != error_code)
2460  {
2461  /* error was not previously set; set error in order to have it returned to client */
2462  er_set (ER_WARNING_SEVERITY, ARG_FILE_LINE, error_code, 3, oid->volid, oid->pageid, oid->slotid);
2463  }
2464  return error_code;
2465  }
2466  }
2467 
2468  assert (!OID_ISNULL (class_oid));
2469 
2470  /* Current version or dirty version for instance with NULL_LOCK is allowed only if the transaction already has a
2471  * lock. This means that is not necessary to request the lock again. */
2472  assert (skip_fetch_version_type_check || (OID_EQ (class_oid, oid_Root_class_oid))
2473  || ((lock != NULL_LOCK)
2474  || (lock_get_object_lock (oid, class_oid) != NULL_LOCK)
2475  || ((class_lock = lock_get_object_lock (class_oid, oid_Root_class_oid)) == S_LOCK
2476  || class_lock >= SIX_LOCK)
2477  || ((class_lock = lock_get_object_lock (oid_Root_class_oid, NULL)) == S_LOCK || class_lock >= SIX_LOCK)));
2478 
2479  /* LC_FETCH_CURRENT_VERSION should be used for classes only */
2480  assert (fetch_version_type != LC_FETCH_CURRENT_VERSION || OID_IS_ROOTOID (class_oid));
2481 #endif /* DEBUG */
2482 
2483  /*
2484  * Lock and fetch the object.
2485  */
2486 
2487  /* Assume that the needed object can fit in one page */
2488  copyarea_length = DB_PAGESIZE;
2489 
2490  error_code = heap_scancache_start (thread_p, &nxobj.area_scancache, NULL, NULL, false, false, mvcc_snapshot);
2491  if (error_code != NO_ERROR)
2492  {
2493  nxobj.mobjs = NULL;
2494  error_code = ER_FAILED;
2495  goto error;
2496  }
2497  nxobj.ptr_scancache = &nxobj.area_scancache;
2498 
2499  while (true)
2500  {
2501  nxobj.comm_area = *fetch_area = locator_allocate_copy_area_by_length (copyarea_length);
2502  if (nxobj.comm_area == NULL)
2503  {
2504  heap_scancache_end (thread_p, &nxobj.area_scancache);
2505  nxobj.mobjs = NULL;
2506  error_code = ER_FAILED;
2507  goto error;
2508  }
2509 
2511  nxobj.obj = LC_START_ONEOBJ_PTR_IN_COPYAREA (nxobj.mobjs);
2512  LC_RECDES_IN_COPYAREA (nxobj.comm_area, &nxobj.recdes);
2513  nxobj.area_offset = 0;
2514  nxobj.mobjs->num_objs = 0;
2515 
2516  /* Get the interested object first */
2517  scan = locator_lock_and_return_object (thread_p, &nxobj, class_oid, p_oid, chn,
2518  object_need_locking ? lock : NULL_LOCK, operation_type);
2519  if (scan == S_SUCCESS)
2520  {
2521  if (object_need_locking)
2522  {
2523  object_need_locking = false;
2524  is_mvcc_disabled_class = mvcc_is_mvcc_disabled_class (class_oid) ? 1 : 0;
2525  if (is_mvcc_disabled_class == 1)
2526  {
2527  if (lock > NULL_LOCK)
2528  {
2529  /* Non-MVCC: Always lock object */
2530  object_locked = true;
2531  }
2532  }
2533  else if (lock == X_LOCK)
2534  {
2535  /* MVCC X_LOCK: Need exclusive lock on object. Get MVCC object version for delete/update. */
2536  object_locked = true;
2537  }
2538  else if (operation_type == S_SELECT_WITH_LOCK)
2539  {
2540  /* MVCC S_SELECT_WITH_LOCK: We need to read and lock last object version found with satisfy dirty
2541  * rules. This object must be also locked. */
2542  object_locked = true;
2543  }
2544  }
2545  break;
2546  }
2547 
2548  /* Get the real length of current fetch/copy area */
2549  copyarea_length = nxobj.comm_area->length;
2551 
2552  /*
2553  * If the object does not fit even when the copy area seems to be
2554  * large enough, increase the copy area by at least one page size.
2555  */
2556  if (scan == S_DOESNT_EXIST || scan == S_SNAPSHOT_NOT_SATISFIED)
2557  {
2558  heap_scancache_end (thread_p, &nxobj.area_scancache);
2559  nxobj.comm_area = *fetch_area = NULL;
2560  error_code = ER_HEAP_UNKNOWN_OBJECT;
2561  if (er_errid () != error_code)
2562  {
2563  /* error was not previously set; set error in order to have it returned to client */
2564  er_set (ER_WARNING_SEVERITY, ARG_FILE_LINE, error_code, 3, oid->volid, oid->pageid, oid->slotid);
2565  }
2566  goto error;
2567  }
2568  else if (scan != S_DOESNT_FIT)
2569  {
2570  heap_scancache_end (thread_p, &nxobj.area_scancache);
2571  nxobj.comm_area = *fetch_area = NULL;
2572  error_code = ER_FAILED;
2573  goto error;
2574  }
2575 
2576  if ((-nxobj.recdes.length) > copyarea_length)
2577  {
2578  copyarea_length = (DB_ALIGN (-nxobj.recdes.length, MAX_ALIGNMENT) + sizeof (*nxobj.mobjs));
2579  }
2580  else
2581  {
2582  copyarea_length += DB_PAGESIZE;
2583  }
2584  }
2585 
2586  /*
2587  * Then, get the interested class, if given class coherency number is not
2588  * current.
2589  */
2590  scan = locator_lock_and_return_object (thread_p, &nxobj, oid_Root_class_oid, class_oid, class_chn, NULL_LOCK,
2591  S_SELECT);
2592  if (scan == S_SUCCESS && nxobj.mobjs->num_objs == 2)
2593  {
2594  LC_COPYAREA_ONEOBJ *first, *second;
2595  LC_COPYAREA_ONEOBJ save;
2596  /*
2597  * It is better if the class is cached first, so swap the
2598  * description. The object was stored first because it has
2599  * priority of retrieval, however, if both the object and its
2600  * class fits, the class should go first for performance reasons
2601  */
2602 
2603  /* Save the object information, then move the class information */
2604  first = LC_START_ONEOBJ_PTR_IN_COPYAREA (nxobj.mobjs);
2605  second = LC_NEXT_ONEOBJ_PTR_IN_COPYAREA (first);
2606 
2607  /* Swap the values */
2608  save = *first;
2609  *first = *second;
2610  *second = save;
2611  }
2612 
2613  error_code = heap_scancache_end (thread_p, &nxobj.area_scancache);
2614  if (error_code != NO_ERROR)
2615  {
2617  *fetch_area = NULL;
2618  error_code = ER_FAILED;
2619  goto error;
2620  }
2621  nxobj.ptr_scancache = NULL;
2622 
2623 
2624  prefetch_des.mobjs = nxobj.mobjs;
2625  prefetch_des.obj = &nxobj.obj;
2626 
2627  prefetch_des.offset = &nxobj.area_offset;
2628  prefetch_des.recdes = &nxobj.recdes;
2629 
2630  /*
2631  * Find any decache notifications and prefetch any neighbors of the
2632  * instance
2633  */
2634 
2635  lock_notify_isolation_incons (thread_p, locator_notify_decache, &prefetch_des);
2636  if (prefetching && nxobj.mobjs->num_objs > 0)
2637  {
2638  error_code = heap_prefetch (thread_p, class_oid, oid, &prefetch_des);
2639  }
2640 
2641  if (nxobj.mobjs->num_objs == 0)
2642  {
2643  /*
2644  * Don't need to send anything. The cache coherency numbers were
2645  * identical. Deallocate the area and return without failure
2646  */
2648  *fetch_area = NULL;
2649  }
2650 
2651 error:
2652  if (lock != NULL_LOCK)
2653  {
2654  if (error_code != NO_ERROR)
2655  {
2656  if (object_locked)
2657  {
2658  lock_unlock_object_donot_move_to_non2pl (thread_p, p_oid, class_oid, lock);
2659  }
2660  }
2661  else if (is_mvcc_disabled_class == 1 || (is_mvcc_disabled_class == -1 && mvcc_is_mvcc_disabled_class (class_oid)))
2662  {
2663  if (lock <= S_LOCK)
2664  {
2665  assert (object_locked);
2666  lock_unlock_object (thread_p, p_oid, class_oid, lock, false);
2667  }
2668  }
2669  }
2670 
2671  return error_code;
2672 }
2673 
2674 /*
2675  * xlocator_get_class () - Lock and fetch the class of an instance, and prefetch
2676  * given instance and some other instances of class
2677  *
2678  * return: NO_ERROR if all OK, ER_ status otherwise
2679  *
2680  * class_oid(in/out): Class identifier of the object. (It is set as a side
2681  * effect when its initial value is a null OID)
2682  * class_chn(in): Cache coherence number of the class of the object
2683  * oid(in): Object identifier of the instance of the desired class
2684  * lock(in): Lock to acquire before the class is acquired/fetched
2685  * Note that the lock is for the class.
2686  * prefetching(in): true when pretching of neighbors is desired
2687  * fetch_area(in/out): Pointer to area where the objects are placed (set to
2688  * point to fetching area)
2689  *
2690  * Note: This function locks and fetches the class of the given
2691  * instance. The class is only placed in a communication copy
2692  * area when the state of the class (class_chn) in the workspace
2693  * (client) is different from the one on disk. Other neighbors of
2694  * the class are included in the copy_area. It is up to the
2695  * caller if the additional classes are cached. Fetch_area is
2696  * set to NULL when there is an error or when there is not a need
2697  * to send any object back since the cache coherent numbers were
2698  * the same as those on disk. The caller must check the return
2699  * value of the function to find out if there was any error.
2700  *
2701  * Note: The returned fetch area should be freed by the caller.
2702  */
2703 int
2704 xlocator_get_class (THREAD_ENTRY * thread_p, OID * class_oid, int class_chn, const OID * oid, LOCK lock,
2705  int prefetching, LC_COPYAREA ** fetch_area)
2706 {
2707  int error_code;
2708 
2709  if (OID_ISNULL (class_oid))
2710  {
2711  /*
2712  * Caller does not know the class of the object. Get the class identifier
2713  * from disk
2714  */
2715  if (heap_get_class_oid (thread_p, oid, class_oid) != S_SUCCESS)
2716  {
2717  /*
2718  * Unable to find out the class identifier.
2719  */
2720  ASSERT_ERROR_AND_SET (error_code);
2721  *fetch_area = NULL;
2722  return error_code;
2723  }
2724  }
2725 
2726  /* Now acquired the desired lock */
2727  if (lock != NULL_LOCK)
2728  {
2729  /* Now acquired the desired lock */
2730  if (lock_object (thread_p, class_oid, oid_Root_class_oid, lock, LK_UNCOND_LOCK) != LK_GRANTED)
2731  {
2732  /*
2733  * Unable to acquired lock
2734  */
2735  *fetch_area = NULL;
2736  return ER_FAILED;
2737  }
2738  }
2739 
2740  /*
2741  * Now fetch the class, the instance and optionally prefetch some
2742  * neighbors of the instance. No need to get the last version for class.
2743  */
2744 
2745  error_code =
2747  oid_Root_class_oid, -1, prefetching, fetch_area);
2748 
2749  if (error_code != NO_ERROR && lock != NULL_LOCK)
2750  {
2751  lock_unlock_object (thread_p, class_oid, oid_Root_class_oid, lock, false);
2752  }
2753 
2754  return error_code;
2755 }
2756 
2757 /*
2758  * xlocator_fetch_all () - Fetch all instances of a class
2759  *
2760  * return: NO_ERROR if all OK, ER_ status otherwise
2761  *
2762  * hfid(in): Heap file where the instances of the class are placed
2763  * lock(in): Lock to acquired (Set as a side effect to NULL_LOCKID)
2764  * fetch_version_type(in): fetch version type
2765  * class_oid(in): Class identifier of the instances to fetch
2766  * nobjects(out): Total number of objects to fetch.
2767  * nfetched(out): Current number of object fetched.
2768  * last_oid(out): Object identifier of last fetched object
2769  * fetch_area(in/out): Pointer to area where the objects are placed
2770  *
2771  */
2772 int
2773 xlocator_fetch_all (THREAD_ENTRY * thread_p, const HFID * hfid, LOCK * lock, LC_FETCH_VERSION_TYPE fetch_version_type,
2774  OID * class_oid, int *nobjects, int *nfetched, OID * last_oid, LC_COPYAREA ** fetch_area)
2775 {
2776  LC_COPYAREA_DESC prefetch_des; /* Descriptor for decache of objects related to transaction isolation level */
2777  LC_COPYAREA_MANYOBJS *mobjs; /* Describe multiple objects in area */
2778  LC_COPYAREA_ONEOBJ *obj; /* Describe on object in area */
2779  RECDES recdes; /* Record descriptor for insertion */
2780  int offset; /* Place to store next object in area */
2781  int round_length; /* Length of object rounded to integer alignment */
2782  int copyarea_length;
2783  OID oid;
2784  HEAP_SCANCACHE scan_cache;
2785  SCAN_CODE scan;
2786  int error_code = NO_ERROR;
2788  MVCC_SNAPSHOT mvcc_snapshot_dirty;
2789 
2790  assert (lock != NULL);
2791  if (OID_ISNULL (last_oid))
2792  {
2793  /* FIRST TIME. */
2794 
2795  /* Obtain the desired lock for the class scan */
2796  if (*lock != NULL_LOCK
2797  && lock_object (thread_p, class_oid, oid_Root_class_oid, *lock, LK_UNCOND_LOCK) != LK_GRANTED)
2798  {
2799  /*
2800  * Unable to acquired lock
2801  */
2802  *fetch_area = NULL;
2803  *lock = NULL_LOCK;
2804  *nobjects = -1;
2805  *nfetched = -1;
2806 
2807  error_code = ER_FAILED;
2808  goto error;
2809  }
2810 
2811  /* Get statistics */
2812  last_oid->volid = hfid->vfid.volid;
2813  last_oid->pageid = NULL_PAGEID;
2814  last_oid->slotid = NULL_SLOTID;
2815  /* Estimate the number of objects to be fetched */
2816  *nobjects = heap_estimate_num_objects (thread_p, hfid);
2817  *nfetched = 0;
2818  if (*nobjects == -1)
2819  {
2820  if (*lock != NULL_LOCK)
2821  {
2822  lock_unlock_object (thread_p, class_oid, oid_Root_class_oid, *lock, false);
2823  }
2824  *fetch_area = NULL;
2825  error_code = ER_FAILED;
2826  goto error;
2827  }
2828  }
2829 
2830  switch (fetch_version_type)
2831  {
2832  case LC_FETCH_MVCC_VERSION:
2833  mvcc_snapshot = logtb_get_mvcc_snapshot (thread_p);
2834  if (mvcc_snapshot == NULL)
2835  {
2836  error_code = er_errid ();
2837  if (error_code == NO_ERROR)
2838  {
2839  error_code = ER_FAILED;
2840  }
2841  goto error;
2842  }
2843  break;
2844 
2846  mvcc_snapshot_dirty.snapshot_fnc = mvcc_satisfies_dirty;
2847  mvcc_snapshot = &mvcc_snapshot_dirty;
2848  break;
2849 
2851  mvcc_snapshot = NULL;
2852  break;
2853 
2854  default:
2855  assert (0);
2856  }
2857 
2858  /* Set OID to last fetched object */
2859  COPY_OID (&oid, last_oid);
2860 
2861  /* Start a scan cursor for getting several classes */
2862  error_code = heap_scancache_start (thread_p, &scan_cache, hfid, class_oid, true, false, mvcc_snapshot);
2863  if (error_code != NO_ERROR)
2864  {
2865  if (*lock != NULL_LOCK)
2866  {
2867  lock_unlock_object (thread_p, class_oid, oid_Root_class_oid, *lock, false);
2868  }
2869  *fetch_area = NULL;
2870 
2871  goto error;
2872  }
2873 
2874  /* Assume that the next object can fit in one page */
2875  copyarea_length = DB_PAGESIZE;
2876 
2877  while (true)
2878  {
2879  *fetch_area = locator_allocate_copy_area_by_length (copyarea_length);
2880  if (*fetch_area == NULL)
2881  {
2882  (void) heap_scancache_end (thread_p, &scan_cache);
2883  if (*lock != NULL_LOCK)
2884  {
2885  lock_unlock_object (thread_p, class_oid, oid_Root_class_oid, *lock, false);
2886  }
2887 
2888  error_code = ER_FAILED;
2889  goto error;
2890  }
2891 
2892  mobjs = LC_MANYOBJS_PTR_IN_COPYAREA (*fetch_area);
2893  LC_RECDES_IN_COPYAREA (*fetch_area, &recdes);
2894  obj = LC_START_ONEOBJ_PTR_IN_COPYAREA (mobjs);
2895  mobjs->num_objs = 0;
2896  offset = 0;
2897 
2898  while ((scan = heap_next (thread_p, hfid, class_oid, &oid, &recdes, &scan_cache, COPY)) == S_SUCCESS)
2899  {
2900  mobjs->num_objs++;
2901  COPY_OID (&obj->class_oid, class_oid);
2902  COPY_OID (&obj->oid, &oid);
2903  obj->flag = 0;
2904  obj->hfid = NULL_HFID;
2905  obj->length = recdes.length;
2906  obj->offset = offset;
2907  obj->operation = LC_FETCH;
2908  obj = LC_NEXT_ONEOBJ_PTR_IN_COPYAREA (obj);
2909  round_length = DB_ALIGN (recdes.length, MAX_ALIGNMENT);
2910 #if !defined(NDEBUG)
2911  /* suppress valgrind UMW error */
2912  memset (recdes.data + recdes.length, 0, MIN (round_length - recdes.length, recdes.area_size - recdes.length));
2913 #endif
2914  offset += round_length;
2915  recdes.data += round_length;
2916  recdes.area_size -= round_length + sizeof (*obj);
2917 
2918  if (mobjs->num_objs == DB_INT32_MAX)
2919  {
2920  /* Prevent overflow */
2921  break;
2922  }
2923  }
2924 
2925  if (scan != S_DOESNT_FIT || mobjs->num_objs > 0)
2926  {
2927  break;
2928  }
2929  /*
2930  * The first object does not fit into given copy area
2931  * Get a larger area
2932  */
2933 
2934  /* Get the real length of current fetch/copy area */
2935  copyarea_length = (*fetch_area)->length;
2936  locator_free_copy_area (*fetch_area);
2937 
2938  /*
2939  * If the object does not fit even when the copy area seems to be
2940  * large enough, increase the copy area by at least one page size.
2941  */
2942 
2943  if ((-recdes.length) > copyarea_length)
2944  {
2945  copyarea_length = DB_ALIGN (-recdes.length, MAX_ALIGNMENT) + sizeof (*mobjs);
2946  }
2947  else
2948  {
2949  copyarea_length += DB_PAGESIZE;
2950  }
2951  }
2952 
2953  if (scan == S_END)
2954  {
2955  /*
2956  * This is the end of the loop. Indicate the caller that no more calls
2957  * are needed by setting nobjects and nfetched to the same value.
2958  */
2959  error_code = heap_scancache_end (thread_p, &scan_cache);
2960  if (error_code != NO_ERROR)
2961  {
2962  locator_free_copy_area (*fetch_area);
2963  *fetch_area = NULL;
2964  if (*lock != NULL_LOCK)
2965  {
2966  lock_unlock_object (thread_p, class_oid, oid_Root_class_oid, *lock, false);
2967  }
2968  *nobjects = *nfetched = -1;
2969 
2970  goto error;
2971  }
2972 
2973  *nfetched += mobjs->num_objs;
2974  *nobjects = *nfetched;
2975  OID_SET_NULL (last_oid);
2976  if (*lock != NULL_LOCK)
2977  {
2978  lock_unlock_object (thread_p, class_oid, oid_Root_class_oid, *lock, false);
2979  }
2980  }
2981  else if (scan == S_ERROR)
2982  {
2983  /* There was an error.. */
2984  (void) heap_scancache_end (thread_p, &scan_cache);
2985 
2986  locator_free_copy_area (*fetch_area);
2987  *fetch_area = NULL;
2988  if (*lock != NULL_LOCK)
2989  {
2990  lock_unlock_object (thread_p, class_oid, oid_Root_class_oid, *lock, false);
2991  }
2992  *nobjects = *nfetched = -1;
2993 
2994  error_code = ER_FAILED;
2995  goto error;
2996  }
2997  else if (mobjs->num_objs != 0)
2998  {
2999  heap_scancache_end_when_scan_will_resume (thread_p, &scan_cache);
3000  /* Set the last_oid.. and the number of fetched objects */
3001  obj = LC_PRIOR_ONEOBJ_PTR_IN_COPYAREA (obj);
3002  COPY_OID (last_oid, &obj->oid);
3003  *nfetched += mobjs->num_objs;
3004  /*
3005  * If the guess on the number of objects to fetch was low, reset the
3006  * value, so that the caller continue to call us until the end of the
3007  * scan
3008  */
3009  if (*nobjects <= *nfetched)
3010  {
3011  *nobjects = *nfetched + 10;
3012  }
3013  }
3014  else
3015  {
3016  error_code = heap_scancache_end (thread_p, &scan_cache);
3017  if (error_code != NO_ERROR)
3018  {
3019  goto error;
3020  }
3021  }
3022 
3023  if (*fetch_area != NULL)
3024  {
3025  prefetch_des.mobjs = mobjs;
3026  prefetch_des.obj = &obj;
3027  prefetch_des.offset = &offset;
3028  prefetch_des.recdes = &recdes;
3029  lock_notify_isolation_incons (thread_p, locator_notify_decache, &prefetch_des);
3030  }
3031 
3032 error:
3033  return error_code;
3034 }
3035 
3036 /*
3037  * xlocator_fetch_lockset () - Lock and fetch many objects
3038  *
3039  * return: NO_ERROR if all OK, ER_ status otherwise
3040  *
3041  * lockset(in/out): Request for finding missing classes and the lock
3042  * requested objects (Set as a side effect).
3043  * fetch_area(in/out): Pointer to area where the objects are placed
3044  *
3045  */
3046 int
3047 xlocator_fetch_lockset (THREAD_ENTRY * thread_p, LC_LOCKSET * lockset, LC_COPYAREA ** fetch_area)
3048 {
3049  LC_COPYAREA_DESC prefetch_des; /* Descriptor for decache of objects related to transaction isolation level */
3050  LOCATOR_RETURN_NXOBJ nxobj; /* Description to return next obj */
3051  struct lc_lockset_reqobj *reqobjs; /* Description of requested objects */
3052  struct lc_lockset_classof *reqclasses; /* Description of classes of requested objects. */
3053  int copyarea_length;
3054  SCAN_CODE scan = S_SUCCESS;
3055  int i, j;
3056  int error_code = NO_ERROR;
3058 
3059  mvcc_snapshot = logtb_get_mvcc_snapshot (thread_p);
3060  if (mvcc_snapshot == NULL)
3061  {
3062  error_code = er_errid ();
3063  return (error_code == NO_ERROR ? ER_FAILED : error_code);
3064  }
3065 
3066  *fetch_area = NULL;
3067 
3068  reqobjs = lockset->objects;
3069  reqclasses = lockset->classes;
3070 
3071  if (lockset->num_reqobjs_processed == -1)
3072  {
3073  /*
3074  * FIRST CALL.
3075  * Initialize num of object processed.
3076  * Make sure that all classes are known and lock the classes and objects
3077  */
3078  lockset->num_reqobjs_processed = 0;
3079  lockset->num_classes_of_reqobjs_processed = 0;
3080 
3081  error_code = locator_find_lockset_missing_class_oids (thread_p, lockset);
3082  if (error_code != NO_ERROR)
3083  {
3084  goto error;
3085  }
3086  }
3087 
3088  /* Start a scan cursor for getting several classes */
3089  error_code = heap_scancache_start (thread_p, &nxobj.area_scancache, NULL, NULL, true, false, NULL);
3090  if (error_code != NO_ERROR)
3091  {
3092  lock_unlock_objects_lock_set (thread_p, lockset);
3093  goto error;
3094  }
3095  nxobj.ptr_scancache = &nxobj.area_scancache;
3096 
3097  /*
3098  * Assume that there are not any objects larger than one page. If there are
3099  * the number of pages is fixed later.
3100  */
3101 
3102  copyarea_length = DB_PAGESIZE;
3103 
3104  nxobj.mobjs = NULL;
3105  nxobj.comm_area = NULL;
3106 
3107  while (scan == S_SUCCESS
3109  || (lockset->num_reqobjs_processed < lockset->num_reqobjs)))
3110  {
3111  nxobj.comm_area = locator_allocate_copy_area_by_length (copyarea_length);
3112  if (nxobj.comm_area == NULL)
3113  {
3114  (void) heap_scancache_end (thread_p, &nxobj.area_scancache);
3115  lock_unlock_objects_lock_set (thread_p, lockset);
3116  error_code = ER_FAILED;
3117  goto error;
3118  }
3119 
3121  nxobj.obj = LC_START_ONEOBJ_PTR_IN_COPYAREA (nxobj.mobjs);
3122  LC_RECDES_IN_COPYAREA (nxobj.comm_area, &nxobj.recdes);
3123  nxobj.area_offset = 0;
3124  nxobj.mobjs->num_objs = 0;
3125 
3126  /*
3127  * CLASSES
3128  * Place the classes on the communication area, don't place those classes
3129  * with correct chns.
3130  */
3131 
3132  for (i = lockset->num_classes_of_reqobjs_processed; scan == S_SUCCESS && i < lockset->num_classes_of_reqobjs; i++)
3133  {
3134  if (OID_ISNULL (&reqclasses[i].oid))
3135  {
3137  continue;
3138  }
3139  if (OID_ISTEMP (&reqclasses[i].oid))
3140  {
3142  continue;
3143  }
3144  scan =
3145  locator_lock_and_return_object (thread_p, &nxobj, oid_Root_class_oid, &reqclasses[i].oid, reqclasses[i].chn,
3146  lockset->reqobj_class_lock, S_SELECT);
3147  if (scan == S_SUCCESS)
3148  {
3150  }
3151  else if (scan == S_DOESNT_FIT && nxobj.mobjs->num_objs == 0)
3152  {
3153  /*
3154  * The first object does not fit into given copy area
3155  * Get a larger area
3156  */
3157 
3158  /* Get the real length of current fetch/copy area */
3159 
3160  copyarea_length = nxobj.comm_area->length;
3161 
3162  /*
3163  * If the object does not fit even when the copy area seems
3164  * to be large enough, increase the copy area by at least one
3165  * page size.
3166  */
3167 
3168  if ((-nxobj.recdes.length) > copyarea_length)
3169  {
3170  copyarea_length = (DB_ALIGN (-nxobj.recdes.length, MAX_ALIGNMENT) + sizeof (*nxobj.mobjs));
3171  }
3172  else
3173  {
3174  copyarea_length += DB_PAGESIZE;
3175  }
3176 
3178  scan = S_SUCCESS;
3179  break; /* finish the for */
3180  }
3181  else if (scan != S_DOESNT_FIT && (scan == S_DOESNT_EXIST || lockset->quit_on_errors == false))
3182  {
3183  OID_SET_NULL (&reqclasses[i].oid);
3184  lockset->num_classes_of_reqobjs_processed += 1;
3185  scan = S_SUCCESS;
3186  }
3187  else
3188  {
3189  break; /* Quit on errors */
3190  }
3191  }
3192 
3193  if (i >= lockset->num_classes_of_reqobjs)
3194  {
3195  /*
3196  * DONE WITH CLASSES... NOW START WITH INSTANCES
3197  * Place the instances in the fetching area, don't place those
3198  * instances with correct chns or when they have been placed through
3199  * the class array
3200  */
3201 
3202  for (i = lockset->num_reqobjs_processed; scan == S_SUCCESS && i < lockset->num_reqobjs; i++)
3203  {
3204  if (OID_ISNULL (&reqobjs[i].oid) || OID_ISTEMP (&reqobjs[i].oid) || reqobjs[i].class_index == -1
3205  || OID_ISNULL (&reqclasses[reqobjs[i].class_index].oid))
3206  {
3207  lockset->num_reqobjs_processed += 1;
3208  continue;
3209  }
3210 
3211  if (OID_IS_ROOTOID (&reqclasses[reqobjs[i].class_index].oid))
3212  {
3213  /*
3214  * The requested object is a class. If this object is a class
3215  * of other requested objects, the object has already been
3216  * processed in the previous class iteration
3217  */
3218  for (j = 0; j < lockset->num_classes_of_reqobjs; j++)
3219  {
3220  if (OID_EQ (&reqobjs[i].oid, &reqclasses[j].oid))
3221  {
3222  /* It has already been processed */
3223  lockset->num_reqobjs_processed += 1;
3224  break;
3225  }
3226  }
3227  if (j < lockset->num_classes_of_reqobjs)
3228  {
3229  continue;
3230  }
3231  nxobj.ptr_scancache->mvcc_snapshot = NULL;
3232  }
3233  else
3234  {
3235  nxobj.ptr_scancache->mvcc_snapshot = mvcc_snapshot;
3236  }
3237 
3238  /* Now return the object */
3239  scan = locator_lock_and_return_object (thread_p, &nxobj, &reqclasses[reqobjs[i].class_index].oid,
3240  &reqobjs[i].oid, reqobjs[i].chn, lockset->reqobj_inst_lock,
3241  S_SELECT);
3242  if (scan == S_SUCCESS)
3243  {
3244  lockset->num_reqobjs_processed++;
3245  continue;
3246  }
3247 
3248  if (scan == S_DOESNT_FIT && nxobj.mobjs->num_objs == 0)
3249  {
3250  /*
3251  * The first object does not fit into given copy area
3252  * Get a larger area
3253  */
3254 
3255  /* Get the real length of current fetch/copy area */
3256 
3257  copyarea_length = nxobj.comm_area->length;
3258 
3259  /*
3260  * If the object does not fit even when the copy area
3261  * seems to be large enough, increase the copy area by at
3262  * least one page size.
3263  */
3264 
3265  if ((-nxobj.recdes.length) > copyarea_length)
3266  {
3267  copyarea_length = ((-nxobj.recdes.length) + sizeof (*nxobj.mobjs));
3268  }
3269  else
3270  {
3271  copyarea_length += DB_PAGESIZE;
3272  }
3273 
3275  scan = S_SUCCESS;
3276  break; /* finish the for */
3277  }
3278  else if (scan != S_DOESNT_FIT && (scan == S_DOESNT_EXIST || lockset->quit_on_errors == false))
3279  {
3280  OID_SET_NULL (&reqobjs[i].oid);
3281  lockset->num_reqobjs_processed += 1;
3282  scan = S_SUCCESS;
3283  }
3284  }
3285  }
3286  }
3287 
3288  /* End the scan cursor */
3289  error_code = heap_scancache_end (thread_p, &nxobj.area_scancache);
3290  if (error_code != NO_ERROR)
3291  {
3292  /* There was an error.. */
3293  if (nxobj.mobjs != NULL)
3294  {
3296  }
3297  lock_unlock_objects_lock_set (thread_p, lockset);
3298  goto error;
3299  }
3300 
3301  if (scan == S_ERROR)
3302  {
3303  /* There was an error.. */
3304  if (nxobj.mobjs != NULL)
3305  {
3307  }
3308  lock_unlock_objects_lock_set (thread_p, lockset);
3309  error_code = ER_FAILED;
3310  goto error;
3311  }
3312  else if (nxobj.mobjs != NULL && nxobj.mobjs->num_objs == 0)
3313  {
3315  }
3316  else
3317  {
3318  *fetch_area = nxobj.comm_area;
3319  }
3320 
3321  if (*fetch_area != NULL)
3322  {
3323  prefetch_des.mobjs = nxobj.mobjs;
3324  prefetch_des.obj = &nxobj.obj;
3325  prefetch_des.offset = &nxobj.area_offset;
3326  prefetch_des.recdes = &nxobj.recdes;
3327  lock_notify_isolation_incons (thread_p, locator_notify_decache, &prefetch_des);
3328  }
3329 
3330  if ((lockset->num_classes_of_reqobjs_processed >= lockset->num_classes_of_reqobjs)
3331  && lockset->num_reqobjs_processed >= lockset->num_reqobjs)
3332  {
3333  lock_unlock_objects_lock_set (thread_p, lockset);
3334  }
3335 
3336 error:
3337  return error_code;
3338 }
3339 
3340 /*
3341  * locator_all_reference_lockset () - Find all objects referenced by given object
3342  *
3343  * return: LC_LOCKSET * or NULL (in case of error)
3344  *
3345  * oid(in): The desired object.
3346  * prune_level(in): Get references up to this level. If the value is <= 0
3347  * means up to an infinite level (i.e., all references).
3348  * inst_lock(in): Indicate this lock in the request area for objects that
3349  * are instances.
3350  * class_lock(in): Indicate this lock in the request area for objects that
3351  * are classes.
3352  * quit_on_errors(in): Quit when an error is found such as cannot lock all
3353  * nested objects.
3354  *
3355  * Note: This function find all direct and indirect references from the
3356  * given object upto the given prune level in the nested graph.
3357  * The given object is also included as a reference. Thus, the
3358  * function can be seen as listing a graph of referenced/nested
3359  * objects.
3360  *
3361  * For performance reasons, the search for duplicate oids now uses an
3362  * mht (hash table). This means that we have to copy the oids into a
3363  * non-relocatable place (see lc_ht_permoids below) until the entire
3364  * graph is known.
3365  */
3366 static LC_LOCKSET *
3367 locator_all_reference_lockset (THREAD_ENTRY * thread_p, OID * oid, int prune_level, LOCK inst_lock, LOCK class_lock,
3368  bool quit_on_errors)
3369 {
3370  OID class_oid; /* The class_oid of an inst */
3371  int max_refs, ref_num; /* Max and reference number in request area */
3372  int max_stack; /* Total size of stack */
3373  int stack_actual_size; /* Actual size of stack */
3374  int level; /* The current listing level */
3375  int oid_list_size = 0; /* Oid list size */
3376  OID *oid_list = NULL; /* List of ref for one object */
3377  LC_LOCKSET *lockset = NULL; /* Building request for obj. */
3378  struct lc_lockset_reqobj *reqobjs; /* Description of one inst */
3379  struct lc_lockset_reqobj *to_reqobjs; /* Description of one inst */
3380  struct lc_lockset_classof *reqclasses; /* Description of one class */
3381  int *stack = NULL; /* The stack for the search */
3382  HEAP_SCANCACHE scan_cache; /* Scan cache used for fetching purposes */
3383  SCAN_CODE scan; /* Scan return value for an object */
3384  RECDES peek_recdes = RECDES_INITIALIZER;
3385  void *new_ptr;
3386  int i, tmp_ref_num, number;
3387  MHT_TABLE *lc_ht_permoids = NULL; /* Hash table of already found oids */
3388  HL_HEAPID heap_id = HL_NULL_HEAPID; /* Id of Heap allocator */
3390 
3391  struct ht_obj_info
3392  {
3393  OID oid;
3394  int ref_num;
3395  }; /* info stored into hash table */
3396  struct ht_obj_info *ht_obj;
3397 
3398  /* Make sure that the object exists ? */
3399  if (!heap_does_exist (thread_p, NULL, oid))
3400  {
3401  if (er_errid () != ER_INTERRUPTED)
3402  {
3404  }
3405 
3406  goto error;
3407  }
3408 
3409  /* Let's assume a number of references for allocation start purposes */
3410  max_refs = max_stack = LOCATOR_GUESS_NUM_NESTED_REFERENCES;
3411 
3412  lockset = locator_allocate_lockset (max_refs, inst_lock, class_lock, quit_on_errors);
3413  if (lockset == NULL)
3414  {
3415  goto error;
3416  }
3417 
3418  stack = (int *) malloc (sizeof (*stack) * max_stack);
3419  if (stack == NULL)
3420  {
3421  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, sizeof (*stack) * max_stack);
3422  goto error;
3423  }
3424 
3425  /* Use a hash table to speed up lockset verification when looking for cycles in the graph */
3426  lc_ht_permoids = mht_create ("Memory hash lc_allrefs", LOCATOR_GUESS_HT_SIZE, oid_hash, oid_compare_equals);
3427  if (lc_ht_permoids == NULL)
3428  {
3429  goto error;
3430  }
3431 
3432  /* Use a chunky memory manager, for fewer mallocs of small stuff */
3433  heap_id = db_create_fixed_heap (sizeof (struct ht_obj_info), LOCATOR_GUESS_HT_SIZE);
3434  if (heap_id == HL_NULL_HEAPID)
3435  {
3436  goto error;
3437  }
3438 
3439  /* Initialize the stack */
3440  stack_actual_size = 0;
3441  level = 0;
3442 
3443  reqobjs = lockset->objects;
3444  reqclasses = lockset->classes;
3445 
3446  /*
3447  * Add first object to the stack and request structure.
3448  * Indicate that the object is only on the stack. That is, the object has
3449  * not been visited.
3450  * The cache coherence number is used to hold the level of the object in
3451  * the nested graph/tree
3452  */
3453 
3454  COPY_OID (&reqobjs->oid, oid);
3455  reqobjs->class_index = -1;
3456  reqobjs->chn = level;
3457  stack[stack_actual_size++] = lockset->num_reqobjs++; /* Push */
3458  reqobjs++;
3459 
3460  mvcc_snapshot = logtb_get_mvcc_snapshot (thread_p);
3461  if (mvcc_snapshot == NULL)
3462  {
3463  goto error;
3464  }
3465 
3466  /*
3467  * Start a kind of depth-first search algorithm to find out all references
3468  * until the prune level is reached
3469  */
3470 
3471  /* Start a scan cursor for getting several classes */
3472  if (heap_scancache_start (thread_p, &scan_cache, NULL, NULL, true, false, mvcc_snapshot) != NO_ERROR)
3473  {
3474  goto error;
3475  }
3476 
3477  while (stack_actual_size > 0)
3478  {
3479  ref_num = stack[--stack_actual_size]; /* Pop */
3480 
3481  /* Get the object to find out its direct references */
3482  OID_SET_NULL (&class_oid);
3483  scan = heap_get_visible_version (thread_p, &lockset->objects[ref_num].oid, &class_oid, &peek_recdes, &scan_cache,
3484  PEEK, NULL_CHN);
3485  if (scan != S_SUCCESS)
3486  {
3487  if (scan != S_DOESNT_EXIST && (quit_on_errors == true || er_errid () == ER_INTERRUPTED))
3488  {
3489  (void) heap_scancache_end (thread_p, &scan_cache);
3490  goto error;
3491  }
3492 
3493  /* Remove the object from the list of requested objects */
3494  if (ref_num == lockset->num_reqobjs - 1)
3495  {
3496  /* Last element remove it */
3497  lockset->num_reqobjs--;
3498  reqobjs--;
3499  }
3500  else
3501  {
3502  /* Marked it as invalid */
3503  OID_SET_NULL (&lockset->objects[ref_num].oid);
3504  }
3505  er_clear ();
3506  continue;
3507  }
3508 
3509  /*
3510  * has the object been visited ?
3511  */
3512  if (lockset->objects[ref_num].class_index == -1)
3513  {
3514  /*
3515  * Object has never been visited. First time in the stack.
3516  * Find its class and marked as listed in the lockset structure
3517  */
3518 
3519  /* Is this class already stored ? */
3520 
3521  for (i = 0; i < lockset->num_classes_of_reqobjs; i++)
3522  {
3523  if (OID_EQ (&class_oid, &lockset->classes[i].oid))
3524  {
3525  break;
3526  }
3527  }
3528  if (i < lockset->num_classes_of_reqobjs)
3529  {
3530  /* Class is already in the lockset class list array */
3531  lockset->objects[ref_num].class_index = i;
3532  }
3533  else
3534  {
3535  /*
3536  * Class is not in the lockset class list array.
3537  * Make sure that this is a valid class
3538  */
3539  if (!heap_does_exist (thread_p, oid_Root_class_oid, &class_oid))
3540  {
3541  /* Remove the object from the list of requested objects */
3542  if (ref_num == lockset->num_reqobjs - 1)
3543  {
3544  /* Last element remove it */
3545  lockset->num_reqobjs--;
3546  reqobjs--;
3547  }
3548  else
3549  {
3550  /* Marked it as invalid */
3551  OID_SET_NULL (&lockset->objects[ref_num].oid);
3552  }
3553  continue;
3554  }
3555  COPY_OID (&reqclasses->oid, &class_oid);
3556  reqclasses->chn = NULL_CHN; /* Note that this is a level */
3557  lockset->objects[ref_num].class_index = lockset->num_classes_of_reqobjs;
3558  lockset->num_classes_of_reqobjs++;
3559  reqclasses++;
3560  }
3561  }
3562 
3563  /* Level for the directly referenced objects */
3564 
3565  level = lockset->objects[ref_num].chn + 1;
3566  if (prune_level >= 0 && level > prune_level)
3567  {
3568  continue;
3569  }
3570 
3571  /*
3572  * Find all direct references from the given object
3573  */
3574  if (OID_IS_ROOTOID (&class_oid))
3575  {
3576  continue;
3577  }
3578  number =
3579  heap_get_referenced_by (thread_p, &class_oid, &lockset->objects[ref_num].oid, &peek_recdes, &oid_list_size,
3580  &oid_list);
3581  if (number <= 0)
3582  {
3583  continue;
3584  }
3585 
3586  /*
3587  * Add the above references to the stack if these objects have not
3588  * been alredy visited or if their current level is smaller than their
3589  * visited level
3590  */
3591 
3592  if (oid_list == NULL || number <= 0)
3593  {
3594  continue;
3595  }
3596  for (i = 0; i < number; i++)
3597  {
3598  if (OID_ISNULL (&oid_list[i]))
3599  {
3600  continue;
3601  }
3602 
3603  ht_obj = (struct ht_obj_info *) mht_get (lc_ht_permoids, &oid_list[i]);
3604  if (ht_obj != NULL)
3605  {
3606  tmp_ref_num = ht_obj->ref_num;
3607  if (lockset->objects[tmp_ref_num].chn > level)
3608  {
3609  /*
3610  * Re-visit the object again since some of its
3611  * references may have been pruned
3612  */
3613  lockset->objects[tmp_ref_num].chn = level;
3614  /* push */
3615  stack[stack_actual_size++] = tmp_ref_num;
3616  }
3617  }
3618  else
3619  {
3620  tmp_ref_num = lockset->num_reqobjs;
3621  /*
3622  * Push the object onto the stack.
3623  * Make sure that we have area in the stack and the
3624  * request area
3625  */
3626  if (stack_actual_size >= max_stack)
3627  {
3628  /* Expand the stack */
3630  {
3631  max_stack += number;
3632  }
3633  else
3634  {
3636  }
3637  new_ptr = realloc (stack, sizeof (*stack) * max_stack);
3638  if (new_ptr == NULL)
3639  {
3641  sizeof (*stack) * max_stack);
3642  if (quit_on_errors == false)
3643  {
3644  break;
3645  }
3646  (void) heap_scancache_end (thread_p, &scan_cache);
3647  goto error;
3648  }
3649  stack = (int *) new_ptr;
3650  }
3651 
3652  if ((lockset->num_reqobjs + 1) > max_refs)
3653  {
3655  {
3656  max_refs += number;
3657  }
3658  else
3659  {
3661  }
3662  new_ptr = locator_reallocate_lockset (lockset, max_refs);
3663  if (new_ptr == NULL)
3664  {
3665  if (quit_on_errors == false)
3666  {
3667  break;
3668  }
3669  (void) heap_scancache_end (thread_p, &scan_cache);
3670  goto error;
3671  }
3672  lockset = (LC_LOCKSET *) new_ptr;
3673  /* Find the new locations since the structure was reallocated */
3674  reqobjs = lockset->objects + lockset->num_reqobjs;
3675  reqclasses = lockset->classes + lockset->num_classes_of_reqobjs;
3676  }
3677 
3678  /* Put object in the hash table */
3679  ht_obj = (struct ht_obj_info *) db_fixed_alloc (heap_id, sizeof (*ht_obj));
3680  if (ht_obj == NULL)
3681  {
3682  if (quit_on_errors == false)
3683  {
3684  break;
3685  }
3686  (void) heap_scancache_end (thread_p, &scan_cache);
3687  goto error;
3688  }
3689  COPY_OID (&ht_obj->oid, &oid_list[i]);
3690  ht_obj->ref_num = tmp_ref_num;
3691 
3692  if (mht_put (lc_ht_permoids, &ht_obj->oid, ht_obj) != ht_obj)
3693  {
3694  if (quit_on_errors == false)
3695  {
3696  break;
3697  }
3698  (void) heap_scancache_end (thread_p, &scan_cache);
3699  goto error;
3700  }
3701 
3702  /*
3703  * Push the object
3704  * Indicate that the object is only on the stack. That is,
3705  * the object has not been visited.
3706  * The cache coherence number is used to hold the level of
3707  * the object in the nested graph/tree
3708  */
3709  COPY_OID (&reqobjs->oid, &oid_list[i]);
3710  reqobjs->class_index = -1;
3711  reqobjs->chn = level;
3712  /* Push */
3713  stack[stack_actual_size++] = lockset->num_reqobjs++;
3714  reqobjs++;
3715  }
3716  }
3717  }
3718 
3719  /* Cleanup */
3720  if (oid_list != NULL)
3721  {
3722  free_and_init (oid_list);
3723  }
3724  free_and_init (stack);
3725  (void) heap_scancache_end (thread_p, &scan_cache);
3726  db_destroy_fixed_heap (heap_id);
3727  mht_destroy (lc_ht_permoids);
3728 
3729  /*
3730  * Set the cache coherence numbers as unknown (these are the ones of the
3731  * client workspace) and compact the array of requested objects. Note that
3732  * before we have used the chn as the level, so it needs to be reset.
3733  */
3734 
3735  number = 0;
3736  to_reqobjs = reqobjs = lockset->objects;
3737  for (i = 0; i < lockset->num_reqobjs; i++)
3738  {
3739  if (!OID_ISNULL (&reqobjs->oid))
3740  {
3741  /* Move it to */
3742  if (to_reqobjs != reqobjs)
3743  {
3744  memcpy (to_reqobjs, reqobjs, sizeof (*reqobjs));
3745  }
3746  to_reqobjs->chn = NULL_CHN;
3747  to_reqobjs++;
3748  }
3749  else
3750  {
3751  number++;
3752  }
3753  reqobjs++;
3754  }
3755  lockset->num_reqobjs -= number;
3756 
3757  for (i = 0; i < lockset->num_classes_of_reqobjs; i++)
3758  {
3759  lockset->classes[i].chn = CHN_UNKNOWN_ATCLIENT;
3760  }
3761 
3762  return lockset;
3763 
3764 error:
3765  if (oid_list != NULL)
3766  {
3767  free_and_init (oid_list);
3768  }
3769  if (lc_ht_permoids != NULL)
3770  {
3771  mht_destroy (lc_ht_permoids);
3772  lc_ht_permoids = NULL;
3773  }
3774  if (stack != NULL)
3775  {
3776  free_and_init (stack);
3777  }
3778  if (lockset != NULL)
3779  {
3780  locator_free_lockset (lockset);
3781  lockset = NULL;
3782  }
3783  if (heap_id != HL_NULL_HEAPID)
3784  {
3785  db_destroy_fixed_heap (heap_id);
3786  }
3787 
3788  return NULL;
3789 }
3790 
3791 /*
3792  * xlocator_fetch_all_reference_lockset () - Lock and fetch the requested objects and its
3793  * direct and indirect references
3794  *
3795  * return: NO_ERROR if all OK, ER_ status otherwise
3796  *
3797  * oid(in): The desired object in the root of nested references
3798  * chn(in): Cache coherence number of desired object
3799  * class_oid(in): Class identifier of the desired object
3800  * class_chn(in): Cache coherence number of the class of the desired object
3801  * lock(in): Lock to acquire on the desired object and its references
3802  * quit_on_errors(in): Wheater to continue in case an error, such as an
3803  * object can be locked
3804  * prune_level(in): Get references upto this level. If the value is <= 0
3805  * means upto an infonite level (i.e., all references).
3806  * lockset(in/out): Request for finding the all references. This is set to
3807  * NULL when the references are unknown.
3808  * fetch_area(in/out): Pointer to area where the objects are placed (Set as a
3809  * side effect)
3810  *
3811  */
3812 int
3813 xlocator_fetch_all_reference_lockset (THREAD_ENTRY * thread_p, OID * oid, int chn, OID * class_oid, int class_chn,
3814  LOCK lock, int quit_on_errors, int prune_level, LC_LOCKSET ** lockset,
3815  LC_COPYAREA ** fetch_area)
3816 {
3817  int i;
3818  LOCK instance_lock;
3819 
3820  /* Find all the references */
3821  if (lock <= S_LOCK)
3822  {
3823  instance_lock = IS_LOCK;
3824  }
3825  else
3826  {
3827  instance_lock = IX_LOCK;
3828  }
3829  *lockset = locator_all_reference_lockset (thread_p, oid, prune_level, lock, instance_lock, quit_on_errors != 0);
3830  if (*lockset == NULL)
3831  {
3832  return ER_FAILED;
3833  }
3834 
3835  /*
3836  * Set the known cache coherence numbers of the desired object and its
3837  * class
3838  */
3839 
3840  if (chn != NULL_CHN)
3841  {
3842  for (i = 0; i < (*lockset)->num_reqobjs; i++)
3843  {
3844  if (OID_EQ (oid, &(*lockset)->objects[i].oid))
3845  {
3846  (*lockset)->objects[i].chn = chn;
3847  break;
3848  }
3849  }
3850  }
3851 
3852  if (class_oid != NULL && class_chn != NULL_CHN)
3853  {
3854  for (i = 0; i < (*lockset)->num_classes_of_reqobjs; i++)
3855  {
3856  if (OID_EQ (class_oid, &(*lockset)->classes[i].oid))
3857  {
3858  (*lockset)->classes[i].chn = class_chn;
3859  break;
3860  }
3861  }
3862  }
3863 
3864  /* Get the first batch of classes and objects */
3865  return xlocator_fetch_lockset (thread_p, *lockset, fetch_area);
3866 }
3867 
3868 /*
3869  * xlocator_does_exist () - Does object exist? if it does prefetch it
3870  *
3871  * return: Either of (LC_EXIST, LC_DOESNOT_EXIST, LC_ERROR)
3872  *
3873  * oid(in): Object identifier of desired object
3874  * chn(in): Cache coherence number of object
3875  * lock(in): Lock to acquire for the object
3876  * fetch_type(in): fetch type
3877  * class_oid(in): Class identifier of the object
3878  * class_chn(in): Cache coherence number of the class of the object
3879  * need_fetching(in):
3880  * prefetching(in): true if prefetching of some of the object neighbors is
3881  * desired.
3882  * fetch_area(in/out): Pointer to area where the objects are placed
3883  (set to point to fetching area)
3884  *
3885  * Note:This function checks if the desired object exist. An error is
3886  * not set if the object does not exist. If the object exists and
3887  * prefetching is desired, prefetching is done for the object and
3888  * some of its neighbors.
3889  */
3890 int
3891 xlocator_does_exist (THREAD_ENTRY * thread_p, OID * oid, int chn, LOCK lock, LC_FETCH_VERSION_TYPE fetch_version_type,
3892  OID * class_oid, int class_chn, int need_fetching, int prefetching, LC_COPYAREA ** fetch_area)
3893 {
3894  OID tmp_oid;
3895  SCAN_CODE scan_code = S_SUCCESS;
3896 
3897  if (need_fetching && fetch_area != NULL)
3898  {
3899  *fetch_area = NULL;
3900  }
3901 
3902  if (class_oid == NULL)
3903  {
3904  class_oid = &tmp_oid;
3905  OID_SET_NULL (class_oid);
3906  }
3907 
3908  /* Quick fix: we need to check if OID is valid - meaning that page is still valid. This code is going to be
3909  * removed with one of the refactoring issues anyway.
3910  */
3911  if (HEAP_ISVALID_OID (thread_p, oid) != DISK_VALID)
3912  {
3913  return LC_DOESNOT_EXIST;
3914  }
3915 
3916  /* Prefetch the object if that operation is desirable */
3917  if (need_fetching && fetch_area != NULL)
3918  {
3919  int ret = xlocator_fetch (thread_p, oid, NULL_CHN, lock, fetch_version_type, fetch_version_type,
3920  class_oid, class_chn, prefetching, fetch_area);
3921  if (ret == ER_FAILED)
3922  {
3923  ASSERT_ERROR ();
3924  if (lock != NULL_LOCK)
3925  {
3926  lock_unlock_object (thread_p, oid, class_oid, lock, false);
3927  }
3928  return LC_ERROR;
3929  }
3930  else if (ret != NO_ERROR)
3931  {
3932  return LC_DOESNOT_EXIST;
3933  }
3934 
3935  /* success -> fall through */
3936  }
3937  else
3938  {
3939  if (lock != NULL_LOCK)
3940  {
3941  /* try to aquire requested lock or the appropriate one; it will be decided according to class type */
3942  SCAN_OPERATION_TYPE op_type;
3943  HEAP_SCANCACHE scan_cache;
3944 
3945  op_type = locator_decide_operation_type (lock, fetch_version_type);
3946 
3947  (void) heap_scancache_quick_start (&scan_cache);
3948 
3949  scan_code = locator_get_object (thread_p, oid, class_oid, NULL, &scan_cache, op_type, lock, PEEK, NULL_CHN);
3950  heap_scancache_end (thread_p, &scan_cache);
3951  if (scan_code == S_ERROR)
3952  {
3953  ASSERT_ERROR ();
3954  return LC_ERROR;
3955  }
3956  else if (scan_code != S_SUCCESS)
3957  {
3958  return LC_DOESNOT_EXIST;
3959  }
3960  }
3961  else if (!heap_does_exist (thread_p, class_oid, oid))
3962  {
3963  /* object doesn't exist */
3964  return LC_DOESNOT_EXIST;
3965  }
3966 
3967  /* success -> fall through */
3968  }
3969 
3970  /* Success */
3971  return LC_EXIST;
3972 }
3973 
3974 /*
3975  * locator_start_force_scan_cache () -
3976  *
3977  * return: NO_ERROR if all OK, ER_ status otherwise
3978  *
3979  * scan_cache(in/out):
3980  * hfid(in):
3981  * class_oid(in):
3982  * op_type(in):
3983  */
3984 int
3986  const OID * class_oid, int op_type)
3987 {
3988  return heap_scancache_start_modify (thread_p, scan_cache, hfid, class_oid, op_type, NULL);
3989 }
3990 
3991 /*
3992  * locator_end_force_scan_cache () -
3993  *
3994  * return:
3995  *
3996  * scan_cache(in):
3997  */
3998 void
4000 {
4001  heap_scancache_end_modify (thread_p, scan_cache);
4002 }
4003 
4004 /*
4005  * locator_check_foreign_key () -
4006  *
4007  * return: NO_ERROR if all OK, ER_ status otherwise
4008  *
4009  * hfid(in):
4010  * class_oid(in):
4011  * inst_oid(in):
4012  * recdes(in):
4013  * new_recdes(in):
4014  * is_cached(in):
4015  * copyarea(in):
4016  */
4017 static int
4018 locator_check_foreign_key (THREAD_ENTRY * thread_p, HFID * hfid, OID * class_oid, OID * inst_oid, RECDES * recdes,
4019  RECDES * new_recdes, bool * is_cached, LC_COPYAREA ** copyarea)
4020 {
4021  int num_found, i;
4022  HEAP_CACHE_ATTRINFO index_attrinfo;
4023  HEAP_IDX_ELEMENTS_INFO idx_info;
4024  BTID btid, local_btid;
4025  DB_VALUE *key_dbvalue;
4026  DB_VALUE dbvalue;
4027  char buf[DBVAL_BUFSIZE + MAX_ALIGNMENT], *aligned_buf;
4028  OR_INDEX *index;
4029  OID unique_oid;
4030  OID part_oid;
4031  HFID class_hfid;
4032  bool has_null;
4033  int error_code = NO_ERROR;
4034  PRUNING_CONTEXT pcontext;
4035  bool clear_pcontext = false;
4036  OR_CLASSREP *classrepr = NULL;
4037  int classrepr_cacheindex = -1;
4038  BTREE_SEARCH ret;
4039 
4040  db_make_null (&dbvalue);
4041 
4042  aligned_buf = PTR_ALIGN (buf, MAX_ALIGNMENT);
4043 
4044  num_found = heap_attrinfo_start_with_index (thread_p, class_oid, NULL, &index_attrinfo, &idx_info);
4045  if (num_found <= 0)
4046  {
4047  return error_code;
4048  }
4049 
4050  if (idx_info.has_single_col)
4051  {
4052  error_code = heap_attrinfo_read_dbvalues (thread_p, inst_oid, recdes, NULL, &index_attrinfo);
4053  if (error_code != NO_ERROR)
4054  {
4055  goto error;
4056  }
4057  }
4058 
4059  for (i = 0; i < idx_info.num_btids; i++)
4060  {
4061  index = &(index_attrinfo.last_classrepr->indexes[i]);
4062  if (index->type != BTREE_FOREIGN_KEY)
4063  {
4064  continue;
4065  }
4066 
4067  /* must be updated when key_prefix_length will be added for FK and PK */
4068  key_dbvalue =
4069  heap_attrvalue_get_key (thread_p, i, &index_attrinfo, recdes, &btid, &dbvalue, aligned_buf, NULL, NULL);
4070  if (key_dbvalue == NULL)
4071  {
4072  error_code = ER_FAILED;
4073  goto error;
4074  }
4075 
4076  /* SQL standard defines as follows:
4077  * If no <match type> was specified then, for each row R1 of the referencing table,
4078  * either at least one of the values of the referencing columns in R1 shall be a null value,
4079  * or the value of each referencing column in R1 shall be equal to the value of
4080  * the corresponding referenced column in some row of the referenced table.
4081  * Please notice that we don't currently support <match type>.
4082  */
4083  if (index->n_atts > 1)
4084  {
4085 
4086  has_null = btree_multicol_key_has_null (key_dbvalue);
4087  }
4088  else
4089  {
4090  has_null = DB_IS_NULL (key_dbvalue);
4091  }
4092 
4093  if (!has_null)
4094  {
4095  /* get class representation to find partition information */
4096  classrepr =
4097  heap_classrepr_get (thread_p, &index->fk->ref_class_oid, NULL, NULL_REPRID, &classrepr_cacheindex);
4098  if (classrepr == NULL)
4099  {
4100  error_code = ER_FAILED;
4101  goto error;
4102  }
4103  if (classrepr->has_partition_info > 0)
4104  {
4105  (void) partition_init_pruning_context (&pcontext);
4106  clear_pcontext = true;
4107  error_code =
4108  partition_load_pruning_context (thread_p, &index->fk->ref_class_oid, DB_PARTITIONED_CLASS, &pcontext);
4109  if (error_code != NO_ERROR)
4110  {
4111  goto error;
4112  }
4113  }
4114 
4115  BTID_COPY (&local_btid, &index->fk->ref_class_pk_btid);
4116  COPY_OID (&part_oid, &index->fk->ref_class_oid);
4117 
4118  if (classrepr->has_partition_info > 0 && pcontext.partitions != NULL)
4119  {
4120  error_code = partition_prune_unique_btid (&pcontext, key_dbvalue, &part_oid, &class_hfid, &local_btid);
4121  if (error_code != NO_ERROR)
4122  {
4123  goto error;
4124  }
4125  }
4126  ret =
4127  xbtree_find_unique (thread_p, &local_btid, S_SELECT_WITH_LOCK, key_dbvalue, &part_oid, &unique_oid, true);
4128  if (ret == BTREE_KEY_NOTFOUND)
4129  {
4130  char *val_print = NULL;
4131 
4132  val_print = pr_valstring (key_dbvalue);
4134  (val_print ? val_print : "unknown value"));
4135  error_code = ER_FK_INVALID;
4136  if (val_print)
4137  {
4138  db_private_free (thread_p, val_print);
4139  }
4140 
4141  if (key_dbvalue == &dbvalue)
4142  {
4143  pr_clear_value (&dbvalue);
4144  }
4145 
4146  if (LOG_CHECK_LOG_APPLIER (thread_p))
4147  {
4148  continue;
4149  }
4150 
4151  goto error;
4152  }
4153  else if (ret == BTREE_ERROR_OCCURRED)
4154  {
4155  ASSERT_ERROR_AND_SET (error_code);
4156  goto error;
4157  }
4158  assert (ret == BTREE_KEY_FOUND);
4159  /* TODO: For read committed... Do we need to keep the lock? */
4160  }
4161 
4162  if (key_dbvalue == &dbvalue)
4163  {
4164  pr_clear_value (&dbvalue);
4165  }
4166  }
4167 
4168 error:
4169  if (clear_pcontext == true)
4170  {
4171  partition_clear_pruning_context (&pcontext);
4172  }
4173  if (classrepr != NULL)
4174  {
4175  heap_classrepr_free_and_init (classrepr, &classrepr_cacheindex);
4176  }
4177  heap_attrinfo_end (thread_p, &index_attrinfo);
4178  return error_code;
4179 }
4180 
4181 /*
4182  * locator_check_primary_key_delete () -
4183  *
4184  * return: NO_ERROR if all OK, ER_ status otherwise
4185  *
4186  * fkref(in):
4187  * key(in):
4188  */
4189 static int
4191 {
4192  OR_FOREIGN_KEY *fkref;
4193  int oid_cnt, force_count, i;
4194  RECDES recdes;
4195  HEAP_SCANCACHE scan_cache;
4196  HFID hfid;
4197  BTREE_SCAN bt_scan;
4198  INDX_SCAN_ID isid;
4200  bool is_upd_scan_init;
4201  int error_code = NO_ERROR;
4202  HEAP_CACHE_ATTRINFO attr_info;
4203  DB_VALUE null_value;
4204  ATTR_ID *attr_ids = NULL;
4205  int num_attrs = 0;
4206  int k;
4207  int *keys_prefix_length = NULL;
4209  OID found_oid;
4210  BTREE_ISCAN_OID_LIST oid_list;
4211 
4212  oid_list.oidp = NULL;
4213 
4214  mvcc_snapshot = logtb_get_mvcc_snapshot (thread_p);
4215  if (mvcc_snapshot == NULL)
4216  {
4217  error_code = er_errid ();
4218  return (error_code == NO_ERROR ? ER_FAILED : error_code);
4219  }
4220 
4221  db_make_null (&null_value);
4222  db_make_null (&key_val_range.key1);
4223  db_make_null (&key_val_range.key2);
4224 
4225  heap_attrinfo_start (thread_p, NULL, 0, NULL, &attr_info);
4226 
4227  for (fkref = index->fk; fkref != NULL; fkref = fkref->next)
4228  {
4230  {
4231  if (!LOG_CHECK_LOG_APPLIER (thread_p))
4232  {
4233  error_code = btree_find_foreign_key (thread_p, &fkref->self_btid, key, &fkref->self_oid, &found_oid);
4234  if (error_code != NO_ERROR)
4235  {
4236  assert (er_errid () != NO_ERROR);
4237  goto error3;
4238  }
4239  if (!OID_ISNULL (&found_oid))
4240  {
4242  error_code = ER_FK_RESTRICT;
4243  /* Unlock child object. */
4244  lock_unlock_object_donot_move_to_non2pl (thread_p, &found_oid, &fkref->self_oid, S_LOCK);
4245  goto error3;
4246  }
4247  }
4248  }
4249  else if (fkref->del_action == SM_FOREIGN_KEY_CASCADE || fkref->del_action == SM_FOREIGN_KEY_SET_NULL)
4250  {
4251  if (attr_ids)
4252  {
4253  db_private_free_and_init (thread_p, attr_ids);
4254  }
4255  error_code =
4256  heap_get_indexinfo_of_btid (thread_p, &fkref->self_oid, &fkref->self_btid, NULL, &num_attrs, &attr_ids,
4257  &keys_prefix_length, NULL, NULL);
4258  if (error_code != NO_ERROR)
4259  {
4260  goto error3;
4261  }
4262  assert (num_attrs == index->n_atts);
4263  /* We might check for foreign key and schema consistency problems here but we rely on the schema manager to
4264  * prevent inconsistency; see do_check_fk_constraints() for details */
4265 
4266  error_code = heap_get_class_info (thread_p, &fkref->self_oid, &hfid, NULL, NULL);
4267  if (error_code != NO_ERROR)
4268  {
4269  goto error3;
4270  }
4271 
4272  if (oid_list.oidp == NULL)
4273  {
4274  oid_list.oidp = (OID *) db_private_alloc (thread_p, ISCAN_OID_BUFFER_CAPACITY);
4275  if (oid_list.oidp == NULL)
4276  {
4277  error_code = ER_OUT_OF_VIRTUAL_MEMORY;
4279  goto error3;
4280  }
4281  oid_list.oid_cnt = 0;
4283  oid_list.max_oid_cnt = oid_list.capacity;
4284  oid_list.next_list = NULL;
4285  }
4286 
4287  error_code = heap_scancache_start (thread_p, &isid.scan_cache, &hfid, &fkref->self_oid, true, true, NULL);
4288  if (error_code != NO_ERROR)
4289  {
4290  ASSERT_ERROR ();
4291  goto error3;
4292  }
4293  scan_init_index_scan (&isid, &oid_list, mvcc_snapshot);
4294  is_upd_scan_init = false;
4295  pr_clone_value (key, &key_val_range.key1);
4296  pr_clone_value (key, &key_val_range.key2);
4297  key_val_range.range = GE_LE;
4298  key_val_range.num_index_term = 0;
4299  BTREE_INIT_SCAN (&bt_scan);
4300 
4301  do
4302  {
4303  bool lob_exist = false;
4304 
4305  error_code =
4306  btree_prepare_bts (thread_p, &bt_scan, &fkref->self_btid, &isid, &key_val_range, NULL, &fkref->self_oid,
4307  NULL, NULL, false, NULL);
4308  if (error_code != NO_ERROR)
4309  {
4310  assert (er_errid () != NO_ERROR);
4311  goto error2;
4312  }
4313  error_code = btree_range_scan (thread_p, &bt_scan, btree_range_scan_select_visible_oids);
4314  if (error_code != NO_ERROR)
4315  {
4316  assert (er_errid () != NO_ERROR);
4317  goto error2;
4318  }
4319  oid_cnt = bt_scan.n_oids_read_last_iteration;
4320 
4321  if (oid_cnt < 0)
4322  {
4323  assert (false);
4324  error_code = ER_FAILED;
4325  goto error2;
4326  }
4327  else if (oid_cnt == 0)
4328  {
4329  break;
4330  }
4331 
4332  if (is_upd_scan_init == false)
4333  {
4334  int op_type = -1;
4335  if (fkref->del_action == SM_FOREIGN_KEY_CASCADE)
4336  {
4337  op_type = SINGLE_ROW_DELETE;
4338  }
4339  else if (fkref->del_action == SM_FOREIGN_KEY_SET_NULL)
4340  {
4341  op_type = SINGLE_ROW_UPDATE;
4342  }
4343  else
4344  {
4345  assert (false);
4346  }
4347  error_code =
4348  heap_scancache_start_modify (thread_p, &scan_cache, &hfid, &fkref->self_oid, op_type, NULL);
4349  if (error_code != NO_ERROR)
4350  {
4351  goto error2;
4352  }
4353  is_upd_scan_init = true;
4355  {
4356  HEAP_ATTRVALUE *value;
4357  error_code = heap_attrinfo_start (thread_p, &fkref->self_oid, -1, NULL, &attr_info);
4358  if (error_code != NO_ERROR)
4359  {
4360  goto error1;
4361  }
4362 
4363  for (i = 0; i < attr_info.num_values; i++)
4364  {
4365  value = &attr_info.values[i];
4366  if (value->last_attrepr->type == DB_TYPE_BLOB || value->last_attrepr->type == DB_TYPE_CLOB)
4367  {
4368  lob_exist = true;
4369  break;
4370  }
4371  }
4372  }
4373  }
4374 
4375  for (i = 0; i < oid_cnt; i++)
4376  {
4377  OID *oid_ptr = &(oid_list.oidp[i]);
4378  SCAN_CODE scan_code = S_SUCCESS;
4379  recdes.data = NULL;
4380  /* TO DO - handle reevaluation */
4381 
4382  scan_code = locator_lock_and_get_object (thread_p, oid_ptr, &fkref->self_oid, &recdes, &scan_cache,
4384  if (scan_code != S_SUCCESS)
4385  {
4386  if (scan_code == S_DOESNT_EXIST && er_errid () != ER_HEAP_UNKNOWN_OBJECT)
4387  {
4389  oid_ptr->pageid, oid_ptr->slotid);
4390  }
4391 
4392  if (er_errid () == ER_HEAP_UNKNOWN_OBJECT)
4393  {
4394  er_log_debug (ARG_FILE_LINE, "locator_update_force: unknown oid ( %d|%d|%d )\n",
4395  oid_ptr->pageid, oid_ptr->slotid, oid_ptr->volid);
4396  continue;
4397  }
4398 
4399  error_code = er_errid ();
4400  error_code = (error_code == NO_ERROR ? ER_FAILED : error_code);
4401  goto error1;
4402  }
4403 
4404  if (fkref->del_action == SM_FOREIGN_KEY_CASCADE)
4405  {
4406  if (lob_exist)
4407  {
4408  error_code = locator_delete_lob_force (thread_p, &fkref->self_oid, oid_ptr, NULL);
4409  }
4410  if (error_code != NO_ERROR)
4411  {
4412  goto error1;
4413  }
4414 
4415  /* oid already locked at locator_lock_and_get_object */
4416  error_code =
4417  locator_delete_force (thread_p, &hfid, oid_ptr, true, SINGLE_ROW_DELETE, &scan_cache,
4418  &force_count, NULL, false);
4419  if (error_code == ER_MVCC_NOT_SATISFIED_REEVALUATION)
4420  {
4421  /* skip foreign keys that were already deleted. For example the "cross type" reference */
4422  error_code = NO_ERROR;
4423  }
4424  else if (error_code != NO_ERROR)
4425  {
4427  goto error1;
4428  }
4429  }
4430  else if (fkref->del_action == SM_FOREIGN_KEY_SET_NULL)
4431  {
4432  error_code = heap_attrinfo_clear_dbvalues (&attr_info);
4433  if (error_code != NO_ERROR)
4434  {
4435  goto error1;
4436  }
4437  for (k = 0; k < num_attrs; ++k)
4438  {
4439  error_code = heap_attrinfo_set (oid_ptr, attr_ids[k], &null_value, &attr_info);
4440  if (error_code != NO_ERROR)
4441  {
4442  goto error1;
4443  }
4444  }
4445  /* oid already locked at locator_lock_and_get_object */
4446  error_code =
4447  locator_attribute_info_force (thread_p, &hfid, oid_ptr, &attr_info, attr_ids, index->n_atts,
4448  LC_FLUSH_UPDATE, SINGLE_ROW_UPDATE, &scan_cache, &force_count,
4450  NULL, NULL, UPDATE_INPLACE_NONE, &recdes, false);
4451  if (error_code != NO_ERROR)
4452  {
4453  if (error_code == ER_MVCC_NOT_SATISFIED_REEVALUATION)
4454  {
4455  error_code = NO_ERROR;
4456  }
4457  else
4458  {
4459  goto error1;
4460  }
4461  }
4462  }
4463  else
4464  {
4465  assert (false);
4466  }
4467  }
4468  }
4469  while (!BTREE_END_OF_SCAN (&bt_scan));
4470 
4471  if (is_upd_scan_init)
4472  {
4473  heap_scancache_end_modify (thread_p, &scan_cache);
4475  {
4476  heap_attrinfo_end (thread_p, &attr_info);
4477  }
4478  }
4479 
4480  btree_scan_clear_key (&bt_scan);
4481  pr_clear_value (&key_val_range.key1);
4482  pr_clear_value (&key_val_range.key2);
4483  error_code = heap_scancache_end (thread_p, &isid.scan_cache);
4484  if (error_code != NO_ERROR)
4485  {
4486  error_code = NO_ERROR;
4487  goto end;
4488  }
4489  }
4490  else
4491  {
4492  assert (false);
4493  }
4494  }
4495 
4496 end:
4497  if (oid_list.oidp)
4498  {
4499  db_private_free_and_init (thread_p, oid_list.oidp);
4500  }
4501  if (attr_ids)
4502  {
4503  db_private_free_and_init (thread_p, attr_ids);
4504  }
4505  if (keys_prefix_length)
4506  {
4507  db_private_free_and_init (thread_p, keys_prefix_length);
4508  }
4509 
4510  return error_code;
4511 
4512 error1:
4513  heap_scancache_end_modify (thread_p, &scan_cache);
4514 
4515 error2:
4516  btree_scan_clear_key (&bt_scan);
4517  pr_clear_value (&key_val_range.key1);
4518  pr_clear_value (&key_val_range.key2);
4519  (void) heap_scancache_end (thread_p, &isid.scan_cache);
4520 
4521 error3:
4522  heap_attrinfo_end (thread_p, &attr_info);
4523 
4524  goto end;
4525 }
4526 
4527 /*
4528  * locator_check_primary_key_update () -
4529  *
4530  * return: NO_ERROR if all OK, ER_ status otherwise
4531  *
4532  * index(in):
4533  * key(in):
4534  */
4535 static int
4537 {
4538  OR_FOREIGN_KEY *fkref;
4539  int oid_cnt, force_count, i;
4540  RECDES recdes;
4541  HEAP_SCANCACHE scan_cache;
4542  HFID hfid;
4543  BTREE_SCAN bt_scan;
4544  INDX_SCAN_ID isid;
4546  bool is_upd_scan_init;
4547  int error_code = NO_ERROR;
4548  HEAP_CACHE_ATTRINFO attr_info;
4549  DB_VALUE null_value;
4550  ATTR_ID *attr_ids = NULL;
4551  int num_attrs = 0;
4552  int k;
4553  int *keys_prefix_length = NULL;
4555  OID found_oid;
4556  BTREE_ISCAN_OID_LIST oid_list;
4557 
4558  oid_list.oidp = NULL;
4559 
4560  mvcc_snapshot = logtb_get_mvcc_snapshot (thread_p);
4561  if (mvcc_snapshot == NULL)
4562  {
4563  error_code = er_errid ();
4564  return (error_code == NO_ERROR ? ER_FAILED : error_code);
4565  }
4566 
4567  db_make_null (&key_val_range.key1);
4568  db_make_null (&key_val_range.key2);
4569  db_make_null (&null_value);
4570  heap_attrinfo_start (thread_p, NULL, 0, NULL, &attr_info);
4571 
4572  for (fkref = index->fk; fkref != NULL; fkref = fkref->next)
4573  {
4575  {
4576  if (!LOG_CHECK_LOG_APPLIER (thread_p))
4577  {
4578  error_code = btree_find_foreign_key (thread_p, &fkref->self_btid, key, &fkref->self_oid, &found_oid);
4579  if (error_code != NO_ERROR)
4580  {
4581  assert (er_errid () != NO_ERROR);
4582  goto error3;
4583  }
4584  if (!OID_ISNULL (&found_oid))
4585  {
4587  error_code = ER_FK_RESTRICT;
4588  /* Unlock child object. */
4589  lock_unlock_object_donot_move_to_non2pl (thread_p, &found_oid, &fkref->self_oid, S_LOCK);
4590  goto error3;
4591  }
4592  }
4593  }
4594  else if (fkref->upd_action == SM_FOREIGN_KEY_CASCADE || fkref->upd_action == SM_FOREIGN_KEY_SET_NULL)
4595  {
4596  if (attr_ids)
4597  {
4598  db_private_free_and_init (thread_p, attr_ids);
4599  }
4600  error_code =
4601  heap_get_indexinfo_of_btid (thread_p, &fkref->self_oid, &fkref->self_btid, NULL, &num_attrs, &attr_ids,
4602  &keys_prefix_length, NULL, NULL);
4603  if (error_code != NO_ERROR)
4604  {
4605  goto error3;
4606  }
4607  assert (num_attrs == index->n_atts);
4608  /* We might check for foreign key and schema consistency problems here but we rely on the schema manager to
4609  * prevent inconsistency; see do_check_fk_constraints() for details */
4610 
4611  error_code = heap_get_class_info (thread_p, &fkref->self_oid, &hfid, NULL, NULL);
4612  if (error_code != NO_ERROR)
4613  {
4614  goto error3;
4615  }
4616 
4617  if (oid_list.oidp == NULL)
4618  {
4619  oid_list.oidp = (OID *) db_private_alloc (thread_p, ISCAN_OID_BUFFER_CAPACITY);
4620  if (oid_list.oidp == NULL)
4621  {
4622  error_code = ER_OUT_OF_VIRTUAL_MEMORY;
4624  goto error3;
4625  }
4627  oid_list.max_oid_cnt = oid_list.capacity;
4628  oid_list.oid_cnt = 0;
4629  oid_list.next_list = NULL;
4630  }
4631 
4632  error_code = heap_scancache_start (thread_p, &isid.scan_cache, &hfid, &fkref->self_oid, true, true, NULL);
4633  if (error_code != NO_ERROR)
4634  {
4635  ASSERT_ERROR ();
4636  goto error3;
4637  }
4638 
4639  scan_init_index_scan (&isid, &oid_list, mvcc_snapshot);
4640 
4641  is_upd_scan_init = false;
4642  pr_clone_value (key, &key_val_range.key1);
4643  pr_clone_value (key, &key_val_range.key2);
4644  key_val_range.range = GE_LE;
4645  key_val_range.num_index_term = 0;
4646  BTREE_INIT_SCAN (&bt_scan);
4647 
4648  do
4649  {
4650  error_code =
4651  btree_prepare_bts (thread_p, &bt_scan, &fkref->self_btid, &isid, &key_val_range, NULL, &fkref->self_oid,
4652  NULL, NULL, false, NULL);
4653  if (error_code != NO_ERROR)
4654  {
4655  assert (er_errid () != NO_ERROR);
4656  goto error2;
4657  }
4658  error_code = btree_range_scan (thread_p, &bt_scan, btree_range_scan_select_visible_oids);
4659  if (error_code != NO_ERROR)
4660  {
4661  assert (er_errid () != NO_ERROR);
4662  goto error2;
4663  }
4664  oid_cnt = bt_scan.n_oids_read_last_iteration;
4665  if (oid_cnt < 0)
4666  {
4667  assert (er_errid () != NO_ERROR);
4668  error_code = er_errid ();
4669  if (error_code == NO_ERROR)
4670  {
4671  error_code = ER_FAILED;
4672  }
4673 
4674  goto error2;
4675  }
4676  else if (oid_cnt == 0)
4677  {
4678  break;
4679  }
4680 
4681  if (is_upd_scan_init == false)
4682  {
4683  error_code =
4684  heap_scancache_start_modify (thread_p, &scan_cache, &hfid, &fkref->self_oid, SINGLE_ROW_UPDATE,
4685  NULL);
4686  if (error_code != NO_ERROR)
4687  {
4688  goto error2;
4689  }
4690  is_upd_scan_init = true;
4691  error_code = heap_attrinfo_start (thread_p, &fkref->self_oid, -1, NULL, &attr_info);
4692  if (error_code != NO_ERROR)
4693  {
4694  goto error1;
4695  }
4696  }
4697 
4698  for (i = 0; i < oid_cnt; i++)
4699  {
4700  OID *oid_ptr = &(oid_list.oidp[i]);
4701  SCAN_CODE scan_code = S_SUCCESS;
4702  recdes.data = NULL;
4703  /* TO DO - handle reevaluation */
4704 
4705  scan_code = locator_lock_and_get_object (thread_p, oid_ptr, &fkref->self_oid, &recdes, &scan_cache,
4707  if (scan_code != S_SUCCESS)
4708  {
4709  if (scan_code == S_DOESNT_EXIST && er_errid () != ER_HEAP_UNKNOWN_OBJECT)
4710  {
4712  oid_ptr->pageid, oid_ptr->slotid);
4713  }
4714  if (er_errid () == ER_HEAP_UNKNOWN_OBJECT)
4715  {
4716  er_log_debug (ARG_FILE_LINE, "locator_update_force: unknown oid ( %d|%d|%d )\n",
4717  oid_ptr->pageid, oid_ptr->slotid, oid_ptr->volid);
4718  continue;
4719  }
4720 
4721  error_code = er_errid ();
4722  error_code = (error_code == NO_ERROR ? ER_FAILED : error_code);
4723  goto error1;
4724  }
4725 
4726  if ((error_code = heap_attrinfo_clear_dbvalues (&attr_info)) != NO_ERROR)
4727  {
4728  goto error1;
4729  }
4730 
4731  if (fkref->upd_action == SM_FOREIGN_KEY_CASCADE)
4732  {
4733  /* This is not yet implemented and this code should not be reached. */
4734  assert (false);
4736  error_code = ER_FK_RESTRICT;
4737  goto error1;
4738  }
4739  else if (fkref->upd_action == SM_FOREIGN_KEY_SET_NULL)
4740  {
4741  for (k = 0; k < num_attrs; ++k)
4742  {
4743  error_code = heap_attrinfo_set (oid_ptr, attr_ids[k], &null_value, &attr_info);
4744  if (error_code != NO_ERROR)
4745  {
4746  goto error1;
4747  }
4748  }
4749  }
4750  else
4751  {
4752  assert (false);
4753  }
4754  /* oid already locked at locator_lock_and_get_object */
4755  error_code =
4756  locator_attribute_info_force (thread_p, &hfid, oid_ptr, &attr_info, attr_ids, index->n_atts,
4757  LC_FLUSH_UPDATE, SINGLE_ROW_UPDATE, &scan_cache, &force_count, false,
4759  UPDATE_INPLACE_NONE, &recdes, false);
4760  if (error_code != NO_ERROR)
4761  {
4762  if (error_code == ER_MVCC_NOT_SATISFIED_REEVALUATION)
4763  {
4764  error_code = NO_ERROR;
4765  }
4766  else
4767  {
4768  goto error1;
4769  }
4770  }
4771  }
4772  }
4773  while (!BTREE_END_OF_SCAN (&bt_scan));
4774 
4775  if (is_upd_scan_init)
4776  {
4777  heap_scancache_end_modify (thread_p, &scan_cache);
4778  heap_attrinfo_end (thread_p, &attr_info);
4779  }
4780 
4781  btree_scan_clear_key (&bt_scan);
4782  pr_clear_value (&key_val_range.key1);
4783  pr_clear_value (&key_val_range.key2);
4784  error_code = heap_scancache_end (thread_p, &isid.scan_cache);
4785  if (error_code != NO_ERROR)
4786  {
4787  error_code = NO_ERROR;
4788  goto end;
4789  }
4790  }
4791  else
4792  {
4793  assert (false);
4794  }
4795  }
4796 
4797 end:
4798  if (oid_list.oidp)
4799  {
4800  db_private_free_and_init (thread_p, oid_list.oidp);
4801  }
4802  if (attr_ids)
4803  {
4804  db_private_free_and_init (thread_p, attr_ids);
4805  }
4806  if (keys_prefix_length)
4807  {
4808  db_private_free_and_init (thread_p, keys_prefix_length);
4809  }
4810 
4811  return error_code;
4812 
4813 error1:
4814  heap_scancache_end_modify (thread_p, &scan_cache);
4815 
4816 error2:
4817  btree_scan_clear_key (&bt_scan);
4818  pr_clear_value (&key_val_range.key1);
4819  pr_clear_value (&key_val_range.key2);
4820  (void) heap_scancache_end (thread_p, &isid.scan_cache);
4821 
4822 error3:
4823  heap_attrinfo_end (thread_p, &attr_info);
4824 
4825  goto end;
4826 }
4827 
4828 /*
4829  * locator_insert_force () - Insert the given object on this heap
4830  *
4831  * return: NO_ERROR if all OK, ER_ status otherwise
4832  *
4833  * hfid(in): Heap where the object is going to be inserted
4834  * class_oid(in/out): the class OID in which it was inserted
4835  * (in case of a partitioned class: it will hold the class OID of
4836  * the actual partition in which the record was inserted)
4837  * oid(in/out): The new object identifier
4838  * recdes(in): The object in disk format
4839  * has_index(in): false if we now for sure that there is not any index on the
4840  * instances of the class.
4841  * op_type(in):
4842  * scan_cache(in/out): Scan cache used to estimate the best space pages
4843  * between heap changes.
4844  * force_count(in):
4845  * pruning_type(in): type of pruning that should be performed
4846  * pcontext(in): partition pruning context
4847  * func_preds(in): cached function index expressions
4848  * force_in_place:
4849  *
4850  * Note: The given object is inserted on this heap and all appropriate
4851  * index entries are inserted.
4852  */
4853 int
4854 locator_insert_force (THREAD_ENTRY * thread_p, HFID * hfid, OID * class_oid, OID * oid, RECDES * recdes, int has_index,
4855  int op_type, HEAP_SCANCACHE * scan_cache, int *force_count, int pruning_type,
4856  PRUNING_CONTEXT * pcontext, FUNC_PRED_UNPACK_INFO * func_preds,
4857  UPDATE_INPLACE_STYLE force_in_place, PGBUF_WATCHER * home_hint_p, bool has_BU_lock,
4858  bool dont_check_fk, bool use_bulk_logging)
4859 {
4860 #if 0 /* TODO - dead code; do not delete me */
4861  OID rep_dir = { NULL_PAGEID, NULL_SLOTID, NULL_VOLID };
4862 #endif
4863  bool isold_object; /* Make sure that this is an old object */
4864  RECDES new_recdes;
4865  bool is_cached = false;
4866  LC_COPYAREA *cache_attr_copyarea = NULL;
4867  int error_code = NO_ERROR;
4868  OID real_class_oid;
4869  HFID real_hfid;
4870  HEAP_SCANCACHE *local_scan_cache = NULL;
4871  FUNC_PRED_UNPACK_INFO *local_func_preds = NULL;
4872  HEAP_OPERATION_CONTEXT context;
4873  bool skip_checking_fk;
4874 
4875  assert (class_oid != NULL);
4876  assert (!OID_ISNULL (class_oid));
4877  assert (!OID_IS_ROOTOID (class_oid));
4878 
4879  HFID_COPY (&real_hfid, hfid);
4880  COPY_OID (&real_class_oid, class_oid);
4881 
4882  local_scan_cache = scan_cache;
4883  local_func_preds = func_preds;
4884 
4885  if (pruning_type != DB_NOT_PARTITIONED_CLASS)
4886  {
4887  OID superclass_oid;
4888  int granted;
4889  /* Perform partition pruning on the given class */
4890  error_code =
4891  partition_prune_insert (thread_p, class_oid, recdes, scan_cache, pcontext, pruning_type, &real_class_oid,
4892  &real_hfid, &superclass_oid);
4893  if (error_code != NO_ERROR)
4894  {
4895  goto error2;
4896  }
4897  if (!OID_ISNULL (&superclass_oid))
4898  {
4899  granted = lock_subclass (thread_p, &real_class_oid, &superclass_oid, IX_LOCK, LK_UNCOND_LOCK);
4900  if (granted != LK_GRANTED)
4901  {
4902  assert (er_errid () != NO_ERROR);
4903  error_code = er_errid ();
4904  if (error_code == NO_ERROR)
4905  {
4906  error_code = ER_FAILED;
4907  }
4908  goto error2;
4909  }
4910  if (pcontext != NULL)
4911  {
4912  /* The scan_cache above is started for the partitioned class, not for the actual partition in which we
4913  * will be performing the insert. See if we already have a scan_cache structure created for the target
4914  * partition and use that one instead of the one supplied to this function */
4915  PRUNING_SCAN_CACHE *ins_cache = NULL;
4916  bool has_func_idx = (func_preds != NULL);
4917 
4918  ins_cache =
4919  locator_get_partition_scancache (pcontext, &real_class_oid, &real_hfid, op_type, has_func_idx);
4920  if (ins_cache == NULL)
4921  {
4922  assert (er_errid () != NO_ERROR);
4923  error_code = er_errid ();
4924  if (error_code == NO_ERROR)
4925  {
4926  error_code = ER_FAILED;
4927  }
4928  goto error2;
4929  }
4930  local_func_preds = ins_cache->func_index_pred;
4931  local_scan_cache = &ins_cache->scan_cache;
4932  }
4933  else
4934  {
4935  /* disable function indexes optimization if we don't have access to a pruning context */
4936  local_func_preds = NULL;
4937  }
4938  }
4939  else
4940  {
4941  /* class_oid was not a partitioned class. This can happen if, for example, this is a request from HA. In this
4942  * which case class_oid already points to the designated partition */
4943  assert_release (OID_EQ (class_oid, &real_class_oid));
4944  }
4945  }
4946 
4947  *force_count = 0;
4948 
4949  /*
4950  * This is a new object. The object must be locked in exclusive mode,
4951  * once its OID is assigned. We just do it for the classes, the new
4952  * instances are not locked since another client cannot get to them,
4953  * in any way. How can a client know their OIDs
4954  */
4955 
4956  /* insert object and lock it */
4957 
4958  assert (!OID_IS_ROOTOID (&real_class_oid));
4959 
4960  /* adjust recdes type (if we got here it should be REC_HOME or REC_BIGONE; REC_BIGONE is detected and handled in
4961  * heap_insert_logical */
4962  recdes->type = REC_HOME;
4963 
4964  /* prepare context */
4965  heap_create_insert_context (&context, &real_hfid, &real_class_oid, recdes, local_scan_cache);
4966  context.update_in_place = force_in_place;
4967  context.is_bulk_op = has_BU_lock;
4968  context.use_bulk_logging = use_bulk_logging;
4969 
4970  if (force_in_place == UPDATE_INPLACE_OLD_MVCCID)
4971  {
4972  REPR_ID rep;
4973 
4974  /* insert due to redistribute partition data - set the correct representation id of the new class */
4975 
4976  rep = heap_get_class_repr_id (thread_p, &real_class_oid);
4977  (void) or_replace_rep_id (context.recdes_p, rep);
4978  }
4979 
4980  /* execute insert */
4981  if (heap_insert_logical (thread_p, &context, home_hint_p) != NO_ERROR)
4982  {
4983  /*
4984  * Problems inserting the object...Maybe, the transaction should be
4985  * aborted by the caller...Quit..
4986  */
4987  assert (er_errid () != NO_ERROR);
4988  error_code = er_errid ();
4989  if (error_code == NO_ERROR)
4990  {
4991  error_code = ER_FAILED;
4992  }
4993  goto error2;
4994  }
4995  COPY_OID (oid, &context.res_oid);
4996 
4997 #if 0 /* TODO - dead code; do not delete me */
4998  if (OID_IS_ROOTOID (&real_class_oid))
4999  {
5000  assert (false); /* is impossible */
5001 
5002  /*
5003  * A CLASS: Add the classname to class_OID entry and add the class
5004  * to the catalog.
5005  * Update the classname table.
5006  * Remove XASL cache entries which is relevant with that class.
5007  */
5008 
5009  classname = or_class_name (recdes);
5010  assert (classname != NULL);
5011  assert (strlen (classname) < 255);
5012 
5013  /* Indicate new oid to classname table */
5014  if (locator_permoid_class_name (thread_p, classname, oid) != NO_ERROR)
5015  {
5016  assert (false); /* should be impossible */
5017  goto error1;
5018  }
5019 
5020  if (!OID_IS_ROOTOID (oid))
5021  {
5022  HEAP_OPERATION_CONTEXT update_context;
5023  char *rep_dir_offset;
5024 
5025  or_class_rep_dir (recdes, &rep_dir);
5026  assert (OID_ISNULL (&rep_dir));
5027 
5028  if (catalog_insert (thread_p, recdes, oid, &rep_dir) < 0)
5029  {
5030  /*
5031  * There is an error inserting the hash entry or catalog
5032  * information. Maybe, the transaction should be aborted by
5033  * the caller...Quit
5034  */
5035  assert (er_errid () != NO_ERROR);
5036  error_code = er_errid ();
5037  if (error_code == NO_ERROR)
5038  {
5039  error_code = ER_FAILED;
5040  }
5041  goto error1;
5042  }
5043 
5044  assert (!OID_ISNULL (&rep_dir));
5045 
5046  /* save oid of the representation directory */
5047  rep_dir_offset =
5048  (char *) recdes->data + OR_FIXED_ATTRIBUTES_OFFSET (recdes->data,
5050 
5051  OR_PUT_OID (rep_dir_offset, &rep_dir);
5052 
5053  heap_create_update_context (&update_context, &real_hfid, oid, &real_class_oid, recdes, local_scan_cache);
5054  update_context.force_non_mvcc = true;
5055 
5056  if (heap_update_logical (thread_p, &update_context) != NO_ERROR)
5057  {
5058  /*
5059  * Problems updating the object...Maybe, the transaction should be
5060  * aborted by the caller...Quit..
5061  */
5062  error_code = er_errid ();
5063  if (error_code == NO_ERROR)
5064  {
5065  error_code = ER_FAILED;
5066  }
5067  goto error1;
5068  }
5069 
5070  assert (isold_object == true);
5071 
5072 #if !defined(NDEBUG)
5073  or_class_rep_dir (recdes, &rep_dir);
5074  assert (!OID_ISNULL (&rep_dir));
5075 #endif
5076  }
5077 
5078  if (catcls_Enable == true && catcls_insert_catalog_classes (thread_p, recdes) != NO_ERROR)
5079  {
5080  assert (er_errid () != NO_ERROR);
5081  error_code = er_errid ();
5082  if (error_code == NO_ERROR)
5083  {
5084  error_code = ER_FAILED;
5085  }
5086  goto error1;
5087  }
5088 
5089  /* system class do not include foreign keys, we need not check here. */
5090  }
5091  else
5092  {
5093 #endif
5094  /*
5095  * AN INSTANCE: Apply the necessary index insertions
5096  */
5097  skip_checking_fk = locator_Dont_check_foreign_key || dont_check_fk;
5098 
5099  if (has_index
5100  && locator_add_or_remove_index (thread_p, recdes, oid, &real_class_oid, true, op_type, local_scan_cache, true,
5101  true, &real_hfid, local_func_preds, has_BU_lock,
5102  skip_checking_fk) != NO_ERROR)
5103  {
5104  assert (er_errid () != NO_ERROR);
5105  error_code = er_errid ();
5106  if (error_code == NO_ERROR)
5107  {
5108  error_code = ER_FAILED;
5109  }
5110  goto error1;
5111  }
5112 
5113  /* check the foreign key constraints */
5114  if (has_index && !skip_checking_fk)
5115  {
5116  error_code =
5117  locator_check_foreign_key (thread_p, &real_hfid, &real_class_oid, oid, recdes, &new_recdes, &is_cached,
5118  &cache_attr_copyarea);
5119  if (error_code != NO_ERROR)
5120  {
5121  goto error1;
5122  }
5123 
5124  if (is_cached)
5125  {
5126  HEAP_OPERATION_CONTEXT update_context;
5127 
5128  recdes = &new_recdes;
5129  /* Cache object has been updated, we need update the value again */
5130  heap_create_update_context (&update_context, &real_hfid, oid, &real_class_oid, recdes, local_scan_cache,
5132  if (heap_update_logical (thread_p, &update_context) != NO_ERROR)
5133  {
5134  assert (er_errid () != NO_ERROR);
5135  error_code = er_errid ();
5136  if (error_code == NO_ERROR)
5137  {
5138  error_code = ER_FAILED;
5139  }
5140  goto error1;
5141  }
5142 
5143  assert (update_context.is_logical_old);
5144  isold_object = update_context.is_logical_old;
5145  }
5146  }
5147 
5148 #if defined(ENABLE_UNUSED_FUNCTION)
5149  /* increase the counter of the catalog */
5150  locator_increase_catalog_count (thread_p, &real_class_oid);
5151 #endif
5152 
5153  /* remove query result cache entries which are relevant with this class */
5155  {
5156  if (qexec_clear_list_cache_by_class (thread_p, &real_class_oid) != NO_ERROR)
5157  {
5159  "locator_insert_force: qexec_clear_list_cache_by_class failed for class { %d %d %d }\n",
5160  real_class_oid.pageid, real_class_oid.slotid, real_class_oid.volid);
5161  }
5162  qmgr_add_modified_class (thread_p, &real_class_oid);
5163  }
5164 #if 0 /* TODO - dead code; do not delete me */
5165  }
5166 #endif
5167 
5168  *force_count = 1;
5169 
5170 error1:
5171  /* update the OID of the class with the actual partition in which the object was inserted */
5172  COPY_OID (class_oid, &real_class_oid);
5173  HFID_COPY (hfid, &real_hfid);
5174 
5175 error2:
5176  if (cache_attr_copyarea != NULL)
5177  {
5178  locator_free_copy_area (cache_attr_copyarea);
5179  }
5180 
5181  return error_code;
5182 }
5183 
5184 /*
5185  * locator_move_record () - relocate a record from a partitioned class
5186  * return : error code or NO_ERROR
5187  * thread_p (in) : caller thread
5188  * old_hfid (in) : source location of the record
5189  * old_class_oid (in) : class owning the record
5190  * obj_oid (in) : record OID
5191  * new_class_oid (in) : destination class
5192  * new_class_hfid (in) : destination hfid
5193  * recdes (in) : record
5194  * scan_cache (in) : scan cache
5195  * op_type (in) : operation type
5196  * has_index (in) : true if the class has indexes
5197  * force_count (in/out) :
5198  * context(in) : pruning context
5199  * mvcc_reev_data(in) : MVCC reevaluation data
5200  * need_locking(in) : true, if need locking
5201  *
5202  * Note: this function calls locator_delete_force on the current object oid
5203  * and locator_insert_force for the RECDES it receives. The record has already
5204  * been set to be used by the receiving class when it went through the pruning
5205  * algorithm (see function partition_find_partition_for_record)
5206  */
5207 static int
5208 locator_move_record (THREAD_ENTRY * thread_p, HFID * old_hfid, OID * old_class_oid, OID * obj_oid, OID * new_class_oid,
5209  HFID * new_class_hfid, RECDES * recdes, HEAP_SCANCACHE * scan_cache, int op_type, int has_index,
5210  int *force_count, PRUNING_CONTEXT * context, MVCC_REEV_DATA * mvcc_reev_data, bool need_locking)
5211 {
5212  int error = NO_ERROR;
5213  OID new_obj_oid;
5214 
5215  assert (!OID_IS_ROOTOID (old_class_oid));
5216  assert (!OID_IS_ROOTOID (new_class_oid));
5217 
5218  if (context != NULL)
5219  {
5220  /* setup a PRUNING_SCAN_CACHE object for this class */
5221  HEAP_SCANCACHE *insert_cache = NULL;
5222  PRUNING_SCAN_CACHE *ins_cache = NULL;
5223  ins_cache = locator_get_partition_scancache (context, new_class_oid, new_class_hfid, op_type, false);
5224  if (ins_cache == NULL)
5225  {
5226  assert (er_errid () != NO_ERROR);
5227  error = er_errid ();
5228  return (error != NO_ERROR) ? error : ER_FAILED;
5229  }
5230 
5231  insert_cache = &ins_cache->scan_cache;
5232 
5233  error =
5234  locator_insert_force (thread_p, new_class_hfid, new_class_oid, &new_obj_oid, recdes, has_index, op_type,
5235  insert_cache, force_count, context->pruning_type, NULL, NULL, UPDATE_INPLACE_NONE, NULL,
5236  false, false);
5237  }
5238  else
5239  {
5240  HEAP_SCANCACHE insert_cache;
5241 
5242  error =
5243  locator_start_force_scan_cache (thread_p, &insert_cache, new_class_hfid, new_class_oid, SINGLE_ROW_INSERT);
5244  if (error != NO_ERROR)
5245  {
5246  return error;
5247  }
5248 
5249  /* insert the new record */
5250  error =
5251  locator_insert_force (thread_p, new_class_hfid, new_class_oid, &new_obj_oid, recdes, has_index, op_type,
5252  &insert_cache, force_count, DB_NOT_PARTITIONED_CLASS, NULL, NULL, UPDATE_INPLACE_NONE,
5253  NULL, false, false);
5254  heap_scancache_end (thread_p, &insert_cache);
5255  }
5256 
5257  if (error != NO_ERROR)
5258  {
5259  return error;
5260  }
5261 
5262  /* delete this record from the class it currently resides in */
5263  error =
5264  locator_delete_force_for_moving (thread_p, old_hfid, obj_oid, true, op_type, scan_cache, force_count,
5265  mvcc_reev_data, &new_obj_oid, new_class_oid, need_locking);
5266  if (error != NO_ERROR)
5267  {
5268  return error;
5269  }
5270 
5271  COPY_OID (obj_oid, &new_obj_oid);
5272 
5273  return NO_ERROR;
5274 }
5275 
5276 /*
5277  * locator_update_force () - Update the given object
5278  *
5279  * return: NO_ERROR if all OK, ER_ status otherwise
5280  *
5281  * hfid(in): Heap where the object is going to be inserted
5282  * class_oid(in):
5283  * oid(in): The object identifier
5284  * oldrecdes(in):
5285  * recdes(in): The object in disk format
5286  * has_index(in): false if we now for sure that there is not any index
5287  * on the instances of the class.
5288  * att_id(in): Updated attr id array
5289  * n_att_id(in): Updated attr id array length
5290  * op_type(in):
5291  * scan_cache(in/out): Scan cache used to estimate the best space pages
5292  * between heap changes.
5293  * force_count(in):
5294  * not_check_fk(in):
5295  * repl_inf(in): replication info
5296  * pruning_type(in): pruning type
5297  * pcontext(in): pruning context
5298  * mvcc_reev_data(in): MVCC reevaluation data
5299  * force_in_place(in): if UPDATE_INPLACE_NONE then the 'in place' will not be forced
5300  * and the update style will be decided in this function.
5301  * Otherwise the update of the instance will be made in
5302  * place and according to provided style.
5303  *
5304  * Note: The given object is updated on this heap and all appropriate
5305  * index entries are updated.
5306  */
5307 static int
5308 locator_update_force (THREAD_ENTRY * thread_p, HFID * hfid, OID * class_oid, OID * oid, RECDES * oldrecdes,
5309  RECDES * recdes, int has_index, ATTR_ID * att_id, int n_att_id, int op_type,
5310  HEAP_SCANCACHE * scan_cache, int *force_count, bool not_check_fk, REPL_INFO_TYPE repl_info_type,
5311  int pruning_type, PRUNING_CONTEXT * pcontext, MVCC_REEV_DATA * mvcc_reev_data,
5312  UPDATE_INPLACE_STYLE force_in_place, bool need_locking)
5313 {
5314  OID rep_dir = { NULL_PAGEID, NULL_SLOTID, NULL_VOLID };
5315  char *rep_dir_offset;
5316  char *classname = NULL; /* Classname to update */
5317  char *old_classname = NULL; /* Classname that may have been renamed */
5318 
5319  bool isold_object; /* Make sure that this is an old object */
5320  RECDES copy_recdes = RECDES_INITIALIZER;
5321  SCAN_CODE scan = S_SUCCESS;
5322 
5323  RECDES new_record;
5324  bool is_cached = false;
5325  LC_COPYAREA *cache_attr_copyarea = NULL;
5326  int error_code = NO_ERROR;
5327  HEAP_SCANCACHE *local_scan_cache;
5328  bool no_data_new_address = false;
5330  TDE_ALGORITHM tde_algo = TDE_ALGORITHM_NONE;
5331 
5332  assert (class_oid != NULL && !OID_ISNULL (class_oid));
5333 
5334  /*
5335  * While scanning objects, the given scancache does not fix the last
5336  * accessed page. So, the object must be copied to the record descriptor.
5337  */
5338  copy_recdes.data = NULL;
5339 
5340  *force_count = 0;
5341 
5342  repl_info.repl_info_type = repl_info_type;
5343  repl_info.need_replication = true;
5344  repl_info.info = NULL;
5345 
5346  if (OID_IS_ROOTOID (class_oid))
5347  {
5348  HEAP_OPERATION_CONTEXT update_context;
5349 
5350  or_class_tde_algorithm (recdes, &tde_algo);
5351  if (tde_algo != TDE_ALGORITHM_NONE && !tde_Cipher.is_loaded)
5352  {
5354  error_code = ER_TDE_CIPHER_IS_NOT_LOADED;
5355  goto error;
5356  }
5357 
5358  /*
5359  * A CLASS: classes do not have any indices...however, the classname
5360  * to oid table may need to be updated
5361  */
5362  classname = or_class_name (recdes);
5363  assert (classname != NULL);
5364  assert (strlen (classname) < 255);
5365 
5366  if (heap_get_class_name_alloc_if_diff (thread_p, oid, classname, &old_classname) != NO_ERROR)
5367  {
5368  /* it is unexpected to fail to get the classname of an existing class */
5369  ASSERT_ERROR_AND_SET (error_code);
5370  goto error;
5371  }
5372 
5373  /*
5374  * Compare the classname pointers. If the same pointers classes are the
5375  * same since the class was no malloc
5376  */
5377  if (old_classname != NULL && old_classname != classname)
5378  {
5379  assert (old_classname != NULL);
5380  assert (strlen (old_classname) < 255);
5381 
5382  /* Different names, the class was renamed. */
5383  error_code = log_add_to_modified_class_list (thread_p, old_classname, oid);
5384  if (error_code != NO_ERROR)
5385  {
5386  goto error;
5387  }
5388  }
5389 
5390  if ((catcls_Enable == true) && (old_classname != NULL))
5391  {
5392  error_code = catcls_update_catalog_classes (thread_p, old_classname, recdes, oid, force_in_place);
5393  if (error_code != NO_ERROR)
5394  {
5395  goto error;
5396  }
5397  }
5398 
5399  /* TODO - defence code to save oid of the representation directory */
5400  if (!OID_IS_ROOTOID (oid))
5401  {
5402  or_class_rep_dir (recdes, &rep_dir);
5403 
5404  if (OID_ISNULL (&rep_dir))
5405  {
5406  OID old_rep_dir = { NULL_PAGEID, NULL_SLOTID, NULL_VOLID };
5407  RECDES old_record, *old_recdes;
5408 
5409  old_record.data = NULL;
5410  old_recdes = &old_record;
5411 
5412  if (heap_get_class_record (thread_p, oid, old_recdes, scan_cache, PEEK) == S_SUCCESS)
5413  {
5414  or_class_rep_dir (old_recdes, &old_rep_dir);
5415 
5416  /* save current oid of the representation directory */
5417  if (!OID_ISNULL (&old_rep_dir))
5418  {
5419  assert (false); /* should avoid */
5420 
5421  rep_dir_offset =
5422  (char *) recdes->data + OR_FIXED_ATTRIBUTES_OFFSET (recdes->data, ORC_CLASS_VAR_ATT_COUNT)
5424 
5425  OR_PUT_OID (rep_dir_offset, &old_rep_dir);
5426  }
5427  }
5428  else
5429  {
5430  /* ignore if the class hasn't been flushed yet */
5432  {
5433  er_clear (); /* clear ER_HEAP_NODATA_NEWADDRESS */
5434  }
5435  }
5436  }
5437  }
5438 
5439  heap_create_update_context (&update_context, hfid, oid, class_oid, recdes, scan_cache,
5441  error_code = heap_update_logical (thread_p, &update_context);
5442  if (error_code != NO_ERROR)
5443  {
5444  /*
5445  * Problems updating the object...Maybe, the transaction should be
5446  * aborted by the caller...Quit..
5447  */
5448  if (error_code == ER_FAILED)
5449  {
5450  ASSERT_ERROR_AND_SET (error_code);
5451  /* FIXME: better to make functions to return ER_INTERRUPTED rather than ER_FAILED for the case */
5452  assert (error_code == ER_INTERRUPTED);
5453  }
5454  else
5455  {
5456  ASSERT_ERROR ();
5457  }
5458 
5459  goto error;
5460  }
5461  isold_object = update_context.is_logical_old;
5462 
5463  if (update_context.is_logical_old)
5464  {
5465  /* Update the catalog as long as it is not the root class */
5466  if (!OID_IS_ROOTOID (oid))
5467  {
5468 #if !defined(NDEBUG)
5469  or_class_rep_dir (recdes, &rep_dir);
5470  assert (!OID_ISNULL (&rep_dir));
5471 #endif
5472  error_code = catalog_update (thread_p, recdes, oid);
5473  if (error_code < 0)
5474  {
5475  /*
5476  * An error occurred during the update of the catalog
5477  */
5478  goto error;
5479  }
5480  }
5481  }
5482  else
5483  {
5484  /*
5485  * NEW CLASS
5486  */
5487  if (!OID_IS_ROOTOID (oid))
5488  {
5489  HEAP_OPERATION_CONTEXT update_context;
5490  or_class_rep_dir (recdes, &rep_dir);
5491  assert (OID_ISNULL (&rep_dir));
5492 
5493  if (catalog_insert (thread_p, recdes, oid, &rep_dir) < 0)
5494  {
5495  /*
5496  * There is an error inserting the hash entry or catalog
5497  * information. The transaction must be aborted by the caller
5498  */
5499  error_code = ER_FAILED;
5500  goto error;
5501  }
5502 
5503  assert (!OID_ISNULL (&rep_dir));
5504 
5505  /* save oid of the representation directory */
5506  rep_dir_offset =
5507  (char *) recdes->data + OR_FIXED_ATTRIBUTES_OFFSET (recdes->data, ORC_CLASS_VAR_ATT_COUNT)
5509 
5510  OR_PUT_OID (rep_dir_offset, &rep_dir);
5511 
5512  heap_create_update_context (&update_context, hfid, oid, class_oid, recdes, scan_cache,
5514  error_code = heap_update_logical (thread_p, &update_context);
5515  if (error_code != NO_ERROR)
5516  {
5517  /*
5518  * Problems updating the object...Maybe, the transaction should be
5519  * aborted by the caller...Quit..
5520  */
5521  if (error_code == ER_FAILED)
5522  {
5523  ASSERT_ERROR_AND_SET (error_code);
5524  }
5525  else
5526  {
5527  ASSERT_ERROR ();
5528  }
5529  goto error;
5530  }
5531  isold_object = update_context.is_logical_old;
5532 
5533 #if !defined(NDEBUG)
5534  or_class_rep_dir (recdes, &rep_dir);
5535  assert (!OID_ISNULL (&rep_dir));
5536 #endif
5537  }
5538 
5539  if (catcls_Enable == true)
5540  {
5541  error_code = catcls_insert_catalog_classes (thread_p, recdes);
5542  if (error_code != NO_ERROR)
5543  {
5544  goto error;
5545  }
5546  }
5547  }
5548 
5549  /* system class do not include foreign keys. we need not check here. */
5550 
5551  /* remove XASL cache entries which is relevant with that class */
5552  if (!OID_IS_ROOTOID (oid))
5553  {
5554  xcache_remove_by_oid (thread_p, oid);
5555  }
5556 
5557  if (!OID_IS_ROOTOID (oid))
5558  {
5559  fpcache_remove_by_class (thread_p, oid);
5560  }
5561  }
5562  else
5563  {
5564  HEAP_OPERATION_CONTEXT update_context;
5565 
5566  local_scan_cache = scan_cache;
5567  if (pruning_type != DB_NOT_PARTITIONED_CLASS && pcontext != NULL)
5568  {
5569  /* Get a scan_cache object for the actual class which is updated. This object is kept in a list in the
5570  * pruning context */
5571  OID real_class_oid;
5572  HFID real_hfid;
5573  PRUNING_SCAN_CACHE *pcache;
5574 
5575  HFID_COPY (&real_hfid, hfid);
5576  COPY_OID (&real_class_oid, class_oid);
5577  pcache = locator_get_partition_scancache (pcontext, &real_class_oid, &real_hfid, op_type, false);
5578  if (pcache == NULL)
5579  {
5580  return ER_FAILED;
5581  }
5582  local_scan_cache = &pcache->scan_cache;
5583  }
5584 
5585  /* There will be no pruning after this point so we should reset op_type to a non pruning operation */
5586 
5587  if (!mvcc_is_mvcc_disabled_class (class_oid))
5588  {
5589  if (oldrecdes == NULL)
5590  {
5591  copy_recdes.data = NULL;
5592  if (mvcc_reev_data != NULL && mvcc_reev_data->type == REEV_DATA_UPDDEL)
5593  {
5594  /* The new recdes can be changed during reevaluation. That's because new recdes fields may refer
5595  * fields of old recdes */
5596  mvcc_reev_data->upddel_reev_data->new_recdes = recdes;
5597  }
5598 
5599  if (need_locking)
5600  {
5601  scan = locator_lock_and_get_object_with_evaluation (thread_p, oid, class_oid, &copy_recdes,
5602  local_scan_cache, COPY, NULL_CHN, mvcc_reev_data,
5604  }
5605  else
5606  {
5607  scan = heap_get_visible_version (thread_p, oid, class_oid, &copy_recdes, local_scan_cache, COPY,
5608  NULL_CHN);
5609  }
5610 
5611 
5612  if (scan == S_SUCCESS && mvcc_reev_data != NULL && mvcc_reev_data->filter_result == V_FALSE)
5613  {
5615  }
5616  else if (scan != S_SUCCESS)
5617  {
5619  {
5620  force_in_place = UPDATE_INPLACE_CURRENT_MVCCID;
5621 
5622  /* The object is a new instance, that is only the address (no content) is known by the heap
5623  * manager. This is a normal behavior and, if we have an index, we need to add the object to the
5624  * index later. Because the following processing can remove this error, we save it here in
5625  * no_data_new_address */
5626  no_data_new_address = true;
5627  er_clear (); /* clear ER_HEAP_NODATA_NEWADDRESS */
5628  }
5629  else
5630  {
5631  if ((scan == S_DOESNT_EXIST || scan == S_SNAPSHOT_NOT_SATISFIED)
5633  {
5635  oid->slotid);
5636  }
5637  error_code = er_errid ();
5638  if (error_code == ER_HEAP_UNKNOWN_OBJECT)
5639  {
5640  er_log_debug (ARG_FILE_LINE, "locator_update_force: unknown oid ( %d|%d|%d )\n",
5641  oid->pageid, oid->slotid, oid->volid);
5642  }
5643  else if (error_code == NO_ERROR)
5644  {
5645  error_code = ER_FAILED;
5646  }
5647 
5648  goto error;
5649  }
5650  }
5651  else
5652  {
5653  oldrecdes = &copy_recdes;
5654  }
5655  }
5656 
5657  if (!HEAP_IS_UPDATE_INPLACE (force_in_place))
5658  {
5659  LOG_TDES *tdes;
5660 
5661  tdes = LOG_FIND_CURRENT_TDES (thread_p);
5662  if (!(has_index & LC_FLAG_HAS_UNIQUE_INDEX))
5663  {
5664  MVCC_REC_HEADER old_rec_header;
5665 
5666  or_mvcc_get_header (oldrecdes, &old_rec_header);
5667  if (logtb_find_current_mvccid (thread_p) != old_rec_header.mvcc_ins_id)
5668  {
5669 #if defined (SERVER_MODE)
5670  /* If not inserted by me, I must have lock. */
5671  assert (lock_has_lock_on_object (oid, class_oid, X_LOCK) > 0);
5672 #endif /* SERVER_MODE */
5673  }
5674  }
5675  }
5676  else if (force_in_place == UPDATE_INPLACE_OLD_MVCCID)
5677  {
5678  MVCC_REC_HEADER old_rec_header, new_rec_header;
5679 
5680  if (or_mvcc_get_header (oldrecdes, &old_rec_header) != NO_ERROR
5681  || or_mvcc_get_header (recdes, &new_rec_header) != NO_ERROR)
5682  {
5683  goto error;
5684  }
5685 
5686  if (MVCC_IS_FLAG_SET (&old_rec_header, OR_MVCC_FLAG_VALID_INSID))
5687  {
5688  MVCC_SET_FLAG_BITS (&new_rec_header, OR_MVCC_FLAG_VALID_INSID);
5689  MVCC_SET_INSID (&new_rec_header, MVCC_GET_INSID (&old_rec_header));
5690  }
5691  else
5692  {
5694  }
5695 
5696  if (MVCC_IS_HEADER_DELID_VALID (&old_rec_header))
5697  {
5698  MVCC_SET_FLAG_BITS (&new_rec_header, OR_MVCC_FLAG_VALID_DELID);
5699  MVCC_SET_DELID (&new_rec_header, MVCC_GET_DELID (&old_rec_header));
5700  }
5701  else
5702  {
5704  }
5705 
5706  if (MVCC_IS_FLAG_SET (&old_rec_header, OR_MVCC_FLAG_VALID_PREV_VERSION))
5707  {
5709  MVCC_SET_PREVIOUS_VERSION_LSA (&new_rec_header, &MVCC_GET_PREV_VERSION_LSA (&old_rec_header));
5710  }
5711  else
5712  {
5714  }
5715 
5716  if (or_mvcc_set_header (recdes, &new_rec_header) != NO_ERROR)
5717  {
5718  goto error;
5719  }
5720  }
5721  }
5722  else
5723  {
5724  if (!HEAP_IS_UPDATE_INPLACE (force_in_place))
5725  {
5726  force_in_place = UPDATE_INPLACE_CURRENT_MVCCID;
5727  }
5728 
5729  if (lock_object (thread_p, oid, class_oid, X_LOCK, LK_UNCOND_LOCK) != LK_GRANTED)
5730  {
5731  ASSERT_ERROR_AND_SET (error_code);
5732  goto error;
5733  }
5734 
5735  if (has_index && oldrecdes == NULL)
5736  {
5737  /* get the old record first */
5738  local_scan_cache->mvcc_snapshot = logtb_get_mvcc_snapshot (thread_p);
5739  if (local_scan_cache->mvcc_snapshot == NULL)
5740  {
5741  error_code = er_errid ();
5742  if (error_code == NO_ERROR)
5743  {
5744  error_code = ER_FAILED;
5745  }
5746  goto error;
5747  }
5748 
5749  scan =
5750  heap_get_visible_version (thread_p, oid, class_oid, &copy_recdes, local_scan_cache, COPY, NULL_CHN);
5751  if (scan == S_SUCCESS)
5752  {
5753  oldrecdes = &copy_recdes;
5754  }
5755  else if (er_errid () == ER_HEAP_NODATA_NEWADDRESS)
5756  {
5757  er_clear (); /* clear ER_HEAP_NODATA_NEWADDRESS */
5758 
5759  /* The object is a new instance, that is only the address (no content) is known by the heap manager.
5760  * This is a normal behaviour and, if we have an index, we need to add the object to the index later.
5761  * Because the following processing can remove this error, we save it here in no_data_new_address */
5762  no_data_new_address = true;
5763  }
5764  else
5765  {
5766  error_code = er_errid ();
5767  if (error_code == ER_HEAP_UNKNOWN_OBJECT)
5768  {
5769  er_log_debug (ARG_FILE_LINE, "locator_update_force: unknown oid ( %d|%d|%d )\n", oid->pageid,
5770  oid->slotid, oid->volid);
5771  }
5772  else if (error_code == ER_INTERRUPTED)
5773  {
5774  // expected error
5775  }
5776  else
5777  {
5778  // todo - why do we force error code?
5779  error_code = ER_HEAP_UNKNOWN_OBJECT;
5780  }
5781  goto error;
5782  }
5783  }
5784  }
5785 
5786  if (pruning_type != DB_NOT_PARTITIONED_CLASS)
5787  {
5788  OID superclass_oid;
5789  OID real_class_oid;
5790  HFID real_hfid;
5791  int granted;
5792 
5793  HFID_COPY (&real_hfid, hfid);
5794  COPY_OID (&real_class_oid, class_oid);
5795  error_code =
5796  partition_prune_update (thread_p, class_oid, recdes, pcontext, pruning_type, &real_class_oid, &real_hfid,
5797  &superclass_oid);
5798  if (error_code != NO_ERROR)
5799  {
5800  goto error;
5801  }
5802 
5803  /* make sure we use the correct class oid - we could be dealing with a classoid resulted from a unique btid
5804  * pruning */
5805  if (heap_get_class_oid (thread_p, oid, class_oid) != S_SUCCESS)
5806  {
5807  ASSERT_ERROR_AND_SET (error_code);
5808  goto error;
5809  }
5810 
5811  if (heap_get_class_info (thread_p, class_oid, hfid, NULL, NULL) != NO_ERROR)
5812  {
5813  goto error;
5814  }
5815 
5816  if (!OID_EQ (class_oid, &real_class_oid))
5817  {
5818  /* If we have to move the record to another partition, we have to lock the target partition for insert.
5819  * The class from which we delete was already locked (X_LOCK for heap scan or IX_LOCK for index scan)
5820  * during the SELECT phase of UPDATE */
5821  granted = lock_subclass (thread_p, &real_class_oid, &superclass_oid, IX_LOCK, LK_UNCOND_LOCK);
5822  if (granted != LK_GRANTED)
5823  {
5824  assert (er_errid () != NO_ERROR);
5825  error_code = er_errid ();
5826  if (error_code == NO_ERROR)
5827  {
5828  error_code = ER_FAILED;
5829  }
5830  goto error;
5831  }
5832 
5833  error_code =
5834  locator_move_record (thread_p, hfid, class_oid, oid, &real_class_oid, &real_hfid, recdes, scan_cache,
5835  op_type, has_index, force_count, pcontext, mvcc_reev_data, need_locking);
5836  if (error_code == NO_ERROR)
5837  {
5838  COPY_OID (class_oid, &real_class_oid);
5839  HFID_COPY (hfid, &real_hfid);
5840  }
5841  return error_code;
5842  }
5843  }
5844 
5845  /* AN INSTANCE: Update indices if any */
5846  if (has_index)
5847  {
5848  if (scan == S_SUCCESS)
5849  {
5850  error_code =
5851  locator_update_index (thread_p, recdes, oldrecdes, att_id, n_att_id, oid, class_oid, op_type,
5852  local_scan_cache, &repl_info);
5853  if (error_code != NO_ERROR)
5854  {
5855  /*
5856  * There is an error updating the index... Quit... The
5857  * transaction must be aborted by the caller
5858  */
5859  ASSERT_ERROR ();
5860  goto error;
5861  }
5862  }
5863  else
5864  {
5865  /*
5866  * We could not get the object.
5867  * The object may be a new instance, that is only the address
5868  * (no content) is known by the heap manager.
5869  */
5870 
5871  if (no_data_new_address)
5872  {
5873  er_clear (); /* clear the error code */
5874  if (op_type == SINGLE_ROW_MODIFY)
5875  { /* to enable uniqueness checking */
5876  op_type = SINGLE_ROW_INSERT;
5877  }
5878 
5879  error_code =
5880  locator_add_or_remove_index (thread_p, recdes, oid, class_oid, true, op_type, local_scan_cache,
5881  true, true, hfid, NULL, false, false);
5882  if (error_code != NO_ERROR)
5883  {
5884  ASSERT_ERROR ();
5885  goto error;
5886  }
5887  }
5888  }
5889 
5890  /* check the foreign key constraints */
5891  if (!not_check_fk && !locator_Dont_check_foreign_key)
5892  {
5893  error_code =
5894  locator_check_foreign_key (thread_p, hfid, class_oid, oid, recdes, &new_record, &is_cached,
5895  &cache_attr_copyarea);
5896  if (error_code != NO_ERROR)
5897  {
5898  goto error;
5899  }
5900 
5901  if (is_cached)
5902  {
5903  recdes = &new_record;
5904  }
5905  }
5906  }
5907 
5908  heap_create_update_context (&update_context, hfid, oid, class_oid, recdes, local_scan_cache, force_in_place);
5909  error_code = heap_update_logical (thread_p, &update_context);
5910  if (error_code != NO_ERROR)
5911  {
5912  /*
5913  * Problems updating the object...Maybe, the transaction should be aborted by the caller...Quit..
5914  */
5915  if (error_code == ER_FAILED)
5916  {
5917  ASSERT_ERROR_AND_SET (error_code);
5918  assert (error_code == ER_INTERRUPTED);
5919  }
5920  else
5921  {
5922  ASSERT_ERROR ();
5923  }
5924  goto error;
5925  }
5926  isold_object = update_context.is_logical_old;
5927 
5928  /*
5929  * for replication,
5930  * We have to set UPDATE LSA number to the log info.
5931  * The target log info was already created when the locator_update_index
5932  */
5933  if (!LOG_CHECK_LOG_APPLIER (thread_p) && log_does_allow_replication () == true
5934  && repl_info.need_replication == true)
5935  {
5936  repl_add_update_lsa (thread_p, oid);
5937  }
5938 
5939 #if defined(ENABLE_UNUSED_FUNCTION)
5940  if (isold_object == false)
5941  {
5942  locator_increase_catalog_count (thread_p, class_oid);
5943  }
5944 #endif
5945 
5946  /* remove query result cache entries which are relevant with this class */
5948  {
5949  if (qexec_clear_list_cache_by_class (thread_p, class_oid) != NO_ERROR)
5950  {
5952  "locator_update_force: qexec_clear_list_cache_by_class failed for class { %d %d %d }\n",
5953  class_oid->pageid, class_oid->slotid, class_oid->volid);
5954  }
5955  qmgr_add_modified_class (thread_p, class_oid);
5956  }
5957  }
5958 
5959  *force_count = 1;
5960 
5961 error:
5962 
5963  if (old_classname != NULL && old_classname != classname)
5964  {
5965  free_and_init (old_classname);
5966  }
5967 
5968  if (cache_attr_copyarea != NULL)
5969  {
5970  locator_free_copy_area (cache_attr_copyarea);
5971  }
5972 
5973  return error_code;
5974 }
5975 
5976 /*
5977  * locator_delete_force () - Delete the given object
5978  *
5979  * return: NO_ERROR if all OK, ER_ status otherwise
5980  *
5981  * hfid(in): Heap where the object is going to be inserted
5982  * oid(in): The object identifier
5983  * has_index(in): false if we now for sure that there is not any index on the instances of the class.
5984  * op_type(in):
5985  * scan_cache(in/out): Scan cache used to estimate the best space pages between heap changes.
5986  * force_count(in):
5987  * mvcc_reev_data(in): MVCC data
5988  * need_locking(in): true, if need locking
5989  *
5990  * Note: The given object is deleted on this heap and all appropiate index entries are deleted.
5991  */
5992 int
5993 locator_delete_force (THREAD_ENTRY * thread_p, HFID * hfid, OID * oid, int has_index, int op_type,
5994  HEAP_SCANCACHE * scan_cache, int *force_count, MVCC_REEV_DATA * mvcc_reev_data, bool need_locking)
5995 {
5996  return locator_delete_force_internal (thread_p, hfid, oid, has_index, op_type, scan_cache, force_count,
5997  mvcc_reev_data, FOR_INSERT_OR_DELETE, NULL, NULL, need_locking);
5998 }
5999 
6000 /*
6001  * locator_delete_force_for_moving () - Delete the given object
6002  * To move record between partitions.
6003  *
6004  * return: NO_ERROR if all OK, ER_ status otherwise
6005  *
6006  * thread_p(in):
6007  * hfid(in): Heap where the object is going to be inserted
6008  * oid(in): The object identifier
6009  * has_index(in): false if we now for sure that there is not any index on the instances of the class.
6010  * op_type(in):
6011  * scan_cache(in/out): Scan cache used to estimate the best space pages between heap changes.
6012  * force_count(in):
6013  * mvcc_reev_data(in): MVCC data
6014  * new_obj_oid(in): next version - only to be used with records relocated in other partitions, in MVCC.
6015  * partition_oid(in): new partition class oid
6016  * need_locking(in): true, if need locking
6017  *
6018  * Note: The given object is deleted on this heap and all appropriate index entries are deleted.
6019  */
6020 static int
6021 locator_delete_force_for_moving (THREAD_ENTRY * thread_p, HFID * hfid, OID * oid, int has_index, int op_type,
6022  HEAP_SCANCACHE * scan_cache, int *force_count, MVCC_REEV_DATA * mvcc_reev_data,
6023  OID * new_obj_oid, OID * partition_oid, bool need_locking)
6024 {
6025  return locator_delete_force_internal (thread_p, hfid, oid, has_index, op_type, scan_cache, force_count,
6026  mvcc_reev_data, FOR_MOVE, new_obj_oid, partition_oid, need_locking);
6027 }
6028 
6029 /*
6030  * locator_delete_force_internal () - helper function of locator_delete_force
6031  *
6032  * hfid(in): Heap where the object is going to be inserted
6033  * oid(in): The object identifier
6034  * has_index(in): false if we now for sure that there is not any index on the instances of the class.
6035  * op_type(in):
6036  * scan_cache(in/out): Scan cache used to estimate the best space pages between heap changes.
6037  * force_count(in):
6038  * mvcc_reev_data(in): MVCC data
6039  * idx_action_flag(in): is moving record between partitioned table?
6040  * If FOR_MOVE, this delete&insert is caused by
6041  * 'UPDATE ... SET ...', NOT 'DELETE FROM ...'
6042  * new_obj_oid(in): next version - only to be used with records relocated in other partitions, in MVCC.
6043  * partition_oid(in): new partition class oid
6044  * need_locking(in): true, if need locking
6045  *
6046  * Note: The given object is deleted on this heap and all appropriate index entries are deleted.
6047  */
6048 static int
6049 locator_delete_force_internal (THREAD_ENTRY * thread_p, HFID * hfid, OID * oid, int has_index, int op_type,
6050  HEAP_SCANCACHE * scan_cache, int *force_count, MVCC_REEV_DATA * mvcc_reev_data,
6051  LOCATOR_INDEX_ACTION_FLAG idx_action_flag, OID * new_obj_oid, OID * partition_oid,
6052  bool need_locking)
6053 {
6054  bool isold_object; /* Make sure that this is an old object during the deletion */
6055  OID class_oid = { NULL_PAGEID, NULL_SLOTID, NULL_VOLID };
6056  /* Class identifier */
6057  char *classname; /* Classname to update */
6058  RECDES copy_recdes;
6059  int error_code = NO_ERROR;
6060  bool deleted = false;
6061  SCAN_CODE scan_code = S_SUCCESS;
6062 
6063  /* Update note : While scanning objects, the given scancache does not fix the last accessed page. So, the object must
6064  * be copied to the record descriptor. Changes : (1) variable name : peek_recdes => copy_recdes (2) function call :
6065  * heap_get_visible_version(..., PEEK, ...) => heap_get_visible_version(..., COPY, ...) (3) SCAN_CODE scan, char *new_area are added */
6066 
6067  copy_recdes.data = NULL;
6068 
6069  *force_count = 0;
6070 
6071  /*
6072  * Is the object a class ?
6073  */
6074  isold_object = true;
6075 
6076  copy_recdes.data = NULL;
6077 
6078  if (need_locking == false)
6079  {
6080  /* the reevaluation is not necessary if the object is already locked */
6081  mvcc_reev_data = NULL;
6082  }
6083 
6084  /* IMPORTANT TODO: use a different get function when need_locking==false, but make sure it gets the last version,
6085  not the visible one; we need only the last version to use it to retrieve the last version of the btree key */
6086  scan_code =
6087  locator_lock_and_get_object_with_evaluation (thread_p, oid, &class_oid, &copy_recdes, scan_cache, COPY, NULL_CHN,
6088  mvcc_reev_data, LOG_WARNING_IF_DELETED);
6089 
6090  if (scan_code == S_SUCCESS && mvcc_reev_data != NULL && mvcc_reev_data->filter_result == V_FALSE)
6091  {
6093  }
6094 
6095  if (scan_code != S_SUCCESS)
6096  {
6097  error_code = er_errid ();
6098 
6099  if (error_code == ER_HEAP_NODATA_NEWADDRESS)
6100  {
6101  isold_object = false;
6102  er_clear (); /* clear ER_HEAP_NODATA_NEWADDRESS */
6103 
6104  error_code = NO_ERROR;
6105  }
6106  else if (error_code == ER_HEAP_UNKNOWN_OBJECT || scan_code == S_DOESNT_EXIST)
6107  {
6108  isold_object = false;
6109  er_clear ();
6110 
6111  error_code = NO_ERROR;
6112  goto error;
6113  }
6114  else
6115  {
6116  /*
6117  * Problems reading the object...Maybe, the transaction should be
6118  * aborted by the caller...Quit..
6119  */
6120  if (error_code == NO_ERROR)
6121  {
6122  error_code = ER_FAILED;
6123  }
6124  goto error;
6125  }
6126  }
6127 
6128  if (isold_object == false)
6129  {
6130  OID_SET_NULL (&class_oid);
6131  }
6132 
6133  if (isold_object == true && OID_IS_ROOTOID (&class_oid))
6134  {
6135  /*
6136  * A CLASS: Remove class from catalog and
6137  * remove any indices on that class
6138  * remove XASL cache entries which is relevant with that class
6139  */
6140 
6141  /* Delete the classname entry */
6142  classname = or_class_name (&copy_recdes);
6143  assert (classname != NULL);
6144  assert (strlen (classname) < 255);
6145 
6146  /* Note: by now, the client has probably already requested this class be deleted. We try again here just to be
6147  * sure it has been marked properly. Note that we would normally want to check the return code, but we must not
6148  * check the return code for this one function in its current form, because we cannot distinguish between a class
6149  * that has already been marked deleted and a real error. */
6150  (void) xlocator_delete_class_name (thread_p, classname);
6151  /* remove from the catalog... when is not the root */
6152  if (!OID_IS_ROOTOID (oid))
6153  {
6154  error_code = catalog_delete (thread_p, oid);
6155  if (error_code != NO_ERROR)
6156  {
6157  er_log_debug (ARG_FILE_LINE, "locator_delete_force: ct_delete_catalog failed for tran %d\n",
6158  LOG_FIND_THREAD_TRAN_INDEX (thread_p));
6159  goto error;
6160  }
6161  }
6162  if (catcls_Enable)
6163  {
6164  error_code = catcls_delete_catalog_classes (thread_p, classname, oid);
6165  if (error_code != NO_ERROR)
6166  {
6167  goto error;
6168  }
6169  }
6170 
6171  /* remove XASL cache entries which is relevant with that class */
6172  if (!OID_IS_ROOTOID (oid))
6173  {
6174  xcache_remove_by_oid (thread_p, oid);
6175  }
6176 
6177  if (!OID_IS_ROOTOID (oid))
6178  {
6179  fpcache_remove_by_class (thread_p, oid);
6180  }
6181  }
6182  else
6183  {
6184  /*
6185  * Likely an INSTANCE: Apply the necessary index deletions
6186  *
6187  * If this is a server delete on an instance, the object must be locked
6188  * in exclusive mode since it is likely that we have just added an
6189  * SIX lock on the class at this moment.
6190  *
6191  * Note that we cannot have server deletes on classes.
6192  */
6193  if (isold_object == true && has_index)
6194  {
6195  /* if MVCC then delete before updating index */
6196  if (!mvcc_is_mvcc_disabled_class (&class_oid))
6197  {
6198  HEAP_OPERATION_CONTEXT delete_context;
6199 
6200  /* build operation context */
6201  heap_create_delete_context (&delete_context, hfid, oid, &class_oid, scan_cache);
6202 
6203  /* attempt delete */
6204  if (heap_delete_logical (thread_p, &delete_context) != NO_ERROR)
6205  {
6206  /*
6207  * Problems deleting the object...Maybe, the transaction should be
6208  * aborted by the caller...Quit..
6209  */
6210  error_code = er_errid ();
6211  er_log_debug (ARG_FILE_LINE, "locator_delete_force: hf_delete failed for tran %d\n",
6212  LOG_FIND_THREAD_TRAN_INDEX (thread_p));
6213  if (error_code == NO_ERROR)
6214  {
6215  error_code = ER_FAILED;
6216  }
6217  goto error;
6218  }
6219 
6220  deleted = true;
6221  }
6222 
6223  if (idx_action_flag == FOR_INSERT_OR_DELETE)
6224  {
6225  error_code =
6226  locator_add_or_remove_index (thread_p, &copy_recdes, oid, &class_oid, false, op_type, scan_cache, true,
6227  true, hfid, NULL, false, false);
6228  }
6229  else
6230  {
6231  error_code =
6232  locator_add_or_remove_index_for_moving (thread_p, &copy_recdes, oid, &class_oid, false, op_type,
6233  scan_cache, true, true, hfid, NULL, false);
6234  }
6235 
6236  if (error_code != NO_ERROR)
6237  {
6238  /*
6239  * There is an error deleting the index... Quit... The
6240  * transaction must be aborted by the caller
6241  */
6242  goto error;
6243  }
6244  }
6245 
6246  /* remove query result cache entries which are relevant with this class */
6248  {
6249  if (qexec_clear_list_cache_by_class (thread_p, &class_oid) != NO_ERROR)
6250  {
6252  "locator_delete_force: qexec_clear_list_cache_by_class failed for class { %d %d %d }\n",
6253  class_oid.pageid, class_oid.slotid, class_oid.volid);
6254  }
6255  qmgr_add_modified_class (thread_p, &class_oid);
6256  }
6257  }
6258 
6259  if (!deleted)
6260  {
6261  HEAP_OPERATION_CONTEXT delete_context;
6262 
6263  /* build operation context */
6264  heap_create_delete_context (&delete_context, hfid, oid, &class_oid, scan_cache);
6265 
6266  /* attempt delete */
6267  if (heap_delete_logical (thread_p, &delete_context) != NO_ERROR)
6268  {
6269  /*
6270  * Problems deleting the object...Maybe, the transaction should be
6271  * aborted by the caller...Quit..
6272  */
6273  er_log_debug (ARG_FILE_LINE, "locator_delete_force: hf_delete failed for tran %d\n",
6274  LOG_FIND_THREAD_TRAN_INDEX (thread_p));
6275  assert (er_errid () != NO_ERROR);
6276  error_code = er_errid ();
6277  if (error_code == NO_ERROR)
6278  {
6279  error_code = ER_FAILED;
6280  }
6281  goto error;
6282  }
6283  deleted = true;
6284  }
6285  *force_count = 1;
6286 
6287 #if defined(ENABLE_UNUSED_FUNCTION)
6288  if (isold_object == true && !OID_IS_ROOTOID (&class_oid))
6289  {
6290  /* decrease the counter of the catalog */
6291  locator_decrease_catalog_count (thread_p, &class_oid);
6292  }
6293 #endif
6294 
6295 error:
6296 
6297  return error_code;
6298 }
6299 
6300 /*
6301  * locator_delete_lob_force () - Delete all blob which is in the given object
6302  *
6303  * return: NO_ERROR if all OK, ER_ status otherwise
6304  *
6305  * thread_p(in):
6306  * class_oid(in):
6307  * oid(in):
6308  * recdes(in):
6309  */
6310 int
6312 {
6313  HEAP_CACHE_ATTRINFO attr_info;
6314  HEAP_ATTRVALUE *value;
6315  bool attr_info_inited;
6316  HEAP_SCANCACHE scan_cache;
6317  RECDES copy_recdes = RECDES_INITIALIZER;
6318  bool scan_cache_inited;
6319  bool found;
6320  int i;
6321  int error_code = NO_ERROR;
6322 
6323  assert ((class_oid != NULL) && (recdes != NULL || oid != NULL));
6324 
6325  attr_info_inited = false;
6326  scan_cache_inited = false;
6327  found = false;
6328 
6329  error_code = heap_attrinfo_start (thread_p, class_oid, -1, NULL, &attr_info);
6330  if (error_code != NO_ERROR)
6331  {
6332  goto error;
6333  }
6334  attr_info_inited = true;
6335 
6336  /* check if lob attribute exists */
6337  for (i = 0; i < attr_info.num_values; i++)
6338  {
6339  value = &attr_info.values[i];
6340  if (value->last_attrepr->type == DB_TYPE_BLOB || value->last_attrepr->type == DB_TYPE_CLOB)
6341  {
6342  found = true;
6343  break;
6344  }
6345  }
6346 
6347  if (found)
6348  {
6349  if (recdes == NULL)
6350  {
6351  SCAN_CODE scan;
6352 
6353  error_code = heap_scancache_quick_start (&scan_cache);
6354  if (error_code != NO_ERROR)
6355  {
6356  goto error;
6357  }
6358  scan_cache_inited = true;
6359 
6360  scan = heap_get_visible_version (thread_p, oid, class_oid, &copy_recdes, &scan_cache, COPY, NULL_CHN);
6361  if (scan != S_SUCCESS)
6362  {
6363  goto error;
6364  }
6365  recdes = &copy_recdes;
6366  }
6367 
6368  error_code = heap_attrinfo_delete_lob (thread_p, recdes, &attr_info);
6369  }
6370 
6371 error:
6372 
6373  if (attr_info_inited)
6374  {
6375  heap_attrinfo_end (thread_p, &attr_info);
6376  }
6377  if (scan_cache_inited)
6378  {
6379  error_code = heap_scancache_end (thread_p, &scan_cache);
6380  }
6381 
6382  return error_code;
6383 }
6384 
6385 /*
6386  * locator_force_for_multi_update () -
6387  *
6388  * return: NO_ERROR if all OK, ER_ status otherwise
6389  *
6390  * force_area(in): Copy area where objects are placed
6391  *
6392  * Note: This function update given objects that are sent by clients.
6393  * The objects are updated by multiple row update performed
6394  * on client and sent to the server through flush request.
6395  */
6396 static int
6398 {
6399  LC_COPYAREA_MANYOBJS *mobjs; /* Describe multiple objects in area */
6400  LC_COPYAREA_ONEOBJ *obj; /* Describe on object in area */
6401  RECDES recdes; /* Record descriptor for object */
6402  HEAP_SCANCACHE scan_cache;
6403  int scan_cache_inited = 0;
6404  LOG_TDES *tdes;
6405  int i;
6406  int force_count;
6407  int tran_index;
6408  int error_code = NO_ERROR;
6410  int has_index;
6411 
6412  tran_index = LOG_FIND_THREAD_TRAN_INDEX (thread_p);
6413  tdes = LOG_FIND_TDES (tran_index);
6414  if (tdes == NULL)
6415  {
6417  error_code = ER_LOG_UNKNOWN_TRANINDEX;
6418  goto error;
6419  }
6420 
6421  mobjs = LC_MANYOBJS_PTR_IN_COPYAREA (force_area);
6422 
6424  {
6425  assert (tdes->m_multiupd_stats.empty ());
6426  }
6427 
6428  if (mobjs->num_objs > 0)
6429  {
6430  int first_update_obj = -1, last_update_obj = -1;
6431 
6432  /*
6433  * Find first and last UPDATE objects
6434  */
6435  obj = LC_START_ONEOBJ_PTR_IN_COPYAREA (mobjs);
6436  obj = LC_PRIOR_ONEOBJ_PTR_IN_COPYAREA (obj);
6437  for (i = 0; i < mobjs->num_objs; i++)
6438  {
6439  obj = LC_NEXT_ONEOBJ_PTR_IN_COPYAREA (obj);
6440  if (LC_IS_FLUSH_UPDATE (obj->operation))
6441  {
6442  last_update_obj = i;
6443  if (first_update_obj == -1)
6444  {
6445  first_update_obj = i;
6446  }
6447  }
6448  }
6449  if (last_update_obj == -1)
6450  {
6451  /* this is not exactly an error case, but we somehow managed to generate a multi-update flush with no updated
6452  * objects */
6453  error_code = NO_ERROR;
6454  goto error;
6455  }
6456 
6457  /*
6458  * Flush objects
6459  */
6460  obj = LC_START_ONEOBJ_PTR_IN_COPYAREA (mobjs);
6461  obj = LC_PRIOR_ONEOBJ_PTR_IN_COPYAREA (obj);
6462  LC_RECDES_IN_COPYAREA (force_area, &recdes);
6463 
6464  for (i = 0; i < mobjs->num_objs; i++)
6465  {
6466  obj = LC_NEXT_ONEOBJ_PTR_IN_COPYAREA (obj);
6467  LC_RECDES_TO_GET_ONEOBJ (force_area, obj, &recdes);
6468 
6469  /* skip all non-updates operations and updates of class objects (non-updates operations and class objects are
6470  * already flushed in xlocator_force) */
6472  {
6473  continue;
6474  }
6475 
6476  if (!scan_cache_inited)
6477  {
6478  /* Initialize a modify scancache */
6479  error_code =
6480  locator_start_force_scan_cache (thread_p, &scan_cache, &obj->hfid, &obj->class_oid, MULTI_ROW_UPDATE);
6481  if (error_code != NO_ERROR)
6482  {
6483  goto error;
6484  }
6485  scan_cache_inited = 1;
6486  }
6487 
6488  if (locator_manyobj_flag_is_set (mobjs, START_MULTI_UPDATE) && i == first_update_obj)
6489  {
6490  repl_info = REPL_INFO_TYPE_RBR_START;
6491  }
6492  else if (locator_manyobj_flag_is_set (mobjs, END_MULTI_UPDATE) && i == last_update_obj)
6493  {
6494  repl_info = REPL_INFO_TYPE_RBR_END;
6495  }
6496  else
6497  {
6498  repl_info = REPL_INFO_TYPE_RBR_NORMAL;
6499  }
6500  has_index = LC_ONEOBJ_GET_INDEX_FLAG (obj);
6501 
6502  scan_cache.mvcc_snapshot = logtb_get_mvcc_snapshot (thread_p);
6503  if (scan_cache.mvcc_snapshot == NULL)
6504  {
6505  error_code = er_errid ();
6506  if (error_code == NO_ERROR)
6507  {
6508  error_code = ER_FAILED;
6509  }
6510 
6511  goto error;
6512  }
6513 
6514  /* update */
6515  error_code =
6516  locator_update_force (thread_p, &obj->hfid, &obj->class_oid, &obj->oid, NULL, &recdes,
6517  has_index, NULL, 0, MULTI_ROW_UPDATE, &scan_cache, &force_count, false, repl_info,
6519  if (error_code != NO_ERROR)
6520  {
6521  /*
6522  * Problems updating the object...Maybe, the transaction should be
6523  * aborted by the caller...Quit..
6524  */
6525  goto error;
6526  }
6527  } /* end-for */
6528 
6529  if (scan_cache.m_index_stats != NULL)
6530  {
6531  tdes->m_multiupd_stats += *scan_cache.m_index_stats;
6532  }
6533  locator_end_force_scan_cache (thread_p, &scan_cache);
6534  scan_cache_inited = 0;
6535  }
6536 
6538  {
6539  // *INDENT-OFF*
6540  for (const auto & it:tdes->m_multiupd_stats.get_map ())
6541  {
6542  if (!it.second.is_unique ())
6543  {
6544  BTREE_SET_UNIQUE_VIOLATION_ERROR (thread_p, NULL, NULL, &mobjs->objs.class_oid, &it.first, NULL);
6545  error_code = ER_BTREE_UNIQUE_FAILED;
6546  goto error;
6547  }
6548  error_code = logtb_tran_update_unique_stats (thread_p, it.first, it.second, true);
6549  if (error_code != NO_ERROR)
6550  {
6551  ASSERT_ERROR ();
6552  goto error;
6553  }
6554  }
6555  // *INDENT-ON*
6556  tdes->m_multiupd_stats.clear ();
6557  }
6558 
6559  return error_code;
6560 
6561 error:
6562  if (scan_cache_inited)
6563  {
6564  locator_end_force_scan_cache (thread_p, &scan_cache);
6565  }
6566 
6567  if (tdes != NULL)
6568  {
6569  tdes->m_multiupd_stats.clear ();
6570  }
6571 
6572  return error_code;
6573 }
6574 
6575 /*
6576  * locator_repl_add_error_to_copyarea () - place error info into copy area that
6577  * will be sent to client
6578  *
6579  * return:
6580  *
6581  * copy_area(out): copy area where error info will be placed
6582  * recdes(in): struct that describes copy_area
6583  * obj(in): object that describes the operation which caused an error
6584  * key_value(in): primary key value
6585  * err_code(in):
6586  * err_msg(in):
6587  */
6588 static void
6590  DB_VALUE * key_value, int err_code, const char *err_msg)
6591 {
6592  LC_COPYAREA *new_copy_area = NULL;
6593  LC_COPYAREA_MANYOBJS *reply_mobjs = NULL;
6594  LC_COPYAREA_ONEOBJ *reply_obj = NULL;
6595  char *ptr;
6596  int packed_length = 0, round_length;
6597  int prev_offset, prev_length;
6598 
6599  packed_length += OR_VALUE_ALIGNED_SIZE (key_value);
6600  packed_length += OR_INT_SIZE;
6601  packed_length += or_packed_string_length (err_msg, NULL);
6602 
6603  if (packed_length > recdes->area_size)
6604  {
6605  int new_length, nw_pagesize;
6606 
6607  prev_offset = CAST_BUFLEN (recdes->data - (*copy_area)->mem);
6608  prev_length = (*copy_area)->length;
6609 
6610  nw_pagesize = db_network_page_size ();
6611  new_length = prev_length + CEIL_PTVDIV (packed_length - recdes->area_size, nw_pagesize) * nw_pagesize;
6612 
6613  new_copy_area = locator_reallocate_copy_area_by_length (*copy_area, new_length);
6614  if (new_copy_area == NULL)
6615  {
6616  /* failed to reallocate copy area. skip the current error */
6617  return;
6618  }
6619  else
6620  {
6621  recdes->data = new_copy_area->mem + prev_offset;
6622  recdes->area_size += CAST_BUFLEN (new_copy_area->length - prev_length);
6623  *copy_area = new_copy_area;
6624  }
6625  }
6626 
6627  reply_mobjs = LC_MANYOBJS_PTR_IN_COPYAREA (*copy_area);
6628  reply_obj = LC_FIND_ONEOBJ_PTR_IN_COPYAREA (reply_mobjs, reply_mobjs->num_objs);
6629 
6630  ptr = recdes->data;
6631  ptr = or_pack_mem_value (ptr, key_value, NULL);
6632  ptr = or_pack_int (ptr, err_code);
6633  ptr = or_pack_string (ptr, err_msg);
6634 
6635  reply_obj->length = CAST_BUFLEN (ptr - recdes->data);
6636  reply_obj->offset = CAST_BUFLEN (recdes->data - (*copy_area)->mem);
6637  COPY_OID (&reply_obj->class_oid, &obj->class_oid);
6638  reply_obj->operation = obj->operation;
6639 
6640  reply_mobjs->num_objs++;
6641 
6642  recdes->length = reply_obj->length;
6643  round_length = DB_ALIGN (recdes->length, MAX_ALIGNMENT);
6644 #if !defined(NDEBUG)
6645  /* suppress valgrind UMW error */
6646  memset (recdes->data + recdes->length, 0, MIN (round_length - recdes->length, recdes->area_size - recdes->length));
6647 #endif
6648  recdes->data += round_length;
6649  recdes->area_size -= round_length + sizeof (*reply_obj);
6650 }
6651 
6652 /*
6653  * locator_repl_prepare_force () - prepare required info for each operation
6654  *
6655  * return: NO_ERROR if all OK, ER_ status otherwise
6656  *
6657  * thread_p(in):
6658  * obj(in): object that describes the current operation
6659  * old_recdes(out): original record needed for update operation
6660  * recdes(in/out): record to be applied
6661  * key_value(in): primary key value
6662  * force_scancache(in):
6663  */
6664 static int
6666  DB_VALUE * key_value, HEAP_SCANCACHE * force_scancache)
6667 {
6668  int error_code = NO_ERROR;
6669  int last_repr_id = -1;
6670  int old_chn = -1;
6671  BTID btid;
6672  SCAN_CODE scan;
6673  SCAN_OPERATION_TYPE scan_op_type;
6674 
6675  if (obj->operation == LC_FLUSH_DELETE)
6676  {
6677  scan_op_type = S_DELETE;
6678  }
6679  else if (LC_IS_FLUSH_UPDATE (obj->operation) == true)
6680  {
6681  scan_op_type = S_UPDATE;
6682  }
6683 
6684  if (obj->operation != LC_FLUSH_DELETE)
6685  {
6686  last_repr_id = heap_get_class_repr_id (thread_p, &obj->class_oid);
6687  if (last_repr_id == 0)
6688  {
6690  return ER_CT_INVALID_REPRID;
6691  }
6692 
6693  error_code = or_replace_rep_id (recdes, last_repr_id);
6694  if (error_code != NO_ERROR)
6695  {
6696  return error_code;
6697  }
6698  }
6699 
6700  if (LC_IS_FLUSH_INSERT (obj->operation) == false)
6701  {
6702  error_code = btree_get_pkey_btid (thread_p, &obj->class_oid, &btid);
6703  if (error_code != NO_ERROR)
6704  {
6705  return error_code;
6706  }
6707 
6708  if (xbtree_find_unique (thread_p, &btid, scan_op_type, key_value, &obj->class_oid, &obj->oid, true) !=
6710  {
6712  return ER_OBJ_OBJECT_NOT_FOUND;
6713  }
6714  }
6715 
6716 
6717  if (LC_IS_FLUSH_UPDATE (obj->operation) == true)
6718  {
6719  assert (OID_ISNULL (&obj->oid) != true);
6720 
6721  scan =
6722  heap_get_visible_version (thread_p, &obj->oid, &obj->class_oid, old_recdes, force_scancache, PEEK, NULL_CHN);
6723 
6724  if (scan != S_SUCCESS)
6725  {
6726  assert (er_errid () != NO_ERROR);
6727  error_code = er_errid ();
6728  if (error_code == ER_HEAP_UNKNOWN_OBJECT)
6729  {
6730  er_log_debug (ARG_FILE_LINE, "locator_repl_prepare_force : unknown oid ( %d|%d|%d )\n",
6731  obj->oid.pageid, obj->oid.slotid, obj->oid.volid);
6732  }
6733 
6734  return error_code;
6735  }
6736 
6737  old_chn = or_chn (old_recdes);
6738 
6739  error_code = or_replace_chn (recdes, old_chn + 1);
6740  if (error_code != NO_ERROR)
6741  {
6742  return error_code;
6743  }
6744  }
6745 
6746  return NO_ERROR;
6747 }
6748 
6749 /*
6750  * locator_repl_get_key_value () - read pkey value from copy_area
6751  *
6752  * return: length of unpacked key value
6753  *
6754  * key_value(out): primary key value
6755  * force_area(in):
6756  * obj(in): object that describes memory location of key_value
6757  *
6758  */
6759 static int
6761 {
6762  char *ptr, *start_ptr;
6763 
6764  start_ptr = ptr = force_area->mem + obj->offset;
6765  ptr = or_unpack_mem_value (ptr, key_value);
6766 
6767  return (int) (ptr - start_ptr);
6768 }
6769 
6770 /*
6771  * xlocator_force () - Updates objects sent by log applier
6772  *
6773  * return: NO_ERROR if all OK, ER_ status otherwise
6774  *
6775  * force_area(in): Copy area where objects are placed
6776  *
6777  * Note: This function applies all the desired operations on each of
6778  * object placed in the force_area.
6779  */
6780 int
6781 xlocator_repl_force (THREAD_ENTRY * thread_p, LC_COPYAREA * force_area, LC_COPYAREA ** reply_area)
6782 {
6783  LC_COPYAREA_MANYOBJS *mobjs; /* Describe multiple objects in area */
6784  LC_COPYAREA_ONEOBJ *obj; /* Describe on object in area */
6785  RECDES recdes; /* Record descriptor for object */
6786  RECDES old_recdes = RECDES_INITIALIZER;
6787  RECDES reply_recdes; /* Describe copy area for reply */
6788  int i;
6789  HEAP_SCANCACHE *force_scancache = NULL;
6790  HEAP_SCANCACHE scan_cache;
6791  int force_count;
6792  LOG_LSA lsa, oneobj_lsa;
6793  int error_code = NO_ERROR;
6794  int pruning_type = 0;
6795  int num_continue_on_error = 0;
6796  DB_VALUE key_value;
6797  int packed_key_value_len;
6798  HFID prev_hfid = HFID_INITIALIZER;
6799  int has_index;
6800 
6801  /* need to start a topop to ensure the atomic operation. */
6802  error_code = xtran_server_start_topop (thread_p, &lsa);
6803  if (error_code != NO_ERROR)
6804  {
6805  return error_code;
6806  }
6807 
6808  mobjs = LC_MANYOBJS_PTR_IN_COPYAREA (force_area);
6809 
6810  obj = LC_START_ONEOBJ_PTR_IN_COPYAREA (mobjs);
6811  obj = LC_PRIOR_ONEOBJ_PTR_IN_COPYAREA (obj);
6812 
6813  HFID_SET_NULL (&prev_hfid);
6814  db_value_put_null (&key_value);
6815 
6816  LC_RECDES_IN_COPYAREA (*reply_area, &reply_recdes);
6817 
6818  for (i = 0; i < mobjs->num_objs; i++)
6819  {
6820  er_clear ();
6821 
6822  obj = LC_NEXT_ONEOBJ_PTR_IN_COPYAREA (obj);
6823 
6824  packed_key_value_len = locator_repl_get_key_value (&key_value, force_area, obj);
6825 
6826  LC_REPL_RECDES_FOR_ONEOBJ (force_area, obj, packed_key_value_len, &recdes);
6827 
6828  error_code = heap_get_class_info (thread_p, &obj->class_oid, &obj->hfid, NULL, NULL);
6829  if (error_code != NO_ERROR)
6830  {
6831  goto exit_on_error;
6832  }
6833 
6834  if (HFID_EQ (&prev_hfid, &obj->hfid) != true && force_scancache != NULL)
6835  {
6836  locator_end_force_scan_cache (thread_p, force_scancache);
6837  force_scancache = NULL;
6838  }
6839 
6840  if (force_scancache == NULL)
6841  {
6842  /* Initialize a modify scancache */
6843  error_code =
6844  locator_start_force_scan_cache (thread_p, &scan_cache, &obj->hfid, &obj->class_oid, SINGLE_ROW_UPDATE);
6845  if (error_code != NO_ERROR)
6846  {
6847  goto exit_on_error;
6848  }
6849  force_scancache = &scan_cache;
6850  HFID_COPY (&prev_hfid, &obj->hfid);
6851  }
6852 
6853  error_code = xtran_server_start_topop (thread_p, &oneobj_lsa);
6854  if (error_code != NO_ERROR)
6855  {
6856  goto exit_on_error;
6857  }
6858 
6859  error_code = locator_repl_prepare_force (thread_p, obj, &old_recdes, &recdes, &key_value, force_scancache);
6860  if (error_code == NO_ERROR)
6861  {
6862  has_index = LC_ONEOBJ_GET_INDEX_FLAG (obj);
6863 
6864  switch (obj->operation)
6865  {
6866  case LC_FLUSH_INSERT:
6867  case LC_FLUSH_INSERT_PRUNE:
6869  pruning_type = locator_area_op_to_pruning_type (obj->operation);
6870  error_code =
6871  locator_insert_force (thread_p, &obj->hfid, &obj->class_oid, &obj->oid, &recdes, has_index,
6872  SINGLE_ROW_INSERT, force_scancache, &force_count, pruning_type, NULL, NULL,
6873  UPDATE_INPLACE_NONE, NULL, false, false);
6874 
6875  if (error_code == NO_ERROR)
6876  {
6877  /* monitor */
6879  }
6880  break;
6881 
6882  case LC_FLUSH_UPDATE:
6883  case LC_FLUSH_UPDATE_PRUNE:
6885  pruning_type = locator_area_op_to_pruning_type (obj->operation);
6886  error_code =
6887  locator_update_force (thread_p, &obj->hfid, &obj->class_oid, &obj->oid, NULL, &recdes, has_index,
6888  NULL, 0, SINGLE_ROW_UPDATE, force_scancache, &force_count, false,
6889  REPL_INFO_TYPE_RBR_NORMAL, pruning_type, NULL, NULL, UPDATE_INPLACE_NONE, true);
6890 
6891  if (error_code == NO_ERROR)
6892  {
6893  /* monitor */
6895  }
6896  break;
6897 
6898  case LC_FLUSH_DELETE:
6899  error_code =
6900  locator_delete_force (thread_p, &obj->hfid, &obj->oid, has_index, SINGLE_ROW_DELETE, force_scancache,
6901  &force_count, NULL, true);
6902 
6903  if (error_code == NO_ERROR)
6904  {
6905  /* monitor */
6907  }
6908  break;
6909 
6910  default:
6911  /*
6912  * Problems forcing the object. Don't known what flush/force operation
6913  * to execute on the object... This is a system error...
6914  * Maybe, the transaction should be aborted by the caller...Quit..
6915  */
6917  obj->oid.pageid, obj->oid.slotid);
6918  error_code = ER_LC_BADFORCE_OPERATION;
6919  break;
6920  } /* end-switch */
6921  }
6922 
6923  if (error_code != NO_ERROR)
6924  {
6925  assert (er_errid () != NO_ERROR);
6926  locator_repl_add_error_to_copyarea (reply_area, &reply_recdes, obj, &key_value, er_errid (), er_msg ());
6927 
6928  error_code = NO_ERROR;
6929  num_continue_on_error++;
6930 
6931  (void) xtran_server_end_topop (thread_p, LOG_RESULT_TOPOP_ABORT, &oneobj_lsa);
6932  }
6933  else
6934  {
6935  (void) xtran_server_end_topop (thread_p, LOG_RESULT_TOPOP_ATTACH_TO_OUTER, &oneobj_lsa);
6936  }
6937  pr_clear_value (&key_value);
6938  }
6939 
6940  if (force_scancache != NULL)
6941  {
6942  locator_end_force_scan_cache (thread_p, force_scancache);
6943  }
6944 
6946 
6947  if (num_continue_on_error > 0)
6948  {
6950  }
6951 
6952  return error_code;
6953 
6954 exit_on_error:
6955  assert_release (error_code == ER_FAILED || error_code == er_errid ());
6956 
6957  if (DB_IS_NULL (&key_value) == false)
6958  {
6959  pr_clear_value (&key_value);
6960  }
6961 
6962  if (force_scancache != NULL)
6963  {
6964  locator_end_force_scan_cache (thread_p, force_scancache);
6965  }
6966 
6967  (void) xtran_server_end_topop (thread_p, LOG_RESULT_TOPOP_ABORT, &lsa);
6968 
6969  return error_code;
6970 }
6971 
6972 /*
6973  * xlocator_force () - Updates objects placed on page
6974  *
6975  * return: NO_ERROR if all OK, ER_ status otherwise
6976  *
6977  * force_area(in): Copy area where objects are placed
6978  *
6979  * Note: This function applies all the desired operations on each of
6980  * object placed in the force_area.
6981  */
6982 int
6983 xlocator_force (THREAD_ENTRY * thread_p, LC_COPYAREA * force_area, int num_ignore_error, int *ignore_error_list)
6984 {
6985  LC_COPYAREA_MANYOBJS *mobjs; /* Describe multiple objects in area */
6986  LC_COPYAREA_ONEOBJ *obj; /* Describe on object in area */
6987  RECDES recdes; /* Record descriptor for object */
6988  int i;
6989  HEAP_SCANCACHE *force_scancache = NULL;
6990  HEAP_SCANCACHE scan_cache;
6991  int force_count;
6992  LOG_LSA lsa, oneobj_lsa;
6993  int error_code = NO_ERROR;
6994  int pruning_type = 0;
6995  int has_index;
6996 
6997  /* need to start a topop to ensure the atomic operation. */
6998  error_code = xtran_server_start_topop (thread_p, &lsa);
6999  if (error_code != NO_ERROR)
7000  {
7001  return error_code;
7002  }
7003 
7004  mobjs = LC_MANYOBJS_PTR_IN_COPYAREA (force_area);
7005  obj = LC_START_ONEOBJ_PTR_IN_COPYAREA (mobjs);
7006  obj = LC_PRIOR_ONEOBJ_PTR_IN_COPYAREA (obj);
7007  LC_RECDES_IN_COPYAREA (force_area, &recdes);
7008 
7009  for (i = 0; i < mobjs->num_objs; i++)
7010  {
7011  obj = LC_NEXT_ONEOBJ_PTR_IN_COPYAREA (obj);
7012  LC_RECDES_TO_GET_ONEOBJ (force_area, obj, &recdes);
7013 
7014  if (i == 0)
7015  {
7016  /*
7017  * Initialize a modify scancache
7018  */
7019  error_code =
7020  locator_start_force_scan_cache (thread_p, &scan_cache, &obj->hfid, &obj->class_oid, SINGLE_ROW_UPDATE);
7021  if (error_code != NO_ERROR)
7022  {
7023  goto error;
7024  }
7025  force_scancache = &scan_cache;
7026  }
7027 
7028  has_index = LC_ONEOBJ_GET_INDEX_FLAG (obj);
7029 
7030  /* For multi update, we're just interested in the INSERT and DELETE operations here, which were generated by
7031  * triggers operating on the same class that is being updated; treat these operations as single row and skip all
7032  * updates. Also, for multi UPDATE operations, the class objects should be flushed here as single row. Instance
7033  * updates will be handled by locator_force_for_multi_update() */
7035  && !OID_EQ (&obj->class_oid, oid_Root_class_oid))
7036  {
7037  continue;
7038  }
7039 
7040  bool topop_started = false;
7041  if (LOG_CHECK_LOG_APPLIER (thread_p) || num_ignore_error > 0)
7042  {
7043  error_code = xtran_server_start_topop (thread_p, &oneobj_lsa);
7044  if (error_code != NO_ERROR)
7045  {
7046  goto error;
7047  }
7048  else
7049  {
7050  topop_started = true;
7051  }
7052  }
7053 
7054  /* delete old row must be set to true for system classes and false for others, therefore it must be updated for
7055  * each object. */
7056 
7057  switch (obj->operation)
7058  {
7059  case LC_FLUSH_INSERT:
7060  case LC_FLUSH_INSERT_PRUNE:
7062  pruning_type = locator_area_op_to_pruning_type (obj->operation);
7063  error_code =
7064  locator_insert_force (thread_p, &obj->hfid, &obj->class_oid, &obj->oid, &recdes, has_index,
7065  SINGLE_ROW_INSERT, force_scancache, &force_count, pruning_type, NULL, NULL,
7066  UPDATE_INPLACE_NONE, NULL, false, false);
7067 
7068  if (error_code == NO_ERROR)
7069  {
7070  /* monitor */
7072  }
7073  break;
7074 
7075  case LC_FLUSH_UPDATE:
7076  case LC_FLUSH_UPDATE_PRUNE:
7078  pruning_type = locator_area_op_to_pruning_type (obj->operation);
7079  error_code =
7080  locator_update_force (thread_p, &obj->hfid, &obj->class_oid, &obj->oid, NULL, &recdes,
7081  has_index, NULL, 0, SINGLE_ROW_UPDATE, force_scancache, &force_count, false,
7082  REPL_INFO_TYPE_RBR_NORMAL, pruning_type, NULL, NULL, UPDATE_INPLACE_NONE, true);
7083 
7084  if (error_code == NO_ERROR)
7085  {
7086  /* monitor */
7088  }
7089  break;
7090 
7091  case LC_FLUSH_DELETE:
7092  error_code =
7093  locator_delete_force (thread_p, &obj->hfid, &obj->oid, has_index, SINGLE_ROW_DELETE, force_scancache,
7094  &force_count, NULL, true);
7095 
7096  if (error_code == NO_ERROR)
7097  {
7098  /* monitor */
7100  }
7101  break;
7102 
7103  default:
7104  /*
7105  * Problems forcing the object. Don't known what flush/force operation
7106  * to execute on the object... This is a system error...
7107  * Maybe, the transaction should be aborted by the caller...Quit..
7108  */
7110  obj->oid.pageid, obj->oid.slotid);
7111  error_code = ER_LC_BADFORCE_OPERATION;
7112  break;
7113  } /* end-switch */
7114 
7115  if (LOG_CHECK_LOG_APPLIER (thread_p) || num_ignore_error > 0)
7116  {
7117  bool need_to_abort_oneobj = false;
7118 
7119  if (error_code != NO_ERROR)
7120  {
7121  if (LOG_CHECK_LOG_APPLIER (thread_p))
7122  {
7123  need_to_abort_oneobj = true;
7124  }
7125  else
7126  {
7127  error_code = locator_filter_errid (thread_p, num_ignore_error, ignore_error_list);
7128  if (error_code == NO_ERROR)
7129  {
7130  /* error is filtered out */
7131  OID_SET_NULL (&obj->oid);
7132  need_to_abort_oneobj = true;
7133  }
7134  }
7135  }
7136 
7137  if (topop_started)
7138  {
7139  LOG_RESULT_TOPOP result_topop =
7141  (void) xtran_server_end_topop (thread_p, result_topop, &oneobj_lsa);
7142  }
7143  }
7144 
7145  if (error_code != NO_ERROR)
7146  {
7147  /*
7148  * Problems... Maybe, the transaction should
7149  * be aborted by the caller...Quit..
7150  */
7151  goto error;
7152  }
7153  } /* end-for */
7154 
7155  if (force_scancache != NULL)
7156  {
7157  locator_end_force_scan_cache (thread_p, force_scancache);
7158  force_scancache = NULL;
7159  }
7160 
7161  /* handle multi-update case */
7163  {
7164  error_code = locator_force_for_multi_update (thread_p, force_area);
7165  if (error_code != NO_ERROR)
7166  {
7167  goto error;
7168  }
7169  }
7170 
7172 
7173  return error_code;
7174 
7175 error:
7176 
7177  /* The reevaluation at update phase of update is currently disabled */
7179  assert_release (error_code == ER_FAILED || error_code == er_errid ());
7180 
7181  if (force_scancache != NULL)
7182  {
7183  locator_end_force_scan_cache (thread_p, force_scancache);
7184  }
7185 
7186  (void) xtran_server_end_topop (thread_p, LOG_RESULT_TOPOP_ABORT, &lsa);
7187 
7188  return error_code;
7189 }
7190 
7191 /*
7192  * locator_allocate_copy_area_by_attr_info () - Transforms attribute
7193  * information into a disk representation and allocates a
7194  * LC_COPYAREA big enough to fit the representation
7195  *
7196  * return: the allocated LC_COPYAREA if all OK, NULL otherwise
7197  *
7198  * attr_info(in/out): Attribute information
7199  * (Set as a side effect to fill the rest of values)
7200  * old_recdes(in): The old representation of the object or NULL if this is a
7201  * new object (to be inserted).
7202  * new_recdes(in): The resulting new representation of the object.
7203  * copyarea_length_hint(in): An estimated size for the LC_COPYAREA or -1 if
7204  * an estimated size is not known.
7205  * lob_create_flag(in) :
7206  *
7207  * Note: The allocated should be freed by using locator_free_copy_area ()
7208  */
7209 LC_COPYAREA *
7211  RECDES * new_recdes, const int copyarea_length_hint, int lob_create_flag)
7212 {
7213  LC_COPYAREA *copyarea = NULL;
7214  int copyarea_length = copyarea_length_hint <= 0 ? DB_PAGESIZE : copyarea_length_hint;
7215  SCAN_CODE scan = S_DOESNT_FIT;
7216  // *INDENT-OFF*
7218  // *INDENT-ON*
7219 
7220  new_recdes->data = NULL;
7221  new_recdes->area_size = 0;
7222 
7223  copyarea = locator_allocate_copy_area_by_length (copyarea_length);
7224  if (copyarea == NULL)
7225  {
7226  return NULL;
7227  }
7228 
7229  assert (copyarea->length > 0);
7230  build_record.set_external_buffer (copyarea->mem, (size_t) copyarea->length);
7231 
7232  new_recdes->data = copyarea->mem;
7233  new_recdes->area_size = copyarea->length;
7234 
7235  if (lob_create_flag == LOB_FLAG_EXCLUDE_LOB)
7236  {
7237  scan = heap_attrinfo_transform_to_disk_except_lob (thread_p, attr_info, old_recdes, &build_record);
7238  }
7239  else
7240  {
7241  scan = heap_attrinfo_transform_to_disk (thread_p, attr_info, old_recdes, &build_record);
7242  }
7243  if (scan != S_SUCCESS)
7244  {
7245  /* Get the real length used in the copy area */
7246  copyarea_length = copyarea->length;
7247  locator_free_copy_area (copyarea);
7248  return NULL;
7249  }
7250 
7251  char *allocated_data = NULL;
7252  size_t allocated_size = 0;
7253  build_record.release_buffer (allocated_data, allocated_size);
7254  if (allocated_data != NULL)
7255  {
7256  assert (allocated_size > (size_t) copyarea_length);
7257  locator_free_copy_area (copyarea);
7258 
7259  copyarea_length = DB_ALIGN ((int) allocated_size, DB_PAGESIZE);
7260  copyarea = locator_allocate_copy_area_by_length (copyarea_length);
7261  if (copyarea == NULL)
7262  {
7263  return NULL;
7264  }
7265  std::memcpy (copyarea->mem, allocated_data, build_record.get_size ());
7266 
7267  free (allocated_data); // c-style allocator was used
7268  }
7269 
7270  *new_recdes = build_record.get_recdes ();
7271  new_recdes->data = copyarea->mem;
7272  new_recdes->area_size = copyarea->length;
7273  return copyarea;
7274 }
7275 
7276 /*
7277  * locator_attribute_info_force () - Force an object represented by attribute
7278  * information structure
7279  *
7280  * return: NO_ERROR if all OK, ER_ status otherwise
7281  *
7282  * hfid(in): Where of the object
7283  * oid(in/out): The object identifier
7284  * (Set as a side effect when operation is insert)
7285  * attr_info(in/out): Attribute information
7286  * (Set as a side effect to fill the rest of values)
7287  * att_id(in): Updated attr id array
7288  * n_att_id(in/out): Updated attr id array length
7289  * (Set as a side effect to fill the rest of values)
7290  * operation(in): Type of operation (either LC_FLUSH_INSERT,
7291  * LC_FLUSH_UPDATE, or LC_FLUSH_DELETE)
7292  * op_type(in):
7293  * scan_cache(in):
7294  * force_count(in):
7295  * not_check_fk(in):
7296  * pruning_type(in):
7297  * pcontext(in): partition pruning context
7298  * func_preds(in): cached function index expressions
7299  * mvcc_reev_data(in): MVCC reevaluation data
7300  * force_in_place(in): if UPDATE_INPLACE_NONE then the 'in place' will not be
7301  * forced and the update style will be decided in this
7302  * function. Otherwise the update of the instance will be
7303  * made in place and according to provided style.
7304  * need_locking(in): true, if need locking
7305  *
7306  * Note: Force an object represented by an attribute information structure.
7307  * For insert the oid is set as a side effect.
7308  * For delete, the attr_info does not need to be given.
7309  */
7310 int
7312  ATTR_ID * att_id, int n_att_id, LC_COPYAREA_OPERATION operation, int op_type,
7313  HEAP_SCANCACHE * scan_cache, int *force_count, bool not_check_fk,
7314  REPL_INFO_TYPE repl_info, int pruning_type, PRUNING_CONTEXT * pcontext,
7315  FUNC_PRED_UNPACK_INFO * func_preds, MVCC_REEV_DATA * mvcc_reev_data,
7316  UPDATE_INPLACE_STYLE force_update_inplace, RECDES * rec_descriptor, bool need_locking)
7317 {
7318  LC_COPYAREA *copyarea = NULL;
7319  RECDES new_recdes;
7320  SCAN_CODE scan = S_SUCCESS; /* Scan return value for next operation */
7321  RECDES copy_recdes;
7322  RECDES *old_recdes = NULL;
7323  int error_code = NO_ERROR;
7324  HFID class_hfid;
7325  OID class_oid;
7326  MVCC_SNAPSHOT *saved_mvcc_snapshot = NULL;
7327 
7328  /*
7329  * While scanning objects, the given scancache does not fix the last
7330  * accessed page. So, the object must be copied to the record descriptor.
7331  */
7332  copy_recdes.data = NULL;
7333 
7334  /* Backup the provided class_oid and class_hfid because the locator actions bellow will change them if this is a
7335  * pruning operation. This changes must not be reflected in the calls to this function. */
7336  HFID_COPY (&class_hfid, hfid);
7337  if (attr_info != NULL)
7338  {
7339  COPY_OID (&class_oid, &attr_info->class_oid);
7340  }
7341  switch (operation)
7342  {
7343  case LC_FLUSH_UPDATE:
7344  case LC_FLUSH_UPDATE_PRUNE:
7346  /* MVCC snapshot no needed for now scan_cache->mvcc_snapshot = logtb_get_mvcc_snapshot (thread_p); */
7347  if (rec_descriptor != NULL)
7348  {
7349  copy_recdes = *rec_descriptor;
7350  }
7351  else if (HEAP_IS_UPDATE_INPLACE (force_update_inplace) || need_locking == false)
7352  {
7353  HEAP_GET_CONTEXT context;
7354 
7355  /* don't consider visiblity, just get the last version of the object */
7356  heap_init_get_context (thread_p, &context, oid, &class_oid, &copy_recdes, scan_cache, COPY, NULL_CHN);
7357  scan = heap_get_last_version (thread_p, &context);
7358  heap_clean_get_context (thread_p, &context);
7359 
7360  assert ((lock_get_object_lock (oid, &class_oid) >= X_LOCK)
7361  || (lock_get_object_lock (&class_oid, oid_Root_class_oid) >= X_LOCK));
7362  }
7363  else
7364  {
7365  /* The oid has been already locked in select phase, however need to get the last object that may differ by
7366  * the current one in case that transaction updates same OID many times during command execution */
7367  /* TODO: investigate if this is still true */
7368  if (scan_cache && scan_cache->mvcc_snapshot != NULL)
7369  {
7370  /* Why is snapshot set to NULL? */
7371  saved_mvcc_snapshot = scan_cache->mvcc_snapshot;
7372  scan_cache->mvcc_snapshot = NULL;
7373  }
7374 
7375  scan = locator_lock_and_get_object (thread_p, oid, &class_oid, &copy_recdes, scan_cache, X_LOCK, COPY,
7377  if (saved_mvcc_snapshot != NULL)
7378  {
7379  scan_cache->mvcc_snapshot = saved_mvcc_snapshot;
7380  }
7381  }
7382 
7383  if (scan == S_SUCCESS)
7384  {
7385  /* do nothing for the moment */
7386  }
7387  else if (scan == S_ERROR || scan == S_DOESNT_FIT)
7388  {
7389  /* Whenever an error including an interrupt was broken out, quit the update. */
7390  return ER_FAILED;
7391  }
7392  else if (scan == S_DOESNT_EXIST)
7393  {
7394  int err_id = er_errid ();
7395  if (err_id == ER_HEAP_NODATA_NEWADDRESS)
7396  {
7397  /* it is an immature record. go ahead to update */
7398  er_clear (); /* clear ER_HEAP_NODATA_NEWADDRESS */
7399  }
7400  else
7401  {
7402  return ((err_id == NO_ERROR) ? ER_HEAP_UNKNOWN_OBJECT : err_id); /* other errors should return S_ERROR? */
7403  }
7404  }
7405  else if (scan == S_SNAPSHOT_NOT_SATISFIED)
7406  {
7407  return ER_FAILED;
7408  }
7409  else
7410  {
7411  assert (false);
7412  return ER_FAILED;
7413  }
7414 
7415  old_recdes = &copy_recdes;
7416 
7417  /* Fall through */
7418 
7419  case LC_FLUSH_INSERT:
7420  case LC_FLUSH_INSERT_PRUNE:
7422  copyarea =
7423  locator_allocate_copy_area_by_attr_info (thread_p, attr_info, old_recdes, &new_recdes, -1,
7425  if (copyarea == NULL)
7426  {
7427  error_code = ER_FAILED;
7428  break;
7429  }
7430 
7431  /* Assume that it has indices */
7432  if (LC_IS_FLUSH_INSERT (operation))
7433  {
7434  error_code =
7435  locator_insert_force (thread_p, &class_hfid, &class_oid, oid, &new_recdes, true, op_type, scan_cache,
7436  force_count, pruning_type, pcontext, func_preds, UPDATE_INPLACE_NONE, NULL, false,
7437  false);
7438  }
7439  else
7440  {
7441  int has_index;
7442 
7443  assert (LC_IS_FLUSH_UPDATE (operation));
7444 
7445  /* MVCC snapshot no needed for now scan_cache->mvcc_snapshot = logtb_get_mvcc_snapshot (thread_p); */
7446  has_index = LC_FLAG_HAS_INDEX;
7447  if (heap_attrinfo_check_unique_index (thread_p, attr_info, att_id, n_att_id))
7448  {
7449  has_index |= LC_FLAG_HAS_UNIQUE_INDEX;
7450  }
7451 
7452  error_code =
7453  locator_update_force (thread_p, &class_hfid, &class_oid, oid, old_recdes, &new_recdes, has_index,
7454  att_id, n_att_id, op_type, scan_cache, force_count, not_check_fk, repl_info,
7455  pruning_type, pcontext, mvcc_reev_data, force_update_inplace, need_locking);
7456  if (error_code != NO_ERROR)
7457  {
7458  ASSERT_ERROR ();
7459  }
7460  }
7461 
7462  if (copyarea != NULL)
7463  {
7464  locator_free_copy_area (copyarea);
7465  copyarea = NULL;
7466  new_recdes.data = NULL;
7467  new_recdes.area_size = 0;
7468  }
7469  break;
7470 
7471  case LC_FLUSH_DELETE:
7472  error_code =
7473  locator_delete_force (thread_p, &class_hfid, oid, true, op_type, scan_cache, force_count, mvcc_reev_data,
7474  need_locking);
7475  break;
7476 
7477  default:
7478  /*
7479  * Problems forcing the object. Don't known what flush/force operation
7480  * to execute on the object... This is a system error...
7481  * Maybe, the transaction should be aborted by the caller...Quit..
7482  */
7484  oid->slotid);
7485  error_code = ER_LC_BADFORCE_OPERATION;
7486  break;
7487  }
7488 
7489  return error_code;
7490 }
7491 
7492 /*
7493  * locator_was_index_already_applied () - Check B-Tree was already added
7494  * or removed entries
7495  *
7496  * return: true if index was already applied
7497  *
7498  * index_attrinfo(in): information of indices
7499  * btid(in): btid of index
7500  * pos(in): index position on indices
7501  *
7502  * Note: B-Tree can be shared by constraints (PK, or FK). The shared B-Tree can
7503  * be added or removed entries one more times during one INSERT or DELETE
7504  * statement is executing. Therefore, we need to check B-Tree was already added
7505  * or removed entries.
7506  */
7507 static bool
7509 {
7510  OR_INDEX *index;
7511  int i;
7512 
7513  for (i = 0; i < pos; i++)
7514  {
7515  index = &(index_attrinfo->last_classrepr->indexes[i]);
7516  if (BTID_IS_EQUAL (btid, &index->btid))
7517  {
7518  return true;
7519  }
7520  }
7521 
7522  return false;
7523 }
7524 
7525 /*
7526  * locator_add_or_remove_index () - Add or remove index entries
7527  *
7528  * return: NO_ERROR if all OK, ER_ status otherwise
7529  *
7530  * recdes(in): The object
7531  * inst_oid(in): The object identifier
7532  * class_oid(in): The class object identifier
7533  * is_insert(in): whether to add or remove the object from the indexes
7534  * op_type(in):
7535  * scan_cache(in):
7536  * datayn(in): true if the target object is "data",
7537  * false if the target object is "schema"
7538  * need_replication(in): true if replication is needed
7539  * hfid(in):
7540  * func_preds(in): cached function index expressions
7541  *
7542  * Note:Either insert indices (in_insert) or delete indices.
7543  */
7544 int
7545 locator_add_or_remove_index (THREAD_ENTRY * thread_p, RECDES * recdes, OID * inst_oid, OID * class_oid, int is_insert,
7546  int op_type, HEAP_SCANCACHE * scan_cache, bool datayn, bool need_replication, HFID * hfid,
7547  FUNC_PRED_UNPACK_INFO * func_preds, bool has_BU_lock, bool skip_checking_fk)
7548 {
7549  return locator_add_or_remove_index_internal (thread_p, recdes, inst_oid, class_oid, is_insert, op_type, scan_cache,
7550  datayn, need_replication, hfid, func_preds, FOR_INSERT_OR_DELETE,
7551  has_BU_lock, skip_checking_fk);
7552 }
7553 
7554 /*
7555  * locator_add_or_remove_index_for_moving () - Add or remove index entries
7556  * To move record between partitions.
7557  *
7558  * return: NO_ERROR if all OK, ER_ status otherwise
7559  *
7560  * recdes(in): The object
7561  * inst_oid(in): The object identifier
7562  * class_oid(in): The class object identifier
7563  * is_insert(in): whether to add or remove the object from the indexes
7564  * op_type(in):
7565  * scan_cache(in):
7566  * datayn(in): true if the target object is "data",
7567  * false if the target object is "schema"
7568  * need_replication(in): true if replication is needed
7569  * hfid(in):
7570  * func_preds(in): cached function index expressions
7571  *
7572  * Note:Either insert indices (in_insert) or delete indices.
7573  */
7574 static int
7576  int is_insert, int op_type, HEAP_SCANCACHE * scan_cache, bool datayn,
7577  bool need_replication, HFID * hfid, FUNC_PRED_UNPACK_INFO * func_preds,
7578  bool has_BU_lock)
7579 {
7580  return locator_add_or_remove_index_internal (thread_p, recdes, inst_oid, class_oid, is_insert, op_type, scan_cache,
7581  datayn, need_replication, hfid, func_preds, FOR_MOVE, has_BU_lock,
7582  false);
7583 }
7584 
7585 /*
7586  * locator_add_or_remove_index_internal () - helper function for
7587  * locator_add_or_remove_index () and
7588  * locator_add_or_remove_index_for_moving ()
7589  *
7590  * return: NO_ERROR if all OK, ER_ status otherwise
7591  *
7592  * recdes(in): The object
7593  * inst_oid(in): The object identifier
7594  * class_oid(in): The class object identifier
7595  * is_insert(in): whether to add or remove the object from the indexes
7596  * op_type(in):
7597  * scan_cache(in):
7598  * datayn(in): true if the target object is "data",
7599  * false if the target object is "schema"
7600  * need_replication(in): true if replication is needed
7601  * hfid(in):
7602  * func_preds(in): cached function index expressions
7603  * idx_action_flag(in): is moving record between partitioned table?
7604  * If FOR_MOVE, this delete(&insert) is caused by
7605  * 'UPDATE ... SET ...', NOT 'DELETE FROM ...'
7606  *
7607  * Note:Either insert indices (in_insert) or delete indices.
7608  */
7609 static int
7610 locator_add_or_remove_index_internal (THREAD_ENTRY * thread_p, RECDES * recdes, OID * inst_oid, OID * class_oid,
7611  int is_insert, int op_type, HEAP_SCANCACHE * scan_cache, bool datayn,
7612  bool need_replication, HFID * hfid, FUNC_PRED_UNPACK_INFO * func_preds,
7613  LOCATOR_INDEX_ACTION_FLAG idx_action_flag, bool has_BU_lock,
7614  bool skip_checking_fk)
7615 {
7616  int num_found;
7617  int i, num_btids;
7618  HEAP_CACHE_ATTRINFO index_attrinfo;
7619  BTID btid;
7620  DB_VALUE *key_dbvalue, *key_ins_del = NULL;
7621  DB_VALUE dbvalue;
7622  int unique_pk;
7623  btree_unique_stats *unique_stat_info;
7624  HEAP_IDX_ELEMENTS_INFO idx_info;
7625  char buf[DBVAL_BUFSIZE + MAX_ALIGNMENT], *aligned_buf;
7626  OR_INDEX *index;
7627  int error_code = NO_ERROR;
7628  OR_PREDICATE *or_pred = NULL;
7629  DB_LOGICAL ev_res = V_UNKNOWN;
7630  bool use_mvcc = false;
7631  MVCCID mvccid;
7632  MVCC_REC_HEADER *p_mvcc_rec_header = NULL;
7633  bool classname_was_alloced = false;
7634 
7635 /* temporary disable standalone optimization (non-mvcc insert/delete style).
7636  * Must be activated when dynamic heap is introduced */
7637 /* #if defined (SERVER_MODE) */
7639 /* #endif */
7640 
7641 #if defined(ENABLE_SYSTEMTAP)
7642  const char *classname = scan_cache->node.classname;
7643 #endif /* ENABLE_SYSTEMTAP */
7644 
7645  assert_release (class_oid != NULL);
7646  assert_release (!OID_ISNULL (class_oid));
7647 
7648  key_dbvalue = NULL;
7649  db_make_null (&dbvalue);
7650 
7651  aligned_buf = PTR_ALIGN (buf, MAX_ALIGNMENT);
7652 
7653 #if defined(SERVER_MODE)
7654  if (!mvcc_is_mvcc_disabled_class (class_oid) && !has_BU_lock)
7655  {
7656  /* Use MVCC if it's not disabled for current class */
7657  use_mvcc = true;
7658  mvccid = logtb_get_current_mvccid (thread_p);
7659  }
7660 #endif /* SERVER_MODE */
7661 
7662  /*
7663  * Populate the index_attrinfo structure.
7664  * Return the number of indexed attributes found.
7665  */
7666  num_found = heap_attrinfo_start_with_index (thread_p, class_oid, NULL, &index_attrinfo, &idx_info);
7667  num_btids = idx_info.num_btids;
7668 
7669  if (num_found == 0)
7670  {
7671  return NO_ERROR;
7672  }
7673  else if (num_found < 0)
7674  {
7675  return ER_FAILED;
7676  }
7677 
7678  /*
7679  * At this point, there are indices and the index attrinfo has
7680  * been initialized
7681  *
7682  * Read the values of the indexed attributes
7683  */
7684  if (idx_info.has_single_col)
7685  {
7686  error_code = heap_attrinfo_read_dbvalues (thread_p, inst_oid, recdes, NULL, &index_attrinfo);
7687  if (error_code != NO_ERROR)
7688  {
7689  goto error;
7690  }
7691  }
7692 
7693 #if defined(ENABLE_SYSTEMTAP)
7694  if (classname == NULL)
7695  {
7696  char *heap_class_name = NULL;
7697  if (heap_get_class_name (thread_p, class_oid, &heap_class_name) != NO_ERROR || heap_class_name == NULL)
7698  {
7699  ASSERT_ERROR_AND_SET (error_code);
7700  goto error;
7701  }
7702 
7703  classname = heap_class_name;
7704  classname_was_alloced = true;
7705  }
7706 
7707  assert (classname != NULL);
7708 #endif /* ENABLE_SYSTEMTAP */
7709 
7710  for (i = 0; i < num_btids; i++)
7711  {
7712  index = &(index_attrinfo.last_classrepr->indexes[i]);
7713  or_pred = index->filter_predicate;
7714  if (or_pred && or_pred->pred_stream)
7715  {
7716  error_code =
7717  locator_eval_filter_predicate (thread_p, &index->btid, or_pred, class_oid, &inst_oid, 1, &recdes, &ev_res);
7718  if (error_code == ER_FAILED)
7719  {
7720  goto error;
7721  }
7722  else if (ev_res != V_TRUE)
7723  {
7724  continue;
7725  }
7726  }
7727  /*
7728  * Generate a B-tree key contained in a DB_VALUE and return a
7729  * pointer to it.
7730  */
7731  key_dbvalue =
7732  heap_attrvalue_get_key (thread_p, i, &index_attrinfo, recdes, &btid, &dbvalue, aligned_buf,
7733  (func_preds ? &func_preds[i] : NULL), NULL);
7734  if (key_dbvalue == NULL)
7735  {
7736  error_code = ER_FAILED;
7737  goto error;
7738  }
7739 
7740  if (i < 1 || !locator_was_index_already_applied (&index_attrinfo, &index->btid, i))
7741  {
7742  if (scan_cache == NULL)
7743  {
7744  unique_stat_info = NULL;
7745  }
7746  else
7747  {
7748  if (op_type == MULTI_ROW_UPDATE || op_type == MULTI_ROW_INSERT || op_type == MULTI_ROW_DELETE)
7749  {
7750  assert (scan_cache->m_index_stats != NULL);
7751  unique_stat_info = &scan_cache->m_index_stats->get_stats_of (index->btid);
7752  }
7753  else
7754  {
7755  unique_stat_info = NULL;
7756  }
7757  }
7758  if (use_mvcc)
7759  {
7760  btree_set_mvcc_header_ids_for_update (thread_p, !is_insert, is_insert, &mvccid, mvcc_rec_header);
7761  p_mvcc_rec_header = mvcc_rec_header;
7762  }
7763 
7764  unique_pk = 0;
7765  if (index->type == BTREE_UNIQUE || index->type == BTREE_REVERSE_UNIQUE)
7766  {
7767  unique_pk = BTREE_CONSTRAINT_UNIQUE;
7768  }
7769  else if (index->type == BTREE_PRIMARY_KEY)
7770  {
7772  }
7773 
7774  if (is_insert)
7775  {
7776 #if defined(ENABLE_SYSTEMTAP)
7777  CUBRID_IDX_INSERT_START (classname, index->btname);
7778 #endif /* ENABLE_SYSTEMTAP */
7779 
7780  if (index->type == BTREE_FOREIGN_KEY && !skip_checking_fk)
7781  {
7782  if (lock_object (thread_p, inst_oid, class_oid, X_LOCK, LK_UNCOND_LOCK) != LK_GRANTED)
7783  {
7784  goto error;
7785  }
7786  }
7787 
7789  {
7790  /* Online index is currently loading. */
7791  error_code =
7792  btree_online_index_dispatcher (thread_p, &btid, key_dbvalue, class_oid, inst_oid, unique_pk,
7794  }
7795  else
7796  {
7797  error_code =
7798  btree_insert (thread_p, &btid, key_dbvalue, class_oid, inst_oid, op_type, unique_stat_info,
7799  &unique_pk, p_mvcc_rec_header);
7800  }
7801 #if defined(ENABLE_SYSTEMTAP)
7802  CUBRID_IDX_INSERT_END (classname, index->btname, (error_code != NO_ERROR));
7803 #endif /* ENABLE_SYSTEMTAP */
7804  }
7805  else
7806  {
7807 #if defined(ENABLE_SYSTEMTAP)
7808  CUBRID_IDX_DELETE_START (classname, index->btname);
7809 #endif /* ENABLE_SYSTEMTAP */
7810 
7811  if (use_mvcc == true)
7812  {
7814  {
7815  /* Online index is currently loading. */
7816  error_code =
7817  btree_online_index_dispatcher (thread_p, &btid, key_dbvalue, class_oid, inst_oid,
7818  unique_pk, BTREE_OP_ONLINE_INDEX_TRAN_DELETE, NULL);
7819  }
7820  else
7821  {
7822  /* in MVCC logical deletion means MVCC DEL_ID insertion */
7823  error_code =
7824  btree_mvcc_delete (thread_p, &btid, key_dbvalue, class_oid, inst_oid, op_type, unique_stat_info,
7825  &unique_pk, p_mvcc_rec_header);
7826  }
7827  }
7828  else
7829  {
7830  error_code =
7831  btree_physical_delete (thread_p, &btid, key_dbvalue, inst_oid, class_oid, &unique_pk, op_type,
7832  unique_stat_info);
7833  if (error_code != NO_ERROR)
7834  {
7835  ASSERT_ERROR ();
7836 
7837 #if defined(ENABLE_SYSTEMTAP)
7838  CUBRID_IDX_DELETE_END (classname, index->btname, 1);
7839 #endif /* ENABLE_SYSTEMTAP */
7840 
7841  goto error;
7842  }
7843  }
7844 #if defined(ENABLE_SYSTEMTAP)
7845  CUBRID_IDX_DELETE_END (classname, index->btname, (error_code != NO_ERROR));
7846 #endif /* ENABLE_SYSTEMTAP */
7847 
7848  }
7849  }
7850 
7851  if (!locator_Dont_check_foreign_key && index->type == BTREE_PRIMARY_KEY && index->fk)
7852  {
7853  /* actually key_prefix_length is -1 for BTREE_PRIMARY_KEY; must be changed when key_prefix_length will be
7854  * added to FK and PK */
7855  if (is_insert)
7856  {
7857  ; /* nop */
7858  }
7859  else
7860  {
7861  if (idx_action_flag == FOR_MOVE)
7862  {
7863  /* This delete is caused by 'UPDATE ... SET ...' between partitioned tables. It first delete a
7864  * record in a partitioned table and insert a record in another partitioned table. It should check
7865  * the 'ON UPDATE ...' condition, not check 'ON DELETE ...' condition. */
7866  error_code = locator_check_primary_key_update (thread_p, index, key_dbvalue);
7867  }
7868  else
7869  {
7870  error_code = locator_check_primary_key_delete (thread_p, index, key_dbvalue);
7871  }
7872  if (error_code != NO_ERROR)
7873  {
7874  goto error;
7875  }
7876  }
7877  }
7878 
7879  /*
7880  * for replication,
7881  * Following step would be executed only when the target index is a
7882  * primary key.
7883  * The right place to insert a replication log info is here
7884  * to avoid another "fetching key values"
7885  * Generates the replication log info. for data insert/delete
7886  * for the update cases, refer to locator_update_force()
7887  */
7888  if (need_replication && index->type == BTREE_PRIMARY_KEY && error_code == NO_ERROR
7889  && !LOG_CHECK_LOG_APPLIER (thread_p) && log_does_allow_replication () == true)
7890  {
7891  error_code =
7892  repl_log_insert (thread_p, class_oid, inst_oid, datayn ? LOG_REPLICATION_DATA : LOG_REPLICATION_STATEMENT,
7893  is_insert ? RVREPL_DATA_INSERT : RVREPL_DATA_DELETE, key_dbvalue,
7895  }
7896  if (error_code != NO_ERROR)
7897  {
7898  assert (er_errid () != NO_ERROR);
7899  goto error;
7900  }
7901 
7902 #if 0
7903  if (key_ins_del != NULL && !DB_IS_NULL (key_dbvalue) && !btree_multicol_key_is_null (key_dbvalue))
7904  {
7905  BTREE_CHECKSCAN bt_checkscan;
7906  DISK_ISVALID isvalid = DISK_VALID;
7907 
7908  /* start a check-scan on index */
7909  if (btree_keyoid_checkscan_start (thread_p, &btid, &bt_checkscan) != NO_ERROR)
7910  {
7911  goto error;
7912  }
7913 
7914  isvalid = btree_keyoid_checkscan_check (thread_p, &bt_checkscan, class_oid, key_dbvalue, inst_oid);
7915 
7916  if (er_errid () == ER_INTERRUPTED)
7917  {
7918  /* in case of user interrupt */
7919  ; /* do not check isvalid */
7920  }
7921  else
7922  {
7923  if (is_insert)
7924  {
7925  assert (isvalid == DISK_VALID); /* found */
7926  }
7927  else
7928  {
7929  assert (isvalid == DISK_INVALID); /* not found */
7930  }
7931  }
7932 
7933  /* close the index check-scan */
7934  btree_keyoid_checkscan_end (thread_p, &bt_checkscan);
7935  }
7936 #endif
7937 
7938  if (key_dbvalue == &dbvalue)
7939  {
7940  pr_clear_value (&dbvalue);
7941  key_dbvalue = NULL;
7942  }
7943  }
7944 
7945 error:
7946 
7947  heap_attrinfo_end (thread_p, &index_attrinfo);
7948 
7949  if (key_dbvalue == &dbvalue)
7950  {
7951  pr_clear_value (&dbvalue);
7952  key_dbvalue = NULL;
7953  }
7954 
7955 #if defined(ENABLE_SYSTEMTAP)
7956  if (classname != NULL && classname_was_alloced)
7957  {
7958  free_and_init (classname);
7959  }
7960 #endif /* ENABLE_SYSTEMTAP */
7961 
7962  return error_code;
7963 }
7964 
7965 #if defined(ENABLE_UNUSED_FUNCTION)
7966 /*
7967  * locator_make_midxkey_domain () -
7968  *
7969  * return:
7970  *
7971  * index(in):
7972  */
7973 static TP_DOMAIN *
7974 locator_make_midxkey_domain (OR_INDEX * index)
7975 {
7976  TP_DOMAIN *set_domain;
7977  TP_DOMAIN *domain = NULL;
7978 
7979  OR_ATTRIBUTE **atts;
7980  int num_atts, i;
7981 
7982  if (index == NULL || index->n_atts < 2)
7983  {
7984  return NULL;
7985  }
7986 
7987  num_atts = index->n_atts;
7988  atts = index->atts;
7989 
7990  set_domain = NULL;
7991  for (i = 0; i < num_atts; i++)
7992  {
7993  if (i == 0)
7994  {
7995  set_domain = tp_domain_copy (atts[i]->domain, 0);
7996  if (set_domain == NULL)
7997  {
7998  return NULL;
7999  }
8000  domain = set_domain;
8001  }
8002  else
8003  {
8004  domain->next = tp_domain_copy (atts[i]->domain, 0);
8005  if (domain->next == NULL)
8006  {
8007  goto error;
8008  }
8009  domain = domain->next;
8010  }
8011  }
8012 
8013  domain = tp_domain_construct (DB_TYPE_MIDXKEY, (DB_OBJECT *) 0, num_atts, 0, set_domain);
8014 
8015  if (domain)
8016  {
8017  return tp_domain_cache (domain);
8018  }
8019  else
8020  {
8021  goto error;
8022  }
8023 
8024 error:
8025 
8026  if (set_domain)
8027  {
8028  TP_DOMAIN *td, *next;
8029 
8030  /* tp_domain_free(set_domain); */
8031  for (td = set_domain, next = NULL; td != NULL; td = next)
8032  {
8033  next = td->next;
8034  tp_domain_free (td);
8035  }
8036  }
8037 
8038  return NULL;
8039 }
8040 #endif /* ENABLE_UNUSED_FUNCTION */
8041 
8042 /*
8043  * locator_eval_filter_predicate () - evaluate index filter predicate
8044  *
8045  * return: error code
8046  *
8047  * btid(in): btid of index
8048  * or_pred(in): index filter predicate
8049  * class_oid(in): object identifier of the class
8050  * inst_oids(in): object identifiers of the instances
8051  * num_insts(in): the length of inst_oids, recs, results
8052  * recs(in): record descriptors
8053  * results(out): predicate evaluation results
8054  */
8055 static int
8056 locator_eval_filter_predicate (THREAD_ENTRY * thread_p, BTID * btid, OR_PREDICATE * or_pred, OID * class_oid,
8057  OID ** inst_oids, int num_insts, RECDES ** recs, DB_LOGICAL * results)
8058 {
8059  int i;
8060  PRED_EXPR_WITH_CONTEXT *pred_filter = NULL;
8061  PR_EVAL_FNC filter_eval_func = NULL;
8062  DB_TYPE single_node_type = DB_TYPE_NULL;
8063  HL_HEAPID old_pri_heap_id = HL_NULL_HEAPID;
8064  int error_code = NO_ERROR;
8065 
8066  if (or_pred == NULL || class_oid == NULL || recs == NULL || inst_oids == NULL || num_insts <= 0 || results == NULL
8067  || or_pred->pred_stream == NULL || btid == NULL)
8068  {
8069  assert (false);
8070  return ER_FAILED;
8071  }
8072 
8073  error_code = fpcache_claim (thread_p, btid, or_pred, &pred_filter);
8074  if (error_code != NO_ERROR)
8075  {
8076  ASSERT_ERROR ();
8077  return error_code;
8078  }
8079  assert (pred_filter != NULL);
8080 
8081  error_code =
8082  heap_attrinfo_start (thread_p, class_oid, pred_filter->num_attrs_pred, pred_filter->attrids_pred,
8083  pred_filter->cache_pred);
8084  if (error_code != NO_ERROR)
8085  {
8086  ASSERT_ERROR ();
8087  goto end;
8088  }
8089  filter_eval_func = eval_fnc (thread_p, pred_filter->pred, &single_node_type);
8090  assert (filter_eval_func != NULL);
8091 
8092  for (i = 0; i < num_insts; i++)
8093  {
8094  error_code = heap_attrinfo_read_dbvalues (thread_p, inst_oids[i], recs[i], NULL, pred_filter->cache_pred);
8095  if (error_code != NO_ERROR)
8096  {
8097  goto end;
8098  }
8099 
8100  /* use global heap for memory allocation */
8101  old_pri_heap_id = db_change_private_heap (thread_p, 0);
8102  results[i] = (*filter_eval_func) (thread_p, pred_filter->pred, NULL, inst_oids[i]);
8103  if (results[i] == V_ERROR)
8104  {
8105  /* restore private heap */
8106  (void) db_change_private_heap (thread_p, old_pri_heap_id);
8107  error_code = ER_FAILED;
8108  goto end;
8109  }
8110  /* restore private heap */
8111  (void) db_change_private_heap (thread_p, old_pri_heap_id);
8112  }
8113 
8114 end:
8115  if (pred_filter)
8116  {
8117  heap_attrinfo_end (thread_p, pred_filter->cache_pred);
8118  /* Except for db_value regu variable, all regu variables from pred expression are cleared. */
8119  old_pri_heap_id = db_change_private_heap (thread_p, 0);
8120  qexec_clear_pred_context (thread_p, pred_filter, false);
8121  (void) db_change_private_heap (thread_p, old_pri_heap_id);
8122  }
8123 
8124  fpcache_retire (thread_p, class_oid, btid, pred_filter);
8125  return error_code;
8126 }
8127 
8128 /*
8129  * locator_update_index () - Update index entries
8130  *
8131  * return: NO_ERROR if all OK, ER_ status otherwise
8132  *
8133  * new_recdes(in): The new recdes object
8134  * old_recdes(in): The old recdes object
8135  * att_id(in): Updated attr id array
8136  * n_att_id(in): Updated attr id array length
8137  * oid(in): The identifier of old/new object
8138  * class_oid(in): The class object identifier
8139  * op_type(in):
8140  * scan_cache(in):
8141  * repl_info(in/out): replication info, set need_replication to false when
8142  * no primary is found
8143  *
8144  * Note: Update the index entries of the given object.
8145  */
8146 int
8147 locator_update_index (THREAD_ENTRY * thread_p, RECDES * new_recdes, RECDES * old_recdes, ATTR_ID * att_id, int n_att_id,
8148  OID * oid, OID * class_oid, int op_type, HEAP_SCANCACHE * scan_cache, REPL_INFO * repl_info)
8149 {
8150  HEAP_CACHE_ATTRINFO space_attrinfo[2];
8151  HEAP_CACHE_ATTRINFO *new_attrinfo = NULL;
8152  HEAP_CACHE_ATTRINFO *old_attrinfo = NULL;
8153  int new_num_found, old_num_found;
8154  BTID new_btid, old_btid;
8155  int pk_btid_index = -1;
8156  DB_VALUE *new_key = NULL, *old_key = NULL;
8157  DB_VALUE *repl_old_key = NULL;
8158  DB_VALUE new_dbvalue, old_dbvalue;
8159  bool new_isnull, old_isnull;
8160  PR_TYPE *pr_type;
8161  OR_INDEX *index = NULL;
8162  int i, j, k, num_btids, old_num_btids, unique_pk;
8163  bool found_btid = true;
8164  btree_unique_stats *unique_stat_info;
8165  HEAP_IDX_ELEMENTS_INFO new_idx_info;
8166  HEAP_IDX_ELEMENTS_INFO old_idx_info;
8167  char newbuf[DBVAL_BUFSIZE + MAX_ALIGNMENT], *aligned_newbuf;
8168  char oldbuf[DBVAL_BUFSIZE + MAX_ALIGNMENT], *aligned_oldbuf;
8169  DB_TYPE dbval_type;
8170  TP_DOMAIN *key_domain = NULL;
8171  int error_code;
8172  DB_LOGICAL ev_results[2];
8173  bool do_delete_only = false;
8174  bool do_insert_only = false;
8175  OID *inst_oids[2];
8176  RECDES *recs[2];
8177  bool same_key = true;
8178  int c = DB_UNK;
8179  bool use_mvcc = false;
8180  MVCC_REC_HEADER *p_mvcc_rec_header = NULL;
8181  /* TODO: MVCC_BTREE_DELETE_OBJECT is removed due to recovery issue regarding MVCCID. Must find a solution to recover
8182  * MVCC info on rollback (otherwise we will have inconsistencies regarding visibility). */
8183  /* MVCC_BTREE_OP_ARGUMENTS mvcc_args, *mvcc_args_p = NULL; */
8184  MVCCID mvccid;
8185 /* temporary disable standalone optimization (non-mvcc insert/delete style).
8186  * Must be activated when dynamic heap is introduced */
8187 /* #if defined(SERVER_MODE) */
8189 /* #endif */
8190 #if defined(ENABLE_SYSTEMTAP)
8191  char *classname = NULL;
8192  bool is_started = false;
8193 #endif /* ENABLE_SYSTEMTAP */
8194  LOG_TDES *tdes;
8195  LOG_LSA preserved_repl_lsa;
8196  int tran_index;
8197 
8198  assert_release (class_oid != NULL);
8199  assert_release (!OID_ISNULL (class_oid));
8200 
8201  mvccid = MVCCID_NULL;
8202 
8203 #if defined(SERVER_MODE)
8204  if (!mvcc_is_mvcc_disabled_class (class_oid))
8205  {
8206  use_mvcc = true;
8207 
8208  mvccid = logtb_get_current_mvccid (thread_p);
8209  }
8210 #endif /* SERVER_MODE */
8211 
8212  LSA_SET_NULL (&preserved_repl_lsa);
8213 
8214  db_make_null (&new_dbvalue);
8215  db_make_null (&old_dbvalue);
8216 
8217  aligned_newbuf = PTR_ALIGN (newbuf, MAX_ALIGNMENT);
8218  aligned_oldbuf = PTR_ALIGN (oldbuf, MAX_ALIGNMENT);
8219 
8220  new_num_found = heap_attrinfo_start_with_index (thread_p, class_oid, NULL, &space_attrinfo[0], &new_idx_info);
8221  num_btids = new_idx_info.num_btids;
8222  if (new_num_found < 0)
8223  {
8224  return ER_FAILED;
8225  }
8226  new_attrinfo = &space_attrinfo[0];
8227 
8228  old_num_found = heap_attrinfo_start_with_index (thread_p, class_oid, NULL, &space_attrinfo[1], &old_idx_info);
8229  old_num_btids = old_idx_info.num_btids;
8230  if (old_num_found < 0)
8231  {
8232  error_code = ER_FAILED;
8233  goto error;
8234  }
8235  old_attrinfo = &space_attrinfo[1];
8236 
8237  if (new_num_found != old_num_found)
8238  {
8239  if (new_num_found > 0)
8240  {
8241  heap_attrinfo_end (thread_p, &space_attrinfo[0]);
8242  }
8243  if (old_num_found > 0)
8244  {
8245  heap_attrinfo_end (thread_p, &space_attrinfo[1]);
8246  }
8247  return ER_FAILED;
8248  }
8249 
8250  if (new_num_found == 0)
8251  {
8252  /* No need to replicate this record since there is no primary key */
8253  if (repl_info != NULL)
8254  {
8255  repl_info->need_replication = false;
8256  }
8257 
8258  return NO_ERROR;
8259  }
8260 
8261  /*
8262  * There are indices and the index attrinfo has been initialized
8263  * Indices must be updated when the indexed attributes have changed in value
8264  * Get the new and old values of key and update the index when
8265  * the keys are different
8266  */
8267 
8268  new_attrinfo = &space_attrinfo[0];
8269  old_attrinfo = &space_attrinfo[1];
8270 
8271  error_code = heap_attrinfo_read_dbvalues (thread_p, oid, new_recdes, NULL, new_attrinfo);
8272  if (error_code != NO_ERROR)
8273  {
8274  goto error;
8275  }
8276  error_code = heap_attrinfo_read_dbvalues (thread_p, oid, old_recdes, NULL, old_attrinfo);
8277  if (error_code != NO_ERROR)
8278  {
8279  goto error;
8280  }
8281 
8282  /*
8283  * Ensure that we have the same number of indexes and
8284  * get the number of B-tree IDs.
8285  */
8286  if (old_attrinfo->last_classrepr->n_indexes != new_attrinfo->last_classrepr->n_indexes)
8287  {
8288  error_code = ER_FAILED;
8289  goto error;
8290  }
8291 
8292 #if defined(ENABLE_SYSTEMTAP)
8293  if (heap_get_class_name (thread_p, class_oid, &classname) != NO_ERROR || classname == NULL)
8294  {
8295  ASSERT_ERROR_AND_SET (error_code);
8296  goto error;
8297  }
8298 #endif /* ENABLE_SYSTEMTAP */
8299 
8300  for (i = 0; i < num_btids; i++)
8301  {
8302  index = &(new_attrinfo->last_classrepr->indexes[i]);
8303  if (pk_btid_index == -1 && repl_info != NULL && repl_info->need_replication == true
8304  && !LOG_CHECK_LOG_APPLIER (thread_p) && index->type == BTREE_PRIMARY_KEY
8305  && log_does_allow_replication () == true)
8306  {
8307  pk_btid_index = i;
8308  }
8309 
8310  /* check for specified update attributes */
8311  if ((att_id != NULL) && ((use_mvcc == false) || (index->type == BTREE_PRIMARY_KEY && index->fk != NULL)))
8312  {
8313  found_btid = false; /* guess as not found */
8314 
8315  for (j = 0; j < n_att_id && !found_btid; j++)
8316  {
8317  for (k = 0; k < index->n_atts && !found_btid; k++)
8318  {
8319  if (att_id[j] == (ATTR_ID) (index->atts[k]->id))
8320  { /* the index key_type has updated attr */
8321  found_btid = true;
8322  }
8323  }
8324  }
8325 
8326  /* in MVCC, in case of BTREE_PRIMARY_KEY having FK need to update PK index but skip foreign key restrictions
8327  * checking */
8328  if (!found_btid && !index->filter_predicate && (index->type != BTREE_PRIMARY_KEY || index->fk == NULL))
8329  {
8330  continue; /* skip and go ahead */
8331  }
8332  }
8333 
8334  do_delete_only = false;
8335  do_insert_only = false;
8336  if (index->filter_predicate)
8337  {
8338  inst_oids[0] = inst_oids[1] = oid;
8339  recs[0] = old_recdes;
8340  recs[1] = new_recdes;
8341  error_code =
8342  locator_eval_filter_predicate (thread_p, &index->btid, index->filter_predicate, class_oid, inst_oids, 2,
8343  recs, ev_results);
8344  if (error_code == ER_FAILED)
8345  {
8346  goto error;
8347  }
8348 
8349  if (ev_results[0] != V_TRUE)
8350  {
8351  if (ev_results[1] != V_TRUE)
8352  {
8353  /* the old rec and the new rec does not satisfied the filter predicate */
8354  continue;
8355  }
8356  else
8357  {
8358  /* the old rec does not satisfied the filter predicate */
8359  /* the new rec satisfied the filter predicate */
8360  do_insert_only = true;
8361  }
8362  }
8363  else
8364  {
8365  if (ev_results[1] != V_TRUE)
8366  {
8367  /* the old rec satisfied the filter predicate the new rec does not satisfied the filter predicate */
8368  do_delete_only = true;
8369  }
8370  else
8371  {
8372  if (found_btid == false)
8373  {
8374  /* the old rec satisfied the filter predicate the new rec satisfied the filter predicate the
8375  * index does not contain updated attributes */
8376  continue;
8377  }
8378  /* nothing to do - update operation */
8379  }
8380  }
8381  }
8382 
8383  new_key =
8384  heap_attrvalue_get_key (thread_p, i, new_attrinfo, new_recdes, &new_btid, &new_dbvalue, aligned_newbuf, NULL,
8385  NULL);
8386  old_key =
8387  heap_attrvalue_get_key (thread_p, i, old_attrinfo, old_recdes, &old_btid, &old_dbvalue, aligned_oldbuf, NULL,
8388  &key_domain);
8389 
8390  if ((new_key == NULL) || (old_key == NULL))
8391  {
8392  error_code = ER_FAILED;
8393  goto error;
8394  }
8395 
8396  dbval_type = DB_VALUE_DOMAIN_TYPE (old_key);
8397  if (DB_VALUE_DOMAIN_TYPE (new_key) != dbval_type)
8398  {
8399  error_code = ER_FAILED;
8400  goto error;
8401  }
8402 
8403  if (scan_cache == NULL)
8404  {
8405  unique_stat_info = NULL;
8406  }
8407  else
8408  {
8409  if (op_type == MULTI_ROW_UPDATE || op_type == MULTI_ROW_INSERT || op_type == MULTI_ROW_DELETE)
8410  {
8411  assert (scan_cache->m_index_stats != NULL);
8412  unique_stat_info = &scan_cache->m_index_stats->get_stats_of (index->btid);
8413  }
8414  else
8415  {
8416  unique_stat_info = NULL;
8417  }
8418  }
8419 
8420  new_isnull = db_value_is_null (new_key);
8421  old_isnull = db_value_is_null (old_key);
8422  pr_type = pr_type_from_id (dbval_type);
8423  if (pr_type == NULL)
8424  {
8425  error_code = ER_FAILED;
8426  goto error;
8427  }
8428 
8429  assert (key_domain != NULL);
8430  if (pr_type->id == DB_TYPE_MIDXKEY)
8431  {
8432  assert (TP_DOMAIN_TYPE (key_domain) == DB_TYPE_MIDXKEY);
8433  new_key->data.midxkey.domain = old_key->data.midxkey.domain = key_domain;
8434  }
8435  else
8436  {
8437  assert (old_isnull || TP_ARE_COMPARABLE_KEY_TYPES (TP_DOMAIN_TYPE (key_domain), pr_type->id));
8438  }
8439 
8440  same_key = true; /* init */
8441  if ((new_isnull && !old_isnull) || (old_isnull && !new_isnull))
8442  {
8443  same_key = false;
8444  }
8445  else
8446  {
8447  if (!(new_isnull && old_isnull))
8448  {
8449  c = btree_compare_key (old_key, new_key, key_domain, 0, 1, NULL);
8450 
8451  if (c == DB_UNK)
8452  {
8453  assert (er_errid () != NO_ERROR);
8454  error_code = er_errid ();
8455  goto error;
8456  }
8457 
8458  if (c != DB_EQ)
8459  {
8460  same_key = false;
8461  }
8462  }
8463  }
8464 
8465 #if defined(ENABLE_SYSTEMTAP)
8466  CUBRID_IDX_UPDATE_START (classname, index->btname);
8467  is_started = true;
8468 #endif /* ENABLE_SYSTEMTAP */
8469 
8470  if (!same_key || do_delete_only || do_insert_only)
8471  {
8472  if (i < 1 || !locator_was_index_already_applied (new_attrinfo, &index->btid, i))
8473  {
8474  if (mvccid != MVCCID_NULL)
8475  {
8476  btree_set_mvcc_header_ids_for_update (thread_p, do_delete_only, do_insert_only, &mvccid,
8477  mvcc_rec_header);
8478  p_mvcc_rec_header = mvcc_rec_header;
8479  }
8480 
8481  unique_pk = 0;
8482  if (index->type == BTREE_UNIQUE || index->type == BTREE_REVERSE_UNIQUE)
8483  {
8484  unique_pk = BTREE_CONSTRAINT_UNIQUE;
8485  }
8486  else if (index->type == BTREE_PRIMARY_KEY)
8487  {
8489  }
8490 
8491  if (do_delete_only)
8492  {
8494  {
8495  error_code =
8496  btree_online_index_dispatcher (thread_p, &index->btid, old_key, class_oid, oid, unique_pk,
8498  if (error_code != NO_ERROR)
8499  {
8500  ASSERT_ERROR ();
8501  goto error;
8502  }
8503  }
8504  else
8505  { /* Not online index. */
8506  if (use_mvcc)
8507  {
8508  /* in MVCC logical deletion means MVCC DEL_ID insertion */
8509  error_code =
8510  btree_mvcc_delete (thread_p, &old_btid, old_key, class_oid, oid, op_type, unique_stat_info,
8511  &unique_pk, p_mvcc_rec_header);
8512  if (error_code != NO_ERROR)
8513  {
8514  assert (er_errid () != NO_ERROR);
8515  goto error;
8516  }
8517  }
8518  else
8519  {
8520  error_code =
8521  btree_physical_delete (thread_p, &old_btid, old_key, oid, class_oid, &unique_pk, op_type,
8522  unique_stat_info);
8523  if (error_code != NO_ERROR)
8524  {
8525  ASSERT_ERROR ();
8526  goto error;
8527  }
8528  }
8529  }
8530  }
8531  else
8532  {
8533  /* in MVCC - update index key means insert index key */
8534  if ((do_insert_only == true))
8535  {
8536  if (index->type == BTREE_FOREIGN_KEY)
8537  {
8538  if (lock_object (thread_p, oid, class_oid, X_LOCK, LK_UNCOND_LOCK) != LK_GRANTED)
8539  {
8540  goto error;
8541  }
8542  }
8543 
8545  {
8546  /* Online index loading on current index. */
8547  error_code =
8548  btree_online_index_dispatcher (thread_p, &index->btid, new_key, class_oid, oid,
8550  }
8551  else
8552  {
8553  error_code =
8554  btree_insert (thread_p, &old_btid, new_key, class_oid, oid, op_type, unique_stat_info,
8555  &unique_pk, p_mvcc_rec_header);
8556  }
8557 
8558  if (error_code != NO_ERROR)
8559  {
8560  ASSERT_ERROR ();
8561  goto error;
8562  }
8563  }
8564  else
8565  {
8567  {
8568  /* Online index loading on current index. */
8569  /* This translates into a delete of the old key and an insert of the new key. */
8570 
8571  /* Delete old key. */
8572  error_code =
8573  btree_online_index_dispatcher (thread_p, &index->btid, old_key, class_oid, oid,
8575  if (error_code != NO_ERROR)
8576  {
8577  goto error;
8578  }
8579 
8580  /* Insert new key. */
8581  error_code =
8582  btree_online_index_dispatcher (thread_p, &index->btid, new_key, class_oid, oid,
8584  }
8585  else
8586  {
8587  error_code =
8588  btree_update (thread_p, &old_btid, old_key, new_key, class_oid, oid, op_type,
8589  unique_stat_info, &unique_pk, p_mvcc_rec_header);
8590 
8591  if (error_code != NO_ERROR)
8592  {
8593  goto error;
8594  }
8595  }
8596  }
8597  }
8598  }
8599 
8600 #if defined(ENABLE_SYSTEMTAP)
8601  CUBRID_IDX_UPDATE_END (classname, index->btname, 0);
8602 #endif /* ENABLE_SYSTEMTAP */
8603 
8604  /* In MVCC need to check for specified update attributes */
8605  if (!locator_Dont_check_foreign_key && !same_key && index->type == BTREE_PRIMARY_KEY && index->fk
8606  && found_btid)
8607  {
8608  assert (do_insert_only == false && do_delete_only == false);
8609 
8610  tran_index = LOG_FIND_THREAD_TRAN_INDEX (thread_p);
8611  tdes = LOG_FIND_TDES (tran_index);
8612 
8613  if (pk_btid_index == i)
8614  {
8615  /*
8616  * save lsa before it is overwritten by FK action. No need
8617  * to consider in-place update (repl_update_lsa) since it updates
8618  * index first and then updates heap
8619  */
8620  LSA_COPY (&preserved_repl_lsa, &tdes->repl_insert_lsa);
8621  LSA_SET_NULL (&tdes->repl_insert_lsa);
8622  }
8623 
8624  error_code = locator_check_primary_key_update (thread_p, index, old_key);
8625  if (error_code != NO_ERROR)
8626  {
8627  goto error;
8628  }
8629 
8630  if (pk_btid_index == i)
8631  {
8632  /* restore repl_insert_lsa */
8633  assert (LSA_ISNULL (&tdes->repl_insert_lsa));
8634  LSA_COPY (&tdes->repl_insert_lsa, &preserved_repl_lsa);
8635  }
8636  }
8637 
8638 #if 0
8639  {
8640  BTREE_CHECKSCAN bt_checkscan;
8641  DISK_ISVALID isvalid = DISK_VALID;
8642 
8643  /* start a check-scan on index */
8644  if (btree_keyoid_checkscan_start (thread_p, &old_btid, &bt_checkscan) != NO_ERROR)
8645  {
8646  goto error;
8647  }
8648 
8649  if (!do_insert_only && !DB_IS_NULL (old_key) && !btree_multicol_key_is_null (old_key))
8650  {
8651  isvalid = btree_keyoid_checkscan_check (thread_p, &bt_checkscan, class_oid, old_key, old_oid);
8652 
8653  if (er_errid () == ER_INTERRUPTED)
8654  {
8655  /* in case of user interrupt */
8656  ; /* do not check isvalid */
8657  }
8658  else
8659  {
8660  assert (isvalid == DISK_INVALID); /* not found */
8661  }
8662  }
8663 
8664  if (!do_delete_only && !DB_IS_NULL (new_key) && !btree_multicol_key_is_null (new_key))
8665  {
8666 
8667  isvalid = btree_keyoid_checkscan_check (thread_p, &bt_checkscan, class_oid, new_key, new_oid);
8668  if (er_errid () == ER_INTERRUPTED)
8669  {
8670  /* in case of user interrupt */
8671  ; /* do not check isvalid */
8672  }
8673  else
8674  {
8675  assert (isvalid == DISK_VALID); /* found */
8676  }
8677  }
8678 
8679  /* close the index check-scan */
8680  btree_keyoid_checkscan_end (thread_p, &bt_checkscan);
8681  }
8682 #endif
8683  }
8684 
8685  if (pk_btid_index == i && repl_old_key == NULL)
8686  {
8687  repl_old_key = pr_make_ext_value ();
8688  pr_clone_value (old_key, repl_old_key);
8689  }
8690 
8691  if (new_key == &new_dbvalue)
8692  {
8693  pr_clear_value (&new_dbvalue);
8694  new_key = NULL;
8695  }
8696  if (old_key == &old_dbvalue)
8697  {
8698  pr_clear_value (&old_dbvalue);
8699  old_key = NULL;
8700  }
8701  }
8702 
8703  if (pk_btid_index != -1)
8704  {
8705  assert (repl_info != NULL);
8706 
8707  if (repl_old_key == NULL)
8708  {
8709  key_domain = NULL;
8710  repl_old_key =
8711  heap_attrvalue_get_key (thread_p, pk_btid_index, old_attrinfo, old_recdes, &old_btid, &old_dbvalue,
8712  aligned_oldbuf, NULL, &key_domain);
8713  if (repl_old_key == NULL)
8714  {
8715  error_code = ER_FAILED;
8716  goto error;
8717  }
8718 
8719  old_isnull = db_value_is_null (repl_old_key);
8720  pr_type = pr_type_from_id (DB_VALUE_DOMAIN_TYPE (repl_old_key));
8721  if (pr_type == NULL)
8722  {
8723  error_code = ER_FAILED;
8724  goto error;
8725  }
8726 
8727  if (pr_type->id == DB_TYPE_MIDXKEY)
8728  {
8729  /*
8730  * The asc/desc properties in midxkey from log_applier may be
8731  * inaccurate. therefore, we should use btree header's domain
8732  * while processing btree search request from log_applier.
8733  */
8734  repl_old_key->data.midxkey.domain = key_domain;
8735  }
8736 
8737  error_code =
8738  repl_log_insert (thread_p, class_oid, oid, LOG_REPLICATION_DATA, RVREPL_DATA_UPDATE, repl_old_key,
8739  (REPL_INFO_TYPE) repl_info->repl_info_type);
8740  if (repl_old_key == &old_dbvalue)
8741  {
8742  pr_clear_value (&old_dbvalue);
8743  }
8744  }
8745  else
8746  {
8747  error_code =
8748  repl_log_insert (thread_p, class_oid, oid, LOG_REPLICATION_DATA, RVREPL_DATA_UPDATE, repl_old_key,
8749  (REPL_INFO_TYPE) repl_info->repl_info_type);
8750  pr_free_ext_value (repl_old_key);
8751  repl_old_key = NULL;
8752  }
8753  }
8754  else
8755  {
8756  /*
8757  * clear repl_insert_lsa to make sure that FK action
8758  * does not overwrite the original update's target lsa.
8759  */
8760  tran_index = LOG_FIND_THREAD_TRAN_INDEX (thread_p);
8761  tdes = LOG_FIND_TDES (tran_index);
8762 
8763  LSA_SET_NULL (&tdes->repl_insert_lsa);
8764 
8765  /* No need to replicate this record since there is no primary key */
8766  if (repl_info != NULL)
8767  {
8768  repl_info->need_replication = false;
8769  }
8770  }
8771 
8772  heap_attrinfo_end (thread_p, new_attrinfo);
8773  heap_attrinfo_end (thread_p, old_attrinfo);
8774 
8775 #if defined(ENABLE_SYSTEMTAP)
8776  if (classname != NULL)
8777  {
8778  free_and_init (classname);
8779  }
8780 #endif /* ENABLE_SYSTEMTAP */
8781 
8782  return error_code;
8783 
8784 error:
8785 
8786  if (new_key == &new_dbvalue)
8787  {
8788  pr_clear_value (&new_dbvalue);
8789  new_key = NULL;
8790  }
8791  if (old_key == &old_dbvalue)
8792  {
8793  pr_clear_value (&old_dbvalue);
8794  old_key = NULL;
8795  }
8796 
8797  if (repl_old_key != NULL)
8798  {
8799  pr_free_ext_value (repl_old_key);
8800  }
8801 
8802  /* Deallocate any index_list .. if any */
8803 
8804  if (new_attrinfo != NULL)
8805  {
8806  heap_attrinfo_end (thread_p, new_attrinfo);
8807  }
8808 
8809  if (old_attrinfo != NULL)
8810  {
8811  heap_attrinfo_end (thread_p, old_attrinfo);
8812  }
8813 
8814 #if defined(ENABLE_SYSTEMTAP)
8815  if (is_started == true)
8816  {
8817  CUBRID_IDX_UPDATE_END (classname, index->btname, 1);
8818  }
8819  if (classname != NULL)
8820  {
8821  free_and_init (classname);
8822  }
8823 #endif /* ENABLE_SYSTEMTAP */
8824 
8825  return error_code;
8826 }
8827 
8828 /*
8829  * xlocator_remove_class_from_index () - Removes class instances from the B-tree
8830  *
8831  * return: NO_ERROR if all OK, ER_ status otherwise
8832  *
8833  * class_oid(in): The class object identifier
8834  * btid(in): B-tree ID
8835  * hfid(in): Heap ID
8836  *
8837  * Note: This function searches for instances belonging to the passes
8838  * class OID and removes the ones found. This function is used to
8839  * remove a class from a spanning B-tree such as a UNIQUE.
8840  */
8841 int
8843 {
8844  HEAP_CACHE_ATTRINFO index_attrinfo;
8845  HEAP_SCANCACHE scan_cache;
8846  OID inst_oid, *p_inst_oid = &inst_oid;
8847  int key_index, i, num_btids, num_found, dummy_unique, key_found;
8848  RECDES copy_rec, *p_copy_rec = &copy_rec;
8849  BTID inst_btid;
8850  DB_VALUE dbvalue;
8851  DB_VALUE *dbvalue_ptr = NULL;
8852  SCAN_CODE scan;
8853  char *new_area;
8854  btree_unique_stats unique_info;
8855  HEAP_IDX_ELEMENTS_INFO idx_info;
8856  char buf[DBVAL_BUFSIZE + MAX_ALIGNMENT], *aligned_buf;
8857  int error_code = NO_ERROR;
8858  OR_INDEX *index = NULL;
8859  DB_LOGICAL ev_res;
8861 
8862  if (class_oid != NULL && !OID_IS_ROOTOID (class_oid))
8863  {
8864  mvcc_snapshot = logtb_get_mvcc_snapshot (thread_p);
8865  if (mvcc_snapshot == NULL)
8866  {
8867  error_code = er_errid ();
8868  return (error_code == NO_ERROR ? ER_FAILED : error_code);
8869  }
8870  }
8871 
8872  db_make_null (&dbvalue);
8873 
8874  aligned_buf = PTR_ALIGN (buf, MAX_ALIGNMENT);
8875 
8876  /* allocate memory space for copying an instance image. */
8877  copy_rec.area_size = DB_PAGESIZE;
8878  copy_rec.data = (char *) malloc (copy_rec.area_size);
8879  if (copy_rec.data == NULL)
8880  {
8882  return ER_OUT_OF_VIRTUAL_MEMORY;
8883  }
8884 
8885  /* Start a scan cursor */
8886  error_code = heap_scancache_start (thread_p, &scan_cache, hfid, class_oid, false, false, mvcc_snapshot);
8887  if (error_code != NO_ERROR)
8888  {
8889  free_and_init (copy_rec.data);
8890  return error_code;
8891  }
8892 
8893  /*
8894  * Populate the index_attrinfo structure.
8895  * Return the number of indexed attributes found.
8896  */
8897  num_found = heap_attrinfo_start_with_index (thread_p, class_oid, NULL, &index_attrinfo, &idx_info);
8898  num_btids = idx_info.num_btids;
8899  if (num_found < 1)
8900  {
8901  (void) heap_scancache_end (thread_p, &scan_cache);
8902  free_and_init (copy_rec.data);
8903  return ER_FAILED;
8904  }
8905 
8906  /* Loop over each instance of the class found in the heap */
8907  inst_oid.volid = hfid->vfid.volid;
8908  inst_oid.pageid = NULL_PAGEID;
8909  inst_oid.slotid = NULL_SLOTID;
8910  key_found = false;
8911  key_index = 0;
8912 
8913  while (true)
8914  {
8915  if (dbvalue_ptr == &dbvalue)
8916  {
8917  pr_clear_value (&dbvalue);
8918  dbvalue_ptr = NULL;
8919  }
8920 
8921  scan = heap_next (thread_p, hfid, class_oid, &inst_oid, &copy_rec, &scan_cache, COPY);
8922  if (scan != S_SUCCESS)
8923  {
8924  if (scan != S_DOESNT_FIT)
8925  {
8926  break;
8927  }
8928 
8929  new_area = (char *) realloc (copy_rec.data, -(copy_rec.length));
8930  if (new_area == NULL)
8931  {
8932  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, (size_t) (-(copy_rec.length)));
8933  error_code = ER_OUT_OF_VIRTUAL_MEMORY;
8934  goto error;
8935  }
8936  copy_rec.area_size = -copy_rec.length;
8937  copy_rec.data = new_area;
8938  continue;
8939  }
8940 
8941  error_code = heap_attrinfo_read_dbvalues (thread_p, &inst_oid, &copy_rec, NULL, &index_attrinfo);
8942  if (error_code != NO_ERROR)
8943  {
8944  goto error;
8945  }
8946 
8947  /* Find the correct key by matching the BTID */
8948  if (key_found == false)
8949  {
8950  for (i = 0; i < num_btids; i++)
8951  {
8952  if (dbvalue_ptr == &dbvalue)
8953  {
8954  pr_clear_value (&dbvalue);
8955  dbvalue_ptr = NULL;
8956  }
8957 
8958  dbvalue_ptr =
8959  heap_attrvalue_get_key (thread_p, i, &index_attrinfo, &copy_rec, &inst_btid, &dbvalue, aligned_buf,
8960  NULL, NULL);
8961  if (dbvalue_ptr == NULL)
8962  {
8963  continue;
8964  }
8965 
8966  if (BTID_IS_EQUAL (btid, &inst_btid))
8967  {
8968  key_found = true;
8969  key_index = i;
8970  index = &(index_attrinfo.last_classrepr->indexes[key_index]);
8971  break;
8972  }
8973  }
8974  }
8975  /*
8976  * We already know the correct BTID index (key_index) so just use it
8977  * to retrieve the key
8978  */
8979  else
8980  {
8981  dbvalue_ptr =
8982  heap_attrvalue_get_key (thread_p, key_index, &index_attrinfo, &copy_rec, &inst_btid, &dbvalue, aligned_buf,
8983  NULL, NULL);
8984  }
8985 
8986  /* Delete the instance from the B-tree */
8987  if (key_found == false || dbvalue_ptr == NULL)
8988  {
8989  error_code = ER_FAILED;
8990  goto error;
8991  }
8992 
8993  assert (index != NULL);
8994  if (index->filter_predicate)
8995  {
8996  error_code =
8997  locator_eval_filter_predicate (thread_p, &index->btid, index->filter_predicate, class_oid, &p_inst_oid, 1,
8998  &p_copy_rec, &ev_res);
8999  if (error_code != NO_ERROR)
9000  {
9001  goto error;
9002  }
9003 
9004  if (ev_res != V_TRUE)
9005  {
9006  continue;
9007  }
9008  }
9009 
9010  error_code =
9011  btree_physical_delete (thread_p, btid, dbvalue_ptr, &inst_oid, class_oid, &dummy_unique, MULTI_ROW_DELETE,
9012  &unique_info);
9013  if (error_code != NO_ERROR)
9014  {
9015  ASSERT_ERROR ();
9016  goto error;
9017  }
9018  }
9019 
9020  error_code = logtb_tran_update_unique_stats (thread_p, *btid, unique_info, true);
9021  if (error_code != NO_ERROR)
9022  {
9023  goto error;
9024  }
9025 
9026  error_code = heap_scancache_end (thread_p, &scan_cache);
9027  if (error_code != NO_ERROR)
9028  {
9029  goto error;
9030  }
9031  heap_attrinfo_end (thread_p, &index_attrinfo);
9032 
9033 end:
9034  if (copy_rec.data != NULL)
9035  {
9036  free_and_init (copy_rec.data);
9037  }
9038 
9039  if (dbvalue_ptr == &dbvalue)
9040  {
9041  pr_clear_value (dbvalue_ptr);
9042  dbvalue_ptr = NULL;
9043  }
9044 
9045  return error_code;
9046 
9047 error:
9048 
9049  (void) heap_scancache_end (thread_p, &scan_cache);
9050  heap_attrinfo_end (thread_p, &index_attrinfo);
9051 
9052  goto end;
9053 }
9054 
9055 /*
9056  * locator_notify_decache () - Notify of a decache
9057  *
9058  * return:
9059  *
9060  * class_oid(in):
9061  * oid(in): Oid to decache
9062  * notify_area(in): Information used for notification purposes
9063  *
9064  * Note: Add an entry in the fetch area with respect to decaching an
9065  * object at the workspace.
9066  */
9067 static bool
9068 locator_notify_decache (const OID * class_oid, const OID * oid, void *notify_area)
9069 {
9070  LC_COPYAREA_DESC *notify;
9071  LC_COPYAREA_ONEOBJ *obj; /* Describe on object in area */
9072  int i;
9073 
9074  /* safe guard. oid must be not null. */
9075  if (OID_ISNULL (oid))
9076  {
9077  assert (false);
9078  return true;
9079  }
9080 
9081  notify = (LC_COPYAREA_DESC *) notify_area;
9082  if (notify->recdes->area_size <= SSIZEOF (**notify->obj))
9083  {
9084  return false;
9085  }
9086 
9087  /*
9088  * Make sure that the object is not already part of the notification area
9089  */
9090  obj = LC_START_ONEOBJ_PTR_IN_COPYAREA (notify->mobjs);
9091  obj = LC_PRIOR_ONEOBJ_PTR_IN_COPYAREA (obj);
9092  for (i = 0; i < notify->mobjs->num_objs; i++)
9093  {
9094  obj = LC_NEXT_ONEOBJ_PTR_IN_COPYAREA (obj);
9095  if (OID_EQ (&obj->oid, oid))
9096  {
9097  /* The object is already in the notification/fetch area */
9099  return true;
9100  }
9101  }
9102  /*
9103  * The object was not part of the notification/fetch area
9104  */
9105  notify->mobjs->num_objs++;
9106  COPY_OID (&((*notify->obj)->class_oid), class_oid);
9107  COPY_OID (&((*notify->obj)->oid), oid);
9108  (*notify->obj)->flag = 0;
9109  (*notify->obj)->hfid = NULL_HFID;
9110  (*notify->obj)->length = -1;
9111  (*notify->obj)->operation = LC_FETCH_DECACHE_LOCK;
9112 
9113  (*notify->obj)->offset = -1;
9114  *notify->obj = LC_NEXT_ONEOBJ_PTR_IN_COPYAREA (*notify->obj);
9115  notify->recdes->area_size -= sizeof (**notify->obj);
9116 
9117  return true;
9118 }
9119 
9120 /*
9121  * xlocator_notify_isolation_incons () - Synchronize possible inconsistencies related
9122  * to non two phase locking
9123  *
9124  * return:
9125  *
9126  * synch_area(in): Pointer to area where the name of the objects are placed.
9127  *
9128  * Note: Notify all inconsistencies related to the transaction
9129  * isolation level.
9130  */
9131 bool
9133 {
9134  LC_COPYAREA_DESC prefetch_des; /* Descriptor for decache of objects related to transaction isolation level */
9135  LC_COPYAREA_MANYOBJS *mobjs; /* Describe multiple objects in area */
9136  LC_COPYAREA_ONEOBJ *obj; /* Describe on object in area */
9137  RECDES recdes; /* Record descriptor for insertion */
9138  int offset; /* Place to store next object in area */
9139  bool more_synch = false;
9140 
9142  if (*synch_area == NULL)
9143  {
9144  return false;
9145  }
9146 
9147  mobjs = LC_MANYOBJS_PTR_IN_COPYAREA (*synch_area);
9148  LC_RECDES_IN_COPYAREA (*synch_area, &recdes);
9149  obj = LC_START_ONEOBJ_PTR_IN_COPYAREA (mobjs);
9150  mobjs->num_objs = 0;
9151  offset = 0;
9152 
9153  prefetch_des.mobjs = mobjs;
9154  prefetch_des.obj = &obj;
9155  prefetch_des.offset = &offset;
9156  prefetch_des.recdes = &recdes;
9157  lock_notify_isolation_incons (thread_p, locator_notify_decache, &prefetch_des);
9158  if (mobjs->num_objs == 0)
9159  {
9160  /*
9161  * Don't need to notify of any client workspace lock decaches
9162  * (i.e., possible object inconsistencies).
9163  */
9164  locator_free_copy_area (*synch_area);
9165  *synch_area = NULL;
9166  }
9167  else if (recdes.area_size >= SSIZEOF (*obj))
9168  {
9169  more_synch = true;
9170  }
9171 
9172  return more_synch;
9173 }
9174 
9175 static DISK_ISVALID
9176 locator_repair_btree_by_insert (THREAD_ENTRY * thread_p, OID * class_oid, BTID * btid, DB_VALUE * key, OID * inst_oid)
9177 {
9178  DISK_ISVALID isvalid = DISK_INVALID;
9179 #if defined(SERVER_MODE)
9180  int tran_index;
9181 
9182  tran_index = LOG_FIND_THREAD_TRAN_INDEX (thread_p);
9183 #endif /* SERVER_MODE */
9184 
9185  if (lock_object (thread_p, inst_oid, class_oid, X_LOCK, LK_UNCOND_LOCK) != LK_GRANTED)
9186  {
9187  return DISK_INVALID;
9188  }
9189 
9190  log_sysop_start (thread_p);
9191 
9192  if (btree_insert (thread_p, btid, key, class_oid, inst_oid, SINGLE_ROW_INSERT, NULL, NULL, NULL) == NO_ERROR)
9193  {
9194  isvalid = DISK_VALID;
9195  log_sysop_commit (thread_p);
9196  }
9197  else
9198  {
9199  ASSERT_ERROR ();
9200  log_sysop_abort (thread_p);
9201  }
9202 
9203 #if defined(SERVER_MODE)
9204  lock_remove_all_inst_locks (thread_p, tran_index, class_oid, X_LOCK);
9205 #endif /* SERVER_MODE */
9206 
9207  return isvalid;
9208 }
9209 
9210 static DISK_ISVALID
9211 locator_repair_btree_by_delete (THREAD_ENTRY * thread_p, OID * class_oid, BTID * btid, OID * inst_oid)
9212 {
9213  DB_VALUE key;
9214  bool clear_key = false;
9215  int dummy_unique;
9216  DISK_ISVALID isvalid = DISK_INVALID;
9217 #if defined(SERVER_MODE)
9218  int tran_index;
9219 
9220  tran_index = LOG_FIND_THREAD_TRAN_INDEX (thread_p);
9221 #endif /* SERVER_MODE */
9222 
9223  btree_init_temp_key_value (&clear_key, &key);
9224 
9225  if (btree_find_key (thread_p, btid, inst_oid, &key, &clear_key) != DISK_VALID)
9226  {
9227  return DISK_INVALID;
9228  }
9229 
9230  if (lock_object (thread_p, inst_oid, class_oid, X_LOCK, LK_UNCOND_LOCK) == LK_GRANTED)
9231  {
9232  log_sysop_start (thread_p);
9233 
9234  if (btree_physical_delete (thread_p, btid, &key, inst_oid, class_oid, &dummy_unique, SINGLE_ROW_DELETE, NULL) ==
9235  NO_ERROR)
9236  {
9237  isvalid = DISK_VALID;
9238  log_sysop_commit (thread_p);
9239  }
9240  else
9241  {
9242  ASSERT_ERROR ();
9243  log_sysop_abort (thread_p);
9244  }
9245 
9246 #if defined(SERVER_MODE)
9247  lock_remove_all_inst_locks (thread_p, tran_index, class_oid, X_LOCK);
9248 #endif /* SERVER_MODE */
9249  }
9250 
9251  if (clear_key)
9252  {
9253  pr_clear_value (&key);
9254  }
9255 
9256  return isvalid;
9257 }
9258 
9259 /*
9260  * locator_check_btree_entries () - Check consistency of btree entries and heap
9261  *
9262  * return: valid
9263  *
9264  * btid(in): Btree identifier
9265  * hfid(in): Heap identfier of the instances of class that are indexed
9266  * class_oid(in): The class identifier
9267  * n_attr_ids(in): Number of attribute ids (size of the array).
9268  * attr_ids(in): Attribute ID array.
9269  * btname(in) :
9270  * repair(in):
9271  *
9272  * Note: Check the consistency of the btree entries against the
9273  * instances stored on heap and vive versa.
9274  */
9276 locator_check_btree_entries (THREAD_ENTRY * thread_p, BTID * btid, HFID * hfid, OID * class_oid, int n_attr_ids,
9277  ATTR_ID * attr_ids, int *atts_prefix_length, const char *btname, bool repair)
9278 {
9279  DISK_ISVALID isvalid = DISK_VALID;
9280  DISK_ISVALID isallvalid = DISK_VALID;
9281  OID inst_oid, *p_inst_oid = &inst_oid;
9282  RECDES record = RECDES_INITIALIZER, *recordp = &record; /* Record descriptor for copying object */
9283  SCAN_CODE scan;
9284  HEAP_SCANCACHE scan_cache;
9285  BTREE_CHECKSCAN bt_checkscan;
9286  BTREE_SCAN bt_scan;
9287  HEAP_CACHE_ATTRINFO attr_info;
9288  int num_btree_oids = 0;
9289  int num_heap_oids = 0;
9290  int oid_cnt;
9291  OID *oid_area = NULL;
9292  INDX_SCAN_ID isid;
9293  BTREE_ISCAN_OID_LIST oid_list;
9294  int i;
9295  DB_VALUE dbvalue;
9296  DB_VALUE *key = NULL;
9297  char buf[DBVAL_BUFSIZE + MAX_ALIGNMENT], *aligned_buf;
9298  char *classname = NULL;
9300  int index_id;
9301  OR_INDEX *index = NULL;
9302  DB_LOGICAL ev_res;
9303  OR_CLASSREP *classrepr = NULL;
9305  BTID btid_info;
9306 #if defined(SERVER_MODE)
9307  int tran_index;
9308 #endif /* SERVER_MODE */
9309  bool is_scancache_started = false;
9310  bool is_attrinfo_started = false;
9311  bool is_bt_checkscan_started = false;
9312 
9313  mvcc_snapshot = logtb_get_mvcc_snapshot (thread_p);
9314  if (mvcc_snapshot == NULL)
9315  {
9316  return DISK_ERROR;
9317  }
9318  db_make_null (&dbvalue);
9319 
9320  aligned_buf = PTR_ALIGN (buf, MAX_ALIGNMENT);
9321 
9322 #if defined(SERVER_MODE)
9323  tran_index = LOG_FIND_THREAD_TRAN_INDEX (thread_p);
9324 #endif /* SERVER_MODE */
9325 
9326  scan_init_index_scan (&isid, NULL, mvcc_snapshot);
9327 
9328  /* Start a scan cursor and a class attribute information */
9329  if (heap_scancache_start (thread_p, &scan_cache, hfid, class_oid, false, false, mvcc_snapshot) != NO_ERROR)
9330  {
9331  return DISK_ERROR;
9332  }
9333  is_scancache_started = true;
9334 
9335  if (heap_attrinfo_start (thread_p, class_oid, n_attr_ids, attr_ids, &attr_info) != NO_ERROR)
9336  {
9337  goto error;
9338  }
9339  is_attrinfo_started = true;
9340 
9341  classrepr = attr_info.last_classrepr;
9342  if (classrepr == NULL)
9343  {
9344  goto error;
9345  }
9346  index_id = -1;
9347  for (i = 0; i < classrepr->n_indexes; i++)
9348  {
9349  if (BTID_IS_EQUAL (&(classrepr->indexes[i].btid), btid))
9350  {
9351  index_id = i;
9352  break;
9353  }
9354  }
9355  assert (index_id != -1);
9356 
9357  index = &(attr_info.last_classrepr->indexes[index_id]);
9358  assert (index != NULL);
9359 
9360  /*
9361  * Step 1) From Heap to B+tree
9362  */
9363 
9364  /* start a check-scan on index */
9365  if (btree_keyoid_checkscan_start (thread_p, btid, &bt_checkscan) != NO_ERROR)
9366  {
9367  goto error;
9368  }
9369  is_bt_checkscan_started = true;
9370 
9371  inst_oid.volid = hfid->vfid.volid;
9372  inst_oid.pageid = NULL_PAGEID;
9373  inst_oid.slotid = NULL_SLOTID;
9374 
9375  while ((scan = heap_next (thread_p, hfid, class_oid, &inst_oid, &record, &scan_cache, COPY)) == S_SUCCESS)
9376  {
9377  num_heap_oids++;
9378 
9379  if (index->filter_predicate)
9380  {
9381  if (locator_eval_filter_predicate (thread_p, &index->btid, index->filter_predicate, class_oid, &p_inst_oid, 1,
9382  &recordp, &ev_res) != NO_ERROR)
9383  {
9384  isallvalid = DISK_ERROR;
9385  }
9386  else if (ev_res != V_TRUE)
9387  {
9388  /*
9389  * To exclude the heap OID of which record cannot satisfy the
9390  * conditions of the index filter predicate.
9391  */
9392  num_heap_oids--;
9393  continue;
9394  }
9395  }
9396 
9397  /* Make sure that the index entry exist */
9398  if ((n_attr_ids == 1 && heap_attrinfo_read_dbvalues (thread_p, &inst_oid, &record, NULL, &attr_info) != NO_ERROR)
9399  || (key = heap_attrvalue_get_key (thread_p, index_id, &attr_info, &record, &btid_info, &dbvalue, aligned_buf,
9400  NULL, NULL)) == NULL)
9401  {
9402  if (isallvalid != DISK_INVALID)
9403  {
9404  isallvalid = DISK_ERROR;
9405  }
9406  }
9407  else
9408  {
9409  assert (key != NULL);
9410 
9411  if (db_value_is_null (key) || btree_multicol_key_is_null (key))
9412  {
9413  /* Do not check the btree since unbound values are not recorded */
9414  num_heap_oids--;
9415  }
9416  else
9417  {
9418  isvalid = btree_keyoid_checkscan_check (thread_p, &bt_checkscan, class_oid, key, &inst_oid);
9419 
9420  if (er_errid () == ER_INTERRUPTED)
9421  {
9422  /* in case of user interrupt */
9423  goto error;
9424  }
9425 
9426  if (isvalid == DISK_INVALID)
9427  {
9428  if (repair)
9429  {
9430  isvalid = locator_repair_btree_by_insert (thread_p, class_oid, btid, key, &inst_oid);
9431  }
9432 
9433  if (isvalid == DISK_INVALID)
9434  {
9435  char *key_dmp;
9436 
9437  key_dmp = pr_valstring (key);
9438 
9439  if (!OID_ISNULL (class_oid))
9440  {
9441  if (heap_get_class_name (thread_p, class_oid, &classname) != NO_ERROR)
9442  {
9443  /* ignore */
9444  er_clear ();
9445  }
9446  }
9447 
9449  (btname) ? btname : "*UNKNOWN-INDEX*", (classname) ? classname : "*UNKNOWN-CLASS*",
9450  class_oid->volid, class_oid->pageid, class_oid->slotid, (key_dmp) ? key_dmp : "_NULL_KEY",
9451  inst_oid.volid, inst_oid.pageid, inst_oid.slotid, btid->vfid.volid, btid->vfid.fileid,
9452  btid->root_pageid);
9453 
9454  if (key_dmp)
9455  {
9456  db_private_free (thread_p, key_dmp);
9457  }
9458 
9459  if (classname)
9460  {
9461  free_and_init (classname);
9462  }
9463 
9464  if (isallvalid != DISK_INVALID)
9465  {
9466  isallvalid = isvalid;
9467  }
9468  }
9469  }
9470  }
9471  }
9472 
9473  if (key == &dbvalue)
9474  {
9475  pr_clear_value (key);
9476  key = NULL;
9477  }
9478  }
9479 
9480  if (scan != S_END && isallvalid != DISK_INVALID)
9481  {
9482  isallvalid = DISK_ERROR;
9483  }
9484 
9485  /* close the index check-scan */
9486  btree_keyoid_checkscan_end (thread_p, &bt_checkscan);
9487  is_bt_checkscan_started = false;
9488 
9489  /* Finish scan cursor and class attribute cache information */
9490  heap_attrinfo_end (thread_p, &attr_info);
9491  is_attrinfo_started = false;
9492 
9493  /*
9494  * Step 2) From B+tree to Heap
9495  */
9496 
9497  BTREE_INIT_SCAN (&bt_scan);
9498 
9499  isid.oid_list = &oid_list;
9500  isid.oid_list->oid_cnt = 0;
9501  isid.oid_list->oidp = (OID *) malloc (ISCAN_OID_BUFFER_CAPACITY);
9502  if (isid.oid_list->oidp == NULL)
9503  {
9505 
9506  isallvalid = DISK_ERROR;
9507  goto error;
9508  }
9510  isid.oid_list->max_oid_cnt = isid.oid_list->capacity;
9511  isid.oid_list->next_list = NULL;
9512  isid.indx_info = NULL;
9513 
9514  /* alloc index key copy_buf */
9515  isid.copy_buf = (char *) db_private_alloc (thread_p, DBVAL_BUFSIZE);
9516  if (isid.copy_buf == NULL)
9517  {
9518  isallvalid = DISK_ERROR;
9519  goto error;
9520  }
9521  isid.copy_buf_len = DBVAL_BUFSIZE;
9522  memset ((void *) (&(isid.indx_cov)), 0, sizeof (INDX_COV));
9523  memset ((void *) (&(isid.multi_range_opt)), 0, sizeof (MULTI_RANGE_OPT));
9524 
9525  scan_init_iss (&isid);
9526 
9527  if (heap_scancache_start (thread_p, &isid.scan_cache, hfid, class_oid, true, true, mvcc_snapshot) != NO_ERROR)
9528  {
9529  isallvalid = DISK_ERROR;
9530  goto error;
9531  }
9532 
9533  isid.check_not_vacuumed = true;
9534  db_make_null (&key_val_range.key1);
9535  db_make_null (&key_val_range.key2);
9536  key_val_range.range = INF_INF;
9537  key_val_range.num_index_term = 0;
9538  do
9539  {
9540  /* search index */
9541  if (btree_prepare_bts (thread_p, &bt_scan, btid, &isid, &key_val_range, NULL, class_oid, NULL, NULL, false, NULL)
9542  != NO_ERROR)
9543  {
9544  assert (er_errid () != NO_ERROR);
9545  break;
9546  }
9547  if (btree_range_scan (thread_p, &bt_scan, btree_range_scan_select_visible_oids) != NO_ERROR)
9548  {
9549  assert (er_errid () != NO_ERROR);
9550  break;
9551  }
9552  oid_cnt = bt_scan.n_oids_read_last_iteration;
9553  if (oid_cnt < 0)
9554  {
9555  assert (false);
9556  break;
9557  }
9558  oid_area = isid.oid_list->oidp;
9559  num_btree_oids += oid_cnt;
9560  for (i = 0; i < oid_cnt; i++)
9561  {
9562  if (!heap_does_exist (thread_p, class_oid, &oid_area[i]))
9563  {
9564  isvalid = DISK_INVALID;
9565 
9566  if (repair)
9567  {
9568  /* don't care about filter predicate here since we are sure that oid_area[i] is contained in tree,
9569  * the keys has been already S_LOCK-ed. */
9570  isvalid = locator_repair_btree_by_delete (thread_p, class_oid, btid, &oid_area[i]);
9571  }
9572 
9573  if (isvalid == DISK_VALID)
9574  {
9575  num_btree_oids--;
9576  }
9577  else
9578  {
9579  if (!OID_ISNULL (class_oid))
9580  {
9581  if (heap_get_class_name (thread_p, class_oid, &classname) != NO_ERROR)
9582  {
9583  /* ignore */
9584  er_clear ();
9585  }
9586  }
9587 
9589  (btname) ? btname : "*UNKNOWN-INDEX*", (classname) ? classname : "*UNKNOWN-CLASS*",
9590  class_oid->volid, class_oid->pageid, class_oid->slotid, oid_area[i].volid, oid_area[i].pageid,
9591  oid_area[i].slotid, btid->vfid.volid, btid->vfid.fileid, btid->root_pageid);
9592 
9593  if (classname)
9594  {
9595  free_and_init (classname);
9596  }
9597 
9598  isallvalid = DISK_INVALID;
9599  }
9600  }
9601  }
9602 
9603  }
9604  while (!BTREE_END_OF_SCAN (&bt_scan));
9605 
9606  if (heap_scancache_end (thread_p, &isid.scan_cache) != NO_ERROR)
9607  {
9608  isallvalid = DISK_INVALID;
9609  }
9610 
9611  if (num_heap_oids != num_btree_oids)
9612  {
9613  if (!OID_ISNULL (class_oid))
9614  {
9615  if (heap_get_class_name (thread_p, class_oid, &classname) != NO_ERROR)
9616  {
9617  /* ignore */
9618  er_clear ();
9619  }
9620  }
9621 
9623  (btname) ? btname : "*UNKNOWN-INDEX*", (classname) ? classname : "*UNKNOWN-CLASS*", class_oid->volid,
9624  class_oid->pageid, class_oid->slotid, num_heap_oids, num_btree_oids, btid->vfid.volid, btid->vfid.fileid,
9625  btid->root_pageid);
9626 
9627  if (classname)
9628  {
9629  free_and_init (classname);
9630  }
9631 
9632  isallvalid = DISK_INVALID;
9633  }
9634 
9635  if (isid.check_not_vacuumed && isid.not_vacuumed_res != DISK_VALID)
9636  {
9638  (btname) ? btname : "*UNKNOWN-INDEX*", (classname) ? classname : "*UNKNOWN-CLASS*", class_oid->volid,
9639  class_oid->pageid, class_oid->slotid);
9640  isallvalid = isid.not_vacuumed_res;
9641  }
9642 
9643 end:
9644 
9645  if (key == &dbvalue)
9646  {
9647  pr_clear_value (key);
9648  }
9649 
9650  if (isid.oid_list != NULL && isid.oid_list->oidp != NULL)
9651  {
9652  free_and_init (isid.oid_list->oidp);
9653  }
9654 
9655  /* free index key copy_buf */
9656  if (isid.copy_buf)
9657  {
9658  db_private_free_and_init (thread_p, isid.copy_buf);
9659  }
9660 
9661  if (is_scancache_started && heap_scancache_end (thread_p, &scan_cache) != NO_ERROR)
9662  {
9663  isallvalid = DISK_INVALID;
9664  }
9665 
9666  if (is_bt_checkscan_started)
9667  {
9668  btree_keyoid_checkscan_end (thread_p, &bt_checkscan);
9669  }
9670 
9671  if (is_attrinfo_started)
9672  {
9673  heap_attrinfo_end (thread_p, &attr_info);
9674  }
9675 
9676  return isallvalid;
9677 
9678 error:
9679  isallvalid = DISK_ERROR;
9680  goto end;
9681 }
9682 
9683 /*
9684  * locator_check_unique_btree_entries () - Check consistency of unique btree entries
9685  * and heaps
9686  *
9687  * return: valid
9688  *
9689  * btid(in): Btree identifier
9690  * class_oid(in):
9691  * classrec(in):
9692  * attr_ids(in): Array of indexed attributes for the btid
9693  * repair(in):
9694  *
9695  * Note: Check the consistency of the unique btree entries against the
9696  * instances stored on heap and vice versa. Unique btrees are
9697  * special because they span hierarchies and can have multiple
9698  * heaps associated with them.
9699  */
9700 static DISK_ISVALID
9701 locator_check_unique_btree_entries (THREAD_ENTRY * thread_p, BTID * btid, OID * cls_oid, RECDES * classrec,
9702  ATTR_ID * attr_ids, const char *btname, bool repair)
9703 {
9704  DISK_ISVALID isvalid = DISK_VALID, isallvalid = DISK_VALID;
9705  OID inst_oid, *p_inst_oid = &inst_oid;
9706  RECDES peek = RECDES_INITIALIZER, *p_peek = &peek;
9707  SCAN_CODE scan;
9708  HEAP_SCANCACHE *scan_cache = NULL;
9709  BTREE_CHECKSCAN bt_checkscan;
9710  BTREE_SCAN bt_scan;
9711  HEAP_CACHE_ATTRINFO attr_info;
9712  DB_VALUE *key = NULL;
9713  DB_VALUE dbvalue;
9714  int num_btree_oids = 0, num_heap_oids = 0, num_nulls = 0;
9715  int oid_cnt;
9716  OID *oid_area = NULL;
9717  int num_classes, scancache_inited = 0, attrinfo_inited = 0;
9718  int i, j, index_id;
9719  HFID *hfids = NULL, *hfid = NULL;
9720  OID *class_oids = NULL, *class_oid = NULL;
9721  INDX_SCAN_ID isid;
9722  BTREE_ISCAN_OID_LIST oid_list;
9723  char buf[DBVAL_BUFSIZE + MAX_ALIGNMENT], *aligned_buf;
9724  char *classname = NULL;
9726  OR_INDEX *index;
9727  DB_LOGICAL ev_res;
9728  int partition_local_index = 0;
9730 #if defined(SERVER_MODE)
9731  int tran_index;
9732 #else
9733  int btree_oid_cnt, btree_null_cnt, btree_key_cnt;
9734 #endif /* SERVER_MODE */
9735  bool bt_checkscan_inited = false;
9736 
9737  mvcc_snapshot = logtb_get_mvcc_snapshot (thread_p);
9738  if (mvcc_snapshot == NULL)
9739  {
9740  return DISK_ERROR;
9741  }
9742  db_make_null (&dbvalue);
9743 
9744  aligned_buf = PTR_ALIGN (buf, MAX_ALIGNMENT);
9745 
9746 #if defined(SERVER_MODE)
9747  tran_index = LOG_FIND_THREAD_TRAN_INDEX (thread_p);
9748 #endif /* SERVER_MODE */
9749 
9750  scan_init_index_scan (&isid, NULL, mvcc_snapshot);
9751 
9752  /* get all the heap files associated with this unique btree */
9753  if (or_get_unique_hierarchy (thread_p, classrec, attr_ids[0], btid, &class_oids, &hfids, &num_classes,
9754  &partition_local_index) != NO_ERROR
9755  || class_oids == NULL || hfids == NULL || num_classes < 1)
9756  {
9757  if (class_oids != NULL)
9758  {
9759  free_and_init (class_oids);
9760  }
9761 
9762  if (hfids != NULL)
9763  {
9764  free_and_init (hfids);
9765  }
9766 
9767  goto error;
9768  }
9769 
9770  /*
9771  * Step 1) Check if all instances of all the heaps are in the unique btree.
9772  */
9773 
9774  scan_cache = (HEAP_SCANCACHE *) malloc (num_classes * sizeof (HEAP_SCANCACHE));
9775  if (scan_cache == NULL)
9776  {
9778  goto error;
9779  }
9780 
9781  if (partition_local_index == 1)
9782  {
9783  if (num_classes == 1)
9784  {
9785  /* partition class with local index */
9786  COPY_OID (&class_oids[0], cls_oid);
9787  or_class_hfid (classrec, &hfids[0]);
9788  }
9789  else
9790  {
9791  /* a partitioned class and a local index */
9792  goto end;
9793  }
9794  }
9795 
9796  for (j = 0; j < num_classes; j++)
9797  {
9798  hfid = &hfids[j];
9799  class_oid = &class_oids[j];
9800 
9801  /* Start a scan cursor and a class attribute information */
9802  if (heap_scancache_start (thread_p, &scan_cache[j], hfid, class_oid, true, false, mvcc_snapshot) != NO_ERROR)
9803  {
9804  goto error;
9805  }
9806  scancache_inited++;
9807 
9808  index_id = heap_attrinfo_start_with_btid (thread_p, class_oid, btid, &attr_info);
9809  if (index_id < 0)
9810  {
9811  goto error;
9812  }
9813  index = &(attr_info.last_classrepr->indexes[index_id]);
9814  assert (index != NULL);
9815 
9816  attrinfo_inited = 1;
9817 
9818  /* start a check-scan on index */
9819  if (btree_keyoid_checkscan_start (thread_p, btid, &bt_checkscan) != NO_ERROR)
9820  {
9821  goto error;
9822  }
9823  bt_checkscan_inited = true;
9824 
9825  inst_oid.volid = hfid->vfid.volid;
9826  inst_oid.pageid = NULL_PAGEID;
9827  inst_oid.slotid = NULL_SLOTID;
9828 
9829  while ((scan = heap_next (thread_p, hfid, class_oid, &inst_oid, &peek, &scan_cache[j], PEEK)) == S_SUCCESS)
9830  {
9831  num_heap_oids++;
9832 
9833  if (index->filter_predicate)
9834  {
9836  (thread_p, btid, index->filter_predicate, class_oid, &p_inst_oid, 1, &p_peek, &ev_res) != NO_ERROR)
9837  {
9838  goto error;
9839  }
9840  else if (ev_res != V_TRUE)
9841  {
9842  continue;
9843  }
9844  }
9845 
9846  /* Make sure that the index entry exists */
9847  if ((heap_attrinfo_read_dbvalues (thread_p, &inst_oid, &peek, NULL, &attr_info) != NO_ERROR)
9848  ||
9849  ((key =
9850  heap_attrvalue_get_key (thread_p, index_id, &attr_info, &peek, btid, &dbvalue, aligned_buf, NULL,
9851  NULL)) == NULL))
9852  {
9853  if (isallvalid != DISK_INVALID)
9854  {
9855  isallvalid = DISK_ERROR;
9856  }
9857  }
9858  else
9859  {
9860  assert (key != NULL);
9861 
9862  if (db_value_is_null (key) || btree_multicol_key_is_null (key))
9863  {
9864  num_nulls++;
9865  }
9866  else
9867  {
9868  isvalid = btree_keyoid_checkscan_check (thread_p, &bt_checkscan, class_oid, key, &inst_oid);
9869 
9870  if (er_errid () == ER_INTERRUPTED)
9871  {
9872  /* in case of user interrupt */
9873  goto error;
9874  }
9875 
9876  if (isvalid == DISK_INVALID)
9877  {
9878  if (repair)
9879  {
9880  isvalid = locator_repair_btree_by_insert (thread_p, class_oid, btid, key, &inst_oid);
9881  }
9882 
9883  if (isvalid == DISK_INVALID)
9884  {
9885  char *key_dmp;
9886 
9887  key_dmp = pr_valstring (key);
9888  if (!OID_ISNULL (class_oid))
9889  {
9890  if (heap_get_class_name (thread_p, class_oid, &classname) != NO_ERROR)
9891  {
9892  /* ignore */
9893  er_clear ();
9894  }
9895  }
9896 
9898  (btname) ? btname : "*UNKNOWN-INDEX*", (classname) ? classname : "*UNKNOWN-CLASS*",
9899  class_oid->volid, class_oid->pageid, class_oid->slotid,
9900  (key_dmp) ? key_dmp : "_NULL_KEY", inst_oid.volid, inst_oid.pageid, inst_oid.slotid,
9901  btid->vfid.volid, btid->vfid.fileid, btid->root_pageid);
9902 
9903  if (key_dmp)
9904  {
9905  db_private_free (thread_p, key_dmp);
9906  }
9907 
9908  if (classname)
9909  {
9910  free_and_init (classname);
9911  }
9912 
9913  if (isallvalid != DISK_INVALID)
9914  {
9915  isallvalid = isvalid;
9916  }
9917  }
9918  }
9919  }
9920  }
9921 
9922  if (key == &dbvalue)
9923  {
9924  pr_clear_value (key);
9925  }
9926  }
9927 
9928  if (scan != S_END && isallvalid != DISK_INVALID)
9929  {
9930  isallvalid = DISK_ERROR;
9931  }
9932 
9933  /* close the index check-scan */
9934  btree_keyoid_checkscan_end (thread_p, &bt_checkscan);
9935  bt_checkscan_inited = false;
9936 
9937  /* Finish scan cursor and class attribute cache information */
9938  heap_attrinfo_end (thread_p, &attr_info);
9939  attrinfo_inited = 0;
9940  }
9941 
9942  /*
9943  * Step 2) Check that all the btree entries are members of one of the heaps.
9944  */
9945 
9946  BTREE_INIT_SCAN (&bt_scan);
9947 
9948  isid.oid_list = &oid_list;
9949  isid.oid_list->oid_cnt = 0;
9950  isid.oid_list->oidp = (OID *) malloc (ISCAN_OID_BUFFER_CAPACITY);
9951  if (isid.oid_list->oidp == NULL)
9952  {
9954  goto error;
9955  }
9957  isid.oid_list->max_oid_cnt = isid.oid_list->capacity;
9958  isid.oid_list->next_list = NULL;
9959  /* alloc index key copy_buf */
9960  isid.copy_buf = (char *) db_private_alloc (thread_p, DBVAL_BUFSIZE);
9961  if (isid.copy_buf == NULL)
9962  {
9963  goto error;
9964  }
9965  isid.copy_buf_len = DBVAL_BUFSIZE;
9966 
9967  if (heap_scancache_start (thread_p, &isid.scan_cache, hfid, class_oid, true, true, mvcc_snapshot) != NO_ERROR)
9968  {
9969  goto error;
9970  }
9971 
9972  isid.check_not_vacuumed = true;
9973  db_make_null (&key_val_range.key1);
9974  db_make_null (&key_val_range.key2);
9975  key_val_range.range = INF_INF;
9976  key_val_range.num_index_term = 0;
9977 
9978  do
9979  {
9980  /* search index */
9981  if (btree_prepare_bts (thread_p, &bt_scan, btid, &isid, &key_val_range, NULL, NULL, NULL, NULL, false, NULL) !=
9982  NO_ERROR)
9983  {
9984  assert (er_errid () != NO_ERROR);
9985  break;
9986  }
9987  if (btree_range_scan (thread_p, &bt_scan, btree_range_scan_select_visible_oids) != NO_ERROR)
9988  {
9989  assert (er_errid () != NO_ERROR);
9990  break;
9991  }
9992  oid_cnt = bt_scan.n_oids_read_last_iteration;
9993 
9994  /* TODO: unique with prefix length */
9995  /* ^ What is this TODO? ^ */
9996 
9997  if (oid_cnt == -1)
9998  {
9999  assert (false);
10000  break;
10001  }
10002 
10003  oid_area = isid.oid_list->oidp;
10004 
10005  num_btree_oids += oid_cnt;
10006  for (i = 0; i < oid_cnt; i++)
10007  {
10008  if (!heap_does_exist (thread_p, NULL, &oid_area[i]))
10009  {
10010  isvalid = DISK_INVALID;
10011  if (repair)
10012  {
10013  /* don't care about filter predicate here since we are sure that oid_area[i] is contained in tree the
10014  * keys has been already S_LOCK-ed. */
10015  isvalid = locator_repair_btree_by_delete (thread_p, class_oid, btid, &oid_area[i]);
10016  }
10017 
10018  if (isvalid == DISK_VALID)
10019  {
10020  num_btree_oids--;
10021  }
10022  else
10023  {
10024  if (!OID_ISNULL (class_oid))
10025  {
10026  if (heap_get_class_name (thread_p, class_oid, &classname) != NO_ERROR)
10027  {
10028  /* ignore */
10029  er_clear ();
10030  }
10031  }
10032 
10034  (btname) ? btname : "*UNKNOWN-INDEX*", (classname) ? classname : "*UNKNOWN-CLASS*",
10035  class_oid->volid, class_oid->pageid, class_oid->slotid, oid_area[i].volid, oid_area[i].pageid,
10036  oid_area[i].slotid, btid->vfid.volid, btid->vfid.fileid, btid->root_pageid);
10037 
10038  if (classname)
10039  {
10040  free_and_init (classname);
10041  }
10042 
10043  isallvalid = DISK_INVALID;
10044  }
10045  }
10046  else
10047  {
10048  OID cl_oid;
10049  int found = 0;
10050 
10051  /*
10052  * check to make sure that the OID is one of the OIDs from our
10053  * list of classes.
10054  */
10055  if (heap_get_class_oid (thread_p, &oid_area[i], &cl_oid) != S_SUCCESS)
10056  {
10057  (void) heap_scancache_end (thread_p, &isid.scan_cache);
10058  goto error;
10059  }
10060 
10061  for (j = 0, found = 0; found == 0 && class_oids != NULL && j < num_classes; j++)
10062  {
10063  if (OID_EQ (&cl_oid, &(class_oids[j])))
10064  {
10065  found = 1;
10066  }
10067  }
10068 
10069  if (!found)
10070  {
10071  if (!OID_ISNULL (class_oid))
10072  {
10073  if (heap_get_class_name (thread_p, class_oid, &classname) != NO_ERROR)
10074  {
10075  /* ignore */
10076  er_clear ();
10077  }
10078  }
10079 
10081  (btname) ? btname : "*UNKNOWN-INDEX*", (classname) ? classname : "*UNKNOWN-CLASS*",
10082  class_oid->volid, class_oid->pageid, class_oid->slotid, oid_area[i].volid, oid_area[i].pageid,
10083  oid_area[i].slotid, btid->vfid.volid, btid->vfid.fileid, btid->root_pageid);
10084 
10085  if (classname)
10086  {
10087  free_and_init (classname);
10088  }
10089  isallvalid = DISK_INVALID;
10090  }
10091  }
10092  }
10093  }
10094  while (!BTREE_END_OF_SCAN (&bt_scan));
10095 
10096  free_and_init (isid.oid_list->oidp);
10097  /* free index key copy_buf */
10098  if (isid.copy_buf)
10099  {
10100  db_private_free_and_init (thread_p, isid.copy_buf);
10101  }
10102 
10103  if (heap_scancache_end (thread_p, &isid.scan_cache) != NO_ERROR)
10104  {
10105  goto error;
10106  }
10107 
10108  /* check to see that the btree root statistics are correct. */
10109 #if defined(SA_MODE)
10110  if (logtb_get_global_unique_stats (thread_p, btid, &btree_oid_cnt, &btree_null_cnt, &btree_key_cnt) != NO_ERROR)
10111  {
10112  goto error;
10113  }
10114 #endif
10115 
10116  /* Do the numbers add up? */
10117  if (num_heap_oids != num_btree_oids + num_nulls)
10118  {
10119  if (!OID_ISNULL (class_oid))
10120  {
10121  if (heap_get_class_name (thread_p, class_oid, &classname) != NO_ERROR)
10122  {
10123  /* ignore */
10124  er_clear ();
10125  }
10126  }
10127 
10129  (btname) ? btname : "*UNKNOWN-INDEX*", (classname) ? classname : "*UNKNOWN-CLASS*", class_oid->volid,
10130  class_oid->pageid, class_oid->slotid, num_heap_oids, num_btree_oids, num_nulls, btid->vfid.volid,
10131  btid->vfid.fileid, btid->root_pageid);
10132 
10133  if (classname)
10134  {
10135  free_and_init (classname);
10136  }
10137 
10138  isallvalid = DISK_INVALID;
10139  }
10140 
10141 #if defined(SA_MODE)
10142  if (num_heap_oids != btree_oid_cnt)
10143  {
10144  if (!OID_ISNULL (class_oid))
10145  {
10146  if (heap_get_class_name (thread_p, class_oid, &classname) != NO_ERROR)
10147  {
10148  /* ignore */
10149  er_clear ();
10150  }
10151  }
10152 
10154  (btname) ? btname : "*UNKNOWN-INDEX*", (classname) ? classname : "*UNKNOWN-CLASS*", class_oid->volid,
10155  class_oid->pageid, class_oid->slotid, num_heap_oids, btree_oid_cnt, btid->vfid.volid, btid->vfid.fileid,
10156  btid->root_pageid);
10157 
10158  if (classname)
10159  {
10160  free_and_init (classname);
10161  }
10162 
10163  isallvalid = DISK_INVALID;
10164  }
10165 
10166  if (num_nulls != btree_null_cnt)
10167  {
10168  if (!OID_ISNULL (class_oid))
10169  {
10170  if (heap_get_class_name (thread_p, class_oid, &classname) != NO_ERROR)
10171  {
10172  /* ignore */
10173  er_clear ();
10174  }
10175  }
10176 
10178  (btname) ? btname : "*UNKNOWN-INDEX*", (classname) ? classname : "*UNKNOWN-CLASS*", class_oid->volid,
10179  class_oid->pageid, class_oid->slotid, num_nulls, btree_null_cnt, btid->vfid.volid, btid->vfid.fileid,
10180  btid->root_pageid);
10181 
10182  if (classname)
10183  {
10184  free_and_init (classname);
10185  }
10186  isallvalid = DISK_INVALID;
10187  }
10188 
10189  /* finally check if the btree thinks that it is unique */
10190  if (btree_oid_cnt != btree_null_cnt + btree_key_cnt)
10191  {
10192  if (!OID_ISNULL (class_oid))
10193  {
10194  if (heap_get_class_name (thread_p, class_oid, &classname) != NO_ERROR)
10195  {
10196  /* ignore */
10197  er_clear ();
10198  }
10199  }
10200 
10202  (btname) ? btname : "*UNKNOWN-INDEX*", (classname) ? classname : "*UNKNOWN-CLASS*", class_oid->volid,
10203  class_oid->pageid, class_oid->slotid, btree_oid_cnt, btree_null_cnt, btree_key_cnt, btid->vfid.volid,
10204  btid->vfid.fileid, btid->root_pageid);
10205 
10206  if (classname)
10207  {
10208  free_and_init (classname);
10209  }
10210 
10211  isallvalid = DISK_INVALID;
10212  }
10213 #endif
10214 
10215  if (isid.check_not_vacuumed && isid.not_vacuumed_res != DISK_VALID)
10216  {
10218  (btname) ? btname : "*UNKNOWN-INDEX*", (classname) ? classname : "*UNKNOWN-CLASS*", class_oid->volid,
10219  class_oid->pageid, class_oid->slotid);
10220  isallvalid = isid.not_vacuumed_res;
10221  }
10222 
10223 end:
10224 
10225  for (j = 0; j < scancache_inited; j++)
10226  {
10227  if (heap_scancache_end (thread_p, &scan_cache[j]) != NO_ERROR)
10228  {
10229  goto error;
10230  }
10231  }
10232 
10233  if (scan_cache)
10234  {
10235  free_and_init (scan_cache);
10236  }
10237 
10238  free_and_init (class_oids);
10239  free_and_init (hfids);
10240 
10241  return isallvalid;
10242 
10243 error:
10244 
10245  if (isid.oid_list != NULL && isid.oid_list->oidp != NULL)
10246  {
10247  free_and_init (isid.oid_list->oidp);
10248  }
10249 
10250  /* free index key copy_buf */
10251  if (isid.copy_buf)
10252  {
10253  db_private_free_and_init (thread_p, isid.copy_buf);
10254  }
10255 
10256  if (class_oids)
10257  {
10258  free_and_init (class_oids);
10259  }
10260 
10261  if (hfids)
10262  {
10263  free_and_init (hfids);
10264  }
10265 
10266  if (attrinfo_inited)
10267  {
10268  heap_attrinfo_end (thread_p, &attr_info);
10269  }
10270 
10271  for (j = 0; j < scancache_inited; j++)
10272  {
10273  (void) heap_scancache_end (thread_p, &scan_cache[j]);
10274  }
10275 
10276  if (scan_cache)
10277  {
10278  free_and_init (scan_cache);
10279  }
10280 
10281  if (bt_checkscan_inited)
10282  {
10283  btree_keyoid_checkscan_end (thread_p, &bt_checkscan);
10284  }
10285 
10286  return DISK_ERROR;
10287 }
10288 
10289 /*
10290  * locator_check_class () - Check consistency of a class
10291  *
10292  * return: valid
10293  *
10294  * repair(in):
10295  */
10297 locator_check_class (THREAD_ENTRY * thread_p, OID * class_oid, RECDES * peek, HFID * class_hfid, BTID * index_btid,
10298  bool repair)
10299 {
10300  DISK_ISVALID isvalid = DISK_VALID, rv = DISK_VALID;
10301  HEAP_CACHE_ATTRINFO attr_info;
10302  int i;
10303  HEAP_IDX_ELEMENTS_INFO idx_info;
10304  BTID *btid;
10305  ATTR_ID *attrids = NULL;
10306  int n_attrs;
10307  char *btname = NULL;
10308  int *attrs_prefix_length = NULL;
10309 
10310  if (heap_attrinfo_start_with_index (thread_p, class_oid, peek, &attr_info, &idx_info) < 0)
10311  {
10312  return DISK_ERROR;
10313  }
10314 
10315  if (idx_info.num_btids <= 0)
10316  {
10317  heap_attrinfo_end (thread_p, &attr_info);
10318  return DISK_VALID;
10319  }
10320 
10321  for (i = 0; i < idx_info.num_btids && rv != DISK_ERROR; i++)
10322  {
10323  btid = heap_indexinfo_get_btid (i, &attr_info);
10324  if (btid == NULL)
10325  {
10326  isvalid = DISK_ERROR;
10327  break;
10328  }
10329 
10330  if (index_btid != NULL && !BTID_IS_EQUAL (btid, index_btid))
10331  {
10332  continue;
10333  }
10334 
10335  n_attrs = heap_indexinfo_get_num_attrs (i, &attr_info);
10336  if (n_attrs <= 0)
10337  {
10338  isvalid = DISK_ERROR;
10339  break;
10340  }
10341 
10342  attrids = (ATTR_ID *) malloc (n_attrs * sizeof (ATTR_ID));
10343  if (attrids == NULL)
10344  {
10346  isvalid = DISK_ERROR;
10347  break;
10348  }
10349 
10350  if (heap_indexinfo_get_attrids (i, &attr_info, attrids) != NO_ERROR)
10351  {
10352  free_and_init (attrids);
10353  isvalid = DISK_ERROR;
10354  break;
10355  }
10356 
10357  attrs_prefix_length = (int *) malloc (n_attrs * sizeof (int));
10358  if (attrs_prefix_length == NULL)
10359  {
10360  free_and_init (attrids);
10361  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, n_attrs * sizeof (int));
10362  isvalid = DISK_ERROR;
10363  break;
10364  }
10365 
10366  if (heap_indexinfo_get_attrs_prefix_length (i, &attr_info, attrs_prefix_length, n_attrs) != NO_ERROR)
10367  {
10368  free_and_init (attrids);
10369  free_and_init (attrs_prefix_length);
10370  isvalid = DISK_ERROR;
10371  break;
10372  }
10373 
10374  if (heap_get_indexinfo_of_btid (thread_p, class_oid, btid, NULL, NULL, NULL, NULL, &btname, NULL) != NO_ERROR)
10375  {
10376  free_and_init (attrids);
10377  free_and_init (attrs_prefix_length);
10378  isvalid = DISK_ERROR;
10379  break;
10380  }
10381 
10382  if (xbtree_get_unique_pk (thread_p, btid))
10383  {
10384  rv = locator_check_unique_btree_entries (thread_p, btid, class_oid, peek, attrids, btname, repair);
10385  }
10386  else
10387  {
10388  rv =
10389  locator_check_btree_entries (thread_p, btid, class_hfid, class_oid, n_attrs, attrids, attrs_prefix_length,
10390  btname, repair);
10391  }
10392  if (rv != DISK_VALID)
10393  {
10394  isvalid = DISK_ERROR;
10395  }
10396 
10397  free_and_init (attrids);
10398  if (attrs_prefix_length)
10399  {
10400  free_and_init (attrs_prefix_length);
10401  }
10402  if (btname)
10403  {
10404  free_and_init (btname);
10405  }
10406  }
10407 
10408  heap_attrinfo_end (thread_p, &attr_info);
10409  return isvalid;
10410 }
10411 
10412 /*
10413  * locator_check_by_class_oid () - Check consistency of a class
10414  *
10415  * return: valid
10416  *
10417  * repair(in):
10418  *
10419  */
10421 locator_check_by_class_oid (THREAD_ENTRY * thread_p, OID * cls_oid, HFID * hfid, BTID * index_btid, bool repair)
10422 {
10423  RECDES copy_rec = RECDES_INITIALIZER;
10424  HEAP_SCANCACHE scan;
10425  HFID root_hfid;
10428 
10429  mvcc_snapshot = logtb_get_mvcc_snapshot (thread_p);
10430  if (mvcc_snapshot == NULL)
10431  {
10432  return DISK_ERROR;
10433  }
10434 
10435  if (boot_find_root_heap (&root_hfid) != NO_ERROR || HFID_IS_NULL (&root_hfid))
10436  {
10437  return DISK_ERROR;
10438  }
10439 
10440  if (heap_scancache_start (thread_p, &scan, &root_hfid, oid_Root_class_oid, true, false, mvcc_snapshot) != NO_ERROR)
10441  {
10442  return DISK_ERROR;
10443  }
10444 
10445  if (heap_get_class_record (thread_p, cls_oid, &copy_rec, &scan, COPY) != S_SUCCESS)
10446  {
10447  heap_scancache_end (thread_p, &scan);
10448  return DISK_ERROR;
10449  }
10450 
10451  /* lock class and unlatch page */
10452  if (lock_object (thread_p, cls_oid, oid_Root_class_oid, IS_LOCK, LK_COND_LOCK) != LK_GRANTED)
10453  {
10454  if (scan.page_watcher.pgptr != NULL)
10455  {
10456  pgbuf_ordered_unfix (thread_p, &scan.page_watcher);
10457  }
10458 
10459  if (lock_object (thread_p, cls_oid, oid_Root_class_oid, IS_LOCK, LK_UNCOND_LOCK) != LK_GRANTED)
10460  {
10461  heap_scancache_end (thread_p, &scan);
10462  return DISK_ERROR;
10463  }
10464 
10465  copy_rec.data = NULL;
10466  if (heap_get_class_record (thread_p, cls_oid, &copy_rec, &scan, COPY) != S_SUCCESS)
10467  {
10468  lock_unlock_object (thread_p, cls_oid, oid_Root_class_oid, IS_LOCK, true);
10469  heap_scancache_end (thread_p, &scan);
10470  return DISK_ERROR;
10471  }
10472  }
10473 
10474  /* we have lock on class_oid, record COPYed, while page is latched */
10475  if (scan.page_watcher.pgptr != NULL)
10476  {
10477  pgbuf_ordered_unfix (thread_p, &scan.page_watcher);
10478  }
10479 
10480  rv = locator_check_class (thread_p, cls_oid, &copy_rec, hfid, index_btid, repair);
10481 
10482  lock_unlock_object (thread_p, cls_oid, oid_Root_class_oid, IS_LOCK, true);
10483 
10484  heap_scancache_end (thread_p, &scan);
10485 
10486  return rv;
10487 }
10488 
10489 /*
10490  * locator_check_all_entries_of_all_btrees () - Check consistency of all
10491  * entries of all btrees
10492  *
10493  * return: valid
10494  *
10495  * repair(in):
10496  *
10497  * Note: Check the consistency of all entries of all btrees against the
10498  * the corresponding heaps.
10499  */
10502 {
10503  RECDES copy_rec = RECDES_INITIALIZER; /* Record descriptor for copy object */
10504  HFID root_hfid;
10505  HFID hfid;
10506  OID oid;
10507  HEAP_SCANCACHE scan;
10508  SCAN_CODE code = S_SUCCESS;
10509  DISK_ISVALID isallvalid = DISK_VALID;
10511 
10512  mvcc_snapshot = logtb_get_mvcc_snapshot (thread_p);
10513  if (mvcc_snapshot == NULL)
10514  {
10515  return DISK_ERROR;
10516  }
10517 
10518  /*
10519  * Find all the classes.
10520  * If the class has an index, check the logical consistency of the index
10521  */
10522 
10523  /* Find the heap for the root classes */
10524 
10525  if (boot_find_root_heap (&root_hfid) != NO_ERROR || HFID_IS_NULL (&root_hfid))
10526  {
10527  return DISK_ERROR;
10528  }
10529 
10530  if (heap_scancache_start (thread_p, &scan, &root_hfid, oid_Root_class_oid, true, false, mvcc_snapshot) != NO_ERROR)
10531  {
10532  return DISK_ERROR;
10533  }
10534 
10535  oid.volid = root_hfid.vfid.volid;
10536  oid.pageid = NULL_PAGEID;
10537  oid.slotid = NULL_SLOTID;
10538 
10539  while (isallvalid != DISK_ERROR)
10540  {
10541  copy_rec.data = NULL;
10542  code = heap_next (thread_p, &root_hfid, oid_Root_class_oid, &oid, &copy_rec, &scan, COPY);
10543  if (code != S_SUCCESS)
10544  {
10545  break;
10546  }
10547 
10548  or_class_hfid (&copy_rec, &hfid);
10549  if (HFID_IS_NULL (&hfid))
10550  {
10551  continue;
10552  }
10553 
10554  /* lock class and unlatch page */
10555  if (lock_object (thread_p, &oid, oid_Root_class_oid, IS_LOCK, LK_COND_LOCK) != LK_GRANTED)
10556  {
10557  if (scan.page_watcher.pgptr != NULL)
10558  {
10559  pgbuf_ordered_unfix (thread_p, &scan.page_watcher);
10560  }
10561 
10562  if (lock_object (thread_p, &oid, oid_Root_class_oid, IS_LOCK, LK_UNCOND_LOCK) != LK_GRANTED)
10563  {
10564  break;
10565  }
10566 
10567  copy_rec.data = NULL;
10568  code = heap_get_class_record (thread_p, &oid, &copy_rec, &scan, COPY);
10569  if (code != S_SUCCESS)
10570  {
10571  break;
10572  }
10573  }
10574 
10575  /* we have lock on class_oid, record COPYed, while page is latched */
10576  if (scan.page_watcher.pgptr != NULL)
10577  {
10578  pgbuf_ordered_unfix (thread_p, &scan.page_watcher);
10579  }
10580 
10581  if (locator_check_class (thread_p, &oid, &copy_rec, &hfid, NULL, repair) != DISK_VALID)
10582  {
10583  isallvalid = DISK_ERROR;
10584  }
10585 
10586  lock_unlock_object (thread_p, &oid, oid_Root_class_oid, IS_LOCK, true);
10587  }
10588 
10589  if (code != S_END)
10590  {
10591  isallvalid = DISK_ERROR;
10592  }
10593 
10594  /* End the scan cursor */
10595  if (heap_scancache_end (thread_p, &scan) != NO_ERROR)
10596  {
10597  isallvalid = DISK_ERROR;
10598  }
10599 
10600  return isallvalid;
10601 }
10602 
10603 /*
10604  * locator_guess_sub_classes () - Guess the subclasses of the given hinted classes
10605  *
10606  * return: NO_ERROR if all OK, ER_ status otherwise
10607  *
10608  * lockhint_subclasses(in): lockhint structure which describes classes
10609  * The content is updated and the structure itself may be
10610  * reallocated
10611  *
10612  * Note:This function guess the subclasses identifiers of requested
10613  * subclasses for the classes referenced by the lockhint
10614  * structure. The lockhint structure is updated to contain the
10615  * needed subclasses.
10616  *
10617  * The subclasses are only guessed for lock hint purposes and
10618  * they should not be used for any other purposes (it is OK, to
10619  * send the objects to the client). That is, the found subclasses
10620  * reflects the classes on the server(database volumes) as they
10621  * are when the function is invoked; the function does not wait
10622  * even when the classes/subclasses may be in the process of been
10623  * updated by any transaction.
10624  *
10625  * In general the function is used to approximately find out all
10626  * needed subclasses, so that they can be locked along with a
10627  * requested set of classes all at once...and not in pieces since
10628  * the later can produce deadlocks.
10629  */
10630 static int
10632 {
10633  int ref_num; /* Max and reference number in request area */
10634  int max_stack; /* Total size of stack */
10635  int stack_actual_size; /* Actual size of stack */
10636  int *stack; /* The stack for the search */
10637  int max_oid_list; /* Max number of immediate subclasses */
10638  OID *oid_list = NULL; /* List of ref for one object */
10639  HEAP_SCANCACHE scan_cache; /* Scan cache used for fetching purposes */
10640  SCAN_CODE scan; /* Scan return value for an object */
10641  void *new_ptr;
10642  RECDES peek_recdes;
10643  LC_LOCKHINT *lockhint;
10644  int num_original_classes;
10645  LOCK lock;
10646  int i, j, k;
10647  int error_code = NO_ERROR;
10648 
10649  /*
10650  * Start a scan cursor for fetching the desired classes.
10651  */
10652 
10653  error_code = heap_scancache_start (thread_p, &scan_cache, NULL, NULL, true, false, NULL);
10654  if (error_code != NO_ERROR)
10655  {
10656  return error_code;
10657  }
10658 
10659  lockhint = *lockhint_subclasses;
10660 
10661  /*
10662  * Let's assume a number of subclasses for allocation purposes of the stack.
10663  * We will assume at least one subclass per class and a minimum of 10
10664  * subclasses for all requested classes.
10665  */
10666 
10667  max_stack = lockhint->max_classes * 2;
10668  if (max_stack < 10)
10669  {
10670  max_stack = 10;
10671  }
10672  max_oid_list = max_stack;
10673 
10674  stack = (int *) malloc (sizeof (*stack) * max_stack);
10675  if (stack == NULL)
10676  {
10677  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, sizeof (*stack) * max_stack);
10678  error_code = ER_OUT_OF_VIRTUAL_MEMORY;
10679  goto error;
10680  }
10681  oid_list = (OID *) malloc (sizeof (*oid_list) * max_oid_list);
10682  if (oid_list == NULL)
10683  {
10684  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, sizeof (*oid_list) * max_oid_list);
10685  error_code = ER_OUT_OF_VIRTUAL_MEMORY;
10686  goto error;
10687  }
10688 
10689  /*
10690  * Obtain the subclasses requested.
10691  */
10692 
10693  num_original_classes = lockhint->num_classes;
10694  for (i = 0; i < num_original_classes; i++)
10695  {
10696  if (OID_ISNULL (&lockhint->classes[i].oid) || OID_ISTEMP (&lockhint->classes[i].oid)
10697  || lockhint->classes[i].need_subclasses <= 0)
10698  {
10699  /*
10700  * It has already been visited or we don't care about its subclasses
10701  */
10702  continue;
10703  }
10704 
10705  /*
10706  * Make sure that this is a valid class
10707  */
10708 
10709  if (!heap_does_exist (thread_p, NULL, &lockhint->classes[i].oid))
10710  {
10711  if (er_errid () == ER_INTERRUPTED)
10712  {
10713  error_code = ER_INTERRUPTED;
10714  goto error;
10715  }
10716 
10718  lockhint->classes[i].oid.pageid, lockhint->classes[i].oid.slotid);
10719  /*
10720  * The class did not exist, continue even in the event of errors.
10721  * Eliminate this class from the list of requested classes.
10722  */
10723  OID_SET_NULL (&lockhint->classes[i].oid);
10724  continue;
10725  }
10726 
10727  /*
10728  * Add the class to the stack and indicate that it has not been visited.
10729  */
10730 
10731  /* Initialize the stack and push the element */
10732  stack_actual_size = 0;
10733  stack[stack_actual_size++] = i;
10734 
10735  /*
10736  * Star a kind of depth-first search algorithm to find out subclasses
10737  */
10738 
10739  while (stack_actual_size > 0)
10740  {
10741  /* Pop */
10742  ref_num = stack[--stack_actual_size];
10743 
10744  /*
10745  * Get the class to find out its immediate subclasses
10746  */
10747 
10748  scan = heap_get_class_record (thread_p, &lockhint->classes[ref_num].oid, &peek_recdes, &scan_cache, PEEK);
10749  if (scan != S_SUCCESS)
10750  {
10751  if (scan != S_DOESNT_EXIST && (lockhint->quit_on_errors == (int) true || er_errid () == ER_INTERRUPTED))
10752  {
10753  error_code = ER_FAILED;
10754  goto error;
10755  }
10756 
10757  /*
10758  * Continue after an error. Remove the class from the list of
10759  * requested classes
10760  */
10761 
10762  if (ref_num == lockhint->num_classes - 1)
10763  {
10764  /* Last element remove it */
10765  lockhint->num_classes--;
10766  }
10767  else
10768  {
10769  /* Marked it as invalid */
10770  OID_SET_NULL (&lockhint->classes[ref_num].oid);
10771  }
10772  er_clear ();
10773  continue;
10774  }
10775 
10776  /*
10777  * has the class been visited ?
10778  */
10779 
10780  if (lockhint->classes[i].need_subclasses <= 0)
10781  {
10782  /*
10783  * This class has already been visited;
10784  */
10785  continue;
10786  }
10787 
10788 
10789  /*
10790  * Object has never been visited. First time in the stack.
10791  * Mark this class as visited.
10792  */
10793 
10794  lockhint->classes[ref_num].need_subclasses = -lockhint->classes[ref_num].need_subclasses;
10795 
10796  /*
10797  * Find all immediate subclasses for this class
10798  */
10799 
10800  OID_SET_NULL (&oid_list[0]);
10801 
10802  error_code = orc_subclasses_from_record (&peek_recdes, &max_oid_list, &oid_list);
10803  if (error_code != NO_ERROR)
10804  {
10805  if (lockhint->quit_on_errors == (int) true)
10806  {
10807  goto error;
10808  }
10809 
10810  /* Continue even in the case of an error */
10811  error_code = NO_ERROR;
10812  continue;
10813  }
10814 
10815  /*
10816  * Add the above references to the stack if these classes have not
10817  * been already been visited or if their current level is smaller
10818  * than their visited level
10819  */
10820 
10821  for (k = 0; k < max_oid_list && !OID_ISNULL (&oid_list[k]); k++)
10822  {
10823  /*
10824  * Has this class already been listed ?
10825  */
10826  for (j = 0; j < lockhint->num_classes; j++)
10827  {
10828  if (OID_EQ (&oid_list[k], &lockhint->classes[j].oid))
10829  {
10830  break; /* It is already listed */
10831  }
10832  }
10833 
10834  if (j == lockhint->num_classes)
10835  {
10836  /*
10837  * This is the first time we have seen this class. Push the
10838  * class onto the stack.
10839  * Make sure that we have area in the stack and the lockhint
10840  * area
10841  */
10842 
10843  if (stack_actual_size >= max_stack)
10844  {
10845  /* Expand the stack by two */
10846  max_stack = max_stack * 2;
10847  new_ptr = realloc (stack, sizeof (*stack) * max_stack);
10848  if (new_ptr == NULL)
10849  {
10851  sizeof (*stack) * max_stack);
10852  if (lockhint->quit_on_errors == false)
10853  {
10854  /* Finish but without an error */
10855  break;
10856  }
10857  error_code = ER_OUT_OF_VIRTUAL_MEMORY;
10858  goto error;
10859  }
10860  stack = (int *) new_ptr;
10861  }
10862  if (lockhint->num_classes >= lockhint->max_classes)
10863  {
10864  /* Expand the lockhint area by two */
10865  new_ptr = locator_reallocate_lockhint (lockhint, (lockhint->max_classes * 2));
10866  if (new_ptr == NULL)
10867  {
10868  if (lockhint->quit_on_errors == false)
10869  {
10870  /* Finish but without an error */
10871  break;
10872  }
10873  error_code = ER_OUT_OF_VIRTUAL_MEMORY;
10874  goto error;
10875  }
10876  lockhint = *lockhint_subclasses = (LC_LOCKHINT *) new_ptr;
10877  }
10878 
10879  /*
10880  * Push the class on the stack.
10881  */
10882 
10883  /* Push */
10884  stack[stack_actual_size++] = lockhint->num_classes;
10885 
10886  COPY_OID (&lockhint->classes[lockhint->num_classes].oid, &oid_list[k]);
10887  lockhint->classes[lockhint->num_classes].chn = CHN_UNKNOWN_ATCLIENT;
10888  lockhint->classes[lockhint->num_classes].lock = lockhint->classes[ref_num].lock;
10889  lockhint->classes[lockhint->num_classes].need_subclasses = 1;
10890  lockhint->num_classes++;
10891 
10892  }
10893  else
10894  {
10895  /*
10896  * This is a class that has already been listed and it may
10897  * have already been visited.
10898  */
10899  assert (lockhint->classes[j].lock >= NULL_LOCK && lockhint->classes[ref_num].lock >= NULL_LOCK);
10900 
10901  if (lockhint->classes[j].need_subclasses >= 0)
10902  {
10903  /*
10904  * The class is only listed at this point. It will be
10905  * visited later. The lock may need to be changed, as well
10906  * as its subclass flag
10907  */
10908 
10909  /* May be lock change */
10910  lockhint->classes[j].lock = lock_Conv[lockhint->classes[j].lock][lockhint->classes[ref_num].lock];
10911  assert (lockhint->classes[j].lock != NA_LOCK);
10912 
10913  /* Make sure that subclasses are obtained */
10914  lockhint->classes[j].need_subclasses = 1;
10915  }
10916  else
10917  {
10918  /*
10919  * This class has already been visited. We may need to
10920  * revisit if a lock conversion is needed as a result of
10921  * several super classes
10922  */
10923  lock = lock_Conv[lockhint->classes[j].lock][lockhint->classes[ref_num].lock];
10924  assert (lock != NA_LOCK);
10925 
10926  if (lockhint->classes[j].lock != lock)
10927  {
10928  /*
10929  * Re-visit
10930  */
10931  lockhint->classes[j].lock = lock;
10932  lockhint->classes[j].need_subclasses = 1;
10933  /* Push */
10934  stack[stack_actual_size++] = j;
10935  }
10936  }
10937  }
10938  }
10939  }
10940  }
10941 
10942  free_and_init (stack);
10943  free_and_init (oid_list);
10944  error_code = heap_scancache_end (thread_p, &scan_cache);
10945  if (error_code != NO_ERROR)
10946  {
10947  return error_code;
10948  }
10949 
10950  /*
10951  * Scan the lockhint area to make the prune levels positive
10952  */
10953 
10954  for (i = 0; i < lockhint->num_classes; i++)
10955  {
10956  lockhint->classes[i].need_subclasses = -lockhint->classes[i].need_subclasses;
10957  }
10958 
10959  return error_code;
10960 
10961 error:
10962 
10963  if (stack)
10964  {
10965  free_and_init (stack);
10966  }
10967  if (oid_list)
10968  {
10969  free_and_init (oid_list);
10970  }
10971  (void) heap_scancache_end (thread_p, &scan_cache);
10972 
10973  return error_code;
10974 }
10975 
10976 /*
10977  * xlocator_find_lockhint_class_oids () - Find the oids associated with the given
10978  * classes
10979  *
10980  * return: LC_FIND_CLASSNAME
10981  * (either of LC_CLASSNAME_EXIST,
10982  * LC_CLASSNAME_DELETED,
10983  * LC_CLASSNAME_ERROR)
10984  *
10985  * num_classes(in): Number of needed classes
10986  * many_classnames(in): Name of the classes
10987  * many_locks(in): The desired lock for each class
10988  * many_need_subclasses(in): Wheater or not the subclasses are needed.
10989  * many_flags(in): flags associated with class names
10990  * guessed_class_oids(in):
10991  * guessed_class_chns(in):
10992  * quit_on_errors(in): Wheater to continue finding the classes in case of
10993  * an error, such as a class does not exist or a lock
10994  * one a may not be granted.
10995  * hlock(in): hlock structure which is set to describe the
10996  * classes
10997  * fetch_area(in):
10998  *
10999  * Note: This function find the class identifiers of the given class
11000  * names and requested subclasses of the above classes, and lock
11001  * the classes with given locks. The function does not quit when
11002  * an error is found and the value of quit_on_errors is false.
11003  * In this case the class (an may be its subclasses) with the
11004  * error is not locked/fetched.
11005  * The function tries to lock all the classes at once, however if
11006  * this fails and the function is allowed to continue when errors
11007  * are detected, the classes are locked individually.
11008  *
11009  * The subclasses are only guessed for locking purposed and they
11010  * should not be used for any other purposes. For example, the
11011  * subclasses should not given to the upper levels of the system.
11012  *
11013  * In general the function is used to find out all needed classes
11014  * and lock them togheter.
11015  */
11017 xlocator_find_lockhint_class_oids (THREAD_ENTRY * thread_p, int num_classes, const char **many_classnames,
11018  LOCK * many_locks, int *many_need_subclasses, LC_PREFETCH_FLAGS * many_flags,
11019  OID * guessed_class_oids, int *guessed_class_chns, bool quit_on_errors,
11020  LC_LOCKHINT ** hlock, LC_COPYAREA ** fetch_area)
11021 {
11022  int tran_index;
11023  LOCATOR_CLASSNAME_ENTRY *entry;
11024  const char *classname;
11025  LOCK tmp_lock;
11028  bool allneed_subclasses = false;
11029  int retry;
11030  int i, j;
11031  int n;
11032 #if !defined(NDEBUG)
11033  int check_own;
11034 #endif
11035 
11036  *fetch_area = NULL;
11037 
11038  /*
11039  * Let's assume the number of classes that are going to be described in the
11040  * lockhint area.
11041  */
11042 
11043  *hlock = locator_allocate_lockhint (num_classes, quit_on_errors);
11044  if (*hlock == NULL)
11045  {
11046  return LC_CLASSNAME_ERROR;
11047  }
11048 
11049  /*
11050  * Find the class oids of the given classnames.
11051  */
11052 
11053  tran_index = LOG_FIND_THREAD_TRAN_INDEX (thread_p);
11054 
11055  for (i = 0; i < num_classes && (allfind == LC_CLASSNAME_EXIST || quit_on_errors == false); i++)
11056  {
11057  classname = many_classnames[i];
11058  if (classname == NULL || !(many_flags[i] & LC_PREF_FLAG_LOCK))
11059  {
11060  continue;
11061  }
11062 
11063  if (many_need_subclasses[i])
11064  {
11065  allneed_subclasses = true;
11066  }
11067 
11068  n = (*hlock)->num_classes;
11069  find = LC_CLASSNAME_EXIST;
11070  retry = 1;
11071 
11072  while (retry)
11073  {
11074  retry = 0;
11075 
11076  /*
11077  * Describe the hinted class
11078  */
11079 
11080  (*hlock)->classes[n].chn = CHN_UNKNOWN_ATCLIENT;
11081  (*hlock)->classes[n].lock = many_locks[i];
11082  (*hlock)->classes[n].need_subclasses = many_need_subclasses[i];
11083 
11085  {
11086  assert (false);
11087  return LC_CLASSNAME_ERROR;
11088  }
11089 
11090  entry = ((LOCATOR_CLASSNAME_ENTRY *) mht_get (locator_Mht_classnames, classname));
11091 
11092  if (entry != NULL)
11093  {
11094  COPY_OID (&(*hlock)->classes[n].oid, &entry->e_current.oid);
11095  assert (find == LC_CLASSNAME_EXIST);
11096 
11097  if (locator_is_exist_class_name_entry (thread_p, entry))
11098  {
11099  assert (find == LC_CLASSNAME_EXIST); /* OK, go ahead */
11100  }
11101  else
11102  {
11104 
11105  /*
11106  * We can only proceed if the entry belongs to the current
11107  * transaction, otherwise, we must lock the class associated
11108  * with the classname and retry the operation once the lock
11109  * is granted.
11110  */
11111  assert (find == LC_CLASSNAME_EXIST);
11112 
11113  if (entry->e_tran_index == tran_index)
11114  {
11115  if (entry->e_current.action == LC_CLASSNAME_DELETED
11117  {
11118  find = LC_CLASSNAME_DELETED;
11119  }
11120  else
11121  {
11122  assert (find == LC_CLASSNAME_EXIST); /* OK, go ahead */
11123  }
11124  }
11125  else
11126  {
11128 
11129  /*
11130  * Do not know the fate of this entry until the transaction is
11131  * committed or aborted. Get the lock and retry later on.
11132  */
11133  if ((*hlock)->classes[n].lock != NULL_LOCK)
11134  {
11135  tmp_lock = (*hlock)->classes[n].lock;
11136  }
11137  else
11138  {
11139  tmp_lock = IS_LOCK;
11140  }
11141 
11142  if (lock_object (thread_p, &(*hlock)->classes[n].oid, oid_Root_class_oid, tmp_lock,
11144  {
11145  /*
11146  * Unable to acquired the lock; exit retry-loop
11147  */
11148  allfind = find = LC_CLASSNAME_ERROR;
11149  assert (allfind == LC_CLASSNAME_ERROR);
11150  }
11151  else
11152  {
11153  /*
11154  * Try again
11155  * Remove the lock.. since the above was a dirty read
11156  */
11157  lock_unlock_object (thread_p, &(*hlock)->classes[n].oid, oid_Root_class_oid, tmp_lock, true);
11158  retry = 1;
11159  }
11160 
11161  /* already exit cset */
11162  continue;
11163  }
11164  }
11165  }
11166  else
11167  {
11168  assert (entry == NULL);
11169 
11170  find = LC_CLASSNAME_DELETED;
11171  }
11172 
11173 #if !defined(NDEBUG)
11174  check_own = csect_check_own (thread_p, CSECT_LOCATOR_SR_CLASSNAME_TABLE);
11175  assert (check_own >= 1);
11176 #endif
11177 
11179 
11180  } /* while (retry) */
11181 
11182  if (find == LC_CLASSNAME_EXIST)
11183  {
11184  /*
11185  * If the client has guessed the right class_oid, use the cache
11186  * coherency number on the client to avoid sending the class object
11187  */
11188  if (guessed_class_oids != NULL && OID_EQ (&(*hlock)->classes[n].oid, &guessed_class_oids[i]))
11189  {
11190  (*hlock)->classes[n].chn = guessed_class_chns[i];
11191  }
11192 
11193  n++;
11194  (*hlock)->num_classes = n;
11195  }
11196  else
11197  {
11198  if (allfind != LC_CLASSNAME_ERROR)
11199  {
11200  allfind = find;
11201  }
11202  if (find == LC_CLASSNAME_DELETED)
11203  {
11205  }
11206  }
11207  } /* for (i = 0; ... ) */
11208 
11209  /*
11210  * Eliminate any duplicates. Note that we did not want to do above since
11211  * we did not want to modify the original arrays.
11212  */
11213 
11214  for (i = 0; i < (*hlock)->num_classes; i++)
11215  {
11216  if (OID_ISNULL (&(*hlock)->classes[i].oid))
11217  {
11218  continue;
11219  }
11220  /*
11221  * Is this duplicated ?
11222  */
11223  for (j = i + 1; j < (*hlock)->num_classes; j++)
11224  {
11225  if (OID_EQ (&(*hlock)->classes[i].oid, &(*hlock)->classes[j].oid))
11226  {
11227  /* Duplicate class, merge the lock and the subclass entry */
11228  assert ((*hlock)->classes[i].lock >= NULL_LOCK && (*hlock)->classes[j].lock >= NULL_LOCK);
11229  (*hlock)->classes[i].lock = lock_Conv[(*hlock)->classes[i].lock][(*hlock)->classes[j].lock];
11230  assert ((*hlock)->classes[i].lock != NA_LOCK);
11231 
11232  if ((*hlock)->classes[i].need_subclasses == 0)
11233  {
11234  (*hlock)->classes[i].need_subclasses = (*hlock)->classes[j].need_subclasses;
11235  }
11236 
11237  /* Now eliminate the entry */
11238  OID_SET_NULL (&(*hlock)->classes[j].oid);
11239  }
11240  }
11241  }
11242 
11243  /*
11244  * Do we need to get subclasses ?
11245  */
11246 
11247  if (allneed_subclasses == true && (allfind == LC_CLASSNAME_EXIST || quit_on_errors == false))
11248  {
11249  if (locator_guess_sub_classes (thread_p, &(*hlock)) != NO_ERROR)
11250  {
11251  allfind = LC_CLASSNAME_ERROR;
11252  }
11253  }
11254 
11255  if (allfind == LC_CLASSNAME_EXIST || quit_on_errors == false)
11256  {
11257  if (xlocator_fetch_lockhint_classes (thread_p, (*hlock), fetch_area) != NO_ERROR)
11258  {
11259  allfind = LC_CLASSNAME_ERROR;
11260  if (quit_on_errors == true)
11261  {
11262  locator_free_lockhint ((*hlock));
11263  *hlock = NULL;
11264  }
11265  }
11266  }
11267  else
11268  {
11269  locator_free_lockhint ((*hlock));
11270  *hlock = NULL;
11271  }
11272 
11273  if (logtb_tran_prepare_count_optim_classes (thread_p, many_classnames, many_flags, num_classes) != NO_ERROR)
11274  {
11275  allfind = LC_CLASSNAME_ERROR;
11276  }
11277 
11278  return allfind;
11279 }
11280 
11281 /*
11282  * xlocator_fetch_lockhint_classes () - Lock and fetch a set of classes
11283  *
11284  * return: NO_ERROR if all OK, ER_ status otherwise
11285  *
11286  * lockhint(in): Description of hinted classses
11287  * fetch_area(in/out): Pointer to area where the objects are placed
11288  *
11289  */
11290 int
11292 {
11293  LOCATOR_RETURN_NXOBJ nxobj; /* Description to return next object */
11294  LC_COPYAREA_DESC prefetch_des; /* Descriptor for decache of objects related to transaction isolation level */
11295  SCAN_CODE scan = S_SUCCESS;
11296  int copyarea_length;
11297  int i;
11298  int error_code = NO_ERROR;
11299 
11300  *fetch_area = NULL;
11301 
11302  if (lockhint->num_classes <= 0)
11303  {
11304  lockhint->num_classes_processed = lockhint->num_classes;
11305  return NO_ERROR;
11306  }
11307 
11308  if (lockhint->num_classes_processed == -1)
11309  {
11310  /*
11311  * FIRST CALL.
11312  * Initialize num of object processed.
11313  */
11314  lockhint->num_classes_processed = 0;
11315 
11316  /* Obtain the locks */
11317  if (lock_classes_lock_hint (thread_p, lockhint) != LK_GRANTED)
11318  {
11319  if (lockhint->quit_on_errors != false)
11320  {
11321  return ER_FAILED;
11322  }
11323  else
11324  {
11325  error_code = ER_FAILED;
11326  /* Lock individual classes */
11327  for (i = 0; i < lockhint->num_classes; i++)
11328  {
11329  if (OID_ISNULL (&lockhint->classes[i].oid))
11330  {
11331  continue;
11332  }
11333  if (lock_object (thread_p, &lockhint->classes[i].oid, oid_Root_class_oid, lockhint->classes[i].lock,
11335  {
11336  OID_SET_NULL (&lockhint->classes[i].oid);
11337  }
11338  else
11339  {
11340  /* We are unable to continue since we lock at least one */
11341  error_code = NO_ERROR;
11342  }
11343  }
11344  if (error_code != NO_ERROR)
11345  {
11346  return error_code;
11347  }
11348  }
11349  }
11350  }
11351 
11352  /*
11353  * Start a scan cursor for getting the classes
11354  */
11355 
11356  error_code = heap_scancache_start (thread_p, &nxobj.area_scancache, NULL, NULL, true, false, NULL);
11357  if (error_code != NO_ERROR)
11358  {
11359  lock_unlock_classes_lock_hint (thread_p, lockhint);
11360  return error_code;
11361  }
11362 
11363  nxobj.ptr_scancache = &nxobj.area_scancache;
11364 
11365  /*
11366  * Assume that there are not any classes larger than one page. If there are
11367  * the number of pages is fixed later.
11368  */
11369 
11370  /* Assume that the needed object can fit in one page */
11371  copyarea_length = DB_PAGESIZE;
11372 
11373  nxobj.mobjs = NULL;
11374  nxobj.comm_area = NULL;
11375 
11376  while (scan == S_SUCCESS && (lockhint->num_classes_processed < lockhint->num_classes))
11377  {
11378  nxobj.comm_area = locator_allocate_copy_area_by_length (copyarea_length);
11379  if (nxobj.comm_area == NULL)
11380  {
11381  (void) heap_scancache_end (thread_p, &nxobj.area_scancache);
11382  lock_unlock_classes_lock_hint (thread_p, lockhint);
11383  return ER_FAILED;
11384  }
11385 
11387  nxobj.obj = LC_START_ONEOBJ_PTR_IN_COPYAREA (nxobj.mobjs);
11388  LC_RECDES_IN_COPYAREA (nxobj.comm_area, &nxobj.recdes);
11389  nxobj.area_offset = 0;
11390  nxobj.mobjs->num_objs = 0;
11391 
11392  /*
11393  * Place the classes on the communication area, don't place those classes
11394  * with correct chns.
11395  */
11396 
11397  for (i = lockhint->num_classes_processed; scan == S_SUCCESS && i < lockhint->num_classes; i++)
11398  {
11399  if (OID_ISNULL (&lockhint->classes[i].oid) || OID_ISTEMP (&lockhint->classes[i].oid))
11400  {
11401  lockhint->num_classes_processed += 1;
11402  continue;
11403  }
11404 
11405  /* Now return the object */
11406  /* Since classes are already locked, call locator_lock_and_return_object with NULL_LOCK as lock_mode argument
11407  * to skip locking. */
11408  scan =
11409  locator_lock_and_return_object (thread_p, &nxobj, oid_Root_class_oid, &lockhint->classes[i].oid,
11410  lockhint->classes[i].chn, NULL_LOCK, S_SELECT);
11411  if (scan == S_SUCCESS)
11412  {
11413  lockhint->num_classes_processed += 1;
11414  }
11415  else if (scan == S_DOESNT_FIT && nxobj.mobjs->num_objs == 0)
11416  {
11417  /*
11418  * The first object on the copy area does not fit.
11419  * Get a larger area
11420  */
11421 
11422  /* Get the real length of the fetch/copy area */
11423 
11424  copyarea_length = nxobj.comm_area->length;
11425 
11426  if ((-nxobj.recdes.length) > copyarea_length)
11427  {
11428  copyarea_length = (DB_ALIGN (-nxobj.recdes.length, MAX_ALIGNMENT) + sizeof (*nxobj.mobjs));
11429  }
11430  else
11431  {
11432  copyarea_length += DB_PAGESIZE;
11433  }
11434 
11436  scan = S_SUCCESS;
11437  break; /* finish the for */
11438  }
11439  else if (scan != S_DOESNT_FIT && (scan == S_DOESNT_EXIST || lockhint->quit_on_errors == false))
11440  {
11441  OID_SET_NULL (&lockhint->classes[i].oid);
11442  lockhint->num_classes_processed += 1;
11443  scan = S_SUCCESS;
11444  }
11445  else
11446  {
11447  break; /* Quit on errors */
11448  }
11449  }
11450  }
11451 
11452  /* End the scan cursor */
11453  error_code = heap_scancache_end (thread_p, &nxobj.area_scancache);
11454  if (error_code != NO_ERROR)
11455  {
11456  /* There was an error.. */
11457  if (nxobj.mobjs != NULL)
11458  {
11460  }
11461  lock_unlock_classes_lock_hint (thread_p, lockhint);
11462  return error_code;
11463  }
11464 
11465  if (scan == S_ERROR)
11466  {
11467  /* There was an error.. */
11468  if (nxobj.mobjs != NULL)
11469  {
11471  }
11472  lock_unlock_classes_lock_hint (thread_p, lockhint);
11473  return ER_FAILED;
11474  }
11475  else if (nxobj.mobjs != NULL && nxobj.mobjs->num_objs == 0)
11476  {
11478  }
11479  else
11480  {
11481  *fetch_area = nxobj.comm_area;
11482  }
11483 
11484  if (*fetch_area != NULL)
11485  {
11486  prefetch_des.mobjs = nxobj.mobjs;
11487  prefetch_des.obj = &nxobj.obj;
11488  prefetch_des.offset = &nxobj.area_offset;
11489  prefetch_des.recdes = &nxobj.recdes;
11490  lock_notify_isolation_incons (thread_p, locator_notify_decache, &prefetch_des);
11491  }
11492 
11493  if (lockhint->num_classes_processed >= lockhint->num_classes)
11494  {
11495  lock_unlock_classes_lock_hint (thread_p, lockhint);
11496  }
11497 
11498  return NO_ERROR;
11499 }
11500 
11501 /*
11502  * xlocator_assign_oid_batch () - Assign a group of permanent oids
11503  *
11504  * return: NO_ERROR if all OK, ER_ status otherwise
11505  *
11506  * oidset(in): LC_OIDSET describing all of the temp oids
11507  *
11508  * Note:Permanent oids are assigned to each of the temporary oids
11509  * listed in the LC_OIDSET.
11510  */
11511 int
11513 {
11514  LC_CLASS_OIDSET *class_oidset;
11515  LC_OIDMAP *oid;
11516  int error_code = NO_ERROR;
11517 
11518  /* establish a rollback point in case we get an error part way through */
11519  log_sysop_start (thread_p);
11520 
11521  /* Now assign the OID's stop on the first error */
11522  for (class_oidset = oidset->classes; class_oidset != NULL; class_oidset = class_oidset->next)
11523  {
11524  for (oid = class_oidset->oids; oid != NULL; oid = oid->next)
11525  {
11526  error_code =
11527  xlocator_assign_oid (thread_p, &class_oidset->hfid, &oid->oid, oid->est_size, &class_oidset->class_oid,
11528  NULL);
11529  if (error_code != NO_ERROR)
11530  {
11531  goto error;
11532  }
11533  }
11534  }
11535 
11536  /* accept the operation */
11537  log_sysop_attach_to_outer (thread_p);
11538 
11539  return error_code;
11540 
11541 error:
11542  /* rollback the operation */
11543  log_sysop_abort (thread_p);
11544  return error_code;
11545 }
11546 
11547 #if defined(ENABLE_UNUSED_FUNCTION)
11548 /*
11549  * locator_increase_catalog_count () -
11550  *
11551  * return:
11552  *
11553  * cls_oid(in): Class OID
11554  *
11555  * Note:Increase the 'tot_objects' counter of the CLS_INFO
11556  * and do update the catalog record in-place.
11557  */
11558 static void
11559 locator_increase_catalog_count (THREAD_ENTRY * thread_p, OID * cls_oid)
11560 {
11561  CLS_INFO *cls_infop = NULL;
11562 
11563  /* retrieve the class information */
11564  cls_infop = catalog_get_class_info (thread_p, cls_oid);
11565  if (cls_infop == NULL)
11566  {
11567  return;
11568  }
11569 
11570  if (cls_infop->ci_hfid.vfid.fileid < 0 || cls_infop->ci_hfid.vfid.volid < 0)
11571  {
11572  /* The class does not have a heap file (i.e. it has no instances); so no statistics can be obtained for this
11573  * class; just set 'tot_objects' field to 0. */
11574  /* Is it safe not to initialize the other fields of CLS_INFO? */
11575  cls_infop->ci_tot_objects = 0;
11576  }
11577  else
11578  {
11579  /* increase the 'tot_objects' counter */
11580  cls_infop->ci_tot_objects++;
11581  }
11582 
11583  /* update the class information to the catalog */
11584  /* NOTE that tot_objects may not be correct because changes are NOT logged. */
11585  (void) catalog_update_class_info (thread_p, cls_oid, cls_infop, true);
11586 
11588 }
11589 
11590 /*
11591  * locator_decrease_catalog_count () -
11592  *
11593  * return:
11594  *
11595  * cls_oid(in): Class OID
11596  *
11597  * Note: Descrease the 'tot_objects' counter of the CLS_INFO
11598  * and do update the catalog record in-place.
11599  */
11600 static void
11601 locator_decrease_catalog_count (THREAD_ENTRY * thread_p, OID * cls_oid)
11602 {
11603  CLS_INFO *cls_infop = NULL;
11604 
11605  /* retrieve the class information */
11606  cls_infop = catalog_get_class_info (thread_p, cls_oid);
11607  if (cls_infop == NULL)
11608  {
11609  return;
11610  }
11611 
11612  if (cls_infop->ci_hfid.vfid.fileid < 0 || cls_infop->ci_hfid.vfid.volid < 0)
11613  {
11614  /* The class does not have a heap file (i.e. it has no instances); so no statistics can be obtained for this
11615  * class; just set 'tot_objects' field to 0. */
11616  /* Is it an error to delete an instance with no heap file? */
11617  cls_infop->ci_tot_objects = 0;
11618  }
11619 
11620  /* decrease the 'tot_objects' counter */
11621  if (cls_infop->ci_tot_objects > 0)
11622  {
11623  cls_infop->ci_tot_objects--;
11624  }
11625 
11626  /* update the class information to the catalog */
11627  /* NOTE that tot_objects may not be correct because changes are NOT logged. */
11628  (void) catalog_update_class_info (thread_p, cls_oid, cls_infop, true);
11629 
11631 }
11632 #endif /* ENABLE_UNUSED_FUNCTION */
11633 
11634 /*
11635  * xrepl_set_info () -
11636  *
11637  * return:
11638  *
11639  * repl_info(in):
11640  */
11641 int
11643 {
11644  int error_code = NO_ERROR;
11645 
11646  if (!LOG_CHECK_LOG_APPLIER (thread_p) && log_does_allow_replication () == true)
11647  {
11648  switch (repl_info->repl_info_type)
11649  {
11650  case REPL_INFO_TYPE_SBR:
11651  error_code = repl_log_insert_statement (thread_p, (REPL_INFO_SBR *) repl_info->info);
11652  break;
11653  default:
11654  error_code = ER_REPL_ERROR;
11655  er_set (ER_WARNING_SEVERITY, ARG_FILE_LINE, ER_REPL_ERROR, 1, "can't make repl sbr info");
11656  break;
11657  }
11658  }
11659 
11660  return error_code;
11661 }
11662 
11663 /*
11664  * xrepl_log_get_append_lsa () -
11665  *
11666  * return:
11667  */
11668 LOG_LSA *
11670 {
11671  return log_get_append_lsa ();
11672 }
11673 
11674 /*
11675  * xlocator_check_fk_validity () -
11676  *
11677  * return: NO_ERROR if all OK, ER_ status otherwise
11678  *
11679  * cls_oid(in):
11680  * hfid(in):
11681  * key_type(in):
11682  * n_attrs(in):
11683  * attr_ids(in):
11684  * pk_cls_oid(in):
11685  * pk_btid(in):
11686  * fk_name(in):
11687  */
11688 int
11689 xlocator_check_fk_validity (THREAD_ENTRY * thread_p, OID * cls_oid, HFID * hfid, TP_DOMAIN * key_type, int n_attrs,
11690  int *attr_ids, OID * pk_cls_oid, BTID * pk_btid, char *fk_name)
11691 {
11692  HEAP_SCANCACHE scan_cache;
11693  HEAP_CACHE_ATTRINFO attr_info;
11694  OID oid;
11695  RECDES copy_recdes;
11696  DB_VALUE *key_val, tmpval;
11697  char midxkey_buf[DBVAL_BUFSIZE + MAX_ALIGNMENT], *aligned_midxkey_buf;
11698  int error_code;
11700 
11701  mvcc_snapshot = logtb_get_mvcc_snapshot (thread_p);
11702  if (mvcc_snapshot == NULL)
11703  {
11704  error_code = er_errid ();
11705  return (error_code == NO_ERROR ? ER_FAILED : error_code);
11706  }
11707 
11708  db_make_null (&tmpval);
11709 
11710  aligned_midxkey_buf = PTR_ALIGN (midxkey_buf, MAX_ALIGNMENT);
11711 
11712  error_code = heap_scancache_start (thread_p, &scan_cache, hfid, cls_oid, false, false, mvcc_snapshot);
11713  if (error_code != NO_ERROR)
11714  {
11715  return error_code;
11716  }
11717 
11718  error_code = heap_attrinfo_start (thread_p, cls_oid, n_attrs, attr_ids, &attr_info);
11719  if (error_code != NO_ERROR)
11720  {
11721  (void) heap_scancache_end (thread_p, &scan_cache);
11722  return error_code;
11723  }
11724 
11725  OID_SET_NULL (&oid);
11726  oid.volid = hfid->vfid.volid;
11727 
11728  copy_recdes.data = NULL;
11729  while (heap_next (thread_p, hfid, NULL, &oid, &copy_recdes, &scan_cache, COPY) == S_SUCCESS)
11730  {
11731  if (n_attrs == 1)
11732  {
11733  error_code = heap_attrinfo_read_dbvalues (thread_p, &oid, &copy_recdes, NULL, &attr_info);
11734  if (error_code != NO_ERROR)
11735  {
11736  goto end;
11737  }
11738  }
11739 
11740  key_val =
11741  heap_attrinfo_generate_key (thread_p, n_attrs, attr_ids, NULL, &attr_info, &copy_recdes, &tmpval,
11742  aligned_midxkey_buf, NULL, NULL);
11743  if (key_val == NULL)
11744  {
11745  error_code = ER_FAILED;
11746  goto end;
11747  }
11748 
11749  error_code =
11750  btree_check_foreign_key (thread_p, cls_oid, hfid, &oid, key_val, n_attrs, pk_cls_oid, pk_btid, fk_name);
11751 
11752  if (key_val == &tmpval)
11753  {
11754  pr_clear_value (&tmpval);
11755  }
11756 
11757  if (error_code != NO_ERROR)
11758  {
11759  goto end;
11760  }
11761  }
11762 
11763 end:
11764 
11765  (void) heap_scancache_end (thread_p, &scan_cache);
11766  heap_attrinfo_end (thread_p, &attr_info);
11767 
11768  return error_code;
11769 }
11770 
11771 /*
11772  * xlocator_lock_and_fetch_all () - Fetch all class instances that can be locked
11773  * in specified locked time
11774  * return: NO_ERROR if all OK, ER_ status otherwise
11775  *
11776  * hfid(in): Heap file where the instances of the class are placed
11777  * instance_lock(in): Instance lock to aquire
11778  * instance_lock_timeout(in): Timeout for instance lock
11779  * class_oid(in): Class identifier of the instances to fetch
11780  * class_lock(in): Lock to acquire (Set as a side effect to NULL_LOCKID)
11781  * nobjects(out): Total number of objects to fetch.
11782  * nfetched(out): Current number of object fetched.
11783  * nfailed_instance_locks(out): count failed instance locks
11784  * last_oid(out): Object identifier of last fetched object
11785  * fetch_area(in/out): Pointer to area where the objects are placed
11786  * mvcc_snapshot(in): the snapshot to be applied in scan
11787  *
11788  */
11789 int
11790 xlocator_lock_and_fetch_all (THREAD_ENTRY * thread_p, const HFID * hfid, LOCK * instance_lock,
11791  int *instance_lock_timeout, OID * class_oid, LOCK * class_lock, int *nobjects,
11792  int *nfetched, int *nfailed_instance_locks, OID * last_oid, LC_COPYAREA ** fetch_area,
11794 {
11795  LC_COPYAREA_DESC prefetch_des; /* Descriptor for decache of objects related to transaction isolation level */
11796  LC_COPYAREA_MANYOBJS *mobjs; /* Describe multiple objects in area */
11797  LC_COPYAREA_ONEOBJ *obj; /* Describe on object in area */
11798  RECDES recdes; /* Record descriptor for insertion */
11799  int offset; /* Place to store next object in area */
11800  int round_length; /* Length of object rounded to integer alignment */
11801  int copyarea_length;
11802  OID oid;
11803  HEAP_SCANCACHE scan_cache;
11804  SCAN_CODE scan;
11805  int error_code = NO_ERROR;
11806 
11807  if (fetch_area == NULL)
11808  {
11809  return ER_FAILED;
11810  }
11811  *fetch_area = NULL;
11812 
11813  if (nfailed_instance_locks == NULL)
11814  {
11815  return ER_FAILED;
11816  }
11817  *nfailed_instance_locks = 0;
11818 
11819  if (OID_ISNULL (last_oid))
11820  {
11821  /* FIRST TIME. */
11822 
11823  /* Obtain the desired lock for the class scan */
11824  if (*class_lock != NULL_LOCK
11825  && lock_object (thread_p, class_oid, oid_Root_class_oid, *class_lock, LK_UNCOND_LOCK) != LK_GRANTED)
11826  {
11827  /*
11828  * Unable to acquired lock
11829  */
11830  *class_lock = NULL_LOCK;
11831  *nobjects = -1;
11832  *nfetched = -1;
11833 
11834  error_code = ER_FAILED;
11835  goto error;
11836  }
11837 
11838  /* Get statistics */
11839  last_oid->volid = hfid->vfid.volid;
11840  last_oid->pageid = NULL_PAGEID;
11841  last_oid->slotid = NULL_SLOTID;
11842  /* Estimate the number of objects to be fetched */
11843  *nobjects = heap_estimate_num_objects (thread_p, hfid);
11844  *nfetched = 0;
11845  if (*nobjects == -1)
11846  {
11847  error_code = ER_FAILED;
11848  goto error;
11849  }
11850  }
11851 
11852  /* Set OID to last fetched object */
11853  COPY_OID (&oid, last_oid);
11854 
11855  /* Start a scan cursor for getting several classes */
11856  error_code = heap_scancache_start (thread_p, &scan_cache, hfid, class_oid, true, false, mvcc_snapshot);
11857  if (error_code != NO_ERROR)
11858  {
11859  goto error;
11860  }
11861 
11862  /* Assume that the next object can fit in one page */
11863  copyarea_length = DB_PAGESIZE;
11864 
11865  while (true)
11866  {
11867  *fetch_area = locator_allocate_copy_area_by_length (copyarea_length);
11868  if (*fetch_area == NULL)
11869  {
11870  (void) heap_scancache_end (thread_p, &scan_cache);
11871  error_code = ER_FAILED;
11872  goto error;
11873  }
11874 
11875  mobjs = LC_MANYOBJS_PTR_IN_COPYAREA (*fetch_area);
11876  LC_RECDES_IN_COPYAREA (*fetch_area, &recdes);
11877  obj = LC_START_ONEOBJ_PTR_IN_COPYAREA (mobjs);
11878  mobjs->num_objs = 0;
11879  offset = 0;
11880 
11881  while (true)
11882  {
11883  if (instance_lock && (*instance_lock != NULL_LOCK))
11884  {
11885  int lock_result = 0;
11886 
11887  scan = heap_next (thread_p, hfid, class_oid, &oid, &recdes, &scan_cache, COPY);
11888  if (scan != S_SUCCESS)
11889  {
11890  break;
11891  }
11892 
11893  if (instance_lock_timeout == NULL)
11894  {
11895  lock_result = lock_object (thread_p, &oid, class_oid, *instance_lock, LK_UNCOND_LOCK);
11896  }
11897  else
11898  {
11899  lock_result =
11900  lock_object_wait_msecs (thread_p, &oid, class_oid, *instance_lock, LK_UNCOND_LOCK,
11901  *instance_lock_timeout);
11902  }
11903 
11904  if (lock_result != LK_GRANTED)
11905  {
11906  (*nfailed_instance_locks)++;
11907  continue;
11908  }
11909 
11910  scan = heap_get_visible_version (thread_p, &oid, class_oid, &recdes, &scan_cache, COPY, NULL_CHN);
11911  if (scan != S_SUCCESS)
11912  {
11913  (*nfailed_instance_locks)++;
11914  continue;
11915  }
11916 
11917  }
11918  else
11919  {
11920  scan = heap_next (thread_p, hfid, class_oid, &oid, &recdes, &scan_cache, COPY);
11921  if (scan != S_SUCCESS)
11922  {
11923  break;
11924  }
11925  }
11926 
11927  mobjs->num_objs++;
11928  COPY_OID (&obj->class_oid, class_oid);
11929  COPY_OID (&obj->oid, &oid);
11930  obj->flag = 0;
11931  obj->hfid = NULL_HFID;
11932  obj->length = recdes.length;
11933  obj->offset = offset;
11934  obj->operation = LC_FETCH;
11935  obj = LC_NEXT_ONEOBJ_PTR_IN_COPYAREA (obj);
11936  round_length = DB_ALIGN (recdes.length, MAX_ALIGNMENT);
11937 #if !defined(NDEBUG)
11938  /* suppress valgrind UMW error */
11939  memset (recdes.data + recdes.length, 0, MIN (round_length - recdes.length, recdes.area_size - recdes.length));
11940 #endif
11941  offset += round_length;
11942  recdes.data += round_length;
11943  recdes.area_size -= round_length + sizeof (*obj);
11944  }
11945 
11946  if (scan != S_DOESNT_FIT || mobjs->num_objs > 0)
11947  {
11948  break;
11949  }
11950  /*
11951  * The first object does not fit into given copy area
11952  * Get a larger area
11953  */
11954 
11955  /* Get the real length of current fetch/copy area */
11956  copyarea_length = (*fetch_area)->length;
11957  locator_free_copy_area (*fetch_area);
11958 
11959  /*
11960  * If the object does not fit even when the copy area seems to be
11961  * large enough, increase the copy area by at least one page size.
11962  */
11963 
11964  if ((-recdes.length) > copyarea_length)
11965  {
11966  copyarea_length = DB_ALIGN (-recdes.length, MAX_ALIGNMENT) + sizeof (*mobjs);
11967  }
11968  else
11969  {
11970  copyarea_length += DB_PAGESIZE;
11971  }
11972  }
11973 
11974  if (scan == S_END)
11975  {
11976  /*
11977  * This is the end of the loop. Indicate the caller that no more calls
11978  * are needed by setting nobjects and nfetched to the same value.
11979  */
11980  error_code = heap_scancache_end (thread_p, &scan_cache);
11981  if (error_code != NO_ERROR)
11982  {
11983  *nobjects = *nfetched = -1;
11984  goto error;
11985  }
11986 
11987  *nfetched += mobjs->num_objs;
11988  *nobjects = *nfetched;
11989  OID_SET_NULL (last_oid);
11990  }
11991  else if (scan == S_ERROR)
11992  {
11993  /* There was an error.. */
11994  (void) heap_scancache_end (thread_p, &scan_cache);
11995  *nobjects = *nfetched = -1;
11996  error_code = ER_FAILED;
11997  goto error;
11998  }
11999  else if (mobjs->num_objs != 0)
12000  {
12001  heap_scancache_end_when_scan_will_resume (thread_p, &scan_cache);
12002  /* Set the last_oid.. and the number of fetched objects */
12003  obj = LC_PRIOR_ONEOBJ_PTR_IN_COPYAREA (obj);
12004  COPY_OID (last_oid, &obj->oid);
12005  *nfetched += mobjs->num_objs;
12006  /*
12007  * If the guess on the number of objects to fetch was low, reset the
12008  * value, so that the caller continue to call us until the end of the
12009  * scan
12010  */
12011  if (*nobjects <= *nfetched)
12012  {
12013  *nobjects = *nfetched + 10;
12014  }
12015  }
12016  else
12017  {
12018  error_code = heap_scancache_end (thread_p, &scan_cache);
12019  if (error_code != NO_ERROR)
12020  {
12021  goto end;
12022  }
12023  }
12024 
12025  if (*fetch_area != NULL)
12026  {
12027  prefetch_des.mobjs = mobjs;
12028  prefetch_des.obj = &obj;
12029  prefetch_des.offset = &offset;
12030  prefetch_des.recdes = &recdes;
12031  lock_notify_isolation_incons (thread_p, locator_notify_decache, &prefetch_des);
12032  }
12033 
12034 end:
12035 
12036  return error_code;
12037 
12038 error:
12039  if (*class_lock != NULL_LOCK)
12040  {
12041  lock_unlock_object (thread_p, class_oid, oid_Root_class_oid, *class_lock, false);
12042  }
12043  if (*fetch_area != NULL)
12044  {
12045  locator_free_copy_area (*fetch_area);
12046  *fetch_area = NULL;
12047  }
12048  return error_code;
12049 }
12050 
12051 /*
12052  * xlocator_upgrade_instances_domain () - scans all instances of a class and
12053  * performs an in-place domain upgrade of the specified attribute
12054  * (identified by its id) from the domain found in its current
12055  * stored representation to the domain found in the last
12056  * representation
12057  *
12058  * return: NO_ERROR if all OK, ER_ status otherwise
12059  *
12060  * thread_p(in): thread context
12061  * class_oid(in): class to upgrade
12062  * att_id(in): attribute id within class to update
12063  *
12064  * Note: This function is used in context of ALTER CHANGE (type change
12065  * syntax). Proper lock (SCH_M_LOCK) is assumed when this function
12066  * is reached.
12067  * The entire tuple is rewritten using the new latest representation.
12068  */
12069 int
12070 xlocator_upgrade_instances_domain (THREAD_ENTRY * thread_p, OID * class_oid, int att_id)
12071 {
12072  LOCK class_lock = SCH_M_LOCK;
12073  LOCK oid_lock = X_LOCK;
12074  LC_COPYAREA *fetch_area = NULL; /* Area where objects are received */
12075  LC_COPYAREA_MANYOBJS *mobjs = NULL; /* Describe multiple objects in area */
12076  LC_COPYAREA_ONEOBJ *obj = NULL; /* Describe one object in area */
12077  RECDES recdes;
12078  HEAP_CACHE_ATTRINFO attr_info;
12079  HEAP_SCANCACHE upd_scancache;
12080  int error = NO_ERROR;
12081  HFID hfid;
12082  int nobjects = 0, nfetched = 0, i = 0;
12083  OID last_oid;
12084  bool scancache_inited = false;
12085  bool attrinfo_inited = false;
12086  int tran_index;
12087  LOG_TDES *tdes = LOG_FIND_CURRENT_TDES (thread_p);
12088  MVCCID threshold_mvccid;
12089 
12090  HFID_SET_NULL (&hfid);
12091  OID_SET_NULL (&last_oid);
12092 
12093  if (class_oid == NULL || OID_ISNULL (class_oid) || att_id < 0)
12094  {
12095  error = ER_UNEXPECTED;
12096  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 1, "Unexpected argument of class OID or attribute id.");
12097  goto error_exit;
12098  }
12099 
12100  tran_index = LOG_FIND_THREAD_TRAN_INDEX (thread_p);
12101  nobjects = 0;
12102  nfetched = -1;
12103 
12104  error = heap_get_class_info (thread_p, class_oid, &hfid, NULL, NULL);
12105  if (error != NO_ERROR)
12106  {
12107  goto error_exit;
12108  }
12109 
12110  error = heap_scancache_start_modify (thread_p, &upd_scancache, &hfid, class_oid, SINGLE_ROW_UPDATE, NULL);
12111  if (error != NO_ERROR)
12112  {
12113  goto error_exit;
12114  }
12115  scancache_inited = true;
12116 
12117  tdes->lock_global_oldest_visible_mvccid ();
12118  threshold_mvccid = log_Gl.mvcc_table.get_global_oldest_visible ();
12119 
12120  /* VACUUM all cleanable heap objects before upgrading the domain */
12121  error = heap_vacuum_all_objects (thread_p, &upd_scancache, threshold_mvccid);
12122  if (error != NO_ERROR)
12123  {
12124  goto error_exit;
12125  }
12126 
12127  error = heap_attrinfo_start (thread_p, class_oid, -1, NULL, &attr_info);
12128  if (error != NO_ERROR)
12129  {
12130  goto error_exit;
12131  }
12132  attrinfo_inited = true;
12133 
12134  while (nobjects != nfetched)
12135  {
12136  int nfailed_instances = 0;
12137 
12138  error =
12139  xlocator_lock_and_fetch_all (thread_p, &hfid, &oid_lock, NULL, class_oid, &class_lock, &nobjects, &nfetched,
12140  &nfailed_instances, &last_oid, &fetch_area, NULL);
12141  if (error != NO_ERROR)
12142  {
12143  goto error_exit;
12144  }
12145 
12146  if (nfailed_instances != 0)
12147  {
12148  error = ER_UNEXPECTED;
12149  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 1, "Some instance is not locked.");
12150  goto error_exit;
12151  }
12152 
12153  if (fetch_area == NULL)
12154  {
12155  error = ER_UNEXPECTED;
12156  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 1, "Fetch area should not be NULL.");
12157  goto error_exit;
12158  }
12159  mobjs = LC_MANYOBJS_PTR_IN_COPYAREA (fetch_area);
12160  obj = LC_START_ONEOBJ_PTR_IN_COPYAREA (mobjs);
12161 
12162  for (i = 0; i < mobjs->num_objs; i++)
12163  {
12164  if (obj->operation == LC_FETCH_DECACHE_LOCK)
12165  {
12166  /* Skip decache lock objects, they have been added by lock_notify_isolation_incons function. */
12167  obj = LC_NEXT_ONEOBJ_PTR_IN_COPYAREA (obj);
12168  continue;
12169  }
12170  LC_RECDES_TO_GET_ONEOBJ (fetch_area, obj, &recdes);
12171 
12172  error = heap_attrinfo_clear_dbvalues (&attr_info);
12173  if (error != NO_ERROR)
12174  {
12175  goto error_exit;
12176  }
12177 
12178  error = heap_attrinfo_read_dbvalues (thread_p, &obj->oid, &recdes, NULL, &attr_info);
12179  if (error != NO_ERROR)
12180  {
12181  goto error_exit;
12182  }
12183 
12184  error = heap_object_upgrade_domain (thread_p, &upd_scancache, &attr_info, &obj->oid, att_id);
12185 
12186  if (error != NO_ERROR)
12187  {
12188  goto error_exit;
12189  }
12190 
12191  COPY_OID (&last_oid, &obj->oid);
12192  obj = LC_NEXT_ONEOBJ_PTR_IN_COPYAREA (obj);
12193  }
12194  if (fetch_area)
12195  {
12196  locator_free_copy_area (fetch_area);
12197  fetch_area = NULL;
12198  }
12199  }
12200 
12201 error_exit:
12202 
12203  if (fetch_area)
12204  {
12205  locator_free_copy_area (fetch_area);
12206  fetch_area = NULL;
12207  }
12208  if (attrinfo_inited)
12209  {
12210  heap_attrinfo_end (thread_p, &attr_info);
12211  }
12212  if (scancache_inited)
12213  {
12214  heap_scancache_end_modify (thread_p, &upd_scancache);
12215  }
12216 
12217  return error;
12218 }
12219 
12220 /*
12221  * locator_filter_errid() -
12222  *
12223  * return:
12224  * num_ignore_error_count(in):
12225  * ignore_error_list(in):
12226  * error_code(in):
12227  */
12228 static int
12229 locator_filter_errid (THREAD_ENTRY * thread_p, int num_ignore_error_count, int *ignore_error_list)
12230 {
12231  int i;
12232  int error_code;
12233 
12234  assert (er_errid () != NO_ERROR);
12235  error_code = er_errid ();
12236 
12237  for (i = 0; i < num_ignore_error_count; i++)
12238  {
12239  if (ignore_error_list[i] == error_code)
12240  {
12241  er_clear ();
12242  return NO_ERROR;
12243  }
12244  }
12245  return error_code;
12246 }
12247 
12248 /*
12249  * locator_get_partition_scancache () - setup a cache for repeated operations
12250  * which require partition pruning
12251  * return : PRUNING_SCAN_CACHE on success, NULL on error
12252  * pcontext (in) : pruning context
12253  * class_oid (in) : OID of the pruned partition
12254  * hfid (in) : HFID of the pruned partition
12255  * op_type (in) : operation type
12256  * has_function_indexes (in) : true if function indexes should be cached
12257  */
12259 locator_get_partition_scancache (PRUNING_CONTEXT * pcontext, const OID * class_oid, const HFID * hfid, int op_type,
12260  bool has_function_indexes)
12261 {
12262  PRUNING_SCAN_CACHE *scan_cache = NULL;
12263  int error_code = NO_ERROR;
12264 
12265  scan_cache = partition_get_scancache (pcontext, class_oid);
12266  if (scan_cache != NULL)
12267  {
12268  /* already cached, return it */
12269  return scan_cache;
12270  }
12271 
12272  /* create a new one and cache it */
12273  scan_cache = partition_new_scancache (pcontext);
12274  if (scan_cache == NULL)
12275  {
12276  return NULL;
12277  }
12278  error_code = locator_start_force_scan_cache (pcontext->thread_p, &scan_cache->scan_cache, hfid, class_oid, op_type);
12279  if (error_code != NO_ERROR)
12280  {
12281  return NULL;
12282  }
12283 
12284  scan_cache->is_scan_cache_started = true;
12285 
12286  if (has_function_indexes)
12287  {
12288  HEAP_CACHE_ATTRINFO attr_info;
12289 
12290  error_code = heap_attrinfo_start (pcontext->thread_p, class_oid, -1, NULL, &attr_info);
12291  if (error_code != NO_ERROR)
12292  {
12293  return NULL;
12294  }
12295  scan_cache->n_indexes = attr_info.last_classrepr->n_indexes;
12296  error_code =
12297  heap_init_func_pred_unpack_info (pcontext->thread_p, &attr_info, class_oid, &scan_cache->func_index_pred);
12298  heap_attrinfo_end (pcontext->thread_p, &attr_info);
12299  if (error_code != NO_ERROR)
12300  {
12301  scan_cache->n_indexes = 0;
12302  scan_cache->func_index_pred = NULL;
12303  return NULL;
12304  }
12305  }
12306 
12307  return scan_cache;
12308 }
12309 
12310 /*
12311  * locator_area_op_to_pruning_type () - get pruning_type operation from
12312  * locator area operation
12313  * return: pruning type
12314  * op (in) : locator operation
12315  */
12316 static int
12318 {
12319  switch (op)
12320  {
12321  case LC_FLUSH_INSERT:
12322  case LC_FLUSH_UPDATE:
12323  case LC_FLUSH_DELETE:
12324  return DB_NOT_PARTITIONED_CLASS;
12325 
12326  case LC_FLUSH_INSERT_PRUNE:
12327  case LC_FLUSH_UPDATE_PRUNE:
12328  return DB_PARTITIONED_CLASS;
12329 
12332  return DB_PARTITION_CLASS;
12333 
12334  default:
12335  assert (false);
12336  return 0;
12337  }
12338  return 0;
12339 }
12340 
12341 static int
12342 locator_prefetch_index_page (THREAD_ENTRY * thread_p, OID * class_oid, RECDES * classrec, RECDES * recdes,
12343  int btid_index, HEAP_CACHE_ATTRINFO * attr_info)
12344 {
12345  int error = NO_ERROR;
12346  BTID *btid = NULL;
12347 
12348  btid = heap_indexinfo_get_btid (btid_index, attr_info);
12349  if (btid == NULL)
12350  {
12351  return ER_FAILED;
12352  }
12353 
12354  error = locator_prefetch_index_page_internal (thread_p, btid, class_oid, classrec, recdes);
12355  return error;
12356 }
12357 
12358 static int
12359 locator_prefetch_index_page_internal (THREAD_ENTRY * thread_p, BTID * btid, OID * class_oid, RECDES * classrec,
12360  RECDES * recdes)
12361 {
12362  int error = NO_ERROR;
12363  BTREE_CHECKSCAN bt_checkscan, *bt_checkscan_p = NULL;
12364  HEAP_CACHE_ATTRINFO attr_info;
12365  HEAP_CACHE_ATTRINFO *attr_info_p = NULL;
12366  HFID hfid;
12367  int index_id = -1;
12368  char buf[DBVAL_BUFSIZE + MAX_ALIGNMENT], *aligned_buf;
12369  DB_VALUE dbvalue;
12370  DB_VALUE *key = NULL;
12372  INDX_SCAN_ID isid;
12373  BTID tmp_btid = *btid;
12374 
12375  aligned_buf = PTR_ALIGN (buf, MAX_ALIGNMENT);
12376 
12377  or_class_hfid (classrec, &hfid);
12378  if (HFID_IS_NULL (&hfid))
12379  {
12380  return NO_ERROR;
12381  }
12382 
12383  index_id = heap_attrinfo_start_with_btid (thread_p, class_oid, &tmp_btid, &attr_info);
12384  if (index_id < 0)
12385  {
12386  goto free_and_return;
12387  }
12388  attr_info_p = &attr_info;
12389 
12390  if (btree_keyoid_checkscan_start (thread_p, &tmp_btid, &bt_checkscan) != NO_ERROR)
12391  {
12392  error = ER_FAILED;
12393  goto free_and_return;
12394  }
12395  bt_checkscan_p = &bt_checkscan;
12396 
12397  BTREE_INIT_SCAN (&bt_checkscan_p->btree_scan);
12398  scan_init_index_scan (&isid, &bt_checkscan_p->oid_list, NULL);
12399 
12400  if (heap_attrinfo_read_dbvalues_without_oid (thread_p, recdes, attr_info_p) != NO_ERROR)
12401  {
12402  error = ER_FAILED;
12403  goto free_and_return;
12404  }
12405 
12406  key = heap_attrvalue_get_key (thread_p, index_id, attr_info_p, recdes, &tmp_btid, &dbvalue, aligned_buf, NULL, NULL);
12407  if (key == NULL)
12408  {
12409  error = ER_FAILED;
12410  goto free_and_return;
12411  }
12412 
12413  pr_share_value (key, &key_val_range.key1);
12414  pr_share_value (key, &key_val_range.key2);
12415  key_val_range.range = GE_LE;
12416  key_val_range.num_index_term = 0;
12417 
12418  btree_keyval_search (thread_p, &tmp_btid, S_SELECT, &bt_checkscan_p->btree_scan, &key_val_range, class_oid, NULL,
12419  &isid, false);
12420 
12421  btree_scan_clear_key (&bt_checkscan.btree_scan);
12422 
12423 free_and_return:
12424  if (key == &dbvalue)
12425  {
12426  pr_clear_value (key);
12427  }
12428 
12429  if (bt_checkscan_p)
12430  {
12431  btree_keyoid_checkscan_end (thread_p, bt_checkscan_p);
12432  }
12433 
12434  if (attr_info_p)
12435  {
12436  heap_attrinfo_end (thread_p, attr_info_p);
12437  }
12438 
12439  return error;
12440 }
12441 
12442 /*
12443  * locator_incr_num_transient_classnames - increase number
12444  *
12445  * return:
12446  *
12447  * tran_index(in):
12448  *
12449  */
12450 static void
12452 {
12453  LOG_TDES *tdes;
12454 
12455  tdes = LOG_FIND_TDES (tran_index);
12456  /* ignore ER_LOG_UNKNOWN_TRANINDEX : It may be detected somewhere else. */
12457  if (tdes != NULL)
12458  {
12459  assert (tdes->num_transient_classnames >= 0);
12460  tdes->num_transient_classnames += 1;
12461  }
12462 }
12463 
12464 /*
12465  * locator_decr_num_transient_classnames - decrease number
12466  *
12467  * return:
12468  *
12469  * tran_index(in):
12470  *
12471  * NOTE:
12472  */
12473 static void
12475 {
12476  LOG_TDES *tdes;
12477 
12478  tdes = LOG_FIND_TDES (tran_index);
12479  /* ignore ER_LOG_UNKNOWN_TRANINDEX : It may be detected somewhere else. */
12480  if (tdes != NULL)
12481  {
12482  tdes->num_transient_classnames -= 1;
12483  assert (tdes->num_transient_classnames >= 0);
12484  }
12485 }
12486 
12487 /*
12488  * locator_get_num_transient_classnames -
12489  *
12490  * return:
12491  *
12492  * tran_index(in):
12493  *
12494  * NOTE:
12495  */
12496 static int
12498 {
12499  LOG_TDES *tdes;
12500 
12501  tdes = LOG_FIND_TDES (tran_index);
12502  /* ignore ER_LOG_UNKNOWN_TRANINDEX : It may be detected somewhere else. */
12503  if (tdes != NULL)
12504  {
12505  assert (tdes->num_transient_classnames >= 0);
12506  return tdes->num_transient_classnames;
12507  }
12508  else
12509  {
12510  return 1; /* someone exists */
12511  }
12512 }
12513 
12514 /*
12515  * locator_is_exist_class_name_entry -
12516  *
12517  * return:
12518  *
12519  * entry(in):
12520  *
12521  * NOTE: debugging function
12522  */
12523 static bool
12525 {
12526 #if !defined(NDEBUG)
12527  int check_own;
12528 
12529  check_own = csect_check_own (thread_p, CSECT_LOCATOR_SR_CLASSNAME_TABLE);
12530  assert (check_own >= 1);
12531 #endif
12532 
12533  if (entry != NULL && entry->e_current.action == LC_CLASSNAME_EXIST)
12534  {
12535  assert (entry->e_name != NULL);
12536  assert (entry->e_tran_index == NULL_TRAN_INDEX);
12537 
12538  assert (!OID_ISNULL (&entry->e_current.oid));
12539  assert (heap_does_exist (thread_p, oid_Root_class_oid, &entry->e_current.oid));
12540 
12541  assert (LSA_ISNULL (&entry->e_current.savep_lsa));
12542  assert (entry->e_current.prev == NULL);
12543 
12544  return true;
12545  }
12546 
12547  return false;
12548 }
12549 
12550 /*
12551  * xchksum_insert_repl_log_and_demote_table_lock -
12552  *
12553  * return: error code
12554  *
12555  * repl_info(in):
12556  *
12557  * NOTE: insert replication log and demote the read lock of the table
12558  */
12559 int
12561 {
12562  LOG_TDES *tdes;
12563  int error = NO_ERROR;
12564 
12565  tdes = LOG_FIND_CURRENT_TDES (thread_p);
12566  if (tdes == NULL)
12567  {
12569  LOG_FIND_THREAD_TRAN_INDEX (thread_p));
12570 
12571  return ER_LOG_UNKNOWN_TRANINDEX;
12572  }
12573 
12574  /* need to start a topop to make sure the repl log is inserted in a correct order */
12575  log_sysop_start (thread_p);
12576 
12577  repl_start_flush_mark (thread_p);
12578 
12579  error = xrepl_set_info (thread_p, repl_info);
12580 
12581  repl_end_flush_mark (thread_p, false);
12582 
12583  if (error != NO_ERROR)
12584  {
12585  ASSERT_ERROR ();
12586  log_sysop_abort (thread_p);
12587  }
12588  else
12589  {
12590  /* manually append repl info */
12591  log_append_repl_info (thread_p, tdes, false);
12592 
12593  log_sysop_commit (thread_p);
12594  }
12595 
12596 #if defined (SERVER_MODE)
12597  /* demote S-lock to IS-lock to allow blocking writers to resume. This will not hurt transactional consistencies of
12598  * checksumdb. */
12599  lock_demote_read_class_lock_for_checksumdb (thread_p, tdes->tran_index, class_oidp);
12600 
12602 #endif /* SERVER_MODE */
12603 
12604  return error;
12605 }
12606 
12607 /*
12608  * locator_rv_redo_rename () - Dummy logical redo function that does nothing.
12609  *
12610  * return : NO_ERROR
12611  * thread_p (in) : Thread entry.
12612  * rcv (in) : Recovery data.
12613  */
12614 int
12616 {
12617  /* Does nothing on recovery. */
12618  return NO_ERROR;
12619 }
12620 
12621 /*
12622  * redistribute_partition_data () - redistribute partition data
12623  *
12624  * return : error code
12625  *
12626  * thread_p (in) :
12627  * class_oid (in) : parent class OID
12628  * no_oids (in) : number of OIDs in the list (promoted partitions)
12629  * oid_list (in) : partition OID list (promoted partitions)
12630  */
12631 static int
12632 redistribute_partition_data (THREAD_ENTRY * thread_p, OID * class_oid, int no_oids, OID * oid_list)
12633 {
12634  int error = NO_ERROR;
12635  int i = 0;
12636  RECDES recdes;
12637  HFID hfid, class_hfid;
12638  OID inst_oid;
12639  SCAN_CODE scan = S_SUCCESS;
12640  VPID vpid;
12641  PGBUF_WATCHER old_page_watcher;
12642  PGSLOTID slotid;
12643  HEAP_SCANCACHE parent_scan_cache, scan_cache;
12644  PRUNING_CONTEXT pcontext;
12645  bool is_scan_end = false;
12646  bool is_parent_scancache_started = false;
12647  bool is_part_scancache_started = false;
12648  bool is_pcontext_inited = false;
12649  int force_count = -1;
12650  OID oid;
12651  OID cls_oid;
12652  LOG_TDES *tdes = LOG_FIND_CURRENT_TDES (thread_p);
12653  MVCCID threshold_mvccid = MVCCID_NULL;
12654 
12655  assert (tdes != NULL);
12656 
12658 
12659  error = heap_get_class_info (thread_p, class_oid, &class_hfid, NULL, NULL);
12660  if (error != NO_ERROR || HFID_IS_NULL (&class_hfid))
12661  {
12662  error = ER_FAILED;
12663  goto exit;
12664  }
12665 
12666  /* start scan cache for insert on parent class */
12667  error = heap_scancache_start_modify (thread_p, &parent_scan_cache, &class_hfid, class_oid, SINGLE_ROW_INSERT, NULL);
12668  if (error != NO_ERROR)
12669  {
12670  goto exit;
12671  }
12672  is_parent_scancache_started = true;
12673 
12674  /* initialize pruning context for parent class */
12675  (void) partition_init_pruning_context (&pcontext);
12676  error = partition_load_pruning_context (thread_p, class_oid, DB_PARTITIONED_CLASS, &pcontext);
12677  if (error != NO_ERROR)
12678  {
12679  goto exit;
12680  }
12681  is_pcontext_inited = true;
12682 
12683  recdes.data = NULL;
12684 
12685  tdes->lock_global_oldest_visible_mvccid ();
12686  threshold_mvccid = log_Gl.mvcc_table.get_global_oldest_visible ();
12687 
12688  for (i = 0; i < no_oids; i++)
12689  {
12690  if (OID_ISNULL (&oid_list[i]))
12691  {
12692  goto exit;
12693  }
12694 
12695  error = heap_get_class_info (thread_p, &oid_list[i], &hfid, NULL, NULL);
12696  if (error != NO_ERROR || HFID_IS_NULL (&hfid))
12697  {
12698  error = ER_FAILED;
12699  goto exit;
12700  }
12701 
12702  PGBUF_INIT_WATCHER (&old_page_watcher, PGBUF_ORDERED_HEAP_NORMAL, &hfid);
12703 
12704  error = heap_scancache_start (thread_p, &scan_cache, &hfid, &oid_list[i], false, false, NULL);
12705  if (error != NO_ERROR)
12706  {
12707  goto exit;
12708  }
12709  is_part_scancache_started = true;
12710 
12711  /* VACUUM all cleanable heap objects before upgrading the domain */
12712  error = heap_vacuum_all_objects (thread_p, &scan_cache, threshold_mvccid);
12713  if (error != NO_ERROR)
12714  {
12715  ASSERT_ERROR ();
12716  goto exit;
12717  }
12718 
12719  /* start with first OID of the first page */
12720  vpid.volid = hfid.vfid.volid;
12721  vpid.pageid = hfid.hpgid;
12722  is_scan_end = false;
12723  while (!is_scan_end)
12724  {
12725  if (scan_cache.page_watcher.pgptr == NULL)
12726  {
12727  error =
12729  &scan_cache.page_watcher);
12730  if (old_page_watcher.pgptr != NULL)
12731  {
12732  pgbuf_ordered_unfix (thread_p, &old_page_watcher);
12733  }
12734  if (error != NO_ERROR)
12735  {
12736  goto exit;
12737  }
12738  }
12739 
12740  slotid = 0;
12741  while (true)
12742  {
12743  /* get next record */
12744  scan = spage_next_record (scan_cache.page_watcher.pgptr, &slotid, &recdes, PEEK);
12745  if (scan == S_ERROR)
12746  {
12747  error = ER_FAILED;
12748  goto exit;
12749  }
12750  else if (scan == S_END)
12751  {
12752  /* move to next page */
12753  error = heap_vpid_next (thread_p, &hfid, scan_cache.page_watcher.pgptr, &vpid);
12754  if (error != NO_ERROR)
12755  {
12756  goto exit;
12757  }
12758 
12759  /* keep latch on current page until the next page is fixed */
12760  pgbuf_replace_watcher (thread_p, &scan_cache.page_watcher, &old_page_watcher);
12761 
12762  if (VPID_ISNULL (&vpid))
12763  {
12764  /* no more pages in the current heap file */
12765  is_scan_end = true;
12766  }
12767  break;
12768  }
12769 
12770  if (slotid == HEAP_HEADER_AND_CHAIN_SLOTID)
12771  {
12772  /* skip the header */
12773  continue;
12774  }
12775 
12776  if (recdes.type != REC_HOME && recdes.type != REC_BIGONE && recdes.type != REC_RELOCATION)
12777  {
12778  continue;
12779  }
12780 
12781  inst_oid.pageid = vpid.pageid;
12782  inst_oid.volid = vpid.volid;
12783  inst_oid.slotid = slotid;
12784 
12785  recdes.data = NULL;
12786 
12787  if (heap_get_visible_version (thread_p, &inst_oid, class_oid, &recdes, &scan_cache, COPY, NULL_CHN) !=
12788  S_SUCCESS)
12789  {
12790  error = ER_FAILED;
12791  goto exit;
12792  }
12793 
12794  /* make sure that pruning does not change the given class OID */
12795  COPY_OID (&cls_oid, class_oid);
12796  error =
12797  locator_insert_force (thread_p, &class_hfid, &cls_oid, &oid, &recdes, true, SINGLE_ROW_INSERT,
12798  &parent_scan_cache, &force_count, DB_PARTITIONED_CLASS, &pcontext, NULL,
12799  UPDATE_INPLACE_OLD_MVCCID, NULL, false, false);
12800  if (error != NO_ERROR)
12801  {
12802  goto exit;
12803  }
12804  }
12805  }
12806 
12807  if (old_page_watcher.pgptr != NULL)
12808  {
12809  pgbuf_ordered_unfix (thread_p, &old_page_watcher);
12810  }
12811  if (is_part_scancache_started == true)
12812  {
12813  (void) heap_scancache_end (thread_p, &scan_cache);
12814  is_part_scancache_started = false;
12815  }
12816  }
12817 
12818 exit:
12819  if (old_page_watcher.pgptr != NULL)
12820  {
12821  pgbuf_ordered_unfix (thread_p, &old_page_watcher);
12822  }
12823  if (scan_cache.page_watcher.pgptr != NULL)
12824  {
12825  pgbuf_ordered_unfix (thread_p, &scan_cache.page_watcher);
12826  }
12827  if (is_parent_scancache_started == true)
12828  {
12829  (void) heap_scancache_end (thread_p, &parent_scan_cache);
12830  }
12831  if (is_part_scancache_started == true)
12832  {
12833  (void) heap_scancache_end (thread_p, &scan_cache);
12834  }
12835  if (is_pcontext_inited == true)
12836  {
12837  partition_clear_pruning_context (&pcontext);
12838  }
12839 
12840  return error;
12841 }
12842 
12843 /*
12844  * xlocator_redistribute_partition_data () - redistribute partition data
12845  *
12846  * return : error code
12847  *
12848  * thread_p (in) :
12849  * class_oid (in) : parent class OID
12850  * no_oids (in) : number of OIDs in the list (promoted partitions)
12851  * oid_list (in) : partition OID list (promoted partitions)
12852  */
12853 int
12854 xlocator_redistribute_partition_data (THREAD_ENTRY * thread_p, OID * class_oid, int no_oids, OID * oid_list)
12855 {
12856  return redistribute_partition_data (thread_p, class_oid, no_oids, oid_list);
12857 }
12858 
12859 /*
12860  * locator_lock_and_get_object_internal () - Internal function: aquire lock and return object
12861  *
12862  * return : scan code
12863  * thread_p (in) :
12864  * context (in/out): Heap get context .
12865  * lock_mode (in) : Type of lock.
12866  *
12867  * NOTE: Caller must handle the cleanup of context
12868  */
12869 static SCAN_CODE
12871 {
12872  SCAN_CODE scan = S_SUCCESS;
12873  bool lock_acquired = false;
12874 
12875  assert (context != NULL);
12876  assert (context->oid_p != NULL && !OID_ISNULL (context->oid_p));
12877  assert (context->class_oid_p != NULL && !OID_ISNULL (context->class_oid_p));
12878  assert (lock_mode > NULL_LOCK); /* this is not the appropriate function for NULL_LOCK */
12879  assert (context->scan_cache != NULL);
12880 
12881  /* try to lock the object conditionally, if it fails unfix page watchers and try unconditionally */
12882 
12883  if (lock_object (thread_p, context->oid_p, context->class_oid_p, lock_mode, LK_COND_LOCK) != LK_GRANTED)
12884  {
12885  if (context->scan_cache && context->scan_cache->cache_last_fix_page && context->home_page_watcher.pgptr != NULL)
12886  {
12887  /* prevent caching home page watcher in scan_cache */
12888  pgbuf_ordered_unfix (thread_p, &context->home_page_watcher);
12889  }
12890  heap_clean_get_context (thread_p, context);
12891  if (lock_object (thread_p, context->oid_p, context->class_oid_p, lock_mode, LK_UNCOND_LOCK) != LK_GRANTED)
12892  {
12893  goto error;
12894  }
12895 
12896  lock_acquired = true;
12897 
12898  /* Prepare for getting record again. Since pages have been unlatched, others may have changed them */
12899  scan = heap_prepare_get_context (thread_p, context, false, LOG_WARNING_IF_DELETED);
12900  if (scan != S_SUCCESS)
12901  {
12902  goto error;
12903  }
12904  }
12905  else
12906  {
12907  lock_acquired = true;
12908  }
12909 
12910  assert (OID_IS_ROOTOID (context->class_oid_p) || lock_mode == S_LOCK || lock_mode == X_LOCK);
12911 
12912  /* Lock should be aquired now -> get recdes */
12913  if (context->recdes_p != NULL)
12914  {
12915  scan = heap_get_last_version (thread_p, context);
12916  /* this scan_code must be preserved until the end of this function to be returned; - unless an error occur */
12917  if (scan != S_SUCCESS && scan != S_SUCCESS_CHN_UPTODATE)
12918  {
12919  goto error;
12920  }
12921  }
12922 
12923  /* Check isolation restrictions and the visibility of the object if it belongs to a mvcc class */
12924  if (!mvcc_is_mvcc_disabled_class (context->class_oid_p))
12925  {
12926  MVCC_REC_HEADER recdes_header;
12927 
12928  /* get header: directly from recdes if it has been obtained, otherwise from heap */
12929  if (context->recdes_p == NULL || scan == S_SUCCESS_CHN_UPTODATE)
12930  {
12931  /* ensure context is prepared to get header of the record */
12932  if (heap_prepare_get_context (thread_p, context, false, LOG_WARNING_IF_DELETED) != S_SUCCESS)
12933  {
12934  scan = S_ERROR;
12935  goto error;
12936  }
12937  if (heap_get_mvcc_header (thread_p, context, &recdes_header) != S_SUCCESS)
12938  {
12939  scan = S_ERROR;
12940  goto error;
12941  }
12942  }
12943  else if (or_mvcc_get_header (context->recdes_p, &recdes_header) != NO_ERROR)
12944  {
12945  goto error;
12946  }
12947 
12948  /* Check REPEATABLE READ/SERIALIZABLE isolation restrictions. */
12951  {
12952  /* In these isolation levels, the transaction is not allowed to modify an object that was already
12953  * modified by other transactions. This would be true if last version matched the visible version.
12954  *
12955  * TODO: We already know here that this last row version is not deleted. It would be enough to just
12956  * check whether the insert MVCCID is considered active relatively to transaction's snapshot.
12957  */
12958  MVCC_SNAPSHOT *tran_snapshot = logtb_get_mvcc_snapshot (thread_p);
12959  MVCC_SATISFIES_SNAPSHOT_RESULT snapshot_res;
12960 
12961  assert (tran_snapshot != NULL && tran_snapshot->snapshot_fnc != NULL);
12962  snapshot_res = tran_snapshot->snapshot_fnc (thread_p, &recdes_header, tran_snapshot);
12963  if (snapshot_res == TOO_OLD_FOR_SNAPSHOT)
12964  {
12965  /* Not visible. */
12967  context->oid_p->pageid, context->oid_p->slotid);
12968  scan = S_DOESNT_EXIST;
12969  goto error;
12970  }
12971  else if (snapshot_res == TOO_NEW_FOR_SNAPSHOT)
12972  {
12973  /* Trying to modify a version already modified by concurrent transaction, which is an isolation conflict.
12974  */
12976  goto error;
12977  }
12978  else if (MVCC_IS_HEADER_DELID_VALID (&recdes_header))
12979  {
12980  /* Trying to modify version deleted by concurrent transaction, which is an isolation conflict. */
12982  goto error;
12983  }
12984  else
12985  {
12986  /* Last version is also visible version and it is not deleted. Fall through. */
12987  }
12988  }
12989 
12990  if (MVCC_IS_HEADER_DELID_VALID (&recdes_header))
12991  {
12992  scan = S_DOESNT_EXIST;
12993  goto error;
12994  }
12995  }
12996 
12997  return scan;
12998 
12999 error:
13000 
13001  if (scan == S_ERROR)
13002  {
13003  /* Caller should handle error setting for other scan codes e.g. S_DOESNT_EXIST, S_DOESNT_FIT. */
13004  ASSERT_ERROR ();
13005  }
13006 
13007  if (lock_acquired)
13008  {
13009  lock_unlock_object_donot_move_to_non2pl (thread_p, context->oid_p, context->class_oid_p, lock_mode);
13010  }
13011 
13012  return (scan != S_SUCCESS && scan != S_SUCCESS_CHN_UPTODATE) ? scan : S_ERROR;
13013 }
13014 
13015 /*
13016  * locator_lock_and_get_object_with_evaluation () - Get MVCC object version for delete/update and check reevaluation.
13017  *
13018  * return : SCAN_CODE.
13019  * thread_p (in) : Thread entry.
13020  * oid (in) : Object OID.
13021  * class_oid (in) : Class OID.
13022  * recdes (out) : Record descriptor.
13023  * scan_cache (in) : Heap scan cache.
13024  * ispeeking (in) : PEEK or COPY.
13025  * old_chn (in) : CHN of known record data.
13026  * mvcc_reev_data (in) : MVCC reevaluation data.
13027  * (obsolete) non_ex_handling_type (in): - LOG_ERROR_IF_DELETED: write the
13028  * ER_HEAP_UNKNOWN_OBJECT error to log
13029  * - LOG_WARNING_IF_DELETED: set only warning
13030  *
13031  * Note: This function will lock the object with X_LOCK. This lock type should correspond to delete/update operations.
13032  */
13033 SCAN_CODE
13035  HEAP_SCANCACHE * scan_cache, int ispeeking, int old_chn,
13036  MVCC_REEV_DATA * mvcc_reev_data,
13037  NON_EXISTENT_HANDLING non_ex_handling_type)
13038 {
13039  HEAP_GET_CONTEXT context;
13040  SCAN_CODE scan = S_SUCCESS;
13041  RECDES recdes_local = RECDES_INITIALIZER;
13043  DB_LOGICAL ev_res = V_UNKNOWN; /* Re-evaluation result. */
13044  OID class_oid_local = OID_INITIALIZER;
13045  LOCK lock_mode = X_LOCK;
13046  int err = NO_ERROR;
13047 
13048  if (recdes == NULL && mvcc_reev_data != NULL)
13049  {
13050  /* peek if only for reevaluation */
13051  recdes = &recdes_local;
13052  ispeeking = PEEK;
13053  old_chn = NULL_CHN;
13054  }
13055 
13056  if (class_oid == NULL)
13057  {
13058  class_oid = &class_oid_local;
13059  }
13060 
13061  if (scan_cache && ispeeking == COPY && recdes != NULL)
13062  {
13063  /* Allocate an area to hold the object. Assume that the object will fit in two pages for not better estimates. */
13064  if (heap_scan_cache_allocate_area (thread_p, scan_cache, DB_PAGESIZE * 2) != NO_ERROR)
13065  {
13066  return S_ERROR;
13067  }
13068  }
13069  heap_init_get_context (thread_p, &context, oid, class_oid, recdes, scan_cache, ispeeking, old_chn);
13070 
13071  /* get class_oid if it is unknown */
13072  if (OID_ISNULL (class_oid))
13073  {
13074  err = heap_prepare_object_page (thread_p, oid, &context.home_page_watcher, context.latch_mode);
13075  if (err != NO_ERROR)
13076  {
13077  ASSERT_ERROR ();
13078  heap_clean_get_context (thread_p, &context);
13079 
13080  /* for non existent object, return S_DOESNT_EXIST and let the caller handle the case */
13081  return err == ER_HEAP_UNKNOWN_OBJECT ? S_DOESNT_EXIST : S_ERROR;
13082  }
13083  if (heap_get_class_oid_from_page (thread_p, context.home_page_watcher.pgptr, class_oid) != NO_ERROR)
13084  {
13085  heap_clean_get_context (thread_p, &context);
13086  return S_DOESNT_EXIST;
13087  }
13088  }
13089 
13090  scan = locator_lock_and_get_object_internal (thread_p, &context, lock_mode);
13091 
13092  /* perform reevaluation */
13093  if (mvcc_reev_data != NULL && (scan == S_SUCCESS || scan == S_SUCCESS_CHN_UPTODATE))
13094  {
13095  if (scan == S_SUCCESS_CHN_UPTODATE)
13096  {
13097  /* PEEK record */
13098  scan = heap_get_record_data_when_all_ready (thread_p, &context);
13099  assert (scan == S_SUCCESS);
13100  }
13101 
13102  if (or_mvcc_get_header (recdes, &mvcc_header) != NO_ERROR)
13103  {
13104  scan = S_ERROR;
13105  goto exit;
13106  }
13107 
13108  if (scan_cache->mvcc_snapshot)
13109  {
13110  MVCC_SATISFIES_SNAPSHOT_RESULT snapshot_res;
13111 
13112  snapshot_res = scan_cache->mvcc_snapshot->snapshot_fnc (thread_p, &mvcc_header, scan_cache->mvcc_snapshot);
13113  if (snapshot_res == SNAPSHOT_SATISFIED)
13114  {
13115  /* Skip the re-evaluation if last version is visible. It should be the same as the visible version
13116  * which was already evaluated. */
13117  goto exit;
13118  }
13119  }
13120  ev_res = locator_mvcc_reev_cond_and_assignment (thread_p, scan_cache, mvcc_reev_data, &mvcc_header, oid, recdes);
13121  if (ev_res != V_TRUE)
13122  {
13123  /* did not pass the evaluation or error occurred - unlock object */
13124  lock_unlock_object_donot_move_to_non2pl (thread_p, oid, class_oid, lock_mode);
13125  }
13126  switch (ev_res)
13127  {
13128  case V_TRUE:
13129  /* Object was locked and passed re-evaluation. Get record. */
13130  goto exit;
13131  case V_ERROR:
13132  /* Error. */
13133  assert (er_errid () != NO_ERROR);
13134  scan = S_ERROR;
13135  goto exit;
13136  case V_FALSE:
13137  case V_UNKNOWN:
13138  /* Record didn't pass re-evaluation. Return S_SUCCESS and let the caller handle the case. */
13139  goto exit;
13140  default:
13141  /* Unhandled. */
13142  assert_release (false);
13143  scan = S_ERROR;
13144  goto exit;
13145  }
13146 
13147  }
13148 
13149 exit:
13150  heap_clean_get_context (thread_p, &context);
13151  return scan;
13152 }
13153 
13154 /*
13155  * locator_get_object () - Retrieve heap objects and decide the type of lock according to the operation type
13156  *
13157  * return : Scan code.
13158  * thread_p (in) : Thread entry.
13159  * oid (in) : Object identifier.
13160  * class_oid (in) : Class oid.
13161  * recdes (out) : Record descriptor.
13162  * scan_cache (in): Scan cache.
13163  * op_type (in) : Requested type of operation.
13164  * lock_mode (in) : Lock type, see note.
13165  * ispeeking (in) : Peek record or copy.
13166  *
13167  * Note: This function should be used when class_oid is unknown, which is required to decide lock_mode;
13168  * When lock_mode is known, a more appropriate function is recommended.
13169  *
13170  * op_type and lock_mode exclude each other according to class type:
13171  * - root class : lock_mode is considered, op_type is ignored
13172  * - instance class: op_type is considered, a new lock_mode is used (according to op_type)
13173  */
13174 SCAN_CODE
13175 locator_get_object (THREAD_ENTRY * thread_p, const OID * oid, OID * class_oid, RECDES * recdes,
13176  HEAP_SCANCACHE * scan_cache, SCAN_OPERATION_TYPE op_type, LOCK lock_mode, int ispeeking, int chn)
13177 {
13178  SCAN_CODE scan_code;
13179  OID class_oid_local = OID_INITIALIZER;
13180  HEAP_GET_CONTEXT context;
13181  int err;
13182 
13183  /* decide the type of lock before anything */
13184 
13185  assert (oid != NULL && !OID_ISNULL (oid));
13186 
13187  if (class_oid == NULL)
13188  {
13189  /* mandatory to decide the lock type */
13190  class_oid = &class_oid_local;
13191  }
13192 
13193  if (scan_cache && ispeeking == COPY && recdes != NULL)
13194  {
13195  /* Allocate an area to hold the object. Assume that the object will fit in two pages for not better estimates. */
13196  if (heap_scan_cache_allocate_area (thread_p, scan_cache, DB_PAGESIZE * 2) != NO_ERROR)
13197  {
13198  return S_ERROR;
13199  }
13200  }
13201 
13202  heap_init_get_context (thread_p, &context, oid, class_oid, recdes, scan_cache, ispeeking, chn);
13203 
13204  /* get class_oid if it is unknown */
13205  if (OID_ISNULL (class_oid))
13206  {
13207  err = heap_prepare_object_page (thread_p, oid, &context.home_page_watcher, context.latch_mode);
13208  if (err != NO_ERROR)
13209  {
13210  ASSERT_ERROR ();
13211  heap_clean_get_context (thread_p, &context);
13212 
13213  /* for non existent object, return S_DOESNT_EXIST and let the caller handle the case */
13214  return err == ER_HEAP_UNKNOWN_OBJECT ? S_DOESNT_EXIST : S_ERROR;
13215  }
13216  if (heap_get_class_oid_from_page (thread_p, context.home_page_watcher.pgptr, class_oid) != NO_ERROR)
13217  {
13218  heap_clean_get_context (thread_p, &context);
13219  return S_DOESNT_EXIST;
13220  }
13221  }
13222 
13223  /* decide lock_mode according to class_oid and op_type */
13224  if (!OID_IS_ROOTOID (class_oid))
13225  {
13226  if (op_type == S_SELECT && !mvcc_is_mvcc_disabled_class (class_oid))
13227  {
13228  /* S_SELECT and mvcc class */
13229  lock_mode = NULL_LOCK;
13230  }
13231  else if (op_type == S_DELETE || op_type == S_UPDATE)
13232  {
13233  assert (lock_mode > S_LOCK);
13234  lock_mode = X_LOCK;
13235  }
13236  else
13237  {
13238  /* S_SELECT and non-mvcc class || S_SELECT_WITH_LOCK */
13239  assert (op_type == S_SELECT || op_type == S_SELECT_WITH_LOCK);
13240  if (lock_mode > S_LOCK)
13241  {
13242  assert (false);
13243  lock_mode = X_LOCK;
13244  }
13245  else
13246  {
13247  lock_mode = S_LOCK;
13248  }
13249  }
13250  }
13251 
13252  if (op_type == S_SELECT && lock_mode == NULL_LOCK)
13253  {
13254  /* No locking */
13255  scan_code = heap_get_visible_version_internal (thread_p, &context, false);
13256  }
13257  else
13258  {
13259  /* Locking */
13260  scan_code = locator_lock_and_get_object_internal (thread_p, &context, lock_mode);
13261  }
13262 
13263  heap_clean_get_context (thread_p, &context);
13264 
13265  return scan_code;
13266 }
13267 
13268 
13269 /*
13270  * locator_lock_and_get_object () - Get MVCC object version for delete/update.
13271  *
13272  * return : SCAN_CODE.
13273  * thread_p (in) : Thread entry.
13274  * oid (in) : Object OID.
13275  * class_oid (in) : Class OID.
13276  * recdes (out) : Record descriptor.
13277  * scan_cache (in) : Heap scan cache.
13278  * ispeeking (in) : PEEK or COPY.
13279  * old_chn (in) : CHN of known record data.
13280  * mvcc_reev_data (in) : MVCC reevaluation data.
13281  * (obsolete) non_ex_handling_type (in): - LOG_ERROR_IF_DELETED: write the
13282  * ER_HEAP_UNKNOWN_OBJECT error to log
13283  * - LOG_WARNING_IF_DELETED: set only warning
13284  */
13285 SCAN_CODE
13286 locator_lock_and_get_object (THREAD_ENTRY * thread_p, const OID * oid, OID * class_oid, RECDES * recdes,
13287  HEAP_SCANCACHE * scan_cache, LOCK lock, int ispeeking, int old_chn,
13288  NON_EXISTENT_HANDLING non_ex_handling_type)
13289 {
13290  HEAP_GET_CONTEXT context;
13291  SCAN_CODE scan_code;
13292 
13293  if (scan_cache && ispeeking == COPY && recdes != NULL)
13294  {
13295  /* Allocate an area to hold the object. Assume that the object will fit in two pages for not better estimates. */
13296  if (heap_scan_cache_allocate_area (thread_p, scan_cache, DB_PAGESIZE * 2) != NO_ERROR)
13297  {
13298  return S_ERROR;
13299  }
13300  }
13301 
13302  heap_init_get_context (thread_p, &context, oid, class_oid, recdes, scan_cache, ispeeking, old_chn);
13303  scan_code = locator_lock_and_get_object_internal (thread_p, &context, lock);
13304  heap_clean_get_context (thread_p, &context);
13305  return scan_code;
13306 }
13307 
13308 /*
13309  * locator_mvcc_reev_cond_and_assignment () -
13310  *
13311  * return: DB_LOGICAL
13312  * thread_p(in): thread entry
13313  * scan_cache(in):
13314  * mvcc_reev_data_p(in/out):
13315  * mvcc_header_p(in):
13316  * curr_row_version_oid_p(in):
13317  * recdes(in):
13318  */
13319 /* TODO: We need to reevaluate relation between primary key * and foreign key. */
13320 static DB_LOGICAL
13322  MVCC_REEV_DATA * mvcc_reev_data_p, MVCC_REC_HEADER * mvcc_header_p,
13323  const OID * curr_row_version_oid_p, RECDES * recdes)
13324 {
13325  DB_LOGICAL ev_res = V_TRUE;
13326 
13327  if (mvcc_reev_data_p == NULL)
13328  {
13329  return ev_res;
13330  }
13331 
13332  assert (mvcc_header_p != NULL && curr_row_version_oid_p != NULL);
13333 
13334  ev_res = V_TRUE;
13335  if (!MVCC_IS_REC_INSERTED_BY_ME (thread_p, mvcc_header_p))
13336  {
13337  switch (mvcc_reev_data_p->type)
13338  {
13339  case REEV_DATA_SCAN:
13340  ev_res = locator_mvcc_reevaluate_filters (thread_p, mvcc_reev_data_p->select_reev_data,
13341  curr_row_version_oid_p, recdes);
13342  mvcc_reev_data_p->filter_result = ev_res;
13343  break;
13344 
13345  case REEV_DATA_UPDDEL:
13346  ev_res =
13347  locator_mvcc_reev_cond_assigns (thread_p, &scan_cache->node.class_oid, curr_row_version_oid_p, scan_cache,
13348  recdes, mvcc_reev_data_p->upddel_reev_data);
13349  mvcc_reev_data_p->filter_result = ev_res;
13350  break;
13351 
13352  default:
13353  break;
13354  }
13355  }
13356  else
13357  {
13358  mvcc_reev_data_p->filter_result = V_TRUE;
13359  }
13360 
13361  return ev_res;
13362 }
13363 
13364 /*
13365  * locator_mvcc_reev_cond_assigns () - reevaluates conditions and assignments
13366  * at update/delete stage of an UPDATE/DELETE
13367  * statement
13368  * return: result of reevaluation
13369  * thread_p(in): thread entry
13370  * class_oid(in): OID of the class that triggered reevaluation
13371  * oid(in) : The OID of the latest version of record that triggered
13372  * reevaluation
13373  * scan_cache(in): scan_cache
13374  * recdes(in): Record descriptor that will contain the updated/deleted record
13375  * mvcc_reev_data(in): The structure that contains data needed for
13376  * reevaluation
13377  *
13378  * Note: the current transaction already acquired X-LOCK on oid parameter
13379  * before calling this function. If the condition returns false then
13380  * the lock must be released by the caller.
13381  * The function reevaluates entire condition: key range, key filter and
13382  * data filter.
13383  * This function allocates memory for recdes and deallocates it if it
13384  * was already allocated for previous reevaluated record. After last
13385  * reevaluation this memory must be deallocated by one of its callers
13386  * (e.g. qexec_execute_update).
13387  */
13388 static DB_LOGICAL
13389 locator_mvcc_reev_cond_assigns (THREAD_ENTRY * thread_p, OID * class_oid, const OID * oid, HEAP_SCANCACHE * scan_cache,
13390  RECDES * recdes, MVCC_UPDDEL_REEV_DATA * mvcc_reev_data)
13391 {
13392  DB_LOGICAL ev_res = V_TRUE;
13393  UPDDEL_MVCC_COND_REEVAL *mvcc_cond_reeval = NULL;
13394  int idx;
13395 
13396  /* reevaluate condition for each class involved into */
13397  for (mvcc_cond_reeval = mvcc_reev_data->mvcc_cond_reev_list; mvcc_cond_reeval != NULL;
13398  mvcc_cond_reeval = mvcc_cond_reeval->next)
13399  {
13400  ev_res =
13401  locator_mvcc_reeval_scan_filters (thread_p, oid, scan_cache, recdes, mvcc_cond_reeval,
13402  mvcc_reev_data->curr_upddel == mvcc_cond_reeval);
13403  if (ev_res != V_TRUE)
13404  {
13405  goto end;
13406  }
13407  }
13408 
13409  if (mvcc_reev_data->new_recdes == NULL)
13410  {
13411  /* Seems that the caller wants to reevaluate only the condition */
13412  goto end;
13413  }
13414 
13415  /* reload data from classes involved only in right side of assignments (not in condition) */
13416  if (mvcc_reev_data->curr_extra_assign_reev != NULL)
13417  {
13418  for (idx = 0; idx < mvcc_reev_data->curr_extra_assign_cnt; idx++)
13419  {
13420  mvcc_cond_reeval = mvcc_reev_data->curr_extra_assign_reev[idx];
13421  ev_res = locator_mvcc_reeval_scan_filters (thread_p, oid, scan_cache, recdes, mvcc_cond_reeval, false);
13422  if (ev_res != V_TRUE)
13423  {
13424  goto end;
13425  }
13426  }
13427  }
13428 
13429  /* after reevaluation perform assignments */
13430  if (mvcc_reev_data->curr_assigns != NULL)
13431  {
13432  UPDATE_MVCC_REEV_ASSIGNMENT *assign = mvcc_reev_data->curr_assigns;
13433  int rc;
13434  DB_VALUE *dbval = NULL;
13435 
13436  if (heap_attrinfo_clear_dbvalues (mvcc_reev_data->curr_attrinfo) != NO_ERROR)
13437  {
13438  ev_res = V_ERROR;
13439  goto end;
13440  }
13441  for (; assign != NULL; assign = assign->next)
13442  {
13443  if (assign->constant != NULL)
13444  {
13445  rc = heap_attrinfo_set (oid, assign->att_id, assign->constant, mvcc_reev_data->curr_attrinfo);
13446  }
13447  else
13448  {
13449  if (fetch_peek_dbval (thread_p, assign->regu_right, mvcc_reev_data->vd, (OID *) class_oid, (OID *) oid,
13450  NULL, &dbval) != NO_ERROR)
13451  {
13452  ev_res = V_ERROR;
13453  goto end;
13454  }
13455  rc = heap_attrinfo_set (oid, assign->att_id, dbval, mvcc_reev_data->curr_attrinfo);
13456  if (dbval->need_clear)
13457  {
13458  pr_clear_value (dbval);
13459  }
13460  }
13461  if (rc != NO_ERROR)
13462  {
13463  ev_res = V_ERROR;
13464  goto end;
13465  }
13466  }
13467 
13468  /* TO DO - reuse already allocated area */
13469  if (mvcc_reev_data->copyarea != NULL)
13470  {
13471  locator_free_copy_area (mvcc_reev_data->copyarea);
13472  mvcc_reev_data->new_recdes->data = NULL;
13473  mvcc_reev_data->new_recdes->area_size = 0;
13474  }
13475  mvcc_reev_data->copyarea =
13476  locator_allocate_copy_area_by_attr_info (thread_p, mvcc_reev_data->curr_attrinfo, recdes,
13477  mvcc_reev_data->new_recdes, -1, LOB_FLAG_INCLUDE_LOB);
13478  if (mvcc_reev_data->copyarea == NULL)
13479  {
13480  ev_res = V_ERROR;
13481  goto end;
13482  }
13483  }
13484 
13485 end:
13486 
13487  return ev_res;
13488 }
13489 
13490 /*
13491  * locator_mvcc_reeval_scan_filters () - reevaluates conditions for a scan table
13492  * at update/delete stage of an UPDATE/DELETE
13493  * statement
13494  * return: result of reevaluation
13495  * thread_p(in): thread entry
13496  * oid(in) : The OID of the latest version of record that triggered
13497  * reevaluation
13498  * scan_cache(in): scan_cache
13499  * recdes(in): Record descriptor of the record to be updated/deleted.
13500  * mvcc_cond_reeval(in): The structure that contains data needed for
13501  * reevaluation
13502  * is_upddel(in): true if current scan is updated/deleted when reevaluation
13503  * occured.
13504  *
13505  * Note: The current transaction already acquired X-LOCK on oid parameter
13506  * before calling this function. If the condition returns false then
13507  * the lock must be released by the caller.
13508  * The function reevaluates entire condition: key range, key filter and
13509  * data filter.
13510  */
13511 static DB_LOGICAL
13513  RECDES * recdes, UPDDEL_MVCC_COND_REEVAL * mvcc_cond_reeval, bool is_upddel)
13514 {
13515  OID *cls_oid = NULL;
13516  const OID *oid_inst = NULL;
13517  MVCC_SCAN_REEV_DATA scan_reev;
13518  RECDES temp_recdes = RECDES_INITIALIZER, *recdesp = NULL;
13519  HEAP_SCANCACHE local_scan_cache;
13520  bool scan_cache_inited = false;
13521  SCAN_CODE scan_code;
13522  DB_LOGICAL ev_res = V_TRUE;
13523 
13524  cls_oid = &mvcc_cond_reeval->cls_oid;
13525  if (!is_upddel)
13526  {
13527  /* the class is different than the class to be updated/deleted, so use the latest version of row */
13528  recdesp = &temp_recdes;
13529  oid_inst = oid;
13530  if (heap_scancache_quick_start_with_class_hfid (thread_p, &local_scan_cache, &scan_cache->node.hfid) != NO_ERROR)
13531  {
13532  ev_res = V_ERROR;
13533  goto end;
13534  }
13535  scan_cache_inited = true;
13536  scan_code = heap_get_visible_version (thread_p, oid_inst, NULL, recdesp, &local_scan_cache, PEEK, NULL_CHN);
13537  if (scan_code != S_SUCCESS)
13538  {
13539  ev_res = V_ERROR;
13540  goto end;
13541  }
13542  }
13543  else
13544  {
13545  /* the class to be updated/deleted */
13546  recdesp = recdes;
13547  oid_inst = mvcc_cond_reeval->inst_oid;
13548  }
13549 
13550  if (mvcc_cond_reeval->rest_attrs->num_attrs != 0)
13551  {
13552  if (heap_attrinfo_read_dbvalues (thread_p, oid_inst, recdesp, NULL, mvcc_cond_reeval->rest_attrs->attr_cache) !=
13553  NO_ERROR)
13554  {
13555  ev_res = V_ERROR;
13556  goto end;
13557  }
13558 
13559  if (fetch_val_list (thread_p, mvcc_cond_reeval->rest_regu_list, NULL, cls_oid, (OID *) oid_inst, NULL, PEEK)
13560  != NO_ERROR)
13561  {
13562  ev_res = V_ERROR;
13563  goto end;
13564  }
13565  }
13566 
13567  if (mvcc_cond_reeval->range_filter.scan_pred != NULL || mvcc_cond_reeval->key_filter.scan_pred != NULL
13568  || mvcc_cond_reeval->data_filter.scan_pred != NULL)
13569  {
13570  /* evaluate conditions */
13571  scan_reev.set_filters (*mvcc_cond_reeval);
13572  scan_reev.qualification = &mvcc_cond_reeval->qualification;
13573  ev_res = locator_mvcc_reevaluate_filters (thread_p, &scan_reev, oid_inst, recdesp);
13574  }
13575 
13576 end:
13577  if (scan_cache_inited)
13578  {
13579  heap_scancache_end (thread_p, &local_scan_cache);
13580  }
13581 
13582  return ev_res;
13583 }
13584 
13585 /*
13586  * locator_mvcc_reevaluate_filters () - reevaluates key range, key filter and data filter predicates
13587  * return: result of reevaluation
13588  * thread_p(in): thread entry
13589  * mvcc_reev_data(in): The structure that contains data needed for reevaluation
13590  * oid(in) : The record that was modified by other transactions and is involved in filters.
13591  * recdes(in): Record descriptor that will contain the record
13592  */
13593 static DB_LOGICAL
13595  RECDES * recdes)
13596 {
13597  FILTER_INFO *filter;
13598  DB_LOGICAL ev_res = V_TRUE;
13599 
13600  filter = mvcc_reev_data->range_filter;
13601  if (filter != NULL && filter->scan_pred != NULL && filter->scan_pred->pred_expr != NULL)
13602  {
13603  if (heap_attrinfo_read_dbvalues (thread_p, oid, recdes, NULL, filter->scan_attrs->attr_cache) != NO_ERROR)
13604  {
13605  return V_ERROR;
13606  }
13607  ev_res = (*filter->scan_pred->pr_eval_fnc) (thread_p, filter->scan_pred->pred_expr, filter->val_descr,
13608  (OID *) oid);
13609  ev_res = update_logical_result (thread_p, ev_res, NULL);
13610  if (ev_res != V_TRUE)
13611  {
13612  return ev_res;
13613  }
13614  }
13615 
13616  filter = mvcc_reev_data->key_filter;
13617  if (filter != NULL && filter->scan_pred != NULL && filter->scan_pred->pred_expr != NULL)
13618  {
13619  if (heap_attrinfo_read_dbvalues (thread_p, oid, recdes, NULL, filter->scan_attrs->attr_cache) != NO_ERROR)
13620  {
13621  return V_ERROR;
13622  }
13623  ev_res = (*filter->scan_pred->pr_eval_fnc) (thread_p, filter->scan_pred->pred_expr, filter->val_descr,
13624  (OID *) oid);
13625  ev_res = update_logical_result (thread_p, ev_res, NULL);
13626  if (ev_res != V_TRUE)
13627  {
13628  return ev_res;
13629  }
13630  }
13631 
13632  filter = mvcc_reev_data->data_filter;
13633  if (filter != NULL && filter->scan_pred != NULL && filter->scan_pred->pred_expr != NULL)
13634  {
13635  ev_res = eval_data_filter (thread_p, (OID *) oid, recdes, NULL, filter);
13636  ev_res = update_logical_result (thread_p, ev_res, (int *) mvcc_reev_data->qualification);
13637  }
13638 
13639  return ev_res;
13640 }
13641 
13642 /*
13643  * locator_decide_operation_type () - returns the operation type that corresponds to the provided lock mode.
13644  *
13645  * return : operation type
13646  * lock_mode (in) : lock_mode
13647  */
13650 {
13651  SCAN_OPERATION_TYPE op_type;
13652 
13653  if (lock_mode == NULL_LOCK)
13654  {
13655  /* for non-mvcc classes, corresponding lock for S_SELECT is S_LOCK;
13656  * this inconsistency should be acceptable, as the operation type is ignored anyway for non-mvcc classes */
13657  op_type = S_SELECT;
13658  }
13659  else if (lock_mode <= S_LOCK)
13660  {
13661  op_type = S_SELECT_WITH_LOCK;
13662  }
13663  else
13664  {
13665  op_type = S_DELETE;
13666  /* equivalent to S_UPDATE */
13667  }
13668 
13669  if (lock_mode > NULL_LOCK && lock_mode <= S_LOCK
13670  && (fetch_version_type == LC_FETCH_MVCC_VERSION || fetch_version_type == LC_FETCH_CURRENT_VERSION))
13671  {
13672  /* In this situation, the operation type must be changed to S_SELECT.
13673  * The final lock mode will be decided when class type will be known */
13674  assert (op_type == S_SELECT_WITH_LOCK);
13675  op_type = S_SELECT;
13676  }
13677 
13678  return op_type;
13679 }
13680 
13681 /*
13682  * locator_get_lock_mode_from_op_type () - returns the lock mode that corresponds to the provided operation type.
13683  *
13684  * return : lock mode
13685  * lock_mode (in) : operation type
13686  */
13687 LOCK
13689 {
13690  switch (op_type)
13691  {
13692  case S_SELECT:
13693  case S_SELECT_WITH_LOCK:
13694  /* S_LOCK -> will be converted to NULL_LOCK for mvcc classes */
13695  return S_LOCK;
13696  case S_UPDATE:
13697  case S_DELETE:
13698  return X_LOCK;
13699  default:
13700  assert (false);
13701  return NA_LOCK;
13702  }
13703 }
13704 
13705 int
13706 xlocator_demote_class_lock (THREAD_ENTRY * thread_p, const OID * class_oid, LOCK lock, LOCK * ex_lock)
13707 {
13708  return lock_demote_class_lock (thread_p, class_oid, lock, ex_lock);
13709 }
13710 
13711 // *INDENT-OFF*
13712 int
13714  const std::vector<record_descriptor> &recdes, int has_index, int op_type,
13715  HEAP_SCANCACHE * scan_cache, int *force_count, int pruning_type, PRUNING_CONTEXT * pcontext,
13716  FUNC_PRED_UNPACK_INFO * func_preds, UPDATE_INPLACE_STYLE force_in_place, bool dont_check_fk)
13717 {
13718  int error_code = NO_ERROR;
13719  size_t accumulated_records_size = 0;
13720  size_t heap_max_page_size;
13721  OID dummy_oid;
13722  std::vector<RECDES> recdes_array;
13723  std::vector<VPID> heap_pages_array;
13724  RECDES local_record;
13725  bool has_BU_lock = lock_has_lock_on_object (class_oid, oid_Root_class_oid, BU_LOCK);
13726  size_t record_overhead = spage_slot_size ();
13727 
13728  // Early-out
13729  if (recdes.size () == 0)
13730  {
13731  // Nothing to insert.
13732  return NO_ERROR;
13733  }
13734 
13735  *force_count = 0;
13736 
13737  // Take into account the unfill factor of the heap file.
13738  heap_max_page_size = heap_nonheader_page_capacity () * (1.0f - prm_get_float_value (PRM_ID_HF_UNFILL_FACTOR));
13739 
13740  for (size_t i = 0; i < recdes.size (); i++)
13741  {
13742  local_record = recdes[i].get_recdes ();
13743  // Loop until we insert all records.
13744 
13745  if (heap_is_big_length (local_record.length))
13746  {
13747  scan_cache->cache_last_fix_page = false;
13748  // We insert other records normally.
13749  error_code = locator_insert_force (thread_p, hfid, class_oid, &dummy_oid, &local_record, has_index,
13750  op_type, scan_cache, force_count, pruning_type, pcontext, func_preds,
13751  force_in_place, NULL, has_BU_lock, dont_check_fk, false);
13752  if (error_code != NO_ERROR)
13753  {
13754  ASSERT_ERROR ();
13755  return error_code;
13756  }
13757  }
13758  else
13759  {
13760  // get records until we fit the size of a page.
13761  if ((DB_ALIGN (local_record.length, HEAP_MAX_ALIGN) + record_overhead + accumulated_records_size)
13762  >= heap_max_page_size)
13763  {
13764  VPID new_page_vpid;
13765  PGBUF_WATCHER home_hint_p;
13766 
13767  VPID_SET_NULL (&new_page_vpid);
13768  scan_cache->cache_last_fix_page = true;
13769 
13770  // First alloc a new empty heap page.
13771  error_code = heap_alloc_new_page (thread_p, hfid, *class_oid, &home_hint_p, &new_page_vpid);
13772  if (error_code != NO_ERROR)
13773  {
13774  ASSERT_ERROR ();
13775  return error_code;
13776  }
13777 
13778  for (size_t j = 0; j < recdes_array.size (); j++)
13779  {
13780  error_code = locator_insert_force (thread_p, hfid, class_oid, &dummy_oid, &recdes_array[j], has_index,
13781  op_type, scan_cache, force_count, pruning_type, pcontext,
13782  func_preds, force_in_place, &home_hint_p, has_BU_lock,
13783  dont_check_fk, true);
13784  if (error_code != NO_ERROR)
13785  {
13786  ASSERT_ERROR ();
13787 
13788  if (home_hint_p.pgptr)
13789  {
13790  pgbuf_ordered_unfix_and_init (thread_p, home_hint_p.pgptr, &home_hint_p);
13791  }
13792 
13793  if (scan_cache->page_watcher.pgptr)
13794  {
13795  pgbuf_ordered_unfix_and_init (thread_p, scan_cache->page_watcher.pgptr,
13796  &scan_cache->page_watcher);
13797  }
13798 
13799  assert (!pgbuf_is_page_fixed_by_thread (thread_p, &new_page_vpid));
13800 
13801  return error_code;
13802  }
13803 
13804  pgbuf_replace_watcher (thread_p, &scan_cache->page_watcher, &home_hint_p);
13805  }
13806 
13807  // Now log the whole page.
13808  pgbuf_log_redo_new_page (thread_p, home_hint_p.pgptr, DB_PAGESIZE, PAGE_HEAP);
13809 
13810  // Add the new VPID to the VPID array.
13811  assert (!VPID_ISNULL (&new_page_vpid));
13812  heap_pages_array.push_back (new_page_vpid);
13813 
13814  // Clear the recdes array.
13815  recdes_array.clear ();
13816  accumulated_records_size = 0;
13817 
13818  // Unfix the page.
13819  pgbuf_ordered_unfix_and_init (thread_p, home_hint_p.pgptr, &home_hint_p);
13820 
13821  assert (!pgbuf_is_page_fixed_by_thread (thread_p, &new_page_vpid));
13822  }
13823 
13824  // Add this record to the recdes array and increase the accumulated size.
13825  recdes_array.push_back (local_record);
13826  accumulated_records_size += DB_ALIGN (local_record.length, HEAP_MAX_ALIGN);
13827  accumulated_records_size += record_overhead; // Add the slot overhead for the record.
13828  }
13829  }
13830 
13831  // We must check if we have records which did not fill an entire page.
13832  for (size_t i = 0; i < recdes_array.size (); i++)
13833  {
13834  scan_cache->cache_last_fix_page = false;
13835  error_code = locator_insert_force (thread_p, hfid, class_oid, &dummy_oid, &recdes_array[i], has_index, op_type,
13836  scan_cache, force_count, pruning_type, pcontext, func_preds, force_in_place,
13837  NULL, has_BU_lock, dont_check_fk, false);
13838  if (error_code != NO_ERROR)
13839  {
13840  ASSERT_ERROR ();
13841  return error_code;
13842  }
13843  }
13844 
13845  // Log the postpone operation
13846  heap_log_postpone_heap_append_pages (thread_p, hfid, class_oid, heap_pages_array);
13847 
13848  return NO_ERROR;
13849 }
13850 
13851 bool
13852 has_errors_filtered_for_insert (std::vector<int> error_filter_array)
13853 {
13854  if (std::find (error_filter_array.begin(), error_filter_array.end(), ER_BTREE_UNIQUE_FAILED)
13855  != error_filter_array.end ())
13856  {
13857  return true;
13858  }
13859 
13860  return false;
13861 }
13862 // *INDENT-ON*
static int locator_eval_filter_predicate(THREAD_ENTRY *thread_p, BTID *btid, OR_PREDICATE *or_pred, OID *class_oid, OID **inst_oids, int num_insts, RECDES **recs, DB_LOGICAL *results)
Definition: locator_sr.c:8056
SCAN_CODE heap_get_record_data_when_all_ready(THREAD_ENTRY *thread_p, HEAP_GET_CONTEXT *context)
Definition: heap_file.c:7707
DISK_ISVALID btree_keyoid_checkscan_check(THREAD_ENTRY *thread_p, BTREE_CHECKSCAN *btscan, OID *cls_oid, DB_VALUE *key, OID *oid)
Definition: btree.c:8364
LC_FETCH_VERSION_TYPE
Definition: locator.h:178
static int locator_find_lockset_missing_class_oids(THREAD_ENTRY *thread_p, LC_LOCKSET *lockset)
Definition: locator_sr.c:2079
#define OID_INITIALIZER
Definition: oid.h:36
static int locator_filter_errid(THREAD_ENTRY *thread_p, int num_ignore_error_count, int *ignore_error_list)
Definition: locator_sr.c:12229
int locator_delete_force(THREAD_ENTRY *thread_p, HFID *hfid, OID *oid, int has_index, int op_type, HEAP_SCANCACHE *scan_cache, int *force_count, MVCC_REEV_DATA *mvcc_reev_data, bool need_locking)
Definition: locator_sr.c:5993
bool check_not_vacuumed
Definition: scan_manager.h:229
void heap_scancache_end_modify(THREAD_ENTRY *thread_p, HEAP_SCANCACHE *scan_cache)
Definition: heap_file.c:7230
DB_VALUE * heap_attrvalue_get_key(THREAD_ENTRY *thread_p, int btid_index, HEAP_CACHE_ATTRINFO *idx_attrinfo, RECDES *recdes, BTID *btid, DB_VALUE *db_value, char *buf, FUNC_PRED_UNPACK_INFO *func_indx_pred, TP_DOMAIN **key_domain)
Definition: heap_file.c:12802
#define OR_PUT_OID(ptr, oid)
OID * oid_Root_class_oid
Definition: oid.c:73
int heap_object_upgrade_domain(THREAD_ENTRY *thread_p, HEAP_SCANCACHE *upd_scancache, HEAP_CACHE_ATTRINFO *attr_info, OID *oid, const ATTR_ID att_id)
Definition: heap_file.c:17011
LC_LOCKSET_CLASSOF * classes
Definition: locator.h:303
int tran_index
Definition: log_impl.h:465
cubthread::entry * thread_get_thread_entry_info(void)
#define NO_ERROR
Definition: error_code.h:46
CLS_INFO * catalog_get_class_info(THREAD_ENTRY *thread_p, OID *class_id_p, CATALOG_ACCESS_INFO *catalog_access_info_p)
int xlocator_lock_and_fetch_all(THREAD_ENTRY *thread_p, const HFID *hfid, LOCK *instance_lock, int *instance_lock_timeout, OID *class_oid, LOCK *class_lock, int *nobjects, int *nfetched, int *nfailed_instance_locks, OID *last_oid, LC_COPYAREA **fetch_area, MVCC_SNAPSHOT *mvcc_snapshot)
Definition: locator_sr.c:11790
int area_size
int db_value_put_null(DB_VALUE *value)
Definition: db_macro.c:122
static bool locator_notify_decache(const OID *class_oid, const OID *oid, void *notify_area)
Definition: locator_sr.c:9068
int locator_drop_transient_class_name_entries(THREAD_ENTRY *thread_p, LOG_LSA *savep_lsa)
Definition: locator_sr.c:1258
#define MVCC_IS_HEADER_DELID_VALID(rec_header_p)
Definition: mvcc.h:87
int heap_get_class_oid_from_page(THREAD_ENTRY *thread_p, PAGE_PTR page_p, OID *class_oid)
Definition: heap_file.c:18824
void log_append_repl_info(THREAD_ENTRY *thread_p, LOG_TDES *tdes, bool is_commit)
Definition: log_manager.c:4564
#define MVCC_GET_INSID(header)
Definition: mvcc.h:51
#define MVCC_SET_PREVIOUS_VERSION_LSA(header, new_lsa)
Definition: mvcc.h:144
static DISK_ISVALID locator_repair_btree_by_delete(THREAD_ENTRY *thread_p, OID *class_oid, BTID *btid, OID *inst_oid)
Definition: locator_sr.c:9211
MVCC_SNAPSHOT * logtb_get_mvcc_snapshot(THREAD_ENTRY *thread_p)
#define pgbuf_ordered_fix(thread_p, req_vpid, fetch_mode, requestmode, req_watcher)
Definition: page_buffer.h:261
int xlocator_assign_oid_batch(THREAD_ENTRY *thread_p, LC_OIDSET *oidset)
Definition: locator_sr.c:11512
bool need_replication
Definition: replication.h:56
BTREE_ISCAN_OID_LIST * next_list
Definition: btree.h:343
REPL_INFO_TYPE
Definition: replication.h:43
int catalog_delete(THREAD_ENTRY *thread_p, OID *class_oid_p)
update_mvcc_reev_assignment * curr_assigns
MVCCID mvcc_ins_id
Definition: mvcc.h:43
LC_FIND_CLASSNAME xlocator_delete_class_name(THREAD_ENTRY *thread_p, const char *classname)
Definition: locator_sr.c:755
#define ASSERT_ERROR()
SCAN_CODE
void or_class_tde_algorithm(RECDES *record, TDE_ALGORITHM *tde_algo)
unsigned int mht_1strhash(const void *key, const unsigned int ht_size)
Definition: memory_hash.c:447
#define CLASSNAME_CACHE_SIZE
Definition: locator_sr.c:74
#define HFID_INITIALIZER
LC_LOCKHINT * locator_reallocate_lockhint(LC_LOCKHINT *lockhint, int max_classes)
Definition: locator.c:1731
LOCATOR_CLASSNAME_ACTION e_current
Definition: locator_sr.c:104
#define ER_MVCC_SERIALIZABLE_CONFLICT
Definition: error_code.h:1484
static int locator_add_or_remove_index_for_moving(THREAD_ENTRY *thread_p, RECDES *recdes, OID *inst_oid, OID *class_oid, int is_insert, int op_type, HEAP_SCANCACHE *scan_cache, bool datayn, bool need_replication, HFID *hfid, FUNC_PRED_UNPACK_INFO *func_preds, bool has_BU_lock)
Definition: locator_sr.c:7575
void set_external_buffer(char *buf, std::size_t buf_size)
int heap_scancache_start_modify(THREAD_ENTRY *thread_p, HEAP_SCANCACHE *scan_cache, const HFID *hfid, const OID *class_oid, int op_type, MVCC_SNAPSHOT *mvcc_snapshot)
Definition: heap_file.c:6867
const block_allocator CSTYLE_BLOCK_ALLOCATOR
Definition: mem_block.cpp:127
bool cache_last_fix_page
Definition: heap_file.h:148
static int locator_prefetch_index_page(THREAD_ENTRY *thread_p, OID *class_oid, RECDES *classrec, RECDES *recdes, int btid_index, HEAP_CACHE_ATTRINFO *attr_info)
Definition: locator_sr.c:12342
static int locator_delete_force_for_moving(THREAD_ENTRY *thread_p, HFID *hfid, OID *oid, int has_index, int op_type, HEAP_SCANCACHE *scan_cache, int *force_count, MVCC_REEV_DATA *mvcc_reev_data, OID *new_obj_oid, OID *partition_oid, bool need_locking)
Definition: locator_sr.c:6021
#define LC_PRIOR_ONEOBJ_PTR_IN_COPYAREA(oneobj_ptr)
Definition: locator.h:49
int locator_start_force_scan_cache(THREAD_ENTRY *thread_p, HEAP_SCANCACHE *scan_cache, const HFID *hfid, const OID *class_oid, int op_type)
Definition: locator_sr.c:3985
void LSA_COPY(log_lsa *plsa1, const log_lsa *plsa2)
Definition: log_lsa.hpp:139
SCAN_CODE heap_get_visible_version(THREAD_ENTRY *thread_p, const OID *oid, OID *class_oid, RECDES *recdes, HEAP_SCANCACHE *scan_cache, int ispeeking, int old_chn)
Definition: heap_file.c:24272
int heap_attrinfo_delete_lob(THREAD_ENTRY *thread_p, RECDES *recdes, HEAP_CACHE_ATTRINFO *attr_info)
Definition: heap_file.c:10464
int qexec_clear_list_cache_by_class(THREAD_ENTRY *thread_p, const OID *class_oid)
int locator_add_or_remove_index(THREAD_ENTRY *thread_p, RECDES *recdes, OID *inst_oid, OID *class_oid, int is_insert, int op_type, HEAP_SCANCACHE *scan_cache, bool datayn, bool need_replication, HFID *hfid, FUNC_PRED_UNPACK_INFO *func_preds, bool has_BU_lock, bool skip_checking_fk)
Definition: locator_sr.c:7545
void locator_free_copy_area(LC_COPYAREA *copyarea)
Definition: locator.c:534
SCAN_PRED * scan_pred
#define ER_LC_INCONSISTENT_BTREE_ENTRY_TYPE7
Definition: error_code.h:858
bool logtb_check_class_for_rr_isolation_err(const OID *class_oid)
int or_replace_rep_id(RECDES *record, int repid)
int heap_prepare_object_page(THREAD_ENTRY *thread_p, const OID *oid, PGBUF_WATCHER *page_watcher_p, PGBUF_LATCH_MODE latch_mode)
Definition: heap_file.c:24609
int partition_load_pruning_context(THREAD_ENTRY *thread_p, const OID *class_oid, int pruning_type, PRUNING_CONTEXT *pinfo)
Definition: partition.c:2249
#define LC_DOESNOT_EXIST
CLS_INFO * catalog_update_class_info(THREAD_ENTRY *thread_p, OID *class_id_p, CLS_INFO *class_info_p, CATALOG_ACCESS_INFO *catalog_access_info_p, bool skip_logging)
SCAN_CODE heap_prepare_get_context(THREAD_ENTRY *thread_p, HEAP_GET_CONTEXT *context, bool is_heap_scan, NON_EXISTENT_HANDLING non_ex_handling_type)
Definition: heap_file.c:7385
#define ER_HEAP_NODATA_NEWADDRESS
Definition: error_code.h:107
DB_TYPE
Definition: dbtype_def.h:670
LOG_LSA * log_get_append_lsa(void)
Definition: log_manager.c:559
#define ER_FAILED
Definition: error_code.h:47
int xlocator_does_exist(THREAD_ENTRY *thread_p, OID *oid, int chn, LOCK lock, LC_FETCH_VERSION_TYPE fetch_version_type, OID *class_oid, int class_chn, int need_fetching, int prefetching, LC_COPYAREA **fetch_area)
Definition: locator_sr.c:3891
#define LC_START_ONEOBJ_PTR_IN_COPYAREA(manyobjs_ptr)
Definition: locator.h:44
#define ER_LC_INCONSISTENT_BTREE_ENTRY_TYPE3
Definition: error_code.h:640
bool mvcc_is_mvcc_disabled_class(const OID *class_oid)
Definition: mvcc.c:616
LOG_GLOBAL log_Gl
#define csect_enter(a, b, c)
Definition: cnv.c:138
#define LC_FLAG_HAS_INDEX
Definition: locator.h:199
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
DISK_ISVALID locator_check_btree_entries(THREAD_ENTRY *thread_p, BTID *btid, HFID *hfid, OID *class_oid, int n_attr_ids, ATTR_ID *attr_ids, int *atts_prefix_length, const char *btname, bool repair)
Definition: locator_sr.c:9276
bool catcls_Enable
ATTR_ID * attrids_pred
Definition: xasl.h:1060
bool xlocator_notify_isolation_incons(THREAD_ENTRY *thread_p, LC_COPYAREA **synch_area)
Definition: locator_sr.c:9132
LC_COPYAREA * locator_reallocate_copy_area_by_length(LC_COPYAREA *old_area, int new_length)
Definition: locator.c:467
MVCCID logtb_find_current_mvccid(THREAD_ENTRY *thread_p)
#define LC_ERROR
int xlocator_fetch_lockset(THREAD_ENTRY *thread_p, LC_LOCKSET *lockset, LC_COPYAREA **fetch_area)
Definition: locator_sr.c:3047
REPR_ID heap_get_class_repr_id(THREAD_ENTRY *thread_p, OID *class_oid)
Definition: heap_file.c:16476
void set_filters(upddel_mvcc_cond_reeval &ureev)
MULTI_RANGE_OPT multi_range_opt
Definition: scan_manager.h:225
char * mem
Definition: locator.h:247
int xlocator_fetch_lockhint_classes(THREAD_ENTRY *thread_p, LC_LOCKHINT *lockhint, LC_COPYAREA **fetch_area)
Definition: locator_sr.c:11291
char * or_pack_string(char *ptr, const char *string)
multi_index_unique_stats * m_index_stats
Definition: heap_file.h:151
const void * mht_put(MHT_TABLE *ht, const void *key, void *data)
Definition: memory_hash.c:1778
#define ER_LC_INCONSISTENT_BTREE_ENTRY_TYPE5
Definition: error_code.h:853
int xbtree_get_unique_pk(THREAD_ENTRY *thread_p, BTID *btid)
Definition: btree.c:6129
void lock_notify_isolation_incons(THREAD_ENTRY *thread_p, bool(*fun)(const OID *class_oid, const OID *oid, void *args), void *args)
PGBUF_WATCHER home_page_watcher
Definition: heap_file.h:378
#define ASSERT_ERROR_AND_SET(error_code)
int num_classes_processed
Definition: locator.h:325
#define OR_MVCC_FLAG_VALID_INSID
char * e_name
Definition: locator_sr.c:102
#define assert_release(e)
Definition: error_manager.h:96
int est_size
Definition: locator.h:353
int lock_demote_class_lock(THREAD_ENTRY *thread_p, const OID *oid, LOCK lock, LOCK *ex_lock)
#define LOG_CHECK_LOG_APPLIER(thread_p)
Definition: log_impl.h:240
void scan_init_index_scan(INDX_SCAN_ID *isidp, struct btree_iscan_oid_list *oid_list, MVCC_SNAPSHOT *mvcc_snapshot)
Definition: scan_manager.c:283
int xtran_server_start_topop(THREAD_ENTRY *thread_p, LOG_LSA *topop_lsa)
int btree_insert(THREAD_ENTRY *thread_p, BTID *btid, DB_VALUE *key, OID *cls_oid, OID *oid, int op_type, btree_unique_stats *unique_stat_info, int *unique, MVCC_REC_HEADER *p_mvcc_rec_header)
Definition: btree.c:25969
const char * classname
Definition: heap_file.h:128
static DB_LOGICAL locator_mvcc_reev_cond_and_assignment(THREAD_ENTRY *thread_p, HEAP_SCANCACHE *scan_cache, MVCC_REEV_DATA *mvcc_reev_data_p, MVCC_REC_HEADER *mvcc_header_p, const OID *curr_row_version_oid_p, RECDES *recdes)
Definition: locator_sr.c:13321
#define LC_FIND_ONEOBJ_PTR_IN_COPYAREA(manyobjs_ptr, obj_num)
Definition: locator.h:51
int catcls_remove_entry(THREAD_ENTRY *thread_p, OID *class_oid)
int or_mvcc_get_header(RECDES *record, MVCC_REC_HEADER *mvcc_header)
#define ER_LC_INCONSISTENT_CLASSNAME_TYPE2
Definition: error_code.h:126
int lock_object(THREAD_ENTRY *thread_p, const OID *oid, const OID *class_oid, LOCK lock, int cond_flag)
SCAN_CODE locator_lock_and_get_object_with_evaluation(THREAD_ENTRY *thread_p, OID *oid, OID *class_oid, RECDES *recdes, HEAP_SCANCACHE *scan_cache, int ispeeking, int old_chn, MVCC_REEV_DATA *mvcc_reev_data, NON_EXISTENT_HANDLING non_ex_handling_type)
Definition: locator_sr.c:13034
#define MVCCID_NULL
void log_sysop_start(THREAD_ENTRY *thread_p)
Definition: log_manager.c:3578
char * info
Definition: replication.h:54
#define OR_MVCC_FLAG_VALID_DELID
#define ER_LC_INCONSISTENT_BTREE_ENTRY_TYPE2
Definition: error_code.h:639
int xlocator_fetch_all(THREAD_ENTRY *thread_p, const HFID *hfid, LOCK *lock, LC_FETCH_VERSION_TYPE fetch_version_type, OID *class_oid, int *nobjects, int *nfetched, OID *last_oid, LC_COPYAREA **fetch_area)
Definition: locator_sr.c:2773
#define OID_SET_NULL(oidp)
Definition: oid.h:85
void locator_free_lockhint(LC_LOCKHINT *lockhint)
Definition: locator.c:1765
#define NULL_SLOTID
DB_LOGICAL(* PR_EVAL_FNC)(THREAD_ENTRY *thread_p, const PRED_EXPR *, val_descr *, OID *)
DISK_ISVALID not_vacuumed_res
Definition: scan_manager.h:231
bool btree_multicol_key_is_null(DB_VALUE *key)
Definition: btree.c:18033
char * data
static DB_LOGICAL locator_mvcc_reev_cond_assigns(THREAD_ENTRY *thread_p, OID *class_oid, const OID *oid, HEAP_SCANCACHE *scan_cache, RECDES *recdes, MVCC_UPDDEL_REEV_DATA *mvcc_reev_data)
Definition: locator_sr.c:13389
LOG_TDES * LOG_FIND_TDES(int tran_index)
Definition: log_impl.h:1095
#define OR_FIXED_ATTRIBUTES_OFFSET(ptr, nvars)
TP_DOMAIN * tp_domain_copy(const TP_DOMAIN *domain, bool check_cache)
int32_t pageid
Definition: dbtype_def.h:879
enum lc_prefetch_flags LC_PREFETCH_FLAGS
Definition: locator.h:339
int xlocator_redistribute_partition_data(THREAD_ENTRY *thread_p, OID *class_oid, int no_oids, OID *oid_list)
Definition: locator_sr.c:12854
INT32 root_pageid
#define LSA_AS_ARGS(lsa_ptr)
Definition: log_lsa.hpp:78
int xrepl_set_info(THREAD_ENTRY *thread_p, REPL_INFO *repl_info)
Definition: locator_sr.c:11642
static void locator_incr_num_transient_classnames(int tran_index)
Definition: locator_sr.c:12451
INT32 hpgid
LC_LOCKSET_REQOBJ * objects
Definition: locator.h:305
#define MULTI_ROW_DELETE
Definition: btree.h:57
#define MVCC_CLEAR_FLAG_BITS(rec_header_p, flag)
Definition: mvcc.h:101
#define BTID_IS_EQUAL(b1, b2)
void btree_init_temp_key_value(bool *clear_flag, DB_VALUE *key_value)
Definition: btree.c:1938
int er_errid(void)
SCAN_CODE heap_get_last_version(THREAD_ENTRY *thread_p, HEAP_GET_CONTEXT *context)
Definition: heap_file.c:24546
DISK_ISVALID locator_check_by_class_oid(THREAD_ENTRY *thread_p, OID *cls_oid, HFID *hfid, BTID *index_btid, bool repair)
Definition: locator_sr.c:10421
#define LC_FETCH_IS_MVCC_VERSION_NEEDED(fetch_type)
Definition: locator.h:186
#define MVCC_SET_DELID(header, mvcc_id)
Definition: mvcc.h:60
void btree_keyoid_checkscan_end(THREAD_ENTRY *thread_p, BTREE_CHECKSCAN *btscan)
Definition: btree.c:8445
MVCC_SATISFIES_SNAPSHOT_RESULT mvcc_satisfies_dirty(THREAD_ENTRY *thread_p, MVCC_REC_HEADER *rec_header, MVCC_SNAPSHOT *snapshot)
Definition: mvcc.c:501
int heap_scancache_end_when_scan_will_resume(THREAD_ENTRY *thread_p, HEAP_SCANCACHE *scan_cache)
Definition: heap_file.c:7210
static int locator_drop_class_name_entry(THREAD_ENTRY *thread_p, const char *classname, LOG_LSA *savep_lsa)
Definition: locator_sr.c:1345
int xlocator_force(THREAD_ENTRY *thread_p, LC_COPYAREA *force_area, int num_ignore_error, int *ignore_error_list)
Definition: locator_sr.c:6983
void xcache_remove_by_oid(THREAD_ENTRY *thread_p, const OID *oid)
Definition: xasl_cache.c:1869
#define PTR_ALIGN(addr, boundary)
Definition: memory_alloc.h:77
void lock_unlock_object_donot_move_to_non2pl(THREAD_ENTRY *thread_p, const OID *oid, const OID *class_oid, LOCK lock)
int catalog_update(THREAD_ENTRY *thread_p, RECDES *record_p, OID *class_oid_p)
#define MULTI_ROW_INSERT
Definition: btree.h:56
void locator_free_lockset(LC_LOCKSET *lockset)
Definition: locator.c:1140
void or_class_hfid(RECDES *record, HFID *hfid)
PRUNING_SCAN_CACHE * locator_get_partition_scancache(PRUNING_CONTEXT *pcontext, const OID *class_oid, const HFID *hfid, int op_type, bool has_function_indexes)
Definition: locator_sr.c:12259
static int locator_repl_get_key_value(DB_VALUE *key_value, LC_COPYAREA *force_area, LC_COPYAREA_ONEOBJ *obj)
Definition: locator_sr.c:6760
bool LSA_LT(const log_lsa *plsa1, const log_lsa *plsa2)
Definition: log_lsa.hpp:174
#define ER_REPL_ERROR
Definition: error_code.h:1121
#define er_log_debug(...)
HL_HEAPID db_change_private_heap(THREAD_ENTRY *thread_p, HL_HEAPID heap_id)
Definition: memory_alloc.c:337
int xlocator_remove_class_from_index(THREAD_ENTRY *thread_p, OID *class_oid, BTID *btid, HFID *hfid)
Definition: locator_sr.c:8842
DB_VALUE_COMPARE_RESULT btree_compare_key(DB_VALUE *key1, DB_VALUE *key2, TP_DOMAIN *key_domain, int do_coercion, int total_order, int *start_colp)
Definition: btree.c:18636
bool heap_does_exist(THREAD_ENTRY *thread_p, OID *class_oid, const OID *oid)
Definition: heap_file.c:8714
int heap_scancache_end(THREAD_ENTRY *thread_p, HEAP_SCANCACHE *scan_cache)
Definition: heap_file.c:7195
tx_transient_class_registry m_modified_classes
Definition: log_impl.h:502
static bool locator_was_index_already_applied(HEAP_CACHE_ATTRINFO *index_attrinfo, BTID *btid, int pos)
Definition: locator_sr.c:7508
void * db_fixed_alloc(HL_HEAPID heap_id, size_t size)
Definition: fixed_alloc.c:92
INDX_COV indx_cov
Definition: scan_manager.h:224
#define MAX_ALIGNMENT
Definition: memory_alloc.h:70
#define ER_CT_INVALID_REPRID
Definition: error_code.h:494
void pgbuf_log_redo_new_page(THREAD_ENTRY *thread_p, PAGE_PTR page_new, int data_size, PAGE_TYPE ptype_new)
int heap_attrinfo_start_with_index(THREAD_ENTRY *thread_p, OID *class_oid, RECDES *class_recdes, HEAP_CACHE_ATTRINFO *attr_info, HEAP_IDX_ELEMENTS_INFO *idx_info)
Definition: heap_file.c:11997
#define COPY_OID(dest_oid_ptr, src_oid_ptr)
Definition: oid.h:63
int length
Definition: locator.h:248
LOCK reqobj_inst_lock
Definition: locator.h:292
LOCK lock_get_object_lock(const OID *oid, const OID *class_oid)
static void locator_repl_add_error_to_copyarea(LC_COPYAREA **copy_area, RECDES *recdes, LC_COPYAREA_ONEOBJ *obj, DB_VALUE *key_value, int err_code, const char *err_msg)
Definition: locator_sr.c:6589
#define DBVAL_BUFSIZE
Definition: btree.h:449
int btree_range_scan_select_visible_oids(THREAD_ENTRY *thread_p, BTREE_SCAN *bts)
Definition: btree.c:25122
LC_CLASS_OIDSET * classes
Definition: locator.h:386
LC_LOCKHINT * locator_allocate_lockhint(int max_classes, bool quit_on_errors)
Definition: locator.c:1629
SCAN_CODE heap_get_mvcc_header(THREAD_ENTRY *thread_p, HEAP_GET_CONTEXT *context, MVCC_REC_HEADER *mvcc_header)
Definition: heap_file.c:7620
int ci_tot_objects
void THREAD_ENTRY
mvcctable mvcc_table
Definition: log_impl.h:684
#define NULL_PAGEID
int catalog_insert(THREAD_ENTRY *thread_p, RECDES *record_p, OID *class_oid_p, OID *rep_dir_p)
HEAP_SCANCACHE_NODE node
Definition: heap_file.h:144
std::size_t get_size(void) const
#define MVCC_GET_PREV_VERSION_LSA(header)
Definition: mvcc.h:152
#define MVCC_SET_INSID(header, mvcc_id)
Definition: mvcc.h:54
void db_destroy_fixed_heap(HL_HEAPID heap_id)
Definition: fixed_alloc.c:80
char * mem
Definition: locator.h:281
int heap_chnguess_put(THREAD_ENTRY *thread_p, const OID *oid, int tran_index, int chn)
Definition: heap_file.c:15306
OR_FOREIGN_KEY * fk
int ATTR_ID
int pr_free_ext_value(DB_VALUE *value)
void heap_log_postpone_heap_append_pages(THREAD_ENTRY *thread_p, const HFID *hfid, const OID *class_oid, const std::vector< VPID > &heap_pages_array)
Definition: heap_file.c:25440
LOCK
int btree_keyoid_checkscan_start(THREAD_ENTRY *thread_p, BTID *btid, BTREE_CHECKSCAN *btscan)
Definition: btree.c:8330
int xlocator_fetch(THREAD_ENTRY *thread_p, OID *oid, int chn, LOCK lock, LC_FETCH_VERSION_TYPE fetch_version_type, LC_FETCH_VERSION_TYPE initial_fetch_version_type, OID *class_oid, int class_chn, int prefetching, LC_COPYAREA **fetch_area)
Definition: locator_sr.c:2375
SCAN_CODE locator_lock_and_get_object(THREAD_ENTRY *thread_p, const OID *oid, OID *class_oid, RECDES *recdes, HEAP_SCANCACHE *scan_cache, LOCK lock, int ispeeking, int old_chn, NON_EXISTENT_HANDLING non_ex_handling_type)
Definition: locator_sr.c:13286
BTREE_SEARCH xbtree_find_unique(THREAD_ENTRY *thread_p, BTID *btid, SCAN_OPERATION_TYPE scan_op_type, DB_VALUE *key, OID *class_oid, OID *oid, bool is_all_class_srch)
Definition: btree.c:23990
void log_append_redo_data2(THREAD_ENTRY *thread_p, LOG_RCVINDEX rcvindex, const VFID *vfid, PAGE_PTR pgptr, PGLENGTH offset, int length, const void *data)
Definition: log_manager.c:1995
void or_class_rep_dir(RECDES *record, OID *rep_dir_p)
int heap_scancache_start(THREAD_ENTRY *thread_p, HEAP_SCANCACHE *scan_cache, const HFID *hfid, const OID *class_oid, int cache_last_fix_page, int is_indexscan, MVCC_SNAPSHOT *mvcc_snapshot)
Definition: heap_file.c:6833
#define ER_UNEXPECTED
Definition: error_code.h:1254
static void locator_generate_class_pseudo_oid(THREAD_ENTRY *thread_p, OID *class_oid)
Definition: locator_sr.c:1816
LC_FIND_CLASSNAME xlocator_reserve_class_names(THREAD_ENTRY *thread_p, const int num_classes, const char **classnames, OID *class_oids)
Definition: locator_sr.c:409
void mht_destroy(MHT_TABLE *ht)
Definition: memory_hash.c:1140
void locator_dump_class_names(THREAD_ENTRY *thread_p, FILE *out_fp)
Definition: locator_sr.c:1786
DB_DATA data
Definition: dbtype_def.h:1083
void partition_clear_pruning_context(PRUNING_CONTEXT *pinfo)
Definition: partition.c:2380
int boot_find_root_heap(HFID *root_hfid_p)
Definition: boot_sr.c:325
#define LC_RECDES_TO_GET_ONEOBJ(copy_area_ptr, oneobj_ptr, recdes_ptr)
Definition: locator.h:54
int locator_initialize(THREAD_ENTRY *thread_p)
Definition: locator_sr.c:246
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
PR_TYPE * pr_type_from_id(DB_TYPE id)
#define RECDES_INITIALIZER
int or_get_unique_hierarchy(THREAD_ENTRY *thread_p, RECDES *record, int attrid, BTID *btid, OID **class_oids, HFID **hfids, int *num_classes, int *partition_local_index)
DISK_ISVALID btree_find_key(THREAD_ENTRY *thread_p, BTID *btid, OID *oid, DB_VALUE *key, bool *clear_key)
Definition: btree.c:18273
void er_set(int severity, const char *file_name, const int line_no, int err_id, int num_args,...)
QPROC_QUALIFICATION * qualification
static int locator_check_foreign_key(THREAD_ENTRY *thread_p, HFID *hfid, OID *class_oid, OID *inst_oid, RECDES *recdes, RECDES *new_recdes, bool *is_cached, LC_COPYAREA **copyarea)
Definition: locator_sr.c:4018
#define csect_check_own(a, b)
int logtb_get_global_unique_stats(THREAD_ENTRY *thread_p, BTID *btid, int *num_oids, int *num_nulls, int *num_keys)
#define OR_MVCC_FLAG_VALID_PREV_VERSION
LOCK locator_get_lock_mode_from_op_type(SCAN_OPERATION_TYPE op_type)
Definition: locator_sr.c:13688
#define HEAP_HEADER_AND_CHAIN_SLOTID
Definition: heap_file.h:62
int heap_attrinfo_read_dbvalues_without_oid(THREAD_ENTRY *thread_p, RECDES *recdes, HEAP_CACHE_ATTRINFO *attr_info)
Definition: heap_file.c:10401
NON_EXISTENT_HANDLING
#define assert(x)
int btree_update(THREAD_ENTRY *thread_p, BTID *btid, DB_VALUE *old_key, DB_VALUE *new_key, OID *cls_oid, OID *oid, int op_type, btree_unique_stats *unique_stat_info, int *unique, MVCC_REC_HEADER *p_mvcc_rec_header)
Definition: btree.c:13967
#define ER_LC_INCONSISTENT_BTREE_ENTRY_TYPE8
Definition: error_code.h:859
#define ER_LC_PARTIALLY_FAILED_TO_FLUSH
Definition: error_code.h:1394
static int lockhint_subclasses(SM_TEMPLATE *temp, SM_CLASS *class_)
TDE_ALGORITHM
Definition: tde.h:71
#define ER_LC_UNKNOWN_CLASSNAME
Definition: error_code.h:121
char * copy_buf
Definition: scan_manager.h:200
int or_packed_string_length(const char *string, int *strlen)
int32_t fileid
Definition: dbtype_def.h:886
BTREE_ISCAN_OID_LIST oid_list
Definition: btree.h:351
LOCATOR_CLASSNAME_ACTION * prev
Definition: locator_sr.c:96
DISK_ISVALID disk_is_page_sector_reserved_with_debug_crash(THREAD_ENTRY *thread_p, VOLID volid, PAGEID pageid, bool debug_crash)
void heap_clean_get_context(THREAD_ENTRY *thread_p, HEAP_GET_CONTEXT *context)
Definition: heap_file.c:24657
int quit_on_errors
Definition: locator.h:326
#define ER_GENERIC_ERROR
Definition: error_code.h:49
#define OID_IS_ROOTOID(oidp)
Definition: oid.h:82
#define ER_FK_INVALID
Definition: error_code.h:1153
LC_FIND_CLASSNAME action
Definition: locator_sr.c:93
BTID * heap_indexinfo_get_btid(int btid_index, HEAP_CACHE_ATTRINFO *attrinfo)
Definition: heap_file.c:12991
void release_buffer(char *&data, std::size_t &size)
int partition_prune_unique_btid(PRUNING_CONTEXT *pcontext, DB_VALUE *key, OID *class_oid, HFID *class_hfid, BTID *btid)
Definition: partition.c:3553
#define LC_REPL_RECDES_FOR_ONEOBJ(copy_area_ptr, oneobj_ptr, key_length, recdes_ptr)
Definition: locator.h:66
#define ER_OUT_OF_VIRTUAL_MEMORY
Definition: error_code.h:50
THREAD_ENTRY * thread_p
Definition: partition_sr.h:69
LC_COPYAREA_MANYOBJS * mobjs
Definition: locator_sr.c:111
int or_chn(RECDES *record)
TDE_CIPHER tde_Cipher
Definition: tde.c:69
#define OID_ISTEMP(oidp)
Definition: oid.h:80
#define LC_FLAG_HAS_UNIQUE_INDEX
Definition: locator.h:201
int locator_rv_redo_rename(THREAD_ENTRY *thread_p, LOG_RCV *rcv)
Definition: locator_sr.c:12615
int heap_get_class_name_alloc_if_diff(THREAD_ENTRY *thread_p, const OID *class_oid, char *guess_classname, char **classname_out)
Definition: heap_file.c:9351
#define OR_VALUE_ALIGNED_SIZE(value)
TRAN_ISOLATION logtb_find_current_isolation(THREAD_ENTRY *thread_p)
#define SINGLE_ROW_UPDATE
Definition: btree.h:54
void fpcache_remove_by_class(THREAD_ENTRY *thread_p, const OID *class_oid)
SCAN_CODE heap_attrinfo_transform_to_disk(THREAD_ENTRY *thread_p, HEAP_CACHE_ATTRINFO *attr_info, RECDES *old_recdes, record_descriptor *new_recdes)
Definition: heap_file.c:11527
#define pgbuf_replace_watcher(thread_p, old_watcher, new_watcher)
Definition: page_buffer.h:337
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
int heap_update_logical(THREAD_ENTRY *thread_p, HEAP_OPERATION_CONTEXT *context)
Definition: heap_file.c:22771
BTREE_SEARCH
#define DB_VALUE_DOMAIN_TYPE(value)
Definition: dbtype.h:70
#define DB_INT32_MAX
Definition: dbtype_def.h:633
HEAP_SCANCACHE * ptr_scancache
Definition: locator_sr.c:113
int or_mvcc_set_header(RECDES *record, MVCC_REC_HEADER *mvcc_rec_header)
void heap_create_update_context(HEAP_OPERATION_CONTEXT *context, HFID *hfid_p, OID *oid_p, OID *class_oid_p, RECDES *recdes_p, HEAP_SCANCACHE *scancache_p, UPDATE_INPLACE_STYLE in_place)
Definition: heap_file.c:22378
#define LC_ONEOBJ_GET_INDEX_FLAG(obj)
Definition: locator.h:196
PRED_EXPR * pred_expr
LC_COPYAREA * locator_allocate_copy_area_by_length(int min_length)
Definition: locator.c:407
#define ER_LC_INCONSISTENT_CLASSNAME_TYPE1
Definition: error_code.h:125
void heap_create_insert_context(HEAP_OPERATION_CONTEXT *context, HFID *hfid_p, OID *class_oid_p, RECDES *recdes_p, HEAP_SCANCACHE *scancache_p)
Definition: heap_file.c:22324
static int locator_get_num_transient_classnames(int tran_index)
Definition: locator_sr.c:12497
multi_index_unique_stats m_multiupd_stats
Definition: log_impl.h:494
void lock_unlock_object(THREAD_ENTRY *thread_p, const OID *oid, const OID *class_oid, LOCK lock, bool force)
static SCAN_CODE locator_return_object_assign(THREAD_ENTRY *thread_p, LOCATOR_RETURN_NXOBJ *assign, OID *class_oid, OID *oid, int chn, int guess_chn, SCAN_CODE scan, int tran_index)
Definition: locator_sr.c:2171
int xlocator_repl_force(THREAD_ENTRY *thread_p, LC_COPYAREA *force_area, LC_COPYAREA **reply_area)
Definition: locator_sr.c:6781
int n_oids_read_last_iteration
Definition: btree.h:232
OR_PREDICATE * filter_predicate
#define HFID_SET_NULL(hfid)
short volid
Definition: dbtype_def.h:880
TRAN_STATE xtran_server_end_topop(THREAD_ENTRY *thread_p, LOG_RESULT_TOPOP result, LOG_LSA *topop_lsa)
LC_FIND_CLASSNAME xlocator_rename_class_name(THREAD_ENTRY *thread_p, const char *oldname, const char *newname, OID *class_oid)
Definition: locator_sr.c:916
#define OID_EQ(oidp1, oidp2)
Definition: oid.h:92
int or_replace_chn(RECDES *record, int chn)
#define heap_classrepr_free_and_init(class_repr, idxp)
Definition: heap_file.h:91
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
VFID vfid
int locator_attribute_info_force(THREAD_ENTRY *thread_p, const HFID *hfid, OID *oid, HEAP_CACHE_ATTRINFO *attr_info, ATTR_ID *att_id, int n_att_id, LC_COPYAREA_OPERATION operation, int op_type, HEAP_SCANCACHE *scan_cache, int *force_count, bool not_check_fk, REPL_INFO_TYPE repl_info, int pruning_type, PRUNING_CONTEXT *pcontext, FUNC_PRED_UNPACK_INFO *func_preds, MVCC_REEV_DATA *mvcc_reev_data, UPDATE_INPLACE_STYLE force_update_inplace, RECDES *rec_descriptor, bool need_locking)
Definition: locator_sr.c:7311
int heap_alloc_new_page(THREAD_ENTRY *thread_p, HFID *hfid, OID class_oid, PGBUF_WATCHER *home_hint_p, VPID *new_page_vpid)
Definition: heap_file.c:24994
#define TP_DOMAIN_TYPE(dom)
int heap_insert_logical(THREAD_ENTRY *thread_p, HEAP_OPERATION_CONTEXT *context, PGBUF_WATCHER *home_hint_p)
Definition: heap_file.c:22426
static int rv
Definition: area_alloc.c:52
update_mvcc_reev_assignment * next
int btree_online_index_dispatcher(THREAD_ENTRY *thread_p, BTID *btid, DB_VALUE *key, OID *cls_oid, OID *oid, int unique, BTREE_OP_PURPOSE purpose, LOG_LSA *undo_nxlsa)
Definition: btree.c:33272
void * mht_get(MHT_TABLE *ht, const void *key)
Definition: memory_hash.c:1419
void locator_finalize(THREAD_ENTRY *thread_p)
Definition: locator_sr.c:364
#define NULL
Definition: freelistheap.h:34
struct lc_oidmap * next
Definition: locator.h:346
RECDES * recdes_p
Definition: heap_file.h:374
UINT64 MVCCID
const char * er_msg(void)
int heap_attrinfo_clear_dbvalues(HEAP_CACHE_ATTRINFO *attr_info)
Definition: heap_file.c:10022
upddel_mvcc_cond_reeval * mvcc_cond_reev_list
#define MVCC_IS_FLAG_SET(rec_header_p, flags)
Definition: mvcc.h:84
#define LC_EXIST
SCAN_ATTRS * scan_attrs
LC_COPYAREA * comm_area
Definition: locator_sr.c:110
int heap_indexinfo_get_attrs_prefix_length(int btid_index, HEAP_CACHE_ATTRINFO *attrinfo, int *attrs_prefix_length, int len_attrs_prefix_length)
Definition: heap_file.c:13054
HEAP_SCANCACHE scan_cache
Definition: scan_manager.h:206
int scan_init_iss(INDX_SCAN_ID *isidp)
Definition: scan_manager.c:214
#define ER_OBJ_OBJECT_NOT_FOUND
Definition: error_code.h:873
PGLENGTH db_network_page_size(void)
int lock_subclass(THREAD_ENTRY *thread_p, const OID *subclass_oid, const OID *superclass_oid, LOCK lock, int cond_flag)
VFID vfid
DB_VALUE * heap_attrinfo_generate_key(THREAD_ENTRY *thread_p, int n_atts, int *att_ids, int *atts_prefix_length, HEAP_CACHE_ATTRINFO *attr_info, RECDES *recdes, DB_VALUE *db_valuep, char *buf, FUNCTION_INDEX_INFO *func_index_info, TP_DOMAIN *midxkey_domain)
Definition: heap_file.c:12672
int xlocator_get_reserved_class_name_oid(THREAD_ENTRY *thread_p, const char *classname, OID *class_oid)
Definition: locator_sr.c:689
#define LC_NEXT_ONEOBJ_PTR_IN_COPYAREA(oneobj_ptr)
Definition: locator.h:48
bool LSA_ISNULL(const log_lsa *lsa_ptr)
Definition: log_lsa.hpp:153
#define SINGLE_ROW_DELETE
Definition: btree.h:53
#define MVCC_IS_REC_INSERTED_BY_ME(thread_p, rec_header_p)
Definition: mvcc.h:114
int heap_vpid_next(THREAD_ENTRY *thread_p, const HFID *hfid, PAGE_PTR pgptr, VPID *next_vpid)
Definition: heap_file.c:4983
LC_FIND_CLASSNAME
static const int LOCATOR_GUESS_NUM_NESTED_REFERENCES
Definition: locator_sr.c:71
btree_unique_stats & get_stats_of(const BTID &index)
void locator_end_force_scan_cache(THREAD_ENTRY *thread_p, HEAP_SCANCACHE *scan_cache)
Definition: locator_sr.c:3999
int xchksum_insert_repl_log_and_demote_table_lock(THREAD_ENTRY *thread_p, REPL_INFO *repl_info, const OID *class_oidp)
Definition: locator_sr.c:12560
DB_VALUE * pr_make_ext_value(void)
TP_DOMAIN * tp_domain_cache(TP_DOMAIN *transient)
#define err(fd,...)
Definition: porting.h:431
struct lc_class_oidset * next
Definition: locator.h:365
int heap_estimate_num_objects(THREAD_ENTRY *thread_p, const HFID *hfid)
Definition: heap_file.c:9060
#define db_private_free_and_init(thrd, ptr)
Definition: memory_alloc.h:141
int xlocator_fetch_all_reference_lockset(THREAD_ENTRY *thread_p, OID *oid, int chn, OID *class_oid, int class_chn, LOCK lock, int quit_on_errors, int prune_level, LC_LOCKSET **lockset, LC_COPYAREA **fetch_area)
Definition: locator_sr.c:3813
int xlocator_demote_class_lock(THREAD_ENTRY *thread_p, const OID *class_oid, LOCK lock, LOCK *ex_lock)
Definition: locator_sr.c:13706
#define ISCAN_OID_BUFFER_CAPACITY
mvcc_scan_reev_data * select_reev_data
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
void partition_init_pruning_context(PRUNING_CONTEXT *pinfo)
Definition: partition.c:2164
#define csect_exit(a, b)
Definition: cnv.c:139
int logtb_tran_update_unique_stats(THREAD_ENTRY *thread_p, const BTID *btid, int n_keys, int n_oids, int n_nulls, bool write_to_log)
#define db_private_free(thrd, ptr)
Definition: memory_alloc.h:229
int btree_prepare_bts(THREAD_ENTRY *thread_p, BTREE_SCAN *bts, BTID *btid, INDX_SCAN_ID *index_scan_id_p, key_val_range *kv_range, FILTER_INFO *filter, const OID *match_class_oid, DB_BIGINT *key_limit_upper, DB_BIGINT *key_limit_lower, bool need_to_check_null, void *bts_other)
Definition: btree.c:15049
SCAN_OPERATION_TYPE
static DB_LOGICAL locator_mvcc_reevaluate_filters(THREAD_ENTRY *thread_p, MVCC_SCAN_REEV_DATA *mvcc_reev_data, const OID *oid, RECDES *recdes)
Definition: locator_sr.c:13594
int btree_physical_delete(THREAD_ENTRY *thread_p, BTID *btid, DB_VALUE *key, OID *oid, OID *class_oid, int *unique, int op_type, btree_unique_stats *unique_stat_info)
Definition: btree.c:29340
unsigned int oid_hash(const void *key_oid, unsigned int htsize)
Definition: oid.c:294
#define MVCC_REC_HEADER_INITIALIZER
Definition: mvcc.h:47
#define db_private_alloc(thrd, size)
Definition: memory_alloc.h:227
PGBUF_WATCHER page_watcher
Definition: heap_file.h:149
regu_variable_list_node * rest_regu_list
LOCATOR_INDEX_ACTION_FLAG
Definition: locator_sr.c:77
OR_PARTITION * partitions
Definition: partition_sr.h:76
static int locator_check_primary_key_update(THREAD_ENTRY *thread_p, OR_INDEX *index, DB_VALUE *key)
Definition: locator_sr.c:4536
INDX_INFO * indx_info
Definition: scan_manager.h:188
need_clear_type need_clear
Definition: dbtype_def.h:1084
#define CEIL_PTVDIV(dividend, divisor)
Definition: memory_alloc.h:50
void btree_scan_clear_key(BTREE_SCAN *btree_scan)
Definition: btree.c:6035
static int locator_guess_sub_classes(THREAD_ENTRY *thread_p, LC_LOCKHINT **lockhint_subclasses)
Definition: locator_sr.c:10631
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
static MHT_TABLE * locator_Mht_classnames
Definition: locator_sr.c:122
LC_COPYAREA_ONEOBJ ** obj
Definition: locator.h:255
#define ER_LOG_UNKNOWN_TRANINDEX
Definition: error_code.h:913
int pr_clear_value(DB_VALUE *value)
void qmgr_add_modified_class(THREAD_ENTRY *thread_p, const OID *class_oid_p)
bool locator_Dont_check_foreign_key
Definition: locator_sr.c:120
int heap_scan_cache_allocate_area(THREAD_ENTRY *thread_p, HEAP_SCANCACHE *scan_cache_p, int size)
Definition: heap_file.c:24744
int max_classes
Definition: locator.h:323
static const INT32 locator_Pseudo_pageid_first
Definition: locator_sr.c:127
int logtb_tran_prepare_count_optim_classes(THREAD_ENTRY *thread_p, const char **classes, LC_PREFETCH_FLAGS *flags, int n_classes)
static SCAN_CODE locator_lock_and_get_object_internal(THREAD_ENTRY *thread_p, HEAP_GET_CONTEXT *context, LOCK lock_mode)
Definition: locator_sr.c:12870
RECDES * recdes
Definition: locator.h:257
bool has_errors_filtered_for_insert(std::vector< int > error_filter_array)
Definition: locator_sr.c:13852
char * or_unpack_mem_value(char *buf, DB_VALUE *value)
char * or_pack_mem_value(char *ptr, DB_VALUE *value, int *packed_len_except_alignment)
LC_OIDMAP * oids
Definition: locator.h:366
void log_sysop_abort(THREAD_ENTRY *thread_p)
Definition: log_manager.c:4017
#define NULL_REPRID
static LC_LOCKSET * locator_all_reference_lockset(THREAD_ENTRY *thread_p, OID *oid, int prune_level, LOCK inst_lock, LOCK class_lock, bool quit_on_errors)
Definition: locator_sr.c:3367
#define MVCC_SET_FLAG_BITS(rec_header_p, flag)
Definition: mvcc.h:95
int heap_vacuum_all_objects(THREAD_ENTRY *thread_p, HEAP_SCANCACHE *upd_scancache, MVCCID threshold_mvccid)
Definition: heap_file.c:23283
int num_reqobjs
Definition: locator.h:287
DB_LOGICAL update_logical_result(THREAD_ENTRY *thread_p, DB_LOGICAL ev_res, int *qualification)
#define LC_RECDES_IN_COPYAREA(copy_area_ptr, recdes_ptr)
Definition: locator.h:74
void heap_create_delete_context(HEAP_OPERATION_CONTEXT *context, HFID *hfid_p, OID *oid_p, OID *class_oid_p, HEAP_SCANCACHE *scancache_p)
Definition: heap_file.c:22351
int oid_compare_equals(const void *key_oid1, const void *key_oid2)
Definition: oid.c:310
static const HFID NULL_HFID
Definition: locator_sr.c:124
Definition: locator_sr.c:100
MVCCID logtb_get_current_mvccid(THREAD_ENTRY *thread_p)
#define CAST_BUFLEN
Definition: porting.h:471
#define NULL_TRAN_INDEX
#define ER_BTREE_UNIQUE_FAILED
Definition: error_code.h:811
int fetch_val_list(THREAD_ENTRY *thread_p, regu_variable_list_node *regu_list, val_descr *vd, OID *class_oid, OID *obj_oid, QFILE_TUPLE tpl, int peek)
Definition: fetch.c:4526
static void error(const char *msg)
Definition: gencat.c:331
LC_COPYAREA * locator_allocate_copy_area_by_attr_info(THREAD_ENTRY *thread_p, HEAP_CACHE_ATTRINFO *attr_info, RECDES *old_recdes, RECDES *new_recdes, const int copyarea_length_hint, int lob_create_flag)
Definition: locator_sr.c:7210
#define MULTI_ROW_UPDATE
Definition: btree.h:58
#define VPID_ISNULL(vpid_ptr)
Definition: dbtype_def.h:925
const recdes & get_recdes(void) const
int xlocator_check_fk_validity(THREAD_ENTRY *thread_p, OID *cls_oid, HFID *hfid, TP_DOMAIN *key_type, int n_attrs, int *attr_ids, OID *pk_cls_oid, BTID *pk_btid, char *fk_name)
Definition: locator_sr.c:11689
int heap_chnguess_get(THREAD_ENTRY *thread_p, const OID *oid, int tran_index)
Definition: heap_file.c:15255
DISK_ISVALID locator_check_class_names(THREAD_ENTRY *thread_p)
Definition: locator_sr.c:1923
static int rc
Definition: serial.c:50
int heap_prefetch(THREAD_ENTRY *thread_p, OID *class_oid, const OID *oid, LC_COPYAREA_DESC *prefetch)
Definition: heap_file.c:13512
char * or_pack_int(char *ptr, int number)
STATIC_INLINE void perfmon_inc_stat(THREAD_ENTRY *thread_p, PERF_STAT_ID psid) __attribute__((ALWAYS_INLINE))
#define ER_INTERRUPTED
Definition: error_code.h:51
MVCCID get_global_oldest_visible() const
Definition: mvcc_table.cpp:612
PRUNING_SCAN_CACHE * partition_new_scancache(PRUNING_CONTEXT *pcontext)
Definition: partition.c:3350
TP_DOMAIN * tp_domain_construct(DB_TYPE domain_type, DB_OBJECT *class_obj, int precision, int scale, TP_DOMAIN *setdomain)
LOG_TDES * LOG_FIND_CURRENT_TDES(THREAD_ENTRY *thread_p=NULL)
Definition: log_impl.h:1115
int mht_dump(THREAD_ENTRY *thread_p, FILE *out_fp, const MHT_TABLE *ht, const int print_id_opt, int(*print_func)(THREAD_ENTRY *thread_p, FILE *fp, const void *key, void *data, void *args), void *func_args)
Definition: memory_hash.c:1299
SCAN_CODE heap_get_class_oid(THREAD_ENTRY *thread_p, const OID *oid, OID *class_oid)
Definition: heap_file.c:9285
DISK_ISVALID locator_check_class(THREAD_ENTRY *thread_p, OID *class_oid, RECDES *peek, HFID *class_hfid, BTID *index_btid, bool repair)
Definition: locator_sr.c:10297
#define LOG_FIND_THREAD_TRAN_INDEX(thrd)
Definition: perf_monitor.h:158
LC_FIND_CLASSNAME xlocator_find_lockhint_class_oids(THREAD_ENTRY *thread_p, int num_classes, const char **many_classnames, LOCK *many_locks, int *many_need_subclasses, LC_PREFETCH_FLAGS *many_flags, OID *guessed_class_oids, int *guessed_class_chns, bool quit_on_errors, LC_LOCKHINT **hlock, LC_COPYAREA **fetch_area)
Definition: locator_sr.c:11017
#define HFID_IS_NULL(hfid)
SCAN_CODE locator_get_object(THREAD_ENTRY *thread_p, const OID *oid, OID *class_oid, RECDES *recdes, HEAP_SCANCACHE *scan_cache, SCAN_OPERATION_TYPE op_type, LOCK lock_mode, int ispeeking, int chn)
Definition: locator_sr.c:13175
bool db_value_is_null(const DB_VALUE *value)
char * or_class_name(RECDES *record)
bool locator_manyobj_flag_is_set(LC_COPYAREA_MANYOBJS *copyarea, enum MULTI_UPDATE_FLAG muf)
Definition: locator.c:2597
static int locator_defence_drop_class_name_entry(const void *name, void *ent, void *args)
Definition: locator_sr.c:1501
static DISK_ISVALID locator_check_unique_btree_entries(THREAD_ENTRY *thread_p, BTID *btid, OID *cls_oid, RECDES *classrec, ATTR_ID *attr_ids, const char *btname, bool repair)
Definition: locator_sr.c:9701
int xlocator_get_class(THREAD_ENTRY *thread_p, OID *class_oid, int class_chn, const OID *oid, LOCK lock, int prefetching, LC_COPYAREA **fetch_area)
Definition: locator_sr.c:2704
int quit_on_errors
Definition: locator.h:300
#define ARG_FILE_LINE
Definition: error_manager.h:44
LC_COPYAREA_OPERATION
Definition: locator.h:106
void lock_unlock_classes_lock_hint(THREAD_ENTRY *thread_p, LC_LOCKHINT *lockhint)
int repl_info_type
Definition: replication.h:55
int pr_clone_value(const DB_VALUE *src, DB_VALUE *dest)
static const bool COPY
int log_add_to_modified_class_list(THREAD_ENTRY *thread_p, const char *classname, const OID *class_oid)
Definition: log_manager.c:4757
PR_EVAL_FNC eval_fnc(THREAD_ENTRY *thread_p, const PRED_EXPR *pr, DB_TYPE *single_node_type)
void heap_init_get_context(THREAD_ENTRY *thread_p, HEAP_GET_CONTEXT *context, const OID *oid, OID *class_oid, RECDES *recdes, HEAP_SCANCACHE *scan_cache, int ispeeking, int old_chn)
Definition: heap_file.c:24697
#define ER_LC_BADFORCE_OPERATION
Definition: error_code.h:123
PR_EVAL_FNC pr_eval_fnc
float prm_get_float_value(PARAM_ID prm_id)
int heap_delete_logical(THREAD_ENTRY *thread_p, HEAP_OPERATION_CONTEXT *context)
Definition: heap_file.c:22606
int xlocator_assign_oid(THREAD_ENTRY *thread_p, const HFID *hfid, OID *perm_oid, int expected_length, OID *class_oid, const char *classname)
Definition: locator_sr.c:2044
int catcls_delete_catalog_classes(THREAD_ENTRY *thread_p, const char *name, OID *class_oid)
#define LOCATOR_GUESS_HT_SIZE
Definition: locator_sr.c:72
LC_COPYAREA_ONEOBJ * obj
Definition: locator_sr.c:112
LC_FIND_CLASSNAME xlocator_find_class_oid(THREAD_ENTRY *thread_p, const char *classname, OID *class_oid, LOCK lock)
Definition: locator_sr.c:1033
MVCC_SNAPSHOT * mvcc_snapshot
Definition: heap_file.h:154
INT16 PGSLOTID
void lock_demote_read_class_lock_for_checksumdb(THREAD_ENTRY *thread_p, int tran_index, const OID *class_oid)
int length
Definition: locator.h:283
int lock_object_wait_msecs(THREAD_ENTRY *thread_p, const OID *oid, const OID *class_oid, LOCK lock, int cond_flag, int wait_msecs)
#define csect_enter_as_reader(a, b, c)
int btree_find_foreign_key(THREAD_ENTRY *thread_p, BTID *btid, DB_VALUE *key, OID *class_oid, OID *found_oid)
Definition: btree.c:5972
int btree_range_scan(THREAD_ENTRY *thread_p, BTREE_SCAN *bts, BTREE_RANGE_SCAN_PROCESS_KEY_FUNC *key_func)
Definition: btree.c:24922
#define free_and_init(ptr)
Definition: memory_alloc.h:147
int heap_scancache_quick_start_with_class_hfid(THREAD_ENTRY *thread_p, HEAP_SCANCACHE *scan_cache, const HFID *hfid)
Definition: heap_file.c:19308
bool heap_attrinfo_check_unique_index(THREAD_ENTRY *thread_p, HEAP_CACHE_ATTRINFO *attr_info, ATTR_ID *att_id, int n_att_id)
Definition: heap_file.c:18957
#define DB_ALIGN(offset, align)
Definition: memory_alloc.h:84
LOG_LSA repl_insert_lsa
Definition: log_impl.h:510
#define strlen(s1)
Definition: intl_support.c:43
#define BTID_COPY(btid_ptr1, btid_ptr2)
static int locator_repl_prepare_force(THREAD_ENTRY *thread_p, LC_COPYAREA_ONEOBJ *obj, RECDES *old_recdes, RECDES *recdes, DB_VALUE *key_value, HEAP_SCANCACHE *force_scancache)
Definition: locator_sr.c:6665
void LSA_SET_NULL(log_lsa *lsa_ptr)
Definition: log_lsa.hpp:146
int locator_update_index(THREAD_ENTRY *thread_p, RECDES *new_recdes, RECDES *old_recdes, ATTR_ID *att_id, int n_att_id, OID *oid, OID *class_oid, int op_type, HEAP_SCANCACHE *scan_cache, REPL_INFO *repl_info)
Definition: locator_sr.c:8147
int locator_multi_insert_force(THREAD_ENTRY *thread_p, HFID *hfid, OID *class_oid, const std::vector< record_descriptor > &recdes, int has_index, int op_type, HEAP_SCANCACHE *scan_cache, int *force_count, int pruning_type, PRUNING_CONTEXT *pcontext, FUNC_PRED_UNPACK_INFO *func_preds, UPDATE_INPLACE_STYLE force_in_place, bool dont_check_fk)
Definition: locator_sr.c:13713
bool pgbuf_is_page_fixed_by_thread(THREAD_ENTRY *thread_p, const VPID *vpid_p)
int lock_classes_lock_hint(THREAD_ENTRY *thread_p, LC_LOCKHINT *lockhint)
int heap_attrinfo_start_with_btid(THREAD_ENTRY *thread_p, OID *class_oid, BTID *btid, HEAP_CACHE_ATTRINFO *attr_info)
Definition: heap_file.c:12237
HEAP_SCANCACHE area_scancache
Definition: locator_sr.c:114
DB_DOMAIN * domain
Definition: dbtype_def.h:865
#define DB_PAGESIZE
#define QFILE_IS_LIST_CACHE_DISABLED
Definition: list_file.h:54
static int locator_add_or_remove_index_internal(THREAD_ENTRY *thread_p, RECDES *recdes, OID *inst_oid, OID *class_oid, int is_insert, int op_type, HEAP_SCANCACHE *scan_cache, bool datayn, bool replyn, HFID *hfid, FUNC_PRED_UNPACK_INFO *func_preds, LOCATOR_INDEX_ACTION_FLAG idx_action_flag, bool has_BU_lock, bool skip_checking_fk)
Definition: locator_sr.c:7610
#define ER_HEAP_UNKNOWN_OBJECT
Definition: error_code.h:102
#define MVCC_GET_DELID(header)
Definition: mvcc.h:57
static int locator_area_op_to_pruning_type(LC_COPYAREA_OPERATION op)
Definition: locator_sr.c:12317
#define BTREE_END_OF_SCAN(bts)
Definition: btree.h:317
int catcls_insert_catalog_classes(THREAD_ENTRY *thread_p, RECDES *record)
DB_LOGICAL
Definition: dbtype_def.h:1218
bool is_loaded
Definition: tde.h:148
#define HFID_EQ(hfid_ptr1, hfid_ptr2)
Definition: heap_file.h:48
#define LC_IS_FLUSH_UPDATE(operation)
Definition: locator.h:125
int orc_subclasses_from_record(RECDES *record, int *array_size, OID **array_ptr)
#define LC_MANYOBJS_PTR_IN_COPYAREA(copy_areaptr)
Definition: locator.h:39
#define ER_LC_INCONSISTENT_BTREE_ENTRY_TYPE1
Definition: error_code.h:638
int e_tran_index
Definition: locator_sr.c:103
SCAN_CODE heap_attrinfo_transform_to_disk_except_lob(THREAD_ENTRY *thread_p, HEAP_CACHE_ATTRINFO *attr_info, RECDES *old_recdes, record_descriptor *new_recdes)
Definition: heap_file.c:11547
int locator_delete_lob_force(THREAD_ENTRY *thread_p, OID *class_oid, OID *oid, RECDES *recdes)
Definition: locator_sr.c:6311
void er_clear(void)
static SCAN_CODE locator_lock_and_return_object(THREAD_ENTRY *thread_p, LOCATOR_RETURN_NXOBJ *assign, OID *class_oid, OID *oid, int chn, LOCK lock_mode, SCAN_OPERATION_TYPE op_type)
Definition: locator_sr.c:2314
void log_sysop_attach_to_outer(THREAD_ENTRY *thread_p)
Definition: log_manager.c:4076
#define SINGLE_ROW_INSERT
Definition: btree.h:52
LOCK lock_Conv[12][12]
Definition: lock_table.c:179
int btree_get_pkey_btid(THREAD_ENTRY *thread_p, OID *cls_oid, BTID *pkey_btid)
Definition: btree.c:7833
OID oid
Definition: locator.h:352
void log_sysop_commit(THREAD_ENTRY *thread_p)
Definition: log_manager.c:3895
static bool locator_is_exist_class_name_entry(THREAD_ENTRY *thread_p, LOCATOR_CLASSNAME_ENTRY *entry)
Definition: locator_sr.c:12524
static int redistribute_partition_data(THREAD_ENTRY *thread_p, OID *class_oid, int no_oids, OID *oid_list)
Definition: locator_sr.c:12632
SCAN_CODE spage_next_record(PAGE_PTR page_p, PGSLOTID *out_slot_id_p, RECDES *record_descriptor_p, int is_peeking)
int REPR_ID
PRED_EXPR * pred
Definition: xasl.h:1058
upddel_mvcc_cond_reeval ** curr_extra_assign_reev
int btree_multicol_key_has_null(DB_VALUE *key)
Definition: btree.c:18079
SCAN_OPERATION_TYPE locator_decide_operation_type(LOCK lock_mode, LC_FETCH_VERSION_TYPE fetch_version_type)
Definition: locator_sr.c:13649
const container_type & get_map() const
int i
Definition: dynamic_load.c:954
#define PGBUF_ORDERED_NULL_HFID
Definition: page_buffer.h:85
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)
char * pr_valstring(const DB_VALUE *val)
#define ER_LC_INCONSISTENT_CLASSNAME_TYPE4
Definition: error_code.h:128
LC_LOCKSET * locator_reallocate_lockset(LC_LOCKSET *lockset, int max_reqobjs)
Definition: locator.c:1091
DB_TYPE id
HL_HEAPID db_create_fixed_heap(int req_size, int recs_per_chunk)
Definition: fixed_alloc.c:64
#define DB_IS_NULL(value)
Definition: dbtype.h:63
int heap_assign_address(THREAD_ENTRY *thread_p, const HFID *hfid, OID *class_oid, OID *oid, int expected_length)
Definition: heap_file.c:5914
int locator_insert_force(THREAD_ENTRY *thread_p, HFID *hfid, OID *class_oid, OID *oid, RECDES *recdes, int has_index, int op_type, HEAP_SCANCACHE *scan_cache, int *force_count, int pruning_type, PRUNING_CONTEXT *pcontext, FUNC_PRED_UNPACK_INFO *func_preds, UPDATE_INPLACE_STYLE force_in_place, PGBUF_WATCHER *home_hint_p, bool has_BU_lock, bool dont_check_fk, bool use_bulk_logging)
Definition: locator_sr.c:4854
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
DB_LOGICAL eval_data_filter(THREAD_ENTRY *thread_p, OID *oid, RECDES *recdesp, HEAP_SCANCACHE *scan_cache, FILTER_INFO *filterp)
struct tp_domain * next
Definition: object_domain.h:74
mvcc_update_reev_data * upddel_reev_data
static int locator_check_primary_key_delete(THREAD_ENTRY *thread_p, OR_INDEX *index, DB_VALUE *key)
Definition: locator_sr.c:4190
static int locator_permoid_class_name(THREAD_ENTRY *thread_p, const char *classname, const OID *class_oid)
Definition: locator_sr.c:1173
int qexec_clear_pred_context(THREAD_ENTRY *thread_p, pred_expr_with_context *pred_filter, bool dealloc_dbvalues)
int num_transient_classnames
Definition: log_impl.h:504
int locator_savepoint_transient_class_name_entries(THREAD_ENTRY *thread_p, LOG_LSA *savep_lsa)
Definition: locator_sr.c:1604
int spage_slot_size(void)
Definition: slotted_page.c:827
INT16 type
static int locator_force_for_multi_update(THREAD_ENTRY *thread_p, LC_COPYAREA *force_area)
Definition: locator_sr.c:6397
void map(const map_func_type &func) const
char * strdup(const char *str)
Definition: porting.c:901
heap_cache_attrinfo * attr_cache
#define NULL_VOLID
MVCC_SNAPSHOT_FUNC snapshot_fnc
Definition: mvcc.h:176
int lock_has_lock_on_object(const OID *oid, const OID *class_oid, LOCK lock)
TRAN_STATE state
Definition: log_impl.h:469
int num_classes_of_reqobjs_processed
Definition: locator.h:297
bool heap_is_big_length(int length)
Definition: heap_file.c:1302
static INT32 locator_Pseudo_pageid_crt
Definition: locator_sr.c:129
int btree_keyval_search(THREAD_ENTRY *thread_p, BTID *btid, SCAN_OPERATION_TYPE scan_op_type, BTREE_SCAN *bts, key_val_range *kv_range, OID *class_oid, FILTER_INFO *filter, INDX_SCAN_ID *isidp, bool is_all_class_srch)
Definition: btree.c:14751
static int locator_force_drop_class_name_entry(const void *name, void *ent, void *args)
Definition: locator_sr.c:1560
static int locator_print_class_name(THREAD_ENTRY *thread_p, FILE *outfp, const void *key, void *ent, void *args)
Definition: locator_sr.c:1722
int heap_indexinfo_get_attrids(int btid_index, HEAP_CACHE_ATTRINFO *attrinfo, ATTR_ID *attrids)
Definition: heap_file.c:13030
DB_VALUE key1
Definition: access_spec.hpp:58
#define catalog_free_class_info_and_init(class_info_p)
DB_MIDXKEY midxkey
Definition: dbtype_def.h:1065
static DB_LOGICAL locator_mvcc_reeval_scan_filters(THREAD_ENTRY *thread_p, const OID *oid, HEAP_SCANCACHE *scan_cache, RECDES *recdes, UPDDEL_MVCC_COND_REEVAL *mvcc_cond_reeval, bool is_upddel)
Definition: locator_sr.c:13512
void heap_attrinfo_end(THREAD_ENTRY *thread_p, HEAP_CACHE_ATTRINFO *attr_info)
Definition: heap_file.c:9979
OR_INDEX_STATUS index_status
#define TP_ARE_COMPARABLE_KEY_TYPES(key1_type, key2_type)
short volid
Definition: dbtype_def.h:887
int heap_init_func_pred_unpack_info(THREAD_ENTRY *thread_p, HEAP_CACHE_ATTRINFO *attr_info, const OID *class_oid, FUNC_PRED_UNPACK_INFO **func_indx_preds)
Definition: heap_file.c:17493
HEAP_SCANCACHE * scan_cache
Definition: heap_file.h:375
static void locator_decr_num_transient_classnames(int tran_index)
Definition: locator_sr.c:12474
int heap_scancache_quick_start(HEAP_SCANCACHE *scan_cache)
Definition: heap_file.c:7040
#define OID_ISNULL(oidp)
Definition: oid.h:81
static int locator_move_record(THREAD_ENTRY *thread_p, HFID *old_hfid, OID *old_class_oid, OID *obj_oid, OID *new_class_oid, HFID *new_class_hfid, RECDES *recdes, HEAP_SCANCACHE *scan_cache, int op_type, int has_index, int *force_count, PRUNING_CONTEXT *context, MVCC_REEV_DATA *mvcc_reev_data, bool need_locking)
Definition: locator_sr.c:5208
LC_COPYAREA_MANYOBJS * mobjs
Definition: locator.h:254
enum mvcc_satisfies_snapshot_result MVCC_SATISFIES_SNAPSHOT_RESULT
Definition: mvcc.h:164
LOG_RESULT_TOPOP
Definition: log_comm.h:73
SCAN_CODE heap_next(THREAD_ENTRY *thread_p, const HFID *hfid, OID *class_oid, OID *next_oid, RECDES *recdes, HEAP_SCANCACHE *scan_cache, int ispeeking)
Definition: heap_file.c:18622
int heap_indexinfo_get_num_attrs(int btid_index, HEAP_CACHE_ATTRINFO *attrinfo)
Definition: heap_file.c:13010
bool log_does_allow_replication(void)
Definition: log_comm.c:270
LOG_LSA * xrepl_log_get_append_lsa(void)
Definition: locator_sr.c:11669
int num_classes_of_reqobjs
Definition: locator.h:296
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
LOCK reqobj_class_lock
Definition: locator.h:293
int xlocator_upgrade_instances_domain(THREAD_ENTRY *thread_p, OID *class_oid, int att_id)
Definition: locator_sr.c:12070
enum update_inplace_style UPDATE_INPLACE_STYLE
Definition: heap_file.h:268
int heap_attrinfo_set(const OID *inst_oid, ATTR_ID attrid, DB_VALUE *attr_val, HEAP_CACHE_ATTRINFO *attr_info)
Definition: heap_file.c:11239
int heap_get_class_info(THREAD_ENTRY *thread_p, const OID *class_oid, HFID *hfid_out, FILE_TYPE *ftype_out, char **classname_out)
Definition: heap_file.c:16733
void lock_unlock_objects_lock_set(THREAD_ENTRY *thread_p, LC_LOCKSET *lockset)
PAGE_PTR pgptr
Definition: page_buffer.h:222
#define LC_IS_FLUSH_INSERT(operation)
Definition: locator.h:121
int num_reqobjs_processed
Definition: locator.h:289
static const INT32 locator_Pseudo_pageid_last
Definition: locator_sr.c:128
#define pgbuf_ordered_unfix(thread_p, watcher_object)
Definition: page_buffer.h:280
#define SINGLE_ROW_MODIFY
Definition: btree.h:55
LC_LOCKSET * locator_allocate_lockset(int max_reqobjs, LOCK reqobj_inst_lock, LOCK reqobj_class_lock, int quit_on_errors)
Definition: locator.c:955
static int locator_delete_force_internal(THREAD_ENTRY *thread_p, HFID *hfid, OID *oid, int has_index, int op_type, HEAP_SCANCACHE *scan_cache, int *force_count, MVCC_REEV_DATA *mvcc_reev_data, LOCATOR_INDEX_ACTION_FLAG idx_action_flag, OID *new_obj_oid, OID *partition_oid, bool need_locking)
Definition: locator_sr.c:6049
PGBUF_LATCH_MODE latch_mode
Definition: heap_file.h:385
static int locator_savepoint_class_name_entry(const char *classname, LOG_LSA *savep_lsa)
Definition: locator_sr.c:1667
BTREE_ISCAN_OID_LIST * oid_list
Definition: scan_manager.h:201
static int locator_check_class_on_heap(const void *name, void *ent, void *args)
Definition: locator_sr.c:1854
int heap_nonheader_page_capacity()
Definition: heap_file.c:25032
void btree_set_mvcc_header_ids_for_update(THREAD_ENTRY *thread_p, bool do_delete_only, bool do_insert_only, MVCCID *mvcc_id, MVCC_REC_HEADER *mvcc_rec_header)
Definition: btree.c:21297
#define ER_FK_RESTRICT
Definition: error_code.h:1155
int heap_get_class_name(THREAD_ENTRY *thread_p, const OID *class_oid, char **class_name)
Definition: heap_file.c:9328
PRUNING_SCAN_CACHE * partition_get_scancache(PRUNING_CONTEXT *pcontext, const OID *partition_oid)
Definition: partition.c:3320
#define ER_TDE_CIPHER_IS_NOT_LOADED
Definition: error_code.h:1613
#define PEEK
Definition: file_io.h:74
DISK_ISVALID locator_check_all_entries_of_all_btrees(THREAD_ENTRY *thread_p, bool repair)
Definition: locator_sr.c:10501
#define pgbuf_ordered_unfix_and_init(thread_p, page, pg_watcher)
Definition: page_buffer.h:69
DB_VALUE key2
Definition: access_spec.hpp:59
int mht_compare_strings_are_equal(const void *key1, const void *key2)
Definition: memory_hash.c:767
#define VPID_SET_NULL(vpid_ptr)
Definition: dbtype_def.h:906
BTREE_SCAN btree_scan
Definition: btree.h:350
#define ER_INDEX_FOUND_NOT_VACUUMED
Definition: error_code.h:1519
upddel_mvcc_cond_reeval * curr_upddel
SCAN_CODE heap_get_visible_version_internal(THREAD_ENTRY *thread_p, HEAP_GET_CONTEXT *context, bool is_heap_scan)
Definition: heap_file.c:24333
int num_classes
Definition: locator.h:324
#define ER_LC_INCONSISTENT_BTREE_ENTRY_TYPE6
Definition: error_code.h:854
OR_ATTRIBUTE ** atts
HFID ci_hfid
int heap_get_referenced_by(THREAD_ENTRY *thread_p, OID *class_oid, const OID *obj_oid, RECDES *recdes, int *max_oid_cnt, OID **oid_list)
Definition: heap_file.c:13303
static DISK_ISVALID locator_repair_btree_by_insert(THREAD_ENTRY *thread_p, OID *class_oid, BTID *btid, DB_VALUE *key, OID *inst_oid)
Definition: locator_sr.c:9176
#define PGBUF_INIT_WATCHER(w, rank, hfid)
Definition: page_buffer.h:123
#define HFID_COPY(hfid_ptr1, hfid_ptr2)
LC_COPYAREA_ONEOBJ objs
Definition: locator.h:238
int btree_check_foreign_key(THREAD_ENTRY *thread_p, OID *cls_oid, HFID *hfid, OID *oid, DB_VALUE *keyval, int n_attrs, OID *pk_cls_oid, BTID *pk_btid, const char *fk_name)
Definition: btree.c:22005
LC_COPYAREA_OPERATION operation
Definition: locator.h:219
const OID * oid_p
Definition: heap_file.h:371
void tp_domain_free(TP_DOMAIN *dom)
UPDATE_INPLACE_STYLE update_in_place
Definition: heap_file.h:280
int catcls_update_catalog_classes(THREAD_ENTRY *thread_p, const char *name, RECDES *record, OID *class_oid_p, UPDATE_INPLACE_STYLE force_in_place)
LC_LOCKHINT_CLASS * classes
Definition: locator.h:329
DISK_ISVALID
Definition: disk_manager.h:53
int btree_mvcc_delete(THREAD_ENTRY *thread_p, BTID *btid, DB_VALUE *key, OID *class_oid, OID *oid, int op_type, btree_unique_stats *unique_stat_info, int *unique, MVCC_REC_HEADER *p_mvcc_rec_header)
Definition: btree.c:26021
int fpcache_retire(THREAD_ENTRY *thread_p, OID *class_oid, BTID *btid, pred_expr_with_context *filter_pred)
#define HEAP_MAX_ALIGN
Definition: heap_file.h:64
VAL_DESCR * val_descr
#define HEAP_IS_UPDATE_INPLACE(update_inplace_style)
Definition: heap_file.h:271
HEAP_SCANCACHE scan_cache
Definition: partition_sr.h:52
HEAP_CACHE_ATTRINFO * cache_pred
Definition: xasl.h:1061
#define ER_LC_INCONSISTENT_CLASSNAME_TYPE3
Definition: error_code.h:127
#define ER_FK_CANT_DELETE_INSTANCE
Definition: error_code.h:1157
func_pred_unpack_info * func_index_pred
Definition: partition_sr.h:54
#define HEAP_ISVALID_OID(thread_p, oid)
Definition: heap_file.h:77
#define BTREE_SET_UNIQUE_VIOLATION_ERROR(THREAD, KEY, OID, C_OID, BTID, BTNM)
Definition: btree.h:96
#define BTREE_INIT_SCAN(bts)
Definition: btree.h:253
#define ER_MVCC_NOT_SATISFIED_REEVALUATION
Definition: error_code.h:1480
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 int locator_update_force(THREAD_ENTRY *thread_p, HFID *hfid, OID *class_oid, OID *oid, RECDES *ikdrecdes, RECDES *recdes, int has_index, ATTR_ID *att_id, int n_att_id, int op_type, HEAP_SCANCACHE *scan_cache, int *force_count, bool not_check_fk, REPL_INFO_TYPE repl_info_type, int pruning_type, PRUNING_CONTEXT *pcontext, MVCC_REEV_DATA *mvcc_reev_data, UPDATE_INPLACE_STYLE force_in_place, bool need_locking)
Definition: locator_sr.c:5308
int fpcache_claim(THREAD_ENTRY *thread_p, BTID *btid, or_predicate *or_pred, pred_expr_with_context **filter_pred)
#define ISCAN_OID_BUFFER_SIZE
static LC_FIND_CLASSNAME xlocator_reserve_class_name(THREAD_ENTRY *thread_p, const char *classname, OID *class_oid)
Definition: locator_sr.c:454
#define ER_LC_INCONSISTENT_BTREE_ENTRY_TYPE4
Definition: error_code.h:852
SCAN_CODE heap_get_class_record(THREAD_ENTRY *thread_p, const OID *class_oid, RECDES *recdes_p, HEAP_SCANCACHE *scan_cache, int ispeeking)
Definition: heap_file.c:24780
static int locator_prefetch_index_page_internal(THREAD_ENTRY *thread_p, BTID *btid, OID *class_oid, RECDES *classrec, RECDES *recdes)
Definition: locator_sr.c:12359