CUBRID Engine  latest
schema_manager.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  * schema_manager.c - "Schema" (in the SQL standard sense) implementation
21  */
22 
23 #ident "$Id$"
24 
25 #include "config.h"
26 
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <ctype.h>
31 #include <assert.h>
32 #ifdef HPUX
33 #include <a.out.h>
34 #endif /* HPUX */
35 
36 
37 #include "dbtype.h"
38 #include "authenticate.h"
39 #include "string_opfunc.h"
40 #include "schema_manager.h"
41 #include "porting.h"
42 #include "chartype.h"
43 #if !defined(WINDOWS)
44 #include "dynamic_load.h"
45 #endif /* !WINDOWS */
46 #include "error_manager.h"
47 #include "work_space.h"
48 #include "object_primitive.h"
49 #include "class_object.h"
50 #include "message_catalog.h"
51 #include "memory_alloc.h"
52 #include "environment_variable.h"
53 
54 #include "language_support.h"
55 #include "object_representation.h"
56 #include "object_domain.h"
57 #include "set_object.h"
58 #include "virtual_object.h"
59 #include "transform_cl.h"
60 #include "locator_cl.h"
61 #include "statistics.h"
62 #include "network_interface_cl.h"
63 #include "parser.h"
64 #include "trigger_manager.h"
65 #include "storage_common.h"
66 #include "transform.h"
67 #include "system_parameter.h"
68 #include "object_template.h"
69 #include "execute_schema.h"
70 #include "release_string.h"
71 #include "execute_statement.h"
72 #include "crypt_opfunc.h"
73 
74 #include "db.h"
75 #include "object_accessor.h"
76 #include "boot_cl.h"
77 
78 #if defined (SUPPRESS_STRLEN_WARNING)
79 #define strlen(s1) ((int) strlen(s1))
80 #endif /* defined (SUPPRESS_STRLEN_WARNING) */
81 
82 #define SM_ADD_CONSTRAINT_SAVEPOINT_NAME "aDDcONSTRAINT"
83 #define SM_ADD_UNIQUE_CONSTRAINT_SAVEPOINT_NAME "aDDuNIQUEcONSTRAINT"
84 #define SM_DROP_CLASS_MOP_SAVEPOINT_NAME "dELETEcLASSmOP"
85 #define SM_TRUNCATE_SAVEPOINT_NAME "SmtRUnCATE"
86 
87 /*
88  * SCHEMA_DEFINITION
89  *
90  * description:
91  * Maintains information about an SQL schema.
92  */
93 
94 /*
95  NOTE: This is simple-minded implementation for now since we don't yet
96  support CREATE SCHEMA, SET SCHEMA, and associated statements.
97  */
98 
99 typedef struct schema_def
100 {
101 
102  /* This is the default qualifier for class/vclass names */
104 
105  /* The only user who can delete this schema. */
106  /* But, note that entry level doesn't support DROP SCHEMA anyway */
108 
109  /* The next three items are currently not used at all. They are simply a reminder of future TODOs. Although entry
110  * level SQL leaves out many schema management functions, entry level SQL does include specification of tables,
111  * views, and grants as part of CREATE SCHEMA statements. */
112 
113  void *tables; /* unused dummy */
114  void *views; /* unused dummy */
115  void *grants; /* unused dummy */
116 
117 } SCHEMA_DEF;
118 
119 /*
120  * Current_schema
121  *
122  * description:
123  * This is the current schema. The schema name in this structure is the
124  * default qualifier for any class/vclass names which are not
125  * explicitly qualified.
126  * This structure should only be changed with sc_set_current_schema which
127  * currently is called only from AU_SET_USER
128  */
129 
130 static SCHEMA_DEF Current_Schema = { {'\0'}, NULL, NULL, NULL, NULL };
131 
132 
133 
134 
135 
136 #define WC_PERIOD L'.'
137 
138 /*
139  * Internal structure for maintaining the global list of static
140  * method linkage information. This list is built with user supplied
141  * information by calling sm_add_static_method().
142  */
144 
146 {
148 
149  char *name;
150  void (*function) ();
151 
152 };
153 
154 /*
155  * Temporary structure used to hold linking state during dynamic linking.
156  */
157 typedef struct method_link METHOD_LINK;
158 
160 {
161  struct method_link *next;
162 
165 
166 };
167 
168 /* various states of a domain comparison. */
169 typedef enum
170 {
171 
176 } DOMAIN_COMP;
177 
178 /*
179  * Structure used internally during the flattening of a class
180  * hierarchy. This information could be folded in with the
181  * class and method structure definitions but its only used once
182  * and makes it less confusing for the flattener.
183  * For each attribute and method in a class hierarchy, a candidate
184  * structure will be built during flattening.
185  */
186 typedef struct sm_candidate SM_CANDIDATE;
187 
189 {
191 
192  const char *name;
193  const char *alias;
196  SM_COMPONENT *obj; /* actual component structure */
198  int order;
199 
200  unsigned int is_alias:1; /* expanded alias candidates */
201  unsigned int is_requested:1; /* requested in a resolution specifier */
202 };
203 
204 /*
205  * Static_method_table
206  *
207  * description:
208  * Global list of static method link information.
209  */
210 
212 
213 /*
214  * Platform specific default extension for method files.
215  * These are added automatically if the extension is not found in the schema
216  */
217 #if defined(WINDOWS)
218 static const char *method_file_extension = ".dll";
219 #elif defined (HPUX)
220 static const char *method_file_extension = ".sl";
221 #elif defined (SOLARIS) || defined(LINUX)
222 static const char *method_file_extension = ".so";
223 #elif defined(sun) || defined(AIX)
224 static const char *method_file_extension = ".o";
225 #else /* WINDOWS */
226 #error "Unknown machine type."
227 #endif /* WINDOWS */
228 
229 #if !defined(WINDOWS)
230 #include <nlist.h>
231 #endif /* !WINDOWS */
232 
233 
234 
235 #if defined (ENABLE_UNUSED_FUNCTION) /* to disable TEXT */
236 const char TEXT_CONSTRAINT_PREFIX[] = "#text_";
237 #endif /* ENABLE_UNUSED_FUNCTION */
238 /*
239  * This is the root of the currently active attribute/method descriptors.
240  * These are kept on a list so we can quickly invalidate them during
241  * significant but unusual events like schema changes.
242  * This list is generally short. If it can be long, consider a
243  * doubly linked list for faster removal.
244 */
245 
247 
248 /* ROOT_CLASS GLOBALS */
249 /* Global root class structure */
251 
252 /* Global MOP for the root class object. Used by the locator */
254 
255 /* Name of the root class */
257 
258 /* Heap file identifier for the root class */
260 
261 static unsigned int local_schema_version = 0;
262 static unsigned int global_schema_version = 0;
263 
264 static int domain_search (MOP dclass_mop, MOP class_mop);
265 static int annotate_method_files (MOP classmop, SM_CLASS * class_);
266 static int alter_trigger_cache (SM_CLASS * class_, const char *attribute, int class_attribute, DB_OBJECT * trigger,
267  int drop_it);
268 static int alter_trigger_hierarchy (DB_OBJECT * classop, const char *attribute, int class_attribute,
269  DB_OBJECT * target_class, DB_OBJECT * trigger, int drop_it);
270 static int find_attribute_op (MOP op, const char *name, SM_CLASS ** classp, SM_ATTRIBUTE ** attp);
271 #if defined (ENABLE_UNUSED_FUNCTION)
272 static int lock_query_subclasses (DB_OBJLIST ** subclasses, MOP op, DB_OBJLIST * exceptions, int update);
273 #endif
274 
275 static int fetch_descriptor_class (MOP op, SM_DESCRIPTOR * desc, int for_update, SM_CLASS ** class_);
276 
277 
278 
279 static STATIC_METHOD *sm_find_static_method (const char *name);
280 static int sm_count_tokens (const char *string, int *maxcharp);
281 static int sm_split_loader_commands (const char *string, const char ***command_ptr);
282 static void sm_free_loader_commands (char **commands);
283 static void sm_free_method_links (METHOD_LINK * links);
284 static int sm_link_static_method (SM_METHOD * method, METHOD_LINK ** link_ptr);
285 static int sm_link_static_methods (SM_CLASS * class_, METHOD_LINK ** links_ptr);
286 static int sm_expand_method_files (SM_METHOD_FILE * files);
287 #if !defined(WINDOWS)
288 static int sm_build_function_nlist (METHOD_LINK * links, struct nlist **nlist_ptr);
289 static void sm_free_function_nlist (struct nlist *namelist);
290 #endif /* !WINDOWS */
291 #if defined (sun) || defined(SOLARIS) || defined(LINUX) || defined(AIX)
292 #if defined(SOLARIS) || defined(LINUX) || defined(AIX)
293 static int sm_link_dynamic_methods (METHOD_LINK * links, const char **files);
294 #else /* SOLARIS || LINUX || AIX */
295 static int sm_link_dynamic_methods (METHOD_LINK * links, const char **files, const char **commands);
296 #endif /* SOLARIS || LINUX || AIX */
297 #elif defined(HPUX)
298 static int sm_link_dynamic_methods (METHOD_LINK * links, const char **files, const char **commands);
299 #elif defined(WINDOWS)
300 static HINSTANCE load_dll (const char *name);
301 static int sm_link_dynamic_methods (METHOD_LINK * links, const char **files, const char **commands);
302 #endif /* sun || SOLARIS || LINUX */
303 static int sm_file_extension (const char *path, const char *ext);
304 static int sm_dynamic_link_class (SM_CLASS * class_, METHOD_LINK * links);
305 static int sm_link_methods (SM_CLASS * class_);
306 
307 
308 static int check_resolution_target (SM_TEMPLATE * template_, SM_RESOLUTION * res, int *valid_ptr);
309 static const char *template_classname (SM_TEMPLATE * template_);
310 static const char *candidate_source_name (SM_TEMPLATE * template_, SM_CANDIDATE * candidate);
311 static int find_superclass (DB_OBJECT * classop, SM_TEMPLATE * temp, DB_OBJECT * super);
313 static SM_METHOD_ARGUMENT *find_argument (SM_METHOD_SIGNATURE * sig, int argnum);
317 static void free_candidates (SM_CANDIDATE * candidates);
318 static SM_CANDIDATE *prune_candidate (SM_CANDIDATE ** clist_pointer);
319 static void add_candidate (SM_CANDIDATE ** candlist, SM_COMPONENT * comp, int order, MOP source,
320  SM_RESOLUTION * resolutions);
323 static int check_attribute_method_overlap (SM_TEMPLATE * template_, SM_CANDIDATE * candidates);
324 static int check_alias_conflict (SM_TEMPLATE * template_, SM_CANDIDATE * candidates);
325 static int check_alias_domains (SM_TEMPLATE * template_, SM_CANDIDATE * candidates, SM_CANDIDATE ** most_specific);
326 static void auto_resolve_conflict (SM_CANDIDATE * candidate, SM_RESOLUTION ** resolutions, SM_NAME_SPACE resspace);
327 static int resolve_candidates (SM_TEMPLATE * template_, SM_CANDIDATE * candidates, int auto_resolve,
328  SM_CANDIDATE ** winner_return);
329 static void insert_attribute (SM_ATTRIBUTE ** attlist, SM_ATTRIBUTE * att);
330 static void insert_method (SM_METHOD ** methlist, SM_METHOD * method);
331 static int flatten_components (SM_TEMPLATE * def, SM_TEMPLATE * flat, SM_NAME_SPACE name_space, int auto_res);
332 static int flatten_method_files (SM_TEMPLATE * def, SM_TEMPLATE * flat);
333 static int flatten_query_spec_lists (SM_TEMPLATE * def, SM_TEMPLATE * flat);
334 static void filter_component_resolutions (SM_TEMPLATE * template_, const char *name, SM_NAME_SPACE resspace);
335 static void remove_shadowed_resolutions (SM_TEMPLATE * original, SM_TEMPLATE * flat);
336 static void filter_reslist (SM_RESOLUTION ** reslist, MOP deleted_class);
337 static int check_invalid_resolutions (SM_TEMPLATE * template_, SM_RESOLUTION ** resolutions,
338  SM_RESOLUTION * original_list);
339 static int filter_resolutions (SM_TEMPLATE * def, SM_TEMPLATE * flat, MOP deleted_class);
340 static SM_ATTRIBUTE *find_matching_att (SM_ATTRIBUTE * list, SM_ATTRIBUTE * att, int idmatch);
341 static int retain_former_ids (SM_TEMPLATE * flat);
342 static int flatten_trigger_cache (SM_TEMPLATE * def, SM_TEMPLATE * flat);
343 static int flatten_properties (SM_TEMPLATE * def, SM_TEMPLATE * flat);
344 static int flatten_template (SM_TEMPLATE * def, MOP deleted_class, SM_TEMPLATE ** flatp, int auto_res);
345 static void assign_attribute_id (SM_CLASS * class_, SM_ATTRIBUTE * att, int class_attribute);
346 static void assign_method_id (SM_CLASS * class_, SM_METHOD * method, bool class_method);
348 static int build_storage_order (SM_CLASS * class_, SM_TEMPLATE * flat);
349 static void fixup_component_classes (MOP classop, SM_TEMPLATE * flat);
350 static void fixup_self_domain (TP_DOMAIN * domain, MOP self);
351 static void fixup_method_self_domains (SM_METHOD * meth, MOP self);
352 static void fixup_attribute_self_domain (SM_ATTRIBUTE * att, MOP self);
353 static void fixup_self_reference_domains (MOP classop, SM_TEMPLATE * flat);
354 static TP_DOMAIN *construct_index_key_domain (int n_atts, SM_ATTRIBUTE ** atts, const int *asc_desc,
355  const int *prefix_lengths, int func_col_id, TP_DOMAIN * func_domain);
356 static int collect_hier_class_info (MOP classop, DB_OBJLIST * subclasses, const char *constraint_name, int reverse,
357  int *n_classes, int n_attrs, OID * oids, int *attr_ids, HFID * hfids);
358 static int allocate_index (MOP classop, SM_CLASS * class_, DB_OBJLIST * subclasses, SM_ATTRIBUTE ** attrs,
359  const int *asc_desc, const int *attrs_prefix_length, int unique_pk, int not_null,
360  int reverse, const char *constraint_name, BTID * index, OID * fk_refcls_oid,
361  BTID * fk_refcls_pk_btid, const char *fk_name, SM_PREDICATE_INFO * filter_index,
362  SM_FUNCTION_INFO * function_index, SM_INDEX_STATUS index_status);
363 static int deallocate_index (SM_CLASS_CONSTRAINT * cons, BTID * index);
364 static int rem_class_from_index (OID * oid, BTID * index, HFID * heap);
365 static int check_fk_validity (MOP classop, SM_CLASS * class_, SM_ATTRIBUTE ** key_attrs, const int *asc_desc,
366  OID * pk_cls_oid, BTID * pk_btid, char *fk_name);
367 static int update_foreign_key_ref (MOP ref_clsop, SM_FOREIGN_KEY_INFO * fk_info);
368 static int allocate_unique_constraint (MOP classop, SM_CLASS * class_, SM_CLASS_CONSTRAINT * con,
369  DB_OBJLIST * subclasses, SM_TEMPLATE * template_);
370 static int allocate_foreign_key (MOP classop, SM_CLASS * class_, SM_CLASS_CONSTRAINT * con, DB_OBJLIST * subclasses);
371 static int allocate_disk_structures_index (MOP classop, SM_CLASS * class_, SM_CLASS_CONSTRAINT * con,
372  DB_OBJLIST * subclasses, SM_TEMPLATE * template_);
373 static int allocate_disk_structures (MOP classop, SM_CLASS * class_, DB_OBJLIST * subclasses, SM_TEMPLATE * template_);
374 static int drop_foreign_key_ref (MOP classop, SM_CLASS * class_, SM_CLASS_CONSTRAINT * flat_cons,
375  SM_CLASS_CONSTRAINT ** cons);
376 static int drop_foreign_key_ref_internal (MOP classop, SM_CLASS_CONSTRAINT * flat_cons, SM_CLASS_CONSTRAINT * cons);
377 static bool is_index_owner (MOP classop, SM_CLASS_CONSTRAINT * con);
378 static int inherit_constraint (MOP classop, SM_CLASS_CONSTRAINT * con);
379 static int transfer_disk_structures (MOP classop, SM_CLASS * class_, SM_TEMPLATE * flat);
380 static void save_previous_value (SM_ATTRIBUTE * old, SM_ATTRIBUTE * new_);
381 static void check_inherited_attributes (MOP classmop, SM_CLASS * class_, SM_TEMPLATE * flat);
382 static void invalidate_unused_triggers (MOP class_mop, SM_CLASS * class_, SM_TEMPLATE * flat);
383 static int install_new_representation (MOP classop, SM_CLASS * class_, SM_TEMPLATE * flat);
384 static int lock_supers (SM_TEMPLATE * def, DB_OBJLIST * current, DB_OBJLIST ** oldlist, DB_OBJLIST ** newlist);
385 static int update_supers (MOP classop, DB_OBJLIST * oldsupers, DB_OBJLIST * newsupers);
386 static int lock_supers_drop (DB_OBJLIST * supers);
387 static int update_supers_drop (MOP classop, DB_OBJLIST * supers);
388 static int lock_subclasses_internal (SM_TEMPLATE * def, MOP op, DB_OBJLIST * newsupers, DB_OBJLIST ** newsubs);
389 static int lock_subclasses (SM_TEMPLATE * def, DB_OBJLIST * newsupers, DB_OBJLIST * cursubs, DB_OBJLIST ** newsubs);
390 static int flatten_subclasses (DB_OBJLIST * subclasses, MOP deleted_class);
391 static void abort_subclasses (DB_OBJLIST * subclasses);
392 static int update_subclasses (DB_OBJLIST * subclasses);
393 static int lockhint_subclasses (SM_TEMPLATE * temp, SM_CLASS * class_);
394 static int update_class (SM_TEMPLATE * template_, MOP * classmop, int auto_res, DB_AUTH auth,
395  bool needs_hierarchy_lock);
396 static int remove_class_triggers (MOP classop, SM_CLASS * class_);
397 static int sm_drop_cascade_foreign_key (SM_CLASS * class_);
398 static char *sm_default_constraint_name (const char *class_name, DB_CONSTRAINT_TYPE type, const char **att_names,
399  const int *asc_desc);
400 
401 static int sm_load_online_index (MOP classmop, const char *constraint_name);
402 
403 static const char *sm_locate_method_file (SM_CLASS * class_, const char *function);
404 
405 #if defined (WINDOWS)
406 static void sm_method_final (void);
407 #endif
408 
409 static int sm_check_index_exist (MOP classop, char **out_shared_cons_name, DB_CONSTRAINT_TYPE constraint_type,
410  const char *constraint_name, const char **att_names, const int *asc_desc,
411  const SM_PREDICATE_INFO * filter_index, const SM_FUNCTION_INFO * func_info);
412 
413 static void sm_reset_descriptors (MOP class_);
414 
415 static bool sm_is_possible_to_recreate_constraint (MOP class_mop, const SM_CLASS * const class_,
416  const SM_CLASS_CONSTRAINT * const constraint);
417 
418 static bool sm_filter_index_pred_have_invalid_attrs (SM_CLASS_CONSTRAINT * constraint, char *class_name,
419  SM_ATTRIBUTE * old_atts, SM_ATTRIBUTE * new_atts);
420 
421 static int sm_truncate_using_delete (MOP class_mop);
422 static int sm_save_nested_view_versions (PARSER_CONTEXT * parser, DB_OBJECT * class_object, SM_CLASS * class_);
424 
425 #if 0
426 static int sm_truncate_using_destroy_heap (MOP class_mop);
427 #endif
428 
429 #if defined(CUBRID_DEBUG)
430 static void sm_print (MOP classmop);
431 #endif
432 
433 #if defined(ENABLE_UNUSED_FUNCTION)
434 static DB_OBJLIST *sm_get_all_objects (DB_OBJECT * op);
435 static TP_DOMAIN *sm_get_set_domain (MOP classop, int att_id);
436 static DB_OBJLIST *sm_query_lock (MOP classop, DB_OBJLIST * exceptions, int only, int update);
437 static DB_OBJLIST *sm_get_all_classes (int external_list);
438 static DB_OBJLIST *sm_get_base_classes (int external_list);
439 static const char *sm_get_class_name_internal (MOP op, bool return_null);
440 static const char *sm_get_class_name (MOP op);
441 static const char *sm_get_class_name_not_null (MOP op);
442 static int sm_update_trigger_cache (DB_OBJECT * class_, const char *attribute, int class_attribute, void *cache);
443 static const char *sc_current_schema_name (void);
444 static int sm_object_disk_size (MOP op);
445 static int sm_has_constraint (MOBJ classobj, SM_ATTRIBUTE_FLAG constraint);
446 static int sm_get_att_domain (MOP op, const char *name, TP_DOMAIN ** domain);
447 static const char *sm_type_name (DB_TYPE id);
448 #endif
449 static int filter_local_constraints (SM_TEMPLATE * template_, SM_CLASS * super_class);
450 static int update_fk_ref_partitioned_class (SM_TEMPLATE * ctemplate, SM_FOREIGN_KEY_INFO * fk_info, const BTID * btid,
451  const char *old_name, const char *new_name);
452 static int flatten_partition_info (SM_TEMPLATE * def, SM_TEMPLATE * flat);
454  LC_FETCH_VERSION_TYPE * force_fetch_version_type);
455 static int sm_flush_and_decache_objects_internal (MOP obj, MOP obj_class_mop, int decache);
456 
458 
459 /*
460  * sc_set_current_schema()
461  * return: NO_ERROR if successful
462  * ER_FAILED if any problem extracting name from authorization
463  *
464  * user(in) : MOP for authorization (user)
465  *
466  * Note :
467  * This function is temporary kludge to allow initial implementation
468  * of schema names. It is to be called from just one place: AU_SET_USER.
469  * Entry level SQL specifies that a schema name is equal to the
470  * <authorization user name>, so this function simply extracts the user
471  * name from the input argument, makes it lower case, and uses that name
472  * as the schema name.
473  *
474  *
475  */
476 
477 int
479 {
480  int error = ER_FAILED;
481  char *wsp_user_name;
482 
483  Current_Schema.name[0] = '\0';
484  Current_Schema.owner = user;
485  wsp_user_name = au_get_user_name (user);
486 
487  if (wsp_user_name == NULL)
488  {
489  return error;
490  }
491 
492  /* As near as I can tell, this is the most generalized */
493  /* case conversion function on our system. If it's not */
494  /* the most general, change this code accordingly. */
495  if (intl_identifier_lower (wsp_user_name, Current_Schema.name) == 0)
496  {
497  /* intl_identifier_lower always returns 0. */
498  /* However, someday it might return an error. */
499  error = NO_ERROR;
500  }
501  ws_free_string (wsp_user_name);
502 
503  /* If there's any error, it's not obvious what can be done about it here. */
504  /* Probably some code needs to be fixed in the caller: AU_SET_USER */
505  return error;
506 }
507 
508 #if defined(ENABLE_UNUSED_FUNCTION)
509 /*
510  * sc_current_schema_name() - Returns current schema name which is
511  * the default qualifier for otherwise
512  * unqualified class/vclass names
513  * return: pointer to current schema name
514  *
515  */
516 
517 static const char *
518 sc_current_schema_name (void)
519 {
520  return (const char *) &(Current_Schema.name);
521 }
522 #endif /* ENABLE_UNUSED_FUNCTION */
523 
524 /*
525  * sm_add_static_method() - Adds an element to the static link table.
526  * The name argument and the name of the function pointed to
527  * are usually the same but this is not mandatory.
528  * return: none
529  * name(in): method function name
530  * function(in): method function pointer
531  */
532 void
533 sm_add_static_method (const char *name, void (*function) ())
534 {
535  STATIC_METHOD *m, *found, *new_;
536 
537  if (name == NULL)
538  {
539  return;
540  }
541 
542  found = NULL;
543  for (m = Static_method_table; m != NULL && found == NULL; m = m->next)
544  {
545  if (strcmp (m->name, name) == 0)
546  {
547  found = m;
548  }
549  }
550  /* if found, assume we just want to change the function */
551  if (found != NULL)
552  {
553  found->function = function;
554  }
555  else
556  {
557  new_ = (STATIC_METHOD *) malloc (sizeof (STATIC_METHOD));
558  if (new_ == NULL)
559  {
561  return;
562  }
563 
564  new_->next = Static_method_table;
565  Static_method_table = new_;
566  new_->function = function;
567 
568  new_->name = (char *) malloc (strlen (name) + 1);
569  if (new_->name == NULL)
570  {
572  free (new_);
573  return;
574  }
575 
576  strcpy ((char *) new_->name, name);
577  }
578 }
579 
580 /*
581  * sm_delete_static_method() - Removes static link information for
582  * the named method function
583  * return: none
584  * name(in): method function name
585  */
586 void
587 sm_delete_static_method (const char *name)
588 {
589  STATIC_METHOD *m, *prev, *found;
590 
591  found = NULL;
592  prev = NULL;
593 
594  for (m = Static_method_table; m != NULL && found == NULL; m = m->next)
595  {
596  if (strcmp (m->name, name) == 0)
597  {
598  found = m;
599  }
600  else
601  {
602  prev = m;
603  }
604  }
605 
606  if (found == NULL)
607  {
608  return;
609  }
610 
611  if (prev == NULL)
612  {
613  Static_method_table = found->next;
614  }
615  else
616  {
617  prev->next = found->next;
618  }
619 
620  free_and_init (found->name);
621  free_and_init (found);
622 }
623 
624 /*
625  * sm_flush_static_methods() - Clear the static method table
626  */
627 
628 void
630 {
631  STATIC_METHOD *m, *next;
632 
633  for (m = Static_method_table, next = NULL; m != NULL; m = next)
634  {
635  next = m->next;
636  free_and_init (m->name);
637  free_and_init (m);
638  }
639 
640  Static_method_table = NULL;
641 }
642 
643 /*
644  * sm_find_static_method() - Searches the global static method list for
645  * the named function
646  * return: static method structure
647  * name(in): method function name
648  */
649 
650 static STATIC_METHOD *
651 sm_find_static_method (const char *name)
652 {
653  STATIC_METHOD *m, *found;
654 
655  found = NULL;
656 
658 
659  while (m != NULL && found == NULL)
660  {
661  if (strcmp (m->name, name) == 0)
662  {
663  found = m;
664  }
665  m = m->next;
666  }
667 
668  return found;
669 }
670 
671 /*
672  * sm_count_tokens() - Work function for split_loader_commands.
673  * A token is defined as any string of characters separated by
674  * whitespace. Calculate the number of tokens in the string and the
675  * maximum length of all tokens.
676  *
677  * return: number of tokens in the command string
678  * string(in): loader command string
679  * maxcharp(out): returned size of maximum token length
680  */
681 
682 static int
683 sm_count_tokens (const char *string, int *maxcharp)
684 {
685  int tokens, chars, maxchars, i;
686 
687  tokens = 0;
688  maxchars = 0;
689 
690  if (string == NULL)
691  {
692  return (tokens);
693  }
694 
695  for (i = 0; i < (int) strlen (string); i++)
696  {
697  if (char_isspace (string[i]))
698  {
699  continue;
700  }
701  tokens++;
702 
703  for (chars = 0; i < (int) strlen (string) && !char_isspace (string[i]); i++, chars++)
704  ;
705  if (chars > maxchars)
706  {
707  maxchars = chars;
708  }
709  }
710 
711  if (maxcharp != NULL)
712  {
713  *maxcharp = maxchars;
714  }
715 
716  return tokens;
717 }
718 
719 /*
720  * sm_split_loader_commands() - Takes a string containing loader commands
721  * separated by whitespace and creates an argv style array with
722  * NULL termination. This is required for the dynamic loader.
723  * return: NO_ERROR on success, non-zero for ERROR
724  * string(in): loader command string
725  * command_ptr(out): argv style array with loader commands
726  */
727 
728 static int
729 sm_split_loader_commands (const char *string, const char ***command_p)
730 {
731  int error = NO_ERROR;
732  int tokens, maxchars, i, j;
733  char *buf, *ptr;
734  const char *new_;
735  char **commands;
736 
737  commands = NULL;
738  tokens = sm_count_tokens (string, &maxchars);
739  if (!tokens)
740  {
741  goto end;
742  }
743 
744  buf = (char *) db_ws_alloc (sizeof (char) * (maxchars + 1));
745  if (buf == NULL)
746  {
747  assert (er_errid () != NO_ERROR);
748  error = er_errid ();
749  goto end;
750  }
751 
752  commands = (char **) db_ws_alloc (sizeof (char *) * (tokens + 1));
753  if (commands == NULL)
754  {
755  assert (er_errid () != NO_ERROR);
756  error = er_errid ();
757  db_ws_free (buf);
758  goto end;
759  }
760 
761  ptr = (char *) string;
762  for (i = 0; i < tokens && error == NO_ERROR; i++)
763  {
764  for (; *ptr != '\0' && char_isspace (*ptr); ptr++)
765  ;
766 
767  for (j = 0; *ptr != '\0' && !char_isspace (*ptr); ptr++, j++)
768  {
769  buf[j] = *ptr;
770  }
771  buf[j] = '\0';
772 
773  new_ = ws_copy_string (buf);
774  if (new_ != NULL)
775  {
776  commands[i] = (char *) new_;
777  }
778  else
779  {
780  assert (er_errid () != NO_ERROR);
781  error = er_errid ();
782  db_ws_free (commands);
783  db_ws_free (buf);
784 
785  return error;
786  }
787  }
788 
789  commands[i] = NULL;
790  db_ws_free (buf);
791 
792 end:
793  if (error == NO_ERROR)
794  {
795  *command_p = (const char **) commands;
796  }
797 
798  return error;
799 }
800 
801 /*
802  * sm_free_loader_commands() - Frees an array of loader commands created with
803  * split_loader_commands()
804  * return: none
805  * commands(in): argv style loader command array
806  */
807 
808 static void
809 sm_free_loader_commands (char **commands)
810 {
811  int i;
812 
813  if (commands != NULL)
814  {
815  for (i = 0; commands[i] != NULL; i++)
816  {
817  db_ws_free ((char *) commands[i]);
818  }
819  db_ws_free (commands);
820  }
821 }
822 
823 /* STATIC LINKING */
824 /*
825  * sm_free_method_links() - Free a list of temporary method link structures
826  * after dynamic linking has finished
827  * return: none
828  * links(in): list of method link structures
829  */
830 
831 static void
833 {
834  METHOD_LINK *link, *next = NULL;
835 
836  for (link = links; link != NULL; link = next)
837  {
838  next = link->next;
839  db_ws_free (link);
840  }
841 }
842 
843 /*
844  * sm_link_static_method() - Attempt to link a single method using the
845  * static method table. If a static link could not be made, construct
846  * and return a method link structure that will be used later during
847  * dynamic linking.
848  * If the method could be statically linked, set up the function
849  * pointer in the method structure and return NULL.
850  * return: NO_ERROR on success, non-zero for ERROR
851  * method(in/out): schema method structure
852  * link_ptr(out): schema method structure
853  */
854 
855 static int
857 {
858  int error = NO_ERROR;
859  STATIC_METHOD *m;
860  METHOD_LINK *link;
861 
862  link = NULL;
863 
864  if (method->signatures == NULL)
865  {
866  goto end;
867  }
868 
870  if (m != NULL)
871  {
872  /* should check for reasonable type */
874  /* put it in the cache as well */
875  method->function = (METHOD_FUNCTION) m->function;
876  }
877  else
878  {
879  /* couldn't statically link, build dynamic link state */
880  link = (METHOD_LINK *) db_ws_alloc (sizeof (METHOD_LINK));
881  if (link == NULL)
882  {
883  assert (er_errid () != NO_ERROR);
884  error = er_errid ();
885  }
886  else
887  {
888  link->next = NULL;
889  link->method = method;
890  link->namelist_index = -1;
891  }
892  }
893 end:
894  if (error == NO_ERROR)
895  {
896  *link_ptr = link;
897  }
898 
899  return error;
900 }
901 
902 /*
903  * sm_link_static_methods() - Attempts to statically link all of the methods
904  * in a class. A METHOD_LINK structure is created for every method that
905  * could not be statically linked and returned in a list. This list
906  * is used later to dynamically link the remaining methods
907  * return: NO_ERROR on success, non-zero for ERROR
908  * class(in): class with methods to be linked
909  * links_ptr(out): list of method link structures
910  */
911 
912 static int
914 {
915  int error = NO_ERROR;
916  METHOD_LINK *links, *link;
917  SM_METHOD *method;
918 
919  links = NULL;
920 
921  for (method = class_->methods; method != NULL && error == NO_ERROR; method = (SM_METHOD *) method->header.next)
922  {
923  error = sm_link_static_method (method, &link);
924  if (error == NO_ERROR)
925  {
926  if (link != NULL)
927  {
928  link->next = links;
929  links = link;
930  }
931  }
932  }
933  for (method = class_->class_methods; method != NULL && error == NO_ERROR; method = (SM_METHOD *) method->header.next)
934  {
935  error = sm_link_static_method (method, &link);
936  if (error == NO_ERROR)
937  {
938  if (link != NULL)
939  {
940  link->next = links;
941  links = link;
942  }
943  }
944  }
945 
946  if (error == NO_ERROR)
947  {
948  *links_ptr = links;
949  }
950 
951  return error;
952 }
953 
954 /* DYNAMIC LINKING */
955 /*
956  * sm_expand_method_files() - This is called prior to dynamic linking to go
957  * through all the method files for a class and expand any environment
958  * variables that may be included in the file pathnames.
959  * This expansion is delayed until link time so that changing the values of
960  * the env variables allow site specific customization of behavior.
961  * When finished, the expanded_name field in the file structures will
962  * be non-NULL if expansions were performed or will be NULL if
963  * no expansion was necessary. If no error code is returned,
964  * assume all expansions were performed. If the expansion_name field
965  * is already set, free it and recalculate the expansion.
966  *
967  * Changed to automatically supply method file extensions if they have
968  * not been specified in the schema. This is useful when databases
969  * are used in a heterogeneous environment, eliminating the need to
970  * have multiple versions of the schema for each platform. This will
971  * handle the most common cases, for really radical platforms, a more
972  * general mechanism may be necessary
973  * return: NO_ERROR on success, non-zero for ERROR
974  * files(in/out): list of method files
975  */
976 static int
978 {
979  char filebuf[PATH_MAX];
980  int error = NO_ERROR;
981  SM_METHOD_FILE *f;
982 
983  for (f = files; f != NULL && error == NO_ERROR; f = f->next)
984  {
985  if (f->expanded_name != NULL)
986  {
988  f->expanded_name = NULL;
989  }
990  if (envvar_expand (f->name, filebuf, PATH_MAX) == NO_ERROR)
991  {
992  /* check for automatic extensions, this is determined by checking to see if there are no '.' characters in
993  * the name, could be more complicated. Use intl_mbs_chr just in case we need to be dealing with wide
994  * strings. */
995  if (intl_mbs_chr (filebuf, WC_PERIOD) == NULL)
996  {
997  strcat (filebuf, method_file_extension);
998  }
999 
1000  /* If the name we've been manipulating is different then the original name, copy it and use it later. */
1001  if (strcmp (filebuf, f->name) != 0)
1002  {
1003  f->expanded_name = ws_copy_string (filebuf);
1004  if (f->expanded_name == NULL)
1005  {
1006  assert (er_errid () != NO_ERROR);
1007  error = er_errid (); /* out of memory */
1008  }
1009  }
1010  }
1011  else
1012  {
1013  /* could stop at the first one but just go through them all */
1014  error = ER_SM_INVALID_METHOD_ENV;
1015  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 1, filebuf);
1016  }
1017  }
1018 
1019  return error;
1020 }
1021 
1022 /*
1023  * sm_build_function_nlist() - Builds an nlist function name array from a list of
1024  * method link structures. The links are filtered so that only unique
1025  * names will be in the nlist array. The links structures are
1026  * modified as a side effect so that their namelist_index is set to the
1027  * index in the nlist array where the information for that function
1028  * will be found.
1029  * The nlist array must be freed with free_function_nlist
1030  * return: NO_ERROR on success, non-zero for ERROR
1031  * links(in): list of method links
1032  * nlist_ptr(out): nlist array
1033  */
1034 
1035 #if !defined(WINDOWS)
1036 
1037 static int
1038 sm_build_function_nlist (METHOD_LINK * links, struct nlist **nlist_p)
1039 {
1040  int error = NO_ERROR;
1041  struct nlist *namelist;
1042  METHOD_LINK *ml;
1043  const char **fnames;
1044  const char *new_;
1045  int i, nlinks, index;
1046  char fname[SM_MAX_IDENTIFIER_LENGTH + 2];
1047 
1048  namelist = NULL;
1049  if (links == NULL)
1050  {
1051  goto end;
1052  }
1053 
1054  /* allocation & initialize an array for building the unique name list */
1055  nlinks = WS_LIST_LENGTH (links);
1056  fnames = (const char **) db_ws_alloc (sizeof (char *) * nlinks);
1057  if (fnames == NULL)
1058  {
1059  assert (er_errid () != NO_ERROR);
1060  error = er_errid ();
1061  }
1062  else
1063  {
1064  for (i = 0; i < nlinks; i++)
1065  {
1066  fnames[i] = NULL;
1067  }
1068 
1069  /* populate the unique name array */
1070  index = 0;
1071  for (ml = links; ml != NULL && error == NO_ERROR; ml = ml->next)
1072  {
1073  ml->namelist_index = -1;
1074  if (ml->method->signatures->function_name != NULL)
1075  {
1076  /* mangle the name as appropriate, sun wants prepended '_', ibm doesn't */
1077 #if defined(sun) && !defined(SOLARIS)
1078  sprintf (fname, "_%s", ml->method->signatures->function_name);
1079 #else /* sun && !SOLARIS */
1080  sprintf (fname, "%s", ml->method->signatures->function_name);
1081 #endif /* sun && !SOLARIS */
1082  /* see if it is already in the nlist array */
1083  for (i = 0; i < index && ml->namelist_index == -1; i++)
1084  {
1085  if (strcmp (fname, fnames[i]) == 0)
1086  {
1087  ml->namelist_index = i;
1088  }
1089  }
1090  /* add it if not already there */
1091  if (ml->namelist_index == -1)
1092  {
1093  ml->namelist_index = index;
1094  new_ = ws_copy_string ((const char *) fname);
1095  if (new_ != NULL)
1096  {
1097  fnames[index++] = new_;
1098  }
1099  else
1100  {
1101  assert (er_errid () != NO_ERROR);
1102  error = er_errid ();
1103  }
1104  }
1105  }
1106  }
1107 
1108  if (error == NO_ERROR)
1109  {
1110  /* build an actual nlist structure from the unique name array */
1111  namelist = (struct nlist *) db_ws_alloc (sizeof (struct nlist) * (index + 1));
1112  if (namelist == NULL)
1113  {
1114  assert (er_errid () != NO_ERROR);
1115  error = er_errid ();
1116  }
1117  else
1118  {
1119  for (i = 0; i < index; i++)
1120  {
1121  namelist[i].n_name = (char *) fnames[i];
1122  }
1123  namelist[index].n_name = NULL;
1124 
1125  }
1126  }
1127  /* don't need this anymore */
1128  db_ws_free (fnames);
1129  }
1130 end:
1131  if (error == NO_ERROR)
1132  {
1133  *nlist_p = namelist;
1134  }
1135 
1136  return error;
1137 }
1138 
1139 /*
1140  * sm_free_function_nlist() - Frees an nlist array that was allocated with
1141  * build_function_nlist()
1142  * return: none
1143  * namelist(in): nlist array
1144  */
1145 
1146 static void
1147 sm_free_function_nlist (struct nlist *namelist)
1148 {
1149  int i;
1150 
1151  if (namelist != NULL)
1152  {
1153  for (i = 0; namelist[i].n_name != NULL; i++)
1154  {
1155  db_ws_free (namelist[i].n_name);
1156  }
1157  db_ws_free (namelist);
1158  }
1159 }
1160 #endif /* !WINDOWS */
1161 
1162 /*
1163  * sm_link_dynamic_methods() - Call the dynamic linker to resolve any function
1164  * references that could not be statically linked. The static linking phase
1165  * produces a list of METHOD_LINK structures for the methods that could
1166  * not be linked. We use this list here to build the control structures
1167  * for the dynamic loader.
1168  * The files array has the names of the method files specified in the
1169  * schema. The commands array has the loader commands.
1170  * This can be used to link methods for several classes
1171  * return: NO_ERROR on success, non-zero for ERROR
1172  * links(in/out): list of method link structures
1173  * files(in): array of method files (NULL terminated)
1174  * commands(in): array of loader commands (NULL terminated)
1175  */
1176 
1177 #if defined (sun) || defined(SOLARIS) || defined(LINUX) || defined(AIX)
1178 #if defined(SOLARIS) || defined(LINUX) || defined(AIX)
1179 static int
1180 sm_link_dynamic_methods (METHOD_LINK * links, const char **files)
1181 #else /* SOLARIS || LINUX || AIX */
1182 static int
1183 sm_link_dynamic_methods (METHOD_LINK * links, const char **files, const char **commands)
1184 #endif /* SOLARIS || LINUX || AIX */
1185 {
1186  int error = NO_ERROR;
1187  METHOD_LINK *ml;
1188  struct nlist *namelist, *nl;
1189  const char *msg;
1190  int status;
1191 
1192  error = sm_build_function_nlist (links, &namelist);
1193  if (error == NO_ERROR && namelist != NULL)
1194  {
1195  /* invoke the linker */
1196 #if defined(SOLARIS) || defined(LINUX) || defined(AIX)
1197  status = dl_load_object_module (files, &msg);
1198 #else /* SOLARIS || LINUX || AIX */
1199  status = dl_load_object_module (files, &msg, commands);
1200 #endif /* SOLARIS || LINUX || AIX */
1201  if (status)
1202  {
1203  assert (er_errid () != NO_ERROR);
1204  error = er_errid ();
1205  }
1206  else
1207  {
1208  /* resolve functions */
1209  status = dl_resolve_object_symbol (namelist);
1210  if (status == -1)
1211  {
1212  assert (er_errid () != NO_ERROR);
1213  error = er_errid ();
1214  }
1215  else
1216  {
1217  /* what does this accomplish ? */
1218  if (status)
1219  {
1220  error = ER_SM_UNRESOLVED_METHODS;
1221  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 1, status);
1222  }
1223 
1224  /* now link the methods, signal and return an error when one is encountered but go ahead and try to link
1225  * whatever is there */
1226  for (ml = links; ml != NULL; ml = ml->next)
1227  {
1228  nl = &namelist[ml->namelist_index];
1229  if (nl->n_type == (N_TEXT | N_EXT))
1230  {
1231  ml->method->signatures->function = (METHOD_FUNCTION) nl->n_value;
1232  ml->method->function = (METHOD_FUNCTION) nl->n_value;
1233  }
1234  else
1235  {
1236  error = ER_SM_UNRESOLVED_METHOD;
1237  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 1, nl->n_name);
1238  }
1239  }
1240  }
1241  }
1242  sm_free_function_nlist (namelist);
1243  }
1244 
1245  return error;
1246 }
1247 
1248 #elif defined(HPUX)
1249 static int
1250 sm_link_dynamic_methods (METHOD_LINK * links, const char **files, const char **commands)
1251 {
1252  int error = NO_ERROR;
1253  METHOD_LINK *ml;
1254  struct nlist *namelist, *nl;
1255  const char *msg;
1256  int status;
1257 
1258  error = sm_build_function_nlist (links, &namelist);
1259  if (error == NO_ERROR && namelist != NULL)
1260  {
1261 
1262  /* invoke the linker */
1263  status = dl_load_object_module (files, &msg, commands);
1264  if (status)
1265  {
1266  assert (er_errid () != NO_ERROR);
1267  error = er_errid ();
1268  }
1269  else
1270  {
1271  /* resolve functions */
1272  status = dl_resolve_object_symbol (namelist);
1273  if (status == -1)
1274  {
1275  assert (er_errid () != NO_ERROR);
1276  error = er_errid ();
1277  }
1278  else
1279  {
1280  /* what does this accomplish ? */
1281  if (status)
1282  {
1283  error = ER_SM_UNRESOLVED_METHODS;
1284  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 1, status);
1285  }
1286 
1287  /* now link the methods, signal and return an error when one is encountered but go ahead and try to link
1288  * whatever is there */
1289  for (ml = links; ml != NULL; ml = ml->next)
1290  {
1291  nl = &namelist[ml->namelist_index];
1292  if (nl->n_type == (ST_ENTRY))
1293  {
1294  ml->method->signatures->function = (METHOD_FUNCTION) nl->n_value;
1295  ml->method->function = (METHOD_FUNCTION) nl->n_value;
1296  }
1297  else
1298  {
1299  error = ER_SM_UNRESOLVED_METHOD;
1300  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 1, nl->n_name);
1301  }
1302  }
1303  }
1304  }
1305  sm_free_function_nlist (namelist);
1306  }
1307 
1308  return error;
1309 }
1310 #elif defined(WINDOWS)
1311 
1312 /* DYNAMIC LINK LIBRARY MAINTENANCE */
1313 /* Structure that maintains a global list of DLL's that have been opened */
1314 typedef struct pc_dll
1315 {
1316  struct pc_dll *next;
1317  HINSTANCE handle;
1318  char *name;
1319 } PC_DLL;
1320 
1321 /* Global list of opened DLL's */
1322 static PC_DLL *pc_dll_list = NULL;
1323 
1324 /*
1325  * load_dll() - This returns a Windows library handle for the named DLL.
1326  * It will first look on our list of opened libraries, if one is not found,
1327  * it asks windows to load it and adds it to the list.
1328  * Only called by the PC version of link_dynamic_methods
1329  * return: library handle
1330  * name(in): library name
1331  */
1332 
1333 static HINSTANCE
1334 load_dll (const char *name)
1335 {
1336  PC_DLL *dll;
1337  HINSTANCE handle;
1338 
1339  handle = NULL;
1340 
1341  /* first see if we've already loaded this */
1342  for (dll = pc_dll_list; dll != NULL && strcmp (name, dll->name) != 0; dll = dll->next);
1343 
1344  if (dll != NULL)
1345  {
1346  handle = dll->handle;
1347  }
1348  else
1349  {
1350  /* never been loaded, ask windows to go find it */
1351 
1352  handle = LoadLibrary (name);
1353  if (handle != NULL)
1354  {
1355  /* successfully loaded, add to the list */
1356 
1357  dll = (PC_DLL *) malloc (sizeof (PC_DLL) + strlen (name) + 2);
1358  if (dll == NULL)
1359  {
1360  /* memory problems */
1361  FreeLibrary (handle);
1362  handle = NULL;
1363  }
1364  else
1365  {
1366  dll->next = pc_dll_list;
1367  pc_dll_list = dll;
1368  dll->handle = handle;
1369  dll->name = (char *) dll + sizeof (PC_DLL);
1370  strcpy (dll->name, name);
1371  }
1372  }
1373  }
1374 
1375  return handle;
1376 }
1377 
1378 /*
1379  * sm_method_final() - Called by sm_final() to clean up state required by
1380  * dynamic linking. This goes through the global DLL list and closes all
1381  * the DLL's we used during this session
1382  */
1383 
1384 void
1385 sm_method_final (void)
1386 {
1387  PC_DLL *dll, *next;
1388 
1389  for (dll = pc_dll_list, next = NULL; dll != NULL; dll = next)
1390  {
1391  next = dll->next;
1392  FreeLibrary (dll->handle);
1393  free_and_init (dll);
1394  }
1395 
1396  pc_dll_list = NULL;
1397 }
1398 
1399 /*
1400  * link_dynamic_methods()
1401  * return: NO_ERROR on success, non-zero for ERROR
1402  * links(in):
1403  * files(in):
1404  * commands(in):
1405  */
1406 static int
1407 sm_link_dynamic_methods (METHOD_LINK * links, const char **files, const char **commands)
1408 {
1409  char filebuf[PATH_MAX];
1410  char fname[SM_MAX_IDENTIFIER_LENGTH + 2];
1411  int error = NO_ERROR;
1412  METHOD_LINK *ml;
1413  const char *file;
1414  HINSTANCE libhandle;
1415  FARPROC func;
1416  int i, j;
1417 
1418  if (links != NULL)
1419  {
1420  /* Load the DLL associated with each file in the files array and try to locate each method in them. If there are
1421  * errors loading a DLL, could continue assuming that Windows has had a chance to popup a message window. */
1422  for (i = 0; files[i] != NULL && error == NO_ERROR; i++)
1423  {
1424  file = files[i];
1425  /* Should have a "method name too long" error but I don't want to introduce one right now. If we have
1426  * problems with a particular DLL file, just ignore it and attempt to get the methods from the other files. */
1427  if (strlen (file) + 3 < PATH_MAX)
1428  {
1429  /* massage the file extension so that it has .dll */
1430  strcpy (filebuf, file);
1431 
1432  for (j = strlen (file) - 1; j > 0 && filebuf[j] != '.'; j--)
1433  ;
1434 
1435  if (j > 0)
1436  {
1437  strcpy (&filebuf[j], ".dll");
1438  }
1439  else
1440  {
1441  /* its a file without an extension, hmm, assume that it needs .dll appended to the end */
1442  strcat (filebuf, ".dll");
1443  }
1444 
1445  /* Ask Windows to open the DLL, example for GetProcAddress uses SetErrorMode to turn off the "file not
1446  * found" boxes, we want these though. */
1447  libhandle = load_dll (filebuf);
1448  if (libhandle != NULL)
1449  {
1450  /* look for each unresolved method in this file */
1451  for (ml = links; ml != NULL; ml = ml->next)
1452  {
1453  /* Formerly only did the GetProcAddress if the signature's function pointer was NULL, this
1454  * prevents us from getting new addresses if the DLL changes. Hopefully this isn't very
1455  * expensive. if (ml->method->signatures->function == NULL) { */
1456  /* its possible that the name they've given for the function name matches exactly the name in the
1457  * export list of the DLL, in that case, always try the given name first, if that fails, assume
1458  * that they've left off the initial underscore necessary for DLL function references and add one
1459  * automatically. */
1460  strcpy (fname, ml->method->signatures->function_name);
1461  func = GetProcAddress (libhandle, fname);
1462  if (func == NULL)
1463  {
1464  /* before giving up, try prefixing an underscore */
1465  strcpy (fname, "_");
1466  strcat (fname, ml->method->signatures->function_name);
1467  func = GetProcAddress (libhandle, fname);
1468  }
1469  if (func != NULL)
1470  {
1471  /* found one */
1472  ml->method->signatures->function = (METHOD_FUNCTION) func;
1473  ml->method->function = (METHOD_FUNCTION) func;
1474  }
1475  }
1476  }
1477  /* else, could abort now but lets look in the other files to see if our methods all get resolved */
1478  }
1479  }
1480 
1481  /* now all the files have been processed, check to see if we couldn't resolve any methods */
1482 
1483  for (ml = links; ml != NULL && error == NO_ERROR; ml = ml->next)
1484  {
1485  if (ml->method->function == NULL)
1486  {
1487  error = ER_SM_UNRESOLVED_METHOD;
1489  }
1490  }
1491 
1492  }
1493 
1494  return (error);
1495 }
1496 
1497 #else /* sun || SOLARIS || LINUX */
1498 #error "Unknown machine type for link_dynamic_methods"
1499 #endif /* sun || SOLARIS || LINUX */
1500 
1501 /*
1502  * sm_file_extension() - Hack to check file extensions, used by dynamic_link_class
1503  * to sort .a files apart from the method object files
1504  * return: non-zero if the path has the given file extension
1505  * path(in):
1506  * ext(in):
1507  */
1508 
1509 static int
1510 sm_file_extension (const char *path, const char *ext)
1511 {
1512  DB_C_INT plen, elen;
1513 
1514  plen = strlen (path);
1515  elen = strlen (ext);
1516 
1517  return (plen > elen) && (strcmp (&(path[plen - elen]), ext) == 0);
1518 }
1519 
1520 /*
1521  * sm_dynamic_link_class() - Perform dynamic linking for a class.
1522  * Tries to resolve the methods in the METHOD_LINK list which could not be
1523  * resolved through static linking.
1524  * Work function for sm_link_methods & sm_link_method.
1525  * return: NO_ERROR on success, non-zero for ERROR
1526  * class_(in/out): class requiring linking
1527  * links(in): unresolved method links
1528  */
1529 
1530 static int
1532 {
1533  int error = NO_ERROR;
1534  SM_METHOD_FILE *files = NULL, *file = NULL;
1535  char **names = NULL, **sorted_names = NULL, **commands = NULL;
1536  int i, nfiles, psn;
1537 
1538  if (links == NULL)
1539  {
1540  return error;
1541  }
1542 
1543  files = class_->method_files;
1544  nfiles = ws_list_length ((DB_LIST *) files);
1545 
1546  names = (char **) db_ws_alloc (sizeof (char *) * (nfiles + 1));
1547  if (names == NULL)
1548  {
1549  assert (er_errid () != NO_ERROR);
1550  error = er_errid ();
1551  return error;
1552  }
1553 
1554  sorted_names = (char **) db_ws_alloc (sizeof (char *) * (nfiles + 1));
1555  if (sorted_names == NULL)
1556  {
1557  assert (er_errid () != NO_ERROR);
1558  error = er_errid ();
1559  db_ws_free (names);
1560  return error;
1561  }
1562 
1563  error = sm_expand_method_files (files);
1564  if (error != NO_ERROR)
1565  {
1566  db_ws_free (sorted_names);
1567  db_ws_free (names);
1568  return (error);
1569 
1570  }
1571  for (file = files, i = 0; file != NULL; file = file->next, i++)
1572  {
1573  if (file->expanded_name != NULL)
1574  {
1575  names[i] = (char *) file->expanded_name;
1576  }
1577  else
1578  {
1579  names[i] = (char *) file->name;
1580  }
1581  }
1582  names[nfiles] = NULL;
1583 
1584  /* Hack, if we have any Unix library (.a) files in the file list, put them at the end. Useful if libraries are used
1585  * for method file support, particularly, when inherited. Try to keep the files int the same order otherwise. */
1586  psn = 0;
1587  for (i = 0; i < nfiles; i++)
1588  {
1589  if (!sm_file_extension (names[i], ".a"))
1590  {
1591  sorted_names[psn++] = names[i];
1592  }
1593  }
1594  for (i = 0; i < nfiles; i++)
1595  {
1596  if (sm_file_extension (names[i], ".a"))
1597  {
1598  sorted_names[psn++] = names[i];
1599  }
1600  }
1601  sorted_names[nfiles] = NULL;
1602  error = sm_split_loader_commands (class_->loader_commands, (const char ***) &commands);
1603  if (error == NO_ERROR)
1604  {
1605 #if defined(SOLARIS) || defined(LINUX) || defined(AIX)
1606  error = sm_link_dynamic_methods (links, (const char **) sorted_names);
1607 #else /* SOLARIS || LINUX || AIX */
1608  error = sm_link_dynamic_methods (links, (const char **) sorted_names, (const char **) commands);
1609 #endif /* SOLARIS || LINUX || AIX */
1610  if (commands != NULL)
1611  {
1612  sm_free_loader_commands (commands);
1613  }
1614 
1615  /* ONLY set this after we have tried to dynamically link the class */
1616  if (error == NO_ERROR)
1617  {
1618  class_->methods_loaded = 1;
1619  }
1620  }
1621 
1622  db_ws_free (sorted_names);
1623  db_ws_free (names);
1624 
1625  return error;
1626 }
1627 
1628 /* FUNCTIONS */
1629 /*
1630  * sm_link_methods() - Links the method functions for a class.
1631  * First tries to use static linking and then uses dynamic linking
1632  * for the methods that could not be statically linked
1633  * return: NO_ERROR on success, non-zero for ERROR
1634  * class(in): class with methods to link
1635  */
1636 
1637 static int
1639 {
1640  int error = NO_ERROR;
1641  METHOD_LINK *links;
1642 
1643  if (class_->methods_loaded)
1644  {
1645  return NO_ERROR;
1646  }
1647 
1648  /* first link through the static table */
1649  error = sm_link_static_methods (class_, &links);
1650  if (error == NO_ERROR)
1651  {
1652  /* if there are unresolved references, use the dynamic loader */
1653  if (links != NULL)
1654  {
1655  error = sm_dynamic_link_class (class_, links);
1656  sm_free_method_links (links);
1657  }
1658  }
1659 
1660  return error;
1661 }
1662 
1663 /*
1664  * sm_link_method() - Link a single method.
1665  * This will first try to statically link the method, while we're at it,
1666  * statically link all methods.
1667  * If the link fails, try dynamic linking. Note that this is different
1668  * than calling sm_link_methods (to link all methods) because it
1669  * will only invoke the dynamic loader if the desired method could not
1670  * be statically linked. sm_link_static_methods will dynamic link
1671  * if ANY methods in the class could not be statically linked.
1672  * Note that this may return an error yet still have linked the
1673  * requested function
1674  * return: NO_ERROR on success, non-zero for ERROR
1675  * class(in): class with method
1676  * method(in): method to link
1677  */
1678 
1679 int
1680 sm_link_method (SM_CLASS * class_, SM_METHOD * method)
1681 {
1682  int error = NO_ERROR;
1683  METHOD_LINK *links;
1684 
1685  if (class_->methods_loaded)
1686  {
1687  return NO_ERROR;
1688  }
1689 
1690  /* first link through the static table */
1691  error = sm_link_static_methods (class_, &links);
1692  if (error == NO_ERROR)
1693  {
1694  if (links != NULL)
1695  {
1696  /* only dynamic link if the desired method was not resolved */
1697  if (method->function == NULL)
1698  {
1699  error = sm_dynamic_link_class (class_, links);
1700  }
1701  sm_free_method_links (links);
1702  }
1703  }
1704 
1705  return error;
1706 }
1707 
1708 /*
1709  * sm_force_method_link() - Called to force a method reload for a class.
1710  * Note that the class is passed in as an object here
1711  * return: NO_ERROR on success, non-zero for ERROR
1712  * obj(in): class object
1713  */
1714 
1715 int
1717 {
1718  int error = NO_ERROR;
1719  SM_CLASS *class_;
1720 
1721  if (obj == NULL)
1722  {
1723  return NO_ERROR;
1724  }
1725 
1726  error = au_fetch_class (obj, &class_, AU_FETCH_READ, AU_SELECT);
1727  if (error == NO_ERROR)
1728  {
1729  class_->methods_loaded = 0;
1730  error = sm_link_methods (class_);
1731  }
1732 
1733  return error;
1734 }
1735 
1736 /*
1737  * sm_prelink_methods() - Used to link the methods for a set of classes
1738  * at one time. Since dynamic linking can be expensive, this avoids repeated
1739  * links for each class
1740  * return: NO_ERROR on success, non-zero for ERROR
1741  * classes(in): list of class objects
1742  */
1743 
1744 int
1746 {
1747  int error = NO_ERROR;
1748  DB_OBJLIST *cl;
1749  SM_METHOD_FILE *f;
1750  SM_CLASS *class_;
1751  char **names;
1752  DB_NAMELIST *filenames, *name;
1753  int nfiles, i;
1754  METHOD_LINK *total_links, *links;
1755 
1756  filenames = NULL;
1757  total_links = NULL;
1758 
1759  /* build link structures for all classes */
1760  for (cl = classes; cl != NULL && error == NO_ERROR; cl = cl->next)
1761  {
1762  /* ignore authorization errors here, what happens if the transaction is aborted ??? */
1763  if (au_fetch_class (cl->op, &class_, AU_FETCH_READ, AU_EXECUTE) != NO_ERROR)
1764  {
1765  continue;
1766  }
1767  /* Ignore this if the class has already been fully linked */
1768 
1769  if (class_->methods_loaded)
1770  {
1771  continue;
1772  }
1773 
1774  /* first link through the static table */
1775  error = sm_link_static_methods (class_, &links);
1776  if (error != NO_ERROR)
1777  {
1778  continue;
1779  }
1780  /* if there are unresolved references, use the dynamic loader */
1781  if (links == NULL)
1782  {
1783  continue;
1784  }
1785 
1786  error = sm_expand_method_files (class_->method_files);
1787  if (error != NO_ERROR)
1788  {
1789  continue;
1790  }
1791 
1792  /* NEED TO BE DETECTING MEMORY ALLOCATION FAILURES IN THE nlist LIBRARY FUNCTIONS ! */
1793 
1794  /* add the files for this class */
1795  for (f = class_->method_files; f != NULL && !error; f = f->next)
1796  {
1797  if (f->expanded_name != NULL)
1798  {
1799  error = nlist_append (&filenames, f->expanded_name, NULL, NULL);
1800  }
1801  else
1802  {
1803  error = nlist_append (&filenames, f->name, NULL, NULL);
1804  }
1805  }
1806 
1807  if (!error)
1808  {
1809  /* put the links on the combined list */
1810  WS_LIST_APPEND (&total_links, links);
1811  }
1812  else
1813  {
1814  db_ws_free (links);
1815  }
1816 
1817  /* will need to have a composite list of loader commands !! */
1818  }
1819 
1820  /* proceed only if we have references that haven't already been statically linked */
1821  if (error == NO_ERROR && total_links != NULL)
1822  {
1823  /* build a name array for dl_load_object_module */
1824  nfiles = ws_list_length ((DB_LIST *) filenames);
1825  names = (char **) db_ws_alloc (sizeof (char *) * (nfiles + 1));
1826  if (names == NULL)
1827  {
1828  assert (er_errid () != NO_ERROR);
1829  error = er_errid ();
1830  }
1831  else
1832  {
1833  for (i = 0, name = filenames; name != NULL; name = name->next, i++)
1834  {
1835  names[i] = (char *) name->name;
1836  }
1837  names[nfiles] = NULL;
1838 
1839  /* need to have commands here ! */
1840 #if defined(SOLARIS) || defined(LINUX) || defined(AIX)
1841  error = sm_link_dynamic_methods (total_links, (const char **) names);
1842 #else /* SOLARIS || LINUX || AIX */
1843  error = sm_link_dynamic_methods (total_links, (const char **) names, NULL);
1844 #endif /* SOLARIS || LINUX || AIX */
1845  db_ws_free (names);
1846  }
1847  }
1848 
1849  /* mark the classes as loaded, don't do this if there were errors */
1850  if (error == NO_ERROR)
1851  {
1852  for (cl = classes; cl != NULL; cl = cl->next)
1853  {
1854  if (au_fetch_class (cl->op, &class_, AU_FETCH_READ, AU_EXECUTE) == NO_ERROR)
1855  {
1856  class_->methods_loaded = 1;
1857  }
1858  }
1859  }
1860 
1861  nlist_free (filenames);
1862  sm_free_method_links (total_links);
1863 
1864  return error;
1865 }
1866 
1867 /*
1868  * sm_locate_method_file() - Search a class' list of method files and
1869  * find which one contains a particular implementation function.
1870  * Uses the Sun OS "nlist" facility. This may not be portable
1871  * return: method file name
1872  * class(in): class to search
1873  * function(in): method function name
1874  */
1875 
1876 const char *
1877 sm_locate_method_file (SM_CLASS * class_, const char *function)
1878 {
1879  /*
1880  * DO NOT use nlist() because of installation problems. - elf library linking error on some Linux platform */
1881  return NULL;
1882 #if 0
1883 #if defined(WINDOWS)
1884  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_PC_UNIMPLEMENTED, 1, "sm_locate_method_file");
1885  return NULL;
1886 #else /* WINDOWS */
1887  struct nlist nl[2];
1888  SM_METHFILE *files;
1889  const char *found;
1890  int status;
1891  char fname[SM_MAX_IDENTIFIER_LENGTH + 2];
1892  const char *filename;
1893 
1894  found = NULL;
1895 
1896  /* machine dependent name mangling */
1897 #if defined(_AIX)
1898  sprintf (fname, "%s", function);
1899 #else /* _AIX */
1900  sprintf (fname, "_%s", function);
1901 #endif /* _AIX */
1902 
1903  nl[0].n_name = fname;
1904  nl[1].n_name = NULL;
1905 
1906  /* if the class hasn't been dynamically linked, expand the method files */
1907  if (class->methods_loaded || sm_expand_method_files (class->method_files) == NO_ERROR)
1908  {
1909 
1910  for (files = class->method_files; files != NULL && found == NULL; files = files->next)
1911  {
1912  if (files->expanded_name != NULL)
1913  {
1914  filename = files->expanded_name;
1915  }
1916  else
1917  {
1918  filename = files->name;
1919  }
1920 
1921  status = nlist (filename, &nl[0]);
1922  if (nl[0].n_type != 0)
1923  {
1924  found = filename;
1925  }
1926  }
1927  }
1928 
1929  return (found);
1930 #endif /* WINDOWS */
1931 #endif /* 0 */
1932 }
1933 
1934 /*
1935  * sm_get_method_source_file() - This is an experimental function for
1936  * the initial browser. It isn't guaranteed to work in all cases.
1937  * It will attempt to locate the .c file that contains the source for
1938  * a method implementation.
1939  * There isn't any way that this can be determined for certain, what it
1940  * does now is find the .o file that contains the implementation function
1941  * and assume that a .c file exists in the same directory that contains
1942  * the source. This will be true in almost all of the current cases
1943  * but cannot be relied upon. In the final version, there will need
1944  * to be some form of checking/checkout procedure so that the method
1945  * source can be stored within the database
1946  * return: C string
1947  * class(in): class or instance
1948  * method(in): method name
1949  */
1950 
1951 char *
1952 sm_get_method_source_file (MOP obj, const char *name)
1953 {
1954 #if defined(WINDOWS)
1955  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_PC_UNIMPLEMENTED, 1, "sm_get_method_source_file");
1956  return NULL;
1957 #else /* WINDOWS */
1958  SM_CLASS *class_;
1959  SM_METHOD *method;
1960  const char *ofile;
1961  char *cfile;
1962  const char *const_cfile;
1963  int len;
1964 
1965  cfile = NULL;
1966  if (au_fetch_class (obj, &class_, AU_FETCH_READ, AU_SELECT) != NO_ERROR)
1967  {
1968  return NULL;
1969  }
1970  method = classobj_find_method (class_, name, 0);
1971 
1972  if (method != NULL && method->signatures != NULL)
1973  {
1974  ofile = sm_locate_method_file (class_, method->signatures->function_name);
1975  if (ofile == NULL)
1976  {
1977  return cfile;
1978  }
1979 
1980  len = strlen (ofile);
1981  if (len <= 2)
1982  {
1983  return cfile;
1984  }
1985  if (ofile[len - 1] == 'o' && ofile[len - 2] == '.')
1986  {
1987  /* noise to prevent const conversion warnings */
1988  const_cfile = ws_copy_string (ofile);
1989  cfile = (char *) const_cfile;
1990  cfile[len - 1] = 'c';
1991  }
1992  }
1993 
1994  return cfile;
1995 #endif /* WINDOWS */
1996 }
1997 
1998 
1999 /*
2000  * sm_init() - Called during database restart.
2001  * Setup the global variables that contain the root class OID and HFID.
2002  * Also initialize the descriptor list
2003  * return: none
2004  * rootclass_oid(in): OID of root class
2005  * rootclass_hfid(in): heap file of root class
2006  */
2007 
2008 void
2009 sm_init (OID * rootclass_oid, HFID * rootclass_hfid)
2010 {
2011  sm_Root_class_mop = ws_mop (rootclass_oid, NULL);
2012 
2013  COPY_OID (oid_Root_class_oid, ws_oid (sm_Root_class_mop));
2014 
2015  OID_SET_NULL (&(sm_Root_class.header.ch_rep_dir)); /* is dummy */
2016 
2017  sm_Root_class.header.ch_heap.vfid.volid = rootclass_hfid->vfid.volid;
2018  sm_Root_class.header.ch_heap.vfid.fileid = rootclass_hfid->vfid.fileid;
2019  sm_Root_class.header.ch_heap.hpgid = rootclass_hfid->hpgid;
2020 
2021  sm_Root_class_hfid = &sm_Root_class.header.ch_heap;
2022 
2023  sm_Descriptors = NULL;
2024 }
2025 
2026 /*
2027  * sm_create_root() - Called when the database is first created.
2028  * Sets up the root class globals, used later when the root class
2029  * is flushed to disk
2030  * return: none
2031  * rootclass_oid(in): OID of root class
2032  * rootclass_hfid(in): heap file of root class
2033  */
2034 
2035 void
2036 sm_create_root (OID * rootclass_oid, HFID * rootclass_hfid)
2037 {
2038  sm_Root_class.header.ch_obj_header.chn = 0;
2039  sm_Root_class.header.ch_type = SM_META_ROOT;
2040  sm_Root_class.header.ch_name = (char *) sm_Root_class_name;
2041 
2042  OID_SET_NULL (&(sm_Root_class.header.ch_rep_dir)); /* is dummy */
2043 
2044  sm_Root_class.header.ch_heap.vfid.volid = rootclass_hfid->vfid.volid;
2045  sm_Root_class.header.ch_heap.vfid.fileid = rootclass_hfid->vfid.fileid;
2046  sm_Root_class.header.ch_heap.hpgid = rootclass_hfid->hpgid;
2047  sm_Root_class_hfid = &sm_Root_class.header.ch_heap;
2048 
2049  /* Sets up sm_Root_class_mop and Rootclass_oid */
2050  locator_add_root (rootclass_oid, (MOBJ) (&sm_Root_class));
2051 }
2052 
2053 /*
2054  * sm_free_resident_classes_virtual_query_cache () - free virual query cache of resident classes
2055  * return: none
2056  */
2057 static void
2059 {
2060  SM_CLASS *class_;
2061  DB_OBJLIST *cl;
2062 
2063  /* go through the resident class list and free anything attached to the class that wasn't allocated in the workspace,
2064  * this is only the virtual_query_cache at this time */
2065  for (cl = ws_Resident_classes; cl != NULL; cl = cl->next)
2066  {
2067  class_ = (SM_CLASS *) cl->op->object;
2068  if (class_ != NULL && class_->virtual_query_cache != NULL)
2069  {
2071  class_->virtual_query_cache = NULL;
2072  }
2073  }
2074 }
2075 
2076 /*
2077  * sm_final() - Called during the shutdown sequence
2078  */
2079 
2080 void
2082 {
2083  SM_DESCRIPTOR *d, *next;
2084 
2085 #if defined(WINDOWS)
2086  /* unload any DLL's we may have opened for methods */
2087  sm_method_final ();
2088 #endif /* WINDOWS */
2089 
2090  /* If there are any remaining descriptors it represents a memory leak in the application. Should be displaying
2091  * warning messages here ! */
2092 
2093  for (d = sm_Descriptors, next = NULL; d != NULL; d = next)
2094  {
2095  next = d->next;
2096  sm_free_descriptor (d);
2097  }
2098 
2100 }
2101 
2102 /*
2103  * sm_transaction_boundary() - This is called by tm_commit() and tm_abort()
2104  * to inform the schema manager that a transaction boundary has been crossed.
2105  * If the commit-flag is non-zero it indicates that we've committed
2106  * the transaction.
2107  * We used to call sm_bump_local_schema_version directly from the tm_ functions.
2108  * Now that we have more than one thing to do however, start
2109  * encapsulating them in a module specific transaction boundary handler
2110  * so we don't have to keep modifying transaction_cl.c
2111  */
2112 
2113 void
2115 {
2116  /* reset any outstanding descriptor caches */
2118 
2119  /* free view cache */
2121 
2122  /* Could be resetting the transaction caches in each class too but the workspace is controlling that */
2123 }
2124 
2125 /* UTILITY FUNCTIONS */
2126 /*
2127  * sm_check_name() - This is made void for ANSI compatibility.
2128  * It previously insured that identifiers which were accepted could be
2129  * parsed in the language interface.
2130  *
2131  * ANSI allows any character in an identifier. It also allows reserved
2132  * words. In order to parse identifiers with non-alpha characters
2133  * or that are reserved words, an escape syntax is defined. See the lexer
2134  * tokens DELIMITED_ID_NAME, BRACKET_ID_NAME and BACKTICK_ID_NAME for
2135  * details on the escaping rules.
2136  * return: non-zero if name is ok
2137  * name(in): name to check
2138  */
2139 
2140 int
2141 sm_check_name (const char *name)
2142 {
2143  if (name == NULL || name[0] == '\0')
2144  {
2146  return 0;
2147  }
2148  else
2149  {
2150  return 1;
2151  }
2152 }
2153 
2154 /*
2155  * sm_downcase_name() - This is a kludge to make sure that class names are
2156  * always converted to lower case in the API.
2157  * This conversion is already done by the parser so we must be consistent.
2158  * This is necessarily largely because the eh_ module on the server does not
2159  * offer a mode for case insensitive string comparison.
2160  * Is there a system function that does this? I couldn't find one
2161  * return: none
2162  * name(in): class name
2163  * buf(out): output buffer
2164  * maxlen(in): maximum buffer length
2165  */
2166 
2167 void
2168 sm_downcase_name (const char *name, char *buf, int maxlen)
2169 {
2170  int name_size;
2171 
2172  name_size = intl_identifier_lower_string_size (name);
2173  /* the sizes of lower and upper version of an identifier are checked when entering the system */
2174  assert (name_size < maxlen);
2175 
2176  intl_identifier_lower (name, buf);
2177 }
2178 
2179 /*
2180  * sm_resolution_space() - This is used to convert a full component
2181  * name_space to one of the more constrained resolution namespaces.
2182  * return: resolution name_space
2183  * name_space(in): component name_space
2184  */
2185 
2188 {
2189  SM_NAME_SPACE res_space = ID_INSTANCE;
2190 
2191  if (name_space == ID_CLASS_ATTRIBUTE || name_space == ID_CLASS_METHOD)
2192  {
2193  res_space = ID_CLASS;
2194  }
2195 
2196  return res_space;
2197 }
2198 
2199 /* CLASS LOCATION FUNCTIONS */
2200 /*
2201  * sm_get_class() - This is just a convenience function used to
2202  * return a class MOP for any possible MOP.
2203  * If this is a class mop return it, if this is an object MOP,
2204  * fetch the class and return its mop.
2205  * return: class mop
2206  * obj(in): object or class mop
2207  */
2208 
2209 MOP
2211 {
2212  MOP op = NULL;
2213  int is_class = 0;
2214 
2215  if (obj != NULL)
2216  {
2217  is_class = locator_is_class (obj, DB_FETCH_READ);
2218  if (is_class < 0)
2219  {
2220  return NULL;
2221  }
2222  if (is_class)
2223  {
2224  op = obj;
2225  }
2226  else
2227  {
2228  if (ws_class_mop (obj) == NULL)
2229  {
2230  /* force class load through object load */
2232  {
2233  return NULL;
2234  }
2235  }
2236  op = ws_class_mop (obj);
2237  }
2238  }
2239 
2240  return op;
2241 }
2242 
2243 /*
2244  * sm_fetch_all_classes() - Fetch all classes for a given purpose.
2245  * Builds a list of all classes in the system. Be careful to filter
2246  * out the root class since it isn't really a class to the callers.
2247  * The external_list flag is set when the object list is to be returned
2248  * above the database interface layer (db_ functions) and must therefore
2249  * be allocated in storage that will serve as roots to the garbage
2250  * collector.
2251  * return: object list of class MOPs
2252  * external_list(in): non-zero if external list links are to be used
2253  * purpose(in): Fetch purpose
2254  */
2255 DB_OBJLIST *
2256 sm_fetch_all_classes (int external_list, DB_FETCH_MODE purpose)
2257 {
2258  LIST_MOPS *lmops;
2259  DB_OBJLIST *objects, *last, *new_;
2260  int i;
2261 
2262  objects = NULL;
2263  lmops = NULL;
2264 
2265  if (au_check_user () == NO_ERROR)
2266  { /* make sure we have a user */
2267  last = NULL;
2268  lmops = locator_get_all_mops (sm_Root_class_mop, purpose, NULL);
2269  /* probably should make sure we push here because the list could be long */
2270  if (lmops != NULL)
2271  {
2272  for (i = 0; i < lmops->num; i++)
2273  {
2274  /* is it necessary to have this check ? */
2275  if (!WS_IS_DELETED (lmops->mops[i]) && lmops->mops[i] != sm_Root_class_mop)
2276  {
2277  if (!external_list)
2278  {
2279  if (ml_append (&objects, lmops->mops[i], NULL))
2280  {
2281  goto memory_error;
2282  }
2283  }
2284  else
2285  {
2286  /* should have a ext_ append function */
2287  new_ = ml_ext_alloc_link ();
2288  if (new_ == NULL)
2289  {
2290  goto memory_error;
2291  }
2292  new_->op = lmops->mops[i];
2293  new_->next = NULL;
2294  if (last != NULL)
2295  {
2296  last->next = new_;
2297  }
2298  else
2299  {
2300  objects = new_;
2301  }
2302  last = new_;
2303  }
2304  }
2305  }
2306  locator_free_list_mops (lmops);
2307  }
2308  }
2309 
2310  return objects;
2311 
2312 memory_error:
2313  if (lmops != NULL)
2314  {
2315  locator_free_list_mops (lmops);
2316  }
2317 
2318  if (external_list)
2319  {
2320  ml_ext_free (objects);
2321  }
2322  else
2323  {
2324  ml_free (objects);
2325  }
2326 
2327  return NULL;
2328 }
2329 
2330 /*
2331  * sm_fetch_base_classes() - Fetch base classes for the given mode.
2332  * Returns a list of classes that have no super classes.
2333  * return: list of class MOPs
2334  * external_list(in): non-zero to create external MOP list
2335  * purpose(in): Fetch purpose
2336  */
2337 
2338 DB_OBJLIST *
2339 sm_fetch_all_base_classes (int external_list, DB_FETCH_MODE purpose)
2340 {
2341  LIST_MOPS *lmops;
2342  DB_OBJLIST *objects, *last, *new_;
2343  int i;
2344  int error;
2345  SM_CLASS *class_;
2346 
2347  objects = NULL;
2348  lmops = NULL;
2349  if (au_check_user () == NO_ERROR)
2350  { /* make sure we have a user */
2351  last = NULL;
2352  lmops = locator_get_all_mops (sm_Root_class_mop, purpose, NULL);
2353  /* probably should make sure we push here because the list could be long */
2354  if (lmops != NULL)
2355  {
2356  for (i = 0; i < lmops->num; i++)
2357  {
2358  /* is it necessary to have this check ? */
2359  if (!WS_IS_DELETED (lmops->mops[i]) && lmops->mops[i] != sm_Root_class_mop)
2360  {
2361  error = au_fetch_class_force (lmops->mops[i], &class_, AU_FETCH_READ);
2362  if (error != NO_ERROR)
2363  {
2364  /* problems accessing the class list, abort */
2365  locator_free_list_mops (lmops);
2366  ml_ext_free (objects);
2367  return NULL;
2368  }
2369  /* only put classes without supers on the list */
2370  else if (class_->inheritance == NULL)
2371  {
2372  if (!external_list)
2373  {
2374  if (ml_append (&objects, lmops->mops[i], NULL))
2375  {
2376  goto memory_error;
2377  }
2378  }
2379  else
2380  {
2381  /* should have a ext_ append function */
2382  new_ = ml_ext_alloc_link ();
2383  if (new_ == NULL)
2384  {
2385  goto memory_error;
2386  }
2387  new_->op = lmops->mops[i];
2388  new_->next = NULL;
2389  if (last != NULL)
2390  {
2391  last->next = new_;
2392  }
2393  else
2394  {
2395  objects = new_;
2396  }
2397  last = new_;
2398  }
2399  }
2400  }
2401  }
2402  locator_free_list_mops (lmops);
2403  }
2404  }
2405 
2406  return objects;
2407 
2408 memory_error:
2409  if (lmops != NULL)
2410  {
2411  locator_free_list_mops (lmops);
2412  }
2413 
2414  if (external_list)
2415  {
2416  ml_ext_free (objects);
2417  }
2418  else
2419  {
2420  ml_free (objects);
2421  }
2422 
2423  return NULL;
2424 }
2425 
2426 #if defined (ENABLE_UNUSED_FUNCTION)
2427 /*
2428  * sm_get_all_classes() - Builds a list of all classes in the system.
2429  * Be careful to filter out the root class since it isn't really a class
2430  * to the callers. The external_list flag is set when the object list is
2431  * to be returned above the database interface layer (db_ functions) and
2432  * must therefore be allocated in storage that will serve as roots to
2433  * the garbage collector.
2434  * Authorization checking is not performed at this level so there may be
2435  * MOPs in the list that you can't actually access.
2436  * return: object list of class MOPs
2437  * external_list(in): non-zero if external list links are to be used
2438  */
2439 
2440 static DB_OBJLIST *
2441 sm_get_all_classes (int external_list)
2442 {
2443  /* Lock all the classes in shared mode */
2444  return sm_fetch_all_classes (external_list, DB_FETCH_QUERY_READ);
2445 } /* sm_get_all_classes */
2446 
2447 /*
2448  * sm_get_base_classes() - Returns a list of classes that have no super classes
2449  * return: list of class MOPs
2450  * external_list(in): non-zero to create external MOP list
2451 */
2452 static DB_OBJLIST *
2453 sm_get_base_classes (int external_list)
2454 {
2455  /* Lock all the classes in shared mode */
2456  return sm_fetch_all_base_classes (external_list, DB_FETCH_QUERY_READ);
2457 }
2458 #endif
2459 
2460 /*
2461  * sm_fetch_all_objects() -
2462  * a general interface function of sm_fetch_all_objects_internal
2463  * return: list of objects
2464  * op(in): class or instance object
2465  * purpose(in): Fetch purpose
2466  */
2467 
2468 DB_OBJLIST *
2470 {
2471  return sm_fetch_all_objects_internal (op, purpose, NULL);
2472 }
2473 
2474 /*
2475  * sm_fetch_all_objects_of_dirty_version() -
2476  * an interface function of sm_fetch_all_objects_internal
2477  * It will fetch DIRTY version.
2478  * Currently, the only user of this function is au_get_new_auth.
2479  * return: list of objects
2480  * op(in): class or instance object
2481  * purpose(in): Fetch purpose
2482  */
2483 DB_OBJLIST *
2485 {
2486  LC_FETCH_VERSION_TYPE fetch_version_type = LC_FETCH_DIRTY_VERSION;
2487 
2488  return sm_fetch_all_objects_internal (op, purpose, &fetch_version_type);
2489 }
2490 
2491 
2492 /* OBJECT LOCATION */
2493 /*
2494  * sm_fetch_all_objects_internal() - Returns a list of all the instances that
2495  * have been created for a class.
2496  * This was used early on before query was available, it should not
2497  * be heavily used now. Be careful, this can potentially bring
2498  * in lots of objects and overflow the workspace.
2499  * This is used in the implementation of a db_ function so it must
2500  * allocate an external mop list !
2501  * return: list of objects
2502  * op(in): class or instance object
2503  * purpose(in): Fetch purpose
2504  * force_fetch_version_type: fetch version type
2505  */
2506 
2507 static DB_OBJLIST *
2509 {
2510  LIST_MOPS *lmops;
2511  SM_CLASS *class_;
2512  DB_OBJLIST *objects, *new_;
2513  MOP classmop;
2514  SM_CLASS_TYPE ct;
2515  int i, is_class = 0;
2516 
2517  objects = NULL;
2518  classmop = NULL;
2519  lmops = NULL;
2520 
2521  if (op != NULL)
2522  {
2523  is_class = locator_is_class (op, purpose);
2524  if (is_class < 0)
2525  {
2526  return NULL;
2527  }
2528  if (is_class)
2529  {
2530  classmop = op;
2531  }
2532  else
2533  {
2534  if (ws_class_mop (op) == NULL)
2535  {
2536  /* force load */
2537  (void) au_fetch_class (op, &class_, AU_FETCH_READ, AU_SELECT);
2538  }
2539  classmop = ws_class_mop (op);
2540  }
2541  if (classmop != NULL)
2542  {
2543  class_ = (SM_CLASS *) classmop->object;
2544  if (!class_)
2545  {
2546  (void) au_fetch_class (classmop, &class_, AU_FETCH_READ, AU_SELECT);
2547  }
2548  if (!class_)
2549  {
2550  return NULL;
2551  }
2552 
2553  ct = sm_get_class_type (class_);
2554  if (ct == SM_CLASS_CT)
2555  {
2556  lmops = locator_get_all_mops (classmop, purpose, force_fetch_version_type);
2557  if (lmops != NULL)
2558  {
2559  for (i = 0; i < lmops->num; i++)
2560  {
2561  /* is it necessary to have this check ? */
2562  if (!WS_IS_DELETED (lmops->mops[i]))
2563  {
2564  new_ = ml_ext_alloc_link ();
2565  if (new_ == NULL)
2566  {
2567  goto memory_error;
2568  }
2569 
2570  new_->op = lmops->mops[i];
2571  new_->next = objects;
2572  objects = new_;
2573  }
2574  }
2575  locator_free_list_mops (lmops);
2576  }
2577  }
2578  else
2579  {
2580  objects = vid_getall_mops (classmop, class_, purpose);
2581  }
2582  }
2583  }
2584 
2585  return objects;
2586 
2587 memory_error:
2588  if (lmops != NULL)
2589  {
2590  locator_free_list_mops (lmops);
2591  }
2592 
2593  ml_ext_free (objects);
2594 
2595  return NULL;
2596 }
2597 
2598 #if defined (ENABLE_UNUSED_FUNCTION)
2599 /*
2600  * sm_get_all_objects() - Returns a list of all the instances that
2601  * have been created for a class.
2602  * This was used early on before query was available, it should not
2603  * be heavily used now. Be careful, this can potentially bring
2604  * in lots of objects and overflow the workspace.
2605  * This is used in the implementation of a db_ function so it must
2606  * allocate an external mop list !
2607  * return: list of objects
2608  * op(in): class or instance object
2609  */
2610 
2611 static DB_OBJLIST *
2612 sm_get_all_objects (DB_OBJECT * op)
2613 {
2615 }
2616 #endif
2617 
2618 /* MISC SCHEMA OPERATIONS */
2619 /*
2620  * sm_rename_class() - This is used to change the name of a class if possible.
2621  * It is not part of the smt_ template layer because its a fairly
2622  * fundamental change that must be checked early.
2623  * return: NO_ERROR on success, non-zero for ERROR
2624  * op(in/out): class mop
2625  * new_name(in):
2626  */
2627 
2628 int
2629 sm_rename_class (MOP op, const char *new_name)
2630 {
2631  int error;
2632  SM_CLASS *class_;
2633  SM_ATTRIBUTE *att;
2634  const char *current, *newname;
2635  char realname[SM_MAX_IDENTIFIER_LENGTH];
2636  int is_partition = 0;
2637 /* TR_STATE *trstate; */
2638 
2639  /* make sure this gets into the server table with no capitalization */
2640  sm_downcase_name (new_name, realname, SM_MAX_IDENTIFIER_LENGTH);
2641 
2642 #if defined (ENABLE_UNUSED_FUNCTION)
2643  if (sm_has_text_domain (db_get_attributes (op), 1))
2644  {
2645  /* prevent to rename class */
2647  return error;
2648  }
2649 #endif /* ENABLE_UNUSED_FUNCTION */
2650 
2651  error = sm_partitioned_class_type (op, &is_partition, NULL, NULL);
2652  if (is_partition == DB_PARTITIONED_CLASS)
2653  {
2655  if (error != NO_ERROR)
2656  {
2657  return error;
2658  }
2659  }
2660 
2661  if (!sm_check_name (realname))
2662  {
2663  assert (er_errid () != NO_ERROR);
2664  error = er_errid ();
2665  }
2666  else if ((error = au_fetch_class (op, &class_, AU_FETCH_UPDATE, AU_ALTER)) == NO_ERROR)
2667  {
2668  /* We need to go ahead and copy the string since prepare_rename uses the address of the string in the hash table. */
2669  current = sm_ch_name ((MOBJ) class_);
2670  newname = ws_copy_string (realname);
2671  if (newname == NULL)
2672  {
2673  assert (er_errid () != NO_ERROR);
2674  return er_errid ();
2675  }
2676 
2677  if (locator_prepare_rename_class (op, current, newname) == NULL)
2678  {
2679  ws_free_string (newname);
2680  assert (er_errid () != NO_ERROR);
2681  error = er_errid ();
2682  }
2683  else
2684  {
2685  class_->header.ch_name = newname;
2686  error = sm_flush_objects (op);
2687 
2688  if (error == NO_ERROR)
2689  {
2690  /* rename related auto_increment serial obj name */
2691  for (att = class_->attributes; att != NULL; att = (SM_ATTRIBUTE *) att->header.next)
2692  {
2693  if (att->auto_increment != NULL)
2694  {
2695  DB_VALUE name_val;
2696  const char *class_name;
2697 
2698  if (db_get (att->auto_increment, "class_name", &name_val) != NO_ERROR)
2699  {
2700  break;
2701  }
2702 
2703  class_name = db_get_string (&name_val);
2704  if (class_name != NULL && (strcmp (current, class_name) == 0))
2705  {
2706  int save;
2707  AU_DISABLE (save);
2708  error =
2710  AU_ENABLE (save);
2711  }
2712  db_value_clear (&name_val);
2713 
2714  if (error != NO_ERROR)
2715  {
2716  break;
2717  }
2718  }
2719  }
2720  }
2721  ws_free_string (current);
2722  }
2723  }
2724 
2725  if (is_partition == DB_PARTITIONED_CLASS)
2726  {
2727  if (error == NO_ERROR)
2728  {
2729  error = do_rename_partition (op, realname);
2730  }
2731 
2732  if (error != NO_ERROR && error != ER_LK_UNILATERALLY_ABORTED)
2733  {
2735  }
2736  }
2737 
2738  return error;
2739 }
2740 
2741 /*
2742  * sm_mark_system_classes() - Hack used to set the "system class" flag for
2743  * all currently resident classes.
2744  * This is only to make it more convenient to tell the
2745  * difference between CUBRID and user defined classes. This is intended
2746  * to be called after the appropriate CUBRID class initialization function.
2747  * Note that authorization is disabled here because these are normally
2748  * called on the authorization classes.
2749  */
2750 
2751 void
2753 {
2754  LIST_MOPS *lmops;
2755  SM_CLASS *class_;
2756  int i;
2757 
2758  if (au_check_user () == NO_ERROR)
2759  {
2760  lmops = locator_get_all_mops (sm_Root_class_mop, DB_FETCH_QUERY_WRITE, NULL);
2761  if (lmops != NULL)
2762  {
2763  for (i = 0; i < lmops->num; i++)
2764  {
2765  if (!WS_IS_DELETED (lmops->mops[i]) && lmops->mops[i] != sm_Root_class_mop)
2766  {
2767  if (au_fetch_class_force (lmops->mops[i], &class_, AU_FETCH_UPDATE) == NO_ERROR)
2768  {
2769  class_->flags |= SM_CLASSFLAG_SYSTEM;
2770  }
2771  }
2772  }
2773  locator_free_list_mops (lmops);
2774  }
2775  }
2776 }
2777 
2778 /*
2779  * sm_mark_system_class() - This turns on or off the system class flag.
2780  * This flag is tested by the sm_is_system_class function.
2781  * return: NO_ERROR on success, non-zero for ERROR
2782  * classop (in): class pointer
2783  * on_or_off(in): state of the flag
2784  */
2785 
2786 int
2787 sm_mark_system_class (MOP classop, int on_or_off)
2788 {
2789  SM_CLASS *class_;
2790  int error = NO_ERROR;
2791 
2792  if (classop != NULL)
2793  {
2794  error = au_fetch_class_force (classop, &class_, AU_FETCH_UPDATE);
2795  if (error == NO_ERROR)
2796  {
2797  if (on_or_off)
2798  {
2799  class_->flags |= SM_CLASSFLAG_SYSTEM;
2800  }
2801  else
2802  {
2803  class_->flags &= ~SM_CLASSFLAG_SYSTEM;
2804  }
2805  }
2806  }
2807 
2808  return error;
2809 }
2810 
2811 #if defined(ENABLE_UNUSED_FUNCTION)
2812 #ifdef SA_MODE
2813 void
2814 sm_mark_system_class_for_catalog (void)
2815 {
2816  MOP classmop;
2817  SM_CLASS *class_;
2818  int i;
2819 
2820  const char *classes[] = {
2832  };
2833 
2834  for (i = 0; classes[i] != NULL; i++)
2835  {
2836  classmop = locator_find_class (classes[i]);
2837  if (au_fetch_class_force (classmop, &class_, AU_FETCH_UPDATE) == NO_ERROR)
2838  {
2839  class_->flags |= SM_CLASSFLAG_SYSTEM;
2840  }
2841  }
2842 }
2843 #endif /* SA_MODE */
2844 #endif
2845 
2846 /*
2847  * sm_set_class_flag() - This turns on or off the given flag.
2848  * The flag may be tested by the sm_get_class_flag function.
2849  * return: NO_ERROR on success, non-zero for ERROR
2850  * classop (in): class pointer
2851  * flag (in): flag to set or clear
2852  * on_or_off(in): 1 to set 0 to clear
2853  */
2854 
2855 int
2856 sm_set_class_flag (MOP classop, SM_CLASS_FLAG flag, int on_or_off)
2857 {
2858  SM_CLASS *class_;
2859  int error = NO_ERROR;
2860 
2861  if (classop != NULL)
2862  {
2863  error = au_fetch_class_force (classop, &class_, AU_FETCH_UPDATE);
2864  if (error == NO_ERROR)
2865  {
2866  if (on_or_off)
2867  {
2868  class_->flags |= flag;
2869  }
2870  else
2871  {
2872  class_->flags &= ~flag;
2873  }
2874  }
2875  }
2876 
2877  return error;
2878 }
2879 
2880 /*
2881  * sm_set_class_tde_algorithm() - This sets the tde encryption algorithm.
2882  * return: NO_ERROR on success, non-zero for ERROR
2883  * classop (in): class pointer
2884  * tde_algo in): encryption algorithm for the class
2885  */
2886 
2887 int
2889 {
2890  SM_CLASS *class_;
2891  int error = NO_ERROR;
2892 
2893  assert (tde_algo == TDE_ALGORITHM_NONE || tde_algo == TDE_ALGORITHM_AES || tde_algo == TDE_ALGORITHM_ARIA);
2894 
2895  if (classop != NULL)
2896  {
2897  error = au_fetch_class_force (classop, &class_, AU_FETCH_UPDATE);
2898  if (error == NO_ERROR)
2899  {
2900  class_->tde_algorithm = (int) tde_algo;
2901  }
2902  }
2903 
2904  return error;
2905 }
2906 
2907 /*
2908  * sm_get_class_tde_algorithm() - Get the tde algorithm of a class.
2909  * return: NO_ERROR on success, negative for ERROR
2910  * classop (in): class pointer
2911  * tde_algo (out): tde algorithm
2912  */
2913 int
2915 {
2916  SM_CLASS *class_;
2917  int error = NO_ERROR;
2918 
2919  assert (classop != NULL);
2920  *tde_algo = TDE_ALGORITHM_NONE;
2921 
2922  error = au_fetch_class_force (classop, &class_, AU_FETCH_READ);
2923  if (error == NO_ERROR)
2924  {
2925  *tde_algo = (TDE_ALGORITHM) class_->tde_algorithm;
2926  }
2927 
2928  return error;
2929 }
2930 
2931 /*
2932  * sm_set_class_collation() - This sets the table collation.
2933  * return: NO_ERROR on success, non-zero for ERROR
2934  * classop (in): class pointer
2935  * collation_id (in): collation id to set as default
2936  */
2937 int
2938 sm_set_class_collation (MOP classop, int collation_id)
2939 {
2940  SM_CLASS *class_;
2941  int error = NO_ERROR;
2942 
2943  assert (classop != NULL);
2944 
2945  error = au_fetch_class_force (classop, &class_, AU_FETCH_UPDATE);
2946  if (error == NO_ERROR)
2947  {
2948  class_->collation_id = collation_id;
2949  }
2950 
2951  return error;
2952 }
2953 
2954 /*
2955  * sm_get_class_collation() - Get the table collation.
2956  * return: NO_ERROR on success, negative for ERROR
2957  * classop (in): class pointer
2958  * collation_id(out): the table's collation
2959  */
2960 int
2961 sm_get_class_collation (MOP classop, int *collation_id)
2962 {
2963  SM_CLASS *class_;
2964  int error = NO_ERROR;
2965 
2966  assert (classop != NULL);
2967  *collation_id = -1;
2968 
2969  error = au_fetch_class_force (classop, &class_, AU_FETCH_READ);
2970  if (error == NO_ERROR)
2971  {
2972  *collation_id = class_->collation_id;
2973  }
2974 
2975  return error;
2976 }
2977 
2978 /*
2979  * sm_set_class_comment() - This sets the table comment.
2980  * return: NO_ERROR on success, non-zero for ERROR
2981  * classop (in): class pointer
2982  * comment (in): table comment
2983  */
2984 
2985 int
2986 sm_set_class_comment (MOP classop, const char *comment)
2987 {
2988  SM_CLASS *class_;
2989  int error = NO_ERROR;
2990 
2991  assert (classop != NULL);
2992 
2993  error = au_fetch_class_force (classop, &class_, AU_FETCH_UPDATE);
2994  if (error == NO_ERROR)
2995  {
2996  ws_free_string (class_->comment);
2997  class_->comment = ws_copy_string (comment);
2998  if (class_->comment == NULL && comment != NULL)
2999  {
3000  error = (er_errid () != NO_ERROR) ? er_errid () : ER_FAILED;
3001  }
3002  }
3003 
3004  return error;
3005 }
3006 
3007 /*
3008  * sm_is_system_class() - Tests the system class flag of a class object.
3009  * return: non-zero if class is a system defined class
3010  * op(in): class object
3011  */
3012 
3013 int
3015 {
3017 }
3018 
3019 /*
3020  * sm_is_reuse_oid_class() - Tests the reuse OID class flag of a class object.
3021  * return: true if class is an OID reusable class. otherwise, false
3022  * op(in): class object
3023  */
3024 
3025 bool
3027 {
3028  SM_CLASS *class_;
3029 
3030  if (op != NULL)
3031  {
3032  if (au_fetch_class_force (op, &class_, AU_FETCH_READ) == NO_ERROR)
3033  {
3034  return (class_->flags & SM_CLASSFLAG_REUSE_OID);
3035  }
3036  }
3037 
3038  return false;
3039 }
3040 
3041 /*
3042  * sm_check_reuse_oid_class() - Tests the reuse OID class flag of a class object.
3043  * return: true, false or error with negative value
3044  * op(in): class object
3045  *
3046  */
3047 
3048 int
3050 {
3051  SM_CLASS *class_;
3052  int error = NO_ERROR;
3053 
3054  if (op != NULL)
3055  {
3056  error = au_fetch_class_force (op, &class_, AU_FETCH_READ);
3057  if (error != NO_ERROR)
3058  {
3059  return error;
3060  }
3061 
3062  return (class_->flags & SM_CLASSFLAG_REUSE_OID);
3063  }
3064 
3065  return false;
3066 }
3067 
3068 /*
3069  * sm_is_partitioned_class () - test if this class is partitioned
3070  * return : < 0 if error, > 0 for partitioned classes, 0 otherwise
3071  * op (in) : class object
3072  */
3073 int
3075 {
3076  SM_CLASS *class_;
3077  int save, result = 0;
3078 
3079  if (locator_is_root (op))
3080  {
3081  return 0;
3082  }
3083 
3084  if (op != NULL)
3085  {
3086  result = locator_is_class (op, DB_FETCH_READ);
3087  if (result < 0)
3088  {
3089  return result;
3090  }
3091  }
3092  if (result)
3093  {
3094  AU_DISABLE (save);
3095  if (au_fetch_class_force (op, &class_, AU_FETCH_READ) == NO_ERROR)
3096  {
3097  result = (class_->partition != NULL);
3098  }
3099  AU_ENABLE (save);
3100  }
3101 
3102  return result;
3103 }
3104 
3105 /*
3106  * sm_partitioned_class_type () -
3107  * return : NO_ERROR or error code
3108  * classop (in) :
3109  * partition_type (in/out) : DB_NOT_PARTITIONED_CLASS, DB_PARTITIONED_CLASS
3110  * OR DB_PARTITION_CLASS
3111  * keyattr (in/out) : if not null, will hold partition key attribute
3112  * name
3113  * partitions (in/out) : if not null, will hold MOP array of partitions
3114  */
3115 int
3116 sm_partitioned_class_type (DB_OBJECT * classop, int *partition_type, char *keyattr, MOP ** partitions)
3117 {
3118  DB_OBJLIST *objs;
3119  SM_CLASS *smclass, *subcls;
3120  DB_VALUE psize, attrname;
3121  int au_save, pcnt, i;
3122  MOP *subobjs = NULL;
3123  int error;
3124 
3125  assert (classop != NULL);
3126  assert (partition_type != NULL);
3127 
3128  *partition_type = DB_NOT_PARTITIONED_CLASS;
3129 
3130  AU_DISABLE (au_save);
3131 
3132  error = au_fetch_class (classop, &smclass, AU_FETCH_READ, AU_SELECT);
3133  if (error != NO_ERROR)
3134  {
3135  AU_ENABLE (au_save);
3136  return error;
3137  }
3138  if (!smclass->partition)
3139  {
3140  AU_ENABLE (au_save);
3141  return NO_ERROR;
3142  }
3143 
3144  if (partitions == NULL && keyattr == NULL)
3145  {
3146  /* Only get partition status (partitioned/not partitioned) */
3147  if (smclass->users == NULL)
3148  {
3149  *partition_type = DB_PARTITION_CLASS;
3150  }
3151  else
3152  {
3153  *partition_type = DB_PARTITIONED_CLASS;
3154  }
3155  AU_ENABLE (au_save);
3156  return NO_ERROR;
3157  }
3158 
3159  db_make_null (&psize);
3160  db_make_null (&attrname);
3161 
3162  *partition_type = (smclass->partition->pname == NULL ? DB_PARTITIONED_CLASS : DB_PARTITION_CLASS);
3163 
3164  if (keyattr || partitions)
3165  {
3166  if (*partition_type == DB_PARTITION_CLASS)
3167  {
3168  /* Fetch the root partition class. Partitions can only inherit from one class which is the partitioned table */
3169  MOP root_op = NULL;
3170 
3171  error = do_get_partition_parent (classop, &root_op);
3172  if (error != NO_ERROR || root_op == NULL)
3173  {
3174  goto partition_failed;
3175  }
3176 
3177  error = au_fetch_class (root_op, &smclass, AU_FETCH_READ, AU_SELECT);
3178 
3179  if (error != NO_ERROR)
3180  {
3181  goto partition_failed;
3182  }
3183  }
3184 
3185  if (set_get_element_nocopy (smclass->partition->values, 0, &attrname) != NO_ERROR)
3186  {
3187  goto partition_failed;
3188  }
3189  if (set_get_element_nocopy (smclass->partition->values, 1, &psize) != NO_ERROR)
3190  {
3191  goto partition_failed;
3192  }
3193 
3194  pcnt = psize.data.i;
3195  if (keyattr)
3196  {
3197  const char *p = NULL;
3198 
3199  keyattr[0] = 0;
3200  if (DB_IS_NULL (&attrname) || (p = db_get_string (&attrname)) == NULL)
3201  {
3202  goto partition_failed;
3203  }
3204  strncpy (keyattr, p, DB_MAX_IDENTIFIER_LENGTH);
3205  if (strlen (p) < DB_MAX_IDENTIFIER_LENGTH)
3206  {
3207  keyattr[strlen (p)] = 0;
3208  }
3209  else
3210  {
3211  keyattr[DB_MAX_IDENTIFIER_LENGTH] = 0;
3212  }
3213  }
3214 
3215  if (partitions)
3216  {
3217  subobjs = (MOP *) malloc (sizeof (MOP) * (pcnt + 1));
3218  if (subobjs == NULL)
3219  {
3220  goto partition_failed;
3221  }
3222  memset (subobjs, 0, sizeof (MOP) * (pcnt + 1));
3223 
3224  for (objs = smclass->users, i = 0; objs && i < pcnt; objs = objs->next)
3225  {
3226  if (au_fetch_class (objs->op, &subcls, AU_FETCH_READ, AU_SELECT) != NO_ERROR)
3227  {
3228  goto partition_failed;
3229  }
3230  if (subcls->partition == NULL)
3231  {
3232  continue;
3233  }
3234  subobjs[i++] = objs->op;
3235  }
3236 
3237  *partitions = subobjs;
3238  }
3239  }
3240 
3241  AU_ENABLE (au_save);
3242 
3243  return NO_ERROR;
3244 
3245 partition_failed:
3246  AU_ENABLE (au_save);
3247  if (subobjs)
3248  {
3249  free_and_init (subobjs);
3250  }
3251 
3253 
3254  return ER_PARTITION_WORK_FAILED;
3255 }
3256 
3257 /*
3258  * sm_get_class_flag() - Tests the class flag of a class object.
3259  * return: non-zero if flag set
3260  * op(in): class object
3261  * flag(in): flag to test
3262  */
3263 
3264 int
3266 {
3267  SM_CLASS *class_;
3268  int result = 0;
3269 
3270  if (op != NULL)
3271  {
3272  result = locator_is_class (op, DB_FETCH_READ);
3273  if (result <= 0)
3274  {
3275  return result;
3276  }
3277  result = au_fetch_class_force (op, &class_, AU_FETCH_READ);
3278  if (result == NO_ERROR)
3279  {
3280  result = class_->flags & flag;
3281  }
3282  }
3283 
3284  return result;
3285 }
3286 
3287 
3288 
3289 /*
3290  * sm_force_write_all_classes()
3291  * return: NO_ERROR on success, non-zero for ERROR
3292  */
3293 
3294 int
3296 {
3297  LIST_MOPS *lmops;
3298  int i;
3299 
3300  /* get all class objects */
3301  lmops = locator_get_all_mops (sm_Root_class_mop, DB_FETCH_QUERY_WRITE, NULL);
3302  if (lmops != NULL)
3303  {
3304  for (i = 0; i < lmops->num; i++)
3305  {
3306  ws_dirty (lmops->mops[i]);
3307  }
3308 
3309  /* insert all class objects into the catalog classes */
3310  if (locator_flush_all_instances (sm_Root_class_mop, DONT_DECACHE) != NO_ERROR)
3311  {
3312  assert (er_errid () != NO_ERROR);
3313  return er_errid ();
3314  }
3315 
3316  for (i = 0; i < lmops->num; i++)
3317  {
3318  ws_dirty (lmops->mops[i]);
3319  }
3320 
3321  /* update class hierarchy values for some class objects. the hierarchy makes class/class mutual references so
3322  * some class objects were inserted with no hierarchy values. */
3323  if (locator_flush_all_instances (sm_Root_class_mop, DONT_DECACHE) != NO_ERROR)
3324  {
3325  assert (er_errid () != NO_ERROR);
3326  return er_errid ();
3327  }
3328 
3329  locator_free_list_mops (lmops);
3330  }
3331 
3332  return NO_ERROR;
3333 }
3334 
3335 /*
3336  * sm_destroy_representations() - This is called by the compaction utility
3337  * after it has swept through the instances of a class and converted them
3338  * all to the latest representation.
3339  * Once this is done, the schema manager no longer needs to maintain
3340  * the history of old representations. In order for this to become
3341  * persistent, the transaction must be committed.
3342  * return: NO_ERROR on success, non-zero for ERROR
3343  * op(in): class object
3344  */
3345 
3346 int
3348 {
3349  int error = NO_ERROR;
3350  SM_CLASS *class_;
3351 
3352  error = au_fetch_class_force (op, &class_, AU_FETCH_UPDATE);
3353  if (error == NO_ERROR)
3354  {
3356  class_->representations = NULL;
3357  }
3358 
3359  return error;
3360 }
3361 
3362 /* DOMAIN MAINTENANCE FUNCTIONS */
3363 
3364 /*
3365  * sm_filter_domain() - This removes any invalid domain references from a
3366  * domain list. See description of filter_domain_list for more details.
3367  * If the domain list was changed, we could get a write lock on the owning
3368  * class to ensure that the change is made persistent.
3369  * Making the change persistent doesn't really improve much since we
3370  * always have to do a filter pass when the class is fetched.
3371  * return: error code
3372  * domain(in): domain list for attribute or method arg
3373  * changes(out): non-zero if changes were made
3374  */
3375 
3376 int
3377 sm_filter_domain (TP_DOMAIN * domain, int *changes)
3378 {
3379  int error = NO_ERROR;
3380 
3381  if (domain != NULL)
3382  {
3383  error = tp_domain_filter_list (domain, changes);
3384  /* if changes, could get write lock on owning_class here */
3385  }
3386 
3387  return error;
3388 }
3389 
3390 /*
3391  * domain_search() - This recursively searches through the class hierarchy
3392  * to see if the "class_mop" is equal to or a subclass of "dclass_mop"
3393  * in which case it is within the domain of dlcass_mop.
3394  * This is essentially the same as sm_is_superclass except that it
3395  * doesn't check for authorization.
3396  * return: non-zero if the class was valid
3397  * dclass_mop(in): domain class
3398  * class_mop(in): class in question
3399  */
3400 
3401 static int
3402 domain_search (MOP dclass_mop, MOP class_mop)
3403 {
3404  DB_OBJLIST *cl;
3405  SM_CLASS *class_;
3406  int ok = 0;
3407 
3408  if (dclass_mop == class_mop)
3409  {
3410  ok = 1;
3411  }
3412  else
3413  {
3414  /* ignore authorization for the purposes of domain checking */
3415  if (au_fetch_class_force (class_mop, &class_, AU_FETCH_READ) == NO_ERROR)
3416  {
3417  for (cl = class_->inheritance; cl != NULL && !ok; cl = cl->next)
3418  {
3419  ok = domain_search (dclass_mop, cl->op);
3420  }
3421  }
3422  }
3423 
3424  return ok;
3425 }
3426 
3427 /*
3428  * sm_check_object_domain() - This checks to see if an instance is valid for
3429  * a given domain. It checks to see if the instance's class is equal to or
3430  * a subclass of the class in the domain. Also handles the various NULL
3431  * conditions.
3432  * return: non-zero if object is within the domain
3433  * domain(in): domain to examine
3434  * object(in): instance
3435  */
3436 
3437 int
3439 {
3440  int ok;
3441 
3442  ok = 0;
3443  if (domain->type == tp_Type_object)
3444  {
3445  /* check for physical and logical NULLness of the MOP, treat it as if it were SQL NULL which is allowed in all
3446  * domains */
3447  if (WS_MOP_IS_NULL (object))
3448  {
3449  ok = 1;
3450  }
3451  /* check for the wildcard object domain */
3452  else if (domain->class_mop == NULL)
3453  {
3454  ok = 1;
3455  }
3456  else
3457  {
3458  /* fetch the class if it hasn't been cached, should this be a write lock ? don't need to pin, only forcing
3459  * the class fetch */
3460  if (ws_class_mop (object) == NULL)
3461  {
3463  }
3464 
3465  /* if its still NULL, assume an authorization error and go on */
3466  if (ws_class_mop (object) != NULL)
3467  {
3468  ok = domain_search (domain->class_mop, ws_class_mop (object));
3469  }
3470  }
3471  }
3472 
3473  return ok;
3474 }
3475 
3476 /*
3477  * sm_coerce_object_domain() - This checks to see if an instance is valid for
3478  * a given domain.
3479  * It checks to see if the instance's class is equal to or a subclass
3480  * of the class in the domain. Also handles the various NULL
3481  * conditions.
3482  * If dest_object is not NULL and the object is a view on a real object,
3483  * the real object will be returned.
3484  * return: non-zero if object is within the domain
3485  * domain(in): domain to examine
3486  * object(in): instance
3487  * dest_object(out): ptr to instance to coerce object to
3488  */
3489 
3490 int
3491 sm_coerce_object_domain (TP_DOMAIN * domain, MOP object, MOP * dest_object)
3492 {
3493  int ok;
3494  MOP object_class_mop;
3495  SM_CLASS *class_;
3496 
3497  ok = 0;
3498  if (!dest_object)
3499  {
3500  return 0;
3501  }
3502 
3503  if (domain->type == tp_Type_object)
3504  {
3505  /* check for physical and logical NULLness of the MOP, treat it as if it were SQL NULL which is allowed in all
3506  * domains */
3507  if (WS_MOP_IS_NULL (object))
3508  {
3509  ok = 1;
3510  }
3511  /* check for the wildcard object domain */
3512  else if (domain->class_mop == NULL)
3513  {
3514  ok = 1;
3515  }
3516  else
3517  {
3518  /* fetch the class if it hasn't been cached, should this be a write lock ? don't need to pin, only forcing
3519  * the class fetch */
3520  if (ws_class_mop (object) == NULL)
3521  {
3523  }
3524 
3525  /* if its still NULL, assume an authorization error and go on */
3526  object_class_mop = ws_class_mop (object);
3527  if (object_class_mop != NULL)
3528  {
3529  if (domain->class_mop == object_class_mop)
3530  {
3531  ok = 1;
3532  }
3533  else
3534  {
3535  if (au_fetch_class_force (object_class_mop, &class_, AU_FETCH_READ) == NO_ERROR)
3536  {
3537  /* Coerce a view to a real class. */
3538  if (class_->class_type == SM_VCLASS_CT)
3539  {
3540  object = vid_get_referenced_mop (object);
3541  object_class_mop = ws_class_mop (object);
3542  if (object && (au_fetch_class_force (object_class_mop, &class_, AU_FETCH_READ) == NO_ERROR)
3543  && (class_->class_type == SM_CLASS_CT))
3544  {
3545  ok = domain_search (domain->class_mop, object_class_mop);
3546  }
3547  }
3548  else
3549  {
3550  ok = domain_search (domain->class_mop, object_class_mop);
3551  }
3552  }
3553  }
3554  }
3555  }
3556  }
3557 
3558  if (ok)
3559  {
3560  *dest_object = object;
3561  }
3562 
3563  return ok;
3564 }
3565 
3566 /*
3567  * sm_check_class_domain() - see if a class is within the domain.
3568  * It is similar to sm_check_object_domain except that we get
3569  * a pointer directly to the class and we don't allow NULL conditions.
3570  * return: non-zero if the class is within the domain
3571  * domain(in): domain to examine
3572  * class(in): class to look for
3573  */
3574 
3575 int
3577 {
3578  int ok = 0;
3579 
3580  if (domain->type == tp_Type_object && class_ != NULL)
3581  {
3582  /* check for domain class deletions and other delayed updates SINCE THIS IS CALLED FOR EVERY ATTRIBUTE UPDATE, WE
3583  * MUST EITHER CACHE THIS INFORMATION OR PERFORM IT ONCE WHEN THE CLASS IS FETCHED */
3584  (void) sm_filter_domain (domain, NULL);
3585 
3586  /* wildcard case */
3587  if (domain->class_mop == NULL)
3588  {
3589  ok = 1;
3590  }
3591  else
3592  {
3593  /* recursively check domains for class & super classes for now assume only one possible base class */
3594  ok = domain_search (domain->class_mop, class_);
3595  }
3596  }
3597 
3598  return ok;
3599 }
3600 
3601 #if defined (ENABLE_UNUSED_FUNCTION)
3602 /*
3603  * sm_get_set_domain() - used only by the set support to get the domain list for
3604  * the attribute that owns a set. Need to be careful that the cached
3605  * domain pointer is cleared if the class is ever swapped out.
3606  * return: domain list
3607  * classop(in): class mop
3608  * att_id(in): attribute id
3609  */
3610 
3611 static TP_DOMAIN *
3612 sm_get_set_domain (MOP classop, int att_id)
3613 {
3614  SM_CLASS *class_;
3615  SM_ATTRIBUTE *att;
3616  TP_DOMAIN *domain;
3617 
3618  domain = NULL;
3619  if (au_fetch_class_force (classop, &class_, AU_FETCH_READ) == NO_ERROR)
3620  {
3621  att = NULL;
3622 
3623  /* search the attribute spaces, ids won't overlap */
3624  for (att = class_->attributes; att != NULL && att->id != att_id; att = (SM_ATTRIBUTE *) att->header.next)
3625  ;
3626 
3627  if (att == NULL)
3628  {
3629  for (att = class_->shared; att != NULL && att->id != att_id; att = (SM_ATTRIBUTE *) att->header.next)
3630  ;
3631 
3632  if (att == NULL)
3633  {
3634  for (att = class_->class_attributes; att != NULL && att->id != att_id;
3635  att = (SM_ATTRIBUTE *) att->header.next)
3636  ;
3637  }
3638  }
3639 
3640  if (att != NULL)
3641  {
3642  domain = att->domain;
3643  }
3644  }
3645 
3646  return domain;
3647 }
3648 #endif
3649 
3650 /*
3651  * annotate_method_files() - This is a kludge to work around the fact that
3652  * we don't store origin or source classes with method files.
3653  * These have inheritance semantics like the other class components.
3654  * They can't be deleted if they were not locally defined etc.
3655  * The source class needs to be stored in the disk representation but
3656  * since we can't change that until 2.0, we have to fake it and compute
3657  * the source class after the class has been brought in from disk.
3658  * Warning, since the transformer doesn't have the class MOP when it
3659  * is building the class structures, it can't call this with a valid
3660  * MOP for the actual class. In this case, we let the class pointer
3661  * remain NULL and assume that that "means" this is a local attribute.
3662  * If we ever support the db_methfile_source() function, this will
3663  * need to be fixed.
3664  * return: NO_ERROR on success, non-zero for ERROR
3665  * classmop(in):
3666  * class(in): class being edited
3667  */
3668 
3669 static int
3670 annotate_method_files (MOP classmop, SM_CLASS * class_)
3671 {
3672  DB_OBJLIST *cl;
3673  SM_CLASS *super;
3674  SM_METHOD_FILE *f;
3675 
3676  if (class_->method_files != NULL)
3677  {
3678  /* might want to have the class loop outside and make multiple passes over the method files ? Probably doesn't
3679  * matter much */
3680 
3681  for (f = class_->method_files; f != NULL; f = f->next)
3682  {
3683  if (f->class_mop == NULL)
3684  {
3685  for (cl = class_->inheritance; cl != NULL && f->class_mop == NULL; cl = cl->next)
3686  {
3687  if (au_fetch_class_force (cl->op, &super, AU_FETCH_READ) != NO_ERROR)
3688  {
3689  assert (er_errid () != NO_ERROR);
3690  return (er_errid ());
3691  }
3692  else
3693  {
3694  if (NLIST_FIND (super->method_files, f->name) != NULL)
3695  {
3696  f->class_mop = cl->op;
3697  }
3698  }
3699  }
3700 
3701  /* if its still NULL, assume its defined locally */
3702  if (f->class_mop == NULL)
3703  {
3704  f->class_mop = classmop;
3705  }
3706  }
3707  }
3708  }
3709 
3710  return NO_ERROR;
3711 }
3712 
3713 /*
3714  * sm_clean_class() - used mainly before constructing a class template but
3715  * it could be used in other places as well. It will walk through the
3716  * class structure and prune out any references to deleted objects
3717  * in domain lists, etc. and do any other housekeeping tasks that it is
3718  * convenient to delay until a major operation is performed.
3719  * return: NO_ERROR on success, non-zero for ERROR
3720  * classmop(in):
3721  * class(in/out): class structure
3722  */
3723 
3724 int
3725 sm_clean_class (MOP classmop, SM_CLASS * class_)
3726 {
3727  int error = NO_ERROR;
3728  SM_ATTRIBUTE *att;
3729 
3730  /* we only need to do this once because once we have read locks, the referenced classes can't be deleted */
3731 
3732  for (att = class_->attributes; att != NULL; att = (SM_ATTRIBUTE *) att->header.next)
3733  {
3734  error = sm_filter_domain (att->domain, NULL);
3735  if (error != NO_ERROR)
3736  {
3737  return error;
3738  }
3739  }
3740  for (att = class_->shared; att != NULL; att = (SM_ATTRIBUTE *) att->header.next)
3741  {
3742  error = sm_filter_domain (att->domain, NULL);
3743  if (error != NO_ERROR)
3744  {
3745  return error;
3746  }
3747  }
3748  for (att = class_->class_attributes; att != NULL; att = (SM_ATTRIBUTE *) att->header.next)
3749  {
3750  error = sm_filter_domain (att->domain, NULL);
3751  if (error != NO_ERROR)
3752  {
3753  return error;
3754  }
3755  }
3756 
3757  if (!class_->post_load_cleanup)
3758  {
3759  /* initialize things that weren't done by the transformer */
3760 
3761  error = annotate_method_files (classmop, class_);
3762 
3763  class_->post_load_cleanup = 1;
3764  }
3765 
3766  return error;
3767 }
3768 
3769 /* CLASS STATISTICS FUNCTIONS */
3770 /*
3771  * sm_get_class_with_statistics() - Fetches and returns the statistics information for a
3772  * class from the system catalog on the server.
3773  * Must make sure callers keep the class MOP visible to the garbage
3774  * collector so the stat structures don't get reclaimed.
3775  * Currently used only by the query optimizer.
3776  * return: class object which contains statistics structure
3777  * classop(in): class object
3778  */
3779 
3780 SM_CLASS *
3782 {
3783  SM_CLASS *class_ = NULL;
3784  int is_class = 0;
3785 
3786  /* only try to get statistics if we know the class has been flushed if it has a temporary oid, it isn't flushed and
3787  * there are no statistics */
3788 
3789  if (classop != NULL)
3790  {
3791  is_class = locator_is_class (classop, DB_FETCH_QUERY_READ);
3792  if (is_class < 0)
3793  {
3794  return NULL;
3795  }
3796  }
3797 
3798  if (!is_class || OID_ISTEMP (WS_OID (classop)))
3799  {
3800  return NULL;
3801  }
3802 
3803  if (au_fetch_class (classop, &class_, AU_FETCH_READ, AU_SELECT) != NO_ERROR)
3804  {
3805  return NULL;
3806  }
3807 
3808  if (class_->stats == NULL)
3809  {
3810  /* it's first time to get the statistics of this class */
3811  if (!OID_ISTEMP (WS_OID (classop)))
3812  {
3813  /* make sure the class is flushed before asking for statistics, this handles the case where an index
3814  * has been added to the class but the catalog & statistics do not reflect this fact until the class
3815  * is flushed. We might want to flush instances as well but that shouldn't affect the statistics ? */
3816  if (locator_flush_class (classop) != NO_ERROR)
3817  {
3818  return NULL;
3819  }
3820  int err = stats_get_statistics (WS_OID (classop), 0, &class_->stats);
3821  if (err != NO_ERROR)
3822  {
3823  return NULL;
3824  }
3825  }
3826  }
3827  else
3828  {
3829  CLASS_STATS *stats;
3830 
3831  /* to get the statistics to be updated, it send timestamp as uninitialized value */
3832  int err = stats_get_statistics (WS_OID (classop), class_->stats->time_stamp, &stats);
3833  /* if newly updated statistics are fetched, replace the old one */
3834  if (stats)
3835  {
3836  stats_free_statistics (class_->stats);
3837  class_->stats = stats;
3838  }
3839  else if (err != NO_ERROR)
3840  {
3841  return NULL;
3842  }
3843  }
3844 
3845  return class_;
3846 }
3847 
3848 /*
3849  * sm_get_statistics_force()
3850  * return: class statistics
3851  * classop(in):
3852  */
3853 CLASS_STATS *
3855 {
3856  SM_CLASS *class_;
3857  CLASS_STATS *stats = NULL;
3858  int is_class = 0;
3859 
3860  if (classop != NULL)
3861  {
3862  is_class = locator_is_class (classop, DB_FETCH_QUERY_READ);
3863  if (is_class < 0)
3864  {
3865  return NULL;
3866  }
3867  }
3868  if (is_class && !OID_ISTEMP (WS_OID (classop)))
3869  {
3870  if (au_fetch_class (classop, &class_, AU_FETCH_READ, AU_SELECT) == NO_ERROR)
3871  {
3872  if (class_->stats)
3873  {
3874  stats_free_statistics (class_->stats);
3875  class_->stats = NULL;
3876  }
3877  int err = stats_get_statistics (WS_OID (classop), 0, &stats);
3878  if (err == NO_ERROR)
3879  {
3880  class_->stats = stats;
3881  }
3882  else
3883  {
3884  class_->stats = stats = NULL;
3885  }
3886  }
3887  }
3888 
3889  return stats;
3890 }
3891 
3892 /*
3893  * sm_update_statistics () - Update statistics on the server for the
3894  * particular class or index. When finished, fetch the new statistics and
3895  * cache them with the class.
3896  * return: NO_ERROR on success, non-zero for ERROR
3897  * classop(in): class object
3898  * with_fullscan(in): true iff WITH FULLSCAN
3899  *
3900  * NOTE: We will delay updating statistics until a transaction is committed
3901  * when it is requested during other processing, such as
3902  * "alter table ..." or "create index ...".
3903  */
3904 int
3905 sm_update_statistics (MOP classop, bool with_fullscan)
3906 {
3907  int error = NO_ERROR, is_class = 0;
3908  SM_CLASS *class_;
3909 
3910  assert_release (classop != NULL);
3911 
3912  /* only try to get statistics if we know the class has been flushed if it has a temporary oid, it isn't flushed and
3913  * there are no statistics */
3914 
3915  if (classop != NULL && !OID_ISTEMP (WS_OID (classop)))
3916  {
3917  is_class = locator_is_class (classop, DB_FETCH_QUERY_READ);
3918  if (is_class < 0)
3919  {
3920  return is_class;
3921  }
3922  }
3923  if (is_class > 0)
3924  {
3925 
3926  /* make sure the workspace is flushed before calculating stats */
3928  {
3929  assert (er_errid () != NO_ERROR);
3930  return er_errid ();
3931  }
3932 
3933  error = stats_update_statistics (WS_OID (classop), (with_fullscan ? 1 : 0));
3934  if (error == NO_ERROR)
3935  {
3936  /* only recache if the class itself is cached */
3937  if (classop->object != NULL)
3938  { /* check cache */
3939  /* why are we checking authorization here ? */
3940  error = au_fetch_class_force (classop, &class_, AU_FETCH_READ);
3941  if (error == NO_ERROR)
3942  {
3943  if (class_->stats != NULL)
3944  {
3945  stats_free_statistics (class_->stats);
3946  class_->stats = NULL;
3947  }
3948 
3949  /* make sure the class is flushed before acquiring stats, see comments above in
3950  * sm_get_class_with_statistics */
3951  if (locator_flush_class (classop) != NO_ERROR)
3952  {
3953  assert (er_errid () != NO_ERROR);
3954  return (er_errid ());
3955  }
3956 
3957  /* get the new ones, should do this at the same time as the update operation to avoid two server
3958  * calls */
3959  error = stats_get_statistics (WS_OID (classop), 0, &class_->stats);
3960  }
3961  }
3962  }
3963  }
3964 
3965  return error;
3966 }
3967 
3968 /*
3969  * sm_update_all_statistics() - Update the statistics for all classes
3970  * in the database.
3971  * with_fullscan(in): true iff WITH FULLSCAN
3972  * return: NO_ERROR on success, non-zero for ERROR
3973  */
3974 
3975 int
3976 sm_update_all_statistics (bool with_fullscan)
3977 {
3978  int error = NO_ERROR;
3979  DB_OBJLIST *cl;
3980  SM_CLASS *class_;
3981 
3982  /* make sure the workspace is flushed before calculating stats */
3983  if (locator_all_flush () != NO_ERROR)
3984  {
3985  assert (er_errid () != NO_ERROR);
3986  return er_errid ();
3987  }
3988 
3989  error = stats_update_all_statistics ((with_fullscan ? 1 : 0));
3990  if (error == NO_ERROR)
3991  {
3992  /* Need to reset the statistics cache for all resident classes */
3993  for (cl = ws_Resident_classes; cl != NULL; cl = cl->next)
3994  {
3995  if (!WS_IS_DELETED (cl->op))
3996  {
3997  /* uncache statistics only if object is cached - MOP trickery */
3998  if (cl->op->object != NULL)
3999  {
4000  class_ = (SM_CLASS *) cl->op->object;
4001  if (class_->stats != NULL)
4002  {
4003  stats_free_statistics (class_->stats);
4004  class_->stats = NULL;
4005  }
4006  /* make sure the class is flushed but quit if an error happens */
4007  if (locator_flush_class (cl->op) != NO_ERROR)
4008  {
4009  assert (er_errid () != NO_ERROR);
4010  return (er_errid ());
4011  }
4012  error = stats_get_statistics (WS_OID (cl->op), 0, &class_->stats);
4013  }
4014  }
4015  }
4016  }
4017 
4018  return error;
4019 }
4020 
4021 /*
4022  * sm_update_all_catalog_statistics()
4023  * return: NO_ERROR on success, non-zero for ERROR
4024  * with_fullscan(in): true iff WITH FULLSCAN
4025  */
4026 
4027 int
4029 {
4030  int error = NO_ERROR;
4031  int i;
4032 
4033  const char *classes[] = {
4039  };
4040 
4041  for (i = 0; classes[i] != NULL && error == NO_ERROR; i++)
4042  {
4043  error = sm_update_catalog_statistics (classes[i], with_fullscan);
4044  }
4045 
4046  return error;
4047 }
4048 
4049 /*
4050  * sm_update_catalog_statistics()
4051  * return: NO_ERROR on success, non-zero for ERROR
4052  * class_name(in):
4053  * with_fullscan(in): true iff WITH FULLSCAN
4054  */
4055 
4056 int
4057 sm_update_catalog_statistics (const char *class_name, bool with_fullscan)
4058 {
4059  int error = NO_ERROR;
4060  DB_OBJECT *obj;
4061 
4062  obj = db_find_class (class_name);
4063  if (obj != NULL)
4064  {
4065  error = sm_update_statistics (obj, with_fullscan);
4066  }
4067  else
4068  {
4069  assert (er_errid () != NO_ERROR);
4070  error = er_errid ();
4071  }
4072 
4073  return error;
4074 }
4075 
4076 /* TRIGGER FUNCTIONS */
4077 /*
4078  * sm_get_trigger_cache() - used to access a trigger cache within a class object.
4079  * It is called by the trigger manager and object manager.
4080  * The "attribute" argument may be NULL in which case the class
4081  * level trigger cache is returned. If the "attribute" argument
4082  * is set, an attribute level trigger cache is returned.
4083  * return: NO_ERROR on success, non-zero for ERROR
4084  * classop(in): class object
4085  * attribute(in): attribute name
4086  * class_attribute(in): flag indicating class attribute name
4087  * cache(out): cache pointer (returned)
4088  */
4089 
4090 int
4091 sm_get_trigger_cache (DB_OBJECT * classop, const char *attribute, int class_attribute, void **cache)
4092 {
4093  int error = NO_ERROR;
4094  SM_ATTRIBUTE *att;
4095  SM_CLASS *class_;
4096  OID *oid;
4097 
4098  oid = WS_OID (classop);
4099  *cache = NULL;
4100 
4101  error = au_fetch_class (classop, &class_, AU_FETCH_READ, AU_SELECT);
4102  if (error != NO_ERROR)
4103  {
4104  if (WS_IS_DELETED (classop) && er_errid () != ER_HEAP_UNKNOWN_OBJECT)
4105  {
4107  error = er_errid ();
4108  }
4109 
4110  return error;
4111  }
4112 
4113  if (attribute == NULL)
4114  {
4115  *cache = class_->triggers;
4116  }
4117  else
4118  {
4119  att = classobj_find_attribute (class_, attribute, class_attribute);
4120  if (att != NULL)
4121  {
4122  *cache = att->triggers;
4123  }
4124  }
4125 
4126  return NO_ERROR;
4127 }
4128 
4129 #if defined(ENABLE_UNUSED_FUNCTION)
4130 /*
4131  * sm_update_trigger_cache() - This adds or modifies the trigger cache pointer
4132  * in the schema. The class is also marked as dirty so
4133  * the updated cache can be stored with the class definition.
4134  * return: NO_ERROR on success, non-zero for ERROR
4135  * classop(in): class object
4136  * attribute(in): attribute name
4137  * class_attribute(in): flag indicating class attribute name
4138  * cache(in/out): cache to update
4139  */
4140 
4141 static int
4142 sm_update_trigger_cache (DB_OBJECT * classop, const char *attribute, int class_attribute, void *cache)
4143 {
4144  int error = NO_ERROR;
4145  SM_CLASS *class_;
4146  SM_ATTRIBUTE *att;
4147 
4148  error = au_fetch_class (classop, &class_, AU_FETCH_UPDATE, AU_ALTER);
4149 
4150  if (error == NO_ERROR)
4151  {
4152  if (attribute == NULL)
4153  {
4154  class_->triggers = cache;
4155  }
4156  else
4157  {
4158  att = classobj_find_attribute (class_, attribute, class_attribute);
4159  if (att != NULL)
4160  {
4161  att->triggers = cache;
4162  }
4163  }
4164 
4165  /* turn off the cache validation bits so we have to recalculate them next time */
4166  class_->triggers_validated = 0;
4167  }
4168  return (error);
4169 }
4170 #endif /* ENABLE_UNUSED_FUNCTION */
4171 
4172 /*
4173  * sm_active_triggers() - Quick check to see if the class has active triggers.
4174  * Returns <0 if errors were encountered.
4175  * return: non-zero if the class has active triggers
4176  * class_mop(in): class mop
4177  * class(in/out): class structure
4178  * event_type(in) : event type of trigger to check.
4179  */
4180 int
4181 sm_active_triggers (MOP class_mop, SM_CLASS * class_, DB_TRIGGER_EVENT event_type)
4182 {
4183  SM_ATTRIBUTE *att;
4184  int status;
4185  bool has_event_type_triggers = false;
4186  LC_FETCH_VERSION_TYPE read_fetch_instance_version;
4187 
4188  /* If trigger firing has been disabled we do not want to search for active triggers. */
4189  if (tr_get_execution_state () != true)
4190  {
4191  return (0);
4192  }
4193 
4194  if (event_type == TR_EVENT_ALL && (class_->triggers_validated))
4195  {
4196  return (class_->has_active_triggers);
4197  }
4198 
4199  /* need locking when fetch in order to get active triggers only */
4200  read_fetch_instance_version = TM_TRAN_READ_FETCH_VERSION ();
4202  class_->has_active_triggers = 0;
4203 
4204  status = tr_active_schema_cache (class_mop, class_->triggers, event_type, &has_event_type_triggers);
4205  if (status < 0)
4206  {
4207  db_set_read_fetch_instance_version (read_fetch_instance_version);
4208  return status;
4209  }
4210  else if (status)
4211  {
4212  class_->has_active_triggers = 1;
4213  }
4214 
4215  /* no class level event type triggers, look for attribute level triggers */
4216  for (att = class_->ordered_attributes; att != NULL && !has_event_type_triggers; att = att->order_link)
4217  {
4218  status = tr_active_schema_cache (class_mop, att->triggers, event_type, &has_event_type_triggers);
4219  if (status < 0)
4220  {
4221  db_set_read_fetch_instance_version (read_fetch_instance_version);
4222  return status;
4223  }
4224  else if (status)
4225  {
4226  class_->has_active_triggers = 1;
4227  }
4228  }
4229 
4230  if (!has_event_type_triggers)
4231  {
4232  for (att = class_->class_attributes; att != NULL; att = (SM_ATTRIBUTE *) att->header.next)
4233  {
4234  status = tr_active_schema_cache (class_mop, att->triggers, event_type, &has_event_type_triggers);
4235  if (status < 0)
4236  {
4237  db_set_read_fetch_instance_version (read_fetch_instance_version);
4238  return status;
4239  }
4240  else if (status)
4241  {
4242  class_->has_active_triggers = 1;
4243  }
4244  }
4245  }
4246 
4247  /* don't repeat this process again */
4248  class_->triggers_validated = 1;
4249 
4250  db_set_read_fetch_instance_version (read_fetch_instance_version);
4251  return ((has_event_type_triggers) ? 1 : 0);
4252 }
4253 
4254 /*
4255  * sm_class_has_triggers() - This function can be used to determine if
4256  * there are any triggers defined for a particular class.
4257  * This could be used to optimize execution paths for the case where
4258  * we know there will be no trigger processing.
4259  * It is important that the trigger support not slow down operations
4260  * on classes that do not have triggers.
4261  * return: NO_ERROR on success, non-zero for ERROR
4262  * classop(in): class object
4263  * status_ptr(in): return status (non-zero if triggers for the class)
4264  * event_type(in): event type of trigger to find.
4265  */
4266 
4267 int
4268 sm_class_has_triggers (DB_OBJECT * classop, int *status_ptr, DB_TRIGGER_EVENT event_type)
4269 {
4270  int error;
4271  SM_CLASS *class_;
4272  int status;
4273 
4274  if (classop == NULL)
4275  {
4277  return ER_OBJ_INVALID_ARGUMENT;
4278  }
4279 
4280  error = au_fetch_class (classop, &class_, AU_FETCH_READ, AU_SELECT);
4281  if (error == NO_ERROR)
4282  {
4283  status = sm_active_triggers (classop, class_, event_type);
4284  if (status < 0)
4285  {
4286  assert (er_errid () != NO_ERROR);
4287  error = er_errid ();
4288  }
4289  else
4290  {
4291  *status_ptr = status;
4292  }
4293  }
4294 
4295  return error;
4296 }
4297 
4298 /*
4299  * sm_invalidate_trigger_cache() - This is called by the trigger manager
4300  * when a trigger associated with this class has undergone a status change.
4301  * When this happens, we need to recalculate the state of the
4302  * has_active_triggers flag that is cached in the class structure.
4303  * return: NO_ERROR on success, non-zero for ERROR
4304  * classop(in): class object
4305  */
4306 
4307 int
4309 {
4310  int error;
4311  SM_CLASS *class_;
4312 
4313  error = au_fetch_class (classop, &class_, AU_FETCH_READ, AU_SELECT);
4314  if (error == NO_ERROR)
4315  {
4316  class_->triggers_validated = 0;
4317  }
4318 
4319  return error;
4320 }
4321 
4322 /*
4323  * alter_trigger_cache() - This function encapsulates the mechanics of updating
4324  * the trigger caches on a class. It calls out to tr_ functions to perform
4325  * the actual modification of the caches.
4326  * return: NO_ERROR on success, non-zero for ERROR
4327  * class(in/out): class structure
4328  * attribute(in): attribute name
4329  * class_attribute(in): non-zero if class attribute name
4330  * trigger(in/out): trigger object to drop/add
4331  * drop_it(in): non-zero if we're dropping the trigger object
4332  */
4333 
4334 static int
4335 alter_trigger_cache (SM_CLASS * class_, const char *attribute, int class_attribute, DB_OBJECT * trigger, int drop_it)
4336 {
4337  int error = NO_ERROR;
4338  TR_SCHEMA_CACHE **location = NULL;
4339  TR_CACHE_TYPE ctype;
4340  SM_ATTRIBUTE *att;
4341 
4342  /* find the slot containing the appropriate schema cache */
4343  if (attribute == NULL)
4344  {
4345  location = &class_->triggers;
4346  }
4347  else
4348  {
4349  att = classobj_find_attribute (class_, attribute, class_attribute);
4350  if (att != NULL)
4351  {
4352  location = &att->triggers;
4353  }
4354  }
4355 
4356  if (location != NULL)
4357  {
4358  if (drop_it)
4359  {
4360  if (*location != NULL)
4361  {
4362  error = tr_drop_cache_trigger (*location, trigger);
4363  }
4364  }
4365  else
4366  {
4367  /* we're adding it, create a cache if one doesn't exist */
4368  if (*location == NULL)
4369  {
4370  ctype = (attribute == NULL) ? TR_CACHE_CLASS : TR_CACHE_ATTRIBUTE;
4371  *location = tr_make_schema_cache (ctype, NULL);
4372  }
4373  if (*location == NULL)
4374  {
4375  assert (er_errid () != NO_ERROR);
4376  error = er_errid (); /* couldn't allocate one */
4377  }
4378  else
4379  {
4380  error = tr_add_cache_trigger (*location, trigger);
4381  }
4382  }
4383  }
4384 
4385  /* Turn off the cache validation bits so we have to recalculate them next time. This is VERY important. */
4386  class_->triggers_validated = 0;
4387 
4388  return error;
4389 }
4390 
4391 /*
4392  * alter_trigger_hierarchy() - This function walks a subclass hierarchy
4393  * performing an alteration to the trigger caches.
4394  * This can be called in two ways. If the trigger attribute is NULL,
4395  * it will walk the hierarchy obtaining the appropriate write locks
4396  * on the subclasses but will not make any changes.
4397  * This is used to make sure that we can in fact lock all the affected
4398  * subclasses before we try to perform the operation.
4399  * When the trigger argument is non-NULL, we walk the hierarchy
4400  * in the same way but this time we actually modify the trigger caches.
4401  * The recursion stops when we encounter a class that has a local
4402  * "shadow" attribute of the given name. For class triggers,
4403  * no shadowing is possible so we go all the way to the bottom.
4404  * I'm not sure if this makes sense, we may need to go all the way
4405  * for attribute triggers too.
4406  * return: NO_ERROR on success, non-zero for ERROR
4407  * classop(in): class MOP
4408  * attribute(in): target attribute (optional)
4409  * class_attribute(in): non-zero if class attribute
4410  * target_class(in):
4411  * trigger(in/out): trigger object (NULL if just locking the hierarchy)
4412  * drop_it(in): non-zero if we're going to drop the trigger
4413  */
4414 
4415 static int
4416 alter_trigger_hierarchy (DB_OBJECT * classop, const char *attribute, int class_attribute, DB_OBJECT * target_class,
4417  DB_OBJECT * trigger, int drop_it)
4418 {
4419  int error = NO_ERROR;
4421  SM_CLASS *class_;
4422  SM_ATTRIBUTE *att;
4423  DB_OBJLIST *u;
4424  int dive;
4425 
4426  /* fetch the class */
4427  mode = (trigger == NULL) ? AU_FETCH_WRITE : AU_FETCH_UPDATE;
4428  error = au_fetch_class_force (classop, &class_, mode);
4429  if (error != NO_ERROR)
4430  {
4431  if (WS_IS_DELETED (classop))
4432  {
4433  error = NO_ERROR; /* in this case, just ignore the error */
4434  }
4435  }
4436  else
4437  {
4438  dive = 1;
4439  if (attribute != NULL)
4440  {
4441  /* dive only if we don't have a shadow of this attribute */
4442  if (classop != target_class)
4443  {
4444  att = classobj_find_attribute (class_, attribute, class_attribute);
4445  if (att == NULL || att->class_mop != target_class)
4446  {
4447  dive = 0;
4448  }
4449  }
4450  }
4451 
4452  if (dive)
4453  {
4454  /* dive to the bottom */
4455  for (u = class_->users; u != NULL && !error; u = u->next)
4456  {
4457  error = alter_trigger_hierarchy (u->op, attribute, class_attribute, target_class, trigger, drop_it);
4458  }
4459  }
4460 
4461  /* if everything went ok, alter the cache */
4462  if (!error && trigger != NULL)
4463  {
4464  error = alter_trigger_cache (class_, attribute, class_attribute, trigger, drop_it);
4465  }
4466  }
4467  return (error);
4468 }
4469 
4470 /*
4471  * sm_add_trigger() - This is called by the trigger manager to associate
4472  * a trigger object with a class.
4473  * The trigger is added to the trigger list for this class and all of
4474  * its subclasses.
4475  * ALTER authorization is required for the topmost class, the subclasses
4476  * are fetched without authorization because the trigger must be added
4477  * to them to maintain the "is-a" relationship.
4478  * The class and the affected subclasses are marked dirty so the new
4479  * trigger will be stored.
4480  * This function must create a trigger cache and add the trigger
4481  * object by calling back to the trigger manager functions
4482  * tr_make_schema_cache, and tr_add_schema_cache at the appropriate times.
4483  * This lets the schema manager perform the class hierarchy walk,
4484  * while the trigger manager still has control over how the caches
4485  * are created and updated.
4486  * return: NO_ERROR on success, non-zero for ERROR
4487  * classop(in): class on which to add a trigger
4488  * attribute(in): attribute name (optional)
4489  * class_attribute(in): non-zero if its a class attribute name
4490  * trigger (in/out): trigger object to add
4491  */
4492 
4493 int
4494 sm_add_trigger (DB_OBJECT * classop, const char *attribute, int class_attribute, DB_OBJECT * trigger)
4495 {
4496  int error = NO_ERROR;
4497  SM_CLASS *class_;
4498 
4499  /* first fetch with authorization on the outer class */
4500  error = au_fetch_class (classop, &class_, AU_FETCH_UPDATE, AU_ALTER);
4501  if (error == NO_ERROR)
4502  {
4503  /* Make sure all the affected subclasses are accessible. */
4504  error = alter_trigger_hierarchy (classop, attribute, class_attribute, classop, NULL, 0);
4505  if (error == NO_ERROR)
4506  {
4507  error = alter_trigger_hierarchy (classop, attribute, class_attribute, classop, trigger, 0);
4508  }
4509  }
4510 
4511  return error;
4512 }
4513 
4514 /*
4515  * sm_drop_trigger() - called by the trigger manager when a trigger is dropped.
4516  * It will walk the class hierarchy and remove the trigger from
4517  * the caches of this class and any subclasses that inherit the trigger.
4518  * return: NO_ERROR on success, non-zero for ERROR
4519  * classop(in): class object
4520  * attribute(in): attribute name
4521  * class_attribute(in): non-zero if class attribute
4522  * trigger(in/out): trigger object to drop
4523  */
4524 
4525 int
4526 sm_drop_trigger (DB_OBJECT * classop, const char *attribute, int class_attribute, DB_OBJECT * trigger)
4527 {
4528  int error = NO_ERROR;
4529  SM_CLASS *class_;
4530 
4531  /* first fetch with authorization on the outer class */
4532  error = au_fetch_class (classop, &class_, AU_FETCH_UPDATE, AU_ALTER);
4533 
4534  /* if the error is "deleted object", just ignore the request since the trigger will be marked invalid and the class
4535  * can't possibly be pointing to it */
4536  if (error == ER_HEAP_UNKNOWN_OBJECT)
4537  {
4538  error = NO_ERROR;
4539  }
4540  else if (error == NO_ERROR)
4541  {
4542  /* Make sure all the affected subclasses are accessible. */
4543  error = alter_trigger_hierarchy (classop, attribute, class_attribute, classop, NULL, 1);
4544  if (error == NO_ERROR)
4545  {
4546  error = alter_trigger_hierarchy (classop, attribute, class_attribute, classop, trigger, 1);
4547  }
4548  }
4549 
4550  return error;
4551 }
4552 
4553 /* MISC INFORMATION FUNCTIONS */
4554 /*
4555  * sm_get_ch_name() - Returns the name of a class associated with an object.
4556  * If the object is a class, its own class name is returned.
4557  * If the object is an instance, the name of the instance's class
4558  * is returned.
4559  * Authorization is ignored for this one case.
4560  * return: class name
4561  * op(in): class or instance object
4562  */
4563 
4564 const char *
4566 {
4567  SM_CLASS *class_;
4568  const char *name = NULL;
4569 
4570  if (op != NULL)
4571  {
4572  if (au_fetch_class_force (op, &class_, AU_FETCH_READ) == NO_ERROR)
4573  {
4574  name = sm_ch_name ((MOBJ) class_);
4575  }
4576  }
4577 
4578  return name;
4579 }
4580 
4581 #if defined(ENABLE_UNUSED_FUNCTION)
4582 /*
4583  * sm_get_class_name_internal()
4584  * sm_get_class_name()
4585  * sm_get_class_name_not_null() - Returns the name of a class associated with
4586  * an object. If the object is a class, its own class name is returned.
4587  * If the object is an instance, the name of the instance's class
4588  * is returned.
4589  * Authorization is ignored for this one case.
4590  * This function is lighter than sm_get_ch_name(), and returns not null.
4591  * return: class name
4592  * op(in): class or instance object
4593  * return_null(in):
4594  */
4595 
4596 static const char *
4597 sm_get_class_name_internal (MOP op, bool return_null)
4598 {
4599  SM_CLASS *class_ = NULL;
4600  const char *name = NULL;
4601  int save;
4602 
4603  if (op != NULL)
4604  {
4605  AU_DISABLE (save);
4606  if (au_fetch_class (op, &class_, AU_FETCH_READ, AU_SELECT) == NO_ERROR)
4607  {
4608  if (class_)
4609  {
4610  name = class_->header.name;
4611  }
4612  }
4613  AU_ENABLE (save);
4614  }
4615 
4616  return (name ? name : (return_null ? NULL : ""));
4617 }
4618 
4619 static const char *
4620 sm_get_class_name (MOP op)
4621 {
4622  return sm_get_class_name_internal (op, true);
4623 }
4624 
4625 static const char *
4626 sm_get_class_name_not_null (MOP op)
4627 {
4628  return sm_get_class_name_internal (op, false);
4629 }
4630 #endif /* ENABLE_UNUSED_FUNCTION */
4631 
4632 /*
4633  * sm_is_subclass() - Checks to see if one class is a subclass of another.
4634  * return: 1 if classmop is subclass of supermop, 0 if classmop is not
4635  * subclass if supermop, negative for errors.
4636  * classmop(in): possible sub class
4637  * supermop(in): possible super class
4638  */
4639 
4640 int
4641 sm_is_subclass (MOP classmop, MOP supermop)
4642 {
4643  DB_OBJLIST *s;
4644  SM_CLASS *class_;
4645  int found;
4646 
4647  found = au_fetch_class (classmop, &class_, AU_FETCH_READ, AU_SELECT);
4648  if (found < 0)
4649  {
4650  /* Error. */
4651  ASSERT_ERROR ();
4652  return found;
4653  }
4654 
4655  for (s = class_->inheritance; s != NULL; s = s->next)
4656  {
4657  if (s->op == supermop)
4658  {
4659  /* Found super class. */
4660  return 1;
4661  }
4662  }
4663 
4664  /* Recursive check on super classes. */
4665  for (s = class_->inheritance; s != NULL; s = s->next)
4666  {
4667  found = sm_is_subclass (s->op, supermop);
4668  if (found != 0)
4669  {
4670  /* Found or error was returned. */
4671  assert (found > 0 || er_errid () != NO_ERROR);
4672  return found;
4673  }
4674  /* Not found, continue searching. */
4675  }
4676 
4677  /* Not found. */
4678  return 0;
4679 }
4680 
4681 /*
4682  * sm_is_partition () - Verify if a class is a partition of another class
4683  * return : > 0 if true, 0 if false, < 0 for error
4684  * classmop (in) : partition candidate
4685  * supermop (in) : partitioned class
4686  */
4687 int
4688 sm_is_partition (MOP classmop, MOP supermop)
4689 {
4690  SM_CLASS *class_;
4691  int error;
4692 
4693  error = au_fetch_class (classmop, &class_, AU_FETCH_READ, AU_SELECT);
4694  if (error != NO_ERROR)
4695  {
4696  return error;
4697  }
4698 
4699  if (class_->partition != NULL && class_->users == NULL)
4700  {
4701  if (class_->inheritance != NULL && class_->inheritance->op == supermop)
4702  {
4703  /* Notice we only verify the first superclass in the list. If class_ is a partition, it should only have one
4704  * superclass, we're not interested in the rest of the list */
4705  return 1;
4706  }
4707  }
4708 
4709  return 0;
4710 }
4711 
4712 /*
4713  * sm_object_size_quick() - Calculate the memory size of an instance.
4714  * Called only by the workspace statistics functions.
4715  * Like sm_object_size but doesn't do any fetches.
4716  * return: byte size of instance
4717  * class(in): class structure
4718  * obj(in): pointer to instance memory
4719  */
4720 
4721 int
4723 {
4724  SM_ATTRIBUTE *att;
4725  int size = 0;
4726 
4727  if (class_ != NULL && obj != NULL)
4728  {
4729  size = class_->object_size;
4730  for (att = class_->attributes; att != (void *) 0; att = (SM_ATTRIBUTE *) att->header.next)
4731  {
4732  if (att->type->variable_p)
4733  {
4734  size += att->type->get_mem_size_of_mem (obj + att->offset);
4735  }
4736  }
4737  }
4738 
4739  return size;
4740 }
4741 
4742 #if defined(ENABLE_UNUSED_FUNCTION)
4743 /*
4744  * sm_object_disk_size() - Calculates the disk size of an object.
4745  * General information function that should be pretty accurate but
4746  * not guaranteed to be absolutely accurate.
4747  * return: byte size of disk representation of object
4748  * op(in): class or instance object
4749  */
4750 
4751 static int
4752 sm_object_disk_size (MOP op)
4753 {
4754  SM_CLASS *class_;
4755  MOBJ obj;
4756  int size, pin;
4757 
4758  size = 0;
4759  if (au_fetch_class (op->class_mop, &class_, AU_FETCH_READ, AU_SELECT) == NO_ERROR)
4760  {
4761  obj = NULL;
4762  if (locator_is_class (op, DB_FETCH_READ))
4763  {
4764  au_fetch_class (op, (SM_CLASS **) (&obj), AU_FETCH_READ, AU_SELECT);
4765  if (obj != NULL)
4766  {
4767  size = tf_object_size ((MOBJ) class_, obj);
4768  }
4769  }
4770  else
4771  {
4773  if (obj != NULL)
4774  {
4775  /* probably woudn't have to pin here since we don't allocate */
4776  pin = ws_pin (op, 1);
4777  size = tf_object_size ((MOBJ) class_, obj);
4778  (void) ws_pin (op, pin);
4779  }
4780  }
4781  }
4782 
4783  return size;
4784 }
4785 #endif /* ENABLE_UNUSED_FUNCTION */
4786 
4787 #if defined(CUBRID_DEBUG)
4788 /*
4789  * sm_dump() - Debug function to dump internal information about class objects.
4790  * return: none
4791  * classmop(in): class object
4792  */
4793 
4794 static void
4795 sm_print (MOP classmop)
4796 {
4797  SM_CLASS *class_;
4798 
4799  if (au_fetch_class (classmop, &class_, AU_FETCH_READ, AU_SELECT) == NO_ERROR)
4800  {
4801  classobj_print (class_);
4802  }
4803 }
4804 #endif
4805 
4806 /* LOCATOR SUPPORT FUNCTIONS */
4807 /*
4808  * sm_ch_name() - Given a pointer to a class object in memory,
4809  * return the name. Used by the transaction locator.
4810  * return: class name
4811  * classobj(in): class structure
4812  */
4813 
4814 const char *
4815 sm_ch_name (const MOBJ clobj)
4816 {
4817  SM_CLASS_HEADER *header;
4818  const char *ch_name = NULL;
4819 
4820  if (clobj != NULL)
4821  {
4822  header = (SM_CLASS_HEADER *) clobj;
4823  ch_name = header->ch_name;
4824 
4825  assert (header->ch_type == SM_META_ROOT || header->ch_type == SM_META_CLASS);
4826 #if !defined(NDEBUG)
4827  if (header->ch_type == SM_META_CLASS)
4828  {
4829  assert (ch_name != NULL);
4830  }
4831 #endif
4832  }
4833 
4834  return ch_name;
4835 }
4836 
4837 /*
4838  * sm_ch_heap() - Support function for the transaction locator.
4839  * This returns a pointer to the heap file identifier in a class.
4840  * This will work for either classes or the root class.
4841  * return: HFID of class
4842  * clobj(in): pointer to class structure in memory
4843  */
4844 
4845 HFID *
4847 {
4848  SM_CLASS_HEADER *header;
4849  HFID *ch_heap = NULL;
4850 
4851  if (clobj != NULL)
4852  {
4853  header = (SM_CLASS_HEADER *) clobj;
4854  ch_heap = &(header->ch_heap);
4855  }
4856 
4857  return ch_heap;
4858 }
4859 
4860 /*
4861  * sm_ch_rep_dir () - Support function for the transaction locator.
4862  * This returns a pointer to the oid of representation directory in a class.
4863  * This will work for either classes or the root class.
4864  * return: oid of representation directory
4865  * clobj(in): pointer to class structure in memory
4866  */
4867 
4868 OID *
4870 {
4871  SM_CLASS_HEADER *header;
4872  OID *ch_rep_dir_p = NULL;
4873 
4874  if (clobj != NULL)
4875  {
4876  header = (SM_CLASS_HEADER *) clobj;
4877  ch_rep_dir_p = &(header->ch_rep_dir);
4878  }
4879 
4880  return ch_rep_dir_p;
4881 }
4882 
4883 /*
4884  * sm_get_ch_heap() - Return the HFID of a class given a MOP.
4885  * Like sm_ch_heap but takes a MOP.
4886  * return: hfid of class
4887  * classmop(in): class object
4888  */
4889 
4890 HFID *
4892 {
4893  SM_CLASS *class_ = NULL;
4894  HFID *ch_heap;
4895 
4896  ch_heap = NULL;
4897  if (locator_is_class (classmop, DB_FETCH_READ) > 0)
4898  {
4899  if (au_fetch_class (classmop, &class_, AU_FETCH_READ, AU_SELECT) == NO_ERROR)
4900  {
4901  ch_heap = sm_ch_heap ((MOBJ) class_);
4902  }
4903  }
4904 
4905  return ch_heap;
4906 }
4907 
4908 #if 0 /* TODO - do not use */
4909 /*
4910  * sm_get_ch_rep_dir () - Return the OID of representation directory
4911  of a class given a MOP.
4912  * return: oid of representation directory
4913  * classmop(in): class object
4914  */
4915 
4916 OID *
4917 sm_get_ch_rep_dir (MOP classmop)
4918 {
4919  SM_CLASS *class_ = NULL;
4920  OID *ch_rep_dir_p = NULL;
4921 
4922  ch_rep_dir_p = NULL;
4923  if (locator_is_class (classmop, DB_FETCH_READ))
4924  {
4925  if (au_fetch_class (classmop, &class_, AU_FETCH_READ, AU_SELECT) == NO_ERROR)
4926  {
4927  ch_rep_dir_p = sm_ch_rep_dir ((MOBJ) class_);
4928  }
4929  }
4930 
4931  return ch_rep_dir_p;
4932 }
4933 #endif
4934 
4935 /*
4936  * sm_has_indexes() - This is used to determine if there are any indexes
4937  * associated with a particular class.
4938  * Currently, this is used only by the locator so
4939  * that when deleted instances are flushed, we can set the appropriate
4940  * flags so that the indexes on the server will be updated. For updated
4941  * objects, the "has indexes" flag is returned by tf_mem_to_disk().
4942  * Since we don't transform deleted objects however, we need a different
4943  * mechanism for determining whether indexes exist. Probably we should
4944  * be using this function for all cases and remove the flag from the
4945  * tf_ interface.
4946  * This will return an error code if the class could not be fetched for
4947  * some reason. Authorization is NOT checked here.
4948  * All of the constraint information is also contained on the class
4949  * property list as well as the class constraint cache. The class
4950  * constraint cache is probably easier and faster to search than
4951  * scanning over each attribute. Something that we might want to change
4952  * later.
4953  * return: Non-zero if there are indexes defined
4954  * classmop(in): class pointer
4955  */
4956 
4957 bool
4959 {
4960  SM_CLASS *class_;
4961  SM_CLASS_CONSTRAINT *con;
4962  bool has_indexes = false;
4963 
4964  class_ = (SM_CLASS *) classobj;
4965  for (con = class_->constraints; con != NULL; con = con->next)
4966  {
4968  {
4969  has_indexes = true;
4970  break;
4971  }
4972  }
4973 
4974  return has_indexes;
4975 }
4976 
4977 #if defined(ENABLE_UNUSED_FUNCTION)
4978 /*
4979  * sm_has_constraint() - This is used to determine if a constraint is
4980  * associated with a particular class.
4981  * return: Non-zero if there are constraints defined
4982  * classobj(in): class pointer
4983  * constraint(in): the constraint to look for
4984  */
4985 
4986 static int
4987 sm_has_constraint (MOBJ classobj, SM_ATTRIBUTE_FLAG constraint)
4988 {
4989  SM_CLASS *class_;
4990  SM_ATTRIBUTE *att;
4991  int has_constraint = 0;
4992 
4993  class_ = (SM_CLASS *) classobj;
4994  for (att = class_->attributes; att != NULL; att = (SM_ATTRIBUTE *) att->header.next)
4995  {
4996  if (att->flags & constraint)
4997  {
4998  has_constraint = 1;
4999  break;
5000  }
5001  }
5002 
5003  return has_constraint;
5004 }
5005 #endif /* ENABLE_UNUSED_FUNCTION */
5006 
5007 /*
5008  * sm_class_constraints() - Return a pointer to the class constraint cache.
5009  * A NULL pointer is returned is an error occurs.
5010  * return: class constraint
5011  * classop(in): class pointer
5012  */
5013 
5016 {
5017  int error = NO_ERROR;
5018  SM_CLASS *class_;
5019  SM_CLASS_CONSTRAINT *constraints = NULL;
5020 
5021  error = au_fetch_class (classop, &class_, AU_FETCH_READ, AU_SELECT);
5022  if (error == NO_ERROR)
5023  {
5024  constraints = class_->constraints;
5025  }
5026 
5027  return constraints;
5028 }
5029 
5030 /* INTERPRETER SUPPORT FUNCTIONS */
5031 /*
5032  * sm_find_class() - Given a class name, return the class object.
5033  * All this really does is call locator_find_class but it makes sure the
5034  * search is case insensitive.
5035  * return: class object
5036  * name(in): class name
5037  */
5038 
5039 MOP
5040 sm_find_class (const char *name)
5041 {
5042  char realname[SM_MAX_IDENTIFIER_LENGTH];
5043 
5044  sm_downcase_name (name, realname, SM_MAX_IDENTIFIER_LENGTH);
5045 
5046  return (locator_find_class (realname));
5047 }
5048 
5049 /*
5050  * sm_find_class_with_purpose() - Given a class name, find the class.
5051  * All this really does is call locator_find_class but it makes sure
5052  * the search is case insensitive.
5053  * return: class object
5054  * name(in): class name
5055  * for_update(in): true, if search the class for update purpose
5056  */
5057 
5058 MOP
5059 sm_find_class_with_purpose (const char *name, bool for_update)
5060 {
5061  char realname[SM_MAX_IDENTIFIER_LENGTH];
5062 
5063  sm_downcase_name (name, realname, SM_MAX_IDENTIFIER_LENGTH);
5064 
5065  return (locator_find_class_with_purpose (realname, for_update));
5066 }
5067 
5068 /*
5069  * find_attribute_op() - Given the MOP of an object and an attribute name,
5070  * return a pointer to the class structure and a pointer to the
5071  * attribute structure with the given name.
5072  * return: NO_ERROR on success, non-zero for ERROR
5073  * op(in): class or instance MOP
5074  * name(in): attribute name
5075  * classp(out): return pointer to class
5076  * attp(out): return pointer to attribute
5077  */
5078 
5079 static int
5080 find_attribute_op (MOP op, const char *name, SM_CLASS ** classp, SM_ATTRIBUTE ** attp)
5081 {
5082  int error = NO_ERROR;
5083  SM_CLASS *class_;
5084  SM_ATTRIBUTE *att;
5085 
5086  if (!sm_check_name (name))
5087  {
5088  assert (er_errid () != NO_ERROR);
5089  error = er_errid ();
5090  }
5091  else
5092  {
5093  error = au_fetch_class (op, &class_, AU_FETCH_READ, AU_SELECT);
5094  if (error == NO_ERROR)
5095  {
5096  att = classobj_find_attribute (class_, name, 0);
5097  if (att == NULL)
5098  {
5099  ERROR1 (error, ER_SM_ATTRIBUTE_NOT_FOUND, name);
5100  }
5101  else
5102  {
5103  *classp = class_;
5104  *attp = att;
5105  }
5106  }
5107  }
5108 
5109  return error;
5110 }
5111 
5112 #if defined(ENABLE_UNUSED_FUNCTION)
5113 /*
5114  * sm_get_att_domain() - Get the domain descriptor for an attribute.
5115  * This should be replaced with sm_get_att_info.
5116  * return: NO_ERROR on success, non-zero for ERROR
5117  * op(in): class object
5118  * name(in): attribute name
5119  * domain(out): returned pointer to domain
5120  */
5121 
5122 static int
5123 sm_get_att_domain (MOP op, const char *name, TP_DOMAIN ** domain)
5124 {
5125  int error = NO_ERROR;
5126  SM_ATTRIBUTE *att;
5127  SM_CLASS *class_;
5128 
5129  if ((error = find_attribute_op (op, name, &class_, &att)) == NO_ERROR)
5130  {
5131  sm_filter_domain (att->domain, NULL);
5132  *domain = att->domain;
5133  }
5134 
5135  return error;
5136 }
5137 #endif /* ENABLE_UNUSED_FUNCTION */
5138 
5139 /*
5140  * sm_get_att_name() - Get the name of an attribute with its id.
5141  * return: attribute name
5142  * classop(in): class object
5143  * id(in): attribute ID
5144  */
5145 
5146 const char *
5147 sm_get_att_name (MOP classop, int id)
5148 {
5149  const char *name = NULL;
5150  int error;
5151  SM_CLASS *class_;
5152  SM_ATTRIBUTE *att;
5153 
5154  error = au_fetch_class (classop, &class_, AU_FETCH_READ, AU_SELECT);
5155  if (error == NO_ERROR)
5156  {
5157  att = classobj_find_attribute_id (class_, id, 0);
5158  if (att != NULL)
5159  {
5160  name = att->header.name;
5161  }
5162  }
5163 
5164  return name;
5165 }
5166 
5167 /*
5168  * sm_att_id() - Returns the internal id number assigned to the attribute.
5169  * return: attribute id number
5170  * classop(in): class object
5171  * name(in): attribute
5172  */
5173 
5174 int
5175 sm_att_id (MOP classop, const char *name)
5176 {
5177  SM_CLASS *class_;
5178  SM_ATTRIBUTE *att = NULL;
5179  int id;
5180 
5181  id = -1;
5182  if (find_attribute_op (classop, name, &class_, &att) == NO_ERROR)
5183  {
5184  id = att->id;
5185  }
5186 
5187  return id;
5188 }
5189 
5190 /*
5191  * sm_att_type_id() - Return the type constant for the basic
5192  * type of an attribute.
5193  * return: type identifier
5194  * classop(in): class object
5195  * name(in): attribute name
5196  */
5197 
5198 DB_TYPE
5199 sm_att_type_id (MOP classop, const char *name)
5200 {
5201  SM_CLASS *class_;
5202  SM_ATTRIBUTE *att = NULL;
5203  DB_TYPE type;
5204 
5205  type = DB_TYPE_NULL;
5206  if (find_attribute_op (classop, name, &class_, &att) == NO_ERROR)
5207  {
5208  type = att->type->id;
5209  }
5210 
5211  return type;
5212 }
5213 
5214 #if defined(ENABLE_UNUSED_FUNCTION)
5215 /*
5216  * sm_type_name() - Accesses the primitive type name for a type identifier.
5217  * Used by the interpreter for error messages during semantic checking.
5218  * return: internal primitive type name
5219  * id(in): type identifier
5220  */
5221 
5222 static const char *
5223 sm_type_name (DB_TYPE id)
5224 {
5225  PR_TYPE *type;
5226 
5227  type = pr_type_from_id (id);
5228  if (type != NULL)
5229  {
5230  return type->name;
5231  }
5232 
5233  return NULL;
5234 }
5235 #endif /* ENABLE_UNUSED_FUNCTION */
5236 
5237 /*
5238  * sm_att_class() - Returns the domain class of an attribute if its basic type
5239  * is DB_TYPE_OBJECT.
5240  * return: domain class of attribute
5241  * classop(in): class object
5242  * name(in): attribute name
5243  */
5244 
5245 MOP
5246 sm_att_class (MOP classop, const char *name)
5247 {
5248  SM_CLASS *class_;
5249  SM_ATTRIBUTE *att = NULL;
5250  MOP attclass;
5251 
5252  attclass = NULL;
5253  if (find_attribute_op (classop, name, &class_, &att) == NO_ERROR)
5254  {
5255  sm_filter_domain (att->domain, NULL);
5256  if (att->domain != NULL && att->domain->type == tp_Type_object)
5257  {
5258  attclass = att->domain->class_mop;
5259  }
5260  }
5261 
5262  return attclass;
5263 }
5264 
5265 /*
5266  * sm_att_info() - Used by the interpreter and query compiler to gather
5267  * misc information about an attribute. Don't set errors
5268  * if the attribute was not found, the compiler may use this to
5269  * probe classes for information and will handle errors on its own.
5270  * return: NO_ERROR on success, non-zero for ERROR
5271  * classop(in): class object
5272  * name(in): attribute name
5273  * idp(out): returned attribute identifier
5274  * domainp(out): returned domain structure
5275  * sharedp(out): returned flag set if shared attribute
5276  * class_attr(in): flag to indicate if you want att info for class attributes
5277  */
5278 
5279 int
5280 sm_att_info (MOP classop, const char *name, int *idp, TP_DOMAIN ** domainp, int *sharedp, int class_attr)
5281 {
5282  int error = NO_ERROR;
5283  SM_CLASS *class_;
5284  SM_ATTRIBUTE *att;
5285 
5286  att = NULL;
5287  *sharedp = 0;
5288 
5289  error = au_fetch_class (classop, &class_, AU_FETCH_READ, AU_SELECT);
5290  if (error == NO_ERROR)
5291  {
5292  att = classobj_find_attribute (class_, name, class_attr);
5293  if (att == NULL)
5294  {
5295  /* return error but don't call er_set */
5296  error = ER_SM_ATTRIBUTE_NOT_FOUND;
5297  }
5298 
5299  if (error == NO_ERROR)
5300  {
5302  {
5303  *sharedp = 1;
5304  }
5305  sm_filter_domain (att->domain, NULL);
5306  *idp = att->id;
5307  *domainp = att->domain;
5308  }
5309  }
5310 
5311  return error;
5312 }
5313 
5314 /*
5315  * sm_find_index()
5316  * return: Pointer to B-tree ID variable.
5317  * classop(in): class object
5318  * att_names(in):
5319  * num_atts(in):
5320  * skip_prefix_index(in): true, if index with prefix length must be skipped
5321  * unique_index_only(in):
5322  * btid(out):
5323  */
5324 
5325 BTID *
5326 sm_find_index (MOP classop, char **att_names, int num_atts, bool unique_index_only, bool skip_prefix_index, BTID * btid)
5327 {
5328  int error = NO_ERROR;
5329  int i;
5330  SM_CLASS *class_;
5331  SM_CLASS_CONSTRAINT *con = NULL;
5332  SM_ATTRIBUTE *att1, *att2;
5333  BTID *index = NULL;
5334  bool force_local_index = false;
5335  int is_global = 0;
5336 
5337  index = NULL;
5338 
5339  error = au_fetch_class (classop, &class_, AU_FETCH_READ, AU_SELECT);
5340  if (error != NO_ERROR)
5341  {
5342  return NULL;
5343  }
5344 
5345  if (class_->partition != NULL && class_->users == NULL)
5346  {
5347  /* this is a partition, we can only use local indexes */
5348  force_local_index = true;
5349  }
5350 
5351  if (unique_index_only)
5352  {
5353  /* unique indexes are global indexes on class hierarchies and we cannot use them. The exception is when the class
5354  * hierarchy is actually a partitioning hierarchy. In this case, we want to use any global/local index if class_
5355  * points to the partitioned class and only local indexes if class_ points to a partition */
5356  if ((class_->inheritance || class_->users) && class_->partition == NULL)
5357  {
5358  /* never use an unique index upon a class hierarchy */
5359  return NULL;
5360  }
5361  }
5362 
5363  for (con = class_->constraints; con != NULL; con = con->next)
5364  {
5365  if (!SM_IS_CONSTRAINT_INDEX_FAMILY (con->type))
5366  {
5367  continue;
5368  }
5369 
5370  if (unique_index_only)
5371  {
5373  {
5374  continue;
5375  }
5376  if (sm_is_global_only_constraint (classop, con, &is_global, NULL) != NO_ERROR)
5377  {
5378  return NULL;
5379  }
5380 
5381  if (force_local_index && is_global)
5382  {
5383  continue;
5384  }
5385  }
5386 
5387  if (skip_prefix_index && num_atts > 0 && con->attributes[0] != NULL && con->attrs_prefix_length
5388  && con->attrs_prefix_length[0] > 0)
5389  {
5390  continue;
5391  }
5392 
5393  if (num_atts == 0)
5394  {
5395  /* we don't care about attributes, any index is a good one */
5396  break;
5397  }
5398 
5399  for (i = 0; i < num_atts; i++)
5400  {
5401  att1 = con->attributes[i];
5402  if (att1 == NULL)
5403  {
5404  break;
5405  }
5406 
5407  att2 = classobj_find_attribute (class_, att_names[i], 0);
5408  if (att2 == NULL || att1->id != att2->id)
5409  {
5410  break;
5411  }
5412  }
5413 
5414  if ((i == num_atts) && con->attributes[i] == NULL)
5415  {
5416  /* found it */
5417  break;
5418  }
5419  }
5420 
5421  if (con)
5422  {
5423  BTID_COPY (btid, &con->index_btid);
5424  index = btid;
5425  }
5426 
5427  return (index);
5428 }
5429 
5430 /*
5431  * sm_att_constrained() - Returns whether the attribute is auto_increment.
5432  * classop(in): class object
5433  * name(in): attribute
5434  */
5435 
5436 bool
5437 sm_att_auto_increment (MOP classop, const char *name)
5438 {
5439  SM_CLASS *class_ = NULL;
5440  SM_ATTRIBUTE *att = NULL;
5441  bool rc = false;
5442 
5443  if (find_attribute_op (classop, name, &class_, &att) == NO_ERROR)
5444  {
5445  rc = att->flags & SM_ATTFLAG_AUTO_INCREMENT ? true : false;
5446  }
5447 
5448  return rc;
5449 }
5450 
5451 /*
5452  * sm_att_default_value() - Gets the default value of a column.
5453  * return: NO_ERROR on success, non-zero for ERROR
5454  * classop(in): class object
5455  * name(in): attribute
5456  * value(out): the default value of the specified attribute
5457  * default_expr(out): default expression
5458  * on_update_expr(out): on_update default expression
5459  */
5460 
5461 int
5462 sm_att_default_value (MOP classop, const char *name, DB_VALUE * value, DB_DEFAULT_EXPR ** default_expr,
5463  DB_DEFAULT_EXPR_TYPE ** on_update_expr)
5464 {
5465  SM_CLASS *class_ = NULL;
5466  SM_ATTRIBUTE *att = NULL;
5467  int error = NO_ERROR;
5468 
5469  assert (value != NULL && default_expr != NULL && on_update_expr != NULL);
5470 
5471  error = db_value_clear (value);
5472  if (error != NO_ERROR)
5473  {
5474  goto error_exit;
5475  }
5476 
5477  error = find_attribute_op (classop, name, &class_, &att);
5478  if (error != NO_ERROR)
5479  {
5480  goto error_exit;
5481  }
5482 
5483  error = db_value_clone (&att->default_value.value, value);
5484  if (error != NO_ERROR)
5485  {
5486  goto error_exit;
5487  }
5488 
5489  *default_expr = &att->default_value.default_expr;
5490  *on_update_expr = &att->on_update_default_expr;
5491  return error;
5492 
5493 error_exit:
5494  return error;
5495 }
5496 
5497 
5498 /*
5499  * sm_att_constrained() - Returns whether the attribute is constained.
5500  * return: whether the attribute is constrained.
5501  * classop(in): class object
5502  * name(in): attribute
5503  * cons(in): constraint
5504  */
5505 
5506 int
5507 sm_att_constrained (MOP classop, const char *name, SM_ATTRIBUTE_FLAG cons)
5508 {
5509  SM_CLASS *class_;
5510  SM_ATTRIBUTE *att = NULL;
5511  int rc;
5512 
5513  rc = 0;
5514  if (find_attribute_op (classop, name, &class_, &att) == NO_ERROR)
5515  {
5516  if (SM_IS_ATTFLAG_INDEX_FAMILY (cons))
5517  {
5519  }
5520  else
5521  {
5522  rc = att->flags & cons;
5523  }
5524  }
5525 
5526  return rc;
5527 }
5528 
5529 /*
5530  * sm_att_fk_constrained() - Returns whether the attribute is foreign key
5531  * constrained.
5532  * return: whether the attribute is foreign key constrained.
5533  * classop(in): class object
5534  * name(in): attribute
5535  */
5536 int
5537 sm_att_fk_constrained (MOP classop, const char *name)
5538 {
5539  SM_CLASS *class_;
5540  SM_ATTRIBUTE *att = NULL;
5541 
5542  if (find_attribute_op (classop, name, &class_, &att) == NO_ERROR)
5543  {
5544  return db_attribute_is_foreign_key (att);
5545  }
5546 
5547  return false;
5548 }
5549 
5550 /*
5551  * sm_class_has_unique_constraint() - Returns whether the class has UNIQUE
5552  * constraint.
5553  * return: NO_ERROR on success, non-zero for ERROR
5554  * classobj(in): SM_CLASS *
5555  * classop(in): class object
5556  * check_subclasses(in): true if need to check all hierarchy
5557  * has_unique(out): true if has unique constraint, false otherwise.
5558  */
5559 int
5560 sm_class_has_unique_constraint (MOBJ classobj, MOP classop, bool check_subclasses, bool * has_unique)
5561 {
5562  int error = NO_ERROR;
5563  SM_CLASS *class_ = NULL;
5564  DB_OBJLIST *subclass = NULL;
5565  bool rc;
5566  int au_save;
5567 
5568  assert (classobj != NULL || classop != NULL);
5569 
5570  if (classobj != NULL)
5571  {
5572  class_ = (SM_CLASS *) classobj;
5573  }
5574  else
5575  {
5576  AU_DISABLE (au_save);
5577  error = au_fetch_class_by_classmop (classop, &class_, AU_FETCH_READ, AU_SELECT);
5578  AU_ENABLE (au_save);
5579 
5580  if (error != NO_ERROR)
5581  {
5582  return error;
5583  }
5584  }
5585 
5587  for (subclass = class_->users; !rc && subclass != NULL; subclass = subclass->next)
5588  {
5589  error = sm_class_has_unique_constraint (NULL, subclass->op, check_subclasses, &rc);
5590  if (error != NO_ERROR)
5591  {
5592  return error;
5593  }
5594  }
5595 
5596  *has_unique = rc;
5597 
5598  return error;
5599 }
5600 
5601 /*
5602  * sm_att_unique_constrained() - Returns whether the attribute is UNIQUE constained.
5603  * return: whether the attribute is UNIQUE constrained.
5604  * classop(in): class object
5605  * name(in): attribute
5606  */
5607 int
5608 sm_att_unique_constrained (MOP classop, const char *name)
5609 {
5610  SM_CLASS *class_;
5611  SM_ATTRIBUTE *att = NULL;
5612  int rc;
5613 
5614  rc = 0;
5615  if (find_attribute_op (classop, name, &class_, &att) == NO_ERROR)
5616  {
5618  }
5619 
5620  return rc;
5621 }
5622 
5623 /*
5624  * sm_att_in_unique_filter_constraint_predicate() - Returns whether the
5625  * attribute is inside
5626  * of unique filter
5627  * constraint predicate
5628  * return: whether the attribute is inside of unique filter constraint
5629  * predicate
5630  * classop(in): class object
5631  * name(in): attribute
5632  */
5633 int
5635 {
5636  SM_CLASS *class_ = NULL;
5637  SM_ATTRIBUTE *att = NULL;
5638 
5639  if ((find_attribute_op (classop, name, &class_, &att) == NO_ERROR) && class_ != NULL)
5640  {
5641  SM_CLASS_CONSTRAINT *constr = NULL;
5642  int i;
5643 
5644  for (constr = class_->constraints; constr != NULL; constr = constr->next)
5645  {
5646  if ((constr->type == SM_CONSTRAINT_UNIQUE || constr->type == SM_CONSTRAINT_REVERSE_UNIQUE)
5647  && constr->filter_predicate && constr->filter_predicate->att_ids)
5648  {
5649  assert (constr->filter_predicate->num_attrs > 0);
5650  for (i = 0; i < constr->filter_predicate->num_attrs; i++)
5651  {
5652  if (constr->filter_predicate->att_ids[i] == att->id)
5653  {
5654  return 1;
5655  }
5656  }
5657  }
5658  }
5659  }
5660 
5661  return 0;
5662 }
5663 
5664 /*
5665  * sm_class_check_uniques() - Returns NO_ERROR if there are no unique constraints
5666  * or if none of the unique constraints are violated.
5667  * Used by the interpreter to check batched unique constraints.
5668  * return: whether class failed unique constraint tests.
5669  * classop(in): class object
5670  */
5671 
5672 int
5674 {
5675  SM_CLASS *class_;
5676  int error = NO_ERROR;
5677  OR_ALIGNED_BUF (200) a_buffer; /* should handle most of the cases */
5678  char *buffer;
5679  int buf_size, buf_len = 0, buf_malloced = 0, uniques = 0;
5680  char *bufp, *buf_start;
5681  SM_CLASS_CONSTRAINT *con;
5682 
5683  buffer = OR_ALIGNED_BUF_START (a_buffer);
5684  bufp = buffer;
5685  buf_start = buffer;
5686  buf_size = 200; /* could use OR_ALIGNED_BUF_SIZE */
5687 
5688  error = au_fetch_class (classop, &class_, AU_FETCH_READ, AU_SELECT);
5689  if (error == NO_ERROR)
5690  {
5691  for (con = class_->constraints; con != NULL; con = con->next)
5692  {
5694  {
5695  uniques = 1;
5696 
5697  /* check if we have space for one more btid */
5698  if (buf_len + OR_BTID_ALIGNED_SIZE > buf_size)
5699  {
5700  buf_size = buf_size * 2;
5701  if (buf_malloced)
5702  {
5703  buf_start = (char *) realloc (buf_start, buf_size);
5704  if (buf_start == NULL)
5705  {
5706  buf_malloced = 0;
5707  error = ER_OUT_OF_VIRTUAL_MEMORY;
5709  goto error_class_check_uniques;
5710  }
5711  }
5712  else
5713  {
5714  buf_start = (char *) malloc (buf_size);
5715  if (buf_start == NULL)
5716  {
5717  error = ER_OUT_OF_VIRTUAL_MEMORY;
5719  goto error_class_check_uniques;
5720  }
5721  memcpy (buf_start, buffer, buf_len);
5722  }
5723  buf_malloced = 1;
5724  bufp = buf_start + buf_len;
5725  }
5726 
5727  bufp = or_pack_btid (bufp, &(con->index_btid));
5728  buf_len += OR_BTID_ALIGNED_SIZE;
5729  }
5730  }
5731 
5732  if (uniques)
5733  {
5734  error = btree_class_test_unique (buf_start, buf_len);
5735  }
5736  }
5737 
5738  if (buf_malloced)
5739  {
5740  free_and_init (buf_start);
5741  }
5742 
5743  return error;
5744 
5745 error_class_check_uniques:
5746  if (buf_malloced)
5747  {
5748  free_and_init (buf_start);
5749  }
5750 
5751  assert (er_errid () != NO_ERROR);
5752  return er_errid ();
5753 }
5754 
5755 /* QUERY PROCESSOR SUPPORT FUNCTIONS */
5756 /*
5757  * sm_get_class_repid() - Used by the query compiler to tag compiled
5758  * queries/views with the representation ids of the involved classes.
5759  * This allows it to check for class modifications at a later date and
5760  * invalidate the query/view.
5761  * return: current representation id if class. Returns -1 if an error ocurred
5762  * classop(in): class object
5763  */
5764 
5765 int
5767 {
5768  SM_CLASS *class_;
5769  int id = -1;
5770 
5771  if (classop != NULL && locator_is_class (classop, DB_FETCH_READ) > 0)
5772  {
5773  if (au_fetch_class (classop, &class_, AU_FETCH_READ, AU_SELECT) == NO_ERROR)
5774  {
5775  id = class_->repid;
5776  }
5777  }
5778 
5779  return id;
5780 }
5781 
5782 #if defined (ENABLE_UNUSED_FUNCTION)
5783 /*
5784  * lock_query_subclasses()
5785  * return: NO_ERROR on success, non-zero for ERROR
5786  * subclasses(in):
5787  * op(in): root class of query
5788  * exceptions(in): list of exception classes
5789  * update(in): set if classes are to be locked for update
5790  */
5791 
5792 static int
5793 lock_query_subclasses (DB_OBJLIST ** subclasses, MOP op, DB_OBJLIST * exceptions, int update)
5794 {
5795  int error = NO_ERROR;
5796  DB_OBJLIST *l, *found, *new_, *u;
5797  SM_CLASS *class_;
5798 
5799  if (!ml_find (exceptions, op))
5800  {
5801  /* must be more effecient here */
5802  if (update)
5803  {
5804  error = au_fetch_class (op, &class_, AU_FETCH_READ, AU_UPDATE);
5805  }
5806  else
5807  {
5808  error = au_fetch_class (op, &class_, AU_FETCH_READ, AU_SELECT);
5809  }
5810 
5811  if (error == NO_ERROR)
5812  {
5813  /* upgrade the lock, MUST change this to be part of the au call */
5814  if (update)
5815  {
5817  }
5818  else
5819  {
5821  }
5822 
5823  if (class_ == NULL)
5824  {
5825  assert (er_errid () != NO_ERROR);
5826  error = er_errid ();
5827  }
5828  else
5829  {
5830  /* dive to the bottom */
5831  for (u = class_->users; u != NULL && error == NO_ERROR; u = u->next)
5832  {
5833  error = lock_query_subclasses (subclasses, u->op, exceptions, update);
5834  }
5835 
5836  /* push the class on the list */
5837  for (l = *subclasses, found = NULL; l != NULL && found == NULL; l = l->next)
5838  {
5839  if (l->op == op)
5840  {
5841  found = l;
5842  }
5843  }
5844  if (found == NULL)
5845  {
5846  new_ = (DB_OBJLIST *) db_ws_alloc (sizeof (DB_OBJLIST));
5847  if (new_ == NULL)
5848  {
5849  assert (er_errid () != NO_ERROR);
5850  return er_errid ();
5851  }
5852  new_->op = op;
5853  new_->next = *subclasses;
5854  *subclasses = new_;
5855  }
5856  }
5857  }
5858  }
5859  return (error);
5860 }
5861 
5862 /*
5863  * sm_query_lock() - Lock a class hierarchy in preparation for a query.
5864  * return: object list
5865  * classop(in): root class of query
5866  * exceptions(in): list of exception classes
5867  * only(in): set if only top level class is locked
5868  * update(in): set if classes are to be locked for update
5869  */
5870 
5871 static DB_OBJLIST *
5872 sm_query_lock (MOP classop, DB_OBJLIST * exceptions, int only, int update)
5873 {
5874  int error;
5875  DB_OBJLIST *classes, *u;
5876  SM_CLASS *class_;
5877 
5878  classes = NULL;
5879  if (classop != NULL)
5880  {
5881  if (update)
5882  {
5883  error = au_fetch_class (classop, &class_, AU_FETCH_READ, AU_UPDATE);
5884  }
5885  else
5886  {
5887  error = au_fetch_class (classop, &class_, AU_FETCH_READ, AU_SELECT);
5888  }
5889 
5890  if (error == NO_ERROR)
5891  {
5892  /* upgrade the lock, MUST change this to be part of the au call */
5893  if (update)
5894  {
5895  class_ = (SM_CLASS *) locator_fetch_class (classop, DB_FETCH_QUERY_WRITE);
5896  }
5897  else
5898  {
5899  class_ = (SM_CLASS *) locator_fetch_class (classop, DB_FETCH_QUERY_READ);
5900  }
5901  if (class_ == NULL)
5902  {
5903  ml_free (classes);
5904  return (NULL);
5905  }
5906  if (!ml_find (exceptions, classop))
5907  {
5908  if (ml_add (&classes, classop, NULL))
5909  {
5910  ml_free (classes);
5911  return NULL;
5912  }
5913  }
5914 
5915  if (!only)
5916  {
5917  for (u = class_->users; u != NULL && error == NO_ERROR; u = u->next)
5918  {
5919  error = lock_query_subclasses (&classes, u->op, exceptions, update);
5920  }
5921  }
5922  }
5923  }
5924  else if (!only)
5925  {
5926  /* KLUDGE, if the classop is NULL, assume that the domain is "object" and that all classes are available -
5927  * shouldn't have to do this !!! */
5928  classes = sm_get_all_classes (0);
5929  }
5930 
5931  return (classes);
5932 }
5933 #endif
5934 
5935 /*
5936  * sm_flush_objects() - Flush all the instances of a particular class
5937  * to the server. Used by the query processor to ensure that all
5938  * dirty objects of a class are flushed before attempting to
5939  * execute the query.
5940  * It is important that the class be flushed as well.
5941  * return: NO_ERROR on success, non-zero for ERROR
5942  * obj(in): class or instance
5943  */
5944 
5945 int
5947 {
5948  return sm_flush_and_decache_objects (obj, false);
5949 }
5950 
5951 /*
5952  * sm_decache_mop() - Decache mop.
5953  * return: error code.
5954  * mop(in): mop
5955  * info(in): additional information, currently not used.
5956  */
5957 int
5958 sm_decache_mop (MOP mop, void *info)
5959 {
5960  if (WS_ISVID (mop))
5961  {
5962  vid_decache_instance (mop);
5963  }
5964  else
5965  {
5966  ws_decache (mop);
5967  }
5968 
5969  return NO_ERROR;
5970 }
5971 
5972 /*
5973  * sm_decache_instances_after_query_executed_with_commit() - Decache class instances after query execution with commit.
5974  * return: error code
5975  * class_mop(in): class mop
5976  */
5977 int
5979 {
5980  SM_CLASS *class_;
5981  DB_OBJLIST class_list, *obj = NULL;
5982  MOBJ class_obj;
5983 
5984  assert (class_mop != NULL && !WS_ISDIRTY (class_mop) && !locator_is_root (class_mop));
5985 
5986  class_list.op = class_mop;
5987  class_list.next = NULL;
5988 
5989  if (ws_find (class_mop, &class_obj) == WS_FIND_MOP_DELETED)
5990  {
5991  /* Should not happen. */
5992  return ER_FAILED;
5993  }
5994 
5995  if (class_obj == NULL)
5996  {
5997  class_obj = locator_fetch_class (class_mop, DB_FETCH_READ);
5998  if (class_obj == NULL)
5999  {
6000  return ER_FAILED;
6001  }
6002  }
6003 
6004  class_ = (SM_CLASS *) class_obj;
6005  if (class_->partition != NULL && class_->users != NULL)
6006  {
6007  class_list.next = class_->users;
6008  }
6009 
6010  /* Decache instances. */
6011  for (obj = &class_list; obj != NULL; obj = obj->next)
6012  {
6013  if (obj->op == NULL || obj->op->object == NULL || class_->flags & SM_CLASSFLAG_SYSTEM)
6014  {
6015  continue;
6016  }
6017 
6018  (void) ws_map_class (obj->op, sm_decache_mop, NULL);
6019  }
6020 
6021  for (obj = &class_list; obj != NULL; obj = obj->next)
6022  {
6024  }
6025 
6026  return NO_ERROR;
6027 }
6028 
6029 static int
6030 sm_flush_and_decache_objects_internal (MOP obj, MOP obj_class_mop, int decache)
6031 {
6032  int error = NO_ERROR;
6033  SM_CLASS *class_;
6034 
6035  if (locator_flush_class (obj_class_mop) != NO_ERROR)
6036  {
6037  ASSERT_ERROR_AND_SET (error);
6038  return error;
6039  }
6040 
6041  class_ = (SM_CLASS *) locator_fetch_class (obj, DB_FETCH_READ);
6042  if (class_ == NULL)
6043  {
6045  return error;
6046  }
6047 
6048  switch (class_->class_type)
6049  {
6050  case SM_CLASS_CT:
6051  if (obj == obj_class_mop && (class_->flags & SM_CLASSFLAG_SYSTEM))
6052  {
6053  /* if system class, flush all dirty class */
6054  if (locator_flush_all_instances (sm_Root_class_mop, DONT_DECACHE) != NO_ERROR)
6055  {
6056  ASSERT_ERROR_AND_SET (error);
6057  return error;
6058  }
6059  }
6060 
6061  if (locator_flush_all_instances (obj_class_mop, decache) != NO_ERROR)
6062  {
6063  ASSERT_ERROR_AND_SET (error);
6064  return error;
6065  }
6066  break;
6067 
6068  case SM_VCLASS_CT:
6069  if (vid_flush_all_instances (obj, decache) != NO_ERROR)
6070  {
6071  ASSERT_ERROR_AND_SET (error);
6072  return error;
6073  }
6074  break;
6075 
6076  case SM_ADT_CT:
6077  /* what to do here?? */
6078  break;
6079  }
6080 
6081  return error;
6082 }
6083 
6084 /*
6085  * sm_flush_and_decache_objects() - Flush all the instances of a particular
6086  * class to the server. Optionally decache the instances of the class.
6087  * return: NO_ERROR on success, non-zero for ERROR
6088  * obj(in): class or instance
6089  * decache(in): whether to decache the instances of the class.
6090  */
6091 
6092 int
6094 {
6095  int error = NO_ERROR, is_class = 0;
6096  MOP obj_class_mop;
6097 
6098  if (obj == NULL)
6099  {
6100  return NO_ERROR;
6101  }
6102 
6103  is_class = locator_is_class (obj, DB_FETCH_READ);
6104  if (is_class < 0)
6105  {
6106  return is_class;
6107  }
6108 
6109  if (is_class)
6110  {
6111  // class
6112  return sm_flush_and_decache_objects_internal (obj, obj, decache);
6113  }
6114  else
6115  {
6116  // instance
6117  obj_class_mop = ws_class_mop (obj);
6118  if (obj_class_mop == NULL)
6119  {
6120  MOBJ mem;
6121 
6123  if (error != NO_ERROR)
6124  {
6125  return error;
6126  }
6127 
6128  /* don't need to pin here, we only wanted to check authorization */
6129  obj_class_mop = ws_class_mop (obj);
6130  if (obj_class_mop == NULL)
6131  {
6133  return error;
6134  }
6135  }
6136 
6137  return sm_flush_and_decache_objects_internal (obj, obj_class_mop, decache);
6138  }
6139 }
6140 
6141 /*
6142  * sm_flush_for_multi_update() - Flush all the dirty instances of a particular
6143  * class to the server.
6144  * It is invoked only in case that client updates multiple instances.
6145  * return: NO_ERROR on success, non-zero for ERROR
6146  * class_mop (in): class MOP
6147  */
6148 
6149 int
6151 {
6152  int success = NO_ERROR;
6153 
6154  if (WS_ISVID (class_mop))
6155  {
6156  /* The second argument, decache, is false. */
6157  if (vid_flush_all_instances (class_mop, false) != NO_ERROR)
6158  {
6159  goto error;
6160  }
6161 
6162  success = sm_class_check_uniques (class_mop);
6163  return success;
6164  }
6165 
6166  if (locator_flush_for_multi_update (class_mop) != NO_ERROR)
6167  {
6168  goto error;
6169  }
6170 
6171  return success;
6172 
6173 error:
6174  assert (er_errid () != NO_ERROR);
6175  return er_errid ();
6176 
6177 }
6178 
6179 /* WORKSPACE/GARBAGE COLLECTION SUPPORT FUNCTIONS */
6180 /*
6181  * sm_issystem() - This is called by the workspace manager to see
6182  * if a class is a system class. This avoids having the ws files know about
6183  * the class structure and flags.
6184  * return: non-zero if class is system class
6185  */
6186 
6187 int
6189 {
6190  return (class_->flags & SM_CLASSFLAG_SYSTEM);
6191 }
6192 
6193 /*
6194  * sm_local_schema_version()
6195  * return: unsigned int indicating any change in local schema as none
6196  */
6197 
6198 unsigned int
6200 {
6201  return local_schema_version;
6202 }
6203 
6204 /*
6205  * sm_bump_local_schema_version()
6206  *
6207  */
6208 
6209 void
6211 {
6213 }
6214 
6215 /*
6216  * sm_global_schema_version()
6217  * return: unsigned int indicating any change in global schema as none
6218  */
6219 
6220 unsigned int
6222 {
6223  return global_schema_version;
6224 }
6225 
6226 /*
6227  * sm_bump_global_schema_version()
6228  *
6229  */
6230 
6231 void
6233 {
6235 }
6236 
6237 /*
6238  * sm_save_nested_view_versions() -- save nested view versions into view_cache
6239  * return:
6240  * parser(in): outer parser
6241  * class_object(in): the db object of nested view
6242  * class_(in): the SM_CLASS of nested view
6243  */
6244 int
6246 {
6247  VIEW_CACHE_INFO *info;
6248  NESTED_VIEW_VERSION_INFO *nested_view, *new_nested_view;
6249 
6250  info = (VIEW_CACHE_INFO *) parser->view_cache;
6251  if (info == NULL)
6252  {
6253  /* not in a vlew */
6254  return NO_ERROR;
6255  }
6256 
6257  /* avoid duplication */
6258  for (nested_view = info->nested_views; nested_view != NULL; nested_view = nested_view->next)
6259  {
6260  if (nested_view->class_object == class_object)
6261  {
6265 
6266  return NO_ERROR;
6267  }
6268  }
6269 
6270  new_nested_view = (NESTED_VIEW_VERSION_INFO *) parser_alloc (parser, sizeof (NESTED_VIEW_VERSION_INFO));
6271  if (new_nested_view == NULL)
6272  {
6274  return ER_OUT_OF_VIRTUAL_MEMORY;
6275  }
6276 
6277  new_nested_view->class_object = class_object;
6281 
6282  new_nested_view->next = info->nested_views;
6283  info->nested_views = new_nested_view;
6284 
6285  return NO_ERROR;
6286 }
6287 
6288 /*
6289  * sm_is_nested_view_recached() -- check whether the nested view recached or changed.
6290  * return: true if one of nested view reached or changed.
6291  * parser(in):
6292  */
6293 static bool
6295 {
6296  VIEW_CACHE_INFO *info;
6297  NESTED_VIEW_VERSION_INFO *nested_view;
6298  SM_CLASS *class_;
6299 
6300  info = (VIEW_CACHE_INFO *) parser->view_cache;
6301  assert_release (info != NULL);
6302 
6303  for (nested_view = info->nested_views; nested_view != NULL; nested_view = nested_view->next)
6304  {
6305  if (au_fetch_class_force (nested_view->class_object, &class_, AU_FETCH_READ) != NO_ERROR)
6306  {
6307  return true;
6308  }
6309 
6310  if (class_->virtual_query_cache == NULL)
6311  {
6312  return true;
6313  }
6314  else
6315  {
6316  if ((nested_view->virtual_cache_local_schema_id != class_->virtual_cache_local_schema_id)
6319  {
6320  return true;
6321  }
6322 
6324  {
6325  return true;
6326  }
6327  }
6328  }
6329 
6330  return false;
6331 }
6332 
6333 
6334 /*
6335  * sm_virtual_queries() - Frees a session for a class.
6336  * return: SM_CLASS pointer, with valid virtual query cache a class db_object
6337  * parser(in): the outer parser
6338  * class_object(in):
6339  */
6340 
6341 struct parser_context *
6343 {
6344  SM_CLASS *cl;
6345  PARSER_CONTEXT *cache = NULL, *tmp = NULL, *old_cache = NULL;
6346  int error = NO_ERROR;
6347  bool recache = false;
6348 
6349  if (au_fetch_class_force (class_object, &cl, AU_FETCH_READ) != NO_ERROR)
6350  {
6351  return NULL;
6352  }
6353 
6354  (void) ws_pin (class_object, 1);
6355 
6356  if (cl->virtual_query_cache != NULL)
6357  {
6359  {
6360  /* Always recache if current client bumped schema version. */
6361  recache = true;
6362  }
6365  {
6366  /* Recache if somebody else bumped schema version and if we are not protected by current snapshot. We don't
6367  * want to recache virtual queries already cached in current statement preparation (most of all, because we
6368  * can cause terrible damage). For RR, it also helps keeping cached virtual queries for the entire
6369  * transaction. */
6370  recache = true;
6371  }
6373  {
6374  recache = true;
6375  }
6376  }
6377 
6378  if (!recache && cl->virtual_query_cache != NULL && cl->virtual_query_cache->view_cache != NULL
6380  {
6381  er_stack_push ();
6383  if (er_has_error ())
6384  {
6385  error = er_errid ();
6386  /* return NULL when the error is generated by pt_class_pre_fetch(), except when the error is
6387  * ER_HEAP_UNKNOWN_OBJECT caused by the inconsistent class cache which should be refetched soon. */
6388  if (error != ER_HEAP_UNKNOWN_OBJECT)
6389  {
6390  return NULL;
6391  }
6392  }
6393  er_stack_pop ();
6394 
6396  {
6398  cl->virtual_query_cache = NULL;
6399  }
6400  }
6401 
6402  if (cl->virtual_query_cache != NULL)
6403  {
6404  if (error == ER_HEAP_UNKNOWN_OBJECT)
6405  {
6406  /* Recache (I don't know what the case means. */
6407  recache = true;
6408  }
6409 
6410  if (recache)
6411  {
6412  old_cache = cl->virtual_query_cache;
6413  cl->virtual_query_cache = NULL;
6414  }
6415  }
6416 
6417  if (cl->class_type != SM_CLASS_CT && cl->virtual_query_cache == NULL)
6418  {
6419  /* Okay, this is a bit of a kludge: If there happens to be a cyclic view definition, then the virtual_query_cache
6420  * will be allocated during the call to mq_virtual_queries. So, we'll assign it to a temp pointer and check it
6421  * again. We need to keep the old one and free the new one because the parser assigned originally contains the
6422  * error message. */
6423  tmp = mq_virtual_queries (class_object);
6424  if (tmp == NULL)
6425  {
6426  if (old_cache)
6427  {
6428  cl->virtual_query_cache = old_cache;
6429  }
6430  return NULL;
6431  }
6432 
6433  if (old_cache)
6434  {
6435  mq_free_virtual_query_cache (old_cache);
6436  }
6437 
6438  if (cl->virtual_query_cache)
6439  {
6441  }
6442  else
6443  {
6444  cl->virtual_query_cache = tmp;
6445  }
6446 
6447  /* Save local schema ID, global schema ID and snapshot version. They will be used to decide on using current
6448  * virtual queries or to recache them on next call. */
6452  }
6453 
6454  sm_save_nested_view_versions (parser, class_object, cl);
6455 
6456  cache = cl->virtual_query_cache;
6457 
6458  return cache;
6459 }
6460 
6461 /*
6462  * sm_get_attribute_descriptor() - Find the named attribute structure
6463  * in the class and return it. Lock the class with the appropriate intent.
6464  * return: NO_ERROR on success, non-zero for ERROR
6465  * op(in): class or instance
6466  * name(in): attribute name
6467  * class_attribute(in): non-zero for locating class attributes
6468  * for_update(in): non-zero if we're intending to update the attribute
6469  * desc_ptr(out): returned attribute descriptor
6470  */
6471 
6472 int
6473 sm_get_attribute_descriptor (DB_OBJECT * op, const char *name, int class_attribute, int for_update,
6474  SM_DESCRIPTOR ** desc_ptr)
6475 {
6476  int error = NO_ERROR;
6477  SM_CLASS *class_;
6478  SM_ATTRIBUTE *att;
6479  SM_DESCRIPTOR *desc;
6480  MOP classmop;
6481  DB_FETCH_MODE class_purpose;
6482 
6483  att = NULL;
6484 
6485  if (class_attribute)
6486  {
6487  /* looking for class attribute */
6488  if (for_update)
6489  {
6490  error = au_fetch_class (op, &class_, AU_FETCH_UPDATE, AU_ALTER);
6491  }
6492  else
6493  {
6494  error = au_fetch_class (op, &class_, AU_FETCH_READ, AU_SELECT);
6495  }
6496 
6497  if (error == NO_ERROR)
6498  {
6499  att = classobj_find_attribute (class_, name, 1);
6500  if (att == NULL)
6501  {
6502  ERROR1 (error, ER_OBJ_INVALID_ATTRIBUTE, name);
6503  }
6504  }
6505  }
6506  else
6507  {
6508  /* looking for an instance attribute */
6509  error = au_fetch_class (op, &class_, AU_FETCH_READ, AU_SELECT);
6510  if (error == NO_ERROR)
6511  {
6512  att = classobj_find_attribute (class_, name, 0);
6513  if (att == NULL)
6514  {
6515  ERROR1 (error, ER_OBJ_INVALID_ATTRIBUTE, name);
6516  }
6517  else if (att->header.name_space == ID_SHARED_ATTRIBUTE)
6518  {
6519  /* sigh, we didn't know that this was going to be a shared attribute when we checked class authorization
6520  * above, we must now upgrade the lock and check for alter access.
6521  *
6522  * Since this is logically in the name_space of the instance, should we use simple AU_UPDATE
6523  * authorization rather than AU_ALTER even though we're technically modifying the class ? */
6524  if (for_update)
6525  {
6526  error = au_fetch_class (op, &class_, AU_FETCH_UPDATE, AU_ALTER);
6527  }
6528  }
6529  }
6530  }
6531 
6532  if (!error && att != NULL)
6533  {
6534  int is_class = 0;
6535 
6536  /* class must have been fetched at this point */
6537  class_purpose = ((for_update) ? DB_FETCH_CLREAD_INSTWRITE : DB_FETCH_CLREAD_INSTREAD);
6538 
6539  is_class = locator_is_class (op, class_purpose);
6540  if (is_class < 0)
6541  {
6542  return is_class;
6543  }
6544  classmop = (is_class) ? op : ws_class_mop (op);
6545 
6546  desc = classobj_make_descriptor (classmop, class_, (SM_COMPONENT *) att, for_update);
6547  if (desc == NULL)
6548  {
6549  assert (er_errid () != NO_ERROR);
6550  error = er_errid ();
6551  }
6552  else
6553  {
6554  desc->next = sm_Descriptors;
6555  sm_Descriptors = desc;
6556  *desc_ptr = desc;
6557  }
6558  }
6559 
6560  return error;
6561 }
6562 
6563 /*
6564  * sm_get_method_desc() - This returns a method descriptor for the named method.
6565  * The descriptor can then be used for faster access the method
6566  * avoiding the name search.
6567  * return: NO_ERROR on success, non-zero for ERROR
6568  * op (in): class or instance
6569  * name(in): method name
6570  * class_method(in): class method name
6571  * desc_ptr(out): returned method descirptor
6572  */
6573 
6574 int
6575 sm_get_method_descriptor (DB_OBJECT * op, const char *name, int class_method, SM_DESCRIPTOR ** desc_ptr)
6576 {
6577  int error = NO_ERROR;
6578  SM_CLASS *class_;
6579  SM_METHOD *method = NULL;
6580  SM_DESCRIPTOR *desc;
6581  MOP classmop;
6582 
6583  error = au_fetch_class (op, &class_, AU_FETCH_READ, AU_EXECUTE);
6584  if (error == NO_ERROR)
6585  {
6586  method = classobj_find_method (class_, name, class_method);
6587  if (method == NULL)
6588  {
6589  ERROR1 (error, ER_OBJ_INVALID_METHOD, name);
6590  }
6591 
6592  /* could do the link here too ? */
6593  }
6594 
6595  if (!error && method != NULL)
6596  {
6597  /* class must have been fetched at this point */
6599  if (is_class < 0)
6600  {
6601  return error;
6602  }
6603  classmop = (is_class) ? op : ws_class_mop (op);
6604 
6605  desc = classobj_make_descriptor (classmop, class_, (SM_COMPONENT *) method, 0);
6606  if (desc == NULL)
6607  {
6608  assert (er_errid () != NO_ERROR);
6609  error = er_errid ();
6610  }
6611  else
6612  {
6613  desc->next = sm_Descriptors;
6614  sm_Descriptors = desc;
6615  *desc_ptr = desc;
6616  }
6617  }
6618 
6619  return error;
6620 }
6621 
6622 /*
6623  * sm_free_descriptor() - Free an attribute or method descriptor.
6624  * Remember to remove it from the global descriptor list.
6625  * return: none
6626  * desc(in): descriptor to free
6627  */
6628 
6629 void
6631 {
6632  SM_DESCRIPTOR *d, *prev;
6633 
6634  for (d = sm_Descriptors, prev = NULL; d != desc; d = d->next)
6635  {
6636  prev = d;
6637  }
6638 
6639  /* if d == NULL, the descriptor wasn't on the global list and is probably a suspect pointer, ignore it */
6640  if (d != NULL)
6641  {
6642  if (prev == NULL)
6643  {
6644  sm_Descriptors = d->next;
6645  }
6646  else
6647  {
6648  prev->next = d->next;
6649  }
6650 
6652  }
6653 }
6654 
6655 /*
6656  * sm_invalidate_descriptors() - This is called whenever a class is edited.
6657  * Or when a transaction commits.
6658  * We need to mark any descriptors that reference this class as
6659  * being invalid since the attribute/method structure pointers contained
6660  * in the descriptor are no longer valid.
6661  * return: none
6662  * class(in): class being modified
6663  */
6664 
6665 void
6667 {
6668  SM_DESCRIPTOR *d;
6669  SM_DESCRIPTOR_LIST *dl;
6670 
6671  if (class_ == NULL)
6672  {
6673  /* transaction boundary, unconditionally clear all outstanding descriptors */
6674  for (d = sm_Descriptors; d != NULL; d = d->next)
6675  {
6677  d->map = NULL;
6678  }
6679  }
6680  else
6681  {
6682  /* Schema change, clear any descriptors that reference the class. Note, the schema manager will call this for
6683  * EVERY class in the hierarcy. */
6684  for (d = sm_Descriptors; d != NULL; d = d->next)
6685  {
6686  for (dl = d->map; dl != NULL && dl->classobj != class_; dl = dl->next)
6687  ;
6688 
6689  if (dl != NULL)
6690  {
6691  /* found one, free the whole list */
6693  d->map = NULL;
6694  }
6695  }
6696  }
6697 }
6698 
6699 /*
6700  * fetch_descriptor_class() - Work function for sm_get_descriptor_component.
6701  * If the descriptor has been cleared or if we need to fetch the
6702  * class and check authorization for some reason, this function obtains
6703  * the appropriate locks and checks the necessary authorization.
6704  * return: NO_ERROR on success, non-zero for ERROR
6705  * op(in): object
6706  * desc(in): descriptor
6707  * for_update(in): non-zero if we're intending to update the attribute
6708  * class(out): returned class pointer
6709  */
6710 
6711 static int
6712 fetch_descriptor_class (MOP op, SM_DESCRIPTOR * desc, int for_update, SM_CLASS ** class_)
6713 {
6714  int error = NO_ERROR;
6715 
6716  if (for_update)
6717  {
6719  {
6720  error = au_fetch_class (op, class_, AU_FETCH_UPDATE, AU_ALTER);
6721  }
6722  else
6723  {
6724  error = au_fetch_class (op, class_, AU_FETCH_READ, AU_UPDATE);
6725  }
6726  }
6727  else
6728  {
6729  if (desc->name_space == ID_METHOD || desc->name_space == ID_CLASS_METHOD)
6730  {
6731  error = au_fetch_class (op, class_, AU_FETCH_READ, AU_EXECUTE);
6732  }
6733  else
6734  {
6735  error = au_fetch_class (op, class_, AU_FETCH_READ, AU_SELECT);
6736  }
6737  }
6738 
6739  return error;
6740 }
6741 
6742 /*
6743  * sm_get_descriptor_component() - This locates an attribute structure
6744  * associated with the class of the supplied object and identified
6745  * by the descriptor.
6746  * If the attribute has already been cached in the descriptor it is
6747  * returned, otherwise, we search the class for the matching component
6748  * and add it to the descriptor cache.
6749  * return: NO_ERROR on success, non-zero for ERROR
6750  * op(in): object
6751  * desc(in): descriptor
6752  * for_update(in): non-zero if we're intending to update the attribute
6753  * class_ptr(out):
6754  * comp_ptr(out):
6755  */
6756 
6757 int
6758 sm_get_descriptor_component (MOP op, SM_DESCRIPTOR * desc, int for_update, SM_CLASS ** class_ptr,
6759  SM_COMPONENT ** comp_ptr)
6760 {
6761  int error = NO_ERROR;
6762  SM_CLASS *class_;
6763  SM_COMPONENT *comp;
6764  SM_DESCRIPTOR_LIST *d, *prev, *new_;
6765  MOP classmop;
6766  int class_component;
6767 
6768  /* handle common case quickly, allow either an instance MOP or class MOP to be used here */
6769  if (desc->map != NULL && (desc->map->classobj == op || desc->map->classobj == ws_class_mop (op))
6770  && (!for_update || desc->map->write_access))
6771  {
6772  *comp_ptr = desc->map->comp;
6773  *class_ptr = desc->map->class_;
6774  }
6775  else
6776  {
6777  /* this is set when a fetch is performed, try to avoid if possible */
6778  class_ = NULL;
6779 
6780  /* get the class MOP for this thing, avoid fetching if possible */
6781  if (ws_class_mop (op) == NULL)
6782  {
6783  if (fetch_descriptor_class (op, desc, for_update, &class_))
6784  {
6785  assert (er_errid () != NO_ERROR);
6786  return er_errid ();
6787  }
6788  }
6789  classmop = (IS_CLASS_MOP (op)) ? op : ws_class_mop (op);
6790 
6791  /* search the descriptor map for this class */
6792  for (d = desc->map, prev = NULL; d != NULL && d->classobj != classmop; d = d->next)
6793  {
6794  prev = d;
6795  }
6796 
6797  if (d != NULL)
6798  {
6799  /* found an existing one, move it to the head of the list */
6800  if (prev != NULL)
6801  {
6802  prev->next = d->next;
6803  d->next = desc->map;
6804  desc->map = d;
6805  }
6806  /* check update authorization if we haven't done it yet */
6807  if (for_update && !d->write_access)
6808  {
6809  if (class_ == NULL)
6810  {
6811  if (fetch_descriptor_class (op, desc, for_update, &class_))
6812  {
6813  assert (er_errid () != NO_ERROR);
6814  return er_errid ();
6815  }
6816  }
6817  d->write_access = 1;
6818  }
6819  *comp_ptr = d->comp;
6820  *class_ptr = d->class_;
6821  }
6822  else
6823  {
6824  /* not on the list, fetch it if we haven't already done so */
6825  if (class_ == NULL)
6826  {
6827  if (fetch_descriptor_class (op, desc, for_update, &class_))
6828  {
6829  assert (er_errid () != NO_ERROR);
6830  return er_errid ();
6831  }
6832  }
6833 
6834  class_component = (desc->name_space == ID_CLASS_ATTRIBUTE || desc->name_space == ID_CLASS_METHOD);
6835  comp = classobj_find_component (class_, desc->name, class_component);
6836  if (comp == NULL)
6837  {
6838  if (desc->name_space == ID_METHOD || desc->name_space == ID_CLASS_METHOD)
6839  {
6840  ERROR1 (error, ER_OBJ_INVALID_METHOD, desc->name);
6841  }
6842  else
6843  {
6844  ERROR1 (error, ER_OBJ_INVALID_ATTRIBUTE, desc->name);
6845  }
6846  }
6847  else
6848  {
6849  /* make a new descriptor and add it to the head of the list */
6850  new_ = classobj_make_desclist (classmop, class_, comp, for_update);
6851  if (new_ == NULL)
6852  {
6853  assert (er_errid () != NO_ERROR);
6854  error = er_errid ();
6855  }
6856  else
6857  {
6858  new_->next = desc->map;
6859  desc->map = new_;
6860  *comp_ptr = comp;
6861  *class_ptr = class_;
6862  }
6863  }
6864  }
6865  }
6866 
6867  return error;
6868 }
6869 
6870 #if defined (ENABLE_UNUSED_FUNCTION) /* to disable TEXT */
6871 /*
6872  * sm_has_text_domain() - Check if it is a TEXT typed attribute
6873  * return: 1 if it has TEXT or 0
6874  * attribute(in): attributes to check a domain
6875  * check_all(in): scope to check a domain, 1 if all check, or 0
6876  */
6877 int
6878 sm_has_text_domain (DB_ATTRIBUTE * attributes, int check_all)
6879 {
6880  DB_ATTRIBUTE *attr;
6881  DB_OBJLIST *supers;
6882  DB_OBJECT *domain;
6883 
6884  attr = attributes;
6885  while (attr)
6886  {
6887  if (db_attribute_type (attr) == DB_TYPE_OBJECT)
6888  {
6889  domain = db_domain_class (db_attribute_domain (attr));
6890  if (domain)
6891  {
6892  supers = db_get_superclasses (domain);
6893  if (supers && supers->op && (intl_identifier_casecmp (db_get_class_name (supers->op), "db_text") == 0))
6894  {
6895  return true;
6896  }
6897  }
6898  }
6899  if (!check_all)
6900  {
6901  break;
6902  }
6903  attr = db_attribute_next (attr);
6904  }
6905 
6906  return false;
6907 }
6908 #endif /* ENABLE_UNUSED_FUNCTION */
6909 
6910 
6911 /* NAME SEARCHERS */
6912 /*
6913  * template_classname() - Shorthand function for calls to er_set.
6914  * Get the class name for the class associated with a template.
6915  * return: class name
6916  * template(in): schema template
6917  */
6918 
6919 static const char *
6921 {
6922  const char *name;
6923 
6924  name = template_->name;
6925  if (name == NULL && template_->op != NULL)
6926  {
6927  name = sm_get_ch_name (template_->op);
6928  }
6929 
6930  return name;
6931 }
6932 
6933 /*
6934  * candidate_source_name() - Shorthand function to determine the class name
6935  * that is the source of the given candidate.
6936  * return: class name
6937  * template(in): template for class being edited
6938  * candidate(in): candidate of interest
6939  */
6940 
6941 static const char *
6943 {
6944  const char *name = NULL;
6945 
6946  if (candidate->source != NULL)
6947  {
6948  name = sm_get_ch_name (candidate->source);
6949  }
6950  else
6951  {
6952  if (template_->name != NULL)
6953  {
6954  name = template_->name;
6955  }
6956  else if (template_->op != NULL)
6957  {
6958  name = sm_get_ch_name (template_->op);
6959  }
6960  }
6961 
6962  return name;
6963 }
6964 
6965 /* DOMAIN COMPARISON */
6966 
6967 /*
6968  * find_superclass() - searches up the class hierarchy looking for a superclass.
6969  * If a superclass has a template pending, we use the superclass list
6970  * of the template rather than the real superclass list so that we can
6971  * recognize domain compatibility in a schema operation that has not
6972  * yet been fully applied.
6973  * return: non-zero if the superclass was found
6974  * classop(in): class object (if passed, temp should be NULL)
6975  * temp(in): template (if passed, classop should be NULL)
6976  * super(in): super class we're looking for
6977  */
6978 
6979 static int
6980 find_superclass (DB_OBJECT * classop, SM_TEMPLATE * temp, DB_OBJECT * super)
6981 {
6982  DB_OBJLIST *super_list, *el;
6983  SM_CLASS *class_;
6984  int status = 0;
6985 
6986  super_list = NULL;
6987 
6988  if (classop != NULL)
6989  {
6990  /* fetch the class and check for a pending template */
6991  if (au_fetch_class_force (classop, &class_, AU_FETCH_READ) != NO_ERROR)
6992  {
6993  return 0;
6994  }
6995  if (class_->new_ != NULL)
6996  {
6997  /* its got a template, use the pending inheritance list */
6998  super_list = class_->new_->inheritance;
6999  }
7000  else
7001  {
7002  /* no template, use the real inheritance list */
7003  super_list = class_->inheritance;
7004  }
7005  }
7006  else if (temp != NULL)
7007  {
7008  /* use the inheritance list of the supplied template */
7009  super_list = temp->inheritance;
7010  }
7011 
7012  /* search immediate superclasses first */
7013  for (el = super_list; el != NULL && !status; el = el->next)
7014  {
7015  if (el->op == super)
7016  {
7017  status = 1;
7018  }
7019  }
7020  if (!status)
7021  {
7022  /* Look all the way up the hierarchy, could be doing this in the previous loop but lets try to make the detection
7023  * of immediate superclasses fast as it is likely to be the most common. Recurse so we recognize pending
7024  * templates on the way up. */
7025  for (el = super_list; el != NULL && !status; el = el->next)
7026  {
7027  status = find_superclass (el->op, NULL, super);
7028  }
7029  }
7030 
7031  return status;
7032 }
7033 
7034 /*
7035  * compare_domains() - Compare two domains and calculate the appropriate
7036  * comparison code.
7037  * The result indicates the state of d1 relative to d2, that is, if the
7038  * result is DC_MORE_SPECIFIC it indicates that d1 is more specific
7039  * than d2.
7040  * If a domain comes in whose type is tp_Type_null, the domain is actually
7041  * a tp_Type_object domain for a class that has not yet been created.
7042  * In this case, the "class" field of the TP_DOMAIN structure will point
7043  * to the template for the new class.
7044  * return: domain comparison code
7045  * d1(in): domain structure
7046  * d2(in): domain structure
7047  */
7048 
7049 static DOMAIN_COMP
7051 {
7052  DOMAIN_COMP status = DC_INCOMPATIBLE;
7053 
7054  if (d1->type == tp_Type_null || d2->type == tp_Type_null)
7055  {
7056  /* domain comparison involving classes that haven't been created yet */
7057  if (d1->type == d2->type)
7058  {
7059  if (d1->class_mop == d2->class_mop)
7060  {
7061  status = DC_EQUAL;
7062  }
7063  /* else, you can't create two different classes in the same template so this can never happen */
7064  }
7065  else if (d1->type == tp_Type_null)
7066  {
7067  if (d2->type != tp_Type_object)
7068  {
7069  status = DC_INCOMPATIBLE;
7070  }
7071  else if (d2->class_mop == NULL)
7072  {
7073  status = DC_MORE_SPECIFIC;
7074  }
7075  else
7076  {
7077  /* If d2->class is accessible by scanning upwards from the inheritance list of the template, then d1 is
7078  * in the process of becoming a subtype of d2 and is therefore more specific. */
7079  if (find_superclass (NULL, (SM_TEMPLATE *) (d1->class_mop), d2->class_mop))
7080  {
7081  status = DC_MORE_SPECIFIC;
7082  }
7083  }
7084  }
7085  else
7086  {
7087  /* same as previous clause except the polarity is reversed */
7088  if (d1->type != tp_Type_object)
7089  {
7090  status = DC_INCOMPATIBLE;
7091  }
7092  else if (d1->class_mop == NULL)
7093  {
7094  status = DC_LESS_SPECIFIC;
7095  }
7096  else
7097  {
7098  if (find_superclass (NULL, (SM_TEMPLATE *) (d2->class_mop), d1->class_mop))
7099  {
7100  status = DC_LESS_SPECIFIC;
7101  }
7102  }
7103  }
7104  }
7105  else if (d1->type == d2->type)
7106  {
7107  if (d1->type == tp_Type_object)
7108  {
7109  if (d1->class_mop == d2->class_mop)
7110  {
7111  status = DC_EQUAL;
7112  }
7113  else if (d1->class_mop == NULL)
7114  {
7115  status = DC_LESS_SPECIFIC;
7116  }
7117  else if (d2->class_mop == NULL)
7118  {
7119  status = DC_MORE_SPECIFIC;
7120  }
7121  else if (find_superclass (d1->class_mop, NULL, d2->class_mop))
7122  {
7123  status = DC_MORE_SPECIFIC;
7124  }
7125  else if (find_superclass (d2->class_mop, NULL, d1->class_mop))
7126  {
7127  status = DC_LESS_SPECIFIC;
7128  }
7129  else
7130  {
7131  status = DC_INCOMPATIBLE;
7132  }
7133  }
7134  else if (pr_is_set_type (TP_DOMAIN_TYPE (d1)))
7135  {
7136  /* set element domains must be compatible */
7137  status = DC_EQUAL;
7138  }
7139  else
7140  {
7141  status = DC_EQUAL;
7142  }
7143  }
7144 
7145  return status;
7146 }
7147 
7148 /*
7149  * find_argument() - Helper function for compare_argument_domains.
7150  * Locate an argument by number. These need to be stored in
7151  * an array for easier lookup.
7152  * return: argument structure
7153  * sig(in): method signature
7154  * argnum(in): argument index
7155  */
7156 
7157 static SM_METHOD_ARGUMENT *
7159 {
7160  SM_METHOD_ARGUMENT *arg;
7161 
7162  for (arg = sig->args; arg != NULL && arg->index != argnum; arg = arg->next)
7163  ;
7164 
7165  return arg;
7166 }
7167 
7168 /*
7169  * compare_argument_domains() - This compares the argument lists of two methods
7170  * to see if they are compatible.
7171  * Currently this is defined so that the arguments must match
7172  * exactly. Eventually this could support the notion of "contravariance"
7173  * in the signature.
7174  * return: domain comparison code
7175  * m1(in): method 1
7176  * m2(in): method 2
7177  */
7178 
7179 static DOMAIN_COMP
7181 {
7182  DOMAIN_COMP status, arg_status;
7183  SM_METHOD_SIGNATURE *sig1, *sig2;
7184  SM_METHOD_ARGUMENT *arg1, *arg2;
7185  int i;
7186 
7187  status = DC_EQUAL;
7188 
7189  sig1 = m1->signatures;
7190  sig2 = m2->signatures;
7191 
7192  /* If both signatures are NULL, assume its ok, this is largely for backward compatibility. */
7193  if (sig1 == NULL || sig2 == NULL)
7194  {
7195  if (sig1 != sig2)
7196  {
7197  status = DC_INCOMPATIBLE;
7198  }
7199  }
7200  else if (sig1->num_args == sig2->num_args)
7201  {
7202  /* Since the arguments aren't set stored in an array, lookup is harder than it should be. Recall that arg
7203  * indexes start with 1 */
7204  for (i = 1; i <= sig1->num_args && status == DC_EQUAL; i++)
7205  {
7206  arg1 = find_argument (sig1, i);
7207  arg2 = find_argument (sig2, i);
7208 
7209  /* if either arg is missing, could assume its a "void" and allow it */
7210  if (arg1 == NULL || arg2 == NULL)
7211  {
7212  if (arg1 != arg2)
7213  {
7214  status = DC_INCOMPATIBLE;
7215  }
7216  }
7217  else
7218  {
7219  arg_status = compare_domains (arg1->domain, arg2->domain);
7220  if (arg_status != DC_EQUAL)
7221  {
7222  status = DC_INCOMPATIBLE;
7223  }
7224  }
7225  }
7226  }
7227 
7228  return status;
7229 }
7230 
7231 /*
7232  * compare_component_domains() - Compare the domains of two components and
7233  * return an appropriate comparison code.
7234  * The result of this function indicates the state of c1 relative to
7235  * c2, that is, if the result is ER_DOMAIN_LESS_SPECIFIC it means that
7236  * c1 is less specific than c2.
7237  * return: domain comparison code
7238  * c1(in): component
7239  * c2(in): component
7240  */
7241 
7242 static DOMAIN_COMP
7244 {
7245  DOMAIN_COMP arg_status, status = DC_INCOMPATIBLE;
7246  SM_ATTRIBUTE *a1, *a2;
7247  SM_METHOD *m1, *m2;
7248  TP_DOMAIN *d1, *d2;
7249 
7250  if (c1->name_space == ID_METHOD || c1->name_space == ID_CLASS_METHOD)
7251  {
7252  if (c2->name_space == c1->name_space)
7253  {
7254  /* compare return argument domains, should do full argument signatures as well ! be careful here because
7255  * methods don't always have domains specified */
7256  m1 = (SM_METHOD *) c1;
7257  m2 = (SM_METHOD *) c2;
7258  d1 = NULL;
7259  d2 = NULL;
7260  if (m1->signatures != NULL && m1->signatures->value != NULL)
7261  {
7262  d1 = m1->signatures->value->domain;
7263  }
7264  if (m2->signatures != NULL && m2->signatures->value != NULL)
7265  {
7266  d2 = m2->signatures->value->domain;
7267  }
7268 
7269  if (d1 != NULL && d2 != NULL)
7270  {
7271  status = compare_domains (d1, d2);
7272  }
7273  else if (d1 == NULL && d2 == NULL)
7274  {
7275  /* neither specified, assume the same */
7276  status = DC_EQUAL;
7277  }
7278  else
7279  {
7280  /* for now, if either method has no domain, assume its ok. this happens a lot with the multimedia
7281  * classes and will happen when using db_add_method before the argument domains are fully specified */
7282  status = DC_EQUAL;
7283  }
7284 
7285  if (status != DC_INCOMPATIBLE)
7286  {
7287  arg_status = compare_argument_domains (m1, m2);
7288  if (arg_status != DC_EQUAL)
7289  {
7290  status = DC_INCOMPATIBLE;
7291  }
7292  }
7293  }
7294  }
7295  else
7296  {
7297  /* allow combination of instance/shared but not instance/class */
7298  if (c1->name_space == c2->name_space
7300  {
7301  /* regular, shared, or class attribute, these must have domains */
7302  a1 = (SM_ATTRIBUTE *) c1;
7303  a2 = (SM_ATTRIBUTE *) c2;
7304  status = compare_domains (a1->domain, a2->domain);
7305  }
7306  }
7307 
7308  return status;
7309 }
7310 
7311 /* CANDIDATE STRUCTURE MAINTENANCE */
7312 
7313 /*
7314  * make_candidate_from_component() - Construct a candidate structure from
7315  * a class component.
7316  * return: candidate structure
7317  * comp(in): component (attribute or method)
7318  * source(in): MOP of source class (immediate super class)
7319  */
7320 
7321 static SM_CANDIDATE *
7323 {
7324  SM_CANDIDATE *candidate;
7325 
7326  candidate = (SM_CANDIDATE *) db_ws_alloc (sizeof (SM_CANDIDATE));
7327  if (candidate != NULL)
7328  {
7329  candidate->next = NULL;
7330  candidate->name = comp->name;
7331  candidate->alias = NULL;
7332  candidate->name_space = comp->name_space;
7333  candidate->source = source;
7334  candidate->obj = comp;
7335  candidate->is_alias = 0;
7336  candidate->is_requested = 0;
7337  candidate->order = 0;
7338 
7339  if (comp->name_space == ID_METHOD || comp->name_space == ID_CLASS_METHOD)
7340  {
7341  candidate->origin = ((SM_METHOD *) comp)->class_mop;
7342  }
7343  else
7344  {
7345  candidate->origin = ((SM_ATTRIBUTE *) comp)->class_mop;
7346  }
7347  }
7348 
7349  return (candidate);
7350 }
7351 
7352 /*
7353  * free_candidates() - Free a list of candidates structures
7354  * when done with schema flattening.
7355  * return: none
7356  * candidates(in): candidates list
7357  */
7358 
7359 static void
7361 {
7362  SM_CANDIDATE *c, *next;
7363 
7364  for (c = candidates, next = NULL; c != NULL; c = next)
7365  {
7366  next = c->next;
7367  db_ws_free (c);
7368  }
7369 }
7370 
7371 /*
7372  * prune_candidate() - This will remove the first candidate in the list AND
7373  * all other candidates in the list that have the same name. The list of
7374  * candidates with the same name as the first candidate as returned.
7375  * The source list is destructively modified to remove the pruned
7376  * candidates.
7377  * return: pruned candidates
7378  * clist_pointer (in): source candidates list
7379  */
7380 
7381 static SM_CANDIDATE *
7382 prune_candidate (SM_CANDIDATE ** clist_pointer)
7383 {
7384  SM_CANDIDATE *candidates, *head;
7385 
7386  candidates = NULL;
7387  head = *clist_pointer;
7388  if (head != NULL)
7389  {
7390  candidates =
7391  (SM_CANDIDATE *) nlist_filter ((DB_NAMELIST **) clist_pointer, head->name, (NLSEARCHER) SM_COMPARE_NAMES);
7392  }
7393 
7394  return candidates;
7395 }
7396 
7397 /*
7398  * add_candidate() - This adds a candidate structure for the component to
7399  * the candidates list.
7400  * If the component has an alias resolution in the resolution list,
7401  * the candidate is marked as being aliased and an additional candidate
7402  * is added to the list with the alias name.
7403  * return: none
7404  * candlist(in/out): pointer to candidate list head
7405  * comp(in): component to build a candidate for
7406  * order(in): the definition order of this candidate
7407  * source(in): the source class of the candidate
7408  * resolutions(in): resolution list in effect
7409  */
7410 
7411 static void
7412 add_candidate (SM_CANDIDATE ** candlist, SM_COMPONENT * comp, int order, MOP source, SM_RESOLUTION * resolutions)
7413 {
7414  SM_CANDIDATE *new_;
7415  SM_RESOLUTION *res;
7416 
7417  new_ = make_candidate_from_component (comp, source);
7418  if (new_ == NULL)
7419  {
7420  return;
7421  }
7422 
7423  new_->order = order;
7424  new_->next = *candlist;
7425  *candlist = new_;
7426 
7427  /* check the resolution list to see if there are any aliases for this component */
7428  res = classobj_find_resolution (resolutions, source, comp->name, ID_NULL);
7429  if (res != NULL)
7430  {
7431  if (res->alias == NULL)
7432  {
7433  /* mark the component as being specifically requested */
7434  new_->is_requested = 1;
7435  }
7436  else
7437  {
7438  /* mark the candidate as having an alias */
7439  new_->alias = res->alias;
7440  /* make an entry in the candidates list for the alias */
7441  new_ = make_candidate_from_component (comp, source);
7442  if (new_ == NULL)
7443  {
7444  return;
7445  }
7446  new_->name = res->alias;
7447  new_->is_alias = 1;
7448  new_->order = order;
7449  new_->next = *candlist;
7450  *candlist = new_;
7451  }
7452  }
7453 }
7454 
7455 /*
7456  * make_component_from_candidate() - Called after candidate flattening
7457  * to construct an actual class component for a flattened candidate.
7458  * return: class component
7459  * classop(in): class being defined
7460  * cand(in): candidate structure
7461  */
7462 
7463 static SM_COMPONENT *
7465 {
7466  SM_COMPONENT *new_;
7467  SM_ATTRIBUTE *att = NULL;
7468  SM_METHOD *method = NULL;
7469  SM_NAME_SPACE space;
7470 
7471  new_ = NULL;
7472 
7473  space = cand->obj->name_space;
7474  if (space == ID_METHOD || space == ID_CLASS_METHOD)
7475  {
7476  method = classobj_copy_method ((SM_METHOD *) cand->obj, NULL);
7477  if (method == NULL)
7478  {
7479  return NULL;
7480  }
7481  new_ = (SM_COMPONENT *) method;
7482  method->order = cand->order;
7483 
7484  /* if this is an inherited component, clear out certain fields that don't get inherited automatically */
7485  if (cand->source != NULL && cand->source != classop)
7486  {
7487  method->id = -1;
7488  }
7489  }
7490  else
7491  {
7492  att = classobj_copy_attribute ((SM_ATTRIBUTE *) cand->obj, NULL);
7493  if (att == NULL)
7494  {
7495  return NULL;
7496  }
7497  new_ = (SM_COMPONENT *) att;
7498  att->order = cand->order;
7499 
7500  /* !! ALWAYS CLEAR THIS, ITS A RUN TIME ONLY FLAG AND CAN'T MAKE IT TO DISK */
7501  att->flags &= ~SM_ATTFLAG_NEW;
7502 
7503  /* if this is an inherited component, clear out certain fields that don't get inherited automatically. We now
7504  * allow the UNIQUE constraint to be inherited but not INDEX */
7505 
7506  if (cand->source != NULL && cand->source != classop)
7507  {
7508  att->id = -1; /* must reassign this */
7509  }
7510  }
7511 
7512  /* if this is an alias candidate, change the name */
7513  if (cand->is_alias)
7514  {
7515  ws_free_string (new_->name);
7516  new_->name = ws_copy_string (cand->name);
7517  if (new_->name == NULL)
7518  {
7519  if (method)
7520  {
7521  classobj_free_method (method);
7522  }
7523 
7524  if (att)
7525  {
7527  }
7528  new_ = NULL;
7529  }
7530  }
7531 
7532  return new_;
7533 }
7534 
7535 /* CANDIDATE GATHERING */
7536 /*
7537  * get_candidates() - This builds a candidates list for either the instance
7538  * or class name_space. The candidates list is the raw flattened list of all
7539  * the attribute and method definitions in the name_space.
7540  * Each candidate is tagged with an order counter so that the definition
7541  * order can be preserved in the resulting class. Although attributes
7542  * and methods are included on the same candidates list, they are ordered
7543  * separately.
7544  * return: candidates list
7545  * def(in): original template
7546  * flag(in): flattened template (in progress)
7547  * namespace(in): ID_CLASS or ID_INSTANCE
7548  */
7549 
7550 static SM_CANDIDATE *
7552 {
7553  SM_COMPONENT *complist, *comp;
7554  SM_RESOLUTION *reslist;
7555  SM_ATTRIBUTE *att;
7556  SM_CANDIDATE *candlist;
7557  DB_OBJLIST *super;
7558  SM_CLASS *sclass;
7559  int att_order, meth_order;
7560 
7561  candlist = NULL;
7562  /* get appropriate resolution list from the flattened template */
7563  if (name_space == ID_CLASS)
7564  {
7565  reslist = flat->class_resolutions;
7566  }
7567  else
7568  {
7569  reslist = flat->resolutions;
7570  }
7571 
7572  /* initialize the component order counters */
7573  att_order = 0;
7574  meth_order = 0;
7575 
7576  /* go left to right through the supers adding the components in order */
7577  for (super = def->inheritance; super != NULL; super = super->next)
7578  {
7579  if (au_fetch_class_force (super->op, &sclass, AU_FETCH_READ) != NO_ERROR)
7580  {
7581  continue;
7582  }
7583 
7584  if (name_space == ID_CLASS)
7585  {
7586  /* add the class attributes */
7587  complist =
7588  (SM_COMPONENT *) ((sclass->new_ == NULL) ? sclass->class_attributes : sclass->new_->class_attributes);
7589  for (comp = complist; comp != NULL; comp = comp->next, att_order++)
7590  {
7591  add_candidate (&candlist, comp, att_order, super->op, reslist);
7592  }
7593 
7594  /* add the class methods */
7595  complist = (SM_COMPONENT *) ((sclass->new_ == NULL) ? sclass->class_methods : sclass->new_->class_methods);
7596  for (comp = complist; comp != NULL; comp = comp->next, meth_order++)
7597  {
7598  add_candidate (&candlist, comp, meth_order, super->op, reslist);
7599  }
7600  }
7601  else
7602  {
7603  /* add the instance and shared attributes, the template is ordered */
7604  if (sclass->new_ != NULL)
7605  {
7606  for (att = sclass->new_->attributes; att != NULL; att = (SM_ATTRIBUTE *) att->header.next, att_order++)
7607  {
7608  add_candidate (&candlist, (SM_COMPONENT *) att, att_order, super->op, reslist);
7609  }
7610  }
7611  else
7612  {
7613  /* get these from the ordered list ! */
7614  for (att = sclass->ordered_attributes; att != NULL; att = att->order_link, att_order++)
7615  {
7616  add_candidate (&candlist, (SM_COMPONENT *) att, att_order, super->op, reslist);
7617  }
7618  }
7619  /* add the instance methods */
7620  complist = (SM_COMPONENT *) ((sclass->new_ == NULL) ? sclass->methods : sclass->new_->methods);
7621  for (comp = complist; comp != NULL; comp = comp->next, meth_order++)
7622  {
7623  add_candidate (&candlist, comp, meth_order, super->op, reslist);
7624  }
7625  }
7626  }
7627 
7628  /* get local definition component list */
7629  if (name_space == ID_CLASS)
7630  {
7631  /* add local class attributes */
7632  complist = (SM_COMPONENT *) def->class_attributes;
7633  for (comp = complist; comp != NULL; comp = comp->next, att_order++)
7634  {
7635  add_candidate (&candlist, comp, att_order, def->op, NULL);
7636  }
7637 
7638  /* add local class methods */
7639  complist = (SM_COMPONENT *) def->class_methods;
7640  for (comp = complist; comp != NULL; comp = comp->next, meth_order++)
7641  {
7642  add_candidate (&candlist, comp, meth_order, def->op, NULL);
7643  }
7644  }
7645  else
7646  {
7647  /* add local attributes */
7648  complist = (SM_COMPONENT *) def->attributes;
7649  for (comp = complist; comp != NULL; comp = comp->next, att_order++)
7650  {
7651  add_candidate (&candlist, comp, att_order, def->op, NULL);
7652  }
7653 
7654  /* add local methods */
7655  complist = (SM_COMPONENT *) def->methods;
7656  for (comp = complist; comp != NULL; comp = comp->next, meth_order++)
7657  {
7658  add_candidate (&candlist, comp, meth_order, def->op, NULL);
7659  }
7660  }
7661 
7662  return candlist;
7663 }
7664 
7665 /*
7666  * CANDIDATE LIST RULES
7667  * These functions map over a pruned candidates list checking for various
7668  * rules of inheritance. Some rules are checked in the more complex
7669  * function resolve_candidates(), so that better error messages can
7670  * be produced.
7671  */
7672 
7673 /*
7674  * check_attribute_method_overlap() - This checks the candidates in the list
7675  * to see if there are any attributes and methods with the same name.
7676  * return: NO_ERROR on success, non-zero for ERROR
7677  * template(in): template of class being edited (used for class name only)
7678  * candidates(in): candidate list
7679  */
7680 
7681 static int
7683 {
7684  int error = NO_ERROR;
7685  SM_CANDIDATE *att_cand, *meth_cand, *c;
7686 
7687  att_cand = meth_cand = NULL;
7688 
7689  for (c = candidates; c != NULL && error == NO_ERROR; c = c->next)
7690  {
7691  if (c->name_space == ID_METHOD || c->name_space == ID_CLASS_METHOD)
7692  {
7693  meth_cand = c;
7694  if (att_cand != NULL)
7695  {
7696  ERROR3 (error, ER_SM_INCOMPATIBLE_COMPONENTS, c->name, candidate_source_name (template_, att_cand),
7697  candidate_source_name (template_, c));
7698  }
7699  }
7700  else
7701  {
7702  att_cand = c;
7703  if (meth_cand != NULL)
7704  {
7705  ERROR3 (error, ER_SM_INCOMPATIBLE_COMPONENTS, c->name, candidate_source_name (template_, c),
7706  candidate_source_name (template_, meth_cand));
7707  }
7708  }
7709  }
7710 
7711  return error;
7712 }
7713 
7714 /*
7715  * check_alias_conflict() - This checks for candidates that were produced
7716  * by aliasing an inherited component. If an alias is defined, there can be
7717  * only one component with that name. Two inherited components cannot
7718  * have the same alias and an alias cannot conflict with a "real"
7719  * component.
7720  * return: NO_ERROR on success, non-zero for ERROR
7721  * template(in): class template (used for name only)
7722  * candidates(in): candidates list
7723  */
7724 
7725 static int
7726 check_alias_conflict (SM_TEMPLATE * template_, SM_CANDIDATE * candidates)
7727 {
7728  int error = NO_ERROR;
7729  SM_CANDIDATE *c, *normal, *alias;
7730 
7731  normal = alias = NULL;
7732 
7733  for (c = candidates; c != NULL && error == NO_ERROR; c = c->next)
7734  {
7735  /* ignore candidates that have been aliased to something else */
7736  if (c->alias == NULL)
7737  {
7738  /* is this candidate using an alias name ? */
7739  if (c->is_alias == 0)
7740  {
7741  /* could be smarter and recognize most specific domains and shadowing in case we get one of the error
7742  * conditions below */
7743  normal = c;
7744  }
7745  else
7746  {
7747  if (alias != NULL)
7748  {
7749  /* Alias name `%1s' is used more than once. */
7750  ERROR1 (error, ER_SM_MULTIPLE_ALIAS, alias->name);
7751  }
7752  else
7753  {
7754  alias = c;
7755  }
7756  }
7757  }
7758  }
7759 
7760  if (error == NO_ERROR && alias != NULL && normal != NULL)
7761  {
7762 
7763  if (normal->source == NULL || normal->source == template_->op)
7764  {
7765  /* Can't use "alias" as an alias for inherited component "name", there is already a locally defined component
7766  * with that name */
7767  ERROR2 (error, ER_SM_ALIAS_COMPONENT_EXISTS, alias->name, alias->obj->name);
7768  }
7769  else
7770  {
7771  /* Can't use `%1$s' as an alias for `%2$s' of `%3$s'. A component with that name is already inherited from
7772  * `%4s'. */
7773  ERROR4 (error, ER_SM_ALIAS_COMPONENT_INHERITED, alias->name, alias->obj->name,
7774  candidate_source_name (template_, alias), candidate_source_name (template_, normal));
7775  }
7776  }
7777 
7778  return error;
7779 }
7780 
7781 /*
7782  * check_alias_domains() - This checks the domains of all candidates in the
7783  * list that have been given aliases.
7784  * Candidates with aliases will be ignored during resolution.
7785  * The rule is however that if a candidate is aliased,
7786  * there must be an appropriate substitute candidate from another class.
7787  * This function first checks to make sure that all of the aliased
7788  * candidates have compatible domains.
7789  * While this check is being done, the alias with the most specific domain
7790  * is found. The domain of the alias substitute must be at least
7791  * as specific as the domains of all the candidates that were aliased.
7792  * This last test is performed at the end of resolve_candidates().
7793  * return: NO_ERROR on success, non-zero for ERROR
7794  * template(in): class template (used for name only)
7795  * candidates(in): candidates list
7796  * most_specific(out): return pointer to most specific aliased candidate
7797  */
7798 
7799 static int
7800 check_alias_domains (SM_TEMPLATE * template_, SM_CANDIDATE * candidates, SM_CANDIDATE ** most_specific)
7801 {
7802  int error = NO_ERROR;
7803  SM_CANDIDATE *c, *most;
7804  DOMAIN_COMP dstate;
7805 
7806  most = NULL;
7807  for (c = candidates; c != NULL && error == NO_ERROR; c = c->next)
7808  {
7809  if (c->alias != NULL)
7810  { /* only look at candidates that are aliased */
7811  if (most == NULL)
7812  {
7813  most = c;
7814  }
7815  else if (c->origin != most->origin)
7816  {
7817  dstate = compare_component_domains (c->obj, most->obj);
7818  switch (dstate)
7819  {
7820  case DC_INCOMPATIBLE:
7821  ERROR4 (error, ER_SM_INCOMPATIBLE_DOMAINS, c->name, candidate_source_name (template_, most),
7822  candidate_source_name (template_, c), template_classname (template_));
7823  break;
7824 
7825  case DC_MORE_SPECIFIC:
7826  most = c;
7827  break;
7828 
7829  case DC_EQUAL:
7830  case DC_LESS_SPECIFIC:
7831  /* ignore it */
7832  break;
7833  }
7834  }
7835  }
7836  }
7837 
7838  *most_specific = most;
7839  return error;
7840 }
7841 
7842 /* CANDIDATE RESOLUTION */
7843 /*
7844  * auto_resolve_conflict() - Add (or modify an existing) resolution for
7845  * the candidate to a resolution list.
7846  * return: none
7847  * candiate(in): candidate needing resolution
7848  * resolutions(in/out): pointer to resolution list
7849  * resspace(in): resolution space (class or instance)
7850  */
7851 
7852 static void
7853 auto_resolve_conflict (SM_CANDIDATE * candidate, SM_RESOLUTION ** resolutions, SM_NAME_SPACE resspace)
7854 {
7855  SM_RESOLUTION *res, *found;
7856 
7857  found = NULL;
7858  for (res = *resolutions; res != NULL && found == NULL; res = res->next)
7859  {
7860  if (res->name_space == resspace && (SM_COMPARE_NAMES (res->name, candidate->name) == 0))
7861  {
7862  if (res->alias == NULL)
7863  {
7864  found = res;
7865  }
7866  }
7867  }
7868  if (found != NULL)
7869  {
7870  /* adjust the existing resolution to point at the new class */
7871  found->class_mop = candidate->source;
7872  }
7873  else
7874  {
7875  /* generate a new resolution */
7876  res = classobj_make_resolution (candidate->source, candidate->name, NULL, resspace);
7877  if (res)
7878  {
7879  res->next = *resolutions;
7880  }
7881  *resolutions = res;
7882  }
7883 }
7884 
7885 /*
7886  * resolve_candidates() - This is the main function for checking component
7887  * combination rules. Given a list of candidates, all of the rules for
7888  * compatibility are checked and a winner is determined if there is
7889  * more than one possible candidate.
7890  * If any of the rules fail, an error code is returned.
7891  * return: NO_ERROR on success, non-zero for ERROR
7892  * template(in): schema template
7893  * candidates(in): candidates list
7894  * auto_resolve(in): non-zero to enable auto resolution of conflicts
7895  * winner_return(out): returned pointer to winning candidates
7896  */
7897 
7898 static int
7899 resolve_candidates (SM_TEMPLATE * template_, SM_CANDIDATE * candidates, int auto_resolve, SM_CANDIDATE ** winner_return)
7900 {
7901  int error = NO_ERROR;
7902  SM_CANDIDATE *winner, *c, *requested, *conflict, *local, *alias;
7903  SM_NAME_SPACE resspace;
7904  DOMAIN_COMP dstate;
7905 
7906  winner = NULL;
7907  alias = NULL;
7908  requested = NULL;
7909  local = NULL;
7910  conflict = NULL;
7911 
7912  /* first check some simple rules */
7913  if ((error = check_attribute_method_overlap (template_, candidates)))
7914  {
7915  return error;
7916  }
7917 
7918  if ((error = check_alias_conflict (template_, candidates)))
7919  {
7920  return error;
7921  }
7922 
7923  if ((error = check_alias_domains (template_, candidates, &alias)))
7924  {
7925  return error;
7926  }
7927 
7928  /* look for a local & requested component */
7929  for (c = candidates; c != NULL; c = c->next)
7930  {
7931  if (c->source == NULL || c->source == template_->op)
7932  {
7933  /* if local is not NULL here, its technically an error */
7934  local = c;
7935  }
7936  if (c->is_requested)
7937  {
7938  /* if local is not NULL here, its technically an error */
7939  requested = c;
7940  }
7941  }
7942 
7943  /* establish an initial winner if possible */
7944  if (local == NULL)
7945  {
7946  winner = requested;
7947  }
7948  else
7949  {
7950  winner = local;
7951  /* this means that we found a resolution for an inherited attribute but we also have a local definition, in this
7952  * case the resolution has no effect and is deleted */
7953  /* remove_invalid_resolution(template, requested); */
7954  requested = NULL;
7955  }
7956 
7957  /* loop through the non-aliases candidates looking for a winner should detect aliases that are ignored because of a
7958  * local definition and remove them from the resolution list ! - try to handle this during template building */
7959 
7960  for (c = candidates; c != NULL && error == NO_ERROR; c = c->next)
7961  {
7962  if (c->alias == NULL)
7963  {
7964  if (winner == NULL)
7965  {
7966  winner = c;
7967  }
7968  else if (c != winner && c->origin != winner->origin)
7969  {
7970  dstate = compare_component_domains (c->obj, winner->obj);
7971  switch (dstate)
7972  {
7973  case DC_INCOMPATIBLE:
7974  if (local == NULL)
7975  /* incompatibility between two inherited things */
7976  ERROR4 (error, ER_SM_INCOMPATIBLE_DOMAINS, winner->name, candidate_source_name (template_, winner),
7977  candidate_source_name (template_, c), template_classname (template_));
7978  else
7979  {
7980  /* incompatiblity between inherited thing and a locally defined thing */
7981  ERROR3 (error, ER_SM_INCOMPATIBLE_SHADOW, winner->name, candidate_source_name (template_, c),
7982  template_classname (template_));
7983  }
7984  break;
7985  case DC_MORE_SPECIFIC:
7986  if (local != NULL)
7987  {
7988  /* trying to shadow an inherited attribute with a more specific domain */
7989  ERROR3 (error, ER_SM_INCOMPATIBLE_SHADOW, winner->name, candidate_source_name (template_, c),
7990  template_classname (template_));
7991  }
7992  else
7993  {
7994  /* must override requested resolution or issue error */
7995  if (winner != requested || auto_resolve)
7996  {
7997  winner = c;
7998  /* reset conflict when upgrading the domain of the winner */
7999  conflict = NULL;
8000  }
8001  else
8002  {
8003  /* can't override resolution on <attname> of <classname> with required attribute from
8004  * <classname2> */
8005  ERROR4 (error, ER_SM_RESOLUTION_OVERRIDE, winner->name,
8006  candidate_source_name (template_, winner), candidate_source_name (template_, c),
8007  template_classname (template_));
8008  }
8009  }
8010  break;
8011  case DC_EQUAL:
8012  /* remember the conflict for later, it may be ignored if there is another candidate with a more
8013  * specific domain */
8014  if (local == NULL && winner != requested)
8015  conflict = c;
8016  break;
8017  case DC_LESS_SPECIFIC:
8018  /* ignore it */
8019  break;
8020  }
8021  }
8022  }
8023  }
8024 
8025  /* check for compatibility with any aliased components */
8026  if (error == NO_ERROR && alias != NULL)
8027  {
8028  if (winner == NULL)
8029  {
8030  ERROR3 (error, ER_SM_MISSING_ALIAS_SUBSTITUTE, alias->name, candidate_source_name (template_, alias),
8031  template_classname (template_));
8032  }
8033  else
8034  {
8035  dstate = compare_component_domains (winner->obj, alias->obj);
8036  if (dstate == DC_INCOMPATIBLE)
8037  {
8038  /* we need to differentiate between a local reference conflicting with an alias so that we can give a
8039  * better error message. */
8040  if (local == winner)
8041  {
8043  candidate_source_name (template_, alias), template_classname (template_));
8044  }
8045  else
8046  {
8048  candidate_source_name (template_, winner), candidate_source_name (template_, alias),
8049  template_classname (template_));
8050  }
8051  }
8052  else if (dstate == DC_LESS_SPECIFIC)
8053  {
8055  candidate_source_name (template_, alias), candidate_source_name (template_, winner),
8056  template_classname (template_));
8057  }
8058  }
8059  }
8060 
8061  /* check for conflicts between two classes of the most specific domains */
8062  if (error == NO_ERROR && conflict != NULL)
8063  {
8064  if (auto_resolve)
8065  {
8066  resspace = sm_resolution_space (winner->name_space);
8067  auto_resolve_conflict (winner, &template_->resolutions, resspace);
8068  }
8069  else
8070  {
8071  ERROR3 (error, ER_SM_ATTRIBUTE_NAME_CONFLICT, winner->name, candidate_source_name (template_, winner),
8072  candidate_source_name (template_, conflict));
8073  }
8074  }
8075 
8076  if (error == NO_ERROR)
8077  {
8078  *winner_return = winner;
8079  }
8080  else
8081  {
8082  *winner_return = NULL;
8083  }
8084 
8085  return error;
8086 }
8087 
8088 /* COMPONENT FLATTENING */
8089 /*
8090  * insert_attribute()
8091  * insert_method() - This inserts an attribute into a list positioned according
8092  * to the "order" field.
8093  * This is intended to be used for the ordering of the flattened attribute
8094  * list. As such, we don't use the order_link field here we just use
8095  * the regular next field.
8096  * Unfortunately we need a separate method version of this since the
8097  * order field isn't part of the common header.
8098  * return: none
8099  * attlist(in/out): pointer to attribte list
8100  * att(in): attribute to insert
8101  */
8102 
8103 static void
8105 {
8106  SM_ATTRIBUTE *a, *prev;
8107 
8108  prev = NULL;
8109  for (a = *attlist; a != NULL && a->order < att->order; a = (SM_ATTRIBUTE *) a->header.next)
8110  {
8111  prev = a;
8112  }
8113 
8114  att->header.next = (SM_COMPONENT *) a;
8115  if (prev == NULL)
8116  {
8117  *attlist = att;
8118  }
8119  else
8120  {
8121  prev->header.next = (SM_COMPONENT *) att;
8122  }
8123 }
8124 
8125 static void
8126 insert_method (SM_METHOD ** methlist, SM_METHOD * method)
8127 {
8128  SM_METHOD *m, *prev;
8129 
8130  prev = NULL;
8131  for (m = *methlist; m != NULL && m->order < method->order; m = (SM_METHOD *) m->header.next)
8132  {
8133  prev = m;
8134  }
8135 
8136  method->header.next = (SM_COMPONENT *) m;
8137  if (prev == NULL)
8138  {
8139  *methlist = method;
8140  }
8141  else
8142  {
8143  prev->header.next = (SM_COMPONENT *) method;
8144  }
8145 }
8146 
8147 /*
8148  * flatten_components() - This is used to flatten the components of a template.
8149  * The components are first converted into a list of candidates.
8150  * The candidates list is then checked for the rules of compatibility
8151  * and conflicts are resolved. The winning candidate for each name
8152  * is then converted back to a component and added to the template
8153  * on the appropriate list.
8154  * NOTE: Formerly we assumed that the candidates would be pruned and
8155  * resolved in order. Although the "order" field in each candidate
8156  * will be set correctly we can't assume that the resulting list we
8157  * produce is also ordered. This is important mainly because this
8158  * template will be stored on the class and used in the flattening
8159  * of any subclasses. get_candidates assumes that the template
8160  * lists of the super classes are ordered.
8161  * return: NO_ERROR on success, non-zero for ERROR
8162  * def(in): schema template
8163  * flat(out): flattened template
8164  * namespace(in): component name_space
8165  * auto_res(in): non-zero to enable auto resolution of conflicts
8166  */
8167 
8168 static int
8169 flatten_components (SM_TEMPLATE * def, SM_TEMPLATE * flat, SM_NAME_SPACE name_space, int auto_res)
8170 {
8171  int error = NO_ERROR;
8172  SM_CANDIDATE *candlist, *candidates, *winner = NULL;
8173  SM_COMPONENT *comp;
8174 
8175  /* get all of the possible candidates for this name_space (class or instance) */
8176  candlist = get_candidates (def, flat, name_space);
8177 
8178  /* prune the like named candidates of the list one at a time, check for consistency and resolve any conflicts */
8179 
8180  while (error == NO_ERROR && ((candidates = prune_candidate (&candlist)) != NULL))
8181  {
8182  error = resolve_candidates (flat, candidates, auto_res, &winner);
8183 
8184  if (error == NO_ERROR)
8185  {
8186  if (winner != NULL)
8187  {
8188  /* convert the candidate back to a component */
8189  comp = make_component_from_candidate (def->op, winner);
8190  if (comp == NULL)
8191  {
8192  assert (er_errid () != NO_ERROR);
8193  error = er_errid ();
8194  free_candidates (candidates);
8195  break;
8196  }
8197 
8198  /* add it to the appropriate list */
8199  switch (comp->name_space)
8200  {
8201  case ID_ATTRIBUTE:
8202  case ID_SHARED_ATTRIBUTE:
8203  insert_attribute (&flat->attributes, (SM_ATTRIBUTE *) comp);
8204  break;
8205  case ID_CLASS_ATTRIBUTE:
8206  insert_attribute (&flat->class_attributes, (SM_ATTRIBUTE *) comp);
8207  break;
8208  case ID_METHOD:
8209  insert_method (&flat->methods, (SM_METHOD *) comp);
8210  break;
8211  case ID_CLASS_METHOD:
8212  insert_method (&flat->class_methods, (SM_METHOD *) comp);
8213  break;
8214  default:
8215  db_ws_free (comp);
8216  break;
8217  }
8218  }
8219  }
8220  free_candidates (candidates);
8221  }
8222 
8223  /* If an error occurs, the remaining candidates in candlist should be freed */
8224 
8225  if (candlist)
8226  {
8227  free_candidates (candlist);
8228  }
8229 
8230  return error;
8231 }
8232 
8233 /*
8234  * flatten_method_files() - Flatten the method file lists from the template
8235  * into the flattened template.
8236  * return: NO_ERROR on success, non-zero for ERROR
8237  * def(in): schema template
8238  * flat(out): flattened template
8239  */
8240 
8241 static int
8243 {
8244  DB_OBJLIST *super;
8245  SM_CLASS *class_;
8246  SM_METHOD_FILE *mfile, *new_mfile;
8247 
8248  /* start by copying the local files to the template */
8250  {
8251  goto memory_error;
8252  }
8253 
8254  /* collect files from the super classes if we don't already have them */
8255 
8256  for (super = flat->inheritance; super != NULL; super = super->next)
8257  {
8258  /* better not be any fetch errors at this point */
8259  if (au_fetch_class_force (super->op, &class_, AU_FETCH_READ))
8260  {
8261  goto memory_error; /* may be a deadlock abort !, don't overwrite the error */
8262  }
8263 
8264  /* if the class is being edited, be sure and get its pending file list */
8265  if (class_->new_ != NULL)
8266  {
8267  mfile = class_->new_->method_files;
8268  }
8269  else
8270  {
8271  mfile = class_->method_files;
8272  }
8273 
8274  for (; mfile != NULL; mfile = mfile->next)
8275  {
8276  if (!NLIST_FIND (flat->method_files, mfile->name))
8277  {
8278  new_mfile = classobj_make_method_file (mfile->name);
8279  if (new_mfile == NULL)
8280  {
8281  goto memory_error;
8282  }
8283  new_mfile->class_mop = mfile->class_mop;
8284  WS_LIST_APPEND (&flat->method_files, new_mfile);
8285  }
8286  }
8287  }
8288 
8289  return NO_ERROR;
8290 
8291 memory_error:
8292  assert (er_errid () != NO_ERROR);
8293  return er_errid ();
8294 }
8295 
8296 /*
8297  * flatten_query_spec_lists() - Flatten the query_spec lists.
8298  * Note that query_spec lists aren't flattened, we just use the one
8299  * currently in the template.
8300  * return: NO_ERROR on success, non-zero for ERROR
8301  * def(in): schema template
8302  * flat(out): flattened template
8303  */
8304 
8305 static int
8307 {
8308  /* start by copying the local definitions to the template */
8309  if (def->query_spec == NULL)
8310  {
8311  flat->query_spec = NULL;
8312  }
8313  else
8314  {
8316  if (flat->query_spec == NULL)
8317  {
8318  assert (er_errid () != NO_ERROR);
8319  return er_errid ();
8320  }
8321  }
8322 
8323  /* no need to flatten the query_spec lists */
8324  return NO_ERROR;
8325 }
8326 
8327 /*
8328  * filter_resolutions() - Work function for check_shadowed_resolutions.
8329  * This will search the resolution list for entries that use a particular
8330  * name and remove them. This is used to remove resolution entries
8331  * that are invalid because there is a local definition for a class
8332  * component (attribute or method) that must use that name.
8333  * return: none
8334  * template(in/out): class definition template
8335  * name(in): component name
8336  * resspace(in): component name_space
8337  */
8338 
8339 static void
8340 filter_component_resolutions (SM_TEMPLATE * template_, const char *name, SM_NAME_SPACE resspace)
8341 {
8342  SM_RESOLUTION **reslist, *res, *prev, *next;
8343  const char *rname;
8344 
8345  reslist = (resspace == ID_INSTANCE) ? &(template_->resolutions) : &(template_->class_resolutions);
8346 
8347  prev = next = NULL;
8348  for (res = *reslist; res != NULL; res = next)
8349  {
8350  next = res->next;
8351  if (res->name_space != resspace)
8352  {
8353  prev = res;
8354  }
8355  else
8356  {
8357  rname = (res->alias == NULL) ? res->name : res->alias;
8358  if (SM_COMPARE_NAMES (rname, name) != 0)
8359  {
8360  prev = res;
8361  }
8362  else
8363  {
8364  if (prev == NULL)
8365  {
8366  *reslist = next;
8367  }
8368  else
8369  {
8370  prev->next = next;
8371  }
8372  res->next = NULL;
8374  }
8375  }
8376  }
8377 }
8378 
8379 /*
8380  * remove_shadowed_resolutions() - This will make sure that there are
8381  * no resolutions in the flattened template that conflict with the names
8382  * of any locally defined components.
8383  * Since the local components will always take precidence over the
8384  * inherited components, resolutions for these inherited components would
8385  * make no sense.
8386  * Note that since the flattened template hasn't been populated with
8387  * components yet, we get the local component list from the original
8388  * template but we modify the resolution list on the flattened
8389  * template.
8390  * return: none
8391  * original(in):
8392  * flat(in/out):
8393  */
8394 
8395 static void
8397 {
8398  SM_COMPONENT *comp;
8399 
8400  for (comp = (SM_COMPONENT *) original->attributes; comp != NULL; comp = comp->next)
8401  {
8403  }
8404 
8405  for (comp = (SM_COMPONENT *) original->methods; comp != NULL; comp = comp->next)
8406  {
8408  }
8409 
8410  for (comp = (SM_COMPONENT *) original->class_attributes; comp != NULL; comp = comp->next)
8411  {
8413  }
8414 
8415  for (comp = (SM_COMPONENT *) original->class_methods; comp != NULL; comp = comp->next)
8416  {
8418  }
8419 }
8420 
8421 /*
8422  * filter_reslist() - This removes any resolutions in the list that
8423  * reference the deleted class.
8424  * return: none
8425  * reslist(in/out): resolution list filter
8426  * deleted_class(in): class to remove
8427  */
8428 
8429 static void
8430 filter_reslist (SM_RESOLUTION ** reslist, MOP deleted_class)
8431 {
8432  SM_RESOLUTION *res, *next, *prev;
8433 
8434  /* filter out any resolutions for the deleted class */
8435  if (deleted_class != NULL)
8436  {
8437  for (res = *reslist, prev = NULL, next = NULL; res != NULL; res = next)
8438  {
8439  next = res->next;
8440  if (res->class_mop != deleted_class)
8441  {
8442  prev = res;
8443  }
8444  else
8445  {
8446  if (prev == NULL)
8447  *reslist = next;
8448  else
8449  prev->next = next;
8451  }
8452  }
8453  }
8454 }
8455 
8456 /*
8457  * check_resolution_target() - This checks to see if a particular resolution
8458  * makes sense for a template. This means that the class specified in the
8459  * resolution must be on the inheritance list of the template and that the
8460  * component name in the resolution must be a valid component of the
8461  * class.
8462  * This may be more easily done if we keep track of the resolutions
8463  * that were actually used during flattening and then prune the ones
8464  * that weren't used. Think about doing this when we rewrite the
8465  * flattening algorithm.
8466  * Determination of which list to look on to match the resolution is
8467  * kind of brute force, when the flattening structures are redesigned,
8468  * Try to maintain them in such a way that this sort of operation is
8469  * easier.
8470  * return: NO_ERROR on success, non-zero for ERROR
8471  * template(in): class template
8472  * res(in): resolution to check
8473  * valid_ptr(out): set if resolution is valid (returned)
8474  */
8475 
8476 static int
8477 check_resolution_target (SM_TEMPLATE * template_, SM_RESOLUTION * res, int *valid_ptr)
8478 {
8479  int error = NO_ERROR;
8480  SM_CLASS *super;
8481  int valid;
8482 
8483  valid = 0;
8484  if (ml_find (template_->inheritance, res->class_mop))
8485  {
8486  /* the class exists, must check to see if the attribute still exists in the class. Note that since we may be in a
8487  * subclass of the edited class, we have to look for templates on the superclass. */
8488  error = au_fetch_class_force (res->class_mop, &super, AU_FETCH_READ);
8489  if (error == NO_ERROR)
8490  {
8491  if (super->new_ != NULL)
8492  {
8493  /* its got a template */
8494  if (res->name_space == ID_INSTANCE)
8495  {
8496  if (SM_FIND_NAME_IN_COMPONENT_LIST (super->new_->attributes, res->name) != NULL
8497  || SM_FIND_NAME_IN_COMPONENT_LIST (super->new_->methods, res->name) != NULL)
8498  {
8499  valid = 1;
8500  }
8501  }
8502  else
8503  {
8506  {
8507  valid = 1;
8508  }
8509  }
8510  }
8511  else
8512  {
8513  /* no template, look directly at the class */
8514  if (res->name_space == ID_INSTANCE)
8515  {
8516  if (classobj_find_component (super, res->name, 0) != NULL)
8517  {
8518  valid = 1;
8519  }
8520  }
8521  else
8522  {
8523  if (classobj_find_component (super, res->name, 1))
8524  {
8525  valid = 1;
8526  }
8527  }
8528  }
8529  }
8530  }
8531 
8532  *valid_ptr = valid;
8533  return error;
8534 }
8535 
8536 /*
8537  * check_invalid_resolutions() - This checks a new resolution list for
8538  * resolutions that don't make any sense. If an invalid resolution appears
8539  * in the current definition of a class, it has atrophied as a side affect
8540  * of some operation and will be removed silently.
8541  * If an invalid resolution does not appear in the current definition,
8542  * it was placed in the template by the user in an invalid state and
8543  * an error will be generated.
8544  * return: NO_ERROR on success, non-zero for ERROR
8545  * template(in): class template
8546  * resolutions(in): the resolution list to examine
8547  * original_list(in): the resolution list in the current class definition
8548  */
8549 
8550 static int
8551 check_invalid_resolutions (SM_TEMPLATE * template_, SM_RESOLUTION ** resolutions, SM_RESOLUTION * original_list)
8552 {
8553  int error = NO_ERROR;
8554  SM_RESOLUTION *res, *prev, *next, *original;
8555  int valid;
8556 
8557  for (res = *resolutions, prev = NULL, next = NULL; res != NULL && error == NO_ERROR; res = next)
8558  {
8559  next = res->next;
8560  error = check_resolution_target (template_, res, &valid);
8561  if (error == NO_ERROR)
8562  {
8563  if (valid)
8564  {
8565  prev = res;
8566  }
8567  else
8568  {
8569  /* looks bogus try to find it in the original list */
8570  original = classobj_find_resolution (original_list, res->class_mop, res->name, res->name_space);
8571  if (original != NULL)
8572  {
8573  /* see if the aliases are the same */
8574  if (res->alias != original->alias)
8575  {
8576  if (res->alias != NULL && original->alias != NULL)
8577  {
8578  if (SM_COMPARE_NAMES (res->alias, original->alias) != 0)
8579  {
8580  original = NULL; /* aliases different */
8581  }
8582  }
8583  else
8584  {
8585  original = NULL; /* aliases different */
8586  }
8587  }
8588  }
8589  if (original != NULL)
8590  {
8591  /* an old resolution that is no longer valid, remove it */
8592  if (prev == NULL)
8593  {
8594  *resolutions = next;
8595  }
8596  else
8597  {
8598  prev->next = next;
8599  }
8601  }
8602  else
8603  {
8604  /* a new resolution that is not valid, signal an error */
8605  ERROR3 (error, ER_SM_INVALID_RESOLUTION, template_classname (template_), res->name,
8606  sm_get_ch_name (res->class_mop));
8607  }
8608  }
8609  }
8610  }
8611 
8612  return error;
8613 }
8614 
8615 /*
8616  * flatten_resolutions() - Flatten the resolutions for a template.
8617  * This doesn't really flatten, it just cleans up the resolution
8618  * lists.
8619  * If a class was deleted, remove any references to the deleted class.
8620  * Remove resolutions for inherited components that are now shadowed
8621  * by local components.
8622  * Remove resolutions for non-existent super classes.
8623  * return: NO_ERROR on success, non-zero for ERROR
8624  * def(in): schema template
8625  * flat(in/out): flattened template
8626  * deleted_class(in): deleted class object (optional, can be NULL)
8627  */
8628 
8629 static int
8630 filter_resolutions (SM_TEMPLATE * def, SM_TEMPLATE * flat, MOP deleted_class)
8631 {
8632  int error = NO_ERROR;
8633  SM_RESOLUTION *original;
8634 
8635  /* no flattening, just get the locally defined resolutions */
8637  {
8638  assert (er_errid () != NO_ERROR);
8639  return er_errid ();
8640  }
8641 
8643  {
8644  assert (er_errid () != NO_ERROR);
8645  return er_errid ();
8646  }
8647 
8648  /* filter resolutions that are shadowed by local definitions, might consider these error conditions ? */
8649  remove_shadowed_resolutions (def, flat);
8650 
8651  /* remove all references to the deleted class if any */
8652  filter_reslist (&flat->resolutions, deleted_class);
8653  filter_reslist (&flat->class_resolutions, deleted_class);
8654 
8655  /* look for newly added bogus resolutions */
8656  original = (def->current == NULL) ? NULL : def->current->resolutions;
8657  error = check_invalid_resolutions (flat, &flat->resolutions, original);
8658  if (error == NO_ERROR)
8659  {
8660  error = check_invalid_resolutions (flat, &flat->class_resolutions, original);
8661  }
8662 
8663  return error;
8664 }
8665 
8666 /*
8667  * find_matching_att() - This is a work function for retain_former_ids and
8668  * others. It performs a very common attribute lookup operation.
8669  * An attribute is said to match if the name, source class, and type
8670  * are the same.
8671  * If idmatch is selected the match is based on the id numbers only.
8672  * return: matching attribute
8673  * list(in): attribute list to search
8674  * att(in): attribute to look for
8675  * idmatch(in): flag to cause search based on id rather than name
8676  */
8677 
8678 static SM_ATTRIBUTE *
8679 find_matching_att (SM_ATTRIBUTE * list, SM_ATTRIBUTE * att, int idmatch)
8680 {
8681  SM_ATTRIBUTE *a, *found;
8682 
8683  found = NULL;
8684  for (a = list; a != NULL && found == NULL; a = (SM_ATTRIBUTE *) a->header.next)
8685  {
8686  if (idmatch)
8687  {
8688  if (a->header.name_space == att->header.name_space && a->id == att->id)
8689  {
8690  found = a;
8691  }
8692  }
8693  else
8694  {
8695  if (a->header.name_space == att->header.name_space && SM_COMPARE_NAMES (a->header.name, att->header.name) == 0
8696  && a->class_mop == att->class_mop && a->type == att->type)
8697  {
8698  found = a;
8699  }
8700  }
8701  }
8702 
8703  return found;
8704 }
8705 
8706 /*
8707  * retain_former_ids() - This is a bit of a kludge because we lost the ids of
8708  * the inherited attributes when the template was created.
8709  * This is a problem for inherited attributes that have been renamed
8710  * in the super class. Since they won't match based on name and the
8711  * attribute id is -1, build_storage_order will think the inherited
8712  * attribute was dropped and replaced with one of a different name.
8713  * Immediately after flattening, we call this to fix the attribute
8714  * id assignments for things that are the same.
8715  * I think this would be a good place to copy the values of shared
8716  * and class attributes as well. We will have the same problem of
8717  * name matching.
8718  * When shadowing an inherited attribute, we used to think that we should
8719  * retain the former attribute ID so that we don't lose access to data
8720  * previously stored for that attribute. We now think that this is not
8721  * the correct behavior. A shadowed attribute is a "new" attribute and
8722  * it should shadow the inherited attribute along with its previously
8723  * stored values.
8724  * return: error code
8725  * flat(in): template
8726  */
8727 
8728 static int
8730 {
8731  SM_ATTRIBUTE *new_att, *found, *super_new, *super_old;
8732  SM_CLASS *sclass;
8733 
8734  /* Does this class have a previous representation ? */
8735  if (flat->current != NULL)
8736  {
8737  bool is_partition = false;
8738 
8739  if (flat->current->partition)
8740  {
8741  is_partition = (flat->current->partition->pname != NULL);
8742  }
8743 
8744  /* Check each new inherited class attribute. These attribute will not have an assigned id and their class MOPs
8745  * will not match */
8746  for (new_att = flat->class_attributes; new_att != NULL; new_att = (SM_ATTRIBUTE *) new_att->header.next)
8747  {
8748  /* is this a new attribute ? */
8749  if (new_att->id == -1)
8750  {
8751  /* is it inherited ? */
8752  if (new_att->class_mop != NULL && new_att->class_mop != flat->op)
8753  {
8754  /* look for a matching attribute in the existing representation */
8755  found = find_matching_att (flat->current->class_attributes, new_att, 0);
8756  if (found != NULL)
8757  {
8758  /* re-use this attribute */
8759  new_att->id = found->id;
8760  }
8761  else
8762  {
8763  /* couldn't find it, it may have been renamed in the super class though */
8764  if (au_fetch_class_force (new_att->class_mop, &sclass, AU_FETCH_READ) == NO_ERROR)
8765  {
8766  /* search the super class' pending attribute list for this name */
8767  if (sclass->new_ != NULL)
8768  {
8769  super_new = find_matching_att (sclass->new_->class_attributes, new_att, 0);
8770  if (super_new != NULL)
8771  {
8772  if (is_partition)
8773  {
8774  /* the current class is a partition it is not necessary to check the ID of
8775  * attribute in a the old configuration Also, in case of ALTER .. CHANGE with
8776  * attribute rename and/or type change, the old attribute will not be found by
8777  * name and type */
8778  found = super_new;
8779  new_att->id = found->id;
8780  continue;
8781  }
8782  /*
8783  * search the supers original attribute list
8784  * based on the id of the new one
8785  */
8786  super_old = find_matching_att (sclass->class_attributes, super_new, 1);
8787  if (super_old != NULL)
8788  {
8789  if (SM_COMPARE_NAMES (super_old->header.name, new_att->header.name) != 0)
8790  {
8791  /* search our old list with the old name */
8792  found = find_matching_att (flat->current->class_attributes, super_old, 0);
8793  if (found != NULL)
8794  {
8795  /* found the renamed attribute, reuse id */
8796  new_att->id = found->id;
8797  }
8798  }
8799  }
8800  }
8801  }
8802  }
8803  }
8804  }
8805  }
8806  }
8807 
8808  /* Check each new inherited attribute. These attribute will not have an assigned id and their class MOPs will
8809  * not match */
8810  for (new_att = flat->attributes; new_att != NULL; new_att = (SM_ATTRIBUTE *) new_att->header.next)
8811  {
8812  /* is this a new attribute ? */
8813  if (new_att->id == -1)
8814  {
8815  /* is it inherited ? */
8816  if (new_att->class_mop != NULL && new_att->class_mop != flat->op)
8817  {
8818  /* look for a matching attribute in the existing representation */
8819  found = find_matching_att (flat->current->attributes, new_att, 0);
8820  if (found != NULL)
8821  {
8822  /* re-use this attribute */
8823  new_att->id = found->id;
8824  }
8825  else
8826  {
8827  /* couldn't find it, it may have been renamed in the super class though */
8828  if (au_fetch_class_force (new_att->class_mop, &sclass, AU_FETCH_READ) == NO_ERROR)
8829  {
8830  /* search the super class' pending attribute list for this name */
8831  if (sclass->new_ != NULL)
8832  {
8833  super_new = find_matching_att (sclass->new_->attributes, new_att, 0);
8834  if (super_new != NULL)
8835  {
8836  if (is_partition)
8837  {
8838  /* the current class is a partition it is not necessary to check the ID of
8839  * attribute in a the old configuration Also, in case of ALTER .. CHANGE with
8840  * attribute rename and/or type change, the old attribute will not be found by
8841  * name and type */
8842  found = super_new;
8843  new_att->id = found->id;
8844  continue;
8845  }
8846  /*
8847  * search the supers original attribute list
8848  * based on the id of the new one
8849  */
8850  super_old = find_matching_att (sclass->attributes, super_new, 1);
8851  if (super_old != NULL)
8852  {
8853  if (SM_COMPARE_NAMES (super_old->header.name, new_att->header.name) != 0)
8854  {
8855  /* search our old list with the old name */
8856  found = find_matching_att (flat->current->attributes, super_old, 0);
8857  if (found != NULL)
8858  {
8859  /* found the renamed attribute, reuse id */
8860  new_att->id = found->id;
8861  }
8862  }
8863  }
8864  }
8865  }
8866  }
8867  }
8868  }
8869 
8870 /* As mentioned in the description above, we no longer think that
8871  it is a good idea to retain the old attribute ID when shadowing
8872  an inherited attribute. Since we had thought differently before
8873  and might think differently again I would rather keep this part
8874  of the code in here as a reminder. */
8875 #if 0
8876  else
8877  {
8878  /* Its a new local attribute. If we're shadowing a previously inherited attribute, reuse the old id
8879  * so we don't lose the previous value. This is new (12/7/94), does it cause unexpected problems ? */
8880  /* look for one in the existing representation */
8881  found = classobj_find_attribute_list (flat->current->attributes, new->header.name, -1);
8882  /* was it inherited ? */
8883  if (found != NULL && found->class != new->class)
8884  {
8885  /* reuse the attribute id, don't have to worry about type compatibility because that must have
8886  * been checked during flattening. */
8887  new->id = found->id;
8888  }
8889  /* else couldn't find it, do we need to deal with the case where the inherited attribute from the
8890  * super class has been renamed as is done above ? */
8891  }
8892 #endif /* 0 */
8893  }
8894  }
8895  }
8896 
8897  return NO_ERROR;
8898 }
8899 
8900 
8901 /*
8902  * flatten_trigger_cache() - This re-flattens the trigger cache for triggers
8903  * directly on this class (not associated with an attribute).
8904  * The attribute caches are maintained directly on the attributes.
8905  * return: NO_ERROR on success, non-zero for ERROR
8906  * def(in): schema template
8907  * flat(out): flattened template
8908  */
8909 
8910 static int
8912 {
8913  int error = NO_ERROR;
8914  TR_SCHEMA_CACHE *flat_triggers = NULL, *super_triggers = NULL;
8915  DB_OBJLIST *super;
8916  SM_CLASS *class_;
8917 
8918  /* trigger list in def has been filtered to contain only those triggers defined directly on the class, combine these
8919  * with those on the current super classes */
8920 
8921  if (def->triggers != NULL)
8922  {
8923  flat_triggers = tr_copy_schema_cache ((TR_SCHEMA_CACHE *) def->triggers, NULL);
8924  }
8925  else
8926  {
8927  flat_triggers = tr_make_schema_cache (TR_CACHE_CLASS, NULL);
8928  }
8929 
8930  if (flat_triggers == NULL)
8931  {
8932  assert (er_errid () != NO_ERROR);
8933  error = er_errid ();
8934  }
8935 
8936  for (super = flat->inheritance; ((super != NULL) && (error == NO_ERROR)); super = super->next)
8937  {
8938  /* better not be any fetch errors at this point */
8939  error = au_fetch_class_force (super->op, &class_, AU_FETCH_READ);
8940  if (error == NO_ERROR)
8941  {
8942  /* if the class is being edited, be sure and get its updated trigger cache */
8943  if (class_->new_ != NULL)
8944  {
8945  super_triggers = (TR_SCHEMA_CACHE *) class_->new_->triggers;
8946  }
8947  else
8948  {
8949  super_triggers = class_->triggers;
8950  }
8951 
8952  if (super_triggers != NULL)
8953  {
8954  error = tr_merge_schema_cache (flat_triggers, super_triggers);
8955  }
8956  }
8957  }
8958 
8959  if (error)
8960  {
8961  if (flat_triggers != NULL)
8962  {
8963  tr_free_schema_cache (flat_triggers);
8964  }
8965  }
8966  else
8967  {
8968  if (tr_empty_schema_cache (flat_triggers))
8969  {
8970  tr_free_schema_cache (flat_triggers);
8971  }
8972  else
8973  {
8974  flat->triggers = flat_triggers;
8975  }
8976  }
8977 
8978  return error;
8979 }
8980 
8981 /*
8982  * flatten_properties() - This combines the interesting properties from the
8983  * superclasses into the template property list. This is used mainly for
8984  * UNIQUE constraint properties which must be inherited uniformly by
8985  * the subclasses.
8986  * NOTE: Things will get a lot more complicated here when we start having
8987  * to deal with constraints over multiple attributes.
8988  * Note that for NEW classes or constraints, the BTID will not have been
8989  * allocated at this time, it is allocated in
8990  * allocate_disk_structures() call after flattening has finished.
8991  * This means that unique constraint info that we inherit may have a NULL
8992  * BTID (fields are all -1). That's ok for now, it will look as if it
8993  * was one of our own local unique constraints. When we get around
8994  * to calling allocate_disk_structures() we must always check to see
8995  * if the associated attributes were inherited and if so, go back
8996  * to the super class to get its real BTID. It is assumred that the
8997  * super class will have the real BTID by this time because the call
8998  * to allocate_disk_structures() has been moved to preceed the call
8999  * to update_subclasses().
9000  * It would be nice if we could allocate the indexes DURING flattening
9001  * rather than deferring it until the end. This would make the whole
9002  * think cleaner and less prone to error.
9003  * return: NO_ERROR on success, non-zero for ERROR
9004  * def(in): original class template
9005  * flat(out): flattened template being built
9006  */
9007 
9008 static int
9010 {
9011  DB_OBJLIST *super;
9012  SM_CLASS *class_;
9013  DB_SET *props;
9014  SM_CLASS_CONSTRAINT *constraints, *c;
9015  SM_ATTRIBUTE *atts, *att;
9016  int error = NO_ERROR;
9017 
9018  constraints = NULL;
9019 
9020  /* start by copying over any locally defined properties */
9021  if (def->properties != NULL)
9022  {
9023  if (classobj_copy_props (def->properties, NULL, &flat->properties) != NO_ERROR)
9024  {
9025  goto structure_error; /* should be a memory error */
9026  }
9027  }
9028 
9029  /* map over each super class */
9030  for (super = flat->inheritance; super != NULL; super = super->next)
9031  {
9032  /* better not be any fetch errors at this point */
9033  if (au_fetch_class_force (super->op, &class_, AU_FETCH_READ))
9034  {
9035  goto structure_error;
9036  }
9037 
9038  /* If the class is being edited, be sure and get its updated property & attribute list. This is going to get
9039  * really annoying if we have to deal with non-instance attributes. */
9040  if (class_->new_ != NULL)
9041  {
9042  props = class_->new_->properties;
9043  atts = class_->new_->attributes;
9044  }
9045  else
9046  {
9047  props = class_->properties;
9048  atts = class_->attributes;
9049  }
9050 
9051  /* For right now, the only thing we're interested in is unique constraint information. As other inheritable
9052  * things make their way onto the property list, this function will become more complicated. Since its so much
9053  * easier to walk over the SM_CLASS_CONSTRAINT list than the property list, built a transient constraint list. */
9054  if (classobj_make_class_constraints (props, atts, &constraints))
9055  {
9056  goto structure_error;
9057  }
9058 
9059  for (c = constraints; c != NULL; c = c->next)
9060  {
9061  /* ignore non-unique for now */
9063  {
9064  SM_ATTRIBUTE **attrs;
9065  int found_match;
9066  int i;
9067 
9068  attrs = c->attributes;
9069  if (attrs[0] != NULL)
9070  {
9071  /* Loop over each attribute in the constraint */
9072  found_match = 1;
9073  for (i = 0; ((attrs[i] != NULL) && found_match); i++)
9074  {
9075  /*
9076  * Try to find a corresponding attribute in the flattened template
9077  */
9078  for (att = flat->attributes; att != NULL; att = (SM_ATTRIBUTE *) att->header.next)
9079  {
9080  if (SM_COMPARE_NAMES (attrs[i]->header.name, att->header.name) == 0)
9081  {
9082  break;
9083  }
9084  }
9085 
9086  /*
9087  * If we found an attribute with a matching name but from a
9088  * different source class, it still isn't a match since it was
9089  * inherited from somewhere else.
9090  */
9091  if ((att == NULL) || (att->class_mop != attrs[i]->class_mop))
9092  {
9093  found_match = 0;
9094  }
9095  }
9096 
9097  if (found_match)
9098  {
9099  DB_VALUE cnstr_val;
9100  int cnstr_exists = 0;
9101 
9102  /* Does the constraint exist in the subclass ? */
9103  db_make_null (&cnstr_val);
9104  cnstr_exists =
9106  c->name, &cnstr_val);
9107  if (cnstr_exists)
9108  {
9109  DB_SEQ *local_property;
9110  DB_VALUE btid_val;
9111  BTID btid;
9112  int is_global_index = 0;
9113 
9114  /* Get the BTID from the local constraint */
9115  db_make_null (&btid_val);
9116  local_property = db_get_set (&cnstr_val);
9117  if (set_get_element (local_property, 0, &btid_val))
9118  {
9119  pr_clear_value (&cnstr_val);
9120  goto structure_error;
9121  }
9122  if (classobj_btid_from_property_value (&btid_val, &btid, NULL))
9123  {
9124  pr_clear_value (&btid_val);
9125  pr_clear_value (&cnstr_val);
9126  goto structure_error;
9127  }
9128  pr_clear_value (&btid_val);
9129 
9130  /* Raise an error if the B-trees are not equal and the constraint is an unique constraint.
9131  * Foreign key constraints do not share the same index so it's expected to have different
9132  * btid in this case */
9133  if (sm_is_global_only_constraint (super->op, c, &is_global_index, def) != NO_ERROR)
9134  {
9135  pr_clear_value (&cnstr_val);
9136  goto structure_error;
9137  }
9138 
9139  if (is_global_index == 1 && !BTID_IS_EQUAL (&btid, &c->index_btid)
9141  {
9142  ERROR1 (error, ER_SM_CONSTRAINT_EXISTS, c->name);
9143  }
9144  }
9145  else
9146  {
9147  BTID index_btid;
9148  int is_global_index = 0;
9149 
9150  BTID_SET_NULL (&index_btid);
9151  if (sm_is_global_only_constraint (super->op, c, &is_global_index, def) != NO_ERROR)
9152  {
9153  goto structure_error;
9154  }
9155 
9156  if (is_global_index == 1)
9157  {
9158  /* unique indexes are shared indexes */
9159  BTID_COPY (&index_btid, &c->index_btid);
9160  }
9161  if (classobj_put_index (&flat->properties, c->type, c->name, attrs, c->asc_desc,
9162  c->attrs_prefix_length, &index_btid, c->filter_predicate, c->fk_info,
9163  NULL, c->func_index_info, c->comment, c->index_status, true)
9164  != NO_ERROR)
9165  {
9166  pr_clear_value (&cnstr_val);
9167  goto structure_error;
9168  }
9169  }
9170 
9171  pr_clear_value (&cnstr_val);
9172  }
9173  }
9174  }
9175  }
9176 
9177  /* make sure we free the transient constraint list */
9178  classobj_free_class_constraints (constraints);
9179 
9180  if (error != NO_ERROR)
9181  {
9182  break;
9183  }
9184  /* drop foreign keys that were dropped in the superclass */
9185  error = filter_local_constraints (flat, class_);
9186  if (error != NO_ERROR)
9187  {
9188  break;
9189  }
9190  }
9191 
9192  return error;
9193 
9194 structure_error:
9195 
9196  classobj_free_class_constraints (constraints);
9197 
9198  /* should have a more appropriate error for this */
9200 
9201  return er_errid ();
9202 }
9203 
9204 /*
9205  * flatten_template() - Flatten a template, checking for all of the various
9206  * schema rules. Returns a flattened template that forms the basis
9207  * for a new class representation if all went well.
9208  * return: NO_ERROR on success, non-zero for ERROR
9209  * def(in): schema template
9210  * deleted_class(in): MOP of deleted class (optional, can be NULL)
9211  * flatp(out): returned pointer to flattened template
9212  * auto_res(in): non-zero to enable auto resolution of conflicts
9213  */
9214 
9215 static int
9216 flatten_template (SM_TEMPLATE * def, MOP deleted_class, SM_TEMPLATE ** flatp, int auto_res)
9217 {
9218  int error = NO_ERROR;
9219  SM_TEMPLATE *flat;
9220 
9221  /* start with an empty template */
9222  flat = classobj_make_template (def->name, def->op, NULL);
9223  if (flat == NULL)
9224  {
9225  goto memory_error;
9226  }
9227 
9228  /* is this necessary ? */
9229  flat->class_type = def->class_type;
9230 
9231  /* remember this, CAN'T PASS THIS AS AN ARGUMENT to classobj_make_template */
9232  flat->current = def->current;
9233 
9234  /* copy the super class list filtering out the deleted class if any */
9235  if (deleted_class != NULL)
9236  {
9237  ml_remove (&def->inheritance, deleted_class);
9238  }
9239  if (def->inheritance != NULL)
9240  {
9241  flat->inheritance = ml_copy (def->inheritance);
9242  if (flat->inheritance == NULL)
9243  {
9244  goto memory_error;
9245  }
9246  }
9247 
9248  /* merge the method file lists */
9249  if (flatten_method_files (def, flat))
9250  {
9251  goto memory_error;
9252  }
9253 
9254  /* merge query_spec lists */
9255  if (flatten_query_spec_lists (def, flat))
9256  {
9257  goto memory_error;
9258  }
9259 
9260  /* merge trigger caches */
9261  if (flatten_trigger_cache (def, flat))
9262  {
9263  goto memory_error;
9264  }
9265 
9266  /* copy the loader commands, we should be flattening these as well ? */
9267  if (def->loader_commands != NULL)
9268  {
9270  if (flat->loader_commands == NULL)
9271  {
9272  goto memory_error;
9273  }
9274  }
9275 
9276  /* filter out any useless resolutions */
9277  error = filter_resolutions (def, flat, deleted_class);
9278  if (error == NO_ERROR)
9279  {
9280  /* flatten each component list */
9281  error = flatten_components (def, flat, ID_INSTANCE, auto_res);
9282  if (error == NO_ERROR)
9283  {
9284  error = flatten_components (def, flat, ID_CLASS, auto_res);
9285  }
9286  }
9287 
9288  if (flatten_partition_info (def, flat) != NO_ERROR)
9289  {
9290  goto memory_error;
9291  }
9292 
9293  /* Flatten the properties (primarily for constraints). Do this after the components have been flattened so we can see
9294  * use this information for selecting constraint properties. */
9295  if (flatten_properties (def, flat))
9296  {
9297  goto memory_error;
9298  }
9299 
9300  if (error == NO_ERROR)
9301  {
9302  /* make sure these get kept */
9303  error = retain_former_ids (flat);
9304  }
9305 
9306  /* if errors, throw away the template and abort */
9307  if (error != NO_ERROR)
9308  {
9309  classobj_free_template (flat);
9310  flat = NULL;
9311  }
9312 
9313  *flatp = flat;
9314  return error;
9315 
9316 memory_error:
9317  if (flat != NULL)
9318  {
9319  classobj_free_template (flat);
9320  }
9321 
9322  assert (er_errid () != NO_ERROR);
9323  return er_errid ();
9324 }
9325 
9326 /* PREPARATION FOR NEW REPRESENTATIONS */
9327 /*
9328  * assign_attribute_id() - Generate an id for a shared or class attribute.
9329  * Instance attribute id's are assigned during order_attributes.
9330  * Must use an existing attribute id if one exists.
9331  * Note that the attribute id counter for all attributes is the same
9332  * so the ids can be assumed unique across all attribute
9333  * namespaces.
9334  * return: none
9335  * class(in/out): class structure
9336  * att(in/out): attribute needing id
9337  * class_attribute(in): non-zero for class name_space
9338  */
9339 
9340 static void
9341 assign_attribute_id (SM_CLASS * class_, SM_ATTRIBUTE * attribute, int class_attribute)
9342 {
9343  SM_ATTRIBUTE *attr;
9344 
9345  /* if it already has one, just leave it alone */
9346  if (attribute->id == -1)
9347  {
9348  if (class_attribute)
9349  {
9350  attr = class_->class_attributes;
9351  }
9352  else
9353  {
9354  attr = class_->shared;
9355  }
9356 
9357  for (; attr != NULL && attribute->id == -1; attr = (SM_ATTRIBUTE *) attr->header.next)
9358  {
9359  if ((SM_COMPARE_NAMES (attr->header.name, attribute->header.name) == 0)
9360  && (attr->class_mop == attribute->class_mop) && (attr->type == attribute->type))
9361  {
9362  /* reuse old id */
9363  attribute->id = attr->id;
9364  }
9365  }
9366 
9367  if (attribute->id)
9368  {
9369  /* couldn't find an existing one, generate a new one */
9370  attribute->id = class_->att_ids++;
9371  }
9372  }
9373 }
9374 
9375 /*
9376  * assign_method_id() - Generate an id for an instance or class method.
9377  * Use the existing id if already present in the class.
9378  * return: none
9379  * class(in/out): class structure
9380  * method(in/out): method needing an id
9381  * class_method(in): non-zero for class name_space
9382  */
9383 
9384 static void
9385 assign_method_id (SM_CLASS * class_, SM_METHOD * method, bool class_method)
9386 {
9387  SM_METHOD *m;
9388 
9389  if (method->id == -1)
9390  {
9391  if (class_method)
9392  {
9393  m = class_->class_methods;
9394  }
9395  else
9396  {
9397  m = class_->methods;
9398  }
9399 
9400  for (; m != NULL && method->id == -1; m = (SM_METHOD *) m->header.next)
9401  {
9402  /* need to check return domains here and reassign id ? */
9403  if ((SM_COMPARE_NAMES (m->header.name, method->header.name) == 0) && m->class_mop == method->class_mop)
9404  {
9405  method->id = m->id;
9406  }
9407  }
9408 
9409  if (method->id == -1)
9410  {
9411  method->id = class_->method_ids++;
9412  }
9413  }
9414 }
9415 
9416 /*
9417  * order_atts_by_alignment() - Order the attributes by descending order of
9418  * alignment needs. Within the same alignment group, order the attributes
9419  * by ascending order of disk size (this is mainly for the char types).
9420  * In this way, if the object is too large to fit on one page, we can try to
9421  * keep the smaller char types on the same page as the OID and thereby
9422  * we might be able to read the attributes we need without reading
9423  * the overflow page.
9424  * This algorithm is simplistic but these lists are not long.
9425  * return: ordered attributes.
9426  * atts(in/out): attributes to be ordered
9427  */
9428 static SM_ATTRIBUTE *
9430 {
9431  SM_ATTRIBUTE *newatts, *found, *attr;
9432 
9433  newatts = NULL;
9434 
9435  while (atts != NULL)
9436  {
9437  for (found = atts, attr = atts; attr != NULL; attr = (SM_ATTRIBUTE *) attr->header.next)
9438  {
9439 
9440  /* the new attr becomes the found attr if it has larger alignment requirements or if it has the same
9441  * alignment needs but has smaller disk size. */
9442  if ((attr->type->alignment > found->type->alignment)
9443  || ((attr->type->alignment == found->type->alignment)
9444  && (tp_domain_disk_size (attr->domain) < tp_domain_disk_size (found->domain))))
9445  {
9446  found = attr;
9447  }
9448  }
9449 
9450  /* move the one we found to the new list */
9451  WS_LIST_REMOVE (&atts, found);
9452  found->header.next = NULL;
9453 
9454  WS_LIST_APPEND (&newatts, found);
9455  }
9456 
9457  return newatts;
9458 }
9459 
9460 /*
9461  * build_storage_order() - Here we take a flattened template and reorder
9462  * the attributes to be close to the ordering the class had before editing.
9463  * In the process we assign attribute ids. If the current and new attribute
9464  * lists turn out to be the same, we can avoid the generation of a
9465  * new representation since the disk structure of the objects will
9466  * be the same. If the two attribute lists differ, non-zero is
9467  * returned indicating that a new representation must be generated.
9468  * At the start, the template has a combined list of instance
9469  * and shared attributes in the attributes list. When this completes,
9470  * the attributes list will be NULL and the attributes will have
9471  * been split into two lists, ordered_attributes and shared_attributes.
9472  * Formerly this function tried to retain ids of attributes that
9473  * hadn't changed. This is now done in retain_former_ids above.
9474  * When we get here, this is the state of attribute ids in the
9475  * flattened template:
9476  * id != -1 : this is a local attribute (possibly renamed) that needs
9477  * to keep its former attribute id.
9478  * id == -1 : this is an inherited attribute or new local attribute
9479  * if its new, assign a new id, if it's inherited, look
9480  * in the old attribute list for one that matches and reuse
9481  * the old id. Searching the old list for matching
9482  * components could be done by make_component_from_candidate?
9483  * return: non-zero if new representation is needed
9484  * class(in): class being modified
9485  * flat(out): new flattened template
9486  */
9487 
9488 static int
9490 {
9491  SM_ATTRIBUTE *fixed, *variable, *current, *new_att, *found, *next, *newatts;
9492  int newrep;
9493 
9494  fixed = variable = NULL;
9495  newrep = 0;
9496 
9498 
9499  for (current = class_->attributes; current != NULL; current = (SM_ATTRIBUTE *) current->header.next)
9500  {
9501  found = NULL;
9502  for (new_att = newatts; new_att != NULL && found == NULL; new_att = (SM_ATTRIBUTE *) new_att->header.next)
9503  {
9504 
9505  /* if the ids are the same, use it without looking at the name, this is how rename works */
9506  if (new_att->id != -1)
9507  {
9508  if (new_att->id == current->id)
9509  {
9510  found = new_att;
9511  /* ALTER CHANGE column : check if new representation is required */
9512  if (!tp_domain_match (current->domain, new_att->domain, TP_EXACT_MATCH))
9513  {
9514  newrep = 1;
9515  }
9516  }
9517  }
9518 
9519  /* this shouldn't be necessary now that we assume ids have been assigned where there was one before */
9520 
9521  else if ((SM_COMPARE_NAMES (current->header.name, new_att->header.name) == 0)
9522  && (current->class_mop == new_att->class_mop) && (current->type == new_att->type))
9523  {
9524  found = new_att;
9525  }
9526  }
9527 
9528  if (found == NULL)
9529  {
9530  newrep = 1; /* attribute was deleted */
9531  }
9532  else
9533  {
9534  /* there was a match, either in name or id */
9535  if (found->id == -1)
9536  {
9537  /* name match, reuse the old id */
9538  found->id = current->id;
9539  }
9540 
9541  (void) WS_LIST_REMOVE (&newatts, found);
9542  found->header.next = NULL;
9543  if (found->type->variable_p)
9544  {
9545  WS_LIST_APPEND (&variable, found);
9546  }
9547  else
9548  {
9549  WS_LIST_APPEND (&fixed, found);
9550  }
9551  }
9552  }
9553 
9554  /* check for new attributes */
9555  if (newatts != NULL)
9556  {
9557  newrep = 1;
9558  for (new_att = newatts, next = NULL; new_att != NULL; new_att = next)
9559  {
9560  next = (SM_ATTRIBUTE *) new_att->header.next;
9561  new_att->header.next = NULL;
9562  new_att->id = class_->att_ids++;
9563 
9564  if (new_att->type->variable_p)
9565  {
9566  WS_LIST_APPEND (&variable, new_att);
9567  }
9568  else
9569  {
9570  WS_LIST_APPEND (&fixed, new_att);
9571  }
9572  }
9573  }
9574 
9575  /* order the fixed attributes in descending order by alignment needs */
9576  if (fixed != NULL)
9577  {
9578  fixed = order_atts_by_alignment (fixed);
9579  }
9580 
9581  /* join the two lists */
9582  if (fixed == NULL)
9583  {
9584  newatts = variable;
9585  }
9586  else
9587  {
9588  newatts = fixed;
9589  for (new_att = fixed; new_att != NULL && new_att->header.next != NULL;
9590  new_att = (SM_ATTRIBUTE *) new_att->header.next)
9591  ;
9592  new_att->header.next = (SM_COMPONENT *) variable;
9593  }
9594 
9595  if (flat->partition_parent_atts != NULL)
9596  {
9597  /* if partition subclass is created, the class must have the same attributes order and id with its parent class */
9598  SM_ATTRIBUTE *supatt, *reorder = NULL, *a, *prev;
9599 
9600  for (supatt = flat->partition_parent_atts; supatt != NULL; supatt = (SM_ATTRIBUTE *) supatt->header.next)
9601  {
9602  prev = found = NULL;
9603  for (a = newatts; a != NULL; a = (SM_ATTRIBUTE *) a->header.next)
9604  {
9605  if (SM_COMPARE_NAMES (a->header.name, supatt->header.name) == 0)
9606  {
9607  found = a;
9608  found->id = supatt->id;
9609 
9610  if (prev == NULL)
9611  {
9612  newatts = (SM_ATTRIBUTE *) newatts->header.next;
9613  }
9614  else
9615  {
9616  prev->header.next = found->header.next;
9617  }
9618  found->header.next = NULL;
9619  WS_LIST_APPEND (&reorder, found);
9620 
9621  break;
9622  }
9623  prev = a;
9624  }
9625  }
9626 
9627  WS_LIST_APPEND (&reorder, newatts);
9628  newatts = reorder;
9629  }
9630 
9631  /* now change the template to reflect the divided instance and shared attribute lists */
9632  flat->instance_attributes = newatts;
9633  flat->shared_attributes = flat->attributes;
9634  flat->attributes = NULL;
9635 
9636  return newrep;
9637 }
9638 
9639 /*
9640  * fixup_component_classes() - Work function for install_new_representation.
9641  * Now that we're certain that the template can be applied
9642  * and we have a MOP for the class being edited, go through and stamp
9643  * the attributes and methods of the class with the classmop. This
9644  * makes it easier later for the browsing functions to get the origin
9645  * class of attributes. This is only a problem when the class is
9646  * defined for the first time.
9647  * return: none
9648  * classop(in): class object
9649  * flat(out): flattened template
9650  */
9651 
9652 static void
9654 {
9655  SM_ATTRIBUTE *a;
9656  SM_METHOD *m;
9657  SM_METHOD_FILE *f;
9658 
9659  for (a = flat->attributes; a != NULL; a = (SM_ATTRIBUTE *) a->header.next)
9660  {
9661  if (a->class_mop == NULL)
9662  {
9663  a->class_mop = classop;
9664  }
9665  }
9666 
9667  for (a = flat->class_attributes; a != NULL; a = (SM_ATTRIBUTE *) a->header.next)
9668  {
9669  if (a->class_mop == NULL)
9670  {
9671  a->class_mop = classop;
9672  }
9673  }
9674 
9675  for (m = flat->methods; m != NULL; m = (SM_METHOD *) m->header.next)
9676  {
9677  if (m->class_mop == NULL)
9678  {
9679  m->class_mop = classop;
9680  }
9681  }
9682 
9683  for (m = flat->class_methods; m != NULL; m = (SM_METHOD *) m->header.next)
9684  {
9685  if (m->class_mop == NULL)
9686  {
9687  m->class_mop = classop;
9688  }
9689  }
9690 
9691  for (f = flat->method_files; f != NULL; f = f->next)
9692  {
9693  if (f->class_mop == NULL)
9694  {
9695  f->class_mop = classop;
9696  }
9697  }
9698 }
9699 
9700 
9701 /*
9702  * fixup_self_domain()
9703  * fixup_method_self_domains()
9704  * fixup_attribute_self_domain()
9705  * fixup_self_reference_domains() - Domains that were build for new classes
9706  * that need to reference the class being build were constructed in a
9707  * special way since the MOP of the class was not available at the time the
9708  * domain structure was created. Once semantic checking has been performed
9709  * and the class is created, we not must go through and modify the
9710  * temporary domain structures to look like real self-referencing
9711  * domains.
9712  * We now have a number of last minute fixup functions. Try to bundle
9713  * these into a single function sometime to avoid repeated passes
9714  * over the class structures. Not really that performance critical but
9715  * nicer if this isn't spread out all over.
9716  * return: none
9717  * classop(in): class object
9718  * flag(in/out): flattened template
9719  */
9720 
9721 static void
9723 {
9724  TP_DOMAIN *d;
9725 
9726  for (d = domain; d != NULL; d = d->next)
9727  {
9728  /* PR_TYPE is changeable only for transient domain. */
9729  assert (d->type != tp_Type_null || !d->is_cached);
9730  if (d->type == tp_Type_null && !d->is_cached)
9731  {
9732  d->type = tp_Type_object;
9733  d->class_mop = self;
9734  }
9735  fixup_self_domain (d->setdomain, self);
9736  }
9737 }
9738 
9739 static void
9741 {
9742  SM_METHOD_SIGNATURE *sig;
9743  SM_METHOD_ARGUMENT *arg;
9744 
9745  for (sig = meth->signatures; sig != NULL; sig = sig->next)
9746  {
9747  for (arg = sig->value; arg != NULL; arg = arg->next)
9748  {
9749  fixup_self_domain (arg->domain, self);
9750  arg->domain = tp_domain_cache (arg->domain);
9751  }
9752  for (arg = sig->args; arg != NULL; arg = arg->next)
9753  {
9754  fixup_self_domain (arg->domain, self);
9755  arg->domain = tp_domain_cache (arg->domain);
9756  }
9757  }
9758 }
9759 
9760 static void
9762 {
9763  /*
9764  * Remember that attributes have a type pointer cache as well as a full domain. BOTH of these need to be updated.
9765  * This is unfortunate, I think its time to remove the type pointer and rely on the domain structure only. */
9766 
9767  fixup_self_domain (att->domain, self);
9768  att->domain = tp_domain_cache (att->domain);
9769 
9770  /* get the type cache as well */
9771  if (att->type == tp_Type_null)
9772  {
9773  att->type = tp_Type_object;
9774  }
9775 }
9776 
9777 static void
9779 {
9780  SM_ATTRIBUTE *a;
9781  SM_METHOD *m;
9782 
9783  /* should only bother with this if the class is new, can we somehow determine this here ? */
9784 
9785  for (a = flat->attributes; a != NULL; a = (SM_ATTRIBUTE *) a->header.next)
9786  {
9787  fixup_attribute_self_domain (a, classop);
9788  }
9789 
9790  for (a = flat->class_attributes; a != NULL; a = (SM_ATTRIBUTE *) a->header.next)
9791  {
9792  fixup_attribute_self_domain (a, classop);
9793  }
9794 
9795  for (a = flat->shared_attributes; a != NULL; a = (SM_ATTRIBUTE *) a->header.next)
9796  {
9797  fixup_attribute_self_domain (a, classop);
9798  }
9799 
9800  for (m = flat->methods; m != NULL; m = (SM_METHOD *) m->header.next)
9801  {
9802  fixup_method_self_domains (m, classop);
9803  }
9804 
9805  for (m = flat->class_methods; m != NULL; m = (SM_METHOD *) m->header.next)
9806  {
9807  fixup_method_self_domains (m, classop);
9808  }
9809 }
9810 
9811 /* DISK STRUCTURE ALLOCATION */
9812 /*
9813  * construct_index_key_domain()
9814  * return:
9815  * n_atts(in):
9816  * atts(in):
9817  * asc_desc(in):
9818  * prefix_lengths(in):
9819  * func_col_id(in):
9820  * func_domain(in):
9821  */
9822 
9823 static TP_DOMAIN *
9824 construct_index_key_domain (int n_atts, SM_ATTRIBUTE ** atts, const int *asc_desc, const int *prefix_lengths,
9825  int func_col_id, TP_DOMAIN * func_domain)
9826 {
9827  int i;
9828  TP_DOMAIN *head = NULL;
9829  TP_DOMAIN *current = NULL;
9830  TP_DOMAIN *set_domain = NULL;
9831  TP_DOMAIN *new_domain = NULL;
9832  TP_DOMAIN *cached_domain = NULL;
9833 
9834  if (n_atts == 1 && func_domain == NULL)
9835  {
9836  if ((asc_desc && asc_desc[0] == 1)
9837  || (prefix_lengths && (*prefix_lengths != -1) && QSTR_IS_ANY_CHAR_OR_BIT (TP_DOMAIN_TYPE (atts[0]->domain))))
9838  {
9839  new_domain = tp_domain_copy (atts[0]->domain, false);
9840  if (new_domain == NULL)
9841  {
9842  goto mem_error;
9843  }
9844 
9845  if (asc_desc && asc_desc[0] == 1)
9846  {
9847  new_domain->is_desc = true;
9848  }
9849  else
9850  {
9851  new_domain->is_desc = false;
9852  }
9853 
9854  if (prefix_lengths && (*prefix_lengths != -1) && QSTR_IS_ANY_CHAR_OR_BIT (TP_DOMAIN_TYPE (atts[0]->domain)))
9855  {
9856  int scale = (TP_DOMAIN_TYPE (atts[0]->domain) == DB_TYPE_BIT) ? 8 : 1;
9857  new_domain->precision = MIN (new_domain->precision, *prefix_lengths * scale);
9858  }
9859 
9860  cached_domain = tp_domain_cache (new_domain);
9861  }
9862  else
9863  {
9864  cached_domain = atts[0]->domain;
9865  }
9866  }
9867  else if ((n_atts > 1) || func_domain)
9868  {
9869  /* If this is multi column index and a function index, we must construct the domain of the keys accordingly,
9870  * using the type returned by the function index expression. If it is just a multi column index, the position at
9871  * which the expression should be found is -1, so it will never be reached. */
9872  for (i = 0; i < n_atts; i++)
9873  {
9874  if (i == func_col_id)
9875  {
9876  new_domain = tp_domain_copy (func_domain, false);
9877  if (head == NULL)
9878  {
9879  head = new_domain;
9880  current = new_domain;
9881  }
9882  else
9883  {
9884  current->next = new_domain;
9885  current = new_domain;
9886  }
9887  }
9888 
9889  new_domain = tp_domain_new (DB_TYPE_NULL);
9890  if (new_domain == NULL)
9891  {
9892  goto mem_error;
9893  }
9894 
9895  new_domain->type = atts[i]->domain->type;
9896  new_domain->precision = atts[i]->domain->precision;
9897  new_domain->scale = atts[i]->domain->scale;
9898  new_domain->codeset = atts[i]->domain->codeset;
9899  new_domain->collation_id = atts[i]->domain->collation_id;
9900  new_domain->is_parameterized = atts[i]->domain->is_parameterized;
9901 
9902  if (new_domain->type->id == DB_TYPE_ENUMERATION)
9903  {
9904  if (tp_domain_copy_enumeration (&DOM_GET_ENUMERATION (new_domain), &DOM_GET_ENUMERATION (atts[i]->domain))
9905  != NO_ERROR)
9906  {
9907  goto mem_error;
9908  }
9909  }
9910 
9911  if (asc_desc && asc_desc[i] == 1)
9912  { /* is descending order */
9913  new_domain->is_desc = true;
9914  }
9915  else
9916  {
9917  new_domain->is_desc = false;
9918  }
9919 
9920  if (head == NULL)
9921  {
9922  head = new_domain;
9923  current = new_domain;
9924  }
9925  else
9926  {
9927  current->next = new_domain;
9928  current = new_domain;
9929  }
9930  }
9931 
9932  if (i == func_col_id)
9933  {
9934  new_domain = tp_domain_copy (func_domain, false);
9935  if (head == NULL)
9936  {
9937  head = new_domain;
9938  current = new_domain;
9939  }
9940  else
9941  {
9942  current->next = new_domain;
9943  current = new_domain;
9944  }
9945  }
9946  set_domain = tp_domain_construct (DB_TYPE_MIDXKEY, NULL, n_atts + (func_domain ? 1 : 0), 0, head);
9947  if (set_domain == NULL)
9948  {
9949  goto mem_error;
9950  }
9951 
9952  cached_domain = tp_domain_cache (set_domain);
9953  }
9954 
9955  return cached_domain;
9956 
9957 mem_error:
9958 
9959  if (head != NULL)
9960  {
9961  TP_DOMAIN *td, *next;
9962  for (td = head, next = NULL; td != NULL; td = next)
9963  {
9964  next = td->next;
9965  tp_domain_free (td);
9966  }
9967  }
9968  return NULL;
9969 }
9970 
9971 /*
9972  * collect_hier_class_info() - calling this function in which case *n_classes
9973  * will equal to 1 upon entry.
9974  * return: NO_ERROR on success, non-zero for ERROR
9975  * classop(in): Class MOP of the base class.
9976  * subclasses(in): List of subclasses.
9977  * constraint_name(in): Name of UNIQUE or FOREIGN KEY constraint to search
9978  * for.
9979  * reverse(in):
9980  * n_classes(out): Number of subclasses which inherit the constraint.
9981  * n_attrs(in): Number of attributes in constraint.
9982  * oids(out): Array of class OID's which inherit the constraint.
9983  * attr_ids(out): Array of attribute ID's for each class
9984  * hfids(out): Array of heaps for classes whicTraverse the subclasses list
9985  * looking for matching constraints.
9986  */
9987 
9988 static int
9989 collect_hier_class_info (MOP classop, DB_OBJLIST * subclasses, const char *constraint_name, int reverse, int *n_classes,
9990  int n_attrs, OID * oids, int *attr_ids, HFID * hfids)
9991 {
9992  DB_OBJLIST *sub;
9993  SM_CLASS *class_;
9994  int error = NO_ERROR;
9995 
9996  for (sub = subclasses; ((sub != NULL) && (error == NO_ERROR)); sub = sub->next)
9997  {
9998  error = au_fetch_class_force (sub->op, &class_, AU_FETCH_READ);
9999  if (error == NO_ERROR)
10000  {
10001  SM_TEMPLATE *flat;
10002  SM_CLASS_CONSTRAINT *constraints, *found;
10003  int *attr_ptr;
10004 
10005  /* Get flattened template */
10006  flat = class_->new_;
10007 
10008  /* Make transient constraint cache from property list. At this point in the process, the property list
10009  * should be current and include inherited constraints */
10010  error = classobj_make_class_constraints (flat->properties, flat->attributes, &constraints);
10011  if (error == NO_ERROR)
10012  {
10013  /* Does this class contain the constraint that we're looking for? Note that we're only interested in
10014  * UNIQUE or FOREIGN KEY constraints at this time. */
10015  if (reverse)
10016  {
10017  found = classobj_find_class_constraint (constraints, SM_CONSTRAINT_REVERSE_UNIQUE, constraint_name);
10018  }
10019  else
10020  {
10021  found = classobj_find_class_constraint (constraints, SM_CONSTRAINT_UNIQUE, constraint_name);
10022  if (!found)
10023  {
10024  found = classobj_find_class_constraint (constraints, SM_CONSTRAINT_PRIMARY_KEY, constraint_name);
10025  }
10026  }
10027 
10028  /* If we found a constraint with a matching name, we also need to make sure that the constraint
10029  * originated in the class that we're interested in. If so, then save the class OID, attribute ID's and
10030  * HFID. We attempt to maintain unique constraint names, but it is possible for different constraint to
10031  * have the same name. This might happen if a subclass shadows and attribute which invalidates the
10032  * constraint and then adds a constraint of the same name. This might also be possible if a class
10033  * inherits from multiple parent which each have constraints of the same name. */
10034  if (found && (found->attributes[0]->class_mop == classop))
10035  {
10036  int i;
10037 
10038  /* Make sure that we have a permanent OID for the class. This function only processes the
10039  * subclasses. We're assuming that the base class has already been processed. */
10040  if (OID_ISTEMP (ws_oid (sub->op)))
10041  {
10042  if (locator_assign_permanent_oid (sub->op) == NULL)
10043  {
10044  if (er_errid () == NO_ERROR)
10045  {
10047  }
10048 
10049  classobj_free_class_constraints (constraints);
10050  return er_errid ();
10051  }
10052  }
10053 
10054  COPY_OID (&oids[*n_classes], WS_OID (sub->op));
10055 
10056  attr_ptr = &attr_ids[(*n_classes) * n_attrs];
10057  for (i = 0; i < n_attrs; i++)
10058  {
10059  attr_ptr[i] = found->attributes[i]->id;
10060  }
10061 
10062  HFID_COPY (&hfids[*n_classes], sm_ch_heap ((MOBJ) class_));
10063  (*n_classes)++;
10064  }
10065 
10066  classobj_free_class_constraints (constraints);
10067  }
10068  }
10069  }
10070 
10071  return error;
10072 }
10073 
10074 /*
10075  This done as a post processing pass of sm_update_class to make sure
10076  that all attributes that were declared to have indexes or unique btids
10077  tables have the necessary disk structures allocated.
10078 
10079  Logically this should be done before the class is created so if any
10080  errors occur, we can abort the operation. Unfortunately, doing this
10081  accurately requires attribute id's being assigned so it would have
10082  to go in install_new_representation. After beta, restructure the
10083  sequence of operations in sm_update_class and install_new_representation
10084  (and probably the flattener as well) so we have all the information necessary
10085  to generate the disk structures before the call to
10086  install_new_representation and before the class is created.
10087 */
10088 
10089 /*
10090  * allocate_index() - Allocates an index on disk for an attribute of a class.
10091  * return: NO_ERROR on success, non-zero for ERROR
10092  * classop(in): class object
10093  * class(in): class structure
10094  * subclasses(in): List of subclasses
10095  * attrs(in): attribute getting the index
10096  * asc_desc(in): asc/desc info list
10097  * unique_pk(in): non-zeor if were allocating a UNIQUE index. zero otherwise.
10098  * not_null(in):
10099  * reverse(in):
10100  * constraint_name(in): Name of constraint.
10101  * index(out): The BTID of the returned index.
10102  * fk_refcls_oid(in):
10103  * fk_refcls_pk_btid(in):
10104  * fk_name(in):
10105  * index_status(in):
10106  */
10107 
10108 static int
10109 allocate_index (MOP classop, SM_CLASS * class_, DB_OBJLIST * subclasses, SM_ATTRIBUTE ** attrs, const int *asc_desc,
10110  const int *attrs_prefix_length, int unique_pk, int not_null, int reverse, const char *constraint_name,
10111  BTID * index, OID * fk_refcls_oid, BTID * fk_refcls_pk_btid, const char *fk_name,
10112  SM_PREDICATE_INFO * filter_index, SM_FUNCTION_INFO * function_index, SM_INDEX_STATUS index_status)
10113 {
10114  int error = NO_ERROR;
10115  DB_TYPE type;
10116  int i, n_attrs;
10117  int *attr_ids = NULL;
10118  size_t attr_ids_size;
10119  OID *oids = NULL;
10120  HFID *hfids = NULL;
10121  TP_DOMAIN *domain = NULL;
10122  int max_classes, n_classes, has_instances;
10123  DB_OBJLIST *sub;
10124 
10125  /* Count the attributes */
10126  for (i = 0, n_attrs = 0; attrs[i] != NULL; i++, n_attrs++)
10127  {
10128  type = attrs[i]->type->id;
10129  if (!tp_valid_indextype (type))
10130  {
10131  error = ER_SM_INVALID_INDEX_TYPE;
10133  }
10134  else if (attrs_prefix_length && attrs_prefix_length[i] >= 0)
10135  {
10136  if (!TP_IS_CHAR_TYPE (type) && !TP_IS_BIT_TYPE (type))
10137  {
10140  }
10141  else if (((long) attrs[i]->domain->precision) < attrs_prefix_length[i])
10142  {
10144  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SM_INVALID_PREFIX_LENGTH, 1, attrs_prefix_length[i]);
10145  }
10146  }
10147  }
10148 
10149  if (error != NO_ERROR)
10150  {
10151  return error;
10152  }
10153 
10154  if (function_index)
10155  {
10156  if (function_index->attr_index_start == 0)
10157  {
10158  /* if this is a single column function index, the key domain is actually the domain of the function
10159  * result */
10160  domain = function_index->fi_domain;
10161  }
10162  else
10163  {
10164  domain = construct_index_key_domain (function_index->attr_index_start, attrs, asc_desc, attrs_prefix_length,
10165  function_index->col_id, function_index->fi_domain);
10166  }
10167  }
10168  else
10169  {
10170  domain = construct_index_key_domain (n_attrs, attrs, asc_desc, attrs_prefix_length, -1, NULL);
10171  }
10172 
10173  if (domain == NULL)
10174  {
10175  ASSERT_ERROR_AND_SET (error);
10176  return error;
10177  }
10178 
10179  /* need to have macros for this !! */
10180  index->vfid.volid = boot_User_volid;
10181 
10182  /* Count maximum possible subclasses */
10183  max_classes = 1; /* Start with 1 for the current class */
10184  for (sub = subclasses; sub != NULL; sub = sub->next)
10185  {
10186  max_classes++;
10187  }
10188 
10189  /* Allocate arrays to hold subclass information */
10190  attr_ids_size = max_classes * n_attrs * sizeof (int);
10191  attr_ids = (int *) malloc (attr_ids_size);
10192  if (attr_ids == NULL)
10193  {
10195  goto mem_error;
10196  }
10197 
10198  oids = (OID *) malloc (max_classes * sizeof (OID));
10199  if (oids == NULL)
10200  {
10201  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, max_classes * sizeof (OID));
10202  goto mem_error;
10203  }
10204 
10205  hfids = (HFID *) malloc (max_classes * sizeof (HFID));
10206  if (hfids == NULL)
10207  {
10208  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, max_classes * sizeof (HFID));
10209  goto mem_error;
10210  }
10211 
10212  /* Enter the base class information into the arrays */
10213  n_classes = 0;
10214  COPY_OID (&oids[n_classes], WS_OID (classop));
10215  for (i = 0; i < n_attrs; i++)
10216  {
10217  attr_ids[i] = attrs[i]->id;
10218  }
10219  HFID_COPY (&hfids[n_classes], sm_ch_heap ((MOBJ) class_));
10220  n_classes++;
10221 
10222  /* If we're creating a UNIQUE B-tree or a FOREIGN KEY, we need to collect information from subclasses which
10223  * inherit the constraint */
10224  if (unique_pk || (fk_refcls_oid != NULL && !OID_ISNULL (fk_refcls_oid)))
10225  {
10226  error = collect_hier_class_info (classop, subclasses, constraint_name, reverse, &n_classes, n_attrs, oids,
10227  attr_ids, hfids);
10228  if (error != NO_ERROR)
10229  {
10230  goto gen_error;
10231  }
10232  }
10233 
10234  /* Are there any populated classes for this index ? */
10235  has_instances = 0;
10236  for (i = 0; i < n_classes; i++)
10237  {
10238  if (!HFID_IS_NULL (&hfids[i]) && heap_has_instance (&hfids[i], &oids[i], false))
10239  {
10240  /* in case of error and instances exist */
10241  has_instances = 1;
10242  break;
10243  }
10244  }
10245 
10246  /* If there are no instances, then call btree_add_index() to create an empty index, otherwise call
10247  * btree_load_index () to load all of the instances (including applicable subclasses) into a new B-tree */
10248  // TODO: optimize has_instances case
10249  if (!has_instances || index_status == SM_ONLINE_INDEX_BUILDING_IN_PROGRESS)
10250  {
10251  error = btree_add_index (index, domain, WS_OID (classop), attrs[0]->id, unique_pk);
10252  }
10253  /* If there are instances, load all of them (including applicable subclasses) into the new B-tree */
10254  else
10255  {
10256  if (function_index)
10257  {
10258  error = btree_load_index (index, constraint_name, domain, oids, n_classes, n_attrs, attr_ids,
10259  (int *) attrs_prefix_length, hfids, unique_pk, not_null, fk_refcls_oid,
10260  fk_refcls_pk_btid, fk_name, SM_GET_FILTER_PRED_STREAM (filter_index),
10261  SM_GET_FILTER_PRED_STREAM_SIZE (filter_index), function_index->expr_stream,
10262  function_index->expr_stream_size, function_index->col_id,
10263  function_index->attr_index_start, index_status);
10264  }
10265  else
10266  {
10267  error = btree_load_index (index, constraint_name, domain, oids, n_classes, n_attrs, attr_ids,
10268  (int *) attrs_prefix_length, hfids, unique_pk, not_null, fk_refcls_oid,
10269  fk_refcls_pk_btid, fk_name, SM_GET_FILTER_PRED_STREAM (filter_index),
10270  SM_GET_FILTER_PRED_STREAM_SIZE (filter_index), NULL, -1, -1, -1, index_status);
10271  }
10272  }
10273 
10274  free_and_init (attr_ids);
10275  free_and_init (oids);
10276  free_and_init (hfids);
10277 
10278  return error;
10279 
10280 mem_error:
10281  ASSERT_ERROR_AND_SET (error);
10282 
10283 gen_error:
10284  if (attr_ids != NULL)
10285  {
10286  free_and_init (attr_ids);
10287  }
10288  if (oids != NULL)
10289  {
10290  free_and_init (oids);
10291  }
10292  if (hfids != NULL)
10293  {
10294  free_and_init (hfids);
10295  }
10296 
10297  return error;
10298 }
10299 
10300 /*
10301  * deallocate_index() - Deallocate an index that was previously created for
10302  * an attribute.
10303  * return: NO_ERROR on success, non-zero for ERROR
10304  * cons(in):
10305  * index(in/out): index disk identifier
10306  */
10307 
10308 static int
10310 {
10311  int error = NO_ERROR;
10312  SM_CLASS_CONSTRAINT *con;
10313  int ref_count = 0;
10314 
10315  for (con = cons; con != NULL; con = con->next)
10316  {
10317  if (BTID_IS_EQUAL (index, &con->index_btid))
10318  {
10319  ref_count++;
10320  }
10321  }
10322 
10323  if (ref_count == 1)
10324  {
10325  error = btree_delete_index (index);
10326  }
10327 
10328  return error;
10329 }
10330 
10331 /*
10332  * remove_class_from_index() - Remove the class from the B-tree.
10333  * This is used when it's necessary to delete instances from a particular
10334  * class out of a B-tree while leaving other class instances intact.
10335  * return: NO_ERROR on success, non-zero for ERROR
10336  * oid(in): Class OID
10337  * index(in/out): B-tree index
10338  * heap(in/out): Class heap
10339  */
10340 
10341 static int
10343 {
10344  /* If there is no heap, then there cannot be instances to remove. */
10345  if (HFID_IS_NULL (heap))
10346  {
10347  return NO_ERROR;
10348  }
10349 
10350  return locator_remove_class_from_index (oid, index, heap);
10351 }
10352 
10353 /*
10354  * check_fk_validity()
10355  * return: NO_ERROR on success, non-zero for ERROR
10356  * classop(in): class object
10357  * class(in): class structure
10358  * key_attrs(in): attribute getting the index
10359  * asc_desc(in): asc/desc info list
10360  * pk_cls_oid(in):
10361  * pk_btid(in):
10362  * fk_name(in):
10363  */
10364 
10365 static int
10366 check_fk_validity (MOP classop, SM_CLASS * class_, SM_ATTRIBUTE ** key_attrs, const int *asc_desc, OID * pk_cls_oid,
10367  BTID * pk_btid, char *fk_name)
10368 {
10369  int error = NO_ERROR;
10370  int i, n_attrs;
10371  int *attr_ids = NULL;
10372  TP_DOMAIN *domain = NULL;
10373  OID *cls_oid;
10374  HFID *hfid;
10375 
10376  cls_oid = ws_oid (classop);
10377  hfid = sm_ch_heap ((MOBJ) class_);
10378 
10379  if (!HFID_IS_NULL (hfid) && heap_has_instance (hfid, cls_oid, 0))
10380  {
10381  for (i = 0, n_attrs = 0; key_attrs[i] != NULL; i++, n_attrs++);
10382 
10383  domain = construct_index_key_domain (n_attrs, key_attrs, asc_desc, NULL, -1, NULL);
10384  if (domain == NULL)
10385  {
10386  assert (er_errid () != NO_ERROR);
10387  return er_errid ();
10388  }
10389 
10390  attr_ids = (int *) malloc (n_attrs * sizeof (int));
10391  if (attr_ids == NULL)
10392  {
10393  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, n_attrs * sizeof (int));
10394  return ER_OUT_OF_VIRTUAL_MEMORY;
10395  }
10396 
10397  for (i = 0; i < n_attrs; i++)
10398  {
10399  attr_ids[i] = key_attrs[i]->id;
10400  }
10401 
10402  error = locator_check_fk_validity (cls_oid, hfid, domain, n_attrs, attr_ids, pk_cls_oid, pk_btid, fk_name);
10403 
10404  free_and_init (attr_ids);
10405  }
10406 
10407  return error;
10408 }
10409 
10410 /*
10411  * update_foreign_key_ref() - Update PK referenced by FK
10412  * return: NO_ERROR on success, non-zero for ERROR
10413  * ref_clsop(in): referenced class by FK
10414  * fk_info(in): foreign key info
10415  */
10416 static int
10418 {
10419  SM_TEMPLATE *template_;
10420  SM_CLASS *ref_class_;
10421  SM_CLASS_CONSTRAINT *pk;
10422  MOP owner_clsop = NULL;
10423  int save, error;
10424 
10425  AU_DISABLE (save);
10426 
10427  error = au_fetch_class_force (ref_clsop, &ref_class_, AU_FETCH_READ);
10428  if (error != NO_ERROR)
10429  {
10430  AU_ENABLE (save);
10431  return error;
10432  }
10433 
10434  if (ref_class_->inheritance != NULL)
10435  {
10436  /* the PK of referenced table may come from.its parent table */
10437  pk = classobj_find_cons_primary_key (ref_class_->constraints);
10438  if (pk == NULL)
10439  {
10440  AU_ENABLE (save);
10443  }
10444  owner_clsop = pk->attributes[0]->class_mop;
10445  }
10446  else
10447  {
10448  owner_clsop = ref_clsop;
10449  }
10450 
10451  template_ = dbt_edit_class (owner_clsop);
10452  if (template_ == NULL)
10453  {
10454  AU_ENABLE (save);
10455 
10456  assert (er_errid () != NO_ERROR);
10457  return er_errid ();
10458  }
10459 
10460  error = update_fk_ref_partitioned_class (template_, fk_info, NULL, NULL, NULL);
10461  if (error != NO_ERROR)
10462  {
10463  dbt_abort_class (template_);
10464  AU_ENABLE (save);
10465  return error;
10466  }
10467 
10468  error = classobj_put_foreign_key_ref (&(template_->properties), fk_info);
10469  if (error != NO_ERROR)
10470  {
10471  dbt_abort_class (template_);
10472  AU_ENABLE (save);
10473  return error;
10474  }
10475 
10476  ref_clsop = dbt_finish_class (template_);
10477  if (ref_clsop == NULL)
10478  {
10479  dbt_abort_class (template_);
10480  AU_ENABLE (save);
10481 
10482  assert (er_errid () != NO_ERROR);
10483  return er_errid ();
10484  }
10485 
10486  AU_ENABLE (save);
10487  return NO_ERROR;
10488 }
10489 
10490 #if defined (ENABLE_RENAME_CONSTRAINT)
10491 /*
10492  * sm_rename_foreign_key_ref() - Rename constraint name in PK referenced by FK
10493  * return: NO_ERROR on success, non-zero for ERROR
10494  * ref_clsop(in): referenced class by FK
10495  * btid(in): the BTID of the constraint which needs to rename
10496  * old_name(in): old constraint name
10497  * new_name(in): new constraint name
10498  */
10499 int
10500 sm_rename_foreign_key_ref (MOP ref_clsop, const BTID * btid, const char *old_name, const char *new_name)
10501 {
10502  SM_TEMPLATE *template_;
10503  SM_CLASS *ref_class_;
10504  SM_CLASS_CONSTRAINT *pk;
10505  MOP owner_clsop = NULL;
10506  int save, error;
10507 
10508  AU_DISABLE (save);
10509 
10510  error = au_fetch_class_force (ref_clsop, &ref_class_, AU_FETCH_READ);
10511  if (error != NO_ERROR)
10512  {
10513  AU_ENABLE (save);
10514  return error;
10515  }
10516 
10517  if (ref_class_->inheritance != NULL)
10518  {
10519  /* the PK of referenced table may come from.its parent table */
10520  pk = classobj_find_cons_primary_key (ref_class_->constraints);
10521  if (pk == NULL)
10522  {
10523  AU_ENABLE (save);
10526  }
10527  owner_clsop = pk->attributes[0]->class_mop;
10528  }
10529  else
10530  {
10531  owner_clsop = ref_clsop;
10532  }
10533 
10534  template_ = dbt_edit_class (owner_clsop);
10535  if (template_ == NULL)
10536  {
10537  AU_ENABLE (save);
10538  return (er_errid () != NO_ERROR) ? er_errid () : ER_FAILED;
10539  }
10540 
10541  error = update_fk_ref_partitioned_class (template_, NULL, btid, old_name, new_name);
10542  if (error != NO_ERROR)
10543  {
10544  dbt_abort_class (template_);
10545  AU_ENABLE (save);
10546  return error;
10547  }
10548 
10549  error = classobj_rename_foreign_key_ref (&(template_->properties), btid, old_name, new_name);
10550  if (error != NO_ERROR)
10551  {
10552  dbt_abort_class (template_);
10553  AU_ENABLE (save);
10554  return error;
10555  }
10556 
10557  ref_clsop = dbt_finish_class (template_);
10558  if (ref_clsop == NULL)
10559  {
10560  dbt_abort_class (template_);
10561  AU_ENABLE (save);
10562  return (er_errid () != NO_ERROR) ? er_errid () : ER_FAILED;
10563  }
10564 
10565  AU_ENABLE (save);
10566  return NO_ERROR;
10567 }
10568 #endif
10569 
10570 /*
10571  * allocate_unique_constraint() - Allocate index for unique constraints
10572  * return: NO_ERROR on success, non-zero for ERROR
10573  * classop(in): class object
10574  * class(in): class structure
10575  * con(in):constraint info
10576  * subclasses(in): sub class list
10577  * template_(in): template
10578  */
10579 static int
10581  SM_TEMPLATE * template_)
10582 {
10583  int unique_pk, not_null, reverse;
10584  SM_CLASS *super_class;
10585  SM_CLASS_CONSTRAINT *super_con, *shared_con;
10586  const int *asc_desc;
10587  int is_global = 0;
10588  SM_ATTRIBUTE *attr = NULL;
10589  SM_ATTRIBUTE *key_attr = NULL;
10590  int i = 0, j = 0;
10591 
10592  /* At this point, we have to distinguish between the following cases: 1. This is a subclass and the constraint is
10593  * inherited -> just copy the BTID 2. This is a subclass and the constraint is duplicated -> create a new BTID and
10594  * load it 3. This is the top class in the hierarchy and the constraint is inherited in the subclasses -> create the
10595  * constraint and load data from this class and all subclasses 4. This is the top class in the hierarchy and the
10596  * constraint is duplicated in the subclasses -> create the constraint and only load data from this class */
10597 
10598  assert (con->attributes != NULL);
10599 
10600  attr = &class_->attributes[0];
10601  while (attr != NULL && i < class_->att_count)
10602  {
10603  if (attr->flags & SM_ATTFLAG_PARTITION_KEY)
10604  {
10605  /* if the attribute is part of the partitioning key, it must be present in the unique key */
10606  j = 0;
10607  key_attr = con->attributes[0];
10608  while (key_attr != NULL)
10609  {
10610  if (key_attr->id == attr->id)
10611  {
10612  /* attribute found */
10613  break;
10614  }
10615  j++;
10616  key_attr = con->attributes[j];
10617  }
10618  if (key_attr == NULL)
10619  {
10620  /* attribute not found, raise an error */
10623  }
10624  }
10625  i++;
10626  attr = &class_->attributes[i];
10627  }
10628 
10629  if (con->attributes[0]->class_mop != classop)
10630  {
10631  /* This is an inherited constraint */
10632  is_global = 1;
10633 
10634  if (sm_is_global_only_constraint (con->attributes[0]->class_mop, con, &is_global, template_) != NO_ERROR)
10635  {
10636  return er_errid ();
10637  }
10638  }
10639 
10640  if (is_global == 0)
10641  {
10642  /* its local, allocate our very own index */
10643  DB_OBJLIST *local_subclasses = NULL;
10644  int is_global_cnst = 0;
10645 
10646  unique_pk = BTREE_CONSTRAINT_UNIQUE;
10647  if (con->type == SM_CONSTRAINT_PRIMARY_KEY)
10648  {
10649  unique_pk |= BTREE_CONSTRAINT_PRIMARY_KEY;
10650  }
10651 
10652  if (con->attributes[0]->class_mop == classop)
10653  {
10654  if (sm_is_global_only_constraint (classop, con, &is_global_cnst, template_) != NO_ERROR)
10655  {
10656  return er_errid ();
10657  }
10658  if (is_global_cnst)
10659  {
10660  /* This is an inherited constraint, load subclasses: case 3 */
10661  local_subclasses = subclasses;
10662  }
10663  else
10664  {
10665  /* This is a duplicated constraint, do not load subclasses: case 4 */
10666  local_subclasses = NULL;
10667  }
10668  }
10669 
10670  if (con->shared_cons_name)
10671  {
10672  shared_con = classobj_find_constraint_by_name (class_->constraints, con->shared_cons_name);
10673  con->index_btid = shared_con->index_btid;
10674  }
10675  else
10676  {
10678  || con->type == SM_CONSTRAINT_PRIMARY_KEY)
10679  {
10680  asc_desc = con->asc_desc;
10681  }
10682  else
10683  {
10684  asc_desc = NULL;
10685  }
10686 
10688  not_null = con->type == SM_CONSTRAINT_PRIMARY_KEY ? true : false;
10689 
10690  if (allocate_index (classop, class_, local_subclasses, con->attributes, asc_desc, con->attrs_prefix_length,
10691  unique_pk, not_null, reverse, con->name, &con->index_btid, NULL, NULL, NULL,
10692  con->filter_predicate, con->func_index_info, con->index_status))
10693  {
10694  assert (er_errid () != NO_ERROR);
10695  return er_errid ();
10696  }
10697  }
10698  }
10699  else
10700  {
10701  if (au_fetch_class_force (con->attributes[0]->class_mop, &super_class, AU_FETCH_READ))
10702  {
10703  assert (er_errid () != NO_ERROR);
10704  return er_errid ();
10705  }
10706 
10707  /* its inherited, go get the btid from the super class */
10708  super_con = classobj_find_class_constraint (super_class->constraints, con->type, con->name);
10709  if (super_con != NULL)
10710  {
10711  con->index_btid = super_con->index_btid;
10712  }
10713  else
10714  {
10715  /* not supposed to happen, need a better error */
10717  return ER_SM_INVALID_PROPERTY;
10718  }
10719  }
10720 
10721  return NO_ERROR;
10722 }
10723 
10724 /*
10725  * allocate_foreign_key() - Allocate index for foreign key
10726  * return: NO_ERROR on success, non-zero for ERROR
10727  * classop(in): class object
10728  * class(in): class structure
10729  * con(in): constraint info
10730  * subclasses(in): subclasses
10731  */
10732 static int
10733 allocate_foreign_key (MOP classop, SM_CLASS * class_, SM_CLASS_CONSTRAINT * con, DB_OBJLIST * subclasses)
10734 {
10735  SM_CLASS_CONSTRAINT *pk, *existing_con;
10736  MOP ref_clsop;
10737 
10738  if (OID_ISNULL (&con->fk_info->ref_class_oid))
10739  {
10740  con->fk_info->ref_class_oid = *(ws_oid (classop));
10741 
10743  if (pk == NULL)
10744  {
10747  }
10748  con->fk_info->ref_class_pk_btid = pk->index_btid;
10749  }
10750 
10751  if (con->shared_cons_name != NULL)
10752  {
10753  existing_con = classobj_find_constraint_by_name (class_->constraints, con->shared_cons_name);
10754  con->index_btid = existing_con->index_btid;
10755 
10756  assert (existing_con->type == SM_CONSTRAINT_FOREIGN_KEY || existing_con->type == SM_CONSTRAINT_UNIQUE
10757  || existing_con->type == SM_CONSTRAINT_PRIMARY_KEY || existing_con->type == SM_CONSTRAINT_INDEX);
10758  if (existing_con->type != SM_CONSTRAINT_FOREIGN_KEY)
10759  {
10760  if (check_fk_validity (classop, class_, con->attributes, con->asc_desc, &(con->fk_info->ref_class_oid),
10761  &(con->fk_info->ref_class_pk_btid), (char *) con->fk_info->name) != NO_ERROR)
10762  {
10763  assert (er_errid () != NO_ERROR);
10764  return er_errid ();
10765  }
10766  }
10767  }
10768  else
10769  {
10770  if (allocate_index (classop, class_, subclasses, con->attributes, NULL, con->attrs_prefix_length,
10771  0 /* unique_pk */ , false, false, con->name, &con->index_btid,
10772  &(con->fk_info->ref_class_oid), &(con->fk_info->ref_class_pk_btid), con->fk_info->name,
10773  con->filter_predicate, con->func_index_info, con->index_status))
10774  {
10775  assert (er_errid () != NO_ERROR);
10776  return er_errid ();
10777  }
10778  }
10779 
10780  con->fk_info->self_oid = *(ws_oid (classop));
10781  con->fk_info->self_btid = con->index_btid;
10782 
10783  ref_clsop = ws_mop (&(con->fk_info->ref_class_oid), NULL);
10784 
10785  if (classop == ref_clsop)
10786  {
10787  if (classobj_put_foreign_key_ref (&(class_->properties), con->fk_info) != NO_ERROR)
10788  {
10789  assert (er_errid () != NO_ERROR);
10790  return er_errid ();
10791  }
10792  class_->recache_constraints = 1;
10793  }
10794  else if (!classobj_is_exist_foreign_key_ref (ref_clsop, con->fk_info) || con->shared_cons_name != NULL)
10795  {
10796  if (update_foreign_key_ref (ref_clsop, con->fk_info) != NO_ERROR)
10797  {
10798  assert (er_errid () != NO_ERROR);
10799  return er_errid ();
10800  }
10801  }
10802 
10803  return NO_ERROR;
10804 }
10805 
10806 /*
10807  * allocate_disk_structures_index() - Helper for index allocation
10808  * return: NO_ERROR on success, non-zero for ERROR
10809  * classop(in): class object
10810  * class(in): class structure
10811  * con(in):constraint info
10812  * subclasses(in): sub class list
10813  * template_(in): object template
10814  */
10815 static int
10817  SM_TEMPLATE * template_)
10818 {
10819  int error = NO_ERROR;
10820  int reverse;
10821 
10822  if (!SM_IS_CONSTRAINT_INDEX_FAMILY (con->type))
10823  {
10824  assert (false);
10825  return NO_ERROR;
10826  }
10827 
10828  if (BTID_IS_NULL (&con->index_btid))
10829  {
10831  {
10832  error = allocate_unique_constraint (classop, class_, con, subclasses, template_);
10833  }
10834  else if (con->type == SM_CONSTRAINT_INDEX || con->type == SM_CONSTRAINT_REVERSE_INDEX)
10835  {
10836  reverse = (con->type == SM_CONSTRAINT_INDEX) ? false : true;
10837  error = allocate_index (classop, class_, NULL, con->attributes, con->asc_desc, con->attrs_prefix_length,
10838  0 /* unique_pk */ , false, reverse, con->name, &con->index_btid, NULL, NULL, NULL,
10839  con->filter_predicate, con->func_index_info, con->index_status);
10840  }
10841  else if (con->type == SM_CONSTRAINT_FOREIGN_KEY)
10842  {
10843  error = allocate_foreign_key (classop, class_, con, subclasses);
10844  }
10845 
10846  if (error != NO_ERROR)
10847  {
10848  return error;
10849  }
10850 
10851  /* check for safe guard */
10852  if (BTID_IS_NULL (&con->index_btid))
10853  {
10854  return ER_FAILED; /* unknown error */
10855  }
10856  }
10857 
10858  /* Whether we allocated a BTID or not, always write the constraint info back out to the property list.
10859  * This is where the promotion of attribute name references to ids references happens.
10860  */
10861  if (classobj_put_index (&(class_->properties), con->type, con->name, con->attributes, con->asc_desc,
10862  con->attrs_prefix_length, &(con->index_btid), con->filter_predicate, con->fk_info, NULL,
10863  con->func_index_info, con->comment, con->index_status, false) != NO_ERROR)
10864  {
10865  return error;
10866  }
10867 
10868  return NO_ERROR;
10869 }
10870 
10871 /*
10872  * allocate_disk_structures() - Allocate the necessary disk structures for
10873  * a new or modified class. For constraints, be careful to recognize
10874  * a place holder for a BTID that hasn't been allocated yet but whose
10875  * definition was actually inherited from a super class. When we find these,
10876  * go to the super class and use the BTID that will have by now been
10877  * allocated in there rather than allocating a new one of our own.
10878  * return: The number of indexes of the table on success, non-zero for ERROR
10879  * classop(in): class object
10880  * class(in): class structure
10881  * template_(in): object template
10882  * subclasses(in):
10883  */
10884 static int
10885 allocate_disk_structures (MOP classop, SM_CLASS * class_, DB_OBJLIST * subclasses, SM_TEMPLATE * template_)
10886 {
10887  SM_CLASS_CONSTRAINT *con;
10888  int num_indexes = 0;
10889  int err;
10890  bool dont_decache_and_flush = false;
10891  SM_ATTRIBUTE **att, **new_attributes;
10892  int att_count;
10893 
10894  assert (classop != NULL);
10895 
10896  if (classop == NULL)
10897  {
10898  return ER_FAILED;
10899  }
10900 
10901  /* Allocate_disk_structures may be called twice on the call-stack. Make sure constraints are not decached or recached
10902  * while they are processed. */
10903  dont_decache_and_flush = class_->dont_decache_constraints_or_flush;
10904 
10905  if (!dont_decache_and_flush)
10906  {
10908  {
10909  goto structure_error;
10910  }
10911  /* be sure that constraints attributes are not decached. This may happen for foreign key, when
10912  * allocate_disk_structures function may be called second time. */
10913  for (con = class_->constraints; con != NULL; con = con->next)
10914  {
10915  if (con->type == SM_CONSTRAINT_FOREIGN_KEY && con->attributes[0] != NULL)
10916  {
10917  /* we are sure that con->attributes points to class attributes */
10918  att_count = 0;
10919  for (att = con->attributes; *att; att++)
10920  {
10921  att_count++;
10922  }
10923 
10924  new_attributes = (SM_ATTRIBUTE **) db_ws_alloc (sizeof (SM_ATTRIBUTE *) * (att_count + 1));
10925  if (new_attributes == NULL)
10926  {
10927  assert (er_errid () != NO_ERROR);
10928  goto structure_error;
10929  }
10930 
10931  att_count = 0;
10932  for (att = con->attributes; *att; att++)
10933  {
10934  new_attributes[att_count++] = classobj_copy_attribute (*att, NULL);
10935  }
10936 
10937  new_attributes[att_count] = NULL;
10938  con->attributes = new_attributes;
10939  }
10940  }
10941  }
10943 
10944  if (OID_ISTEMP (ws_oid (classop)))
10945  {
10946  if (locator_assign_permanent_oid (classop) == NULL)
10947  {
10948  if (er_errid () == NO_ERROR)
10949  {
10951  }
10952 
10953  goto structure_error;
10954  }
10955  }
10956 
10957  for (con = class_->constraints; con != NULL; con = con->next)
10958  {
10959  /* check for non-shared indexes */
10960  if (SM_IS_CONSTRAINT_INDEX_FAMILY (con->type) && con->attributes[0] != NULL && con->shared_cons_name == NULL)
10961  {
10962  if (allocate_disk_structures_index (classop, class_, con, subclasses, template_) != NO_ERROR)
10963  {
10964  goto structure_error;
10965  }
10966 
10967  num_indexes++;
10968  }
10969  }
10970 
10971  for (con = class_->constraints; con != NULL; con = con->next)
10972  {
10973  /* check for shared indexes */
10974  if (SM_IS_CONSTRAINT_INDEX_FAMILY (con->type) && con->attributes[0] != NULL && con->shared_cons_name != NULL)
10975  {
10976  if (allocate_disk_structures_index (classop, class_, con, subclasses, template_) != NO_ERROR)
10977  {
10978  goto structure_error;
10979  }
10980 
10981  num_indexes++;
10982  }
10983  }
10984 
10985  if (!dont_decache_and_flush)
10986  {
10987  /* Reset dont_decache_constraints_or_flush */
10989 
10990  for (con = class_->constraints; con != NULL; con = con->next)
10991  {
10992  if (con->type == SM_CONSTRAINT_FOREIGN_KEY)
10993  {
10994  /* free attributes to avoid memory leak */
10995  for (att = con->attributes; *att; att++)
10996  {
10997  db_ws_free_and_init (*att);
10998  }
10999 
11000  if (class_->recache_constraints == 0)
11001  {
11002  /* recache constraints since attributes are not set */
11003  class_->recache_constraints = 1;
11004  }
11005  }
11006  }
11007 
11008  /* recache class constraint for foreign key */
11009  if (class_->recache_constraints)
11010  {
11012  {
11013  goto structure_error;
11014  }
11015  }
11016  class_->recache_constraints = 0;
11017 
11018  /* when we're done, make sure that each attribute cache is also updated. */
11019  if (!classobj_cache_constraints (class_))
11020  {
11021  goto structure_error;
11022  }
11023 
11024  if (locator_update_class (classop) == NULL)
11025  {
11026  goto structure_error;
11027  }
11028 
11029  if (locator_flush_class (classop) != NO_ERROR)
11030  {
11031  goto structure_error;
11032  }
11033  }
11034  else
11035  {
11036  /* Class constraints will be recached, updated and flushed on a previous call. */
11037  }
11038 
11039  return num_indexes;
11040 
11041 structure_error:
11042  /* the workspace has already been damaged by this point, the caller will have to recognize the error and abort the
11043  * transaction. */
11044  ASSERT_ERROR_AND_SET (err);
11045  return err;
11046 }
11047 
11048 /*
11049  * drop_foreign_key_ref() - The wrap function to drop foreign key reference
11050  * and retrieve some data which may have been renewed during the process.
11051  * return: NO_ERROR on success, non-zero for ERROR
11052  * classop(in): the class object
11053  * class_(in): the class structure
11054  * flat_cons(in): the flattened constraint list
11055  * cons(in/out): the constraint to drop.
11056  */
11057 static int
11059 {
11060  int error = NO_ERROR;
11061  char *saved_name = NULL;
11062  int name_length = 0;
11063 
11064  assert (class_ != NULL && class_->constraints != NULL && *cons != NULL);
11065 
11066  name_length = strlen ((*cons)->name) + 1;
11067  saved_name = (char *) malloc (name_length);
11068  if (saved_name == NULL)
11069  {
11070  error = ER_OUT_OF_VIRTUAL_MEMORY;
11071  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, (size_t) name_length);
11072  goto end;
11073  }
11074 
11075  strcpy (saved_name, (*cons)->name);
11076 
11077  /* Since the constraints may be reallocated during the following process, we have to mark a special status flag to be
11078  * used for identifying whether the instance will have been reallocated. */
11080 
11081  error = drop_foreign_key_ref_internal (classop, flat_cons, *cons);
11082  if (error != NO_ERROR)
11083  {
11084  goto end;
11085  }
11086 
11088  {
11089  /* The above function has freed and refetched the class_ together with its constraints list. The 'con' should
11090  * have been freed also, therefore we have to retrieve the 'con' from the renewed constraints list. */
11092  if (*cons == NULL)
11093  {
11094  /* Normally, it should not reach here. */
11095  assert (false);
11096 
11097  error = ER_GENERIC_ERROR;
11098  goto end;
11099  }
11100  }
11101 
11102 end:
11103 
11104  if (class_->constraints != NULL && class_->constraints->extra_status == SM_FLAG_TO_BE_REINTIALIZED)
11105  {
11106  /* Since the constraints have never been reallocated during the above process, just recover the normal status of
11107  * the constraint. */
11109  }
11110 
11111  if (saved_name != NULL)
11112  {
11113  free_and_init (saved_name);
11114  }
11115 
11116  return error;
11117 }
11118 
11119 /*
11120  * drop_foreign_key_ref_internal()
11121  * return: NO_ERROR on success, non-zero for ERROR
11122  * classop(in):
11123  * flat_cons(in):
11124  * cons(in):
11125  */
11126 
11127 static int
11129 {
11130  int err = NO_ERROR;
11131  MOP ref_clsop;
11132  SM_TEMPLATE *refcls_template;
11133  int save;
11134  SM_CLASS_CONSTRAINT *con;
11135  SM_FOREIGN_KEY_INFO *fk;
11136 
11137  AU_DISABLE (save);
11138 
11139  ref_clsop = ws_mop (&cons->fk_info->ref_class_oid, NULL);
11140 
11141  if (classop == ref_clsop)
11142  {
11143  for (con = flat_cons; con != NULL; con = con->next)
11144  {
11145  if (con->type == SM_CONSTRAINT_PRIMARY_KEY)
11146  {
11147  for (fk = con->fk_info; fk != NULL; fk = fk->next)
11148  {
11149  if (BTID_IS_EQUAL (&fk->self_btid, &cons->index_btid))
11150  {
11151  fk->is_dropped = true;
11152  break;
11153  }
11154  }
11155  break;
11156  }
11157  }
11158  }
11159  else
11160  {
11161  SM_CLASS *ref_class_;
11162  SM_CLASS_CONSTRAINT *pk;
11163  MOP owner_clsop;
11164 
11165  err = au_fetch_class_force (ref_clsop, &ref_class_, AU_FETCH_READ);
11166  if (err != NO_ERROR)
11167  {
11168  AU_ENABLE (save);
11169  return err;
11170  }
11171  if (ref_class_->inheritance != NULL)
11172  {
11173  /* the PK of referenced table may come from.its parent table */
11174  pk = classobj_find_cons_primary_key (ref_class_->constraints);
11175  if (pk == NULL)
11176  {
11177  AU_ENABLE (save);
11180  }
11181  owner_clsop = pk->attributes[0]->class_mop;
11182  }
11183  else
11184  {
11185  owner_clsop = ref_clsop;
11186  }
11187 
11188  refcls_template = dbt_edit_class (owner_clsop);
11189  if (refcls_template == NULL)
11190  {
11191  AU_ENABLE (save);
11192 
11193  assert (er_errid () != NO_ERROR);
11194  return er_errid ();
11195  }
11196 
11197  err = update_fk_ref_partitioned_class (refcls_template, NULL, &cons->index_btid, cons->name, NULL);
11198  if (err != NO_ERROR)
11199  {
11200  goto error;
11201  }
11202 
11203  err = classobj_drop_foreign_key_ref (&refcls_template->properties, &cons->index_btid, cons->name);
11204  if (err != NO_ERROR)
11205  {
11206  goto error;
11207  }
11208 
11209  ref_clsop = dbt_finish_class (refcls_template);
11210  if (ref_clsop == NULL)
11211  {
11212  assert (er_errid () != NO_ERROR);
11213  err = er_errid ();
11214  goto error;
11215  }
11216  }
11217 
11218  AU_ENABLE (save);
11219  return NO_ERROR;
11220 
11221 error:
11222  dbt_abort_class (refcls_template);
11223  AU_ENABLE (save);
11224 
11225  return err;
11226 }
11227 
11228 /*
11229  * is_index_owner() - check if class is index owner
11230  * return: true if index owner or false
11231  * classop(in):
11232  * con(in):
11233  */
11234 
11235 static bool
11237 {
11238  MOP origin_classop;
11239  int is_global = 0;
11240 
11241  origin_classop = con->attributes[0]->class_mop;
11242 
11243  if (origin_classop == classop)
11244  {
11245  return true;
11246  }
11247 
11248  /* we are not the owner of this index so it belongs to us only if it is not a global constraint */
11249  if (sm_is_global_only_constraint (classop, con, &is_global, NULL) != NO_ERROR)
11250  {
11251  return false;
11252  }
11253  return !is_global;
11254 }
11255 
11256 /*
11257  * inherit_constraint() - inherit constraint from super class
11258  * return: NO_ERROR on success, non-zero for ERROR
11259  * classop(in):
11260  * con(in):
11261  */
11262 
11263 static int
11265 {
11266  SM_ATTRIBUTE *att;
11267  SM_CLASS *super_class;
11268  SM_CLASS_CONSTRAINT *super_con;
11269  int error = NO_ERROR;
11270 
11271  att = con->attributes[0];
11272  if (att != NULL && att->class_mop != classop)
11273  {
11274  /* its inherited, go get the btid from the super class */
11275 
11276  error = au_fetch_class_force (att->class_mop, &super_class, AU_FETCH_READ);
11277  if (error == NO_ERROR)
11278  {
11279  super_con = classobj_find_class_constraint (super_class->constraints, con->type, con->name);
11280  if (super_con == NULL)
11281  {
11282  /* not supposed to happen, need a better error */
11283  error = ER_SM_INVALID_PROPERTY;
11284  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 0);
11285  }
11286  else
11287  {
11288  /* copy the index */
11289  con->index_btid = super_con->index_btid;
11290  }
11291  }
11292  }
11293 
11294  return error;
11295 }
11296 
11297 /*
11298  * sm_filter_index_pred_have_invalid_attrs() - Check whether filter index
11299  * predicate contain invalid
11300  * class attributes
11301  * return: true if filter index predicate contain invalid (removed)
11302  * attributes, false otherwise
11303  * class_name(in): class name
11304  * old_atts(in): old class attributes
11305  * new_atts(in): new class attributes
11306  */
11307 bool
11309  SM_ATTRIBUTE * new_atts)
11310 {
11311  SM_ATTRIBUTE *old_att = NULL;
11312  int i;
11313 
11314  if (constraint == NULL || old_atts == NULL || new_atts == NULL || constraint->filter_predicate == NULL
11315  || constraint->filter_predicate->att_ids == NULL)
11316  {
11317  return false;
11318  }
11319 
11320  assert (constraint->filter_predicate->num_attrs > 0);
11321  for (old_att = old_atts; old_att != NULL; old_att = (SM_ATTRIBUTE *) old_att->header.next)
11322  {
11323  if (find_matching_att (new_atts, old_att, 1) == NULL)
11324  {
11325  /* old_att has been removed */
11326  for (i = 0; i < constraint->filter_predicate->num_attrs; i++)
11327  {
11328  if (constraint->filter_predicate->att_ids[i] == old_att->id)
11329  {
11330  return true;
11331  }
11332  }
11333  }
11334  }
11335 
11336  return false;
11337 }
11338 
11339 
11340 /*
11341  * transfer_disk_structures() - Work function for install_new_representation.
11342  * Here we look for any attributes that are being dropped from the
11343  * class and remove their associated disk structures (if any).
11344  * This also moves the index ids from the existing attribute structures
11345  * into the new ones. It must do this because copying the index
11346  * field is not part of the usual copying done by the cl_ functions.
11347  * This is because indexes are not inherited and we
11348  * must be very careful that they stay only with the class on which
11349  * they were defined.
11350  * This can also be called for sm_delete_class with a template of
11351  * NULL in which case we just free all disk structures we find.
11352  * We DO NOT allocate new index structures here, see
11353  * allocate_disk_structures to see how that is done.
11354  * This is where BTID's for unique & indexes get inherited.
11355  * return: NO_ERROR on success, non-zero for ERROR
11356  * classop(in): class object
11357  * class(in): class structure
11358  * flat(out): new flattened template
11359  */
11360 /*
11361  * TODO: Think about moving the functionality of allocate_disk_structures
11362  * in here, it should be possible to do that and would simplify things.
11363  */
11364 
11365 static int
11367 {
11368  int error = NO_ERROR;
11369  SM_CLASS_CONSTRAINT *flat_constraints = NULL, *con, *new_con, *prev, *next;
11370  SM_ATTRIBUTE *attr = NULL;
11371  int num_pk;
11372  bool is_partitioned;
11373  BTID btid;
11374  MOP origin_classop;
11375  int is_global_index = 0;
11376 
11377  /* Get the cached constraint info for the flattened template. Sigh, convert the template property list to a transient
11378  * constraint cache so we have a prayer of dealing with it. */
11379  if (flat != NULL)
11380  {
11381  error = classobj_make_class_constraints (flat->properties, flat->instance_attributes, &flat_constraints);
11382  if (error != NO_ERROR)
11383  {
11384  goto end;
11385  }
11386  }
11387 
11388  /* loop over each old constraint */
11389  for (con = class_->constraints; ((con != NULL) && (error == NO_ERROR)); con = con->next)
11390  {
11391  if (!SM_IS_CONSTRAINT_INDEX_FAMILY (con->type))
11392  {
11393  continue;
11394  }
11395 
11396  new_con = classobj_find_class_constraint (flat_constraints, con->type, con->name);
11397 #if defined (ENABLE_RENAME_CONSTRAINT)
11398  /* TODO: We have to differentiate between the case of rename constraint and dropping a shared index. For
11399  * instance, when index is renamed, the foreign key references in primary key are also updated. We don't have to
11400  * call drop_foreign_key_ref here. */
11401 #endif
11402 
11403  if (new_con != NULL)
11404  {
11405  /* Index still exists. */
11406 
11407  if (!BTID_IS_EQUAL (&con->index_btid, &new_con->index_btid))
11408  {
11409  if (BTID_IS_NULL (&(new_con->index_btid)))
11410  {
11411  /* Template index isn't set, transfer the old one Can this happen, it should have been transfered by
11412  * now. */
11413  new_con->index_btid = con->index_btid;
11414  }
11415  else
11416  {
11417  /* The index in the new template is not the same, I'm not entirely sure what this means or how we can
11418  * get here. Possibly if we drop the unique but add it again with the same name but over different
11419  * attributes. */
11420  if (con->attributes[0] != NULL && is_index_owner (classop, con))
11421  {
11422  if (con->type == SM_CONSTRAINT_FOREIGN_KEY)
11423  {
11424  error = drop_foreign_key_ref (classop, class_, flat_constraints, &con);
11425  if (error != NO_ERROR)
11426  {
11427  goto end;
11428  }
11429  }
11430 
11431  error = deallocate_index (class_->constraints, &con->index_btid);
11432  if (error != NO_ERROR)
11433  {
11434  goto end;
11435  }
11436  BTID_SET_NULL (&con->index_btid);
11437  }
11438  }
11439  }
11440  continue;
11441  }
11442  /* Index was dropped or renamed. */
11443 
11444  if (con->attributes[0] != NULL)
11445  {
11446  if (con->type == SM_CONSTRAINT_FOREIGN_KEY)
11447  {
11448  error = drop_foreign_key_ref (classop, class_, flat_constraints, &con);
11449  if (error != NO_ERROR)
11450  {
11451  goto end;
11452  }
11453  }
11454  /* Does index structure still exist? It is possible if index was renamed or if BTID was shared. */
11455  new_con = classobj_find_class_constraint_by_btid (flat_constraints, con->type, con->index_btid);
11456  if (new_con == NULL)
11457  {
11458  /* Index structure doesn't exist. */
11459  if (is_index_owner (classop, con))
11460  {
11461  /* destroy the old index but only if we're the owner of it! */
11462  error = deallocate_index (class_->constraints, &con->index_btid);
11463  if (error != NO_ERROR)
11464  {
11465  goto end;
11466  }
11467  }
11468  else
11469  {
11470  /* If we're not the owner of it, then only remove this class from the B-tree (the B-tree will still
11471  * exist). */
11472  origin_classop = con->attributes[0]->class_mop;
11473  if (sm_exist_index (origin_classop, con->name, &btid) == NO_ERROR)
11474  {
11475  /* Only do this if the B-tree still exists. If classop is a subclass of the class owning the
11476  * index and we're in the middle of a drop index statement, the index has already been dropped. */
11477  /* Don't call rem_class_from_index twice in the same index */
11478  SM_CLASS_CONSTRAINT *other_con;
11479  for (other_con = con->next; other_con != NULL; other_con = other_con->next)
11480  {
11481  if (BTID_IS_EQUAL (&con->index_btid, &other_con->index_btid))
11482  {
11483  /* Found duplicate index. */
11484  break;
11485  }
11486  }
11487  if (other_con == NULL)
11488  {
11489  /* No duplicate indexes. */
11490  error = rem_class_from_index (WS_OID (classop), &con->index_btid, sm_ch_heap ((MOBJ) class_));
11491  if (error != NO_ERROR)
11492  {
11493  goto end;
11494  }
11495  }
11496  }
11497  }
11498 
11499  BTID_SET_NULL (&con->index_btid);
11500  }
11501  }
11502  }
11503 
11504  /* Filter out any constraints that don't have associated attributes, this is normally only the case for old
11505  * constraints whose attributes have been deleted. */
11506  for (con = flat_constraints, prev = NULL, next = NULL; con != NULL; con = next)
11507  {
11508  next = con->next;
11509  if (con->attributes[0] != NULL
11510  && sm_filter_index_pred_have_invalid_attrs (con, (char *) sm_ch_name ((MOBJ) class_), class_->attributes,
11511  flat->instance_attributes) == false)
11512  {
11513  prev = con;
11514  }
11515  else
11516  {
11517  if (prev == NULL)
11518  {
11519  flat_constraints = con->next;
11520  }
11521  else
11522  {
11523  prev->next = con->next;
11524  }
11525 
11526  con->next = NULL;
11527  if (!BTID_IS_NULL (&con->index_btid))
11528  {
11529  if (con->type == SM_CONSTRAINT_FOREIGN_KEY)
11530  {
11531  error = drop_foreign_key_ref (classop, class_, flat_constraints, &con);
11532  if (error != NO_ERROR)
11533  {
11534  goto end;
11535  }
11536  }
11537 
11538  error = deallocate_index (class_->constraints, &con->index_btid);
11539  if (error != NO_ERROR)
11540  {
11541  goto end;
11542  }
11543  BTID_SET_NULL (&con->index_btid);
11544  }
11546  }
11547  }
11548 
11549  /* Loop over each new constraint, if we find any without indexes, this must be inherited, go get the real index from
11550  * the super class. If this is local constraint without an allocated index, we could allocate one here rather than
11551  * maintaining separate logic in allocate_disk_structures! Think about this. UNIQUE constraints are inheritable but
11552  * INDEX'es are not. */
11553  error = sm_is_partitioned_class (classop);
11554  if (error < 0)
11555  {
11556  goto end;
11557  }
11558  is_partitioned = (error ? true : false);
11559  error = NO_ERROR;
11560  for (con = flat_constraints; ((con != NULL) && (error == NO_ERROR)); con = con->next)
11561  {
11562  is_global_index = 0;
11563  error = sm_is_global_only_constraint (classop, con, &is_global_index, flat);
11564  if (SM_IS_CONSTRAINT_UNIQUE_FAMILY (con->type) && is_global_index == 1 && BTID_IS_NULL (&(con->index_btid)))
11565  {
11566  error = inherit_constraint (classop, con);
11567  }
11568  }
11569 
11570  /* rebuild the unique property list entry based on the modified constraint list */
11571  if (flat != NULL)
11572  {
11579 
11580  num_pk = 0;
11581  for (con = flat_constraints; ((con != NULL) && (error == NO_ERROR)); con = con->next)
11582  {
11583  if (SM_IS_CONSTRAINT_UNIQUE_FAMILY (con->type) || con->type == SM_CONSTRAINT_FOREIGN_KEY)
11584  {
11585  if (con->type == SM_CONSTRAINT_PRIMARY_KEY)
11586  {
11587  /* Do not count the primary key from parent when rename primary key for partition class NOTE:
11588  * BTID_IS_NULL is used to make sure the btid must be NULL for (local indexed) PK of a partition
11589  * table. See flatten_properties for details */
11590  if (num_pk != 0 && (!is_partitioned || !BTID_IS_NULL (&con->index_btid)))
11591  {
11592  error = ER_SM_PRIMARY_KEY_EXISTS;
11593  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 2, sm_ch_name ((MOBJ) class_), con->name);
11594  break;
11595  }
11596  ++num_pk;
11597  }
11598 
11599  error =
11600  classobj_put_index (&(flat->properties), con->type, con->name, con->attributes, con->asc_desc,
11601  con->attrs_prefix_length, &(con->index_btid), con->filter_predicate,
11602  con->fk_info, con->shared_cons_name, con->func_index_info, con->comment,
11603  con->index_status, false);
11604  if (error != NO_ERROR)
11605  {
11606  error = ER_SM_INVALID_PROPERTY;
11607  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 0);
11608  }
11609  }
11610  else if (con->type == SM_CONSTRAINT_INDEX || con->type == SM_CONSTRAINT_REVERSE_INDEX)
11611  {
11612  error =
11613  classobj_put_index (&(flat->properties), con->type, con->name, con->attributes, con->asc_desc,
11614  con->attrs_prefix_length, &(con->index_btid), con->filter_predicate, NULL, NULL,
11615  con->func_index_info, con->comment, con->index_status, false);
11616  if (error != NO_ERROR)
11617  {
11618  error = ER_SM_INVALID_PROPERTY;
11619  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 0);
11620  }
11621  }
11622  }
11623  }
11624 
11625  if (is_partitioned && flat != NULL && flat->partition == NULL)
11626  {
11627  /* this class is not partitioned anymore, clear the partitioning key flag from the attribute */
11628  for (attr = flat->instance_attributes; attr != NULL; attr = (SM_ATTRIBUTE *) attr->header.next)
11629  {
11630  attr->flags &= ~(SM_ATTFLAG_PARTITION_KEY);
11631  }
11632  }
11633 end:
11634  /* This was used only for convenience here, be sure to free it. Eventually, we'll just maintain these directly on the
11635  * template. */
11636  if (flat_constraints != NULL)
11637  {
11638  classobj_free_class_constraints (flat_constraints);
11639  }
11640  return error;
11641 }
11642 
11643 /*
11644  * save_previous_value() - Transfer the value in the old attribute definition
11645  * to the new attribute definition.
11646  * Work function for check_inherited_attributes.
11647  * return: none
11648  * old(in): old attribute definition
11649  * new(out): new attribute definition
11650  */
11651 
11652 static void
11654 {
11657 
11659 
11660  /* Transfer the current value to the copied definition. Note that older code copied old->value into
11661  * new->original_value, I don't think thats, right, I changed it to copy the old->original_value */
11663 
11666 }
11667 
11668 /*
11669  * check_inherited_attributes() - We maintain a separate copy of the values
11670  * for inherited class attributes and shared attributes for each class.
11671  * That is, the value of a class/shared attribute is not inherited, only the
11672  * definition. When we have finished re-flattening a class, we must
11673  * remember to use the value of the class/shared attribute that is
11674  * currently stored in the class NOT the value that came from the
11675  * inherited definitions.
11676  * return: none
11677  * classmop(in): class object
11678  * class(in): class structure
11679  * flat(in): flattened template
11680  */
11681 
11682 static void
11684 {
11685  SM_ATTRIBUTE *old, *att, *new_attr;
11686 
11687  if (flat != NULL)
11688  {
11689  for (old = class_->shared; old != NULL; old = (SM_ATTRIBUTE *) old->header.next)
11690  {
11691  new_attr = NULL;
11692  for (att = flat->attributes; att != NULL && new_attr == NULL; att = (SM_ATTRIBUTE *) att->header.next)
11693  {
11695  && SM_COMPARE_NAMES (att->header.name, old->header.name) == 0 && att->class_mop != classmop
11696  && att->class_mop == old->class_mop)
11697  {
11698  /* inherited attribute */
11699  new_attr = att;
11700  }
11701  }
11702  if (new_attr != NULL)
11703  {
11704  save_previous_value (old, new_attr);
11705  }
11706  }
11707 
11708  for (old = class_->class_attributes; old != NULL; old = (SM_ATTRIBUTE *) old->header.next)
11709  {
11710  new_attr = NULL;
11711  for (att = flat->class_attributes; att != NULL && new_attr == NULL; att = (SM_ATTRIBUTE *) att->header.next)
11712  {
11713  if (SM_COMPARE_NAMES (att->header.name, old->header.name) == 0 && att->class_mop != classmop
11714  && att->class_mop == old->class_mop)
11715  {
11716  /* inherited attribute */
11717  new_attr = att;
11718  }
11719  }
11720 
11721  if (new_attr != NULL)
11722  {
11723  save_previous_value (old, new_attr);
11724  }
11725  }
11726  }
11727 }
11728 
11729 /*
11730  * invalidate_unused_triggers() - This will invalidate any triggers that are
11731  * associated with attributes that have been deleted. This is performed
11732  * by the function tr_delete_schema_cache which frees the schema cache
11733  * but also marks the triggers contained in the cache as invalid.
11734  * Note that since a trigger can be referenced by caches throughout
11735  * the hierarchy, we only invalidate the trigger if the attribute
11736  * being removed was defined directly on this class and not inherited.
11737  * We can't invalidate triggers on inherited attributes because the
11738  * attribute may still exist in the super class. tr_delete_schema_cache
11739  * must be passed in the MOP of the current class, it will only
11740  * invalidate triggers whose target class is the same as this
11741  * class.
11742  * return: NO_ERROR on success, non-zero for ERROR
11743  * class_mop(in): class object
11744  * class(in): class structure
11745  * flat(in): flattened template
11746  */
11747 
11748 static void
11750 {
11751  SM_ATTRIBUTE *old, *new_;
11752 
11753  /* instance level attributes */
11754  for (old = class_->ordered_attributes; old != NULL; old = old->order_link)
11755  {
11756  new_ = NULL;
11757  if (flat != NULL)
11758  {
11759  for (new_ = flat->instance_attributes; new_ != NULL && new_->id != old->id;
11760  new_ = (SM_ATTRIBUTE *) new_->header.next)
11761  ;
11762  }
11763 
11764  if (new_ == NULL)
11765  {
11766  if (old->triggers != NULL)
11767  {
11768  tr_delete_schema_cache (old->triggers, class_mop);
11769  old->triggers = NULL;
11770  }
11771  }
11772  }
11773 
11774  /* class attributes */
11775  for (old = class_->class_attributes; old != NULL; old = (SM_ATTRIBUTE *) old->header.next)
11776  {
11777  new_ = NULL;
11778  if (flat != NULL)
11779  {
11780  for (new_ = flat->class_attributes; new_ != NULL && new_->id != old->id;
11781  new_ = (SM_ATTRIBUTE *) new_->header.next)
11782  ;
11783  }
11784 
11785  if (new_ == NULL)
11786  {
11787  if (old->triggers != NULL)
11788  {
11789  tr_delete_schema_cache (old->triggers, class_mop);
11790  old->triggers = NULL;
11791  }
11792  }
11793  }
11794 }
11795 
11796 /*
11797  * install_new_representation() - Final installation of a class template.
11798  * It is necessary to guarantee that this is an atomic operation and
11799  * the workspace will not change while this executes.
11800  * Garbage collection should be disabled while this happens
11801  * although we keep MOP cached in structures everywhere so it won't
11802  * make a difference.
11803  * This is essentially the "commit" operation of a schema modification,
11804  * be VERY sure you know what you're doing if you change this
11805  * code.
11806  * return: NO_ERROR on success, non-zero for ERROR
11807  * classop(in): class object
11808  * class(in): class structure
11809  * flat(out): flattened template
11810  */
11811 
11812 static int
11814 {
11815  int error = NO_ERROR;
11816  SM_ATTRIBUTE *a;
11817  SM_METHOD *m;
11818  int needrep, newrep;
11819 
11820  assert (classop != NULL);
11821 
11822  if (classop == NULL)
11823  {
11824  return ER_FAILED;
11825  }
11826 
11827  /* now that we're ready, make sure attribute/methods are stamped with the proper class mop */
11828  fixup_component_classes (classop, flat);
11829 
11830  /* go through and replace kludged "self referencing" domain with a proper domain containing the new class MOP */
11831  fixup_self_reference_domains (classop, flat);
11832 
11833  /* check for inherited class and shared attributes and make sure we maintain the current value */
11834  check_inherited_attributes (classop, class_, flat);
11835 
11836  /* assign attribute ids and check for structural representation changes */
11837  needrep = build_storage_order (class_, flat);
11838 
11839  /* assign identifiers for the shared and class attributes */
11840  for (a = flat->shared_attributes; a != NULL; a = (SM_ATTRIBUTE *) a->header.next)
11841  {
11842  assign_attribute_id (class_, a, 0);
11843  }
11844  for (a = flat->class_attributes; a != NULL; a = (SM_ATTRIBUTE *) a->header.next)
11845  {
11846  assign_attribute_id (class_, a, 1);
11847  }
11848 
11849  /* methods don't currently have ids stored persistently but go ahead and assign them anyway in the hopes that someday
11850  * they'll be stored */
11851  for (m = flat->methods; m != NULL; m = (SM_METHOD *) m->header.next)
11852  {
11853  assign_method_id (class_, m, 0);
11854  }
11855  for (m = flat->class_methods; m != NULL; m = (SM_METHOD *) m->header.next)
11856  {
11857  assign_method_id (class_, m, 1);
11858  }
11859 
11860  /* if the representation changed but there have been no objects created with the previous representation, don't
11861  * create a new one, otherwise, flush all resident instances */
11862  newrep = 0;
11863  if (needrep)
11864  {
11865  /* check for error on each of the locator functions, an error can happen if we run out of space during flushing. */
11866  if (!classop->no_objects)
11867  {
11868  switch (class_->class_type)
11869  {
11870  case SM_CLASS_CT:
11871  if (locator_flush_all_instances (classop, DECACHE) != NO_ERROR)
11872  {
11873  assert (er_errid () != NO_ERROR);
11874  return (er_errid ());
11875  }
11876  break;
11877 
11878  case SM_VCLASS_CT:
11879  if (vid_flush_all_instances (classop, true) != NO_ERROR)
11880  {
11881  assert (er_errid () != NO_ERROR);
11882  return (er_errid ());
11883  }
11884  break;
11885 
11886  default:
11887  break;
11888  }
11889 
11890  /* note that the previous operation will flush the current class representation along with the instances and
11891  * clear the dirty bit, this is unnecessary if the class was only marked dirty in preparation for the new
11892  * representation. Because the dirty bit is clear however, we must turn it back on after the new
11893  * representation is installed so it will be properly flushed, the next time a transaction commits or
11894  * locator_flush_all_instances is called */
11895  if (locator_update_class (classop) == NULL)
11896  {
11897  assert (er_errid () != NO_ERROR);
11898  return (er_errid ());
11899  }
11900 
11901  /* !!! I've seen some cases where objects are left cached while this flag is on which is illegal. Not sure
11902  * how this happens but leave this trap so we can track it down. Shouldn't be necessary */
11903  if (ws_class_has_cached_objects (classop))
11904  {
11905  ERROR0 (error, ER_SM_CORRUPTED);
11906  return error;
11907  }
11908 
11909  newrep = 1;
11910 
11911  /* Set the no_objects flag so we know that if no object dependencies are introduced on this representation,
11912  * we don't have to generate another one the next time the class is updated. */
11913 
11914  /* this used to be outside, think about why */
11915  WS_SET_NO_OBJECTS (classop);
11916  }
11917  else
11918  {
11919  newrep = 1;
11920  }
11921  }
11922 
11923  error = transfer_disk_structures (classop, class_, flat);
11924  if (error != NO_ERROR)
11925  {
11926  return error;
11927  }
11928 
11929  /* Delete the trigger caches associated with attributes that are no longer part of the class. This will also mark
11930  * the triggers as invalid since their associated attribute has gone away. */
11931  invalidate_unused_triggers (classop, class_, flat);
11932 
11933  /* clear any attribute or method descriptor caches that reference this class. */
11934  sm_reset_descriptors (classop);
11935 
11936  /* install the template, the dirty bit must be on at this point */
11937  error = classobj_install_template (class_, flat, newrep);
11938  if (error != NO_ERROR)
11939  {
11940  return error;
11941  }
11942 
11943  /* make absolutely sure this gets marked dirty after the installation, this is usually redundant but the class could
11944  * get flushed during memory panics so we always must make sure it gets flushed again */
11945  if (locator_update_class (classop) == NULL)
11946  {
11947  assert (er_errid () != NO_ERROR);
11948  return er_errid ();
11949  }
11950 
11951  /* If the representation was incremented, invalidate any existing statistics cache. The next time statistics are
11952  * requested, we'll go to the server and get them based on the new catalog information. This probably isn't necessary
11953  * in all cases but let's be safe and waste it unconditionally. */
11954  if (newrep && class_->stats != NULL)
11955  {
11956  stats_free_statistics (class_->stats);
11957  class_->stats = NULL;
11958  }
11959 
11960  /* formerly had classop->no_objects = 1 here, why ? */
11961 
11962  /* now that we don't always load methods immediately after editing, must make sure that the methods_loaded flag is
11963  * cleared so they will be loaded the next time a message is sent */
11964  class_->methods_loaded = 0;
11965 
11966  return error;
11967 }
11968 
11969 /* CLASS DEPENDENCY LOCKING */
11970 
11971 /*
11972  * lock_supers() - Get write locks on any super classes that will need to
11973  * have their subclass list updated because of changes in the inheritance
11974  * of the class being edited.
11975  * As a side effect, this constructs the "oldsupers" and "newsupers" list
11976  * by comparing the new super class list with the old definition.
11977  * These lists will be used later by update_supers.
11978  * return: NO_ERROR on success, non-zero for ERROR
11979  * def(in): schema template
11980  * current(in): list of current super classes
11981  * oldlist(out): returned list of supers being dropped
11982  * newlist(out): returned list of supers being added
11983  */
11984 
11985 static int
11986 lock_supers (SM_TEMPLATE * def, DB_OBJLIST * current, DB_OBJLIST ** oldlist, DB_OBJLIST ** newlist)
11987 {
11988  int error = NO_ERROR;
11989  DB_OBJLIST *super;
11990  SM_CLASS *class_;
11991 
11992  /* first check for removals */
11993  for (super = current; super != NULL; super = super->next)
11994  {
11995  if (def != NULL && !ml_find (def->inheritance, super->op))
11996  {
11997  /* Lock for write */
11998  error = au_fetch_class (super->op, &class_, AU_FETCH_WRITE, AU_SELECT);
11999  if (error != NO_ERROR)
12000  {
12001  ASSERT_ERROR ();
12002  return error;
12003  }
12004  error = ml_append (oldlist, super->op, NULL);
12005  if (error != NO_ERROR)
12006  {
12007  ASSERT_ERROR ();
12008  return error;
12009  }
12010  }
12011  else
12012  {
12013  /* Lock for read. We want to prevent other from writing the super. */
12014  error = au_fetch_class (super->op, &class_, AU_FETCH_READ, AU_SELECT);
12015  if (error != NO_ERROR)
12016  {
12017  ASSERT_ERROR ();
12018  return error;
12019  }
12020  }
12021  /* Recursive super locking. */
12022  if (class_->inheritance != NULL)
12023  {
12024  error = lock_supers (NULL, class_->inheritance, NULL, NULL);
12025  if (error != NO_ERROR)
12026  {
12027  ASSERT_ERROR ();
12028  return error;
12029  }
12030  }
12031  }
12032 
12033  if (def != NULL)
12034  {
12035  /* now check for new supers */
12036  for (super = def->inheritance; super != NULL; super = super->next)
12037  {
12038  if (!ml_find (current, super->op))
12039  {
12040  error = au_fetch_class (super->op, &class_, AU_FETCH_WRITE, AU_SELECT);
12041  if (error != NO_ERROR)
12042  {
12043  ASSERT_ERROR ();
12044  return error;
12045  }
12046  error = ml_append (newlist, super->op, NULL);
12047  if (error != NO_ERROR)
12048  {
12049  ASSERT_ERROR ();
12050  return error;
12051  }
12052  /* Recursive super locking. */
12053  if (class_->inheritance != NULL)
12054  {
12055  error = lock_supers (NULL, class_->inheritance, NULL, NULL);
12056  if (error != NO_ERROR)
12057  {
12058  ASSERT_ERROR ();
12059  return error;
12060  }
12061  }
12062  }
12063  }
12064  }
12065 
12066  /* Success on locking all supers. */
12067  return NO_ERROR;
12068 }
12069 
12070 /*
12071  * update_supers() - This updates the subclass list on all super classes that
12072  * were affected by a class edit. It uses the lists built by the
12073  * lock_supers function.
12074  * return: NO_ERROR on success, non-zero for ERROR
12075  * classop(in): class being edited
12076  * oldsupers(in): supers no longer connected
12077  * newsupers(out): supers being added
12078  */
12079 
12080 static int
12081 update_supers (MOP classop, DB_OBJLIST * oldsupers, DB_OBJLIST * newsupers)
12082 {
12083  int error = NO_ERROR;
12084  DB_OBJLIST *super;
12085  SM_CLASS *class_;
12086 
12087  /* removals */
12088  for (super = oldsupers; ((super != NULL) && (error == NO_ERROR)); super = super->next)
12089  {
12090  error = au_fetch_class_force (super->op, &class_, AU_FETCH_UPDATE);
12091  if (error == NO_ERROR)
12092  {
12093  ml_remove (&class_->users, classop);
12094  }
12095  }
12096 
12097  /* additions */
12098  for (super = newsupers; ((super != NULL) && (error == NO_ERROR)); super = super->next)
12099  {
12100  error = au_fetch_class_force (super->op, &class_, AU_FETCH_UPDATE);
12101  if (error == NO_ERROR)
12102  {
12103  error = ml_append (&class_->users, classop, NULL);
12104  }
12105  }
12106 
12107  return error;
12108 }
12109 
12110 /*
12111  * lock_supers_drop() - Lock the super classes in preparation for a drop
12112  * operation. All supers in the list will have to be locked.
12113  * return: NO_ERROR on success, non-zero for ERROR
12114  * supers(in): list of super classes
12115  */
12116 
12117 static int
12119 {
12120  int error = NO_ERROR;
12121  DB_OBJLIST *super;
12122  SM_CLASS *class_;
12123 
12124  for (super = supers; super != NULL; super = super->next)
12125  {
12126  error = au_fetch_class (super->op, &class_, AU_FETCH_WRITE, AU_SELECT);
12127  if (error != NO_ERROR)
12128  {
12129  ASSERT_ERROR ();
12130  return error;
12131  }
12132  /* Recursive super lock. */
12133  if (class_->inheritance != NULL)
12134  {
12135  error = lock_supers (NULL, class_->inheritance, NULL, NULL);
12136  if (error != NO_ERROR)
12137  {
12138  ASSERT_ERROR ();
12139  return error;
12140  }
12141  }
12142  }
12143 
12144  return NO_ERROR;
12145 }
12146 
12147 /*
12148  * update_supers_drop() - This updates the subclass list on super classes
12149  * after a class has been deleted.
12150  * return: NO_ERROR on success, non-zero for ERROR
12151  * classmop(in): class object being dropped
12152  * supers(in): super class list to update
12153  */
12154 
12155 static int
12156 update_supers_drop (MOP classop, DB_OBJLIST * supers)
12157 {
12158  int error = NO_ERROR;
12159  DB_OBJLIST *super;
12160  SM_CLASS *class_;
12161 
12162  for (super = supers; ((super != NULL) && (error == NO_ERROR)); super = super->next)
12163  {
12164  error = au_fetch_class_force (super->op, &class_, AU_FETCH_UPDATE);
12165  if (error == NO_ERROR)
12166  {
12167  ml_remove (&class_->users, classop);
12168  }
12169  }
12170 
12171  return error;
12172 }
12173 
12174 /*
12175  * lock_subclasses_internal()
12176  * lock_subclasses() - Recursively get write locks on all subclasses that
12177  * inherit directly or indirectly from the class being edited. Returns zero
12178  * if all classes were successfully locked.
12179  * NOTE: The order of the list produced here is very important.
12180  * We must make sure that the classes are updated BEFORE any other
12181  * classes that use them.
12182  * As a side effect, a flattened list of all effected subclasses
12183  * is build for later use by update_users.
12184  * We're also checking for cycles in the class hierarchy here.
12185  * If any of the encountered subclasses are in the immediate super class
12186  * list of the class being edited, we must abort. This is the reason
12187  * we pass in the immediate super class list.
12188  * return: NO_ERROR on success, non-zero for ERROR
12189  * def(in): schema template
12190  * op(in): MOP of class being edited
12191  * newsupers(in): new super class list
12192  * newsubs(out): retured list of flattened subclasses
12193  */
12194 static int
12195 lock_subclasses_internal (SM_TEMPLATE * def, MOP op, DB_OBJLIST * newsupers, DB_OBJLIST ** newsubs)
12196 {
12197  int error = NO_ERROR;
12198  DB_OBJLIST *l, *found, *new_, *u;
12199  SM_CLASS *class_;
12200 
12201  if (ml_find (newsupers, op))
12202  {
12203  if (def != NULL)
12204  {
12205  ERROR2 (error, ER_SM_CYCLE_DETECTED, sm_get_ch_name (op), def->name);
12206  }
12207  else
12208  {
12209  ERROR0 (error, ER_SM_INVALID_CLASS);
12210  }
12211  }
12212  else
12213  {
12214  error = au_fetch_class_force (op, &class_, AU_FETCH_WRITE);
12215  if (error != NO_ERROR)
12216  {
12217  if (WS_IS_DELETED (op))
12218  {
12219  /* in this case, just ignore the error */
12220  error = NO_ERROR;
12221  }
12222  }
12223  else
12224  {
12225  /* dive to the bottom */
12226  for (u = class_->users; ((u != NULL) && (error == NO_ERROR)); u = u->next)
12227  {
12228  error = lock_subclasses_internal (def, u->op, newsupers, newsubs);
12229  }
12230 
12231  if (error == NO_ERROR)
12232  {
12233  /* push the class on the list */
12234  for (l = *newsubs, found = NULL; l != NULL && found == NULL; l = l->next)
12235  {
12236  if (l->op == op)
12237  {
12238  found = l;
12239  }
12240  }
12241 
12242  if (found == NULL)
12243  {
12244  new_ = (DB_OBJLIST *) db_ws_alloc (sizeof (DB_OBJLIST));
12245  if (new_ == NULL)
12246  {
12247  assert (er_errid () != NO_ERROR);
12248  return er_errid ();
12249  }
12250  new_->op = op;
12251  new_->next = *newsubs;
12252  *newsubs = new_;
12253  }
12254  }
12255  }
12256  }
12257 
12258  return error;
12259 }
12260 
12261 static int
12262 lock_subclasses (SM_TEMPLATE * def, DB_OBJLIST * newsupers, DB_OBJLIST * cursubs, DB_OBJLIST ** newsubs)
12263 {
12264  int error = NO_ERROR;
12265  DB_OBJLIST *sub;
12266 
12267  for (sub = cursubs; ((sub != NULL) && (error == NO_ERROR)); sub = sub->next)
12268  {
12269  error = lock_subclasses_internal (def, sub->op, newsupers, newsubs);
12270  }
12271 
12272  return error;
12273 }
12274 
12275 /*
12276  * sm_check_catalog_rep_dir () - Checks class representations directory
12277  * return: NO_ERROR on success, non-zero for ERROR
12278  * classmop(in): class pointer
12279  * class_(in/out): class structure, set ch_rep_dir
12280  * return: NO_ERROR on success, non-zero for ERROR
12281  */
12282 
12283 int
12285 {
12286  OID rep_dir;
12287  int error = NO_ERROR;
12288  int status;
12289 
12290  /* if the OID is temporary, then we haven't flushed the class yet and it isn't necessary to check since there will be
12291  * no existing entries in the catalog */
12292 
12293  if (!OID_ISTEMP (WS_OID (classmop)))
12294  {
12295  /* if the oid is permanent, we still may not have flushed the class because the OID could have been assigned
12296  * during the transformation of another object that referenced this class. In this case, the catalog manager will
12297  * return ER_HEAP_NODATA_NEWADDRESS because it will have no entries for this class oid. */
12298 
12299  status = catalog_check_rep_dir (WS_OID (classmop), &rep_dir);
12300 
12301  assert (er_errid () != ER_HEAP_NODATA_NEWADDRESS); /* TODO - */
12302 
12303  if (status != NO_ERROR)
12304  {
12305  assert (er_errid () != NO_ERROR);
12306  error = er_errid ();
12307  /* ignore if the class hasn't been flushed yet */
12308  if (error == ER_HEAP_NODATA_NEWADDRESS)
12309  {
12310  error = NO_ERROR;
12311  }
12312  }
12313  else
12314  {
12315  assert (!OID_ISNULL (&rep_dir));
12316  assert (OID_ISNULL (&(class_->header.ch_rep_dir)) || OID_EQ (&(class_->header.ch_rep_dir), &rep_dir));
12317 
12318  if (!OID_ISNULL (&rep_dir))
12319  {
12320  /* save server-side representation directory oid */
12321  COPY_OID (&(class_->header.ch_rep_dir), &rep_dir);
12322  }
12323  }
12324  }
12325 
12326  return error;
12327 }
12328 
12329 /*
12330  * flatten_subclasses() - Construct a flattened template for every subclass
12331  * affected by a class edit (or deletion). If flattening fails for any
12332  * of the subclasses, the entire class edit must be aborted.
12333  * return: NO_ERROR on success, non-zero for ERROR
12334  * subclasses(in): list of subclasses needing flattening
12335  * deleted_class(in): MOP of delete_class (if any, can be NULL)
12336  */
12337 
12338 static int
12339 flatten_subclasses (DB_OBJLIST * subclasses, MOP deleted_class)
12340 {
12341  int error = NO_ERROR;
12342  DB_OBJLIST *sub;
12343  SM_CLASS *class_;
12344  SM_TEMPLATE *utemplate, *flat;
12345 
12346  for (sub = subclasses; ((sub != NULL) && (error == NO_ERROR)); sub = sub->next)
12347  {
12348  error = au_fetch_class_force (sub->op, &class_, AU_FETCH_UPDATE);
12349  if (error == NO_ERROR)
12350  {
12351  /* make sure the run-time stuff is cached before editing, this is particularly important for the method file
12352  * source class kludge */
12353  error = sm_clean_class (sub->op, class_);
12354  if (error == NO_ERROR)
12355  {
12356  /* create a template */
12357  utemplate = classobj_make_template (sm_ch_name ((MOBJ) class_), sub->op, class_);
12358  if (utemplate == NULL)
12359  {
12360  assert (er_errid () != NO_ERROR);
12361  error = er_errid ();
12362  }
12363  else
12364  {
12365  /* reflatten it without any local changes (will inherit changes) */
12366  error = flatten_template (utemplate, deleted_class, &flat, 1);
12367  if (error == NO_ERROR)
12368  {
12369  class_->new_ = flat;
12370  }
12371 
12372  /* free the definition template */
12373  classobj_free_template (utemplate);
12374  }
12375  }
12376  }
12377  }
12378 
12379  return error;
12380 }
12381 
12382 /*
12383  * abort_subclasses() - If subclass flattening failed for some reason, must go
12384  * through the list and free the temporary templates for those subclasses
12385  * that were sucessfully flattened.
12386  * return: none
12387  * subclasses(in): subclass list
12388  */
12389 
12390 static void
12392 {
12393  DB_OBJLIST *sub;
12394  SM_CLASS *class_;
12395 
12396  /* don't stop the loop if we get fetch errors, we're just trying to clean up the templates that are attached to the
12397  * classes here. */
12398  for (sub = subclasses; sub != NULL; sub = sub->next)
12399  {
12400  if (au_fetch_class_force (sub->op, &class_, AU_FETCH_WRITE) == NO_ERROR)
12401  {
12402  if (class_->new_ != NULL)
12403  {
12404  classobj_free_template (class_->new_);
12405  class_->new_ = NULL;
12406  }
12407  }
12408  }
12409 }
12410 
12411 static bool
12413 {
12414  if (con->attributes[0] == NULL)
12415  {
12416  assert (false);
12417  return true;
12418  }
12419  if (con->attributes[0]->class_mop == mop)
12420  {
12421  return true;
12422  }
12423  return false;
12424 }
12425 
12426 /*
12427  * update_subclasses() - At this point, all subclasses have been successfully
12428  * flattened and it is ok to install new representations for each.
12429  * return: NO_ERROR on success, non-zero for ERROR
12430  * subclasses(in): list of subclasses
12431  *
12432  * NOTE:
12433  * update constraints
12434  * update_subclasses():
12435  * SM_CONSTRAINT_UNIQUE,
12436  * SM_CONSTRAINT_REVERSE_UNIQUE,
12437  * SM_CONSTRAINT_PRIMARY_KEY,
12438  * SM_CONSTRAINT_FOREIGN_KEY
12439  * SM_CONSTRAINT_INDEX,
12440  * SM_CONSTRAINT_REVERSE_INDEX,
12441  * sm_drop_index():
12442  * SM_CONSTRAINT_INDEX,
12443  * SM_CONSTRAINT_REVERSE_INDEX,
12444  */
12445 
12446 static int
12448 {
12449  int error = NO_ERROR;
12450  int num_indexes;
12451  DB_OBJLIST *sub;
12452  SM_CLASS *class_;
12453 
12454  for (sub = subclasses; sub != NULL && error == NO_ERROR; sub = sub->next)
12455  {
12456  if (au_fetch_class_force (sub->op, &class_, AU_FETCH_UPDATE) == NO_ERROR)
12457  {
12458  if (class_->new_ == NULL)
12459  {
12460  ERROR0 (error, ER_SM_CORRUPTED);
12461  }
12462  else
12463  {
12464  error = install_new_representation (sub->op, class_, class_->new_);
12465  if (error == NO_ERROR)
12466  {
12467  /*
12468  * currently, install_new_representation, allocate_disk_structures
12469  * both increment repr_id.
12470  * NEED MORE CONSIDERATION
12471  * someday later, consider the following:
12472  * modify install_new_representation and
12473  * remove allocated_disk_structures
12474  */
12475  num_indexes = allocate_disk_structures (sub->op, class_, NULL, NULL);
12476  if (num_indexes < 0)
12477  {
12478  /* an error has happened */
12479  error = num_indexes;
12480  }
12481  else if (!class_->dont_decache_constraints_or_flush && class_->class_type == SM_CLASS_CT)
12482  {
12484  }
12485 
12486  classobj_free_template (class_->new_);
12487  class_->new_ = NULL;
12488 
12489  if (error != NO_ERROR)
12490  {
12491  return error;
12492  }
12493  }
12494  }
12495  }
12496  }
12497 
12498  return error;
12499 }
12500 
12501 /*
12502  * lockhint_subclasses() - This is called early during the processing of
12503  * sm_update_class. It will use the new subclass lattice locking function
12504  * to try to get all the locks we need before we proceed. This will
12505  * be better for deadlock avoidance.
12506  * This is done as a "hint" only, if we don't lock everything,
12507  * we'll hit them again later and suspend.
12508  * return: NO_ERROR on success, non-zero for ERROR
12509  * temp(in):
12510  * class(in): class structure
12511  */
12512 
12513 static int
12515 {
12516  int error = NO_ERROR;
12517  const char *names[1];
12518  LOCK locks[1];
12519  int subs[1];
12520  LC_PREFETCH_FLAGS flags[1];
12521 
12522  if (class_ != NULL)
12523  {
12524  names[0] = sm_ch_name ((MOBJ) class_);
12526  subs[0] = 1;
12527  flags[0] = LC_PREF_FLAG_LOCK;
12528  if (locator_lockhint_classes (1, names, locks, subs, flags, 1, NULL_LOCK) == LC_CLASSNAME_ERROR)
12529  {
12530  assert (er_errid () != NO_ERROR);
12531  error = er_errid ();
12532  }
12533  }
12534  else if (temp != NULL)
12535  {
12536  names[0] = temp->name;
12538  subs[0] = 1;
12539  flags[0] = LC_PREF_FLAG_LOCK;
12540  if (locator_lockhint_classes (1, names, locks, subs, flags, 1, NULL_LOCK) == LC_CLASSNAME_ERROR)
12541  {
12542  assert (er_errid () != NO_ERROR);
12543  error = er_errid ();
12544  }
12545  }
12546 
12547  return error;
12548 }
12549 
12550 /*
12551  * update_class() - Apply a schema template for a new or existing class.
12552  * If there is an error in the local class or any affected subclass
12553  * because of a change in the template, none of the changes in the
12554  * template will be applied.
12555  * Even if there were no errors detected during the building of the
12556  * template, there still may be some outstanding errors detected
12557  * during actual flattening that will cause application of the template
12558  * to fail.
12559  * Locking affected superclasses and subclasses has also been deferred
12560  * till now so if locks cannot be obtained, the template cannot be
12561  * applied.
12562  * If the returned error status is zero, the template application
12563  * was successful and the template was freed and can no longer be used.
12564  * If the returned error status indicates a problem locking an affected
12565  * object, you either abort the template or wait and try again later.
12566  * If there is another error in the template, you can either abort
12567  * the template or alter the template and try again.
12568  * return: NO_ERROR on success, non-zero for ERROR
12569  * template(in): schema template
12570  * classmop(in): MOP of existing class (NULL if new class)
12571  * auto_res(in): non-zero to enable auto-resolution of conflicts
12572  * auth(in): the given authorization mode to modify class
12573  * needs_hierarchy_lock(in): lock sub/super classes?
12574  */
12575 
12576 /* NOTE: There were some problems when the transaction was unilaterally
12577  * aborted in the middle of a schema change operation. What happens is
12578  * that during flattening, each class structure is given a pointer to
12579  * the flattened template. If the transaction is aborted, all of the
12580  * dirty objects in the workspace would be flushed. classobj_free_class()
12581  * would always free an associated template if one was present. When
12582  * that happened, we would get back from some function, find and error,
12583  * but not realize that our template had been freed out from under us.
12584  *
12585  * The simplest solution to this problem is to prevent classobj_free_class()
12586  * from freeing templates. This is ok in the normal case but in the
12587  * event of a unilateral abort, we may end up with some memory leaks as
12588  * the templates that had been attached to the classes will be lost.
12589  *
12590  * Fixing this to avoid this leak will be complicated and the likelihood
12591  * of this problem is very remote.
12592  */
12593 
12594 static int
12595 update_class (SM_TEMPLATE * template_, MOP * classmop, int auto_res, DB_AUTH auth, bool needs_hierarchy_lock)
12596 {
12597  int error = NO_ERROR;
12598  int num_indexes;
12599  SM_CLASS *class_;
12600  DB_OBJLIST *cursupers, *oldsupers, *newsupers, *cursubs, *newsubs;
12601  SM_TEMPLATE *flat;
12602 
12604  class_ = NULL;
12605  cursupers = NULL;
12606  oldsupers = NULL;
12607  newsupers = NULL;
12608  cursubs = NULL;
12609  newsubs = NULL;
12610 
12611  assert (template_ != NULL);
12612 
12613  /*
12614  * Set a savepoint in the event that we are adding a unique constraint
12615  * to a class with instances and the constraint is violated. In this
12616  * situation, we do not want to abort the entire transaction.
12617  */
12619 
12620  if ((error == NO_ERROR) && (template_->op != NULL))
12621  {
12622  /* existing class, fetch it */
12623  error = au_fetch_class (template_->op, &class_, AU_FETCH_UPDATE, auth);
12624  }
12625 
12626  if (error != NO_ERROR)
12627  {
12628  goto end;
12629  }
12630 
12631  if (needs_hierarchy_lock)
12632  {
12633  /* pre-lock subclass lattice to the extent possible */
12634  error = lockhint_subclasses (template_, class_);
12635  if (error != NO_ERROR)
12636  {
12637  goto end;
12638  }
12639 
12640  /* get write locks on all super classes */
12641  if (class_ != NULL)
12642  {
12643  cursupers = class_->inheritance;
12644  }
12645 
12646  error = lock_supers (template_, cursupers, &oldsupers, &newsupers);
12647  if (error != NO_ERROR)
12648  {
12649  goto end;
12650  }
12651  }
12652 
12653  /* flatten template, store the pending template in the "new" field of the class in case we need it to make domain
12654  * comparisons */
12655  if (class_ != NULL)
12656  {
12657  class_->new_ = template_;
12658  }
12659 
12660  error = flatten_template (template_, NULL, &flat, auto_res);
12661  if (error != NO_ERROR)
12662  {
12663  /* If we aborted the operation (error == ER_LK_UNILATERALLY_ABORTED) then the class may no longer be in the
12664  * workspace. So make sure that the class exists before using it. */
12665  if (class_ != NULL && error != ER_LK_UNILATERALLY_ABORTED)
12666  {
12667  class_->new_ = NULL;
12668  }
12669 
12670  goto end;
12671  }
12672 
12673  if (needs_hierarchy_lock)
12674  {
12675  /* get write locks on all subclasses */
12676  if (class_ != NULL)
12677  {
12678  cursubs = class_->users;
12679  }
12680 
12681  error = lock_subclasses (template_, newsupers, cursubs, &newsubs);
12682  if (error != NO_ERROR)
12683  {
12684  classobj_free_template (flat);
12685  /* don't touch this class if we aborted ! */
12686  if (class_ != NULL && error != ER_LK_UNILATERALLY_ABORTED)
12687  {
12688  class_->new_ = NULL;
12689  }
12690 
12691  goto end;
12692  }
12693  }
12694 
12695  /* put the flattened definition in the class for use during subclass flattening */
12696  if (class_ != NULL)
12697  {
12698  class_->new_ = flat;
12699  }
12700 
12701  /* flatten all subclasses */
12702  error = flatten_subclasses (newsubs, NULL);
12703  if (error != NO_ERROR)
12704  {
12705  abort_subclasses (newsubs);
12706  classobj_free_template (flat);
12707 
12708  /* don't touch this class if we aborted ! */
12709  if (class_ != NULL && error != ER_LK_UNILATERALLY_ABORTED)
12710  {
12711  class_->new_ = NULL;
12712  }
12713 
12714  goto end;
12715  }
12716 
12717  /* now we can assume that every class we need to touch has a write lock - proceed with the installation of the
12718  * changes */
12719 
12720  /* are we creating a new class ? */
12721  if (class_ == NULL)
12722  {
12723  class_ = classobj_make_class (template_->name);
12724  if (class_ == NULL)
12725  {
12726  assert (er_errid () != NO_ERROR);
12727  error = er_errid ();
12728  if (error == NO_ERROR)
12729  {
12730  error = ER_FAILED;
12731  }
12732  }
12733  else
12734  {
12735  /* making object relation is not complete, so cannot use sm_is_partition(), sm_partitioned_class_type() */
12736  if (template_->inheritance != NULL && template_->partition_parent_atts != NULL)
12737  {
12738  SM_CLASS *super_class = NULL;
12739  int au_save;
12740  AU_DISABLE (au_save);
12741  error = au_fetch_class (template_->inheritance->op, &super_class, AU_FETCH_READ, AU_SELECT);
12742  AU_ENABLE (au_save);
12743 
12744  if (error != NO_ERROR)
12745  {
12746  abort_subclasses (newsubs);
12747  classobj_free_template (flat);
12748  classobj_free_class (class_);
12749  goto end;
12750  }
12751  class_->owner = super_class->owner;
12752  }
12753  else
12754  {
12755  class_->owner = Au_user; /* remember the owner id */
12756  }
12757 
12758  /* NOTE: Garbage collection can occur in the following function as a result of the allocation of the class
12759  * MOP. We must ensure that there are no object handles in the SM_CLASS structure at this point that don't
12760  * have roots elsewhere. Currently, this is the case since we are simply caching a newly created empty class
12761  * structure which will later be populated with install_new_representation. The template that holds the new
12762  * class contents IS already a GC root. */
12763  template_->op = locator_add_class ((MOBJ) class_, (char *) sm_ch_name ((MOBJ) class_));
12764  if (template_->op == NULL)
12765  {
12766  /* return locator error code */
12767  assert (er_errid () != NO_ERROR);
12768  error = er_errid ();
12769  abort_subclasses (newsubs);
12770  classobj_free_template (flat);
12771  classobj_free_class (class_);
12772  }
12773  }
12774  }
12775 
12776  if (error != NO_ERROR || class_ == NULL)
12777  {
12778  goto end;
12779  }
12780 
12781  /* the next sequence of operations is extremely critical, if any errors are detected, we'll have to abort the current
12782  * transaction or the database will be left in an inconsistent state. */
12783 
12784  flat->partition_parent_atts = template_->partition_parent_atts;
12785  error = install_new_representation (template_->op, class_, flat);
12786  if (error != NO_ERROR)
12787  {
12788  goto error_return;
12789  }
12790 
12791  /* This used to be done toward the end but since the unique btid has to be inherited, the disk structures have to be
12792  * created before we update the subclasses. We also have to disable updating statistics for now because we haven't
12793  * finshed modifying the all the classes yet and the code which updates statistics on partitioned classes does not
12794  * work if partitions and the partitioned class have different schema. */
12795 
12796  num_indexes = allocate_disk_structures (template_->op, class_, newsubs, template_);
12797  if (num_indexes < 0)
12798  {
12799  error = num_indexes;
12800  goto error_return;
12801  }
12802 
12803  error = update_supers (template_->op, oldsupers, newsupers);
12804  if (error != NO_ERROR)
12805  {
12806  goto error_return;
12807  }
12808 
12809  error = update_subclasses (newsubs);
12810  if (error != NO_ERROR)
12811  {
12812  goto error_return;
12813  }
12814 
12815  /* we're done */
12816  if (classmop != NULL)
12817  {
12818  *classmop = template_->op;
12819  }
12820  class_->new_ = NULL;
12821 
12822  /* All objects are updated, now we can update class statistics also. */
12823  if (template_->class_type == SM_CLASS_CT)
12824  {
12825  error = sm_update_statistics (template_->op, STATS_WITH_SAMPLING);
12826  if (error != NO_ERROR)
12827  {
12828  goto error_return;
12829  }
12830  }
12831 
12832  classobj_free_template (flat);
12833  classobj_free_template (template_);
12834 
12835 end:
12836  ml_free (oldsupers);
12837  ml_free (newsupers);
12838  ml_free (newsubs);
12839 
12840  return error;
12841 
12842 error_return:
12843 
12844  assert (error != ER_HEAP_NODATA_NEWADDRESS); /* TODO - */
12845 
12846  classobj_free_template (flat);
12847  abort_subclasses (newsubs);
12848 
12850  {
12852  }
12853 
12854  goto end;
12855 }
12856 
12857 /*
12858  * sm_finish_class() - this is called to finish a dbt template,
12859  * don't perform auto resolutions
12860  * return: NO_ERROR on success, non-zero for ERROR
12861  * template(in): schema template
12862  * classmop(in): MOP of existing class (NULL if new class)
12863  */
12864 
12865 int
12866 sm_finish_class (SM_TEMPLATE * template_, MOP * classmop)
12867 {
12868  return update_class (template_, classmop, 0, AU_ALTER, true);
12869 }
12870 
12871 /*
12872  * sm_update_class() - this is what the interpreter calls,
12873  * don't perform auto resolutions
12874  * return: NO_ERROR on success, non-zero for ERROR
12875  * template(in): schema template
12876  * classmop(in): MOP of existing class (NULL if new class)
12877  */
12878 
12879 int
12880 sm_update_class (SM_TEMPLATE * template_, MOP * classmop)
12881 {
12882  return update_class (template_, classmop, 0, AU_ALTER, true);
12883 }
12884 
12885 int
12886 sm_update_class_with_auth (SM_TEMPLATE * template_, MOP * classmop, DB_AUTH auth, bool needs_hierarchy_lock)
12887 {
12888  return update_class (template_, classmop, 0, auth, needs_hierarchy_lock);
12889 }
12890 
12891 /*
12892  * sm_update_class_auto() - this is called by the db_ layer,
12893  * perform auto resolution
12894  * return: NO_ERROR on success, non-zero for ERROR
12895  * template(in): schema template
12896  * classmop(in): MOP of existing class (NULL if new class)
12897  */
12898 
12899 int
12900 sm_update_class_auto (SM_TEMPLATE * template_, MOP * classmop)
12901 {
12902  return update_class (template_, classmop, 1, AU_ALTER, true);
12903 }
12904 
12905 /*
12906  * remove_class_triggers() - Work function for sm_delete_class_mop.
12907  * Inform the trigger manager that the class is going away so
12908  * it can update the triggers defined for this class.
12909  * Need a better strategy for handling errors here.
12910  * return: error code
12911  * classop(in):
12912  * class(in): class structure
12913  */
12914 
12915 static int
12917 {
12918  SM_ATTRIBUTE *att;
12919  int error = NO_ERROR;
12920 
12921  /* use tr_delete triggers_for_class() instead of tr_delete_schema_cache so that we physically delete the triggers. */
12922  for (att = class_->ordered_attributes; att != NULL; att = att->order_link)
12923  {
12924  error = tr_delete_triggers_for_class (&att->triggers, classop);
12925  if (error != NO_ERROR)
12926  {
12927  return error;
12928  }
12929  att->triggers = NULL;
12930  }
12931 
12932  for (att = class_->class_attributes; att != NULL; att = (SM_ATTRIBUTE *) att->header.next)
12933  {
12934  error = tr_delete_triggers_for_class (&att->triggers, classop);
12935  if (error != NO_ERROR)
12936  {
12937  return error;
12938  }
12939  att->triggers = NULL;
12940  }
12941 
12942  error = tr_delete_triggers_for_class (&class_->triggers, classop);
12943  if (error != NO_ERROR)
12944  {
12945  return error;
12946  }
12947  class_->triggers = NULL;
12948  return NO_ERROR;
12949 }
12950 
12951 /*
12952  * drop_cascade_foreign_key() - if table include PK, drop the relative
12953  * foreign key constraint.
12954  * return : error code
12955  * class_(in): class structure
12956  */
12957 static int
12959 {
12960  int error = NO_ERROR;
12961  SM_CLASS_CONSTRAINT *pk;
12962  MOP fk_class_mop;
12963  SM_TEMPLATE *template_;
12964 
12965  assert (class_ != NULL);
12966 
12968  while (pk != NULL && pk->fk_info != NULL)
12969  {
12970  fk_class_mop = ws_mop (&pk->fk_info->self_oid, sm_Root_class_mop);
12971  if (fk_class_mop == NULL)
12972  {
12973  assert (er_errid () != NO_ERROR);
12974  error = er_errid ();
12975  goto end;
12976  }
12977 
12978  template_ = dbt_edit_class (fk_class_mop);
12979  if (template_ == NULL)
12980  {
12981  assert (er_errid () != NO_ERROR);
12982  error = er_errid ();
12983  goto end;
12984  }
12985 
12986  error = dbt_drop_constraint (template_, DB_CONSTRAINT_FOREIGN_KEY, pk->fk_info->name, NULL, 0);
12987  if (error != NO_ERROR)
12988  {
12989  dbt_abort_class (template_);
12990  goto end;
12991  }
12992 
12993  if (dbt_finish_class (template_) == NULL)
12994  {
12995  dbt_abort_class (template_);
12996  assert (er_errid () != NO_ERROR);
12997  error = er_errid ();
12998  goto end;
12999  }
13000 
13002  }
13003 
13004 end:
13005  return error;
13006 }
13007 
13008 /*
13009  * sm_delete_class() - This will delete a class from the schema and
13010  * delete all instances of the class from the database. All classes that
13011  * inherit from this class will be updated so that inherited components
13012  * are removed.
13013  * return: NO_ERROR on success, non-zero for ERROR
13014  * op(in): class object
13015  * is_cascade_constraints(in): whether drop relative FK constrants
13016  */
13017 
13018 int
13019 sm_delete_class_mop (MOP op, bool is_cascade_constraints)
13020 {
13021  int error = NO_ERROR, is_class = 0;
13022  DB_OBJLIST *oldsupers, *oldsubs;
13023  SM_CLASS *class_;
13024  SM_TEMPLATE *template_;
13025  SM_ATTRIBUTE *att;
13026  int is_partition = 0, subdel = 0;
13027  SM_CLASS_CONSTRAINT *pk;
13028  char *fk_name = NULL;
13029  const char *table_name;
13030 
13031  if (op == NULL)
13032  {
13033  assert (false);
13034  return ER_FAILED;
13035  }
13036 
13037  error = sm_partitioned_class_type (op, &is_partition, NULL, NULL);
13038  if (error != NO_ERROR)
13039  {
13040  return error;
13041  }
13042 
13043  if (is_partition == DB_PARTITIONED_CLASS)
13044  {
13046  if (error != NO_ERROR)
13047  {
13048  return error;
13049  }
13050 
13051  error = do_drop_partitioned_class (op, 1, is_cascade_constraints);
13052  if (error != NO_ERROR)
13053  {
13054  if (error != ER_LK_UNILATERALLY_ABORTED)
13055  {
13057  }
13058  return error;
13059  }
13060  subdel = 1;
13061  }
13062 
13063  oldsubs = NULL;
13064  oldsupers = NULL;
13065 
13066  /* if the delete fails, we'll need to rollback to savepoint */
13068  if (error != NO_ERROR)
13069  {
13070  if (subdel == 1 && error != ER_TM_SERVER_DOWN_UNILATERALLY_ABORTED && error != ER_LK_UNILATERALLY_ABORTED)
13071  {
13073  }
13074  return error;
13075  }
13076 
13078 
13079  /* op should be a class */
13080  is_class = locator_is_class (op, DB_FETCH_WRITE);
13081  if (is_class < 0)
13082  {
13083  error = is_class;
13084  goto end;
13085  }
13086  if (!is_class)
13087  {
13088  ERROR0 (error, ER_OBJ_NOT_A_CLASS);
13089 
13090  goto end;
13091  }
13092 
13093  /* Authorization + pre-lock subclass lattice to the extent possible */
13094  error = au_fetch_class (op, &class_, AU_FETCH_WRITE, AU_ALTER);
13095  if (error != NO_ERROR)
13096  {
13097  goto end;
13098  }
13099 
13100  table_name = sm_get_ch_name (op);
13101  if (table_name == NULL)
13102  {
13103  goto end;
13104  }
13105 
13106  error = lockhint_subclasses (NULL, class_);
13107  if (error != NO_ERROR)
13108  {
13109  goto end;
13110  }
13111 
13113  if (pk && pk->fk_info && classobj_is_pk_referred (op, pk->fk_info, false, &fk_name))
13114  {
13115  if (is_cascade_constraints)
13116  {
13117  error = sm_drop_cascade_foreign_key (class_);
13118  if (error != NO_ERROR)
13119  {
13120  goto end;
13121  }
13122  }
13123  else
13124  {
13125  ERROR2 (error, ER_FK_CANT_DROP_PK_REFERRED, pk->name, fk_name);
13126  goto end;
13127  }
13128  }
13129 
13130  /* remove auto_increment serial object if exist */
13131  for (att = class_->ordered_attributes; att; att = att->order_link)
13132  {
13133  if (att->auto_increment != NULL)
13134  {
13135  DB_VALUE name_val;
13136  const char *class_name;
13137 
13138  error = db_get (att->auto_increment, "class_name", &name_val);
13139  if (error == NO_ERROR)
13140  {
13141  class_name = db_get_string (&name_val);
13142  if (class_name != NULL && (strcmp (sm_ch_name ((MOBJ) class_), class_name) == 0))
13143  {
13144  int save;
13145  OID *oidp, serial_obj_id;
13146 
13147  oidp = ws_identifier (att->auto_increment);
13148  COPY_OID (&serial_obj_id, oidp);
13149 
13150  AU_DISABLE (save);
13151  error = obj_delete (att->auto_increment);
13152  AU_ENABLE (save);
13153 
13154  if (error == NO_ERROR)
13155  {
13156  (void) serial_decache (&serial_obj_id);
13157  }
13158  }
13159  db_value_clear (&name_val);
13160  }
13161 
13162  if (error != NO_ERROR)
13163  {
13164  goto end;
13165  }
13166  }
13167  }
13168 
13169  /* we don't really need this but some of the support routines use it */
13170  template_ = classobj_make_template (NULL, op, class_);
13171  if (template_ == NULL)
13172  {
13173  assert (er_errid () != NO_ERROR);
13174  error = er_errid ();
13175  goto end;
13176  }
13177 
13178  if (class_->inheritance != NULL)
13179  {
13180  oldsupers = ml_copy (class_->inheritance);
13181  if (oldsupers == NULL)
13182  {
13183  assert (er_errid () != NO_ERROR);
13184  error = er_errid ();
13185  goto end;
13186  }
13187  }
13188 
13189  error = lock_supers_drop (oldsupers);
13190  if (error != NO_ERROR)
13191  {
13192  classobj_free_template (template_);
13193 
13194  goto end;
13195  }
13196 
13197  /* get write locks on all subclasses */
13198  error = lock_subclasses (template_, NULL, class_->users, &oldsubs);
13199  if (error != NO_ERROR)
13200  {
13201  classobj_free_template (template_);
13202 
13203  goto end;
13204  }
13205 
13206  /* now we can assume that every class we need to touch has a write lock - attempt to flatten subclasses to reflect
13207  * the deletion */
13208  error = flatten_subclasses (oldsubs, op);
13209  if (error != NO_ERROR)
13210  {
13211  abort_subclasses (oldsubs);
13212 
13213  goto end;
13214  }
13215 
13216  /* mark all instance MOPs as deleted, should the locator be doing this ? */
13218 
13219  /* flush all instances of this class */
13220  switch (class_->class_type)
13221  {
13222  case SM_CLASS_CT:
13224  {
13225  assert (er_errid () != NO_ERROR);
13226  error = er_errid ();
13227  }
13228  break;
13229 
13230  case SM_VCLASS_CT:
13231  if (vid_flush_all_instances (op, true) != NO_ERROR)
13232  {
13233  assert (er_errid () != NO_ERROR);
13234  error = er_errid ();
13235  }
13236  break;
13237 
13238  default:
13239  break;
13240  }
13241 
13242  if (error != NO_ERROR)
13243  {
13244  /* we had problems flushing, this may be due to an out of space condition, probably the transaction should be
13245  * aborted as well */
13246  abort_subclasses (oldsubs);
13247 
13248  goto end;
13249  }
13250 
13251  /* this section is critical, if any errors happen here, the workspace will be in an inconsistent state and the
13252  * transaction will have to be aborted */
13253 
13254  /* now update the supers and users */
13255  error = update_supers_drop (op, oldsupers);
13256  if (error != NO_ERROR)
13257  {
13258  goto end;
13259  }
13260  error = update_subclasses (oldsubs);
13261  if (error != NO_ERROR)
13262  {
13263  goto end;
13264  }
13265 
13266  /* OLD CODE, here we removed the class from the resident class list, this causes bad problems for GC since the class
13267  * will be GC'd before instances have been decached. This operation has been moved below with
13268  * ws_remove_resident_class(). Not sure if this is position dependent. If it doesn't cause any problems remove this
13269  * comment. */
13270  /* ml_remove(&ws_Resident_classes, op); */
13271 
13272  /* free any indexes, unique btids, or other associated disk structures */
13273  error = transfer_disk_structures (op, class_, NULL);
13274  if (error != NO_ERROR)
13275  {
13276  goto end;
13277  }
13278 
13279  /* now that the class is gone, physically delete all the triggers. Note that this does not just invalidate the
13280  * triggers, it deletes them forever. */
13281  error = remove_class_triggers (op, class_);
13282  if (error != NO_ERROR)
13283  {
13284  goto end;
13285  }
13286 
13287  /* now delete _db_auth tuples refers to the table */
13288  error = au_delete_auth_of_dropping_table (table_name);
13289  if (error != NO_ERROR)
13290  {
13291  goto end;
13292  }
13293 
13294  /* This to be maintained as long as the class is cached in the workspace, dirty or not. When the deleted class is
13295  * flushed, the name is removed. Assuming this doesn't cause problems, remove this comment */
13296  /* ws_drop_classname((MOBJ) class); */
13297 
13298  /* inform the locator - this will mark the class MOP as deleted so all operations that require the current class
13299  * object must be done before calling this function */
13300 
13301  error = locator_remove_class (op);
13302  if (error != NO_ERROR)
13303  {
13304  goto end;
13305  }
13306 
13307  /* make sure this is removed from the resident class list, this will also make the class mop subject to garbage
13308  * collection. This function will expect that all of the instances of the class have been decached by this point ! */
13309 
13311 
13312  classobj_free_template (template_);
13313 
13314 
13315 end:
13316  if (oldsupers != NULL)
13317  {
13318  ml_free (oldsupers);
13319  }
13320  if (oldsubs != NULL)
13321  {
13322  ml_free (oldsubs);
13323  }
13324 
13325  if (error != NO_ERROR && error != ER_TM_SERVER_DOWN_UNILATERALLY_ABORTED && error != ER_LK_UNILATERALLY_ABORTED)
13326  {
13327  if (subdel == 1)
13328  {
13330  }
13331  else
13332  {
13334  }
13335  }
13336 
13337  return error;
13338 }
13339 
13340 #if defined(ENABLE_UNUSED_FUNCTION)
13341 /*
13342  * sm_delete_class() - Delete a class by name.
13343  * return: NO_ERROR on success, non-zero for ERROR
13344  * name(in): class name
13345  */
13346 
13347 int
13348 sm_delete_class (const char *name)
13349 {
13350  int error = NO_ERROR;
13351  MOP classop;
13352 
13353  classop = sm_find_class (name);
13354  if (classop == NULL)
13355  {
13356  assert (er_errid () != NO_ERROR);
13357  error = er_errid ();
13358  }
13359  else
13360  {
13361  error = sm_delete_class_mop (classop, false);
13362  }
13363 
13364  return error;
13365 }
13366 #endif /* ENABLE_UNUSED_FUNCTION */
13367 
13368 /* INDEX FUNCTIONS */
13369 /*
13370  * These are in here bacause they share some of the internal
13371  * allocation/deallocation for indexes.
13372  * They also play games with the representation id so the
13373  * catalog gets updated correctly to include the new index.
13374 */
13375 /*
13376  * sm_exist_index() - Checks to see if an index exist
13377  * return: NO_ERROR on success, non-zero for ERROR
13378  * classop(in): class object
13379  * idxname(in): index name
13380  */
13381 int
13382 sm_exist_index (MOP classop, const char *idxname, BTID * btid)
13383 {
13384  int error = NO_ERROR;
13385  SM_CLASS *class_;
13386  SM_CLASS_CONSTRAINT *cons;
13387 
13388  error = au_fetch_class (classop, &class_, AU_FETCH_READ, AU_SELECT);
13389  if (error == NO_ERROR)
13390  {
13391  cons = classobj_find_class_index (class_, idxname);
13392  if (cons)
13393  {
13394  if (btid)
13395  {
13396  BTID_COPY (btid, &cons->index_btid);
13397  }
13398 
13399  return NO_ERROR;
13400  }
13401  }
13402 
13403  return ER_FAILED;
13404 }
13405 
13406 #if 0
13407 // TODO: leave it for reference. Remove it when we complete the task.
13408 /*
13409  * sm_add_index() - Adds an index to an attribute.
13410  * return: NO_ERROR on success, non-zero for ERROR
13411  * classop(in): class object
13412  * db_constraint_type(in): constraint type
13413  * constraint_name(in): Name of constraint.
13414  * attname(in): attribute name
13415  * asc_desc(in): asc/desc info list
13416  * attrs_prefix_length(in): prefix length
13417  * filter_predicate(in): expression from
13418  * CREATE INDEX idx ON tbl(col1, ...) WHERE filter_predicate
13419  * comment(in): index comment
13420  */
13421 
13422 int
13423 sm_add_index (MOP classop, DB_CONSTRAINT_TYPE db_constraint_type, const char *constraint_name, const char **attnames,
13424  const int *asc_desc, const int *attrs_prefix_length, SM_PREDICATE_INFO * filter_index,
13425  SM_FUNCTION_INFO * function_index, const char *comment)
13426 {
13427  int error = NO_ERROR;
13428  SM_CLASS *class_;
13429  BTID index;
13430  int i, n_attrs, is_partition = 0, savepoint_index = 0;
13431  MOP *sub_partitions = NULL;
13432  SM_ATTRIBUTE **attrs = NULL;
13433  size_t attrs_size;
13434  const char *class_name;
13435  const char *partition_name;
13436  int use_prefix_length;
13437  SM_CONSTRAINT_TYPE constraint_type;
13438  int reverse_index;
13439  char *out_shared_cons_name = NULL;
13440  SM_FUNCTION_INFO *new_func_index_info = NULL;
13441  SM_PREDICATE_INFO *new_filter_index_info = NULL;
13442 
13443  assert (db_constraint_type == DB_CONSTRAINT_INDEX || db_constraint_type == DB_CONSTRAINT_REVERSE_INDEX);
13444 
13445  /* AU_FETCH_EXCLUSIVE_SCAN will set SIX-lock on the table. It will allow other reads but neither a write nor another
13446  * index builder. */
13447  error = au_fetch_class_by_classmop (classop, &class_, AU_FETCH_EXCLUSIVE_SCAN, AU_INDEX);
13448  if (error != NO_ERROR)
13449  {
13450  return error;
13451  }
13452 
13453  error =
13454  sm_check_index_exist (classop, &out_shared_cons_name, db_constraint_type, constraint_name, attnames, asc_desc,
13455  filter_index, function_index);
13456  if (error != NO_ERROR)
13457  {
13458  return error;
13459  }
13460 
13461  constraint_type = SM_MAP_DB_INDEX_CONSTRAINT_TO_SM_CONSTRAINT (db_constraint_type);
13462  reverse_index = SM_IS_CONSTRAINT_REVERSE_INDEX_FAMILY (constraint_type);
13463 
13464  error = sm_partitioned_class_type (classop, &is_partition, NULL, &sub_partitions);
13465  if (error != NO_ERROR)
13466  {
13467  goto fail_end;
13468  }
13469 
13470  if (is_partition == 1)
13471  {
13472  if (attrs_prefix_length)
13473  {
13474  /* Count the number of attributes */
13475  n_attrs = 0;
13476  for (i = 0; attnames[i] != NULL; i++)
13477  {
13478  n_attrs++;
13479  }
13480 
13481  use_prefix_length = false;
13482  for (i = 0; i < n_attrs; i++)
13483  {
13484  if (attrs_prefix_length[i] != -1)
13485  {
13486  use_prefix_length = true;
13487  break;
13488  }
13489  }
13490 
13491  if (use_prefix_length)
13492  {
13495  goto fail_end;
13496  }
13497  }
13499  if (error != NO_ERROR)
13500  {
13501  goto fail_end;
13502  }
13503 
13504  savepoint_index = 1;
13505  if (function_index)
13506  {
13507  error = sm_save_function_index_info (&new_func_index_info, function_index);
13508  if (error != NO_ERROR)
13509  {
13510  goto fail_end;
13511  }
13512  }
13513  if (filter_index)
13514  {
13515  error = sm_save_filter_index_info (&new_filter_index_info, filter_index);
13516  if (error != NO_ERROR)
13517  {
13518  goto fail_end;
13519  }
13520  }
13521  for (i = 0; error == NO_ERROR && sub_partitions[i]; i++)
13522  {
13523  if (sm_exist_index (sub_partitions[i], constraint_name, NULL) == NO_ERROR)
13524  {
13525  class_name = sm_get_ch_name (sub_partitions[i]);
13526  if (class_name)
13527  {
13528  error = ER_SM_INDEX_EXISTS;
13529  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 2, class_name, constraint_name);
13530  }
13531  else
13532  {
13533  assert (er_errid () != NO_ERROR);
13534  error = er_errid ();
13535  }
13536  break;
13537  }
13538 
13539  if (function_index)
13540  {
13541  class_name = sm_get_ch_name (classop);
13542  if (class_name == NULL)
13543  {
13544  assert (er_errid () != NO_ERROR);
13545  error = er_errid ();
13546  break;
13547  }
13548 
13549  partition_name = sm_get_ch_name (sub_partitions[i]);
13550  if (partition_name == NULL)
13551  {
13552  assert (er_errid () != NO_ERROR);
13553  error = er_errid ();
13554  break;
13555  }
13556 
13557  /* make sure the expression is compiled using the appropriate name, the partition name */
13558  error = do_recreate_func_index_constr (NULL, NULL, new_func_index_info, NULL, class_name, partition_name);
13559  if (error != NO_ERROR)
13560  {
13561  goto fail_end;
13562  }
13563  }
13564  else
13565  {
13566  new_func_index_info = NULL;
13567  }
13568 
13569  if (filter_index)
13570  {
13571  /* make sure the expression is compiled using the appropriate name, the partition name */
13572  if (new_filter_index_info->num_attrs > 0)
13573  {
13574  class_name = sm_get_ch_name (classop);
13575  if (class_name == NULL)
13576  {
13577  assert (er_errid () != NO_ERROR);
13578  error = er_errid ();
13579  break;
13580  }
13581 
13582  partition_name = sm_get_ch_name (sub_partitions[i]);
13583  if (partition_name == NULL)
13584  {
13585  assert (er_errid () != NO_ERROR);
13586  error = er_errid ();
13587  break;
13588  }
13589 
13590  error =
13591  do_recreate_filter_index_constr (NULL, new_filter_index_info, NULL, class_name, partition_name);
13592  if (error != NO_ERROR)
13593  {
13594  goto fail_end;
13595  }
13596  }
13597  }
13598  else
13599  {
13600  new_filter_index_info = NULL;
13601  }
13602 
13603  error =
13604  sm_add_index (sub_partitions[i], db_constraint_type, constraint_name, attnames, asc_desc, NULL,
13605  new_filter_index_info, new_func_index_info, comment);
13606  }
13607 
13608  if (new_func_index_info)
13609  {
13610  sm_free_function_index_info (new_func_index_info);
13611  free_and_init (new_func_index_info);
13612  }
13613  if (new_filter_index_info)
13614  {
13615  sm_free_filter_index_info (new_filter_index_info);
13616  free_and_init (new_filter_index_info);
13617  }
13618 
13619  if (error != NO_ERROR)
13620  {
13621  goto fail_end;
13622  }
13623  }
13624 
13625  if (sub_partitions)
13626  {
13627  free_and_init (sub_partitions);
13628  }
13629 
13630  /* should be checked before if this index already exist */
13631 
13632  /* Count the number of attributes */
13633  n_attrs = 0;
13634  for (i = 0; attnames[i] != NULL; i++)
13635  {
13636  n_attrs++;
13637  }
13638 
13639  /* Allocate memory for the attribute array */
13640  attrs_size = sizeof (SM_ATTRIBUTE *) * (n_attrs + 1);
13641  attrs = (SM_ATTRIBUTE **) malloc (attrs_size);
13642  if (attrs == NULL)
13643  {
13645  error = ER_OUT_OF_VIRTUAL_MEMORY;
13646  goto general_error;
13647  }
13648 
13649  /* Retrieve all of the attributes */
13650  for (i = 0; i < n_attrs; i++)
13651  {
13652  attrs[i] = classobj_find_attribute (class_, attnames[i], 0);
13653 
13654  if (attrs[i] != NULL && attrs[i]->header.name_space == ID_SHARED_ATTRIBUTE)
13655  {
13656  ERROR1 (error, ER_SM_INDEX_ON_SHARED, attnames[i]);
13657  goto general_error;
13658  }
13659  if (attrs[i] == NULL || attrs[i]->header.name_space != ID_ATTRIBUTE)
13660  {
13661  ERROR1 (error, ER_SM_ATTRIBUTE_NOT_FOUND, attnames[i]);
13662  goto general_error;
13663  }
13664 #if defined (ENABLE_UNUSED_FUNCTION) /* to disable TEXT */
13665  if (sm_has_text_domain (attrs[i], 0))
13666  {
13667  if (strstr (constraint_name, TEXT_CONSTRAINT_PREFIX))
13668  {
13669  /* prevent to create index on TEXT attribute */
13671  goto general_error;
13672  }
13673  }
13674 #endif /* ENABLE_UNUSED_FUNCTION */
13675  }
13676  attrs[n_attrs] = NULL;
13677 
13678  /* Make sure both the class and the instances are flushed before creating the index. NOTE THAT THIS WILL REMOVE THE
13679  * DIRTY BIT FROM THE CLASS OBJECT BEFORE THE INDEX HAS ACTUALLY BEEN ATTACHED ! WE NEED TO MAKE SURE THE CLASS IS
13680  * MARKED DIRTY AGAIN AFTER THE INDEX LOAD. */
13681 
13682  if (locator_flush_class (classop) != NO_ERROR || locator_flush_all_instances (classop, DECACHE) != NO_ERROR)
13683  {
13684  goto general_error;
13685  }
13686 
13687  if (out_shared_cons_name)
13688  {
13689  /* only normal index can share with foreign key */
13690  SM_CLASS_CONSTRAINT *existing_con;
13691  existing_con = classobj_find_constraint_by_name (class_->constraints, out_shared_cons_name);
13692  assert (existing_con != NULL);
13693 
13694  BTID_COPY (&index, &existing_con->index_btid);
13695  }
13696  else
13697  {
13698  /* allocate the index - this will result in a btree load if there are existing instances */
13699  BTID_SET_NULL (&index);
13700  error = allocate_index (classop, class_, NULL, attrs, asc_desc, attrs_prefix_length, 0 /* unique_pk */ ,
13701  false, reverse_index, constraint_name, &index, NULL, NULL, NULL, filter_index,
13702  function_index);
13703  }
13704 
13705  if (error == NO_ERROR)
13706  {
13707  /* promote the class lock as SCH_M lock and mark class as dirty */
13708  if (locator_update_class (classop) == NULL)
13709  {
13710  ASSERT_ERROR_AND_SET (error);
13711  goto severe_error;
13712  }
13713 
13714  /* modify the class to point at the new index */
13715  error =
13716  classobj_put_index (&(class_->properties), constraint_type, constraint_name, attrs, asc_desc,
13717  attrs_prefix_length, &index, filter_index, NULL, out_shared_cons_name, function_index,
13718  comment, false);
13719  if (error != NO_ERROR)
13720  {
13721  ASSERT_ERROR ();
13722  goto severe_error;
13723  }
13724 
13725  error = classobj_cache_class_constraints (class_);
13726  if (error != NO_ERROR)
13727  {
13728  ASSERT_ERROR ();
13729  goto severe_error;
13730  }
13731 
13732  if (!classobj_cache_constraints (class_))
13733  {
13734  ASSERT_ERROR_AND_SET (error);
13735  goto severe_error;
13736  }
13737 
13738  /* now that the index is physically attached to the class, we must flush it again to make sure the catalog is
13739  * updated correctly. */
13740  error = locator_flush_class (classop);
13741  if (error != NO_ERROR)
13742  {
13743  ASSERT_ERROR ();
13744  goto severe_error;
13745  }
13746 
13747  /* since we almost always want to use the index after it has been created, cause the statistics for this class to
13748  * be updated so that the optimizer is able to make use of the new index. Recall that the optimizer looks at the
13749  * statistics structures, not the schema structures. */
13750  assert_release (!BTID_IS_NULL (&index));
13751  error = sm_update_statistics (classop, STATS_WITH_SAMPLING);
13752  if (error != NO_ERROR)
13753  {
13754  ASSERT_ERROR ();
13755  goto severe_error;
13756  }
13757  }
13758 
13759  free_and_init (attrs);
13760 
13761 fail_end:
13762  if (savepoint_index && error != NO_ERROR && error != ER_LK_UNILATERALLY_ABORTED)
13763  {
13765  }
13766  if (sub_partitions)
13767  {
13768  free_and_init (sub_partitions);
13769  }
13770  if (out_shared_cons_name)
13771  {
13772  free_and_init (out_shared_cons_name);
13773  }
13774  if (new_func_index_info)
13775  {
13776  sm_free_function_index_info (new_func_index_info);
13777  free_and_init (new_func_index_info);
13778  }
13779  if (new_filter_index_info)
13780  {
13781  sm_free_filter_index_info (new_filter_index_info);
13782  free_and_init (new_filter_index_info);
13783  }
13784 
13785  return error;
13786 
13787 general_error:
13788  if (attrs != NULL)
13789  {
13790  free_and_init (attrs);
13791  }
13792  if (out_shared_cons_name)
13793  {
13794  free_and_init (out_shared_cons_name);
13795  }
13796  if (new_func_index_info)
13797  {
13798  sm_free_function_index_info (new_func_index_info);
13799  free_and_init (new_func_index_info);
13800  }
13801  if (new_filter_index_info)
13802  {
13803  sm_free_filter_index_info (new_filter_index_info);
13804  free_and_init (new_filter_index_info);
13805  }
13806 
13807  return error;
13808 
13809 severe_error:
13810 
13811  if (error == NO_ERROR)
13812  {
13813  ASSERT_ERROR_AND_SET (error);
13814  }
13815  else
13816  {
13817  ASSERT_ERROR ();
13818  }
13819 
13820  /* Something happened at a bad time, the database is in an inconsistent state. Must abort the transaction. Save the
13821  * error that caused the problem. We should try to disable error overwriting when we abort so the caller can find out
13822  * what happened. */
13823  if (attrs != NULL)
13824  {
13825  free_and_init (attrs);
13826  }
13827  if (out_shared_cons_name)
13828  {
13829  free_and_init (out_shared_cons_name);
13830  }
13831  if (new_func_index_info)
13832  {
13833  sm_free_function_index_info (new_func_index_info);
13834  free_and_init (new_func_index_info);
13835  }
13836  if (new_filter_index_info)
13837  {
13838  sm_free_filter_index_info (new_filter_index_info);
13839  free_and_init (new_filter_index_info);
13840  }
13841 
13842  /* Some errors will led ws_abort_mops() be called. mops maybe be decached. In this case, its class_ is invalid and we
13843  * cannot access it any more. */
13844  if (!classop->decached)
13845  {
13847  }
13848 
13849  (void) tran_unilaterally_abort ();
13850 
13851  return error;
13852 }
13853 #endif
13854 
13855 /*
13856  * sm_drop_index() - Removes an index for an attribute.
13857  * Take care to remove the class property list entry for this
13858  * index if one has been created. !! This works now because
13859  * sm_drop_index is the only way that we can remove indexes. If
13860  * index add/drop can ever be done during template processing, we'll
13861  * have to make that code more aware of this.
13862  * return: NO_ERROR on success, non-zero for ERROR
13863  * classop(in): class object
13864  * constraint_name(in): constraint name
13865  */
13866 
13867 int
13868 sm_drop_index (MOP classop, const char *constraint_name)
13869 {
13870  int error = NO_ERROR;
13871  SM_CLASS *class_;
13872  SM_CLASS_CONSTRAINT *found;
13873  SM_CONSTRAINT_TYPE ctype;
13874  int i, is_partition = 0, savepoint_index = 0;
13875  MOP *sub_partitions = NULL;
13876 
13877  error = au_fetch_class (classop, &class_, AU_FETCH_UPDATE, AU_INDEX);
13878  if (error != NO_ERROR)
13879  {
13880  return error;
13881  }
13882 
13883  error = sm_partitioned_class_type (classop, &is_partition, NULL, &sub_partitions);
13884  if (error != NO_ERROR)
13885  {
13886  return error;
13887  }
13888 
13889  if (is_partition == 1)
13890  {
13892  if (error != NO_ERROR)
13893  {
13894  goto fail_end;
13895  }
13896 
13897  savepoint_index = 1;
13898  for (i = 0; sub_partitions[i]; i++)
13899  {
13900  if (sm_exist_index (sub_partitions[i], constraint_name, NULL) != NO_ERROR)
13901  {
13902  continue;
13903  }
13904  error = sm_drop_index (sub_partitions[i], constraint_name);
13905  if (error != NO_ERROR)
13906  {
13907  goto fail_end;
13908  }
13909  }
13910  }
13911 
13912  if (sub_partitions)
13913  {
13914  free_and_init (sub_partitions);
13915  }
13916 
13917  /* Verify that this constraint does exist */
13918  ctype = SM_CONSTRAINT_INDEX;
13919  found = classobj_find_class_constraint (class_->constraints, ctype, constraint_name);
13920 
13921  if (found == NULL)
13922  {
13924  found = classobj_find_class_constraint (class_->constraints, ctype, constraint_name);
13925  }
13926 
13927  if (found == NULL)
13928  {
13929  ERROR1 (error, ER_SM_NO_INDEX, constraint_name);
13930  }
13931  else
13932  {
13933  /*
13934  * Remove the index from the class. We do this is an awkward
13935  * way. First we remove it from the class constraint cache and
13936  * then we back propagate the changes to the class property list.
13937  * We do this backwards because it's easier, go figure.
13938  */
13939  if (deallocate_index (class_->constraints, &found->index_btid))
13940  {
13941  goto severe_error;
13942  }
13943 
13944  BTID_SET_NULL (&found->index_btid);
13947 
13948  error = classobj_populate_class_properties (&class_->properties, class_->constraints, ctype);
13949 
13951  {
13952  goto severe_error;
13953  }
13954 
13955  if (!classobj_cache_constraints (class_))
13956  {
13957  goto severe_error;
13958  }
13959 
13960  /* Make sure the class is now marked dirty and flushed so that the catalog is updated. Also update statistics so
13961  * that the optimizer will know that the index no longer exists. */
13962  if (locator_update_class (classop) == NULL)
13963  {
13964  goto severe_error;
13965  }
13966 
13967  if (locator_flush_class (classop) != NO_ERROR)
13968  {
13969  goto severe_error;
13970  }
13971 
13973  {
13974  goto severe_error;
13975  }
13976  }
13977 
13978 fail_end:
13979  if (savepoint_index && error != NO_ERROR && error != ER_LK_UNILATERALLY_ABORTED)
13980  {
13982  }
13983  if (sub_partitions)
13984  {
13985  free_and_init (sub_partitions);
13986  }
13987 
13988  return error;
13989 
13990 severe_error:
13991  /* Something happened at a bad time, the database is in an inconsistent state. Must abort the transaction. Save the
13992  * error that caused the problem. We should try to disable error overwriting when we abort so the caller can find out
13993  * what happened. */
13994  assert (er_errid () != NO_ERROR);
13995  error = er_errid ();
13996  (void) tran_unilaterally_abort ();
13997 
13998  return error;
13999 }
14000 
14001 /*
14002  * sm_get_index() - Checks to see if an attribute has an index and if so,
14003  * returns the BTID of the index.
14004  * return: NO_ERROR on success, non-zero for ERROR
14005  * classop(in): class object
14006  * attname(in): attribute name
14007  * index(out): returned pointer to index
14008  */
14009 
14010 int
14011 sm_get_index (MOP classop, const char *attname, BTID * index)
14012 {
14013  int error = NO_ERROR;
14014  SM_CLASS *class_;
14015  SM_ATTRIBUTE *att;
14016 
14017  /* what happens if we formerly indexed the attribute, revoked index authorization and now want to remove it ? */
14018 
14019  error = au_fetch_class (classop, &class_, AU_FETCH_READ, AU_SELECT);
14020  if (error == NO_ERROR)
14021  {
14022  att = classobj_find_attribute (class_, attname, 0);
14023  if (att == NULL || att->header.name_space != ID_ATTRIBUTE)
14024  {
14025  ERROR1 (error, ER_SM_ATTRIBUTE_NOT_FOUND, attname);
14026  }
14027  else
14028  {
14029  SM_CONSTRAINT *con;
14030  int found = 0;
14031 
14032  /* First look for the index in the attribute constraint cache */
14033  for (con = att->constraints; ((con != NULL) && !found); con = con->next)
14034  {
14036  {
14037  *index = con->index;
14038  found = 1;
14039  }
14040  }
14041  }
14042  }
14043 
14044  return error;
14045 }
14046 
14047 /*
14048  * sm_default_constraint_name() - Constructs a constraint name based upon
14049  * the class and attribute names and names' asc/desc info.
14050  * Returns the constraint name or NULL is an error occurred. The string
14051  * should be deallocated with free_and_init() when no longer needed.
14052  * The class name is normally obtained from the Class Object. This is
14053  * not always possible, though (for instance at class creation time,
14054  * there is no class object and <classop> will be NULL). Under this
14055  * condition, the class name will be taken from the Class Template
14056  * <ctmpl>.
14057  * The format of the default name is;
14058  * X_<class>_att1_att2_... or
14059  * X_<class>_att1_d_att2_... --> _d implies that att1 order is 'desc'
14060  * where X indicates the constraint type;
14061  * i=INDEX, u=UNIQUE, pk=PRIMARY KEY,
14062  * fk=FOREIGN KEY, n=NOT NULL, ru=REVERSE UNIQUE,
14063  * ri=REVERSE INDEX
14064  * <class> is the class name
14065  * attn is the attribute name
14066  * (ex) If we are generating a default name for
14067  * create index on foo (a, b);
14068  * It would look like i_foo_a_b
14069  * (ex) If we are generating a default name for
14070  * create index on foo (a desc, b);
14071  * It would look like i_foo_a_d_b --> use '_d' for 'desc'
14072  * (ex) If we are generating a default name for
14073  * create reverse index on foo (a desc, b);
14074  * It would look like ri_foo_a_b --> not use '_d' for reverse type
14075  * return: constraint name
14076  * class_name(in): class name
14077  * type(in): Constraint Type
14078  * att_names(in): Attribute Names
14079  * asc_desc(in): asc/desc info list
14080  */
14081 
14082 static char *
14083 sm_default_constraint_name (const char *class_name, DB_CONSTRAINT_TYPE type, const char **att_names,
14084  const int *asc_desc)
14085 {
14086 #define MAX_ATTR_IN_AUTO_GEN_NAME 30
14087  const char **ptr;
14088  char *name = NULL;
14089  int name_length = 0;
14090  bool do_desc;
14091  int error = NO_ERROR;
14092  int n_attrs = 0;
14093  /*
14094  * Construct the constraint name
14095  */
14096  if ((class_name == NULL) || (att_names == NULL))
14097  {
14099  }
14100  else
14101  {
14102  const char *prefix;
14103  int i, k;
14104  int class_name_prefix_size = DB_MAX_IDENTIFIER_LENGTH;
14105  int att_name_prefix_size = DB_MAX_IDENTIFIER_LENGTH;
14106  char md5_str[32 + 1] = { '\0' };
14107 
14108  switch (type)
14109  {
14110  case DB_CONSTRAINT_INDEX:
14111  prefix = "i_";
14112  break;
14113  case DB_CONSTRAINT_UNIQUE:
14114  prefix = "u_";
14115  break;
14117  prefix = "pk_";
14118  break;
14120  prefix = "fk_";
14121  break;
14123  prefix = "n_";
14124  break;
14126  prefix = "ru_";
14127  break;
14129  prefix = "ri_";
14130  break;
14131  default:
14132  assert (false);
14133  prefix = "x_"; /* unknown */
14134  break;
14135  }
14136 
14137  /*
14138  * Count the number of characters that we'll need for the name
14139  */
14140  name_length = strlen (prefix);
14141  name_length += strlen (class_name); /* class name */
14142 
14143  for (ptr = att_names; *ptr != NULL; ptr++)
14144  {
14145  n_attrs++;
14146  }
14147 
14148  i = 0;
14149  for (ptr = att_names; (*ptr != NULL) && (i < n_attrs); ptr++, i++)
14150  {
14151  int ptr_size = 0;
14152 
14153  do_desc = false; /* init */
14154  if (asc_desc)
14155  {
14157  {
14158  /* attr is marked as 'desc' in the non-reverse index */
14159  if (asc_desc[i] == 1)
14160  {
14161  do_desc = true;
14162  }
14163  }
14164  }
14165 
14166  ptr_size = intl_identifier_lower_string_size (*ptr);
14167  name_length += (1 + ptr_size); /* separator and attr name */
14168  if (do_desc)
14169  {
14170  name_length += 2; /* '_d' for 'desc' */
14171  }
14172  } /* for (ptr = ...) */
14173 
14174  if (name_length >= DB_MAX_IDENTIFIER_LENGTH)
14175  {
14176  /* constraint name will contain a descriptive prefix + prefixes of class name + prefixes of the first
14177  * MAX_ATTR_IN_AUTO_GEN_NAME attributes + MD5 of the entire string of concatenated class name and attributes
14178  * names */
14179  char *name_all = NULL;
14180  int size_class_and_attrs = DB_MAX_IDENTIFIER_LENGTH - 1 - strlen (prefix) - 32 - 1;
14181  int ec = NO_ERROR;
14182 
14183  name_all = (char *) malloc (name_length + 1);
14184  if (name_all == NULL)
14185  {
14186  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, (size_t) (name_length + 1));
14187  goto exit;
14188  }
14189  strcpy (name_all, class_name);
14190  for (ptr = att_names, i = 0; i < n_attrs; ptr++, i++)
14191  {
14192  strcat (name_all, *ptr);
14193  if (asc_desc && !DB_IS_CONSTRAINT_REVERSE_INDEX_FAMILY (type) && asc_desc[i] == 1)
14194  {
14195  strcat (name_all, "d");
14196  }
14197  }
14198 
14199  ec = crypt_md5_buffer_hex (name_all, strlen (name_all), md5_str);
14200  free_and_init (name_all);
14201  if (ec != NO_ERROR)
14202  {
14203  goto exit;
14204  }
14205 
14206  if (n_attrs > MAX_ATTR_IN_AUTO_GEN_NAME)
14207  {
14208  n_attrs = MAX_ATTR_IN_AUTO_GEN_NAME;
14209  }
14210 
14211  att_name_prefix_size = size_class_and_attrs / (n_attrs + 1);
14212  class_name_prefix_size = att_name_prefix_size;
14213 
14214  if (strlen (class_name) < class_name_prefix_size)
14215  {
14216  class_name_prefix_size = strlen (class_name);
14217  }
14218  else
14219  {
14220  char class_name_trunc[DB_MAX_IDENTIFIER_LENGTH];
14221 
14222  strncpy (class_name_trunc, class_name, class_name_prefix_size);
14223  class_name_trunc[class_name_prefix_size] = '\0';
14224 
14225  /* make sure last character is not truncated */
14226  if (intl_identifier_fix (class_name_trunc, class_name_prefix_size, false) != NO_ERROR)
14227  {
14228  /* this should not happen */
14229  assert (false);
14231  name = NULL;
14232  goto exit;
14233  }
14234  class_name_prefix_size = strlen (class_name_trunc);
14235  }
14236 
14237  /* includes '_' between attributes */
14238  att_name_prefix_size = ((size_class_and_attrs - class_name_prefix_size) / n_attrs) - 1;
14239  name_length = DB_MAX_IDENTIFIER_LENGTH;
14240  }
14241  /*
14242  * Allocate space for the name and construct it
14243  */
14244  name = (char *) malloc (name_length + 1); /* Remember terminating NULL */
14245  if (name != NULL)
14246  {
14247  /* Constraint Type */
14248  strcpy (name, prefix);
14249 
14250  /* Class name */
14251  strncat (name, class_name, class_name_prefix_size);
14252 
14253  /* separated list of attribute names */
14254  k = 0;
14255  i = 0;
14256  /* n_attrs is already limited to MAX_ATTR_IN_AUTO_GEN_NAME here */
14257  for (ptr = att_names; k < n_attrs; ptr++, i++)
14258  {
14259  do_desc = false; /* init */
14260  if (asc_desc)
14261  {
14263  {
14264  /* attr is marked as 'desc' in the non-reverse index */
14265  if (asc_desc[i] == 1)
14266  {
14267  do_desc = true;
14268  }
14269  }
14270  }
14271 
14272  strcat (name, "_");
14273 
14274  if (att_name_prefix_size == DB_MAX_IDENTIFIER_LENGTH)
14275  {
14276  (void) intl_identifier_lower (*ptr, &name[strlen (name)]);
14277 
14278  /* attr is marked as 'desc' */
14279  if (do_desc)
14280  {
14281  strcat (name, "_d");
14282  }
14283  }
14284  else
14285  {
14286  char att_name_trunc[DB_MAX_IDENTIFIER_LENGTH];
14287 
14288  (void) intl_identifier_lower (*ptr, att_name_trunc);
14289 
14290  if (do_desc)
14291  {
14292  /* make sure last character is not truncated */
14293  assert (att_name_prefix_size > 2);
14294  if (intl_identifier_fix (att_name_trunc, att_name_prefix_size - 2, false) != NO_ERROR)
14295  {
14296  assert (false);
14298  free_and_init (name);
14299  goto exit;
14300  }
14301  strcat (att_name_trunc, "_d");
14302  }
14303  else
14304  {
14305  if (intl_identifier_fix (att_name_trunc, att_name_prefix_size, false) != NO_ERROR)
14306  {
14307  assert (false);
14309  free_and_init (name);
14310  goto exit;
14311  }
14312  }
14313 
14314  strcat (name, att_name_trunc);
14315  }
14316  k++;
14317  }
14318 
14319  if (att_name_prefix_size != DB_MAX_IDENTIFIER_LENGTH || class_name_prefix_size != DB_MAX_IDENTIFIER_LENGTH)
14320  {
14321  /* append MD5 */
14322  strcat (name, "_");
14323  strcat (name, md5_str);
14324 
14326  }
14327  }
14328  else
14329  {
14330  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, (size_t) (name_length + 1));
14331  }
14332  }
14333 
14334 exit:
14335  return name;
14336 
14337 #undef MAX_ATTR_IN_AUTO_GEN_NAME
14338 }
14339 
14340 /*
14341  * sm_produce_constraint_name() - Generate a normalized constraint name.
14342  * If a constraint name is given <given_name> != NULL, then this name is
14343  * downcased and returned. In this case, the constraint type and attribute
14344  * names are not needed.
14345  * If a given name is not provided <given_name> == NULL, then a
14346  * normalized name is generated using the constraint type and attribute
14347  * names.
14348  * In either case, the returned name is generated its own memory area
14349  * and should be deallocated with by calling free()
14350  * when it is no longer needed.
14351  * This function differs from sm_produce_constraint_name_mop() in that
14352  * the class name is supplied as a parameters and therefore, does not
14353  * need to be derived.
14354  * return: constraint name
14355  * class_name(in): Class Name
14356  * constraint_type(in): Constraint Type
14357  * att_names(in): Attribute Names
14358  * asc_desc(in): asc/desc info list
14359  * given_name(in): Optional constraint name.
14360  */
14361 
14362 char *
14363 sm_produce_constraint_name (const char *class_name, DB_CONSTRAINT_TYPE constraint_type, const char **att_names,
14364  const int *asc_desc, const char *given_name)
14365 {
14366  char *name = NULL;
14367  size_t name_size;
14368 
14369  if (given_name == NULL)
14370  {
14371  name = sm_default_constraint_name (class_name, constraint_type, att_names, asc_desc);
14372  }
14373  else
14374  {
14375  name_size = intl_identifier_lower_string_size (given_name);
14376  name = (char *) malloc (name_size + 1);
14377  if (name != NULL)
14378  {
14379  intl_identifier_lower (given_name, name);
14380  }
14381  else
14382  {
14384  }
14385  }
14386 
14387  return name;
14388 }
14389 
14390 /*
14391  * sm_produce_constraint_name_mop() - This function serves the same
14392  * functionality as sm_produce_constraint_name() except that it accepts
14393  * a class MOP instead of a class name.
14394  * return: constraint name
14395  * classop(in): Class Object
14396  * constraint_type(in): Constraint Type
14397  * att_names(in): Attribute Names
14398  * given_name(in): Optional constraint name.
14399  */
14400 
14401 char *
14402 sm_produce_constraint_name_mop (MOP classop, DB_CONSTRAINT_TYPE constraint_type, const char **att_names,
14403  const int *asc_desc, const char *given_name)
14404 {
14405  return sm_produce_constraint_name (sm_get_ch_name (classop), constraint_type, att_names, asc_desc, given_name);
14406 }
14407 
14408 /*
14409  * sm_produce_constraint_name_tmpl() - This function serves the same
14410  * functionality as sm_produce_constraint_name() except that it accepts
14411  * a class template instead of a class name.
14412  * return: constraint name
14413  * tmpl(in): Class Template
14414  * constraint_type(in): Constraint Type
14415  * att_names(in): Attribute Names
14416  * given_name(in): Optional constraint name.
14417  */
14418 char *
14419 sm_produce_constraint_name_tmpl (SM_TEMPLATE * tmpl, DB_CONSTRAINT_TYPE constraint_type, const char **att_names,
14420  const int *asc_desc, const char *given_name)
14421 {
14422  return sm_produce_constraint_name (template_classname (tmpl), constraint_type, att_names, asc_desc, given_name);
14423 }
14424 
14425 /*
14426  * sm_check_index_exist() - Check index is duplicated.
14427  * return: NO_ERROR on success, non-zero for ERROR
14428  * classop(in): class (or instance) pointer
14429  * out_shared_cons_name(out):
14430  * constraint_type: constraint type
14431  * constraint_name(in): Constraint name.
14432  * att_names(in): array of attribute names
14433  * asc_desc(in): asc/desc info list
14434  * filter_index(in): expression from CREATE INDEX idx
14435  * ON tbl(col1, ...) WHERE filter_predicate
14436  * func_info(in): function info pointer
14437  */
14438 static int
14439 sm_check_index_exist (MOP classop, char **out_shared_cons_name, DB_CONSTRAINT_TYPE constraint_type,
14440  const char *constraint_name, const char **att_names, const int *asc_desc,
14441  const SM_PREDICATE_INFO * filter_index, const SM_FUNCTION_INFO * func_info)
14442 {
14443  int error = NO_ERROR;
14444  SM_CLASS *class_;
14445 
14446  if (!DB_IS_CONSTRAINT_INDEX_FAMILY (constraint_type))
14447  {
14448  return NO_ERROR;
14449  }
14450 
14451  error = au_fetch_class (classop, &class_, AU_FETCH_READ, AU_INDEX);
14452  if (error != NO_ERROR)
14453  {
14454  return error;
14455  }
14456 
14457  return classobj_check_index_exist (class_->constraints, out_shared_cons_name, sm_ch_name ((MOBJ) class_),
14458  constraint_type, constraint_name, att_names, asc_desc, filter_index, func_info);
14459 }
14460 
14461 static int
14463  const char *constraint_name, const char **att_names, const int *asc_desc,
14464  const int *attrs_prefix_length, int class_attributes,
14465  SM_PREDICATE_INFO * filter_index, SM_FUNCTION_INFO * function_index,
14466  const char *comment, SM_INDEX_STATUS index_status, MOP * sub_partitions)
14467 {
14468  int error, i;
14469  bool set_savept = false;
14470  SM_FUNCTION_INFO *new_func_index_info = NULL;
14471  SM_PREDICATE_INFO *new_filter_index_info = NULL;
14472  const char *class_name, *partition_name;
14473 
14474  /* TODO: This will not work for online indexes from the point of view of concurrent transactions since the
14475  * global index will hold the lock until all the partitions finished loading.
14476  * We need to let the partition loading to also demote the global table as well.
14477  */
14478 
14480  if (error != NO_ERROR)
14481  {
14482  goto end;
14483  }
14484  set_savept = true;
14485 
14486  if (function_index != NULL)
14487  {
14488  error = sm_save_function_index_info (&new_func_index_info, function_index);
14489  if (error != NO_ERROR)
14490  {
14491  goto end;
14492  }
14493  }
14494 
14495  if (filter_index != NULL)
14496  {
14497  error = sm_save_filter_index_info (&new_filter_index_info, filter_index);
14498  if (error != NO_ERROR)
14499  {
14500  goto end;
14501  }
14502  }
14503 
14504  for (i = 0; error == NO_ERROR && sub_partitions[i]; i++)
14505  {
14506  if (sm_exist_index (sub_partitions[i], constraint_name, NULL) == NO_ERROR)
14507  {
14508  class_name = sm_get_ch_name (sub_partitions[i]);
14509  if (class_name == NULL)
14510  {
14511  ASSERT_ERROR_AND_SET (error);
14512  }
14513  else
14514  {
14515  error = ER_SM_INDEX_EXISTS;
14516  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 2, class_name, constraint_name);
14517  }
14518  break;
14519  }
14520 
14521  if (function_index != NULL)
14522  {
14523  class_name = sm_get_ch_name (classop);
14524  if (class_name == NULL)
14525  {
14526  ASSERT_ERROR_AND_SET (error);
14527  break;
14528  }
14529 
14530  partition_name = sm_get_ch_name (sub_partitions[i]);
14531  if (partition_name == NULL)
14532  {
14533  ASSERT_ERROR_AND_SET (error);
14534  break;
14535  }
14536 
14537  /* make sure the expression is compiled using the appropriate name, the partition name */
14538  error = do_recreate_func_index_constr (NULL, NULL, new_func_index_info, NULL, class_name, partition_name);
14539  if (error != NO_ERROR)
14540  {
14541  goto end;
14542  }
14543  }
14544 
14545  if (filter_index != NULL)
14546  {
14547  /* make sure the expression is compiled using the appropriate name, the partition name */
14548  if (new_filter_index_info->num_attrs > 0)
14549  {
14550  class_name = sm_get_ch_name (classop);
14551  if (class_name == NULL)
14552  {
14553  ASSERT_ERROR_AND_SET (error);
14554  break;
14555  }
14556 
14557  partition_name = sm_get_ch_name (sub_partitions[i]);
14558  if (partition_name == NULL)
14559  {
14560  ASSERT_ERROR_AND_SET (error);
14561  break;
14562  }
14563 
14564  error = do_recreate_filter_index_constr (NULL, new_filter_index_info, NULL, class_name, partition_name);
14565  if (error != NO_ERROR)
14566  {
14567  goto end;
14568  }
14569  }
14570  }
14571 
14572  error = sm_add_constraint (sub_partitions[i], constraint_type, constraint_name, att_names, asc_desc,
14573  attrs_prefix_length, class_attributes, new_filter_index_info, new_func_index_info,
14574  comment, index_status);
14575  }
14576 
14577 end:
14578  if (set_savept && error != NO_ERROR && error != ER_LK_UNILATERALLY_ABORTED)
14579  {
14581  }
14582  if (new_func_index_info != NULL)
14583  {
14584  sm_free_function_index_info (new_func_index_info);
14585  free_and_init (new_func_index_info);
14586  }
14587  if (new_filter_index_info != NULL)
14588  {
14589  sm_free_filter_index_info (new_filter_index_info);
14590  free_and_init (new_filter_index_info);
14591  }
14592 
14593  return error;
14594 }
14595 
14596 /*
14597  * sm_add_constraint() - Add a constraint to the class.
14598  * return: NO_ERROR on success, non-zero for ERROR
14599  * classop(in): class (or instance) pointer
14600  * constraint_type(in): Type of constraint to add (UNIQUE, NOT NULL or INDEX)
14601  * constraint_name(in): What to call the new constraint
14602  * att_names(in): Names of attributes to be constrained
14603  * asc_desc(in): asc/desc info list
14604  * attrs_prefix_length(in): prefix length for each of the index attributes
14605  * filter_predicate(in): string with the WHERE expression from
14606  * CREATE INDEX idx ON tbl(...) WHERE filter_predicate
14607  * class_attributes(in): Flag. A true value indicates that the names refer to
14608  * class attributes. A false value indicates that the names
14609  * refer to instance attributes.
14610  * comment(in): constraint comment
14611  * is_online_index(in):
14612  *
14613  * Note: When adding NOT NULL constraint, this function doesn't check the
14614  * existing values of the attribute. To make sure NOT NULL constraint
14615  * checks the existing values, use API function 'db_add_constraint'.
14616  */
14617 int
14618 sm_add_constraint (MOP classop, DB_CONSTRAINT_TYPE constraint_type, const char *constraint_name, const char **att_names,
14619  const int *asc_desc, const int *attrs_prefix_length, int class_attributes,
14620  SM_PREDICATE_INFO * filter_index, SM_FUNCTION_INFO * function_index, const char *comment,
14621  SM_INDEX_STATUS index_status)
14622 {
14623  int error = NO_ERROR;
14624  SM_TEMPLATE *def = NULL;
14625  MOP newmop = NULL;
14626  bool needs_hierarchy_lock;
14627  bool set_savepoint = false;
14628  int partition_type;
14629  MOP *sub_partitions = NULL;
14630 
14631  if (att_names == NULL)
14632  {
14634  return error;
14635  }
14636 
14637  switch (constraint_type)
14638  {
14639  case DB_CONSTRAINT_INDEX:
14641  case DB_CONSTRAINT_UNIQUE:
14644  DB_AUTH auth;
14645  bool is_secondary_index;
14646 
14648  if (error != NO_ERROR)
14649  {
14650  return error;
14651  }
14652  set_savepoint = true;
14653 
14654  is_secondary_index = (constraint_type == DB_CONSTRAINT_INDEX || constraint_type == DB_CONSTRAINT_REVERSE_INDEX);
14655 
14656  if (is_secondary_index)
14657  {
14658  auth = AU_INDEX;
14659  }
14660  else
14661  {
14662  auth = AU_ALTER;
14663  }
14664 
14665 #if defined (SA_MODE)
14666  if (index_status == SM_ONLINE_INDEX_BUILDING_IN_PROGRESS)
14667  {
14668  // We don't allow online index for SA_MODE.
14669  index_status = SM_NORMAL_INDEX;
14670  }
14671 #endif /* SA_MODE */
14672 
14673  if (index_status == SM_ONLINE_INDEX_BUILDING_IN_PROGRESS && classop->lock > IX_LOCK)
14674  {
14675  // if the transaction already hold a lock which is greater than IX,
14676  // we don't allow online index creation for transaction consistency.
14677  index_status = SM_NORMAL_INDEX;
14678  }
14679 
14680  def = smt_edit_class_mop (classop, auth);
14681  if (def == NULL)
14682  {
14683  ASSERT_ERROR_AND_SET (error);
14684  goto error_exit;
14685  }
14686 
14687  if (index_status == SM_ONLINE_INDEX_BUILDING_IN_PROGRESS)
14688  {
14689  /* Check for shared constraints. */
14690  char *shared_cons_name = NULL;
14691 
14692  error = smt_check_index_exist (def, &shared_cons_name, constraint_type, constraint_name, att_names,
14693  asc_desc, filter_index, function_index);
14694  if (error != NO_ERROR)
14695  {
14696  smt_quit (def);
14697 
14698  assert (shared_cons_name == NULL);
14699  goto error_exit;
14700  }
14701 
14702  if (shared_cons_name != NULL)
14703  {
14704  /* If index is shared with another constraint, build it as a normal index. */
14705  index_status = SM_NORMAL_INDEX;
14706 
14707  free_and_init (shared_cons_name);
14708  }
14709  }
14710 
14711  error = sm_partitioned_class_type (classop, &partition_type, NULL, &sub_partitions);
14712  if (error != NO_ERROR)
14713  {
14714  smt_quit (def);
14715  goto error_exit;
14716  }
14717 
14718  if (index_status == SM_ONLINE_INDEX_BUILDING_IN_PROGRESS)
14719  {
14720  /* We allow online index on hierarchies just for the special case of partitions.
14721  * Here ->users denotes the immediate subclass, while ->inheritance is the immediate superclass.
14722  */
14723  if (partition_type == DB_NOT_PARTITIONED_CLASS
14724  && (def->current->users != NULL || def->current->inheritance != NULL))
14725  {
14726  // Current class is part of a hierarchy stop here and throw an error as we do not support online index
14727  // for hierarchies.
14729  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 0);
14730 
14731  if (sub_partitions != NULL)
14732  {
14733  free_and_init (sub_partitions);
14734  }
14735  smt_quit (def);
14736  goto error_exit;
14737  }
14738  }
14739 
14740  // create local indexes on partitions
14741  if (is_secondary_index)
14742  {
14743  if (partition_type == DB_PARTITIONED_CLASS)
14744  {
14745  // prefix index is not allowed on partition
14746  for (int i = 0; attrs_prefix_length != NULL && att_names[i] != NULL; i++)
14747  {
14748  if (attrs_prefix_length[i] != -1)
14749  {
14751  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 0);
14752 
14753  if (sub_partitions != NULL)
14754  {
14755  free_and_init (sub_partitions);
14756  }
14757  smt_quit (def);
14758  goto error_exit;
14759  }
14760  }
14761 
14762  error = sm_add_secondary_index_on_partition (classop, constraint_type, constraint_name, att_names,
14763  asc_desc, attrs_prefix_length, class_attributes,
14764  filter_index, function_index, comment, index_status,
14765  sub_partitions);
14766  if (error != NO_ERROR)
14767  {
14768  if (sub_partitions != NULL)
14769  {
14770  free_and_init (sub_partitions);
14771  }
14772  smt_quit (def);
14773  goto error_exit;
14774  }
14775  }
14776  }
14777 
14778  if (sub_partitions != NULL)
14779  {
14780  free_and_init (sub_partitions);
14781  }
14782 
14783  error = smt_add_constraint (def, constraint_type, constraint_name, att_names, asc_desc, attrs_prefix_length,
14784  class_attributes, NULL, filter_index, function_index, comment, index_status);
14785  if (error != NO_ERROR)
14786  {
14787  smt_quit (def);
14788  goto error_exit;
14789  }
14790 
14791  needs_hierarchy_lock = DB_IS_CONSTRAINT_UNIQUE_FAMILY (constraint_type);
14792  /* This one frees the template inside!!! */
14793  error = sm_update_class_with_auth (def, &newmop, auth, needs_hierarchy_lock);
14794  if (error != NO_ERROR)
14795  {
14796  smt_quit (def);
14797  goto error_exit;
14798  }
14799 
14800  if (index_status == SM_ONLINE_INDEX_BUILDING_IN_PROGRESS && partition_type != DB_PARTITION_CLASS)
14801  {
14802  // Load index phase.
14803  error = sm_load_online_index (newmop, constraint_name);
14804  if (error != NO_ERROR)
14805  {
14806  goto error_exit;
14807  }
14808 
14809  error = sm_update_statistics (newmop, STATS_WITH_SAMPLING);
14810  if (error != NO_ERROR)
14811  {
14812  goto error_exit;
14813  }
14814 
14815  def = smt_edit_class_mop (classop, auth);
14816  if (def == NULL)
14817  {
14818  ASSERT_ERROR_AND_SET (error);
14819  goto error_exit;
14820  }
14821 
14822  error = smt_change_constraint_status (def, constraint_name, SM_NORMAL_INDEX);
14823  if (error != NO_ERROR)
14824  {
14825  smt_quit (def);
14826  goto error_exit;
14827  }
14828 
14829  /* Update the class now. */
14830  /* This one frees the template inside!!! */
14831  error = sm_update_class_with_auth (def, &newmop, auth, needs_hierarchy_lock);
14832  if (error != NO_ERROR)
14833  {
14834  smt_quit (def);
14835  goto error_exit;
14836  }
14837  }
14838  break;
14839 
14841  def = smt_edit_class_mop (classop, AU_ALTER);
14842  if (def == NULL)
14843  {
14844  ASSERT_ERROR_AND_SET (error);
14845  return error;
14846  }
14847 
14848  error = smt_add_constraint (def, constraint_type, constraint_name, att_names, asc_desc, attrs_prefix_length,
14849  class_attributes, NULL, filter_index, function_index, comment, index_status);
14850  if (error != NO_ERROR)
14851  {
14852  smt_quit (def);
14853  return error;
14854  }
14855 
14856  error = do_check_fk_constraints (def, NULL);
14857  if (error != NO_ERROR)
14858  {
14859  smt_quit (def);
14860  return error;
14861  }
14862 
14863  error = sm_update_class (def, NULL);
14864  if (error != NO_ERROR)
14865  {
14866  smt_quit (def);
14867  return error;
14868  }
14869  break;
14870 
14871  default:
14872  break;
14873  }
14874 
14875  return error;
14876 
14877 error_exit:
14878  if (set_savepoint && error != ER_TM_SERVER_DOWN_UNILATERALLY_ABORTED && error != ER_LK_UNILATERALLY_ABORTED)
14879  {
14881  }
14882 
14883  return error;
14884 }
14885 
14886 /*
14887  * sm_drop_constraint() - Drops a constraint from a class.
14888  * return: NO_ERROR on success, non-zero for ERROR
14889  * classop(in): class (or instance) pointer
14890  * constraint_type(in): Type of constraint to drop (UNIQUE, PK, NOT NULL or
14891  * INDEX). Foreign keys are not dropped by this
14892  * function. See dbt_drop_constraint instead.
14893  * constraint_name(in): The name of the constraint to drop
14894  * att_names(in): Names of attributes the constraint is defined on
14895  * class_attributes(in): Whether the names in att_names refer to class
14896  * attributes or instance attributes.
14897  * mysql_index_name(in): If true and constraint_type is DB_CONSTRAINT_INDEX,
14898  * the function behaves like MySQL and drops the
14899  * constraint with the name given by constraint_name
14900  * even if it has a different type than
14901  * DB_CONSTRAINT_INDEX
14902  */
14903 int
14904 sm_drop_constraint (MOP classop, DB_CONSTRAINT_TYPE constraint_type, const char *constraint_name,
14905  const char **att_names, bool class_attributes, bool mysql_index_name)
14906 {
14907  int error = NO_ERROR;
14908  SM_TEMPLATE *def = NULL;
14909 
14910  if (mysql_index_name && constraint_type == DB_CONSTRAINT_INDEX)
14911  {
14912  SM_CLASS *smcls = NULL;
14913 
14914  /* MySQL does not differentiate between index types. Therefore MySQL's DROP INDEX idx ON tbl; will drop idx even
14915  * if it is a UNIQUE index. On MySQL primary keys don't have names - and therefore should not be considered here
14916  * - while foreign keys need to be dropped in two steps: first the constraint and then the associated index. We
14917  * don't provide compatibility for foreign keys because CUBRID's behavior makes much more sense and changing it
14918  * is difficult. */
14919  if (au_fetch_class (classop, &smcls, AU_FETCH_READ, AU_SELECT) == NO_ERROR)
14920  {
14921  const SM_CLASS_CONSTRAINT *const constraint = classobj_find_class_index (smcls, constraint_name);
14922 
14923  if (constraint != NULL
14924  && (constraint->type == SM_CONSTRAINT_INDEX || constraint->type == SM_CONSTRAINT_REVERSE_INDEX
14925  || constraint->type == SM_CONSTRAINT_UNIQUE || constraint->type == SM_CONSTRAINT_REVERSE_UNIQUE))
14926  {
14927  constraint_type = db_constraint_type (constraint);
14928  }
14929  }
14930  }
14931 
14932  switch (constraint_type)
14933  {
14934  case DB_CONSTRAINT_INDEX:
14936  error = sm_drop_index (classop, constraint_name);
14937  break;
14938 
14939  case DB_CONSTRAINT_UNIQUE:
14942  def = smt_edit_class_mop (classop, AU_ALTER);
14943  if (def == NULL)
14944  {
14945  assert (er_errid () != NO_ERROR);
14946  error = er_errid ();
14947  }
14948  else
14949  {
14950  error =
14951  smt_drop_constraint (def, att_names, constraint_name, class_attributes,
14952  SM_MAP_CONSTRAINT_TO_ATTFLAG (constraint_type));
14953 
14954  if (error == NO_ERROR)
14955  {
14956  error = sm_update_class (def, NULL);
14957  }
14958 
14959  if (error != NO_ERROR)
14960  {
14961  smt_quit (def);
14962  }
14963  }
14964  break;
14965 
14967  def = smt_edit_class_mop (classop, AU_ALTER);
14968  if (def == NULL)
14969  {
14970  assert (er_errid () != NO_ERROR);
14971  error = er_errid ();
14972  }
14973  else
14974  {
14975  error = smt_drop_constraint (def, att_names, constraint_name, class_attributes, SM_ATTFLAG_NON_NULL);
14976  if (error == NO_ERROR)
14977  {
14978  error = sm_update_class (def, NULL);
14979  }
14980 
14981  if (error != NO_ERROR)
14982  {
14983  smt_quit (def);
14984  }
14985  }
14986  break;
14987 
14988  default:
14989  break;
14990  }
14991 
14992  return error;
14993 }
14994 
14995 /*
14996  * sm_is_possible_to_recreate_constraint() -
14997  * return: Whether it is safe/efficient to drop a constraint on a class and
14998  * then recreate it during truncation
14999  * class_mop(in): class (or instance) pointer
15000  * class_(in): class to be truncated
15001  * constraint(in): the constraint to be considered
15002  * NOTE: If an index can refer to multiple classes (in an inheritance
15003  * hierarchy), we choose not to recreate it. If it is a non-unique index
15004  * (not involved in inheritance issues) or if the class or constraint
15005  * are not involved in inheritance, we are sure that the index will
15006  * only contain OIDs of the class being truncated. It is safe to drop
15007  * and recreate the index in this scenario.
15008  */
15009 static bool
15010 sm_is_possible_to_recreate_constraint (MOP class_mop, const SM_CLASS * const class_,
15011  const SM_CLASS_CONSTRAINT * const constraint)
15012 {
15013  if (class_->inheritance == NULL && class_->users == NULL)
15014  {
15015  return true;
15016  }
15017 
15018  if (constraint->type == SM_CONSTRAINT_NOT_NULL || constraint->type == SM_CONSTRAINT_INDEX
15019  || constraint->type == SM_CONSTRAINT_REVERSE_INDEX)
15020  {
15021  return true;
15022  }
15023 
15024  if (class_->users != NULL)
15025  {
15026  return false;
15027  }
15028 
15029  assert (class_->inheritance != NULL && class_->users == NULL);
15030  if (sm_constraint_belongs_to_class (constraint, class_mop))
15031  {
15032  return true;
15033  }
15034 
15035  return false;
15036 }
15037 
15038 /*
15039  * sm_free_constraint_info() - Frees a SM_CONSTRAINT_INFO list
15040  * save_info(in/out): The list to be freed
15041  * NOTE: the pointer to the list is set to NULL after the list is freed.
15042  */
15043 void
15045 {
15046  SM_CONSTRAINT_INFO *info = NULL;
15047 
15048  if (save_info == NULL || *save_info == NULL)
15049  {
15050  return;
15051  }
15052 
15053  info = *save_info;
15054  while (info != NULL)
15055  {
15056  SM_CONSTRAINT_INFO *next = info->next;
15057  char **crt_name_p = NULL;
15058 
15059  for (crt_name_p = info->att_names; *crt_name_p != NULL; ++crt_name_p)
15060  {
15061  free_and_init (*crt_name_p);
15062  }
15063  free_and_init (info->att_names);
15064 
15065  if (info->ref_attrs != NULL)
15066  {
15067  for (crt_name_p = info->ref_attrs; *crt_name_p != NULL; ++crt_name_p)
15068  {
15069  free_and_init (*crt_name_p);
15070  }
15071  free_and_init (info->ref_attrs);
15072  }
15073 
15074  if (info->name != NULL)
15075  {
15076  free_and_init (info->name);
15077  }
15078  if (info->comment != NULL)
15079  {
15080  free_and_init (info->comment);
15081  }
15082  free_and_init (info->asc_desc);
15083  free_and_init (info->prefix_length);
15084 
15085  if (info->func_index_info)
15086  {
15089  }
15090 
15091  if (info->filter_predicate)
15092  {
15095  }
15096  free_and_init (info->ref_cls_name);
15097 
15098  free_and_init (info);
15099  info = next;
15100  }
15101 
15102  *save_info = NULL;
15103  return;
15104 }
15105 
15106 /*
15107  * sm_touch_class () - makes sure that the XASL query cache is emptied
15108  * by performing a null operation on a class
15109  * return: NO_ERROR on success, non-zero for ERROR
15110  * classmop (in): The class to be "touched"
15111  */
15112 
15113 int
15115 {
15116  DB_CTMPL *ctmpl = NULL;
15117  int error = NO_ERROR;
15118 
15119  ctmpl = dbt_edit_class (classmop);
15120  if (ctmpl == NULL)
15121  {
15122  assert (er_errid () != NO_ERROR);
15123  error = er_errid ();
15124  goto exit;
15125  }
15126 
15127  if (dbt_finish_class (ctmpl) == NULL)
15128  {
15129  dbt_abort_class (ctmpl);
15130  assert (er_errid () != NO_ERROR);
15131  error = er_errid ();
15132  goto exit;
15133  }
15134 
15135 exit:
15136  return error;
15137 }
15138 
15139 /*
15140  * sm_save_constraint_info() - Saves the information necessary to recreate a
15141  * constraint
15142  * return: NO_ERROR on success, non-zero for ERROR
15143  * save_info(in/out): The information saved
15144  * c(in): The constraint to be saved
15145  */
15146 int
15148 {
15149  int error_code = NO_ERROR;
15150  SM_CONSTRAINT_INFO *new_constraint = NULL;
15151  int num_atts = 0;
15152  int i = 0;
15153  SM_ATTRIBUTE **crt_att_p = NULL;
15154 
15155  new_constraint = (SM_CONSTRAINT_INFO *) calloc (1, sizeof (SM_CONSTRAINT_INFO));
15156  if (new_constraint == NULL)
15157  {
15158  error_code = ER_OUT_OF_VIRTUAL_MEMORY;
15159  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error_code, 1, sizeof (SM_CONSTRAINT_INFO));
15160  goto error_exit;
15161  }
15162 
15163  new_constraint->constraint_type = db_constraint_type (c);
15164  new_constraint->name = strdup (c->name);
15165  if (new_constraint->name == NULL)
15166  {
15167  error_code = ER_OUT_OF_VIRTUAL_MEMORY;
15168  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error_code, 1, (size_t) (strlen (c->name) + 1));
15169  goto error_exit;
15170  }
15171 
15172  new_constraint->comment = (c->comment == NULL) ? NULL : strdup (c->comment);
15173  new_constraint->index_status = c->index_status;
15174 
15175  assert (c->attributes != NULL);
15176  for (crt_att_p = c->attributes, num_atts = 0; *crt_att_p != NULL; ++crt_att_p)
15177  {
15178  ++num_atts;
15179  }
15180  assert (num_atts > 0);
15181 
15182  new_constraint->att_names = (char **) calloc (num_atts + 1, sizeof (char *));
15183  if (new_constraint->att_names == NULL)
15184  {
15185  error_code = ER_OUT_OF_VIRTUAL_MEMORY;
15186  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error_code, 1, (num_atts + 1) * sizeof (char *));
15187  goto error_exit;
15188  }
15189 
15190  for (crt_att_p = c->attributes, i = 0; *crt_att_p != NULL; ++crt_att_p, ++i)
15191  {
15192  const char *const attr_name = (*crt_att_p)->header.name;
15193 
15194  new_constraint->att_names[i] = strdup (attr_name);
15195  if (new_constraint->att_names[i] == NULL)
15196  {
15197  error_code = ER_OUT_OF_VIRTUAL_MEMORY;
15198  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error_code, 1, (size_t) (strlen (attr_name) + 1));
15199  goto error_exit;
15200  }
15201  }
15202 
15203  if (c->asc_desc != NULL)
15204  {
15205  int i = 0;
15206 
15207  new_constraint->asc_desc = (int *) calloc (num_atts, sizeof (int));
15208  if (new_constraint->asc_desc == NULL)
15209  {
15210  error_code = ER_OUT_OF_VIRTUAL_MEMORY;
15211  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error_code, 1, num_atts * sizeof (int));
15212  goto error_exit;
15213  }
15214  for (i = 0; i < num_atts; ++i)
15215  {
15216  new_constraint->asc_desc[i] = c->asc_desc[i];
15217  }
15218  }
15219 
15220  if (c->attrs_prefix_length != NULL)
15221  {
15222  int i = 0;
15223 
15224  new_constraint->prefix_length = (int *) calloc (num_atts, sizeof (int));
15225  if (new_constraint->prefix_length == NULL)
15226  {
15227  error_code = ER_OUT_OF_VIRTUAL_MEMORY;
15228  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error_code, 1, num_atts * sizeof (int));
15229  goto error_exit;
15230  }
15231  for (i = 0; i < num_atts; ++i)
15232  {
15233  new_constraint->prefix_length[i] = c->attrs_prefix_length[i];
15234  }
15235  }
15236 
15237  if (c->filter_predicate != NULL)
15238  {
15239  error_code = sm_save_filter_index_info (&new_constraint->filter_predicate, c->filter_predicate);
15240  if (error_code != NO_ERROR)
15241  {
15242  goto error_exit;
15243  }
15244  }
15245  else
15246  {
15247  new_constraint->filter_predicate = NULL;
15248  }
15249 
15250  if (c->func_index_info != NULL)
15251  {
15252  error_code = sm_save_function_index_info (&new_constraint->func_index_info, c->func_index_info);
15253  if (error_code != NO_ERROR)
15254  {
15255  goto error_exit;
15256  }
15257  }
15258  else
15259  {
15260  new_constraint->func_index_info = NULL;
15261  }
15262 
15263  if (c->type == SM_CONSTRAINT_FOREIGN_KEY)
15264  {
15265  MOP ref_clsop = NULL;
15266  SM_CLASS *ref_cls = NULL;
15267  SM_CLASS_CONSTRAINT *pk_cons = NULL;
15268 
15269  assert (c->fk_info != NULL);
15270  assert (c->fk_info->next == NULL);
15271 
15272  ref_clsop = ws_mop (&(c->fk_info->ref_class_oid), NULL);
15273  if (ref_clsop == NULL)
15274  {
15275  assert (er_errid () != NO_ERROR);
15276  error_code = er_errid ();
15277  goto error_exit;
15278  }
15279  error_code = au_fetch_class_force (ref_clsop, &ref_cls, AU_FETCH_READ);
15280  if (error_code != NO_ERROR)
15281  {
15282  goto error_exit;
15283  }
15284  assert (ref_cls->constraints != NULL);
15285 
15286  new_constraint->ref_cls_name = strdup (sm_ch_name ((MOBJ) ref_cls));
15287  if (new_constraint->ref_cls_name == NULL)
15288  {
15289  error_code = ER_OUT_OF_VIRTUAL_MEMORY;
15290  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error_code, 1, (size_t) (strlen (sm_ch_name ((MOBJ) ref_cls)) + 1));
15291  goto error_exit;
15292  }
15293 
15294  pk_cons = classobj_find_cons_primary_key (ref_cls->constraints);
15295  if (pk_cons == NULL)
15296  {
15297  assert (false);
15298  error_code = ER_FK_REF_CLASS_HAS_NOT_PK;
15299  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error_code, 1, sm_ch_name ((MOBJ) ref_cls));
15300  goto error_exit;
15301  }
15302 
15303  new_constraint->ref_attrs = (char **) calloc (num_atts + 1, sizeof (char *));
15304  if (new_constraint->ref_attrs == NULL)
15305  {
15306  error_code = ER_OUT_OF_VIRTUAL_MEMORY;
15307  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error_code, 1, (num_atts + 1) * sizeof (char *));
15308  goto error_exit;
15309  }
15310 
15311  for (crt_att_p = pk_cons->attributes, i = 0; *crt_att_p != NULL; ++crt_att_p, ++i)
15312  {
15313  const char *const attr_name = (*crt_att_p)->header.name;
15314 
15315  assert (i < num_atts);
15316 
15317  new_constraint->ref_attrs[i] = strdup (attr_name);
15318  if (new_constraint->ref_attrs[i] == NULL)
15319  {
15320  error_code = ER_OUT_OF_VIRTUAL_MEMORY;
15321  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error_code, 1, (size_t) (strlen (attr_name) + 1));
15322  goto error_exit;
15323  }
15324  }
15325 
15326  new_constraint->fk_delete_action = c->fk_info->delete_action;
15327  new_constraint->fk_update_action = c->fk_info->update_action;
15328 
15329  ref_cls = NULL;
15330  ref_clsop = NULL;
15331  }
15332 
15333  assert (new_constraint->next == NULL);
15334  while ((*save_info) != NULL)
15335  {
15336  save_info = &((*save_info)->next);
15337  }
15338  *save_info = new_constraint;
15339 
15340  return error_code;
15341 
15342 error_exit:
15343  if (new_constraint != NULL)
15344  {
15345  sm_free_constraint_info (&new_constraint);
15346  }
15347  return error_code;
15348 }
15349 
15350 /*
15351  * sm_save_function_index_info() - Saves the information necessary to recreate
15352  * a function index constraint
15353  * return: NO_ERROR on success, non-zero for ERROR
15354  * save_info(in/out): The information saved
15355  * func_index_info(in): The function index information to be saved
15356  */
15357 int
15359 {
15360  int error_code = NO_ERROR;
15361  SM_FUNCTION_INFO *new_func_index_info = NULL;
15362 
15363  if (func_index_info != NULL)
15364  {
15365  int len = strlen (func_index_info->expr_str);
15366 
15367  new_func_index_info = (SM_FUNCTION_INFO *) calloc (1, sizeof (SM_FUNCTION_INFO));
15368  if (new_func_index_info == NULL)
15369  {
15370  error_code = ER_OUT_OF_VIRTUAL_MEMORY;
15371  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error_code, 1, sizeof (SM_FUNCTION_INFO));
15372  goto error_exit;
15373  }
15374 
15375  new_func_index_info->fi_domain = tp_domain_copy (func_index_info->fi_domain, true);
15376  if (new_func_index_info->fi_domain == NULL)
15377  {
15378  error_code = ER_FAILED;
15379  goto error_exit;
15380  }
15381 
15382  new_func_index_info->expr_str = (char *) calloc (len + 1, sizeof (char));
15383  if (new_func_index_info->expr_str == NULL)
15384  {
15385  error_code = ER_OUT_OF_VIRTUAL_MEMORY;
15386  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error_code, 1, (len + 1) * sizeof (char));
15387  goto error_exit;
15388  }
15389 
15390  memcpy (new_func_index_info->expr_str, func_index_info->expr_str, len);
15391  new_func_index_info->expr_stream = (char *) calloc (func_index_info->expr_stream_size, sizeof (char));
15392  if (new_func_index_info->expr_stream == NULL)
15393  {
15394  error_code = ER_OUT_OF_VIRTUAL_MEMORY;
15395  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error_code, 1, func_index_info->expr_stream_size * sizeof (char));
15396  goto error_exit;
15397  }
15398  memcpy (new_func_index_info->expr_stream, func_index_info->expr_stream, func_index_info->expr_stream_size);
15399  new_func_index_info->expr_stream_size = func_index_info->expr_stream_size;
15400  new_func_index_info->col_id = func_index_info->col_id;
15401  new_func_index_info->attr_index_start = func_index_info->attr_index_start;
15402  }
15403 
15404  *save_info = new_func_index_info;
15405  return error_code;
15406 
15407 error_exit:
15408  if (new_func_index_info != NULL)
15409  {
15410  sm_free_function_index_info (new_func_index_info);
15411  free_and_init (new_func_index_info);
15412  }
15413  return error_code;
15414 }
15415 
15416 /*
15417  * sm_save_filter_index_info() - Saves the information necessary to recreate a
15418  * filter index constraint
15419  * return: NO_ERROR on success, non-zero for ERROR
15420  * save_info(in/out): The information saved
15421  * filter_index_info(in): The filter index information to be saved
15422  */
15423 int
15425 {
15426  int error_code = NO_ERROR;
15427  SM_PREDICATE_INFO *new_filter_index_info = NULL;
15428  int i, len;
15429 
15430  len = strlen (filter_index_info->pred_string);
15431  new_filter_index_info = (SM_PREDICATE_INFO *) calloc (1, sizeof (SM_PREDICATE_INFO));
15432  if (new_filter_index_info == NULL)
15433  {
15434  error_code = ER_OUT_OF_VIRTUAL_MEMORY;
15435  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error_code, 1, sizeof (SM_PREDICATE_INFO));
15436  goto error_exit;
15437  }
15438 
15439  new_filter_index_info->pred_string = (char *) calloc (len + 1, sizeof (char));
15440  if (new_filter_index_info->pred_string == NULL)
15441  {
15442  error_code = ER_OUT_OF_VIRTUAL_MEMORY;
15443  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error_code, 1, (len + 1) * sizeof (char));
15444  goto error_exit;
15445  }
15446  memcpy (new_filter_index_info->pred_string, filter_index_info->pred_string, len);
15447 
15448  new_filter_index_info->pred_stream = (char *) calloc (filter_index_info->pred_stream_size, sizeof (char));
15449  if (new_filter_index_info->pred_stream == NULL)
15450  {
15451  error_code = ER_OUT_OF_VIRTUAL_MEMORY;
15452  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error_code, 1, new_filter_index_info->pred_stream_size * sizeof (char));
15453  goto error_exit;
15454  }
15455  memcpy (new_filter_index_info->pred_stream, filter_index_info->pred_stream, filter_index_info->pred_stream_size);
15456 
15457  new_filter_index_info->pred_stream_size = filter_index_info->pred_stream_size;
15458 
15459  if (filter_index_info->num_attrs == 0)
15460  {
15461  new_filter_index_info->att_ids = NULL;
15462  }
15463  else
15464  {
15465  new_filter_index_info->att_ids = (int *) calloc (filter_index_info->num_attrs, sizeof (int));
15466  if (new_filter_index_info->att_ids == NULL)
15467  {
15468  error_code = ER_OUT_OF_VIRTUAL_MEMORY;
15469  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error_code, 1, filter_index_info->num_attrs * sizeof (int));
15470  goto error_exit;
15471  }
15472  for (i = 0; i < filter_index_info->num_attrs; i++)
15473  {
15474  new_filter_index_info->att_ids[i] = filter_index_info->att_ids[i];
15475  }
15476 
15477  new_filter_index_info->num_attrs = filter_index_info->num_attrs;
15478  }
15479 
15480  *save_info = new_filter_index_info;
15481  return error_code;
15482 
15483 error_exit:
15484  if (new_filter_index_info != NULL)
15485  {
15486  sm_free_filter_index_info (new_filter_index_info);
15487  free_and_init (new_filter_index_info);
15488  }
15489  return error_code;
15490 }
15491 
15492 /*
15493  * sm_truncate_using_delete() -
15494  * return: error code
15495  * class_mop(in): class (or instance) pointer
15496  */
15497 static int
15499 {
15500  DB_SESSION *session = NULL;
15501  char delete_query[DB_MAX_IDENTIFIER_LENGTH + 64] = { 0 };
15502  int stmt_id = 0;
15503  int error = NO_ERROR;
15504  const char *class_name;
15505  bool save_tr_state;
15506 
15507  class_name = db_get_class_name (class_mop);
15508  if (class_name == NULL)
15509  {
15510  return ER_FAILED;
15511  }
15512 
15513  /* We will run a DELETE statement with triggers disabled. */
15514  save_tr_state = tr_set_execution_state (false);
15515 
15516  (void) snprintf (delete_query, sizeof (delete_query), "DELETE /*+ RECOMPILE */ FROM [%s];", class_name);
15517 
15518  session = db_open_buffer (delete_query);
15519  if (session == NULL)
15520  {
15521  assert (er_errid () != NO_ERROR);
15522  error = er_errid ();
15523  goto end;
15524  }
15525 
15526  if (db_get_errors (session) || db_statement_count (session) != 1)
15527  {
15528  assert (er_errid () != NO_ERROR);
15529  error = er_errid ();
15530  goto end;
15531  }
15532 
15533  stmt_id = db_compile_statement (session);
15534  if (stmt_id != 1)
15535  {
15536  assert (er_errid () != NO_ERROR);
15537  error = er_errid ();
15538  goto end;
15539  }
15540 
15541  error = db_execute_statement_local (session, stmt_id, NULL);
15542  if (error < 0)
15543  {
15544  goto end;
15545  }
15546 
15547  error = NO_ERROR;
15548 
15549 end:
15550  if (session != NULL)
15551  {
15552  db_free_query (session);
15553  db_close_session (session);
15554  }
15555 
15556  (void) tr_set_execution_state (save_tr_state);
15557 
15558  return error;
15559 }
15560 
15561 #if 0
15562 /*
15563  * sm_truncate_using_destroy_heap() -
15564  * return: error code
15565  * class_mop(in): class (or instance) pointer
15566  */
15567 static int
15568 sm_truncate_using_destroy_heap (MOP class_mop)
15569 {
15570  HFID *insts_hfid = NULL;
15571  SM_CLASS *class_ = NULL;
15572  int error = NO_ERROR;
15573  bool reuse_oid = false;
15574  OID *oid = NULL;
15575 
15576  oid = ws_oid (class_mop);
15577  assert (!OID_ISTEMP (oid));
15578 
15579  reuse_oid = sm_is_reuse_oid_class (class_mop);
15580 
15581  error = au_fetch_class (class_mop, &class_, AU_FETCH_WRITE, DB_AUTH_ALTER);
15582  if (error != NO_ERROR || class_ == NULL)
15583  {
15584  assert (er_errid () != NO_ERROR);
15585  return er_errid ();
15586  }
15587 
15588  insts_hfid = sm_ch_heap ((MOBJ) class_);
15589  assert (!HFID_IS_NULL (insts_hfid));
15590 
15591  /* Destroy the heap */
15592  error = heap_destroy_newly_created (insts_hfid);
15593  if (error != NO_ERROR)
15594  {
15595  return error;
15596  }
15597 
15598  HFID_SET_NULL (insts_hfid);
15599  ws_dirty (class_mop);
15600 
15601  error = locator_flush_class (class_mop);
15602  if (error != NO_ERROR)
15603  {
15604  return error;
15605  }
15606 
15607  /* Create a new heap */
15608  error = heap_create (insts_hfid, oid, reuse_oid);
15609  if (error != NO_ERROR)
15610  {
15611  return error;
15612  }
15613 
15614  ws_dirty (class_mop);
15615  error = locator_flush_class (class_mop);
15616 
15617  return error;
15618 }
15619 #endif
15620 
15621 /*
15622  * sm_truncate_class () - truncates a class
15623  * return: NO_ERROR on success, non-zero for ERROR
15624  * class_mop(in):
15625  */
15626 int
15628 {
15629  SM_CLASS *class_ = NULL;
15631  int error = NO_ERROR;
15632  SM_CONSTRAINT_INFO *unique_save_info = NULL;
15633  SM_CONSTRAINT_INFO *fk_save_info = NULL;
15634  SM_CONSTRAINT_INFO *index_save_info = NULL;
15635  SM_CONSTRAINT_INFO *saved = NULL;
15636  DB_CTMPL *ctmpl = NULL;
15637  SM_ATTRIBUTE *att = NULL;
15638  bool keep_pk = false;
15639  int au_save = 0;
15640 
15641  assert (class_mop != NULL);
15642 
15644  if (error != NO_ERROR)
15645  {
15646  return error;
15647  }
15648 
15649  /* We need to flush everything so that the server logs the inserts that happened before the truncate. We need this in
15650  * order to make sure that a rollback takes us into a consistent state. If we can prove that simply discarding the
15651  * objects would work correctly we would be able to remove this call. However, it's better to be safe than sorry. */
15652  error = sm_flush_and_decache_objects (class_mop, true);
15653  if (error != NO_ERROR)
15654  {
15655  goto error_exit;
15656  }
15657 
15658  error = au_fetch_class (class_mop, &class_, AU_FETCH_WRITE, DB_AUTH_ALTER);
15659  if (error != NO_ERROR || class_ == NULL)
15660  {
15661  assert (er_errid () != NO_ERROR);
15662  error = er_errid ();
15663  goto error_exit;
15664  }
15665 
15667  if (c != NULL && classobj_is_pk_referred (class_mop, c->fk_info, false, NULL))
15668  {
15669  /* We need to perform a normal delete operation because we need to execute the FOREIGN KEY actions on the
15670  * referring classes. We also need to keep the PRIMARY KEY constraint in order to correctly perform the FOREIGN
15671  * KEY actions. */
15672  keep_pk = true;
15673  }
15674 
15675  /* collect index information */
15676  for (c = class_->constraints; c; c = c->next)
15677  {
15679  {
15681  continue;
15682  }
15683 
15684  if (keep_pk == true && c->type == SM_CONSTRAINT_PRIMARY_KEY)
15685  {
15686  /* Do not save PK referred by FK. the PK can't be dropped. */
15687  continue;
15688  }
15689 
15690  if (sm_is_possible_to_recreate_constraint (class_mop, class_, c))
15691  {
15692  /* All the OIDs in the index should belong to the current class, so it is safe to drop and create the
15693  * constraint again. We save the information required to recreate the constraint. */
15694 
15696  {
15697  if (sm_save_constraint_info (&unique_save_info, c) != NO_ERROR)
15698  {
15699  goto error_exit;
15700  }
15701  }
15702  else if (c->type == SM_CONSTRAINT_FOREIGN_KEY)
15703  {
15704  if (sm_save_constraint_info (&fk_save_info, c) != NO_ERROR)
15705  {
15706  goto error_exit;
15707  }
15708  }
15709  else
15710  {
15711  if (sm_save_constraint_info (&index_save_info, c) != NO_ERROR)
15712  {
15713  goto error_exit;
15714  }
15715  }
15716  }
15717  }
15718 
15719  /* Drop constraints. It's also faster to do this if we truncate by deleting. */
15720 
15721  /* FK must be dropped earlier than PK, because of self referencing case */
15722  if (fk_save_info != NULL)
15723  {
15724  ctmpl = dbt_edit_class (class_mop);
15725  if (ctmpl == NULL)
15726  {
15727  assert (er_errid () != NO_ERROR);
15728  error = er_errid ();
15729  goto error_exit;
15730  }
15731 
15732  for (saved = fk_save_info; saved != NULL; saved = saved->next)
15733  {
15734  error = dbt_drop_constraint (ctmpl, saved->constraint_type, saved->name, (const char **) saved->att_names, 0);
15735  if (error != NO_ERROR)
15736  {
15737  dbt_abort_class (ctmpl);
15738  goto error_exit;
15739  }
15740  }
15741 
15742  if (dbt_finish_class (ctmpl) == NULL)
15743  {
15744  dbt_abort_class (ctmpl);
15745  assert (er_errid () != NO_ERROR);
15746  error = er_errid ();
15747  goto error_exit;
15748  }
15749  }
15750 
15751  for (saved = unique_save_info; saved != NULL; saved = saved->next)
15752  {
15753  error =
15754  sm_drop_constraint (class_mop, saved->constraint_type, saved->name, (const char **) saved->att_names, 0, false);
15755  if (error != NO_ERROR)
15756  {
15757  goto error_exit;
15758  }
15759  }
15760 
15761  for (saved = index_save_info; saved != NULL; saved = saved->next)
15762  {
15763  error = sm_drop_index (class_mop, saved->name);
15764  if (error != NO_ERROR)
15765  {
15766  goto error_exit;
15767  }
15768  }
15769 
15770 #if 0
15771  if (keep_pk == true && log_does_allow_replication () == true)
15772  {
15773  error = sm_truncate_using_delete (class_mop);
15774  }
15775  else
15776  {
15777  error = sm_truncate_using_destroy_heap (class_mop);
15778  }
15779  if (error != NO_ERROR)
15780  {
15781  goto error_exit;
15782  }
15783 #else
15784  error = sm_truncate_using_delete (class_mop);
15785  if (error != NO_ERROR)
15786  {
15787  goto error_exit;
15788  }
15789 #endif
15790 
15791  /* Normal index must be created earlier than unique constraint or FK, because of shared btree case. */
15792  for (saved = index_save_info; saved != NULL; saved = saved->next)
15793  {
15794  error = sm_add_constraint (class_mop, saved->constraint_type, saved->name, (const char **) saved->att_names,
15795  saved->asc_desc, saved->prefix_length, false, saved->filter_predicate,
15796  saved->func_index_info, saved->comment, saved->index_status);
15797  if (error != NO_ERROR)
15798  {
15799  goto error_exit;
15800  }
15801  }
15802 
15803  /* PK must be created earlier than FK, because of self referencing case */
15804  for (saved = unique_save_info; saved != NULL; saved = saved->next)
15805  {
15806  error = sm_add_constraint (class_mop, saved->constraint_type, saved->name, (const char **) saved->att_names,
15807  saved->asc_desc, saved->prefix_length, false, saved->filter_predicate,
15808  saved->func_index_info, saved->comment, saved->index_status);
15809  if (error != NO_ERROR)
15810  {
15811  goto error_exit;
15812  }
15813  }
15814 
15815  /* To drop all xasl cache related class, we need to touch class. */
15816  ctmpl = dbt_edit_class (class_mop);
15817  if (ctmpl == NULL)
15818  {
15819  assert (er_errid () != NO_ERROR);
15820  error = er_errid ();
15821  goto error_exit;
15822  }
15823 
15824  for (saved = fk_save_info; saved != NULL; saved = saved->next)
15825  {
15826  error = dbt_add_foreign_key (ctmpl, saved->name, (const char **) saved->att_names, saved->ref_cls_name,
15827  (const char **) saved->ref_attrs, saved->fk_delete_action, saved->fk_update_action,
15828  saved->comment);
15829 
15830  if (error != NO_ERROR)
15831  {
15832  dbt_abort_class (ctmpl);
15833  goto error_exit;
15834  }
15835  }
15836 
15837  if (dbt_finish_class (ctmpl) == NULL)
15838  {
15839  dbt_abort_class (ctmpl);
15840  assert (er_errid () != NO_ERROR);
15841  error = er_errid ();
15842  goto error_exit;
15843  }
15844 
15845  /* reset auto_increment starting value */
15846  for (att = db_get_attributes (class_mop); att != NULL; att = db_attribute_next (att))
15847  {
15848  if (att->auto_increment != NULL)
15849  {
15850  AU_DISABLE (au_save);
15852  AU_ENABLE (au_save);
15853 
15854  if (error != NO_ERROR)
15855  {
15856  goto error_exit;
15857  }
15858  }
15859  }
15860 
15861  if (unique_save_info != NULL)
15862  {
15863  sm_free_constraint_info (&unique_save_info);
15864  }
15865 
15866  if (fk_save_info != NULL)
15867  {
15868  sm_free_constraint_info (&fk_save_info);
15869  }
15870 
15871  if (index_save_info != NULL)
15872  {
15873  sm_free_constraint_info (&index_save_info);
15874  }
15875 
15876  return NO_ERROR;
15877 
15878 error_exit:
15879 
15880  if (error != ER_LK_UNILATERALLY_ABORTED)
15881  {
15883  }
15884 
15885  if (unique_save_info != NULL)
15886  {
15887  sm_free_constraint_info (&unique_save_info);
15888  }
15889 
15890  if (fk_save_info != NULL)
15891  {
15892  sm_free_constraint_info (&fk_save_info);
15893  }
15894 
15895  if (index_save_info != NULL)
15896  {
15897  sm_free_constraint_info (&index_save_info);
15898  }
15899 
15900  return error;
15901 }
15902 
15903 /*
15904  * sm_has_non_null_attribute () - check if whether there is at least
15905  * one non null constraint in a given
15906  * attribute pointer array
15907  * return: 1 if it exists, otherwise 0
15908  * attrs(in): null terminated array of SM_ATTRIBUTE *
15909  */
15910 int
15912 {
15913  int i;
15914 
15915  assert (attrs != NULL);
15916 
15917  for (i = 0; attrs[i] != NULL; i++)
15918  {
15919  if (attrs[i]->flags & SM_ATTFLAG_NON_NULL)
15920  {
15921  return 1;
15922  }
15923  }
15924 
15925  return 0;
15926 }
15927 
15928 /*
15929  * filter_local_constraints () - filter constrains which were dropped from the
15930  * inherited class
15931  * return : error code or NO_ERROR
15932  * template_ (in/out) : class template
15933  * super_class (in) : superclass
15934  */
15935 static int
15936 filter_local_constraints (SM_TEMPLATE * template_, SM_CLASS * super_class)
15937 {
15938  SM_CLASS_CONSTRAINT *old_constraints = NULL, *new_constraints = NULL;
15939  SM_CLASS_CONSTRAINT *c, *new_con;
15940  DB_SEQ *seq;
15941  DB_VALUE oldval, newval;
15942  int error = NO_ERROR, found = 0;
15943  int is_global_index = 0;
15944 
15945  assert_release (template_ != NULL);
15946  assert_release (super_class != NULL);
15947  if (template_ == NULL || super_class == NULL)
15948  {
15949  return ER_FAILED;
15950  }
15951 
15952  if (super_class->new_ == NULL)
15953  {
15954  /* superclass was not edited, nothing to do here */
15955  return NO_ERROR;
15956  }
15957 
15958  db_make_null (&oldval);
15959  db_make_null (&newval);
15960 
15961  /* get old constraints */
15962  error = classobj_make_class_constraints (super_class->properties, super_class->attributes, &old_constraints);
15963  if (error != NO_ERROR)
15964  {
15966  error = ER_SM_INVALID_PROPERTY;
15967  goto cleanup;
15968  }
15969 
15970  /* get new constraints */
15971  error =
15972  classobj_make_class_constraints (super_class->new_->properties, super_class->new_->attributes, &new_constraints);
15973  if (error != NO_ERROR)
15974  {
15976  error = ER_SM_INVALID_PROPERTY;
15977  goto cleanup;
15978  }
15979 
15980  for (c = old_constraints; c != NULL; c = c->next)
15981  {
15984  {
15985  continue;
15986  }
15987  is_global_index = 0;
15988  error = sm_is_global_only_constraint (template_->op, c, &is_global_index, template_);
15989  if (error != NO_ERROR)
15990  {
15991  goto cleanup;
15992  }
15993  if (c->type != SM_CONSTRAINT_FOREIGN_KEY && is_global_index == 1)
15994  {
15995  continue;
15996  }
15997 
15998  /* search for this constraint in the new constraints */
15999  new_con = classobj_find_class_constraint (new_constraints, c->type, c->name);
16000 
16001  if (new_con == NULL)
16002  {
16003  /* drop this constraint from the template since it was dropped from the superclass */
16004  found = classobj_get_prop (template_->properties, classobj_map_constraint_to_property (c->type), &oldval);
16005  if (found == 0)
16006  {
16007  ERROR1 (error, ER_SM_CONSTRAINT_NOT_FOUND, c->name);
16008  goto cleanup;
16009  }
16010 
16011  seq = db_get_set (&oldval);
16012  found = classobj_drop_prop (seq, c->name);
16013  if (found == 0)
16014  {
16015  error = er_errid ();
16016  if (error != NO_ERROR)
16017  {
16018  goto cleanup;
16019  }
16020  }
16021 
16022  db_make_sequence (&newval, seq);
16023 
16025 
16026  pr_clear_value (&oldval);
16027  pr_clear_value (&newval);
16028  }
16029  }
16030 
16031 cleanup:
16032  classobj_free_class_constraints (old_constraints);
16033  classobj_free_class_constraints (new_constraints);
16034 
16035  pr_clear_value (&oldval);
16036  pr_clear_value (&newval);
16037 
16038  return error;
16039 }
16040 
16041 /*
16042  * sm_free_function_index_info () -
16043  */
16044 void
16046 {
16047  assert (func_index_info != NULL);
16048 
16049  if (func_index_info->expr_str != NULL)
16050  {
16051  free_and_init (func_index_info->expr_str);
16052  }
16053 
16054  if (func_index_info->expr_stream != NULL)
16055  {
16056  free_and_init (func_index_info->expr_stream);
16057  }
16058 
16059  if (func_index_info->fi_domain != NULL)
16060  {
16061  tp_domain_free (func_index_info->fi_domain);
16062  func_index_info->fi_domain = NULL;
16063  }
16064 }
16065 
16066 /*
16067  * sm_free_filter_index_info () -
16068  */
16069 void
16071 {
16072  assert (filter_index_info != NULL);
16073 
16074  if (filter_index_info->pred_string)
16075  {
16076  free_and_init (filter_index_info->pred_string);
16077  }
16078  if (filter_index_info->pred_stream)
16079  {
16080  free_and_init (filter_index_info->pred_stream);
16081  }
16082  if (filter_index_info->att_ids)
16083  {
16084  free_and_init (filter_index_info->att_ids);
16085  }
16086 }
16087 
16088 /*
16089  * sm_is_global_only_constraint () - verify if this constraint must be global
16090  * across a class hierarchy
16091  * return : whether is global, local or error code
16092  * classmop (in) : the class to which this constraint belongs to
16093  * constraint (in) : constraint
16094  * Note:
16095  * SM_CONSTRAINT_INDEX - always local
16096  * SM_CONSTRAINT_REVERSE_INDEX - always local
16097  * SM_CONSTRAINT_FOREIGN_KEY - always local
16098  * SM_CONSTRAINT_UNIQUE - global unless this is a partitioned class
16099  * SM_CONSTRAINT_REVERSE_UNIQUE - same as SM_CONSTRAINT_UNIQUE
16100  * SM_CONSTRAINT_PRIMARY_KEY - always global unless this is a partitioned
16101  * class
16102  */
16103 int
16104 sm_is_global_only_constraint (MOP classmop, SM_CLASS_CONSTRAINT * constraint, int *is_global, SM_TEMPLATE * template_)
16105 {
16106  SM_ATTRIBUTE *attr = NULL;
16107  int i = 0;
16108  bool has_partition = false;
16109 
16110  *is_global = 0;
16111 
16112  if (constraint == NULL)
16113  {
16114  assert_release (constraint != NULL);
16115  return 0;
16116  }
16117 
16118  switch (constraint->type)
16119  {
16120  case SM_CONSTRAINT_UNIQUE:
16122  /* not enough information yet */
16123  break;
16124  case SM_CONSTRAINT_INDEX:
16128  /* always local */
16129  *is_global = 0;
16130  return NO_ERROR;
16132  /* always global */
16133  break;
16134  }
16135 
16136  /* the condition for unique indexes on partitions has already been checked during the creation of the B-tree */
16137 
16138  assert (constraint->attributes != NULL);
16139 
16140  attr = constraint->attributes[0];
16141  i = 0;
16142  has_partition = false;
16143  while (attr != NULL)
16144  {
16145  if (attr->flags & SM_ATTFLAG_PARTITION_KEY)
16146  {
16147  has_partition = true;
16148  break;
16149  }
16150  i++;
16151  attr = constraint->attributes[i];
16152  }
16153 
16154  if (has_partition == true
16155  && (template_ == NULL || (template_->inheritance == NULL && template_->partition_parent_atts == NULL)
16156  || template_->partition != NULL))
16157  {
16158  *is_global = 0;
16159  return NO_ERROR;
16160  }
16161 
16162  if (template_ != NULL)
16163  {
16164  if (template_->inheritance != NULL && template_->partition_parent_atts != NULL)
16165  {
16166  *is_global = 0;
16167  return NO_ERROR;
16168  }
16169  }
16170 
16171  *is_global = 1;
16172  return NO_ERROR;
16173 }
16174 
16175 /*
16176  * sm_find_class_in_hierarchy() - find class in hierarchy
16177  *
16178  * return: error code
16179  * hierarchy(in): the hierarchy
16180  * classop(in): class to find into hierarchy
16181  * found(out): true if founded, false otherwise
16182  */
16183 int
16184 sm_find_subclass_in_hierarchy (MOP hierarchy, MOP class_mop, bool * found)
16185 {
16186  SM_CLASS *class_ = NULL;
16187  DB_OBJLIST *subclass = NULL;
16188  int error;
16189 
16190  assert (found != NULL && hierarchy != NULL && class_mop != NULL);
16191 
16192  *found = false;
16193 
16194  error = au_fetch_class_by_classmop (hierarchy, &class_, AU_FETCH_READ, AU_SELECT);
16195  if (error != NO_ERROR)
16196  {
16197  return error;
16198  }
16199 
16200  for (subclass = class_->users; subclass != NULL; subclass = subclass->next)
16201  {
16202  if (ws_mop_compare (subclass->op, class_mop) == 0)
16203  {
16204  *found = true;
16205  return NO_ERROR;
16206  }
16207  }
16208 
16209  for (subclass = class_->users; subclass != NULL; subclass = subclass->next)
16210  {
16211  error = sm_find_subclass_in_hierarchy (subclass->op, class_mop, found);
16212  if (error != NO_ERROR)
16213  {
16214  return error;
16215  }
16216 
16217  if (*found == true)
16218  {
16219  return NO_ERROR;
16220  }
16221  }
16222 
16223  return NO_ERROR;
16224 }
16225 
16226 /*
16227  * update_fk_ref_partitioned_class () - This function renames
16228  * constraints in sub-classes(partition classes).
16229  * return: NO_ERROR on success, non-zero for ERROR
16230  * ctemplate(in): sm_template of the super class (partition class)
16231  * fk_info(in): foreign key reference info of super class (partition class)
16232  * btid(in): btid of the foreign key reference
16233  * old_name(in):
16234  * new_name(in):
16235  */
16236 static int
16238  const char *old_name, const char *new_name)
16239 {
16240  int error = NO_ERROR;
16241  int i, is_partition = 0;
16242  MOP *sub_partitions = NULL;
16243  SM_TEMPLATE *sub_ctemplate = NULL;
16244  SM_CLASS_CONSTRAINT *sm_cons = NULL;
16245  SM_CLASS_CONSTRAINT *pk = NULL;
16246  SM_FOREIGN_KEY_INFO *fk = NULL;
16247 
16248  assert (ctemplate != NULL);
16249 
16250  error = sm_partitioned_class_type (ctemplate->op, &is_partition, NULL, &sub_partitions);
16251  if (error != NO_ERROR)
16252  {
16253  goto error_exit;
16254  }
16255 
16256  if (is_partition == DB_PARTITION_CLASS)
16257  {
16259  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 0);
16260  goto error_exit;
16261  }
16262  else if (is_partition == DB_NOT_PARTITIONED_CLASS)
16263  {
16264  goto end;
16265  }
16266 
16267  assert (is_partition == DB_PARTITIONED_CLASS);
16268 
16269  for (i = 0; sub_partitions[i] != 0; i++)
16270  {
16271  sub_ctemplate = smt_edit_class_mop (sub_partitions[i], AU_INDEX);
16272  if (sub_ctemplate == NULL)
16273  {
16274  assert (er_errid () != NO_ERROR);
16275  error = er_errid ();
16276  assert (error != NO_ERROR);
16277  goto error_exit;
16278  }
16279 
16280  /* make a list of constraints that is included in the partitioned class. */
16281  error = classobj_make_class_constraints (sub_ctemplate->properties, sub_ctemplate->attributes, &sm_cons);
16282  if (error != NO_ERROR)
16283  {
16284  goto error_exit;
16285  }
16286 
16287  if (sm_cons == NULL)
16288  {
16290  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 1, old_name);
16291  goto error_exit;
16292  }
16293 
16294  if (old_name != NULL)
16295  {
16296  pk = classobj_find_cons_primary_key (sm_cons);
16297  if (pk == NULL)
16298  {
16299  assert (false);
16300 
16302  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 1, sm_get_ch_name (ctemplate->op));
16303  goto error_exit;
16304  }
16305 
16306  for (fk = pk->fk_info; fk != NULL; fk = fk->next)
16307  {
16308  if (fk->name != NULL && intl_identifier_casecmp (fk->name, old_name) == 0)
16309  {
16310  break;
16311  }
16312  }
16313 
16314  if (fk == NULL)
16315  {
16317  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 1, old_name);
16318  goto error_exit;
16319  }
16320  }
16321 
16322 #if defined (ENABLE_RENAME_CONSTRAINT)
16323  if (old_name != NULL && new_name != NULL)
16324  {
16325  error = classobj_rename_foreign_key_ref (&sub_ctemplate->properties, btid, old_name, new_name);
16326  if (error != NO_ERROR)
16327  {
16328  goto error_exit;
16329  }
16330  }
16331  else
16332 #endif
16333  {
16334  /* disable rename constraint */
16335  assert (new_name == NULL);
16336 
16337  if (fk_info != NULL)
16338  {
16339  error = classobj_put_foreign_key_ref (&sub_ctemplate->properties, fk_info);
16340  if (error != NO_ERROR)
16341  {
16342  goto error_exit;
16343  }
16344  }
16345  else if (btid != NULL)
16346  {
16347  error = classobj_drop_foreign_key_ref (&sub_ctemplate->properties, btid, old_name);
16348  if (error != NO_ERROR)
16349  {
16350  goto error_exit;
16351  }
16352  }
16353  else
16354  {
16355  assert (false);
16356  }
16357  }
16358 
16359  if (sm_cons)
16360  {
16362  sm_cons = NULL;
16363  }
16364 
16365  /* classobj_free_template() is included in sm_update_class() */
16366  error = sm_update_class (sub_ctemplate, NULL);
16367  if (error != NO_ERROR)
16368  {
16369  /* Even though sm_update() did not return NO_ERROR, sub_ctemplate is already freed */
16370  sub_ctemplate = NULL;
16371  goto error_exit;
16372  }
16373  }
16374 
16375 end:
16376  if (sub_partitions != NULL)
16377  {
16378  free_and_init (sub_partitions);
16379  }
16380  return error;
16381 
16382 error_exit:
16383  if (sm_cons)
16384  {
16386  }
16387  if (sub_ctemplate != NULL)
16388  {
16389  /* smt_quit() always returns NO_ERROR */
16390  smt_quit (sub_ctemplate);
16391  }
16392  goto end;
16393 }
16394 
16395 /*
16396  * flatten_partition info() - Flatten partition info structure. Currently, it
16397  * can not be a list.
16398  * return: NO_ERROR on success, non-zero for ERROR
16399  * def(in): schema template
16400  * flat(out): flattened template
16401  */
16402 
16403 static int
16405 {
16406  if (def->partition == NULL)
16407  {
16408  flat->partition = NULL;
16409  }
16410  else
16411  {
16413  if (flat->partition == NULL)
16414  {
16415  assert (er_errid () != NO_ERROR);
16416  return er_errid ();
16417  }
16418  }
16419 
16420  return NO_ERROR;
16421 }
16422 
16423 int
16424 sm_load_online_index (MOP classmop, const char *constraint_name)
16425 {
16426  SM_CLASS *class_ = NULL, *subclass_ = NULL;
16427  int error = NO_ERROR;
16428  SM_CLASS_CONSTRAINT *con = NULL;
16429  TP_DOMAIN *domain;
16430  int i, n_attrs, n_classes, max_classes;
16431  DB_TYPE type;
16432  DB_OBJLIST *subclasses, *sub;
16433  int *attr_ids = NULL;
16434  size_t attr_ids_size;
16435  OID *oids = NULL;
16436  HFID *hfids = NULL;
16437  int reverse;
16438  int unique_pk = 0;
16439  int not_null = 0;
16440 
16441  /* Fetch the class. */
16442  error = au_fetch_class (classmop, &class_, AU_FETCH_UPDATE, AU_ALTER);
16443  if (error != NO_ERROR)
16444  {
16445  goto error_return;
16446  }
16447 
16448  /* Get subclasses. */
16449  subclasses = class_->users;
16450 
16451  /* Get the constraint on which we want to load the online index. */
16452  con = classobj_find_constraint_by_name (class_->constraints, constraint_name);
16453  if (con == NULL)
16454  {
16455  /* This should never happen. */
16456  error = ER_FAILED;
16457  goto error_return;
16458  }
16459 
16460  /* Safeguards. */
16461  assert (con != NULL);
16463 
16464  /* We must check if the constraint isn't shared from another one. */
16465  if (con->shared_cons_name != NULL)
16466  {
16467  /* The BTID already exists and surely it has been loaded. Therefore we can just stop here */
16468  return NO_ERROR;
16469  }
16470 
16471  /* Count the attributes */
16472  for (i = 0, n_attrs = 0; con->attributes[i] != NULL; i++, n_attrs++)
16473  {
16474  type = con->attributes[i]->type->id;
16475  if (!tp_valid_indextype (type))
16476  {
16477  error = ER_SM_INVALID_INDEX_TYPE;
16479  }
16480  else if (con->attrs_prefix_length && con->attrs_prefix_length[i] >= 0)
16481  {
16482  if (!TP_IS_CHAR_TYPE (type) && !TP_IS_BIT_TYPE (type))
16483  {
16486  }
16487  else if (((long) con->attributes[i]->domain->precision) < con->attrs_prefix_length[i])
16488  {
16491  }
16492  }
16493  }
16494 
16495  if (error != NO_ERROR)
16496  {
16497  goto error_return;
16498  }
16499 
16500  if (con->func_index_info)
16501  {
16502  if (con->func_index_info->attr_index_start == 0)
16503  {
16504  /* if this is a single column function index, the key domain is actually the domain of the function
16505  * result */
16506  domain = con->func_index_info->fi_domain;
16507  }
16508  else
16509  {
16510  domain =
16513  con->func_index_info->fi_domain);
16514  }
16515  }
16516  else
16517  {
16518  domain = construct_index_key_domain (n_attrs, con->attributes, con->asc_desc, con->attrs_prefix_length, -1, NULL);
16519  }
16520 
16521  /* Count maximum possible subclasses */
16522  max_classes = 1; /* Start with 1 for the current class */
16523  for (sub = subclasses; sub != NULL; sub = sub->next)
16524  {
16525  max_classes++;
16526  }
16527 
16528  /* Allocate arrays to hold subclass information */
16529  attr_ids_size = max_classes * n_attrs * sizeof (int);
16530  attr_ids = (int *) malloc (attr_ids_size);
16531  if (attr_ids == NULL)
16532  {
16534  goto error_return;
16535  }
16536 
16537  oids = (OID *) malloc (max_classes * sizeof (OID));
16538  if (oids == NULL)
16539  {
16540  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, max_classes * sizeof (OID));
16541  goto error_return;
16542  }
16543 
16544  hfids = (HFID *) malloc (max_classes * sizeof (HFID));
16545  if (hfids == NULL)
16546  {
16547  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, max_classes * sizeof (HFID));
16548  goto error_return;
16549  }
16550 
16551  /* Enter the base class information into the arrays */
16552  n_classes = 0;
16553  COPY_OID (&oids[n_classes], WS_OID (classmop));
16554  for (i = 0; i < n_attrs; i++)
16555  {
16556  attr_ids[i] = con->attributes[i]->id;
16557  }
16558  HFID_COPY (&hfids[n_classes], sm_ch_heap ((MOBJ) class_));
16559  n_classes++;
16560 
16561  for (sub = subclasses; sub != NULL; sub = sub->next, n_classes++)
16562  {
16563  error = au_fetch_class (sub->op, &subclass_, AU_FETCH_UPDATE, AU_ALTER);
16564  if (error != NO_ERROR)
16565  {
16566  ASSERT_ERROR ();
16567  goto error_return;
16568  }
16569 
16570  COPY_OID (&oids[n_classes], WS_OID (sub->op));
16571 
16572  for (int j = 0; j < n_attrs; j++)
16573  {
16574  attr_ids[n_classes * n_attrs + j] = con->attributes[j]->id;
16575  }
16576 
16577  HFID_COPY (&hfids[n_classes], sm_ch_heap ((MOBJ) subclass_));
16578 
16579  subclass_ = NULL;
16580  }
16581 
16583  {
16584  reverse = 1;
16585  }
16586  else
16587  {
16588  reverse = 0;
16589  }
16590 
16592  {
16593  unique_pk = BTREE_CONSTRAINT_UNIQUE;
16594  not_null = 0;
16595  }
16596  else if (con->type == SM_CONSTRAINT_PRIMARY_KEY)
16597  {
16599  not_null = 1;
16600  }
16601 
16602  if (con->func_index_info)
16603  {
16604  error = btree_load_index (&con->index_btid, constraint_name, domain, oids, n_classes, n_attrs, attr_ids,
16605  (int *) con->attrs_prefix_length, hfids, unique_pk, not_null, NULL,
16610  con->index_status);
16611  }
16612  else
16613  {
16614  error = btree_load_index (&con->index_btid, constraint_name, domain, oids, n_classes, n_attrs, attr_ids,
16615  (int *) con->attrs_prefix_length, hfids, unique_pk, not_null, NULL,
16618  con->index_status);
16619  }
16620 
16621  if (error != NO_ERROR)
16622  {
16623  goto error_return;
16624  }
16625 
16626  free_and_init (attr_ids);
16627  free_and_init (oids);
16628  free_and_init (hfids);
16629 
16630  return error;
16631 
16632 error_return:
16633  if (attr_ids != NULL)
16634  {
16635  free_and_init (attr_ids);
16636  }
16637  if (oids != NULL)
16638  {
16639  free_and_init (oids);
16640  }
16641  if (hfids != NULL)
16642  {
16643  free_and_init (hfids);
16644  }
16645 
16646  return error;
16647 }
16648 
16649 /*
16650  * sm_is_index_visible () - Check if the index represented by the BTID is visible.
16651  * return - bool
16652  * constraint_list (in) - The list of constraints to look into.
16653  * btid (in) - BTID to look for
16654  */
16655 bool
16657 {
16658  int error_code = NO_ERROR;
16659  SM_CLASS_CONSTRAINT *constr;
16660 
16661  for (constr = constraint_list; constr != NULL; constr = constr->next)
16662  {
16663  /* Iterate through all constraints. */
16664  if (BTID_IS_EQUAL (&constr->index_btid, &btid))
16665  {
16666  break;
16667  }
16668  }
16669 
16670  /* We should always find the constraint. */
16671  if (constr == NULL)
16672  {
16673  assert (false);
16674  return false;
16675  }
16676  else
16677  {
16678  return (constr->index_status == SM_NORMAL_INDEX);
16679  }
16680 }
16681 
16682 /*
16683  * sm_domain_free () -
16684  * return:
16685  * ptr(in) : pointer to a schema manager domain
16686  *
16687  * Note: Free function for SM_DOMAIN using free_and_init.
16688  */
16689 void
16691 {
16692  if (ptr != NULL)
16693  {
16694  sm_domain_free (ptr->next);
16695  sm_domain_free (ptr->setdomain);
16696  free_and_init (ptr);
16697  }
16698 }
16699 
16700 SM_DOMAIN *
16702 {
16703  return (SM_DOMAIN *) malloc (sizeof (SM_DOMAIN));
16704 }
16705 
16706 /*
16707  * sm_domain_copy () -
16708  * return: SM_DOMAIN *
16709  * ptr(in) : pointer to a schema manager domain
16710  *
16711  * Note: Copy function for SM_DOMAIN.
16712  */
16713 SM_DOMAIN *
16715 {
16716  SM_DOMAIN *new_ptr;
16717 
16718  if (ptr == NULL)
16719  {
16720  return NULL;
16721  }
16722 
16723  new_ptr = sm_domain_alloc ();
16724  if (new_ptr == NULL)
16725  {
16726  return NULL;
16727  }
16728  *new_ptr = *ptr;
16729 
16730  if (ptr->next != NULL)
16731  {
16732  new_ptr->next = sm_domain_copy (ptr->next);
16733  if (new_ptr->next == NULL)
16734  {
16735  free_and_init (new_ptr);
16736  return NULL;
16737  }
16738  }
16739 
16740  if (ptr->setdomain != NULL)
16741  {
16742  new_ptr->setdomain = sm_domain_copy (ptr->setdomain);
16743  if (new_ptr->setdomain == NULL)
16744  {
16745  sm_domain_free (new_ptr->next);
16746  new_ptr->next = NULL;
16747  free_and_init (new_ptr);
16748  return NULL;
16749  }
16750  }
16751 
16752  return new_ptr;
16753 }
#define CT_ATTRIBUTE_NAME
Definition: transform.h:120
struct tr_schema_cache * triggers
Definition: class_object.h:463
bool sm_has_indexes(MOBJ classobj)
char * sm_produce_constraint_name_tmpl(SM_TEMPLATE *tmpl, DB_CONSTRAINT_TYPE constraint_type, const char **att_names, const int *asc_desc, const char *given_name)
static bool sm_is_nested_view_recached(PARSER_CONTEXT *parser)
unsigned decached
Definition: work_space.h:152
DB_OBJECT * db_find_class(const char *name)
Definition: db_info.c:133
static DB_OBJLIST * sm_fetch_all_objects_internal(DB_OBJECT *op, DB_FETCH_MODE purpose, LC_FETCH_VERSION_TYPE *force_fetch_version_type)
LC_FETCH_VERSION_TYPE
Definition: locator.h:178
int char_isspace(int c)
Definition: chartype.c:109
#define ROOTCLASS_NAME
Definition: oid.h:32
const char * name
Definition: class_object.h:631
#define ER_LK_UNILATERALLY_ABORTED
Definition: error_code.h:130
SM_ATTRIBUTE * shared
Definition: class_object.h:722
static bool is_index_owner(MOP classop, SM_CLASS_CONSTRAINT *con)
int sm_is_subclass(MOP classmop, MOP supermop)
int btree_load_index(BTID *btid, const char *bt_name, TP_DOMAIN *key_type, OID *class_oids, int n_classes, int n_attrs, int *attr_ids, int *attrs_prefix_length, HFID *hfids, int unique_pk, int not_null_flag, OID *fk_refcls_oid, BTID *fk_refcls_pk_btid, const char *fk_name, char *pred_stream, int pred_stream_size, char *expr_stream, int expr_stream_size, int func_col_id, int func_attr_index_start, SM_INDEX_STATUS index_status)
#define CT_DATATYPE_NAME
Definition: transform.h:131
#define OR_BTID_ALIGNED_SIZE
WS_OBJECT_HEADER ch_obj_header
Definition: class_object.h:347
#define ER_SM_ATTRIBUTE_NOT_FOUND
Definition: error_code.h:311
int ml_append(DB_OBJLIST **list, MOP mop, int *added_ptr)
Definition: work_space.c:4548
int tp_domain_disk_size(TP_DOMAIN *domain)
int btree_add_index(BTID *btid, TP_DOMAIN *key_type, OID *class_oid, int attr_id, int unique_pk)
int db_execute_statement_local(DB_SESSION *session, int stmt, DB_QUERY_RESULT **result)
Definition: db_vdb.c:2939
static int rem_class_from_index(OID *oid, BTID *index, HFID *heap)
void * handle
DB_CONSTRAINT_TYPE constraint_type
int tran_system_savepoint(const char *savept_name)
bool classobj_has_unique_constraint(SM_CONSTRAINT *constraints)
OID * oid_Root_class_oid
Definition: oid.c:73
char * or_pack_btid(char *buf, const BTID *btid)
int sm_destroy_representations(MOP op)
#define CT_CLASSAUTH_NAME
Definition: transform.h:130
int tr_delete_triggers_for_class(TR_SCHEMA_CACHE **cache, DB_OBJECT *class_object)
#define WS_IS_DELETED(mop)
Definition: work_space.h:284
int sm_check_object_domain(TP_DOMAIN *domain, MOP object)
int tr_drop_cache_trigger(TR_SCHEMA_CACHE *cache, DB_OBJECT *trigger_object)
#define NO_ERROR
Definition: error_code.h:46
int sm_touch_class(MOP classmop)
int set_get_element_nocopy(DB_COLLECTION *set, int index, DB_VALUE *value)
Definition: set_object.c:2616
static char * sm_default_constraint_name(const char *class_name, DB_CONSTRAINT_TYPE type, const char **att_names, const int *asc_desc)
void mq_free_virtual_query_cache(PARSER_CONTEXT *parser)
static int alter_trigger_hierarchy(DB_OBJECT *classop, const char *attribute, int class_attribute, DB_OBJECT *target_class, DB_OBJECT *trigger, int drop_it)
#define AU_DISABLE(save)
Definition: authenticate.h:106
static int flatten_components(SM_TEMPLATE *def, SM_TEMPLATE *flat, SM_NAME_SPACE name_space, int auto_res)
int tr_delete_schema_cache(TR_SCHEMA_CACHE *cache, DB_OBJECT *class_object)
static int sm_load_online_index(MOP classmop, const char *constraint_name)
#define DB_MAX_SCHEMA_LENGTH
Definition: dbtype_def.h:503
DB_COLLECTION * db_get_set(const DB_VALUE *value)
void er_stack_push(void)
int dbt_add_foreign_key(DB_CTMPL *def, const char *constraint_name, const char **attnames, const char *ref_class, const char **ref_attrs, int del_action, int upd_action, const char *comment)
Definition: db_temp.c:524
#define DB_IS_CONSTRAINT_UNIQUE_FAMILY(c)
Definition: dbtype_def.h:170
#define ER_SM_INVALID_RESOLUTION
Definition: error_code.h:370
static void sm_free_function_nlist(struct nlist *namelist)
NESTED_VIEW_VERSION_INFO * next
Definition: parse_tree.h:1722
int sm_att_id(MOP classop, const char *name)
static int lock_supers_drop(DB_OBJLIST *supers)
int sm_is_system_class(MOP op)
SM_CLASS * current
Definition: class_object.h:783
int sm_add_constraint(MOP classop, DB_CONSTRAINT_TYPE constraint_type, const char *constraint_name, const char **att_names, const int *asc_desc, const int *attrs_prefix_length, int class_attributes, SM_PREDICATE_INFO *filter_index, SM_FUNCTION_INFO *function_index, const char *comment, SM_INDEX_STATUS index_status)
bool sm_att_auto_increment(MOP classop, const char *name)
#define CTV_METHFILE_NAME
Definition: transform.h:156
SM_CLASS * classobj_make_class(const char *name)
#define SM_MAP_CONSTRAINT_TO_ATTFLAG(c)
Definition: class_object.h:93
SM_FOREIGN_KEY_INFO * fk_info
Definition: class_object.h:537
static int update_class(SM_TEMPLATE *template_, MOP *classmop, int auto_res, DB_AUTH auth, bool needs_hierarchy_lock)
int tr_merge_schema_cache(TR_SCHEMA_CACHE *destination, TR_SCHEMA_CACHE *source)
static STATIC_METHOD * sm_find_static_method(const char *name)
int btree_class_test_unique(char *buf, int buf_size)
void classobj_free_method(SM_METHOD *meth)
#define ASSERT_ERROR()
static void fixup_method_self_domains(SM_METHOD *meth, MOP self)
DB_OBJLIST * inheritance
Definition: class_object.h:718
static SM_CANDIDATE * get_candidates(SM_TEMPLATE *def, SM_TEMPLATE *flat, SM_NAME_SPACE name_space)
const char * db_get_class_name(DB_OBJECT *class_)
Definition: db_info.c:608
void sm_bump_global_schema_version(void)
void * parser_alloc(const PARSER_CONTEXT *parser, const int length)
Definition: parse_tree.c:951
BTID * sm_find_index(MOP classop, char **att_names, int num_atts, bool unique_index_only, bool skip_prefix_index, BTID *btid)
MOP ws_mop(const OID *oid, MOP class_mop)
Definition: work_space.c:614
enum au_fetchmode AU_FETCHMODE
int smt_quit(SM_TEMPLATE *template_)
static int sm_link_static_method(SM_METHOD *method, METHOD_LINK **link_ptr)
DB_ATTRIBUTE * db_get_attributes(DB_OBJECT *obj)
Definition: db_info.c:908
int do_reset_auto_increment_serial(MOP serial_obj)
int sm_decache_mop(MOP mop, void *info)
bool sm_is_index_visible(SM_CLASS_CONSTRAINT *constraint_list, BTID btid)
SM_COMPONENT header
Definition: class_object.h:591
SM_PREDICATE_INFO * filter_predicate
Definition: class_object.h:536
int dbt_drop_constraint(DB_CTMPL *def, DB_CONSTRAINT_TYPE constraint_type, const char *constraint_name, const char **attnames, int class_attributes)
Definition: db_temp.c:473
int tran_unilaterally_abort(void)
unsigned char codeset
Definition: object_domain.h:91
#define SM_GET_FILTER_PRED_STREAM(filter)
Definition: class_object.h:162
int obj_delete(MOP op)
int classobj_install_template(SM_CLASS *class_, SM_TEMPLATE *flat, int saverep)
char * MOBJ
Definition: work_space.h:174
int classobj_put_index(DB_SEQ **properties, SM_CONSTRAINT_TYPE type, const char *constraint_name, SM_ATTRIBUTE **atts, const int *asc_desc, const int *attr_prefix_length, const BTID *id, SM_PREDICATE_INFO *filter_index_info, SM_FOREIGN_KEY_INFO *fk_info, char *shared_cons_name, SM_FUNCTION_INFO *func_index_info, const char *comment, SM_INDEX_STATUS index_status, bool attr_name_instead_of_id)
Definition: class_object.c:976
bool tr_get_execution_state(void)
int sm_att_in_unique_filter_constraint_predicate(MOP classop, const char *name)
static DOMAIN_COMP compare_component_domains(SM_COMPONENT *c1, SM_COMPONENT *c2)
int tr_add_cache_trigger(TR_SCHEMA_CACHE *cache, DB_OBJECT *trigger_object)
#define CT_METHOD_NAME
Definition: transform.h:122
int sm_mark_system_class(MOP classop, int on_or_off)
#define ER_SM_RESOLUTION_OVERRIDE
Definition: error_code.h:351
PT_NODE * pt_class_pre_fetch(PARSER_CONTEXT *parser, PT_NODE *statement)
Definition: compile.c:431
static int transfer_disk_structures(MOP classop, SM_CLASS *class_, SM_TEMPLATE *flat)
static int annotate_method_files(MOP classmop, SM_CLASS *class_)
#define ERROR4(error, code, arg1, arg2, arg3, arg4)
Definition: error_manager.h:80
int stats_update_all_statistics(int with_fullscan)
SM_ATTRIBUTE * classobj_find_attribute_list(SM_ATTRIBUTE *attlist, const char *name, int id)
DB_ATTRIBUTE * partition_parent_atts
Definition: class_object.h:813
char * intl_mbs_chr(const char *mbs, wchar_t wc)
Definition: intl_support.c:149
const char * name
Definition: class_object.h:616
int sm_update_all_statistics(bool with_fullscan)
void ws_dirty(MOP op)
Definition: work_space.c:1622
SM_METATYPE ch_type
Definition: class_object.h:349
#define ER_HEAP_NODATA_NEWADDRESS
Definition: error_code.h:107
int sm_truncate_class(MOP class_mop)
DB_TYPE
Definition: dbtype_def.h:670
#define CTV_ATTR_SD_NAME
Definition: transform.h:152
#define ER_FAILED
Definition: error_code.h:47
DB_OBJLIST * inheritance
Definition: class_object.h:788
unsigned triggers_validated
Definition: class_object.h:772
static int flatten_partition_info(SM_TEMPLATE *def, SM_TEMPLATE *flat)
int tp_domain_copy_enumeration(DB_ENUMERATION *dest, const DB_ENUMERATION *src)
SM_METHOD * class_methods
Definition: class_object.h:795
unsigned int virtual_cache_snapshot_version
Definition: parse_tree.h:1721
SM_CLASS_CONSTRAINT * classobj_find_cons_primary_key(SM_CLASS_CONSTRAINT *cons_list)
void sm_delete_static_method(const char *name)
static SM_METHOD_ARGUMENT * find_argument(SM_METHOD_SIGNATURE *sig, int argnum)
struct tp_domain * setdomain
Definition: object_domain.h:82
int sm_check_class_domain(TP_DOMAIN *domain, MOP class_)
TP_DOMAIN * domain
Definition: class_object.h:444
static int find_attribute_op(MOP op, const char *name, SM_CLASS **classp, SM_ATTRIBUTE **attp)
#define ER_SM_CORRUPTED
Definition: error_code.h:335
int db_value_clone(DB_VALUE *src, DB_VALUE *dest)
Definition: db_macro.c:1564
#define SM_MAP_INDEX_ATTFLAG_TO_CONSTRAINT(c)
Definition: class_object.h:78
int classobj_get_prop(DB_SEQ *properties, const char *name, DB_VALUE *pvalue)
DB_NAMELIST * nlist_filter(DB_NAMELIST **root, const char *name, NLSEARCHER fcn)
Definition: work_space.c:4410
int sm_class_check_uniques(MOP classop)
SM_CONSTRAINT_TYPE
Definition: class_object.h:274
CLASS_STATS * stats
Definition: class_object.h:747
#define CTV_CLASS_NAME
Definition: transform.h:148
DB_OBJLIST * ml_ext_alloc_link(void)
Definition: work_space.c:4777
static const char * template_classname(SM_TEMPLATE *template_)
int sm_invalidate_trigger_cache(DB_OBJECT *classop)
SM_ATTRIBUTE * attributes
Definition: class_object.h:721
void nlist_free(DB_NAMELIST *list)
Definition: work_space.c:4344
unsigned int virtual_cache_local_schema_id
Definition: parse_tree.h:1719
VIEW_CACHE_INFO * view_cache
Definition: parse_tree.h:3571
SM_COMPONENT * classobj_find_component(SM_CLASS *class_, const char *name, int class_component)
SM_PARTITION * partition
Definition: class_object.h:760
#define ASSERT_ERROR_AND_SET(error_code)
static int sm_expand_method_files(SM_METHOD_FILE *files)
#define CT_DOMAIN_NAME
Definition: transform.h:121
#define CT_METHSIG_NAME
Definition: transform.h:123
DB_SEQ * properties
Definition: class_object.h:754
DB_SEQ * properties
Definition: class_object.h:807
unsigned int is_alias
int tr_empty_schema_cache(TR_SCHEMA_CACHE *cache)
#define assert_release(e)
Definition: error_manager.h:96
SM_RESOLUTION * resolutions
Definition: class_object.h:735
void classobj_free_template(SM_TEMPLATE *template_ptr)
#define SM_MAX_IDENTIFIER_LENGTH
int au_check_user(void)
SM_CLASS_TYPE
Definition: class_object.h:289
MOP locator_add_root(OID *root_oid, MOBJ class_root)
Definition: locator_cl.c:5544
void * triggers
Definition: class_object.h:811
void classobj_free_desclist(SM_DESCRIPTOR_LIST *dl)
#define ER_SM_ALIAS_COMPONENT_INHERITED
Definition: error_code.h:358
SM_CLASS_TYPE sm_get_class_type(SM_CLASS *class_)
int sm_is_partition(MOP classmop, MOP supermop)
SM_NAME_SPACE
DB_OBJECT * dbt_finish_class(DB_CTMPL *def)
Definition: db_temp.c:226
SM_DEFAULT_VALUE default_value
Definition: class_object.h:451
unsigned no_objects
Definition: work_space.h:146
struct sm_descriptor * next
Definition: class_object.h:896
void sm_free_constraint_info(SM_CONSTRAINT_INFO **save_info)
static int allocate_disk_structures(MOP classop, SM_CLASS *class_, DB_OBJLIST *subclasses, SM_TEMPLATE *template_)
#define OR_ALIGNED_BUF(size)
OID * ws_oid(MOP mop)
Definition: work_space.c:2884
NESTED_VIEW_VERSION_INFO * nested_views
Definition: parse_tree.h:1738
#define SM_IS_CONSTRAINT_UNIQUE_FAMILY(c)
Definition: class_object.h:111
SM_CLASS_CONSTRAINT * classobj_find_constraint_by_name(SM_CLASS_CONSTRAINT *cons_list, const char *name)
int sm_flush_and_decache_objects(MOP obj, int decache)
#define WS_ISVID(mop)
Definition: work_space.h:288
OID * ws_identifier(MOP mop)
Definition: work_space.c:2805
struct sm_component * next
Definition: class_object.h:384
#define OID_SET_NULL(oidp)
Definition: oid.h:85
#define ER_WS_NO_CLASS_FOR_INSTANCE
Definition: error_code.h:403
void sm_downcase_name(const char *name, char *buf, int maxlen)
unsigned is_cached
char * sm_get_method_source_file(MOP obj, const char *name)
#define ER_SM_INVALID_METHOD_ENV
Definition: error_code.h:366
TP_DOMAIN * domain
Definition: class_object.h:559
static int sm_check_index_exist(MOP classop, char **out_shared_cons_name, DB_CONSTRAINT_TYPE constraint_type, const char *constraint_name, const char **att_names, const int *asc_desc, const SM_PREDICATE_INFO *filter_index, const SM_FUNCTION_INFO *func_info)
void ws_mark_instances_deleted(MOP class_op)
Definition: work_space.c:2192
int do_update_auto_increment_serial_on_rename(MOP serial_obj, const char *class_name, const char *att_name)
DB_OBJLIST * db_get_superclasses(DB_OBJECT *obj)
Definition: db_info.c:630
int db_make_sequence(DB_VALUE *value, DB_C_SET *set)
MOP locator_find_class(const char *classname)
Definition: locator_cl.c:3142
int sm_prelink_methods(DB_OBJLIST *classes)
SM_FUNCTION_INFO * func_index_info
Definition: class_object.h:541
int smt_add_constraint(SM_TEMPLATE *template_, DB_CONSTRAINT_TYPE constraint_type, const char *constraint_name, const char **att_names, const int *asc_desc, const int *attrs_prefix_length, int class_attribute, SM_FOREIGN_KEY_INFO *fk_info, SM_PREDICATE_INFO *filter_index, SM_FUNCTION_INFO *function_index, const char *comment, SM_INDEX_STATUS index_status)
#define CTV_METHARG_SD_NAME
Definition: transform.h:155
int sm_update_catalog_statistics(const char *class_name, bool with_fullscan)
const char * pname
Definition: class_object.h:694
unsigned int ws_get_mvcc_snapshot_version(void)
Definition: work_space.c:4976
TP_DOMAIN * tp_domain_copy(const TP_DOMAIN *domain, bool check_cache)
SM_ATTRIBUTE * classobj_find_attribute(SM_CLASS *class_, const char *name, int class_attribute)
enum lc_prefetch_flags LC_PREFETCH_FLAGS
Definition: locator.h:339
struct sm_constraint_info * next
SM_METHOD_ARGUMENT * value
Definition: class_object.h:575
struct sm_class_constraint * next
Definition: class_object.h:530
INT32 hpgid
#define BTID_IS_EQUAL(b1, b2)
SM_NAME_SPACE name_space
Definition: class_object.h:386
int er_errid(void)
#define ER_SM_ATTRIBUTE_NAME_CONFLICT
Definition: error_code.h:338
static int check_attribute_method_overlap(SM_TEMPLATE *template_, SM_CANDIDATE *candidates)
int do_get_partition_parent(DB_OBJECT *const classop, MOP *const parentop)
int sm_set_class_comment(MOP classop, const char *comment)
static const char * sm_locate_method_file(SM_CLASS *class_, const char *function)
#define ER_SM_CONSTRAINT_NOT_FOUND
Definition: error_code.h:870
static int filter_local_constraints(SM_TEMPLATE *template_, SM_CLASS *super_class)
#define ER_SM_MISSING_ALIAS_SUBSTITUTE
Definition: error_code.h:353
int sm_save_function_index_info(SM_FUNCTION_INFO **save_info, SM_FUNCTION_INFO *func_index_info)
void sm_free_filter_index_info(SM_PREDICATE_INFO *filter_index_info)
const char * name
void locator_free_list_mops(LIST_MOPS *mops)
Definition: locator_cl.c:2978
#define CT_STORED_PROC_NAME
Definition: transform.h:132
HFID * sm_get_ch_heap(MOP classmop)
int classobj_drop_foreign_key_ref(DB_SEQ **properties, const BTID *btid, const char *name)
static int allocate_index(MOP classop, SM_CLASS *class_, DB_OBJLIST *subclasses, SM_ATTRIBUTE **attrs, const int *asc_desc, const int *attrs_prefix_length, int unique_pk, int not_null, int reverse, const char *constraint_name, BTID *index, OID *fk_refcls_oid, BTID *fk_refcls_pk_btid, const char *fk_name, SM_PREDICATE_INFO *filter_index, SM_FUNCTION_INFO *function_index, SM_INDEX_STATUS index_status)
#define WS_ISDIRTY(mop)
Definition: work_space.h:259
#define CT_METHFILE_NAME
Definition: transform.h:125
int collation_id
Definition: class_object.h:750
LIST_MOPS * locator_get_all_mops(MOP class_mop, DB_FETCH_MODE purpose, LC_FETCH_VERSION_TYPE *force_fetch_version_type)
Definition: locator_cl.c:2839
const char * sm_get_att_name(MOP classop, int id)
static int check_alias_conflict(SM_TEMPLATE *template_, SM_CANDIDATE *candidates)
MOBJ locator_prepare_rename_class(MOP class_mop, const char *old_classname, const char *new_classname)
Definition: locator_cl.c:5975
struct sm_foreign_key_info * next
Definition: class_object.h:474
unsigned int is_requested
PR_TYPE * tp_Type_object
void db_ws_free(void *ptr)
Definition: quick_fit.c:194
static void check_inherited_attributes(MOP classmop, SM_CLASS *class_, SM_TEMPLATE *flat)
#define CT_CLASS_NAME
Definition: transform.h:119
int ws_map_class(MOP class_op, MAPFUNC function, void *args)
Definition: work_space.c:2118
int ml_find(DB_OBJLIST *list, MOP mop)
Definition: work_space.c:4465
static int sm_build_function_nlist(METHOD_LINK *links, struct nlist **nlist_ptr)
static void assign_method_id(SM_CLASS *class_, SM_METHOD *method, bool class_method)
#define CT_PARTITION_NAME
Definition: transform.h:134
struct parser_context * virtual_query_cache
Definition: class_object.h:755
char * sm_produce_constraint_name_mop(MOP classop, DB_CONSTRAINT_TYPE constraint_type, const char **att_names, const int *asc_desc, const char *given_name)
#define AU_ALTER
Definition: authenticate.h:73
SM_DESCRIPTOR * sm_Descriptors
#define COPY_OID(dest_oid_ptr, src_oid_ptr)
Definition: oid.h:63
SM_FOREIGN_KEY_ACTION update_action
Definition: class_object.h:482
static void fixup_attribute_self_domain(SM_ATTRIBUTE *att, MOP self)
void ws_free_string(const char *str)
Definition: work_space.c:3480
int get_mem_size_of_mem(const void *mem, const tp_domain *domain=NULL) const
static int deallocate_index(SM_CLASS_CONSTRAINT *cons, BTID *index)
static int flatten_properties(SM_TEMPLATE *def, SM_TEMPLATE *flat)
int sm_save_filter_index_info(SM_PREDICATE_INFO **save_info, SM_PREDICATE_INFO *filter_index_info)
static bool sm_constraint_belongs_to_class(const SM_CLASS_CONSTRAINT *const con, MOP const mop)
int heap_destroy_newly_created(const HFID *hfid, const OID *class_oid)
SM_CLASS_CONSTRAINT * sm_class_constraints(MOP classop)
#define ER_FK_REF_CLASS_HAS_NOT_PK
Definition: error_code.h:1150
#define ERROR0(error, code)
Definition: error_manager.h:48
SM_METHOD * methods
Definition: class_object.h:791
#define ER_SM_INCOMPATIBLE_DOMAINS
Definition: error_code.h:350
SM_CLASS_CONSTRAINT * classobj_find_class_constraint_by_btid(SM_CLASS_CONSTRAINT *constraints, SM_CONSTRAINT_TYPE type, BTID btid)
static int flatten_query_spec_lists(SM_TEMPLATE *def, SM_TEMPLATE *flat)
void sm_transaction_boundary(void)
static int update_supers_drop(MOP classop, DB_OBJLIST *supers)
const char * expanded_name
Definition: class_object.h:618
SM_DESCRIPTOR_LIST * map
Definition: class_object.h:900
CLASS_STATS * sm_get_statistics_force(MOP classop)
SM_PARTITION * classobj_copy_partition_info(SM_PARTITION *partition_info)
int sm_drop_trigger(DB_OBJECT *classop, const char *attribute, int class_attribute, DB_OBJECT *trigger)
ROOT_CLASS sm_Root_class
static int sm_split_loader_commands(const char *string, const char ***command_ptr)
int sm_get_descriptor_component(MOP op, SM_DESCRIPTOR *desc, int for_update, SM_CLASS **class_ptr, SM_COMPONENT **comp_ptr)
const char * comment
Definition: class_object.h:542
LOCK locator_fetch_mode_to_lock(DB_FETCH_MODE purpose, LC_OBJTYPE type, LC_FETCH_VERSION_TYPE fetch_version_type)
Definition: locator_cl.c:2068
SM_ATTRIBUTE_FLAG
static SCHEMA_DEF Current_Schema
static int flatten_method_files(SM_TEMPLATE *def, SM_TEMPLATE *flat)
static int domain_search(MOP dclass_mop, MOP class_mop)
int intl_identifier_lower(const char *src, char *dst)
int do_recreate_filter_index_constr(PARSER_CONTEXT *parser, SM_PREDICATE_INFO *filter_index_info, PT_NODE *alter, const char *src_cls_name, const char *new_cls_name)
static DB_OBJECT * is_class(OID *obj_oid, OID *class_oid)
Definition: compactdb.c:637
int classobj_copy_props(DB_SEQ *properties, MOP filter_class, DB_SEQ **new_properties)
Definition: class_object.c:549
#define OR_ALIGNED_BUF_START(abuf)
LOCK
int classobj_cache_class_constraints(SM_CLASS *class_)
int locator_remove_class_from_index(OID *oid, BTID *btid, HFID *hfid)
MOBJ locator_fetch_class(MOP class_mop, DB_FETCH_MODE purpose)
Definition: locator_cl.c:2293
#define AU_EXECUTE
Definition: authenticate.h:75
static int sm_file_extension(const char *path, const char *ext)
#define SM_GET_FILTER_PRED_STREAM_SIZE(filter)
Definition: class_object.h:165
bool pr_is_set_type(DB_TYPE type)
#define CT_STORED_PROC_ARGS_NAME
Definition: transform.h:133
DB_DATA data
Definition: dbtype_def.h:1083
const char TEXT_CONSTRAINT_PREFIX[]
DB_DEFAULT_EXPR default_expr
Definition: class_object.h:395
const char * name
Definition: dbtype_def.h:431
int do_drop_partitioned_class(MOP class_, int drop_sub_flag, bool is_cascade_constraints)
int sm_find_subclass_in_hierarchy(MOP hierarchy, MOP class_mop, bool *found)
unsigned is_parameterized
PR_TYPE * pr_type_from_id(DB_TYPE id)
#define UNIQUE_PARTITION_SAVEPOINT_DROP
int sm_issystem(SM_CLASS *class_)
static DOMAIN_COMP compare_domains(TP_DOMAIN *d1, TP_DOMAIN *d2)
#define ER_SM_CONSTRAINT_EXISTS
Definition: error_code.h:875
static void invalidate_unused_triggers(MOP class_mop, SM_CLASS *class_, SM_TEMPLATE *flat)
#define SM_ADD_CONSTRAINT_SAVEPOINT_NAME
int sm_get_class_repid(MOP classop)
void er_set(int severity, const char *file_name, const int line_no, int err_id, int num_args,...)
int classobj_put_foreign_key_ref(DB_SEQ **properties, SM_FOREIGN_KEY_INFO *fk_info)
SM_FOREIGN_KEY_ACTION fk_update_action
Definition: db_set.h:35
bool classobj_is_pk_referred(MOP clsop, SM_FOREIGN_KEY_INFO *fk_info, bool include_self_ref, char **fk_name)
int sm_has_non_null_attribute(SM_ATTRIBUTE **attrs)
const char * sm_ch_name(const MOBJ clobj)
DB_OBJLIST * vid_getall_mops(MOP class_mop, SM_CLASS *class_p, DB_FETCH_MODE purpose)
struct tr_schema_cache * triggers
Definition: class_object.h:756
int tp_domain_match(const TP_DOMAIN *dom1, const TP_DOMAIN *dom2, TP_MATCH exact)
int tran_abort_upto_system_savepoint(const char *savepoint_name)
#define assert(x)
SM_CONSTRAINT_TYPE type
Definition: class_object.h:369
#define ER_SM_INCOMPATIBLE_ALIAS_LOCAL_SUB
Definition: error_code.h:734
#define ER_SM_NO_INDEX
Definition: error_code.h:345
void classobj_free_descriptor(SM_DESCRIPTOR *desc)
static int fetch_descriptor_class(MOP op, SM_DESCRIPTOR *desc, int for_update, SM_CLASS **class_)
PR_TYPE * tp_Type_null
static int lockhint_subclasses(SM_TEMPLATE *temp, SM_CLASS *class_)
DB_CONSTRAINT_TYPE
Definition: dbtype_def.h:452
int classobj_copy_methfiles(SM_METHOD_FILE *files, MOP filter_class, SM_METHOD_FILE **copy_ptr)
struct sm_candidate * next
TDE_ALGORITHM
Definition: tde.h:71
#define ER_SM_INCOMPATIBLE_ALIAS_SUBSTITUTE
Definition: error_code.h:354
int32_t fileid
Definition: dbtype_def.h:886
#define WS_SET_NO_OBJECTS(mop)
Definition: work_space.h:311
SM_PARTITION * partition
Definition: class_object.h:814
int sm_att_constrained(MOP classop, const char *name, SM_ATTRIBUTE_FLAG cons)
SM_ATTRIBUTE * shared_attributes
Definition: class_object.h:803
static int check_alias_domains(SM_TEMPLATE *template_, SM_CANDIDATE *candidates, SM_CANDIDATE **most_specific)
unsigned int virtual_cache_snapshot_version
Definition: class_object.h:765
void sm_create_root(OID *rootclass_oid, HFID *rootclass_hfid)
static SM_ATTRIBUTE * find_matching_att(SM_ATTRIBUTE *list, SM_ATTRIBUTE *att, int idmatch)
#define ER_SM_INDEX_PREFIX_LENGTH_ON_PARTITIONED_CLASS
Definition: error_code.h:1259
static void fixup_self_reference_domains(MOP classop, SM_TEMPLATE *flat)
int smt_change_constraint_status(SM_TEMPLATE *ctemplate, const char *index_name, SM_INDEX_STATUS index_status)
unsigned recache_constraints
Definition: class_object.h:775
unsigned int virtual_cache_local_schema_id
Definition: class_object.h:763
#define ER_GENERIC_ERROR
Definition: error_code.h:49
int au_fetch_class(MOP op, SM_CLASS **class_ptr, AU_FETCHMODE fetchmode, DB_AUTH type)
void ws_list_free(DB_LIST *list, LFREEER function)
Definition: work_space.c:3945
const char * sm_Root_class_name
#define ERROR1(error, code, arg1)
Definition: error_manager.h:56
int sm_clean_class(MOP classmop, SM_CLASS *class_)
int sm_class_has_triggers(DB_OBJECT *classop, int *status_ptr, DB_TRIGGER_EVENT event_type)
int sm_att_default_value(MOP classop, const char *name, DB_VALUE *value, DB_DEFAULT_EXPR **default_expr, DB_DEFAULT_EXPR_TYPE **on_update_expr)
int sm_object_size_quick(SM_CLASS *class_, MOBJ obj)
void stats_free_statistics(CLASS_STATS *stats)
SM_DESCRIPTOR * classobj_make_descriptor(MOP class_mop, SM_CLASS *classobj, SM_COMPONENT *comp, int write_access)
SM_REPRESENTATION * representations
Definition: class_object.h:716
int ws_pin(MOP mop, int pin)
Definition: work_space.c:2989
static int update_subclasses(DB_OBJLIST *subclasses)
void(* LFREEER)(void *)
Definition: work_space.h:562
struct db_object * class_mop
Definition: work_space.h:121
#define CTV_INDEX_NAME
Definition: transform.h:157
unsigned dont_decache_constraints_or_flush
Definition: class_object.h:774
#define ER_OUT_OF_VIRTUAL_MEMORY
Definition: error_code.h:50
int sm_check_catalog_rep_dir(MOP classmop, SM_CLASS *class_)
static int flatten_template(SM_TEMPLATE *def, MOP deleted_class, SM_TEMPLATE **flatp, int auto_res)
#define OID_ISTEMP(oidp)
Definition: oid.h:80
#define ER_SM_CYCLE_DETECTED
Definition: error_code.h:343
void classobj_free_class(SM_CLASS *class_)
#define DOM_GET_ENUMERATION(dom)
Definition: object_domain.h:38
int do_rename_partition(MOP old_class, const char *newname)
int sm_update_class_auto(SM_TEMPLATE *template_, MOP *classmop)
DB_VALUE original_value
Definition: class_object.h:393
unsigned is_desc
int sm_is_partitioned_class(MOP op)
SM_ATTRIBUTE * class_attributes
Definition: class_object.h:725
static void sm_reset_descriptors(MOP class_)
SM_FOREIGN_KEY_ACTION fk_delete_action
#define WC_PERIOD
HFID * sm_ch_heap(MOBJ clobj)
static unsigned int local_schema_version
int sm_save_constraint_info(SM_CONSTRAINT_INFO **save_info, const SM_CLASS_CONSTRAINT *const c)
int sm_update_statistics(MOP classop, bool with_fullscan)
int intl_identifier_casecmp(const char *str1, const char *str2)
int tf_object_size(MOBJ classobj, MOBJ obj)
int classobj_make_class_constraints(DB_SET *class_props, SM_ATTRIBUTE *attributes, SM_CLASS_CONSTRAINT **con_ptr)
static int sm_truncate_using_delete(MOP class_mop)
static TP_DOMAIN * construct_index_key_domain(int n_atts, SM_ATTRIBUTE **atts, const int *asc_desc, const int *prefix_lengths, int func_col_id, TP_DOMAIN *func_domain)
#define CTV_AUTH_NAME
Definition: transform.h:159
SM_METHOD_FILE * method_files
Definition: class_object.h:727
#define DB_MAX_IDENTIFIER_LENGTH
Definition: dbtype_def.h:495
int method_ids
Definition: class_object.h:742
SM_COMPONENT * obj
struct sm_descriptor_list * next
Definition: class_object.h:866
int locator_flush_class(MOP class_mop)
Definition: locator_cl.c:5068
int stats_get_statistics(OID *classoid, unsigned int timestamp, CLASS_STATS **stats_p)
Definition: statistics_cl.c:54
DB_OBJECT * db_domain_class(const DB_DOMAIN *domain)
Definition: db_macro.c:4030
static enum scanner_mode mode
SM_QUERY_SPEC * query_spec
Definition: class_object.h:800
SM_NAME_SPACE name_space
Definition: class_object.h:633
void sm_flush_static_methods()
#define CTV_METHARG_NAME
Definition: transform.h:154
#define SM_COMPARE_NAMES
Definition: class_object.h:47
SM_TEMPLATE * new_
Definition: class_object.h:746
DB_SEQ * values
Definition: class_object.h:696
static int collect_hier_class_info(MOP classop, DB_OBJLIST *subclasses, const char *constraint_name, int reverse, int *n_classes, int n_attrs, OID *oids, int *attr_ids, HFID *hfids)
METHOD_FUNCTION function
Definition: class_object.h:594
int sm_filter_domain(TP_DOMAIN *domain, int *changes)
#define HFID_SET_NULL(hfid)
DB_ATTRIBUTE * db_attribute_next(DB_ATTRIBUTE *attribute)
Definition: db_info.c:1020
SM_ATTRIBUTE * instance_attributes
Definition: class_object.h:802
unsigned methods_loaded
Definition: class_object.h:769
unsigned int sm_global_schema_version(void)
#define ER_SM_INVALID_PREFIX_LENGTH
Definition: error_code.h:1278
void sm_final()
const char * sm_get_ch_name(MOP op)
static int flatten_subclasses(DB_OBJLIST *subclasses, MOP deleted_class)
#define UNIQUE_PARTITION_SAVEPOINT_RENAME
void sm_add_static_method(const char *name, void(*function)())
#define OID_EQ(oidp1, oidp2)
Definition: oid.h:92
TR_CACHE_TYPE
MOP ws_class_mop(MOP mop)
Definition: work_space.c:2907
void classobj_free_attribute(SM_ATTRIBUTE *att)
const char * function_name
Definition: class_object.h:570
int sm_update_class_with_auth(SM_TEMPLATE *template_, MOP *classmop, DB_AUTH auth, bool needs_hierarchy_lock)
int classobj_get_cached_constraint(SM_CONSTRAINT *constraints, SM_CONSTRAINT_TYPE type, BTID *id)
#define DB_IS_CONSTRAINT_REVERSE_INDEX_FAMILY(c)
Definition: dbtype_def.h:177
static int allocate_foreign_key(MOP classop, SM_CLASS *class_, SM_CLASS_CONSTRAINT *con, DB_OBJLIST *subclasses)
DB_OBJLIST * sm_fetch_all_base_classes(int external_list, DB_FETCH_MODE purpose)
VFID vfid
#define TP_DOMAIN_TYPE(dom)
void db_set_read_fetch_instance_version(LC_FETCH_VERSION_TYPE read_Fetch_Instance_Version)
Definition: db_vdb.c:3904
int do_check_fk_constraints(DB_CTMPL *ctemplate, PT_NODE *constraints)
TP_DOMAIN * fi_domain
Definition: class_object.h:502
#define ER_SM_MULTIPLE_ALIAS
Definition: error_code.h:369
#define ER_SM_INVALID_NAME
Definition: error_code.h:346
#define UNIQUE_PARTITION_SAVEPOINT_INDEX
static void cleanup(int signo)
Definition: broker.c:717
#define SM_MAP_DB_INDEX_CONSTRAINT_TO_SM_CONSTRAINT(c)
Definition: class_object.h:103
SP_PARSER_CTX * parser
static int install_new_representation(MOP classop, SM_CLASS *class_, SM_TEMPLATE *flat)
struct db_namelist * next
Definition: dbtype_def.h:430
#define CT_INDEX_NAME
Definition: transform.h:128
#define NULL
Definition: freelistheap.h:34
int heap_create(HFID *hfid, const OID *class_oid, bool reuse_oid)
int tp_valid_indextype(DB_TYPE type)
#define CTV_STORED_PROC_ARGS_NAME
Definition: transform.h:162
struct pr_type * type
Definition: object_domain.h:76
const char * alias
Definition: class_object.h:632
#define SM_ADD_UNIQUE_CONSTRAINT_SAVEPOINT_NAME
SM_METHOD_SIGNATURE * signatures
Definition: class_object.h:593
const char * pr_type_name(DB_TYPE id)
#define ER_PC_UNIMPLEMENTED
Definition: error_code.h:716
#define ER_REGU_NOT_IMPLEMENTED
Definition: error_code.h:194
if(extra_options)
Definition: dynamic_load.c:958
DB_SESSION * db_open_buffer(const char *buffer)
Definition: db_vdb.c:232
#define CTV_TRIGGER_NAME
Definition: transform.h:160
SM_QUERY_SPEC * classobj_copy_query_spec_list(SM_QUERY_SPEC *query_spec)
int db_compile_statement(DB_SESSION *session)
Definition: db_vdb.c:766
int sm_force_write_all_classes(void)
int sm_check_name(const char *name)
int db_attribute_is_foreign_key(DB_ATTRIBUTE *attribute)
Definition: db_info.c:1282
void db_close_session(DB_SESSION *session)
Definition: db_vdb.c:3319
VFID vfid
DB_OBJLIST * ws_Resident_classes
Definition: work_space.c:97
static int check_invalid_resolutions(SM_TEMPLATE *template_, SM_RESOLUTION **resolutions, SM_RESOLUTION *original_list)
#define SM_PROPERTY_UNIQUE
static unsigned int global_schema_version
void db_free_query(DB_SESSION *session)
Definition: db_vdb.c:3683
#define CT_METHARG_NAME
Definition: transform.h:124
static int success()
struct pr_type * type
Definition: class_object.h:443
int sm_get_class_flag(MOP op, SM_CLASS_FLAG flag)
int sm_add_trigger(DB_OBJECT *classop, const char *attribute, int class_attribute, DB_OBJECT *trigger)
#define CTV_SUPER_CLASS_NAME
Definition: transform.h:149
void(* function)()
#define ER_OBJ_CANT_ASSIGN_OID
Definition: error_code.h:945
#define BTID_SET_NULL(btid)
int vid_flush_all_instances(MOP class_mop, bool decache)
OID * sm_ch_rep_dir(MOBJ clobj)
char name[DB_MAX_SCHEMA_LENGTH *INTL_UTF8_MAX_CHAR_SIZE+4]
#define SM_IS_CONSTRAINT_INDEX_FAMILY(c)
Definition: class_object.h:117
TP_DOMAIN * tp_domain_cache(TP_DOMAIN *transient)
#define err(fd,...)
Definition: porting.h:431
#define ERROR3(error, code, arg1, arg2, arg3)
Definition: error_manager.h:72
int crypt_md5_buffer_hex(const char *buffer, size_t len, char *resblock)
Definition: crypt_opfunc.c:646
int ml_remove(DB_OBJLIST **list, MOP mop)
Definition: work_space.c:4613
void classobj_remove_class_constraint_node(SM_CLASS_CONSTRAINT **constraints, SM_CLASS_CONSTRAINT *node)
#define ER_OBJ_INVALID_ATTRIBUTE
Definition: error_code.h:273
int sm_set_class_collation(MOP classop, int collation_id)
int sm_decache_instances_after_query_executed_with_commit(MOP class_mop)
#define TM_TRAN_READ_FETCH_VERSION()
#define DONT_DECACHE
Definition: locator_cl.h:49
const char * loader_commands
Definition: class_object.h:799
static const char * candidate_source_name(SM_TEMPLATE *template_, SM_CANDIDATE *candidate)
static int allocate_unique_constraint(MOP classop, SM_CLASS *class_, SM_CLASS_CONSTRAINT *con, DB_OBJLIST *subclasses, SM_TEMPLATE *template_)
static int sm_count_tokens(const char *string, int *maxcharp)
SM_TEMPLATE * smt_edit_class_mop(MOP op, DB_AUTH db_auth_type)
LOCK lock
Definition: work_space.h:134
static int sm_dynamic_link_class(SM_CLASS *class_, METHOD_LINK *links)
#define SM_DROP_CLASS_MOP_SAVEPOINT_NAME
#define CT_QUERYSPEC_NAME
Definition: transform.h:126
int set_get_element(DB_COLLECTION *set, int index, DB_VALUE *value)
Definition: set_object.c:2575
void ml_free(DB_OBJLIST *list)
Definition: work_space.c:4654
METHOD_FUNCTION function
Definition: class_object.h:571
MOP vid_get_referenced_mop(MOP mop)
struct db_objlist * next
Definition: dbtype_def.h:442
static void auto_resolve_conflict(SM_CANDIDATE *candidate, SM_RESOLUTION **resolutions, SM_NAME_SPACE resspace)
SM_ATTRIBUTE * class_attributes
Definition: class_object.h:794
int sm_exist_index(MOP classop, const char *idxname, BTID *btid)
static int check_fk_validity(MOP classop, SM_CLASS *class_, SM_ATTRIBUTE **key_attrs, const int *asc_desc, OID *pk_cls_oid, BTID *pk_btid, char *fk_name)
const char * classobj_map_constraint_to_property(SM_CONSTRAINT_TYPE constraint)
Definition: class_object.c:502
int sm_flush_objects(MOP obj)
#define CT_COLLATION_NAME
Definition: transform.h:137
void ws_disconnect_deleted_instances(MOP classop)
Definition: work_space.c:1230
int pr_clear_value(DB_VALUE *value)
void sm_bump_local_schema_version(void)
DB_CTMPL * dbt_edit_class(MOP classobj)
Definition: db_temp.c:133
SM_ATTRIBUTE * classobj_find_attribute_id(SM_CLASS *class_, int id, int class_attribute)
int stats_update_statistics(OID *classoid, int with_fullscan)
unsigned post_load_cleanup
Definition: class_object.h:770
int sm_active_triggers(MOP class_mop, SM_CLASS *class_, DB_TRIGGER_EVENT event_type)
int sm_set_class_tde_algorithm(MOP classop, TDE_ALGORITHM tde_algo)
struct schema_def SCHEMA_DEF
int nlist_append(DB_NAMELIST **list, const char *name, NLSEARCHER fcn, int *added_ptr)
Definition: work_space.c:4198
const char * comment
#define ER_FK_CANT_DROP_PK_REFERRED
Definition: error_code.h:1154
#define ER_SM_INCOMPATIBLE_SHADOW
Definition: error_code.h:352
void classobj_free_representation(SM_REPRESENTATION *rep)
DB_DOMAIN * db_attribute_domain(DB_ATTRIBUTE *attribute)
Definition: db_info.c:1165
int ws_class_has_cached_objects(MOP class_mop)
Definition: work_space.c:3180
SM_CONSTRAINT * constraints
Definition: class_object.h:454
#define ER_SM_INVALID_UNIQUE_IDX_PARTITION
Definition: error_code.h:1499
SM_METHOD * class_methods
Definition: class_object.h:733
void er_stack_pop(void)
#define WS_LIST_APPEND(lst, element)
Definition: work_space.h:577
#define CTV_METHOD_NAME
Definition: transform.h:153
int au_fetch_class_by_classmop(MOP op, SM_CLASS **class_ptr, AU_FETCHMODE fetchmode, DB_AUTH type)
#define d1
static void insert_attribute(SM_ATTRIBUTE **attlist, SM_ATTRIBUTE *att)
int ws_mop_compare(MOP mop1, MOP mop2)
Definition: work_space.c:3144
SM_RESOLUTION * resolutions
Definition: class_object.h:792
#define ER_OBJ_INVALID_ARGUMENT
Definition: error_code.h:946
#define ER_SM_LESS_SPECIFIC_ALIAS_SUBSTITUTE
Definition: error_code.h:355
struct db_object * op
Definition: dbtype_def.h:443
DB_TYPE sm_att_type_id(MOP classop, const char *name)
MOP Au_user
Definition: authenticate.c:343
SM_CLASS_CONSTRAINT * constraints
Definition: class_object.h:757
struct static_method * next
#define INTL_UTF8_MAX_CHAR_SIZE
void classobj_free_class_constraints(SM_CLASS_CONSTRAINT *constraints)
#define TP_IS_CHAR_TYPE(typeid)
MOP locator_find_class_with_purpose(const char *classname, bool for_update)
Definition: locator_cl.c:3167
static int build_storage_order(SM_CLASS *class_, SM_TEMPLATE *flat)
SM_DOMAIN * sm_domain_alloc()
static int alter_trigger_cache(SM_CLASS *class_, const char *attribute, int class_attribute, DB_OBJECT *trigger, int drop_it)
static void error(const char *msg)
Definition: gencat.c:331
int classobj_btid_from_property_value(DB_VALUE *value, BTID *btid, char **shared_cons_name)
SM_COMPONENT * comp
Definition: class_object.h:870
SM_DESCRIPTOR_LIST * classobj_make_desclist(MOP classobj, SM_CLASS *class_, SM_COMPONENT *comp, int write_access)
SM_NAME_SPACE name_space
Definition: class_object.h:904
DB_DEFAULT_EXPR_TYPE on_update_default_expr
Definition: class_object.h:452
static void sm_free_loader_commands(char **commands)
unsigned int flags
Definition: class_object.h:459
static int rc
Definition: serial.c:50
void classobj_free_resolution(SM_RESOLUTION *res)
int ml_add(DB_OBJLIST **list, MOP mop, int *added_ptr)
Definition: work_space.c:4493
SM_TEMPLATE * classobj_make_template(const char *name, MOP op, SM_CLASS *class_)
int sm_is_global_only_constraint(MOP classmop, SM_CLASS_CONSTRAINT *constraint, int *is_global, SM_TEMPLATE *template_)
#define AU_UPDATE
Definition: authenticate.h:71
SM_CLASS_CONSTRAINT * classobj_find_class_constraint(SM_CLASS_CONSTRAINT *constraints, SM_CONSTRAINT_TYPE type, const char *name)
int sm_get_method_descriptor(DB_OBJECT *op, const char *name, int class_method, SM_DESCRIPTOR **desc_ptr)
TP_DOMAIN * tp_domain_construct(DB_TYPE domain_type, DB_OBJECT *class_obj, int precision, int scale, TP_DOMAIN *setdomain)
struct sm_method_signature * next
Definition: class_object.h:568
#define ER_SM_INVALID_DEF_CONSTRAINT_NAME_PARAMS
Definition: error_code.h:896
SM_CLASS_HEADER header
Definition: class_object.h:710
DB_OBJLIST * sm_fetch_all_objects(DB_OBJECT *op, DB_FETCH_MODE purpose)
int sm_att_info(MOP classop, const char *name, int *idp, TP_DOMAIN **domainp, int *sharedp, int class_attr)
int locator_check_fk_validity(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)
#define WS_LIST_REMOVE(lst, element)
Definition: work_space.h:581
SM_CLASS_CONSTRAINT * classobj_find_class_index(SM_CLASS *class_, const char *name)
static int resolve_candidates(SM_TEMPLATE *template_, SM_CANDIDATE *candidates, int auto_resolve, SM_CANDIDATE **winner_return)
#define HFID_IS_NULL(hfid)
OID * locator_assign_permanent_oid(MOP mop)
Definition: locator_cl.c:6084
static int sm_link_static_methods(SM_CLASS *class_, METHOD_LINK **links_ptr)
#define AU_SELECT
Definition: authenticate.h:69
static int allocate_disk_structures_index(MOP classop, SM_CLASS *class_, SM_CLASS_CONSTRAINT *con, DB_OBJLIST *subclasses, SM_TEMPLATE *template_)
DB_OBJLIST * ml_copy(DB_OBJLIST *list)
Definition: work_space.c:4671
DB_AUTH
Definition: dbtype_def.h:239
#define ARG_FILE_LINE
Definition: error_manager.h:44
#define CTV_ATTRIBUTE_NAME
Definition: transform.h:151
int smt_check_index_exist(SM_TEMPLATE *template_, char **out_shared_cons_name, DB_CONSTRAINT_TYPE constraint_type, const char *constraint_name, const char **att_names, const int *asc_desc, const SM_PREDICATE_INFO *filter_index, const SM_FUNCTION_INFO *function_index)
unsigned int virtual_cache_global_schema_id
Definition: parse_tree.h:1720
struct parser_context * sm_virtual_queries(PARSER_CONTEXT *parser, DB_OBJECT *class_object)
SM_METHOD_FILE * method_files
Definition: class_object.h:798
bool er_has_error(void)
int sm_partitioned_class_type(DB_OBJECT *classop, int *partition_type, char *keyattr, MOP **partitions)
unsigned int time_stamp
Definition: statistics.h:88
int locator_remove_class(MOP class_mop)
Definition: locator_cl.c:5858
int pr_clone_value(const DB_VALUE *src, DB_VALUE *dest)
#define SM_PROPERTY_INDEX
void ws_decache(MOP mop)
Definition: work_space.c:2701
static int lock_supers(SM_TEMPLATE *def, DB_OBJLIST *current, DB_OBJLIST **oldlist, DB_OBJLIST **newlist)
static int lock_subclasses_internal(SM_TEMPLATE *def, MOP op, DB_OBJLIST *newsupers, DB_OBJLIST **newsubs)
int sm_get_index(MOP classop, const char *attname, BTID *index)
#define NLIST_FIND(lst, name)
Definition: work_space.h:610
#define SM_PROPERTY_PRIMARY_KEY
#define WS_OID(mop)
Definition: work_space.h:293
int locator_all_flush(void)
Definition: locator_cl.c:5457
#define AU_ENABLE(save)
Definition: authenticate.h:113
int classobj_populate_class_properties(DB_SET **properties, SM_CLASS_CONSTRAINT *constraints, SM_CONSTRAINT_TYPE type)
LC_FIND_CLASSNAME locator_lockhint_classes(int num_classes, const char **many_classnames, LOCK *many_locks, int *need_subclasses, LC_PREFETCH_FLAGS *flags, int quit_on_errors, LOCK lock_rr_tran)
Definition: locator_cl.c:6260
const char * name
Definition: class_object.h:787
static void abort_subclasses(DB_OBJLIST *subclasses)
SM_FOREIGN_KEY_ACTION delete_action
Definition: class_object.h:481
char * sm_produce_constraint_name(const char *class_name, DB_CONSTRAINT_TYPE constraint_type, const char **att_names, const int *asc_desc, const char *given_name)
int sm_update_all_catalog_statistics(bool with_fullscan)
const char * name
static int inherit_constraint(MOP classop, SM_CLASS_CONSTRAINT *con)
SM_METHOD_FILE * classobj_make_method_file(const char *name)
static SM_CANDIDATE * make_candidate_from_component(SM_COMPONENT *comp, MOP source)
int sm_force_method_link(MOP obj)
int sm_class_has_unique_constraint(MOBJ classobj, MOP classop, bool check_subclasses, bool *has_unique)
unsigned has_active_triggers
Definition: class_object.h:773
int intl_identifier_lower_string_size(const char *src)
DOMAIN_COMP
void classobj_decache_class_constraints(SM_CLASS *class_)
SM_METHOD * classobj_copy_method(SM_METHOD *src, const char *alias)
int nlist(char *, struct nlist *)
static int retain_former_ids(SM_TEMPLATE *flat)
static int find_superclass(DB_OBJECT *classop, SM_TEMPLATE *temp, DB_OBJECT *super)
void * object
Definition: work_space.h:123
#define free_and_init(ptr)
Definition: memory_alloc.h:147
int sm_coerce_object_domain(TP_DOMAIN *domain, MOP object, MOP *dest_object)
#define strlen(s1)
Definition: intl_support.c:43
#define BTID_COPY(btid_ptr1, btid_ptr2)
#define CTV_INDEXKEY_NAME
Definition: transform.h:158
bool sm_is_reuse_oid_class(MOP op)
static int sm_add_secondary_index_on_partition(MOP classop, DB_CONSTRAINT_TYPE constraint_type, const char *constraint_name, const char **att_names, const int *asc_desc, const int *attrs_prefix_length, int class_attributes, SM_PREDICATE_INFO *filter_index, SM_FUNCTION_INFO *function_index, const char *comment, SM_INDEX_STATUS index_status, MOP *sub_partitions)
int classobj_check_index_exist(SM_CLASS_CONSTRAINT *constraints, char **out_shared_cons_name, const char *class_name, DB_CONSTRAINT_TYPE constraint_type, const char *constraint_name, const char **att_names, const int *asc_desc, const SM_PREDICATE_INFO *filter_index, const SM_FUNCTION_INFO *func_index_info)
SM_COMPONENT header
Definition: class_object.h:441
DB_OBJLIST * sm_fetch_all_objects_of_dirty_version(DB_OBJECT *op, DB_FETCH_MODE purpose)
static int sm_flush_and_decache_objects_internal(MOP obj, MOP obj_class_mop, int decache)
DB_CONSTRAINT_TYPE db_constraint_type(const DB_CONSTRAINT *constraint)
Definition: db_info.c:1978
#define ER_SM_INVALID_INDEX_TYPE
Definition: error_code.h:341
#define ERROR2(error, code, arg1, arg2)
Definition: error_manager.h:64
static void free_candidates(SM_CANDIDATE *candidates)
int smt_drop_constraint(SM_TEMPLATE *template_, const char **att_names, const char *constraint_name, int class_attribute, SM_ATTRIBUTE_FLAG constraint)
static int sm_link_methods(SM_CLASS *class_)
#define ER_OBJ_INVALID_ARGUMENTS
Definition: error_code.h:275
static void insert_method(SM_METHOD **methlist, SM_METHOD *method)
DB_TRIGGER_EVENT
Definition: dbtype_def.h:356
bool classobj_has_class_unique_constraint(SM_CLASS_CONSTRAINT *constraints)
int sm_check_reuse_oid_class(MOP op)
const char * ch_name
Definition: class_object.h:350
DB_C_INT(* NLSEARCHER)(const void *, const void *)
Definition: work_space.h:599
SM_COMPONENT * classobj_filter_components(SM_COMPONENT **complist, SM_NAME_SPACE name_space)
MOP mops[1]
Definition: locator_cl.h:67
#define ER_HEAP_UNKNOWN_OBJECT
Definition: error_code.h:102
int tp_domain_filter_list(TP_DOMAIN *dlist, int *list_changes)
SM_RESOLUTION * classobj_make_resolution(MOP class_mop, const char *name, const char *alias, SM_NAME_SPACE name_space)
static void filter_reslist(SM_RESOLUTION **reslist, MOP deleted_class)
static int sm_drop_cascade_foreign_key(SM_CLASS *class_)
int db_get(DB_OBJECT *object, const char *attpath, DB_VALUE *value)
Definition: db_obj.c:233
bool tr_set_execution_state(bool new_state)
static void remove_shadowed_resolutions(SM_TEMPLATE *original, SM_TEMPLATE *flat)
void ml_ext_free(DB_OBJLIST *list)
Definition: work_space.c:4806
int sm_drop_index(MOP classop, const char *constraint_name)
static SM_CANDIDATE * prune_candidate(SM_CANDIDATE **clist_pointer)
static STATIC_METHOD * Static_method_table
static void assign_attribute_id(SM_CLASS *class_, SM_ATTRIBUTE *att, int class_attribute)
#define QSTR_IS_ANY_CHAR_OR_BIT(s)
Definition: string_opfunc.h:47
MOP sm_find_class_with_purpose(const char *name, bool for_update)
static void save_previous_value(SM_ATTRIBUTE *old, SM_ATTRIBUTE *new_)
#define MAX_ATTR_IN_AUTO_GEN_NAME
int catalog_check_rep_dir(OID *class_id, OID *rep_dir_p)
SM_ATTRIBUTE ** attributes
Definition: class_object.h:533
SM_CLASS_TYPE class_type
Definition: class_object.h:784
SM_CLASS_TYPE class_type
Definition: class_object.h:713
SM_FUNCTION_INFO * func_index_info
void * db_ws_alloc(size_t size)
Definition: quick_fit.c:73
SM_METHOD_ARGUMENT * args
Definition: class_object.h:577
#define CT_INDEXKEY_NAME
Definition: transform.h:129
int sm_drop_constraint(MOP classop, DB_CONSTRAINT_TYPE constraint_type, const char *constraint_name, const char **att_names, bool class_attributes, bool mysql_index_name)
int tr_active_schema_cache(MOP class_mop, TR_SCHEMA_CACHE *cache, DB_TRIGGER_EVENT event_type, bool *has_event_type_triggers)
#define WS_LIST_LENGTH(lst)
Definition: work_space.h:573
static bool sm_is_possible_to_recreate_constraint(MOP class_mop, const SM_CLASS *const class_, const SM_CLASS_CONSTRAINT *const constraint)
unsigned int sm_local_schema_version(void)
SM_CLASS * sm_get_class_with_statistics(MOP classop)
SM_NAME_SPACE name_space
TR_SCHEMA_CACHE * tr_make_schema_cache(TR_CACHE_TYPE type, DB_OBJLIST *objects)
SM_PREDICATE_INFO * filter_predicate
int serial_decache(OID *oid)
static void sm_free_method_links(METHOD_LINK *links)
#define SM_IS_CONSTRAINT_REVERSE_INDEX_FAMILY(c)
Definition: class_object.h:124
#define ER_TM_SERVER_DOWN_UNILATERALLY_ABORTED
Definition: error_code.h:171
#define is_global(M)
#define IS_CLASS_MOP(mop)
Definition: work_space.h:209
SM_CONSTRAINT_TYPE type
Definition: class_object.h:540
DB_TYPE db_attribute_type(DB_ATTRIBUTE *attribute)
Definition: db_info.c:1000
int locator_flush_for_multi_update(MOP class_mop)
Definition: locator_cl.c:5401
unsigned int virtual_cache_global_schema_id
Definition: class_object.h:764
int classobj_copy_reslist(SM_RESOLUTION *src, SM_NAME_SPACE resspace, SM_RESOLUTION **copy_ptr)
int heap_has_instance(HFID *hfid, OID *class_oid, int has_visible_instance)
void ws_remove_resident_class(MOP classop)
Definition: work_space.c:1277
DB_OBJLIST * users
Definition: class_object.h:712
int i
Definition: dynamic_load.c:954
TR_SCHEMA_CACHE * tr_copy_schema_cache(TR_SCHEMA_CACHE *cache, MOP filter_class)
#define DECACHE
Definition: locator_cl.h:48
int locator_flush_all_instances(MOP class_mop, bool decache)
Definition: locator_cl.c:5278
#define CTV_STORED_PROC_NAME
Definition: transform.h:161
int db_make_null(DB_VALUE *value)
#define AU_INDEX
Definition: authenticate.h:74
DB_TYPE id
void vid_decache_instance(MOP mop)
#define SM_TRUNCATE_SAVEPOINT_NAME
#define SM_PROPERTY_FOREIGN_KEY
int sm_get_class_collation(MOP classop, int *collation_id)
#define DB_IS_NULL(value)
Definition: dbtype.h:63
int intl_identifier_fix(char *name, int ident_max_size, bool error_on_case_overflow)
MOP sm_get_class(MOP obj)
struct tp_domain * next
Definition: object_domain.h:74
for(p=libs;*p;p++)
Definition: dynamic_load.c:968
MOBJ locator_update_class(MOP mop)
Definition: locator_cl.c:5938
char * au_get_user_name(MOP obj)
#define ER_NOT_ALLOWED_ACCESS_TO_PARTITION
Definition: error_code.h:1137
#define ER_SM_UNRESOLVED_METHODS
Definition: error_code.h:307
static int flatten_trigger_cache(SM_TEMPLATE *def, SM_TEMPLATE *flat)
const char * name
Definition: class_object.h:385
#define DB_IS_CONSTRAINT_INDEX_FAMILY(c)
Definition: dbtype_def.h:173
int sm_att_fk_constrained(MOP classop, const char *name)
static int filter_resolutions(SM_TEMPLATE *def, SM_TEMPLATE *flat, MOP deleted_class)
#define SM_IS_ATTFLAG_INDEX_FAMILY(c)
Definition: class_object.h:61
void(* METHOD_FUNCTION)()
Definition: class_object.h:168
static int remove_class_triggers(MOP classop, SM_CLASS *class_)
char * strdup(const char *str)
Definition: porting.c:901
SM_CLASS_FLAG
Definition: class_object.h:300
void dbt_abort_class(DB_CTMPL *def)
Definition: db_temp.c:249
int sm_flush_for_multi_update(MOP class_mop)
int sm_get_attribute_descriptor(DB_OBJECT *op, const char *name, int class_attribute, int for_update, SM_DESCRIPTOR **desc_ptr)
#define ER_SM_ONLINE_INDEX_ON_HIERARCHY
Definition: error_code.h:1593
SM_INDEX_STATUS index_status
Definition: class_object.h:544
int au_fetch_instance(MOP op, MOBJ *obj_ptr, AU_FETCHMODE mode, LC_FETCH_VERSION_TYPE fetch_version_type, DB_AUTH type)
DB_OBJLIST * sm_fetch_all_classes(int external_list, DB_FETCH_MODE purpose)
#define ER_PARTITION_WORK_FAILED
Definition: error_code.h:1109
struct sm_attribute * order_link
Definition: class_object.h:461
static bool sm_filter_index_pred_have_invalid_attrs(SM_CLASS_CONSTRAINT *constraint, char *class_name, SM_ATTRIBUTE *old_atts, SM_ATTRIBUTE *new_atts)
DB_FETCH_MODE
Definition: dbtype_def.h:215
#define ER_SM_INDEX_EXISTS
Definition: error_code.h:344
int sm_link_method(SM_CLASS *class_, SM_METHOD *method)
int ws_list_length(DB_LIST *list)
Definition: work_space.c:3925
MOP sm_Root_class_mop
#define BTID_IS_NULL(btid)
static SM_ATTRIBUTE * order_atts_by_alignment(SM_ATTRIBUTE *atts)
int db_value_clear(DB_VALUE *value)
Definition: db_macro.c:1588
struct db_object * class_mop
Definition: object_domain.h:81
int object_size
Definition: class_object.h:719
int DB_C_INT
Definition: dbtype_def.h:1149
const char * alias
#define pt_has_error(parser)
Definition: parser.h:507
#define ER_SM_ALIAS_COMPONENT_EXISTS
Definition: error_code.h:357
short volid
Definition: dbtype_def.h:887
PT_NODE * vquery_for_query
Definition: parse_tree.h:1728
MOP sm_att_class(MOP classop, const char *name)
#define ER_SM_INCOMPATIBLE_COMPONENTS
Definition: error_code.h:363
MOP sm_find_class(const char *name)
#define STATS_WITH_SAMPLING
Definition: statistics.h:35
int au_delete_auth_of_dropping_table(const char *class_name)
bool classobj_is_exist_foreign_key_ref(MOP refop, SM_FOREIGN_KEY_INFO *fk_info)
#define db_ws_free_and_init(obj)
Definition: quick_fit.h:30
static DOMAIN_COMP compare_argument_domains(SM_METHOD *m1, SM_METHOD *m2)
#define OID_ISNULL(oidp)
Definition: oid.h:81
void sm_free_descriptor(SM_DESCRIPTOR *desc)
static int update_foreign_key_ref(MOP ref_clsop, SM_FOREIGN_KEY_INFO *fk_info)
int locator_is_class(MOP mop, DB_FETCH_MODE hint_purpose)
Definition: locator_cl.c:239
static void filter_component_resolutions(SM_TEMPLATE *template_, const char *name, SM_NAME_SPACE resspace)
#define ER_SM_INVALID_INDEX_WITH_PREFIX_TYPE
Definition: error_code.h:1262
int sm_finish_class(SM_TEMPLATE *template_, MOP *classmop)
int sm_att_unique_constrained(MOP classop, const char *name)
bool log_does_allow_replication(void)
Definition: log_comm.c:270
SM_CONSTRAINT_EXTRA_FLAG extra_status
Definition: class_object.h:543
static void fixup_self_domain(TP_DOMAIN *domain, MOP self)
#define SM_PROPERTY_REVERSE_INDEX
void tr_free_schema_cache(TR_SCHEMA_CACHE *cache)
int collation_id
Definition: object_domain.h:92
static int update_fk_ref_partitioned_class(SM_TEMPLATE *ctemplate, SM_FOREIGN_KEY_INFO *fk_info, const BTID *btid, const char *old_name, const char *new_name)
char * ws_copy_string(const char *str)
Definition: work_space.c:3457
int envvar_expand(const char *string, char *buffer, size_t maxlen)
SM_RESOLUTION * class_resolutions
Definition: class_object.h:796
struct sm_resolution * next
Definition: class_object.h:628
bool locator_is_root(MOP mop)
Definition: locator_cl.c:212
struct sm_constraint * next
Definition: class_object.h:366
#define WS_MOP_IS_NULL(mop)
Definition: work_space.h:328
#define SM_FIND_NAME_IN_COMPONENT_LIST(complist, name)
Definition: class_object.h:146
SM_ATTRIBUTE * ordered_attributes
Definition: class_object.h:753
void sm_mark_system_classes(void)
#define CTV_PARTITION_NAME
Definition: transform.h:163
int ws_find(MOP mop, MOBJ *obj)
Definition: work_space.c:3112
void sm_init(OID *rootclass_oid, HFID *rootclass_hfid)
bool classobj_cache_constraints(SM_CLASS *class_)
const char * comment
Definition: class_object.h:758
#define TP_IS_BIT_TYPE(typeid)
#define SM_PROPERTY_REVERSE_UNIQUE
PARSER_CONTEXT * mq_virtual_queries(DB_OBJECT *class_obj)
TP_DOMAIN * tp_domain_new(DB_TYPE type)
SM_METHOD * methods
Definition: class_object.h:730
int sm_get_trigger_cache(DB_OBJECT *classop, const char *attribute, int class_attribute, void **cache)
int do_recreate_func_index_constr(PARSER_CONTEXT *parser, SM_CONSTRAINT_INFO *constr, SM_FUNCTION_INFO *func_index_info, PT_NODE *alter, const char *src_cls_name, const char *new_cls_name)
int sm_get_class_tde_algorithm(MOP classop, TDE_ALGORITHM *tde_algo)
#define ER_SM_INVALID_CLASS
Definition: error_code.h:365
int btree_delete_index(BTID *btid)
#define CTV_VCLASS_NAME
Definition: transform.h:150
DB_SESSION_ERROR * db_get_errors(DB_SESSION *session)
Definition: db_vdb.c:926
void sm_domain_free(SM_DOMAIN *ptr)
SM_INDEX_STATUS
Definition: class_object.h:510
SM_ATTRIBUTE * classobj_copy_attribute(SM_ATTRIBUTE *src, const char *alias)
static void sm_free_resident_classes_virtual_query_cache(void)
#define HFID_COPY(hfid_ptr1, hfid_ptr2)
SM_ATTRIBUTE * attributes
Definition: class_object.h:790
#define ER_OBJ_INVALID_METHOD
Definition: error_code.h:279
static int lock_subclasses(SM_TEMPLATE *def, DB_OBJLIST *newsupers, DB_OBJLIST *cursubs, DB_OBJLIST **newsubs)
#define ER_OBJ_NOT_A_CLASS
Definition: error_code.h:288
#define ER_SM_INDEX_ON_SHARED
Definition: error_code.h:322
int au_fetch_class_force(MOP op, SM_CLASS **class_, AU_FETCHMODE fetchmode)
#define ER_SM_UNRESOLVED_METHOD
Definition: error_code.h:308
struct sm_method_file * next
Definition: class_object.h:615
const char ** p
Definition: dynamic_load.c:945
void tp_domain_free(TP_DOMAIN *dom)
DB_CONST_C_CHAR db_get_string(const DB_VALUE *value)
const char * loader_commands
Definition: class_object.h:728
int db_statement_count(DB_SESSION *session)
Definition: db_vdb.c:132
static void add_candidate(SM_CANDIDATE **candlist, SM_COMPONENT *comp, int order, MOP source, SM_RESOLUTION *resolutions)
static int drop_foreign_key_ref(MOP classop, SM_CLASS *class_, SM_CLASS_CONSTRAINT *flat_cons, SM_CLASS_CONSTRAINT **cons)
struct sm_method_argument * next
Definition: class_object.h:556
DB_DEFAULT_EXPR_TYPE
Definition: dbtype_def.h:1181
static int drop_foreign_key_ref_internal(MOP classop, SM_CLASS_CONSTRAINT *flat_cons, SM_CLASS_CONSTRAINT *cons)
int sc_set_current_schema(MOP user)
SM_RESOLUTION * classobj_find_resolution(SM_RESOLUTION *reslist, MOP class_mop, const char *name, SM_NAME_SPACE name_space)
int sm_rename_class(MOP op, const char *new_name)
const char * rel_major_release_string(void)
MOP locator_add_class(MOBJ class_obj, const char *classname)
Definition: locator_cl.c:5595
int classobj_drop_prop(DB_SEQ *properties, const char *name)
Definition: class_object.c:394
static int check_resolution_target(SM_TEMPLATE *template_, SM_RESOLUTION *res, int *valid_ptr)
HFID * sm_Root_class_hfid
SM_NAME_SPACE sm_resolution_space(SM_NAME_SPACE name_space)
#define ER_SM_PRIMARY_KEY_EXISTS
Definition: error_code.h:1112
int tde_algorithm
Definition: class_object.h:767
SM_DOMAIN * sm_domain_copy(SM_DOMAIN *ptr)
static SM_COMPONENT * make_component_from_candidate(MOP classop, SM_CANDIDATE *cand)
static int sm_save_nested_view_versions(PARSER_CONTEXT *parser, DB_OBJECT *class_object, SM_CLASS *class_)
const char * name
Definition: class_object.h:532
int sm_delete_class_mop(MOP op, bool is_cascade_constraints)
int classobj_put_prop(DB_SEQ *properties, const char *name, DB_VALUE *pvalue)
Definition: class_object.c:314
int classobj_find_prop_constraint(DB_SEQ *properties, const char *prop_name, const char *cnstr_name, DB_VALUE *cnstr_val)
SM_METHOD * classobj_find_method(SM_CLASS *class_, const char *name, int class_method)
#define ER_SM_INVALID_PROPERTY
Definition: error_code.h:368
static void fixup_component_classes(MOP classop, SM_TEMPLATE *flat)
int sm_update_class(SM_TEMPLATE *template_, MOP *classmop)
SM_INDEX_STATUS index_status
VOLID boot_User_volid
Definition: boot_cl.c:153
unsigned int flags
Definition: class_object.h:762
int sm_set_class_flag(MOP classop, SM_CLASS_FLAG flag, int on_or_off)
static int update_supers(MOP classop, DB_OBJLIST *oldsupers, DB_OBJLIST *newsupers)
void sm_free_function_index_info(SM_FUNCTION_INFO *func_index_info)
#define CT_CHARSET_NAME
Definition: transform.h:144