8
0
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:
Alexander Peshkov 2016-03-28 21:10:01 +03:00
parent f58ecf78b4
commit f92f2a1b09
5 changed files with 380 additions and 19 deletions

View File

@ -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

View File

@ -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

View File

@ -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>

View File

@ -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

View File

@ -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