mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-30 20:03:03 +01:00
1597 lines
46 KiB
Plaintext
1597 lines
46 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/ods.h"
|
|
#include "../jrd/btr.h"
|
|
#include "gen/ids.h"
|
|
#include "../jrd/intl.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 "../common/gdsassert.h"
|
|
#include "../dsql/dsql.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 "../yvalve/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/obj.h"
|
|
#include "../jrd/acl.h"
|
|
#include "../jrd/dyn.h"
|
|
#include "../jrd/irq.h"
|
|
#include "../jrd/IntlManager.h"
|
|
#include "../jrd/PreparedStatement.h"
|
|
#include "../jrd/constants.h"
|
|
|
|
using namespace Firebird;
|
|
using namespace Jrd;
|
|
|
|
DATABASE DB = FILENAME "ODS.RDB";
|
|
|
|
#define PAD(string, field) jrd_vtof ((char*)(string), field, sizeof (field))
|
|
const int FB_MAX_ACL_SIZE = 4096;
|
|
|
|
|
|
static void add_index_set(thread_db*);
|
|
static void add_security_to_sys_obj(thread_db*, const MetaName&, USHORT, const MetaName&,
|
|
USHORT = 0, const UCHAR* = NULL);
|
|
static void add_security_class(thread_db* tdbb, const MetaName& class_name, USHORT acl_length, const UCHAR* acl);
|
|
static void add_security_to_sys_rel(thread_db*, const MetaName&,
|
|
const TEXT*, const USHORT, const UCHAR*);
|
|
static void store_generator(thread_db*, const gen*, AutoRequest&, const MetaName&);
|
|
static void store_global_field(thread_db*, const gfld*, AutoRequest&, const MetaName&);
|
|
static void store_intlnames(thread_db*, const MetaName&);
|
|
static void store_message(thread_db*, const trigger_msg*, AutoRequest&);
|
|
static void store_relation_field(thread_db*, const int*, const int*, int, AutoRequest&);
|
|
static void store_trigger(thread_db*, const jrd_trg*, AutoRequest&);
|
|
|
|
|
|
// 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_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_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_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 char* owner, const char* 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();
|
|
Jrd::Attachment* attachment = tdbb->getAttachment();
|
|
|
|
fb_assert(owner && owner[0]);
|
|
|
|
// Uppercase owner name
|
|
MetaName ownerName(owner);
|
|
|
|
// Uppercase charset name
|
|
MetaName rdbCharSetName(charset && charset[0] ? charset : DEFAULT_DB_CHARACTER_SET_NAME);
|
|
|
|
const int* fld;
|
|
|
|
// Make sure relations exist already
|
|
|
|
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)
|
|
;
|
|
}
|
|
|
|
jrd_tra* transaction = attachment->getSysTransaction();
|
|
|
|
// Store RELATIONS and RELATION_FIELDS
|
|
|
|
SLONG rdbRelationId;
|
|
MetaName rdbRelationName;
|
|
SLONG rdbFieldId;
|
|
SLONG rdbSystemFlag = RDB_system;
|
|
SLONG rdbRelationType;
|
|
|
|
PreparedStatement::Builder sql;
|
|
sql << "insert into rdb$relations (rdb$relation_id, rdb$relation_name, rdb$field_id,"
|
|
<< "rdb$format, rdb$system_flag, rdb$dbkey_length, rdb$owner_name, rdb$relation_type)"
|
|
<< "values (" << rdbRelationId << ", " << rdbRelationName << ", " << rdbFieldId << ", 0,"
|
|
<< rdbSystemFlag << ", 8, " << ownerName << ", " << rdbRelationType << ")";
|
|
|
|
AutoPreparedStatement ps(attachment->prepareStatement(tdbb, transaction, sql));
|
|
|
|
AutoRequest handle1;
|
|
for (const int* relfld = relfields; relfld[RFLD_R_NAME]; relfld = fld + 1)
|
|
{
|
|
for (rdbFieldId = 0, fld = relfld + RFLD_RPT; fld[RFLD_F_NAME]; fld += RFLD_F_LENGTH)
|
|
{
|
|
const int* pFld = fld;
|
|
const int* pRelFld = relfld;
|
|
store_relation_field(tdbb, pFld, pRelFld, rdbFieldId, handle1);
|
|
++rdbFieldId;
|
|
}
|
|
|
|
rdbRelationId = relfld[RFLD_R_ID];
|
|
rdbRelationName = names[relfld[RFLD_R_NAME]];
|
|
rdbRelationType = relfld[RFLD_R_TYPE];
|
|
ps->execute(tdbb, transaction);
|
|
}
|
|
|
|
handle1.reset();
|
|
|
|
// Store global FIELDS
|
|
|
|
for (const gfld* gfield = gfields; gfield->gfld_name; gfield++)
|
|
store_global_field(tdbb, gfield, handle1, ownerName);
|
|
|
|
// Store DATABASE record
|
|
|
|
sql = PreparedStatement::Builder();
|
|
sql << "insert into rdb$database (rdb$relation_id, rdb$character_set_name) values ("
|
|
<< rdbRelationId << ", " << rdbCharSetName << ")";
|
|
|
|
ps.reset(attachment->prepareStatement(tdbb, transaction, sql));
|
|
|
|
rdbRelationId = USER_DEF_REL_INIT_ID;
|
|
ps->execute(tdbb, transaction);
|
|
|
|
// Store ADMIN_ROLE record
|
|
|
|
handle1.reset();
|
|
|
|
STORE(REQUEST_HANDLE handle1) X IN RDB$ROLES
|
|
{
|
|
PAD (ADMIN_ROLE, X.RDB$ROLE_NAME);
|
|
X.RDB$ROLE_NAME.NULL = FALSE;
|
|
if (ownerName.hasData())
|
|
PAD(ownerName.c_str(), X.RDB$OWNER_NAME);
|
|
else
|
|
PAD(SYSDBA_USER_NAME, X.RDB$OWNER_NAME);
|
|
X.RDB$OWNER_NAME.NULL = FALSE;
|
|
X.RDB$SYSTEM_FLAG = 1; // We have single system role, always treat it as privileged
|
|
X.RDB$SYSTEM_FLAG.NULL = FALSE;
|
|
}
|
|
END_STORE
|
|
|
|
// Create indices for system relations
|
|
add_index_set(tdbb);
|
|
|
|
// Create parameter types
|
|
|
|
handle1.reset();
|
|
|
|
for (const rtyp* type = types; type->rtyp_name; ++type)
|
|
{
|
|
// this STORE should be compatible with two below,
|
|
// as they use the same compiled request
|
|
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;
|
|
X.RDB$SYSTEM_FLAG.NULL = FALSE;
|
|
}
|
|
END_STORE
|
|
}
|
|
|
|
for (const IntlManager::CharSetDefinition* charSet = IntlManager::defaultCharSets;
|
|
charSet->name; ++charSet)
|
|
{
|
|
// this STORE should be compatible with one above and below,
|
|
// as they use the same compiled request
|
|
STORE(REQUEST_HANDLE handle1) X IN RDB$TYPES
|
|
PAD(names[nam_charset_name], X.RDB$FIELD_NAME);
|
|
PAD(charSet->name, X.RDB$TYPE_NAME);
|
|
X.RDB$TYPE = charSet->id;
|
|
X.RDB$SYSTEM_FLAG = RDB_system;
|
|
X.RDB$SYSTEM_FLAG.NULL = FALSE;
|
|
END_STORE;
|
|
}
|
|
|
|
for (const IntlManager::CharSetAliasDefinition* alias = IntlManager::defaultCharSetAliases;
|
|
alias->name; ++alias)
|
|
{
|
|
// this STORE should be compatible with two above,
|
|
// as they use the same compiled request
|
|
STORE(REQUEST_HANDLE handle1) X IN RDB$TYPES
|
|
PAD(names[nam_charset_name], X.RDB$FIELD_NAME);
|
|
PAD(alias->name, X.RDB$TYPE_NAME);
|
|
X.RDB$TYPE = alias->charSetId;
|
|
X.RDB$SYSTEM_FLAG = RDB_system;
|
|
X.RDB$SYSTEM_FLAG.NULL = FALSE;
|
|
END_STORE;
|
|
}
|
|
|
|
// Store symbols for international character sets & collations
|
|
store_intlnames(tdbb, ownerName);
|
|
|
|
// Create generators to be used by system triggers
|
|
|
|
handle1.reset();
|
|
|
|
for (const gen* generator = generators; generator->gen_name; generator++)
|
|
store_generator(tdbb, generator, handle1, ownerName);
|
|
|
|
// Adjust the value of the hidden generator RDB$GENERATORS
|
|
DPM_gen_id(tdbb, 0, true, FB_NELEM(generators) - 1);
|
|
|
|
// store system-defined triggers
|
|
|
|
handle1.reset();
|
|
|
|
for (const jrd_trg* trigger = triggers; trigger->trg_relation; ++trigger)
|
|
store_trigger(tdbb, trigger, handle1);
|
|
|
|
// store trigger messages to go with triggers
|
|
|
|
handle1.reset();
|
|
|
|
for (const trigger_msg* message = trigger_messages; message->trigmsg_name; ++message)
|
|
store_message(tdbb, message, handle1);
|
|
|
|
DFW_perform_system_work(tdbb);
|
|
|
|
const size_t ownerNameLength = ownerName.length();
|
|
fb_assert(ownerNameLength <= MAX_UCHAR);
|
|
|
|
// Add security for the non-relation system metadata objects
|
|
|
|
const UCHAR NON_REL_OWNER_ACL[] =
|
|
{ACL_priv_list, priv_control, priv_alter, priv_drop, priv_usage, ACL_end};
|
|
|
|
const UCHAR NON_REL_PUBLIC_ACL[] =
|
|
{ACL_priv_list, priv_usage, ACL_end};
|
|
|
|
UCHAR buffer[FB_MAX_ACL_SIZE];
|
|
UCHAR* acl = buffer;
|
|
*acl++ = ACL_version;
|
|
*acl++ = ACL_id_list;
|
|
*acl++ = id_person;
|
|
|
|
*acl++ = (UCHAR) ownerNameLength;
|
|
memcpy(acl, ownerName.c_str(), ownerNameLength);
|
|
acl += ownerNameLength;
|
|
|
|
*acl++ = ACL_end;
|
|
|
|
memcpy(acl, NON_REL_OWNER_ACL, sizeof(NON_REL_OWNER_ACL));
|
|
acl += sizeof(NON_REL_OWNER_ACL);
|
|
|
|
*acl++ = ACL_id_list;
|
|
*acl++ = ACL_end;
|
|
memcpy(acl, NON_REL_PUBLIC_ACL, sizeof(NON_REL_PUBLIC_ACL));
|
|
acl += sizeof(NON_REL_PUBLIC_ACL);
|
|
*acl++ = ACL_end; // Put an extra terminator to avoid scl.epp:walk_acl() missing the end.
|
|
|
|
USHORT length = acl - buffer;
|
|
|
|
for (const gfld* gfield = gfields; gfield->gfld_name; gfield++)
|
|
{
|
|
add_security_to_sys_obj(tdbb, ownerName, obj_field,
|
|
names[(USHORT) gfield->gfld_name], length, buffer);
|
|
}
|
|
|
|
for (const gen* generator = generators; generator->gen_name; generator++)
|
|
{
|
|
add_security_to_sys_obj(tdbb, ownerName, obj_generator,
|
|
generator->gen_name, length, buffer);
|
|
}
|
|
|
|
for (const IntlManager::CharSetDefinition* charset = IntlManager::defaultCharSets;
|
|
charset->name;
|
|
++charset)
|
|
{
|
|
add_security_to_sys_obj(tdbb, ownerName, obj_charset, charset->name, length, buffer);
|
|
}
|
|
|
|
for (const IntlManager::CollationDefinition* collation = IntlManager::defaultCollations;
|
|
collation->name;
|
|
++collation)
|
|
{
|
|
add_security_to_sys_obj(tdbb, ownerName, obj_collation, collation->name, length, buffer);
|
|
}
|
|
|
|
// Add default DDL security
|
|
|
|
const UCHAR DDL_OWNER_ACL[] =
|
|
{ACL_priv_list, priv_control, priv_alter, priv_drop, ACL_end};
|
|
|
|
const UCHAR DDL_PUBLIC_ACL[] =
|
|
{ACL_priv_list, ACL_end};
|
|
|
|
acl = buffer;
|
|
*acl++ = ACL_version;
|
|
*acl++ = ACL_id_list;
|
|
*acl++ = id_person;
|
|
|
|
*acl++ = (UCHAR) ownerNameLength;
|
|
memcpy(acl, ownerName.c_str(), ownerNameLength);
|
|
acl += ownerNameLength;
|
|
|
|
*acl++ = ACL_end;
|
|
|
|
memcpy(acl, DDL_OWNER_ACL, sizeof(DDL_OWNER_ACL));
|
|
acl += sizeof(DDL_OWNER_ACL);
|
|
|
|
*acl++ = ACL_id_list;
|
|
*acl++ = ACL_end;
|
|
memcpy(acl, DDL_PUBLIC_ACL, sizeof(DDL_PUBLIC_ACL));
|
|
acl += sizeof(DDL_PUBLIC_ACL);
|
|
*acl++ = ACL_end; // Put an extra terminator to avoid scl.epp:walk_acl() missing the end.
|
|
|
|
length = acl - buffer;
|
|
|
|
for (int ddl_obj = obj_database + 1; ddl_obj < obj_type_MAX; ++ddl_obj)
|
|
{
|
|
add_security_class(tdbb, get_object_name(ddl_obj), length, buffer);
|
|
}
|
|
|
|
add_security_to_sys_obj(tdbb, ownerName, obj_database, "", length, buffer);
|
|
|
|
// Add security on system tables
|
|
|
|
const UCHAR REL_OWNER_ACL[] =
|
|
{ACL_priv_list, priv_control, priv_alter, priv_drop,
|
|
priv_select, priv_insert, priv_update, priv_delete, ACL_end};
|
|
|
|
const UCHAR REL_PUBLIC_ACL[] =
|
|
{ACL_priv_list, priv_select, ACL_end};
|
|
|
|
acl = buffer;
|
|
*acl++ = ACL_version;
|
|
*acl++ = ACL_id_list;
|
|
*acl++ = id_person;
|
|
|
|
*acl++ = (UCHAR) ownerNameLength;
|
|
memcpy(acl, ownerName.c_str(), ownerNameLength);
|
|
acl += ownerNameLength;
|
|
|
|
*acl++ = ACL_end;
|
|
|
|
memcpy(acl, REL_OWNER_ACL, sizeof(REL_OWNER_ACL));
|
|
acl += sizeof(REL_OWNER_ACL);
|
|
|
|
*acl++ = ACL_id_list;
|
|
*acl++ = ACL_end;
|
|
memcpy(acl, REL_PUBLIC_ACL, sizeof(REL_PUBLIC_ACL));
|
|
acl += sizeof(REL_PUBLIC_ACL);
|
|
*acl++ = ACL_end; // Put an extra terminator to avoid scl.epp:walk_acl() missing the end.
|
|
|
|
length = acl - buffer;
|
|
|
|
add_security_to_sys_rel(tdbb, ownerName, "RDB$ROLES", length, buffer);
|
|
add_security_to_sys_rel(tdbb, ownerName, "RDB$PAGES", length, buffer);
|
|
// DFW writes here
|
|
add_security_to_sys_rel(tdbb, ownerName, "RDB$FORMATS", length, buffer);
|
|
}
|
|
|
|
|
|
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(thread_db* tdbb)
|
|
{
|
|
/**************************************
|
|
*
|
|
* 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.
|
|
*
|
|
**************************************/
|
|
SET_TDBB(tdbb);
|
|
Database* const dbb = tdbb->getDatabase();
|
|
CHECK_DBB(dbb);
|
|
|
|
Jrd::Attachment* attachment = tdbb->getAttachment();
|
|
MemoryPool* pool = attachment->att_pool;
|
|
|
|
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_flags |= MET_get_rel_flags_from_TYPE(relfld[RFLD_R_TYPE]);
|
|
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(*pool, n);
|
|
relation->rel_fields = fields;
|
|
vec<jrd_fld*>::iterator itr = fields->begin();
|
|
Format* format = Format::newFormat(*pool, n);
|
|
relation->rel_current_format = format;
|
|
vec<Format*>* formats = vec<Format*>::newVector(*pool, 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;
|
|
if (gfield->gfld_dtype == dtype_varying)
|
|
{
|
|
fb_assert(desc->dsc_length <= MAX_USHORT - sizeof(USHORT));
|
|
desc->dsc_length += sizeof(USHORT);
|
|
}
|
|
|
|
desc->dsc_dtype = gfield->gfld_dtype;
|
|
|
|
if (desc->isText())
|
|
{
|
|
if (gfield->gfld_sub_type & dsc_text_type_metadata)
|
|
desc->dsc_sub_type = CS_METADATA;
|
|
else
|
|
desc->dsc_sub_type = CS_NONE;
|
|
}
|
|
else
|
|
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(*pool) jrd_fld(*pool);
|
|
*itr = field;
|
|
field->fld_name = names[fld[RFLD_F_NAME]];
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void INI_init2(thread_db* tdbb)
|
|
{
|
|
/**************************************
|
|
*
|
|
* 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.
|
|
*
|
|
**************************************/
|
|
SET_TDBB(tdbb);
|
|
Database* const dbb = tdbb->getDatabase();
|
|
|
|
const USHORT major_version = dbb->dbb_ods_version;
|
|
const USHORT minor_version = dbb->dbb_minor_version;
|
|
vec<jrd_rel*>* vector = tdbb->getAttachment()->att_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_version))
|
|
{
|
|
// 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;
|
|
delete relation;
|
|
(*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 (ENCODE_ODS(major_version, minor_version) >= fld[RFLD_F_ODS])
|
|
n++;
|
|
}
|
|
|
|
relation->rel_fields->resize(n);
|
|
format->fmt_count = n; // We are using less than the allocated members.
|
|
format->fmt_length = 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 = MET_align(&(*desc), format->fmt_length);
|
|
desc->dsc_address = (UCHAR*)(IPTR) format->fmt_length;
|
|
format->fmt_length += desc->dsc_length;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// Load system objects into DSQL metadata cache.
|
|
void INI_init_dsql(thread_db* tdbb, dsql_dbb* database)
|
|
{
|
|
SET_TDBB(tdbb);
|
|
|
|
Database* const dbb = tdbb->getDatabase();
|
|
const USHORT majorVersion = dbb->dbb_ods_version;
|
|
const USHORT minorVersion = dbb->dbb_minor_version;
|
|
const int* fld;
|
|
|
|
// Load relation and fields.
|
|
|
|
for (const int* relfld = relfields; relfld[RFLD_R_NAME]; relfld = fld + 1)
|
|
{
|
|
if (relfld[RFLD_R_ODS] > ENCODE_ODS(majorVersion, minorVersion))
|
|
continue;
|
|
|
|
dsql_rel* relation = FB_NEW(database->dbb_pool) dsql_rel(database->dbb_pool);
|
|
|
|
relation->rel_id = relfld[RFLD_R_ID];
|
|
relation->rel_name = names[relfld[RFLD_R_NAME]];
|
|
relation->rel_owner = SYSDBA_USER_NAME;
|
|
relation->rel_dbkey_length = 8;
|
|
|
|
dsql_fld** ptr = &relation->rel_fields;
|
|
int n = 0;
|
|
|
|
for (fld = relfld + RFLD_RPT; fld[RFLD_F_NAME]; fld += RFLD_F_LENGTH)
|
|
{
|
|
if (ENCODE_ODS(majorVersion, minorVersion) < fld[RFLD_F_ODS])
|
|
continue;
|
|
|
|
dsql_fld* field = FB_NEW(database->dbb_pool) dsql_fld(database->dbb_pool);
|
|
field->fld_id = n++;
|
|
|
|
*ptr = field;
|
|
ptr = &field->fld_next;
|
|
|
|
// get field information
|
|
|
|
const gfld* gfield = &gfields[fld[RFLD_F_ID]];
|
|
|
|
field->fld_name = names[fld[RFLD_F_NAME]];
|
|
field->fieldSource = names[gfield->gfld_name];
|
|
field->length = gfield->gfld_length;
|
|
field->scale = 0;
|
|
field->subType = gfield->gfld_sub_type;
|
|
field->fld_relation = relation;
|
|
|
|
field->dtype = gfield->gfld_dtype;
|
|
|
|
if (field->dtype == dtype_varying)
|
|
field->length += sizeof(USHORT);
|
|
else if (field->dtype == dtype_blob)
|
|
{
|
|
field->segLength = 80;
|
|
if (gfield->gfld_sub_type == isc_blob_text)
|
|
field->charSetId = CS_METADATA;
|
|
}
|
|
|
|
if (DTYPE_IS_TEXT(gfield->gfld_dtype))
|
|
{
|
|
switch (gfield->gfld_sub_type)
|
|
{
|
|
case dsc_text_type_metadata:
|
|
field->charSetId = CS_METADATA;
|
|
break;
|
|
case dsc_text_type_ascii:
|
|
field->charSetId = CS_ASCII;
|
|
break;
|
|
case dsc_text_type_fixed:
|
|
field->charSetId = CS_BINARY;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (gfield->gfld_nullable)
|
|
field->flags |= FLD_nullable;
|
|
|
|
field->flags |= FLD_system;
|
|
}
|
|
|
|
database->dbb_relations.put(relation->rel_name, relation);
|
|
MET_dsql_cache_use(tdbb, SYM_relation, relation->rel_name);
|
|
}
|
|
|
|
// Load internal character sets and collations, necessary for engine operation.
|
|
|
|
for (const IntlManager::CharSetDefinition* csDef = IntlManager::defaultCharSets;
|
|
csDef->name; ++csDef)
|
|
{
|
|
if (csDef->id > ttype_last_internal)
|
|
continue;
|
|
|
|
dsql_intlsym* csSymbol = FB_NEW(database->dbb_pool) dsql_intlsym(database->dbb_pool);
|
|
csSymbol->intlsym_name = csDef->name;
|
|
csSymbol->intlsym_charset_id = csDef->id;
|
|
csSymbol->intlsym_collate_id = 0;
|
|
csSymbol->intlsym_ttype =
|
|
INTL_CS_COLL_TO_TTYPE(csSymbol->intlsym_charset_id, csSymbol->intlsym_collate_id);
|
|
csSymbol->intlsym_bytes_per_char = csDef->maxBytes;
|
|
|
|
// Mark the charset as invalid to reload it ASAP. This is done because we cannot know here
|
|
// if the user has altered its default collation.
|
|
csSymbol->intlsym_flags = INTLSYM_dropped;
|
|
|
|
database->dbb_charsets.put(csDef->name, csSymbol);
|
|
database->dbb_charsets_by_id.put(csSymbol->intlsym_charset_id, csSymbol);
|
|
MET_dsql_cache_use(tdbb, SYM_intlsym_charset, csDef->name);
|
|
|
|
for (const IntlManager::CollationDefinition* colDef = IntlManager::defaultCollations;
|
|
colDef->name; ++colDef)
|
|
{
|
|
if (colDef->charSetId != csDef->id)
|
|
continue;
|
|
|
|
dsql_intlsym* colSymbol = FB_NEW(database->dbb_pool) dsql_intlsym(database->dbb_pool);
|
|
colSymbol->intlsym_name = colDef->name;
|
|
colSymbol->intlsym_flags = 0;
|
|
colSymbol->intlsym_charset_id = csDef->id;
|
|
colSymbol->intlsym_collate_id = colDef->collationId;
|
|
colSymbol->intlsym_ttype =
|
|
INTL_CS_COLL_TO_TTYPE(colSymbol->intlsym_charset_id, colSymbol->intlsym_collate_id);
|
|
colSymbol->intlsym_bytes_per_char = csDef->maxBytes;
|
|
|
|
database->dbb_collations.put(colDef->name, colSymbol);
|
|
MET_dsql_cache_use(tdbb, SYM_intlsym_collation, colDef->name);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
static void add_index_set(thread_db* tdbb)
|
|
{
|
|
/**************************************
|
|
*
|
|
* 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).
|
|
*
|
|
**************************************/
|
|
SET_TDBB(tdbb);
|
|
Jrd::Attachment* attachment = tdbb->getAttachment();
|
|
|
|
index_desc idx;
|
|
|
|
AutoRequest handle1, handle2, handle3;
|
|
|
|
for (int n = 0; n < SYSTEM_INDEX_COUNT; n++)
|
|
{
|
|
const ini_idx_t* index = &indices[n];
|
|
jrd_rel* relation = MET_relation(tdbb, index->ini_idx_relid);
|
|
|
|
Firebird::MetaName indexName;
|
|
indexName.printf("RDB$INDEX_%d", index->ini_idx_index_id);
|
|
|
|
STORE(REQUEST_HANDLE handle1) X IN RDB$INDICES
|
|
PAD(relation->rel_name.c_str(), X.RDB$RELATION_NAME);
|
|
PAD(indexName.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 = RDB_system;
|
|
X.RDB$SYSTEM_FLAG.NULL = FALSE;
|
|
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, indexName.c_str(), NULL,
|
|
attachment->getSysTransaction(), selectivity);
|
|
|
|
X.RDB$INDEX_ID = idx.idx_id + 1;
|
|
END_STORE
|
|
|
|
if (index->ini_idx_flags & idx_unique)
|
|
{
|
|
STORE(REQUEST_HANDLE handle3) RC IN RDB$RELATION_CONSTRAINTS
|
|
PAD(indexName.c_str(), RC.RDB$CONSTRAINT_NAME);
|
|
PAD(indexName.c_str(), RC.RDB$INDEX_NAME);
|
|
PAD(relation->rel_name.c_str(), RC.RDB$RELATION_NAME);
|
|
strcpy(RC.RDB$CONSTRAINT_TYPE, UNIQUE_CNSTRT);
|
|
strcpy(RC.RDB$DEFERRABLE, "NO");
|
|
strcpy(RC.RDB$INITIALLY_DEFERRED, "NO");
|
|
END_STORE
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// 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 USHORT acl_length,
|
|
const UCHAR* acl)
|
|
{
|
|
/**************************************
|
|
*
|
|
* 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.
|
|
*
|
|
**************************************/
|
|
Firebird::MetaName security_class, default_class;
|
|
|
|
SET_TDBB(tdbb);
|
|
Jrd::Attachment* attachment = tdbb->getAttachment();
|
|
|
|
bid blob_id_1;
|
|
attachment->storeBinaryBlob(tdbb, attachment->getSysTransaction(), &blob_id_1,
|
|
ByteChunk(acl, acl_length));
|
|
|
|
bid blob_id_2;
|
|
attachment->storeBinaryBlob(tdbb, attachment->getSysTransaction(), &blob_id_2,
|
|
ByteChunk(acl, acl_length));
|
|
|
|
security_class.printf("%s%" SQUADFORMAT, SQL_SECCLASS_PREFIX,
|
|
DPM_gen_id(tdbb, MET_lookup_generator(tdbb, SQL_SECCLASS_GENERATOR), false, 1));
|
|
|
|
default_class.printf("%s%" SQUADFORMAT, DEFAULT_CLASS,
|
|
DPM_gen_id(tdbb, MET_lookup_generator(tdbb, DEFAULT_CLASS), false, 1));
|
|
|
|
AutoRequest handle1;
|
|
|
|
STORE(REQUEST_HANDLE handle1)
|
|
CLS IN RDB$SECURITY_CLASSES
|
|
{
|
|
PAD(security_class.c_str(), CLS.RDB$SECURITY_CLASS);
|
|
CLS.RDB$ACL = blob_id_1;
|
|
}
|
|
END_STORE
|
|
|
|
handle1.reset();
|
|
|
|
STORE(REQUEST_HANDLE handle1)
|
|
CLS IN RDB$SECURITY_CLASSES
|
|
{
|
|
PAD(default_class.c_str(), CLS.RDB$SECURITY_CLASS);
|
|
CLS.RDB$ACL = blob_id_2;
|
|
}
|
|
END_STORE
|
|
|
|
handle1.reset();
|
|
|
|
FOR(REQUEST_HANDLE handle1) REL IN RDB$RELATIONS
|
|
WITH REL.RDB$RELATION_NAME EQ rel_name
|
|
{
|
|
MODIFY REL USING
|
|
REL.RDB$SECURITY_CLASS.NULL = FALSE;
|
|
PAD(security_class.c_str(), REL.RDB$SECURITY_CLASS);
|
|
|
|
REL.RDB$DEFAULT_CLASS.NULL = FALSE;
|
|
PAD(default_class.c_str(), REL.RDB$DEFAULT_CLASS);
|
|
END_MODIFY
|
|
}
|
|
END_FOR
|
|
|
|
handle1.reset();
|
|
|
|
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
|
|
}
|
|
}
|
|
|
|
|
|
// Add security to system objects.
|
|
static void add_security_to_sys_obj(thread_db* tdbb,
|
|
const MetaName& user_name,
|
|
USHORT obj_type,
|
|
const MetaName& obj_name,
|
|
USHORT acl_length,
|
|
const UCHAR* acl)
|
|
{
|
|
SET_TDBB(tdbb);
|
|
Jrd::Attachment* const attachment = tdbb->getAttachment();
|
|
|
|
bid blob_id;
|
|
attachment->storeBinaryBlob(tdbb, attachment->getSysTransaction(), &blob_id,
|
|
ByteChunk(acl, acl_length));
|
|
|
|
Firebird::MetaName security_class;
|
|
security_class.printf("%s%"SQUADFORMAT, SQL_SECCLASS_PREFIX,
|
|
DPM_gen_id(tdbb, MET_lookup_generator(tdbb, SQL_SECCLASS_GENERATOR), false, 1));
|
|
|
|
AutoRequest handle;
|
|
|
|
STORE(REQUEST_HANDLE handle)
|
|
CLS IN RDB$SECURITY_CLASSES
|
|
{
|
|
PAD(security_class.c_str(), CLS.RDB$SECURITY_CLASS);
|
|
CLS.RDB$ACL = blob_id;
|
|
}
|
|
END_STORE
|
|
|
|
handle.reset();
|
|
|
|
if (obj_type == obj_field)
|
|
{
|
|
FOR(REQUEST_HANDLE handle) FLD IN RDB$FIELDS
|
|
WITH FLD.RDB$FIELD_NAME EQ obj_name.c_str()
|
|
{
|
|
MODIFY FLD USING
|
|
FLD.RDB$SECURITY_CLASS.NULL = FALSE;
|
|
PAD(security_class.c_str(), FLD.RDB$SECURITY_CLASS);
|
|
END_MODIFY
|
|
}
|
|
END_FOR
|
|
}
|
|
else if (obj_type == obj_charset)
|
|
{
|
|
FOR(REQUEST_HANDLE handle) CS IN RDB$CHARACTER_SETS
|
|
WITH CS.RDB$CHARACTER_SET_NAME EQ obj_name.c_str()
|
|
{
|
|
MODIFY CS USING
|
|
CS.RDB$SECURITY_CLASS.NULL = FALSE;
|
|
PAD(security_class.c_str(), CS.RDB$SECURITY_CLASS);
|
|
END_MODIFY
|
|
}
|
|
END_FOR
|
|
}
|
|
else if (obj_type == obj_collation)
|
|
{
|
|
FOR(REQUEST_HANDLE handle) COLL IN RDB$COLLATIONS
|
|
WITH COLL.RDB$COLLATION_NAME EQ obj_name.c_str()
|
|
{
|
|
MODIFY COLL USING
|
|
COLL.RDB$SECURITY_CLASS.NULL = FALSE;
|
|
PAD(security_class.c_str(), COLL.RDB$SECURITY_CLASS);
|
|
END_MODIFY
|
|
}
|
|
END_FOR
|
|
}
|
|
else if (obj_type == obj_exception)
|
|
{
|
|
FOR(REQUEST_HANDLE handle) XCP IN RDB$EXCEPTIONS
|
|
WITH XCP.RDB$EXCEPTION_NAME EQ obj_name.c_str()
|
|
{
|
|
MODIFY XCP USING
|
|
XCP.RDB$SECURITY_CLASS.NULL = FALSE;
|
|
PAD(security_class.c_str(), XCP.RDB$SECURITY_CLASS);
|
|
END_MODIFY
|
|
}
|
|
END_FOR
|
|
}
|
|
else if (obj_type == obj_generator)
|
|
{
|
|
FOR(REQUEST_HANDLE handle) GEN IN RDB$GENERATORS
|
|
WITH GEN.RDB$GENERATOR_NAME EQ obj_name.c_str()
|
|
{
|
|
MODIFY GEN USING
|
|
GEN.RDB$SECURITY_CLASS.NULL = FALSE;
|
|
PAD(security_class.c_str(), GEN.RDB$SECURITY_CLASS);
|
|
END_MODIFY
|
|
}
|
|
END_FOR
|
|
}
|
|
else if (obj_type == obj_database)
|
|
{
|
|
FOR(REQUEST_HANDLE handle) DB IN RDB$DATABASE
|
|
{
|
|
MODIFY DB USING
|
|
DB.RDB$SECURITY_CLASS.NULL = FALSE;
|
|
PAD(security_class.c_str(), DB.RDB$SECURITY_CLASS);
|
|
END_MODIFY
|
|
}
|
|
END_FOR
|
|
}
|
|
|
|
handle.reset();
|
|
|
|
for (const char* p = USAGE_PRIVILEGES; *p; ++p)
|
|
{
|
|
STORE(REQUEST_HANDLE handle) PRIV IN RDB$USER_PRIVILEGES
|
|
PAD(user_name.c_str(), PRIV.RDB$USER);
|
|
PAD(obj_name.c_str(), PRIV.RDB$RELATION_NAME);
|
|
PRIV.RDB$PRIVILEGE[0] = *p;
|
|
PRIV.RDB$PRIVILEGE[1] = 0;
|
|
PRIV.RDB$GRANT_OPTION = 1;
|
|
PRIV.RDB$USER_TYPE = obj_user;
|
|
PRIV.RDB$OBJECT_TYPE = obj_type;
|
|
END_STORE
|
|
}
|
|
}
|
|
|
|
|
|
// Add security class.
|
|
static void add_security_class(thread_db* tdbb, const MetaName& class_name, USHORT acl_length, const UCHAR* acl)
|
|
{
|
|
SET_TDBB(tdbb);
|
|
Jrd::Attachment* const attachment = tdbb->getAttachment();
|
|
|
|
bid blob_id;
|
|
attachment->storeBinaryBlob(tdbb, attachment->getSysTransaction(), &blob_id,
|
|
ByteChunk(acl, acl_length));
|
|
|
|
AutoRequest handle;
|
|
|
|
STORE(REQUEST_HANDLE handle)
|
|
CLS IN RDB$SECURITY_CLASSES
|
|
{
|
|
PAD(class_name.c_str(), CLS.RDB$SECURITY_CLASS);
|
|
CLS.RDB$ACL = blob_id;
|
|
}
|
|
END_STORE
|
|
}
|
|
|
|
|
|
static void store_generator(thread_db* tdbb, const gen* generator, AutoRequest& handle,
|
|
const MetaName& owner)
|
|
{
|
|
/**************************************
|
|
*
|
|
* 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);
|
|
Jrd::Attachment* attachment = tdbb->getAttachment();
|
|
|
|
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;
|
|
X.RDB$SYSTEM_FLAG.NULL = FALSE;
|
|
PAD(owner.c_str(), X.RDB$OWNER_NAME);
|
|
X.RDB$OWNER_NAME.NULL = FALSE;
|
|
X.RDB$INITIAL_VALUE = 0;
|
|
X.RDB$INITIAL_VALUE.NULL = FALSE;
|
|
if (generator->gen_description)
|
|
{
|
|
attachment->storeMetaDataBlob(tdbb, attachment->getSysTransaction(), &X.RDB$DESCRIPTION,
|
|
generator->gen_description);
|
|
X.RDB$DESCRIPTION.NULL = FALSE;
|
|
}
|
|
else
|
|
X.RDB$DESCRIPTION.NULL = TRUE;
|
|
|
|
X.RDB$GENERATOR_INCREMENT = 0; // only sys gens have zero default increment
|
|
}
|
|
END_STORE
|
|
}
|
|
|
|
|
|
static void store_global_field(thread_db* tdbb, const gfld* gfield, AutoRequest& handle,
|
|
const MetaName& owner)
|
|
{
|
|
/**************************************
|
|
*
|
|
* 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->getDatabase();
|
|
Jrd::Attachment* attachment = tdbb->getAttachment();
|
|
|
|
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$SYSTEM_FLAG.NULL = FALSE;
|
|
PAD(owner.c_str(), X.RDB$OWNER_NAME);
|
|
X.RDB$OWNER_NAME.NULL = FALSE;
|
|
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;
|
|
X.RDB$CHARACTER_LENGTH.NULL = TRUE;
|
|
if (gfield->gfld_dflt_blr)
|
|
{
|
|
attachment->storeBinaryBlob(tdbb, attachment->getSysTransaction(), &X.RDB$DEFAULT_VALUE,
|
|
ByteChunk(gfield->gfld_dflt_blr, gfield->gfld_dflt_len));
|
|
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;
|
|
}
|
|
switch (gfield->gfld_sub_type)
|
|
{
|
|
case 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;
|
|
X.RDB$CHARACTER_LENGTH.NULL = FALSE;
|
|
X.RDB$CHARACTER_LENGTH = X.RDB$FIELD_LENGTH / METADATA_BYTES_PER_CHAR;
|
|
break;
|
|
case 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;
|
|
break;
|
|
case 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;
|
|
break;
|
|
default:
|
|
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;
|
|
}
|
|
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;
|
|
|
|
case dtype_boolean:
|
|
X.RDB$FIELD_TYPE = (int) blr_bool;
|
|
break;
|
|
|
|
default:
|
|
fb_assert(FALSE);
|
|
break;
|
|
}
|
|
|
|
// Acknowledge not NULL sys fields
|
|
X.RDB$NULL_FLAG.NULL = FALSE;
|
|
X.RDB$NULL_FLAG = !gfield->gfld_nullable;
|
|
}
|
|
END_STORE
|
|
}
|
|
|
|
|
|
static void store_intlnames(thread_db* tdbb, const MetaName& owner)
|
|
{
|
|
/**************************************
|
|
*
|
|
* 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::Attachment* attachment = tdbb->getAttachment();
|
|
|
|
AutoRequest handle;
|
|
|
|
for (const IntlManager::CharSetDefinition* charSet = IntlManager::defaultCharSets;
|
|
charSet->name; ++charSet)
|
|
{
|
|
STORE(REQUEST_HANDLE handle) X IN RDB$CHARACTER_SETS USING
|
|
{
|
|
PAD(charSet->name, X.RDB$CHARACTER_SET_NAME);
|
|
PAD(charSet->name, X.RDB$DEFAULT_COLLATE_NAME);
|
|
X.RDB$CHARACTER_SET_ID = charSet->id;
|
|
X.RDB$BYTES_PER_CHARACTER = charSet->maxBytes;
|
|
X.RDB$SYSTEM_FLAG = RDB_system;
|
|
X.RDB$SYSTEM_FLAG.NULL = FALSE;
|
|
PAD(owner.c_str(), X.RDB$OWNER_NAME);
|
|
X.RDB$OWNER_NAME.NULL = FALSE;
|
|
}
|
|
END_STORE
|
|
}
|
|
|
|
handle.reset();
|
|
|
|
for (const IntlManager::CollationDefinition* collation = IntlManager::defaultCollations;
|
|
collation->name; ++collation)
|
|
{
|
|
STORE(REQUEST_HANDLE handle) X IN RDB$COLLATIONS USING
|
|
{
|
|
PAD(collation->name, X.RDB$COLLATION_NAME);
|
|
|
|
if (collation->baseName)
|
|
{
|
|
X.RDB$BASE_COLLATION_NAME.NULL = false;
|
|
PAD(collation->baseName, X.RDB$BASE_COLLATION_NAME);
|
|
}
|
|
else
|
|
X.RDB$BASE_COLLATION_NAME.NULL = true;
|
|
|
|
X.RDB$CHARACTER_SET_ID = collation->charSetId;
|
|
X.RDB$COLLATION_ID = collation->collationId;
|
|
X.RDB$SYSTEM_FLAG = RDB_system;
|
|
X.RDB$SYSTEM_FLAG.NULL = FALSE;
|
|
PAD(owner.c_str(), X.RDB$OWNER_NAME);
|
|
X.RDB$OWNER_NAME.NULL = FALSE;
|
|
X.RDB$COLLATION_ATTRIBUTES = collation->attributes;
|
|
|
|
if (collation->specificAttributes)
|
|
{
|
|
attachment->storeMetaDataBlob(tdbb, attachment->getSysTransaction(),
|
|
&X.RDB$SPECIFIC_ATTRIBUTES, collation->specificAttributes);
|
|
X.RDB$SPECIFIC_ATTRIBUTES.NULL = FALSE;
|
|
}
|
|
else
|
|
X.RDB$SPECIFIC_ATTRIBUTES.NULL = TRUE;
|
|
}
|
|
END_STORE
|
|
}
|
|
}
|
|
|
|
|
|
static void store_message(thread_db* tdbb, const trigger_msg* message, AutoRequest& handle)
|
|
{
|
|
/**************************************
|
|
*
|
|
* s t o r e _ m e s s a g e
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Store system trigger messages.
|
|
*
|
|
**************************************/
|
|
SET_TDBB(tdbb);
|
|
Jrd::Attachment* attachment = tdbb->getAttachment();
|
|
|
|
// 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,
|
|
AutoRequest& handle)
|
|
{
|
|
/**************************************
|
|
*
|
|
* 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);
|
|
Jrd::Attachment* attachment = tdbb->getAttachment();
|
|
|
|
STORE(REQUEST_HANDLE handle) X IN RDB$RELATION_FIELDS
|
|
{
|
|
const gfld* gfield = &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$SYSTEM_FLAG.NULL = FALSE;
|
|
X.RDB$UPDATE_FLAG = fld[RFLD_F_UPDATE];
|
|
}
|
|
END_STORE
|
|
}
|
|
|
|
|
|
static void store_trigger(thread_db* tdbb, const jrd_trg* trigger, AutoRequest& 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);
|
|
Jrd::Attachment* attachment = tdbb->getAttachment();
|
|
|
|
// indicate that the relation format needs revising
|
|
dsc desc;
|
|
desc.makeText(static_cast<USHORT>(strlen(names[trigger->trg_relation])), CS_METADATA,
|
|
(UCHAR*) names[trigger->trg_relation]);
|
|
DFW_post_system_work(tdbb, 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$SYSTEM_FLAG.NULL = FALSE;
|
|
X.RDB$TRIGGER_TYPE = trigger->trg_type;
|
|
X.RDB$FLAGS = trigger->trg_flags;
|
|
attachment->storeBinaryBlob(tdbb, attachment->getSysTransaction(), &X.RDB$TRIGGER_BLR,
|
|
ByteChunk(trigger->trg_blr, trigger->trg_length));
|
|
}
|
|
END_STORE
|
|
}
|