8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-27 17:23:03 +01:00
firebird-mirror/src/remote/protocol.cpp

1912 lines
50 KiB
C++
Raw Normal View History

2001-05-23 15:26:42 +02:00
/*
* PROGRAM: JRD Remote Interface/Server
* MODULE: protocol.cpp
2001-05-23 15:26:42 +02:00
* DESCRIPTION: Protocol data structure mapper
*
* The contents of this file are subject to the Interbase Public
* License Version 1.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy
* of the License at http://www.Inprise.com/IPL.html
*
* Software distributed under the License is distributed on an
* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express
* or implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code was created by Inprise Corporation
* and its predecessors. Portions created by Inprise Corporation are
* Copyright (C) Inprise Corporation.
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
2002-02-16 04:27:33 +01:00
*
* 2002.02.15 Sean Leyne - Code Cleanup, removed obsolete "IMP" port
*
* 2002.10.27 Sean Leyne - Code Cleanup, removed obsolete "Ultrix/MIPS" port
* 2002.10.28 Sean Leyne - Code cleanup, removed obsolete "SGI" port
*
2001-05-23 15:26:42 +02:00
*/
#include "firebird.h"
2001-05-23 15:26:42 +02:00
#include "../jrd/ib_stdio.h"
#include <string.h>
#include "../remote/remote.h"
#include "gen/codes.h"
2001-05-23 15:26:42 +02:00
#include "../jrd/sdl.h"
#include "../jrd/gdsassert.h"
#include "../remote/parse_proto.h"
#include "../remote/proto_proto.h"
#include "../remote/remot_proto.h"
#include "../jrd/gds_proto.h"
#include "../jrd/sdl_proto.h"
#ifdef DEBUG_XDR_MEMORY
#define P_TRUE xdr_debug_packet (xdrs, XDR_FREE, p)
#define P_FALSE !xdr_debug_packet (xdrs, XDR_FREE, p)
#define DEBUG_XDR_PACKET xdr_debug_packet (xdrs, XDR_DECODE, p)
2001-05-23 15:26:42 +02:00
#define DEBUG_XDR_ALLOC(xdrvar, addr, len) \
xdr_debug_memory (xdrs, XDR_DECODE, xdrvar, addr, (ULONG) len)
#define DEBUG_XDR_FREE(xdrvar, addr, len) \
xdr_debug_memory (xdrs, XDR_FREE, xdrvar, addr, (ULONG) len)
#else
#define P_TRUE TRUE
#define P_FALSE FALSE
#define DEBUG_XDR_PACKET
#define DEBUG_XDR_ALLOC(xdrvar, addr, len)
#define DEBUG_XDR_FREE(xdrvar, addr, len)
#endif /* DEBUG_XDR_MEMORY */
#define MAP(routine, ptr) if (!routine (xdrs, &ptr)) return P_FALSE;
#define MAX_OPAQUE 32768
typedef enum {
TYPE_IMMEDIATE,
TYPE_PREPARED
} SQL_STMT_TYPE;
2003-09-11 20:59:34 +02:00
static bool alloc_cstring(XDR *, CSTRING *);
2001-05-23 15:26:42 +02:00
static void free_cstring(XDR *, CSTRING *);
static RSR get_statement(XDR *, SSHORT);
static bool_t xdr_cstring(XDR*, CSTRING*);
static inline bool_t xdr_cstring_bpb(XDR*, CSTRING_CONST*);
2001-05-23 15:26:42 +02:00
static bool_t xdr_datum(XDR *, DSC *, BLOB_PTR *);
#ifdef DEBUG_XDR_MEMORY
2001-05-23 15:26:42 +02:00
static bool_t xdr_debug_packet(XDR *, enum xdr_op, PACKET *);
#endif
2001-05-23 15:26:42 +02:00
static bool_t xdr_longs(XDR *, CSTRING *);
2002-11-19 13:40:54 +01:00
static bool_t xdr_message(XDR *, REM_MSG, FMT);
static bool_t xdr_quad(XDR *, struct bid *);
2001-05-23 15:26:42 +02:00
static bool_t xdr_request(XDR *, USHORT, USHORT, USHORT);
#ifdef VMS
2002-11-19 13:40:54 +01:00
static bool_t xdr_semi_opaque(XDR *, REM_MSG, FMT);
2001-05-23 15:26:42 +02:00
static bool_t xdr_semi_opaque_slice(XDR *, LSTRING *);
#endif
static bool_t xdr_slice(XDR*, LSTRING*, USHORT, const UCHAR*);
2003-04-10 12:31:28 +02:00
static bool_t xdr_status_vector(XDR *, ISC_STATUS *, TEXT * strings[]);
2001-05-23 15:26:42 +02:00
static bool_t xdr_sql_blr(XDR *, SLONG, CSTRING *, int, SQL_STMT_TYPE);
static bool_t xdr_sql_message(XDR *, SLONG);
static bool_t xdr_trrq_blr(XDR *, CSTRING *);
static bool_t xdr_trrq_message(XDR *, USHORT);
#ifdef NOT_USED_OR_REPLACED
2001-05-23 15:26:42 +02:00
// TMN: Patched away this for now, it should probably be removed.
// Now why the ... would anyone want to define functions differently
// in an implementation file than they are defined in their header?!
bool_t xdr_enum();
bool_t xdr_short();
bool_t xdr_u_short();
bool_t xdr_long();
# ifdef SOLARIS
bool_t xdr_hyper();
# endif
bool_t xdr_opaque();
bool_t xdr_string();
bool_t xdr_float();
bool_t xdr_double();
bool_t xdr_wrapstring();
2001-05-23 15:26:42 +02:00
bool_t xdr_free();
2001-05-23 15:26:42 +02:00
#else // NOT_USED_OR_REPLACED
2001-05-23 15:26:42 +02:00
# include "../remote/xdr_proto.h"
#endif // NOT_USED_OR_REPLACED
2001-05-23 15:26:42 +02:00
#ifdef VMS
double MTH$CVT_D_G(), MTH$CVT_G_D();
2001-05-23 15:26:42 +02:00
static STR gfloat_buffer;
#endif
#ifdef DEBUG
static ULONG xdr_save_size = 0;
#define DEBUG_PRINTSIZE(p) ib_fprintf (ib_stderr, "xdr_protocol: %s op %d size %lu\n", \
2001-05-23 15:26:42 +02:00
((xdrs->x_op == XDR_FREE) ? "free" : \
(xdrs->x_op == XDR_ENCODE) ? "enc " : \
(xdrs->x_op == XDR_DECODE) ? "dec " : \
"othr"), \
(p), \
((xdrs->x_op == XDR_ENCODE) \
? (xdrs->x_handy - xdr_save_size) \
: (xdr_save_size - xdrs->x_handy)))
#endif
#ifndef DEBUG_PRINTSIZE
#define DEBUG_PRINTSIZE(p) /* nothing */
#endif
#ifdef DEBUG_XDR_MEMORY
void xdr_debug_memory(
XDR* xdrs,
2001-05-23 15:26:42 +02:00
enum xdr_op xop,
const void* xdrvar, const void* address, ULONG length)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* x d r _ d e b u g _ m e m o r y
*
**************************************
*
* Functional description
* Track memory allocation patterns of XDR aggregate
* types (i.e. xdr_cstring, xdr_string, etc.) to
* validate that memory is not leaked by overwriting
* XDR aggregate pointers and that freeing a packet
* with REMOTE_free_packet() does not miss anything.
*
* All memory allocations due to marshalling XDR
* variables are recorded in a debug memory alloca-
* tion table stored at the front of a packet.
*
* Once a packet is being tracked it is an assertion
* error if a memory allocation can not be recorded
* due to space limitations or if a previous memory
* allocation being freed cannot be found. At most
* P_MALLOC_SIZE entries can be stored in the memory
* allocation table. A rough estimate of the number
* of XDR aggregates that can hang off a packet can
* be obtained by examining the subpackets defined
* in <remote/protocol.h>: A guestimate of 36 at this
* time includes 10 strings used to decode an xdr
* status vector.
*
**************************************/
PORT port = (PORT) xdrs->x_public;
2003-11-04 00:59:24 +01:00
fb_assert(port != 0);
fb_assert(port->port_header.blk_type == type_port);
2001-05-23 15:26:42 +02:00
/* Compare the XDR variable address with the lower and upper bounds
of each packet to determine which packet contains it. Record or
delete an entry in that packet's memory allocation table. */
VEC vector = port->port_packet_vector;
if (!vector) /* Not tracking port's protocol */
2001-05-23 15:26:42 +02:00
return;
ULONG i;
2001-05-23 15:26:42 +02:00
for (i = 0; i < vector->vec_count; i++) {
PACKET* packet = (PACKET*) vector->vec_object[i];
if (packet) {
2003-11-04 00:59:24 +01:00
fb_assert(packet->p_operation > op_void
2001-05-23 15:26:42 +02:00
&& packet->p_operation < op_max);
if ((SCHAR *) xdrvar >= (SCHAR *) packet &&
(SCHAR *) xdrvar < (SCHAR *) packet + sizeof(PACKET)) {
ULONG j;
2001-05-23 15:26:42 +02:00
for (j = 0; j < P_MALLOC_SIZE; j++) {
if (xop == XDR_FREE) {
if ((SCHAR *) packet->p_malloc[j].p_address ==
(SCHAR *) address) {
packet->p_malloc[j].p_operation = op_void;
packet->p_malloc[j].p_allocated = NULL;
packet->p_malloc[j].p_address = 0;
/* packet->p_malloc [j].p_xdrvar = 0; */
return;
}
}
else { /* XDR_ENCODE or XDR_DECODE */
2003-11-04 00:59:24 +01:00
fb_assert(xop == XDR_ENCODE || xop == XDR_DECODE);
2001-05-23 15:26:42 +02:00
if (packet->p_malloc[j].p_operation == op_void) {
packet->p_malloc[j].p_operation =
packet->p_operation;
packet->p_malloc[j].p_allocated = length;
packet->p_malloc[j].p_address = address;
/* packet->p_malloc [j].p_xdrvar = xdrvar; */
return;
}
}
}
/* Assertion failure if not enough entries to record every xdr
memory allocation or an entry to be freed can't be found. */
2003-11-04 00:59:24 +01:00
fb_assert(j < P_MALLOC_SIZE); /* Increase P_MALLOC_SIZE if necessary */
2001-05-23 15:26:42 +02:00
}
}
}
2003-11-04 00:59:24 +01:00
fb_assert(i < vector->vec_count); /* Couldn't find packet for this xdr arg */
2001-05-23 15:26:42 +02:00
}
#endif
bool_t xdr_protocol(XDR* xdrs, PACKET* p)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* x d r _ p r o t o c o l
*
**************************************
*
* Functional description
* Encode, decode, or free a protocol packet.
*
**************************************/
USHORT i;
p_cnct::p_cnct_repeat * tail;
PORT port;
P_CNCT *connect;
P_ACPT *accept;
P_ATCH *attach;
P_RESP *response;
P_CMPL *compile;
P_STTR *transaction;
P_DATA *data;
P_RLSE *release;
P_BLOB *blob;
P_SGMT *segment;
P_INFO *info;
P_PREP *prepare;
P_EVENT *event;
P_REQ *request;
P_DDL *ddl;
P_SLC *slice;
P_SLR *slice_response;
P_SEEK *seek;
P_SQLFREE *free_stmt;
P_SQLCUR *sqlcur;
P_SQLST *prep_stmt;
P_SQLDATA *sqldata;
P_TRRQ *trrq;
#ifdef DEBUG
xdr_save_size = xdrs->x_handy;
#endif
DEBUG_XDR_PACKET;
if (!xdr_enum(xdrs, reinterpret_cast < xdr_op * >(&p->p_operation)))
2001-05-23 15:26:42 +02:00
return P_FALSE;
switch (p->p_operation) {
case op_reject:
case op_disconnect:
case op_dummy:
return P_TRUE;
case op_connect:
connect = &p->p_cnct;
MAP(xdr_enum,
reinterpret_cast < xdr_op & >(connect->p_cnct_operation));
2001-05-23 15:26:42 +02:00
MAP(xdr_short,
reinterpret_cast < SSHORT & >(connect->p_cnct_cversion));
MAP(xdr_enum, reinterpret_cast < xdr_op & >(connect->p_cnct_client));
2001-05-23 15:26:42 +02:00
MAP(xdr_cstring, connect->p_cnct_file);
MAP(xdr_short, reinterpret_cast < SSHORT & >(connect->p_cnct_count));
MAP(xdr_cstring, connect->p_cnct_user_id);
for (i = 0, tail = connect->p_cnct_versions;
i < connect->p_cnct_count; i++, tail++) {
MAP(xdr_short,
reinterpret_cast < SSHORT & >(tail->p_cnct_version));
MAP(xdr_enum,
reinterpret_cast < xdr_op & >(tail->p_cnct_architecture));
2001-05-23 15:26:42 +02:00
MAP(xdr_u_short, tail->p_cnct_min_type);
MAP(xdr_u_short, tail->p_cnct_max_type);
MAP(xdr_short,
reinterpret_cast < SSHORT & >(tail->p_cnct_weight));
}
DEBUG_PRINTSIZE(p->p_operation);
return P_TRUE;
case op_accept:
accept = &p->p_acpt;
MAP(xdr_short, reinterpret_cast < SSHORT & >(accept->p_acpt_version));
MAP(xdr_enum,
reinterpret_cast < xdr_op & >(accept->p_acpt_architecture));
2001-05-23 15:26:42 +02:00
MAP(xdr_u_short, accept->p_acpt_type);
DEBUG_PRINTSIZE(p->p_operation);
return P_TRUE;
case op_connect_request:
case op_aux_connect:
request = &p->p_req;
MAP(xdr_short, reinterpret_cast < SSHORT & >(request->p_req_type));
MAP(xdr_short, reinterpret_cast < SSHORT & >(request->p_req_object));
MAP(xdr_long, reinterpret_cast < SLONG & >(request->p_req_partner));
DEBUG_PRINTSIZE(p->p_operation);
return P_TRUE;
case op_attach:
case op_create:
case op_service_attach:
attach = &p->p_atch;
MAP(xdr_short,
reinterpret_cast < SSHORT & >(attach->p_atch_database));
MAP(xdr_cstring, attach->p_atch_file);
MAP(xdr_cstring, attach->p_atch_dpb);
DEBUG_PRINTSIZE(p->p_operation);
return P_TRUE;
case op_compile:
compile = &p->p_cmpl;
MAP(xdr_short,
reinterpret_cast < SSHORT & >(compile->p_cmpl_database));
MAP(xdr_cstring, compile->p_cmpl_blr);
DEBUG_PRINTSIZE(p->p_operation);
return P_TRUE;
case op_receive:
case op_start:
case op_start_and_receive:
data = &p->p_data;
MAP(xdr_short, reinterpret_cast < SSHORT & >(data->p_data_request));
MAP(xdr_short,
reinterpret_cast < SSHORT & >(data->p_data_incarnation));
MAP(xdr_short,
reinterpret_cast < SSHORT & >(data->p_data_transaction));
MAP(xdr_short,
reinterpret_cast < SSHORT & >(data->p_data_message_number));
MAP(xdr_short, reinterpret_cast < SSHORT & >(data->p_data_messages));
#ifdef SCROLLABLE_CURSORS
port = (PORT) xdrs->x_public;
if ((p->p_operation == op_receive) &&
(port->port_protocol > PROTOCOL_VERSION8)) {
MAP(xdr_short,
reinterpret_cast < SSHORT & >(data->p_data_direction));
MAP(xdr_long, data->p_data_offset);
}
#endif
DEBUG_PRINTSIZE(p->p_operation);
return P_TRUE;
case op_send:
case op_start_and_send:
case op_start_send_and_receive:
data = &p->p_data;
MAP(xdr_short, reinterpret_cast < SSHORT & >(data->p_data_request));
MAP(xdr_short,
reinterpret_cast < SSHORT & >(data->p_data_incarnation));
MAP(xdr_short,
reinterpret_cast < SSHORT & >(data->p_data_transaction));
MAP(xdr_short,
reinterpret_cast < SSHORT & >(data->p_data_message_number));
MAP(xdr_short, reinterpret_cast < SSHORT & >(data->p_data_messages));
/* Changes to this op's protocol must mirror in xdr_protocol_overhead */
return xdr_request(xdrs, data->p_data_request,
data->p_data_message_number,
data->p_data_incarnation) ? P_TRUE : P_FALSE;
case op_response:
case op_response_piggyback:
2002-02-16 04:27:33 +01:00
/* Changes to this op's protocol must be mirrored
2001-05-23 15:26:42 +02:00
in xdr_protocol_overhead */
response = &p->p_resp;
MAP(xdr_short,
reinterpret_cast < SSHORT & >(response->p_resp_object));
MAP(xdr_quad, response->p_resp_blob_id);
MAP(xdr_cstring, response->p_resp_data);
return xdr_status_vector(xdrs, response->p_resp_status_vector,
reinterpret_cast <
char **>(response->
p_resp_strings)) ? P_TRUE : P_FALSE;
case op_transact:
trrq = &p->p_trrq;
MAP(xdr_short, reinterpret_cast < SSHORT & >(trrq->p_trrq_database));
MAP(xdr_short,
reinterpret_cast < SSHORT & >(trrq->p_trrq_transaction));
xdr_trrq_blr(xdrs, &trrq->p_trrq_blr);
MAP(xdr_cstring, trrq->p_trrq_blr);
MAP(xdr_short, reinterpret_cast < SSHORT & >(trrq->p_trrq_messages));
if (trrq->p_trrq_messages)
return xdr_trrq_message(xdrs, 0) ? P_TRUE : P_FALSE;
DEBUG_PRINTSIZE(p->p_operation);
return P_TRUE;
case op_transact_response:
data = &p->p_data;
MAP(xdr_short, reinterpret_cast < SSHORT & >(data->p_data_messages));
if (data->p_data_messages)
return xdr_trrq_message(xdrs, 1) ? P_TRUE : P_FALSE;
DEBUG_PRINTSIZE(p->p_operation);
return P_TRUE;
case op_open_blob2:
case op_create_blob2:
blob = &p->p_blob;
MAP(xdr_cstring_bpb, blob->p_blob_bpb);
// fall into:
2001-05-23 15:26:42 +02:00
case op_open_blob:
case op_create_blob:
blob = &p->p_blob;
MAP(xdr_short,
reinterpret_cast < SSHORT & >(blob->p_blob_transaction));
MAP(xdr_quad, blob->p_blob_id);
DEBUG_PRINTSIZE(p->p_operation);
return P_TRUE;
case op_get_segment:
case op_put_segment:
case op_batch_segments:
segment = &p->p_sgmt;
MAP(xdr_short, reinterpret_cast < SSHORT & >(segment->p_sgmt_blob));
MAP(xdr_short, reinterpret_cast < SSHORT & >(segment->p_sgmt_length));
MAP(xdr_cstring_bpb, segment->p_sgmt_segment);
2001-05-23 15:26:42 +02:00
DEBUG_PRINTSIZE(p->p_operation);
return P_TRUE;
case op_seek_blob:
seek = &p->p_seek;
MAP(xdr_short, reinterpret_cast < SSHORT & >(seek->p_seek_blob));
MAP(xdr_short, reinterpret_cast < SSHORT & >(seek->p_seek_mode));
MAP(xdr_long, seek->p_seek_offset);
DEBUG_PRINTSIZE(p->p_operation);
return P_TRUE;
case op_reconnect:
case op_transaction:
transaction = &p->p_sttr;
MAP(xdr_short,
reinterpret_cast < SSHORT & >(transaction->p_sttr_database));
MAP(xdr_cstring, transaction->p_sttr_tpb);
DEBUG_PRINTSIZE(p->p_operation);
return P_TRUE;
case op_info_blob:
case op_info_database:
case op_info_request:
case op_info_transaction:
case op_service_info:
case op_info_sql:
info = &p->p_info;
MAP(xdr_short, reinterpret_cast < SSHORT & >(info->p_info_object));
MAP(xdr_short,
reinterpret_cast < SSHORT & >(info->p_info_incarnation));
MAP(xdr_cstring, info->p_info_items);
if (p->p_operation == op_service_info)
MAP(xdr_cstring, info->p_info_recv_items);
MAP(xdr_short,
reinterpret_cast < SSHORT & >(info->p_info_buffer_length));
DEBUG_PRINTSIZE(p->p_operation);
return P_TRUE;
case op_service_start:
info = &p->p_info;
MAP(xdr_short, reinterpret_cast < SSHORT & >(info->p_info_object));
MAP(xdr_short,
reinterpret_cast < SSHORT & >(info->p_info_incarnation));
MAP(xdr_cstring, info->p_info_items);
DEBUG_PRINTSIZE(p->p_operation);
return P_TRUE;
case op_commit:
case op_prepare:
case op_rollback:
case op_unwind:
case op_release:
case op_close_blob:
case op_cancel_blob:
case op_detach:
case op_drop_database:
case op_service_detach:
case op_commit_retaining:
case op_rollback_retaining:
case op_allocate_statement:
release = &p->p_rlse;
MAP(xdr_short, reinterpret_cast < SSHORT & >(release->p_rlse_object));
DEBUG_PRINTSIZE(p->p_operation);
return P_TRUE;
case op_prepare2:
prepare = &p->p_prep;
MAP(xdr_short,
reinterpret_cast < SSHORT & >(prepare->p_prep_transaction));
MAP(xdr_cstring, prepare->p_prep_data);
DEBUG_PRINTSIZE(p->p_operation);
return P_TRUE;
case op_que_events:
case op_event:
event = &p->p_event;
MAP(xdr_short,
reinterpret_cast < SSHORT & >(event->p_event_database));
MAP(xdr_cstring, event->p_event_items);
MAP(xdr_long, event->p_event_ast);
MAP(xdr_long, event->p_event_arg);
MAP(xdr_long, event->p_event_rid);
DEBUG_PRINTSIZE(p->p_operation);
return P_TRUE;
case op_cancel_events:
event = &p->p_event;
MAP(xdr_short,
reinterpret_cast < SSHORT & >(event->p_event_database));
MAP(xdr_long, event->p_event_rid);
DEBUG_PRINTSIZE(p->p_operation);
return P_TRUE;
case op_ddl:
ddl = &p->p_ddl;
MAP(xdr_short, reinterpret_cast < SSHORT & >(ddl->p_ddl_database));
MAP(xdr_short, reinterpret_cast < SSHORT & >(ddl->p_ddl_transaction));
MAP(xdr_cstring, ddl->p_ddl_blr);
DEBUG_PRINTSIZE(p->p_operation);
return P_TRUE;
case op_get_slice:
case op_put_slice:
slice = &p->p_slc;
MAP(xdr_short,
reinterpret_cast < SSHORT & >(slice->p_slc_transaction));
MAP(xdr_quad, slice->p_slc_id);
MAP(xdr_long, reinterpret_cast < SLONG & >(slice->p_slc_length));
MAP(xdr_cstring, slice->p_slc_sdl);
MAP(xdr_longs, slice->p_slc_parameters);
slice_response = &p->p_slr;
if (slice_response->p_slr_sdl) {
if (!xdr_slice(xdrs, &slice->p_slc_slice,
slice_response->p_slr_sdl_length,
slice_response->p_slr_sdl)) return P_FALSE;
}
else
if (!xdr_slice(xdrs, &slice->p_slc_slice,
slice->p_slc_sdl.cstr_length,
2003-08-15 12:23:46 +02:00
slice->p_slc_sdl.cstr_address)) return P_FALSE;
2001-05-23 15:26:42 +02:00
DEBUG_PRINTSIZE(p->p_operation);
return P_TRUE;
case op_slice:
slice_response = &p->p_slr;
MAP(xdr_long,
reinterpret_cast < SLONG & >(slice_response->p_slr_length));
if (!xdr_slice
(xdrs, &slice_response->p_slr_slice,
slice_response->p_slr_sdl_length,
slice_response->p_slr_sdl)) return P_FALSE;
DEBUG_PRINTSIZE(p->p_operation);
return P_TRUE;
case op_execute:
case op_execute2:
sqldata = &p->p_sqldata;
MAP(xdr_short,
reinterpret_cast < SSHORT & >(sqldata->p_sqldata_statement));
MAP(xdr_short,
reinterpret_cast < SSHORT & >(sqldata->p_sqldata_transaction));
if (xdrs->x_op == XDR_DECODE) {
2002-02-16 04:27:33 +01:00
/* the statement should be reset for each execution so that
all prefetched information from a prior execute is properly
cleared out. This should be done before fetching any message
2001-05-23 15:26:42 +02:00
information (for example: blr info)
*/
RSR statement = NULL;
statement = get_statement(xdrs, sqldata->p_sqldata_statement);
if (statement)
REMOTE_reset_statement(statement);
}
xdr_sql_blr(xdrs, (SLONG) sqldata->p_sqldata_statement,
&sqldata->p_sqldata_blr, FALSE, TYPE_PREPARED);
MAP(xdr_short,
reinterpret_cast < SSHORT & >(sqldata->p_sqldata_message_number));
MAP(xdr_short,
reinterpret_cast < SSHORT & >(sqldata->p_sqldata_messages));
if (sqldata->p_sqldata_messages) {
if (!xdr_sql_message(xdrs, (SLONG) sqldata->p_sqldata_statement))
return P_FALSE;
}
if (p->p_operation == op_execute2) {
xdr_sql_blr(xdrs, (SLONG) - 1, &sqldata->p_sqldata_out_blr, TRUE,
TYPE_PREPARED);
MAP(xdr_short,
reinterpret_cast <
SSHORT & >(sqldata->p_sqldata_out_message_number));
}
DEBUG_PRINTSIZE(p->p_operation);
return P_TRUE;
case op_exec_immediate2:
prep_stmt = &p->p_sqlst;
xdr_sql_blr(xdrs, (SLONG) - 1, &prep_stmt->p_sqlst_blr, FALSE,
TYPE_IMMEDIATE);
MAP(xdr_short,
reinterpret_cast < SSHORT & >(prep_stmt->p_sqlst_message_number));
MAP(xdr_short,
reinterpret_cast < SSHORT & >(prep_stmt->p_sqlst_messages));
if (prep_stmt->p_sqlst_messages) {
if (!xdr_sql_message(xdrs, (SLONG) - 1))
return P_FALSE;
}
xdr_sql_blr(xdrs, (SLONG) - 1, &prep_stmt->p_sqlst_out_blr, TRUE,
TYPE_IMMEDIATE);
MAP(xdr_short,
reinterpret_cast <
SSHORT & >(prep_stmt->p_sqlst_out_message_number));
/* Fall into ... */
case op_exec_immediate:
case op_prepare_statement:
prep_stmt = &p->p_sqlst;
MAP(xdr_short,
reinterpret_cast < SSHORT & >(prep_stmt->p_sqlst_transaction));
MAP(xdr_short,
reinterpret_cast < SSHORT & >(prep_stmt->p_sqlst_statement));
MAP(xdr_short,
reinterpret_cast < SSHORT & >(prep_stmt->p_sqlst_SQL_dialect));
MAP(xdr_cstring, prep_stmt->p_sqlst_SQL_str);
MAP(xdr_cstring, prep_stmt->p_sqlst_items);
MAP(xdr_short,
reinterpret_cast < SSHORT & >(prep_stmt->p_sqlst_buffer_length));
DEBUG_PRINTSIZE(p->p_operation);
return P_TRUE;
case op_fetch:
sqldata = &p->p_sqldata;
MAP(xdr_short,
reinterpret_cast < SSHORT & >(sqldata->p_sqldata_statement));
xdr_sql_blr(xdrs, (SLONG) sqldata->p_sqldata_statement,
&sqldata->p_sqldata_blr, TRUE, TYPE_PREPARED);
MAP(xdr_short,
reinterpret_cast < SSHORT & >(sqldata->p_sqldata_message_number));
MAP(xdr_short,
reinterpret_cast < SSHORT & >(sqldata->p_sqldata_messages));
DEBUG_PRINTSIZE(p->p_operation);
return P_TRUE;
case op_fetch_response:
sqldata = &p->p_sqldata;
MAP(xdr_long,
reinterpret_cast < SLONG & >(sqldata->p_sqldata_status));
MAP(xdr_short,
reinterpret_cast < SSHORT & >(sqldata->p_sqldata_messages));
/* Changes to this op's protocol must mirror in xdr_protocol_overhead */
port = (PORT) xdrs->x_public;
if (
(port->port_protocol > PROTOCOL_VERSION7
&& sqldata->p_sqldata_messages)
|| (port->port_protocol <= PROTOCOL_VERSION7
&& !sqldata->p_sqldata_status)) return xdr_sql_message(xdrs,
(SLONG)
sqldata->
p_sqldata_statement)
? P_TRUE : P_FALSE;
DEBUG_PRINTSIZE(p->p_operation);
return P_TRUE;
case op_free_statement:
free_stmt = &p->p_sqlfree;
MAP(xdr_short,
reinterpret_cast < SSHORT & >(free_stmt->p_sqlfree_statement));
MAP(xdr_short,
reinterpret_cast < SSHORT & >(free_stmt->p_sqlfree_option));
DEBUG_PRINTSIZE(p->p_operation);
return P_TRUE;
case op_insert:
sqldata = &p->p_sqldata;
MAP(xdr_short,
reinterpret_cast < SSHORT & >(sqldata->p_sqldata_statement));
xdr_sql_blr(xdrs, (SLONG) sqldata->p_sqldata_statement,
&sqldata->p_sqldata_blr, FALSE, TYPE_PREPARED);
MAP(xdr_short,
reinterpret_cast < SSHORT & >(sqldata->p_sqldata_message_number));
MAP(xdr_short,
reinterpret_cast < SSHORT & >(sqldata->p_sqldata_messages));
if (sqldata->p_sqldata_messages)
return xdr_sql_message(xdrs,
(SLONG) sqldata->
p_sqldata_statement) ? P_TRUE : P_FALSE;
DEBUG_PRINTSIZE(p->p_operation);
return P_TRUE;
case op_set_cursor:
sqlcur = &p->p_sqlcur;
MAP(xdr_short,
reinterpret_cast < SSHORT & >(sqlcur->p_sqlcur_statement));
MAP(xdr_cstring, sqlcur->p_sqlcur_cursor_name);
MAP(xdr_short, reinterpret_cast < SSHORT & >(sqlcur->p_sqlcur_type));
DEBUG_PRINTSIZE(p->p_operation);
return P_TRUE;
case op_sql_response:
sqldata = &p->p_sqldata;
MAP(xdr_short,
reinterpret_cast < SSHORT & >(sqldata->p_sqldata_messages));
if (sqldata->p_sqldata_messages)
return xdr_sql_message(xdrs, (SLONG) - 1) ? P_TRUE : P_FALSE;
DEBUG_PRINTSIZE(p->p_operation);
return P_TRUE;
default:
#ifdef DEBUG
if (xdrs->x_op != XDR_FREE)
ib_fprintf(ib_stderr, "xdr_packet: operation %d not recognized\n",
p->p_operation);
#endif
2003-11-04 00:59:24 +01:00
fb_assert(xdrs->x_op == XDR_FREE);
2001-05-23 15:26:42 +02:00
return P_FALSE;
}
}
ULONG xdr_protocol_overhead(P_OP op)
{
/**************************************
*
* x d r _ p r o t o c o l _ o v e r h e a d
*
**************************************
*
* Functional description
* Report the overhead size of a particular packet.
* NOTE: This is not the same as the actual size to
* send the packet - as this figure discounts any data
* to be sent with the packet. It's purpose is to figure
* overhead for deciding on a batching window count.
*
* A better version of this routine would use xdr_sizeof - but
* it is unknown how portable that Solaris call is to other
* OS.
*
**************************************/
ULONG size = 4 /* xdr_sizeof (xdr_enum, p->p_operation) */ ;
2001-05-23 15:26:42 +02:00
switch (op) {
case op_fetch_response:
size += 4 /* xdr_sizeof (xdr_long, sqldata->p_sqldata_status) */
+ 4 /* xdr_sizeof (xdr_short, sqldata->p_sqldata_messages) */ ;
break;
case op_send:
case op_start_and_send:
case op_start_send_and_receive:
size += 4 /* xdr_sizeof (xdr_short, data->p_data_request) */
+ 4 /* xdr_sizeof (xdr_short, data->p_data_incarnation) */
+ 4 /* xdr_sizeof (xdr_short, data->p_data_transaction) */
+ 4 /* xdr_sizeof (xdr_short, data->p_data_message_number) */
+ 4 /* xdr_sizeof (xdr_short, data->p_data_messages) */ ;
break;
case op_response:
case op_response_piggyback:
/* Note: minimal amounts are used for cstring & status_vector */
size += 4 /* xdr_sizeof (xdr_short, response->p_resp_object) */
+ 8 /* xdr_sizeof (xdr_quad, response->p_resp_blob_id) */
+ 4 /* xdr_sizeof (xdr_cstring, response->p_resp_data) */
+
3 *
4
/* xdr_sizeof (xdr_status_vector (xdrs, response->p_resp_status_vector */
;
break;
default:
2003-11-04 00:59:24 +01:00
fb_assert(FALSE); /* Not supported operation */
2001-05-23 15:26:42 +02:00
return 0;
}
return size;
}
static bool alloc_cstring(XDR* xdrs,
CSTRING* cstring)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* a l l o c _ c s t r i n g
*
**************************************
*
* Functional description
* Handle allocation for cstring.
*
**************************************/
if (!cstring->cstr_length)
2003-09-11 20:59:34 +02:00
return true;
2001-05-23 15:26:42 +02:00
if (cstring->cstr_length > cstring->cstr_allocated &&
cstring->cstr_allocated)
{
free_cstring(xdrs, cstring);
}
2001-05-23 15:26:42 +02:00
if (!cstring->cstr_address) {
2003-11-04 00:59:24 +01:00
// fb_assert(!cstring->cstr_allocated);
2001-05-23 15:26:42 +02:00
if (!
(cstring->cstr_address =
ALLR_alloc((SLONG) cstring->cstr_length)))
{
2001-05-23 15:26:42 +02:00
/* NOMEM: handled by ALLR_alloc() */
/* FREE: in realloc case above & free_cstring() */
2003-09-11 20:59:34 +02:00
return false;
}
2001-05-23 15:26:42 +02:00
cstring->cstr_allocated = cstring->cstr_length;
DEBUG_XDR_ALLOC(cstring, cstring->cstr_address,
cstring->cstr_allocated);
}
2003-09-11 20:59:34 +02:00
return true;
2001-05-23 15:26:42 +02:00
}
static void free_cstring( XDR* xdrs, CSTRING* cstring)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* f r e e _ c s t r i n g
*
**************************************
*
* Functional description
* Free any memory allocated for a cstring.
*
**************************************/
if (cstring->cstr_allocated) {
ALLR_free(cstring->cstr_address);
DEBUG_XDR_FREE(cstring, cstring->cstr_address,
cstring->cstr_allocated);
}
cstring->cstr_address = NULL;
cstring->cstr_allocated = 0;
}
// CVC: This function is a little stub to validate that indeed, bpb's aren't
// overwritten by accident. Even though xdr_string writes to cstr_address,
// an action we wanted to block, it first allocates a new buffer.
// The problem is that bpb's aren't copied, but referenced by address, so we
// don't want a const param being hijacked and its memory location overwritten.
// The same test has been applied to put_segment and batch_segments operations.
// The layout of CSTRING and CSTRING_CONST is exactly the same.
// Changing CSTRING to use cstr_address as const pointer would upset other
// places of the code, so only P_BLOB was changed to use CSTRING_CONST.
static inline bool_t xdr_cstring_bpb(XDR* xdrs, CSTRING_CONST* cstring)
{
#ifdef SUPERCLIENT
#ifdef DEV_BUILD
const bool cond =
!(xdrs->x_op == XDR_DECODE &&
cstring->cstr_length <= cstring->cstr_allocated
&& cstring->cstr_allocated);
2003-11-04 00:59:24 +01:00
fb_assert(cond);
#endif
#endif
return xdr_cstring(xdrs, reinterpret_cast<CSTRING*>(cstring));
}
static bool_t xdr_cstring( XDR* xdrs, CSTRING* cstring)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* x d r _ c s t r i n g
*
**************************************
*
* Functional description
* Map a counted string structure.
*
**************************************/
SLONG l;
SCHAR trash[4];
2003-02-13 10:33:26 +01:00
static const SCHAR filler[4] = { 0, 0, 0, 0 };
2001-05-23 15:26:42 +02:00
if (!xdr_short
(xdrs,
reinterpret_cast < SSHORT * >(&cstring->cstr_length)))
{
return FALSE;
}
2001-05-23 15:26:42 +02:00
switch (xdrs->x_op) {
case XDR_ENCODE:
if (cstring->cstr_length &&
!(*xdrs->x_ops->x_putbytes) (xdrs,
reinterpret_cast <
const SCHAR* >(cstring->cstr_address),
cstring->cstr_length))
{
return FALSE;
}
2001-05-23 15:26:42 +02:00
l = (4 - cstring->cstr_length) & 3;
if (l)
return (*xdrs->x_ops->x_putbytes) (xdrs,
filler,
2001-05-23 15:26:42 +02:00
l);
{
return TRUE;
}
2001-05-23 15:26:42 +02:00
case XDR_DECODE:
if (!alloc_cstring(xdrs, cstring))
return FALSE;
if (!(*xdrs->x_ops->x_getbytes)
(xdrs, reinterpret_cast < SCHAR * >(cstring->cstr_address),
cstring->cstr_length))
{
return FALSE;
}
2001-05-23 15:26:42 +02:00
l = (4 - cstring->cstr_length) & 3;
if (l)
return (*xdrs->x_ops->x_getbytes) (xdrs, trash, l);
return TRUE;
case XDR_FREE:
free_cstring(xdrs, cstring);
return TRUE;
}
return FALSE;
}
static bool_t xdr_datum( XDR* xdrs, DSC* desc, BLOB_PTR* buffer)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* x d r _ d a t u m
*
**************************************
*
* Functional description
* Handle a data item by relative descriptor and buffer.
*
**************************************/
SSHORT n;
BLOB_PTR* p = buffer + (ULONG) desc->dsc_address;
2001-05-23 15:26:42 +02:00
switch (desc->dsc_dtype) {
case dtype_text:
if (!xdr_opaque
(xdrs, reinterpret_cast < SCHAR * >(p),
desc->dsc_length)) return FALSE;
break;
case dtype_varying:
2003-11-04 00:59:24 +01:00
fb_assert(desc->dsc_length >= sizeof(USHORT));
if (!xdr_short(xdrs,
reinterpret_cast<SSHORT*>(&((vary*) p)->vary_length)))
{
return FALSE;
}
if (!xdr_opaque(xdrs,
reinterpret_cast<SCHAR*>(((vary*) p)->vary_string),
MIN((USHORT) (desc->dsc_length - 2), ((vary*) p)->vary_length)))
{
2001-05-23 15:26:42 +02:00
return FALSE;
}
2001-05-23 15:26:42 +02:00
break;
case dtype_cstring:
if (xdrs->x_op == XDR_ENCODE)
n =
MIN(strlen(reinterpret_cast < char *>(p)),
(ULONG) (desc->dsc_length - 1));
if (!xdr_short(xdrs, &n))
return FALSE;
if (!xdr_opaque(xdrs, reinterpret_cast < SCHAR * >(p), n))
return FALSE;
if (xdrs->x_op == XDR_DECODE)
p[n] = 0;
break;
case dtype_short:
2003-11-04 00:59:24 +01:00
fb_assert(desc->dsc_length >= sizeof(SSHORT));
2001-05-23 15:26:42 +02:00
if (!xdr_short(xdrs, reinterpret_cast < SSHORT * >(p)))
return FALSE;
break;
case dtype_sql_time:
case dtype_sql_date:
case dtype_long:
2003-11-04 00:59:24 +01:00
fb_assert(desc->dsc_length >= sizeof(SLONG));
2001-05-23 15:26:42 +02:00
if (!xdr_long(xdrs, reinterpret_cast < SLONG * >(p)))
return FALSE;
break;
case dtype_real:
2003-11-04 00:59:24 +01:00
fb_assert(desc->dsc_length >= sizeof(float));
2001-05-23 15:26:42 +02:00
if (!xdr_float(xdrs, reinterpret_cast < float *>(p)))
return FALSE;
break;
case dtype_double:
2003-11-04 00:59:24 +01:00
fb_assert(desc->dsc_length >= sizeof(double));
2001-05-23 15:26:42 +02:00
if (!xdr_double(xdrs, reinterpret_cast < double *>(p)))
return FALSE;
break;
#ifdef VMS
case dtype_d_float:
2003-11-04 00:59:24 +01:00
fb_assert(desc->dsc_length >= sizeof(d_float));
2001-05-23 15:26:42 +02:00
if (!xdr_d_float(xdrs, p))
return FALSE;
break;
#endif
case dtype_timestamp:
2003-11-04 00:59:24 +01:00
fb_assert(desc->dsc_length >= 2 * sizeof(SLONG));
2001-05-23 15:26:42 +02:00
if (!xdr_long(xdrs, &((SLONG *) p)[0]))
return FALSE;
if (!xdr_long(xdrs, &((SLONG *) p)[1]))
return FALSE;
break;
case dtype_int64:
2003-11-04 00:59:24 +01:00
fb_assert(desc->dsc_length >= sizeof(SINT64));
2001-05-23 15:26:42 +02:00
if (!xdr_hyper(xdrs, (SINT64 *) p))
return FALSE;
break;
case dtype_array:
case dtype_quad:
case dtype_blob:
2003-11-04 00:59:24 +01:00
fb_assert(desc->dsc_length >= sizeof(struct bid));
2001-05-23 15:26:42 +02:00
if (!xdr_quad(xdrs, (struct bid *) p))
return FALSE;
break;
default:
2003-11-04 00:59:24 +01:00
fb_assert(FALSE);
2001-05-23 15:26:42 +02:00
return FALSE;
}
return TRUE;
}
#ifdef DEBUG_XDR_MEMORY
static bool_t xdr_debug_packet( XDR* xdrs, enum xdr_op xop, PACKET* packet)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* x d r _ d e b u g _ p a c k e t
*
**************************************
*
* Functional description
* Start/stop monitoring a packet's memory allocations by
* entering/removing from a port's packet tracking vector.
*
**************************************/
ULONG i;
PORT port = (PORT) xdrs->x_public;
2003-11-04 00:59:24 +01:00
fb_assert(port != 0);
fb_assert(port->port_header.blk_type == type_port);
2001-05-23 15:26:42 +02:00
if (xop == XDR_FREE) {
/* Free a slot in the packet tracking vector */
VEC vector = port->port_packet_vector;
if (vector)
2001-05-23 15:26:42 +02:00
for (i = 0; i < vector->vec_count; i++)
if (vector->vec_object[i] == (BLK) packet) {
vector->vec_object[i] = 0;
return TRUE;
}
}
else { /* XDR_ENCODE or XDR_DECODE */
/* Allocate an unused slot in the packet tracking vector
to start recording memory allocations for this packet. */
2003-11-04 00:59:24 +01:00
fb_assert(xop == XDR_ENCODE || xop == XDR_DECODE);
VEC vector = ALLR_vector(&port->port_packet_vector, 0);
2001-05-23 15:26:42 +02:00
for (i = 0; i < vector->vec_count; i++)
if (vector->vec_object[i] == (BLK) packet)
return TRUE;
for (i = 0; i < vector->vec_count; i++)
if (vector->vec_object[i] == 0)
break;
if (i >= vector->vec_count)
vector = ALLR_vector(&port->port_packet_vector, i);
vector->vec_object[i] = (BLK) packet;
}
return TRUE;
}
#endif
static bool_t xdr_longs( XDR* xdrs, CSTRING* cstring)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* x d r _ l o n g s
*
**************************************
*
* Functional description
* Pass a vector of longs.
*
**************************************/
if (!xdr_short
(xdrs,
reinterpret_cast < SSHORT * >(&cstring->cstr_length)))
{
return FALSE;
}
2001-05-23 15:26:42 +02:00
/* Handle operation specific stuff, particularly memory allocation/deallocation */
switch (xdrs->x_op) {
case XDR_ENCODE:
break;
case XDR_DECODE:
if (!alloc_cstring(xdrs, cstring))
return FALSE;
break;
case XDR_FREE:
free_cstring(xdrs, cstring);
return TRUE;
}
const ULONG n = cstring->cstr_length / sizeof(SLONG);
2001-05-23 15:26:42 +02:00
SLONG* next = (SLONG*) cstring->cstr_address;
for (const SLONG* const end = next + (int) n; next < end; next++)
{
2001-05-23 15:26:42 +02:00
if (!xdr_long(xdrs, next))
return FALSE;
}
2001-05-23 15:26:42 +02:00
return TRUE;
}
static bool_t xdr_message( XDR* xdrs, REM_MSG message, FMT format)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* x d r _ m e s s a g e
*
**************************************
*
* Functional description
* Map a formatted message.
*
**************************************/
if (xdrs->x_op == XDR_FREE)
return TRUE;
PORT port = (PORT) xdrs->x_public;
2001-05-23 15:26:42 +02:00
/* If we are running a symmetric version of the protocol, just slop
the bits and don't sweat the translations */
if (port->port_flags & PORT_symmetric)
#ifndef VMS
return xdr_opaque(xdrs,
reinterpret_cast < SCHAR * >(message->msg_address),
format->fmt_length);
#else
if (port->port_protocol >= PROTOCOL_VERSION5)
return xdr_opaque(xdrs, message->msg_address, format->fmt_length);
else
return xdr_semi_opaque(xdrs, message, format);
#endif
dsc* desc = format->fmt_desc;
for (const dsc* const end = desc + format->fmt_count; desc < end; ++desc)
2001-05-23 15:26:42 +02:00
if (!xdr_datum(xdrs, desc, message->msg_address))
return FALSE;
DEBUG_PRINTSIZE(0);
return TRUE;
}
static bool_t xdr_quad( XDR* xdrs, struct bid* ip)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* x d r _ q u a d
*
**************************************
*
* Functional description
* Map from external to internal representation (or vice versa).
* A "quad" is represented by two longs.
* Currently used only for blobs
*
**************************************/
switch (xdrs->x_op) {
case XDR_ENCODE:
if ((*xdrs->x_ops->x_putlong)
(xdrs, reinterpret_cast < SLONG * >(&ip->bid_relation_id))
&& (*xdrs->x_ops->x_putlong) (xdrs,
reinterpret_cast <
SLONG *
>(&ip->bid_number)))
{
return TRUE;
}
2001-05-23 15:26:42 +02:00
return FALSE;
case XDR_DECODE:
if (!(*xdrs->x_ops->x_getlong)
(xdrs,
reinterpret_cast <
SLONG * >(&ip->bid_relation_id)))
{
return FALSE;
}
2001-05-23 15:26:42 +02:00
return (*xdrs->x_ops->x_getlong) (xdrs,
reinterpret_cast <
SLONG * >(&ip->bid_number));
case XDR_FREE:
return TRUE;
}
return FALSE;
}
static bool_t xdr_request(
XDR* xdrs,
2001-05-23 15:26:42 +02:00
USHORT request_id,
USHORT message_number, USHORT incarnation)
{
/**************************************
*
* x d r _ r e q u e s t
*
**************************************
*
* Functional description
* Map a formatted message.
*
**************************************/
if (xdrs->x_op == XDR_FREE)
return TRUE;
PORT port = (PORT) xdrs->x_public;
RRQ request = (RRQ) port->port_objects[request_id];
2001-05-23 15:26:42 +02:00
if (!request)
return FALSE;
if (incarnation && !(request = REMOTE_find_request(request, incarnation)))
return FALSE;
rrq::rrq_repeat* tail = &request->rrq_rpt[message_number];
2001-05-23 15:26:42 +02:00
REM_MSG message = tail->rrq_xdr;
if (!message)
2001-05-23 15:26:42 +02:00
return FALSE;
tail->rrq_xdr = message->msg_next;
FMT format = tail->rrq_format;
2001-05-23 15:26:42 +02:00
/* Find the address of the record */
if (!message->msg_address)
message->msg_address = message->msg_buffer;
return xdr_message(xdrs, message, format);
}
#ifdef VMS
static bool_t xdr_semi_opaque( XDR* xdrs, REM_MSG message, FMT format)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* x d r _ s e m i _ o p a q u e
*
**************************************
*
* Functional description
* Move data while checking for doubles in d_float format.
*
**************************************/
DSC *desc, *end;
BLOB_PTR *msg_address;
double *convert;
switch (xdrs->x_op) {
case XDR_ENCODE:
for (desc = format->fmt_desc, end = desc + format->fmt_count;
desc < end; desc++)
if (desc->dsc_dtype == dtype_d_float)
break;
if (desc >= end)
return xdr_opaque(xdrs, message->msg_address, format->fmt_length);
if (!gfloat_buffer || gfloat_buffer->str_length < format->fmt_length) {
if (gfloat_buffer)
ALLR_free(gfloat_buffer);
gfloat_buffer = (STR) ALLOCV(type_str, format->fmt_length);
gfloat_buffer->str_length = format->fmt_length;
}
msg_address = gfloat_buffer->str_data;
memcpy(msg_address, message->msg_address, format->fmt_length);
for (desc = format->fmt_desc, end = desc + format->fmt_count;
desc < end; desc++)
if (desc->dsc_dtype == dtype_d_float) {
convert = (double *) (msg_address + (int) desc->dsc_address);
*convert = MTH$CVT_D_G(convert);
}
return xdr_opaque(xdrs, msg_address, format->fmt_length);
case XDR_DECODE:
if (!xdr_opaque(xdrs, message->msg_address, format->fmt_length))
return FALSE;
for (desc = format->fmt_desc, end = desc + format->fmt_count;
desc < end; desc++)
if (desc->dsc_dtype == dtype_d_float) {
convert =
(double *) (message->msg_address +
(int) desc->dsc_address);
*convert = MTH$CVT_G_D(convert);
}
return TRUE;
case XDR_FREE:
return TRUE;
}
2002-07-06 07:32:02 +02:00
return FALSE;
2001-05-23 15:26:42 +02:00
}
#endif
#ifdef VMS
static bool_t xdr_semi_opaque_slice( XDR* xdrs, LSTRING* slice)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* x d r _ s e m i _ o p a q u e _ s l i c e
*
**************************************
*
* Functional description
* Move data while converting for doubles in d_float format.
*
**************************************/
ULONG msg_len;
2001-05-23 15:26:42 +02:00
BLOB_PTR* p = slice->lstr_address;
for (ULONG n = slice->lstr_length; n; n -= msg_len, p += msg_len) {
2001-05-23 15:26:42 +02:00
msg_len = MIN(n, MAX_OPAQUE);
BLOB_PTR* msg_addr;
2001-05-23 15:26:42 +02:00
if (xdrs->x_op == XDR_ENCODE) {
/* Using an str structure is fine as long as MAX_OPAQUE < 64K */
if (!gfloat_buffer || gfloat_buffer->str_length < msg_len) {
if (gfloat_buffer)
ALLR_free(gfloat_buffer);
gfloat_buffer = (STR) ALLOCV(type_str, msg_len);
gfloat_buffer->str_length = msg_len;
}
msg_addr = gfloat_buffer->str_data;
memcpy(msg_addr, p, msg_len);
double* convert = (double*) msg_addr;
for (double* const end = (double*) (msg_addr + msg_len);
convert < end; ++convert)
{
2001-05-23 15:26:42 +02:00
*convert = MTH$CVT_D_G(convert);
}
2001-05-23 15:26:42 +02:00
}
else
msg_addr = p;
if (!xdr_opaque(xdrs, msg_addr, msg_len))
return FALSE;
if (xdrs->x_op == XDR_DECODE) {
double* convert = (double*) msg_addr
for (double* const end = (double*) (msg_addr + msg_len);
convert < end; ++convert)
{
2001-05-23 15:26:42 +02:00
*convert = MTH$CVT_G_D(convert);
}
2001-05-23 15:26:42 +02:00
}
}
return TRUE;
}
#endif
static bool_t xdr_slice(
XDR* xdrs,
LSTRING* slice, USHORT sdl_length, const UCHAR* sdl)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* x d r _ s l i c e
*
**************************************
*
* Functional description
* Move a slice of an array under
*
**************************************/
2003-04-16 12:18:51 +02:00
ISC_STATUS_ARRAY status_vector;
2001-05-23 15:26:42 +02:00
PORT port;
ULONG n;
BLOB_PTR *p;
DSC *desc;
struct sdl_info info;
if (!xdr_long(xdrs, reinterpret_cast < SLONG * >(&slice->lstr_length)))
return FALSE;
/* Handle operation specific stuff, particularly memory allocation/deallocation */
switch (xdrs->x_op) {
case XDR_ENCODE:
break;
case XDR_DECODE:
if (!slice->lstr_length)
return TRUE;
if (slice->lstr_length > slice->lstr_allocated &&
slice->lstr_allocated) {
ALLR_free(slice->lstr_address);
DEBUG_XDR_FREE(slice, slice->lstr_address, slice->lstr_allocated);
slice->lstr_address = NULL;
}
if (!slice->lstr_address) {
if (!
(slice->lstr_address =
ALLR_alloc((SLONG) slice->lstr_length)))
/* NOMEM: handled by ALLR_alloc() */
/* FREE: in realloc case above & XDR_FREE case of this routine */
return FALSE;
slice->lstr_allocated = slice->lstr_length;
DEBUG_XDR_ALLOC(slice, slice->lstr_address,
slice->lstr_allocated);
}
break;
case XDR_FREE:
if (slice->lstr_allocated) {
ALLR_free(slice->lstr_address);
DEBUG_XDR_FREE(slice, slice->lstr_address, slice->lstr_allocated);
}
slice->lstr_address = NULL;
slice->lstr_allocated = 0;
return TRUE;
}
/* Get descriptor of array element */
if (SDL_info(status_vector, sdl, &info, 0))
return FALSE;
desc = &info.sdl_info_element;
port = (PORT) xdrs->x_public;
p = (BLOB_PTR *) slice->lstr_address;
if (port->port_flags & PORT_symmetric) {
#ifdef VMS
if (port->port_protocol < PROTOCOL_VERSION5 &&
desc->dsc_dtype == dtype_d_float)
return xdr_semi_opaque_slice(xdrs, slice);
#endif
for (n = slice->lstr_length; n > MAX_OPAQUE;
n -= MAX_OPAQUE, p += (int) MAX_OPAQUE)
if (!xdr_opaque
(xdrs, reinterpret_cast < SCHAR * >(p),
MAX_OPAQUE)) return FALSE;
if (n)
if (!xdr_opaque(xdrs, reinterpret_cast < SCHAR * >(p), n))
return FALSE;
}
else {
for (n = 0; n < slice->lstr_length / desc->dsc_length; n++) {
if (!xdr_datum(xdrs, desc, p))
return FALSE;
p = p + (ULONG) desc->dsc_length;
}
}
return TRUE;
}
static bool_t xdr_sql_blr(
XDR* xdrs,
2001-05-23 15:26:42 +02:00
SLONG statement_id,
CSTRING* blr,
2001-05-23 15:26:42 +02:00
int direction, SQL_STMT_TYPE stmt_type)
{
/**************************************
*
* x d r _ s q l _ b l r
*
**************************************
*
* Functional description
* Map an sql blr string. This work is necessary because
* we will use the blr to read data in the current packet.
*
**************************************/
if (!xdr_cstring(xdrs, blr))
return FALSE;
/* We care about all receives and sends from fetch */
if (xdrs->x_op == XDR_FREE)
return TRUE;
PORT port = (PORT) xdrs->x_public;
RSR statement;
2001-05-23 15:26:42 +02:00
if (statement_id >= 0) {
if (!(statement = (RSR) port->port_objects[statement_id]))
return FALSE;
}
else {
if (!(statement = port->port_statement))
statement = port->port_statement = (RSR) ALLOC(type_rsr);
}
if ((xdrs->x_op == XDR_ENCODE) && !direction) {
if (statement->rsr_bind_format)
statement->rsr_format = statement->rsr_bind_format;
return TRUE;
}
/* Parse the blr describing the message. */
FMT* fmt_ptr = (direction) ?
2001-05-23 15:26:42 +02:00
&statement->rsr_select_format : &statement->rsr_bind_format;
if (xdrs->x_op == XDR_DECODE) {
/* For an immediate statement, flush out any previous format information
* that might be hanging around from an earlier execution.
* For all statements, if we have new blr, flush out the format information
* for the old blr.
*/
if (*fmt_ptr
&& ((stmt_type == TYPE_IMMEDIATE) || blr->cstr_length != 0)) {
ALLR_release(*fmt_ptr);
*fmt_ptr = NULL;
}
/* If we have BLR describing a new input/output message, get ready by
2002-02-16 04:27:33 +01:00
* setting up a format
2001-05-23 15:26:42 +02:00
*/
if (blr->cstr_length) {
REM_MSG temp_msg =
(REM_MSG) PARSE_messages(blr->cstr_address, blr->cstr_length);
if (temp_msg != (REM_MSG) -1) {
*fmt_ptr = (FMT) temp_msg->msg_address;
ALLR_release(temp_msg);
2001-05-23 15:26:42 +02:00
}
}
}
/* If we know the length of the message, make sure there is a buffer
large enough to hold it. */
if (!(statement->rsr_format = *fmt_ptr))
return TRUE;
REM_MSG message = statement->rsr_buffer;
2002-07-06 07:32:02 +02:00
if (!(message != 0) ||
2001-05-23 15:26:42 +02:00
statement->rsr_format->fmt_length > statement->rsr_fmt_length) {
REMOTE_release_messages(message);
statement->rsr_fmt_length = statement->rsr_format->fmt_length;
statement->rsr_buffer = message =
2002-11-19 13:40:54 +01:00
(REM_MSG) ALLOCV(type_msg, statement->rsr_fmt_length);
2001-05-23 15:26:42 +02:00
statement->rsr_message = message;
message->msg_next = message;
#ifdef SCROLLABLE_CURSORS
message->msg_prior = message;
#endif
}
return TRUE;
}
static bool_t xdr_sql_message( XDR* xdrs, SLONG statement_id)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* x d r _ s q l _ m e s s a g e
*
**************************************
*
* Functional description
* Map a formatted sql message.
*
**************************************/
2002-11-19 13:40:54 +01:00
REM_MSG message;
2001-05-23 15:26:42 +02:00
RSR statement;
if (xdrs->x_op == XDR_FREE)
return TRUE;
PORT port = (PORT) xdrs->x_public;
2001-05-23 15:26:42 +02:00
if (statement_id >= 0) {
if (!(statement = (RSR) port->port_objects[statement_id]))
return FALSE;
}
else
statement = port->port_statement;
2002-06-29 10:49:39 +02:00
if ((message = statement->rsr_buffer) != 0) {
2001-05-23 15:26:42 +02:00
statement->rsr_buffer = message->msg_next;
if (!message->msg_address)
message->msg_address = message->msg_buffer;
}
return xdr_message(xdrs, message, statement->rsr_format);
}
static bool_t xdr_status_vector(
XDR* xdrs, ISC_STATUS* vector, TEXT* strings[])
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* x d r _ s t a t u s _ v e c t o r
*
**************************************
*
* Functional description
* Map a status vector. This is tricky since the status vector
* may contain argument types, numbers, and strings.
*
**************************************/
TEXT **sp, **end;
SLONG vec;
XDR temp_xdrs;
/* If this is a free operation, release any allocated strings */
if (xdrs->x_op == XDR_FREE) {
for (sp = strings, end = strings + 10; sp < end; sp++)
if (*sp && !xdr_wrapstring(xdrs, sp))
return FALSE;
return TRUE;
}
while (true) {
2001-05-23 15:26:42 +02:00
if (xdrs->x_op == XDR_ENCODE)
vec = (SLONG) * vector++;
if (!xdr_long(xdrs, &vec))
return FALSE;
if (xdrs->x_op == XDR_DECODE)
2003-04-10 12:31:28 +02:00
*vector++ = (ISC_STATUS) vec;
2001-05-23 15:26:42 +02:00
switch ((USHORT) vec) {
case gds_arg_end:
return TRUE;
case gds_arg_interpreted:
case gds_arg_string:
if (xdrs->x_op == XDR_ENCODE) {
if (!xdr_wrapstring
(xdrs, reinterpret_cast < SCHAR ** >(vector++)))
return FALSE;
}
else {
/* Use the first slot in the strings table */
sp = strings;
if (*sp) {
/* Slot is used, by a string passed in a previous
* status vector. Free that string, and allocate
* a new one to prevent any size mismatches trashing
* memory.
*/
temp_xdrs.x_public = xdrs->x_public;
temp_xdrs.x_op = XDR_FREE;
if (!xdr_wrapstring(&temp_xdrs, sp))
return FALSE;
*sp = NULL;
}
if (!xdr_wrapstring(xdrs, sp))
return FALSE;
2003-04-10 12:31:28 +02:00
*vector++ = (ISC_STATUS) * sp;
2001-05-23 15:26:42 +02:00
strings++;
}
break;
case gds_arg_number:
default:
if (xdrs->x_op == XDR_ENCODE)
vec = (SLONG) * vector++;
if (!xdr_long(xdrs, &vec))
return FALSE;
if (xdrs->x_op == XDR_DECODE)
2003-04-10 12:31:28 +02:00
*vector++ = (ISC_STATUS) vec;
2001-05-23 15:26:42 +02:00
break;
}
}
}
static bool_t xdr_trrq_blr( XDR* xdrs, CSTRING* blr)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* x d r _ t r r q _ b l r
*
**************************************
*
* Functional description
* Map a message blr string. This work is necessary because
* we will use the blr to read data in the current packet.
*
**************************************/
2002-11-19 13:40:54 +01:00
REM_MSG message, temp;
2001-05-23 15:26:42 +02:00
if (!xdr_cstring(xdrs, blr))
return FALSE;
/* We care about all receives and sends from fetch */
if (xdrs->x_op == XDR_FREE || xdrs->x_op == XDR_ENCODE)
return TRUE;
PORT port = (PORT) xdrs->x_public;
RPR procedure = port->port_rpr;
if (!procedure)
2001-05-23 15:26:42 +02:00
procedure = port->port_rpr = (RPR) ALLOC(type_rpr);
/* Parse the blr describing the message. */
if (procedure->rpr_in_msg) {
ALLR_release(procedure->rpr_in_msg);
procedure->rpr_in_msg = NULL;
}
if (procedure->rpr_in_format) {
ALLR_release(procedure->rpr_in_format);
procedure->rpr_in_format = NULL;
}
if (procedure->rpr_out_msg) {
ALLR_release(procedure->rpr_out_msg);
procedure->rpr_out_msg = NULL;
}
if (procedure->rpr_out_format) {
ALLR_release(procedure->rpr_out_format);
procedure->rpr_out_format = NULL;
}
if ((message = PARSE_messages(blr->cstr_address, blr->cstr_length)) !=
2002-11-19 13:40:54 +01:00
(REM_MSG) - 1) {
2001-05-23 15:26:42 +02:00
while (message) {
if (message->msg_number == 0) {
procedure->rpr_in_msg = message;
procedure->rpr_in_format = (FMT) message->msg_address;
message->msg_address = message->msg_buffer;
message = message->msg_next;
procedure->rpr_in_msg->msg_next = NULL;
}
else if (message->msg_number == 1) {
procedure->rpr_out_msg = message;
procedure->rpr_out_format = (FMT) message->msg_address;
message->msg_address = message->msg_buffer;
message = message->msg_next;
procedure->rpr_out_msg->msg_next = NULL;
}
else {
temp = message;
message = message->msg_next;
ALLR_release(temp);
}
}
}
else
2003-11-04 00:59:24 +01:00
fb_assert(FALSE);
2001-05-23 15:26:42 +02:00
return TRUE;
}
static bool_t xdr_trrq_message( XDR* xdrs, USHORT msg_type)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* x d r _ t r r q _ m e s s a g e
*
**************************************
*
* Functional description
* Map a formatted transact request message.
*
**************************************/
if (xdrs->x_op == XDR_FREE)
return TRUE;
PORT port = (PORT) xdrs->x_public;
RPR procedure = port->port_rpr;
2001-05-23 15:26:42 +02:00
if (msg_type == 1)
return xdr_message(xdrs, procedure->rpr_out_msg,
procedure->rpr_out_format);
else
return xdr_message(xdrs, procedure->rpr_in_msg,
procedure->rpr_in_format);
}
static RSR get_statement( XDR * xdrs, SSHORT statement_id)
{
/**************************************
*
* g e t _ s t a t e m e n t
*
**************************************
*
* Functional description
* Returns the statement based upon the statement id
* if statement_id = -1 then statement = port_statement
* otherwise, the statement comes from port_objects[statement_id]
* if there are no port_objects, then statement = NULL
*
**************************************/
RSR statement = NULL;
PORT port = (PORT) xdrs->x_public;
2002-02-16 04:27:33 +01:00
/* if the statement ID is -1, this seems to indicate that we are
2001-05-23 15:26:42 +02:00
re-executing the previous statement. This is not a
well-understood area of the implementation.
if (statement_id == -1)
statement = port->port_statement;
else
*/
2003-11-04 00:59:24 +01:00
fb_assert(statement_id >= -1);
2001-05-23 15:26:42 +02:00
if ((port->port_objects) &&
((SLONG) statement_id < (SLONG) port->port_object_vector->vec_count)
&& (statement_id >= 0))
statement = (RSR) port->port_objects[(SLONG) statement_id];
/* Check that what we found really is a statement structure */
2003-11-04 00:59:24 +01:00
fb_assert(!statement || (statement->rsr_header.blk_type == type_rsr));
2001-05-23 15:26:42 +02:00
return statement;
}