2001-05-23 15:26:42 +02:00
|
|
|
/*
|
|
|
|
* PROGRAM: JRD Access Method
|
2003-09-25 13:49:12 +02:00
|
|
|
* MODULE: met.epp
|
2001-05-23 15:26:42 +02:00
|
|
|
* DESCRIPTION: Meta data handler
|
|
|
|
*
|
|
|
|
* 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): ______________________________________.
|
2002-02-24 17:39:31 +01:00
|
|
|
*
|
2002-07-01 18:59:09 +02:00
|
|
|
* 2001.6.25 Claudio Valderrama: Finish MET_lookup_generator_id() by
|
|
|
|
* assigning it a number in the compiled requests table.
|
|
|
|
*
|
|
|
|
* 2001.07.06 Sean Leyne - Code Cleanup, removed "#ifdef READONLY_DATABASE"
|
|
|
|
* conditionals, as the engine now fully supports
|
|
|
|
* readonly databases.
|
|
|
|
* 2001.10.03 Claudio Valderrama: MET_relation_owns_trigger() determines if
|
|
|
|
* there's a row in rdb$triggers with the given relation's and trigger's names.
|
|
|
|
* 2001.10.04 Claudio Valderrama: MET_relation_default_class() determines if the
|
|
|
|
* given security class name is the default security class for a relation.
|
|
|
|
* Modify MET_lookup_field() so it can verify the field's security class, too.
|
2002-09-19 18:02:58 +02:00
|
|
|
* 2002-02-24 Sean Leyne - Code Cleanup of old Win 3.1 port (WINDOWS_ONLY)
|
|
|
|
* 2002-09-16 Nickolay Samofatov - Deferred trigger compilation changes
|
2002-10-30 07:40:58 +01:00
|
|
|
* 2002.10.29 Sean Leyne - Removed obsolete "Netware" port
|
2004-01-16 13:59:16 +01:00
|
|
|
* 2004.01.16 Vlad Horsun: added support for default parameters
|
2001-05-23 15:26:42 +02:00
|
|
|
*/
|
|
|
|
/*
|
2004-03-19 07:14:53 +01:00
|
|
|
$Id: met.epp,v 1.98 2004-03-19 06:14:47 robocop Exp $
|
2001-05-23 15:26:42 +02:00
|
|
|
*/
|
2001-12-24 03:51:06 +01:00
|
|
|
// This MUST be at the top of the file
|
|
|
|
#ifdef DARWIN
|
|
|
|
#define _STLP_CCTYPE
|
|
|
|
#endif
|
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2001-07-29 19:42:23 +02:00
|
|
|
#include "firebird.h"
|
2001-05-23 15:26:42 +02:00
|
|
|
#include "../jrd/ib_stdio.h"
|
|
|
|
#include <string.h>
|
|
|
|
#include "../jrd/common.h"
|
|
|
|
#include <stdarg.h>
|
|
|
|
|
|
|
|
#include "../jrd/constants.h"
|
2003-11-08 17:40:17 +01:00
|
|
|
#include "../jrd/y_ref.h"
|
|
|
|
#include "../jrd/ibase.h"
|
2001-05-23 15:26:42 +02:00
|
|
|
#include "../jrd/jrd.h"
|
|
|
|
#include "../jrd/val.h"
|
|
|
|
#include "../jrd/irq.h"
|
|
|
|
#include "../jrd/tra.h"
|
|
|
|
#include "../jrd/lck.h"
|
|
|
|
#include "../jrd/ods.h"
|
|
|
|
#include "../jrd/btr.h"
|
|
|
|
#include "../jrd/req.h"
|
|
|
|
#include "../jrd/exe.h"
|
|
|
|
#include "../jrd/scl.h"
|
|
|
|
#include "../jrd/blb.h"
|
|
|
|
#include "../jrd/met.h"
|
2003-07-14 12:35:49 +02:00
|
|
|
#include "../jrd/os/pio.h"
|
2001-05-23 15:26:42 +02:00
|
|
|
#include "../jrd/sdw.h"
|
|
|
|
#include "../jrd/flags.h"
|
|
|
|
#include "../jrd/all.h"
|
|
|
|
#include "../jrd/lls.h"
|
|
|
|
#include "../jrd/intl.h"
|
|
|
|
#include "../jrd/align.h"
|
|
|
|
#include "../jrd/flu.h"
|
|
|
|
#include "../jrd/blob_filter.h"
|
|
|
|
#include "../intl/charsets.h"
|
|
|
|
#include "../jrd/gdsassert.h"
|
|
|
|
#include "../jrd/all_proto.h"
|
|
|
|
#include "../jrd/blb_proto.h"
|
|
|
|
#include "../jrd/cmp_proto.h"
|
|
|
|
#include "../jrd/dfw_proto.h"
|
|
|
|
#include "../jrd/dsc_proto.h"
|
|
|
|
#include "../jrd/err_proto.h"
|
|
|
|
#include "../jrd/exe_proto.h"
|
|
|
|
#include "../jrd/ext_proto.h"
|
|
|
|
#include "../jrd/flu_proto.h"
|
|
|
|
#include "../jrd/gds_proto.h"
|
|
|
|
#include "../jrd/idx_proto.h"
|
|
|
|
#include "../jrd/ini_proto.h"
|
|
|
|
|
|
|
|
#include "../jrd/lck_proto.h"
|
|
|
|
#include "../jrd/met_proto.h"
|
|
|
|
#include "../jrd/mov_proto.h"
|
|
|
|
#include "../jrd/par_proto.h"
|
|
|
|
#include "../jrd/pcmet_proto.h"
|
2003-07-14 12:35:49 +02:00
|
|
|
#include "../jrd/os/pio_proto.h"
|
2001-05-23 15:26:42 +02:00
|
|
|
#include "../jrd/scl_proto.h"
|
|
|
|
#include "../jrd/sdw_proto.h"
|
|
|
|
#include "../jrd/thd_proto.h"
|
|
|
|
#include "../jrd/sch_proto.h"
|
|
|
|
#include "../jrd/iberr.h"
|
2003-12-31 06:36:12 +01:00
|
|
|
#include "../common/utils_proto.h"
|
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2001-07-12 08:32:05 +02:00
|
|
|
#ifdef HAVE_CTYPE_H
|
|
|
|
#include <ctype.h>
|
|
|
|
#endif
|
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
/* Pick up relation ids */
|
|
|
|
|
|
|
|
#define RELATION(name,id,ods) id,
|
|
|
|
#define FIELD(symbol,name,id,update,ods,new_id,new_ods)
|
|
|
|
#define END_RELATION
|
|
|
|
|
2003-08-22 12:56:55 +02:00
|
|
|
typedef enum rids {
|
2003-08-04 01:54:39 +02:00
|
|
|
#include "../jrd/relations.h"
|
2001-05-23 15:26:42 +02:00
|
|
|
rel_MAX
|
|
|
|
} RIDS;
|
|
|
|
|
|
|
|
#undef RELATION
|
|
|
|
#undef FIELD
|
|
|
|
#undef END_RELATION
|
|
|
|
|
2003-09-28 23:36:05 +02:00
|
|
|
#define BLR_BYTE *(csb->csb_running)++
|
2001-05-23 15:26:42 +02:00
|
|
|
#define BLANK '\040'
|
|
|
|
|
|
|
|
DATABASE DB = FILENAME "ODS.RDB";
|
|
|
|
|
2004-03-18 06:56:06 +01:00
|
|
|
static int blocking_ast_procedure(void*);
|
|
|
|
static int blocking_ast_relation(void*);
|
2004-03-11 06:04:26 +01:00
|
|
|
static void get_trigger(thread_db*, jrd_rel*, bid*, trig_vec**, const TEXT*, bool, USHORT);
|
|
|
|
static bool get_type(thread_db*, SSHORT*, const UCHAR*, const TEXT*);
|
|
|
|
static void lookup_view_contexts(thread_db*, jrd_rel*);
|
2003-12-11 11:33:30 +01:00
|
|
|
static void name_copy(TEXT*, const TEXT*);
|
2003-02-13 11:11:35 +01:00
|
|
|
static USHORT name_length(const TEXT *);
|
2004-03-11 06:04:26 +01:00
|
|
|
static jrd_nod* parse_param_blr(thread_db*, jrd_prc*, bid*, Csb*);
|
|
|
|
static jrd_nod* parse_procedure_blr(thread_db*, jrd_prc*, bid*, Csb*);
|
|
|
|
static bool par_messages(thread_db*, const UCHAR*, USHORT, jrd_prc*, Csb*);
|
|
|
|
static bool resolve_charset_and_collation(thread_db*, SSHORT*, const UCHAR*,
|
2003-12-11 11:33:30 +01:00
|
|
|
const UCHAR*);
|
2004-03-11 06:04:26 +01:00
|
|
|
static str* save_name(thread_db*, const TEXT*);
|
|
|
|
static void save_trigger_data(thread_db*, trig_vec**, jrd_rel*, JRD_REQ, STR,
|
2003-12-03 09:19:24 +01:00
|
|
|
const TEXT*, bool, USHORT);
|
2004-03-11 06:04:26 +01:00
|
|
|
static void store_dependencies(thread_db*, Csb*, const TEXT*, USHORT);
|
|
|
|
static bool verify_TRG_ignore_perm(thread_db*, const TEXT*);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
2002-09-28 00:59:24 +02:00
|
|
|
// Decompile all triggers from vector
|
2004-03-11 06:04:26 +01:00
|
|
|
void release_cached_triggers(thread_db* tdbb, trig_vec* vector)
|
2002-09-28 00:59:24 +02:00
|
|
|
{
|
2004-01-03 11:59:52 +01:00
|
|
|
if (!vector) {
|
2003-12-22 11:00:59 +01:00
|
|
|
return;
|
2004-01-03 11:59:52 +01:00
|
|
|
}
|
2002-09-28 00:59:24 +02:00
|
|
|
|
2004-01-03 11:59:52 +01:00
|
|
|
trig_vec::iterator ptr = vector->begin();
|
|
|
|
for (const trig_vec::const_iterator end = vector->end(); ptr < end; ptr++) {
|
2002-09-28 00:59:24 +02:00
|
|
|
ptr->release(tdbb);
|
2004-01-03 11:59:52 +01:00
|
|
|
}
|
2002-09-28 00:59:24 +02:00
|
|
|
}
|
|
|
|
|
2003-12-06 03:58:22 +01:00
|
|
|
// Increment int_use_count for all procedures used by triggers
|
2004-03-11 06:04:26 +01:00
|
|
|
void post_used_procedures(thread_db* tdbb, trig_vec* vector)
|
2003-12-06 03:58:22 +01:00
|
|
|
{
|
2004-01-03 11:59:52 +01:00
|
|
|
if (!vector) {
|
2003-12-22 11:00:59 +01:00
|
|
|
return;
|
2004-01-03 11:59:52 +01:00
|
|
|
}
|
2003-12-22 11:00:59 +01:00
|
|
|
|
2004-01-03 11:59:52 +01:00
|
|
|
trig_vec::iterator ptr = vector->begin();
|
|
|
|
for (const trig_vec::const_iterator end = vector->end(); ptr < end; ptr++) {
|
2003-12-06 03:58:22 +01:00
|
|
|
if (ptr->request) {
|
2004-02-20 07:43:27 +01:00
|
|
|
for (Resource* resource = ptr->request->req_resources; resource;
|
2003-12-06 03:58:22 +01:00
|
|
|
resource = resource->rsc_next)
|
|
|
|
{
|
2004-02-20 07:43:27 +01:00
|
|
|
if (resource->rsc_type == Resource::rsc_procedure) {
|
2003-12-22 11:00:59 +01:00
|
|
|
++resource->rsc_prc->prc_int_use_count;
|
2004-01-03 11:59:52 +01:00
|
|
|
}
|
2003-12-06 03:58:22 +01:00
|
|
|
}
|
|
|
|
}
|
2003-12-22 11:00:59 +01:00
|
|
|
}
|
2003-12-06 03:58:22 +01:00
|
|
|
}
|
|
|
|
|
2004-03-11 06:04:26 +01:00
|
|
|
void MET_update_partners(thread_db* tdbb)
|
2002-09-30 16:21:34 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* M E T _ u p d a t e _ p a r t n e r s
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Mark all relations to update their links to FK partners
|
|
|
|
* Called when any index is deleted because engine don't know
|
|
|
|
* was it used in any FK or not
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
SET_TDBB(tdbb);
|
2004-03-07 08:58:55 +01:00
|
|
|
Database* dbb = tdbb->tdbb_database;
|
2002-09-30 16:21:34 +02:00
|
|
|
|
2003-12-22 11:00:59 +01:00
|
|
|
vec* relations = dbb->dbb_relations;
|
2002-09-30 16:21:34 +02:00
|
|
|
|
2004-01-03 11:59:52 +01:00
|
|
|
vec::iterator ptr = relations->begin();
|
|
|
|
for (const vec::const_iterator end = relations->end(); ptr < end; ptr++)
|
2002-09-30 16:21:34 +02:00
|
|
|
{
|
2003-12-22 11:00:59 +01:00
|
|
|
jrd_rel* relation = reinterpret_cast<jrd_rel*>(*ptr);
|
2004-01-03 11:59:52 +01:00
|
|
|
if (!relation) {
|
2003-12-22 11:00:59 +01:00
|
|
|
continue;
|
2004-01-03 11:59:52 +01:00
|
|
|
}
|
2002-09-30 16:21:34 +02:00
|
|
|
relation->rel_flags |= REL_check_partners;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-12-22 11:00:59 +01:00
|
|
|
void adjust_dependencies(jrd_prc* procedure) {
|
2004-01-03 11:59:52 +01:00
|
|
|
if (procedure->prc_int_use_count == -1) {
|
2002-10-05 00:08:43 +02:00
|
|
|
// Already processed
|
|
|
|
return;
|
2004-01-03 11:59:52 +01:00
|
|
|
}
|
2003-12-22 11:00:59 +01:00
|
|
|
procedure->prc_int_use_count = -1; // Mark as undeletable
|
2003-06-30 15:11:40 +02:00
|
|
|
if (procedure->prc_request) {
|
2004-02-20 07:43:27 +01:00
|
|
|
for (Resource* resource = procedure->prc_request->req_resources; resource;
|
2002-10-05 00:08:43 +02:00
|
|
|
resource = resource->rsc_next)
|
2003-06-30 15:11:40 +02:00
|
|
|
{
|
2004-02-20 07:43:27 +01:00
|
|
|
if (resource->rsc_type == Resource::rsc_procedure) {
|
2003-06-30 15:11:40 +02:00
|
|
|
procedure = resource->rsc_prc;
|
2004-01-03 11:59:52 +01:00
|
|
|
if (procedure->prc_int_use_count == procedure->prc_use_count) {
|
2003-06-30 15:11:40 +02:00
|
|
|
// Mark it and all dependent procedures as undeletable
|
|
|
|
adjust_dependencies(procedure);
|
|
|
|
}
|
2002-10-05 00:08:43 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-06-01 18:22:47 +02:00
|
|
|
#ifdef DEV_BUILD
|
2004-03-11 06:04:26 +01:00
|
|
|
void MET_verify_cache(thread_db* tdbb) {
|
2003-06-01 18:22:47 +02:00
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* M E T _ v e r i f y _ c a c h e
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Check if all links between procedures are properly counted
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
SET_TDBB(tdbb);
|
2004-03-07 08:58:55 +01:00
|
|
|
Database* dbb = tdbb->tdbb_database;
|
2003-06-01 18:22:47 +02:00
|
|
|
|
2003-12-22 11:00:59 +01:00
|
|
|
vec* procedures = dbb->dbb_procedures;
|
|
|
|
if (procedures) {
|
|
|
|
jrd_prc* procedure;
|
|
|
|
vec::iterator ptr, end;
|
|
|
|
|
2003-06-01 18:22:47 +02:00
|
|
|
for (ptr = procedures->begin(), end = procedures->end();
|
|
|
|
ptr < end; ptr++)
|
|
|
|
{
|
2004-01-03 11:59:52 +01:00
|
|
|
if ( (procedure = (jrd_prc*)(*ptr)) && procedure->prc_request /*&&
|
2003-06-01 18:22:47 +02:00
|
|
|
!(procedure->prc_flags & PRC_obsolete)*/ )
|
|
|
|
{
|
2003-11-04 00:59:24 +01:00
|
|
|
fb_assert(procedure->prc_int_use_count == 0);
|
2003-06-01 18:22:47 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Walk procedures and calculate internal dependencies */
|
|
|
|
for (ptr = procedures->begin(), end = procedures->end();
|
|
|
|
ptr < end; ptr++)
|
|
|
|
{
|
2004-01-03 11:59:52 +01:00
|
|
|
if ( (procedure = (jrd_prc*)(*ptr)) && procedure->prc_request /*&&
|
2003-06-01 18:22:47 +02:00
|
|
|
!(procedure->prc_flags & PRC_obsolete)*/ )
|
|
|
|
{
|
2004-02-20 07:43:27 +01:00
|
|
|
for (Resource* resource = procedure->prc_request->req_resources;
|
|
|
|
resource; resource = resource->rsc_next)
|
2003-06-01 18:22:47 +02:00
|
|
|
{
|
2004-02-20 07:43:27 +01:00
|
|
|
if (resource->rsc_type == Resource::rsc_procedure) {
|
2003-11-04 00:59:24 +01:00
|
|
|
fb_assert(resource->rsc_prc->prc_int_use_count >= 0);
|
2003-06-01 18:22:47 +02:00
|
|
|
resource->rsc_prc->prc_int_use_count++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Walk procedures again and check dependencies */
|
|
|
|
for (ptr = procedures->begin(), end = procedures->end();
|
|
|
|
ptr < end; ptr++)
|
|
|
|
{
|
2004-01-03 11:59:52 +01:00
|
|
|
if ( (procedure = (jrd_prc*)(*ptr)) && procedure->prc_request && /*
|
2003-06-01 18:22:47 +02:00
|
|
|
!(procedure->prc_flags & PRC_obsolete) && */
|
|
|
|
procedure->prc_use_count < procedure->prc_int_use_count)
|
|
|
|
{
|
|
|
|
char buffer[1024], *buf = buffer;
|
|
|
|
buf += sprintf(buf, "Procedure %d:%s is not properly counted (use count=%d, prc use=%d). Used by: \n",
|
|
|
|
procedure->prc_id, procedure->prc_name->str_data, procedure->prc_use_count, procedure->prc_int_use_count);
|
2004-01-03 11:59:52 +01:00
|
|
|
vec::const_iterator ptr2 = procedures->begin();
|
|
|
|
for (const vec::const_iterator end2 = procedures->end();
|
|
|
|
ptr2 < end2; ptr2++)
|
2003-06-01 18:22:47 +02:00
|
|
|
{
|
2004-01-03 11:59:52 +01:00
|
|
|
const jrd_prc* prc = (jrd_prc*)(*ptr2);
|
|
|
|
if (prc && prc->prc_request /*&&
|
|
|
|
!(prc->prc_flags & PRC_obsolete)*/ )
|
2003-06-01 18:22:47 +02:00
|
|
|
{
|
2004-02-20 07:43:27 +01:00
|
|
|
for (const Resource* resource = prc->prc_request->req_resources;
|
|
|
|
resource; resource = resource->rsc_next)
|
2003-06-01 18:22:47 +02:00
|
|
|
{
|
2004-02-20 07:43:27 +01:00
|
|
|
if (resource->rsc_type == Resource::rsc_procedure) {
|
2003-06-01 18:22:47 +02:00
|
|
|
if (resource->rsc_prc == procedure) {
|
|
|
|
buf += sprintf(buf, "%d:%s\n", prc->prc_id, prc->prc_name->str_data);
|
|
|
|
}
|
2004-01-03 11:59:52 +01:00
|
|
|
}
|
2003-06-01 18:22:47 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
gds__log(buffer);
|
2003-11-04 00:59:24 +01:00
|
|
|
fb_assert(false);
|
2003-06-01 18:22:47 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Fix back int_use_count */
|
|
|
|
for (ptr = procedures->begin(), end = procedures->end();
|
|
|
|
ptr < end; ptr++)
|
|
|
|
{
|
2004-01-03 11:59:52 +01:00
|
|
|
if ( (procedure = (jrd_prc*)(*ptr)) )
|
2003-06-01 18:22:47 +02:00
|
|
|
{
|
|
|
|
procedure->prc_int_use_count = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2004-03-11 06:04:26 +01:00
|
|
|
bool MET_clear_cache(thread_db* tdbb, jrd_prc* proc)
|
2002-09-28 00:59:24 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
2002-10-05 00:08:43 +02:00
|
|
|
* M E T _ c l e a r _ c a c h e
|
2002-09-28 00:59:24 +02:00
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Try to release all resources locked by cached triggers
|
2002-10-05 00:08:43 +02:00
|
|
|
* do not remove proc procedure from cache because it will be
|
|
|
|
* handled by the caller
|
2002-09-28 00:59:24 +02:00
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
SET_TDBB(tdbb);
|
2003-06-01 18:22:47 +02:00
|
|
|
#ifdef DEV_BUILD
|
|
|
|
MET_verify_cache(tdbb);
|
|
|
|
#endif
|
2003-12-22 11:00:59 +01:00
|
|
|
vec::iterator ptr, end;
|
|
|
|
|
2004-03-07 08:58:55 +01:00
|
|
|
Database* dbb = tdbb->tdbb_database;
|
2003-12-22 11:00:59 +01:00
|
|
|
|
|
|
|
vec* relations = dbb->dbb_relations;
|
2002-09-28 00:59:24 +02:00
|
|
|
for (ptr = relations->begin(), end = relations->end(); ptr < end; ptr++)
|
|
|
|
{
|
2004-01-03 11:59:52 +01:00
|
|
|
jrd_rel* relation = reinterpret_cast<jrd_rel*>(*ptr);
|
2003-12-22 11:00:59 +01:00
|
|
|
if (!relation)
|
|
|
|
continue;
|
2004-03-11 06:04:26 +01:00
|
|
|
release_cached_triggers(tdbb, relation->rel_pre_store);
|
|
|
|
release_cached_triggers(tdbb, relation->rel_post_store);
|
|
|
|
release_cached_triggers(tdbb, relation->rel_pre_erase);
|
|
|
|
release_cached_triggers(tdbb, relation->rel_post_erase);
|
|
|
|
release_cached_triggers(tdbb, relation->rel_pre_modify);
|
|
|
|
release_cached_triggers(tdbb, relation->rel_post_modify);
|
2002-09-28 00:59:24 +02:00
|
|
|
}
|
|
|
|
|
2004-02-20 07:43:27 +01:00
|
|
|
bool result = true;
|
2002-09-28 00:59:24 +02:00
|
|
|
|
2003-12-22 11:00:59 +01:00
|
|
|
vec* procedures = dbb->dbb_procedures;
|
|
|
|
if (procedures) {
|
|
|
|
jrd_prc* procedure;
|
2002-10-05 00:08:43 +02:00
|
|
|
/* Walk procedures and calculate internal dependencies */
|
|
|
|
for (ptr = procedures->begin(), end = procedures->end();
|
|
|
|
ptr < end; ptr++)
|
|
|
|
{
|
2004-01-03 11:59:52 +01:00
|
|
|
if ( (procedure = (jrd_prc*)(*ptr)) && procedure->prc_request &&
|
2002-12-24 19:14:49 +01:00
|
|
|
!(procedure->prc_flags & PRC_obsolete) )
|
2002-09-28 00:59:24 +02:00
|
|
|
{
|
2004-02-20 07:43:27 +01:00
|
|
|
for (Resource* resource = procedure->prc_request->req_resources;
|
|
|
|
resource; resource = resource->rsc_next)
|
2002-09-28 00:59:24 +02:00
|
|
|
{
|
2004-02-20 07:43:27 +01:00
|
|
|
if (resource->rsc_type == Resource::rsc_procedure)
|
2002-10-05 00:08:43 +02:00
|
|
|
resource->rsc_prc->prc_int_use_count++;
|
2002-09-28 00:59:24 +02:00
|
|
|
}
|
|
|
|
}
|
2002-10-05 00:08:43 +02:00
|
|
|
}
|
|
|
|
|
2004-02-20 07:43:27 +01:00
|
|
|
// Walk procedures again and adjust dependencies for procedures
|
|
|
|
// which will not be removed.
|
2002-10-05 00:08:43 +02:00
|
|
|
for (ptr = procedures->begin(), end = procedures->end();
|
|
|
|
ptr < end; ptr++)
|
|
|
|
{
|
2004-01-03 11:59:52 +01:00
|
|
|
if ( (procedure = (jrd_prc*)(*ptr)) && procedure->prc_request &&
|
2002-12-24 19:14:49 +01:00
|
|
|
!(procedure->prc_flags & PRC_obsolete) &&
|
2004-02-20 07:43:27 +01:00
|
|
|
procedure->prc_use_count != procedure->prc_int_use_count
|
|
|
|
&& procedure != proc )
|
2002-10-05 00:08:43 +02:00
|
|
|
{
|
|
|
|
adjust_dependencies(procedure);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-11-14 14:39:02 +01:00
|
|
|
if (proc) {
|
2002-12-24 19:14:49 +01:00
|
|
|
result = proc->prc_use_count == proc->prc_int_use_count;
|
|
|
|
if (proc->prc_request)
|
|
|
|
adjust_dependencies(proc);
|
2002-11-14 14:39:02 +01:00
|
|
|
}
|
|
|
|
|
2002-10-05 00:08:43 +02:00
|
|
|
/* Deallocate all used requests */
|
|
|
|
for (ptr = procedures->begin(), end = procedures->end();
|
|
|
|
ptr < end; ptr++)
|
|
|
|
{
|
2004-01-03 11:59:52 +01:00
|
|
|
if ( (procedure = (jrd_prc*)(*ptr)) )
|
2002-10-05 00:08:43 +02:00
|
|
|
{
|
|
|
|
|
2003-06-01 18:22:47 +02:00
|
|
|
if ( procedure->prc_request &&
|
|
|
|
!(procedure->prc_flags & PRC_obsolete) &&
|
|
|
|
procedure->prc_int_use_count >= 0 &&
|
|
|
|
procedure->prc_use_count == procedure->prc_int_use_count &&
|
|
|
|
procedure != proc )
|
2002-10-05 00:08:43 +02:00
|
|
|
{
|
|
|
|
CMP_release(tdbb, procedure->prc_request);
|
|
|
|
procedure->prc_request = NULL;
|
2002-11-14 10:17:35 +01:00
|
|
|
LCK_release(tdbb, procedure->prc_existence_lock);
|
|
|
|
procedure->prc_existence_lock = NULL;
|
|
|
|
procedure->prc_flags |= PRC_obsolete;
|
2003-06-01 18:22:47 +02:00
|
|
|
}
|
|
|
|
// Leave it in state 0 to avoid extra pass next time to clear it
|
|
|
|
// Note: we need to adjust prc_int_use_count for all procedures
|
|
|
|
// in cache because any of them may have been affected from
|
|
|
|
// dependencies earlier. Even procedures that were not scanned yet !
|
|
|
|
procedure->prc_int_use_count = 0;
|
2002-10-05 00:08:43 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-11-14 10:17:35 +01:00
|
|
|
/* Remove deallocated procedures from cache */
|
|
|
|
for (ptr = procedures->begin(), end = procedures->end();
|
|
|
|
ptr < end; ptr++)
|
|
|
|
{
|
2004-01-03 11:59:52 +01:00
|
|
|
if ( (procedure = (jrd_prc*)(*ptr)) &&
|
2002-11-14 10:17:35 +01:00
|
|
|
(procedure->prc_flags & PRC_obsolete) && (procedure != proc) )
|
|
|
|
{
|
|
|
|
procedure->prc_flags &= ~PRC_being_altered; // Just a safety sake
|
|
|
|
MET_remove_procedure(tdbb, procedure->prc_id, procedure);
|
|
|
|
}
|
2002-10-05 00:08:43 +02:00
|
|
|
}
|
2002-11-16 19:48:01 +01:00
|
|
|
|
2002-10-05 00:08:43 +02:00
|
|
|
}
|
2003-06-01 18:22:47 +02:00
|
|
|
#ifdef DEV_BUILD
|
|
|
|
MET_verify_cache(tdbb);
|
|
|
|
#endif
|
2002-11-14 14:39:02 +01:00
|
|
|
return result;
|
2002-09-28 00:59:24 +02:00
|
|
|
}
|
|
|
|
|
2004-03-11 06:04:26 +01:00
|
|
|
bool MET_procedure_in_use(thread_db* tdbb, jrd_prc* proc)
|
2003-12-06 03:58:22 +01:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* M E T _ p r o c e d u r e _ i n _ u s e
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Determine if procedure is used by any user requests or transactions.
|
2004-02-20 07:43:27 +01:00
|
|
|
* Return false if procedure is used only inside cache or not used at all.
|
2003-12-06 03:58:22 +01:00
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
SET_TDBB(tdbb);
|
|
|
|
#ifdef DEV_BUILD
|
|
|
|
MET_verify_cache(tdbb);
|
|
|
|
#endif
|
2004-03-07 08:58:55 +01:00
|
|
|
Database* dbb = tdbb->tdbb_database;
|
2003-12-06 03:58:22 +01:00
|
|
|
|
|
|
|
// This should not really happen
|
2003-12-22 11:00:59 +01:00
|
|
|
vec* procedures = dbb->dbb_procedures;
|
2004-01-03 11:59:52 +01:00
|
|
|
if (!procedures) {
|
2004-02-20 07:43:27 +01:00
|
|
|
return false;
|
2004-01-03 11:59:52 +01:00
|
|
|
}
|
2003-12-06 03:58:22 +01:00
|
|
|
|
2003-12-22 11:00:59 +01:00
|
|
|
vec* relations = dbb->dbb_relations;
|
2003-12-06 03:58:22 +01:00
|
|
|
|
|
|
|
vec::iterator ptr, end;
|
|
|
|
for (ptr = relations->begin(), end = relations->end(); ptr < end; ptr++)
|
|
|
|
{
|
2004-01-03 11:59:52 +01:00
|
|
|
jrd_rel* relation = reinterpret_cast<jrd_rel*>(*ptr);
|
|
|
|
if (!relation) {
|
2003-12-22 11:00:59 +01:00
|
|
|
continue;
|
2004-01-03 11:59:52 +01:00
|
|
|
}
|
2004-03-11 06:04:26 +01:00
|
|
|
post_used_procedures(tdbb, relation->rel_pre_store);
|
|
|
|
post_used_procedures(tdbb, relation->rel_post_store);
|
|
|
|
post_used_procedures(tdbb, relation->rel_pre_erase);
|
|
|
|
post_used_procedures(tdbb, relation->rel_post_erase);
|
|
|
|
post_used_procedures(tdbb, relation->rel_pre_modify);
|
|
|
|
post_used_procedures(tdbb, relation->rel_post_modify);
|
2003-12-06 03:58:22 +01:00
|
|
|
}
|
2003-12-22 11:00:59 +01:00
|
|
|
|
|
|
|
jrd_prc* procedure;
|
2003-12-06 03:58:22 +01:00
|
|
|
/* Walk procedures and calculate internal dependencies */
|
|
|
|
for (ptr = procedures->begin(), end = procedures->end();
|
|
|
|
ptr < end; ptr++)
|
|
|
|
{
|
2004-01-03 11:59:52 +01:00
|
|
|
if ( (procedure = (jrd_prc*)(*ptr)) && procedure->prc_request &&
|
2003-12-06 03:58:22 +01:00
|
|
|
!(procedure->prc_flags & PRC_obsolete) )
|
|
|
|
{
|
2004-02-20 07:43:27 +01:00
|
|
|
for (Resource* resource = procedure->prc_request->req_resources;
|
|
|
|
resource; resource = resource->rsc_next)
|
2003-12-06 03:58:22 +01:00
|
|
|
{
|
2004-02-20 07:43:27 +01:00
|
|
|
if (resource->rsc_type == Resource::rsc_procedure)
|
2003-12-06 03:58:22 +01:00
|
|
|
resource->rsc_prc->prc_int_use_count++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-02-20 07:43:27 +01:00
|
|
|
// Walk procedures again and adjust dependencies for procedures
|
|
|
|
// which will not be removed.
|
2003-12-06 03:58:22 +01:00
|
|
|
for (ptr = procedures->begin(), end = procedures->end();
|
|
|
|
ptr < end; ptr++)
|
|
|
|
{
|
2004-01-03 11:59:52 +01:00
|
|
|
if ( (procedure = (jrd_prc*)(*ptr)) && procedure->prc_request &&
|
2003-12-06 03:58:22 +01:00
|
|
|
!(procedure->prc_flags & PRC_obsolete) &&
|
2004-02-20 07:43:27 +01:00
|
|
|
procedure->prc_use_count != procedure->prc_int_use_count &&
|
|
|
|
procedure != proc )
|
2003-12-06 03:58:22 +01:00
|
|
|
{
|
|
|
|
adjust_dependencies(procedure);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-02-20 07:43:27 +01:00
|
|
|
const bool result = proc->prc_use_count != proc->prc_int_use_count;
|
2003-12-06 03:58:22 +01:00
|
|
|
|
|
|
|
/* Fix back int_use_count */
|
|
|
|
for (ptr = procedures->begin(), end = procedures->end();
|
|
|
|
ptr < end; ptr++)
|
|
|
|
{
|
2004-01-03 11:59:52 +01:00
|
|
|
if ( (procedure = (jrd_prc*)(*ptr)) )
|
2003-12-06 03:58:22 +01:00
|
|
|
{
|
|
|
|
procedure->prc_int_use_count = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#ifdef DEV_BUILD
|
|
|
|
MET_verify_cache(tdbb);
|
|
|
|
#endif
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
|
2004-03-11 06:04:26 +01:00
|
|
|
void MET_activate_shadow( thread_db* tdbb)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* M E T _ a c t i v a t e _ s h a d o w
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Activate the current database, which presumably
|
|
|
|
* was formerly a shadow, by deleting all records
|
|
|
|
* corresponding to the shadow that this database
|
|
|
|
* represents.
|
|
|
|
* Get rid of write ahead log for the activated shadow.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
SET_TDBB(tdbb);
|
2004-03-07 08:58:55 +01:00
|
|
|
Database* dbb = tdbb->tdbb_database;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* Erase any secondary files of the primary database of the
|
|
|
|
shadow being activated. */
|
|
|
|
|
2003-12-22 11:00:59 +01:00
|
|
|
blk* handle = NULL;
|
2001-05-23 15:26:42 +02:00
|
|
|
FOR(REQUEST_HANDLE handle) X IN RDB$FILES
|
|
|
|
WITH X.RDB$SHADOW_NUMBER NOT MISSING
|
2001-07-12 08:32:05 +02:00
|
|
|
AND X.RDB$SHADOW_NUMBER EQ 0
|
2001-05-23 15:26:42 +02:00
|
|
|
ERASE X;
|
|
|
|
END_FOR;
|
|
|
|
|
2004-01-03 11:59:52 +01:00
|
|
|
CMP_release(tdbb, (jrd_req*)handle);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-12-22 11:00:59 +01:00
|
|
|
const char* dbb_file_name = dbb->dbb_file->fil_string;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* go through files looking for any that expand to the current database name */
|
2003-12-22 11:00:59 +01:00
|
|
|
SCHAR expanded_name[MAXPATHLEN];
|
|
|
|
blk* handle2 = handle = NULL;
|
2001-05-23 15:26:42 +02:00
|
|
|
FOR(REQUEST_HANDLE handle) X IN RDB$FILES
|
|
|
|
WITH X.RDB$SHADOW_NUMBER NOT MISSING
|
|
|
|
AND X.RDB$SHADOW_NUMBER NE 0
|
|
|
|
|
|
|
|
PIO_expand(X.RDB$FILE_NAME, (USHORT)strlen(X.RDB$FILE_NAME),
|
|
|
|
expanded_name);
|
|
|
|
|
|
|
|
if (!strcmp(expanded_name, dbb_file_name)) {
|
|
|
|
FOR(REQUEST_HANDLE handle2) Y IN RDB$FILES
|
|
|
|
WITH X.RDB$SHADOW_NUMBER EQ Y.RDB$SHADOW_NUMBER
|
|
|
|
MODIFY Y
|
|
|
|
Y.RDB$SHADOW_NUMBER = 0;
|
|
|
|
END_MODIFY;
|
|
|
|
END_FOR;
|
|
|
|
ERASE X;
|
|
|
|
}
|
|
|
|
END_FOR;
|
|
|
|
|
|
|
|
if (handle2)
|
|
|
|
{
|
2004-01-03 11:59:52 +01:00
|
|
|
CMP_release(tdbb, (jrd_req*)handle2);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2004-01-03 11:59:52 +01:00
|
|
|
CMP_release(tdbb, (jrd_req*)handle);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-12-22 11:00:59 +01:00
|
|
|
ULONG MET_align(const dsc* desc, USHORT value)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* M E T _ a l i g n
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Align value (presumed offset) on appropriate border
|
|
|
|
* and return.
|
|
|
|
*
|
|
|
|
**************************************/
|
2003-12-22 11:00:59 +01:00
|
|
|
USHORT alignment = desc->dsc_length;
|
2001-05-23 15:26:42 +02:00
|
|
|
switch (desc->dsc_dtype) {
|
|
|
|
case dtype_text:
|
|
|
|
case dtype_cstring:
|
|
|
|
return value;
|
|
|
|
|
|
|
|
case dtype_varying:
|
|
|
|
alignment = sizeof(USHORT);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
alignment = MIN(alignment, ALIGNMENT);
|
|
|
|
|
|
|
|
return FB_ALIGN(value, alignment);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-03-11 06:04:26 +01:00
|
|
|
void MET_change_fields( thread_db* tdbb, jrd_tra* transaction, DSC * field_source)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* M E T _ c h a n g e _ f i e l d s
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Somebody is modifying RDB$FIELDS. Find all relations affected
|
|
|
|
* and schedule a format update.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
SET_TDBB(tdbb);
|
2004-03-07 08:58:55 +01:00
|
|
|
Database* dbb = tdbb->tdbb_database;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-12-22 11:00:59 +01:00
|
|
|
dsc relation_name;
|
2004-02-20 07:43:27 +01:00
|
|
|
blk* request = CMP_find_request(tdbb, irq_m_fields, IRQ_REQUESTS);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
FOR(REQUEST_HANDLE request)
|
|
|
|
X IN RDB$RELATION_FIELDS WITH
|
2002-12-22 14:08:50 +01:00
|
|
|
X.RDB$FIELD_SOURCE EQ field_source->dsc_address
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-12-22 11:00:59 +01:00
|
|
|
if (!REQUEST(irq_m_fields))
|
|
|
|
REQUEST(irq_m_fields) = request;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
relation_name.dsc_dtype = dtype_text;
|
|
|
|
INTL_ASSIGN_DSC(&relation_name, CS_METADATA, COLLATE_NONE);
|
|
|
|
relation_name.dsc_length = sizeof(X.RDB$RELATION_NAME);
|
|
|
|
relation_name.dsc_address = (UCHAR *) X.RDB$RELATION_NAME;
|
|
|
|
SCL_check_relation(&relation_name, SCL_control);
|
|
|
|
DFW_post_work(transaction, dfw_update_format, &relation_name, 0);
|
|
|
|
END_FOR;
|
|
|
|
|
|
|
|
if (!REQUEST(irq_m_fields))
|
|
|
|
REQUEST(irq_m_fields) = request;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-03-11 06:04:26 +01:00
|
|
|
fmt* MET_current(thread_db* tdbb, jrd_rel* relation)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* M E T _ c u r r e n t
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Get the current format for a relation. The current format is the
|
|
|
|
* format in which new records are to be stored.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
|
|
|
if (relation->rel_current_format)
|
|
|
|
return relation->rel_current_format;
|
|
|
|
|
|
|
|
SET_TDBB(tdbb);
|
|
|
|
|
|
|
|
return relation->rel_current_format =
|
|
|
|
MET_format(tdbb, relation, relation->rel_current_fmt);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-03-11 06:04:26 +01:00
|
|
|
void MET_delete_dependencies(thread_db* tdbb,
|
2004-02-20 07:43:27 +01:00
|
|
|
const TEXT* object_name,
|
2001-05-23 15:26:42 +02:00
|
|
|
USHORT dependency_type)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* M E T _ d e l e t e _ d e p e n d e n c i e s
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
2001-07-12 08:32:05 +02:00
|
|
|
* Delete all dependencies for the specified
|
2001-05-23 15:26:42 +02:00
|
|
|
* object of given type.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
SET_TDBB(tdbb);
|
2004-03-07 08:58:55 +01:00
|
|
|
Database* dbb = tdbb->tdbb_database;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (!object_name)
|
|
|
|
return;
|
|
|
|
|
2004-02-20 07:43:27 +01:00
|
|
|
blk* request = CMP_find_request(tdbb, irq_d_deps, IRQ_REQUESTS);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
FOR(REQUEST_HANDLE request)
|
|
|
|
DEP IN RDB$DEPENDENCIES
|
|
|
|
WITH DEP.RDB$DEPENDENT_NAME = object_name
|
|
|
|
AND DEP.RDB$DEPENDENT_TYPE = dependency_type
|
|
|
|
|
|
|
|
if (!REQUEST(irq_d_deps)) REQUEST(irq_d_deps) = request;
|
|
|
|
|
|
|
|
ERASE DEP;
|
|
|
|
END_FOR;
|
|
|
|
|
|
|
|
if (!REQUEST(irq_d_deps))
|
|
|
|
REQUEST(irq_d_deps) = request;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-03-11 06:04:26 +01:00
|
|
|
void MET_delete_shadow( thread_db* tdbb, USHORT shadow_number)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* M E T _ d e l e t e _ s h a d o w
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
2001-07-12 08:32:05 +02:00
|
|
|
* Functional description
|
2001-05-23 15:26:42 +02:00
|
|
|
* When any of the shadows in RDB$FILES for a particular
|
|
|
|
* shadow are deleted, stop shadowing to that file and
|
|
|
|
* remove all other files from the same shadow.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
SET_TDBB(tdbb);
|
2004-03-07 08:58:55 +01:00
|
|
|
Database* dbb = tdbb->tdbb_database;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-12-22 11:00:59 +01:00
|
|
|
blk* handle = NULL;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
FOR(REQUEST_HANDLE handle)
|
2001-07-12 08:32:05 +02:00
|
|
|
X IN RDB$FILES WITH X.RDB$SHADOW_NUMBER EQ shadow_number
|
2001-05-23 15:26:42 +02:00
|
|
|
ERASE X;
|
|
|
|
END_FOR;
|
|
|
|
|
2004-01-03 11:59:52 +01:00
|
|
|
CMP_release(tdbb, (jrd_req*)handle);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-02-20 07:43:27 +01:00
|
|
|
for (Shadow* shadow = dbb->dbb_shadow; shadow; shadow = shadow->sdw_next) {
|
2004-01-03 11:59:52 +01:00
|
|
|
if (shadow->sdw_number == shadow_number) {
|
2001-05-23 15:26:42 +02:00
|
|
|
shadow->sdw_flags |= SDW_shutdown;
|
2004-01-03 11:59:52 +01:00
|
|
|
}
|
2003-12-22 11:00:59 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* notify other processes to check for shadow deletion */
|
2004-01-03 11:59:52 +01:00
|
|
|
if (SDW_lck_update((SLONG) 0)) {
|
2001-05-23 15:26:42 +02:00
|
|
|
SDW_notify();
|
2004-01-03 11:59:52 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-12-22 11:00:59 +01:00
|
|
|
void MET_error(const TEXT* string, ...)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* M E T _ e r r o r
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Post an error in a metadata update
|
|
|
|
* Oh, wow.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
TEXT s[128];
|
|
|
|
va_list ptr;
|
|
|
|
|
|
|
|
VA_START(ptr, string);
|
|
|
|
vsprintf(s, string, ptr);
|
|
|
|
|
2003-11-08 17:40:17 +01:00
|
|
|
ERR_post(isc_no_meta_update, isc_arg_gds, isc_random, isc_arg_string,
|
2001-05-23 15:26:42 +02:00
|
|
|
ERR_cstring(s), 0);
|
|
|
|
}
|
|
|
|
|
2004-03-11 06:04:26 +01:00
|
|
|
fmt* MET_format(thread_db* tdbb, jrd_rel* relation, USHORT number)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* M E T _ f o r m a t
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Lookup a format for given relation.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
SET_TDBB(tdbb);
|
2004-03-07 08:58:55 +01:00
|
|
|
Database* dbb = tdbb->tdbb_database;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-12-22 11:00:59 +01:00
|
|
|
fmt* format;
|
|
|
|
vec* formats = relation->rel_formats;
|
|
|
|
if (formats &&
|
2001-12-24 03:51:06 +01:00
|
|
|
(number < formats->count()) &&
|
2004-01-28 08:50:41 +01:00
|
|
|
(format = (fmt*) (*formats)[number]))
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
return format;
|
|
|
|
}
|
|
|
|
|
|
|
|
format = NULL;
|
2004-02-20 07:43:27 +01:00
|
|
|
blk* request = CMP_find_request(tdbb, irq_r_format, IRQ_REQUESTS);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
FOR(REQUEST_HANDLE request)
|
|
|
|
X IN RDB$FORMATS WITH X.RDB$RELATION_ID EQ relation->rel_id AND
|
2001-07-12 08:32:05 +02:00
|
|
|
X.RDB$FORMAT EQ number
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (!REQUEST(irq_r_format))
|
|
|
|
{
|
|
|
|
REQUEST(irq_r_format) = request;
|
|
|
|
}
|
2004-01-21 08:18:30 +01:00
|
|
|
blb* blob = BLB_open(tdbb, dbb->dbb_sys_trans, &X.RDB$DESCRIPTOR);
|
2003-12-22 11:00:59 +01:00
|
|
|
const USHORT count = blob->blb_length / sizeof(struct dsc);
|
2001-12-24 03:51:06 +01:00
|
|
|
format = fmt::newFmt(*dbb->dbb_permanent, count);
|
2001-05-23 15:26:42 +02:00
|
|
|
format->fmt_count = count;
|
2002-01-04 12:34:22 +01:00
|
|
|
// BLB_get_data(tdbb, blob, (UCHAR*) &*(format->fmt_desc.begin()), blob->blb_length);
|
|
|
|
BLB_get_data(tdbb, blob, (UCHAR*) &(format->fmt_desc[0]), blob->blb_length);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-12-22 11:00:59 +01:00
|
|
|
for (fmt::fmt_desc_const_iterator desc = format->fmt_desc.end() - 1;
|
2001-12-24 03:51:06 +01:00
|
|
|
desc >= format->fmt_desc.begin();
|
2001-05-23 15:26:42 +02:00
|
|
|
--desc)
|
|
|
|
{
|
|
|
|
if (desc->dsc_address)
|
|
|
|
{
|
|
|
|
format->fmt_length =
|
2004-01-21 08:18:30 +01:00
|
|
|
(IPTR) desc->dsc_address + desc->dsc_length;
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
END_FOR;
|
|
|
|
|
|
|
|
if (!REQUEST(irq_r_format)) {
|
|
|
|
REQUEST(irq_r_format) = request;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!format) {
|
2001-12-24 03:51:06 +01:00
|
|
|
format = fmt::newFmt(*dbb->dbb_permanent);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
format->fmt_version = number;
|
|
|
|
|
|
|
|
/* Link the format block into the world */
|
|
|
|
|
2003-02-19 16:25:27 +01:00
|
|
|
formats = relation->rel_formats =
|
|
|
|
vec::newVector(*dbb->dbb_permanent, relation->rel_formats, number + 1);
|
2001-12-24 03:51:06 +01:00
|
|
|
(*formats)[number] = (BLK) format;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
return format;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-03-11 06:04:26 +01:00
|
|
|
bool MET_get_char_subtype(thread_db* tdbb,
|
2003-12-22 11:00:59 +01:00
|
|
|
SSHORT* id, const UCHAR* name, USHORT length)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
2001-07-12 08:32:05 +02:00
|
|
|
* M E T _ g e t _ c h a r _ s u b t y p e
|
2001-05-23 15:26:42 +02:00
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Character types can be specified as either:
|
|
|
|
* a) A POSIX style locale name "<collation>.<characterset>"
|
|
|
|
* or
|
|
|
|
* b) A simple <characterset> name (using default collation)
|
|
|
|
* c) A simple <collation> name (use charset for collation)
|
|
|
|
*
|
|
|
|
* Given an ASCII7 string which could be any of the above, try to
|
|
|
|
* resolve the name in the order a, b, c
|
|
|
|
* a) is only tried iff the name contains a period.
|
|
|
|
* (in which case b) and c) are not tried).
|
|
|
|
*
|
|
|
|
* Return:
|
|
|
|
* 1 if no errors (and *id is set).
|
|
|
|
* 0 if the name could not be resolved.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
SET_TDBB(tdbb);
|
|
|
|
|
2003-11-04 00:59:24 +01:00
|
|
|
fb_assert(id != NULL);
|
|
|
|
fb_assert(name != NULL);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-12-22 11:00:59 +01:00
|
|
|
const UCHAR* const end_name = name + length;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* Force key to uppercase, following C locale rules for uppercasing */
|
|
|
|
/* At the same time, search for the first period in the string (if any) */
|
2003-12-22 11:00:59 +01:00
|
|
|
UCHAR buffer[32]; /* BASED ON RDB$COLLATION_NAME */
|
|
|
|
UCHAR* p = buffer;
|
|
|
|
UCHAR* period = NULL;
|
|
|
|
for (; name < end_name && p < buffer + sizeof(buffer) - 1; p++, name++) {
|
2001-05-23 15:26:42 +02:00
|
|
|
*p = UPPER7(*name);
|
2004-01-03 11:59:52 +01:00
|
|
|
if ((*p == '.') && !period) {
|
2001-05-23 15:26:42 +02:00
|
|
|
period = p;
|
2004-01-03 11:59:52 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
*p = 0;
|
|
|
|
|
|
|
|
/* Is there a period, separating collation name from character set? */
|
|
|
|
if (period) {
|
|
|
|
*period = 0;
|
|
|
|
return resolve_charset_and_collation(tdbb, id, period + 1, buffer);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* Is it a character set name (implying charset default collation sequence) */
|
|
|
|
|
2004-03-11 06:04:26 +01:00
|
|
|
bool res = resolve_charset_and_collation(tdbb, id, buffer, NULL);
|
2001-05-23 15:26:42 +02:00
|
|
|
if (!res) {
|
|
|
|
/* Is it a collation name (implying implementation-default character set) */
|
|
|
|
res = resolve_charset_and_collation(tdbb, id, NULL, buffer);
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-03-11 06:04:26 +01:00
|
|
|
jrd_nod* MET_get_dependencies(thread_db* tdbb,
|
2003-12-22 11:00:59 +01:00
|
|
|
jrd_rel* relation,
|
2004-03-11 06:04:26 +01:00
|
|
|
const TEXT* blob,
|
|
|
|
Csb* view_csb,
|
|
|
|
bid* blob_id,
|
2004-01-03 11:59:52 +01:00
|
|
|
jrd_req** request,
|
2004-03-11 06:04:26 +01:00
|
|
|
Csb** csb_ptr,
|
|
|
|
const TEXT* object_name,
|
|
|
|
USHORT type)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* M E T _ g e t _ d e p e n d e n c i e s
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
2001-07-12 08:32:05 +02:00
|
|
|
* Get dependencies for an object by parsing
|
2001-05-23 15:26:42 +02:00
|
|
|
* the blr used in its definition.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
SET_TDBB(tdbb);
|
2004-03-07 08:58:55 +01:00
|
|
|
Database* dbb = tdbb->tdbb_database;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-03-11 06:04:26 +01:00
|
|
|
Csb* csb = Csb::newCsb(*tdbb->tdbb_default, 5);
|
|
|
|
csb->csb_g_flags |= csb_get_dependencies;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-12-22 11:00:59 +01:00
|
|
|
jrd_nod* node;
|
2001-05-23 15:26:42 +02:00
|
|
|
if (blob)
|
|
|
|
{
|
|
|
|
node = PAR_blr( tdbb,
|
|
|
|
relation,
|
2003-12-03 09:19:24 +01:00
|
|
|
reinterpret_cast<const UCHAR*>(blob),
|
2001-05-23 15:26:42 +02:00
|
|
|
view_csb,
|
2004-03-11 06:04:26 +01:00
|
|
|
&csb,
|
2001-05-23 15:26:42 +02:00
|
|
|
request,
|
2004-03-18 06:56:06 +01:00
|
|
|
(type == obj_trigger),
|
2001-05-23 15:26:42 +02:00
|
|
|
0);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
node =
|
|
|
|
MET_parse_blob( tdbb,
|
|
|
|
relation,
|
|
|
|
blob_id,
|
2004-03-11 06:04:26 +01:00
|
|
|
&csb,
|
2001-05-23 15:26:42 +02:00
|
|
|
request,
|
2004-03-18 06:56:06 +01:00
|
|
|
(type == obj_trigger),
|
|
|
|
false);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (type == (USHORT) obj_computed)
|
|
|
|
{
|
2003-12-22 11:00:59 +01:00
|
|
|
blk* handle = NULL;
|
2001-05-23 15:26:42 +02:00
|
|
|
FOR(REQUEST_HANDLE handle)
|
|
|
|
RLF IN RDB$RELATION_FIELDS CROSS
|
|
|
|
FLD IN RDB$FIELDS WITH
|
|
|
|
RLF.RDB$FIELD_SOURCE EQ FLD.RDB$FIELD_NAME AND
|
2002-12-22 14:08:50 +01:00
|
|
|
RLF.RDB$RELATION_NAME EQ relation->rel_name AND
|
|
|
|
RLF.RDB$FIELD_NAME EQ object_name
|
2001-05-23 15:26:42 +02:00
|
|
|
object_name = FLD.RDB$FIELD_NAME;
|
|
|
|
END_FOR;
|
2004-01-03 11:59:52 +01:00
|
|
|
CMP_release(tdbb, (jrd_req*)handle);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2004-03-11 06:04:26 +01:00
|
|
|
store_dependencies(tdbb, csb, object_name, type);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (csb_ptr)
|
|
|
|
{
|
2004-03-11 06:04:26 +01:00
|
|
|
*csb_ptr = csb;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2004-03-11 06:04:26 +01:00
|
|
|
delete csb;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return node;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-01-03 11:59:52 +01:00
|
|
|
jrd_fld* MET_get_field(jrd_rel* relation, USHORT id)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* M E T _ g e t _ f i e l d
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Get the field block for a field if possible. If not,
|
|
|
|
* return NULL;
|
|
|
|
*
|
|
|
|
**************************************/
|
2003-12-22 11:00:59 +01:00
|
|
|
vec* vector;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (!relation ||
|
|
|
|
!(vector = relation->rel_fields) ||
|
2003-12-22 11:00:59 +01:00
|
|
|
id >= vector->count())
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-01-03 11:59:52 +01:00
|
|
|
return (jrd_fld*) (*vector)[id];
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-03-11 06:04:26 +01:00
|
|
|
void MET_get_shadow_files( thread_db* tdbb, bool deleteVar)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* M E T _ g e t _ s h a d o w _ f i l e s
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Check the shadows found in the database against
|
2001-07-12 08:32:05 +02:00
|
|
|
* our in-memory list: if any new shadow files have
|
2001-05-23 15:26:42 +02:00
|
|
|
* been defined since the last time we looked, start
|
|
|
|
* shadowing to them; if any have been deleted, stop
|
|
|
|
* shadowing to them.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
SET_TDBB(tdbb);
|
2004-03-07 08:58:55 +01:00
|
|
|
Database* dbb = tdbb->tdbb_database;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-12-22 11:00:59 +01:00
|
|
|
blk* handle = NULL;
|
2001-05-23 15:26:42 +02:00
|
|
|
FOR(REQUEST_HANDLE handle) X IN RDB$FILES
|
|
|
|
WITH X.RDB$SHADOW_NUMBER NOT MISSING
|
|
|
|
AND X.RDB$SHADOW_NUMBER NE 0
|
|
|
|
AND X.RDB$FILE_SEQUENCE EQ 0
|
|
|
|
if ((X.RDB$FILE_FLAGS & FILE_shadow) &&
|
|
|
|
!(X.RDB$FILE_FLAGS & FILE_inactive))
|
|
|
|
{
|
2003-12-22 11:00:59 +01:00
|
|
|
const USHORT file_flags = X.RDB$FILE_FLAGS;
|
2001-05-23 15:26:42 +02:00
|
|
|
SDW_start(X.RDB$FILE_NAME, X.RDB$SHADOW_NUMBER, file_flags,
|
2001-07-12 08:32:05 +02:00
|
|
|
deleteVar);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2001-07-12 08:32:05 +02:00
|
|
|
/* if the shadow exists, mark the appropriate shadow
|
2001-05-23 15:26:42 +02:00
|
|
|
block as found for the purposes of this routine;
|
|
|
|
if the shadow was conditional and is no longer, note it */
|
|
|
|
|
2004-02-20 07:43:27 +01:00
|
|
|
for (Shadow* shadow = dbb->dbb_shadow; shadow; shadow = shadow->sdw_next)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
if ((shadow->sdw_number == X.RDB$SHADOW_NUMBER) &&
|
|
|
|
!(shadow->sdw_flags & SDW_IGNORE))
|
|
|
|
{
|
|
|
|
shadow->sdw_flags |= SDW_found;
|
2004-01-03 11:59:52 +01:00
|
|
|
if (!(file_flags & FILE_conditional)) {
|
2001-05-23 15:26:42 +02:00
|
|
|
shadow->sdw_flags &= ~SDW_conditional;
|
2004-01-03 11:59:52 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
END_FOR;
|
|
|
|
|
2004-01-03 11:59:52 +01:00
|
|
|
CMP_release(tdbb, (jrd_req*)handle);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2001-07-12 08:32:05 +02:00
|
|
|
/* if any current shadows were not defined in database, mark
|
2001-05-23 15:26:42 +02:00
|
|
|
them to be shutdown since they don't exist anymore */
|
|
|
|
|
2004-02-20 07:43:27 +01:00
|
|
|
for (Shadow* shadow = dbb->dbb_shadow; shadow; shadow = shadow->sdw_next) {
|
2004-01-03 11:59:52 +01:00
|
|
|
if (!(shadow->sdw_flags & SDW_found)) {
|
2001-05-23 15:26:42 +02:00
|
|
|
shadow->sdw_flags |= SDW_shutdown;
|
2004-01-03 11:59:52 +01:00
|
|
|
}
|
|
|
|
else {
|
2001-05-23 15:26:42 +02:00
|
|
|
shadow->sdw_flags &= ~SDW_found;
|
2004-01-03 11:59:52 +01:00
|
|
|
}
|
2003-12-22 11:00:59 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
SDW_check();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void MET_load_trigger(
|
2004-03-11 06:04:26 +01:00
|
|
|
thread_db* tdbb,
|
2004-02-20 07:43:27 +01:00
|
|
|
jrd_rel* relation, const TEXT* trigger_name,
|
|
|
|
trig_vec** triggers)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* M E T _ l o a d _ t r i g g e r
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Load triggers from RDB$TRIGGERS. If a requested,
|
|
|
|
* also load triggers from RDB$RELATIONS.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
TEXT errmsg[MAX_ERRMSG_LEN + 1];
|
|
|
|
|
|
|
|
SET_TDBB(tdbb);
|
2004-03-07 08:58:55 +01:00
|
|
|
Database* dbb = tdbb->tdbb_database;
|
2001-05-23 15:26:42 +02:00
|
|
|
CHECK_DBB(dbb);
|
|
|
|
|
2004-01-03 11:59:52 +01:00
|
|
|
if (relation->rel_flags & REL_sys_trigs_being_loaded) {
|
2001-05-23 15:26:42 +02:00
|
|
|
return;
|
2004-01-03 11:59:52 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* No need to load triggers for ReadOnly databases,
|
|
|
|
since INSERT/DELETE/UPDATE statements are not going to be allowed */
|
2004-01-03 11:59:52 +01:00
|
|
|
if (dbb->dbb_flags & DBB_read_only) {
|
2001-05-23 15:26:42 +02:00
|
|
|
return;
|
2004-01-03 11:59:52 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* Scan RDB$TRIGGERS next */
|
|
|
|
|
2004-02-20 07:43:27 +01:00
|
|
|
blk* trigger_request = CMP_find_request(tdbb, irq_s_triggers, IRQ_REQUESTS);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
FOR(REQUEST_HANDLE trigger_request)
|
|
|
|
TRG IN RDB$TRIGGERS WITH TRG.RDB$RELATION_NAME =
|
2003-12-22 11:00:59 +01:00
|
|
|
relation->rel_name AND TRG.RDB$TRIGGER_NAME EQ trigger_name
|
|
|
|
if (!REQUEST(irq_s_triggers))
|
2001-05-23 15:26:42 +02:00
|
|
|
REQUEST(irq_s_triggers) = trigger_request;
|
|
|
|
|
2002-06-14 14:09:37 +02:00
|
|
|
if (TRG.RDB$TRIGGER_TYPE > 0 && TRG.RDB$TRIGGER_TYPE < TRIGGER_COMBINED_MAX)
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
/* check if the trigger is to be fired without any permissions
|
|
|
|
checks. Verify such a claim */
|
2003-12-22 11:00:59 +01:00
|
|
|
USHORT trig_flags = (USHORT) TRG.RDB$FLAGS;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* if there is an ignore permission flag, see if it is legit */
|
|
|
|
if ((TRG.RDB$FLAGS & TRG_ignore_perm) &&
|
2002-06-14 14:09:37 +02:00
|
|
|
!verify_TRG_ignore_perm(tdbb, trigger_name))
|
|
|
|
{
|
2003-08-28 15:16:03 +02:00
|
|
|
gds__msg_format(NULL, JRD_BUGCHK, 304, sizeof(errmsg),
|
|
|
|
errmsg, trigger_name, NULL, NULL,
|
|
|
|
NULL, NULL);
|
2001-05-23 15:26:42 +02:00
|
|
|
ERR_log(JRD_BUGCHK, 304, errmsg);
|
|
|
|
|
|
|
|
trig_flags &= ~TRG_ignore_perm;
|
|
|
|
}
|
|
|
|
|
2002-06-14 14:09:37 +02:00
|
|
|
// dimitr: support for the universal triggers
|
|
|
|
int trigger_action, slot_index = 0;
|
|
|
|
while ((trigger_action = TRIGGER_ACTION_SLOT(TRG.RDB$TRIGGER_TYPE, ++slot_index)) > 0)
|
|
|
|
{
|
|
|
|
get_trigger(tdbb,
|
|
|
|
relation,
|
2004-01-21 08:18:30 +01:00
|
|
|
&TRG.RDB$TRIGGER_BLR,
|
2002-06-14 14:09:37 +02:00
|
|
|
triggers + trigger_action,
|
|
|
|
TRG.RDB$TRIGGER_NAME,
|
2003-12-03 09:19:24 +01:00
|
|
|
(bool) TRG.RDB$SYSTEM_FLAG,
|
2002-06-14 14:09:37 +02:00
|
|
|
trig_flags);
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
END_FOR;
|
|
|
|
|
|
|
|
if (!REQUEST(irq_s_triggers))
|
|
|
|
REQUEST(irq_s_triggers) = trigger_request;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2004-03-11 06:04:26 +01:00
|
|
|
void MET_lookup_cnstrt_for_index(thread_db* tdbb,
|
2003-10-03 03:53:34 +02:00
|
|
|
TEXT* constraint_name,
|
|
|
|
const TEXT* index_name)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* M E T _ l o o k u p _ c n s t r t _ f o r _ i n d e x
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Lookup constraint name from index name, if one exists.
|
|
|
|
* Calling routine must pass a buffer of at least 32 bytes.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
SET_TDBB(tdbb);
|
2004-03-07 08:58:55 +01:00
|
|
|
Database* dbb = tdbb->tdbb_database;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
constraint_name[0] = 0;
|
2004-02-20 07:43:27 +01:00
|
|
|
blk* request = CMP_find_request(tdbb, irq_l_cnstrt, IRQ_REQUESTS);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
FOR(REQUEST_HANDLE request)
|
2002-12-22 14:08:50 +01:00
|
|
|
X IN RDB$RELATION_CONSTRAINTS WITH X.RDB$INDEX_NAME EQ index_name
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (!REQUEST(irq_l_cnstrt))
|
|
|
|
REQUEST(irq_l_cnstrt) = request;
|
|
|
|
|
|
|
|
X.RDB$CONSTRAINT_NAME[name_length(X.RDB$CONSTRAINT_NAME)] = 0;
|
|
|
|
strcpy(constraint_name, X.RDB$CONSTRAINT_NAME);
|
|
|
|
|
|
|
|
END_FOR;
|
|
|
|
|
|
|
|
if (!REQUEST(irq_l_cnstrt))
|
|
|
|
REQUEST(irq_l_cnstrt) = request;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void MET_lookup_cnstrt_for_trigger(
|
2004-03-11 06:04:26 +01:00
|
|
|
thread_db* tdbb,
|
2003-12-03 09:19:24 +01:00
|
|
|
TEXT* constraint_name,
|
|
|
|
TEXT* relation_name,
|
|
|
|
const TEXT* trigger_name)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
2001-07-12 08:32:05 +02:00
|
|
|
* M E T _ l o o k u p _ c n s t r t _ f o r _ t r i g g e r
|
2001-05-23 15:26:42 +02:00
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Lookup constraint name from trigger name, if one exists.
|
|
|
|
* Calling routine must pass a buffer of at least 32 bytes.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
SET_TDBB(tdbb);
|
2004-03-07 08:58:55 +01:00
|
|
|
Database* dbb = tdbb->tdbb_database;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
constraint_name[0] = 0;
|
|
|
|
relation_name[0] = 0;
|
2004-02-20 07:43:27 +01:00
|
|
|
blk* request = CMP_find_request(tdbb, irq_l_check, IRQ_REQUESTS);
|
|
|
|
blk* request2 = CMP_find_request(tdbb, irq_l_check2, IRQ_REQUESTS);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2001-07-12 08:32:05 +02:00
|
|
|
/* utilize two requests rather than one so that we
|
2001-05-23 15:26:42 +02:00
|
|
|
guarantee we always return the name of the relation
|
2001-07-12 08:32:05 +02:00
|
|
|
that the trigger is defined on, even if we don't
|
2001-05-23 15:26:42 +02:00
|
|
|
have a check constraint defined for that trigger */
|
|
|
|
|
|
|
|
FOR(REQUEST_HANDLE request)
|
|
|
|
Y IN RDB$TRIGGERS WITH
|
|
|
|
Y.RDB$TRIGGER_NAME EQ trigger_name
|
|
|
|
|
2004-01-03 11:59:52 +01:00
|
|
|
if (!REQUEST(irq_l_check))
|
|
|
|
REQUEST(irq_l_check) = request;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
FOR(REQUEST_HANDLE request2)
|
|
|
|
X IN RDB$CHECK_CONSTRAINTS WITH
|
|
|
|
X.RDB$TRIGGER_NAME EQ Y.RDB$TRIGGER_NAME
|
|
|
|
|
2004-01-03 11:59:52 +01:00
|
|
|
if (!REQUEST(irq_l_check2))
|
|
|
|
REQUEST(irq_l_check2) = request2;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
X.RDB$CONSTRAINT_NAME[name_length(X.RDB$CONSTRAINT_NAME)] = 0;
|
|
|
|
strcpy(constraint_name, X.RDB$CONSTRAINT_NAME);
|
|
|
|
|
|
|
|
END_FOR;
|
|
|
|
|
|
|
|
if (!REQUEST(irq_l_check2))
|
|
|
|
REQUEST(irq_l_check2) = request2;
|
|
|
|
|
|
|
|
Y.RDB$RELATION_NAME[name_length(Y.RDB$RELATION_NAME)] = 0;
|
|
|
|
strcpy(relation_name, Y.RDB$RELATION_NAME);
|
|
|
|
|
|
|
|
END_FOR;
|
|
|
|
|
|
|
|
if (!REQUEST(irq_l_check))
|
|
|
|
REQUEST(irq_l_check) = request;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-03-11 06:04:26 +01:00
|
|
|
void MET_lookup_exception(thread_db* tdbb,
|
2001-05-23 15:26:42 +02:00
|
|
|
SLONG number,
|
|
|
|
TEXT* name,
|
|
|
|
TEXT* message)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* M E T _ l o o k u p _ e x c e p t i o n
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Lookup exception by number and return its name and message.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
SET_TDBB(tdbb);
|
2004-03-07 08:58:55 +01:00
|
|
|
Database* dbb = tdbb->tdbb_database;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* We need to look up exception in RDB$EXCEPTIONS */
|
|
|
|
|
2004-02-20 07:43:27 +01:00
|
|
|
blk* request = CMP_find_request(tdbb, irq_l_exception, IRQ_REQUESTS);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
*name = 0;
|
|
|
|
if (message)
|
|
|
|
{
|
|
|
|
*message = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
FOR(REQUEST_HANDLE request)
|
|
|
|
X IN RDB$EXCEPTIONS WITH X.RDB$EXCEPTION_NUMBER = number
|
|
|
|
|
|
|
|
if (!REQUEST(irq_l_exception))
|
|
|
|
{
|
|
|
|
REQUEST(irq_l_exception) = request;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!X.RDB$EXCEPTION_NAME.NULL)
|
|
|
|
{
|
|
|
|
name_copy(name, X.RDB$EXCEPTION_NAME);
|
|
|
|
}
|
|
|
|
if (!X.RDB$MESSAGE.NULL && message)
|
|
|
|
{
|
|
|
|
name_copy(message, X.RDB$MESSAGE);
|
|
|
|
}
|
|
|
|
END_FOR;
|
|
|
|
|
|
|
|
if (!REQUEST(irq_l_exception))
|
|
|
|
{
|
|
|
|
REQUEST(irq_l_exception) = request;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-03-11 06:04:26 +01:00
|
|
|
SLONG MET_lookup_exception_number(thread_db* tdbb, const TEXT* name)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* M E T _ l o o k u p _ e x c e p t i o n _ n u m b e r
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Lookup exception by name and return its number.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
SET_TDBB(tdbb);
|
2004-03-07 08:58:55 +01:00
|
|
|
Database* dbb = tdbb->tdbb_database;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* We need to look up exception in RDB$EXCEPTIONS */
|
|
|
|
|
2004-02-20 07:43:27 +01:00
|
|
|
blk* request = CMP_find_request(tdbb, irq_l_except_no, IRQ_REQUESTS);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-12-22 11:00:59 +01:00
|
|
|
SLONG number = 0;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
FOR(REQUEST_HANDLE request)
|
|
|
|
X IN RDB$EXCEPTIONS WITH X.RDB$EXCEPTION_NAME = name
|
|
|
|
|
2003-12-22 11:00:59 +01:00
|
|
|
if (!REQUEST(irq_l_except_no))
|
|
|
|
REQUEST(irq_l_except_no) = request;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
number = X.RDB$EXCEPTION_NUMBER;
|
|
|
|
|
|
|
|
END_FOR;
|
|
|
|
|
|
|
|
if (!REQUEST(irq_l_except_no))
|
|
|
|
REQUEST(irq_l_except_no) = request;
|
|
|
|
|
|
|
|
return number;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-03-11 06:04:26 +01:00
|
|
|
int MET_lookup_field(thread_db* tdbb, jrd_rel* relation, const TEXT* name,
|
2004-02-20 07:43:27 +01:00
|
|
|
const TEXT* security_name)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* M E T _ l o o k u p _ f i e l d
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Look up a field name.
|
2002-07-01 18:59:09 +02:00
|
|
|
* Additinally, if security_name is a not null pointer,
|
|
|
|
* it's used to include the condition that it should match
|
|
|
|
* the field's security class name, too.
|
2001-05-23 15:26:42 +02:00
|
|
|
*
|
2003-02-20 01:10:25 +01:00
|
|
|
* if the field is not found return -1
|
|
|
|
*
|
|
|
|
*****************************************/
|
2001-05-23 15:26:42 +02:00
|
|
|
SET_TDBB(tdbb);
|
2004-03-07 08:58:55 +01:00
|
|
|
Database* dbb = tdbb->tdbb_database;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* Start by checking field names that we already know */
|
2004-01-03 11:59:52 +01:00
|
|
|
vec* vector = relation->rel_fields;
|
|
|
|
if (vector) {
|
|
|
|
const UCHAR length = strlen(name);
|
|
|
|
USHORT id = 0;
|
|
|
|
vec::iterator fieldIter = vector->begin();
|
|
|
|
for (const vec::const_iterator end = vector->end();
|
2003-12-22 11:00:59 +01:00
|
|
|
fieldIter < end; fieldIter++, id++)
|
|
|
|
{
|
2002-07-05 17:00:26 +02:00
|
|
|
if (*fieldIter) {
|
2004-01-03 11:59:52 +01:00
|
|
|
const jrd_fld* field = (jrd_fld*) *fieldIter;
|
|
|
|
const TEXT* p;
|
2002-07-05 17:00:26 +02:00
|
|
|
if (field->fld_length == length && (p = field->fld_name)) {
|
2004-01-03 11:59:52 +01:00
|
|
|
const TEXT* q = name;
|
2002-07-05 17:00:26 +02:00
|
|
|
while (*p++ == *q) { // Check equal till end of string
|
|
|
|
if (!*q++) { // Found end of string and so are equal
|
|
|
|
if (!security_name) {
|
|
|
|
return id;
|
|
|
|
}
|
|
|
|
|
2003-12-22 11:00:59 +01:00
|
|
|
const size_t nl2 = name_length (security_name);
|
2002-07-05 17:00:26 +02:00
|
|
|
if (field->fld_security_name) {
|
2003-12-22 11:00:59 +01:00
|
|
|
const size_t nl = name_length(field->fld_security_name);
|
2004-01-03 11:59:52 +01:00
|
|
|
if (nl == nl2 && !strncmp(field->fld_security_name, security_name, nl))
|
|
|
|
{
|
2002-07-05 17:00:26 +02:00
|
|
|
return id;
|
|
|
|
}
|
|
|
|
}
|
2002-07-01 18:59:09 +02:00
|
|
|
}
|
2002-07-05 17:00:26 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* Not found. Next, try system relations directly */
|
|
|
|
|
2004-01-03 11:59:52 +01:00
|
|
|
USHORT id = (USHORT) -1;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (!relation->rel_name)
|
|
|
|
{
|
|
|
|
return id;
|
|
|
|
}
|
|
|
|
|
2004-02-20 07:43:27 +01:00
|
|
|
blk* request = CMP_find_request(tdbb, irq_l_field, IRQ_REQUESTS);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
FOR(REQUEST_HANDLE request)
|
|
|
|
X IN RDB$RELATION_FIELDS WITH
|
|
|
|
X.RDB$RELATION_NAME EQ relation->rel_name AND
|
2001-07-12 08:32:05 +02:00
|
|
|
X.RDB$FIELD_NAME EQ name
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2002-07-01 18:59:09 +02:00
|
|
|
if (!REQUEST(irq_l_field)) {
|
2001-05-23 15:26:42 +02:00
|
|
|
REQUEST(irq_l_field) = request;
|
|
|
|
}
|
2002-07-01 18:59:09 +02:00
|
|
|
|
|
|
|
if (!security_name) {
|
|
|
|
id = X.RDB$FIELD_ID;
|
|
|
|
}
|
|
|
|
else {
|
2004-01-03 11:59:52 +01:00
|
|
|
USHORT nl;
|
|
|
|
const USHORT nl2 = name_length (security_name);
|
2002-07-01 18:59:09 +02:00
|
|
|
if (!X.RDB$SECURITY_CLASS.NULL
|
|
|
|
&& (nl = name_length (X.RDB$SECURITY_CLASS)) == nl2
|
2004-01-03 11:59:52 +01:00
|
|
|
&& !strncmp (X.RDB$SECURITY_CLASS, security_name, nl))
|
|
|
|
{
|
2002-07-01 18:59:09 +02:00
|
|
|
id = X.RDB$FIELD_ID;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
END_FOR;
|
|
|
|
|
2002-07-01 18:59:09 +02:00
|
|
|
if (!REQUEST(irq_l_field)) {
|
2001-05-23 15:26:42 +02:00
|
|
|
REQUEST(irq_l_field) = request;
|
|
|
|
}
|
|
|
|
|
|
|
|
return id;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-03-19 07:14:53 +01:00
|
|
|
BlobFilter* MET_lookup_filter(thread_db* tdbb, SSHORT from, SSHORT to)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* M E T _ l o o k u p _ f i l t e r
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
SET_TDBB(tdbb);
|
2004-03-07 08:58:55 +01:00
|
|
|
Database* dbb = tdbb->tdbb_database;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-12-22 11:00:59 +01:00
|
|
|
FPTR_BFILTER_CALLBACK filter = NULL;
|
2004-03-19 07:14:53 +01:00
|
|
|
BlobFilter* blf = NULL;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-02-20 07:43:27 +01:00
|
|
|
blk* request = CMP_find_request(tdbb, irq_r_filters, IRQ_REQUESTS);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
FOR(REQUEST_HANDLE request)
|
|
|
|
X IN RDB$FILTERS WITH X.RDB$INPUT_SUB_TYPE EQ from AND
|
2001-07-12 08:32:05 +02:00
|
|
|
X.RDB$OUTPUT_SUB_TYPE EQ to
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (!REQUEST(irq_r_filters))
|
|
|
|
REQUEST(irq_r_filters) = request;
|
2003-12-31 06:36:12 +01:00
|
|
|
fb_utils::fb_exact_name(X.RDB$MODULE_NAME);
|
|
|
|
fb_utils::fb_exact_name(X.RDB$ENTRYPOINT);
|
2003-12-11 11:33:30 +01:00
|
|
|
filter = (FPTR_BFILTER_CALLBACK)
|
2001-05-23 15:26:42 +02:00
|
|
|
ISC_lookup_entrypoint(X.RDB$MODULE_NAME, X.RDB$ENTRYPOINT,
|
2003-06-16 17:43:00 +02:00
|
|
|
ISC_EXT_LIB_PATH_ENV, true);
|
2001-05-23 15:26:42 +02:00
|
|
|
if (filter)
|
|
|
|
{
|
2004-03-19 07:14:53 +01:00
|
|
|
blf = FB_NEW(*dbb->dbb_permanent) BlobFilter();
|
|
|
|
blf->blf_next = NULL;
|
|
|
|
blf->blf_from = from;
|
|
|
|
blf->blf_to = to;
|
|
|
|
blf->blf_filter = filter;
|
2003-12-22 11:00:59 +01:00
|
|
|
str* exception_msg =
|
2002-09-25 19:12:16 +02:00
|
|
|
FB_NEW_RPT(*dbb->dbb_permanent,
|
2001-05-23 15:26:42 +02:00
|
|
|
strlen(EXCEPTION_MESSAGE) +
|
|
|
|
strlen(X.RDB$FUNCTION_NAME) +
|
|
|
|
strlen(X.RDB$ENTRYPOINT) +
|
2001-12-24 03:51:06 +01:00
|
|
|
strlen(X.RDB$MODULE_NAME) + 1) str();
|
2001-07-12 08:32:05 +02:00
|
|
|
sprintf((char*)exception_msg->str_data, EXCEPTION_MESSAGE,
|
2001-05-23 15:26:42 +02:00
|
|
|
X.RDB$FUNCTION_NAME, X.RDB$ENTRYPOINT, X.RDB$MODULE_NAME);
|
2004-03-19 07:14:53 +01:00
|
|
|
blf->blf_exception_message = exception_msg;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2003-12-22 11:00:59 +01:00
|
|
|
|
|
|
|
MOD module = FLU_lookup_module(X.RDB$MODULE_NAME);
|
|
|
|
if (module)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/* Register interest in the module by database. */
|
|
|
|
|
2003-12-22 11:00:59 +01:00
|
|
|
lls* stack;
|
|
|
|
for (stack = dbb->dbb_modules; stack; stack = stack->lls_next) {
|
2004-01-03 11:59:52 +01:00
|
|
|
if (module == (MOD) stack->lls_object) {
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
2004-01-03 11:59:52 +01:00
|
|
|
}
|
2003-12-22 11:00:59 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* If the module was already registered with this database
|
|
|
|
then decrement the use count that was incremented in
|
|
|
|
ISC_lookup_entrypoint() above. Otherwise push it onto
|
|
|
|
the stack of registered modules. */
|
|
|
|
|
2004-01-03 11:59:52 +01:00
|
|
|
if (stack) {
|
2001-05-23 15:26:42 +02:00
|
|
|
FLU_unregister_module(module);
|
2004-01-03 11:59:52 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
else
|
|
|
|
{
|
2003-12-22 11:00:59 +01:00
|
|
|
JrdMemoryPool* old_pool = tdbb->tdbb_default;
|
2001-05-23 15:26:42 +02:00
|
|
|
tdbb->tdbb_default = dbb->dbb_permanent;
|
|
|
|
LLS_PUSH(module, &dbb->dbb_modules);
|
|
|
|
tdbb->tdbb_default = old_pool;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
END_FOR;
|
|
|
|
|
|
|
|
if (!REQUEST(irq_r_filters))
|
|
|
|
REQUEST(irq_r_filters) = request;
|
|
|
|
|
2004-03-19 07:14:53 +01:00
|
|
|
return blf;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-03-11 06:04:26 +01:00
|
|
|
SLONG MET_lookup_generator(thread_db* tdbb, const TEXT* name)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* M E T _ l o o k u p _ g e n e r a t o r
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Lookup generator (aka gen_id). If we can't find it, make a new one.
|
2002-07-01 18:59:09 +02:00
|
|
|
* CVC: I don't see how this function "makes" a new generator; it simply
|
|
|
|
* returns -1 if the name is not found.
|
2001-05-23 15:26:42 +02:00
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
SET_TDBB(tdbb);
|
2004-03-07 08:58:55 +01:00
|
|
|
Database* dbb = tdbb->tdbb_database;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (!strcmp(name, "RDB$GENERATORS"))
|
|
|
|
return 0;
|
|
|
|
|
2003-12-22 11:00:59 +01:00
|
|
|
SLONG gen_id = -1;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-02-20 07:43:27 +01:00
|
|
|
blk* request = CMP_find_request(tdbb, irq_r_gen_id, IRQ_REQUESTS);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
FOR(REQUEST_HANDLE request)
|
|
|
|
X IN RDB$GENERATORS WITH X.RDB$GENERATOR_NAME EQ name
|
|
|
|
|
|
|
|
if (!REQUEST(irq_r_gen_id))
|
|
|
|
REQUEST(irq_r_gen_id) = request;
|
|
|
|
|
|
|
|
gen_id = X.RDB$GENERATOR_ID;
|
|
|
|
END_FOR;
|
|
|
|
|
|
|
|
if (!REQUEST(irq_r_gen_id))
|
|
|
|
REQUEST(irq_r_gen_id) = request;
|
|
|
|
|
|
|
|
return gen_id;
|
|
|
|
}
|
|
|
|
|
2004-03-11 06:04:26 +01:00
|
|
|
void MET_lookup_generator_id (thread_db* tdbb, SLONG gen_id, TEXT* name)
|
2002-07-01 18:59:09 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* M E T _ l o o k u p _ g e n e r a t o r _ i d
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Lookup generator (aka gen_id) by ID. It will load
|
|
|
|
* the name in the third parameter.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
SET_TDBB (tdbb);
|
2004-03-07 08:58:55 +01:00
|
|
|
Database* dbb = tdbb->tdbb_database;
|
2002-07-01 18:59:09 +02:00
|
|
|
|
|
|
|
if (!gen_id) {
|
|
|
|
strcpy (name, "RDB$GENERATORS");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
*name = 0;
|
|
|
|
|
2004-02-20 07:43:27 +01:00
|
|
|
blk* request = CMP_find_request (tdbb, irq_r_gen_id_num, IRQ_REQUESTS);
|
2002-07-01 18:59:09 +02:00
|
|
|
|
|
|
|
FOR (REQUEST_HANDLE request)
|
|
|
|
X IN RDB$GENERATORS WITH X.RDB$GENERATOR_ID EQ gen_id
|
|
|
|
|
|
|
|
if (!REQUEST (irq_r_gen_id_num))
|
|
|
|
REQUEST (irq_r_gen_id_num) = request;
|
|
|
|
name_copy (name, X.RDB$GENERATOR_NAME);
|
|
|
|
END_FOR;
|
|
|
|
|
|
|
|
if (!REQUEST (irq_r_gen_id_num))
|
|
|
|
REQUEST (irq_r_gen_id_num) = request;
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-03-11 06:04:26 +01:00
|
|
|
void MET_lookup_index(thread_db* tdbb,
|
2003-12-22 11:00:59 +01:00
|
|
|
TEXT* index_name,
|
|
|
|
const TEXT* relation_name,
|
2003-10-03 03:53:34 +02:00
|
|
|
USHORT number)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* M E T _ l o o k u p _ i n d e x
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Lookup index name from relation and index number.
|
|
|
|
* Calling routine must pass a buffer of at least 32 bytes.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
SET_TDBB(tdbb);
|
2004-03-07 08:58:55 +01:00
|
|
|
Database* dbb = tdbb->tdbb_database;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
index_name[0] = 0;
|
|
|
|
|
2004-02-20 07:43:27 +01:00
|
|
|
blk* request = CMP_find_request(tdbb, irq_l_index, IRQ_REQUESTS);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
FOR(REQUEST_HANDLE request)
|
|
|
|
X IN RDB$INDICES WITH X.RDB$RELATION_NAME EQ relation_name
|
2001-07-12 08:32:05 +02:00
|
|
|
AND X.RDB$INDEX_ID EQ number
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (!REQUEST(irq_l_index))
|
|
|
|
REQUEST(irq_l_index) = request;
|
|
|
|
|
|
|
|
X.RDB$INDEX_NAME[name_length(X.RDB$INDEX_NAME)] = 0;
|
|
|
|
strcpy(index_name, X.RDB$INDEX_NAME);
|
|
|
|
|
|
|
|
END_FOR;
|
|
|
|
|
|
|
|
if (!REQUEST(irq_l_index))
|
|
|
|
REQUEST(irq_l_index) = request;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-03-11 06:04:26 +01:00
|
|
|
SLONG MET_lookup_index_name(thread_db* tdbb,
|
2003-12-22 11:00:59 +01:00
|
|
|
const TEXT* index_name,
|
|
|
|
SLONG* relation_id, SSHORT* status)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* M E T _ l o o k u p _ i n d e x _ n a m e
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Lookup index id from index name.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
SLONG id = -1;
|
|
|
|
|
|
|
|
SET_TDBB(tdbb);
|
2004-03-07 08:58:55 +01:00
|
|
|
Database* dbb = tdbb->tdbb_database;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-02-20 07:43:27 +01:00
|
|
|
blk* request = CMP_find_request(tdbb, irq_l_index_name, IRQ_REQUESTS);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
*status = MET_object_unknown;
|
|
|
|
|
|
|
|
FOR(REQUEST_HANDLE request)
|
|
|
|
X IN RDB$INDICES WITH
|
|
|
|
X.RDB$INDEX_NAME EQ index_name
|
|
|
|
|
|
|
|
if (!REQUEST(irq_l_index_name))
|
|
|
|
REQUEST(irq_l_index_name) = request;
|
|
|
|
|
2004-01-03 11:59:52 +01:00
|
|
|
if (X.RDB$INDEX_INACTIVE == 0) {
|
2001-05-23 15:26:42 +02:00
|
|
|
*status = MET_object_active;
|
2004-01-03 11:59:52 +01:00
|
|
|
}
|
|
|
|
else {
|
2001-05-23 15:26:42 +02:00
|
|
|
*status = MET_object_inactive;
|
2004-01-03 11:59:52 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
id = X.RDB$INDEX_ID - 1;
|
2003-12-22 11:00:59 +01:00
|
|
|
const jrd_rel* relation = MET_lookup_relation(tdbb, X.RDB$RELATION_NAME);
|
2001-05-23 15:26:42 +02:00
|
|
|
*relation_id = relation->rel_id;
|
|
|
|
|
|
|
|
END_FOR;
|
|
|
|
|
|
|
|
if (!REQUEST(irq_l_index_name))
|
|
|
|
REQUEST(irq_l_index_name) = request;
|
|
|
|
|
|
|
|
return id;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-01-03 11:59:52 +01:00
|
|
|
bool MET_lookup_partner(
|
2004-03-11 06:04:26 +01:00
|
|
|
thread_db* tdbb, jrd_rel* relation, IDX* idx, const TEXT* index_name)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* M E T _ l o o k u p _ p a r t n e r
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Find partner index participating in a
|
|
|
|
* foreign key relationship.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
|
|
|
SET_TDBB(tdbb);
|
2004-03-07 08:58:55 +01:00
|
|
|
Database* dbb = tdbb->tdbb_database;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (relation->rel_flags & REL_check_partners)
|
|
|
|
{
|
|
|
|
/* Prepare for rescan of foreign references on other relations'
|
|
|
|
primary keys and release stale vectors. */
|
|
|
|
|
2004-02-20 07:43:27 +01:00
|
|
|
blk* request = CMP_find_request(tdbb, irq_foreign1, IRQ_REQUESTS);
|
2004-01-03 11:59:52 +01:00
|
|
|
frgn* references = &relation->rel_foreign_refs;
|
|
|
|
int index_number = 0;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (references->frgn_reference_ids) {
|
2001-12-24 03:51:06 +01:00
|
|
|
delete references->frgn_reference_ids;
|
2003-08-28 15:16:03 +02:00
|
|
|
references->frgn_reference_ids = NULL;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
if (references->frgn_relations) {
|
2001-12-24 03:51:06 +01:00
|
|
|
delete references->frgn_relations;
|
2003-08-28 15:16:03 +02:00
|
|
|
references->frgn_relations = NULL;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
if (references->frgn_indexes) {
|
2001-12-24 03:51:06 +01:00
|
|
|
delete references->frgn_indexes;
|
2003-08-28 15:16:03 +02:00
|
|
|
references->frgn_indexes = NULL;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
FOR(REQUEST_HANDLE request)
|
|
|
|
IDX IN RDB$INDICES CROSS
|
2002-09-01 17:49:03 +02:00
|
|
|
RC IN RDB$RELATION_CONSTRAINTS
|
|
|
|
OVER RDB$INDEX_NAME CROSS
|
2001-05-23 15:26:42 +02:00
|
|
|
IND IN RDB$INDICES WITH
|
2002-09-01 17:49:03 +02:00
|
|
|
RC.RDB$CONSTRAINT_TYPE EQ "FOREIGN KEY" AND
|
2001-05-23 15:26:42 +02:00
|
|
|
IDX.RDB$RELATION_NAME EQ relation->rel_name AND
|
|
|
|
IND.RDB$INDEX_NAME EQ IDX.RDB$FOREIGN_KEY AND
|
2001-07-12 08:32:05 +02:00
|
|
|
IND.RDB$UNIQUE_FLAG NOT MISSING
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (!REQUEST(irq_foreign1))
|
|
|
|
{
|
|
|
|
REQUEST(irq_foreign1) = request;
|
|
|
|
}
|
|
|
|
|
2004-01-03 11:59:52 +01:00
|
|
|
const jrd_rel* partner_relation =
|
2001-05-23 15:26:42 +02:00
|
|
|
MET_lookup_relation(tdbb, IND.RDB$RELATION_NAME);
|
|
|
|
|
|
|
|
if (partner_relation)
|
|
|
|
{
|
2003-02-19 16:25:27 +01:00
|
|
|
references->frgn_reference_ids =
|
|
|
|
vec::newVector(*dbb->dbb_permanent, references->frgn_reference_ids,
|
|
|
|
index_number + 1);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
(*references->frgn_reference_ids)[index_number] =
|
2004-01-21 08:18:30 +01:00
|
|
|
(BLK)(IPTR)(IDX.RDB$INDEX_ID - 1);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-02-19 16:25:27 +01:00
|
|
|
references->frgn_relations =
|
|
|
|
vec::newVector(*dbb->dbb_permanent, references->frgn_relations,
|
|
|
|
index_number + 1);
|
2001-12-24 03:51:06 +01:00
|
|
|
|
|
|
|
(*references->frgn_relations)[index_number] =
|
2004-01-21 08:18:30 +01:00
|
|
|
(BLK) (IPTR) partner_relation->rel_id;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-02-19 16:25:27 +01:00
|
|
|
references->frgn_indexes =
|
|
|
|
vec::newVector(*dbb->dbb_permanent, references->frgn_indexes,
|
|
|
|
index_number + 1);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
(*references->frgn_indexes)[index_number] =
|
2004-01-21 08:18:30 +01:00
|
|
|
(BLK) (IPTR) (IND.RDB$INDEX_ID - 1);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
index_number++;
|
|
|
|
}
|
|
|
|
END_FOR;
|
|
|
|
|
|
|
|
if (!REQUEST(irq_foreign1))
|
|
|
|
{
|
|
|
|
REQUEST(irq_foreign1) = request;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Prepare for rescan of primary dependencies on relation's primary
|
|
|
|
key and stale vectors. */
|
|
|
|
|
2004-02-20 07:43:27 +01:00
|
|
|
request = CMP_find_request(tdbb, irq_foreign2, IRQ_REQUESTS);
|
2004-01-03 11:59:52 +01:00
|
|
|
prim* dependencies = &relation->rel_primary_dpnds;
|
2001-05-23 15:26:42 +02:00
|
|
|
index_number = 0;
|
|
|
|
|
|
|
|
if (dependencies->prim_reference_ids) {
|
2001-12-24 03:51:06 +01:00
|
|
|
delete dependencies->prim_reference_ids;
|
2003-08-28 15:16:03 +02:00
|
|
|
dependencies->prim_reference_ids = NULL;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
if (dependencies->prim_relations) {
|
2001-12-24 03:51:06 +01:00
|
|
|
delete dependencies->prim_relations;
|
2003-08-28 15:16:03 +02:00
|
|
|
dependencies->prim_relations = NULL;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
if (dependencies->prim_indexes) {
|
2001-12-24 03:51:06 +01:00
|
|
|
delete dependencies->prim_indexes;
|
2003-08-28 15:16:03 +02:00
|
|
|
dependencies->prim_indexes = NULL;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
** ============================================================
|
|
|
|
** ==
|
|
|
|
** == since UNIQUE constraint also could be used as primary key
|
|
|
|
** == therefore we change:
|
|
|
|
** ==
|
|
|
|
** == IDX.RDB$INDEX_NAME STARTING WITH "RDB$PRIMARY"
|
|
|
|
** ==
|
|
|
|
** == to
|
|
|
|
** ==
|
|
|
|
** == IDX.RDB$UNIQUE_FLAG = 1
|
|
|
|
** ==
|
|
|
|
** ============================================================
|
|
|
|
*/
|
|
|
|
|
|
|
|
FOR(REQUEST_HANDLE request)
|
|
|
|
IDX IN RDB$INDICES CROSS
|
|
|
|
IND IN RDB$INDICES WITH
|
|
|
|
IDX.RDB$UNIQUE_FLAG = 1 AND
|
|
|
|
IDX.RDB$RELATION_NAME EQ relation->rel_name AND
|
|
|
|
IND.RDB$FOREIGN_KEY EQ IDX.RDB$INDEX_NAME
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
if (!REQUEST(irq_foreign2)) {
|
2001-05-23 15:26:42 +02:00
|
|
|
REQUEST(irq_foreign2) = request;
|
2001-12-24 03:51:06 +01:00
|
|
|
}
|
2004-01-03 11:59:52 +01:00
|
|
|
const jrd_rel* partner_relation =
|
|
|
|
MET_lookup_relation(tdbb, IND.RDB$RELATION_NAME);
|
2001-12-24 03:51:06 +01:00
|
|
|
if (partner_relation)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2003-02-19 16:25:27 +01:00
|
|
|
dependencies->prim_reference_ids =
|
|
|
|
vec::newVector(*dbb->dbb_permanent, dependencies->prim_reference_ids,
|
|
|
|
index_number + 1);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
(*dependencies->prim_reference_ids)[index_number] =
|
2004-01-21 08:18:30 +01:00
|
|
|
(BLK) (IPTR) (IDX.RDB$INDEX_ID - 1);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-02-19 16:25:27 +01:00
|
|
|
dependencies->prim_relations =
|
|
|
|
vec::newVector(*dbb->dbb_permanent, dependencies->prim_relations,
|
|
|
|
index_number+1);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
(*dependencies->prim_relations)[index_number] =
|
2004-01-21 08:18:30 +01:00
|
|
|
(BLK) (IPTR) partner_relation->rel_id;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-02-19 16:25:27 +01:00
|
|
|
dependencies->prim_indexes =
|
|
|
|
vec::newVector(*dbb->dbb_permanent, dependencies->prim_indexes,
|
|
|
|
index_number+1);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
(*dependencies->prim_indexes)[index_number] =
|
2004-01-21 08:18:30 +01:00
|
|
|
(BLK) (IPTR) (IND.RDB$INDEX_ID - 1);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
index_number++;
|
|
|
|
}
|
|
|
|
END_FOR;
|
|
|
|
|
|
|
|
if (!REQUEST(irq_foreign2))
|
|
|
|
REQUEST(irq_foreign2) = request;
|
|
|
|
|
|
|
|
relation->rel_flags &= ~REL_check_partners;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (idx->idx_flags & idx_foreign)
|
|
|
|
{
|
|
|
|
if (*index_name)
|
|
|
|
{
|
|
|
|
/* Since primary key index names aren't being cached, do a long
|
|
|
|
hard lookup. This is only called during index create for foreign
|
|
|
|
keys. */
|
|
|
|
|
2004-01-03 11:59:52 +01:00
|
|
|
bool found = false;
|
|
|
|
blk* request = NULL;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
FOR(REQUEST_HANDLE request)
|
|
|
|
IDX IN RDB$INDICES CROSS
|
|
|
|
IND IN RDB$INDICES WITH
|
|
|
|
IDX.RDB$RELATION_NAME EQ relation->rel_name AND
|
|
|
|
(IDX.RDB$INDEX_ID EQ idx->idx_id + 1 OR
|
2002-12-22 14:08:50 +01:00
|
|
|
IDX.RDB$INDEX_NAME EQ index_name) AND
|
2001-05-23 15:26:42 +02:00
|
|
|
IND.RDB$INDEX_NAME EQ IDX.RDB$FOREIGN_KEY AND
|
|
|
|
IND.RDB$UNIQUE_FLAG NOT MISSING
|
|
|
|
|
2004-01-03 11:59:52 +01:00
|
|
|
const jrd_rel* partner_relation =
|
2001-05-23 15:26:42 +02:00
|
|
|
MET_lookup_relation(tdbb, IND.RDB$RELATION_NAME);
|
|
|
|
|
|
|
|
if (partner_relation)
|
|
|
|
{
|
|
|
|
idx->idx_primary_relation = partner_relation->rel_id;
|
|
|
|
idx->idx_primary_index = IND.RDB$INDEX_ID - 1;
|
2004-01-03 11:59:52 +01:00
|
|
|
found = true;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
END_FOR;
|
|
|
|
|
2004-01-03 11:59:52 +01:00
|
|
|
CMP_release(tdbb, (jrd_req*)request);
|
2001-05-23 15:26:42 +02:00
|
|
|
return found;
|
|
|
|
}
|
|
|
|
|
2004-01-03 11:59:52 +01:00
|
|
|
frgn* references = &relation->rel_foreign_refs;
|
2001-05-23 15:26:42 +02:00
|
|
|
if (references->frgn_reference_ids)
|
|
|
|
{
|
2004-01-03 11:59:52 +01:00
|
|
|
for (int index_number = 0;
|
2003-08-09 23:15:32 +02:00
|
|
|
index_number < (int) references->frgn_reference_ids->count();
|
2001-05-23 15:26:42 +02:00
|
|
|
index_number++)
|
|
|
|
{
|
2004-01-21 08:18:30 +01:00
|
|
|
if (idx->idx_id == (UCHAR)(IPTR) (*references->frgn_reference_ids)
|
2001-12-24 03:51:06 +01:00
|
|
|
[index_number])
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
idx->idx_primary_relation =
|
2004-01-21 08:18:30 +01:00
|
|
|
(USHORT)(IPTR) (*references->frgn_relations)[index_number];
|
2001-05-23 15:26:42 +02:00
|
|
|
idx->idx_primary_index =
|
2004-01-21 08:18:30 +01:00
|
|
|
(UCHAR)(IPTR) (*references->frgn_indexes)[index_number];
|
2004-01-03 11:59:52 +01:00
|
|
|
return true;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2004-01-03 11:59:52 +01:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
else if (idx->idx_flags & (idx_primary | idx_unique))
|
|
|
|
{
|
2004-01-03 11:59:52 +01:00
|
|
|
const prim* dependencies = &relation->rel_primary_dpnds;
|
2001-05-23 15:26:42 +02:00
|
|
|
if (dependencies->prim_reference_ids)
|
|
|
|
{
|
2004-01-03 11:59:52 +01:00
|
|
|
for (int index_number = 0;
|
2003-08-09 23:15:32 +02:00
|
|
|
index_number < (int) dependencies->prim_reference_ids->count();
|
2001-05-23 15:26:42 +02:00
|
|
|
index_number++)
|
|
|
|
{
|
2004-01-21 08:18:30 +01:00
|
|
|
if (idx->idx_id == (UCHAR)(IPTR) (*dependencies->prim_reference_ids)
|
2001-12-24 03:51:06 +01:00
|
|
|
[index_number])
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
idx->idx_foreign_primaries =
|
|
|
|
relation->rel_primary_dpnds.prim_reference_ids;
|
|
|
|
idx->idx_foreign_relations =
|
|
|
|
relation->rel_primary_dpnds.prim_relations;
|
|
|
|
idx->idx_foreign_indexes =
|
|
|
|
relation->rel_primary_dpnds.prim_indexes;
|
2004-01-03 11:59:52 +01:00
|
|
|
return true;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2004-01-03 11:59:52 +01:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2004-01-03 11:59:52 +01:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-03-11 06:04:26 +01:00
|
|
|
jrd_prc* MET_lookup_procedure(thread_db* tdbb, SCHAR * name, bool noscan)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* M E T _ l o o k u p _ p r o c e d u r e
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Lookup procedure by name. Name passed in is
|
|
|
|
* ASCIZ name.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
SET_TDBB(tdbb);
|
2004-03-07 08:58:55 +01:00
|
|
|
Database* dbb = tdbb->tdbb_database;
|
2003-12-22 11:00:59 +01:00
|
|
|
jrd_prc* check_procedure = NULL;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2002-11-16 19:48:01 +01:00
|
|
|
/* See if we already know the procedure by name */
|
2004-01-03 11:59:52 +01:00
|
|
|
vec* procedures = dbb->dbb_procedures;
|
|
|
|
if (procedures) {
|
|
|
|
vec::iterator ptr = procedures->begin();
|
|
|
|
for (const vec::const_iterator end = procedures->end();
|
2002-11-16 21:20:44 +01:00
|
|
|
ptr < end; ptr++)
|
|
|
|
{
|
2004-01-03 11:59:52 +01:00
|
|
|
jrd_prc* procedure = (jrd_prc*)(*ptr);
|
|
|
|
if (procedure && !(procedure->prc_flags & PRC_obsolete)
|
2002-11-16 19:48:01 +01:00
|
|
|
&& ((procedure->prc_flags & PRC_scanned) || noscan)
|
2001-05-23 15:26:42 +02:00
|
|
|
&& !(procedure->prc_flags & PRC_being_scanned)
|
|
|
|
&& !(procedure->prc_flags & PRC_being_altered)
|
2002-11-17 01:13:59 +01:00
|
|
|
&& procedure->prc_name)
|
2002-11-16 19:48:01 +01:00
|
|
|
{
|
2004-01-03 11:59:52 +01:00
|
|
|
const SCHAR* p = (SCHAR*)procedure->prc_name->str_data;
|
|
|
|
for (const SCHAR* q = name; *p == *q; p++, q++)
|
2002-11-16 21:20:44 +01:00
|
|
|
{
|
2003-11-27 12:39:10 +01:00
|
|
|
if (*p == 0) {
|
|
|
|
if (procedure->prc_flags & PRC_check_existence) {
|
|
|
|
check_procedure = procedure;
|
2004-02-20 07:43:27 +01:00
|
|
|
LCK_lock(tdbb, check_procedure->prc_existence_lock,
|
|
|
|
LCK_SR, TRUE);
|
2003-11-27 12:39:10 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return procedure;
|
|
|
|
}
|
|
|
|
}
|
2002-11-16 21:20:44 +01:00
|
|
|
}
|
2002-11-16 19:48:01 +01:00
|
|
|
}
|
2003-11-27 12:39:10 +01:00
|
|
|
if (check_procedure) {
|
|
|
|
break;
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2004-01-03 11:59:52 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* We need to look up the procedure name in RDB$PROCEDURES */
|
|
|
|
|
2004-01-03 11:59:52 +01:00
|
|
|
jrd_prc* procedure = NULL;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-02-20 07:43:27 +01:00
|
|
|
blk* request = CMP_find_request(tdbb, irq_l_procedure, IRQ_REQUESTS);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
FOR(REQUEST_HANDLE request)
|
|
|
|
P IN RDB$PROCEDURES WITH P.RDB$PROCEDURE_NAME EQ name
|
|
|
|
|
2001-07-12 08:32:05 +02:00
|
|
|
if (!REQUEST(irq_l_procedure))
|
2001-05-23 15:26:42 +02:00
|
|
|
REQUEST(irq_l_procedure) = request;
|
|
|
|
|
2002-11-04 16:12:34 +01:00
|
|
|
procedure = MET_procedure(tdbb, P.RDB$PROCEDURE_ID, noscan, 0);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
END_FOR;
|
|
|
|
|
|
|
|
if (!REQUEST(irq_l_procedure))
|
|
|
|
REQUEST(irq_l_procedure) = request;
|
|
|
|
|
2003-11-27 12:39:10 +01:00
|
|
|
if (check_procedure) {
|
|
|
|
check_procedure->prc_flags &= ~PRC_check_existence;
|
|
|
|
if (check_procedure != procedure) {
|
|
|
|
LCK_release(tdbb, check_procedure->prc_existence_lock);
|
|
|
|
check_procedure->prc_flags |= PRC_obsolete;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
return procedure;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-03-11 06:04:26 +01:00
|
|
|
jrd_prc* MET_lookup_procedure_id(thread_db* tdbb, SSHORT id,
|
2004-02-20 07:43:27 +01:00
|
|
|
bool return_deleted, bool noscan, USHORT flags)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* M E T _ l o o k u p _ p r o c e d u r e _ i d
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Lookup procedure by id.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
SET_TDBB(tdbb);
|
2004-03-07 08:58:55 +01:00
|
|
|
Database* dbb = tdbb->tdbb_database;
|
2003-12-22 11:00:59 +01:00
|
|
|
jrd_prc* check_procedure = NULL;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-01-03 11:59:52 +01:00
|
|
|
jrd_prc* procedure;
|
|
|
|
|
|
|
|
VEC procedures = dbb->dbb_procedures;
|
|
|
|
if (procedures
|
2003-08-09 23:15:32 +02:00
|
|
|
&& id < (SSHORT) procedures->count()
|
2003-12-22 11:00:59 +01:00
|
|
|
&& (procedure = (jrd_prc*)(*procedures)[id])
|
2002-11-16 19:48:01 +01:00
|
|
|
&& procedure->prc_id == id
|
|
|
|
&& !(procedure->prc_flags & PRC_being_scanned)
|
|
|
|
&& ((procedure->prc_flags & PRC_scanned) || noscan)
|
|
|
|
&& !(procedure->prc_flags & PRC_being_altered)
|
|
|
|
&& (!(procedure->prc_flags & PRC_obsolete) || return_deleted))
|
|
|
|
{
|
2003-11-27 12:39:10 +01:00
|
|
|
if (procedure->prc_flags & PRC_check_existence) {
|
|
|
|
check_procedure = procedure;
|
|
|
|
LCK_lock(tdbb, check_procedure->prc_existence_lock, LCK_SR, TRUE);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return procedure;
|
|
|
|
}
|
2002-11-16 19:48:01 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* We need to look up the procedure name in RDB$PROCEDURES */
|
|
|
|
|
|
|
|
procedure = NULL;
|
|
|
|
|
2004-02-20 07:43:27 +01:00
|
|
|
blk* request = CMP_find_request(tdbb, irq_l_proc_id, IRQ_REQUESTS);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
FOR(REQUEST_HANDLE request)
|
|
|
|
P IN RDB$PROCEDURES WITH P.RDB$PROCEDURE_ID EQ id
|
|
|
|
|
2001-07-12 08:32:05 +02:00
|
|
|
if (!REQUEST(irq_l_proc_id))
|
2001-05-23 15:26:42 +02:00
|
|
|
REQUEST(irq_l_proc_id) = request;
|
|
|
|
|
2002-11-04 16:12:34 +01:00
|
|
|
procedure = MET_procedure(tdbb, P.RDB$PROCEDURE_ID, noscan, flags);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
END_FOR;
|
|
|
|
|
|
|
|
if (!REQUEST(irq_l_proc_id))
|
|
|
|
REQUEST(irq_l_proc_id) = request;
|
|
|
|
|
2003-11-27 12:39:10 +01:00
|
|
|
if (check_procedure) {
|
|
|
|
check_procedure->prc_flags &= ~PRC_check_existence;
|
|
|
|
if (check_procedure != procedure) {
|
|
|
|
LCK_release(tdbb, check_procedure->prc_existence_lock);
|
|
|
|
check_procedure->prc_flags |= PRC_obsolete;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
return procedure;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-03-11 06:04:26 +01:00
|
|
|
jrd_rel* MET_lookup_relation(thread_db* tdbb, const char* name)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* M E T _ l o o k u p _ r e l a t i o n
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Lookup relation by name. Name passed in is
|
|
|
|
* ASCIZ name.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
SET_TDBB(tdbb);
|
2004-03-07 08:58:55 +01:00
|
|
|
Database* dbb = tdbb->tdbb_database;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* See if we already know the relation by name */
|
|
|
|
|
2004-01-03 11:59:52 +01:00
|
|
|
vec* relations = dbb->dbb_relations;
|
|
|
|
jrd_rel* check_relation = NULL;
|
|
|
|
const UCHAR length = strlen(name);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-01-03 11:59:52 +01:00
|
|
|
vec::iterator ptr = relations->begin();
|
|
|
|
for (const vec::const_iterator end = relations->end(); ptr < end; ptr++)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2004-01-03 11:59:52 +01:00
|
|
|
const SCHAR* p;
|
|
|
|
jrd_rel* relation = reinterpret_cast<jrd_rel*>(*ptr);
|
|
|
|
if (relation &&
|
2001-05-23 15:26:42 +02:00
|
|
|
(relation->rel_length == length) &&
|
|
|
|
(!(relation->rel_flags & REL_deleted)) &&
|
|
|
|
(p = relation->rel_name))
|
|
|
|
{
|
2003-02-24 16:19:20 +01:00
|
|
|
/* dimitr: for non-system relations we should also check
|
|
|
|
REL_scanned and REL_being_scanned flags. Look
|
|
|
|
at MET_lookup_procedure for example. */
|
|
|
|
if (!(relation->rel_flags & REL_system) &&
|
|
|
|
(!(relation->rel_flags & REL_scanned) ||
|
2004-01-03 11:59:52 +01:00
|
|
|
(relation->rel_flags & REL_being_scanned)))
|
|
|
|
{
|
2003-02-24 16:37:15 +01:00
|
|
|
continue;
|
2003-02-24 16:19:20 +01:00
|
|
|
}
|
|
|
|
|
2004-01-03 11:59:52 +01:00
|
|
|
for (const SCHAR* q = name; *p == *q; p++, q++)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
if (*p == 0)
|
|
|
|
{
|
|
|
|
if (relation->rel_flags & REL_check_existence)
|
|
|
|
{
|
|
|
|
check_relation = relation;
|
|
|
|
LCK_lock(tdbb, check_relation->rel_existence_lock,
|
|
|
|
LCK_SR, TRUE);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return relation;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (check_relation)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* We need to look up the relation name in RDB$RELATIONS */
|
|
|
|
|
2004-01-03 11:59:52 +01:00
|
|
|
jrd_rel* relation = NULL;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-02-20 07:43:27 +01:00
|
|
|
blk* request = CMP_find_request(tdbb, irq_l_relation, IRQ_REQUESTS);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
FOR(REQUEST_HANDLE request)
|
|
|
|
X IN RDB$RELATIONS WITH X.RDB$RELATION_NAME EQ name
|
|
|
|
|
|
|
|
if (!REQUEST(irq_l_relation))
|
|
|
|
{
|
|
|
|
REQUEST(irq_l_relation) = request;
|
|
|
|
}
|
|
|
|
|
|
|
|
relation = MET_relation(tdbb, X.RDB$RELATION_ID);
|
|
|
|
if (!relation->rel_name)
|
|
|
|
{
|
|
|
|
relation->rel_name = MET_save_name(tdbb, name);
|
|
|
|
relation->rel_length = strlen(relation->rel_name);
|
|
|
|
}
|
|
|
|
END_FOR;
|
|
|
|
|
|
|
|
if (!REQUEST(irq_l_relation))
|
|
|
|
{
|
|
|
|
REQUEST(irq_l_relation) = request;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (check_relation) {
|
|
|
|
check_relation->rel_flags &= ~REL_check_existence;
|
|
|
|
if (check_relation != relation) {
|
|
|
|
LCK_release(tdbb, check_relation->rel_existence_lock);
|
|
|
|
check_relation->rel_flags |= REL_deleted;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return relation;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-03-11 06:04:26 +01:00
|
|
|
jrd_rel* MET_lookup_relation_id(thread_db* tdbb, SLONG id, bool return_deleted)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* M E T _ l o o k u p _ r e l a t i o n _ i d
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Lookup relation by id. Make sure it really exists.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
SET_TDBB(tdbb);
|
2004-03-07 08:58:55 +01:00
|
|
|
Database* dbb = tdbb->tdbb_database;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* System relations are above suspicion */
|
|
|
|
|
|
|
|
if (id < (int) rel_MAX)
|
|
|
|
{
|
2003-11-04 00:59:24 +01:00
|
|
|
fb_assert((USHORT)id < MAX_USHORT);
|
2001-05-23 15:26:42 +02:00
|
|
|
return MET_relation(tdbb, (USHORT) id);
|
|
|
|
}
|
|
|
|
|
2004-01-03 11:59:52 +01:00
|
|
|
jrd_rel* check_relation = NULL;
|
|
|
|
jrd_rel* relation;
|
|
|
|
vec* vector = dbb->dbb_relations;
|
|
|
|
if (vector &&
|
2003-12-22 11:00:59 +01:00
|
|
|
(id < (SLONG) vector->count()) && (relation = (jrd_rel*) (*vector)[id]))
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
if (relation->rel_flags & REL_deleted)
|
|
|
|
{
|
|
|
|
if (return_deleted)
|
|
|
|
return relation;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
else if (relation->rel_flags & REL_check_existence)
|
|
|
|
{
|
|
|
|
check_relation = relation;
|
|
|
|
LCK_lock(tdbb, check_relation->rel_existence_lock, LCK_SR, TRUE);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return relation;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* We need to look up the relation id in RDB$RELATIONS */
|
|
|
|
|
|
|
|
relation = NULL;
|
|
|
|
|
2004-02-20 07:43:27 +01:00
|
|
|
blk* request = CMP_find_request(tdbb, irq_l_rel_id, IRQ_REQUESTS);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
FOR(REQUEST_HANDLE request)
|
|
|
|
X IN RDB$RELATIONS WITH X.RDB$RELATION_ID EQ id
|
|
|
|
|
2004-01-03 11:59:52 +01:00
|
|
|
if (!REQUEST(irq_l_rel_id))
|
|
|
|
REQUEST(irq_l_rel_id) = request;
|
2001-05-23 15:26:42 +02:00
|
|
|
relation = MET_relation(tdbb, X.RDB$RELATION_ID);
|
|
|
|
if (!relation->rel_name) {
|
|
|
|
relation->rel_name = MET_save_name(tdbb, X.RDB$RELATION_NAME);
|
|
|
|
relation->rel_length = strlen(relation->rel_name);
|
|
|
|
}
|
|
|
|
END_FOR;
|
|
|
|
|
|
|
|
if (!REQUEST(irq_l_rel_id))
|
|
|
|
REQUEST(irq_l_rel_id) = request;
|
|
|
|
|
|
|
|
if (check_relation) {
|
|
|
|
check_relation->rel_flags &= ~REL_check_existence;
|
|
|
|
if (check_relation != relation) {
|
|
|
|
LCK_release(tdbb, check_relation->rel_existence_lock);
|
|
|
|
check_relation->rel_flags |= REL_deleted;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return relation;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-03-18 06:56:06 +01:00
|
|
|
jrd_nod* MET_parse_blob(thread_db* tdbb,
|
2003-12-22 11:00:59 +01:00
|
|
|
jrd_rel* relation,
|
2004-03-18 06:56:06 +01:00
|
|
|
bid* blob_id,
|
2004-01-13 10:52:19 +01:00
|
|
|
Csb** csb_ptr,
|
2004-03-18 06:56:06 +01:00
|
|
|
jrd_req** request_ptr,
|
|
|
|
const bool trigger,
|
|
|
|
const bool ignore_perm)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* M E T _ p a r s e _ b l o b
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Parse blr, returning a compiler scratch block with the results.
|
|
|
|
*
|
|
|
|
* if ignore_perm is true then, the request generated must be set to
|
|
|
|
* ignore all permissions checks. In this case, we call PAR_blr
|
|
|
|
* passing it the csb_ignore_perm flag to generate a request
|
|
|
|
* which must go through without checking any permissions.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
SET_TDBB(tdbb);
|
2004-03-07 08:58:55 +01:00
|
|
|
Database* dbb = tdbb->tdbb_database;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-01-21 08:18:30 +01:00
|
|
|
blb* blob = BLB_open(tdbb, dbb->dbb_sys_trans, blob_id);
|
2004-01-03 11:59:52 +01:00
|
|
|
const SLONG length = blob->blb_length + 10;
|
|
|
|
str* temp = FB_NEW_RPT(*tdbb->tdbb_default, length) str();
|
2001-05-23 15:26:42 +02:00
|
|
|
BLB_get_data(tdbb, blob, temp->str_data, length);
|
|
|
|
|
2004-01-03 11:59:52 +01:00
|
|
|
jrd_nod* node = PAR_blr(tdbb, relation, temp->str_data, NULL, csb_ptr, request_ptr,
|
2003-08-28 15:16:03 +02:00
|
|
|
trigger, (USHORT)(ignore_perm ? csb_ignore_perm : 0));
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
delete temp;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
return node;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-03-11 06:04:26 +01:00
|
|
|
void MET_parse_sys_trigger(thread_db* tdbb, jrd_rel* relation)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* M E T _ p a r s e _ s y s _ t r i g g e r
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Parse the blr for a system relation's triggers.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
SET_TDBB(tdbb);
|
2004-03-07 08:58:55 +01:00
|
|
|
Database* dbb = tdbb->tdbb_database;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
relation->rel_flags &= ~REL_sys_triggers;
|
|
|
|
|
|
|
|
/* release any triggers in case of a rescan */
|
|
|
|
|
|
|
|
if (relation->rel_pre_store)
|
|
|
|
MET_release_triggers(tdbb, &relation->rel_pre_store);
|
|
|
|
if (relation->rel_post_store)
|
|
|
|
MET_release_triggers(tdbb, &relation->rel_post_store);
|
|
|
|
if (relation->rel_pre_erase)
|
|
|
|
MET_release_triggers(tdbb, &relation->rel_pre_erase);
|
|
|
|
if (relation->rel_post_erase)
|
|
|
|
MET_release_triggers(tdbb, &relation->rel_post_erase);
|
|
|
|
if (relation->rel_pre_modify)
|
|
|
|
MET_release_triggers(tdbb, &relation->rel_pre_modify);
|
|
|
|
if (relation->rel_post_modify)
|
|
|
|
MET_release_triggers(tdbb, &relation->rel_post_modify);
|
|
|
|
|
|
|
|
/* No need to load triggers for ReadOnly databases, since
|
|
|
|
INSERT/DELETE/UPDATE statements are not going to be allowed */
|
|
|
|
|
|
|
|
if (dbb->dbb_flags & DBB_read_only)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
relation->rel_flags |= REL_sys_trigs_being_loaded;
|
|
|
|
|
2003-12-03 09:19:24 +01:00
|
|
|
const jrd_trg* trigger = NULL;
|
|
|
|
const UCHAR* blr;
|
|
|
|
UCHAR type;
|
|
|
|
const TEXT* name;
|
|
|
|
USHORT trig_flags;
|
2004-01-03 11:59:52 +01:00
|
|
|
jrd_req* request;
|
2003-12-03 09:19:24 +01:00
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
while ( (trigger =
|
2003-12-03 09:19:24 +01:00
|
|
|
INI_lookup_sys_trigger(relation,
|
|
|
|
trigger,
|
2001-05-23 15:26:42 +02:00
|
|
|
&blr,
|
|
|
|
&type,
|
|
|
|
&name,
|
2001-12-24 03:51:06 +01:00
|
|
|
&trig_flags)) )
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2004-01-03 11:59:52 +01:00
|
|
|
trig_vec** ptr;
|
2001-05-23 15:26:42 +02:00
|
|
|
switch (type) {
|
|
|
|
case 1:
|
|
|
|
ptr = &relation->rel_pre_store;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
ptr = &relation->rel_post_store;
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
ptr = &relation->rel_pre_modify;
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
ptr = &relation->rel_post_modify;
|
|
|
|
break;
|
|
|
|
case 5:
|
|
|
|
ptr = &relation->rel_pre_erase;
|
|
|
|
break;
|
|
|
|
case 6:
|
|
|
|
ptr = &relation->rel_post_erase;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
ptr = NULL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ptr)
|
|
|
|
{
|
|
|
|
const USHORT par_flags = (USHORT)
|
|
|
|
((trig_flags & TRG_ignore_perm) ? csb_ignore_perm : 0);
|
|
|
|
|
2004-01-03 11:59:52 +01:00
|
|
|
JrdMemoryPool* old_pool = tdbb->tdbb_default;
|
2003-01-16 18:47:10 +01:00
|
|
|
tdbb->tdbb_default = JrdMemoryPool::createPool();
|
2003-12-03 09:19:24 +01:00
|
|
|
PAR_blr(tdbb, relation, blr, NULL, NULL,
|
2004-03-18 06:56:06 +01:00
|
|
|
&request, true, par_flags);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
tdbb->tdbb_default = old_pool;
|
|
|
|
|
2004-01-03 11:59:52 +01:00
|
|
|
request->req_trg_name = name;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
request->req_flags |= req_sys_trigger;
|
|
|
|
if (trig_flags & TRG_ignore_perm)
|
|
|
|
{
|
|
|
|
request->req_flags |= req_ignore_perm;
|
|
|
|
}
|
|
|
|
|
2003-12-03 09:19:24 +01:00
|
|
|
save_trigger_data(tdbb, ptr, relation, request, NULL, NULL, true, 0);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
relation->rel_flags &= ~REL_sys_trigs_being_loaded;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-03-11 06:04:26 +01:00
|
|
|
int MET_post_existence( thread_db* tdbb, jrd_rel* relation)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* M E T _ p o s t _ e x i s t e n c e
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Post an interest in the existence of a relation.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
SET_TDBB(tdbb);
|
|
|
|
|
|
|
|
if (++relation->rel_use_count == 1 &&
|
2004-02-20 07:43:27 +01:00
|
|
|
!MET_lookup_relation_id(tdbb, relation->rel_id, false))
|
2004-01-03 11:59:52 +01:00
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
return FALSE;
|
2004-01-03 11:59:52 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-03-11 06:04:26 +01:00
|
|
|
void MET_prepare( thread_db* tdbb, jrd_tra* transaction, USHORT length,
|
2003-10-29 11:53:47 +01:00
|
|
|
const UCHAR* msg)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
2001-07-12 08:32:05 +02:00
|
|
|
* M E T _ p r e p a r e
|
2001-05-23 15:26:42 +02:00
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Post a transaction description to RDB$TRANSACTIONS.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
SET_TDBB(tdbb);
|
2004-03-07 08:58:55 +01:00
|
|
|
Database* dbb = tdbb->tdbb_database;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-02-20 07:43:27 +01:00
|
|
|
blk* request = CMP_find_request(tdbb, irq_s_trans, IRQ_REQUESTS);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
STORE(REQUEST_HANDLE request) X IN RDB$TRANSACTIONS
|
|
|
|
X.RDB$TRANSACTION_ID = transaction->tra_number;
|
|
|
|
X.RDB$TRANSACTION_STATE =
|
|
|
|
RDB$TRANSACTIONS.RDB$TRANSACTION_STATE.LIMBO;
|
2004-01-03 11:59:52 +01:00
|
|
|
blb* blob =
|
2001-05-23 15:26:42 +02:00
|
|
|
BLB_create(tdbb, dbb->dbb_sys_trans,
|
2004-01-21 08:18:30 +01:00
|
|
|
&X.RDB$TRANSACTION_DESCRIPTION);
|
2001-05-23 15:26:42 +02:00
|
|
|
BLB_put_segment(tdbb, blob, msg, length);
|
|
|
|
BLB_close(tdbb, blob);
|
|
|
|
END_STORE;
|
|
|
|
|
|
|
|
if (!REQUEST(irq_s_trans))
|
|
|
|
REQUEST(irq_s_trans) = request;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-03-11 06:04:26 +01:00
|
|
|
jrd_prc* MET_procedure(thread_db* tdbb, int id, bool noscan, USHORT flags)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* M E T _ p r o c e d u r e
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Find or create a procedure block for a given procedure id.
|
|
|
|
*
|
|
|
|
**************************************/
|
2001-12-24 03:51:06 +01:00
|
|
|
BLK request, request2;
|
|
|
|
vec::iterator ptr, end;
|
2001-05-23 15:26:42 +02:00
|
|
|
PRM parameter;
|
2001-12-24 03:51:06 +01:00
|
|
|
JrdMemoryPool *old_pool;
|
2004-01-13 10:52:19 +01:00
|
|
|
jrd_nod* node;
|
2004-01-28 08:50:41 +01:00
|
|
|
fmt* format;
|
2001-12-24 03:51:06 +01:00
|
|
|
fmt::fmt_desc_iterator desc;
|
2001-05-23 15:26:42 +02:00
|
|
|
SSHORT i;
|
|
|
|
|
|
|
|
SET_TDBB(tdbb);
|
2004-03-07 08:58:55 +01:00
|
|
|
Database* dbb = tdbb->tdbb_database;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-01-03 11:59:52 +01:00
|
|
|
vec* vector = dbb->dbb_procedures;
|
|
|
|
if (!vector)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2001-12-24 03:51:06 +01:00
|
|
|
vector = dbb->dbb_procedures = vec::newVector(*dbb->dbb_permanent, id + 10);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2003-08-09 23:15:32 +02:00
|
|
|
else if (id >= (int) vector->count())
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2001-12-24 03:51:06 +01:00
|
|
|
vector->resize(id + 10);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef SUPERSERVER
|
|
|
|
|
|
|
|
if (!(dbb->dbb_flags & DBB_sp_rec_mutex_init))
|
|
|
|
{
|
|
|
|
THD_rec_mutex_init(&dbb->dbb_sp_rec_mutex);
|
|
|
|
dbb->dbb_flags |= DBB_sp_rec_mutex_init;
|
|
|
|
}
|
|
|
|
THREAD_EXIT;
|
2001-07-12 08:32:05 +02:00
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
if (THD_rec_mutex_lock(&dbb->dbb_sp_rec_mutex))
|
|
|
|
{
|
|
|
|
THREAD_ENTER;
|
|
|
|
return NULL;
|
|
|
|
}
|
2001-07-12 08:32:05 +02:00
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
THREAD_ENTER;
|
|
|
|
|
|
|
|
#endif /* SUPERSERVER */
|
|
|
|
|
2004-01-03 11:59:52 +01:00
|
|
|
jrd_prc* procedure = (jrd_prc*) (*vector)[id];
|
2001-05-23 15:26:42 +02:00
|
|
|
if (procedure)
|
|
|
|
{
|
|
|
|
/* Make sure PRC_being_scanned and PRC_scanned
|
|
|
|
are not set at the same time
|
|
|
|
*/
|
2003-11-04 00:59:24 +01:00
|
|
|
fb_assert(!(procedure->prc_flags & PRC_being_scanned) ||
|
2001-05-23 15:26:42 +02:00
|
|
|
!(procedure->prc_flags & PRC_scanned));
|
|
|
|
|
|
|
|
/* To avoid scanning recursive procedure's blr recursively let's
|
|
|
|
make use of PRC_being_scanned bit. Because this bit is set
|
|
|
|
later in the code, it is not set when we are here first time.
|
2001-07-12 08:32:05 +02:00
|
|
|
If (in case of rec. procedure) we get here second time it is
|
2001-05-23 15:26:42 +02:00
|
|
|
already set and we return half baked procedure.
|
|
|
|
In case of superserver this code is under the rec. mutex
|
|
|
|
protection, thus the only guy (thread) who can get here and see
|
|
|
|
PRC_being_scanned bit set is the guy which started procedure scan
|
|
|
|
and currently holds the mutex.
|
2001-07-12 08:32:05 +02:00
|
|
|
In case of classic, there is always only one guy and if it
|
2001-05-23 15:26:42 +02:00
|
|
|
sees PRC_being_scanned bit set it is safe to assume it is here
|
|
|
|
second time.
|
|
|
|
|
|
|
|
If procedure has already been scanned - return. This condition
|
2001-07-12 08:32:05 +02:00
|
|
|
is for those threads that did not find procedure in cach and
|
2001-05-23 15:26:42 +02:00
|
|
|
came here to get it from disk. But only one was able to lock
|
|
|
|
the mutex and do the scanning, others were waiting. As soon as
|
|
|
|
the first thread releases the mutex another thread gets in and
|
|
|
|
it would be just unfair to make it do the work again
|
|
|
|
*/
|
|
|
|
if ((procedure->prc_flags & PRC_being_scanned) ||
|
|
|
|
(procedure->prc_flags & PRC_scanned))
|
|
|
|
{
|
|
|
|
|
|
|
|
#ifdef SUPERSERVER
|
|
|
|
THD_rec_mutex_unlock(&dbb->dbb_sp_rec_mutex);
|
|
|
|
#endif
|
|
|
|
return procedure;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!procedure)
|
|
|
|
{
|
2002-11-21 00:18:16 +01:00
|
|
|
procedure = FB_NEW_RPT(*dbb->dbb_permanent, 0) jrd_prc;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
try {
|
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
procedure->prc_flags |= (PRC_being_scanned | flags);
|
2003-06-01 18:22:47 +02:00
|
|
|
procedure->prc_flags &= ~PRC_obsolete;
|
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
procedure->prc_id = id;
|
2004-02-20 07:43:27 +01:00
|
|
|
(*vector)[id] = procedure;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2002-11-04 16:12:34 +01:00
|
|
|
if (!procedure->prc_existence_lock) {
|
2004-03-18 06:56:06 +01:00
|
|
|
Lock* lock = FB_NEW_RPT(*dbb->dbb_permanent, 0) Lock;
|
2004-01-03 11:59:52 +01:00
|
|
|
procedure->prc_existence_lock = lock;
|
2002-11-04 16:12:34 +01:00
|
|
|
lock->lck_parent = dbb->dbb_lock;
|
|
|
|
lock->lck_dbb = dbb;
|
|
|
|
lock->lck_key.lck_long = procedure->prc_id;
|
|
|
|
lock->lck_length = sizeof(lock->lck_key.lck_long);
|
|
|
|
lock->lck_type = LCK_prc_exist;
|
|
|
|
lock->lck_owner_handle = LCK_get_owner_handle(tdbb, lock->lck_type);
|
2004-02-20 07:43:27 +01:00
|
|
|
lock->lck_object = procedure;
|
2003-05-16 22:35:19 +02:00
|
|
|
lock->lck_ast = blocking_ast_procedure;
|
2002-11-04 16:12:34 +01:00
|
|
|
|
|
|
|
LCK_lock(tdbb, procedure->prc_existence_lock, LCK_SR, TRUE);
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2002-11-04 16:12:34 +01:00
|
|
|
if (!noscan) {
|
2004-02-20 07:43:27 +01:00
|
|
|
request = CMP_find_request(tdbb, irq_r_procedure, IRQ_REQUESTS);
|
|
|
|
request2 = CMP_find_request(tdbb, irq_r_params, IRQ_REQUESTS);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-01-04 05:41:56 +01:00
|
|
|
FOR(REQUEST_HANDLE request)
|
|
|
|
P IN RDB$PROCEDURES WITH P.RDB$PROCEDURE_ID EQ procedure->prc_id
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-01-04 05:41:56 +01:00
|
|
|
if (!REQUEST(irq_r_procedure))
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2004-01-04 05:41:56 +01:00
|
|
|
REQUEST(irq_r_procedure) = request;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2004-01-04 05:41:56 +01:00
|
|
|
if (!procedure->prc_name)
|
|
|
|
{
|
|
|
|
procedure->prc_name = save_name(tdbb, P.RDB$PROCEDURE_NAME);
|
|
|
|
}
|
|
|
|
procedure->prc_id = P.RDB$PROCEDURE_ID;
|
|
|
|
if (!P.RDB$SECURITY_CLASS.NULL)
|
|
|
|
{
|
|
|
|
procedure->prc_security_name =
|
|
|
|
save_name(tdbb, P.RDB$SECURITY_CLASS);
|
|
|
|
}
|
|
|
|
if (P.RDB$SYSTEM_FLAG.NULL || !P.RDB$SYSTEM_FLAG)
|
|
|
|
{
|
|
|
|
procedure->prc_flags &= ~PRC_system;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
procedure->prc_flags |= PRC_system;
|
|
|
|
}
|
|
|
|
if ( (procedure->prc_inputs = P.RDB$PROCEDURE_INPUTS) )
|
|
|
|
{
|
|
|
|
procedure->prc_input_fields =
|
|
|
|
vec::newVector(*dbb->dbb_permanent, procedure->prc_input_fields,
|
|
|
|
P.RDB$PROCEDURE_INPUTS + 1);
|
|
|
|
}
|
|
|
|
if ( (procedure->prc_outputs = P.RDB$PROCEDURE_OUTPUTS) )
|
|
|
|
{
|
|
|
|
procedure->prc_output_fields =
|
|
|
|
vec::newVector(*dbb->dbb_permanent, procedure->prc_output_fields,
|
|
|
|
P.RDB$PROCEDURE_OUTPUTS + 1);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2004-01-16 13:59:16 +01:00
|
|
|
procedure->prc_defaults = 0;
|
2004-01-04 05:41:56 +01:00
|
|
|
FOR(REQUEST_HANDLE request2) PA IN RDB$PROCEDURE_PARAMETERS CROSS
|
|
|
|
F IN RDB$FIELDS WITH F.RDB$FIELD_NAME = PA.RDB$FIELD_SOURCE
|
|
|
|
AND PA.RDB$PROCEDURE_NAME = P.RDB$PROCEDURE_NAME
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-01-04 05:41:56 +01:00
|
|
|
if (!REQUEST(irq_r_params))
|
|
|
|
{
|
|
|
|
REQUEST(irq_r_params) = request2;
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-01-04 05:41:56 +01:00
|
|
|
if (PA.RDB$PARAMETER_TYPE) {
|
|
|
|
vector = procedure->prc_output_fields;
|
2004-01-28 08:50:41 +01:00
|
|
|
}
|
|
|
|
else {
|
2004-01-04 05:41:56 +01:00
|
|
|
vector = procedure->prc_input_fields;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* should be error if field already exists */
|
|
|
|
parameter =
|
|
|
|
FB_NEW_RPT(*dbb->dbb_permanent, name_length(PA.RDB$PARAMETER_NAME)) prm();
|
|
|
|
parameter->prm_number = PA.RDB$PARAMETER_NUMBER;
|
|
|
|
(*vector)[parameter->prm_number] = (BLK) parameter;
|
|
|
|
name_copy(parameter->prm_string, PA.RDB$PARAMETER_NAME);
|
|
|
|
parameter->prm_name = parameter->prm_string;
|
|
|
|
DSC_make_descriptor(¶meter->prm_desc, F.RDB$FIELD_TYPE,
|
|
|
|
F.RDB$FIELD_SCALE, F.RDB$FIELD_LENGTH,
|
|
|
|
F.RDB$FIELD_SUB_TYPE, F.RDB$CHARACTER_SET_ID,
|
|
|
|
F.RDB$COLLATION_ID);
|
2004-01-16 13:59:16 +01:00
|
|
|
|
|
|
|
if ((PA.RDB$PARAMETER_TYPE == 0) && !F.RDB$DEFAULT_VALUE.NULL) {
|
|
|
|
procedure->prc_defaults++;
|
|
|
|
|
|
|
|
old_pool = tdbb->tdbb_default;
|
|
|
|
tdbb->tdbb_default = JrdMemoryPool::createPool();
|
|
|
|
|
2004-03-11 06:04:26 +01:00
|
|
|
Csb* csb = Csb::newCsb(*tdbb->tdbb_default, 5);
|
2004-01-16 13:59:16 +01:00
|
|
|
parameter->prm_default_val =
|
2004-03-11 06:04:26 +01:00
|
|
|
parse_param_blr(tdbb, procedure, &F.RDB$DEFAULT_VALUE, csb);
|
2004-01-16 13:59:16 +01:00
|
|
|
|
2004-03-11 06:04:26 +01:00
|
|
|
delete csb;
|
2004-01-16 13:59:16 +01:00
|
|
|
tdbb->tdbb_default = old_pool;
|
|
|
|
}
|
|
|
|
|
2004-01-04 05:41:56 +01:00
|
|
|
END_FOR;
|
|
|
|
|
|
|
|
if (!REQUEST(irq_r_params)) {
|
|
|
|
REQUEST(irq_r_params) = request2;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((vector = procedure->prc_output_fields) && (*vector)[0])
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2004-01-04 05:41:56 +01:00
|
|
|
ULONG length;
|
|
|
|
format = procedure->prc_format =
|
|
|
|
fmt::newFmt(*dbb->dbb_permanent, procedure->prc_outputs);
|
|
|
|
format->fmt_count = procedure->prc_outputs;
|
|
|
|
length = FLAG_BYTES(format->fmt_count);
|
|
|
|
desc = format->fmt_desc.begin();
|
|
|
|
for (ptr = vector->begin(), end = vector->end();
|
|
|
|
ptr < end; ptr++, desc++)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2004-01-04 05:41:56 +01:00
|
|
|
parameter = (PRM) * ptr;
|
|
|
|
/* check for parameter to be null, this can only happen if the
|
|
|
|
* parameter numbers get out of sync. This was added to fix bug
|
|
|
|
* 10534. -Shaunak Mistry 12-May-99
|
|
|
|
*/
|
|
|
|
if (parameter)
|
|
|
|
{
|
|
|
|
*desc = parameter->prm_desc;
|
|
|
|
length = MET_align(&*desc, length);
|
2004-01-21 08:18:30 +01:00
|
|
|
desc->dsc_address = (UCHAR *) (IPTR) length;
|
2004-01-04 05:41:56 +01:00
|
|
|
length += desc->dsc_length;
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2004-01-04 05:41:56 +01:00
|
|
|
format->fmt_length = (USHORT) length;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2004-01-04 05:41:56 +01:00
|
|
|
old_pool = tdbb->tdbb_default;
|
|
|
|
tdbb->tdbb_default = JrdMemoryPool::createPool();
|
2004-03-11 06:04:26 +01:00
|
|
|
Csb* csb = Csb::newCsb(*tdbb->tdbb_default, 5);
|
2004-02-20 07:43:27 +01:00
|
|
|
// Now, check the result of this function here! Null pointer means failure.
|
|
|
|
// Or should parse_procedure_blr and its callee throw exceptions instead?
|
2004-03-11 06:04:26 +01:00
|
|
|
if (!parse_procedure_blr(tdbb, procedure, &P.RDB$PROCEDURE_BLR, csb))
|
2004-02-21 10:24:14 +01:00
|
|
|
ERR_post(isc_random, isc_arg_string, "Error while parsing procedure's BLR.", 0);
|
2004-01-04 05:41:56 +01:00
|
|
|
procedure->prc_request->req_procedure = procedure;
|
2004-03-11 06:04:26 +01:00
|
|
|
for (i = 0; i < csb->csb_rpt.getCount(); i++)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2004-03-11 06:04:26 +01:00
|
|
|
if ( (node = csb->csb_rpt[i].csb_message) )
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2004-01-04 05:41:56 +01:00
|
|
|
if ((int) (IPTR) node->nod_arg[e_msg_number] == 0)
|
|
|
|
{
|
|
|
|
procedure->prc_input_msg = node;
|
2004-01-28 08:50:41 +01:00
|
|
|
}
|
|
|
|
else if ((int) (IPTR) node->nod_arg[e_msg_number] == 1)
|
2004-01-04 05:41:56 +01:00
|
|
|
{
|
|
|
|
procedure->prc_output_msg = node;
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
}
|
2004-03-11 06:04:26 +01:00
|
|
|
delete csb;
|
2004-01-04 05:41:56 +01:00
|
|
|
tdbb->tdbb_default = old_pool;
|
|
|
|
|
|
|
|
END_FOR;
|
|
|
|
|
|
|
|
if (!REQUEST(irq_r_procedure)) {
|
|
|
|
REQUEST(irq_r_procedure) = request;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2004-01-04 05:41:56 +01:00
|
|
|
procedure->prc_flags |= PRC_scanned;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2002-11-04 16:12:34 +01:00
|
|
|
} /* if !noscan */
|
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
/* Make sure that it is really being Scanned ! */
|
2003-11-04 00:59:24 +01:00
|
|
|
fb_assert(procedure->prc_flags & PRC_being_scanned);
|
2002-11-04 16:12:34 +01:00
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
procedure->prc_flags &= ~PRC_being_scanned;
|
|
|
|
|
|
|
|
#ifdef SUPERSERVER
|
|
|
|
THD_rec_mutex_unlock(&dbb->dbb_sp_rec_mutex);
|
|
|
|
#endif
|
2001-12-24 03:51:06 +01:00
|
|
|
|
|
|
|
} // try
|
2003-02-13 14:33:57 +01:00
|
|
|
catch (const std::exception&) {
|
2001-12-24 03:51:06 +01:00
|
|
|
procedure->prc_flags &= ~(PRC_being_scanned | PRC_scanned);
|
|
|
|
#ifdef SUPERSERVER
|
|
|
|
THD_rec_mutex_unlock(&dbb->dbb_sp_rec_mutex);
|
|
|
|
#endif
|
|
|
|
if (procedure->prc_existence_lock)
|
|
|
|
{
|
|
|
|
LCK_release(tdbb, procedure->prc_existence_lock);
|
2002-11-04 16:12:34 +01:00
|
|
|
procedure->prc_existence_lock = NULL;
|
2001-12-24 03:51:06 +01:00
|
|
|
}
|
2004-03-01 04:35:23 +01:00
|
|
|
throw;
|
2001-12-24 03:51:06 +01:00
|
|
|
}
|
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
return procedure;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-03-11 06:04:26 +01:00
|
|
|
jrd_rel* MET_relation(thread_db* tdbb, USHORT id)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* M E T _ r e l a t i o n
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Find or create a relation block for a given relation id.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
SET_TDBB(tdbb);
|
2004-03-07 08:58:55 +01:00
|
|
|
Database* dbb = tdbb->tdbb_database;
|
2001-05-23 15:26:42 +02:00
|
|
|
CHECK_DBB(dbb);
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
VEC vector = dbb->dbb_relations;
|
|
|
|
|
|
|
|
if (!vector)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2001-12-24 03:51:06 +01:00
|
|
|
vector = dbb->dbb_relations = vec::newVector(*dbb->dbb_permanent, id + 10);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2001-12-24 03:51:06 +01:00
|
|
|
else if (id >= vector->count())
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2001-12-24 03:51:06 +01:00
|
|
|
vector->resize(id + 10);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2004-01-03 11:59:52 +01:00
|
|
|
jrd_rel* relation = (jrd_rel*) (*vector)[id];
|
|
|
|
if (relation) {
|
2001-05-23 15:26:42 +02:00
|
|
|
return relation;
|
2004-01-03 11:59:52 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-12-31 06:36:12 +01:00
|
|
|
const USHORT major_version = dbb->dbb_ods_version;
|
|
|
|
const USHORT minor_original = dbb->dbb_minor_original;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2001-07-12 08:32:05 +02:00
|
|
|
/* From ODS 9 onwards, the first 128 relation IDS have been
|
2001-05-23 15:26:42 +02:00
|
|
|
reserved for system relations */
|
2003-12-31 06:36:12 +01:00
|
|
|
USHORT max_sys_rel;
|
2004-01-03 11:59:52 +01:00
|
|
|
if (ENCODE_ODS(major_version, minor_original) < ODS_9_0) {
|
2001-05-23 15:26:42 +02:00
|
|
|
max_sys_rel = (USHORT) USER_REL_INIT_ID_ODS8 - 1;
|
2004-01-03 11:59:52 +01:00
|
|
|
}
|
|
|
|
else {
|
2001-05-23 15:26:42 +02:00
|
|
|
max_sys_rel = (USHORT) USER_DEF_REL_INIT_ID - 1;
|
2004-01-03 11:59:52 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2002-11-21 00:18:16 +01:00
|
|
|
relation = FB_NEW(*dbb->dbb_permanent) jrd_rel();
|
2004-02-20 07:43:27 +01:00
|
|
|
(*vector)[id] = relation;
|
2001-05-23 15:26:42 +02:00
|
|
|
relation->rel_id = id;
|
|
|
|
|
2004-01-03 11:59:52 +01:00
|
|
|
// This should check system flag instead.
|
|
|
|
if (relation->rel_id <= max_sys_rel) {
|
2001-05-23 15:26:42 +02:00
|
|
|
return relation;
|
2004-01-03 11:59:52 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-03-18 06:56:06 +01:00
|
|
|
Lock* lock = FB_NEW_RPT(*dbb->dbb_permanent, 0) Lock;
|
2004-01-03 11:59:52 +01:00
|
|
|
relation->rel_existence_lock = lock;
|
2001-05-23 15:26:42 +02:00
|
|
|
lock->lck_parent = dbb->dbb_lock;
|
|
|
|
lock->lck_dbb = dbb;
|
|
|
|
lock->lck_key.lck_long = relation->rel_id;
|
|
|
|
lock->lck_length = sizeof(lock->lck_key.lck_long);
|
|
|
|
lock->lck_type = LCK_rel_exist;
|
|
|
|
lock->lck_owner_handle = LCK_get_owner_handle(tdbb, lock->lck_type);
|
2004-02-20 07:43:27 +01:00
|
|
|
lock->lck_object = relation;
|
2003-05-16 22:35:19 +02:00
|
|
|
lock->lck_ast = blocking_ast_relation;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
relation->rel_flags |= (REL_check_existence | REL_check_partners);
|
|
|
|
return relation;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-03-11 06:04:26 +01:00
|
|
|
bool MET_relation_owns_trigger (thread_db* tdbb, const TEXT* relation_name,
|
2004-02-20 07:43:27 +01:00
|
|
|
const TEXT* trigger_name)
|
2002-07-01 18:59:09 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* M E T _ r e l a t i o n _ o w n s _ t r i g g e r
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Checks that a given trigger is defined for a
|
|
|
|
* given relation, returning TRUE if there's a match.
|
|
|
|
* It's almost a subset of MET_load_trigger().
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
SET_TDBB (tdbb);
|
2004-03-07 08:58:55 +01:00
|
|
|
Database* dbb = tdbb->tdbb_database;
|
2002-07-01 18:59:09 +02:00
|
|
|
CHECK_DBB (dbb);
|
|
|
|
|
|
|
|
/* No need to load triggers for ReadOnly databases,
|
|
|
|
since INSERT/DELETE/UPDATE statements are not going to be allowed;
|
|
|
|
but we do not care of this flag here. We do not load, we only check. */
|
|
|
|
/*if (dbb->dbb_flags & DBB_read_only)
|
|
|
|
return;*/
|
|
|
|
|
|
|
|
/* Scan RDB$TRIGGERS next */
|
|
|
|
|
2004-02-20 07:43:27 +01:00
|
|
|
bool found = false;
|
2002-07-01 18:59:09 +02:00
|
|
|
/* CVC: Notice that we'll use the request irq_s_triggers2 that was found
|
|
|
|
to be unused at this time. */
|
|
|
|
|
2004-02-20 07:43:27 +01:00
|
|
|
blk* trigger_request = CMP_find_request (tdbb, irq_s_triggers2, IRQ_REQUESTS);
|
2002-07-01 18:59:09 +02:00
|
|
|
|
|
|
|
FOR (REQUEST_HANDLE trigger_request)
|
|
|
|
TRG IN RDB$TRIGGERS WITH TRG.RDB$RELATION_NAME = relation_name AND
|
|
|
|
TRG.RDB$TRIGGER_NAME EQ trigger_name
|
|
|
|
|
|
|
|
if (!REQUEST (irq_s_triggers2))
|
|
|
|
REQUEST (irq_s_triggers2) = trigger_request;
|
|
|
|
|
2004-02-20 07:43:27 +01:00
|
|
|
found = true;
|
2002-07-01 18:59:09 +02:00
|
|
|
|
|
|
|
/* Notice we do not care whether the trigger is valid or not. We assume
|
|
|
|
the caller wants to verify already validated entities.
|
|
|
|
if (TRG.RDB$TRIGGER_TYPE > 0 && TRG.RDB$TRIGGER_TYPE < TRIGGER_MAX)
|
|
|
|
*/
|
|
|
|
|
|
|
|
END_FOR;
|
|
|
|
|
|
|
|
if (!REQUEST (irq_s_triggers2))
|
|
|
|
REQUEST (irq_s_triggers2) = trigger_request;
|
|
|
|
|
|
|
|
return found;
|
|
|
|
}
|
|
|
|
|
2004-03-11 06:04:26 +01:00
|
|
|
bool MET_relation_default_class (thread_db* tdbb, const TEXT* relation_name,
|
2004-02-20 07:43:27 +01:00
|
|
|
const TEXT* default_security_class_name)
|
2002-07-01 18:59:09 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* M E T _ r e l a t i o n _ d e f a u l t _ c l a s s
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Checks that a given security class is the default for
|
|
|
|
* a given relation, returning TRUE if there's a match.
|
2003-12-22 11:00:59 +01:00
|
|
|
* It can be made obsolete in the future if jrd_rel struct
|
2002-07-01 18:59:09 +02:00
|
|
|
* gets another field, although metadata loading order
|
|
|
|
* would not be safe when compared with this function.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
SET_TDBB (tdbb);
|
2004-03-07 08:58:55 +01:00
|
|
|
Database* dbb = tdbb->tdbb_database;
|
2002-07-01 18:59:09 +02:00
|
|
|
CHECK_DBB (dbb);
|
|
|
|
|
2004-02-20 07:43:27 +01:00
|
|
|
bool found = false;
|
|
|
|
blk* request = CMP_find_request (tdbb, irq_l_relation_defsec, IRQ_REQUESTS);
|
2002-07-01 18:59:09 +02:00
|
|
|
|
|
|
|
FOR (REQUEST_HANDLE request)
|
|
|
|
REL IN RDB$RELATIONS WITH REL.RDB$RELATION_NAME EQ relation_name
|
|
|
|
|
|
|
|
if (!REQUEST (irq_l_relation_defsec))
|
|
|
|
REQUEST (irq_l_relation_defsec) = request;
|
|
|
|
|
|
|
|
if (!REL.RDB$DEFAULT_CLASS.NULL) {
|
2004-01-03 11:59:52 +01:00
|
|
|
const USHORT nl = name_length (REL.RDB$DEFAULT_CLASS),
|
2002-07-01 18:59:09 +02:00
|
|
|
nl2 = name_length (default_security_class_name);
|
2004-02-20 07:43:27 +01:00
|
|
|
if (nl == nl2 &&
|
|
|
|
!strncmp (REL.RDB$DEFAULT_CLASS, default_security_class_name, nl))
|
|
|
|
{
|
|
|
|
found = true;
|
2002-07-01 18:59:09 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
END_FOR;
|
|
|
|
|
|
|
|
if (!REQUEST (irq_l_relation_defsec))
|
|
|
|
REQUEST (irq_l_relation_defsec) = request;
|
|
|
|
|
|
|
|
return found;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-12-22 11:00:59 +01:00
|
|
|
void MET_release_existence( jrd_rel* relation)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* M E T _ r e l e a s e _ e x i s t e n c e
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Release interest in relation. If no remaining interest
|
|
|
|
* and we're blocking the drop of the relation then release
|
|
|
|
* existence lock and mark deleted.
|
|
|
|
*
|
|
|
|
**************************************/
|
2004-01-03 11:59:52 +01:00
|
|
|
if (relation->rel_use_count) {
|
|
|
|
relation->rel_use_count--;
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-01-03 11:59:52 +01:00
|
|
|
if (!relation->rel_use_count) {
|
|
|
|
if (relation->rel_flags & REL_blocking) {
|
2001-05-23 15:26:42 +02:00
|
|
|
LCK_re_post(relation->rel_existence_lock);
|
2004-01-03 11:59:52 +01:00
|
|
|
}
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-03-11 06:04:26 +01:00
|
|
|
void MET_remove_procedure( thread_db* tdbb, int id, jrd_prc* procedure)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* M E T _ r e m o v e _ p r o c e d u r e
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Remove a procedure from cache
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
SET_TDBB(tdbb);
|
2004-03-07 08:58:55 +01:00
|
|
|
Database* dbb = tdbb->tdbb_database;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-01-03 11:59:52 +01:00
|
|
|
vec* vector = dbb->dbb_procedures;
|
|
|
|
if (!vector) {
|
2002-09-28 22:58:40 +02:00
|
|
|
return;
|
2004-01-03 11:59:52 +01:00
|
|
|
}
|
2002-09-28 22:58:40 +02:00
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
if (!procedure) {
|
2004-02-20 07:43:27 +01:00
|
|
|
/** If we are in here then dfw.epp/modify_procedure() called us **/
|
2003-12-22 11:00:59 +01:00
|
|
|
if (!(procedure = (jrd_prc*) (*vector)[id]))
|
2001-05-23 15:26:42 +02:00
|
|
|
return;
|
|
|
|
}
|
2002-09-30 20:24:56 +02:00
|
|
|
|
|
|
|
/* MET_procedure locks it. Lets unlock it now to avoid troubles later */
|
|
|
|
if (procedure->prc_existence_lock)
|
|
|
|
{
|
|
|
|
LCK_release(tdbb, procedure->prc_existence_lock);
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* Procedure that is being altered may have references
|
|
|
|
to it by other procedures via pointer to current meta
|
2002-09-28 00:59:24 +02:00
|
|
|
data structure, so don't loose the structure or the pointer. */
|
2004-01-03 11:59:52 +01:00
|
|
|
if ((procedure == (jrd_prc*) (*vector)[id]) &&
|
|
|
|
!(procedure->prc_flags & PRC_being_altered))
|
|
|
|
{
|
2003-08-28 15:16:03 +02:00
|
|
|
(*vector)[id] = NULL;
|
2004-01-03 11:59:52 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* deallocate all structure which were allocated. The procedure
|
|
|
|
* blr is originally read into a new pool from which all request
|
|
|
|
* are allocated. That will not be freed up.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (procedure->prc_existence_lock)
|
2001-12-24 03:51:06 +01:00
|
|
|
delete procedure->prc_existence_lock;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (procedure->prc_name)
|
2001-12-24 03:51:06 +01:00
|
|
|
delete procedure->prc_name;
|
2001-05-23 15:26:42 +02:00
|
|
|
if (procedure->prc_security_name)
|
2001-12-24 03:51:06 +01:00
|
|
|
delete procedure->prc_security_name;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* deallocate input param structures */
|
2004-01-03 11:59:52 +01:00
|
|
|
SSHORT i;
|
2001-05-23 15:26:42 +02:00
|
|
|
if ((procedure->prc_inputs) && (vector = procedure->prc_input_fields)) {
|
|
|
|
for (i = 0; i < procedure->prc_inputs; i++)
|
|
|
|
{
|
2001-12-24 03:51:06 +01:00
|
|
|
if ((*vector)[i])
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2001-12-24 03:51:06 +01:00
|
|
|
delete (*vector)[i];
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
}
|
2001-12-24 03:51:06 +01:00
|
|
|
delete vector;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* deallocate output param structures */
|
|
|
|
|
|
|
|
if ((procedure->prc_outputs) && (vector = procedure->prc_output_fields)) {
|
|
|
|
for (i = 0; i < procedure->prc_outputs; i++)
|
|
|
|
{
|
2001-12-24 03:51:06 +01:00
|
|
|
if ((*vector)[i])
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2001-12-24 03:51:06 +01:00
|
|
|
delete (*vector)[i];
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
}
|
2001-12-24 03:51:06 +01:00
|
|
|
delete vector;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (procedure->prc_format)
|
2001-12-24 03:51:06 +01:00
|
|
|
delete procedure->prc_format;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-06-01 18:22:47 +02:00
|
|
|
if (!(procedure->prc_flags & PRC_being_altered) && !procedure->prc_use_count)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2001-12-24 03:51:06 +01:00
|
|
|
delete procedure;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2004-01-03 11:59:52 +01:00
|
|
|
const USHORT save_proc_flags = procedure->prc_flags;
|
|
|
|
const USHORT save_use_count = procedure->prc_use_count;
|
2002-11-16 19:48:01 +01:00
|
|
|
memset(((SCHAR *)&procedure->prc_id), 0,
|
2004-03-19 07:14:53 +01:00
|
|
|
sizeof(jrd_prc) - ((SCHAR *)&procedure->prc_id - (SCHAR *)procedure));
|
2001-05-23 15:26:42 +02:00
|
|
|
procedure->prc_flags = save_proc_flags;
|
2003-06-01 18:22:47 +02:00
|
|
|
procedure->prc_use_count = save_use_count;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void MET_revoke(
|
2004-03-11 06:04:26 +01:00
|
|
|
thread_db* tdbb,
|
2003-12-22 11:00:59 +01:00
|
|
|
jrd_tra* transaction,
|
2004-01-03 11:59:52 +01:00
|
|
|
const TEXT* relation,
|
|
|
|
const TEXT* revokee, const TEXT* privilege)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* M E T _ r e v o k e
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Execute a recursive revoke. This is called only when
|
|
|
|
* a revoked privilege had the grant option.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
SET_TDBB(tdbb);
|
2004-03-07 08:58:55 +01:00
|
|
|
Database* dbb = tdbb->tdbb_database;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* See if the revokee still has the privilege. If so, there's
|
|
|
|
nothing to do */
|
|
|
|
|
2004-01-03 11:59:52 +01:00
|
|
|
USHORT count = 0;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-02-20 07:43:27 +01:00
|
|
|
blk* request = CMP_find_request(tdbb, irq_revoke1, IRQ_REQUESTS);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction)
|
|
|
|
FIRST 1 P IN RDB$USER_PRIVILEGES WITH
|
|
|
|
P.RDB$RELATION_NAME EQ relation AND
|
|
|
|
P.RDB$PRIVILEGE EQ privilege AND
|
2001-07-12 08:32:05 +02:00
|
|
|
P.RDB$USER EQ revokee
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (!REQUEST(irq_revoke1))
|
|
|
|
REQUEST(irq_revoke1) = request;
|
|
|
|
++count;
|
|
|
|
END_FOR;
|
|
|
|
|
|
|
|
if (!REQUEST(irq_revoke1))
|
|
|
|
REQUEST(irq_revoke1) = request;
|
|
|
|
|
|
|
|
if (count)
|
|
|
|
return;
|
|
|
|
|
2004-02-20 07:43:27 +01:00
|
|
|
request = CMP_find_request(tdbb, irq_revoke2, IRQ_REQUESTS);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* User lost privilege. Take it away from anybody he/she gave
|
|
|
|
it to. */
|
|
|
|
|
|
|
|
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction)
|
|
|
|
P IN RDB$USER_PRIVILEGES WITH
|
|
|
|
P.RDB$RELATION_NAME EQ relation AND
|
|
|
|
P.RDB$PRIVILEGE EQ privilege AND
|
2001-07-12 08:32:05 +02:00
|
|
|
P.RDB$GRANTOR EQ revokee
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (!REQUEST(irq_revoke2))
|
|
|
|
REQUEST(irq_revoke2) = request;
|
|
|
|
ERASE P;
|
|
|
|
END_FOR;
|
|
|
|
|
|
|
|
if (!REQUEST(irq_revoke2))
|
|
|
|
REQUEST(irq_revoke2) = request;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-03-11 06:04:26 +01:00
|
|
|
TEXT* MET_save_name(thread_db* tdbb, const TEXT* name)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* M E T _ s a v e _ n a m e
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Immortalize a field or relation name in a permant string block.
|
|
|
|
* Oh, wow.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
SET_TDBB(tdbb);
|
|
|
|
|
2003-12-03 09:19:24 +01:00
|
|
|
str* string = save_name(tdbb, name);
|
2001-05-23 15:26:42 +02:00
|
|
|
return (TEXT*) string->str_data;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-03-11 06:04:26 +01:00
|
|
|
void MET_scan_relation( thread_db* tdbb, jrd_rel* relation)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* M E T _ s c a n _ r e l a t i o n
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Scan a relation for view rse, computed by expressions, missing
|
|
|
|
* expressions, and validation expressions.
|
|
|
|
*
|
|
|
|
**************************************/
|
2004-01-03 11:59:52 +01:00
|
|
|
USHORT length, view_context, field_id;
|
2004-03-19 07:14:53 +01:00
|
|
|
ArrayField* array;
|
2004-02-20 07:43:27 +01:00
|
|
|
trig_vec* triggers[TRIGGER_MAX];
|
2002-09-19 18:02:58 +02:00
|
|
|
VEC vector;
|
2004-01-03 11:59:52 +01:00
|
|
|
jrd_fld* field;
|
2001-05-23 15:26:42 +02:00
|
|
|
BLK request;
|
2004-02-20 07:43:27 +01:00
|
|
|
blb* blob;
|
2004-01-03 11:59:52 +01:00
|
|
|
UCHAR temp[256];
|
2001-05-23 15:26:42 +02:00
|
|
|
STR name, string;
|
|
|
|
|
|
|
|
SET_TDBB(tdbb);
|
2004-03-07 08:58:55 +01:00
|
|
|
Database* dbb = tdbb->tdbb_database;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
#ifdef SUPERSERVER
|
|
|
|
if (!(dbb->dbb_flags & DBB_sp_rec_mutex_init)) {
|
|
|
|
THD_rec_mutex_init(&dbb->dbb_sp_rec_mutex);
|
|
|
|
dbb->dbb_flags |= DBB_sp_rec_mutex_init;
|
|
|
|
}
|
|
|
|
THREAD_EXIT;
|
|
|
|
if (THD_rec_mutex_lock(&dbb->dbb_sp_rec_mutex)) {
|
|
|
|
THREAD_ENTER;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
THREAD_ENTER;
|
|
|
|
#endif /* SUPERSERVER */
|
|
|
|
|
|
|
|
if (relation->rel_flags & REL_scanned
|
|
|
|
|| relation->rel_flags & REL_deleted) {
|
|
|
|
#ifdef SUPERSERVER
|
|
|
|
THD_rec_mutex_unlock(&dbb->dbb_sp_rec_mutex);
|
|
|
|
#endif
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
relation->rel_flags |= REL_being_scanned;
|
2004-03-01 04:35:23 +01:00
|
|
|
bool dependencies =
|
2004-01-03 11:59:52 +01:00
|
|
|
(relation->rel_flags & REL_get_dependencies) ? true : false;
|
2004-03-01 04:35:23 +01:00
|
|
|
bool sys_triggers = (relation->rel_flags & REL_sys_triggers) ? true : false;
|
2001-05-23 15:26:42 +02:00
|
|
|
relation->rel_flags &= ~(REL_get_dependencies | REL_sys_triggers);
|
2004-01-03 11:59:52 +01:00
|
|
|
for (USHORT itr = 0; itr < TRIGGER_MAX; ++itr) {
|
|
|
|
triggers[itr] = NULL;
|
|
|
|
}
|
|
|
|
JrdMemoryPool* old_pool = tdbb->tdbb_default;
|
2001-05-23 15:26:42 +02:00
|
|
|
tdbb->tdbb_default = dbb->dbb_permanent;
|
|
|
|
|
|
|
|
/* If anything errors, catch it to reset the scan flag. This will
|
|
|
|
make sure that the error will be caught if the operation is tried
|
|
|
|
again. */
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
try {
|
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
/* Since this can be called recursively, find an inactive clone of the request */
|
|
|
|
|
2004-02-20 07:43:27 +01:00
|
|
|
request = CMP_find_request(tdbb, irq_r_fields, IRQ_REQUESTS);
|
2004-03-11 06:04:26 +01:00
|
|
|
Csb* csb = NULL;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
FOR(REQUEST_HANDLE request)
|
|
|
|
REL IN RDB$RELATIONS WITH REL.RDB$RELATION_ID EQ relation->rel_id
|
|
|
|
/* Pick up relation level stuff */
|
2001-12-24 03:51:06 +01:00
|
|
|
if (!REQUEST(irq_r_fields)) {
|
2001-05-23 15:26:42 +02:00
|
|
|
REQUEST(irq_r_fields) = request;
|
2001-12-24 03:51:06 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
relation->rel_current_fmt = REL.RDB$FORMAT;
|
2003-02-19 16:25:27 +01:00
|
|
|
vector = relation->rel_fields =
|
|
|
|
vec::newVector(*dbb->dbb_permanent, relation->rel_fields,
|
|
|
|
REL.RDB$FIELD_ID + 1);
|
2001-12-24 03:51:06 +01:00
|
|
|
if (!REL.RDB$SECURITY_CLASS.NULL) {
|
2001-05-23 15:26:42 +02:00
|
|
|
relation->rel_security_name =
|
|
|
|
MET_save_name(tdbb, REL.RDB$SECURITY_CLASS);
|
2001-12-24 03:51:06 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
if (!relation->rel_name) {
|
|
|
|
relation->rel_name = MET_save_name(tdbb, REL.RDB$RELATION_NAME);
|
|
|
|
relation->rel_length = strlen(relation->rel_name);
|
|
|
|
}
|
|
|
|
if (!relation->rel_owner_name)
|
|
|
|
relation->rel_owner_name =
|
|
|
|
MET_save_name(tdbb, REL.RDB$OWNER_NAME);
|
|
|
|
if (REL.RDB$FLAGS & REL_sql)
|
|
|
|
{
|
|
|
|
relation->rel_flags |= REL_sql_relation;
|
|
|
|
}
|
2004-01-21 08:18:30 +01:00
|
|
|
if (!REL.RDB$VIEW_BLR.isEmpty())
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/* parse the view blr, getting dependencies on relations, etc. at the same time */
|
|
|
|
|
|
|
|
if (dependencies)
|
|
|
|
{
|
|
|
|
relation->rel_view_rse =
|
2003-08-28 15:16:03 +02:00
|
|
|
(RSE) MET_get_dependencies(tdbb, relation, NULL, NULL,
|
2004-01-21 08:18:30 +01:00
|
|
|
&REL.RDB$VIEW_BLR, NULL,
|
2004-03-11 06:04:26 +01:00
|
|
|
&csb, REL.RDB$RELATION_NAME,
|
2001-05-23 15:26:42 +02:00
|
|
|
obj_view);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2002-04-01 02:03:52 +02:00
|
|
|
relation->rel_view_rse =
|
2003-08-28 15:16:03 +02:00
|
|
|
(RSE) MET_parse_blob(tdbb, relation,
|
2004-03-11 06:04:26 +01:00
|
|
|
&REL.RDB$VIEW_BLR, &csb,
|
2004-03-18 06:56:06 +01:00
|
|
|
NULL, false, false);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* retrieve the view context names */
|
|
|
|
|
|
|
|
lookup_view_contexts(tdbb, relation);
|
|
|
|
}
|
|
|
|
|
|
|
|
relation->rel_flags |= REL_scanned;
|
|
|
|
if (REL.RDB$EXTERNAL_FILE[0])
|
|
|
|
{
|
|
|
|
EXT_file(relation,
|
|
|
|
REL.RDB$EXTERNAL_FILE,
|
2004-02-24 06:34:44 +01:00
|
|
|
&REL.RDB$EXTERNAL_DESCRIPTION);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Pick up field specific stuff */
|
|
|
|
|
2004-01-03 11:59:52 +01:00
|
|
|
UCHAR* buffer;
|
2004-01-21 08:18:30 +01:00
|
|
|
blob = BLB_open(tdbb, dbb->dbb_sys_trans, &REL.RDB$RUNTIME);
|
2001-05-23 15:26:42 +02:00
|
|
|
if (blob->blb_max_segment < sizeof(temp))
|
|
|
|
{
|
|
|
|
buffer = temp;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2002-09-25 19:12:16 +02:00
|
|
|
string = FB_NEW_RPT(*tdbb->tdbb_default, blob->blb_max_segment) str();
|
2001-05-23 15:26:42 +02:00
|
|
|
buffer = string->str_data;
|
|
|
|
}
|
|
|
|
|
|
|
|
field = NULL;
|
|
|
|
for (;;)
|
|
|
|
{
|
|
|
|
length =
|
|
|
|
BLB_get_segment(tdbb, blob, buffer, blob->blb_max_segment);
|
|
|
|
if (blob->blb_flags & BLB_eof)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
2004-01-03 11:59:52 +01:00
|
|
|
USHORT n;
|
2001-05-23 15:26:42 +02:00
|
|
|
buffer[length] = 0;
|
2004-01-03 11:59:52 +01:00
|
|
|
UCHAR* p = (UCHAR*) &n;
|
|
|
|
const UCHAR* q = buffer + 1;
|
2001-05-23 15:26:42 +02:00
|
|
|
while (q < buffer + 1 + sizeof(SSHORT))
|
|
|
|
{
|
|
|
|
*p++ = *q++;
|
|
|
|
}
|
|
|
|
p = buffer + 1;
|
|
|
|
--length;
|
|
|
|
switch ((RSR_T) buffer[0]) {
|
|
|
|
case RSR_field_id:
|
|
|
|
if (field && !field->fld_security_name
|
2004-02-20 07:43:27 +01:00
|
|
|
&& !REL.RDB$DEFAULT_CLASS.NULL)
|
|
|
|
{
|
|
|
|
field->fld_security_name =
|
2001-05-23 15:26:42 +02:00
|
|
|
MET_save_name(tdbb, REL.RDB$DEFAULT_CLASS);
|
2004-02-20 07:43:27 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
field_id = n;
|
2004-01-03 11:59:52 +01:00
|
|
|
field = (jrd_fld*) (*vector)[field_id];
|
2001-05-23 15:26:42 +02:00
|
|
|
array = NULL;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case RSR_field_name:
|
|
|
|
if (field) {
|
|
|
|
/* The field exists. If its name hasn't changed, then
|
|
|
|
there's no need to copy anything. */
|
|
|
|
|
2001-07-12 08:32:05 +02:00
|
|
|
if (!strcmp((char*)p, (char*)field->fld_name))
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
2002-09-25 19:12:16 +02:00
|
|
|
name = FB_NEW_RPT(*dbb->dbb_permanent, length) str();
|
2001-05-23 15:26:42 +02:00
|
|
|
field->fld_name = (TEXT *) name->str_data;
|
|
|
|
}
|
|
|
|
else {
|
2002-12-02 11:29:02 +01:00
|
|
|
field = FB_NEW_RPT(*dbb->dbb_permanent, length) jrd_fld();
|
2004-02-20 07:43:27 +01:00
|
|
|
(*vector)[field_id] = field;
|
2001-05-23 15:26:42 +02:00
|
|
|
field->fld_name = (TEXT *) field->fld_string;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* TMN: This const_cast equivalent is safe since
|
|
|
|
* we just allocated the struct.
|
|
|
|
*/
|
2001-07-12 08:32:05 +02:00
|
|
|
strcpy((char*)field->fld_name, (char*)p);
|
2001-05-23 15:26:42 +02:00
|
|
|
field->fld_length = strlen(field->fld_name);
|
2002-07-01 18:59:09 +02:00
|
|
|
|
|
|
|
// CVC: Be paranoid and allow the possible trigger(s) to have a
|
|
|
|
// not null security class to work on, even if we only take it
|
|
|
|
// from the relation itself.
|
|
|
|
if (!field->fld_security_name && !REL.RDB$DEFAULT_CLASS.NULL) {
|
|
|
|
field->fld_security_name = MET_save_name (tdbb, REL.RDB$DEFAULT_CLASS);
|
|
|
|
}
|
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case RSR_view_context:
|
|
|
|
view_context = n;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case RSR_base_field:
|
|
|
|
field->fld_source =
|
2004-03-11 06:04:26 +01:00
|
|
|
PAR_make_field(tdbb, csb, view_context, (TEXT*)p);
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case RSR_computed_blr:
|
|
|
|
field->fld_computation = (dependencies) ?
|
2004-03-11 06:04:26 +01:00
|
|
|
MET_get_dependencies(tdbb, relation, (const TEXT*) p, csb,
|
2004-02-20 07:43:27 +01:00
|
|
|
NULL, NULL, NULL, field->fld_name,
|
2001-05-23 15:26:42 +02:00
|
|
|
obj_computed) :
|
2004-03-18 06:56:06 +01:00
|
|
|
PAR_blr(tdbb, relation, p, csb, NULL, NULL, false, 0);
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case RSR_missing_value:
|
|
|
|
field->fld_missing_value =
|
2004-03-18 06:56:06 +01:00
|
|
|
PAR_blr(tdbb, relation, p, csb, NULL, NULL, false, 0);
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case RSR_default_value:
|
|
|
|
field->fld_default_value =
|
2004-03-18 06:56:06 +01:00
|
|
|
PAR_blr(tdbb, relation, p, csb, NULL, NULL, false, 0);
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case RSR_validation_blr:
|
|
|
|
field->fld_validation =
|
2004-03-18 06:56:06 +01:00
|
|
|
PAR_blr(tdbb, relation, p, csb, NULL, NULL, false,
|
2001-05-23 15:26:42 +02:00
|
|
|
csb_validation);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case RSR_field_not_null:
|
|
|
|
field->fld_not_null =
|
2004-03-18 06:56:06 +01:00
|
|
|
PAR_blr(tdbb, relation, p, csb, NULL, NULL, false,
|
2001-05-23 15:26:42 +02:00
|
|
|
csb_validation);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case RSR_security_class:
|
2004-03-11 06:04:26 +01:00
|
|
|
field->fld_security_name = MET_save_name(tdbb, (const TEXT*) p);
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case RSR_trigger_name:
|
2004-03-11 06:04:26 +01:00
|
|
|
MET_load_trigger(tdbb, relation, (const TEXT*) p, triggers);
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case RSR_dimensions:
|
2004-03-19 07:14:53 +01:00
|
|
|
field->fld_array = array = FB_NEW_RPT(*dbb->dbb_permanent, n) ArrayField();
|
|
|
|
array->arr_desc.iad_dimensions = n;
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case RSR_array_desc:
|
|
|
|
if (array)
|
|
|
|
MOVE_FAST(p, &array->arr_desc, length);
|
|
|
|
break;
|
2004-03-11 06:04:26 +01:00
|
|
|
|
|
|
|
default: /* Shut up compiler warning */
|
|
|
|
break;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (field && !field->fld_security_name && !REL.RDB$DEFAULT_CLASS.NULL)
|
|
|
|
{
|
|
|
|
field->fld_security_name =
|
|
|
|
MET_save_name(tdbb, REL.RDB$DEFAULT_CLASS);
|
|
|
|
}
|
|
|
|
if (buffer != temp)
|
|
|
|
{
|
2001-12-24 03:51:06 +01:00
|
|
|
delete string;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
END_FOR;
|
|
|
|
|
2004-03-11 06:04:26 +01:00
|
|
|
if (csb)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2004-03-11 06:04:26 +01:00
|
|
|
delete csb;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2001-07-12 08:32:05 +02:00
|
|
|
/* release any triggers in case of a rescan, but not if the rescan
|
2001-05-23 15:26:42 +02:00
|
|
|
hapenned while system triggers were being loaded. */
|
|
|
|
|
|
|
|
if (!(relation->rel_flags & REL_sys_trigs_being_loaded)) {
|
2001-07-12 08:32:05 +02:00
|
|
|
/* if we are scanning a system relation during loading the system
|
2001-05-23 15:26:42 +02:00
|
|
|
triggers, (during parsing its blr actually), we must not release the
|
|
|
|
existing system triggers; because we have already set the
|
|
|
|
relation->rel_flag to not have REL_sys_trig, so these
|
|
|
|
system triggers will not get loaded again. This fixes bug 8149. */
|
|
|
|
|
|
|
|
/* We have just loaded the triggers onto the local vector triggers.
|
|
|
|
Its now time to place them at their rightful place ie the relation
|
2001-07-12 08:32:05 +02:00
|
|
|
block.
|
2001-05-23 15:26:42 +02:00
|
|
|
*/
|
2004-01-03 11:59:52 +01:00
|
|
|
trig_vec* tmp_vector;
|
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
tmp_vector = relation->rel_pre_store;
|
|
|
|
relation->rel_pre_store = triggers[TRIGGER_PRE_STORE];
|
|
|
|
MET_release_triggers(tdbb, &tmp_vector);
|
|
|
|
|
|
|
|
tmp_vector = relation->rel_post_store;
|
|
|
|
relation->rel_post_store = triggers[TRIGGER_POST_STORE];
|
|
|
|
MET_release_triggers(tdbb, &tmp_vector);
|
|
|
|
|
|
|
|
tmp_vector = relation->rel_pre_erase;
|
|
|
|
relation->rel_pre_erase = triggers[TRIGGER_PRE_ERASE];
|
|
|
|
MET_release_triggers(tdbb, &tmp_vector);
|
|
|
|
|
|
|
|
tmp_vector = relation->rel_post_erase;
|
|
|
|
relation->rel_post_erase = triggers[TRIGGER_POST_ERASE];
|
|
|
|
MET_release_triggers(tdbb, &tmp_vector);
|
|
|
|
|
|
|
|
tmp_vector = relation->rel_pre_modify;
|
|
|
|
relation->rel_pre_modify = triggers[TRIGGER_PRE_MODIFY];
|
|
|
|
MET_release_triggers(tdbb, &tmp_vector);
|
|
|
|
|
|
|
|
tmp_vector = relation->rel_post_modify;
|
|
|
|
relation->rel_post_modify = triggers[TRIGGER_POST_MODIFY];
|
|
|
|
MET_release_triggers(tdbb, &tmp_vector);
|
|
|
|
}
|
|
|
|
|
|
|
|
relation->rel_flags &= ~REL_being_scanned;
|
|
|
|
#ifdef SUPERSERVER
|
|
|
|
THD_rec_mutex_unlock(&dbb->dbb_sp_rec_mutex);
|
|
|
|
#endif
|
|
|
|
relation->rel_current_format = NULL;
|
|
|
|
tdbb->tdbb_default = old_pool;
|
2001-12-24 03:51:06 +01:00
|
|
|
|
|
|
|
} // try
|
2003-02-13 14:33:57 +01:00
|
|
|
catch (const std::exception&) {
|
2001-12-24 03:51:06 +01:00
|
|
|
relation->rel_flags &= ~(REL_being_scanned | REL_scanned);
|
|
|
|
if (dependencies) {
|
|
|
|
relation->rel_flags |= REL_get_dependencies;
|
|
|
|
}
|
|
|
|
if (sys_triggers) {
|
|
|
|
relation->rel_flags |= REL_sys_triggers;
|
|
|
|
}
|
|
|
|
#ifdef SUPERSERVER
|
|
|
|
THD_rec_mutex_unlock(&dbb->dbb_sp_rec_mutex);
|
|
|
|
#endif
|
|
|
|
tdbb->tdbb_default = old_pool;
|
2004-03-01 04:35:23 +01:00
|
|
|
throw;
|
2001-12-24 03:51:06 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-03-11 06:04:26 +01:00
|
|
|
const TEXT* MET_trigger_msg(thread_db* tdbb, const TEXT* name, USHORT number)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* M E T _ t r i g g e r _ m s g
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Look up trigger message using trigger and abort code.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
SET_TDBB(tdbb);
|
2004-03-07 08:58:55 +01:00
|
|
|
Database* dbb = tdbb->tdbb_database;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2002-10-29 17:27:47 +01:00
|
|
|
const TEXT* msg = 0;
|
2004-02-20 07:43:27 +01:00
|
|
|
BLK request = CMP_find_request(tdbb, irq_s_msgs, IRQ_REQUESTS);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
FOR(REQUEST_HANDLE request)
|
|
|
|
MSG IN RDB$TRIGGER_MESSAGES WITH
|
|
|
|
MSG.RDB$TRIGGER_NAME EQ name AND
|
2001-07-12 08:32:05 +02:00
|
|
|
MSG.RDB$MESSAGE_NUMBER EQ number
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (!REQUEST(irq_s_msgs))
|
|
|
|
REQUEST(irq_s_msgs) = request;
|
|
|
|
msg = ERR_cstring(MSG.RDB$MESSAGE);
|
|
|
|
END_FOR;
|
|
|
|
|
|
|
|
if (!REQUEST(irq_s_msgs))
|
|
|
|
REQUEST(irq_s_msgs) = request;
|
|
|
|
|
|
|
|
return msg;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-03-11 06:04:26 +01:00
|
|
|
void MET_update_shadow( thread_db* tdbb, Shadow* shadow, USHORT file_flags)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* M E T _ u p d a t e _ s h a d o w
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Update the stored file flags for the specified shadow.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
SET_TDBB(tdbb);
|
2004-03-07 08:58:55 +01:00
|
|
|
Database* dbb = tdbb->tdbb_database;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-01-03 11:59:52 +01:00
|
|
|
blk* handle = NULL;
|
2001-05-23 15:26:42 +02:00
|
|
|
FOR(REQUEST_HANDLE handle)
|
|
|
|
FIL IN RDB$FILES WITH FIL.RDB$SHADOW_NUMBER EQ shadow->sdw_number
|
|
|
|
MODIFY FIL USING
|
|
|
|
FIL.RDB$FILE_FLAGS = file_flags;
|
|
|
|
END_MODIFY;
|
|
|
|
END_FOR;
|
2004-01-03 11:59:52 +01:00
|
|
|
CMP_release(tdbb, (jrd_req*)handle);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-03-11 06:04:26 +01:00
|
|
|
void MET_update_transaction( thread_db* tdbb, jrd_tra* transaction, const bool do_commit)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* M E T _ u p d a t e _ t r a n s a c t i o n
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
2003-12-22 11:00:59 +01:00
|
|
|
* Update a record in RDB$TRANSACTIONS. If do_commit is true, this is a
|
2001-05-23 15:26:42 +02:00
|
|
|
* commit; otherwise it is a ROLLBACK.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
SET_TDBB(tdbb);
|
2004-03-07 08:58:55 +01:00
|
|
|
Database* dbb = tdbb->tdbb_database;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-02-20 07:43:27 +01:00
|
|
|
blk* request = CMP_find_request(tdbb, irq_m_trans, IRQ_REQUESTS);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
FOR(REQUEST_HANDLE request)
|
2001-07-12 08:32:05 +02:00
|
|
|
X IN RDB$TRANSACTIONS
|
|
|
|
WITH X.RDB$TRANSACTION_ID EQ transaction->tra_number
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (!REQUEST(irq_m_trans))
|
|
|
|
REQUEST(irq_m_trans) = request;
|
2003-12-22 11:00:59 +01:00
|
|
|
if (do_commit && (transaction->tra_flags & TRA_prepare2))
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
ERASE X
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
MODIFY X
|
2003-12-22 11:00:59 +01:00
|
|
|
X.RDB$TRANSACTION_STATE = (do_commit) ?
|
2001-05-23 15:26:42 +02:00
|
|
|
RDB$TRANSACTIONS.RDB$TRANSACTION_STATE.COMMITTED :
|
|
|
|
RDB$TRANSACTIONS.RDB$TRANSACTION_STATE.ROLLED_BACK;
|
|
|
|
END_MODIFY;
|
|
|
|
}
|
|
|
|
END_FOR;
|
|
|
|
|
|
|
|
if (!REQUEST(irq_m_trans))
|
|
|
|
REQUEST(irq_m_trans) = request;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-12-31 06:36:12 +01:00
|
|
|
static int blocking_ast_procedure(void* ast_object)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* b l o c k i n g _ a s t _ p r o c e d u r e
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Someone is trying to drop a proceedure. If there
|
|
|
|
* are outstanding interests in the existence of
|
|
|
|
* the relation then just mark as blocking and return.
|
|
|
|
* Otherwise, mark the procedure block as questionable
|
|
|
|
* and release the procedure existence lock.
|
|
|
|
*
|
|
|
|
**************************************/
|
2004-03-18 06:56:06 +01:00
|
|
|
jrd_prc* procedure = static_cast<jrd_prc*>(ast_object);
|
2004-03-11 06:04:26 +01:00
|
|
|
thread_db thd_context, *tdbb;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* Since this routine will be called asynchronously, we must establish
|
|
|
|
a thread context. */
|
|
|
|
|
|
|
|
SET_THREAD_DATA;
|
|
|
|
|
|
|
|
tdbb->tdbb_database = procedure->prc_existence_lock->lck_dbb;
|
|
|
|
tdbb->tdbb_attachment = procedure->prc_existence_lock->lck_attachment;
|
|
|
|
tdbb->tdbb_quantum = QUANTUM;
|
|
|
|
tdbb->tdbb_request = NULL;
|
|
|
|
tdbb->tdbb_transaction = NULL;
|
|
|
|
tdbb->tdbb_default = NULL;
|
|
|
|
|
2004-01-03 11:59:52 +01:00
|
|
|
if (procedure->prc_existence_lock) {
|
2001-05-23 15:26:42 +02:00
|
|
|
LCK_release(tdbb, procedure->prc_existence_lock);
|
2004-01-03 11:59:52 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
procedure->prc_flags |= PRC_obsolete;
|
|
|
|
|
|
|
|
/* Restore the prior thread context */
|
|
|
|
|
|
|
|
RESTORE_THREAD_DATA;
|
2003-05-19 08:57:08 +02:00
|
|
|
return 0;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-05-16 22:35:19 +02:00
|
|
|
static int blocking_ast_relation(void* ast_object)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* b l o c k i n g _ a s t _ r e l a t i o n
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Someone is trying to drop a relation. If there
|
|
|
|
* are outstanding interests in the existence of
|
|
|
|
* the relation then just mark as blocking and return.
|
|
|
|
* Otherwise, mark the relation block as questionable
|
|
|
|
* and release the relation existence lock.
|
|
|
|
*
|
|
|
|
**************************************/
|
2004-03-18 06:56:06 +01:00
|
|
|
jrd_rel* relation = static_cast<jrd_rel*>(ast_object);
|
2004-03-11 06:04:26 +01:00
|
|
|
thread_db thd_context, *tdbb;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* Since this routine will be called asynchronously, we must establish
|
|
|
|
a thread context. */
|
|
|
|
|
|
|
|
SET_THREAD_DATA;
|
|
|
|
|
|
|
|
tdbb->tdbb_database = relation->rel_existence_lock->lck_dbb;
|
|
|
|
tdbb->tdbb_attachment = relation->rel_existence_lock->lck_attachment;
|
|
|
|
tdbb->tdbb_quantum = QUANTUM;
|
|
|
|
tdbb->tdbb_request = NULL;
|
|
|
|
tdbb->tdbb_transaction = NULL;
|
|
|
|
tdbb->tdbb_default = NULL;
|
|
|
|
|
2004-01-03 11:59:52 +01:00
|
|
|
if (relation->rel_use_count) {
|
2001-05-23 15:26:42 +02:00
|
|
|
relation->rel_flags |= REL_blocking;
|
2004-01-03 11:59:52 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
else {
|
|
|
|
relation->rel_flags &= ~REL_blocking;
|
|
|
|
relation->rel_flags |= (REL_check_existence | REL_check_partners);
|
|
|
|
if (relation->rel_existence_lock)
|
|
|
|
LCK_release(tdbb, relation->rel_existence_lock);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Restore the prior thread context */
|
|
|
|
|
|
|
|
RESTORE_THREAD_DATA;
|
2003-05-16 22:35:19 +02:00
|
|
|
return 0;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void get_trigger(
|
2004-03-11 06:04:26 +01:00
|
|
|
thread_db* tdbb,
|
2003-12-22 11:00:59 +01:00
|
|
|
jrd_rel* relation,
|
2004-02-20 07:43:27 +01:00
|
|
|
bid* blob_id,
|
|
|
|
trig_vec** ptr,
|
2003-12-03 09:19:24 +01:00
|
|
|
const TEXT* name, bool sys_trigger, USHORT flags)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* g e t _ t r i g g e r
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Get trigger.
|
|
|
|
*
|
|
|
|
**************************************/
|
2002-09-19 18:02:58 +02:00
|
|
|
SET_TDBB(tdbb);
|
2004-01-03 11:59:52 +01:00
|
|
|
|
2004-01-21 08:18:30 +01:00
|
|
|
if (blob_id->isEmpty())
|
2001-05-23 15:26:42 +02:00
|
|
|
return;
|
|
|
|
|
2004-03-07 08:58:55 +01:00
|
|
|
Database* dbb = tdbb->tdbb_database;
|
2004-02-20 07:43:27 +01:00
|
|
|
blb* blob = BLB_open(tdbb, dbb->dbb_sys_trans, blob_id);
|
2002-09-19 18:02:58 +02:00
|
|
|
SLONG length = blob->blb_length + 10;
|
2002-09-26 20:13:02 +02:00
|
|
|
STR blr = FB_NEW_RPT(*dbb->dbb_permanent,length) str();
|
2002-09-19 18:02:58 +02:00
|
|
|
BLB_get_data(tdbb, blob, blr->str_data, length);
|
|
|
|
save_trigger_data(tdbb, ptr, relation, NULL, blr, name, sys_trigger, flags);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-03-11 06:04:26 +01:00
|
|
|
static bool get_type(thread_db* tdbb, SSHORT* id, const UCHAR* name, const TEXT* field)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* g e t _ t y p e
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Resoved a symbolic name in RDB$TYPES. Returned the value
|
|
|
|
* defined for the name in (*id). Don't touch (*id) if you
|
|
|
|
* don't find the name.
|
|
|
|
*
|
|
|
|
* Return (1) if found, (0) otherwise.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
UCHAR buffer[32]; /* BASED ON RDB$TYPE_NAME */
|
|
|
|
|
|
|
|
SET_TDBB(tdbb);
|
2004-03-07 08:58:55 +01:00
|
|
|
Database* dbb = tdbb->tdbb_database;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-11-04 00:59:24 +01:00
|
|
|
fb_assert(id != NULL);
|
|
|
|
fb_assert(name != NULL);
|
|
|
|
fb_assert(field != NULL);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* Force key to uppercase, following C locale rules for uppercase */
|
2003-12-11 11:33:30 +01:00
|
|
|
UCHAR* p;
|
2001-05-23 15:26:42 +02:00
|
|
|
for (p = buffer; *name && p < buffer + sizeof(buffer) - 1; p++, name++)
|
|
|
|
{
|
|
|
|
*p = UPPER7(*name);
|
|
|
|
}
|
|
|
|
*p = 0;
|
|
|
|
|
|
|
|
/* Try for exact name match */
|
|
|
|
|
2003-12-11 11:33:30 +01:00
|
|
|
bool found = false;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-12-11 11:33:30 +01:00
|
|
|
BLK handle = NULL;
|
2001-05-23 15:26:42 +02:00
|
|
|
FOR(REQUEST_HANDLE handle)
|
|
|
|
FIRST 1 T IN RDB$TYPES WITH
|
2002-12-22 14:08:50 +01:00
|
|
|
T.RDB$FIELD_NAME EQ field AND
|
|
|
|
T.RDB$TYPE_NAME EQ buffer
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-12-11 11:33:30 +01:00
|
|
|
found = true;
|
2001-05-23 15:26:42 +02:00
|
|
|
*id = T.RDB$TYPE;
|
|
|
|
END_FOR;
|
2004-01-03 11:59:52 +01:00
|
|
|
CMP_release(tdbb, (jrd_req*)handle);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
return found;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-03-11 06:04:26 +01:00
|
|
|
static void lookup_view_contexts( thread_db* tdbb, jrd_rel* view)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* l o o k u p _ v i e w _ c o n t e x t s
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
2001-07-12 08:32:05 +02:00
|
|
|
* Lookup view contexts and store in a linked
|
2001-05-23 15:26:42 +02:00
|
|
|
* list on the relation block.
|
2001-07-12 08:32:05 +02:00
|
|
|
*
|
2001-05-23 15:26:42 +02:00
|
|
|
**************************************/
|
|
|
|
SET_TDBB(tdbb);
|
2004-03-07 08:58:55 +01:00
|
|
|
Database* dbb = tdbb->tdbb_database;
|
2004-02-20 07:43:27 +01:00
|
|
|
blk* request = CMP_find_request(tdbb, irq_view_context, IRQ_REQUESTS);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-03-18 06:56:06 +01:00
|
|
|
ViewContext** vcx_ptr = &view->rel_view_contexts;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
FOR(REQUEST_HANDLE request)
|
|
|
|
V IN RDB$VIEW_RELATIONS WITH
|
|
|
|
V.RDB$VIEW_NAME EQ view->rel_name
|
2001-07-12 08:32:05 +02:00
|
|
|
SORTED BY V.RDB$VIEW_CONTEXT
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (!REQUEST(irq_view_context))
|
|
|
|
REQUEST(irq_view_context) = request;
|
|
|
|
|
|
|
|
/* allocate a view context block and link it in
|
|
|
|
to the relation block's linked list */
|
|
|
|
|
2004-03-18 06:56:06 +01:00
|
|
|
ViewContext* view_context = FB_NEW(*tdbb->tdbb_default) ViewContext();
|
2001-05-23 15:26:42 +02:00
|
|
|
*vcx_ptr = view_context;
|
|
|
|
vcx_ptr = &view_context->vcx_next;
|
|
|
|
|
|
|
|
view_context->vcx_context = V.RDB$VIEW_CONTEXT;
|
|
|
|
|
|
|
|
/* allocate a string block for the context name */
|
|
|
|
|
2004-01-03 11:59:52 +01:00
|
|
|
SSHORT length = name_length(V.RDB$CONTEXT_NAME);
|
|
|
|
str* alias = FB_NEW_RPT(*tdbb->tdbb_default, length + 1) str();
|
2001-05-23 15:26:42 +02:00
|
|
|
V.RDB$CONTEXT_NAME[length] = 0;
|
2001-07-12 08:32:05 +02:00
|
|
|
strcpy((char*)alias->str_data, V.RDB$CONTEXT_NAME);
|
2001-05-23 15:26:42 +02:00
|
|
|
alias->str_length = length;
|
|
|
|
|
|
|
|
view_context->vcx_context_name = alias;
|
|
|
|
|
|
|
|
/* allocate a string block for the relation name */
|
|
|
|
|
|
|
|
length = name_length(V.RDB$RELATION_NAME);
|
2002-09-25 19:12:16 +02:00
|
|
|
alias = FB_NEW_RPT(*tdbb->tdbb_default, length + 1) str();
|
2001-05-23 15:26:42 +02:00
|
|
|
V.RDB$RELATION_NAME[length] = 0;
|
2001-07-12 08:32:05 +02:00
|
|
|
strcpy((char*)alias->str_data, V.RDB$RELATION_NAME);
|
2001-05-23 15:26:42 +02:00
|
|
|
alias->str_length = length;
|
|
|
|
|
|
|
|
view_context->vcx_relation_name = alias;
|
|
|
|
|
|
|
|
END_FOR;
|
|
|
|
|
|
|
|
if (!REQUEST(irq_view_context))
|
|
|
|
REQUEST(irq_view_context) = request;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-12-11 11:33:30 +01:00
|
|
|
static void name_copy(TEXT* to, const TEXT* from)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* n a m e _ c o p y
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Copy a system name, stripping trailing blanks.
|
|
|
|
*
|
|
|
|
**************************************/
|
2003-12-11 11:33:30 +01:00
|
|
|
const USHORT length = name_length(from);
|
2001-05-23 15:26:42 +02:00
|
|
|
memcpy(to, from, length);
|
|
|
|
to[length] = '\0';
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-02-13 11:11:35 +01:00
|
|
|
static USHORT name_length(const TEXT* name)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* n a m e _ l e n g t h
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Compute effective length of system relation name.
|
|
|
|
* SQL delimited identifier may contain blanks.
|
|
|
|
*
|
|
|
|
**************************************/
|
2003-12-11 11:33:30 +01:00
|
|
|
const TEXT* q = name - 1;
|
|
|
|
for (const TEXT* p = name; *p; p++)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
if (*p != BLANK)
|
|
|
|
{
|
|
|
|
q = p;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return (q + 1) - name;
|
|
|
|
}
|
|
|
|
|
2004-03-11 06:04:26 +01:00
|
|
|
static jrd_nod* parse_param_blr(thread_db* tdbb,
|
2004-02-20 07:43:27 +01:00
|
|
|
jrd_prc* procedure, bid* blob_id, Csb* csb)
|
2004-01-16 13:59:16 +01:00
|
|
|
{
|
|
|
|
SET_TDBB(tdbb);
|
2004-03-07 08:58:55 +01:00
|
|
|
Database* dbb = tdbb->tdbb_database;
|
2004-01-16 13:59:16 +01:00
|
|
|
|
2004-02-20 07:43:27 +01:00
|
|
|
blb* blob = BLB_open(tdbb, dbb->dbb_sys_trans, blob_id);
|
2004-01-16 13:59:16 +01:00
|
|
|
SLONG length = blob->blb_length + 10;
|
|
|
|
STR temp = FB_NEW_RPT(*tdbb->tdbb_default, length) str();
|
|
|
|
|
|
|
|
BLB_get_data(tdbb, blob, temp->str_data, length);
|
|
|
|
csb->csb_blr = temp->str_data;
|
|
|
|
|
|
|
|
jrd_nod* node = PAR_blr(tdbb, NULL, temp->str_data, NULL, &csb,
|
|
|
|
&procedure->prc_request, false, 0);
|
|
|
|
delete temp;
|
|
|
|
|
|
|
|
return node;
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-12-11 11:33:30 +01:00
|
|
|
static jrd_nod* parse_procedure_blr(
|
2004-03-11 06:04:26 +01:00
|
|
|
thread_db* tdbb,
|
2004-02-20 07:43:27 +01:00
|
|
|
jrd_prc* procedure, bid* blob_id, Csb* csb)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* p a r s e _ p r o c e d u r e _ b l r
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Parse blr, returning a compiler scratch block with the results.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
SET_TDBB(tdbb);
|
2004-03-07 08:58:55 +01:00
|
|
|
Database* dbb = tdbb->tdbb_database;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-01-21 08:18:30 +01:00
|
|
|
blb* blob = BLB_open(tdbb, dbb->dbb_sys_trans, blob_id);
|
2003-12-11 11:33:30 +01:00
|
|
|
const SLONG length = blob->blb_length + 10;
|
|
|
|
// CVC: Warning: the str class is limited by 64K
|
|
|
|
str* temp = FB_NEW_RPT(*tdbb->tdbb_default, length) str();
|
2001-05-23 15:26:42 +02:00
|
|
|
BLB_get_data(tdbb, blob, temp->str_data, length);
|
2003-09-28 23:36:05 +02:00
|
|
|
csb->csb_blr = temp->str_data;
|
2004-02-20 07:43:27 +01:00
|
|
|
// CVC: Why don't we check this function's return value!
|
|
|
|
// Trashed memory may be a cause of failure here
|
|
|
|
if (!par_messages(tdbb, temp->str_data, (USHORT) length, procedure, csb))
|
|
|
|
{
|
|
|
|
delete temp;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2003-12-11 11:33:30 +01:00
|
|
|
jrd_nod* node =
|
2003-09-28 23:36:05 +02:00
|
|
|
PAR_blr(tdbb, NULL, temp->str_data, NULL, &csb,
|
2004-03-18 06:56:06 +01:00
|
|
|
&procedure->prc_request, false, 0);
|
2001-12-24 03:51:06 +01:00
|
|
|
delete temp;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
return node;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-03-11 06:04:26 +01:00
|
|
|
static bool par_messages(thread_db* tdbb,
|
2003-12-11 11:33:30 +01:00
|
|
|
const UCHAR* blr,
|
2001-05-23 15:26:42 +02:00
|
|
|
USHORT blr_length,
|
2003-12-11 11:33:30 +01:00
|
|
|
jrd_prc* procedure,
|
2004-01-13 10:52:19 +01:00
|
|
|
Csb* csb)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* p a r _ m e s s a g e s
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Parse the messages of a blr request. For specified message, allocate
|
|
|
|
* a format (fmt) block.
|
|
|
|
*
|
|
|
|
**************************************/
|
2003-09-28 23:36:05 +02:00
|
|
|
csb->csb_running = blr;
|
2003-12-11 11:33:30 +01:00
|
|
|
const SSHORT version = BLR_BYTE;
|
2004-01-03 11:59:52 +01:00
|
|
|
if (version != blr_version4 && version != blr_version5) {
|
2004-02-20 07:43:27 +01:00
|
|
|
return false;
|
2004-01-03 11:59:52 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-01-03 11:59:52 +01:00
|
|
|
if (BLR_BYTE != blr_begin) {
|
2004-02-20 07:43:27 +01:00
|
|
|
return false;
|
2004-01-03 11:59:52 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
SET_TDBB(tdbb);
|
|
|
|
|
|
|
|
while (BLR_BYTE == blr_message) {
|
2003-12-11 11:33:30 +01:00
|
|
|
const USHORT msg_number = BLR_BYTE;
|
|
|
|
USHORT count = BLR_BYTE;
|
2001-05-23 15:26:42 +02:00
|
|
|
count += (BLR_BYTE) << 8;
|
2003-12-11 11:33:30 +01:00
|
|
|
fmt* format = fmt::newFmt(*tdbb->tdbb_default, count);
|
2001-05-23 15:26:42 +02:00
|
|
|
format->fmt_count = count;
|
2003-12-11 11:33:30 +01:00
|
|
|
// CVC: This offset should be protected against 32K overflow in the future
|
|
|
|
USHORT offset = 0;
|
|
|
|
for (fmt::fmt_desc_iterator desc = format->fmt_desc.begin(); count;
|
|
|
|
--count, ++desc)
|
|
|
|
{
|
|
|
|
const USHORT align = PAR_desc(csb, &*desc);
|
2004-01-03 11:59:52 +01:00
|
|
|
if (align) {
|
2001-05-23 15:26:42 +02:00
|
|
|
offset = FB_ALIGN(offset, align);
|
2004-01-03 11:59:52 +01:00
|
|
|
}
|
2004-01-21 08:18:30 +01:00
|
|
|
desc->dsc_address = (UCHAR *) (IPTR) offset;
|
2001-05-23 15:26:42 +02:00
|
|
|
offset += desc->dsc_length;
|
|
|
|
}
|
|
|
|
format->fmt_length = offset;
|
|
|
|
if (msg_number == 0)
|
|
|
|
{
|
|
|
|
procedure->prc_input_fmt = format;
|
|
|
|
}
|
|
|
|
else if (msg_number == 1)
|
|
|
|
{
|
|
|
|
procedure->prc_output_fmt = format;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2001-12-24 03:51:06 +01:00
|
|
|
delete format;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-02-20 07:43:27 +01:00
|
|
|
return true;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-03-11 06:04:26 +01:00
|
|
|
void MET_release_triggers( thread_db* tdbb, trig_vec** vector_ptr)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/***********************************************
|
|
|
|
*
|
|
|
|
* M E T _ r e l e a s e _ t r i g g e r s
|
|
|
|
*
|
|
|
|
***********************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Release a possibly null vector of triggers.
|
|
|
|
* If triggers are still active let someone
|
|
|
|
* else do the work.
|
|
|
|
*
|
|
|
|
**************************************/
|
2003-12-22 11:00:59 +01:00
|
|
|
trig_vec* vector = *vector_ptr;
|
2004-01-03 11:59:52 +01:00
|
|
|
if (!vector) {
|
2001-05-23 15:26:42 +02:00
|
|
|
return;
|
2004-01-03 11:59:52 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
SET_TDBB(tdbb);
|
|
|
|
|
|
|
|
*vector_ptr = NULL;
|
|
|
|
|
2003-12-22 11:00:59 +01:00
|
|
|
trig_vec::iterator ptr, end;
|
2001-12-24 03:51:06 +01:00
|
|
|
for (ptr = vector->begin(), end = vector->end(); ptr < end; ptr++)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2003-12-22 11:00:59 +01:00
|
|
|
if (ptr->request && CMP_clone_is_active(ptr->request))
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
for (ptr = vector->begin(), end = vector->end(); ptr < end; ptr++)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2004-01-03 11:59:52 +01:00
|
|
|
if (ptr->request) {
|
2002-09-19 18:02:58 +02:00
|
|
|
CMP_release(tdbb, ptr->request);
|
2004-01-03 11:59:52 +01:00
|
|
|
}
|
2003-12-22 11:00:59 +01:00
|
|
|
else {
|
2004-01-03 11:59:52 +01:00
|
|
|
if (ptr->name) {
|
|
|
|
delete ptr->name;
|
|
|
|
}
|
2003-12-22 11:00:59 +01:00
|
|
|
}
|
2004-01-03 11:59:52 +01:00
|
|
|
if (ptr->blr) {
|
2002-09-19 18:02:58 +02:00
|
|
|
delete ptr->blr;
|
2004-01-03 11:59:52 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
delete vector;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-03-11 06:04:26 +01:00
|
|
|
static bool resolve_charset_and_collation(
|
|
|
|
thread_db* tdbb,
|
2003-12-11 11:33:30 +01:00
|
|
|
SSHORT* id,
|
|
|
|
const UCHAR* charset,
|
|
|
|
const UCHAR* collation)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* r e s o l v e _ c h a r s e t _ a n d _ c o l l a t i o n
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Given ASCII7 name of charset & collation
|
|
|
|
* resolve the specification to a Character set id.
|
|
|
|
* This character set id is also the id of the text_object
|
|
|
|
* that implements the C locale for the Character set.
|
|
|
|
*
|
|
|
|
* Inputs:
|
|
|
|
* (charset)
|
|
|
|
* ASCII7z name of character set.
|
|
|
|
* NULL (implying unspecified) means use the character set
|
|
|
|
* for defined for (collation).
|
|
|
|
*
|
|
|
|
* (collation)
|
|
|
|
* ASCII7z name of collation.
|
|
|
|
* NULL means use the default collation for (charset).
|
|
|
|
*
|
|
|
|
* Outputs:
|
2001-07-12 08:32:05 +02:00
|
|
|
* (*id)
|
2001-05-23 15:26:42 +02:00
|
|
|
* Set to character set specified by this name.
|
|
|
|
*
|
|
|
|
* Return:
|
|
|
|
* 1 if no errors (and *id is set).
|
|
|
|
* 0 if either name not found.
|
|
|
|
* or if names found, but the collation isn't for the specified
|
|
|
|
* character set.
|
|
|
|
*
|
|
|
|
**************************************/
|
2004-03-11 06:04:26 +01:00
|
|
|
bool found = false;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
SET_TDBB(tdbb);
|
2004-03-07 08:58:55 +01:00
|
|
|
Database* dbb = tdbb->tdbb_database;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-11-04 00:59:24 +01:00
|
|
|
fb_assert(id != NULL);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-01-03 11:59:52 +01:00
|
|
|
blk* handle = NULL;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (collation == NULL)
|
|
|
|
{
|
|
|
|
if (charset == NULL)
|
2003-12-11 11:33:30 +01:00
|
|
|
charset = (const UCHAR*) DEFAULT_CHARACTER_SET_NAME;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-01-03 11:59:52 +01:00
|
|
|
SSHORT charset_id = 0;
|
2003-12-11 11:33:30 +01:00
|
|
|
if (get_type(tdbb, &charset_id, charset, "RDB$CHARACTER_SET_NAME"))
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
*id = charset_id;
|
2004-03-11 06:04:26 +01:00
|
|
|
return true;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Charset name not found in the alias table - before giving up
|
|
|
|
try the character_set table */
|
|
|
|
|
|
|
|
FOR(REQUEST_HANDLE handle)
|
|
|
|
FIRST 1 CS IN RDB$CHARACTER_SETS
|
2002-12-22 14:08:50 +01:00
|
|
|
WITH CS.RDB$CHARACTER_SET_NAME EQ charset
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-03-11 06:04:26 +01:00
|
|
|
found = true;
|
2001-05-23 15:26:42 +02:00
|
|
|
*id = CS.RDB$CHARACTER_SET_ID;
|
|
|
|
|
|
|
|
END_FOR;
|
2004-01-03 11:59:52 +01:00
|
|
|
CMP_release(tdbb, (jrd_req*)handle);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
return found;
|
|
|
|
}
|
|
|
|
else if (charset == NULL)
|
|
|
|
{
|
|
|
|
FOR(REQUEST_HANDLE handle)
|
|
|
|
FIRST 1 COL IN RDB$COLLATIONS
|
2002-12-22 14:08:50 +01:00
|
|
|
WITH COL.RDB$COLLATION_NAME EQ collation
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-03-11 06:04:26 +01:00
|
|
|
found = true;
|
2001-05-23 15:26:42 +02:00
|
|
|
*id = COL.RDB$CHARACTER_SET_ID;
|
|
|
|
|
|
|
|
END_FOR;
|
2004-01-03 11:59:52 +01:00
|
|
|
CMP_release(tdbb, (jrd_req*)handle);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
return found;
|
|
|
|
}
|
|
|
|
|
|
|
|
FOR(REQUEST_HANDLE handle)
|
|
|
|
FIRST 1 CS IN RDB$CHARACTER_SETS CROSS
|
|
|
|
COL IN RDB$COLLATIONS OVER RDB$CHARACTER_SET_ID CROSS
|
|
|
|
AL1 IN RDB$TYPES
|
|
|
|
WITH AL1.RDB$FIELD_NAME EQ "RDB$CHARACTER_SET_NAME"
|
2002-12-22 14:08:50 +01:00
|
|
|
AND AL1.RDB$TYPE_NAME EQ charset
|
|
|
|
AND COL.RDB$COLLATION_NAME EQ collation
|
2001-07-12 08:32:05 +02:00
|
|
|
AND AL1.RDB$TYPE EQ CS.RDB$CHARACTER_SET_ID
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-03-11 06:04:26 +01:00
|
|
|
found = true;
|
2001-05-23 15:26:42 +02:00
|
|
|
*id = CS.RDB$CHARACTER_SET_ID;
|
|
|
|
|
|
|
|
END_FOR;
|
2004-01-03 11:59:52 +01:00
|
|
|
CMP_release(tdbb, (jrd_req*)handle);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
return found;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-03-11 06:04:26 +01:00
|
|
|
static str* save_name(thread_db* tdbb, const TEXT* name)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* s a v e _ n a m e
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* save a name in a string.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
SET_TDBB(tdbb);
|
2004-03-07 08:58:55 +01:00
|
|
|
Database* dbb = tdbb->tdbb_database;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-12-03 09:19:24 +01:00
|
|
|
USHORT l = name_length(name);
|
|
|
|
str* string = FB_NEW_RPT(*dbb->dbb_permanent, l) str();
|
2001-05-23 15:26:42 +02:00
|
|
|
string->str_length = l;
|
2003-12-03 09:19:24 +01:00
|
|
|
TEXT* p = (TEXT *) string->str_data;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (l)
|
|
|
|
{
|
|
|
|
do {
|
|
|
|
*p++ = *name++;
|
|
|
|
} while (--l);
|
|
|
|
}
|
|
|
|
|
|
|
|
return string;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-03-11 06:04:26 +01:00
|
|
|
static void save_trigger_data(thread_db* tdbb, trig_vec** ptr, jrd_rel* relation,
|
2004-01-03 11:59:52 +01:00
|
|
|
jrd_req* request, STR blr,
|
2003-12-03 09:19:24 +01:00
|
|
|
const TEXT* name, bool sys_trigger, USHORT flags)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
2002-09-19 18:02:58 +02:00
|
|
|
* s a v e _ t r i g g e r _ d a t a
|
2001-05-23 15:26:42 +02:00
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
2002-09-19 18:02:58 +02:00
|
|
|
* Save trigger data to passed vector
|
2001-05-23 15:26:42 +02:00
|
|
|
*
|
|
|
|
**************************************/
|
2004-03-11 06:04:26 +01:00
|
|
|
const USHORT n = (*ptr) ? (*ptr)->size() : 0;
|
2004-02-20 07:43:27 +01:00
|
|
|
trig_vec* vector = *ptr;
|
2001-12-24 03:51:06 +01:00
|
|
|
|
|
|
|
if (!vector) {
|
2002-09-25 19:12:16 +02:00
|
|
|
vector = FB_NEW(*tdbb->tdbb_database->dbb_permanent)
|
2003-12-03 09:19:24 +01:00
|
|
|
trig_vec(n + 1, *tdbb->tdbb_database->dbb_permanent);
|
2001-12-24 03:51:06 +01:00
|
|
|
*ptr = vector;
|
2004-01-03 11:59:52 +01:00
|
|
|
}
|
|
|
|
else {
|
2001-12-24 03:51:06 +01:00
|
|
|
vector->resize(n + 1);
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2002-09-19 18:02:58 +02:00
|
|
|
trig& t = (*vector)[n];
|
|
|
|
t.blr = blr;
|
2003-12-03 09:19:24 +01:00
|
|
|
if (name) {
|
2002-09-19 18:02:58 +02:00
|
|
|
t.name = save_name(tdbb, name);
|
2003-12-03 09:19:24 +01:00
|
|
|
}
|
|
|
|
else {
|
2002-09-19 18:02:58 +02:00
|
|
|
t.name = NULL;
|
2003-12-03 09:19:24 +01:00
|
|
|
}
|
2002-09-19 18:02:58 +02:00
|
|
|
t.flags = flags;
|
2004-01-03 11:59:52 +01:00
|
|
|
t.compile_in_progress = false;
|
2004-02-20 07:43:27 +01:00
|
|
|
t.sys_trigger = sys_trigger;
|
2002-09-19 18:02:58 +02:00
|
|
|
t.request = request;
|
|
|
|
t.relation = relation;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-03-11 06:04:26 +01:00
|
|
|
static void store_dependencies(thread_db* tdbb,
|
2004-01-13 10:52:19 +01:00
|
|
|
Csb* csb,
|
2003-02-13 11:11:35 +01:00
|
|
|
const TEXT* object_name,
|
2001-05-23 15:26:42 +02:00
|
|
|
USHORT dependency_type)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* s t o r e _ d e p e n d e n c i e s
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Store records in RDB$DEPENDENCIES
|
2001-07-12 08:32:05 +02:00
|
|
|
* corresponding to the objects found during
|
2001-05-23 15:26:42 +02:00
|
|
|
* compilation of blr for a trigger, view, etc.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
TEXT name[32];
|
|
|
|
|
|
|
|
SET_TDBB(tdbb);
|
2004-03-07 08:58:55 +01:00
|
|
|
Database* dbb = tdbb->tdbb_database;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
while (csb->csb_dependencies)
|
|
|
|
{
|
2004-01-13 10:52:19 +01:00
|
|
|
jrd_nod* node = (jrd_nod*) LLS_POP(&csb->csb_dependencies);
|
2001-05-23 15:26:42 +02:00
|
|
|
if (!node->nod_arg[e_dep_object])
|
|
|
|
continue;
|
2004-01-21 08:18:30 +01:00
|
|
|
const SSHORT dpdo_type = (SSHORT) (IPTR) node->nod_arg[e_dep_object_type];
|
2004-01-03 11:59:52 +01:00
|
|
|
jrd_rel* relation = NULL;
|
|
|
|
jrd_prc* procedure = NULL;
|
|
|
|
const TEXT* dpdo_name;
|
2002-07-01 18:59:09 +02:00
|
|
|
switch (dpdo_type) {
|
|
|
|
case obj_relation:
|
2003-12-22 11:00:59 +01:00
|
|
|
relation = (jrd_rel*) node->nod_arg[e_dep_object];
|
2001-05-23 15:26:42 +02:00
|
|
|
dpdo_name = relation->rel_name;
|
2002-07-01 18:59:09 +02:00
|
|
|
break;
|
|
|
|
case obj_procedure:
|
2003-12-22 11:00:59 +01:00
|
|
|
procedure = (jrd_prc*) node->nod_arg [e_dep_object];
|
2002-07-05 17:00:26 +02:00
|
|
|
dpdo_name = (TEXT*) procedure->prc_name->str_data;
|
2002-07-01 18:59:09 +02:00
|
|
|
break;
|
|
|
|
case obj_exception:
|
2004-01-03 11:59:52 +01:00
|
|
|
{
|
2004-01-21 08:18:30 +01:00
|
|
|
const SLONG number = (IPTR) node->nod_arg [e_dep_object];
|
2004-01-03 11:59:52 +01:00
|
|
|
MET_lookup_exception (tdbb, number, name, NULL);
|
|
|
|
dpdo_name = name;
|
|
|
|
break;
|
|
|
|
}
|
2002-07-01 18:59:09 +02:00
|
|
|
/* CVC: Here I'm going to track those pesky things named generators and UDFs. */
|
2004-01-03 11:59:52 +01:00
|
|
|
case obj_generator:
|
|
|
|
{
|
2004-01-21 08:18:30 +01:00
|
|
|
const SLONG number = (IPTR) node->nod_arg [e_dep_object];
|
2004-01-03 11:59:52 +01:00
|
|
|
MET_lookup_generator_id (tdbb, number, name);
|
|
|
|
dpdo_name = name;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case obj_udf:
|
|
|
|
{
|
|
|
|
fun* udf = (FUN) node->nod_arg [e_dep_object];
|
2002-07-01 18:59:09 +02:00
|
|
|
dpdo_name = udf->fun_symbol->sym_string;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2004-01-03 11:59:52 +01:00
|
|
|
jrd_nod* field_node = node->nod_arg[e_dep_field];
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-01-03 11:59:52 +01:00
|
|
|
const TEXT* field_name = NULL;
|
2001-05-23 15:26:42 +02:00
|
|
|
if (field_node)
|
|
|
|
{
|
|
|
|
if (field_node->nod_type == nod_field)
|
|
|
|
{
|
2004-01-21 08:18:30 +01:00
|
|
|
const SSHORT fld_id = (SSHORT) (IPTR) field_node->nod_arg[0];
|
2001-05-23 15:26:42 +02:00
|
|
|
if (relation)
|
|
|
|
{
|
2004-01-03 11:59:52 +01:00
|
|
|
const jrd_fld* field = MET_get_field(relation, fld_id);
|
|
|
|
if (field)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
field_name = field->fld_name;
|
|
|
|
}
|
2004-02-20 07:43:27 +01:00
|
|
|
}
|
|
|
|
else if (procedure)
|
|
|
|
{
|
|
|
|
const jrd_fld* field =
|
|
|
|
(jrd_fld*) (*procedure->prc_output_fields)[fld_id];
|
|
|
|
// CVC: Setting the field var here didn't make sense alone,
|
|
|
|
// so I thought the missing code was to try to extract
|
|
|
|
// the field name that's in this case an output var from a proc.
|
|
|
|
if (field)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2004-02-20 07:43:27 +01:00
|
|
|
field_name = field->fld_name;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
field_name = (TEXT *) field_node->nod_arg[0];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (field_name)
|
|
|
|
{
|
2004-01-03 11:59:52 +01:00
|
|
|
blk* request =
|
2004-02-20 07:43:27 +01:00
|
|
|
CMP_find_request(tdbb, irq_c_deps_f, IRQ_REQUESTS);
|
2004-01-03 11:59:52 +01:00
|
|
|
bool found = false;
|
2001-05-23 15:26:42 +02:00
|
|
|
FOR(REQUEST_HANDLE request) X IN RDB$DEPENDENCIES WITH
|
|
|
|
X.RDB$DEPENDENT_NAME = object_name AND
|
|
|
|
X.RDB$DEPENDED_ON_NAME = dpdo_name AND
|
|
|
|
X.RDB$DEPENDED_ON_TYPE = dpdo_type AND
|
|
|
|
X.RDB$FIELD_NAME = field_name AND
|
|
|
|
X.RDB$DEPENDENT_TYPE = dependency_type
|
|
|
|
|
|
|
|
if (!REQUEST(irq_c_deps_f))
|
|
|
|
REQUEST(irq_c_deps_f) = request;
|
2004-01-03 11:59:52 +01:00
|
|
|
found = true;
|
2001-05-23 15:26:42 +02:00
|
|
|
END_FOR;
|
|
|
|
|
2004-01-03 11:59:52 +01:00
|
|
|
if (found) {
|
2001-05-23 15:26:42 +02:00
|
|
|
continue;
|
2004-01-03 11:59:52 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
if (!REQUEST(irq_c_deps_f))
|
|
|
|
REQUEST(irq_c_deps_f) = request;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2004-02-20 07:43:27 +01:00
|
|
|
blk* request = CMP_find_request(tdbb, irq_c_deps, IRQ_REQUESTS);
|
2004-01-03 11:59:52 +01:00
|
|
|
bool found = false;
|
2001-05-23 15:26:42 +02:00
|
|
|
FOR(REQUEST_HANDLE request) X IN RDB$DEPENDENCIES WITH
|
|
|
|
X.RDB$DEPENDENT_NAME = object_name AND
|
|
|
|
X.RDB$DEPENDED_ON_NAME = dpdo_name AND
|
|
|
|
X.RDB$DEPENDED_ON_TYPE = dpdo_type AND
|
|
|
|
X.RDB$FIELD_NAME MISSING AND
|
|
|
|
X.RDB$DEPENDENT_TYPE = dependency_type
|
|
|
|
|
|
|
|
if (!REQUEST(irq_c_deps))
|
|
|
|
REQUEST(irq_c_deps) = request;
|
2004-01-03 11:59:52 +01:00
|
|
|
found = true;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
END_FOR;
|
|
|
|
|
2004-01-03 11:59:52 +01:00
|
|
|
if (found) {
|
2001-05-23 15:26:42 +02:00
|
|
|
continue;
|
2004-01-03 11:59:52 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
if (!REQUEST(irq_c_deps))
|
|
|
|
REQUEST(irq_c_deps) = request;
|
|
|
|
}
|
|
|
|
|
2004-02-20 07:43:27 +01:00
|
|
|
blk* request = CMP_find_request(tdbb, irq_s_deps, IRQ_REQUESTS);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
STORE(REQUEST_HANDLE request) DEP IN RDB$DEPENDENCIES
|
|
|
|
strcpy(DEP.RDB$DEPENDENT_NAME, object_name);
|
|
|
|
DEP.RDB$DEPENDED_ON_TYPE = dpdo_type;
|
|
|
|
strcpy(DEP.RDB$DEPENDED_ON_NAME, dpdo_name);
|
|
|
|
if (field_name)
|
|
|
|
{
|
|
|
|
DEP.RDB$FIELD_NAME.NULL = FALSE;
|
|
|
|
strcpy(DEP.RDB$FIELD_NAME, field_name);
|
|
|
|
}
|
2004-01-03 11:59:52 +01:00
|
|
|
else {
|
2001-05-23 15:26:42 +02:00
|
|
|
DEP.RDB$FIELD_NAME.NULL = TRUE;
|
2004-01-03 11:59:52 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
DEP.RDB$DEPENDENT_TYPE = dependency_type;
|
|
|
|
END_STORE;
|
|
|
|
|
|
|
|
if (!REQUEST(irq_s_deps))
|
|
|
|
REQUEST(irq_s_deps) = request;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-03-11 06:04:26 +01:00
|
|
|
static bool verify_TRG_ignore_perm(thread_db* tdbb, const TEXT* trig_name)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/*****************************************************
|
|
|
|
*
|
|
|
|
* v e r i f y _ T R G _ i g n o r e _ p e r m
|
|
|
|
*
|
|
|
|
*****************************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
2004-01-03 11:59:52 +01:00
|
|
|
* Return true if this trigger can go through without any permission
|
2001-05-23 15:26:42 +02:00
|
|
|
* checks. Currently, the only class of triggers that can go
|
2001-07-12 08:32:05 +02:00
|
|
|
* through without permission checks are
|
2001-05-23 15:26:42 +02:00
|
|
|
* (a) two system triggers (RDB$TRIGGERS_34 and RDB$TRIGGERS_35)
|
2001-07-12 08:32:05 +02:00
|
|
|
* (b) those defined for referential integrity actions such as,
|
2001-05-23 15:26:42 +02:00
|
|
|
* set null, set default, and cascade.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
SET_TDBB(tdbb);
|
2004-03-07 08:58:55 +01:00
|
|
|
Database* dbb = tdbb->tdbb_database;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* see if this is a system trigger, with the flag set as TRG_ignore_perm */
|
|
|
|
if (INI_get_trig_flags(trig_name) & (USHORT) TRG_ignore_perm)
|
|
|
|
{
|
2003-12-11 11:33:30 +01:00
|
|
|
return true;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2004-02-20 07:43:27 +01:00
|
|
|
BLK request = CMP_find_request(tdbb, irq_c_trg_perm, IRQ_REQUESTS);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
FOR(REQUEST_HANDLE request)
|
|
|
|
CHK IN RDB$CHECK_CONSTRAINTS CROSS
|
|
|
|
REF IN RDB$REF_CONSTRAINTS WITH
|
|
|
|
CHK.RDB$TRIGGER_NAME EQ trig_name AND
|
|
|
|
REF.RDB$CONSTRAINT_NAME = CHK.RDB$CONSTRAINT_NAME
|
|
|
|
|
|
|
|
if (!REQUEST(irq_c_trg_perm))
|
|
|
|
{
|
|
|
|
REQUEST(irq_c_trg_perm) = request;
|
|
|
|
}
|
|
|
|
|
2004-01-03 11:59:52 +01:00
|
|
|
EXE_unwind(tdbb, (jrd_req*)request);
|
|
|
|
fb_utils::fb_exact_name_limit(REF.RDB$UPDATE_RULE, sizeof(REF.RDB$UPDATE_RULE));
|
|
|
|
fb_utils::fb_exact_name_limit(REF.RDB$DELETE_RULE, sizeof(REF.RDB$DELETE_RULE));
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (!strcmp(REF.RDB$UPDATE_RULE, RI_ACTION_CASCADE) ||
|
|
|
|
!strcmp(REF.RDB$UPDATE_RULE, RI_ACTION_NULL) ||
|
|
|
|
!strcmp(REF.RDB$UPDATE_RULE, RI_ACTION_DEFAULT) ||
|
|
|
|
!strcmp(REF.RDB$DELETE_RULE, RI_ACTION_CASCADE) ||
|
|
|
|
!strcmp(REF.RDB$DELETE_RULE, RI_ACTION_NULL) ||
|
|
|
|
!strcmp(REF.RDB$DELETE_RULE, RI_ACTION_DEFAULT))
|
|
|
|
{
|
2003-12-11 11:33:30 +01:00
|
|
|
return true;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2003-12-11 11:33:30 +01:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
END_FOR;
|
|
|
|
|
|
|
|
if (!REQUEST(irq_c_trg_perm))
|
|
|
|
{
|
|
|
|
REQUEST(irq_c_trg_perm) = request;
|
|
|
|
}
|
|
|
|
|
2003-12-11 11:33:30 +01:00
|
|
|
return false;
|
2001-07-12 08:32:05 +02:00
|
|
|
}
|
2003-10-29 11:53:47 +01:00
|
|
|
|