8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-27 20:03:03 +01:00
firebird-mirror/src/jrd/ini.epp

1726 lines
50 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/common.h"
#include "../jrd/flags.h"
#include "../jrd/jrd.h"
#include "../jrd/val.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/ini.h"
#include "../jrd/idx.h"
#include "../jrd/gdsassert.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.h"
#include "../jrd/obj.h"
#include "../jrd/acl.h"
#include "../jrd/irq.h"
using namespace Jrd;
DATABASE DB = FILENAME "ODS.RDB";
#define PAD(string, field) jrd_vtof ((char*)(string), field, sizeof (field))
const int MAX_ACL_SIZE = 4096;
const char* DEFAULT_CLASS = "SQL$DEFAULT";
#ifdef NOT_USED_OR_REPLACED
static void add_generator(TEXT*, jrd_req**);
#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 Firebird::MetaName&,
const TEXT*, const UCHAR*, const SSHORT);
#ifdef NOT_USED_OR_REPLACED
static void add_trigger(TEXT*, jrd_req**, jrd_req**);
#endif
//static void add_user_priv(thread_db*, TEXT*, TEXT*, TEXT*, TEXT);
static int init2_helper(const int* fld, int n, jrd_rel* relation);
static void modify_relation_field(thread_db*, const int*, const int*, jrd_req**);
static void store_generator(thread_db*, const gen*, jrd_req**);
static void store_global_field(thread_db*, const gfld*, jrd_req**);
static void store_intlnames(thread_db*, Database*);
static void store_functions(thread_db*, Database*);
static void store_message(thread_db*, const trigger_msg*, jrd_req**);
static void store_relation_field(thread_db*, const int*, const int*, int, jrd_req**, bool);
static void store_trigger(thread_db*, const jrd_trg*, jrd_req**);
/* 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 },
{ "RDB$TRIGGER_36", (UCHAR) nam_fields,
RDB$TRIGGERS.RDB$TRIGGER_TYPE.PRE_MODIFY, sizeof(trigger36),
trigger36, 0, ODS_11_0 },
{ 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 },
{ "RDB$TRIGGER_24", 2, "integ_index_seg_mod", ODS_11_0 },
{ "RDB$TRIGGER_36", 1, "integ_index_seg_mod", ODS_11_0 },
{ 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 = JRD_get_thread_data();
Database* dbb = tdbb->tdbb_database;
/* Uppercase owner name */
Firebird::MetaName string(owner ? owner : "");
string.upper7();
/* Uppercase charset name */
Firebird::MetaName string2(charset ? charset : "");
string2.upper7();
int n;
const int* fld;
/* Make sure relations exist already */
{ // scope for MSVC6
for (const int* relfld = relfields; relfld[RFLD_R_NAME]; relfld = fld + 1)
{
if (relfld[RFLD_R_TYPE] == rel_persistent)
{
DPM_create_relation(tdbb, MET_relation(tdbb, relfld[RFLD_R_ID]));
}
for (fld = relfld + RFLD_RPT; fld[RFLD_F_NAME]; fld += RFLD_F_LENGTH)
;
}
} // scope for MSVC6
/* Store RELATIONS and RELATION_FIELDS */
jrd_req* handle1 = NULL;
jrd_req* handle2 = NULL;
for (const int* 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 int* pFld = fld;
const int* 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;
X.RDB$RELATION_TYPE = relfld[RFLD_R_TYPE];
if (string.length())
{
PAD(string.c_str(), X.RDB$OWNER_NAME);
X.RDB$OWNER_NAME.NULL = FALSE;
}
END_STORE;
}
CMP_release(tdbb, handle1);
CMP_release(tdbb, 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, 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.length()) {
PAD (string2.c_str(), 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, 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, 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, handle1);
// Adjust the value of the hidden generator RDB$GENERATORS
DPM_gen_id(tdbb, 0, true, FB_NELEM(generators) - 1);
/* store system-defined triggers */
handle1 = NULL;
for (const jrd_trg* trigger = triggers; trigger->trg_relation; ++trigger)
{
store_trigger(tdbb, trigger, &handle1);
}
CMP_release(tdbb, 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, handle1);
// Store IUDFs declared automatically as system functions.
// CVC: Demonstration code to register IUDF automatically moved to functions.h
store_functions(tdbb, dbb);
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;
USHORT length = string.length();
if (length > MAX_UCHAR)
length = MAX_UCHAR;
*acl++ = (UCHAR)length;
if (length)
{
const TEXT* p_1 = string.c_str();
memcpy(acl, p_1, length);
acl += 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);
add_security_to_sys_rel(tdbb, string, "RDB$PAGES", buffer, length);
// DFW writes here
add_security_to_sys_rel(tdbb, string, "RDB$FORMATS", 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 = JRD_get_thread_data();
Database* dbb = tdbb->tdbb_database;
CHECK_DBB(dbb);
const int* fld;
for (const int* 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 = names[relfld[RFLD_R_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<jrd_fld*>* fields = vec<jrd_fld*>::newVector(*dbb->dbb_permanent, n);
relation->rel_fields = fields;
vec<jrd_fld*>::iterator itr = fields->begin();
Format* format = Format::newFormat(*dbb->dbb_permanent, n);
relation->rel_current_format = format;
vec<Format*>* formats = vec<Format*>::newVector(*dbb->dbb_permanent, 1);
relation->rel_formats = formats;
(*formats)[0] = format;
Format::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;
desc->dsc_sub_type = gfield->gfld_sub_type;
if (desc->dsc_dtype == dtype_blob && desc->dsc_sub_type == isc_blob_text)
desc->dsc_scale = CS_METADATA; // blob charset
jrd_fld* field = FB_NEW(*dbb->dbb_permanent) jrd_fld(*dbb->dbb_permanent);
*itr = field;
field->fld_name = names[fld[RFLD_F_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 = JRD_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<jrd_rel*>* vector = dbb->dbb_relations;
const int* fld;
for (const int* relfld = relfields; relfld[RFLD_R_NAME]; relfld = fld + 1)
{
if (relfld[RFLD_R_ODS] > ENCODE_ODS(major_version, minor_original))
{
/*****************************************************
**
** free the space allocated for RDB$ROLES
**
******************************************************/
const USHORT id = relfld[RFLD_R_ID];
jrd_rel* relation = (*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]);
Format* 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)
n = init2_helper(fld, n, relation);
}
else if (fld[RFLD_F_NAME] == nam_statistics &&
relfld[RFLD_R_NAME] == nam_i_segments)
{
if (major_version >= ODS_VERSION11)
n = init2_helper(fld, n, relation);
}
else if ((fld[RFLD_F_NAME] == nam_description ||
fld[RFLD_F_NAME] == nam_sys_flag) &&
relfld[RFLD_R_NAME] == nam_roles)
{
if (major_version >= ODS_VERSION11)
n = init2_helper(fld, n, relation);
}
else if (fld[RFLD_F_NAME] == nam_description &&
relfld[RFLD_R_NAME] == nam_gens)
{
if (major_version >= ODS_VERSION11)
n = init2_helper(fld, n, relation);
}
else if ((fld[RFLD_F_NAME] == nam_base_collation_name ||
fld[RFLD_F_NAME] == nam_specific_attr) &&
relfld[RFLD_R_NAME] == nam_collations)
{
if (major_version >= ODS_VERSION11)
n = init2_helper(fld, n, relation);
}
else if (fld[RFLD_F_NAME] == nam_r_type &&
relfld[RFLD_R_NAME] == nam_relations)
{
if (ENCODE_ODS(major_version, minor_original) >= ODS_11_1)
n = init2_helper(fld, n, relation);
}
else if (fld[RFLD_F_NAME] == nam_valid_blr &&
relfld[RFLD_R_NAME] == nam_trgs)
{
if (ENCODE_ODS(major_version, minor_original) >= ODS_11_1)
n = init2_helper(fld, n, relation);
}
else if ((fld[RFLD_F_NAME] == nam_prc_type ||
fld[RFLD_F_NAME] == nam_valid_blr) &&
relfld[RFLD_R_NAME] == nam_procedures)
{
if (ENCODE_ODS(major_version, minor_original) >= ODS_11_1)
n = init2_helper(fld, n, relation);
}
else if ((fld[RFLD_F_NAME] == nam_default ||
fld[RFLD_F_NAME] == nam_d_source ||
fld[RFLD_F_NAME] == nam_collate_id /***||
fld[RFLD_F_NAME] == nam_null_flag***/) &&
relfld[RFLD_R_NAME] == nam_proc_parameters)
{
if (ENCODE_ODS(major_version, minor_original) >= ODS_11_1)
n = init2_helper(fld, n, relation);
}
else
n = init2_helper(fld, n, relation);
}
relation->rel_fields->resize(n);
format->fmt_count = n; // We are using less than the allocated members.
format->fmt_length = (USHORT)FLAG_BYTES(n);
Format::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(dbb, &(*desc), format->fmt_length);
desc->dsc_address = (UCHAR*) (IPTR) format->fmt_length;
/* In ODS11 length of RDB$MESSAGES are
enlarged from 80 to 1023 bytes */
if ((fld[RFLD_F_NAME] == nam_msg) &&
(major_version < ODS_VERSION11))
{
desc->dsc_length = 80;
}
format->fmt_length += desc->dsc_length;
}
}
}
}
}
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 = JRD_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_NUMBER);
Ods::header_page* header =
(Ods::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, jrd_req** 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 = JRD_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 = JRD_get_thread_data();
/* add desired global fields to system relations */
jrd_req* 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, 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).
*
**************************************/
Firebird::MetaName string;
index_desc idx;
thread_db* tdbb = JRD_get_thread_data();
jrd_req* handle1 = NULL;
jrd_req* 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.c_str(), X.RDB$RELATION_NAME);
string.printf("RDB$INDEX_%d", index->ini_idx_index_id);
PAD(string.c_str(), 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 */
index_desc::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 = (*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.c_str(), Y.RDB$FIELD_NAME);
tail->idx_field = segment->ini_idx_rfld_id;
tail->idx_itype = segment->ini_idx_type;
tail->idx_selectivity = 0;
END_STORE;
}
idx.idx_count = index->ini_idx_segment_count;
idx.idx_flags = index->ini_idx_flags;
SelectivityList selectivity(*tdbb->getDefaultPool());
IDX_create_index(tdbb, relation, &idx, string.c_str(), NULL, NULL,
selectivity);
X.RDB$INDEX_ID = idx.idx_id + 1;
END_STORE;
}
if (handle1) {
CMP_release(tdbb, handle1);
}
if (handle2) {
CMP_release(tdbb, 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 = JRD_get_thread_data();
jrd_req* 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);
}
}
jrd_req* 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, handle1);
}
if (handle2) {
CMP_release(tdbb, 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 = JRD_get_thread_data();
Database* dbb = tdbb->tdbb_database;
/* add desired fields to system relations, forcing a new format version */
jrd_req* s_handle = NULL;
jrd_req* m_handle = NULL;
const int* fld;
for (const int* 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, s_handle);
}
if (m_handle) {
CMP_release(tdbb, 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 Firebird::MetaName& 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];
Firebird::MetaName default_class;
SET_TDBB(tdbb);
Database* dbb = tdbb->tdbb_database;
strcpy(sec_class_name, SQL_SECCLASS_PREFIX);
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);
default_class.printf("%s%" SQUADFORMAT, DEFAULT_CLASS,
DPM_gen_id(tdbb, MET_lookup_generator(tdbb, DEFAULT_CLASS),
false, (SINT64) 1));
jrd_req* handle1 = NULL;
for (int cnt = 0; cnt < 6; cnt++)
{
STORE(REQUEST_HANDLE handle1) PRIV IN RDB$USER_PRIVILEGES
switch (cnt)
{
case 0:
strcpy(PRIV.RDB$USER, user_name.c_str());
PRIV.RDB$PRIVILEGE[0] = 'S';
PRIV.RDB$GRANT_OPTION = 1;
break;
case 1:
strcpy(PRIV.RDB$USER, user_name.c_str());
PRIV.RDB$PRIVILEGE[0] = 'I';
PRIV.RDB$GRANT_OPTION = 1;
break;
case 2:
strcpy(PRIV.RDB$USER, user_name.c_str());
PRIV.RDB$PRIVILEGE[0] = 'U';
PRIV.RDB$GRANT_OPTION = 1;
break;
case 3:
strcpy(PRIV.RDB$USER, user_name.c_str());
PRIV.RDB$PRIVILEGE[0] = 'D';
PRIV.RDB$GRANT_OPTION = 1;
break;
case 4:
strcpy(PRIV.RDB$USER, user_name.c_str());
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.c_str());
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, 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, handle1);
handle1 = NULL;
STORE(REQUEST_HANDLE handle1)
CLS IN RDB$SECURITY_CLASSES
jrd_vtof(default_class.c_str(), CLS.RDB$SECURITY_CLASS,
sizeof(CLS.RDB$SECURITY_CLASS));
CLS.RDB$ACL = blob_id_2;
END_STORE;
CMP_release(tdbb, 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(default_class.c_str(), REL.RDB$DEFAULT_CLASS,
sizeof(REL.RDB$DEFAULT_CLASS));
END_MODIFY;
END_FOR;
CMP_release(tdbb, handle1);
}
#ifdef NOT_USED_OR_REPLACED
static void add_trigger(TEXT* trigger_name, jrd_req** handle1, jrd_req** 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 = JRD_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 int init2_helper(const int* fld, int n, jrd_rel* relation)
{
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;
}
return n;
}
static void modify_relation_field(thread_db* tdbb,
const int* fld,
const int* relfld,
jrd_req** 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, jrd_req** 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;
jrd_tra* trans = dbb->dbb_sys_trans;
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;
if (generator->gen_description)
{
blb* blob = BLB_create(tdbb, trans, &X.RDB$DESCRIPTION);
BLB_put_segment(tdbb,
blob,
reinterpret_cast<const UCHAR*>(generator->gen_description),
strlen(generator->gen_description));
BLB_close(tdbb, blob);
X.RDB$DESCRIPTION.NULL = FALSE;
}
else
{
X.RDB$DESCRIPTION.NULL = TRUE;
}
END_STORE;
}
static void store_global_field(thread_db* tdbb, const gfld* gfield, jrd_req** 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_ascii)
{
X.RDB$CHARACTER_SET_ID.NULL = FALSE;
X.RDB$CHARACTER_SET_ID = CS_ASCII;
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 == isc_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);
jrd_req* 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, 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;
X.RDB$COLLATION_ATTRIBUTES = collptr->init_collation_attributes;
END_STORE;
}
CMP_release(tdbb, handle);
handle = NULL;
}
static void store_function_argument(
thread_db* tdbb, Database* dbb,
jrd_req* &handle,
const char* function_name, SLONG argument_position, SLONG mechanism, SLONG type, SLONG scale,
SLONG length, SLONG sub_type, SLONG charset, SLONG precision, SLONG char_length)
{
STORE(REQUEST_HANDLE handle) FA IN RDB$FUNCTION_ARGUMENTS
PAD(function_name, FA.RDB$FUNCTION_NAME);
FA.RDB$FUNCTION_NAME.NULL = FALSE;
FA.RDB$ARGUMENT_POSITION = argument_position;
FA.RDB$MECHANISM = mechanism;
FA.RDB$FIELD_TYPE = type;
FA.RDB$FIELD_SCALE = scale;
FA.RDB$FIELD_LENGTH = length;
FA.RDB$FIELD_SUB_TYPE = sub_type;
FA.RDB$CHARACTER_SET_ID = charset;
FA.RDB$FIELD_PRECISION = precision;
FA.RDB$CHARACTER_LENGTH = char_length;
END_STORE;
}
static void store_function(
thread_db* tdbb, Database* dbb,
jrd_req* &handle,
const char* function_name, const char* module, const char* entrypoint, SLONG argument)
{
STORE(REQUEST_HANDLE handle) F IN RDB$FUNCTIONS
PAD(function_name, F.RDB$FUNCTION_NAME);
F.RDB$FUNCTION_NAME.NULL = FALSE;
//F.RDB$FUNCTION_TYPE <null>
//F.RDB$QUERY_NAME <null>
//F.RDB$DESCRIPTION <null>
strcpy(F.RDB$MODULE_NAME, module);
F.RDB$MODULE_NAME.NULL = FALSE;
PAD(entrypoint, F.RDB$ENTRYPOINT);
F.RDB$ENTRYPOINT.NULL = FALSE;
F.RDB$RETURN_ARGUMENT = argument;
F.RDB$SYSTEM_FLAG = RDB_system;
END_STORE;
}
static void store_functions(thread_db* tdbb, Database* dbb)
{
/**************************************
*
* s t o r e _ f u n c t i o n s
*
**************************************
*
* Functional description
* Store built-in functions and their arguments
*
**************************************/
SET_TDBB(tdbb);
jrd_req *fun_handle = NULL, *arg_handle = NULL;
const char *function_name;
SLONG argument_position;
#define FUNCTION(ROUTINE, FUNCTION_NAME, MODULE_NAME, ENTRYPOINT, RET_ARG) \
function_name = FUNCTION_NAME; \
argument_position = RET_ARG ? 1 : 0; \
store_function(tdbb, dbb, fun_handle, FUNCTION_NAME, MODULE_NAME, ENTRYPOINT, RET_ARG);
#define END_FUNCTION
#define FUNCTION_ARGUMENT(MECHANISM, TYPE, SCALE, LENGTH, SUB_TYPE, CHARSET, PRECISION, CHAR_LENGTH) \
store_function_argument(tdbb, dbb, arg_handle, function_name, argument_position, \
MECHANISM, TYPE, SCALE, LENGTH, SUB_TYPE, CHARSET, PRECISION, CHAR_LENGTH); \
argument_position++;
#include "../jrd/functions.h"
CMP_release(tdbb, fun_handle);
CMP_release(tdbb, arg_handle);
}
static void store_message(thread_db* tdbb, const trigger_msg* message, jrd_req** 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 int* fld,
const int* relfld,
int field_id,
jrd_req** 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, jrd_req** 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;
}