File class_object.c¶
File List > cubrid > src > object > class_object.c
Go to the documentation of this file
/*
* Copyright 2008 Search Solution Corporation
* Copyright 2016 CUBRID Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
/*
* class_object.c - Class Constructors
*/
#ident "$Id$"
#include "config.h"
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "language_support.h"
#include "area_alloc.h"
#include "work_space.h"
#include "object_representation.h"
#include "object_primitive.h"
#include "class_object.h"
#include "boot_cl.h"
#include "locator_cl.h"
#include "authenticate.h"
#include "set_object.h"
#include "object_accessor.h"
#include "object_print.h"
#include "parser.h"
#include "trigger_manager.h"
#include "schema_manager.h"
#include "dbi.h"
#if defined(WINDOWS)
#include "misc_string.h"
#endif
#include "dbtype.h"
#include "printer.hpp"
#include "string_opfunc.h"
#if defined (SUPPRESS_STRLEN_WARNING)
#define strlen(s1) ((int) strlen(s1))
#endif /* defined (SUPPRESS_STRLEN_WARNING) */
/* Macro to generate the UNIQUE property string from the components */
#define SM_SPRINTF_UNIQUE_PROPERTY_VALUE(buffer, volid, fileid, pageid) \
sprintf(buffer, "%d|%d|%d", (int)volid, (int)fileid, (int)pageid)
typedef enum
{
SM_CREATE_NEW_INDEX = 0,
SM_SHARE_INDEX = 1,
SM_NOT_SHARE_INDEX_AND_WARNING = 2,
SM_NOT_SHARE_PRIMARY_KEY_AND_WARNING = 3
} SM_CONSTRAINT_COMPATIBILITY;
const int SM_MAX_STRING_LENGTH = 1073741823; /* 0x3fffffff */
static SM_CONSTRAINT_TYPE Constraint_types[] = {
SM_CONSTRAINT_PRIMARY_KEY,
SM_CONSTRAINT_UNIQUE,
SM_CONSTRAINT_REVERSE_UNIQUE,
SM_CONSTRAINT_INDEX,
SM_CONSTRAINT_REVERSE_INDEX,
SM_CONSTRAINT_FOREIGN_KEY,
};
static const char *Constraint_properties[] = {
SM_PROPERTY_PRIMARY_KEY,
SM_PROPERTY_UNIQUE,
SM_PROPERTY_REVERSE_UNIQUE,
SM_PROPERTY_INDEX,
SM_PROPERTY_REVERSE_INDEX,
SM_PROPERTY_FOREIGN_KEY,
};
#define NUM_CONSTRAINT_TYPES \
((int)(sizeof(Constraint_types)/sizeof(Constraint_types[0])))
#define NUM_CONSTRAINT_PROPERTIES \
((int)(sizeof(Constraint_properties)/sizeof(Constraint_properties[0])))
static AREA *Template_area = NULL;
static void classobj_print_props (DB_SEQ * properties);
static DB_SEQ *classobj_make_foreign_key_info_seq (SM_FOREIGN_KEY_INFO * fk_info);
static DB_SEQ *classobj_make_foreign_key_ref_seq (SM_FOREIGN_KEY_INFO * fk_info);
static DB_SEQ *classobj_make_index_attr_prefix_seq (int num_attrs, const int *attrs_prefix_length);
static DB_SEQ *classobj_make_index_filter_pred_seq (SM_PREDICATE_INFO * filter_index_info);
static void classobj_put_value_and_iterate (DB_SEQ * destination, int &index, DB_VALUE & value);
static int classobj_put_seq_and_iterate (DB_SEQ * destination, int &index, DB_SEQ * element);
static int classobj_put_seq_with_name_and_iterate (DB_SEQ * destination, int &index, const char *name, DB_SEQ * seq);
static SM_CONSTRAINT *classobj_make_constraint (const char *name, SM_CONSTRAINT_TYPE type, BTID * id,
bool has_function_constraint);
static void classobj_free_constraint (SM_CONSTRAINT * constraint);
static int classobj_constraint_size (SM_CONSTRAINT * constraint);
static bool classobj_cache_constraint_entry (const char *name, DB_SEQ * constraint_seq, SM_CLASS * class_,
SM_CONSTRAINT_TYPE constraint_type);
static bool classobj_cache_constraint_list (DB_SEQ * seq, SM_CLASS * class_, SM_CONSTRAINT_TYPE constraint_type);
static SM_CLASS_CONSTRAINT *classobj_make_class_constraint (const char *name, SM_CONSTRAINT_TYPE type);
static SM_FOREIGN_KEY_INFO *classobj_make_foreign_key_info (DB_SEQ * fk_seq, const char *cons_name,
SM_ATTRIBUTE * attributes);
static SM_FOREIGN_KEY_INFO *classobj_make_foreign_key_ref (DB_SEQ * fk_seq);
static SM_FOREIGN_KEY_INFO *classobj_make_foreign_key_ref_list (DB_SEQ * fk_container);
static int *classobj_make_index_prefix_info (DB_SEQ * prefix_seq, int num_attrs);
static SM_PREDICATE_INFO *classobj_make_index_filter_pred_info (DB_SEQ * pred_seq);
static int classobj_cache_not_null_constraints (const char *class_name, SM_ATTRIBUTE * attributes,
SM_CLASS_CONSTRAINT ** con_ptr);
static bool classobj_is_possible_constraint (SM_CONSTRAINT_TYPE existed, DB_CONSTRAINT_TYPE new_);
static int classobj_domain_size (TP_DOMAIN * domain);
static void classobj_filter_attribute_props (DB_SEQ * props);
static int classobj_init_attribute (SM_ATTRIBUTE * src, SM_ATTRIBUTE * dest, int copy);
static void classobj_clear_attribute_value (DB_VALUE * value);
static void classobj_clear_attribute (SM_ATTRIBUTE * att);
static int classobj_attribute_size (SM_ATTRIBUTE * att);
static void classobj_free_method_arg (SM_METHOD_ARGUMENT * arg);
static SM_METHOD_ARGUMENT *classobj_copy_method_arg (SM_METHOD_ARGUMENT * src);
static int classobj_method_arg_size (SM_METHOD_ARGUMENT * arg);
static SM_METHOD_SIGNATURE *classobj_copy_method_signature (SM_METHOD_SIGNATURE * sig);
static int classobj_method_signature_size (SM_METHOD_SIGNATURE * sig);
static void classobj_clear_method (SM_METHOD * meth);
static int classobj_init_method (SM_METHOD * src, SM_METHOD * dest, int copy);
static int classobj_copy_methlist (SM_METHOD * methlist, MOP filter_class, SM_METHOD ** copy_ptr);
static int classobj_method_size (SM_METHOD * meth);
static int classobj_resolution_size (SM_RESOLUTION * res);
static SM_METHOD_FILE *classobj_copy_methfile (SM_METHOD_FILE * src);
static int classobj_method_file_size (SM_METHOD_FILE * file);
static void classobj_free_repattribute (SM_REPR_ATTRIBUTE * rat);
static int classobj_repattribute_size (void);
static int classobj_representation_size (SM_REPRESENTATION * rep);
static int classobj_query_spec_size (SM_QUERY_SPEC * query_spec);
static void classobj_insert_ordered_attribute (SM_ATTRIBUTE ** attlist, SM_ATTRIBUTE * att);
static SM_REPRESENTATION *classobj_capture_representation (SM_CLASS * class_);
static void classobj_sort_attlist (SM_ATTRIBUTE ** source);
static void classobj_sort_methlist (SM_METHOD ** source);
static int classobj_copy_attribute_like (DB_CTMPL * ctemplate, SM_ATTRIBUTE * attribute,
const char *const like_class_name);
static int classobj_copy_constraint_like (DB_CTMPL * ctemplate, SM_CLASS_CONSTRAINT * constraint,
const char *const like_class_name);
static SM_FUNCTION_INFO *classobj_make_function_index_info (DB_SEQ * func_seq);
static DB_SEQ *classobj_make_function_index_info_seq (SM_FUNCTION_INFO * func_index_info);
static SM_CONSTRAINT_COMPATIBILITY classobj_check_index_compatibility (SM_CLASS_CONSTRAINT * constraints,
const DB_CONSTRAINT_TYPE constraint_type,
const SM_CLASS_CONSTRAINT * existing_con,
SM_CLASS_CONSTRAINT ** primary_con);
static int classobj_check_function_constraint_info (DB_SEQ * constraint_seq, bool * has_function_constraint);
static int classobj_partition_info_size (SM_PARTITION * partition_info);
/*
* classobj_area_init - Initialize the area for schema templates.
* return: NO_ERROR or error code.
*/
int
classobj_area_init (void)
{
Template_area = area_create ("Schema templates", sizeof (SM_TEMPLATE), 4);
if (Template_area == NULL)
{
assert (er_errid () != NO_ERROR);
return er_errid ();
}
return NO_ERROR;
}
/*
* classobj_area_final - Finalize the area for schema templates.
* return: none.
*/
void
classobj_area_final (void)
{
if (Template_area != NULL)
{
area_destroy (Template_area);
Template_area = NULL;
}
}
/* THREADED ARRAYS */
/*
* These are used for the representation of the flattened attribute and
* method lists. The structures are maintained contiguously in an array for
* quick indexing but in addition have a link field at the top so they can be
* traversed as lists. This is particularly helpful during class definition
* and makes it simpler for the class transformer to walk over the structures.
*/
/*
* classobj_alloc_threaded_array() - Allocates a threaded array and initializes
* the thread pointers.
* return: threaded array
* size(in): element size
* count(in): number of elements
*/
DB_LIST *
classobj_alloc_threaded_array (int size, int count)
{
DB_LIST *array, *l;
char *ptr;
int i;
array = NULL;
if (count)
{
array = (DB_LIST *) db_ws_alloc (size * count);
if (array == NULL)
{
return NULL;
}
ptr = (char *) array;
for (i = 0; i < (count - 1); i++)
{
l = (DB_LIST *) ptr;
l->next = (DB_LIST *) (ptr + size);
ptr += size;
}
l = (DB_LIST *) ptr;
l->next = NULL;
}
return (array);
}
/*
* classobj_free_threaded_array() - Frees a threaded array and calls a function on
* each element to free any storage referenced by the elements.
* return: none
* array(in): threaded array
* clear(in): function to free storage contained in elements
*/
void
classobj_free_threaded_array (DB_LIST * array, LFREEER clear)
{
DB_LIST *l;
if (clear != NULL)
{
for (l = array; l != NULL; l = l->next)
{
if (clear != NULL)
{
(*clear) (l);
}
}
}
db_ws_free (array);
}
/* PROPERTY LISTS */
/*
* These are used to maintain random values on class, method, and attribute
* definitions. The values are used infrequently so there is a motiviation
* for not reserving space for them unconditionally in the main
* structure body. They are implemented as sequences of name/value pairs.
*/
/*
* classobj_make_prop() - Creates an empty property list for a class, attribute,
* or method.
* return: an initialized property list
*/
DB_SEQ *
classobj_make_prop ()
{
return (set_create_sequence (0));
}
/*
* classobj_free_prop() - Frees a property list for a class, attribute, or method.
* return: none
* properties(in): a property list
*/
void
classobj_free_prop (DB_SEQ * properties)
{
if (properties != NULL)
{
set_free (properties);
}
}
/*
* classobj_put_prop() - This is used to add a new property to a property list.
* First the list is searched for a property with the given name. If the
* property already exists, the property value will be replaced with the
* new value and a non-zero is returned from the function.
* If the property does not exist, it will be added to the end of the
* list.
* return: index of the replaced property, 0 if not found
* properties(in): property list
* name(in): property name
* pvalue(in): new property value
*/
int
classobj_put_prop (DB_SEQ * properties, const char *name, DB_VALUE * pvalue)
{
int error;
int found, max, i;
DB_VALUE value;
const char *val_str;
error = NO_ERROR;
found = 0;
if (properties == NULL || name == NULL || pvalue == NULL)
{
return found;
}
max = set_size (properties);
for (i = 0; i < max && !found && error == NO_ERROR; i += 2)
{
error = set_get_element (properties, i, &value);
if (error != NO_ERROR)
{
continue;
}
if (DB_VALUE_TYPE (&value) != DB_TYPE_STRING || (val_str = db_get_string (&value)) == NULL)
{
error = ER_SM_INVALID_PROPERTY;
}
else
{
if (strcmp (name, val_str) == 0)
{
if ((i + 1) >= max)
{
error = ER_SM_INVALID_PROPERTY;
}
else
{
found = i + 1;
}
}
}
pr_clear_value (&value);
}
if (error == NO_ERROR)
{
if (found)
{
set_put_element (properties, found, pvalue);
}
else
{
/* start with the property value to avoid growing the array twice */
set_put_element (properties, max + 1, pvalue);
db_make_string (&value, name);
set_put_element (properties, max, &value);
pr_clear_value (&value);
}
}
if (error != NO_ERROR)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 0);
}
return (found);
}
/*
* classobj_drop_prop() - This removes a property from a property list.
* If the property was found, the name and value entries in the sequence
* are removed and a non-zero value is returned. If the property
* was not found, the sequence is unchanged and a zero is returned.
* return: non-zero if the property was dropped
* properties(in): property list
* name(in): property name
*/
int
classobj_drop_prop (DB_SEQ * properties, const char *name)
{
int error;
int dropped, max, i;
DB_VALUE value;
const char *val_str;
error = NO_ERROR;
dropped = 0;
if (properties == NULL || name == NULL)
{
goto error;
}
max = set_size (properties);
for (i = 0; i < max && !dropped && error == NO_ERROR; i += 2)
{
error = set_get_element (properties, i, &value);
if (error != NO_ERROR)
{
continue;
}
if (DB_VALUE_TYPE (&value) != DB_TYPE_STRING || (val_str = db_get_string (&value)) == NULL)
{
error = ER_SM_INVALID_PROPERTY;
}
else
{
if (strcmp (name, val_str) == 0)
{
if ((i + 1) >= max)
{
error = ER_SM_INVALID_PROPERTY;
}
else
{
dropped = 1;
/* drop the two elements at the found position */
set_drop_seq_element (properties, i);
set_drop_seq_element (properties, i);
}
}
}
pr_clear_value (&value);
}
error:
if (error)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 0);
}
return (dropped);
}
/*
* classobj_print_props() - Debug function to dump a property list to standard out.
* return: none
* properties(in): property list
*/
static void
classobj_print_props (DB_SEQ * properties)
{
set_print (properties);
fprintf (stdout, "\n");
#if 0
DB_VALUE value;
int max, i;
if (properties == NULL)
{
return;
}
max = set_size (properties);
if (max)
{
for (i = 0; i < max; i++)
{
if (set_get_element (properties, i, &value) != NO_ERROR)
fprintf (stdout, "*** error *** ");
else
{
help_fprint_value (stdout, &value);
pr_clear_value (&value);
fprintf (stdout, " ");
}
}
fprintf (stdout, "\n");
}
#endif /* 0 */
}
/*
* classobj_map_constraint_to_property() - Return the SM_PROPERTY type corresponding to
* the SM_CONSTRAINT_TYPE. This is necessary since we don't store
* SM_CONSTRAINT_TYPE's in the property lists.
* A NULL is returned if there is not a corresponding SM_PROPERTY type
* return: SM_PROPERTY type
* constraint(in): constraint type
*/
const char *
classobj_map_constraint_to_property (SM_CONSTRAINT_TYPE constraint)
{
const char *property_type = NULL;
switch (constraint)
{
case SM_CONSTRAINT_INDEX:
property_type = SM_PROPERTY_INDEX;
break;
case SM_CONSTRAINT_UNIQUE:
property_type = SM_PROPERTY_UNIQUE;
break;
case SM_CONSTRAINT_NOT_NULL:
property_type = SM_PROPERTY_NOT_NULL;
break;
case SM_CONSTRAINT_REVERSE_INDEX:
property_type = SM_PROPERTY_REVERSE_INDEX;
break;
case SM_CONSTRAINT_REVERSE_UNIQUE:
property_type = SM_PROPERTY_REVERSE_UNIQUE;
break;
case SM_CONSTRAINT_PRIMARY_KEY:
property_type = SM_PROPERTY_PRIMARY_KEY;
break;
case SM_CONSTRAINT_FOREIGN_KEY:
property_type = SM_PROPERTY_FOREIGN_KEY;
break;
default:
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SM_INVALID_CONSTRAINT, 0);
break;
}
return property_type;
}
/*
* classobj_copy_props() - Copies a property list. The filter class is optional and
* will cause those properties whose origin is the given class to be copied
* and others to be filtered out. This is useful when we want to filter out
* inherited properties.
* return: NO_ERROR on success, non-zero for ERROR
* properties(in): property list to copy
* filter_class(in): optional filter class
* new_properties(out): output property list where the properties are copied to
*/
int
classobj_copy_props (DB_SEQ * properties, MOP filter_class, DB_SEQ ** new_properties)
{
int error = NO_ERROR;
SM_CLASS_CONSTRAINT *constraints = NULL;
if (properties == NULL)
{
return error;
}
*new_properties = set_copy (properties);
if (*new_properties == NULL)
{
assert (er_errid () != NO_ERROR);
return er_errid ();
}
/* Filter out INDEXs and UNIQUE constraints which are inherited */
if (filter_class != NULL)
{
SM_CLASS_CONSTRAINT *c;
SM_CLASS *class_;
int is_global = 0;
error = au_fetch_class_force (filter_class, &class_, AU_FETCH_READ);
if (error != NO_ERROR)
{
goto error_condition;
}
/* Remove all constraints from the property list. We'll add the locally defined ones bellow. We can't just
* start with an empty property list since there might be other properties on it (such as proxy information).
*
* We don't know (or care) if the properties already exist so just ignore the return value. */
(void) classobj_drop_prop (*new_properties, SM_PROPERTY_UNIQUE);
(void) classobj_drop_prop (*new_properties, SM_PROPERTY_INDEX);
(void) classobj_drop_prop (*new_properties, SM_PROPERTY_NOT_NULL);
(void) classobj_drop_prop (*new_properties, SM_PROPERTY_REVERSE_UNIQUE);
(void) classobj_drop_prop (*new_properties, SM_PROPERTY_REVERSE_INDEX);
(void) classobj_drop_prop (*new_properties, SM_PROPERTY_PRIMARY_KEY);
(void) classobj_drop_prop (*new_properties, SM_PROPERTY_FOREIGN_KEY);
error = classobj_make_class_constraints (properties, class_->attributes, &constraints);
if (error != NO_ERROR)
{
goto error_condition;
}
for (c = constraints; c != NULL; c = c->next)
{
if (c->attributes == NULL)
{
error = ER_FAILED;
goto error_condition;
}
if (c->type == SM_CONSTRAINT_INDEX || c->type == SM_CONSTRAINT_REVERSE_INDEX
|| c->type == SM_CONSTRAINT_FOREIGN_KEY || c->attributes[0]->class_mop == filter_class)
{
is_global = 0;
}
else if (SM_IS_CONSTRAINT_UNIQUE_FAMILY (c->type))
{
SM_CLASS *super_class = NULL;
error = au_fetch_class_force (c->attributes[0]->class_mop, &super_class, AU_FETCH_READ);
if (error != NO_ERROR)
{
goto error_condition;
}
error = sm_is_global_only_constraint (c->attributes[0]->class_mop, c, &is_global, NULL);
if (error != NO_ERROR)
{
goto error_condition;
}
}
if (is_global == 0)
{
if (classobj_put_index (new_properties, c, &(c->index_btid), c->fk_info, c->shared_cons_name, false) !=
NO_ERROR)
{
error = ER_SM_INVALID_PROPERTY;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 0);
goto error_condition;
}
}
}
classobj_free_class_constraints (constraints);
}
return (error);
/* Error Handlers */
error_condition:
if (*new_properties != NULL)
{
classobj_free_prop (*new_properties);
}
if (constraints != NULL)
{
classobj_free_class_constraints (constraints);
}
return error;
}
/*
* classobj_make_foreign_key_info_seq()
* return:
* fk_info(in):
*/
static DB_SEQ *
classobj_make_foreign_key_info_seq (SM_FOREIGN_KEY_INFO * fk_info)
{
DB_VALUE value;
DB_SEQ *fk_seq;
char pbuf[128];
fk_seq = set_create_sequence (SM_FK_INFO_SIZE);
if (fk_seq == NULL)
{
return NULL;
}
sprintf (pbuf, "%d|%d|%d", (int) fk_info->ref_class_oid.pageid, (int) fk_info->ref_class_oid.slotid,
(int) fk_info->ref_class_oid.volid);
db_make_string (&value, pbuf);
set_put_element (fk_seq, SM_FK_INFO_REF_CLASS_OID_INDEX, &value);
sprintf (pbuf, "%d|%d|%d", (int) fk_info->ref_class_pk_btid.vfid.volid, (int) fk_info->ref_class_pk_btid.vfid.fileid,
(int) fk_info->ref_class_pk_btid.root_pageid);
db_make_string (&value, pbuf);
set_put_element (fk_seq, SM_FK_INFO_REF_CLASS_PK_BTID_INDEX, &value);
db_make_int (&value, fk_info->delete_action);
set_put_element (fk_seq, SM_FK_INFO_DELETE_ACTION_INDEX, &value);
db_make_int (&value, fk_info->update_action);
set_put_element (fk_seq, SM_FK_INFO_UPDATE_ACTION_INDEX, &value);
db_make_object (&value, fk_info->index_catalog_of_ref_class);
set_put_element (fk_seq, SM_FK_INFO_INDEX_CATALOG_OF_REF_CLASS_INDEX, &value);
db_make_int (&value, fk_info->ref_match_option);
set_put_element (fk_seq, SM_FK_INFO_REF_MATCH_OPTION_INDEX, &value);
return fk_seq;
}
/*
* classobj_make_foreign_key_ref_seq()
* return:
* fk_info(in):
*/
static DB_SEQ *
classobj_make_foreign_key_ref_seq (SM_FOREIGN_KEY_INFO * fk_info)
{
DB_VALUE value;
DB_SEQ *fk_seq;
char pbuf[128];
fk_seq = set_create_sequence (5);
if (fk_seq == NULL)
{
return NULL;
}
sprintf (pbuf, "%d|%d|%d", (int) fk_info->self_oid.pageid, (int) fk_info->self_oid.slotid,
(int) fk_info->self_oid.volid);
db_make_string (&value, pbuf);
set_put_element (fk_seq, 0, &value);
sprintf (pbuf, "%d|%d|%d", (int) fk_info->self_btid.vfid.volid, (int) fk_info->self_btid.vfid.fileid,
(int) fk_info->self_btid.root_pageid);
db_make_string (&value, pbuf);
set_put_element (fk_seq, 1, &value);
db_make_int (&value, fk_info->delete_action);
set_put_element (fk_seq, 2, &value);
db_make_int (&value, fk_info->update_action);
set_put_element (fk_seq, 3, &value);
db_make_string (&value, fk_info->name);
set_put_element (fk_seq, 4, &value);
return fk_seq;
}
/*
* classobj_describe_foreign_key_action()
* return:
* action(in):
*/
char *
classobj_describe_foreign_key_action (SM_FOREIGN_KEY_ACTION action)
{
switch (action)
{
case SM_FOREIGN_KEY_CASCADE:
return (char *) "CASCADE";
case SM_FOREIGN_KEY_RESTRICT:
return (char *) "RESTRICT";
case SM_FOREIGN_KEY_NO_ACTION:
return (char *) "NO ACTION";
case SM_FOREIGN_KEY_SET_NULL:
return (char *) "SET NULL";
}
return (char *) "";
}
/*
* classobj_make_index_attr_prefix_seq() - Make sequence which contains prefix length
* return: sequence
* num_attrs(in): key attribute count
* attrs_prefix_length(in): array which contains prefix length
*/
static DB_SEQ *
classobj_make_index_attr_prefix_seq (int num_attrs, const int *attrs_prefix_length)
{
DB_SEQ *prefix_seq;
DB_VALUE v;
int i;
prefix_seq = set_create_sequence (num_attrs);
if (prefix_seq == NULL)
{
return NULL;
}
for (i = 0; i < num_attrs; i++)
{
if (attrs_prefix_length != NULL)
{
db_make_int (&v, attrs_prefix_length[i]);
}
else
{
db_make_int (&v, -1);
}
set_put_element (prefix_seq, i, &v);
}
return prefix_seq;
}
/*
* classobj_make_index_attr_prefix_seq() - Make sequence which contains filter predicate
* return: sequence
* filter_index_info(in): filter predicate
*/
static DB_SEQ *
classobj_make_index_filter_pred_seq (SM_PREDICATE_INFO * filter_index_info)
{
DB_SEQ *pred_seq = NULL;
DB_VALUE value;
DB_SEQ *att_seq = NULL;
int i;
if (filter_index_info == NULL)
{
return NULL;
}
pred_seq = set_create_sequence (3);
if (pred_seq == NULL)
{
return NULL;
}
att_seq = set_create_sequence (0);
if (att_seq == NULL)
{
set_free (pred_seq);
return NULL;
}
if (filter_index_info->pred_string)
{
db_make_string (&value, filter_index_info->pred_string);
}
else
{
db_make_null (&value);
}
set_put_element (pred_seq, 0, &value);
if (filter_index_info->pred_stream)
{
db_make_char (&value, filter_index_info->pred_stream_size, filter_index_info->pred_stream,
filter_index_info->pred_stream_size, LANG_SYS_CODESET, LANG_SYS_COLLATION);
}
else
{
db_make_null (&value);
}
set_put_element (pred_seq, 1, &value);
/* attribute ids */
for (i = 0; i < filter_index_info->num_attrs; i++)
{
db_make_int (&value, filter_index_info->att_ids[i]);
set_put_element (att_seq, i, &value);
}
db_make_sequence (&value, att_seq);
set_put_element (pred_seq, 2, &value);
pr_clear_value (&value);
return pred_seq;
}
static void
classobj_put_value_and_iterate (DB_SEQ * destination, int &index, DB_VALUE & value)
{
set_put_element (destination, index, &value);
pr_clear_value (&value);
// increment index
++index;
}
static int
classobj_put_seq_and_iterate (DB_SEQ * destination, int &index, DB_SEQ * element)
{
if (element == NULL)
{
// assert (false); // is this acceptable?
return ER_FAILED;
}
DB_VALUE elem_dbval;
if (db_make_sequence (&elem_dbval, element) != NO_ERROR)
{
assert (false); // should not happen
return ER_FAILED;
}
classobj_put_value_and_iterate (destination, index, elem_dbval);
return NO_ERROR;
}
static int
classobj_put_seq_with_name_and_iterate (DB_SEQ * destination, int &index, const char *name, DB_SEQ * seq)
{
// we make a sequence with name and seq and add that to destination
DB_SEQ *subseq = set_create_sequence (0);
if (subseq == NULL)
{
return ER_FAILED;
}
DB_VALUE value;
int subseq_index = 0;
int error_code = NO_ERROR;
db_make_string (&value, name);
classobj_put_value_and_iterate (subseq, subseq_index, value);
error_code = classobj_put_seq_and_iterate (subseq, subseq_index, seq);
if (error_code != NO_ERROR)
{
set_free (subseq);
return error_code;
}
// now put built sequence into destination
error_code = classobj_put_seq_and_iterate (destination, index, subseq);
if (error_code != NO_ERROR)
{
set_free (subseq);
return error_code;
}
return NO_ERROR;
}
/*
* classobj_put_index() - This is used to put and update indexes on the property list.
* The property list is composed of name/value pairs. For unique
* indexes, this will be SM_PROPERTY_UNIQUE/{uniques} where {uniques}
* are another property list of unique instances.
*
* Until we fully support named constraints, use the attribute name as
* the constraint name. Each constraint instance must be uniquely named.
* An old value will be overwritten with a new value with the same name.
* return: non-zero if property was replaced
* properties(out):
* type(in):
* constraint_name(in):
* atts(in): attribute list
* asc_desc: asc/desc info list
* attr_prefix_length:
* id(in): new index value
* filter_index_info(in):
* fk_info(in):
* shared_cons_name(in):
* func_index_info(in):
* comment(in):
*
* Note: For constraint structure details, see comment on SM_CLASS_CONSTRAINT in class_object.h.
*/
int
classobj_put_index (DB_SEQ ** properties, SM_CLASS_CONSTRAINT * con, const BTID * id, SM_FOREIGN_KEY_INFO * fk_info,
char *shared_cons_name, bool attr_name_instead_of_id)
{
int i;
const char *prop_name = classobj_map_constraint_to_property (con->type);
DB_VALUE pvalue, value;
DB_SEQ *unique_property = NULL, *constraint = NULL;
int found = 0;
bool is_new_created = false; /* Is *properties new created or not */
char buf[128], *pbuf;
int constraint_seq_index;
int num_attrs = 0;
db_make_null (&pvalue);
db_make_null (&value);
/*
* If the property pointer is NULL, create an empty property sequence
*/
if (*properties == NULL)
{
*properties = classobj_make_prop ();
if (*properties == NULL)
{
goto error;
}
is_new_created = true;
}
/*
* Get a copy of the existing UNIQUE property value. If one
* doesn't exist, create a new one.
*/
found = classobj_get_prop (*properties, prop_name, &pvalue);
if (found)
{
unique_property = db_get_set (&pvalue);
}
else
{
unique_property = set_create_sequence (0);
if (unique_property == NULL)
{
goto error;
}
}
/* Create a sequence that will hold a constraint instance
* i.e. constraint_name {unique BTID, attribute_name(s)} */
constraint = set_create_sequence (2);
if (constraint == NULL)
{
goto error;
}
constraint_seq_index = 0; /* init */
/* Fill the BTID into the sequence */
if ((id == NULL || BTID_IS_NULL (id)) && shared_cons_name != NULL)
{
size_t len = strlen (shared_cons_name) + 10;
pbuf = (char *) malloc (len);
if (pbuf)
{
sprintf (pbuf, "SHARED:%s", shared_cons_name);
}
else
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, len);
goto error;
}
}
else
{
pbuf = &(buf[0]);
if (id != NULL)
{
sprintf (pbuf, "%d|%d|%d", (int) id->vfid.volid, (int) id->vfid.fileid, (int) id->root_pageid);
}
else
{
sprintf (pbuf, "%d|%d|%d", (int) NULL_VOLID, (int) NULL_FILEID, (int) NULL_PAGEID);
}
}
db_make_string (&value, pbuf);
classobj_put_value_and_iterate (constraint, constraint_seq_index, value);
if (pbuf && pbuf != &(buf[0]))
{
free_and_init (pbuf);
}
/* Fill the indexed attributes into the sequence */
for (i = 0, num_attrs = 0; con->attributes[i] != NULL; i++, num_attrs++)
{
if (attr_name_instead_of_id)
{
/* name */
db_make_string (&value, con->attributes[i]->header.name);
}
else
{
/* id */
db_make_int (&value, con->attributes[i]->id);
}
classobj_put_value_and_iterate (constraint, constraint_seq_index, value);
/* asc_desc */
db_make_int (&value, con->asc_desc ? con->asc_desc[i] : 0);
classobj_put_value_and_iterate (constraint, constraint_seq_index, value);
}
if (con->type == SM_CONSTRAINT_FOREIGN_KEY)
{
if (classobj_put_seq_and_iterate (constraint, constraint_seq_index, classobj_make_foreign_key_info_seq (fk_info))
!= NO_ERROR)
{
goto error;
}
}
else if (con->type == SM_CONSTRAINT_PRIMARY_KEY)
{
SM_FOREIGN_KEY_INFO *fk;
int num_live_fk = 0;
for (fk = fk_info; fk != NULL; fk = fk->next)
{
if (!fk->is_dropped)
{
num_live_fk++;
}
}
if (0 < num_live_fk)
{
// create subset sequence for all foreign key references
DB_SEQ *fk_container = set_create_sequence (1);
if (fk_container == NULL)
{
goto error;
}
int fk_index = 0;
for (fk = fk_info; fk; fk = fk->next)
{
if (fk->is_dropped)
{
continue;
}
if (classobj_put_seq_and_iterate (fk_container, fk_index,
classobj_make_foreign_key_ref_seq (fk)) != NO_ERROR)
{
set_free (fk_container);
goto error;
}
}
assert (num_live_fk == fk_index);
// put fk sequence into constraint sequence
if (classobj_put_seq_and_iterate (constraint, constraint_seq_index, fk_container) != NO_ERROR)
{
set_free (fk_container);
goto error;
}
fk_container = NULL;
}
}
else
{
int *attr_prefix_length = con->attrs_prefix_length;
if (con->filter_predicate == NULL && con->func_index_info == NULL)
{
/* prefix length */
if (classobj_put_seq_and_iterate (constraint, constraint_seq_index,
classobj_make_index_attr_prefix_seq (num_attrs,
attr_prefix_length)) != NO_ERROR)
{
goto error;
}
}
else
{
int seq_index = 0;
DB_SEQ *seq = set_create_sequence (0);
if (seq == NULL)
{
goto error;
}
if (con->filter_predicate != NULL)
{
if (classobj_put_seq_with_name_and_iterate (seq, seq_index, SM_FILTER_INDEX_ID,
classobj_make_index_filter_pred_seq (con->filter_predicate))
!= NO_ERROR)
{
set_free (seq);
goto error;
}
if (classobj_put_seq_with_name_and_iterate (seq, seq_index, SM_PREFIX_INDEX_ID,
classobj_make_index_attr_prefix_seq (num_attrs,
attr_prefix_length)) !=
NO_ERROR)
{
set_free (seq);
goto error;
}
}
if (con->func_index_info != NULL)
{
if (classobj_put_seq_with_name_and_iterate (seq, seq_index, SM_FUNCTION_INDEX_ID,
classobj_make_function_index_info_seq (con->func_index_info))
!= NO_ERROR)
{
set_free (seq);
goto error;
}
}
// now put seq into constraint
if (classobj_put_seq_and_iterate (constraint, constraint_seq_index, seq) != NO_ERROR)
{
set_free (seq);
goto error;
}
}
}
/* add index status. */
db_make_int (&value, con->index_status);
classobj_put_value_and_iterate (constraint, constraint_seq_index, value);
/* index_type */
db_make_int (&value, con->index_type);
classobj_put_value_and_iterate (constraint, constraint_seq_index, value);
/* options */
db_make_int (&value, con->options);
classobj_put_value_and_iterate (constraint, constraint_seq_index, value);
/* comment */
db_make_string (&value, con->comment);
classobj_put_value_and_iterate (constraint, constraint_seq_index, value);
/* Append the constraint to the unique property sequence */
db_make_sequence (&value, constraint);
constraint = NULL;
classobj_put_prop (unique_property, con->name, &value);
pr_clear_value (&value);
/* Put/Replace the unique property */
db_make_sequence (&value, unique_property);
unique_property = NULL;
classobj_put_prop (*properties, prop_name, &value);
pr_clear_value (&value);
if (found)
{
pr_clear_value (&pvalue);
}
/* Just to be sure. */
pr_clear_value (&value);
return NO_ERROR;
error:
if (is_new_created && *properties != NULL)
{
set_free (*properties);
}
if (found)
{
pr_clear_value (&pvalue);
}
else
{
if (unique_property != NULL)
{
set_free (unique_property);
}
}
if (constraint != NULL)
{
set_free (constraint);
}
return ER_FAILED;
}
/*
* classobj_is_exist_foreign_key_ref()
* return:
* refop(in):
* fk_info(in):
*/
bool
classobj_is_exist_foreign_key_ref (MOP refop, SM_FOREIGN_KEY_INFO * fk_info)
{
SM_CLASS *ref_cls;
SM_CLASS_CONSTRAINT *pk;
SM_FOREIGN_KEY_INFO *fk_ref;
int error = NO_ERROR;
error = au_fetch_class_force (refop, &ref_cls, AU_FETCH_READ);
if (error != NO_ERROR)
{
return false;
}
pk = classobj_find_class_primary_key (ref_cls);
if (pk == NULL)
{
return false;
}
for (fk_ref = pk->fk_info; fk_ref; fk_ref = fk_ref->next)
{
if (OID_EQ (&fk_ref->self_oid, &fk_info->self_oid))
{
if (BTID_IS_EQUAL (&(fk_ref->self_btid), &(fk_info->self_btid))
/* although enough to BTID_IS_EQUAL, check for full match BTID structure */
&& (fk_ref->self_btid.root_pageid == fk_info->self_btid.root_pageid))
{
return true;
}
}
}
return false;
}
/*
* classobj_is_pk_refer_other()
* return:
* clsop(in):
* fk_info(in):
* include_self_ref(in): include the class where PK is defined
*/
bool
classobj_is_pk_referred (MOP clsop, SM_FOREIGN_KEY_INFO * fk_info, bool include_self_ref, char **fk_name)
{
if (fk_name != NULL)
{
*fk_name = NULL;
}
if (include_self_ref)
{
if (fk_info != NULL)
{
if (fk_name != NULL)
{
*fk_name = fk_info->name;
}
return true;
}
else
{
return false;
}
}
else
{
SM_FOREIGN_KEY_INFO *fk_ref;
OID *cls_oid;
cls_oid = ws_oid (clsop);
for (fk_ref = fk_info; fk_ref; fk_ref = fk_ref->next)
{
if (!OID_EQ (&fk_ref->self_oid, cls_oid))
{
if (fk_name != NULL)
{
*fk_name = fk_ref->name;
}
return true;
}
}
return false;
}
}
/*
* classobj_put_foreign_key_ref()
* return: NO_ERROR on success, non-zero for ERROR
* properties(in/out):
* fk_info(in):
*/
int
classobj_put_foreign_key_ref (DB_SEQ ** properties, SM_FOREIGN_KEY_INFO * fk_info)
{
DB_VALUE prop_val, pk_val, fk_container_val, fk_val;
DB_VALUE status, index_type, options, comment;
DB_SEQ *pk_property, *pk_seq, *fk_container, *fk_seq;
int size;
int fk_container_pos;
int err = NO_ERROR;
bool has_fk_container;
PRIM_SET_NULL (&prop_val);
PRIM_SET_NULL (&pk_val);
PRIM_SET_NULL (&fk_container_val);
PRIM_SET_NULL (&fk_val);
PRIM_SET_NULL (&status);
PRIM_SET_NULL (&index_type);
PRIM_SET_NULL (&options);
PRIM_SET_NULL (&comment);
if (classobj_get_prop (*properties, SM_PROPERTY_PRIMARY_KEY, &prop_val) <= 0)
{
assert (er_errid () != NO_ERROR);
return er_errid ();
}
pk_property = db_get_set (&prop_val);
err = set_get_element (pk_property, 1, &pk_val);
if (err != NO_ERROR)
{
goto end;
}
pk_seq = db_get_set (&pk_val);
size = set_size (pk_seq);
err =
set_get_element (pk_seq, get_class_constraint_index (size, SM_CONSTRAINT_OPTIONAL_INFO_INDEX), &fk_container_val);
if (err != NO_ERROR)
{
goto end;
}
// If fk_container_val exists, pk_seq_pos points to OPTIONAL_INFO;
// otherwise, pk_seq_pos is the position to insert OPTIONAL_INFO.
has_fk_container = DB_VALUE_TYPE (&fk_container_val) == DB_TYPE_SEQUENCE;
if (has_fk_container == true)
{
fk_container = db_get_set (&fk_container_val);
fk_container_pos = set_size (fk_container);
}
else
{
fk_container = set_create_sequence (1);
if (fk_container == NULL)
{
goto end;
}
db_make_sequence (&fk_container_val, fk_container);
fk_container_pos = 0;
}
fk_seq = classobj_make_foreign_key_ref_seq (fk_info);
if (fk_seq == NULL)
{
goto end;
}
db_make_sequence (&fk_val, fk_seq);
err = set_put_element (fk_container, fk_container_pos, &fk_val);
if (err != NO_ERROR)
{
goto end;
}
if (has_fk_container == true)
{
err =
set_put_element (pk_seq, get_class_constraint_index (size, SM_CONSTRAINT_OPTIONAL_INFO_INDEX),
&fk_container_val);
if (err != NO_ERROR)
{
goto end;
}
}
else
{
err = set_get_element (pk_seq, get_class_constraint_index (size, SM_CONSTRAINT_STATUS_INDEX), &status);
if (err != NO_ERROR)
{
goto end;
}
err = set_get_element (pk_seq, get_class_constraint_index (size, SM_CONSTRAINT_INDEX_TYPE_INDEX), &index_type);
if (err != NO_ERROR)
{
goto end;
}
err = set_get_element (pk_seq, get_class_constraint_index (size, SM_CONSTRAINT_OPTIONS_INDEX), &options);
if (err != NO_ERROR)
{
goto end;
}
err = set_get_element (pk_seq, get_class_constraint_index (size, SM_CONSTRAINT_COMMENT_INDEX), &comment);
if (err != NO_ERROR)
{
goto end;
}
err =
set_put_element (pk_seq, get_class_constraint_index (size + 1, SM_CONSTRAINT_OPTIONAL_INFO_INDEX),
&fk_container_val);
if (err != NO_ERROR)
{
goto end;
}
err = set_put_element (pk_seq, get_class_constraint_index (size + 1, SM_CONSTRAINT_STATUS_INDEX), &status);
if (err != NO_ERROR)
{
goto end;
}
err =
set_put_element (pk_seq, get_class_constraint_index (size + 1, SM_CONSTRAINT_INDEX_TYPE_INDEX), &index_type);
if (err != NO_ERROR)
{
goto end;
}
err = set_put_element (pk_seq, get_class_constraint_index (size + 1, SM_CONSTRAINT_OPTIONS_INDEX), &options);
if (err != NO_ERROR)
{
goto end;
}
err = set_put_element (pk_seq, get_class_constraint_index (size + 1, SM_CONSTRAINT_COMMENT_INDEX), &comment);
if (err != NO_ERROR)
{
goto end;
}
}
err = set_put_element (pk_property, 1, &pk_val);
if (err != NO_ERROR)
{
goto end;
}
if (classobj_put_prop (*properties, SM_PROPERTY_PRIMARY_KEY, &prop_val) == 0)
{
assert (er_errid () != NO_ERROR);
err = er_errid ();
goto end;
}
end:
pr_clear_value (&prop_val);
pr_clear_value (&pk_val);
pr_clear_value (&fk_container_val);
pr_clear_value (&fk_val);
pr_clear_value (&status);
pr_clear_value (&index_type);
pr_clear_value (&options);
pr_clear_value (&comment);
return err;
}
#if defined (ENABLE_RENAME_CONSTRAINT)
/*
* classobj_rename_foreign_key_ref()
*
* return: NO_ERROR on success, non-zero for ERROR
* properties(in/out):
* btid(in): The BTID of the constraint which needs rename.
* old_name(in): The old constraint name.
* new_name(in): The new constraint name.
*/
int
classobj_rename_foreign_key_ref (DB_SEQ ** properties, const BTID * btid, const char *old_name, const char *new_name)
{
DB_VALUE prop_val, pk_val, fk_container_val;
DB_VALUE fk_val, new_fk_val;
DB_VALUE name_val, new_name_val;
DB_VALUE btid_val;
DB_SEQ *pk_property, *pk_seq, *fk_container, *fk_seq = NULL;
int size;
int fk_container_pos, pk_seq_pos;
int err = NO_ERROR;
int fk_container_len;
int i;
int volid, pageid, fileid;
char *name = NULL;
int found = 0;
PRIM_SET_NULL (&prop_val);
PRIM_SET_NULL (&pk_val);
PRIM_SET_NULL (&fk_container_val);
PRIM_SET_NULL (&fk_val);
PRIM_SET_NULL (&new_fk_val);
PRIM_SET_NULL (&new_name_val);
if (classobj_get_prop (*properties, SM_PROPERTY_PRIMARY_KEY, &prop_val) <= 0)
{
err = (er_errid () != NO_ERROR) ? er_errid () : ER_FAILED;
return err;
}
pk_property = db_get_set (&prop_val);
err = set_get_element (pk_property, 1, &pk_val);
if (err != NO_ERROR)
{
goto end;
}
pk_seq = db_get_set (&pk_val);
size = set_size (pk_seq);
err = set_get_element (pk_seq, size - 4, &fk_container_val);
if (err != NO_ERROR)
{
goto end;
}
if (DB_VALUE_TYPE (&fk_container_val) == DB_TYPE_SEQUENCE)
{
fk_container = db_get_set (&fk_container_val);
fk_container_len = set_size (fk_container);
pk_seq_pos = size - 4;
/* find the position of the existing FK ref */
for (i = 0; i < fk_container_len; i++)
{
PRIM_SET_NULL (&fk_val);
PRIM_SET_NULL (&name_val);
err = set_get_element (fk_container, i, &fk_val);
if (err != NO_ERROR)
{
goto end;
}
fk_seq = db_get_set (&fk_val);
/* A shallow copy for btid_val is enough. So, no need pr_clear_val(&btid_val). */
err = set_get_element_nocopy (fk_seq, 1, &btid_val);
if (err != NO_ERROR)
{
goto end;
}
if (classobj_decompose_property_oid (db_get_string (&btid_val), &volid, &fileid, &pageid) != 3)
{
err = ER_SM_INVALID_PROPERTY;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, err, 0);
goto end;
}
/* A shallow copy for name_val is enough. So, no need pr_clear_val(&name_val). */
err = set_get_element_nocopy (fk_seq, 4, &name_val);
if (err != NO_ERROR)
{
goto end;
}
if (DB_VALUE_TYPE (&name_val) != DB_TYPE_STRING)
{
err = ER_SM_INVALID_PROPERTY;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, err, 0);
goto end;
}
name = db_get_string (&name_val);
if (btid->vfid.volid == volid && btid->vfid.fileid == fileid && btid->root_pageid == pageid
&& old_name != NULL && name != NULL && SM_COMPARE_NAMES (old_name, name) == 0)
{
fk_container_pos = i;
db_make_string (&new_name_val, new_name);
err = set_put_element (fk_seq, 4, &new_name_val);
if (err != NO_ERROR)
{
goto end;
}
found = 1;
break;
}
else
{
/* This fk_val is not the one we need. */
pr_clear_value (&fk_val);
}
}
}
if (!found)
{
assert (false);
err = ER_SM_INVALID_PROPERTY;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, err, 0);
goto end;
}
db_make_sequence (&new_fk_val, fk_seq);
err = set_put_element (fk_container, fk_container_pos, &new_fk_val);
if (err != NO_ERROR)
{
goto end;
}
err = set_put_element (pk_seq, pk_seq_pos, &fk_container_val);
if (err != NO_ERROR)
{
goto end;
}
err = set_put_element (pk_property, 1, &pk_val);
if (err != NO_ERROR)
{
goto end;
}
if (classobj_put_prop (*properties, SM_PROPERTY_PRIMARY_KEY, &prop_val) == 0)
{
err = (er_errid () != NO_ERROR) ? er_errid () : ER_FAILED;
goto end;
}
end:
pr_clear_value (&prop_val);
pr_clear_value (&pk_val);
pr_clear_value (&fk_container_val);
pr_clear_value (&fk_val);
pr_clear_value (&new_fk_val);
pr_clear_value (&new_name_val);
return err;
}
#endif
/*
* classobj_drop_foreign_key_ref()
* return: NO_ERROR on success, non-zero for ERROR
* properties(in/out):
* btid(in): The BTID of the constraint which needs drop.
* name(in): The constraint name
*/
int
classobj_drop_foreign_key_ref (DB_SEQ ** properties, const BTID * btid, const char *name)
{
int i, fk_container_pos, fk_count;
DB_VALUE prop_val, pk_val, fk_container_val, fk_val, btid_val;
DB_SEQ *pk_property, *pk_seq, *fk_container, *fk_seq;
DB_VALUE cons_name_val;
const char *cons_name = NULL;
int volid, pageid, fileid;
int err = NO_ERROR;
int size;
db_make_null (&prop_val);
db_make_null (&pk_val);
db_make_null (&fk_container_val);
db_make_null (&fk_val);
db_make_null (&btid_val);
if (classobj_get_prop (*properties, SM_PROPERTY_PRIMARY_KEY, &prop_val) <= 0)
{
assert (er_errid () != NO_ERROR);
return er_errid ();
}
pk_property = db_get_set (&prop_val);
err = set_get_element (pk_property, 1, &pk_val);
if (err != NO_ERROR)
{
goto end;
}
pk_seq = db_get_set (&pk_val);
size = set_size (pk_seq);
fk_container_pos = get_class_constraint_index (size, SM_CONSTRAINT_OPTIONAL_INFO_INDEX);
err = set_get_element (pk_seq, fk_container_pos, &fk_container_val);
if (err != NO_ERROR)
{
goto end;
}
if (DB_VALUE_TYPE (&fk_container_val) != DB_TYPE_SEQUENCE)
{
err = ER_SM_INVALID_PROPERTY;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, err, 0);
goto end;
}
fk_container = db_get_set (&fk_container_val);
fk_count = set_size (fk_container);
for (i = 0; i < fk_count; i++)
{
err = set_get_element (fk_container, i, &fk_val);
if (err != NO_ERROR)
{
goto end;
}
fk_seq = db_get_set (&fk_val);
err = set_get_element (fk_seq, 1, &btid_val);
if (err != NO_ERROR)
{
goto end;
}
if (classobj_decompose_property_oid (db_get_string (&btid_val), &volid, &fileid, &pageid) != 3)
{
err = ER_SM_INVALID_PROPERTY;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, err, 0);
goto end;
}
/* A shallow copy for cons_name_val is enough. So, no need pr_clear_val(&cons_name_val). */
err = set_get_element_nocopy (fk_seq, 4, &cons_name_val);
if (err != NO_ERROR)
{
goto end;
}
if (DB_VALUE_TYPE (&cons_name_val) != DB_TYPE_STRING)
{
err = ER_SM_INVALID_PROPERTY;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, err, 0);
goto end;
}
cons_name = db_get_string (&cons_name_val);
if (btid->vfid.volid == volid && btid->vfid.fileid == fileid && btid->root_pageid == pageid && name != NULL
&& cons_name != NULL && SM_COMPARE_NAMES (name, cons_name) == 0)
{
err = set_drop_seq_element (fk_container, i);
if (err != NO_ERROR)
{
goto end;
}
break;
}
pr_clear_value (&btid_val);
/* fk_val should clear after cons_name not be used anymore. */
pr_clear_value (&fk_val);
}
if (set_size (fk_container) < 1)
{
err = set_drop_seq_element (pk_seq, fk_container_pos);
if (err != NO_ERROR)
{
goto end;
}
}
else
{
err = set_put_element (pk_seq, fk_container_pos, &fk_container_val);
if (err != NO_ERROR)
{
goto end;
}
}
err = set_put_element (pk_property, 1, &pk_val);
if (err != NO_ERROR)
{
goto end;
}
if (classobj_put_prop (*properties, SM_PROPERTY_PRIMARY_KEY, &prop_val) == 0)
{
assert (er_errid () != NO_ERROR);
err = er_errid ();
goto end;
}
end:
pr_clear_value (&prop_val);
pr_clear_value (&pk_val);
pr_clear_value (&fk_container_val);
pr_clear_value (&fk_val);
pr_clear_value (&btid_val);
return err;
}
/*
* classobj_find_prop_constraint() - This function is used to find and return
* a constraint from a class property list.
* return: non-zero if property was found
* properties(in): Class property list
* prop_name(in): Class property name
* cnstr_name(in): Class constraint name
* cnstr_val(out): Returned class constraint value
*/
int
classobj_find_prop_constraint (DB_SEQ * properties, const char *prop_name, const char *cnstr_name, DB_VALUE * cnstr_val)
{
DB_VALUE prop_val;
DB_SEQ *prop_seq;
int found = 0;
db_make_null (&prop_val);
if (classobj_get_prop (properties, prop_name, &prop_val) > 0)
{
prop_seq = db_get_set (&prop_val);
found = classobj_get_prop (prop_seq, cnstr_name, cnstr_val);
}
pr_clear_value (&prop_val);
return found;
}
#if defined (ENABLE_RENAME_CONSTRAINT)
/*
* classobj_rename_constraint() - This function is used to rename
* a constraint name.
* return: NO_ERROR on success, non-zero for ERROR
* properties(in): Class property list
* prop_name(in): Class property name
* old_name(in): old constraint name
* new_name(in): new constraint name
*/
int
classobj_rename_constraint (DB_SEQ * properties, const char *prop_name, const char *old_name, const char *new_name)
{
DB_VALUE prop_val, cnstr_val, new_val;
DB_SEQ *prop_seq;
int found = 0;
int error = NO_ERROR;
db_make_null (&prop_val);
db_make_null (&cnstr_val);
db_make_null (&new_val);
found = classobj_get_prop (properties, prop_name, &prop_val);
if (found == 0)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SM_INVALID_PROPERTY, 0);
error = ER_SM_INVALID_PROPERTY;
goto end;
}
prop_seq = db_get_set (&prop_val);
found = classobj_get_prop (prop_seq, old_name, &cnstr_val);
if (found == 0)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SM_INVALID_PROPERTY, 0);
error = ER_SM_INVALID_PROPERTY;
goto end;
}
db_make_string (&new_val, new_name);
/* found - 1 (should be modified.. It seems to be ambiguous.) */
error = set_put_element (prop_seq, found - 1, &new_val);
if (error != NO_ERROR)
{
goto end;
}
found = classobj_put_prop (properties, prop_name, &prop_val);
if (found == 0)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SM_INVALID_PROPERTY, 0);
error = ER_SM_INVALID_PROPERTY;
goto end;
}
end:
pr_clear_value (&prop_val);
pr_clear_value (&cnstr_val);
pr_clear_value (&new_val);
return error;
}
#endif
/*
* classobj_change_constraint_comment() - This function is used to change a constraint comment.
* return: NO_ERROR on success, non-zero for ERROR
* properties(in): Class property list
* cons(in): constraint
* comment(in): new comment of property
*
* Note: For constraint structure details, see comment on SM_CLASS_CONSTRAINT in class_object.h.
*/
int
classobj_change_constraint_comment (DB_SEQ * properties, SM_CLASS_CONSTRAINT * cons, const char *comment)
{
DB_VALUE prop_val, cnstr_val, curr_comment, new_comment;
DB_SEQ *prop_seq, *idx_seq;
const char *property_type;
int found = 0;
int error = NO_ERROR;
int len = 0;
assert (properties != NULL && cons != NULL);
db_make_null (&prop_val);
db_make_null (&cnstr_val);
db_make_null (&curr_comment);
db_make_null (&new_comment);
property_type = classobj_map_constraint_to_property (cons->type);
found = classobj_get_prop (properties, property_type, &prop_val);
if (found == 0)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SM_INVALID_PROPERTY, 0);
error = ER_SM_INVALID_PROPERTY;
goto end;
}
prop_seq = db_get_set (&prop_val);
found = classobj_get_prop (prop_seq, cons->name, &cnstr_val);
if (found == 0)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SM_INVALID_PROPERTY, 0);
error = ER_SM_INVALID_PROPERTY;
goto end;
}
idx_seq = db_get_set (&cnstr_val);
len = set_size (idx_seq);
set_get_element (idx_seq, get_class_constraint_index (len, SM_CONSTRAINT_COMMENT_INDEX), &curr_comment);
if (!DB_IS_NULL (&curr_comment) && DB_VALUE_TYPE (&curr_comment) != DB_TYPE_STRING)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SM_INVALID_PROPERTY, 0);
error = ER_SM_INVALID_PROPERTY;
goto end;
}
if (db_make_string (&new_comment, comment) != NO_ERROR ||
set_put_element (idx_seq, get_class_constraint_index (len, SM_CONSTRAINT_COMMENT_INDEX),
&new_comment) != NO_ERROR)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SM_INVALID_PROPERTY, 0);
error = ER_SM_INVALID_PROPERTY;
goto end;
}
db_make_sequence (&cnstr_val, idx_seq);
found = classobj_put_prop (prop_seq, cons->name, &cnstr_val);
if (found == 0)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SM_INVALID_PROPERTY, 0);
error = ER_SM_INVALID_PROPERTY;
goto end;
}
db_make_sequence (&prop_val, prop_seq);
found = classobj_put_prop (properties, property_type, &prop_val);
if (found == 0)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SM_INVALID_PROPERTY, 0);
error = ER_SM_INVALID_PROPERTY;
goto end;
}
end:
pr_clear_value (&prop_val);
pr_clear_value (&cnstr_val);
pr_clear_value (&curr_comment);
pr_clear_value (&new_comment);
return error;
}
/*
* classobj_btid_from_property_value() - Little helper function to get a btid out of
* a DB_VALUE that was obtained from a property list.
* Note that it is still up to the caller to clear this value when they're
* done with it.
* return: NO_ERROR on success, non-zero for ERROR
* value(in): value containing btid property
* btid(out): btid we extracted
* shared_cons_name(out):
*/
int
classobj_btid_from_property_value (DB_VALUE * value, BTID * btid, char **shared_cons_name)
{
const char *btid_string = NULL;
int volid, pageid, fileid;
int args;
if (DB_VALUE_TYPE (value) != DB_TYPE_STRING)
{
goto structure_error;
}
btid_string = db_get_string (value);
if (btid_string == NULL)
{
goto structure_error;
}
if (strncasecmp ("SHARED:", btid_string, 7) == 0)
{
if (shared_cons_name)
{
*shared_cons_name = strdup (btid_string + 7);
}
}
else
{
args = classobj_decompose_property_oid (btid_string, &volid, &fileid, &pageid);
if (args != 3)
{
goto structure_error;
}
btid->vfid.volid = (VOLID) volid;
btid->root_pageid = (PAGEID) pageid;
btid->vfid.fileid = (FILEID) fileid;
}
return NO_ERROR;
structure_error:
/* should have a more appropriate error for this */
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SM_INVALID_PROPERTY, 0);
return er_errid ();
}
/*
* classobj_oid_from_property_value()
* return: NO_ERROR on success, non-zero for ERROR
* value(in):
* oid(out):
*/
int
classobj_oid_from_property_value (DB_VALUE * value, OID * oid)
{
const char *oid_string;
int volid, pageid, slotid;
int args;
if (DB_VALUE_TYPE (value) != DB_TYPE_STRING)
{
goto structure_error;
}
oid_string = db_get_string (value);
if (oid_string == NULL)
{
goto structure_error;
}
args = classobj_decompose_property_oid (oid_string, &pageid, &slotid, &volid);
if (args != 3)
{
goto structure_error;
}
oid->pageid = (PAGEID) pageid;
oid->slotid = (PGSLOTID) slotid;
oid->volid = (VOLID) volid;
return NO_ERROR;
structure_error:
/* should have a more appropriate error for this */
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SM_INVALID_PROPERTY, 0);
return er_errid ();
}
/*
* classobj_get_cached_constraint() - This is used to find a constraint of the given
* type, and return the ID. If the constraint list does not contain
* a constraint of the requested type, a 0 is returned. Non-zero is returned
* if the constraint is found. The value pointed to by id is only
* valid if the function returns non-zero.
* return: non-zero if id was found
* constraints(in): constraint list
* type(in): constraint type
* id(out): pointer to ID
*/
int
classobj_get_cached_constraint (SM_CONSTRAINT * constraints, SM_CONSTRAINT_TYPE type, BTID * id)
{
SM_CONSTRAINT *cnstr;
int ok = 0;
for (cnstr = constraints; cnstr != NULL; cnstr = cnstr->next)
{
if (cnstr->type != type)
{
continue;
}
if (id != NULL)
{
*id = cnstr->index;
}
ok = 1;
break;
}
return ok;
}
/*
* classobj_has_unique_constraint ()
* return: true if an unique constraint is contained in the constraint list,
* otherwise false.
* constraints(in): constraint list
*/
bool
classobj_has_class_unique_constraint (SM_CLASS_CONSTRAINT * constraints)
{
SM_CLASS_CONSTRAINT *c;
for (c = constraints; c != NULL; c = c->next)
{
if (SM_IS_CONSTRAINT_UNIQUE_FAMILY (c->type))
{
return true;
}
}
return false;
}
/*
* classobj_has_unique_constraint ()
* return: true if an unique constraint is contained in the constraint list,
* otherwise false.
* constraints(in): constraint list
*/
bool
classobj_has_unique_constraint (SM_CONSTRAINT * constraints)
{
SM_CONSTRAINT *c;
for (c = constraints; c != NULL; c = c->next)
{
if (SM_IS_CONSTRAINT_UNIQUE_FAMILY (c->type))
{
return true;
}
}
return false;
}
/*
* classobj_has_function_constraint () - check if has function constraint
* return: true if an function constraint is contained in the
* constraint list, otherwise false.
* constraints(in): constraint list
*/
bool
classobj_has_function_constraint (SM_CONSTRAINT * constraints)
{
SM_CONSTRAINT *c;
for (c = constraints; c != NULL; c = c->next)
{
if (c->has_function)
{
return true;
}
}
return false;
}
/* SM_CONSTRAINT */
/*
* classobj_make_constraint() - Creates a new constraint node.
* return: new constraint structure
* name(in): Constraint name
* type(in): Constraint type
* id(in): Unique BTID
* has_function_constraint(in): true if is function constraint
*/
static SM_CONSTRAINT *
classobj_make_constraint (const char *name, SM_CONSTRAINT_TYPE type, BTID * id, bool has_function_constraint)
{
SM_CONSTRAINT *constraint;
constraint = (SM_CONSTRAINT *) db_ws_alloc (sizeof (SM_CONSTRAINT));
if (constraint == NULL)
{
return NULL;
}
constraint->next = NULL;
constraint->name = ws_copy_string (name);
constraint->type = type;
constraint->index = *id;
constraint->has_function = has_function_constraint;
if (name && !constraint->name)
{
classobj_free_constraint (constraint);
return NULL;
}
return constraint;
}
/*
* classobj_free_constraint() - Frees an constraint structure and all memory
* associated with a constraint node.
* return: none
* constraint(in): Pointer to constraint node
*/
static void
classobj_free_constraint (SM_CONSTRAINT * constraint)
{
if (constraint == NULL)
{
return;
}
if (constraint->next)
{
classobj_free_constraint (constraint->next);
}
if (constraint->name)
{
db_ws_free (constraint->name);
}
db_ws_free (constraint);
}
/*
* classobj_constraint_size() - Calculates the total number of bytes occupied by
* the constraint list.
* return: size of constraint list
* constraint(in): Pointer to constraint list
*/
static int
classobj_constraint_size (SM_CONSTRAINT * constraint)
{
return sizeof (SM_CONSTRAINT);
}
/*
* classobj_cache_constraint_entry() - Cache the constraint entry on the caches of
* the associated attributes.
* return: true if constraint entry was cached
* name(in): Constraint name
* constraint_seq(in): constraint entry
* class(in): Class pointer.
* constraint_type(in):
*
* Note: For constraint structure details, see comment on SM_CLASS_CONSTRAINT in class_object.h.
*/
static bool
classobj_cache_constraint_entry (const char *name, DB_SEQ * constraint_seq, SM_CLASS * class_,
SM_CONSTRAINT_TYPE constraint_type)
{
int error;
int i, e, info_len, att_cnt;
BTID id;
DB_VALUE id_val, att_val;
SM_ATTRIBUTE *att;
SM_CONSTRAINT *ptr;
bool ok = true;
bool has_function_constraint = false;
/*
* Extract the first element of the sequence which is the
* encoded B-tree ID
*/
info_len = set_size (constraint_seq);
att_cnt = get_class_constraint_att_count (info_len);
e = 0;
/* get the btid */
error = set_get_element (constraint_seq, e++, &id_val);
if (error != NO_ERROR)
{
goto finish;
}
if (classobj_btid_from_property_value (&id_val, &id, NULL))
{
pr_clear_value (&id_val);
goto finish;
}
/*
* Assign the B-tree ID.
* Loop over the attribute names in the constraint and cache
* the constraint in those attributes.
*/
for (i = 0; i < att_cnt && ok; i++)
{
/* name( or id) */
error = set_get_element (constraint_seq, e++, &att_val);
if (error == NO_ERROR)
{
att = NULL;
if (DB_VALUE_TYPE (&att_val) == DB_TYPE_STRING && db_get_string (&att_val) != NULL)
{
att = classobj_find_attribute (class_, db_get_string (&att_val), 0);
}
else if (DB_VALUE_TYPE (&att_val) == DB_TYPE_INTEGER)
{
att = classobj_find_attribute_id (class_, db_get_int (&att_val), 0);
}
if (att != NULL)
{
if (constraint_type == SM_CONSTRAINT_INDEX || constraint_type == SM_CONSTRAINT_REVERSE_INDEX
|| constraint_type == SM_CONSTRAINT_UNIQUE || constraint_type == SM_CONSTRAINT_REVERSE_UNIQUE)
{
if (classobj_check_function_constraint_info (constraint_seq, &has_function_constraint) != NO_ERROR)
{
pr_clear_value (&att_val);
pr_clear_value (&id_val);
ok = false;
goto finish;
}
}
/*
* Add a new constraint node to the cache list
*/
ptr = classobj_make_constraint (name, constraint_type, &id, has_function_constraint);
if (ptr == NULL)
{
ok = false;
}
else
{
if (att->constraints == NULL)
{
att->constraints = ptr;
}
else
{
ptr->next = att->constraints;
att->constraints = ptr;
}
}
}
}
pr_clear_value (&att_val);
/* asc_desc */
e++;
}
pr_clear_value (&id_val);
finish:
return ok;
}
/*
* classobj_cache_constraint_list() - Cache the constraint list into the appropriate
* attribute caches
* return: non-zero if constraint list was cached
* seq(in): Unique constraint list
* class(in): Class pointer
* constraint_type(in):
*
* Note: For constraint structure details, see comment on SM_CLASS_CONSTRAINT in class_object.h.
*/
static bool
classobj_cache_constraint_list (DB_SEQ * seq, SM_CLASS * class_, SM_CONSTRAINT_TYPE constraint_type)
{
int i, max;
DB_VALUE ids_val, name_val;
DB_SEQ *ids_seq;
int error = NO_ERROR;
bool ok = true;
/* Make sure that the DB_VALUES are initialized */
db_make_null (&ids_val);
db_make_null (&name_val);
max = set_size (seq);
for (i = 0; i < max && error == NO_ERROR && ok; i += 2)
{
/* Get the constraint name */
error = set_get_element (seq, i, &name_val);
if (error != NO_ERROR)
{
continue;
}
/* get the constraint value sequence */
error = set_get_element (seq, i + 1, &ids_val);
if (error == NO_ERROR)
{
if (DB_VALUE_TYPE (&ids_val) == DB_TYPE_SEQUENCE)
{
ids_seq = db_get_set (&ids_val);
ok = classobj_cache_constraint_entry (db_get_string (&name_val), ids_seq, class_, constraint_type);
}
pr_clear_value (&ids_val);
}
pr_clear_value (&name_val);
}
if (error != NO_ERROR)
{
goto error;
}
return ok;
/* Error Processing */
error:
pr_clear_value (&ids_val);
pr_clear_value (&name_val);
return 0;
}
/*
* classobj_cache_constraints() - Cache the constraint properties from the property
* list into the attribute's constraint structure for faster retrieval.
* return: true if constraint properties were cached
* class(in): Pointer to attribute structure
*/
bool
classobj_cache_constraints (SM_CLASS * class_)
{
SM_ATTRIBUTE *att;
DB_VALUE un_value;
DB_SEQ *un_seq;
int i;
bool ok = true;
int num_constraint_types = NUM_CONSTRAINT_TYPES;
/*
* Clear the attribute caches
*/
for (att = class_->attributes; att != NULL; att = (SM_ATTRIBUTE *) att->header.next)
{
if (att->constraints)
{
classobj_free_constraint (att->constraints);
att->constraints = NULL;
}
}
/*
* Extract the constraint property and process
*/
if (class_->properties == NULL)
{
return ok;
}
for (i = 0; i < num_constraint_types && ok; i++)
{
if (classobj_get_prop (class_->properties, Constraint_properties[i], &un_value) > 0)
{
if (DB_VALUE_TYPE (&un_value) == DB_TYPE_SEQUENCE)
{
un_seq = db_get_set (&un_value);
ok = classobj_cache_constraint_list (un_seq, class_, Constraint_types[i]);
}
pr_clear_value (&un_value);
}
}
return ok;
}
/* SM_CLASS_CONSTRAINT */
/*
* classobj_find_attribute_list() - Alternative to classobj_find_attribute when we're
* looking for an attribute on a particular list.
* return: attribute structure
* attlist(in): list of attributes
* name(in): name to look for
* id(in): attribute id
*/
static SM_ATTRIBUTE *
classobj_find_attribute_list (SM_ATTRIBUTE * attlist, const char *name, int id)
{
SM_ATTRIBUTE *att;
if (name != NULL)
{
for (att = attlist; att != NULL; att = (SM_ATTRIBUTE *) att->header.next)
{
if (intl_identifier_casecmp (att->header.name, name) == 0)
{
return att;
}
}
if (IS_DEDUPLICATE_KEY_ATTR_NAME (name))
{
return dk_find_sm_deduplicate_key_attribute (-1, name);
}
}
else
{
for (att = attlist; att != NULL; att = (SM_ATTRIBUTE *) att->header.next)
{
if (att->id == id)
{
return att;
}
}
if (IS_DEDUPLICATE_KEY_ATTR_ID (id))
{
return dk_find_sm_deduplicate_key_attribute (id, NULL);
}
}
return NULL;
}
/*
* classobj_make_class_constraint() - Allocate and initialize a new constraint
* structure. The supplied name is ours to keep, don't make a copy.
* return: new constraint structure
* name(in): constraint name
* type(in): constraint type
*/
static SM_CLASS_CONSTRAINT *
classobj_make_class_constraint (const char *name, SM_CONSTRAINT_TYPE type)
{
SM_CLASS_CONSTRAINT *new_;
/* make a new constraint list entry */
new_ = (SM_CLASS_CONSTRAINT *) db_ws_alloc (sizeof (SM_CLASS_CONSTRAINT));
if (new_ == NULL)
{
return NULL;
}
new_->next = NULL;
new_->name = name;
new_->type = type;
new_->attributes = NULL;
new_->asc_desc = NULL;
new_->attrs_prefix_length = NULL;
BTID_SET_NULL (&new_->index_btid);
new_->fk_info = NULL;
new_->shared_cons_name = NULL;
new_->filter_predicate = NULL;
new_->func_index_info = NULL;
new_->comment = NULL;
new_->extra_status = SM_FLAG_NORMALLY_INITIALIZED;
new_->index_status = SM_NO_INDEX;
return new_;
}
/*
* classobj_free_foreign_key_ref()
* return: none
* fk_info(in):
*/
void
classobj_free_foreign_key_ref (SM_FOREIGN_KEY_INFO * fk_info)
{
SM_FOREIGN_KEY_INFO *p, *next;
for (p = fk_info; p; p = next)
{
next = p->next;
free_and_init (p->name);
db_ws_free (p);
}
}
/*
* classobj_free_class_constraints() - Frees a list of class constraint structures
* allocated by classobj_make_class_constraints.
* If we ever get into the situation where SM_CONSTRAINT structures
* point back to these, we'll need to make sure that the
* these are freed LAST.
* return: none
* constraints(in): constraint list
*/
void
classobj_free_class_constraints (SM_CLASS_CONSTRAINT * constraints)
{
SM_CLASS_CONSTRAINT *c, *next;
for (c = constraints, next = NULL; c != NULL; c = next)
{
next = c->next;
ws_free_string (c->name);
ws_free_string (c->comment);
db_ws_free (c->attributes);
db_ws_free (c->asc_desc);
if (c->attrs_prefix_length)
{
db_ws_free (c->attrs_prefix_length);
}
if (c->func_index_info)
{
classobj_free_function_index_ref (c->func_index_info);
}
free_and_init (c->shared_cons_name);
if (c->filter_predicate)
{
if (c->filter_predicate->pred_stream)
{
db_ws_free (c->filter_predicate->pred_stream);
}
if (c->filter_predicate->pred_string)
{
db_ws_free (c->filter_predicate->pred_string);
}
if (c->filter_predicate->att_ids)
{
db_ws_free (c->filter_predicate->att_ids);
}
db_ws_free (c->filter_predicate);
}
if (c->fk_info)
{
if (c->type == SM_CONSTRAINT_PRIMARY_KEY)
{
classobj_free_foreign_key_ref (c->fk_info);
}
else if (c->type == SM_CONSTRAINT_FOREIGN_KEY)
{
db_ws_free (c->fk_info);
}
}
db_ws_free (c);
}
}
/*
* classobj_make_foreign_key_info()
* return:
* fk_seq(in):
* cons_name(in):
* attributes(in):
*/
static SM_FOREIGN_KEY_INFO *
classobj_make_foreign_key_info (DB_SEQ * fk_seq, const char *cons_name, SM_ATTRIBUTE * attributes)
{
DB_VALUE fvalue;
SM_FOREIGN_KEY_INFO *fk_info;
fk_info = (SM_FOREIGN_KEY_INFO *) db_ws_alloc (sizeof (SM_FOREIGN_KEY_INFO));
if (fk_info == NULL)
{
return NULL;
}
if (set_get_element (fk_seq, SM_FK_INFO_REF_CLASS_OID_INDEX, &fvalue))
{
goto error;
}
if (classobj_oid_from_property_value (&fvalue, &fk_info->ref_class_oid))
{
goto error;
}
pr_clear_value (&fvalue);
if (set_get_element (fk_seq, SM_FK_INFO_REF_CLASS_PK_BTID_INDEX, &fvalue))
{
goto error;
}
if (classobj_btid_from_property_value (&fvalue, &fk_info->ref_class_pk_btid, NULL))
{
goto error;
}
pr_clear_value (&fvalue);
if (set_get_element (fk_seq, SM_FK_INFO_DELETE_ACTION_INDEX, &fvalue))
{
goto error;
}
fk_info->delete_action = (SM_FOREIGN_KEY_ACTION) db_get_int (&fvalue);
if (set_get_element (fk_seq, SM_FK_INFO_UPDATE_ACTION_INDEX, &fvalue))
{
goto error;
}
fk_info->update_action = (SM_FOREIGN_KEY_ACTION) db_get_int (&fvalue);
if (set_get_element (fk_seq, SM_FK_INFO_INDEX_CATALOG_OF_REF_CLASS_INDEX, &fvalue))
{
goto error;
}
fk_info->index_catalog_of_ref_class = db_get_object (&fvalue);
if (set_get_element (fk_seq, SM_FK_INFO_REF_MATCH_OPTION_INDEX, &fvalue))
{
goto error;
}
fk_info->ref_match_option = (SM_FOREIGN_KEY_MATCH_OPTION) db_get_int (&fvalue);
fk_info->name = (char *) cons_name;
fk_info->is_dropped = false;
fk_info->next = NULL;
return fk_info;
error:
if (fk_info)
{
db_ws_free (fk_info);
}
return NULL;
}
/*
* classobj_make_foreign_key_ref()
* return:
* fk_seq(in):
*/
static SM_FOREIGN_KEY_INFO *
classobj_make_foreign_key_ref (DB_SEQ * fk_seq)
{
DB_VALUE fvalue;
SM_FOREIGN_KEY_INFO *fk_info;
const char *val_str;
fk_info = (SM_FOREIGN_KEY_INFO *) db_ws_alloc (sizeof (SM_FOREIGN_KEY_INFO));
if (fk_info == NULL)
{
return NULL;
}
fk_info->next = NULL;
if (set_get_element (fk_seq, 0, &fvalue))
{
goto error;
}
if (classobj_oid_from_property_value (&fvalue, &fk_info->self_oid))
{
goto error;
}
pr_clear_value (&fvalue);
if (set_get_element (fk_seq, 1, &fvalue))
{
goto error;
}
if (classobj_btid_from_property_value (&fvalue, &fk_info->self_btid, NULL))
{
goto error;
}
pr_clear_value (&fvalue);
if (set_get_element (fk_seq, 2, &fvalue))
{
goto error;
}
fk_info->delete_action = (SM_FOREIGN_KEY_ACTION) db_get_int (&fvalue);
if (set_get_element (fk_seq, 3, &fvalue))
{
goto error;
}
fk_info->update_action = (SM_FOREIGN_KEY_ACTION) db_get_int (&fvalue);
if (set_get_element (fk_seq, 4, &fvalue))
{
goto error;
}
val_str = db_get_string (&fvalue);
if (val_str == NULL)
{
goto error;
}
fk_info->name = strdup (val_str);
pr_clear_value (&fvalue);
fk_info->is_dropped = false;
return fk_info;
error:
if (fk_info)
{
db_ws_free (fk_info);
}
return NULL;
}
/*
* classobj_make_foreign_key_ref_list()
* return:
* fk_container(in):
*/
static SM_FOREIGN_KEY_INFO *
classobj_make_foreign_key_ref_list (DB_SEQ * fk_container)
{
int size, i;
DB_VALUE fkvalue;
SM_FOREIGN_KEY_INFO *list = NULL, *fk_info, *cur = NULL;
DB_SEQ *fk_seq;
size = set_size (fk_container);
for (i = 0; i < size; i++)
{
if (set_get_element (fk_container, i, &fkvalue))
{
goto error;
}
fk_seq = db_get_set (&fkvalue);
fk_info = classobj_make_foreign_key_ref (fk_seq);
if (fk_info == NULL)
{
goto error;
}
pr_clear_value (&fkvalue);
if (i == 0)
{
list = fk_info;
cur = list;
}
else
{
cur->next = fk_info;
cur = cur->next;
}
}
return list;
error:
if (list)
{
classobj_free_foreign_key_ref (list);
}
return NULL;
}
/*
* classobj_make_index_prefix_info() - Make array which contains
* prefix length
* return: array
* prefix_seq(in): sequence which contains prefix length
* num_attrs(in): key attribute count
*/
static int *
classobj_make_index_prefix_info (DB_SEQ * prefix_seq, int num_attrs)
{
DB_VALUE v;
int *prefix_length;
int i;
assert (prefix_seq != NULL && set_size (prefix_seq) == num_attrs);
prefix_length = (int *) db_ws_alloc (sizeof (int) * num_attrs);
if (prefix_length == NULL)
{
return NULL;
}
for (i = 0; i < num_attrs; i++)
{
if (set_get_element_nocopy (prefix_seq, i, &v) != NO_ERROR)
{
db_ws_free (prefix_length);
return NULL;
}
prefix_length[i] = db_get_int (&v);
}
return prefix_length;
}
/*
* classobj_make_index_filter_pred_info() - Make index filter predicate
* from sequence
* return: SM_PREDICATE_INFO *
* pred_seq(in): sequence which contains filter predicate
*/
static SM_PREDICATE_INFO *
classobj_make_index_filter_pred_info (DB_SEQ * pred_seq)
{
SM_PREDICATE_INFO *filter_predicate = NULL;
DB_VALUE fvalue, avalue, v;
const char *val_str = NULL;
size_t val_str_len = 0;
const char *buffer = NULL;
int buffer_len = 0;
DB_SEQ *att_seq = NULL;
int att_seq_size = 0, i;
assert (pred_seq != NULL && set_size (pred_seq) == 3);
db_make_null (&avalue);
if (set_get_element_nocopy (pred_seq, 0, &fvalue) != NO_ERROR)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SM_INVALID_PROPERTY, 0);
goto error;
}
if (DB_VALUE_TYPE (&fvalue) == DB_TYPE_NULL)
{
return NULL;
}
assert (DB_VALUE_TYPE (&fvalue) == DB_TYPE_STRING);
if (DB_VALUE_TYPE (&fvalue) != DB_TYPE_STRING)
{
assert (false);
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_GENERIC_ERROR, 0);
goto error;
}
val_str = db_get_string (&fvalue);
val_str_len = db_get_string_size (&fvalue);
assert (val_str != NULL);
filter_predicate = (SM_PREDICATE_INFO *) db_ws_alloc (sizeof (SM_PREDICATE_INFO));
if (filter_predicate == NULL)
{
goto error;
}
filter_predicate->pred_string = NULL;
filter_predicate->pred_stream = NULL;
filter_predicate->att_ids = NULL;
if (val_str_len > 0)
{
filter_predicate->pred_string = (char *) db_ws_alloc (val_str_len + 1);
if (filter_predicate->pred_string == NULL)
{
goto error;
}
memset (filter_predicate->pred_string, 0, val_str_len + 1);
memcpy (filter_predicate->pred_string, (val_str), val_str_len);
}
if (set_get_element_nocopy (pred_seq, 1, &fvalue) != NO_ERROR)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SM_INVALID_PROPERTY, 0);
goto error;
}
/* since pred string is not null, pred stream should be not null, also */
if (DB_VALUE_TYPE (&fvalue) != DB_TYPE_CHAR)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SM_INVALID_PROPERTY, 0);
goto error;
}
buffer = db_get_string (&fvalue);
buffer_len = db_get_string_size (&fvalue);
filter_predicate->pred_stream = (char *) db_ws_alloc (buffer_len * sizeof (char));
if (filter_predicate->pred_stream == NULL)
{
goto error;
}
memcpy (filter_predicate->pred_stream, buffer, buffer_len);
filter_predicate->pred_stream_size = buffer_len;
if (set_get_element (pred_seq, 2, &avalue) != NO_ERROR)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SM_INVALID_PROPERTY, 0);
goto error;
}
if (DB_VALUE_TYPE (&avalue) != DB_TYPE_SEQUENCE)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SM_INVALID_PROPERTY, 0);
goto error;
}
att_seq = db_get_set (&avalue);
filter_predicate->num_attrs = att_seq_size = set_size (att_seq);
if (att_seq_size == 0)
{
filter_predicate->att_ids = NULL;
}
else
{
filter_predicate->att_ids = (int *) db_ws_alloc (sizeof (int) * att_seq_size);
if (filter_predicate->att_ids == NULL)
{
goto error;
}
for (i = 0; i < att_seq_size; i++)
{
if (set_get_element_nocopy (att_seq, i, &v) != NO_ERROR)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SM_INVALID_PROPERTY, 0);
goto error;
}
filter_predicate->att_ids[i] = db_get_int (&v);
}
}
pr_clear_value (&avalue);
return filter_predicate;
error:
if (filter_predicate)
{
if (filter_predicate->pred_string)
{
db_ws_free (filter_predicate->pred_string);
}
if (filter_predicate->pred_stream)
{
db_ws_free (filter_predicate->pred_stream);
}
if (filter_predicate->att_ids)
{
db_ws_free (filter_predicate->att_ids);
}
db_ws_free (filter_predicate);
}
pr_clear_value (&avalue);
return NULL;
}
/*
* classobj_make_class_constraints() - Walk over a class property list extracting
* constraint information. Build up a list of SM_CLASS_CONSTRAINT structures
* and return it.
* The list must be freed with classobj_free_class_constraints().
* return: NO_ERROR on success, non-zero for ERROR
* class_props(in): class property list
* attributes(in):
* con_ptr(out):
*
* Note: For constraint structure details, see comment on SM_CLASS_CONSTRAINT in class_object.h.
*/
int
classobj_make_class_constraints (DB_SET * class_props, SM_ATTRIBUTE * attributes, SM_CLASS_CONSTRAINT ** con_ptr)
{
SM_ATTRIBUTE *att;
SM_CLASS_CONSTRAINT *constraints, *last, *new_;
DB_SET *props, *info, *fk;
DB_VALUE pvalue, uvalue, bvalue, avalue, fvalue, statusval;
DB_VALUE index_type, options, cvalue;
int i, j, k, e, len, info_len, att_cnt;
int *asc_desc;
int num_constraint_types = NUM_CONSTRAINT_TYPES;
if (con_ptr != NULL)
{
*con_ptr = NULL;
}
/* make sure these are initialized for the error cleanup code */
db_make_null (&pvalue);
db_make_null (&uvalue);
db_make_null (&bvalue);
db_make_null (&avalue);
db_make_null (&fvalue);
db_make_null (&statusval);
db_make_null (&index_type);
db_make_null (&options);
db_make_null (&cvalue);
constraints = last = NULL;
/*
* Process Index and Unique constraints
*/
for (k = 0; k < num_constraint_types; k++)
{
if (classobj_get_prop (class_props, Constraint_properties[k], &pvalue) > 0)
{
/* get the sequence & its size */
if (DB_VALUE_TYPE (&pvalue) != DB_TYPE_SEQUENCE)
{
goto structure_error;
}
props = db_get_set (&pvalue);
len = set_size (props);
for (i = 0; i < len; i += 2)
{
/* get the name */
if (set_get_element (props, i, &uvalue))
{
goto other_error;
}
if (DB_VALUE_TYPE (&uvalue) != DB_TYPE_STRING)
{
goto structure_error;
}
/* make a new constraint list node, the string in uvalue will become owned by the constraint so we don't
* have to free it. */
new_ = classobj_make_class_constraint (db_get_string (&uvalue), Constraint_types[k]);
if (new_ == NULL)
{
goto memory_error;
}
if (constraints == NULL)
{
constraints = new_;
}
else
{
last->next = new_;
}
last = new_;
/* Get the information sequence, this sequence contains a BTID followed by the names/ids of each
* attribute. */
if (set_get_element (props, i + 1, &uvalue))
{
goto structure_error;
}
if (DB_VALUE_TYPE (&uvalue) != DB_TYPE_SEQUENCE)
{
goto structure_error;
}
info = db_get_set (&uvalue);
info_len = set_size (info);
att_cnt = get_class_constraint_att_count (info_len);
e = 0;
/* get the btid */
if (set_get_element (info, e++, &bvalue))
{
goto structure_error;
}
if (classobj_btid_from_property_value (&bvalue, &new_->index_btid, (char **) &new_->shared_cons_name))
{
goto structure_error;
}
pr_clear_value (&bvalue);
/* Allocate an array to contain pointers to the attributes involved in this constraint. The array will be
* NULL terminated. */
new_->attributes = (SM_ATTRIBUTE **) db_ws_alloc (sizeof (SM_ATTRIBUTE *) * (att_cnt + 1));
if (new_->attributes == NULL)
{
goto memory_error;
}
new_->asc_desc = (int *) db_ws_alloc (sizeof (int) * att_cnt);
if (new_->asc_desc == NULL)
{
goto memory_error;
}
asc_desc = (int *) new_->asc_desc;
att = NULL;
/* Find each attribute referenced by the constraint. */
for (j = 0; j < att_cnt; j++)
{
/* name( or id) */
if (set_get_element (info, e++, &avalue))
{
goto structure_error;
}
if (DB_VALUE_TYPE (&avalue) == DB_TYPE_SEQUENCE)
{
new_->attributes[j] = NULL;
pr_clear_value (&avalue);
break;
}
if (DB_VALUE_TYPE (&avalue) == DB_TYPE_STRING)
{
att = classobj_find_attribute_list (attributes, db_get_string (&avalue), -1);
}
else if (DB_VALUE_TYPE (&avalue) == DB_TYPE_INTEGER)
{
att = classobj_find_attribute_list (attributes, NULL, db_get_int (&avalue));
}
else
{
goto structure_error;
}
new_->attributes[j] = att;
/* clear each attribute name/id value */
pr_clear_value (&avalue);
if (att == NULL)
{
/* go to the next element index in "info" */
e = 1 + att_cnt * 2;
break;
}
/* asc_desc */
if (set_get_element (info, e++, &avalue))
{
goto structure_error;
}
if (DB_VALUE_TYPE (&avalue) == DB_TYPE_INTEGER)
{
asc_desc[j] = db_get_int (&avalue);
if (Constraint_types[k] == SM_CONSTRAINT_REVERSE_UNIQUE
|| Constraint_types[k] == SM_CONSTRAINT_REVERSE_INDEX)
{
asc_desc[j] = 1; /* Desc */
}
}
else
{
goto structure_error;
}
/* clear each attribute asc_desc value */
pr_clear_value (&avalue);
}
/* If an attribute couldn't be found, then NULL out the entire array. Otherwise (if all attributes were
* found), NULL terminate the array . */
if (att == NULL)
{
j = 0;
}
for (; j < att_cnt + 1; j++)
{
new_->attributes[j] = NULL;
}
if (Constraint_types[k] == SM_CONSTRAINT_FOREIGN_KEY)
{
if (set_get_element (info, e++, &bvalue))
{
goto structure_error;
}
fk = db_get_set (&bvalue);
new_->fk_info = classobj_make_foreign_key_info (fk, new_->name, attributes);
if (new_->fk_info == NULL)
{
goto structure_error;
}
pr_clear_value (&bvalue);
}
else if (Constraint_types[k] == SM_CONSTRAINT_PRIMARY_KEY)
{
if (set_get_element (info, e++, &bvalue))
{
goto structure_error;
}
if (DB_VALUE_TYPE (&bvalue) == DB_TYPE_SEQUENCE)
{
new_->fk_info = classobj_make_foreign_key_ref_list (db_get_set (&bvalue));
if (new_->fk_info == NULL)
{
goto structure_error;
}
pr_clear_value (&bvalue);
}
}
else
{
if (set_get_element (info, e++, &bvalue))
{
goto structure_error;
}
if (DB_VALUE_TYPE (&bvalue) == DB_TYPE_SEQUENCE)
{
DB_SEQ *seq = db_get_set (&bvalue);
if (set_get_element (seq, 0, &fvalue))
{
pr_clear_value (&bvalue);
goto structure_error;
}
if (DB_VALUE_TYPE (&fvalue) == DB_TYPE_INTEGER)
{
new_->attrs_prefix_length = classobj_make_index_prefix_info (seq, att_cnt);
if (new_->attrs_prefix_length == NULL)
{
goto structure_error;
}
}
else if (DB_VALUE_TYPE (&fvalue) == DB_TYPE_SEQUENCE)
{
DB_SET *seq = db_get_set (&bvalue);
DB_SET *child_seq = db_get_set (&fvalue);
int seq_size = set_size (seq);
SM_INDEX_FLAG index_flag;
const char *index_flag_str;
j = 0;
while (true)
{
if (set_get_element (child_seq, 0, &avalue) != NO_ERROR)
{
goto structure_error;
}
if (DB_IS_NULL (&avalue) || DB_VALUE_TYPE (&avalue) != DB_TYPE_STRING)
{
goto structure_error;
}
index_flag_str = db_get_string (&avalue);
if (strcmp (index_flag_str, SM_FILTER_INDEX_ID) == 0)
{
index_flag = SM_INDEX_FLAG_FILTER;
}
else if (strcmp (index_flag_str, SM_FUNCTION_INDEX_ID) == 0)
{
index_flag = SM_INDEX_FLAG_FUNCTION;
}
else if (strcmp (index_flag_str, SM_PREFIX_INDEX_ID) == 0)
{
index_flag = SM_INDEX_FLAG_PREFIX;
}
else
{
index_flag = SM_INDEX_FLAG_NONE;
}
pr_clear_value (&avalue);
if (set_get_element (child_seq, 1, &avalue) != NO_ERROR)
{
goto structure_error;
}
if (DB_VALUE_TYPE (&avalue) != DB_TYPE_SEQUENCE)
{
goto structure_error;
}
switch (index_flag)
{
case SM_INDEX_FLAG_FILTER:
new_->filter_predicate = classobj_make_index_filter_pred_info (db_get_set (&avalue));
break;
case SM_INDEX_FLAG_FUNCTION:
new_->func_index_info = classobj_make_function_index_info (db_get_set (&avalue));
break;
case SM_INDEX_FLAG_PREFIX:
new_->attrs_prefix_length =
classobj_make_index_prefix_info (db_get_set (&avalue), att_cnt);
break;
default:
break;
}
pr_clear_value (&avalue);
j++;
if (j >= seq_size)
{
break;
}
pr_clear_value (&fvalue);
if (set_get_element (seq, j, &fvalue) != NO_ERROR)
{
goto structure_error;
}
if (DB_VALUE_TYPE (&fvalue) != DB_TYPE_SEQUENCE)
{
goto structure_error;
}
child_seq = db_get_set (&fvalue);
}
if (new_->func_index_info)
{
/* function index and prefix length not allowed, yet */
new_->attrs_prefix_length = (int *) db_ws_alloc (sizeof (int) * att_cnt);
if (new_->attrs_prefix_length == NULL)
{
goto structure_error;
}
for (j = 0; j < att_cnt; j++)
{
new_->attrs_prefix_length[j] = -1;
}
}
}
else
{
goto structure_error;
}
pr_clear_value (&bvalue);
pr_clear_value (&fvalue);
}
else
{
goto structure_error;
}
}
set_get_element (info, get_class_constraint_index (info_len, SM_CONSTRAINT_STATUS_INDEX), &statusval);
new_->index_status = (SM_INDEX_STATUS) db_get_int (&statusval);
set_get_element (info, get_class_constraint_index (info_len, SM_CONSTRAINT_INDEX_TYPE_INDEX),
&index_type);
new_->index_type = (SM_INDEX_TYPE) db_get_int (&index_type);
set_get_element (info, get_class_constraint_index (info_len, SM_CONSTRAINT_OPTIONS_INDEX), &options);
new_->options = db_get_int (&options);
if (set_get_element (info, get_class_constraint_index (info_len, SM_CONSTRAINT_COMMENT_INDEX), &cvalue))
{
/* if not exists, set comment to null */
new_->comment = NULL;
}
else if (DB_IS_NULL (&cvalue) || DB_VALUE_TYPE (&cvalue) == DB_TYPE_STRING)
{
/* take "cvalue == null" case into account */
new_->comment = db_get_string (&cvalue);
}
else
{
goto structure_error;
}
/* clear each unique info sequence value */
pr_clear_value (&uvalue);
}
/* clear the property value */
pr_clear_value (&pvalue);
}
}
if (con_ptr == NULL)
{
classobj_free_class_constraints (constraints);
}
else
{
*con_ptr = constraints;
}
return NO_ERROR;
/* ERROR PROCESSING */
structure_error:
/* should have a more appropriate error for this */
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SM_INVALID_PROPERTY, 0);
memory_error:
other_error:
/* clean up our values and return the error that has been set */
pr_clear_value (&cvalue);
pr_clear_value (&fvalue);
pr_clear_value (&avalue);
pr_clear_value (&bvalue);
pr_clear_value (&uvalue);
pr_clear_value (&pvalue);
pr_clear_value (&statusval);
pr_clear_value (&index_type);
pr_clear_value (&options);
classobj_free_class_constraints (constraints);
assert (er_errid () != NO_ERROR);
return er_errid ();
}
/*
* classobj_decache_class_constraints() - Removes any cached constraint information
* from the class.
* return: none
* class(in): class to ponder
*/
void
classobj_decache_class_constraints (SM_CLASS * class_)
{
assert (!class_->dont_decache_constraints_or_flush);
if (class_->constraints != NULL)
{
classobj_free_class_constraints (class_->constraints);
class_->constraints = NULL;
}
}
/*
* classobj_cache_not_null_constraints() - Cache the NOT NULL constraints from
* the attribute list into the CLASS constraint cache.
* return: NO_ERROR on success, non-zero for ERROR
* class_name(in): Class Name
* attributes(in): Pointer to an attribute list. NOT NULL constraints can
* be applied to normal, shared and class attributes.
* con_ptr(in/out): Pointer to the class constraint cache.
*/
static int
classobj_cache_not_null_constraints (const char *class_name, SM_ATTRIBUTE * attributes, SM_CLASS_CONSTRAINT ** con_ptr)
{
SM_ATTRIBUTE *att = NULL;
SM_CLASS_CONSTRAINT *new_ = NULL;
SM_CLASS_CONSTRAINT *constraints = NULL;
SM_CLASS_CONSTRAINT *last = NULL;
const char *att_names[2];
char *ws_name = NULL;
char *constraint_name = NULL;
/* Set constraints to point to the first node of the constraint cache and last to point to the last node. */
assert (con_ptr != NULL);
constraints = last = *con_ptr;
if (last != NULL)
{
while (last->next != NULL)
{
last = last->next;
}
}
for (att = attributes; att != NULL; att = (SM_ATTRIBUTE *) att->header.next)
{
if (att->flags & SM_ATTFLAG_NON_NULL)
{
/* Construct a default name for the constraint node. The constraint name is normally allocated from the heap
* but we want it stored in the workspace so we'll construct it as usual and then copy it into the workspace
* before calling classobj_make_class_constraint(). After the name is copied into the workspace it can be
* deallocated from the heap. The name will be deallocated from the workspace when the constraint node is
* destroyed. */
att_names[0] = att->header.name;
att_names[1] = NULL;
constraint_name = sm_produce_constraint_name (class_name, DB_CONSTRAINT_NOT_NULL, att_names, NULL, NULL);
if (constraint_name == NULL)
{
goto memory_error;
}
ws_name = ws_copy_string (constraint_name);
if (ws_name == NULL)
{
goto memory_error;
}
/* Allocate a new class constraint node */
new_ = classobj_make_class_constraint (ws_name, SM_CONSTRAINT_NOT_NULL);
if (new_ == NULL)
{
goto memory_error;
}
/* The constraint node now has a pointer to the workspace name so we'll disassociate our local pointer with
* the string. */
ws_name = NULL;
/* Add the new constraint node to the list */
if (constraints == NULL)
{
constraints = new_;
}
else
{
last->next = new_;
}
last = new_;
/* Allocate an array for the attribute involved in the constraint. The array will always contain one
* attribute pointer and a terminating NULL pointer. */
new_->attributes = (SM_ATTRIBUTE **) db_ws_alloc (sizeof (SM_ATTRIBUTE *) * 2);
if (new_->attributes == NULL)
{
goto memory_error;
}
new_->attributes[0] = att;
new_->attributes[1] = NULL;
free_and_init (constraint_name);
}
}
*con_ptr = constraints;
return NO_ERROR;
/* ERROR PROCESSING */
memory_error:
classobj_free_class_constraints (constraints);
if (constraint_name)
{
free_and_init (constraint_name);
}
if (ws_name)
{
db_ws_free (ws_name);
}
assert (er_errid () != NO_ERROR);
return er_errid ();
}
/*
* classobj_cache_class_constraints() - Converts the constraint information stored on
* the class's property list into the cache SM_CLASS_CONSTRAINT list in
* the class structure. This is way more convenient to deal with than
* walking through the property list. Note that modifications to the class
* do NOT become persistent.
* Need to merge this with the earlier code for SM_CONSTRAINT maintenance
* above.
* return: NO_ERROR on success, non-zero for ERROR
* class(in): class to ponder
*/
int
classobj_cache_class_constraints (SM_CLASS * class_)
{
int error = NO_ERROR;
classobj_decache_class_constraints (class_);
/* Cache the Indexes and Unique constraints found in the property list */
error = classobj_make_class_constraints (class_->properties, class_->attributes, &(class_->constraints));
/* The NOT NULL constraints are not in the property lists but are instead contained in the SM_ATTRIBUTE structures as
* flags. Search through the attributes and cache the NOT NULL constraints found. */
if (error != NO_ERROR)
{
return error;
}
error = classobj_cache_not_null_constraints (sm_ch_name ((MOBJ) class_), class_->attributes, &(class_->constraints));
if (error != NO_ERROR)
{
return error;
}
error = classobj_cache_not_null_constraints (sm_ch_name ((MOBJ) class_), class_->shared, &(class_->constraints));
if (error != NO_ERROR)
{
return error;
}
return classobj_cache_not_null_constraints (sm_ch_name ((MOBJ) class_), class_->class_attributes,
&(class_->constraints));
}
/*
* classobj_find_class_constraint() - Searches a list of class constraint structures
* for one with a certain name. Couldn't we be using nlist for this?
* return: constraint
* constraints(in): constraint list
* type(in):
* name(in): name to look for
*/
SM_CLASS_CONSTRAINT *
classobj_find_class_constraint (SM_CLASS_CONSTRAINT * constraints, SM_CONSTRAINT_TYPE type, const char *name)
{
SM_CLASS_CONSTRAINT *con;
for (con = constraints; con != NULL; con = con->next)
{
if ((con->type == type) && (intl_identifier_casecmp (con->name, name) == 0))
{
break;
}
}
return con;
}
/*
* classobj_find_class_constraint_by_btid() - Searches a list of class
* constraint structures for one with a certain btid. Couldn't we be
* using nlist for this?
* return: constraint
* constraints(in): constraint list
* type(in):
* btid(in): btid to look for
*/
SM_CLASS_CONSTRAINT *
classobj_find_class_constraint_by_btid (SM_CLASS_CONSTRAINT * constraints, SM_CONSTRAINT_TYPE type, BTID btid)
{
SM_CLASS_CONSTRAINT *con;
for (con = constraints; con != NULL; con = con->next)
{
if ((con->type == type) && BTID_IS_EQUAL (&btid, &con->index_btid))
{
break;
}
}
return con;
}
/*
* classobj_find_cons_index()
* return: constraint
* cons_list(in): constraint list
* name(in): name to look for
*/
SM_CLASS_CONSTRAINT *
classobj_find_constraint_by_name (SM_CLASS_CONSTRAINT * cons_list, const char *name)
{
SM_CLASS_CONSTRAINT *cons;
for (cons = cons_list; cons; cons = cons->next)
{
if ((SM_IS_CONSTRAINT_INDEX_FAMILY (cons->type)) && !SM_COMPARE_NAMES (cons->name, name))
{
break;
}
}
return cons;
}
/*
* classobj_find_class_index()
* return: constraint
* class(in):
* name(in): name to look for
*/
SM_CLASS_CONSTRAINT *
classobj_find_class_index (SM_CLASS * class_, const char *name)
{
return classobj_find_constraint_by_name (class_->constraints, name);
}
/*
* classobj_find_cons_primary_key()
* return: constraint
* cons_list(in):
*/
SM_CLASS_CONSTRAINT *
classobj_find_cons_primary_key (SM_CLASS_CONSTRAINT * cons_list)
{
SM_CLASS_CONSTRAINT *cons = NULL;
for (cons = cons_list; cons; cons = cons->next)
{
if (cons->type == SM_CONSTRAINT_PRIMARY_KEY)
{
break;
}
}
return cons;
}
/*
* classobj_find_class_primary_key()
* return: constraint
* class(in):
*/
SM_CLASS_CONSTRAINT *
classobj_find_class_primary_key (SM_CLASS * class_)
{
return classobj_find_cons_primary_key (class_->constraints);
}
#if defined(ENABLE_UNUSED_FUNCTION)
/*
* classobj_count_class_foreign_key()
* return:
* class(in):
*/
int
classobj_count_class_foreign_key (SM_CLASS * class_)
{
SM_CLASS_CONSTRAINT *cons = NULL;
int count = 0;
for (cons = class_->constraints; cons; cons = cons->next)
{
if (cons->type == SM_CONSTRAINT_FOREIGN_KEY)
count++;
}
return count;
}
/*
* classobj_count_cons_attributes()
* return:
* cons(in):
*/
int
classobj_count_cons_attributes (SM_CLASS_CONSTRAINT * cons)
{
int i = 0;
for (i = 0; cons->attributes[i]; i++);
return i;
}
#endif /* ENABLE_UNUSED_FUNCTION */
/*
* classobj_is_possible_constraint()
* return:
* existed(in):
* new(in):
*/
static bool
classobj_is_possible_constraint (SM_CONSTRAINT_TYPE existed, DB_CONSTRAINT_TYPE new_)
{
switch (existed)
{
case SM_CONSTRAINT_UNIQUE:
case SM_CONSTRAINT_PRIMARY_KEY:
switch (new_)
{
case DB_CONSTRAINT_UNIQUE:
case DB_CONSTRAINT_PRIMARY_KEY:
return false;
case DB_CONSTRAINT_INDEX:
return false;
case DB_CONSTRAINT_REVERSE_UNIQUE:
return false;
case DB_CONSTRAINT_REVERSE_INDEX:
return true;
case DB_CONSTRAINT_FOREIGN_KEY:
return false;
default:
return true;
}
case SM_CONSTRAINT_INDEX:
switch (new_)
{
case DB_CONSTRAINT_UNIQUE:
case DB_CONSTRAINT_PRIMARY_KEY:
return false;
case DB_CONSTRAINT_INDEX:
return false;
case DB_CONSTRAINT_REVERSE_UNIQUE:
return true;
case DB_CONSTRAINT_REVERSE_INDEX:
return true;
case DB_CONSTRAINT_FOREIGN_KEY:
return false;
default:
return true;
}
case SM_CONSTRAINT_REVERSE_UNIQUE:
switch (new_)
{
case DB_CONSTRAINT_UNIQUE:
case DB_CONSTRAINT_PRIMARY_KEY:
return false;
case DB_CONSTRAINT_INDEX:
return true;
case DB_CONSTRAINT_REVERSE_UNIQUE:
return false;
case DB_CONSTRAINT_REVERSE_INDEX:
return false;
case DB_CONSTRAINT_FOREIGN_KEY:
return false;
default:
return true;
}
case SM_CONSTRAINT_REVERSE_INDEX:
switch (new_)
{
case DB_CONSTRAINT_UNIQUE:
case DB_CONSTRAINT_PRIMARY_KEY:
return true;
case DB_CONSTRAINT_INDEX:
return true;
case DB_CONSTRAINT_REVERSE_UNIQUE:
return false;
case DB_CONSTRAINT_REVERSE_INDEX:
return false;
case DB_CONSTRAINT_FOREIGN_KEY:
return true;
default:
return true;
}
case SM_CONSTRAINT_FOREIGN_KEY:
switch (new_)
{
case DB_CONSTRAINT_UNIQUE:
case DB_CONSTRAINT_PRIMARY_KEY:
return false;
case DB_CONSTRAINT_INDEX:
return false;
case DB_CONSTRAINT_REVERSE_UNIQUE:
return false;
case DB_CONSTRAINT_REVERSE_INDEX:
return true;
case DB_CONSTRAINT_FOREIGN_KEY:
return false;
default:
return true;
}
default:
return true;
}
}
/*
* classobj_find_cons_index2_col_type_list()
* return:
* cons(in):
* stats(in):
*/
TP_DOMAIN *
classobj_find_cons_index2_col_type_list (SM_CLASS_CONSTRAINT * cons, OID * root_oid)
{
TP_DOMAIN *key_type = NULL;
int i, j;
ATTR_STATS *attr_statsp;
BTREE_STATS *bt_statsp;
CLASS_STATS *local_stats = NULL;
if (!cons)
{
return NULL; /* invalid args */
}
if (!SM_IS_CONSTRAINT_INDEX_FAMILY (cons->type))
{
return NULL; /* give up */
}
if (OID_ISNULL (root_oid))
{
return NULL;
}
/* Get local stats including invisible indexes. */
int err = stats_get_statistics (root_oid, 0, &local_stats);
if (err != NO_ERROR || local_stats == NULL)
{
return NULL;
}
attr_statsp = local_stats->attr_stats;
for (i = 0; i < local_stats->n_attrs && !key_type; i++, attr_statsp++)
{
bt_statsp = attr_statsp->bt_stats;
for (j = 0; j < attr_statsp->n_btstats && !key_type; j++, bt_statsp++)
{
if (BTID_IS_EQUAL (&bt_statsp->btid, &cons->index_btid))
{
key_type = bt_statsp->key_type;
}
} /* for ( j = 0; ...) */
} /* for ( i = 0; ...) */
if (TP_DOMAIN_TYPE (key_type) == DB_TYPE_MIDXKEY)
{
/* get the column key-type of multi-column index */
key_type = key_type->setdomain;
}
if (local_stats != NULL)
{
stats_free_statistics (local_stats);
}
return key_type;
}
/* support for SUPPORT_DEDUPLICATE_KEY_MODE */
bool
classobj_check_attr_in_unique_constraint (SM_CLASS_CONSTRAINT * cons_list, char **att_names,
SM_FUNCTION_INFO * func_index_info)
{
SM_CLASS_CONSTRAINT *cons;
SM_ATTRIBUTE **attp;
char **namep;
int cols_non_func;
// If there is a column corresponding to PK/UK among the attributes constituting the index, the deduplicate_key_column is not added.
if (func_index_info)
{
cols_non_func = func_index_info->attr_index_start;
}
else
{
cols_non_func = 0;
for (namep = att_names; *namep; namep++)
{
cols_non_func++;
}
}
for (cons = cons_list; cons; cons = cons->next)
{
if (SM_IS_CONSTRAINT_UNIQUE_FAMILY (cons->type) == false)
{
continue;
}
else if (!cons->attributes)
{
continue;
}
for (attp = cons->attributes; *attp; attp++)
{
int idx;
bool found = false;
for (idx = 0, namep = att_names; *namep && idx < cols_non_func; namep++, idx++)
{
if (intl_identifier_casecmp ((*attp)->header.name, *namep) == 0)
{
found = true;
break;
}
}
if (found == false)
{
break; /* not found */
}
}
if (*attp == NULL)
{
return true;
}
}
return false;
}
/*
* classobj_find_cons_index2()
* return:
* cons_list(in):
* stats(in):
* new_cons(in):
* att_names(in):
* asc_desc(in):
*/
SM_CLASS_CONSTRAINT *
classobj_find_constraint_by_attrs (SM_CLASS_CONSTRAINT * cons_list, DB_CONSTRAINT_TYPE new_cons, const char **att_names,
const int *asc_desc, const SM_PREDICATE_INFO * filter_predicate,
const SM_FUNCTION_INFO * func_index_info)
{
SM_CLASS_CONSTRAINT *cons;
SM_ATTRIBUTE **attp;
const char **namep;
int i, len, order;
int new_len = 0;
int new_index_start = 0, con_index_start = 0;
bool is_uk_new, is_compare_except_dedup_key = false;
/* for foreign key, need to check redundancy first */
if (new_cons == DB_CONSTRAINT_FOREIGN_KEY)
{
for (cons = cons_list; cons; cons = cons->next)
{
/* check foreign key only */
if (!cons->attributes || cons->type != SM_CONSTRAINT_FOREIGN_KEY)
{
continue;
}
attp = cons->attributes;
namep = att_names;
while (*attp && *namep && !intl_identifier_casecmp ((*attp)->header.name, *namep))
{
attp++;
namep++;
}
/* In the case of FK, reserved index columns are ignored when comparing identical configurations. */
if (*attp && IS_DEDUPLICATE_KEY_ATTR_NAME ((*attp)->header.name))
{
attp++;
}
if (*namep && IS_DEDUPLICATE_KEY_ATTR_NAME (*namep))
{
namep++;
}
/* not allowed redundant one */
if (!*attp && !*namep)
{
return cons;
}
}
}
is_uk_new = DB_IS_CONSTRAINT_UNIQUE_FAMILY (new_cons);
for (cons = cons_list; cons; cons = cons->next)
{
if (!SM_IS_CONSTRAINT_INDEX_FAMILY (cons->type))
{
continue;
}
attp = cons->attributes;
namep = att_names;
assert (namep != NULL);
if (!attp)
{
continue;
}
if (((filter_predicate && !cons->filter_predicate) || (!filter_predicate && cons->filter_predicate))
|| ((func_index_info && !cons->func_index_info) || (!func_index_info && cons->func_index_info)))
{
continue;
}
len = 0; /* init */
while (*attp && *namep && !intl_identifier_casecmp ((*attp)->header.name, *namep))
{
attp++;
namep++;
len++; /* increase name number */
}
is_compare_except_dedup_key = is_uk_new || SM_IS_CONSTRAINT_UNIQUE_FAMILY (cons->type);
if (func_index_info)
{
con_index_start = cons->func_index_info->attr_index_start;
new_index_start = func_index_info->attr_index_start;
}
if (is_compare_except_dedup_key)
{
// In comparison with UK, the information of the added key column is ignored and compared.
new_len = len;
if (*attp)
{
if (IS_DEDUPLICATE_KEY_ATTR_NAME ((*attp)->header.name))
{
attp++;
len++;
con_index_start--;
}
}
if (*namep)
{
if (IS_DEDUPLICATE_KEY_ATTR_NAME (*namep))
{
namep++;
new_len++;
new_index_start--;
}
}
}
else if (new_cons == DB_CONSTRAINT_FOREIGN_KEY)
{
// In the case of FK, even if the key columns to be added are different, they are ignored.
if (*namep && IS_DEDUPLICATE_KEY_ATTR_NAME (*namep))
{
if (*attp && IS_DEDUPLICATE_KEY_ATTR_NAME ((*attp)->header.name))
{
attp++;
namep++;
}
}
}
if (*attp || *namep || classobj_is_possible_constraint (cons->type, new_cons))
{
continue;
}
for (i = 0; i < len; i++)
{
if (is_compare_except_dedup_key)
{
if (i >= new_len)
{
if ((i + 1) == len)
{
i++; /* set matched */
}
break;
}
}
/* if not specified, ascending order */
order = (asc_desc ? asc_desc[i] : 0);
assert (order == 0 || order == 1);
if (order != cons->asc_desc[i])
{
break; /* not match */
}
}
if (i != len)
{
continue;
}
if (filter_predicate)
{
if (!filter_predicate->pred_string || !cons->filter_predicate->pred_string)
{
continue;
}
if (strcmp (filter_predicate->pred_string, cons->filter_predicate->pred_string))
{
continue;
}
}
if (func_index_info)
{
/* expr_str are printed tree, identifiers are already lower case */
if ((func_index_info->col_id != cons->func_index_info->col_id)
|| (new_index_start != con_index_start)
|| (func_index_info->fi_domain->is_desc != cons->func_index_info->fi_domain->is_desc)
|| (strcmp (func_index_info->expr_str, cons->func_index_info->expr_str) != 0))
{
continue;
}
}
return cons;
}
return cons;
}
/*
* cl_remove_class_constraint() - Drop the constraint node from the class
* constraint cache.
* return: none
* constraints(in): Pointer to class constraint list
* node(in): Pointer to a node in the constraint list
*/
void
classobj_remove_class_constraint_node (SM_CLASS_CONSTRAINT ** constraints, SM_CLASS_CONSTRAINT * node)
{
SM_CLASS_CONSTRAINT *con = NULL, *next = NULL, *prev = NULL;
for (con = *constraints; con != NULL; con = next)
{
next = con->next;
if (con != node)
{
prev = con;
}
else
{
if (prev == NULL)
{
*constraints = con->next;
}
else
{
prev->next = con->next;
}
con->next = NULL;
}
}
}
/*
* classobj_populate_class_properties() - Populate the property list from the class
* constraint cache. Only the specified constraint type is populated.
* return: NO_ERROR on success, non-zero for ERROR
* properties(out): Pointer to class properties
* constraints(in): Pointer to class constraint list
* type(in): Type of constraint
*/
int
classobj_populate_class_properties (DB_SET ** properties, SM_CLASS_CONSTRAINT * constraints, SM_CONSTRAINT_TYPE type)
{
int error = NO_ERROR;
SM_CLASS_CONSTRAINT *con;
const char *property_type;
/* Map the SM_CONSTRAINT_TYPE to a SM_PROPERTY_TYPE */
property_type = classobj_map_constraint_to_property (type);
if (property_type == NULL)
{
assert (er_errid () != NO_ERROR);
error = er_errid ();
}
if (error != NO_ERROR)
{
return error;
}
/* Drop the selected property from the property list */
classobj_drop_prop (*properties, property_type);
/* Rebuild the property list entry from the constraint cache */
for (con = constraints; con != NULL && !error; con = con->next)
{
if (con->type != type)
{
continue;
}
if (classobj_put_index (properties, con, &(con->index_btid), con->fk_info, con->shared_cons_name, false) !=
NO_ERROR)
{
error = ER_SM_INVALID_PROPERTY;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 0);
}
}
return error;
}
/*
* classobj_class_has_indexes() - Searches the class constraints
* return: true if the class contains indexes(INDEX or UNIQUE constraints)
* class(in): Class
*/
bool
classobj_class_has_indexes (SM_CLASS * class_)
{
SM_CLASS_CONSTRAINT *con;
bool has_index = false;
has_index = false;
for (con = class_->constraints; (con != NULL && !has_index); con = con->next)
{
if (SM_IS_CONSTRAINT_INDEX_FAMILY (con->type))
{
has_index = true;
}
}
return has_index;
}
/* SM_DOMAIN */
/*
* classobj_domain_size() - Caclassobj_domain_sizee number of bytes of memory required for
* a domain list.
* return: byte size of domain list
* domain(in): domain list
*/
static int
classobj_domain_size (TP_DOMAIN * domain)
{
int size;
size = sizeof (TP_DOMAIN);
size += ws_list_total ((DB_LIST *) domain->setdomain, (LTOTALER) classobj_domain_size);
return (size);
}
/* SM_ATTRIBUTE */
/*
* classobj_make_attribute() - Construct a new attribute structure.
* return: attribute structure
* name(in): attribute name
* type(in): primitive type
* namespace(in): type of attribute (instance or class )
*/
SM_ATTRIBUTE *
classobj_make_attribute (const char *name, const PR_TYPE * type, SM_NAME_SPACE name_space)
{
SM_ATTRIBUTE *att;
att = (SM_ATTRIBUTE *) db_ws_alloc (sizeof (SM_ATTRIBUTE));
if (att == NULL)
{
return NULL;
}
att->header.next = NULL;
att->header.name = NULL;
att->header.name_space = name_space;
att->id = -1;
/* try to start phasing out att->type and instead use att->domain everywhere - jsl */
att->type = type;
att->domain = NULL;
att->class_mop = NULL;
att->offset = 0;
att->flags = 0;
att->order = 0;
att->storage_order = 0;
/* initial values are unbound */
db_make_null (&att->default_value.original_value);
db_make_null (&att->default_value.value);
classobj_initialize_default_expr (&att->default_value.default_expr);
att->on_update_default_expr = DB_DEFAULT_NONE;
att->constraints = NULL;
att->order_link = NULL;
att->properties = NULL;
att->triggers = NULL;
if (name != NULL)
{
att->header.name = ws_copy_string (name);
if (att->header.name == NULL)
{
db_ws_free (att);
return NULL;
}
}
att->comment = NULL;
return (att);
}
/*
* classobj_filter_attribute_props() - This examines the property list for copied
* attribute and removes properties that aren't supposed to be copied as
* attributes definitions are flattened. We could possibly make this
* part of classobj_copy_props above.
* UNIQUE properties are inheritable but INDEX properties are not.
* return: none
* properties(in): property list to filter
*/
static void
classobj_filter_attribute_props (DB_SEQ * props)
{
/* these properties aren't inherited, they must be defined locally */
classobj_drop_prop (props, SM_PROPERTY_INDEX);
classobj_drop_prop (props, SM_PROPERTY_REVERSE_INDEX);
}
/*
* classobj_initialize_attributes() - Initializes attribute
*
* return: nothing
* attributes(in): attributes
*/
void
classobj_initialize_attributes (SM_ATTRIBUTE * attributes)
{
SM_ATTRIBUTE *attr;
for (attr = attributes; attr != NULL; attr = (SM_ATTRIBUTE *) (attr->header.next))
{
attr->constraints = NULL;
attr->order_link = NULL;
attr->properties = NULL;
attr->triggers = NULL;
attr->header.name = NULL;
attr->domain = NULL;
attr->comment = NULL;
db_value_put_null (&attr->default_value.value);
db_value_put_null (&attr->default_value.original_value);
classobj_initialize_default_expr (&attr->default_value.default_expr);
attr->on_update_default_expr = DB_DEFAULT_NONE;
}
}
/*
* classobj_initialize_methods() - Initializes methods
*
* return: nothing
* attributes(in): attributes
*/
void
classobj_initialize_methods (SM_METHOD * methods)
{
SM_METHOD *method;
for (method = methods; method != NULL; method = (SM_METHOD *) (method->header.next))
{
method->properties = NULL;
method->function = NULL;
method->signatures = NULL;
method->header.name = NULL;
}
}
/*
* classobj_init_attribute() - Initializes an attribute using the contents of
* another attribute. This is used when an attribute list is flattened
* during class definition and the attribute lists are converted into
* a threaded array of attributes.
* NOTE: External allocations like name & domain may be either copied
* or simply have their pointers transfered depending on the value
* of the copy flag.
* NOTE: Be careful not to touch the "next" field here since it may
* have been already initialized as part of a threaded array.
* return: NO_ERROR on success, non-zero for ERROR
* src(in): source attribute
* dest(out): destination attribute
* copy(in): copy flag (non-zero to copy)
*/
static int
classobj_init_attribute (SM_ATTRIBUTE * src, SM_ATTRIBUTE * dest, int copy)
{
int error = NO_ERROR;
assert (src != NULL);
dest->header.name = NULL;
dest->header.name_space = src->header.name_space;
dest->id = src->id; /* correct ? */
dest->type = src->type;
dest->class_mop = src->class_mop;
dest->offset = src->offset;
dest->flags = src->flags;
dest->order = src->order;
dest->storage_order = src->storage_order;
dest->order_link = NULL; /* can never be copied */
dest->constraints = NULL;
dest->triggers = NULL;
dest->domain = NULL;
dest->properties = NULL;
dest->auto_increment = src->auto_increment;
classobj_copy_default_expr (&dest->default_value.default_expr, &src->default_value.default_expr);
dest->on_update_default_expr = src->on_update_default_expr;
dest->comment = NULL;
if (copy)
{
if (src->header.name != NULL)
{
dest->header.name = ws_copy_string (src->header.name);
if (dest->header.name == NULL)
{
goto memory_error;
}
}
if (src->comment != NULL)
{
dest->comment = ws_copy_string (src->comment);
if (dest->comment == NULL)
{
goto memory_error;
}
}
if (src->domain != NULL)
{
dest->domain = tp_domain_copy (src->domain, true);
if (dest->domain == NULL)
{
goto memory_error;
}
}
if (src->properties != NULL)
{
error = classobj_copy_props (src->properties, NULL, &dest->properties);
if (error != NO_ERROR)
{
goto memory_error;
}
}
if (src->triggers != NULL)
{
dest->triggers = tr_copy_schema_cache (src->triggers, NULL);
if (dest->triggers == NULL)
{
goto memory_error;
}
}
/* remove the properties that can't be inherited */
classobj_filter_attribute_props (dest->properties);
if (src->constraints != NULL)
{
/*
* We used to just copy the unique BTID from the source to the
* destination. We might want to copy the src cache to dest, or
* maybe regenerate the cache for dest since the information is
* already in its property list. - JB
*/
}
/* make a copy of the default value */
if (pr_clone_value (&src->default_value.value, &dest->default_value.value))
{
goto memory_error;
}
if (pr_clone_value (&src->default_value.original_value, &dest->default_value.original_value))
{
goto memory_error;
}
}
else
{
dest->header.name = src->header.name;
dest->constraints = src->constraints;
dest->properties = src->properties;
dest->triggers = src->triggers;
dest->comment = src->comment;
src->header.name = NULL;
src->constraints = NULL;
src->properties = NULL;
src->triggers = NULL;
src->comment = NULL;
/* Note that we don't clear the source domain here since it must be cached at this point. We keep the
* src->domain around until the attribute is freed in case it is needed for something related to the default
* values, etc. */
dest->domain = src->domain;
/*
* do structure copies on the values and make sure the sources
* get cleared
*/
dest->default_value.value = src->default_value.value;
dest->default_value.original_value = src->default_value.original_value;
db_value_put_null (&src->default_value.value);
db_value_put_null (&src->default_value.original_value);
}
return NO_ERROR;
memory_error:
/* Could try to free the partially allocated things. If we get here then we're out of virtual memory, a few leaks
* aren't going to matter much. */
assert (er_errid () != NO_ERROR);
return er_errid ();
}
/*
* classobj_copy_attribute() - Copies an attribute.
* The alias if provided will override the attribute name.
* return: new attribute
* src(in): source attribute
* alias(in): alias name (can be NULL)
*/
SM_ATTRIBUTE *
classobj_copy_attribute (SM_ATTRIBUTE * src, const char *alias)
{
SM_ATTRIBUTE *att;
att = (SM_ATTRIBUTE *) db_ws_alloc (sizeof (SM_ATTRIBUTE));
if (att == NULL)
{
return NULL;
}
att->header.next = NULL;
/* make a unique copy */
if (classobj_init_attribute (src, att, 1))
{
db_ws_free (att);
return NULL;
}
if (alias != NULL)
{
ws_free_string (att->header.name);
att->header.name = ws_copy_string (alias);
if (att->header.name == NULL)
{
db_ws_free (att);
return NULL;
}
}
return (att);
}
/*
* classobj_copy_attlist() - Copies an attribute list. This does NOT return a
* threaded array. The filter_class is optional and will cause only those
* attributes whose origin is the given class to be copied to the result list
* return: NO_ERROR on success, non-zero for ERROR
* attlist(in): attribute list
* filter_class(in): optional filter class
* ordered(in):
* copy_ptr(out): new attribute list
*/
int
classobj_copy_attlist (SM_ATTRIBUTE * attlist, MOP filter_class, int ordered, SM_ATTRIBUTE ** copy_ptr)
{
SM_ATTRIBUTE *att, *new_, *first, *last, *next;
first = last = NULL;
for (att = attlist, next = NULL; att != NULL; att = next)
{
if (ordered)
{
next = att->order_link;
}
else
{
next = (SM_ATTRIBUTE *) att->header.next;
}
if ((filter_class == NULL) || (filter_class == att->class_mop))
{
new_ = classobj_copy_attribute (att, NULL);
if (new_ == NULL)
{
goto memory_error;
}
if (first == NULL)
{
first = new_;
}
else
{
last->header.next = (SM_COMPONENT *) new_;
}
last = new_;
}
}
*copy_ptr = first;
return NO_ERROR;
memory_error:
/* Could try to free the previously copied attribute list. We're out of virtual memory at this point. A few leaks
* aren't going to matter. */
assert (er_errid () != NO_ERROR);
return er_errid ();
}
/*
* classobj_clear_attribute_value() - This gets rid of storage for a DB_VALUE attached
* to a class. This is a kludge primarily for the handling of set handles.
* In normal db_value_clear() semantics, we would simply end up calling
* set_free() on the set reference.
* set_free() checks the ownership if the reference and will not free
* the underlying set object if it is owned. Also, it won't free the
* reference or set if the reference count is >1.
* Here its a bit different since the class completely in charge of
* how the storage for this set is managed.
* We go around the usual db_value_clear() rules to make sure the
* set gets freed.
* As always, the handling of set memory needs to be cleaned up.
* return: none
* value(in/out): value to clear
*/
static void
classobj_clear_attribute_value (DB_VALUE * value)
{
SETREF *ref;
SETOBJ *set;
if (!DB_IS_NULL (value) && TP_IS_SET_TYPE (DB_VALUE_TYPE (value)))
{
/* get directly to the set */
ref = db_get_set (value);
if (ref != NULL)
{
set = ref->set;
/* always free the underlying set object */
if (set != NULL)
{
setobj_free (set);
}
/* now free the reference, if the counter goes to zero its freed otherwise, it gets left dangling but at
* least we've free the set storage at this point */
set_free (ref);
}
}
else
{
/* clear it the usual way */
pr_clear_value (value);
}
}
/*
* classobj_clear_attribute() - Deallocate storage associated with an attribute.
* Note that this doesn't deallocate the attribute structure itself since
* this may be part of a threaded array.
* return: none
* att(in/out): attribute
*/
static void
classobj_clear_attribute (SM_ATTRIBUTE * att)
{
if (att == NULL)
{
return;
}
if (att->header.name != NULL)
{
ws_free_string (att->header.name);
att->header.name = NULL;
}
if (att->comment != NULL)
{
ws_free_string (att->comment);
att->comment = NULL;
}
if (att->constraints != NULL)
{
classobj_free_constraint (att->constraints);
att->constraints = NULL;
}
if (att->properties != NULL)
{
classobj_free_prop (att->properties);
att->properties = NULL;
}
if (att->triggers != NULL)
{
tr_free_schema_cache (att->triggers);
att->triggers = NULL;
}
classobj_clear_attribute_value (&att->default_value.value);
classobj_clear_attribute_value (&att->default_value.original_value);
if (att->default_value.default_expr.default_expr_format)
{
ws_free_string (att->default_value.default_expr.default_expr_format);
att->default_value.default_expr.default_expr_format = NULL;
}
att->header.name = NULL;
/* Do this last in case we needed it for default value maintenance or something. This probably isn't necessary, the
* domain should have been cached at this point ? */
if (att->domain != NULL)
{
tp_domain_free (att->domain);
att->domain = NULL;
}
}
/*
* classobj_free_attribute() - Frees an attribute structure and all memory
* associated with the attribute.
* return: none
* att(in): attribute
*/
void
classobj_free_attribute (SM_ATTRIBUTE * att)
{
if (att != NULL)
{
classobj_clear_attribute (att);
db_ws_free (att);
}
}
/*
* classobj_attribute_size() - Calculates the number of bytes required for the
* memory representation of an attribute.
* return: byte size of attribute
* att(in): attribute
*/
static int
classobj_attribute_size (SM_ATTRIBUTE * att)
{
int size;
size = sizeof (SM_ATTRIBUTE);
/* this can be NULL only for attributes used in an old representation */
if (att->header.name != NULL)
{
size += strlen (att->header.name) + 1;
}
size += ws_list_total ((DB_LIST *) att->domain, (LTOTALER) classobj_domain_size);
size += pr_value_mem_size (&att->default_value.value);
size += pr_value_mem_size (&att->default_value.original_value);
if (att->constraints != NULL)
{
size += ws_list_total ((DB_LIST *) att->constraints, (LTOTALER) classobj_constraint_size);
}
if (att->comment != NULL)
{
size += strlen (att->comment) + 1;
}
/* need to add in property set */
return (size);
}
/* SM_METHOD_ARGUMENT */
/*
* Initially these were threaded arrays. I changed them to be simple lists
* because its easier to maintain and we won't be doing method overloading
* for awhile (possibly never).
*
* When we start doing performance optimization for method dispatching, the
* arglist should be compiled into an arrays.
*/
/*
* classobj_make_method_arg() - Creates and initializes a method argument strucutre.
* return: new method argument
* index(in): argument index
*/
SM_METHOD_ARGUMENT *
classobj_make_method_arg (int index)
{
SM_METHOD_ARGUMENT *arg;
arg = (SM_METHOD_ARGUMENT *) db_ws_alloc (sizeof (SM_METHOD_ARGUMENT));
if (arg != NULL)
{
arg->next = NULL;
arg->index = index;
arg->type = NULL;
arg->domain = NULL;
}
return (arg);
}
/*
* classobj_free_method_arg() - Frees memory associated with a method argument.
* return: none
* arg(in): method argument
*/
static void
classobj_free_method_arg (SM_METHOD_ARGUMENT * arg)
{
if (arg != NULL)
{
if (arg->domain != NULL)
{
tp_domain_free (arg->domain);
}
db_ws_free (arg);
}
}
/*
* classobj_copy_method_arg() - Copies a method argument structure
* including the domain list.
* return: new method argument
* src(in): source method argument
*/
static SM_METHOD_ARGUMENT *
classobj_copy_method_arg (SM_METHOD_ARGUMENT * src)
{
SM_METHOD_ARGUMENT *new_ = NULL;
if (src == NULL)
{
return NULL;
}
new_ = classobj_make_method_arg (src->index);
if (new_ != NULL)
{
new_->type = src->type;
if (src->domain != NULL)
{
new_->domain = tp_domain_copy (src->domain, true);
if (new_->domain == NULL)
{
classobj_free_method_arg (new_);
new_ = NULL;
}
}
}
return (new_);
}
/*
* classobj_method_arg_size() - Calculates the number of bytes of storage
* for a method argument.
* return: byte size of method argument
* arg(in): argument
*/
static int
classobj_method_arg_size (SM_METHOD_ARGUMENT * arg)
{
int size;
size = sizeof (SM_METHOD_ARGUMENT);
size += ws_list_total ((DB_LIST *) arg->domain, (LTOTALER) classobj_domain_size);
return (size);
}
/*
* classobj_find_method_arg() - This searches an argument list for an argument with the
* given index. If the argument was not found and the create flag is
* non-zero, a new argument structure is allocated and added to the list.
* return: method argument structure
* arglist(in): argument list (possibly modified)
* index(in): argument index
* create(in): create flag (non-zero to create)
*/
SM_METHOD_ARGUMENT *
classobj_find_method_arg (SM_METHOD_ARGUMENT ** arglist, int index, int create)
{
SM_METHOD_ARGUMENT *arg, *found;
found = NULL;
for (arg = *arglist; arg != NULL && found == NULL; arg = arg->next)
{
if (arg->index == index)
{
found = arg;
}
}
if ((found == NULL) && create)
{
found = classobj_make_method_arg (index);
if (found != NULL)
{
found->next = *arglist;
*arglist = found;
}
}
return (found);
}
/* SM_METHOD_SIGNATURE */
/* Multiple method signatures are not actually supported in the language but
* the original implementation supported them so we'll leave them in in case
* we wish to support them in the future.
*/
/*
* classobj_make_method_signature() - Makes a method signature.
* The name must be the name of the C function that implements this
* method. Two signatures cannot have the same name.
* return: new method signature
* name(in): implementation name
*/
SM_METHOD_SIGNATURE *
classobj_make_method_signature (const char *name)
{
SM_METHOD_SIGNATURE *sig;
sig = (SM_METHOD_SIGNATURE *) db_ws_alloc (sizeof (SM_METHOD_SIGNATURE));
if (sig == NULL)
{
return NULL;
}
sig->next = NULL;
sig->function_name = NULL;
sig->sql_definition = NULL;
sig->function = NULL;
sig->num_args = 0;
sig->value = NULL;
sig->args = NULL;
if (name != NULL)
{
sig->function_name = ws_copy_string (name);
if (sig->function_name == NULL)
{
db_ws_free (sig);
sig = NULL;
}
}
return (sig);
}
/*
* classobj_free_method_signature() - Free a method signature structure and
* associated storage.
* return: none
* sig(in): signature
*/
void
classobj_free_method_signature (SM_METHOD_SIGNATURE * sig)
{
if (sig != NULL)
{
ws_free_string (sig->function_name);
ws_free_string (sig->sql_definition);
ws_list_free ((DB_LIST *) sig->value, (LFREEER) classobj_free_method_arg);
ws_list_free ((DB_LIST *) sig->args, (LFREEER) classobj_free_method_arg);
db_ws_free (sig);
}
}
/*
* classobj_copy_method_signature() - Copy a method signature and all associated
* arguments and domains.
* return: new method signature
* sig(in): source method signature
*/
static SM_METHOD_SIGNATURE *
classobj_copy_method_signature (SM_METHOD_SIGNATURE * sig)
{
SM_METHOD_SIGNATURE *new_;
new_ = classobj_make_method_signature (sig->function_name);
if (new_ == NULL)
{
return NULL;
}
new_->value = NULL;
new_->args = NULL;
new_->sql_definition = NULL;
new_->num_args = sig->num_args;
new_->function = sig->function; /* should this be reset to NULL ? */
if (sig->value != NULL)
{
new_->value =
(SM_METHOD_ARGUMENT *) ws_list_copy ((DB_LIST *) sig->value, (LCOPIER) classobj_copy_method_arg,
(LFREEER) classobj_free_method_arg);
if (new_->value == NULL)
{
goto memory_error;
}
}
if (sig->args != NULL)
{
new_->args =
(SM_METHOD_ARGUMENT *) ws_list_copy ((DB_LIST *) sig->args, (LCOPIER) classobj_copy_method_arg,
(LFREEER) classobj_free_method_arg);
if (new_->args == NULL)
{
goto memory_error;
}
}
if (sig->sql_definition != NULL)
{
new_->sql_definition = ws_copy_string (sig->sql_definition);
if (new_->sql_definition == NULL)
{
goto memory_error;
}
}
return (new_);
memory_error:
if (new_ != NULL)
{
classobj_free_method_signature (new_);
}
return NULL;
}
/*
* classobj_method_signature_size() - Calculates the amound of memory used by
* a method signature.
* return: byte size of signature
* sig(in): signature to examine
*/
static int
classobj_method_signature_size (SM_METHOD_SIGNATURE * sig)
{
int size;
size = sizeof (SM_METHOD_SIGNATURE);
if (sig->function_name != NULL)
{
size += strlen (sig->function_name) + 1;
}
if (sig->sql_definition != NULL)
{
size += strlen (sig->sql_definition) + 1;
}
size += ws_list_total ((DB_LIST *) sig->value, (LTOTALER) classobj_method_arg_size);
size += ws_list_total ((DB_LIST *) sig->args, (LTOTALER) classobj_method_arg_size);
return (size);
}
/* SM_METHOD */
/*
* classobj_make_method() - Creates a new method strucutre.
* return: new method
* name(in): method name
* namespace (in): method type (class or instance)
*/
SM_METHOD *
classobj_make_method (const char *name, SM_NAME_SPACE name_space)
{
SM_METHOD *meth;
meth = (SM_METHOD *) db_ws_alloc (sizeof (SM_METHOD));
if (meth == NULL)
{
return NULL;
}
meth->header.next = NULL;
meth->header.name = NULL;
meth->header.name_space = name_space;
meth->function = NULL;
meth->class_mop = NULL;
meth->id = -1;
meth->signatures = NULL;
meth->properties = NULL;
if (name != NULL)
{
meth->header.name = ws_copy_string (name);
if (meth->header.name == NULL)
{
db_ws_free (meth);
meth = NULL;
}
}
return (meth);
}
/*
* classobj_clear_method() - Release storage contained in a method structure.
* The method structure itself is not freed.
* return: none
* meth(in/out): method
*/
static void
classobj_clear_method (SM_METHOD * meth)
{
if (meth == NULL)
{
return;
}
if (meth->header.name != NULL)
{
ws_free_string (meth->header.name);
meth->header.name = NULL;
}
if (meth->properties != NULL)
{
classobj_free_prop (meth->properties);
meth->properties = NULL;
}
if (meth->signatures != NULL)
{
ws_list_free ((DB_LIST *) meth->signatures, (LFREEER) classobj_free_method_signature);
meth->signatures = NULL;
}
}
/*
* classobj_init_method() - Initializes a method structure with a copy of another
* method structure. If the copy flag is non-zero, external allocations
* like method name and signatures are copied. If the copy
* flag is zero, the pointers to the external allocations are
* used directly.
* return: NO_ERROR on success, non-zero for ERROR
* src(in): source method
* dest(out): destination method
* copy(in): copy flag (non-zero to copy)
*/
static int
classobj_init_method (SM_METHOD * src, SM_METHOD * dest, int copy)
{
int error = NO_ERROR;
dest->header.name = NULL;
dest->header.name_space = src->header.name_space;
dest->class_mop = src->class_mop;
dest->id = src->id;
dest->function = src->function; /* reset to NULL ? */
dest->signatures = NULL;
dest->properties = NULL;
if (copy)
{
if (src->header.name != NULL)
{
dest->header.name = ws_copy_string (src->header.name);
if (dest->header.name == NULL)
{
goto memory_error;
}
}
if (src->signatures != NULL)
{
dest->signatures =
(SM_METHOD_SIGNATURE *) ws_list_copy ((DB_LIST *) src->signatures, (LCOPIER) classobj_copy_method_signature,
(LFREEER) classobj_free_method_signature);
if (dest->signatures == NULL)
{
goto memory_error;
}
}
if (src->properties != NULL)
{
/* there are no method properties that need to be filtered */
error = classobj_copy_props (src->properties, NULL, &dest->properties);
if (error != NO_ERROR)
{
goto memory_error;
}
}
}
else
{
dest->header.name = src->header.name;
dest->signatures = src->signatures;
dest->properties = src->properties;
src->header.name = NULL;
src->signatures = NULL;
src->properties = NULL;
}
return NO_ERROR;
memory_error:
classobj_clear_method (dest);
assert (er_errid () != NO_ERROR);
return er_errid ();
}
/*
* classobj_copy_method() - Copies a method structure. The alias name is given
* will override the method name.
* return: new method
* src(in): source method
* alias(in): alias name (optional)
*/
SM_METHOD *
classobj_copy_method (SM_METHOD * src, const char *alias)
{
SM_METHOD *meth;
meth = (SM_METHOD *) db_ws_alloc (sizeof (SM_METHOD));
if (meth == NULL)
{
return NULL;
}
meth->header.next = NULL;
if (classobj_init_method (src, meth, 1))
{
db_ws_free (meth);
return NULL;
}
if (alias != NULL)
{
ws_free_string (meth->header.name);
meth->header.name = ws_copy_string (alias);
if (meth->header.name == NULL)
{
db_ws_free (meth);
return NULL;
}
}
return (meth);
}
/*
* classobj_copy_methlist() - Copies a method list. This does NOT return a threaded
* array. The filter class is optional and if set will copy only those
* methods whose origin is the filter class.
* return: NO_ERROR on success, non-zero for ERROR
* methlist(in): method list
* filter_class(in): optional filter class
* copy_ptr(out): new method list
*/
static int
classobj_copy_methlist (SM_METHOD * methlist, MOP filter_class, SM_METHOD ** copy_ptr)
{
SM_METHOD *meth, *new_meth, *first, *last;
first = last = NULL;
for (meth = methlist; meth != NULL; meth = (SM_METHOD *) meth->header.next)
{
if ((filter_class == NULL) || (meth->class_mop == filter_class))
{
new_meth = classobj_copy_method (meth, NULL);
if (new_meth == NULL)
{
goto memory_error;
}
if (first == NULL)
{
first = new_meth;
}
else
{
last->header.next = (SM_COMPONENT *) new_meth;
}
last = new_meth;
}
}
*copy_ptr = first;
return NO_ERROR;
memory_error:
/* could free the partially constructed method list */
assert (er_errid () != NO_ERROR);
return er_errid ();
}
/*
* classobj_free_method() - Free a method and any associated storage.
* return: none
* meth(in): method
*/
void
classobj_free_method (SM_METHOD * meth)
{
if (meth != NULL)
{
classobj_clear_method (meth);
db_ws_free (meth);
}
}
/*
* classobj_method_size() - Calculates the amount of memory used for a method.
* return: byte size of method
* meth(in): method
*/
static int
classobj_method_size (SM_METHOD * meth)
{
int size;
size = sizeof (SM_METHOD);
size += strlen (meth->header.name) + 1;
size += ws_list_total ((DB_LIST *) meth->signatures, (LTOTALER) classobj_method_signature_size);
return (size);
}
/* SM_RESOLUTION */
/*
* classobj_free_resolution() - Free a resolution structure and any associated memory.
* return: none
* res(in): resolution
*/
void
classobj_free_resolution (SM_RESOLUTION * res)
{
if (res != NULL)
{
if (res->name != NULL)
{
ws_free_string (res->name);
}
if (res->alias != NULL)
{
ws_free_string (res->alias);
}
db_ws_free (res);
}
}
/*
* classobj_make_resolution() - Builds a new resolution structure.
* return: new resolution
* class_mop(in): source class
* name(in): attribute/method name
* alias(in): optional alias
* name_space(in): resolution type (class or instance)
*/
SM_RESOLUTION *
classobj_make_resolution (MOP class_mop, const char *name, const char *alias, SM_NAME_SPACE name_space)
{
SM_RESOLUTION *res;
res = (SM_RESOLUTION *) db_ws_alloc (sizeof (SM_RESOLUTION));
if (res == NULL)
{
return NULL;
}
res->next = NULL;
res->class_mop = class_mop;
res->name_space = name_space;
res->name = NULL;
res->alias = NULL;
if (name != NULL)
{
res->name = ws_copy_string (name);
if (res->name == NULL)
{
goto memory_error;
}
}
if (alias != NULL)
{
res->alias = ws_copy_string (alias);
if (res->alias == NULL)
{
goto memory_error;
}
}
return res;
memory_error:
if (res != NULL)
{
classobj_free_resolution (res);
}
return NULL;
}
/*
* classobj_copy_reslist() - Copies a resolution list.
* The copy can be filtered by using the resspace argument.
* If resspace is ID_INSTANCE, only instance level resolutions
* will be copied. If resspace is ID_CLASS, only class level resolutions
* will be copied. If resspace is ID_NULL, all resolutions will be
* copied.
* return: NO_ERROR on success, non-zero for ERROR
* src(in): source resolution list
* resspace(in): resolution name_space (ID_NULL if no filtering)
* copy_ptr(out): new resolution list
*/
int
classobj_copy_reslist (SM_RESOLUTION * src, SM_NAME_SPACE resspace, SM_RESOLUTION ** copy_ptr)
{
SM_RESOLUTION *r, *new_resolution, *first, *last;
first = last = NULL;
for (r = src; r != NULL; r = r->next)
{
if (resspace == ID_NULL || resspace == r->name_space)
{
new_resolution = classobj_make_resolution (r->class_mop, r->name, r->alias, r->name_space);
if (new_resolution == NULL)
{
goto memory_error;
}
if (first == NULL)
{
first = new_resolution;
}
else
{
last->next = new_resolution;
}
last = new_resolution;
}
}
*copy_ptr = first;
return NO_ERROR;
memory_error:
/* could free the partially constructed resolution list */
assert (er_errid () != NO_ERROR);
return er_errid ();
}
/*
* classobj_resolution_size() - Calculates the amount of memory used by a resolution.
* return: byte size of resolution
* res(in): resolution
*/
static int
classobj_resolution_size (SM_RESOLUTION * res)
{
int size;
size = sizeof (SM_RESOLUTION);
size += strlen (res->name) + 1;
if (res->alias != NULL)
{
size += strlen (res->alias) + 1;
}
return (size);
}
/*
* classobj_find_resolution() - Searches a resolution list for a resolution
* that matches the arguments.
* return: resolution structure
* reslist(in): list of resolution structures
* class_mop(in): source class
* name(in): attribute/method name
* name_space(in): name_space identifier (class or instance)
*/
SM_RESOLUTION *
classobj_find_resolution (SM_RESOLUTION * reslist, MOP class_mop, const char *name, SM_NAME_SPACE name_space)
{
SM_RESOLUTION *res, *found = NULL;
for (res = reslist, found; res != NULL && found == NULL; res = res->next)
{
if ((name_space == ID_NULL || name_space == res->name_space) && (class_mop == res->class_mop)
&& (strcmp (res->name, name) == 0))
{
found = res;
}
}
return found;
}
/* SM_METHOD_FILE */
/*
* classobj_free_method_file() - Frees a method file and any associated storage.
* return: none
* file(in): method file structure
*/
void
classobj_free_method_file (SM_METHOD_FILE * file)
{
if (file != NULL)
{
if (file->name != NULL)
{
ws_free_string (file->name);
}
if (file->expanded_name != NULL)
{
ws_free_string (file->expanded_name);
}
if (file->source_name)
{
ws_free_string (file->source_name);
}
db_ws_free (file);
}
}
/*
* classobj_make_method_file() - This builds a method file structure.
* return: method file structure
* name(in): name of the file
*/
SM_METHOD_FILE *
classobj_make_method_file (const char *name)
{
SM_METHOD_FILE *file;
file = (SM_METHOD_FILE *) db_ws_alloc (sizeof (SM_METHOD_FILE));
if (file == NULL)
{
return NULL;
}
file->next = NULL;
file->name = NULL;
file->class_mop = NULL;
file->expanded_name = NULL;
file->source_name = NULL;
if (name != NULL)
{
file->name = ws_copy_string (name);
if (file->name == NULL)
{
db_ws_free (file);
file = NULL;
}
}
return (file);
}
/*
* classobj_copy_methfile() - Copy a method file structure.
* return: copied method file
* src(in): method file to copy
*/
static SM_METHOD_FILE *
classobj_copy_methfile (SM_METHOD_FILE * src)
{
SM_METHOD_FILE *new_method_file = NULL;
if (src == NULL)
{
return NULL;
}
new_method_file = classobj_make_method_file (src->name);
if (new_method_file == NULL)
{
return NULL;
}
new_method_file->class_mop = src->class_mop;
if (src->expanded_name != NULL)
{
new_method_file->expanded_name = ws_copy_string (src->expanded_name);
if (new_method_file->expanded_name == NULL)
{
goto memory_error;
}
}
if (src->source_name != NULL)
{
new_method_file->source_name = ws_copy_string (src->source_name);
if (new_method_file->source_name == NULL)
{
goto memory_error;
}
}
return new_method_file;
memory_error:
if (new_method_file != NULL)
{
classobj_free_method_file (new_method_file);
}
return NULL;
}
/*
* classobj_copy_methfiles() - Copy a list of method files.
* return: NO_ERROR on success, non-zero for ERROR
* files(in): method file list
* filter_class(in): optional filter class
* copy_ptr(out): new method file list
*/
int
classobj_copy_methfiles (SM_METHOD_FILE * files, MOP filter_class, SM_METHOD_FILE ** copy_ptr)
{
SM_METHOD_FILE *f, *new_method_file, *first, *last;
first = last = NULL;
for (f = files; f != NULL; f = f->next)
{
if (filter_class == NULL || f->class_mop == NULL || f->class_mop == filter_class)
{
new_method_file = classobj_copy_methfile (f);
if (new_method_file == NULL)
{
goto memory_error;
}
if (first == NULL)
{
first = new_method_file;
}
else
{
last->next = new_method_file;
}
last = new_method_file;
}
}
*copy_ptr = first;
return NO_ERROR;
memory_error:
assert (er_errid () != NO_ERROR);
return er_errid ();
}
/*
* classobj_method_file_size() - Calculates the amount of storage used by a method file.
* return: byte size of method file
* file(in): method file structure
*/
static int
classobj_method_file_size (SM_METHOD_FILE * method_file)
{
int size;
size = sizeof (SM_METHOD_FILE);
size += strlen (method_file->name) + 1;
if (method_file->expanded_name != NULL)
{
size += strlen (method_file->expanded_name) + 1;
}
if (method_file->source_name != NULL)
{
size += strlen (method_file->source_name) + 1;
}
return (size);
}
/* SM_REPR_ATTRIBUTE */
/*
* classobj_make_repattribute() - Creates a new representation attribute structure.
* return: new repattribute structure
* attid(in): attribute id
* typeid(in): type id
* domain(in):
*/
SM_REPR_ATTRIBUTE *
classobj_make_repattribute (int attid, DB_TYPE type_id, TP_DOMAIN * domain)
{
SM_REPR_ATTRIBUTE *rat;
rat = (SM_REPR_ATTRIBUTE *) db_ws_alloc (sizeof (SM_REPR_ATTRIBUTE));
if (rat == NULL)
{
return NULL;
}
rat->next = NULL;
rat->attid = attid;
rat->typeid_ = type_id;
/* think about consolidating the typeid & domain fields */
rat->domain = domain;
return (rat);
}
/*
* classobj_free_repattribute() - Frees storage for a representation attribute.
* return: none
* rat(in): representation attribute
*/
static void
classobj_free_repattribute (SM_REPR_ATTRIBUTE * rat)
{
if (rat != NULL)
{
db_ws_free (rat);
}
}
/*
* classobj_repattribute_size() - memory size of a representation attribute.
* return: byte size of attribute
*/
static int
classobj_repattribute_size (void)
{
int size = sizeof (SM_REPR_ATTRIBUTE);
return (size);
}
/* SM_REPRESENTATION */
/*
* classobj_make_representation() - Create a new representation structure.
* return: new representation
*/
SM_REPRESENTATION *
classobj_make_representation ()
{
SM_REPRESENTATION *rep;
rep = (SM_REPRESENTATION *) db_ws_alloc (sizeof (SM_REPRESENTATION));
if (rep == NULL)
{
return NULL;
}
rep->next = NULL;
rep->id = -1;
rep->fixed_count = 0;
rep->variable_count = 0;
rep->attributes = NULL;
return (rep);
}
/*
* classobj_free_representation() - Free a representation structure and any
* associated memory.
* return: none
* rep(in): representation
*/
void
classobj_free_representation (SM_REPRESENTATION * rep)
{
if (rep != NULL)
{
ws_list_free ((DB_LIST *) rep->attributes, (LFREEER) classobj_free_repattribute);
db_ws_free (rep);
}
}
/*
* classobj_representation_size() - memory storage used by a representation.
* return: byte size of representation
* rep(in): representation strcuture
*/
static int
classobj_representation_size (SM_REPRESENTATION * rep)
{
SM_REPR_ATTRIBUTE *rat;
int size;
size = sizeof (SM_REPRESENTATION);
for (rat = rep->attributes; rat != NULL; rat = rat->next)
{
size += classobj_repattribute_size ();
}
return (size);
}
/* SM_QUERY_SPEC */
/*
* classobj_make_query_spec() - Allocate and initialize a query_spec structure.
* return: new query_spec structure
* specification(in): query_spec string
*/
SM_QUERY_SPEC *
classobj_make_query_spec (const char *specification)
{
SM_QUERY_SPEC *query_spec;
query_spec = (SM_QUERY_SPEC *) db_ws_alloc (sizeof (SM_QUERY_SPEC));
if (query_spec == NULL)
{
return NULL;
}
query_spec->next = NULL;
query_spec->specification = NULL;
if (specification != NULL)
{
query_spec->specification = ws_copy_string (specification);
if (query_spec->specification == NULL)
{
db_ws_free (query_spec);
query_spec = NULL;
}
}
return (query_spec);
}
/*
* classobj_copy_query_spec_list() - Copy a list of SM_QUERY_SPEC structures.
* return: new list
* query_spec(in): source list
*/
SM_QUERY_SPEC *
classobj_copy_query_spec_list (SM_QUERY_SPEC * query_spec)
{
SM_QUERY_SPEC *p, *new_, *first, *last;
first = last = NULL;
for (p = query_spec; p != NULL; p = p->next)
{
new_ = classobj_make_query_spec (p->specification);
if (new_ == NULL)
{
goto memory_error;
}
if (first == NULL)
{
first = new_;
}
else
{
last->next = new_;
}
last = new_;
}
return (first);
memory_error:
return NULL;
}
/*
* classobj_free_query_spec() - Frees storage for a query_spec specification and
* any associated memory.
* return: none
* query_spec(in): query_spec structure to free
*/
void
classobj_free_query_spec (SM_QUERY_SPEC * query_spec)
{
if (query_spec != NULL)
{
if (query_spec->specification != NULL)
{
ws_free_string (query_spec->specification);
}
db_ws_free (query_spec);
}
}
/*
* classobj_query_spec_size() - Calculates the amount of storage used by
* a query_spec structure.
* return: byte size of query_spec
* query_spec(in): query_spec structure
*/
static int
classobj_query_spec_size (SM_QUERY_SPEC * query_spec)
{
int size;
size = sizeof (SM_QUERY_SPEC);
size += strlen (query_spec->specification) + 1;
return (size);
}
/*
* classobj_partition_info_size () - Calculates the amount of storage used by
* a sm_partition structure
* return: byte size of query_spec
* partition_info(in): sm_partition structure
*/
static int
classobj_partition_info_size (SM_PARTITION * partition_info)
{
int size;
DB_VALUE val;
size = sizeof (SM_PARTITION);
if (partition_info->comment)
{
size += strlen (partition_info->comment) + 1;
}
if (partition_info->pname)
{
size += strlen (partition_info->pname) + 1;
}
if (partition_info->expr)
{
size += strlen (partition_info->expr) + 1;
}
db_make_sequence (&val, partition_info->values);
size += or_packed_value_size (&val, 1, 1, 0);
return (size);
}
/* SM_TEMPLATE */
/*
* classobj_free_template() - Frees a class template and any associated memory.
* return: none
* template(in): class editing template
*/
void
classobj_free_template (SM_TEMPLATE * template_ptr)
{
if (template_ptr == NULL)
{
return;
}
ml_free (template_ptr->inheritance);
ws_list_free ((DB_LIST *) template_ptr->attributes, (LFREEER) classobj_free_attribute);
ws_list_free ((DB_LIST *) template_ptr->class_attributes, (LFREEER) classobj_free_attribute);
ws_list_free ((DB_LIST *) template_ptr->instance_attributes, (LFREEER) classobj_free_attribute);
ws_list_free ((DB_LIST *) template_ptr->shared_attributes, (LFREEER) classobj_free_attribute);
ws_list_free ((DB_LIST *) template_ptr->methods, (LFREEER) classobj_free_method);
ws_list_free ((DB_LIST *) template_ptr->class_methods, (LFREEER) classobj_free_method);
ws_list_free ((DB_LIST *) template_ptr->resolutions, (LFREEER) classobj_free_resolution);
ws_list_free ((DB_LIST *) template_ptr->class_resolutions, (LFREEER) classobj_free_resolution);
ws_list_free ((DB_LIST *) template_ptr->method_files, (LFREEER) classobj_free_method_file);
ws_list_free ((DB_LIST *) template_ptr->query_spec, (LFREEER) classobj_free_query_spec);
ws_list_free ((DB_LIST *) template_ptr->partition, (LFREEER) classobj_free_partition_info);
ws_free_string (template_ptr->loader_commands);
ws_free_string (template_ptr->name);
if (template_ptr->super_id_map != NULL)
{
db_ws_free (template_ptr->super_id_map);
}
classobj_free_prop (template_ptr->properties);
ml_ext_free (template_ptr->ext_references);
if (template_ptr->triggers != NULL)
{
tr_free_schema_cache ((TR_SCHEMA_CACHE *) template_ptr->triggers);
}
(void) area_free (Template_area, template_ptr);
}
/*
* classobj_make_template() - Allocates and initializes a class editing template.
* The class MOP and structure are optional, it supplied the template
* will be initialized with the contents of the class. If not supplied
* the template will be empty.
* return: new template
* name(in): class name
* op(in): class MOP
* class(in): class structure
*/
SM_TEMPLATE *
classobj_make_template (const char *name, MOP op, SM_CLASS * class_)
{
SM_TEMPLATE *template_ptr;
int error = NO_ERROR;
template_ptr = (SM_TEMPLATE *) area_alloc (Template_area);
if (template_ptr == NULL)
{
return NULL;
}
template_ptr->class_type = SM_CLASS_CT;
template_ptr->op = op;
template_ptr->current = class_;
template_ptr->tran_index = tm_Tran_index;
template_ptr->name = NULL;
template_ptr->inheritance = NULL;
template_ptr->attributes = NULL;
template_ptr->class_attributes = NULL;
template_ptr->methods = NULL;
template_ptr->class_methods = NULL;
template_ptr->resolutions = NULL;
template_ptr->class_resolutions = NULL;
template_ptr->method_files = NULL;
template_ptr->loader_commands = NULL;
template_ptr->query_spec = NULL;
template_ptr->instance_attributes = NULL;
template_ptr->shared_attributes = NULL;
template_ptr->ext_references = NULL;
template_ptr->properties = NULL;
template_ptr->super_id_map = NULL;
template_ptr->triggers = NULL;
template_ptr->partition_parent_atts = NULL;
template_ptr->partition = NULL;
if (name != NULL)
{
template_ptr->name = ws_copy_string (name);
if (template_ptr->name == NULL)
{
goto memory_error;
}
}
if (class_ != NULL)
{
template_ptr->class_type = class_->class_type;
if (classobj_copy_attlist (class_->ordered_attributes, op, 1, &template_ptr->attributes))
{
goto memory_error;
}
if (classobj_copy_attlist (class_->class_attributes, op, 0, &template_ptr->class_attributes))
{
goto memory_error;
}
if (classobj_copy_methlist (class_->methods, op, &template_ptr->methods))
{
goto memory_error;
}
if (classobj_copy_methlist (class_->class_methods, op, &template_ptr->class_methods))
{
goto memory_error;
}
if (classobj_copy_reslist (class_->resolutions, ID_INSTANCE, &template_ptr->resolutions))
{
goto memory_error;
}
if (classobj_copy_reslist (class_->resolutions, ID_CLASS, &template_ptr->class_resolutions))
{
goto memory_error;
}
if (classobj_copy_methfiles (class_->method_files, op, &template_ptr->method_files))
{
goto memory_error;
}
if (class_->inheritance != NULL)
{
template_ptr->inheritance = ml_copy (class_->inheritance);
if (template_ptr->inheritance == NULL)
{
goto memory_error;
}
}
if (class_->loader_commands != NULL)
{
template_ptr->loader_commands = ws_copy_string (class_->loader_commands);
if (template_ptr->loader_commands == NULL)
{
goto memory_error;
}
}
if (class_->query_spec)
{
template_ptr->query_spec = classobj_copy_query_spec_list (class_->query_spec);
if (template_ptr->query_spec == NULL)
{
goto memory_error;
}
}
if (class_->properties != NULL)
{
error = classobj_copy_props (class_->properties, op, &template_ptr->properties);
if (error != NO_ERROR)
{
goto memory_error;
}
}
if (class_->triggers != NULL)
{
template_ptr->triggers = tr_copy_schema_cache (class_->triggers, op);
if (template_ptr->triggers == NULL)
{
goto memory_error;
}
}
if (class_->partition != NULL)
{
template_ptr->partition = classobj_copy_partition_info (class_->partition);
if (template_ptr->partition == NULL)
{
goto memory_error;
}
}
/* Formerly cl_make_id_map(class), forget what that was supposed to do. This isn't currently used. */
template_ptr->super_id_map = NULL;
}
return (template_ptr);
memory_error:
if (template_ptr != NULL)
{
classobj_free_template (template_ptr);
}
return NULL;
}
/*
* classobj_make_template_like() - Allocates and initializes a class template
* based on an existing class.
* The existing class attributes and constraints are duplicated so that the
* new template can be used for the "CREATE LIKE" statement.
* Triggers are not duplicated (this is the same as MySQL does).
* Indexes cannot be duplicated by this function because class templates
* don't allow index creation. The indexes will be duplicated after the class
* is created.
* Partitions are not yet duplicated by this function.
* return: the new template
* name(in): the name of the new class
* class(in): class structure to duplicate
*/
SM_TEMPLATE *
classobj_make_template_like (const char *name, SM_CLASS * class_)
{
SM_TEMPLATE *template_ptr;
const char *existing_name = NULL;
SM_ATTRIBUTE *a;
SM_CLASS_CONSTRAINT *c;
assert (name != NULL);
assert (class_ != NULL);
assert (class_->class_type == SM_CLASS_CT);
assert (class_->query_spec == NULL);
existing_name = sm_ch_name ((MOBJ) class_);
if (class_->partition != NULL)
{
/* It is possible to support this but the code has not been written yet. */
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SM_CANT_COPY_WITH_FEATURE, 3, name, existing_name,
"CREATE TABLE ... PARTITION BY");
return NULL;
}
if (class_->inheritance != NULL || class_->users != NULL || class_->resolutions != NULL)
{
/* Copying a class that is part of an inheritance chain would result in weird situations; we disallow this.
* MySQL's CREATE LIKE did not need to interact with OO features anyway. */
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SM_CANT_COPY_WITH_FEATURE, 3, name, existing_name,
"CREATE CLASS ... UNDER");
return NULL;
}
if (class_->methods != NULL || class_->class_methods != NULL || class_->method_files != NULL
|| class_->loader_commands != NULL)
{
/* It does not make sense to copy the methods that were designed for another class. We could silently ignore the
* methods but we prefer to flag an error because CREATE LIKE will be used for MySQL type applications mostly and
* will not interact with CUBRID features too often. */
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SM_CANT_COPY_WITH_FEATURE, 3, name, existing_name,
"CREATE CLASS ... METHOD");
return NULL;
}
template_ptr = smt_def_class (name);
if (template_ptr == NULL)
{
return NULL;
}
if (class_->attributes != NULL || class_->shared != NULL)
{
for (a = class_->ordered_attributes; a != NULL; a = a->order_link)
{
if (classobj_copy_attribute_like (template_ptr, a, existing_name) != NO_ERROR)
{
goto error_exit;
}
}
}
if (class_->class_attributes != NULL)
{
for (a = class_->class_attributes; a != NULL; a = (SM_ATTRIBUTE *) a->header.next)
{
if (classobj_copy_attribute_like (template_ptr, a, existing_name) != NO_ERROR)
{
goto error_exit;
}
}
}
if (class_->constraints != NULL)
{
for (c = class_->constraints; c; c = c->next)
{
if (SM_IS_CONSTRAINT_UNIQUE_FAMILY (c->type) || c->type == SM_CONSTRAINT_FOREIGN_KEY)
{
if (classobj_copy_constraint_like (template_ptr, c, existing_name) != NO_ERROR)
{
goto error_exit;
}
}
else
{
/* NOT NULL have already been copied by classobj_copy_attribute_like. INDEX will be duplicated after the
* class is created. */
assert (c->type == SM_CONSTRAINT_INDEX || c->type == SM_CONSTRAINT_REVERSE_INDEX
|| c->type == SM_CONSTRAINT_NOT_NULL);
}
}
}
return template_ptr;
error_exit:
if (template_ptr != NULL)
{
classobj_free_template (template_ptr);
}
return NULL;
}
/*
* classobj_copy_attribute_like() - Copies an attribute from an existing class
* to a new class template.
* Potential NOT NULL constraints on the attribute are copied also.
* return: NO_ERROR on success, non-zero for ERROR
* ctemplate(in): the template to copy to
* attribute(in): the attribute to be duplicated
* like_class_name(in): the name of the class that is duplicated
*/
static int
classobj_copy_attribute_like (DB_CTMPL * ctemplate, SM_ATTRIBUTE * attribute, const char *const like_class_name)
{
int error = NO_ERROR;
const char *names[2];
assert (like_class_name != NULL);
if (attribute->flags & SM_ATTFLAG_AUTO_INCREMENT)
{
/* It is possible to support this but the code has not been written yet. The fact that CUBRID supports the
* "AUTO_INCREMENT(start_at, increment)" syntax complicates the duplication of the attribute. */
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SM_CANT_COPY_WITH_FEATURE, 3, ctemplate->name, like_class_name,
"AUTO_INCREMENT");
return er_errid ();
}
error =
smt_add_attribute_w_dflt (ctemplate, attribute->header.name, NULL, attribute->domain,
&attribute->default_value.value, attribute->header.name_space,
&attribute->default_value.default_expr,
&attribute->on_update_default_expr, attribute->comment);
if (error != NO_ERROR)
{
return error;
}
if (attribute->flags & SM_ATTFLAG_NON_NULL)
{
names[0] = attribute->header.name;
names[1] = NULL;
error =
dbt_add_constraint (ctemplate, DB_CONSTRAINT_NOT_NULL, NULL, names,
attribute->header.name_space == ID_CLASS_ATTRIBUTE ? 1 : 0, NULL);
if (error != NO_ERROR)
{
return error;
}
}
return error;
}
/*
* classobj_point_at_att_names() - Allocates a NULL-terminated array of pointers
* to the names of the attributes referenced in
* a constraint.
* return: the array on success, NULL on error
* constraint(in): the constraint
* count_ref(out): if supplied, the referenced integer will be modified to
* contain the number of attributes
*/
const char **
classobj_point_at_att_names (SM_CLASS_CONSTRAINT * constraint, int *count_ref)
{
const char **att_names = NULL;
SM_ATTRIBUTE **attribute_p = NULL;
int count;
int i;
for (attribute_p = constraint->attributes, count = 0; *attribute_p; ++attribute_p)
{
++count;
}
att_names = (const char **) malloc ((count + 1) * sizeof (const char *));
if (att_names == NULL)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, (count + 1) * sizeof (const char *));
return NULL;
}
for (attribute_p = constraint->attributes, i = 0; *attribute_p != NULL; ++attribute_p, ++i)
{
att_names[i] = (*attribute_p)->header.name;
}
att_names[i] = NULL;
if (count_ref != NULL)
{
*count_ref = count;
}
return att_names;
}
/*
* classobj_copy_constraint_like() - Copies a constraint from an existing
* class to a new class template.
* Constraint names are copied as they are, even if they are the defaults
* given to unnamed constraints. The default names will be a bit misleading
* since they will have the duplicated class name in their contents. MySQL
* also copies the default name for indexes.
* return: NO_ERROR on success, non-zero for ERROR
* ctemplate(in): the template to copy to
* constraint(in): the constraint to be duplicated
* like_class_name(in): the name of the class that is duplicated
*/
static int
classobj_copy_constraint_like (DB_CTMPL * ctemplate, SM_CLASS_CONSTRAINT * constraint,
const char *const like_class_name)
{
int error = NO_ERROR;
DB_CONSTRAINT_TYPE constraint_type = db_constraint_type (constraint);
const char **att_names = NULL;
const char **ref_attrs = NULL;
int count = 0;
int count_ref = 0;
char *auto_cons_name = NULL;
char *new_cons_name = NULL;
assert (like_class_name != NULL);
/* We are sure this will not be a class constraint (the only possible class constraints are NOT NULL constraints). */
assert (constraint_type != DB_CONSTRAINT_NOT_NULL);
/* We are sure this constraint can be processed by dbt_add_constraint (indexes cannot be added to templates). */
assert (constraint_type != DB_CONSTRAINT_INDEX && constraint_type != DB_CONSTRAINT_REVERSE_INDEX);
att_names = classobj_point_at_att_names (constraint, &count);
if (att_names == NULL)
{
assert (er_errid () != NO_ERROR);
return er_errid ();
}
auto_cons_name = sm_produce_constraint_name (like_class_name, constraint_type, att_names, constraint->asc_desc, NULL);
if (auto_cons_name == NULL)
{
assert (er_errid () != NO_ERROR);
error = er_errid ();
goto error_exit;
}
/* check if constraint's name was generated automatically */
if (strcmp (auto_cons_name, constraint->name) == 0)
{
/* regenerate name automatically for new class */
new_cons_name =
sm_produce_constraint_name_tmpl (ctemplate, constraint_type, att_names, constraint->asc_desc, NULL);
if (new_cons_name == NULL)
{
assert (er_errid () != NO_ERROR);
error = er_errid ();
goto error_exit;
}
}
else
{
/* use name given by user */
new_cons_name = (char *) constraint->name;
}
if (auto_cons_name != NULL)
{
free_and_init (auto_cons_name);
}
if (constraint_type != DB_CONSTRAINT_FOREIGN_KEY)
{
error = smt_add_constraint (ctemplate, constraint_type, new_cons_name, att_names,
(constraint_type == DB_CONSTRAINT_UNIQUE) ? constraint->asc_desc : NULL, NULL, 0,
NULL, constraint->filter_predicate, constraint->func_index_info, constraint->comment,
constraint->index_status);
}
else
{
MOP ref_clsop;
SM_CLASS *ref_cls;
SM_CLASS_CONSTRAINT *c;
assert (constraint->fk_info != NULL);
ref_clsop = ws_mop (&(constraint->fk_info->ref_class_oid), NULL);
if (ref_clsop == NULL)
{
assert (er_errid () != NO_ERROR);
error = er_errid ();
goto error_exit;
}
error = au_fetch_class_force (ref_clsop, &ref_cls, AU_FETCH_READ);
if (error != NO_ERROR)
{
goto error_exit;
}
assert (ref_cls->constraints != NULL);
c = classobj_find_cons_primary_key (ref_cls->constraints);
if (c != NULL)
{
ref_attrs = classobj_point_at_att_names (c, &count_ref);
if (ref_attrs == NULL)
{
goto error_exit;
}
assert (((count > 1
&& IS_DEDUPLICATE_KEY_ATTR_NAME (att_names[count - 1])) ? (count - 1) : count) == count_ref);
}
else
{
assert (false);
error = ER_FK_REF_CLASS_HAS_NOT_PK;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 1, sm_ch_name ((MOBJ) ref_cls));
goto error_exit;
}
error =
dbt_add_foreign_key (ctemplate, new_cons_name, att_names, sm_ch_name ((MOBJ) ref_cls), ref_attrs,
constraint->fk_info->delete_action, constraint->fk_info->update_action,
constraint->comment);
free_and_init (ref_attrs);
}
free_and_init (att_names);
if (new_cons_name != NULL && new_cons_name != constraint->name)
{
free_and_init (new_cons_name);
}
return error;
error_exit:
if (att_names != NULL)
{
free_and_init (att_names);
}
if (ref_attrs != NULL)
{
free_and_init (ref_attrs);
}
if (new_cons_name != NULL && new_cons_name != constraint->name)
{
free_and_init (new_cons_name);
}
return error;
}
#if defined(ENABLE_UNUSED_FUNCTION)
/*
* classobj_add_template_reference() - The template keeps a list of all MOPS that
* are placed inside the template in an external objlist format so they will
* serve as roots to the garbage collector. This prevents any MOPs in the
* template from being reclaimed. See the discussion under
* Template_area above for more information.
* return: NO_ERROR on success, non-zero for ERROR
* template(in/out): class editing template
* obj(in): MOP to register
*/
int
classobj_add_template_reference (SM_TEMPLATE * template_ptr, MOP obj)
{
return ml_ext_add (&template_ptr->ext_references, obj, NULL);
}
#endif /* ENABLE_UNUSED_FUNCTION */
/* SM_CLASS */
/*
* classobj_make_class() - Creates a new class structure.
* return: new class structure
* name(in): class name
*/
SM_CLASS *
classobj_make_class (const char *name)
{
SM_CLASS *class_;
class_ = (SM_CLASS *) db_ws_alloc (sizeof (SM_CLASS));
if (class_ == NULL)
{
return NULL;
}
class_->class_type = SM_CLASS_CT;
class_->header.ch_obj_header.chn = NULL_CHN; /* start with NULL chn ? */
class_->header.ch_type = SM_META_CLASS;
class_->header.ch_name = NULL;
/* shouldn't know how to initialize these, either need external init function */
OID_SET_NULL (&(class_->header.ch_rep_dir));
HFID_SET_NULL (&(class_->header.ch_heap));
class_->header.ch_heap.vfid.volid = boot_User_volid;
class_->repid = 0; /* initial rep is zero */
class_->users = NULL;
class_->representations = NULL;
class_->inheritance = NULL;
class_->object_size = 0;
class_->att_count = 0;
class_->attributes = NULL;
class_->shared_count = 0;
class_->shared = NULL;
class_->class_attribute_count = 0;
class_->class_attributes = NULL;
class_->ordered_attributes = NULL;
class_->method_count = 0;
class_->methods = NULL;
class_->class_method_count = 0;
class_->class_methods = NULL;
class_->method_files = NULL;
class_->query_spec = NULL;
class_->loader_commands = NULL;
class_->resolutions = NULL;
class_->partition = NULL;
class_->fixed_count = 0;
class_->variable_count = 0;
class_->fixed_size = 0;
class_->methods_loaded = 0;
class_->post_load_cleanup = 0;
class_->triggers_validated = 0;
class_->has_active_triggers = 0;
class_->dont_decache_constraints_or_flush = 0;
class_->recache_constraints = 0;
class_->load_index_from_heap = 1;
class_->att_ids = 0;
class_->method_ids = 0;
class_->new_ = NULL;
class_->stats = NULL;
class_->owner = NULL;
class_->collation_id = LANG_SYS_COLLATION;
class_->auth_cache = NULL;
class_->flags = 0;
class_->properties = NULL;
class_->virtual_cache_local_schema_id = 0;
class_->virtual_cache_global_schema_id = 0;
class_->virtual_cache_snapshot_version = 0;
class_->virtual_query_cache = NULL;
class_->triggers = NULL;
class_->constraints = NULL;
class_->comment = NULL;
class_->tde_algorithm = (int) TDE_ALGORITHM_NONE;
if (name != NULL)
{
class_->header.ch_name = ws_copy_string (name);
if (class_->header.ch_name == NULL)
{
db_ws_free (class_);
class_ = NULL;
}
}
return (class_);
}
/*
* classobj_free_class() - Frees a class and any associated memory.
* return: none
* class(in): class structure
*/
void
classobj_free_class (SM_CLASS * class_)
{
if (class_ == NULL)
{
return;
}
ws_free_string_and_init (class_->header.ch_name);
ws_free_string_and_init (class_->loader_commands);
ws_free_string_and_init (class_->comment);
ml_free_and_init (class_->users);
ml_free_and_init (class_->inheritance);
ws_list_free_and_init (class_->representations, classobj_free_representation);
ws_list_free_and_init (class_->method_files, classobj_free_method_file);
ws_list_free_and_init (class_->query_spec, classobj_free_query_spec);
ws_list_free_and_init (class_->resolutions, classobj_free_resolution);
ws_list_free_and_init (class_->partition, classobj_free_partition_info);
classobj_free_threaded_array_and_init (class_->attributes, classobj_clear_attribute);
classobj_free_threaded_array_and_init (class_->shared, classobj_clear_attribute);
classobj_free_threaded_array_and_init (class_->class_attributes, classobj_clear_attribute);
classobj_free_threaded_array_and_init (class_->methods, classobj_clear_method);
classobj_free_threaded_array_and_init (class_->class_methods, classobj_clear_method);
/* this shouldn't happen here ? - make sure we can't GC this away in the middle of an edit. */
#if 0
if (class_->new_ != NULL)
{
classobj_free_template (class_->new_);
}
#endif /* 0 */
if (class_->stats != NULL)
{
stats_free_statistics_and_init (class_->stats);
}
if (class_->properties != NULL)
{
classobj_free_prop_and_init (class_->properties);
}
if (class_->virtual_query_cache != NULL)
{
mq_free_virtual_query_cache_and_init (class_->virtual_query_cache);
}
if (class_->triggers != NULL)
{
tr_free_schema_cache_and_init (class_->triggers);
}
if (class_->auth_cache != NULL)
{
au_free_authorization_cache_and_init (class_->auth_cache);
}
if (class_->constraints != NULL)
{
classobj_free_class_constraints_and_init (class_->constraints);
}
db_ws_free_and_init (class_);
}
/*
* classobj_class_size() - Calculates the amount of memory used by a class structure.
* return: byte size of class
* class(in): class structure
*/
int
classobj_class_size (SM_CLASS * class_)
{
SM_ATTRIBUTE *att;
SM_METHOD *meth;
int size;
size = sizeof (SM_CLASS);
size += strlen (sm_ch_name ((MOBJ) class_)) + 1;
size += ws_list_total ((DB_LIST *) class_->representations, (LTOTALER) classobj_representation_size);
size += ml_size (class_->users);
size += ml_size (class_->inheritance);
size += ws_list_total ((DB_LIST *) class_->resolutions, (LTOTALER) classobj_resolution_size);
size += ws_list_total ((DB_LIST *) class_->method_files, (LTOTALER) classobj_method_file_size);
size += ws_list_total ((DB_LIST *) class_->query_spec, (LTOTALER) classobj_query_spec_size);
size += ws_list_total ((DB_LIST *) class_->partition, (LTOTALER) classobj_partition_info_size);
if (class_->loader_commands != NULL)
{
size += strlen (class_->loader_commands) + 1;
}
if (class_->comment != NULL)
{
size += strlen (class_->comment) + 1;
}
for (att = class_->attributes; att != NULL; att = (SM_ATTRIBUTE *) att->header.next)
{
size += classobj_attribute_size (att);
}
for (att = class_->shared; att != NULL; att = (SM_ATTRIBUTE *) att->header.next)
{
size += classobj_attribute_size (att);
}
for (att = class_->class_attributes; att != NULL; att = (SM_ATTRIBUTE *) att->header.next)
{
size += classobj_attribute_size (att);
}
for (meth = class_->methods; meth != NULL; meth = (SM_METHOD *) meth->header.next)
{
size += classobj_method_size (meth);
}
for (meth = class_->class_methods; meth != NULL; meth = (SM_METHOD *) meth->header.next)
{
size += classobj_method_size (meth);
}
/* should have trigger cache here */
/* should have constraint cache here */
return (size);
}
/*
* classobj_insert_ordered_attribute() - Inserts an attribute in a list ordered by
* the "order" field in the attribute.
* Work function for classobj_fixup_loaded_class.
* return: none
* attlist(in/out): pointer to attribute list root
* att(in): attribute to insert
*/
static void
classobj_insert_ordered_attribute (SM_ATTRIBUTE ** attlist, SM_ATTRIBUTE * att)
{
SM_ATTRIBUTE *a, *prev;
prev = NULL;
for (a = *attlist; a != NULL && a->order < att->order; a = a->order_link)
{
prev = a;
}
att->order_link = a;
if (prev == NULL)
{
*attlist = att;
}
else
{
prev->order_link = att;
}
}
/*
* classobj_fixup_loaded_class() - Orders the instance and shared attributes of
* a class in a single list according to the order in which the attributes
* were defined. This list is not stored with the disk representation of
* a class, it is created in memory when the class is loaded.
* The actual attribute lists are kept separate in storage order.
* The transformer can call this for a newly loaded class or the
* schema manager can call this after a class has been edited to
* create the ordered list prior to returning control to the user.
* This now also goes through and assigns storage_order because this
* isn't currently stored as part of the disk representation.
* return: none
* class(in/out): class to order
*/
void
classobj_fixup_loaded_class (SM_CLASS * class_)
{
SM_ATTRIBUTE *att;
SM_METHOD *meth;
int i, offset, fixed_count;
class_->ordered_attributes = NULL;
/* Calculate the number of fixed width attributes, Isn't this already set in the fixed_count field ? */
fixed_count = 0;
for (att = class_->attributes; att != NULL; att = (SM_ATTRIBUTE *) att->header.next)
{
if (!att->domain->type->variable_p)
{
fixed_count++;
}
}
/* calculate the instance memory offset to the first attribute */
offset = sizeof (WS_OBJECT_HEADER);
/* if we have at least one fixed width attribute, then we'll also need a bound bit array. */
if (fixed_count)
{
offset += OBJ_BOUND_BIT_BYTES (fixed_count);
}
/* Make sure the first attribute is brought up to a longword alignment. */
offset = DB_ATT_ALIGN (offset);
/* set storage order index and calculate memory offsets */
for (i = 0, att = class_->attributes; att != NULL; i++, att = (SM_ATTRIBUTE *) att->header.next)
{
att->storage_order = i;
/* when we get to the end of the fixed attributes, bring the alignment up to a word boundary. */
if (i == fixed_count)
{
offset = DB_ATT_ALIGN (offset);
}
att->offset = offset;
offset += tp_domain_memory_size (att->domain);
classobj_insert_ordered_attribute (&class_->ordered_attributes, att);
}
offset = DB_ATT_ALIGN (offset);
class_->object_size = offset;
for (i = 0, att = class_->shared; att != NULL; i++, att = (SM_ATTRIBUTE *) att->header.next)
{
classobj_insert_ordered_attribute (&class_->ordered_attributes, att);
}
/* the list is ordered, since during flattening there may have been "holes" in the order numbers due to conflicts in
* multiple inheritance, whip through the list and re-number things */
for (att = class_->ordered_attributes, i = 0; att != NULL; att = att->order_link, i++)
{
att->order = i;
}
/* for consistency, make sure the other lists are ordered according to definition as well */
for (att = class_->class_attributes, i = 0; att != NULL; att = (SM_ATTRIBUTE *) att->header.next, i++)
{
att->order = i;
}
for (meth = class_->methods, i = 0; meth != NULL; meth = (SM_METHOD *) meth->header.next, i++)
{
meth->order = i;
}
for (meth = class_->class_methods, i = 0; meth != NULL; meth = (SM_METHOD *) meth->header.next, i++)
{
meth->order = i;
}
if (!class_->dont_decache_constraints_or_flush)
{
/* Cache constraints into both the class constraint list & the attribute constraint lists. */
(void) classobj_cache_class_constraints (class_);
(void) classobj_cache_constraints (class_);
}
else
{
class_->recache_constraints = 1;
}
}
/*
* classobj_capture_representation() - Builds a representation structure for
* the current state of a class.
* return: new representation structure
* class(in): class structure
*/
static SM_REPRESENTATION *
classobj_capture_representation (SM_CLASS * class_)
{
SM_REPRESENTATION *rep;
SM_REPR_ATTRIBUTE *rat, *last;
SM_ATTRIBUTE *att;
rep = classobj_make_representation ();
if (rep == NULL)
{
return NULL;
}
rep->id = class_->repid;
rep->fixed_count = class_->fixed_count;
rep->variable_count = class_->variable_count;
rep->next = class_->representations;
rep->attributes = NULL;
last = NULL;
for (att = class_->attributes; att != NULL; att = (SM_ATTRIBUTE *) att->header.next)
{
rat = classobj_make_repattribute (att->id, TP_DOMAIN_TYPE (att->domain), att->domain);
if (rat == NULL)
{
goto memory_error;
}
if (last == NULL)
{
rep->attributes = rat;
}
else
{
last->next = rat;
}
last = rat;
}
return (rep);
memory_error:
if (rep != NULL)
{
classobj_free_representation (rep);
}
return NULL;
}
/*
* classobj_sort_attlist * classobj_sort_methlist() - Work function for classobj_install_template
* Destructively modifies a list so that it is ordered according
* to the "order" field.
* Rather than have two versions of this for attributes and methods,
* can we make this part of the component header ?
* return: none
* source(in/out): list to sort
*/
static void
classobj_sort_attlist (SM_ATTRIBUTE ** source)
{
SM_ATTRIBUTE *sorted, *next, *prev, *ins, *att;
sorted = NULL;
for (att = *source, next = NULL; att != NULL; att = next)
{
next = (SM_ATTRIBUTE *) att->header.next;
prev = NULL;
for (ins = sorted; ins != NULL && ins->order < att->order; ins = (SM_ATTRIBUTE *) ins->header.next)
{
prev = ins;
}
att->header.next = (SM_COMPONENT *) ins;
if (prev == NULL)
{
sorted = att;
}
else
{
prev->header.next = (SM_COMPONENT *) att;
}
}
*source = sorted;
}
/*
* classobj_sort_methlist()
* return: none
* source(in/out): list to sort
*/
static void
classobj_sort_methlist (SM_METHOD ** source)
{
SM_METHOD *sorted, *next, *prev, *ins, *method;
sorted = NULL;
for (method = *source, next = NULL; method != NULL; method = next)
{
next = (SM_METHOD *) method->header.next;
prev = NULL;
for (ins = sorted; ins != NULL && ins->order < method->order; ins = (SM_METHOD *) ins->header.next)
{
prev = ins;
}
method->header.next = (SM_COMPONENT *) ins;
if (prev == NULL)
{
sorted = method;
}
else
{
prev->header.next = (SM_COMPONENT *) method;
}
}
*source = sorted;
}
/*
* classobj_install_template() - This is called after a template has been flattened
* and validated to install the new definitions in the class. If the newrep
* argument is non zero, a representation will be saved from the current
* class contents before installing the template.
* NOTE: It is extremely important that as fields in the class structure
* are being replaced, that the field be set to NULL.
* This is particularly important for the attribute lists.
* The reason is that garbage collection can happen during the template
* installation and the attribute lists that are freed must not be
* scanned by the gc class scanner.
* It is critical that errors be handled here without damaging the
* class structure. Perform all allocations before the class is touched
* so we can make sure that if we return an error, the class is untouched.
* return: NO_ERROR on success, non-zero for ERROR
* class(in/out): class structure
* flat(in/out): flattened template
* saverep(in): flag indicating new representation
*/
int
classobj_install_template (SM_CLASS * class_, SM_TEMPLATE * flat, int saverep)
{
SM_ATTRIBUTE *att, *atts, *shared_atts, *class_atts;
SM_METHOD *meth, *methods, *class_methods;
SM_REPRESENTATION *oldrep;
int fixed_size, fixed_count, variable_count;
int att_count, shared_count, class_attribute_count;
int method_count, class_method_count;
int i;
/* shapshot the representation if necessary */
oldrep = NULL;
if (saverep)
{
oldrep = classobj_capture_representation (class_);
if (oldrep == NULL)
{
goto memory_error;
}
}
atts = NULL;
shared_atts = NULL;
class_atts = NULL;
methods = NULL;
class_methods = NULL;
fixed_count = 0;
variable_count = 0;
fixed_size = 0;
att_count = ws_list_length ((DB_LIST *) flat->instance_attributes);
if (att_count)
{
atts = (SM_ATTRIBUTE *) classobj_alloc_threaded_array (sizeof (SM_ATTRIBUTE), att_count);
if (atts == NULL)
{
goto memory_error;
}
/* in order to properly calculate the memory offset, we must make an initial pass and count the number of fixed
* width attributes */
for (att = flat->instance_attributes; att != NULL; att = (SM_ATTRIBUTE *) att->header.next)
{
if (!att->domain->type->variable_p)
{
fixed_count++;
}
else
{
variable_count++;
}
}
/* calculate the disk size of the fixed width attribute block */
for (att = flat->instance_attributes, i = 0; att != NULL; att = (SM_ATTRIBUTE *) att->header.next, i++)
{
if (classobj_init_attribute (att, &atts[i], 0))
{
goto memory_error;
}
/* disk information */
if (!att->domain->type->variable_p)
{
fixed_size += tp_domain_disk_size (att->domain);
}
}
/* bring the size of the fixed block up to a word boundary */
fixed_size = DB_ATT_ALIGN (fixed_size);
}
/* SHARED ATTRIBUTES */
shared_count = ws_list_length ((DB_LIST *) flat->shared_attributes);
if (shared_count)
{
shared_atts = (SM_ATTRIBUTE *) classobj_alloc_threaded_array (sizeof (SM_ATTRIBUTE), shared_count);
if (shared_atts == NULL)
{
goto memory_error;
}
classobj_sort_attlist (&flat->shared_attributes);
for (att = flat->shared_attributes, i = 0; att != NULL; att = (SM_ATTRIBUTE *) att->header.next, i++)
{
if (classobj_init_attribute (att, &shared_atts[i], 0))
{
goto memory_error;
}
}
}
/* CLASS ATTRIBUTES */
class_attribute_count = ws_list_length ((DB_LIST *) flat->class_attributes);
if (class_attribute_count)
{
class_atts = (SM_ATTRIBUTE *) classobj_alloc_threaded_array (sizeof (SM_ATTRIBUTE), class_attribute_count);
if (class_atts == NULL)
{
goto memory_error;
}
classobj_sort_attlist (&flat->class_attributes);
for (att = flat->class_attributes, i = 0; att != NULL; att = (SM_ATTRIBUTE *) att->header.next, i++)
{
if (classobj_init_attribute (att, &class_atts[i], 0))
{
goto memory_error;
}
}
}
/* METHODS */
method_count = ws_list_length ((DB_LIST *) flat->methods);
if (method_count)
{
methods = (SM_METHOD *) classobj_alloc_threaded_array (sizeof (SM_METHOD), method_count);
if (methods == NULL)
{
goto memory_error;
}
classobj_sort_methlist (&flat->methods);
for (i = 0, meth = flat->methods; meth != NULL; meth = (SM_METHOD *) meth->header.next, i++)
{
if (classobj_init_method (meth, &methods[i], 0))
{
goto memory_error;
}
}
}
/* CLASS METHODS */
class_method_count = ws_list_length ((DB_LIST *) flat->class_methods);
if (class_method_count)
{
class_methods = (SM_METHOD *) classobj_alloc_threaded_array (sizeof (SM_METHOD), class_method_count);
if (class_methods == NULL)
{
goto memory_error;
}
classobj_sort_methlist (&flat->class_methods);
for (i = 0, meth = flat->class_methods; meth != NULL; meth = (SM_METHOD *) meth->header.next, i++)
{
if (classobj_init_method (meth, &class_methods[i], 0))
{
goto memory_error;
}
}
}
/* NO ERRORS ARE ALLOWED AFTER THIS POINT ! Modify the class structure to contain the new information. */
class_->class_type = flat->class_type;
class_->att_count = att_count;
class_->shared_count = shared_count;
class_->class_attribute_count = class_attribute_count;
class_->method_count = method_count;
class_->class_method_count = class_method_count;
class_->fixed_count = fixed_count;
class_->variable_count = variable_count;
class_->fixed_size = fixed_size;
/* install attribute/method lists */
classobj_free_threaded_array ((DB_LIST *) class_->attributes, (LFREEER) classobj_clear_attribute);
class_->attributes = atts;
classobj_free_threaded_array ((DB_LIST *) class_->shared, (LFREEER) classobj_clear_attribute);
class_->shared = shared_atts;
classobj_free_threaded_array ((DB_LIST *) class_->class_attributes, (LFREEER) classobj_clear_attribute);
class_->class_attributes = class_atts;
classobj_free_threaded_array ((DB_LIST *) class_->methods, (LFREEER) classobj_clear_method);
class_->methods = methods;
classobj_free_threaded_array ((DB_LIST *) class_->class_methods, (LFREEER) classobj_clear_method);
class_->class_methods = class_methods;
/* build the definition order list from the instance/shared attribute list */
classobj_fixup_loaded_class (class_);
/* save the old representation */
if (oldrep != NULL)
{
oldrep->next = class_->representations;
class_->representations = oldrep;
class_->repid = class_->repid + 1;
}
/* install super class list, subclass list stays the same */
ml_free (class_->inheritance);
class_->inheritance = flat->inheritance;
flat->inheritance = NULL;
/* install loader commands */
ws_free_string (class_->loader_commands);
class_->loader_commands = flat->loader_commands;
flat->loader_commands = NULL;
/* install method files */
ws_list_free ((DB_LIST *) class_->method_files, (LFREEER) classobj_free_method_file);
class_->method_files = flat->method_files;
flat->method_files = NULL;
/* install the query spec */
ws_list_free ((DB_LIST *) class_->query_spec, (LFREEER) classobj_free_query_spec);
class_->query_spec = flat->query_spec;
flat->query_spec = NULL;
/* install the property list */
classobj_free_prop (class_->properties);
class_->properties = flat->properties;
flat->properties = NULL;
/* install resolution list, merge the res lists in the class for simplicity */
ws_list_free ((DB_LIST *) class_->resolutions, (LFREEER) classobj_free_resolution);
class_->resolutions = (SM_RESOLUTION *) WS_LIST_NCONC (flat->resolutions, flat->class_resolutions);
flat->resolutions = NULL;
flat->class_resolutions = NULL;
/* install trigger cache */
if (class_->triggers != NULL)
{
tr_free_schema_cache (class_->triggers);
}
class_->triggers = (tr_schema_cache *) flat->triggers;
flat->triggers = NULL;
ws_list_free ((DB_LIST *) class_->partition, (LFREEER) classobj_free_partition_info);
class_->partition = flat->partition;
flat->partition = NULL;
if (!class_->dont_decache_constraints_or_flush)
{
/* Cache constraints into both the class constraint list & the attribute constraint lists. */
if (classobj_cache_class_constraints (class_))
{
goto memory_error;
}
if (!classobj_cache_constraints (class_))
{
goto memory_error;
}
}
else
{
class_->recache_constraints = 1;
}
return NO_ERROR;
memory_error:
/* This is serious, the caller probably should be prepared to abort the current transaction. The class state has
* been preserved but a nested schema update may now be in an inconsistent state. */
assert (er_errid () != NO_ERROR);
return er_errid ();
}
/*
* classobj_find_representation() - This searches a class for a representation
* structure with a particular id. Called by the object transformer when
* obsolete objects are encountered.
* return: representation
* class(in): class structure
* id(in): representation id
*/
SM_REPRESENTATION *
classobj_find_representation (SM_CLASS * class_, int id)
{
SM_REPRESENTATION *rep, *found;
for (rep = class_->representations, found = NULL; rep != NULL && found == NULL; rep = rep->next)
{
if (rep->id == id)
{
found = rep;
}
}
return (found);
}
/*
* classobj_filter_components() - Extracts components from a list with a
* certain name_space and returns a list of the extracted components.
* The source list is destructively modified.
* return: extracted components
* complist(in/out): component list to filter
* namespace(in): name_space of elements to remove
*/
SM_COMPONENT *
classobj_filter_components (SM_COMPONENT ** complist, SM_NAME_SPACE name_space)
{
SM_COMPONENT *filtered, *comp, *next, *prev;
filtered = NULL;
prev = NULL;
for (comp = *complist, next = NULL; comp != NULL; comp = next)
{
next = comp->next;
if (comp->name_space != name_space)
{
prev = comp;
}
else
{
if (prev == NULL)
{
*complist = next;
}
else
{
prev->next = next;
}
comp->next = filtered;
filtered = comp;
}
}
return (filtered);
}
#if defined (CUBRID_DEBUG)
/*
* classobj_print () - This debug function is used for printing out things
* that aren't displayed by the help_ level utility functions.
* return: none
* class(in): class structure
*/
void
classobj_print (SM_CLASS * class_)
{
SM_ATTRIBUTE *att;
SM_METHOD *meth;
if (class_ == NULL)
{
return;
}
file_print_output output_ctx (stdout);
output_ctx ("Class : %s\n", sm_ch_name ((MOBJ) class_));
if (class_->properties != NULL)
{
output_ctx (" Properties : ");
classobj_print_props (class_->properties);
}
if (class_->ordered_attributes != NULL)
{
output_ctx ("Attributes\n");
for (att = class_->ordered_attributes; att != NULL; att = att->order_link)
{
output_ctx (" Name=%-25s, id=%3d", att->header.name, att->id);
if (att->domain != NULL && att->domain->type != NULL)
{
output_ctx (", pr_type=%-10s", att->domain->type->name);
}
output_ctx ("\n");
output_ctx (" mem_offset=%3d, order=%3d, storage_order=%3d\n", att->offset, att->order,
att->storage_order);
if (att->properties != NULL)
{
output_ctx (" Properties : ");
classobj_print_props (att->properties);
}
if (att->comment != NULL)
{
output_ctx (" ");
help_print_describe_comment (output_ctx, att->comment);
}
output_ctx ("\n");
}
}
if (class_->class_attributes != NULL)
{
output_ctx ("Class Attributes\n");
for (att = class_->class_attributes; att != NULL; att = att->order_link)
{
output_ctx (" Name=%-25s, id=%3d", att->header.name, att->id);
if (att->domain != NULL && att->domain->type != NULL)
{
output_ctx (", pr_type=%-10s", att->domain->type->name);
}
output_ctx ("\n");
output_ctx (" mem_offset=%3d, order=%3d, storage_order=%3d\n", att->offset, att->order,
att->storage_order);
if (att->properties != NULL)
{
output_ctx (" Properties : ");
classobj_print_props (att->properties);
}
if (att->comment != NULL)
{
output_ctx (" ");
help_print_describe_comment (output_ctx, att->comment);
}
output_ctx ("\n");
}
}
if (class_->methods != NULL)
{
output_ctx ("Methods\n");
for (meth = class_->methods; meth != NULL; meth = (SM_METHOD *) meth->header.next)
{
output_ctx (" %s\n", meth->header.name);
if (meth->properties != NULL)
{
output_ctx (" Properties : ");
classobj_print_props (meth->properties);
}
}
}
if (class_->class_methods != NULL)
{
output_ctx ("Class Methods\n");
for (meth = class_->methods; meth != NULL; meth = (SM_METHOD *) meth->header.next)
{
output_ctx (" %s\n", meth->header.name);
if (meth->properties != NULL)
{
output_ctx (" Properties : ");
classobj_print_props (meth->properties);
}
}
}
}
#endif
/* MISC UTILITIES */
/*
* classobj_find_attribute() - Finds a named attribute within a class structure.
* return: attribute descriptor
* class(in): class structure
* name(in): attribute name
* class_attribute(in): non-zero if this is a class attribute
*/
SM_ATTRIBUTE *
classobj_find_attribute (SM_CLASS * class_, const char *name, int class_attribute)
{
SM_ATTRIBUTE *att;
if (class_attribute)
{
for (att = class_->class_attributes; att != NULL; att = (SM_ATTRIBUTE *) att->header.next)
{
if (intl_identifier_casecmp (att->header.name, name) == 0)
{
return (att);
}
}
}
else
{
for (att = class_->attributes; att != NULL; att = (SM_ATTRIBUTE *) att->header.next)
{
if (intl_identifier_casecmp (att->header.name, name) == 0)
{
return (att);
}
}
for (att = class_->shared; att != NULL; att = (SM_ATTRIBUTE *) att->header.next)
{
if (intl_identifier_casecmp (att->header.name, name) == 0)
{
return (att);
}
}
}
return (NULL);
}
/*
* classobj_find_attribute_id() - Finds an attribute within a class structure by id.
* return: attribute descriptor
* class(in): class structure
* id(in): attribute id
* class_attribute(in): non-zero if this is a class attribute
*/
SM_ATTRIBUTE *
classobj_find_attribute_id (SM_CLASS * class_, int id, int class_attribute)
{
SM_ATTRIBUTE *att;
if (class_attribute)
{
for (att = class_->class_attributes; att != NULL; att = (SM_ATTRIBUTE *) att->header.next)
{
if (att->id == id)
{
return (att);
}
}
}
else
{
for (att = class_->attributes; att != NULL; att = (SM_ATTRIBUTE *) att->header.next)
{
if (att->id == id)
{
return (att);
}
}
for (att = class_->shared; att != NULL; att = (SM_ATTRIBUTE *) att->header.next)
{
if (att->id == id)
{
return (att);
}
}
}
return (NULL);
}
/*
* classobj_find_method() - Finds a named method within a class structure.
* return: method structure
* class(in): class structure
* name(in): method name
* class_method(in): non-zero if this is a class method
*/
SM_METHOD *
classobj_find_method (SM_CLASS * class_, const char *name, int class_method)
{
SM_METHOD *meth;
if (class_method)
{
for (meth = class_->class_methods; meth != NULL; meth = (SM_METHOD *) meth->header.next)
{
if (intl_identifier_casecmp (meth->header.name, name) == 0)
{
return (meth);
}
}
}
else
{
for (meth = class_->methods; meth != NULL; meth = (SM_METHOD *) meth->header.next)
{
if (intl_identifier_casecmp (meth->header.name, name) == 0)
{
return (meth);
}
}
}
return (NULL);
}
/*
* classobj_find_component() - This locates either an attribute or method with
* the given name.
* return: component (NULL if not found)
* name(in): component name (attribute or method)
* class_component(in): non-zero if looking in the class name_space
*/
SM_COMPONENT *
classobj_find_component (SM_CLASS * class_, const char *name, int class_component)
{
SM_COMPONENT *comp;
if (class_component)
{
for (comp = (SM_COMPONENT *) class_->class_attributes; comp != NULL; comp = comp->next)
{
if (intl_identifier_casecmp (comp->name, name) == 0)
{
return (comp);
}
}
for (comp = (SM_COMPONENT *) class_->class_methods; comp != NULL; comp = comp->next)
{
if (intl_identifier_casecmp (comp->name, name) == 0)
{
return (comp);
}
}
}
else
{
for (comp = (SM_COMPONENT *) class_->attributes; comp != NULL; comp = comp->next)
{
if (intl_identifier_casecmp (comp->name, name) == 0)
{
return (comp);
}
}
for (comp = (SM_COMPONENT *) class_->shared; comp != NULL; comp = comp->next)
{
if (intl_identifier_casecmp (comp->name, name) == 0)
{
return (comp);
}
}
for (comp = (SM_COMPONENT *) class_->methods; comp != NULL; comp = comp->next)
{
if (intl_identifier_casecmp (comp->name, name) == 0)
{
return (comp);
}
}
}
return (NULL);
}
/*
* classobj_complist_search() - This is used to scan a list of components
* using the usual rules for name comparison.
* return: component pointer
* list(in): list to search
* name(in): name to look for
*/
SM_COMPONENT *
classobj_complist_search (SM_COMPONENT * list, const char *name)
{
SM_COMPONENT *comp;
for (comp = list; comp != NULL; comp = comp->next)
{
if (intl_identifier_casecmp (comp->name, name) == 0)
{
return (comp);
}
}
return (NULL);
}
/* DESCRIPTORS */
/*
* classobj_make_desclist() - Builds a descriptor list element and initializes
* all the fields.
* return: descriptor list element
* classobj(in): class MOP
* class(in): class structure
* comp(in): component pointer (attribute or method)
* write_access(in): non-zero if we already have write access
*/
SM_DESCRIPTOR_LIST *
classobj_make_desclist (MOP classobj, SM_CLASS * class_, SM_COMPONENT * comp, int write_access)
{
SM_DESCRIPTOR_LIST *dl;
dl = (SM_DESCRIPTOR_LIST *) malloc (sizeof (SM_DESCRIPTOR_LIST));
if (dl == NULL)
{
return NULL;
}
dl->next = NULL;
dl->classobj = classobj;
dl->class_ = class_;
dl->comp = comp;
dl->write_access = write_access;
return dl;
}
/*
* classobj_free_desclist() - Frees a descriptor list
* return: none
* dl(in): descriptor list element
*/
void
classobj_free_desclist (SM_DESCRIPTOR_LIST * dl)
{
SM_DESCRIPTOR_LIST *next;
for (next = NULL; dl != NULL; dl = next)
{
next = dl->next;
/* make sure to NULL potential GC roots */
dl->classobj = NULL;
free_and_init (dl);
}
}
/*
* classobj_free_descriptor() - Frees a descriptor including all the map list entries
* return: none
* desc(in): descriptor
*/
void
classobj_free_descriptor (SM_DESCRIPTOR * desc)
{
if (desc == NULL)
{
return;
}
classobj_free_desclist (desc->map);
if (desc->name != NULL)
{
free_and_init (desc->name);
}
if (desc->valid != NULL)
{
ml_ext_free (desc->valid->validated_classes);
free_and_init (desc->valid);
}
free_and_init (desc);
}
/*
* classobj_make_descriptor() - Builds a descriptor structure including an initial
* class map entry and initializes it with the supplied information.
* return: descriptor structure
* class_mop(in): class MOP
* classobj(in): class structure
* comp(in): component (attribute or method)
* write_access(in): non-zero if we already have write access on the class
*/
SM_DESCRIPTOR *
classobj_make_descriptor (MOP class_mop, SM_CLASS * classobj, SM_COMPONENT * comp, int write_access)
{
SM_DESCRIPTOR *desc;
SM_VALIDATION *valid;
desc = (SM_DESCRIPTOR *) malloc (sizeof (SM_DESCRIPTOR));
if (desc == NULL)
{
return NULL;
}
desc->next = NULL;
desc->map = NULL;
desc->class_mop = class_mop;
if (comp != NULL)
{
/* save the component name so we can rebuild the map cache after schema/transaction changes */
desc->name = (char *) malloc (strlen (comp->name) + 1);
if (desc->name == NULL)
{
free_and_init (desc);
return NULL;
}
strcpy (desc->name, comp->name);
desc->name_space = comp->name_space;
}
/* create the initial map entry if we have the information */
if (class_mop != NULL)
{
desc->map = classobj_make_desclist (class_mop, classobj, comp, write_access);
if (desc->map == NULL)
{
classobj_free_descriptor (desc);
desc = NULL;
}
}
/* go ahead and make a validation cache all the time */
valid = (SM_VALIDATION *) malloc (sizeof (SM_VALIDATION));
if (valid == NULL)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, sizeof (SM_VALIDATION));
classobj_free_descriptor (desc);
desc = NULL;
}
else
{
if (desc == NULL)
{
free_and_init (valid);
return desc;
}
else
{
desc->valid = valid;
}
valid->last_class = NULL;
valid->validated_classes = NULL;
valid->last_setdomain = NULL;
/* don't use DB_TYPE_NULL as the "uninitialized" value here as it can prevent NULL constraint checking from
* happening correctly. Should have a magic constant somewhere that could be used for this purpose. */
valid->last_type = DB_TYPE_ERROR;
valid->last_precision = 0;
valid->last_scale = 0;
}
return desc;
}
/*
* classobj_check_index_compatibility() - Check whether indexes are compatible.
* return: share, not share, create new index.
* constraint(in): the constraints list
* constraint_type(in): the new constraint type
* filter_predicate(in): the new expression from CREATE INDEX idx ON tbl(col1, ...) WHERE filter_predicate
* func_index_info (in): the new function index information
* existing_con(in): the existed relative constraint
* primary_con(out): the reference of existed primary key
*
* There are some rules about index compatibility.
* 1.There is only one primary key allowed in a table.
* 2 The Basic rules of index compatibility are defined in below table.
* share : share index with existed index;
* new idx: create new index;
* error : not share index and return error msg.
* 3. filter_predicate and func_index_info were checked in classobj_find_constraint_by_attrs().
* 4. The fact that existing_con is not NULL means that there are the same indexes,
* from the count and order of attributes, order direction, function index composition, and filter conditions.
* +---------------+-------------------------------------------------------+
* | | Existed constraint or index |
* | +----------+-----------+---------+----------+-----------+
* | | PK(asc) | PK(desc) | FK | Idx(asc) | Idx(desc) |
* | | /UK(asc) | /UK(desc) | | | /R-Idx |
* | | | /R-UK | | | |
* +---+-----------+----------+-----------+---------+----------+-----------+
* | | PK(asc) | share | new idx | error | error | new idx |
* | n | /UK(asc): | | | | | |
* | e +-----------+----------+-----------+---------+----------+-----------+
* | w | PK(desc) | | | | | |
* | | /UK(desc) | new idx | share | new idx | new idx | error |
* | i | /R-UK: | | | | | |
* | n +-----------+----------+-----------+---------+----------+-----------+
* | d | FK: | new idx | new idx | error | share | share |
* | e +-----------+----------+-----------+---------+----------+-----------+
* | x | idx(asc): | error | new idx | share | error | new idx |
* | +-----------+----------+-----------+---------+----------+-----------+
* | | idx(desc) | new idx | error | new idx | new idx | error |
* | | /R-idx: | | | | | |
* +---+-----------+----------+-----------+---------+----------+-----------+
*/
static SM_CONSTRAINT_COMPATIBILITY
classobj_check_index_compatibility (SM_CLASS_CONSTRAINT * constraints, const DB_CONSTRAINT_TYPE constraint_type,
const SM_CLASS_CONSTRAINT * existing_con, SM_CLASS_CONSTRAINT ** primary_con)
{
SM_CONSTRAINT_COMPATIBILITY ret;
/* only one primary key is allowed in a table. */
if (constraint_type == DB_CONSTRAINT_PRIMARY_KEY)
{
SM_CLASS_CONSTRAINT *prim_con;
prim_con = classobj_find_cons_primary_key (constraints);
if (prim_con != NULL)
{
*primary_con = prim_con;
return SM_NOT_SHARE_PRIMARY_KEY_AND_WARNING;
}
}
if (existing_con == NULL)
{
return SM_CREATE_NEW_INDEX;
}
switch (constraint_type)
{
case DB_CONSTRAINT_PRIMARY_KEY:
case DB_CONSTRAINT_UNIQUE:
case DB_CONSTRAINT_REVERSE_UNIQUE:
if (SM_IS_CONSTRAINT_UNIQUE_FAMILY (existing_con->type))
{
return SM_SHARE_INDEX;
}
break;
case DB_CONSTRAINT_FOREIGN_KEY:
if (SM_IS_CONSTRAINT_UNIQUE_FAMILY (existing_con->type))
{
return SM_CREATE_NEW_INDEX;
}
else if (existing_con->type == SM_CONSTRAINT_INDEX || existing_con->type == SM_CONSTRAINT_REVERSE_INDEX)
{
return SM_SHARE_INDEX;
}
break;
case DB_CONSTRAINT_INDEX:
case DB_CONSTRAINT_REVERSE_INDEX:
if (existing_con->type == SM_CONSTRAINT_FOREIGN_KEY)
{
return SM_SHARE_INDEX;
}
break;
default:
break;
}
return SM_NOT_SHARE_INDEX_AND_WARNING;
}
/*
* classobj_check_index_exist() - Check index is duplicated.
* return: NO_ERROR on success, non-zero for ERROR
* constraint(in): the constraints list
* out_shared_cons_name(out):
* constraint_type: constraint type
* constraint_name(in): Constraint name.
* att_names(in): array of attribute names
* asc_desc(in): asc/desc info list
* filter_index(in): expression from CREATE INDEX idx
* ON tbl(col1, ...) WHERE filter_predicate
* func_index_info (in): function index information
*/
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)
{
int error = NO_ERROR;
SM_CLASS_CONSTRAINT *existing_con, *prim_con = NULL;
SM_CONSTRAINT_COMPATIBILITY compat_state;
if (constraints == NULL)
{
return NO_ERROR;
}
/* check index name uniqueness */
existing_con = classobj_find_constraint_by_name (constraints, constraint_name);
if (existing_con)
{
ERROR2 (error, ER_SM_INDEX_EXISTS, class_name, existing_con->name);
return error;
}
existing_con =
classobj_find_constraint_by_attrs (constraints, constraint_type, att_names, asc_desc, filter_index,
func_index_info);
#if defined (ENABLE_UNUSED_FUNCTION) /* to disable TEXT */
if (existing_con != NULL)
{
if (existing_con->name && strstr (existing_con->name, TEXT_CONSTRAINT_PREFIX))
{
ERROR1 (error, ER_REGU_NOT_IMPLEMENTED, rel_major_release_string ());
return error;
}
}
#endif /* ENABLE_UNUSED_FUNCTION */
compat_state = classobj_check_index_compatibility (constraints, constraint_type, existing_con, &prim_con);
switch (compat_state)
{
case SM_CREATE_NEW_INDEX:
break;
case SM_SHARE_INDEX:
if (out_shared_cons_name != NULL)
{
if (constraint_type == DB_CONSTRAINT_FOREIGN_KEY)
{
int level;
SM_ATTRIBUTE **attp = existing_con->attributes;
const char **namep = att_names;
while (*attp)
{
if (IS_DEDUPLICATE_KEY_ATTR_NAME ((*attp)->header.name))
{
#ifndef NDEBUG
GET_DEDUPLICATE_KEY_ATTR_LEVEL_FROM_NAME (*namep, level);
assert (*namep == dk_get_deduplicate_key_attr_name (level));
#endif
GET_DEDUPLICATE_KEY_ATTR_LEVEL_FROM_NAME ((*attp)->header.name, level);
*namep = dk_get_deduplicate_key_attr_name (level);
break;
}
attp++;
namep++;
}
}
*out_shared_cons_name = strdup (existing_con->name);
}
break;
case SM_NOT_SHARE_INDEX_AND_WARNING:
ERROR2 (error, ER_SM_INDEX_EXISTS, class_name, existing_con->name);
break;
case SM_NOT_SHARE_PRIMARY_KEY_AND_WARNING:
assert (prim_con != NULL);
ERROR2 (error, ER_SM_PRIMARY_KEY_EXISTS, class_name, prim_con->name);
break;
default:
/* not suppose to here */
assert (false);
}
return error;
}
/*
* classobj_make_function_index_info() -
* return:
* func_seq(in):
*/
static SM_FUNCTION_INFO *
classobj_make_function_index_info (DB_SEQ * func_seq)
{
SM_FUNCTION_INFO *fi_info = NULL;
DB_VALUE val;
const char *buffer;
char *ptr;
int size;
if (func_seq == NULL)
{
return NULL;
}
fi_info = (SM_FUNCTION_INFO *) db_ws_alloc (sizeof (SM_FUNCTION_INFO));
if (fi_info == NULL)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, sizeof (SM_FUNCTION_INFO));
goto error;
}
memset (fi_info, 0, sizeof (SM_FUNCTION_INFO));
if (set_get_element_nocopy (func_seq, 0, &val) != NO_ERROR)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SM_INVALID_PROPERTY, 0);
goto error;
}
buffer = db_get_string (&val);
size = db_get_string_size (&val);
fi_info->expr_str = (char *) db_ws_alloc (size + 1);
if (fi_info->expr_str == NULL)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, (size_t) (size + 1));
goto error;
}
memset (fi_info->expr_str, 0, size + 1);
memcpy (fi_info->expr_str, buffer, size);
if (set_get_element_nocopy (func_seq, 1, &val) != NO_ERROR)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SM_INVALID_PROPERTY, 0);
goto error;
}
buffer = db_get_string (&val);
fi_info->expr_stream_size = db_get_string_size (&val);
fi_info->expr_stream = (char *) db_ws_alloc (fi_info->expr_stream_size);
if (fi_info->expr_stream == NULL)
{
goto error;
}
memcpy (fi_info->expr_stream, buffer, fi_info->expr_stream_size);
if (set_get_element_nocopy (func_seq, 2, &val) != NO_ERROR)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SM_INVALID_PROPERTY, 0);
goto error;
}
fi_info->col_id = db_get_int (&val);
if (set_get_element_nocopy (func_seq, 3, &val) != NO_ERROR)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SM_INVALID_PROPERTY, 0);
goto error;
}
fi_info->attr_index_start = db_get_int (&val);
if (set_get_element_nocopy (func_seq, 4, &val) != NO_ERROR)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SM_INVALID_PROPERTY, 0);
goto error;
}
buffer = db_get_string (&val);
// use const_cast since of a limitation of or_unpack_* functions which do not accept const
ptr = CONST_CAST (char *, buffer);
ptr = or_unpack_domain (ptr, &(fi_info->fi_domain), NULL);
return fi_info;
error:
if (fi_info)
{
if (fi_info->expr_str)
{
db_ws_free (fi_info->expr_str);
}
if (fi_info->expr_stream)
{
db_ws_free (fi_info->expr_stream);
}
db_ws_free (fi_info);
}
return NULL;
}
/*
* classobj_make_function_index_info_seq()
* return:
* func_index_info(in):
*/
static DB_SEQ *
classobj_make_function_index_info_seq (SM_FUNCTION_INFO * func_index_info)
{
DB_SEQ *fi_seq;
DB_VALUE val;
int fi_domain_size;
char *fi_domain_buf = NULL, *ptr = NULL;
if (func_index_info == NULL)
{
return NULL;
}
fi_domain_size = or_packed_domain_size (func_index_info->fi_domain, 0);
fi_domain_buf = (char *) malloc (fi_domain_size);
if (fi_domain_buf == NULL)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, (size_t) fi_domain_size);
return NULL;
}
ptr = fi_domain_buf;
ptr = or_pack_domain (ptr, func_index_info->fi_domain, 0, 0);
fi_seq = set_create_sequence (5);
db_make_string (&val, func_index_info->expr_str);
set_put_element (fi_seq, 0, &val);
db_make_char (&val, func_index_info->expr_stream_size, func_index_info->expr_stream,
func_index_info->expr_stream_size, LANG_SYS_CODESET, LANG_SYS_COLLATION);
set_put_element (fi_seq, 1, &val);
db_make_int (&val, func_index_info->col_id);
set_put_element (fi_seq, 2, &val);
db_make_int (&val, func_index_info->attr_index_start);
set_put_element (fi_seq, 3, &val);
db_make_char (&val, fi_domain_size, fi_domain_buf, fi_domain_size, LANG_SYS_CODESET, LANG_SYS_COLLATION);
set_put_element (fi_seq, 4, &val);
free_and_init (fi_domain_buf);
return fi_seq;
}
/*
* classobj_free_function_index_ref()
* return: none
* func_index_info(in):
*/
void
classobj_free_function_index_ref (SM_FUNCTION_INFO * func_index_info)
{
ws_free_string (func_index_info->expr_str);
ws_free_string (func_index_info->expr_stream);
tp_domain_free (func_index_info->fi_domain);
func_index_info->expr_str = NULL;
func_index_info->expr_stream = NULL;
}
/*
* classobj_check_function_constraint_info() - check function constraint info
* return: error code
* constraint_seq(in): constraint sequence
* has_function_constraint(in): true, if function constraint sequence
*/
static int
classobj_check_function_constraint_info (DB_SEQ * constraint_seq, bool * has_function_constraint)
{
DB_VALUE bvalue, fvalue, avalue;
int constraint_seq_len = set_size (constraint_seq);
int j = 0;
assert (constraint_seq != NULL && has_function_constraint != NULL);
/* initializations */
*has_function_constraint = false;
db_make_null (&bvalue);
db_make_null (&avalue);
db_make_null (&fvalue);
if (set_get_element
(constraint_seq, get_class_constraint_index (constraint_seq_len, SM_CONSTRAINT_OPTIONAL_INFO_INDEX),
&bvalue) != NO_ERROR)
{
goto structure_error;
}
if (DB_VALUE_TYPE (&bvalue) == DB_TYPE_SEQUENCE)
{
DB_SEQ *seq = db_get_set (&bvalue);
if (set_get_element (seq, 0, &fvalue) != NO_ERROR)
{
pr_clear_value (&bvalue);
goto structure_error;
}
if (DB_VALUE_TYPE (&fvalue) == DB_TYPE_INTEGER)
{
/* don't care about prefix length */
}
else if (DB_VALUE_TYPE (&fvalue) == DB_TYPE_SEQUENCE)
{
DB_SET *child_seq = db_get_set (&fvalue);
int seq_size = set_size (seq);
j = 0;
while (true)
{
if (set_get_element (child_seq, 0, &avalue) != NO_ERROR)
{
goto structure_error;
}
if (DB_IS_NULL (&avalue) || DB_VALUE_TYPE (&avalue) != DB_TYPE_STRING)
{
goto structure_error;
}
if (strcmp (db_get_string (&avalue), SM_FUNCTION_INDEX_ID) == 0)
{
*has_function_constraint = true;
pr_clear_value (&avalue);
break;
}
pr_clear_value (&avalue);
j++;
if (j >= seq_size)
{
break;
}
pr_clear_value (&fvalue);
if (set_get_element (seq, j, &fvalue) != NO_ERROR)
{
goto structure_error;
}
if (DB_VALUE_TYPE (&fvalue) != DB_TYPE_SEQUENCE)
{
goto structure_error;
}
child_seq = db_get_set (&fvalue);
}
}
else
{
goto structure_error;
}
pr_clear_value (&fvalue);
pr_clear_value (&bvalue);
}
else
{
goto structure_error;
}
return NO_ERROR;
structure_error:
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SM_INVALID_PROPERTY, 0);
/* clean up our values and return the error that has been set */
pr_clear_value (&fvalue);
pr_clear_value (&avalue);
pr_clear_value (&bvalue);
assert (er_errid () != NO_ERROR);
return er_errid ();
}
/* SM_PARTITION */
/*
* classobj_make_partition_info () - Allocate and initialize a sm_partition
* structure.
* return: new partition structure
*/
SM_PARTITION *
classobj_make_partition_info (void)
{
SM_PARTITION *partition_info;
partition_info = (SM_PARTITION *) db_ws_alloc (sizeof (SM_PARTITION));
if (partition_info == NULL)
{
return NULL;
}
partition_info->partition_type = -1;
partition_info->class_partition_type = DB_NOT_PARTITIONED_CLASS;
partition_info->values = NULL;
partition_info->pname = NULL;
partition_info->comment = NULL;
partition_info->expr = NULL;
partition_info->next = NULL;
return (partition_info);
}
/*
* classobj_free_partition_info () - free a sm_partition structure.
* return:
* partition_info (in):
*/
void
classobj_free_partition_info (SM_PARTITION * partition_info)
{
if (partition_info == NULL)
{
return;
}
if (partition_info->comment != NULL)
{
ws_free_string (partition_info->comment);
}
if (partition_info->pname != NULL)
{
ws_free_string (partition_info->pname);
}
if (partition_info->expr != NULL)
{
ws_free_string (partition_info->expr);
}
if (partition_info->values != NULL)
{
set_free (partition_info->values);
}
db_ws_free (partition_info);
}
/*
* classobj_copy_partition_info () - Copy a SM_PARTITION structure.
* return: new structure
* partition_info(in):
*/
SM_PARTITION *
classobj_copy_partition_info (SM_PARTITION * partition_info)
{
SM_PARTITION *new_partition_info;
new_partition_info = classobj_make_partition_info ();
if (new_partition_info == NULL)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, sizeof (SM_PARTITION));
goto error;
}
new_partition_info->partition_type = partition_info->partition_type;
new_partition_info->class_partition_type = partition_info->class_partition_type;
if (partition_info->comment != NULL)
{
new_partition_info->comment = ws_copy_string (partition_info->comment);
if (new_partition_info->comment == NULL)
{
goto error;
}
}
if (partition_info->expr != NULL)
{
new_partition_info->expr = ws_copy_string (partition_info->expr);
if (new_partition_info->expr == NULL)
{
goto error;
}
}
if (partition_info->pname != NULL)
{
new_partition_info->pname = ws_copy_string (partition_info->pname);
if (new_partition_info->pname == NULL)
{
goto error;
}
}
if (partition_info->values != NULL)
{
new_partition_info->values = db_seq_copy (partition_info->values);
if (new_partition_info->values == NULL)
{
goto error;
}
}
return new_partition_info;
error:
classobj_free_partition_info (new_partition_info);
return NULL;
}
/*
* classobj_copy_default_expr() - Copies default expression.
* return: error code
*
* dest(out): destination default expression
* src(in): source default expression
*/
int
classobj_copy_default_expr (DB_DEFAULT_EXPR * dest, const DB_DEFAULT_EXPR * src)
{
assert (dest != NULL && src != NULL);
dest->default_expr_type = src->default_expr_type;
dest->default_expr_op = src->default_expr_op;
if (src->default_expr_format)
{
dest->default_expr_format = ws_copy_string (src->default_expr_format);
if (dest->default_expr_format == NULL)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, strlen (src->default_expr_format));
return ER_OUT_OF_VIRTUAL_MEMORY;
}
}
else
{
dest->default_expr_format = NULL;
}
return NO_ERROR;
}
/*
* Note: For constraint structure details, see comment on SM_CLASS_CONSTRAINT in class_object.h.
*/
int
classobj_change_constraint_status (DB_SEQ * properties, SM_CLASS_CONSTRAINT * cons, SM_INDEX_STATUS index_status)
{
DB_VALUE prop_val, cnstr_val, curr_status, new_status, updated_time;
DB_SEQ *prop_seq, *idx_seq;
const char *property_type;
int found = 0;
int error = NO_ERROR;
int len = 0;
assert (properties != NULL && cons != NULL);
db_make_null (&prop_val);
db_make_null (&cnstr_val);
db_make_null (&curr_status);
db_make_null (&new_status);
db_make_null (&updated_time);
property_type = classobj_map_constraint_to_property (cons->type);
found = classobj_get_prop (properties, property_type, &prop_val);
if (found == 0)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SM_INVALID_PROPERTY, 0);
error = ER_SM_INVALID_PROPERTY;
goto end;
}
prop_seq = db_get_set (&prop_val);
found = classobj_get_prop (prop_seq, cons->name, &cnstr_val);
if (found == 0)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SM_INVALID_PROPERTY, 0);
error = ER_SM_INVALID_PROPERTY;
goto end;
}
idx_seq = db_get_set (&cnstr_val);
len = set_size (idx_seq);
set_get_element (idx_seq, get_class_constraint_index (len, SM_CONSTRAINT_STATUS_INDEX), &curr_status);
if (!DB_IS_NULL (&curr_status) && DB_VALUE_TYPE (&curr_status) != DB_TYPE_INTEGER)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SM_INVALID_PROPERTY, 0);
error = ER_SM_INVALID_PROPERTY;
goto end;
}
if (db_make_int (&new_status, index_status) != NO_ERROR ||
set_put_element (idx_seq, get_class_constraint_index (len, SM_CONSTRAINT_STATUS_INDEX), &new_status) != NO_ERROR)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SM_INVALID_PROPERTY, 0);
error = ER_SM_INVALID_PROPERTY;
goto end;
}
db_make_sequence (&cnstr_val, idx_seq);
found = classobj_put_prop (prop_seq, cons->name, &cnstr_val);
if (found == 0)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SM_INVALID_PROPERTY, 0);
error = ER_SM_INVALID_PROPERTY;
goto end;
}
db_make_sequence (&prop_val, prop_seq);
found = classobj_put_prop (properties, property_type, &prop_val);
if (found == 0)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SM_INVALID_PROPERTY, 0);
error = ER_SM_INVALID_PROPERTY;
goto end;
}
end:
pr_clear_value (&prop_val);
pr_clear_value (&cnstr_val);
pr_clear_value (&curr_status);
pr_clear_value (&new_status);
pr_clear_value (&updated_time);
return error;
}