8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-27 06:43:04 +01:00
firebird-mirror/src/dsql/metd.epp

2323 lines
59 KiB
Plaintext
Raw Normal View History

2001-05-23 15:26:42 +02:00
/*
* PROGRAM: Dynamic SQL runtime support
2003-12-31 06:36:12 +01:00
* MODULE: metd.epp
2001-05-23 15:26:42 +02:00
* DESCRIPTION: Meta-data interface
*
* 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-06-29 08:56:51 +02:00
* 2001.11.28 Claudio Valderrama: load not only udfs but udf arguments;
* handle possible collisions with udf redefinitions (drop->declare).
* This closes SF Bug# 409769.
* 2001.12.06 Claudio Valderrama: METD_get_charset_bpc() was added to
* get only the bytes per char of a field, given its charset id.
* This request is not cached.
* 2001.02.23 Claudio Valderrama: Fix SF Bug #228135 with views spoiling
* NULLs in outer joins.
* 2004.01.16 Vlad Horsun: make METD_get_col_default and
* METD_get_domain_default return actual length of default BLR
* 2004.01.16 Vlad Horsun: added support for default parameters
2001-05-23 15:26:42 +02:00
*/
#include "firebird.h"
2001-05-23 15:26:42 +02:00
#include <string.h>
#include "../dsql/dsql.h"
2003-11-08 00:27:24 +01:00
#include "../jrd/ibase.h"
2001-05-23 15:26:42 +02:00
#include "../jrd/align.h"
#include "../jrd/intl.h"
#include "../jrd/thd.h"
#include "../dsql/alld_proto.h"
#include "../dsql/ddl_proto.h"
#include "../dsql/metd_proto.h"
#include "../dsql/hsh_proto.h"
#include "../dsql/make_proto.h"
#include "../dsql/errd_proto.h"
#include "../jrd/gds_proto.h"
#include "../jrd/sch_proto.h"
#include "../jrd/thread_proto.h"
#include "../jrd/why_proto.h"
2003-12-31 06:36:12 +01:00
#include "../common/utils_proto.h"
2005-10-28 18:34:59 +02:00
#include "../common/classes/init.h"
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
/* NOTE: The static definition of DB and gds_trans by gpre will not
2001-05-23 15:26:42 +02:00
be used by the meta data routines. Each of those routines has
its own local definition of these variables. */
/**************************************************************
V4 Multi-threading changes.
-- direct calls to gds__ () & isc_ () entrypoints
2004-05-15 02:58:46 +02:00
THREAD_EXIT();
2001-05-23 15:26:42 +02:00
gds__ () or isc_ () call.
2004-05-15 02:58:46 +02:00
THREAD_ENTER();
2001-05-23 15:26:42 +02:00
-- calls through embedded GDML.
the following protocol will be used. Care should be taken if
nested FOR loops are added.
2004-05-15 02:58:46 +02:00
THREAD_EXIT(); // last statment before FOR loop
2001-05-23 15:26:42 +02:00
FOR ...............
2004-05-15 02:58:46 +02:00
THREAD_ENTER(); // First statment in FOR loop
2001-05-23 15:26:42 +02:00
.....some C code....
.....some C code....
2004-05-15 02:58:46 +02:00
THREAD_EXIT(); // last statment in FOR loop
2001-05-23 15:26:42 +02:00
END_FOR;
2004-05-15 02:58:46 +02:00
THREAD_ENTER(); // First statment after FOR loop
2001-05-23 15:26:42 +02:00
***************************************************************/
DATABASE DB = STATIC "yachts.lnk";
2001-05-23 15:26:42 +02:00
2003-11-10 10:16:38 +01:00
static const UCHAR blr_bpb[] = {
isc_bpb_version1,
isc_bpb_source_type, 1, isc_blob_blr,
isc_bpb_target_type, 1, isc_blob_blr
2001-05-23 15:26:42 +02:00
};
2006-01-16 17:31:15 +01:00
//static void check_array(dsql_req*, const SCHAR*, dsql_fld*);
2003-11-10 10:16:38 +01:00
static void convert_dtype(dsql_fld*, SSHORT);
static void free_function (dsql_udf*);
static void free_procedure(dsql_prc*);
static void free_relation(dsql_rel*);
static void insert_symbol(dsql_dbb*, dsql_sym*);
static dsql_sym* lookup_symbol(dsql_dbb*, USHORT, const char*, SYM_TYPE, USHORT = 0);
static dsql_sym* lookup_symbol(dsql_dbb*, const dsql_str*, SYM_TYPE, USHORT = 0);
2001-05-23 15:26:42 +02:00
2005-10-28 18:34:59 +02:00
namespace {
2001-05-23 15:26:42 +02:00
#ifdef SUPERSERVER
2005-10-28 18:34:59 +02:00
REC_MUTX_T rec_mutex; // Recursive metadata mutex
class RecMutexInit
2003-09-28 02:36:28 +02:00
{
2005-10-28 18:34:59 +02:00
public:
static void init() {
THD_rec_mutex_init (&rec_mutex);
}
static void cleanup() {
THD_rec_mutex_destroy (&rec_mutex);
}
};
Firebird::InitMutex<RecMutexInit> recMutexInited;
2005-10-28 18:34:59 +02:00
class RecMutexHolder {
public:
RecMutexHolder() {
recMutexInited.init();
THREAD_EXIT();
THD_rec_mutex_lock (&rec_mutex);
THREAD_ENTER();
}
~RecMutexHolder() {
THD_rec_mutex_unlock (&rec_mutex);
}
};
2001-05-23 15:26:42 +02:00
#else
2005-10-28 18:34:59 +02:00
class RecMutexHolder {
public:
RecMutexHolder() { }
~RecMutexHolder() { }
};
#endif
2003-09-28 02:36:28 +02:00
}
2001-05-23 15:26:42 +02:00
void METD_drop_collation(dsql_req* request, const dsql_str* name)
{
/**************************************
*
* M E T D _ d r o p _ c o l l a t i o n
*
**************************************
*
* Functional description
* Drop a collation from our metadata, and
* the next caller who wants it will
* look up the new version.
*
* Dropping will be achieved by marking the collation
* as dropped. Anyone with current access can continue
* accessing it.
*
**************************************/
RecMutexHolder holder;
// If the symbol wasn't defined, we've got nothing to do
dsql_sym* symbol = lookup_symbol(request->req_dbb, name, SYM_intlsym_collation, 0);
if (symbol)
{
dsql_intlsym* intlsym = (dsql_intlsym*) symbol->sym_object;
intlsym->intlsym_flags |= INTLSYM_dropped;
}
// mark other potential candidates as maybe dropped
HSHD_set_flag(request->req_dbb,
reinterpret_cast<const TEXT*>(name->str_data),
name->str_length, SYM_intlsym_collation, INTLSYM_dropped);
}
void METD_drop_function(dsql_req* request, const dsql_str* name)
2002-06-29 08:56:51 +02:00
{
/**************************************
*
* M E T D _ d r o p _ f u n c t i o n
*
**************************************
*
* Functional description
* Drop a user defined function from our metadata, and
* the next caller who wants it will
* look up the new version.
*
* Dropping will be achieved by marking the function
* as dropped. Anyone with current access can continue
* accessing it.
*
**************************************/
2005-10-28 18:34:59 +02:00
RecMutexHolder holder;
2002-06-29 08:56:51 +02:00
// If the symbol wasn't defined, we've got nothing to do
2002-06-29 08:56:51 +02:00
dsql_sym* symbol = lookup_symbol(request->req_dbb, name, SYM_udf);
2002-06-29 08:56:51 +02:00
if (symbol) {
dsql_udf* userFunc = (dsql_udf*) symbol->sym_object;
userFunc->udf_flags |= UDF_dropped;
2002-06-29 08:56:51 +02:00
}
// mark other potential candidates as maybe dropped
2002-06-29 08:56:51 +02:00
HSHD_set_flag(request->req_dbb,
2003-10-16 10:51:06 +02:00
reinterpret_cast<const TEXT*>(name->str_data),
name->str_length, SYM_udf, UDF_dropped);
2002-06-29 08:56:51 +02:00
}
2001-05-23 15:26:42 +02:00
void METD_drop_procedure(dsql_req* request, const dsql_str* name)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* M E T D _ d r o p _ p r o c e d u r e
*
**************************************
*
* Functional description
* Drop a procedure from our metadata, and
* the next caller who wants it will
* look up the new version.
*
* Dropping will be achieved by marking the procedure
* as dropped. Anyone with current access can continue
* accessing it.
*
**************************************/
2005-10-28 18:34:59 +02:00
RecMutexHolder holder;
2001-05-23 15:26:42 +02:00
// If the symbol wasn't defined, we've got nothing to do
2001-05-23 15:26:42 +02:00
dsql_sym* symbol = lookup_symbol(request->req_dbb, name, SYM_procedure);
2001-05-23 15:26:42 +02:00
if (symbol) {
dsql_prc* procedure = (dsql_prc*) symbol->sym_object;
2001-05-23 15:26:42 +02:00
procedure->prc_flags |= PRC_dropped;
}
// mark other potential candidates as maybe dropped
2001-05-23 15:26:42 +02:00
HSHD_set_flag(request->req_dbb, (TEXT*)name->str_data, name->str_length,
2001-05-23 15:26:42 +02:00
SYM_procedure, PRC_dropped);
}
void METD_drop_relation(dsql_req* request, const dsql_str* name)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* M E T D _ d r o p _ r e l a t i o n
*
**************************************
*
* Functional description
* Drop a relation from our metadata, and
* rely on the next guy who wants it to
* look up the new version.
*
* Dropping will be achieved by marking the relation
* as dropped. Anyone with current access can continue
* accessing it.
*
**************************************/
2005-10-28 18:34:59 +02:00
RecMutexHolder holder;
2001-05-23 15:26:42 +02:00
// If the symbol wasn't defined, we've got nothing to do
2001-05-23 15:26:42 +02:00
dsql_sym* symbol = lookup_symbol(request->req_dbb, name, SYM_relation);
2001-05-23 15:26:42 +02:00
if (symbol) {
dsql_rel* relation = (dsql_rel*) symbol->sym_object;
2001-05-23 15:26:42 +02:00
relation->rel_flags |= REL_dropped;
}
// mark other potential candidates as maybe dropped
2001-05-23 15:26:42 +02:00
HSHD_set_flag(request->req_dbb, (TEXT*)name->str_data, name->str_length,
2001-05-23 15:26:42 +02:00
SYM_relation, REL_dropped);
}
dsql_intlsym* METD_get_collation(dsql_req* request,
const dsql_str* name,
USHORT charset_id)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* M E T D _ g e t _ c o l l a t i o n
*
**************************************
*
* Functional description
* Look up an international text type object.
* If it doesn't exist, return NULL.
*
**************************************/
RecMutexHolder holder;
2001-05-23 15:26:42 +02:00
// Start by seeing if symbol is already defined
2001-05-23 15:26:42 +02:00
dsql_sym* symbol = lookup_symbol(request->req_dbb, name, SYM_intlsym_collation, charset_id);
if (symbol)
return (dsql_intlsym*) symbol->sym_object;
2001-05-23 15:26:42 +02:00
// Now see if it is in the database
2001-05-23 15:26:42 +02:00
2005-09-04 23:32:16 +02:00
ISC_STATUS_ARRAY isc_status = {0};
dsql_dbb* dbb = request->req_dbb;
2005-11-12 19:48:09 +01:00
isc_db_handle DB = dbb->dbb_database_handle;
dsql_intlsym* iname = NULL;
2001-05-23 15:26:42 +02:00
2004-05-15 02:58:46 +02:00
THREAD_EXIT();
2001-05-23 15:26:42 +02:00
FOR(REQUEST_HANDLE dbb->dbb_requests[irq_collation] TRANSACTION_HANDLE request->req_trans)
2001-05-23 15:26:42 +02:00
X IN RDB$COLLATIONS
CROSS Y IN RDB$CHARACTER_SETS OVER RDB$CHARACTER_SET_ID
2005-05-28 00:45:31 +02:00
WITH X.RDB$COLLATION_NAME EQ name->str_data AND
X.RDB$CHARACTER_SET_ID EQ charset_id;
2001-05-23 15:26:42 +02:00
2004-05-15 02:58:46 +02:00
THREAD_ENTER();
2001-05-23 15:26:42 +02:00
iname = FB_NEW_RPT(*dbb->dbb_pool, name->str_length) dsql_intlsym;
2001-05-23 15:26:42 +02:00
strcpy(iname->intlsym_name, (TEXT *) name->str_data);
iname->intlsym_flags = 0;
iname->intlsym_charset_id = X.RDB$CHARACTER_SET_ID;
iname->intlsym_collate_id = X.RDB$COLLATION_ID;
iname->intlsym_ttype =
INTL_CS_COLL_TO_TTYPE(iname->intlsym_charset_id,
iname->intlsym_collate_id);
iname->intlsym_bytes_per_char =
(Y.RDB$BYTES_PER_CHARACTER.NULL) ? 1 : (Y.RDB$BYTES_PER_CHARACTER);
2004-05-15 02:58:46 +02:00
THREAD_EXIT();
2001-05-23 15:26:42 +02:00
2005-09-04 23:32:16 +02:00
END_FOR
ON_ERROR
THREAD_ENTER();
ERRD_punt(isc_status);
END_ERROR;
2001-05-23 15:26:42 +02:00
2004-05-15 02:58:46 +02:00
THREAD_ENTER();
2001-05-23 15:26:42 +02:00
if (!iname)
return NULL;
// Store in the symbol table
2001-05-23 15:26:42 +02:00
symbol = iname->intlsym_symbol = FB_NEW_RPT(*dbb->dbb_pool, 0) dsql_sym;
2001-05-23 15:26:42 +02:00
symbol->sym_object = (BLK) iname;
symbol->sym_string = iname->intlsym_name;
symbol->sym_length = name->str_length;
symbol->sym_type = SYM_intlsym_collation;
2001-05-23 15:26:42 +02:00
symbol->sym_dbb = dbb;
insert_symbol(request->req_dbb, symbol);
2001-05-23 15:26:42 +02:00
return iname;
}
USHORT METD_get_col_default(dsql_req* request,
const char* for_rel_name,
const char* for_col_name,
bool* has_default,
TEXT* buffer,
USHORT buff_length)
2001-05-23 15:26:42 +02:00
{
/*************************************************************
*
* M E T D _ g e t _ c o l _ d e f a u l t
*
**************************************************************
*
* Function:
* Gets the default value for a column of an existing table.
* Will check the default for the column of the table, if that is
* not present, will check for the default of the relevant domain
*
* The default blr is returned in buffer. The blr is of the form
* blr_version4 blr_literal ..... blr_eoc
*
* Reads the system tables RDB$FIELDS and RDB$RELATION_FIELDS.
*
**************************************************************/
2004-02-02 12:02:12 +01:00
dsql_dbb* dbb;
2003-04-16 12:18:51 +02:00
ISC_STATUS_ARRAY status_vect;
2001-05-23 15:26:42 +02:00
ISC_QUAD *blob_id;
TEXT *ptr_in_buffer;
2003-04-10 08:32:58 +02:00
ISC_STATUS stat;
USHORT length, result = 0;
2004-05-03 01:06:37 +02:00
isc_blob_handle blob_handle = 0;
2001-05-23 15:26:42 +02:00
2003-09-12 03:41:03 +02:00
*has_default = false;
2001-05-23 15:26:42 +02:00
2005-09-04 23:32:16 +02:00
ISC_STATUS_ARRAY isc_status = {0};
2001-05-23 15:26:42 +02:00
dbb = request->req_dbb;
2005-11-12 19:48:09 +01:00
isc_db_handle DB = dbb->dbb_database_handle;
2001-05-23 15:26:42 +02:00
// V4.x multi threading requirements
2004-05-15 02:58:46 +02:00
THREAD_EXIT();
2001-05-23 15:26:42 +02:00
FOR(REQUEST_HANDLE dbb->dbb_requests[irq_col_default] TRANSACTION_HANDLE request->req_trans)
2001-05-23 15:26:42 +02:00
RFL IN RDB$RELATION_FIELDS CROSS
FLD IN RDB$FIELDS WITH
RFL.RDB$RELATION_NAME EQ for_rel_name AND
RFL.RDB$FIELD_SOURCE EQ FLD.RDB$FIELD_NAME AND
RFL.RDB$FIELD_NAME EQ for_col_name
2004-05-15 02:58:46 +02:00
THREAD_ENTER();
2001-05-23 15:26:42 +02:00
if (!RFL.RDB$DEFAULT_VALUE.NULL) {
blob_id = &RFL.RDB$DEFAULT_VALUE;
2003-09-12 03:41:03 +02:00
*has_default = true;
2001-05-23 15:26:42 +02:00
}
else if (!FLD.RDB$DEFAULT_VALUE.NULL) {
blob_id = &FLD.RDB$DEFAULT_VALUE;
2003-09-12 03:41:03 +02:00
*has_default = true;
2001-05-23 15:26:42 +02:00
}
else
2003-09-12 03:41:03 +02:00
*has_default = false;
2001-05-23 15:26:42 +02:00
if (*has_default) {
// open the blob
2004-05-15 02:58:46 +02:00
THREAD_EXIT();
stat = isc_open_blob2(status_vect, &DB, &request->req_trans,
&blob_handle, blob_id, sizeof(blr_bpb),
blr_bpb);
2004-05-15 02:58:46 +02:00
THREAD_ENTER();
2001-05-23 15:26:42 +02:00
if (stat)
2005-09-04 23:32:16 +02:00
ERRD_punt(status_vect);
2001-05-23 15:26:42 +02:00
// fetch segments. Assuming here that the buffer is big enough.
2001-05-23 15:26:42 +02:00
ptr_in_buffer = buffer;
while (true) {
2004-05-15 02:58:46 +02:00
THREAD_EXIT();
2001-05-23 15:26:42 +02:00
stat = isc_get_segment(status_vect, &blob_handle,
&length, buff_length, ptr_in_buffer);
2004-05-15 02:58:46 +02:00
THREAD_ENTER();
2001-05-23 15:26:42 +02:00
ptr_in_buffer = ptr_in_buffer + length;
buff_length = buff_length - length;
result += length;
2001-05-23 15:26:42 +02:00
if (!stat)
continue;
2003-11-08 00:27:24 +01:00
else if (stat == isc_segstr_eof) {
// null terminate the buffer
2001-05-23 15:26:42 +02:00
*ptr_in_buffer = 0;
break;
}
else
2005-09-04 23:32:16 +02:00
ERRD_punt(status_vect);
2001-05-23 15:26:42 +02:00
}
2004-05-15 02:58:46 +02:00
THREAD_EXIT();
2001-05-23 15:26:42 +02:00
isc_close_blob(status_vect, &blob_handle);
2004-05-15 02:58:46 +02:00
THREAD_ENTER();
2001-05-23 15:26:42 +02:00
/* the default string must be of the form:
blr_version4 blr_literal ..... blr_eoc */
2003-11-04 00:59:24 +01:00
fb_assert((buffer[0] == blr_version4) || (buffer[0] == blr_version5));
fb_assert(buffer[1] == blr_literal);
2001-05-23 15:26:42 +02:00
}
else {
if (request->req_dbb->dbb_db_SQL_dialect > SQL_DIALECT_V5)
buffer[0] = blr_version5;
else
buffer[0] = blr_version4;
buffer[1] = blr_eoc;
result = 2;
2001-05-23 15:26:42 +02:00
}
2004-05-15 02:58:46 +02:00
THREAD_EXIT();
2001-05-23 15:26:42 +02:00
2005-09-04 23:32:16 +02:00
END_FOR
ON_ERROR
THREAD_ENTER();
ERRD_punt(isc_status);
END_ERROR
THREAD_ENTER();
2001-05-23 15:26:42 +02:00
return result;
2001-05-23 15:26:42 +02:00
}
dsql_intlsym* METD_get_charset(dsql_req* request, USHORT length, const char* name) // UTF-8
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* M E T D _ g e t _ c h a r s e t
*
**************************************
*
* Functional description
* Look up an international text type object.
* If it doesn't exist, return NULL.
*
**************************************/
RecMutexHolder holder;
2001-05-23 15:26:42 +02:00
// Start by seeing if symbol is already defined
2001-05-23 15:26:42 +02:00
dsql_sym* symbol = lookup_symbol(request->req_dbb, length, name, SYM_intlsym_charset);
if (symbol)
return (dsql_intlsym*) symbol->sym_object;
2001-05-23 15:26:42 +02:00
// Now see if it is in the database
2001-05-23 15:26:42 +02:00
2005-09-04 23:32:16 +02:00
ISC_STATUS_ARRAY isc_status = {0};
dsql_dbb* dbb = request->req_dbb;
2005-11-12 19:48:09 +01:00
isc_db_handle DB = dbb->dbb_database_handle;
dsql_intlsym* iname = NULL;
2001-05-23 15:26:42 +02:00
2004-05-15 02:58:46 +02:00
THREAD_EXIT();
2001-05-23 15:26:42 +02:00
FOR(REQUEST_HANDLE dbb->dbb_requests[irq_charset] TRANSACTION_HANDLE request->req_trans)
2001-05-23 15:26:42 +02:00
X IN RDB$COLLATIONS
CROSS Y IN RDB$CHARACTER_SETS OVER RDB$CHARACTER_SET_ID
CROSS Z IN RDB$TYPES
WITH Z.RDB$TYPE EQ Y.RDB$CHARACTER_SET_ID
AND Z.RDB$TYPE_NAME EQ name
AND Z.RDB$FIELD_NAME EQ "RDB$CHARACTER_SET_NAME"
AND Y.RDB$DEFAULT_COLLATE_NAME EQ X.RDB$COLLATION_NAME;
2004-05-15 02:58:46 +02:00
THREAD_ENTER();
2001-05-23 15:26:42 +02:00
iname = FB_NEW_RPT(*dbb->dbb_pool, length) dsql_intlsym;
2004-10-08 13:08:42 +02:00
strcpy(iname->intlsym_name, name);
2001-05-23 15:26:42 +02:00
iname->intlsym_flags = 0;
iname->intlsym_charset_id = X.RDB$CHARACTER_SET_ID;
iname->intlsym_collate_id = X.RDB$COLLATION_ID;
iname->intlsym_ttype =
INTL_CS_COLL_TO_TTYPE(iname->intlsym_charset_id,
iname->intlsym_collate_id);
iname->intlsym_bytes_per_char =
(Y.RDB$BYTES_PER_CHARACTER.NULL) ? 1 : (Y.RDB$BYTES_PER_CHARACTER);
2004-05-15 02:58:46 +02:00
THREAD_EXIT();
2001-05-23 15:26:42 +02:00
END_FOR
ON_ERROR
THREAD_ENTER();
ERRD_punt(isc_status);
2001-05-23 15:26:42 +02:00
END_ERROR;
2004-05-15 02:58:46 +02:00
THREAD_ENTER();
2001-05-23 15:26:42 +02:00
if (!iname)
return NULL;
// Store in the symbol table
2001-05-23 15:26:42 +02:00
symbol = iname->intlsym_symbol = FB_NEW_RPT(*dbb->dbb_pool, 0) dsql_sym;
2001-05-23 15:26:42 +02:00
symbol->sym_object = (BLK) iname;
symbol->sym_string = iname->intlsym_name;
symbol->sym_length = length;
symbol->sym_type = SYM_intlsym_charset;
2001-05-23 15:26:42 +02:00
symbol->sym_dbb = dbb;
insert_symbol(request->req_dbb, symbol);
2001-05-23 15:26:42 +02:00
dbb->dbb_charsets_by_id.add(iname);
2001-05-23 15:26:42 +02:00
return iname;
}
USHORT METD_get_charset_bpc(dsql_req* request, SSHORT charset_id)
2002-06-29 08:56:51 +02:00
{
/**************************************
*
* M E T D _ g e t _ c h a r s e t _ b p c
*
**************************************
*
* Functional description
* Look up an international text type object.
* If it doesn't exist, return NULL.
* Go directly to system tables & return only the
* number of bytes per character. Lookup by
* charset' id, not by name.
*
**************************************/
dsql_dbb* dbb;
USHORT bpc = 0;
2002-06-29 08:56:51 +02:00
ISC_STATUS_ARRAY isc_status = {0};
dbb = request->req_dbb;
isc_db_handle DB = dbb->dbb_database_handle;
2002-06-29 08:56:51 +02:00
if (charset_id == CS_dynamic)
charset_id = dbb->dbb_att_charset;
2002-06-29 08:56:51 +02:00
dsql_intlsym* cs_sym = 0;
size_t pos = 0;
if (dbb->dbb_charsets_by_id.find(charset_id, pos)) {
cs_sym = dbb->dbb_charsets_by_id[pos];
}
else {
Firebird::MetaName cs_name = METD_get_charset_name(request, charset_id);
cs_sym = METD_get_charset(request, cs_name.length(), cs_name.c_str());
}
return cs_sym->intlsym_bytes_per_char;
2002-06-29 08:56:51 +02:00
}
2005-06-16 07:02:37 +02:00
Firebird::MetaName METD_get_charset_name(dsql_req* request, SSHORT charset_id)
{
/**************************************
*
* M E T D _ g e t _ c h a r s e t _ n a m e
*
**************************************
*
* Functional description
* Look up an international text type object.
* If it doesn't exist, return empty string.
* Go directly to system tables & return only the
* name.
*
**************************************/
Firebird::MetaName name;
2005-09-04 23:32:16 +02:00
ISC_STATUS_ARRAY isc_status = {0};
2005-06-16 07:02:37 +02:00
dsql_dbb* dbb = request->req_dbb;
2005-11-12 19:48:09 +01:00
isc_db_handle DB = dbb->dbb_database_handle;
if (charset_id == CS_dynamic)
charset_id = dbb->dbb_att_charset;
size_t pos = 0;
if (dbb->dbb_charsets_by_id.find(charset_id, pos))
{
return dbb->dbb_charsets_by_id[pos]->intlsym_name;
}
THREAD_EXIT();
FOR (REQUEST_HANDLE dbb->dbb_requests[irq_cs_name] TRANSACTION_HANDLE request->req_trans)
Y IN RDB$CHARACTER_SETS
WITH Y.RDB$CHARACTER_SET_ID EQ charset_id
THREAD_ENTER();
name = Y.RDB$CHARACTER_SET_NAME;
THREAD_EXIT();
END_FOR
ON_ERROR
THREAD_ENTER();
ERRD_punt(isc_status);
END_ERROR;
THREAD_ENTER();
// put new charset into hash table if needed
METD_get_charset(request, name.length(), name.c_str());
return name;
}
2005-06-16 07:02:37 +02:00
2003-11-10 10:16:38 +01:00
dsql_str* METD_get_default_charset(dsql_req* request)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* M E T D _ g e t _ d e f a u l t _ c h a r s e t
*
**************************************
*
* Functional description
* Find the default character set for a database
*
**************************************/
2005-09-04 23:32:16 +02:00
ISC_STATUS_ARRAY isc_status = {0};
2006-01-04 06:55:24 +01:00
dsql_dbb* dbb = request->req_dbb;
2001-05-23 15:26:42 +02:00
if (dbb->dbb_flags & DBB_no_charset)
return NULL;
if (dbb->dbb_dfl_charset)
2006-01-04 06:55:24 +01:00
return dbb->dbb_dfl_charset;
2001-05-23 15:26:42 +02:00
// Now see if it is in the database
2001-05-23 15:26:42 +02:00
2005-11-12 19:48:09 +01:00
isc_db_handle DB = dbb->dbb_database_handle;
2001-05-23 15:26:42 +02:00
2004-05-15 02:58:46 +02:00
THREAD_EXIT();
2001-05-23 15:26:42 +02:00
FOR(REQUEST_HANDLE dbb->dbb_requests[irq_default_cs] TRANSACTION_HANDLE request->req_trans)
2001-05-23 15:26:42 +02:00
FIRST 1 DBB IN RDB$DATABASE
WITH DBB.RDB$CHARACTER_SET_NAME NOT MISSING;
2004-05-15 02:58:46 +02:00
THREAD_ENTER();
2001-05-23 15:26:42 +02:00
// Terminate ASCIIZ string on first trailing blank
fb_utils::exact_name(DBB.RDB$CHARACTER_SET_NAME);
2006-01-04 06:55:24 +01:00
USHORT length = strlen(DBB.RDB$CHARACTER_SET_NAME);
2003-11-10 10:16:38 +01:00
dbb->dbb_dfl_charset = FB_NEW_RPT(*dbb->dbb_pool, length) dsql_str;
2001-05-23 15:26:42 +02:00
dbb->dbb_dfl_charset->str_length = length;
dbb->dbb_dfl_charset->str_charset = NULL;
const UCHAR* str_charset = (UCHAR*) DBB.RDB$CHARACTER_SET_NAME;
for (char* p = dbb->dbb_dfl_charset->str_data; length; --length) {
*p++ = *str_charset++;
}
2001-05-23 15:26:42 +02:00
2004-05-15 02:58:46 +02:00
THREAD_EXIT();
2001-05-23 15:26:42 +02:00
END_FOR
ON_ERROR
THREAD_ENTER();
ERRD_punt(isc_status);
2001-05-23 15:26:42 +02:00
END_ERROR;
2004-05-15 02:58:46 +02:00
THREAD_ENTER();
2001-05-23 15:26:42 +02:00
if (dbb->dbb_dfl_charset == NULL)
dbb->dbb_flags |= DBB_no_charset;
return dbb->dbb_dfl_charset;
}
USHORT METD_get_domain(dsql_req* request, dsql_fld* field, const char* name) // UTF-8
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* M E T D _ g e t _ d o m a i n
*
**************************************
*
* Functional description
* Fetch domain information for field defined as 'name'
*
**************************************/
bool found = false;
2005-09-04 23:32:16 +02:00
ISC_STATUS_ARRAY isc_status = {0};
dsql_dbb* dbb = request->req_dbb;
2005-11-12 19:48:09 +01:00
isc_db_handle DB = dbb->dbb_database_handle;
2001-05-23 15:26:42 +02:00
2004-05-15 02:58:46 +02:00
THREAD_EXIT();
2001-05-23 15:26:42 +02:00
FOR(REQUEST_HANDLE dbb->dbb_requests[irq_domain] TRANSACTION_HANDLE request->req_trans)
2001-05-23 15:26:42 +02:00
FLX IN RDB$FIELDS WITH FLX.RDB$FIELD_NAME EQ name
2004-05-15 02:58:46 +02:00
THREAD_ENTER();
2001-05-23 15:26:42 +02:00
found = true;
2001-05-23 15:26:42 +02:00
field->fld_length = FLX.RDB$FIELD_LENGTH;
field->fld_scale = FLX.RDB$FIELD_SCALE;
field->fld_sub_type = FLX.RDB$FIELD_SUB_TYPE;
field->fld_character_set_id = 0;
if (!FLX.RDB$CHARACTER_SET_ID.NULL)
field->fld_character_set_id = FLX.RDB$CHARACTER_SET_ID;
field->fld_collation_id = 0;
if (!FLX.RDB$COLLATION_ID.NULL)
field->fld_collation_id = FLX.RDB$COLLATION_ID;
field->fld_character_length = 0;
if (!FLX.RDB$CHARACTER_LENGTH.NULL)
field->fld_character_length = FLX.RDB$CHARACTER_LENGTH;
if (!FLX.RDB$COMPUTED_BLR.NULL)
field->fld_flags |= FLD_computed;
if (FLX.RDB$SYSTEM_FLAG == 1)
field->fld_flags |= FLD_system;
2001-05-23 15:26:42 +02:00
convert_dtype(field, FLX.RDB$FIELD_TYPE);
if (FLX.RDB$FIELD_TYPE == blr_blob) {
field->fld_seg_length = FLX.RDB$SEGMENT_LENGTH;
}
2004-05-15 02:58:46 +02:00
THREAD_EXIT();
2001-05-23 15:26:42 +02:00
END_FOR
ON_ERROR
2005-09-04 23:32:16 +02:00
THREAD_ENTER();
ERRD_punt(isc_status);
2001-05-23 15:26:42 +02:00
END_ERROR;
2004-05-15 02:58:46 +02:00
THREAD_ENTER();
2001-05-23 15:26:42 +02:00
return found ? TRUE : FALSE;
2001-05-23 15:26:42 +02:00
}
USHORT METD_get_domain_default(dsql_req* request,
const TEXT* domain_name,
bool* has_default,
TEXT* buffer,
USHORT buff_length)
2001-05-23 15:26:42 +02:00
{
/*************************************************************
*
* M E T D _ g e t _ d o m a i n _ d e f a u l t
*
**************************************************************
*
* Function:
* Gets the default value for a domain of an existing table.
*
**************************************************************/
2003-04-16 12:18:51 +02:00
ISC_STATUS_ARRAY status_vect;
2001-05-23 15:26:42 +02:00
2003-09-12 03:41:03 +02:00
*has_default = false;
2001-05-23 15:26:42 +02:00
2005-09-04 23:32:16 +02:00
ISC_STATUS_ARRAY isc_status = {0};
2004-02-02 12:02:12 +01:00
dsql_dbb* dbb = request->req_dbb;
2005-11-12 19:48:09 +01:00
isc_db_handle DB = dbb->dbb_database_handle;
USHORT result = 0;
2001-05-23 15:26:42 +02:00
// V4.x multi threading requirements
2004-05-15 02:58:46 +02:00
THREAD_EXIT();
2001-05-23 15:26:42 +02:00
FOR(REQUEST_HANDLE dbb->dbb_requests[irq_domain_2] TRANSACTION_HANDLE request->req_trans)
2003-10-16 10:51:06 +02:00
FLD IN RDB$FIELDS WITH FLD.RDB$FIELD_NAME EQ domain_name
2004-05-15 02:58:46 +02:00
THREAD_ENTER();
2001-05-23 15:26:42 +02:00
ISC_QUAD* blob_id;
2001-05-23 15:26:42 +02:00
if (!FLD.RDB$DEFAULT_VALUE.NULL) {
blob_id = &FLD.RDB$DEFAULT_VALUE;
2003-09-12 03:41:03 +02:00
*has_default = true;
2001-05-23 15:26:42 +02:00
}
else
2003-09-12 03:41:03 +02:00
*has_default = false;
2001-05-23 15:26:42 +02:00
if (*has_default) {
// open the blob
2004-05-15 02:58:46 +02:00
THREAD_EXIT();
2004-05-03 01:06:37 +02:00
isc_blob_handle blob_handle = 0;
ISC_STATUS stat = isc_open_blob2(status_vect, &DB, &request->req_trans,
&blob_handle, blob_id, sizeof(blr_bpb),
blr_bpb);
2004-05-15 02:58:46 +02:00
THREAD_ENTER();
2001-05-23 15:26:42 +02:00
if (stat)
2005-09-04 23:32:16 +02:00
ERRD_punt(status_vect);
2001-05-23 15:26:42 +02:00
// fetch segments. Assume buffer is big enough.
TEXT* ptr_in_buffer = buffer;
while (true) {
2004-05-15 02:58:46 +02:00
THREAD_EXIT();
USHORT length;
2001-05-23 15:26:42 +02:00
stat = isc_get_segment(status_vect,
&blob_handle,
&length, buff_length, ptr_in_buffer);
2004-05-15 02:58:46 +02:00
THREAD_ENTER();
2001-05-23 15:26:42 +02:00
ptr_in_buffer = ptr_in_buffer + length;
buff_length = buff_length - length;
result += length;
2001-05-23 15:26:42 +02:00
if (!stat)
continue;
2003-11-08 00:27:24 +01:00
else if (stat == isc_segstr_eof) {
// null terminate the buffer
2001-05-23 15:26:42 +02:00
*ptr_in_buffer = 0;
break;
}
else
2005-09-04 23:32:16 +02:00
ERRD_punt(status_vect);
2001-05-23 15:26:42 +02:00
}
2004-05-15 02:58:46 +02:00
THREAD_EXIT();
2001-05-23 15:26:42 +02:00
isc_close_blob(status_vect, &blob_handle);
2004-05-15 02:58:46 +02:00
THREAD_ENTER();
2001-05-23 15:26:42 +02:00
/* the default string must be of the form:
blr_version4 blr_literal ..... blr_eoc */
2003-11-04 00:59:24 +01:00
fb_assert((buffer[0] == blr_version4) || (buffer[0] == blr_version5));
fb_assert(buffer[1] == blr_literal);
2001-05-23 15:26:42 +02:00
}
else {
if (request->req_dbb->dbb_db_SQL_dialect > SQL_DIALECT_V5)
buffer[0] = blr_version5;
else
buffer[0] = blr_version4;
buffer[1] = blr_eoc;
result = 2;
2001-05-23 15:26:42 +02:00
}
2004-05-15 02:58:46 +02:00
THREAD_EXIT();
2001-05-23 15:26:42 +02:00
END_FOR
ON_ERROR
2005-09-04 23:32:16 +02:00
THREAD_ENTER();
ERRD_punt(isc_status);
2001-05-23 15:26:42 +02:00
END_ERROR
2004-05-15 02:58:46 +02:00
THREAD_ENTER();
2001-05-23 15:26:42 +02:00
return result;
2001-05-23 15:26:42 +02:00
}
bool METD_get_exception(dsql_req* request, const dsql_str* name)
{
/**************************************
*
* M E T D _ g e t _ e x c e p t i o n
*
**************************************
*
* Functional description
* Look up an exception.
*
**************************************/
dsql_dbb* dbb;
bool found = false;
2005-09-04 23:32:16 +02:00
ISC_STATUS_ARRAY isc_status = {0};
dbb = request->req_dbb;
2005-11-12 19:48:09 +01:00
isc_db_handle DB = dbb->dbb_database_handle;
THREAD_EXIT();
FOR(REQUEST_HANDLE dbb->dbb_requests[irq_exception] TRANSACTION_HANDLE request->req_trans)
X IN RDB$EXCEPTIONS WITH
X.RDB$EXCEPTION_NAME EQ name->str_data;
THREAD_ENTER();
found = true;
THREAD_EXIT();
END_FOR
ON_ERROR
2005-09-04 23:32:16 +02:00
THREAD_ENTER();
ERRD_punt(isc_status);
END_ERROR;
THREAD_ENTER();
return found;
}
2003-11-10 10:16:38 +01:00
dsql_udf* METD_get_function(dsql_req* request, const dsql_str* name)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* M E T D _ g e t _ f u n c t i o n
*
**************************************
*
* Functional description
* Look up a user defined function. If it doesn't exist,
* return NULL.
*
**************************************/
dsql_nod* udf_param_node;
2004-04-10 02:25:22 +02:00
dsql_nod** ptr;
2002-06-29 08:56:51 +02:00
2005-10-28 18:34:59 +02:00
RecMutexHolder holder;
2001-05-23 15:26:42 +02:00
// Start by seeing if symbol is already defined
2001-05-23 15:26:42 +02:00
dsql_sym* symbol = lookup_symbol(request->req_dbb, name, SYM_udf);
if (symbol)
2003-11-10 10:16:38 +01:00
return (dsql_udf*) symbol->sym_object;
2002-06-29 08:56:51 +02:00
// Now see if it is in the database
2001-05-23 15:26:42 +02:00
2005-09-04 23:32:16 +02:00
ISC_STATUS_ARRAY isc_status = {0};
2004-02-02 12:02:12 +01:00
dsql_dbb* dbb = request->req_dbb;
2005-11-12 19:48:09 +01:00
isc_db_handle DB = dbb->dbb_database_handle;
dsql_udf* userFunc = NULL;
DsqlNodStack stack;
USHORT return_arg;
2001-05-23 15:26:42 +02:00
2004-05-15 02:58:46 +02:00
THREAD_EXIT();
2001-05-23 15:26:42 +02:00
FOR(REQUEST_HANDLE dbb->dbb_requests[irq_function] TRANSACTION_HANDLE request->req_trans)
2001-05-23 15:26:42 +02:00
X IN RDB$FUNCTIONS WITH
X.RDB$FUNCTION_NAME EQ name->str_data
2004-05-15 02:58:46 +02:00
THREAD_ENTER();
2001-05-23 15:26:42 +02:00
2003-11-10 10:16:38 +01:00
userFunc = FB_NEW_RPT(*dbb->dbb_pool, name->str_length) dsql_udf;
2002-06-29 08:56:51 +02:00
/* Moved below as still can't say for sure it will be stored.
Following the same logic for MET_get_procedure and MET_get_relation
userFunc->udf_next = dbb->dbb_functions;
dbb->dbb_functions = userFunc;
2002-06-29 08:56:51 +02:00
*/
2004-10-08 13:08:42 +02:00
strcpy(userFunc->udf_name, (char*) name->str_data);
2001-05-23 15:26:42 +02:00
return_arg = X.RDB$RETURN_ARGUMENT;
userFunc->udf_arguments = 0;
2001-05-23 15:26:42 +02:00
2004-05-15 02:58:46 +02:00
THREAD_EXIT();
2001-05-23 15:26:42 +02:00
END_FOR
ON_ERROR
2005-09-04 23:32:16 +02:00
THREAD_ENTER();
ERRD_punt(isc_status);
2001-05-23 15:26:42 +02:00
END_ERROR;
2004-05-15 02:58:46 +02:00
THREAD_ENTER();
2001-05-23 15:26:42 +02:00
if (!userFunc) {
2001-05-23 15:26:42 +02:00
return NULL;
2002-06-29 08:56:51 +02:00
}
2001-05-23 15:26:42 +02:00
// Note: The following two requests differ in the fields which are
// new since ODS7 (DBB_v3 flag). One of the two requests
// here will be cached in dbb_requests[ird_func_return],
// the one that is appropriate for the database we are
// working against.
2004-05-15 02:58:46 +02:00
THREAD_EXIT();
2001-05-23 15:26:42 +02:00
FOR(REQUEST_HANDLE dbb->dbb_requests[irq_func_return] TRANSACTION_HANDLE request->req_trans)
X IN RDB$FUNCTION_ARGUMENTS WITH
X.RDB$FUNCTION_NAME EQ name->str_data
SORTED BY X.RDB$ARGUMENT_POSITION
2001-05-23 15:26:42 +02:00
THREAD_ENTER();
2001-05-23 15:26:42 +02:00
if (X.RDB$ARGUMENT_POSITION == return_arg) {
userFunc->udf_dtype = (X.RDB$FIELD_TYPE != blr_blob) ?
2001-05-23 15:26:42 +02:00
gds_cvt_blr_dtype[X.RDB$FIELD_TYPE] : dtype_blob;
userFunc->udf_scale = X.RDB$FIELD_SCALE;
2001-05-23 15:26:42 +02:00
if (!X.RDB$FIELD_SUB_TYPE.NULL) {
userFunc->udf_sub_type = X.RDB$FIELD_SUB_TYPE;
2002-06-29 08:56:51 +02:00
}
else {
userFunc->udf_sub_type = 0;
}
/* CVC: We are overcoming a bug in ddl.c:put_field()
when any field is defined: the length is not given for blobs. */
if (X.RDB$FIELD_TYPE == blr_blob)
userFunc->udf_length = sizeof (ISC_QUAD);
else
userFunc->udf_length = X.RDB$FIELD_LENGTH;
if (!X.RDB$CHARACTER_SET_ID.NULL) {
userFunc->udf_character_set_id = X.RDB$CHARACTER_SET_ID;
}
}
2002-06-29 08:56:51 +02:00
else {
DSC* d;
/* udf_param_node = MAKE_node (type_nod, 0); */
udf_param_node = FB_NEW_RPT(*dbb->dbb_pool, 0) dsql_nod;
d = &udf_param_node->nod_desc;
d->dsc_dtype = (X.RDB$FIELD_TYPE != blr_blob) ?
gds_cvt_blr_dtype[X.RDB$FIELD_TYPE] : dtype_blob;
d->dsc_scale = X.RDB$FIELD_SCALE;
if (!X.RDB$FIELD_SUB_TYPE.NULL) {
d->dsc_sub_type = X.RDB$FIELD_SUB_TYPE;
}
2002-06-29 08:56:51 +02:00
else {
d->dsc_sub_type = 0;
}
d->dsc_length = X.RDB$FIELD_LENGTH;
if (d->dsc_dtype == dtype_varying) {
d->dsc_length += sizeof (USHORT);
}
d->dsc_address = NULL;
if (!X.RDB$CHARACTER_SET_ID.NULL) {
if (d->dsc_dtype != dtype_blob) {
d->dsc_ttype() = X.RDB$CHARACTER_SET_ID;
2002-06-29 08:56:51 +02:00
}
else {
d->dsc_scale = X.RDB$CHARACTER_SET_ID;
2002-06-29 08:56:51 +02:00
}
}
if (X.RDB$MECHANISM != Jrd::FUN_value && X.RDB$MECHANISM != Jrd::FUN_reference)
{
d->dsc_flags = DSC_nullable;
}
stack.push(udf_param_node);
}
2001-05-23 15:26:42 +02:00
THREAD_EXIT();
2001-05-23 15:26:42 +02:00
END_FOR
ON_ERROR
THREAD_ENTER();
ERRD_punt(isc_status);
END_ERROR;
2001-05-23 15:26:42 +02:00
2004-05-15 02:58:46 +02:00
THREAD_ENTER();
2001-05-23 15:26:42 +02:00
// Adjust the return type & length of the UDF to account for
// cstring & varying. While a UDF can return CSTRING, we convert it
// to VARCHAR for manipulation as CSTRING is not a SQL type.
2001-05-23 15:26:42 +02:00
if (userFunc->udf_dtype == dtype_cstring) {
userFunc->udf_dtype = dtype_varying;
userFunc->udf_length += sizeof(USHORT);
if (userFunc->udf_length > MAX_SSHORT)
userFunc->udf_length = MAX_SSHORT;
2001-05-23 15:26:42 +02:00
}
else if (userFunc->udf_dtype == dtype_varying)
userFunc->udf_length += sizeof(USHORT);
2001-05-23 15:26:42 +02:00
2002-06-29 08:56:51 +02:00
/* Can't call MAKE_list because it allocates an initial list node
in the default pool. */
USHORT arg_count = stack.getCount();
2002-06-29 08:56:51 +02:00
/* userFunc->udf_arguments = MAKE_node (nod_list, count); */
userFunc->udf_arguments = FB_NEW_RPT(*dbb->dbb_pool, arg_count) dsql_nod;
userFunc->udf_arguments->nod_type = nod_list;
userFunc->udf_arguments->nod_count = arg_count;
2002-06-29 08:56:51 +02:00
ptr = userFunc->udf_arguments->nod_arg + arg_count;
while (stack.hasData())
{
*--ptr = stack.pop();
// dimitr: adjust the UDF arguments for CSTRING
if ((*ptr)->nod_desc.dsc_dtype == dtype_cstring)
(*ptr)->nod_desc.dsc_dtype = dtype_text;
2002-06-29 08:56:51 +02:00
}
2002-06-29 08:56:51 +02:00
/* Since we could give up control due to the THREAD_EXIT and THEAD_ENTER
* calls, another thread may have added the same udf in the mean time
*/
if ((symbol = lookup_symbol(request->req_dbb, name, SYM_udf)))
{
// Get rid of all the stuff we just read in. Use existing one
free_function (userFunc);
return (dsql_udf*) symbol->sym_object;
2002-06-29 08:56:51 +02:00
}
// Add udf in the front of the list.
userFunc->udf_next = dbb->dbb_functions;
dbb->dbb_functions = userFunc;
2002-06-29 08:56:51 +02:00
// Store in the symbol table
// The UDF_new_udf flag is not used, so nothing extra to check.
2001-05-23 15:26:42 +02:00
symbol = userFunc->udf_symbol = FB_NEW_RPT(*dbb->dbb_pool, 0) dsql_sym;
symbol->sym_object = (BLK) userFunc;
symbol->sym_string = userFunc->udf_name;
2001-05-23 15:26:42 +02:00
symbol->sym_length = name->str_length;
symbol->sym_type = SYM_udf;
symbol->sym_dbb = dbb;
insert_symbol(request->req_dbb, symbol);
2001-05-23 15:26:42 +02:00
return userFunc;
2001-05-23 15:26:42 +02:00
}
dsql_nod* METD_get_primary_key(dsql_req* request, const dsql_str* relation_name)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* M E T D _ g e t _ p r i m a r y _ k e y
*
**************************************
*
* Functional description
* Lookup the fields for the primary key
* index on a relation, returning a list
* node of the fields.
*
**************************************/
2005-09-04 23:32:16 +02:00
ISC_STATUS_ARRAY isc_status = {0};
2004-02-02 12:02:12 +01:00
dsql_dbb* dbb = request->req_dbb;
2005-11-12 19:48:09 +01:00
isc_db_handle DB = dbb->dbb_database_handle;
2001-05-23 15:26:42 +02:00
dsql_nod* list = NULL;
USHORT count = 0;
2001-05-23 15:26:42 +02:00
2004-05-15 02:58:46 +02:00
THREAD_EXIT();
2001-05-23 15:26:42 +02:00
FOR(REQUEST_HANDLE dbb->dbb_requests[irq_primary_key] TRANSACTION_HANDLE request->req_trans)
2001-05-23 15:26:42 +02:00
X IN RDB$INDICES CROSS
2002-09-10 10:07:16 +02:00
Y IN RDB$INDEX_SEGMENTS
OVER RDB$INDEX_NAME CROSS
Z IN RDB$RELATION_CONSTRAINTS
2001-05-23 15:26:42 +02:00
OVER RDB$INDEX_NAME
2002-09-10 20:30:52 +02:00
WITH Z.RDB$RELATION_NAME EQ relation_name->str_data
AND Z.RDB$CONSTRAINT_TYPE EQ "PRIMARY KEY"
2001-05-23 15:26:42 +02:00
SORTED BY Y.RDB$FIELD_POSITION
2004-05-15 02:58:46 +02:00
THREAD_ENTER();
2001-05-23 15:26:42 +02:00
if (!list)
list = MAKE_node(nod_list, (int) X.RDB$SEGMENT_COUNT);
2003-11-10 10:16:38 +01:00
dsql_str* field_name = MAKE_cstring(Y.RDB$FIELD_NAME);
dsql_nod* field_node = MAKE_node(nod_field_name, (int) e_fln_count);
2004-04-10 02:25:22 +02:00
field_node->nod_arg[e_fln_name] = (dsql_nod*) field_name;
2001-05-23 15:26:42 +02:00
list->nod_arg[count] = field_node;
count++;
2004-05-15 02:58:46 +02:00
THREAD_EXIT();
2001-05-23 15:26:42 +02:00
END_FOR
ON_ERROR
2005-09-04 23:32:16 +02:00
THREAD_ENTER();
ERRD_punt(isc_status);
2001-05-23 15:26:42 +02:00
END_ERROR;
2004-05-15 02:58:46 +02:00
THREAD_ENTER();
2001-05-23 15:26:42 +02:00
return list;
}
2003-11-10 10:16:38 +01:00
dsql_prc* METD_get_procedure(dsql_req* request, const dsql_str* name)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* M E T D _ g e t _ p r o c e d u r e
*
**************************************
*
* Functional description
* Look up a procedure. If it doesn't exist, return NULL.
* If it does, fetch field information as well.
* If it is marked dropped, try to read from system tables
*
**************************************/
2004-02-02 12:02:12 +01:00
dsql_dbb* dbb;
2003-11-10 10:16:38 +01:00
dsql_fld* parameter;
dsql_fld** ptr;
dsql_prc* temp;
SSHORT type, count, defaults;
2001-05-23 15:26:42 +02:00
// see if the procedure is the one currently being defined in this request
if (((temp = request->req_procedure) != NULL) &&
2006-12-16 03:21:21 +01:00
!strcmp((char*) temp->prc_name, (char*) name->str_data))
{
return temp;
}
2005-10-28 18:34:59 +02:00
RecMutexHolder holder;
2001-05-23 15:26:42 +02:00
// Start by seeing if symbol is already defined
2001-05-23 15:26:42 +02:00
dsql_sym* symbol = lookup_symbol(request->req_dbb, name, SYM_procedure);
if (symbol)
return (dsql_prc*) symbol->sym_object;
2001-05-23 15:26:42 +02:00
// now see if it is in the database
2001-05-23 15:26:42 +02:00
2005-09-04 23:32:16 +02:00
ISC_STATUS_ARRAY isc_status = {0};
2001-05-23 15:26:42 +02:00
dbb = request->req_dbb;
2005-11-12 19:48:09 +01:00
isc_db_handle DB = dbb->dbb_database_handle;
dsql_prc* procedure = NULL;
2001-05-23 15:26:42 +02:00
2004-05-15 02:58:46 +02:00
THREAD_EXIT();
2001-05-23 15:26:42 +02:00
FOR(REQUEST_HANDLE dbb->dbb_requests[irq_procedure] TRANSACTION_HANDLE request->req_trans)
2001-05-23 15:26:42 +02:00
X IN RDB$PROCEDURES WITH
X.RDB$PROCEDURE_NAME EQ name->str_data
2004-05-15 02:58:46 +02:00
THREAD_ENTER();
2001-05-23 15:26:42 +02:00
fb_utils::exact_name(X.RDB$OWNER_NAME);
2001-05-23 15:26:42 +02:00
procedure = FB_NEW_RPT(*dbb->dbb_pool,
name->str_length + strlen(X.RDB$OWNER_NAME)) dsql_prc;
2001-05-23 15:26:42 +02:00
procedure->prc_id = X.RDB$PROCEDURE_ID;
procedure->prc_name = procedure->prc_data;
procedure->prc_owner = procedure->prc_data + name->str_length + 1;
strcpy(procedure->prc_name, (TEXT *) name->str_data);
2004-10-08 13:08:42 +02:00
strcpy(procedure->prc_owner, X.RDB$OWNER_NAME);
2001-05-23 15:26:42 +02:00
2004-05-15 02:58:46 +02:00
THREAD_EXIT();
2001-05-23 15:26:42 +02:00
END_FOR
ON_ERROR
2005-09-04 23:32:16 +02:00
THREAD_ENTER();
ERRD_punt(isc_status);
2001-05-23 15:26:42 +02:00
END_ERROR;
2004-05-15 02:58:46 +02:00
THREAD_ENTER();
2001-05-23 15:26:42 +02:00
if (!procedure) {
return NULL;
}
// Lookup parameter stuff
2001-05-23 15:26:42 +02:00
for (type = 0; type < 2; type++) {
if (type)
ptr = &procedure->prc_outputs;
else
ptr = &procedure->prc_inputs;
count = defaults = 0;
2001-05-23 15:26:42 +02:00
2004-05-15 02:58:46 +02:00
THREAD_EXIT();
2001-05-23 15:26:42 +02:00
FOR(REQUEST_HANDLE dbb->dbb_requests[irq_parameters] TRANSACTION_HANDLE request->req_trans)
2001-05-23 15:26:42 +02:00
PR IN RDB$PROCEDURE_PARAMETERS CROSS
FLD IN RDB$FIELDS
WITH FLD.RDB$FIELD_NAME EQ PR.RDB$FIELD_SOURCE
2001-05-23 15:26:42 +02:00
AND PR.RDB$PROCEDURE_NAME EQ name->str_data
AND PR.RDB$PARAMETER_TYPE = type
SORTED BY DESCENDING PR.RDB$PARAMETER_NUMBER
SSHORT pr_collation_id_null = TRUE;
SSHORT pr_collation_id;
SSHORT pr_default_value_null = TRUE;
SSHORT pr_null_flag_null = TRUE;
SSHORT pr_null_flag;
bool pr_type_of = false;
if (ENCODE_ODS(dbb->dbb_ods_version, dbb->dbb_minor_version) >= ODS_11_1)
{
FOR(REQUEST_HANDLE dbb->dbb_requests[irq_parameters2] TRANSACTION_HANDLE request->req_trans)
PR2 IN RDB$PROCEDURE_PARAMETERS
WITH PR2.RDB$PROCEDURE_NAME EQ PR.RDB$PROCEDURE_NAME AND
PR2.RDB$PARAMETER_NAME EQ PR.RDB$PARAMETER_NAME
pr_collation_id_null = PR2.RDB$COLLATION_ID.NULL;
pr_collation_id = PR2.RDB$COLLATION_ID;
pr_default_value_null = PR2.RDB$DEFAULT_VALUE.NULL;
pr_null_flag_null = PR2.RDB$NULL_FLAG.NULL;
pr_null_flag = PR2.RDB$NULL_FLAG;
if (!PR2.RDB$PARAMETER_MECHANISM.NULL && PR2.RDB$PARAMETER_MECHANISM == prm_mech_type_of)
pr_type_of = true;
END_FOR
}
2001-05-23 15:26:42 +02:00
THREAD_ENTER();
2001-05-23 15:26:42 +02:00
count++;
// allocate the field block
2001-05-23 15:26:42 +02:00
fb_utils::exact_name(PR.RDB$PARAMETER_NAME);
parameter = FB_NEW_RPT(*dbb->dbb_pool,
strlen(PR.RDB$PARAMETER_NAME)) dsql_fld;
parameter->fld_next = *ptr;
*ptr = parameter;
// get parameter information
strcpy(parameter->fld_name, PR.RDB$PARAMETER_NAME);
parameter->fld_id = PR.RDB$PARAMETER_NUMBER;
parameter->fld_length = FLD.RDB$FIELD_LENGTH;
parameter->fld_scale = FLD.RDB$FIELD_SCALE;
parameter->fld_sub_type = FLD.RDB$FIELD_SUB_TYPE;
parameter->fld_procedure = procedure;
if (!FLD.RDB$CHARACTER_SET_ID.NULL)
parameter->fld_character_set_id = FLD.RDB$CHARACTER_SET_ID;
if (!pr_collation_id_null)
parameter->fld_collation_id = pr_collation_id;
else if (!FLD.RDB$COLLATION_ID.NULL)
parameter->fld_collation_id = FLD.RDB$COLLATION_ID;
convert_dtype(parameter, FLD.RDB$FIELD_TYPE);
2001-05-23 15:26:42 +02:00
if (!pr_null_flag_null)
{
if (!pr_null_flag)
parameter->fld_flags |= FLD_nullable;
}
else if (!FLD.RDB$NULL_FLAG || pr_type_of)
parameter->fld_flags |= FLD_nullable;
if (FLD.RDB$FIELD_TYPE == blr_blob)
parameter->fld_seg_length = FLD.RDB$SEGMENT_LENGTH;
if (type == 0 &&
(!pr_default_value_null ||
(fb_utils::implicit_domain(FLD.RDB$FIELD_NAME) &&
!FLD.RDB$DEFAULT_VALUE.NULL)))
{
defaults++;
}
THREAD_EXIT();
2001-05-23 15:26:42 +02:00
END_FOR
ON_ERROR
2005-09-04 23:32:16 +02:00
THREAD_ENTER();
ERRD_punt(isc_status);
2001-05-23 15:26:42 +02:00
END_ERROR;
2004-05-15 02:58:46 +02:00
THREAD_ENTER();
2001-05-23 15:26:42 +02:00
if (type)
procedure->prc_out_count = count;
else {
2001-05-23 15:26:42 +02:00
procedure->prc_in_count = count;
procedure->prc_def_count = defaults;
}
2001-05-23 15:26:42 +02:00
}
// Since we could give up control due to the THREAD_EXIT and THEAD_ENTER
// calls, another thread may have added the same procedure in the mean time
2001-05-23 15:26:42 +02:00
if ((symbol = lookup_symbol(request->req_dbb, name, SYM_procedure)))
{
// Get rid of all the stuff we just read in. Use existing one
free_procedure(procedure);
return (dsql_prc*) symbol->sym_object;
}
2001-05-23 15:26:42 +02:00
// store in the symbol table unless the procedure is not yet committed
// CVC: This is strange, because PRC_new_procedure is never set.
2001-05-23 15:26:42 +02:00
if (!(procedure->prc_flags & PRC_new_procedure)) {
// add procedure in the front of the list
2001-05-23 15:26:42 +02:00
procedure->prc_next = dbb->dbb_procedures;
dbb->dbb_procedures = procedure;
symbol = procedure->prc_symbol = FB_NEW_RPT(*dbb->dbb_pool, 0) dsql_sym;
2001-05-23 15:26:42 +02:00
symbol->sym_object = (BLK) procedure;
symbol->sym_string = procedure->prc_name;
symbol->sym_length = name->str_length;
symbol->sym_type = SYM_procedure;
symbol->sym_dbb = dbb;
insert_symbol(request->req_dbb, symbol);
2001-05-23 15:26:42 +02:00
}
return procedure;
}
2003-11-10 10:16:38 +01:00
dsql_rel* METD_get_relation(dsql_req* request, const dsql_str* name)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* M E T D _ g e t _ r e l a t i o n
*
**************************************
*
* Functional description
* Look up a relation. If it doesn't exist, return NULL.
* If it does, fetch field information as well.
*
**************************************/
2004-02-02 12:02:12 +01:00
dsql_dbb* dbb;
2003-11-10 10:16:38 +01:00
dsql_fld* field;
dsql_fld** ptr;
dsql_rel* temp;
2001-05-23 15:26:42 +02:00
// See if the relation is the one currently being defined in this request
if (((temp = request->req_relation) != NULL) &&
2006-12-16 03:21:21 +01:00
!strcmp((char*) temp->rel_name, (char*) name->str_data))
{
return temp;
}
tsql* tdsql = DSQL_get_thread_data();
2001-05-23 15:26:42 +02:00
2005-10-28 18:34:59 +02:00
RecMutexHolder holder;
2001-05-23 15:26:42 +02:00
// Start by seeing if symbol is already defined
2001-05-23 15:26:42 +02:00
dsql_sym* symbol = lookup_symbol(request->req_dbb, name, SYM_relation);
if (symbol)
return (dsql_rel*) symbol->sym_object;
2001-05-23 15:26:42 +02:00
2005-09-04 23:32:16 +02:00
ISC_STATUS_ARRAY isc_status = {0};
2001-05-23 15:26:42 +02:00
dbb = request->req_dbb;
2005-11-12 19:48:09 +01:00
isc_db_handle DB = dbb->dbb_database_handle;
// If the relation id or any of the field ids have not yet been assigned,
// and this is a type of request which does not use ids, prepare a
// temporary relation block to provide information without caching it
bool permanent = true;
THREAD_EXIT();
FOR(REQUEST_HANDLE dbb->dbb_requests[irq_rel_ids] TRANSACTION_HANDLE request->req_trans)
REL IN RDB$RELATIONS
CROSS RFR IN RDB$RELATION_FIELDS OVER RDB$RELATION_NAME
WITH REL.RDB$RELATION_NAME EQ name->str_data
AND (REL.RDB$RELATION_ID MISSING OR RFR.RDB$FIELD_ID MISSING)
THREAD_ENTER();
permanent = false;
THREAD_EXIT();
END_FOR
ON_ERROR
THREAD_ENTER();
ERRD_punt(isc_status);
END_ERROR;
THREAD_ENTER();
// Now see if it is in the database
DsqlMemoryPool& pool =
permanent ? *dbb->dbb_pool : *tdsql->getDefaultPool();
dsql_rel* relation = NULL;
2001-05-23 15:26:42 +02:00
2004-05-15 02:58:46 +02:00
THREAD_EXIT();
2001-05-23 15:26:42 +02:00
FOR(REQUEST_HANDLE dbb->dbb_requests[irq_relation] TRANSACTION_HANDLE request->req_trans)
2001-05-23 15:26:42 +02:00
X IN RDB$RELATIONS WITH X.RDB$RELATION_NAME EQ name->str_data
2004-05-15 02:58:46 +02:00
THREAD_ENTER();
2001-05-23 15:26:42 +02:00
fb_utils::exact_name(X.RDB$OWNER_NAME);
const int length = name->str_length + strlen(X.RDB$OWNER_NAME);
// Allocate from default or permanent pool as appropriate
2001-05-23 15:26:42 +02:00
if (!X.RDB$RELATION_ID.NULL) {
relation = FB_NEW_RPT(pool, length) dsql_rel;
2001-05-23 15:26:42 +02:00
relation->rel_id = X.RDB$RELATION_ID;
}
else if (!DDL_ids(request)) {
relation = FB_NEW_RPT(pool, length) dsql_rel;
2001-05-23 15:26:42 +02:00
}
// fill out the relation information
2001-05-23 15:26:42 +02:00
if (relation) {
relation->rel_name = relation->rel_data;
relation->rel_owner = relation->rel_data + name->str_length + 1;
strcpy(relation->rel_name, (TEXT *) name->str_data);
2004-10-08 13:08:42 +02:00
strcpy(relation->rel_owner, X.RDB$OWNER_NAME);
2001-05-23 15:26:42 +02:00
if (!(relation->rel_dbkey_length = X.RDB$DBKEY_LENGTH))
relation->rel_dbkey_length = 8;
// CVC: let's see if this is a table or a view.
2002-06-29 08:56:51 +02:00
if (!X.RDB$VIEW_BLR.NULL) {
relation->rel_flags |= REL_view;
}
if (!X.RDB$EXTERNAL_FILE.NULL) {
relation->rel_flags |= REL_external;
}
2001-05-23 15:26:42 +02:00
}
2004-05-15 02:58:46 +02:00
THREAD_EXIT();
2001-05-23 15:26:42 +02:00
END_FOR
ON_ERROR
2005-09-04 23:32:16 +02:00
THREAD_ENTER();
ERRD_punt(isc_status);
2001-05-23 15:26:42 +02:00
END_ERROR;
2004-05-15 02:58:46 +02:00
THREAD_ENTER();
2001-05-23 15:26:42 +02:00
if (!relation) {
return NULL;
}
// Lookup field stuff
2001-05-23 15:26:42 +02:00
ptr = &relation->rel_fields;
2004-05-15 02:58:46 +02:00
THREAD_EXIT();
2001-05-23 15:26:42 +02:00
FOR(REQUEST_HANDLE dbb->dbb_requests[irq_fields] TRANSACTION_HANDLE request->req_trans)
FLX IN RDB$FIELDS CROSS
RFR IN RDB$RELATION_FIELDS
WITH FLX.RDB$FIELD_NAME EQ RFR.RDB$FIELD_SOURCE
AND RFR.RDB$RELATION_NAME EQ name->str_data
SORTED BY RFR.RDB$FIELD_POSITION
2001-05-23 15:26:42 +02:00
THREAD_ENTER();
2001-05-23 15:26:42 +02:00
// allocate the field block
2001-05-23 15:26:42 +02:00
fb_utils::exact_name(RFR.RDB$FIELD_NAME);
const int length = strlen(RFR.RDB$FIELD_NAME);
2001-05-23 15:26:42 +02:00
// Allocate from default or permanent pool as appropriate
field = NULL;
if (!RFR.RDB$FIELD_ID.NULL) {
field = FB_NEW_RPT(pool, length) dsql_fld;
field->fld_id = RFR.RDB$FIELD_ID;
}
else if (!DDL_ids(request)) {
field = FB_NEW_RPT(pool, length) dsql_fld;
}
2002-06-29 08:56:51 +02:00
if (field) {
*ptr = field;
ptr = &field->fld_next;
// get field information
strcpy(field->fld_name, RFR.RDB$FIELD_NAME);
field->fld_length = FLX.RDB$FIELD_LENGTH;
field->fld_scale = FLX.RDB$FIELD_SCALE;
field->fld_sub_type = FLX.RDB$FIELD_SUB_TYPE;
field->fld_relation = relation;
if (!FLX.RDB$COMPUTED_BLR.NULL)
field->fld_flags |= FLD_computed;
convert_dtype(field, FLX.RDB$FIELD_TYPE);
if (FLX.RDB$FIELD_TYPE == blr_blob) {
field->fld_seg_length = FLX.RDB$SEGMENT_LENGTH;
}
if (!FLX.RDB$DIMENSIONS.NULL && FLX.RDB$DIMENSIONS) {
field->fld_element_dtype = field->fld_dtype;
field->fld_element_length = field->fld_length;
field->fld_dtype = dtype_array;
field->fld_length = sizeof(ISC_QUAD);
field->fld_dimensions = FLX.RDB$DIMENSIONS;
}
if (!FLX.RDB$CHARACTER_SET_ID.NULL)
field->fld_character_set_id = FLX.RDB$CHARACTER_SET_ID;
if (!RFR.RDB$COLLATION_ID.NULL)
field->fld_collation_id = RFR.RDB$COLLATION_ID;
else if (!FLX.RDB$COLLATION_ID.NULL)
field->fld_collation_id = FLX.RDB$COLLATION_ID;
if (!(RFR.RDB$NULL_FLAG || FLX.RDB$NULL_FLAG)
|| (relation->rel_flags & REL_view))
{
field->fld_flags |= FLD_nullable;
}
if (RFR.RDB$SYSTEM_FLAG == 1 || FLX.RDB$SYSTEM_FLAG == 1)
field->fld_flags |= FLD_system;
}
THREAD_EXIT();
2001-05-23 15:26:42 +02:00
END_FOR
ON_ERROR
THREAD_ENTER();
ERRD_punt(isc_status);
END_ERROR;
2001-05-23 15:26:42 +02:00
2004-05-15 02:58:46 +02:00
THREAD_ENTER();
2001-05-23 15:26:42 +02:00
// Since we could give up control due to the THREAD_EXIT and THREAD_ENTER,
// another thread may have added the same table in the mean time
if ((symbol = lookup_symbol(request->req_dbb, name, SYM_relation)))
{
free_relation(relation);
return (dsql_rel*) symbol->sym_object;
}
2001-05-23 15:26:42 +02:00
// Add relation to front of list
2001-05-23 15:26:42 +02:00
if (permanent) {
2001-05-23 15:26:42 +02:00
relation->rel_next = dbb->dbb_relations;
dbb->dbb_relations = relation;
// store in the symbol table unless the relation is not yet committed
2001-05-23 15:26:42 +02:00
symbol = relation->rel_symbol = FB_NEW_RPT(*dbb->dbb_pool, 0) dsql_sym;
2001-05-23 15:26:42 +02:00
symbol->sym_object = (BLK) relation;
symbol->sym_string = relation->rel_name;
symbol->sym_length = name->str_length;
symbol->sym_type = SYM_relation;
symbol->sym_dbb = dbb;
insert_symbol(request->req_dbb, symbol);
2001-05-23 15:26:42 +02:00
}
else {
relation->rel_flags |= REL_new_relation;
}
2001-05-23 15:26:42 +02:00
return relation;
}
bool METD_get_trigger(dsql_req* request, const dsql_str* name, dsql_str** relation, USHORT* trig_type)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* M E T D _ g e t _ t r i g g e r
2001-05-23 15:26:42 +02:00
*
**************************************
*
* Functional description
* Look up a trigger's relation and it's current type
2001-05-23 15:26:42 +02:00
*
**************************************/
2004-02-02 12:02:12 +01:00
dsql_dbb* dbb;
2001-05-23 15:26:42 +02:00
2005-09-04 23:32:16 +02:00
ISC_STATUS_ARRAY isc_status = {0};
2001-05-23 15:26:42 +02:00
dbb = request->req_dbb;
2005-11-12 19:48:09 +01:00
isc_db_handle DB = dbb->dbb_database_handle;
2001-05-23 15:26:42 +02:00
bool found = false;
if (relation)
*relation = NULL;
2001-05-23 15:26:42 +02:00
2004-05-15 02:58:46 +02:00
THREAD_EXIT();
2001-05-23 15:26:42 +02:00
FOR(REQUEST_HANDLE dbb->dbb_requests[irq_trigger] TRANSACTION_HANDLE request->req_trans)
2003-10-16 10:51:06 +02:00
X IN RDB$TRIGGERS WITH X.RDB$TRIGGER_NAME EQ name->str_data
2004-05-15 02:58:46 +02:00
THREAD_ENTER();
2001-05-23 15:26:42 +02:00
found = true;
2003-10-16 10:51:06 +02:00
*trig_type = X.RDB$TRIGGER_TYPE;
if (!X.RDB$RELATION_NAME.NULL)
{
if (relation)
{
fb_utils::exact_name(X.RDB$RELATION_NAME);
*relation = MAKE_string(X.RDB$RELATION_NAME, strlen(X.RDB$RELATION_NAME));
}
}
2004-05-15 02:58:46 +02:00
THREAD_EXIT();
2001-05-23 15:26:42 +02:00
END_FOR
ON_ERROR
2005-09-04 23:32:16 +02:00
THREAD_ENTER();
ERRD_punt(isc_status);
2001-05-23 15:26:42 +02:00
END_ERROR;
2004-05-15 02:58:46 +02:00
THREAD_ENTER();
2001-05-23 15:26:42 +02:00
return found;
2001-05-23 15:26:42 +02:00
}
bool METD_get_type(dsql_req* request, const dsql_str* name, char* field, SSHORT* value)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* M E T D _ g e t _ t y p e
*
**************************************
*
* Functional description
* Look up a symbolic name in RDB$TYPES
*
**************************************/
2004-02-02 12:02:12 +01:00
dsql_dbb* dbb;
bool found = false;
2001-05-23 15:26:42 +02:00
2005-09-04 23:32:16 +02:00
ISC_STATUS_ARRAY isc_status = {0};
2001-05-23 15:26:42 +02:00
dbb = request->req_dbb;
2005-11-12 19:48:09 +01:00
isc_db_handle DB = dbb->dbb_database_handle;
2001-05-23 15:26:42 +02:00
2004-05-15 02:58:46 +02:00
THREAD_EXIT();
2001-05-23 15:26:42 +02:00
FOR(REQUEST_HANDLE dbb->dbb_requests[irq_type] TRANSACTION_HANDLE request->req_trans)
2003-10-16 10:51:06 +02:00
X IN RDB$TYPES WITH
2001-05-23 15:26:42 +02:00
X.RDB$FIELD_NAME EQ field AND X.RDB$TYPE_NAME EQ name->str_data;
2004-05-15 02:58:46 +02:00
THREAD_ENTER();
2001-05-23 15:26:42 +02:00
found = true;
2003-10-16 10:51:06 +02:00
*value = X.RDB$TYPE;
2004-05-15 02:58:46 +02:00
THREAD_EXIT();
2001-05-23 15:26:42 +02:00
END_FOR
ON_ERROR
2005-09-04 23:32:16 +02:00
THREAD_ENTER();
ERRD_punt(isc_status);
2001-05-23 15:26:42 +02:00
END_ERROR;
2004-05-15 02:58:46 +02:00
THREAD_ENTER();
2001-05-23 15:26:42 +02:00
return found;
}
2006-09-03 03:09:23 +02:00
dsql_rel* METD_get_view_base(dsql_req* request,
const char* view_name, // UTF-8
MetaNamePairMap& fields)
{
/**************************************
*
* M E T D _ g e t _ v i e w _ b a s e
*
**************************************
*
* Functional description
* Return the base table of a view or NULL if there
* is more than one.
* If there is only one base, put in fields a map of
* top view field name / bottom base field name.
* Ignores the field in the case of a base field name
* appearing more than one time in a level.
2006-09-03 03:09:23 +02:00
*
**************************************/
dsql_rel* relation = NULL;
ISC_STATUS_ARRAY isc_status = {0};
dsql_dbb* dbb = request->req_dbb;
isc_db_handle DB = dbb->dbb_database_handle;
bool first = true;
bool cont = true;
MetaNamePairMap previousAux;
2006-09-03 03:09:23 +02:00
fields.clear();
while (cont)
{
THREAD_EXIT();
FOR(REQUEST_HANDLE dbb->dbb_requests[irq_view_base]
TRANSACTION_HANDLE request->req_trans)
X IN RDB$VIEW_RELATIONS
WITH X.RDB$VIEW_NAME EQ view_name
// return NULL if there is more than one context
if (X.RDB$VIEW_CONTEXT != 1)
{
relation = NULL;
cont = false;
break;
}
THREAD_ENTER();
fb_utils::exact_name(X.RDB$CONTEXT_NAME);
fb_utils::exact_name(X.RDB$RELATION_NAME);
dsql_str* relation_name =
MAKE_string(X.RDB$RELATION_NAME, strlen(X.RDB$RELATION_NAME));
relation = METD_get_relation(request, relation_name);
delete relation_name;
Firebird::Array<Firebird::MetaName> ambiguities;
MetaNamePairMap currentAux;
2006-09-03 03:09:23 +02:00
THREAD_EXIT();
if (!relation)
{
cont = false;
break;
}
FOR(REQUEST_HANDLE dbb->dbb_requests[irq_view_base_flds]
TRANSACTION_HANDLE request->req_trans)
RFL IN RDB$RELATION_FIELDS
WITH RFL.RDB$RELATION_NAME EQ X.RDB$VIEW_NAME
2006-09-07 05:43:55 +02:00
if (RFL.RDB$BASE_FIELD.NULL || RFL.RDB$FIELD_NAME.NULL)
continue;
2006-09-03 03:09:23 +02:00
2006-09-07 05:43:55 +02:00
THREAD_ENTER();
if (currentAux.exist(RFL.RDB$BASE_FIELD))
ambiguities.add(RFL.RDB$BASE_FIELD);
2006-09-03 03:09:23 +02:00
else
{
if (first)
{
fields.put(RFL.RDB$FIELD_NAME, RFL.RDB$BASE_FIELD);
currentAux.put(RFL.RDB$BASE_FIELD, RFL.RDB$FIELD_NAME);
}
else
2006-09-03 03:09:23 +02:00
{
Firebird::MetaName field;
2006-09-03 03:09:23 +02:00
if (previousAux.get(RFL.RDB$FIELD_NAME, field))
{
fields.put(field, RFL.RDB$BASE_FIELD);
currentAux.put(RFL.RDB$BASE_FIELD, field);
}
2006-09-03 03:09:23 +02:00
}
}
THREAD_EXIT();
END_FOR
for (Firebird::MetaName* i = ambiguities.begin(); i != ambiguities.end(); ++i)
{
Firebird::MetaName field;
if (currentAux.get(*i, field))
{
currentAux.remove(*i);
fields.remove(field);
}
}
previousAux.takeOwnership(currentAux);
2006-09-03 03:09:23 +02:00
if (relation->rel_flags & REL_view)
view_name = X.RDB$RELATION_NAME;
else
{
cont = false;
break;
}
first = false;
END_FOR
ON_ERROR
THREAD_ENTER();
ERRD_punt(isc_status);
END_ERROR;
THREAD_ENTER();
}
if (!relation)
fields.clear();
return relation;
}
dsql_rel* METD_get_view_relation(dsql_req* request,
const char* view_name, // UTF-8
const char* relation_or_alias, // UTF-8
USHORT level)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* M E T D _ g e t _ v i e w _ r e l a t i o n
*
**************************************
*
* Functional description
* Return TRUE if the passed view_name represents a
* view with the passed relation as a base table
* (the relation could be an alias).
*
**************************************/
2006-09-03 03:09:23 +02:00
dsql_rel* relation = NULL;
2001-05-23 15:26:42 +02:00
2005-09-04 23:32:16 +02:00
ISC_STATUS_ARRAY isc_status = {0};
dsql_dbb* dbb = request->req_dbb;
2005-11-12 19:48:09 +01:00
isc_db_handle DB = dbb->dbb_database_handle;
2001-05-23 15:26:42 +02:00
2004-05-15 02:58:46 +02:00
THREAD_EXIT();
2001-05-23 15:26:42 +02:00
FOR(REQUEST_HANDLE dbb->dbb_requests[irq_view] TRANSACTION_HANDLE request->req_trans, LEVEL level)
2003-10-16 10:51:06 +02:00
X IN RDB$VIEW_RELATIONS WITH X.RDB$VIEW_NAME EQ view_name
2001-05-23 15:26:42 +02:00
2004-05-15 02:58:46 +02:00
THREAD_ENTER();
2001-05-23 15:26:42 +02:00
fb_utils::exact_name(X.RDB$CONTEXT_NAME);
fb_utils::exact_name(X.RDB$RELATION_NAME);
2003-10-16 10:51:06 +02:00
if (!strcmp(X.RDB$RELATION_NAME, relation_or_alias) ||
!strcmp(X.RDB$CONTEXT_NAME, relation_or_alias))
{
2003-11-10 10:16:38 +01:00
dsql_str* relation_name = MAKE_string(X.RDB$RELATION_NAME,
2006-09-03 03:09:23 +02:00
strlen(X.RDB$RELATION_NAME));
2003-10-16 10:51:06 +02:00
relation = METD_get_relation(request, relation_name);
delete relation_name;
return relation;
}
relation =
2003-10-16 10:51:06 +02:00
METD_get_view_relation(request, X.RDB$RELATION_NAME,
2006-09-03 03:09:23 +02:00
relation_or_alias, (USHORT)level + 1);
2003-10-16 10:51:06 +02:00
if (relation) {
return relation;
}
2001-05-23 15:26:42 +02:00
2004-05-15 02:58:46 +02:00
THREAD_EXIT();
2001-05-23 15:26:42 +02:00
END_FOR
ON_ERROR
2005-09-04 23:32:16 +02:00
THREAD_ENTER();
ERRD_punt(isc_status);
2001-05-23 15:26:42 +02:00
END_ERROR;
2004-05-15 02:58:46 +02:00
THREAD_ENTER();
2001-05-23 15:26:42 +02:00
return NULL;
}
2006-01-16 17:31:15 +01:00
#ifdef NOT_USED_OR_REPLACED
/* - to make gpre happy too
static void check_array(dsql_req* request, const TEXT* field_name, dsql_fld* field)
2001-05-23 15:26:42 +02:00
{
2006-01-16 17:31:15 +01:00
**************************************
2001-05-23 15:26:42 +02:00
*
* c h e c k _ a r r a y
*
**************************************
*
* Functional description
* Try to get field dimensions (RDB$FIELD_DIMENSIONS may not be
* defined in the meta-data). If we're not successful, indicate
* so in the database block to avoid wasting further effort.
*
2006-01-16 17:31:15 +01:00
**************************************
2004-02-02 12:02:12 +01:00
dsql_dbb* dbb;
2001-05-23 15:26:42 +02:00
2005-09-04 23:32:16 +02:00
ISC_STATUS_ARRAY isc_status = {0};
2001-05-23 15:26:42 +02:00
dbb = request->req_dbb;
2005-11-12 19:48:09 +01:00
isc_db_handle DB = dbb->dbb_database_handle;
2001-05-23 15:26:42 +02:00
2004-05-15 02:58:46 +02:00
THREAD_EXIT();
2001-05-23 15:26:42 +02:00
FOR(REQUEST_HANDLE dbb->dbb_requests[irq_dimensions] TRANSACTION_HANDLE request->req_trans)
2001-05-23 15:26:42 +02:00
X IN RDB$FIELDS WITH X.RDB$FIELD_NAME EQ field_name
2004-05-15 02:58:46 +02:00
THREAD_ENTER();
2001-05-23 15:26:42 +02:00
if (!X.RDB$DIMENSIONS.NULL && X.RDB$DIMENSIONS) {
field->fld_element_dtype = field->fld_dtype;
field->fld_element_length = field->fld_length;
field->fld_dtype = dtype_array;
field->fld_length = sizeof(ISC_QUAD);
2001-05-23 15:26:42 +02:00
field->fld_dimensions = X.RDB$DIMENSIONS;
}
2004-05-15 02:58:46 +02:00
THREAD_EXIT();
2001-05-23 15:26:42 +02:00
END_FOR
ON_ERROR
dbb->dbb_flags |= DBB_no_arrays;
END_ERROR;
2004-05-15 02:58:46 +02:00
THREAD_ENTER();
2001-05-23 15:26:42 +02:00
}
2006-01-16 17:31:15 +01:00
*/
#endif
2001-05-23 15:26:42 +02:00
static void convert_dtype(dsql_fld* field, SSHORT field_type)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* c o n v e r t _ d t y p e
*
**************************************
*
* Functional description
* Convert from the blr_<type> stored in system metadata
* to the internal dtype_* descriptor. Also set field
* length.
*
**************************************/
// fill out the type descriptor
2001-05-23 15:26:42 +02:00
if (field_type == blr_text) {
field->fld_dtype = dtype_text;
}
else if (field_type == blr_varying) {
field->fld_dtype = dtype_varying;
field->fld_length += sizeof(USHORT);
}
else if (field_type == blr_blob) {
field->fld_dtype = dtype_blob;
field->fld_length = type_lengths[field->fld_dtype];
}
else {
field->fld_dtype = gds_cvt_blr_dtype[field_type];
field->fld_length = type_lengths[field->fld_dtype];
2003-12-22 11:00:59 +01:00
fb_assert(field->fld_dtype != dtype_unknown);
2001-05-23 15:26:42 +02:00
}
}
static void free_function(dsql_udf* userFunc)
2002-06-29 08:56:51 +02:00
{
/**************************************
*
* f r e e _ f u n c t i o n
*
**************************************
*
* Functional description
* Free memory allocated for a function block and args
*
**************************************/
// release the arguments blocks
2002-06-29 08:56:51 +02:00
if (userFunc->udf_arguments) {
dsql_nod* args = userFunc->udf_arguments;
for (USHORT arg_count = 0; arg_count < args->nod_count; ++arg_count) {
2003-11-10 10:16:38 +01:00
dsql_nod* udf_argument = args->nod_arg[arg_count];
2002-06-29 08:56:51 +02:00
delete udf_argument;
}
}
/* release the udf & symbol blocks */
delete userFunc;
2002-06-29 08:56:51 +02:00
}
static void free_procedure(dsql_prc* procedure)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* f r e e _ p r o c e d u r e
*
**************************************
*
* Functional description
* Free memory allocated for a procedure block and params
*
**************************************/
2003-11-10 10:16:38 +01:00
dsql_fld* param;
dsql_fld* temp;
2001-05-23 15:26:42 +02:00
/* release the input & output parameter blocks */
for (param = procedure->prc_inputs; param;) {
temp = param;
param = param->fld_next;
2001-12-24 03:51:06 +01:00
delete temp;
2001-05-23 15:26:42 +02:00
}
for (param = procedure->prc_outputs; param;) {
temp = param;
param = param->fld_next;
2001-12-24 03:51:06 +01:00
delete temp;
2001-05-23 15:26:42 +02:00
}
/* release the procedure & symbol blocks */
2001-12-24 03:51:06 +01:00
delete procedure;
2001-05-23 15:26:42 +02:00
}
static void free_relation(dsql_rel* relation)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* f r e e _ r e l a t i o n
*
**************************************
*
* Functional description
* Free memory allocated for a relation block and fields
*
**************************************/
2003-11-10 10:16:38 +01:00
dsql_fld* field;
dsql_fld* temp;
2001-05-23 15:26:42 +02:00
// release the field blocks
2001-05-23 15:26:42 +02:00
for (field = relation->rel_fields; field;) {
temp = field;
field = field->fld_next;
2001-12-24 03:51:06 +01:00
delete temp;
2001-05-23 15:26:42 +02:00
}
/* release the relation & symbol blocks */
2001-12-24 03:51:06 +01:00
delete relation;
2001-05-23 15:26:42 +02:00
}
static void insert_symbol(dsql_dbb* dbb, dsql_sym* symbol)
{
/**************************************
*
* i n s e r t _ s y m b o l
*
**************************************
*
* Functional description
* Insert a symbol in the hash table and
* inform the engine that we're using it.
*
**************************************/
HSHD_insert(symbol);
#ifndef SUPERSERVER
ISC_STATUS_ARRAY status;
THREAD_EXIT();
const ISC_STATUS s = gds__dsql_cache(status, &dbb->dbb_database_handle,
DSQL_CACHE_USE, symbol->sym_type, symbol->sym_string, NULL);
THREAD_ENTER();
if (s)
ERRD_punt(status);
#endif // SUPERSERVER
}
static dsql_sym* lookup_symbol(dsql_dbb* dbb, USHORT length, const char* name, SYM_TYPE type, USHORT charset_id)
{
/**************************************
*
* l o o k u p _ s y m b o l
*
**************************************
*
* Functional description
* Lookup a symbol in the hash table and
* inform the engine that we're using it.
* The engine may inform that the symbol
* is obsolete, in this case mark it as
* dropped and return NULL.
*
**************************************/
dsql_intlsym* intlSym;
dsql_prc* procedure;
dsql_rel* relation;
dsql_udf* userFunc;
dsql_sym* symbol = HSHD_lookup(dbb, name, length, type, 0);
for (; symbol; symbol = symbol->sym_homonym)
{
if (symbol->sym_type == type)
{
if (type == SYM_intlsym_charset)
break;
else if (type == SYM_intlsym_collation &&
(intlSym = (dsql_intlsym*) symbol->sym_object) &&
(!(intlSym->intlsym_flags & INTLSYM_dropped)) &&
(charset_id == 0 || intlSym->intlsym_charset_id == charset_id))
{
break;
}
else if (type == SYM_procedure &&
(procedure = (dsql_prc*) symbol->sym_object) &&
(!(procedure->prc_flags & PRC_dropped)))
{
break;
}
else if (type == SYM_relation &&
(relation = (dsql_rel*) symbol->sym_object) &&
(!(relation->rel_flags & REL_dropped)))
{
break;
}
else if (type == SYM_udf &&
(userFunc = (dsql_udf*) symbol->sym_object) &&
(!(userFunc->udf_flags & UDF_dropped)))
{
break;
}
}
}
#ifndef SUPERSERVER
if (symbol)
{
ISC_STATUS_ARRAY status;
bool obsolete;
THREAD_EXIT();
const ISC_STATUS s = gds__dsql_cache(status, &dbb->dbb_database_handle,
DSQL_CACHE_USE, type, name, &obsolete);
THREAD_ENTER();
if (s)
ERRD_punt(status);
if (obsolete)
{
switch (type)
{
case SYM_intlsym_collation:
intlSym->intlsym_flags |= INTLSYM_dropped;
break;
case SYM_procedure:
procedure->prc_flags |= PRC_dropped;
break;
case SYM_relation:
relation->rel_flags |= REL_dropped;
break;
case SYM_udf:
userFunc->udf_flags |= UDF_dropped;
break;
default:
return symbol;
}
symbol = NULL;
}
}
#endif // SUPERSERVER
return symbol;
}
static dsql_sym* lookup_symbol(dsql_dbb* dbb, const dsql_str* name, SYM_TYPE type, USHORT charset_id)
{
/**************************************
*
* l o o k u p _ s y m b o l
*
**************************************
*
* Functional description
* Wrapper for the above function.
*
**************************************/
return lookup_symbol(dbb, name->str_length,
reinterpret_cast<const TEXT*>(name->str_data), type, charset_id);
}