mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-23 18:03:04 +01:00
2149 lines
108 KiB
HTML
2149 lines
108 KiB
HTML
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
|
||
<HTML>
|
||
<HEAD>
|
||
<META HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html; charset=utf-8">
|
||
<TITLE></TITLE>
|
||
<META NAME="GENERATOR" CONTENT="OpenOffice 4.1.2 (Unix)">
|
||
<META NAME="AUTHOR" CONTENT="alex ">
|
||
<META NAME="CREATED" CONTENT="20130531;10003100">
|
||
<META NAME="CHANGEDBY" CONTENT="Alex Peshkoff">
|
||
<META NAME="CHANGED" CONTENT="20160404;21484900">
|
||
<META NAME="CHANGEDBY" CONTENT="Alex Peshkoff">
|
||
<STYLE TYPE="text/css">
|
||
<!--
|
||
@page { size: 8.5in 11in; margin: 0.79in }
|
||
TD P { margin-bottom: 0.08in; color: #000000 }
|
||
H1 { color: #000000 }
|
||
P { margin-bottom: 0.08in; color: #000000 }
|
||
-->
|
||
</STYLE>
|
||
</HEAD>
|
||
<BODY LANG="en-US" TEXT="#000000" DIR="LTR">
|
||
<P STYLE="margin-top: 0.17in; margin-bottom: 0.2in; page-break-after: avoid">
|
||
<FONT FACE="Albany, sans-serif"><FONT SIZE=5>Firebird interfaces.</FONT></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>Firebird's OO API is based
|
||
on use of interfaces. That interfaces, though looking in some aspects
|
||
like OLE2 interfaces (some of them have addRef() and release()
|
||
methods) are non standard and have features, missing in ither widely
|
||
used types of interfaces. First of all Firebird interfaces are
|
||
</FONT><FONT SIZE=4><B>language independent</B></FONT> – <FONT SIZE=4>that
|
||
means that to define/use them one need not use language specific
|
||
constructions like </FONT><FONT SIZE=4><I>class</I></FONT> <FONT SIZE=4>in
|
||
C++, interface may be defined using any language having concepts of
|
||
array and pointer to procedure/function. Next interfaces are
|
||
</FONT><FONT SIZE=4><SPAN STYLE="font-style: normal"><B>versioned</B></SPAN></FONT>
|
||
– <FONT SIZE=4>i.e. we support different versions of same
|
||
interface. Binary layout of interfaces is designed to support that
|
||
features very efficient (there is no need in additional virtual calls
|
||
like in OLE2/COM with it's </FONT><STRONG><FONT SIZE=4><SPAN STYLE="font-weight: normal">QueryInterface</SPAN></FONT></STRONG><STRONG><FONT SIZE=4>)</FONT></STRONG><STRONG>
|
||
</STRONG><STRONG><FONT SIZE=4><SPAN STYLE="font-weight: normal">but
|
||
it's not convenient for direct use from most languages. Therefore
|
||
language-specific wrappers should better be designed for different
|
||
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++
|
||
and Pascal have absolutely no difference, though some additional
|
||
language-specific features present in C++ (like ability to turn off
|
||
automatic status check after API calls) are missing in Pascal.</SPAN></FONT></STRONG></P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in; font-weight: normal"><FONT SIZE=4>Typically
|
||
database API is used to access data stored in database. Firebird OO
|
||
API certainly performs this task but in addition it supports writing
|
||
your own </FONT><FONT SIZE=4><B>plugins</B></FONT> – <FONT SIZE=4>modules,
|
||
making it possible to enhance Firebird capabilities according to your
|
||
needs. Therefore this document contains 2 big parts – accessing
|
||
databases and writing plugins. Certainly some interfaces (like status
|
||
vector) are used in both parts of API, they will be discussed in data
|
||
access part and freely referenced later when discussing plugins.
|
||
Therefore even if you plan to write some plugin you should better
|
||
start with the first part of this document. Moreover a lot of plugins
|
||
need to access databases themselves and data access API is typically
|
||
needed for it.</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><A NAME="result_box"></A><FONT SIZE=4><SPAN STYLE="font-weight: normal">Firebird
|
||
installation package contains a number of live samples of use of OO
|
||
API – they are in examples/interfaces (database access) and
|
||
examples/dbcrypt (plugin performing </SPAN></FONT><FONT SIZE=4><SPAN LANG="en-US">fictitious
|
||
database encryption</SPAN></FONT><FONT SIZE=4><SPAN STYLE="font-weight: normal">)
|
||
directories. It's supposed that the reader is familiar with ISC API
|
||
used in Firebird since interbase times.</SPAN></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><SPAN STYLE="font-weight: normal">This
|
||
document does not pretend to be a full Firebird 3 documentation –
|
||
it just describes new object oriented API, and a reader should be
|
||
familiar with main Firebird concepts, knowledge about ISC API is also
|
||
much welcome. For example – when describing how to work with
|
||
services there is no explanation what is service and why is it
|
||
needed, only description of how to obtain <A HREF="#Service">IService</A>
|
||
interface and how to use it. Also pay attention that samples of code
|
||
do not use a lot of powerful features of C++. Not used reference
|
||
counted pointers, not user other RAII holders, not used templates
|
||
(except one present in firebird public headers), etc. Primary goal is
|
||
to make this text usable not only to C++ people because our API is
|
||
oriented to support not only C++ but other, more simple languages
|
||
too.</SPAN></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-top: 0.17in; margin-bottom: 0.2in; page-break-after: avoid">
|
||
<FONT FACE="Albany, sans-serif"><FONT SIZE=5>Accessing databases.</FONT></FONT></P>
|
||
<H1><FONT SIZE=4>Creating database and attaching to existing
|
||
database.</FONT></H1>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>First of all we need to
|
||
get access to <B>IMaster</B> interface. IMaster is primary Firebird
|
||
interface, required to access all the rest of interfaces. Therefore
|
||
there is a special way of accessing it – the only one needed to use
|
||
OO API plain function called fb_get_master_interface(). This function
|
||
has no parameters and always succeeds. There is one and only one
|
||
instance of IMaster per Firebird client library, therefore one need
|
||
not care about releasing memory, used by master interface. A simplest
|
||
way to access it from your program is to have appropriate global or
|
||
static variable:</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>static <A HREF="#Master">IMaster</A>*
|
||
master = fb_get_master_interface();</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>For a lot of methods, used
|
||
in Firebird API, first parameter is <B>IStatus</B> interface. It's a
|
||
logical replacement of ISC_STATUS_ARRAY, but works separately with
|
||
errors and warnings (not mixing them in same array), can contain
|
||
unlimited number of errors inside and (this will be important if you
|
||
plan to implement IStatus yourself) always keeps strings, referenced
|
||
by it, inside interface. Typically you need at least one instance of
|
||
IStatus to call other methods. You obtain it from IMaster:</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I><A HREF="#Status">IStatus</A>*
|
||
st = master->getStatus();</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>If method getStatus()
|
||
fails for some reason (OOM for example) it returns NULL – obviously
|
||
we can't use generic error reporting method which is based on use of
|
||
IStatus here.</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>Now we are going to deal
|
||
with first interface, directly related to database calls. This is
|
||
<A HREF="#Provider">IProvider</A> – interface called this way cause
|
||
it's exactly that interface that must be implemented by any provider
|
||
in Firebird. Firebird client library also has it's own implementation
|
||
of IProvider, which must be used to start any database activity. To
|
||
obtain it we call IMaster's method:</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>IProvider* prov =
|
||
master->getDispatcher();</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>When attaching to existing
|
||
database or moreover creating new one it's often necessary to pass a
|
||
lot of additional parameters (logon/password, page size for new
|
||
database, etc.) to API call. Having separate language-level
|
||
parameters is close to unreal – we 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 one needs to pass not too much of
|
||
them. Therefore to pass additional parameters special in-memory data
|
||
structure, called </FONT><FONT SIZE=4><I>database parameters block</I></FONT>
|
||
<FONT SIZE=4>(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 </FONT><A HREF="#XpbBuilder"><FONT SIZE=4><B>IXpbBuilder</B></FONT></A><FONT SIZE=4>,
|
||
which simplifies creation of various parameters blocks. To obtain an
|
||
instance of IXpbBuilder you must know one more generic-use interface
|
||
of firebird API – </FONT><A HREF="#Util"><FONT SIZE=4><B>IUtil</B></FONT></A><FONT SIZE=4>.
|
||
It's a kind of placeholder for the calls that do not fit well in
|
||
other places. So we do</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>IUtil* utl =
|
||
master->getUtilInterface();</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>IXpbBuilder* dpb =
|
||
utl->getXpbBuilder(&status, IXpbBuilder::DPB, NULL, 0);</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>This creates empty
|
||
parameters' block builder of DPB type. Now adding required parameter
|
||
to it is trivial:</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>dpb->insertInt(&status,
|
||
isc_dpb_page_size, 4 * 1024);</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>will make firebird to
|
||
create new database with pagesize equal to 4Kb and meaning of</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>dpb->insertString(&status,
|
||
isc_dpb_user_name, “sysdba”);</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>dpb->insertString(&status,
|
||
isc_dpb_password, “masterkey”);</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>is (I hope) obvious.</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><U>The following is C++
|
||
specific: </U>We are almost ready to call createDatabase() method of
|
||
IProvider, but before it a few words about concept of <B>Status
|
||
Wrapper</B> should be said. Status wrapper is not an interface, it's
|
||
very thin envelope for IStatus interface. It helps to customize
|
||
behavior of C++ API (change a way how errors, returned in IStatus
|
||
interface, are processed). For the first time we recommend use of
|
||
<B>ThrowStatusWrapper</B>, which raises C++ exception each time an
|
||
error is returned in IStatus.</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>ThrowStatusWrapper
|
||
status(st);</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>Now we may create new
|
||
empty database:</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I><A HREF="#Attachment">IAttachment</A>*
|
||
att = prov->createDatabase(&status, "fbtests.fdb",
|
||
dpb->getBufferLength(&status), dpb->getBuffer(&status));</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>printf("Database
|
||
fbtests.fdb created\n");</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>Pay attention that we do
|
||
not check status after the call to createDatabase(), because in case
|
||
of error C++ or Pascal exception will be raised (therefore it's very
|
||
good idea to have try/catch/except syntax in your program). We also
|
||
use two new functions from IXpbBuilder – getBufferLength() and
|
||
getBuffer(), which extract data from interface in native parameters
|
||
block format. As you can see there is no need to check explicitly for
|
||
status of functions, returning intermediate results.</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>Detaching from just
|
||
created database is trivial:</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>att->detach(&status);</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>Now it remains to enclose
|
||
all operators into <I>try</I> block and write a handler in catch
|
||
block. When using ThrowStatusWrapper you should always catch defined
|
||
in C++ API exception class FbException, in Pascal you must also work
|
||
with class FbException. Exception handler block in simplest case may
|
||
look this way:</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>catch (const
|
||
FbException& error)</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>{</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>char buf[256];</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>utl->formatStatus(buf,
|
||
sizeof(buf), error.getStatus());</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>fprintf(stderr, "%s\n",
|
||
buf);</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>}</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>Pay attention that here we
|
||
use one more function from <A HREF="#Util">IUtil</A> –
|
||
formatStatus(). It returns in buffer text, describing an error
|
||
(warning), stored in IStatus parameter.</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>To attach to existing
|
||
database just use attachDatabase() method of IProvider instead
|
||
createDatabase(). All parameters are the same for both methods.</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>att =
|
||
prov->attachDatabase(&status, "fbtests.fdb", 0,
|
||
NULL);</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>This sample is using no
|
||
additional DPB parameters. Take into account that without
|
||
logon/password any remote connection will fail if no trusted
|
||
authorization plugin is configured. Certainly login info may be also
|
||
provided in environment (in ISC_USER and ISC_PASSWORD variables) like
|
||
it was before.</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>Our examples contain
|
||
complete samples, dedicated except others to creating databases –
|
||
01.create.cpp and 01.create.pas. When samples are present it will be
|
||
very useful to build and try to run appropriate samples when reading
|
||
this document.</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<H1><FONT SIZE=4>Working with transactions.</FONT></H1>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>Only 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) in database
|
||
and insert data in that tables. Any operation within database is
|
||
performed by firebird under transaction control. Therefore first of
|
||
all we must learn to start transaction. Here we do not discuss
|
||
distributed transactions (supported by <A HREF="#Dtc">IDtc</A>
|
||
interface) to avoid unneeded to most users overcomplication. Starting
|
||
of non-distributed transaction is very simple and done via attachment
|
||
interface:</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I><A HREF="#Transaction">ITransaction</A>*
|
||
tra = att->startTransaction(&status, 0, NULL);</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>In this sample default
|
||
transaction parameters are used – no TPB is passed to
|
||
startTransaction() method. If you need non-default parameters you may
|
||
create appropriate <A HREF="#XpbBuilder">IXpbBuilder</A>, add
|
||
required items to it:</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I><A HREF="#XpbBuilder">IXpbBuilder</A>*
|
||
tpb = utl->getXpbBuilder(&status, IXpbBuilder::TPB, NULL, 0);</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>tpb->insertTag(&status,
|
||
isc_tpb_read_committed);</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>and pass resulting TPB to
|
||
startTransaction():</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>ITransaction* tra =
|
||
att->startTransaction(&status, tpb->getBufferLength(&status),
|
||
tpb->getBuffer(&status));</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>Transaction interface is
|
||
used as a parameter in a lot of other API calls but itself it does
|
||
not perform any actions except commit/rollback transaction, may be
|
||
retaining:</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>tra->commit(&status);</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>You may take a look at how
|
||
to start and commit transaction in examples 01.create.cpp and
|
||
01.create.pas.</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<H1><FONT SIZE=4>Executing SQL operator without input parameters and
|
||
returned rows.</FONT></H1>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>With started transaction
|
||
we are ready to execute our first SQL operators. Used for it
|
||
execute() method in <A HREF="#Attachment">IAttachment</A> is rather
|
||
universal and may be also used to execute SQL operators with input
|
||
and output parameters (which is typical for EXECUTE PROCEDURE
|
||
statement), but right now we will use the simple most form of it.
|
||
Both DDL and DML operators can be executed:</FONT></P>
|
||
<P STYLE="margin-bottom: 0in; font-weight: normal"><FONT SIZE=4><I>att->execute(&status,
|
||
tra, 0, "create table dates_table (d1 date)",
|
||
SQL_DIALECT_V6, NULL, NULL, NULL, NULL);</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in; font-weight: normal"><FONT SIZE=4><I>tra->commitRetaining(&status);</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in; font-weight: normal"><FONT SIZE=4><I>att->execute(&status,
|
||
tra, 0, "insert into dates_table values (CURRENT_DATE)",
|
||
SQL_DIALECT_V6, NULL, NULL, NULL, NULL);</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>As you can see transaction
|
||
interface is a required parameter for execute() method (must be NULL
|
||
only if you execute START TRANSACTION statement). Next follows length
|
||
of SQL operator (may be zero causing use of C rules to determine
|
||
string length), text of operator and SQL dialect that should be used
|
||
for it. The following for NULLs stand for metadata descriptions and
|
||
buffers of input parameters and output data. Complete description of
|
||
this method is provided in <A HREF="#Attachment">IAttachment</A>
|
||
interface.</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>You may take a look at how
|
||
to start and commit transaction in examples 01.create.cpp and
|
||
01.create.pas.</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<H1><FONT SIZE=4>Executing SQL operator with input parameters.</FONT></H1>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>There are 2 ways to
|
||
execute statement with input parameters. Choice of correct method
|
||
depends upon do you need to execute it more than once and do you know
|
||
in advance format of parameters. When that format is known and
|
||
statement is needed to be run only once single call to
|
||
IAttachment::execute() may be used. In other cases SQL statement
|
||
should be prepared first and after it executed, may be many times
|
||
with different parameters.</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>To prepare SQL statement
|
||
for execution use prepare() method of <A HREF="#Attachment">IAttachment</A>
|
||
interface:</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I><A HREF="#Statement">IStatement</A>*
|
||
stmt = att->prepare(&status, tra, 0, “UPDATE department SET
|
||
budget = ? * budget + budget WHERE dept_no = ?”,</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>SQL_DIALECT_V6,
|
||
IStatement::PREPARE_PREFETCH_METADATA);</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>If you are not going to
|
||
use parameters description from firebird (i.e. you can provide that
|
||
information yourself) please use IStatement::PREPARE_PREFETCH_NONE
|
||
instead PREPARE_PREFETCH_METADATA – this will save client/server
|
||
traffic and server resources a bit.</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>In ISC API XSQLDA is used
|
||
to describe format of statement parameters. New API does not use
|
||
XSQLDA – instead interface IMessageMetadata is used. A set of input
|
||
parameters (and also a row fetched from cursor) is described in
|
||
firebird API in same way and later called message. <A HREF="#MessageMetadata">IMessageMetadata</A>
|
||
is passed as a parameter to the methods performing message exchange
|
||
between your program and database engine. There are many ways to have
|
||
an instance of IMessageMetadata – one can:</FONT></P>
|
||
<UL>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>get it from
|
||
<A HREF="#Statement">IStatement</A>,</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>build using
|
||
<A HREF="#MetadataBuilder">IMetadataBuilder</A> interface,</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>have your own
|
||
implementation of this interface.</FONT></P>
|
||
</UL>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>Getting metadata from
|
||
prepared statement is very simple – method getInputMetadata()
|
||
return interface describing input message (i.e. statement
|
||
parameters), interface returned by getOutputMetadata() describes
|
||
output message (i.e. row in selected data or values returned by
|
||
procedure). In our case we can:</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I><A HREF="#MessageMetadata">IMessageMetadata</A>*
|
||
meta = stmt->getInputMetadata(&status);</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>Or we can build message
|
||
metadata ourself. First of all we need builder interface for it:</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I><A HREF="#MetadataBuilder">IMetadataBuilder</A>*
|
||
builder = master->getMetadataBuilder(&status, 2);</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>Second parameter is
|
||
expected number of fields in the message, it can be changed later,
|
||
i.e. that's just an optimization.</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>Now it's necessary to set
|
||
individual fields characteristics in the builder. An absolute minimum
|
||
is field types and length for string fields:</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>builder->setType(&status,
|
||
0, SQL_DOUBLE + 1);</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>builder->setType(&status,
|
||
1, SQL_TEXT + 1);</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>builder->setLength(&status,
|
||
1, 3);</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in; font-style: normal"><FONT SIZE=4>New
|
||
API is using old constants for SQL types, smallest bit as earlier
|
||
stands for nullability. In some case it may also make sense to set
|
||
sub-type (for blobs), character set (for text fields) or scale (for
|
||
numeric fields). And finally it's time to get an instance of
|
||
IMessageMetadata:</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I><A HREF="#MessageMetadata">IMessageMetadata</A>*
|
||
meta = builder->getMetadata(&status);</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in; font-style: normal"><FONT SIZE=4>Here
|
||
we do not discuss in details own implementation of IMessageMetadata.
|
||
If one cares there is a sample 05.user_metadata.cpp.</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>So finally we have
|
||
obtained (one or another way) an instance of metadata description of
|
||
input parameters. But to work with a message we also need buffer for
|
||
it. Buffer size is one of main message metadata characteristics and
|
||
it's returned by method in IMessageMetadata:</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>char* buffer = new
|
||
char[meta->getMessageLength(&status)];</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>To deal with individual
|
||
values inside buffer offset to them should be taken into an account.
|
||
IMessageMetadata is aware of offsets for all values in a message,
|
||
using it we can create pointers to them:</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>double* percent_inc =
|
||
(double*) &buffer[meta->getOffset(&status, 0)];</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>char* dept_no =
|
||
&buffer[meta->getOffset(&status, 1)];</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>Also let's do not forget
|
||
to set to NOT NULL null flags:</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>short* flag =
|
||
(short*)&buffer[meta->getNullOffset(&status, 0)];</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>*flag = 0;</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>flag = (short*)
|
||
&buffer[meta->getNullOffset(&status, 1)];</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>*flag = 0;</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>After finishing with
|
||
offsets we are ready to execute statement with some parameters
|
||
values:</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>getInputValues(dept_no,
|
||
percent_inc);</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>and may execute prepared
|
||
statement:</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>stmt->execute(&status,
|
||
tra, meta, buffer, NULL, NULL);</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>Two more NULLs in the end
|
||
of parameters stand for output message and is used typically for
|
||
EXECUTE PROCEDURE statement.</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>If you do not need to get
|
||
metadata from statement and plan to execute it only once you may
|
||
choose a simpler way – use method execute() in <A HREF="#Attachment">IAttachment</A>
|
||
interface:</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>att->execute(&status,
|
||
tra, 0, "UPDATE department SET budget = ? * budget + budget
|
||
WHERE dept_no = ?", SQL_DIALECT_V6, meta, buffer, NULL, NULL);</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>In that case you do not
|
||
need to use <A HREF="#Statement">IStatement</A> at all.</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>An example how to execute
|
||
UPDATE with parameters is present in 02.update.cpp, you will also see
|
||
how raised in trigger/procedure exception may be caught by C++
|
||
program.</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<H1><FONT SIZE=4>Opening cursor and fetching data from it.</FONT></H1>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>The only way to get rows
|
||
of data, returned by SELECT operator, in OO API is to use <A HREF="#ResultSet">IResultSet</A>
|
||
interface. This interface is returned by openCursor() method in both
|
||
IAttachment and IStatement. openCursor() is in most aspects alike
|
||
execute() and a choice how to open cursor (using prepared statement
|
||
or directly from attachment interface) is the same. In the samples
|
||
03.select.cpp and 04.print_table.cpp both methods are used. Let's pay
|
||
attention at one specific openCursor() feature compared with
|
||
execute() - one does not pass buffer for output message into
|
||
openCursor(), it will be passed later when data is fetched from
|
||
cursor. This makes it possible to open cursor with unknown format of
|
||
output message (NULL is passed instead output metadata). Firebird is
|
||
using in this case default message format which may be requested from
|
||
IResultSet interface:</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>const char* sql =
|
||
"select * from ..."; // some select statement</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I><A HREF="#ResultSet">IResultSet</A>*
|
||
curs = att->openCursor(&status, tra, 0, sql, SQL_DIALECT_V6,
|
||
NULL, NULL, NULL, NULL, 0);</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I><A HREF="#MessageMetadata">IMessageMetadata</A>*
|
||
meta = curs->getMetadata(&status);</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>Later this metadata may be
|
||
used to allocate buffer for data and parse fetched rows.</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>As an alternative one can
|
||
first prepare statement, get metadata from prepared statement and
|
||
after it open cursor. This is preferred way if cursor is likely to be
|
||
opened >1 times.</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><A HREF="#Statement">IStatement</A>*
|
||
stmt = att->prepare(&status, tra, 0, sql, SQL_DIALECT_V6,
|
||
Istatement::PREPARE_PREFETCH_METADATA);</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><A HREF="#MessageMetadata">IMessageMetadata</A>*
|
||
meta = stmt->getOutputMetadata(&status);</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><A HREF="#ResultSet">IResultSet</A>*
|
||
curs = stmt->openCursor(&status, tra, NULL, NULL, NULL, 0);</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>We have obtained (one or
|
||
another way) an instance of metadata description of output fields (a
|
||
row in a set). To work with a message we also need buffer for it:</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>unsigned char* buffer =
|
||
new unsigned char[meta->getMessageLength(&status)];</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>IResultSet has a lot of
|
||
various fetch methods but when cursor is not opened with SCROLL
|
||
option only fetchNext() works, i.e. one can navigate only forward
|
||
record by record. In addition to errors and warnings in status
|
||
fetchNext() returns completion code, which may have values RESULT_OK
|
||
(when buffer is filled with values for next row) or RESULT_NO_DATA
|
||
(when no more rows left in cursor). RESULT_NO_DATA is not error
|
||
state, it's normal state after completion of the method, but we know
|
||
that data in cursor is over. If status wrapper, not throwing
|
||
exception in case of error return is used, one more value –
|
||
RESULT_ERROR – may be returned, that means no data in buffer and
|
||
error vector in status. Method fetchNext() is usually called in a
|
||
cycle:</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>while
|
||
(curs->fetchNext(&status, buffer) == IStatus::RESULT_OK)</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>{</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>// row processing</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>}</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>What is done during row
|
||
processing depends upon your needs. To access particular field
|
||
field's offset should be used:</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>unsigned char*
|
||
field_N_ptr = buffer + meta->getOffset(&status, n);</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in; font-style: normal"><FONT SIZE=4>where
|
||
n is the number of a field in a message. That pointer should be
|
||
casted to appropriate type, depending upon field type. For example,
|
||
for a VARCHAR field cast to struct vary should be used:</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>vary* v_ptr = (vary*)
|
||
(buffer + meta->getOffset(&status, n));</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>Now we may print the value
|
||
of a field:</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>printf(“field %s
|
||
value is %*.*s\n”, meta->getField(&status, n),
|
||
v_ptr->vary_length, v_ptr->vary_length, v_ptr->vary_string);</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>If you need maximum
|
||
performance it will be good idea to cache needed metadata values like
|
||
it's done in our samples 03.select.cpp and 04.print_table.cpp.</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<H1><FONT SIZE=4>Using FB_MESSAGE macro for static messages.</FONT></H1>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>Working with data using
|
||
offsets is rather efficient but requires a lot of code to be written.
|
||
In C++ this problem can be solved using templates, but even compared
|
||
with them the most convenient way to work with the message is to
|
||
represent it in native (for given language) way – structure in
|
||
C/C++, record in Pascal, etc. Certainly this works only if format of
|
||
a message is known in advance. To help building such structures in
|
||
C++ firebird contains special macro FB_MESSAGE.</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>FB_MESSAGE has 3 arguments
|
||
– message (struct) name, type of status wrapper and list of fields.
|
||
Usage of first and second is obvious, list of fields contains pairs
|
||
(field_type, field_name), where field_type is one of the following:</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>FB_BIGINT</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>FB_BLOB</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>FB_BOOLEAN</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>FB_CHAR(len)</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>FB_DATE</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>FB_DOUBLE</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>FB_FLOAT</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>FB_INTEGER</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>FB_INTL_CHAR(len, charSet)</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>FB_INTL_VARCHAR(len,
|
||
charSet)</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>FB_SCALED_BIGINT(x)</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>FB_SCALED_INTEGER(x)</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>FB_SCALED_SMALLINT(x)</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>FB_SMALLINT</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>FB_TIME</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>FB_TIMESTAMP</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>FB_VARCHAR(len)</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>In generated by
|
||
preprocessor structure integer and float types are matched with
|
||
appropriate C types, date and time – with classes <A HREF="#FbDate">FbDate</A>
|
||
and <A HREF="#FbTime">FbTime</A> (all mentioned here classes are in
|
||
namespace Firebird), timestamp – with class FbTimestamp, containing
|
||
two public data members date and time of appropriate class, char -
|
||
with struct <A HREF="#FbChar">FbChar</A> and varchar – with struct
|
||
<A HREF="#FbVarChar">FbVarChar</A>. For each field preprocessor
|
||
creates two data members in the message – <I>name</I> for
|
||
field/parameter value and <I>nameNull</I> for NULL indicator. Message
|
||
constructor has 2 parameters – pointer to status wrapper and master
|
||
interface:</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>FB_MESSAGE(Output,
|
||
ThrowStatusWrapper,</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>(FB_SMALLINT,
|
||
relationId)</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>(FB_CHAR(31),
|
||
relationName)</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>(FB_VARCHAR(100),
|
||
description)</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>)
|
||
output(&status, master);</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>For static messages use of
|
||
FB_MESSAGE is sooner of all the best choice – they can be at the
|
||
same time easily passed to execute, openCursor and fetch methods:</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>rs =
|
||
att->openCursor(&status, tra, 0, sqlText,</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>SQL_DIALECT_V6,
|
||
NULL, NULL, output.getMetadata(), NULL, 0);</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>and used to work with
|
||
values of individual fields:</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>while
|
||
(rs->fetchNext(&status, output.getData()) ==
|
||
IStatus::RESULT_OK)</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>{</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>printf("%4d
|
||
%31.31s %*.*s\n", output->relationId,
|
||
output->relationName.str,</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>output->descriptionNull
|
||
? 0 : output->description.length,</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>output->descriptionNull
|
||
? 0 : output->description.length, output->description.str);</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>}</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>An example of using macro
|
||
FB_MESSAGE to work with messages is in the sample 06.fb_message.cpp.</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<H1><FONT SIZE=4>Working with blobs.</FONT></H1>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>For blobs in message
|
||
buffer firebird stores blob identifier – an 8-byte entity which
|
||
should be aligned on 4-byte boundary. Identifier has ISC_QUAD type.
|
||
Interface <A HREF="#Attachment">IAttachment</A> has 2 methods to work
|
||
with blobs – openBlob() and createBlob(), both returning interface
|
||
<A HREF="#Blob">IBlob</A> and having same set of parameters, but
|
||
performing somewhat contrary actions: openBlob() takes blob
|
||
identifier from the message and prepares blob for reading but
|
||
createBlob() creates new blob, puts it's identifier into message and
|
||
prepares blob for writing. </FONT>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>To work with blobs one
|
||
must first of all include blob identifier into the message. If you
|
||
get metadata from firebird engine field of appropriate type will be
|
||
already present. You just use it's offset (assuming variable
|
||
blobFieldNumber contains number of blob field) (and appropriate null
|
||
offset to check for nulls or set null flag) to obtain pointer into
|
||
the message buffer:</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>ISC_QUAD* blobPtr =
|
||
(ISC_QUAD*) &buffer[metadata->getOffset(&status,
|
||
blobFieldNumber)];</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>ISC_SHORT* blobNullPtr
|
||
= (ISC_SHORT*) &buffer[metadata->getNullOffset(&status,
|
||
blobFieldNumber)];</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>If you use static messages
|
||
and FB_MESSAGE macro blob field is declared as having FB_BLOB type:</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>FB_MESSAGE(Msg,
|
||
ThrowStatusWrapper,</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>(FB_BLOB,
|
||
b)</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>) message(&status,
|
||
master);</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>ISC_QUAD* blobPtr =
|
||
&message->b;</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>ISC_SHORT* blobNullPtr
|
||
= &message->bNull;</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>To create new blob invoke
|
||
createBlob() method:</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I><A HREF="#Blob">IBlob</A>*
|
||
blob = att->createBlob(status, tra, blobPtr, 0, NULL);</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>Last two parameters are
|
||
required only if you want to use blob filters or use stream blob,
|
||
that's out of scope here.</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>Blob interface is ready to
|
||
accept data into blob. Use putSegment() method to send data to
|
||
engine:</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>void* segmentData;</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>unsigned segmentLength;</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>while
|
||
(userFunctionProvidingBlobData(&segmentData, &segmentLength))</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>blob->putSegment(&status,
|
||
segmentLength, segmentData);</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>After sending some data to
|
||
blob do not forget to close blob interface:</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>blob->close(&status);</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>Make sure that null flag
|
||
is not set (not required if you nullified all message buffer before
|
||
creating blob):</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>*blobNullPtr = 0;</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>and message, containing
|
||
blob, may be used in insert or update statement. After execution of
|
||
that statement new blob will be stored in database.</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>To read a blob begin with
|
||
getting containing it's identifier message from firebird engine. This
|
||
may be done using fetch() or execute() methods. After it use
|
||
openBlob() attachment's method:</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I><A HREF="#Blob">IBlob</A>*
|
||
blob = att->openBlob(status, tra, blobPtr, 0, NULL);</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>Blob interface is ready
|
||
to provide blob data. Use getSegment() method to receive data from
|
||
engine:</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>char buffer[BUFSIZE];</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>unsigned actualLength;</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>for(;;)</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>{</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>switch
|
||
(blob->getSegment(&status, sizeof(buffer), buffer,
|
||
&actualLength))</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>{</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>case
|
||
IStatus::RESULT_OK:</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in">
|
||
<FONT SIZE=4><I>userFunctionAcceptingBlobData(buffer, actualLength,
|
||
true);</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>continue;</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>case
|
||
IStatus::RESULT_SEGMENT:</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in">
|
||
<FONT SIZE=4><I>userFunctionAcceptingBlobData(buffer, actualLength,
|
||
false);</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>continue;</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>default:</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>break;</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>}</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>}</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>Last parameter in
|
||
userFunctionAcceptingBlobData() is a flag that end of segment is
|
||
reached – when getSegment() returns RESULT_SEGMENT completion code
|
||
that function is notified (by passing false as last parameter) that
|
||
segment was not read completely and continuation is expected at next
|
||
call.</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>After finishing with blob
|
||
do not forget top close it:</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>blob->close(&status);</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<H1><FONT SIZE=4>Working with events.</FONT></H1>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>Events interface was not
|
||
completed in FB3, we expect to have something more interesting in
|
||
next version. The minimum existing support is as follows: <A HREF="#Attachment">IAttachment</A>
|
||
contains call queEvents() which performs almost same functions as
|
||
isc_que_events() call. Instead the pair of parameters
|
||
<I>FPTR_EVENT_CALLBACK ast</I> and <I>void* arg</I>, required to
|
||
invoke user code when event happens in firebird engine, callback
|
||
interface IEventCallback is used. This is traditional approach which
|
||
helps to avoid non-safe casts from void* in user function. Another
|
||
important difference is that instead event identifier (a kind of
|
||
handler) this function returns reference counted interface <A HREF="#Events">IEvents</A>
|
||
having method 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
|
||
is received right before canceling interface call to cancel() would
|
||
cause segfault when interface is already destroyed. Therefore
|
||
interface <A HREF="#Events">IEvents</A> must be explicitly released
|
||
after receiving an event. This may be done for example right before
|
||
queuing for an event next time:</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>events->release();</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>events = NULL;</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>events =
|
||
attachment->queEvents(&status, this, eveLen, eveBuffer);</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>Setting interface pointer
|
||
to NULL is useful in case of exception during queEvents. In other
|
||
aspects events handling did not change compared with ISC API. Please
|
||
use for additional details our sample 08.events.cpp. </FONT>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<H1><FONT SIZE=4>Using services.</FONT></H1>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>To begin to use services
|
||
one should first of all connect to service manager. This is done
|
||
using attachServiceManager() method of <A HREF="#Provider">IProvider</A>.
|
||
This method returns <A HREF="#Service">IService</A> interface which
|
||
is used later to talk to service. To prepare SPB to attach to service
|
||
manager one can use IXpbBuilder:</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>IXpbBuilder* spb1 =
|
||
utl->getXpbBuilder(&status, IXpbBuilder::SPB_ATTACH, NULL, 0);</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>spb1->insertString(&status,
|
||
isc_spb_user_name, “sysdba”);</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>spb1->insertString(&status,
|
||
isc_spb_password, “masterkey”);</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>and proceed with attach:</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><A HREF="#Service">IService</A>*
|
||
svc = prov->attachServiceManager(&status, “service_mgr”,
|
||
spb1->getBufferLength(&status), spb1->getBuffer(&status));</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>Using IService one can
|
||
perform both available for services actions – start services and
|
||
query various information about started utilities and server in
|
||
general. When querying information one limitation takes place –
|
||
formats of parameter blocks, used by query() method, in Firebird 3
|
||
are not supported by IXpbBuilder. Support will be probably added in
|
||
later versions, in Firebird 3 you will have to build and analyze that
|
||
blocks manually. Format of that blocks matches old format (used in
|
||
ISC API) one to one. </FONT>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>To start service one
|
||
should first of all create appropriate SPB:</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>IXpbBuilder* spb2 =
|
||
utl->getXpbBuilder(&status, IXpbBuilder::SPB_START, NULL, 0);</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>and add required items to
|
||
it. For example, to print encryption statistics for database employee
|
||
the following should be placed into SPB:</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>spb2->insertTag(&status,
|
||
isc_action_svc_db_stats);</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>spb2->insertString(&status,
|
||
isc_spb_dbname, "employee");</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>spb2->insertInt(&status,
|
||
isc_spb_options, isc_spb_sts_encryption);</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>After it service can be
|
||
started using start() method of <A HREF="#Service">IService</A>
|
||
interface:</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>svc->start(&status,
|
||
spb2->getBufferLength(&status), spb2->getBuffer(&status));</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>Many started services
|
||
(including mentioned here gstat) return text information during
|
||
execution. To display it one should query started service anout that
|
||
information line by line. This is done by calling query() method of
|
||
<A HREF="#Service">IService</A> interface with appropriate send and
|
||
receive blocks of parameters. Send block may contain various helper
|
||
information (like timeout when querying service) or information to be
|
||
passed to stdin of service utility or may be empty in the simplest
|
||
case. Receive block must contain list of tags you want to receive
|
||
from service. For most of utilities this is single isc_info_svc_line:</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>const unsigned char
|
||
receiveItems1[] = {isc_info_svc_line};</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>To query information one
|
||
also needs a buffer for that information:</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>unsigned char
|
||
results[1024];</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>After that preliminary
|
||
steps we are ready to query service in a loop (each line returned in
|
||
a single call to query()):</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>do</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>{</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>svc->query(&status,
|
||
0, NULL, sizeof(receiveItems1), receiveItems1, sizeof(results),
|
||
results);</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>} while
|
||
(printInfo(results, sizeof(results)));</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>In this example we suppose
|
||
that printInfo() function returns TRUE as long as service returns
|
||
results block containing next output line (i.e. till end of data
|
||
stream from service). Format of results block varies from service to
|
||
service, and some services like gsec produce historical formats that
|
||
are not trivial for parse – but this is out of our scope here. A
|
||
minimum working sample of printInfo() is present in example
|
||
09.service.cpp.</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>Same query method is used
|
||
to retrieve information about server but in this case query function
|
||
is not invoked in a loop, i.e. buffer must be big enough to fit all
|
||
information at once. This is not too hard – typically such calls do
|
||
not return much data. As in previous case begin with receive block
|
||
placing required items in it – in our example it's
|
||
isc_info_svc_server_version:</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>const unsigned char
|
||
receiveItems2[] = {isc_info_svc_server_version};</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>Existing from previous
|
||
call results buffer may be reused. No loop is needed here:</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>svc->query(&status,
|
||
0, NULL, sizeof(receiveItems2), receiveItems2, sizeof(results),
|
||
results);</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>printInfo(results,
|
||
sizeof(results));</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>After finishing with
|
||
services tasks do not forget to close an interface:</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>svc->detach(&status);</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-top: 0.17in; margin-bottom: 0.2in; page-break-after: avoid">
|
||
<FONT FACE="Albany, sans-serif"><FONT SIZE=5>Writing plugins.</FONT></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>To write a plugin means to
|
||
implement some interfaces and place your implementation into dynamic
|
||
library (.dll in windows or .so in linux) later referenced as <I>plugin
|
||
module</I> or just <I>module</I>. In most cases single plugin is
|
||
place in dynamic library but in common case. One of that interfaces –
|
||
<A HREF="#PluginModule">IPluginModule</A> – is module-wide (as more
|
||
or less clear from it's name), others are per plugin. Also each
|
||
plugin module should contain special exported entrypoint
|
||
firebird_plugin() which name is defined in include file
|
||
firebird/Interfaces.h as FB_PLUGIN_ENTRY_POINT.</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>In previous part of this
|
||
text we were mostly describing how to use existing interfaces, here
|
||
main attention will be paid to implementing interfaces yourself.
|
||
Certainly to do it one can and should use already existing interfaces
|
||
both generic needed for accessing firebird databases (already
|
||
described) and some more interfaces specifically designed for
|
||
plugins.</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>Following text is actively
|
||
using example of database encryption plugin
|
||
examples/dbcrypt/DbCrypt.cpp. It will be good idea to compile this
|
||
sample yourself and learn it when reading later.</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<H1><FONT SIZE=4>Implementation of plugin module.</FONT></H1>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>Plugins actively interact
|
||
with special firebird component called <I>plugin manager</I>. In
|
||
particular plugin manager should be aware what plugin modules were
|
||
loaded and must be notified if operating system tries to unload one
|
||
of that modules without explicit plugin manager command (this may
|
||
happen first of all when using embedded access – when exit() is
|
||
called in a program or main firebird library <I><SPAN STYLE="font-weight: normal">fbclient</SPAN></I>
|
||
is unloaded). Primary task of IPluginModule interface is that
|
||
notification. First of all one must decide - how to detect that
|
||
module is going to be unloaded? When dynamic library is unloaded for
|
||
some reason a lot of OS-dependent actions is performed and some of
|
||
that actions may be used to detect this fact in the program. When
|
||
writing plugins distributed with firebird we always use invocation of
|
||
destructor of global variable. The big “plus” for this method is
|
||
that it is OS independent (though something like atexit() function
|
||
maybe also used successfully). But use of destructor makes it
|
||
possible to easily concentrate almost everything related with unload
|
||
detection in single class implementing at the same time <A HREF="#PluginModule">IPluginModule</A>
|
||
interface.</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>Minimum implementation
|
||
looks as follows:</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>class PluginModule :
|
||
public IPluginModuleImpl<PluginModule, CheckStatusWrapper></I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>{</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>private:</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>IPluginManager*
|
||
pluginManager;</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>public:</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>PluginModule()</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>:
|
||
pluginManager(NULL)</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>{ }</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>~PluginModule()</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>{</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>if
|
||
(pluginManager)</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>{</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in">
|
||
<FONT SIZE=4><I>pluginManager->unregisterModule(this);</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>doClean();</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>}</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>}</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>void
|
||
registerMe(IPluginManager* m)</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>{</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>pluginManager =
|
||
m;</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in">
|
||
<FONT SIZE=4><I>pluginManager->registerModule(this);</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>}</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>void doClean()</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>{</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>pluginManager
|
||
= NULL;</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>}</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>};</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>The only data member is
|
||
plugin manager interface <A HREF="#PluginManager">IPluginManager</A>.
|
||
It's passed to registerModule() function and saved in private
|
||
variable, at the same time module is registered in plugin manager by
|
||
the call to registerModule() method with own address as a single
|
||
parameter. Variable <I>pluginManager </I>not only stores pointer to
|
||
interface, at the same time it serves as a flag that module is
|
||
registered. When destructor of registered module is invoked it
|
||
notifies plugin manager (yes, this is what for this class exists!)
|
||
about unexpected unload by the call to unregisterModule() passing
|
||
pointer to itself. When plugin manager is going to unload module in
|
||
regular way in first of all calls doClean() method changing module
|
||
state to unregistered and this avoiding call to unregisterModule()
|
||
when OS performs actual unload.</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>Implementing plugin's
|
||
interface IPluginModule we met with first interface required to
|
||
implement plugins – <A HREF="#PluginManager">IPluginManager</A>. It
|
||
will be actively used later, the rest of internals of this class will
|
||
hardly be required to you after copying it to your program. Just
|
||
don't forget to declare global variable of this type and call
|
||
registerMe() function from FB_PLUGIN_ENTRY_POINT.</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<H1><FONT SIZE=4>Core interface of any plugin.</FONT></H1>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>Let's start implementing
|
||
plugin itself. The type of main interface depends upon plugin type
|
||
(which is obvious), but all of them are based on common reference
|
||
counted interface IPluginBase which performs common for all plugins
|
||
(and very simple) tasks. Each plugin has some (also reference
|
||
counted) object which <I>owns</I> this plugin. In order to perform
|
||
smart plugin lifetime management any plugin must be able to store
|
||
that owner information and report it to plugin manager on request.
|
||
That means that each plugin must implement two trivial methods
|
||
setOwner() and getOwner() contained in IPluginBase interface.
|
||
Type-dependent methods are certainly more interesting - they are
|
||
discussed in interfaces description part.</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>Let's take a look at
|
||
typical part of any plugin implementation (here I specially use
|
||
non-existent type SomePlugin):</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>class MyPlugin : public
|
||
ISomePluginImpl<MyPlugin, CheckStatusWrapper></I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>{</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>public:</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>explicit
|
||
MyPlugin(<A HREF="#PluginConfig">IPluginConfig</A>* cnf) throw()</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>:
|
||
config(cnf), refCounter(0), owner(NULL)</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>{</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>config->addRef();</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>}</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in; font-style: normal"><FONT SIZE=4>Constructor
|
||
gets as parameter plugin configuration interface. If you are going to
|
||
have you plugin configured in some way it's good idea to save this
|
||
interface in your plugin and use it later. This will let you use
|
||
common for all firebird configuration style letting users have
|
||
familiar configuration and minimize code written. Certainly when
|
||
saving any reference counted interface it's better not forget to add
|
||
reference to it. Also set reference counter to 0 and plugin owner to
|
||
NULL.</FONT></P>
|
||
<P STYLE="margin-bottom: 0in; font-style: normal"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>~MyPlugin()</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>{</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>config->release();</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>}</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in; font-style: normal"><FONT SIZE=4>Destructor
|
||
releases config interface. Pay attention – we do not change
|
||
reference counter of our owner cause it owns us, not we own it.</FONT></P>
|
||
<P STYLE="margin-bottom: 0in; font-style: normal"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>// IRefCounted
|
||
implementation</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>int release()</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>{</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>if
|
||
(--refCounter == 0)</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>{</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>delete
|
||
this;</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>return
|
||
0;</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>}</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>return
|
||
1;</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>}</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>void addRef()</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>{</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>++refCounter;</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>}</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in; font-style: normal"><FONT SIZE=4>Absolutely
|
||
typical implementation of reference counted object.</FONT></P>
|
||
<P STYLE="margin-bottom: 0in; font-style: normal"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>// IPluginBase
|
||
implementation</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>void
|
||
setOwner(IReferenceCounted* o)</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>{</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>owner =
|
||
o;</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>}</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>IReferenceCounted*
|
||
getOwner()</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>{</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>return
|
||
owner;</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>}</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in; font-style: normal"><FONT SIZE=4>As it
|
||
was promised implementation of IPluginBase is trivial.</FONT></P>
|
||
<P STYLE="margin-bottom: 0in; font-style: normal"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>// ISomePlugin
|
||
implementation</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>// … here go
|
||
various methods required for particular plugin type</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>private:</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>IPluginConfig*
|
||
config;</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>FbSampleAtomic
|
||
refCounter;</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>IReferenceCounted*
|
||
owner;</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>};</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>With this sample formal
|
||
part of main plugin interface implementation is over. After adding
|
||
type-specific methods (and writing probably a lo-o-o-ot of code to
|
||
make them useful) interface is ready.</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<H1><FONT SIZE=4>Plugin's factory.</FONT></H1>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>One more interface
|
||
required for plugin to work is <A HREF="#PluginFactory">IPluginFactory</A>.
|
||
Factory creates instances of plugin and returns them to plugin
|
||
manager. Factory typically looks this way:</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>class Factory : public
|
||
IPluginFactoryImpl<Factory, CheckStatusWrapper></I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>{</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>public:</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>IPluginBase*
|
||
createPlugin(CheckStatusWrapper* status, IPluginConfig*
|
||
factoryParameter)</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>{</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>MyPlugin* p =
|
||
new MyPlugin(factoryParameter);</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>p->addRef();</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>return p;</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4><I>}</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>};</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in; font-style: normal"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in; font-style: normal"><FONT SIZE=4>Here
|
||
attention should be payed to the fact that even in a case when code
|
||
in a function may throw exceptions (operator new may throw in a case
|
||
when memory exhausted) one need not always manually define try/catch
|
||
block – implementation of firebird interfaces does this job for
|
||
you, in implementation of IPluginFactory it's placed into template
|
||
IPluginFactoryImpl. Take into an account that default status wrappers
|
||
perform meaning-full processing only for FbException. But if you
|
||
(that definitely makes sense if you work on some big project) define
|
||
your own wrapper you can handle any type of C++ exception and pass
|
||
useful information about it from your plugin.</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<H1><FONT SIZE=4>Plugin module initialization entrypoint.</FONT></H1>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>When plugin manager loads
|
||
plugin module it invokes module initializing routine – the only
|
||
exported from plugin function FB_PLUGIN_ENTRY_POINT. To wrote it's
|
||
code one will need two global variables – plugin module and plugin
|
||
factory. In our case that is:</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>PluginModule module;</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>Factory factory;</I></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>If you module contains
|
||
more than one plugin you will need a factory per each plugin.</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>For FB_PLUGIN_ENTRY_POINT
|
||
we should not forget that it should be exported from plugin module,
|
||
and it requires taking into an account some OS specifics. We do it
|
||
using macro FB_DLL_EXPORT defined in
|
||
examples/interfaces/ifaceExamples.h. If you are sure you write plugin
|
||
only for some specific OS you can make this place a bit simpler. In
|
||
minimum case the function should register module and all factories in
|
||
plugin manager:</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>extern "C" void
|
||
FB_DLL_EXPORT FB_PLUGIN_ENTRY_POINT(IMaster* master)</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>{</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4>IPluginManager*
|
||
pluginManager = master->getPluginManager();</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4>module.registerMe(pluginManager);</FONT></P>
|
||
<P STYLE="margin-bottom: 0in">
|
||
<FONT SIZE=4>pluginManager->registerPluginFactory(IPluginManager::TYPE_DB_CRYPT,
|
||
"DbCrypt_example", &factory);</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>}</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>First of all we call
|
||
written by us not long ago PluginModule::registerMe() function which
|
||
will saves IPluginManager for future use and registers our plugin
|
||
module. Next time to register factory (or factories in case of
|
||
multiple plugins per module) takes place. We must pass correct plugin
|
||
type (valid types are enumerated in interface IPluginManager) and a
|
||
name under which plugin will be registered. In simple case it should
|
||
match with the name of dynamic library with plugin module. Following
|
||
last rule will help you avoid configuring your plugin manually in
|
||
plugins.conf.</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>Pay attention - unlike
|
||
applications plugins should not use fb_get_master_interface() to
|
||
obtain IMaster. Instance, passed to FB_PLUGIN_ENTRY_POINT, should be
|
||
used instead. If you ever need master interface in your plugin take
|
||
care about saving it in this function.</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-top: 0.17in; margin-bottom: 0.2in; page-break-after: avoid">
|
||
<FONT FACE="Albany, sans-serif"><FONT SIZE=5>Interfaces: from A to Z</FONT></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>In this glossary we do not
|
||
list interfaces that are not actively used (like IRequest, needed
|
||
first of all to support legacy ISC API requests). Same reference may
|
||
be made for a number of methods (like compileRequest() in
|
||
IAttachment).</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<H1><FONT SIZE=4>Generic interfaces.</FONT></H1>
|
||
<P STYLE="margin-bottom: 0in"><A NAME="Attachment"></A><FONT SIZE=4>Attachment
|
||
interface:</FONT></P>
|
||
<OL>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void
|
||
getInfo(StatusType* status, unsigned itemsLength, const unsigned
|
||
char* items, unsigned bufferLength, unsigned char* buffer)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>ITransaction*
|
||
startTransaction(StatusType* status, unsigned tpbLength, const
|
||
unsigned char* tpb)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>ITransaction*
|
||
reconnectTransaction(StatusType* status, unsigned length, const
|
||
unsigned char* id)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>IRequest*
|
||
compileRequest(StatusType* status, unsigned blrLength, const
|
||
unsigned char* blr)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void
|
||
transactRequest(StatusType* status, ITransaction* transaction,
|
||
unsigned blrLength, const unsigned char* blr, unsigned inMsgLength,
|
||
const unsigned char* inMsg, unsigned outMsgLength, unsigned char*
|
||
outMsg)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>IBlob*
|
||
createBlob(StatusType* status, ITransaction* transaction, ISC_QUAD*
|
||
id, unsigned bpbLength, const unsigned char* bpb)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>IBlob*
|
||
openBlob(StatusType* status, ITransaction* transaction, ISC_QUAD*
|
||
id, unsigned bpbLength, const unsigned char* bpb)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>int
|
||
getSlice(StatusType* status, ITransaction* transaction, ISC_QUAD*
|
||
id, unsigned sdlLength, const unsigned char* sdl, unsigned
|
||
paramLength, const unsigned char* param, int sliceLength, unsigned
|
||
char* slice)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void
|
||
putSlice(StatusType* status, ITransaction* transaction, ISC_QUAD*
|
||
id, unsigned sdlLength, const unsigned char* sdl, unsigned
|
||
paramLength, const unsigned char* param, int sliceLength, unsigned
|
||
char* slice)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void
|
||
executeDyn(StatusType* status, ITransaction* transaction, unsigned
|
||
length, const unsigned char* dyn)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>IStatement*
|
||
prepare(StatusType* status, ITransaction* tra, unsigned stmtLength,
|
||
const char* sqlStmt, unsigned dialect, unsigned flags)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>ITransaction*
|
||
execute(StatusType* status, ITransaction* transaction, unsigned
|
||
stmtLength, const char* sqlStmt, unsigned dialect, IMessageMetadata*
|
||
inMetadata, void* inBuffer, IMessageMetadata* outMetadata, void*
|
||
outBuffer)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>IResultSet*
|
||
openCursor(StatusType* status, ITransaction* transaction, unsigned
|
||
stmtLength, const char* sqlStmt, unsigned dialect, IMessageMetadata*
|
||
inMetadata, void* inBuffer, IMessageMetadata* outMetadata, const
|
||
char* cursorName, unsigned cursorFlags)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>IEvents*
|
||
queEvents(StatusType* status, IEventCallback* callback, unsigned
|
||
length, const unsigned char* events)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void
|
||
cancelOperation(StatusType* status, int option)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void ping(StatusType*
|
||
status)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void
|
||
detach(StatusType* status)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void
|
||
dropDatabase(StatusType* status)</FONT></P>
|
||
</OL>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><A NAME="Blob"></A><FONT SIZE=4>Blob
|
||
interface:</FONT></P>
|
||
<OL>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void
|
||
getInfo(StatusType* status, unsigned itemsLength, const unsigned
|
||
char* items, unsigned bufferLength, u</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>int
|
||
getSegment(StatusType* status, unsigned bufferLength, void* buffer,
|
||
unsigned* segmentLength)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void
|
||
putSegment(StatusType* status, unsigned length, const void* buffer)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void
|
||
cancel(StatusType* status)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void
|
||
close(StatusType* status)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>int seek(StatusType*
|
||
status, int mode, int offset)</FONT></P>
|
||
</OL>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>Config interface:</FONT></P>
|
||
<OL>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>IConfigEntry*
|
||
find(StatusType* status, const char* name)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>IConfigEntry*
|
||
findValue(StatusType* status, const char* name, const char* value)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>IConfigEntry*
|
||
findPos(StatusType* status, const char* name, unsigned pos)</FONT></P>
|
||
</OL>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>ConfigManager interface:</FONT></P>
|
||
<OL>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>const char*
|
||
getDirectory(unsigned code)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>IFirebirdConf*
|
||
getFirebirdConf()</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>IFirebirdConf*
|
||
getDatabaseConf(const char* dbName)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>IConfig*
|
||
getPluginConfig(const char* configuredPlugin)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>const char*
|
||
getInstallDirectory()</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>const char*
|
||
getRootDirectory()</FONT></P>
|
||
</OL>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>ConfigEntry interface:</FONT></P>
|
||
<OL>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>const char* getName()</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>const char*
|
||
getValue()</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>ISC_INT64
|
||
getIntValue()</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>FB_BOOLEAN
|
||
getBoolValue()</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>IConfig*
|
||
getSubConfig(StatusType* status)</FONT></P>
|
||
</OL>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><A NAME="Dtc"></A><FONT SIZE=4>Dtc
|
||
interface:</FONT></P>
|
||
<OL>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>ITransaction*
|
||
join(StatusType* status, ITransaction* one, ITransaction* two)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>IDtcStart*
|
||
startBuilder(StatusType* status)</FONT></P>
|
||
</OL>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><A NAME="DtcStart"></A><FONT SIZE=4>DtcStart
|
||
interface:</FONT></P>
|
||
<OL>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void
|
||
addAttachment(StatusType* status, IAttachment* att)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void
|
||
addWithTpb(StatusType* status, IAttachment* att, unsigned length,
|
||
const unsigned char* tpb)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>ITransaction*
|
||
start(StatusType* status)</FONT></P>
|
||
</OL>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><A NAME="EventCallback"></A><FONT SIZE=4>EventCallback
|
||
interface:</FONT></P>
|
||
<OL>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void
|
||
eventCallbackFunction(unsigned length, const unsigned char* events)</FONT></P>
|
||
</OL>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><A NAME="Events"></A><FONT SIZE=4>Events
|
||
interface:</FONT></P>
|
||
<OL>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void
|
||
cancel(StatusType* status)</FONT></P>
|
||
</OL>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>FirebirdConf</FONT></P>
|
||
<OL>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>unsigned getKey(const
|
||
char* name)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>ISC_INT64
|
||
asInteger(unsigned key)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>const char*
|
||
asString(unsigned key)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>FB_BOOLEAN
|
||
asBoolean(unsigned key)</FONT></P>
|
||
</OL>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><A NAME="Master"></A><FONT SIZE=4>Master
|
||
interface:</FONT></P>
|
||
<OL>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>IStatus* getStatus()</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>IProvider*
|
||
getDispatcher()</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>IPluginManager*
|
||
getPluginManager()</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>ITimerControl*
|
||
getTimerControl()</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>IDtc* getDtc()</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>IUtil*
|
||
getUtilInterface()</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>IConfigManager*
|
||
getConfigManager()</FONT></P>
|
||
</OL>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><A NAME="MessageMetadata"></A><FONT SIZE=4>MessageMetadata
|
||
interface:</FONT></P>
|
||
<OL>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>unsigned
|
||
getCount(StatusType* status)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>const char*
|
||
getField(StatusType* status, unsigned index)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>const char*
|
||
getRelation(StatusType* status, unsigned index)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>const char*
|
||
getOwner(StatusType* status, unsigned index)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>const char*
|
||
getAlias(StatusType* status, unsigned index)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>unsigned
|
||
getType(StatusType* status, unsigned index)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>FB_BOOLEAN
|
||
isNullable(StatusType* status, unsigned index)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>int
|
||
getSubType(StatusType* status, unsigned index)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>unsigned
|
||
getLength(StatusType* status, unsigned index)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>int
|
||
getScale(StatusType* status, unsigned index)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>unsigned
|
||
getCharSet(StatusType* status, unsigned index)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>unsigned
|
||
getOffset(StatusType* status, unsigned index)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>unsigned
|
||
getNullOffset(StatusType* status, unsigned index)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>IMetadataBuilder*
|
||
getBuilder(StatusType* status)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>unsigned
|
||
getMessageLength(StatusType* status)</FONT></P>
|
||
</OL>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><A NAME="MetadataBuilder"></A><FONT SIZE=4>MetadataBuilder
|
||
interface:</FONT></P>
|
||
<OL>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void
|
||
setType(StatusType* status, unsigned index, unsigned type)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void
|
||
setSubType(StatusType* status, unsigned index, int subType)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void
|
||
setLength(StatusType* status, unsigned index, unsigned length)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void
|
||
setCharSet(StatusType* status, unsigned index, unsigned charSet)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void
|
||
setScale(StatusType* status, unsigned index, unsigned scale)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void
|
||
truncate(StatusType* status, unsigned count)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void
|
||
moveNameToIndex(StatusType* status, const char* name, unsigned
|
||
index)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void
|
||
remove(StatusType* status, unsigned index)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>unsigned
|
||
addField(StatusType* status)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>IMessageMetadata*
|
||
getMetadata(StatusType* status)</FONT></P>
|
||
</OL>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><A NAME="PluginConfig"></A><FONT SIZE=4>PluginConfig
|
||
interface:</FONT></P>
|
||
<OL>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>const char*
|
||
getConfigFileName()</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>IConfig*
|
||
getDefaultConfig(StatusType* status)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>IFirebirdConf*
|
||
getFirebirdConf(StatusType* status)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void
|
||
setReleaseDelay(StatusType* status, ISC_UINT64 microSeconds)</FONT></P>
|
||
</OL>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><A NAME="PluginFactory"></A><FONT SIZE=4>PluginFactory
|
||
interface:</FONT></P>
|
||
<OL>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>IPluginBase*
|
||
createPlugin(StatusType* status, IPluginConfig* factoryParameter)</FONT></P>
|
||
</OL>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><A NAME="PluginManager"></A><FONT SIZE=4>PluginManager
|
||
interface:</FONT></P>
|
||
<OL>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void
|
||
registerPluginFactory(unsigned pluginType, const char* defaultName,
|
||
IPluginFactory* factory)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void
|
||
registerModule(IPluginModule* cleanup)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void
|
||
unregisterModule(IPluginModule* cleanup)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>IPluginSet*
|
||
getPlugins(StatusType* status, unsigned pluginType, const char*
|
||
namesList, IFirebirdConf* firebirdConf)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>IConfig*
|
||
getConfig(StatusType* status, const char* filename)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void
|
||
releasePlugin(IPluginBase* plugin)</FONT></P>
|
||
</OL>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>Constants defined by
|
||
PluginManager interface (plugin types):</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4>TYPE_PROVIDER</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4>TYPE_AUTH_SERVER</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4>TYPE_AUTH_CLIENT</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4>TYPE_AUTH_USER_MANAGEMENT</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4>TYPE_EXTERNAL_ENGINE</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4>TYPE_TRACE</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4>TYPE_WIRE_CRYPT</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4>TYPE_DB_CRYPT</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4>TYPE_KEY_HOLDER</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><A NAME="PluginModule"></A><FONT SIZE=4>PluginModule
|
||
interface:</FONT></P>
|
||
<OL>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void doClean()</FONT></P>
|
||
</OL>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><A NAME="Provider"></A><FONT SIZE=4>Provider
|
||
interface:</FONT></P>
|
||
<OL>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>IAttachment*
|
||
attachDatabase(StatusType* status, const char* fileName, unsigned
|
||
dpbLength, const unsigned char* dpb)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>IAttachment*
|
||
createDatabase(StatusType* status, const char* fileName, unsigned
|
||
dpbLength, const unsigned char* dpb)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>IService*
|
||
attachServiceManager(StatusType* status, const char* service,
|
||
unsigned spbLength, const unsigned char* spb)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void
|
||
shutdown(StatusType* status, unsigned timeout, const int reason)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void
|
||
setDbCryptCallback(StatusType* status, ICryptKeyCallback*
|
||
cryptCallback)</FONT></P>
|
||
</OL>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><A NAME="ResultSet"></A><FONT SIZE=4>ResultSet
|
||
interface:</FONT></P>
|
||
<OL>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>int
|
||
fetchNext(StatusType* status, void* message)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>int
|
||
fetchPrior(StatusType* status, void* message)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>int
|
||
fetchFirst(StatusType* status, void* message)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>int
|
||
fetchLast(StatusType* status, void* message)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>int
|
||
fetchAbsolute(StatusType* status, int position, void* message)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>int
|
||
fetchRelative(StatusType* status, int offset, void* message)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>FB_BOOLEAN
|
||
isEof(StatusType* status)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>FB_BOOLEAN
|
||
isBof(StatusType* status)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>IMessageMetadata*
|
||
getMetadata(StatusType* status)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void
|
||
close(StatusType* status)</FONT></P>
|
||
</OL>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><A NAME="Service"></A><FONT SIZE=4>Service
|
||
interface:</FONT></P>
|
||
<OL>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void
|
||
detach(StatusType* status)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void
|
||
query(StatusType* status, unsigned sendLength, const unsigned char*
|
||
sendItems, unsigned receiveLength, const unsigned char*
|
||
receiveItems, unsigned bufferLength, unsigned char* buffer)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void
|
||
start(StatusType* status, unsigned spbLength, const unsigned char*
|
||
spb)</FONT></P>
|
||
</OL>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><A NAME="Statement"></A><FONT SIZE=4>Statement
|
||
interface:</FONT></P>
|
||
<OL>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void
|
||
getInfo(StatusType* status, unsigned itemsLength, const unsigned
|
||
char* items, unsigned bufferLength, unsigned char* buffer)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>unsigned
|
||
getType(StatusType* status)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>const char*
|
||
getPlan(StatusType* status, FB_BOOLEAN detailed)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>ISC_UINT64
|
||
getAffectedRecords(StatusType* status)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>IMessageMetadata*
|
||
getInputMetadata(StatusType* status)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>IMessageMetadata*
|
||
getOutputMetadata(StatusType* status)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>ITransaction*
|
||
execute(StatusType* status, ITransaction* transaction,
|
||
IMessageMetadata* inMetadata, void* inBuffer, IMessageMetadata*
|
||
outMetadata, void* outBuffer)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>IResultSet*
|
||
openCursor(StatusType* status, ITransaction* transaction,
|
||
IMessageMetadata* inMetadata, void* inBuffer, IMessageMetadata*
|
||
outMetadata, unsigned flags)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void
|
||
setCursorName(StatusType* status, const char* name)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void free(StatusType*
|
||
status)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>unsigned
|
||
getFlags(StatusType* status)</FONT></P>
|
||
</OL>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>Constants defined by
|
||
Statement interface:</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>- prepare() flags (may be
|
||
ORed):</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>PREPARE_PREFETCH_NONE</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>PREPARE_PREFETCH_TYPE</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>PREPARE_PREFETCH_INPUT_PARAMETERS</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>PREPARE_PREFETCH_OUTPUT_PARAMETERS</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>PREPARE_PREFETCH_LEGACY_PLAN</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>PREPARE_PREFETCH_DETAILED_PLAN</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>PREPARE_PREFETCH_AFFECTED_RECORDS</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>PREPARE_PREFETCH_FLAGS</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>- prepare() flags –
|
||
often used combinations of flags:</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>PREPARE_PREFETCH_METADATA</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>PREPARE_PREFETCH_ALL </FONT>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>FLAG_HAS_CURSOR = 1;</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>FLAG_REPEAT_EXECUTE = 2;</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>CURSOR_TYPE_SCROLLABLE =
|
||
1;</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><A NAME="Status"></A><FONT SIZE=4>Status
|
||
interface:</FONT></P>
|
||
<OL>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void init()</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>unsigned getState()</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void
|
||
setErrors2(unsigned length, const intptr_t* value)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void
|
||
setWarnings2(unsigned length, const intptr_t* value)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void setErrors(const
|
||
intptr_t* value)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void
|
||
setWarnings(const intptr_t* value)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>const intptr_t*
|
||
getErrors()</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>const intptr_t*
|
||
getWarnings()</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>IStatus* clone()</FONT></P>
|
||
</OL>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>Constants defined by
|
||
Status interface:</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>- flags set in the value,
|
||
returned by getState() method:</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>STATE_WARNINGS</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>STATE_ERRORS</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>- completion codes:</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>RESULT_ERROR</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>RESULT_OK</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>RESULT_NO_DATA</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>RESULT_SEGMENT</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><A NAME="Transaction"></A><FONT SIZE=4>Transaction
|
||
interface:</FONT></P>
|
||
<OL>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void
|
||
getInfo(StatusType* status, unsigned itemsLength, const unsigned
|
||
char* items, unsigned bufferLength, unsigned char* buffer)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void
|
||
prepare(StatusType* status, unsigned msgLength, const unsigned char*
|
||
message)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void
|
||
commit(StatusType* status)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void
|
||
commitRetaining(StatusType* status)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void
|
||
rollback(StatusType* status)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void
|
||
rollbackRetaining(StatusType* status)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void
|
||
disconnect(StatusType* status)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>ITransaction*
|
||
join(StatusType* status, ITransaction* transaction)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>ITransaction*
|
||
validate(StatusType* status, IAttachment* attachment)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>ITransaction*
|
||
enterDtc(StatusType* status)</FONT></P>
|
||
</OL>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><A NAME="Util"></A><FONT SIZE=4>Util
|
||
methods:</FONT></P>
|
||
<OL>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void
|
||
getFbVersion(StatusType* status, IAttachment* att, IVersionCallback*
|
||
callback)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void
|
||
loadBlob(StatusType* status, ISC_QUAD* blobId, IAttachment* att,
|
||
ITransaction* tra, const char* file, FB_BOOLEAN txt)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void
|
||
dumpBlob(StatusType* status, ISC_QUAD* blobId, IAttachment* att,
|
||
ITransaction* tra, const char* file, FB_BOOLEAN txt)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void
|
||
getPerfCounters(StatusType* status, IAttachment* att, const char*
|
||
countersSet, ISC_INT64* counters)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>IAttachment*
|
||
executeCreateDatabase(StatusType* status, unsigned stmtLength, const
|
||
char* creatDBstatement, unsigned dialect, FB_BOOLEAN*
|
||
stmtIsCreateDb)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void
|
||
decodeDate(ISC_DATE date, unsigned* year, unsigned* month, unsigned*
|
||
day)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void
|
||
decodeTime(ISC_TIME time, unsigned* hours, unsigned* minutes,
|
||
unsigned* seconds, unsigned* fractions)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>ISC_DATE
|
||
encodeDate(unsigned year, unsigned month, unsigned day)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>ISC_TIME
|
||
encodeTime(unsigned hours, unsigned minutes, unsigned seconds,
|
||
unsigned fractions)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>unsigned
|
||
formatStatus(char* buffer, unsigned bufferSize, IStatus* status)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>unsigned
|
||
getClientVersion()</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>IXpbBuilder*
|
||
getXpbBuilder(StatusType* status, unsigned kind, const unsigned
|
||
char* buf, unsigned len)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>unsigned
|
||
setOffsets(StatusType* status, IMessageMetadata* metadata,
|
||
IOffsetsCallback* callback)</FONT></P>
|
||
</OL>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><A NAME="XpbBuilder"></A><FONT SIZE=4>XpbBuilder
|
||
methods:</FONT></P>
|
||
<OL>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void
|
||
clear(StatusType* status)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void
|
||
removeCurrent(StatusType* status)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void
|
||
insertInt(StatusType* status, unsigned char tag, int value)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void
|
||
insertBigInt(StatusType* status, unsigned char tag, ISC_INT64 value)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void
|
||
insertBytes(StatusType* status, unsigned char tag, const void*
|
||
bytes, unsigned length)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void
|
||
insertTag(StatusType* status, unsigned char tag)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>FB_BOOLEAN
|
||
isEof(StatusType* status)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void
|
||
moveNext(StatusType* status)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void
|
||
rewind(StatusType* status)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>FB_BOOLEAN
|
||
findFirst(StatusType* status, unsigned char tag)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>FB_BOOLEAN
|
||
findNext(StatusType* status)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>unsigned char
|
||
getTag(StatusType* status)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>unsigned
|
||
getLength(StatusType* status)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>int
|
||
getInt(StatusType* status)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>ISC_INT64
|
||
getBigInt(StatusType* status)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>const char*
|
||
getString(StatusType* status)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>const unsigned char*
|
||
getBytes(StatusType* status)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>unsigned
|
||
getBufferLength(StatusType* status)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>const unsigned char*
|
||
getBuffer(StatusType* status)</FONT></P>
|
||
</OL>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>Constants defined by
|
||
XpbBuilder interface:</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>static const unsigned DPB
|
||
= 1;</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>static const unsigned
|
||
SPB_ATTACH = 2;</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>static const unsigned
|
||
SPB_START = 3;</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>static const unsigned TPB
|
||
= 4;</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<H1><FONT SIZE=4>Plugin, encrypting data transferred over the wire.</FONT></H1>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>CryptKey interface:</FONT></P>
|
||
<OL>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void
|
||
setSymmetric(StatusType* status, const char* type, unsigned
|
||
keyLength, const void* key)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void
|
||
setAsymmetric(StatusType* status, const char* type, unsigned
|
||
encryptKeyLength, const void* encryptKey, unsigned decryptKeyLength,
|
||
const void* decryptKey)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>const void*
|
||
getEncryptKey(unsigned* length)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>const void*
|
||
getDecryptKey(unsigned* length)</FONT></P>
|
||
</OL>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>WireCryptPlugin interface:</FONT></P>
|
||
<OL>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>const char*
|
||
getKnownTypes(StatusType* status)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void
|
||
setKey(StatusType* status, ICryptKey* key)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void
|
||
encrypt(StatusType* status, unsigned length, const void* from, void*
|
||
to)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void
|
||
decrypt(StatusType* status, unsigned length, const void* from, void*
|
||
to)</FONT></P>
|
||
</OL>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<H1><FONT SIZE=4>Server side of authentication plugin.</FONT></H1>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>Writer interface:</FONT></P>
|
||
<OL>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void reset()</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void add(StatusType*
|
||
status, const char* name)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void
|
||
setType(StatusType* status, const char* value)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void
|
||
setDb(StatusType* status, const char* value)</FONT></P>
|
||
</OL>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>ServerBlock interface:</FONT></P>
|
||
<OL>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>const char*
|
||
getLogin()</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>const unsigned char*
|
||
getData(unsigned* length)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void
|
||
putData(StatusType* status, unsigned length, const void* data)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>ICryptKey*
|
||
newKey(StatusType* status)</FONT></P>
|
||
</OL>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>Server interface:</FONT></P>
|
||
<OL>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>int
|
||
authenticate(StatusType* status, IServerBlock* sBlock, IWriter*
|
||
writerInterface)</FONT></P>
|
||
</OL>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<H1><FONT SIZE=4>Client side of authentication plugin.</FONT></H1>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>ClientBlock interface:</FONT></P>
|
||
<OL>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>const char*
|
||
getLogin()</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>const char*
|
||
getPassword()</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>const unsigned char*
|
||
getData(unsigned* length)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void
|
||
putData(StatusType* status, unsigned length, const void* data)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>ICryptKey*
|
||
newKey(StatusType* status)</FONT></P>
|
||
</OL>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>Client</FONT><FONT SIZE=4>
|
||
interface:</FONT></P>
|
||
<OL>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>int
|
||
authenticate(StatusType* status, IClientBlock* cBlock)</FONT></P>
|
||
</OL>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<H1><FONT SIZE=4>User management plugin.</FONT></H1>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>UserField interface:</FONT></P>
|
||
<OL>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>int entered()</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>int specified()</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void
|
||
setEntered(StatusType* status, int newValue)</FONT></P>
|
||
</OL>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>CharUserField interface:</FONT></P>
|
||
<OL>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>const char* get()</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void set(StatusType*
|
||
status, const char* newValue)</FONT></P>
|
||
</OL>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>IntUserField interface:</FONT></P>
|
||
<OL>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>int get()</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void set(StatusType*
|
||
status, int newValue)</FONT></P>
|
||
</OL>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>User interface:</FONT></P>
|
||
<OL>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>int operation()</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>ICharUserField*
|
||
userName()</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>ICharUserField*
|
||
password()</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>ICharUserField*
|
||
firstName()</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>ICharUserField*
|
||
lastName()</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>ICharUserField*
|
||
middleName()</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>ICharUserField*
|
||
comment()</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>ICharUserField*
|
||
attributes()</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>IIntUserField*
|
||
active()</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>IIntUserField*
|
||
admin()</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void
|
||
clear(StatusType* status)</FONT></P>
|
||
</OL>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>ListUsers interface:</FONT></P>
|
||
<OL>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void list(StatusType*
|
||
status, IUser* user)</FONT></P>
|
||
</OL>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>LogonInfo interface:</FONT></P>
|
||
<OL>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>const char* name()</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>const char* role()</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>const char*
|
||
networkProtocol()</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>const char*
|
||
remoteAddress()</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>const unsigned char*
|
||
authBlock(unsigned* length)</FONT></P>
|
||
</OL>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>Management interface:</FONT></P>
|
||
<OL>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void
|
||
start(StatusType* status, ILogonInfo* logonInfo)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>int
|
||
execute(StatusType* status, IUser* user, IListUsers* callback)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void
|
||
commit(StatusType* status)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void
|
||
rollback(StatusType* status)</FONT></P>
|
||
</OL>
|
||
<H1><FONT SIZE=4>Database encryption plugin.</FONT></H1>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>CryptKeyCallback
|
||
interface:</FONT></P>
|
||
<OL>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>unsigned
|
||
callback(unsigned dataLength, const void* data, unsigned
|
||
bufferLength, void* buffer)</FONT></P>
|
||
</OL>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>DbCryptPlugin interface:</FONT></P>
|
||
<OL>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void
|
||
setKey(StatusType* status, unsigned length, IKeyHolderPlugin**
|
||
sources, const char* keyName)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void
|
||
encrypt(StatusType* status, unsigned length, const void* from, void*
|
||
to)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void
|
||
decrypt(StatusType* status, unsigned length, const void* from, void*
|
||
to)</FONT></P>
|
||
</OL>
|
||
<H1><FONT SIZE=4>Key holder for database encryption plugin.</FONT></H1>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>KeyHolderPlugin interface:</FONT></P>
|
||
<OL>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>int
|
||
keyCallback(StatusType* status, ICryptKeyCallback* callback)</FONT></P>
|
||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>ICryptKeyCallback*
|
||
keyHandle(StatusType* status, const char* keyName)</FONT></P>
|
||
</OL>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<H1><FONT SIZE=4>Non-interface objects used by API (C++ specific
|
||
header Message.h).</FONT></H1>
|
||
<P STYLE="margin-bottom: 0in"><A NAME="FbDate"></A><FONT SIZE=4>class
|
||
FbDate methods:</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4>void decode(IUtil*
|
||
util, unsigned* year, unsigned* month, unsigned* day)</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4>unsigned
|
||
getYear(IUtil* util) </FONT>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4>unsigned
|
||
getMonth(IUtil* util)</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4>unsigned getDay(IUtil*
|
||
util)</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4>void encode(IUtil*
|
||
util, unsigned year, unsigned month, unsigned day)</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><A NAME="FbTime"></A><FONT SIZE=4>class
|
||
FbTime methods:</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4>void decode(IUtil*
|
||
util, unsigned* hours, unsigned* minutes, unsigned* seconds,
|
||
unsigned* fractions)</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4>unsigned
|
||
getHours(IUtil* util)</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4>unsigned
|
||
getMinutes(IUtil* util)</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4>unsigned
|
||
getSeconds(IUtil* util)</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4>unsigned
|
||
getFractions(IUtil* util)</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4>void encode(IUtil*
|
||
util, unsigned hours, unsigned minutes, unsigned seconds, unsigned
|
||
fractions)</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>template <unsigned N></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><A NAME="FbChar"></A><FONT SIZE=4>struct
|
||
FbChar</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>{</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4>char str[N];</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>};</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>template <unsigned N></FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><A NAME="FbVarChar"></A><FONT SIZE=4>struct
|
||
FbVarChar</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>{</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4>ISC_USHORT length;</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4>char str[N];</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4>void set(const char*
|
||
s);</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>};</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4>TYPE_EXTERNAL_ENGINE</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"> <FONT SIZE=4>TYPE_TRACE</FONT></P>
|
||
<P STYLE="margin-bottom: 0in"><BR>
|
||
</P>
|
||
</BODY>
|
||
</HTML> |