mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-02-02 09:20:39 +01:00
Implemented CORE-5176: Add interface replacing isc_event_block() and isc_event_counts() functions
This commit is contained in:
parent
f58ecf78b4
commit
f92f2a1b09
@ -1,13 +1,12 @@
|
||||
/*
|
||||
* PROGRAM: Object oriented API samples.
|
||||
* MODULE: 07.blob.cpp
|
||||
* DESCRIPTION: A sample of loading data into blob and reading.
|
||||
* Run second time (when database already exists) to see
|
||||
* how FbException is caught and handled by this code.
|
||||
* MODULE: 08.events.cpp
|
||||
* DESCRIPTION: A sample of working with events.
|
||||
*
|
||||
* Example for the following interfaces:
|
||||
* IAttachment - use of open and create blob methods
|
||||
* IBlob - interface to work with blobs
|
||||
* IEvents - returned by queEvents(), used to cancel events monitoring
|
||||
* IEventBlock - creates and handles various blocks needed to que events
|
||||
* IEventCallback - it's callback is invoked when event happens
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
@ -39,6 +38,7 @@ static IMaster* master = fb_get_master_interface();
|
||||
|
||||
namespace
|
||||
{
|
||||
// This class encapsulates single event handling
|
||||
class Event : public IEventCallbackImpl<Event, ThrowStatusWrapper>
|
||||
{
|
||||
public:
|
||||
@ -48,7 +48,8 @@ namespace
|
||||
counter(0),
|
||||
status(master->getStatus()),
|
||||
eventBlock(NULL),
|
||||
events(NULL)
|
||||
events(NULL),
|
||||
first(true)
|
||||
{
|
||||
const char* names[] = {name, NULL};
|
||||
eventBlock = master->getUtilInterface()->createEventBlock(&status, names);
|
||||
@ -60,19 +61,33 @@ namespace
|
||||
if (!events)
|
||||
return;
|
||||
|
||||
unsigned tot = 0;
|
||||
if (counter)
|
||||
{
|
||||
eventBlock->counts();
|
||||
unsigned tot = eventBlock->getCounters()[0];
|
||||
printf("Event count on pass %d is %d\n", pass, tot);
|
||||
tot = eventBlock->getCounters()[0];
|
||||
|
||||
events->release();
|
||||
events = NULL;
|
||||
counter = 0;
|
||||
events = attachment->queEvents(&status, this, eventBlock->getLength(), eventBlock->getValues());
|
||||
}
|
||||
|
||||
if (tot && !first)
|
||||
printf("Event count on pass %d is %d\n", pass, tot);
|
||||
else
|
||||
printf("Pass %d - no events\n", pass);
|
||||
|
||||
first = false;
|
||||
}
|
||||
|
||||
// IEventCallback implementation
|
||||
void eventCallbackFunction(unsigned int length, const ISC_UCHAR* data)
|
||||
{
|
||||
memcpy(eventBlock->getBuffer(), data, length);
|
||||
++counter;
|
||||
if (!first)
|
||||
printf("AST called\n");
|
||||
}
|
||||
|
||||
// refCounted implementation
|
||||
@ -92,14 +107,6 @@ namespace
|
||||
return 1;
|
||||
}
|
||||
|
||||
// IEventCallback implementation
|
||||
void eventCallbackFunction(unsigned int length, const ISC_UCHAR* data)
|
||||
{
|
||||
memcpy(eventBlock->getBuffer(), data, length);
|
||||
++counter;
|
||||
printf("AST called\n");
|
||||
}
|
||||
|
||||
private:
|
||||
~Event()
|
||||
{
|
||||
@ -115,6 +122,7 @@ namespace
|
||||
ThrowStatusWrapper status;
|
||||
IEventBlock* eventBlock;
|
||||
IEvents* events;
|
||||
bool first;
|
||||
};
|
||||
}
|
||||
|
||||
@ -137,7 +145,7 @@ int main()
|
||||
|
||||
try
|
||||
{
|
||||
// create database
|
||||
// attach database
|
||||
att = prov->attachDatabase(&status, "employee", 0, NULL);
|
||||
|
||||
// register an event
|
||||
|
@ -462,6 +462,16 @@ interface Events : ReferenceCounted
|
||||
void cancel(Status status);
|
||||
}
|
||||
|
||||
interface EventBlock : Disposable
|
||||
{
|
||||
uint getLength();
|
||||
uchar* getValues();
|
||||
uchar* getBuffer();
|
||||
uint getCount();
|
||||
uint* getCounters();
|
||||
void counts();
|
||||
}
|
||||
|
||||
interface Attachment : ReferenceCounted
|
||||
{
|
||||
void getInfo(Status status,
|
||||
@ -929,6 +939,9 @@ interface Util : Versioned
|
||||
uint getClientVersion(); // Returns major * 256 + minor
|
||||
XpbBuilder getXpbBuilder(Status status, uint kind, const uchar* buf, uint len);
|
||||
uint setOffsets(Status status, MessageMetadata metadata, OffsetsCallback callback);
|
||||
|
||||
version:
|
||||
EventBlock createEventBlock(Status status, const string* events);
|
||||
}
|
||||
|
||||
interface OffsetsCallback : Versioned
|
||||
|
@ -51,6 +51,7 @@ namespace Firebird
|
||||
class IStatement;
|
||||
class IRequest;
|
||||
class IEvents;
|
||||
class IEventBlock;
|
||||
class IAttachment;
|
||||
class IService;
|
||||
class IProvider;
|
||||
@ -1775,6 +1776,68 @@ namespace Firebird
|
||||
}
|
||||
};
|
||||
|
||||
class IEventBlock : public IDisposable
|
||||
{
|
||||
public:
|
||||
struct VTable : public IDisposable::VTable
|
||||
{
|
||||
unsigned (CLOOP_CARG *getLength)(IEventBlock* self) throw();
|
||||
unsigned char* (CLOOP_CARG *getValues)(IEventBlock* self) throw();
|
||||
unsigned char* (CLOOP_CARG *getBuffer)(IEventBlock* self) throw();
|
||||
unsigned (CLOOP_CARG *getCount)(IEventBlock* self) throw();
|
||||
unsigned* (CLOOP_CARG *getCounters)(IEventBlock* self) throw();
|
||||
void (CLOOP_CARG *counts)(IEventBlock* self) throw();
|
||||
};
|
||||
|
||||
protected:
|
||||
IEventBlock(DoNotInherit)
|
||||
: IDisposable(DoNotInherit())
|
||||
{
|
||||
}
|
||||
|
||||
~IEventBlock()
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
static const unsigned VERSION = 3;
|
||||
|
||||
unsigned getLength()
|
||||
{
|
||||
unsigned ret = static_cast<VTable*>(this->cloopVTable)->getLength(this);
|
||||
return ret;
|
||||
}
|
||||
|
||||
unsigned char* getValues()
|
||||
{
|
||||
unsigned char* ret = static_cast<VTable*>(this->cloopVTable)->getValues(this);
|
||||
return ret;
|
||||
}
|
||||
|
||||
unsigned char* getBuffer()
|
||||
{
|
||||
unsigned char* ret = static_cast<VTable*>(this->cloopVTable)->getBuffer(this);
|
||||
return ret;
|
||||
}
|
||||
|
||||
unsigned getCount()
|
||||
{
|
||||
unsigned ret = static_cast<VTable*>(this->cloopVTable)->getCount(this);
|
||||
return ret;
|
||||
}
|
||||
|
||||
unsigned* getCounters()
|
||||
{
|
||||
unsigned* ret = static_cast<VTable*>(this->cloopVTable)->getCounters(this);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void counts()
|
||||
{
|
||||
static_cast<VTable*>(this->cloopVTable)->counts(this);
|
||||
}
|
||||
};
|
||||
|
||||
class IAttachment : public IReferenceCounted
|
||||
{
|
||||
public:
|
||||
@ -3448,6 +3511,7 @@ namespace Firebird
|
||||
unsigned (CLOOP_CARG *getClientVersion)(IUtil* self) throw();
|
||||
IXpbBuilder* (CLOOP_CARG *getXpbBuilder)(IUtil* self, IStatus* status, unsigned kind, const unsigned char* buf, unsigned len) throw();
|
||||
unsigned (CLOOP_CARG *setOffsets)(IUtil* self, IStatus* status, IMessageMetadata* metadata, IOffsetsCallback* callback) throw();
|
||||
IEventBlock* (CLOOP_CARG *createEventBlock)(IUtil* self, IStatus* status, const char** events) throw();
|
||||
};
|
||||
|
||||
protected:
|
||||
@ -3461,7 +3525,7 @@ namespace Firebird
|
||||
}
|
||||
|
||||
public:
|
||||
static const unsigned VERSION = 2;
|
||||
static const unsigned VERSION = 3;
|
||||
|
||||
template <typename StatusType> void getFbVersion(StatusType* status, IAttachment* att, IVersionCallback* callback)
|
||||
{
|
||||
@ -3548,6 +3612,20 @@ namespace Firebird
|
||||
StatusType::checkException(status);
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <typename StatusType> IEventBlock* createEventBlock(StatusType* status, const char** events)
|
||||
{
|
||||
if (cloopVTable->version < 3)
|
||||
{
|
||||
StatusType::setVersionError(status, "IUtil", cloopVTable->version, 3);
|
||||
StatusType::checkException(status);
|
||||
return 0;
|
||||
}
|
||||
StatusType::clearException(status);
|
||||
IEventBlock* ret = static_cast<VTable*>(this->cloopVTable)->createEventBlock(this, status, events);
|
||||
StatusType::checkException(status);
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
class IOffsetsCallback : public IVersioned
|
||||
@ -8481,6 +8559,143 @@ namespace Firebird
|
||||
virtual void cancel(StatusType* status) = 0;
|
||||
};
|
||||
|
||||
template <typename Name, typename StatusType, typename Base>
|
||||
class IEventBlockBaseImpl : public Base
|
||||
{
|
||||
public:
|
||||
typedef IEventBlock Declaration;
|
||||
|
||||
IEventBlockBaseImpl(DoNotInherit = DoNotInherit())
|
||||
{
|
||||
static struct VTableImpl : Base::VTable
|
||||
{
|
||||
VTableImpl()
|
||||
{
|
||||
this->version = Base::VERSION;
|
||||
this->dispose = &Name::cloopdisposeDispatcher;
|
||||
this->getLength = &Name::cloopgetLengthDispatcher;
|
||||
this->getValues = &Name::cloopgetValuesDispatcher;
|
||||
this->getBuffer = &Name::cloopgetBufferDispatcher;
|
||||
this->getCount = &Name::cloopgetCountDispatcher;
|
||||
this->getCounters = &Name::cloopgetCountersDispatcher;
|
||||
this->counts = &Name::cloopcountsDispatcher;
|
||||
}
|
||||
} vTable;
|
||||
|
||||
this->cloopVTable = &vTable;
|
||||
}
|
||||
|
||||
static unsigned CLOOP_CARG cloopgetLengthDispatcher(IEventBlock* self) throw()
|
||||
{
|
||||
try
|
||||
{
|
||||
return static_cast<Name*>(self)->Name::getLength();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
StatusType::catchException(0);
|
||||
return static_cast<unsigned>(0);
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned char* CLOOP_CARG cloopgetValuesDispatcher(IEventBlock* self) throw()
|
||||
{
|
||||
try
|
||||
{
|
||||
return static_cast<Name*>(self)->Name::getValues();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
StatusType::catchException(0);
|
||||
return static_cast<unsigned char*>(0);
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned char* CLOOP_CARG cloopgetBufferDispatcher(IEventBlock* self) throw()
|
||||
{
|
||||
try
|
||||
{
|
||||
return static_cast<Name*>(self)->Name::getBuffer();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
StatusType::catchException(0);
|
||||
return static_cast<unsigned char*>(0);
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned CLOOP_CARG cloopgetCountDispatcher(IEventBlock* self) throw()
|
||||
{
|
||||
try
|
||||
{
|
||||
return static_cast<Name*>(self)->Name::getCount();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
StatusType::catchException(0);
|
||||
return static_cast<unsigned>(0);
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned* CLOOP_CARG cloopgetCountersDispatcher(IEventBlock* self) throw()
|
||||
{
|
||||
try
|
||||
{
|
||||
return static_cast<Name*>(self)->Name::getCounters();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
StatusType::catchException(0);
|
||||
return static_cast<unsigned*>(0);
|
||||
}
|
||||
}
|
||||
|
||||
static void CLOOP_CARG cloopcountsDispatcher(IEventBlock* self) throw()
|
||||
{
|
||||
try
|
||||
{
|
||||
static_cast<Name*>(self)->Name::counts();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
StatusType::catchException(0);
|
||||
}
|
||||
}
|
||||
|
||||
static void CLOOP_CARG cloopdisposeDispatcher(IDisposable* self) throw()
|
||||
{
|
||||
try
|
||||
{
|
||||
static_cast<Name*>(self)->Name::dispose();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
StatusType::catchException(0);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Name, typename StatusType, typename Base = IDisposableImpl<Name, StatusType, Inherit<IVersionedImpl<Name, StatusType, Inherit<IEventBlock> > > > >
|
||||
class IEventBlockImpl : public IEventBlockBaseImpl<Name, StatusType, Base>
|
||||
{
|
||||
protected:
|
||||
IEventBlockImpl(DoNotInherit = DoNotInherit())
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
virtual ~IEventBlockImpl()
|
||||
{
|
||||
}
|
||||
|
||||
virtual unsigned getLength() = 0;
|
||||
virtual unsigned char* getValues() = 0;
|
||||
virtual unsigned char* getBuffer() = 0;
|
||||
virtual unsigned getCount() = 0;
|
||||
virtual unsigned* getCounters() = 0;
|
||||
virtual void counts() = 0;
|
||||
};
|
||||
|
||||
template <typename Name, typename StatusType, typename Base>
|
||||
class IAttachmentBaseImpl : public Base
|
||||
{
|
||||
@ -12297,6 +12512,7 @@ namespace Firebird
|
||||
this->getClientVersion = &Name::cloopgetClientVersionDispatcher;
|
||||
this->getXpbBuilder = &Name::cloopgetXpbBuilderDispatcher;
|
||||
this->setOffsets = &Name::cloopsetOffsetsDispatcher;
|
||||
this->createEventBlock = &Name::cloopcreateEventBlockDispatcher;
|
||||
}
|
||||
} vTable;
|
||||
|
||||
@ -12479,6 +12695,21 @@ namespace Firebird
|
||||
return static_cast<unsigned>(0);
|
||||
}
|
||||
}
|
||||
|
||||
static IEventBlock* CLOOP_CARG cloopcreateEventBlockDispatcher(IUtil* self, IStatus* status, const char** events) throw()
|
||||
{
|
||||
StatusType status2(status);
|
||||
|
||||
try
|
||||
{
|
||||
return static_cast<Name*>(self)->Name::createEventBlock(&status2, events);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
StatusType::catchException(&status2);
|
||||
return static_cast<IEventBlock*>(0);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Name, typename StatusType, typename Base = IVersionedImpl<Name, StatusType, Inherit<IUtil> > >
|
||||
@ -12507,6 +12738,7 @@ namespace Firebird
|
||||
virtual unsigned getClientVersion() = 0;
|
||||
virtual IXpbBuilder* getXpbBuilder(StatusType* status, unsigned kind, const unsigned char* buf, unsigned len) = 0;
|
||||
virtual unsigned setOffsets(StatusType* status, IMessageMetadata* metadata, IOffsetsCallback* callback) = 0;
|
||||
virtual IEventBlock* createEventBlock(StatusType* status, const char** events) = 0;
|
||||
};
|
||||
|
||||
template <typename Name, typename StatusType, typename Base>
|
||||
|
@ -569,6 +569,7 @@ public:
|
||||
unsigned kind, const unsigned char* buf, unsigned len);
|
||||
unsigned setOffsets(Firebird::CheckStatusWrapper* status, Firebird::IMessageMetadata* metadata,
|
||||
Firebird::IOffsetsCallback* callback);
|
||||
Firebird::IEventBlock* createEventBlock(Firebird::CheckStatusWrapper* status, const char** events);
|
||||
};
|
||||
|
||||
} // namespace Why
|
||||
|
@ -1089,6 +1089,113 @@ unsigned UtilInterface::setOffsets(CheckStatusWrapper* status, IMessageMetadata*
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Deal with events
|
||||
class EventBlock FB_FINAL : public DisposeIface<IEventBlockImpl<EventBlock, CheckStatusWrapper> >
|
||||
{
|
||||
public:
|
||||
EventBlock(const char** events)
|
||||
: values(getPool()), buffer(getPool()), counters(getPool())
|
||||
{
|
||||
if (!events[0])
|
||||
{
|
||||
(Arg::Gds(isc_random) << "No events passed as an argument"
|
||||
<< Arg::SqlState("HY024")).raise();
|
||||
// HY024: Invalid attribute value
|
||||
}
|
||||
|
||||
unsigned num = 0;
|
||||
try
|
||||
{
|
||||
values.push(EPB_version1);
|
||||
|
||||
for (const char** e = events; *e; ++e)
|
||||
{
|
||||
++num;
|
||||
|
||||
string ev(*e);
|
||||
ev.rtrim();
|
||||
|
||||
if (ev.length() > 255)
|
||||
{
|
||||
(Arg::Gds(isc_random) << ("Too long event name: " + ev)
|
||||
<< Arg::SqlState("HY024")).raise();
|
||||
// HY024: Invalid attribute value
|
||||
}
|
||||
values.push(ev.length());
|
||||
values.push(reinterpret_cast<const unsigned char*>(ev.begin()), ev.length());
|
||||
values.push(0);
|
||||
values.push(0);
|
||||
values.push(0);
|
||||
values.push(0);
|
||||
}
|
||||
|
||||
// allocate memory for various buffers
|
||||
buffer.getBuffer(values.getCount());
|
||||
counters.getBuffer(num);
|
||||
}
|
||||
catch(const Exception&)
|
||||
{
|
||||
counters.free();
|
||||
buffer.free();
|
||||
values.free();
|
||||
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned getLength()
|
||||
{
|
||||
return values.getCount();
|
||||
}
|
||||
|
||||
unsigned char* getValues()
|
||||
{
|
||||
return values.begin();
|
||||
}
|
||||
|
||||
unsigned char* getBuffer()
|
||||
{
|
||||
return buffer.begin();
|
||||
}
|
||||
|
||||
unsigned getCount()
|
||||
{
|
||||
return counters.getCount();
|
||||
}
|
||||
|
||||
unsigned* getCounters()
|
||||
{
|
||||
return counters.begin();
|
||||
}
|
||||
|
||||
void counts()
|
||||
{
|
||||
isc_event_counts(counters.begin(), values.getCount(), values.begin(), buffer.begin());
|
||||
}
|
||||
|
||||
void dispose()
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
|
||||
private:
|
||||
UCharBuffer values;
|
||||
UCharBuffer buffer;
|
||||
HalfStaticArray<unsigned, 16> counters;
|
||||
};
|
||||
|
||||
IEventBlock* UtilInterface::createEventBlock(CheckStatusWrapper* status, const char** events)
|
||||
{
|
||||
try
|
||||
{
|
||||
return FB_NEW EventBlock(events);
|
||||
}
|
||||
catch (const Exception& ex)
|
||||
{
|
||||
ex.stuffException(status);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Why
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user