8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-27 06:03:02 +01:00
firebird-mirror/src/jrd/rdbint.cpp

1216 lines
27 KiB
C++

/*
* 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): ______________________________________.
*/
#include "firebird.h"
#include descrip
#include ssdef
#include "../jrd/lnmdef.h"
#include "../jrd/gds.h"
#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);
}