8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-29 06:43:03 +01:00
firebird-mirror/src/gpre/gpre_meta.epp

2253 lines
58 KiB
Plaintext
Raw Normal View History

2001-05-23 15:26:42 +02:00
/*
* tab=4
*____________________________________________________________
*
* PROGRAM: C preprocessor
2001-12-24 03:51:06 +01:00
* MODULE: gpre_meta.epp
2001-05-23 15:26:42 +02:00
* DESCRIPTION: Meta data interface to system
*
* 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): ______________________________________.
*
*
*____________________________________________________________
*
2003-10-07 11:58:26 +02:00
* $Id: gpre_meta.epp,v 1.27 2003-10-07 09:58:26 robocop Exp $
2001-05-23 15:26:42 +02:00
*/
#include "firebird.h"
2001-05-23 15:26:42 +02:00
#include <string.h>
#include "../jrd/gds.h"
2001-05-23 15:26:42 +02:00
#include "../gpre/gpre.h"
#include "../jrd/license.h"
#include "../gpre/parse.h"
#include "../jrd/intl.h"
#include "../gpre/gpre_proto.h"
#include "../gpre/hsh_proto.h"
#include "../gpre/jrdme_proto.h"
#include "../gpre/gpre_meta.h"
#include "../gpre/msc_proto.h"
#include "../gpre/par_proto.h"
#include "../jrd/constants.h"
#define MAX_USER_LENGTH 33
#define MAX_PASSWORD_LENGTH 33
2003-09-05 12:14:08 +02:00
DATABASE DB = FILENAME "yachts.lnk" RUNTIME database->dbb_filename;
2001-05-23 15:26:42 +02:00
extern enum lang_t sw_language;
extern bool sw_cstring;
2001-05-23 15:26:42 +02:00
extern DBB isc_databases;
2003-02-13 10:58:19 +01:00
static const UCHAR blr_bpb[] = { isc_bpb_version1,
2001-05-23 15:26:42 +02:00
isc_bpb_source_type, 1, BLOB_blr,
isc_bpb_target_type, 1, BLOB_blr
};
#ifdef SCROLLABLE_CURSORS
static SCHAR db_version_info[] = { gds__info_base_level };
#endif
static SLONG array_size(GPRE_FLD);
2003-10-07 11:58:26 +02:00
static void get_array(dbb*, const TEXT*, GPRE_FLD);
static bool get_intl_char_subtype(SSHORT*, const UCHAR*, USHORT, dbb*);
static bool resolve_charset_and_collation(SSHORT*, const UCHAR*, const UCHAR*);
static int symbol_length(const TEXT*);
#ifdef NOT_USED_OR_REPLACED
2003-10-07 11:58:26 +02:00
static int upcase(const TEXT*, TEXT*);
#endif
2001-05-23 15:26:42 +02:00
/*____________________________________________________________
*
* Lookup a field by name in a context.
* If found, return field block. If not, return NULL.
*/
2003-10-07 11:58:26 +02:00
GPRE_FLD MET_context_field( GPRE_CTX context, const char* string)
2001-05-23 15:26:42 +02:00
{
if (context->ctx_relation) {
2003-10-07 11:58:26 +02:00
return MET_field(context->ctx_relation, string);
2001-05-23 15:26:42 +02:00
}
if (!context->ctx_procedure) {
return NULL;
}
2003-10-07 11:58:26 +02:00
SCHAR name[NAME_SIZE];
2001-05-23 15:26:42 +02:00
strcpy(name, string);
2003-10-07 11:58:26 +02:00
GPRE_PRC procedure = context->ctx_procedure;
2001-05-23 15:26:42 +02:00
/* At this point the procedure should have been scanned, so all
* its fields are in the symbol table.
*/
2003-10-07 11:58:26 +02:00
GPRE_FLD field = NULL;
for (SYM symbol = HSH_lookup(name); symbol; symbol = symbol->sym_homonym) {
2001-05-23 15:26:42 +02:00
if (symbol->sym_type == SYM_field &&
(field = (GPRE_FLD) symbol->sym_object) &&
2001-05-23 15:26:42 +02:00
field->fld_procedure == procedure)
{
return field;
}
}
return field;
}
/*____________________________________________________________
*
* Initialize meta data access to database. If the
* database can't be opened, return false.
2001-05-23 15:26:42 +02:00
*/
bool MET_database(dbb* database, bool print_version)
2001-05-23 15:26:42 +02:00
{
2003-10-07 11:58:26 +02:00
static const UCHAR sql_version_info[] =
{
isc_info_base_level,
2001-05-23 15:26:42 +02:00
isc_info_ods_version,
isc_info_db_sql_dialect,
isc_info_end
};
/*
** Each info item requested will return
**
** 1 byte for the info item tag
** 2 bytes for the length of the information that follows
** 1 to 4 bytes of integer information
**
** isc_info_end will not have a 2-byte length - which gives us
** some padding in the buffer.
*/
UCHAR sql_buffer[sizeof(sql_version_info) * (1 + 2 + 4)];
#ifndef REQUESTER
if (sw_language == lang_internal) {
2003-09-05 12:14:08 +02:00
JRDMET_init(database);
return true;
2001-05-23 15:26:42 +02:00
}
#endif
DB = NULL;
2003-09-05 12:14:08 +02:00
if (!database->dbb_filename) {
2001-05-23 15:26:42 +02:00
CPR_error("No database specified");
return false;
2001-05-23 15:26:42 +02:00
}
/* generate a dpb for the attach from the specified
* compiletime user name and password
*/
2003-10-07 11:58:26 +02:00
SCHAR dpb[MAX_PASSWORD_LENGTH + MAX_USER_LENGTH + 5];
SCHAR* d = dpb;
2003-09-05 12:14:08 +02:00
if (database->dbb_c_user || database->dbb_c_password) {
*d++ = gds_dpb_version1;
2003-10-07 11:58:26 +02:00
const SCHAR* p = database->dbb_c_user;
if (p) {
*d++ = gds_dpb_user_name;
2001-05-23 15:26:42 +02:00
*d++ = strlen(p);
while (*p)
*d++ = *p++;
}
2003-10-07 11:58:26 +02:00
p = database->dbb_c_password;
if (p) {
*d++ = gds_dpb_password;
2001-05-23 15:26:42 +02:00
*d++ = strlen(p);
while (*p)
*d++ = *p++;
}
}
if (gds__attach_database
2003-09-05 12:14:08 +02:00
(gds_status, 0, database->dbb_filename, &DB, d - &dpb[0], dpb)) {
/* We failed to attach, try in read only mode just in case
if (d == dpb)
*d++ = gds_dpb_version1;
*d++ = isc_dpb_set_db_readonly;
*d++ = 1;
*d++ = TRUE;
if (gds__attach_database
2003-09-05 12:14:08 +02:00
(gds_status, 0, database->dbb_filename, &DB, d - &dpb[0], dpb)) {
2003-08-30 04:12:44 +02:00
*/
2001-12-24 03:51:06 +01:00
gds__print_status(gds_status);
return false;
//}
2001-05-23 15:26:42 +02:00
}
2003-09-05 12:14:08 +02:00
database->dbb_handle = DB;
2001-05-23 15:26:42 +02:00
if (sw_version && print_version) {
2003-09-05 12:14:08 +02:00
ib_printf(" Version(s) for database \"%s\"\n", database->dbb_filename);
2001-05-23 15:26:42 +02:00
gds__version(&DB, NULL, NULL);
}
sw_ods_version = 0;
sw_server_version = 0;
if (isc_database_info(isc_status, &DB, sizeof(sql_version_info),
(char*) sql_version_info, sizeof(sql_buffer), (char*) sql_buffer)) {
2001-05-23 15:26:42 +02:00
gds__print_status(isc_status);
return false;
2001-05-23 15:26:42 +02:00
}
2003-10-07 11:58:26 +02:00
const UCHAR* ptr = sql_buffer;
2001-05-23 15:26:42 +02:00
while (*ptr != isc_info_end) {
2003-10-07 11:58:26 +02:00
const UCHAR item = *ptr++;
const USHORT length = isc_vax_integer((char*)ptr, sizeof(USHORT));
2001-05-23 15:26:42 +02:00
ptr += sizeof(USHORT);
2003-10-07 11:58:26 +02:00
2001-05-23 15:26:42 +02:00
switch (item) {
case isc_info_base_level:
sw_server_version = (USHORT) ptr[1];
break;
case isc_info_ods_version:
sw_ods_version = isc_vax_integer((char*)ptr, length);
2001-05-23 15:26:42 +02:00
break;
case isc_info_db_sql_dialect:
compiletime_db_dialect = isc_vax_integer((char*)ptr, length);
2001-05-23 15:26:42 +02:00
break;
2003-10-07 11:58:26 +02:00
2001-05-23 15:26:42 +02:00
case isc_info_error:
/* Error indicates that one of the option
was not understood by thr server. Make sure it was
isc_info_db_sql_dialect and assume
that the database dialect is SQL_DIALECT_V5
*/
if ((sw_server_version != 0) && (sw_ods_version != 0))
compiletime_db_dialect = SQL_DIALECT_V5;
else
ib_printf("Internal error: Unexpected isc_info_value %d\n",
item);
break;
2003-10-07 11:58:26 +02:00
2001-05-23 15:26:42 +02:00
default:
ib_printf("Internal error: Unexpected isc_info_value %d\n", item);
break;
}
ptr += length;
}
if (!dialect_specified)
sw_sql_dialect = compiletime_db_dialect;
if (sw_ods_version < 10) {
if (sw_sql_dialect != compiletime_db_dialect) {
char warn_mesg[100];
sprintf(warn_mesg,
"Pre 6.0 database. Cannot use dialect %d, Resetting to %d\n",
sw_sql_dialect, compiletime_db_dialect);
CPR_warn(warn_mesg);
}
sw_sql_dialect = compiletime_db_dialect;
}
else if (sw_sql_dialect != compiletime_db_dialect) {
char warn_mesg[100];
sprintf(warn_mesg,
"Client dialect set to %d. Compiletime database dialect is %d\n",
sw_sql_dialect, compiletime_db_dialect);
CPR_warn(warn_mesg);
}
#ifdef DEBUG
if (sw_version && print_version)
ib_printf("Gpre Start up values. \
\n\tServer Ver : %d\
\n\tCompile time db Ver : %d\
\n\tCompile time db Sql Dialect : %d\
2003-10-07 11:58:26 +02:00
\n\tClient Sql dialect set to : %d\n\n",
sw_server_version, sw_ods_version, compiletime_db_dialect, sw_sql_dialect);
2001-05-23 15:26:42 +02:00
#endif
#ifdef SCROLLABLE_CURSORS
2001-12-24 03:51:06 +01:00
SCHAR buffer[16];
2001-05-23 15:26:42 +02:00
/* get the base level of the engine */
2003-08-30 04:12:44 +02:00
if (gds__database_info(gds_status, &DB, sizeof(db_version_info),
2001-05-23 15:26:42 +02:00
db_version_info, sizeof(buffer), buffer)) {
2001-12-24 03:51:06 +01:00
gds__print_status(gds_status);
return false;
2001-05-23 15:26:42 +02:00
}
/* this seems like a lot of rigamarole to read one info item,
* but it provides for easy extensibility in case we need
* more info items later
*/
2003-10-07 11:58:26 +02:00
const SCHAR* data = buffer;
while (*data != gds__info_end) {
const SCHAR item = *data++;
const USHORT l = isc_vax_integer(data, sizeof(USHORT));
data += sizeof(USHORT);
2001-05-23 15:26:42 +02:00
2003-10-07 11:58:26 +02:00
switch (item) {
2001-05-23 15:26:42 +02:00
/* This flag indicates the version level of the engine
itself, so we can tell what capabilities the engine
code itself (as opposed to the on-disk structure).
Apparently the base level up to now indicated the major
version number, but for 4.1 the base level is being
incremented, so the base level indicates an engine version
as follows:
1 == v1.x
2 == v2.x
3 == v3.x
4 == v4.0 only
5 == v4.1
Note: this info item is so old it apparently uses an
archaic format, not a standard vax integer format.
*/
case gds__info_base_level:
2003-09-05 12:14:08 +02:00
database->dbb_base_level = (USHORT) data[1];
2001-05-23 15:26:42 +02:00
break;
default:
;
}
data += l;
}
#endif
return true;
2001-05-23 15:26:42 +02:00
}
/*____________________________________________________________
*
* Lookup a domain by name.
* Initialize the size of the field.
*/
2003-10-07 11:58:26 +02:00
bool MET_domain_lookup(GPRE_REQ request, GPRE_FLD field, const char* string)
2001-05-23 15:26:42 +02:00
{
SCHAR name[NAME_SIZE];
bool found = false;
2001-05-23 15:26:42 +02:00
strcpy(name, string);
/* Lookup domain. If we find it in the hash table, and it is not the
* field we a currently looking at, use it. Else look it up from the
* database.
*/
2003-10-07 11:58:26 +02:00
for (SYM symbol = HSH_lookup(name); symbol; symbol = symbol->sym_homonym)
{
GPRE_FLD d_field;
2001-05-23 15:26:42 +02:00
if ((symbol->sym_type == SYM_field) &&
2003-10-07 11:58:26 +02:00
((d_field = (GPRE_FLD) symbol->sym_object) && (d_field != field)))
{
2001-05-23 15:26:42 +02:00
field->fld_length = d_field->fld_length;
field->fld_scale = d_field->fld_scale;
field->fld_sub_type = d_field->fld_sub_type;
field->fld_dtype = d_field->fld_dtype;
field->fld_ttype = d_field->fld_ttype;
field->fld_charset_id = d_field->fld_charset_id;
field->fld_collate_id = d_field->fld_collate_id;
field->fld_char_length = d_field->fld_char_length;
return true;
2001-05-23 15:26:42 +02:00
}
2003-10-07 11:58:26 +02:00
}
2001-05-23 15:26:42 +02:00
if (!request)
return false;
2001-05-23 15:26:42 +02:00
2003-10-07 11:58:26 +02:00
dbb* database = request->req_database;
2003-09-05 12:14:08 +02:00
if (database->dbb_flags & DBB_sqlca)
return false;
2001-05-23 15:26:42 +02:00
2003-09-05 12:14:08 +02:00
DB = database->dbb_handle;
gds_trans = database->dbb_transaction;
2001-05-23 15:26:42 +02:00
2003-09-05 12:14:08 +02:00
if (!(database->dbb_flags & DBB_v3)) {
FOR(REQUEST_HANDLE database->dbb_domain_request)
F IN RDB$FIELDS WITH F.RDB$FIELD_NAME EQ name
2003-10-07 11:58:26 +02:00
found = true;
field->fld_length = F.RDB$FIELD_LENGTH;
field->fld_scale = F.RDB$FIELD_SCALE;
field->fld_sub_type = F.RDB$FIELD_SUB_TYPE;
field->fld_dtype = MET_get_dtype(F.RDB$FIELD_TYPE, F.RDB$FIELD_SUB_TYPE,
&field->fld_length);
switch (field->fld_dtype) {
case dtype_text:
case dtype_cstring:
field->fld_flags |= FLD_text;
break;
2001-05-23 15:26:42 +02:00
2003-10-07 11:58:26 +02:00
case dtype_blob:
field->fld_flags |= FLD_blob;
field->fld_seg_length = F.RDB$SEGMENT_LENGTH;
break;
}
2001-05-23 15:26:42 +02:00
2003-10-07 11:58:26 +02:00
if (field->fld_dtype <= dtype_any_text) {
if (!F.RDB$CHARACTER_LENGTH.NULL)
field->fld_char_length = F.RDB$CHARACTER_LENGTH;
if (!F.RDB$CHARACTER_SET_ID.NULL)
field->fld_charset_id = F.RDB$CHARACTER_SET_ID;
if (!F.RDB$COLLATION_ID.NULL)
field->fld_collate_id = F.RDB$COLLATION_ID;
}
2001-05-23 15:26:42 +02:00
2003-10-07 11:58:26 +02:00
field->fld_ttype = INTL_CS_COLL_TO_TTYPE(field->fld_charset_id,
field->fld_collate_id);
2001-05-23 15:26:42 +02:00
END_FOR;
}
else {
2003-09-05 12:14:08 +02:00
FOR(REQUEST_HANDLE database->dbb_domain_request)
F IN RDB$FIELDS WITH F.RDB$FIELD_NAME EQ name
2003-10-07 11:58:26 +02:00
found = true;
field->fld_length = F.RDB$FIELD_LENGTH;
field->fld_scale = F.RDB$FIELD_SCALE;
field->fld_sub_type = F.RDB$FIELD_SUB_TYPE;
field->fld_dtype = MET_get_dtype(F.RDB$FIELD_TYPE, F.RDB$FIELD_SUB_TYPE,
&field->fld_length);
switch (field->fld_dtype) {
case dtype_text:
case dtype_cstring:
field->fld_flags |= FLD_text;
break;
2001-05-23 15:26:42 +02:00
2003-10-07 11:58:26 +02:00
case dtype_blob:
field->fld_flags |= FLD_blob;
field->fld_seg_length = F.RDB$SEGMENT_LENGTH;
break;
}
2001-05-23 15:26:42 +02:00
2003-10-07 11:58:26 +02:00
field->fld_ttype = INTL_CS_COLL_TO_TTYPE(field->fld_charset_id,
field->fld_collate_id);
2001-05-23 15:26:42 +02:00
END_FOR;
}
return found;
}
/*____________________________________________________________
*
* Gets the default value for a domain of an existing table
*/
bool MET_get_domain_default(dbb* database,
const TEXT* domain_name,
TEXT* buffer,
USHORT buff_length)
2001-05-23 15:26:42 +02:00
{
SCHAR name[NAME_SIZE];
2003-04-16 12:18:51 +02:00
ISC_STATUS_ARRAY status_vect;
2001-05-23 15:26:42 +02:00
strcpy(name, domain_name);
2003-09-05 12:14:08 +02:00
if (database == NULL)
return false;
2001-05-23 15:26:42 +02:00
if ((database->dbb_handle == NULL) && !MET_database(database, false))
2001-05-23 15:26:42 +02:00
CPR_exit(FINI_ERROR);
2003-09-05 12:14:08 +02:00
assert(database->dbb_transaction == NULL);
2003-10-07 11:58:26 +02:00
FRBRD* gds_trans = NULL;
2001-05-23 15:26:42 +02:00
2003-10-07 11:58:26 +02:00
FRBRD* DB = database->dbb_handle; // Overrides global DB
2001-05-23 15:26:42 +02:00
START_TRANSACTION;
2003-10-07 11:58:26 +02:00
bool has_default = false;
2003-09-05 12:14:08 +02:00
FOR(REQUEST_HANDLE database->dbb_domain_request)
GPRE_FLD IN RDB$FIELDS WITH
2003-10-07 11:58:26 +02:00
GPRE_FLD.RDB$FIELD_NAME EQ name
if (!GPRE_FLD.RDB$DEFAULT_VALUE.NULL) {
ISC_QUAD* blob_id = &GPRE_FLD.RDB$DEFAULT_VALUE;
/* open the blob */
isc_blob_handle blob_handle = NULL;
ISC_STATUS stat = isc_open_blob2(status_vect, &DB, &gds_trans,
&blob_handle, blob_id, sizeof(blr_bpb),
const_cast<unsigned char*>(blr_bpb));
if (stat) {
gds__print_status(status_vect);
2001-05-23 15:26:42 +02:00
CPR_exit(FINI_ERROR);
2003-10-07 11:58:26 +02:00
}
/* fetch segments. Assume buffer is big enough. */
TEXT* ptr_in_buffer = buffer;
while (true) {
SSHORT length;
stat = isc_get_segment(status_vect, &blob_handle, (USHORT*) &length,
buff_length, ptr_in_buffer);
ptr_in_buffer = ptr_in_buffer + length;
buff_length = buff_length - length;
if (!stat)
continue;
else if (stat == gds_segstr_eof) {
/* null terminate the buffer */
*ptr_in_buffer = 0;
break;
}
else
CPR_exit(FINI_ERROR);
}
isc_close_blob(status_vect, &blob_handle);
2001-05-23 15:26:42 +02:00
2003-10-07 11:58:26 +02:00
/* the default string must be of the form:
blr_version4 blr_literal ..... blr_eoc OR
blr_version4 blr_null blr_eoc OR
blr_version4 blr_user_name blr_eoc */
assert(buffer[0] == blr_version4 || buffer[0] == blr_version5);
assert(buffer[1] == blr_literal ||
buffer[1] == blr_null || buffer[1] == blr_user_name);
2001-05-23 15:26:42 +02:00
2003-10-07 11:58:26 +02:00
has_default = true;
}
else { /* default not found */
2001-05-23 15:26:42 +02:00
2003-10-07 11:58:26 +02:00
if (sw_sql_dialect > SQL_DIALECT_V5)
buffer[0] = blr_version5;
else
buffer[0] = blr_version4;
buffer[1] = blr_eoc;
}
END_FOR
COMMIT;
return has_default;
2001-05-23 15:26:42 +02:00
}
/*____________________________________________________________
*
* 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.
*/
bool MET_get_column_default(GPRE_REL relation,
2003-10-07 11:58:26 +02:00
const TEXT* column_name,
TEXT* buffer,
USHORT buff_length)
2001-05-23 15:26:42 +02:00
{
SCHAR name[NAME_SIZE];
2003-04-16 12:18:51 +02:00
ISC_STATUS_ARRAY status_vect;
2001-05-23 15:26:42 +02:00
strcpy(name, column_name);
2003-10-07 11:58:26 +02:00
dbb* database = relation->rel_database;
if (database == NULL)
return false;
2001-05-23 15:26:42 +02:00
if ((database->dbb_handle == NULL) && !MET_database(database, false))
2001-05-23 15:26:42 +02:00
CPR_exit(FINI_ERROR);
2003-09-05 12:14:08 +02:00
assert(database->dbb_transaction == NULL);
2003-10-07 11:58:26 +02:00
FRBRD* gds_trans = NULL;
2001-05-23 15:26:42 +02:00
2003-10-07 11:58:26 +02:00
FRBRD* DB = database->dbb_handle; // Overrides global DB
2001-05-23 15:26:42 +02:00
START_TRANSACTION;
2003-10-07 11:58:26 +02:00
bool has_default = false;
2003-09-05 12:14:08 +02:00
FOR(REQUEST_HANDLE database->dbb_field_request)
2001-05-23 15:26:42 +02:00
RFR IN RDB$RELATION_FIELDS CROSS F IN RDB$FIELDS WITH
RFR.RDB$FIELD_SOURCE EQ F.RDB$FIELD_NAME AND
RFR.RDB$FIELD_NAME EQ name AND
RFR.RDB$RELATION_NAME EQ relation->rel_symbol->sym_string
2003-10-07 11:58:26 +02:00
ISC_QUAD* blob_id;
2001-05-23 15:26:42 +02:00
if (!RFR.RDB$DEFAULT_VALUE.NULL) {
2003-10-07 11:58:26 +02:00
blob_id = &RFR.RDB$DEFAULT_VALUE;
has_default = true;
}
else if (!F.RDB$DEFAULT_VALUE.NULL) {
blob_id = &F.RDB$DEFAULT_VALUE;
has_default = true;
2001-05-23 15:26:42 +02:00
}
2003-10-07 11:58:26 +02:00
if (has_default) {
/* open the blob */
isc_blob_handle blob_handle = NULL;
ISC_STATUS stat = isc_open_blob2(status_vect, &DB, &gds_trans,
&blob_handle, blob_id, sizeof(blr_bpb),
const_cast<unsigned char*>(blr_bpb));
if (stat) {
gds__print_status(status_vect);
2001-05-23 15:26:42 +02:00
CPR_exit(FINI_ERROR);
2003-10-07 11:58:26 +02:00
}
2001-05-23 15:26:42 +02:00
2003-10-07 11:58:26 +02:00
/* fetch segments. Assuming here that the buffer is big enough. */
TEXT* ptr_in_buffer = buffer;
while (true) {
SSHORT length;
stat = isc_get_segment(status_vect, &blob_handle,
(USHORT*)&length, buff_length, ptr_in_buffer);
ptr_in_buffer = ptr_in_buffer + length;
buff_length = buff_length - length;
if (!stat)
continue;
else if (stat == gds_segstr_eof) {
/* null terminate the buffer */
*ptr_in_buffer = 0;
break;
}
else
CPR_exit(FINI_ERROR);
}
isc_close_blob(status_vect, &blob_handle);
2001-05-23 15:26:42 +02:00
2003-10-07 11:58:26 +02:00
/* the default string must be of the form:
blr_version4 blr_literal ..... blr_eoc OR
blr_version4 blr_null blr_eoc OR
blr_version4 blr_user_name blr_eoc */
assert(buffer[0] == blr_version4 || buffer[0] == blr_version5);
assert(buffer[1] == blr_literal ||
buffer[1] == blr_null || buffer[1] == blr_user_name);
}
else {
if (sw_sql_dialect > SQL_DIALECT_V5)
buffer[0] = blr_version5;
else
buffer[0] = blr_version4;
buffer[1] = blr_eoc;
}
2001-05-23 15:26:42 +02:00
END_FOR;
COMMIT;
return has_default;
2001-05-23 15:26:42 +02:00
}
/*____________________________________________________________
*
* Lookup the fields for the primary key
* index on a relation, returning a list
* of the fields.
*/
2003-10-07 11:58:26 +02:00
LLS MET_get_primary_key(dbb* database, const TEXT* relation_name)
2001-05-23 15:26:42 +02:00
{
SCHAR name[NAME_SIZE];
strcpy(name, relation_name);
2003-09-05 12:14:08 +02:00
if (database == NULL)
2001-05-23 15:26:42 +02:00
return NULL;
if ((database->dbb_handle == NULL) && !MET_database(database, false))
2001-05-23 15:26:42 +02:00
CPR_exit(FINI_ERROR);
2003-09-05 12:14:08 +02:00
assert(database->dbb_transaction == NULL);
2003-10-07 11:58:26 +02:00
FRBRD* gds_trans = NULL;
2001-05-23 15:26:42 +02:00
2003-10-07 11:58:26 +02:00
FRBRD* DB = database->dbb_handle; // Overrides global DB
2001-05-23 15:26:42 +02:00
START_TRANSACTION;
2003-10-07 11:58:26 +02:00
LLS fields = NULL;
LLS* ptr_fields = &fields;
2001-05-23 15:26:42 +02:00
2003-09-05 12:14:08 +02:00
FOR(REQUEST_HANDLE database->dbb_primary_key_request)
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 name
AND Z.RDB$CONSTRAINT_TYPE EQ "PRIMARY KEY"
2001-05-23 15:26:42 +02:00
SORTED BY Y.RDB$FIELD_POSITION
2003-10-07 11:58:26 +02:00
STR field_name = (str*) MAKE_STRING(Y.RDB$FIELD_NAME);
// Strip off any trailing spaces from field name
// CVC: This code stops at the first space, even in the middle.
TEXT* tmp = (TEXT*) field_name;
while (*tmp && *tmp != ' ')
*tmp++;
*tmp = '\0';
PUSH((GPRE_NOD) field_name, ptr_fields);
ptr_fields = &(*ptr_fields)->lls_next;
END_FOR
COMMIT;
2001-05-23 15:26:42 +02:00
return fields;
}
/*____________________________________________________________
*
* Lookup a field by name in a relation.
* If found, return field block. If not, return NULL.
*/
2003-10-07 11:58:26 +02:00
GPRE_FLD MET_field(GPRE_REL relation, const char* string)
2001-05-23 15:26:42 +02:00
{
SCHAR name[NAME_SIZE];
strcpy(name, string);
2003-10-07 11:58:26 +02:00
const SSHORT length = strlen(name);
2001-05-23 15:26:42 +02:00
2003-10-07 11:58:26 +02:00
// Lookup field. If we find it, nifty. If not, look it up in the
// database.
2001-05-23 15:26:42 +02:00
2003-10-07 11:58:26 +02:00
GPRE_FLD field = NULL;
SYM symbol;
2001-05-23 15:26:42 +02:00
for (symbol = HSH_lookup(name); symbol; symbol = symbol->sym_homonym)
if (symbol->sym_type == SYM_keyword &&
2003-10-07 11:58:26 +02:00
symbol->sym_keyword == (int) KW_DBKEY)
{
return relation->rel_dbkey;
}
2001-05-23 15:26:42 +02:00
else if (symbol->sym_type == SYM_field &&
(field = (GPRE_FLD) symbol->sym_object) &&
2003-10-07 11:58:26 +02:00
field->fld_relation == relation)
{
return field;
}
2001-05-23 15:26:42 +02:00
if (sw_language == lang_internal)
return NULL;
2003-10-07 11:58:26 +02:00
dbb* database = relation->rel_database;
2001-05-23 15:26:42 +02:00
2003-09-05 12:14:08 +02:00
if (database->dbb_flags & DBB_sqlca)
2001-05-23 15:26:42 +02:00
return NULL;
2003-09-05 12:14:08 +02:00
DB = database->dbb_handle;
gds_trans = database->dbb_transaction;
2001-05-23 15:26:42 +02:00
2003-10-07 11:58:26 +02:00
field = NULL;
2003-09-05 12:14:08 +02:00
if (!(database->dbb_flags & DBB_v3)) {
FOR(REQUEST_HANDLE database->dbb_field_request)
2001-05-23 15:26:42 +02:00
RFR IN RDB$RELATION_FIELDS CROSS F IN RDB$FIELDS WITH
RFR.RDB$FIELD_SOURCE EQ F.RDB$FIELD_NAME AND
RFR.RDB$FIELD_NAME EQ name AND
RFR.RDB$RELATION_NAME EQ relation->rel_symbol->sym_string
field = (GPRE_FLD) ALLOC(FLD_LEN);
2003-10-07 11:58:26 +02:00
field->fld_relation = relation;
field->fld_next = relation->rel_fields;
relation->rel_fields = field;
field->fld_id = RFR.RDB$FIELD_ID;
field->fld_length = F.RDB$FIELD_LENGTH;
field->fld_scale = F.RDB$FIELD_SCALE;
field->fld_position = RFR.RDB$FIELD_POSITION;
field->fld_sub_type = F.RDB$FIELD_SUB_TYPE;
field->fld_dtype =
MET_get_dtype(F.RDB$FIELD_TYPE, F.RDB$FIELD_SUB_TYPE,
2001-05-23 15:26:42 +02:00
&field->fld_length);
2003-10-07 11:58:26 +02:00
switch (field->fld_dtype) {
case dtype_text:
case dtype_cstring:
field->fld_flags |= FLD_text;
break;
2001-05-23 15:26:42 +02:00
2003-10-07 11:58:26 +02:00
case dtype_blob:
field->fld_flags |= FLD_blob;
field->fld_seg_length = F.RDB$SEGMENT_LENGTH;
break;
}
2001-05-23 15:26:42 +02:00
2003-10-07 11:58:26 +02:00
if (F.RDB$DIMENSIONS && !(database->dbb_flags & DBB_no_arrays))
get_array(database, F.RDB$FIELD_NAME, field);
if ((field->fld_dtype <= dtype_any_text)
|| (field->fld_dtype == dtype_blob))
{
if (!F.RDB$CHARACTER_LENGTH.NULL)
field->fld_char_length = F.RDB$CHARACTER_LENGTH;
if (!F.RDB$CHARACTER_SET_ID.NULL)
field->fld_charset_id = F.RDB$CHARACTER_SET_ID;
if (!RFR.RDB$COLLATION_ID.NULL)
field->fld_collate_id = RFR.RDB$COLLATION_ID;
else if (!F.RDB$COLLATION_ID.NULL)
field->fld_collate_id = F.RDB$COLLATION_ID;
}
2001-05-23 15:26:42 +02:00
2003-10-07 11:58:26 +02:00
field->fld_ttype =
INTL_CS_COLL_TO_TTYPE(field->fld_charset_id,
field->fld_collate_id);
field->fld_symbol = symbol =
MSC_symbol(SYM_field, name, length, (GPRE_CTX) field);
HSH_insert(symbol);
field->fld_global = symbol =
MSC_symbol(SYM_field, RFR.RDB$FIELD_SOURCE,
symbol_length(RFR.RDB$FIELD_SOURCE), (GPRE_CTX) field);
2001-05-23 15:26:42 +02:00
END_FOR;
}
else {
2003-09-05 12:14:08 +02:00
FOR(REQUEST_HANDLE database->dbb_field_request)
2001-05-23 15:26:42 +02:00
RFR IN RDB$RELATION_FIELDS CROSS F IN RDB$FIELDS WITH
RFR.RDB$FIELD_SOURCE EQ F.RDB$FIELD_NAME AND
RFR.RDB$FIELD_NAME EQ name AND
RFR.RDB$RELATION_NAME EQ relation->rel_symbol->sym_string
field = (GPRE_FLD) ALLOC(FLD_LEN);
2003-10-07 11:58:26 +02:00
field->fld_relation = relation;
field->fld_next = relation->rel_fields;
relation->rel_fields = field;
field->fld_id = RFR.RDB$FIELD_ID;
field->fld_length = F.RDB$FIELD_LENGTH;
field->fld_scale = F.RDB$FIELD_SCALE;
field->fld_position = RFR.RDB$FIELD_POSITION;
field->fld_sub_type = F.RDB$FIELD_SUB_TYPE;
field->fld_dtype =
MET_get_dtype(F.RDB$FIELD_TYPE, F.RDB$FIELD_SUB_TYPE,
&field->fld_length);
switch (field->fld_dtype) {
case dtype_text:
case dtype_cstring:
field->fld_flags |= FLD_text;
break;
2001-05-23 15:26:42 +02:00
2003-10-07 11:58:26 +02:00
case dtype_blob:
field->fld_flags |= FLD_blob;
field->fld_seg_length = F.RDB$SEGMENT_LENGTH;
break;
}
2001-05-23 15:26:42 +02:00
2003-10-07 11:58:26 +02:00
if (!(database->dbb_flags & DBB_no_arrays))
get_array(database, F.RDB$FIELD_NAME, field);
2001-05-23 15:26:42 +02:00
2003-10-07 11:58:26 +02:00
field->fld_ttype =
INTL_CS_COLL_TO_TTYPE(field->fld_charset_id,
field->fld_collate_id);
field->fld_symbol = symbol =
MSC_symbol(SYM_field, name, length, (GPRE_CTX) field);
HSH_insert(symbol);
field->fld_global = symbol =
MSC_symbol(SYM_field, RFR.RDB$FIELD_SOURCE,
symbol_length(RFR.RDB$FIELD_SOURCE), (GPRE_CTX) field);
2001-05-23 15:26:42 +02:00
END_FOR;
}
return field;
}
/*____________________________________________________________
*
* Return a list of the fields in a relation
*/
GPRE_NOD MET_fields(GPRE_CTX context)
2001-05-23 15:26:42 +02:00
{
GPRE_FLD field;
2003-10-07 11:58:26 +02:00
GPRE_NOD field_node;
2001-05-23 15:26:42 +02:00
REF reference;
2003-10-07 11:58:26 +02:00
GPRE_PRC procedure = context->ctx_procedure;
if (procedure) {
GPRE_NOD node = MAKE_NODE(nod_list, procedure->prc_out_count);
//count = 0;
2001-05-23 15:26:42 +02:00
for (field = procedure->prc_outputs; field; field = field->fld_next) {
reference = (REF) ALLOC(REF_LEN);
reference->ref_field = field;
reference->ref_context = context;
2002-11-11 20:19:43 +01:00
field_node = MSC_unary(nod_field, (GPRE_NOD) reference);
2001-05-23 15:26:42 +02:00
node->nod_arg[field->fld_position] = field_node;
2003-10-07 11:58:26 +02:00
//count++;
2001-05-23 15:26:42 +02:00
}
return node;
}
2003-10-07 11:58:26 +02:00
GPRE_REL relation = context->ctx_relation;
2001-05-23 15:26:42 +02:00
if (relation->rel_meta) {
2003-10-07 11:58:26 +02:00
int count = 0;
for (field = relation->rel_fields; field; field = field->fld_next) {
++count;
}
GPRE_NOD anode = MAKE_NODE(nod_list, count);
//count = 0;
2001-05-23 15:26:42 +02:00
for (field = relation->rel_fields; field; field = field->fld_next) {
reference = (REF) ALLOC(REF_LEN);
reference->ref_field = field;
reference->ref_context = context;
2002-11-11 20:19:43 +01:00
field_node = MSC_unary(nod_field, (GPRE_NOD) reference);
2003-10-07 11:58:26 +02:00
anode->nod_arg[field->fld_position] = field_node;
//count++;
2001-05-23 15:26:42 +02:00
}
2003-10-07 11:58:26 +02:00
return anode;
2001-05-23 15:26:42 +02:00
}
if (sw_language == lang_internal)
return NULL;
2003-10-07 11:58:26 +02:00
dbb* database = relation->rel_database;
2003-09-05 12:14:08 +02:00
DB = database->dbb_handle;
gds_trans = database->dbb_transaction;
2001-05-23 15:26:42 +02:00
2003-10-07 11:58:26 +02:00
int count = 0;
LLS stack = NULL;
2003-09-05 12:14:08 +02:00
FOR(REQUEST_HANDLE database->dbb_flds_request)
RFR IN RDB$RELATION_FIELDS CROSS GPRE_FLD IN RDB$FIELDS WITH
RFR.RDB$FIELD_SOURCE EQ GPRE_FLD.RDB$FIELD_NAME AND
2001-05-23 15:26:42 +02:00
RFR.RDB$RELATION_NAME EQ relation->rel_symbol->sym_string
SORTED BY RFR.RDB$FIELD_POSITION
2003-10-07 11:58:26 +02:00
TEXT* p;
// This code stops at the first blank.
2001-05-23 15:26:42 +02:00
for (p = RFR.RDB$FIELD_NAME; *p && *p != ' '; p++);
2003-10-07 11:58:26 +02:00
*p = 0;
PUSH((GPRE_NOD) MET_field(relation, RFR.RDB$FIELD_NAME), &stack);
count++;
2001-05-23 15:26:42 +02:00
END_FOR;
2003-10-07 11:58:26 +02:00
GPRE_NOD node = MAKE_NODE(nod_list, count);
2001-05-23 15:26:42 +02:00
while (stack) {
field = (GPRE_FLD) POP(&stack);
2001-05-23 15:26:42 +02:00
reference = (REF) ALLOC(REF_LEN);
reference->ref_field = field;
reference->ref_context = context;
2002-11-11 20:19:43 +01:00
field_node = MSC_unary(nod_field, (GPRE_NOD) reference);
2001-05-23 15:26:42 +02:00
node->nod_arg[--count] = field_node;
}
return node;
}
/*____________________________________________________________
*
* Shutdown all attached databases.
*/
2003-09-05 12:14:08 +02:00
void MET_fini(dbb* end)
2001-05-23 15:26:42 +02:00
{
2003-10-07 11:58:26 +02:00
for (dbb* database = isc_databases;
2003-09-05 12:14:08 +02:00
database && database != end;
database = database->dbb_next)
{
if (DB = database->dbb_handle) {
if (gds_trans = database->dbb_transaction)
2001-05-23 15:26:42 +02:00
COMMIT;
FINISH;
2003-09-05 12:14:08 +02:00
database->dbb_handle = NULL;
database->dbb_transaction = NULL;
database->dbb_field_request = NULL;
database->dbb_flds_request = NULL;
database->dbb_relation_request = NULL;
database->dbb_procedure_request = NULL;
database->dbb_udf_request = NULL;
database->dbb_trigger_request = NULL;
database->dbb_proc_prms_request = NULL;
database->dbb_proc_prm_fld_request = NULL;
database->dbb_index_request = NULL;
database->dbb_type_request = NULL;
database->dbb_array_request = NULL;
database->dbb_dimension_request = NULL;
database->dbb_domain_request = NULL;
database->dbb_generator_request = NULL;
database->dbb_view_request = NULL;
database->dbb_primary_key_request = NULL;
2001-05-23 15:26:42 +02:00
}
2003-09-05 12:14:08 +02:00
}
2001-05-23 15:26:42 +02:00
}
/*____________________________________________________________
*
* Lookup a generator by name.
* If found, return string. If not, return NULL.
*/
const SCHAR* MET_generator(const TEXT* string, dbb* database)
2001-05-23 15:26:42 +02:00
{
SCHAR name[NAME_SIZE];
strcpy(name, string);
for (SYM symbol = HSH_lookup(name); symbol; symbol = symbol->sym_homonym)
2001-05-23 15:26:42 +02:00
if ((symbol->sym_type == SYM_generator) &&
(database == (dbb*) (symbol->sym_object)))
{
return symbol->sym_string;
}
2001-05-23 15:26:42 +02:00
return NULL;
}
/*____________________________________________________________
*
* Compute internal datatype and length based on system relation field values.
*/
2003-10-07 11:58:26 +02:00
USHORT MET_get_dtype(USHORT blr_dtype, USHORT sub_type, USHORT* length)
2001-05-23 15:26:42 +02:00
{
2003-10-07 11:58:26 +02:00
USHORT dtype;
2001-05-23 15:26:42 +02:00
2003-10-07 11:58:26 +02:00
USHORT l = *length;
2001-05-23 15:26:42 +02:00
switch (blr_dtype) {
case blr_varying:
case blr_text:
dtype = dtype_text;
if (sw_cstring && !SUBTYPE_ALLOWS_NULLS(sub_type)) {
++l;
dtype = dtype_cstring;
}
break;
case blr_cstring:
dtype = dtype_cstring;
++l;
break;
case blr_short:
dtype = dtype_short;
l = sizeof(SSHORT);
break;
case blr_long:
dtype = dtype_long;
l = sizeof(SLONG);
break;
case blr_quad:
dtype = dtype_quad;
l = sizeof(GDS__QUAD);
break;
case blr_float:
dtype = dtype_real;
l = sizeof(float);
break;
case blr_double:
dtype = dtype_double;
l = sizeof(double);
break;
case blr_blob:
dtype = dtype_blob;
l = sizeof(GDS__QUAD);
break;
/** Begin sql date/time/timestamp **/
case blr_sql_date:
dtype = dtype_sql_date;
l = sizeof(ISC_DATE);
break;
case blr_sql_time:
dtype = dtype_sql_time;
l = sizeof(ISC_TIME);
break;
case blr_timestamp:
dtype = dtype_timestamp;
l = sizeof(ISC_TIMESTAMP);
break;
/** Begin sql date/time/timestamp **/
case blr_int64:
dtype = dtype_int64;
l = sizeof(ISC_INT64);
break;
default:
CPR_error("datatype not supported");
}
*length = l;
return dtype;
}
/*____________________________________________________________
*
* Lookup a procedure (represented by a token) in a database.
* Return a procedure block (if name is found) or NULL.
*
* This function has been cloned into MET_get_udf
*/
2003-10-07 11:58:26 +02:00
GPRE_PRC MET_get_procedure(dbb* database, const TEXT* string, const TEXT* owner_name)
2001-05-23 15:26:42 +02:00
{
SCHAR name[NAME_SIZE], owner[NAME_SIZE];
strcpy(name, string);
strcpy(owner, owner_name);
2003-10-07 11:58:26 +02:00
GPRE_PRC procedure = NULL;
2001-05-23 15:26:42 +02:00
2003-10-07 11:58:26 +02:00
for (SYM symbol = HSH_lookup(name); symbol; symbol = symbol->sym_homonym)
2001-05-23 15:26:42 +02:00
if (symbol->sym_type == SYM_procedure &&
(procedure = (GPRE_PRC) symbol->sym_object) &&
2003-09-05 12:14:08 +02:00
procedure->prc_database == database &&
2001-05-23 15:26:42 +02:00
(!owner[0] ||
(procedure->prc_owner
2003-10-07 11:58:26 +02:00
&& !strcmp(owner, procedure->prc_owner->sym_string))))
{
break;
}
2001-05-23 15:26:42 +02:00
if (!procedure)
return NULL;
if (procedure->prc_flags & PRC_scanned)
return procedure;
2003-09-05 12:14:08 +02:00
FOR(REQUEST_HANDLE database->dbb_procedure_request)
2001-05-23 15:26:42 +02:00
X IN RDB$PROCEDURES WITH X.RDB$PROCEDURE_ID = procedure->prc_id;
2003-10-07 11:58:26 +02:00
for (USHORT type = 0; type < 2; type++) {
USHORT count = 0;
GPRE_FLD* fld_list;
2001-05-23 15:26:42 +02:00
if (type)
fld_list = &procedure->prc_outputs;
else
fld_list = &procedure->prc_inputs;
2003-09-05 12:14:08 +02:00
FOR(REQUEST_HANDLE database->dbb_proc_prms_request)
2001-05-23 15:26:42 +02:00
Y IN RDB$PROCEDURE_PARAMETERS WITH
Y.RDB$PROCEDURE_NAME EQ name AND
Y.RDB$PARAMETER_TYPE EQ type
2003-10-07 11:58:26 +02:00
SORTED BY DESCENDING Y.RDB$PARAMETER_NUMBER
count++;
2001-05-23 15:26:42 +02:00
2003-10-07 11:58:26 +02:00
FOR(REQUEST_HANDLE database->dbb_proc_prm_fld_request)
F IN RDB$FIELDS WITH
Y.RDB$FIELD_SOURCE EQ F.RDB$FIELD_NAME
gpre_fld* field = (GPRE_FLD) ALLOC(FLD_LEN);
field->fld_procedure = procedure;
field->fld_next = *fld_list;
*fld_list = field;
field->fld_position = Y.RDB$PARAMETER_NUMBER;
field->fld_length = F.RDB$FIELD_LENGTH;
field->fld_scale = F.RDB$FIELD_SCALE;
field->fld_sub_type = F.RDB$FIELD_SUB_TYPE;
field->fld_dtype = MET_get_dtype(F.RDB$FIELD_TYPE,
F.RDB$FIELD_SUB_TYPE,
&field->fld_length);
switch (field->fld_dtype) {
case dtype_text:
case dtype_cstring:
field->fld_flags |= FLD_text;
if (!F.RDB$CHARACTER_LENGTH.NULL)
field->fld_char_length = F.RDB$CHARACTER_LENGTH;
if (!F.RDB$CHARACTER_SET_ID.NULL)
field->fld_charset_id = F.RDB$CHARACTER_SET_ID;
if (!F.RDB$COLLATION_ID.NULL)
field->fld_collate_id = F.RDB$COLLATION_ID;
field->fld_ttype =
INTL_CS_COLL_TO_TTYPE(field->fld_charset_id,
field->fld_collate_id);
break;
case dtype_blob:
field->fld_flags |= FLD_blob;
field->fld_seg_length = F.RDB$SEGMENT_LENGTH;
if (!F.RDB$CHARACTER_SET_ID.NULL)
field->fld_charset_id = F.RDB$CHARACTER_SET_ID;
break;
}
field->fld_symbol = MSC_symbol(SYM_field,
Y.RDB$PARAMETER_NAME,
symbol_length(Y.RDB$PARAMETER_NAME),
(GPRE_CTX) field);
/* If output parameter, insert in symbol table as a
field. */
if (type)
HSH_insert(field->fld_symbol);
END_FOR;
2001-05-23 15:26:42 +02:00
END_FOR;
if (type)
procedure->prc_out_count = count;
else
procedure->prc_in_count = count;
}
END_FOR;
procedure->prc_flags |= PRC_scanned;
/* Generate a dummy relation to point to the procedure to use when procedure
* is used as a view.
*/
return procedure;
}
/*____________________________________________________________
*
* Lookup a relation (represented by a token) in a database.
* Return a relation block (if name is found) or NULL.
*/
2003-10-07 11:58:26 +02:00
GPRE_REL MET_get_relation(dbb* database, const TEXT* string, const TEXT* owner_name)
2001-05-23 15:26:42 +02:00
{
GPRE_REL relation;
2001-05-23 15:26:42 +02:00
SCHAR name[NAME_SIZE], owner[NAME_SIZE];
strcpy(name, string);
strcpy(owner, owner_name);
2003-10-07 11:58:26 +02:00
for (SYM symbol = HSH_lookup(name); symbol; symbol = symbol->sym_homonym)
2001-05-23 15:26:42 +02:00
if (symbol->sym_type == SYM_relation &&
(relation = (GPRE_REL) symbol->sym_object) &&
2003-09-05 12:14:08 +02:00
relation->rel_database == database &&
2001-05-23 15:26:42 +02:00
(!owner[0] ||
(relation->rel_owner
2003-10-07 11:58:26 +02:00
&& !strcmp(owner, relation->rel_owner->sym_string))))
{
return relation;
}
2001-05-23 15:26:42 +02:00
return NULL;
}
/*____________________________________________________________
*
*/
INTLSYM MET_get_text_subtype(SSHORT ttype)
{
2003-10-07 11:58:26 +02:00
for (INTLSYM p = text_subtypes; p; p = p->intlsym_next)
2001-05-23 15:26:42 +02:00
if (p->intlsym_ttype == ttype)
return p;
return NULL;
}
/*____________________________________________________________
*
* Lookup a udf (represented by a token) in a database.
* Return a udf block (if name is found) or NULL.
*
* This function was cloned from MET_get_procedure
*/
2003-10-07 11:58:26 +02:00
UDF MET_get_udf(dbb* database, const TEXT* string)
2001-05-23 15:26:42 +02:00
{
SCHAR name[NAME_SIZE];
strcpy(name, string);
2003-10-07 11:58:26 +02:00
udf* the_udf = NULL;
for (SYM symbol = HSH_lookup(name); symbol; symbol = symbol->sym_homonym)
2001-05-23 15:26:42 +02:00
if (symbol->sym_type == SYM_udf &&
2003-09-05 12:14:08 +02:00
(the_udf = (udf*) symbol->sym_object) && the_udf->udf_database == database)
2001-05-23 15:26:42 +02:00
break;
2003-09-05 12:14:08 +02:00
if (!the_udf)
2001-05-23 15:26:42 +02:00
return NULL;
2003-09-05 12:14:08 +02:00
if (the_udf->udf_flags & UDF_scanned)
return the_udf;
2001-05-23 15:26:42 +02:00
2003-09-05 12:14:08 +02:00
if (database->dbb_flags & DBB_v3) {
2001-05-23 15:26:42 +02:00
/* Version of V4 request without new V4 metadata */
2003-09-05 12:14:08 +02:00
FOR(REQUEST_HANDLE database->dbb_udf_request)
2001-05-23 15:26:42 +02:00
UDF_DEF IN RDB$FUNCTIONS CROSS
UDF_ARG IN RDB$FUNCTION_ARGUMENTS
WITH UDF_DEF.RDB$FUNCTION_NAME EQ name AND
UDF_DEF.RDB$FUNCTION_NAME EQ UDF_ARG.RDB$FUNCTION_NAME AND
UDF_DEF.RDB$RETURN_ARGUMENT != UDF_ARG.RDB$ARGUMENT_POSITION
SORTED BY DESCENDING UDF_ARG.RDB$ARGUMENT_POSITION;
2003-10-07 11:58:26 +02:00
gpre_fld* field = (GPRE_FLD) ALLOC(FLD_LEN);
field->fld_next = the_udf->udf_inputs;
the_udf->udf_inputs = field;
the_udf->udf_args++;
field->fld_position = UDF_ARG.RDB$ARGUMENT_POSITION;
field->fld_length = UDF_ARG.RDB$FIELD_LENGTH;
field->fld_scale = UDF_ARG.RDB$FIELD_SCALE;
field->fld_sub_type = UDF_ARG.RDB$FIELD_SUB_TYPE;
field->fld_dtype = MET_get_dtype(UDF_ARG.RDB$FIELD_TYPE,
UDF_ARG.RDB$FIELD_SUB_TYPE,
&field->fld_length);
switch (field->fld_dtype) {
case dtype_text:
case dtype_cstring:
field->fld_flags |= FLD_text;
break;
2001-05-23 15:26:42 +02:00
2003-10-07 11:58:26 +02:00
case dtype_blob:
field->fld_flags |= FLD_blob;
break;
}
2001-05-23 15:26:42 +02:00
END_FOR;
}
else {
/* Same request as above, but with V4 metadata also fetched */
2003-09-05 12:14:08 +02:00
FOR(REQUEST_HANDLE database->dbb_udf_request)
2001-05-23 15:26:42 +02:00
UDF_DEF IN RDB$FUNCTIONS CROSS
UDF_ARG IN RDB$FUNCTION_ARGUMENTS
WITH UDF_DEF.RDB$FUNCTION_NAME EQ name AND
UDF_DEF.RDB$FUNCTION_NAME EQ UDF_ARG.RDB$FUNCTION_NAME AND
UDF_DEF.RDB$RETURN_ARGUMENT != UDF_ARG.RDB$ARGUMENT_POSITION
SORTED BY DESCENDING UDF_ARG.RDB$ARGUMENT_POSITION;
2003-10-07 11:58:26 +02:00
gpre_fld* field = (GPRE_FLD) ALLOC(FLD_LEN);
field->fld_next = the_udf->udf_inputs;
the_udf->udf_inputs = field;
the_udf->udf_args++;
field->fld_position = UDF_ARG.RDB$ARGUMENT_POSITION;
field->fld_length = UDF_ARG.RDB$FIELD_LENGTH;
field->fld_scale = UDF_ARG.RDB$FIELD_SCALE;
field->fld_sub_type = UDF_ARG.RDB$FIELD_SUB_TYPE;
field->fld_dtype = MET_get_dtype(UDF_ARG.RDB$FIELD_TYPE,
UDF_ARG.RDB$FIELD_SUB_TYPE,
&field->fld_length);
switch (field->fld_dtype) {
case dtype_text:
case dtype_cstring:
field->fld_flags |= FLD_text;
if (!UDF_ARG.RDB$CHARACTER_SET_ID.NULL)
field->fld_charset_id = UDF_ARG.RDB$CHARACTER_SET_ID;
field->fld_ttype =
INTL_CS_COLL_TO_TTYPE(field->fld_charset_id,
field->fld_collate_id);
break;
2001-05-23 15:26:42 +02:00
2003-10-07 11:58:26 +02:00
case dtype_blob:
field->fld_flags |= FLD_blob;
if (!UDF_ARG.RDB$CHARACTER_SET_ID.NULL)
field->fld_charset_id = UDF_ARG.RDB$CHARACTER_SET_ID;
break;
}
2001-05-23 15:26:42 +02:00
END_FOR;
}
2003-09-05 12:14:08 +02:00
the_udf->udf_flags |= UDF_scanned;
2001-05-23 15:26:42 +02:00
2003-09-05 12:14:08 +02:00
return the_udf;
2001-05-23 15:26:42 +02:00
}
/*____________________________________________________________
*
* Return relation if the passed view_name represents a
2001-05-23 15:26:42 +02:00
* view with the passed relation as a base table
* (the relation could be an alias).
*/
GPRE_REL MET_get_view_relation(GPRE_REQ request,
const char* view_name,
const char* relation_or_alias,
USHORT level)
2001-05-23 15:26:42 +02:00
{
2003-10-07 11:58:26 +02:00
dbb* database = request->req_database;
2003-09-05 12:14:08 +02:00
DB = database->dbb_handle;
gds_trans = database->dbb_transaction;
2001-05-23 15:26:42 +02:00
2003-10-07 11:58:26 +02:00
GPRE_REL relation = NULL;
2001-05-23 15:26:42 +02:00
2003-09-05 12:14:08 +02:00
FOR(REQUEST_HANDLE database->dbb_view_request, LEVEL level)
2001-05-23 15:26:42 +02:00
X IN RDB$VIEW_RELATIONS WITH
X.RDB$VIEW_NAME EQ view_name
2003-10-07 11:58:26 +02:00
TEXT* p;
// This code stops at the first blank.
2001-05-23 15:26:42 +02:00
for (p = X.RDB$CONTEXT_NAME; *p && *p != ' '; p++);
*p = 0;
2001-05-23 15:26:42 +02:00
for (p = X.RDB$RELATION_NAME; *p && *p != ' '; p++);
*p = 0;
2001-05-23 15:26:42 +02:00
if (!strcmp(X.RDB$RELATION_NAME, relation_or_alias) ||
!strcmp(X.RDB$CONTEXT_NAME, relation_or_alias))
{
return MET_get_relation(database, X.RDB$RELATION_NAME, "");
}
2001-05-23 15:26:42 +02:00
if (relation = MET_get_view_relation(request, X.RDB$RELATION_NAME,
relation_or_alias, level + 1))
{
return relation;
}
2001-05-23 15:26:42 +02:00
END_FOR;
return NULL;
}
/*____________________________________________________________
*
* Lookup an index for a database.
* Return an index block (if name is found) or NULL.
*/
2003-10-07 11:58:26 +02:00
IND MET_index(dbb* database, const TEXT* string)
2001-05-23 15:26:42 +02:00
{
IND index;
SCHAR name[NAME_SIZE];
strcpy(name, string);
2003-10-07 11:58:26 +02:00
const USHORT length = strlen(name);
2001-05-23 15:26:42 +02:00
2003-10-07 11:58:26 +02:00
SYM symbol;
2001-05-23 15:26:42 +02:00
for (symbol = HSH_lookup(name); symbol; symbol = symbol->sym_homonym)
if (symbol->sym_type == SYM_index &&
(index = (IND) symbol->sym_object) &&
2003-09-05 12:14:08 +02:00
index->ind_relation->rel_database == database)
2001-05-23 15:26:42 +02:00
return index;
if (sw_language == lang_internal)
return NULL;
2003-09-05 12:14:08 +02:00
if (database->dbb_flags & DBB_sqlca)
2001-05-23 15:26:42 +02:00
return NULL;
2003-09-05 12:14:08 +02:00
DB = database->dbb_handle;
gds_trans = database->dbb_transaction;
2001-05-23 15:26:42 +02:00
index = NULL;
2003-09-05 12:14:08 +02:00
FOR(REQUEST_HANDLE database->dbb_index_request)
2001-05-23 15:26:42 +02:00
X IN RDB$INDICES WITH X.RDB$INDEX_NAME EQ name
index = (IND) ALLOC(IND_LEN);
2003-10-07 11:58:26 +02:00
index->ind_symbol = symbol = MSC_symbol(SYM_index, name, length, (GPRE_CTX) index);
index->ind_relation = MET_get_relation(database, X.RDB$RELATION_NAME, "");
HSH_insert(symbol);
2001-05-23 15:26:42 +02:00
END_FOR;
return index;
}
/*____________________________________________________________
*
2003-10-07 11:58:26 +02:00
* Load all of the relation names, procedure names
2001-05-23 15:26:42 +02:00
* and user defined function names
* into the symbol (hash) table.
2003-10-07 11:58:26 +02:00
* Includes also charsets and collations.
2001-05-23 15:26:42 +02:00
*/
2003-09-05 12:14:08 +02:00
void MET_load_hash_table(dbb* database)
2001-05-23 15:26:42 +02:00
{
/* If this is an internal ISC access method invocation, don't do any of this
* stuff
*/
if (sw_language == lang_internal)
return;
2003-09-05 12:14:08 +02:00
if (!database->dbb_handle)
if (!MET_database(database, false))
2001-05-23 15:26:42 +02:00
CPR_exit(FINI_ERROR);
2003-09-05 12:14:08 +02:00
if (database->dbb_transaction)
2001-05-23 15:26:42 +02:00
/* we must have already loaded this one */
return;
2001-12-24 03:51:06 +01:00
gds_trans = NULL;
2003-09-05 12:14:08 +02:00
DB = database->dbb_handle;
2001-05-23 15:26:42 +02:00
START_TRANSACTION;
2003-09-05 12:14:08 +02:00
database->dbb_transaction = gds_trans;
2001-05-23 15:26:42 +02:00
/* Determine if the database is V3. */
bool post_v3_flag = false;
2003-10-07 11:58:26 +02:00
FRBRD* handle = NULL;
2001-05-23 15:26:42 +02:00
FOR(REQUEST_HANDLE handle)
X IN RDB$RELATIONS WITH X.RDB$RELATION_NAME = 'RDB$PROCEDURES' AND
X.RDB$SYSTEM_FLAG = 1
post_v3_flag = true;
2001-05-23 15:26:42 +02:00
END_FOR;
2003-08-30 04:12:44 +02:00
gds__release_request(gds_status, &handle);
2001-05-23 15:26:42 +02:00
if (!post_v3_flag)
2003-09-05 12:14:08 +02:00
database->dbb_flags |= DBB_v3;
2001-05-23 15:26:42 +02:00
2003-10-07 11:58:26 +02:00
SYM symbol;
TEXT* p;
SLONG length;
2001-05-23 15:26:42 +02:00
/* Pick up all relations (necessary to parse parts of the GDML grammar) */
2003-09-05 12:14:08 +02:00
if (database->dbb_flags & DBB_v3) {
2001-05-23 15:26:42 +02:00
FOR(REQUEST_HANDLE handle)
2003-10-07 11:58:26 +02:00
X IN RDB$RELATIONS
gpre_rel* relation = (GPRE_REL) ALLOC(REL_LEN);
relation->rel_database = database;
relation->rel_next = database->dbb_relations;
database->dbb_relations = relation;
relation->rel_id = X.RDB$RELATION_ID;
relation->rel_symbol = symbol =
MSC_symbol(SYM_relation, X.RDB$RELATION_NAME,
symbol_length(X.RDB$RELATION_NAME), (GPRE_CTX) relation);
HSH_insert(symbol);
const USHORT dbk_len = (X.RDB$DBKEY_LENGTH) ? X.RDB$DBKEY_LENGTH : 8;
GPRE_FLD dbkey = MET_make_field("rdb$db_key", dtype_text,
dbk_len, false);
relation->rel_dbkey = dbkey;
dbkey->fld_flags |= FLD_dbkey | FLD_text | FLD_charset;
dbkey->fld_ttype = ttype_binary;
2001-05-23 15:26:42 +02:00
END_FOR;
}
else {
FOR(REQUEST_HANDLE handle)
2003-10-07 11:58:26 +02:00
X IN RDB$RELATIONS
gpre_rel* relation = (GPRE_REL) ALLOC(REL_LEN);
relation->rel_database = database;
relation->rel_next = database->dbb_relations;
database->dbb_relations = relation;
relation->rel_id = X.RDB$RELATION_ID;
relation->rel_symbol = symbol =
MSC_symbol(SYM_relation, X.RDB$RELATION_NAME,
symbol_length(X.RDB$RELATION_NAME), (GPRE_CTX) relation);
HSH_insert(symbol);
const USHORT dbk_len = (X.RDB$DBKEY_LENGTH) ? X.RDB$DBKEY_LENGTH : 8;
GPRE_FLD dbkey = MET_make_field("rdb$db_key", dtype_text,
dbk_len, false);
relation->rel_dbkey = dbkey;
dbkey->fld_flags |= FLD_dbkey | FLD_text | FLD_charset;
dbkey->fld_ttype = ttype_binary;
if (!X.RDB$OWNER_NAME.NULL
&& (length = symbol_length(X.RDB$OWNER_NAME)))
{
relation->rel_owner =
MSC_symbol(SYM_username, X.RDB$OWNER_NAME, length, NULL);
}
2001-05-23 15:26:42 +02:00
END_FOR;
}
2003-08-30 04:12:44 +02:00
gds__release_request(gds_status, &handle);
2001-05-23 15:26:42 +02:00
/* Pick up all procedures (necessary to parse parts of the GDML grammar) */
FOR(REQUEST_HANDLE handle)
2003-10-07 11:58:26 +02:00
X IN RDB$PROCEDURES
gpre_prc* procedure = (GPRE_PRC) ALLOC(REL_LEN);
procedure->prc_database = database;
procedure->prc_next = (GPRE_PRC) database->dbb_procedures;
database->dbb_procedures = (GPRE_REL) procedure;
procedure->prc_id = X.RDB$PROCEDURE_ID;
procedure->prc_symbol = symbol =
MSC_symbol(SYM_procedure, X.RDB$PROCEDURE_NAME,
symbol_length(X.RDB$PROCEDURE_NAME), (GPRE_CTX) procedure);
HSH_insert(symbol);
if (!X.RDB$OWNER_NAME.NULL && (length = symbol_length(X.RDB$OWNER_NAME)))
procedure->prc_owner =
MSC_symbol(SYM_username, X.RDB$OWNER_NAME, length, NULL);
END_FOR
ON_ERROR
2001-05-23 15:26:42 +02:00
/* assume pre V4 database, no procedures */
2003-10-07 11:58:26 +02:00
END_ERROR;
2001-05-23 15:26:42 +02:00
if (handle)
2003-08-30 04:12:44 +02:00
gds__release_request(gds_status, &handle);
2001-05-23 15:26:42 +02:00
/* Pickup any user defined functions. If the database does not support UDF's,
* this may fail
*/
2003-10-07 11:58:26 +02:00
FRBRD* handle2 = NULL;
2001-05-23 15:26:42 +02:00
FOR(REQUEST_HANDLE handle)
FUN IN RDB$FUNCTIONS CROSS ARG IN RDB$FUNCTION_ARGUMENTS WITH
FUN.RDB$FUNCTION_NAME EQ ARG.RDB$FUNCTION_NAME AND
FUN.RDB$RETURN_ARGUMENT EQ ARG.RDB$ARGUMENT_POSITION
p = FUN.RDB$FUNCTION_NAME;
2003-10-07 11:58:26 +02:00
length = symbol_length(p);
2001-05-23 15:26:42 +02:00
p[length] = 0;
2003-10-07 11:58:26 +02:00
udf* an_udf = (udf*) ALLOC(UDF_LEN + length);
strcpy(an_udf->udf_function, p);
an_udf->udf_database = database;
an_udf->udf_type = FUN.RDB$FUNCTION_TYPE;
2001-05-23 15:26:42 +02:00
2003-10-07 11:58:26 +02:00
if (length = symbol_length(FUN.RDB$QUERY_NAME)) {
p = FUN.RDB$QUERY_NAME;
p[length] = 0;
}
an_udf->udf_symbol = symbol = MSC_symbol(SYM_udf, p, strlen(p), (GPRE_CTX) an_udf);
HSH_insert(symbol);
2001-05-23 15:26:42 +02:00
2003-10-07 11:58:26 +02:00
an_udf->udf_length = ARG.RDB$FIELD_LENGTH;
an_udf->udf_scale = ARG.RDB$FIELD_SCALE;
an_udf->udf_sub_type = ARG.RDB$FIELD_SUB_TYPE;
an_udf->udf_dtype =
MET_get_dtype(ARG.RDB$FIELD_TYPE, ARG.RDB$FIELD_SUB_TYPE,
&an_udf->udf_length);
if (post_v3_flag) {
FOR(REQUEST_HANDLE handle2)
V4ARG IN RDB$FUNCTION_ARGUMENTS
CROSS CS IN RDB$CHARACTER_SETS
CROSS COLL IN RDB$COLLATIONS WITH
V4ARG.RDB$CHARACTER_SET_ID EQ CS.RDB$CHARACTER_SET_ID AND
COLL.RDB$COLLATION_NAME EQ CS.RDB$DEFAULT_COLLATE_NAME AND
V4ARG.RDB$CHARACTER_SET_ID NOT MISSING AND
V4ARG.RDB$FUNCTION_NAME EQ ARG.RDB$FUNCTION_NAME AND
V4ARG.RDB$ARGUMENT_POSITION EQ ARG.RDB$ARGUMENT_POSITION;
an_udf->udf_charset_id = V4ARG.RDB$CHARACTER_SET_ID;
an_udf->udf_ttype =
INTL_CS_COLL_TO_TTYPE(an_udf->udf_charset_id, COLL.RDB$COLLATION_ID);
END_FOR;
}
2001-05-23 15:26:42 +02:00
2003-10-07 11:58:26 +02:00
END_FOR
ON_ERROR
// Nothing
END_ERROR;
2001-05-23 15:26:42 +02:00
2003-08-30 04:12:44 +02:00
gds__release_request(gds_status, &handle);
2001-05-23 15:26:42 +02:00
if (handle2)
2003-08-30 04:12:44 +02:00
gds__release_request(gds_status, &handle2);
2001-05-23 15:26:42 +02:00
/* Pick up all Collation names, might have several collations
* for a given character set.
* There can also be several alias names for a character set.
*/
FOR(REQUEST_HANDLE handle)
CHARSET IN RDB$CHARACTER_SETS CROSS COLL IN RDB$COLLATIONS OVER
RDB$CHARACTER_SET_ID;
2003-10-07 11:58:26 +02:00
p = COLL.RDB$COLLATION_NAME;
length = symbol_length(p);
p[length] = 0;
INTLSYM iname = (INTLSYM) ALLOC(INTLSYM_LEN + length);
strcpy(iname->intlsym_name, p);
iname->intlsym_database = database;
iname->intlsym_symbol = symbol =
MSC_symbol(SYM_collate, p, strlen(p), (GPRE_CTX) iname);
HSH_insert(symbol);
iname->intlsym_type = INTLSYM_collation;
iname->intlsym_flags = 0;
iname->intlsym_charset_id = COLL.RDB$CHARACTER_SET_ID;
iname->intlsym_collate_id = COLL.RDB$COLLATION_ID;
iname->intlsym_ttype =
INTL_CS_COLL_TO_TTYPE(iname->intlsym_charset_id,
iname->intlsym_collate_id);
iname->intlsym_bytes_per_char =
(CHARSET.RDB$BYTES_PER_CHARACTER.NULL) ? 1 : (CHARSET.
RDB$BYTES_PER_CHARACTER);
iname->intlsym_next = text_subtypes;
text_subtypes = iname;
FOR(REQUEST_HANDLE handle2)
TYPE IN RDB$TYPES
WITH TYPE.RDB$FIELD_NAME = "RDB$COLLATION_NAME"
AND TYPE.RDB$TYPE = COLL.RDB$COLLATION_ID
AND TYPE.RDB$TYPE_NAME != COLL.RDB$COLLATION_NAME;
p = TYPE.RDB$TYPE_NAME;
length = symbol_length(p);
p[length] = 0;
symbol = MSC_symbol(SYM_collate, p, length, (GPRE_CTX) iname);
HSH_insert(symbol);
END_FOR
ON_ERROR
// Nothing
2001-05-23 15:26:42 +02:00
END_ERROR;
2003-10-07 11:58:26 +02:00
END_FOR
ON_ERROR
/* assume pre V4 database, no collations */
END_ERROR;
2003-08-30 04:12:44 +02:00
gds__release_request(gds_status, &handle);
2001-05-23 15:26:42 +02:00
if (handle2)
2003-08-30 04:12:44 +02:00
gds__release_request(gds_status, &handle2);
2001-05-23 15:26:42 +02:00
/* Now pick up all character set names - with the subtype set to
* the type of the default collation for the character set.
*/
FOR(REQUEST_HANDLE handle)
CHARSET IN RDB$CHARACTER_SETS CROSS COLL IN RDB$COLLATIONS
WITH CHARSET.RDB$DEFAULT_COLLATE_NAME EQ COLL.RDB$COLLATION_NAME;
2003-10-07 11:58:26 +02:00
p = CHARSET.RDB$CHARACTER_SET_NAME;
length = symbol_length(p);
p[length] = 0;
INTLSYM iname = (INTLSYM) ALLOC(INTLSYM_LEN + length);
strcpy(iname->intlsym_name, p);
iname->intlsym_database = database;
iname->intlsym_symbol = symbol =
MSC_symbol(SYM_charset, p, strlen(p), (GPRE_CTX) iname);
HSH_insert(symbol);
iname->intlsym_type = INTLSYM_collation;
iname->intlsym_flags = 0;
iname->intlsym_charset_id = COLL.RDB$CHARACTER_SET_ID;
iname->intlsym_collate_id = COLL.RDB$COLLATION_ID;
iname->intlsym_ttype =
INTL_CS_COLL_TO_TTYPE(iname->intlsym_charset_id,
iname->intlsym_collate_id);
iname->intlsym_bytes_per_char =
(CHARSET.RDB$BYTES_PER_CHARACTER.NULL) ? 1 : (CHARSET.
RDB$BYTES_PER_CHARACTER);
FOR(REQUEST_HANDLE handle2)
TYPE IN RDB$TYPES
WITH TYPE.RDB$FIELD_NAME = "RDB$CHARACTER_SET_NAME"
AND TYPE.RDB$TYPE = CHARSET.RDB$CHARACTER_SET_ID
AND TYPE.RDB$TYPE_NAME != CHARSET.RDB$CHARACTER_SET_NAME;
p = TYPE.RDB$TYPE_NAME;
length = symbol_length(p);
p[length] = 0;
symbol = MSC_symbol(SYM_charset, p, length, (GPRE_CTX) iname);
HSH_insert(symbol);
END_FOR
ON_ERROR
// Nothing
2001-05-23 15:26:42 +02:00
END_ERROR;
2003-10-07 11:58:26 +02:00
END_FOR
ON_ERROR
/* assume pre V4 database, no character sets */
END_ERROR;
2003-08-30 04:12:44 +02:00
gds__release_request(gds_status, &handle);
2001-05-23 15:26:42 +02:00
if (handle2)
2003-08-30 04:12:44 +02:00
gds__release_request(gds_status, &handle2);
2001-05-23 15:26:42 +02:00
/* Pick up name of database default character set for SQL */
FOR(REQUEST_HANDLE handle)
FIRST 1 DBB IN RDB$DATABASE
WITH DBB.RDB$CHARACTER_SET_NAME NOT MISSING
p = DBB.RDB$CHARACTER_SET_NAME;
2003-10-07 11:58:26 +02:00
length = symbol_length(p);
p[length] = 0;
database->dbb_def_charset = (TEXT*) ALLOC(length + 1);
strcpy(database->dbb_def_charset, p);
if (!MSC_find_symbol(HSH_lookup(database->dbb_def_charset), SYM_charset))
CPR_warn("Default character set for database is not known");
END_FOR
ON_ERROR
2001-05-23 15:26:42 +02:00
/* Assume V3 Db, no default charset */
2003-10-07 11:58:26 +02:00
END_ERROR;
2001-05-23 15:26:42 +02:00
2003-08-30 04:12:44 +02:00
gds__release_request(gds_status, &handle);
2001-05-23 15:26:42 +02:00
/* Pick up all generators for the database */
FOR(REQUEST_HANDLE handle)
X IN RDB$GENERATORS
symbol = MSC_symbol(SYM_generator, X.RDB$GENERATOR_NAME,
2003-09-05 12:14:08 +02:00
symbol_length(X.RDB$GENERATOR_NAME), (GPRE_CTX) database);
2003-10-07 11:58:26 +02:00
HSH_insert(symbol);
2001-05-23 15:26:42 +02:00
2003-10-07 11:58:26 +02:00
END_FOR
ON_ERROR
// Nothing
END_ERROR;
2001-05-23 15:26:42 +02:00
2003-08-30 04:12:44 +02:00
gds__release_request(gds_status, &handle);
2001-05-23 15:26:42 +02:00
/* now that we have attached to the database, resolve the character set
* request (if any) (and if we can)
*/
2003-09-05 12:14:08 +02:00
if (database->dbb_c_lc_ctype) {
2001-05-23 15:26:42 +02:00
if (get_intl_char_subtype
2003-09-05 12:14:08 +02:00
(&database->dbb_char_subtype, (UCHAR*) database->dbb_c_lc_ctype,
strlen(database->dbb_c_lc_ctype), database))
2003-10-07 11:58:26 +02:00
{
2003-09-05 12:14:08 +02:00
database->dbb_know_subtype = 1;
2003-10-07 11:58:26 +02:00
}
2001-05-23 15:26:42 +02:00
else {
TEXT buffer[200];
sprintf(buffer, "Cannot recognize character set '%s'",
2003-09-05 12:14:08 +02:00
database->dbb_c_lc_ctype);
2001-05-23 15:26:42 +02:00
PAR_error(buffer);
}
2003-09-05 12:14:08 +02:00
sw_know_interp = database->dbb_know_subtype;
sw_interp = database->dbb_char_subtype;
2001-05-23 15:26:42 +02:00
}
}
/*____________________________________________________________
*
* Make a field symbol.
*/
2003-10-07 11:58:26 +02:00
GPRE_FLD MET_make_field(const SCHAR* name,
SSHORT dtype,
SSHORT length,
bool insert_flag)
2001-05-23 15:26:42 +02:00
{
2003-10-07 11:58:26 +02:00
GPRE_FLD field = (GPRE_FLD) ALLOC(FLD_LEN);
2001-05-23 15:26:42 +02:00
field->fld_length = length;
field->fld_dtype = dtype;
2003-10-07 11:58:26 +02:00
SYM symbol = MSC_symbol(SYM_field, name, strlen(name), (GPRE_CTX) field);
field->fld_symbol = symbol;
2001-05-23 15:26:42 +02:00
if (insert_flag)
HSH_insert(symbol);
return field;
}
/*____________________________________________________________
*
* Make an index symbol.
*/
2003-10-07 11:58:26 +02:00
IND MET_make_index(const SCHAR* name)
2001-05-23 15:26:42 +02:00
{
2003-10-07 11:58:26 +02:00
IND index = (IND) ALLOC(IND_LEN);
index->ind_symbol = MSC_symbol(SYM_index, name, strlen(name), (GPRE_CTX) index);
2001-05-23 15:26:42 +02:00
return index;
}
/*____________________________________________________________
*
* Make an relation symbol.
*/
2003-10-07 11:58:26 +02:00
GPRE_REL MET_make_relation(const SCHAR* name)
2001-05-23 15:26:42 +02:00
{
2003-10-07 11:58:26 +02:00
GPRE_REL relation = (GPRE_REL) ALLOC(REL_LEN);
2001-05-23 15:26:42 +02:00
relation->rel_symbol =
MSC_symbol(SYM_relation, name, strlen(name), (GPRE_CTX) relation);
2001-05-23 15:26:42 +02:00
return relation;
}
/*____________________________________________________________
*
* Lookup a type name for a field.
*/
bool MET_type(GPRE_FLD field,
2003-10-07 11:58:26 +02:00
const TEXT* string,
SSHORT* ptr)
2001-05-23 15:26:42 +02:00
{
TYP type;
UCHAR buffer[32]; /* BASED ON RDB$TYPES.RDB$TYPE_NAME */
2003-10-07 11:58:26 +02:00
SYM symbol;
2001-05-23 15:26:42 +02:00
for (symbol = HSH_lookup(string); symbol; symbol = symbol->sym_homonym)
if (symbol->sym_type == SYM_type &&
(type = (TYP) symbol->sym_object) &&
(!type->typ_field || type->typ_field == field))
{
2001-05-23 15:26:42 +02:00
*ptr = type->typ_value;
return true;
2001-05-23 15:26:42 +02:00
}
2003-10-07 11:58:26 +02:00
GPRE_REL relation = field->fld_relation;
dbb* database = relation->rel_database;
2003-09-05 12:14:08 +02:00
DB = database->dbb_handle;
gds_trans = database->dbb_transaction;
2001-05-23 15:26:42 +02:00
/* Force the name to uppercase, using C locale rules for uppercasing */
2003-10-07 11:58:26 +02:00
UCHAR* p;
2001-05-23 15:26:42 +02:00
for (p = buffer; *string && p < &buffer[sizeof(buffer) - 1];
2003-10-07 11:58:26 +02:00
++p, ++string)
{
*p = UPPER7(*string);
}
2001-05-23 15:26:42 +02:00
*p = '\0';
2003-09-05 12:14:08 +02:00
FOR(REQUEST_HANDLE database->dbb_type_request)
2001-05-23 15:26:42 +02:00
X IN RDB$TYPES WITH X.RDB$FIELD_NAME EQ field->fld_global->sym_string AND
2003-10-07 11:58:26 +02:00
X.RDB$TYPE_NAME EQ buffer
2001-05-23 15:26:42 +02:00
type = (TYP) ALLOC(TYP_LEN);
type->typ_field = field;
*ptr = type->typ_value = X.RDB$TYPE;
type->typ_symbol = symbol =
MSC_symbol(SYM_type, string, strlen(string), (GPRE_CTX) type);
2001-05-23 15:26:42 +02:00
HSH_insert(symbol);
return true;
2003-10-07 11:58:26 +02:00
END_FOR
ON_ERROR
// Nothing
END_ERROR;
2001-05-23 15:26:42 +02:00
return false;
2001-05-23 15:26:42 +02:00
}
/*____________________________________________________________
*
* Lookup an index for a database.
*
* Return: true if the trigger exists
* false otherwise
2001-05-23 15:26:42 +02:00
*/
bool MET_trigger_exists(dbb* database,
2003-10-07 11:58:26 +02:00
const TEXT* trigger_name)
2001-05-23 15:26:42 +02:00
{
2001-12-24 03:51:06 +01:00
char name[NAME_SIZE];
2001-05-23 15:26:42 +02:00
strcpy(name, trigger_name);
2003-09-05 12:14:08 +02:00
DB = database->dbb_handle;
gds_trans = database->dbb_transaction;
2001-05-23 15:26:42 +02:00
2003-09-05 12:14:08 +02:00
FOR(REQUEST_HANDLE database->dbb_trigger_request)
TRIG IN RDB$TRIGGERS WITH TRIG.RDB$TRIGGER_NAME EQ name
return true;
2001-05-23 15:26:42 +02:00
END_FOR;
return false;
2001-05-23 15:26:42 +02:00
}
/*____________________________________________________________
*
* Compute and return the size of the array.
*/
static SLONG array_size( GPRE_FLD field)
2001-05-23 15:26:42 +02:00
{
2003-10-07 11:58:26 +02:00
ARY array_block = field->fld_array_info;
SLONG count = field->fld_array->fld_length;
for (DIM dimension = array_block->ary_dimension; dimension;
dimension = dimension->dim_next)
{
count =
2001-05-23 15:26:42 +02:00
count * (dimension->dim_upper - dimension->dim_lower + 1);
2003-10-07 11:58:26 +02:00
}
2001-05-23 15:26:42 +02:00
return count;
}
/*____________________________________________________________
*
* See if field is array.
*/
2003-10-07 11:58:26 +02:00
static void get_array(dbb* database, const TEXT* field_name, GPRE_FLD field)
2001-05-23 15:26:42 +02:00
{
2003-10-07 11:58:26 +02:00
ARY array_block = NULL;
USHORT field_dimensions = 0;
2001-05-23 15:26:42 +02:00
2003-09-05 12:14:08 +02:00
FOR(REQUEST_HANDLE database->dbb_array_request)
2003-10-07 11:58:26 +02:00
F IN RDB$FIELDS WITH F.RDB$FIELD_NAME EQ field_name
if (F.RDB$DIMENSIONS) {
GPRE_FLD sub_field = (GPRE_FLD) ALLOC(FLD_LEN);
*sub_field = *field;
// CVC: beware, the above line is far from deep copy;
// there are only 13 non-pointer members in gpre_fld.
// The 14 pointer members share target locations with "field".
field->fld_array = sub_field;
field->fld_dtype = dtype_blob;
field->fld_flags |= FLD_blob;
field->fld_length = 8;
// CVC: Someone allocated the the max size inside the ary structure,
// so the dynamic length is irrelevant to create the array_block.
field_dimensions = F.RDB$DIMENSIONS;
fb_assert(field_dimensions <= MAX_ARRAY_DIMENSIONS);
fb_assert(field_dimensions > 0); // Sometimes, sys tables screw
field->fld_array_info = array_block = (ary*) ALLOC(ARY_LEN);
//(ARY) ALLOC(ARY_LEN(F.RDB$DIMENSIONS));
array_block->ary_dtype = sub_field->fld_dtype;
}
END_FOR
ON_ERROR {
2003-09-05 12:14:08 +02:00
database->dbb_flags |= DBB_no_arrays;
2001-05-23 15:26:42 +02:00
return;
}
END_ERROR;
if (!array_block)
return;
2003-10-07 11:58:26 +02:00
DIM last_dimension_block = 0;
USHORT dimension_counter = 0;
2003-09-05 12:14:08 +02:00
FOR(REQUEST_HANDLE database->dbb_dimension_request)
2001-05-23 15:26:42 +02:00
D IN RDB$FIELD_DIMENSIONS WITH D.RDB$FIELD_NAME EQ field_name
SORTED BY ASCENDING D.RDB$DIMENSION
array_block->ary_rpt[D.RDB$DIMENSION].ary_lower = D.RDB$LOWER_BOUND;
2003-10-07 11:58:26 +02:00
array_block->ary_rpt[D.RDB$DIMENSION].ary_upper = D.RDB$UPPER_BOUND;
DIM dimension_block = (DIM) ALLOC(DIM_LEN);
dimension_block->dim_number = D.RDB$DIMENSION;
dimension_block->dim_lower = D.RDB$LOWER_BOUND;
dimension_block->dim_upper = D.RDB$UPPER_BOUND;
if (D.RDB$DIMENSION != 0) {
last_dimension_block->dim_next = dimension_block;
dimension_block->dim_previous = last_dimension_block;
}
else
array_block->ary_dimension = dimension_block;
last_dimension_block = dimension_block;
++dimension_counter;
2001-05-23 15:26:42 +02:00
END_FOR;
2003-10-07 11:58:26 +02:00
// Check for lack of sync between RDB$FIELDS & RDB$FIELD_DIMENSIONS,
// it happened in the past due to buggy DYN code.
fb_assert(last_dimension_block);
fb_assert(dimension_counter == field_dimensions);
2001-05-23 15:26:42 +02:00
array_block->ary_dimension_count = last_dimension_block->dim_number + 1;
array_block->ary_size = array_size(field);
}
/*____________________________________________________________
*
* Character types can be specified as either:
* b) A POSIX style locale name "<collation>.<characterset>"
* or
* c) A simple <characterset> name (using default collation)
* d) A simple <collation> name (use charset for collation)
*
* Given an ASCII7 string which could be any of the above, try to
* resolve the name in the order b, c, d.
* b) is only tried iff the name contains a period.
* (in which case c) and d) are not tried).
*
* Return:
2003-10-07 11:58:26 +02:00
* true if no errors (and *id is set).
* false if the name could not be resolved.
2001-05-23 15:26:42 +02:00
*/
2003-10-07 11:58:26 +02:00
static bool get_intl_char_subtype(
SSHORT* id,
const UCHAR* name, USHORT length, dbb* database)
2001-05-23 15:26:42 +02:00
{
UCHAR buffer[32]; /* BASED ON RDB$COLLATION_NAME */
assert(id != NULL);
assert(name != NULL);
2003-09-05 12:14:08 +02:00
assert(database != NULL);
2001-05-23 15:26:42 +02:00
2003-09-05 12:14:08 +02:00
DB = database->dbb_handle;
2001-05-23 15:26:42 +02:00
if (!DB)
2003-10-07 11:58:26 +02:00
return false;
2003-09-05 12:14:08 +02:00
gds_trans = database->dbb_transaction;
2001-05-23 15:26:42 +02:00
2003-10-07 11:58:26 +02:00
const UCHAR* const end_name = name + length;
2001-05-23 15:26:42 +02:00
/* Force key to uppercase, following C locale rules for uppercasing
* At the same time, search for the first period in the string (if any)
*/
2003-10-07 11:58:26 +02:00
UCHAR* period = NULL;
UCHAR* p;
for (p = buffer;
name < end_name && p < (buffer + sizeof(buffer) - 1);
p++, name++)
{
2001-05-23 15:26:42 +02:00
*p = UPPER7(*name);
if ((*p == '.') && !period)
period = p;
2003-10-07 11:58:26 +02:00
}
2001-05-23 15:26:42 +02:00
*p = 0;
/* Is there a period, separating collation name from character set? */
if (period) {
*period = 0;
2003-10-07 11:58:26 +02:00
return resolve_charset_and_collation(id, period + 1, buffer);
2001-05-23 15:26:42 +02:00
}
else {
/* Is it a character set name (implying charset default collation sequence) */
2003-10-07 11:58:26 +02:00
bool res = resolve_charset_and_collation(id, buffer, NULL);
2001-05-23 15:26:42 +02:00
if (!res) {
/* Is it a collation name (implying implementation-default character set) */
res = resolve_charset_and_collation(id, NULL, buffer);
}
2003-10-07 11:58:26 +02:00
return res;
2001-05-23 15:26:42 +02:00
}
}
/*____________________________________________________________
*
* Given ASCII7 name of charset & collation
* resolve the specification to a ttype (id) that implements
* it.
*
* Inputs:
* (charset)
* ASCII7z name of characterset.
* NULL (implying unspecified) means use the character set
* for defined for (collation).
*
* (collation)
* ASCII7z name of collation.
* NULL means use the default collation for (charset).
*
* Outputs:
* (*id)
* Set to subtype specified by this name.
*
* Return:
2003-10-07 11:58:26 +02:00
* true if no errors (and *id is set).
* false if either name not found.
2001-05-23 15:26:42 +02:00
* or if names found, but the collation isn't for the specified
* character set.
*/
2003-10-07 11:58:26 +02:00
static bool resolve_charset_and_collation(
SSHORT* id,
const UCHAR* charset,
const UCHAR* collation)
2001-05-23 15:26:42 +02:00
{
assert(id != NULL);
if (!DB)
2003-10-07 11:58:26 +02:00
return false;
2001-05-23 15:26:42 +02:00
2003-10-07 11:58:26 +02:00
bool found = false;
FRBRD* request = NULL;
2001-05-23 15:26:42 +02:00
if (collation == NULL) {
if (charset == NULL) {
FOR(REQUEST_HANDLE request)
FIRST 1 DBB IN RDB$DATABASE
WITH DBB.RDB$CHARACTER_SET_NAME NOT MISSING
AND DBB.RDB$CHARACTER_SET_NAME != " ";
2003-10-07 11:58:26 +02:00
charset = (UCHAR*) DBB.RDB$CHARACTER_SET_NAME;
2001-05-23 15:26:42 +02:00
2003-10-07 11:58:26 +02:00
END_FOR
ON_ERROR
2001-05-23 15:26:42 +02:00
/* Assume V3 DB, without default character set */
2003-10-07 11:58:26 +02:00
END_ERROR;
2001-05-23 15:26:42 +02:00
2003-08-30 04:12:44 +02:00
gds__release_request(gds_status, &request);
2001-05-23 15:26:42 +02:00
if (charset == NULL)
2003-10-07 11:58:26 +02:00
charset = (UCHAR*) DEFAULT_CHARACTER_SET_NAME;
2001-05-23 15:26:42 +02:00
}
FOR(REQUEST_HANDLE request)
FIRST 1 CS IN RDB$CHARACTER_SETS
CROSS COLL IN RDB$COLLATIONS
CROSS TYPE IN RDB$TYPES
WITH TYPE.RDB$TYPE_NAME EQ charset
AND TYPE.RDB$FIELD_NAME EQ "RDB$CHARACTER_SET_NAME"
AND TYPE.RDB$TYPE EQ CS.RDB$CHARACTER_SET_ID
AND CS.RDB$DEFAULT_COLLATE_NAME EQ COLL.RDB$COLLATION_NAME;
2003-10-07 11:58:26 +02:00
found = true;
*id = MAP_CHARSET_TO_TTYPE(CS.RDB$CHARACTER_SET_ID);
2001-05-23 15:26:42 +02:00
2003-10-07 11:58:26 +02:00
END_FOR
ON_ERROR
// Nothing
END_ERROR;
2001-05-23 15:26:42 +02:00
2003-08-30 04:12:44 +02:00
gds__release_request(gds_status, &request);
2001-05-23 15:26:42 +02:00
2003-10-07 11:58:26 +02:00
return found;
2001-05-23 15:26:42 +02:00
}
else if (charset == NULL) {
FOR(REQUEST_HANDLE request)
FIRST 1 CS IN RDB$CHARACTER_SETS
CROSS COLL IN RDB$COLLATIONS
OVER RDB$CHARACTER_SET_ID
WITH COLL.RDB$COLLATION_NAME EQ collation;
2003-10-07 11:58:26 +02:00
found = true;
*id = MAP_CHARSET_TO_TTYPE(CS.RDB$CHARACTER_SET_ID);
END_FOR
ON_ERROR
// Nothing
END_ERROR;
2001-05-23 15:26:42 +02:00
2003-08-30 04:12:44 +02:00
gds__release_request(gds_status, &request);
2001-05-23 15:26:42 +02:00
2003-10-07 11:58:26 +02:00
return found;
2001-05-23 15:26:42 +02:00
}
FOR(REQUEST_HANDLE request)
FIRST 1 CS IN RDB$CHARACTER_SETS
CROSS COL IN RDB$COLLATIONS OVER RDB$CHARACTER_SET_ID
CROSS NAME2 IN RDB$TYPES
WITH COL.RDB$COLLATION_NAME EQ collation
AND NAME2.RDB$TYPE_NAME EQ charset
AND NAME2.RDB$FIELD_NAME EQ "RDB$CHARACTER_SET_NAME"
AND NAME2.RDB$TYPE EQ CS.RDB$CHARACTER_SET_ID;
2003-10-07 11:58:26 +02:00
found = true;
*id = MAP_CHARSET_TO_TTYPE(CS.RDB$CHARACTER_SET_ID);
END_FOR
ON_ERROR
// Nothing
END_ERROR;
2001-05-23 15:26:42 +02:00
2003-08-30 04:12:44 +02:00
gds__release_request(gds_status, &request);
2001-05-23 15:26:42 +02:00
2003-10-07 11:58:26 +02:00
return found;
2001-05-23 15:26:42 +02:00
}
/*____________________________________________________________
*
* Compute significant length of symbol.
*/
2003-10-07 11:58:26 +02:00
static int symbol_length(const TEXT* string)
2001-05-23 15:26:42 +02:00
{
2003-10-07 11:58:26 +02:00
const int len = strlen(string);
2001-05-23 15:26:42 +02:00
2003-10-07 11:58:26 +02:00
const TEXT* p = string + (len - 1);
2001-05-23 15:26:42 +02:00
for (; p >= string && *p == ' '; p--);
if (p < string)
return 0;
++p;
return p - string;
}
#ifdef NOT_USED_OR_REPLACED
2001-05-23 15:26:42 +02:00
/*____________________________________________________________
*
* Upcase a string into another string. Return
* length of string.
*/
2003-10-07 11:58:26 +02:00
static int upcase(const TEXT* from, TEXT* to)
2001-05-23 15:26:42 +02:00
{
2003-10-07 11:58:26 +02:00
TEXT c;
2001-05-23 15:26:42 +02:00
2003-10-07 11:58:26 +02:00
TEXT* p = to;
const TEXT* const end = to + NAME_SIZE;
2001-05-23 15:26:42 +02:00
while (p < end && (c = *from++)) {
*p++ = UPPER(c);
}
*p = 0;
return p - to;
}
#endif
2003-10-07 11:58:26 +02:00