mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-02-02 10:00:38 +01:00
Resolved CORE-2897: Don't send full length of field over the wire when field is null.
This commit is contained in:
parent
fae24dd12b
commit
4b5b82615b
@ -42,6 +42,8 @@
|
|||||||
#include "../common/StatusHolder.h"
|
#include "../common/StatusHolder.h"
|
||||||
#include "../common/classes/stack.h"
|
#include "../common/classes/stack.h"
|
||||||
|
|
||||||
|
using namespace Firebird;
|
||||||
|
|
||||||
#ifdef DEBUG_XDR_MEMORY
|
#ifdef DEBUG_XDR_MEMORY
|
||||||
inline bool_t P_TRUE(XDR* xdrs, PACKET* p)
|
inline bool_t P_TRUE(XDR* xdrs, PACKET* p)
|
||||||
{
|
{
|
||||||
@ -102,9 +104,10 @@ static bool_t xdr_debug_packet(XDR*, enum xdr_op, PACKET*);
|
|||||||
#endif
|
#endif
|
||||||
static bool_t xdr_longs(XDR*, CSTRING*);
|
static bool_t xdr_longs(XDR*, CSTRING*);
|
||||||
static bool_t xdr_message(XDR*, RMessage*, const rem_fmt*);
|
static bool_t xdr_message(XDR*, RMessage*, const rem_fmt*);
|
||||||
|
static bool_t xdr_packed_message(XDR*, RMessage*, const rem_fmt*);
|
||||||
static bool_t xdr_request(XDR*, USHORT, USHORT, USHORT);
|
static bool_t xdr_request(XDR*, USHORT, USHORT, USHORT);
|
||||||
static bool_t xdr_slice(XDR*, lstring*, /*USHORT,*/ const UCHAR*);
|
static bool_t xdr_slice(XDR*, lstring*, /*USHORT,*/ const UCHAR*);
|
||||||
static bool_t xdr_status_vector(XDR*, Firebird::DynamicStatusVector*&);
|
static bool_t xdr_status_vector(XDR*, DynamicStatusVector*&);
|
||||||
static bool_t xdr_sql_blr(XDR*, SLONG, CSTRING*, bool, SQL_STMT_TYPE);
|
static bool_t xdr_sql_blr(XDR*, SLONG, CSTRING*, bool, SQL_STMT_TYPE);
|
||||||
static bool_t xdr_sql_message(XDR*, SLONG);
|
static bool_t xdr_sql_message(XDR*, SLONG);
|
||||||
static bool_t xdr_trrq_blr(XDR*, CSTRING*);
|
static bool_t xdr_trrq_blr(XDR*, CSTRING*);
|
||||||
@ -903,7 +906,7 @@ static bool alloc_cstring(XDR* xdrs, CSTRING* cstring)
|
|||||||
try {
|
try {
|
||||||
cstring->cstr_address = FB_NEW(*getDefaultMemoryPool()) UCHAR[cstring->cstr_length];
|
cstring->cstr_address = FB_NEW(*getDefaultMemoryPool()) UCHAR[cstring->cstr_length];
|
||||||
}
|
}
|
||||||
catch (const Firebird::BadAlloc&) {
|
catch (const BadAlloc&) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1158,21 +1161,16 @@ static bool_t xdr_message( XDR* xdrs, RMessage* message, const rem_fmt* format)
|
|||||||
if (xdrs->x_op == XDR_FREE)
|
if (xdrs->x_op == XDR_FREE)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
const rem_port* port = (rem_port*) xdrs->x_public;
|
rem_port* port = (rem_port*) xdrs->x_public;
|
||||||
|
|
||||||
|
|
||||||
if (!message || !format)
|
if (!message || !format)
|
||||||
{
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
|
||||||
|
|
||||||
// If we are running a symmetric version of the protocol, just slop
|
// If we are running a symmetric version of the protocol, just slop
|
||||||
// the bits and don't sweat the translations
|
// the bits and don't sweat the translations
|
||||||
|
|
||||||
if (port->port_flags & PORT_symmetric)
|
if (port->port_flags & PORT_symmetric)
|
||||||
{
|
|
||||||
return xdr_opaque(xdrs, reinterpret_cast<SCHAR*>(message->msg_address), format->fmt_length);
|
return xdr_opaque(xdrs, reinterpret_cast<SCHAR*>(message->msg_address), format->fmt_length);
|
||||||
}
|
|
||||||
|
|
||||||
const dsc* desc = format->fmt_desc.begin();
|
const dsc* desc = format->fmt_desc.begin();
|
||||||
for (const dsc* const end = format->fmt_desc.end(); desc < end; ++desc)
|
for (const dsc* const end = format->fmt_desc.end(); desc < end; ++desc)
|
||||||
@ -1186,6 +1184,136 @@ static bool_t xdr_message( XDR* xdrs, RMessage* message, const rem_fmt* format)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static bool_t xdr_packed_message( XDR* xdrs, RMessage* message, const rem_fmt* format)
|
||||||
|
{
|
||||||
|
/**************************************
|
||||||
|
*
|
||||||
|
* x d r _ p a c k e d _ m e s s a g e
|
||||||
|
*
|
||||||
|
**************************************
|
||||||
|
*
|
||||||
|
* Functional description
|
||||||
|
* Map a formatted message.
|
||||||
|
*
|
||||||
|
**************************************/
|
||||||
|
|
||||||
|
if (xdrs->x_op == XDR_FREE)
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
const rem_port* const port = (rem_port*) xdrs->x_public;
|
||||||
|
|
||||||
|
if (!message || !format)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
return xdr_opaque(xdrs, reinterpret_cast<SCHAR*>(message->msg_address), format->fmt_length);
|
||||||
|
|
||||||
|
// Optimize the message by transforming NULL indicators into a bitmap
|
||||||
|
// and then skipping the NULL items
|
||||||
|
|
||||||
|
class NullBitmap : private HalfStaticArray<UCHAR, 4>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit NullBitmap(USHORT size)
|
||||||
|
{
|
||||||
|
resize(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setNull(USHORT id)
|
||||||
|
{
|
||||||
|
data[id >> 3] |= (1 << (id & 7));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isNull(USHORT id) const
|
||||||
|
{
|
||||||
|
return data[id >> 3] & (1 << (id & 7));
|
||||||
|
}
|
||||||
|
|
||||||
|
UCHAR* getData()
|
||||||
|
{
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
fb_assert(format->fmt_desc.getCount() % 2 == 0);
|
||||||
|
const USHORT flagBytes = (format->fmt_desc.getCount() / 2 + 7) / 8;
|
||||||
|
NullBitmap nulls(flagBytes);
|
||||||
|
|
||||||
|
if (xdrs->x_op == XDR_ENCODE)
|
||||||
|
{
|
||||||
|
// First pass (odd elements): track NULL indicators
|
||||||
|
|
||||||
|
const dsc* desc = format->fmt_desc.begin() + 1;
|
||||||
|
for (const dsc* const end = format->fmt_desc.end(); desc < end; desc += 2)
|
||||||
|
{
|
||||||
|
fb_assert(desc->dsc_dtype == dtype_short);
|
||||||
|
const USHORT index = (USHORT) (desc - format->fmt_desc.begin()) / 2;
|
||||||
|
const SSHORT* const flag = (SSHORT*) (message->msg_address + (IPTR) desc->dsc_address);
|
||||||
|
|
||||||
|
if (*flag)
|
||||||
|
nulls.setNull(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send the NULL bitmap
|
||||||
|
|
||||||
|
if (!xdr_opaque(xdrs, reinterpret_cast<SCHAR*>(nulls.getData()), flagBytes))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
// Second pass (even elements): process non-NULL items
|
||||||
|
|
||||||
|
desc = format->fmt_desc.begin();
|
||||||
|
for (const dsc* const end = format->fmt_desc.end(); desc < end; desc += 2)
|
||||||
|
{
|
||||||
|
const USHORT index = (USHORT) (desc - format->fmt_desc.begin()) / 2;
|
||||||
|
|
||||||
|
if (!nulls.isNull(index))
|
||||||
|
{
|
||||||
|
if (!xdr_datum(xdrs, desc, message->msg_address))
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Receive the NULL bitmap
|
||||||
|
|
||||||
|
if (!xdr_opaque(xdrs, reinterpret_cast<SCHAR*>(nulls.getData()), flagBytes))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
// First pass (odd elements): initialize NULL indicators
|
||||||
|
|
||||||
|
const dsc* desc = format->fmt_desc.begin() + 1;
|
||||||
|
for (const dsc* const end = format->fmt_desc.end(); desc < end; desc += 2)
|
||||||
|
{
|
||||||
|
fb_assert(desc->dsc_dtype == dtype_short);
|
||||||
|
const USHORT index = (USHORT) (desc - format->fmt_desc.begin()) / 2;
|
||||||
|
SSHORT* const flag = (SSHORT*) (message->msg_address + (IPTR) desc->dsc_address);
|
||||||
|
*flag = nulls.isNull(index) ? -1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Second pass (even elements): process non-NULL items
|
||||||
|
|
||||||
|
desc = format->fmt_desc.begin();
|
||||||
|
for (const dsc* const end = format->fmt_desc.end(); desc < end; desc += 2)
|
||||||
|
{
|
||||||
|
const USHORT index = (USHORT) (desc - format->fmt_desc.begin()) / 2;
|
||||||
|
|
||||||
|
if (!nulls.isNull(index))
|
||||||
|
{
|
||||||
|
if (!xdr_datum(xdrs, desc, message->msg_address))
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG_PRINTSIZE(xdrs, op_void);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static bool_t xdr_request(XDR* xdrs,
|
static bool_t xdr_request(XDR* xdrs,
|
||||||
USHORT request_id,
|
USHORT request_id,
|
||||||
USHORT message_number, USHORT incarnation)
|
USHORT message_number, USHORT incarnation)
|
||||||
@ -1214,7 +1342,7 @@ static bool_t xdr_request(XDR* xdrs,
|
|||||||
{
|
{
|
||||||
request = port->port_objects[request_id];
|
request = port->port_objects[request_id];
|
||||||
}
|
}
|
||||||
catch (const Firebird::status_exception&)
|
catch (const status_exception&)
|
||||||
{
|
{
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
@ -1280,7 +1408,7 @@ static bool_t xdr_slice(XDR* xdrs, lstring* slice, /*USHORT sdl_length,*/ const
|
|||||||
try {
|
try {
|
||||||
slice->lstr_address = FB_NEW(*getDefaultMemoryPool()) UCHAR[slice->lstr_length];
|
slice->lstr_address = FB_NEW(*getDefaultMemoryPool()) UCHAR[slice->lstr_length];
|
||||||
}
|
}
|
||||||
catch (const Firebird::BadAlloc&) {
|
catch (const BadAlloc&) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1373,7 +1501,7 @@ static bool_t xdr_sql_blr(XDR* xdrs,
|
|||||||
{
|
{
|
||||||
statement = port->port_objects[statement_id];
|
statement = port->port_objects[statement_id];
|
||||||
}
|
}
|
||||||
catch (const Firebird::status_exception&)
|
catch (const status_exception&)
|
||||||
{
|
{
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
@ -1479,7 +1607,7 @@ static bool_t xdr_sql_message( XDR* xdrs, SLONG statement_id)
|
|||||||
{
|
{
|
||||||
statement = port->port_objects[statement_id];
|
statement = port->port_objects[statement_id];
|
||||||
}
|
}
|
||||||
catch (const Firebird::status_exception&)
|
catch (const status_exception&)
|
||||||
{
|
{
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
@ -1494,20 +1622,19 @@ static bool_t xdr_sql_message( XDR* xdrs, SLONG statement_id)
|
|||||||
|
|
||||||
RMessage* message = statement->rsr_buffer;
|
RMessage* message = statement->rsr_buffer;
|
||||||
if (!message)
|
if (!message)
|
||||||
{
|
|
||||||
// We should not call xdr_message() with NULL
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
|
||||||
|
|
||||||
statement->rsr_buffer = message->msg_next;
|
statement->rsr_buffer = message->msg_next;
|
||||||
if (!message->msg_address)
|
if (!message->msg_address)
|
||||||
message->msg_address = message->msg_buffer;
|
message->msg_address = message->msg_buffer;
|
||||||
|
|
||||||
return xdr_message(xdrs, message, statement->rsr_format);
|
return (port->port_protocol >= PROTOCOL_VERSION13) ?
|
||||||
|
xdr_packed_message(xdrs, message, statement->rsr_format) :
|
||||||
|
xdr_message(xdrs, message, statement->rsr_format);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static bool_t xdr_status_vector(XDR* xdrs, Firebird::DynamicStatusVector*& vector)
|
static bool_t xdr_status_vector(XDR* xdrs, DynamicStatusVector*& vector)
|
||||||
{
|
{
|
||||||
/**************************************
|
/**************************************
|
||||||
*
|
*
|
||||||
@ -1531,12 +1658,12 @@ static bool_t xdr_status_vector(XDR* xdrs, Firebird::DynamicStatusVector*& vecto
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!vector)
|
if (!vector)
|
||||||
vector = FB_NEW(*getDefaultMemoryPool()) Firebird::DynamicStatusVector();
|
vector = FB_NEW(*getDefaultMemoryPool()) DynamicStatusVector();
|
||||||
|
|
||||||
Firebird::SimpleStatusVector vectorDecode;
|
SimpleStatusVector vectorDecode;
|
||||||
const ISC_STATUS* vectorEncode = vector->value();
|
const ISC_STATUS* vectorEncode = vector->value();
|
||||||
|
|
||||||
Firebird::Stack<SCHAR*> space;
|
Stack<SCHAR*> space;
|
||||||
bool rc = false;
|
bool rc = false;
|
||||||
|
|
||||||
SLONG vec;
|
SLONG vec;
|
||||||
@ -1745,7 +1872,7 @@ static void reset_statement( XDR* xdrs, SSHORT statement_id)
|
|||||||
statement = port->port_objects[statement_id];
|
statement = port->port_objects[statement_id];
|
||||||
REMOTE_reset_statement(statement);
|
REMOTE_reset_statement(statement);
|
||||||
}
|
}
|
||||||
catch (const Firebird::status_exception&)
|
catch (const status_exception&)
|
||||||
{} // no-op
|
{} // no-op
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -73,6 +73,7 @@ const USHORT PROTOCOL_VERSION11 = (FB_PROTOCOL_FLAG | 11);
|
|||||||
const USHORT PROTOCOL_VERSION12 = (FB_PROTOCOL_FLAG | 12);
|
const USHORT PROTOCOL_VERSION12 = (FB_PROTOCOL_FLAG | 12);
|
||||||
|
|
||||||
// Protocol 13 has support for authentication plugins (op_cont_auth).
|
// Protocol 13 has support for authentication plugins (op_cont_auth).
|
||||||
|
// It also transfers SQL messages in the packed (null aware) format.
|
||||||
|
|
||||||
const USHORT PROTOCOL_VERSION13 = (FB_PROTOCOL_FLAG | 13);
|
const USHORT PROTOCOL_VERSION13 = (FB_PROTOCOL_FLAG | 13);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user