05.user_metadata.cpp 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. /*
  2. * PROGRAM: Object oriented API samples.
  3. * MODULE: 05.user_metadata.cpp
  4. * DESCRIPTION: A sample of user-implemented IMessageMetadata.
  5. * Prints firebird user name (SYSDBA by default).
  6. *
  7. * Example for the following interfaces:
  8. *
  9. * IOffsetsCallback - callback for IUtil::setOffsets()
  10. * IMessageMetadata - how to implement it yourself
  11. *
  12. * The contents of this file are subject to the Initial
  13. * Developer's Public License Version 1.0 (the "License");
  14. * you may not use this file except in compliance with the
  15. * License. You may obtain a copy of the License at
  16. * http://www.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl.
  17. *
  18. * Software distributed under the License is distributed AS IS,
  19. * WITHOUT WARRANTY OF ANY KIND, either express or implied.
  20. * See the License for the specific language governing rights
  21. * and limitations under the License.
  22. *
  23. * The Original Code was created by Alexander Peshkoff
  24. * for the Firebird Open Source RDBMS project.
  25. *
  26. * Copyright (c) 2016 Alexander Peshkoff <[email protected]>
  27. * and all contributors signed below.
  28. *
  29. * All Rights Reserved.
  30. * Contributor(s): ______________________________________.
  31. */
  32. #include "ifaceExamples.h"
  33. #include <atomic>
  34. static IMaster* master = fb_get_master_interface();
  35. /*
  36. * Trivial sample of IMessageMetadata implementation.
  37. * Metadata is created for a fixed output format with single char field.
  38. * Therefore index parameter in all functions is ignored.
  39. * Because the only possible error is index out of bounds status parameter is ignored too.
  40. * Atomic operation is not used in IReferenceCounted cause we do not plan MT support.
  41. * Non-array vars used to represent offset and nullOffset of that single field.
  42. */
  43. class MyMetadata : public IMessageMetadataImpl<MyMetadata, ThrowStatusWrapper>
  44. {
  45. private:
  46. class Callback : public IOffsetsCallbackImpl<Callback, ThrowStatusWrapper>
  47. {
  48. private:
  49. MyMetadata* metadata;
  50. public:
  51. Callback(MyMetadata* pmeta)
  52. : metadata(pmeta)
  53. { }
  54. //IOffsetsCallback implementation
  55. void setOffset(ThrowStatusWrapper* status, unsigned /*index*/, unsigned offset, unsigned nullOffset)
  56. {
  57. // Typically setOffset() function should save passed offsets
  58. // in your implementation of message metadata.
  59. metadata->offset = offset;
  60. metadata->nullOffset = nullOffset;
  61. }
  62. };
  63. std::atomic_int referenceCounter;
  64. // we are using only single field (varchar) in a sample, therefore no strong alignment requirements.
  65. // In general message alignment is the maximum field alignment in that message.
  66. static const unsigned messageAlignment = sizeof(ISC_SHORT);
  67. public:
  68. unsigned offset, nullOffset, length;
  69. MyMetadata()
  70. : referenceCounter(0)
  71. {
  72. IUtil* utl = master->getUtilInterface();
  73. ThrowStatusWrapper s(master->getStatus());
  74. try
  75. {
  76. Callback cb(this);
  77. length = utl->setOffsets(&s, this, &cb);
  78. }
  79. catch(...)
  80. {
  81. s.dispose();
  82. throw;
  83. }
  84. s.dispose();
  85. }
  86. void addRef()
  87. {
  88. ++referenceCounter;
  89. }
  90. int release()
  91. {
  92. int rc = --referenceCounter;
  93. if (!rc)
  94. delete this;
  95. return rc;
  96. }
  97. // IMessageMetadata implementation
  98. unsigned getCount(ThrowStatusWrapper* /*status*/)
  99. {
  100. return 1;
  101. }
  102. const char* getField(ThrowStatusWrapper* /*status*/, unsigned /*index*/)
  103. {
  104. return NULL;
  105. }
  106. const char* getRelation(ThrowStatusWrapper* /*status*/, unsigned /*index*/)
  107. {
  108. return NULL;
  109. }
  110. const char* getOwner(ThrowStatusWrapper* /*status*/, unsigned /*index*/)
  111. {
  112. return NULL;
  113. }
  114. const char* getAlias(ThrowStatusWrapper* /*status*/, unsigned /*index*/)
  115. {
  116. return NULL;
  117. }
  118. unsigned getType(ThrowStatusWrapper* /*status*/, unsigned /*index*/)
  119. {
  120. return SQL_VARYING;
  121. }
  122. FB_BOOLEAN isNullable(ThrowStatusWrapper* /*status*/, unsigned /*index*/)
  123. {
  124. return false;
  125. }
  126. int getSubType(ThrowStatusWrapper* /*status*/, unsigned /*index*/)
  127. {
  128. return 0;
  129. }
  130. unsigned getLength(ThrowStatusWrapper* /*status*/, unsigned /*index*/)
  131. {
  132. return 20; // Want to make it fit
  133. }
  134. int getScale(ThrowStatusWrapper* /*status*/, unsigned /*index*/)
  135. {
  136. return 0;
  137. }
  138. unsigned getCharSet(ThrowStatusWrapper* /*status*/, unsigned /*index*/)
  139. {
  140. return 0;
  141. }
  142. unsigned getOffset(ThrowStatusWrapper* /*status*/, unsigned /*index*/)
  143. {
  144. return offset;
  145. }
  146. unsigned getNullOffset(ThrowStatusWrapper* /*status*/, unsigned /*index*/)
  147. {
  148. return nullOffset;
  149. }
  150. IMetadataBuilder* getBuilder(ThrowStatusWrapper* status)
  151. {
  152. ISC_STATUS err[] = {isc_arg_gds, isc_wish_list, isc_arg_end};
  153. status->setErrors(err);
  154. return NULL;
  155. }
  156. unsigned getMessageLength(ThrowStatusWrapper* /*status*/)
  157. {
  158. return length;
  159. }
  160. unsigned getAlignment(ThrowStatusWrapper* /*status*/)
  161. {
  162. return messageAlignment;
  163. }
  164. unsigned getAlignedLength(ThrowStatusWrapper* /*status*/)
  165. {
  166. return ((length / messageAlignment) + (length % messageAlignment ? 1 : 0)) * messageAlignment;
  167. }
  168. };
  169. template <typename T>
  170. T to(const unsigned char* b, unsigned o)
  171. {
  172. return *((T*) (b + o));
  173. }
  174. int main()
  175. {
  176. int rc = 0;
  177. unsigned char* buffer = NULL;
  178. // set default password if none specified in environment
  179. setenv("ISC_USER", "sysdba", 0);
  180. setenv("ISC_PASSWORD", "masterkey", 0);
  181. // status vector and main dispatcher
  182. ThrowStatusWrapper status(master->getStatus());
  183. IProvider* prov = master->getDispatcher();
  184. // declare pointers to required interfaces
  185. IAttachment* att = NULL;
  186. ITransaction* tra = NULL;
  187. IResultSet* curs = NULL;
  188. MyMetadata* meta = NULL;
  189. try
  190. {
  191. // Instance of our metadata
  192. meta = new MyMetadata;
  193. meta->addRef();
  194. // allocate output buffer
  195. buffer = new unsigned char[meta->length];
  196. // attach employee db
  197. att = prov->attachDatabase(&status, "employee", 0, NULL);
  198. // start default transaction
  199. tra = att->startTransaction(&status, 0, NULL);
  200. // open cursor
  201. curs = att->openCursor(&status, tra, 0, "select current_user from rdb$database",
  202. SAMPLES_DIALECT, NULL, NULL, meta, NULL, 0);
  203. // fetch record from cursor and print it
  204. curs->fetchNext(&status, buffer);
  205. ISC_SHORT l = to<ISC_SHORT>(buffer, meta->offset);
  206. printf("<%*.*s>\n", l, l, buffer + meta->offset + sizeof(ISC_SHORT));
  207. // close interfaces
  208. curs->close(&status);
  209. curs = NULL;
  210. tra->commit(&status);
  211. tra = NULL;
  212. att->detach(&status);
  213. att = NULL;
  214. }
  215. catch (const FbException& error)
  216. {
  217. // handle error
  218. rc = 1;
  219. char buf[256];
  220. master->getUtilInterface()->formatStatus(buf, sizeof(buf), error.getStatus());
  221. fprintf(stderr, "%s\n", buf);
  222. }
  223. // release interfaces after error caught
  224. if (curs)
  225. curs->release();
  226. if (tra)
  227. tra->release();
  228. if (att)
  229. att->release();
  230. // generic cleanup
  231. if (meta)
  232. meta->release();
  233. prov->release();
  234. status.dispose();
  235. delete[] buffer;
  236. return rc;
  237. }