2001-05-23 15:26:42 +02:00
|
|
|
/*
|
|
|
|
* PROGRAM: Rdb/GDS Access Method Interface
|
|
|
|
* MODULE: rdbint.c
|
|
|
|
* DESCRIPTION: Rdb/VMS 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): ______________________________________.
|
|
|
|
*/
|
|
|
|
|
2001-07-29 19:42:23 +02:00
|
|
|
#include "firebird.h"
|
2001-05-23 15:26:42 +02:00
|
|
|
#include descrip
|
|
|
|
#include ssdef
|
|
|
|
|
|
|
|
#include "../jrd/lnmdef.h"
|
2001-07-29 19:42:23 +02:00
|
|
|
#include "../jrd/gds.h"
|
2001-05-23 15:26:42 +02:00
|
|
|
#include "../jrd/common.h"
|
|
|
|
|
|
|
|
#define RDB_IMAGE "RDBVMSSHR"
|
|
|
|
#define RDB_CALL(name) if (!name) find_symbol (&name,"name"); (*name)
|
|
|
|
#define CHECK_HANDLE(handle,code) if (check_handle(handle))\
|
|
|
|
return bad_handle (user_status, code)
|
|
|
|
|
|
|
|
#define rdb$bad_req_handle 20480058
|
|
|
|
|
|
|
|
typedef struct handle {
|
|
|
|
int *handle;
|
|
|
|
int *messages;
|
|
|
|
struct handle *parent;
|
|
|
|
struct handle *next;
|
|
|
|
} *HANDLE, *REQ, *DBB, *TRA, *BLB;
|
|
|
|
|
|
|
|
typedef struct teb {
|
|
|
|
DBB *teb_database;
|
|
|
|
int teb_tpb_length;
|
|
|
|
UCHAR *teb_tpb;
|
|
|
|
} TEB;
|
|
|
|
|
|
|
|
static USHORT debug_flags;
|
|
|
|
static UCHAR *temp_buffer;
|
|
|
|
static SLONG temp_buffer_length;
|
|
|
|
static struct handle empty_handle;
|
|
|
|
|
|
|
|
|
|
|
|
#define DEBUG_BLR 1
|
|
|
|
#define DEBUG_ERROR_BLR 2
|
|
|
|
|
|
|
|
static int (*RDB$ATTACH_DATABASE) (),
|
|
|
|
(*RDB$COMMIT_TRANSACTION) (),
|
|
|
|
(*RDB$COMPILE_REQUEST) (),
|
|
|
|
(*RDB$CREATE_DATABASE) (),
|
|
|
|
(*RDB$DETACH_DATABASE) (),
|
|
|
|
(*RDB$PREPARE_TRANSACTION) (),
|
|
|
|
(*RDB$RECEIVE) (),
|
|
|
|
(*RDB$RELEASE_REQUEST) (),
|
|
|
|
(*RDB$ROLLBACK_TRANSACTION) (),
|
|
|
|
(*RDB$SEND) (),
|
|
|
|
(*RDB$START_AND_SEND) (),
|
|
|
|
(*RDB$START_REQUEST) (),
|
|
|
|
(*RDB$START_TRANSACTION) (),
|
|
|
|
(*RDB$UNWIND_REQUEST) (),
|
|
|
|
(*RDB$CREATE_SEGMENTED_STRING) (),
|
|
|
|
(*RDB$OPEN_SEGMENTED_STRING) (),
|
|
|
|
(*RDB$CLOSE_SEGMENTED_STRING) (),
|
|
|
|
(*RDB$CANCEL_SEGMENTED_STRING) (),
|
|
|
|
(*RDB$GET_SEGMENT) (),
|
|
|
|
(*RDB$PUT_SEGMENT) (),
|
|
|
|
(*RDB$SEGMENTED_STRING_INFO) (),
|
|
|
|
(*RDB$REQUEST_INFO) (),
|
|
|
|
(*RDB$DATABASE_INFO) (),
|
|
|
|
(*RDB$TRANSACTION_INFO) (), (*RDB$RECONNECT_TRANSACTION) ();
|
|
|
|
|
|
|
|
static HANDLE allocate_handle(int *);
|
|
|
|
static UCHAR *allocate_temp(int);
|
|
|
|
static int bad_handle(int *, int);
|
|
|
|
static int check_handle(HANDLE *);
|
|
|
|
static int condition_handler(int *, int *, int *);
|
|
|
|
static int find_symbol(int *, UCHAR *);
|
|
|
|
static void init(void);
|
|
|
|
static void make_desc(UCHAR *, int, struct dsc$descriptor *);
|
|
|
|
|
|
|
|
|
|
|
|
int RDB_attach_database(
|
|
|
|
int *user_status,
|
|
|
|
SSHORT file_length,
|
|
|
|
SCHAR * file_name,
|
|
|
|
DBB * handle,
|
|
|
|
SSHORT dpb_length, SCHAR * dpb, SSHORT db_type)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* G D S _ A T T A C H _ D A T A B A S E
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Attempt to attach an RDB database. Since
|
|
|
|
* we and RDB share some dpb values and have
|
|
|
|
* the same values for different paramters in
|
|
|
|
* other cases. The results of misunderstandings
|
|
|
|
* are bad, so we strip off our extended parameters.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
STATUS stat, status_vector[20];
|
|
|
|
struct dsc$descriptor_s name;
|
|
|
|
SCHAR new_dpb[128], *p, *q;
|
|
|
|
SSHORT new_length, l, c_len;
|
|
|
|
|
|
|
|
init();
|
|
|
|
|
|
|
|
if (!RDB$ATTACH_DATABASE &&
|
|
|
|
!find_symbol(&RDB$ATTACH_DATABASE, "RDB$ATTACH_DATABASE")) {
|
|
|
|
user_status[0] = gds_arg_gds;
|
|
|
|
user_status[1] = gds_unavailable;
|
|
|
|
user_status[0] = 0;
|
|
|
|
return user_status[1];
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dpb_length > 1) {
|
|
|
|
p = new_dpb;
|
|
|
|
q = dpb;
|
|
|
|
*p++ = gds_dpb_version1;
|
|
|
|
q++;
|
|
|
|
for (l = dpb_length; l; l -= (q - dpb))
|
|
|
|
if (*q < gds_dpb_damaged) {
|
|
|
|
*p++ = *q++;
|
|
|
|
c_len = *p++ = *q++;
|
|
|
|
while (c_len--)
|
|
|
|
*p++ = *q++;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
*q++;
|
|
|
|
c_len = *q++;
|
|
|
|
while (c_len--)
|
|
|
|
*q++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((new_length = p - new_dpb) == 1)
|
|
|
|
new_length = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
new_length = 0;
|
|
|
|
|
|
|
|
make_desc(file_name, file_length, &name);
|
|
|
|
RDB_CALL(RDB$ATTACH_DATABASE) (status_vector, &name, handle, new_length,
|
|
|
|
new_dpb);
|
|
|
|
|
|
|
|
if (!(stat = MAP_status_to_gds(status_vector, user_status)))
|
|
|
|
*handle = allocate_handle(*handle);
|
|
|
|
|
|
|
|
return stat;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int RDB_blob_info(
|
|
|
|
int *user_status,
|
|
|
|
BLB * handle,
|
|
|
|
SSHORT item_length,
|
|
|
|
SCHAR * items, SSHORT buffer_length, SCHAR * buffer)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* g d s _ $ b l o b _ i n f o
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Get info on object.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
STATUS status_vector[20];
|
|
|
|
|
|
|
|
CHECK_HANDLE(handle, gds_bad_segstr_handle);
|
|
|
|
|
|
|
|
RDB_CALL(RDB$SEGMENTED_STRING_INFO) (status_vector, &(*handle)->handle,
|
|
|
|
item_length, items, buffer_length,
|
|
|
|
buffer);
|
|
|
|
|
|
|
|
return MAP_status_to_gds(status_vector, user_status);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int RDB_cancel_blob(int *user_status, BLB * blob_handle)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* R D B _ C A N C E L _ B L O B
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Cancel a blob (surprise!)
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
STATUS stat, status_vector[20];
|
|
|
|
|
|
|
|
if (!*blob_handle) {
|
|
|
|
if (user_status) {
|
|
|
|
*user_status++ = gds_arg_gds;
|
|
|
|
*user_status++ = 0;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
RDB_CALL(RDB$CANCEL_SEGMENTED_STRING) (status_vector,
|
|
|
|
&(*blob_handle)->handle);
|
|
|
|
|
|
|
|
if (!(stat = MAP_status_to_gds(status_vector, user_status))) {
|
|
|
|
gds__free(*blob_handle);
|
|
|
|
*blob_handle = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return stat;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int RDB_close_blob(int *user_status, BLB * blob_handle)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* R D B _ C L O S E _ B L O B
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Close a blob (surprise!)
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
STATUS stat, status_vector[20];
|
|
|
|
|
|
|
|
CHECK_HANDLE(blob_handle, gds_bad_segstr_handle);
|
|
|
|
|
|
|
|
RDB_CALL(RDB$CLOSE_SEGMENTED_STRING) (status_vector,
|
|
|
|
&(*blob_handle)->handle);
|
|
|
|
|
|
|
|
if (!(stat = MAP_status_to_gds(status_vector, user_status))) {
|
|
|
|
gds__free(*blob_handle);
|
|
|
|
*blob_handle = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return stat;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int RDB_commit_transaction(int *user_status, TRA * tra_handle)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* G D S _ C O M M I T
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Commit a transaction.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
STATUS stat, status_vector[20];
|
|
|
|
|
|
|
|
CHECK_HANDLE(tra_handle, gds_bad_trans_handle);
|
|
|
|
RDB_CALL(RDB$COMMIT_TRANSACTION) (status_vector, &(*tra_handle)->handle);
|
|
|
|
|
|
|
|
if (!(stat = MAP_status_to_gds(status_vector, user_status))) {
|
|
|
|
gds__free(*tra_handle);
|
|
|
|
*tra_handle = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return stat;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int RDB_compile_request(
|
|
|
|
int *user_status,
|
|
|
|
DBB * db_handle,
|
|
|
|
REQ * req_handle, SSHORT blr_length, SCHAR * blr)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* G D S _ C O M P I L E
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
STATUS stat, status_vector[20];
|
|
|
|
int *messages;
|
|
|
|
UCHAR *temp;
|
|
|
|
USHORT temp_length;
|
|
|
|
DBB database;
|
|
|
|
REQ request;
|
|
|
|
SLONG max_length;
|
|
|
|
|
|
|
|
CHECK_HANDLE(db_handle, gds_bad_db_handle);
|
|
|
|
messages = NULL;
|
|
|
|
database = *db_handle;
|
|
|
|
temp = allocate_temp(blr_length + 200);
|
|
|
|
|
|
|
|
if (messages =
|
|
|
|
MAP_parse_blr(blr, blr_length, temp, &temp_length, &max_length)) {
|
|
|
|
blr = temp;
|
|
|
|
blr_length = temp_length;
|
|
|
|
allocate_temp(max_length);
|
|
|
|
}
|
|
|
|
|
|
|
|
RDB_CALL(RDB$COMPILE_REQUEST) (status_vector, &database->handle,
|
|
|
|
req_handle, blr_length, blr);
|
|
|
|
|
|
|
|
if (stat = MAP_status_to_gds(status_vector, user_status))
|
|
|
|
MAP_release(messages);
|
|
|
|
else {
|
|
|
|
*req_handle = request = allocate_handle(*req_handle);
|
|
|
|
request->messages = messages;
|
|
|
|
request->parent = database;
|
|
|
|
request->next = database->next;
|
|
|
|
database->next = request;
|
|
|
|
}
|
|
|
|
|
|
|
|
return stat;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int RDB_create_blob(
|
|
|
|
int *user_status,
|
|
|
|
HANDLE * db_handle,
|
|
|
|
HANDLE * tra_handle,
|
|
|
|
HANDLE * blob_handle, GDS_QUAD * blob_id)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* R D B _ C R E A T E _ B L O B
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Get a segment from a blob (surprise!)
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
STATUS stat, status_vector[20];
|
|
|
|
|
|
|
|
CHECK_HANDLE(db_handle, gds_bad_db_handle);
|
|
|
|
CHECK_HANDLE(tra_handle, gds_bad_trans_handle);
|
|
|
|
|
|
|
|
RDB_CALL(RDB$CREATE_SEGMENTED_STRING) (status_vector,
|
|
|
|
&(*db_handle)->handle,
|
|
|
|
&(*tra_handle)->handle,
|
|
|
|
blob_handle, blob_id);
|
|
|
|
|
|
|
|
if (!(stat = MAP_status_to_gds(status_vector, user_status)))
|
|
|
|
*blob_handle = allocate_handle(*blob_handle);
|
|
|
|
|
|
|
|
return stat;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int RDB_create_database(
|
|
|
|
int *user_status,
|
|
|
|
USHORT file_length,
|
|
|
|
UCHAR * file_name,
|
|
|
|
DBB * handle,
|
|
|
|
USHORT dpb_length, UCHAR * dpb, USHORT db_type)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* G D S _ C R E A T E _ D A T A B A S E
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Create a nice, squeeky clean database, uncorrupted by user data.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
STATUS stat, status_vector[20];
|
|
|
|
struct dsc$descriptor_s name;
|
|
|
|
|
|
|
|
/* Try GDS first; if ok, we're done */
|
|
|
|
|
|
|
|
init();
|
|
|
|
if (!RDB$CREATE_DATABASE &&
|
|
|
|
!find_symbol(&RDB$CREATE_DATABASE, "RDB$ATTACH_DATABASE")) {
|
|
|
|
user_status[0] = gds_arg_gds;
|
|
|
|
user_status[1] = gds_unavailable;
|
|
|
|
user_status[0] = 0;
|
|
|
|
return user_status[1];
|
|
|
|
}
|
|
|
|
|
|
|
|
make_desc(file_name, file_length, &name);
|
|
|
|
RDB_CALL(RDB$CREATE_DATABASE) (status_vector, &name, handle, dpb_length,
|
|
|
|
dpb, db_type);
|
|
|
|
|
|
|
|
if (!(stat = MAP_status_to_gds(status_vector, user_status)))
|
|
|
|
*handle = allocate_handle(*handle);
|
|
|
|
|
|
|
|
return stat;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int RDB_database_info(
|
|
|
|
int *user_status,
|
|
|
|
DBB * handle,
|
|
|
|
SSHORT item_length,
|
|
|
|
SCHAR * items, SSHORT buffer_length, SCHAR * buffer)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* g d s _ $ d a t a b a s e _ i n f o
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Get info on object.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
STATUS status_vector[20];
|
|
|
|
SCHAR item, *item_ptr, *end, *tmp_ptr, tmp_buff[32];
|
|
|
|
SSHORT len;
|
|
|
|
|
|
|
|
CHECK_HANDLE(handle, gds_bad_db_handle);
|
|
|
|
|
|
|
|
/* Rdb implemented some new db info items which overlap ours!
|
|
|
|
If we're here, we're known to be coming from gds, so force them
|
|
|
|
to return error by upping our codes */
|
|
|
|
|
|
|
|
tmp_ptr = tmp_buff;
|
|
|
|
item_ptr = items;
|
|
|
|
end = item_ptr + item_length;
|
|
|
|
while (item_ptr < end) {
|
|
|
|
*tmp_ptr = item = *item_ptr++;
|
|
|
|
if (item > gds_info_limbo)
|
|
|
|
*tmp_ptr += 200;
|
|
|
|
tmp_ptr++;
|
|
|
|
}
|
|
|
|
|
|
|
|
RDB_CALL(RDB$DATABASE_INFO) (status_vector, &(*handle)->handle,
|
|
|
|
item_length, &tmp_buff, buffer_length,
|
|
|
|
buffer);
|
|
|
|
|
|
|
|
/* Now clean the clumplets all back up again... */
|
|
|
|
|
|
|
|
item_ptr = buffer;
|
|
|
|
end = item_ptr + buffer_length;
|
|
|
|
while (item_ptr < end) {
|
|
|
|
item = *item_ptr++;
|
|
|
|
len = *item_ptr++;
|
|
|
|
len |= (*item_ptr++) << 8;
|
|
|
|
if (item == gds_info_error && *item_ptr > 200)
|
|
|
|
*item_ptr -= 200;
|
|
|
|
else if (item == gds_info_end || item == gds_info_truncated)
|
|
|
|
break;
|
|
|
|
item_ptr += len;
|
|
|
|
}
|
|
|
|
|
|
|
|
return MAP_status_to_gds(status_vector, user_status);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int RDB_detach_database(int *user_status, DBB * handle)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* G D S _ D E T A C H
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Close down a database.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
STATUS stat, status_vector[20];
|
|
|
|
DBB database;
|
|
|
|
REQ request;
|
|
|
|
|
|
|
|
CHECK_HANDLE(handle, gds_bad_db_handle);
|
|
|
|
database = *handle;
|
|
|
|
|
|
|
|
RDB_CALL(RDB$DETACH_DATABASE) (status_vector, &database->handle);
|
|
|
|
|
|
|
|
if (!(stat = MAP_status_to_gds(status_vector, user_status))) {
|
|
|
|
while (request = database->next) {
|
|
|
|
database->next = request->next;
|
|
|
|
MAP_release(request->messages);
|
|
|
|
gds__free(request);
|
|
|
|
}
|
|
|
|
gds__free(database);
|
|
|
|
*handle = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return stat;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int RDB_get_segment(
|
|
|
|
int *user_status,
|
|
|
|
BLB * blob_handle,
|
|
|
|
SSHORT * length, SSHORT buffer_length, UCHAR * buffer)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* R D B _ G E T _ S E G M E N T
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Get a segment from a blob (surprise!)
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
STATUS status_vector[20];
|
|
|
|
|
|
|
|
CHECK_HANDLE(blob_handle, gds_bad_segstr_handle);
|
|
|
|
|
|
|
|
RDB_CALL(RDB$GET_SEGMENT) (status_vector, &(*blob_handle)->handle,
|
|
|
|
length, buffer_length, buffer);
|
|
|
|
|
|
|
|
return MAP_status_to_gds(status_vector, user_status);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int RDB_open_blob(
|
|
|
|
int *user_status,
|
|
|
|
HANDLE * db_handle,
|
|
|
|
HANDLE * tra_handle,
|
|
|
|
HANDLE * blob_handle, GDS_QUAD * blob_id)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* R D B _ O P E N _ B L O B
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Get a segment from a blob (surprise!)
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
STATUS stat, status_vector[20];
|
|
|
|
|
|
|
|
CHECK_HANDLE(db_handle, gds_bad_db_handle);
|
|
|
|
CHECK_HANDLE(tra_handle, gds_bad_trans_handle);
|
|
|
|
|
|
|
|
RDB_CALL(RDB$OPEN_SEGMENTED_STRING) (status_vector, &(*db_handle)->handle,
|
|
|
|
&(*tra_handle)->handle, blob_handle,
|
|
|
|
blob_id);
|
|
|
|
|
|
|
|
if (!(stat = MAP_status_to_gds(status_vector, user_status)))
|
|
|
|
*blob_handle = allocate_handle(*blob_handle);
|
|
|
|
|
|
|
|
return stat;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int RDB_prepare_transaction(int *user_status, TRA * tra_handle)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* G D S _ P R E P A R E
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Prepare a transaction for commit. First phase of a two
|
|
|
|
* phase commit.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
STATUS status_vector[20];
|
|
|
|
|
|
|
|
CHECK_HANDLE(tra_handle, gds_bad_trans_handle);
|
|
|
|
RDB_CALL(RDB$PREPARE_TRANSACTION) (status_vector, &(*tra_handle)->handle);
|
|
|
|
|
|
|
|
return MAP_status_to_gds(status_vector, user_status);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int RDB_put_segment(
|
|
|
|
int *user_status,
|
|
|
|
BLB * blob_handle, SSHORT buffer_length, UCHAR * buffer)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* R D B _ P U T _ S E G M E N T
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Put a segment into a blob (surprise!)
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
STATUS status_vector[20];
|
|
|
|
|
|
|
|
CHECK_HANDLE(blob_handle, gds_bad_segstr_handle);
|
|
|
|
|
|
|
|
RDB_CALL(RDB$PUT_SEGMENT) (status_vector, &(*blob_handle)->handle,
|
|
|
|
buffer_length, buffer);
|
|
|
|
|
|
|
|
return MAP_status_to_gds(status_vector, user_status);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int RDB_receive(
|
|
|
|
int *user_status,
|
|
|
|
REQ * req_handle,
|
|
|
|
USHORT msg_type, USHORT msg_length, SCHAR * msg, SSHORT level)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* G D S _ R E C E I V E
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Get a record from the host program. Note
|
|
|
|
* that compile has already wandered through
|
|
|
|
* and made the temporary buffer large enough
|
|
|
|
* for the largest message.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
STATUS status_vector[20];
|
|
|
|
int length;
|
|
|
|
UCHAR *temp;
|
|
|
|
|
|
|
|
CHECK_HANDLE(req_handle, gds_bad_req_handle);
|
|
|
|
temp = allocate_temp(0);
|
|
|
|
|
|
|
|
if (length = MAP_rdb_length(msg_type, (*req_handle)->messages)) {
|
|
|
|
RDB_CALL(RDB$RECEIVE) (status_vector, &(*req_handle)->handle,
|
|
|
|
msg_type, length, temp, level);
|
|
|
|
MAP_rdb_to_gds(msg_type, (*req_handle)->messages, temp, msg);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
RDB_CALL(RDB$RECEIVE) (status_vector, &(*req_handle)->handle,
|
|
|
|
msg_type, msg_length, msg, level);
|
|
|
|
}
|
|
|
|
|
|
|
|
return MAP_status_to_gds(status_vector, user_status);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int RDB_reconnect_transaction(
|
|
|
|
int *user_status,
|
|
|
|
DBB * db_handle,
|
|
|
|
TRA * tra_handle, SSHORT length, UCHAR * id)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* G D S _ R E C O N N E C T
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Reconnect to a transaction in limbo.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
STATUS status_vector[20];
|
|
|
|
|
|
|
|
RDB_CALL(RDB$RECONNECT_TRANSACTION) (status_vector,
|
|
|
|
(*db_handle)->handle,
|
|
|
|
(*tra_handle)->handle, length, id);
|
|
|
|
|
|
|
|
return MAP_status_to_gds(status_vector, user_status);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int RDB_release_request(int *user_status, REQ * req_handle)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* G D S _ R E L E A S E _ R E Q U E S T
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Release a request.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
STATUS stat, status_vector[20];
|
|
|
|
DBB database;
|
|
|
|
REQ request, *ptr;
|
|
|
|
|
|
|
|
CHECK_HANDLE(req_handle, gds_bad_req_handle);
|
|
|
|
|
|
|
|
request = *req_handle;
|
|
|
|
RDB_CALL(RDB$RELEASE_REQUEST) (status_vector, &request->handle);
|
|
|
|
|
|
|
|
if (!(stat = MAP_status_to_gds(status_vector, user_status))) {
|
|
|
|
database = request->parent;
|
|
|
|
for (ptr = &database->next; *ptr; ptr = &(*ptr)->next)
|
|
|
|
if (*ptr == request) {
|
|
|
|
*ptr = request->next;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
MAP_release(request->messages);
|
|
|
|
gds__free(request);
|
|
|
|
*req_handle = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return stat;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int RDB_request_info(
|
|
|
|
int *user_status,
|
|
|
|
REQ * handle,
|
|
|
|
SSHORT level,
|
|
|
|
SSHORT item_length,
|
|
|
|
SCHAR * items, SSHORT buffer_length, SCHAR * buffer)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* g d s _ $ r e q u e s t _ i n f o
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Get info on object.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
STATUS status_vector[20];
|
|
|
|
|
|
|
|
CHECK_HANDLE(handle, gds_bad_req_handle);
|
|
|
|
|
|
|
|
RDB_CALL(RDB$REQUEST_INFO) (status_vector, &(*handle)->handle, level,
|
|
|
|
item_length, items, buffer_length, buffer);
|
|
|
|
|
|
|
|
return MAP_status_to_gds(status_vector, user_status);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int RDB_rollback_transaction(int *user_status, TRA * tra_handle)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* G D S _ R O L L B A C K
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Abort a transaction.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
STATUS stat, status_vector[20];
|
|
|
|
|
|
|
|
CHECK_HANDLE(tra_handle, gds_bad_trans_handle);
|
|
|
|
RDB_CALL(RDB$ROLLBACK_TRANSACTION) (status_vector,
|
|
|
|
&(*tra_handle)->handle);
|
|
|
|
|
|
|
|
if (!(stat = MAP_status_to_gds(status_vector, user_status))) {
|
|
|
|
gds__free(*tra_handle);
|
|
|
|
*tra_handle = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return stat;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int RDB_send(
|
|
|
|
int *user_status,
|
|
|
|
REQ * req_handle,
|
|
|
|
USHORT msg_type, USHORT msg_length, SCHAR * msg, SSHORT level)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* G D S _ S E N D
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Get a record from the host program. Note that
|
|
|
|
* the compile call has already checked and made the
|
|
|
|
* buffer big enough.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
STATUS status_vector[20];
|
|
|
|
UCHAR *temp;
|
|
|
|
int length;
|
|
|
|
|
|
|
|
|
|
|
|
temp = allocate_temp(0);
|
|
|
|
|
|
|
|
if (length = MAP_gds_to_rdb(msg_type, (*req_handle)->messages, msg, temp)) {
|
|
|
|
msg_length = length;
|
|
|
|
msg = temp;
|
|
|
|
}
|
|
|
|
|
|
|
|
RDB_CALL(RDB$SEND) (status_vector, &(*req_handle)->handle,
|
|
|
|
msg_type, msg_length, msg, level);
|
|
|
|
|
|
|
|
return MAP_status_to_gds(status_vector, user_status);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int RDB_start_and_send(
|
|
|
|
int *user_status,
|
|
|
|
REQ * req_handle,
|
|
|
|
TRA * tra_handle,
|
|
|
|
USHORT msg_type,
|
|
|
|
USHORT msg_length, SCHAR * msg, SSHORT level)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* G D S _ S T A R T _ A N D _ S E N D
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Get a record from the host program. Note
|
|
|
|
* that compile has already made the temporary
|
|
|
|
* buffer large enough for the largest message.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
STATUS status_vector[20];
|
|
|
|
UCHAR *temp;
|
|
|
|
int length;
|
|
|
|
|
|
|
|
CHECK_HANDLE(tra_handle, gds_bad_trans_handle);
|
|
|
|
CHECK_HANDLE(req_handle, gds_bad_req_handle);
|
|
|
|
temp = allocate_temp(0);
|
|
|
|
|
|
|
|
if (length = MAP_gds_to_rdb(msg_type, (*req_handle)->messages, msg, temp)) {
|
|
|
|
msg_length = length;
|
|
|
|
msg = temp;
|
|
|
|
}
|
|
|
|
|
|
|
|
RDB_CALL(RDB$START_AND_SEND) (status_vector, &(*req_handle)->handle,
|
|
|
|
&(*tra_handle)->handle, msg_type,
|
|
|
|
msg_length, msg, level);
|
|
|
|
|
|
|
|
return MAP_status_to_gds(status_vector, user_status);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int RDB_start_request(
|
|
|
|
int *user_status,
|
|
|
|
register REQ * req_handle,
|
|
|
|
register TRA * tra_handle, SSHORT level)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* G D S _ S T A R T _ R E Q U E S T
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Get a record from the host program.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
STATUS status_vector[20];
|
|
|
|
|
|
|
|
CHECK_HANDLE(tra_handle, gds_bad_trans_handle);
|
|
|
|
CHECK_HANDLE(req_handle, gds_bad_req_handle);
|
|
|
|
|
|
|
|
RDB_CALL(RDB$START_REQUEST) (status_vector, &(*req_handle)->handle,
|
|
|
|
&(*tra_handle)->handle, level);
|
|
|
|
|
|
|
|
return MAP_status_to_gds(status_vector, user_status);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int RDB_start_multiple(
|
|
|
|
int *user_status,
|
|
|
|
TRA * tra_handle, SSHORT count, TEB * teb)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* G D S _ S T A R T _ M U L T I P L E
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Start a transaction.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
STATUS stat, status_vector[20];
|
|
|
|
DBB database;
|
|
|
|
int rdb_vector[32], *rdb, c;
|
|
|
|
|
|
|
|
if (*tra_handle)
|
|
|
|
return bad_handle(user_status, gds_bad_trans_handle);
|
|
|
|
|
|
|
|
rdb = rdb_vector;
|
|
|
|
*rdb++ = 0;
|
|
|
|
*rdb++ = status_vector;
|
|
|
|
*rdb++ = tra_handle;
|
|
|
|
*rdb++ = 0;
|
|
|
|
|
|
|
|
for (c = 0; c < count; c++, teb++) {
|
|
|
|
database = *teb->teb_database;
|
|
|
|
if (!database)
|
|
|
|
return bad_handle(user_status, gds_bad_db_handle);
|
|
|
|
++rdb_vector[3];
|
|
|
|
*rdb++ = &database->handle;
|
|
|
|
*rdb++ = teb->teb_tpb_length;
|
|
|
|
*rdb++ = teb->teb_tpb;
|
|
|
|
}
|
|
|
|
|
|
|
|
rdb_vector[0] = rdb - rdb_vector - 1;
|
|
|
|
find_symbol(&RDB$START_TRANSACTION, "RDB$START_TRANSACTION");
|
|
|
|
lib$callg(rdb_vector, RDB$START_TRANSACTION);
|
|
|
|
|
|
|
|
if (!(stat = MAP_status_to_gds(status_vector, user_status)))
|
|
|
|
*tra_handle = allocate_handle(*tra_handle);
|
|
|
|
|
|
|
|
return stat;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int RDB_start_transaction(
|
|
|
|
int *user_status,
|
|
|
|
TRA * tra_handle,
|
|
|
|
SSHORT count,
|
|
|
|
DBB * db_handle, SSHORT tpb_length, SCHAR * tpb)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* G D S _ S T A R T _ T R A N S A C T I O N
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Start a transaction.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
STATUS stat, status_vector[20];
|
|
|
|
TEB *teb;
|
|
|
|
DBB database;
|
|
|
|
int rdb_vector[32], *rdb, c;
|
|
|
|
|
|
|
|
if (*tra_handle)
|
|
|
|
return bad_handle(user_status, gds_bad_trans_handle);
|
|
|
|
|
|
|
|
rdb = rdb_vector;
|
|
|
|
*rdb++ = 0;
|
|
|
|
*rdb++ = status_vector;
|
|
|
|
*rdb++ = tra_handle;
|
|
|
|
*rdb++ = 0;
|
|
|
|
|
|
|
|
for (teb = &db_handle, c = 0; c < count; c++, teb++) {
|
|
|
|
database = *teb->teb_database;
|
|
|
|
if (!database)
|
|
|
|
return bad_handle(user_status, gds_bad_db_handle);
|
|
|
|
++rdb_vector[3];
|
|
|
|
*rdb++ = &database->handle;
|
|
|
|
*rdb++ = teb->teb_tpb_length;
|
|
|
|
*rdb++ = teb->teb_tpb;
|
|
|
|
}
|
|
|
|
|
|
|
|
rdb_vector[0] = rdb - rdb_vector - 1;
|
|
|
|
find_symbol(&RDB$START_TRANSACTION, "RDB$START_TRANSACTION");
|
|
|
|
lib$callg(rdb_vector, RDB$START_TRANSACTION);
|
|
|
|
|
|
|
|
if (!(stat = MAP_status_to_gds(status_vector, user_status)))
|
|
|
|
*tra_handle = allocate_handle(*tra_handle);
|
|
|
|
|
|
|
|
return stat;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int RDB_transaction_info(
|
|
|
|
int *user_status,
|
|
|
|
TRA * handle,
|
|
|
|
SSHORT item_length,
|
|
|
|
SCHAR * items, SSHORT buffer_length, SCHAR * buffer)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* g d s _ $ t r a n s a c t i o n _ i n f o
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Get info on object.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
STATUS status_vector[20];
|
|
|
|
|
|
|
|
CHECK_HANDLE(handle, gds_bad_trans_handle);
|
|
|
|
|
|
|
|
RDB_CALL(RDB$TRANSACTION_INFO) (status_vector, &(*handle)->handle,
|
|
|
|
item_length, items, buffer_length,
|
|
|
|
buffer);
|
|
|
|
|
|
|
|
return MAP_status_to_gds(status_vector, user_status);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int RDB_unwind_request(int *user_status, REQ * req_handle, SSHORT level)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* G D S _ U N W I N D _ R E Q U E S T
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Unwind a running request.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
STATUS status_vector[20];
|
|
|
|
|
|
|
|
CHECK_HANDLE(req_handle, gds_bad_req_handle);
|
|
|
|
|
|
|
|
RDB_CALL(RDB$UNWIND_REQUEST) (status_vector, &(*req_handle)->handle,
|
|
|
|
level);
|
|
|
|
|
|
|
|
return MAP_status_to_gds(status_vector, user_status);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static HANDLE allocate_handle(int *real_handle)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* a l l o c a t e _ h a n d l e
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Allocate an indirect handle.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
HANDLE handle;
|
|
|
|
|
|
|
|
handle = gds__alloc((SLONG) sizeof(struct handle));
|
|
|
|
/* FREE: unknown - user process? */
|
|
|
|
if (!handle) /* NOMEM: not a great handler */
|
|
|
|
return NULL;
|
|
|
|
*handle = empty_handle;
|
|
|
|
handle->handle = real_handle;
|
|
|
|
|
|
|
|
return handle;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static UCHAR *allocate_temp(int length)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* a l l o c a t e _ t e m p
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Allocate a temp of at least a given size.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
|
|
|
if (length && temp_buffer_length < length) {
|
|
|
|
if (temp_buffer)
|
|
|
|
gds__free(temp_buffer);
|
|
|
|
temp_buffer = gds__alloc((SLONG) length);
|
|
|
|
/* FREE: unknown, reallocation handled above */
|
|
|
|
/* NOMEM: Caller must handle */
|
|
|
|
if (temp_buffer)
|
|
|
|
temp_buffer_length = length;
|
|
|
|
else
|
|
|
|
temp_buffer_length = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return temp_buffer;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int bad_handle(int *user_status, int code)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* b a d _ h a n d l e
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Generate an error for a bad handle.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
int local_status[20];
|
|
|
|
int trans, *vector;
|
|
|
|
|
|
|
|
vector = (user_status) ? user_status : local_status;
|
|
|
|
*vector++ = gds_arg_gds;
|
|
|
|
*vector++ = code;
|
|
|
|
*vector = 0;
|
|
|
|
|
|
|
|
return user_status[1];
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int check_handle(HANDLE * handle)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* c h e c k _ h a n d l e
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Validate a handle. Return TRUE if it's lousy.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
HANDLE blk;
|
|
|
|
|
|
|
|
if (blk = *handle)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int condition_handler(int *sig.int *mech.int *enbl)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* c o n d i t i o n _ h a n d l e r
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Ignore signal from "lib$find_symbol".
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
|
|
|
return SS$_CONTINUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int find_symbol(int *address, UCHAR * name)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* f i n d _ s y m b o l
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Look up entrypoint into RDB image.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
struct dsc$descriptor file, symbol;
|
|
|
|
|
|
|
|
VAXC$ESTABLISH(condition_handler);
|
|
|
|
make_desc(RDB_IMAGE, 0, &file);
|
|
|
|
make_desc(name, 0, &symbol);
|
|
|
|
lib$find_image_symbol(&file, &symbol, address);
|
|
|
|
|
|
|
|
return *address;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void init(void)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* i n i t
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Initialize module. Mostly just look up the
|
|
|
|
* Rdb/VMS debug flags.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
UCHAR *p, buffer[16];
|
|
|
|
USHORT l;
|
|
|
|
int status;
|
|
|
|
struct dsc$descriptor name, value;
|
|
|
|
|
|
|
|
make_desc("RDMS$DEBUG_FLAGS", 0, &name);
|
|
|
|
make_desc(buffer, sizeof(buffer), &value);
|
|
|
|
status = lib$sys_trnlog(&name, &l, &value);
|
|
|
|
|
|
|
|
if (status != SS$_NORMAL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (p = buffer; l; --l)
|
|
|
|
switch (*p++) {
|
|
|
|
case 'B':
|
|
|
|
debug_flags |= DEBUG_BLR;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'E':
|
|
|
|
debug_flags |= DEBUG_ERROR_BLR;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void make_desc(
|
|
|
|
UCHAR * string, int length, struct dsc$descriptor *desc)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* m a k e _ d e s c
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Fill in VMS descriptor.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
|
|
|
desc->dsc$b_dtype = DSC$K_DTYPE_T;
|
|
|
|
desc->dsc$b_class = DSC$K_CLASS_S;
|
|
|
|
desc->dsc$a_pointer = string;
|
|
|
|
|
|
|
|
if (!(desc->dsc$w_length = length))
|
|
|
|
desc->dsc$w_length = strlen(string);
|
|
|
|
}
|