8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-25 00:03:03 +01:00
firebird-mirror/src/jrd/dyn_util.epp
alexpeshkoff 7fed9ff78c cleanup
2015-03-05 16:18:46 +00:00

557 lines
13 KiB
Plaintext

/*
* PROGRAM: JRD Data Definition Utility
* MODULE: dyn_util.epp
* DESCRIPTION: Dynamic data definition - utility functions
*
* The contents of this file are subject to the Interbase Public
* License Version 1.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy
* of the License at http://www.Inprise.com/IPL.html
*
* Software distributed under the License is distributed on an
* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express
* or implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code was created by Inprise Corporation
* and its predecessors. Portions created by Inprise Corporation are
* Copyright (C) Inprise Corporation.
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
*
* 2002-02-24 Sean Leyne - Code Cleanup of old Win 3.1 port (WINDOWS_ONLY)
*
*/
#include "firebird.h"
#include "dyn_consts.h"
#include <stdio.h>
#include <string.h>
#include "../jrd/jrd.h"
#include "../jrd/tra.h"
#include "../jrd/scl.h"
#include "../jrd/drq.h"
#include "../jrd/flags.h"
#include "../jrd/lls.h"
#include "../jrd/met.h"
#include "../jrd/btr.h"
#include "../jrd/intl.h"
#include "../jrd/dyn.h"
#include "../jrd/ods.h"
#include "../jrd/blb_proto.h"
#include "../jrd/cmp_proto.h"
#include "../jrd/dyn_ut_proto.h"
#include "../jrd/err_proto.h"
#include "../jrd/exe_proto.h"
#include "../yvalve/gds_proto.h"
#include "../jrd/inf_proto.h"
#include "../jrd/intl_proto.h"
#include "../common/isc_f_proto.h"
#include "../jrd/vio_proto.h"
#include "../common/utils_proto.h"
using MsgFormat::SafeArg;
using namespace Firebird;
using namespace Jrd;
DATABASE DB = STATIC "ODS.RDB";
static const UCHAR gen_id_blr1[] =
{
blr_version5,
blr_begin,
blr_message, 0, 1, 0,
blr_int64, 0,
blr_begin,
blr_send, 0,
blr_begin,
blr_assignment,
blr_gen_id
};
static const UCHAR gen_id_blr2[] =
{
blr_literal, blr_long, 0, 1, 0, 0, 0,
blr_parameter, 0, 0, 0, blr_end, blr_end, blr_end, blr_eoc
};
void DYN_UTIL_check_unique_name(thread_db* tdbb, jrd_tra* transaction,
const Firebird::MetaName& object_name, int object_type)
{
/**************************************
*
* D Y N _ U T I L _ c h e c k _ u n i q u e _ n a m e
*
**************************************
*
* Functional description
* Check if an object already exists.
* If yes then return error.
*
**************************************/
SET_TDBB(tdbb);
USHORT error_code = 0;
AutoCacheRequest request;
switch (object_type)
{
case obj_relation:
case obj_procedure:
request.reset(tdbb, drq_l_rel_name, DYN_REQUESTS);
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction)
EREL IN RDB$RELATIONS WITH EREL.RDB$RELATION_NAME EQ object_name.c_str()
{
error_code = 132;
}
END_FOR
if (!error_code)
{
request.reset(tdbb, drq_l_prc_name, DYN_REQUESTS);
FOR (REQUEST_HANDLE request TRANSACTION_HANDLE transaction)
EPRC IN RDB$PROCEDURES
WITH EPRC.RDB$PROCEDURE_NAME EQ object_name.c_str() AND
EPRC.RDB$PACKAGE_NAME MISSING
{
error_code = 135;
}
END_FOR
}
break;
case obj_index:
request.reset(tdbb, drq_l_idx_name, DYN_REQUESTS);
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction)
EIDX IN RDB$INDICES WITH EIDX.RDB$INDEX_NAME EQ object_name.c_str()
{
error_code = 251;
}
END_FOR
break;
case obj_exception:
request.reset(tdbb, drq_l_xcp_name, DYN_REQUESTS);
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction)
EXCP IN RDB$EXCEPTIONS WITH EXCP.RDB$EXCEPTION_NAME EQ object_name.c_str()
{
error_code = 253;
}
END_FOR
break;
case obj_generator:
request.reset(tdbb, drq_l_gen_name, DYN_REQUESTS);
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction)
EGEN IN RDB$GENERATORS WITH EGEN.RDB$GENERATOR_NAME EQ object_name.c_str()
{
error_code = 254;
}
END_FOR
break;
case obj_udf:
request.reset(tdbb, drq_l_fun_name, DYN_REQUESTS);
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction)
EFUN IN RDB$FUNCTIONS
WITH EFUN.RDB$FUNCTION_NAME EQ object_name.c_str() AND
EFUN.RDB$PACKAGE_NAME MISSING
{
error_code = 268;
}
END_FOR
break;
default:
fb_assert(false);
}
if (error_code)
status_exception::raise(Arg::PrivateDyn(error_code) << object_name.c_str());
}
SINT64 DYN_UTIL_gen_unique_id(thread_db* tdbb, SSHORT id, const char* generator_name)
{
/**************************************
*
* D Y N _ U T I L _ g e n _ u n i q u e _ i d
*
**************************************
*
* Functional description
* Generate a unique id using a generator.
*
**************************************/
SET_TDBB(tdbb);
Jrd::Attachment* attachment = tdbb->getAttachment();
AutoCacheRequest request(tdbb, id, DYN_REQUESTS);
SINT64 value = 0;
if (!request)
{
const FB_SIZE_T name_length = fb_strlen(generator_name);
fb_assert(name_length < MAX_SQL_IDENTIFIER_SIZE);
const FB_SIZE_T blr_size = static_cast<FB_SIZE_T>(
sizeof(gen_id_blr1) + sizeof(gen_id_blr2)) + 1 + name_length;
Firebird::UCharBuffer blr;
UCHAR* p = blr.getBuffer(blr_size);
memcpy(p, gen_id_blr1, sizeof(gen_id_blr1));
p += sizeof(gen_id_blr1);
*p++ = name_length;
memcpy(p, generator_name, name_length);
p += name_length;
memcpy(p, gen_id_blr2, sizeof(gen_id_blr2));
p += sizeof(gen_id_blr2);
fb_assert(size_t(p - blr.begin()) == blr_size);
request.compile(tdbb, blr.begin(), (ULONG) blr.getCount());
}
EXE_start(tdbb, request, attachment->getSysTransaction());
EXE_receive(tdbb, request, 0, sizeof(value), (UCHAR*) &value);
return value;
}
void DYN_UTIL_generate_constraint_name(thread_db* tdbb, MetaName& buffer)
{
/**************************************
*
* D Y N _ U T I L _ g e n e r a t e _ c o n s t r a i n t _ n a m e
*
**************************************
*
* Functional description
* Generate a name unique to RDB$RELATION_CONSTRAINTS.
*
**************************************/
SET_TDBB(tdbb);
Jrd::Attachment* attachment = tdbb->getAttachment();
bool found = false;
do
{
buffer.printf("INTEG_%" SQUADFORMAT,
DYN_UTIL_gen_unique_id(tdbb, drq_g_nxt_con, "RDB$CONSTRAINT_NAME"));
AutoCacheRequest request(tdbb, drq_f_nxt_con, DYN_REQUESTS);
found = false;
FOR(REQUEST_HANDLE request)
FIRST 1 X IN RDB$RELATION_CONSTRAINTS
WITH X.RDB$CONSTRAINT_NAME EQ buffer.c_str()
{
found = true;
}
END_FOR
} while (found);
}
void DYN_UTIL_generate_field_name(thread_db* tdbb, TEXT* buffer)
{
/**************************************
*
* D Y N _ U T I L _ g e n e r a t e _ f i e l d _ n a m e
*
**************************************
*
* Functional description
* Stub to make it work with char* too.
*
**************************************/
Firebird::MetaName temp;
DYN_UTIL_generate_field_name(tdbb, temp);
strcpy(buffer, temp.c_str());
}
void DYN_UTIL_generate_field_name(thread_db* tdbb, Firebird::MetaName& buffer)
{
/**************************************
*
* D Y N _ U T I L _ g e n e r a t e _ f i e l d _ n a m e
*
**************************************
*
* Functional description
* Generate a name unique to RDB$FIELDS.
*
**************************************/
SET_TDBB(tdbb);
Jrd::Attachment* attachment = tdbb->getAttachment();
bool found = false;
do
{
buffer.printf("RDB$%" SQUADFORMAT,
DYN_UTIL_gen_unique_id(tdbb, drq_g_nxt_fld, "RDB$FIELD_NAME"));
AutoCacheRequest request(tdbb, drq_f_nxt_fld, DYN_REQUESTS);
found = false;
FOR(REQUEST_HANDLE request)
FIRST 1 X IN RDB$FIELDS
WITH X.RDB$FIELD_NAME EQ buffer.c_str()
{
found = true;
}
END_FOR
} while (found);
}
void DYN_UTIL_generate_field_position(thread_db* tdbb, const MetaName& relation_name,
SLONG* field_pos)
{
/**************************************
*
* D Y N _ U T I L _ g e n e r a t e _ f i e l d _ p o s i t i o n
*
**************************************
*
* Functional description
* Generate a field position if not specified
*
**************************************/
SLONG field_position = -1;
SET_TDBB(tdbb);
Jrd::Attachment* attachment = tdbb->getAttachment();
AutoCacheRequest request(tdbb, drq_l_fld_pos, DYN_REQUESTS);
FOR(REQUEST_HANDLE request)
X IN RDB$RELATION_FIELDS
WITH X.RDB$RELATION_NAME EQ relation_name.c_str()
{
if (X.RDB$FIELD_POSITION.NULL)
continue;
field_position = MAX(X.RDB$FIELD_POSITION, field_position);
}
END_FOR
*field_pos = field_position;
}
void DYN_UTIL_generate_index_name(thread_db* tdbb, jrd_tra* /*transaction*/,
Firebird::MetaName& buffer, UCHAR verb)
{
/**************************************
*
* D Y N _ U T I L _ g e n e r a t e _ i n d e x _ n a m e
*
**************************************
*
* Functional description
* Generate a name unique to RDB$INDICES.
*
**************************************/
SET_TDBB(tdbb);
Jrd::Attachment* attachment = tdbb->getAttachment();
bool found = false;
do
{
const SCHAR* format;
switch (verb)
{
case isc_dyn_def_primary_key:
format = "RDB$PRIMARY%" SQUADFORMAT;
break;
case isc_dyn_def_foreign_key:
format = "RDB$FOREIGN%" SQUADFORMAT;
break;
default:
format = "RDB$%" SQUADFORMAT;
}
buffer.printf(format,
DYN_UTIL_gen_unique_id(tdbb, drq_g_nxt_idx, "RDB$INDEX_NAME"));
AutoCacheRequest request(tdbb, drq_f_nxt_idx, DYN_REQUESTS);
found = false;
FOR(REQUEST_HANDLE request)
FIRST 1 X IN RDB$INDICES
WITH X.RDB$INDEX_NAME EQ buffer.c_str()
{
found = true;
}
END_FOR
} while (found);
}
// Generate a name unique to RDB$GENERATORS.
void DYN_UTIL_generate_generator_name(thread_db* tdbb, Firebird::MetaName& buffer)
{
SET_TDBB(tdbb);
Jrd::Attachment* attachment = tdbb->getAttachment();
AutoCacheRequest request(tdbb, drq_f_nxt_gen, DYN_REQUESTS);
bool found = false;
do
{
buffer.printf("RDB$%" SQUADFORMAT,
DYN_UTIL_gen_unique_id(tdbb, drq_g_nxt_gen, "RDB$GENERATOR_NAME"));
found = false;
FOR (REQUEST_HANDLE request)
FIRST 1 X IN RDB$GENERATORS WITH X.RDB$GENERATOR_NAME EQ buffer.c_str()
{
found = true;
}
END_FOR
} while (found);
}
void DYN_UTIL_generate_trigger_name(thread_db* tdbb, jrd_tra* /*transaction*/, MetaName& buffer)
{
/**************************************
*
* D Y N _ U T I L _ g e n e r a t e _ t r i g g e r _ n a m e
*
**************************************
*
* Functional description
* Generate a name unique to RDB$TRIGGERS.
*
**************************************/
SET_TDBB(tdbb);
Jrd::Attachment* attachment = tdbb->getAttachment();
bool found = false;
do
{
buffer.printf("CHECK_%" SQUADFORMAT,
DYN_UTIL_gen_unique_id(tdbb, drq_g_nxt_trg, "RDB$TRIGGER_NAME"));
AutoCacheRequest request(tdbb, drq_f_nxt_trg, DYN_REQUESTS);
found = false;
FOR(REQUEST_HANDLE request)
FIRST 1 X IN RDB$TRIGGERS
WITH X.RDB$TRIGGER_NAME EQ buffer.c_str()
{
found = true;
}
END_FOR
} while (found);
}
bool DYN_UTIL_find_field_source(thread_db* tdbb,
jrd_tra* transaction,
const Firebird::MetaName& view_name,
USHORT context,
const TEXT* local_name,
TEXT* output_field_name)
{
/**************************************
*
* D Y N _ U T I L _ f i n d _ f i e l d _ s o u r c e
*
**************************************
*
* Functional description
* Find the original source for a view field.
*
**************************************/
SET_TDBB(tdbb);
AutoCacheRequest request(tdbb, drq_l_fld_src2, DYN_REQUESTS);
bool found = false;
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction)
VRL IN RDB$VIEW_RELATIONS CROSS
RFR IN RDB$RELATION_FIELDS OVER RDB$RELATION_NAME
WITH VRL.RDB$VIEW_NAME EQ view_name.c_str() AND
VRL.RDB$VIEW_CONTEXT EQ context AND
VRL.RDB$CONTEXT_TYPE BETWEEN VCT_TABLE AND VCT_VIEW AND
VRL.RDB$PACKAGE_NAME MISSING AND
RFR.RDB$FIELD_NAME EQ local_name
{
found = true;
fb_utils::exact_name_limit(RFR.RDB$FIELD_SOURCE, sizeof(RFR.RDB$FIELD_SOURCE));
strcpy(output_field_name, RFR.RDB$FIELD_SOURCE);
}
END_FOR
if (!found)
{
request.reset(tdbb, drq_l_fld_src3, DYN_REQUESTS);
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction)
VRL IN RDB$VIEW_RELATIONS CROSS
PPR IN RDB$PROCEDURE_PARAMETERS
WITH VRL.RDB$RELATION_NAME EQ PPR.RDB$PROCEDURE_NAME AND
VRL.RDB$VIEW_NAME EQ view_name.c_str() AND
VRL.RDB$VIEW_CONTEXT EQ context AND
VRL.RDB$CONTEXT_TYPE EQ VCT_PROCEDURE AND
PPR.RDB$PACKAGE_NAME EQUIV VRL.RDB$PACKAGE_NAME AND
PPR.RDB$PARAMETER_TYPE = 1 AND // output
PPR.RDB$PARAMETER_NAME EQ local_name
{
found = true;
fb_utils::exact_name_limit(PPR.RDB$FIELD_SOURCE, sizeof(PPR.RDB$FIELD_SOURCE));
strcpy(output_field_name, PPR.RDB$FIELD_SOURCE);
}
END_FOR
}
return found;
}
void DYN_UTIL_store_check_constraints(thread_db* tdbb, jrd_tra* transaction,
const MetaName& constraint_name, const MetaName& trigger_name)
{
/**************************************
*
* D Y N _ U T I L _ s t o r e _ c h e c k _ c o n s t r a i n t s
*
**************************************
*
* Functional description
* Fill in rdb$check_constraints the association between a check name and the
* system defined trigger that implements that check.
*
**************************************/
SET_TDBB(tdbb);
AutoCacheRequest request(tdbb, drq_s_chk_con, DYN_REQUESTS);
STORE(REQUEST_HANDLE request TRANSACTION_HANDLE transaction)
CHK IN RDB$CHECK_CONSTRAINTS
{
strcpy(CHK.RDB$CONSTRAINT_NAME, constraint_name.c_str());
strcpy(CHK.RDB$TRIGGER_NAME, trigger_name.c_str());
}
END_STORE
}