| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283 |
- /*
- * PROGRAM: Object oriented API samples.
- * MODULE: 05.user_metadata.cpp
- * DESCRIPTION: A sample of user-implemented IMessageMetadata.
- * Prints firebird user name (SYSDBA by default).
- *
- * Example for the following interfaces:
- *
- * IOffsetsCallback - callback for IUtil::setOffsets()
- * IMessageMetadata - how to implement it yourself
- *
- * 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) 2016 Alexander Peshkoff <[email protected]>
- * and all contributors signed below.
- *
- * All Rights Reserved.
- * Contributor(s): ______________________________________.
- */
- #include "ifaceExamples.h"
- static IMaster* master = fb_get_master_interface();
- /*
- * Trivial sample of IMessageMetadata implementation.
- * Metadata is created for a fixed output format with single char field.
- * Therefore index parameter in all functions is ignored.
- * Because the only possible error is index out of bounds status parameter is ignored too.
- * Atomic operation is not used in IReferenceCounted cause we do not plan MT support.
- * Non-array vars used to represent offset and nullOffset of that single field.
- */
- class MyMetadata : public IMessageMetadataImpl<MyMetadata, ThrowStatusWrapper>
- {
- private:
- class Callback : public IOffsetsCallbackImpl<Callback, ThrowStatusWrapper>
- {
- private:
- MyMetadata* metadata;
- public:
- Callback(MyMetadata* pmeta)
- : metadata(pmeta)
- { }
- //IOffsetsCallback implementation
- void setOffset(ThrowStatusWrapper* status, unsigned /*index*/, unsigned offset, unsigned nullOffset)
- {
- // Typically setOffset() function should save passed offsets
- // in your implementation of message metadata.
- metadata->offset = offset;
- metadata->nullOffset = nullOffset;
- }
- };
- FbSampleAtomic referenceCounter;
- // we are using only single field (varchar) in a sample, therefore no strong alignment requirements.
- // In general message alignment is the maximum field alignment in that message.
- static const unsigned messageAlignment = sizeof(ISC_SHORT);
- public:
- unsigned offset, nullOffset, length;
- MyMetadata()
- : referenceCounter(0)
- {
- IUtil* utl = master->getUtilInterface();
- ThrowStatusWrapper s(master->getStatus());
- try
- {
- Callback cb(this);
- length = utl->setOffsets(&s, this, &cb);
- }
- catch(...)
- {
- s.dispose();
- throw;
- }
- s.dispose();
- }
- void addRef()
- {
- ++referenceCounter;
- }
- int release()
- {
- int rc = --referenceCounter;
- if (!rc)
- delete this;
- return rc;
- }
- // IMessageMetadata implementation
- unsigned getCount(ThrowStatusWrapper* /*status*/)
- {
- return 1;
- }
- const char* getField(ThrowStatusWrapper* /*status*/, unsigned /*index*/)
- {
- return NULL;
- }
- const char* getRelation(ThrowStatusWrapper* /*status*/, unsigned /*index*/)
- {
- return NULL;
- }
- const char* getOwner(ThrowStatusWrapper* /*status*/, unsigned /*index*/)
- {
- return NULL;
- }
- const char* getAlias(ThrowStatusWrapper* /*status*/, unsigned /*index*/)
- {
- return NULL;
- }
- unsigned getType(ThrowStatusWrapper* /*status*/, unsigned /*index*/)
- {
- return SQL_VARYING;
- }
- FB_BOOLEAN isNullable(ThrowStatusWrapper* /*status*/, unsigned /*index*/)
- {
- return false;
- }
- int getSubType(ThrowStatusWrapper* /*status*/, unsigned /*index*/)
- {
- return 0;
- }
- unsigned getLength(ThrowStatusWrapper* /*status*/, unsigned /*index*/)
- {
- return 20; // Want to make it fit
- }
- int getScale(ThrowStatusWrapper* /*status*/, unsigned /*index*/)
- {
- return 0;
- }
- unsigned getCharSet(ThrowStatusWrapper* /*status*/, unsigned /*index*/)
- {
- return 0;
- }
- unsigned getOffset(ThrowStatusWrapper* /*status*/, unsigned /*index*/)
- {
- return offset;
- }
- unsigned getNullOffset(ThrowStatusWrapper* /*status*/, unsigned /*index*/)
- {
- return nullOffset;
- }
- IMetadataBuilder* getBuilder(ThrowStatusWrapper* status)
- {
- ISC_STATUS err[] = {isc_arg_gds, isc_wish_list, isc_arg_end};
- status->setErrors(err);
- return NULL;
- }
- unsigned getMessageLength(ThrowStatusWrapper* /*status*/)
- {
- return length;
- }
- unsigned getAlignment(ThrowStatusWrapper* /*status*/)
- {
- return messageAlignment;
- }
- unsigned getAlignedLength(ThrowStatusWrapper* /*status*/)
- {
- return ((length / messageAlignment) + (length % messageAlignment ? 1 : 0)) * messageAlignment;
- }
- };
- template <typename T>
- T to(const unsigned char* b, unsigned o)
- {
- return *((T*) (b + o));
- }
- int main()
- {
- int rc = 0;
- unsigned char* buffer = NULL;
- // set default password if none specified in environment
- setenv("ISC_USER", "sysdba", 0);
- setenv("ISC_PASSWORD", "masterkey", 0);
- // status vector and main dispatcher
- ThrowStatusWrapper status(master->getStatus());
- IProvider* prov = master->getDispatcher();
- // declare pointers to required interfaces
- IAttachment* att = NULL;
- ITransaction* tra = NULL;
- IResultSet* curs = NULL;
- MyMetadata* meta = NULL;
- try
- {
- // Instance of our metadata
- meta = new MyMetadata;
- meta->addRef();
- // allocate output buffer
- buffer = new unsigned char[meta->length];
- // attach employee db
- att = prov->attachDatabase(&status, "employee", 0, NULL);
- // start default transaction
- tra = att->startTransaction(&status, 0, NULL);
- // open cursor
- curs = att->openCursor(&status, tra, 0, "select current_user from rdb$database",
- SAMPLES_DIALECT, NULL, NULL, meta, NULL, 0);
- // fetch record from cursor and print it
- curs->fetchNext(&status, buffer);
- ISC_SHORT l = to<ISC_SHORT>(buffer, meta->offset);
- printf("<%*.*s>\n", l, l, buffer + meta->offset + sizeof(ISC_SHORT));
- // close interfaces
- curs->close(&status);
- curs = NULL;
- tra->commit(&status);
- tra = NULL;
- att->detach(&status);
- att = NULL;
- }
- catch (const FbException& error)
- {
- // handle error
- rc = 1;
- char buf[256];
- master->getUtilInterface()->formatStatus(buf, sizeof(buf), error.getStatus());
- fprintf(stderr, "%s\n", buf);
- }
- // release interfaces after error caught
- if (curs)
- curs->release();
- if (tra)
- tra->release();
- if (att)
- att->release();
- // generic cleanup
- if (meta)
- meta->release();
- prov->release();
- status.dispose();
- delete[] buffer;
- return rc;
- }
|