8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-23 23:23:04 +01:00
firebird-mirror/src/jrd/ini.epp
alexpeshkoff 67f1740fea Various cleanup to make engine compile and work after mentioned earlier changes.
Mainly:
1) MemoryPool* => MemoryPool& in arrays' constructors
2) use Firebird::string to keep strings data
2004-03-14 13:40:14 +00:00

1606 lines
44 KiB
Plaintext

/*
* PROGRAM: JRD Access Method
* MODULE: ini.epp
* DESCRIPTION: Metadata initialization / population
*
* The contents of this file are subject to the Interbase Public
* License Version 1.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.Inprise.com/IPL.html
*
* Software distributed under the License is distributed on an
* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express
* or implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code was created by Inprise Corporation
* and its predecessors. Portions created by Inprise Corporation are
* Copyright (C) Inprise Corporation.
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
*/
#include "firebird.h"
#include <stdio.h>
#include <string.h>
#include "../jrd/flags.h"
#include "../jrd/jrd.h"
#include "../jrd/val.h"
#include "../jrd/y_ref.h"
#include "../jrd/ibase.h"
#include "../jrd/ods.h"
#include "../jrd/btr.h"
#include "gen/ids.h"
#include "../jrd/tra.h"
#include "../jrd/trig.h"
#include "../jrd/intl.h"
#include "../jrd/dflt.h"
#include "../jrd/constants.h"
#include "../jrd/ini.h"
#include "../jrd/idx.h"
#include "../jrd/gdsassert.h"
#include "../jrd/all_proto.h"
#include "../jrd/blb_proto.h"
#include "../jrd/cch_proto.h"
#include "../jrd/cmp_proto.h"
#include "../jrd/dfw_proto.h"
#include "../jrd/dpm_proto.h"
#include "../jrd/err_proto.h"
#include "../jrd/exe_proto.h"
#include "../jrd/gds_proto.h"
#include "../jrd/idx_proto.h"
#include "../jrd/ini_proto.h"
#include "../jrd/jrd_proto.h"
#include "../jrd/met_proto.h"
#include "../jrd/thd_proto.h"
#include "../jrd/obj.h"
#include "../jrd/acl.h"
#include "../jrd/irq.h"
DATABASE DB = FILENAME "ODS.RDB";
#define PAD(string, field) jrd_vtof ((char*)(string), field, sizeof (field))
#define MAX_ACL_SIZE 4096
#define DEFAULT_CLASS "SQL$DEFAULT"
#ifdef NOT_USED_OR_REPLACED
static void add_generator(TEXT*, BLK*);
#endif
static void add_global_fields(USHORT);
static void add_index_set(Database*, bool, USHORT, USHORT);
static void add_new_triggers(USHORT, USHORT);
static void add_relation_fields(USHORT);
static void add_security_to_sys_rel(thread_db*, const TEXT*, const TEXT*, const UCHAR*,
const SSHORT);
#ifdef NOT_USED_OR_REPLACED
static void add_trigger(TEXT*, BLK*, BLK*);
#endif
//static void add_user_priv(thread_db*, TEXT*, TEXT*, TEXT*, TEXT);
static void modify_relation_field(thread_db*, const UCHAR*, const UCHAR*, BLK*);
static void store_generator(thread_db*, const gen*, BLK*);
static void store_global_field(thread_db*, const gfld*, BLK*);
static void store_intlnames(thread_db*, Database*);
static void store_message(thread_db*, const trigger_msg*, BLK*);
static void store_relation_field(thread_db*, const UCHAR*, const UCHAR*, int, BLK*, bool);
static void store_trigger(thread_db*, const jrd_trg*, BLK*);
/* This is the table used in defining triggers; note that
RDB$TRIGGER_0 was first changed to RDB$TRIGGER_7 to make it easier to
upgrade a database to support field-level grant. It has since been
changed to RDB$TRIGGER_9 to handle SQL security on relations whose
name is > 27 characters */
static const jrd_trg triggers[] =
{
{ "RDB$TRIGGER_1", (UCHAR) nam_user_privileges,
RDB$TRIGGERS.RDB$TRIGGER_TYPE.PRE_MODIFY, sizeof(trigger3), trigger3,
0, ODS_8_0 },
{ "RDB$TRIGGER_8", (UCHAR) nam_user_privileges,
RDB$TRIGGERS.RDB$TRIGGER_TYPE.PRE_ERASE, sizeof(trigger2), trigger2,
0, ODS_8_0 },
{ "RDB$TRIGGER_9", (UCHAR) nam_user_privileges,
RDB$TRIGGERS.RDB$TRIGGER_TYPE.PRE_STORE, sizeof(trigger1), trigger1,
0, ODS_8_0 },
{ "RDB$TRIGGER_2", (UCHAR) nam_trgs,
RDB$TRIGGERS.RDB$TRIGGER_TYPE.PRE_MODIFY, sizeof(trigger4), trigger4,
0, ODS_8_0 },
{ "RDB$TRIGGER_3", (UCHAR) nam_trgs,
RDB$TRIGGERS.RDB$TRIGGER_TYPE.PRE_ERASE, sizeof(trigger4), trigger4,
0, ODS_8_0 },
{ "RDB$TRIGGER_4", (UCHAR) nam_relations,
RDB$TRIGGERS.RDB$TRIGGER_TYPE.PRE_STORE, sizeof(trigger5), trigger5,
0, ODS_8_0 },
{ "RDB$TRIGGER_5", (UCHAR) nam_relations,
RDB$TRIGGERS.RDB$TRIGGER_TYPE.PRE_MODIFY, sizeof(trigger6), trigger6,
0, ODS_8_0 },
{ "RDB$TRIGGER_6", (UCHAR) nam_gens,
RDB$TRIGGERS.RDB$TRIGGER_TYPE.PRE_STORE, sizeof(trigger7), trigger7,
0, ODS_8_0 },
{ "RDB$TRIGGER_26", (UCHAR) nam_rel_constr,
RDB$TRIGGERS.RDB$TRIGGER_TYPE.PRE_STORE, sizeof(trigger26), trigger26,
0, ODS_8_0 },
{ "RDB$TRIGGER_25", (UCHAR) nam_rel_constr,
RDB$TRIGGERS.RDB$TRIGGER_TYPE.PRE_MODIFY, sizeof(trigger25),
trigger25, 0, ODS_8_0 },
{ "RDB$TRIGGER_10", (UCHAR) nam_rel_constr,
RDB$TRIGGERS.RDB$TRIGGER_TYPE.PRE_ERASE, sizeof(trigger10), trigger10,
0, ODS_8_0 },
{ "RDB$TRIGGER_11", (UCHAR) nam_rel_constr,
RDB$TRIGGERS.RDB$TRIGGER_TYPE.POST_ERASE, sizeof(trigger11),
trigger11, 0, ODS_8_0 },
{ "RDB$TRIGGER_12", (UCHAR) nam_ref_constr,
RDB$TRIGGERS.RDB$TRIGGER_TYPE.PRE_STORE, sizeof(trigger12), trigger12,
0, ODS_8_0 },
{ "RDB$TRIGGER_13", (UCHAR) nam_ref_constr,
RDB$TRIGGERS.RDB$TRIGGER_TYPE.PRE_MODIFY, sizeof(trigger13),
trigger13, 0, ODS_8_0 },
{ "RDB$TRIGGER_14", (UCHAR) nam_chk_constr,
RDB$TRIGGERS.RDB$TRIGGER_TYPE.PRE_MODIFY, sizeof(trigger14),
trigger14, 0, ODS_8_0 },
{ "RDB$TRIGGER_15", (UCHAR) nam_chk_constr,
RDB$TRIGGERS.RDB$TRIGGER_TYPE.PRE_ERASE, sizeof(trigger15), trigger15,
0, ODS_8_0 },
{ "RDB$TRIGGER_16", (UCHAR) nam_chk_constr,
RDB$TRIGGERS.RDB$TRIGGER_TYPE.POST_ERASE, sizeof(trigger16),
trigger16, 0, ODS_8_0 },
{ "RDB$TRIGGER_17", (UCHAR) nam_i_segments,
RDB$TRIGGERS.RDB$TRIGGER_TYPE.PRE_ERASE, sizeof(trigger17), trigger17,
0, ODS_8_0 },
{ "RDB$TRIGGER_18", (UCHAR) nam_i_segments,
RDB$TRIGGERS.RDB$TRIGGER_TYPE.PRE_MODIFY, sizeof(trigger18),
trigger18, 0, ODS_8_0 },
{ "RDB$TRIGGER_19", (UCHAR) nam_indices,
RDB$TRIGGERS.RDB$TRIGGER_TYPE.PRE_ERASE, sizeof(trigger19), trigger19,
0, ODS_8_0 },
{ "RDB$TRIGGER_20", (UCHAR) nam_indices,
RDB$TRIGGERS.RDB$TRIGGER_TYPE.PRE_MODIFY, sizeof(trigger20),
trigger20, 0, ODS_8_0 },
{ "RDB$TRIGGER_21", (UCHAR) nam_trgs,
RDB$TRIGGERS.RDB$TRIGGER_TYPE.PRE_ERASE, sizeof(trigger21), trigger21,
0, ODS_8_0 },
{ "RDB$TRIGGER_22", (UCHAR) nam_trgs,
RDB$TRIGGERS.RDB$TRIGGER_TYPE.PRE_MODIFY, sizeof(trigger22),
trigger22, 0, ODS_8_0 },
{ "RDB$TRIGGER_23", (UCHAR) nam_r_fields,
RDB$TRIGGERS.RDB$TRIGGER_TYPE.PRE_ERASE, sizeof(trigger23), trigger23,
0, ODS_8_0 },
{ "RDB$TRIGGER_24", (UCHAR) nam_r_fields,
RDB$TRIGGERS.RDB$TRIGGER_TYPE.PRE_MODIFY, sizeof(trigger24),
trigger24, 0, ODS_8_0 },
{ "RDB$TRIGGER_27", (UCHAR) nam_r_fields,
RDB$TRIGGERS.RDB$TRIGGER_TYPE.POST_ERASE, sizeof(trigger27),
trigger27, 0, ODS_8_0 },
{ "RDB$TRIGGER_28", (UCHAR) nam_procedures,
RDB$TRIGGERS.RDB$TRIGGER_TYPE.PRE_STORE, sizeof(trigger28), trigger28,
0, ODS_8_0 },
{ "RDB$TRIGGER_29", (UCHAR) nam_procedures,
RDB$TRIGGERS.RDB$TRIGGER_TYPE.PRE_MODIFY, sizeof(trigger29),
trigger29, 0, ODS_8_0 },
{ "RDB$TRIGGER_30", (UCHAR) nam_exceptions,
RDB$TRIGGERS.RDB$TRIGGER_TYPE.PRE_STORE, sizeof(trigger30), trigger30,
0, ODS_8_0 },
{ "RDB$TRIGGER_31", (UCHAR) nam_user_privileges,
RDB$TRIGGERS.RDB$TRIGGER_TYPE.PRE_MODIFY, sizeof(trigger31),
trigger31, 0, ODS_8_1 },
{ "RDB$TRIGGER_32", (UCHAR) nam_user_privileges,
RDB$TRIGGERS.RDB$TRIGGER_TYPE.PRE_ERASE, sizeof(trigger31), trigger31,
0, ODS_8_1 },
{ "RDB$TRIGGER_33", (UCHAR) nam_user_privileges,
RDB$TRIGGERS.RDB$TRIGGER_TYPE.PRE_STORE, sizeof(trigger31), trigger31,
0, ODS_8_1 },
{ "RDB$TRIGGER_34", (UCHAR) nam_rel_constr,
RDB$TRIGGERS.RDB$TRIGGER_TYPE.POST_ERASE, sizeof(trigger34),
trigger34, TRG_ignore_perm, ODS_8_1 },
{ "RDB$TRIGGER_35", (UCHAR) nam_chk_constr,
RDB$TRIGGERS.RDB$TRIGGER_TYPE.POST_ERASE, sizeof(trigger35),
trigger35, TRG_ignore_perm, ODS_8_1 },
{ 0, 0, 0, 0, 0, 0 }
};
/* this table is used in defining messages for system triggers */
static const trigger_msg trigger_messages[] =
{
{ "RDB$TRIGGER_9", 0, "grant_obj_notfound", ODS_8_0 },
{ "RDB$TRIGGER_9", 1, "grant_fld_notfound", ODS_8_0 },
{ "RDB$TRIGGER_9", 2, "grant_nopriv", ODS_8_0 },
{ "RDB$TRIGGER_9", 3, "nonsql_security_rel", ODS_8_0 },
{ "RDB$TRIGGER_9", 4, "nonsql_security_fld", ODS_8_0 },
{ "RDB$TRIGGER_9", 5, "grant_nopriv_on_base", ODS_8_0 },
{ "RDB$TRIGGER_1", 0, "existing_priv_mod", ODS_8_0 },
{ "RDB$TRIGGER_2", 0, "systrig_update", ODS_8_0 },
{ "RDB$TRIGGER_3", 0, "systrig_update", ODS_8_0 },
{ "RDB$TRIGGER_5", 0, "not_rel_owner", ODS_8_0 },
{ "RDB$TRIGGER_24", 1, "cnstrnt_fld_rename", ODS_8_0 },
{ "RDB$TRIGGER_23", 1, "cnstrnt_fld_del", ODS_8_0 },
{ "RDB$TRIGGER_22", 1, "check_trig_update", ODS_8_0 },
{ "RDB$TRIGGER_21", 1, "check_trig_del", ODS_8_0 },
{ "RDB$TRIGGER_20", 1, "integ_index_mod", ODS_8_0 },
{ "RDB$TRIGGER_20", 2, "integ_index_deactivate", ODS_8_0 },
{ "RDB$TRIGGER_20", 3, "integ_deactivate_primary", ODS_8_0 },
{ "RDB$TRIGGER_19", 1, "integ_index_del", ODS_8_0 },
{ "RDB$TRIGGER_18", 1, "integ_index_seg_mod", ODS_8_0 },
{ "RDB$TRIGGER_17", 1, "integ_index_seg_del", ODS_8_0 },
{ "RDB$TRIGGER_15", 1, "check_cnstrnt_del", ODS_8_0 },
{ "RDB$TRIGGER_14", 1, "check_cnstrnt_update", ODS_8_0 },
{ "RDB$TRIGGER_13", 1, "ref_cnstrnt_update", ODS_8_0 },
{ "RDB$TRIGGER_12", 1, "ref_cnstrnt_notfound", ODS_8_0 },
{ "RDB$TRIGGER_12", 2, "foreign_key_notfound", ODS_8_0 },
{ "RDB$TRIGGER_10", 1, "primary_key_ref", ODS_8_0 },
{ "RDB$TRIGGER_10", 2, "primary_key_notnull", ODS_8_0 },
{ "RDB$TRIGGER_25", 1, "rel_cnstrnt_update", ODS_8_0 },
{ "RDB$TRIGGER_26", 1, "constaint_on_view", ODS_8_0 },
{ "RDB$TRIGGER_26", 2, "invld_cnstrnt_type", ODS_8_0 },
{ "RDB$TRIGGER_26", 3, "primary_key_exists", ODS_8_0 },
{ "RDB$TRIGGER_31", 0, "no_write_user_priv", ODS_8_1 },
{ "RDB$TRIGGER_32", 0, "no_write_user_priv", ODS_8_1 },
{ "RDB$TRIGGER_33", 0, "no_write_user_priv", ODS_8_1 },
{ 0, 0, 0, 0 }
};
void INI_format(const TEXT* owner, const TEXT* charset)
{
/**************************************
*
* I N I _ f o r m a t
*
**************************************
*
* Functional description
* Initialize system relations in the database.
* The full complement of metadata should be
* stored here.
*
**************************************/
thread_db* tdbb = GET_THREAD_DATA;
Database* dbb = tdbb->tdbb_database;
/* Uppercase owner name */
TEXT string[32];
*string = 0;
if (owner && *owner)
{
TEXT* p = string;
while ( (*p++ = UPPER7(*owner)) )
{
++owner;
}
}
/* Uppercase charset name */
TEXT string2[32];
*string2 = 0;
if (charset && *charset)
{
TEXT* p2 = string2;
while ( (*p2++ = UPPER7(*charset)) )
{
++charset;
}
}
int n;
/* Make sure relations exist already */
for (n = 0; n < (int) rel_MAX; n++) {
DPM_create_relation(tdbb, MET_relation(tdbb, (USHORT)n));
}
/* Store RELATIONS and RELATION_FIELDS */
blk* handle1 = NULL;
blk* handle2 = NULL;
const UCHAR* fld;
for (const UCHAR* relfld = relfields; relfld[RFLD_R_NAME]; relfld = fld + 1)
{
for (n = 0, fld = relfld + RFLD_RPT; fld[RFLD_F_NAME];
fld += RFLD_F_LENGTH)
{
if (!fld[RFLD_F_MINOR])
{
const UCHAR* pFld = fld;
const UCHAR* pRelFld = relfld;
store_relation_field(tdbb, pFld, pRelFld, n, &handle2, true);
n++;
}
}
STORE(REQUEST_HANDLE handle1) X IN RDB$RELATIONS
X.RDB$RELATION_ID = relfld[RFLD_R_ID];
PAD(names[relfld[RFLD_R_NAME]], X.RDB$RELATION_NAME);
X.RDB$FIELD_ID = n;
X.RDB$FORMAT = 0;
X.RDB$SYSTEM_FLAG = RDB_system;
X.RDB$DBKEY_LENGTH = 8;
X.RDB$OWNER_NAME.NULL = TRUE;
if (*string)
{
PAD(string, X.RDB$OWNER_NAME);
X.RDB$OWNER_NAME.NULL = FALSE;
}
END_STORE;
}
CMP_release(tdbb, (jrd_req*)handle1);
CMP_release(tdbb, (jrd_req*)handle2);
handle1 = handle2 = NULL;
/* Store global FIELDS */
for (const gfld* gfield = (gfld*) gfields; gfield->gfld_name; gfield++)
{
store_global_field(tdbb, gfield, &handle1);
}
CMP_release(tdbb, (jrd_req*)handle1);
handle1 = NULL;
STORE(REQUEST_HANDLE handle1) X IN RDB$DATABASE
X.RDB$RELATION_ID = (int) USER_DEF_REL_INIT_ID;
X.RDB$CHARACTER_SET_NAME.NULL = TRUE;
if (*string2) {
PAD ( string2, X.RDB$CHARACTER_SET_NAME);
X.RDB$CHARACTER_SET_NAME.NULL = FALSE;
}
else {
PAD (DEFAULT_DB_CHARACTER_SET_NAME, X.RDB$CHARACTER_SET_NAME);
X.RDB$CHARACTER_SET_NAME.NULL = FALSE;
}
END_STORE
CMP_release(tdbb, (jrd_req*)handle1);
handle1 = NULL;
/* Create indices for system relations */
add_index_set(dbb, false, 0, 0);
/* Create parameter types */
handle1 = NULL;
for (const rtyp* type = types; type->rtyp_name; ++type)
{
STORE(REQUEST_HANDLE handle1) X IN RDB$TYPES
PAD(names[type->rtyp_field], X.RDB$FIELD_NAME);
PAD(type->rtyp_name, X.RDB$TYPE_NAME);
X.RDB$TYPE = type->rtyp_value;
X.RDB$SYSTEM_FLAG = RDB_system;
END_STORE;
}
CMP_release(tdbb, (jrd_req*)handle1);
/* Store symbols for international character sets & collations */
store_intlnames(tdbb, dbb);
/* Create generators to be used by system triggers */
handle1 = NULL;
for (const gen* generator = generators; generator->gen_name; generator++)
{
store_generator(tdbb, generator, &handle1);
}
CMP_release(tdbb, (jrd_req*)handle1);
/* store system-defined triggers */
handle1 = NULL;
for (const jrd_trg* trigger = triggers; trigger->trg_relation; ++trigger)
{
store_trigger(tdbb, trigger, &handle1);
}
CMP_release(tdbb, (jrd_req*)handle1);
/* store trigger messages to go with triggers */
handle1 = NULL;
for (const trigger_msg* message = trigger_messages; message->trigmsg_name;
++message)
{
store_message(tdbb, message, &handle1);
}
CMP_release(tdbb, (jrd_req*)handle1);
DFW_perform_system_work();
add_relation_fields(0);
/*
====================================================================
==
== Add security on RDB$ROLES system table
==
======================================================================
*/
UCHAR buffer[MAX_ACL_SIZE];
UCHAR* acl = buffer;
*acl++ = ACL_version;
*acl++ = ACL_id_list;
*acl++ = id_person;
const TEXT* p_1 = string;
USHORT length = strlen(string);
*acl++ = (UCHAR)length;
if (length)
{
do {
*acl++ = *p_1++;
} while (--length);
}
*acl++ = ACL_end;
*acl++ = ACL_priv_list;
*acl++ = priv_protect;
*acl++ = priv_control;
*acl++ = priv_delete;
*acl++ = priv_write;
*acl++ = priv_read;
*acl++ = ACL_end;
*acl++ = ACL_id_list;
*acl++ = ACL_end;
*acl++ = ACL_priv_list;
*acl++ = priv_read;
*acl++ = ACL_end;
*acl++ = ACL_end;
length = acl - buffer;
add_security_to_sys_rel(tdbb, string, "RDB$ROLES", buffer, length);
}
USHORT INI_get_trig_flags(const TEXT* trig_name)
{
/*********************************************
*
* I N I _ g e t _ t r i g _ f l a g s
*
*********************************************
*
* Functional description
* Return the trigger flags for a system trigger.
*
**************************************/
for (const jrd_trg* trig = triggers; trig->trg_length > 0; trig++)
{
if (!strcmp(trig->trg_name, trig_name))
{
return (trig->trg_flags);
}
}
return (0);
}
void INI_init(void)
{
/**************************************
*
* I N I _ i n i t
*
**************************************
*
* Functional description
* Initialize in memory meta data. Assume that all meta data
* fields exist in the database even if this is not the case.
* Do not fill in the format length or the address in each
* format descriptor.
*
**************************************/
thread_db* tdbb = GET_THREAD_DATA;
Database* dbb = tdbb->tdbb_database;
CHECK_DBB(dbb);
const UCHAR* fld_;
for (const UCHAR* relfld = relfields; relfld[RFLD_R_NAME]; relfld = fld_ + 1)
{
jrd_rel* relation = MET_relation(tdbb, relfld[RFLD_R_ID]);
relation->rel_flags |= REL_system;
relation->rel_name = (/* const_cast */ TEXT*)names[relfld[RFLD_R_NAME]];
relation->rel_length = strlen(relation->rel_name);
int n = 0;
for (fld_ = relfld + RFLD_RPT; fld_[RFLD_F_NAME];
fld_ += RFLD_F_LENGTH)
{
n++;
}
/* Set a flag if their is a trigger on the relation. Later we may
need to compile it. */
for (const jrd_trg* trigger = triggers; trigger->trg_relation; trigger++)
{
if (relation->rel_name == names[trigger->trg_relation])
{
relation->rel_flags |= REL_sys_triggers;
break;
}
}
vec* fields = vec::newVector(*dbb->dbb_permanent, n);
relation->rel_fields = fields;
vec::iterator itr = fields->begin();
fmt* format = fmt::newFmt(*dbb->dbb_permanent, n);
relation->rel_current_format = format;
vec* formats = vec::newVector(*dbb->dbb_permanent, 1);
relation->rel_formats = formats;
(*formats)[0] = format;
format->fmt_count = n;
fmt::fmt_desc_iterator desc = format->fmt_desc.begin();
for (fld_ = relfld + RFLD_RPT; fld_[RFLD_F_NAME];
fld_ += RFLD_F_LENGTH, desc++, itr++)
{
const gfld* gfield = &gfields[fld_[RFLD_F_ID]];
desc->dsc_length = gfield->gfld_length;
desc->dsc_dtype = gfield->gfld_dtype;
jrd_fld* field = FB_NEW_RPT(*dbb->dbb_permanent, 0) jrd_fld();
*itr = field;
field->fld_name = names[fld_[RFLD_F_NAME]];
field->fld_length = strlen(field->fld_name);
}
}
}
void INI_init2(void)
{
/**************************************
*
* I N I _ i n i t 2
*
**************************************
*
* Functional description
* Re-initialize in memory meta data. Fill in
* format 0 based on the minor ODS version of
* the database when it was created.
*
**************************************/
thread_db* tdbb = GET_THREAD_DATA;
Database* dbb = tdbb->tdbb_database;
const USHORT major_version = dbb->dbb_ods_version;
const USHORT minor_original = dbb->dbb_minor_original;
vec* vector = dbb->dbb_relations;
const UCHAR* fld;
for (const UCHAR* relfld = relfields; relfld[RFLD_R_NAME]; relfld = fld + 1)
{
if (relfld[RFLD_R_MINOR] > ENCODE_ODS(major_version, minor_original))
{
/*****************************************************
**
** free the space allocated for RDB$ROLES
**
******************************************************/
const USHORT id = relfld[RFLD_R_ID];
jrd_rel* relation = (jrd_rel*)(*vector)[id];
delete relation->rel_current_format;
delete relation->rel_formats;
delete relation->rel_fields;
(*vector)[id] = NULL;
fld = relfld + RFLD_RPT;
while (fld[RFLD_F_NAME])
{
fld += RFLD_F_LENGTH;
}
}
else
{
jrd_rel* relation = MET_relation(tdbb, relfld[RFLD_R_ID]);
fmt* format = relation->rel_current_format;
int n = 0;
for (fld = relfld + RFLD_RPT; fld[RFLD_F_NAME];
fld += RFLD_F_LENGTH)
{
/* If the ODS is less than 10, then remove all fields named
* RDB$FIELD_PRECISION and field RDB$CHARACTER_LENGTH from
* relation RDB$FUNCTION_ARGUMENTS , as they were not present
* in < 10 ODS
*/
if (fld[RFLD_F_NAME] == nam_f_precision ||
(fld[RFLD_F_NAME] == nam_char_length &&
relfld[RFLD_R_NAME] == nam_args))
{
if (major_version >= ODS_VERSION10)
{
if (!fld[RFLD_F_MINOR])
{
n++;
if (fld[RFLD_F_UPD_MINOR])
relation->rel_flags |= REL_force_scan;
}
else
{
relation->rel_flags |= REL_force_scan;
}
}
}
else if (fld[RFLD_F_NAME] == nam_statistics &&
relfld[RFLD_R_NAME] == nam_i_segments)
{
if (major_version >= ODS_VERSION11)
{
if (!fld[RFLD_F_MINOR])
{
n++;
if (fld[RFLD_F_UPD_MINOR])
relation->rel_flags |= REL_force_scan;
}
else
{
relation->rel_flags |= REL_force_scan;
}
}
}
else
{
if (!fld[RFLD_F_MINOR])
{
n++;
if (fld[RFLD_F_UPD_MINOR])
relation->rel_flags |= REL_force_scan;
}
else
{
relation->rel_flags |= REL_force_scan;
}
}
}
relation->rel_fields->resize(n);
format->fmt_count = n;
format->fmt_length = (USHORT)FLAG_BYTES(n);
fmt::fmt_desc_iterator desc = format->fmt_desc.begin();
for (fld = relfld + RFLD_RPT; fld[RFLD_F_NAME];
fld += RFLD_F_LENGTH, desc++)
{
if (n-- > 0)
{
format->fmt_length = (USHORT)MET_align(&*desc, format->fmt_length);
desc->dsc_address = (UCHAR*) (IPTR) format->fmt_length;
format->fmt_length += desc->dsc_length;
}
}
}
}
}
const jrd_trg* INI_lookup_sys_trigger(jrd_rel* relation,
const jrd_trg* trigger,
const UCHAR** blr,
UCHAR* trigger_type,
const SCHAR** trigger_name,
USHORT* trig_flags)
{
/**************************************
*
* I N I _ l o o k u p _ s y s _ t r i g g e r
*
**************************************
*
* Functional description
* Lookup the next trigger for a system relation.
*
**************************************/
trigger = (trigger) ? trigger + 1 : triggers;
for (; trigger->trg_relation; trigger++)
{
if (!strcmp(relation->rel_name, names[trigger->trg_relation]))
{
*blr = trigger->trg_blr;
*trigger_type = trigger->trg_type;
*trigger_name = trigger->trg_name;
*trig_flags = trigger->trg_flags;
return trigger;
}
}
return NULL;
}
void INI_update_database()
{
/**************************************
*
* I N I _ u p d a t e _ d a t a b a s e
*
**************************************
*
* Functional description
* Perform changes to ODS that were required
* since ODS 8 and are dynamically updatable.
*
* %% Note %% Update the switch() statement to reflect new major ODS
* addition
**************************************/
thread_db* tdbb = GET_THREAD_DATA;
Database* dbb = tdbb->tdbb_database;
CHECK_DBB(dbb);
/* If database is ReadOnly, return without upgrading ODS */
if (dbb->dbb_flags & DBB_read_only)
return;
/* check out the update version to see if we have work to do */
const USHORT major_version = dbb->dbb_ods_version;
const USHORT minor_version = dbb->dbb_minor_version;
/*******************************************************************
** when old engine is attaching a newer ODS database, do nothing
********************************************************************/
/* if database ODS is less than the server's, then upgrade */
if (ENCODE_ODS(major_version, minor_version) >= ODS_CURRENT_VERSION)
{
return;
}
/*******************************************************************
** when new engine is attaching an older ODS database
** perform the necessary modifications
********************************************************************/
if (major_version == ODS_VERSION8)
{
/*** NOTE: The following two functions/structures need to understand
the difference between major ODS versions. The structure
which holds their information needs to have an additional field
to define which major ODS version they belong to.
PENDING WORK.
add_global_fields (major_version, minor_version);
add_relation_fields (major_version, minor_version);
Look at add_new_triggers() for reference.
***/
add_global_fields(minor_version);
add_relation_fields(minor_version);
}
add_index_set(dbb, true, major_version, minor_version);
add_new_triggers(major_version, minor_version);
/* if the database was updated; mark it with the current ODS minor
version so other process will attempt to do so. We mark this after
doing the update so that no other process can see the new minor
version but not the update. */
WIN window(HEADER_PAGE);
header_page* header =
(header_page*) CCH_FETCH(tdbb, &window, LCK_write, pag_header);
CCH_MARK(tdbb, &window);
/* Only minor upgrades can occur within a major ODS, define which one
occured here. */
switch (major_version)
{
case ODS_VERSION8:
header->hdr_ods_minor = ODS_CURRENT8;
break;
case ODS_VERSION9:
header->hdr_ods_minor = ODS_CURRENT9;
break;
case ODS_VERSION10:
header->hdr_ods_minor = ODS_CURRENT10;
break;
default:
/* Make sure we add a new case per new major ODS. Look at code above */
fb_assert(FALSE);
header->hdr_ods_minor = minor_version;
break;
}
dbb->dbb_minor_version = header->hdr_ods_minor;
CCH_RELEASE(tdbb, &window);
DFW_perform_system_work();
}
#ifdef NOT_USED_OR_REPLACED
static void add_generator(TEXT* generator_name, BLK* handle)
{
/**************************************
*
* a d d _ g e n e r a t o r
*
**************************************
*
* Functional description
* Store a generator of the given name.
* This routine is used to upgrade ODS versions.
* DO NOT DELETE, even though it is not used
* now, since it may be used when we go to 8.1.
*
**************************************/
const gen* generator = generators;
thread_db* tdbb = GET_THREAD_DATA;
/* find the new generator to be stored; assume it exists in the table */
/* TMN: If it doesn't exist in the table, we will CRASH here! */
while (strcmp(generator->gen_name, generator_name))
{
++generator;
}
store_generator(tdbb, generator, handle);
}
#endif
static void add_global_fields( USHORT minor_version)
{
/**************************************
*
* a d d _ g l o b a l _ f i e l d s
*
**************************************
*
* Functional description
* Add any global fields which have a non-zero
* update number in the fields table. That
* is, those that have been added since the last
* ODS change.
*
**************************************/
thread_db* tdbb = GET_THREAD_DATA;
/* add desired global fields to system relations */
blk* handle = NULL;
for (const gfld* gfield = (gfld*) gfields; gfield->gfld_name; gfield++)
{
if (minor_version < gfield->gfld_minor)
{
store_global_field(tdbb, gfield, &handle);
}
}
if (handle) {
CMP_release(tdbb, (jrd_req*)handle);
}
DFW_perform_system_work();
}
static void add_index_set(Database* dbb,
bool update_ods,
USHORT major_version,
USHORT minor_version)
{
/**************************************
*
* a d d _ i n d e x _ s e t
*
**************************************
*
* Functional description
* Add system indices. If update_ods is true we are performing
* an ODS update, and only add the indices marked as newer than
* ODS (major_version,minor_version).
*
**************************************/
TEXT string[32];
IDX idx;
thread_db* tdbb = GET_THREAD_DATA;
blk* handle1 = NULL;
blk* handle2 = NULL;
for (int n = 0; n < SYSTEM_INDEX_COUNT; n++)
{
const ini_idx_t* index = &indices[n];
/* For minor ODS updates, only add indices newer than on-disk ODS */
if (update_ods &&
((index->ini_idx_version_flag <=
ENCODE_ODS(major_version, minor_version)) ||
(index->ini_idx_version_flag > ODS_CURRENT_VERSION) ||
(((USHORT) DECODE_ODS_MAJOR(index->ini_idx_version_flag)) !=
major_version)))
{
/* The DECODE_ODS_MAJOR() is used (in this case) to instruct the server
to perform updates for minor ODS versions only within a major ODS */
continue;
}
STORE(REQUEST_HANDLE handle1) X IN RDB$INDICES
jrd_rel* relation = MET_relation(tdbb, index->ini_idx_relid);
PAD(relation->rel_name, X.RDB$RELATION_NAME);
sprintf(string, "RDB$INDEX_%d", index->ini_idx_index_id);
PAD(string, X.RDB$INDEX_NAME);
X.RDB$UNIQUE_FLAG = index->ini_idx_flags & idx_unique;
X.RDB$SEGMENT_COUNT = index->ini_idx_segment_count;
if (index->ini_idx_flags & idx_descending) {
X.RDB$INDEX_TYPE.NULL = FALSE;
X.RDB$INDEX_TYPE = 1;
}
else {
X.RDB$INDEX_TYPE.NULL = TRUE;
}
X.RDB$SYSTEM_FLAG = 1;
X.RDB$INDEX_INACTIVE = 0;
/* Store each segment for the index */
idx::idx_repeat* tail = idx.idx_rpt;
for (USHORT position = 0;
position < index->ini_idx_segment_count; position++, tail++)
{
const ini_idx_t::ini_idx_segment_t* segment =
&index->ini_idx_segment[position];
STORE(REQUEST_HANDLE handle2) Y IN RDB$INDEX_SEGMENTS
jrd_fld* field =
(jrd_fld*) (*relation->rel_fields)[segment->ini_idx_rfld_id];
Y.RDB$FIELD_POSITION = position;
PAD(X.RDB$INDEX_NAME, Y.RDB$INDEX_NAME);
PAD(field->fld_name, Y.RDB$FIELD_NAME);
tail->idx_field = segment->ini_idx_rfld_id;
tail->idx_itype = segment->ini_idx_type;
END_STORE;
}
idx.idx_count = index->ini_idx_segment_count;
idx.idx_flags = index->ini_idx_flags;
SelectivityList selectivity(*tdbb->tdbb_default);
IDX_create_index(tdbb, relation, &idx, string, NULL, NULL,
selectivity);
X.RDB$INDEX_ID = idx.idx_id + 1;
END_STORE;
}
if (handle1) {
CMP_release(tdbb, (jrd_req*)handle1);
}
if (handle2) {
CMP_release(tdbb, (jrd_req*)handle2);
}
}
static void add_new_triggers(USHORT major_version, USHORT minor_version)
{
/**************************************
*
* a d d _ n e w _ t r i g g e r s
*
**************************************
*
* Functional description
* Store all new ODS 8.x (x > 0) triggers.
* The major and minor_version passed in are the ODS versions
* before the ODS is upgraded.
* This routine is used to upgrade ODS versions.
*
**************************************/
thread_db* tdbb = GET_THREAD_DATA;
BLK handle1 = NULL;
/* add all new triggers, that were added since the database was created */
for (const jrd_trg* trig = triggers; trig->trg_length > 0; trig++)
{
if ((trig->trg_ods_version > ENCODE_ODS(major_version, minor_version))
&& (DECODE_ODS_MAJOR(trig->trg_ods_version) == major_version))
{
store_trigger(tdbb, trig, &handle1);
}
}
BLK handle2 = NULL;
for (const trigger_msg* message = trigger_messages; message->trigmsg_name; message++)
{
if ((message->trg_ods_version >
ENCODE_ODS(major_version, minor_version)) &&
(DECODE_ODS_MAJOR(message->trg_ods_version) == major_version))
{
store_message(tdbb, message, &handle2);
}
}
if (handle1) {
CMP_release(tdbb, (jrd_req*)handle1);
}
if (handle2) {
CMP_release(tdbb, (jrd_req*)handle2);
}
}
static void add_relation_fields( USHORT minor_version)
{
/**************************************
*
* a d d _ r e l a t i o n _ f i e l d s
*
**************************************
*
* Functional description
* Add any local fields which have a non-zero
* update number in the relfields table. That
* is, those that have been added since the last
* ODS change.
*
**************************************/
thread_db* tdbb = GET_THREAD_DATA;
Database* dbb = tdbb->tdbb_database;
/* add desired fields to system relations, forcing a new format version */
blk* s_handle = NULL;
blk* m_handle = NULL;
const UCHAR* fld;
for (const UCHAR* relfld = relfields; relfld[RFLD_R_NAME]; relfld = fld + 1)
{
int n = 0;
for (fld = relfld + RFLD_RPT; fld[RFLD_F_NAME];
n++, fld += RFLD_F_LENGTH)
{
if (minor_version < fld[RFLD_F_MINOR] ||
minor_version < fld[RFLD_F_UPD_MINOR])
{
if (minor_version < fld[RFLD_F_MINOR])
{
store_relation_field(tdbb, fld, relfld, n, &s_handle,
false);
}
else
{
modify_relation_field(tdbb, fld, relfld, &m_handle);
}
dsc desc;
desc.dsc_dtype = dtype_text;
INTL_ASSIGN_DSC(&desc, CS_METADATA, COLLATE_NONE);
desc.dsc_address = (UCHAR*) names[relfld[RFLD_R_NAME]];
desc.dsc_length = strlen((char*)desc.dsc_address);
DFW_post_work(dbb->dbb_sys_trans, dfw_update_format, &desc, 0);
}
}
}
if (s_handle) {
CMP_release(tdbb, (jrd_req*)s_handle);
}
if (m_handle) {
CMP_release(tdbb, (jrd_req*)m_handle);
}
DFW_perform_system_work();
}
// The caller used an UCHAR* to store the acl, it was converted to TEXT* to
// be passed to this function, only to be converted to UCHAR* to be passed
// to BLB_put_segment. Therefore, "acl" was changed to UCHAR* as param.
static void add_security_to_sys_rel(thread_db* tdbb,
const TEXT* user_name,
const TEXT* rel_name,
const UCHAR* acl,
const SSHORT acl_length)
{
/**************************************
*
* a d d _ s e c u r i t y _ t o _ s y s _ r e l
*
**************************************
*
* Functional description
*
* Add security to system relations. Only the owner of the
* database has SELECT/INSERT/UPDATE/DELETE privileges on
* any system relations. Any other users only has SELECT
* privilege.
*
**************************************/
TEXT sec_class_name[100];
TEXT default_class[32];
SET_TDBB(tdbb);
Database* dbb = tdbb->tdbb_database;
strcpy(sec_class_name, "SQL$");
strcat(sec_class_name, rel_name);
bid blob_id_1;
blb* blob = BLB_create(tdbb, dbb->dbb_sys_trans, &blob_id_1);
BLB_put_segment(tdbb, blob, acl, acl_length);
BLB_close(tdbb, blob);
bid blob_id_2;
blob = BLB_create(tdbb, dbb->dbb_sys_trans, &blob_id_2);
BLB_put_segment(tdbb, blob, acl, acl_length);
BLB_close(tdbb, blob);
sprintf(default_class, "%s%" QUADFORMAT "d", DEFAULT_CLASS,
DPM_gen_id(tdbb, MET_lookup_generator(tdbb, DEFAULT_CLASS),
0, (SINT64) 1));
BLK handle1;
for (int cnt = 0; cnt < 6; cnt++)
{
handle1 = NULL;
STORE(REQUEST_HANDLE handle1) PRIV IN RDB$USER_PRIVILEGES
switch (cnt)
{
case 0:
strcpy(PRIV.RDB$USER, user_name);
PRIV.RDB$PRIVILEGE[0] = 'S';
PRIV.RDB$GRANT_OPTION = 1;
break;
case 1:
strcpy(PRIV.RDB$USER, user_name);
PRIV.RDB$PRIVILEGE[0] = 'I';
PRIV.RDB$GRANT_OPTION = 1;
break;
case 2:
strcpy(PRIV.RDB$USER, user_name);
PRIV.RDB$PRIVILEGE[0] = 'U';
PRIV.RDB$GRANT_OPTION = 1;
break;
case 3:
strcpy(PRIV.RDB$USER, user_name);
PRIV.RDB$PRIVILEGE[0] = 'D';
PRIV.RDB$GRANT_OPTION = 1;
break;
case 4:
strcpy(PRIV.RDB$USER, user_name);
PRIV.RDB$PRIVILEGE[0] = 'R';
PRIV.RDB$GRANT_OPTION = 1;
break;
default:
strcpy(PRIV.RDB$USER, "PUBLIC");
PRIV.RDB$PRIVILEGE[0] = 'S';
PRIV.RDB$GRANT_OPTION = 0;
break;
}
strcpy(PRIV.RDB$GRANTOR, user_name);
PRIV.RDB$PRIVILEGE[1] = 0;
strcpy(PRIV.RDB$RELATION_NAME, rel_name);
PRIV.RDB$FIELD_NAME.NULL = TRUE;
PRIV.RDB$USER_TYPE = obj_user;
PRIV.RDB$OBJECT_TYPE = obj_relation;
END_STORE;
CMP_release(tdbb, (jrd_req*)handle1);
}
handle1 = NULL;
STORE(REQUEST_HANDLE handle1)
CLS IN RDB$SECURITY_CLASSES
jrd_vtof((char*)sec_class_name, CLS.RDB$SECURITY_CLASS,
sizeof(CLS.RDB$SECURITY_CLASS));
CLS.RDB$ACL = blob_id_1;
END_STORE;
CMP_release(tdbb, (jrd_req*)handle1);
handle1 = NULL;
STORE(REQUEST_HANDLE handle1)
CLS IN RDB$SECURITY_CLASSES
jrd_vtof((char*)default_class, CLS.RDB$SECURITY_CLASS,
sizeof(CLS.RDB$SECURITY_CLASS));
CLS.RDB$ACL = blob_id_2;
END_STORE;
CMP_release(tdbb, (jrd_req*)handle1);
handle1 = NULL;
FOR(REQUEST_HANDLE handle1) REL IN RDB$RELATIONS
WITH REL.RDB$RELATION_NAME EQ rel_name
MODIFY REL USING
REL.RDB$DEFAULT_CLASS.NULL = FALSE;
jrd_vtof((char*)default_class, REL.RDB$DEFAULT_CLASS,
sizeof(REL.RDB$DEFAULT_CLASS));
END_MODIFY;
END_FOR;
CMP_release(tdbb, (jrd_req*)handle1);
}
#ifdef NOT_USED_OR_REPLACED
static void add_trigger(TEXT* trigger_name, BLK* handle1, BLK* handle2)
{
/**************************************
*
* a d d _ t r i g g e r
*
**************************************
*
* Functional description
* Store a trigger of the given name.
* This routine is used to upgrade ODS versions.
* DO NOT DELETE, even though it is not used
* now, since it will be used when we go to 8.1.
*
**************************************/
thread_db* tdbb = GET_THREAD_DATA;
/* Find the new trigger to be stored; assume it exists in the table */
const jrd_trg* trigger = triggers;
while (strcmp(trigger->trg_name, trigger_name))
{
++trigger;
}
store_trigger(tdbb, trigger, handle1);
/* Look for any related trigger messages */
for (const trigger_msg* message = trigger_messages; message->trigmsg_name;
++message)
{
if (!strcmp(message->trigmsg_name, trigger->trg_name))
{
store_message(tdbb, message, handle2);
}
}
}
#endif
static void modify_relation_field(thread_db* tdbb,
const UCHAR* fld,
const UCHAR* relfld,
BLK* handle)
{
/**************************************
*
* m o d i f y _ r e l a t i o n _ f i e l d
*
**************************************
*
* Functional description
* Modify a local field according to the
* passed information. Note that the field id and
* field position do not change.
*
**************************************/
SET_TDBB(tdbb);
Database* dbb = tdbb->tdbb_database;
FOR(REQUEST_HANDLE * handle) X IN RDB$RELATION_FIELDS WITH
X.RDB$RELATION_NAME EQ names[relfld[RFLD_R_NAME]] AND
X.RDB$FIELD_NAME EQ names[fld[RFLD_F_NAME]]
MODIFY X USING
const gfld* gfield = &gfields[fld[RFLD_F_UPD_ID]];
PAD(names[gfield->gfld_name], X.RDB$FIELD_SOURCE);
X.RDB$UPDATE_FLAG = fld[RFLD_F_UPDATE];
END_MODIFY;
END_FOR;
}
static void store_generator(thread_db* tdbb, const gen* generator, BLK* handle)
{
/**************************************
*
* s t o r e _ g e n e r a t o r
*
**************************************
*
* Functional description
* Store the passed generator according to
* the information in the generator block.
*
**************************************/
SET_TDBB(tdbb);
Database* dbb = tdbb->tdbb_database;
STORE(REQUEST_HANDLE * handle) X IN RDB$GENERATORS
PAD(generator->gen_name, X.RDB$GENERATOR_NAME);
X.RDB$GENERATOR_ID = generator->gen_id;
X.RDB$SYSTEM_FLAG = RDB_system;
END_STORE;
}
static void store_global_field(thread_db* tdbb, const gfld* gfield, BLK* handle)
{
/**************************************
*
* s t o r e _ g l o b a l _ f i e l d
*
**************************************
*
* Functional description
* Store a global field according to the
* passed information.
*
**************************************/
SET_TDBB(tdbb);
Database* dbb = tdbb->tdbb_database;
jrd_tra* trans = dbb->dbb_sys_trans;
STORE(REQUEST_HANDLE * handle) X IN RDB$FIELDS
PAD(names[(USHORT)gfield->gfld_name], X.RDB$FIELD_NAME);
X.RDB$FIELD_LENGTH = gfield->gfld_length;
X.RDB$FIELD_SCALE = 0;
X.RDB$SYSTEM_FLAG = RDB_system;
X.RDB$FIELD_SUB_TYPE.NULL = TRUE;
X.RDB$CHARACTER_SET_ID.NULL = TRUE;
X.RDB$COLLATION_ID.NULL = TRUE;
X.RDB$SEGMENT_LENGTH.NULL = TRUE;
if (gfield->gfld_dflt_blr)
{
blb* blob = BLB_create(tdbb, trans, &X.RDB$DEFAULT_VALUE);
BLB_put_segment(tdbb,
blob,
gfield->gfld_dflt_blr,
gfield->gfld_dflt_len);
BLB_close(tdbb, blob);
X.RDB$DEFAULT_VALUE.NULL = FALSE;
}
else
{
X.RDB$DEFAULT_VALUE.NULL = TRUE;
}
switch (gfield->gfld_dtype)
{
case dtype_timestamp:
X.RDB$FIELD_TYPE = (int) blr_timestamp;
break;
case dtype_sql_time:
X.RDB$FIELD_TYPE = (int) blr_sql_time;
break;
case dtype_sql_date:
X.RDB$FIELD_TYPE = (int) blr_sql_date;
break;
case dtype_short:
case dtype_long:
case dtype_int64:
if (gfield->gfld_dtype == dtype_short)
X.RDB$FIELD_TYPE = (int) blr_short;
else if (gfield->gfld_dtype == dtype_long)
X.RDB$FIELD_TYPE = (int) blr_long;
else
X.RDB$FIELD_TYPE = (int) blr_int64;
if ((gfield->gfld_sub_type == dsc_num_type_numeric) ||
(gfield->gfld_sub_type == dsc_num_type_decimal))
{
X.RDB$FIELD_SUB_TYPE.NULL = FALSE;
X.RDB$FIELD_SUB_TYPE = gfield->gfld_sub_type;
}
break;
case dtype_double:
X.RDB$FIELD_TYPE = (int) blr_double;
break;
case dtype_text:
case dtype_varying:
if (gfield->gfld_dtype == dtype_text)
{
X.RDB$FIELD_TYPE = (int) blr_text;
}
else
{
X.RDB$FIELD_TYPE = (int) blr_varying;
X.RDB$FIELD_LENGTH -= sizeof(USHORT);
}
if (gfield->gfld_sub_type == dsc_text_type_metadata)
{
X.RDB$CHARACTER_SET_ID.NULL = FALSE;
X.RDB$CHARACTER_SET_ID = CS_METADATA;
X.RDB$COLLATION_ID.NULL = FALSE;
X.RDB$COLLATION_ID = COLLATE_NONE;
X.RDB$FIELD_SUB_TYPE.NULL = FALSE;
X.RDB$FIELD_SUB_TYPE = gfield->gfld_sub_type;
}
else if (gfield->gfld_sub_type == dsc_text_type_fixed)
{
X.RDB$CHARACTER_SET_ID.NULL = FALSE;
X.RDB$CHARACTER_SET_ID = CS_BINARY;
X.RDB$COLLATION_ID.NULL = FALSE;
X.RDB$COLLATION_ID = COLLATE_NONE;
X.RDB$FIELD_SUB_TYPE.NULL = FALSE;
X.RDB$FIELD_SUB_TYPE = gfield->gfld_sub_type;
}
else
{
X.RDB$CHARACTER_SET_ID.NULL = FALSE;
X.RDB$CHARACTER_SET_ID = CS_NONE;
X.RDB$COLLATION_ID.NULL = FALSE;
X.RDB$COLLATION_ID = COLLATE_NONE;
}
break;
case dtype_blob:
X.RDB$FIELD_TYPE = (int) blr_blob;
X.RDB$FIELD_SUB_TYPE.NULL = FALSE;
X.RDB$SEGMENT_LENGTH.NULL = FALSE;
X.RDB$FIELD_SUB_TYPE = gfield->gfld_sub_type;
X.RDB$SEGMENT_LENGTH = 80;
if (gfield->gfld_sub_type == BLOB_text)
{
X.RDB$CHARACTER_SET_ID.NULL = FALSE;
X.RDB$CHARACTER_SET_ID = CS_METADATA;
}
break;
default:
fb_assert(FALSE);
break;
}
END_STORE;
}
static void store_intlnames(thread_db* tdbb, Database* dbb)
{
/**************************************
*
* s t o r e _ i n t l n a m e s
*
**************************************
*
* Functional description
* Store symbolic names & information for international
* character sets & collations.
*
**************************************/
SET_TDBB(tdbb);
BLK handle = NULL;
for (const CS_TYPE* csptr = cs_types; csptr->init_charset_name; csptr++)
{
STORE(REQUEST_HANDLE handle) X IN RDB$CHARACTER_SETS USING
PAD(csptr->init_charset_name, X.RDB$CHARACTER_SET_NAME);
PAD(csptr->init_charset_name, X.RDB$DEFAULT_COLLATE_NAME);
X.RDB$CHARACTER_SET_ID = csptr->init_charset_id;
X.RDB$BYTES_PER_CHARACTER = csptr->init_charset_bytes_per_char;
X.RDB$SYSTEM_FLAG = RDB_system;
END_STORE;
}
CMP_release(tdbb, (jrd_req*)handle);
handle = NULL;
for (const COLL_TYPE* collptr = coll_types; collptr->init_collation_name; collptr++)
{
STORE(REQUEST_HANDLE handle) X IN RDB$COLLATIONS USING
PAD(collptr->init_collation_name, X.RDB$COLLATION_NAME);
X.RDB$CHARACTER_SET_ID = collptr->init_collation_charset;
X.RDB$COLLATION_ID = collptr->init_collation_id;
X.RDB$SYSTEM_FLAG = RDB_system;
END_STORE;
}
CMP_release(tdbb, (jrd_req*)handle);
handle = NULL;
}
static void store_message(thread_db* tdbb, const trigger_msg* message, BLK* handle)
{
/**************************************
*
* s t o r e _ m e s s a g e
*
**************************************
*
* Functional description
* Store system trigger messages.
*
**************************************/
SET_TDBB(tdbb);
Database* dbb = tdbb->tdbb_database;
/* store the trigger */
STORE(REQUEST_HANDLE * handle) X IN RDB$TRIGGER_MESSAGES
PAD(message->trigmsg_name, X.RDB$TRIGGER_NAME);
X.RDB$MESSAGE_NUMBER = message->trigmsg_number;
PAD(message->trigmsg_text, X.RDB$MESSAGE);
END_STORE;
}
static void store_relation_field(thread_db* tdbb,
const UCHAR* fld,
const UCHAR* relfld,
int field_id,
BLK* handle,
bool fmt0_flag)
{
/**************************************
*
* s t o r e _ r e l a t i o n _ f i e l d
*
**************************************
*
* Functional description
* Store a local field according to the
* passed information.
*
**************************************/
SET_TDBB(tdbb);
Database* dbb = tdbb->tdbb_database;
STORE(REQUEST_HANDLE * handle) X IN RDB$RELATION_FIELDS
const gfld* gfield = (fld[RFLD_F_UPD_MINOR] && !fmt0_flag) ?
&gfields[fld[RFLD_F_UPD_ID]] : &gfields[fld[RFLD_F_ID]];
PAD(names[relfld[RFLD_R_NAME]], X.RDB$RELATION_NAME);
PAD(names[fld[RFLD_F_NAME]], X.RDB$FIELD_NAME);
PAD(names[gfield->gfld_name], X.RDB$FIELD_SOURCE);
X.RDB$FIELD_POSITION = field_id;
X.RDB$FIELD_ID = field_id;
X.RDB$SYSTEM_FLAG = RDB_system;
X.RDB$UPDATE_FLAG = fld[RFLD_F_UPDATE];
END_STORE;
}
static void store_trigger(thread_db* tdbb, const jrd_trg* trigger, BLK* handle)
{
/**************************************
*
* s t o r e _ t r i g g e r
*
**************************************
*
* Functional description
* Store the trigger according to the
* information in the trigger block.
*
**************************************/
SET_TDBB(tdbb);
Database* dbb = tdbb->tdbb_database;
jrd_tra* trans = dbb->dbb_sys_trans;
/* indicate that the relation format needs revising */
dsc desc;
desc.dsc_dtype = dtype_text;
INTL_ASSIGN_DSC(&desc, CS_METADATA, COLLATE_NONE);
desc.dsc_address = (UCHAR*) names[trigger->trg_relation];
desc.dsc_length = strlen((char*)desc.dsc_address);
DFW_post_work(trans, dfw_update_format, &desc, 0);
/* store the trigger */
STORE(REQUEST_HANDLE * handle) X IN RDB$TRIGGERS
PAD(trigger->trg_name, X.RDB$TRIGGER_NAME);
PAD(names[trigger->trg_relation], X.RDB$RELATION_NAME);
X.RDB$TRIGGER_SEQUENCE = 0;
X.RDB$SYSTEM_FLAG = RDB_system;
X.RDB$TRIGGER_TYPE = trigger->trg_type;
X.RDB$FLAGS = trigger->trg_flags;
blb* blob = BLB_create(tdbb, trans, &X.RDB$TRIGGER_BLR);
BLB_put_segment(tdbb,
blob,
trigger->trg_blr,
trigger->trg_length);
BLB_close(tdbb, blob);
END_STORE;
}