|
From: <di...@us...> - 2014-09-10 11:55:52
|
Revision: 60040
http://sourceforge.net/p/firebird/code/60040
Author: dimitr
Date: 2014-09-10 11:55:43 +0000 (Wed, 10 Sep 2014)
Log Message:
-----------
Resolved CORE-2897: Don't send full length of field over the wire when field is null.
Modified Paths:
--------------
firebird/trunk/src/remote/protocol.cpp
firebird/trunk/src/remote/protocol.h
Modified: firebird/trunk/src/remote/protocol.cpp
===================================================================
--- firebird/trunk/src/remote/protocol.cpp 2014-09-09 07:43:46 UTC (rev 60039)
+++ firebird/trunk/src/remote/protocol.cpp 2014-09-10 11:55:43 UTC (rev 60040)
@@ -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 @@
#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 @@
try {
cstring->cstr_address = FB_NEW(*getDefaultMemoryPool()) UCHAR[cstring->cstr_length];
}
- catch (const Firebird::BadAlloc&) {
+ catch (const BadAlloc&) {
return false;
}
@@ -1158,21 +1161,16 @@
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_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 @@
{
request = port->port_objects[request_id];
}
- catch (const Firebird::status_exception&)
+ catch (const status_exception&)
{
return FALSE;
}
@@ -1280,7 +1408,7 @@
try {
slice->lstr_address = FB_NEW(*getDefaultMemoryPool()) UCHAR[slice->lstr_length];
}
- catch (const Firebird::BadAlloc&) {
+ catch (const BadAlloc&) {
return false;
}
@@ -1373,7 +1501,7 @@
{
statement = port->port_objects[statement_id];
}
- catch (const Firebird::status_exception&)
+ catch (const status_exception&)
{
return FALSE;
}
@@ -1479,7 +1607,7 @@
{
statement = port->port_objects[statement_id];
}
- catch (const Firebird::status_exception&)
+ catch (const status_exception&)
{
return FALSE;
}
@@ -1494,20 +1622,19 @@
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 @@
}
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 @@
statement = port->port_objects[statement_id];
REMOTE_reset_statement(statement);
}
- catch (const Firebird::status_exception&)
+ catch (const status_exception&)
{} // no-op
}
}
Modified: firebird/trunk/src/remote/protocol.h
===================================================================
--- firebird/trunk/src/remote/protocol.h 2014-09-09 07:43:46 UTC (rev 60039)
+++ firebird/trunk/src/remote/protocol.h 2014-09-10 11:55:43 UTC (rev 60040)
@@ -73,6 +73,7 @@
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);
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|