File catalog_class.c¶
File List > cubrid > src > storage > catalog_class.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.
*
*/
/*
* catalog_class.c - catalog class
*/
#ident "$Id$"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "catalog_class.h"
#include "system_catalog.h"
#include "btree.h" // for single/multi ops
#include "deduplicate_key.h"
#include "error_manager.h"
#include "heap_file.h"
#include "transform.h"
#include "set_object.h"
#include "locator_sr.h"
#include "xserver_interface.h"
#include "object_primitive.h"
#include "object_representation.h"
#include "query_dump.h"
#include "tz_support.h"
#include "db_date.h"
#include "dbtype.h"
#include "string_opfunc.h"
#include "thread_manager.hpp"
#include "storage_common.h"
// XXX: SHOULD BE THE LAST INCLUDE HEADER
#include "memory_wrapper.hpp"
#define IS_SUBSET(value) (value).sub.count >= 0
#define EXCHANGE_OR_VALUE(a,b) \
do { \
OR_VALUE t; \
t = a; \
a = b; \
b = t; \
} while (0)
#define CATCLS_INDEX_NAME "i__db_class_unique_name"
#define CATCLS_OID_TABLE_SIZE 1024
/* SM_CLASSFLAG_SYSTEM is defined in a client-side header (class_object.h). Keep in sync with the shared definition. */
#define SM_CLASSFLAG_SYSTEM (1)
typedef struct or_value OR_VALUE;
typedef struct catcls_entry CATCLS_ENTRY;
typedef struct catcls_property CATCLS_PROPERTY;
typedef int (*CREADER) (THREAD_ENTRY * thread_p, OR_BUF * buf, OR_VALUE * value_p);
struct or_value
{
union or_id
{
OID classoid;
ATTR_ID attrid;
} id;
DB_VALUE value;
struct or_sub
{
struct or_value *value;
int count;
} sub;
};
struct catcls_entry
{
OID class_oid;
OID oid;
CATCLS_ENTRY *next;
};
struct catcls_property
{
const char *name;
DB_SEQ *seq;
int size;
int is_unique;
int is_reverse;
int is_primary_key;
int is_foreign_key;
};
bool catcls_Enable = false;
static BTID catcls_Btid;
static CATCLS_ENTRY *catcls_Free_entry_list = NULL;
static MHT_TABLE *catcls_Class_oid_to_oid_hash_table = NULL;
static int catcls_initialize_class_oid_to_oid_hash_table (THREAD_ENTRY * thread_p, int num_entry);
static int catcls_get_or_value_from_class (THREAD_ENTRY * thread_p, OR_BUF * buf_p, OR_VALUE * value_p);
static int catcls_get_or_value_from_attribute (THREAD_ENTRY * thread_p, OR_BUF * buf_p, OR_VALUE * value_p);
static int catcls_get_or_value_from_attrid (THREAD_ENTRY * thread_p, OR_BUF * buf_p, OR_VALUE * value_p);
static int catcls_get_or_value_from_domain (THREAD_ENTRY * thread_p, OR_BUF * buf_p, OR_VALUE * value_p);
static int catcls_get_or_value_from_method (THREAD_ENTRY * thread_p, OR_BUF * buf_p, OR_VALUE * value_p);
static int catcls_get_or_value_from_method_signiture (THREAD_ENTRY * thread_p, OR_BUF * buf_p, OR_VALUE * value_p);
static int catcls_get_or_value_from_method_argument (THREAD_ENTRY * thread_p, OR_BUF * buf_p, OR_VALUE * value_p);
static int catcls_get_or_value_from_method_file (THREAD_ENTRY * thread_p, OR_BUF * buf_p, OR_VALUE * value_p);
static int catcls_get_or_value_from_resolution (THREAD_ENTRY * thread_p, OR_BUF * buf_p, OR_VALUE * value_p);
static int catcls_get_or_value_from_query_spec (THREAD_ENTRY * thread_p, OR_BUF * buf_p, OR_VALUE * value_p);
static int catcls_get_or_value_from_indexes (DB_SEQ * seq, OR_VALUE * subset, int is_unique, int is_reverse,
int is_primary_key, int is_foreign_key);
static int catcls_get_subset (THREAD_ENTRY * thread_p, OR_BUF * buf_p, int expected_size, OR_VALUE * value_p,
CREADER reader);
static int catcls_get_object_set (THREAD_ENTRY * thread_p, OR_BUF * buf_p, int expected_size, OR_VALUE * value);
static int catcls_get_property_set (THREAD_ENTRY * thread_p, OR_BUF * buf_p, int expected_size, OR_VALUE * value_p);
static int catcls_reorder_attributes_by_repr (THREAD_ENTRY * thread_p, OR_VALUE * value_p);
static int catcls_expand_or_value_by_repr (OR_VALUE * value_p, OID * class_oid, DISK_REPR * rep);
static int catcls_expand_or_value_by_subset (THREAD_ENTRY * thread_p, OR_VALUE * value_p);
static int catcls_get_or_value_from_buffer (THREAD_ENTRY * thread_p, OR_BUF * buf_p, OR_VALUE * value_p,
DISK_REPR * rep);
static int catcls_put_or_value_into_buffer (OR_VALUE * value_p, int chn, OR_BUF * buf_p, OID * class_oid,
DISK_REPR * rep);
static OR_VALUE *catcls_get_or_value_from_class_record (THREAD_ENTRY * thread_p, RECDES * record);
static OR_VALUE *catcls_get_or_value_from_record (THREAD_ENTRY * thread_p, RECDES * record, OID * class_oid);
static int catcls_put_or_value_into_record (THREAD_ENTRY * thread_p, OR_VALUE * value_p, int chn, RECDES * record,
OID * class_oid);
static int catcls_insert_subset (THREAD_ENTRY * thread_p, OR_VALUE * value_p, OID * root_oid);
static int catcls_delete_subset (THREAD_ENTRY * thread_p, OR_VALUE * value_p);
static int catcls_update_subset (THREAD_ENTRY * thread_p, OR_VALUE * value_p, OR_VALUE * old_value, bool * uflag,
UPDATE_INPLACE_STYLE force_in_place);
static int catcls_insert_instance (THREAD_ENTRY * thread_p, OR_VALUE * value_p, OID * oid, OID * root_oid,
OID * class_oid, HFID * hfid, HEAP_SCANCACHE * scan);
static int catcls_delete_instance (THREAD_ENTRY * thread_p, OID * oid, OID * class_oid, HFID * hfid,
HEAP_SCANCACHE * scan);
static int catcls_update_instance (THREAD_ENTRY * thread_p, OR_VALUE * value_p, OID * oid, OID * class_oid, HFID * hfid,
HEAP_SCANCACHE * scan, UPDATE_INPLACE_STYLE force_in_place);
static CATCLS_ENTRY *catcls_allocate_entry (THREAD_ENTRY * thread_p);
static int catcls_free_entry_kv (const void *key, void *data, void *args);
static int catcls_free_entry (CATCLS_ENTRY * entry_p);
static OID *catcls_find_oid (THREAD_ENTRY * thread_p, OID * class_oid);
static int catcls_put_entry (THREAD_ENTRY * thread_p, CATCLS_ENTRY * entry, bool * already_exists);
static char *catcls_unpack_allocator (int size);
static OR_VALUE *catcls_allocate_or_value (int size);
static void catcls_free_sub_value (OR_VALUE * values, int count);
static void catcls_free_or_value (OR_VALUE * value);
static int catcls_expand_or_value_by_def (OR_VALUE * value_p, CT_CLASS * def);
static int catcls_guess_record_length (OR_VALUE * value_p);
static int catcls_find_class_oid_by_class_name (THREAD_ENTRY * thread_p, const char *name, OID * class_oid);
static int catcls_find_btid_of_class_name (THREAD_ENTRY * thread_p, BTID * btid);
static int catcls_find_oid_by_class_name (THREAD_ENTRY * thread_p, const char *name, OID * oid);
static int catcls_convert_class_oid_to_oid (THREAD_ENTRY * thread_p, DB_VALUE * oid_val);
static int catcls_convert_attr_id_to_name (THREAD_ENTRY * thread_p, OR_BUF * orbuf_p, OR_VALUE * value_p);
static void catcls_apply_component_type (OR_VALUE * value_p, int type);
static int catcls_resolution_space (int name_space);
static void catcls_apply_resolutions (OR_VALUE * value_p, OR_VALUE * resolution_p);
static int catcls_replace_entry_oid (THREAD_ENTRY * thread_p, OID * entry_class_oid, OID * entry_new_oid);
static int catcls_get_or_value_from_partition (THREAD_ENTRY * thread_p, OR_BUF * buf_p, OR_VALUE * value_p);
static void catcls_set_or_value_timestamps (OR_VALUE * value_p);
static void catcls_update_or_value_updated_time (OR_VALUE * value_p);
static void catcls_copy_or_value_times_and_statistics (OR_VALUE * value_p, OR_VALUE * old_value_p);
static void catcls_update_or_value_class_stats_fields (OR_VALUE * value_p, unsigned int ci_time_stamp,
bool with_fullscan);
static int catcls_cache_fixed_attr_indexes (THREAD_ENTRY * thread_p);
static int _gv_ct_Class_created_time_idx = -1;
static int _gv_ct_Class_updated_time_idx = -1;
static int _gv_ct_Index_created_time_idx = -1;
static int _gv_ct_Index_updated_time_idx = -1;
static int _gv_ct_Class_checked_time_idx = -1;
static int _gv_ct_Class_statistics_strategy_idx = -1;
/*
* catcls_allocate_entry () -
* return:
* thread_p(in):
*/
static CATCLS_ENTRY *
catcls_allocate_entry (THREAD_ENTRY * thread_p)
{
CATCLS_ENTRY *entry_p;
assert (csect_check_own (thread_p, CSECT_CT_OID_TABLE) == 1);
if (catcls_Free_entry_list != NULL)
{
entry_p = catcls_Free_entry_list;
catcls_Free_entry_list = catcls_Free_entry_list->next;
}
else
{
entry_p = (CATCLS_ENTRY *) malloc (sizeof (CATCLS_ENTRY));
if (entry_p == NULL)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, sizeof (CATCLS_ENTRY));
return NULL;
}
}
entry_p->next = NULL;
return entry_p;
}
/*
* catcls_free_entry_kv () - A callback function to free memory
* allocated for a catcls entry.
* return:
* key(in):
* data(in):
* args(in):
*/
static int
catcls_free_entry_kv (const void *key, void *data, void *args)
{
return catcls_free_entry ((CATCLS_ENTRY *) data);
}
/*
* catcls_free_entry () - free memory allocated for a catcls entry.
* return:
* entry_p(in)
*/
static int
catcls_free_entry (CATCLS_ENTRY * entry_p)
{
assert (csect_check_own (NULL, CSECT_CT_OID_TABLE) == 1);
entry_p->next = catcls_Free_entry_list;
catcls_Free_entry_list = entry_p;
return NO_ERROR;
}
/*
* catcls_initialize_class_oid_to_oid_hash_table () -
* return:
* thread_p(in):
* num_entry(in):
*/
static int
catcls_initialize_class_oid_to_oid_hash_table (THREAD_ENTRY * thread_p, int num_entry)
{
if (csect_enter (thread_p, CSECT_CT_OID_TABLE, INF_WAIT) != NO_ERROR)
{
return ER_FAILED;
}
catcls_Class_oid_to_oid_hash_table = mht_create ("Class OID to OID", num_entry, oid_hash, oid_compare_equals);
if (catcls_Class_oid_to_oid_hash_table == NULL)
{
csect_exit (thread_p, CSECT_CT_OID_TABLE);
return ER_FAILED;
}
csect_exit (thread_p, CSECT_CT_OID_TABLE);
return NO_ERROR;
}
/*
* catcls_finalize_class_oid_to_oid_hash_table () -
* return:
* thread_p(in):
*/
int
catcls_finalize_class_oid_to_oid_hash_table (THREAD_ENTRY * thread_p)
{
CATCLS_ENTRY *entry_p, *next_p;
if (csect_enter (thread_p, CSECT_CT_OID_TABLE, INF_WAIT) != NO_ERROR)
{
return ER_FAILED;
}
if (catcls_Class_oid_to_oid_hash_table)
{
mht_map (catcls_Class_oid_to_oid_hash_table, catcls_free_entry_kv, NULL);
mht_destroy (catcls_Class_oid_to_oid_hash_table);
}
for (entry_p = catcls_Free_entry_list; entry_p; entry_p = next_p)
{
next_p = entry_p->next;
free_and_init (entry_p);
}
catcls_Free_entry_list = NULL;
catcls_Class_oid_to_oid_hash_table = NULL;
csect_exit (thread_p, CSECT_CT_OID_TABLE);
return NO_ERROR;
}
/*
* catcls_find_oid () -
* return:
* thread_p(in):
* class_oid(in):
*/
static OID *
catcls_find_oid (THREAD_ENTRY * thread_p, OID * class_oid_p)
{
CATCLS_ENTRY *entry_p;
#if defined (SERVER_MODE)
assert (csect_check_own (thread_p, CSECT_CT_OID_TABLE) == 2);
#endif
if (catcls_Class_oid_to_oid_hash_table)
{
entry_p = (CATCLS_ENTRY *) mht_get (catcls_Class_oid_to_oid_hash_table, (void *) class_oid_p);
if (entry_p != NULL)
{
return &entry_p->oid;
}
else
{
return NULL;
}
}
return NULL;
}
/*
* catcls_put_entry () -
* return:
* thread_p(in):
* entry(in):
* already_exists(out):
*/
static int
catcls_put_entry (THREAD_ENTRY * thread_p, CATCLS_ENTRY * entry_p, bool * already_exists)
{
const CATCLS_ENTRY *val_p = NULL;
*already_exists = true;
assert (csect_check_own (thread_p, CSECT_CT_OID_TABLE) == 1);
if (catcls_Class_oid_to_oid_hash_table)
{
val_p =
(const CATCLS_ENTRY *) mht_put_if_not_exists (catcls_Class_oid_to_oid_hash_table, &entry_p->class_oid, entry_p);
if (val_p == NULL)
{
return ER_FAILED;
}
if ((void *) val_p != (void *) entry_p)
{
assert (OID_EQ (&val_p->class_oid, &entry_p->class_oid));
assert (OID_EQ (&val_p->oid, &entry_p->oid));
*already_exists = true;
}
else
{
*already_exists = false;
}
}
return NO_ERROR;
}
/*
* catcls_remove_entry () -
* return:
* thread_p(in):
* class_oid(in):
*/
int
catcls_remove_entry (THREAD_ENTRY * thread_p, OID * class_oid_p)
{
assert (csect_check_own (thread_p, CSECT_CT_OID_TABLE) == 1);
if (catcls_Class_oid_to_oid_hash_table)
{
mht_rem (catcls_Class_oid_to_oid_hash_table, class_oid_p, catcls_free_entry_kv, NULL);
}
return NO_ERROR;
}
/*
* catcls_replace_entry_oid () - replace entry OID
* return: error code
* thread_p(in): thread entry
* entry_class_oid(in): entry class OID
* entry_new_oid(in): entry new OID
*/
int
catcls_replace_entry_oid (THREAD_ENTRY * thread_p, OID * entry_class_oid, OID * entry_new_oid)
{
CATCLS_ENTRY *entry_p;
assert (csect_check_own (thread_p, CSECT_CT_OID_TABLE) == 1);
if (catcls_Class_oid_to_oid_hash_table)
{
entry_p = (CATCLS_ENTRY *) mht_get (catcls_Class_oid_to_oid_hash_table, (void *) entry_class_oid);
if (entry_p != NULL)
{
COPY_OID (&entry_p->oid, entry_new_oid);
return NO_ERROR;
}
else
{
return ER_FAILED;
}
}
return NO_ERROR;
}
/*
* catcls_unpack_allocator () -
* return:
* size(in):
*/
static char *
catcls_unpack_allocator (int size)
{
return ((char *) malloc (size));
}
/*
* catcls_allocate_or_value () -
* return:
* size(in):
*/
static OR_VALUE *
catcls_allocate_or_value (int size)
{
OR_VALUE *value_p;
int i;
size_t msize;
msize = size * sizeof (OR_VALUE);
value_p = (OR_VALUE *) malloc (msize);
if (value_p == NULL)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, msize);
}
else
{
for (i = 0; i < size; i++)
{
db_value_put_null (&value_p[i].value);
value_p[i].sub.value = NULL;
value_p[i].sub.count = -1;
}
}
return (value_p);
}
/*
* cr_free_sub_value () -
* return:
* values(in):
* count(in):
*/
static void
catcls_free_sub_value (OR_VALUE * values, int count)
{
int i;
if (values != NULL)
{
for (i = 0; i < count; i++)
{
pr_clear_value (&values[i].value);
catcls_free_sub_value (values[i].sub.value, values[i].sub.count);
}
free_and_init (values);
}
}
/*
* catcls_free_or_value () -
* return:
* value(in):
*/
static void
catcls_free_or_value (OR_VALUE * value_p)
{
if (value_p != NULL)
{
pr_clear_value (&value_p->value);
catcls_free_sub_value (value_p->sub.value, value_p->sub.count);
free_and_init (value_p);
}
}
/*
* catcls_expand_or_value_by_def () -
* return:
* value(in):
* def(in):
*/
static int
catcls_expand_or_value_by_def (OR_VALUE * value_p, CT_CLASS * def_p)
{
OR_VALUE *attrs_p;
int n_attrs;
CT_ATTR *att_def_p;
int i;
int error;
if (value_p != NULL)
{
/* index_of */
COPY_OID (&value_p->id.classoid, &def_p->cc_classoid);
n_attrs = def_p->cc_n_atts;
attrs_p = catcls_allocate_or_value (n_attrs);
if (attrs_p == NULL)
{
return ER_OUT_OF_VIRTUAL_MEMORY;
}
value_p->sub.value = attrs_p;
value_p->sub.count = n_attrs;
att_def_p = def_p->cc_atts;
for (i = 0; i < n_attrs; i++)
{
attrs_p[i].id.attrid = att_def_p[i].ca_id;
error =
db_value_domain_init (&attrs_p[i].value, att_def_p[i].ca_type, DB_DEFAULT_PRECISION, DB_DEFAULT_SCALE);
if (error != NO_ERROR)
{
return error;
}
}
}
return NO_ERROR;
}
/*
* catcls_guess_record_length () -
* return:
* value(in):
*/
static int
catcls_guess_record_length (OR_VALUE * value_p)
{
int length;
DB_TYPE data_type;
const PR_TYPE *map_p;
OR_VALUE *attrs_p;
int n_attrs, i;
attrs_p = value_p->sub.value;
n_attrs = value_p->sub.count;
length = OR_MVCC_MAX_HEADER_SIZE + OR_VAR_TABLE_SIZE (n_attrs) + OR_BOUND_BIT_BYTES (n_attrs);
for (i = 0; i < n_attrs; i++)
{
data_type = DB_VALUE_DOMAIN_TYPE (&attrs_p[i].value);
map_p = tp_Type_id_map[data_type];
length += map_p->get_disk_size_of_value (&attrs_p[i].value);
}
return (length);
}
/*
* catcls_find_class_oid_by_class_name () -
* return:
* name(in):
* class_oid(in):
*/
static int
catcls_find_class_oid_by_class_name (THREAD_ENTRY * thread_p, const char *name_p, OID * class_oid_p)
{
LC_FIND_CLASSNAME status;
status = xlocator_find_class_oid (thread_p, name_p, class_oid_p, NULL_LOCK);
if (status == LC_CLASSNAME_ERROR)
{
er_set (ER_WARNING_SEVERITY, ARG_FILE_LINE, ER_LC_UNKNOWN_CLASSNAME, 1, name_p);
return ER_FAILED;
}
else if (status == LC_CLASSNAME_DELETED)
{
/* not found the class */
OID_SET_NULL (class_oid_p);
}
return NO_ERROR;
}
/*
* catcls_find_btid_of_class_name () -
* return:
* btid(in):
*/
static int
catcls_find_btid_of_class_name (THREAD_ENTRY * thread_p, BTID * btid_p)
{
DISK_REPR *repr_p = NULL;
DISK_ATTR *att_repr_p;
REPR_ID repr_id;
OID *index_class_p;
ATTR_ID index_key;
int error = NO_ERROR;
index_class_p = &ct_Class.cc_classoid;
index_key = (ct_Class.cc_atts)[CT_CLASS_UNIQUE_NAME_INDEX].ca_id;
error = catalog_get_last_representation_id (thread_p, index_class_p, &repr_id);
if (error != NO_ERROR)
{
goto error;
}
else
{
repr_p = catalog_get_representation (thread_p, index_class_p, repr_id, NULL);
if (repr_p == NULL)
{
assert (er_errid () != NO_ERROR);
error = er_errid ();
goto error;
}
}
for (att_repr_p = repr_p->variable; att_repr_p->id != index_key; att_repr_p++)
{
;
}
if (att_repr_p->bt_stats == NULL)
{
error = ER_SM_NO_INDEX;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 1, CATCLS_INDEX_NAME);
goto error;
}
else
{
BTID_COPY (btid_p, &(att_repr_p->bt_stats->btid));
}
catalog_free_representation_and_init (repr_p);
return NO_ERROR;
error:
if (repr_p)
{
catalog_free_representation_and_init (repr_p);
}
return error;
}
/*
* catcls_find_oid_by_class_name () - Get an instance oid in the ct_Class using the
* index for classname
* return:
* name(in):
* oid(in):
*/
static int
catcls_find_oid_by_class_name (THREAD_ENTRY * thread_p, const char *name_p, OID * oid_p)
{
DB_VALUE key_val;
int error = NO_ERROR;
error = db_make_varchar (&key_val, DB_MAX_IDENTIFIER_LENGTH, name_p, (int) strlen (name_p), LANG_SYS_CODESET,
LANG_SYS_COLLATION);
if (error != NO_ERROR)
{
return error;
}
error = xbtree_find_unique (thread_p, &catcls_Btid, S_SELECT, &key_val, &ct_Class.cc_classoid, oid_p, false);
if (error == BTREE_ERROR_OCCURRED)
{
pr_clear_value (&key_val);
assert (er_errid () != NO_ERROR);
error = er_errid ();
return ((error == NO_ERROR) ? ER_FAILED : error);
}
else if (error == BTREE_KEY_NOTFOUND)
{
OID_SET_NULL (oid_p);
}
pr_clear_value (&key_val);
return NO_ERROR;
}
/*
* catcls_convert_class_oid_to_oid () -
* return:
* oid_val(in):
*/
static int
catcls_convert_class_oid_to_oid (THREAD_ENTRY * thread_p, DB_VALUE * oid_val_p)
{
char *name_p = NULL;
OID oid_buf;
OID *class_oid_p, *oid_p;
CATCLS_ENTRY *entry_p;
bool already_exists;
if (DB_IS_NULL (oid_val_p))
{
return NO_ERROR;
}
class_oid_p = db_get_oid (oid_val_p);
if (csect_enter_as_reader (thread_p, CSECT_CT_OID_TABLE, INF_WAIT) != NO_ERROR)
{
return ER_FAILED;
}
oid_p = catcls_find_oid (thread_p, class_oid_p);
csect_exit (thread_p, CSECT_CT_OID_TABLE);
if (oid_p == NULL)
{
oid_p = &oid_buf;
if (heap_get_class_name (thread_p, class_oid_p, &name_p) != NO_ERROR)
{
/* class_oid object may be deleted */
ASSERT_ERROR ();
db_make_null (oid_val_p);
return er_errid ();
}
if (name_p == NULL)
{
/* this is only possible if ER_HEAP_NODATA_NEWADDRESS occur */
db_make_null (oid_val_p);
return NO_ERROR;
}
if (catcls_find_oid_by_class_name (thread_p, name_p, oid_p) != NO_ERROR)
{
free_and_init (name_p);
assert (er_errid () != NO_ERROR);
return er_errid ();
}
if (!OID_ISNULL (oid_p))
{
if (csect_enter (thread_p, CSECT_CT_OID_TABLE, INF_WAIT) != NO_ERROR)
{
return ER_FAILED;
}
if ((entry_p = catcls_allocate_entry (thread_p)) != NULL)
{
COPY_OID (&entry_p->class_oid, class_oid_p);
COPY_OID (&entry_p->oid, oid_p);
catcls_put_entry (thread_p, entry_p, &already_exists);
/* if it already exists, just free current entry_p */
if (already_exists)
{
catcls_free_entry (entry_p);
}
}
csect_exit (thread_p, CSECT_CT_OID_TABLE);
}
}
db_make_oid (oid_val_p, oid_p);
if (name_p)
{
free_and_init (name_p);
}
return NO_ERROR;
}
/*
* catcls_convert_attr_id_to_name () -
* return:
* obuf(in):
* value(in):
*/
static int
catcls_convert_attr_id_to_name (THREAD_ENTRY * thread_p, OR_BUF * orbuf_p, OR_VALUE * value_p)
{
OR_BUF *buf_p, orep;
OR_VALUE *indexes, *keys;
OR_VALUE *index_atts, *key_atts;
OR_VALUE *id_val_p = NULL, *id_atts;
OR_VALUE *ids;
OR_VARINFO *vars = NULL;
int id;
int size;
int i, j, k;
int error = NO_ERROR;
buf_p = &orep;
or_init (buf_p, orbuf_p->buffer, (int) (orbuf_p->endptr - orbuf_p->buffer));
or_advance (buf_p, OR_NON_MVCC_HEADER_SIZE);
size = tf_Metaclass_class.mc_n_variable;
vars = or_get_var_table (buf_p, size, catcls_unpack_allocator);
if (vars == NULL)
{
size_t msize = size * sizeof (OR_VARINFO);
error = ER_OUT_OF_VIRTUAL_MEMORY;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 1, msize);
return error;
}
/* jump to the 'attributes' and extract its id/name. there are no indexes for shared or class attributes, so we need
* only id/name for 'attributes'. the offsets are relative to end of the class record header */
or_seek (buf_p, vars[ORC_ATTRIBUTES_INDEX].offset + OR_NON_MVCC_HEADER_SIZE);
id_val_p = catcls_allocate_or_value (1);
if (id_val_p == NULL)
{
free_and_init (vars);
return ER_OUT_OF_VIRTUAL_MEMORY;
}
error =
catcls_get_subset (thread_p, buf_p, vars[ORC_ATTRIBUTES_INDEX].length, id_val_p, catcls_get_or_value_from_attrid);
if (error != NO_ERROR)
{
free_and_init (vars);
free_and_init (id_val_p);
return error;
}
/* replace id with name for each key attribute */
for (indexes = value_p->sub.value, i = 0; i < value_p->sub.count; i++)
{
index_atts = indexes[i].sub.value;
for (keys = (index_atts[4]).sub.value, j = 0; j < (index_atts[4]).sub.count; j++)
{
key_atts = keys[j].sub.value;
if (DB_IS_NULL (&key_atts[1].value))
{
continue;
}
id = db_get_int (&key_atts[1].value);
if (IS_DEDUPLICATE_KEY_ATTR_ID (id))
{
DB_VALUE tmp_val;
db_make_string (&tmp_val, dk_get_deduplicate_key_attr_name (GET_DEDUPLICATE_KEY_ATTR_LEVEL (id)));
pr_clear_value (&key_atts[1].value);
pr_clone_value (&tmp_val, &key_atts[1].value);
if (tmp_val.need_clear)
{
pr_clear_value (&tmp_val);
}
}
else
{
for (ids = id_val_p->sub.value, k = 0; k < id_val_p->sub.count; k++)
{
id_atts = ids[k].sub.value;
if (!DB_IS_NULL (&id_atts[0].value) && id == db_get_int (&id_atts[0].value))
{
pr_clear_value (&key_atts[1].value);
pr_clone_value (&id_atts[1].value, &key_atts[1].value);
}
}
}
}
}
catcls_free_or_value (id_val_p);
free_and_init (vars);
return NO_ERROR;
}
/*
* catcls_apply_component_type () -
* return:
* value(in):
* type(in):
*/
static void
catcls_apply_component_type (OR_VALUE * value_p, int type)
{
OR_VALUE *subset_p, *attrs;
int i;
for (subset_p = value_p->sub.value, i = 0; i < value_p->sub.count; i++)
{
attrs = subset_p[i].sub.value;
/* assume that the attribute values of xxx are ordered by { class_of, xxx_name, xxx_type, from_xxx_name, ... } */
db_make_int (&attrs[2].value, type);
}
}
/*
* catcls_resolution_space () - modified of sm_resolution_space()
* return:
* name_space(in):
*
* TODO: need to integrate
*/
static int
catcls_resolution_space (int name_space)
{
int res_space = 5; /* ID_INSTANCE */
/* TODO: is ID_CLASS_ATTRIBUTE corret?? */
if (name_space == 1) /* ID_SHARED_ATTRIBUTE */
{
res_space = 6; /* ID_CLASS */
}
return res_space;
}
/*
* catcls_apply_resolutions () -
* return:
* value(in):
* res(in):
*/
static void
catcls_apply_resolutions (OR_VALUE * value_p, OR_VALUE * resolution_p)
{
OR_VALUE *subset_p, *resolution_subset_p;
OR_VALUE *attrs, *res_attrs;
int i, j;
int attr_name_space;
for (resolution_subset_p = resolution_p->sub.value, i = 0; i < resolution_p->sub.count; i++)
{
res_attrs = resolution_subset_p[i].sub.value;
for (subset_p = value_p->sub.value, j = 0; j < value_p->sub.count; j++)
{
attrs = subset_p[j].sub.value;
/* assume that the attribute values of xxx are ordered by { class_of, xxx_name, xxx_type, from_xxx_name, ...
* } */
/* compare component name & name space */
if (tp_value_compare (&attrs[1].value, &res_attrs[1].value, 1, 0) == DB_EQ)
{
attr_name_space = catcls_resolution_space (db_get_int (&attrs[2].value));
if (attr_name_space == db_get_int (&res_attrs[2].value))
{
/* set the value as 'from_xxx_name' */
pr_clear_value (&attrs[3].value);
pr_clone_value (&res_attrs[3].value, &attrs[3].value);
}
}
}
}
}
/*
* catcls_get_or_value_from_class () -
* return:
* buf(in):
* value(in):
*/
static int
catcls_get_or_value_from_class (THREAD_ENTRY * thread_p, OR_BUF * buf_p, OR_VALUE * value_p)
{
OR_VALUE *attrs;
DB_VALUE flags_val;
DB_VALUE *attr_val_p;
OR_VARINFO *vars = NULL;
int size;
OR_VALUE *resolution_p = NULL;
OID class_oid;
const char *dot = NULL;
const char *class_name = NULL;
int error = NO_ERROR;
int flags;
error = catcls_expand_or_value_by_def (value_p, &ct_Class);
if (error != NO_ERROR)
{
goto error;
}
attrs = value_p->sub.value;
size = tf_Metaclass_class.mc_n_variable;
vars = or_get_var_table (buf_p, size, catcls_unpack_allocator);
if (vars == NULL)
{
size_t msize = size * sizeof (OR_VARINFO);
error = ER_OUT_OF_VIRTUAL_MEMORY;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 1, msize);
goto error;
}
/* fixed */
or_advance (buf_p, ORC_ATT_COUNT_OFFSET);
/* attribute_count */
tp_Integer.data_readval (buf_p, &attrs[CT_CLASS_INST_ATTR_COUNT_INDEX].value, NULL, -1, true, NULL, 0);
/* object_size */
or_advance (buf_p, OR_INT_SIZE);
/* shared_count */
tp_Integer.data_readval (buf_p, &attrs[CT_CLASS_SHARED_ATTR_COUNT_INDEX].value, NULL, -1, true, NULL, 0);
/* method_count */
tp_Integer.data_readval (buf_p, &attrs[CT_CLASS_INST_METH_COUNT_INDEX].value, NULL, -1, true, NULL, 0);
/* class_method_count */
tp_Integer.data_readval (buf_p, &attrs[CT_CLASS_CLASS_METH_COUNT_INDEX].value, NULL, -1, true, NULL, 0);
/* class_att_count */
tp_Integer.data_readval (buf_p, &attrs[CT_CLASS_CLASS_ATTR_COUNT_INDEX].value, NULL, -1, true, NULL, 0);
/* flags */
tp_Integer.data_readval (buf_p, &flags_val, NULL, -1, true, NULL, 0);
/* split legacy packed flags: bit0 -> is_system_class (0/1), others -> flags; recombine on write for compatibility. */
flags = db_get_int (&flags_val);
db_make_int (&attrs[CT_CLASS_IS_SYSTEM_CLASS_INDEX].value, flags & SM_CLASSFLAG_SYSTEM);
db_make_int (&attrs[CT_CLASS_FLAGS_INDEX].value, flags & ~SM_CLASSFLAG_SYSTEM);
/* class_type */
tp_Integer.data_readval (buf_p, &attrs[CT_CLASS_CLASS_TYPE_INDEX].value, NULL, -1, true, NULL, 0);
/* owner */
tp_Object.data_readval (buf_p, &attrs[CT_CLASS_OWNER_INDEX].value, NULL, -1, true, NULL, 0);
/* collation_id */
tp_Integer.data_readval (buf_p, &attrs[CT_CLASS_COLLATION_ID_INDEX].value, NULL, -1, true, NULL, 0);
/* tde_algorithm */
tp_Integer.data_readval (buf_p, &attrs[CT_CLASS_TDE_ALGORITHM_INDEX].value, NULL, -1, true, NULL, 0);
/* variable */
/* unique_name */
attr_val_p = &attrs[CT_CLASS_UNIQUE_NAME_INDEX].value;
tp_String.data_readval (buf_p, attr_val_p, NULL, vars[ORC_NAME_INDEX].length, true, NULL, 0);
db_string_truncate (attr_val_p, DB_MAX_IDENTIFIER_LENGTH);
/* class_name */
class_name = db_get_string (attr_val_p);
assert (class_name != NULL);
dot = strchr (class_name, '.');
if (dot)
{
class_name = dot + 1;
}
db_make_string (&attrs[CT_CLASS_CLASS_NAME_INDEX].value, class_name);
/* (class_of) */
if (catcls_find_class_oid_by_class_name
(thread_p, db_get_string (&attrs[CT_CLASS_UNIQUE_NAME_INDEX].value), &class_oid) != NO_ERROR)
{
assert (er_errid () != NO_ERROR);
error = er_errid ();
goto error;
}
db_make_oid (&attrs[CT_CLASS_CLASS_OF_INDEX].value, &class_oid);
/* loader_commands */
or_advance (buf_p, vars[ORC_LOADER_COMMANDS_INDEX].length);
/* representations */
or_advance (buf_p, vars[ORC_REPRESENTATIONS_INDEX].length);
/* sub_classes */
error =
catcls_get_object_set (thread_p, buf_p, vars[ORC_SUBCLASSES_INDEX].length, &attrs[CT_CLASS_SUB_CLASSES_INDEX]);
if (error != NO_ERROR)
{
goto error;
}
/* super_classes */
error =
catcls_get_object_set (thread_p, buf_p, vars[ORC_SUPERCLASSES_INDEX].length, &attrs[CT_CLASS_SUPER_CLASSES_INDEX]);
if (error != NO_ERROR)
{
goto error;
}
/* attributes */
error =
catcls_get_subset (thread_p, buf_p, vars[ORC_ATTRIBUTES_INDEX].length, &attrs[CT_CLASS_INST_ATTRS_INDEX],
catcls_get_or_value_from_attribute);
if (error != NO_ERROR)
{
goto error;
}
/* shared_attributes */
error =
catcls_get_subset (thread_p, buf_p, vars[ORC_SHARED_ATTRS_INDEX].length, &attrs[CT_CLASS_SHARED_ATTRS_INDEX],
catcls_get_or_value_from_attribute);
if (error != NO_ERROR)
{
goto error;
}
/* class_attributes */
error =
catcls_get_subset (thread_p, buf_p, vars[ORC_CLASS_ATTRS_INDEX].length, &attrs[CT_CLASS_CLASS_ATTRS_INDEX],
catcls_get_or_value_from_attribute);
if (error != NO_ERROR)
{
goto error;
}
/* methods */
error =
catcls_get_subset (thread_p, buf_p, vars[ORC_METHODS_INDEX].length, &attrs[CT_CLASS_INST_METHS_INDEX],
catcls_get_or_value_from_method);
if (error != NO_ERROR)
{
goto error;
}
/* class_methods */
error =
catcls_get_subset (thread_p, buf_p, vars[ORC_CLASS_METHODS_INDEX].length, &attrs[CT_CLASS_CLASS_METHS_INDEX],
catcls_get_or_value_from_method);
if (error != NO_ERROR)
{
goto error;
}
/* (apply attribute & method type) */
catcls_apply_component_type (&attrs[CT_CLASS_INST_ATTRS_INDEX], 0);
catcls_apply_component_type (&attrs[CT_CLASS_SHARED_ATTRS_INDEX], 2);
catcls_apply_component_type (&attrs[CT_CLASS_CLASS_ATTRS_INDEX], 1);
catcls_apply_component_type (&attrs[CT_CLASS_INST_METHS_INDEX], 0);
catcls_apply_component_type (&attrs[CT_CLASS_CLASS_METHS_INDEX], 1);
/* method_files */
error =
catcls_get_subset (thread_p, buf_p, vars[ORC_METHOD_FILES_INDEX].length, &attrs[CT_CLASS_METH_FILES_INDEX],
catcls_get_or_value_from_method_file);
if (error != NO_ERROR)
{
goto error;
}
/* (resolutions) */
if (vars[ORC_RESOLUTIONS_INDEX].length > 0)
{
resolution_p = catcls_allocate_or_value (1);
if (resolution_p == NULL)
{
error = ER_OUT_OF_VIRTUAL_MEMORY;
goto error;
}
error =
catcls_get_subset (thread_p, buf_p, vars[ORC_RESOLUTIONS_INDEX].length, resolution_p,
catcls_get_or_value_from_resolution);
if (error != NO_ERROR)
{
goto error;
}
catcls_apply_resolutions (&attrs[CT_CLASS_INST_ATTRS_INDEX], resolution_p);
catcls_apply_resolutions (&attrs[CT_CLASS_SHARED_ATTRS_INDEX], resolution_p);
catcls_apply_resolutions (&attrs[CT_CLASS_CLASS_ATTRS_INDEX], resolution_p);
catcls_apply_resolutions (&attrs[CT_CLASS_INST_METHS_INDEX], resolution_p);
catcls_apply_resolutions (&attrs[CT_CLASS_CLASS_METHS_INDEX], resolution_p);
catcls_free_or_value (resolution_p);
resolution_p = NULL;
}
/* query_spec */
error =
catcls_get_subset (thread_p, buf_p, vars[ORC_QUERY_SPEC_INDEX].length, &attrs[CT_CLASS_QUERY_SPECS_INDEX],
catcls_get_or_value_from_query_spec);
if (error != NO_ERROR)
{
goto error;
}
/* triggers */
or_advance (buf_p, vars[ORC_TRIGGERS_INDEX].length);
/* properties */
error = catcls_get_property_set (thread_p, buf_p, vars[ORC_PROPERTIES_INDEX].length, &attrs[CT_CLASS_INDEXES_INDEX]);
if (error != NO_ERROR)
{
goto error;
}
/* comment */
attr_val_p = &attrs[CT_CLASS_COMMENT_INDEX].value;
tp_String.data_readval (buf_p, attr_val_p, NULL, vars[ORC_COMMENT_INDEX].length, true, NULL, 0);
db_string_truncate (attr_val_p, DB_MAX_CLASS_COMMENT_LENGTH);
/* partition information */
error =
catcls_get_subset (thread_p, buf_p, vars[ORC_PARTITION_INDEX].length, &attrs[CT_CLASS_PARTITION_INDEX],
catcls_get_or_value_from_partition);
if (error != NO_ERROR)
{
goto error;
}
if (vars)
{
free_and_init (vars);
}
return NO_ERROR;
error:
if (vars)
{
free_and_init (vars);
}
if (resolution_p)
{
catcls_free_or_value (resolution_p);
}
return error;
}
/*
* catcls_get_or_value_from_attribute () -
* return:
* buf(in):
* value(in):
*/
static int
catcls_get_or_value_from_attribute (THREAD_ENTRY * thread_p, OR_BUF * buf_p, OR_VALUE * value_p)
{
OR_VALUE *attrs;
DB_VALUE *attr_val_p;
DB_VALUE default_expr, val, db_value_default_expr_type, db_value_default_expr_format, db_value_default_expr_op;
DB_DEFAULT_EXPR_TYPE default_expr_type;
DB_SEQ *def_expr_seq = NULL;
DB_SEQ *att_props = NULL;
OR_VARINFO *vars = NULL;
int size;
int error = NO_ERROR;
const char *default_expr_type_string = NULL;
const char *def_expr_format_string = NULL;
bool with_to_char = false;
error = catcls_expand_or_value_by_def (value_p, &ct_Attribute);
if (error != NO_ERROR)
{
goto error;
}
/* The order of attrs[] is same with that of ct_attribute_atts[]. */
attrs = value_p->sub.value;
size = tf_Metaclass_attribute.mc_n_variable;
vars = or_get_var_table (buf_p, size, catcls_unpack_allocator);
if (vars == NULL)
{
size_t msize = size * sizeof (OR_VARINFO);
error = ER_OUT_OF_VIRTUAL_MEMORY;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 1, msize);
goto error;
}
/* id */
or_advance (buf_p, OR_INT_SIZE);
/* type */
tp_Integer.data_readval (buf_p, &attrs[4].value, NULL, -1, true, NULL, 0);
/* offset */
or_advance (buf_p, OR_INT_SIZE);
/* order */
tp_Integer.data_readval (buf_p, &attrs[5].value, NULL, -1, true, NULL, 0);
/* class */
attr_val_p = &attrs[6].value;
tp_Object.data_readval (buf_p, attr_val_p, NULL, -1, true, NULL, 0);
error = catcls_convert_class_oid_to_oid (thread_p, attr_val_p);
if (error != NO_ERROR)
{
ASSERT_ERROR ();
goto error;
}
/* flag */
attr_val_p = &attrs[7].value;
tp_Integer.data_readval (buf_p, attr_val_p, NULL, -1, true, NULL, 0);
/* for 'is_nullable', reverse NON_NULL flag */
db_make_int (attr_val_p, (db_get_int (attr_val_p) & SM_ATTFLAG_NON_NULL) ? false : true);
/* index_file_id */
or_advance (buf_p, OR_INT_SIZE);
/* index_root_pageid */
or_advance (buf_p, OR_INT_SIZE);
/* index_volid_key */
or_advance (buf_p, OR_INT_SIZE);
/* name */
attr_val_p = &attrs[1].value;
tp_String.data_readval (buf_p, attr_val_p, NULL, vars[ORC_ATT_NAME_INDEX].length, true, NULL, 0);
db_string_truncate (attr_val_p, DB_MAX_IDENTIFIER_LENGTH);
/* default value */
attr_val_p = &attrs[8].value;
or_get_value (buf_p, attr_val_p, NULL, vars[ORC_ATT_CURRENT_VALUE_INDEX].length, true);
/* original value - advance only */
or_advance (buf_p, vars[ORC_ATT_ORIGINAL_VALUE_INDEX].length);
/* domain */
error =
catcls_get_subset (thread_p, buf_p, vars[ORC_ATT_DOMAIN_INDEX].length, &attrs[9], catcls_get_or_value_from_domain);
if (error != NO_ERROR)
{
goto error;
}
/* Complete default value of enumeration type. We need to access domain structure of the attribute in order to get
* access to the elements of enumeration type. */
if (DB_VALUE_TYPE (attr_val_p) == DB_TYPE_ENUMERATION && attrs[9].sub.count > 0)
{
OR_VALUE *or_val = attrs[9].sub.value;
if (or_val == NULL || or_val->sub.count < 8)
{
error = ER_FAILED;
goto error;
}
or_val = or_val[0].sub.value;
if (or_val == NULL)
{
error = ER_FAILED;
goto error;
}
or_val = &or_val[7];
if (!TP_IS_SET_TYPE (DB_VALUE_TYPE (&or_val->value))
|| db_get_enum_short (attr_val_p) > or_val->value.data.set->set->size)
{
error = ER_FAILED;
goto error;
}
error = set_get_element (db_get_set (&or_val->value), db_get_enum_short (attr_val_p) - 1, &val);
if (error != NO_ERROR)
{
goto error;
}
val.need_clear = false;
db_make_enumeration (attr_val_p, db_get_enum_short (attr_val_p), db_get_string (&val), db_get_string_size (&val),
db_get_enum_codeset (attr_val_p), db_get_enum_collation (attr_val_p));
attr_val_p->need_clear = true;
}
/* triggers - advance only */
or_advance (buf_p, vars[ORC_ATT_TRIGGER_INDEX].length);
/* properties */
or_get_value (buf_p, &val, tp_domain_resolve_default (DB_TYPE_SEQUENCE), vars[ORC_ATT_PROPERTIES_INDEX].length, true);
att_props = db_get_set (&val);
attr_val_p = &attrs[8].value;
db_make_null (&default_expr);
if (att_props != NULL)
{
size_t default_value_len = 0;
const char *default_str_val = NULL;
if (classobj_get_prop (att_props, "default_expr", &default_expr) > 0)
{
size_t len;
if (DB_VALUE_TYPE (&default_expr) == DB_TYPE_SEQUENCE)
{
assert (set_size (db_get_set (&default_expr)) == 3);
def_expr_seq = db_get_set (&default_expr);
error = set_get_element_nocopy (def_expr_seq, 0, &db_value_default_expr_op);
if (error != NO_ERROR)
{
goto error;
}
assert (DB_VALUE_TYPE (&db_value_default_expr_op) == DB_TYPE_INTEGER
&& db_get_int (&db_value_default_expr_op) == (int) T_TO_CHAR);
with_to_char = true;
error = set_get_element_nocopy (def_expr_seq, 1, &db_value_default_expr_type);
if (error != NO_ERROR)
{
goto error;
}
default_expr_type = (DB_DEFAULT_EXPR_TYPE) db_get_int (&db_value_default_expr_type);
error = set_get_element_nocopy (def_expr_seq, 2, &db_value_default_expr_format);
if (error != NO_ERROR)
{
goto error;
}
if (!db_value_is_null (&db_value_default_expr_format))
{
#if !defined(NDEBUG)
DB_TYPE db_value_type_local = db_value_type (&db_value_default_expr_format);
assert (db_value_type_local == DB_TYPE_NULL
|| db_value_type_local == DB_TYPE_CHAR || db_value_type_local == DB_TYPE_VARCHAR);
#endif
assert (DB_VALUE_TYPE (&db_value_default_expr_format) == DB_TYPE_STRING);
def_expr_format_string = db_get_string (&db_value_default_expr_format);
}
}
else
{
default_expr_type = (DB_DEFAULT_EXPR_TYPE) db_get_int (&default_expr);
}
default_expr_type_string = db_default_expression_string (default_expr_type);
if (default_expr_type_string == NULL)
{
pr_clear_value (&default_expr);
pr_clear_value (&val);
assert (false);
error = ER_GENERIC_ERROR;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_GENERIC_ERROR, 0);
goto error;
}
len = strlen (default_expr_type_string);
char *default_str_val_tmp = NULL;
if (with_to_char)
{
const char *default_expr_op_string = qdump_operator_type_string (T_TO_CHAR);
assert (default_expr_op_string != NULL);
len += ((default_expr_op_string ? strlen (default_expr_op_string) : 0) /* to_char */
+ 6 /* parenthesis, a comma, a blank and quotes */
+ (def_expr_format_string ? strlen (def_expr_format_string) : 0)); /* nothing or format */
default_str_val_tmp = (char *) db_private_alloc (thread_p, len + 1);
if (default_str_val_tmp == NULL)
{
pr_clear_value (&default_expr);
pr_clear_value (&val);
error = ER_OUT_OF_VIRTUAL_MEMORY;
goto error;
}
strcpy (default_str_val_tmp, default_expr_op_string);
strcat (default_str_val_tmp, "(");
strcat (default_str_val_tmp, default_expr_type_string);
if (def_expr_format_string)
{
strcat (default_str_val_tmp, ", \'");
strcat (default_str_val_tmp, def_expr_format_string);
strcat (default_str_val_tmp, "\'");
}
strcat (default_str_val_tmp, ")");
}
else
{
default_str_val_tmp = (char *) db_private_alloc (thread_p, len + 1);
if (default_str_val_tmp == NULL)
{
pr_clear_value (&default_expr);
pr_clear_value (&val);
error = ER_OUT_OF_VIRTUAL_MEMORY;
goto error;
}
strcpy (default_str_val_tmp, default_expr_type_string);
}
default_str_val = default_str_val_tmp;
pr_clear_value (attr_val_p); /* clean old default value */
db_make_string (attr_val_p, default_str_val);
attr_val_p->need_clear = true;
default_value_len = len;
}
else
{
/* update_default exists and default_expr is not a DEFAULT EXPRESSION or does not exist */
valcnv_convert_value_to_string (attr_val_p);
db_string_truncate (attr_val_p, DB_MAX_IDENTIFIER_LENGTH);
default_str_val = db_get_string (attr_val_p);
if (default_str_val != NULL)
{
default_value_len = strlen (default_str_val);
}
}
if (classobj_get_prop (att_props, "update_default", &default_expr) > 0)
{
default_expr_type = (DB_DEFAULT_EXPR_TYPE) db_get_int (&default_expr);
char *str_val = NULL;
size_t len;
default_expr_type_string = db_default_expression_string (default_expr_type);
if (default_expr_type_string == NULL)
{
pr_clear_value (&default_expr);
pr_clear_value (&val);
assert (false);
error = ER_GENERIC_ERROR;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_GENERIC_ERROR, 0);
goto error;
}
len = strlen (default_expr_type_string);
/* add whitespace character if default_str_val is not an empty string */
str_val =
(char *) db_private_alloc (thread_p,
(default_value_len + (default_value_len ? 1 : 0) + len + strlen ("ON UPDATE ")
+ 1));
if (str_val == NULL)
{
pr_clear_value (&default_expr);
pr_clear_value (&val);
error = ER_OUT_OF_VIRTUAL_MEMORY;
goto error;
}
if (default_str_val != NULL)
{
strcpy (str_val, default_str_val);
strcat (str_val, " ON UPDATE ");
strcat (str_val, default_expr_type_string);
}
else
{
strcpy (str_val, "ON UPDATE ");
strcat (str_val, default_expr_type_string);
}
pr_clear_value (attr_val_p); /* clean old default value */
db_make_string (attr_val_p, str_val);
attr_val_p->need_clear = true;
}
}
else
{
valcnv_convert_value_to_string (attr_val_p);
}
pr_clear_value (&default_expr);
pr_clear_value (&val);
attr_val_p->need_clear = true;
db_string_truncate (attr_val_p, DB_MAX_IDENTIFIER_LENGTH);
/* comment */
attr_val_p = &attrs[10].value;
tp_String.data_readval (buf_p, attr_val_p, NULL, vars[ORC_ATT_COMMENT_INDEX].length, true, NULL, 0);
db_string_truncate (attr_val_p, DB_MAX_COMMENT_LENGTH);
if (vars)
{
free_and_init (vars);
}
return NO_ERROR;
error:
if (vars)
{
free_and_init (vars);
}
return error;
}
/*
* catcls_get_or_value_from_attrid () -
* return:
* buf(in):
* value(in):
*/
static int
catcls_get_or_value_from_attrid (THREAD_ENTRY * thread_p, OR_BUF * buf, OR_VALUE * value)
{
OR_VALUE *attrs;
DB_VALUE *attr_val;
OR_VARINFO *vars = NULL;
int size;
char *start_ptr;
int error = NO_ERROR;
error = catcls_expand_or_value_by_def (value, &ct_Attrid);
if (error != NO_ERROR)
{
goto error;
}
attrs = value->sub.value;
/* variable offset */
start_ptr = buf->ptr;
size = tf_Metaclass_attribute.mc_n_variable;
vars = or_get_var_table (buf, size, catcls_unpack_allocator);
if (vars == NULL)
{
size_t msize = size * sizeof (OR_VARINFO);
error = ER_OUT_OF_VIRTUAL_MEMORY;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 1, msize);
goto error;
}
/* id */
tp_Integer.data_readval (buf, &attrs[0].value, NULL, -1, true, NULL, 0);
or_advance (buf, (int) (start_ptr - buf->ptr) + vars[ORC_ATT_NAME_INDEX].offset);
/* name */
attr_val = &attrs[1].value;
tp_String.data_readval (buf, attr_val, NULL, vars[ORC_ATT_NAME_INDEX].length, true, NULL, 0);
db_string_truncate (attr_val, DB_MAX_IDENTIFIER_LENGTH);
/* go to the end */
or_advance (buf, (int) (start_ptr - buf->ptr) + (vars[(size - 1)].offset + vars[(size - 1)].length));
if (vars)
{
free_and_init (vars);
}
return NO_ERROR;
error:
if (vars)
{
free_and_init (vars);
}
return error;
}
/*
* catcls_get_or_value_from_domain () -
* return:
* buf(in):
* value(in):
*/
static int
catcls_get_or_value_from_domain (THREAD_ENTRY * thread_p, OR_BUF * buf_p, OR_VALUE * value_p)
{
OR_VALUE *attrs;
DB_VALUE *attr_val_p;
OR_VARINFO *vars = NULL;
int size;
int error = NO_ERROR;
error = catcls_expand_or_value_by_def (value_p, &ct_Domain);
if (error != NO_ERROR)
{
goto error;
}
attrs = value_p->sub.value;
size = tf_Metaclass_domain.mc_n_variable;
vars = or_get_var_table (buf_p, size, catcls_unpack_allocator);
if (vars == NULL)
{
size_t msize = size * sizeof (OR_VARINFO);
error = ER_OUT_OF_VIRTUAL_MEMORY;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 1, msize);
goto error;
}
/* type */
tp_Integer.data_readval (buf_p, &attrs[1].value, NULL, -1, true, NULL, 0);
/* precision */
tp_Integer.data_readval (buf_p, &attrs[2].value, NULL, -1, true, NULL, 0);
/* scale */
tp_Integer.data_readval (buf_p, &attrs[3].value, NULL, -1, true, NULL, 0);
/* codeset */
tp_Integer.data_readval (buf_p, &attrs[4].value, NULL, -1, true, NULL, 0);
/* collation id */
tp_Integer.data_readval (buf_p, &attrs[5].value, NULL, -1, true, NULL, 0);
/* class */
attr_val_p = &attrs[6].value;
tp_Object.data_readval (buf_p, attr_val_p, NULL, -1, true, NULL, 0);
if (!DB_IS_NULL (attr_val_p))
{
error = catcls_convert_class_oid_to_oid (thread_p, attr_val_p);
if (error != NO_ERROR)
{
ASSERT_ERROR ();
if (er_errid () == ER_HEAP_UNKNOWN_OBJECT)
{
/* class oid may be deleted; class_oid will be set to NULL OID */
er_clear ();
assert (DB_IS_NULL (attr_val_p));
}
else
{
goto error;
}
}
if (DB_IS_NULL (attr_val_p))
{
/* if self reference for example, "class x (a x)" set an invalid data type, and fill its value later */
error = db_value_domain_init (attr_val_p, DB_TYPE_VARIABLE, DB_DEFAULT_PRECISION, DB_DEFAULT_SCALE);
if (error != NO_ERROR)
{
goto error;
}
}
}
/* enumeration */
if (vars[ORC_DOMAIN_ENUMERATION_INDEX].length)
{
/* enumerations are stored as a collection of strings */
TP_DOMAIN *string_dom = tp_domain_resolve_default (DB_TYPE_STRING);
const PR_TYPE *seq_type = pr_type_from_id (DB_TYPE_SEQUENCE);
TP_DOMAIN *domain = tp_domain_construct (DB_TYPE_SEQUENCE, NULL, 0, 0, string_dom);
if (domain == NULL)
{
error = ER_FAILED;
goto error;
}
domain = tp_domain_cache (domain);
seq_type->data_readval (buf_p, &attrs[7].value, domain, -1, true, NULL, 0);
}
/* set_domain */
error =
catcls_get_subset (thread_p, buf_p, vars[ORC_DOMAIN_SETDOMAIN_INDEX].length, &attrs[8],
catcls_get_or_value_from_domain);
if (vars[ORC_DOMAIN_SCHEMA_JSON_OFFSET].length > 0)
{
char *schema_str;
error = or_get_json_schema (buf_p, schema_str);
if (error != NO_ERROR)
{
goto error;
}
db_make_string (&attrs[9].value, schema_str);
attrs[9].value.need_clear = true;
}
else
{
db_make_null (&attrs[9].value);
}
if (error != NO_ERROR)
{
goto error;
}
if (vars)
{
free_and_init (vars);
}
return NO_ERROR;
error:
if (vars)
{
free_and_init (vars);
}
return error;
}
/*
* catcls_get_or_value_from_method () -
* return:
* buf(in):
* value(in):
*/
static int
catcls_get_or_value_from_method (THREAD_ENTRY * thread_p, OR_BUF * buf_p, OR_VALUE * value_p)
{
OR_VALUE *attrs;
DB_VALUE *attr_val_p;
OR_VARINFO *vars = NULL;
int size;
int error = NO_ERROR;
error = catcls_expand_or_value_by_def (value_p, &ct_Method);
if (error != NO_ERROR)
{
goto error;
}
attrs = value_p->sub.value;
size = tf_Metaclass_method.mc_n_variable;
vars = or_get_var_table (buf_p, size, catcls_unpack_allocator);
if (vars == NULL)
{
size_t msize = size * sizeof (OR_VARINFO);
error = ER_OUT_OF_VIRTUAL_MEMORY;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 1, msize);
goto error;
}
/* class */
attr_val_p = &attrs[4].value;
tp_Object.data_readval (buf_p, attr_val_p, NULL, -1, true, NULL, 0);
error = catcls_convert_class_oid_to_oid (thread_p, attr_val_p);
if (error != NO_ERROR)
{
ASSERT_ERROR ();
goto error;
}
/* id */
or_advance (buf_p, OR_INT_SIZE);
/* name */
attr_val_p = &attrs[1].value;
tp_String.data_readval (buf_p, attr_val_p, NULL, vars[ORC_METHOD_NAME_INDEX].length, true, NULL, 0);
db_string_truncate (attr_val_p, DB_MAX_IDENTIFIER_LENGTH);
/* signatures */
error =
catcls_get_subset (thread_p, buf_p, vars[ORC_METHOD_SIGNATURE_INDEX].length, &attrs[5],
catcls_get_or_value_from_method_signiture);
if (error != NO_ERROR)
{
goto error;
}
/* properties */
or_advance (buf_p, vars[ORC_METHOD_PROPERTIES_INDEX].length);
if (vars)
{
free_and_init (vars);
}
return NO_ERROR;
error:
if (vars)
{
free_and_init (vars);
}
return error;
}
/*
* catcls_get_or_value_from_method_signiture () -
* return:
* buf(in):
* value(in):
*/
static int
catcls_get_or_value_from_method_signiture (THREAD_ENTRY * thread_p, OR_BUF * buf_p, OR_VALUE * value_p)
{
OR_VALUE *attrs;
DB_VALUE *attr_val_p;
OR_VARINFO *vars = NULL;
int size;
int error = NO_ERROR;
error = catcls_expand_or_value_by_def (value_p, &ct_Methsig);
if (error != NO_ERROR)
{
goto error;
}
attrs = value_p->sub.value;
/* variable offset */
size = tf_Metaclass_methsig.mc_n_variable;
vars = or_get_var_table (buf_p, size, catcls_unpack_allocator);
if (vars == NULL)
{
size_t msize = size * sizeof (OR_VARINFO);
error = ER_OUT_OF_VIRTUAL_MEMORY;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 1, msize);
goto error;
}
/* arg_count */
tp_Integer.data_readval (buf_p, &attrs[1].value, NULL, -1, true, NULL, 0);
/* function_name */
attr_val_p = &attrs[2].value;
tp_String.data_readval (buf_p, attr_val_p, NULL, vars[ORC_METHSIG_FUNCTION_NAME_INDEX].length, true, NULL, 0);
db_string_truncate (attr_val_p, DB_MAX_IDENTIFIER_LENGTH);
/* string_def */
or_advance (buf_p, vars[ORC_METHSIG_SQL_DEF_INDEX].length);
/* return_value */
error =
catcls_get_subset (thread_p, buf_p, vars[ORC_METHSIG_RETURN_VALUE_INDEX].length, &attrs[3],
catcls_get_or_value_from_method_argument);
if (error != NO_ERROR)
{
goto error;
}
/* arguments */
error =
catcls_get_subset (thread_p, buf_p, vars[ORC_METHSIG_ARGUMENTS_INDEX].length, &attrs[4],
catcls_get_or_value_from_method_argument);
if (error != NO_ERROR)
{
goto error;
}
if (vars)
{
free_and_init (vars);
}
return NO_ERROR;
error:
if (vars)
{
free_and_init (vars);
}
return error;
}
/*
* catcls_get_or_value_from_method_argument () -
* return:
* buf(in):
* value(in):
*/
static int
catcls_get_or_value_from_method_argument (THREAD_ENTRY * thread_p, OR_BUF * buf_p, OR_VALUE * value_p)
{
OR_VALUE *attrs;
OR_VARINFO *vars = NULL;
int size;
int error;
error = catcls_expand_or_value_by_def (value_p, &ct_Metharg);
if (error != NO_ERROR)
{
goto error;
}
attrs = value_p->sub.value;
size = tf_Metaclass_metharg.mc_n_variable;
vars = or_get_var_table (buf_p, size, catcls_unpack_allocator);
if (vars == NULL)
{
size_t msize = size * sizeof (OR_VARINFO);
error = ER_OUT_OF_VIRTUAL_MEMORY;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 1, msize);
goto error;
}
/* type */
tp_Integer.data_readval (buf_p, &attrs[1].value, NULL, -1, true, NULL, 0);
/* index */
tp_Integer.data_readval (buf_p, &attrs[2].value, NULL, -1, true, NULL, 0);
/* domain */
error =
catcls_get_subset (thread_p, buf_p, vars[ORC_METHARG_DOMAIN_INDEX].length, &attrs[3],
catcls_get_or_value_from_domain);
if (error != NO_ERROR)
{
goto error;
}
if (vars)
{
free_and_init (vars);
}
return NO_ERROR;
error:
if (vars)
{
free_and_init (vars);
}
return error;
}
/*
* catcls_get_or_value_from_method_file () -
* return:
* buf(in):
* value(in):
*/
static int
catcls_get_or_value_from_method_file (THREAD_ENTRY * thread_p, OR_BUF * buf_p, OR_VALUE * value_p)
{
OR_VALUE *attrs;
DB_VALUE *attr_val_p;
OR_VARINFO *vars = NULL;
int size;
int error = NO_ERROR;
error = catcls_expand_or_value_by_def (value_p, &ct_Methfile);
if (error != NO_ERROR)
{
goto error;
}
attrs = value_p->sub.value;
size = tf_Metaclass_methfile.mc_n_variable;
vars = or_get_var_table (buf_p, size, catcls_unpack_allocator);
if (vars == NULL)
{
size_t msize = size * sizeof (OR_VARINFO);
error = ER_OUT_OF_VIRTUAL_MEMORY;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 1, msize);
goto error;
}
/* class */
attr_val_p = &attrs[1].value;
tp_Object.data_readval (buf_p, attr_val_p, NULL, -1, true, NULL, 0);
error = catcls_convert_class_oid_to_oid (thread_p, attr_val_p);
if (error != NO_ERROR)
{
ASSERT_ERROR ();
goto error;
}
/* name */
attr_val_p = &attrs[2].value;
tp_String.data_readval (buf_p, attr_val_p, NULL, vars[ORC_METHFILE_NAME_INDEX].length, true, NULL, 0);
db_string_truncate (attr_val_p, DB_MAX_IDENTIFIER_LENGTH);
/* properties */
or_advance (buf_p, vars[ORC_METHFILE_PROPERTIES_INDEX].length);
if (vars)
{
free_and_init (vars);
}
return NO_ERROR;
error:
if (vars)
{
free_and_init (vars);
}
return error;
}
/*
* catcls_get_or_value_from_resolution () -
* return:
* buf(in):
* value(in):
*/
static int
catcls_get_or_value_from_resolution (THREAD_ENTRY * thread_p, OR_BUF * buf_p, OR_VALUE * value_p)
{
OR_VALUE *attrs;
DB_VALUE *attr_val_p;
OR_VARINFO *vars = NULL;
int size;
int error = NO_ERROR;
error = catcls_expand_or_value_by_def (value_p, &ct_Resolution);
if (error != NO_ERROR)
{
goto error;
}
attrs = value_p->sub.value;
size = tf_Metaclass_resolution.mc_n_variable;
vars = or_get_var_table (buf_p, size, catcls_unpack_allocator);
if (vars == NULL)
{
size_t msize = size * sizeof (OR_VARINFO);
error = ER_OUT_OF_VIRTUAL_MEMORY;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 1, msize);
goto error;
}
/* class */
attr_val_p = &attrs[0].value;
tp_Object.data_readval (buf_p, attr_val_p, NULL, -1, true, NULL, 0);
error = catcls_convert_class_oid_to_oid (thread_p, attr_val_p);
if (error != NO_ERROR)
{
ASSERT_ERROR ();
goto error;
}
/* type */
tp_Integer.data_readval (buf_p, &attrs[2].value, NULL, -1, true, NULL, 0);
/* name */
attr_val_p = &attrs[3].value;
tp_String.data_readval (buf_p, attr_val_p, NULL, vars[ORC_RES_NAME_INDEX].length, true, NULL, 0);
db_string_truncate (attr_val_p, DB_MAX_IDENTIFIER_LENGTH);
/* alias */
attr_val_p = &attrs[1].value;
tp_String.data_readval (buf_p, attr_val_p, NULL, vars[ORC_RES_ALIAS_INDEX].length, true, NULL, 0);
db_string_truncate (attr_val_p, DB_MAX_IDENTIFIER_LENGTH);
if (vars)
{
free_and_init (vars);
}
return NO_ERROR;
error:
if (vars)
{
free_and_init (vars);
}
return error;
}
/*
* catcls_get_or_value_from_query_spec () -
* return:
* buf(in):
* value(in):
*/
static int
catcls_get_or_value_from_query_spec (THREAD_ENTRY * thread_p, OR_BUF * buf_p, OR_VALUE * value_p)
{
OR_VALUE *attrs;
DB_VALUE *attr_val_p;
OR_VARINFO *vars = NULL;
int size;
int error = NO_ERROR;
error = catcls_expand_or_value_by_def (value_p, &ct_Queryspec);
if (error != NO_ERROR)
{
goto error;
}
attrs = value_p->sub.value;
size = tf_Metaclass_query_spec.mc_n_variable;
vars = or_get_var_table (buf_p, size, catcls_unpack_allocator);
if (vars == NULL)
{
size_t msize = size * sizeof (OR_VARINFO);
error = ER_OUT_OF_VIRTUAL_MEMORY;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 1, msize);
goto error;
}
/* specification */
attr_val_p = &attrs[1].value;
tp_String.data_readval (buf_p, attr_val_p, NULL, vars[ORC_QUERY_SPEC_SPEC_INDEX].length, true, NULL, 0);
db_string_truncate (attr_val_p, DB_MAX_SPEC_LENGTH);
if (vars)
{
free_and_init (vars);
}
return NO_ERROR;
error:
if (vars)
{
free_and_init (vars);
}
return error;
}
/*
* catcls_get_or_value_from_indexes () -
* return:
* seq(in):
* values(in):
* is_unique(in):
* is_reverse(in):
* is_primary_key(in):
* is_foreign_key(in):
*/
static int
catcls_get_or_value_from_indexes (DB_SEQ * seq_p, OR_VALUE * values, int is_unique, int is_reverse, int is_primary_key,
int is_foreign_key)
{
int seq_size;
DB_VALUE keys, svalue, val, avalue, *pvalue = NULL;
DB_SEQ *key_seq_p = NULL, *seq = NULL, *pred_seq = NULL, *prefix_seq = NULL;
int key_size, att_cnt;
OR_VALUE *attrs, *key_attrs;
DB_VALUE *attr_val_p;
OR_VALUE *subset_p = NULL;
int e, i, j, k;
int has_function_index = 0;
int error = NO_ERROR;
db_value_put_null (&keys);
db_value_put_null (&svalue);
db_value_put_null (&val);
db_value_put_null (&avalue);
seq_size = set_size (seq_p);
for (i = 0, j = 0; i < seq_size; i += 2, j++)
{
has_function_index = 0;
prefix_seq = NULL;
error = catcls_expand_or_value_by_def (&values[j], &ct_Index);
if (error != NO_ERROR)
{
goto error;
}
attrs = values[j].sub.value;
attr_val_p = &attrs[CT_INDEX_INDEX_NAME_INDEX].value;
error = set_get_element (seq_p, i, attr_val_p);
if (error != NO_ERROR)
{
goto error;
}
db_string_truncate (attr_val_p, DB_MAX_IDENTIFIER_LENGTH);
db_make_int (&attrs[CT_INDEX_IS_UNIQUE_INDEX].value, is_unique);
error = set_get_element (seq_p, i + 1, &keys);
if (error != NO_ERROR)
{
goto error;
}
if (DB_VALUE_TYPE (&keys) == DB_TYPE_SEQUENCE)
{
key_seq_p = db_get_set (&keys);
}
else
{
assert (0);
error = ER_SM_INVALID_PROPERTY;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 0);
goto error;
}
key_size = set_size (key_seq_p);
att_cnt = get_class_constraint_att_count (key_size);
error =
set_get_element (key_seq_p, get_class_constraint_index (key_size, SM_CONSTRAINT_STATUS_INDEX),
&attrs[CT_INDEX_STATUS_INDEX].value);
if (error != NO_ERROR)
{
goto error;
}
if (is_foreign_key)
{
error = set_get_element (key_seq_p,
get_class_constraint_index (key_size, SM_CONSTRAINT_OPTIONAL_INFO_INDEX), &svalue);
if (error != NO_ERROR)
{
goto error;
}
if (DB_VALUE_TYPE (&svalue) != DB_TYPE_SEQUENCE)
{
error = ER_SM_INVALID_PROPERTY;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 0);
goto error;
}
seq = db_get_set (&svalue);
error = set_get_element (seq, SM_FK_INFO_INDEX_CATALOG_OF_REF_CLASS_INDEX, &val);
if (error != NO_ERROR)
{
goto error;
}
if (db_value_is_null (&val) == false)
{
db_make_oid (&attrs[CT_INDEX_REFERENTIAL_INDEX_INDEX].value, db_get_oid (&val));
}
error = set_get_element (seq, SM_FK_INFO_DELETE_ACTION_INDEX, &val);
if (error != NO_ERROR)
{
goto error;
}
db_make_int (&attrs[CT_INDEX_DELETE_RULE_INDEX].value, db_get_int (&val));
error = set_get_element (seq, SM_FK_INFO_UPDATE_ACTION_INDEX, &val);
if (error != NO_ERROR)
{
goto error;
}
db_make_int (&attrs[CT_INDEX_UPDATE_RULE_INDEX].value, db_get_int (&val));
seq = db_get_set (&svalue);
error = set_get_element (seq, SM_FK_INFO_REF_MATCH_OPTION_INDEX, &val);
if (error != NO_ERROR)
{
goto error;
}
db_make_int (&attrs[CT_INDEX_REFERENTIAL_MATCH_OPTION_INDEX].value, db_get_int (&val));
}
error =
set_get_element (key_seq_p, get_class_constraint_index (key_size, SM_CONSTRAINT_INDEX_TYPE_INDEX),
&attrs[CT_INDEX_INDEX_TYPE_INDEX].value);
if (error != NO_ERROR)
{
goto error;
}
error =
set_get_element (key_seq_p, get_class_constraint_index (key_size, SM_CONSTRAINT_OPTIONS_INDEX),
&attrs[CT_INDEX_OPTIONS_INDEX].value);
if (error != NO_ERROR)
{
goto error;
}
error =
set_get_element (key_seq_p, get_class_constraint_index (key_size, SM_CONSTRAINT_COMMENT_INDEX),
&attrs[CT_INDEX_COMMENT_INDEX].value);
if (error != NO_ERROR)
{
goto error;
}
db_string_truncate (&attrs[CT_INDEX_COMMENT_INDEX].value, DB_MAX_COMMENT_LENGTH);
if (!is_primary_key && !is_foreign_key)
{
error =
set_get_element (key_seq_p, get_class_constraint_index (key_size, SM_CONSTRAINT_OPTIONAL_INFO_INDEX),
&svalue);
if (error != NO_ERROR)
{
goto error;
}
if (DB_VALUE_TYPE (&svalue) != DB_TYPE_SEQUENCE)
{
error = ER_SM_INVALID_PROPERTY;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 0);
goto error;
}
seq = db_get_set (&svalue);
error = set_get_element (seq, 0, &val);
if (error != NO_ERROR)
{
goto error;
}
if (DB_VALUE_TYPE (&val) == DB_TYPE_INTEGER)
{
/* have prefix length */
prefix_seq = seq;
}
else if (DB_VALUE_TYPE (&val) == DB_TYPE_SEQUENCE)
{
DB_SET *child_seq = db_get_set (&val);
int seq_size = set_size (seq);
SM_INDEX_FLAG index_flag;
int l = 0;
DB_VALUE temp;
int col_id, att_index_start;
char *buffer, *ptr;
TP_DOMAIN *fi_domain = NULL;
const char *index_flag_str;
/* have filter or function index */
while (true)
{
error = set_get_element (child_seq, 0, &avalue);
if (error != NO_ERROR)
{
goto error;
}
if (DB_IS_NULL (&avalue) || DB_VALUE_TYPE (&avalue) != DB_TYPE_STRING)
{
error = ER_SM_INVALID_PROPERTY;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 0);
goto error;
}
index_flag_str = db_get_string (&avalue);
if (!intl_identifier_casecmp (index_flag_str, SM_FILTER_INDEX_ID))
{
index_flag = SM_INDEX_FLAG_FILTER;
}
else if (!intl_identifier_casecmp (index_flag_str, SM_FUNCTION_INDEX_ID))
{
index_flag = SM_INDEX_FLAG_FUNCTION;
}
else if (!intl_identifier_casecmp (index_flag_str, SM_PREFIX_INDEX_ID))
{
index_flag = SM_INDEX_FLAG_PREFIX;
}
else
{
index_flag = SM_INDEX_FLAG_NONE;
}
pr_clear_value (&avalue);
error = set_get_element (child_seq, 1, &avalue);
if (error != NO_ERROR)
{
goto error;
}
if (DB_VALUE_TYPE (&avalue) != DB_TYPE_SEQUENCE)
{
error = ER_SM_INVALID_PROPERTY;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 0);
goto error;
}
switch (index_flag)
{
case SM_INDEX_FLAG_FILTER:
pred_seq = db_get_set (&avalue);
attr_val_p = &attrs[CT_INDEX_FILTER_EXPRESSION_INDEX].value;
error = set_get_element (pred_seq, 0, attr_val_p);
if (error != NO_ERROR)
{
goto error;
}
break;
case SM_INDEX_FLAG_FUNCTION:
has_function_index = 1;
pred_seq = db_get_set (&avalue);
error = set_get_element_nocopy (pred_seq, 2, &temp);
if (error != NO_ERROR)
{
goto error;
}
col_id = db_get_int (&temp);
error = set_get_element_nocopy (pred_seq, 3, &temp);
if (error != NO_ERROR)
{
goto error;
}
att_index_start = db_get_int (&temp);
assert (col_id <= att_index_start);
att_cnt = att_index_start + 1;
db_make_int (&attrs[CT_INDEX_KEY_COUNT_INDEX].value, att_cnt);
subset_p = catcls_allocate_or_value (att_cnt);
if (subset_p == NULL)
{
error = ER_OUT_OF_VIRTUAL_MEMORY;
goto error;
}
attrs[CT_INDEX_KEY_ATTRS_INDEX].sub.value = subset_p;
attrs[CT_INDEX_KEY_ATTRS_INDEX].sub.count = att_cnt;
/* key_attrs */
e = 1;
for (k = 0; k < att_cnt; k++) /* for each [attrID, asc_desc]+ */
{
error = catcls_expand_or_value_by_def (&subset_p[k], &ct_Indexkey);
if (error != NO_ERROR)
{
goto error;
}
key_attrs = subset_p[k].sub.value;
if (k != col_id)
{
/* key_attr_id */
attr_val_p = &key_attrs[1].value;
error = set_get_element (key_seq_p, e++, attr_val_p);
if (error != NO_ERROR)
{
goto error;
}
/* key_order */
db_make_int (&key_attrs[2].value, k);
/* asc_desc */
attr_val_p = &key_attrs[3].value;
error = set_get_element (key_seq_p, e++, attr_val_p);
if (error != NO_ERROR)
{
goto error;
}
/* function name */
db_make_null (&key_attrs[5].value);
}
else
{
/* key_attr_id */
db_make_null (&key_attrs[1].value);
/* key_order */
db_make_int (&key_attrs[2].value, k);
/* asc_desc */
error = set_get_element_nocopy (pred_seq, 4, &temp);
if (error != NO_ERROR)
{
goto error;
}
// use const_cast since of a limitation of or_unpack_* functions which do not accept const
buffer = CONST_CAST (char *, db_get_string (&temp));
ptr = buffer;
ptr = or_unpack_domain (ptr, &fi_domain, NULL);
db_make_int (&key_attrs[3].value, fi_domain->is_desc);
tp_domain_free (fi_domain);
/* function name */
attr_val_p = &key_attrs[5].value;
error = set_get_element (pred_seq, 0, attr_val_p);
if (error != NO_ERROR)
{
goto error;
}
}
/* prefix_length */
db_make_int (&key_attrs[4].value, -1);
}
break;
case SM_INDEX_FLAG_PREFIX:
pvalue = db_value_copy (&avalue);
prefix_seq = db_get_set (pvalue);
break;
default:
break;
}
pr_clear_value (&avalue);
l++;
if (l >= seq_size)
{
break;
}
pr_clear_value (&val);
if (set_get_element (seq, l, &val) != NO_ERROR)
{
error = ER_FAILED;
goto error;
}
if (DB_VALUE_TYPE (&val) != DB_TYPE_SEQUENCE)
{
error = ER_FAILED;
goto error;
}
child_seq = db_get_set (&val);
}
}
else
{
error = ER_SM_INVALID_PROPERTY;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 0);
goto error;
}
pr_clear_value (&val);
}
if (has_function_index == 0)
{
db_make_int (&attrs[CT_INDEX_KEY_COUNT_INDEX].value, att_cnt);
subset_p = catcls_allocate_or_value (att_cnt);
if (subset_p == NULL)
{
error = ER_OUT_OF_VIRTUAL_MEMORY;
goto error;
}
attrs[CT_INDEX_KEY_ATTRS_INDEX].sub.value = subset_p;
attrs[CT_INDEX_KEY_ATTRS_INDEX].sub.count = att_cnt;
/* key_attrs */
e = 1;
for (k = 0; k < att_cnt; k++) /* for each [attrID, asc_desc]+ */
{
error = catcls_expand_or_value_by_def (&subset_p[k], &ct_Indexkey);
if (error != NO_ERROR)
{
goto error;
}
key_attrs = subset_p[k].sub.value;
/* key_attr_id */
attr_val_p = &key_attrs[1].value;
error = set_get_element (key_seq_p, e++, attr_val_p);
if (error != NO_ERROR)
{
goto error;
}
/* key_order */
db_make_int (&key_attrs[2].value, k);
/* asc_desc */
attr_val_p = &key_attrs[3].value;
error = set_get_element (key_seq_p, e++, attr_val_p);
if (error != NO_ERROR)
{
goto error;
}
/* prefix_length */
db_make_int (&key_attrs[4].value, -1);
/* function name */
db_make_null (&key_attrs[5].value);
}
}
if (prefix_seq)
{
for (k = 0; k < att_cnt; k++)
{
key_attrs = subset_p[k].sub.value;
attr_val_p = &key_attrs[4].value;
error = set_get_element (prefix_seq, k, attr_val_p);
if (error != NO_ERROR)
{
goto error;
}
}
}
pr_clear_value (&svalue);
pr_clear_value (&keys);
if (pvalue)
{
pr_free_ext_value (pvalue);
pvalue = NULL;
}
db_make_int (&attrs[CT_INDEX_IS_REVERSE_INDEX].value, is_reverse);
db_make_int (&attrs[CT_INDEX_IS_PRIMARY_KEY_INDEX].value, is_primary_key);
db_make_int (&attrs[CT_INDEX_IS_FOREIGN_KEY_INDEX].value, is_foreign_key);
db_make_int (&attrs[CT_INDEX_HAVE_FUNCTION_INDEX].value, has_function_index);
}
return NO_ERROR;
error:
pr_clear_value (&keys);
pr_clear_value (&svalue);
pr_clear_value (&val);
pr_clear_value (&avalue);
if (pvalue)
{
pr_free_ext_value (pvalue);
}
return error;
}
/*
* catcls_get_subset () -
* return:
* buf(in):
* expected_size(in):
* value(in):
* reader(in):
*/
static int
catcls_get_subset (THREAD_ENTRY * thread_p, OR_BUF * buf_p, int expected_size, OR_VALUE * value_p, CREADER reader)
{
OR_VALUE *subset_p;
int count, i;
int error = NO_ERROR;
if (expected_size == 0)
{
value_p->sub.count = 0;
return NO_ERROR;
}
count = or_skip_set_header (buf_p);
subset_p = catcls_allocate_or_value (count);
if (subset_p == NULL)
{
return ER_OUT_OF_VIRTUAL_MEMORY;
}
value_p->sub.value = subset_p;
value_p->sub.count = count;
for (i = 0; i < count; i++)
{
error = (*reader) (thread_p, buf_p, &subset_p[i]);
if (error != NO_ERROR)
{
return error;
}
}
return NO_ERROR;
}
/*
* catcls_get_object_set () -
* return:
* buf(in):
* expected_size(in):
* value(in):
*/
static int
catcls_get_object_set (THREAD_ENTRY * thread_p, OR_BUF * buf_p, int expected_size, OR_VALUE * value_p)
{
DB_SET *oid_set_p = NULL;
DB_VALUE oid_val;
int count, i;
int error = NO_ERROR;
if (expected_size == 0)
{
return NO_ERROR;
}
count = or_skip_set_header (buf_p);
oid_set_p = set_create_sequence (count);
if (oid_set_p == NULL)
{
assert (er_errid () != NO_ERROR);
error = er_errid ();
goto error;
}
for (i = 0; i < count; i++)
{
tp_Object.data_readval (buf_p, &oid_val, NULL, -1, true, NULL, 0);
error = catcls_convert_class_oid_to_oid (thread_p, &oid_val);
if (error != NO_ERROR)
{
ASSERT_ERROR ();
goto error;
}
error = set_put_element (oid_set_p, i, &oid_val);
if (error != NO_ERROR)
{
goto error;
}
}
db_make_sequence (&value_p->value, oid_set_p);
return NO_ERROR;
error:
if (oid_set_p)
{
set_free (oid_set_p);
}
return error;
}
/*
* catcls_get_property_set () -
* return:
* buf(in):
* expected_size(in):
* value(in):
*/
static int
catcls_get_property_set (THREAD_ENTRY * thread_p, OR_BUF * buf_p, int expected_size, OR_VALUE * value_p)
{
DB_VALUE prop_val;
DB_SEQ *prop_seq_p = NULL;
int n_size = 0;
CATCLS_PROPERTY property_vars[SM_PROPERTY_NUM_INDEX_FAMILY] = {
{SM_PROPERTY_PRIMARY_KEY, NULL, 0, true, false, true, false},
{SM_PROPERTY_UNIQUE, NULL, 0, true, false, false, false},
{SM_PROPERTY_REVERSE_UNIQUE, NULL, 0, true, true, false, false},
{SM_PROPERTY_INDEX, NULL, 0, false, false, false, false},
{SM_PROPERTY_REVERSE_INDEX, NULL, 0, false, true, false, false},
{SM_PROPERTY_FOREIGN_KEY, NULL, 0, false, false, false, true},
};
DB_VALUE vals[SM_PROPERTY_NUM_INDEX_FAMILY];
OR_VALUE *subset_p = NULL;
int error = NO_ERROR;
int i, idx;
if (expected_size == 0)
{
value_p->sub.count = 0;
return NO_ERROR;
}
db_value_put_null (&prop_val);
for (i = 0; i < SM_PROPERTY_NUM_INDEX_FAMILY; i++)
{
db_value_put_null (&vals[i]);
}
tp_Sequence.data_readval (buf_p, &prop_val, NULL, expected_size, true, NULL, 0);
prop_seq_p = db_get_set (&prop_val);
for (i = 0; i < SM_PROPERTY_NUM_INDEX_FAMILY; i++)
{
if (prop_seq_p != NULL && (classobj_get_prop (prop_seq_p, property_vars[i].name, &vals[i]) > 0))
{
if (DB_VALUE_TYPE (&vals[i]) == DB_TYPE_SEQUENCE)
{
property_vars[i].seq = db_get_set (&vals[i]);
}
if (property_vars[i].seq != NULL)
{
property_vars[i].size = set_size (property_vars[i].seq) / 2;
n_size += property_vars[i].size;
}
}
}
if (n_size > 0)
{
subset_p = catcls_allocate_or_value (n_size);
if (subset_p == NULL)
{
error = ER_OUT_OF_VIRTUAL_MEMORY;
goto error;
}
value_p->sub.value = subset_p;
value_p->sub.count = n_size;
}
else
{
value_p->sub.value = NULL;
value_p->sub.count = 0;
}
idx = 0;
for (i = 0; i < SM_PROPERTY_NUM_INDEX_FAMILY; i++)
{
if (property_vars[i].seq != NULL)
{
error =
catcls_get_or_value_from_indexes (property_vars[i].seq, &subset_p[idx], property_vars[i].is_unique,
property_vars[i].is_reverse, property_vars[i].is_primary_key,
property_vars[i].is_foreign_key);
if (error != NO_ERROR)
{
goto error;
}
}
idx += property_vars[i].size;
}
error = catcls_convert_attr_id_to_name (thread_p, buf_p, value_p);
if (error != NO_ERROR)
{
goto error;
}
pr_clear_value (&prop_val);
for (i = 0; i < SM_PROPERTY_NUM_INDEX_FAMILY; i++)
{
pr_clear_value (&vals[i]);
}
return NO_ERROR;
error:
pr_clear_value (&prop_val);
for (i = 0; i < SM_PROPERTY_NUM_INDEX_FAMILY; i++)
{
pr_clear_value (&vals[i]);
}
return error;
}
/*
* catcls_reorder_attributes_by_repr () -
* return:
* value(in):
*/
static int
catcls_reorder_attributes_by_repr (THREAD_ENTRY * thread_p, OR_VALUE * value_p)
{
OR_VALUE *attrs, *var_attrs;
int n_attrs;
DISK_ATTR *fixed_p, *variable_p;
int n_fixed, n_variable;
DISK_REPR *repr_p = NULL;
REPR_ID repr_id;
OID *class_oid_p;
int i, j;
int error = NO_ERROR;
class_oid_p = &value_p->id.classoid;
error = catalog_get_last_representation_id (thread_p, class_oid_p, &repr_id);
if (error != NO_ERROR)
{
goto error;
}
else
{
repr_p = catalog_get_representation (thread_p, class_oid_p, repr_id, NULL);
if (repr_p == NULL)
{
assert (er_errid () != NO_ERROR);
error = er_errid ();
goto error;
}
}
fixed_p = repr_p->fixed;
n_fixed = repr_p->n_fixed;
variable_p = repr_p->variable;
n_variable = repr_p->n_variable;
attrs = value_p->sub.value;
n_attrs = n_fixed + n_variable;
for (i = 0; i < n_fixed; i++)
{
for (j = i; j < n_attrs; j++)
{
if (fixed_p[i].id == attrs[j].id.attrid)
{
if (i != j)
{ /* need to exchange */
EXCHANGE_OR_VALUE (attrs[i], attrs[j]);
}
break;
}
}
}
var_attrs = &attrs[n_fixed];
for (i = 0; i < n_variable; i++)
{
for (j = i; j < n_variable; j++)
{
if (variable_p[i].id == var_attrs[j].id.attrid)
{
if (i != j)
{ /* need to exchange */
EXCHANGE_OR_VALUE (var_attrs[i], var_attrs[j]);
}
break;
}
}
}
catalog_free_representation_and_init (repr_p);
return NO_ERROR;
error:
if (repr_p)
{
catalog_free_representation_and_init (repr_p);
}
return error;
}
/*
* catcls_expand_or_value_by_repr () -
* return:
* value(in):
* class_oid(in):
* rep(in):
*/
static int
catcls_expand_or_value_by_repr (OR_VALUE * value_p, OID * class_oid_p, DISK_REPR * repr_p)
{
OR_VALUE *attrs, *var_attrs;
int n_attrs;
DISK_ATTR *fixed_p, *variable_p;
int n_fixed, n_variable;
int i;
int error = NO_ERROR;
fixed_p = repr_p->fixed;
n_fixed = repr_p->n_fixed;
variable_p = repr_p->variable;
n_variable = repr_p->n_variable;
n_attrs = n_fixed + n_variable;
attrs = catcls_allocate_or_value (n_attrs);
if (attrs == NULL)
{
return ER_OUT_OF_VIRTUAL_MEMORY;
}
value_p->sub.value = attrs;
value_p->sub.count = n_attrs;
COPY_OID (&value_p->id.classoid, class_oid_p);
for (i = 0; i < n_fixed; i++)
{
attrs[i].id.attrid = fixed_p[i].id;
error = db_value_domain_init (&attrs[i].value, fixed_p[i].type, DB_DEFAULT_PRECISION, DB_DEFAULT_SCALE);
if (error != NO_ERROR)
{
return error;
}
}
var_attrs = &attrs[n_fixed];
for (i = 0; i < n_variable; i++)
{
var_attrs[i].id.attrid = variable_p[i].id;
error = db_value_domain_init (&var_attrs[i].value, variable_p[i].type, DB_DEFAULT_PRECISION, DB_DEFAULT_SCALE);
if (error != NO_ERROR)
{
return error;
}
}
return NO_ERROR;
}
/*
* catcls_expand_or_value_by_subset () -
* return:
* value(in):
*/
static int
catcls_expand_or_value_by_subset (THREAD_ENTRY * thread_p, OR_VALUE * value_p)
{
DB_SET *set_p;
int size, i;
DB_VALUE element;
OID *oid_p, class_oid;
OR_VALUE *subset_p;
SCAN_CODE scan_code;
int err = NO_ERROR;
if (!pr_is_set_type (DB_VALUE_TYPE (&value_p->value)))
{
return NO_ERROR;
}
set_p = db_get_set (&value_p->value);
size = set_size (set_p);
if (size > 0)
{
set_get_element_nocopy (set_p, 0, &element);
if (DB_VALUE_TYPE (&element) == DB_TYPE_OID)
{
oid_p = db_get_oid (&element);
scan_code = heap_get_class_oid (thread_p, oid_p, &class_oid);
if (er_errid () == ER_HEAP_UNKNOWN_OBJECT)
{
/* Currently, we have reached here the situation where an instance has already been removed by the same
* transaction. One example is when dropping a partition. The instances corresponding the partitions will
* first be removed, which implies that the class OID can no longer be found and will be set to NULL. */
er_clear ();
}
else if (scan_code == S_ERROR)
{
ASSERT_ERROR_AND_SET (err);
}
if (!OID_EQ (&class_oid, &ct_Class.cc_classoid) && !OID_ISNULL (&class_oid))
{
subset_p = catcls_allocate_or_value (size);
if (subset_p != NULL)
{
value_p->sub.value = subset_p;
value_p->sub.count = size;
for (i = 0; i < size; i++)
{
COPY_OID (&((subset_p[i]).id.classoid), &class_oid);
}
}
}
}
}
return err;
}
/*
* catcls_put_or_value_into_buffer () -
* return:
* value(in):
* chn(in):
* buf(in):
* class_oid(in):
* rep(in):
*/
static int
catcls_put_or_value_into_buffer (OR_VALUE * value_p, int chn, OR_BUF * buf_p, OID * class_oid_p, DISK_REPR * repr_p)
{
OR_VALUE *attrs, *var_attrs;
int n_attrs;
DISK_ATTR *fixed_p, *variable_p;
int n_fixed, n_variable;
DB_TYPE data_type;
unsigned int repr_id_bits;
char *bound_bits = NULL;
int bound_size;
char *offset_p, *start_p;
int i, pad, offset, header_size;
int error = NO_ERROR;
fixed_p = repr_p->fixed;
n_fixed = repr_p->n_fixed;
variable_p = repr_p->variable;
n_variable = repr_p->n_variable;
attrs = value_p->sub.value;
n_attrs = n_fixed + n_variable;
bound_size = OR_BOUND_BIT_BYTES (n_fixed);
bound_bits = (char *) malloc (bound_size);
if (bound_bits == NULL)
{
error = ER_OUT_OF_VIRTUAL_MEMORY;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 1, (size_t) bound_size);
goto error;
}
memset (bound_bits, 0, bound_size);
/* header */
repr_id_bits = repr_p->id;
if (n_fixed)
{
repr_id_bits |= OR_BOUND_BIT_FLAG;
}
OR_SET_VAR_OFFSET_SIZE (repr_id_bits, BIG_VAR_OFFSET_SIZE); /* 4byte */
repr_id_bits |= (OR_MVCC_FLAG_VALID_INSID << OR_MVCC_FLAG_SHIFT_BITS);
or_put_int (buf_p, repr_id_bits);
or_put_int (buf_p, chn); /* CHN */
or_put_bigint (buf_p, MVCCID_NULL); /* MVCC insert id */
header_size = OR_MVCC_INSERT_HEADER_SIZE;
/* offset table */
offset_p = buf_p->ptr;
or_advance (buf_p, OR_VAR_TABLE_SIZE (n_variable));
/* fixed */
start_p = buf_p->ptr;
for (i = 0; i < n_fixed; i++)
{
data_type = fixed_p[i].type;
if (DB_IS_NULL (&attrs[i].value))
{
or_advance (buf_p, (*tp_Type_id_map[data_type]).disksize);
OR_CLEAR_BOUND_BIT (bound_bits, i);
}
else
{
(*tp_Type_id_map[data_type]).data_writeval (buf_p, &attrs[i].value);
OR_ENABLE_BOUND_BIT (bound_bits, i);
}
}
pad = (int) (buf_p->ptr - start_p);
if (pad < repr_p->fixed_length)
{
or_pad (buf_p, repr_p->fixed_length - pad);
}
else if (pad > repr_p->fixed_length)
{
error = ER_SM_CORRUPTED;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 0);
goto error;
}
/* bound bits */
if (n_fixed)
{
or_put_data (buf_p, bound_bits, bound_size);
}
/* variable */
var_attrs = &attrs[n_fixed];
for (i = 0; i < n_variable; i++)
{
/* the variable offsets are relative to end of the class record header */
offset = (int) (buf_p->ptr - buf_p->buffer - header_size);
data_type = variable_p[i].type;
(*tp_Type_id_map[data_type]).data_writeval (buf_p, &var_attrs[i].value);
OR_PUT_OFFSET (offset_p, offset);
offset_p += BIG_VAR_OFFSET_SIZE;
}
/* put last offset */
offset = (int) (buf_p->ptr - buf_p->buffer - header_size);
OR_PUT_OFFSET (offset_p, offset);
if (bound_bits)
{
free_and_init (bound_bits);
}
return NO_ERROR;
error:
if (bound_bits)
{
free_and_init (bound_bits);
}
return error;
}
/*
* catcls_get_or_value_from_buffer () -
* return:
* buf(in):
* value(in):
* rep(in):
*/
static int
catcls_get_or_value_from_buffer (THREAD_ENTRY * thread_p, OR_BUF * buf_p, OR_VALUE * value_p, DISK_REPR * repr_p)
{
OR_VALUE *attrs, *var_attrs;
int n_attrs;
DISK_ATTR *fixed_p, *variable_p;
int n_fixed, n_variable;
DB_TYPE data_type;
OR_VARINFO *vars = NULL;
unsigned int repr_id_bits;
char *bound_bits = NULL;
int bound_bits_flag = false;
char *start_p;
int i, pad, size, rc;
int error = NO_ERROR;
char mvcc_flags;
int offset_size;
fixed_p = repr_p->fixed;
n_fixed = repr_p->n_fixed;
variable_p = repr_p->variable;
n_variable = repr_p->n_variable;
attrs = value_p->sub.value;
n_attrs = n_fixed + n_variable;
offset_size = OR_GET_OFFSET_SIZE (buf_p->ptr);
/* header */
assert (offset_size == BIG_VAR_OFFSET_SIZE || offset_size == SHORT_VAR_OFFSET_SIZE);
repr_id_bits = or_mvcc_get_repid_and_flags (buf_p, &rc);
/* get bound_bits_flag and skip other MVCC header fields */
bound_bits_flag = repr_id_bits & OR_BOUND_BIT_FLAG;
mvcc_flags = (char) ((repr_id_bits >> OR_MVCC_FLAG_SHIFT_BITS) & OR_MVCC_FLAG_MASK);
repr_id_bits = repr_id_bits & OR_MVCC_REPID_MASK;
or_advance (buf_p, OR_INT_SIZE); /* skip CHN */
if (mvcc_flags & OR_MVCC_FLAG_VALID_INSID)
{
or_advance (buf_p, OR_MVCCID_SIZE); /* skip INS_ID */
}
if (mvcc_flags & OR_MVCC_FLAG_VALID_DELID)
{
or_advance (buf_p, OR_MVCCID_SIZE); /* skip DEL_ID */
}
if (mvcc_flags & OR_MVCC_FLAG_VALID_PREV_VERSION)
{
/* skip previous version lsa */
or_advance (buf_p, OR_MVCC_PREV_VERSION_LSA_SIZE);
}
if (bound_bits_flag)
{
size = OR_BOUND_BIT_BYTES (n_fixed);
bound_bits = (char *) malloc (size);
if (bound_bits == NULL)
{
error = ER_OUT_OF_VIRTUAL_MEMORY;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 1, (size_t) size);
goto error;
}
memset (bound_bits, 0, size);
}
/* get the offsets relative to the end of the header (beginning of variable table) */
vars = or_get_var_table_internal (buf_p, n_variable, catcls_unpack_allocator, offset_size);
if (vars == NULL)
{
error = ER_OUT_OF_VIRTUAL_MEMORY;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 1, n_variable * sizeof (OR_VARINFO));
goto error;
}
/* fixed */
start_p = buf_p->ptr;
/* read bound bits before accessing fixed attributes */
buf_p->ptr += repr_p->fixed_length;
if (bound_bits_flag)
{
or_get_data (buf_p, bound_bits, OR_BOUND_BIT_BYTES (n_fixed));
}
buf_p->ptr = start_p;
for (i = 0; i < n_fixed; i++)
{
data_type = fixed_p[i].type;
if (bound_bits_flag && OR_GET_BOUND_BIT (bound_bits, i))
{
(*tp_Type_id_map[data_type]).data_readval (buf_p, &attrs[i].value, NULL, -1, true, NULL, 0);
}
else
{
db_value_put_null (&attrs[i].value);
or_advance (buf_p, (*tp_Type_id_map[data_type]).disksize);
}
}
pad = (int) (buf_p->ptr - start_p);
if (pad < repr_p->fixed_length)
{
or_advance (buf_p, repr_p->fixed_length - pad);
}
else if (pad > repr_p->fixed_length)
{
error = ER_SM_CORRUPTED;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 0);
goto error;
}
/* bound bits */
if (bound_bits_flag)
{
or_advance (buf_p, OR_BOUND_BIT_BYTES (n_fixed));
}
/* variable */
var_attrs = &attrs[n_fixed];
for (i = 0; i < n_variable; i++)
{
data_type = variable_p[i].type;
(*tp_Type_id_map[data_type]).data_readval (buf_p, &var_attrs[i].value, NULL, vars[i].length, true, NULL, 0);
error = catcls_expand_or_value_by_subset (thread_p, &var_attrs[i]);
if (error != NO_ERROR)
{
goto error;
}
}
if (vars)
{
free_and_init (vars);
}
if (bound_bits)
{
free_and_init (bound_bits);
}
return NO_ERROR;
error:
if (vars)
{
free_and_init (vars);
}
if (bound_bits)
{
free_and_init (bound_bits);
}
return error;
}
/*
* catcls_put_or_value_into_record () -
* return:
* value(in):
* chn(in):
* record(in):
* class_oid(in):
*/
static int
catcls_put_or_value_into_record (THREAD_ENTRY * thread_p, OR_VALUE * value_p, int chn, RECDES * record_p,
OID * class_oid_p)
{
OR_BUF *buf_p, repr_buffer;
DISK_REPR *repr_p = NULL;
REPR_ID repr_id;
int error = NO_ERROR;
error = catalog_get_last_representation_id (thread_p, class_oid_p, &repr_id);
if (error != NO_ERROR)
{
return error;
}
else
{
repr_p = catalog_get_representation (thread_p, class_oid_p, repr_id, NULL);
if (repr_p == NULL)
{
assert (er_errid () != NO_ERROR);
error = er_errid ();
return error;
}
}
buf_p = &repr_buffer;
or_init (buf_p, record_p->data, record_p->length);
error = catcls_put_or_value_into_buffer (value_p, chn, buf_p, class_oid_p, repr_p);
if (error != NO_ERROR)
{
catalog_free_representation_and_init (repr_p);
return error;
}
record_p->length = (int) (buf_p->ptr - buf_p->buffer);
catalog_free_representation_and_init (repr_p);
return NO_ERROR;
}
/*
* catcls_get_or_value_from_class_record () -
* return:
* record(in):
*/
static OR_VALUE *
catcls_get_or_value_from_class_record (THREAD_ENTRY * thread_p, RECDES * record_p)
{
OR_VALUE *value_p = NULL;
OR_BUF *buf_p, repr_buffer;
value_p = catcls_allocate_or_value (1);
if (value_p == NULL)
{
return NULL;
}
assert (OR_GET_OFFSET_SIZE (record_p->data) == BIG_VAR_OFFSET_SIZE);
buf_p = &repr_buffer;
or_init (buf_p, record_p->data, record_p->length);
/* class record header does not contain MVCC info */
or_advance (buf_p, OR_NON_MVCC_HEADER_SIZE);
if (catcls_get_or_value_from_class (thread_p, buf_p, value_p) != NO_ERROR)
{
catcls_free_or_value (value_p);
return NULL;
}
return value_p;
}
/*
* catcls_get_or_value_from_record () -
* return:
* record(in):
* class_oid(in):
*/
static OR_VALUE *
catcls_get_or_value_from_record (THREAD_ENTRY * thread_p, RECDES * record_p, OID * class_oid_p)
{
OR_VALUE *value_p = NULL;
OR_BUF *buf_p, repr_buffer;
REPR_ID repr_id;
DISK_REPR *repr_p = NULL;
if (catalog_get_last_representation_id (thread_p, class_oid_p, &repr_id) != NO_ERROR)
{
goto error;
}
repr_p = catalog_get_representation (thread_p, class_oid_p, repr_id, NULL);
if (repr_p == NULL)
{
assert (er_errid () != NO_ERROR);
goto error;
}
value_p = catcls_allocate_or_value (1);
if (value_p == NULL)
{
goto error;
}
if (catcls_expand_or_value_by_repr (value_p, class_oid_p, repr_p) != NO_ERROR)
{
goto error;
}
buf_p = &repr_buffer;
or_init (buf_p, record_p->data, record_p->length);
if (catcls_get_or_value_from_buffer (thread_p, buf_p, value_p, repr_p) != NO_ERROR)
{
goto error;
}
catalog_free_representation_and_init (repr_p);
return value_p;
error:
if (value_p)
{
catcls_free_or_value (value_p);
}
if (repr_p)
{
catalog_free_representation_and_init (repr_p);
}
return NULL;
}
/*
* catcls_insert_subset () -
* return:
* value(in):
* root_oid(in):
*/
static int
catcls_insert_subset (THREAD_ENTRY * thread_p, OR_VALUE * value_p, OID * root_oid_p)
{
OR_VALUE *subset_p;
int n_subset;
OID *class_oid_p, oid;
CLS_INFO *cls_info_p = NULL;
HFID *hfid_p;
DB_SET *oid_set_p = NULL;
DB_VALUE oid_val;
int i;
HEAP_SCANCACHE scan;
bool is_scan_inited = false;
int error = NO_ERROR;
subset_p = value_p->sub.value;
n_subset = value_p->sub.count;
if (n_subset == 0)
{
return NO_ERROR;
}
oid_set_p = set_create_sequence (n_subset);
if (oid_set_p == NULL)
{
assert (er_errid () != NO_ERROR);
error = er_errid ();
goto error;
}
class_oid_p = &subset_p[0].id.classoid;
cls_info_p = catalog_get_class_info (thread_p, class_oid_p, NULL);
if (cls_info_p == NULL)
{
assert (er_errid () != NO_ERROR);
error = er_errid ();
goto error;
}
hfid_p = &cls_info_p->ci_hfid;
/* need to update assigned oid of each instance */
if (heap_scancache_start_modify (thread_p, &scan, hfid_p, class_oid_p, MULTI_ROW_UPDATE, NULL) != NO_ERROR)
{
assert (er_errid () != NO_ERROR);
error = er_errid ();
goto error;
}
is_scan_inited = true;
for (i = 0; i < n_subset; i++)
{
error = catcls_insert_instance (thread_p, &subset_p[i], &oid, root_oid_p, class_oid_p, hfid_p, &scan);
if (error != NO_ERROR)
{
goto error;
}
db_make_oid (&oid_val, &oid);
error = set_put_element (oid_set_p, i, &oid_val);
if (error != NO_ERROR)
{
goto error;
}
}
db_make_sequence (&value_p->value, oid_set_p);
heap_scancache_end_modify (thread_p, &scan);
catalog_free_class_info_and_init (cls_info_p);
return NO_ERROR;
error:
if (oid_set_p)
{
set_free (oid_set_p);
}
if (is_scan_inited)
{
heap_scancache_end_modify (thread_p, &scan);
}
if (cls_info_p)
{
catalog_free_class_info_and_init (cls_info_p);
}
return error;
}
/*
* catcls_delete_subset () -
* return:
* value(in):
*/
static int
catcls_delete_subset (THREAD_ENTRY * thread_p, OR_VALUE * value_p)
{
OR_VALUE *subset_p;
int n_subset;
OID *class_oid_p, *oid_p;
CLS_INFO *cls_info_p = NULL;
HFID *hfid_p;
DB_SET *oid_set_p;
DB_VALUE oid_val;
int i;
HEAP_SCANCACHE scan;
bool is_scan_inited = false;
int error = NO_ERROR;
subset_p = value_p->sub.value;
n_subset = value_p->sub.count;
if (n_subset == 0)
{
return NO_ERROR;
}
oid_set_p = db_get_set (&value_p->value);
class_oid_p = &subset_p[0].id.classoid;
cls_info_p = catalog_get_class_info (thread_p, class_oid_p, NULL);
if (cls_info_p == NULL)
{
assert (er_errid () != NO_ERROR);
error = er_errid ();
goto error;
}
hfid_p = &cls_info_p->ci_hfid;
if (heap_scancache_start_modify (thread_p, &scan, hfid_p, class_oid_p, MULTI_ROW_DELETE, NULL) != NO_ERROR)
{
assert (er_errid () != NO_ERROR);
error = er_errid ();
goto error;
}
is_scan_inited = true;
for (i = 0; i < n_subset; i++)
{
error = set_get_element (oid_set_p, i, &oid_val);
if (error != NO_ERROR)
{
goto error;
}
oid_p = db_get_oid (&oid_val);
error = catcls_delete_instance (thread_p, oid_p, class_oid_p, hfid_p, &scan);
if (error != NO_ERROR)
{
goto error;
}
}
heap_scancache_end_modify (thread_p, &scan);
catalog_free_class_info_and_init (cls_info_p);
return NO_ERROR;
error:
if (is_scan_inited)
{
heap_scancache_end_modify (thread_p, &scan);
}
if (cls_info_p)
{
catalog_free_class_info_and_init (cls_info_p);
}
return error;
}
/*
* catcls_insert_instance () -
* return:
* value(in):
* oid(in):
* root_oid(in):
* class_oid(in):
* hfid(in):
* scan(in):
*/
static int
catcls_insert_instance (THREAD_ENTRY * thread_p, OR_VALUE * value_p, OID * oid_p, OID * root_oid_p, OID * class_oid_p,
HFID * hfid_p, HEAP_SCANCACHE * scan_p)
{
HEAP_OPERATION_CONTEXT update_context;
RECDES record;
OR_VALUE *attrs;
OR_VALUE *subset_p, *attr_p;
int i, j, k;
bool is_lock_inited = false;
int error = NO_ERROR;
record.data = NULL;
if (heap_assign_address (thread_p, hfid_p, class_oid_p, oid_p, 0) != NO_ERROR)
{
assert (er_errid () != NO_ERROR);
error = er_errid ();
goto error;
}
is_lock_inited = true;
if (OID_ISNULL (root_oid_p))
{
COPY_OID (root_oid_p, oid_p);
}
if (OID_EQ (class_oid_p, &ct_Class.cc_classoid) || OID_EQ (class_oid_p, &ct_Index.cc_classoid))
{
catcls_set_or_value_timestamps (value_p);
}
for (attrs = value_p->sub.value, i = 0; i < value_p->sub.count; i++)
{
if (IS_SUBSET (attrs[i]))
{
/* set backward oid */
for (subset_p = attrs[i].sub.value, j = 0; j < attrs[i].sub.count; j++)
{
/* assume that the attribute values of xxx are ordered by { class_of, xxx_name, xxx_type, from_xxx_name,
* ... } */
attr_p = subset_p[j].sub.value;
db_make_oid (&attr_p[0].value, oid_p);
if (OID_EQ (class_oid_p, &ct_Class.cc_classoid))
{
/* if root node, eliminate self references */
for (k = 1; k < subset_p[j].sub.count; k++)
{
if (DB_VALUE_TYPE (&attr_p[k].value) == DB_TYPE_OID)
{
if (OID_EQ (oid_p, db_get_oid (&attr_p[k].value)))
{
db_value_put_null (&attr_p[k].value);
}
}
}
}
}
error = catcls_insert_subset (thread_p, &attrs[i], root_oid_p);
if (error != NO_ERROR)
{
goto error;
}
}
else if (DB_VALUE_DOMAIN_TYPE (&attrs[i].value) == DB_TYPE_VARIABLE)
{
/* set a self referenced oid */
db_make_oid (&attrs[i].value, root_oid_p);
}
}
error = catcls_reorder_attributes_by_repr (thread_p, value_p);
if (error != NO_ERROR)
{
goto error;
}
record.length = catcls_guess_record_length (value_p);
record.area_size = record.length;
record.type = REC_HOME;
record.data = (char *) malloc (record.length);
if (record.data == NULL)
{
error = ER_OUT_OF_VIRTUAL_MEMORY;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 1, (size_t) record.length);
goto error;
}
error = catcls_put_or_value_into_record (thread_p, value_p, 0, &record, class_oid_p);
if (error != NO_ERROR)
{
goto error;
}
/* for replication */
if (locator_add_or_remove_index (thread_p, &record, oid_p, class_oid_p, true, SINGLE_ROW_INSERT, scan_p, false, false,
hfid_p, NULL, false, false) != NO_ERROR)
{
assert (er_errid () != NO_ERROR);
error = er_errid ();
goto error;
}
heap_create_update_context (&update_context, hfid_p, oid_p, class_oid_p, &record, scan_p,
UPDATE_INPLACE_CURRENT_MVCCID);
if (heap_update_logical (thread_p, &update_context) != NO_ERROR)
{
error = er_errid ();
assert (error != NO_ERROR);
goto error;
}
free_and_init (record.data);
return NO_ERROR;
error:
if (record.data)
{
free_and_init (record.data);
}
return error;
}
/*
* catcls_delete_instance () -
* return:
* oid(in):
* class_oid(in):
* hfid(in):
* scan(in):
*/
static int
catcls_delete_instance (THREAD_ENTRY * thread_p, OID * oid_p, OID * class_oid_p, HFID * hfid_p, HEAP_SCANCACHE * scan_p)
{
HEAP_OPERATION_CONTEXT delete_context;
RECDES record = RECDES_INITIALIZER;
OR_VALUE *value_p = NULL;
OR_VALUE *attrs;
int i;
#if defined(SERVER_MODE)
bool is_lock_inited = false;
#endif /* SERVER_MODE */
int error = NO_ERROR;
assert (oid_p != NULL && class_oid_p != NULL && hfid_p != NULL && scan_p != NULL);
#if defined(SERVER_MODE)
if (lock_object (thread_p, oid_p, class_oid_p, X_LOCK, LK_UNCOND_LOCK) != LK_GRANTED)
{
assert (er_errid () != NO_ERROR);
error = er_errid ();
goto error;
}
is_lock_inited = true;
#endif /* SERVER_MODE */
if (heap_get_visible_version (thread_p, oid_p, class_oid_p, &record, scan_p, COPY, NULL_CHN) != S_SUCCESS)
{
assert (er_errid () != NO_ERROR);
error = er_errid ();
goto error;
}
value_p = catcls_get_or_value_from_record (thread_p, &record, class_oid_p);
if (value_p == NULL)
{
assert (er_errid () != NO_ERROR);
error = er_errid ();
goto error;
}
for (attrs = value_p->sub.value, i = 0; i < value_p->sub.count; i++)
{
if (IS_SUBSET (attrs[i]))
{
error = catcls_delete_subset (thread_p, &attrs[i]);
if (error != NO_ERROR)
{
goto error;
}
}
}
/* for replication */
if (locator_add_or_remove_index (thread_p, &record, oid_p, class_oid_p, false, SINGLE_ROW_DELETE, scan_p, false,
false, hfid_p, NULL, false, false) != NO_ERROR)
{
assert (er_errid () != NO_ERROR);
error = er_errid ();
goto error;
}
/* build operation context */
heap_create_delete_context (&delete_context, hfid_p, oid_p, class_oid_p, scan_p);
/* delete */
if (heap_delete_logical (thread_p, &delete_context) != NO_ERROR)
{
assert (er_errid () != NO_ERROR);
error = er_errid ();
goto error;
}
catcls_free_or_value (value_p);
return NO_ERROR;
error:
if (value_p)
{
catcls_free_or_value (value_p);
}
return error;
}
static void
catcls_set_or_value_timestamps (OR_VALUE * value_p)
{
DB_VALUE datetime_val;
DB_DATETIME *datetime;
int created_time_idx, updated_time_idx;
if (OID_EQ (&value_p->id.classoid, &ct_Class.cc_classoid))
{
created_time_idx = CT_CLASS_CREATED_TIME_INDEX;
updated_time_idx = CT_CLASS_UPDATED_TIME_INDEX;
}
else
{
/* OID_EQ(value_p->id.classoid, &ct_Index.cc_classoid) */
created_time_idx = CT_INDEX_CREATED_TIME_INDEX;
updated_time_idx = CT_INDEX_UPDATED_TIME_INDEX;
}
db_sys_datetime (&datetime_val);
datetime = db_get_datetime (&datetime_val);
db_make_datetime (&value_p->sub.value[created_time_idx].value, datetime);
db_make_datetime (&value_p->sub.value[updated_time_idx].value, datetime);
}
static void
catcls_copy_or_value_times_and_statistics (OR_VALUE * value_p, OR_VALUE * old_value_p)
{
int created_time_idx, updated_time_idx;
DB_DATETIME *created_time_dt = NULL;
DB_DATETIME *updated_time_dt = NULL;
OR_VALUE *new_value = value_p->sub.value;
OR_VALUE *old_value = old_value_p->sub.value;
if (OID_EQ (&value_p->id.classoid, &ct_Class.cc_classoid))
{
if (!db_value_is_null (&old_value[_gv_ct_Class_checked_time_idx].value) &&
!db_value_is_null (&old_value[_gv_ct_Class_statistics_strategy_idx].value))
{
db_make_datetime (&new_value[_gv_ct_Class_checked_time_idx].value,
db_get_datetime (&old_value[_gv_ct_Class_checked_time_idx].value));
db_make_int (&new_value[_gv_ct_Class_statistics_strategy_idx].value,
db_get_int (&old_value[_gv_ct_Class_statistics_strategy_idx].value));
}
created_time_idx = _gv_ct_Class_created_time_idx;
updated_time_idx = _gv_ct_Class_updated_time_idx;
}
else
{
/* OID_EQ(value_p->id.classoid, &ct_Index.cc_classoid) */
created_time_idx = _gv_ct_Index_created_time_idx;
updated_time_idx = _gv_ct_Index_updated_time_idx;
}
created_time_dt = db_get_datetime (&old_value[created_time_idx].value);
updated_time_dt = db_get_datetime (&old_value[updated_time_idx].value);
db_make_datetime (&new_value[created_time_idx].value, created_time_dt);
db_make_datetime (&new_value[updated_time_idx].value, updated_time_dt);
}
static void
catcls_update_or_value_updated_time (OR_VALUE * value_p)
{
int updated_time_idx = OID_EQ (&value_p->id.classoid, &ct_Class.cc_classoid) ?
_gv_ct_Class_updated_time_idx : _gv_ct_Index_updated_time_idx;
db_sys_datetime (&value_p->sub.value[updated_time_idx].value);
}
static void
catcls_update_or_value_class_stats_fields (OR_VALUE * value_p, unsigned int ci_time_stamp, bool with_fullscan)
{
DB_VALUE timestamp_val;
db_make_timestamp (×tamp_val, ci_time_stamp);
db_timestamp_to_datetime (×tamp_val, &value_p->sub.value[_gv_ct_Class_checked_time_idx].value);
db_make_int (&value_p->sub.value[_gv_ct_Class_statistics_strategy_idx].value, with_fullscan);
}
/*
* catcls_update_instance () -
* return:
* value(in):
* oid(in):
* class_oid(in):
* hfid(in):
* scan(in):
* force_in_place(in): UPDATE_INPLACE style
*/
static int
catcls_update_instance (THREAD_ENTRY * thread_p, OR_VALUE * value_p, OID * oid_p, OID * class_oid_p, HFID * hfid_p,
HEAP_SCANCACHE * scan_p, UPDATE_INPLACE_STYLE force_in_place)
{
RECDES record = RECDES_INITIALIZER, old_record = RECDES_INITIALIZER;
OR_VALUE *old_value_p = NULL;
OR_VALUE *attrs, *old_attrs;
OR_VALUE *subset_p, *attr_p;
int old_chn;
bool uflag = false;
int i, j, k;
int error = NO_ERROR;
if (heap_get_visible_version (thread_p, oid_p, class_oid_p, &old_record, scan_p, COPY, NULL_CHN) != S_SUCCESS)
{
assert (er_errid () != NO_ERROR);
error = er_errid ();
goto error;
}
old_chn = or_chn (&old_record);
old_value_p = catcls_get_or_value_from_record (thread_p, &old_record, class_oid_p);
if (old_value_p == NULL)
{
assert (er_errid () != NO_ERROR);
error = er_errid ();
goto error;
}
error = catcls_reorder_attributes_by_repr (thread_p, value_p);
if (error != NO_ERROR)
{
goto error;
}
if (OID_EQ (class_oid_p, &ct_Class.cc_classoid) || OID_EQ (class_oid_p, &ct_Index.cc_classoid))
{
catcls_copy_or_value_times_and_statistics (value_p, old_value_p);
}
/* update old_value */
for (attrs = value_p->sub.value, old_attrs = old_value_p->sub.value, i = 0; i < value_p->sub.count; i++)
{
if (IS_SUBSET (attrs[i]))
{
/* set backward oid */
for (subset_p = attrs[i].sub.value, j = 0; j < attrs[i].sub.count; j++)
{
/* assume that the attribute values of xxx are ordered by { class_of, xxx_name, xxx_type, from_xxx_name,
* ... } */
attr_p = subset_p[j].sub.value;
db_make_oid (&attr_p[0].value, oid_p);
if (OID_EQ (class_oid_p, &ct_Class.cc_classoid))
{
/* if root node, eliminate self references */
for (k = 1; k < subset_p[j].sub.count; k++)
{
if (DB_VALUE_TYPE (&attr_p[k].value) == DB_TYPE_OID)
{
if (OID_EQ (oid_p, db_get_oid (&attr_p[k].value)))
{
db_value_put_null (&attr_p[k].value);
}
}
}
}
}
error = catcls_update_subset (thread_p, &attrs[i], &old_attrs[i], &uflag, force_in_place);
if (error != NO_ERROR)
{
goto error;
}
}
else
{
if (tp_value_compare (&old_attrs[i].value, &attrs[i].value, 1, 1) != DB_EQ)
{
uflag = true;
}
}
}
if (uflag == true)
{
HEAP_OPERATION_CONTEXT update_context;
if (OID_EQ (class_oid_p, &ct_Class.cc_classoid) || OID_EQ (class_oid_p, &ct_Index.cc_classoid))
{
catcls_update_or_value_updated_time (value_p);
}
record.length = catcls_guess_record_length (value_p);
record.area_size = record.length;
record.type = REC_HOME;
record.data = (char *) malloc (record.length);
if (record.data == NULL)
{
error = ER_OUT_OF_VIRTUAL_MEMORY;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 1, (size_t) record.length);
goto error;
}
error = catcls_put_or_value_into_record (thread_p, value_p, old_chn + 1, &record, class_oid_p);
if (error != NO_ERROR)
{
goto error;
}
/* give up setting updated attr info */
if (locator_update_index (thread_p, &record, &old_record, NULL, 0, oid_p, class_oid_p, SINGLE_ROW_UPDATE,
scan_p, NULL) != NO_ERROR)
{
assert (er_errid () != NO_ERROR);
error = er_errid ();
goto error;
}
/* update in place */
heap_create_update_context (&update_context, hfid_p, oid_p, class_oid_p, &record, scan_p, force_in_place);
if (heap_update_logical (thread_p, &update_context) != NO_ERROR)
{
assert (er_errid () != NO_ERROR);
error = er_errid ();
goto error;
}
free_and_init (record.data);
}
catcls_free_or_value (old_value_p);
return NO_ERROR;
error:
if (record.data)
{
free_and_init (record.data);
}
if (old_value_p)
{
catcls_free_or_value (old_value_p);
}
return error;
}
/*
* catcls_insert_catalog_classes () -
* return:
* record(in):
*/
int
catcls_insert_catalog_classes (THREAD_ENTRY * thread_p, RECDES * record_p)
{
OR_VALUE *value_p = NULL;
OID oid, *class_oid_p;
OID root_oid = { NULL_PAGEID, NULL_SLOTID, NULL_VOLID };
CLS_INFO *cls_info_p = NULL;
HFID *hfid_p;
HEAP_SCANCACHE scan;
bool is_scan_inited = false;
value_p = catcls_get_or_value_from_class_record (thread_p, record_p);
if (value_p == NULL)
{
goto error;
}
class_oid_p = &ct_Class.cc_classoid;
cls_info_p = catalog_get_class_info (thread_p, class_oid_p, NULL);
if (cls_info_p == NULL)
{
goto error;
}
hfid_p = &cls_info_p->ci_hfid;
if (heap_scancache_start_modify (thread_p, &scan, hfid_p, class_oid_p, SINGLE_ROW_UPDATE, NULL) != NO_ERROR)
{
goto error;
}
is_scan_inited = true;
if (catcls_insert_instance (thread_p, value_p, &oid, &root_oid, class_oid_p, hfid_p, &scan) != NO_ERROR)
{
goto error;
}
heap_scancache_end_modify (thread_p, &scan);
catalog_free_class_info_and_init (cls_info_p);
catcls_free_or_value (value_p);
return NO_ERROR;
error:
if (is_scan_inited)
{
heap_scancache_end_modify (thread_p, &scan);
}
if (cls_info_p)
{
catalog_free_class_info_and_init (cls_info_p);
}
if (value_p)
{
catcls_free_or_value (value_p);
}
return ER_FAILED;
}
/*
* catcls_delete_catalog_classes () -
* return:
* name(in):
* class_oid(in):
*/
int
catcls_delete_catalog_classes (THREAD_ENTRY * thread_p, const char *name_p, OID * class_oid_p)
{
OID oid, *ct_class_oid_p;
CLS_INFO *cls_info_p = NULL;
HFID *hfid_p;
HEAP_SCANCACHE scan;
bool is_scan_inited = false;
if (catcls_find_oid_by_class_name (thread_p, name_p, &oid) != NO_ERROR)
{
goto error;
}
if (OID_ISNULL (&oid))
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_LC_UNKNOWN_CLASSNAME, 1, name_p);
goto error;
}
ct_class_oid_p = &ct_Class.cc_classoid;
cls_info_p = catalog_get_class_info (thread_p, ct_class_oid_p, NULL);
if (cls_info_p == NULL)
{
goto error;
}
hfid_p = &cls_info_p->ci_hfid;
/* in MVCC, do not physically remove the row */
if (heap_scancache_start_modify (thread_p, &scan, hfid_p, ct_class_oid_p, SINGLE_ROW_DELETE, NULL) != NO_ERROR)
{
goto error;
}
is_scan_inited = true;
if (catcls_delete_instance (thread_p, &oid, ct_class_oid_p, hfid_p, &scan) != NO_ERROR)
{
goto error;
}
if (csect_enter (thread_p, CSECT_CT_OID_TABLE, INF_WAIT) != NO_ERROR)
{
goto error;
}
if (catcls_remove_entry (thread_p, class_oid_p) != NO_ERROR)
{
csect_exit (thread_p, CSECT_CT_OID_TABLE);
goto error;
}
csect_exit (thread_p, CSECT_CT_OID_TABLE);
heap_scancache_end_modify (thread_p, &scan);
catalog_free_class_info_and_init (cls_info_p);
return NO_ERROR;
error:
if (is_scan_inited)
{
heap_scancache_end_modify (thread_p, &scan);
}
if (cls_info_p)
{
catalog_free_class_info_and_init (cls_info_p);
}
return ER_FAILED;
}
int
catcls_update_class_stats (THREAD_ENTRY * thread_p, const char *class_name, unsigned int ci_time_stamp,
bool with_fullscan)
{
int error = NO_ERROR;
OID oid;
OID *catalog_class_oid_p = NULL;
CLS_INFO *cls_info_p = NULL;
HFID *hfid_p = NULL;
HEAP_SCANCACHE scan;
bool is_scan_inited = false;
int old_chn;
OR_VALUE *value_p = NULL;
RECDES record = RECDES_INITIALIZER;
HEAP_OPERATION_CONTEXT update_context;
error = catcls_find_oid_by_class_name (thread_p, class_name, &oid);
if (error != NO_ERROR)
{
goto error;
}
catalog_class_oid_p = &ct_Class.cc_classoid;
cls_info_p = catalog_get_class_info (thread_p, catalog_class_oid_p, NULL);
if (cls_info_p == NULL)
{
goto error;
}
hfid_p = &cls_info_p->ci_hfid;
if (heap_scancache_start_modify (thread_p, &scan, hfid_p, catalog_class_oid_p, SINGLE_ROW_UPDATE, NULL) != NO_ERROR)
{
goto error;
}
is_scan_inited = true;
if (heap_get_visible_version (thread_p, &oid, catalog_class_oid_p, &record, &scan, COPY, NULL_CHN) != S_SUCCESS)
{
ASSERT_ERROR_AND_SET (error);
goto error;
}
old_chn = or_chn (&record);
value_p = catcls_get_or_value_from_record (thread_p, &record, catalog_class_oid_p);
if (value_p == NULL)
{
ASSERT_ERROR_AND_SET (error);
goto error;
}
catcls_update_or_value_class_stats_fields (value_p, ci_time_stamp, with_fullscan);
record.length = catcls_guess_record_length (value_p);
record.area_size = record.length;
record.type = REC_HOME;
record.data = (char *) malloc (record.length);
if (record.data == NULL)
{
error = ER_OUT_OF_VIRTUAL_MEMORY;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 1, (size_t) record.length);
goto error;
}
error = catcls_put_or_value_into_record (thread_p, value_p, old_chn + 1, &record, catalog_class_oid_p);
if (error != NO_ERROR)
{
goto error;
}
if (locator_update_index (thread_p, &record, &record, NULL, 0, &oid, catalog_class_oid_p, SINGLE_ROW_UPDATE,
&scan, NULL) != NO_ERROR)
{
ASSERT_ERROR_AND_SET (error);
goto error;
}
heap_create_update_context (&update_context, hfid_p, &oid, catalog_class_oid_p, &record, &scan, UPDATE_INPLACE_NONE);
if (heap_update_logical (thread_p, &update_context) != NO_ERROR)
{
ASSERT_ERROR_AND_SET (error);
goto error;
}
error:
if (record.data)
{
free_and_init (record.data);
}
if (value_p)
{
catcls_free_or_value (value_p);
}
if (is_scan_inited)
{
heap_scancache_end_modify (thread_p, &scan);
}
if (cls_info_p)
{
catalog_free_class_info_and_init (cls_info_p);
}
return error;
}
/*
* catcls_update_catalog_classes () -
* return:
* name(in):
* record(in):
* class_oid_p(in): class OID
* force_in_place(in): if UPDATE_INPLACE_NONE then the 'in place' will not be forced
* and the update style will be decided in this function.
* Otherwise the update of the instance will be made in
* place and according to provided style.
*/
int
catcls_update_catalog_classes (THREAD_ENTRY * thread_p, const char *name_p, RECDES * record_p, OID * class_oid_p,
UPDATE_INPLACE_STYLE force_in_place)
{
OR_VALUE *value_p = NULL;
OID oid, *catalog_class_oid_p;
CLS_INFO *cls_info_p = NULL;
HFID *hfid_p;
HEAP_SCANCACHE scan;
bool is_scan_inited = false;
if (catcls_find_oid_by_class_name (thread_p, name_p, &oid) != NO_ERROR)
{
goto error;
}
if (OID_ISNULL (&oid))
{
return (catcls_insert_catalog_classes (thread_p, record_p));
}
value_p = catcls_get_or_value_from_class_record (thread_p, record_p);
if (value_p == NULL)
{
goto error;
}
catalog_class_oid_p = &ct_Class.cc_classoid;
cls_info_p = catalog_get_class_info (thread_p, catalog_class_oid_p, NULL);
if (cls_info_p == NULL)
{
goto error;
}
hfid_p = &cls_info_p->ci_hfid;
if (heap_scancache_start_modify (thread_p, &scan, hfid_p, catalog_class_oid_p, SINGLE_ROW_UPDATE, NULL) != NO_ERROR)
{
goto error;
}
is_scan_inited = true;
/* update catalog classes */
if (catcls_update_instance (thread_p, value_p, &oid, catalog_class_oid_p, hfid_p, &scan, force_in_place) != NO_ERROR)
{
goto error;
}
heap_scancache_end_modify (thread_p, &scan);
catalog_free_class_info_and_init (cls_info_p);
catcls_free_or_value (value_p);
return NO_ERROR;
error:
if (is_scan_inited)
{
heap_scancache_end_modify (thread_p, &scan);
}
if (cls_info_p)
{
catalog_free_class_info_and_init (cls_info_p);
}
if (value_p)
{
catcls_free_or_value (value_p);
}
return ER_FAILED;
}
static int
catcls_cache_fixed_attr_indexes (THREAD_ENTRY * thread_p)
{
OID *ct_Class_oid_p = &ct_Class.cc_classoid;
OID *ct_Index_oid_p = &ct_Index.cc_classoid;
int error = NO_ERROR;
REPR_ID ct_Class_repr_id, ct_Index_repr_id;
DISK_REPR *ct_Class_repr_p = NULL;
DISK_REPR *ct_Index_repr_p = NULL;
DISK_ATTR *ct_Class_fixed_p = NULL;
DISK_ATTR *ct_Index_fixed_p = NULL;
error = catalog_get_last_representation_id (thread_p, ct_Class_oid_p, &ct_Class_repr_id);
if (error != NO_ERROR)
{
goto end;
}
ct_Class_repr_p = catalog_get_representation (thread_p, ct_Class_oid_p, ct_Class_repr_id, NULL);
if (ct_Class_repr_p == NULL)
{
ASSERT_ERROR_AND_SET (error);
goto end;
}
ct_Class_fixed_p = ct_Class_repr_p->fixed;
for (int i = 0; i < ct_Class_repr_p->n_fixed; i++)
{
if (ct_Class_fixed_p[i].id == ct_Class.cc_atts[CT_CLASS_CREATED_TIME_INDEX].ca_id)
{
_gv_ct_Class_created_time_idx = i;
}
else if (ct_Class_fixed_p[i].id == ct_Class.cc_atts[CT_CLASS_UPDATED_TIME_INDEX].ca_id)
{
_gv_ct_Class_updated_time_idx = i;
}
else if (ct_Class_fixed_p[i].id == ct_Class.cc_atts[CT_CLASS_CHECKED_TIME_INDEX].ca_id)
{
_gv_ct_Class_checked_time_idx = i;
}
else if (ct_Class_fixed_p[i].id == ct_Class.cc_atts[CT_CLASS_STATISTICS_STRATEGY_INDEX].ca_id)
{
_gv_ct_Class_statistics_strategy_idx = i;
}
}
assert (_gv_ct_Class_created_time_idx != -1);
assert (_gv_ct_Class_updated_time_idx != -1);
assert (_gv_ct_Class_checked_time_idx != -1);
assert (_gv_ct_Class_statistics_strategy_idx != -1);
error = catalog_get_last_representation_id (thread_p, ct_Index_oid_p, &ct_Index_repr_id);
if (error != NO_ERROR)
{
goto end;
}
ct_Index_repr_p = catalog_get_representation (thread_p, ct_Index_oid_p, ct_Index_repr_id, NULL);
if (ct_Index_repr_p == NULL)
{
ASSERT_ERROR_AND_SET (error);
goto end;
}
ct_Index_fixed_p = ct_Index_repr_p->fixed;
for (int i = 0; i < ct_Index_repr_p->n_fixed; i++)
{
if (ct_Index_fixed_p[i].id == ct_Index.cc_atts[CT_INDEX_CREATED_TIME_INDEX].ca_id)
{
_gv_ct_Index_created_time_idx = i;
}
else if (ct_Index_fixed_p[i].id == ct_Index.cc_atts[CT_INDEX_UPDATED_TIME_INDEX].ca_id)
{
_gv_ct_Index_updated_time_idx = i;
}
}
assert (_gv_ct_Index_created_time_idx != -1);
assert (_gv_ct_Index_updated_time_idx != -1);
end:
catalog_free_representation_and_init (ct_Class_repr_p);
catalog_free_representation_and_init (ct_Index_repr_p);
return error;
}
/*
* catcls_compile_catalog_classes () -
* return:
* void(in):
*/
int
catcls_compile_catalog_classes (THREAD_ENTRY * thread_p)
{
RECDES class_record;
OID *class_oid_p, tmp_oid;
const char *class_name_p;
char *attr_name_p;
CT_ATTR *atts;
int n_atts;
int c, a, i;
HEAP_SCANCACHE scan;
int alloced_string = 0;
int error = NO_ERROR;
if (thread_p == NULL)
{
// because SA_MODE client calls this directly with NULL argument...
thread_p = thread_get_thread_entry_info ();
}
/* check if an old version database */
if (catcls_find_class_oid_by_class_name (thread_p, CT_CLASS_NAME, &tmp_oid) != NO_ERROR)
{
return ER_FAILED;
}
else if (OID_ISNULL (&tmp_oid))
{
/* no catalog classes */
return NO_ERROR;
}
/* fill classoid and attribute ids for each meta catalog classes */
for (c = 0; ct_Classes[c] != NULL; c++)
{
class_name_p = ct_Classes[c]->cc_name;
class_oid_p = &ct_Classes[c]->cc_classoid;
if (catcls_find_class_oid_by_class_name (thread_p, class_name_p, class_oid_p) != NO_ERROR)
{
return ER_FAILED;
}
atts = ct_Classes[c]->cc_atts;
n_atts = ct_Classes[c]->cc_n_atts;
if (heap_scancache_quick_start_root_hfid (thread_p, &scan) != NO_ERROR)
{
return ER_FAILED;
}
if (heap_get_class_record (thread_p, class_oid_p, &class_record, &scan, PEEK) != S_SUCCESS)
{
(void) heap_scancache_end (thread_p, &scan);
return ER_FAILED;
}
for (i = 0; i < n_atts; i++)
{
alloced_string = 0;
error = or_get_attrname (&class_record, i, &attr_name_p, &alloced_string);
if (error != NO_ERROR || attr_name_p == NULL)
{
ASSERT_ERROR ();
(void) heap_scancache_end (thread_p, &scan);
return ER_FAILED;
}
for (a = 0; a < n_atts; a++)
{
if (strcmp (atts[a].ca_name, attr_name_p) == 0)
{
atts[a].ca_id = i;
break;
}
}
if (attr_name_p != NULL && alloced_string == 1)
{
db_private_free_and_init (thread_p, attr_name_p);
}
if (a == n_atts)
{
assert (false);
(void) heap_scancache_end (thread_p, &scan);
return ER_FAILED;
}
}
if (heap_scancache_end (thread_p, &scan) != NO_ERROR)
{
return ER_FAILED;
}
}
catcls_Enable = true;
if (catcls_find_btid_of_class_name (thread_p, &catcls_Btid) != NO_ERROR)
{
return ER_FAILED;
}
if (catcls_initialize_class_oid_to_oid_hash_table (thread_p, CATCLS_OID_TABLE_SIZE) != NO_ERROR)
{
return ER_FAILED;
}
error = catcls_cache_fixed_attr_indexes (thread_p);
if (error != NO_ERROR)
{
return error;
}
return NO_ERROR;
}
/*
* catcls_get_server_compat_info () - get the language id, charset id and
* timezone checksum stored in the
* "db_root" system table
* return: NO_ERROR, or error code
* thread_p(in) : thread context
* charset_id_p(out):
* lang_buf(in/out): buffer language string
* lang_buf_size(in): size of buffer language string
* timezone_checksum(out): timezone_checksum
* Note : This function is called during server initialization, for this
* reason, no locks are required on the class.
*/
int
catcls_get_server_compat_info (THREAD_ENTRY * thread_p, INTL_CODESET * charset_id_p, char *lang_buf,
const int lang_buf_size, char *timezone_checksum)
{
OID class_oid;
OID inst_oid;
HFID hfid;
HEAP_CACHE_ATTRINFO attr_info;
HEAP_SCANCACHE scan_cache;
RECDES recdes;
const char *class_name = "db_root";
int charset_att_id = -1, lang_att_id = -1;
int timezone_id = -1;
int i;
int error = NO_ERROR;
bool scan_cache_inited = false;
bool attr_info_inited = false;
assert (charset_id_p != NULL);
assert (lang_buf != NULL);
assert (timezone_checksum != NULL);
OID_SET_NULL (&class_oid);
OID_SET_NULL (&inst_oid);
error = catcls_find_class_oid_by_class_name (thread_p, class_name, &class_oid);
if (error != NO_ERROR)
{
goto exit;
}
if (OID_ISNULL (&class_oid))
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_LC_UNKNOWN_CLASSNAME, 1, class_name);
error = ER_LC_UNKNOWN_CLASSNAME;
goto exit;
}
error = heap_attrinfo_start (thread_p, &class_oid, -1, NULL, &attr_info);
if (error != NO_ERROR)
{
goto exit;
}
attr_info_inited = true;
(void) heap_scancache_quick_start_root_hfid (thread_p, &scan_cache);
scan_cache_inited = true;
if (heap_get_class_record (thread_p, &class_oid, &recdes, &scan_cache, PEEK) != S_SUCCESS)
{
error = ER_FAILED;
goto exit;
}
for (i = 0; i < attr_info.num_values; i++)
{
char *rec_attr_name_p, *string = NULL;
int alloced_string = 0;
bool set_break = false;
error = or_get_attrname (&recdes, i, &string, &alloced_string);
if (error != NO_ERROR)
{
ASSERT_ERROR ();
goto exit;
}
rec_attr_name_p = string;
if (rec_attr_name_p == NULL)
{
error = ER_FAILED;
goto exit;
}
if (strcmp ("charset", rec_attr_name_p) == 0)
{
charset_att_id = i;
if (lang_att_id != -1)
{
set_break = true;
goto clean_string;
}
}
if (strcmp ("lang", rec_attr_name_p) == 0)
{
lang_att_id = i;
if (charset_att_id != -1)
{
set_break = true;
goto clean_string;
}
}
if (strcmp ("timezone_checksum", rec_attr_name_p) == 0)
{
timezone_id = i;
}
clean_string:
if (string != NULL && alloced_string == 1)
{
db_private_free_and_init (thread_p, string);
}
if (set_break == true)
{
break;
}
}
if (charset_att_id == -1 || lang_att_id == -1 || timezone_id == -1)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_GENERIC_ERROR, 0);
error = ER_FAILED;
goto exit;
}
(void) heap_scancache_end (thread_p, &scan_cache);
scan_cache_inited = false;
/* read values of the single record in heap */
error = heap_get_class_info (thread_p, &class_oid, &hfid, NULL, NULL);
if (error != NO_ERROR || HFID_IS_NULL (&hfid))
{
error = ER_FAILED;
goto exit;
}
error = heap_scancache_start (thread_p, &scan_cache, &hfid, NULL, true, NULL);
if (error != NO_ERROR)
{
goto exit;
}
scan_cache_inited = true;
while (heap_next (thread_p, &hfid, NULL, &inst_oid, &recdes, &scan_cache, PEEK) == S_SUCCESS)
{
HEAP_ATTRVALUE *heap_value = NULL;
if (heap_attrinfo_read_dbvalues (thread_p, &inst_oid, &recdes, &attr_info) != NO_ERROR)
{
error = ER_FAILED;
goto exit;
}
for (i = 0, heap_value = attr_info.values; i < attr_info.num_values; i++, heap_value++)
{
if (heap_value->attrid == charset_att_id)
{
if (DB_IS_NULL (&heap_value->dbvalue))
{
error = ER_FAILED;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_GENERIC_ERROR, 0);
goto exit;
}
assert (DB_VALUE_DOMAIN_TYPE (&(heap_value->dbvalue)) == DB_TYPE_INTEGER);
*charset_id_p = (INTL_CODESET) db_get_int (&heap_value->dbvalue);
}
else if (heap_value->attrid == lang_att_id)
{
const char *lang_str = NULL;
size_t lang_str_len;
if (DB_IS_NULL (&heap_value->dbvalue))
{
error = ER_FAILED;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_GENERIC_ERROR, 0);
goto exit;
}
assert (DB_VALUE_DOMAIN_TYPE (&(heap_value->dbvalue)) == DB_TYPE_STRING);
lang_str = db_get_string (&heap_value->dbvalue);
lang_str_len = (lang_str != NULL) ? strlen (lang_str) : 0;
assert ((int) lang_str_len < lang_buf_size);
if (lang_str_len > 0)
{
/* Copying length 0 from NULL pointer fails when DUMA is enabled. */
assert (lang_str != NULL);
assert (lang_buf_size > 0);
memcpy (lang_buf, lang_str, MIN (lang_str_len, lang_buf_size));
}
lang_buf[MIN (lang_str_len, lang_buf_size)] = '\0';
}
else if (heap_value->attrid == timezone_id)
{
const char *checksum = NULL;
size_t checksum_len;
if (DB_IS_NULL (&heap_value->dbvalue))
{
error = ER_FAILED;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_GENERIC_ERROR, 0);
goto exit;
}
assert (DB_VALUE_DOMAIN_TYPE (&(heap_value->dbvalue)) == DB_TYPE_STRING);
checksum = db_get_string (&heap_value->dbvalue);
checksum_len = (checksum != NULL) ? strlen (checksum) : 0;
assert (checksum_len <= TZ_CHECKSUM_SIZE);
if (checksum_len > 0)
{
/* Copying length 0 from NULL pointer fails when DUMA is enabled. */
assert (checksum != NULL);
strcpy (timezone_checksum, checksum);
}
timezone_checksum[checksum_len] = '\0';
}
}
}
exit:
if (scan_cache_inited == true)
{
(void) heap_scancache_end (thread_p, &scan_cache);
scan_cache_inited = false;
}
if (attr_info_inited == true)
{
heap_attrinfo_end (thread_p, &attr_info);
attr_info_inited = false;
}
return error;
}
/*
* catcls_update_subset () - Update catalog class subset
* return:
* thread_p(in): thred entry
* value(in): new values
* old_value_p(in): old values
* uflag(in): update necessary flag
* force_in_place(in): UPDATE_INPLACE style
*/
static int
catcls_update_subset (THREAD_ENTRY * thread_p, OR_VALUE * value_p, OR_VALUE * old_value_p, bool * uflag,
UPDATE_INPLACE_STYLE force_in_place)
{
OR_VALUE *subset_p = NULL, *old_subset_p = NULL;
DB_SET *oid_set_p = NULL;
int n_subset, n_old_subset;
int n_min_subset;
OID *class_oid_p = NULL;
CLS_INFO *cls_info_p = NULL;
HFID *hfid_p = NULL;
OID *oid_p = NULL, tmp_oid;
DB_SET *old_oid_set_p = NULL;
DB_VALUE oid_val;
int i;
HEAP_SCANCACHE scan;
bool is_scan_inited = false;
int error = NO_ERROR;
old_subset_p = old_value_p->sub.value;
n_old_subset = old_value_p->sub.count;
if (n_old_subset < 0)
{
n_old_subset = 0;
}
subset_p = value_p->sub.value;
n_subset = value_p->sub.count;
if (n_subset < 0)
{
n_subset = 0;
}
if (subset_p != NULL)
{
class_oid_p = &subset_p[0].id.classoid;
}
else if (old_subset_p != NULL)
{
class_oid_p = &old_subset_p[0].id.classoid;
}
else
{
return NO_ERROR;
}
if (n_subset > 0)
{
/* get the OIDs set */
if (DB_IS_NULL (&value_p->value))
{
oid_set_p = set_create_sequence (n_subset);
if (oid_set_p == NULL)
{
error = er_errid ();
goto error;
}
}
else
{
oid_set_p = db_get_set (&value_p->value);
}
}
if (n_old_subset > 0)
{
old_oid_set_p = db_get_set (&old_value_p->value);
}
cls_info_p = catalog_get_class_info (thread_p, class_oid_p, NULL);
if (cls_info_p == NULL)
{
error = er_errid ();
goto error;
}
hfid_p = &cls_info_p->ci_hfid;
error = heap_scancache_start_modify (thread_p, &scan, hfid_p, class_oid_p, MULTI_ROW_UPDATE, NULL);
if (error != NO_ERROR)
{
goto error;
}
is_scan_inited = true;
n_min_subset = (n_subset > n_old_subset) ? n_old_subset : n_subset;
/* update components */
for (i = 0; i < n_min_subset; i++)
{
error = set_get_element (old_oid_set_p, i, &oid_val);
if (error != NO_ERROR)
{
goto error;
}
if (DB_VALUE_TYPE (&oid_val) != DB_TYPE_OID)
{
error = ER_FAILED;
goto error;
}
oid_p = db_get_oid (&oid_val);
error = catcls_update_instance (thread_p, &subset_p[i], oid_p, class_oid_p, hfid_p, &scan, force_in_place);
if (error != NO_ERROR)
{
goto error;
}
/* oid_p remains the same, but it has to be reinserted in set; set_get_element don't let the value unchanged */
db_make_oid (&oid_val, oid_p);
error = set_put_element (oid_set_p, i, &oid_val);
if (error != NO_ERROR)
{
goto error;
}
}
/* drop components */
if (n_old_subset > n_subset)
{
for (i = n_old_subset - 1; i >= n_min_subset; i--)
{
error = set_get_element (old_oid_set_p, i, &oid_val);
if (error != NO_ERROR)
{
goto error;
}
if (DB_VALUE_TYPE (&oid_val) != DB_TYPE_OID)
{
error = ER_FAILED;
goto error;
}
/* logical deletion - keep OID in sequence */
oid_p = db_get_oid (&oid_val);
error = catcls_delete_instance (thread_p, oid_p, class_oid_p, hfid_p, &scan);
if (error != NO_ERROR)
{
goto error;
}
}
*uflag = true;
}
/* add components */
else if (n_old_subset < n_subset)
{
OID root_oid = { NULL_PAGEID, NULL_SLOTID, NULL_VOLID };
for (i = n_min_subset, oid_p = &tmp_oid; i < n_subset; i++)
{
error = catcls_insert_instance (thread_p, &subset_p[i], oid_p, &root_oid, class_oid_p, hfid_p, &scan);
if (error != NO_ERROR)
{
goto error;
}
db_make_oid (&oid_val, oid_p);
error = set_put_element (oid_set_p, i, &oid_val);
if (error != NO_ERROR)
{
goto error;
}
}
*uflag = true;
}
if (DB_IS_NULL (&value_p->value))
{
db_make_sequence (&value_p->value, oid_set_p);
}
heap_scancache_end_modify (thread_p, &scan);
catalog_free_class_info_and_init (cls_info_p);
return NO_ERROR;
error:
if (oid_set_p && DB_IS_NULL (&value_p->value))
{
set_free (oid_set_p);
}
if (is_scan_inited)
{
heap_scancache_end_modify (thread_p, &scan);
}
if (cls_info_p)
{
catalog_free_class_info_and_init (cls_info_p);
}
assert (error != NO_ERROR);
return error;
}
/*
* catcls_get_db_collation () - get infomation on all collation in DB
* stored in the "_db_collation" system table
*
* return: NO_ERROR, or error code
* thread_p(in) : thread context
* db_collations(out): array of collation info
* coll_cnt(out): number of collations found in DB
*
* Note : This function is called during server initialization, for this
* reason, no locks are required on the class.
*/
int
catcls_get_db_collation (THREAD_ENTRY * thread_p, LANG_COLL_COMPAT ** db_collations, int *coll_cnt)
{
OID class_oid;
OID inst_oid;
HFID hfid;
HEAP_CACHE_ATTRINFO attr_info;
HEAP_SCANCACHE scan_cache;
RECDES recdes;
const char *class_name = "_db_collation";
int i;
int error = NO_ERROR;
int att_id_cnt = 0;
int max_coll_cnt;
int coll_id_att_id = -1, coll_name_att_id = -1, charset_id_att_id = -1, checksum_att_id = -1;
int alloc_size;
bool attr_info_inited = false;
bool scan_cache_inited = false;
assert (db_collations != NULL);
assert (coll_cnt != NULL);
OID_SET_NULL (&class_oid);
OID_SET_NULL (&inst_oid);
error = catcls_find_class_oid_by_class_name (thread_p, class_name, &class_oid);
if (error != NO_ERROR)
{
goto exit;
}
if (OID_ISNULL (&class_oid))
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_LC_UNKNOWN_CLASSNAME, 1, class_name);
error = ER_LC_UNKNOWN_CLASSNAME;
goto exit;
}
error = heap_attrinfo_start (thread_p, &class_oid, -1, NULL, &attr_info);
if (error != NO_ERROR)
{
goto exit;
}
attr_info_inited = true;
(void) heap_scancache_quick_start_root_hfid (thread_p, &scan_cache);
scan_cache_inited = true;
if (heap_get_class_record (thread_p, &class_oid, &recdes, &scan_cache, PEEK) != S_SUCCESS)
{
error = ER_FAILED;
goto exit;
}
for (i = 0; i < attr_info.num_values; i++)
{
char *rec_attr_name_p, *string = NULL;
int alloced_string = 0;
error = or_get_attrname (&recdes, i, &string, &alloced_string);
if (error != NO_ERROR)
{
ASSERT_ERROR ();
goto exit;
}
rec_attr_name_p = string;
if (rec_attr_name_p == NULL)
{
error = ER_FAILED;
goto exit;
}
if (strcmp (CT_DBCOLL_COLL_ID_COLUMN, rec_attr_name_p) == 0)
{
coll_id_att_id = i;
att_id_cnt++;
}
else if (strcmp (CT_DBCOLL_COLL_NAME_COLUMN, rec_attr_name_p) == 0)
{
coll_name_att_id = i;
att_id_cnt++;
}
else if (strcmp (CT_DBCOLL_CHARSET_ID_COLUMN, rec_attr_name_p) == 0)
{
charset_id_att_id = i;
att_id_cnt++;
}
else if (strcmp (CT_DBCOLL_CHECKSUM_COLUMN, rec_attr_name_p) == 0)
{
checksum_att_id = i;
att_id_cnt++;
}
if (string != NULL && alloced_string == 1)
{
db_private_free_and_init (thread_p, string);
}
if (att_id_cnt >= 4)
{
break;
}
}
if (att_id_cnt != 4)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_GENERIC_ERROR, 0);
error = ER_FAILED;
goto exit;
}
(void) heap_scancache_end (thread_p, &scan_cache);
scan_cache_inited = false;
/* read values of all records in heap */
error = heap_get_class_info (thread_p, &class_oid, &hfid, NULL, NULL);
if (error != NO_ERROR || HFID_IS_NULL (&hfid))
{
error = ER_FAILED;
goto exit;
}
error = heap_scancache_start (thread_p, &scan_cache, &hfid, NULL, true, NULL);
if (error != NO_ERROR)
{
goto exit;
}
scan_cache_inited = true;
max_coll_cnt = LANG_MAX_COLLATIONS;
alloc_size = max_coll_cnt * sizeof (LANG_COLL_COMPAT);
*db_collations = (LANG_COLL_COMPAT *) db_private_alloc (thread_p, alloc_size);
if (*db_collations == NULL)
{
error = ER_OUT_OF_VIRTUAL_MEMORY;
goto exit;
}
*coll_cnt = 0;
while (heap_next (thread_p, &hfid, NULL, &inst_oid, &recdes, &scan_cache, PEEK) == S_SUCCESS)
{
HEAP_ATTRVALUE *heap_value = NULL;
LANG_COLL_COMPAT *curr_coll;
if (heap_attrinfo_read_dbvalues (thread_p, &inst_oid, &recdes, &attr_info) != NO_ERROR)
{
error = ER_FAILED;
goto exit;
}
if (*coll_cnt >= max_coll_cnt)
{
max_coll_cnt = max_coll_cnt * 2;
alloc_size = max_coll_cnt * sizeof (LANG_COLL_COMPAT);
*db_collations = (LANG_COLL_COMPAT *) db_private_realloc (thread_p, *db_collations, alloc_size);
if (db_collations == NULL)
{
error = ER_OUT_OF_VIRTUAL_MEMORY;
goto exit;
}
}
curr_coll = &((*db_collations)[(*coll_cnt)++]);
memset (curr_coll, 0, sizeof (LANG_COLL_COMPAT));
for (i = 0, heap_value = attr_info.values; i < attr_info.num_values; i++, heap_value++)
{
if (heap_value->attrid == coll_id_att_id)
{
assert (DB_VALUE_DOMAIN_TYPE (&(heap_value->dbvalue)) == DB_TYPE_INTEGER);
curr_coll->coll_id = db_get_int (&heap_value->dbvalue);
}
else if (heap_value->attrid == coll_name_att_id)
{
const char *lang_str = NULL;
size_t lang_str_len;
assert (DB_VALUE_DOMAIN_TYPE (&(heap_value->dbvalue)) == DB_TYPE_STRING);
lang_str = db_get_string (&heap_value->dbvalue);
lang_str_len = (lang_str != NULL) ? strlen (lang_str) : 0;
lang_str_len = MIN (lang_str_len, sizeof (curr_coll->coll_name));
strncpy (curr_coll->coll_name, lang_str, lang_str_len);
curr_coll->coll_name[lang_str_len] = '\0';
}
else if (heap_value->attrid == charset_id_att_id)
{
assert (DB_VALUE_DOMAIN_TYPE (&(heap_value->dbvalue)) == DB_TYPE_INTEGER);
curr_coll->codeset = (INTL_CODESET) db_get_int (&heap_value->dbvalue);
}
else if (heap_value->attrid == checksum_att_id)
{
const char *checksum_str = NULL;
size_t str_len;
assert (DB_VALUE_DOMAIN_TYPE (&(heap_value->dbvalue)) == DB_TYPE_STRING);
checksum_str = db_get_string (&heap_value->dbvalue);
str_len = (checksum_str != NULL) ? strlen (checksum_str) : 0;
assert (str_len == 32);
strncpy (curr_coll->checksum, checksum_str, str_len);
curr_coll->checksum[str_len] = '\0';
}
}
}
exit:
if (scan_cache_inited == true)
{
(void) heap_scancache_end (thread_p, &scan_cache);
scan_cache_inited = false;
}
if (attr_info_inited == true)
{
heap_attrinfo_end (thread_p, &attr_info);
attr_info_inited = false;
}
return error;
}
/*
* catcls_get_apply_info_log_record_time () - get max log_record_time
* in _db_ha_apply_info
*
* return: NO_ERROR, or error code
* thread_p(in) : thread context
* log_record_time(out): log_record_time
*
*/
int
catcls_get_apply_info_log_record_time (THREAD_ENTRY * thread_p, time_t * log_record_time)
{
OID class_oid;
OID inst_oid;
HFID hfid;
HEAP_CACHE_ATTRINFO attr_info;
HEAP_SCANCACHE scan_cache;
RECDES recdes;
DB_DATETIME tmp_datetime;
time_t tmp_log_record_time = 0;
int log_record_time_att_id = -1;
int error = NO_ERROR;
int i;
bool attr_info_inited = false;
bool scan_cache_inited = false;
int num_record = 0;
assert (log_record_time != NULL);
*log_record_time = 0;
OID_SET_NULL (&class_oid);
OID_SET_NULL (&inst_oid);
error = catcls_find_class_oid_by_class_name (thread_p, CT_HA_APPLY_INFO_NAME, &class_oid);
if (error != NO_ERROR)
{
goto exit;
}
if (OID_ISNULL (&class_oid))
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_LC_UNKNOWN_CLASSNAME, 1, CT_HA_APPLY_INFO_NAME);
error = ER_LC_UNKNOWN_CLASSNAME;
goto exit;
}
error = heap_attrinfo_start (thread_p, &class_oid, -1, NULL, &attr_info);
if (error != NO_ERROR)
{
goto exit;
}
attr_info_inited = true;
heap_scancache_quick_start_root_hfid (thread_p, &scan_cache);
scan_cache_inited = true;
if (heap_get_class_record (thread_p, &class_oid, &recdes, &scan_cache, PEEK) != S_SUCCESS)
{
error = ER_FAILED;
goto exit;
}
for (i = 0; i < attr_info.num_values; i++)
{
char *rec_attr_name_p, *string = NULL;
int alloced_string = 0;
error = or_get_attrname (&recdes, i, &string, &alloced_string);
if (error != NO_ERROR)
{
ASSERT_ERROR ();
goto exit;
}
rec_attr_name_p = string;
if (rec_attr_name_p == NULL)
{
error = ER_FAILED;
goto exit;
}
if (strcmp ("log_record_time", rec_attr_name_p) == 0)
{
log_record_time_att_id = i;
if (string != NULL && alloced_string == 1)
{
db_private_free_and_init (thread_p, string);
}
break;
}
if (string != NULL && alloced_string == 1)
{
db_private_free_and_init (thread_p, string);
}
}
if (log_record_time_att_id == -1)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_GENERIC_ERROR, 0);
error = ER_FAILED;
goto exit;
}
heap_scancache_end (thread_p, &scan_cache);
scan_cache_inited = false;
error = heap_get_class_info (thread_p, &class_oid, &hfid, NULL, NULL);
if (error != NO_ERROR || HFID_IS_NULL (&hfid))
{
error = ER_FAILED;
goto exit;
}
error = heap_scancache_start (thread_p, &scan_cache, &hfid, NULL, true, NULL);
if (error != NO_ERROR)
{
goto exit;
}
scan_cache_inited = true;
while (heap_next (thread_p, &hfid, NULL, &inst_oid, &recdes, &scan_cache, PEEK) == S_SUCCESS)
{
HEAP_ATTRVALUE *heap_value = NULL;
if (heap_attrinfo_read_dbvalues (thread_p, &inst_oid, &recdes, &attr_info) != NO_ERROR)
{
error = ER_FAILED;
goto exit;
}
for (i = 0, heap_value = attr_info.values; i < attr_info.num_values; i++, heap_value++)
{
if (heap_value->attrid == log_record_time_att_id)
{
tmp_log_record_time = 0;
if (!DB_IS_NULL (&heap_value->dbvalue))
{
tmp_datetime = *(db_get_datetime (&heap_value->dbvalue));
tmp_datetime.time /= 1000;
tmp_log_record_time = db_mktime (&tmp_datetime.date, &tmp_datetime.time);
}
break;
}
}
if (tmp_log_record_time > *log_record_time)
{
*log_record_time = tmp_log_record_time;
}
num_record++;
}
exit:
if (scan_cache_inited == true)
{
(void) heap_scancache_end (thread_p, &scan_cache);
scan_cache_inited = false;
}
if (attr_info_inited == true)
{
heap_attrinfo_end (thread_p, &attr_info);
attr_info_inited = false;
}
if (error == NO_ERROR && num_record == 0)
{
error = ER_FAILED;
}
return error;
}
/*
* catcls_find_and_set_cached_class_oid () - Used to find OID for collation
* class and set the global
* variable for collation class
* OID.
*
* return : Error code.
* thread_p (in) : Thread entry.
*/
int
catcls_find_and_set_cached_class_oid (THREAD_ENTRY * thread_p)
{
OID class_oid;
LC_FIND_CLASSNAME status;
int i;
/* skip OID for root class, is already set with 'boot_get_db_parm' */
for (i = OID_CACHE_CLASS_CLASS_ID; i < OID_CACHE_SIZE; i++)
{
status = xlocator_find_class_oid (thread_p, oid_get_cached_class_name (i), &class_oid, NULL_LOCK);
if (status == LC_CLASSNAME_ERROR)
{
return ER_FAILED;
}
oid_set_cached_class_oid (i, &class_oid);
}
return NO_ERROR;
}
/*
* catcls_get_or_value_from_partition () -
* return: error code
*
* thread_p (in):
* buf(in):
* value(in):
*/
static int
catcls_get_or_value_from_partition (THREAD_ENTRY * thread_p, OR_BUF * buf_p, OR_VALUE * value_p)
{
OR_VALUE *attrs;
DB_VALUE *attr_val_p;
OR_VARINFO *vars = NULL;
int size;
int error = NO_ERROR;
error = catcls_expand_or_value_by_def (value_p, &ct_Partition);
if (error != NO_ERROR)
{
goto end;
}
attrs = value_p->sub.value;
size = tf_Metaclass_partition.mc_n_variable;
vars = or_get_var_table (buf_p, size, catcls_unpack_allocator);
if (vars == NULL)
{
size_t msize = size * sizeof (OR_VARINFO);
error = ER_OUT_OF_VIRTUAL_MEMORY;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 1, msize);
goto end;
}
/* type */
tp_Integer.data_readval (buf_p, &attrs[1].value, NULL, -1, true, NULL, 0);
/* depth */
tp_Integer.data_readval (buf_p, &attrs[2].value, NULL, -1, true, NULL, 0);
/* name */
attr_val_p = &attrs[3].value;
tp_String.data_readval (buf_p, attr_val_p, NULL, vars[ORC_PARTITION_NAME_INDEX].length, true, NULL, 0);
db_string_truncate (attr_val_p, DB_MAX_SPEC_LENGTH);
/* expr */
attr_val_p = &attrs[4].value;
tp_String.data_readval (buf_p, attr_val_p, NULL, vars[ORC_PARTITION_EXPR_INDEX].length, true, NULL, 0);
assert (DB_IS_NULL (attr_val_p) || db_get_string_length (attr_val_p) <= DB_MAX_PARTITION_EXPR_LENGTH);
/* values */
attr_val_p = &attrs[5].value;
error = or_get_value (buf_p, attr_val_p, NULL, vars[ORC_PARTITION_VALUES_INDEX].length, true);
if (error != NO_ERROR)
{
goto end;
}
/* comment */
attr_val_p = &attrs[6].value;
tp_String.data_readval (buf_p, attr_val_p, NULL, vars[ORC_PARTITION_COMMENT_INDEX].length, true, NULL, 0);
db_string_truncate (attr_val_p, DB_MAX_SPEC_LENGTH);
end:
if (vars)
{
free_and_init (vars);
}
return error;
}