mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-02-02 09:20:39 +01:00
Make it possible to use batch interface from ISC API based applications
This commit is contained in:
parent
9a4ebe904f
commit
e306caff9b
@ -4,7 +4,8 @@
|
||||
* DESCRIPTION: A trivial sample of using Batch interface.
|
||||
*
|
||||
* Example for the following interfaces:
|
||||
* IBatch - interface to work with FB pipes
|
||||
* IBatch - interface to work with FB batches
|
||||
* IBatchCompletionState - contains result of batch execution
|
||||
*
|
||||
* c++ 11.batch.cpp -lfbclient
|
||||
*
|
||||
|
332
examples/interfaces/12.batch_isc.cpp
Normal file
332
examples/interfaces/12.batch_isc.cpp
Normal file
@ -0,0 +1,332 @@
|
||||
/*
|
||||
* PROGRAM: Object oriented API samples.
|
||||
* MODULE: 12.batch_isc.cpp
|
||||
* DESCRIPTION: A sample of using Batch interface.
|
||||
*
|
||||
* Example for the following interfaces:
|
||||
* IUtil - get IStatement/ITransaction by handle
|
||||
* IBatch - interface to work with FB batches
|
||||
* IBatchCompletionState - contains result of batch execution
|
||||
*
|
||||
* c++ 12.batch_isc.cpp -lfbclient
|
||||
*
|
||||
* The contents of this file are subject to the Initial
|
||||
* Developer's Public License Version 1.0 (the "License");
|
||||
* you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
* http://www.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl.
|
||||
*
|
||||
* Software distributed under the License is distributed AS IS,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing rights
|
||||
* and limitations under the License.
|
||||
*
|
||||
* The Original Code was created by Alexander Peshkoff
|
||||
* for the Firebird Open Source RDBMS project.
|
||||
*
|
||||
* Copyright (c) 2018 Alexander Peshkoff <peshkoff@mail.ru>
|
||||
* and all contributors signed below.
|
||||
*
|
||||
* All Rights Reserved.
|
||||
* Contributor(s): ______________________________________.
|
||||
*/
|
||||
|
||||
#include "ifaceExamples.h"
|
||||
#include <firebird/Message.h>
|
||||
|
||||
static IMaster* master = fb_get_master_interface();
|
||||
|
||||
|
||||
// output error message to user
|
||||
|
||||
static void errPrint(IStatus* status)
|
||||
{
|
||||
isc_print_status(status->getErrors());
|
||||
}
|
||||
|
||||
static void raiseError(ThrowStatusWrapper& status, ISC_STATUS *vector)
|
||||
{
|
||||
throw FbException(&status, vector);
|
||||
}
|
||||
|
||||
// BatchCompletionState printer - prints all what we know about completed batch
|
||||
|
||||
static void print_cs(ThrowStatusWrapper& status, IBatchCompletionState* cs, IUtil* utl)
|
||||
{
|
||||
unsigned p = 0;
|
||||
IStatus* s2 = NULL;
|
||||
bool pr1 = false, pr2 = false;
|
||||
|
||||
// 1. Print per-message state info
|
||||
|
||||
unsigned upcount = cs->getSize(&status);
|
||||
unsigned unk = 0, succ = 0;
|
||||
for (p = 0; p < upcount; ++p)
|
||||
{
|
||||
int s = cs->getState(&status, p);
|
||||
switch (s)
|
||||
{
|
||||
case IBatchCompletionState::EXECUTE_FAILED:
|
||||
if (!pr1)
|
||||
{
|
||||
printf("Message Status\n");
|
||||
pr1 = true;
|
||||
}
|
||||
printf("%5u Execute failed\n", p);
|
||||
break;
|
||||
|
||||
case IBatchCompletionState::SUCCESS_NO_INFO:
|
||||
++unk;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (!pr1)
|
||||
{
|
||||
printf("Message Status\n");
|
||||
pr1 = true;
|
||||
}
|
||||
printf("%5u Updated %d record(s)\n", p, s);
|
||||
++succ;
|
||||
break;
|
||||
}
|
||||
}
|
||||
printf("Summary: total=%u success=%u success(but no update info)=%u\n", upcount, succ, unk);
|
||||
|
||||
// 2. Print detailed errors (if exist) for messages
|
||||
|
||||
s2 = master->getStatus();
|
||||
for(p = 0; (p = cs->findError(&status, p)) != IBatchCompletionState::NO_MORE_ERRORS; ++p)
|
||||
{
|
||||
try
|
||||
{
|
||||
cs->getStatus(&status, s2, p);
|
||||
|
||||
char text[1024];
|
||||
utl->formatStatus(text, sizeof(text) - 1, s2);
|
||||
text[sizeof(text) - 1] = 0;
|
||||
if (!pr2)
|
||||
{
|
||||
printf("\nDetailed errors status:\n");
|
||||
pr2 = true;
|
||||
}
|
||||
printf("Message %u: %s\n", p, text);
|
||||
}
|
||||
catch (const FbException& error)
|
||||
{
|
||||
// handle error
|
||||
fprintf(stderr, "\nError describing message %u\n", p);
|
||||
errPrint(error.getStatus());
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (s2)
|
||||
s2->dispose();
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
// set default password if none specified in environment
|
||||
setenv("ISC_USER", "sysdba", 0);
|
||||
setenv("ISC_PASSWORD", "masterkey", 0);
|
||||
|
||||
// With ThrowStatusWrapper passed as status interface FbException will be thrown on error
|
||||
ThrowStatusWrapper status(master->getStatus());
|
||||
|
||||
ISC_STATUS_ARRAY st;
|
||||
isc_db_handle db = 0;
|
||||
isc_tr_handle tr = 0;
|
||||
isc_stmt_handle stmt = 0;
|
||||
isc_blob_handle blb = 0;
|
||||
|
||||
// Declare pointers to required interfaces
|
||||
/*IProvider* prov = master->getDispatcher();
|
||||
IAttachment* att = NULL;*/
|
||||
IUtil* utl = master->getUtilInterface();
|
||||
IStatement* statemt = NULL;
|
||||
ITransaction* tra = NULL;
|
||||
IBatch* batch = NULL;
|
||||
IBatchCompletionState* cs = NULL;
|
||||
IXpbBuilder* pb = NULL;
|
||||
|
||||
unsigned char streamBuf[10240]; // big enough for demo
|
||||
unsigned char* stream = NULL;
|
||||
|
||||
try
|
||||
{
|
||||
// attach employee db
|
||||
if (isc_attach_database(st, 0, "employee", &db, 0, NULL))
|
||||
raiseError(status, st);
|
||||
|
||||
isc_tr_handle tr = 0;
|
||||
if (isc_start_transaction(st, &tr, 1, &db, 0, NULL))
|
||||
raiseError(status, st);
|
||||
|
||||
// cleanup
|
||||
const char* cleanSql = "delete from project where proj_id like 'BAT%'";
|
||||
if (isc_dsql_execute_immediate(st, &db, &tr, 0, cleanSql, 3, NULL))
|
||||
raiseError(status, st);
|
||||
|
||||
if (isc_dsql_allocate_statement(st, &db, &stmt))
|
||||
raiseError(status, st);
|
||||
|
||||
// get transaction interface
|
||||
tra = utl->getTransactionByHandle(&status, &tr);
|
||||
|
||||
//
|
||||
printf("\nPart 1. BLOB created using IBlob interface.\n");
|
||||
//
|
||||
|
||||
// prepare statement
|
||||
const char* sqlStmt1 = "insert into project(proj_id, proj_name) values(?, ?)";
|
||||
if (isc_dsql_prepare(st, &tr, &stmt, 0, sqlStmt1, 3, NULL))
|
||||
raiseError(status, st);
|
||||
// and get it's interface
|
||||
statemt = utl->getStatementByHandle(&status, &stmt);
|
||||
|
||||
// Message to store in a table
|
||||
FB_MESSAGE(Msg1, ThrowStatusWrapper,
|
||||
(FB_VARCHAR(5), id)
|
||||
(FB_VARCHAR(10), name)
|
||||
) project1(&status, master);
|
||||
project1.clear();
|
||||
IMessageMetadata* meta = project1.getMetadata();
|
||||
|
||||
// set batch parameters
|
||||
pb = utl->getXpbBuilder(&status, IXpbBuilder::BATCH, NULL, 0);
|
||||
// collect per-message statistics
|
||||
pb->insertInt(&status, IBatch::TAG_RECORD_COUNTS, 1);
|
||||
|
||||
// create batch
|
||||
batch = statemt->createBatch(&status, meta,
|
||||
pb->getBufferLength(&status), pb->getBuffer(&status));
|
||||
|
||||
// fill batch with data record by record
|
||||
project1->id.set("BAT11");
|
||||
project1->name.set("SNGL_REC");
|
||||
batch->add(&status, 1, project1.getData());
|
||||
|
||||
project1->id.set("BAT12");
|
||||
project1->name.set("SNGL_REC2");
|
||||
batch->add(&status, 1, project1.getData());
|
||||
|
||||
// execute it
|
||||
cs = batch->execute(&status, tra);
|
||||
print_cs(status, cs, utl);
|
||||
|
||||
// close batch
|
||||
batch->release();
|
||||
batch = NULL;
|
||||
|
||||
// unprepare statement
|
||||
statemt->release();
|
||||
statemt = NULL;
|
||||
if (isc_dsql_free_statement(st, &stmt, DSQL_unprepare))
|
||||
raiseError(status, st);
|
||||
|
||||
|
||||
//
|
||||
printf("\nPart 2. BLOB created using isc_create_blob.\n");
|
||||
//
|
||||
|
||||
// prepare statement
|
||||
const char* sqlStmt2 = "insert into project(proj_id, proj_name, proj_desc) values(?, ?, ?)";
|
||||
if (isc_dsql_prepare(st, &tr, &stmt, 0, sqlStmt2, 3, NULL))
|
||||
raiseError(status, st);
|
||||
// and get it's interface
|
||||
statemt = utl->getStatementByHandle(&status, &stmt);
|
||||
|
||||
// Message to store in a table
|
||||
FB_MESSAGE(Msg2, ThrowStatusWrapper,
|
||||
(FB_VARCHAR(5), id)
|
||||
(FB_VARCHAR(10), name)
|
||||
(FB_BLOB, desc)
|
||||
) project2(&status, master);
|
||||
project2.clear();
|
||||
meta = project2.getMetadata();
|
||||
|
||||
// set batch parameters
|
||||
pb->clear(&status);
|
||||
// enable blobs processing - IDs generated by firebird engine
|
||||
pb->insertInt(&status, IBatch::TAG_BLOB_POLICY, IBatch::BLOB_ID_ENGINE);
|
||||
|
||||
// create batch
|
||||
batch = statemt->createBatch(&status, meta,
|
||||
pb->getBufferLength(&status), pb->getBuffer(&status));
|
||||
|
||||
// create blob
|
||||
ISC_QUAD realId;
|
||||
if (isc_create_blob(st, &db, &tr, &blb, &realId))
|
||||
raiseError(status, st);
|
||||
const char* text = "Blob created using traditional API";
|
||||
if (isc_put_segment(st, &blb, strlen(text), text))
|
||||
raiseError(status, st);
|
||||
if (isc_close_blob(st, &blb))
|
||||
raiseError(status, st);
|
||||
|
||||
// add message
|
||||
project2->id.set("BAT38");
|
||||
project2->name.set("FRGN_BLB");
|
||||
batch->registerBlob(&status, &realId, &project2->desc);
|
||||
batch->add(&status, 1, project2.getData());
|
||||
|
||||
// execute it
|
||||
cs = batch->execute(&status, tra);
|
||||
print_cs(status, cs, utl);
|
||||
|
||||
// close batch
|
||||
batch->release();
|
||||
batch = NULL;
|
||||
|
||||
// unprepare statement
|
||||
statemt->release();
|
||||
statemt = NULL;
|
||||
if (isc_dsql_free_statement(st, &stmt, DSQL_drop))
|
||||
raiseError(status, st);
|
||||
|
||||
// cleanup
|
||||
tra->release();
|
||||
tra = NULL;
|
||||
|
||||
if (isc_commit_transaction (st, &tr))
|
||||
raiseError(status, st);
|
||||
|
||||
if (isc_detach_database(st, &db))
|
||||
raiseError(status, st);
|
||||
}
|
||||
catch (const FbException& error)
|
||||
{
|
||||
// handle error
|
||||
rc = 1;
|
||||
errPrint(error.getStatus());
|
||||
}
|
||||
|
||||
// release interfaces after error caught
|
||||
if (cs)
|
||||
cs->dispose();
|
||||
if (batch)
|
||||
batch->release();
|
||||
if (tra)
|
||||
tra->release();
|
||||
if (statemt)
|
||||
statemt->release();
|
||||
|
||||
// close handles if not closed
|
||||
if (blb)
|
||||
isc_cancel_blob(st, &blb);
|
||||
if (stmt)
|
||||
isc_dsql_free_statement(st, &stmt, DSQL_close);
|
||||
if (tr)
|
||||
isc_rollback_transaction (st, &tr);
|
||||
if (db)
|
||||
isc_detach_database(st, &db);
|
||||
|
||||
// cleanup
|
||||
if (pb)
|
||||
pb->dispose();
|
||||
status.dispose();
|
||||
|
||||
return rc;
|
||||
}
|
@ -31,6 +31,8 @@ typedef ISC_QUAD;
|
||||
typedef ISC_TIME;
|
||||
typedef FB_DEC16;
|
||||
typedef FB_DEC34;
|
||||
typedef isc_tr_handle;
|
||||
typedef isc_stmt_handle;
|
||||
|
||||
// Versioned interface - base for all FB interfaces
|
||||
interface Versioned
|
||||
@ -1078,6 +1080,8 @@ version: // 3.0 => 4.0
|
||||
EventBlock createEventBlock(Status status, const string* events);
|
||||
DecFloat16 getDecFloat16(Status status);
|
||||
DecFloat34 getDecFloat34(Status status);
|
||||
Transaction getTransactionByHandle(Status status, isc_tr_handle* hndlPtr);
|
||||
Statement getStatementByHandle(Status status, isc_stmt_handle* hndlPtr);
|
||||
}
|
||||
|
||||
interface OffsetsCallback : Versioned
|
||||
|
@ -4037,6 +4037,8 @@ namespace Firebird
|
||||
IEventBlock* (CLOOP_CARG *createEventBlock)(IUtil* self, IStatus* status, const char** events) throw();
|
||||
IDecFloat16* (CLOOP_CARG *getDecFloat16)(IUtil* self, IStatus* status) throw();
|
||||
IDecFloat34* (CLOOP_CARG *getDecFloat34)(IUtil* self, IStatus* status) throw();
|
||||
ITransaction* (CLOOP_CARG *getTransactionByHandle)(IUtil* self, IStatus* status, isc_tr_handle* hndlPtr) throw();
|
||||
IStatement* (CLOOP_CARG *getStatementByHandle)(IUtil* self, IStatus* status, isc_stmt_handle* hndlPtr) throw();
|
||||
};
|
||||
|
||||
protected:
|
||||
@ -4179,6 +4181,34 @@ namespace Firebird
|
||||
StatusType::checkException(status);
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <typename StatusType> ITransaction* getTransactionByHandle(StatusType* status, isc_tr_handle* hndlPtr)
|
||||
{
|
||||
if (cloopVTable->version < 3)
|
||||
{
|
||||
StatusType::setVersionError(status, "IUtil", cloopVTable->version, 3);
|
||||
StatusType::checkException(status);
|
||||
return 0;
|
||||
}
|
||||
StatusType::clearException(status);
|
||||
ITransaction* ret = static_cast<VTable*>(this->cloopVTable)->getTransactionByHandle(this, status, hndlPtr);
|
||||
StatusType::checkException(status);
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <typename StatusType> IStatement* getStatementByHandle(StatusType* status, isc_stmt_handle* hndlPtr)
|
||||
{
|
||||
if (cloopVTable->version < 3)
|
||||
{
|
||||
StatusType::setVersionError(status, "IUtil", cloopVTable->version, 3);
|
||||
StatusType::checkException(status);
|
||||
return 0;
|
||||
}
|
||||
StatusType::clearException(status);
|
||||
IStatement* ret = static_cast<VTable*>(this->cloopVTable)->getStatementByHandle(this, status, hndlPtr);
|
||||
StatusType::checkException(status);
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
class IOffsetsCallback : public IVersioned
|
||||
@ -14017,6 +14047,8 @@ namespace Firebird
|
||||
this->createEventBlock = &Name::cloopcreateEventBlockDispatcher;
|
||||
this->getDecFloat16 = &Name::cloopgetDecFloat16Dispatcher;
|
||||
this->getDecFloat34 = &Name::cloopgetDecFloat34Dispatcher;
|
||||
this->getTransactionByHandle = &Name::cloopgetTransactionByHandleDispatcher;
|
||||
this->getStatementByHandle = &Name::cloopgetStatementByHandleDispatcher;
|
||||
}
|
||||
} vTable;
|
||||
|
||||
@ -14244,6 +14276,36 @@ namespace Firebird
|
||||
return static_cast<IDecFloat34*>(0);
|
||||
}
|
||||
}
|
||||
|
||||
static ITransaction* CLOOP_CARG cloopgetTransactionByHandleDispatcher(IUtil* self, IStatus* status, isc_tr_handle* hndlPtr) throw()
|
||||
{
|
||||
StatusType status2(status);
|
||||
|
||||
try
|
||||
{
|
||||
return static_cast<Name*>(self)->Name::getTransactionByHandle(&status2, hndlPtr);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
StatusType::catchException(&status2);
|
||||
return static_cast<ITransaction*>(0);
|
||||
}
|
||||
}
|
||||
|
||||
static IStatement* CLOOP_CARG cloopgetStatementByHandleDispatcher(IUtil* self, IStatus* status, isc_stmt_handle* hndlPtr) throw()
|
||||
{
|
||||
StatusType status2(status);
|
||||
|
||||
try
|
||||
{
|
||||
return static_cast<Name*>(self)->Name::getStatementByHandle(&status2, hndlPtr);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
StatusType::catchException(&status2);
|
||||
return static_cast<IStatement*>(0);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Name, typename StatusType, typename Base = IVersionedImpl<Name, StatusType, Inherit<IUtil> > >
|
||||
@ -14275,6 +14337,8 @@ namespace Firebird
|
||||
virtual IEventBlock* createEventBlock(StatusType* status, const char** events) = 0;
|
||||
virtual IDecFloat16* getDecFloat16(StatusType* status) = 0;
|
||||
virtual IDecFloat34* getDecFloat34(StatusType* status) = 0;
|
||||
virtual ITransaction* getTransactionByHandle(StatusType* status, isc_tr_handle* hndlPtr) = 0;
|
||||
virtual IStatement* getStatementByHandle(StatusType* status, isc_stmt_handle* hndlPtr) = 0;
|
||||
};
|
||||
|
||||
template <typename Name, typename StatusType, typename Base>
|
||||
|
@ -55,6 +55,14 @@ typedef unsigned int FB_API_HANDLE;
|
||||
typedef void* FB_API_HANDLE;
|
||||
#endif
|
||||
|
||||
typedef FB_API_HANDLE isc_att_handle;
|
||||
typedef FB_API_HANDLE isc_blob_handle;
|
||||
typedef FB_API_HANDLE isc_db_handle;
|
||||
typedef FB_API_HANDLE isc_req_handle;
|
||||
typedef FB_API_HANDLE isc_stmt_handle;
|
||||
typedef FB_API_HANDLE isc_svc_handle;
|
||||
typedef FB_API_HANDLE isc_tr_handle;
|
||||
|
||||
/******************************************************************/
|
||||
/* Sizes of memory blocks */
|
||||
/******************************************************************/
|
||||
|
@ -66,17 +66,10 @@
|
||||
|
||||
#include "types_pub.h"
|
||||
|
||||
/********************************/
|
||||
/* Firebird Handle Definitions */
|
||||
/********************************/
|
||||
/***********************/
|
||||
/* Firebird misc types */
|
||||
/***********************/
|
||||
|
||||
typedef FB_API_HANDLE isc_att_handle;
|
||||
typedef FB_API_HANDLE isc_blob_handle;
|
||||
typedef FB_API_HANDLE isc_db_handle;
|
||||
typedef FB_API_HANDLE isc_req_handle;
|
||||
typedef FB_API_HANDLE isc_stmt_handle;
|
||||
typedef FB_API_HANDLE isc_svc_handle;
|
||||
typedef FB_API_HANDLE isc_tr_handle;
|
||||
typedef void (* isc_callback) ();
|
||||
typedef ISC_LONG isc_resv_handle;
|
||||
|
||||
|
@ -19,6 +19,9 @@
|
||||
FB_DEC34 = array [1..2] of Int64;
|
||||
FB_DEC_FIXED = array [1..2] of Int64;
|
||||
|
||||
isc_tr_handle = ^integer32;
|
||||
isc_stmt_handle = ^integer32;
|
||||
|
||||
ntrace_relation_t = Integer;
|
||||
TraceCounts = Record
|
||||
trc_relation_id : ntrace_relation_t;
|
||||
|
@ -654,6 +654,8 @@ public:
|
||||
Firebird::IEventBlock* createEventBlock(Firebird::CheckStatusWrapper* status, const char** events);
|
||||
Firebird::IDecFloat16* getDecFloat16(Firebird::CheckStatusWrapper* status);
|
||||
Firebird::IDecFloat34* getDecFloat34(Firebird::CheckStatusWrapper* status);
|
||||
Firebird::ITransaction* getTransactionByHandle(Firebird::CheckStatusWrapper* status, isc_tr_handle* hndlPtr);
|
||||
Firebird::IStatement* getStatementByHandle(Firebird::CheckStatusWrapper* status, isc_stmt_handle* hndlPtr);
|
||||
};
|
||||
|
||||
} // namespace Why
|
||||
|
@ -1255,6 +1255,13 @@ namespace Why
|
||||
Arg::Gds(isc_dsql_cursor_open_err).raise();
|
||||
}
|
||||
|
||||
IStatement* getInterface()
|
||||
{
|
||||
fb_assert(statement);
|
||||
statement->addRef();
|
||||
return statement;
|
||||
}
|
||||
|
||||
AtomicAttPtr attachment;
|
||||
string cursorName;
|
||||
YStatement* statement;
|
||||
@ -6450,4 +6457,39 @@ void Dispatcher::setDbCryptCallback(CheckStatusWrapper* status, ICryptKeyCallbac
|
||||
cryptCallback = callback;
|
||||
}
|
||||
|
||||
ITransaction* UtilInterface::getTransactionByHandle(CheckStatusWrapper* status, isc_tr_handle* hndlPtr)
|
||||
{
|
||||
try
|
||||
{
|
||||
RefPtr<YTransaction> transaction(translateHandle(transactions, hndlPtr));
|
||||
|
||||
transaction->addRef();
|
||||
return transaction;
|
||||
}
|
||||
catch (const Exception& e)
|
||||
{
|
||||
e.stuffException(status);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
IStatement* UtilInterface::getStatementByHandle(Firebird::CheckStatusWrapper* status, isc_stmt_handle* hndlPtr)
|
||||
{
|
||||
try
|
||||
{
|
||||
RefPtr<IscStatement> statement(translateHandle(statements, hndlPtr));
|
||||
statement->checkPrepared(isc_info_unprepared_stmt);
|
||||
|
||||
return statement->getInterface();
|
||||
}
|
||||
catch (const Exception& e)
|
||||
{
|
||||
e.stuffException(status);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace Why
|
||||
|
Loading…
Reference in New Issue
Block a user