8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-22 17:23:03 +01:00

Resolved CORE-2897: Don't send full length of field over the wire when field is null.

This commit is contained in:
dimitr 2014-09-10 11:55:43 +00:00
parent fae24dd12b
commit 4b5b82615b
2 changed files with 149 additions and 21 deletions

View File

@ -42,6 +42,8 @@
#include "../common/StatusHolder.h"
#include "../common/classes/stack.h"
using namespace Firebird;
#ifdef DEBUG_XDR_MEMORY
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
static bool_t xdr_longs(XDR*, CSTRING*);
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_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_message(XDR*, SLONG);
static bool_t xdr_trrq_blr(XDR*, CSTRING*);
@ -903,7 +906,7 @@ static bool alloc_cstring(XDR* xdrs, CSTRING* cstring)
try {
cstring->cstr_address = FB_NEW(*getDefaultMemoryPool()) UCHAR[cstring->cstr_length];
}
catch (const Firebird::BadAlloc&) {
catch (const BadAlloc&) {
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)
return TRUE;
const rem_port* port = (rem_port*) xdrs->x_public;
rem_port* 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);
}
const dsc* desc = format->fmt_desc.begin();
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,
USHORT request_id,
USHORT message_number, USHORT incarnation)
@ -1214,7 +1342,7 @@ static bool_t xdr_request(XDR* xdrs,
{
request = port->port_objects[request_id];
}
catch (const Firebird::status_exception&)
catch (const status_exception&)
{
return FALSE;
}
@ -1280,7 +1408,7 @@ static bool_t xdr_slice(XDR* xdrs, lstring* slice, /*USHORT sdl_length,*/ const
try {
slice->lstr_address = FB_NEW(*getDefaultMemoryPool()) UCHAR[slice->lstr_length];
}
catch (const Firebird::BadAlloc&) {
catch (const BadAlloc&) {
return false;
}
@ -1373,7 +1501,7 @@ static bool_t xdr_sql_blr(XDR* xdrs,
{
statement = port->port_objects[statement_id];
}
catch (const Firebird::status_exception&)
catch (const status_exception&)
{
return FALSE;
}
@ -1479,7 +1607,7 @@ static bool_t xdr_sql_message( XDR* xdrs, SLONG statement_id)
{
statement = port->port_objects[statement_id];
}
catch (const Firebird::status_exception&)
catch (const status_exception&)
{
return FALSE;
}
@ -1494,20 +1622,19 @@ static bool_t xdr_sql_message( XDR* xdrs, SLONG statement_id)
RMessage* message = statement->rsr_buffer;
if (!message)
{
// We should not call xdr_message() with NULL
return FALSE;
}
statement->rsr_buffer = message->msg_next;
if (!message->msg_address)
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)
vector = FB_NEW(*getDefaultMemoryPool()) Firebird::DynamicStatusVector();
vector = FB_NEW(*getDefaultMemoryPool()) DynamicStatusVector();
Firebird::SimpleStatusVector vectorDecode;
SimpleStatusVector vectorDecode;
const ISC_STATUS* vectorEncode = vector->value();
Firebird::Stack<SCHAR*> space;
Stack<SCHAR*> space;
bool rc = false;
SLONG vec;
@ -1745,7 +1872,7 @@ static void reset_statement( XDR* xdrs, SSHORT statement_id)
statement = port->port_objects[statement_id];
REMOTE_reset_statement(statement);
}
catch (const Firebird::status_exception&)
catch (const status_exception&)
{} // no-op
}
}

View File

@ -73,6 +73,7 @@ const USHORT PROTOCOL_VERSION11 = (FB_PROTOCOL_FLAG | 11);
const USHORT PROTOCOL_VERSION12 = (FB_PROTOCOL_FLAG | 12);
// 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);