2001-05-23 15:26:42 +02:00
|
|
|
/*
|
|
|
|
* PROGRAM: JRD Access Method
|
|
|
|
* MODULE: dfw.e
|
|
|
|
* DESCRIPTION: Deferred Work 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-23 11:27:40 +01:00
|
|
|
*
|
2002-06-29 15:03:13 +02:00
|
|
|
* 2001.6.25 Claudio Valderrama: Implement deferred check for udf usage
|
|
|
|
* inside a procedure before dropping the uff and creating stub for future
|
|
|
|
* processing of dependencies from dropped generators.
|
|
|
|
*
|
|
|
|
* 2001.8.12 Claudio Valderrama: find_depend_in_dfw() and other functions
|
|
|
|
* should respect identifiers with embedded blanks instead of chopping them
|
|
|
|
*.
|
|
|
|
* 2001.10.01 Claudio Valderrama: check constraints should fire AFTER the
|
|
|
|
* BEFORE <action> triggers; otherwise they allow invalid data to be stored.
|
|
|
|
* This is a quick fix for SF Bug #444463 until a more robust one is devised
|
|
|
|
* using trigger's rdb$flags or another mechanism.
|
|
|
|
*
|
|
|
|
* 2001.10.10 Ann Harrison: Don't increment the format version unless the
|
|
|
|
* table is actually reformatted. At the same time, break out some of
|
|
|
|
* the parts of make_version making some new subroutines with the goal
|
|
|
|
* of making make_version readable.
|
|
|
|
*
|
|
|
|
* 2001.10.18 Ann Harrison: some cleanup of trigger & constraint handling.
|
|
|
|
* it now appears to work correctly on new Firebird databases with lots
|
|
|
|
* of system types and on InterBase databases, without checking for
|
|
|
|
* missing source.
|
|
|
|
*
|
2002-02-23 11:27:40 +01:00
|
|
|
* 23-Feb-2002 Dmitry Yemanov - Events wildcarding
|
|
|
|
*
|
2002-02-24 17:39:31 +01:00
|
|
|
* 2002-02-24 Sean Leyne - Code Cleanup of old Win 3.1 port (WINDOWS_ONLY)
|
|
|
|
*
|
2001-05-23 15:26:42 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef SHLIB_DEFS
|
|
|
|
#define LOCAL_SHLIB_DEFS
|
|
|
|
#endif
|
|
|
|
|
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>
|
2001-07-29 19:42:23 +02:00
|
|
|
#include "../jrd/gds.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/pio.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"
|
|
|
|
#include "../jrd/lck.h"
|
|
|
|
#include "../jrd/sdw.h"
|
|
|
|
#include "../jrd/flags.h"
|
|
|
|
#include "../jrd/all.h"
|
|
|
|
#include "../jrd/intl.h"
|
|
|
|
#include "../intl/charsets.h"
|
|
|
|
#include "../jrd/align.h"
|
|
|
|
#include "../jrd/gdsassert.h"
|
|
|
|
#include "../jrd/constants.h"
|
|
|
|
#include "../jrd/all_proto.h"
|
|
|
|
#include "../jrd/blb_proto.h"
|
|
|
|
#include "../jrd/btr_proto.h"
|
|
|
|
#include "../jrd/cch_proto.h"
|
|
|
|
#include "../jrd/cmp_proto.h"
|
|
|
|
#include "../jrd/dfw_proto.h"
|
|
|
|
#include "../jrd/dpm_proto.h"
|
|
|
|
#include "../jrd/dsc_proto.h"
|
|
|
|
#include "../jrd/err_proto.h"
|
|
|
|
#include "../jrd/exe_proto.h"
|
2001-09-18 21:12:25 +02:00
|
|
|
#include "../jrd/ext_proto.h"
|
2001-05-23 15:26:42 +02:00
|
|
|
#include "../jrd/gds_proto.h"
|
|
|
|
#include "../jrd/grant_proto.h"
|
|
|
|
#include "../jrd/idx_proto.h"
|
|
|
|
#include "../jrd/intl_proto.h"
|
|
|
|
#include "../jrd/isc_f_proto.h"
|
|
|
|
|
|
|
|
#include "../jrd/lck_proto.h"
|
|
|
|
#include "../jrd/met_proto.h"
|
|
|
|
#include "../jrd/mov_proto.h"
|
|
|
|
#include "../jrd/pag_proto.h"
|
|
|
|
#include "../jrd/pcmet_proto.h"
|
|
|
|
#include "../jrd/pio_proto.h"
|
|
|
|
#include "../jrd/sch_proto.h"
|
|
|
|
#include "../jrd/scl_proto.h"
|
|
|
|
#include "../jrd/sbm_proto.h"
|
|
|
|
#include "../jrd/sdw_proto.h"
|
|
|
|
#include "../jrd/thd_proto.h"
|
|
|
|
#include "../jrd/event_proto.h"
|
|
|
|
|
2001-07-12 08:32:05 +02:00
|
|
|
#ifdef HAVE_UNISTD_H
|
|
|
|
#include <unistd.h>
|
|
|
|
#endif
|
|
|
|
|
2001-07-29 19:42:23 +02:00
|
|
|
#include "gen/codes.h"
|
2001-07-12 08:32:05 +02:00
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
/* Pick up system relation ids */
|
|
|
|
|
|
|
|
#define RELATION(name,id,ods) id,
|
|
|
|
#define FIELD(symbol,name,id,update,ods,new_id,new_ods)
|
|
|
|
#define END_RELATION
|
|
|
|
|
|
|
|
typedef ENUM rids
|
|
|
|
{
|
|
|
|
#include "../jrd/relations.h"
|
|
|
|
rel_MAX
|
|
|
|
} RIDS;
|
|
|
|
|
|
|
|
#undef RELATION
|
|
|
|
#undef FIELD
|
|
|
|
#undef END_RELATION
|
|
|
|
|
|
|
|
/* Define range of user relation ids */
|
|
|
|
|
|
|
|
#define MIN_RELATION_ID rel_MAX
|
|
|
|
#define MAX_RELATION_ID 32767
|
|
|
|
|
|
|
|
#define COMPUTED_FLAG 128
|
|
|
|
#define NULL_BLOB(id) (!id.gds_quad_high && !id.gds_quad_low)
|
|
|
|
#define WAIT_PERIOD -1
|
|
|
|
|
|
|
|
DATABASE DB = FILENAME "ODS.RDB";
|
|
|
|
|
|
|
|
/*==================================================================
|
|
|
|
**
|
|
|
|
** NOTE:
|
|
|
|
**
|
|
|
|
** The following functions required the same number of
|
|
|
|
** parameters to be passed.
|
|
|
|
**
|
|
|
|
**==================================================================
|
|
|
|
*/
|
2002-11-17 01:13:59 +01:00
|
|
|
static bool add_file(TDBB, SSHORT, DFW, JRD_TRA);
|
|
|
|
static bool add_shadow(TDBB, SSHORT, DFW, JRD_TRA);
|
|
|
|
static bool delete_shadow(TDBB, SSHORT, DFW, JRD_TRA);
|
|
|
|
static bool compute_security(TDBB, SSHORT, DFW, JRD_TRA);
|
|
|
|
static bool create_index(TDBB, SSHORT, DFW, JRD_TRA);
|
|
|
|
static bool delete_index(TDBB, SSHORT, DFW, JRD_TRA);
|
|
|
|
static bool create_log(TDBB, SSHORT, DFW, JRD_TRA);
|
|
|
|
static bool delete_log(TDBB, SSHORT, DFW, JRD_TRA);
|
|
|
|
static bool create_procedure(TDBB, SSHORT, DFW, JRD_TRA);
|
|
|
|
static bool delete_procedure(TDBB, SSHORT, DFW, JRD_TRA);
|
|
|
|
static bool modify_procedure(TDBB, SSHORT, DFW, JRD_TRA);
|
|
|
|
static bool create_relation(TDBB, SSHORT, DFW, JRD_TRA);
|
|
|
|
static bool delete_relation(TDBB, SSHORT, DFW, JRD_TRA);
|
|
|
|
static bool scan_relation(TDBB, SSHORT, DFW, JRD_TRA);
|
|
|
|
static bool create_trigger(TDBB, SSHORT, DFW, JRD_TRA);
|
|
|
|
static bool delete_trigger(TDBB, SSHORT, DFW, JRD_TRA);
|
|
|
|
static bool modify_trigger(TDBB, SSHORT, DFW, JRD_TRA);
|
|
|
|
static bool delete_exception(TDBB, SSHORT, DFW, JRD_TRA);
|
|
|
|
static bool delete_generator(TDBB, SSHORT, DFW, JRD_TRA);
|
|
|
|
static bool delete_udf(TDBB, SSHORT, DFW, JRD_TRA);
|
|
|
|
static bool delete_field(TDBB, SSHORT, DFW, JRD_TRA);
|
|
|
|
static bool delete_global(TDBB, SSHORT, DFW, JRD_TRA);
|
|
|
|
static bool delete_parameter(TDBB, SSHORT, DFW, JRD_TRA);
|
|
|
|
static bool delete_rfr(TDBB, SSHORT, DFW, JRD_TRA);
|
|
|
|
static bool make_version(TDBB, SSHORT, DFW, JRD_TRA);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* ---------------------------------------------------------------- */
|
|
|
|
|
2002-11-17 01:13:59 +01:00
|
|
|
static void check_dependencies(TDBB, TEXT*, TEXT*, USHORT, JRD_TRA);
|
2001-05-23 15:26:42 +02:00
|
|
|
static void check_filename(TEXT*, USHORT);
|
2002-07-05 17:00:26 +02:00
|
|
|
static bool formatsAreEqual(FMT, FMT);
|
2002-11-17 01:13:59 +01:00
|
|
|
static bool find_depend_in_dfw(TDBB, TEXT*, USHORT, USHORT, JRD_TRA);
|
2001-05-23 15:26:42 +02:00
|
|
|
static void get_array_desc(TDBB, TEXT*, ADS);
|
|
|
|
static void get_procedure_dependencies(DFW);
|
|
|
|
static void get_trigger_dependencies(DFW);
|
2002-11-17 01:13:59 +01:00
|
|
|
static void load_trigs(TDBB, JRD_REL, TRIG_VEC *);
|
|
|
|
static FMT make_format(TDBB, JRD_REL, USHORT *, TFB);
|
2001-05-23 15:26:42 +02:00
|
|
|
static USHORT name_length(TEXT *);
|
|
|
|
static void put_summary_blob(BLB, enum rsr_t, SLONG[2]);
|
|
|
|
static void put_summary_record(BLB, enum rsr_t, UCHAR *, USHORT);
|
2002-07-05 17:00:26 +02:00
|
|
|
static void setup_array(TDBB, BLB, TEXT *, USHORT, TFB);
|
2002-11-17 01:13:59 +01:00
|
|
|
static BLB setup_triggers(TDBB, JRD_REL, BOOLEAN, TRIG_VEC *, BLB);
|
|
|
|
static void setup_trigger_details(TDBB, JRD_REL, BLB, TRIG_VEC *, TEXT*, TEXT*, BOOLEAN);
|
|
|
|
//static void setup_trigger_details(TDBB, JRD_REL, BLB, VEC *, UCHAR *, UCHAR *, BOOLEAN);
|
2001-12-24 03:51:06 +01:00
|
|
|
static bool shadow_defined(TDBB);
|
2002-06-29 15:03:13 +02:00
|
|
|
static bool validate_text_type (TDBB, STATUS *, TFB);
|
2001-12-24 03:51:06 +01:00
|
|
|
static bool wal_defined(TDBB);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
static CONST UCHAR nonnull_validation_blr[] =
|
|
|
|
{
|
|
|
|
blr_version5,
|
|
|
|
blr_not,
|
|
|
|
blr_missing,
|
|
|
|
blr_fid, 0, 0, 0,
|
|
|
|
blr_eoc
|
|
|
|
};
|
|
|
|
|
|
|
|
typedef struct task
|
|
|
|
{
|
|
|
|
ENUM dfw_t task_type;
|
2002-11-17 01:13:59 +01:00
|
|
|
bool (*task_routine) (TDBB, SSHORT, DFW, JRD_TRA);
|
2001-05-23 15:26:42 +02:00
|
|
|
} TASK;
|
|
|
|
|
|
|
|
static CONST TASK task_table[] =
|
|
|
|
{
|
2001-12-24 03:51:06 +01:00
|
|
|
{ dfw_add_file, add_file },
|
|
|
|
{ dfw_add_shadow, add_shadow },
|
|
|
|
{ dfw_delete_index, delete_index },
|
|
|
|
{ dfw_delete_rfr, delete_rfr },
|
|
|
|
{ dfw_delete_relation, delete_relation },
|
|
|
|
{ dfw_delete_shadow, delete_shadow },
|
|
|
|
{ dfw_delete_field, delete_field },
|
|
|
|
{ dfw_delete_global, delete_global },
|
|
|
|
{ dfw_create_relation, create_relation },
|
|
|
|
{ dfw_update_format, make_version },
|
|
|
|
{ dfw_scan_relation, scan_relation },
|
|
|
|
{ dfw_compute_security, compute_security },
|
|
|
|
{ dfw_create_index, create_index },
|
2001-05-23 15:26:42 +02:00
|
|
|
#ifdef EXPRESSION_INDICES
|
2001-12-24 03:51:06 +01:00
|
|
|
{ dfw_create_expression_index, PCMET_expression_index },
|
2001-05-23 15:26:42 +02:00
|
|
|
#endif
|
2001-12-24 03:51:06 +01:00
|
|
|
{ dfw_delete_expression_index, delete_index },
|
2002-11-17 01:13:59 +01:00
|
|
|
{ dfw_grant, (bool(*)(TDBB, SSHORT, DFW, JRD_TRA))GRANT_privileges },
|
2001-12-24 03:51:06 +01:00
|
|
|
{ dfw_create_trigger, create_trigger },
|
|
|
|
{ dfw_delete_trigger, delete_trigger },
|
|
|
|
{ dfw_modify_trigger, modify_trigger },
|
|
|
|
{ dfw_create_log, create_log },
|
|
|
|
{ dfw_delete_log, delete_log },
|
|
|
|
{ dfw_create_procedure, create_procedure },
|
|
|
|
{ dfw_delete_procedure, delete_procedure },
|
|
|
|
{ dfw_modify_procedure, modify_procedure },
|
|
|
|
{ dfw_delete_prm, delete_parameter },
|
|
|
|
{ dfw_delete_exception, delete_exception },
|
2002-06-29 15:03:13 +02:00
|
|
|
{ dfw_delete_generator, delete_generator },
|
|
|
|
{ dfw_delete_udf, delete_udf },
|
2001-12-24 03:51:06 +01:00
|
|
|
{ dfw_null, NULL }
|
2001-05-23 15:26:42 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
#ifdef SHLIB_DEFS
|
|
|
|
#define strcpy (*_libgds_strcpy)
|
|
|
|
#define strlen (*_libgds_strlen)
|
|
|
|
#define strcmp (*_libgds_strcmp)
|
|
|
|
#define memcmp (*_libgds_memcmp)
|
|
|
|
#define strncmp (*_libgds_strncmp)
|
|
|
|
#define unlink (*_libgds_unlink)
|
|
|
|
#define _iob (*_libgds__iob)
|
|
|
|
#define ib_fprintf (*_libgds_fprintf)
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
extern int strlen(const char*);
|
|
|
|
extern int strcmp(const char*, const char*);
|
|
|
|
extern int memcmp(const void*, const void*, size_t);
|
|
|
|
extern int strncmp(const char*, char*, size_t);
|
|
|
|
extern char* strcpy(char* const char*);
|
|
|
|
extern int unlink(const char*);
|
2001-05-23 15:26:42 +02:00
|
|
|
extern IB_FILE _iob[];
|
|
|
|
extern int ib_fprintf();
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
USHORT DFW_assign_index_type(DFW work, SSHORT field_type, SSHORT ttype)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* D F W _ a s s i g n _ i n d e x _ t y p e
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Define the index segment type based
|
|
|
|
* on the field's type and subtype.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
TDBB tdbb;
|
|
|
|
|
|
|
|
tdbb = GET_THREAD_DATA;
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
if (field_type == dtype_varying || field_type == dtype_text)
|
|
|
|
{
|
2002-10-24 11:01:44 +02:00
|
|
|
STATUS status[ISC_STATUS_LENGTH];
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (ttype == ttype_none)
|
|
|
|
return idx_string;
|
|
|
|
|
|
|
|
if (ttype == ttype_binary)
|
|
|
|
return idx_byte_array;
|
|
|
|
|
|
|
|
if (ttype == ttype_metadata)
|
|
|
|
return idx_metadata;
|
|
|
|
|
|
|
|
if (ttype == ttype_ascii)
|
|
|
|
return idx_string;
|
|
|
|
|
|
|
|
/* Dynamic text cannot occur here as this is for an on-disk
|
|
|
|
index, which must be bound to a text type. */
|
|
|
|
|
|
|
|
assert(ttype != ttype_dynamic);
|
|
|
|
|
|
|
|
if (INTL_defined_type(tdbb, status, ttype))
|
|
|
|
return INTL_TEXT_TO_INDEX(ttype);
|
|
|
|
|
2001-07-29 19:42:23 +02:00
|
|
|
ERR_post(gds_no_meta_update,
|
|
|
|
gds_arg_gds, gds_random, gds_arg_string,
|
2001-05-23 15:26:42 +02:00
|
|
|
ERR_cstring(work->dfw_name), status[0], status[1], status[2],
|
|
|
|
status[3],
|
|
|
|
0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (field_type == dtype_timestamp)
|
|
|
|
return idx_timestamp2;
|
|
|
|
else if (field_type == dtype_sql_date)
|
|
|
|
return idx_sql_date;
|
|
|
|
else if (field_type == dtype_sql_time)
|
|
|
|
return idx_sql_time;
|
|
|
|
|
|
|
|
/* idx_numeric2 used for 64-bit Integer support */
|
|
|
|
if (field_type == dtype_int64)
|
|
|
|
return idx_numeric2;
|
|
|
|
|
|
|
|
return idx_numeric;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-11-17 01:13:59 +01:00
|
|
|
void DFW_delete_deferred( JRD_TRA transaction, SLONG sav_number)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* D F W _ d e l e t e _ d e f e r r e d
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Get rid of work deferred that was to be done at
|
|
|
|
* COMMIT time as the statement has been rolled back.
|
|
|
|
*
|
|
|
|
* if (sav_number == -1), then remove all entries.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
USHORT deferred_meta = 0;
|
|
|
|
DFW work, *ptr;
|
|
|
|
|
|
|
|
/* If there is no deferred work, just return */
|
|
|
|
|
|
|
|
if (!transaction->tra_deferred_work) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Remove deferred work and events which are to be rolled back */
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
for (ptr = &transaction->tra_deferred_work; (work = *ptr);)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
if ((work->dfw_sav_number == sav_number) || (sav_number == -1))
|
|
|
|
{
|
|
|
|
*ptr = work->dfw_next;
|
2001-12-24 03:51:06 +01:00
|
|
|
delete work;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ptr = &(*ptr)->dfw_next;
|
|
|
|
if (work->dfw_type != dfw_post_event)
|
|
|
|
deferred_meta = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!deferred_meta) {
|
|
|
|
transaction->tra_flags &= ~TRA_deferred_meta;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-11-17 01:13:59 +01:00
|
|
|
void DFW_merge_work(JRD_TRA transaction,
|
2001-05-23 15:26:42 +02:00
|
|
|
SLONG old_sav_number,
|
|
|
|
SLONG new_sav_number)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* D F W _ m e r g e _ w o r k
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Merge the deferred work with the previous level. This will
|
2002-06-29 15:03:13 +02:00
|
|
|
* be called only if there is a previous level.
|
2001-05-23 15:26:42 +02:00
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
DFW work, *ptr;
|
|
|
|
DFW work_m, *ptr_m;
|
|
|
|
|
|
|
|
/* If there is no deferred work, just return */
|
|
|
|
|
|
|
|
if (!transaction->tra_deferred_work)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* Decrement the save point number in the deferred block
|
|
|
|
* i.e. merge with the previous level.
|
|
|
|
*/
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
for (ptr = &transaction->tra_deferred_work; (work = *ptr);)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
if (work->dfw_sav_number == old_sav_number)
|
|
|
|
{
|
|
|
|
work->dfw_sav_number = new_sav_number;
|
|
|
|
|
|
|
|
/* merge this entry with other identical entries at
|
|
|
|
* same save point level. Start from the beginning and
|
|
|
|
* stop with the that is being merged.
|
|
|
|
*/
|
|
|
|
|
|
|
|
for (ptr_m = &transaction->tra_deferred_work;
|
|
|
|
((work_m = *ptr_m) && (work_m != work));
|
|
|
|
ptr_m = &(*ptr_m)->dfw_next)
|
|
|
|
{
|
|
|
|
if (work_m->dfw_type == work->dfw_type &&
|
|
|
|
work_m->dfw_id == work->dfw_id &&
|
|
|
|
work_m->dfw_name_length == work->dfw_name_length &&
|
|
|
|
work_m->dfw_sav_number == work->dfw_sav_number)
|
|
|
|
{
|
|
|
|
if ((work->dfw_name_length) &&
|
|
|
|
(memcmp(work->dfw_name,
|
|
|
|
work_m->dfw_name,
|
|
|
|
work->dfw_name_length)))
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Yes! There is a duplicate entry. Take out the
|
|
|
|
* entry for which the save point was decremented
|
|
|
|
*/
|
|
|
|
|
|
|
|
*ptr = work->dfw_next;
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
if (work_m->dfw_name_length) {
|
2001-05-23 15:26:42 +02:00
|
|
|
work_m->dfw_count += work->dfw_count;
|
2001-12-24 03:51:06 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
delete work;
|
2001-05-23 15:26:42 +02:00
|
|
|
work = (DFW) 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
if (work) {
|
2001-05-23 15:26:42 +02:00
|
|
|
ptr = &(*ptr)->dfw_next;
|
2001-12-24 03:51:06 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void DFW_perform_system_work(void)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* D F W _ p e r f o r m _ s y s t e m _ w o r k
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Flush out the work left to be done in the
|
|
|
|
* system transaction.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
DBB dbb;
|
|
|
|
|
|
|
|
dbb = GET_DBB;
|
|
|
|
|
|
|
|
DFW_perform_work(dbb->dbb_sys_trans);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-11-17 01:13:59 +01:00
|
|
|
void DFW_perform_work(JRD_TRA transaction)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* D F W _ p e r f o r m _ w o r k
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Do work deferred to COMMIT time 'cause that time has
|
|
|
|
* come.
|
|
|
|
*
|
|
|
|
**************************************/
|
2001-12-24 03:51:06 +01:00
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
TDBB tdbb = GET_THREAD_DATA;
|
2001-12-24 03:51:06 +01:00
|
|
|
bool dump_shadow = false;
|
2001-05-23 15:26:42 +02:00
|
|
|
SSHORT phase = 1;
|
|
|
|
DFW work;
|
|
|
|
|
|
|
|
/* If no deferred work or it's all deferred event posting
|
|
|
|
don't bother */
|
|
|
|
|
|
|
|
if (!transaction->tra_deferred_work ||
|
|
|
|
!(transaction->tra_flags & TRA_deferred_meta))
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
tdbb->tdbb_default = transaction->tra_pool;
|
|
|
|
|
|
|
|
/* Loop for as long as any of the deferred work routines says that it has
|
|
|
|
more to do. A deferred work routine should be able to deal with any
|
|
|
|
value of phase, either to say that it wants to be called again in the
|
|
|
|
next phase (by returning TRUE) or that it has nothing more to do in this
|
|
|
|
or later phases (by returning FALSE). By convention, phase 0 has been
|
|
|
|
designated as the cleanup phase. If any non-zero phase punts, then phase 0
|
|
|
|
is executed for all deferred work blocks to cleanup work-in-progress. */
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
bool more;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
do
|
|
|
|
{
|
2001-12-24 03:51:06 +01:00
|
|
|
more = false;
|
|
|
|
try {
|
|
|
|
const TASK* task;
|
|
|
|
for (task = task_table; task->task_type != dfw_null; ++task)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2001-12-24 03:51:06 +01:00
|
|
|
for (work = transaction->tra_deferred_work;
|
|
|
|
work;
|
|
|
|
work = work->dfw_next)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2001-12-24 03:51:06 +01:00
|
|
|
if (work->dfw_type == task->task_type)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2001-12-24 03:51:06 +01:00
|
|
|
if (work->dfw_type == dfw_add_shadow)
|
|
|
|
{
|
|
|
|
dump_shadow = true;
|
|
|
|
}
|
|
|
|
if ((*task->task_routine)(tdbb, phase, work, transaction))
|
|
|
|
{
|
|
|
|
more = true;
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2001-12-24 03:51:06 +01:00
|
|
|
if (!phase) {
|
|
|
|
ERR_punt();
|
|
|
|
}
|
|
|
|
++phase;
|
|
|
|
}
|
|
|
|
catch (...) {
|
|
|
|
/* Do any necessary cleanup */
|
|
|
|
if (!phase) {
|
|
|
|
ERR_punt();
|
|
|
|
}
|
|
|
|
phase = 0;
|
|
|
|
more = true;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
} while (more);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* Remove deferred work blocks so that system transaction and
|
|
|
|
commit retaining transactions don't re-execute them. Leave
|
|
|
|
events to be posted after commit */
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
for (DFW* ptr = &transaction->tra_deferred_work; (work = *ptr);)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
if ((work->dfw_type == dfw_post_event) ||
|
|
|
|
(work->dfw_type == dfw_delete_shadow))
|
|
|
|
{
|
|
|
|
ptr = &(*ptr)->dfw_next;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
*ptr = work->dfw_next;
|
2001-12-24 03:51:06 +01:00
|
|
|
delete work;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
transaction->tra_flags &= ~TRA_deferred_meta;
|
|
|
|
|
|
|
|
if (dump_shadow) {
|
|
|
|
SDW_dump_pages();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-11-17 01:13:59 +01:00
|
|
|
void DFW_perform_post_commit_work(JRD_TRA transaction)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* D F W _ p e r f o r m _ p o s t _ c o m m i t _ w o r k
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Perform any post commit work
|
|
|
|
* 1. Post any pending events.
|
|
|
|
* 2. Unlink shadow files for dropped shadows
|
|
|
|
*
|
|
|
|
* Then, delete it from chain of pending work.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
DBB dbb;
|
|
|
|
LCK lock;
|
2002-10-24 11:01:44 +02:00
|
|
|
STATUS status[ISC_STATUS_LENGTH];
|
2001-05-23 15:26:42 +02:00
|
|
|
DFW work, *ptr;
|
|
|
|
|
|
|
|
if (!transaction->tra_deferred_work)
|
|
|
|
return;
|
|
|
|
|
|
|
|
dbb = GET_DBB;
|
|
|
|
lock = dbb->dbb_lock;
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
for (ptr = &transaction->tra_deferred_work; (work = *ptr);)
|
2001-05-23 15:26:42 +02:00
|
|
|
if (work->dfw_type == dfw_post_event)
|
|
|
|
{
|
|
|
|
EVENT_post( status,
|
|
|
|
lock->lck_length,
|
|
|
|
(TEXT *) & lock->lck_key,
|
|
|
|
work->dfw_name_length,
|
|
|
|
work->dfw_name,
|
|
|
|
work->dfw_count);
|
|
|
|
*ptr = work->dfw_next;
|
2001-12-24 03:51:06 +01:00
|
|
|
delete work;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
else if (work->dfw_type == dfw_delete_shadow)
|
|
|
|
{
|
|
|
|
unlink(work->dfw_name);
|
|
|
|
*ptr = work->dfw_next;
|
2001-12-24 03:51:06 +01:00
|
|
|
delete work;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ptr = &(*ptr)->dfw_next;
|
|
|
|
}
|
2002-02-23 11:27:40 +01:00
|
|
|
|
|
|
|
#ifdef EVENTS_WILDCARDING
|
|
|
|
/* Deliver all pending events */
|
|
|
|
EVENT_post_finalize();
|
|
|
|
#endif /* EVENTS_WILDCARDING */
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-11-17 01:13:59 +01:00
|
|
|
void DFW_post_work( JRD_TRA transaction, ENUM dfw_t type, DSC * desc, USHORT id)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* D F W _ p o s t _ w o r k
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Post a piece of work to be deferred to commit time.
|
|
|
|
* If we already know about it, so much the better.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
DFW work, *ptr;
|
2002-10-29 17:27:47 +01:00
|
|
|
const char* string;
|
2001-05-23 15:26:42 +02:00
|
|
|
USHORT length;
|
|
|
|
TEXT temp[256]; /* Must hold largest metadata field */
|
|
|
|
SLONG sav_number;
|
|
|
|
|
|
|
|
if (!desc)
|
|
|
|
{
|
|
|
|
string = NULL;
|
|
|
|
length = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Find the actual length of the string, searching until the claimed
|
|
|
|
end of the string, or the terminating \0, whichever comes first. */
|
|
|
|
|
|
|
|
length = MOV_make_string(desc,
|
|
|
|
ttype_metadata,
|
|
|
|
&string,
|
|
|
|
(VARY*)temp,
|
|
|
|
sizeof(temp));
|
|
|
|
|
2002-10-29 17:27:47 +01:00
|
|
|
const char* p = string;
|
|
|
|
const char* q = string + length;
|
2001-05-23 15:26:42 +02:00
|
|
|
while (p < q && *p)
|
|
|
|
{
|
|
|
|
++p;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Trim trailing blanks (bug 3355) */
|
|
|
|
|
|
|
|
while (--p >= string && *p == ' ')
|
|
|
|
;
|
|
|
|
length = (p + 1) - string;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* get the current save point number */
|
|
|
|
|
|
|
|
sav_number = transaction->tra_save_point ?
|
|
|
|
transaction->tra_save_point->sav_number : 0;
|
|
|
|
|
|
|
|
/* Check to see if work is already posted */
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
for (ptr = &transaction->tra_deferred_work; (work = *ptr);
|
2001-05-23 15:26:42 +02:00
|
|
|
ptr = &(*ptr)->dfw_next)
|
|
|
|
{
|
|
|
|
if (work->dfw_type == type &&
|
|
|
|
work->dfw_id == id &&
|
|
|
|
work->dfw_name_length == length &&
|
|
|
|
work->dfw_sav_number == sav_number)
|
|
|
|
{
|
|
|
|
if (!length)
|
|
|
|
return;
|
|
|
|
if (!memcmp(string, work->dfw_name, length)) {
|
|
|
|
++work->dfw_count;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Not already posted, so do so now. */
|
|
|
|
|
2002-09-25 19:12:16 +02:00
|
|
|
*ptr = work = FB_NEW_RPT(*transaction->tra_pool, length) dfw;
|
2001-05-23 15:26:42 +02:00
|
|
|
work->dfw_type = type;
|
|
|
|
work->dfw_id = id;
|
|
|
|
work->dfw_count = 1;
|
|
|
|
work->dfw_name_length = length;
|
|
|
|
work->dfw_sav_number = sav_number;
|
|
|
|
if (length)
|
|
|
|
MOVE_FAST(string, work->dfw_name, length);
|
|
|
|
|
|
|
|
if (type != dfw_post_event)
|
|
|
|
transaction->tra_flags |= TRA_deferred_meta;
|
|
|
|
else if (transaction->tra_save_point)
|
|
|
|
transaction->tra_save_point->sav_flags |= SAV_event_post;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void DFW_update_index( DFW work, USHORT id, float selectivity)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* D F W _ u p d a t e _ i n d e x
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Update information in the index relation after creation
|
|
|
|
* of the index.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
TDBB tdbb;
|
|
|
|
DBB dbb;
|
|
|
|
BLK request;
|
|
|
|
|
|
|
|
tdbb = GET_THREAD_DATA;
|
|
|
|
dbb = tdbb->tdbb_database;
|
|
|
|
|
|
|
|
request = (BLK) CMP_find_request(tdbb, irq_m_index, IRQ_REQUESTS);
|
|
|
|
|
|
|
|
FOR(REQUEST_HANDLE request)
|
|
|
|
IDX IN RDB$INDICES WITH IDX.RDB$INDEX_NAME EQ work->dfw_name
|
|
|
|
if (!REQUEST(irq_m_index))
|
2001-07-12 08:32:05 +02:00
|
|
|
REQUEST(irq_m_index) = (BLK)request;
|
2001-05-23 15:26:42 +02:00
|
|
|
MODIFY IDX USING
|
|
|
|
IDX.RDB$INDEX_ID = id + 1;
|
|
|
|
IDX.RDB$STATISTICS = selectivity;
|
|
|
|
END_MODIFY;
|
|
|
|
END_FOR;
|
|
|
|
|
|
|
|
if (!REQUEST(irq_m_index))
|
|
|
|
REQUEST(irq_m_index) = (BLK)request;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-11-17 01:13:59 +01:00
|
|
|
static bool add_file(TDBB tdbb, SSHORT phase, DFW work, JRD_TRA transaction)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* a d d _ f i l e
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Add a file to a database.
|
|
|
|
* This file could be a regular database
|
|
|
|
* file or a shadow file. Either way we
|
|
|
|
* require exclusive access to the database.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
DBB dbb;
|
|
|
|
USHORT section, shadow_number;
|
|
|
|
SLONG start, max;
|
|
|
|
BLK handle, handle2;
|
2002-10-24 11:01:44 +02:00
|
|
|
TEXT temp[MAXPATHLEN];
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
SET_TDBB(tdbb);
|
|
|
|
dbb = tdbb->tdbb_database;
|
|
|
|
|
|
|
|
switch (phase)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
CCH_release_exclusive(tdbb);
|
2001-12-24 03:51:06 +01:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
case 1:
|
|
|
|
case 2:
|
2001-12-24 03:51:06 +01:00
|
|
|
return true;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
case 3:
|
|
|
|
if (CCH_exclusive(tdbb, LCK_EX, WAIT_PERIOD))
|
|
|
|
{
|
2001-12-24 03:51:06 +01:00
|
|
|
return true;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2001-07-29 19:42:23 +02:00
|
|
|
ERR_post(gds_no_meta_update,
|
|
|
|
gds_arg_gds, gds_lock_timeout,
|
|
|
|
gds_arg_gds, gds_obj_in_use,
|
2001-05-23 15:26:42 +02:00
|
|
|
gds_arg_string, ERR_cstring(dbb->dbb_file->fil_string),
|
|
|
|
0);
|
2001-12-24 03:51:06 +01:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
case 4:
|
|
|
|
CCH_flush(tdbb, (USHORT) FLUSH_FINI, 0L);
|
|
|
|
max = PIO_max_alloc(dbb) + 1;
|
|
|
|
handle = handle2 = NULL;
|
|
|
|
|
|
|
|
/* Check the file name for node name. This has already been done for
|
2001-12-24 03:51:06 +01:00
|
|
|
** shadows in add_shadow() */
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
if (work->dfw_type != dfw_add_shadow) {
|
2001-05-23 15:26:42 +02:00
|
|
|
check_filename(work->dfw_name, work->dfw_name_length);
|
2001-12-24 03:51:06 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* get any files to extend into */
|
|
|
|
|
|
|
|
FOR(REQUEST_HANDLE handle) X IN RDB$FILES
|
|
|
|
WITH X.RDB$FILE_NAME EQ work->dfw_name
|
|
|
|
/* First expand the file name This has already been done
|
|
|
|
** for shadows in add_shadow ()) */
|
|
|
|
if (work->dfw_type != dfw_add_shadow)
|
|
|
|
{
|
|
|
|
ISC_expand_filename(X.RDB$FILE_NAME, 0, temp);
|
|
|
|
MODIFY X USING
|
|
|
|
strcpy(X.RDB$FILE_NAME, temp);
|
|
|
|
END_MODIFY;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If there is no starting position specified, or if it is
|
|
|
|
too low a value, make a stab at assigning one based on
|
|
|
|
the indicated preference for the previous file length. */
|
|
|
|
|
|
|
|
if ((start = X.RDB$FILE_START) < max)
|
|
|
|
{
|
|
|
|
FOR(REQUEST_HANDLE handle2)
|
|
|
|
FIRST 1 Y IN RDB$FILES
|
|
|
|
WITH Y.RDB$SHADOW_NUMBER EQ X.RDB$SHADOW_NUMBER
|
|
|
|
AND Y.RDB$FILE_SEQUENCE NOT MISSING
|
|
|
|
SORTED BY DESCENDING Y.RDB$FILE_SEQUENCE
|
|
|
|
start = Y.RDB$FILE_START + Y.RDB$FILE_LENGTH;
|
|
|
|
END_FOR;
|
|
|
|
}
|
|
|
|
|
|
|
|
start = MAX(max, start);
|
|
|
|
shadow_number = X.RDB$SHADOW_NUMBER;
|
|
|
|
if ((shadow_number &&
|
|
|
|
(section = SDW_add_file(X.RDB$FILE_NAME,
|
|
|
|
start,
|
|
|
|
shadow_number))) ||
|
|
|
|
(section = PAG_add_file(X.RDB$FILE_NAME, start)))
|
|
|
|
{
|
|
|
|
MODIFY X USING
|
|
|
|
X.RDB$FILE_SEQUENCE = section;
|
|
|
|
X.RDB$FILE_START = start;
|
|
|
|
END_MODIFY;
|
|
|
|
}
|
|
|
|
END_FOR;
|
|
|
|
|
2002-11-17 01:13:59 +01:00
|
|
|
CMP_release(tdbb, (JRD_REQ)handle);
|
2001-05-23 15:26:42 +02:00
|
|
|
if (handle2)
|
|
|
|
{
|
2002-11-17 01:13:59 +01:00
|
|
|
CMP_release(tdbb, (JRD_REQ)handle2);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (section)
|
|
|
|
{
|
|
|
|
handle = NULL;
|
|
|
|
section--;
|
|
|
|
FOR(REQUEST_HANDLE handle) X IN RDB$FILES
|
|
|
|
WITH X.RDB$FILE_SEQUENCE EQ section
|
|
|
|
AND X.RDB$SHADOW_NUMBER EQ shadow_number
|
|
|
|
MODIFY X USING
|
|
|
|
X.RDB$FILE_LENGTH = start - X.RDB$FILE_START;
|
|
|
|
END_MODIFY;
|
|
|
|
END_FOR;
|
2002-11-17 01:13:59 +01:00
|
|
|
CMP_release(tdbb, (JRD_REQ)handle);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
CCH_release_exclusive(tdbb);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2002-11-17 01:13:59 +01:00
|
|
|
static bool add_shadow( TDBB tdbb, SSHORT phase, DFW work, JRD_TRA transaction)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* a d d _ s h a d o w
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* A file or files have been added for shadowing.
|
|
|
|
* Get all files for this particular shadow first
|
|
|
|
* in order of starting page, if specified, then
|
|
|
|
* in sequence order.
|
|
|
|
*
|
|
|
|
**************************************/
|
2001-12-24 03:51:06 +01:00
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
BLK handle;
|
|
|
|
SDW shadow;
|
|
|
|
USHORT sequence, add_sequence;
|
2001-12-24 03:51:06 +01:00
|
|
|
bool finished;
|
2001-05-23 15:26:42 +02:00
|
|
|
ULONG min_page;
|
|
|
|
TEXT expanded_fname[1024];
|
|
|
|
|
|
|
|
SET_TDBB(tdbb);
|
2001-12-24 03:51:06 +01:00
|
|
|
DBB dbb = tdbb->tdbb_database;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
switch (phase)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
CCH_release_exclusive(tdbb);
|
2001-12-24 03:51:06 +01:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
case 1:
|
|
|
|
case 2:
|
|
|
|
case 3:
|
2001-12-24 03:51:06 +01:00
|
|
|
return true;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
case 4:
|
|
|
|
if (wal_defined(tdbb))
|
2001-12-24 03:51:06 +01:00
|
|
|
{
|
2001-07-29 19:42:23 +02:00
|
|
|
ERR_post(gds_no_meta_update,
|
|
|
|
gds_arg_gds, gds_wal_shadow_err, 0);
|
2001-12-24 03:51:06 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
/* Msg309: Write-Ahead Log with Shadowing configuration not allowed */
|
|
|
|
|
|
|
|
check_filename(work->dfw_name, work->dfw_name_length);
|
|
|
|
|
|
|
|
/* could have two cases:
|
|
|
|
1) this shadow has already been written to, so add this file using
|
|
|
|
the standard routine to extend a database
|
|
|
|
2) this file is part of a newly added shadow which has already been
|
|
|
|
fetched in totem and prepared for writing to, so just ignore it
|
|
|
|
*/
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
finished = false;
|
2001-05-23 15:26:42 +02:00
|
|
|
handle = NULL;
|
|
|
|
FOR(REQUEST_HANDLE handle)
|
|
|
|
F IN RDB$FILES
|
|
|
|
WITH F.RDB$FILE_NAME EQ work->dfw_name
|
|
|
|
ISC_expand_filename(F.RDB$FILE_NAME, 0, expanded_fname);
|
|
|
|
MODIFY F USING
|
|
|
|
strcpy(F.RDB$FILE_NAME, expanded_fname);
|
|
|
|
END_MODIFY;
|
|
|
|
|
|
|
|
for (shadow = dbb->dbb_shadow; shadow; shadow = shadow->sdw_next)
|
|
|
|
if ((F.RDB$SHADOW_NUMBER == shadow->sdw_number) &&
|
|
|
|
!(shadow->sdw_flags & SDW_IGNORE))
|
|
|
|
{
|
|
|
|
if (F.RDB$FILE_FLAGS & FILE_shadow)
|
2001-12-24 03:51:06 +01:00
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
/* This is the case of a bogus duplicate posted
|
|
|
|
* work when we added a multi-file shadow
|
|
|
|
*/
|
2001-12-24 03:51:06 +01:00
|
|
|
finished = true;
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
else if (shadow->sdw_flags & (SDW_dumped))
|
|
|
|
{
|
|
|
|
/* Case of adding a file to a currently active
|
|
|
|
* shadow set.
|
|
|
|
* Note: as of 1995-January-31 there is
|
|
|
|
* no SQL syntax that supports this, but there
|
|
|
|
* may be GDML
|
|
|
|
*/
|
|
|
|
if (!CCH_exclusive(tdbb, LCK_EX, WAIT_PERIOD))
|
2001-07-29 19:42:23 +02:00
|
|
|
ERR_post(gds_no_meta_update,
|
|
|
|
gds_arg_gds, gds_lock_timeout,
|
|
|
|
gds_arg_gds, gds_obj_in_use,
|
2001-05-23 15:26:42 +02:00
|
|
|
gds_arg_string,
|
|
|
|
ERR_cstring(dbb->dbb_file->fil_string),
|
|
|
|
0);
|
2002-11-17 01:13:59 +01:00
|
|
|
add_file(tdbb, phase, work, (JRD_TRA) 0);
|
2001-12-24 03:51:06 +01:00
|
|
|
finished = true;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* We cannot add a file to a shadow that is still
|
|
|
|
* in the process of being created.
|
|
|
|
*/
|
2001-07-29 19:42:23 +02:00
|
|
|
ERR_post(gds_no_meta_update,
|
|
|
|
gds_arg_gds, gds_obj_in_use,
|
2001-05-23 15:26:42 +02:00
|
|
|
gds_arg_string,
|
|
|
|
ERR_cstring(dbb->dbb_file->fil_string),
|
|
|
|
0);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
END_FOR;
|
2002-11-17 01:13:59 +01:00
|
|
|
CMP_release(tdbb, (JRD_REQ)handle);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
if (finished) {
|
|
|
|
return false;
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* this file is part of a new shadow, so get all files for the shadow
|
|
|
|
in order of the starting page for the file */
|
|
|
|
|
|
|
|
/* Note that for a multi-file shadow, we have several pieces of
|
|
|
|
* work posted (one dfw_add_shadow for each file). Rather than
|
|
|
|
* trying to cancel the other pieces of work we ignore them
|
|
|
|
* when they arrive in this routine.
|
|
|
|
*/
|
|
|
|
|
|
|
|
sequence = 0;
|
|
|
|
min_page = 0;
|
|
|
|
shadow = NULL;
|
|
|
|
handle = NULL;
|
|
|
|
FOR(REQUEST_HANDLE handle)
|
|
|
|
X IN RDB$FILES CROSS
|
|
|
|
Y IN RDB$FILES
|
|
|
|
OVER RDB$SHADOW_NUMBER
|
|
|
|
WITH X.RDB$FILE_NAME EQ expanded_fname
|
|
|
|
SORTED BY Y.RDB$FILE_START
|
|
|
|
/* for the first file, create a brand new shadow; for secondary
|
|
|
|
files that have a starting page specified, add a file */
|
|
|
|
if (!sequence)
|
|
|
|
SDW_add(Y.RDB$FILE_NAME, Y.RDB$SHADOW_NUMBER, Y.RDB$FILE_FLAGS);
|
|
|
|
else if (Y.RDB$FILE_START)
|
|
|
|
{
|
|
|
|
if (!shadow)
|
|
|
|
{
|
|
|
|
for (shadow = dbb->dbb_shadow;
|
|
|
|
shadow;
|
|
|
|
shadow = shadow->sdw_next)
|
|
|
|
{
|
|
|
|
if ((Y.RDB$SHADOW_NUMBER == shadow->sdw_number) &&
|
|
|
|
!(shadow->sdw_flags & SDW_IGNORE))
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!shadow)
|
|
|
|
BUGCHECK(203); /* msg 203 shadow block not found for extend file */
|
|
|
|
|
|
|
|
min_page = MAX((min_page + 1), Y.RDB$FILE_START);
|
|
|
|
add_sequence =
|
|
|
|
SDW_add_file(Y.RDB$FILE_NAME,
|
|
|
|
min_page,
|
|
|
|
Y.RDB$SHADOW_NUMBER);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* update the sequence number and bless the file entry as being
|
|
|
|
good */
|
|
|
|
|
|
|
|
if (!sequence || (Y.RDB$FILE_START && add_sequence))
|
|
|
|
{
|
|
|
|
MODIFY Y
|
|
|
|
Y.RDB$FILE_FLAGS |= FILE_shadow;
|
|
|
|
Y.RDB$FILE_SEQUENCE = sequence;
|
|
|
|
Y.RDB$FILE_START = min_page;
|
|
|
|
END_MODIFY;
|
|
|
|
sequence++;
|
|
|
|
}
|
|
|
|
|
|
|
|
END_FOR;
|
2002-11-17 01:13:59 +01:00
|
|
|
CMP_release(tdbb, (JRD_REQ)handle);
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void check_dependencies(TDBB tdbb,
|
|
|
|
TEXT * dpdo_name,
|
|
|
|
TEXT * field_name,
|
|
|
|
USHORT dpdo_type,
|
2002-11-17 01:13:59 +01:00
|
|
|
JRD_TRA transaction)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* c h e c k _ d e p e n d e n c i e s
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Check the dependency list for relation or relation.field
|
|
|
|
* before deleting such.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
DBB dbb;
|
|
|
|
BLK request;
|
|
|
|
USHORT dep_counts[obj_count], i;
|
|
|
|
STATUS obj_type;
|
|
|
|
|
|
|
|
SET_TDBB(tdbb);
|
|
|
|
dbb = tdbb->tdbb_database;
|
|
|
|
|
|
|
|
for (i = 0; i < (USHORT) obj_count; i++)
|
|
|
|
dep_counts[i] = 0;
|
|
|
|
|
|
|
|
if (field_name)
|
|
|
|
{
|
|
|
|
request = (BLK) CMP_find_request(tdbb, irq_ch_f_dpd, IRQ_REQUESTS);
|
|
|
|
|
|
|
|
FOR(REQUEST_HANDLE request)
|
|
|
|
DEP IN RDB$DEPENDENCIES
|
|
|
|
WITH DEP.RDB$DEPENDED_ON_NAME EQ dpdo_name
|
|
|
|
AND DEP.RDB$DEPENDED_ON_TYPE = dpdo_type
|
|
|
|
AND DEP.RDB$FIELD_NAME EQ field_name
|
|
|
|
REDUCED TO DEP.RDB$DEPENDENT_NAME
|
|
|
|
if (!REQUEST(irq_ch_f_dpd))
|
|
|
|
REQUEST(irq_ch_f_dpd) = (BLK)request;
|
|
|
|
|
|
|
|
/* If the found object is also being deleted, there's no dependency */
|
|
|
|
|
|
|
|
if (!find_depend_in_dfw(tdbb,
|
|
|
|
DEP.RDB$DEPENDENT_NAME,
|
|
|
|
DEP.RDB$DEPENDENT_TYPE,
|
|
|
|
0,
|
|
|
|
transaction))
|
|
|
|
{
|
|
|
|
dep_counts[DEP.RDB$DEPENDENT_TYPE]++;
|
|
|
|
}
|
|
|
|
END_FOR;
|
|
|
|
|
|
|
|
if (!REQUEST(irq_ch_f_dpd))
|
|
|
|
REQUEST(irq_ch_f_dpd) = (BLK)request;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
request = (BLK) CMP_find_request(tdbb, irq_ch_dpd, IRQ_REQUESTS);
|
|
|
|
|
|
|
|
FOR(REQUEST_HANDLE request)
|
|
|
|
DEP IN RDB$DEPENDENCIES
|
|
|
|
WITH DEP.RDB$DEPENDED_ON_NAME EQ dpdo_name
|
|
|
|
AND DEP.RDB$DEPENDED_ON_TYPE = dpdo_type
|
|
|
|
REDUCED TO DEP.RDB$DEPENDENT_NAME
|
|
|
|
|
|
|
|
if (!REQUEST(irq_ch_dpd))
|
|
|
|
REQUEST(irq_ch_dpd) = (BLK)request;
|
|
|
|
|
|
|
|
/* If the found object is also being deleted, there's no dependency */
|
|
|
|
|
|
|
|
if (!find_depend_in_dfw(tdbb,
|
|
|
|
DEP.RDB$DEPENDENT_NAME,
|
|
|
|
DEP.RDB$DEPENDENT_TYPE,
|
|
|
|
0,
|
|
|
|
transaction))
|
|
|
|
{
|
|
|
|
dep_counts[DEP.RDB$DEPENDENT_TYPE]++;
|
|
|
|
}
|
|
|
|
END_FOR;
|
|
|
|
|
|
|
|
if (!REQUEST(irq_ch_dpd))
|
|
|
|
REQUEST(irq_ch_dpd) = (BLK)request;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < obj_count; i++)
|
|
|
|
if (dep_counts[i])
|
|
|
|
{
|
|
|
|
switch (dpdo_type)
|
|
|
|
{
|
|
|
|
case obj_relation:
|
2001-07-29 19:42:23 +02:00
|
|
|
obj_type = gds_table_name;
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
case obj_procedure:
|
2001-07-29 19:42:23 +02:00
|
|
|
obj_type = gds_proc_name;
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
case obj_exception:
|
2001-07-29 19:42:23 +02:00
|
|
|
obj_type = gds_exception_name;
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
2002-06-29 15:03:13 +02:00
|
|
|
case obj_generator:
|
|
|
|
obj_type = gds_generator_name;
|
|
|
|
break;
|
|
|
|
case obj_udf:
|
|
|
|
obj_type = gds_udf_name;
|
|
|
|
break;
|
2001-05-23 15:26:42 +02:00
|
|
|
default:
|
|
|
|
assert(FALSE);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (field_name)
|
2001-07-29 19:42:23 +02:00
|
|
|
ERR_post( gds_no_meta_update,
|
|
|
|
gds_arg_gds, gds_no_delete, /* Msg353: can not delete */
|
|
|
|
gds_arg_gds, gds_field_name,
|
2001-05-23 15:26:42 +02:00
|
|
|
gds_arg_string, ERR_cstring(field_name),
|
2001-07-29 19:42:23 +02:00
|
|
|
gds_arg_gds, gds_dependency,
|
2001-05-23 15:26:42 +02:00
|
|
|
gds_arg_number, (SLONG) dep_counts[i],
|
|
|
|
0); /* Msg310: there are %ld dependencies */
|
|
|
|
else
|
2001-07-29 19:42:23 +02:00
|
|
|
ERR_post( gds_no_meta_update,
|
|
|
|
gds_arg_gds, gds_no_delete, /* can not delete */
|
2001-05-23 15:26:42 +02:00
|
|
|
gds_arg_gds, obj_type,
|
|
|
|
gds_arg_string, ERR_cstring(dpdo_name),
|
2001-07-29 19:42:23 +02:00
|
|
|
gds_arg_gds, gds_dependency,
|
2001-05-23 15:26:42 +02:00
|
|
|
gds_arg_number, (SLONG) dep_counts[i],
|
|
|
|
0); /* there are %ld dependencies */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void check_filename( TEXT * name, USHORT l)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* c h e c k _ f i l e n a m e
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Make sure that a file path doesn't contain an
|
|
|
|
* inet node name.
|
|
|
|
*
|
|
|
|
**************************************/
|
2002-10-24 11:01:44 +02:00
|
|
|
TEXT file_name[MAXPATHLEN], *p, *q;
|
2001-05-23 15:26:42 +02:00
|
|
|
BOOLEAN valid = TRUE;
|
|
|
|
|
|
|
|
l = MIN(l, sizeof(file_name) - 1);
|
|
|
|
for (p = file_name, q = name; l--; *p++ = *q++)
|
|
|
|
;
|
|
|
|
*p = 0;
|
|
|
|
for (p = file_name; *p; p++)
|
|
|
|
if (p[0] == ':' && p[1] == ':')
|
|
|
|
valid = FALSE;
|
|
|
|
|
|
|
|
if (!valid || ISC_check_if_remote(file_name, FALSE))
|
2001-07-29 19:42:23 +02:00
|
|
|
ERR_post(gds_no_meta_update, gds_arg_gds, gds_node_name_err, 0);
|
2001-05-23 15:26:42 +02:00
|
|
|
/* Msg305: A node name is not permitted in a secondary, shadow, or log file name */
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-07-05 17:00:26 +02:00
|
|
|
static bool formatsAreEqual(FMT old_format, FMT new_format)
|
2002-06-29 15:03:13 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Compare two format blocks
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
|
|
|
if ((old_format->fmt_length != new_format->fmt_length)
|
2002-07-05 17:00:26 +02:00
|
|
|
|| (old_format->fmt_count != new_format->fmt_count)) {
|
|
|
|
return false;
|
2002-06-29 15:03:13 +02:00
|
|
|
}
|
|
|
|
|
2002-07-05 17:00:26 +02:00
|
|
|
fmt::fmt_desc_iterator old_desc = old_format->fmt_desc.begin();
|
|
|
|
fmt::fmt_desc_iterator old_end = old_format->fmt_desc.end();
|
2002-06-29 15:03:13 +02:00
|
|
|
|
2002-07-05 17:00:26 +02:00
|
|
|
fmt::fmt_desc_iterator new_desc = old_format->fmt_desc.begin();
|
|
|
|
|
|
|
|
while (old_desc != old_end) {
|
2002-06-29 15:03:13 +02:00
|
|
|
if ((old_desc->dsc_dtype != new_desc->dsc_dtype)
|
|
|
|
|| (old_desc->dsc_scale != new_desc->dsc_scale)
|
|
|
|
|| (old_desc->dsc_length != new_desc->dsc_length)
|
|
|
|
|| (old_desc->dsc_sub_type != new_desc->dsc_sub_type)
|
|
|
|
|| (old_desc->dsc_flags != new_desc->dsc_flags)
|
2002-07-05 17:00:26 +02:00
|
|
|
|| (old_desc->dsc_address != new_desc->dsc_address)) {
|
|
|
|
return false;
|
2002-06-29 15:03:13 +02:00
|
|
|
}
|
2002-07-05 17:00:26 +02:00
|
|
|
|
|
|
|
new_desc++;
|
|
|
|
old_desc++;
|
2002-06-29 15:03:13 +02:00
|
|
|
}
|
|
|
|
|
2002-07-05 17:00:26 +02:00
|
|
|
return true;
|
2002-06-29 15:03:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
static bool compute_security( TDBB tdbb,
|
|
|
|
SSHORT phase,
|
|
|
|
DFW work,
|
2002-11-17 01:13:59 +01:00
|
|
|
JRD_TRA transaction)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* c o m p u t e _ s e c u r i t y
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* There was a change in a security class. Recompute everything
|
|
|
|
* it touches.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
DBB dbb;
|
|
|
|
BLK handle;
|
2001-07-12 08:32:05 +02:00
|
|
|
SCL s_class;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
SET_TDBB(tdbb);
|
|
|
|
dbb = tdbb->tdbb_database;
|
|
|
|
|
|
|
|
switch (phase)
|
|
|
|
{
|
|
|
|
case 1:
|
|
|
|
case 2:
|
2001-12-24 03:51:06 +01:00
|
|
|
return true;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
case 3:
|
|
|
|
/* Get security class. This may return NULL if it doesn't exist */
|
|
|
|
|
2001-07-12 08:32:05 +02:00
|
|
|
s_class = SCL_recompute_class(tdbb, work->dfw_name);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
handle = NULL;
|
|
|
|
FOR(REQUEST_HANDLE handle) X IN RDB$DATABASE
|
|
|
|
WITH X.RDB$SECURITY_CLASS EQ work->dfw_name
|
|
|
|
|
2001-07-12 08:32:05 +02:00
|
|
|
tdbb->tdbb_attachment->att_security_class = s_class;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
END_FOR;
|
2002-11-17 01:13:59 +01:00
|
|
|
CMP_release(tdbb, (JRD_REQ)handle);
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/**** OBSOLETE!!! Only security class name strings in relations and fields.
|
|
|
|
Note: fld_security_class --> fld_security_name
|
|
|
|
rel_security_class --> rel_security_name
|
|
|
|
|
|
|
|
handle = NULL;
|
|
|
|
for (request_handle handle) x in rdb$relation_fields
|
|
|
|
with x.rdb$security_class eq work->dfw_name
|
|
|
|
if (relation = MET_lookup_relation (tdbb, x.rdb$relation_name))
|
|
|
|
{
|
2002-06-29 15:03:13 +02:00
|
|
|
id = MET_lookup_field (tdbb, relation, x.rdb$field_name, 0);
|
2001-05-23 15:26:42 +02:00
|
|
|
if (field = MET_get_field (relation, id))
|
|
|
|
field->fld_security_class = class;
|
|
|
|
}
|
|
|
|
end_for;
|
|
|
|
CMP_release (tdbb, handle);
|
|
|
|
|
|
|
|
handle = NULL;
|
|
|
|
for (request_handle handle) x in rdb$relations
|
|
|
|
with x.rdb$security_class eq work->dfw_name
|
|
|
|
if (relation = MET_lookup_relation (tdbb, x.rdb$relation_name))
|
|
|
|
relation->rel_security_class = class;
|
|
|
|
end_for;
|
|
|
|
CMP_release (tdbb, handle);
|
|
|
|
|
|
|
|
****/
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
static bool create_index( TDBB tdbb,
|
|
|
|
SSHORT phase,
|
|
|
|
DFW work,
|
2002-11-17 01:13:59 +01:00
|
|
|
JRD_TRA transaction)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* c r e a t e _ i n d e x
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Create a new index or change the state of an index between active/inactive.
|
|
|
|
*
|
|
|
|
**************************************/
|
2001-12-24 03:51:06 +01:00
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
BLK request;
|
2002-11-17 01:13:59 +01:00
|
|
|
JRD_REL relation, partner_relation;
|
2001-05-23 15:26:42 +02:00
|
|
|
IDX idx;
|
|
|
|
int key_count;
|
|
|
|
float selectivity;
|
|
|
|
SSHORT text_type;
|
|
|
|
SSHORT collate;
|
|
|
|
BLK handle;
|
|
|
|
WIN window;
|
|
|
|
|
|
|
|
SET_TDBB(tdbb);
|
2001-12-24 03:51:06 +01:00
|
|
|
DBB dbb = tdbb->tdbb_database;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
switch (phase)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
handle = NULL;
|
|
|
|
|
|
|
|
/* Drop those indices at clean up time. */
|
|
|
|
FOR(REQUEST_HANDLE handle) IDXN IN RDB$INDICES CROSS
|
|
|
|
IREL IN RDB$RELATIONS OVER RDB$RELATION_NAME
|
|
|
|
WITH IDXN.RDB$INDEX_NAME EQ work->dfw_name
|
|
|
|
/* Views do not have indices */
|
|
|
|
if (IREL.RDB$VIEW_BLR.NULL)
|
|
|
|
{
|
|
|
|
relation = MET_lookup_relation(tdbb, IDXN.RDB$RELATION_NAME);
|
|
|
|
|
|
|
|
/* Fetch the root index page and mark MUST_WRITE, and then
|
|
|
|
delete the index. It will also clean the index slot. */
|
|
|
|
if (relation->rel_index_root)
|
|
|
|
{
|
|
|
|
if (work->dfw_id != MAX_IDX)
|
|
|
|
{
|
|
|
|
window.win_page = relation->rel_index_root;
|
|
|
|
window.win_flags = 0;
|
|
|
|
CCH_FETCH(tdbb, &window, LCK_write, pag_root);
|
|
|
|
CCH_MARK_MUST_WRITE(tdbb, &window);
|
|
|
|
BTR_delete_index(tdbb, &window, work->dfw_id);
|
|
|
|
work->dfw_id = MAX_IDX;
|
|
|
|
}
|
|
|
|
if (!IDXN.RDB$INDEX_ID.NULL)
|
|
|
|
{
|
|
|
|
MODIFY IDXN USING
|
|
|
|
IDXN.RDB$INDEX_ID.NULL = TRUE;
|
|
|
|
END_MODIFY;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
END_FOR;
|
|
|
|
|
2002-11-17 01:13:59 +01:00
|
|
|
CMP_release(tdbb, (JRD_REQ)handle);
|
2001-05-23 15:26:42 +02:00
|
|
|
CCH_release_exclusive(tdbb);
|
2001-12-24 03:51:06 +01:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
case 1:
|
|
|
|
case 2:
|
2001-12-24 03:51:06 +01:00
|
|
|
return true;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
case 3:
|
|
|
|
key_count = 0;
|
|
|
|
relation = NULL;
|
|
|
|
idx.idx_flags = 0;
|
|
|
|
|
|
|
|
/* Fetch the information necessary to create the index. On the first
|
|
|
|
time thru, check to see if the index already exists. If so, delete
|
|
|
|
it. If the index inactive flag is set, don't create the index */
|
|
|
|
|
|
|
|
request = (BLK) CMP_find_request(tdbb, irq_c_index, IRQ_REQUESTS);
|
|
|
|
|
|
|
|
FOR(REQUEST_HANDLE request)
|
|
|
|
IDX IN RDB$INDICES CROSS
|
|
|
|
SEG IN RDB$INDEX_SEGMENTS OVER RDB$INDEX_NAME CROSS
|
|
|
|
RFR IN RDB$RELATION_FIELDS OVER RDB$FIELD_NAME,
|
|
|
|
RDB$RELATION_NAME CROSS
|
|
|
|
FLD IN RDB$FIELDS CROSS
|
|
|
|
REL IN RDB$RELATIONS OVER RDB$RELATION_NAME WITH
|
|
|
|
FLD.RDB$FIELD_NAME EQ RFR.RDB$FIELD_SOURCE AND
|
|
|
|
IDX.RDB$INDEX_NAME EQ work->dfw_name
|
|
|
|
|
|
|
|
if (!REQUEST(irq_c_index))
|
|
|
|
REQUEST(irq_c_index) = (BLK)request;
|
|
|
|
|
|
|
|
if (!relation)
|
|
|
|
{
|
|
|
|
relation =
|
|
|
|
MET_lookup_relation_id(tdbb, REL.RDB$RELATION_ID, FALSE);
|
|
|
|
if (!relation)
|
|
|
|
{
|
2002-11-17 01:13:59 +01:00
|
|
|
EXE_unwind(tdbb, (JRD_REQ)request);
|
2001-07-29 19:42:23 +02:00
|
|
|
ERR_post(gds_no_meta_update,
|
|
|
|
gds_arg_gds, gds_idx_create_err,
|
2001-05-23 15:26:42 +02:00
|
|
|
gds_arg_string, ERR_cstring(work->dfw_name),
|
|
|
|
0);
|
|
|
|
/* Msg308: can't create index %s */
|
|
|
|
}
|
|
|
|
if (IDX.RDB$INDEX_ID && IDX.RDB$STATISTICS < 0.0)
|
|
|
|
{
|
|
|
|
MODIFY IDX
|
|
|
|
IDX.RDB$STATISTICS =
|
|
|
|
IDX_statistics( tdbb,
|
|
|
|
relation,
|
|
|
|
(USHORT)(IDX.RDB$INDEX_ID - 1));
|
|
|
|
END_MODIFY;
|
2002-11-17 01:13:59 +01:00
|
|
|
EXE_unwind(tdbb, (JRD_REQ)request);
|
2001-12-24 03:51:06 +01:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
if (IDX.RDB$INDEX_ID)
|
|
|
|
{
|
|
|
|
IDX_delete_index( tdbb,
|
|
|
|
relation,
|
|
|
|
(USHORT)(IDX.RDB$INDEX_ID - 1));
|
|
|
|
MODIFY IDX
|
|
|
|
IDX.RDB$INDEX_ID.NULL = TRUE;
|
|
|
|
END_MODIFY;
|
|
|
|
}
|
|
|
|
if (IDX.RDB$INDEX_INACTIVE)
|
|
|
|
{
|
2002-11-17 01:13:59 +01:00
|
|
|
EXE_unwind(tdbb, (JRD_REQ)request);
|
2001-12-24 03:51:06 +01:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
idx.idx_count = IDX.RDB$SEGMENT_COUNT;
|
|
|
|
if (!idx.idx_count || idx.idx_count > 16)
|
|
|
|
{
|
2002-11-17 01:13:59 +01:00
|
|
|
EXE_unwind(tdbb, (JRD_REQ)request);
|
2001-05-23 15:26:42 +02:00
|
|
|
if (!idx.idx_count)
|
2001-07-29 19:42:23 +02:00
|
|
|
ERR_post(gds_no_meta_update,
|
|
|
|
gds_arg_gds, gds_idx_seg_err,
|
2001-05-23 15:26:42 +02:00
|
|
|
gds_arg_string, ERR_cstring(work->dfw_name),
|
|
|
|
0);
|
|
|
|
/* Msg304: segment count of 0 defined for index %s */
|
|
|
|
else
|
2001-07-29 19:42:23 +02:00
|
|
|
ERR_post(gds_no_meta_update,
|
|
|
|
gds_arg_gds, gds_idx_key_err,
|
2001-05-23 15:26:42 +02:00
|
|
|
gds_arg_string, ERR_cstring(work->dfw_name),
|
|
|
|
0);
|
|
|
|
/* Msg311: too many keys defined for index %s */
|
|
|
|
}
|
|
|
|
if (IDX.RDB$UNIQUE_FLAG)
|
|
|
|
idx.idx_flags |= idx_unique;
|
|
|
|
if (IDX.RDB$INDEX_TYPE == 1)
|
|
|
|
idx.idx_flags |= idx_descending;
|
|
|
|
if (!IDX.RDB$FOREIGN_KEY.NULL)
|
|
|
|
idx.idx_flags |= idx_foreign;
|
2002-09-01 17:49:03 +02:00
|
|
|
|
|
|
|
BLK rc_request = NULL;
|
|
|
|
|
|
|
|
FOR(REQUEST_HANDLE rc_request)
|
|
|
|
RC IN RDB$RELATION_CONSTRAINTS WITH
|
|
|
|
RC.RDB$INDEX_NAME EQ work->dfw_name AND
|
|
|
|
RC.RDB$CONSTRAINT_TYPE = "PRIMARY KEY"
|
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
idx.idx_flags |= idx_primary;
|
2002-09-01 17:49:03 +02:00
|
|
|
|
|
|
|
END_FOR;
|
|
|
|
|
2002-11-17 01:13:59 +01:00
|
|
|
CMP_release(tdbb, (JRD_REQ)rc_request);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (++key_count > idx.idx_count ||
|
|
|
|
SEG.RDB$FIELD_POSITION > idx.idx_count ||
|
|
|
|
FLD.RDB$FIELD_TYPE == blr_blob ||
|
|
|
|
!FLD.RDB$DIMENSIONS.NULL)
|
|
|
|
{
|
2002-11-17 01:13:59 +01:00
|
|
|
EXE_unwind(tdbb, (JRD_REQ)request);
|
2001-05-23 15:26:42 +02:00
|
|
|
if (key_count > idx.idx_count)
|
2001-07-29 19:42:23 +02:00
|
|
|
ERR_post(gds_no_meta_update,
|
|
|
|
gds_arg_gds, gds_idx_key_err,
|
2001-05-23 15:26:42 +02:00
|
|
|
gds_arg_string, ERR_cstring(work->dfw_name),
|
|
|
|
0);
|
|
|
|
/* Msg311: too many keys defined for index %s */
|
|
|
|
else if (SEG.RDB$FIELD_POSITION > idx.idx_count)
|
2001-07-29 19:42:23 +02:00
|
|
|
ERR_post(gds_no_meta_update,
|
|
|
|
gds_arg_gds, gds_inval_key_posn,
|
2001-05-23 15:26:42 +02:00
|
|
|
/* Msg358: invalid key position */
|
2001-07-29 19:42:23 +02:00
|
|
|
gds_arg_gds, gds_field_name,
|
2001-05-23 15:26:42 +02:00
|
|
|
gds_arg_string, ERR_cstring(RFR.RDB$FIELD_NAME),
|
2001-07-29 19:42:23 +02:00
|
|
|
gds_arg_gds, gds_index_name,
|
2001-05-23 15:26:42 +02:00
|
|
|
gds_arg_string, ERR_cstring(work->dfw_name),
|
|
|
|
0);
|
|
|
|
else if (FLD.RDB$FIELD_TYPE == blr_blob)
|
2001-07-29 19:42:23 +02:00
|
|
|
ERR_post(gds_no_meta_update,
|
|
|
|
gds_arg_gds, gds_blob_idx_err,
|
2001-05-23 15:26:42 +02:00
|
|
|
gds_arg_string, ERR_cstring(work->dfw_name),
|
|
|
|
0);
|
|
|
|
/* Msg350: attempt to index blob column in index %s */
|
|
|
|
else
|
2001-07-29 19:42:23 +02:00
|
|
|
ERR_post(gds_no_meta_update,
|
|
|
|
gds_arg_gds, gds_array_idx_err,
|
2001-05-23 15:26:42 +02:00
|
|
|
gds_arg_string, ERR_cstring(work->dfw_name),
|
|
|
|
0);
|
|
|
|
/* Msg351: attempt to index array column in index %s */
|
|
|
|
}
|
|
|
|
|
|
|
|
idx.idx_rpt[SEG.RDB$FIELD_POSITION].idx_field = RFR.RDB$FIELD_ID;
|
|
|
|
|
|
|
|
if (FLD.RDB$CHARACTER_SET_ID.NULL)
|
|
|
|
FLD.RDB$CHARACTER_SET_ID = CS_NONE;
|
|
|
|
|
|
|
|
if (!RFR.RDB$COLLATION_ID.NULL)
|
|
|
|
collate = RFR.RDB$COLLATION_ID;
|
|
|
|
else if (!FLD.RDB$COLLATION_ID.NULL)
|
|
|
|
collate = FLD.RDB$COLLATION_ID;
|
|
|
|
else
|
|
|
|
collate = COLLATE_NONE;
|
|
|
|
|
|
|
|
text_type =
|
|
|
|
INTL_CS_COLL_TO_TTYPE(FLD.RDB$CHARACTER_SET_ID, collate);
|
|
|
|
idx.idx_rpt[SEG.RDB$FIELD_POSITION].idx_itype =
|
|
|
|
DFW_assign_index_type(work,
|
|
|
|
gds_cvt_blr_dtype[FLD.RDB$FIELD_TYPE],
|
|
|
|
text_type);
|
|
|
|
END_FOR;
|
|
|
|
|
|
|
|
if (!REQUEST(irq_c_index))
|
|
|
|
REQUEST(irq_c_index) = (BLK)request;
|
|
|
|
|
|
|
|
if (key_count != idx.idx_count)
|
2001-07-29 19:42:23 +02:00
|
|
|
ERR_post(gds_no_meta_update,
|
|
|
|
gds_arg_gds, gds_key_field_err,
|
2001-05-23 15:26:42 +02:00
|
|
|
gds_arg_string, ERR_cstring(work->dfw_name),
|
|
|
|
0);
|
|
|
|
/* Msg352: too few key columns found for index %s (incorrect column name?) */
|
|
|
|
if (!relation)
|
2001-07-29 19:42:23 +02:00
|
|
|
ERR_post(gds_no_meta_update,
|
|
|
|
gds_arg_gds, gds_idx_create_err,
|
2001-05-23 15:26:42 +02:00
|
|
|
gds_arg_string, ERR_cstring(work->dfw_name),
|
|
|
|
0);
|
|
|
|
/* Msg308: can't create index %s */
|
|
|
|
|
|
|
|
/* Make sure the relation info is all current */
|
|
|
|
|
|
|
|
MET_scan_relation(tdbb, relation);
|
|
|
|
|
|
|
|
if (relation->rel_view_rse)
|
2001-07-29 19:42:23 +02:00
|
|
|
ERR_post(gds_no_meta_update,
|
|
|
|
gds_arg_gds, gds_idx_create_err,
|
2001-05-23 15:26:42 +02:00
|
|
|
gds_arg_string, ERR_cstring(work->dfw_name),
|
|
|
|
0);
|
|
|
|
/* Msg308: can't create index %s */
|
|
|
|
|
|
|
|
/* Actually create the index */
|
|
|
|
|
2002-11-17 01:13:59 +01:00
|
|
|
partner_relation = (JRD_REL) NULL_PTR;
|
2001-05-23 15:26:42 +02:00
|
|
|
if (idx.idx_flags & idx_foreign)
|
|
|
|
{
|
|
|
|
/* Get an exclusive lock on the database if the index being
|
|
|
|
defined enforces a foreign key constraint. This will prevent
|
|
|
|
the constraint from being violated during index construction. */
|
|
|
|
|
2001-07-12 08:32:05 +02:00
|
|
|
if (MET_lookup_partner(tdbb, relation, &idx, (UCHAR*) work->dfw_name) &&
|
2001-05-23 15:26:42 +02:00
|
|
|
(partner_relation =
|
|
|
|
MET_lookup_relation_id( tdbb,
|
|
|
|
idx.idx_primary_relation,
|
|
|
|
TRUE)) &&
|
|
|
|
!CCH_exclusive(tdbb, LCK_EX, LCK_NO_WAIT))
|
|
|
|
{
|
2001-07-29 19:42:23 +02:00
|
|
|
ERR_post(gds_no_meta_update,
|
|
|
|
gds_arg_gds, gds_obj_in_use,
|
2001-05-23 15:26:42 +02:00
|
|
|
gds_arg_string, partner_relation->rel_name,
|
|
|
|
0);
|
2002-06-29 15:03:13 +02:00
|
|
|
|
|
|
|
/* CVC: Currently, the server doesn't enforce FK creation more than at DYN level.
|
|
|
|
If DYN is bypassed, then FK creation succeeds and operation will fail at run-time.
|
|
|
|
The aim is to check REFERENCES at DDL time instead of DML time and behave accordingly
|
|
|
|
to ANSI SQL rules for REFERENCES rights.
|
|
|
|
For testing purposes, I'm calling SCL_check_index, although most of the DFW ops are
|
|
|
|
carried using internal metadata structures that are refreshed from system tables. */
|
|
|
|
|
|
|
|
if (partner_relation)
|
|
|
|
{
|
|
|
|
/* Don't bother if the master's owner is the same than the detail's owner.
|
|
|
|
If both tables aren't defined in the same session, partner_relation->rel_owner_name
|
|
|
|
won't be loaded hence, we need to be careful about null pointers. */
|
|
|
|
|
|
|
|
if (!relation->rel_owner_name || !partner_relation->rel_owner_name
|
|
|
|
|| strcmp(relation->rel_owner_name, partner_relation->rel_owner_name))
|
|
|
|
SCL_check_index(tdbb, partner_relation->rel_name, idx.idx_id + 1, SCL_sql_references);
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(work->dfw_id == MAX_IDX);
|
|
|
|
IDX_create_index( tdbb,
|
|
|
|
relation,
|
|
|
|
&idx,
|
2001-07-12 08:32:05 +02:00
|
|
|
(UCHAR*) work->dfw_name,
|
2001-05-23 15:26:42 +02:00
|
|
|
&work->dfw_id,
|
|
|
|
transaction,
|
|
|
|
&selectivity);
|
|
|
|
assert(work->dfw_id == idx.idx_id);
|
|
|
|
DFW_update_index(work, idx.idx_id, selectivity);
|
|
|
|
|
|
|
|
if (partner_relation)
|
|
|
|
{
|
|
|
|
relation->rel_flags |= REL_check_partners;
|
|
|
|
partner_relation->rel_flags |= REL_check_partners;
|
|
|
|
CCH_release_exclusive(tdbb);
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-11-17 01:13:59 +01:00
|
|
|
static bool create_log(TDBB tdbb, SSHORT phase, DFW work, JRD_TRA transaction)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* c r e a t e _ l o g
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Do work associated with the addition of records to RDB$LOG_FILES
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
BLK handle;
|
2002-10-24 11:01:44 +02:00
|
|
|
TEXT temp[MAXPATHLEN];
|
2001-05-23 15:26:42 +02:00
|
|
|
DBB dbb;
|
|
|
|
|
|
|
|
SET_TDBB(tdbb);
|
|
|
|
dbb = tdbb->tdbb_database;
|
|
|
|
|
|
|
|
switch (phase)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
CCH_release_exclusive(tdbb);
|
2001-12-24 03:51:06 +01:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
case 1:
|
|
|
|
case 2:
|
2001-12-24 03:51:06 +01:00
|
|
|
return true;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
case 3:
|
|
|
|
if (CCH_exclusive(tdbb, LCK_EX, WAIT_PERIOD))
|
2001-12-24 03:51:06 +01:00
|
|
|
return true;
|
2001-05-23 15:26:42 +02:00
|
|
|
else
|
|
|
|
{
|
2001-07-29 19:42:23 +02:00
|
|
|
ERR_post(gds_no_meta_update,
|
|
|
|
gds_arg_gds, gds_lock_timeout,
|
|
|
|
gds_arg_gds, gds_obj_in_use,
|
2001-05-23 15:26:42 +02:00
|
|
|
gds_arg_string, ERR_cstring(dbb->dbb_file->fil_string),
|
|
|
|
0);
|
2001-12-24 03:51:06 +01:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
case 4:
|
|
|
|
|
|
|
|
handle = NULL;
|
|
|
|
if (shadow_defined(tdbb))
|
2001-12-24 03:51:06 +01:00
|
|
|
{
|
2001-07-29 19:42:23 +02:00
|
|
|
ERR_post(gds_no_meta_update,
|
|
|
|
gds_arg_gds, gds_wal_shadow_err,
|
2001-05-23 15:26:42 +02:00
|
|
|
0);
|
2001-12-24 03:51:06 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
/* Msg309: Write-Ahead Log with Shadowing configuration not allowed */
|
|
|
|
check_filename(work->dfw_name, work->dfw_name_length);
|
|
|
|
|
|
|
|
FOR(REQUEST_HANDLE handle) X IN RDB$LOG_FILES
|
|
|
|
|
|
|
|
ISC_expand_filename(X.RDB$FILE_NAME, 0, temp);
|
|
|
|
|
|
|
|
MODIFY X USING
|
|
|
|
strcpy(X.RDB$FILE_NAME, temp);
|
|
|
|
END_MODIFY;
|
|
|
|
END_FOR;
|
|
|
|
|
2002-11-17 01:13:59 +01:00
|
|
|
CMP_release(tdbb, (JRD_REQ)handle);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
transaction->tra_flags |= TRA_add_log;
|
|
|
|
PAG_modify_log(transaction->tra_number, TRA_add_log);
|
2001-12-24 03:51:06 +01:00
|
|
|
return true;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
case 5:
|
|
|
|
CCH_release_exclusive(tdbb);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
static bool create_procedure( TDBB tdbb,
|
2001-05-23 15:26:42 +02:00
|
|
|
SSHORT phase,
|
|
|
|
DFW work,
|
2002-11-17 01:13:59 +01:00
|
|
|
JRD_TRA transaction)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* c r e a t e _ p r o c e d u r e
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Create a new procedure.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
|
|
|
SET_TDBB(tdbb);
|
|
|
|
|
|
|
|
switch (phase)
|
|
|
|
{
|
|
|
|
case 1:
|
|
|
|
case 2:
|
2001-12-24 03:51:06 +01:00
|
|
|
return true;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
case 3:
|
2001-12-24 03:51:06 +01:00
|
|
|
{
|
|
|
|
get_procedure_dependencies(work);
|
2002-11-17 01:13:59 +01:00
|
|
|
JRD_PRC procedure = MET_lookup_procedure(tdbb, work->dfw_name, FALSE);
|
2001-12-24 03:51:06 +01:00
|
|
|
if (!procedure) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
procedure->prc_flags |= PRC_create;
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
static bool create_relation(TDBB tdbb,
|
|
|
|
SSHORT phase,
|
|
|
|
DFW work,
|
2002-11-17 01:13:59 +01:00
|
|
|
JRD_TRA transaction)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* c r e a t e _ r e l a t i o n
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Create a new relation.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
DBB dbb;
|
|
|
|
BLK request;
|
2002-11-17 01:13:59 +01:00
|
|
|
JRD_REL relation;
|
2001-05-23 15:26:42 +02:00
|
|
|
USHORT rel_id, external_flag;
|
|
|
|
GDS__QUAD blob_id;
|
|
|
|
BLK handle;
|
|
|
|
LCK lock;
|
|
|
|
USHORT major_version, minor_original, local_min_relation_id;
|
|
|
|
|
|
|
|
|
|
|
|
SET_TDBB(tdbb);
|
|
|
|
dbb = tdbb->tdbb_database;
|
|
|
|
|
|
|
|
major_version = (SSHORT) dbb->dbb_ods_version;
|
|
|
|
minor_original = (SSHORT) dbb->dbb_minor_original;
|
|
|
|
|
|
|
|
if (ENCODE_ODS(major_version, minor_original) < ODS_9_0)
|
|
|
|
local_min_relation_id = MIN_RELATION_ID;
|
|
|
|
else
|
|
|
|
local_min_relation_id = USER_DEF_REL_INIT_ID;
|
|
|
|
|
|
|
|
switch (phase)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
if (work->dfw_lock)
|
|
|
|
{
|
|
|
|
LCK_release(tdbb, work->dfw_lock);
|
2001-12-24 03:51:06 +01:00
|
|
|
delete work->dfw_lock;
|
2001-05-23 15:26:42 +02:00
|
|
|
work->dfw_lock = NULL;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 1:
|
|
|
|
case 2:
|
2001-12-24 03:51:06 +01:00
|
|
|
return true;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
case 3:
|
|
|
|
/* Take a relation lock on rel id -1 before actually
|
|
|
|
generating a relation id. */
|
|
|
|
|
2002-09-25 19:12:16 +02:00
|
|
|
work->dfw_lock = lock = FB_NEW_RPT(*tdbb->tdbb_default, sizeof(SLONG)) lck;
|
2001-05-23 15:26:42 +02:00
|
|
|
lock->lck_dbb = dbb;
|
|
|
|
lock->lck_attachment = tdbb->tdbb_attachment;
|
|
|
|
lock->lck_length = sizeof(SLONG);
|
|
|
|
lock->lck_key.lck_long = -1;
|
|
|
|
lock->lck_type = LCK_relation;
|
|
|
|
lock->lck_owner_handle = LCK_get_owner_handle(tdbb, lock->lck_type);
|
|
|
|
lock->lck_parent = dbb->dbb_lock;
|
|
|
|
lock->lck_owner = (BLK) tdbb->tdbb_attachment;
|
|
|
|
|
|
|
|
LCK_lock_non_blocking(tdbb, lock, LCK_EX, LCK_WAIT);
|
|
|
|
|
|
|
|
/* Assign a relation ID and dbkey length to the new relation.
|
|
|
|
Probe the candidate relation ID returned from the system
|
|
|
|
relation RDB$DATABASE to make sure it isn't already assigned.
|
|
|
|
This can happen from nefarious manipulation of RDB$DATABASE
|
|
|
|
or wraparound of the next relation ID. Keep looking for a
|
|
|
|
usable relation ID until the search space is exhausted. */
|
|
|
|
|
|
|
|
rel_id = 0;
|
|
|
|
request = (BLK) CMP_find_request(tdbb, irq_c_relation, IRQ_REQUESTS);
|
|
|
|
|
|
|
|
FOR(REQUEST_HANDLE request)
|
|
|
|
X IN RDB$DATABASE CROSS Y IN RDB$RELATIONS WITH
|
|
|
|
Y.RDB$RELATION_NAME EQ work->dfw_name
|
|
|
|
if (!REQUEST(irq_c_relation))
|
|
|
|
REQUEST(irq_c_relation) = (BLK)request;
|
|
|
|
|
|
|
|
blob_id = Y.RDB$VIEW_BLR;
|
|
|
|
external_flag = Y.RDB$EXTERNAL_FILE[0];
|
|
|
|
|
|
|
|
MODIFY X USING
|
|
|
|
rel_id = X.RDB$RELATION_ID;
|
|
|
|
|
|
|
|
if (rel_id < local_min_relation_id ||
|
|
|
|
rel_id > MAX_RELATION_ID)
|
|
|
|
{
|
|
|
|
rel_id = X.RDB$RELATION_ID = local_min_relation_id;
|
|
|
|
}
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
while ( (relation = MET_lookup_relation_id(tdbb, rel_id++, FALSE)) )
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
if (rel_id < local_min_relation_id ||
|
|
|
|
rel_id > MAX_RELATION_ID)
|
|
|
|
{
|
|
|
|
rel_id = local_min_relation_id;
|
|
|
|
}
|
|
|
|
if (rel_id == X.RDB$RELATION_ID)
|
|
|
|
{
|
2002-11-17 01:13:59 +01:00
|
|
|
EXE_unwind(tdbb, (JRD_REQ)request);
|
2001-07-29 19:42:23 +02:00
|
|
|
ERR_post(gds_no_meta_update,
|
|
|
|
gds_arg_gds, gds_table_name,
|
2001-05-23 15:26:42 +02:00
|
|
|
gds_arg_string, ERR_cstring(work->dfw_name),
|
2001-07-29 19:42:23 +02:00
|
|
|
gds_arg_gds, gds_imp_exc,
|
2001-05-23 15:26:42 +02:00
|
|
|
0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
X.RDB$RELATION_ID = (rel_id > MAX_RELATION_ID) ?
|
|
|
|
local_min_relation_id : rel_id;
|
|
|
|
MODIFY Y USING
|
|
|
|
Y.RDB$RELATION_ID = --rel_id;
|
|
|
|
if (NULL_BLOB(blob_id))
|
|
|
|
Y.RDB$DBKEY_LENGTH = 8;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* update the dbkey length to include each of the base
|
|
|
|
relations */
|
|
|
|
|
|
|
|
handle = NULL;
|
|
|
|
Y.RDB$DBKEY_LENGTH = 0;
|
|
|
|
FOR(REQUEST_HANDLE handle)
|
|
|
|
Z IN RDB$VIEW_RELATIONS CROSS
|
|
|
|
R IN RDB$RELATIONS OVER RDB$RELATION_NAME WITH
|
|
|
|
Z.RDB$VIEW_NAME = work->dfw_name
|
|
|
|
|
|
|
|
Y.RDB$DBKEY_LENGTH += R.RDB$DBKEY_LENGTH;
|
|
|
|
|
|
|
|
END_FOR;
|
2002-11-17 01:13:59 +01:00
|
|
|
CMP_release(tdbb, (JRD_REQ)handle);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
END_MODIFY
|
|
|
|
END_MODIFY
|
|
|
|
END_FOR;
|
|
|
|
|
|
|
|
LCK_release(tdbb, lock);
|
2001-12-24 03:51:06 +01:00
|
|
|
delete lock;
|
2001-05-23 15:26:42 +02:00
|
|
|
work->dfw_lock = NULL;
|
|
|
|
|
|
|
|
if (!REQUEST(irq_c_relation))
|
2001-07-12 08:32:05 +02:00
|
|
|
REQUEST(irq_c_relation) = (BLK) request;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* If relation wasn't found, don't do anymore. This can happen
|
|
|
|
when the relation is created and deleted in the same transaction. */
|
|
|
|
|
|
|
|
if (!rel_id)
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* get the relation and flag it to check for dependencies
|
|
|
|
in the view blr (if it exists) and any computed fields */
|
|
|
|
|
|
|
|
relation = MET_relation(tdbb, rel_id);
|
|
|
|
relation->rel_flags |= REL_get_dependencies;
|
|
|
|
|
|
|
|
/* if this is not a view, create the relation */
|
|
|
|
|
|
|
|
if (NULL_BLOB(blob_id))
|
|
|
|
{
|
|
|
|
if (!external_flag)
|
|
|
|
DPM_create_relation(tdbb, relation);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-11-17 01:13:59 +01:00
|
|
|
static bool create_trigger(TDBB tdbb, SSHORT phase, DFW work, JRD_TRA transaction)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* c r e a t e _ t r i g g e r
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Perform required actions on creation of trigger.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
|
|
|
SET_TDBB(tdbb);
|
|
|
|
|
|
|
|
switch (phase)
|
|
|
|
{
|
|
|
|
case 1:
|
|
|
|
case 2:
|
2001-12-24 03:51:06 +01:00
|
|
|
return true;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
case 3:
|
|
|
|
get_trigger_dependencies(work);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
static bool delete_exception( TDBB tdbb,
|
|
|
|
SSHORT phase,
|
|
|
|
DFW work,
|
2002-11-17 01:13:59 +01:00
|
|
|
JRD_TRA transaction)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* d e l e t e _ e x c e p t i o n
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Check if it is allowable to delete
|
|
|
|
* an exception, and if so, clean up after it.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
|
|
|
SET_TDBB(tdbb);
|
|
|
|
|
|
|
|
switch (phase)
|
|
|
|
{
|
|
|
|
case 0:
|
2001-12-24 03:51:06 +01:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
case 1:
|
2001-07-12 08:32:05 +02:00
|
|
|
check_dependencies(tdbb, work->dfw_name, (TEXT*)NULL_PTR,
|
2001-05-23 15:26:42 +02:00
|
|
|
obj_exception, transaction);
|
2001-12-24 03:51:06 +01:00
|
|
|
return true;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
case 2:
|
2001-12-24 03:51:06 +01:00
|
|
|
return true;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
case 3:
|
2001-12-24 03:51:06 +01:00
|
|
|
return true;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
case 4:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-11-17 01:13:59 +01:00
|
|
|
static bool delete_generator(TDBB tdbb, SSHORT phase, DFW work, JRD_TRA transaction)
|
2002-06-29 15:03:13 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* d e l e t e _ g e n e r a t o r
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Check if it is allowable to delete
|
|
|
|
* a generator, and if so, clean up after it.
|
|
|
|
* CVC: This function was modelled after delete_exception.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
|
|
|
SET_TDBB(tdbb);
|
|
|
|
|
|
|
|
switch (phase)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
return false;
|
|
|
|
case 1:
|
|
|
|
check_dependencies(tdbb, work->dfw_name, 0,
|
|
|
|
obj_generator, transaction);
|
|
|
|
return true;
|
|
|
|
case 2:
|
|
|
|
return true;
|
|
|
|
case 3:
|
|
|
|
return true;
|
|
|
|
case 4:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-11-17 01:13:59 +01:00
|
|
|
static bool delete_udf(TDBB tdbb, SSHORT phase, DFW work, JRD_TRA transaction)
|
2002-06-29 15:03:13 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* d e l e t e _ u d f
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Check if it is allowable to delete
|
|
|
|
* an udf, and if so, clean up after it.
|
|
|
|
* CVC: This function was modelled after delete_exception.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
|
|
|
SET_TDBB(tdbb);
|
|
|
|
|
|
|
|
switch (phase)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
return false;
|
|
|
|
case 1:
|
|
|
|
check_dependencies(tdbb, work->dfw_name, 0,
|
|
|
|
obj_udf, transaction);
|
|
|
|
return true;
|
|
|
|
case 2:
|
|
|
|
return true;
|
|
|
|
case 3:
|
|
|
|
return true;
|
|
|
|
case 4:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
static bool delete_field( TDBB tdbb,
|
|
|
|
SSHORT phase,
|
|
|
|
DFW work,
|
2002-11-17 01:13:59 +01:00
|
|
|
JRD_TRA transaction)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* d e l e t e _ f i e l d
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* This whole routine exists just to
|
|
|
|
* return an error if someone attempts to
|
|
|
|
* delete a global field that is in use
|
|
|
|
*
|
|
|
|
**************************************/
|
2001-12-24 03:51:06 +01:00
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
int field_count;
|
|
|
|
BLK handle;
|
|
|
|
|
|
|
|
SET_TDBB(tdbb);
|
2001-12-24 03:51:06 +01:00
|
|
|
DBB dbb = tdbb->tdbb_database;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
switch (phase)
|
|
|
|
{
|
|
|
|
case 1:
|
|
|
|
/* Look up the field in RFR. If we can't find the field,
|
|
|
|
go ahead with the delete. */
|
|
|
|
|
|
|
|
handle = NULL;
|
|
|
|
field_count = 0;
|
|
|
|
|
|
|
|
FOR(REQUEST_HANDLE handle)
|
|
|
|
RFR IN RDB$RELATION_FIELDS CROSS
|
|
|
|
REL IN RDB$RELATIONS
|
|
|
|
OVER RDB$RELATION_NAME
|
|
|
|
WITH RFR.RDB$FIELD_SOURCE EQ work->dfw_name
|
|
|
|
/* If the rfr field is also being deleted, there's no dependency */
|
|
|
|
if (!find_depend_in_dfw(tdbb,
|
|
|
|
RFR.RDB$FIELD_NAME,
|
|
|
|
obj_computed,
|
|
|
|
REL.RDB$RELATION_ID,
|
|
|
|
transaction))
|
|
|
|
{
|
|
|
|
field_count++;
|
|
|
|
}
|
|
|
|
END_FOR;
|
2002-11-17 01:13:59 +01:00
|
|
|
CMP_release(tdbb, (JRD_REQ)handle);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (field_count)
|
2001-07-29 19:42:23 +02:00
|
|
|
ERR_post(gds_no_meta_update,
|
|
|
|
gds_arg_gds, gds_no_delete, /* Msg353: can not delete */
|
|
|
|
gds_arg_gds, gds_field_name,
|
2001-05-23 15:26:42 +02:00
|
|
|
gds_arg_string, ERR_cstring(work->dfw_name),
|
2001-07-29 19:42:23 +02:00
|
|
|
gds_arg_gds, gds_dependency,
|
2001-05-23 15:26:42 +02:00
|
|
|
gds_arg_number, (SLONG) field_count,
|
|
|
|
0); /* Msg310: there are %ld dependencies */
|
|
|
|
|
|
|
|
case 2:
|
2001-12-24 03:51:06 +01:00
|
|
|
return true;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
case 3:
|
|
|
|
MET_delete_dependencies(tdbb, work->dfw_name, obj_computed);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-11-17 01:13:59 +01:00
|
|
|
static bool delete_global(TDBB tdbb, SSHORT phase, DFW work, JRD_TRA transaction)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* d e l e t e _ g l o b a l
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* If a local field has been deleted,
|
|
|
|
* check to see if its global field
|
|
|
|
* is computed. If so, delete all its
|
|
|
|
* dependencies under the assumption
|
|
|
|
* that a global computed field has only
|
|
|
|
* one local field.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
DBB dbb;
|
|
|
|
BLK handle;
|
|
|
|
|
|
|
|
SET_TDBB(tdbb);
|
|
|
|
dbb = tdbb->tdbb_database;
|
|
|
|
|
|
|
|
switch (phase)
|
|
|
|
{
|
|
|
|
case 1:
|
|
|
|
case 2:
|
2001-12-24 03:51:06 +01:00
|
|
|
return true;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
case 3:
|
|
|
|
handle = NULL;
|
|
|
|
FOR(REQUEST_HANDLE handle)
|
|
|
|
FLD IN RDB$FIELDS WITH
|
|
|
|
FLD.RDB$FIELD_NAME EQ work->dfw_name AND
|
|
|
|
FLD.RDB$COMPUTED_BLR NOT MISSING
|
|
|
|
|
|
|
|
MET_delete_dependencies(tdbb, work->dfw_name, obj_computed);
|
|
|
|
|
|
|
|
END_FOR;
|
2002-11-17 01:13:59 +01:00
|
|
|
CMP_release(tdbb, (JRD_REQ)handle);
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-11-17 01:13:59 +01:00
|
|
|
static bool delete_index(TDBB tdbb, SSHORT phase, DFW work, JRD_TRA transaction)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* d e l e t e _ i n d e x
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
IDL index, *ptr;
|
|
|
|
IDB index_block, *iptr;
|
2002-11-17 01:13:59 +01:00
|
|
|
JRD_REL relation;
|
2001-05-23 15:26:42 +02:00
|
|
|
USHORT id, wait;
|
|
|
|
|
|
|
|
SET_TDBB(tdbb);
|
|
|
|
|
|
|
|
switch (phase)
|
|
|
|
{
|
|
|
|
case 0:
|
2001-12-24 03:51:06 +01:00
|
|
|
relation = MET_lookup_relation(tdbb, work->dfw_name);
|
|
|
|
if (!relation) {
|
|
|
|
return false;
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
id = work->dfw_id - 1;
|
2001-12-24 03:51:06 +01:00
|
|
|
index = CMP_get_index_lock(tdbb, relation, id);
|
|
|
|
if (index) {
|
|
|
|
if (!index->idl_count) {
|
2001-05-23 15:26:42 +02:00
|
|
|
LCK_release(tdbb, index->idl_lock);
|
2001-12-24 03:51:06 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
case 1:
|
|
|
|
case 2:
|
2001-12-24 03:51:06 +01:00
|
|
|
return true;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
case 3:
|
|
|
|
/* Look up the relation. If we can't find the relation,
|
|
|
|
don't worry about the index. */
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
relation = MET_lookup_relation(tdbb, work->dfw_name);
|
|
|
|
if (!relation) {
|
|
|
|
return false;
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* Make sure nobody is currently using the index */
|
|
|
|
|
|
|
|
id = work->dfw_id - 1;
|
2001-12-24 03:51:06 +01:00
|
|
|
index = CMP_get_index_lock(tdbb, relation, id);
|
|
|
|
if (index)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
wait = (transaction->tra_flags & TRA_nowait) ? FALSE : TRUE;
|
2002-09-28 00:59:24 +02:00
|
|
|
// Try to clear trigger cache to release lock
|
|
|
|
if (index->idl_count)
|
2002-10-05 00:08:43 +02:00
|
|
|
MET_clear_cache(tdbb, NULL);
|
2001-05-23 15:26:42 +02:00
|
|
|
if (index->idl_count ||
|
|
|
|
!LCK_lock_non_blocking(tdbb, index->idl_lock, LCK_EX, wait))
|
|
|
|
{
|
2001-07-29 19:42:23 +02:00
|
|
|
ERR_post(gds_no_meta_update,
|
|
|
|
gds_arg_gds, gds_obj_in_use,
|
2001-05-23 15:26:42 +02:00
|
|
|
gds_arg_string, "INDEX",
|
|
|
|
0);
|
|
|
|
}
|
|
|
|
index->idl_count++;
|
|
|
|
}
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
return true;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
case 4:
|
2001-12-24 03:51:06 +01:00
|
|
|
relation = MET_lookup_relation(tdbb, work->dfw_name);
|
|
|
|
if (!relation) {
|
|
|
|
return false;
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
id = work->dfw_id - 1;
|
|
|
|
index = CMP_get_index_lock(tdbb, relation, id);
|
|
|
|
IDX_delete_index(tdbb, relation, id);
|
|
|
|
if (work->dfw_type == dfw_delete_expression_index)
|
2001-12-24 03:51:06 +01:00
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
MET_delete_dependencies(tdbb,
|
|
|
|
work->dfw_name,
|
|
|
|
obj_expression_index);
|
2001-12-24 03:51:06 +01:00
|
|
|
}
|
2002-09-30 16:21:34 +02:00
|
|
|
MET_update_partners(tdbb);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (index)
|
|
|
|
{
|
|
|
|
/* in order for us to have gotten the lock in phase 3
|
|
|
|
* idl_count HAD to be 0, therefore after having incremented
|
|
|
|
* it for the exclusive lock it would have to be 1.
|
|
|
|
* IF now it is NOT 1 then someone else got a lock to
|
|
|
|
* the index and something is seriously wrong */
|
|
|
|
assert(index->idl_count == 1);
|
|
|
|
if (!--index->idl_count)
|
|
|
|
{
|
|
|
|
/* Release index existence lock and memory. */
|
|
|
|
|
|
|
|
for (ptr = &relation->rel_index_locks;
|
|
|
|
*ptr;
|
|
|
|
ptr = &(*ptr)->idl_next)
|
|
|
|
{
|
|
|
|
if (*ptr == index)
|
|
|
|
{
|
|
|
|
*ptr = index->idl_next;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (index->idl_lock)
|
|
|
|
{
|
|
|
|
LCK_release(tdbb, index->idl_lock);
|
2001-12-24 03:51:06 +01:00
|
|
|
delete index->idl_lock;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2001-12-24 03:51:06 +01:00
|
|
|
delete index;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* Release index refresh lock and memory. */
|
|
|
|
|
|
|
|
for (iptr = &relation->rel_index_blocks;
|
|
|
|
*iptr;
|
|
|
|
iptr = &(*iptr)->idb_next)
|
|
|
|
{
|
|
|
|
if ((*iptr)->idb_id == id)
|
|
|
|
{
|
|
|
|
index_block = *iptr;
|
|
|
|
*iptr = index_block->idb_next;
|
|
|
|
|
|
|
|
/* Lock was released in IDX_delete_index(). */
|
|
|
|
|
|
|
|
if (index_block->idb_lock)
|
2001-12-24 03:51:06 +01:00
|
|
|
delete index_block->idb_lock;
|
|
|
|
delete index_block;
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-11-17 01:13:59 +01:00
|
|
|
static bool delete_log(TDBB tdbb, SSHORT phase, DFW work, JRD_TRA transaction)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* d e l e t e _ l o g
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Do work associated with the deletion of records in RDB$LOG_FILES
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
DBB dbb;
|
|
|
|
|
|
|
|
SET_TDBB(tdbb);
|
|
|
|
dbb = tdbb->tdbb_database;
|
|
|
|
|
|
|
|
switch (phase)
|
|
|
|
{
|
|
|
|
case 1:
|
|
|
|
case 2:
|
2001-12-24 03:51:06 +01:00
|
|
|
return true;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
case 3:
|
2001-12-24 03:51:06 +01:00
|
|
|
if (CCH_exclusive(tdbb, LCK_EX, WAIT_PERIOD)) {
|
|
|
|
return true;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2001-12-24 03:51:06 +01:00
|
|
|
ERR_post(gds_no_meta_update,
|
|
|
|
gds_arg_gds, gds_lock_timeout,
|
|
|
|
gds_arg_gds, gds_obj_in_use,
|
|
|
|
gds_arg_string, ERR_cstring(dbb->dbb_file->fil_string),
|
|
|
|
0);
|
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
case 4:
|
|
|
|
transaction->tra_flags |= TRA_delete_log;
|
|
|
|
PAG_modify_log(transaction->tra_number, TRA_delete_log);
|
2001-12-24 03:51:06 +01:00
|
|
|
return true;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
case 5:
|
|
|
|
CCH_release_exclusive(tdbb);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
static bool delete_parameter( TDBB tdbb,
|
|
|
|
SSHORT phase,
|
|
|
|
DFW work,
|
2002-11-17 01:13:59 +01:00
|
|
|
JRD_TRA transaction)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* d e l e t e _ p a r a m e t e r
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Return an error if someone attempts to
|
|
|
|
* delete a field from a procedure and it is
|
|
|
|
* used by a view or procedure.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
|
|
|
SET_TDBB(tdbb);
|
|
|
|
|
|
|
|
switch (phase)
|
|
|
|
{
|
|
|
|
case 1:
|
2002-11-04 16:12:34 +01:00
|
|
|
if (MET_lookup_procedure_id(tdbb, work->dfw_id, FALSE, TRUE, 0))
|
2001-12-24 03:51:06 +01:00
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
check_dependencies(tdbb, work->dfw_name, work->dfw_name,
|
|
|
|
obj_procedure, transaction);
|
2001-12-24 03:51:06 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
case 2:
|
2001-12-24 03:51:06 +01:00
|
|
|
return true;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
case 3:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
static bool delete_procedure( TDBB tdbb,
|
|
|
|
SSHORT phase,
|
|
|
|
DFW work,
|
2002-11-17 01:13:59 +01:00
|
|
|
JRD_TRA transaction)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* d e l e t e _ p r o c e d u r e
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Check if it is allowable to delete
|
|
|
|
* a procedure , and if so, clean up after it.
|
|
|
|
*
|
|
|
|
**************************************/
|
2002-11-17 01:13:59 +01:00
|
|
|
JRD_PRC procedure;
|
2001-05-23 15:26:42 +02:00
|
|
|
USHORT wait;
|
|
|
|
USHORT old_flags;
|
|
|
|
|
|
|
|
SET_TDBB(tdbb);
|
|
|
|
|
|
|
|
switch (phase)
|
|
|
|
{
|
|
|
|
case 0:
|
2002-11-04 16:12:34 +01:00
|
|
|
procedure = MET_lookup_procedure_id(tdbb, work->dfw_id, FALSE, TRUE, 0);
|
2001-12-24 03:51:06 +01:00
|
|
|
if (!procedure) {
|
|
|
|
return false;
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
wait = (transaction->tra_flags & TRA_nowait) ? FALSE : TRUE;
|
|
|
|
LCK_convert_non_blocking( tdbb,
|
|
|
|
procedure->prc_existence_lock,
|
|
|
|
LCK_SR,
|
|
|
|
wait);
|
2001-12-24 03:51:06 +01:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
case 1:
|
2001-07-12 08:32:05 +02:00
|
|
|
check_dependencies(tdbb, work->dfw_name, (TEXT*)NULL_PTR,
|
2001-05-23 15:26:42 +02:00
|
|
|
obj_procedure, transaction);
|
2001-12-24 03:51:06 +01:00
|
|
|
return true;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
case 2:
|
2002-11-04 16:12:34 +01:00
|
|
|
procedure = MET_lookup_procedure_id(tdbb, work->dfw_id, FALSE, TRUE, 0);
|
2001-12-24 03:51:06 +01:00
|
|
|
if (!procedure) {
|
|
|
|
return false;
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
wait = (transaction->tra_flags & TRA_nowait) ? FALSE : TRUE;
|
|
|
|
if (!LCK_convert_non_blocking( tdbb,
|
|
|
|
procedure->prc_existence_lock,
|
|
|
|
LCK_EX,
|
|
|
|
wait))
|
|
|
|
{
|
2001-07-29 19:42:23 +02:00
|
|
|
ERR_post(gds_no_meta_update,
|
|
|
|
gds_arg_gds, gds_obj_in_use,
|
2001-05-23 15:26:42 +02:00
|
|
|
gds_arg_string, ERR_cstring(work->dfw_name),
|
|
|
|
0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If we are in a multi-client server, someone else may have marked
|
|
|
|
procedure obsolete. Unmark and we will remark it later. */
|
|
|
|
|
|
|
|
procedure->prc_flags &= ~PRC_obsolete;
|
2001-12-24 03:51:06 +01:00
|
|
|
return true;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
case 3:
|
2001-12-24 03:51:06 +01:00
|
|
|
return true;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
case 4:
|
2002-11-04 16:12:34 +01:00
|
|
|
procedure = MET_lookup_procedure_id(tdbb, work->dfw_id, TRUE, TRUE, 0);
|
2001-12-24 03:51:06 +01:00
|
|
|
if (!procedure) {
|
|
|
|
return false;
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2002-10-05 00:08:43 +02:00
|
|
|
// "OBJECT IN USE" error should be emitted in this case, but some more
|
|
|
|
// code needs to be reviewed for that. Now you can drop procedure
|
|
|
|
// used by other compiled requests
|
2002-11-14 14:39:02 +01:00
|
|
|
if (procedure->prc_use_count && !MET_clear_cache(tdbb, procedure))
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2002-10-05 00:08:43 +02:00
|
|
|
gds__log("Deleting unfreed procedure %s",work->dfw_name);
|
2001-05-23 15:26:42 +02:00
|
|
|
MET_delete_dependencies(tdbb, work->dfw_name, obj_procedure);
|
|
|
|
|
|
|
|
LCK_release(tdbb, procedure->prc_existence_lock);
|
2001-12-24 03:51:06 +01:00
|
|
|
(*tdbb->tdbb_database->dbb_procedures)[procedure->prc_id] =
|
|
|
|
(BLK) NULL_PTR;
|
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
old_flags = procedure->prc_flags;
|
|
|
|
procedure->prc_flags |= PRC_obsolete;
|
|
|
|
if (procedure->prc_request)
|
|
|
|
{
|
|
|
|
if (CMP_clone_active(procedure->prc_request))
|
|
|
|
{
|
|
|
|
procedure->prc_flags = old_flags;
|
2001-07-29 19:42:23 +02:00
|
|
|
ERR_post(gds_no_meta_update,
|
|
|
|
gds_arg_gds, gds_obj_in_use,
|
2001-05-23 15:26:42 +02:00
|
|
|
gds_arg_string, ERR_cstring(work->dfw_name),
|
|
|
|
0);
|
|
|
|
}
|
|
|
|
|
|
|
|
CMP_release(tdbb, procedure->prc_request);
|
|
|
|
procedure->prc_request = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* delete dependency lists */
|
|
|
|
|
|
|
|
MET_delete_dependencies(tdbb, work->dfw_name, obj_procedure);
|
|
|
|
|
|
|
|
LCK_release(tdbb, procedure->prc_existence_lock);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-11-17 01:13:59 +01:00
|
|
|
static bool delete_relation(TDBB tdbb, SSHORT phase, DFW work, JRD_TRA transaction)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* d e l e t e _ r e l a t i o n
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Check if it is allowable to delete
|
|
|
|
* a relation, and if so, clean up after it.
|
|
|
|
*
|
|
|
|
**************************************/
|
2001-12-24 03:51:06 +01:00
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
BLK request;
|
2002-11-17 01:13:59 +01:00
|
|
|
JRD_REL relation;
|
2001-05-23 15:26:42 +02:00
|
|
|
RSC rsc;
|
|
|
|
USHORT wait, view_count, adjusted;
|
|
|
|
|
|
|
|
SET_TDBB(tdbb);
|
2001-12-24 03:51:06 +01:00
|
|
|
DBB dbb = tdbb->tdbb_database;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
switch (phase)
|
|
|
|
{
|
|
|
|
case 0:
|
2001-12-24 03:51:06 +01:00
|
|
|
relation = MET_lookup_relation_id(tdbb, work->dfw_id, FALSE);
|
|
|
|
if (!relation) {
|
|
|
|
return false;
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (relation->rel_existence_lock)
|
|
|
|
{
|
|
|
|
wait = (transaction->tra_flags & TRA_nowait) ? FALSE : TRUE;
|
|
|
|
LCK_convert_non_blocking(tdbb,
|
|
|
|
relation->rel_existence_lock,
|
|
|
|
LCK_SR,
|
|
|
|
wait);
|
|
|
|
}
|
|
|
|
|
|
|
|
relation->rel_flags &= ~REL_deleting;
|
2001-12-24 03:51:06 +01:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
case 1:
|
|
|
|
/* check if any views use this as a base relation */
|
|
|
|
|
|
|
|
request = NULL;
|
|
|
|
view_count = 0;
|
|
|
|
FOR(REQUEST_HANDLE request)
|
|
|
|
X IN RDB$VIEW_RELATIONS WITH
|
|
|
|
X.RDB$RELATION_NAME EQ work->dfw_name
|
|
|
|
/* If the view is also being deleted, there's no dependency */
|
|
|
|
if (!find_depend_in_dfw(tdbb, X.RDB$VIEW_NAME, obj_view, 0,
|
|
|
|
transaction))
|
2001-12-24 03:51:06 +01:00
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
view_count++;
|
2001-12-24 03:51:06 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
END_FOR;
|
2002-11-17 01:13:59 +01:00
|
|
|
CMP_release(tdbb, (JRD_REQ)request);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (view_count)
|
2001-12-24 03:51:06 +01:00
|
|
|
{
|
2001-07-29 19:42:23 +02:00
|
|
|
ERR_post(gds_no_meta_update,
|
|
|
|
gds_arg_gds, gds_no_delete, /* Msg353: can not delete */
|
|
|
|
gds_arg_gds, gds_table_name,
|
2001-05-23 15:26:42 +02:00
|
|
|
gds_arg_string, ERR_cstring(work->dfw_name),
|
2001-07-29 19:42:23 +02:00
|
|
|
gds_arg_gds, gds_dependency,
|
2001-05-23 15:26:42 +02:00
|
|
|
gds_arg_number, (SLONG) view_count,
|
|
|
|
0); /* Msg310: there are %ld dependencies */
|
2001-12-24 03:51:06 +01:00
|
|
|
}
|
2001-07-12 08:32:05 +02:00
|
|
|
check_dependencies(tdbb, work->dfw_name, (TEXT*)NULL_PTR,
|
2001-05-23 15:26:42 +02:00
|
|
|
obj_relation, transaction);
|
2001-12-24 03:51:06 +01:00
|
|
|
return true;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
case 2:
|
2001-12-24 03:51:06 +01:00
|
|
|
relation = MET_lookup_relation_id(tdbb, work->dfw_id, FALSE);
|
|
|
|
if (!relation) {
|
|
|
|
return false;
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* Let relation be deleted if only this transaction is using it */
|
|
|
|
|
|
|
|
adjusted = FALSE;
|
|
|
|
if (relation->rel_use_count == 1)
|
2001-12-24 03:51:06 +01:00
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
for (rsc = transaction->tra_resources; rsc; rsc = rsc->rsc_next)
|
|
|
|
{
|
|
|
|
if (rsc->rsc_rel == relation)
|
|
|
|
{
|
|
|
|
--relation->rel_use_count;
|
|
|
|
adjusted = TRUE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2001-12-24 03:51:06 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
wait = (transaction->tra_flags & TRA_nowait) ? FALSE : TRUE;
|
2002-10-05 00:08:43 +02:00
|
|
|
if (relation->rel_use_count)
|
|
|
|
MET_clear_cache(tdbb, NULL);
|
2001-05-23 15:26:42 +02:00
|
|
|
if (relation->rel_use_count ||
|
|
|
|
(relation->rel_existence_lock &&
|
|
|
|
!LCK_convert_non_blocking( tdbb,
|
|
|
|
relation->rel_existence_lock,
|
|
|
|
LCK_EX,
|
|
|
|
wait)))
|
|
|
|
{
|
2001-12-24 03:51:06 +01:00
|
|
|
if (adjusted) {
|
2001-05-23 15:26:42 +02:00
|
|
|
++relation->rel_use_count;
|
2001-12-24 03:51:06 +01:00
|
|
|
}
|
2001-07-29 19:42:23 +02:00
|
|
|
ERR_post(gds_no_meta_update,
|
|
|
|
gds_arg_gds, gds_obj_in_use,
|
2001-05-23 15:26:42 +02:00
|
|
|
gds_arg_string, ERR_cstring(work->dfw_name),
|
|
|
|
0);
|
|
|
|
}
|
2001-12-24 03:51:06 +01:00
|
|
|
return true;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
case 3:
|
2001-12-24 03:51:06 +01:00
|
|
|
return true;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
case 4:
|
2001-12-24 03:51:06 +01:00
|
|
|
relation = MET_lookup_relation_id(tdbb, work->dfw_id, TRUE);
|
|
|
|
if (!relation) {
|
|
|
|
return false;
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* Flag relation delete in progress so that active sweep or
|
|
|
|
garbage collector threads working on relation can skip over it. */
|
|
|
|
|
|
|
|
relation->rel_flags |= REL_deleting;
|
|
|
|
|
|
|
|
/* The sweep and garbage collector threads have no more than
|
|
|
|
a single record latency in responding to the flagged relation
|
|
|
|
deletion. Nevertheless, as a defensive programming measure,
|
|
|
|
don't wait forever if something has gone awry and the sweep
|
|
|
|
count doesn't run down. */
|
|
|
|
|
|
|
|
for (wait = 0; wait < 60; wait++)
|
2001-12-24 03:51:06 +01:00
|
|
|
{
|
|
|
|
if (!relation->rel_sweep_count) {
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
THREAD_EXIT;
|
|
|
|
THREAD_SLEEP(1 * 1000);
|
|
|
|
THREAD_ENTER;
|
|
|
|
}
|
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
if (relation->rel_sweep_count)
|
2001-12-24 03:51:06 +01:00
|
|
|
{
|
2001-07-29 19:42:23 +02:00
|
|
|
ERR_post(gds_no_meta_update,
|
|
|
|
gds_arg_gds, gds_obj_in_use,
|
2001-05-23 15:26:42 +02:00
|
|
|
gds_arg_string, ERR_cstring(work->dfw_name),
|
|
|
|
0);
|
2001-12-24 03:51:06 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
#ifdef GARBAGE_THREAD
|
|
|
|
/* Free any memory associated with the relation's
|
|
|
|
garbage collection bitmap. */
|
|
|
|
|
|
|
|
if (relation->rel_gc_bitmap)
|
|
|
|
{
|
|
|
|
SBM_release(relation->rel_gc_bitmap);
|
2001-12-24 03:51:06 +01:00
|
|
|
relation->rel_gc_bitmap = 0;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
#endif
|
2001-12-24 03:51:06 +01:00
|
|
|
if (relation->rel_file) {
|
2001-09-18 21:12:25 +02:00
|
|
|
EXT_fini (relation);
|
2001-12-24 03:51:06 +01:00
|
|
|
}
|
2001-09-18 21:12:25 +02:00
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
if (relation->rel_index_root) {
|
2001-05-23 15:26:42 +02:00
|
|
|
IDX_delete_indices(tdbb, relation);
|
2001-12-24 03:51:06 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
if (relation->rel_pages) {
|
2001-05-23 15:26:42 +02:00
|
|
|
DPM_delete_relation(tdbb, relation);
|
2001-12-24 03:51:06 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* if this is a view (or even if we don't know),
|
|
|
|
delete dependency lists */
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
if (relation->rel_view_rse || !(relation->rel_flags & REL_scanned)) {
|
2001-05-23 15:26:42 +02:00
|
|
|
MET_delete_dependencies(tdbb, work->dfw_name, obj_view);
|
2001-12-24 03:51:06 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* Now that the data, pointer, and index pages are gone,
|
|
|
|
get rid of formats as well */
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
if (relation->rel_existence_lock) {
|
2001-05-23 15:26:42 +02:00
|
|
|
LCK_release(tdbb, relation->rel_existence_lock);
|
2001-12-24 03:51:06 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
request = NULL;
|
|
|
|
|
|
|
|
FOR(REQUEST_HANDLE request) X IN RDB$FORMATS WITH
|
|
|
|
X.RDB$RELATION_ID EQ relation->rel_id
|
|
|
|
ERASE X;
|
|
|
|
END_FOR;
|
|
|
|
|
|
|
|
relation->rel_name = NULL;
|
|
|
|
relation->rel_flags |= REL_deleted;
|
|
|
|
relation->rel_flags &= ~REL_deleting;
|
2002-09-28 00:59:24 +02:00
|
|
|
|
|
|
|
// Release relation triggers
|
|
|
|
MET_release_triggers(tdbb, &relation->rel_pre_store);
|
|
|
|
MET_release_triggers(tdbb, &relation->rel_post_store);
|
|
|
|
MET_release_triggers(tdbb, &relation->rel_pre_erase);
|
|
|
|
MET_release_triggers(tdbb, &relation->rel_post_erase);
|
|
|
|
MET_release_triggers(tdbb, &relation->rel_pre_modify);
|
|
|
|
MET_release_triggers(tdbb, &relation->rel_post_modify);
|
|
|
|
|
2002-11-17 01:13:59 +01:00
|
|
|
CMP_release(tdbb, (JRD_REQ)request);
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-11-17 01:13:59 +01:00
|
|
|
static bool delete_rfr(TDBB tdbb, SSHORT phase, DFW work, JRD_TRA transaction)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* d e l e t e _ r f r
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* This whole routine exists just to
|
|
|
|
* return an error if someone attempts to
|
|
|
|
* 1. delete a field from a relation if the relation
|
|
|
|
* is used in a view and the field is referenced in
|
|
|
|
* the view.
|
|
|
|
* 2. drop the last column of a table
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
DBB dbb;
|
|
|
|
int rel_exists, field_count, id;
|
|
|
|
BLK handle;
|
2002-06-29 15:03:13 +02:00
|
|
|
TEXT f[32];
|
2002-11-17 01:13:59 +01:00
|
|
|
JRD_REL relation;
|
2001-05-23 15:26:42 +02:00
|
|
|
VEC vector;
|
|
|
|
|
|
|
|
SET_TDBB(tdbb);
|
|
|
|
dbb = tdbb->tdbb_database;
|
|
|
|
|
|
|
|
switch (phase)
|
|
|
|
{
|
|
|
|
case 1:
|
|
|
|
/* first check if there are any fields used explicitly by the view */
|
|
|
|
|
|
|
|
handle = NULL;
|
|
|
|
field_count = 0;
|
|
|
|
FOR(REQUEST_HANDLE handle)
|
|
|
|
REL IN RDB$RELATIONS CROSS
|
|
|
|
VR IN RDB$VIEW_RELATIONS OVER RDB$RELATION_NAME CROSS
|
|
|
|
VFLD IN RDB$RELATION_FIELDS WITH
|
|
|
|
REL.RDB$RELATION_ID EQ work->dfw_id AND
|
|
|
|
VFLD.RDB$VIEW_CONTEXT EQ VR.RDB$VIEW_CONTEXT AND
|
|
|
|
VFLD.RDB$RELATION_NAME EQ VR.RDB$VIEW_NAME AND
|
|
|
|
VFLD.RDB$BASE_FIELD EQ work->dfw_name
|
|
|
|
/* If the view is also being deleted, there's no dependency */
|
|
|
|
if (!find_depend_in_dfw(tdbb, VR.RDB$VIEW_NAME, obj_view,
|
|
|
|
0, transaction))
|
|
|
|
{
|
2002-06-29 15:03:13 +02:00
|
|
|
TEXT *p = f, *endp = f + sizeof(f)-1, *q;
|
|
|
|
for (q = VFLD.RDB$BASE_FIELD; *q && p < endp; *p++ = *q++)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
; /* empty body */
|
|
|
|
}
|
|
|
|
*p = 0;
|
2002-06-29 15:03:13 +02:00
|
|
|
MET_exact_name(f);
|
2001-05-23 15:26:42 +02:00
|
|
|
field_count++;
|
2001-12-24 03:51:06 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
END_FOR;
|
2002-11-17 01:13:59 +01:00
|
|
|
CMP_release(tdbb, (JRD_REQ)handle);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (field_count)
|
2001-07-29 19:42:23 +02:00
|
|
|
ERR_post(gds_no_meta_update,
|
|
|
|
gds_arg_gds, gds_no_delete, /* Msg353: can not delete */
|
|
|
|
gds_arg_gds, gds_field_name,
|
2001-05-23 15:26:42 +02:00
|
|
|
gds_arg_string, ERR_cstring(f),
|
2001-07-29 19:42:23 +02:00
|
|
|
gds_arg_gds, gds_dependency,
|
2001-05-23 15:26:42 +02:00
|
|
|
gds_arg_number, (SLONG) field_count,
|
|
|
|
0); /* Msg310: there are %ld dependencies */
|
|
|
|
|
|
|
|
/* now check if there are any dependencies generated through the blr
|
|
|
|
that defines the relation */
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
if ( (relation = MET_lookup_relation_id(tdbb, work->dfw_id, FALSE)) )
|
2001-05-23 15:26:42 +02:00
|
|
|
check_dependencies(tdbb, relation->rel_name, work->dfw_name,
|
|
|
|
obj_relation, transaction);
|
|
|
|
|
|
|
|
/* see if the relation itself is being dropped */
|
|
|
|
|
|
|
|
handle = NULL;
|
|
|
|
rel_exists = 0;
|
|
|
|
FOR(REQUEST_HANDLE handle)
|
|
|
|
REL IN RDB$RELATIONS WITH REL.RDB$RELATION_ID EQ work->dfw_id
|
|
|
|
rel_exists++;
|
|
|
|
END_FOR;
|
|
|
|
if (handle)
|
2002-11-17 01:13:59 +01:00
|
|
|
CMP_release(tdbb, (JRD_REQ)handle);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* if table exists, check if this is the last column in the table */
|
|
|
|
|
|
|
|
if (rel_exists)
|
|
|
|
{
|
|
|
|
field_count = 0;
|
|
|
|
handle = NULL;
|
|
|
|
|
|
|
|
FOR(REQUEST_HANDLE handle)
|
|
|
|
REL IN RDB$RELATIONS CROSS
|
|
|
|
RFLD IN RDB$RELATION_FIELDS OVER RDB$RELATION_NAME WITH
|
|
|
|
REL.RDB$RELATION_ID EQ work->dfw_id
|
|
|
|
field_count++;
|
|
|
|
END_FOR;
|
|
|
|
if (handle)
|
|
|
|
{
|
2002-11-17 01:13:59 +01:00
|
|
|
CMP_release(tdbb, (JRD_REQ)handle);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!field_count)
|
|
|
|
{
|
2001-07-29 19:42:23 +02:00
|
|
|
ERR_post(gds_no_meta_update,
|
|
|
|
gds_arg_gds, gds_del_last_field,
|
2001-05-23 15:26:42 +02:00
|
|
|
0);
|
|
|
|
/* Msg354: last column in a relation cannot be deleted */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
case 2:
|
2001-12-24 03:51:06 +01:00
|
|
|
return true;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
case 3:
|
|
|
|
/* Unlink field from data structures. Don't try to actually release field and
|
|
|
|
friends -- somebody may be pointing to them */
|
|
|
|
|
|
|
|
relation = MET_lookup_relation_id(tdbb, work->dfw_id, FALSE);
|
|
|
|
if (relation)
|
|
|
|
{
|
2002-06-29 15:03:13 +02:00
|
|
|
id = MET_lookup_field(tdbb, relation, work->dfw_name, 0);
|
2001-05-23 15:26:42 +02:00
|
|
|
if (id >= 0)
|
|
|
|
{
|
|
|
|
vector = relation->rel_fields;
|
|
|
|
if (vector &&
|
2001-12-24 03:51:06 +01:00
|
|
|
(ULONG)id < vector->count() &&
|
|
|
|
(*vector)[id])
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2001-12-24 03:51:06 +01:00
|
|
|
(*vector)[id] = NULL;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
static bool delete_shadow( TDBB tdbb,
|
|
|
|
SSHORT phase,
|
|
|
|
DFW work,
|
2002-11-17 01:13:59 +01:00
|
|
|
JRD_TRA transaction)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* d e l e t e _ s h a d o w
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Provide deferred work interface to
|
|
|
|
* MET_delete_shadow.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
|
|
|
SET_TDBB(tdbb);
|
|
|
|
|
|
|
|
switch (phase)
|
|
|
|
{
|
|
|
|
case 1:
|
|
|
|
case 2:
|
2001-12-24 03:51:06 +01:00
|
|
|
return true;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
case 3:
|
|
|
|
MET_delete_shadow(tdbb, work->dfw_id);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
static bool delete_trigger( TDBB tdbb,
|
|
|
|
SSHORT phase,
|
|
|
|
DFW work,
|
2002-11-17 01:13:59 +01:00
|
|
|
JRD_TRA transaction)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* d e l e t e _ t r i g g e r
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Cleanup after a deleted trigger.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
|
|
|
SET_TDBB(tdbb);
|
|
|
|
|
|
|
|
switch (phase)
|
|
|
|
{
|
|
|
|
case 1:
|
|
|
|
case 2:
|
2001-12-24 03:51:06 +01:00
|
|
|
return true;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
case 3:
|
|
|
|
/* get rid of dependencies */
|
|
|
|
|
|
|
|
MET_delete_dependencies(tdbb, work->dfw_name, obj_trigger);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
static bool find_depend_in_dfw( TDBB tdbb,
|
|
|
|
TEXT* object_name,
|
|
|
|
USHORT dep_type,
|
|
|
|
USHORT rel_id,
|
2002-11-17 01:13:59 +01:00
|
|
|
JRD_TRA transaction)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* f i n d _ d e p e n d _ i n _ d f w
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Check the object to see if it is being
|
|
|
|
* deleted as part of the deferred work.
|
2002-06-29 15:03:13 +02:00
|
|
|
* Return TRUE if it is, FALSE otherwise.
|
2001-05-23 15:26:42 +02:00
|
|
|
*
|
|
|
|
**************************************/
|
2001-12-24 03:51:06 +01:00
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
BLK request;
|
|
|
|
ENUM dfw_t dfw_type;
|
|
|
|
DFW work;
|
|
|
|
|
|
|
|
SET_TDBB(tdbb);
|
2001-12-24 03:51:06 +01:00
|
|
|
DBB dbb = tdbb->tdbb_database;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2002-06-29 15:03:13 +02:00
|
|
|
MET_exact_name(object_name);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
switch (dep_type)
|
|
|
|
{
|
|
|
|
case obj_view:
|
|
|
|
dfw_type = dfw_delete_relation;
|
|
|
|
break;
|
|
|
|
case obj_trigger:
|
|
|
|
dfw_type = dfw_delete_trigger;
|
|
|
|
break;
|
|
|
|
case obj_computed:
|
|
|
|
dfw_type = (rel_id) ? dfw_delete_rfr : dfw_delete_global;
|
|
|
|
break;
|
|
|
|
case obj_procedure:
|
|
|
|
dfw_type = dfw_delete_procedure;
|
|
|
|
break;
|
|
|
|
case obj_expression_index:
|
|
|
|
dfw_type = dfw_delete_index;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
assert(FALSE);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Look to see if an object of the desired type is being deleted. */
|
|
|
|
|
|
|
|
for (work = transaction->tra_deferred_work; work; work = work->dfw_next)
|
|
|
|
{
|
|
|
|
if (work->dfw_type == dfw_type &&
|
|
|
|
!strcmp(object_name, work->dfw_name) &&
|
|
|
|
(!rel_id || rel_id == work->dfw_id))
|
|
|
|
{
|
2001-12-24 03:51:06 +01:00
|
|
|
return true;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dfw_type == dfw_delete_global)
|
|
|
|
{
|
|
|
|
/* Computed fields are more complicated. If the global field isn't being
|
|
|
|
deleted, see if all of the fields it is the source for, are. */
|
|
|
|
|
|
|
|
request = (BLK) CMP_find_request(tdbb, irq_ch_cmp_dpd, IRQ_REQUESTS);
|
|
|
|
|
|
|
|
FOR(REQUEST_HANDLE request)
|
|
|
|
FLD IN RDB$FIELDS CROSS
|
|
|
|
RFR IN RDB$RELATION_FIELDS CROSS
|
|
|
|
REL IN RDB$RELATIONS
|
|
|
|
WITH FLD.RDB$FIELD_NAME EQ RFR.RDB$FIELD_SOURCE
|
|
|
|
AND FLD.RDB$FIELD_NAME EQ object_name
|
|
|
|
AND REL.RDB$RELATION_NAME EQ RFR.RDB$RELATION_NAME
|
|
|
|
if (!REQUEST(irq_ch_cmp_dpd))
|
2001-07-12 08:32:05 +02:00
|
|
|
REQUEST(irq_ch_cmp_dpd) = (BLK) request;
|
2001-05-23 15:26:42 +02:00
|
|
|
if (!find_depend_in_dfw(tdbb, RFR.RDB$FIELD_NAME, obj_computed,
|
|
|
|
REL.RDB$RELATION_ID, transaction))
|
|
|
|
{
|
2002-11-17 01:13:59 +01:00
|
|
|
EXE_unwind(tdbb, (JRD_REQ)request);
|
2001-12-24 03:51:06 +01:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
END_FOR;
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
if (!REQUEST(irq_ch_cmp_dpd)) {
|
2001-07-12 08:32:05 +02:00
|
|
|
REQUEST(irq_ch_cmp_dpd) = (BLK) request;
|
2001-12-24 03:51:06 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
return true;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void get_array_desc( TDBB tdbb, TEXT * field_name, ADS desc)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* g e t _ a r r a y _ d e s c
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Get array descriptor for an array.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
DBB dbb;
|
|
|
|
BLK request;
|
2001-07-12 08:32:05 +02:00
|
|
|
struct ads::ads_repeat *ranges;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
SET_TDBB(tdbb);
|
|
|
|
dbb = tdbb->tdbb_database;
|
|
|
|
|
|
|
|
request = (BLK) CMP_find_request(tdbb, irq_r_fld_dim, IRQ_REQUESTS);
|
|
|
|
|
|
|
|
FOR (REQUEST_HANDLE request)
|
|
|
|
D IN RDB$FIELD_DIMENSIONS WITH D.RDB$FIELD_NAME EQ field_name
|
|
|
|
if (!REQUEST(irq_r_fld_dim))
|
|
|
|
{
|
2001-07-12 08:32:05 +02:00
|
|
|
REQUEST(irq_r_fld_dim) = (BLK) request;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
if (D.RDB$DIMENSION >= 0 && D.RDB$DIMENSION < desc->ads_dimensions)
|
|
|
|
{
|
|
|
|
ranges = desc->ads_rpt + D.RDB$DIMENSION;
|
|
|
|
ranges->ads_lower = D.RDB$LOWER_BOUND;
|
|
|
|
ranges->ads_upper = D.RDB$UPPER_BOUND;
|
|
|
|
}
|
|
|
|
END_FOR;
|
|
|
|
|
|
|
|
if (!REQUEST(irq_r_fld_dim))
|
|
|
|
{
|
2001-07-12 08:32:05 +02:00
|
|
|
REQUEST(irq_r_fld_dim) = (BLK) request;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
desc->ads_count = 1;
|
|
|
|
|
|
|
|
for (ranges = desc->ads_rpt + desc->ads_dimensions;
|
|
|
|
--ranges >= desc->ads_rpt;)
|
|
|
|
{
|
|
|
|
ranges->ads_length = desc->ads_count;
|
|
|
|
desc->ads_count *= ranges->ads_upper - ranges->ads_lower + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
desc->ads_version = ADS_VERSION_1;
|
|
|
|
desc->ads_length =
|
|
|
|
ADS_LEN(MAX(desc->ads_struct_count, desc->ads_dimensions));
|
|
|
|
desc->ads_element_length = desc->ads_rpt[0].ads_desc.dsc_length;
|
|
|
|
desc->ads_total_length = desc->ads_element_length * desc->ads_count;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void get_procedure_dependencies(DFW work)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* g e t _ p r o c e d u r e _ d e p e n d e n c i e s
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Get relations and fields on which this
|
|
|
|
* procedure depends, either when it's being
|
|
|
|
* created or when it's modified.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
TDBB tdbb;
|
|
|
|
DBB dbb;
|
2002-11-17 01:13:59 +01:00
|
|
|
JRD_PRC procedure;
|
2001-05-23 15:26:42 +02:00
|
|
|
GDS__QUAD blob_id;
|
2002-11-17 01:13:59 +01:00
|
|
|
JRD_REQ request;
|
2001-05-23 15:26:42 +02:00
|
|
|
BLK handle;
|
2001-12-24 03:51:06 +01:00
|
|
|
JrdMemoryPool *old_pool;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
tdbb = GET_THREAD_DATA;
|
|
|
|
dbb = tdbb->tdbb_database;
|
|
|
|
|
|
|
|
procedure = NULL;
|
|
|
|
|
|
|
|
handle = (BLK) CMP_find_request(tdbb, irq_c_prc_dpd, IRQ_REQUESTS);
|
|
|
|
|
|
|
|
FOR(REQUEST_HANDLE handle)
|
|
|
|
X IN RDB$PROCEDURES WITH
|
|
|
|
X.RDB$PROCEDURE_NAME EQ work->dfw_name
|
|
|
|
if (!REQUEST(irq_c_prc_dpd))
|
2001-07-12 08:32:05 +02:00
|
|
|
REQUEST(irq_c_prc_dpd) = (BLK) handle;
|
2001-05-23 15:26:42 +02:00
|
|
|
blob_id = X.RDB$PROCEDURE_BLR;
|
2002-11-04 16:12:34 +01:00
|
|
|
procedure = MET_lookup_procedure(tdbb, work->dfw_name, FALSE);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
END_FOR;
|
|
|
|
|
|
|
|
if (!REQUEST(irq_c_prc_dpd))
|
2001-07-12 08:32:05 +02:00
|
|
|
REQUEST(irq_c_prc_dpd) = (BLK) handle;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* get any dependencies now by parsing the blr */
|
|
|
|
|
|
|
|
if (procedure && !NULL_BLOB(blob_id))
|
|
|
|
{
|
|
|
|
old_pool = tdbb->tdbb_default;
|
2002-09-26 20:13:02 +02:00
|
|
|
/* Nickolay Samofatov: allocate statement memory pool... */
|
2002-09-25 19:12:16 +02:00
|
|
|
tdbb->tdbb_default = FB_NEW(*dbb->dbb_permanent) JrdMemoryPool;
|
2001-05-23 15:26:42 +02:00
|
|
|
MET_get_dependencies(tdbb,
|
2002-11-21 00:18:16 +01:00
|
|
|
(struct jrd_rel*)NULL_PTR,
|
2001-07-12 08:32:05 +02:00
|
|
|
(TEXT*)NULL_PTR,
|
2001-12-24 03:51:06 +01:00
|
|
|
(CSB)NULL_PTR,
|
2001-05-23 15:26:42 +02:00
|
|
|
(SLONG*)&blob_id,
|
|
|
|
&request,
|
2001-12-24 03:51:06 +01:00
|
|
|
(CSB*)NULL_PTR,
|
2001-05-23 15:26:42 +02:00
|
|
|
work->dfw_name,
|
|
|
|
obj_procedure);
|
|
|
|
if (request)
|
|
|
|
CMP_release(tdbb, request);
|
|
|
|
else
|
2001-12-24 03:51:06 +01:00
|
|
|
delete tdbb->tdbb_default;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
tdbb->tdbb_default = old_pool;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void get_trigger_dependencies( DFW work)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* g e t _ t r i g g e r _ d e p e n d e n c i e s
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Get relations and fields on which this
|
|
|
|
* trigger depends, either when it's being
|
|
|
|
* created or when it's modified.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
TDBB tdbb;
|
|
|
|
DBB dbb;
|
2002-11-17 01:13:59 +01:00
|
|
|
JRD_REL relation;
|
2001-05-23 15:26:42 +02:00
|
|
|
GDS__QUAD blob_id;
|
2002-11-17 01:13:59 +01:00
|
|
|
JRD_REQ request;
|
2001-05-23 15:26:42 +02:00
|
|
|
BLK handle;
|
|
|
|
|
|
|
|
tdbb = GET_THREAD_DATA;
|
|
|
|
dbb = tdbb->tdbb_database;
|
|
|
|
|
|
|
|
relation = NULL;
|
|
|
|
|
|
|
|
handle = (BLK) CMP_find_request(tdbb, irq_c_trigger, IRQ_REQUESTS);
|
|
|
|
|
|
|
|
FOR(REQUEST_HANDLE handle)
|
|
|
|
X IN RDB$TRIGGERS WITH
|
|
|
|
X.RDB$TRIGGER_NAME EQ work->dfw_name
|
|
|
|
if (!REQUEST(irq_c_trigger))
|
2001-07-12 08:32:05 +02:00
|
|
|
REQUEST(irq_c_trigger) = (BLK) handle;
|
2001-05-23 15:26:42 +02:00
|
|
|
blob_id = X.RDB$TRIGGER_BLR;
|
|
|
|
relation = MET_lookup_relation(tdbb, X.RDB$RELATION_NAME);
|
|
|
|
|
|
|
|
END_FOR;
|
|
|
|
|
|
|
|
if (!REQUEST(irq_c_trigger))
|
2001-07-12 08:32:05 +02:00
|
|
|
REQUEST(irq_c_trigger) = (BLK) handle;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* get any dependencies now by parsing the blr */
|
|
|
|
|
|
|
|
if (relation && !NULL_BLOB(blob_id))
|
|
|
|
{
|
2002-09-29 00:42:48 +02:00
|
|
|
JrdMemoryPool *old_pool = tdbb->tdbb_default;
|
2002-09-29 00:37:41 +02:00
|
|
|
/* Nickolay Samofatov: allocate statement memory pool... */
|
|
|
|
tdbb->tdbb_default = FB_NEW(*dbb->dbb_permanent) JrdMemoryPool;
|
2001-05-23 15:26:42 +02:00
|
|
|
MET_get_dependencies(tdbb, relation,
|
2001-07-12 08:32:05 +02:00
|
|
|
(TEXT*)NULL_PTR,
|
2001-12-24 03:51:06 +01:00
|
|
|
(CSB)NULL_PTR,
|
2001-05-23 15:26:42 +02:00
|
|
|
(SLONG*)&blob_id,
|
|
|
|
&request,
|
2001-12-24 03:51:06 +01:00
|
|
|
(CSB*)NULL_PTR,
|
2001-05-23 15:26:42 +02:00
|
|
|
work->dfw_name,
|
|
|
|
obj_trigger);
|
2002-09-29 00:37:41 +02:00
|
|
|
if (request)
|
|
|
|
CMP_release(tdbb, request);
|
|
|
|
else
|
|
|
|
delete tdbb->tdbb_default;
|
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
tdbb->tdbb_default = old_pool;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-11-17 01:13:59 +01:00
|
|
|
static void load_trigs(TDBB tdbb, JRD_REL relation, TRIG_VEC * triggers)
|
2002-06-29 15:03:13 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* l o a d _ t r i g s
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* We have just loaded the triggers onto the local vector
|
|
|
|
* triggers. Its now time to place them at their rightful
|
|
|
|
* place ie the relation block.
|
|
|
|
*
|
|
|
|
**************************************/
|
2002-09-19 18:02:58 +02:00
|
|
|
TRIG_VEC tmp_vector;
|
2002-06-29 15:03:13 +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);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-11-17 01:13:59 +01:00
|
|
|
static FMT make_format(TDBB tdbb, JRD_REL relation, USHORT * version, TFB stack)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* m a k e _ f o r m a t
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Make a format block for a relation.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
DBB dbb;
|
|
|
|
BLK request;
|
2002-06-29 15:03:13 +02:00
|
|
|
FMT format, old_format;
|
2001-05-23 15:26:42 +02:00
|
|
|
TFB tfb;
|
|
|
|
BLB blob;
|
|
|
|
USHORT count;
|
|
|
|
ULONG offset, old_offset;
|
|
|
|
DSC *desc;
|
|
|
|
|
|
|
|
SET_TDBB(tdbb);
|
|
|
|
dbb = tdbb->tdbb_database;
|
|
|
|
|
|
|
|
/* Figure out the highest field id and allocate a format block */
|
|
|
|
|
|
|
|
count = 0;
|
|
|
|
for (tfb = stack; tfb; tfb = tfb->tfb_next)
|
|
|
|
count = MAX(count, tfb->tfb_id);
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
format = fmt::newFmt(*dbb->dbb_permanent, count + 1);
|
2001-05-23 15:26:42 +02:00
|
|
|
format->fmt_count = count + 1;
|
2002-06-29 15:03:13 +02:00
|
|
|
if (version)
|
|
|
|
format->fmt_version = *version;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* Fill in the format block from the temporary field blocks */
|
|
|
|
|
|
|
|
for (tfb = stack; tfb; tfb = tfb->tfb_next)
|
|
|
|
{
|
2001-12-24 03:51:06 +01:00
|
|
|
desc = &format->fmt_desc[tfb->tfb_id];
|
2001-05-23 15:26:42 +02:00
|
|
|
if (tfb->tfb_flags & TFB_array)
|
|
|
|
{
|
|
|
|
desc->dsc_dtype = dtype_array;
|
|
|
|
desc->dsc_length = sizeof(GDS__QUAD);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
*desc = tfb->tfb_desc;
|
|
|
|
if (tfb->tfb_flags & TFB_computed)
|
|
|
|
desc->dsc_dtype |= COMPUTED_FLAG;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Compute the offsets of the various fields */
|
|
|
|
|
|
|
|
offset = FLAG_BYTES(count);
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
count = 0;
|
|
|
|
for (fmt::fmt_desc_iterator desc2 = format->fmt_desc.begin();
|
2001-05-23 15:26:42 +02:00
|
|
|
count < format->fmt_count;
|
2001-12-24 03:51:06 +01:00
|
|
|
count++, desc2++)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2001-12-24 03:51:06 +01:00
|
|
|
if (desc2->dsc_dtype & COMPUTED_FLAG)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2001-12-24 03:51:06 +01:00
|
|
|
desc2->dsc_dtype &= ~COMPUTED_FLAG;
|
2001-05-23 15:26:42 +02:00
|
|
|
continue;
|
|
|
|
}
|
2001-12-24 03:51:06 +01:00
|
|
|
if (desc2->dsc_dtype)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
old_offset = offset;
|
2002-01-04 12:34:22 +01:00
|
|
|
offset = MET_align(&*desc2, (USHORT) offset);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* see of record too big */
|
|
|
|
|
|
|
|
if (offset < old_offset)
|
|
|
|
{
|
|
|
|
offset += 65536L;
|
|
|
|
break;
|
|
|
|
}
|
2001-12-24 03:51:06 +01:00
|
|
|
desc2->dsc_address = (UCHAR *) (SLONG) offset;
|
|
|
|
offset += desc2->dsc_length;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(offset <= MAX_USHORT);
|
|
|
|
|
|
|
|
format->fmt_length = (USHORT)offset;
|
|
|
|
|
|
|
|
/* Release the temporary field blocks */
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
while ( (tfb = stack) )
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
stack = tfb->tfb_next;
|
2001-12-24 03:51:06 +01:00
|
|
|
delete tfb;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (offset > MAX_FORMAT_SIZE)
|
|
|
|
{
|
2001-12-24 03:51:06 +01:00
|
|
|
delete format;
|
2001-07-29 19:42:23 +02:00
|
|
|
ERR_post(gds_no_meta_update,
|
|
|
|
gds_arg_gds, gds_rec_size_err,
|
2001-05-23 15:26:42 +02:00
|
|
|
gds_arg_number, (SLONG) offset,
|
2001-07-29 19:42:23 +02:00
|
|
|
gds_arg_gds, gds_table_name,
|
2001-05-23 15:26:42 +02:00
|
|
|
gds_arg_string, ERR_cstring(relation->rel_name),
|
|
|
|
0);
|
|
|
|
/* Msg361: new record size of %ld bytes is too big */
|
|
|
|
}
|
|
|
|
|
2002-06-29 15:03:13 +02:00
|
|
|
if ((format->fmt_version)
|
|
|
|
&& (old_format = MET_format(tdbb, relation, (format->fmt_version - 1)))
|
2002-07-05 17:00:26 +02:00
|
|
|
&& (formatsAreEqual(old_format, format)))
|
2002-06-29 15:03:13 +02:00
|
|
|
{
|
|
|
|
delete format;
|
|
|
|
*version = old_format->fmt_version;
|
|
|
|
return old_format;
|
|
|
|
}
|
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
/* Link the format block into the world */
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
VEC vector = relation->rel_formats;
|
|
|
|
if (!vector) {
|
2002-06-29 15:03:13 +02:00
|
|
|
vector = vec::newVector(*dbb->dbb_permanent, format->fmt_version + 1);
|
2001-12-24 03:51:06 +01:00
|
|
|
relation->rel_formats = vector;
|
|
|
|
} else {
|
2002-06-29 15:03:13 +02:00
|
|
|
vector->resize(format->fmt_version + 1);
|
2001-12-24 03:51:06 +01:00
|
|
|
}
|
2002-06-29 15:03:13 +02:00
|
|
|
(*vector)[format->fmt_version] = (BLK) format;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* Store format in system relation */
|
|
|
|
|
|
|
|
request = (BLK) CMP_find_request(tdbb, irq_format3, IRQ_REQUESTS);
|
|
|
|
|
|
|
|
STORE(REQUEST_HANDLE request)
|
|
|
|
FMT IN RDB$FORMATS
|
|
|
|
if (!REQUEST(irq_format3))
|
2001-07-12 08:32:05 +02:00
|
|
|
REQUEST(irq_format3) = (BLK) request;
|
2002-06-29 15:03:13 +02:00
|
|
|
FMT.RDB$FORMAT = format->fmt_version;
|
2001-05-23 15:26:42 +02:00
|
|
|
FMT.RDB$RELATION_ID = relation->rel_id;
|
|
|
|
blob = BLB_create(tdbb, dbb->dbb_sys_trans, (BID)&FMT.RDB$DESCRIPTOR);
|
|
|
|
BLB_put_segment(tdbb,
|
|
|
|
blob,
|
2002-01-04 12:34:22 +01:00
|
|
|
// (UCHAR*) &*(format->fmt_desc.begin()),
|
|
|
|
(UCHAR*) &(format->fmt_desc[0]),
|
2001-05-23 15:26:42 +02:00
|
|
|
(USHORT)(format->fmt_count * sizeof(struct dsc)));
|
|
|
|
BLB_close(tdbb, blob);
|
|
|
|
END_STORE;
|
|
|
|
|
|
|
|
if (!REQUEST(irq_format3))
|
2001-07-12 08:32:05 +02:00
|
|
|
REQUEST(irq_format3) = (BLK) request;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
return format;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-11-17 01:13:59 +01:00
|
|
|
static bool make_version(TDBB tdbb, SSHORT phase, DFW work, JRD_TRA transaction)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* m a k e _ v e r s i o n
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Make a new format version for a relation. While we're at it, make
|
|
|
|
* sure all fields have id's. If the relation is a view, make a
|
|
|
|
* a format anyway -- used for view updates.
|
|
|
|
*
|
|
|
|
* While we're in the vicinity, also check the updatability of fields.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
DBB dbb;
|
|
|
|
BLK request_fmt1, request_fmtx;
|
2001-12-24 03:51:06 +01:00
|
|
|
TFB stack, external, tfb_;
|
2002-11-17 01:13:59 +01:00
|
|
|
JRD_REL relation;
|
2001-05-23 15:26:42 +02:00
|
|
|
BLB blob;
|
|
|
|
GDS__QUAD blob_id;
|
|
|
|
BLK temp;
|
|
|
|
USHORT version, n, external_flag;
|
|
|
|
BOOLEAN null_view, computed_field;
|
2002-10-24 11:01:44 +02:00
|
|
|
STATUS status[ISC_STATUS_LENGTH];
|
2001-05-23 15:26:42 +02:00
|
|
|
SSHORT collation;
|
2002-09-19 18:02:58 +02:00
|
|
|
TRIG_VEC triggers[TRIGGER_MAX];
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
SET_TDBB(tdbb);
|
|
|
|
dbb = tdbb->tdbb_database;
|
|
|
|
|
|
|
|
switch (phase)
|
|
|
|
{
|
|
|
|
case 1:
|
|
|
|
case 2:
|
2001-12-24 03:51:06 +01:00
|
|
|
return true;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
case 3:
|
|
|
|
relation = NULL;
|
|
|
|
stack = external = NULL;
|
|
|
|
computed_field = FALSE;
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
for (n = 0; n < TRIGGER_MAX; n++) {
|
2002-09-19 18:02:58 +02:00
|
|
|
triggers[n] = (TRIG_VEC) NULL_PTR;
|
2001-12-24 03:51:06 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
request_fmt1 =
|
|
|
|
(BLK) CMP_find_request(tdbb, irq_format1, IRQ_REQUESTS);
|
|
|
|
|
|
|
|
FOR(REQUEST_HANDLE request_fmt1)
|
|
|
|
REL IN RDB$RELATIONS WITH REL.RDB$RELATION_NAME EQ work->dfw_name
|
2001-12-24 03:51:06 +01:00
|
|
|
if (!REQUEST(irq_format1)) {
|
2001-07-12 08:32:05 +02:00
|
|
|
REQUEST(irq_format1) = (BLK) request_fmt1;
|
2001-12-24 03:51:06 +01:00
|
|
|
}
|
|
|
|
relation =
|
|
|
|
MET_lookup_relation_id(tdbb, REL.RDB$RELATION_ID, FALSE);
|
|
|
|
if (!relation)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2002-11-17 01:13:59 +01:00
|
|
|
EXE_unwind(tdbb, (JRD_REQ)request_fmt1);
|
2001-12-24 03:51:06 +01:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
blob_id = REL.RDB$VIEW_BLR;
|
|
|
|
null_view = NULL_BLOB(blob_id);
|
|
|
|
external_flag = REL.RDB$EXTERNAL_FILE[0];
|
|
|
|
if (REL.RDB$FORMAT == 255)
|
|
|
|
{
|
2002-11-17 01:13:59 +01:00
|
|
|
EXE_unwind(tdbb, (JRD_REQ)request_fmt1);
|
2001-07-29 19:42:23 +02:00
|
|
|
ERR_post(gds_no_meta_update,
|
|
|
|
gds_arg_gds, gds_table_name,
|
2001-05-23 15:26:42 +02:00
|
|
|
gds_arg_string, ERR_cstring(work->dfw_name),
|
2001-07-29 19:42:23 +02:00
|
|
|
gds_arg_gds, gds_version_err,
|
2001-05-23 15:26:42 +02:00
|
|
|
0);
|
|
|
|
/* Msg357: too many versions */
|
|
|
|
}
|
|
|
|
MODIFY REL USING
|
|
|
|
blob = BLB_create(tdbb,
|
|
|
|
dbb->dbb_sys_trans,
|
|
|
|
(BID)&REL.RDB$RUNTIME);
|
|
|
|
request_fmtx =
|
|
|
|
(BLK) CMP_find_request(tdbb, irq_format2, IRQ_REQUESTS);
|
|
|
|
FOR(REQUEST_HANDLE request_fmtx)
|
|
|
|
RFR IN RDB$RELATION_FIELDS CROSS
|
|
|
|
FLD IN RDB$FIELDS WITH
|
|
|
|
RFR.RDB$RELATION_NAME EQ work->dfw_name AND
|
|
|
|
RFR.RDB$FIELD_SOURCE EQ FLD.RDB$FIELD_NAME
|
|
|
|
|
|
|
|
/* Update RFR to reflect new fields id */
|
|
|
|
|
|
|
|
if (!RFR.RDB$FIELD_ID.NULL &&
|
|
|
|
RFR.RDB$FIELD_ID >= REL.RDB$FIELD_ID)
|
|
|
|
REL.RDB$FIELD_ID = RFR.RDB$FIELD_ID + 1;
|
|
|
|
|
|
|
|
if (RFR.RDB$FIELD_ID.NULL || RFR.RDB$UPDATE_FLAG.NULL)
|
|
|
|
MODIFY RFR USING
|
|
|
|
if (RFR.RDB$FIELD_ID.NULL)
|
|
|
|
{
|
|
|
|
if (external_flag)
|
|
|
|
{
|
|
|
|
RFR.RDB$FIELD_ID = RFR.RDB$FIELD_POSITION;
|
|
|
|
/* RFR.RDB$FIELD_POSITION.NULL is
|
|
|
|
needed to be referenced in the
|
|
|
|
code somewhere for GPRE to include
|
|
|
|
this field in the structures that
|
|
|
|
it generates at the top of this func. */
|
|
|
|
RFR.RDB$FIELD_ID.NULL =
|
|
|
|
RFR.RDB$FIELD_POSITION.NULL;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
RFR.RDB$FIELD_ID = REL.RDB$FIELD_ID;
|
|
|
|
RFR.RDB$FIELD_ID.NULL = FALSE;
|
|
|
|
}
|
|
|
|
REL.RDB$FIELD_ID++;
|
|
|
|
}
|
|
|
|
if (RFR.RDB$UPDATE_FLAG.NULL)
|
|
|
|
{
|
|
|
|
RFR.RDB$UPDATE_FLAG.NULL = FALSE;
|
|
|
|
RFR.RDB$UPDATE_FLAG = 1;
|
|
|
|
if (!NULL_BLOB(FLD.RDB$COMPUTED_BLR))
|
|
|
|
{
|
|
|
|
RFR.RDB$UPDATE_FLAG = 0;
|
|
|
|
computed_field = TRUE;
|
|
|
|
}
|
|
|
|
if (!null_view && REL.RDB$DBKEY_LENGTH > 8)
|
|
|
|
{
|
|
|
|
temp = NULL;
|
|
|
|
RFR.RDB$UPDATE_FLAG = 0;
|
|
|
|
FOR(REQUEST_HANDLE temp) X IN RDB$TRIGGERS WITH
|
|
|
|
X.RDB$RELATION_NAME EQ work->dfw_name AND
|
|
|
|
X.RDB$TRIGGER_TYPE EQ 1
|
|
|
|
RFR.RDB$UPDATE_FLAG = 1;
|
|
|
|
END_FOR;
|
2002-11-17 01:13:59 +01:00
|
|
|
CMP_release(tdbb, (JRD_REQ)temp);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
END_MODIFY;
|
|
|
|
|
|
|
|
/* Store stuff in field summary */
|
|
|
|
|
|
|
|
n = RFR.RDB$FIELD_ID;
|
|
|
|
put_summary_record(blob, RSR_field_id, (UCHAR*)&n, sizeof(n));
|
|
|
|
put_summary_record(blob, RSR_field_name,
|
2001-07-12 08:32:05 +02:00
|
|
|
(UCHAR*) RFR.RDB$FIELD_NAME,
|
2001-05-23 15:26:42 +02:00
|
|
|
name_length(RFR.RDB$FIELD_NAME));
|
|
|
|
if (!NULL_BLOB(FLD.RDB$COMPUTED_BLR)
|
|
|
|
&& !RFR.RDB$VIEW_CONTEXT)
|
|
|
|
{
|
|
|
|
put_summary_blob(blob,
|
|
|
|
RSR_computed_blr,
|
|
|
|
(SLONG*)&FLD.RDB$COMPUTED_BLR);
|
|
|
|
}
|
|
|
|
else if (!null_view)
|
|
|
|
{
|
|
|
|
n = RFR.RDB$VIEW_CONTEXT;
|
|
|
|
put_summary_record(blob,
|
|
|
|
RSR_view_context,
|
|
|
|
(UCHAR*)&n,
|
|
|
|
sizeof(n));
|
|
|
|
put_summary_record(blob, RSR_base_field,
|
2001-07-12 08:32:05 +02:00
|
|
|
(UCHAR*) RFR.RDB$BASE_FIELD,
|
2001-05-23 15:26:42 +02:00
|
|
|
name_length(RFR.RDB$BASE_FIELD));
|
|
|
|
}
|
|
|
|
put_summary_blob(blob, RSR_missing_value,
|
|
|
|
(SLONG*)&FLD.RDB$MISSING_VALUE);
|
|
|
|
put_summary_blob(blob, RSR_default_value,
|
|
|
|
(SLONG*)((NULL_BLOB(RFR.RDB$DEFAULT_VALUE)) ?
|
|
|
|
&FLD.RDB$DEFAULT_VALUE :
|
|
|
|
&RFR.RDB$DEFAULT_VALUE));
|
|
|
|
put_summary_blob(blob, RSR_validation_blr,
|
|
|
|
(SLONG*)&FLD.RDB$VALIDATION_BLR);
|
|
|
|
if (FLD.RDB$NULL_FLAG || RFR.RDB$NULL_FLAG)
|
|
|
|
{
|
|
|
|
put_summary_record(blob,
|
|
|
|
RSR_field_not_null,
|
|
|
|
(UCHAR*)nonnull_validation_blr,
|
|
|
|
sizeof(nonnull_validation_blr));
|
|
|
|
}
|
|
|
|
|
|
|
|
n = name_length(RFR.RDB$SECURITY_CLASS);
|
|
|
|
if (!RFR.RDB$SECURITY_CLASS.NULL && n)
|
|
|
|
put_summary_record(blob, RSR_security_class,
|
2001-07-12 08:32:05 +02:00
|
|
|
(UCHAR*) RFR.RDB$SECURITY_CLASS, n);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* Make a temporary field block */
|
|
|
|
|
2002-09-25 19:12:16 +02:00
|
|
|
tfb_ = FB_NEW(*tdbb->tdbb_default) tfb;
|
2001-12-24 03:51:06 +01:00
|
|
|
tfb_->tfb_next = stack;
|
|
|
|
stack = tfb_;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* for text data types, grab the CHARACTER_SET and
|
|
|
|
COLLATION to give the type of international text */
|
|
|
|
|
|
|
|
if (FLD.RDB$CHARACTER_SET_ID.NULL)
|
|
|
|
FLD.RDB$CHARACTER_SET_ID = CS_NONE;
|
|
|
|
|
|
|
|
collation = COLLATE_NONE; /* codepoint collation */
|
|
|
|
if (!FLD.RDB$COLLATION_ID.NULL)
|
|
|
|
collation = FLD.RDB$COLLATION_ID;
|
|
|
|
if (!RFR.RDB$COLLATION_ID.NULL)
|
|
|
|
collation = RFR.RDB$COLLATION_ID;
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
DSC_make_descriptor(&tfb_->tfb_desc, FLD.RDB$FIELD_TYPE,
|
2001-05-23 15:26:42 +02:00
|
|
|
FLD.RDB$FIELD_SCALE,
|
|
|
|
FLD.RDB$FIELD_LENGTH,
|
|
|
|
FLD.RDB$FIELD_SUB_TYPE,
|
|
|
|
FLD.RDB$CHARACTER_SET_ID, collation);
|
|
|
|
|
|
|
|
/* Make sure the text type specified is implemented */
|
2002-07-05 17:00:26 +02:00
|
|
|
if (!(validate_text_type(tdbb, status, tfb_)))
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2002-11-17 01:13:59 +01:00
|
|
|
EXE_unwind(tdbb, (JRD_REQ)request_fmt1);
|
|
|
|
EXE_unwind(tdbb, (JRD_REQ)request_fmtx);
|
2001-07-29 19:42:23 +02:00
|
|
|
ERR_post(gds_no_meta_update,
|
|
|
|
gds_arg_gds, gds_random,
|
2001-05-23 15:26:42 +02:00
|
|
|
gds_arg_string, ERR_cstring(work->dfw_name),
|
|
|
|
status[0], status[1], status[2], status[3],
|
|
|
|
0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!NULL_BLOB(FLD.RDB$COMPUTED_BLR))
|
2001-12-24 03:51:06 +01:00
|
|
|
tfb_->tfb_flags |= TFB_computed;
|
|
|
|
tfb_->tfb_id = RFR.RDB$FIELD_ID;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2002-06-29 15:03:13 +02:00
|
|
|
if ((n = FLD.RDB$DIMENSIONS))
|
2002-07-05 17:00:26 +02:00
|
|
|
setup_array(tdbb, blob, FLD.RDB$FIELD_NAME, n, tfb_);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (external_flag)
|
|
|
|
{
|
2002-09-25 19:12:16 +02:00
|
|
|
tfb_ = FB_NEW(*tdbb->tdbb_default) tfb;
|
2001-12-24 03:51:06 +01:00
|
|
|
tfb_->tfb_next = external;
|
|
|
|
external = tfb_;
|
2001-05-23 15:26:42 +02:00
|
|
|
assert(FLD.RDB$EXTERNAL_TYPE <= MAX_UCHAR);
|
2001-12-24 03:51:06 +01:00
|
|
|
tfb_->tfb_desc.dsc_dtype = (UCHAR)FLD.RDB$EXTERNAL_TYPE;
|
2001-05-23 15:26:42 +02:00
|
|
|
assert(FLD.RDB$EXTERNAL_SCALE >= MIN_SCHAR &&
|
|
|
|
FLD.RDB$EXTERNAL_SCALE <= MAX_SCHAR);
|
2001-12-24 03:51:06 +01:00
|
|
|
tfb_->tfb_desc.dsc_scale = (SCHAR)FLD.RDB$EXTERNAL_SCALE;
|
|
|
|
tfb_->tfb_desc.dsc_length = FLD.RDB$EXTERNAL_LENGTH;
|
|
|
|
tfb_->tfb_id = RFR.RDB$FIELD_ID;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
END_FOR;
|
|
|
|
|
|
|
|
if (!REQUEST(irq_format2))
|
2001-07-12 08:32:05 +02:00
|
|
|
REQUEST(irq_format2) = (BLK) request_fmtx;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2002-06-29 15:03:13 +02:00
|
|
|
blob = setup_triggers(tdbb, relation, null_view, triggers, blob);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
BLB_close(tdbb, blob);
|
2002-06-29 15:03:13 +02:00
|
|
|
version = REL.RDB$FORMAT;
|
|
|
|
version++;
|
|
|
|
relation->rel_current_format = make_format(tdbb, relation,
|
|
|
|
&version, stack);
|
|
|
|
REL.RDB$FORMAT = version;
|
2001-05-23 15:26:42 +02:00
|
|
|
END_MODIFY;
|
|
|
|
END_FOR;
|
|
|
|
|
|
|
|
if (!REQUEST(irq_format1))
|
2001-07-12 08:32:05 +02:00
|
|
|
REQUEST(irq_format1) = (BLK) request_fmt1;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* If we didn't find the relation, it is probably being dropped */
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
if (!relation) {
|
|
|
|
return false;
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (!(relation->rel_flags & REL_sys_trigs_being_loaded))
|
2002-06-29 15:03:13 +02:00
|
|
|
load_trigs(tdbb, relation, triggers);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* in case somebody changed the view definition or a computed
|
|
|
|
field, reset the dependencies by deleting the current ones
|
|
|
|
and setting a flag for MET_scan_relation to find the new ones */
|
|
|
|
|
|
|
|
if (!null_view)
|
|
|
|
MET_delete_dependencies(tdbb, work->dfw_name, obj_view);
|
|
|
|
|
|
|
|
if (!null_view || computed_field)
|
|
|
|
relation->rel_flags |= REL_get_dependencies;
|
|
|
|
|
|
|
|
if (external_flag)
|
|
|
|
{
|
|
|
|
temp = NULL;
|
|
|
|
FOR(REQUEST_HANDLE temp) FMT IN RDB$FORMATS WITH
|
|
|
|
FMT.RDB$RELATION_ID EQ relation->rel_id AND
|
|
|
|
FMT.RDB$FORMAT EQ 0
|
|
|
|
ERASE FMT;
|
|
|
|
END_FOR;
|
2002-11-17 01:13:59 +01:00
|
|
|
CMP_release(tdbb, (JRD_REQ)temp);
|
2001-05-23 15:26:42 +02:00
|
|
|
make_format(tdbb, relation, 0, external);
|
|
|
|
}
|
|
|
|
|
|
|
|
relation->rel_flags &= ~REL_scanned;
|
2001-07-12 08:32:05 +02:00
|
|
|
DFW_post_work(transaction, dfw_scan_relation, (DSC*) NULL_PTR,
|
2001-05-23 15:26:42 +02:00
|
|
|
relation->rel_id);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
static bool modify_procedure( TDBB tdbb,
|
2001-05-23 15:26:42 +02:00
|
|
|
SSHORT phase,
|
|
|
|
DFW work,
|
2002-11-17 01:13:59 +01:00
|
|
|
JRD_TRA transaction)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* m o d i f y _ p r o c e d u r e
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Perform required actions when modifying procedure.
|
|
|
|
*
|
|
|
|
**************************************/
|
2002-11-17 01:13:59 +01:00
|
|
|
JRD_PRC procedure;
|
2001-05-23 15:26:42 +02:00
|
|
|
USHORT wait;
|
|
|
|
|
|
|
|
SET_TDBB(tdbb);
|
|
|
|
|
|
|
|
switch (phase)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
{
|
|
|
|
procedure = MET_lookup_procedure_id(tdbb,
|
|
|
|
work->dfw_id,
|
|
|
|
FALSE,
|
2002-11-04 16:12:34 +01:00
|
|
|
TRUE,
|
2001-05-23 15:26:42 +02:00
|
|
|
0);
|
2001-12-24 03:51:06 +01:00
|
|
|
if (!procedure) {
|
|
|
|
return false;
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
wait = (transaction->tra_flags & TRA_nowait) ? FALSE : TRUE;
|
|
|
|
LCK_convert_non_blocking(tdbb, procedure->prc_existence_lock, LCK_SR,
|
|
|
|
wait);
|
2001-12-24 03:51:06 +01:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
case 1:
|
2001-12-24 03:51:06 +01:00
|
|
|
return true;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
case 2:
|
2001-12-24 03:51:06 +01:00
|
|
|
return true;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
case 3:
|
2002-11-04 16:12:34 +01:00
|
|
|
procedure = MET_lookup_procedure_id(tdbb, work->dfw_id, FALSE, TRUE, 0);
|
2001-12-24 03:51:06 +01:00
|
|
|
if (!procedure) {
|
|
|
|
return false;
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
wait = (transaction->tra_flags & TRA_nowait) ? FALSE : TRUE;
|
|
|
|
|
|
|
|
/* Let relation be deleted if only this transaction is using it */
|
|
|
|
|
|
|
|
if (!LCK_convert_non_blocking(tdbb, procedure->prc_existence_lock,
|
|
|
|
LCK_EX, wait))
|
2001-12-24 03:51:06 +01:00
|
|
|
{
|
2001-07-29 19:42:23 +02:00
|
|
|
ERR_post(gds_no_meta_update,
|
|
|
|
gds_arg_gds, gds_obj_in_use,
|
2001-05-23 15:26:42 +02:00
|
|
|
gds_arg_string, ERR_cstring(work->dfw_name),
|
|
|
|
0);
|
2001-12-24 03:51:06 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* If we are in a multi-client server, someone else may have marked
|
|
|
|
procedure obsolete. Unmark and we will remark it later. */
|
|
|
|
|
|
|
|
procedure->prc_flags &= ~PRC_obsolete;
|
2001-12-24 03:51:06 +01:00
|
|
|
return true;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
case 4:
|
2002-11-04 16:12:34 +01:00
|
|
|
procedure = MET_lookup_procedure_id(tdbb, work->dfw_id, FALSE, TRUE, 0);
|
2001-12-24 03:51:06 +01:00
|
|
|
if (!procedure) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
#ifdef SUPERSERVER
|
|
|
|
if (!(tdbb->tdbb_database->dbb_flags & DBB_sp_rec_mutex_init))
|
|
|
|
{
|
|
|
|
THD_rec_mutex_init(&tdbb->tdbb_database->dbb_sp_rec_mutex);
|
|
|
|
tdbb->tdbb_database->dbb_flags |= DBB_sp_rec_mutex_init;
|
|
|
|
}
|
|
|
|
THREAD_EXIT;
|
|
|
|
if (THD_rec_mutex_lock(&tdbb->tdbb_database->dbb_sp_rec_mutex))
|
|
|
|
{
|
|
|
|
THREAD_ENTER;
|
2001-12-24 03:51:06 +01:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
THREAD_ENTER;
|
|
|
|
#endif /* SUPERSERVER */
|
2002-11-14 14:39:02 +01:00
|
|
|
if (procedure->prc_use_count && !MET_clear_cache(tdbb,procedure))
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2002-10-05 00:08:43 +02:00
|
|
|
gds__log("Modifying unfreed procedure %s",work->dfw_name);
|
2001-05-23 15:26:42 +02:00
|
|
|
USHORT prc_alter_count = procedure->prc_alter_count;
|
|
|
|
if (prc_alter_count > MAX_PROC_ALTER)
|
|
|
|
{
|
2001-07-29 19:42:23 +02:00
|
|
|
ERR_post(gds_no_meta_update,
|
|
|
|
gds_arg_gds, gds_proc_name,
|
2001-05-23 15:26:42 +02:00
|
|
|
gds_arg_string, ERR_cstring(work->dfw_name),
|
2001-07-29 19:42:23 +02:00
|
|
|
gds_arg_gds, gds_version_err,
|
2001-05-23 15:26:42 +02:00
|
|
|
0);
|
|
|
|
/* Msg357: too many versions */
|
|
|
|
}
|
|
|
|
LCK_release(tdbb, procedure->prc_existence_lock);
|
2001-12-24 03:51:06 +01:00
|
|
|
(*tdbb->tdbb_database->dbb_procedures)
|
|
|
|
[procedure->prc_id] = (BLK) NULL_PTR;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (!(procedure = MET_lookup_procedure_id(tdbb,
|
|
|
|
work->dfw_id,
|
|
|
|
FALSE,
|
2002-11-04 16:12:34 +01:00
|
|
|
TRUE,
|
2001-05-23 15:26:42 +02:00
|
|
|
PRC_being_altered)))
|
|
|
|
{
|
|
|
|
#ifdef SUPERSERVER
|
|
|
|
THD_rec_mutex_unlock(&tdbb->tdbb_database->dbb_sp_rec_mutex);
|
|
|
|
#endif
|
2001-12-24 03:51:06 +01:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
procedure->prc_alter_count = ++prc_alter_count;
|
|
|
|
}
|
|
|
|
|
|
|
|
procedure->prc_flags |= PRC_being_altered;
|
|
|
|
if (procedure->prc_request)
|
|
|
|
{
|
|
|
|
if (CMP_clone_active(procedure->prc_request))
|
2001-07-29 19:42:23 +02:00
|
|
|
ERR_post(gds_no_meta_update,
|
|
|
|
gds_arg_gds, gds_obj_in_use,
|
2001-05-23 15:26:42 +02:00
|
|
|
gds_arg_string, ERR_cstring(work->dfw_name),
|
|
|
|
0);
|
|
|
|
|
|
|
|
/* release the request */
|
|
|
|
|
|
|
|
CMP_release(tdbb, procedure->prc_request);
|
|
|
|
procedure->prc_request = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* delete dependency lists */
|
|
|
|
|
|
|
|
MET_delete_dependencies(tdbb, work->dfw_name, obj_procedure);
|
|
|
|
|
|
|
|
/* the procedure has just been scanned by MET_lookup_procedure_id
|
|
|
|
and its PRC_scanned flag is set. We are going to reread it
|
|
|
|
from file (create all new dependencies) and do not want this
|
|
|
|
flag to be set. That is why we do not add PRC_obsolete and
|
|
|
|
PRC_being_altered flags, we set only these two flags
|
|
|
|
*/
|
|
|
|
procedure->prc_flags = (PRC_obsolete | PRC_being_altered);
|
|
|
|
|
|
|
|
if (procedure->prc_existence_lock)
|
|
|
|
LCK_release(tdbb, procedure->prc_existence_lock);
|
|
|
|
|
|
|
|
/* remove procedure from cache */
|
|
|
|
|
|
|
|
MET_remove_procedure(tdbb, work->dfw_id, NULL);
|
|
|
|
|
|
|
|
/* Now handle the new definition */
|
|
|
|
|
|
|
|
get_procedure_dependencies(work);
|
|
|
|
|
|
|
|
procedure->prc_flags &= ~(PRC_obsolete | PRC_being_altered);
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
} // try
|
|
|
|
catch (...)
|
|
|
|
{
|
|
|
|
#ifdef SUPERSERVER
|
|
|
|
THD_rec_mutex_unlock(&tdbb->tdbb_database->dbb_sp_rec_mutex);
|
|
|
|
#endif
|
|
|
|
ERR_punt();
|
|
|
|
}
|
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
#ifdef SUPERSERVER
|
|
|
|
THD_rec_mutex_unlock(&tdbb->tdbb_database->dbb_sp_rec_mutex);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-11-17 01:13:59 +01:00
|
|
|
static bool modify_trigger(TDBB tdbb, SSHORT phase, DFW work, JRD_TRA transaction)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* m o d i f y _ t r i g g e r
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Perform required actions when modifying trigger.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
|
|
|
SET_TDBB(tdbb);
|
|
|
|
|
|
|
|
switch (phase)
|
|
|
|
{
|
|
|
|
case 1:
|
|
|
|
case 2:
|
2001-12-24 03:51:06 +01:00
|
|
|
return true;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
case 3:
|
|
|
|
/* get rid of old dependencies, bring in the new */
|
|
|
|
|
|
|
|
MET_delete_dependencies(tdbb, work->dfw_name, obj_trigger);
|
|
|
|
get_trigger_dependencies(work);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
static USHORT name_length(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.
|
|
|
|
* Trailing blanks are ignored.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
TEXT* q = name - 1;
|
|
|
|
for (TEXT* p = name; *p; p++) {
|
|
|
|
if (*p != ' ') {
|
2001-05-23 15:26:42 +02:00
|
|
|
q = p;
|
2001-12-24 03:51:06 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return ((q + 1) - name);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
static void put_summary_blob(BLB blob, RSR_T type, SLONG blob_id[2])
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* p u t _ s u m m a r y _ b l o b
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Put an attribute record to the relation summary blob.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
UCHAR temp[128];
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
TDBB tdbb = GET_THREAD_DATA;
|
|
|
|
DBB dbb = tdbb->tdbb_database;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
/* If blob is null, don't both */
|
|
|
|
|
|
|
|
if (!blob_id[0] && !blob_id[1]) {
|
2001-05-23 15:26:42 +02:00
|
|
|
return;
|
2001-12-24 03:51:06 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
// Go ahead and open blob
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
BLB blr = BLB_open(tdbb, dbb->dbb_sys_trans, (BID)blob_id);
|
2001-05-23 15:26:42 +02:00
|
|
|
assert(blr->blb_length <= MAX_USHORT);
|
2001-12-24 03:51:06 +01:00
|
|
|
USHORT length = (USHORT)blr->blb_length;
|
|
|
|
UCHAR* buffer = (length > sizeof(temp)) ?
|
|
|
|
(UCHAR*) MemoryPool::malloc_from_system((SLONG) blr->blb_length) : temp;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
// Setup to cleanup after any error that may occur
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
try {
|
|
|
|
length = (USHORT)BLB_get_data(tdbb, blr, buffer, (SLONG) length);
|
|
|
|
put_summary_record(blob, type, buffer, length);
|
|
|
|
}
|
|
|
|
catch (...) {
|
|
|
|
if (buffer != temp) {
|
|
|
|
MemoryPool::free_from_system(buffer);
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
ERR_punt();
|
|
|
|
}
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
if (buffer != temp) {
|
|
|
|
MemoryPool::free_from_system(buffer);
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
static void put_summary_record(BLB blob,
|
|
|
|
RSR_T type,
|
|
|
|
UCHAR* data,
|
|
|
|
USHORT length)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* p u t _ s u m m a r y _ r e c o r d
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Put an attribute record to the relation summary blob.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
TDBB tdbb = GET_THREAD_DATA;
|
|
|
|
UCHAR temp[129];
|
|
|
|
|
|
|
|
UCHAR* buffer = (length + 1 > sizeof(temp)) ?
|
|
|
|
(UCHAR *) MemoryPool::malloc_from_system((SLONG) (length + 1)) : temp;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
UCHAR* p = buffer;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
*p++ = (UCHAR) type;
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
if (length) {
|
|
|
|
do {
|
2001-05-23 15:26:42 +02:00
|
|
|
*p++ = *data++;
|
2001-12-24 03:51:06 +01:00
|
|
|
} while (--length);
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
try {
|
|
|
|
BLB_put_segment(tdbb, blob, buffer, (USHORT)(p - buffer));
|
|
|
|
}
|
|
|
|
catch (...) {
|
|
|
|
if (buffer != temp) {
|
|
|
|
MemoryPool::free_from_system(buffer);
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
ERR_punt();
|
|
|
|
}
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
if (buffer != temp) {
|
|
|
|
MemoryPool::free_from_system(buffer);
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-11-17 01:13:59 +01:00
|
|
|
static bool scan_relation(TDBB tdbb, SSHORT phase, DFW work, JRD_TRA transaction)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* s c a n _ r e l a t i o n
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Call MET_scan_relation with the appropriate
|
|
|
|
* relation.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
|
|
|
SET_TDBB(tdbb);
|
|
|
|
|
|
|
|
switch (phase)
|
|
|
|
{
|
|
|
|
case 1:
|
|
|
|
case 2:
|
2001-12-24 03:51:06 +01:00
|
|
|
return true;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
case 3:
|
|
|
|
MET_scan_relation(tdbb, MET_relation(tdbb, work->dfw_id));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
static bool shadow_defined(TDBB tdbb)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* s h a d o w _ d e f i n e d
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Return TRUE if any shadows have been has been defined
|
|
|
|
* for the database else return FALSE.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
|
|
|
SET_TDBB(tdbb);
|
2001-12-24 03:51:06 +01:00
|
|
|
DBB dbb = tdbb->tdbb_database;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
bool result = false;
|
|
|
|
BLK handle = NULL;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
FOR(REQUEST_HANDLE handle) FIRST 1 X IN RDB$FILES
|
|
|
|
WITH X.RDB$SHADOW_NUMBER > 0
|
2001-12-24 03:51:06 +01:00
|
|
|
result = true;
|
2001-05-23 15:26:42 +02:00
|
|
|
END_FOR
|
|
|
|
|
2002-11-17 01:13:59 +01:00
|
|
|
CMP_release(tdbb, (JRD_REQ)handle);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-07-05 17:00:26 +02:00
|
|
|
static void setup_array(TDBB tdbb, BLB blob, TEXT* field_name, USHORT n, TFB tfb)
|
2002-06-29 15:03:13 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* s e t u p _ a r r a y
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
*
|
|
|
|
* setup an array descriptor in a tfb
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
|
|
|
SLONG stuff[64];
|
|
|
|
ADS array;
|
|
|
|
|
2002-07-05 17:00:26 +02:00
|
|
|
put_summary_record(blob, RSR_dimensions, (UCHAR*) &n, sizeof(n));
|
2002-06-29 15:03:13 +02:00
|
|
|
tfb->tfb_flags |= TFB_array;
|
|
|
|
array = reinterpret_cast<ADS>(stuff);
|
|
|
|
MOVE_CLEAR(array, (SLONG) sizeof(struct ads));
|
|
|
|
array->ads_dimensions = n;
|
|
|
|
array->ads_struct_count = 1;
|
|
|
|
array->ads_rpt[0].ads_desc = tfb->tfb_desc;
|
|
|
|
get_array_desc(tdbb, field_name, array);
|
2002-07-05 17:00:26 +02:00
|
|
|
put_summary_record(blob, RSR_array_desc, (UCHAR*) array, array->ads_length);
|
2002-06-29 15:03:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-11-17 01:13:59 +01:00
|
|
|
static BLB setup_triggers(TDBB tdbb, JRD_REL relation, BOOLEAN null_view, TRIG_VEC * triggers, BLB blob)
|
2002-06-29 15:03:13 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* s e t u p _ t r i g g e r s
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
*
|
|
|
|
* Get the triggers in the right order, which appears
|
|
|
|
* to be system triggers first, then user triggers,
|
|
|
|
* then triggers that implement check constraints.
|
|
|
|
*
|
|
|
|
* BUG #8458: Check constraint triggers have to be loaded
|
|
|
|
* (and hence executed) after the user-defined
|
|
|
|
* triggers because user-defined triggers can modify
|
|
|
|
* the values being inserted or updated so that
|
|
|
|
* the end values stored in the database don't
|
|
|
|
* fulfill the check constraint. .
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
BLK request_fmtx;
|
|
|
|
DBB dbb;
|
|
|
|
|
|
|
|
if (!relation)
|
|
|
|
return blob;
|
|
|
|
|
|
|
|
dbb = tdbb->tdbb_database;
|
|
|
|
|
|
|
|
|
|
|
|
/* system triggers */
|
|
|
|
|
|
|
|
request_fmtx = (BLK) CMP_find_request(tdbb, irq_format4, IRQ_REQUESTS);
|
|
|
|
|
|
|
|
FOR (REQUEST_HANDLE request_fmtx)
|
|
|
|
TRG IN RDB$TRIGGERS
|
|
|
|
WITH TRG.RDB$RELATION_NAME = relation->rel_name
|
|
|
|
AND TRG.RDB$SYSTEM_FLAG = 1
|
|
|
|
SORTED BY TRG.RDB$TRIGGER_SEQUENCE
|
|
|
|
|
|
|
|
if (!TRG.RDB$TRIGGER_INACTIVE)
|
|
|
|
setup_trigger_details(tdbb, relation, blob, triggers,
|
|
|
|
TRG.RDB$TRIGGER_NAME, TRG.RDB$RELATION_NAME, null_view);
|
|
|
|
END_FOR;
|
|
|
|
|
|
|
|
if (!REQUEST(irq_format4))
|
|
|
|
REQUEST(irq_format4) = request_fmtx;
|
|
|
|
|
|
|
|
|
|
|
|
/* user triggers */
|
|
|
|
|
|
|
|
request_fmtx = (BLK) CMP_find_request(tdbb, irq_format5, IRQ_REQUESTS);
|
|
|
|
|
|
|
|
FOR (REQUEST_HANDLE request_fmtx)
|
|
|
|
TRG IN RDB$TRIGGERS
|
|
|
|
WITH TRG.RDB$RELATION_NAME EQ relation->rel_name
|
|
|
|
AND (TRG.RDB$SYSTEM_FLAG = 0 OR TRG.RDB$SYSTEM_FLAG MISSING)
|
|
|
|
AND (NOT ANY
|
|
|
|
CHK IN RDB$CHECK_CONSTRAINTS CROSS
|
|
|
|
RCN IN RDB$RELATION_CONSTRAINTS
|
|
|
|
WITH TRG.RDB$TRIGGER_NAME EQ CHK.RDB$TRIGGER_NAME
|
|
|
|
AND CHK.RDB$CONSTRAINT_NAME EQ RCN.RDB$CONSTRAINT_NAME
|
|
|
|
AND (RCN.RDB$CONSTRAINT_TYPE EQ "CHECK"
|
|
|
|
OR RCN.RDB$CONSTRAINT_TYPE EQ "FOREIGN KEY")
|
|
|
|
)
|
|
|
|
SORTED BY TRG.RDB$TRIGGER_SEQUENCE
|
|
|
|
|
|
|
|
if (!TRG.RDB$TRIGGER_INACTIVE)
|
|
|
|
setup_trigger_details(tdbb, relation, blob, triggers,
|
|
|
|
TRG.RDB$TRIGGER_NAME, TRG.RDB$RELATION_NAME, null_view);
|
|
|
|
END_FOR;
|
|
|
|
|
|
|
|
if (!REQUEST(irq_format5))
|
|
|
|
REQUEST(irq_format5) = request_fmtx;
|
|
|
|
|
|
|
|
|
|
|
|
/* check constraint triggers */
|
|
|
|
|
|
|
|
request_fmtx = (BLK) CMP_find_request(tdbb, irq_format6, IRQ_REQUESTS);
|
|
|
|
|
|
|
|
FOR (REQUEST_HANDLE request_fmtx)
|
|
|
|
TRG IN RDB$TRIGGERS
|
|
|
|
WITH TRG.RDB$RELATION_NAME = relation->rel_name
|
|
|
|
AND (TRG.RDB$SYSTEM_FLAG BT 3 AND 5
|
|
|
|
OR ((TRG.RDB$SYSTEM_FLAG = 0 OR TRG.RDB$SYSTEM_FLAG MISSING)
|
|
|
|
AND ANY
|
|
|
|
CHK IN RDB$CHECK_CONSTRAINTS CROSS
|
|
|
|
RCN IN RDB$RELATION_CONSTRAINTS
|
|
|
|
WITH TRG.RDB$TRIGGER_NAME EQ CHK.RDB$TRIGGER_NAME
|
|
|
|
AND CHK.RDB$CONSTRAINT_NAME EQ RCN.RDB$CONSTRAINT_NAME
|
|
|
|
AND (RCN.RDB$CONSTRAINT_TYPE EQ "CHECK"
|
|
|
|
OR RCN.RDB$CONSTRAINT_TYPE EQ "FOREIGN KEY")
|
|
|
|
)
|
|
|
|
)
|
|
|
|
SORTED BY TRG.RDB$TRIGGER_SEQUENCE
|
|
|
|
|
|
|
|
if (!TRG.RDB$TRIGGER_INACTIVE)
|
|
|
|
setup_trigger_details(tdbb, relation, blob, triggers,
|
|
|
|
TRG.RDB$TRIGGER_NAME, TRG.RDB$RELATION_NAME, null_view);
|
|
|
|
END_FOR;
|
|
|
|
|
|
|
|
if (!REQUEST(irq_format6))
|
|
|
|
REQUEST(irq_format6) = request_fmtx;
|
|
|
|
|
|
|
|
return blob;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void setup_trigger_details(TDBB tdbb,
|
2002-11-17 01:13:59 +01:00
|
|
|
JRD_REL relation,
|
2002-06-29 15:03:13 +02:00
|
|
|
BLB blob,
|
2002-09-19 18:02:58 +02:00
|
|
|
TRIG_VEC * triggers,
|
2002-07-05 17:00:26 +02:00
|
|
|
TEXT * trigger_name,
|
|
|
|
TEXT * relation_name,
|
2002-06-29 15:03:13 +02:00
|
|
|
BOOLEAN null_view)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* s e t u p _ t r i g g e r _ d e t a i l s
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Stuff trigger details in places.
|
|
|
|
*
|
|
|
|
* for a view, load the trigger temporarily --
|
|
|
|
* this is inefficient since it will just be reloaded
|
|
|
|
* in MET_scan_relation () but it needs to be done
|
|
|
|
* in case the view would otherwise be non-updatable
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
|
|
|
put_summary_record(blob, RSR_trigger_name,
|
2002-07-05 17:00:26 +02:00
|
|
|
(UCHAR*) trigger_name, name_length(trigger_name));
|
2002-06-29 15:03:13 +02:00
|
|
|
|
2002-07-05 17:00:26 +02:00
|
|
|
if (!null_view) {
|
2002-06-29 15:03:13 +02:00
|
|
|
if (!relation->rel_name)
|
|
|
|
relation->rel_name = MET_save_name(tdbb, relation_name);
|
|
|
|
MET_load_trigger(tdbb, relation, trigger_name, triggers);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static bool validate_text_type(TDBB tdbb, STATUS * status, TFB tfb)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* v a l i d a t e _ t e x t _ t y p e
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Make sure the text type specified is implemented
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
|
|
|
if ((IS_DTYPE_ANY_TEXT (tfb->tfb_desc.dsc_dtype) &&
|
|
|
|
!INTL_defined_type(tdbb, status, tfb->tfb_desc.dsc_ttype))
|
|
|
|
||
|
|
|
|
(tfb->tfb_desc.dsc_dtype == dtype_blob &&
|
|
|
|
tfb->tfb_desc.dsc_sub_type == BLOB_text &&
|
|
|
|
!INTL_defined_type(tdbb, status, tfb->tfb_desc.dsc_scale)))
|
|
|
|
return false;
|
|
|
|
else
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
static bool wal_defined(TDBB tdbb)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* w a l _ d e f i n e d
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Return TRUE if Writ_ahead Log (WAL) has been defined
|
|
|
|
* for the database else return FALSE.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
|
|
|
SET_TDBB(tdbb);
|
2001-12-24 03:51:06 +01:00
|
|
|
DBB dbb = tdbb->tdbb_database;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
bool result = false;
|
|
|
|
BLK handle = NULL;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
FOR(REQUEST_HANDLE handle) FIRST 1 X IN RDB$LOG_FILES
|
2001-12-24 03:51:06 +01:00
|
|
|
result = true;
|
2001-05-23 15:26:42 +02:00
|
|
|
END_FOR
|
|
|
|
|
2002-11-17 01:13:59 +01:00
|
|
|
CMP_release(tdbb, (JRD_REQ)handle);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|