mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-26 08:03:03 +01:00
0c1b55dd08
Since we already have the define ISC_STATUS_LENGTH for the the length of the status vector, we should use it! Replaced 'status[20]' with 'status[ISC_STATUS_LENGTH]'. Replaced the different symbolic names for the maximum length of a path (MAX_PATH, MAX_PATH_LENGTH, MAXPATHLEN) with one uniq symbol MAXPATHLEN.
1444 lines
32 KiB
C++
1444 lines
32 KiB
C++
/*
|
|
* PROGRAM: Rdb/GDS Access Method Interface
|
|
* MODULE: rdb.c
|
|
* DESCRIPTION: User visible entrypoints
|
|
*
|
|
* 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/gds.h"
|
|
#include "../jrd/rdb.h"
|
|
#include "../jrd/common.h"
|
|
#include "../jrd/mblr.h"
|
|
#include "../jrd/gds_proto.h"
|
|
#include "../jrd/map_proto.h"
|
|
#include "../jrd/mblr_proto.h"
|
|
|
|
#define RDB_IMAGE "RDBVMSSHR"
|
|
#define RDB_CALL(name) if (!name) find_symbol (&name,"name"); stat = (*name)
|
|
|
|
#define rdb$bad_req_handle 20480058
|
|
|
|
#define DBTYPE_ISC 37
|
|
|
|
/* Transaction element block */
|
|
|
|
typedef struct teb {
|
|
int *teb_database;
|
|
int teb_tpb_length;
|
|
SCHAR *teb_tpb;
|
|
} TEB;
|
|
|
|
typedef enum {
|
|
impl_rdb = 1,
|
|
impl_gds
|
|
} IMPL;
|
|
|
|
typedef struct handle {
|
|
IMPL implementation;
|
|
int *handle;
|
|
int *messages;
|
|
struct handle *parent;
|
|
struct handle *next;
|
|
} *HANDLE, *REQ, *DBB, *TRA, *BLB;
|
|
|
|
static TRA *dyn_tra_handle;
|
|
static STATUS status_vector[ISC_STATUS_LENGTH];
|
|
static UCHAR *temp_buffer;
|
|
static SLONG temp_buffer_length;
|
|
|
|
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) (), (*RDB$DDL) (), (*RDB$EXTENSION) ();
|
|
|
|
static HANDLE allocate_handle(IMPL, int *);
|
|
static UCHAR *allocate_temp(int);
|
|
static int condition_handler(int *, int *, int *);
|
|
static SSHORT dsc_length(struct dsc$descriptor *);
|
|
static int find_symbol(int *, UCHAR *);
|
|
static void make_desc(UCHAR *, int, struct dsc$descriptor *);
|
|
static void putmsg(struct dsc$descriptor *, SCHAR *);
|
|
static int set_status(int *, int);
|
|
|
|
static SLONG codes[] = {
|
|
#include "../jrd/rdbcodes.h"
|
|
};
|
|
|
|
|
|
int rdb$attach_database(
|
|
int *user_status,
|
|
struct dsc$descriptor *file,
|
|
DBB * handle,
|
|
SSHORT dpb_length, SCHAR * dpb, SSHORT db_type)
|
|
{
|
|
/**************************************
|
|
*
|
|
* r d b $ A T T A C H _ D A T A B A S E
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Create a nice, squeeky clean database, uncorrupted by user data.
|
|
*
|
|
**************************************/
|
|
int *status, stat;
|
|
int len;
|
|
|
|
/* Try Rdb/VMS first. If it succeeds, everything is ducky */
|
|
|
|
if (RDB$ATTACH_DATABASE ||
|
|
find_symbol(&RDB$ATTACH_DATABASE, "RDB$ATTACH_DATABASE")) {
|
|
RDB_CALL(RDB$ATTACH_DATABASE) (user_status, file, handle, dpb_length,
|
|
dpb);
|
|
if (stat & 1) {
|
|
*handle = allocate_handle(impl_rdb, *handle);
|
|
return stat;
|
|
}
|
|
}
|
|
|
|
/* Try GDS next.
|
|
Rdb/VMS implemented a new dpb version number, not documented.
|
|
Sense it and ignore the dpb. */
|
|
|
|
if (dpb_length && (dpb[0] == 2))
|
|
len = 0;
|
|
else
|
|
len = dpb_length;
|
|
|
|
stat = gds__attach_database(status_vector, dsc_length(file),
|
|
file->dsc$a_pointer, handle, len, dpb,
|
|
db_type);
|
|
|
|
if (!stat) {
|
|
*handle = allocate_handle(impl_gds, *handle);
|
|
return MAP_status_to_rdb(status_vector, user_status);
|
|
}
|
|
|
|
/* Neither worked -- return Rdb/VMS status */
|
|
|
|
return user_status[1];
|
|
}
|
|
|
|
|
|
int rdb$cancel_segmented_string(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!)
|
|
*
|
|
**************************************/
|
|
int stat;
|
|
|
|
if (!*blob_handle) {
|
|
*user_status++ = 1;
|
|
*user_status++ = 1;
|
|
return 1;
|
|
}
|
|
|
|
if ((*blob_handle)->implementation == impl_gds) {
|
|
gds__cancel_blob(status_vector, &(*blob_handle)->handle);
|
|
stat = MAP_status_to_rdb(status_vector, user_status);
|
|
}
|
|
else {
|
|
RDB_CALL(RDB$CANCEL_SEGMENTED_STRING) (user_status,
|
|
&(*blob_handle)->handle);
|
|
}
|
|
|
|
if (stat & 1) {
|
|
gds__free(*blob_handle);
|
|
*blob_handle = NULL;
|
|
}
|
|
|
|
return stat;
|
|
}
|
|
|
|
|
|
int rdb$close_segmented_string(int *user_status, BLB * blob_handle)
|
|
{
|
|
/**************************************
|
|
*
|
|
* r d b $ _ C L O S E _ B L O B
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Close a blob (surprise!)
|
|
*
|
|
**************************************/
|
|
int stat;
|
|
|
|
if (!*blob_handle)
|
|
return set_status(user_status, rdb$_bad_req_handle);
|
|
|
|
if ((*blob_handle)->implementation == impl_gds) {
|
|
gds__close_blob(status_vector, &(*blob_handle)->handle);
|
|
stat = MAP_status_to_rdb(status_vector, user_status);
|
|
}
|
|
else {
|
|
RDB_CALL(RDB$CLOSE_SEGMENTED_STRING) (user_status,
|
|
&(*blob_handle)->handle);
|
|
}
|
|
|
|
if (stat & 1) {
|
|
gds__free(*blob_handle);
|
|
*blob_handle = NULL;
|
|
}
|
|
|
|
return stat;
|
|
}
|
|
|
|
|
|
int rdb$commit_transaction(int *user_status, TRA * tra_handle)
|
|
{
|
|
/**************************************
|
|
*
|
|
* r d b $ C O M M I T
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Commit a transaction.
|
|
*
|
|
**************************************/
|
|
int stat;
|
|
|
|
if (!*tra_handle)
|
|
return set_status(user_status, rdb$_bad_trans_handle);
|
|
|
|
if ((*tra_handle)->implementation == impl_gds) {
|
|
gds__commit_transaction(status_vector, &(*tra_handle)->handle);
|
|
stat = MAP_status_to_rdb(status_vector, user_status);
|
|
}
|
|
else {
|
|
RDB_CALL(RDB$COMMIT_TRANSACTION) (user_status,
|
|
&(*tra_handle)->handle);
|
|
}
|
|
|
|
if (stat & 1) {
|
|
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)
|
|
{
|
|
/**************************************
|
|
*
|
|
* r d b $ C O M P I L E
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
*
|
|
**************************************/
|
|
STATUS stat;
|
|
int *messages;
|
|
REQ request;
|
|
DBB database;
|
|
USHORT temp_length;
|
|
UCHAR *temp;
|
|
SLONG max_length;
|
|
|
|
if (!*db_handle)
|
|
return set_status(user_status, rdb$_bad_db_handle);
|
|
|
|
messages = NULL;
|
|
database = *db_handle;
|
|
temp = allocate_temp(blr_length + 200);
|
|
|
|
if ((*db_handle)->implementation == impl_gds) {
|
|
if (messages =
|
|
MAP_parse_blr(blr, blr_length, temp, &temp_length, &max_length)) {
|
|
blr = temp;
|
|
blr_length = temp_length;
|
|
allocate_temp(max_length);
|
|
}
|
|
if (gds__compile_request(status_vector, &database->handle,
|
|
req_handle, blr_length, blr))
|
|
MAP_release(messages);
|
|
stat = MAP_status_to_rdb(status_vector, user_status);
|
|
}
|
|
else {
|
|
RDB_CALL(RDB$COMPILE_REQUEST) (user_status, &database->handle,
|
|
req_handle, blr_length, blr);
|
|
}
|
|
|
|
if (stat & 1) {
|
|
*req_handle = request =
|
|
allocate_handle(database->implementation, *req_handle);
|
|
request->parent = database;
|
|
request->next = database->next;
|
|
database->next = request;
|
|
request->messages = messages;
|
|
}
|
|
|
|
return stat;
|
|
}
|
|
|
|
|
|
int rdb$create_database(
|
|
int *user_status,
|
|
struct dsc$descriptor *file,
|
|
DBB * handle,
|
|
USHORT dpb_length, UCHAR * dpb, USHORT db_type)
|
|
{
|
|
/**************************************
|
|
*
|
|
* r d b $ 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.
|
|
*
|
|
**************************************/
|
|
int stat;
|
|
|
|
if (db_type = DBTYPE_ISC) {
|
|
stat = gds__create_database(status_vector, dsc_length(file),
|
|
file->dsc$a_pointer, handle, dpb_length,
|
|
dpb, db_type);
|
|
if (stat & 1)
|
|
*handle = allocate_handle(impl_gds, *handle);
|
|
return MAP_status_to_rdb(status_vector, user_status);
|
|
}
|
|
|
|
else {
|
|
RDB_CALL(RDB$CREATE_DATABASE) (user_status, file, handle,
|
|
dpb_length, dpb, db_type);
|
|
if (stat & 1)
|
|
*handle = allocate_handle(impl_rdb, *handle);
|
|
return stat;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
int rdb$create_segmented_string(
|
|
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!)
|
|
*
|
|
**************************************/
|
|
int stat;
|
|
|
|
if (!*db_handle)
|
|
return set_status(user_status, rdb$_bad_db_handle);
|
|
|
|
if ((*db_handle)->implementation == impl_gds) {
|
|
gds__create_blob(status_vector, &(*db_handle)->handle,
|
|
&(*tra_handle)->handle, blob_handle, blob_id);
|
|
stat = MAP_status_to_rdb(status_vector, user_status);
|
|
}
|
|
else {
|
|
RDB_CALL(RDB$CREATE_SEGMENTED_STRING) (user_status,
|
|
&(*db_handle)->handle,
|
|
&(*tra_handle)->handle,
|
|
blob_handle, blob_id);
|
|
}
|
|
|
|
if (stat & 1)
|
|
*blob_handle =
|
|
allocate_handle((*db_handle)->implementation, *blob_handle);
|
|
|
|
return stat;
|
|
}
|
|
|
|
|
|
int rdb$database_info(
|
|
int *user_status,
|
|
DBB * handle,
|
|
SSHORT item_length,
|
|
SCHAR * items, SSHORT buffer_length, SCHAR * buffer)
|
|
{
|
|
/**************************************
|
|
*
|
|
* r d b $ d a t a b a s e _ i n f o
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Get info on object.
|
|
*
|
|
**************************************/
|
|
int stat;
|
|
SCHAR item, *item_ptr, *end, *tmp_ptr, tmp_buff[32];
|
|
SSHORT len;
|
|
|
|
if (!*handle)
|
|
return set_status(user_status, rdb$_bad_db_handle);
|
|
|
|
if ((*handle)->implementation == impl_gds) {
|
|
/* Rdb implemented more info items (but didnt' document them)
|
|
and theirs overlap ours. So, force error on the ones
|
|
we don't know about. */
|
|
|
|
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++;
|
|
}
|
|
|
|
gds__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;
|
|
}
|
|
|
|
stat = MAP_status_to_rdb(status_vector, user_status);
|
|
}
|
|
else {
|
|
RDB_CALL(RDB$DATABASE_INFO) (user_status, &(*handle)->handle,
|
|
item_length, items, buffer_length,
|
|
buffer);
|
|
}
|
|
|
|
return stat;
|
|
}
|
|
|
|
|
|
int rdb$ddl(
|
|
int *user_status,
|
|
DBB * db_handle, UCHAR ddl_operation, int length, UCHAR * buffer)
|
|
{
|
|
/**************************************
|
|
*
|
|
* r d b $ d d l
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Support RDB metadata BLR (MBLR) through
|
|
* translation to InterBase DYN, or pass
|
|
* it through as before to RDB.
|
|
*
|
|
**************************************/
|
|
int stat, dyn_length, gds_vector[32], *gds;
|
|
UCHAR *dyn_buffer;
|
|
|
|
if (!*db_handle)
|
|
return set_status(user_status, rdb$_bad_db_handle);
|
|
|
|
if (!dyn_tra_handle)
|
|
return set_status(user_status, rdb$_bad_trans_handle);
|
|
|
|
if ((*db_handle)->implementation == impl_gds) {
|
|
|
|
/* First see if we can in fact translate the MBLR string into a DYN string */
|
|
|
|
dyn_buffer = allocate_temp(2 * length);
|
|
if (!MBLR_translate_to_dyn((int) ddl_operation, length, buffer,
|
|
&dyn_length, dyn_buffer))
|
|
return set_status(user_status, rdb$_wish_list);
|
|
|
|
/* Finally we can ship off the DYN string built to be processed */
|
|
|
|
if (gds__ddl(status_vector, &(*db_handle)->handle,
|
|
&(*dyn_tra_handle)->handle, dyn_length, dyn_buffer));
|
|
{
|
|
stat = MAP_status_to_rdb(status_vector, user_status);
|
|
return stat;
|
|
}
|
|
}
|
|
else {
|
|
RDB_CALL(RDB$DDL) (user_status, &(*db_handle)->handle,
|
|
ddl_operation, length, buffer);
|
|
}
|
|
|
|
return stat;
|
|
}
|
|
|
|
|
|
int rdb$detach_database(int *user_status, DBB * handle)
|
|
{
|
|
/**************************************
|
|
*
|
|
* r d b $ D E T A C H
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Close down a database.
|
|
*
|
|
**************************************/
|
|
DBB database;
|
|
REQ request;
|
|
int stat;
|
|
|
|
if (!(database = *handle))
|
|
return set_status(user_status, rdb$_bad_db_handle);
|
|
|
|
if (database->implementation == impl_gds) {
|
|
gds__detach_database(status_vector, &database->handle);
|
|
stat = MAP_status_to_rdb(status_vector, user_status);
|
|
}
|
|
else {
|
|
RDB_CALL(RDB$DETACH_DATABASE) (user_status, &database->handle);
|
|
}
|
|
|
|
if (stat & 1) {
|
|
while (request = database->next) {
|
|
database->next = request->next;
|
|
MAP_release(request->messages);
|
|
gds__free(request);
|
|
}
|
|
gds__free(database);
|
|
*handle = NULL;
|
|
}
|
|
|
|
return stat;
|
|
}
|
|
|
|
|
|
int rdb$extension(
|
|
int *user_status,
|
|
USHORT index,
|
|
HANDLE * handle,
|
|
UCHAR type,
|
|
USHORT input_length,
|
|
UCHAR * input, USHORT result_length, UCHAR * result)
|
|
{
|
|
/**************************************
|
|
*
|
|
* r d b $ e x t e n s i o n
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Unimplemented function.
|
|
*
|
|
**************************************/
|
|
int stat;
|
|
|
|
if (!*handle)
|
|
return set_status(user_status, rdb$_bad_db_handle);
|
|
|
|
if ((*handle)->implementation == impl_gds)
|
|
return set_status(user_status, rdb$_wish_list);
|
|
else {
|
|
RDB_CALL(RDB$EXTENSION) (user_status,
|
|
index,
|
|
&(*handle)->handle,
|
|
type,
|
|
input_length, input, result_length, result);
|
|
}
|
|
|
|
return stat;
|
|
}
|
|
|
|
|
|
int rdb$get_segment(
|
|
int *user_status,
|
|
HANDLE * 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!)
|
|
*
|
|
**************************************/
|
|
int stat;
|
|
|
|
if (!*blob_handle)
|
|
return set_status(user_status, rdb$_bad_segstr_handle);
|
|
|
|
if ((*blob_handle)->implementation == impl_gds) {
|
|
gds__get_segment(status_vector, &(*blob_handle)->handle,
|
|
length, buffer_length, buffer);
|
|
stat = MAP_status_to_rdb(status_vector, user_status);
|
|
}
|
|
else {
|
|
RDB_CALL(RDB$GET_SEGMENT) (user_status, &(*blob_handle)->handle,
|
|
length, buffer_length, buffer);
|
|
}
|
|
|
|
return stat;
|
|
}
|
|
|
|
|
|
int rdb$open_segmented_string(
|
|
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!)
|
|
*
|
|
**************************************/
|
|
int stat;
|
|
|
|
if (!*db_handle)
|
|
return set_status(user_status, rdb$_bad_db_handle);
|
|
|
|
if ((*db_handle)->implementation == impl_gds) {
|
|
gds__open_blob(status_vector, &(*db_handle)->handle,
|
|
&(*tra_handle)->handle, blob_handle, blob_id);
|
|
stat = MAP_status_to_rdb(status_vector, user_status);
|
|
}
|
|
else {
|
|
RDB_CALL(RDB$OPEN_SEGMENTED_STRING) (user_status,
|
|
&(*db_handle)->handle,
|
|
&(*tra_handle)->handle,
|
|
blob_handle, blob_id);
|
|
}
|
|
|
|
if (stat & 1)
|
|
*blob_handle =
|
|
allocate_handle((*db_handle)->implementation, *blob_handle);
|
|
|
|
return stat;
|
|
}
|
|
|
|
|
|
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!)
|
|
*
|
|
**************************************/
|
|
int stat;
|
|
|
|
if (!*blob_handle)
|
|
return set_status(user_status, rdb$_bad_segstr_handle);
|
|
|
|
if ((*blob_handle)->implementation == impl_gds) {
|
|
gds__put_segment(status_vector, &(*blob_handle)->handle,
|
|
buffer_length, buffer);
|
|
stat = MAP_status_to_rdb(status_vector, user_status);
|
|
}
|
|
else {
|
|
RDB_CALL(RDB$PUT_SEGMENT) (user_status, &(*blob_handle)->handle,
|
|
buffer_length, buffer);
|
|
}
|
|
|
|
return stat;
|
|
}
|
|
|
|
|
|
int rdb$prepare_transaction(int *user_status, TRA * tra_handle)
|
|
{
|
|
/**************************************
|
|
*
|
|
* r d b $ p r e p a r e
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Prepare a transaction for commit. First phase of a two
|
|
* phase commit.
|
|
*
|
|
**************************************/
|
|
int stat;
|
|
|
|
if (!*tra_handle)
|
|
return set_status(user_status, rdb$_bad_trans_handle);
|
|
|
|
if ((*tra_handle)->implementation == impl_gds) {
|
|
gds__prepare_transaction(status_vector, &(*tra_handle)->handle);
|
|
stat = MAP_status_to_rdb(status_vector, user_status);
|
|
}
|
|
else {
|
|
RDB_CALL(RDB$PREPARE_TRANSACTION) (user_status,
|
|
&(*tra_handle)->handle);
|
|
}
|
|
|
|
return stat;
|
|
}
|
|
|
|
|
|
int rdb$receive(
|
|
int *user_status,
|
|
REQ * req_handle,
|
|
USHORT msg_type, USHORT msg_length, SCHAR * msg, SSHORT level)
|
|
{
|
|
/**************************************
|
|
*
|
|
* r d b $ R E C E I V E
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Get a record from the host program.
|
|
*
|
|
**************************************/
|
|
STATUS stat;
|
|
REQ request;
|
|
UCHAR *temp;
|
|
int length;
|
|
|
|
if (!(request = *req_handle))
|
|
return set_status(user_status, rdb$_bad_req_handle);
|
|
|
|
if (request->implementation == impl_gds) {
|
|
if (length = MAP_rdb_length(msg_type, request->messages)) {
|
|
temp = allocate_temp(0);
|
|
gds__receive(status_vector, &request->handle,
|
|
msg_type, length, temp, level);
|
|
MAP_gds_to_rdb(msg_type, request->messages, temp, msg);
|
|
}
|
|
else
|
|
gds__receive(status_vector, &request->handle,
|
|
msg_type, msg_length, msg, level);
|
|
stat = MAP_status_to_rdb(status_vector, user_status);
|
|
}
|
|
else {
|
|
RDB_CALL(RDB$RECEIVE) (user_status, &request->handle,
|
|
msg_type, msg_length, msg, level);
|
|
}
|
|
|
|
return stat;
|
|
}
|
|
|
|
|
|
int rdb$reconnect_transaction(
|
|
int *user_status,
|
|
DBB * db_handle,
|
|
TRA * tra_handle, SSHORT length, UCHAR * id)
|
|
{
|
|
/**************************************
|
|
*
|
|
* r d b $ r e c o n n e c t _ t r a n s a c t i o n
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Reconnect to a transaction in limbo.
|
|
*
|
|
**************************************/
|
|
int stat;
|
|
|
|
if (!*db_handle)
|
|
return set_status(user_status, rdb$_bad_db_handle);
|
|
|
|
if ((*db_handle)->handle == impl_gds) {
|
|
gds__reconnect_transaction(status_vector,
|
|
(*db_handle)->handle,
|
|
(*tra_handle)->handle, length, id);
|
|
return MAP_status_to_rdb(status_vector, user_status);
|
|
}
|
|
|
|
RDB_CALL(RDB$RECONNECT_TRANSACTION) (user_status,
|
|
(*db_handle)->handle,
|
|
(*tra_handle)->handle, length, id);
|
|
|
|
return stat;
|
|
}
|
|
|
|
|
|
int rdb$request_info(
|
|
int *user_status,
|
|
REQ * handle,
|
|
SSHORT level,
|
|
SSHORT item_length,
|
|
SCHAR * items, SSHORT buffer_length, SCHAR * buffer)
|
|
{
|
|
/**************************************
|
|
*
|
|
* r d b $ r e q u e s t _ i n f o
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Get info on object.
|
|
*
|
|
**************************************/
|
|
int stat;
|
|
|
|
if (!*handle)
|
|
return set_status(user_status, rdb$_bad_req_handle);
|
|
|
|
if ((*handle)->implementation == impl_gds) {
|
|
gds__request_info(status_vector, &(*handle)->handle,
|
|
item_length, items, buffer_length, buffer, level);
|
|
stat = MAP_status_to_rdb(status_vector, user_status);
|
|
}
|
|
else {
|
|
RDB_CALL(RDB$REQUEST_INFO) (user_status, &(*handle)->handle,
|
|
item_length, items, buffer_length, buffer,
|
|
level);
|
|
}
|
|
|
|
return stat;
|
|
}
|
|
|
|
|
|
int rdb$release_request(int *user_status, REQ * req_handle)
|
|
{
|
|
/**************************************
|
|
*
|
|
* r d b $ R E L E A S E _ R E Q U E S T
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Release a request.
|
|
*
|
|
**************************************/
|
|
REQ *ptr, request;
|
|
DBB database;
|
|
int stat;
|
|
|
|
if (!(request = *req_handle))
|
|
return set_status(user_status, rdb$_bad_req_handle);
|
|
|
|
if (request->implementation == impl_gds) {
|
|
gds__release_request(status_vector, &request->handle);
|
|
stat = MAP_status_to_rdb(status_vector, user_status);
|
|
}
|
|
else {
|
|
RDB_CALL(RDB$RELEASE_REQUEST) (user_status, &request->handle);
|
|
}
|
|
|
|
if (stat & 1) {
|
|
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$rollback_transaction(int *user_status, TRA * tra_handle)
|
|
{
|
|
/**************************************
|
|
*
|
|
* r d b $ R O L L B A C K
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Abort a transaction.
|
|
*
|
|
**************************************/
|
|
int stat;
|
|
|
|
if (!*tra_handle)
|
|
return set_status(user_status, rdb$_bad_trans_handle);
|
|
|
|
if ((*tra_handle)->implementation == impl_gds) {
|
|
gds__rollback_transaction(status_vector, &(*tra_handle)->handle);
|
|
stat = MAP_status_to_rdb(status_vector, user_status);
|
|
}
|
|
else {
|
|
RDB_CALL(RDB$ROLLBACK_TRANSACTION) (user_status,
|
|
&(*tra_handle)->handle);
|
|
}
|
|
|
|
if (stat & 1) {
|
|
gds__free(*tra_handle);
|
|
*tra_handle = NULL;
|
|
}
|
|
|
|
return stat;
|
|
}
|
|
|
|
|
|
int rdb$segmented_string_info(
|
|
int *user_status,
|
|
BLB * handle,
|
|
SSHORT item_length,
|
|
SCHAR * items,
|
|
SSHORT buffer_length, SCHAR * buffer)
|
|
{
|
|
/**************************************
|
|
*
|
|
* r d b $ b l o b _ i n f o
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Get info on object.
|
|
*
|
|
**************************************/
|
|
int stat;
|
|
|
|
if (!*handle)
|
|
return set_status(user_status, rdb$_bad_segstr_handle);
|
|
|
|
if ((*handle)->implementation == impl_gds) {
|
|
gds__blob_info(status_vector, &(*handle)->handle,
|
|
item_length, items, buffer_length, buffer);
|
|
stat = MAP_status_to_rdb(status_vector, user_status);
|
|
}
|
|
else {
|
|
RDB_CALL(RDB$SEGMENTED_STRING_INFO) (user_status, &(*handle)->handle,
|
|
item_length, items,
|
|
buffer_length, buffer);
|
|
}
|
|
|
|
return stat;
|
|
}
|
|
|
|
|
|
int rdb$send(
|
|
int *user_status,
|
|
REQ * req_handle,
|
|
USHORT msg_type, USHORT msg_length, SCHAR * msg, SSHORT level)
|
|
{
|
|
/**************************************
|
|
*
|
|
* r d b $ S E N D
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Get a record from the host program.
|
|
*
|
|
**************************************/
|
|
int length, stat;
|
|
REQ request;
|
|
UCHAR *temp;
|
|
|
|
if (!(request = *req_handle))
|
|
return set_status(user_status, rdb$_bad_req_handle);
|
|
|
|
if (request->implementation == impl_gds) {
|
|
temp = allocate_temp(0);
|
|
if (length = MAP_rdb_to_gds(msg_type, request->messages, msg, temp)) {
|
|
msg_length = length;
|
|
msg = temp;
|
|
}
|
|
gds__send(status_vector, &request->handle,
|
|
msg_type, msg_length, msg, level);
|
|
stat = MAP_status_to_rdb(status_vector, user_status);
|
|
}
|
|
else {
|
|
RDB_CALL(RDB$SEND) (user_status, &request->handle,
|
|
msg_type, msg_length, msg, level);
|
|
}
|
|
|
|
return stat;
|
|
}
|
|
|
|
|
|
int rdb$start_and_send(
|
|
int *user_status,
|
|
REQ * req_handle,
|
|
TRA * tra_handle,
|
|
USHORT msg_type,
|
|
USHORT msg_length, SCHAR * msg, SSHORT level)
|
|
{
|
|
/**************************************
|
|
*
|
|
* r d b $ S T A R T _ A N D _ S E N D
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Get a record from the host program.
|
|
*
|
|
**************************************/
|
|
int length, stat;
|
|
REQ request;
|
|
UCHAR *temp;
|
|
|
|
if (!(request = *req_handle))
|
|
return set_status(user_status, rdb$_bad_req_handle);
|
|
|
|
if ((*req_handle)->implementation == impl_gds) {
|
|
temp = allocate_temp(0);
|
|
if (length = MAP_rdb_to_gds(msg_type, request->messages, msg, temp)) {
|
|
msg_length = length;
|
|
msg = temp;
|
|
}
|
|
gds__start_and_send(status_vector, &request->handle,
|
|
&(*tra_handle)->handle, msg_type, msg_length, msg,
|
|
level);
|
|
stat = MAP_status_to_rdb(status_vector, user_status);
|
|
}
|
|
else {
|
|
RDB_CALL(RDB$START_AND_SEND) (user_status, &request->handle,
|
|
&(*tra_handle)->handle, msg_type,
|
|
msg_length, msg, level);
|
|
}
|
|
|
|
return stat;
|
|
}
|
|
|
|
|
|
int rdb$start_request(
|
|
int *user_status,
|
|
register REQ * req_handle,
|
|
register TRA * tra_handle, SSHORT level)
|
|
{
|
|
/**************************************
|
|
*
|
|
* r d b $ s t a r t _ r e q u e s t
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Get a record from the host program.
|
|
*
|
|
**************************************/
|
|
int stat;
|
|
|
|
if (!*req_handle)
|
|
return set_status(user_status, rdb$_bad_req_handle);
|
|
|
|
if ((*req_handle)->implementation == impl_gds) {
|
|
gds__start_request(status_vector, &(*req_handle)->handle,
|
|
&(*tra_handle)->handle, level);
|
|
stat = MAP_status_to_rdb(status_vector, user_status);
|
|
}
|
|
else {
|
|
RDB_CALL(RDB$START_REQUEST) (user_status, &(*req_handle)->handle,
|
|
&(*tra_handle)->handle, level);
|
|
}
|
|
|
|
return stat;
|
|
}
|
|
|
|
|
|
int rdb$start_multiple(
|
|
int *user_status,
|
|
TRA * tra_handle, SSHORT count, TEB * teb)
|
|
{
|
|
/**************************************
|
|
*
|
|
* r d b $ s t a r t _ m u l t i p l e
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Start a transaction.
|
|
*
|
|
**************************************/
|
|
}
|
|
|
|
|
|
int rdb$start_transaction(
|
|
int *user_status,
|
|
TRA * tra_handle,
|
|
SSHORT count,
|
|
DBB * db_handle, SSHORT tpb_length, SCHAR * tpb)
|
|
{
|
|
/**************************************
|
|
*
|
|
* r d b $ s t a r t _ t r a n s a c t i o n
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Start a transaction.
|
|
*
|
|
**************************************/
|
|
TEB *teb;
|
|
DBB database;
|
|
int stat, gds_vector[32], rdb_vector[32], *gds, *rdb, c;
|
|
|
|
if (*tra_handle)
|
|
return set_status(user_status, rdb$_bad_trans_handle);
|
|
|
|
gds = gds_vector;
|
|
*gds++ = 0;
|
|
*gds++ = user_status;
|
|
*gds++ = tra_handle;
|
|
*gds++ = 0;
|
|
|
|
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 set_status(user_status, rdb$_bad_db_handle);
|
|
if (database->implementation == impl_gds) {
|
|
++gds_vector[3];
|
|
*gds++ = &database->handle;
|
|
*gds++ = teb->teb_tpb_length;
|
|
*gds++ = teb->teb_tpb;
|
|
}
|
|
else {
|
|
++rdb_vector[3];
|
|
*rdb++ = &database->handle;
|
|
*rdb++ = teb->teb_tpb_length;
|
|
*rdb++ = teb->teb_tpb;
|
|
}
|
|
}
|
|
|
|
if (gds_vector[3]) {
|
|
gds_vector[0] = gds - gds_vector - 1;
|
|
stat = lib$callg(gds_vector, gds__start_transaction);
|
|
if (!stat) {
|
|
*tra_handle = allocate_handle(impl_gds, *tra_handle);
|
|
dyn_tra_handle = *tra_handle;
|
|
}
|
|
stat = MAP_status_to_rdb(status_vector, user_status);
|
|
}
|
|
|
|
if (rdb_vector[3]) {
|
|
rdb_vector[0] = rdb - rdb_vector - 1;
|
|
find_symbol(&RDB$START_TRANSACTION, "RDB$START_TRANSACTION");
|
|
stat = lib$callg(rdb_vector, RDB$START_TRANSACTION);
|
|
if (stat & 1)
|
|
*tra_handle = allocate_handle(impl_rdb, *tra_handle);
|
|
}
|
|
|
|
return stat;
|
|
}
|
|
|
|
|
|
int rdb$transaction_info(
|
|
int *user_status,
|
|
TRA * handle,
|
|
SSHORT item_length,
|
|
SCHAR * items, SSHORT buffer_length, SCHAR * buffer)
|
|
{
|
|
/**************************************
|
|
*
|
|
* r d b $ t r a n s a c t i o n _ i n f o
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Get info on object.
|
|
*
|
|
**************************************/
|
|
int stat;
|
|
|
|
if (!*handle)
|
|
return set_status(user_status, rdb$_bad_trans_handle);
|
|
|
|
if ((*handle)->implementation == impl_gds) {
|
|
gds__transaction_info(status_vector, &(*handle)->handle,
|
|
item_length, items, buffer_length, buffer);
|
|
stat = MAP_status_to_rdb(status_vector, user_status);
|
|
}
|
|
else {
|
|
RDB_CALL(RDB$TRANSACTION_INFO) (user_status, &(*handle)->handle,
|
|
item_length, items, buffer_length,
|
|
buffer);
|
|
}
|
|
|
|
return stat;
|
|
}
|
|
|
|
|
|
int rdb$unwind_request(int *user_status, REQ * req_handle, SSHORT level)
|
|
{
|
|
/**************************************
|
|
*
|
|
* r d b $ U N W I N D _ r e q u e s t
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Unwind a running request.
|
|
*
|
|
**************************************/
|
|
int stat;
|
|
|
|
if (!*req_handle)
|
|
return set_status(user_status, rdb$_bad_req_handle);
|
|
|
|
if ((*req_handle)->implementation == impl_gds) {
|
|
gds__unwind_request(status_vector, &(*req_handle)->handle, level);
|
|
stat = MAP_status_to_rdb(status_vector, user_status);
|
|
}
|
|
else {
|
|
RDB_CALL(RDB$UNWIND_REQUEST) (user_status, &(*req_handle)->handle,
|
|
level);
|
|
}
|
|
|
|
return stat;
|
|
}
|
|
|
|
|
|
static HANDLE allocate_handle(IMPL implementation, int *real_handle)
|
|
{
|
|
/**************************************
|
|
*
|
|
* a l l o c a t e _ h a n d l e
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Allocate an indirect handle.
|
|
*
|
|
**************************************/
|
|
UCHAR *p, *end;
|
|
HANDLE handle;
|
|
|
|
handle = gds__alloc((SLONG) sizeof(struct handle));
|
|
/* FREE: unknown */
|
|
if (!handle) { /* NOMEM: crash here */
|
|
DEV_REPORT("allocate_handle: no memory");
|
|
/* NOMEM: not handled, crash here */
|
|
}
|
|
|
|
for (p = handle, end = p + sizeof(struct handle); p < end;)
|
|
*p++ = 0;
|
|
|
|
handle->implementation = implementation;
|
|
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 of buffer handled above */
|
|
/* NOMEM: caller must handle */
|
|
if (temp_buffer)
|
|
temp_buffer_length = length;
|
|
else
|
|
temp_buffer_length = 0;
|
|
}
|
|
|
|
return temp_buffer;
|
|
}
|
|
|
|
|
|
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 SSHORT dsc_length(struct dsc$descriptor *d)
|
|
{
|
|
/**************************************
|
|
*
|
|
* d s c _ l e n g t h
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Determine length of argument passed by descriptor
|
|
*
|
|
**************************************/
|
|
struct dsc$descriptor_a *a;
|
|
|
|
switch (d->dsc$b_class) {
|
|
case DSC$K_CLASS_A:
|
|
a = d;
|
|
return a->dsc$l_arsize;
|
|
|
|
default:
|
|
return d->dsc$w_length;
|
|
}
|
|
}
|
|
|
|
|
|
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 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);
|
|
}
|
|
|
|
|
|
|
|
static void putmsg(struct dsc$descriptor_s *desc, SCHAR * arg)
|
|
{
|
|
/**************************************
|
|
*
|
|
* p u t m s g
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Get a line of message.
|
|
*
|
|
**************************************/
|
|
|
|
}
|
|
|
|
|
|
static int set_status(int *status, int code)
|
|
{
|
|
/**************************************
|
|
*
|
|
* s e t _ s t a t u s
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Generate an error for a bad handle.
|
|
*
|
|
**************************************/
|
|
|
|
*status++ = 1;
|
|
*status++ = code;
|
|
*status = 0;
|
|
|
|
return code;
|
|
}
|
|
|
|
|
|
#define DUMMY(name) name () {ib_printf ("name entered\n"); return 0;}
|
|
DUMMY(rdb$dummy1);
|