PageRenderTime 57ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 1ms

/src/odbc/unittests/blob1.c

https://gitlab.com/xk/FreeTDS
C | 395 lines | 318 code | 70 blank | 7 comment | 82 complexity | 42d95cd4171cbe066cc7cd8051a64a2d MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.0
  1. /* Testing large objects */
  2. /* Test from Sebastien Flaesch */
  3. #include "common.h"
  4. #include <ctype.h>
  5. #include <assert.h>
  6. static char software_version[] = "$Id: blob1.c,v 1.24 2011-07-12 10:16:59 freddy77 Exp $";
  7. static void *no_unused_var_warn[] = { software_version, no_unused_var_warn };
  8. #define NBYTES 10000u
  9. static int failed = 0;
  10. static void
  11. fill_chars(char *buf, size_t len, unsigned int start, unsigned int step)
  12. {
  13. size_t n;
  14. for (n = 0; n < len; ++n)
  15. buf[n] = 'a' + ((start+n) * step % ('z' - 'a' + 1));
  16. }
  17. static void
  18. fill_hex(char *buf, size_t len, unsigned int start, unsigned int step)
  19. {
  20. size_t n;
  21. for (n = 0; n < len; ++n)
  22. sprintf(buf + 2*n, "%2x", (unsigned int)('a' + ((start+n) * step % ('z' - 'a' + 1))));
  23. }
  24. static int
  25. check_chars(const char *buf, size_t len, unsigned int start, unsigned int step)
  26. {
  27. size_t n;
  28. for (n = 0; n < len; ++n)
  29. if (buf[n] != 'a' + ((start+n) * step % ('z' - 'a' + 1)))
  30. return 0;
  31. return 1;
  32. }
  33. static int
  34. check_hex(const char *buf, size_t len, unsigned int start, unsigned int step)
  35. {
  36. size_t n;
  37. char symbol[3];
  38. for (n = 0; n < len; ++n) {
  39. sprintf(symbol, "%2x", (unsigned int)('a' + ((start+n) / 2 * step % ('z' - 'a' + 1))));
  40. if (tolower((unsigned char) buf[n]) != symbol[(start+n) % 2])
  41. return 0;
  42. }
  43. return 1;
  44. }
  45. #define MAX_TESTS 10
  46. typedef struct {
  47. unsigned num;
  48. SQLSMALLINT c_type, sql_type;
  49. const char *db_type;
  50. unsigned gen1, gen2;
  51. SQLLEN vind;
  52. char *buf;
  53. } test_info;
  54. static test_info test_infos[MAX_TESTS];
  55. static unsigned num_tests = 0;
  56. static void
  57. dump(FILE* out, const char* start, void* buf, unsigned len)
  58. {
  59. unsigned n;
  60. char s[17];
  61. if (len >= 16)
  62. len = 16;
  63. fprintf(out, "%s", start);
  64. for (n = 0; n < len; ++n) {
  65. unsigned char c = ((unsigned char*)buf)[n];
  66. fprintf(out, " %02X", c);
  67. s[n] = (c >= 0x20 && c < 127) ? (char) c : '.';
  68. }
  69. s[len] = 0;
  70. fprintf(out, " - %s\n", s);
  71. }
  72. static void
  73. readBlob(test_info *t)
  74. {
  75. SQLRETURN rc;
  76. char buf[4096];
  77. SQLLEN len, total = 0;
  78. int i = 0;
  79. int check;
  80. printf(">> readBlob field %d\n", t->num);
  81. while (1) {
  82. i++;
  83. rc = CHKGetData(t->num, SQL_C_BINARY, (SQLPOINTER) buf, (SQLINTEGER) sizeof(buf), &len, "SINo");
  84. if (rc == SQL_NO_DATA || len <= 0)
  85. break;
  86. if (len > (SQLLEN) sizeof(buf))
  87. len = (SQLLEN) sizeof(buf);
  88. printf(">> step %d: %d bytes readed\n", i, (int) len);
  89. check = check_chars(buf, len, t->gen1 + total, t->gen2);
  90. if (!check) {
  91. fprintf(stderr, "Wrong buffer content\n");
  92. dump(stderr, " buf ", buf, len);
  93. failed = 1;
  94. }
  95. total += len;
  96. }
  97. printf(">> total bytes read = %d \n", (int) total);
  98. if (total != 10000) {
  99. fprintf(stderr, "Wrong buffer length, expected 20000\n");
  100. failed = 1;
  101. }
  102. }
  103. static void
  104. readBlobAsChar(test_info *t, int step, int wide)
  105. {
  106. SQLRETURN rc = SQL_SUCCESS_WITH_INFO;
  107. char buf[8192];
  108. SQLLEN len, total = 0, len2;
  109. int i = 0;
  110. int check;
  111. int bufsize;
  112. SQLSMALLINT type = SQL_C_CHAR;
  113. unsigned int char_len = 1;
  114. if (wide) {
  115. char_len = sizeof(SQLWCHAR);
  116. type = SQL_C_WCHAR;
  117. }
  118. if (step%2) bufsize = sizeof(buf) - char_len;
  119. else bufsize = sizeof(buf);
  120. printf(">> readBlobAsChar field %d\n", t->num);
  121. while (rc == SQL_SUCCESS_WITH_INFO) {
  122. i++;
  123. rc = CHKGetData(t->num, type, (SQLPOINTER) buf, (SQLINTEGER) bufsize, &len, "SINo");
  124. if (rc == SQL_SUCCESS_WITH_INFO && len == SQL_NO_TOTAL) {
  125. len = bufsize - char_len;
  126. rc = SQL_SUCCESS;
  127. }
  128. if (rc == SQL_NO_DATA || len <= 0)
  129. break;
  130. rc = CHKGetData(t->num, type, (SQLPOINTER) buf, 0, &len2, "SINo");
  131. if (rc == SQL_SUCCESS_WITH_INFO && len2 != SQL_NO_TOTAL)
  132. len = len - len2;
  133. #if 0
  134. if (len > (SQLLEN) (bufsize - char_len))
  135. len = (SQLLEN) (bufsize - char_len);
  136. len -= len % (2u * char_len);
  137. #endif
  138. printf(">> step %d: %d bytes readed\n", i, (int) len);
  139. if (wide) {
  140. len /= sizeof(SQLWCHAR);
  141. odbc_from_sqlwchar((char *) buf, (SQLWCHAR *) buf, len + 1);
  142. }
  143. check = check_hex(buf, len, 2*t->gen1 + total, t->gen2);
  144. if (!check) {
  145. fprintf(stderr, "Wrong buffer content\n");
  146. dump(stderr, " buf ", buf, len);
  147. failed = 1;
  148. }
  149. total += len;
  150. }
  151. printf(">> total bytes read = %d \n", (int) total);
  152. if (total != 20000) {
  153. fprintf(stderr, "Wrong buffer length, expected 20000\n");
  154. failed = 1;
  155. }
  156. }
  157. static void
  158. add_test(SQLSMALLINT c_type, SQLSMALLINT sql_type, const char *db_type, unsigned gen1, unsigned gen2)
  159. {
  160. test_info *t = NULL;
  161. size_t buf_len;
  162. if (num_tests >= MAX_TESTS) {
  163. fprintf(stderr, "too max tests\n");
  164. exit(1);
  165. }
  166. t = &test_infos[num_tests++];
  167. t->num = num_tests;
  168. t->c_type = c_type;
  169. t->sql_type = sql_type;
  170. t->db_type = db_type;
  171. t->gen1 = gen1;
  172. t->gen2 = gen2;
  173. t->vind = 0;
  174. switch (c_type) {
  175. case SQL_C_CHAR:
  176. buf_len = NBYTES*2+1;
  177. break;
  178. case SQL_C_WCHAR:
  179. buf_len = (NBYTES*2+1) * sizeof(SQLWCHAR);
  180. break;
  181. default:
  182. buf_len = NBYTES;
  183. }
  184. t->buf = (char*) malloc(buf_len);
  185. if (!t->buf) {
  186. fprintf(stderr, "memory error\n");
  187. exit(1);
  188. }
  189. if (c_type != SQL_C_CHAR && c_type != SQL_C_WCHAR)
  190. fill_chars(t->buf, NBYTES, t->gen1, t->gen2);
  191. else
  192. memset(t->buf, 0, buf_len);
  193. t->vind = SQL_LEN_DATA_AT_EXEC(buf_len);
  194. }
  195. static void
  196. free_tests(void)
  197. {
  198. while (num_tests > 0) {
  199. test_info *t = &test_infos[--num_tests];
  200. free(t->buf);
  201. t->buf = NULL;
  202. }
  203. }
  204. int
  205. main(int argc, char **argv)
  206. {
  207. SQLRETURN RetCode;
  208. SQLHSTMT old_odbc_stmt = SQL_NULL_HSTMT;
  209. int i;
  210. int key;
  211. SQLLEN vind0;
  212. int cnt = 2, wide;
  213. char sql[256];
  214. test_info *t = NULL;
  215. odbc_use_version3 = 1;
  216. odbc_connect();
  217. /* tests (W)CHAR/BINARY -> (W)CHAR/BINARY (9 cases) */
  218. add_test(SQL_C_BINARY, SQL_LONGVARCHAR, "TEXT", 123, 1 );
  219. add_test(SQL_C_BINARY, SQL_LONGVARBINARY, "IMAGE", 987, 25);
  220. add_test(SQL_C_CHAR, SQL_LONGVARBINARY, "IMAGE", 987, 25);
  221. add_test(SQL_C_CHAR, SQL_LONGVARCHAR, "TEXT", 343, 47);
  222. add_test(SQL_C_WCHAR, SQL_LONGVARBINARY, "IMAGE", 561, 29);
  223. add_test(SQL_C_WCHAR, SQL_LONGVARCHAR, "TEXT", 698, 24);
  224. if (odbc_db_is_microsoft()) {
  225. add_test(SQL_C_BINARY, SQL_WLONGVARCHAR, "NTEXT", 765, 12);
  226. add_test(SQL_C_CHAR, SQL_WLONGVARCHAR, "NTEXT", 237, 71);
  227. add_test(SQL_C_WCHAR, SQL_WLONGVARCHAR, "NTEXT", 687, 68);
  228. }
  229. strcpy(sql, "CREATE TABLE #tt(k INT");
  230. for (t = test_infos; t < test_infos+num_tests; ++t)
  231. sprintf(strchr(sql, 0), ",f%u %s", t->num, t->db_type);
  232. strcat(sql, ",v INT)");
  233. odbc_command(sql);
  234. old_odbc_stmt = odbc_stmt;
  235. odbc_stmt = SQL_NULL_HSTMT;
  236. /* Insert rows ... */
  237. for (i = 0; i < cnt; i++) {
  238. /* MS do not save correctly char -> binary */
  239. if (!odbc_driver_is_freetds() && i)
  240. continue;
  241. CHKAllocHandle(SQL_HANDLE_STMT, odbc_conn, &odbc_stmt, "S");
  242. strcpy(sql, "INSERT INTO #tt VALUES(?");
  243. for (t = test_infos; t < test_infos+num_tests; ++t)
  244. strcat(sql, ",?");
  245. strcat(sql, ",?)");
  246. CHKPrepare(T(sql), SQL_NTS, "S");
  247. CHKBindParameter(1, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER, 0, 0, &key, 0, &vind0, "S");
  248. for (t = test_infos; t < test_infos+num_tests; ++t)
  249. CHKBindParameter(t->num+1, SQL_PARAM_INPUT, t->c_type, t->sql_type, 0x10000000, 0, t->buf, 0, &t->vind, "S");
  250. CHKBindParameter(num_tests+2, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER, 0, 0, &key, 0, &vind0, "S");
  251. key = i;
  252. vind0 = 0;
  253. printf(">> insert... %d\n", i);
  254. RetCode = CHKExecute("SINe");
  255. while (RetCode == SQL_NEED_DATA) {
  256. char *p;
  257. RetCode = CHKParamData((SQLPOINTER) & p, "SINe");
  258. printf(">> SQLParamData: ptr = %p RetCode = %d\n", (void *) p, RetCode);
  259. if (RetCode == SQL_NEED_DATA) {
  260. for (t = test_infos; t < test_infos+num_tests && t->buf != p; ++t)
  261. ;
  262. assert(t < test_infos+num_tests);
  263. if (t->c_type == SQL_C_CHAR || t->c_type == SQL_C_WCHAR) {
  264. unsigned char_len = 1;
  265. fill_hex(p, NBYTES, t->gen1, t->gen2);
  266. if (t->c_type == SQL_C_WCHAR) {
  267. char_len = sizeof(SQLWCHAR);
  268. odbc_to_sqlwchar((SQLWCHAR*) p, p, NBYTES * 2);
  269. }
  270. CHKPutData(p, (NBYTES - (i&1)) * char_len, "S");
  271. printf(">> param %p: total bytes written = %d\n", (void *) p, NBYTES - (i&1));
  272. CHKPutData(p + (NBYTES - (i&1)) * char_len, (NBYTES + (i&1)) * char_len, "S");
  273. printf(">> param %p: total bytes written = %d\n", (void *) p, NBYTES + (i&1));
  274. } else {
  275. CHKPutData(p, NBYTES, "S");
  276. printf(">> param %p: total bytes written = %d\n", (void *) p, NBYTES);
  277. }
  278. }
  279. }
  280. CHKFreeHandle(SQL_HANDLE_STMT, (SQLHANDLE) odbc_stmt, "S");
  281. odbc_stmt = SQL_NULL_HSTMT;
  282. }
  283. /* Now fetch rows ... */
  284. for (wide = 0; wide < 2; ++wide)
  285. for (i = 0; i < cnt; i++) {
  286. /* MS do not save correctly char -> binary */
  287. if (!odbc_driver_is_freetds() && i)
  288. continue;
  289. CHKAllocHandle(SQL_HANDLE_STMT, odbc_conn, &odbc_stmt, "S");
  290. if (odbc_db_is_microsoft()) {
  291. CHKSetStmtAttr(SQL_ATTR_CURSOR_SCROLLABLE, (SQLPOINTER) SQL_NONSCROLLABLE, SQL_IS_UINTEGER, "S");
  292. CHKSetStmtAttr(SQL_ATTR_CURSOR_SENSITIVITY, (SQLPOINTER) SQL_SENSITIVE, SQL_IS_UINTEGER, "S");
  293. }
  294. strcpy(sql, "SELECT ");
  295. for (t = test_infos; t < test_infos+num_tests; ++t)
  296. sprintf(strchr(sql, 0), "f%u,", t->num);
  297. strcat(sql, "v FROM #tt WHERE k = ?");
  298. CHKPrepare(T(sql), SQL_NTS, "S");
  299. CHKBindParameter(1, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER, 0, 0, &i, 0, &vind0, "S");
  300. for (t = test_infos; t < test_infos+num_tests; ++t) {
  301. t->vind = SQL_DATA_AT_EXEC;
  302. CHKBindCol(t->num, SQL_C_BINARY, NULL, 0, &t->vind, "S");
  303. }
  304. CHKBindCol(num_tests+1, SQL_C_LONG, &key, 0, &vind0, "S");
  305. vind0 = 0;
  306. CHKExecute("S");
  307. CHKFetchScroll(SQL_FETCH_NEXT, 0, "S");
  308. printf(">> fetch... %d\n", i);
  309. for (t = test_infos; t < test_infos+num_tests; ++t) {
  310. if (t->c_type == SQL_C_CHAR || t->c_type == SQL_C_WCHAR)
  311. readBlobAsChar(t, i, wide);
  312. else
  313. readBlob(t);
  314. }
  315. CHKCloseCursor("S");
  316. CHKFreeHandle(SQL_HANDLE_STMT, (SQLHANDLE) odbc_stmt, "S");
  317. odbc_stmt = SQL_NULL_HSTMT;
  318. }
  319. odbc_stmt = old_odbc_stmt;
  320. free_tests();
  321. odbc_disconnect();
  322. if (!failed)
  323. printf("ok!\n");
  324. return failed ? 1 : 0;
  325. }