mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-22 18:43:02 +01:00
Implemented #6959: IBatch::getInfo()
This commit is contained in:
parent
a6d36dac0f
commit
33caf198dd
@ -6,7 +6,7 @@
|
|||||||
<meta name="generator" content="LibreOffice 6.4.7.2 (Linux)"/>
|
<meta name="generator" content="LibreOffice 6.4.7.2 (Linux)"/>
|
||||||
<meta name="author" content="alex "/>
|
<meta name="author" content="alex "/>
|
||||||
<meta name="created" content="2013-05-31T00:00:00.010003100"/>
|
<meta name="created" content="2013-05-31T00:00:00.010003100"/>
|
||||||
<meta name="changed" content="2021-08-12T15:06:38.252335410"/>
|
<meta name="changed" content="2021-09-10T16:41:58.007600045"/>
|
||||||
<meta name="created" content="00:00:00">
|
<meta name="created" content="00:00:00">
|
||||||
<meta name="created" content="00:00:00">
|
<meta name="created" content="00:00:00">
|
||||||
<meta name="created" content="00:00:00">
|
<meta name="created" content="00:00:00">
|
||||||
@ -30,21 +30,19 @@ in some aspects like OLE2 interfaces (some of them have addRef() and
|
|||||||
release() methods) are non standard and have features, missing in
|
release() methods) are non standard and have features, missing in
|
||||||
other widely used types of interfaces. First of all Firebird
|
other widely used types of interfaces. First of all Firebird
|
||||||
interfaces are </font><font size="4" style="font-size: 14pt"><b>language
|
interfaces are </font><font size="4" style="font-size: 14pt"><b>language
|
||||||
independent</b></font> –
|
independent</b></font> – <font size="4" style="font-size: 14pt">that
|
||||||
<font size="4" style="font-size: 14pt">that
|
|
||||||
means that to define/use them one need not use language specific
|
means that to define/use them one need not use language specific
|
||||||
constructions like </font><font size="4" style="font-size: 14pt"><i>class</i></font>
|
constructions like </font><font size="4" style="font-size: 14pt"><i>class</i></font>
|
||||||
<font size="4" style="font-size: 14pt">in
|
<font size="4" style="font-size: 14pt">in C++, interface may be
|
||||||
C++, interface may be defined using any language able to call
|
defined using any language able to call functions using C calling
|
||||||
functions using C calling conventions and having concepts of array
|
conventions and having concepts of array and pointer to
|
||||||
and pointer to procedure/function. Next interfaces are </font><font size="4" style="font-size: 14pt"><b>versioned</b></font>
|
procedure/function. Next interfaces are </font><font size="4" style="font-size: 14pt"><b>versioned</b></font>
|
||||||
– <font size="4" style="font-size: 14pt">i.e.
|
– <font size="4" style="font-size: 14pt">i.e. we support different
|
||||||
we support different versions of same interface. Binary layout of
|
versions of same interface. Binary layout of interfaces is designed
|
||||||
interfaces is designed to support that features very efficient (there
|
to support that features very efficient (there is no need in
|
||||||
is no need in additional virtual calls like in OLE2/COM with it's
|
additional virtual calls like in OLE2/COM with it's </font><strong><font size="4" style="font-size: 14pt">QueryInterface)</font></strong><strong>
|
||||||
</font><strong><font size="4" style="font-size: 14pt">QueryInterface</font></strong><strong><font size="4" style="font-size: 14pt">)</font></strong><strong>
|
</strong><strong><font size="4" style="font-size: 14pt">but it's not
|
||||||
</strong><strong><font size="4" style="font-size: 14pt">but
|
convenient for direct use from most languages. Therefore
|
||||||
it's not convenient for direct use from most languages. Therefore
|
|
||||||
language-specific wrappers should better be designed for different
|
language-specific wrappers should better be designed for different
|
||||||
languages making use of API easier. Currently we have wrappers for
|
languages making use of API easier. Currently we have wrappers for
|
||||||
C++ and Pascal, Java is coming soon. From end-user POV calls from C++
|
C++ and Pascal, Java is coming soon. From end-user POV calls from C++
|
||||||
@ -74,8 +72,7 @@ for it.</font></p>
|
|||||||
<p style="margin-bottom: 0cm"><a name="result_box"></a><font size="4" style="font-size: 14pt">Firebird
|
<p style="margin-bottom: 0cm"><a name="result_box"></a><font size="4" style="font-size: 14pt">Firebird
|
||||||
installation package contains a number of live samples of use of OO
|
installation package contains a number of live samples of use of OO
|
||||||
API – they are in examples/interfaces (database access) and
|
API – they are in examples/interfaces (database access) and
|
||||||
examples/dbcrypt (plugin performing </font><font size="4" style="font-size: 14pt">fictitious
|
examples/dbcrypt (plugin performing fictitious database encryption)
|
||||||
database encryption</font><font size="4" style="font-size: 14pt">)
|
|
||||||
directories. It's supposed that the reader is familiar with ISC API
|
directories. It's supposed that the reader is familiar with ISC API
|
||||||
used in Firebird since interbase times.</font></p>
|
used in Firebird since interbase times.</font></p>
|
||||||
<p style="margin-bottom: 0cm"><br/>
|
<p style="margin-bottom: 0cm"><br/>
|
||||||
@ -101,8 +98,8 @@ too.</font></p>
|
|||||||
<p style="margin-top: 0.43cm; margin-bottom: 0.51cm; page-break-after: avoid">
|
<p style="margin-top: 0.43cm; margin-bottom: 0.51cm; page-break-after: avoid">
|
||||||
<font face="Albany, sans-serif"><font size="5" style="font-size: 18pt">Accessing
|
<font face="Albany, sans-serif"><font size="5" style="font-size: 18pt">Accessing
|
||||||
databases.</font></font></p>
|
databases.</font></font></p>
|
||||||
<h1><font size="4" style="font-size: 14pt">Creating
|
<h1><font size="4" style="font-size: 14pt">Creating database and
|
||||||
database and attaching to existing database.</font></h1>
|
attaching to existing database.</font></h1>
|
||||||
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">First
|
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">First
|
||||||
of all we need to get access to <b>IMaster</b> interface. IMaster is
|
of all we need to get access to <b>IMaster</b> interface. IMaster is
|
||||||
primary Firebird interface, required to access all the rest of
|
primary Firebird interface, required to access all the rest of
|
||||||
@ -157,8 +154,7 @@ will have to modify a call too often to add new parameters, and
|
|||||||
number of them will be very big no matter of the fact that typically
|
number of them will be very big no matter of the fact that typically
|
||||||
one needs to pass not too much of them. Therefore to pass additional
|
one needs to pass not too much of them. Therefore to pass additional
|
||||||
parameters special in-memory data structure, called </font><font size="4" style="font-size: 14pt"><i>database
|
parameters special in-memory data structure, called </font><font size="4" style="font-size: 14pt"><i>database
|
||||||
parameters block</i></font>
|
parameters block</i></font> <font size="4" style="font-size: 14pt">(DPB)
|
||||||
<font size="4" style="font-size: 14pt">(DPB)
|
|
||||||
is used. Format of it is well defined, and it's possible to build DPB
|
is used. Format of it is well defined, and it's possible to build DPB
|
||||||
byte after byte. But it's much easier to use special interface
|
byte after byte. But it's much easier to use special interface
|
||||||
</font><a href="#XpbBuilder"><font size="4" style="font-size: 14pt"><b>IXpbBuilder</b></font></a><font size="4" style="font-size: 14pt">,
|
</font><a href="#XpbBuilder"><font size="4" style="font-size: 14pt"><b>IXpbBuilder</b></font></a><font size="4" style="font-size: 14pt">,
|
||||||
@ -274,8 +270,7 @@ appropriate samples when reading this document.</font></p>
|
|||||||
<p style="margin-bottom: 0cm"><br/>
|
<p style="margin-bottom: 0cm"><br/>
|
||||||
|
|
||||||
</p>
|
</p>
|
||||||
<h1><font size="4" style="font-size: 14pt">Working
|
<h1><font size="4" style="font-size: 14pt">Working with transactions.</font></h1>
|
||||||
with transactions.</font></h1>
|
|
||||||
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">Only
|
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">Only
|
||||||
creating empty databases is definitely not enough to work with RDBMS.
|
creating empty databases is definitely not enough to work with RDBMS.
|
||||||
We want to be able to create various objects (like tables and so on)
|
We want to be able to create various objects (like tables and so on)
|
||||||
@ -319,8 +314,8 @@ may take a look at how to start and commit transaction in examples
|
|||||||
<p style="margin-bottom: 0cm"><br/>
|
<p style="margin-bottom: 0cm"><br/>
|
||||||
|
|
||||||
</p>
|
</p>
|
||||||
<h1><font size="4" style="font-size: 14pt">Executing
|
<h1><font size="4" style="font-size: 14pt">Executing SQL operator
|
||||||
SQL operator without input parameters and returned rows.</font></h1>
|
without input parameters and returned rows.</font></h1>
|
||||||
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">With
|
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">With
|
||||||
started transaction we are ready to execute our first SQL operators.
|
started transaction we are ready to execute our first SQL operators.
|
||||||
Used for it execute() method in <a href="#Attachment">IAttachment</a>
|
Used for it execute() method in <a href="#Attachment">IAttachment</a>
|
||||||
@ -353,8 +348,8 @@ may take a look at how to start and commit transaction in examples
|
|||||||
<p style="margin-bottom: 0cm"><br/>
|
<p style="margin-bottom: 0cm"><br/>
|
||||||
|
|
||||||
</p>
|
</p>
|
||||||
<h1><font size="4" style="font-size: 14pt">Executing
|
<h1><font size="4" style="font-size: 14pt">Executing SQL operator
|
||||||
SQL operator with input parameters.</font></h1>
|
with input parameters.</font></h1>
|
||||||
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">There
|
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">There
|
||||||
are 2 ways to execute statement with input parameters. Choice of
|
are 2 ways to execute statement with input parameters. Choice of
|
||||||
correct method depends upon do you need to execute it more than once
|
correct method depends upon do you need to execute it more than once
|
||||||
@ -434,21 +429,20 @@ fields:</font></p>
|
|||||||
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt"><i>builder->setLength(&status,
|
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt"><i>builder->setLength(&status,
|
||||||
1, 3);</i></font></p>
|
1, 3);</i></font></p>
|
||||||
<p style="margin-bottom: 0cm; font-variant: normal; font-style: normal">
|
<p style="margin-bottom: 0cm; font-variant: normal; font-style: normal">
|
||||||
<font size="4" style="font-size: 14pt">New
|
<font size="4" style="font-size: 14pt">New API is using old constants
|
||||||
API is using old constants for SQL types, smallest bit as earlier
|
for SQL types, smallest bit as earlier stands for nullability. In
|
||||||
stands for nullability. In some case it may also make sense to set
|
some case it may also make sense to set sub-type (for blobs),
|
||||||
sub-type (for blobs), character set (for text fields) or scale (for
|
character set (for text fields) or scale (for numeric fields). And
|
||||||
numeric fields). And finally it's time to get an instance of
|
finally it's time to get an instance of IMessageMetadata:</font></p>
|
||||||
IMessageMetadata:</font></p>
|
|
||||||
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt"><i><a href="#MessageMetadata">IMessageMetadata</a>*
|
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt"><i><a href="#MessageMetadata">IMessageMetadata</a>*
|
||||||
meta = builder->getMetadata(&status);</i></font></p>
|
meta = builder->getMetadata(&status);</i></font></p>
|
||||||
<p style="margin-bottom: 0cm"><br/>
|
<p style="margin-bottom: 0cm"><br/>
|
||||||
|
|
||||||
</p>
|
</p>
|
||||||
<p style="margin-bottom: 0cm; font-variant: normal; font-style: normal">
|
<p style="margin-bottom: 0cm; font-variant: normal; font-style: normal">
|
||||||
<font size="4" style="font-size: 14pt">Here
|
<font size="4" style="font-size: 14pt">Here we do not discuss in
|
||||||
we do not discuss in details own implementation of IMessageMetadata.
|
details own implementation of IMessageMetadata. If one cares there is
|
||||||
If one cares there is a sample 05.user_metadata.cpp.</font></p>
|
a sample 05.user_metadata.cpp.</font></p>
|
||||||
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">So
|
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">So
|
||||||
finally we have obtained (one or another way) an instance of metadata
|
finally we have obtained (one or another way) an instance of metadata
|
||||||
description of input parameters. But to work with a message we also
|
description of input parameters. But to work with a message we also
|
||||||
@ -513,8 +507,8 @@ exception may be caught by C++ program.</font></p>
|
|||||||
<p style="margin-bottom: 0cm"><br/>
|
<p style="margin-bottom: 0cm"><br/>
|
||||||
|
|
||||||
</p>
|
</p>
|
||||||
<h1><font size="4" style="font-size: 14pt">Opening
|
<h1><font size="4" style="font-size: 14pt">Opening cursor and
|
||||||
cursor and fetching data from it.</font></h1>
|
fetching data from it.</font></h1>
|
||||||
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">The
|
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">The
|
||||||
only way to get rows of data, returned by SELECT operator, in OO API
|
only way to get rows of data, returned by SELECT operator, in OO API
|
||||||
is to use <a href="#ResultSet">IResultSet</a> interface. This
|
is to use <a href="#ResultSet">IResultSet</a> interface. This
|
||||||
@ -596,10 +590,10 @@ particular field field's offset should be used:</font></p>
|
|||||||
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt"><i>unsigned
|
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt"><i>unsigned
|
||||||
char* field_N_ptr = buffer + meta->getOffset(&status, n);</i></font></p>
|
char* field_N_ptr = buffer + meta->getOffset(&status, n);</i></font></p>
|
||||||
<p style="margin-bottom: 0cm; font-variant: normal; font-style: normal">
|
<p style="margin-bottom: 0cm; font-variant: normal; font-style: normal">
|
||||||
<font size="4" style="font-size: 14pt">where
|
<font size="4" style="font-size: 14pt">where n is the number of a
|
||||||
n is the number of a field in a message. That pointer should be
|
field in a message. That pointer should be casted to appropriate
|
||||||
casted to appropriate type, depending upon field type. For example,
|
type, depending upon field type. For example, for a VARCHAR field
|
||||||
for a VARCHAR field cast to struct vary should be used:</font></p>
|
cast to struct vary should be used:</font></p>
|
||||||
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt"><i>vary*
|
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt"><i>vary*
|
||||||
v_ptr = (vary*) (buffer + meta->getOffset(&status, n));</i></font></p>
|
v_ptr = (vary*) (buffer + meta->getOffset(&status, n));</i></font></p>
|
||||||
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">Now
|
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">Now
|
||||||
@ -617,8 +611,8 @@ metadata values like it's done in our samples 03.select.cpp and
|
|||||||
<p style="margin-bottom: 0cm"><br/>
|
<p style="margin-bottom: 0cm"><br/>
|
||||||
|
|
||||||
</p>
|
</p>
|
||||||
<h1><font size="4" style="font-size: 14pt">Using
|
<h1><font size="4" style="font-size: 14pt">Using FB_MESSAGE macro for
|
||||||
FB_MESSAGE macro for static messages.</font></h1>
|
static messages.</font></h1>
|
||||||
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">Working
|
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">Working
|
||||||
with data using offsets is rather efficient but requires a lot of
|
with data using offsets is rather efficient but requires a lot of
|
||||||
code to be written. In C++ this problem can be solved using
|
code to be written. In C++ this problem can be solved using
|
||||||
@ -667,12 +661,11 @@ class FbTimestamp, containing two public data members date and time
|
|||||||
of appropriate class, char - with struct <a href="#FbChar">FbChar</a>
|
of appropriate class, char - with struct <a href="#FbChar">FbChar</a>
|
||||||
and varchar – with struct <a href="#FbVarChar">FbVarChar</a>. For
|
and varchar – with struct <a href="#FbVarChar">FbVarChar</a>. For
|
||||||
each field preprocessor creates two data members in the message –
|
each field preprocessor creates two data members in the message –
|
||||||
</font><font size="4" style="font-size: 14pt"><i>name</i></font>
|
</font><font size="4" style="font-size: 14pt"><i>name</i></font> <font size="4" style="font-size: 14pt">for
|
||||||
<font size="4" style="font-size: 14pt">for
|
|
||||||
field/parameter value and </font><font size="4" style="font-size: 14pt"><i>nameNull</i></font>
|
field/parameter value and </font><font size="4" style="font-size: 14pt"><i>nameNull</i></font>
|
||||||
<font size="4" style="font-size: 14pt">for
|
<font size="4" style="font-size: 14pt">for NULL indicator. Message
|
||||||
NULL indicator. Message constructor has 2 parameters – pointer to
|
constructor has 2 parameters – pointer to status wrapper and master
|
||||||
status wrapper and master interface:</font></p>
|
interface:</font></p>
|
||||||
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt"><i>FB_MESSAGE(Output,
|
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt"><i>FB_MESSAGE(Output,
|
||||||
ThrowStatusWrapper,</i></font></p>
|
ThrowStatusWrapper,</i></font></p>
|
||||||
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt"><i>(FB_SMALLINT,
|
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt"><i>(FB_SMALLINT,
|
||||||
@ -717,8 +710,7 @@ sample 06.fb_message.cpp.</font></p>
|
|||||||
<p style="margin-bottom: 0cm"><br/>
|
<p style="margin-bottom: 0cm"><br/>
|
||||||
|
|
||||||
</p>
|
</p>
|
||||||
<h1><font size="4" style="font-size: 14pt">Working
|
<h1><font size="4" style="font-size: 14pt">Working with blobs.</font></h1>
|
||||||
with blobs.</font></h1>
|
|
||||||
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">For
|
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">For
|
||||||
blobs in message buffer firebird stores blob identifier – an 8-byte
|
blobs in message buffer firebird stores blob identifier – an 8-byte
|
||||||
entity which should be aligned on 4-byte boundary. Identifier has
|
entity which should be aligned on 4-byte boundary. Identifier has
|
||||||
@ -911,16 +903,16 @@ meta = batch->getMetadata(&status);</i></font></p>
|
|||||||
if you have passed your own format of messages to the batch you may
|
if you have passed your own format of messages to the batch you may
|
||||||
simply use it.</font></p>
|
simply use it.</font></p>
|
||||||
<p style="margin-bottom: 0cm; font-variant: normal; font-style: normal">
|
<p style="margin-bottom: 0cm; font-variant: normal; font-style: normal">
|
||||||
<font size="4" style="font-size: 14pt">In
|
<font size="4" style="font-size: 14pt">In the former text I suppose
|
||||||
the former text I suppose that some function fillNextMessage(unsigned
|
that some function fillNextMessage(unsigned char* data,
|
||||||
char* data, IMessageMetadata* metadata) is present and can fill
|
IMessageMetadata* metadata) is present and can fill buffer ‘data’
|
||||||
buffer ‘data’ according to passed format ‘metadata’. In order
|
according to passed format ‘metadata’. In order to work with
|
||||||
to work with messages we need a buffer for a data:</font></p>
|
messages we need a buffer for a data:</font></p>
|
||||||
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt"><i>unsigned
|
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt"><i>unsigned
|
||||||
char* data = new unsigned char[meta->getMessageLength(&status)];</i></font></p>
|
char* data = new unsigned char[meta->getMessageLength(&status)];</i></font></p>
|
||||||
<p style="margin-bottom: 0cm; font-variant: normal; font-style: normal">
|
<p style="margin-bottom: 0cm; font-variant: normal; font-style: normal">
|
||||||
<font size="4" style="font-size: 14pt">Now
|
<font size="4" style="font-size: 14pt">Now we can add some messages
|
||||||
we can add some messages full of data to the batch:</font></p>
|
full of data to the batch:</font></p>
|
||||||
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt"><i>fillNextMessage(data,
|
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt"><i>fillNextMessage(data,
|
||||||
meta);</i></font></p>
|
meta);</i></font></p>
|
||||||
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt"><i>batch->add(&status,
|
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt"><i>batch->add(&status,
|
||||||
@ -930,15 +922,15 @@ meta);</i></font></p>
|
|||||||
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt"><i>batch->add(&status,
|
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt"><i>batch->add(&status,
|
||||||
1, data);</i></font></p>
|
1, data);</i></font></p>
|
||||||
<p style="margin-bottom: 0cm; font-variant: normal; font-style: normal">
|
<p style="margin-bottom: 0cm; font-variant: normal; font-style: normal">
|
||||||
<font size="4" style="font-size: 14pt">An
|
<font size="4" style="font-size: 14pt">An alternative way of working
|
||||||
alternative way of working with messages (using FB_MESSAGE macro) is
|
with messages (using FB_MESSAGE macro) is present in the sample of
|
||||||
present in the sample of using batch interface 11.batch.cpp.</font></p>
|
using batch interface 11.batch.cpp.</font></p>
|
||||||
<p style="margin-bottom: 0cm"><br/>
|
<p style="margin-bottom: 0cm"><br/>
|
||||||
|
|
||||||
</p>
|
</p>
|
||||||
<p style="margin-bottom: 0cm; font-variant: normal; font-style: normal">
|
<p style="margin-bottom: 0cm; font-variant: normal; font-style: normal">
|
||||||
<font size="4" style="font-size: 14pt">Finally
|
<font size="4" style="font-size: 14pt">Finally batch should be
|
||||||
batch should be executed:</font></p>
|
executed:</font></p>
|
||||||
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt"><i><a href="#BatchCompletionState">IBatchCompletionState</a>*
|
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt"><i><a href="#BatchCompletionState">IBatchCompletionState</a>*
|
||||||
cs = batch->execute(&status, tra);</i></font></p>
|
cs = batch->execute(&status, tra);</i></font></p>
|
||||||
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">We
|
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">We
|
||||||
@ -949,19 +941,19 @@ Determine total number of messages processed by batch (it can be less
|
|||||||
than the number of messages passed to the batch if error happened and
|
than the number of messages passed to the batch if error happened and
|
||||||
an option enabling multiple errors during batch processing was not
|
an option enabling multiple errors during batch processing was not
|
||||||
turned on):</font></p>
|
turned on):</font></p>
|
||||||
<p><font size="4" style="font-size: 14pt"><i>unsigned
|
<p><font size="4" style="font-size: 14pt"><i>unsigned total =
|
||||||
total = cs->getSize(&status);</i></font></p>
|
cs->getSize(&status);</i></font></p>
|
||||||
<p><font size="4" style="font-size: 14pt">Now
|
<p><font size="4" style="font-size: 14pt">Now print the state of each
|
||||||
print the state of each message:</font></p>
|
message:</font></p>
|
||||||
<p><font size="4" style="font-size: 14pt"><i>for
|
<p><font size="4" style="font-size: 14pt"><i>for (unsigned p = 0; p <
|
||||||
(unsigned p = 0; p < total; ++p) printf(“Msg %u state %d\n”,
|
total; ++p) printf(“Msg %u state %d\n”, p, cs->getState(&status,
|
||||||
p, cs->getState(&status, p));</i></font></p>
|
p));</i></font></p>
|
||||||
<p style="font-variant: normal; font-style: normal"><font size="4" style="font-size: 14pt">When
|
<p style="font-variant: normal; font-style: normal"><font size="4" style="font-size: 14pt">When
|
||||||
finished analyzing completion state don’t forget to dispose it:</font></p>
|
finished analyzing completion state don’t forget to dispose it:</font></p>
|
||||||
<p><font size="4" style="font-size: 14pt"><i>cs->dispose();</i></font></p>
|
<p><font size="4" style="font-size: 14pt"><i>cs->dispose();</i></font></p>
|
||||||
<p><font color="#000000"><font size="4" style="font-size: 14pt">Full
|
<p><font color="#000000"><font size="4" style="font-size: 14pt">Full
|
||||||
sample of printing contents</font></font><font color="#000000">
|
sample of printing contents</font></font><font color="#000000"> of
|
||||||
of </font><font color="#000000"><font size="4" style="font-size: 14pt"><a href="#BatchCompletionState">BatchCompletionState</a>
|
</font><font color="#000000"><font size="4" style="font-size: 14pt"><a href="#BatchCompletionState">BatchCompletionState</a>
|
||||||
is in print_cs() function in sample 11.batch.cpp.</font></font></p>
|
is in print_cs() function in sample 11.batch.cpp.</font></font></p>
|
||||||
<p style="font-variant: normal; font-style: normal"><font size="4" style="font-size: 14pt">If
|
<p style="font-variant: normal; font-style: normal"><font size="4" style="font-size: 14pt">If
|
||||||
for some reason you want to make batch buffers empty not executing it
|
for some reason you want to make batch buffers empty not executing it
|
||||||
@ -969,18 +961,17 @@ for some reason you want to make batch buffers empty not executing it
|
|||||||
method:</font></p>
|
method:</font></p>
|
||||||
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt"><i>batch->cancel(&status);</i></font></p>
|
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt"><i>batch->cancel(&status);</i></font></p>
|
||||||
<p style="margin-bottom: 0cm; font-variant: normal; font-style: normal">
|
<p style="margin-bottom: 0cm; font-variant: normal; font-style: normal">
|
||||||
<font size="4" style="font-size: 14pt">Like
|
<font size="4" style="font-size: 14pt">Like the rest of our data
|
||||||
the rest of our data access interfaces Batch has special method to
|
access interfaces Batch has special method to close it:</font></p>
|
||||||
close it:</font></p>
|
|
||||||
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt"><i>batch->close(&status);</i></font></p>
|
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt"><i>batch->close(&status);</i></font></p>
|
||||||
<p style="margin-bottom: 0cm; font-variant: normal; font-style: normal">
|
<p style="margin-bottom: 0cm; font-variant: normal; font-style: normal">
|
||||||
<font size="4" style="font-size: 14pt">Standard
|
<font size="4" style="font-size: 14pt">Standard release() call may be
|
||||||
release() call may be used instead if one does not care about errors:</font></p>
|
used instead if one does not care about errors:</font></p>
|
||||||
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt"><i>batch->release();</i></font></p>
|
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt"><i>batch->release();</i></font></p>
|
||||||
<p style="margin-bottom: 0cm; font-variant: normal; font-style: normal">
|
<p style="margin-bottom: 0cm; font-variant: normal; font-style: normal">
|
||||||
<font size="4" style="font-size: 14pt">Described
|
<font size="4" style="font-size: 14pt">Described methods help to
|
||||||
methods help to implement all what one needs for JDBC-style prepared
|
implement all what one needs for JDBC-style prepared statement batch
|
||||||
statement batch operations. </font>
|
operations. </font>
|
||||||
</p>
|
</p>
|
||||||
<p style="margin-bottom: 0cm"><br/>
|
<p style="margin-bottom: 0cm"><br/>
|
||||||
|
|
||||||
@ -1002,27 +993,23 @@ returned in </font><font color="#000000"><font size="4" style="font-size: 14pt">
|
|||||||
An optimal batch size should be found for each particular case but
|
An optimal batch size should be found for each particular case but
|
||||||
sooner of all having it >1000 hardly gives you serious performance
|
sooner of all having it >1000 hardly gives you serious performance
|
||||||
increase.</font></font></p>
|
increase.</font></font></p>
|
||||||
<p><br/>
|
<p style="margin-bottom: 0cm"><br/>
|
||||||
<br/>
|
|
||||||
|
|
||||||
</p>
|
</p>
|
||||||
<p><font size="4" style="font-size: 14pt">One
|
<p><font size="4" style="font-size: 14pt">One can add more than
|
||||||
can add more than single message in one call to the batch. When doing
|
single message in one call to the batch. When doing it please
|
||||||
it please remember – messages should be appropriately aligned for
|
remember – messages should be appropriately aligned for this
|
||||||
this feature to work correctly. Required alignment and aligned size
|
feature to work correctly. Required alignment and aligned size of the
|
||||||
of the message should be obtained from <a href="#MessageMetadata">MessageMetadata</a>
|
message should be obtained from <a href="#MessageMetadata">MessageMetadata</a>
|
||||||
interface, for example:</font></p>
|
interface, for example:</font></p>
|
||||||
<p><font size="4" style="font-size: 14pt"><i>unsigned
|
<p><font size="4" style="font-size: 14pt"><i>unsigned aligned =
|
||||||
aligned = meta->getAlignedLength(&status);</i></font></p>
|
meta->getAlignedLength(&status);</i></font></p>
|
||||||
<p><font size="4" style="font-size: 14pt">Later
|
<p><font size="4" style="font-size: 14pt">Later that size will be
|
||||||
that size will be useful when allocating an array of messages and
|
useful when allocating an array of messages and working with it:</font></p>
|
||||||
working with it:</font></p>
|
<p><font size="4" style="font-size: 14pt"><i>unsigned char* data =
|
||||||
<p><font size="4" style="font-size: 14pt"><i>unsigned
|
new unsigned char[aligned * N]; // N is desired number of messages</i></font></p>
|
||||||
char* data = new unsigned char[aligned * N]; // N is desired number
|
<p><font size="4" style="font-size: 14pt"><i>for (int n = 0; n <
|
||||||
of messages</i></font></p>
|
N; ++n) fillNextMessage(&data[aligned * n], meta);</i></font></p>
|
||||||
<p><font size="4" style="font-size: 14pt"><i>for
|
|
||||||
(int n = 0; n < N; ++n) fillNextMessage(&data[aligned * n],
|
|
||||||
meta);</i></font></p>
|
|
||||||
<p><font size="4" style="font-size: 14pt"><i>batch->add(&status,
|
<p><font size="4" style="font-size: 14pt"><i>batch->add(&status,
|
||||||
N, data);</i></font></p>
|
N, data);</i></font></p>
|
||||||
<p style="font-variant: normal; font-style: normal"><font size="4" style="font-size: 14pt">After
|
<p style="font-variant: normal; font-style: normal"><font size="4" style="font-size: 14pt">After
|
||||||
@ -1031,19 +1018,18 @@ it batch may be executed or next portion of messages added to it.</font></p>
|
|||||||
<br/>
|
<br/>
|
||||||
|
|
||||||
</p>
|
</p>
|
||||||
<p><font size="4" style="font-size: 14pt">Blobs
|
<p><font size="4" style="font-size: 14pt">Blobs in general are not
|
||||||
in general are not compatible with batches – batch is efficient
|
compatible with batches – batch is efficient when one needs to pass
|
||||||
when one needs to pass a lot of small data to the server in single
|
a lot of small data to the server in single step, blobs are treated
|
||||||
step, blobs are treated as large objects and therefore in general it
|
as large objects and therefore in general it makes no sense to use
|
||||||
makes no sense to use them in batches. But on practice it often
|
them in batches. But on practice it often happens that blobs are not
|
||||||
happens that blobs are not too big – and in this case use of
|
too big – and in this case use of traditional blob API (create
|
||||||
traditional blob API (create blob, pass segments to the server, close
|
blob, pass segments to the server, close blob, pass blobs ID in the
|
||||||
blob, pass blobs ID in the message) kills performance, specially when
|
message) kills performance, specially when used over WAN. Therefore
|
||||||
used over WAN. Therefore in firebird batch supports passing blobs to
|
in firebird batch supports passing blobs to server inline, together
|
||||||
server inline, together with other messages. To use that feature
|
with other messages. To use that feature first of all <a href="#Batch_Blob_Policy">blob
|
||||||
first of all <a href="#Batch_Blob_Policy">blob usage policy</a> for a
|
usage policy</a> for a batch to be created should be set (as an
|
||||||
batch to be created should be set (as an option in <a href="#Batch_PB">parameters
|
option in <a href="#Batch_PB">parameters block</a>):</font></p>
|
||||||
block</a>):</font></p>
|
|
||||||
<p><font size="4" style="font-size: 14pt"><i>pb->insertInt(&status,
|
<p><font size="4" style="font-size: 14pt"><i>pb->insertInt(&status,
|
||||||
IBatch::BLOB_IDS, IBatch::BLOB_IDS_ENGINE);</i></font></p>
|
IBatch::BLOB_IDS, IBatch::BLOB_IDS_ENGINE);</i></font></p>
|
||||||
<p style="font-variant: normal; font-style: normal"><font size="4" style="font-size: 14pt">In
|
<p style="font-variant: normal; font-style: normal"><font size="4" style="font-size: 14pt">In
|
||||||
@ -1053,29 +1039,26 @@ that’s the simplest and rather common usage. Imagine that the
|
|||||||
message is described as follows:</font></p>
|
message is described as follows:</font></p>
|
||||||
<p style="font-variant: normal"><font size="4" style="font-size: 14pt"><i>FB_MESSAGE(Msg,
|
<p style="font-variant: normal"><font size="4" style="font-size: 14pt"><i>FB_MESSAGE(Msg,
|
||||||
ThrowStatusWrapper,</i></font></p>
|
ThrowStatusWrapper,</i></font></p>
|
||||||
<p><font size="4" style="font-size: 14pt"><i>(FB_VARCHAR(5),
|
<p><font size="4" style="font-size: 14pt"><i>(FB_VARCHAR(5), id)</i></font></p>
|
||||||
id)</i></font></p>
|
<p><font size="4" style="font-size: 14pt"><i>(FB_VARCHAR(10), name)</i></font></p>
|
||||||
<p><font size="4" style="font-size: 14pt"><i>(FB_VARCHAR(10),
|
<p><font size="4" style="font-size: 14pt"><i>(FB_BLOB, desc)</i></font></p>
|
||||||
name)</i></font></p>
|
<p><font size="4" style="font-size: 14pt"><i>) project(&status,
|
||||||
<p><font size="4" style="font-size: 14pt"><i>(FB_BLOB,
|
master);</i></font></p>
|
||||||
desc)</i></font></p>
|
|
||||||
<p><font size="4" style="font-size: 14pt"><i>)
|
|
||||||
project(&status, master);</i></font></p>
|
|
||||||
<p style="font-variant: normal; font-style: normal"><font size="4" style="font-size: 14pt">In
|
<p style="font-variant: normal; font-style: normal"><font size="4" style="font-size: 14pt">In
|
||||||
that case to send a message containing blob to the server one can do
|
that case to send a message containing blob to the server one can do
|
||||||
something like this:</font></p>
|
something like this:</font></p>
|
||||||
<p><font size="4" style="font-size: 14pt"><i>project->id
|
<p><font size="4" style="font-size: 14pt"><i>project->id =
|
||||||
= ++idCounter;</i></font></p>
|
++idCounter;</i></font></p>
|
||||||
<p><font size="4" style="font-size: 14pt"><i>project->name.set(currentName);</i></font></p>
|
<p><font size="4" style="font-size: 14pt"><i>project->name.set(currentName);</i></font></p>
|
||||||
<p><font size="4" style="font-size: 14pt"><i>batch->addBlob(&status,
|
<p><font size="4" style="font-size: 14pt"><i>batch->addBlob(&status,
|
||||||
descriptionSize, descriptionText, &project->desc);</i></font></p>
|
descriptionSize, descriptionText, &project->desc);</i></font></p>
|
||||||
<p><font size="4" style="font-size: 14pt"><i>batch->add(&status,
|
<p><font size="4" style="font-size: 14pt"><i>batch->add(&status,
|
||||||
1, project.getData());</i></font></p>
|
1, project.getData());</i></font></p>
|
||||||
<p style="margin-bottom: 0cm; font-variant: normal; font-style: normal">
|
<p style="margin-bottom: 0cm; font-variant: normal; font-style: normal">
|
||||||
<font size="4" style="font-size: 14pt">If
|
<font size="4" style="font-size: 14pt">If some blob happened to be
|
||||||
some blob happened to be big enough not to fit into your existing
|
big enough not to fit into your existing buffer you may instead
|
||||||
buffer you may instead reallocating buffer use appendBlobData()
|
reallocating buffer use appendBlobData() method. It appends more data
|
||||||
method. It appends more data to last added blob. </font>
|
to last added blob. </font>
|
||||||
</p>
|
</p>
|
||||||
<p style="font-variant: normal"><font size="4" style="font-size: 14pt"><i>batch->addBlob(&status,
|
<p style="font-variant: normal"><font size="4" style="font-size: 14pt"><i>batch->addBlob(&status,
|
||||||
descriptionSize, descriptionText, &project→desc, bpbLength,
|
descriptionSize, descriptionText, &project→desc, bpbLength,
|
||||||
@ -1085,13 +1068,13 @@ adding first part of blob get next portion of data into
|
|||||||
descriptionText, update descriptionSize and:</font></p>
|
descriptionText, update descriptionSize and:</font></p>
|
||||||
<p style="font-variant: normal"><font size="4" style="font-size: 14pt"><i>batch->appendBlobData(&status,
|
<p style="font-variant: normal"><font size="4" style="font-size: 14pt"><i>batch->appendBlobData(&status,
|
||||||
descriptionSize, descriptionText);</i></font></p>
|
descriptionSize, descriptionText);</i></font></p>
|
||||||
<p><font size="4" style="font-size: 14pt">This
|
<p><font size="4" style="font-size: 14pt">This may be done in a loop
|
||||||
may be done in a loop but take care not to overflow internal batch
|
but take care not to overflow internal batch buffers – it’s size
|
||||||
buffers – it’s size is controlled by <a href="#Batch_PB">BUFFER_BYTES_SIZE</a>
|
is controlled by <a href="#Batch_PB">BUFFER_BYTES_SIZE</a> option
|
||||||
option when creating batch interface but can’t exceed 256Mb
|
when creating batch interface but can’t exceed 256Mb (default is
|
||||||
(default is 16Mb). If you need to process such big blob (for example
|
16Mb). If you need to process such big blob (for example on the
|
||||||
on the background of a lot of small one – this can explain use of
|
background of a lot of small one – this can explain use of batch)
|
||||||
batch) just use standard blob API and <a href="#Batch::registerBlob">registerBlob</a>
|
just use standard blob API and <a href="#Batch::registerBlob">registerBlob</a>
|
||||||
method of <a href="#Batch">Batch</a> interface.</font></p>
|
method of <a href="#Batch">Batch</a> interface.</font></p>
|
||||||
<p style="font-variant: normal; font-style: normal"><font size="4" style="font-size: 14pt">One
|
<p style="font-variant: normal; font-style: normal"><font size="4" style="font-size: 14pt">One
|
||||||
more possible choice of blob policy is BLOB_IDS_USER. Usage at the
|
more possible choice of blob policy is BLOB_IDS_USER. Usage at the
|
||||||
@ -1104,17 +1087,16 @@ imagine a case when you get blobs and other data in relatively
|
|||||||
independent streams (blocks in a file for example) and some good IDs
|
independent streams (blocks in a file for example) and some good IDs
|
||||||
are already present in them. In such case use of user-supplied blob
|
are already present in them. In such case use of user-supplied blob
|
||||||
IDs can greatly simplify your code.</font></p>
|
IDs can greatly simplify your code.</font></p>
|
||||||
<p><font size="4" style="font-size: 14pt">Please
|
<p><font size="4" style="font-size: 14pt">Please take into an account
|
||||||
take into an account – unlike blobs created using regular
|
– unlike blobs created using regular <a href="#Attachment">createBlob</a>()
|
||||||
<a href="#Attachment">createBlob</a>() blobs created by <a href="#Batch">Batch</a>
|
blobs created by <a href="#Batch">Batch</a> interface are by default
|
||||||
interface are by default stream, not segmented. Segmented blobs
|
stream, not segmented. Segmented blobs provide nothing interesting
|
||||||
provide nothing interesting compared with stream one and therefore
|
compared with stream one and therefore not recommended to be used in
|
||||||
not recommended to be used in new development, we support that format
|
new development, we support that format only for backward
|
||||||
only for backward compatibility reasons. If you really need segmented
|
compatibility reasons. If you really need segmented blobs this
|
||||||
blobs this default may be overridden by calling:</font></p>
|
default may be overridden by calling:</font></p>
|
||||||
<p><font size="4" style="font-size: 14pt"><i>batch->setDefaultBpb(&status,</i></font>
|
<p><font size="4" style="font-size: 14pt"><i>batch->setDefaultBpb(&status,</i></font>
|
||||||
<font size="4" style="font-size: 14pt"><i>bpbLength,
|
<font size="4" style="font-size: 14pt"><i>bpbLength, bpb);</i></font></p>
|
||||||
bpb);</i></font></p>
|
|
||||||
<p style="font-variant: normal; font-style: normal"><font size="4" style="font-size: 14pt">Certainly
|
<p style="font-variant: normal; font-style: normal"><font size="4" style="font-size: 14pt">Certainly
|
||||||
passed BPB may contain any other blob creation parameters too. As you
|
passed BPB may contain any other blob creation parameters too. As you
|
||||||
may have already noticed you may also pass BPB directly to addBlob()
|
may have already noticed you may also pass BPB directly to addBlob()
|
||||||
@ -1124,13 +1106,12 @@ to segmented blobs – call to addBlob() will add first segment to
|
|||||||
the blob, following calls to appendBlobData() will add more segments.
|
the blob, following calls to appendBlobData() will add more segments.
|
||||||
Do not forget that segment size is limited to 64Kb – 1, an attempt
|
Do not forget that segment size is limited to 64Kb – 1, an attempt
|
||||||
to pass more data in a single call with cause an error.</font></p>
|
to pass more data in a single call with cause an error.</font></p>
|
||||||
<p><font size="4" style="font-size: 14pt">Next
|
<p><font size="4" style="font-size: 14pt">Next step when working with
|
||||||
step when working with existing blob streams is use of
|
existing blob streams is use of addBlobStream() method. Using it one
|
||||||
addBlobStream() method. Using it one can add more than one blob to
|
can add more than one blob to the batch per single call. Blob stream
|
||||||
the batch per single call. Blob stream is a sequence of blobs, each
|
is a sequence of blobs, each starts with blob header. Header should
|
||||||
starts with blob header. Header should be appropriately aligned -
|
be appropriately aligned - <a href="#Batch">Batch</a> interface
|
||||||
<a href="#Batch">Batch</a> interface provides special call for this
|
provides special call for this purpose:</font></p>
|
||||||
purpose:</font></p>
|
|
||||||
<p style="font-variant: normal"><font size="4" style="font-size: 14pt"><i>unsigned
|
<p style="font-variant: normal"><font size="4" style="font-size: 14pt"><i>unsigned
|
||||||
alignment = batch->getBlobAlignment(&status);</i></font></p>
|
alignment = batch->getBlobAlignment(&status);</i></font></p>
|
||||||
<p style="font-variant: normal; font-style: normal"><font size="4" style="font-size: 14pt">It’s
|
<p style="font-variant: normal; font-style: normal"><font size="4" style="font-size: 14pt">It’s
|
||||||
@ -1161,8 +1142,7 @@ ID must be zero and BPB size must always be zero too. Typically you
|
|||||||
will want to have one continuation record per addBlobStream() call.</font></p>
|
will want to have one continuation record per addBlobStream() call.</font></p>
|
||||||
<p><a name="Batch::registerBlob"></a><font size="4" style="font-size: 14pt">Last
|
<p><a name="Batch::registerBlob"></a><font size="4" style="font-size: 14pt">Last
|
||||||
method used to work with blobs stands alone from the first three that
|
method used to work with blobs stands alone from the first three that
|
||||||
pass blob data inline with the rest of batch data </font>–
|
pass blob data inline with the rest of batch data </font>– <font size="4" style="font-size: 14pt">it’s
|
||||||
<font size="4" style="font-size: 14pt">it’s
|
|
||||||
needed to register in a batch ID of a blob created using standard
|
needed to register in a batch ID of a blob created using standard
|
||||||
blob API. This may be unavoidable if one needs to pass to a batch
|
blob API. This may be unavoidable if one needs to pass to a batch
|
||||||
really big blob. Do not use ID of such blob in batch directly –
|
really big blob. Do not use ID of such blob in batch directly –
|
||||||
@ -1171,50 +1151,47 @@ do:</font></p>
|
|||||||
<p><font size="4" style="font-size: 14pt"><i>batch->registerBlob(&status,
|
<p><font size="4" style="font-size: 14pt"><i>batch->registerBlob(&status,
|
||||||
&realId, &msg->desc);</i></font></p>
|
&realId, &msg->desc);</i></font></p>
|
||||||
<p style="margin-bottom: 0cm; font-variant: normal; font-style: normal">
|
<p style="margin-bottom: 0cm; font-variant: normal; font-style: normal">
|
||||||
<font size="4" style="font-size: 14pt">If
|
<font size="4" style="font-size: 14pt">If blob policy makes firebird
|
||||||
blob policy makes firebird engine generate blob IDs this code is
|
engine generate blob IDs this code is enough to correctly register
|
||||||
enough to correctly register existing blob in a batch. In other cases
|
existing blob in a batch. In other cases you will have to assign
|
||||||
you will have to assign correct (from batch POV) ID to msg->desc.</font></p>
|
correct (from batch POV) ID to msg->desc.</font></p>
|
||||||
<p style="margin-bottom: 0cm"><br/>
|
<p style="margin-bottom: 0cm"><br/>
|
||||||
|
|
||||||
</p>
|
</p>
|
||||||
<p style="margin-bottom: 0cm; font-variant: normal; font-style: normal">
|
<p style="margin-bottom: 0cm; font-variant: normal; font-style: normal">
|
||||||
<font size="4" style="font-size: 14pt">Almost
|
<font size="4" style="font-size: 14pt">Almost all mentioned methods
|
||||||
all mentioned methods are used in 11.batch.cpp – please use it to
|
are used in 11.batch.cpp – please use it to see an alive sample of
|
||||||
see an alive sample of batching in firebird.</font></p>
|
batching in firebird.</font></p>
|
||||||
<p style="margin-bottom: 0cm"><br/>
|
<p style="margin-bottom: 0cm"><br/>
|
||||||
|
|
||||||
</p>
|
</p>
|
||||||
<p style="margin-bottom: 0cm; font-variant: normal; font-style: normal">
|
<p style="margin-bottom: 0cm; font-variant: normal; font-style: normal">
|
||||||
<font size="4" style="font-size: 14pt">Two
|
<font size="4" style="font-size: 14pt">Two words about access to
|
||||||
words about access to batches from ISC API - one can execute prepared
|
batches from ISC API - one can execute prepared ISC statement in
|
||||||
ISC statement in batch mode. Main support for it is presence of two
|
batch mode. Main support for it is presence of two new API functions,
|
||||||
new API functions, namely fb_get_transaction_interface &
|
namely fb_get_transaction_interface & fb_get_statement_interface,
|
||||||
fb_get_statement_interface, which make it possible to access
|
which make it possible to access appropriate interfaces identical to
|
||||||
appropriate interfaces identical to existing ISC handles. An example
|
existing ISC handles. An example of it is present in
|
||||||
of it is present in 12.batch_isc.cpp.</font></p>
|
12.batch_isc.cpp.</font></p>
|
||||||
<p style="margin-bottom: 0cm"><br/>
|
<p style="margin-bottom: 0cm"><br/>
|
||||||
|
|
||||||
</p>
|
</p>
|
||||||
<h1><font size="4" style="font-size: 14pt">Working
|
<h1><font size="4" style="font-size: 14pt">Working with events.</font></h1>
|
||||||
with events.</font></h1>
|
|
||||||
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">Events
|
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">Events
|
||||||
interface was not completed in FB3, we expect to have something more
|
interface was not completed in FB3, we expect to have something more
|
||||||
interesting in next version. The minimum existing support is as
|
interesting in next version. The minimum existing support is as
|
||||||
follows: <a href="#Attachment">IAttachment</a> contains call
|
follows: <a href="#Attachment">IAttachment</a> contains call
|
||||||
queEvents() which performs almost same functions as isc_que_events()
|
queEvents() which performs almost same functions as isc_que_events()
|
||||||
call. Instead the pair of parameters </font><font size="4" style="font-size: 14pt"><i>FPTR_EVENT_CALLBACK
|
call. Instead the pair of parameters </font><font size="4" style="font-size: 14pt"><i>FPTR_EVENT_CALLBACK
|
||||||
ast</i></font> <font size="4" style="font-size: 14pt">and
|
ast</i></font> <font size="4" style="font-size: 14pt">and </font><font size="4" style="font-size: 14pt"><i>void*
|
||||||
</font><font size="4" style="font-size: 14pt"><i>void*
|
arg</i></font><font size="4" style="font-size: 14pt">, required to
|
||||||
arg</i></font><font size="4" style="font-size: 14pt">,
|
invoke user code when event happens in firebird engine, callback
|
||||||
required to invoke user code when event happens in firebird engine,
|
interface IEventCallback is used. This is traditional approach which
|
||||||
callback interface IEventCallback is used. This is traditional
|
helps to avoid non-safe casts from void* in user function. Another
|
||||||
approach which helps to avoid non-safe casts from void* in user
|
important difference is that instead event identifier (a kind of
|
||||||
function. Another important difference is that instead event
|
handler) this function returns reference counted interface <a href="#Events">IEvents</a>
|
||||||
identifier (a kind of handler) this function returns reference
|
having method cancel() used when waiting for event should be stopped.
|
||||||
counted interface <a href="#Events">IEvents</a> having method
|
Unlike identifier which is automatically destroyed when event arrives
|
||||||
cancel() used when waiting for event should be stopped. Unlike
|
|
||||||
identifier which is automatically destroyed when event arrives
|
|
||||||
interface can not be automatically destroyed – in case when event
|
interface can not be automatically destroyed – in case when event
|
||||||
is received right before canceling interface call to cancel() would
|
is received right before canceling interface call to cancel() would
|
||||||
cause segfault when interface is already destroyed. Therefore
|
cause segfault when interface is already destroyed. Therefore
|
||||||
@ -1235,8 +1212,7 @@ with ISC API. Please use for additional details our sample
|
|||||||
<p style="margin-bottom: 0cm"><br/>
|
<p style="margin-bottom: 0cm"><br/>
|
||||||
|
|
||||||
</p>
|
</p>
|
||||||
<h1><font size="4" style="font-size: 14pt">Using
|
<h1><font size="4" style="font-size: 14pt">Using services.</font></h1>
|
||||||
services.</font></h1>
|
|
||||||
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">To
|
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">To
|
||||||
begin to use services one should first of all connect to service
|
begin to use services one should first of all connect to service
|
||||||
manager. This is done using attachServiceManager() method of
|
manager. This is done using attachServiceManager() method of
|
||||||
@ -1364,15 +1340,14 @@ plugins.</font></font></p>
|
|||||||
write a plugin means to implement some interfaces and place your
|
write a plugin means to implement some interfaces and place your
|
||||||
implementation into dynamic library (.dll in windows or .so in linux)
|
implementation into dynamic library (.dll in windows or .so in linux)
|
||||||
later referenced as </font><font size="4" style="font-size: 14pt"><i>plugin
|
later referenced as </font><font size="4" style="font-size: 14pt"><i>plugin
|
||||||
module</i></font> <font size="4" style="font-size: 14pt">or
|
module</i></font> <font size="4" style="font-size: 14pt">or just
|
||||||
just </font><font size="4" style="font-size: 14pt"><i>module</i></font><font size="4" style="font-size: 14pt">.
|
</font><font size="4" style="font-size: 14pt"><i>module</i></font><font size="4" style="font-size: 14pt">.
|
||||||
In most cases single plugin is placed</font>
|
In most cases single plugin is placed</font> <font size="4" style="font-size: 14pt">into</font>
|
||||||
<font size="4" style="font-size: 14pt">into</font>
|
<font size="4" style="font-size: 14pt">dynamic library but in common
|
||||||
<font size="4" style="font-size: 14pt">dynamic
|
case multiple plugins may coexist in single dynamic library. One of
|
||||||
library but in common case multiple plugins may coexist in single
|
that interfaces – <a href="#PluginModule">IPluginModule</a> – is
|
||||||
dynamic library. One of that interfaces – <a href="#PluginModule">IPluginModule</a>
|
module-wide (as more or less clear from it's name), others are per
|
||||||
– is module-wide (as more or less clear from it's name), others are
|
plugin. Also each plugin module should contain special exported
|
||||||
per plugin. Also each plugin module should contain special exported
|
|
||||||
entrypoint firebird_plugin() which name is defined in include file
|
entrypoint firebird_plugin() which name is defined in include file
|
||||||
firebird/Interfaces.h as FB_PLUGIN_ENTRY_POINT.</font></p>
|
firebird/Interfaces.h as FB_PLUGIN_ENTRY_POINT.</font></p>
|
||||||
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">In
|
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">In
|
||||||
@ -1392,28 +1367,28 @@ sample yourself and learn it when reading later.</font></p>
|
|||||||
<p style="margin-bottom: 0cm"><br/>
|
<p style="margin-bottom: 0cm"><br/>
|
||||||
|
|
||||||
</p>
|
</p>
|
||||||
<h1><font size="4" style="font-size: 14pt">Implementation
|
<h1><font size="4" style="font-size: 14pt">Implementation of plugin
|
||||||
of plugin module.</font></h1>
|
module.</font></h1>
|
||||||
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">Plugins
|
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">Plugins
|
||||||
actively interact with special firebird component called </font><font size="4" style="font-size: 14pt"><i>plugin
|
actively interact with special firebird component called </font><font size="4" style="font-size: 14pt"><i>plugin
|
||||||
manager</i></font><font size="4" style="font-size: 14pt">.
|
manager</i></font><font size="4" style="font-size: 14pt">. In
|
||||||
In particular plugin manager should be aware what plugin modules were
|
particular plugin manager should be aware what plugin modules were
|
||||||
loaded and must be notified if operating system tries to unload one
|
loaded and must be notified if operating system tries to unload one
|
||||||
of that modules without explicit plugin manager command (this may
|
of that modules without explicit plugin manager command (this may
|
||||||
happen first of all when using embedded access – when exit() is
|
happen first of all when using embedded access – when exit() is
|
||||||
called in a program or main firebird library </font><font size="4" style="font-size: 14pt"><i>fbclient</i></font>
|
called in a program or main firebird library </font><font size="4" style="font-size: 14pt"><i>fbclient</i></font>
|
||||||
<font size="4" style="font-size: 14pt">is
|
<font size="4" style="font-size: 14pt">is unloaded). Primary task of
|
||||||
unloaded). Primary task of IPluginModule interface is that
|
IPluginModule interface is that notification. First of all one must
|
||||||
notification. First of all one must decide - how to detect that
|
decide - how to detect that module is going to be unloaded? When
|
||||||
module is going to be unloaded? When dynamic library is unloaded for
|
dynamic library is unloaded for some reason a lot of OS-dependent
|
||||||
some reason a lot of OS-dependent actions is performed and some of
|
actions is performed and some of that actions may be used to detect
|
||||||
that actions may be used to detect this fact in the program. When
|
this fact in the program. When writing plugins distributed with
|
||||||
writing plugins distributed with firebird we always use invocation of
|
firebird we always use invocation of destructor of global variable.
|
||||||
destructor of global variable. The big “plus” for this method is
|
The big “plus” for this method is that it is OS independent
|
||||||
that it is OS independent (though something like atexit() function
|
(though something like atexit() function maybe also used
|
||||||
maybe also used successfully). But use of destructor makes it
|
successfully). But use of destructor makes it possible to easily
|
||||||
possible to easily concentrate almost everything related with unload
|
concentrate almost everything related with unload detection in single
|
||||||
detection in single class implementing at the same time <a href="#PluginModule">IPluginModule</a>
|
class implementing at the same time <a href="#PluginModule">IPluginModule</a>
|
||||||
interface.</font></p>
|
interface.</font></p>
|
||||||
<p style="margin-bottom: 0cm"><br/>
|
<p style="margin-bottom: 0cm"><br/>
|
||||||
|
|
||||||
@ -1480,15 +1455,15 @@ It's passed to registerModule() function and saved in private
|
|||||||
variable, at the same time module is registered in plugin manager by
|
variable, at the same time module is registered in plugin manager by
|
||||||
the call to registerModule() method with own address as a single
|
the call to registerModule() method with own address as a single
|
||||||
parameter. Variable </font><font size="4" style="font-size: 14pt"><i>pluginManager
|
parameter. Variable </font><font size="4" style="font-size: 14pt"><i>pluginManager
|
||||||
</i></font><font size="4" style="font-size: 14pt">not
|
</i></font><font size="4" style="font-size: 14pt">not only stores
|
||||||
only stores pointer to interface, at the same time it serves as a
|
pointer to interface, at the same time it serves as a flag that
|
||||||
flag that module is registered. When destructor of registered module
|
module is registered. When destructor of registered module is invoked
|
||||||
is invoked it notifies plugin manager (yes, this is what for this
|
it notifies plugin manager (yes, this is what for this class exists!)
|
||||||
class exists!) about unexpected unload by the call to
|
about unexpected unload by the call to unregisterModule() passing
|
||||||
unregisterModule() passing pointer to itself. When plugin manager is
|
pointer to itself. When plugin manager is going to unload module in
|
||||||
going to unload module in regular way in first of all calls doClean()
|
regular way in first of all calls doClean() method changing module
|
||||||
method changing module state to unregistered and this avoiding call
|
state to unregistered and this avoiding call to unregisterModule()
|
||||||
to unregisterModule() when OS performs actual unload.</font></p>
|
when OS performs actual unload.</font></p>
|
||||||
<p style="margin-bottom: 0cm"><br/>
|
<p style="margin-bottom: 0cm"><br/>
|
||||||
|
|
||||||
</p>
|
</p>
|
||||||
@ -1502,8 +1477,8 @@ registerMe() function from FB_PLUGIN_ENTRY_POINT.</font></p>
|
|||||||
<p style="margin-bottom: 0cm"><br/>
|
<p style="margin-bottom: 0cm"><br/>
|
||||||
|
|
||||||
</p>
|
</p>
|
||||||
<h1><font size="4" style="font-size: 14pt">Core
|
<h1><font size="4" style="font-size: 14pt">Core interface of any
|
||||||
interface of any plugin.</font></h1>
|
plugin.</font></h1>
|
||||||
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">Let's
|
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">Let's
|
||||||
start implementing plugin itself. The type of main interface depends
|
start implementing plugin itself. The type of main interface depends
|
||||||
upon plugin type (which is obvious), but all of them are based on
|
upon plugin type (which is obvious), but all of them are based on
|
||||||
@ -1534,15 +1509,14 @@ config(cnf), refCounter(0), owner(NULL)</i></font></p>
|
|||||||
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt"><i>config->addRef();</i></font></p>
|
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt"><i>config->addRef();</i></font></p>
|
||||||
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt"><i>}</i></font></p>
|
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt"><i>}</i></font></p>
|
||||||
<p style="margin-bottom: 0cm; font-variant: normal; font-style: normal">
|
<p style="margin-bottom: 0cm; font-variant: normal; font-style: normal">
|
||||||
<font size="4" style="font-size: 14pt">Constructor
|
<font size="4" style="font-size: 14pt">Constructor gets as parameter
|
||||||
gets as parameter plugin configuration interface. If you are going to
|
plugin configuration interface. If you are going to have you plugin
|
||||||
have you plugin configured in some way it's good idea to save this
|
configured in some way it's good idea to save this interface in your
|
||||||
interface in your plugin and use it later. This will let you use
|
plugin and use it later. This will let you use common for all
|
||||||
common for all firebird configuration style letting users have
|
firebird configuration style letting users have familiar
|
||||||
familiar configuration and minimize code written. Certainly when
|
configuration and minimize code written. Certainly when saving any
|
||||||
saving any reference counted interface it's better not forget to add
|
reference counted interface it's better not forget to add reference
|
||||||
reference to it. Also set reference counter to 0 and plugin owner to
|
to it. Also set reference counter to 0 and plugin owner to NULL.</font></p>
|
||||||
NULL.</font></p>
|
|
||||||
<p style="margin-bottom: 0cm"><br/>
|
<p style="margin-bottom: 0cm"><br/>
|
||||||
|
|
||||||
</p>
|
</p>
|
||||||
@ -1551,9 +1525,9 @@ NULL.</font></p>
|
|||||||
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt"><i>config->release();</i></font></p>
|
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt"><i>config->release();</i></font></p>
|
||||||
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt"><i>}</i></font></p>
|
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt"><i>}</i></font></p>
|
||||||
<p style="margin-bottom: 0cm; font-variant: normal; font-style: normal">
|
<p style="margin-bottom: 0cm; font-variant: normal; font-style: normal">
|
||||||
<font size="4" style="font-size: 14pt">Destructor
|
<font size="4" style="font-size: 14pt">Destructor releases config
|
||||||
releases config interface. Pay attention – we do not change
|
interface. Pay attention – we do not change reference counter of
|
||||||
reference counter of our owner cause it owns us, not we own it.</font></p>
|
our owner cause it owns us, not we own it.</font></p>
|
||||||
<p style="margin-bottom: 0cm"><br/>
|
<p style="margin-bottom: 0cm"><br/>
|
||||||
|
|
||||||
</p>
|
</p>
|
||||||
@ -1582,8 +1556,8 @@ addRef()</i></font></p>
|
|||||||
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt"><i>++refCounter;</i></font></p>
|
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt"><i>++refCounter;</i></font></p>
|
||||||
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt"><i>}</i></font></p>
|
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt"><i>}</i></font></p>
|
||||||
<p style="margin-bottom: 0cm; font-variant: normal; font-style: normal">
|
<p style="margin-bottom: 0cm; font-variant: normal; font-style: normal">
|
||||||
<font size="4" style="font-size: 14pt">Absolutely
|
<font size="4" style="font-size: 14pt">Absolutely typical
|
||||||
typical implementation of reference counted object.</font></p>
|
implementation of reference counted object.</font></p>
|
||||||
<p style="margin-bottom: 0cm"><br/>
|
<p style="margin-bottom: 0cm"><br/>
|
||||||
|
|
||||||
</p>
|
</p>
|
||||||
@ -1605,8 +1579,8 @@ getOwner()</i></font></p>
|
|||||||
owner;</i></font></p>
|
owner;</i></font></p>
|
||||||
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt"><i>}</i></font></p>
|
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt"><i>}</i></font></p>
|
||||||
<p style="margin-bottom: 0cm; font-variant: normal; font-style: normal">
|
<p style="margin-bottom: 0cm; font-variant: normal; font-style: normal">
|
||||||
<font size="4" style="font-size: 14pt">As
|
<font size="4" style="font-size: 14pt">As it was promised
|
||||||
it was promised implementation of IPluginBase is trivial.</font></p>
|
implementation of IPluginBase is trivial.</font></p>
|
||||||
<p style="margin-bottom: 0cm"><br/>
|
<p style="margin-bottom: 0cm"><br/>
|
||||||
|
|
||||||
</p>
|
</p>
|
||||||
@ -1635,8 +1609,7 @@ lo-o-o-ot of code to make them useful) interface is ready.</font></p>
|
|||||||
<p style="margin-bottom: 0cm"><br/>
|
<p style="margin-bottom: 0cm"><br/>
|
||||||
|
|
||||||
</p>
|
</p>
|
||||||
<h1><font size="4" style="font-size: 14pt">Plugin's
|
<h1><font size="4" style="font-size: 14pt">Plugin's factory.</font></h1>
|
||||||
factory.</font></h1>
|
|
||||||
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">One
|
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">One
|
||||||
more interface required for plugin to work is <a href="#PluginFactory">IPluginFactory</a>.
|
more interface required for plugin to work is <a href="#PluginFactory">IPluginFactory</a>.
|
||||||
Factory creates instances of plugin and returns them to plugin
|
Factory creates instances of plugin and returns them to plugin
|
||||||
@ -1660,12 +1633,12 @@ p;</i></font></p>
|
|||||||
|
|
||||||
</p>
|
</p>
|
||||||
<p style="margin-bottom: 0cm; font-variant: normal; font-style: normal">
|
<p style="margin-bottom: 0cm; font-variant: normal; font-style: normal">
|
||||||
<font size="4" style="font-size: 14pt">Here
|
<font size="4" style="font-size: 14pt">Here attention should be payed
|
||||||
attention should be payed to the fact that even in a case when code
|
to the fact that even in a case when code in a function may throw
|
||||||
in a function may throw exceptions (operator new may throw in a case
|
exceptions (operator new may throw in a case when memory exhausted)
|
||||||
when memory exhausted) one need not always manually define try/catch
|
one need not always manually define try/catch block –
|
||||||
block – implementation of firebird interfaces does this job for
|
implementation of firebird interfaces does this job for you, in
|
||||||
you, in implementation of IPluginFactory it's placed into template
|
implementation of IPluginFactory it's placed into template
|
||||||
IPluginFactoryImpl. Take into an account that default status wrappers
|
IPluginFactoryImpl. Take into an account that default status wrappers
|
||||||
perform meaning-full processing only for FbException. But if you
|
perform meaning-full processing only for FbException. But if you
|
||||||
(that definitely makes sense if you work on some big project) define
|
(that definitely makes sense if you work on some big project) define
|
||||||
@ -1674,8 +1647,8 @@ useful information about it from your plugin.</font></p>
|
|||||||
<p style="margin-bottom: 0cm"><br/>
|
<p style="margin-bottom: 0cm"><br/>
|
||||||
|
|
||||||
</p>
|
</p>
|
||||||
<h1><font size="4" style="font-size: 14pt">Plugin
|
<h1><font size="4" style="font-size: 14pt">Plugin module
|
||||||
module initialization entrypoint.</font></h1>
|
initialization entrypoint.</font></h1>
|
||||||
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">When
|
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">When
|
||||||
plugin manager loads plugin module it invokes module initializing
|
plugin manager loads plugin module it invokes module initializing
|
||||||
routine – the only exported from plugin function
|
routine – the only exported from plugin function
|
||||||
@ -1749,8 +1722,7 @@ direct analogue in old API, that analogue is provided.</font></p>
|
|||||||
<p style="margin-bottom: 0cm"><br/>
|
<p style="margin-bottom: 0cm"><br/>
|
||||||
|
|
||||||
</p>
|
</p>
|
||||||
<h1><font size="4" style="font-size: 14pt">Generic
|
<h1><font size="4" style="font-size: 14pt">Generic interfaces.</font></h1>
|
||||||
interfaces.</font></h1>
|
|
||||||
<p style="margin-bottom: 0cm"><a name="Attachment"></a><font size="4" style="font-size: 14pt">Attachment
|
<p style="margin-bottom: 0cm"><a name="Attachment"></a><font size="4" style="font-size: 14pt">Attachment
|
||||||
interface – replaces isc_db_handle:</font></p>
|
interface – replaces isc_db_handle:</font></p>
|
||||||
<ol>
|
<ol>
|
||||||
@ -1827,12 +1799,10 @@ interface – replaces isc_db_handle:</font></p>
|
|||||||
<li><p><font size="4" style="font-size: 14pt">I</font><font face="Liberation Serif, serif"><font size="4" style="font-size: 14pt">Batch*
|
<li><p><font size="4" style="font-size: 14pt">I</font><font face="Liberation Serif, serif"><font size="4" style="font-size: 14pt">Batch*
|
||||||
createBatch(StatusType* status, ITransaction* transaction, unsigned
|
createBatch(StatusType* status, ITransaction* transaction, unsigned
|
||||||
stmtLength, const char* sqlStmt, unsigned dialect, IMessageMetadata*
|
stmtLength, const char* sqlStmt, unsigned dialect, IMessageMetadata*
|
||||||
inMetadata, unsigned</font></font>
|
inMetadata, unsigned</font></font> <font face="Liberation Serif, serif"><font size="4" style="font-size: 14pt">parLength,
|
||||||
<font face="Liberation Serif, serif"><font size="4" style="font-size: 14pt">parLength,
|
|
||||||
const unsigned char* par) – prepares sqlStmt and creates <a href="#Batch">Batch</a>
|
const unsigned char* par) – prepares sqlStmt and creates <a href="#Batch">Batch</a>
|
||||||
interface ready to accept multiple sets of input parameters in
|
interface ready to accept multiple sets of input parameters in
|
||||||
inMetadata format. Leaving inMetadata</font></font>
|
inMetadata format. Leaving inMetadata</font></font> <font face="Liberation Serif, serif"><font size="4" style="font-size: 14pt">NULL
|
||||||
<font face="Liberation Serif, serif"><font size="4" style="font-size: 14pt">NULL
|
|
||||||
makes batch use default format for sqlStmt. Parameters block may be
|
makes batch use default format for sqlStmt. Parameters block may be
|
||||||
passed to createBatch() making it possible to adjust batch behavior.</font></font></p>
|
passed to createBatch() making it possible to adjust batch behavior.</font></font></p>
|
||||||
<li><p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">IEvents*
|
<li><p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">IEvents*
|
||||||
@ -1861,15 +1831,13 @@ interface – makes it possible to process multiple sets of
|
|||||||
parameters in single statement execution.</font></p>
|
parameters in single statement execution.</font></p>
|
||||||
<ol>
|
<ol>
|
||||||
<li><p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">void
|
<li><p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">void
|
||||||
add(StatusType* status, unsigned</font>
|
add(StatusType* status, unsigned</font> <font size="4" style="font-size: 14pt">count,
|
||||||
<font size="4" style="font-size: 14pt">count,
|
|
||||||
const void* inBuffer) – adds count messages from inBuffer to the
|
const void* inBuffer) – adds count messages from inBuffer to the
|
||||||
batch. Total size of messages that can be added to the batch is
|
batch. Total size of messages that can be added to the batch is
|
||||||
limited by TAG_BUFFER_BYTES_SIZE <a href="#Batch_PB">parameter</a>
|
limited by TAG_BUFFER_BYTES_SIZE <a href="#Batch_PB">parameter</a>
|
||||||
of batch creation.</font></p>
|
of batch creation.</font></p>
|
||||||
<li><p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">void
|
<li><p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">void
|
||||||
addBlob(StatusType* status, unsigned</font>
|
addBlob(StatusType* status, unsigned</font> <font size="4" style="font-size: 14pt">length,
|
||||||
<font size="4" style="font-size: 14pt">length,
|
|
||||||
const void* inBuffer, ISC_QUAD* blobId, unsigned bpbLength, const
|
const void* inBuffer, ISC_QUAD* blobId, unsigned bpbLength, const
|
||||||
unsigned char* bpb) – adds single blob having length bytes from
|
unsigned char* bpb) – adds single blob having length bytes from
|
||||||
inBuffer to the batch, blob identifier is located at blobId address.
|
inBuffer to the batch, blob identifier is located at blobId address.
|
||||||
@ -1932,6 +1900,10 @@ parameters in single statement execution.</font></p>
|
|||||||
char* par) – sets BPB which will be used for all blobs missing
|
char* par) – sets BPB which will be used for all blobs missing
|
||||||
non-default BPB. Must be called before adding any message or blob to
|
non-default BPB. Must be called before adding any message or blob to
|
||||||
batch.</font></p>
|
batch.</font></p>
|
||||||
|
<li><p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">void
|
||||||
|
getInfo(StatusType* status, unsigned itemsLength, const unsigned
|
||||||
|
char* items, unsigned bufferLength, unsigned char* buffer) –
|
||||||
|
requests information about batch.</font></p>
|
||||||
</ol>
|
</ol>
|
||||||
<p style="margin-bottom: 0cm"><a name="Batch_PB"></a><font size="4" style="font-size: 14pt">Tag
|
<p style="margin-bottom: 0cm"><a name="Batch_PB"></a><font size="4" style="font-size: 14pt">Tag
|
||||||
for parameters block:</font></p>
|
for parameters block:</font></p>
|
||||||
@ -1960,6 +1932,17 @@ used to store blobs:</font></p>
|
|||||||
- blobs are added one by one, IDs are generated by user</font></p>
|
- blobs are added one by one, IDs are generated by user</font></p>
|
||||||
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">BLOB_STREAM
|
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">BLOB_STREAM
|
||||||
- blobs are added in a stream</font></p>
|
- blobs are added in a stream</font></p>
|
||||||
|
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">Items
|
||||||
|
accepted in getInfo() call:</font></p>
|
||||||
|
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">INF_BUFFER_BYTES_SIZE
|
||||||
|
– actual </font><font color="#000000"><font size="4" style="font-size: 14pt">m</font></font><font size="4" style="font-size: 14pt">aximum
|
||||||
|
possible buffer size (one set by TAG_BUFFER_BYTES_SIZE)</font></p>
|
||||||
|
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">INF_DATA_BYTES_SIZE
|
||||||
|
- already added messages size</font></p>
|
||||||
|
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">INF_BLOBS_BYTES_SIZE
|
||||||
|
- already added blobs size</font></p>
|
||||||
|
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">INF_BLOB_ALIGNMENT
|
||||||
|
- required alignment for the BLOB data (duplicates getBlobAlignment)</font></p>
|
||||||
<p style="margin-bottom: 0cm"><br/>
|
<p style="margin-bottom: 0cm"><br/>
|
||||||
|
|
||||||
</p>
|
</p>
|
||||||
@ -2156,10 +2139,10 @@ sub-entries) in firebird configuration file:</font></p>
|
|||||||
|
|
||||||
</p>
|
</p>
|
||||||
<p style="margin-bottom: 0cm"><a name="DecFloat16"></a><a name="DecFloat34"></a>
|
<p style="margin-bottom: 0cm"><a name="DecFloat16"></a><a name="DecFloat34"></a>
|
||||||
<font size="4" style="font-size: 14pt">DecFloat16
|
<font size="4" style="font-size: 14pt">DecFloat16 / DecFloat34 –
|
||||||
/ DecFloat34 – interfaces that help to work with DECFLOAT (16 &
|
interfaces that help to work with DECFLOAT (16 & 34 respectively)
|
||||||
34 respectively) datatypes. They have almost same set of methods with
|
datatypes. They have almost same set of methods with FB_DEC16
|
||||||
FB_DEC16 parameter replaced by FB_DEC34 for DecFloat34:</font></p>
|
parameter replaced by FB_DEC34 for DecFloat34:</font></p>
|
||||||
<ol>
|
<ol>
|
||||||
<li><p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">void
|
<li><p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">void
|
||||||
toBcd(const FB_DEC16* from, int* sign, unsigned char* bcd, int* exp)
|
toBcd(const FB_DEC16* from, int* sign, unsigned char* bcd, int* exp)
|
||||||
@ -2794,8 +2777,8 @@ defined by Statement interface:</font></p>
|
|||||||
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">IAttachment::prepare()
|
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">IAttachment::prepare()
|
||||||
flags:</font></p>
|
flags:</font></p>
|
||||||
<p style="margin-left: 0.96cm; text-indent: -0.02cm; margin-bottom: 0cm; page-break-before: auto; page-break-after: auto">
|
<p style="margin-left: 0.96cm; text-indent: -0.02cm; margin-bottom: 0cm; page-break-before: auto; page-break-after: auto">
|
||||||
<font size="4" style="font-size: 14pt">PREPARE_PREFETCH_NONE
|
<font size="4" style="font-size: 14pt">PREPARE_PREFETCH_NONE –
|
||||||
– constant to pass no flags, 0 value.</font></p>
|
constant to pass no flags, 0 value.</font></p>
|
||||||
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">The
|
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">The
|
||||||
following flags may be OR-ed to get desired set of flags:</font></p>
|
following flags may be OR-ed to get desired set of flags:</font></p>
|
||||||
<ol>
|
<ol>
|
||||||
@ -2820,8 +2803,8 @@ used combinations of flags:</font></p>
|
|||||||
|
|
||||||
</p>
|
</p>
|
||||||
<p style="margin-bottom: 0cm"><a name="Values returned by getFlags"></a>
|
<p style="margin-bottom: 0cm"><a name="Values returned by getFlags"></a>
|
||||||
<font size="4" style="font-size: 14pt">Values
|
<font size="4" style="font-size: 14pt">Values returned by getFlags()
|
||||||
returned by getFlags() method: </font>
|
method: </font>
|
||||||
</p>
|
</p>
|
||||||
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">FLAG_HAS_CURSOR
|
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">FLAG_HAS_CURSOR
|
||||||
– use openCursor() to execute this statement, not execute()</font></p>
|
– use openCursor() to execute this statement, not execute()</font></p>
|
||||||
@ -2832,8 +2815,7 @@ parameters</font></p>
|
|||||||
|
|
||||||
</p>
|
</p>
|
||||||
<p style="margin-bottom: 0cm"><a name="Flags passed to openCursor"></a>
|
<p style="margin-bottom: 0cm"><a name="Flags passed to openCursor"></a>
|
||||||
<font size="4" style="font-size: 14pt">Flags
|
<font size="4" style="font-size: 14pt">Flags passed to openCursor():</font></p>
|
||||||
passed to openCursor():</font></p>
|
|
||||||
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">CURSOR_TYPE_SCROLLABLE
|
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">CURSOR_TYPE_SCROLLABLE
|
||||||
– open bidirectional cursor.</font></p>
|
– open bidirectional cursor.</font></p>
|
||||||
<p style="margin-bottom: 0cm"><br/>
|
<p style="margin-bottom: 0cm"><br/>
|
||||||
@ -2931,8 +2913,8 @@ moment when given timer should alarm.</font></p>
|
|||||||
start(StatusType* status, ITimer* timer, ISC_UINT64 microSeconds) –
|
start(StatusType* status, ITimer* timer, ISC_UINT64 microSeconds) –
|
||||||
start <a href="#Timer">ITimer</a> to alarm after given delay (in
|
start <a href="#Timer">ITimer</a> to alarm after given delay (in
|
||||||
microseconds, 10</font><sup><font size="4" style="font-size: 14pt">-6</font></sup>
|
microseconds, 10</font><sup><font size="4" style="font-size: 14pt">-6</font></sup>
|
||||||
<font size="4" style="font-size: 14pt">seconds).
|
<font size="4" style="font-size: 14pt">seconds). Timer will be waked
|
||||||
Timer will be waked up only once after this call.</font></p>
|
up only once after this call.</font></p>
|
||||||
<li><p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">void
|
<li><p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">void
|
||||||
stop(StatusType* status, ITimer* timer) – stop <a href="#Timer">ITimer</a>.
|
stop(StatusType* status, ITimer* timer) – stop <a href="#Timer">ITimer</a>.
|
||||||
It's not an error to stop not started timer thus avoiding problems
|
It's not an error to stop not started timer thus avoiding problems
|
||||||
@ -3066,8 +3048,8 @@ interface – various helper methods required here or there.</font></p>
|
|||||||
decodeTimeTz(StatusType* status, const ISC_TIME_TZ* timeTz,
|
decodeTimeTz(StatusType* status, const ISC_TIME_TZ* timeTz,
|
||||||
unsigned* hours, unsigned* minutes, unsigned* seconds, unsigned*</font></p>
|
unsigned* hours, unsigned* minutes, unsigned* seconds, unsigned*</font></p>
|
||||||
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">fractions,
|
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">fractions,
|
||||||
unsigned timeZoneBufferLength, char* timeZoneBuffer)
|
unsigned timeZoneBufferLength, char* timeZoneBuffer) – decode time
|
||||||
– decode time taking time zone into an account.</font></p>
|
taking time zone into an account.</font></p>
|
||||||
<li><p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">void
|
<li><p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">void
|
||||||
decodeTimeStampTz(StatusType* status, const ISC_TIMESTAMP_TZ*
|
decodeTimeStampTz(StatusType* status, const ISC_TIMESTAMP_TZ*
|
||||||
timeStampTz, unsigned* year, unsigned* month, unsigned* day,
|
timeStampTz, unsigned* year, unsigned* month, unsigned* day,
|
||||||
@ -3195,8 +3177,8 @@ builder types:</font></p>
|
|||||||
<p style="margin-bottom: 0cm"><br/>
|
<p style="margin-bottom: 0cm"><br/>
|
||||||
|
|
||||||
</p>
|
</p>
|
||||||
<h1><font size="4" style="font-size: 14pt">Plugin,
|
<h1><font size="4" style="font-size: 14pt">Plugin, encrypting data
|
||||||
encrypting data transferred over the wire.</font></h1>
|
transferred over the wire.</font></h1>
|
||||||
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">Algorithms
|
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">Algorithms
|
||||||
performing encryption of data for different purposes are well known
|
performing encryption of data for different purposes are well known
|
||||||
for many years. The only “little” typical problem remaining is
|
for many years. The only “little” typical problem remaining is
|
||||||
@ -3262,8 +3244,8 @@ such interface it should be implemented by author of the plugin.</font></p>
|
|||||||
<p style="margin-bottom: 0cm"><br/>
|
<p style="margin-bottom: 0cm"><br/>
|
||||||
|
|
||||||
</p>
|
</p>
|
||||||
<h1><font size="4" style="font-size: 14pt">Server
|
<h1><font size="4" style="font-size: 14pt">Server side of
|
||||||
side of authentication plugin.</font></h1>
|
authentication plugin.</font></h1>
|
||||||
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">Authentication
|
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">Authentication
|
||||||
plugin contains two required parts – client and server and may also
|
plugin contains two required parts – client and server and may also
|
||||||
contain related third part - user manager. During authentication
|
contain related third part - user manager. During authentication
|
||||||
@ -3350,8 +3332,8 @@ interface is main interface of server side of authentication plugin. </font>
|
|||||||
<p style="margin-bottom: 0cm"><br/>
|
<p style="margin-bottom: 0cm"><br/>
|
||||||
|
|
||||||
</p>
|
</p>
|
||||||
<h1><font size="4" style="font-size: 14pt">Client
|
<h1><font size="4" style="font-size: 14pt">Client side of
|
||||||
side of authentication plugin.</font></h1>
|
authentication plugin.</font></h1>
|
||||||
<p style="margin-bottom: 0cm"><a name="ClientBlock"></a><font size="4" style="font-size: 14pt">ClientBlock
|
<p style="margin-bottom: 0cm"><a name="ClientBlock"></a><font size="4" style="font-size: 14pt">ClientBlock
|
||||||
interface is used by client side of authentication plugin to exchange
|
interface is used by client side of authentication plugin to exchange
|
||||||
data with server.</font></p>
|
data with server.</font></p>
|
||||||
@ -3387,8 +3369,7 @@ interface is main interface of client side of authentication plugin.</font></p>
|
|||||||
<p style="margin-bottom: 0cm"><br/>
|
<p style="margin-bottom: 0cm"><br/>
|
||||||
|
|
||||||
</p>
|
</p>
|
||||||
<h1><font size="4" style="font-size: 14pt">User
|
<h1><font size="4" style="font-size: 14pt">User management plugin.</font></h1>
|
||||||
management plugin.</font></h1>
|
|
||||||
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">This
|
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">This
|
||||||
plugin is actively related with server side of authentication – it
|
plugin is actively related with server side of authentication – it
|
||||||
prepares users' list for authentication plugin. Not each
|
prepares users' list for authentication plugin. Not each
|
||||||
@ -3481,8 +3462,8 @@ about the user. </font>
|
|||||||
|
|
||||||
</p>
|
</p>
|
||||||
<p style="margin-bottom: 0cm"><a name="Constants defined by User interface"></a>
|
<p style="margin-bottom: 0cm"><a name="Constants defined by User interface"></a>
|
||||||
<font size="4" style="font-size: 14pt">Constants
|
<font size="4" style="font-size: 14pt">Constants defined by User
|
||||||
defined by User interface – valid codes of operation.</font></p>
|
interface – valid codes of operation.</font></p>
|
||||||
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">OP_USER_ADD
|
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">OP_USER_ADD
|
||||||
– create user</font></p>
|
– create user</font></p>
|
||||||
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">OP_USER_MODIFY
|
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">OP_USER_MODIFY
|
||||||
@ -3559,8 +3540,8 @@ interface is main interface of user management plugin.</font></p>
|
|||||||
<p style="margin-bottom: 0cm"><br/>
|
<p style="margin-bottom: 0cm"><br/>
|
||||||
|
|
||||||
</p>
|
</p>
|
||||||
<h1><font size="4" style="font-size: 14pt">Database
|
<h1><font size="4" style="font-size: 14pt">Database encryption
|
||||||
encryption plugin.</font></h1>
|
plugin.</font></h1>
|
||||||
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">An
|
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">An
|
||||||
ability to encrypt database was present in firebird since interbase
|
ability to encrypt database was present in firebird since interbase
|
||||||
times but appropriate places in the code were commented.
|
times but appropriate places in the code were commented.
|
||||||
@ -3651,8 +3632,8 @@ interface is main interface of database crypt plugin.</font></p>
|
|||||||
<p style="margin-bottom: 0cm"><br/>
|
<p style="margin-bottom: 0cm"><br/>
|
||||||
|
|
||||||
</p>
|
</p>
|
||||||
<h1><font size="4" style="font-size: 14pt">Key
|
<h1><font size="4" style="font-size: 14pt">Key holder for database
|
||||||
holder for database encryption plugin.</font></h1>
|
encryption plugin.</font></h1>
|
||||||
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">This
|
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">This
|
||||||
type of plugin is needed to delineate functionality – db crypt
|
type of plugin is needed to delineate functionality – db crypt
|
||||||
plugin is dealing with actual encryption, key holder solves questions
|
plugin is dealing with actual encryption, key holder solves questions
|
||||||
@ -3706,8 +3687,8 @@ interface is main interface of database crypt key holder plugin.</font></p>
|
|||||||
<p style="margin-bottom: 0cm"><br/>
|
<p style="margin-bottom: 0cm"><br/>
|
||||||
|
|
||||||
</p>
|
</p>
|
||||||
<h1><font size="4" style="font-size: 14pt">Non-interface
|
<h1><font size="4" style="font-size: 14pt">Non-interface objects used
|
||||||
objects used by API (C++ specific header Message.h).</font></h1>
|
by API (C++ specific header Message.h).</font></h1>
|
||||||
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">Following
|
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">Following
|
||||||
3 classes are used to represent date, time and timestamp (datetime)
|
3 classes are used to represent date, time and timestamp (datetime)
|
||||||
when using FB_MESSAGE macro. Members of data structure, representing
|
when using FB_MESSAGE macro. Members of data structure, representing
|
||||||
|
@ -114,6 +114,53 @@ unsigned putSegment(unsigned char*& ptr, const char* testData)
|
|||||||
return align(l + sizeof l, IBatch::BLOB_SEGHDR_ALIGN);
|
return align(l + sizeof l, IBatch::BLOB_SEGHDR_ALIGN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// batch info printer - prints what we know about batch
|
||||||
|
|
||||||
|
static void printInfo(ThrowStatusWrapper& status, const char* hdr, IBatch* b, IUtil* utl)
|
||||||
|
{
|
||||||
|
printf("\n%s\n", hdr);
|
||||||
|
|
||||||
|
const unsigned char items[] = {IBatch::INF_BLOB_ALIGNMENT, IBatch::INF_BUFFER_BYTES_SIZE,
|
||||||
|
IBatch::INF_DATA_BYTES_SIZE, IBatch::INF_BLOBS_BYTES_SIZE};
|
||||||
|
unsigned char buffer[29];
|
||||||
|
b->getInfo(&status, sizeof items, items, sizeof buffer, buffer);
|
||||||
|
|
||||||
|
IXpbBuilder* pb = utl->getXpbBuilder(&status, IXpbBuilder::INFO_RESPONSE, buffer, sizeof buffer);
|
||||||
|
for (pb->rewind(&status); !pb->isEof(&status); pb->moveNext(&status))
|
||||||
|
{
|
||||||
|
int val = pb->getInt(&status);
|
||||||
|
const char* text = "Unknown tag";
|
||||||
|
switch (pb->getTag(&status))
|
||||||
|
{
|
||||||
|
case IBatch::INF_BLOB_ALIGNMENT:
|
||||||
|
text = "Blob alignment";
|
||||||
|
break;
|
||||||
|
case IBatch::INF_BUFFER_BYTES_SIZE:
|
||||||
|
text = "Buffer size";
|
||||||
|
break;
|
||||||
|
case IBatch::INF_DATA_BYTES_SIZE:
|
||||||
|
text = "Messages size";
|
||||||
|
break;
|
||||||
|
case IBatch::INF_BLOBS_BYTES_SIZE:
|
||||||
|
text = "Blobs size";
|
||||||
|
break;
|
||||||
|
case isc_info_truncated:
|
||||||
|
printf(" truncated\n");
|
||||||
|
// fall down...
|
||||||
|
case isc_info_end:
|
||||||
|
pb->dispose();
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
printf("Unexpected item %d\n", pb->getTag(&status));
|
||||||
|
pb->dispose();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("%s = %d\n", text, val);
|
||||||
|
}
|
||||||
|
pb->dispose();
|
||||||
|
}
|
||||||
|
|
||||||
// BatchCompletionState printer - prints all what we know about completed batch
|
// BatchCompletionState printer - prints all what we know about completed batch
|
||||||
|
|
||||||
static void print_cs(ThrowStatusWrapper& status, IBatchCompletionState* cs, IUtil* utl)
|
static void print_cs(ThrowStatusWrapper& status, IBatchCompletionState* cs, IUtil* utl)
|
||||||
@ -270,6 +317,9 @@ int main()
|
|||||||
batch->add(&status, 1, project1.getData());
|
batch->add(&status, 1, project1.getData());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check batch state
|
||||||
|
printInfo(status, "Info when added many records", batch, utl);
|
||||||
|
|
||||||
// ... and cancel that records
|
// ... and cancel that records
|
||||||
batch->cancel(&status);
|
batch->cancel(&status);
|
||||||
|
|
||||||
@ -347,6 +397,8 @@ int main()
|
|||||||
batch->appendBlobData(&status, strlen(sqlStmt1), sqlStmt1);
|
batch->appendBlobData(&status, strlen(sqlStmt1), sqlStmt1);
|
||||||
batch->add(&status, 1, project2.getData());
|
batch->add(&status, 1, project2.getData());
|
||||||
|
|
||||||
|
printInfo(status, "Info with blob", batch, utl);
|
||||||
|
|
||||||
// execute it
|
// execute it
|
||||||
cs = batch->execute(&status, tra);
|
cs = batch->execute(&status, tra);
|
||||||
print_cs(status, cs, utl);
|
print_cs(status, cs, utl);
|
||||||
|
@ -242,6 +242,7 @@ UCHAR ClumpletReader::getBufferTag() const
|
|||||||
case SpbReceiveItems:
|
case SpbReceiveItems:
|
||||||
case SpbResponse:
|
case SpbResponse:
|
||||||
case InfoResponse:
|
case InfoResponse:
|
||||||
|
case InfoItems:
|
||||||
usage_mistake("buffer is not tagged");
|
usage_mistake("buffer is not tagged");
|
||||||
return 0;
|
return 0;
|
||||||
case SpbAttach:
|
case SpbAttach:
|
||||||
@ -313,6 +314,7 @@ ClumpletReader::ClumpletType ClumpletReader::getClumpletType(UCHAR tag) const
|
|||||||
}
|
}
|
||||||
return StringSpb;
|
return StringSpb;
|
||||||
case SpbReceiveItems:
|
case SpbReceiveItems:
|
||||||
|
case InfoItems:
|
||||||
return SingleTpb;
|
return SingleTpb;
|
||||||
case SpbStart:
|
case SpbStart:
|
||||||
switch(tag)
|
switch(tag)
|
||||||
@ -704,6 +706,7 @@ void ClumpletReader::rewind()
|
|||||||
case SpbReceiveItems:
|
case SpbReceiveItems:
|
||||||
case SpbResponse:
|
case SpbResponse:
|
||||||
case InfoResponse:
|
case InfoResponse:
|
||||||
|
case InfoItems:
|
||||||
cur_offset = 0;
|
cur_offset = 0;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -58,7 +58,8 @@ public:
|
|||||||
SpbSendItems,
|
SpbSendItems,
|
||||||
SpbReceiveItems,
|
SpbReceiveItems,
|
||||||
SpbResponse,
|
SpbResponse,
|
||||||
InfoResponse
|
InfoResponse,
|
||||||
|
InfoItems
|
||||||
};
|
};
|
||||||
|
|
||||||
struct KindList
|
struct KindList
|
||||||
|
@ -36,15 +36,23 @@
|
|||||||
|
|
||||||
namespace Firebird {
|
namespace Firebird {
|
||||||
|
|
||||||
ClumpletWriter::ClumpletWriter(Kind k, FB_SIZE_T limit, UCHAR tag) :
|
ClumpletWriter::ClumpletWriter(Kind k, FB_SIZE_T limit, UCHAR tag)
|
||||||
ClumpletReader(k, NULL, 0), sizeLimit(limit), kindList(NULL), dynamic_buffer(getPool())
|
: ClumpletReader(k, NULL, 0),
|
||||||
|
sizeLimit(limit),
|
||||||
|
kindList(NULL),
|
||||||
|
dynamic_buffer(getPool()),
|
||||||
|
flag_overflow(false)
|
||||||
{
|
{
|
||||||
initNewBuffer(tag);
|
initNewBuffer(tag);
|
||||||
rewind();
|
rewind();
|
||||||
}
|
}
|
||||||
|
|
||||||
ClumpletWriter::ClumpletWriter(MemoryPool& given_pool, Kind k, FB_SIZE_T limit, UCHAR tag) :
|
ClumpletWriter::ClumpletWriter(MemoryPool& given_pool, Kind k, FB_SIZE_T limit, UCHAR tag)
|
||||||
ClumpletReader(given_pool, k, NULL, 0), sizeLimit(limit), kindList(NULL), dynamic_buffer(getPool())
|
: ClumpletReader(given_pool, k, NULL, 0),
|
||||||
|
sizeLimit(limit),
|
||||||
|
kindList(NULL),
|
||||||
|
dynamic_buffer(getPool()),
|
||||||
|
flag_overflow(false)
|
||||||
{
|
{
|
||||||
initNewBuffer(tag);
|
initNewBuffer(tag);
|
||||||
rewind();
|
rewind();
|
||||||
@ -82,46 +90,72 @@ void ClumpletWriter::initNewBuffer(UCHAR tag)
|
|||||||
}
|
}
|
||||||
|
|
||||||
ClumpletWriter::ClumpletWriter(Kind k, FB_SIZE_T limit, const UCHAR* buffer, FB_SIZE_T buffLen, UCHAR tag)
|
ClumpletWriter::ClumpletWriter(Kind k, FB_SIZE_T limit, const UCHAR* buffer, FB_SIZE_T buffLen, UCHAR tag)
|
||||||
: ClumpletReader(k, NULL, 0), sizeLimit(limit), kindList(NULL), dynamic_buffer(getPool())
|
: ClumpletReader(k, NULL, 0),
|
||||||
|
sizeLimit(limit),
|
||||||
|
kindList(NULL),
|
||||||
|
dynamic_buffer(getPool()),
|
||||||
|
flag_overflow(false)
|
||||||
{
|
{
|
||||||
create(buffer, buffLen, tag);
|
create(buffer, buffLen, tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
ClumpletWriter::ClumpletWriter(MemoryPool& pool, const KindList* kl, FB_SIZE_T limit,
|
ClumpletWriter::ClumpletWriter(MemoryPool& pool, const KindList* kl, FB_SIZE_T limit,
|
||||||
const UCHAR* buffer, FB_SIZE_T buffLen)
|
const UCHAR* buffer, FB_SIZE_T buffLen)
|
||||||
: ClumpletReader(pool, kl, buffer, buffLen), sizeLimit(limit),
|
: ClumpletReader(pool, kl, buffer, buffLen),
|
||||||
kindList(kl), dynamic_buffer(getPool())
|
sizeLimit(limit),
|
||||||
|
kindList(kl),
|
||||||
|
dynamic_buffer(getPool()),
|
||||||
|
flag_overflow(false)
|
||||||
{
|
{
|
||||||
create(buffer, buffLen, kl->tag);
|
create(buffer, buffLen, kl->tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
ClumpletWriter::ClumpletWriter(const KindList* kl, FB_SIZE_T limit, const UCHAR* buffer, FB_SIZE_T buffLen)
|
ClumpletWriter::ClumpletWriter(const KindList* kl, FB_SIZE_T limit, const UCHAR* buffer, FB_SIZE_T buffLen)
|
||||||
: ClumpletReader(kl, buffer, buffLen), sizeLimit(limit), kindList(kl), dynamic_buffer(getPool())
|
: ClumpletReader(kl, buffer, buffLen),
|
||||||
|
sizeLimit(limit),
|
||||||
|
kindList(kl),
|
||||||
|
dynamic_buffer(getPool()),
|
||||||
|
flag_overflow(false)
|
||||||
{
|
{
|
||||||
create(buffer, buffLen, kl->tag);
|
create(buffer, buffLen, kl->tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
ClumpletWriter::ClumpletWriter(MemoryPool& pool, const KindList* kl, FB_SIZE_T limit)
|
ClumpletWriter::ClumpletWriter(MemoryPool& pool, const KindList* kl, FB_SIZE_T limit)
|
||||||
: ClumpletReader(pool, kl, NULL, 0), sizeLimit(limit),
|
: ClumpletReader(pool, kl, NULL, 0),
|
||||||
kindList(kl), dynamic_buffer(getPool())
|
sizeLimit(limit),
|
||||||
|
kindList(kl),
|
||||||
|
dynamic_buffer(getPool()),
|
||||||
|
flag_overflow(false)
|
||||||
{
|
{
|
||||||
create(NULL, 0, kl->tag);
|
create(NULL, 0, kl->tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
ClumpletWriter::ClumpletWriter(const KindList* kl, FB_SIZE_T limit)
|
ClumpletWriter::ClumpletWriter(const KindList* kl, FB_SIZE_T limit)
|
||||||
: ClumpletReader(kl, NULL, 0), sizeLimit(limit), kindList(kl), dynamic_buffer(getPool())
|
: ClumpletReader(kl, NULL, 0),
|
||||||
|
sizeLimit(limit),
|
||||||
|
kindList(kl),
|
||||||
|
dynamic_buffer(getPool()),
|
||||||
|
flag_overflow(false)
|
||||||
{
|
{
|
||||||
create(NULL, 0, kl->tag);
|
create(NULL, 0, kl->tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
ClumpletWriter::ClumpletWriter(MemoryPool& pool, const ClumpletWriter& from)
|
ClumpletWriter::ClumpletWriter(MemoryPool& pool, const ClumpletWriter& from)
|
||||||
: ClumpletReader(pool, from), sizeLimit(from.sizeLimit), kindList(NULL), dynamic_buffer(getPool())
|
: ClumpletReader(pool, from),
|
||||||
|
sizeLimit(from.sizeLimit),
|
||||||
|
kindList(NULL),
|
||||||
|
dynamic_buffer(getPool()),
|
||||||
|
flag_overflow(false)
|
||||||
{
|
{
|
||||||
create(from.getBuffer(), from.getBufferEnd() - from.getBuffer(), from.isTagged() ? from.getBufferTag() : 0);
|
create(from.getBuffer(), from.getBufferEnd() - from.getBuffer(), from.isTagged() ? from.getBufferTag() : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
ClumpletWriter::ClumpletWriter(const ClumpletWriter& from)
|
ClumpletWriter::ClumpletWriter(const ClumpletWriter& from)
|
||||||
: ClumpletReader(from), sizeLimit(from.sizeLimit), kindList(NULL), dynamic_buffer(getPool())
|
: ClumpletReader(from),
|
||||||
|
sizeLimit(from.sizeLimit),
|
||||||
|
kindList(NULL),
|
||||||
|
dynamic_buffer(getPool()),
|
||||||
|
flag_overflow(false)
|
||||||
{
|
{
|
||||||
create(from.getBuffer(), from.getBufferEnd() - from.getBuffer(), from.isTagged() ? from.getBufferTag() : 0);
|
create(from.getBuffer(), from.getBufferEnd() - from.getBuffer(), from.isTagged() ? from.getBufferTag() : 0);
|
||||||
}
|
}
|
||||||
@ -138,8 +172,11 @@ void ClumpletWriter::create(const UCHAR* buffer, FB_SIZE_T buffLen, UCHAR tag)
|
|||||||
}
|
}
|
||||||
|
|
||||||
ClumpletWriter::ClumpletWriter(MemoryPool& given_pool, Kind k, FB_SIZE_T limit,
|
ClumpletWriter::ClumpletWriter(MemoryPool& given_pool, Kind k, FB_SIZE_T limit,
|
||||||
const UCHAR* buffer, FB_SIZE_T buffLen, UCHAR tag) :
|
const UCHAR* buffer, FB_SIZE_T buffLen, UCHAR tag)
|
||||||
ClumpletReader(given_pool, k, NULL, 0), sizeLimit(limit), dynamic_buffer(getPool())
|
: ClumpletReader(given_pool, k, NULL, 0),
|
||||||
|
sizeLimit(limit),
|
||||||
|
dynamic_buffer(getPool()),
|
||||||
|
flag_overflow(false)
|
||||||
{
|
{
|
||||||
if (buffer && buffLen) {
|
if (buffer && buffLen) {
|
||||||
dynamic_buffer.push(buffer, buffLen);
|
dynamic_buffer.push(buffer, buffLen);
|
||||||
@ -194,6 +231,13 @@ void ClumpletWriter::size_overflow()
|
|||||||
fatal_exception::raise("Clumplet buffer size limit reached");
|
fatal_exception::raise("Clumplet buffer size limit reached");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ClumpletWriter::size_overflow(bool condition)
|
||||||
|
{
|
||||||
|
flag_overflow = condition;
|
||||||
|
if (condition)
|
||||||
|
size_overflow();
|
||||||
|
}
|
||||||
|
|
||||||
void ClumpletWriter::toVaxInteger(UCHAR* ptr, FB_SIZE_T length, const SINT64 value)
|
void ClumpletWriter::toVaxInteger(UCHAR* ptr, FB_SIZE_T length, const SINT64 value)
|
||||||
{
|
{
|
||||||
fb_assert(ptr && length > 0 && length < 9); // We can't handle numbers bigger than int64.
|
fb_assert(ptr && length > 0 && length < 9); // We can't handle numbers bigger than int64.
|
||||||
@ -362,9 +406,7 @@ void ClumpletWriter::insertBytesLengthCheck(UCHAR tag, const void* bytes, const
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check that resulting data doesn't overflow size limit
|
// Check that resulting data doesn't overflow size limit
|
||||||
if (dynamic_buffer.getCount() + length + lenSize + 1 > sizeLimit) {
|
size_overflow(dynamic_buffer.getCount() + length + lenSize + 1 > sizeLimit);
|
||||||
size_overflow();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Insert the data
|
// Insert the data
|
||||||
const FB_SIZE_T saved_offset = cur_offset;
|
const FB_SIZE_T saved_offset = cur_offset;
|
||||||
@ -415,9 +457,7 @@ void ClumpletWriter::insertEndMarker(UCHAR tag)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check that resulting data doesn't overflow size limit
|
// Check that resulting data doesn't overflow size limit
|
||||||
if (cur_offset + 1 > sizeLimit) {
|
size_overflow(cur_offset + 1 > sizeLimit);
|
||||||
size_overflow();
|
|
||||||
}
|
|
||||||
|
|
||||||
dynamic_buffer.shrink(cur_offset);
|
dynamic_buffer.shrink(cur_offset);
|
||||||
dynamic_buffer.push(tag);
|
dynamic_buffer.push(tag);
|
||||||
|
@ -98,10 +98,14 @@ public:
|
|||||||
// Returns true if any found
|
// Returns true if any found
|
||||||
bool deleteWithTag(UCHAR tag);
|
bool deleteWithTag(UCHAR tag);
|
||||||
|
|
||||||
virtual const UCHAR* getBuffer() const;
|
const UCHAR* getBuffer() const override;
|
||||||
|
bool hasOverflow() const
|
||||||
|
{
|
||||||
|
return flag_overflow;
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual const UCHAR* getBufferEnd() const;
|
const UCHAR* getBufferEnd() const override;
|
||||||
virtual void size_overflow();
|
virtual void size_overflow();
|
||||||
void insertBytesLengthCheck(UCHAR tag, const void* bytes, const FB_SIZE_T length);
|
void insertBytesLengthCheck(UCHAR tag, const void* bytes, const FB_SIZE_T length);
|
||||||
bool upgradeVersion(); // upgrade clumplet version - obtain newest from kindList
|
bool upgradeVersion(); // upgrade clumplet version - obtain newest from kindList
|
||||||
@ -117,14 +121,10 @@ private:
|
|||||||
void initNewBuffer(UCHAR tag);
|
void initNewBuffer(UCHAR tag);
|
||||||
void create(const UCHAR* buffer, FB_SIZE_T buffLen, UCHAR tag);
|
void create(const UCHAR* buffer, FB_SIZE_T buffLen, UCHAR tag);
|
||||||
static void toVaxInteger(UCHAR* ptr, FB_SIZE_T length, const SINT64 value);
|
static void toVaxInteger(UCHAR* ptr, FB_SIZE_T length, const SINT64 value);
|
||||||
|
|
||||||
|
void size_overflow(bool condition);
|
||||||
|
bool flag_overflow;
|
||||||
};
|
};
|
||||||
/*
|
|
||||||
template <>
|
|
||||||
void ClumpletWriter::insertString(UCHAR tag, const char*& str)
|
|
||||||
{
|
|
||||||
insertString(tag, str, strlen(str));
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
} // namespace Firebird
|
} // namespace Firebird
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@
|
|||||||
#include "../jrd/exe_proto.h"
|
#include "../jrd/exe_proto.h"
|
||||||
#include "../dsql/dsql.h"
|
#include "../dsql/dsql.h"
|
||||||
#include "../dsql/errd_proto.h"
|
#include "../dsql/errd_proto.h"
|
||||||
#include "../common/classes/ClumpletReader.h"
|
#include "../common/classes/ClumpletWriter.h"
|
||||||
#include "../common/classes/auto.h"
|
#include "../common/classes/auto.h"
|
||||||
#include "../common/classes/fb_string.h"
|
#include "../common/classes/fb_string.h"
|
||||||
#include "../common/utils_proto.h"
|
#include "../common/utils_proto.h"
|
||||||
@ -966,6 +966,14 @@ ULONG DsqlBatch::DataCache::getSize() const
|
|||||||
return m_used + m_cache.getCount();
|
return m_used + m_cache.getCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ULONG DsqlBatch::DataCache::getCapacity() const
|
||||||
|
{
|
||||||
|
if (!m_cacheCapacity)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return m_limit;
|
||||||
|
}
|
||||||
|
|
||||||
void DsqlBatch::DataCache::clear()
|
void DsqlBatch::DataCache::clear()
|
||||||
{
|
{
|
||||||
m_cache.clear();
|
m_cache.clear();
|
||||||
@ -973,3 +981,99 @@ void DsqlBatch::DataCache::clear()
|
|||||||
m_space->releaseSpace(0, m_used);
|
m_space->releaseSpace(0, m_used);
|
||||||
m_used = m_got = m_shift = 0;
|
m_used = m_got = m_shift = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DsqlBatch::info(thread_db* tdbb, unsigned int itemsLength, const unsigned char* items,
|
||||||
|
unsigned int bufferLength, unsigned char* buffer)
|
||||||
|
{
|
||||||
|
// Sanity check
|
||||||
|
if (bufferLength < 3) // bigger values will be processed by later code OK
|
||||||
|
{
|
||||||
|
if (bufferLength-- > 0)
|
||||||
|
{
|
||||||
|
*buffer++ = isc_info_truncated;
|
||||||
|
if (bufferLength-- > 0)
|
||||||
|
*buffer++ = isc_info_end;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ClumpletReader it(ClumpletReader::InfoItems, items, itemsLength);
|
||||||
|
ClumpletWriter out(ClumpletReader::InfoResponse, bufferLength - 1); // place for isc_info_truncated / isc_info_end
|
||||||
|
enum BufCloseState {BUF_OPEN, BUF_INTERNAL, BUF_END};
|
||||||
|
BufCloseState closeOut = BUF_OPEN;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
bool flInfoLength = false;
|
||||||
|
|
||||||
|
for (it.rewind(); !it.isEof(); it.moveNext())
|
||||||
|
{
|
||||||
|
UCHAR item = it.getClumpTag();
|
||||||
|
if (item == isc_info_end)
|
||||||
|
break;
|
||||||
|
|
||||||
|
switch(item)
|
||||||
|
{
|
||||||
|
case IBatch::INF_BUFFER_BYTES_SIZE:
|
||||||
|
out.insertInt(item, m_messages.getCapacity());
|
||||||
|
break;
|
||||||
|
case IBatch::INF_DATA_BYTES_SIZE:
|
||||||
|
out.insertInt(item, FB_ALIGN(m_messages.getSize(), m_alignment));
|
||||||
|
break;
|
||||||
|
case IBatch::INF_BLOBS_BYTES_SIZE:
|
||||||
|
if (m_blobs.getSize())
|
||||||
|
out.insertInt(item, m_blobs.getSize());
|
||||||
|
break;
|
||||||
|
case IBatch::INF_BLOB_ALIGNMENT:
|
||||||
|
out.insertInt(item, BLOB_STREAM_ALIGN);
|
||||||
|
break;
|
||||||
|
case isc_info_length:
|
||||||
|
flInfoLength = true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
out.insertInt(isc_info_error, isc_infunk);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// finalize writer
|
||||||
|
closeOut = BUF_INTERNAL; // finished adding internal info
|
||||||
|
out.insertTag(isc_info_end);
|
||||||
|
closeOut = BUF_END; // alreayd marked with isc_info_end but misses isc_info_length
|
||||||
|
if (flInfoLength)
|
||||||
|
{
|
||||||
|
out.rewind();
|
||||||
|
out.insertInt(isc_info_length, out.getBufferLength());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(const fatal_exception&)
|
||||||
|
{
|
||||||
|
// here it's sooner of all caused by writer overflow but carefully check that
|
||||||
|
if (out.hasOverflow())
|
||||||
|
{
|
||||||
|
memcpy(buffer, out.getBuffer(), out.getBufferLength());
|
||||||
|
buffer += out.getBufferLength();
|
||||||
|
switch (closeOut)
|
||||||
|
{
|
||||||
|
case BUF_OPEN:
|
||||||
|
*buffer++ = isc_info_truncated;
|
||||||
|
if (out.getBufferLength() <= bufferLength - 2)
|
||||||
|
*buffer++ = isc_info_end;
|
||||||
|
break;
|
||||||
|
case BUF_INTERNAL:
|
||||||
|
// overflow adding isc_info_end, but we actually have 1 reserved byte
|
||||||
|
*buffer++ = isc_info_end;
|
||||||
|
break;
|
||||||
|
case BUF_END:
|
||||||
|
// ignore isc_info_length
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(buffer, out.getBuffer(), out.getBufferLength());
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -76,6 +76,8 @@ public:
|
|||||||
Firebird::IMessageMetadata* getMetadata(thread_db* tdbb);
|
Firebird::IMessageMetadata* getMetadata(thread_db* tdbb);
|
||||||
void cancel(thread_db* tdbb);
|
void cancel(thread_db* tdbb);
|
||||||
void setDefaultBpb(thread_db* tdbb, unsigned parLength, const unsigned char* par);
|
void setDefaultBpb(thread_db* tdbb, unsigned parLength, const unsigned char* par);
|
||||||
|
void info(thread_db* tdbb, unsigned int itemsLength, const unsigned char* items,
|
||||||
|
unsigned int bufferLength, unsigned char* buffer);
|
||||||
|
|
||||||
// Additional flags - start from the maximum one
|
// Additional flags - start from the maximum one
|
||||||
static const UCHAR FLAG_DEFAULT_SEGMENTED = 31;
|
static const UCHAR FLAG_DEFAULT_SEGMENTED = 31;
|
||||||
@ -121,6 +123,7 @@ private:
|
|||||||
ULONG reget(ULONG size, UCHAR** buffer, ULONG alignment);
|
ULONG reget(ULONG size, UCHAR** buffer, ULONG alignment);
|
||||||
void remained(ULONG size, ULONG alignment = 0);
|
void remained(ULONG size, ULONG alignment = 0);
|
||||||
ULONG getSize() const;
|
ULONG getSize() const;
|
||||||
|
ULONG getCapacity() const;
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -530,6 +530,11 @@ interface Batch : ReferenceCounted
|
|||||||
|
|
||||||
const uint BLOB_SEGHDR_ALIGN = 2; // Alignment of segment header in the stream
|
const uint BLOB_SEGHDR_ALIGN = 2; // Alignment of segment header in the stream
|
||||||
|
|
||||||
|
const uchar INF_BUFFER_BYTES_SIZE = 10; // Maximum possible buffer size
|
||||||
|
const uchar INF_DATA_BYTES_SIZE = 11; // Already added messages size
|
||||||
|
const uchar INF_BLOBS_BYTES_SIZE = 12; // Already added blobs size
|
||||||
|
const uchar INF_BLOB_ALIGNMENT = 13; // Duplicate getBlobAlignment
|
||||||
|
|
||||||
void add(Status status, uint count, const void* inBuffer);
|
void add(Status status, uint count, const void* inBuffer);
|
||||||
void addBlob(Status status, uint length, const void* inBuffer, ISC_QUAD* blobId, uint parLength, const uchar* par);
|
void addBlob(Status status, uint length, const void* inBuffer, ISC_QUAD* blobId, uint parLength, const uchar* par);
|
||||||
void appendBlobData(Status status, uint length, const void* inBuffer);
|
void appendBlobData(Status status, uint length, const void* inBuffer);
|
||||||
@ -545,6 +550,9 @@ interface Batch : ReferenceCounted
|
|||||||
version: // 4.0.0 => 4.0.1
|
version: // 4.0.0 => 4.0.1
|
||||||
[notImplementedAction if ::FB_UsedInYValve then defaultAction else call deprecatedClose(status) endif]
|
[notImplementedAction if ::FB_UsedInYValve then defaultAction else call deprecatedClose(status) endif]
|
||||||
void close(Status status);
|
void close(Status status);
|
||||||
|
void getInfo(Status status,
|
||||||
|
uint itemsLength, const uchar* items,
|
||||||
|
uint bufferLength, uchar* buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
interface BatchCompletionState : Disposable
|
interface BatchCompletionState : Disposable
|
||||||
@ -1203,6 +1211,8 @@ interface XpbBuilder : Disposable
|
|||||||
const uint SPB_SEND = 7;
|
const uint SPB_SEND = 7;
|
||||||
const uint SPB_RECEIVE = 8;
|
const uint SPB_RECEIVE = 8;
|
||||||
const uint SPB_RESPONSE = 9;
|
const uint SPB_RESPONSE = 9;
|
||||||
|
const uint INFO_SEND = 10;
|
||||||
|
const uint INFO_RESPONSE = 11;
|
||||||
|
|
||||||
// removing data
|
// removing data
|
||||||
void clear(Status status);
|
void clear(Status status);
|
||||||
|
@ -1999,6 +1999,7 @@ namespace Firebird
|
|||||||
void (CLOOP_CARG *setDefaultBpb)(IBatch* self, IStatus* status, unsigned parLength, const unsigned char* par) throw();
|
void (CLOOP_CARG *setDefaultBpb)(IBatch* self, IStatus* status, unsigned parLength, const unsigned char* par) throw();
|
||||||
void (CLOOP_CARG *deprecatedClose)(IBatch* self, IStatus* status) throw();
|
void (CLOOP_CARG *deprecatedClose)(IBatch* self, IStatus* status) throw();
|
||||||
void (CLOOP_CARG *close)(IBatch* self, IStatus* status) throw();
|
void (CLOOP_CARG *close)(IBatch* self, IStatus* status) throw();
|
||||||
|
void (CLOOP_CARG *getInfo)(IBatch* self, IStatus* status, unsigned itemsLength, const unsigned char* items, unsigned bufferLength, unsigned char* buffer) throw();
|
||||||
};
|
};
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@ -2025,6 +2026,10 @@ namespace Firebird
|
|||||||
static const unsigned char BLOB_ID_USER = 2;
|
static const unsigned char BLOB_ID_USER = 2;
|
||||||
static const unsigned char BLOB_STREAM = 3;
|
static const unsigned char BLOB_STREAM = 3;
|
||||||
static const unsigned BLOB_SEGHDR_ALIGN = 2;
|
static const unsigned BLOB_SEGHDR_ALIGN = 2;
|
||||||
|
static const unsigned char INF_BUFFER_BYTES_SIZE = 10;
|
||||||
|
static const unsigned char INF_DATA_BYTES_SIZE = 11;
|
||||||
|
static const unsigned char INF_BLOBS_BYTES_SIZE = 12;
|
||||||
|
static const unsigned char INF_BLOB_ALIGNMENT = 13;
|
||||||
|
|
||||||
template <typename StatusType> void add(StatusType* status, unsigned count, const void* inBuffer)
|
template <typename StatusType> void add(StatusType* status, unsigned count, const void* inBuffer)
|
||||||
{
|
{
|
||||||
@ -2123,6 +2128,19 @@ namespace Firebird
|
|||||||
static_cast<VTable*>(this->cloopVTable)->close(this, status);
|
static_cast<VTable*>(this->cloopVTable)->close(this, status);
|
||||||
StatusType::checkException(status);
|
StatusType::checkException(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename StatusType> void getInfo(StatusType* status, unsigned itemsLength, const unsigned char* items, unsigned bufferLength, unsigned char* buffer)
|
||||||
|
{
|
||||||
|
if (cloopVTable->version < 4)
|
||||||
|
{
|
||||||
|
StatusType::setVersionError(status, "IBatch", cloopVTable->version, 4);
|
||||||
|
StatusType::checkException(status);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
StatusType::clearException(status);
|
||||||
|
static_cast<VTable*>(this->cloopVTable)->getInfo(this, status, itemsLength, items, bufferLength, buffer);
|
||||||
|
StatusType::checkException(status);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class IBatchCompletionState : public IDisposable
|
class IBatchCompletionState : public IDisposable
|
||||||
@ -4755,6 +4773,8 @@ namespace Firebird
|
|||||||
static const unsigned SPB_SEND = 7;
|
static const unsigned SPB_SEND = 7;
|
||||||
static const unsigned SPB_RECEIVE = 8;
|
static const unsigned SPB_RECEIVE = 8;
|
||||||
static const unsigned SPB_RESPONSE = 9;
|
static const unsigned SPB_RESPONSE = 9;
|
||||||
|
static const unsigned INFO_SEND = 10;
|
||||||
|
static const unsigned INFO_RESPONSE = 11;
|
||||||
|
|
||||||
template <typename StatusType> void clear(StatusType* status)
|
template <typename StatusType> void clear(StatusType* status)
|
||||||
{
|
{
|
||||||
@ -10173,6 +10193,7 @@ namespace Firebird
|
|||||||
this->setDefaultBpb = &Name::cloopsetDefaultBpbDispatcher;
|
this->setDefaultBpb = &Name::cloopsetDefaultBpbDispatcher;
|
||||||
this->deprecatedClose = &Name::cloopdeprecatedCloseDispatcher;
|
this->deprecatedClose = &Name::cloopdeprecatedCloseDispatcher;
|
||||||
this->close = &Name::cloopcloseDispatcher;
|
this->close = &Name::cloopcloseDispatcher;
|
||||||
|
this->getInfo = &Name::cloopgetInfoDispatcher;
|
||||||
}
|
}
|
||||||
} vTable;
|
} vTable;
|
||||||
|
|
||||||
@ -10350,6 +10371,20 @@ namespace Firebird
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void CLOOP_CARG cloopgetInfoDispatcher(IBatch* self, IStatus* status, unsigned itemsLength, const unsigned char* items, unsigned bufferLength, unsigned char* buffer) throw()
|
||||||
|
{
|
||||||
|
StatusType status2(status);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
static_cast<Name*>(self)->Name::getInfo(&status2, itemsLength, items, bufferLength, buffer);
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
StatusType::catchException(&status2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void CLOOP_CARG cloopaddRefDispatcher(IReferenceCounted* self) throw()
|
static void CLOOP_CARG cloopaddRefDispatcher(IReferenceCounted* self) throw()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@ -10401,6 +10436,7 @@ namespace Firebird
|
|||||||
virtual void setDefaultBpb(StatusType* status, unsigned parLength, const unsigned char* par) = 0;
|
virtual void setDefaultBpb(StatusType* status, unsigned parLength, const unsigned char* par) = 0;
|
||||||
virtual void deprecatedClose(StatusType* status) = 0;
|
virtual void deprecatedClose(StatusType* status) = 0;
|
||||||
virtual void close(StatusType* status) = 0;
|
virtual void close(StatusType* status) = 0;
|
||||||
|
virtual void getInfo(StatusType* status, unsigned itemsLength, const unsigned char* items, unsigned bufferLength, unsigned char* buffer) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Name, typename StatusType, typename Base>
|
template <typename Name, typename StatusType, typename Base>
|
||||||
|
@ -366,6 +366,7 @@ type
|
|||||||
IBatch_setDefaultBpbPtr = procedure(this: IBatch; status: IStatus; parLength: Cardinal; par: BytePtr); cdecl;
|
IBatch_setDefaultBpbPtr = procedure(this: IBatch; status: IStatus; parLength: Cardinal; par: BytePtr); cdecl;
|
||||||
IBatch_deprecatedClosePtr = procedure(this: IBatch; status: IStatus); cdecl;
|
IBatch_deprecatedClosePtr = procedure(this: IBatch; status: IStatus); cdecl;
|
||||||
IBatch_closePtr = procedure(this: IBatch; status: IStatus); cdecl;
|
IBatch_closePtr = procedure(this: IBatch; status: IStatus); cdecl;
|
||||||
|
IBatch_getInfoPtr = procedure(this: IBatch; status: IStatus; itemsLength: Cardinal; items: BytePtr; bufferLength: Cardinal; buffer: BytePtr); cdecl;
|
||||||
IBatchCompletionState_getSizePtr = function(this: IBatchCompletionState; status: IStatus): Cardinal; cdecl;
|
IBatchCompletionState_getSizePtr = function(this: IBatchCompletionState; status: IStatus): Cardinal; cdecl;
|
||||||
IBatchCompletionState_getStatePtr = function(this: IBatchCompletionState; status: IStatus; pos: Cardinal): Integer; cdecl;
|
IBatchCompletionState_getStatePtr = function(this: IBatchCompletionState; status: IStatus; pos: Cardinal): Integer; cdecl;
|
||||||
IBatchCompletionState_findErrorPtr = function(this: IBatchCompletionState; status: IStatus; pos: Cardinal): Cardinal; cdecl;
|
IBatchCompletionState_findErrorPtr = function(this: IBatchCompletionState; status: IStatus; pos: Cardinal): Cardinal; cdecl;
|
||||||
@ -1548,6 +1549,7 @@ type
|
|||||||
setDefaultBpb: IBatch_setDefaultBpbPtr;
|
setDefaultBpb: IBatch_setDefaultBpbPtr;
|
||||||
deprecatedClose: IBatch_deprecatedClosePtr;
|
deprecatedClose: IBatch_deprecatedClosePtr;
|
||||||
close: IBatch_closePtr;
|
close: IBatch_closePtr;
|
||||||
|
getInfo: IBatch_getInfoPtr;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
IBatch = class(IReferenceCounted)
|
IBatch = class(IReferenceCounted)
|
||||||
@ -1563,6 +1565,10 @@ type
|
|||||||
const BLOB_ID_USER = Byte(2);
|
const BLOB_ID_USER = Byte(2);
|
||||||
const BLOB_STREAM = Byte(3);
|
const BLOB_STREAM = Byte(3);
|
||||||
const BLOB_SEGHDR_ALIGN = Cardinal(2);
|
const BLOB_SEGHDR_ALIGN = Cardinal(2);
|
||||||
|
const INF_BUFFER_BYTES_SIZE = Byte(10);
|
||||||
|
const INF_DATA_BYTES_SIZE = Byte(11);
|
||||||
|
const INF_BLOBS_BYTES_SIZE = Byte(12);
|
||||||
|
const INF_BLOB_ALIGNMENT = Byte(13);
|
||||||
|
|
||||||
procedure add(status: IStatus; count: Cardinal; inBuffer: Pointer);
|
procedure add(status: IStatus; count: Cardinal; inBuffer: Pointer);
|
||||||
procedure addBlob(status: IStatus; length: Cardinal; inBuffer: Pointer; blobId: ISC_QUADPtr; parLength: Cardinal; par: BytePtr);
|
procedure addBlob(status: IStatus; length: Cardinal; inBuffer: Pointer; blobId: ISC_QUADPtr; parLength: Cardinal; par: BytePtr);
|
||||||
@ -1576,6 +1582,7 @@ type
|
|||||||
procedure setDefaultBpb(status: IStatus; parLength: Cardinal; par: BytePtr);
|
procedure setDefaultBpb(status: IStatus; parLength: Cardinal; par: BytePtr);
|
||||||
procedure deprecatedClose(status: IStatus);
|
procedure deprecatedClose(status: IStatus);
|
||||||
procedure close(status: IStatus);
|
procedure close(status: IStatus);
|
||||||
|
procedure getInfo(status: IStatus; itemsLength: Cardinal; items: BytePtr; bufferLength: Cardinal; buffer: BytePtr);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
IBatchImpl = class(IBatch)
|
IBatchImpl = class(IBatch)
|
||||||
@ -1595,6 +1602,7 @@ type
|
|||||||
procedure setDefaultBpb(status: IStatus; parLength: Cardinal; par: BytePtr); virtual; abstract;
|
procedure setDefaultBpb(status: IStatus; parLength: Cardinal; par: BytePtr); virtual; abstract;
|
||||||
procedure deprecatedClose(status: IStatus); virtual; abstract;
|
procedure deprecatedClose(status: IStatus); virtual; abstract;
|
||||||
procedure close(status: IStatus); virtual; abstract;
|
procedure close(status: IStatus); virtual; abstract;
|
||||||
|
procedure getInfo(status: IStatus; itemsLength: Cardinal; items: BytePtr; bufferLength: Cardinal; buffer: BytePtr); virtual; abstract;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
BatchCompletionStateVTable = class(DisposableVTable)
|
BatchCompletionStateVTable = class(DisposableVTable)
|
||||||
@ -2798,6 +2806,8 @@ type
|
|||||||
const SPB_SEND = Cardinal(7);
|
const SPB_SEND = Cardinal(7);
|
||||||
const SPB_RECEIVE = Cardinal(8);
|
const SPB_RECEIVE = Cardinal(8);
|
||||||
const SPB_RESPONSE = Cardinal(9);
|
const SPB_RESPONSE = Cardinal(9);
|
||||||
|
const INFO_SEND = Cardinal(10);
|
||||||
|
const INFO_RESPONSE = Cardinal(11);
|
||||||
|
|
||||||
procedure clear(status: IStatus);
|
procedure clear(status: IStatus);
|
||||||
procedure removeCurrent(status: IStatus);
|
procedure removeCurrent(status: IStatus);
|
||||||
@ -6685,6 +6695,17 @@ begin
|
|||||||
FbException.checkException(status);
|
FbException.checkException(status);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure IBatch.getInfo(status: IStatus; itemsLength: Cardinal; items: BytePtr; bufferLength: Cardinal; buffer: BytePtr);
|
||||||
|
begin
|
||||||
|
if (vTable.version < 4) then begin
|
||||||
|
FbException.setVersionError(status, 'IBatch', vTable.version, 4);
|
||||||
|
end
|
||||||
|
else begin
|
||||||
|
BatchVTable(vTable).getInfo(Self, status, itemsLength, items, bufferLength, buffer);
|
||||||
|
end;
|
||||||
|
FbException.checkException(status);
|
||||||
|
end;
|
||||||
|
|
||||||
function IBatchCompletionState.getSize(status: IStatus): Cardinal;
|
function IBatchCompletionState.getSize(status: IStatus): Cardinal;
|
||||||
begin
|
begin
|
||||||
Result := BatchCompletionStateVTable(vTable).getSize(Self, status);
|
Result := BatchCompletionStateVTable(vTable).getSize(Self, status);
|
||||||
@ -10704,6 +10725,15 @@ begin
|
|||||||
end
|
end
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure IBatchImpl_getInfoDispatcher(this: IBatch; status: IStatus; itemsLength: Cardinal; items: BytePtr; bufferLength: Cardinal; buffer: BytePtr); cdecl;
|
||||||
|
begin
|
||||||
|
try
|
||||||
|
IBatchImpl(this).getInfo(status, itemsLength, items, bufferLength, buffer);
|
||||||
|
except
|
||||||
|
on e: Exception do FbException.catchException(status, e);
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
|
||||||
var
|
var
|
||||||
IBatchImpl_vTable: BatchVTable;
|
IBatchImpl_vTable: BatchVTable;
|
||||||
|
|
||||||
@ -15637,6 +15667,7 @@ initialization
|
|||||||
IBatchImpl_vTable.setDefaultBpb := @IBatchImpl_setDefaultBpbDispatcher;
|
IBatchImpl_vTable.setDefaultBpb := @IBatchImpl_setDefaultBpbDispatcher;
|
||||||
IBatchImpl_vTable.deprecatedClose := @IBatchImpl_deprecatedCloseDispatcher;
|
IBatchImpl_vTable.deprecatedClose := @IBatchImpl_deprecatedCloseDispatcher;
|
||||||
IBatchImpl_vTable.close := @IBatchImpl_closeDispatcher;
|
IBatchImpl_vTable.close := @IBatchImpl_closeDispatcher;
|
||||||
|
IBatchImpl_vTable.getInfo := @IBatchImpl_getInfoDispatcher;
|
||||||
|
|
||||||
IBatchCompletionStateImpl_vTable := BatchCompletionStateVTable.create;
|
IBatchCompletionStateImpl_vTable := BatchCompletionStateVTable.create;
|
||||||
IBatchCompletionStateImpl_vTable.version := 3;
|
IBatchCompletionStateImpl_vTable.version := 3;
|
||||||
|
@ -882,7 +882,7 @@ Data source : @4"}, /* eds_statement */
|
|||||||
{335545175, "Segment size (@1) should not exceed 65535 (64K - 1) when using segmented blob"}, /* big_segment */
|
{335545175, "Segment size (@1) should not exceed 65535 (64K - 1) when using segmented blob"}, /* big_segment */
|
||||||
{335545176, "Invalid blob policy in the batch for @1() call"}, /* batch_policy */
|
{335545176, "Invalid blob policy in the batch for @1() call"}, /* batch_policy */
|
||||||
{335545177, "Can't change default BPB after adding any data to batch"}, /* batch_defbpb */
|
{335545177, "Can't change default BPB after adding any data to batch"}, /* batch_defbpb */
|
||||||
{335545178, "Unexpected info buffer structure querying for default blob alignment"}, /* batch_align */
|
{335545178, "Unexpected info buffer structure querying for server batch parameters"}, /* batch_align */
|
||||||
{335545179, "Duplicated segment @1 in multisegment connect block parameter"}, /* multi_segment_dup */
|
{335545179, "Duplicated segment @1 in multisegment connect block parameter"}, /* multi_segment_dup */
|
||||||
{335545180, "Plugin not supported by network protocol"}, /* non_plugin_protocol */
|
{335545180, "Plugin not supported by network protocol"}, /* non_plugin_protocol */
|
||||||
{335545181, "Error parsing message format"}, /* message_format */
|
{335545181, "Error parsing message format"}, /* message_format */
|
||||||
|
@ -209,6 +209,8 @@ public:
|
|||||||
void setDefaultBpb(Firebird::CheckStatusWrapper* status, unsigned parLength, const unsigned char* par) override;
|
void setDefaultBpb(Firebird::CheckStatusWrapper* status, unsigned parLength, const unsigned char* par) override;
|
||||||
void close(Firebird::CheckStatusWrapper* status) override;
|
void close(Firebird::CheckStatusWrapper* status) override;
|
||||||
void deprecatedClose(Firebird::CheckStatusWrapper* status) override;
|
void deprecatedClose(Firebird::CheckStatusWrapper* status) override;
|
||||||
|
void getInfo(Firebird::CheckStatusWrapper* status, unsigned int itemsLength, const unsigned char* items,
|
||||||
|
unsigned int bufferLength, unsigned char* buffer) override;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
JBatch(DsqlBatch* handle, JStatement* aStatement, Firebird::IMessageMetadata* aMetadata);
|
JBatch(DsqlBatch* handle, JStatement* aStatement, Firebird::IMessageMetadata* aMetadata);
|
||||||
|
@ -6330,6 +6330,48 @@ void JBatch::cancel(CheckStatusWrapper* status)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void JBatch::getInfo(CheckStatusWrapper* user_status,
|
||||||
|
unsigned int itemsLength, const unsigned char* items,
|
||||||
|
unsigned int bufferLength, unsigned char* buffer)
|
||||||
|
{
|
||||||
|
/**************************************
|
||||||
|
*
|
||||||
|
* g d s _ $ b l o b _ i n f o
|
||||||
|
*
|
||||||
|
**************************************
|
||||||
|
*
|
||||||
|
* Functional description
|
||||||
|
* Provide information on blob object.
|
||||||
|
*
|
||||||
|
**************************************/
|
||||||
|
try
|
||||||
|
{
|
||||||
|
EngineContextHolder tdbb(user_status, this, FB_FUNCTION);
|
||||||
|
check_database(tdbb);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
DsqlBatch* b = getHandle();
|
||||||
|
b->info(tdbb, itemsLength, items, bufferLength, buffer);
|
||||||
|
}
|
||||||
|
catch (const Exception& ex)
|
||||||
|
{
|
||||||
|
transliterateException(tdbb, ex, user_status, "JBatch::getInfo");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (const Exception& ex)
|
||||||
|
{
|
||||||
|
ex.stuffException(user_status);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
successful_completion(user_status);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
JReplicator::JReplicator(Applier* appl, StableAttachmentPart* sa)
|
JReplicator::JReplicator(Applier* appl, StableAttachmentPart* sa)
|
||||||
: applier(appl), sAtt(sa)
|
: applier(appl), sAtt(sa)
|
||||||
{ }
|
{ }
|
||||||
|
@ -965,7 +965,7 @@ Data source : @4', NULL, NULL)
|
|||||||
('big_segment', NULL, NULL, NULL, 0, 855, NULL, 'Segment size (@1) should not exceed 65535 (64K - 1) when using segmented blob', NULL, NULL);
|
('big_segment', NULL, NULL, NULL, 0, 855, NULL, 'Segment size (@1) should not exceed 65535 (64K - 1) when using segmented blob', NULL, NULL);
|
||||||
('batch_policy', NULL, NULL, NULL, 0, 856, NULL, 'Invalid blob policy in the batch for @1() call', NULL, NULL);
|
('batch_policy', NULL, NULL, NULL, 0, 856, NULL, 'Invalid blob policy in the batch for @1() call', NULL, NULL);
|
||||||
('batch_defbpb', NULL, NULL, NULL, 0, 857, NULL, 'Can''t change default BPB after adding any data to batch', NULL, NULL);
|
('batch_defbpb', NULL, NULL, NULL, 0, 857, NULL, 'Can''t change default BPB after adding any data to batch', NULL, NULL);
|
||||||
('batch_align', NULL, 'interface.cpp', NULL, 0, 858, NULL, 'Unexpected info buffer structure querying for default blob alignment', NULL, NULL);
|
('batch_align', NULL, 'interface.cpp', NULL, 0, 858, NULL, 'Unexpected info buffer structure querying for server batch parameters', NULL, NULL);
|
||||||
('multi_segment_dup', 'getMultiPartConnectParameter', 'server.cpp', NULL, 0, 859, NULL, 'Duplicated segment @1 in multisegment connect block parameter', NULL, NULL);
|
('multi_segment_dup', 'getMultiPartConnectParameter', 'server.cpp', NULL, 0, 859, NULL, 'Duplicated segment @1 in multisegment connect block parameter', NULL, NULL);
|
||||||
('non_plugin_protocol', NULL, 'server.cpp', NULL, 0, 860, NULL, 'Plugin not supported by network protocol', NULL, NULL);
|
('non_plugin_protocol', NULL, 'server.cpp', NULL, 0, 860, NULL, 'Plugin not supported by network protocol', NULL, NULL);
|
||||||
('message_format', NULL, 'server.cpp', NULL, 0, 861, NULL, 'Error parsing message format', NULL, NULL);
|
('message_format', NULL, 'server.cpp', NULL, 0, 861, NULL, 'Error parsing message format', NULL, NULL);
|
||||||
|
@ -349,11 +349,14 @@ public:
|
|||||||
Firebird::IMessageMetadata* getMetadata(Firebird::CheckStatusWrapper* status) override;
|
Firebird::IMessageMetadata* getMetadata(Firebird::CheckStatusWrapper* status) override;
|
||||||
void close(Firebird::CheckStatusWrapper* status) override;
|
void close(Firebird::CheckStatusWrapper* status) override;
|
||||||
void deprecatedClose(Firebird::CheckStatusWrapper* status) override;
|
void deprecatedClose(Firebird::CheckStatusWrapper* status) override;
|
||||||
|
void getInfo(CheckStatusWrapper* status,
|
||||||
|
unsigned int itemsLength, const unsigned char* items,
|
||||||
|
unsigned int bufferLength, unsigned char* buffer) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void freeClientData(CheckStatusWrapper* status, bool force = false);
|
void freeClientData(CheckStatusWrapper* status, bool force = false);
|
||||||
void releaseStatement();
|
void releaseStatement();
|
||||||
void setBlobAlignment();
|
void setServerInfo();
|
||||||
|
|
||||||
void cleanup()
|
void cleanup()
|
||||||
{
|
{
|
||||||
@ -411,7 +414,7 @@ private:
|
|||||||
// working with blob stream buffer
|
// working with blob stream buffer
|
||||||
void newBlob()
|
void newBlob()
|
||||||
{
|
{
|
||||||
setBlobAlignment();
|
setServerInfo();
|
||||||
alignBlobBuffer(blobAlign);
|
alignBlobBuffer(blobAlign);
|
||||||
|
|
||||||
fb_assert(blobStream - blobStreamBuffer <= blobBufferSize);
|
fb_assert(blobStream - blobStreamBuffer <= blobBufferSize);
|
||||||
@ -513,7 +516,7 @@ private:
|
|||||||
{
|
{
|
||||||
if (blobPolicy != BLOB_NONE)
|
if (blobPolicy != BLOB_NONE)
|
||||||
{
|
{
|
||||||
setBlobAlignment();
|
setServerInfo();
|
||||||
alignBlobBuffer(blobAlign);
|
alignBlobBuffer(blobAlign);
|
||||||
ULONG size = blobStream - blobStreamBuffer;
|
ULONG size = blobStream - blobStreamBuffer;
|
||||||
if (size)
|
if (size)
|
||||||
@ -530,6 +533,7 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
batchActive = false;
|
batchActive = false;
|
||||||
|
blobCount = messageCount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void sendBlobPacket(unsigned size, const UCHAR* ptr, bool flash);
|
void sendBlobPacket(unsigned size, const UCHAR* ptr, bool flash);
|
||||||
@ -549,6 +553,8 @@ private:
|
|||||||
UCHAR blobPolicy;
|
UCHAR blobPolicy;
|
||||||
bool segmented, defSegmented, batchActive;
|
bool segmented, defSegmented, batchActive;
|
||||||
|
|
||||||
|
ULONG messageCount, blobCount, serverSize;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
bool tmpStatement;
|
bool tmpStatement;
|
||||||
};
|
};
|
||||||
@ -2368,7 +2374,8 @@ Batch::Batch(Statement* s, IMessageMetadata* inFmt, unsigned parLength, const un
|
|||||||
: messageStream(0), blobStream(nullptr), sizePointer(nullptr),
|
: messageStream(0), blobStream(nullptr), sizePointer(nullptr),
|
||||||
messageSize(0), alignedSize(0), blobBufferSize(0), messageBufferSize(0), flags(0),
|
messageSize(0), alignedSize(0), blobBufferSize(0), messageBufferSize(0), flags(0),
|
||||||
stmt(s), format(inFmt), blobAlign(0), blobPolicy(BLOB_NONE),
|
stmt(s), format(inFmt), blobAlign(0), blobPolicy(BLOB_NONE),
|
||||||
segmented(false), defSegmented(false), batchActive(false), tmpStatement(false)
|
segmented(false), defSegmented(false), batchActive(false),
|
||||||
|
messageCount(0), blobCount(0), serverSize(0), tmpStatement(false)
|
||||||
{
|
{
|
||||||
LocalStatus ls;
|
LocalStatus ls;
|
||||||
CheckStatusWrapper st(&ls);
|
CheckStatusWrapper st(&ls);
|
||||||
@ -2484,6 +2491,7 @@ void Batch::sendMessagePacket(unsigned count, const UCHAR* ptr, bool flash)
|
|||||||
statement->rsr_batch_size = alignedSize;
|
statement->rsr_batch_size = alignedSize;
|
||||||
|
|
||||||
sendDeferredPacket(port, packet, flash);
|
sendDeferredPacket(port, packet, flash);
|
||||||
|
messageCount += count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -2616,7 +2624,7 @@ void Batch::sendBlobPacket(unsigned size, const UCHAR* ptr, bool flash)
|
|||||||
Rdb* rdb = statement->rsr_rdb;
|
Rdb* rdb = statement->rsr_rdb;
|
||||||
rem_port* port = rdb->rdb_port;
|
rem_port* port = rdb->rdb_port;
|
||||||
|
|
||||||
setBlobAlignment();
|
setServerInfo();
|
||||||
fb_assert(!(size % blobAlign));
|
fb_assert(!(size % blobAlign));
|
||||||
|
|
||||||
PACKET* packet = &rdb->rdb_packet;
|
PACKET* packet = &rdb->rdb_packet;
|
||||||
@ -2627,6 +2635,8 @@ void Batch::sendBlobPacket(unsigned size, const UCHAR* ptr, bool flash)
|
|||||||
batch->p_batch_blob_data.cstr_length = size;
|
batch->p_batch_blob_data.cstr_length = size;
|
||||||
|
|
||||||
sendDeferredPacket(port, packet, flash);
|
sendDeferredPacket(port, packet, flash);
|
||||||
|
|
||||||
|
blobCount += size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -2698,7 +2708,7 @@ unsigned Batch::getBlobAlignment(CheckStatusWrapper* status)
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
setBlobAlignment();
|
setServerInfo();
|
||||||
}
|
}
|
||||||
catch (const Exception& ex)
|
catch (const Exception& ex)
|
||||||
{
|
{
|
||||||
@ -2709,7 +2719,7 @@ unsigned Batch::getBlobAlignment(CheckStatusWrapper* status)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Batch::setBlobAlignment()
|
void Batch::setServerInfo()
|
||||||
{
|
{
|
||||||
if (blobAlign)
|
if (blobAlign)
|
||||||
return;
|
return;
|
||||||
@ -2727,21 +2737,68 @@ void Batch::setBlobAlignment()
|
|||||||
rem_port* port = rdb->rdb_port;
|
rem_port* port = rdb->rdb_port;
|
||||||
RefMutexGuard portGuard(*port->port_sync, FB_FUNCTION);
|
RefMutexGuard portGuard(*port->port_sync, FB_FUNCTION);
|
||||||
|
|
||||||
// Perform info call to server
|
|
||||||
LocalStatus ls;
|
LocalStatus ls;
|
||||||
CheckStatusWrapper s(&ls);
|
CheckStatusWrapper s(&ls);
|
||||||
UCHAR item = isc_info_sql_stmt_blob_align;
|
|
||||||
UCHAR buffer[16];
|
if (port->port_protocol < PROTOCOL_VERSION17)
|
||||||
info(&s, rdb, op_info_sql, statement->rsr_id, 0,
|
{
|
||||||
1, &item, 0, 0, sizeof(buffer), buffer);
|
UCHAR item = isc_info_sql_stmt_blob_align;
|
||||||
|
UCHAR buffer[16];
|
||||||
|
info(&s, rdb, op_info_sql, statement->rsr_id, 0,
|
||||||
|
1, &item, 0, 0, sizeof(buffer), buffer);
|
||||||
|
check(&s);
|
||||||
|
|
||||||
|
// Extract from buffer
|
||||||
|
if (buffer[0] != item)
|
||||||
|
Arg::Gds(isc_batch_align).raise();
|
||||||
|
|
||||||
|
int len = gds__vax_integer(&buffer[1], 2);
|
||||||
|
statement->rsr_batch_stream.alignment = blobAlign = gds__vax_integer(&buffer[3], len);
|
||||||
|
|
||||||
|
if (!blobAlign)
|
||||||
|
Arg::Gds(isc_batch_align).raise();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Perform info call to server
|
||||||
|
UCHAR items[] = {IBatch::INF_BLOB_ALIGNMENT, IBatch::INF_BUFFER_BYTES_SIZE};
|
||||||
|
UCHAR buffer[32];
|
||||||
|
info(&s, rdb, op_info_batch, statement->rsr_id, 0,
|
||||||
|
sizeof(items), items, 0, 0, sizeof(buffer), buffer);
|
||||||
check(&s);
|
check(&s);
|
||||||
|
|
||||||
// Extract from buffer
|
// Extract from buffer
|
||||||
if (buffer[0] != item)
|
ClumpletReader out(ClumpletReader::InfoResponse, buffer, sizeof(buffer));
|
||||||
Arg::Gds(isc_batch_align).raise();
|
for (out.rewind(); !out.isEof(); out.moveNext())
|
||||||
|
{
|
||||||
|
UCHAR item = out.getClumpTag();
|
||||||
|
if (item == isc_info_end)
|
||||||
|
break;
|
||||||
|
|
||||||
int len = gds__vax_integer(&buffer[1], 2);
|
switch(item)
|
||||||
statement->rsr_batch_stream.alignment = blobAlign = gds__vax_integer(&buffer[3], len);
|
{
|
||||||
|
case IBatch::INF_BLOB_ALIGNMENT:
|
||||||
|
statement->rsr_batch_stream.alignment = blobAlign = out.getInt();
|
||||||
|
break;
|
||||||
|
case IBatch::INF_BUFFER_BYTES_SIZE:
|
||||||
|
serverSize = out.getInt();
|
||||||
|
break;
|
||||||
|
case isc_info_error:
|
||||||
|
(Arg::Gds(isc_batch_align) << Arg::Gds(out.getInt())).raise();
|
||||||
|
case isc_info_truncated:
|
||||||
|
(Arg::Gds(isc_batch_align) << Arg::Gds(isc_random) << "truncated").raise();
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
string msg;
|
||||||
|
msg.printf("Wrong info item %u", item);
|
||||||
|
(Arg::Gds(isc_batch_align) << Arg::Gds(isc_random) << msg).raise();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! (blobAlign && serverSize))
|
||||||
|
Arg::Gds(isc_batch_align).raise();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -2960,6 +3017,73 @@ void Batch::close(CheckStatusWrapper* status)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Batch::getInfo(CheckStatusWrapper* status, unsigned int itemsLength, const unsigned char* items,
|
||||||
|
unsigned int bufferLength, unsigned char* buffer)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ClumpletReader it(ClumpletReader::InfoItems, items, itemsLength);
|
||||||
|
ClumpletWriter out(ClumpletReader::InfoResponse, bufferLength - 1); // place for isc_info_end / isc_info_truncated
|
||||||
|
|
||||||
|
for (it.rewind(); !it.isEof(); it.moveNext())
|
||||||
|
{
|
||||||
|
UCHAR item = it.getClumpTag();
|
||||||
|
if (item == isc_info_end)
|
||||||
|
break;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
switch(item)
|
||||||
|
{
|
||||||
|
case IBatch::INF_BUFFER_BYTES_SIZE:
|
||||||
|
setServerInfo();
|
||||||
|
if (serverSize)
|
||||||
|
out.insertInt(item, serverSize);
|
||||||
|
break;
|
||||||
|
case IBatch::INF_DATA_BYTES_SIZE:
|
||||||
|
out.insertInt(item, (messageCount + messageStream) * alignedSize);
|
||||||
|
break;
|
||||||
|
case IBatch::INF_BLOBS_BYTES_SIZE:
|
||||||
|
if (blobStream)
|
||||||
|
out.insertInt(item, blobCount + (blobStream - blobStreamBuffer));
|
||||||
|
break;
|
||||||
|
case IBatch::INF_BLOB_ALIGNMENT:
|
||||||
|
setServerInfo();
|
||||||
|
out.insertInt(item, blobAlign);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
out.insertInt(isc_info_error, isc_infunk);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(const fatal_exception&)
|
||||||
|
{
|
||||||
|
// here it's sooner of all caused by writer overflow but anyway check that
|
||||||
|
if (out.hasOverflow())
|
||||||
|
{
|
||||||
|
memcpy(buffer, out.getBuffer(), out.getBufferLength());
|
||||||
|
buffer += out.getBufferLength();
|
||||||
|
*buffer++ = isc_info_truncated;
|
||||||
|
if (out.getBufferLength() <= bufferLength - 2)
|
||||||
|
*buffer++ = isc_info_end;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(buffer, out.getBuffer(), out.getBufferLength());
|
||||||
|
buffer += out.getBufferLength();
|
||||||
|
*buffer++ = isc_info_end;
|
||||||
|
}
|
||||||
|
catch (const Exception& ex)
|
||||||
|
{
|
||||||
|
ex.stuffException(status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void Batch::releaseStatement()
|
void Batch::releaseStatement()
|
||||||
{
|
{
|
||||||
if (tmpStatement)
|
if (tmpStatement)
|
||||||
|
@ -504,6 +504,7 @@ bool_t xdr_protocol(RemoteXdr* xdrs, PACKET* p)
|
|||||||
case op_info_transaction:
|
case op_info_transaction:
|
||||||
case op_service_info:
|
case op_service_info:
|
||||||
case op_info_sql:
|
case op_info_sql:
|
||||||
|
case op_info_batch:
|
||||||
info = &p->p_info;
|
info = &p->p_info;
|
||||||
MAP(xdr_short, reinterpret_cast<SSHORT&>(info->p_info_object));
|
MAP(xdr_short, reinterpret_cast<SSHORT&>(info->p_info_object));
|
||||||
MAP(xdr_short, reinterpret_cast<SSHORT&>(info->p_info_incarnation));
|
MAP(xdr_short, reinterpret_cast<SSHORT&>(info->p_info_incarnation));
|
||||||
|
@ -94,7 +94,7 @@ const USHORT PROTOCOL_VERSION16 = (FB_PROTOCOL_FLAG | 16);
|
|||||||
const USHORT PROTOCOL_STMT_TOUT = PROTOCOL_VERSION16;
|
const USHORT PROTOCOL_STMT_TOUT = PROTOCOL_VERSION16;
|
||||||
|
|
||||||
// Protocol 17:
|
// Protocol 17:
|
||||||
// - supports op_batch_sync
|
// - supports op_batch_sync, op_info_batch
|
||||||
|
|
||||||
const USHORT PROTOCOL_VERSION17 = (FB_PROTOCOL_FLAG | 17);
|
const USHORT PROTOCOL_VERSION17 = (FB_PROTOCOL_FLAG | 17);
|
||||||
|
|
||||||
@ -295,6 +295,7 @@ enum P_OP
|
|||||||
|
|
||||||
op_batch_cancel = 109,
|
op_batch_cancel = 109,
|
||||||
op_batch_sync = 110,
|
op_batch_sync = 110,
|
||||||
|
op_info_batch = 111,
|
||||||
|
|
||||||
op_max
|
op_max
|
||||||
};
|
};
|
||||||
|
@ -4431,6 +4431,15 @@ void rem_port::info(P_OP op, P_INFO* stuff, PACKET* sendL)
|
|||||||
statement->rsr_iface->getInfo(&status_vector, info_len, info_buffer,
|
statement->rsr_iface->getInfo(&status_vector, info_len, info_buffer,
|
||||||
buffer_length, buffer);
|
buffer_length, buffer);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case op_info_batch:
|
||||||
|
getHandle(statement, stuff->p_info_object);
|
||||||
|
statement->checkIface();
|
||||||
|
statement->checkBatch();
|
||||||
|
|
||||||
|
statement->rsr_batch->getInfo(&status_vector, info_len, info_buffer,
|
||||||
|
buffer_length, buffer);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send a response that includes the segment.
|
// Send a response that includes the segment.
|
||||||
@ -4911,6 +4920,7 @@ static bool process_packet(rem_port* port, PACKET* sendL, PACKET* receive, rem_p
|
|||||||
case op_info_transaction:
|
case op_info_transaction:
|
||||||
case op_service_info:
|
case op_service_info:
|
||||||
case op_info_sql:
|
case op_info_sql:
|
||||||
|
case op_info_batch:
|
||||||
port->info(op, &receive->p_info, sendL);
|
port->info(op, &receive->p_info, sendL);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -397,6 +397,8 @@ public:
|
|||||||
void setDefaultBpb(Firebird::CheckStatusWrapper* status, unsigned parLength, const unsigned char* par);
|
void setDefaultBpb(Firebird::CheckStatusWrapper* status, unsigned parLength, const unsigned char* par);
|
||||||
void close(Firebird::CheckStatusWrapper* status);
|
void close(Firebird::CheckStatusWrapper* status);
|
||||||
void deprecatedClose(Firebird::CheckStatusWrapper* status);
|
void deprecatedClose(Firebird::CheckStatusWrapper* status);
|
||||||
|
void getInfo(Firebird::CheckStatusWrapper* status, unsigned int itemsLength, const unsigned char* items,
|
||||||
|
unsigned int bufferLength, unsigned char* buffer);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AtomicAttPtr attachment;
|
AtomicAttPtr attachment;
|
||||||
|
@ -916,8 +916,14 @@ public:
|
|||||||
case SPB_RESPONSE:
|
case SPB_RESPONSE:
|
||||||
k = ClumpletReader::SpbResponse;
|
k = ClumpletReader::SpbResponse;
|
||||||
break;
|
break;
|
||||||
|
case INFO_SEND:
|
||||||
|
k = ClumpletReader::InfoItems;
|
||||||
|
break;
|
||||||
|
case INFO_RESPONSE:
|
||||||
|
k = ClumpletReader::InfoResponse;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
fatal_exception::raiseFmt("Wrong parameters block kind %d, should be from %d to %d", kind, DPB, SPB_RESPONSE);
|
fatal_exception::raiseFmt("Wrong parameters block kind %d, should be from %d to %d", kind, DPB, INFO_RESPONSE);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5084,6 +5084,22 @@ void YBatch::deprecatedClose(CheckStatusWrapper* status)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void YBatch::getInfo(CheckStatusWrapper* status, unsigned int itemsLength, const unsigned char* items,
|
||||||
|
unsigned int bufferLength, unsigned char* buffer)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
YEntry<YBatch> entry(status, this);
|
||||||
|
|
||||||
|
entry.next()->getInfo(status, itemsLength, items, bufferLength, buffer);
|
||||||
|
}
|
||||||
|
catch (const Exception& e)
|
||||||
|
{
|
||||||
|
e.stuffException(status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//-------------------------------------
|
//-------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user