File load_sa_loader.cpp¶
File List > cubrid > src > loaddb > load_sa_loader.cpp
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.
*
*/
/*
* load_sa_loader.cpp - Database loader (Optimized version)
*/
#include "config.h"
#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <fstream>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if defined (WINDOWS)
#include <io.h>
#else
#include <unistd.h>
#endif /* !WINDOWS */
#include "authenticate.h"
#include "db.h"
#include "db_client_type.hpp"
#include "db_json.hpp"
#include "dbi.h"
#include "dbtype.h"
#include "elo.h"
#include "environment_variable.h"
#include "execute_schema.h"
#include "intl_support.h"
#include "language_support.h"
#include "load_db_value_converter.hpp"
#include "load_driver.hpp"
#include "load_error_handler.hpp"
#include "load_object.h"
#include "load_object_table.h"
#include "load_sa_loader.hpp"
#include "load_scanner.hpp"
#include "locator_cl.h"
#include "memory_alloc.h"
#include "message_catalog.h"
#include "network.h"
#include "object_accessor.h"
#include "object_primitive.h"
#include "object_representation.h"
#include "porting.h"
#include "schema_manager.h"
#include "set_object.h"
#include "system_parameter.h"
#include "thread_manager.hpp"
#include "transaction_cl.h"
#include "trigger_manager.h"
#include "utility.h"
#include "work_space.h"
#include "schema_system_catalog_constants.h"
using namespace cubload;
const std::size_t LDR_MAX_ARGS = 32;
/* filter out ignorable errid */
#define FILTER_OUT_ERR_INTERNAL(err, expr) \
( err = ((expr) == NO_ERROR ? NO_ERROR : er_filter_errid(false)) )
#define CHECK_ERR(err, expr) \
do { \
int inner_err = (expr); \
if (FILTER_OUT_ERR_INTERNAL(err, inner_err) != NO_ERROR) { \
display_error(0); \
goto error_exit; \
} \
if (inner_err != NO_ERROR && err == NO_ERROR ) { \
skip_current_instance = true; \
} \
} while (0)
/*
* CHECK_PARSE_ERR is used by the element setters to output more information
* about the source token and destination attribute being processed, if
* an error occurs.
*/
#define CHECK_PARSE_ERR(err, expr, cont, type, str) \
do { \
int inner_err = (expr); \
if (FILTER_OUT_ERR_INTERNAL(err, inner_err) != NO_ERROR) { \
display_error(0); \
parse_error(cont, type, str); \
goto error_exit; \
} \
if (inner_err != NO_ERROR && err == NO_ERROR) { \
skip_current_instance = true; \
} \
} while (0)
#define CHECK_PTR(err, expr) \
do { \
if ((expr) == NULL) { \
display_error(0); \
if (err == NO_ERROR) { \
if ((err = er_errid()) == NO_ERROR) { /* need to set errid */ \
err = ER_GENERIC_ERROR; \
er_set(ER_ERROR_SEVERITY, ARG_FILE_LINE, err, 0); \
} \
} \
goto error_exit; \
} \
} while (0)
#define CHECK_CONTEXT_VALIDITY(context, expr) \
do { \
if ((expr)) { \
ldr_increment_err_count (context, 1); \
context->valid = false; \
} \
} while (0)
#define RETURN_IF_NOT_VALID(context) \
do { \
if (!context->valid) return; \
} while (0)
#define RETURN_IF_NOT_VALID_WITH(context, ret) \
do { \
if (!context->valid) return (ret); \
} while (0)
#define CHECK_VALIDATION_ONLY(context) \
do { \
if (context->validation_only) goto error_exit; \
} while (0)
#define GET_DOMAIN(context, domain) \
do { \
if (context->collection == NULL && context->valid) \
domain = context->attrs[context->next_attr].att->domain; \
else \
domain = context->set_domain; \
} while (0)
#define CHECK_SKIP() \
do { \
if (skip_current_class == true) { \
return; \
} \
} while (0)
#define CHECK_SKIP_WITH(ret) \
do { \
if (skip_current_class == true) { \
return (ret); \
} \
} while (0)
typedef struct ldr_context LDR_CONTEXT;
typedef void (*LDR_POST_COMMIT_HANDLER) (int64_t);
typedef void (*LDR_POST_INTERRUPT_HANDLER) (int64_t);
typedef int (*LDR_SETTER) (LDR_CONTEXT *, const char *, size_t, SM_ATTRIBUTE *);
typedef int (*LDR_ELEM) (LDR_CONTEXT *, const char *, size_t, DB_VALUE *);
/*
* LDR_ATTDESC
* Loader attribute description structure.
* This contains the description, attribute, and fast setter function
* for the attribute.
* parser_* holds the parser token information and is used when parsing
* the constructor syntax, to simulate the parse phase when creating a
* constructor object.
*/
typedef struct LDR_ATTDESC
{
DB_ATTDESC *attdesc; /* Attribute descriptor */
SM_ATTRIBUTE *att; /* Attribute */
LDR_SETTER setter[NUM_LDR_TYPES]; /* Setter functions indexed by type */
char *parser_str; /* used as a holder to hold the parser strings when parsing method arguments. */
size_t parser_str_len; /* Length of parser token string */
size_t parser_buf_len; /* Length of parser token buffer */
data_type parser_type; /* Used when parsing method arguments, to store */
/* the type information. */
DB_OBJECT *ref_class; /* Class referenced by object reference */
int instance_id; /* Instance id of instance referenced by ref_class object ref */
TP_DOMAIN *collection_domain; /* Best domain for collection */
} LDR_ATTDESC;
/*
* LDR_MOP_TEMPOID_MAP
* LDR_MOP_TEMPOID_MAPS
* Information about a temporary OID created while parsing the load file,
* LDR_MOP_TEMPOID_MAP.
* An array of these structures will be used to hold MOP -> CLASS_TABLE
* entry information, LDR_MOP_TEMPOID_MAPS. The CLASS_TABLE and id will
* be used to access the INST_INFO structure to directly access the
* oid pointer in the instances array of the loaders otable.
* Prior to flushing and LC_OIDSET is created with the list
* of mops in this structure. This set is sent to the server to obtain
* permanent OIDs. The loader's otable is updated with the permanent OIDs
* sent back from the server.
*/
typedef struct ldr_mop_tempoid_map
{
MOP mop; /* Workspace MOP */
CLASS_TABLE *table; /* otable class table */
int id; /* instance identifier in table */
} LDR_MOP_TEMPOID_MAP;
typedef struct ldr_mop_tempoid_maps
{
int count; /* number of LDR_MOP_TEMPOID_MAP maps */
int index; /* next available slot */
int size; /* size of LDR_MOP_TEMPOID_MAP array */
LDR_MOP_TEMPOID_MAP *mop_tempoid_maps; /* array of maps */
} LDR_MOP_TEMPOID_MAPS;
static LDR_MOP_TEMPOID_MAPS *ldr_Mop_tempoid_maps = NULL;
/*
* LDR_CONTEXT
* The loader context, holds the state information for the parser actions
* to use when triggered.
*/
struct ldr_context
{
DB_OBJECT *cls; /* Current class */
char *class_name; /* Class name of current class */
DB_OBJECT *obj; /* Instance of class */
MOBJ mobj; /* Memory object of instance */
int obj_pin; /* pins returned when pinning the */
int class_pin; /* current class */
int class_type; /* not partitioned, partitioned, partition */
LDR_ATTDESC *attrs; /* array of attribute descriptors for */
/* the current class. */
int num_attrs; /* Number of attributes for class */
int next_attr; /* Index of current attribute */
unsigned int instance_started:1; /* Instance stared flag */
bool valid; /* State of the loader. */
load_args *args; /* loaddb executable arguments */
int err_count; /* Current error count for instance */
int err_total; /* Total error counter */
int64_t inst_count; /* Instance count for this class */
int64_t inst_total; /* Total instance count */
int inst_num; /* Instance id of current instance */
int flush_total; /* Total number of flushes performed */
/* for the current class */
int flush_interval; /* The number of instances before a */
/* flush is performed */
CLASS_TABLE *table; /* Table of instances currently */
/* accumlated for the class */
bool validation_only; /* Syntax checking only flag */
INTL_LANG lang_id; /* Current language */
DB_COLLECTION *collection; /* Pointer to hang collection from */
TP_DOMAIN *set_domain; /* Set domain of current set if */
/* applicable. */
SM_METHOD *constructor; /* Method constructor */
int arg_index; /* Index where arguments start in */
/* the attr descriptor array. */
int max_arg; /* Maximum number of arguments */
SM_METHOD_ARGUMENT **method_args; /* Pointer to the arguments */
int arg_count; /* argument counter */
DB_OBJECT *id_class; /* Holds class ptr when processing ids */
attribute_type attr_type; /* type of attribute if class */
/* attribute, shared, default */
int status_count; /* Count used to indicate number of */
/* instances committed for internal */
/* debugging use only */
int status_counter; /* Internal debug instance counter */
int commit_counter; /* periodic commit counter */
int default_count; /* the number of instances with */
};
static bool skip_current_class = false;
static bool skip_current_instance = false;
extern bool locator_Dont_check_foreign_key; /* from locator_sr.h */
/*
* ldr_Current_context, ldr_Context
* Global variables holding the parser current context information.
* This pointer is exported and used by the parser module ld.g
*
*/
static LDR_CONTEXT *ldr_Current_context = NULL;
static LDR_CONTEXT ldr_Context;
// Global driver instance for client loader
static driver *ldr_Driver;
/*
* ldr_Hint_locks
* ldr_Hint_class_names
* ldr_Hint_subclasses
* ldr_Hint_flags
* Global array used to hold the class read, instance write lock
* set up at initialization. This will be used by ldr_find_class()
* This is a temporary solution to fix the client/server deadlock problem.
* This needs to be done for all classes, perhaps attached to the otable.
*/
#define LDR_LOCKHINT_COUNT 1
static LOCK ldr_Hint_locks[LDR_LOCKHINT_COUNT];
static const char *ldr_Hint_class_names[LDR_LOCKHINT_COUNT];
static int ldr_Hint_subclasses[LDR_LOCKHINT_COUNT];
static LC_PREFETCH_FLAGS ldr_Hint_flags[LDR_LOCKHINT_COUNT];
/*
* elem_converter
* array to fucntions indexed by attribute type for for setting elements in
* in a collection.
*/
static LDR_ELEM elem_converter[NUM_LDR_TYPES];
/*
* Total_objects
* Global total object count.
*/
static int64_t Total_objects = 0;
static int64_t Last_committed_line = 0;
static int Total_fails = 0;
static int64_t Total_objects_loaded = 0; /* The number of objects inserted if an interrupted occurred. */
/*
* ldr_post_commit_handler
* Post commit callback function. Called with number of instances
* committed.
*/
static LDR_POST_COMMIT_HANDLER ldr_post_commit_handler = NULL;
/*
* ldr_post_interrupt_handler
* Post commit interrupt handler. Called with number of instances
* committed.
*/
static LDR_POST_INTERRUPT_HANDLER ldr_post_interrupt_handler = NULL;
/*
* ldr_Load_interrupted
* Global flag which is turned on when an interrupt is received, via
* Values : interrupt_type :
* LDR_NO_INTERRUPT
* LDR_STOP_AND_ABORT_INTERRUPT
* LDR_STOP_AND_COMMIT_INTERRUPT
*/
static int ldr_Load_interrupted = LDR_NO_INTERRUPT;
static int ldr_Interrupt_type = LDR_NO_INTERRUPT;
static jmp_buf *ldr_Jmp_buf_ptr = NULL;
static jmp_buf ldr_Jmp_buf; /* Jump buffer for loader to jump to if we have an interrupt */
/*
* Id_map
* Id_map_size
* The global class id map.
* The class id map provides a textually shorter way to reference classes.
* When the %class <name> <id> statement is parsed, an entry will be made
* in this map table so the class can be referenced by id number rather
* than continually using the full class name.
*/
static DB_OBJECT **Id_map = NULL;
static int Id_map_size = 0;
/*
* internal_classes
* Global list of internal_classes.
* These are the classes that we don't allow to be loaded.
* Initialized by clist_init().
*/
static DB_OBJLIST *internal_classes = NULL;
/*
* DB_VALUE TEMPLATES
*
* These templates are used to avoid the overhead of calling
* db_value_domain_init incessantly. Incredibly, that adds up when you're
* dealing with thousands of attributes and values.
*
* This is very dangerous from a maintenance standpoint, because it means
* that this code now has to know and obey all of the quirks for the various
* fields. If any of the handling in dbtype.h and/or db_macro.c changes,
* this code will probably need to change, too.
*/
static DB_VALUE ldr_short_tmpl;
static DB_VALUE ldr_int_tmpl;
static DB_VALUE ldr_bigint_tmpl;
static DB_VALUE ldr_char_tmpl;
static DB_VALUE ldr_varchar_tmpl;
static DB_VALUE ldr_float_tmpl;
static DB_VALUE ldr_double_tmpl;
static DB_VALUE ldr_date_tmpl;
static DB_VALUE ldr_time_tmpl;
static DB_VALUE ldr_timestamp_tmpl;
static DB_VALUE ldr_timestampltz_tmpl;
static DB_VALUE ldr_timestamptz_tmpl;
static DB_VALUE ldr_datetime_tmpl;
static DB_VALUE ldr_datetimeltz_tmpl;
static DB_VALUE ldr_datetimetz_tmpl;
static DB_VALUE ldr_blob_tmpl;
static DB_VALUE ldr_clob_tmpl;
static DB_VALUE ldr_bit_tmpl;
static DB_VALUE ldr_json_tmpl;
/* default for 64 bit signed big integers, i.e., 9223372036854775807 (0x7FFFFFFFFFFFFFFF) */
#define MAX_DIGITS_FOR_BIGINT 19
/* default for 32 bit signed integers, i.e., 2147483647 (0x7FFFFFFF) */
#define MAX_DIGITS_FOR_INT 10
#define MAX_DIGITS_FOR_SHORT 5
#define ROUND(x) (int)((x) > 0 ? ((x) + .5) : ((x) - .5))
#define PARSE_ELO_STR(str, new_len) \
do \
{ \
if (str[0] == '\"') \
str++; \
new_len = (int) strlen (str); \
if (new_len && str[new_len-1] == '\"') \
new_len--; \
} \
while (0)
/*
* presize for mop_tempoid_map array.
* Also used as the increment size to grow the maps array.
*/
#define LDR_MOP_TEMPOID_MAPS_PRESIZE 1000
#define LDR_ARG_GROW_SIZE 128
/* Loader initialization and shutdown functions */
static int ldr_start ();
static int ldr_destroy (LDR_CONTEXT *context, int err);
static int ldr_init (load_args *args);
static void ldr_init_driver ();
static int ldr_final (void);
/* Statistics updating/retrieving functions */
static void ldr_stats (int *errors, int64_t *objects, int *defaults, int64_t *lastcommit, int *fails);
static int ldr_update_statistics (void);
/* Callback functions */
static void ldr_register_post_commit_handler ();
static void ldr_register_post_interrupt_handler ();
static void ldr_signal_handler (void);
static void ldr_report_num_of_commits (int64_t num_committed);
static void ldr_get_num_of_inserted_objects (int64_t num_objects);
/* Action to initialize the parser context to deal with a new class */
static void ldr_act_init_context (LDR_CONTEXT *context, const char *class_name, size_t len);
/* Action to deal with attribute names and argument names */
static int ldr_act_check_missing_non_null_attrs (LDR_CONTEXT *context);
static void ldr_act_add_attr (LDR_CONTEXT *context, const char *attr_name, size_t len);
/* Actions for object references */
static void ldr_act_set_ref_class_id (LDR_CONTEXT *context, int id);
static void ldr_act_set_ref_class (LDR_CONTEXT *context, char *name);
static void ldr_act_set_instance_id (LDR_CONTEXT *context, int id);
static DB_OBJECT *ldr_act_get_ref_class (LDR_CONTEXT *context);
/* Special action for class, shared, default attributes */
static void ldr_act_restrict_attributes (LDR_CONTEXT *context, attribute_type type);
/* Actions for constructor syntax */
static int ldr_act_set_constructor (LDR_CONTEXT *context, const char *name);
static int ldr_act_add_argument (LDR_CONTEXT *context, const char *name);
static void ldr_act_set_skip_current_class (char *class_name, size_t size);
static bool ldr_is_ignore_class (const char *class_name, size_t size);
/* error handling functions */
static void ldr_increment_err_count (LDR_CONTEXT *context, int i);
static void ldr_clear_err_count (LDR_CONTEXT *context);
static void ldr_clear_err_total (LDR_CONTEXT *context);
static const char *ldr_class_name (LDR_CONTEXT *context);
static const char *ldr_attr_name (LDR_CONTEXT *context);
static int select_set_domain (LDR_CONTEXT *context, TP_DOMAIN *domain, TP_DOMAIN **set_domain_ptr);
static int check_object_domain (LDR_CONTEXT *context, DB_OBJECT *class_, DB_OBJECT **actual_class);
static int check_class_domain (LDR_CONTEXT *context);
static void idmap_init (void);
static void idmap_final (void);
static int idmap_grow (int size);
static int ldr_assign_class_id (DB_OBJECT *class_, int id);
static DB_OBJECT *ldr_find_class (const char *class_name);
static int ldr_find_class_by_query (const char *name, char *buf, int buf_size);
static DB_OBJECT *ldr_get_class_from_id (int id);
static void ldr_clear_context (LDR_CONTEXT *context);
static void ldr_clear_and_free_context (LDR_CONTEXT *context);
static void ldr_internal_error (LDR_CONTEXT *context);
static void display_error_line (int adjust);
static void display_error (int adjust);
static void ldr_invalid_class_error (LDR_CONTEXT *context);
static void parse_error (LDR_CONTEXT *context, DB_TYPE token_type, const char *token);
static int clist_init (void);
static void clist_final (void);
static int is_internal_class (DB_OBJECT *class_);
static void ldr_act_elem (LDR_CONTEXT *context, const char *str, size_t len, data_type type);
static void ldr_act_attr (LDR_CONTEXT *context, const char *str, size_t len, data_type type);
static void ldr_act_meth (LDR_CONTEXT *context, const char *str, size_t len, data_type type);
static int ldr_mismatch (LDR_CONTEXT *context, const char *str, size_t len, SM_ATTRIBUTE *att);
static int ldr_ignore (LDR_CONTEXT *context, const char *str, size_t len, SM_ATTRIBUTE *att);
static int ldr_generic (LDR_CONTEXT *context, DB_VALUE *value);
static int ldr_null_elem (LDR_CONTEXT *context, const char *str, size_t len, DB_VALUE *val);
static int ldr_null_db_generic (LDR_CONTEXT *context, const char *str, size_t len, SM_ATTRIBUTE *att);
static int ldr_class_attr_db_generic (LDR_CONTEXT *context, const char *str, size_t len, SM_ATTRIBUTE *att,
DB_VALUE *val);
static void ldr_act_class_attr (LDR_CONTEXT *context, const char *str, size_t len, data_type type);
static int ldr_sys_user_db_generic (LDR_CONTEXT *context, const char *str, size_t len, SM_ATTRIBUTE *att);
static int ldr_sys_class_db_generic (LDR_CONTEXT *context, const char *str, size_t len, SM_ATTRIBUTE *att);
static int ldr_int_elem (LDR_CONTEXT *context, const char *str, size_t len, DB_VALUE *val);
static int ldr_int_db_generic (LDR_CONTEXT *context, const char *str, size_t len, SM_ATTRIBUTE *att);
static int ldr_int_db_bigint (LDR_CONTEXT *context, const char *str, size_t len, SM_ATTRIBUTE *att);
static int ldr_int_db_int (LDR_CONTEXT *context, const char *str, size_t len, SM_ATTRIBUTE *att);
static int ldr_int_db_short (LDR_CONTEXT *context, const char *str, size_t len, SM_ATTRIBUTE *att);
static int ldr_str_elem (LDR_CONTEXT *context, const char *str, size_t len, DB_VALUE *val);
static int ldr_str_db_char (LDR_CONTEXT *context, const char *str, size_t len, SM_ATTRIBUTE *att);
static int ldr_str_db_varchar (LDR_CONTEXT *context, const char *str, size_t len, SM_ATTRIBUTE *att);
static int ldr_str_db_generic (LDR_CONTEXT *context, const char *str, size_t len, SM_ATTRIBUTE *att);
static int ldr_bstr_elem (LDR_CONTEXT *context, const char *str, size_t len, DB_VALUE *val);
static int ldr_bstr_db_varbit (LDR_CONTEXT *context, const char *str, size_t len, SM_ATTRIBUTE *att);
static int ldr_xstr_elem (LDR_CONTEXT *context, const char *str, size_t len, DB_VALUE *val);
static int ldr_xstr_db_varbit (LDR_CONTEXT *context, const char *str, size_t len, SM_ATTRIBUTE *att);
static int ldr_numeric_elem (LDR_CONTEXT *context, const char *str, size_t len, DB_VALUE *val);
static int ldr_numeric_db_generic (LDR_CONTEXT *context, const char *str, size_t len, SM_ATTRIBUTE *att);
static int ldr_double_elem (LDR_CONTEXT *context, const char *str, size_t len, DB_VALUE *val);
static int ldr_float_elem (LDR_CONTEXT *context, const char *str, size_t len, DB_VALUE *val);
static int ldr_real_db_generic (LDR_CONTEXT *context, const char *str, size_t len, SM_ATTRIBUTE *att);
static int ldr_real_db_float (LDR_CONTEXT *context, const char *str, size_t len, SM_ATTRIBUTE *att);
static int ldr_real_db_double (LDR_CONTEXT *context, const char *str, size_t len, SM_ATTRIBUTE *att);
static int ldr_date_elem (LDR_CONTEXT *context, const char *str, size_t len, DB_VALUE *val);
static int ldr_date_db_date (LDR_CONTEXT *context, const char *str, size_t len, SM_ATTRIBUTE *att);
static int ldr_time_elem (LDR_CONTEXT *context, const char *str, size_t len, DB_VALUE *val);
static int ldr_time_db_time (LDR_CONTEXT *context, const char *str, size_t len, SM_ATTRIBUTE *att);
static int ldr_timestamp_elem (LDR_CONTEXT *context, const char *str, size_t len, DB_VALUE *val);
static int ldr_timestamp_db_timestamp (LDR_CONTEXT *context, const char *str, size_t len, SM_ATTRIBUTE *att);
static int ldr_timestamptz_elem (LDR_CONTEXT *context, const char *str, size_t len, DB_VALUE *val);
static int ldr_timestampltz_elem (LDR_CONTEXT *context, const char *str, size_t len, DB_VALUE *val);
static int ldr_timestamptz_db_timestamptz (LDR_CONTEXT *context, const char *str, size_t len, SM_ATTRIBUTE *att);
static int ldr_timestampltz_db_timestampltz (LDR_CONTEXT *context, const char *str, size_t len, SM_ATTRIBUTE *att);
static int ldr_datetime_elem (LDR_CONTEXT *context, const char *str, size_t len, DB_VALUE *val);
static int ldr_datetime_db_datetime (LDR_CONTEXT *context, const char *str, size_t len, SM_ATTRIBUTE *att);
static int ldr_datetimetz_elem (LDR_CONTEXT *context, const char *str, size_t len, DB_VALUE *val);
static int ldr_datetimeltz_elem (LDR_CONTEXT *context, const char *str, size_t len, DB_VALUE *val);
static int ldr_datetimetz_db_datetimetz (LDR_CONTEXT *context, const char *str, size_t len, SM_ATTRIBUTE *att);
static int ldr_datetimeltz_db_datetimeltz (LDR_CONTEXT *context, const char *str, size_t len, SM_ATTRIBUTE *att);
static void ldr_date_time_conversion_error (const char *token, DB_TYPE type);
static int ldr_check_date_time_conversion (const char *str, data_type type);
static int ldr_elo_int_elem (LDR_CONTEXT *context, const char *str, size_t len, DB_VALUE *val);
static int ldr_elo_int_db_elo (LDR_CONTEXT *context, const char *str, size_t len, SM_ATTRIBUTE *att);
static int ldr_elo_ext_elem (LDR_CONTEXT *context, const char *str, size_t len, DB_VALUE *val);
static int ldr_elo_ext_db_elo (LDR_CONTEXT *context, const char *str, size_t len, SM_ATTRIBUTE *att);
static int ldr_mop_tempoid_maps_init (void);
static void ldr_mop_tempoid_maps_final (void);
static int ldr_add_mop_tempoid_map (MOP mop, CLASS_TABLE *table, int id);
static int ldr_assign_all_perm_oids (void);
static int find_instance (LDR_CONTEXT *context, DB_OBJECT *class_, OID *oid, int id);
static int ldr_class_oid_elem (LDR_CONTEXT *context, const char *str, size_t len, DB_VALUE *val);
static int ldr_class_oid_db_object (LDR_CONTEXT *context, const char *str, size_t len, SM_ATTRIBUTE *att);
static int ldr_oid_elem (LDR_CONTEXT *context, const char *str, size_t len, DB_VALUE *val);
static int ldr_oid_db_object (LDR_CONTEXT *context, const char *str, size_t len, SM_ATTRIBUTE *att);
static int ldr_monetary_elem (LDR_CONTEXT *context, const char *str, size_t len, DB_VALUE *val);
static int ldr_monetary_db_monetary (LDR_CONTEXT *context, const char *str, size_t len, SM_ATTRIBUTE *att);
static int ldr_collection_elem (LDR_CONTEXT *context, const char *str, size_t len, DB_VALUE *val);
static int ldr_collection_db_collection (LDR_CONTEXT *context, const char *str, size_t len, SM_ATTRIBUTE *att);
static int ldr_reset_context (LDR_CONTEXT *context);
static void ldr_flush (LDR_CONTEXT *context);
static int check_commit (LDR_CONTEXT *context);
static void ldr_restore_pin_and_drop_obj (LDR_CONTEXT *context, bool drop_obj);
static int ldr_finish_context (LDR_CONTEXT *context);
static int ldr_refresh_attrs (LDR_CONTEXT *context);
static int update_default_count (CLASS_TABLE *table, OID *oid);
static int update_default_instances_stats (LDR_CONTEXT *context);
static int insert_instance (LDR_CONTEXT *context);
static MOP construct_instance (LDR_CONTEXT *context);
static int insert_meth_instance (LDR_CONTEXT *context);
static int add_element (void ***elements, int *count, int *max, int grow);
static int add_argument (LDR_CONTEXT *context);
static void invalid_class_id_error (LDR_CONTEXT *context, int id);
static int ldr_init_loader (LDR_CONTEXT *context);
static void ldr_abort (void);
static void ldr_process_object_ref (object_ref_type *ref, int type);
static int ldr_act_add_class_all_attrs (const char *class_name);
static int ldr_json_elem (LDR_CONTEXT *context, const char *str, size_t len, DB_VALUE *val);
static int ldr_json_db_json (LDR_CONTEXT *context, const char *str, size_t len, SM_ATTRIBUTE *att);
/* default action */
void (*ldr_act) (LDR_CONTEXT *context, const char *str, size_t len, data_type type) = ldr_act_attr;
namespace cubload
{
void
sa_class_installer::set_class_id (class_id clsid)
{
(void) clsid;
// do nothing on SA_MODE
}
void
sa_class_installer::check_class (const char *class_name, int class_id)
{
DB_OBJECT *class_;
int err = NO_ERROR;
bool is_ignore_class;
// moved from grammar file;
skip_current_class = false;
if (!ldr_Current_context->validation_only)
{
class_ = ldr_find_class (class_name);
if (class_ != NULL)
{
ldr_Current_context->id_class = class_;
}
else
{
is_ignore_class = ldr_is_ignore_class (class_name, strlen (class_name));
if (!is_ignore_class)
{
display_error (0);
CHECK_CONTEXT_VALIDITY (ldr_Current_context, true);
}
else if (er_errid () == ER_LC_UNKNOWN_CLASSNAME)
{
er_clear ();
}
}
}
if (ldr_Current_context->id_class != NULL)
{
ldr_Current_context->inst_num = class_id;
CHECK_ERR (err, ldr_assign_class_id (ldr_Current_context->id_class, class_id));
ldr_Current_context->id_class = NULL;
}
error_exit:
CHECK_CONTEXT_VALIDITY (ldr_Current_context, err != NO_ERROR);
}
int
sa_class_installer::install_class (const char *class_name)
{
ldr_act_init_context (ldr_Current_context, class_name, strlen (class_name));
/*
* If there is no class or not authorized,
* Error message is printed and ER_FAILED is returned.
*/
return ldr_act_add_class_all_attrs (class_name);
}
void
sa_class_installer::install_class (string_type *class_name, class_command_spec_type *cmd_spec)
{
if (class_name == NULL)
{
return;
}
if (cmd_spec == NULL)
{
// fallback on default attribute list
install_class (class_name->val);
return;
}
// setup class
ldr_act_set_skip_current_class (class_name->val, class_name->size);
ldr_act_init_context (ldr_Current_context, class_name->val, class_name->size);
// setup class attributes
if (cmd_spec->attr_type != LDR_ATTRIBUTE_ANY)
{
ldr_act_restrict_attributes (ldr_Current_context, cmd_spec->attr_type);
}
for (string_type *attr = cmd_spec->attr_list; attr; attr = attr->next)
{
ldr_act_add_attr (ldr_Current_context, attr->val, attr->size);
}
ldr_act_check_missing_non_null_attrs (ldr_Current_context);
// setup class constructor
if (cmd_spec->ctor_spec)
{
if (cmd_spec->ctor_spec->id_name)
{
ldr_act_set_constructor (ldr_Current_context, cmd_spec->ctor_spec->id_name->val);
}
for (string_type *arg = cmd_spec->ctor_spec->arg_list; arg; arg = arg->next)
{
ldr_act_add_argument (ldr_Current_context, arg->val);
}
}
}
void
sa_object_loader::init (class_id clsid)
{
(void) clsid;
// do nothing on SA_MODE
}
void
sa_object_loader::destroy ()
{
/* do not display duplicate error msg */
int err = er_filter_errid (false);
if (ldr_destroy (ldr_Current_context, 0) && err == NO_ERROR)
{
display_error (-1);
}
}
void
sa_object_loader::flush_records ()
{
; // Do nothing.
}
std::size_t
sa_object_loader::get_rows_number ()
{
// Do nothing on SA_MODE
assert (false);
return 0;
}
/*
* sa_object_loader::start_line - Finishes off the previous instance and resets the
* context to deal with a new instance.
* return: void
* object_id(in): id of current instance.
* Note:
* This is called when a new instance if found by the parser.
*/
void
sa_object_loader::start_line (int object_id)
{
// moved from grammar file;
skip_current_instance = false;
CHECK_SKIP ();
if (ldr_Current_context->valid)
{
ldr_Current_context->inst_num = object_id;
if (ldr_reset_context (ldr_Current_context) != NO_ERROR)
{
display_error (-1);
}
ldr_Current_context->instance_started = 1;
}
}
void
sa_object_loader::process_line (constant_type *cons)
{
CHECK_SKIP ();
if (er_errid () != NO_ERROR)
{
display_error (0);
CHECK_CONTEXT_VALIDITY (ldr_Current_context, true);
ldr_abort ();
return;
}
if (cons != NULL && ldr_Current_context->num_attrs == 0)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_LDR_NO_CLASS_OR_NO_ATTRIBUTE, 0);
/* diplay the msg 1 time for each class */
if (ldr_Current_context->valid)
{
display_error (0);
}
CHECK_CONTEXT_VALIDITY (ldr_Current_context, true);
ldr_abort ();
return;
}
for (constant_type *c = cons; c != NULL; c = c->next)
{
switch (c->type)
{
case LDR_NULL:
(*ldr_act) (ldr_Current_context, NULL, 0, LDR_NULL);
break;
case LDR_INT:
case LDR_FLOAT:
case LDR_DOUBLE:
case LDR_NUMERIC:
case LDR_DATE:
case LDR_TIME:
case LDR_TIMESTAMP:
case LDR_TIMESTAMPLTZ:
case LDR_TIMESTAMPTZ:
case LDR_DATETIME:
case LDR_DATETIMELTZ:
case LDR_DATETIMETZ:
case LDR_STR:
{
string_type *str = (string_type *) c->val;
(*ldr_act) (ldr_Current_context, str->val, str->size, c->type);
}
break;
case LDR_MONETARY:
{
monetary_type *mon = (monetary_type *) c->val;
string_type *str = (string_type *) mon->amount;
/* buffer size for monetary : numeric size + grammar currency symbol + string terminator */
char full_mon_str[NUM_BUF_SIZE + 3 + 1];
char *full_mon_str_p = full_mon_str;
/* In Loader grammar always print symbol before value (position of currency symbol is not localized) */
char *curr_str = intl_get_money_esc_ISO_symbol ((DB_CURRENCY) mon->currency_type);
size_t full_mon_str_len = (str->size + strlen (curr_str));
if (full_mon_str_len >= sizeof (full_mon_str))
{
full_mon_str_p = new char[full_mon_str_len + 1];
}
strcpy (full_mon_str_p, curr_str);
strcat (full_mon_str_p, str->val);
(*ldr_act) (ldr_Current_context, full_mon_str_p, strlen (full_mon_str_p), c->type);
if (full_mon_str_p != full_mon_str)
{
delete [] full_mon_str_p;
}
delete mon;
}
break;
case LDR_BSTR:
case LDR_XSTR:
case LDR_ELO_INT:
case LDR_ELO_EXT:
case LDR_SYS_USER:
case LDR_SYS_CLASS:
{
string_type *str = (string_type *) c->val;
(*ldr_act) (ldr_Current_context, str->val, str->size, c->type);
}
break;
case LDR_OID:
case LDR_CLASS_OID:
ldr_process_object_ref ((object_ref_type *) c->val, c->type);
break;
case LDR_COLLECTION:
(*ldr_act) (ldr_Current_context, "{", 1, LDR_COLLECTION);
process_line ((constant_type *) c->val);
ldr_act_attr (ldr_Current_context, NULL, 0, LDR_COLLECTION);
break;
default:
break;
}
}
}
/*
* sa_object_loader::finish_line - Completes an instance line.
* return: void
* Note:
* If there are missing attributes/arguments an error is flagged. The
* instance is inserted if it is not a class attribute modification. If
* the flush interval has been reached, the current set of instances created
* are flushed.
*/
void
sa_object_loader::finish_line ()
{
int err = NO_ERROR;
CHECK_SKIP ();
if (ldr_Current_context->valid)
{
if (ldr_Current_context->next_attr < (ldr_Current_context->num_attrs + ldr_Current_context->arg_count))
{
if (ldr_Current_context->arg_count && (ldr_Current_context->next_attr >= ldr_Current_context->arg_index))
{
err = ER_LDR_MISSING_ARGUMENT;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, err, 2, ldr_Current_context->arg_count,
ldr_Current_context->next_attr - ldr_Current_context->arg_index);
}
else
{
err = ER_LDR_MISSING_ATTRIBUTES;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, err, 2, ldr_Current_context->num_attrs,
ldr_Current_context->next_attr);
}
ldr_increment_err_count (ldr_Current_context, 1);
}
}
ldr_restore_pin_and_drop_obj (ldr_Current_context, ((ldr_Current_context->err_count != 0) || (err != NO_ERROR))
|| skip_current_instance);
CHECK_ERR (err, err);
if (ldr_Current_context->valid && !ldr_Current_context->err_count && !skip_current_instance)
{
if (ldr_Current_context->constructor)
{
err = insert_meth_instance (ldr_Current_context);
}
else if (ldr_Current_context->attr_type == LDR_ATTRIBUTE_ANY)
{
err = insert_instance (ldr_Current_context);
}
if (err == NO_ERROR)
{
if (ldr_Current_context->flush_interval
&& ldr_Current_context->inst_count >= ldr_Current_context->flush_interval)
{
err = ldr_assign_all_perm_oids ();
if (err == NO_ERROR)
{
if (!ldr_Current_context->validation_only)
{
ldr_flush (ldr_Current_context);
err = er_errid ();
if (err != NO_ERROR)
{
/* flush failed */
err = er_filter_errid (true); /* ignore warning */
if (err == NO_ERROR)
{
/* Flush error was ignored. Objects in workspace must be decached for later flush */
ws_decache_all_instances (ldr_Current_context->cls);
}
}
CHECK_ERR (err, er_errid ());
}
}
else
{
ldr_increment_err_count (ldr_Current_context, 1);
}
}
}
else
{
ldr_increment_err_count (ldr_Current_context, 1);
}
}
error_exit:
if (ldr_Current_context->err_count || (err != NO_ERROR))
{
ldr_abort ();
}
ldr_Current_context->instance_started = 0;
}
} // namespace cubload
/*
* ldr_increment_err_total - increment err_total count of the given context
* return: void
* context(out): context
*/
void
ldr_increment_err_total ()
{
if (ldr_Current_context)
{
ldr_Current_context->err_total += 1;
}
}
/*
* ldr_increment_fails - increment Total_fails count
* return: void
*/
void
ldr_increment_fails ()
{
Total_fails++;
}
/*
* ldr_increment_err_count - increment err_count of the given context
* return: void
* context(out): context
* i(in): count
*/
static void
ldr_increment_err_count (LDR_CONTEXT *context, int i)
{
if (context)
{
context->err_count += i;
}
}
/*
* ldr_clear_err_count - clear err_count of a context
* return: in
* context(out): context
*/
static void
ldr_clear_err_count (LDR_CONTEXT *context)
{
if (context)
{
context->err_count = 0;
}
}
/*
* ldr_clear_err_total - clear err_total of a context
* return: void
* context(out): context
*/
static void
ldr_clear_err_total (LDR_CONTEXT *context)
{
if (context)
{
context->err_total = 0;
}
}
/*
* ldr_class_name - Returns the name of the class currently being loaded.
* return: name
* context(in): context
* Note:
* Used predominately to get the class name when an error occurs.
*/
static const char *
ldr_class_name (LDR_CONTEXT *context)
{
const char *name = NULL;
if (context)
{
if (context->cls)
{
name = db_get_class_name (context->cls);
}
}
return name;
}
/*
* ldr_attr_name - Returns the name of the attribute we are currently dealing
* with.
* return: name
* context(in): context
* Note:
* Used predominately to get the attribute name when an error occurs.
*/
static const char *
ldr_attr_name (LDR_CONTEXT *context)
{
const char *name = NULL;
if (context && context->attrs && context->valid)
{
if (context->num_attrs >= context->next_attr)
{
if (context->num_attrs)
{
name = context->attrs[context->next_attr].att->header.name;
}
else
{
/* haven't processed an attribute yet */
name = "";
}
}
else
{
/* should return some kind of string representation for the current method argument */
name = "";
}
}
return name;
}
/*
* select_set_domain - looks through a domain list and selects a domain that
* is one of the set types.
* return: NO_ERROR if successful, error code otherwise
* context(in): context
* domain(in): target domain
* set_domain_ptr(out): returned set domain
* Note:
* Work functions for ldr_act_add*() functions, when the target type is
* collection.
* In all current cases, there will be only one element in the target
* domain list.
* Assuming there were more than one, we should be smarter and select
* the most "general" domain, for now, just pick the first one.
* NOTE : This is similar to tp_domain_select(), expect we are not dealing
* with a value here. The checking here should match the checking peformed
* by relevant code in tp_domain_select()
*/
static int
select_set_domain (LDR_CONTEXT *context, TP_DOMAIN *domain, TP_DOMAIN **set_domain_ptr)
{
int err = NO_ERROR;
TP_DOMAIN *best = NULL;
/*
* Must pick an appropriate set domain, probably we should pick
* the most general if there are more than one possibilities.
* In practice, this won't ever happen until we allow nested
* sets or union domains.
*/
for (TP_DOMAIN *d = domain; d != NULL && best == NULL; d = d->next)
{
if (TP_IS_SET_TYPE (TP_DOMAIN_TYPE (d)))
{
/* pick the first one */
best = d;
}
}
if (best == NULL)
{
err = ER_LDR_DOMAIN_MISMATCH;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, err, 4, ldr_attr_name (context), ldr_class_name (context),
domain->type->name, db_get_type_name (DB_TYPE_SET));
}
else
{
if (set_domain_ptr != NULL)
{
*set_domain_ptr = best;
}
}
return err;
}
/*
* check_object_domain - checks the type of an incoming value against the
* target domain.
* return: NO_ERROR if successful, error code otherwise
* context(in): context
* class(in): class of incoming object reference
* actual_class(out): class to expect (if first arg is NULL)
* Note:
* If they don't match LDR_DOMAIN_MISMATCH is returned.
* If "class" is NULL, we try to determine what the class will really
* be by examining the domain. If there is only one possible class
* in the domain, we return it through "actual_class".
* If there are more than one possible classes in the domain,
* we return the LDR_AMBIGUOUS_DOMAIN error.
*/
static int
check_object_domain (LDR_CONTEXT *context, DB_OBJECT *class_, DB_OBJECT **actual_class)
{
int err = NO_ERROR;
TP_DOMAIN *domain = NULL, *best = NULL;
GET_DOMAIN (context, domain);
if (class_ == NULL)
{
/* its an object but no domain was specified, see if we can unambiguously select one. */
if (domain == NULL)
{
err = ER_LDR_AMBIGUOUS_DOMAIN;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, err, 2, ldr_attr_name (context), ldr_class_name (context));
}
else
{
for (TP_DOMAIN *d = domain; d != NULL; d = d->next)
{
if (d->type == tp_Type_object)
{
if (class_ == NULL && d->class_mop != NULL)
{
class_ = d->class_mop;
}
else
{
class_ = NULL;
break;
}
}
}
if (class_ == NULL)
{
err = ER_LDR_AMBIGUOUS_DOMAIN;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, err, 2, ldr_attr_name (context), ldr_class_name (context));
}
}
}
else
{
if (domain != NULL)
{
/* make sure we have a compabile class in the domain list */
best = tp_domain_select_type (domain, DB_TYPE_OBJECT, class_, 1);
if (best == NULL)
{
err = ER_LDR_OBJECT_DOMAIN_MISMATCH;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, err, 3, ldr_attr_name (context), ldr_class_name (context),
db_get_class_name (class_));
}
}
}
if (actual_class != NULL)
{
*actual_class = class_;
}
return err;
}
/*
* check_class_domain - checks the domain for an incoming reference to an
* actual class object (not an instance).
* return: NO_ERROR if successful, error code otherwise
* context(in): context
* Note:
* For these references, the target domain must contain a wildcard
* "object" domain.
*/
static int
check_class_domain (LDR_CONTEXT *context)
{
int err = NO_ERROR;
TP_DOMAIN *domain = NULL;
GET_DOMAIN (context, domain);
/* the domain must support "object" */
if (domain != NULL)
{
for (TP_DOMAIN *d = domain; d != NULL; d = d->next)
{
if (d->type == tp_Type_object && d->class_mop == NULL)
{
goto error_exit; /* we found it */
}
}
/*
* could make this more specific but not worth the trouble
* right now, can only happen in internal trigger objects
*/
err = ER_LDR_CLASS_OBJECT_REFERENCE;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, err, 0);
}
error_exit:
return err;
}
/*
* idmap_init - Initialize the global class id map.
* return: void
*/
static void
idmap_init (void)
{
Id_map = NULL;
Id_map_size = 0;
}
/*
* idmap_final - free the class id map
* return: void
*/
static void
idmap_final (void)
{
if (Id_map != NULL)
{
free_and_init (Id_map);
Id_map_size = 0;
}
}
/*
* idmap_grow - This makes sure the class id map is large enough to accomodate
* the given index.
* return: NO_ERROR if successful, error code otherwise
* size(in): element index we want to set
*/
static int
idmap_grow (int size)
{
int err = NO_ERROR;
int newsize, i;
DB_OBJECT **id_map_old;
if (size > Id_map_size)
{
newsize = size + 10; /* some extra for growth */
id_map_old = Id_map;
Id_map = (DB_OBJECT **) realloc (Id_map, (sizeof (DB_OBJECT *) * newsize));
if (Id_map == NULL)
{
/* Prevent leakage if we get a memory problem. */
if (id_map_old)
{
free_and_init (id_map_old);
}
err = ER_LDR_MEMORY_ERROR;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, err, 0);
}
else
{
for (i = Id_map_size; i < newsize; i++)
{
Id_map[i] = NULL;
}
Id_map_size = newsize;
}
}
return err;
}
/*
* ldr_assign_class_id - assign an id to a class
* return: NO_ERROR if successful, error code otherwise
* class(in): class object
* id(in): id for this class
* Note:
* An entry will be made to the global class map.
*/
static int
ldr_assign_class_id (DB_OBJECT *class_, int id)
{
int err;
err = idmap_grow (id + 1);
if (err == NO_ERROR)
{
Id_map[id] = class_;
}
return err;
}
/*
* ldr_find_class - find a class hinting that we need the class for reading and
* for writing instances.
* return: class db_object
* class_name(in): string
* Note:
* This uses the ldr_Hint* arrays global arrays. The lock that we require
* is setup once in ldr_init_loader().
*/
static DB_OBJECT *
ldr_find_class (const char *class_name)
{
DB_OBJECT *class_ = NULL;
LC_FIND_CLASSNAME found = LC_CLASSNAME_EXIST;
char realname[DB_MAX_IDENTIFIER_LENGTH] = { '\0' };
/* Check for internal error */
if (class_name == NULL || class_name[0] == '\0')
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_GENERIC_ERROR, 0);
display_error (0);
return NULL;
}
sm_user_specified_name (class_name, realname, DB_MAX_IDENTIFIER_LENGTH);
ldr_Hint_class_names[0] = realname;
found = locator_lockhint_classes (1, ldr_Hint_class_names, ldr_Hint_locks, ldr_Hint_subclasses, ldr_Hint_flags, 1,
NULL_LOCK);
if (found == LC_CLASSNAME_EXIST)
{
class_ = db_find_class (class_name);
ldr_Hint_class_names[0] = NULL;
return class_;
}
/* This is the case when the loaddb utility is executed with the --no-user-specified-name option as the dba user. */
if (db_get_client_type() == DB_CLIENT_TYPE_ADMIN_LOADDB_COMPAT_UNDER_11_2)
{
/* Called by ldr_sa_load or ldr_server_load to load an object file; DDL must not be executed. */
assert (db_get_client_statement_type () == CUBRID_STMT_NONE);
char other_class_name[DB_MAX_IDENTIFIER_LENGTH] = { '\0' };
ldr_find_class_by_query (realname, other_class_name, DB_MAX_IDENTIFIER_LENGTH);
if (other_class_name[0] != '\0')
{
ldr_Hint_class_names[0] = other_class_name;
found = locator_lockhint_classes (1, ldr_Hint_class_names, ldr_Hint_locks, ldr_Hint_subclasses, ldr_Hint_flags, 1,
NULL_LOCK);
if (found == LC_CLASSNAME_EXIST)
{
class_ = db_find_class (other_class_name);
ldr_Hint_class_names[0] = NULL;
return class_;
}
}
}
ldr_Hint_class_names[0] = NULL;
return class_;
}
static int
ldr_find_class_by_query (const char *name, char *buf, int buf_size)
{
#define QUERY_BUF_SIZE 2048
DB_QUERY_RESULT *query_result = NULL;
DB_QUERY_ERROR query_error;
DB_VALUE value;
const char *query = NULL;
char query_buf[QUERY_BUF_SIZE] = { '\0' };
const char *current_schema_name = NULL;
const char *class_name = NULL;
char qualifier_name[DB_MAX_USER_LENGTH] = { '\0' };
int error = NO_ERROR;
db_make_null (&value);
query_error.err_lineno = 0;
query_error.err_posno = 0;
if (name == NULL || name[0] == '\0')
{
ERROR_SET_WARNING (error, ER_OBJ_INVALID_ARGUMENTS);
return error;
}
assert (buf != NULL);
current_schema_name = sc_current_schema_name ();
if (sm_qualifier_name (name, qualifier_name, DB_MAX_USER_LENGTH) != NULL)
{
if (strcmp (qualifier_name, current_schema_name) != 0)
{
/* Additional cross-schema object lookups during an ongoing cross-schema lookup
* are beyond the scope of the compatibility option */
assert (intl_identifier_casecmp (name, qualifier_name) != 0);
ERROR_SET_WARNING_1ARG (error, ER_LC_UNKNOWN_CLASSNAME, name);
return error;
}
}
class_name = sm_remove_qualifier_name (name);
query = "SELECT [unique_name] FROM [%s] WHERE [class_name] = '%s' AND [owner].[name] != UPPER ('%s')";
assert (QUERY_BUF_SIZE > snprintf (NULL, 0, query, CT_CLASS_NAME, class_name, current_schema_name));
snprintf (query_buf, QUERY_BUF_SIZE, query, CT_CLASS_NAME, class_name, current_schema_name);
assert (query_buf[0] != '\0');
error = db_compile_and_execute_local (query_buf, &query_result, &query_error);
if (error < NO_ERROR)
{
ASSERT_ERROR ();
goto end;
}
error = db_query_first_tuple (query_result);
if (error != DB_CURSOR_SUCCESS)
{
if (error == DB_CURSOR_END)
{
ERROR_SET_WARNING_1ARG (error, ER_LC_UNKNOWN_CLASSNAME, name);
}
else
{
ASSERT_ERROR ();
}
goto end;
}
error = db_query_get_tuple_value (query_result, 0, &value);
if (error != NO_ERROR)
{
ASSERT_ERROR ();
goto end;
}
if (!DB_IS_NULL (&value))
{
assert (STATIC_CAST (int, strlen (db_get_string (&value))) < buf_size);
strncpy (buf, db_get_string (&value), buf_size -1);
buf[buf_size -1] = '\0';
}
else
{
/* unique_name must not be null. */
ASSERT_ERROR_AND_SET (error);
goto end;
}
error = db_query_next_tuple (query_result);
if (error != DB_CURSOR_END)
{
/* No result can be returned because unique_name is not unique. */
buf[0] = '\0';
}
end:
if (query_result)
{
db_query_end (query_result);
query_result = NULL;
}
return error;
#undef QUERY_BUF_SIZE
}
/*
* ldr_get_class_from_id - return the class with the given 'id' from global
* class id map
* return: class object
* id(in): class id
*/
static DB_OBJECT *
ldr_get_class_from_id (int id)
{
DB_OBJECT *class_ = NULL;
if (id <= Id_map_size)
{
class_ = Id_map[id];
}
return (class_);
}
/*
* ldr_clear_context - clears any information on the class/attribute/argument
* definitions that have been made.
* return: void
* context(out): current context
*/
static void
ldr_clear_context (LDR_CONTEXT *context)
{
context->cls = NULL;
context->class_name = NULL;
context->obj = NULL;
context->mobj = NULL;
context->obj_pin = 0;
context->class_pin = 0;
context->class_type = DB_NOT_PARTITIONED_CLASS;
context->attrs = NULL;
context->num_attrs = 0;
context->next_attr = 0;
context->instance_started = 0;
context->valid = false;
/* verbose and periodic_commit are should be set out side this function */
ldr_clear_err_count (context);
/* error_total should not be reset here */
context->inst_count = 0;
context->inst_total = 0;
context->inst_num = -1;
// not sure the param helps, however I don't like to change the existing behavior.
// We may remove it someday.
context->flush_interval = prm_get_integer_value (PRM_ID_LOADDB_FLUSH_INTERVAL);
if (context->args->periodic_commit <= context->flush_interval)
{
// deactive flush_interval, since it is useless for this case
context->flush_interval = 0;
}
context->table = NULL;
/* validation_only, lang_id flag should be set outside this function */
context->collection = NULL;
context->set_domain = NULL;
context->constructor = NULL;
context->arg_index = 0;
context->max_arg = 0;
context->method_args = NULL;
context->arg_count = 0;
context->id_class = NULL;
context->attr_type = LDR_ATTRIBUTE_ANY;
}
/*
* ldr_clear_and_free_context - Frees up the space allocated for the
* constructor strings, attribute descriptors and args array.
* return: void
* context(in/out): current context
* Note:
* Called if we have an internal error, or when we finish processing each
* class.
*/
static void
ldr_clear_and_free_context (LDR_CONTEXT *context)
{
int i;
if (context->attrs)
{
for (i = 0; i < (context->num_attrs + context->arg_count); i += 1)
{
if (context->attrs[i].parser_str)
{
free_and_init (context->attrs[i].parser_str);
}
if (context->attrs[i].attdesc)
{
db_free_attribute_descriptor (context->attrs[i].attdesc);
}
context->attrs[i].attdesc = NULL;
}
free_and_init (context->attrs);
}
if (context->method_args)
{
free_and_init (context->method_args);
}
if (context->class_name)
{
free_and_init (context->class_name);
}
ldr_clear_context (context);
}
/*
* LOADER ERROR NOTIFICATION
*
* There are two levels of error handling here. When a call
* is made to a ldr_ function, those functions will return a int
* and use er_set to set the global error state. For those errors,
* we simply use db_error_string to get the text and display it.
*
* Other errors are detected by the action routines in this file.
* For these, we don't use er_set since it isn't really necessary. Instead
* we just have message catalog entries for the error text we wish
* to display.
*
*/
/*
* ldr_internal_error - handle internal error
* return: void
* context(in/out): context
* Note:
* This can be called by an upper level when an error is detected
* and we need to reset the internal loader state.
* Call this when serious errors are encountered and we need to
* stop immediately. Probably we could longjmp out of parser here to
* avoid parsing the rest of the file.
*/
static void
ldr_internal_error (LDR_CONTEXT *context)
{
ldr_clear_and_free_context (context);
ldr_abort ();
}
/*
* display_error_line - display error line
* return: void
* adjust(in): line number adjuster
* Note:
* This will display the line number of the current input file.
* It is intended to give error messages context within the file.
* Its public because there are a few places in the loader internals
* where we need to display messages without propogating
* errors back up to the action routine level.
*/
static void
display_error_line (int adjust)
{
int lineno = 0;
if (adjust != 0)
{
// In case of adjustment required, use the old behavior of using the scanner line.
lineno = ldr_Driver->get_scanner ().lineno() + adjust;
}
else
{
// No adjustment needed, we can report the current line.
lineno = ldr_Driver->get_start_line ();
}
if (lineno == 0)
{
// Most likely parsing hasn't started yet so we should not print the line number.
return;
}
fprintf (stderr, msgcat_message (MSGCAT_CATALOG_UTILS, MSGCAT_UTIL_SET_LOADDB, LOADDB_MSG_LINE), lineno);
}
/*
* display_error - ldr_ function error handler
* return: void
* adjust(in): line number adjuster
* Note:
* This is called whenever one of the ldr_ functions returns
* an error. In this case, a standard system error has been set
* and the text is obtained through db_error_string.
*/
static void
display_error (int adjust)
{
const char *msg;
display_error_line (adjust);
msg = db_error_string (3);
fprintf (stderr, msg);
fprintf (stderr, "\n");
}
/*
* ldr_invalid_class_error - invalid class error handler
* return: void
* context(in): context
* Note:
* Called when the name of an invalid class reference was specified.
*/
static void
ldr_invalid_class_error (LDR_CONTEXT *context)
{
display_error_line (0);
fprintf (stderr, msgcat_message (MSGCAT_CATALOG_UTILS, MSGCAT_UTIL_SET_LOADDB, LOADDB_MSG_UNKNOWN_ATT_CLASS),
ldr_attr_name (context), ldr_class_name (context));
}
/*
* parse_error - parse error handler
* return: void
* context(in): context
* token_type(in): incoming token type
* token(in): token string
* Note:
* Called when we have some sort of parsing problem with an incoming
* token that made it past parser's initial level of checking.
* System errors have not been set.
* This is called by serveral of the setters.
*/
static void
parse_error (LDR_CONTEXT *context, DB_TYPE token_type, const char *token)
{
display_error_line (0);
/*
* This is called when we experience an error when performing a string to
* DB_TYPE conversion. Called via CHECK_PARSE_ERR() macro.
*/
fprintf (stderr, msgcat_message (MSGCAT_CATALOG_UTILS, MSGCAT_UTIL_SET_LOADDB, LOADDB_MSG_PARSE_ERROR), token,
db_get_type_name (token_type), ldr_attr_name (context), ldr_class_name (context));
}
/*
* clist_init - Initializes the list of internal classes.
* return: NO_ERROR if successful, error code otherwise
* Note:
* These are the classes that we don't allow to be loaded.
*/
static int
clist_init (void)
{
DB_OBJECT *class_;
internal_classes = NULL;
class_ = db_find_class (AU_ROOT_CLASS_NAME);
if (class_ != NULL)
{
if (ml_ext_add (&internal_classes, class_, NULL))
{
assert (er_errid () != NO_ERROR);
return er_errid ();
}
}
class_ = db_find_class (AU_USER_CLASS_NAME);
if (class_ != NULL)
{
if (ml_ext_add (&internal_classes, class_, NULL))
{
assert (er_errid () != NO_ERROR);
return er_errid ();
}
}
class_ = db_find_class (AU_PASSWORD_CLASS_NAME);
if (class_ != NULL)
{
if (ml_ext_add (&internal_classes, class_, NULL))
{
assert (er_errid () != NO_ERROR);
return er_errid ();
}
}
class_ = db_find_class (AU_AUTH_CLASS_NAME);
if (class_ != NULL)
{
if (ml_ext_add (&internal_classes, class_, NULL))
{
assert (er_errid () != NO_ERROR);
return er_errid ();
}
}
return NO_ERROR;
}
/*
* clist_final - free the list of internal classes
* return: void
*/
static void
clist_final (void)
{
ml_ext_free (internal_classes);
internal_classes = NULL;
}
/*
* is_internal_class - test to see if a class is an internal class
* return: non-zero if this is an internal class
* class(in): class to examine
*/
static int
is_internal_class (DB_OBJECT *class_)
{
return (ml_find (internal_classes, class_));
}
/*
* LEXER ACTION ROUTINES
*
* These routines are, for the most part, just dispatchers. They allow us
* factor out the information about the form of the incoming string (i.e.,
* we know that it's an integer, a quoted string, a numeric, or a real),
* which allows the the function we dispatch to to make certain significant
* optimizations (usually based on the domain of the attribute it's known to
* be setting).
*/
/*
* ldr_act_attr - Invokes the appropriate setter from a vector of setters
* indexed by the parser type.
* return: void
* context(in/out): current context
* str(in): parser token
* len(in): length of token
* type(in): Parser type
*/
static void
ldr_act_attr (LDR_CONTEXT *context, const char *str, size_t len, data_type type)
{
LDR_ATTDESC *attdesc;
int err = NO_ERROR;
CHECK_SKIP ();
/* we have reached an invalid state, ignore the tuples */
RETURN_IF_NOT_VALID (context);
if (context->next_attr >= context->num_attrs)
{
context->valid = false;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_LDR_VALUE_OVERFLOW, 1, context->num_attrs);
CHECK_ERR (err, ER_LDR_VALUE_OVERFLOW);
goto error_exit;
}
if (context->validation_only)
{
switch (type)
{
/*
* For validation only simply parse the set elements, by switching
* to the element setter
*/
case LDR_COLLECTION:
/* ending brace of collection */
if (str == NULL)
{
ldr_act = ldr_act_attr;
goto error_exit;
}
else
{
ldr_act = ldr_act_elem;
return;
}
/* Check validity of date/time/timestamp string during validation */
case LDR_TIME:
case LDR_DATE:
case LDR_TIMESTAMP:
case LDR_TIMESTAMPLTZ:
case LDR_TIMESTAMPTZ:
case LDR_DATETIME:
case LDR_DATETIMELTZ:
case LDR_DATETIMETZ:
CHECK_ERR (err, ldr_check_date_time_conversion (str, type));
break;
default:
break;
}
}
else
{
attdesc = &context->attrs[context->next_attr];
CHECK_ERR (err, (* (attdesc->setter[type])) (context, str, len, attdesc->att));
}
error_exit:
context->next_attr += 1;
ldr_increment_err_count (context, (err != NO_ERROR));
}
/*
* ldr_act_elem - Invokes the appropriate converter from a set of vectored
* converters indexed by the parser type.
* return: void
* context(in/out): current context
* str(in): parser token
* len(in): length of token
* type(in): Parser type
* Note:
* If an object reference is encountered we need to use a special
* function set_new_element() to generate a collection element, since we
* are dealing with DB_TYPE_OIDs not DB_TYPE_OBJECT.
* assign_set_value(), called by set_add_element(), calls
* tp_domain_check(), and tp_value_cast to determine if the domains are
* compatible, for DB_TYPE_OID, these do not return DB_DOMAIN_COMPATIBLE
* for DB_OBJECT and DB_OID.
*/
static void
ldr_act_elem (LDR_CONTEXT *context, const char *str, size_t len, data_type type)
{
DB_VALUE tempval;
int err = NO_ERROR;
/* we have reached an invalid state, ignore the tuples */
RETURN_IF_NOT_VALID (context);
if (context->validation_only)
{
switch (type)
{
/*
* For validation only simply parse the set elements, by switching
* to the element setter
*/
case LDR_COLLECTION:
err = ER_LDR_NESTED_SET;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, err, 0);
display_error (0);
break;
/* Check validity of date/time/timestamp string during validation */
case LDR_TIME:
case LDR_DATE:
case LDR_TIMESTAMP:
case LDR_TIMESTAMPLTZ:
case LDR_TIMESTAMPTZ:
case LDR_DATETIME:
case LDR_DATETIMELTZ:
case LDR_DATETIMETZ:
CHECK_ERR (err, ldr_check_date_time_conversion (str, type));
break;
default:
break;
}
}
else
{
CHECK_ERR (err, (* (elem_converter[type])) (context, str, len, &tempval));
if ((err = set_add_element (context->collection, &tempval)) == ER_SET_DOMAIN_CONFLICT)
{
display_error_line (0);
fprintf (stderr, msgcat_message (MSGCAT_CATALOG_UTILS, MSGCAT_UTIL_SET_LOADDB, LOADDB_MSG_SET_DOMAIN_ERROR),
ldr_attr_name (context), ldr_class_name (context), db_get_type_name (db_value_type (&tempval)));
CHECK_ERR (err, ER_SET_DOMAIN_CONFLICT);
}
else
{
CHECK_ERR (err, err);
}
}
error_exit:
ldr_increment_err_count (context, (err != NO_ERROR));
}
/*
* ldr_act_meth - set up the attr desc for an instance generated via a
* constructor.
* return: void
* context(in/out): current context
* str(in): parser token
* len(in): length of token
* type(in): Parser type
* Note:
* This simulates the parse phase here.
*/
static void
ldr_act_meth (LDR_CONTEXT *context, const char *str, size_t len, data_type type)
{
int err = NO_ERROR;
LDR_ATTDESC *attdesc = NULL;
/* we have reached an invalid state, ignore the tuples */
RETURN_IF_NOT_VALID (context);
if ((context->next_attr) >= (context->num_attrs + context->arg_count))
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_LDR_UNEXPECTED_ARGUMENT, 1, context->arg_count);
CHECK_ERR (err, ER_LDR_UNEXPECTED_ARGUMENT);
}
CHECK_VALIDATION_ONLY (context);
attdesc = &context->attrs[context->next_attr];
/*
* Save the parser buffer and type information, this will be
* used later to feed to the fast setters to populate the
* constructor generated instance
* Attempt to reuse the strings buffers.
*/
if (attdesc->parser_buf_len == 0)
{
attdesc->parser_str = (char *) (malloc (len + 1));
if (attdesc->parser_str == NULL)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_LDR_MEMORY_ERROR, 0);
}
CHECK_PTR (err, attdesc->parser_str);
attdesc->parser_buf_len = len;
}
else if (len > attdesc->parser_buf_len)
{
char *parser_str_old;
parser_str_old = attdesc->parser_str;
/* Prevent leak from realloc call failure */
attdesc->parser_str = (char *) realloc (attdesc->parser_str, len + 1);
if (attdesc->parser_str == NULL)
{
/* Prevent leakage if realloc fails */
free_and_init (parser_str_old);
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_LDR_MEMORY_ERROR, 0);
}
CHECK_PTR (err, attdesc->parser_str);
attdesc->parser_buf_len = len;
}
memcpy (attdesc->parser_str, str, len + 1);
attdesc->parser_type = type;
attdesc->parser_str_len = len;
error_exit:
context->next_attr += 1;
ldr_increment_err_count (context, (err != NO_ERROR));
}
/*
* ldr_mismatch - always error handler.
* return: ER_OBJ_DOMAIN_CONFLICT
* context(in): not used
* str(in): not used
* len(in): not used
* att(in): attribute
*/
static int
ldr_mismatch (LDR_CONTEXT *context, const char *str, size_t len, SM_ATTRIBUTE *att)
{
int err;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OBJ_DOMAIN_CONFLICT, 1, att->header.name);
CHECK_ERR (err, ER_OBJ_DOMAIN_CONFLICT);
error_exit:
return err;
}
/*
* ldr_ignore - always ignoring handler.
* return: ER_OBJ_DOMAIN_CONFLICT
* context(in): not used
* str(in): not used
* len(in): not used
* att(in): not used
*/
static int
ldr_ignore (LDR_CONTEXT *context, const char *str, size_t len, SM_ATTRIBUTE *att)
{
/*
* No need to set an error here, we've already issued a message when we were
* studying the attribute in ldr_act_add_attr(). Just return an error code
* so that the caller will increment context->err_count, causing us to
* skip the row rather than flush it.
*/
return ER_OBJ_DOMAIN_CONFLICT;
}
/*
* ldr_generic - set attribute value
* return: NO_ERROR if successful, error code otherwise
* context(in): context
* value(in): DB_VALUE
*/
static int
ldr_generic (LDR_CONTEXT *context, DB_VALUE *value)
{
int err;
CHECK_ERR (err, obj_desc_set (context->obj, context->attrs[context->next_attr].attdesc, value));
error_exit:
return err;
}
/*
* ldr_null_elem - set db value to null
* return: NO_ERROR
* context(in):
* str(in): not used
* len(in): not used
* val(out): DB_VALUE
*/
static int
ldr_null_elem (LDR_CONTEXT *context, const char *str, size_t len, DB_VALUE *val)
{
db_make_null (val);
return NO_ERROR;
}
/*
* ldr_null_db_generic - set attribute value to null
* return:
* context(in): context
* str(in): not used
* len(in): not used
* att(att): memory representation of attribute
*/
static int
ldr_null_db_generic (LDR_CONTEXT *context, const char *str, size_t len, SM_ATTRIBUTE *att)
{
int err = NO_ERROR;
char *mem;
if (att->flags & SM_ATTFLAG_NON_NULL)
{
char class_attr[DB_MAX_IDENTIFIER_LENGTH * 2];
snprintf (class_attr, DB_MAX_IDENTIFIER_LENGTH * 2, "%s.%s", context->class_name, att->header.name);
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OBJ_ATTRIBUTE_CANT_BE_NULL, 1, class_attr);
CHECK_ERR (err, ER_OBJ_ATTRIBUTE_CANT_BE_NULL);
}
else
{
mem = context->mobj + att->offset;
CHECK_ERR (err, att->domain->type->setmem (mem, att->domain, NULL));
if (!att->domain->type->variable_p)
{
OBJ_CLEAR_BOUND_BIT (context->mobj, att->storage_order);
}
}
error_exit:
return err;
}
/*
* ldr_class_attr_db_generic - set attribute of a class
* return: NO_ERROR if successful, error code otherwise
* context(in/out): context
* str(in): not used
* len(in): not used
* att(in): memory representation of attribute
* val(in): value to set
* Note:
* This is a special setter, and is not called via the same process as the
* other setters. i.e., ldr_act(). This is called by ldr_act_class_attr().
*/
static int
ldr_class_attr_db_generic (LDR_CONTEXT *context, const char *str, size_t len, SM_ATTRIBUTE *att, DB_VALUE *val)
{
int err = NO_ERROR;
if (att->header.name_space == ID_SHARED_ATTRIBUTE)
{
CHECK_ERR (err, obj_set_shared (context->cls, att->header.name, val));
}
else if (att->header.name_space == ID_CLASS_ATTRIBUTE)
{
CHECK_ERR (err, obj_set (context->cls, att->header.name, val));
}
else if (context->attr_type == LDR_ATTRIBUTE_DEFAULT)
{
CHECK_ERR (err, db_change_default (context->cls, att->header.name, val));
}
error_exit:
return err;
}
/*
* ldr_act_class_attr -
* return:
* context():
* str():
* len():
* type():
*/
static void
ldr_act_class_attr (LDR_CONTEXT *context, const char *str, size_t len, data_type type)
{
int err = NO_ERROR;
DB_VALUE src_val, dest_val, *val;
TP_DOMAIN *domain;
/* we have reached an invalid state, ignore the tuples */
RETURN_IF_NOT_VALID (context);
CHECK_VALIDATION_ONLY (context);
if (context->next_attr >= context->num_attrs)
{
context->valid = false;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_LDR_VALUE_OVERFLOW, 1, context->num_attrs);
CHECK_ERR (err, ER_LDR_VALUE_OVERFLOW);
}
if (type == LDR_COLLECTION)
{
if (context->attrs[context->next_attr].collection_domain == NULL)
{
CHECK_CONTEXT_VALIDITY (context, true);
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OBJ_DOMAIN_CONFLICT, 1,
context->attrs[context->next_attr].att->header.name);
CHECK_ERR (err, ER_OBJ_DOMAIN_CONFLICT);
}
CHECK_ERR (err, ldr_collection_db_collection (context, str, len, context->attrs[context->next_attr].att));
}
else
{
CHECK_ERR (err, (* (elem_converter[type])) (context, str, len, &src_val));
GET_DOMAIN (context, domain);
CHECK_ERR (err, db_value_domain_init (&dest_val, TP_DOMAIN_TYPE (domain), domain->precision, domain->scale));
val = &dest_val;
/* tp_value_cast does not handle DB_TYPE_OID coersions, simply use the value returned by the elem converter. */
if (type == LDR_OID || type == LDR_CLASS_OID)
{
if (TP_DOMAIN_TYPE (domain) == DB_TYPE_OBJECT)
{
val = &src_val;
}
else
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OBJ_DOMAIN_CONFLICT, 1,
context->attrs[context->next_attr].att->header.name);
CHECK_ERR (err, ER_OBJ_DOMAIN_CONFLICT);
}
}
else if (tp_value_cast (&src_val, &dest_val, domain, false))
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OBJ_DOMAIN_CONFLICT, 1,
context->attrs[context->next_attr].att->header.name);
CHECK_PARSE_ERR (err, ER_OBJ_DOMAIN_CONFLICT, context, TP_DOMAIN_TYPE (domain), str);
}
CHECK_ERR (err, ldr_class_attr_db_generic (context, str, len, context->attrs[context->next_attr].att, val));
}
error_exit:
context->next_attr += 1;
ldr_increment_err_count (context, (err != NO_ERROR));
}
/*
* ldr_sys_user_db_generic -
* return:
* context():
* str():
* len():
* att():
*/
static int
ldr_sys_user_db_generic (LDR_CONTEXT *context, const char *str, size_t len, SM_ATTRIBUTE *att)
{
display_error_line (0);
fprintf (stderr, msgcat_message (MSGCAT_CATALOG_UTILS, MSGCAT_UTIL_SET_LOADDB, LOADDB_MSG_UNAUTHORIZED_CLASS),
"db_user");
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_GENERIC_ERROR, 0);
ldr_increment_err_count (context, 1);
return (ER_GENERIC_ERROR);
}
/*
* ldr_sys_class_db_generic -
* return:
* context():
* str():
* len():
* att():
*/
static int
ldr_sys_class_db_generic (LDR_CONTEXT *context, const char *str, size_t len, SM_ATTRIBUTE *att)
{
display_error_line (0);
fprintf (stderr, msgcat_message (MSGCAT_CATALOG_UTILS, MSGCAT_UTIL_SET_LOADDB, LOADDB_MSG_UNAUTHORIZED_CLASS),
"*system class*");
CHECK_CONTEXT_VALIDITY (context, true);
ldr_increment_err_count (context, 1);
return (NO_ERROR);
}
/*
* INT SETTERS
*
* These functions (ldr_int_db_*) are called when int constants are
* processed by the lexer. They probably only make sense for int, float,
* double, and numeric types. An "int" string is known to consist only of
* digits with an optional preceding sign character.
*
* Right now we don't have a special handler for DB_TYPE_SHORT attributes.
* We may want to build one if they turn out to be prevalent. That handler
* would have to be on the lookout for overflow situations. (For that
* matter, ldr_int_db_int maybe ought to look out for it too.)
*/
/*
* ldr_int_elem -
* return:
* context():
* str():
* len():
* val():
*/
static int
ldr_int_elem (LDR_CONTEXT *context, const char *str, size_t len, DB_VALUE *val)
{
int err = NO_ERROR;
int result = 0;
/*
* Watch out for really long digit strings that really are being
* assigned into a DB_TYPE_NUMERIC attribute; they can hold more than a
* standard integer can, and calling atol() on that string will lose
* data.
* Is there some better way to test for this condition?
*/
if (len < MAX_DIGITS_FOR_INT || (len == MAX_DIGITS_FOR_INT && (str[0] == '0' || str[0] == '1')))
{
val->domain = ldr_int_tmpl.domain;
result = parse_int (&val->data.i, str, 10);
if (result != 0)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_IT_DATA_OVERFLOW, 1, db_get_type_name (DB_TYPE_INTEGER));
CHECK_PARSE_ERR (err, ER_IT_DATA_OVERFLOW, context, DB_TYPE_INTEGER, str);
}
}
else if (len < MAX_DIGITS_FOR_BIGINT || (len == MAX_DIGITS_FOR_BIGINT && str[0] != '9'))
{
val->domain = ldr_bigint_tmpl.domain;
result = parse_bigint (&val->data.bigint, str, 10);
if (result != 0)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_IT_DATA_OVERFLOW, 1, db_get_type_name (DB_TYPE_BIGINT));
CHECK_PARSE_ERR (err, ER_IT_DATA_OVERFLOW, context, DB_TYPE_BIGINT, str);
}
}
else
{
DB_NUMERIC num;
DB_BIGINT tmp_bigint;
numeric_coerce_dec_str_to_num (str, num.d.buf);
if (numeric_coerce_num_to_bigint (num.d.buf, 0, &tmp_bigint) != NO_ERROR)
{
CHECK_PARSE_ERR (err, db_value_domain_init (val, DB_TYPE_NUMERIC, (int) len, 0), context, DB_TYPE_BIGINT, str);
CHECK_PARSE_ERR (err, db_value_put (val, DB_TYPE_C_CHAR, (char *) str, (int) len), context, DB_TYPE_BIGINT, str);
}
else
{
val->domain = ldr_bigint_tmpl.domain;
val->data.bigint = tmp_bigint;
}
}
error_exit:
return err;
}
/*
* ldr_int_db_generic -
* return:
* context():
* str():
* len():
* att():
*/
static int
ldr_int_db_generic (LDR_CONTEXT *context, const char *str, size_t len, SM_ATTRIBUTE *att)
{
int err;
DB_VALUE val;
CHECK_ERR (err, ldr_int_elem (context, str, len, &val));
CHECK_ERR (err, ldr_generic (context, &val));
error_exit:
return err;
}
/*
* ldr_int_db_bigint -
* return:
* context():
* str():
* len():
* att():
*/
static int
ldr_int_db_bigint (LDR_CONTEXT *context, const char *str, size_t len, SM_ATTRIBUTE *att)
{
char *mem;
int err;
int result = 0;
DB_VALUE val;
val.domain = ldr_bigint_tmpl.domain;
/* Let try take the fastest path here, if we know that number we are getting fits into a long, use strtol, else we
* need to convert it to a double and coerce it, checking for overflow. Note if integers with leading zeros are
* entered this can take the slower route. */
if (len < MAX_DIGITS_FOR_BIGINT || (len == MAX_DIGITS_FOR_BIGINT && str[0] != '9'))
{
result = parse_bigint (&val.data.bigint, str, 10);
if (result != 0)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_IT_DATA_OVERFLOW, 1, db_get_type_name (DB_TYPE_BIGINT));
CHECK_PARSE_ERR (err, ER_IT_DATA_OVERFLOW, context, DB_TYPE_BIGINT, str);
}
}
else
{
DB_NUMERIC num;
DB_BIGINT tmp_bigint;
numeric_coerce_dec_str_to_num (str, num.d.buf);
if (numeric_coerce_num_to_bigint (num.d.buf, 0, &tmp_bigint) != NO_ERROR)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_IT_DATA_OVERFLOW, 1, db_get_type_name (DB_TYPE_BIGINT));
CHECK_PARSE_ERR (err, ER_IT_DATA_OVERFLOW, context, DB_TYPE_BIGINT, str);
}
else
{
val.data.bigint = tmp_bigint;
}
}
mem = context->mobj + att->offset;
CHECK_ERR (err, att->domain->type->setmem (mem, att->domain, &val));
OBJ_SET_BOUND_BIT (context->mobj, att->storage_order);
error_exit:
return err;
}
/*
* ldr_int_db_int -
* return:
* context():
* str():
* len():
* att():
*/
static int
ldr_int_db_int (LDR_CONTEXT *context, const char *str, size_t len, SM_ATTRIBUTE *att)
{
char *mem;
int err;
int result = 0;
DB_VALUE val;
char *str_ptr;
val.domain = ldr_int_tmpl.domain;
/* Let try take the fastest path here, if we know that number we are getting fits into a long, use strtol, else we
* need to convert it to a double and coerce it, checking for overflow. Note if integers with leading zeros are
* entered this can take the slower route. */
if (len < MAX_DIGITS_FOR_INT || (len == MAX_DIGITS_FOR_INT && (str[0] == '0' || str[0] == '1')))
{
result = parse_int (&val.data.i, str, 10);
if (result != 0)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_IT_DATA_OVERFLOW, 1, db_get_type_name (DB_TYPE_INTEGER));
CHECK_PARSE_ERR (err, ER_IT_DATA_OVERFLOW, context, DB_TYPE_INTEGER, str);
}
}
else
{
double d;
d = strtod (str, &str_ptr);
if (str_ptr == str || OR_CHECK_INT_OVERFLOW (d))
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_IT_DATA_OVERFLOW, 1, db_get_type_name (DB_TYPE_INTEGER));
CHECK_PARSE_ERR (err, ER_IT_DATA_OVERFLOW, context, DB_TYPE_INTEGER, str);
}
else
{
val.data.i = ROUND (d);
}
}
mem = context->mobj + att->offset;
CHECK_ERR (err, att->domain->type->setmem (mem, att->domain, &val));
OBJ_SET_BOUND_BIT (context->mobj, att->storage_order);
error_exit:
return err;
}
/*
* ldr_int_db_short -
* return:
* context():
* str():
* len():
* att():
*/
static int
ldr_int_db_short (LDR_CONTEXT *context, const char *str, size_t len, SM_ATTRIBUTE *att)
{
char *mem;
int err;
int result = 0;
DB_VALUE val;
char *str_ptr;
val.domain = ldr_short_tmpl.domain;
/* Let try take the fastest path here, if we know that number we are getting fits into a long, use strtol, else we
* need to convert it to a double and coerce it, checking for overflow. Note if integers with leading zeros are
* entered this can take the slower route. */
if (len > MAX_DIGITS_FOR_SHORT)
{
double d;
d = strtod (str, &str_ptr);
if (str_ptr == str || OR_CHECK_SHORT_OVERFLOW (d))
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_IT_DATA_OVERFLOW, 1, db_get_type_name (DB_TYPE_SHORT));
CHECK_PARSE_ERR (err, ER_IT_DATA_OVERFLOW, context, DB_TYPE_SHORT, str);
}
else
{
val.data.sh = ROUND (d);
}
}
else
{
int i_val;
result = parse_int (&i_val, str, 10);
if (result != 0)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_IT_DATA_OVERFLOW, 1, db_get_type_name (DB_TYPE_SHORT));
CHECK_PARSE_ERR (err, ER_IT_DATA_OVERFLOW, context, DB_TYPE_SHORT, str);
}
val.data.sh = (short) i_val;
}
mem = context->mobj + att->offset;
CHECK_ERR (err, att->domain->type->setmem (mem, att->domain, &val));
OBJ_SET_BOUND_BIT (context->mobj, att->storage_order);
error_exit:
return err;
}
/*
* STRING SETTERS
*
* These functions (ldr_str_db_*) are called when quoted strings are
* processed by the lexer. They probably only make sense for char, varchar,
* bit, and varbit domains.
*
* WARNING: these functions cheat and assume a char-is-a-byte model, which
* won't work when dealing with non-ASCII (or non-Latin, at least) charsets.
* We'll need new versions to cope with those other charsets, but DON'T ADD
* CHARSET TESTING INTO THE BODIES OF THESE FUNCTIONS. Move those tests WAY
* out into the initialization code, and initialize function pointers to
* point to fast (ASCII) or slow (e.g., S-JIS) versions.
*/
/*
* ldr_str_elem -
* return:
* context():
* str():
* len():
* val():
*/
static int
ldr_str_elem (LDR_CONTEXT *context, const char *str, size_t len, DB_VALUE *val)
{
/* todo: switch this to db_make_string_copy and avoid any possible leaks */
db_make_string (val, str);
return NO_ERROR;
}
/*
* ldr_str_db_char -
* return:
* context():
* str():
* len():
* att():
*/
static int
ldr_str_db_char (LDR_CONTEXT *context, const char *str, size_t len, SM_ATTRIBUTE *att)
{
char *mem;
int precision;
int err;
DB_VALUE val;
precision = att->domain->precision;
/* char_count <= byte_count in every codeset, so byte_size <= precision guarantees no truncation */
if ((int) len > precision)
{
int char_count = 0;
intl_char_count ((unsigned char *) str, (int) len, (INTL_CODESET) att->domain->codeset, &char_count);
if (char_count > precision)
{
/*
* May be a violation, but first we have to check for trailing pad
* characters that might allow us to successfully truncate the
* thing.
*/
int safe;
const char *p;
int truncate_size;
intl_char_size ((unsigned char *) str, precision, (INTL_CODESET) att->domain->codeset, &truncate_size);
for (p = &str[truncate_size], safe = 1; p < &str[len]; p++)
{
if (*p != ' ')
{
safe = 0;
break;
}
}
if (safe)
{
len = truncate_size;
}
else
{
/*
* It's a genuine violation; raise an error.
*/
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_IT_DATA_OVERFLOW, 1, db_get_type_name (DB_TYPE_CHAR));
CHECK_PARSE_ERR (err, ER_IT_DATA_OVERFLOW, context, DB_TYPE_CHAR, str);
}
}
}
val.domain = ldr_char_tmpl.domain;
val.domain.char_info.length = precision;
val.data.ch.info.style = MEDIUM_STRING;
val.data.ch.info.is_max_string = false;
val.data.ch.info.compressed_need_clear = false;
val.data.ch.medium.size = (int) len;
val.data.ch.medium.buf = (char *) str;
val.data.ch.medium.compressed_buf = NULL;
val.data.ch.medium.compressed_size = DB_NOT_YET_COMPRESSED;
mem = context->mobj + att->offset;
CHECK_ERR (err, att->domain->type->setmem (mem, att->domain, &val));
OBJ_SET_BOUND_BIT (context->mobj, att->storage_order);
error_exit:
return err;
}
/*
* ldr_str_db_varchar -
* return:
* context():
* str():
* len():
* att():
*/
static int
ldr_str_db_varchar (LDR_CONTEXT *context, const char *str, size_t len, SM_ATTRIBUTE *att)
{
char *mem;
int precision;
int err;
DB_VALUE val;
precision = att->domain->precision;
/* char_count <= byte_count in every codeset, so byte_size <= precision guarantees no truncation */
if ((int) len > precision)
{
int char_count = 0;
intl_char_count ((unsigned char *) str, (int) len, (INTL_CODESET) att->domain->codeset, &char_count);
if (char_count > precision)
{
/*
* May be a violation, but first we have to check for trailing pad
* characters that might allow us to successfully truncate the
* thing.
*/
int safe;
const char *p;
int truncate_size;
intl_char_size ((unsigned char *) str, precision, (INTL_CODESET) att->domain->codeset, &truncate_size);
for (p = &str[truncate_size], safe = 1; p < &str[len]; p++)
{
if (*p != ' ')
{
safe = 0;
break;
}
}
if (safe)
{
len = truncate_size;
}
else
{
/*
* It's a genuine violation; raise an error.
*/
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_IT_DATA_OVERFLOW, 1, db_get_type_name (DB_TYPE_VARCHAR));
CHECK_PARSE_ERR (err, ER_IT_DATA_OVERFLOW, context, DB_TYPE_VARCHAR, str);
}
}
}
val.domain = ldr_varchar_tmpl.domain;
val.domain.char_info.length = precision;
val.data.ch.medium.size = (int) len;
val.data.ch.medium.buf = (char *) str;
val.data.ch.info.style = MEDIUM_STRING;
val.data.ch.info.is_max_string = false;
val.data.ch.info.compressed_need_clear = false;
val.data.ch.medium.compressed_buf = NULL;
val.data.ch.medium.compressed_size = DB_NOT_YET_COMPRESSED;
mem = context->mobj + att->offset;
CHECK_ERR (err, att->domain->type->setmem (mem, att->domain, &val));
/*
* No bound bit to be set for a variable length attribute.
*/
error_exit:
return err;
}
/*
* ldr_str_db_generic -
* return:
* context():
* str():
* len():
* att():
*/
static int
ldr_str_db_generic (LDR_CONTEXT *context, const char *str, size_t len, SM_ATTRIBUTE *att)
{
DB_VALUE val;
/* todo: switch this to db_make_string_copy and avoid any possible leaks */
db_make_string (&val, str);
return ldr_generic (context, &val);
}
/*
* ldr_bstr_elem -
* return:
* context():
* str():
* len():
* val():
*/
static int
ldr_bstr_elem (LDR_CONTEXT *context, const char *str, size_t len, DB_VALUE *val)
{
int err = NO_ERROR;
size_t dest_size;
char *bstring;
TP_DOMAIN *domain;
DB_VALUE temp;
TP_DOMAIN *domain_ptr, temp_domain;
dest_size = (len + 7) / 8;
CHECK_PTR (err, bstring = (char *) db_private_alloc (NULL, dest_size + 1));
if (qstr_bit_to_bin (bstring, dest_size, (char *) str, (int) len) != (int) len)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OBJ_DOMAIN_CONFLICT, 1,
context->attrs[context->next_attr].att->header.name);
CHECK_PARSE_ERR (err, ER_OBJ_DOMAIN_CONFLICT, context, DB_TYPE_BIT, str);
}
db_make_varbit (&temp, TP_FLOATING_PRECISION_VALUE, bstring, (int) len);
temp.need_clear = true;
GET_DOMAIN (context, domain);
if (domain == NULL)
{
CHECK_PARSE_ERR (err, db_value_domain_init (val, DB_TYPE_BIT, DB_DEFAULT_PRECISION, DB_DEFAULT_SCALE), context,
DB_TYPE_BIT, str);
}
else
{
CHECK_PARSE_ERR (err, db_value_domain_init (val, TP_DOMAIN_TYPE (domain), domain->precision, domain->scale),
context, DB_TYPE_BIT, str);
}
domain_ptr = tp_domain_resolve_value (val, &temp_domain);
if (tp_value_cast (&temp, val, domain_ptr, false))
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OBJ_DOMAIN_CONFLICT, 1,
context->attrs[context->next_attr].att->header.name);
CHECK_PARSE_ERR (err, ER_OBJ_DOMAIN_CONFLICT, context, DB_TYPE_BIT, str);
}
error_exit:
/* cleanup */
db_value_clear (&temp);
return err;
}
/*
* ldr_bstr_db_varbit -
* return:
* context():
* str():
* len():
* att():
*/
static int
ldr_bstr_db_varbit (LDR_CONTEXT *context, const char *str, size_t len, SM_ATTRIBUTE *att)
{
int err;
DB_VALUE val;
CHECK_ERR (err, ldr_bstr_elem (context, str, len, &val));
CHECK_ERR (err, ldr_generic (context, &val));
error_exit:
db_value_clear (&val);
return err;
}
/*
* ldr_xstr_elem -
* return:
* context():
* str():
* len():
* val():
*/
static int
ldr_xstr_elem (LDR_CONTEXT *context, const char *str, size_t len, DB_VALUE *val)
{
int err = NO_ERROR;
size_t dest_size;
char *bstring = NULL;
TP_DOMAIN *domain;
DB_VALUE temp;
TP_DOMAIN *domain_ptr, temp_domain;
db_make_null (&temp);
dest_size = (len + 1) / 2;
CHECK_PTR (err, bstring = (char *) db_private_alloc (NULL, dest_size + 1));
if (qstr_hex_to_bin (bstring, dest_size, (char *) str, (int) len) != (int) len)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OBJ_DOMAIN_CONFLICT, 1, ldr_attr_name (context));
CHECK_PARSE_ERR (err, ER_OBJ_DOMAIN_CONFLICT, context, DB_TYPE_BIT, str);
}
db_make_varbit (&temp, TP_FLOATING_PRECISION_VALUE, bstring, (int) len * 4);
temp.need_clear = true;
/* temp takes ownership of this piece of memory */
bstring = NULL;
GET_DOMAIN (context, domain);
if (domain == NULL)
{
db_value_domain_init (val, DB_TYPE_BIT, DB_DEFAULT_PRECISION, DB_DEFAULT_SCALE);
}
else
{
CHECK_PARSE_ERR (err, db_value_domain_init (val, TP_DOMAIN_TYPE (domain), domain->precision, domain->scale),
context, DB_TYPE_BIT, str);
}
domain_ptr = tp_domain_resolve_value (val, &temp_domain);
if (tp_value_cast (&temp, val, domain_ptr, false))
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OBJ_DOMAIN_CONFLICT, 1,
context->attrs[context->next_attr].att->header.name);
CHECK_PARSE_ERR (err, ER_OBJ_DOMAIN_CONFLICT, context, DB_TYPE_BIT, str);
}
error_exit:
/* cleanup */
if (bstring != NULL)
{
db_private_free_and_init (NULL, bstring);
}
db_value_clear (&temp);
return err;
}
/*
* ldr_xstr_db_varbit -
* return:
* context():
* str():
* len():
* att():
*/
static int
ldr_xstr_db_varbit (LDR_CONTEXT *context, const char *str, size_t len, SM_ATTRIBUTE *att)
{
int err;
DB_VALUE val;
CHECK_ERR (err, ldr_xstr_elem (context, str, len, &val));
CHECK_ERR (err, ldr_generic (context, &val));
error_exit:
db_value_clear (&val);
return err;
}
/*
* NUMERIC SETTERS
*
* A "numeric" string is known to have a decimal point in it but *not* to
* have any exponent. It may also have a leading sign character. Most of
* the interesting cases (float and double attributes) will be handled by
* the ldr_numeric_db_{float, double} functions below, but this one will
* catch assignments into actual numeric attributes.
*/
/*
* ldr_numeric_elem -
* return:
* context():
* str():
* len():
* val():
*/
static int
ldr_numeric_elem (LDR_CONTEXT *context, const char *str, size_t len, DB_VALUE *val)
{
int precision, scale;
int err = NO_ERROR;
precision = (int) len - 1 - (str[0] == '+' || str[0] == '-');
scale = (int) len - (int) strcspn (str, ".") - 1;
CHECK_PARSE_ERR (err, db_value_domain_init (val, DB_TYPE_NUMERIC, precision, scale), context, DB_TYPE_NUMERIC, str);
CHECK_PARSE_ERR (err, db_value_put (val, DB_TYPE_C_CHAR, (char *) str, (int) len), context, DB_TYPE_NUMERIC, str);
error_exit:
return err;
}
/*
* ldr_numeric_db_generic -
* return:
* context():
* str():
* len():
* att():
*/
static int
ldr_numeric_db_generic (LDR_CONTEXT *context, const char *str, size_t len, SM_ATTRIBUTE *att)
{
int err;
DB_VALUE val;
CHECK_ERR (err, ldr_numeric_elem (context, str, len, &val));
CHECK_ERR (err, ldr_generic (context, &val));
error_exit:
return err;
}
/*
* ldr_double_elem -
* return:
* context():
* str():
* len():
* val():
*/
static int
ldr_double_elem (LDR_CONTEXT *context, const char *str, size_t len, DB_VALUE *val)
{
double d;
char *str_ptr;
int err = NO_ERROR;
val->domain = ldr_double_tmpl.domain;
d = strtod (str, &str_ptr);
/* The ascii representation should be ok, check for overflow */
if (str_ptr == str || OR_CHECK_DOUBLE_OVERFLOW (d))
{
TP_DOMAIN *domain;
GET_DOMAIN (context, domain);
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_IT_DATA_OVERFLOW, 1, db_get_type_name (TP_DOMAIN_TYPE (domain)));
CHECK_PARSE_ERR (err, ER_IT_DATA_OVERFLOW, context, TP_DOMAIN_TYPE (domain), str);
}
else
{
val->data.d = d;
}
error_exit:
return err;
}
/*
* ldr_float_elem -
* return:
* context():
* str():
* len():
* val():
*/
static int
ldr_float_elem (LDR_CONTEXT *context, const char *str, size_t len, DB_VALUE *val)
{
double d;
char *str_ptr;
int err = NO_ERROR;
val->domain = ldr_float_tmpl.domain;
d = strtod (str, &str_ptr);
/* The ascii representation should be ok, check for overflow */
if (str_ptr == str || OR_CHECK_FLOAT_OVERFLOW (d))
{
TP_DOMAIN *domain;
GET_DOMAIN (context, domain);
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_IT_DATA_OVERFLOW, 1, db_get_type_name (TP_DOMAIN_TYPE (domain)));
CHECK_PARSE_ERR (err, ER_IT_DATA_OVERFLOW, context, TP_DOMAIN_TYPE (domain), str);
}
else
{
val->data.f = (float) d;
}
error_exit:
return err;
}
/*
* ldr_real_db_generic -
* return:
* context():
* str():
* len():
* att():
*/
static int
ldr_real_db_generic (LDR_CONTEXT *context, const char *str, size_t len, SM_ATTRIBUTE *att)
{
int err;
DB_VALUE val;
CHECK_ERR (err, ldr_double_elem (context, str, len, &val));
CHECK_ERR (err, ldr_generic (context, &val));
error_exit:
return err;
}
/*
* ldr_real_db_float -
* return:
* context():
* str():
* len():
* att():
*/
static int
ldr_real_db_float (LDR_CONTEXT *context, const char *str, size_t len, SM_ATTRIBUTE *att)
{
char *mem;
int err;
DB_VALUE val;
double d;
char *str_ptr;
val.domain = ldr_float_tmpl.domain;
d = strtod (str, &str_ptr);
/* The ascii representation should be ok, check for overflow */
if (str_ptr == str || OR_CHECK_FLOAT_OVERFLOW (d))
{
TP_DOMAIN *domain;
GET_DOMAIN (context, domain);
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_IT_DATA_OVERFLOW, 1, db_get_type_name (TP_DOMAIN_TYPE (domain)));
CHECK_PARSE_ERR (err, ER_IT_DATA_OVERFLOW, context, TP_DOMAIN_TYPE (domain), str);
}
else
{
val.data.f = (float) d;
}
mem = context->mobj + att->offset;
CHECK_ERR (err, att->domain->type->setmem (mem, att->domain, &val));
OBJ_SET_BOUND_BIT (context->mobj, att->storage_order);
error_exit:
return err;
}
/*
* ldr_real_db_double -
* return:
* context():
* str():
* len():
* att():
*/
static int
ldr_real_db_double (LDR_CONTEXT *context, const char *str, size_t len, SM_ATTRIBUTE *att)
{
char *mem;
int err;
DB_VALUE val;
double d;
char *str_ptr;
val.domain = ldr_double_tmpl.domain;
d = strtod (str, &str_ptr);
/* The ascii representation should be ok, check for overflow */
if (str_ptr == str || OR_CHECK_DOUBLE_OVERFLOW (d))
{
TP_DOMAIN *domain;
GET_DOMAIN (context, domain);
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_IT_DATA_OVERFLOW, 1, db_get_type_name (TP_DOMAIN_TYPE (domain)));
CHECK_PARSE_ERR (err, ER_IT_DATA_OVERFLOW, context, TP_DOMAIN_TYPE (domain), str);
}
else
{
val.data.d = d;
}
mem = context->mobj + att->offset;
CHECK_ERR (err, att->domain->type->setmem (mem, att->domain, &val));
OBJ_SET_BOUND_BIT (context->mobj, att->storage_order);
error_exit:
return err;
}
/*
* DATE/TIME/TIMESTAMP/DATETIME SETTERS
*
* Any of the "date", "time" , "timestamp" or "datetime" strings have already
* had the tag and surrounding quotes stripped off. We know which one we
* have by virtue knowing which function has been called.
*/
/*
* ldr_date_elem -
* return:
* context():
* str():
* len():
* val():
*/
static int
ldr_date_elem (LDR_CONTEXT *context, const char *str, size_t len, DB_VALUE *val)
{
int err = NO_ERROR;
val->domain = ldr_date_tmpl.domain;
CHECK_PARSE_ERR (err, db_string_to_date (str, &val->data.date), context, DB_TYPE_DATE, str);
error_exit:
return err;
}
/*
* ldr_date_db_date -
* return:
* context():
* str():
* len():
* att():
*/
static int
ldr_date_db_date (LDR_CONTEXT *context, const char *str, size_t len, SM_ATTRIBUTE *att)
{
int err;
char *mem;
DB_VALUE val;
CHECK_ERR (err, ldr_date_elem (context, str, len, &val));
mem = context->mobj + att->offset;
CHECK_ERR (err, att->domain->type->setmem (mem, att->domain, &val));
OBJ_SET_BOUND_BIT (context->mobj, att->storage_order);
error_exit:
return err;
}
/*
* ldr_time_elem -
* return:
* context():
* str():
* len():
* val():
*/
static int
ldr_time_elem (LDR_CONTEXT *context, const char *str, size_t len, DB_VALUE *val)
{
int err = NO_ERROR;
val->domain = ldr_time_tmpl.domain;
CHECK_PARSE_ERR (err, db_string_to_time (str, &val->data.time), context, DB_TYPE_TIME, str);
error_exit:
return err;
}
/*
* ldr_time_db_time -
* return:
* context():
* str():
* len():
* att():
*/
static int
ldr_time_db_time (LDR_CONTEXT *context, const char *str, size_t len, SM_ATTRIBUTE *att)
{
int err;
char *mem;
DB_VALUE val;
CHECK_ERR (err, ldr_time_elem (context, str, len, &val));
mem = context->mobj + att->offset;
CHECK_ERR (err, att->domain->type->setmem (mem, att->domain, &val));
OBJ_SET_BOUND_BIT (context->mobj, att->storage_order);
error_exit:
return err;
}
/*
* ldr_timestamp_elem -
* return:
* context():
* str():
* len():
* val():
*/
static int
ldr_timestamp_elem (LDR_CONTEXT *context, const char *str, size_t len, DB_VALUE *val)
{
int err = NO_ERROR;
val->domain = ldr_timestamp_tmpl.domain;
CHECK_PARSE_ERR (err, db_string_to_timestamp (str, &val->data.utime), context, DB_TYPE_TIMESTAMP, str);
error_exit:
return err;
}
/*
* ldr_timestamp_db_timestamp -
* return:
* context():
* str():
* len():
* att():
*/
static int
ldr_timestamp_db_timestamp (LDR_CONTEXT *context, const char *str, size_t len, SM_ATTRIBUTE *att)
{
int err;
char *mem;
DB_VALUE val;
CHECK_ERR (err, ldr_timestamp_elem (context, str, len, &val));
mem = context->mobj + att->offset;
CHECK_ERR (err, att->domain->type->setmem (mem, att->domain, &val));
OBJ_SET_BOUND_BIT (context->mobj, att->storage_order);
error_exit:
return err;
}
/*
* ldr_timestamptz_elem -
* return:
* context():
* str():
* len():
* val():
*/
static int
ldr_timestamptz_elem (LDR_CONTEXT *context, const char *str, size_t len, DB_VALUE *val)
{
int err = NO_ERROR;
bool has_zone;
val->domain = ldr_timestamptz_tmpl.domain;
CHECK_PARSE_ERR (err, db_string_to_timestamptz (str, &val->data.timestamptz, &has_zone), context, DB_TYPE_TIMESTAMPTZ,
str);
/* if no zone text, than it is assumed session timezone */
error_exit:
return err;
}
/*
* ldr_timestampltz_elem -
* return:
* context():
* str():
* len():
* val():
*/
static int
ldr_timestampltz_elem (LDR_CONTEXT *context, const char *str, size_t len, DB_VALUE *val)
{
int err = NO_ERROR;
val->domain = ldr_timestampltz_tmpl.domain;
CHECK_PARSE_ERR (err, db_string_to_timestampltz (str, &val->data.utime), context, DB_TYPE_TIMESTAMPLTZ, str);
/* if no zone text, than it is assumed session timezone */
error_exit:
return err;
}
/*
* ldr_timestamptz_db_timestamptz -
* return:
* context():
* str():
* len():
* att():
*/
static int
ldr_timestamptz_db_timestamptz (LDR_CONTEXT *context, const char *str, size_t len, SM_ATTRIBUTE *att)
{
int err;
char *mem;
DB_VALUE val;
CHECK_ERR (err, ldr_timestamptz_elem (context, str, len, &val));
mem = context->mobj + att->offset;
CHECK_ERR (err, att->domain->type->setmem (mem, att->domain, &val));
OBJ_SET_BOUND_BIT (context->mobj, att->storage_order);
error_exit:
return err;
}
/*
* ldr_timestampltz_db_timestampltz -
* return:
* context():
* str():
* len():
* att():
*/
static int
ldr_timestampltz_db_timestampltz (LDR_CONTEXT *context, const char *str, size_t len, SM_ATTRIBUTE *att)
{
int err;
char *mem;
DB_VALUE val;
CHECK_ERR (err, ldr_timestampltz_elem (context, str, len, &val));
mem = context->mobj + att->offset;
CHECK_ERR (err, att->domain->type->setmem (mem, att->domain, &val));
OBJ_SET_BOUND_BIT (context->mobj, att->storage_order);
error_exit:
return err;
}
/*
* ldr_datetime_elem -
* return:
* context():
* str():
* len():
* val():
*/
static int
ldr_datetime_elem (LDR_CONTEXT *context, const char *str, size_t len, DB_VALUE *val)
{
int err = NO_ERROR;
val->domain = ldr_datetime_tmpl.domain;
CHECK_PARSE_ERR (err, db_string_to_datetime (str, &val->data.datetime), context, DB_TYPE_DATETIME, str);
error_exit:
return err;
}
/*
* ldr_datetime_db_datetime -
* return:
* context():
* str():
* len():
* att():
*/
static int
ldr_datetime_db_datetime (LDR_CONTEXT *context, const char *str, size_t len, SM_ATTRIBUTE *att)
{
int err;
char *mem;
DB_VALUE val;
CHECK_ERR (err, ldr_datetime_elem (context, str, len, &val));
mem = context->mobj + att->offset;
CHECK_ERR (err, att->domain->type->setmem (mem, att->domain, &val));
OBJ_SET_BOUND_BIT (context->mobj, att->storage_order);
error_exit:
return err;
}
/*
* ldr_datetimetz_elem -
* return:
* context():
* str():
* len():
* val():
*/
static int
ldr_datetimetz_elem (LDR_CONTEXT *context, const char *str, size_t len, DB_VALUE *val)
{
int err = NO_ERROR;
bool has_zone;
val->domain = ldr_datetimetz_tmpl.domain;
CHECK_PARSE_ERR (err, db_string_to_datetimetz (str, &val->data.datetimetz, &has_zone), context, DB_TYPE_DATETIMETZ,
str);
/* if no zone text, than it is assumed session timezone */
error_exit:
return err;
}
/*
* ldr_datetimeltz_elem -
* return:
* context():
* str():
* len():
* val():
*/
static int
ldr_datetimeltz_elem (LDR_CONTEXT *context, const char *str, size_t len, DB_VALUE *val)
{
int err = NO_ERROR;
val->domain = ldr_datetimeltz_tmpl.domain;
CHECK_PARSE_ERR (err, db_string_to_datetimeltz (str, &val->data.datetime), context, DB_TYPE_DATETIMELTZ, str);
/* if no zone text, than it is assumed session timezone */
error_exit:
return err;
}
/*
* ldr_datetimetz_db_datetimetz -
* return:
* context():
* str():
* len():
* att():
*/
static int
ldr_datetimetz_db_datetimetz (LDR_CONTEXT *context, const char *str, size_t len, SM_ATTRIBUTE *att)
{
int err;
char *mem;
DB_VALUE val;
CHECK_ERR (err, ldr_datetimetz_elem (context, str, len, &val));
mem = context->mobj + att->offset;
CHECK_ERR (err, att->domain->type->setmem (mem, att->domain, &val));
OBJ_SET_BOUND_BIT (context->mobj, att->storage_order);
error_exit:
return err;
}
/*
* ldr_datetimeltz_db_datetimeltz -
* return:
* context():
* str():
* len():
* att():
*/
static int
ldr_datetimeltz_db_datetimeltz (LDR_CONTEXT *context, const char *str, size_t len, SM_ATTRIBUTE *att)
{
int err;
char *mem;
DB_VALUE val;
CHECK_ERR (err, ldr_datetimeltz_elem (context, str, len, &val));
mem = context->mobj + att->offset;
CHECK_ERR (err, att->domain->type->setmem (mem, att->domain, &val));
OBJ_SET_BOUND_BIT (context->mobj, att->storage_order);
error_exit:
return err;
}
/*
* ldr_date_time_conversion_error - display date/time validation error
* return: void
* token(in): string that failed.
* type(in): loader type
*/
static void
ldr_date_time_conversion_error (const char *token, DB_TYPE type)
{
display_error_line (0);
fprintf (stderr, msgcat_message (MSGCAT_CATALOG_UTILS, MSGCAT_UTIL_SET_LOADDB, LOADDB_MSG_CONVERSION_ERROR), token,
db_get_type_name (type));
}
/*
* ldr_check_date_time_conversion - check time/date/timestamp string w.r.t. type
* return: NO_ERROR if successful, error code otherwise
* str(in): string to convert
* type(in): loader type
* Note:
* Strings are checked for correctness during the validation only phase
*/
static int
ldr_check_date_time_conversion (const char *str, data_type type)
{
int err = NO_ERROR;
DB_TIME dummy_time;
DB_DATE dummy_date;
DB_TIMESTAMP dummy_timestamp;
DB_TIMESTAMPTZ dummy_timestamptz;
DB_DATETIME dummy_datetime;
DB_DATETIMETZ dummy_datetimetz;
DB_TYPE current_type = DB_TYPE_NULL;
bool has_zone;
/*
* Flag invalid date/time/timestamp strings as errors.
* e.g., DATE '01///' should be an error, this is not detected by the lexical
* analysis phase since DATE 'str' is valid.
* Attempt to do the string to type conversion here.
*/
switch (type)
{
case LDR_TIME:
current_type = DB_TYPE_TIME;
err = db_string_to_time (str, &dummy_time);
break;
case LDR_DATE:
current_type = DB_TYPE_DATE;
err = db_string_to_date (str, &dummy_date);
break;
case LDR_TIMESTAMP:
current_type = DB_TYPE_TIMESTAMP;
err = db_string_to_timestamp (str, &dummy_timestamp);
break;
case LDR_TIMESTAMPLTZ:
current_type = DB_TYPE_TIMESTAMPLTZ;
err = db_string_to_timestampltz (str, &dummy_timestamp);
break;
case LDR_TIMESTAMPTZ:
current_type = DB_TYPE_TIMESTAMPTZ;
err = db_string_to_timestamptz (str, &dummy_timestamptz, &has_zone);
break;
case LDR_DATETIME:
current_type = DB_TYPE_DATETIME;
err = db_string_to_datetime (str, &dummy_datetime);
break;
case LDR_DATETIMELTZ:
current_type = DB_TYPE_DATETIMELTZ;
err = db_string_to_datetimeltz (str, &dummy_datetime);
break;
case LDR_DATETIMETZ:
current_type = DB_TYPE_DATETIMETZ;
err = db_string_to_datetimetz (str, &dummy_datetimetz, &has_zone);
break;
default:
break;
}
if (err != NO_ERROR)
{
if (err == ER_DATE_CONVERSION)
{
ldr_date_time_conversion_error (str, current_type);
}
else
{
display_error (0);
}
}
return err;
}
/*
* ldr_elo_int_elem -
* return:
* context():
* str():
* len():
* val():
*/
static int
ldr_elo_int_elem (LDR_CONTEXT *context, const char *str, size_t len, DB_VALUE *val)
{
/* not implemented. should not be called */
assert (0);
return ER_FAILED;
}
/*
* ldr_elo_int_db_elo -
* return:
* context():
* str():
* len():
* att():
*/
static int
ldr_elo_int_db_elo (LDR_CONTEXT *context, const char *str, size_t len, SM_ATTRIBUTE *att)
{
/* not implemented. should not be called */
assert (0);
return ER_FAILED;
}
/*
* ldr_elo_ext_elem -
* return:
* context():
* str():
* len():
* val():
*/
static int
ldr_elo_ext_elem (LDR_CONTEXT *context, const char *str, size_t len, DB_VALUE *val)
{
DB_ELO elo;
int err = NO_ERROR;
int result = 0;
int new_len;
INT64 size;
char *locator = NULL;
char *meta_data = NULL;
if (!context->valid)
{
err = ER_LDR_INVALID_STATE;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, err, 0);
/* reset the error count by adding -1, since this is not real error */
ldr_increment_err_count (context, -1);
return (err);
}
PARSE_ELO_STR (str, new_len);
/* parse elo string: see process_value () in unload_object.c */
if (new_len > 0)
{
DB_TYPE type;
char *size_sp, *size_ep;
const char *locator_sp, *locator_ep;
const char *meta_sp, *meta_ep;
/* db type */
assert (str[0] == 'B' || str[0] == 'C');
if (str[0] == 'B')
{
type = DB_TYPE_BLOB;
val->domain = ldr_blob_tmpl.domain;
}
else
{
type = DB_TYPE_CLOB;
val->domain = ldr_clob_tmpl.domain;
}
/* size */
size_sp = (char *) (str + 1);
size_ep = strchr (size_sp, '|');
if (size_ep == NULL || size_ep - size_sp == 0)
{
/* FBO TODO: error message --> invalid elo format */
err = ER_LDR_ELO_INPUT_FILE;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, err, 1, str);
goto error_exit;
}
/* locator */
locator_sp = size_ep + 1;
locator_ep = strchr (locator_sp, '|');
if (locator_ep == NULL || locator_ep - locator_sp == 0)
{
/* FBO TODO: error message --> invalid elo format */
err = ER_LDR_ELO_INPUT_FILE;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, err, 1, str);
goto error_exit;
}
/* meta_data */
meta_ep = meta_sp = locator_ep + 1;
while (*meta_ep)
{
meta_ep++;
}
/* make elo */
elo_init_structure (&elo);
result = str_to_int64 (&size, &size_ep, size_sp, 10);
if (result != 0 || size < 0)
{
err = ER_LDR_ELO_INPUT_FILE;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_LDR_ELO_INPUT_FILE, 1, str);
goto error_exit;
}
locator = (char *) db_private_alloc (NULL, locator_ep - locator_sp + 1);
if (locator == NULL)
{
goto error_exit;
}
memcpy (locator, locator_sp, locator_ep - locator_sp);
locator[locator_ep - locator_sp] = '\0';
if (meta_ep - meta_sp > 0)
{
meta_data = (char *) db_private_alloc (NULL, meta_ep - meta_sp + 1);
if (meta_data == NULL)
{
goto error_exit;
}
memcpy (meta_data, meta_sp, meta_ep - meta_sp);
meta_data[meta_ep - meta_sp] = '\0';
}
elo.size = size;
elo.locator = locator;
elo.meta_data = meta_data;
elo.type = ELO_FBO;
err = db_make_elo (val, type, &elo);
if (err == NO_ERROR)
{
val->need_clear = true;
locator = NULL;
meta_data = NULL;
}
}
error_exit:
if (locator != NULL)
{
db_private_free_and_init (NULL, locator);
}
if (meta_data != NULL)
{
db_private_free_and_init (NULL, meta_data);
}
if (err != NO_ERROR)
{
display_error (0);
}
return err;
}
/*
* ldr_elo_ext_db_elo -
* return:
* context():
* str():
* len():
* att():
*/
static int
ldr_elo_ext_db_elo (LDR_CONTEXT *context, const char *str, size_t len, SM_ATTRIBUTE *att)
{
int err = NO_ERROR;
char *mem;
DB_VALUE val;
char name_buf[8196];
char *name = NULL;
size_t new_len;
db_make_null (&val);
PARSE_ELO_STR (str, new_len);
if (new_len >= 8196)
{
name = (char *) malloc (new_len);
if (name == NULL)
{
err = ER_LDR_MEMORY_ERROR;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, err, 0);
CHECK_CONTEXT_VALIDITY (context, true);
ldr_abort ();
goto error_exit;
}
}
else
{
name = &name_buf[0];
}
strncpy (name, str, new_len);
name[new_len] = '\0';
CHECK_ERR (err, ldr_elo_ext_elem (context, name, new_len, &val));
mem = context->mobj + att->offset;
CHECK_ERR (err, att->domain->type->setmem (mem, att->domain, &val));
/* No bound bit to be set for a variable length attribute. */
error_exit:
if (name != NULL && name != &name_buf[0])
{
free (name);
}
db_value_clear (&val);
return err;
}
/*
* LDR_MOP_TEMPOID_MAP MAINTENANCE
*/
/*
* ldr_mop_tempoid_maps_init - initialize ldr_Mop_tempoid_maps
* return: NO_ERROR if successful, error code otherwise
*/
static int
ldr_mop_tempoid_maps_init (void)
{
int err = NO_ERROR;
int presize = 0;
if (ldr_Mop_tempoid_maps)
{
ldr_Mop_tempoid_maps->count = 0;
ldr_Mop_tempoid_maps->index = 0;
return (err);
}
ldr_Mop_tempoid_maps = NULL;
if ((ldr_Mop_tempoid_maps = (LDR_MOP_TEMPOID_MAPS *) malloc (sizeof (LDR_MOP_TEMPOID_MAPS))) == NULL)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_LDR_MEMORY_ERROR, 0);
return ER_LDR_MEMORY_ERROR;
}
presize = LDR_MOP_TEMPOID_MAPS_PRESIZE;
if ((ldr_Mop_tempoid_maps->mop_tempoid_maps =
(LDR_MOP_TEMPOID_MAP *) malloc (presize * sizeof (LDR_MOP_TEMPOID_MAP))) == NULL)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_LDR_MEMORY_ERROR, 0);
err = ER_LDR_MEMORY_ERROR;
ldr_Mop_tempoid_maps->count = -1;
ldr_Mop_tempoid_maps->index = -1;
ldr_Mop_tempoid_maps->size = 0;
}
else
{
int i = 0;
while (i < presize)
{
ldr_Mop_tempoid_maps->mop_tempoid_maps[i].mop = NULL;
ldr_Mop_tempoid_maps->mop_tempoid_maps[i].table = NULL;
ldr_Mop_tempoid_maps->mop_tempoid_maps[i].id = 0;
i += 1;
}
ldr_Mop_tempoid_maps->count = 0;
ldr_Mop_tempoid_maps->index = 0;
ldr_Mop_tempoid_maps->size = presize;
}
return err;
}
/*
* ldr_mop_tempoid_maps_final - Frees ldr_Mop_tempoid_maps.
* return: NO_ERROR if successful, error code otherwise
*/
static void
ldr_mop_tempoid_maps_final (void)
{
if (!ldr_Mop_tempoid_maps)
{
return;
}
if (ldr_Mop_tempoid_maps->mop_tempoid_maps)
{
free_and_init (ldr_Mop_tempoid_maps->mop_tempoid_maps);
}
free_and_init (ldr_Mop_tempoid_maps);
return;
}
/*
* ldr_add_mop_tempoid_map - add a temporary oid mop to CLASS_TABLE mapping
* to ldr_Mop_tempoid_maps.
* return: NO_ERROR if successful, error code otherwise
* mop(in): MOP to add
* table(out): CLASS_TABLE
* id(in): instance id.
*/
static int
ldr_add_mop_tempoid_map (MOP mop, CLASS_TABLE *table, int id)
{
int err = NO_ERROR;
if (ldr_Mop_tempoid_maps == NULL || ldr_Mop_tempoid_maps->mop_tempoid_maps == NULL)
{
err = ldr_mop_tempoid_maps_init ();
if (err != NO_ERROR)
{
display_error (0);
return err;
}
}
ldr_Mop_tempoid_maps->mop_tempoid_maps[ldr_Mop_tempoid_maps->index].mop = mop;
ldr_Mop_tempoid_maps->mop_tempoid_maps[ldr_Mop_tempoid_maps->index].table = table;
ldr_Mop_tempoid_maps->mop_tempoid_maps[ldr_Mop_tempoid_maps->index].id = id;
ldr_Mop_tempoid_maps->count += 1;
ldr_Mop_tempoid_maps->index += 1;
/* Grow array if required */
if (ldr_Mop_tempoid_maps->index == ldr_Mop_tempoid_maps->size)
{
LDR_MOP_TEMPOID_MAP *mop_tempoid_maps_old;
mop_tempoid_maps_old = ldr_Mop_tempoid_maps->mop_tempoid_maps;
ldr_Mop_tempoid_maps->mop_tempoid_maps =
(LDR_MOP_TEMPOID_MAP *) realloc (ldr_Mop_tempoid_maps->mop_tempoid_maps,
sizeof (LDR_MOP_TEMPOID_MAP) * (ldr_Mop_tempoid_maps->size +
LDR_MOP_TEMPOID_MAPS_PRESIZE));
if (ldr_Mop_tempoid_maps->mop_tempoid_maps == NULL)
{
/* Prevent realloc memory leak, if error occurs. */
if (mop_tempoid_maps_old)
{
free_and_init (mop_tempoid_maps_old);
}
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_LDR_MEMORY_ERROR, 0);
return ER_LDR_MEMORY_ERROR;
}
else
{
ldr_Mop_tempoid_maps->size += LDR_MOP_TEMPOID_MAPS_PRESIZE;
}
}
return err;
}
/*
* ldr_assign_all_perm_oids - traverses ldr_Mop_tempoid_maps and creates a
* list LC_OIDSET, to send to the server to get permanent oids.
* return: NO_ERROR if successful, error code otherwise
*/
static int
ldr_assign_all_perm_oids (void)
{
int err = NO_ERROR;
LC_OIDSET *oidset = NULL;
LDR_MOP_TEMPOID_MAP *mop_tempoid_map = NULL;
INST_INFO *inst;
int i;
if (!ldr_Mop_tempoid_maps)
{
return (err);
}
/* No permanent oids to assign */
if (!ldr_Mop_tempoid_maps->count)
{
return (NO_ERROR);
}
oidset = locator_make_oid_set ();
if (oidset == NULL)
{
assert (er_errid () != NO_ERROR);
err = er_errid ();
}
else
{
i = 0;
while (i < ldr_Mop_tempoid_maps->count)
{
mop_tempoid_map = & (ldr_Mop_tempoid_maps->mop_tempoid_maps[i]);
if (mop_tempoid_map->mop && OID_ISTEMP (WS_REAL_OID (mop_tempoid_map->mop)))
{
if (locator_add_oidset_object (oidset, mop_tempoid_map->mop) == NULL)
{
CHECK_ERR (err, er_errid ());
}
}
i += 1;
if (oidset->total_oids > OID_BATCH_SIZE)
{
CHECK_ERR (err, locator_assign_oidset (oidset, NULL));
locator_clear_oid_set (NULL, oidset);
}
}
/* call locator_assign_oidset(). This will make a server call to get permanent oids. */
if (oidset->total_oids)
{
CHECK_ERR (err, locator_assign_oidset (oidset, NULL));
}
/* At this point the mapping between mop -> permanent oid should be complete. Update the otable oids via the oid
* pointer obtained from the CLASS_TABLE and id. */
if (!ldr_Current_context->args->no_oid_hint)
{
i = 0;
while (i < ldr_Mop_tempoid_maps->count)
{
mop_tempoid_map = & (ldr_Mop_tempoid_maps->mop_tempoid_maps[i]);
CHECK_PTR (err, inst = otable_find (mop_tempoid_map->table, mop_tempoid_map->id));
COPY_OID (& (inst->oid), WS_REAL_OID (mop_tempoid_map->mop));
mop_tempoid_map->mop = NULL;
mop_tempoid_map->table = NULL;
mop_tempoid_map->id = 0;
i += 1;
}
}
ldr_Mop_tempoid_maps->index = 0;
ldr_Mop_tempoid_maps->count = 0;
}
error_exit:
if (oidset)
{
locator_free_oid_set (NULL, oidset);
}
return err;
}
/*
* find_instance - locates an instance OID given the class and an instance id.
* return: NO_ERROR if successful, error code otherwise
* context(in): context
* class(in): class object
* oid(out): instance OID (returned)
* id(in): instance identifier
* Note:
* If the instance does not exist, an OID is reserved for this
* instance.
* Note : the oid references return are temporary OIDs. This will be
* when the objects are packed to be sent to the server, using a batch
* oid set.
* The oids in the workspace to which the references point to are updated
* via the call ldr_assign_all_perm_oids()
*/
static int
find_instance (LDR_CONTEXT *context, DB_OBJECT *class_, OID *oid, int id)
{
int err = NO_ERROR;
CLASS_TABLE *table;
INST_INFO *inst;
table = otable_find_class (class_);
if (table == NULL)
{
OID_SET_NULL (oid);
assert (er_errid () != NO_ERROR);
err = er_errid ();
}
else
{
inst = otable_find (table, id);
if (inst != NULL)
{
/* Backward reference */
*oid = inst->oid;
}
else
{
/* Forward reference */
if ((class_ == context->cls) && (context->inst_num == id))
{
/*
* We have a reference to the current object being processed.
* Simply use the oid of the object.
*/
COPY_OID (oid, WS_REAL_OID (context->obj));
}
else
{
/* Forward reference */
OID_SET_NULL (oid);
/* sigh, should try to catch this at a higher level */
if (is_internal_class (class_))
{
err = ER_LDR_INTERNAL_REFERENCE;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, err, 1, db_get_class_name (class_));
}
else
{
MOP mop;
INST_INFO *inst;
/*
* Create object, this will be used used when the instance
* is defined in the load file.
* We do not mark the MOP as released yet. This will be done
* when we encounter the real instance.
*/
CHECK_PTR (err, mop = db_create_internal (context->attrs[context->next_attr].ref_class));
COPY_OID (oid, WS_REAL_OID (mop));
CHECK_ERR (err, otable_reserve (table, oid, id));
CHECK_PTR (err, inst = otable_find (table, id));
/*
* Mark forward references to class attributes so that we do
* not cull the objects they point to after we encounter them.
*/
if (context->attr_type != LDR_ATTRIBUTE_ANY)
{
otable_class_att_ref (inst);
}
/*
* Add to the list of mops for which we need a permanent oid
* for
*/
CHECK_ERR (err, ldr_add_mop_tempoid_map (mop, table, id));
}
}
}
}
error_exit:
return (err);
}
/*
* ldr_class_oid_elem -
* return:
* context():
* str():
* len():
* val():
*/
static int
ldr_class_oid_elem (LDR_CONTEXT *context, const char *str, size_t len, DB_VALUE *val)
{
int err = NO_ERROR;
if (context->attrs[context->next_attr].ref_class == NULL)
{
ldr_internal_error (context);
goto error_exit;
}
CHECK_ERR (err, check_class_domain (context));
db_make_object (val, context->attrs[context->next_attr].ref_class);
error_exit:
return err;
}
/*
* ldr_class_oid_db_object -
* return:
* context():
* str():
* len():
* att():
*/
static int
ldr_class_oid_db_object (LDR_CONTEXT *context, const char *str, size_t len, SM_ATTRIBUTE *att)
{
int err = NO_ERROR;
DB_VALUE val;
char *mem;
CHECK_ERR (err, ldr_class_oid_elem (context, str, len, &val));
/*
* We need to treat shared attributes in the generic way.
* There is a problem when setting the bound bit for shared attributes.
*/
if (att->header.name_space == ID_SHARED_ATTRIBUTE)
{
ldr_generic (context, &val);
}
else
{
mem = context->mobj + att->offset;
CHECK_ERR (err, att->domain->type->setmem (mem, att->domain, &val));
OBJ_SET_BOUND_BIT (context->mobj, att->storage_order);
}
error_exit:
ldr_increment_err_count (context, (err != NO_ERROR));
return err;
}
/*
* ldr_oid_elem -
* return:
* context():
* str():
* len():
* val():
*/
static int
ldr_oid_elem (LDR_CONTEXT *context, const char *str, size_t len, DB_VALUE *val)
{
int err = NO_ERROR;
DB_OBJECT *actual_class;
OID oid;
if (context->attrs[context->next_attr].ref_class == NULL)
{
ldr_internal_error (context);
goto error_exit;
}
CHECK_ERR (err, check_object_domain (context, context->attrs[context->next_attr].ref_class, &actual_class));
err = find_instance (context, actual_class, &oid, context->attrs[context->next_attr].instance_id);
if (err == ER_LDR_INTERNAL_REFERENCE)
{
db_make_null (val);
}
else
{
DB_OBJECT *mop;
if ((mop = ws_mop (&oid, context->attrs[context->next_attr].ref_class)) == NULL)
{
if ((err = er_errid ()) == NO_ERROR)
{
err = ER_GENERIC_ERROR;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, err, 0);
}
CHECK_ERR (err, err);
}
db_make_object (val, mop);
}
error_exit:
ldr_increment_err_count (context, (err != NO_ERROR));
return err;
}
/*
* ldr_oid_db_object -
* return:
* context():
* str():
* len():
* att():
*/
static int
ldr_oid_db_object (LDR_CONTEXT *context, const char *str, size_t len, SM_ATTRIBUTE *att)
{
int err = NO_ERROR;
DB_VALUE val;
char *mem;
CHECK_ERR (err, ldr_oid_elem (context, str, len, &val));
mem = context->mobj + att->offset;
CHECK_ERR (err, att->domain->type->setmem (mem, att->domain, &val));
OBJ_SET_BOUND_BIT (context->mobj, att->storage_order);
error_exit:
return (err);
}
/*
* ldr_monetary_elem -
* return:
* context():
* str():
* len():
* val():
*/
static int
ldr_monetary_elem (LDR_CONTEXT *context, const char *str, size_t len, DB_VALUE *val)
{
const unsigned char *p = (const unsigned char *) str;
const unsigned char *token = (const unsigned char *) str;
char *str_ptr;
double amt;
int err = NO_ERROR;
int symbol_size = 0;
DB_CURRENCY currency_type = DB_CURRENCY_NULL;
if (len >= 2
&& intl_is_currency_symbol ((const char *) p, ¤cy_type, &symbol_size,
(CURRENCY_CHECK_MODE) (CURRENCY_CHECK_MODE_ESC_ISO | CURRENCY_CHECK_MODE_GRAMMAR)))
{
token += symbol_size;
}
if (currency_type == DB_CURRENCY_NULL)
{
currency_type = DB_CURRENCY_DOLLAR;
}
amt = strtod ((const char *) token, &str_ptr);
if (str == str_ptr || OR_CHECK_DOUBLE_OVERFLOW (amt))
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_IT_DATA_OVERFLOW, 1, db_get_type_name (DB_TYPE_MONETARY));
CHECK_PARSE_ERR (err, ER_IT_DATA_OVERFLOW, context, DB_TYPE_MONETARY, str);
}
else
{
db_make_monetary (val, currency_type, amt);
}
error_exit:
return (err);
}
/*
* ldr_monetary_db_monetary -
* return:
* context():
* str():
* len():
* att():
*/
static int
ldr_monetary_db_monetary (LDR_CONTEXT *context, const char *str, size_t len, SM_ATTRIBUTE *att)
{
int err;
char *mem;
DB_VALUE val;
CHECK_ERR (err, ldr_monetary_elem (context, str, len, &val));
mem = context->mobj + att->offset;
CHECK_ERR (err, att->domain->type->setmem (mem, att->domain, &val));
OBJ_SET_BOUND_BIT (context->mobj, att->storage_order);
error_exit:
return err;
}
/*
* ldr_collection_elem -
* return:
* context():
* str():
* len():
* val():
*/
static int
ldr_collection_elem (LDR_CONTEXT *context, const char *str, size_t len, DB_VALUE *val)
{
int err = ER_LDR_NESTED_SET;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, err, 0);
display_error (0);
(void) ldr_null_elem (context, str, len, val);
return err;
}
/*
* ldr_collection_db_collection -
* return:
* context():
* str():
* len():
* att():
*/
static int
ldr_collection_db_collection (LDR_CONTEXT *context, const char *str, size_t len, SM_ATTRIBUTE *att)
{
int err = NO_ERROR;
LDR_ATTDESC *attdesc;
attdesc = &context->attrs[context->next_attr];
/* Set the approriate action function to deal with collection elements */
ldr_act = ldr_act_elem;
if (context->collection == NULL)
{
/*
* This kind of bites: we need to avoid advancing the next_attr
* counter until we actually hit the closing brace. Since ldr_act_attr
* (which has called this function) will increment the counter
* unconditionally, we decrement it here to compensate. I with there
* were a better way of dealing with this.
*/
context->next_attr -= 1;
/*
* We've just seen the leading brace of a collection, and we need to
* create the "holding" collection.
*/
context->collection = db_col_create (TP_DOMAIN_TYPE (att->domain), 0, attdesc->collection_domain);
if (context->collection == NULL)
{
assert (er_errid () != NO_ERROR);
err = er_errid ();
}
else
{
context->set_domain = attdesc->collection_domain->setdomain;
}
}
else
{
/*
* We've seen the trailing brace that ends the collection, and it's
* now time to assign the collection to the instance.
*/
DB_VALUE tmp;
db_make_collection (&tmp, context->collection);
context->collection = NULL;
context->set_domain = NULL;
/* We finished dealing with elements of a collection, set the action function to deal with normal attributes. */
if (context->attr_type == LDR_ATTRIBUTE_ANY)
{
ldr_act = ldr_act_attr;
err = ldr_generic (context, &tmp);
}
else
{
ldr_act = ldr_act_class_attr;
err = ldr_class_attr_db_generic (context, str, len, context->attrs[context->next_attr].att, &tmp);
}
}
return err;
}
/*
* ldr_reset_context -
* return:
* context():
*/
static int
ldr_reset_context (LDR_CONTEXT *context)
{
int err = NO_ERROR;
INST_INFO *inst = NULL;
/*
* Check that we are not dealing with class attributes, use attribute_type
* Do not create instances for class attributes.
*/
if (context->cls && context->attr_type == LDR_ATTRIBUTE_ANY && context->constructor == NULL)
{
/* Check that this instance was not a forward reference */
if (context->table && context->inst_num > -1)
{
inst = otable_find (context->table, context->inst_num);
}
if (inst && (inst->flags & INST_FLAG_RESERVED))
{
/*
* This instance was already referenced and a workspace MOP created.
*/
context->obj = ws_mop (& (inst->oid), context->cls);
if (context->obj == NULL)
{
err = er_filter_errid (false);
display_error (0);
goto error_exit;
}
/*
* If this was a forward reference from a class attribute than we
* do not want to mark it as releasable.
*/
if (! (inst->flags & INST_FLAG_CLASS_ATT))
{
ws_release_instance (context->obj);
}
}
else
{
context->obj = db_create_internal (context->cls);
if (context->obj == NULL)
{
err = er_filter_errid (false);
display_error (0);
goto error_exit;
}
/* set pruning type to be performed on this object */
context->obj->pruning_type = context->class_type;
/*
* Mark this mop as released so that we can cull it when we
* complete inserting this instance.
*/
ws_release_instance (context->obj);
}
CHECK_ERR (err,
au_fetch_instance (context->obj, &context->mobj, AU_FETCH_UPDATE, LC_FETCH_MVCC_VERSION, AU_UPDATE));
ws_pin_instance_and_class (context->obj, &context->obj_pin, &context->class_pin);
ws_class_has_object_dependencies (context->cls);
}
context->next_attr = 0;
ldr_clear_err_count (context);
error_exit:
CHECK_CONTEXT_VALIDITY (context, err != NO_ERROR);
return err;
}
/*
* ldr_flush -
* return:
* context():
*/
static void
ldr_flush (LDR_CONTEXT *context)
{
if (context->cls)
{
ws_intern_instances (context->cls);
}
context->flush_total += 1;
context->inst_count = 0;
}
/*
* check_commit - check interrupt and commit w.r.t. commit period
* return: NO_ERROR if successful, error code otherwise
* context(in): context
* Note:
* Checks to see if the interrupt flag was raised. If it was we check
* the interrupt type. We abort or commit based on the interrupt type.
* The interrupt type is determined by whether logging was enabled or not.
* Checks the state of the periodic commit counters.
* If this is enabled and the counter goes to zero, we commit
* the transaction.
*/
static int
check_commit (LDR_CONTEXT *context)
{
int err = NO_ERROR;
int64_t committed_instances = 0;
/* Check interrupt flag */
if (ldr_Load_interrupted)
{
if (ldr_Load_interrupted == LDR_STOP_AND_ABORT_INTERRUPT)
{
CHECK_ERR (err, db_abort_transaction ());
display_error_line (-1);
fprintf (stderr, msgcat_message (MSGCAT_CATALOG_UTILS, MSGCAT_UTIL_SET_LOADDB, LOADDB_MSG_INTERRUPTED_ABORT));
if (context->args->periodic_commit && Total_objects >= context->args->periodic_commit)
{
committed_instances = Total_objects - (context->args->periodic_commit - context->commit_counter);
}
else
{
committed_instances = 0;
}
}
else
{
if (context->cls != NULL)
{
CHECK_ERR (err, ldr_assign_all_perm_oids ());
CHECK_ERR (err, db_commit_transaction ());
Last_committed_line = ldr_Driver->get_scanner ().lineno () - 1;
committed_instances = Total_objects + 1;
display_error_line (-1);
fprintf (stderr,
msgcat_message (MSGCAT_CATALOG_UTILS, MSGCAT_UTIL_SET_LOADDB, LOADDB_MSG_INTERRUPTED_COMMIT));
}
}
/* Invoke post interrupt callback function */
if (ldr_post_interrupt_handler != NULL)
{
(*ldr_post_interrupt_handler) (committed_instances);
}
if (ldr_Jmp_buf_ptr != NULL)
{
longjmp (*ldr_Jmp_buf_ptr, 1);
}
else
{
return (err);
}
}
if (context->args->periodic_commit)
{
context->commit_counter--;
if (context->commit_counter <= 0)
{
if (context->cls != NULL)
{
print_log_msg (context->args->verbose,
msgcat_message (MSGCAT_CATALOG_UTILS, MSGCAT_UTIL_SET_LOADDB, LOADDB_MSG_COMMITTING));
CHECK_ERR (err, ldr_assign_all_perm_oids ());
CHECK_ERR (err, db_commit_transaction ());
Last_committed_line = ldr_Driver->get_scanner ().lineno () - 1;
context->commit_counter = context->args->periodic_commit;
/* Invoke post commit callback function */
if (ldr_post_commit_handler != NULL)
{
(*ldr_post_commit_handler) ((Total_objects + 1));
}
/* After a commit we need to ensure that our attributes and attribute descriptors are updated. The commit
* process can pull these from under us if another client is also updating the class. */
CHECK_ERR (err, ldr_refresh_attrs (context));
}
}
}
error_exit:
if (err != NO_ERROR)
{
display_error_line (-1);
fprintf (stderr, "%s\n", db_error_string (3));
committed_instances = (-1);
CHECK_CONTEXT_VALIDITY (context, true);
ldr_increment_err_count (context, 1);
}
return err;
}
/*
* ldr_restore_pin_and_drop_obj - restore pin flag of a object and delete the
* object optionally
* return: in
* context(in/out):
* drop_obj(in): if set, delete object also
*/
static void
ldr_restore_pin_and_drop_obj (LDR_CONTEXT *context, bool drop_obj)
{
if (context->obj)
{
ws_restore_pin (context->obj, context->obj_pin, context->class_pin);
if (drop_obj)
{
db_drop (context->obj);
context->obj = NULL;
}
}
}
/*
* ldr_fini_context - finish parse context
* return: NO_ERROR if successful, error code otherwise
* context(in/out): context
*/
static int
ldr_finish_context (LDR_CONTEXT *context)
{
int err = er_filter_errid (false);
if (err != NO_ERROR)
{
CHECK_CONTEXT_VALIDITY (context, true);
}
else
{
if (!context->validation_only)
{
/*
* Get permanent oids for the current class,
* Note : we have to this even if the instance total is 0 since
* we might have had forward object references, specified from
* class DEFAULT, SHARED or CLASS attributes
*/
CHECK_ERR (err, ldr_assign_all_perm_oids ());
/* Need to flush the class now, for class attributes. Class objects are flushed during a commit, if
* ws_intern_instances() is called and culls object references from within a class_object the class_object
* will loose these references. */
if (context->attr_type != LDR_ATTRIBUTE_ANY)
{
if (locator_flush_class (context->cls) != NO_ERROR)
{
CHECK_ERR (err, er_errid ());
}
}
}
if (context->inst_total && context->valid)
{
if (!context->validation_only)
{
ldr_flush (context);
CHECK_ERR (err, er_errid ());
}
if (context->args->verbose)
{
fprintf (stdout, msgcat_message (MSGCAT_CATALOG_UTILS, MSGCAT_UTIL_SET_LOADDB, LOADDB_MSG_INSTANCE_COUNT),
(context->class_name ? context->class_name : ""), context->inst_total);
}
}
}
/* Reset the action function to deal with attributes */
ldr_act = ldr_act_attr;
#if defined(CUBRID_DEBUG) || defined(CUBRID_DEBUG_TEST)
if (err == NO_ERROR)
{
if (context->inst_total)
{
printf ("%ld %s %s inserted in %d %s\n", context->inst_total, ldr_class_name (context),
context->inst_total == 1 ? "instance" : "instances", context->flush_total,
context->flush_total == 1 ? "flush" : "flushes");
}
if (context->err_total)
{
printf ("%d %s %s ignored because of errors\n", context->err_total, ldr_class_name (context),
context->err_total == 1 ? "instance" : "instances");
}
}
#endif /* CUBRID_DEBUG */
ldr_clear_and_free_context (context);
error_exit:
if (err != NO_ERROR)
{
ldr_abort ();
}
return (err);
}
/*
* ldr_act_init_context -
* return:
* context():
* class_name():
* len():
*/
static void
ldr_act_init_context (LDR_CONTEXT *context, const char *class_name, size_t len)
{
int err = NO_ERROR;
DB_OBJECT *class_mop;
CHECK_SKIP ();
er_clear ();
err = ldr_finish_context (context);
if (err != NO_ERROR)
{
display_error (-1);
return;
}
if (class_name)
{
const char *dot = NULL;
int len = 0, sub_len = 0;
len = STATIC_CAST (int, strlen (class_name));
sub_len = len;
dot = strchr (class_name, '.');
if (dot)
{
/* user specified name */
if (db_get_client_type () == DB_CLIENT_TYPE_ADMIN_LOADDB_COMPAT_UNDER_11_2)
{
db_set_client_type (DB_CLIENT_TYPE_ADMIN_LOADDB_COMPAT_UNDER_11_4);
}
/* user name of user specified name */
sub_len = STATIC_CAST (int, dot - class_name);
if (sub_len >= DB_MAX_USER_LENGTH)
{
display_error_line (0);
PRINT_AND_LOG_ERR_MSG (msgcat_message (MSGCAT_CATALOG_UTILS, MSGCAT_UTIL_SET_LOADDB,
LOADDB_MSG_EXCEED_MAX_USER_LEN),
DB_MAX_USER_LENGTH - 1);
CHECK_CONTEXT_VALIDITY (context, true);
ldr_abort ();
goto error_exit;
}
/* class name of user specified name */
sub_len = STATIC_CAST (int, strlen (dot + 1));
}
if (sub_len >= DB_MAX_IDENTIFIER_LENGTH - DB_MAX_USER_LENGTH)
{
display_error_line (0);
PRINT_AND_LOG_ERR_MSG (msgcat_message (MSGCAT_CATALOG_UTILS, MSGCAT_UTIL_SET_LOADDB,
LOADDB_MSG_EXCEED_MAX_LEN),
DB_MAX_IDENTIFIER_LENGTH - DB_MAX_USER_LENGTH - 1);
CHECK_CONTEXT_VALIDITY (context, true);
ldr_abort ();
goto error_exit;
}
class_mop = ldr_find_class (class_name);
if (class_mop == NULL)
{
display_error_line (0);
fprintf (stderr, msgcat_message (MSGCAT_CATALOG_UTILS, MSGCAT_UTIL_SET_LOADDB, LOADDB_MSG_UNKNOWN_CLASS),
class_name);
CHECK_CONTEXT_VALIDITY (context, true);
ldr_abort ();
goto error_exit;
}
if (!context->validation_only)
{
context->cls = class_mop;
/*
* Cache the class name. This will be used if we have a periodic
* commit and need to refresh the class
* This is a temporary fix, we will have to cache all the class
* names that we deal with, and refetch the classes and locks
* after a periodic commit.
*/
context->class_name = (char *) malloc (len + 1);
if (context->class_name == NULL)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_LDR_MEMORY_ERROR, 0);
CHECK_CONTEXT_VALIDITY (context, true);
ldr_abort ();
goto error_exit;
}
memcpy (context->class_name, class_name, len);
context->class_name[len] = '\0';
if (is_internal_class (context->cls))
{
err = ER_LDR_SYSTEM_CLASS;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, err, 1, class_name);
CHECK_CONTEXT_VALIDITY (context, true);
display_error (-1);
ldr_abort ();
CHECK_ERR (err, err);
}
err = sm_partitioned_class_type (class_mop, &context->class_type, NULL, NULL);
if (err != NO_ERROR)
{
CHECK_CONTEXT_VALIDITY (context, true);
ldr_abort ();
goto error_exit;
}
}
}
context->valid = true;
if (context->args->verbose && class_name != NULL)
{
fprintf (stdout, msgcat_message (MSGCAT_CATALOG_UTILS, MSGCAT_UTIL_SET_LOADDB, LOADDB_MSG_CLASS_TITLE),
class_name);
fflush (stdout);
}
CHECK_VALIDATION_ONLY (context);
if (context->cls)
{
if ((context->table = otable_find_class (context->cls)) == NULL)
{
err = ER_LDR_MEMORY_ERROR;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, err, 0);
display_error (-1);
ldr_internal_error (context);
CHECK_CONTEXT_VALIDITY (context, true);
}
}
error_exit:
return;
}
/*
* ldr_act_check_missing_non_null_attrs - xxx
* return:
* context(in): current context
* Note:
* xxx
*/
static int
ldr_act_check_missing_non_null_attrs (LDR_CONTEXT *context)
{
int err = NO_ERROR;
int i;
DB_ATTDESC *db_attdesc;
SM_CLASS *class_;
SM_ATTRIBUTE *att;
CHECK_SKIP_WITH (err);
RETURN_IF_NOT_VALID_WITH (context, err);
if (context->validation_only)
{
goto error_exit;
}
err = au_fetch_class (context->cls, &class_, AU_FETCH_READ, AU_SELECT);
if (err != NO_ERROR)
{
goto error_exit;
}
switch (context->attr_type)
{
case LDR_ATTRIBUTE_CLASS:
att = class_->class_attributes;
break;
case LDR_ATTRIBUTE_SHARED:
att = class_->shared;
break;
case LDR_ATTRIBUTE_ANY:
case LDR_ATTRIBUTE_DEFAULT:
att = class_->attributes;
break;
default:
att = NULL; /* impossible case */
break;
}
if (att == NULL)
{
goto error_exit; /* do nothing */
}
for (; att != NULL; att = (SM_ATTRIBUTE *) att->header.next)
{
if (att->flags & SM_ATTFLAG_NON_NULL)
{
for (i = 0; i < context->num_attrs; i++)
{
db_attdesc = context->attrs[i].attdesc;
if (db_attdesc->name_space == att->header.name_space
&& intl_identifier_casecmp (db_attdesc->name, att->header.name) == 0)
{
break;
}
}
/* not found */
if (i >= context->num_attrs)
{
char class_attr[DB_MAX_IDENTIFIER_LENGTH * 2];
snprintf (class_attr, DB_MAX_IDENTIFIER_LENGTH * 2, "%s.%s", context->class_name, att->header.name);
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OBJ_ATTRIBUTE_CANT_BE_NULL, 1, class_attr);
CHECK_ERR (err, ER_OBJ_ATTRIBUTE_CANT_BE_NULL);
}
}
}
error_exit:
if (err != NO_ERROR)
{
CHECK_CONTEXT_VALIDITY (context, true);
ldr_abort ();
}
return err;
}
/*
* ldr_act_add_attr - Sets up the appropriate setters for the dealing with the
* attributes.
* return: void
* context(in/out): current context
* attr_name(in): attribute name token
* len(in): length of token
* Note:
* Determines the target type and sets the setter accordingly
*/
static void
ldr_act_add_attr (LDR_CONTEXT *context, const char *attr_name, size_t len)
{
int err = NO_ERROR;
int i, n;
LDR_ATTDESC *attdesc, *attrs_old;
SM_CLASS *class_;
SM_COMPONENT **comp_ptr = NULL;
CHECK_SKIP ();
RETURN_IF_NOT_VALID (context);
if (context->validation_only)
{
context->num_attrs += 1;
goto error_exit;
}
n = context->num_attrs + context->arg_count;
attrs_old = context->attrs;
context->attrs = (LDR_ATTDESC *) realloc (context->attrs, (n + 1) * sizeof (context->attrs[0]));
if (context->attrs == NULL)
{
free_and_init (attrs_old); /* Prevent leakage if realloc fails */
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_LDR_MEMORY_ERROR, 0);
}
CHECK_PTR (err, context->attrs);
attdesc = &context->attrs[n];
attdesc->attdesc = NULL;
attdesc->att = NULL;
attdesc->parser_str_len = 0;
attdesc->parser_buf_len = 0;
attdesc->parser_str = NULL;
attdesc->ref_class = NULL;
attdesc->collection_domain = NULL;
/*
* Initialize the setters to something that hopefully won't crash and
* burn if either of the following initialization calls fails.
*/
for (i = 0; i < NUM_LDR_TYPES; i++)
{
attdesc->setter[i] = &ldr_ignore;
}
if (context->constructor)
{
/*
* At this point the parser has seen the CONSTRUCTOR syntax.
* We are dealing with arguments for the constructor.
* There is no attribute descriptor for method arguments so a check
* to see that the number of args is within the number of args specified
* is made and the function returns.
*/
if (context->constructor->signatures->num_args
&& (context->arg_count >= context->constructor->signatures->num_args))
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_LDR_UNEXPECTED_ARGUMENT, 1,
context->constructor->signatures->num_args);
CHECK_ERR (err, ER_LDR_UNEXPECTED_ARGUMENT);
}
return;
}
CHECK_ERR (err,
db_get_attribute_descriptor (context->cls, attr_name, context->attr_type == LDR_ATTRIBUTE_CLASS, true,
&attdesc->attdesc));
comp_ptr = (SM_COMPONENT **) (&attdesc->att);
CHECK_ERR (err, sm_get_descriptor_component (context->cls, attdesc->attdesc, 1, /* for update */
&class_, comp_ptr));
context->num_attrs += 1;
/*
* When dealing with class attributes the normal setters are not used, since
* they rely on the use of an empty instance.
*/
if (context->attr_type != LDR_ATTRIBUTE_ANY)
{
int invalid_attr = 0;
/*
* Set elements need to be gathhers in a collection value bucket
* We can use the existing setter for this.
*/
if (TP_IS_SET_TYPE (TP_DOMAIN_TYPE (attdesc->att->domain)))
{
attdesc->setter[LDR_COLLECTION] = &ldr_collection_db_collection;
CHECK_ERR (err, select_set_domain (context, attdesc->att->domain, & (attdesc->collection_domain)));
}
if (context->attr_type == LDR_ATTRIBUTE_SHARED)
{
if (attdesc->att->header.name_space != ID_SHARED_ATTRIBUTE)
{
invalid_attr = 1;
}
}
else if (context->attr_type == LDR_ATTRIBUTE_CLASS)
{
if (attdesc->att->header.name_space != ID_CLASS_ATTRIBUTE)
{
invalid_attr = 1;
}
}
if (invalid_attr)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_LDR_INVALID_CLASS_ATTR, 2, ldr_attr_name (context),
ldr_class_name (context));
CHECK_ERR (err, ER_LDR_INVALID_CLASS_ATTR);
}
goto error_exit;
}
/*
* Now that we know we really have an attribute descriptor and a
* SM_ATTRIBUTE, we can go ahead and initialize our setters to
* something that can exploit them.
*/
for (i = 0; i < NUM_LDR_TYPES; i++)
{
attdesc->setter[i] = &ldr_mismatch;
}
attdesc->setter[LDR_NULL] = &ldr_null_db_generic;
attdesc->setter[LDR_INT] = &ldr_int_db_generic;
attdesc->setter[LDR_NUMERIC] = &ldr_numeric_db_generic;
attdesc->setter[LDR_DOUBLE] = &ldr_real_db_generic;
attdesc->setter[LDR_FLOAT] = &ldr_real_db_generic;
/*
* These two system object setters are setup to return an
* appropriate error message to the user.
*/
attdesc->setter[LDR_SYS_USER] = &ldr_sys_user_db_generic;
attdesc->setter[LDR_SYS_CLASS] = &ldr_sys_class_db_generic;
switch (TP_DOMAIN_TYPE (attdesc->att->domain))
{
case DB_TYPE_CHAR:
attdesc->setter[LDR_STR] = &ldr_str_db_char;
break;
case DB_TYPE_VARCHAR:
attdesc->setter[LDR_STR] = &ldr_str_db_varchar;
break;
case DB_TYPE_BIGINT:
attdesc->setter[LDR_INT] = &ldr_int_db_bigint;
break;
case DB_TYPE_INTEGER:
attdesc->setter[LDR_INT] = &ldr_int_db_int;
break;
case DB_TYPE_SHORT:
attdesc->setter[LDR_INT] = &ldr_int_db_short;
break;
case DB_TYPE_FLOAT:
attdesc->setter[LDR_INT] = &ldr_real_db_float;
attdesc->setter[LDR_NUMERIC] = &ldr_real_db_float;
attdesc->setter[LDR_DOUBLE] = &ldr_real_db_float;
attdesc->setter[LDR_FLOAT] = &ldr_real_db_float;
break;
case DB_TYPE_DOUBLE:
attdesc->setter[LDR_INT] = &ldr_real_db_double;
attdesc->setter[LDR_NUMERIC] = &ldr_real_db_double;
attdesc->setter[LDR_DOUBLE] = &ldr_real_db_double;
attdesc->setter[LDR_FLOAT] = &ldr_real_db_double;
break;
case DB_TYPE_NUMERIC:
attdesc->setter[LDR_INT] = &ldr_int_db_generic;
attdesc->setter[LDR_NUMERIC] = &ldr_numeric_db_generic;
attdesc->setter[LDR_DOUBLE] = &ldr_real_db_generic;
attdesc->setter[LDR_FLOAT] = &ldr_real_db_generic;
break;
case DB_TYPE_DATE:
attdesc->setter[LDR_STR] = &ldr_str_db_generic;
attdesc->setter[LDR_DATE] = &ldr_date_db_date;
break;
case DB_TYPE_TIME:
attdesc->setter[LDR_STR] = &ldr_str_db_generic;
attdesc->setter[LDR_TIME] = &ldr_time_db_time;
break;
case DB_TYPE_TIMESTAMP:
attdesc->setter[LDR_STR] = &ldr_str_db_generic;
attdesc->setter[LDR_TIMESTAMP] = &ldr_timestamp_db_timestamp;
break;
case DB_TYPE_TIMESTAMPLTZ:
attdesc->setter[LDR_STR] = &ldr_str_db_generic;
attdesc->setter[LDR_TIMESTAMPLTZ] = &ldr_timestampltz_db_timestampltz;
break;
case DB_TYPE_TIMESTAMPTZ:
attdesc->setter[LDR_STR] = &ldr_str_db_generic;
attdesc->setter[LDR_TIMESTAMPTZ] = &ldr_timestamptz_db_timestamptz;
break;
case DB_TYPE_DATETIME:
attdesc->setter[LDR_STR] = &ldr_str_db_generic;
attdesc->setter[LDR_DATETIME] = &ldr_datetime_db_datetime;
break;
case DB_TYPE_DATETIMELTZ:
attdesc->setter[LDR_STR] = &ldr_str_db_generic;
attdesc->setter[LDR_DATETIMELTZ] = &ldr_datetimeltz_db_datetimeltz;
break;
case DB_TYPE_DATETIMETZ:
attdesc->setter[LDR_STR] = &ldr_str_db_generic;
attdesc->setter[LDR_DATETIMETZ] = &ldr_datetimetz_db_datetimetz;
break;
case DB_TYPE_SET:
case DB_TYPE_MULTISET:
case DB_TYPE_SEQUENCE:
attdesc->setter[LDR_COLLECTION] = &ldr_collection_db_collection;
CHECK_ERR (err, select_set_domain (context, attdesc->att->domain, & (attdesc->collection_domain)));
break;
case DB_TYPE_OBJECT:
case DB_TYPE_VOBJ:
attdesc->setter[LDR_CLASS_OID] = &ldr_class_oid_db_object;
attdesc->setter[LDR_OID] = &ldr_oid_db_object;
break;
case DB_TYPE_BIT:
case DB_TYPE_VARBIT:
attdesc->setter[LDR_BSTR] = &ldr_bstr_db_varbit;
attdesc->setter[LDR_XSTR] = &ldr_xstr_db_varbit;
break;
case DB_TYPE_BLOB:
case DB_TYPE_CLOB:
attdesc->setter[LDR_ELO_EXT] = &ldr_elo_ext_db_elo;
attdesc->setter[LDR_ELO_INT] = &ldr_elo_int_db_elo;
break;
case DB_TYPE_MONETARY:
attdesc->setter[LDR_MONETARY] = &ldr_monetary_db_monetary;
break;
case DB_TYPE_JSON:
attdesc->setter[LDR_STR] = &ldr_json_db_json;
break;
default:
break;
}
error_exit:
if (err != NO_ERROR)
{
CHECK_CONTEXT_VALIDITY (context, true);
ldr_abort ();
}
return;
}
/*
* ldr_refresh_attrs - refresh the attributes and attribute descriptors for
* a class.
* return: error code
* context(in): context
* Note:
* This is called after a periodic commit to refresh the attributes and
* attribute descriptors for a class. These may have been pulled from under
* us if another client updated the class.
* The attrs, LDR_ATTRS array, is traversed and each attribute, and
* attribute descriptor is refreshed for the current class.
*/
static int
ldr_refresh_attrs (LDR_CONTEXT *context)
{
int err = NO_ERROR;
DB_ATTDESC *db_attdesc;
LDR_ATTDESC *attdesc;
int i;
SM_CLASS *class_;
SM_COMPONENT **comp_ptr = NULL;
context->cls = ldr_find_class (context->class_name);
if (context->cls == NULL)
{
display_error (0);
return er_filter_errid (false);
}
for (i = 0; i < context->num_attrs; i += 1)
{
attdesc = & (context->attrs[i]);
CHECK_ERR (err,
db_get_attribute_descriptor (context->cls, attdesc->attdesc->name,
context->attr_type == LDR_ATTRIBUTE_CLASS, true, &db_attdesc));
/* Free existing descriptor */
db_free_attribute_descriptor (attdesc->attdesc);
attdesc->attdesc = db_attdesc;
/* Get refreshed attribute */
comp_ptr = (SM_COMPONENT **) & attdesc->att;
CHECK_ERR (err, sm_get_descriptor_component (context->cls, attdesc->attdesc, 1, /* for update */
&class_, comp_ptr));
}
error_exit:
return err;
}
/*
* ldr_act_restrict_attributes - called after ldr_start_class to indicate that
* the attributes being added are class/shared attributes rather than normal
* instance attributes.
* return: none
* context(in):
* type(in): type of attributes to expect
*/
static void
ldr_act_restrict_attributes (LDR_CONTEXT *context, attribute_type type)
{
CHECK_SKIP ();
RETURN_IF_NOT_VALID (context);
context->attr_type = type;
if (!context->validation_only)
{
/* Set the appropriate functions to handle class attributes */
ldr_act = ldr_act_class_attr;
}
}
/*
* update_default_count - Updates the default instances counter.
* return: none
* table(out):
* oid(in): not used
*/
static int
update_default_count (CLASS_TABLE *table, OID *oid)
{
ldr_Current_context->default_count++;
table->total_inserts++;
return NO_ERROR;
}
/*
* update_default_instances_stats - Update the statics of the number of
* instances referenced but never actually defined in the loader input file.
* return: NO_ERROR if successful, error code otherwise
* context(in): context
* Note:
* These will be inserted with all default values.
*/
static int
update_default_instances_stats (LDR_CONTEXT *context)
{
int err;
context->default_count = 0;
/*
* note that if we run out of space, the context->valid flag will get
* turned off, insert_default_instance needs to check this
*/
err = otable_map_reserved (update_default_count, 1);
return err;
}
/*
* ldr_destroy -
* return:
* context():
* err():
*/
static int
ldr_destroy (LDR_CONTEXT *context, int err)
{
int finish_error = NO_ERROR;
if (err)
{
ldr_clear_and_free_context (context);
}
else
{
finish_error = ldr_finish_context (context);
if (!finish_error && !context->validation_only && ! (context->err_total))
{
finish_error = update_default_instances_stats (context);
}
}
return finish_error;
}
/*
* insert_instance - Adds the instance to the loader internal oid table,
* otable, and adds the mop to the list of mops that require permanent oids,
* prior to flushing.
* return: NO_ERROR if successful, error code otherwise
* context(in/out): context
*/
static int
insert_instance (LDR_CONTEXT *context)
{
int err = NO_ERROR;
INST_INFO *inst;
if (!context->validation_only)
{
if (context->obj)
{
/*
* Note : instances without ids are not inserted in the otable as
* there can not be referenced from the load file.
*/
if (context->inst_num >= 0)
{
if (context->args->no_oid_hint)
{
CHECK_ERR (err, ldr_add_mop_tempoid_map (context->obj, context->table, context->inst_num));
}
else
{
inst = otable_find (context->table, context->inst_num);
if (inst == NULL || ! (inst->flags & INST_FLAG_RESERVED))
{
CHECK_ERR (err, otable_insert (context->table, WS_REAL_OID (context->obj), context->inst_num));
CHECK_PTR (err, inst = otable_find (context->table, context->inst_num));
CHECK_ERR (err, ldr_add_mop_tempoid_map (context->obj, context->table, context->inst_num));
}
else
{
err = otable_update (context->table, context->inst_num);
}
}
}
if (!err)
{
context->obj = NULL;
context->table->total_inserts++;
err = check_commit (context);
}
}
}
if (err)
{
ldr_internal_error (context);
}
else
{
context->inst_count++;
context->inst_total += 1;
Total_objects++;
if (context->args->verbose && context->status_count)
{
context->status_counter++;
if (context->status_counter >= context->status_count)
{
fprintf (stdout,
msgcat_message (MSGCAT_CATALOG_UTILS, MSGCAT_UTIL_SET_LOADDB, LOADDB_MSG_INSTANCE_COUNT_EX),
context->inst_total);
fflush (stdout);
context->status_counter = 0;
}
}
}
error_exit:
return err;
}
/*
* construct_instance - called to insert an instance using the current
* constructor method.
* return: object pointer
* context(in/out):
* Note:
* This simulates the token parsing here.
*/
static MOP
construct_instance (LDR_CONTEXT *context)
{
DB_VALUE *meth_args[LDR_MAX_ARGS + 1];
DB_VALUE retval;
int err = NO_ERROR;
MOP obj = NULL;
DB_VALUE vals[LDR_MAX_ARGS];
int i, a;
LDR_ATTDESC *attdesc;
SM_CLASS *class_;
SM_COMPONENT **comp_ptr = NULL;
for (i = 0, a = context->arg_index; i < context->arg_count && err == NO_ERROR && i < (int) LDR_MAX_ARGS; i++, a++)
{
err =
(* (elem_converter[context->attrs[a].parser_type])) (context, context->attrs[a].parser_str,
context->attrs[a].parser_str_len, &vals[i]);
meth_args[i] = & (vals[i]);
}
meth_args[i] = NULL;
err = db_send_argarray (context->cls, context->constructor->header.name, &retval, meth_args);
if (!err && DB_VALUE_TYPE (&retval) == DB_TYPE_OBJECT)
{
obj = db_get_object (&retval);
context->obj = obj;
err = au_fetch_instance (context->obj, &context->mobj, AU_FETCH_UPDATE, LC_FETCH_MVCC_VERSION, AU_UPDATE);
if (err == NO_ERROR)
{
ws_pin_instance_and_class (context->obj, &context->obj_pin, &context->class_pin);
ws_class_has_object_dependencies (context->cls);
}
/* now we have to initialize the instance with the supplied values */
for (context->next_attr = 0; context->next_attr < context->arg_index && !err; context->next_attr++)
{
attdesc = &context->attrs[context->next_attr];
comp_ptr = (SM_COMPONENT **) & attdesc->att;
err = sm_get_descriptor_component (context->cls, attdesc->attdesc, 1, &class_, comp_ptr);
if (!err)
{
err =
(* (attdesc->setter[attdesc->parser_type])) (context, attdesc->parser_str, attdesc->parser_str_len,
attdesc->att);
}
}
}
else
{
CHECK_ERR (err, ER_GENERIC_ERROR);
ldr_internal_error (context);
}
error_exit:
return context->obj;
}
/*
* insert_meth_instance - Inserts the pending instance generated for by a
* method call into the database.
* return: NO_ERROR if successful, error code otherwise
* context(in/out): context
*/
static int
insert_meth_instance (LDR_CONTEXT *context)
{
int err = NO_ERROR;
INST_INFO *inst;
MOP real_obj;
if (!context->validation_only)
{
if (context->constructor != NULL)
{
CHECK_PTR (err, real_obj = construct_instance (context));
if (real_obj == NULL)
{
CHECK_ERR (err, er_errid ());
}
else
{
ws_release_instance (real_obj);
inst = otable_find (context->table, context->inst_num);
if (inst == NULL || ! (inst->flags & INST_FLAG_RESERVED))
{
CHECK_ERR (err, otable_insert (context->table, WS_OID (real_obj), context->inst_num));
CHECK_PTR (err, inst = otable_find (context->table, context->inst_num));
CHECK_ERR (err, ldr_add_mop_tempoid_map (real_obj, context->table, context->inst_num));
}
else
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_LDR_FORWARD_CONSTRUCTOR, 0);
CHECK_ERR (err, ER_LDR_FORWARD_CONSTRUCTOR);
}
}
}
else
{
err = ER_GENERIC_ERROR;
}
}
if (err)
{
ldr_internal_error (context);
}
else
{
context->inst_count++;
context->inst_total += 1;
Total_objects++;
if (context->args->verbose && context->status_count)
{
context->status_counter++;
if (context->status_counter >= context->status_count)
{
fprintf (stdout,
msgcat_message (MSGCAT_CATALOG_UTILS, MSGCAT_UTIL_SET_LOADDB, LOADDB_MSG_INSTANCE_COUNT_EX),
context->inst_total);
fflush (stdout);
context->status_counter = 0;
}
}
}
error_exit:
return err;
}
/*
* ldr_act_set_constructor - Specifies a constructor method for the instances
* of the current class.
* return: NO_ERROR if successful, error code otherwise
* context(in/out): context
* name(in): method name
* Note:
* The name must be the name of a class method that when called will return
* an instance. After this function, the loader will expect zero or more
* calls to ldr_act_add_argument to specify any arguments that must be
* passed to the constructor method.
*/
static int
ldr_act_set_constructor (LDR_CONTEXT *context, const char *name)
{
int err = NO_ERROR;
SM_METHOD *meth;
CHECK_SKIP_WITH (err);
if (context->validation_only)
{
context->arg_index = context->num_attrs;
/* setup the appropriate constructor handling functions */
ldr_act = ldr_act_meth;
goto error_exit;
}
if (context->valid)
{
meth = db_get_class_method (context->cls, name);
if (meth == NULL)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_LDR_INVALID_CONSTRUCTOR, 2, name, ldr_class_name (context));
CHECK_ERR (err, ER_LDR_INVALID_CONSTRUCTOR);
}
else
{
/* for now, a method can have exactly one signature */
context->constructor = meth;
context->arg_index = context->num_attrs;
/* setup the appropriate constructor handling functions */
ldr_act = ldr_act_meth;
}
}
error_exit:
if (err != NO_ERROR)
{
CHECK_CONTEXT_VALIDITY (context, true);
ldr_abort ();
}
return err;
}
/*
* add_element - add an element to either the loader's argument array
* return: success code (non-zero if ok)
* elements(in): pointer to an array of pointers
* count(in/out): current index (and returned new index)
* max(in/out): maximum size (and returned maximum size)
* grow(in): amount to grow if necessary
* Note:
* We first check to see if *count is less than *max, if so we simply
* increment count. If not, we extend the array, return the incremented
* count and also returned the new max size.
*/
static int
add_element (void ***elements, int *count, int *max, int grow)
{
int new_ = -1, resize, i;
int err = NO_ERROR;
void ***elements_old;
if (*count >= *max)
{
resize = *max + grow;
elements_old = elements;
*elements = (void **) realloc (*elements, sizeof (void *) * resize);
if (*elements == NULL)
{
free_and_init (*elements_old); /* Prevent leak if realloc fails */
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_LDR_MEMORY_ERROR, 0);
}
CHECK_PTR (err, *elements);
for (i = *count; i < resize; i++)
{
(*elements)[i] = NULL;
}
*max = resize;
}
new_ = *count;
*count = new_ + 1;
error_exit:
if (err != NO_ERROR || *elements == NULL)
{
return (-1);
}
return new_;
}
/*
* add_argument - Extends the loader's argument array.
* return: next argument index
* context(out): context
*/
static int
add_argument (LDR_CONTEXT *context)
{
int index;
index =
add_element ((void ***) (& (context->method_args)), & (context->arg_count), & (context->max_arg), LDR_ARG_GROW_SIZE);
return index;
}
/*
* ldr_act_add_argument - specify parameters to an instance constructor method
* previously specified with ldr_act_set_constructor.
* return: NO_ERROR if successful, error code otherwise
* context(in/out): context
* name(in): argument name
* Note:
* The name isn't really important here since method argumetns don't
* have domains. It is however important to specify as many arguments
* as the method expects because the domain validation will be
* done positionally according to the method signature in the schema.
*/
static int
ldr_act_add_argument (LDR_CONTEXT *context, const char *name)
{
int err = NO_ERROR;
SM_METHOD_SIGNATURE *sig;
SM_METHOD_ARGUMENT *arg;
int index;
CHECK_SKIP_WITH (err);
if (context->validation_only)
{
context->arg_count += 1;
goto error_exit;
}
if (context->valid)
{
if (context->constructor == NULL)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_LDR_UNEXPECTED_ARGUMENT, 1, 0);
CHECK_ERR (err, ER_LDR_UNEXPECTED_ARGUMENT);
}
else
{
sig = context->constructor->signatures;
/* arg count of zero currently means "variable", not good */
if (sig->num_args && (context->arg_count) >= sig->num_args)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_LDR_UNEXPECTED_ARGUMENT, 1, sig->num_args);
CHECK_ERR (err, ER_LDR_UNEXPECTED_ARGUMENT);
}
else
{
/* Locate the argument descriptor, remember to adjust for 1 based argument numbering. */
arg = classobj_find_method_arg (&sig->args, context->arg_count, 0);
/* This is called to setup the LDR_ATTDESC structure */
ldr_act_add_attr (context, name, strlen (name));
index = add_argument (context);
if (index >= 0)
{
context->method_args[index] = arg;
}
else
{
err = ER_LDR_MEMORY_ERROR;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, err, 0);
ldr_internal_error (context);
CHECK_ERR (err, err);
}
}
}
}
error_exit:
if (err != NO_ERROR)
{
CHECK_CONTEXT_VALIDITY (context, true);
ldr_abort ();
}
return err;
}
/*
* invalid_class_id_error - called when invalid class id is met.
* return:
* context(in):
* id(in): class id
*/
static void
invalid_class_id_error (LDR_CONTEXT *context, int id)
{
display_error_line (0);
fprintf (stderr, msgcat_message (MSGCAT_CATALOG_UTILS, MSGCAT_UTIL_SET_LOADDB, LOADDB_MSG_UNKNOWN_CLASS_ID), id,
ldr_attr_name (context), ldr_class_name (context));
CHECK_CONTEXT_VALIDITY (context, true);
}
/*
* ldr_act_set_ref_class - Find the class that is about to be used in an
* instance reference.
* return: void
* context(in/out): context
* name(in): class name
*/
static void
ldr_act_set_ref_class (LDR_CONTEXT *context, char *name)
{
DB_OBJECT *mop;
CHECK_SKIP ();
RETURN_IF_NOT_VALID (context);
if (!context->validation_only)
{
mop = db_find_class (name);
if (mop != NULL)
{
context->attrs[context->next_attr].ref_class = mop;
}
else
{
ldr_invalid_class_error (context);
}
}
}
/*
* ldr_act_set_instance_id - Set the instance to be used from the reference
* class
* return: void
* context(in/out): context
* id(in): instance id for ref_class already set
*/
static void
ldr_act_set_instance_id (LDR_CONTEXT *context, int id)
{
CHECK_SKIP ();
RETURN_IF_NOT_VALID (context);
if (!context->validation_only)
{
if (context->attrs[context->next_attr].ref_class != NULL)
{
context->attrs[context->next_attr].instance_id = id;
}
else
{
CHECK_CONTEXT_VALIDITY (context, true);
}
}
}
/*
* ldr_act_set_ref_class_id - Find the class that is about to be used in an
* instance reference
* return: void
* context(in/out): context
* id(in): class id
* Note:
* Unlike act_set_ref_class, the class is identified through a previously
* assigned id number.
*/
static void
ldr_act_set_ref_class_id (LDR_CONTEXT *context, int id)
{
DB_OBJECT *class_;
CHECK_SKIP ();
RETURN_IF_NOT_VALID (context);
if (!context->validation_only)
{
class_ = ldr_get_class_from_id (id);
if (class_ != NULL)
{
context->attrs[context->next_attr].ref_class = class_;
}
else
{
invalid_class_id_error (context, id);
}
}
}
static DB_OBJECT *
ldr_act_get_ref_class (LDR_CONTEXT *context)
{
RETURN_IF_NOT_VALID_WITH (context, NULL);
if (!context->validation_only)
{
return context->attrs[context->next_attr].ref_class;
}
return NULL;
}
/*
* ldr_init_loader - Initializes the global loader state.
* return: NO_ERROR if successful, error code otherwise
* context(in/out): context
* Note:
* This should be called once prior to loader operation.
*/
static int
ldr_init_loader (LDR_CONTEXT *context)
{
int i;
int err = NO_ERROR;
DB_DATETIME datetime;
DB_DATETIMETZ datetimetz;
DB_TIMESTAMPTZ timestamptz;
DB_ELO *null_elo = NULL;
/*
* Definitely *don't* want to use oid preflushing in this app; it just
* gives us some extra overhead that we don't care about.
*/
tm_Use_OID_preflush = false;
/* Set the appropriate action function for normal attribute values */
ldr_act = ldr_act_attr;
/*
* Optimization to avoid calling db_value_domain_init all of the time
* during loading; we can simply copy these templates much more cheaply.
*/
db_make_short (&ldr_short_tmpl, 0);
db_make_int (&ldr_int_tmpl, 0);
db_make_bigint (&ldr_bigint_tmpl, 0);
db_make_char (&ldr_char_tmpl, 1, "a", 1, LANG_SYS_CODESET, LANG_SYS_COLLATION);
db_make_varchar (&ldr_varchar_tmpl, 1, "a", 1, LANG_SYS_CODESET, LANG_SYS_COLLATION);
db_make_float (&ldr_float_tmpl, (float) 0.0);
db_make_double (&ldr_double_tmpl, (double) 0.0);
db_make_date (&ldr_date_tmpl, 1, 1, 1996);
db_make_time (&ldr_time_tmpl, 0, 0, 0);
db_make_timestamp (&ldr_timestamp_tmpl, 0);
timestamptz.timestamp = 0;
timestamptz.tz_id = 0;
db_make_timestampltz (&ldr_timestampltz_tmpl, 0);
db_make_timestamptz (&ldr_timestamptz_tmpl, ×tamptz);
db_datetime_encode (&datetime, 1, 1, 1996, 0, 0, 0, 0);
db_make_datetime (&ldr_datetime_tmpl, &datetime);
datetimetz.datetime = datetime;
datetimetz.tz_id = 0;
db_make_datetimeltz (&ldr_datetimeltz_tmpl, & (datetimetz.datetime));
db_make_datetimetz (&ldr_datetimetz_tmpl, &datetimetz);
db_make_elo (&ldr_blob_tmpl, DB_TYPE_BLOB, null_elo);
db_make_elo (&ldr_clob_tmpl, DB_TYPE_CLOB, null_elo);
db_make_bit (&ldr_bit_tmpl, 1, "0", 1);
db_make_json (&ldr_json_tmpl, NULL, false);
/*
* Set up the conversion functions for collection elements. These
* don't need to be done on a per-attribute basis (well, I suppose they
* could if we were really worried about it, but for now we let the
* usual domain coercion stuff take care of the dirty work).
*/
for (i = 0; i < NUM_LDR_TYPES; i++)
{
elem_converter[i] = &ldr_null_elem;
}
elem_converter[LDR_NULL] = &ldr_null_elem;
elem_converter[LDR_INT] = &ldr_int_elem;
elem_converter[LDR_STR] = &ldr_str_elem;
elem_converter[LDR_NUMERIC] = &ldr_numeric_elem;
elem_converter[LDR_DOUBLE] = &ldr_double_elem;
elem_converter[LDR_FLOAT] = &ldr_float_elem;
elem_converter[LDR_OID] = &ldr_oid_elem;
elem_converter[LDR_CLASS_OID] = &ldr_class_oid_elem;
elem_converter[LDR_DATE] = &ldr_date_elem;
elem_converter[LDR_TIME] = &ldr_time_elem;
elem_converter[LDR_TIMESTAMP] = &ldr_timestamp_elem;
elem_converter[LDR_TIMESTAMPLTZ] = &ldr_timestampltz_elem;
elem_converter[LDR_TIMESTAMPTZ] = &ldr_timestamptz_elem;
elem_converter[LDR_DATETIME] = &ldr_datetime_elem;
elem_converter[LDR_DATETIMELTZ] = &ldr_datetimeltz_elem;
elem_converter[LDR_DATETIMETZ] = &ldr_datetimetz_elem;
elem_converter[LDR_COLLECTION] = &ldr_collection_elem;
elem_converter[LDR_BSTR] = &ldr_bstr_elem;
elem_converter[LDR_XSTR] = &ldr_xstr_elem;
elem_converter[LDR_MONETARY] = &ldr_monetary_elem;
elem_converter[LDR_ELO_EXT] = &ldr_elo_ext_elem;
elem_converter[LDR_ELO_INT] = &ldr_elo_int_elem;
elem_converter[LDR_JSON] = &ldr_json_elem;
/* Set up the lockhint array. Used by ldr_find_class() when locating a class. */
ldr_Hint_locks[0] = locator_fetch_mode_to_lock (DB_FETCH_CLREAD_INSTWRITE, LC_CLASS, LC_FETCH_CURRENT_VERSION);
ldr_Hint_class_names[0] = NULL;
ldr_Hint_subclasses[0] = 0;
ldr_Hint_flags[0] = LC_PREF_FLAG_LOCK;
Total_objects = 0;
Total_fails = 0;
ldr_clear_context (context);
ldr_act_init_context (context, NULL, 0);
ldr_Current_context = context;
ldr_clear_err_total (context);
context->validation_only = 0;
context->valid = true;
context->flush_total = 0;
return (err);
}
/*
* ldr_init - This prepares the loader for use.
* return: none
* verbose(in): non-zero to enable printing of status messages
* Note:
* If the verbose flag is on, status messages will be displayed
* as the load proceeds.
* The loader is initially configured for validation mode.
* Call ldr_start() to clear the current state and enter
* insertion mode.
*/
static int
ldr_init (load_args *args)
{
LDR_CONTEXT *context;
ldr_Current_context = &ldr_Context;
context = ldr_Current_context;
context->args = args;
if (ldr_init_loader (ldr_Current_context))
{
assert (er_errid () != NO_ERROR);
return er_errid ();
}
idmap_init ();
if (otable_init ())
{
assert (er_errid () != NO_ERROR);
return er_errid ();
}
if (clist_init ())
{
assert (er_errid () != NO_ERROR);
return er_errid ();
}
context->validation_only = true;
context->status_count = 0;
/* used to monitor the number of insertions performed */
context->status_counter = 0;
context->status_count = 10;
obt_enable_unique_checking (false);
return NO_ERROR;
}
/*
* ldr_start - This prepares the loader for actual insertion of data.
* return: none
* periodic_commit(in): periodic_commit interval value
* Note:
* It is commonly called after the input file has been processed
* once for syntax checking. It can also be called immediately
* after ldr_init() to skip the syntax check and go right into
* insertion mode.
*/
static int
ldr_start ()
{
int err;
LDR_CONTEXT *context;
if (!ldr_Current_context)
{
ldr_Current_context = &ldr_Context;
}
context = ldr_Current_context;
ldr_clear_context (context);
/*
* Initialize the mop -> temporary_oid, table used to obtain a mapping
* between permanent OID and workspace mop, when permanent OIDs are obtained.
*/
err = ldr_mop_tempoid_maps_init ();
if (err != NO_ERROR)
{
return err;
}
context->validation_only = 0;
if (context->args->periodic_commit <= 0)
{
context->args->periodic_commit = 0;
}
else
{
context->commit_counter = context->args->periodic_commit;
}
/* make sure we reset this to get accurate statistics */
Total_objects = 0;
Total_fails = 0;
return NO_ERROR;
}
/*
* ldr_final - shut down the loader.
* return: void
* Note:
* Since there may be a pending instance that has not yet been inserted,
* you must always call ldr_destroy to make sure this occurs.
* If the caller detects an error and wishes to abort the load immediate,
* pass in non-zero and the pending instance will not be inserted.
* After this call, the loader cannot be used and the session
* must begin again with a ldr_init() call.
*/
static int
ldr_final (void)
{
int shutdown_error = NO_ERROR;
LDR_CONTEXT *context;
context = ldr_Current_context;
shutdown_error = ldr_destroy (context, 1);
clist_final ();
idmap_final ();
otable_final ();
ldr_mop_tempoid_maps_final ();
return shutdown_error;
}
static void
ldr_init_driver ()
{
if (ldr_Driver != NULL)
{
return;
}
ldr_Driver = new driver ();
cubthread::get_entry ().m_loaddb_driver = ldr_Driver;
error_handler *error_handler_ = new error_handler ();
class_installer *cls_installer = new sa_class_installer ();
object_loader *obj_loader = new sa_object_loader ();
ldr_Driver->initialize (cls_installer, obj_loader, error_handler_);
}
void
ldr_sa_load (load_args *args, int *status, volatile bool *interrupted)
{
int errors = 0;
int64_t objects = 0;
int defaults = 0;
int fails = 0;
int64_t lastcommit = 0;
volatile bool is_emptyfile = false;
int ldr_init_ret = NO_ERROR;
int client_type = DB_CLIENT_TYPE_LOADDB_UTILITY;
std::ifstream object_file (args->object_file);
ldr_init_driver ();
locator_Dont_check_foreign_key = true;
if (ldr_init (args) != NO_ERROR)
{
goto exit;
}
/* set the flag to indicate what type of interrupts to raise If logging has been disabled set commit flag. If
* logging is enabled set abort flag. */
if (args->ignore_logging)
{
ldr_Interrupt_type = LDR_STOP_AND_COMMIT_INTERRUPT;
}
else
{
ldr_Interrupt_type = LDR_STOP_AND_ABORT_INTERRUPT;
}
if (args->periodic_commit)
{
/* register the post commit function */
ldr_register_post_commit_handler ();
}
/* get the size of object file */
object_file.seekg (0, std::ios::end);
if (object_file.tellg() <= 0)
{
is_emptyfile = true;
}
object_file.seekg (0, std::ios::beg);
client_type = db_get_client_type ();
/* Check if we need to perform syntax checking. */
if (!args->load_only)
{
print_log_msg ((int) args->verbose,
msgcat_message (MSGCAT_CATALOG_UTILS, MSGCAT_UTIL_SET_LOADDB, LOADDB_MSG_CHECKING));
if (!args->table_name.empty ())
{
ldr_init_ret = ldr_Driver->get_class_installer ().install_class (args->table_name.c_str ());
}
if (!is_emptyfile)
{
ldr_Driver->parse (object_file);
}
ldr_stats (&errors, &objects, &defaults, &lastcommit, &fails);
}
else
{
errors = 0;
}
if (errors)
{
print_log_msg (1, msgcat_message (MSGCAT_CATALOG_UTILS, MSGCAT_UTIL_SET_LOADDB, LOADDB_MSG_ERROR_COUNT), errors);
}
else if (ldr_init_ret == NO_ERROR && !args->syntax_check)
{
/* now do it for real if there were no errors and we aren't doing a simple syntax check */
ldr_start ();
object_file.close ();
object_file.open (args->object_file, std::fstream::in | std::fstream::binary);
if (object_file.is_open ())
{
if (client_type == DB_CLIENT_TYPE_ADMIN_LOADDB_COMPAT_UNDER_11_2)
{
if (db_get_client_type () == DB_CLIENT_TYPE_ADMIN_LOADDB_COMPAT_UNDER_11_4)
{
if (args->verbose)
{
print_log_msg (1, "\n");
print_log_msg (1,
msgcat_message (MSGCAT_CATALOG_UTILS, MSGCAT_UTIL_SET_LOADDB,
LOADDB_MSG_COMPAT_UNDER_11_4));
}
}
else
{
assert (db_get_client_type () == DB_CLIENT_TYPE_ADMIN_LOADDB_COMPAT_UNDER_11_2);
}
}
print_log_msg ((int) args->verbose,
msgcat_message (MSGCAT_CATALOG_UTILS, MSGCAT_UTIL_SET_LOADDB, LOADDB_MSG_INSERTING));
/* make sure signals are caught */
util_arm_signal_handlers (ldr_signal_handler, ldr_signal_handler);
/* register function to call and jmp environment to longjmp to after aborting or committing. */
ldr_register_post_interrupt_handler ();
if (setjmp (ldr_Jmp_buf) != 0)
{
/* We have had an interrupt, the transaction should have been already been aborted or committed by
* the loader. If Total_objects_loaded is -1 an error occurred during rollback or commit. */
if (Total_objects_loaded != -1)
{
print_log_msg (1,
msgcat_message (MSGCAT_CATALOG_UTILS, MSGCAT_UTIL_SET_LOADDB,
LOADDB_MSG_OBJECT_COUNT), Total_objects_loaded);
}
ldr_stats (&errors, &objects, &defaults, &lastcommit, &fails);
if (lastcommit > 0)
{
print_log_msg (1,
msgcat_message (MSGCAT_CATALOG_UTILS, MSGCAT_UTIL_SET_LOADDB,
LOADDB_MSG_LAST_COMMITTED_LINE), lastcommit);
}
*interrupted = true;
}
else
{
if (!args->table_name.empty ())
{
ldr_Driver->get_class_installer ().install_class (args->table_name.c_str ());
}
if (!is_emptyfile)
{
ldr_Driver->parse (object_file);
}
ldr_stats (&errors, &objects, &defaults, &lastcommit, &fails);
if (errors)
{
if (lastcommit > 0)
{
print_log_msg (1,
msgcat_message (MSGCAT_CATALOG_UTILS, MSGCAT_UTIL_SET_LOADDB,
LOADDB_MSG_LAST_COMMITTED_LINE), lastcommit);
}
util_log_write_errstr ("%s\n", db_error_string (3));
/*
* don't allow the transaction to be committed at
* this point, note that if we ever move to a scheme
* where we write directly to the heap without the
* transaction context, we will have to unwind the
* changes made if errors are detected !
*/
db_abort_transaction ();
}
else
{
print_log_msg (1,
msgcat_message (MSGCAT_CATALOG_UTILS, MSGCAT_UTIL_SET_LOADDB,
LOADDB_MSG_INSERT_AND_FAIL_COUNT), objects, fails);
if (defaults)
{
print_log_msg (1,
msgcat_message (MSGCAT_CATALOG_UTILS, MSGCAT_UTIL_SET_LOADDB,
LOADDB_MSG_DEFAULT_COUNT), defaults);
}
print_log_msg ((int) args->verbose,
msgcat_message (MSGCAT_CATALOG_UTILS, MSGCAT_UTIL_SET_LOADDB, LOADDB_MSG_COMMITTING));
/* commit the transaction and then update statistics */
if (!db_commit_transaction ())
{
if (!args->disable_statistics)
{
if (args->verbose)
{
print_log_msg (1,
msgcat_message (MSGCAT_CATALOG_UTILS, MSGCAT_UTIL_SET_LOADDB,
LOADDB_MSG_UPDATING_STATISTICS));
}
if (!ldr_update_statistics ())
{
/*
* would it be faster to update statistics
* before the first commit and just have a
* single commit ?
*/
print_log_msg ((int) args->verbose,
msgcat_message (MSGCAT_CATALOG_UTILS, MSGCAT_UTIL_SET_LOADDB,
LOADDB_MSG_COMMITTING));
(void) db_commit_transaction ();
}
}
}
}
}
}
}
if (errors > 0 || *interrupted == true)
{
*status = 3;
}
exit:
ldr_final ();
if (ldr_Driver != NULL)
{
delete ldr_Driver;
ldr_Driver = NULL;
cubthread::get_entry ().m_loaddb_driver = NULL;
}
if (object_file.is_open ())
{
object_file.close ();
}
}
/*
* ldr_register_post_interrupt_handler - registers a post interrupt callback
* function.
* return: void return, sets ldr_post_interrupt_handler
*/
void static
ldr_register_post_interrupt_handler ()
{
ldr_Jmp_buf_ptr = &ldr_Jmp_buf;
ldr_post_interrupt_handler = &ldr_get_num_of_inserted_objects;
}
/*
* ldr_register_post_commit_handler - registers a post commit callback
* function.
* return: void return, sets ldr_post_commit_handler
*/
static void
ldr_register_post_commit_handler ()
{
ldr_post_commit_handler = &ldr_report_num_of_commits;
}
/*
* ldr_stats - This is used to access the statistics maintained during loading.
* return: void
* errors(out): return error count
* objects(out): return object count
* defaults(out): return default object count
* lastcommit(out):
* fails(out): return fail count
*/
static void
ldr_stats (int *errors, int64_t *objects, int *defaults, int64_t *lastcommit, int *fails)
{
if (errors != NULL)
{
*errors = ldr_Current_context->err_total;
}
if (objects != NULL)
{
*objects = Total_objects;
}
if (defaults != NULL)
{
*defaults = ldr_Current_context->default_count;
}
if (lastcommit != NULL)
{
*lastcommit = Last_committed_line;
}
if (fails != NULL)
{
*fails = Total_fails;
}
}
/*
* ldr_update_statistics - update statistics
* return: NO_ERROR if successful, error code otherwise
* Note:
* This can be called after loading has finished but BEFORE ldr_final
* to update the statistics for the classes that were involved
* in the load.
*/
static int
ldr_update_statistics (void)
{
int err = NO_ERROR;
const char *class_name = NULL;
for (CLASS_TABLE *table = Classes; table != NULL && !err; table = table->next)
{
if (ldr_Current_context->args->verbose)
{
class_name = sm_get_ch_name (table->class_);
if (class_name == NULL)
{
err = er_errid ();
assert (err != NO_ERROR);
break;
}
fprintf (stdout, msgcat_message (MSGCAT_CATALOG_UTILS, MSGCAT_UTIL_SET_LOADDB, LOADDB_MSG_CLASS_TITLE),
class_name);
fflush (stdout);
}
err = sm_update_statistics (table->class_, STATS_WITH_SAMPLING);
}
return err;
}
/*
* ldr_abort - immediately error exit function
* return: void
*/
static void
ldr_abort (void)
{
db_abort_transaction ();
if (ldr_post_interrupt_handler != NULL)
{
(*ldr_post_interrupt_handler) (-1);
}
if (ldr_Jmp_buf_ptr != NULL)
{
longjmp (*ldr_Jmp_buf_ptr, 1);
}
}
static void
ldr_act_set_skip_current_class (char *class_name, size_t size)
{
skip_current_class = ldr_is_ignore_class (class_name, size);
if (skip_current_class && !ldr_Current_context->validation_only)
{
print_log_msg (1, "Class %s is ignored.\n", class_name);
}
}
static bool
ldr_is_ignore_class (const char *class_name, size_t size)
{
if (class_name == NULL)
{
return false;
}
if (IS_OLD_GLO_CLASS (class_name))
{
return true;
}
for (std::string &ignore_class : ldr_Current_context->args->ignore_classes)
{
if (intl_identifier_ncasecmp (ignore_class.c_str (), class_name, (int) MAX (ignore_class.size (), size)) == 0)
{
return true;
}
}
return false;
}
static void
ldr_process_object_ref (object_ref_type *ref, int type)
{
bool ignore_class = false;
const char *class_name;
DB_OBJECT *ref_class = NULL;
if (ref->class_id && ref->class_id->val)
{
ldr_act_set_ref_class_id (ldr_Current_context, atoi (ref->class_id->val));
}
else
{
ldr_act_set_ref_class (ldr_Current_context, ref->class_name->val);
}
if (ref->instance_number && ref->instance_number->val)
{
ldr_act_set_instance_id (ldr_Current_context, atoi (ref->instance_number->val));
}
else
{
/* ldr_act_set_instance_id(ldr_Current_context, 0); *//* right?? */
}
ref_class = ldr_act_get_ref_class (ldr_Current_context);
if (ref_class != NULL)
{
class_name = db_get_class_name (ref_class);
ignore_class = ldr_is_ignore_class (class_name, ((class_name) ? strlen (class_name) : 0));
}
if (type == LDR_OID)
{
(*ldr_act) (ldr_Current_context, ref->instance_number->val,
((ref->instance_number->val == NULL) ? 0 : ref->instance_number->size),
(ignore_class) ? LDR_NULL : LDR_OID);
}
else
{
/* right ?? */
if (ref->class_name)
{
(*ldr_act) (ldr_Current_context, ref->class_name->val, ref->class_name->size,
(ignore_class) ? LDR_NULL : LDR_CLASS_OID);
}
else
{
(*ldr_act) (ldr_Current_context, ref->class_id->val, ((ref->class_id->val == NULL) ? 0 : ref->class_id->size),
(ignore_class) ? LDR_NULL : LDR_CLASS_OID);
}
}
delete ref;
}
static int
ldr_act_add_class_all_attrs (const char *class_name)
{
int err = NO_ERROR;
SM_CLASS *class_;
DB_OBJECT *class_mop;
RETURN_IF_NOT_VALID_WITH (ldr_Current_context, ER_FAILED);
if (ldr_Current_context->validation_only)
{
assert (ldr_Current_context->cls == NULL);
class_mop = ldr_find_class (class_name);
if (class_mop == NULL)
{
display_error_line (0);
fprintf (stderr, msgcat_message (MSGCAT_CATALOG_UTILS, MSGCAT_UTIL_SET_LOADDB, LOADDB_MSG_UNKNOWN_CLASS),
class_name);
err = er_filter_errid (false);
goto error_exit;
}
}
else
{
class_mop = ldr_Current_context->cls;
}
CHECK_ERR (err, au_fetch_class (class_mop, &class_, AU_FETCH_READ, AU_SELECT));
for (SM_ATTRIBUTE *att = class_->ordered_attributes; att != NULL; att = att->order_link)
{
ldr_act_add_attr (ldr_Current_context, att->header.name, strlen (att->header.name));
}
return NO_ERROR;
error_exit:
if (err != NO_ERROR)
{
CHECK_CONTEXT_VALIDITY (ldr_Current_context, true);
ldr_abort ();
}
return ER_FAILED;
}
static int
ldr_json_elem (LDR_CONTEXT *context, const char *str, size_t len, DB_VALUE *val)
{
JSON_DOC *document = NULL;
int error_code = NO_ERROR;
error_code = db_json_get_json_from_str (str, document, len);
if (error_code != NO_ERROR)
{
assert (document == NULL);
return error_code;
}
db_make_json (val, document, true);
return NO_ERROR;
}
static int
ldr_json_db_json (LDR_CONTEXT *context, const char *str, size_t len, SM_ATTRIBUTE *att)
{
int err = NO_ERROR;
DB_VALUE val;
db_make_null (&val);
CHECK_ERR (err, ldr_json_elem (context, str, len, &val));
CHECK_ERR (err, ldr_generic (context, &val));
error_exit:
db_value_clear (&val);
return err;
}
/*
* ldr_signal_handler - signal handler registered via util_arm_signal_handlers
* return: void
*/
static void
ldr_signal_handler (void)
{
ldr_Load_interrupted = ldr_Interrupt_type;
print_log_msg (1, msgcat_message (MSGCAT_CATALOG_UTILS, MSGCAT_UTIL_SET_LOADDB, LOADDB_MSG_SIG1));
}
/*
* ldr_report_num_of_commits - report number of commits
* return: void
* num_committed(in): number of commits
*
* Note:
* registered as a callback function the loader will call this function
* to report the number of insertion that have taken place if the '-vc',
* verbose commit parameter was specified.
*/
static void
ldr_report_num_of_commits (int64_t num_committed)
{
print_log_msg (ldr_Current_context->args->verbose_commit,
msgcat_message (MSGCAT_CATALOG_UTILS, MSGCAT_UTIL_SET_LOADDB, LOADDB_MSG_COMMITTED_INSTANCES),
(ldr_Current_context->class_name ? ldr_Current_context->class_name : ""), num_committed);
}
/*
* ldr_get_num_of_inserted_objects - set of object inserted value to
* Total_objects_loaded global variable
* return: void
* num_objects(in): number of inserted object to set
*/
static void
ldr_get_num_of_inserted_objects (int64_t num_objects)
{
Total_objects_loaded = num_objects;
}