File db_virt.c¶
File List > compat > db_virt.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.
*
*/
/*
* db_virt.c - API functions related to virtual class.
*/
#ident "$Id$"
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <ctype.h>
#include <assert.h>
#include "authenticate.h"
#include "system_parameter.h"
#include "storage_common.h"
#include "db.h"
#include "class_object.h"
#include "object_print.h"
#include "server_interface.h"
#include "boot_cl.h"
#include "locator_cl.h"
#include "schema_manager.h"
#include "schema_template.h"
#include "object_accessor.h"
#include "object_primitive.h"
#include "set_object.h"
#include "virtual_object.h"
#include "parser.h"
#include "view_transform.h"
#define ERROR_SET(error, code) \
do { \
error = code; \
er_set (ER_WARNING_SEVERITY, ARG_FILE_LINE, code, 0); \
} while (0)
/*
* NAMELIST SUPPORT
*/
/*
* db_namelist_free() - This function frees a list of names that was returned
* by one of the other db_ functions. The links in the list and the strings
* themselves are both freed to it is not wise to cache pointers to the
* strings in the list.
* return : none
* list(in): a list of names (strings)
*/
void
db_namelist_free (DB_NAMELIST * list)
{
nlist_free (list);
}
/*
* db_namelist_add() - This function adds the name to the list if it is not
* already present. The position that the name is added is undefined
* return : true if the element was added, false if it existed.
* list(in): a pointer to a list pointer.
* name(in): the name to add
*/
int
db_namelist_add (DB_NAMELIST ** list, const char *name)
{
int error;
int status;
CHECK_CONNECT_FALSE ();
CHECK_2ARGS_ZERO (list, name);
error = nlist_add (list, name, NULL, &status);
if (!error)
{
status = false;
}
return status;
}
/*
* db_namelist_append() - This function appends the name to the list if it
* isn't already present. The name will be placed at the end of the list
* return : true if the name was added, false if it existed
* list(in): pointer to pointer to list
* name(in): name to add
*/
int
db_namelist_append (DB_NAMELIST ** list, const char *name)
{
int error;
int status;
CHECK_CONNECT_FALSE ();
CHECK_2ARGS_ZERO (list, name);
error = nlist_append (list, name, NULL, &status);
if (!error)
{
status = false;
}
return status;
}
/*
* VCLASS CREATION
*/
/*
* db_create_vclass() - This function creates and returns a new virtual class
* with the given name. Initially, the virtual class is created with no
* definition. that is, it has no attributes, methods, or query
* specifications.
* If the name specified has already been used by an existing class in the
* database, NULL is returned. In this case, the system sets the global
* error status to indicate the exact nature of the error.
* return : new virtual class object
* name(in): the name of a virtual class
*/
DB_OBJECT *
db_create_vclass (const char *name)
{
int error = NO_ERROR;
SM_TEMPLATE *def;
DB_OBJECT *virtual_class;
const PR_TYPE *type;
OID class_oid = OID_INITIALIZER;
const char *class_name = NULL;
CHECK_CONNECT_NULL ();
CHECK_MODIFICATION_NULL ();
virtual_class = NULL;
if (name != NULL)
{
class_name = sm_remove_qualifier_name (name);
type = pr_find_type (class_name);
if (type != NULL || pt_is_reserved_word (class_name))
{
error = ER_SM_CLASS_WITH_PRIM_NAME;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SM_CLASS_WITH_PRIM_NAME, 1, class_name);
}
else
{
def = smt_def_typed_class (name, SM_VCLASS_CT);
if (def == NULL)
{
assert (er_errid () != NO_ERROR);
error = er_errid ();
}
else
{
if (locator_reserve_class_name (def->name, &class_oid) != LC_CLASSNAME_RESERVED)
{
assert_release (false);
smt_quit (def);
}
else
{
error = sm_update_class (def, &virtual_class);
if (error)
{
smt_quit (def);
}
}
}
}
}
return (virtual_class);
}
/*
* db_get_vclass_ldb_name() - This function returns the name of the ldb used
* with a virtual class. It simply makes a copy of the ldb name.
* return : ldb name used with virtual class
* op(in): class pointer
*
* note : The returned string must later be freed with db_string_free.
*/
char *
db_get_vclass_ldb_name (DB_OBJECT * op)
{
return NULL;
}
/*
* db_is_real_instance() - This function is used to determine whether an object
* is an instance of a class (real instance) or an instance of a virtual
* class (derived instance).
* returns: non-zero if the object is a real object, zero if the object is
* virtual class or an instance of a virtual class
* obj(in): object pointer
*/
int
db_is_real_instance (DB_OBJECT * obj)
{
int retval;
CHECK_CONNECT_ZERO ();
CHECK_1ARG_ZERO (obj);
if (locator_is_class (obj, DB_FETCH_READ) > 0)
{
return 1;
}
if (obj->is_vid)
{
retval = vid_is_base_instance (obj) ? 1 : 0;
return (retval);
}
else
{
return 1;
}
}
/*
* db_real_instance() - This function returns the object itself if the given
* object is a base object, or the real object derived from the given
* virtual object. A derived instance of a virtual class can only be
* associated with a single real instance. NULL is returned when the derived
* instance is not updatable. This is an identity function on real objects.
* return : the real object
* obj(in): virtual class instance
*/
DB_OBJECT *
db_real_instance (DB_OBJECT * obj)
{
DB_OBJECT *retval;
CHECK_CONNECT_NULL ();
CHECK_1ARG_NULL (obj);
if (db_is_real_instance (obj))
{
return obj;
}
if (obj->is_vid)
{
retval = vid_base_instance (obj);
return (retval);
}
else
{
return (DB_OBJECT *) 0;
}
}
/*
* db_instance_equal() - This function returns a non-zero value if the given
* objects are equal. Two objects are equal if both are updatable and they
* represent the same object, or if both are non-updatable but their
* attributes are equal. If the objects are not equal, 0 is returned.
* return : < 0 if error, > 0 if obj1 is equal to obj2, 0 otherwise
* obj1(in): an object
* obj2(in): an object
*/
int
db_instance_equal (DB_OBJECT * obj1, DB_OBJECT * obj2)
{
int retval;
int obj1_is_updatable, obj2_is_updatable;
int is_class = 0;
CHECK_CONNECT_ZERO ();
CHECK_2ARGS_ZERO (obj1, obj2);
if (obj1 == obj2)
{
return 1;
}
is_class = locator_is_class (obj1, DB_FETCH_READ);
if (is_class < 0)
{
return is_class;
}
if (is_class)
{
/* We have already checked obj1 pointer vs obj2 pointer. The classes cannot be equal if they are not the same
* MOP. */
return 0;
}
is_class = locator_is_class (obj2, DB_FETCH_READ);
if (is_class < 0)
{
return is_class;
}
if (is_class)
{
/* We have already checked obj1 pointer vs obj2 pointer. The classes cannot be equal if they are not the same
* MOP. */
return 0;
}
obj1_is_updatable = db_is_updatable_object (obj1);
obj2_is_updatable = db_is_updatable_object (obj2);
if (obj1_is_updatable && obj2_is_updatable)
{
retval = db_real_instance (obj1) == db_real_instance (obj2);
return (retval);
}
else if ((!obj1_is_updatable) && (!obj2_is_updatable))
{
retval = vid_compare_non_updatable_objects (obj1, obj2) ? 1 : 0;
return (retval);
}
return 0;
}
/*
* db_is_updatable_object() - This function returns non-zero if the given
* object is updatable.
* return : non-zero if object is updatable
* obj(in): A class, virtual class or instance object
*/
int
db_is_updatable_object (DB_OBJECT * obj)
{
int retval;
int error = NO_ERROR;
SM_CLASS *class_;
CHECK_CONNECT_ZERO ();
CHECK_1ARG_ZERO (obj);
if (locator_is_class (obj, DB_FETCH_READ) > 0)
{
if (au_fetch_class (obj, &class_, AU_FETCH_READ, AU_SELECT) == NO_ERROR)
{
switch (class_->class_type)
{
case SM_CLASS_CT:
return 1;
case SM_VCLASS_CT:
retval = (int) mq_is_updatable (obj);
return (retval);
default:
break;
}
}
else
{
ERROR_SET (error, ER_WS_NO_CLASS_FOR_INSTANCE);
return 0;
}
}
else
{
if (obj->is_vid)
{
retval = (int) vid_is_updatable (obj);
return (retval);
}
else
{
return 1;
}
}
return 0;
}
/*
* db_is_updatable_attribute() - This function returns a non-zero value if the
* class or instance is updatable and if the attribute is updatable.
* return : non-zero if both the class and the attribute are updatable
* obj(in): An instance
* attr_name(in): An attribute name
*/
int
db_is_updatable_attribute (DB_OBJECT * obj, const char *attr_name)
{
int retval;
int error = NO_ERROR;
SM_CLASS *class_;
DB_OBJECT *class_obj = NULL;
DB_OBJECT *real_obj = NULL;
DB_OBJECT *real_class_obj = NULL;
CHECK_CONNECT_ZERO ();
CHECK_1ARG_ZERO (obj);
if (locator_is_class (obj, DB_FETCH_WRITE) > 0)
{
ERROR_SET (error, ER_OBJ_INVALID_ARGUMENTS);
return 0;
}
if (db_get_attribute_type (obj, attr_name) == DB_TYPE_NULL)
{
return 0;
}
if (au_fetch_class (obj, &class_, AU_FETCH_READ, AU_SELECT) == NO_ERROR)
{
switch (class_->class_type)
{
case SM_CLASS_CT:
return 1;
case SM_VCLASS_CT:
class_obj = db_get_class (obj);
real_obj = db_real_instance (obj);
if (real_obj)
{
real_class_obj = db_get_class (real_obj);
}
if (class_obj && real_class_obj)
{
retval = mq_is_updatable_attribute (class_obj, attr_name, real_class_obj) ? 1 : 0;
return (retval);
}
else
{
return 0;
}
break;
default:
break;
}
}
else
{
ERROR_SET (error, ER_WS_NO_CLASS_FOR_INSTANCE);
return 0;
}
return 0;
}
/*
* db_add_query_spec() - This function adds a query to a virtual class.
* return : error code
* class(in): vrtual class
* query(in): query string
*/
int
db_add_query_spec (MOP vclass, const char *query)
{
int error = NO_ERROR;
SM_TEMPLATE *def;
MOP newmop;
CHECK_CONNECT_ERROR ();
CHECK_MODIFICATION_ERROR ();
if ((vclass == NULL) || (query == NULL))
{
ERROR_SET (error, ER_OBJ_INVALID_ARGUMENTS);
}
else
{
def = smt_edit_class_mop (vclass, AU_ALTER);
if (def == NULL)
{
assert (er_errid () != NO_ERROR);
error = er_errid ();
}
else
{
error = smt_add_query_spec (def, query);
if (error)
{
smt_quit (def);
}
else
{
error = sm_update_class (def, &newmop);
if (error)
{
smt_quit (def);
}
}
}
}
return (error);
}
/*
* db_drop_query_spec() -
* return:
* vclass(in) :
* query_no(in) :
*/
int
db_drop_query_spec (DB_OBJECT * vclass, const int query_no)
{
int error = NO_ERROR;
SM_TEMPLATE *def;
MOP newmop;
CHECK_CONNECT_ERROR ();
CHECK_MODIFICATION_ERROR ();
if (vclass == NULL)
{
ERROR_SET (error, ER_OBJ_INVALID_ARGUMENTS);
}
else
{
def = smt_edit_class_mop (vclass, AU_ALTER);
if (def == NULL)
{
assert (er_errid () != NO_ERROR);
error = er_errid ();
}
else
{
error = smt_drop_query_spec (def, query_no);
if (error)
{
smt_quit (def);
}
else
{
error = sm_update_class (def, &newmop);
if (error)
{
smt_quit (def);
}
}
}
}
return (error);
}
/*
* db_change_query_spec() -
* return:
* vclass(in) :
* new_query(in) :
* query_no(in) :
*/
int
db_change_query_spec (DB_OBJECT * vclass, const char *new_query, const int query_no)
{
int error = NO_ERROR;
SM_TEMPLATE *def;
MOP newmop;
CHECK_CONNECT_ERROR ();
CHECK_MODIFICATION_ERROR ();
if (vclass == NULL)
{
ERROR_SET (error, ER_OBJ_INVALID_ARGUMENTS);
}
else
{
def = smt_edit_class_mop (vclass, AU_ALTER);
if (def == NULL)
{
assert (er_errid () != NO_ERROR);
error = er_errid ();
}
else
{
error = smt_change_query_spec (def, new_query, query_no);
if (error)
{
smt_quit (def);
}
else
{
error = sm_update_class (def, &newmop);
if (error)
{
smt_quit (def);
}
}
}
}
return (error);
}
/*
* db_get_query_specs() - This function returns a list of query_spec
* descriptors for a virtual class.
* return : list of query specifications
* obj(in): class or instance
*/
DB_QUERY_SPEC *
db_get_query_specs (DB_OBJECT * obj)
{
SM_QUERY_SPEC *query_spec;
SM_CLASS *class_;
CHECK_CONNECT_NULL ();
query_spec = NULL;
if (au_fetch_class (obj, &class_, AU_FETCH_READ, AU_SELECT) == NO_ERROR)
{
query_spec = class_->query_spec;
}
return ((DB_QUERY_SPEC *) query_spec);
}
/*
* db_query_spec_next() - This function returns the next query_spec descriptor
* in the list or NULL if you're at the end of the list.
* return : query_spec descriptor
* query_spec(in): query_spec descriptor
*/
DB_QUERY_SPEC *
db_query_spec_next (DB_QUERY_SPEC * query_spec)
{
DB_QUERY_SPEC *next = NULL;
if (query_spec != NULL)
{
next = query_spec->next;
}
return (next);
}
/*
* db_query_spec_string() - This function returns the string defining the
* virtual query
* return : query specification string
* query_spec(in): query_spec descriptor
*/
const char *
db_query_spec_string (DB_QUERY_SPEC * query_spec)
{
const char *spec = NULL;
if (query_spec != NULL)
{
spec = query_spec->specification;
}
return (spec);
}
/*
* db_get_object_id() - This function gets object_id for the vclass on ldb
* return : odject id name list
* class(in): virtual class
*/
DB_NAMELIST *
db_get_object_id (MOP vclass)
{
return NULL;
}
/*
* db_is_vclass() - This function returns a > 0 value if and only if the
* object is a virtual class.
* return : < 0 if error, > 0 if the object is a virtual class, = 0 otherwise
* op(in): class pointer
*/
int
db_is_vclass (DB_OBJECT * op)
{
SM_CLASS *class_ = NULL;
int error = 0;
CHECK_CONNECT_ZERO ();
if (op == NULL)
{
return 0;
}
error = locator_is_class (op, DB_FETCH_READ);
if (error <= 0)
{
return error;
}
error = au_fetch_class_force (op, &class_, AU_FETCH_READ);
if (error < 0)
{
return error;
}
if (sm_get_class_type (class_) != SM_VCLASS_CT)
{
return 0;
}
return 1;
}