8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-02-02 09:20:39 +01:00

Bring examples up-to-date, use ThrowStatusWrapper in them

This commit is contained in:
alexpeshkoff 2015-02-10 13:32:03 +00:00
parent 2560be77ae
commit 9e627f3c64
5 changed files with 118 additions and 196 deletions

View File

@ -2,6 +2,8 @@
* PROGRAM: Object oriented API samples.
* MODULE: 01.create.cpp
* DESCRIPTION: A sample of creating new database and new table in it.
* Run second time (whene database already exists) to see
* how FbException is caught and handled by thid code.
*
* Example for the following interfaces:
* IMaster - main inteface to access all the rest
@ -66,6 +68,10 @@ int main()
st = master->getStatus();
prov = master->getDispatcher();
// status wrapper - will be used later in all calls where status interface is needed
// With ThrowStatusWrapper passed as status interface FbException will be thrown on error
ThrowStatusWrapper status(st);
// create DPB (to be replaced with IPBWriter)
unsigned char dpbBuf[32];
unsigned char *dpb = dpbBuf;
@ -76,58 +82,47 @@ int main()
*dpb++ = (8 * 1024) >> 8;
// create empty database
att = prov->createDatabase(st, "fbtests.fdb", dpb - dpbBuf, dpbBuf);
check(st, "createDatabase");
att = prov->createDatabase(&status, "fbtests.fdb", dpb - dpbBuf, dpbBuf);
printf("Database fbtests.fdb created\n");
// detach from database
att->detach(st);
check(st, "detach");
att->detach(&status);
att = NULL;
// attach it once again
att = prov->attachDatabase(st, "fbtests.fdb", 0, NULL);
check(st, "attachDatabase");
att = prov->attachDatabase(&status, "fbtests.fdb", 0, NULL);
printf("Re-attached database fbtests.fdb\n");
// start transaction
tra = att->startTransaction(st, 0, NULL);
check(st, "startTransaction");
tra = att->startTransaction(&status, 0, NULL);
// create table
att->execute(st, tra, 0, "create table dates_table (d1 date)", 3,
att->execute(&status, tra, 0, "create table dates_table (d1 date)", 3,
NULL, NULL, NULL, NULL); // Input parameters and output data not used
check(st, "execute");
// commit transaction retaining
tra->commitRetaining(st);
check(st, "commitRetaining");
tra->commitRetaining(&status);
printf("Table dates_table created\n");
// insert a record into dates_table
att->execute(st, tra, 0, "insert into dates_table values (CURRENT_DATE)", 3,
att->execute(&status, tra, 0, "insert into dates_table values (CURRENT_DATE)", 3,
NULL, NULL, NULL, NULL); // Input parameters and output data not used
check(st, "execute");
// commit transaction (will close interface)
tra->commit(st);
check(st, "commit");
tra->commit(&status);
tra = NULL;
printf("Record inserted into dates_table\n");
// detach from database (will close interface)
att->detach(st);
check(st, "detach");
att->detach(&status);
att = NULL;
}
catch (const char* text)
catch (const FbException& error)
{
// handle error
rc = 1;
fprintf(stderr, "%s:\n", text);
if (st)
isc_print_status(st->getErrors());
isc_print_status(error.getStatus()->getErrors());
}
// release interfaces after error caught

View File

@ -4,7 +4,8 @@
* DESCRIPTION: Run once prepared statement with parameters
* a few times, committing transaction after each run.
* Learns how to prepare statement, manually define parameters
* for it and execute that statement with different parameters.
* for it, execute that statement with different parameters
* and perform non-default error processing.
*
* Example for the following interfaces:
* IAttachment - database attachment
@ -76,59 +77,47 @@ int main()
{
// status vector and main dispatcher
st = master->getStatus();
ThrowStatusWrapper status(st);
prov = master->getDispatcher();
// attach employee db
att = prov->attachDatabase(st, "employee", 0, NULL);
check(st, "attachDatabase");
att = prov->attachDatabase(&status, "employee", 0, NULL);
// start transaction
tra = att->startTransaction(st, 0, NULL);
check(st, "startTransaction");
tra = att->startTransaction(&status, 0, NULL);
// prepare statement
stmt = att->prepare(st, tra, 0, updstr, 3, 0);
check(st, "prepare");
stmt = att->prepare(&status, tra, 0, updstr, 3, 0);
// build metadata
// IMaster creates empty new metadata in builder
builder = master->getMetadataBuilder(st, 2);
check(st, "getMetadataBuilder");
builder = master->getMetadataBuilder(&status, 2);
// set required info on fields
builder->setType(st, 0, SQL_DOUBLE + 1);
check(st, "setType");
builder->setType(st, 1, SQL_TEXT + 1);
check(st, "setType");
builder->setLength(st, 1, 3);
check(st, "setLength");
builder->setType(&status, 0, SQL_DOUBLE + 1);
builder->setType(&status, 1, SQL_TEXT + 1);
builder->setLength(&status, 1, 3);
// IMetadata should be ready
meta = builder->getMetadata(st);
check(st, "getMetadata");
meta = builder->getMetadata(&status);
// no need in builder any more
builder->release();
builder = NULL;
// allocate buffer
// allocate buffer on stack
char buffer[256];
unsigned len = meta->getMessageLength(st);
check(st, "getMessageLength");
if (len > 256)
unsigned len = meta->getMessageLength(&status);
if (len > sizeof(buffer))
{
throw "Input message length too big - can't continue";
}
// locations of parameters in input message
char* dept_no = &buffer[meta->getOffset(st, 1)];
check(st, "getOffset");
double* percent_inc = (double*) &buffer[meta->getOffset(st, 0)];
check(st, "getOffset");
char* dept_no = &buffer[meta->getOffset(&status, 1)];
double* percent_inc = (double*) &buffer[meta->getOffset(&status, 0)];
// null IDs (set to NOT NULL)
short* flag = (short*)&buffer[meta->getNullOffset(st, 0)];
check(st, "getNullOffset");
short* flag = (short*)&buffer[meta->getNullOffset(&status, 0)];
*flag = 0;
flag = (short*) &buffer[meta->getNullOffset(st, 1)];
check(st, "getNullOffset");
flag = (short*) &buffer[meta->getNullOffset(&status, 1)];
*flag = 0;
// Get the next department-percent increase input pair.
@ -138,54 +127,51 @@ int main()
dept_no, *percent_inc);
// Update the budget.
stmt->execute(st, tra, meta, buffer, NULL, NULL);
if (st->getStatus() & IStatus::FB_HAS_ERRORS)
{
int sqlcode = isc_sqlcode(st->getErrors());
// Don't save the update, if the new budget exceeds the limit.
if (sqlcode == -625)
{
printf("\tExceeded budget limit -- not updated.\n");
try
{
stmt->execute(&status, tra, meta, buffer, NULL, NULL);
}
catch(const FbException& error)
{
// Handle exception raised during statement execution
int sqlcode = isc_sqlcode(error.getStatus()->getErrors());
// Don't save the update, if the new budget exceeds the limit.
if (sqlcode == -625)
{
printf("\tExceeded budget limit -- not updated.\n");
tra->rollbackRetaining(st);
check(st, "rollback");
continue;
}
tra->rollbackRetaining(&status);
continue;
}
// use default handler
check(st, "execute");
}
// Another error - use default handler
throw;
}
// Save each department's update independently.
// *** Change to commitRetaining() to see changes
// *** tra->commitRetaining(st);
tra->rollbackRetaining(st);
check(st, "rollback");
// *** tra->commitRetaining(&status);
tra->rollbackRetaining(&status);
}
// close interfaces
stmt->free(st);
check(st, "free");
stmt->free(&status);
stmt = NULL;
meta->release();
meta = NULL;
tra->commit(st);
check(st, "commit");
tra->commit(&status);
tra = NULL;
att->detach(st);
check(st, "detach");
att->detach(&status);
att = NULL;
}
catch (const char* text)
catch (const FbException& error)
{
// handle error
rc = 1;
fprintf(stderr, "%s:\n", text);
if (st)
isc_print_status(st->getErrors());
isc_print_status(error.getStatus()->getErrors());
}
// release interfaces after error caught

View File

@ -61,29 +61,24 @@ int main()
{
// status vector and main dispatcher
st = master->getStatus();
ThrowStatusWrapper status(st);
prov = master->getDispatcher();
// attach employee db
att = prov->attachDatabase(st, "employee", 0, NULL);
check(st, "attachDatabase");
att = prov->attachDatabase(&status, "employee", 0, NULL);
// start default transaction
tra = att->startTransaction(st, 0, NULL);
check(st, "startTransaction");
tra = att->startTransaction(&status, 0, NULL);
// prepare statement
stmt = att->prepare(st, tra, 0, "select last_name, first_name, phone_ext from phone_list "
stmt = att->prepare(&status, tra, 0, "select last_name, first_name, phone_ext from phone_list "
"where location = 'Monterey' order by last_name, first_name",
3, IStatement::PREPARE_PREFETCH_METADATA);
check(st, "prepare");
// get list of columns
meta = stmt->getOutputMetadata(st);
check(st, "getOutputMetadata");
builder = meta->getBuilder(st);
check(st, "getBuilder");
unsigned cols = meta->getCount(st);
check(st, "getCount");
meta = stmt->getOutputMetadata(&status);
builder = meta->getBuilder(&status);
unsigned cols = meta->getCount(&status);
// struct to cache received metadata
struct MyField
@ -97,15 +92,12 @@ int main()
// parse columns list & coerce datatype(s)
for (unsigned j = 0; j < cols; ++j)
{
unsigned t = meta->getType(st, j);
check(st, "getType");
unsigned t = meta->getType(&status, j);
if (t == SQL_VARYING || t == SQL_TEXT)
{
builder->setType(st, j, SQL_TEXT);
check(st, "setType");
fields[j].name = meta->getField(st, j);
check(st, "getField");
builder->setType(&status, j, SQL_TEXT);
fields[j].name = meta->getField(&status, j);
}
}
@ -114,8 +106,7 @@ int main()
meta->release();
// get metadata with coerced datatypes
meta = builder->getMetadata(st);
check(st, "getMetadata");
meta = builder->getMetadata(&status);
// builder not needed any more
builder->release();
@ -126,64 +117,66 @@ int main()
{
if (fields[j].name)
{
fields[j].length = meta->getLength(st, j);
check(st, "getLength");
fields[j].offset = meta->getOffset(st, j);
check(st, "getOffset");
fields[j].length = meta->getLength(&status, j);
fields[j].offset = meta->getOffset(&status, j);
}
}
// open cursor
curs = stmt->openCursor(st, tra, NULL, NULL, meta);
check(st, "openCursor");
curs = stmt->openCursor(&status, tra, NULL, NULL, meta, 0);
// allocate output buffer
unsigned l = meta->getMessageLength(st);
check(st, "getMessageLength");
unsigned l = meta->getMessageLength(&status);
unsigned char* buffer = new unsigned char[l];
// fetch records from cursor and print them
while (curs->fetchNext(st, buffer) == IStatus::FB_OK)
for (int line = 0; curs->fetchNext(&status, buffer) == IStatus::FB_OK; ++line)
{
if (line % 10 == 0)
{
printf("\n");
for (unsigned j = 0; j < cols; ++j)
{
if (fields[j].name)
{
printf("%-*.*s ", fields[j].length, fields[j].length, fields[j].name);
}
}
printf("\n");
}
for (unsigned j = 0; j < cols; ++j)
{
if (fields[j].name)
{
printf("%s: %*.*s\n", fields[j].name, fields[j].length, fields[j].length,
buffer + fields[j].offset);
printf("%*.*s ", fields[j].length, fields[j].length, buffer + fields[j].offset);
}
}
printf("\n");
}
check(st, "fetchNext");
printf("\n");
// close interfaces
curs->close(st);
check(st, "close");
curs->close(&status);
curs = NULL;
stmt->free(st);
check(st, "free");
stmt->free(&status);
stmt = NULL;
meta->release();
meta = NULL;
tra->commit(st);
check(st, "commit");
tra->commit(&status);
tra = NULL;
att->detach(st);
check(st, "detach");
att->detach(&status);
att = NULL;
}
catch (const char* text)
catch (const FbException& error)
{
// handle error
rc = 1;
fprintf(stderr, "%s:\n", text);
if (st)
isc_print_status(st->getErrors());
isc_print_status(error.getStatus()->getErrors());
}
// release interfaces after error caught

View File

@ -42,7 +42,7 @@ struct MyField
const char* name;
unsigned type, length, offset, null;
void print(IStatus* st, IAttachment* att, ITransaction* tra, unsigned char* buf);
void print(ThrowStatusWrapper* st, IAttachment* att, ITransaction* tra, unsigned char* buf);
};
int main()
@ -54,6 +54,7 @@ int main()
setenv("ISC_PASSWORD", "masterkey", 0);
IStatus* st = master->getStatus();
ThrowStatusWrapper status(st);
IProvider* prov = master->getDispatcher();
IAttachment* att = NULL;
@ -63,11 +64,8 @@ int main()
try
{
att = prov->attachDatabase(st, "employee", 0, NULL);
check(st, "attachDatabase");
tra = att->startTransaction(st, 0, NULL);
check(st, "startTransaction");
att = prov->attachDatabase(&status, "employee", 0, NULL);
tra = att->startTransaction(&status, 0, NULL);
// If we are not going to run same SELECT query many times we may do not prepare it,
// opening cursor instead with single API call.
@ -81,14 +79,9 @@ int main()
"or RDB$VIEW_SOURCE is not null";
// Do not use IStatement - just ask attachment to open cursor
curs = att->openCursor(st, tra, 0, sql, 3, NULL, NULL, NULL, NULL);
check(st, "openCursor");
meta = curs->getMetadata(st);
check(st, "getMetadata");
unsigned cols = meta->getCount(st);
check(st, "getCount");
curs = att->openCursor(&status, tra, 0, sql, 3, NULL, NULL, NULL, NULL, 0);
meta = curs->getMetadata(&status);
unsigned cols = meta->getCount(&status);
MyField* fields = new MyField[cols];
memset(fields, 0, sizeof(MyField) * cols);
@ -96,10 +89,8 @@ int main()
unsigned f = 0;
for (unsigned j = 0; j < cols; ++j)
{
unsigned t = meta->getType(st, j) & ~1;
check(st, "getType");
unsigned sub = meta->getSubType(st, j);
check(st, "getSubType");
unsigned t = meta->getType(&status, j) & ~1;
unsigned sub = meta->getSubType(&status, j);
switch (t)
{
@ -116,7 +107,7 @@ int main()
default:
{
sprintf(s, "Unknown type %d for %s", t, meta->getField(st, j));
sprintf(s, "Unknown type %d for %s", t, meta->getField(&status, j));
throw s;
}
continue;
@ -124,51 +115,37 @@ int main()
// we can work with this field - cache metadata info for fast access
fields[f].type = t;
fields[f].name = meta->getField(st, j);
check(st, "getField");
fields[f].length = meta->getLength(st, j);
check(st, "getLength");
fields[f].offset = meta->getOffset(st, j);
check(st, "getLength");
fields[f].null = meta->getNullOffset(st, j);
check(st, "getNullOffset");
fields[f].name = meta->getField(&status, j);
fields[f].length = meta->getLength(&status, j);
fields[f].offset = meta->getOffset(&status, j);
fields[f].null = meta->getNullOffset(&status, j);
++f;
}
unsigned l = meta->getMessageLength(st);
check(st, "getMessageLength");
unsigned l = meta->getMessageLength(&status);
unsigned char* buffer = new unsigned char[l];
// fetch records from cursor
while (curs->fetchNext(st, buffer) == IStatus::FB_OK)
while (curs->fetchNext(&status, buffer) == IStatus::FB_OK)
{
for (unsigned j = 0; j < f; ++j)
{
// call field's function to print it
fields[j].print(st, att, tra, buffer);
fields[j].print(&status, att, tra, buffer);
}
printf("\n");
}
check(st, "fetch");
curs->close(st);
check(st, "close");
curs->close(&status);
curs = NULL;
meta->release();
meta = NULL;
tra->commit(st);
check(st, "commit");
tra->commit(&status);
tra = NULL;
att->detach(st);
check(st, "detach");
att->detach(&status);
att = NULL;
}
catch (const char* text)
@ -203,7 +180,7 @@ T as(unsigned char* ptr)
return *((T*) ptr);
}
void MyField::print(IStatus* st, IAttachment* att, ITransaction* tra, unsigned char* buf)
void MyField::print(ThrowStatusWrapper* st, IAttachment* att, ITransaction* tra, unsigned char* buf)
{
printf("%s: ", name);
if (as<short>(buf + null))
@ -243,7 +220,6 @@ void MyField::print(IStatus* st, IAttachment* att, ITransaction* tra, unsigned c
{
// use attachment's method to access BLOB object
blob = att->openBlob(st, tra, (ISC_QUAD*) (buf + offset), 0, NULL);
check(st, "openBlob");
char segbuf[16];
unsigned len;
@ -255,11 +231,9 @@ void MyField::print(IStatus* st, IAttachment* att, ITransaction* tra, unsigned c
break;
fwrite(segbuf, sizeof(char), len, stdout);
}
check(st, "getSegment");
// close BLOB after receiving all data
blob->close(st);
check(st, "close");
blob = NULL;
printf("\n");
}

View File

@ -32,29 +32,3 @@
#include <firebird/Interface.h>
using namespace Firebird;
typedef FirebirdApi<class ExamplesPolicy> Api;
FB_USE_API(Api)
// Dummy policy - to be enhanced
class ExamplesPolicy
{
public:
template <unsigned V, typename T>
static inline bool checkVersion(T* versioned, IStatus* status)
{ return true; }
static void checkException(Api::IStatus*) { }
static void catchException(Api::IStatus*) { }
typedef Api::IStatus* IStatus;
};
// Declare function to get access to master interface.
DECLARE_GET_MASTER(ExamplesPolicy);
// Probably not best way of error processing, but it's OK for a sample
static void check(IStatus* s, const char* text)
{
if (s->getStatus() & IStatus::FB_HAS_ERRORS)
throw text;
}