04.print_table.cpp 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. /*
  2. * PROGRAM: Object oriented API samples.
  3. * MODULE: 04.print_table.cpp
  4. * DESCRIPTION: Run SELECT statement without parameters.
  5. * Use attachment method to open cursor.
  6. * Print all fields for selected records in a table.
  7. * Learns how to access blob data and use unprepared statement.
  8. *
  9. * Example for the following interfaces:
  10. *
  11. * IAttachment - database attachment
  12. * IMessageMetadata - describe input and output data format
  13. * IResultSet - fetch data returned by statement after execution
  14. *
  15. * The contents of this file are subject to the Initial
  16. * Developer's Public License Version 1.0 (the "License");
  17. * you may not use this file except in compliance with the
  18. * License. You may obtain a copy of the License at
  19. * http://www.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl.
  20. *
  21. * Software distributed under the License is distributed AS IS,
  22. * WITHOUT WARRANTY OF ANY KIND, either express or implied.
  23. * See the License for the specific language governing rights
  24. * and limitations under the License.
  25. *
  26. * The Original Code was created by Alexander Peshkoff
  27. * for the Firebird Open Source RDBMS project.
  28. *
  29. * Copyright (c) 2013 Alexander Peshkoff <[email protected]>
  30. * and all contributors signed below.
  31. *
  32. * All Rights Reserved.
  33. * Contributor(s): ______________________________________.
  34. */
  35. #include "ifaceExamples.h"
  36. static IMaster* master = fb_get_master_interface();
  37. struct MyField
  38. {
  39. const char* name;
  40. unsigned type, length, offset, null;
  41. void print(ThrowStatusWrapper* st, IAttachment* att, ITransaction* tra, unsigned char* buf);
  42. };
  43. int main()
  44. {
  45. int rc = 0;
  46. char s[100];
  47. setenv("ISC_USER", "sysdba", 0);
  48. setenv("ISC_PASSWORD", "masterkey", 0);
  49. ThrowStatusWrapper status(master->getStatus());
  50. IProvider* prov = master->getDispatcher();
  51. IAttachment* att = NULL;
  52. ITransaction* tra = NULL;
  53. IResultSet* curs = NULL;
  54. IMessageMetadata* meta = NULL;
  55. try
  56. {
  57. att = prov->attachDatabase(&status, "employee", 0, NULL);
  58. tra = att->startTransaction(&status, 0, NULL);
  59. // If we are not going to run same SELECT query many times we may do not prepare it,
  60. // opening cursor instead with single API call.
  61. // If statement has input parameters and we know them, appropriate IMetadata may be
  62. // constructed and passed to openCursor() together with data buffer.
  63. // We also may provide out format info and coerce data passing appropriate metadata
  64. // into API call.
  65. // In this sample we have no input parameters and do not coerce anything - just
  66. // print what we get from SQL query.
  67. const char* sql = "select * from rdb$relations where RDB$RELATION_ID < 3 "
  68. "or RDB$VIEW_SOURCE is not null";
  69. // Do not use IStatement - just ask attachment to open cursor
  70. curs = att->openCursor(&status, tra, 0, sql, SAMPLES_DIALECT, NULL, NULL, NULL, NULL, 0);
  71. meta = curs->getMetadata(&status);
  72. unsigned cols = meta->getCount(&status);
  73. MyField* fields = new MyField[cols];
  74. memset(fields, 0, sizeof(MyField) * cols);
  75. unsigned f = 0;
  76. for (unsigned j = 0; j < cols; ++j)
  77. {
  78. unsigned t = meta->getType(&status, j) & ~1;
  79. unsigned sub = meta->getSubType(&status, j);
  80. switch (t)
  81. {
  82. case SQL_BLOB:
  83. if (sub != 1)
  84. continue;
  85. break;
  86. case SQL_TEXT:
  87. case SQL_VARYING:
  88. case SQL_SHORT:
  89. case SQL_DOUBLE:
  90. break;
  91. default:
  92. {
  93. sprintf(s, "Unknown type %d for %s", t, meta->getField(&status, j));
  94. throw s;
  95. }
  96. continue;
  97. }
  98. // we can work with this field - cache metadata info for fast access
  99. fields[f].type = t;
  100. fields[f].name = meta->getField(&status, j);
  101. fields[f].length = meta->getLength(&status, j);
  102. fields[f].offset = meta->getOffset(&status, j);
  103. fields[f].null = meta->getNullOffset(&status, j);
  104. ++f;
  105. }
  106. unsigned l = meta->getMessageLength(&status);
  107. unsigned char* buffer = new unsigned char[l];
  108. // fetch records from cursor
  109. while (curs->fetchNext(&status, buffer) == IStatus::RESULT_OK)
  110. {
  111. for (unsigned j = 0; j < f; ++j)
  112. {
  113. // call field's function to print it
  114. fields[j].print(&status, att, tra, buffer);
  115. }
  116. printf("\n");
  117. }
  118. curs->close(&status);
  119. curs = NULL;
  120. meta->release();
  121. meta = NULL;
  122. tra->commit(&status);
  123. tra = NULL;
  124. att->detach(&status);
  125. att = NULL;
  126. }
  127. catch (const FbException& error)
  128. {
  129. // handle error
  130. fflush(stdout);
  131. rc = 1;
  132. char buf[256];
  133. master->getUtilInterface()->formatStatus(buf, sizeof(buf), error.getStatus());
  134. fprintf(stderr, "%s\n", buf);
  135. }
  136. if (meta)
  137. meta->release();
  138. if (curs)
  139. curs->release();
  140. if (tra)
  141. tra->release();
  142. if (att)
  143. att->release();
  144. prov->release();
  145. status.dispose();
  146. return rc;
  147. }
  148. template <typename T>
  149. T as(unsigned char* ptr)
  150. {
  151. return *((T*) ptr);
  152. }
  153. void MyField::print(ThrowStatusWrapper* st, IAttachment* att, ITransaction* tra, unsigned char* buf)
  154. {
  155. printf("%s: ", name);
  156. if (as<short>(buf + null))
  157. {
  158. printf("<Null>\n");
  159. return;
  160. }
  161. // IBlob makes it possible to read/write BLOB data
  162. IBlob* blob = NULL;
  163. switch (type)
  164. {
  165. // text fields
  166. case SQL_TEXT:
  167. printf("%*.*s\n", length, length, buf + offset);
  168. break;
  169. case SQL_VARYING:
  170. {
  171. unsigned l = as<short>(buf + offset);
  172. printf("%*.*s\n", l, l, buf + offset + sizeof(short));
  173. }
  174. break;
  175. // numeric fields
  176. case SQL_SHORT:
  177. printf("%d\n", as<short>(buf + offset));
  178. break;
  179. case SQL_DOUBLE:
  180. printf("%f\n", as<double>(buf + offset));
  181. break;
  182. // blob requires more handling in DB
  183. case SQL_BLOB:
  184. try
  185. {
  186. // use attachment's method to access BLOB object
  187. blob = att->openBlob(st, tra, (ISC_QUAD*) (buf + offset), 0, NULL);
  188. char segbuf[16];
  189. unsigned len;
  190. // read data segment by segment
  191. for (;;)
  192. {
  193. int cc = blob->getSegment(st, sizeof(segbuf), segbuf, &len);
  194. if (cc != IStatus::RESULT_OK && cc != IStatus::RESULT_SEGMENT)
  195. break;
  196. fwrite(segbuf, sizeof(char), len, stdout);
  197. }
  198. // close BLOB after receiving all data
  199. blob->close(st);
  200. blob = NULL;
  201. printf("\n");
  202. }
  203. catch (...)
  204. {
  205. if (blob)
  206. blob->release();
  207. throw;
  208. }
  209. break;
  210. // do not plan to have all types here
  211. default:
  212. throw "Unknown type in MyField::print()";
  213. }
  214. }