8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-25 00:43:03 +01:00
firebird-mirror/src/jrd/dyn_def.epp
asfernandes 888174719e Misc.
2005-06-08 02:09:46 +00:00

4432 lines
117 KiB
Plaintext

/*
* PROGRAM: JRD Data Definition Utility
* MODULE: dyn_define.epp
* DESCRIPTION: Dynamic data definition DYN_define_<x>
*
* 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): ______________________________________.
*
* 23-May-2001 Claudio Valderrama - Forbid zero length identifiers,
* they are not ANSI SQL compliant.
* 2001.10.08 Claudio Valderrama: Add case isc_dyn_system_flag to
* DYN_define_trigger() in order to receive values for special triggers
* as defined in constants.h.
* 2001.10.08 Ann Harrison: Changed dyn_create_index so it doesn't consider
* simple unique indexes when finding a "referred index", but only
* indexes that support unique constraints or primary keys.
* 26-Sep-2001 Paul Beach - External File Directory Config. Parameter
* 2002-02-24 Sean Leyne - Code Cleanup of old Win 3.1 port (WINDOWS_ONLY)
* 2002.08.10 Dmitry Yemanov: ALTER VIEW
*
* 2002.10.29 Sean Leyne - Removed obsolete "Netware" port
*
* 2004.01.16 Vlad Horsun: added support for default parameters
*/
#include "firebird.h"
#include "../common/classes/fb_string.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "../jrd/common.h"
#include <stdarg.h>
#include "../jrd/jrd.h"
#include "../jrd/ods.h"
#include "../jrd/tra.h"
#include "../jrd/scl.h"
#include "../jrd/drq.h"
#include "../jrd/req.h"
#include "../jrd/flags.h"
#include "../jrd/ibase.h"
#include "../jrd/lls.h"
#include "../jrd/all.h"
#include "../jrd/met.h"
#include "../jrd/btr.h"
#include "../jrd/intl.h"
#include "../jrd/dyn.h"
#include "../jrd/gdsassert.h"
#include "../jrd/all_proto.h"
#include "../jrd/blb_proto.h"
#include "../jrd/cmp_proto.h"
#include "../jrd/dls_proto.h"
#include "../jrd/dyn_proto.h"
#include "../jrd/dyn_df_proto.h"
#include "../jrd/dyn_ut_proto.h"
#include "../jrd/err_proto.h"
#include "../jrd/exe_proto.h"
#include "../jrd/gds_proto.h"
#include "../jrd/inf_proto.h"
#include "../jrd/intl_proto.h"
#include "../jrd/isc_f_proto.h"
#include "../jrd/met_proto.h"
#include "../jrd/thd.h"
#include "../jrd/vio_proto.h"
#include "../jrd/scl_proto.h"
#include "../jrd/gdsassert.h"
#include "../jrd/os/path_utils.h"
#include "../common/utils_proto.h"
#include "../jrd/IntlManager.h"
using namespace Jrd;
typedef Firebird::ObjectsArray<Firebird::MetaName> MetaNameArray;
const int FOR_KEY_UPD_CASCADE = 0x01;
const int FOR_KEY_UPD_NULL = 0x02;
const int FOR_KEY_UPD_DEFAULT = 0x04;
const int FOR_KEY_UPD_NONE = 0x08;
const int FOR_KEY_DEL_CASCADE = 0x10;
const int FOR_KEY_DEL_NULL = 0x20;
const int FOR_KEY_DEL_DEFAULT = 0x40;
const int FOR_KEY_DEL_NONE = 0x80;
DATABASE DB = STATIC "ODS.RDB";
static const UCHAR who_blr[] =
{
blr_version5,
blr_begin,
blr_message, 0, 1, 0,
blr_cstring, 32, 0,
blr_begin,
blr_send, 0,
blr_begin,
blr_assignment,
blr_user_name,
blr_parameter, 0, 0, 0,
blr_end,
blr_end,
blr_end,
blr_eoc
};
static void check_unique_name(thread_db*, Global*, const Firebird::MetaName&, bool);
static bool find_field_source(thread_db*, Global*, const Firebird::MetaName&, USHORT, const TEXT*, TEXT*);
static bool get_who(thread_db*, Global*, Firebird::MetaName&);
static bool is_it_user_name(Global*, const Firebird::MetaName&, thread_db*);
static USHORT skip_blr_blob(const UCHAR** ptr);
void DYN_define_collation( Global* gbl, const UCHAR** ptr)
{
/**************************************
*
* D Y N _ d e f i n e _ c o l l a t i o n
*
**************************************
*
* Functional description
* Define a collation.
*
**************************************/
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;
if (ENCODE_ODS(major_version, minor_original) < ODS_11_0)
{
DYN_error_punt(false, 220, NULL, NULL, NULL, NULL, NULL);
/* msg 220: "CREATE COLLATION statement is not supported in older versions of the database.
A backup and restore is required." */
}
Firebird::MetaName collation_name;
Firebird::MetaName charsetName;
GET_STRING(ptr, collation_name);
if (!collation_name.length())
DYN_error_punt(false, 212, NULL, NULL, NULL, NULL, NULL);
/* msg 212: "Zero length identifiers not allowed" */
jrd_req* request = CMP_find_request(tdbb, drq_s_colls, DYN_REQUESTS);
bool b_ending_store = false;
try
{
STORE(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
X IN RDB$COLLATIONS
SubtypeInfo info;
USHORT attributes_on = 0;
USHORT attributes_off = 0;
SSHORT specific_attributes_charset = CS_NONE;
info.attributes = 0;
X.RDB$SPECIFIC_ATTRIBUTES.NULL = TRUE;
X.RDB$BASE_COLLATION_NAME.NULL = TRUE;
while (**ptr != isc_dyn_end)
{
switch (*(*ptr)++)
{
case isc_dyn_coll_for_charset:
{
X.RDB$CHARACTER_SET_ID.NULL = FALSE;
X.RDB$CHARACTER_SET_ID = DYN_get_number(ptr);
// ASF: User collations are created with the last number available,
// to minimize the possibility of conflicts with future system collations.
// The greater available number is 126 to avoid signed/unsigned problems.
X.RDB$COLLATION_ID.NULL = FALSE;
X.RDB$COLLATION_ID = 126;
jrd_req* request2 = CMP_find_request(tdbb, drq_l_colls, DYN_REQUESTS);
bool found = false;
FOR(REQUEST_HANDLE request2
TRANSACTION_HANDLE gbl->gbl_transaction)
Y IN RDB$COLLATIONS CROSS
CS IN RDB$CHARACTER_SETS
WITH Y.RDB$CHARACTER_SET_ID = X.RDB$CHARACTER_SET_ID AND
CS.RDB$CHARACTER_SET_ID EQ Y.RDB$CHARACTER_SET_ID
SORTED BY DESCENDING Y.RDB$COLLATION_ID
if (!DYN_REQUEST(drq_l_colls))
DYN_REQUEST(drq_l_colls) = request2;
if (found) {
EXE_unwind(tdbb, request2);
break;
}
if (Y.RDB$COLLATION_ID + 1 <= X.RDB$COLLATION_ID)
{
found = true;
charsetName = CS.RDB$CHARACTER_SET_NAME;
}
else
X.RDB$COLLATION_ID = Y.RDB$COLLATION_ID - 1;
END_FOR
if (!DYN_REQUEST(drq_l_colls))
DYN_REQUEST(drq_l_colls) = request2;
if (!found)
{
DYN_error_punt(false, 221, NULL, NULL, NULL, NULL, NULL);
/* msg 221: "Maximum number of collations per character set exceeded" */
}
break;
}
case isc_dyn_coll_from:
//// TODO: verify return value
MET_get_char_coll_subtype_info(tdbb, DYN_get_number(ptr), &info);
X.RDB$BASE_COLLATION_NAME.NULL = FALSE;
strcpy(X.RDB$BASE_COLLATION_NAME, info.baseCollationName.c_str());
break;
case isc_dyn_coll_attribute:
{
const SSHORT attr = DYN_get_number(ptr);
if (attr >= 0)
{
attributes_on |= attr;
attributes_off &= ~attr;
}
else
{
attributes_on &= ~(-attr);
attributes_off |= -attr;
}
break;
}
// ASF: Our DDL strings is very weak.
// I've added isc_dyn_coll_specific_attributes_charset to pass the character set of a string.
// It may be the connection charset or some charset specified with INTRODUCER.
// Better approach is to pass DYN strings (including delimited identifiers) with the
// charset and reading it converting to CS_METADATA.
case isc_dyn_coll_specific_attributes_charset:
specific_attributes_charset = DYN_get_number(ptr);
break;
case isc_dyn_coll_specific_attributes:
{
UCHAR bpb[] = {isc_bpb_version1,
isc_bpb_source_type, 1, isc_blob_text, isc_bpb_source_interp, 1, 0,
isc_bpb_target_type, 1, isc_blob_text, isc_bpb_target_interp, 1, 0};
bpb[6] = specific_attributes_charset; // from charset
bpb[12] = CS_METADATA; // to charset
X.RDB$SPECIFIC_ATTRIBUTES.NULL = FALSE;
DYN_put_text_blob(gbl, ptr, &X.RDB$SPECIFIC_ATTRIBUTES, sizeof(bpb), bpb);
// ASF: retrieve RDB$SPECIFIC_ATTRIBUTES with UNICODE_FSS character set
blb* blob = BLB_open(tdbb, gbl->gbl_transaction, &X.RDB$SPECIFIC_ATTRIBUTES);
BLB_get_data(tdbb, blob, info.specificAttributes.getBuffer(blob->blb_length),
blob->blb_length);
break;
}
default:
DYN_unsupported_verb();
}
}
strcpy(X.RDB$COLLATION_NAME, collation_name.c_str());
X.RDB$COLLATION_ATTRIBUTES = (info.attributes | attributes_on) & (~attributes_off);
// If isc_dyn_coll_specific_attributes is not provided, then inherit from the base collation
if (X.RDB$SPECIFIC_ATTRIBUTES.NULL && info.specificAttributes.getCount() != 0)
{
X.RDB$SPECIFIC_ATTRIBUTES.NULL = FALSE;
// ASF: Transliteration should not occur here because
// info.specificAttributes and X.RDB$SPECIFIC_ATTRIBUTES
// are already in UNICODE_FSS character set.
blb* blob = BLB_create(tdbb, gbl->gbl_transaction, &X.RDB$SPECIFIC_ATTRIBUTES);
BLB_put_segment(tdbb, blob, info.specificAttributes.begin(), info.specificAttributes.getCount());
BLB_close(tdbb, blob);
}
info.charsetName = charsetName.c_str();
info.collationName = X.RDB$COLLATION_NAME;
if (X.RDB$BASE_COLLATION_NAME.NULL)
info.baseCollationName = info.collationName;
else
info.baseCollationName = X.RDB$BASE_COLLATION_NAME;
info.attributes = X.RDB$COLLATION_ATTRIBUTES;
info.ignoreAttributes = false;
if (!IntlManager::collationInstalled(info.baseCollationName, info.charsetName))
{
DYN_error_punt(false, 223, NULL, NULL, NULL, NULL, NULL);
/* msg: 223: "Collation not installed" */
}
if (!INTL_texttype_validate(tdbb, &info))
{
DYN_error_punt(false, 222, NULL, NULL, NULL, NULL, NULL);
/* msg: 222: "Invalid collation attributes" */
}
b_ending_store = true;
END_STORE;
if (!DYN_REQUEST(drq_s_colls))
DYN_REQUEST(drq_s_colls) = request;
}
catch (const std::exception& ex) {
Firebird::stuff_exception(tdbb->tdbb_status_vector, ex);
if (b_ending_store) {
DYN_rundown_request(request, drq_s_colls);
DYN_error_punt(true, 219, NULL, NULL, NULL, NULL, NULL);
/* msg 219: "DEFINE COLLATION failed" */
}
throw;
}
}
void DYN_define_constraint(Global* gbl,
const UCHAR** ptr,
const Firebird::MetaName* relation_name,
Firebird::MetaName* field_name)
{
/**************************************
*
* D Y N _ d e f i n e _ c o n s t r a i n t
*
**************************************
*
* Functional description
* Execute a dynamic ddl statement that
* creates an integrity constraint and if not a CHECK
* constraint, also an index for the constraint.
*
**************************************/
UCHAR verb;
Firebird::MetaName constraint_name, index_name, referred_index_name;
Firebird::MetaName null_field_name, trigger_name;
MetaNameArray field_list;
int list_index = -1;
int all_count, unique_count;
bool primary_flag = false, foreign_flag = false;
UCHAR ri_action = 0;
thread_db* tdbb = JRD_get_thread_data();
Database* dbb = tdbb->tdbb_database;
GET_STRING(ptr, constraint_name);
if (constraint_name.length() == 0)
{
DYN_UTIL_generate_constraint_name(tdbb, gbl, constraint_name);
}
if (constraint_name.length() == 0)
{
DYN_error_punt(false, 212, NULL, NULL, NULL, NULL, NULL);
/* msg 212: "Zero length identifiers not allowed" */
}
jrd_req* request = NULL;
SSHORT id = -1;
try {
request = CMP_find_request(tdbb, drq_s_rel_con, DYN_REQUESTS);
id = drq_s_rel_con;
STORE(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
CRT IN RDB$RELATION_CONSTRAINTS
strcpy(CRT.RDB$CONSTRAINT_NAME, constraint_name.c_str());
strcpy(CRT.RDB$RELATION_NAME, relation_name->c_str());
switch (verb = *(*ptr)++)
{
case isc_dyn_def_primary_key:
primary_flag = true;
strcpy(CRT.RDB$CONSTRAINT_TYPE, PRIMARY_KEY);
break;
case isc_dyn_def_foreign_key:
foreign_flag = true;
strcpy(CRT.RDB$CONSTRAINT_TYPE, FOREIGN_KEY);
break;
case isc_dyn_def_unique:
strcpy(CRT.RDB$CONSTRAINT_TYPE, UNIQUE_CNSTRT);
break;
case isc_dyn_def_trigger:
strcpy(CRT.RDB$CONSTRAINT_TYPE, CHECK_CNSTRT);
CRT.RDB$INDEX_NAME.NULL = TRUE;
break;
case isc_dyn_fld_not_null:
strcpy(CRT.RDB$CONSTRAINT_TYPE, NOT_NULL_CNSTRT);
CRT.RDB$INDEX_NAME.NULL = TRUE;
break;
default:
DYN_unsupported_verb();
}
if (verb != isc_dyn_def_trigger && verb != isc_dyn_fld_not_null) {
referred_index_name = "";
DYN_define_index(gbl, ptr, relation_name, verb, &index_name,
&referred_index_name, &constraint_name,
&ri_action);
strcpy(CRT.RDB$INDEX_NAME, index_name.c_str());
CRT.RDB$INDEX_NAME.NULL = FALSE;
/* check that we have references permissions on the table and
fields that the index:referred_index_name is on. */
SCL_check_index(tdbb, referred_index_name, 0, SCL_sql_references);
}
END_STORE;
if (!DYN_REQUEST(drq_s_rel_con))
{
DYN_REQUEST(drq_s_rel_con) = request;
}
} // try
catch (const std::exception& ex) {
Firebird::stuff_exception(tdbb->tdbb_status_vector, ex);
SSHORT local_id = -1;
USHORT number;
// msg 121: "STORE RDB$RELATION_CONSTRAINTS failed"
// msg 124: "A column name is repeated in the definition of constraint: %s"
// msg 125: "Integrity constraint lookup failed"
// msg 127: "STORE RDB$REF_CONSTRAINTS failed"
switch (id) {
case drq_s_rel_con: number = 121; local_id = id; break;
case drq_s_ref_con: number = 127; local_id = id; break;
case drq_c_unq_nam: number = 121; break;
case drq_n_idx_seg: number = 124; break;
case drq_c_dup_con: number = 125; break;
default: number = 125; break;
}
DYN_rundown_request(request, local_id);
DYN_error_punt(true,
number,
number == 124 ? constraint_name.c_str() : NULL,
NULL,
NULL,
NULL,
NULL);
}
if (verb == isc_dyn_def_trigger)
{
do {
DYN_define_trigger(gbl, ptr, relation_name, &trigger_name, false);
DYN_UTIL_store_check_constraints(tdbb, gbl, constraint_name,
trigger_name);
} while ((verb = *(*ptr)++) == isc_dyn_def_trigger);
if (verb != isc_dyn_end) {
DYN_unsupported_verb();
}
return;
}
if (verb == isc_dyn_fld_not_null)
{
fb_assert(field_name);
DYN_UTIL_store_check_constraints(tdbb, gbl, constraint_name,
*field_name);
if (*(*ptr)++ != isc_dyn_end) {
DYN_unsupported_verb();
}
return;
}
try {
/* Make sure unique field names were specified for UNIQUE/PRIMARY/FOREIGN */
/* All fields must have the NOT NULL attribute specified for UNIQUE/PRIMARY. */
request = CMP_find_request(tdbb, drq_c_unq_nam, DYN_REQUESTS);
id = drq_c_unq_nam;
bool not_null = true;
all_count = unique_count = 0;
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
IDS IN RDB$INDEX_SEGMENTS
CROSS RFR IN RDB$RELATION_FIELDS
CROSS FLX IN RDB$FIELDS WITH
IDS.RDB$INDEX_NAME EQ index_name.c_str() AND
RFR.RDB$RELATION_NAME EQ relation_name->c_str() AND
RFR.RDB$FIELD_NAME EQ IDS.RDB$FIELD_NAME AND
FLX.RDB$FIELD_NAME EQ RFR.RDB$FIELD_SOURCE
REDUCED TO IDS.RDB$FIELD_NAME, IDS.RDB$INDEX_NAME,
FLX.RDB$NULL_FLAG
SORTED BY ASCENDING IDS.RDB$FIELD_NAME
if (!DYN_REQUEST(drq_c_unq_nam))
DYN_REQUEST(drq_c_unq_nam) = request;
if ((FLX.RDB$NULL_FLAG.NULL || !FLX.RDB$NULL_FLAG) &&
(RFR.RDB$NULL_FLAG.NULL || !RFR.RDB$NULL_FLAG) &&
primary_flag)
{
not_null = false;
null_field_name = RFR.RDB$FIELD_NAME;
EXE_unwind(tdbb, request);
break;
}
unique_count++;
field_list.add() = IDS.RDB$FIELD_NAME;
END_FOR;
if (!DYN_REQUEST(drq_c_unq_nam)) {
DYN_REQUEST(drq_c_unq_nam) = request;
}
if (!not_null) {
DYN_error_punt(false, 123, null_field_name.c_str(), NULL, NULL, NULL, NULL);
/* msg 123: "Field: %s not defined as NOT NULL - can't be used in PRIMARY KEY constraint definition" */
}
request = CMP_find_request(tdbb, drq_n_idx_seg, DYN_REQUESTS);
id = drq_n_idx_seg;
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
IDS IN RDB$INDEX_SEGMENTS WITH IDS.RDB$INDEX_NAME EQ index_name.c_str()
if (!DYN_REQUEST(drq_n_idx_seg)) {
DYN_REQUEST(drq_n_idx_seg) = request;
}
all_count++;
END_FOR;
if (!DYN_REQUEST(drq_n_idx_seg)) {
DYN_REQUEST(drq_n_idx_seg) = request;
}
if (unique_count != all_count) {
goto dyn_punt_false_124;
}
/* For PRIMARY KEY/UNIQUE constraints, make sure same set of columns
is not used in another constraint of either type */
if (!foreign_flag)
{
request = CMP_find_request(tdbb, drq_c_dup_con, DYN_REQUESTS);
id = drq_c_dup_con;
index_name = "";
list_index = -1;
bool found = false;
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
CRT IN RDB$RELATION_CONSTRAINTS CROSS
IDS IN RDB$INDEX_SEGMENTS OVER RDB$INDEX_NAME
WITH CRT.RDB$RELATION_NAME EQ relation_name->c_str() AND
(CRT.RDB$CONSTRAINT_TYPE EQ PRIMARY_KEY OR
CRT.RDB$CONSTRAINT_TYPE EQ UNIQUE_CNSTRT) AND
CRT.RDB$CONSTRAINT_NAME NE constraint_name.c_str()
SORTED BY CRT.RDB$INDEX_NAME, DESCENDING IDS.RDB$FIELD_NAME
if (!DYN_REQUEST(drq_c_dup_con))
DYN_REQUEST(drq_c_dup_con) = request;
if (index_name != CRT.RDB$INDEX_NAME)
{
if (list_index >= 0) {
found = false;
}
if (found) {
EXE_unwind(tdbb, request);
break;
}
list_index = field_list.getCount() - 1;
index_name = CRT.RDB$INDEX_NAME;
found = true;
}
if (list_index >= 0)
{
if (field_list[list_index--] != IDS.RDB$FIELD_NAME)
{
found = false;
}
}
else {
found = false;
}
END_FOR;
if (!DYN_REQUEST(drq_c_dup_con)) {
DYN_REQUEST(drq_c_dup_con) = request;
}
if (list_index >= 0) {
found = false;
}
if (found) {
goto dyn_punt_false_126;
}
}
else
{ /* Foreign key being defined */
request = CMP_find_request(tdbb, drq_s_ref_con, DYN_REQUESTS);
id = drq_s_ref_con;
jrd_req* old_request = NULL;
STORE(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
REF IN RDB$REF_CONSTRAINTS
old_request = request;
const SSHORT old_id = id;
request =
CMP_find_request(tdbb, drq_l_intg_con, DYN_REQUESTS);
id = drq_l_intg_con;
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
CRT IN RDB$RELATION_CONSTRAINTS WITH
CRT.RDB$INDEX_NAME EQ referred_index_name.c_str() AND
(CRT.RDB$CONSTRAINT_TYPE = PRIMARY_KEY OR
CRT.RDB$CONSTRAINT_TYPE = UNIQUE_CNSTRT)
if (!DYN_REQUEST(drq_l_intg_con))
DYN_REQUEST(drq_l_intg_con) = request;
fb_utils::exact_name_limit(CRT.RDB$CONSTRAINT_NAME,
sizeof(CRT.RDB$CONSTRAINT_NAME));
strcpy(REF.RDB$CONST_NAME_UQ, CRT.RDB$CONSTRAINT_NAME);
strcpy(REF.RDB$CONSTRAINT_NAME, constraint_name.c_str());
REF.RDB$UPDATE_RULE.NULL = FALSE;
if (ri_action & FOR_KEY_UPD_CASCADE)
strcpy(REF.RDB$UPDATE_RULE, RI_ACTION_CASCADE);
else if (ri_action & FOR_KEY_UPD_NULL)
strcpy(REF.RDB$UPDATE_RULE, RI_ACTION_NULL);
else if (ri_action & FOR_KEY_UPD_DEFAULT)
strcpy(REF.RDB$UPDATE_RULE, RI_ACTION_DEFAULT);
else if (ri_action & FOR_KEY_UPD_NONE)
strcpy(REF.RDB$UPDATE_RULE, RI_ACTION_NONE);
else
/* RESTRICT is the default value for this column */
strcpy(REF.RDB$UPDATE_RULE, RI_RESTRICT);
REF.RDB$DELETE_RULE.NULL = FALSE;
if (ri_action & FOR_KEY_DEL_CASCADE)
strcpy(REF.RDB$DELETE_RULE, RI_ACTION_CASCADE);
else if (ri_action & FOR_KEY_DEL_NULL)
strcpy(REF.RDB$DELETE_RULE, RI_ACTION_NULL);
else if (ri_action & FOR_KEY_DEL_DEFAULT)
strcpy(REF.RDB$DELETE_RULE, RI_ACTION_DEFAULT);
else if (ri_action & FOR_KEY_DEL_NONE)
strcpy(REF.RDB$DELETE_RULE, RI_ACTION_NONE);
else
/* RESTRICT is the default value for this column */
strcpy(REF.RDB$DELETE_RULE, RI_RESTRICT);
END_FOR;
if (!DYN_REQUEST(drq_l_intg_con))
DYN_REQUEST(drq_l_intg_con) = request;
request = old_request;
id = old_id;
END_STORE;
if (!DYN_REQUEST(drq_s_ref_con))
DYN_REQUEST(drq_s_ref_con) = request;
}
} // try
catch (const std::exception& ex) {
Firebird::stuff_exception(tdbb->tdbb_status_vector, ex);
SSHORT local_id = -1;
USHORT number;
// msg 121: "STORE RDB$RELATION_CONSTRAINTS failed"
// msg 124: "A column name is repeated in the definition of constraint: %s"
// msg 125: "Integrity constraint lookup failed"
// msg 127: "STORE RDB$REF_CONSTRAINTS failed"
switch (id) {
case drq_s_rel_con: number = 121; local_id = id; break;
case drq_s_ref_con: number = 127; local_id = id; break;
case drq_c_unq_nam: number = 121; break;
case drq_n_idx_seg: number = 124; break;
case drq_c_dup_con: number = 125; break;
default: number = 125; break;
}
DYN_rundown_request(request, local_id);
DYN_error_punt(true,
number,
number == 124 ? constraint_name.c_str() : NULL,
NULL,
NULL,
NULL,
NULL);
}
return;
dyn_punt_false_124:
DYN_error_punt(false, 124, constraint_name.c_str(), NULL, NULL, NULL, NULL);
/* msg 124: "A column name is repeated in the definition of constraint: %s" */
return;
dyn_punt_false_126:
DYN_error_punt(false, 126, NULL, NULL, NULL, NULL, NULL);
/* msg 126: "Same set of columns cannot be used in more than one PRIMARY KEY and/or UNIQUE constraint definition" */
}
void DYN_define_dimension(Global* gbl,
const UCHAR** ptr,
const Firebird::MetaName* relation_name,
Firebird::MetaName* field_name)
{
/**************************************
*
* D Y N _ d e f i n e _ d i m e n s i o n
*
**************************************
*
* Functional description
* Execute a dynamic ddl statement that
* defines a single dimension for a field.
*
**************************************/
thread_db* tdbb = JRD_get_thread_data();
Database* dbb = tdbb->tdbb_database;
jrd_req* request = CMP_find_request(tdbb, drq_s_dims, DYN_REQUESTS);
bool b_ending_store = false;
try {
STORE(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
DIM IN RDB$FIELD_DIMENSIONS
DIM.RDB$UPPER_BOUND.NULL = TRUE;
DIM.RDB$LOWER_BOUND.NULL = TRUE;
DIM.RDB$DIMENSION = (SSHORT)DYN_get_number(ptr);
if (field_name) {
strcpy(DIM.RDB$FIELD_NAME, field_name->c_str());
}
UCHAR verb;
while ((verb = *(*ptr)++) != isc_dyn_end)
{
switch (verb)
{
case isc_dyn_fld_name:
GET_STRING(ptr, DIM.RDB$FIELD_NAME);
break;
case isc_dyn_dim_upper:
DIM.RDB$UPPER_BOUND = DYN_get_number(ptr);
DIM.RDB$UPPER_BOUND.NULL = FALSE;
break;
case isc_dyn_dim_lower:
DIM.RDB$LOWER_BOUND = DYN_get_number(ptr);
DIM.RDB$LOWER_BOUND.NULL = FALSE;
break;
default:
--(*ptr);
DYN_execute(gbl, ptr, relation_name, field_name,
NULL, NULL, NULL);
}
}
b_ending_store = true;
END_STORE;
}
catch (const std::exception& ex) {
Firebird::stuff_exception(tdbb->tdbb_status_vector, ex);
if (b_ending_store) {
DYN_rundown_request(request, drq_s_dims);
DYN_error_punt(true, 3, NULL, NULL, NULL, NULL, NULL);
/* msg 3: "STORE RDB$FIELD_DIMENSIONS failed" */
}
throw;
}
if (!DYN_REQUEST(drq_s_dims)) {
DYN_REQUEST(drq_s_dims) = request;
}
}
void DYN_define_exception( Global* gbl, const UCHAR** ptr)
{
/**************************************
*
* D Y N _ d e f i n e _ e x c e p t i o n
*
**************************************
*
* Functional description
* Define an exception.
*
**************************************/
Firebird::MetaName exception_name;
thread_db* tdbb = JRD_get_thread_data();
Database* dbb = tdbb->tdbb_database;
GET_STRING(ptr, exception_name);
if (exception_name.length() == 0) {
DYN_error_punt(false, 212, NULL, NULL, NULL, NULL, NULL);
/* msg 212: "Zero length identifiers not allowed" */
}
jrd_req* request = CMP_find_request(tdbb, drq_s_xcp, DYN_REQUESTS);
bool b_ending_store = false;
try {
STORE(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
X IN RDB$EXCEPTIONS
strcpy(X.RDB$EXCEPTION_NAME, exception_name.c_str());
X.RDB$MESSAGE.NULL = TRUE;
UCHAR verb;
while ((verb = *(*ptr)++) != isc_dyn_end)
{
switch (verb)
{
case isc_dyn_xcp_msg:
GET_STRING_2(ptr, X.RDB$MESSAGE);
X.RDB$MESSAGE.NULL = FALSE;
break;
default:
DYN_unsupported_verb();
}
}
b_ending_store = true;
END_STORE;
if (!DYN_REQUEST(drq_s_xcp)) {
DYN_REQUEST(drq_s_xcp) = request;
}
}
catch (const std::exception& ex) {
Firebird::stuff_exception(tdbb->tdbb_status_vector, ex);
if (b_ending_store) {
DYN_rundown_request(request, drq_s_trg_msgs);
DYN_error_punt(true, 142, NULL, NULL, NULL, NULL, NULL);
/* msg 142: "DEFINE EXCEPTION failed" */
}
throw;
}
}
void DYN_define_file(Global* gbl,
const UCHAR** ptr,
SLONG shadow_number,
SLONG* start,
USHORT msg)
{
/**************************************
*
* D Y N _ d e f i n e _ f i l e
*
**************************************
*
* Functional description
* Define a database or shadow file.
*
**************************************/
UCHAR verb;
SLONG temp;
USHORT man_auto;
SSHORT id;
thread_db* tdbb = JRD_get_thread_data();
Database* dbb = tdbb->tdbb_database;
jrd_req* request = NULL;
try {
id = -1;
request = CMP_find_request(tdbb, id = drq_l_files, DYN_REQUESTS);
Firebird::PathName temp_f;
GET_STRING(ptr, temp_f);
ISC_expand_filename(temp_f, false);
if (dbb->dbb_filename == temp_f) {
DYN_error_punt(false, 166, NULL, NULL, NULL, NULL, NULL);
}
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
FIRST 1 X IN RDB$FILES WITH X.RDB$FILE_NAME EQ temp_f.c_str()
DYN_error_punt(false, 166, NULL, NULL, NULL, NULL, NULL);
END_FOR;
request = CMP_find_request(tdbb, id = drq_s_files, DYN_REQUESTS);
STORE(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
X IN RDB$FILES
temp_f.copyTo(X.RDB$FILE_NAME, sizeof(X.RDB$FILE_NAME));
X.RDB$SHADOW_NUMBER = (SSHORT)shadow_number;
X.RDB$FILE_FLAGS = 0;
X.RDB$FILE_FLAGS.NULL = FALSE;
X.RDB$FILE_START.NULL = TRUE;
X.RDB$FILE_LENGTH.NULL = TRUE;
while ((verb = *(*ptr)++) != isc_dyn_end)
{
switch (verb)
{
case isc_dyn_file_start:
temp = DYN_get_number(ptr);
*start = MAX(*start, temp);
X.RDB$FILE_START = *start;
X.RDB$FILE_START.NULL = FALSE;
break;
case isc_dyn_file_length:
X.RDB$FILE_LENGTH = DYN_get_number(ptr);
X.RDB$FILE_LENGTH.NULL = FALSE;
break;
case isc_dyn_shadow_man_auto:
man_auto = (USHORT)DYN_get_number(ptr);
if (man_auto)
X.RDB$FILE_FLAGS |= FILE_manual;
break;
case isc_dyn_shadow_conditional:
if (DYN_get_number(ptr))
X.RDB$FILE_FLAGS |= FILE_conditional;
break;
default:
DYN_unsupported_verb();
}
}
*start += X.RDB$FILE_LENGTH;
END_STORE;
if (!DYN_REQUEST(drq_s_files))
{
DYN_REQUEST(drq_s_files) = request;
}
}
catch (const std::exception& ex) {
Firebird::stuff_exception(tdbb->tdbb_status_vector, ex);
if (id == drq_l_files)
{
DYN_rundown_request(request, drq_l_files);
DYN_error_punt(false, 166, NULL, NULL, NULL, NULL, NULL);
}
else
{
DYN_rundown_request(request, drq_s_files);
DYN_error_punt(true, msg, NULL, NULL, NULL, NULL, NULL);
}
}
}
void DYN_define_difference(Global* gbl,
const UCHAR** ptr)
{
/**************************************
*
* D Y N _ d e f i n e _ d i f f e r e n c e
*
**************************************
*
* Functional description
* Define backup difference file.
*
**************************************/
SSHORT id = -1;
thread_db* tdbb = JRD_get_thread_data();
Database* dbb = tdbb->tdbb_database;
jrd_req* request = NULL;
try {
bool found = false;
id = drq_l_difference;
request = CMP_find_request(tdbb, drq_l_difference, DYN_REQUESTS);
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
FIL IN RDB$FILES
if (FIL.RDB$FILE_FLAGS & FILE_difference)
found = true;
END_FOR;
if (!DYN_REQUEST(drq_l_difference)) {
DYN_REQUEST(drq_l_difference) = request;
}
if (found) {
goto dyn_punt_216;
}
request = CMP_find_request(tdbb, drq_s_difference, DYN_REQUESTS);
id = drq_s_difference;
STORE(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
X IN RDB$FILES
GET_STRING(ptr, X.RDB$FILE_NAME);
X.RDB$FILE_FLAGS = FILE_difference;
X.RDB$FILE_FLAGS.NULL = FALSE;
X.RDB$FILE_START = 0;
X.RDB$FILE_START.NULL = FALSE;
X.RDB$FILE_LENGTH.NULL = TRUE;
X.RDB$SHADOW_NUMBER.NULL = TRUE;
END_STORE;
if (!DYN_REQUEST(drq_s_difference))
{
DYN_REQUEST(drq_s_difference) = request;
}
}
catch (const std::exception& ex) {
Firebird::stuff_exception(tdbb->tdbb_status_vector, ex);
if (id == drq_s_difference)
{
DYN_rundown_request(request, drq_s_difference);
DYN_error_punt(true, 150, NULL, NULL, NULL, NULL, NULL);
/* msg 150: STORE RDB$FILES failed */
}
else
{
DYN_rundown_request(request, drq_l_difference);
DYN_error_punt(true, 156, NULL, NULL, NULL, NULL, NULL);
/* msg 156: Difference file lookup failed */
}
}
return;
dyn_punt_216:
DYN_error_punt(false, 216, NULL, NULL, NULL, NULL, NULL);
/* msg 216: "Difference file is already defined" */
}
void DYN_define_filter( Global* gbl, const UCHAR** ptr)
{
/**************************************
*
* D Y N _ d e f i n e _ f i l t e r
*
**************************************
*
* Functional description
* Define a blob filter.
*
**************************************/
thread_db* tdbb = JRD_get_thread_data();
Database* dbb = tdbb->tdbb_database;
Firebird::MetaName filter_name;
GET_STRING(ptr, filter_name);
if (filter_name.length() == 0) {
DYN_error_punt(false, 212, NULL, NULL, NULL, NULL, NULL);
/* msg 212: "Zero length identifiers not allowed" */
}
jrd_req* request = CMP_find_request(tdbb, drq_s_filters, DYN_REQUESTS);
bool b_ending_store = false;
try {
STORE(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
X IN RDB$FILTERS USING
strcpy(X.RDB$FUNCTION_NAME, filter_name.c_str());
X.RDB$OUTPUT_SUB_TYPE.NULL = TRUE;
X.RDB$INPUT_SUB_TYPE.NULL = TRUE;
X.RDB$MODULE_NAME.NULL = TRUE;
X.RDB$ENTRYPOINT.NULL = TRUE;
X.RDB$DESCRIPTION.NULL = TRUE;
UCHAR verb;
while ((verb = *(*ptr)++) != isc_dyn_end)
{
switch (verb)
{
case isc_dyn_filter_in_subtype:
X.RDB$INPUT_SUB_TYPE = (SSHORT)DYN_get_number(ptr);
X.RDB$INPUT_SUB_TYPE.NULL = FALSE;
break;
case isc_dyn_filter_out_subtype:
X.RDB$OUTPUT_SUB_TYPE = (SSHORT)DYN_get_number(ptr);
X.RDB$OUTPUT_SUB_TYPE.NULL = FALSE;
break;
case isc_dyn_func_module_name:
GET_STRING(ptr, X.RDB$MODULE_NAME);
X.RDB$MODULE_NAME.NULL = FALSE;
break;
case isc_dyn_func_entry_point:
GET_STRING(ptr, X.RDB$ENTRYPOINT);
X.RDB$ENTRYPOINT.NULL = FALSE;
break;
case isc_dyn_description:
DYN_put_text_blob(gbl, ptr, &X.RDB$DESCRIPTION);
X.RDB$DESCRIPTION.NULL = FALSE;
break;
default:
DYN_unsupported_verb();
}
}
END_STORE;
if (!DYN_REQUEST(drq_s_filters)) {
DYN_REQUEST(drq_s_filters) = request;
}
}
catch (const std::exception& ex) {
Firebird::stuff_exception(tdbb->tdbb_status_vector, ex);
if (b_ending_store) {
DYN_rundown_request(request, drq_s_filters);
DYN_error_punt(true, 7, NULL, NULL, NULL, NULL, NULL);
/* msg 7: "DEFINE BLOB FILTER failed" */
}
throw;
}
}
void DYN_define_function( Global* gbl, const UCHAR** ptr)
{
/**************************************
*
* D Y N _ d e f i n e _ f u n c t i o n
*
**************************************
*
* Functional description
* Define a user defined function.
*
**************************************/
thread_db* tdbb = JRD_get_thread_data();
Database* dbb = tdbb->tdbb_database;
Firebird::MetaName function_name;
GET_STRING(ptr, function_name);
if (function_name.length() == 0)
DYN_error_punt(false, 212, NULL, NULL, NULL, NULL, NULL);
/* msg 212: "Zero length identifiers not allowed" */
jrd_req* request = CMP_find_request(tdbb, drq_s_funcs, DYN_REQUESTS);
bool b_ending_store = false;
try {
STORE(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
X IN RDB$FUNCTIONS USING
strcpy(X.RDB$FUNCTION_NAME, function_name.c_str());
X.RDB$RETURN_ARGUMENT.NULL = TRUE;
X.RDB$QUERY_NAME.NULL = TRUE;
X.RDB$MODULE_NAME.NULL = TRUE;
X.RDB$ENTRYPOINT.NULL = TRUE;
X.RDB$DESCRIPTION.NULL = TRUE;
UCHAR verb;
while ((verb = *(*ptr)++) != isc_dyn_end)
{
switch (verb)
{
case isc_dyn_func_return_argument:
X.RDB$RETURN_ARGUMENT = (SSHORT)DYN_get_number(ptr);
X.RDB$RETURN_ARGUMENT.NULL = FALSE;
if (X.RDB$RETURN_ARGUMENT > MAX_UDF_ARGUMENTS)
DYN_error_punt(true, 10, NULL, NULL, NULL, NULL, NULL);
/* msg 10: "DEFINE FUNCTION failed" */
break;
case isc_dyn_func_module_name:
GET_STRING(ptr, X.RDB$MODULE_NAME);
X.RDB$MODULE_NAME.NULL = FALSE;
break;
case isc_dyn_fld_query_name:
GET_STRING(ptr, X.RDB$QUERY_NAME);
X.RDB$QUERY_NAME.NULL = FALSE;
break;
case isc_dyn_func_entry_point:
GET_STRING(ptr, X.RDB$ENTRYPOINT);
X.RDB$ENTRYPOINT.NULL = FALSE;
break;
case isc_dyn_description:
DYN_put_text_blob(gbl, ptr, &X.RDB$DESCRIPTION);
X.RDB$DESCRIPTION.NULL = FALSE;
break;
default:
--(*ptr);
MetaTmp(X.RDB$FUNCTION_NAME)
DYN_execute(gbl, ptr, NULL, NULL, NULL, &tmp, NULL);
}
}
b_ending_store = true;
END_STORE;
if (!DYN_REQUEST(drq_s_funcs)) {
DYN_REQUEST(drq_s_funcs) = request;
}
}
catch (const std::exception& ex) {
Firebird::stuff_exception(tdbb->tdbb_status_vector, ex);
if (b_ending_store) {
DYN_rundown_request(request, drq_s_funcs);
DYN_error_punt(true, 10, NULL, NULL, NULL, NULL, NULL);
/* msg 10: "DEFINE FUNCTION failed" */
}
throw;
}
}
void DYN_define_function_arg(Global* gbl, const UCHAR** ptr, Firebird::MetaName* function_name)
{
/**************************************
*
* D Y N _ d e f i n e _ f u n c t i o n _ a r g
*
**************************************
*
* Functional description
* Define a user defined function argument.
*
**************************************/
jrd_req* request = NULL;
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;
try {
request = CMP_find_request(tdbb, drq_s_func_args, DYN_REQUESTS);
STORE(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
X IN RDB$FUNCTION_ARGUMENTS
X.RDB$ARGUMENT_POSITION = (SSHORT)DYN_get_number(ptr);
if (X.RDB$ARGUMENT_POSITION > MAX_UDF_ARGUMENTS)
DYN_error_punt(true, 12, NULL, NULL, NULL, NULL, NULL);
/* msg 12: "DEFINE FUNCTION ARGUMENT failed" */
if (function_name) {
strcpy(X.RDB$FUNCTION_NAME, function_name->c_str());
X.RDB$FUNCTION_NAME.NULL = FALSE;
}
else
X.RDB$FUNCTION_NAME.NULL = TRUE;
X.RDB$MECHANISM.NULL = TRUE;
X.RDB$FIELD_TYPE.NULL = TRUE;
X.RDB$FIELD_SCALE.NULL = TRUE;
X.RDB$FIELD_LENGTH.NULL = TRUE;
X.RDB$FIELD_SUB_TYPE.NULL = TRUE;
X.RDB$CHARACTER_SET_ID.NULL = TRUE;
X.RDB$FIELD_PRECISION.NULL = TRUE;
UCHAR verb;
while ((verb = *(*ptr)++) != isc_dyn_end)
switch (verb)
{
case isc_dyn_function_name:
GET_STRING(ptr, X.RDB$FUNCTION_NAME);
X.RDB$FUNCTION_NAME.NULL = FALSE;
break;
case isc_dyn_func_mechanism:
X.RDB$MECHANISM = (SSHORT)DYN_get_number(ptr);
X.RDB$MECHANISM.NULL = FALSE;
break;
case isc_dyn_fld_type:
X.RDB$FIELD_TYPE = (SSHORT)DYN_get_number(ptr);
X.RDB$FIELD_TYPE.NULL = FALSE;
break;
case isc_dyn_fld_sub_type:
X.RDB$FIELD_SUB_TYPE = (SSHORT)DYN_get_number(ptr);
X.RDB$FIELD_SUB_TYPE.NULL = FALSE;
break;
case isc_dyn_fld_scale:
X.RDB$FIELD_SCALE = (SSHORT)DYN_get_number(ptr);
X.RDB$FIELD_SCALE.NULL = FALSE;
break;
case isc_dyn_fld_length:
X.RDB$FIELD_LENGTH = (SSHORT)DYN_get_number(ptr);
X.RDB$FIELD_LENGTH.NULL = FALSE;
break;
case isc_dyn_fld_character_set:
X.RDB$CHARACTER_SET_ID = (SSHORT)DYN_get_number(ptr);
X.RDB$CHARACTER_SET_ID.NULL = FALSE;
break;
case isc_dyn_fld_precision:
X.RDB$FIELD_PRECISION = (SSHORT)DYN_get_number(ptr);
X.RDB$FIELD_PRECISION.NULL = FALSE;
break;
/* Ignore the field character length as the system UDF parameter
* table has no place to store the information
* But IB6/FB has the place for this information. CVC 2001.
*/
case isc_dyn_fld_char_length:
if (ENCODE_ODS(major_version, minor_original) < ODS_10_0)
{
DYN_get_number(ptr);
}
else
{
X.RDB$CHARACTER_LENGTH = (SSHORT)DYN_get_number (ptr);
X.RDB$CHARACTER_LENGTH.NULL = FALSE;
}
break;
default:
DYN_unsupported_verb();
}
END_STORE;
if (!DYN_REQUEST(drq_s_func_args)) {
DYN_REQUEST(drq_s_func_args) = request;
}
}
catch (const std::exception& ex) {
Firebird::stuff_exception(tdbb->tdbb_status_vector, ex);
if (request) {
DYN_rundown_request(request, drq_s_func_args);
}
DYN_error_punt(true, 12, NULL, NULL, NULL, NULL, NULL);
/* msg 12: "DEFINE FUNCTION ARGUMENT failed" */
}
}
void DYN_define_generator( Global* gbl, const UCHAR** ptr)
{
/**************************************
*
* D Y N _ d e f i n e _ g e n e r a t o r
*
**************************************
*
* Functional description
* Define a generator.
*
**************************************/
thread_db* tdbb = JRD_get_thread_data();
Database* dbb = tdbb->tdbb_database;
Firebird::MetaName generator_name;
GET_STRING(ptr, generator_name);
if (generator_name.length() == 0) {
DYN_error_punt(false, 212, NULL, NULL, NULL, NULL, NULL);
/* msg 212: "Zero length identifiers not allowed" */
}
jrd_req* request = CMP_find_request(tdbb, drq_s_gens, DYN_REQUESTS);
bool b_ending_store = false;
try {
STORE(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
X IN RDB$GENERATORS
strcpy(X.RDB$GENERATOR_NAME, generator_name.c_str());
b_ending_store = true;
END_STORE;
if (!DYN_REQUEST(drq_s_gens)) {
DYN_REQUEST(drq_s_gens) = request;
}
}
catch (const std::exception& ex) {
Firebird::stuff_exception(tdbb->tdbb_status_vector, ex);
if (b_ending_store) {
DYN_rundown_request(request, drq_s_gens);
DYN_error_punt(true, 8, NULL, NULL, NULL, NULL, NULL);
/* msg 8: "DEFINE GENERATOR failed" */
}
throw;
}
if (*(*ptr)++ != isc_dyn_end)
{
DYN_error_punt(true, 9, NULL, NULL, NULL, NULL, NULL);
/* msg 9: "DEFINE GENERATOR unexpected dyn verb" */
}
}
void DYN_define_global_field(Global* gbl,
const UCHAR** ptr,
const Firebird::MetaName* relation_name,
Firebird::MetaName* field_name)
{
/**************************************
*
* D Y N _ d e f i n e _ g l o b a l _ f i e l d
*
**************************************
*
* Functional description
* Execute a dynamic ddl statement.
*
**************************************/
thread_db* tdbb = JRD_get_thread_data();
Database* dbb = tdbb->tdbb_database;
UCHAR verb;
Firebird::MetaName global_field_name;
USHORT dtype;
GET_STRING(ptr, global_field_name);
if (global_field_name.length() == 0)
{
DYN_UTIL_generate_field_name(tdbb, gbl, global_field_name);
}
if (global_field_name.length() == 0)
{
DYN_error_punt(false, 212, NULL, NULL, NULL, NULL, NULL);
/* msg 212: "Zero length identifiers not allowed" */
}
jrd_req* request = CMP_find_request(tdbb, drq_s_gfields, DYN_REQUESTS);
bool b_ending_store = false;
try {
STORE(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
FLD IN RDB$FIELDS USING
strcpy(FLD.RDB$FIELD_NAME, global_field_name.c_str());
FLD.RDB$SYSTEM_FLAG.NULL = TRUE;
FLD.RDB$FIELD_SCALE.NULL = TRUE;
FLD.RDB$FIELD_SUB_TYPE.NULL = TRUE;
FLD.RDB$SEGMENT_LENGTH.NULL = TRUE;
FLD.RDB$QUERY_NAME.NULL = TRUE;
FLD.RDB$QUERY_HEADER.NULL = TRUE;
FLD.RDB$EDIT_STRING.NULL = TRUE;
FLD.RDB$MISSING_VALUE.NULL = TRUE;
FLD.RDB$COMPUTED_BLR.NULL = TRUE;
FLD.RDB$COMPUTED_SOURCE.NULL = TRUE;
FLD.RDB$DEFAULT_VALUE.NULL = TRUE;
FLD.RDB$DEFAULT_SOURCE.NULL = TRUE;
FLD.RDB$VALIDATION_BLR.NULL = TRUE;
FLD.RDB$VALIDATION_SOURCE.NULL = TRUE;
FLD.RDB$DESCRIPTION.NULL = TRUE;
FLD.RDB$DIMENSIONS.NULL = TRUE;
FLD.RDB$CHARACTER_LENGTH.NULL = TRUE;
FLD.RDB$NULL_FLAG.NULL = TRUE;
FLD.RDB$CHARACTER_SET_ID.NULL = TRUE;
FLD.RDB$COLLATION_ID.NULL = TRUE;
FLD.RDB$FIELD_PRECISION.NULL = TRUE;
while ((verb = *(*ptr)++) != isc_dyn_end)
{
switch (verb)
{
case isc_dyn_system_flag:
FLD.RDB$SYSTEM_FLAG = (SSHORT)DYN_get_number(ptr);
FLD.RDB$SYSTEM_FLAG.NULL = FALSE;
break;
case isc_dyn_fld_length:
FLD.RDB$FIELD_LENGTH = (SSHORT)DYN_get_number(ptr);
FLD.RDB$FIELD_LENGTH.NULL = FALSE;
break;
case isc_dyn_fld_type:
dtype = (USHORT)DYN_get_number(ptr);
FLD.RDB$FIELD_TYPE = (SSHORT)dtype;
switch (dtype)
{
case blr_short:
FLD.RDB$FIELD_LENGTH = 2;
FLD.RDB$FIELD_LENGTH.NULL = FALSE;
break;
case blr_long:
case blr_float:
case blr_sql_time:
case blr_sql_date:
FLD.RDB$FIELD_LENGTH = 4;
FLD.RDB$FIELD_LENGTH.NULL = FALSE;
break;
case blr_int64:
case blr_quad:
case blr_timestamp:
case blr_double:
case blr_d_float:
case blr_blob:
FLD.RDB$FIELD_LENGTH = 8;
FLD.RDB$FIELD_LENGTH.NULL = FALSE;
break;
default:
break;
}
break;
case isc_dyn_fld_scale:
FLD.RDB$FIELD_SCALE = (SSHORT)DYN_get_number(ptr);
FLD.RDB$FIELD_SCALE.NULL = FALSE;
break;
case isc_dyn_fld_precision:
FLD.RDB$FIELD_PRECISION = (SSHORT)DYN_get_number(ptr);
FLD.RDB$FIELD_PRECISION.NULL = FALSE;
break;
case isc_dyn_fld_sub_type:
FLD.RDB$FIELD_SUB_TYPE = (SSHORT)DYN_get_number(ptr);
FLD.RDB$FIELD_SUB_TYPE.NULL = FALSE;
break;
case isc_dyn_fld_char_length:
FLD.RDB$CHARACTER_LENGTH = (SSHORT)DYN_get_number(ptr);
FLD.RDB$CHARACTER_LENGTH.NULL = FALSE;
break;
case isc_dyn_fld_character_set:
FLD.RDB$CHARACTER_SET_ID = (SSHORT)DYN_get_number(ptr);
FLD.RDB$CHARACTER_SET_ID.NULL = FALSE;
break;
case isc_dyn_fld_collation:
FLD.RDB$COLLATION_ID = (SSHORT)DYN_get_number(ptr);
FLD.RDB$COLLATION_ID.NULL = FALSE;
break;
case isc_dyn_fld_segment_length:
FLD.RDB$SEGMENT_LENGTH = (SSHORT)DYN_get_number(ptr);
FLD.RDB$SEGMENT_LENGTH.NULL = FALSE;
break;
case isc_dyn_fld_query_name:
GET_STRING(ptr, FLD.RDB$QUERY_NAME);
FLD.RDB$QUERY_NAME.NULL = FALSE;
break;
case isc_dyn_fld_query_header:
DYN_put_blr_blob(gbl, ptr, &FLD.RDB$QUERY_HEADER);
FLD.RDB$QUERY_HEADER.NULL = FALSE;
break;
case isc_dyn_fld_not_null:
FLD.RDB$NULL_FLAG.NULL = FALSE;
FLD.RDB$NULL_FLAG = TRUE;
break;
case isc_dyn_fld_missing_value:
DYN_put_blr_blob(gbl, ptr, &FLD.RDB$MISSING_VALUE);
FLD.RDB$MISSING_VALUE.NULL = FALSE;
break;
case isc_dyn_fld_computed_blr:
DYN_put_blr_blob(gbl, ptr, &FLD.RDB$COMPUTED_BLR);
FLD.RDB$COMPUTED_BLR.NULL = FALSE;
break;
case isc_dyn_fld_computed_source:
DYN_put_text_blob(gbl, ptr, &FLD.RDB$COMPUTED_SOURCE);
FLD.RDB$COMPUTED_SOURCE.NULL = FALSE;
break;
case isc_dyn_fld_default_value:
FLD.RDB$DEFAULT_VALUE.NULL = FALSE;
DYN_put_blr_blob(gbl, ptr, &FLD.RDB$DEFAULT_VALUE);
break;
case isc_dyn_fld_default_source:
FLD.RDB$DEFAULT_SOURCE.NULL = FALSE;
DYN_put_text_blob(gbl, ptr, &FLD.RDB$DEFAULT_SOURCE);
break;
case isc_dyn_fld_validation_blr:
DYN_put_blr_blob(gbl, ptr, &FLD.RDB$VALIDATION_BLR);
FLD.RDB$VALIDATION_BLR.NULL = FALSE;
break;
case isc_dyn_fld_validation_source:
DYN_put_text_blob(gbl, ptr, &FLD.RDB$VALIDATION_SOURCE);
FLD.RDB$VALIDATION_SOURCE.NULL = FALSE;
break;
case isc_dyn_fld_edit_string:
GET_STRING(ptr, FLD.RDB$EDIT_STRING);
FLD.RDB$EDIT_STRING.NULL = FALSE;
break;
case isc_dyn_description:
DYN_put_text_blob(gbl, ptr, &FLD.RDB$DESCRIPTION);
FLD.RDB$DESCRIPTION.NULL = FALSE;
break;
case isc_dyn_fld_dimensions:
FLD.RDB$DIMENSIONS = (SSHORT)DYN_get_number(ptr);
FLD.RDB$DIMENSIONS.NULL = FALSE;
break;
default:
--(*ptr);
MetaTmp(FLD.RDB$FIELD_NAME)
DYN_execute(gbl, ptr, relation_name,
field_name ? field_name : &tmp,
NULL, NULL, NULL);
}
}
b_ending_store = true;
END_STORE;
if (!DYN_REQUEST(drq_s_gfields)) {
DYN_REQUEST(drq_s_gfields) = request;
}
}
catch (const std::exception& ex) {
Firebird::stuff_exception(tdbb->tdbb_status_vector, ex);
if (b_ending_store) {
DYN_rundown_request(request, drq_s_gfields);
DYN_error_punt(true, 13, NULL, NULL, NULL, NULL, NULL);
/* msg 13: "STORE RDB$FIELDS failed" */
}
throw;
}
}
void DYN_define_index(Global* gbl,
const UCHAR** ptr,
const Firebird::MetaName* relation_name,
UCHAR index_type,
Firebird::MetaName* new_index_name,
Firebird::MetaName* referred_index_name,
Firebird::MetaName* cnst_name,
UCHAR* ri_actionP)
{
/**************************************
*
* D Y N _ d e f i n e _ i n d e x
*
**************************************
*
* Functional description
* Execute a dynamic ddl statement that
* creates an index.
*
**************************************/
Firebird::MetaName index_name;
Firebird::MetaName referenced_relation;
UCHAR verb;
UCHAR fld_count, seg_count;
MetaNameArray field_list, seg_list;
int list_index = -1;
USHORT key_length, length, referred_cols = 0;
Firebird::MetaName trigger_name;
if (ri_actionP != NULL) {
(*ri_actionP) = 0;
}
thread_db* tdbb = JRD_get_thread_data();
Database* dbb = tdbb->tdbb_database;
GET_STRING(ptr, index_name);
if (index_name.length() == 0)
{
DYN_UTIL_generate_index_name(tdbb, gbl, index_name, index_type);
}
if (index_name.length() == 0) {
DYN_error_punt(false, 212, NULL, NULL, NULL, NULL, NULL);
/* msg 212: "Zero length identifiers not allowed" */
}
jrd_req* request = NULL;
SSHORT id = -1;
try {
request = CMP_find_request(tdbb, drq_s_indices, DYN_REQUESTS);
id = drq_s_indices;
key_length = 0;
jrd_req* old_request = NULL;
STORE(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
IDX IN RDB$INDICES
IDX.RDB$UNIQUE_FLAG.NULL = TRUE;
IDX.RDB$INDEX_INACTIVE.NULL = TRUE;
IDX.RDB$INDEX_TYPE.NULL = TRUE;
IDX.RDB$DESCRIPTION.NULL = TRUE;
IDX.RDB$FOREIGN_KEY.NULL = TRUE;
IDX.RDB$EXPRESSION_SOURCE.NULL = TRUE;
IDX.RDB$EXPRESSION_BLR.NULL = TRUE;
fld_count = seg_count = 0;
strcpy(IDX.RDB$INDEX_NAME, index_name.c_str());
if (new_index_name)
*new_index_name = IDX.RDB$INDEX_NAME;
if (relation_name)
strcpy(IDX.RDB$RELATION_NAME, relation_name->c_str());
else if (*(*ptr)++ == isc_dyn_rel_name)
GET_STRING(ptr, IDX.RDB$RELATION_NAME);
else
DYN_error_punt(false, 14, NULL, NULL, NULL, NULL, NULL);
/* msg 14: "No relation specified for index" */
IDX.RDB$RELATION_NAME.NULL = FALSE;
/* Check if the table is actually a view */
old_request = request;
SSHORT old_id = id;
request = CMP_find_request(tdbb, drq_l_view_idx, DYN_REQUESTS);
id = drq_l_view_idx;
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
VREL IN RDB$RELATIONS WITH VREL.RDB$RELATION_NAME EQ
IDX.RDB$RELATION_NAME
if (!VREL.RDB$VIEW_BLR.NULL)
DYN_error_punt(false, 181, NULL, NULL, NULL, NULL, NULL);
/* msg 181: "attempt to index a view" */
END_FOR;
if (!DYN_REQUEST(drq_l_view_idx))
DYN_REQUEST(drq_l_view_idx) = request;
request = old_request;
id = old_id;
/* The previous 2 lines and the next two lines can
* deleted as long as no code is added in the middle.
*/
old_request = request;
old_id = id;
request = CMP_find_request(tdbb, drq_l_lfield, DYN_REQUESTS);
id = drq_l_lfield;
while ((verb = *(*ptr)++) != isc_dyn_end)
switch (verb)
{
case isc_dyn_idx_unique:
IDX.RDB$UNIQUE_FLAG = (SSHORT)DYN_get_number(ptr);
IDX.RDB$UNIQUE_FLAG.NULL = FALSE;
break;
case isc_dyn_idx_inactive:
IDX.RDB$INDEX_INACTIVE = (SSHORT)DYN_get_number(ptr);
IDX.RDB$INDEX_INACTIVE.NULL = FALSE;
break;
case isc_dyn_idx_type:
IDX.RDB$INDEX_TYPE = (SSHORT)DYN_get_number(ptr);
IDX.RDB$INDEX_TYPE.NULL = FALSE;
break;
case isc_dyn_fld_name:
{
Firebird::MetaName& str = seg_list.add();
GET_STRING(ptr, str);
seg_count++;
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
F IN RDB$RELATION_FIELDS CROSS GF IN RDB$FIELDS
WITH GF.RDB$FIELD_NAME EQ F.RDB$FIELD_SOURCE AND
F.RDB$FIELD_NAME EQ str.c_str() AND
IDX.RDB$RELATION_NAME EQ F.RDB$RELATION_NAME
if (!DYN_REQUEST(drq_l_lfield))
{
DYN_REQUEST(drq_l_lfield) = request;
}
fld_count++;
if (GF.RDB$FIELD_TYPE == blr_blob)
{
DYN_error_punt(false, 116, IDX.RDB$INDEX_NAME, NULL,
NULL, NULL, NULL);
/* msg 116 "attempt to index blob field in index %s" */
}
else if (!GF.RDB$DIMENSIONS.NULL)
{
DYN_error_punt(false, 117, IDX.RDB$INDEX_NAME, NULL,
NULL, NULL, NULL);
/* msg 117 "attempt to index array field in index %s" */
}
else if (!GF.RDB$COMPUTED_BLR.NULL)
{
DYN_error_punt(false, 179, IDX.RDB$INDEX_NAME, NULL,
NULL, NULL, NULL);
/* msg 179 "attempt to index COMPUTED BY field in index %s" */
}
else if (GF.RDB$FIELD_TYPE == blr_varying ||
GF.RDB$FIELD_TYPE == blr_text)
{
/* Compute the length of the key segment allowing
for international information. Note that we
must convert a <character set, collation> type
to an index type in order to compute the length */
if (!F.RDB$COLLATION_ID.NULL)
{
length =
INTL_key_length(tdbb,
INTL_TEXT_TO_INDEX(
INTL_CS_COLL_TO_TTYPE(GF.RDB$CHARACTER_SET_ID,
F.RDB$COLLATION_ID)),
GF.RDB$FIELD_LENGTH);
}
else if (!GF.RDB$COLLATION_ID.NULL)
{
length =
INTL_key_length(tdbb,
INTL_TEXT_TO_INDEX(
INTL_CS_COLL_TO_TTYPE(GF.RDB$CHARACTER_SET_ID,
GF.RDB$COLLATION_ID)),
GF.RDB$FIELD_LENGTH);
}
else
{
length = GF.RDB$FIELD_LENGTH;
}
}
else
{
length = sizeof(double);
}
if (key_length)
{
key_length += ((length + STUFF_COUNT - 1) /
(unsigned) STUFF_COUNT) *
(STUFF_COUNT + 1);
}
else
{
key_length = length;
}
END_FOR;
if (!DYN_REQUEST(drq_l_lfield))
DYN_REQUEST(drq_l_lfield) = request;
break;
}
#ifdef EXPRESSION_INDICES
/* for expression indices, store the BLR and the source string */
case isc_dyn_fld_computed_blr:
DYN_put_blr_blob(gbl, ptr, &IDX.RDB$EXPRESSION_BLR);
IDX.RDB$EXPRESSION_BLR.NULL = FALSE;
break;
case isc_dyn_fld_computed_source:
DYN_put_text_blob(gbl, ptr, &IDX.RDB$EXPRESSION_SOURCE);
IDX.RDB$EXPRESSION_SOURCE.NULL = FALSE;
break;
#endif
/* for foreign keys, point to the corresponding relation */
case isc_dyn_idx_foreign_key:
GET_STRING(ptr, referenced_relation);
if (referenced_relation.length() == 0) {
DYN_error_punt(false, 212, NULL, NULL, NULL, NULL, NULL);
/* msg 212: "Zero length identifiers not allowed" */
}
break;
case isc_dyn_idx_ref_column:
{
Firebird::MetaName& str2 = field_list.add();
GET_STRING(ptr, str2);
referred_cols++;
}
break;
case isc_dyn_description:
DYN_put_text_blob(gbl, ptr, &IDX.RDB$DESCRIPTION);
IDX.RDB$DESCRIPTION.NULL = FALSE;
break;
case isc_dyn_foreign_key_delete:
fb_assert(ri_actionP != NULL);
switch (verb = *(*ptr)++)
{
case isc_dyn_foreign_key_cascade:
(*ri_actionP) |= FOR_KEY_DEL_CASCADE;
if ((verb = *(*ptr)++) == isc_dyn_def_trigger)
{
DYN_define_trigger(gbl, ptr, relation_name,
&trigger_name, true);
fb_assert(cnst_name);
DYN_UTIL_store_check_constraints(tdbb, gbl, *cnst_name,
trigger_name);
}
else
DYN_unsupported_verb();
break;
case isc_dyn_foreign_key_null:
(*ri_actionP) |= FOR_KEY_DEL_NULL;
if ((verb = *(*ptr)++) == isc_dyn_def_trigger)
{
DYN_define_trigger(gbl, ptr, relation_name,
&trigger_name, true);
fb_assert(cnst_name);
DYN_UTIL_store_check_constraints(tdbb, gbl, *cnst_name,
trigger_name);
}
else
DYN_unsupported_verb();
break;
case isc_dyn_foreign_key_default:
(*ri_actionP) |= FOR_KEY_DEL_DEFAULT;
if ((verb = *(*ptr)++) == isc_dyn_def_trigger)
{
DYN_define_trigger(gbl, ptr, relation_name,
&trigger_name, true);
fb_assert(cnst_name);
DYN_UTIL_store_check_constraints(tdbb, gbl, *cnst_name,
trigger_name);
}
else
DYN_unsupported_verb();
break;
case isc_dyn_foreign_key_none:
(*ri_actionP) |= FOR_KEY_DEL_NONE;
break;
default:
fb_assert(0); /* should not come here */
DYN_unsupported_verb();
}
break;
case isc_dyn_foreign_key_update:
fb_assert(ri_actionP != NULL);
switch (verb = *(*ptr)++)
{
case isc_dyn_foreign_key_cascade:
(*ri_actionP) |= FOR_KEY_UPD_CASCADE;
if ((verb = *(*ptr)++) == isc_dyn_def_trigger)
{
DYN_define_trigger(gbl, ptr, relation_name,
&trigger_name, true);
fb_assert(cnst_name);
DYN_UTIL_store_check_constraints(tdbb, gbl, *cnst_name,
trigger_name);
}
else
DYN_unsupported_verb();
break;
case isc_dyn_foreign_key_null:
(*ri_actionP) |= FOR_KEY_UPD_NULL;
if ((verb = *(*ptr)++) == isc_dyn_def_trigger)
{
DYN_define_trigger(gbl, ptr, relation_name,
&trigger_name, true);
fb_assert(cnst_name);
DYN_UTIL_store_check_constraints(tdbb, gbl, *cnst_name,
trigger_name);
}
else
DYN_unsupported_verb();
break;
case isc_dyn_foreign_key_default:
(*ri_actionP) |= FOR_KEY_UPD_DEFAULT;
if ((verb = *(*ptr)++) == isc_dyn_def_trigger)
{
DYN_define_trigger(gbl, ptr, relation_name,
&trigger_name, true);
fb_assert(cnst_name);
DYN_UTIL_store_check_constraints(tdbb, gbl, *cnst_name,
trigger_name);
}
else
DYN_unsupported_verb();
break;
case isc_dyn_foreign_key_none:
(*ri_actionP) |= FOR_KEY_UPD_NONE;
break;
default:
fb_assert(0); /* should not come here */
DYN_unsupported_verb();
}
break;
default:
DYN_unsupported_verb();
}
request = old_request;
id = old_id;
key_length = ROUNDUP(key_length, sizeof(SLONG));
if (key_length >= MAX_KEY)
DYN_error_punt(false, 118, IDX.RDB$INDEX_NAME, NULL, NULL, NULL,
NULL);
/* msg 118 "key size too big for index %s" */
if (seg_count) {
if (seg_count != fld_count)
DYN_error_punt(false, 120, IDX.RDB$INDEX_NAME, NULL, NULL,
NULL, NULL);
/* msg 118 "Unknown fields in index %s" */
old_request = request;
old_id = id;
request = CMP_find_request(tdbb, drq_s_idx_segs, DYN_REQUESTS);
id = drq_s_idx_segs;
while (seg_list.getCount()) {
STORE(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
X IN RDB$INDEX_SEGMENTS
strcpy(X.RDB$INDEX_NAME, IDX.RDB$INDEX_NAME);
Firebird::MetaName str = seg_list.pop();
strcpy(X.RDB$FIELD_NAME, str.c_str());
X.RDB$FIELD_POSITION = --fld_count;
END_STORE;
}
if (!DYN_REQUEST(drq_s_idx_segs))
DYN_REQUEST(drq_s_idx_segs) = request;
request = old_request;
id = old_id;
}
else
#ifdef EXPRESSION_INDICES
if (IDX.RDB$EXPRESSION_BLR.NULL)
#endif
DYN_error_punt(false, 119, IDX.RDB$INDEX_NAME, NULL, NULL, NULL,
NULL);
/* msg 119 "no keys for index %s" */
if (field_list.getCount()) {
/* If referring columns count <> referred columns return error */
if (seg_count != referred_cols)
DYN_error_punt(true, 133, NULL, NULL, NULL, NULL, NULL);
/* msg 133: "Number of referencing columns do not equal number of referenced columns */
/* lookup a unique index in the referenced relation with the
referenced fields mentioned */
old_request = request;
old_id = id;
request = CMP_find_request(tdbb, drq_l_unq_idx, DYN_REQUESTS);
id = drq_l_unq_idx;
index_name = "";
list_index = -1;
bool found = false;
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
X IN RDB$RELATION_CONSTRAINTS CROSS
Y IN RDB$INDICES OVER RDB$INDEX_NAME CROSS
Z IN RDB$INDEX_SEGMENTS OVER RDB$INDEX_NAME WITH
Y.RDB$RELATION_NAME EQ referenced_relation.c_str() AND
Y.RDB$UNIQUE_FLAG NOT MISSING AND
(X.RDB$CONSTRAINT_TYPE = PRIMARY_KEY OR
X.RDB$CONSTRAINT_TYPE = UNIQUE_CNSTRT)
SORTED BY Y.RDB$INDEX_NAME,
DESCENDING Z.RDB$FIELD_POSITION
if (!DYN_REQUEST(drq_l_unq_idx))
DYN_REQUEST(drq_l_unq_idx) = request;
/* create a control break on index name, in which we set up
to handle a new index, assuming it is the right one */
if (index_name != Y.RDB$INDEX_NAME) {
if (list_index >= 0)
found = false;
if (found) {
EXE_unwind(tdbb, request);
break;
}
list_index = field_list.getCount() - 1;
index_name = Y.RDB$INDEX_NAME;
found = true;
}
/* if there are no more fields or the field name doesn't
match, then this is not the correct index */
if (list_index >= 0) {
fb_utils::exact_name_limit(Z.RDB$FIELD_NAME, sizeof(Z.RDB$FIELD_NAME));
if (field_list[list_index--] != Z.RDB$FIELD_NAME)
{
found = false;
}
}
else
found = false;
END_FOR;
if (!DYN_REQUEST(drq_l_unq_idx))
DYN_REQUEST(drq_l_unq_idx) = request;
request = old_request;
id = old_id;
if (list_index >= 0)
found = false;
if (found) {
strcpy(IDX.RDB$FOREIGN_KEY, index_name.c_str());
IDX.RDB$FOREIGN_KEY.NULL = FALSE;
if (referred_index_name) {
*referred_index_name = index_name;
}
}
else {
DYN_error_punt(false, 18, NULL, NULL, NULL, NULL, NULL);
/* msg 18: "could not find unique index with specified fields" */
}
}
else if (referenced_relation.length()) {
old_request = request;
old_id = id;
request = CMP_find_request(tdbb, drq_l_primary, DYN_REQUESTS);
id = drq_l_primary;
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
IND IN RDB$INDICES CROSS
RC IN RDB$RELATION_CONSTRAINTS
OVER RDB$INDEX_NAME WITH
IND.RDB$RELATION_NAME EQ referenced_relation.c_str() AND
RC.RDB$CONSTRAINT_TYPE EQ PRIMARY_KEY
if (!DYN_REQUEST(drq_l_primary))
DYN_REQUEST(drq_l_primary) = request;
/* Number of columns in referred index should be same as number
of columns in referring index */
if (seg_count != IND.RDB$SEGMENT_COUNT)
DYN_error_punt(true, 133, NULL, NULL, NULL, NULL, NULL);
/* msg 133: "Number of referencing columns do not equal number of referenced columns" */
fb_utils::exact_name_limit(IND.RDB$INDEX_NAME, sizeof(IND.RDB$INDEX_NAME));
strcpy(IDX.RDB$FOREIGN_KEY, IND.RDB$INDEX_NAME);
IDX.RDB$FOREIGN_KEY.NULL = FALSE;
if (referred_index_name)
*referred_index_name = IND.RDB$INDEX_NAME;
END_FOR;
if (!DYN_REQUEST(drq_l_primary))
DYN_REQUEST(drq_l_primary) = request;
request = old_request;
id = old_id;
if (IDX.RDB$FOREIGN_KEY.NULL)
DYN_error_punt(false, 20, NULL, NULL, NULL, NULL, NULL);
/* msg 20: "could not find primary key index in specified relation" */
}
IDX.RDB$SEGMENT_COUNT = seg_count;
END_STORE;
if (!DYN_REQUEST(drq_s_indices)) {
DYN_REQUEST(drq_s_indices) = request;
}
} // try
catch (const std::exception& ex) {
Firebird::stuff_exception(tdbb->tdbb_status_vector, ex);
if (id == drq_s_indices) {
DYN_rundown_request(request, id);
DYN_error_punt(true, 21, NULL, NULL, NULL, NULL, NULL);
/* msg 21: "STORE RDB$INDICES failed" */
}
else if (id == drq_s_idx_segs) {
DYN_rundown_request(request, id);
DYN_error_punt(true, 15, NULL, NULL, NULL, NULL, NULL);
/* msg 15: "STORE RDB$INDICES failed" */
}
DYN_rundown_request(request, -1);
switch (id)
{
case drq_l_lfield:
DYN_error_punt(true, 15, NULL, NULL, NULL, NULL, NULL);
/* msg 15: "STORE RDB$INDICES failed" */
break;
case drq_l_unq_idx:
DYN_error_punt(true, 17, NULL, NULL, NULL, NULL, NULL);
/* msg 17: "Primary Key field lookup failed" */
break;
case drq_l_view_idx:
DYN_error_punt(true, 180, NULL, NULL, NULL, NULL, NULL);
/* msg 180: "Table Name lookup failed" */
break;
default:
DYN_error_punt(true, 19, NULL, NULL, NULL, NULL, NULL);
/* msg 19: "Primary Key lookup failed" */
break;
}
}
}
void DYN_define_local_field(Global* gbl,
const UCHAR** ptr,
const Firebird::MetaName* relation_name,
Firebird::MetaName* field_name)
{
/**************************************
*
* D Y N _ d e f i n e _ l o c a l _ f i e l d
*
**************************************
*
* Functional description
* Execute a dynamic ddl statement.
*
**************************************/
UCHAR verb;
USHORT dtype, length, clength, precision;
SSHORT stype, scale;
SSHORT charset_id;
SLONG fld_pos;
thread_db* tdbb = JRD_get_thread_data();
Database* dbb = tdbb->tdbb_database;
Firebird::MetaName local_field_name;
GET_STRING(ptr, local_field_name);
if (local_field_name.length() == 0) {
DYN_error_punt(false, 212, NULL, NULL, NULL, NULL, NULL);
/* msg 212: "Zero length identifiers not allowed" */
}
jrd_req* request = NULL;
SSHORT id = -1;
try {
request = CMP_find_request(tdbb, drq_s_lfields, DYN_REQUESTS);
id = drq_s_lfields;
bool lflag, sflag, slflag, scflag, clflag, prflag;
scflag = lflag = sflag = slflag = clflag = prflag = false;
bool charset_id_flag = false;
const UCHAR* blr = NULL;
const UCHAR* source = NULL;
Firebird::MetaName relation_buffer;
STORE(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
RFR IN RDB$RELATION_FIELDS
strcpy(RFR.RDB$FIELD_NAME, local_field_name.c_str());
strcpy(RFR.RDB$FIELD_SOURCE, RFR.RDB$FIELD_NAME);
if (field_name) {
*field_name = RFR.RDB$FIELD_NAME;
}
RFR.RDB$RELATION_NAME.NULL = TRUE;
if (relation_name) {
strcpy(RFR.RDB$RELATION_NAME, relation_name->c_str());
RFR.RDB$RELATION_NAME.NULL = FALSE;
}
RFR.RDB$SYSTEM_FLAG = 0;
RFR.RDB$SYSTEM_FLAG.NULL = FALSE;
RFR.RDB$NULL_FLAG.NULL = TRUE;
RFR.RDB$BASE_FIELD.NULL = TRUE;
RFR.RDB$UPDATE_FLAG.NULL = TRUE;
RFR.RDB$FIELD_POSITION.NULL = TRUE;
RFR.RDB$VIEW_CONTEXT.NULL = TRUE;
RFR.RDB$QUERY_NAME.NULL = TRUE;
RFR.RDB$QUERY_HEADER.NULL = TRUE;
RFR.RDB$SECURITY_CLASS.NULL = TRUE;
RFR.RDB$DESCRIPTION.NULL = TRUE;
RFR.RDB$DEFAULT_VALUE.NULL = TRUE;
RFR.RDB$DEFAULT_SOURCE.NULL = TRUE;
RFR.RDB$EDIT_STRING.NULL = TRUE;
RFR.RDB$COLLATION_ID.NULL = TRUE;
while ((verb = *(*ptr)++) != isc_dyn_end)
switch (verb)
{
case isc_dyn_rel_name:
GET_STRING(ptr, relation_buffer);
relation_name = &relation_buffer;
strcpy(RFR.RDB$RELATION_NAME, relation_name->c_str());
RFR.RDB$RELATION_NAME.NULL = FALSE;
break;
case isc_dyn_fld_source:
GET_STRING(ptr, RFR.RDB$FIELD_SOURCE);
break;
case isc_dyn_fld_base_fld:
GET_STRING(ptr, RFR.RDB$BASE_FIELD);
RFR.RDB$BASE_FIELD.NULL = FALSE;
break;
case isc_dyn_fld_query_name:
GET_STRING(ptr, RFR.RDB$QUERY_NAME);
RFR.RDB$QUERY_NAME.NULL = FALSE;
break;
case isc_dyn_fld_query_header:
DYN_put_blr_blob(gbl, ptr, &RFR.RDB$QUERY_HEADER);
RFR.RDB$QUERY_HEADER.NULL = FALSE;
break;
case isc_dyn_fld_edit_string:
GET_STRING(ptr, RFR.RDB$EDIT_STRING);
RFR.RDB$EDIT_STRING.NULL = FALSE;
break;
case isc_dyn_fld_position:
RFR.RDB$FIELD_POSITION = (SSHORT)DYN_get_number(ptr);
RFR.RDB$FIELD_POSITION.NULL = FALSE;
break;
case isc_dyn_system_flag:
RFR.RDB$SYSTEM_FLAG = (SSHORT)DYN_get_number(ptr);
RFR.RDB$SYSTEM_FLAG.NULL = FALSE;
break;
case isc_dyn_fld_update_flag:
case isc_dyn_update_flag:
RFR.RDB$UPDATE_FLAG = (SSHORT)DYN_get_number(ptr);
RFR.RDB$UPDATE_FLAG.NULL = FALSE;
break;
case isc_dyn_view_context:
RFR.RDB$VIEW_CONTEXT = (SSHORT)DYN_get_number(ptr);
RFR.RDB$VIEW_CONTEXT.NULL = FALSE;
break;
case isc_dyn_security_class:
GET_STRING(ptr, RFR.RDB$SECURITY_CLASS);
RFR.RDB$SECURITY_CLASS.NULL = FALSE;
break;
case isc_dyn_description:
DYN_put_text_blob(gbl, ptr, &RFR.RDB$DESCRIPTION);
RFR.RDB$DESCRIPTION.NULL = FALSE;
break;
case isc_dyn_fld_computed_blr:
DYN_UTIL_generate_field_name(tdbb, gbl, RFR.RDB$FIELD_SOURCE);
blr = *ptr;
DYN_skip_attribute(ptr);
break;
case isc_dyn_fld_computed_source:
source = *ptr;
DYN_skip_attribute(ptr);
break;
case isc_dyn_fld_default_value:
RFR.RDB$DEFAULT_VALUE.NULL = FALSE;
DYN_put_blr_blob(gbl, ptr, &RFR.RDB$DEFAULT_VALUE);
break;
case isc_dyn_fld_default_source:
RFR.RDB$DEFAULT_SOURCE.NULL = FALSE;
DYN_put_text_blob(gbl, ptr, &RFR.RDB$DEFAULT_SOURCE);
break;
case isc_dyn_fld_not_null:
RFR.RDB$NULL_FLAG.NULL = FALSE;
RFR.RDB$NULL_FLAG = TRUE;
break;
case isc_dyn_fld_type:
dtype = (USHORT)DYN_get_number(ptr);
break;
case isc_dyn_fld_length:
length = (USHORT)DYN_get_number(ptr);
lflag = true;
break;
case isc_dyn_fld_sub_type:
stype = (SSHORT)DYN_get_number(ptr);
sflag = true;
break;
case isc_dyn_fld_char_length:
clength = (USHORT)DYN_get_number(ptr);
clflag = true;
break;
case isc_dyn_fld_segment_length:
stype = (SSHORT)DYN_get_number(ptr);
slflag = true;
break;
case isc_dyn_fld_scale:
scale = (SSHORT)DYN_get_number(ptr);
scflag = true;
break;
case isc_dyn_fld_precision:
precision = (USHORT)DYN_get_number(ptr);
prflag = true;
break;
case isc_dyn_fld_character_set:
charset_id = (SSHORT)DYN_get_number(ptr);
charset_id_flag = true;
break;
case isc_dyn_fld_collation:
RFR.RDB$COLLATION_ID.NULL = FALSE;
RFR.RDB$COLLATION_ID = (SSHORT)DYN_get_number(ptr);
break;
default:
MetaTmp(RFR.RDB$FIELD_SOURCE)
DYN_execute(gbl, ptr, relation_name, &tmp, NULL, NULL, NULL);
}
if (RFR.RDB$FIELD_POSITION.NULL == TRUE) {
fld_pos = -1;
fb_assert(relation_name);
DYN_UTIL_generate_field_position(tdbb, gbl, *relation_name,
&fld_pos);
if (fld_pos >= 0) {
RFR.RDB$FIELD_POSITION = (SSHORT)++fld_pos;
RFR.RDB$FIELD_POSITION.NULL = FALSE;
}
}
if (blr) {
jrd_req* old_request = request;
const SSHORT old_id = id;
request = CMP_find_request(tdbb, drq_s_gfields2, DYN_REQUESTS);
STORE(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
FLD IN RDB$FIELDS
strcpy(FLD.RDB$FIELD_NAME, RFR.RDB$FIELD_SOURCE);
DYN_put_blr_blob(gbl, &blr, &FLD.RDB$COMPUTED_BLR);
if (source) {
DYN_put_text_blob(gbl, &source, &FLD.RDB$COMPUTED_SOURCE);
}
FLD.RDB$FIELD_TYPE = dtype;
if (lflag) {
FLD.RDB$FIELD_LENGTH = length;
FLD.RDB$FIELD_LENGTH.NULL = FALSE;
}
else
FLD.RDB$FIELD_LENGTH.NULL = TRUE;
if (sflag) {
FLD.RDB$FIELD_SUB_TYPE = stype;
FLD.RDB$FIELD_SUB_TYPE.NULL = FALSE;
}
else
FLD.RDB$FIELD_SUB_TYPE.NULL = TRUE;
if (clflag) {
FLD.RDB$CHARACTER_LENGTH = clength;
FLD.RDB$CHARACTER_LENGTH.NULL = FALSE;
}
else
FLD.RDB$CHARACTER_LENGTH.NULL = TRUE;
if (slflag) {
FLD.RDB$SEGMENT_LENGTH = stype;
FLD.RDB$SEGMENT_LENGTH.NULL = FALSE;
}
else
FLD.RDB$SEGMENT_LENGTH.NULL = TRUE;
if (scflag) {
FLD.RDB$FIELD_SCALE = scale;
FLD.RDB$FIELD_SCALE.NULL = FALSE;
}
else
FLD.RDB$FIELD_SCALE.NULL = TRUE;
if (prflag) {
FLD.RDB$FIELD_PRECISION = precision;
FLD.RDB$FIELD_PRECISION.NULL = FALSE;
}
else
FLD.RDB$FIELD_PRECISION.NULL = TRUE;
if (charset_id_flag) {
FLD.RDB$CHARACTER_SET_ID = charset_id;
FLD.RDB$CHARACTER_SET_ID.NULL = FALSE;
}
else
FLD.RDB$CHARACTER_SET_ID.NULL = TRUE;
END_STORE;
if (!DYN_REQUEST(drq_s_gfields2))
DYN_REQUEST(drq_s_gfields2) = request;
request = old_request;
id = old_id;
}
if (!RFR.RDB$VIEW_CONTEXT.NULL)
{
fb_assert(relation_name);
find_field_source(tdbb, gbl, *relation_name, RFR.RDB$VIEW_CONTEXT,
RFR.RDB$BASE_FIELD, RFR.RDB$FIELD_SOURCE);
}
END_STORE;
if (!DYN_REQUEST(drq_s_lfields)) {
DYN_REQUEST(drq_s_lfields) = request;
}
} // try
catch (const std::exception& ex) {
Firebird::stuff_exception(tdbb->tdbb_status_vector, ex);
if (id == drq_s_lfields) {
DYN_rundown_request(request, id);
DYN_error_punt(true, 23, NULL, NULL, NULL, NULL, NULL);
/* msg 23: "STORE RDB$RELATION_FIELDS failed" */
}
else {
DYN_rundown_request(request, id);
DYN_error_punt(true, 22, NULL, NULL, NULL, NULL, NULL);
/* msg 22: "STORE RDB$FIELDS failed" */
}
}
}
void DYN_define_parameter( Global* gbl, const UCHAR** ptr, Firebird::MetaName* procedure_name)
{
/**************************************
*
* D Y N _ d e f i n e _ p a r a m e t e r
*
**************************************
*
* Functional description
* Execute a dynamic ddl statement.
*
**************************************/
// Leave these as USHORT. Don't convert the *_null ones to bool.
USHORT f_length, f_type, f_charlength, f_seg_length,
f_scale_null, f_subtype_null, f_seg_length_null,
f_charlength_null, f_precision_null, f_charset_null, f_collation_null;
SSHORT id;
SSHORT f_subtype, f_scale, f_precision;
SSHORT f_charset, f_collation;
const UCHAR* default_value_ptr = NULL;
const UCHAR* default_source_ptr = NULL;
thread_db* tdbb = JRD_get_thread_data();
Database* dbb = tdbb->tdbb_database;
Firebird::MetaName parameter_name;
GET_STRING(ptr, parameter_name);
if (parameter_name.length() == 0) {
DYN_error_punt(false, 212, NULL, NULL, NULL, NULL, NULL);
/* msg 212: "Zero length identifiers not allowed" */
}
jrd_req* request = CMP_find_request(tdbb, drq_s_prms, DYN_REQUESTS);
try {
id = -1;
f_length = f_type = f_subtype = f_charlength = f_scale = f_seg_length = 0;
f_charset = f_collation = f_precision = 0;
f_scale_null = f_subtype_null = f_charlength_null = f_seg_length_null =
TRUE;
f_precision_null = f_charset_null = f_collation_null = TRUE;
id = drq_s_prms;
STORE(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
P IN RDB$PROCEDURE_PARAMETERS USING
strcpy(P.RDB$PARAMETER_NAME, parameter_name.c_str());
if (procedure_name) {
P.RDB$PROCEDURE_NAME.NULL = FALSE;
strcpy(P.RDB$PROCEDURE_NAME, procedure_name->c_str());
}
else
P.RDB$PROCEDURE_NAME.NULL = TRUE;
P.RDB$PARAMETER_NUMBER.NULL = TRUE;
P.RDB$PARAMETER_TYPE.NULL = TRUE;
P.RDB$FIELD_SOURCE.NULL = TRUE;
P.RDB$SYSTEM_FLAG.NULL = TRUE;
P.RDB$DESCRIPTION.NULL = TRUE;
UCHAR verb;
while ((verb = *(*ptr)++) != isc_dyn_end)
switch (verb)
{
case isc_dyn_system_flag:
P.RDB$SYSTEM_FLAG = (SSHORT)DYN_get_number(ptr);
P.RDB$SYSTEM_FLAG.NULL = FALSE;
break;
case isc_dyn_prm_number:
P.RDB$PARAMETER_NUMBER = (SSHORT)DYN_get_number(ptr);
P.RDB$PARAMETER_NUMBER.NULL = FALSE;
break;
case isc_dyn_prm_type:
P.RDB$PARAMETER_TYPE = (SSHORT)DYN_get_number(ptr);
P.RDB$PARAMETER_TYPE.NULL = FALSE;
break;
case isc_dyn_prc_name:
GET_STRING(ptr, P.RDB$PROCEDURE_NAME);
P.RDB$PROCEDURE_NAME.NULL = FALSE;
break;
case isc_dyn_fld_source:
GET_STRING(ptr, P.RDB$FIELD_SOURCE);
P.RDB$FIELD_SOURCE.NULL = FALSE;
break;
case isc_dyn_fld_length:
f_length = (USHORT)DYN_get_number(ptr);
break;
case isc_dyn_fld_type:
f_type = (USHORT)DYN_get_number(ptr);
switch (f_type)
{
case blr_short:
f_length = 2;
break;
case blr_long:
case blr_float:
case blr_sql_time:
case blr_sql_date:
f_length = 4;
break;
case blr_int64:
case blr_quad:
case blr_timestamp:
case blr_double:
case blr_d_float:
f_length = 8;
break;
default:
if (f_type == blr_blob)
f_length = 8;
break;
}
break;
case isc_dyn_fld_scale:
f_scale = (SSHORT)DYN_get_number(ptr);
f_scale_null = FALSE;
break;
case isc_dyn_fld_precision:
f_precision = (SSHORT)DYN_get_number(ptr);
f_precision_null = FALSE;
break;
case isc_dyn_fld_sub_type:
f_subtype = (SSHORT)DYN_get_number(ptr);
f_subtype_null = FALSE;
break;
case isc_dyn_fld_char_length:
f_charlength = (USHORT)DYN_get_number(ptr);
f_charlength_null = FALSE;
break;
case isc_dyn_fld_character_set:
f_charset = (SSHORT)DYN_get_number(ptr);
f_charset_null = FALSE;
break;
case isc_dyn_fld_collation:
f_collation = (SSHORT)DYN_get_number(ptr);
f_collation_null = FALSE;
break;
case isc_dyn_fld_segment_length:
f_seg_length = (USHORT)DYN_get_number(ptr);
f_seg_length_null = FALSE;
break;
case isc_dyn_description:
DYN_put_text_blob(gbl, ptr, &P.RDB$DESCRIPTION);
P.RDB$DESCRIPTION.NULL = FALSE;
break;
case isc_dyn_fld_default_value:
default_value_ptr = *ptr;
skip_blr_blob(ptr);
break;
case isc_dyn_fld_default_source:
default_source_ptr = *ptr;
skip_blr_blob(ptr);
break;
default:
--(*ptr);
DYN_execute(gbl, ptr, NULL, NULL, NULL, NULL, procedure_name);
}
if (P.RDB$FIELD_SOURCE.NULL) {
/* Need to store dummy global field */
id = drq_s_prm_src;
jrd_req* request2 = CMP_find_request(tdbb, drq_s_prm_src, DYN_REQUESTS);
STORE(REQUEST_HANDLE request2 TRANSACTION_HANDLE gbl->gbl_transaction)
PS IN RDB$FIELDS USING
DYN_UTIL_generate_field_name(tdbb, gbl,
PS.RDB$FIELD_NAME);
strcpy(P.RDB$FIELD_SOURCE, PS.RDB$FIELD_NAME);
P.RDB$FIELD_SOURCE.NULL = FALSE;
PS.RDB$FIELD_LENGTH = f_length;
PS.RDB$FIELD_TYPE = f_type;
PS.RDB$FIELD_SUB_TYPE = f_subtype;
PS.RDB$FIELD_SUB_TYPE.NULL = f_subtype_null;
PS.RDB$FIELD_SCALE = f_scale;
PS.RDB$FIELD_SCALE.NULL = f_scale_null;
PS.RDB$FIELD_PRECISION = f_precision;
PS.RDB$FIELD_PRECISION.NULL = f_precision_null;
PS.RDB$SEGMENT_LENGTH = f_seg_length;
PS.RDB$SEGMENT_LENGTH.NULL = f_seg_length_null;
PS.RDB$CHARACTER_LENGTH = f_charlength;
PS.RDB$CHARACTER_LENGTH.NULL = f_charlength_null;
PS.RDB$CHARACTER_SET_ID = f_charset;
PS.RDB$CHARACTER_SET_ID.NULL = f_charset_null;
PS.RDB$COLLATION_ID = f_collation;
PS.RDB$COLLATION_ID.NULL = f_collation_null;
PS.RDB$DEFAULT_VALUE.NULL = (default_value_ptr == NULL) ? TRUE : FALSE;
if (default_value_ptr) {
DYN_put_blr_blob(gbl, &default_value_ptr, &PS.RDB$DEFAULT_VALUE);
}
PS.RDB$DEFAULT_SOURCE.NULL = (default_source_ptr == NULL) ? TRUE : FALSE;
if (default_source_ptr) {
DYN_put_text_blob(gbl, &default_source_ptr, &PS.RDB$DEFAULT_SOURCE);
}
END_STORE;
if (!DYN_REQUEST(drq_s_prm_src))
DYN_REQUEST(drq_s_prm_src) = request2;
id = drq_s_prms;
}
END_STORE;
if (!DYN_REQUEST(drq_s_prms)) {
DYN_REQUEST(drq_s_prms) = request;
}
}
catch (const std::exception& ex) {
Firebird::stuff_exception(tdbb->tdbb_status_vector, ex);
if (id == drq_s_prms) {
DYN_rundown_request(request, drq_s_prms);
DYN_error_punt(true, 136, NULL, NULL, NULL, NULL, NULL);
/* msg 163: "STORE RDB$PROCEDURE_PARAMETERS failed" */
}
else if (id == drq_s_prm_src) {
DYN_rundown_request(request, drq_s_prm_src);
DYN_error_punt(true, 136, NULL, NULL, NULL, NULL, NULL);
/* msg 136: "STORE RDB$PROCEDURE_PARAMETERS failed" */
}
DYN_rundown_request(request, -1);
/* Control should never reach this point,
because id should always have one of the values tested above. */
fb_assert(0);
DYN_error_punt(true, 0, NULL, NULL, NULL, NULL, NULL);
}
}
void DYN_define_procedure( Global* gbl, const UCHAR** ptr)
{
/**************************************
*
* D Y N _ d e f i n e _ p r o c e d u r e
*
**************************************
*
* Functional description
* Execute a dynamic ddl statement.
*
**************************************/
Firebird::MetaName procedure_name;
thread_db* tdbb = JRD_get_thread_data();
Database* dbb = tdbb->tdbb_database;
GET_STRING(ptr, procedure_name);
if (procedure_name.length() == 0)
DYN_error_punt(false, 212, NULL, NULL, NULL, NULL, NULL);
/* msg 212: "Zero length identifiers not allowed" */
jrd_req* request = NULL;
SSHORT id = -1;
try {
id = drq_l_prc_name;
check_unique_name(tdbb, gbl, procedure_name, true);
bool sql_prot = false;
request = CMP_find_request(tdbb, drq_s_prcs, DYN_REQUESTS);
id = drq_s_prcs;
STORE(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
P IN RDB$PROCEDURES
strcpy(P.RDB$PROCEDURE_NAME, procedure_name.c_str());
P.RDB$SYSTEM_FLAG.NULL = TRUE;
P.RDB$PROCEDURE_BLR.NULL = TRUE;
P.RDB$PROCEDURE_SOURCE.NULL = TRUE;
P.RDB$SECURITY_CLASS.NULL = TRUE;
P.RDB$DESCRIPTION.NULL = TRUE;
P.RDB$PROCEDURE_INPUTS.NULL = TRUE;
P.RDB$PROCEDURE_OUTPUTS.NULL = TRUE;
UCHAR verb;
while ((verb = *(*ptr)++) != isc_dyn_end)
switch (verb)
{
case isc_dyn_system_flag:
P.RDB$SYSTEM_FLAG = (SSHORT)DYN_get_number(ptr);
P.RDB$SYSTEM_FLAG.NULL = FALSE;
break;
case isc_dyn_prc_blr:
P.RDB$PROCEDURE_BLR.NULL = FALSE;
DYN_put_blr_blob(gbl, ptr, &P.RDB$PROCEDURE_BLR);
break;
case isc_dyn_description:
DYN_put_text_blob(gbl, ptr, &P.RDB$DESCRIPTION);
P.RDB$DESCRIPTION.NULL = FALSE;
break;
case isc_dyn_prc_source:
DYN_put_text_blob(gbl, ptr, &P.RDB$PROCEDURE_SOURCE);
P.RDB$PROCEDURE_SOURCE.NULL = FALSE;
break;
case isc_dyn_prc_inputs:
P.RDB$PROCEDURE_INPUTS = (SSHORT)DYN_get_number(ptr);
P.RDB$PROCEDURE_INPUTS.NULL = FALSE;
break;
case isc_dyn_prc_outputs:
P.RDB$PROCEDURE_OUTPUTS = (SSHORT)DYN_get_number(ptr);
P.RDB$PROCEDURE_OUTPUTS.NULL = FALSE;
break;
case isc_dyn_security_class:
GET_STRING(ptr, P.RDB$SECURITY_CLASS);
P.RDB$SECURITY_CLASS.NULL = FALSE;
break;
case isc_dyn_rel_sql_protection:
sql_prot = (bool) DYN_get_number(ptr);
break;
default:
--(*ptr);
DYN_execute(gbl, ptr, NULL, NULL, NULL, NULL, &procedure_name);
}
END_STORE;
if (!DYN_REQUEST(drq_s_prcs))
DYN_REQUEST(drq_s_prcs) = request;
if (sql_prot) {
Firebird::MetaName owner_name;
if (!get_who(tdbb, gbl, owner_name))
DYN_error_punt(true, 134, NULL, NULL, NULL, NULL, NULL);
/* msg 134: "STORE RDB$PROCEDURES failed" */
for (const TEXT* p = ALL_PROC_PRIVILEGES; *p; p++) {
request = CMP_find_request(tdbb, drq_s_prc_usr_prvs, DYN_REQUESTS);
id = drq_s_prc_usr_prvs;
STORE(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
X IN RDB$USER_PRIVILEGES
strcpy(X.RDB$RELATION_NAME, procedure_name.c_str());
strcpy(X.RDB$USER, owner_name.c_str());
X.RDB$USER_TYPE = obj_user;
X.RDB$OBJECT_TYPE = obj_procedure;
X.RDB$PRIVILEGE[0] = *p;
X.RDB$PRIVILEGE[1] = 0;
END_STORE;
if (!DYN_REQUEST(drq_s_prc_usr_prvs))
DYN_REQUEST(drq_s_prc_usr_prvs) = request;
}
}
}
catch (const std::exception& ex) {
Firebird::stuff_exception(tdbb->tdbb_status_vector, ex);
if (id == drq_s_prcs) {
DYN_rundown_request(request, id);
DYN_error_punt(true, 134, NULL, NULL, NULL, NULL, NULL);
/* msg 134: "STORE RDB$PROCEDURES failed" */
}
else if (id == drq_s_prc_usr_prvs) {
DYN_rundown_request(request, id);
DYN_error_punt(true, 25, NULL, NULL, NULL, NULL, NULL);
/* msg 25: "STORE RDB$USER_PRIVILEGES failed defining a relation" */
}
DYN_rundown_request(request, -1);
if (id == drq_l_prc_name) {
DYN_error_punt(true, 134, NULL, NULL, NULL, NULL, NULL);
/* msg 134: "STORE RDB$PROCEDURES failed" */
}
/* Control should never reach this point, because id should have
one of the values tested-for above. */
fb_assert(0);
DYN_error_punt(true, 0, NULL, NULL, NULL, NULL, NULL);
}
}
void DYN_define_relation( Global* gbl, const UCHAR** ptr)
{
/**************************************
*
* D Y N _ d e f i n e _ r e l a t i o n
*
**************************************
*
* Functional description
* Execute a dynamic ddl statement.
*
**************************************/
Firebird::MetaName relation_name, owner_name;
Firebird::MetaName field_name; // unused, only passed empty to DYN_execute again.
thread_db* tdbb = JRD_get_thread_data();
Database* dbb = tdbb->tdbb_database;
GET_STRING(ptr, relation_name);
if (relation_name.length() == 0)
{
DYN_error_punt(false, 212, NULL, NULL, NULL, NULL, NULL);
/* msg 212: "Zero length identifiers not allowed" */
}
jrd_req* request = NULL;
SSHORT id = -1;
Firebird::PathName Path, Name;
try {
id = drq_l_rel_name;
check_unique_name(tdbb, gbl, relation_name, false);
bool sql_prot = false, is_a_view = false;
request = CMP_find_request(tdbb, drq_s_rels, DYN_REQUESTS);
id = drq_s_rels;
STORE(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
REL IN RDB$RELATIONS
strcpy(REL.RDB$RELATION_NAME, relation_name.c_str());
REL.RDB$SYSTEM_FLAG.NULL = TRUE;
REL.RDB$VIEW_BLR.NULL = TRUE;
REL.RDB$VIEW_SOURCE.NULL = TRUE;
REL.RDB$SECURITY_CLASS.NULL = TRUE;
REL.RDB$DESCRIPTION.NULL = TRUE;
REL.RDB$EXTERNAL_FILE.NULL = TRUE;
REL.RDB$FLAGS = 0;
REL.RDB$FLAGS.NULL = FALSE;
UCHAR verb;
while ((verb = *(*ptr)++) != isc_dyn_end)
switch (verb)
{
case isc_dyn_system_flag:
REL.RDB$SYSTEM_FLAG = DYN_get_number(ptr);
REL.RDB$SYSTEM_FLAG.NULL = FALSE;
break;
case isc_dyn_sql_object:
REL.RDB$FLAGS |= REL_sql;
break;
case isc_dyn_view_blr:
REL.RDB$VIEW_BLR.NULL = FALSE;
is_a_view = true;
DYN_put_blr_blob(gbl, ptr, &REL.RDB$VIEW_BLR);
break;
case isc_dyn_description:
DYN_put_text_blob(gbl, ptr, &REL.RDB$DESCRIPTION);
REL.RDB$DESCRIPTION.NULL = FALSE;
break;
case isc_dyn_view_source:
DYN_put_text_blob(gbl, ptr, &REL.RDB$VIEW_SOURCE);
REL.RDB$VIEW_SOURCE.NULL = FALSE;
break;
case isc_dyn_security_class:
GET_STRING(ptr, REL.RDB$SECURITY_CLASS);
REL.RDB$SECURITY_CLASS.NULL = FALSE;
break;
case isc_dyn_rel_ext_file:
GET_STRING(ptr, REL.RDB$EXTERNAL_FILE);
if (ISC_check_if_remote(REL.RDB$EXTERNAL_FILE, false))
DYN_error_punt(true, 163, NULL, NULL, NULL, NULL, NULL);
// Check for any path, present in filename.
// If miss it, file will be searched in External Tables Dirs,
// that's why no expand_filename required.
PathUtils::splitLastComponent(Path, Name, REL.RDB$EXTERNAL_FILE);
if (Path.length() > 0) // path component present in filename
{
ISC_expand_filename(REL.RDB$EXTERNAL_FILE,
strlen(REL.RDB$EXTERNAL_FILE),
REL.RDB$EXTERNAL_FILE,
sizeof(REL.RDB$EXTERNAL_FILE),
false);
}
REL.RDB$EXTERNAL_FILE.NULL = FALSE;
break;
case isc_dyn_rel_sql_protection:
REL.RDB$FLAGS |= REL_sql;
sql_prot = (bool) DYN_get_number(ptr);
break;
default:
--(*ptr);
MetaTmp(REL.RDB$RELATION_NAME)
DYN_execute(gbl, ptr, &tmp, &field_name, NULL, NULL, NULL);
}
if (sql_prot) {
if (!get_who(tdbb, gbl, owner_name))
DYN_error_punt(true, 115, NULL, NULL, NULL, NULL, NULL);
/* msg 115: "CREATE VIEW failed" */
if (is_a_view) {
jrd_req* old_request = request;
const SSHORT old_id = id;
request = CMP_find_request(tdbb, drq_l_view_rels, DYN_REQUESTS);
id = drq_l_view_rels;
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
VRL IN RDB$VIEW_RELATIONS CROSS
PREL IN RDB$RELATIONS OVER RDB$RELATION_NAME WITH
VRL.RDB$VIEW_NAME EQ relation_name.c_str()
if (!DYN_REQUEST(drq_l_view_rels))
DYN_REQUEST(drq_l_view_rels) = request;
/* CVC: This never matches so it causes unnecessary calls to verify,
so I included a call to strip trailing blanks. */
fb_utils::exact_name_limit(PREL.RDB$OWNER_NAME, sizeof(PREL.RDB$OWNER_NAME));
if (owner_name != PREL.RDB$OWNER_NAME) {
SecurityClass::flags_t priv;
if (!DYN_UTIL_get_prot
(tdbb, gbl, PREL.RDB$RELATION_NAME, "", &priv))
{
// I think this should be the responsability of DFW
// or the user will find ways to circumvent DYN.
DYN_error_punt(true, 115, NULL, NULL, NULL, NULL,
NULL);
/* msg 115: "CREATE VIEW failed" */
}
if (!(priv & SCL_read)) {
ISC_STATUS* s = tdbb->tdbb_status_vector;
*s++ = isc_arg_gds;
*s++ = isc_no_priv;
*s++ = isc_arg_string;
*s++ = (ISC_STATUS) "SELECT"; /* Non-Translatable */
*s++ = isc_arg_string;
// Remember, a view may be based on a view.
*s++ = (ISC_STATUS) "TABLE/VIEW"; /* Non-Translatable */
*s++ = isc_arg_string;
// We want to print the name of the base table or view.
*s++ = (ISC_STATUS) ERR_cstring(PREL.RDB$RELATION_NAME);
*s = 0;
/* msg 32: no permission for %s access to %s %s */
DYN_error_punt(true, 115, NULL, NULL, NULL, NULL,
NULL);
/* msg 115: "CREATE VIEW failed" */
}
}
END_FOR;
if (!DYN_REQUEST(drq_l_view_rels))
DYN_REQUEST(drq_l_view_rels) = request;
request = old_request;
id = old_id;
}
}
END_STORE;
if (!DYN_REQUEST(drq_s_rels))
DYN_REQUEST(drq_s_rels) = request;
if (sql_prot)
for (const TEXT* p = ALL_PRIVILEGES; *p; p++) {
request = CMP_find_request(tdbb, drq_s_usr_prvs, DYN_REQUESTS);
id = drq_s_usr_prvs;
STORE(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
X IN RDB$USER_PRIVILEGES
strcpy(X.RDB$RELATION_NAME, relation_name.c_str());
strcpy(X.RDB$USER, owner_name.c_str());
X.RDB$USER_TYPE = obj_user;
X.RDB$OBJECT_TYPE = obj_relation;
X.RDB$PRIVILEGE[0] = *p;
X.RDB$PRIVILEGE[1] = 0;
X.RDB$GRANT_OPTION = 1;
END_STORE;
if (!DYN_REQUEST(drq_s_usr_prvs))
DYN_REQUEST(drq_s_usr_prvs) = request;
}
}
catch (const std::exception& ex) {
Firebird::stuff_exception(tdbb->tdbb_status_vector, ex);
if (id == drq_s_rels) {
DYN_rundown_request(request, id);
DYN_error_punt(true, 24, NULL, NULL, NULL, NULL, NULL);
/* msg 24: "STORE RDB$RELATIONS failed" */
}
else if (id == drq_s_usr_prvs) {
DYN_rundown_request(request, id);
DYN_error_punt(true, 25, NULL, NULL, NULL, NULL, NULL);
/* msg 25: "STORE RDB$USER_PRIVILEGES failed defining a relation" */
}
DYN_rundown_request(request, -1);
if (id == drq_l_rel_name)
DYN_error_punt(true, 24, NULL, NULL, NULL, NULL, NULL);
/* msg 24: "STORE RDB$RELATIONS failed" */
else if (id == drq_l_view_rels)
DYN_error_punt(true, 115, NULL, NULL, NULL, NULL, NULL);
/* msg 115: "CREATE VIEW failed" */
/* Control should never reach this point, because id should
always have one of the values test-for above. */
fb_assert(0);
DYN_error_punt(true, 0, NULL, NULL, NULL, NULL, NULL);
}
}
void DYN_define_role( Global* gbl, const UCHAR** ptr)
{
/**************************************
*
* D Y N _ d e f i n e _ r o l e
*
**************************************
*
* Functional description
*
* Define a SQL role.
* ROLES cannot be named the same as any existing user name
*
**************************************/
jrd_req* request = NULL;
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;
if (ENCODE_ODS(major_version, minor_original) < ODS_9_0)
{
DYN_error(false, 196, NULL, NULL, NULL, NULL, NULL);
ERR_punt();
}
Firebird::MetaName owner_name = tdbb->tdbb_attachment->att_user->usr_user_name;
owner_name.upper7();
Firebird::MetaName role_name;
GET_STRING(ptr, role_name);
if (role_name == owner_name) {
/************************************************
**
** user name could not be used for SQL role
**
*************************************************/
DYN_error(false, 193, owner_name.c_str(), NULL, NULL, NULL, NULL);
ERR_punt();
}
if (role_name == NULL_ROLE) {
/************************************************
**
** keyword NONE could not be used as SQL role name
**
*************************************************/
DYN_error(false, 195, role_name.c_str(), NULL, NULL, NULL, NULL);
ERR_punt();
}
try {
if (is_it_user_name(gbl, role_name, tdbb)) {
/************************************************
**
** user name could not be used for SQL role
**
*************************************************/
DYN_error(false, 193, role_name.c_str(), NULL, NULL, NULL, NULL);
goto do_err_punt;
}
Firebird::MetaName dummy_name;
if (DYN_is_it_sql_role(gbl, role_name, dummy_name, tdbb)) {
/************************************************
**
** SQL role already exist
**
*************************************************/
DYN_error(false, 194, role_name.c_str(), NULL, NULL, NULL, NULL);
goto do_err_punt;
}
request = CMP_find_request(tdbb, drq_role_gens, DYN_REQUESTS);
STORE(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
X IN RDB$ROLES
strcpy(X.RDB$ROLE_NAME, role_name.c_str());
strcpy(X.RDB$OWNER_NAME, owner_name.c_str());
END_STORE;
if (!DYN_REQUEST(drq_role_gens)) {
DYN_REQUEST(drq_role_gens) = request;
}
if (*(*ptr)++ != isc_dyn_end) {
goto do_error_punt_9;
}
}
catch (const std::exception& ex) {
Firebird::stuff_exception(tdbb->tdbb_status_vector, ex);
if (request) {
DYN_rundown_request(request, drq_role_gens);
}
DYN_error_punt(true, 8, NULL, NULL, NULL, NULL, NULL);
/* msg 8: "DEFINE ROLE failed" */
}
return;
do_err_punt:
ERR_punt();
return;
do_error_punt_9:
DYN_error_punt(true, 9, NULL, NULL, NULL, NULL, NULL);
/* msg 9: "DEFINE ROLE unexpected dyn verb" */
}
void DYN_define_security_class( Global* gbl, const UCHAR** ptr)
{
/**************************************
*
* D Y N _ d e f i n e _ s e c u r i t y _ c l a s s
*
**************************************
*
* Functional description
* Execute a dynamic ddl statement.
*
**************************************/
thread_db* tdbb = JRD_get_thread_data();
Database* dbb = tdbb->tdbb_database;
jrd_req* request = CMP_find_request(tdbb, drq_s_classes, DYN_REQUESTS);
bool b_ending_store = false;
try {
STORE(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
SC IN RDB$SECURITY_CLASSES
GET_STRING(ptr, SC.RDB$SECURITY_CLASS);
SC.RDB$ACL.NULL = TRUE;
SC.RDB$DESCRIPTION.NULL = TRUE;
UCHAR verb;
while ((verb = *(*ptr)++) != isc_dyn_end)
{
switch (verb)
{
case isc_dyn_scl_acl:
DYN_put_blr_blob(gbl, ptr, &SC.RDB$ACL);
SC.RDB$ACL.NULL = FALSE;
break;
case isc_dyn_description:
DYN_put_text_blob(gbl, ptr, &SC.RDB$DESCRIPTION);
SC.RDB$DESCRIPTION.NULL = FALSE;
break;
default:
DYN_unsupported_verb();
}
}
b_ending_store = true;
END_STORE;
if (!DYN_REQUEST(drq_s_classes)) {
DYN_REQUEST(drq_s_classes) = request;
}
}
catch (const std::exception& ex) {
Firebird::stuff_exception(tdbb->tdbb_status_vector, ex);
if (b_ending_store) {
DYN_rundown_request(request, drq_s_classes);
DYN_error_punt(true, 27, NULL, NULL, NULL, NULL, NULL);
/* msg 27: "STORE RDB$RELATIONS failed" */
}
throw;
}
}
void DYN_define_sql_field(Global* gbl,
const UCHAR** ptr,
const Firebird::MetaName* relation_name,
Firebird::MetaName* field_name)
{
/**************************************
*
* D Y N _ d e f i n e _ s q l _ f i e l d
*
**************************************
*
* Functional description
* Define a local, SQL field. This will require generation of
* an global field name.
*
**************************************/
UCHAR verb;
USHORT dtype;
SLONG fld_pos;
thread_db* tdbb = JRD_get_thread_data();
Database* dbb = tdbb->tdbb_database;
Firebird::MetaName sql_field_name;
GET_STRING(ptr, sql_field_name);
if (sql_field_name.length() == 0) {
DYN_error_punt(false, 212, NULL, NULL, NULL, NULL, NULL);
/* msg 212: "Zero length identifiers not allowed" */
}
jrd_req* request = NULL;
SSHORT id = -1;
try {
request = CMP_find_request(tdbb, drq_s_sql_lfld, DYN_REQUESTS);
id = drq_s_sql_lfld;
jrd_req* old_request = NULL;
STORE(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
RFR IN RDB$RELATION_FIELDS
strcpy(RFR.RDB$FIELD_NAME, sql_field_name.c_str());
if (field_name)
*field_name = RFR.RDB$FIELD_NAME;
if (relation_name)
strcpy(RFR.RDB$RELATION_NAME, relation_name->c_str());
RFR.RDB$SYSTEM_FLAG = 0;
RFR.RDB$SYSTEM_FLAG.NULL = FALSE;
RFR.RDB$QUERY_NAME.NULL = TRUE;
RFR.RDB$QUERY_HEADER.NULL = TRUE;
RFR.RDB$EDIT_STRING.NULL = TRUE;
RFR.RDB$FIELD_POSITION.NULL = TRUE;
RFR.RDB$VIEW_CONTEXT.NULL = TRUE;
RFR.RDB$BASE_FIELD.NULL = TRUE;
RFR.RDB$UPDATE_FLAG.NULL = TRUE;
RFR.RDB$NULL_FLAG.NULL = TRUE;
RFR.RDB$DEFAULT_SOURCE.NULL = TRUE;
RFR.RDB$DEFAULT_VALUE.NULL = TRUE;
RFR.RDB$COLLATION_ID.NULL = TRUE;
old_request = request;
const SSHORT old_id = id;
request = CMP_find_request(tdbb, drq_s_sql_gfld, DYN_REQUESTS);
id = drq_s_sql_gfld;
STORE(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
FLD IN RDB$FIELDS FLD.RDB$SYSTEM_FLAG.NULL = TRUE;
FLD.RDB$FIELD_SCALE.NULL = TRUE;
FLD.RDB$FIELD_PRECISION.NULL = TRUE;
FLD.RDB$FIELD_SUB_TYPE.NULL = TRUE;
FLD.RDB$SEGMENT_LENGTH.NULL = TRUE;
FLD.RDB$COMPUTED_BLR.NULL = TRUE;
FLD.RDB$COMPUTED_SOURCE.NULL = TRUE;
FLD.RDB$DEFAULT_VALUE.NULL = TRUE;
FLD.RDB$DEFAULT_SOURCE.NULL = TRUE;
FLD.RDB$VALIDATION_BLR.NULL = TRUE;
FLD.RDB$VALIDATION_SOURCE.NULL = TRUE;
FLD.RDB$NULL_FLAG.NULL = TRUE;
FLD.RDB$EDIT_STRING.NULL = TRUE;
FLD.RDB$DIMENSIONS.NULL = TRUE;
FLD.RDB$CHARACTER_LENGTH.NULL = TRUE;
FLD.RDB$CHARACTER_SET_ID.NULL = TRUE;
FLD.RDB$COLLATION_ID.NULL = TRUE;
DYN_UTIL_generate_field_name(tdbb, gbl, RFR.RDB$FIELD_SOURCE);
strcpy(FLD.RDB$FIELD_NAME, RFR.RDB$FIELD_SOURCE);
while ((verb = *(*ptr)++) != isc_dyn_end)
switch (verb)
{
case isc_dyn_rel_name:
GET_STRING(ptr, RFR.RDB$RELATION_NAME);
break;
case isc_dyn_fld_query_name:
GET_STRING(ptr, RFR.RDB$QUERY_NAME);
RFR.RDB$QUERY_NAME.NULL = FALSE;
break;
case isc_dyn_fld_edit_string:
GET_STRING(ptr, RFR.RDB$EDIT_STRING);
RFR.RDB$EDIT_STRING.NULL = FALSE;
break;
case isc_dyn_fld_position:
RFR.RDB$FIELD_POSITION = DYN_get_number(ptr);
RFR.RDB$FIELD_POSITION.NULL = FALSE;
break;
case isc_dyn_view_context:
RFR.RDB$VIEW_CONTEXT = DYN_get_number(ptr);
RFR.RDB$VIEW_CONTEXT.NULL = FALSE;
break;
case isc_dyn_system_flag:
RFR.RDB$SYSTEM_FLAG = FLD.RDB$SYSTEM_FLAG =
DYN_get_number(ptr);
RFR.RDB$SYSTEM_FLAG.NULL = FLD.RDB$SYSTEM_FLAG.NULL =
FALSE;
break;
case isc_dyn_update_flag:
RFR.RDB$UPDATE_FLAG = DYN_get_number(ptr);
RFR.RDB$UPDATE_FLAG.NULL = FALSE;
break;
case isc_dyn_fld_length:
FLD.RDB$FIELD_LENGTH = DYN_get_number(ptr);
break;
case isc_dyn_fld_computed_blr:
FLD.RDB$COMPUTED_BLR.NULL = FALSE;
DYN_put_blr_blob(gbl, ptr, &FLD.RDB$COMPUTED_BLR);
break;
case isc_dyn_fld_computed_source:
FLD.RDB$COMPUTED_SOURCE.NULL = FALSE;
DYN_put_text_blob(gbl, ptr, &FLD.RDB$COMPUTED_SOURCE);
break;
case isc_dyn_fld_default_value:
RFR.RDB$DEFAULT_VALUE.NULL = FALSE;
DYN_put_blr_blob(gbl, ptr, &RFR.RDB$DEFAULT_VALUE);
break;
case isc_dyn_fld_default_source:
RFR.RDB$DEFAULT_SOURCE.NULL = FALSE;
DYN_put_text_blob(gbl, ptr, &RFR.RDB$DEFAULT_SOURCE);
break;
case isc_dyn_fld_validation_blr:
FLD.RDB$VALIDATION_BLR.NULL = FALSE;
DYN_put_blr_blob(gbl, ptr, &FLD.RDB$VALIDATION_BLR);
break;
case isc_dyn_fld_not_null:
RFR.RDB$NULL_FLAG.NULL = FALSE;
RFR.RDB$NULL_FLAG = TRUE;
break;
case isc_dyn_fld_query_header:
DYN_put_blr_blob(gbl, ptr, &RFR.RDB$QUERY_HEADER);
RFR.RDB$QUERY_HEADER.NULL = FALSE;
break;
case isc_dyn_fld_type:
FLD.RDB$FIELD_TYPE = dtype = DYN_get_number(ptr);
switch (dtype)
{
case blr_short:
FLD.RDB$FIELD_LENGTH = 2;
break;
case blr_long:
case blr_float:
case blr_sql_date:
case blr_sql_time:
FLD.RDB$FIELD_LENGTH = 4;
break;
case blr_int64:
case blr_quad:
case blr_timestamp:
case blr_double:
case blr_d_float:
FLD.RDB$FIELD_LENGTH = 8;
break;
default:
if (dtype == blr_blob)
FLD.RDB$FIELD_LENGTH = 8;
break;
}
break;
case isc_dyn_fld_scale:
FLD.RDB$FIELD_SCALE = DYN_get_number(ptr);
FLD.RDB$FIELD_SCALE.NULL = FALSE;
break;
case isc_dyn_fld_precision:
FLD.RDB$FIELD_PRECISION = DYN_get_number(ptr);
FLD.RDB$FIELD_PRECISION.NULL = FALSE;
break;
case isc_dyn_fld_sub_type:
FLD.RDB$FIELD_SUB_TYPE = DYN_get_number(ptr);
FLD.RDB$FIELD_SUB_TYPE.NULL = FALSE;
break;
case isc_dyn_fld_char_length:
FLD.RDB$CHARACTER_LENGTH = DYN_get_number(ptr);
FLD.RDB$CHARACTER_LENGTH.NULL = FALSE;
break;
case isc_dyn_fld_character_set:
FLD.RDB$CHARACTER_SET_ID = DYN_get_number(ptr);
FLD.RDB$CHARACTER_SET_ID.NULL = FALSE;
break;
case isc_dyn_fld_collation:
/* Note: the global field's collation is not set, just
* the local field. There is no full "domain"
* created for the local field.
* This is the same decision for items like NULL_FLAG
*/
RFR.RDB$COLLATION_ID = DYN_get_number(ptr);
RFR.RDB$COLLATION_ID.NULL = FALSE;
break;
case isc_dyn_fld_dimensions:
FLD.RDB$DIMENSIONS = DYN_get_number(ptr);
FLD.RDB$DIMENSIONS.NULL = FALSE;
break;
case isc_dyn_fld_segment_length:
FLD.RDB$SEGMENT_LENGTH = DYN_get_number(ptr);
FLD.RDB$SEGMENT_LENGTH.NULL = FALSE;
break;
default:
--(*ptr);
MetaTmp(RFR.RDB$FIELD_SOURCE)
DYN_execute(gbl, ptr, relation_name, &tmp, NULL, NULL, NULL);
}
if (RFR.RDB$FIELD_POSITION.NULL == TRUE) {
fld_pos = -1;
fb_assert(relation_name);
DYN_UTIL_generate_field_position(tdbb, gbl, *relation_name,
&fld_pos);
if (fld_pos >= 0) {
RFR.RDB$FIELD_POSITION = ++fld_pos;
RFR.RDB$FIELD_POSITION.NULL = FALSE;
}
}
END_STORE;
if (!DYN_REQUEST(drq_s_sql_gfld))
DYN_REQUEST(drq_s_sql_gfld) = request;
request = old_request;
id = old_id;
END_STORE;
if (!DYN_REQUEST(drq_s_sql_lfld))
DYN_REQUEST(drq_s_sql_lfld) = request;
}
catch (const std::exception& ex) {
Firebird::stuff_exception(tdbb->tdbb_status_vector, ex);
if (id == drq_s_sql_lfld) {
DYN_rundown_request(request, id);
DYN_error_punt(true, 29, NULL, NULL, NULL, NULL, NULL);
/* msg 29: "STORE RDB$RELATION_FIELDS failed" */
}
else {
DYN_rundown_request(request, id);
DYN_error_punt(true, 28, NULL, NULL, NULL, NULL, NULL);
/* msg 28: "STORE RDB$FIELDS failed" */
}
}
}
void DYN_define_shadow( Global* gbl, const UCHAR** ptr)
{
/**************************************
*
* D Y N _ d e f i n e _ s h a d o w
*
**************************************
*
* Functional description
* Define a shadow.
*
**************************************/
thread_db* tdbb = JRD_get_thread_data();
Database* dbb = tdbb->tdbb_database;
bool found = false;
const SLONG shadow_number = DYN_get_number(ptr);
/* If a shadow set identified by the
shadow number already exists return error. */
jrd_req* request = CMP_find_request(tdbb, drq_l_shadow, DYN_REQUESTS);
try {
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
FIRST 1 X IN RDB$FILES WITH X.RDB$SHADOW_NUMBER EQ shadow_number
found = true;
END_FOR;
if (!DYN_REQUEST(drq_l_shadow)) {
DYN_REQUEST(drq_l_shadow) = request;
}
}
catch (const std::exception& ex) {
Firebird::stuff_exception(tdbb->tdbb_status_vector, ex);
DYN_rundown_request(request, drq_l_shadow);
DYN_error_punt(true, 164, NULL, NULL, NULL, NULL, NULL);
/* msg 164: "Shadow lookup failed" */
}
if (found) {
DYN_error_punt(false, 165, (TEXT*)(IPTR)shadow_number, NULL, NULL, NULL,
NULL);
/* msg 165: "Shadow %ld already exists" */
}
SLONG start = 0;
UCHAR verb;
while ((verb = *(*ptr)++) != isc_dyn_end)
{
switch (verb)
{
case isc_dyn_def_file:
DYN_define_file(gbl, ptr, shadow_number, &start, 157);
break;
default:
DYN_unsupported_verb();
}
}
}
void DYN_define_trigger(Global* gbl,
const UCHAR** ptr,
const Firebird::MetaName* relation_name,
Firebird::MetaName* trigger_name,
const bool ignore_perm)
{
/**************************************
*
* D Y N _ d e f i n e _ t r i g g e r
*
**************************************
*
* Functional description
* Define a trigger for a relation.
*
*
* if the ignore_perm flag is true, then this trigger must be defined
* now (and fired at run time) without making SQL permissions checks.
* In particular, one should not need control permissions on the table
* to define this trigger. Currently used to define triggers for
* cascading referential interity.
*
**************************************/
thread_db* tdbb = JRD_get_thread_data();
Database* dbb = tdbb->tdbb_database;
Firebird::MetaName t;
GET_STRING(ptr, t);
if (t.length() == 0)
{
DYN_UTIL_generate_trigger_name(tdbb, gbl, t);
}
if (t.length() == 0)
{
DYN_error_punt(false, 212, NULL, NULL, NULL, NULL, NULL);
/* msg 212: "Zero length identifiers not allowed" */
}
if (trigger_name) {
*trigger_name = t;
}
jrd_req* request = CMP_find_request(tdbb, drq_s_triggers, DYN_REQUESTS);
bool b_ending_store = false;
try {
STORE(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
X IN RDB$TRIGGERS
X.RDB$TRIGGER_TYPE.NULL = TRUE;
X.RDB$TRIGGER_SEQUENCE = 0;
X.RDB$TRIGGER_SEQUENCE.NULL = FALSE;
X.RDB$TRIGGER_INACTIVE = 0;
X.RDB$TRIGGER_INACTIVE.NULL = FALSE;
X.RDB$SYSTEM_FLAG.NULL = TRUE;
/* currently, we make no difference between ignoring permissions in
order to define this trigger and ignoring permissions checks when the
trigger fires. The RDB$FLAGS is used to indicate permissions checks
when the trigger fires. Later, if we need to make a difference
between these, then the caller should pass the required value
of RDB$FLAGS as an extra argument to this func. */
X.RDB$FLAGS = ignore_perm ? TRG_ignore_perm : 0;
X.RDB$FLAGS.NULL = FALSE;
if (relation_name) {
strcpy(X.RDB$RELATION_NAME, relation_name->c_str());
X.RDB$RELATION_NAME.NULL = FALSE;
}
else
X.RDB$RELATION_NAME.NULL = TRUE;
X.RDB$TRIGGER_BLR.NULL = TRUE;
X.RDB$TRIGGER_SOURCE.NULL = TRUE;
X.RDB$DESCRIPTION.NULL = TRUE;
strcpy(X.RDB$TRIGGER_NAME, t.c_str());
UCHAR verb;
while ((verb = *(*ptr)++) != isc_dyn_end)
{
switch (verb)
{
case isc_dyn_trg_type:
X.RDB$TRIGGER_TYPE = DYN_get_number(ptr);
X.RDB$TRIGGER_TYPE.NULL = FALSE;
break;
case isc_dyn_sql_object:
X.RDB$FLAGS |= TRG_sql;
X.RDB$FLAGS.NULL = FALSE;
break;
case isc_dyn_trg_sequence:
X.RDB$TRIGGER_SEQUENCE = DYN_get_number(ptr);
X.RDB$TRIGGER_SEQUENCE.NULL = FALSE;
break;
case isc_dyn_trg_inactive:
X.RDB$TRIGGER_INACTIVE = DYN_get_number(ptr);
X.RDB$TRIGGER_INACTIVE.NULL = FALSE;
break;
case isc_dyn_rel_name:
GET_STRING(ptr, X.RDB$RELATION_NAME);
X.RDB$RELATION_NAME.NULL = FALSE;
break;
case isc_dyn_trg_blr:
{
const UCHAR* blr = *ptr;
DYN_skip_attribute(ptr);
DYN_put_blr_blob(gbl, &blr, &X.RDB$TRIGGER_BLR);
X.RDB$TRIGGER_BLR.NULL = FALSE;
break;
}
case isc_dyn_trg_source:
{
const UCHAR* source = *ptr;
DYN_skip_attribute(ptr);
DYN_put_text_blob(gbl, &source, &X.RDB$TRIGGER_SOURCE);
X.RDB$TRIGGER_SOURCE.NULL = FALSE;
break;
}
case isc_dyn_description:
DYN_put_text_blob(gbl, ptr, &X.RDB$DESCRIPTION);
X.RDB$DESCRIPTION.NULL = FALSE;
break;
case isc_dyn_system_flag:
X.RDB$SYSTEM_FLAG = DYN_get_number(ptr);
X.RDB$SYSTEM_FLAG.NULL = FALSE;
/* fb_assert(!ignore_perm || ignore_perm
&& X.RDB$SYSTEM_FLAG == fb_sysflag_referential_constraint); */
break;
default:
--(*ptr);
MetaTmp(X.RDB$RELATION_NAME)
DYN_execute(gbl, ptr, &tmp, NULL, &t, NULL, NULL);
}
}
b_ending_store = true;
/* the END_STORE_SPECIAL adds the foll. lines of code to the END_STORE
if (ignore_perm)
request->req_flags |= req_ignore_perm;
after the request is compiled and before the request is sent.
It makes the current request (to define the trigger) go through
without checking any permissions lower in the engine */
END_STORE_SPECIAL;
if (ignore_perm)
request->req_flags &= ~req_ignore_perm;
if (!DYN_REQUEST(drq_s_triggers)) {
DYN_REQUEST(drq_s_triggers) = request;
}
}
catch (const std::exception& ex) {
Firebird::stuff_exception(tdbb->tdbb_status_vector, ex);
if (b_ending_store) {
DYN_rundown_request(request, drq_s_triggers);
DYN_error_punt(true, 31, NULL, NULL, NULL, NULL, NULL);
/* msg 31: "DEFINE TRIGGER failed" */
}
throw;
}
}
void DYN_define_trigger_msg(Global* gbl, const UCHAR** ptr, const Firebird::MetaName* trigger_name)
{
/**************************************
*
* D Y N _ d e f i n e _ t r i g g e r _ m s g
*
**************************************
*
* Functional description
* Define a trigger message.
*
**************************************/
thread_db* tdbb = JRD_get_thread_data();
Database* dbb = tdbb->tdbb_database;
jrd_req* request = CMP_find_request(tdbb, drq_s_trg_msgs, DYN_REQUESTS);
bool b_ending_store = false;
try {
STORE(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
X IN RDB$TRIGGER_MESSAGES
X.RDB$MESSAGE_NUMBER = DYN_get_number(ptr);
X.RDB$MESSAGE.NULL = TRUE;
if (trigger_name) {
strcpy(X.RDB$TRIGGER_NAME, trigger_name->c_str());
X.RDB$TRIGGER_NAME.NULL = FALSE;
}
else {
X.RDB$TRIGGER_NAME.NULL = TRUE;
}
UCHAR verb;
while ((verb = *(*ptr)++) != isc_dyn_end)
{
switch (verb)
{
case isc_dyn_trg_name:
GET_STRING(ptr, X.RDB$TRIGGER_NAME);
X.RDB$TRIGGER_NAME.NULL = FALSE;
break;
case isc_dyn_trg_msg:
GET_STRING(ptr, X.RDB$MESSAGE);
X.RDB$MESSAGE.NULL = FALSE;
break;
default:
DYN_unsupported_verb();
}
}
b_ending_store = true;
END_STORE;
if (!DYN_REQUEST(drq_s_trg_msgs)) {
DYN_REQUEST(drq_s_trg_msgs) = request;
}
}
catch (const std::exception& ex) {
Firebird::stuff_exception(tdbb->tdbb_status_vector, ex);
if (b_ending_store) {
DYN_rundown_request(request, drq_s_trg_msgs);
DYN_error_punt(true, 33, NULL, NULL, NULL, NULL, NULL);
/* msg 33: "DEFINE TRIGGER MESSAGE failed" */
}
throw;
}
}
void DYN_define_view_relation( Global* gbl, const UCHAR** ptr, const Firebird::MetaName* view)
{
/**************************************
*
* D Y N _ d e f i n e _ v i e w _ r e l a t i o n
*
**************************************
*
* Functional description
* Store a RDB$VIEW_RELATION record.
*
**************************************/
thread_db* tdbb = JRD_get_thread_data();
Database* dbb = tdbb->tdbb_database;
fb_assert(view);
if (view->length() == 0) {
DYN_error_punt(false, 212, NULL, NULL, NULL, NULL, NULL);
/* msg 212: "Zero length identifiers not allowed" */
}
jrd_req* request = CMP_find_request(tdbb, drq_s_view_rels, DYN_REQUESTS);
SSHORT id = drq_s_view_rels;
bool b_ending_store = false;
try {
/*
* The below code has been added for ALTER VIEW support,
* but implementation was definitely wrong,
* so it's commented our till the better times
*
const SSHORT old_id = id;
jrd_req* old_request = request;
request = CMP_find_request(tdbb, drq_e_view_rels, DYN_REQUESTS);
id = drq_e_view_rels;
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
VRL IN RDB$VIEW_RELATIONS WITH VRL.RDB$VIEW_NAME EQ view->c_str()
if (!DYN_REQUEST(drq_e_view_rels))
DYN_REQUEST(drq_e_view_rels) = request;
ERASE VRL;
END_FOR;
if (!DYN_REQUEST(drq_e_view_rels))
DYN_REQUEST(drq_e_view_rels) = request;
request = old_request;
id = old_id;
*/
STORE(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
VRL IN RDB$VIEW_RELATIONS
strcpy(VRL.RDB$VIEW_NAME, view->c_str());
GET_STRING(ptr, VRL.RDB$RELATION_NAME);
VRL.RDB$CONTEXT_NAME.NULL = TRUE;
VRL.RDB$VIEW_CONTEXT.NULL = TRUE;
UCHAR verb;
while ((verb = *(*ptr)++) != isc_dyn_end)
{
switch (verb)
{
case isc_dyn_view_context:
VRL.RDB$VIEW_CONTEXT = DYN_get_number(ptr);
VRL.RDB$VIEW_CONTEXT.NULL = FALSE;
break;
case isc_dyn_view_context_name:
GET_STRING(ptr, VRL.RDB$CONTEXT_NAME);
VRL.RDB$CONTEXT_NAME.NULL = FALSE;
break;
default:
--(*ptr);
MetaTmp(VRL.RDB$RELATION_NAME)
DYN_execute(gbl, ptr, &tmp, NULL, NULL, NULL, NULL);
}
}
b_ending_store = true;
END_STORE;
if (!DYN_REQUEST(drq_s_view_rels)) {
DYN_REQUEST(drq_s_view_rels) = request;
}
}
catch (const std::exception& ex) {
Firebird::stuff_exception(tdbb->tdbb_status_vector, ex);
if (b_ending_store) {
DYN_rundown_request(request, id);
if (id == drq_s_view_rels)
{
DYN_error_punt(true, 34, NULL, NULL, NULL, NULL, NULL);
/* msg 34: "STORE RDB$VIEW_RELATIONS failed" */
}
else if (id == drq_e_view_rels)
{
DYN_error_punt(true, 59, NULL, NULL, NULL, NULL, NULL);
/* msg 59: "ERASE RDB$VIEW_RELATIONS failed" */
}
}
throw;
}
}
static void check_unique_name( thread_db* tdbb,
Global* gbl,
const Firebird::MetaName& object_name,
bool proc_flag)
{
/**************************************
*
* c h e c k _ u n i q u e _ n a m e
*
**************************************
*
* Functional description
* Check if a procedure, view or relation by
* name of object_name already exists.
* If yes then return error.
*
**************************************/
bool found = false;
SET_TDBB(tdbb);
Database* dbb = tdbb->tdbb_database;
jrd_req* request = NULL;
try {
request = CMP_find_request(tdbb, drq_l_rel_name, DYN_REQUESTS);
found = false;
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
EREL IN RDB$RELATIONS WITH EREL.RDB$RELATION_NAME EQ object_name.c_str()
if (!DYN_REQUEST(drq_l_rel_name)) {
DYN_REQUEST(drq_l_rel_name) = request;
}
found = true;
END_FOR;
if (!DYN_REQUEST(drq_l_rel_name))
DYN_REQUEST(drq_l_rel_name) = request;
if (found) {
goto local_punt_false_132;
}
request = CMP_find_request(tdbb, drq_l_prc_name, DYN_REQUESTS);
found = false;
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
EPRC IN RDB$PROCEDURES WITH EPRC.RDB$PROCEDURE_NAME EQ object_name.c_str()
if (!DYN_REQUEST(drq_l_prc_name)) {
DYN_REQUEST(drq_l_prc_name) = request;
}
found = true;
END_FOR;
if (!DYN_REQUEST(drq_l_prc_name)) {
DYN_REQUEST(drq_l_prc_name) = request;
}
}
catch (const std::exception& ex) {
Firebird::stuff_exception(tdbb->tdbb_status_vector, ex);
DYN_rundown_request(request, -1);
if (!proc_flag)
DYN_error_punt(true, 24, NULL, NULL, NULL, NULL, NULL);
/* msg 24: "STORE RDB$RELATIONS failed" */
DYN_error_punt(true, 134, NULL, NULL, NULL, NULL, NULL);
}
if (found) {
DYN_error_punt(false, 135, object_name.c_str(), NULL, NULL, NULL, NULL);
}
return;
local_punt_false_132:
DYN_error_punt(false, 132, object_name.c_str(), NULL, NULL, NULL, NULL);
}
static bool find_field_source(thread_db* tdbb,
Global* gbl,
const Firebird::MetaName& view_name,
USHORT context,
const TEXT* local_name,
TEXT* output_field_name)
{
/**************************************
*
* f i n d _ f i e l d _ s o u r c e
*
**************************************
*
* Functional description
* Find the original source for a view field.
*
**************************************/
SET_TDBB(tdbb);
Database* dbb = tdbb->tdbb_database;
jrd_req* request = NULL;
/* CVC: It seems the logic of this function was changed over time. It's unlikely
it will cause a failure that leads to call DYN_error_punt(), unless the request finds
problems due to database corruption or unexpected ODS changes. Under normal
circumstances, it will return either true or false. When true, we found a field source
for the view's name/context/field and are loading this value in the last parameter,
that can be used against rdb$fields' rdb$field_name. */
bool found = false;
try {
request = CMP_find_request(tdbb, drq_l_fld_src2, DYN_REQUESTS);
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
VRL IN RDB$VIEW_RELATIONS CROSS
RFR IN RDB$RELATION_FIELDS OVER RDB$RELATION_NAME
WITH VRL.RDB$VIEW_NAME EQ view_name.c_str() AND
VRL.RDB$VIEW_CONTEXT EQ context AND
RFR.RDB$FIELD_NAME EQ local_name
if (!DYN_REQUEST(drq_l_fld_src2)) {
DYN_REQUEST(drq_l_fld_src2) = request;
}
found = true;
fb_utils::exact_name_limit(RFR.RDB$FIELD_SOURCE, sizeof(RFR.RDB$FIELD_SOURCE));
strcpy(output_field_name, RFR.RDB$FIELD_SOURCE);
END_FOR;
if (!DYN_REQUEST(drq_l_fld_src2)) {
DYN_REQUEST(drq_l_fld_src2) = request;
}
if (!found)
{
request = CMP_find_request(tdbb, drq_l_fld_src3, DYN_REQUESTS);
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
VRL IN RDB$VIEW_RELATIONS CROSS
PPR IN RDB$PROCEDURE_PARAMETERS
WITH VRL.RDB$RELATION_NAME EQ PPR.RDB$PROCEDURE_NAME AND
VRL.RDB$VIEW_NAME EQ view_name.c_str() AND
VRL.RDB$VIEW_CONTEXT EQ context AND
PPR.RDB$PARAMETER_NAME EQ local_name
if (!DYN_REQUEST(drq_l_fld_src3)) {
DYN_REQUEST(drq_l_fld_src3) = request;
}
found = true;
fb_utils::exact_name_limit(PPR.RDB$FIELD_SOURCE, sizeof(PPR.RDB$FIELD_SOURCE));
strcpy(output_field_name, PPR.RDB$FIELD_SOURCE);
END_FOR;
if (!DYN_REQUEST(drq_l_fld_src3)) {
DYN_REQUEST(drq_l_fld_src3) = request;
}
}
}
catch (const std::exception& ex) {
Firebird::stuff_exception(tdbb->tdbb_status_vector, ex);
DYN_rundown_request(request, -1);
DYN_error_punt(true, 80, NULL, NULL, NULL, NULL, NULL);
/* msg 80: "Specified domain or source field does not exist" */
}
return found;
}
static bool get_who( thread_db* tdbb, Global* gbl, Firebird::MetaName& output_name)
{
/**************************************
*
* g e t _ w h o
*
**************************************
*
* Functional description
* Get user name
*
**************************************/
SET_TDBB(tdbb);
jrd_req* request = CMP_find_request(tdbb, drq_l_user_name, DYN_REQUESTS);
try {
if (!request)
{
request = CMP_compile2(tdbb, who_blr, TRUE);
}
EXE_start(tdbb, request, gbl->gbl_transaction);
SqlIdentifier x;
EXE_receive(tdbb, request, 0, sizeof(x), (UCHAR*) x);
output_name = x;
DYN_rundown_request(request, drq_l_user_name);
}
catch (const std::exception& ex) {
Firebird::stuff_exception(tdbb->tdbb_status_vector, ex);
DYN_rundown_request(request, drq_l_user_name);
return false;
}
return true;
}
bool is_it_user_name(Global* gbl, const Firebird::MetaName& role_name, thread_db* tdbb)
{
/**************************************
*
* i s _ i t _ u s e r _ n a m e
*
**************************************
*
* Functional description
*
* if role_name is user name returns true. Otherwise returns false.
*
**************************************/
jrd_req* request;
USHORT request_id;
SET_TDBB(tdbb);
Database* dbb = tdbb->tdbb_database;
bool found = false;
try {
/* If there is a user with privilege or a grantor on a relation we
can infer there is a user with this name */
request_id = drq_get_user_priv;
request = CMP_find_request(tdbb, request_id, DYN_REQUESTS);
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
PRIV IN RDB$USER_PRIVILEGES WITH
(PRIV.RDB$USER EQ role_name.c_str() AND
PRIV.RDB$USER_TYPE = obj_user) OR
(PRIV.RDB$GRANTOR EQ role_name.c_str() AND
PRIV.RDB$OBJECT_TYPE = obj_relation)
found = true;
END_FOR;
if (!DYN_REQUEST(drq_get_user_priv))
DYN_REQUEST(drq_get_user_priv) = request;
if (found) {
return found;
}
/* We can infer that 'role_name' is a user name if it owns any relations
Note we can only get here if a user creates a table and revokes all
his privileges on the table */
request_id = drq_get_rel_owner;
request = CMP_find_request(tdbb, request_id, DYN_REQUESTS);
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
REL IN RDB$RELATIONS WITH
REL.RDB$OWNER_NAME EQ role_name.c_str()
found = true;
END_FOR;
if (!DYN_REQUEST(drq_get_rel_owner)) {
DYN_REQUEST(drq_get_rel_owner) = request;
}
}
catch (const std::exception& ex) {
Firebird::stuff_exception(tdbb->tdbb_status_vector, ex);
if (request) {
DYN_rundown_request(request, request_id);
}
ERR_punt();
}
return found;
}
static USHORT skip_blr_blob(const UCHAR** ptr)
{
/**************************************
*
* s k i p _ b l r _ b l o b
*
**************************************
*
* Functional description
* Skip a blr blob.
*
**************************************/
const UCHAR* p = *ptr;
USHORT length = *p++;
length |= (*p++) << 8;
if (!length) {
*ptr = p;
return length;
}
*ptr = p + length;
return length;
}