1 // Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
2 //
3 // This program is free software; you can redistribute it and/or modify
4 // it under the terms of the GNU General Public License, version 2.0, as
5 // published by the Free Software Foundation.
6 //
7 // This program is also distributed with certain software (including
8 // but not limited to OpenSSL) that is licensed under separate terms,
9 // as designated in a particular file or component or in included license
10 // documentation. The authors of MySQL hereby grant you an
11 // additional permission to link the program and your derivative works
12 // with the separately licensed software that they have included with
13 // MySQL.
14 //
15 // Without limiting anything contained in the foregoing, this file,
16 // which is part of <MySQL Product>, is also subject to the
17 // Universal FOSS Exception, version 1.0, a copy of which can be found at
18 // http://oss.oracle.com/licenses/universal-foss-exception.
19 //
20 // This program is distributed in the hope that it will be useful, but
21 // WITHOUT ANY WARRANTY; without even the implied warranty of
22 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
23 // See the GNU General Public License, version 2.0, for more details.
24 //
25 // You should have received a copy of the GNU General Public License
26 // along with this program; if not, write to the Free Software Foundation, Inc.,
27 // 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
28
29 /**
30 @file odbctap.h
31
32 A basic interface for writing tests that produces TAP-compliant output.
33 */
34
35 /* We don't want ansi calls to be mapped to unicode counterparts, but that does not work */
36 /* #define SQL_NOUNICODEMAP 1*/
37
38 #ifdef HAVE_CONFIG_H
39 # include <myconf.h>
40 #endif
41 /* Work around iODBC header bug on Mac OS X 10.3 */
42 #undef HAVE_CONFIG_H
43
44 #include <stdarg.h>
45 #ifdef WIN32
46 # include <windows.h>
47 # define sleep(x) Sleep(x*1000)
48 # include <crtdbg.h>
49 #else
50 # include <unistd.h>
51 # include <signal.h>
52 #endif
53
54 #include <stdio.h>
55 #include <stdlib.h>
56 #include <string.h>
57
58 #ifdef _WIN32
59 /* Driver does that - applications should do that too, to have same size of structures */
60 # ifndef RC_INVOKED
61 # pragma pack(push, 1)
62 # endif
63 #endif
64
65 #include <sql.h>
66 #include <sqlext.h>
67 #include <odbcinst.h>
68
69 #ifdef _WIN32
70 # ifndef RC_INVOKED
71 # pragma pack(pop)
72 # endif
73 #endif
74
75 /* for clock() */
76 #include <time.h>
77
78 /* Get routines for helping with Unicode conversion. */
79 #define ODBCTAP
80
81 #include "mysql_version.h"
82 #include "../util/unicode_transcode.h"
83
84
printMessage(const char * fmt,...)85 void printMessage(const char *fmt, ...)
86 {
87 va_list ap;
88 va_start(ap, fmt);
89 fprintf(stdout, "# ");
90 vfprintf(stdout, fmt, ap);
91 fprintf(stdout, "\n");
92 va_end(ap);
93 }
94
95
96 /* Function that converts wchr_t string to char string for a debug output
97 Minimum guaranteed lenght of string it can convert is 2048/12=170. Stops if its
98 buffer cannot accomodate more characters from parameter string */
wstr4output(const wchar_t * wstr)99 const char * wstr4output(const wchar_t *wstr)
100 {
101 size_t i;
102 static char str[2048];
103 char dbuf[16], *to= str;
104
105 for (i= 0; i < wcslen(wstr); ++i)
106 {
107 if (wstr[i] < 0x7f )
108 {
109 sprintf(dbuf, "%c", wstr[i]);
110 }
111 else
112 {
113 sprintf(dbuf, "[0x%x]", wstr[i]);
114 }
115
116 if (to - str + strlen(dbuf) + 1 < sizeof(str))
117 {
118 to+= sprintf(to, "%s", dbuf);
119 }
120 else
121 {
122 break;
123 }
124 }
125
126 return str;
127 }
128
129 #define MAX_NAME_LEN 255
130 #define MAX_COLUMNS 500
131 #define MAX_ROW_DATA_LEN 1000
132 #define MYSQL_NAME_LEN 64
133 #define MAX_MEM_BLOCK_ELEMENTS 100
134
135 #ifdef __WIN__
136 #define _MY_NEWLINE "\r\n"
137 #else
138 #define _MY_NEWLINE "\n"
139 #endif
140
141 SQLCHAR *mydriver= (SQLCHAR *)"{MySQL ODBC 5.3 Driver}";
142 SQLCHAR *mydsn= (SQLCHAR *)"test";
143 SQLCHAR *myuid= (SQLCHAR *)"root";
144 SQLCHAR *mypwd= (SQLCHAR *)"";
145 SQLCHAR *mysock= NULL;
146 int myoption= 0, myport= 0, myenable_pooling= 0;
147 SQLCHAR *my_str_options= (SQLCHAR *)""; /* String for additional connection options */
148 SQLCHAR *myserver= (SQLCHAR *)"localhost";
149 SQLCHAR *mydb= (SQLCHAR *)"test";
150 SQLCHAR *myauth= NULL;
151 SQLCHAR *myplugindir= NULL;
152
153 SQLCHAR *test_db= (SQLCHAR *)"client_odbc_test";
154 /* Suffix is useful if a testsuite is run more than once */
155 const SQLCHAR *testname_suffix="";
156 /* -1 means that the fact has to be established, 0 - ansi driver, 1 - unicode */
157 int unicode_driver= -1;
158 #define REQUIRES_UNICODE_DRIVER if (unicode_driver == 0) skip("This testcase is designed for Unicode drivers only")
159 #define REQUIRES_ANSI_DRIVER if (unicode_driver != 0) skip("This testcase is designed for ANSI drivers only")
160
161 int init_auth_plugin= 0;
162
163 #ifndef OK
164 # define OK 0
165 #endif
166 #ifndef FAIL
167 # define FAIL 1
168 #endif
169 #ifndef SKIP
170 # define SKIP -1
171 #endif
172 #ifndef FALSE
173 # define FALSE 0
174 #endif
175 #ifndef TRUE
176 # define TRUE 1
177 #endif
178
179 char *SKIP_REASON= NULL;
180
181 #define USE_DRIVER (char *)-1
182
183 typedef int (*test_func)(SQLHDBC, SQLHSTMT, SQLHENV);
184 static void print_diag(SQLRETURN rc, SQLSMALLINT htype, SQLHANDLE handle,
185 const char *text, const char *file, int line);
186
187 /* Disable _attribute__ on non-gcc compilers. */
188 #if !defined(__attribute__) && !defined(__GNUC__)
189 # define __attribute__(arg)
190 #endif
191
192 /*
193 The parameters may be unused. so we add the attribute to stifle warnings.
194 They may also still be used, and no warning will be generated.
195 */
196 #define DECLARE_TEST(name) \
197 int (name)(SQLHDBC hdbc __attribute__((unused)), \
198 SQLHSTMT hstmt __attribute__((unused)), \
199 SQLHENV henv __attribute__((unused)))
200
201 typedef struct {
202 char *name;
203 test_func func;
204 int expect;
205 int required_driver_type;
206 } my_test;
207
208
209 typedef struct
210 {
211 void *blk[MAX_MEM_BLOCK_ELEMENTS];
212 int counter;
213 } GCOLL;
214
215 GCOLL gc_blk;
216
217
218 #ifdef WIN32
219 void test_timeout(int signum);
220 HANDLE halarm= NULL;
win32_alarm(LPVOID arg)221 DWORD WINAPI win32_alarm(LPVOID arg)
222 {
223 unsigned long long llarg = (unsigned long long)arg;
224 DWORD timeout= ((DWORD) llarg) * 1000;
225 while (WaitForSingleObject(halarm, timeout) == WAIT_OBJECT_0);
226 test_timeout(0);
227 return 0;
228 }
229 #define ENABLE_ALARMS int do_alarms= !getenv("DISABLE_TIMEOUT")
230 #define RUN_TESTS_SIGNAL halarm= CreateEvent(NULL, FALSE, FALSE, NULL); \
231 if (do_alarms) \
232 CreateThread(NULL, 0, win32_alarm, (LPVOID) 1200, 0, NULL); \
233 do_alarms= 0
234 #define RUN_TESTS_ALARM (void) SetEvent(halarm)
235 #else
236 #define ENABLE_ALARMS int do_alarms= !getenv("DISABLE_TIMEOUT")
237 #define RUN_TESTS_SIGNAL (void)signal(SIGALRM, test_timeout)
238 #define RUN_TESTS_ALARM if (do_alarms) alarm(1200)
239 #endif
240
mem_debug_init()241 void mem_debug_init()
242 {
243 #ifdef _WIN32
244 int dbg = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
245 dbg |= _CRTDBG_ALLOC_MEM_DF;
246 dbg |= _CRTDBG_CHECK_ALWAYS_DF;
247 dbg |= _CRTDBG_DELAY_FREE_MEM_DF;
248 dbg |= _CRTDBG_LEAK_CHECK_DF;
249 _CrtSetDbgFlag(dbg);
250 #endif
251 }
252
253 /*
254 Initialize garbage collector
255 counter (or position)
256 */
mem_gc_init()257 void mem_gc_init()
258 {
259 gc_blk.counter= 0;
260 }
261
262 #define DECLARE_BASIC_HANDLES(E, C, S) SQLHENV E= NULL; \
263 SQLHDBC C= NULL; \
264 SQLHSTMT S= NULL
265
266 #define BEGIN_TESTS my_test tests[]= {
267 #define ADD_TEST(name) { #name, name, OK , -1 },
268 #define ADD_TEST_UNICODE(name) { #name, name, OK , 1 },
269 #define ADD_TEST_ANSI(name) { #name, name, OK , 0 },
270 #define ADD_TODO(name) { #name, name, FAIL, -1 },
271 #ifdef EXPOSE_TOFIX_TESTS
272 # define ADD_TOFIX(name) { #name, name, OK, -1 },
273 #else
274 # define ADD_TOFIX(name) { #name, name, FAIL, -1 },
275 #endif
276 #define END_TESTS }; \
277 void test_timeout(int signum __attribute__((unused))) \
278 { \
279 printf("Bail out! Timeout.\n"); \
280 exit(1); \
281 } \
282 \
283 int main(int argc, char **argv) \
284 { \
285 SQLHENV henv; \
286 SQLHDBC hdbc; \
287 SQLHSTMT hstmt = NULL; \
288 int i, num_tests, failcnt= 0; \
289 ENABLE_ALARMS; \
290 \
291 mem_debug_init(); \
292 mem_gc_init(); \
293 \
294 /* Set from environment, possibly overrided by command line */ \
295 if (getenv("TEST_DSN")) \
296 mydsn= (SQLCHAR *)getenv("TEST_DSN"); \
297 if (getenv("TEST_DRIVER")) \
298 mydriver= (SQLCHAR *)getenv("TEST_DRIVER"); \
299 if (getenv("TEST_UID")) \
300 myuid= (SQLCHAR *)getenv("TEST_UID"); \
301 if (getenv("TEST_PASSWORD")) \
302 mypwd= (SQLCHAR *)getenv("TEST_PASSWORD"); \
303 if (getenv("TEST_SOCKET")) \
304 mysock= (SQLCHAR *)getenv("TEST_SOCKET"); \
305 if (getenv("TEST_SERVER")) \
306 myserver= (SQLCHAR *)getenv("TEST_SERVER"); \
307 if (getenv("TEST_PORT")) \
308 myport= atoi(getenv("TEST_PORT")); \
309 if (getenv("TEST_ENABLE_POOLING")) \
310 myenable_pooling= atoi(getenv("TEST_ENABLE_POOLING")); \
311 if (getenv("TEST_DEFAULTAUTH")) \
312 myauth= (SQLCHAR *)getenv("TEST_DEFAULTAUTH"); \
313 if (getenv("TEST_PLUGINDIR")) \
314 myplugindir= (SQLCHAR *)getenv("TEST_PLUGINDIR"); \
315 \
316 if (argc > 1) \
317 mydsn= (SQLCHAR *)argv[1]; \
318 if (argc > 2) \
319 myuid= (SQLCHAR *)argv[2]; \
320 if (argc > 3) \
321 mypwd= (SQLCHAR *)argv[3]; \
322 if (argc > 4) \
323 mysock= (SQLCHAR *)argv[4];
324
325 #define SET_DSN_OPTION(x) \
326 myoption= (x);
327
328 #define RUN_TESTS_ONCE \
329 setbuf(stdout, NULL); \
330 num_tests= sizeof(tests) / sizeof(tests[0]); \
331 printf("1..%d\n", num_tests); \
332 \
333 RUN_TESTS_SIGNAL; \
334 \
335 if (alloc_basic_handles(&henv, &hdbc, &hstmt) != OK) \
336 exit(1); \
337 \
338 for (i= 0; i < num_tests; i++ ) \
339 { \
340 int rc; \
341 if (tests[i].required_driver_type > -1 && tests[i].required_driver_type != unicode_driver) \
342 { \
343 printf("ok %d # SKIP This testcase is designed for %s drivers only\n", i+1, \
344 unicode_driver == 0 ? "Unicode" : "ANSI" ); \
345 } \
346 else \
347 { \
348 RUN_TESTS_ALARM; \
349 rc= tests[i].func(hdbc, hstmt, henv); \
350 printf("%s %d - %s%s %s%s\n", \
351 (rc == OK || rc == SKIP) ? "ok" : "not ok", \
352 i + 1, \
353 tests[i].name, testname_suffix, \
354 (tests[i].expect == FAIL ? "# TODO" : \
355 rc == SKIP ? "# SKIP " : ""), \
356 SKIP_REASON ? SKIP_REASON : ""); \
357 if ((rc == FAIL) && (FAIL != tests[i].expect)) \
358 ++failcnt; \
359 SKIP_REASON= NULL; /* Reset SKIP_REASON */ \
360 /* Re-allocate statement to reset all its properties. */ \
361 SQLFreeStmt(hstmt, SQL_DROP); \
362 SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); \
363 /* Freeing allocated memory */ \
364 mem_gc_flush(); \
365 } \
366 }
367
368 #define RUN_TESTS \
369 RUN_TESTS_ONCE \
370 (void)free_basic_handles(&henv, &hdbc, &hstmt); \
371 mem_gc_flush(); \
372 exit(failcnt); \
373 }
374
375
376 /**
377 Skip a test, giving a reason.
378 */
379 #define skip(reason) \
380 do { \
381 SKIP_REASON= reason; \
382 return SKIP; \
383 } while (0)
384
385
386 /**
387 Execute an SQL statement and bail out if the execution does not return
388 SQL_SUCCESS or SQL_SUCCESS_WITH_INFO.
389
390 @param statement Handle for statement object
391 @param query The query to execute
392 */
393 #define ok_sql(statement, query) \
394 do { \
395 SQLRETURN rc= SQLExecDirect((statement), (SQLCHAR *)(query), SQL_NTS); \
396 print_diag(rc, SQL_HANDLE_STMT, (statement), \
397 "SQLExecDirect(" #statement ", \"" query "\", SQL_NTS)",\
398 __FILE__, __LINE__); \
399 if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) \
400 return FAIL; \
401 } while (0)
402
403
404 /**
405 Verify that the result of an SQL statement call matches an expected
406 result, such as SQL_ERROR.
407
408 @param statement Handle for statement object
409 @param query The query to execute
410 @param expect The expected result
411 */
412 #define expect_sql(statement, query, expect) \
413 do { \
414 SQLRETURN rc= SQLExecDirect((statement), (SQLCHAR *)(query), SQL_NTS); \
415 if (rc != (expect)) \
416 { \
417 print_diag(rc, SQL_HANDLE_STMT, (statement), \
418 "SQLExecDirect(" #statement ", \"" query "\", SQL_NTS)",\
419 __FILE__, __LINE__); \
420 printf("# Expected %d, but got %d in %s on line %d\n", expect, rc, \
421 __FILE__, __LINE__); \
422 return FAIL; \
423 } \
424 } while (0)
425
426
427 /**
428 Verify that the results of an ODBC function call on a statement handle was
429 SQL_SUCCESS or SQL_SUCCESS_WITH_INFO.
430
431 @param statement Handle for statement object
432 @param call The function call
433 */
434 #define ok_stmt(statement, call) \
435 do { \
436 SQLRETURN rc= (call); \
437 print_diag(rc, SQL_HANDLE_STMT, (statement), #call, __FILE__, __LINE__); \
438 if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) \
439 return FAIL; \
440 } while (0)
441
442
443 /**
444 Verify that the results of an ODBC function call on a descriptor handle was
445 SQL_SUCCESS or SQL_SUCCESS_WITH_INFO.
446
447 @param desc Handle for descriptor object
448 @param call The function call
449 */
450 #define ok_desc(desc, call) \
451 do { \
452 SQLRETURN rc= (call); \
453 print_diag(rc, SQL_HANDLE_DESC, (desc), #call, __FILE__, __LINE__); \
454 if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) \
455 return FAIL; \
456 } while (0)
457
458
459 /**
460 Verify that the result of an ODBC function call matches an expected
461 result, such as SQL_ERROR or SQL_NO_DATA_FOUND.
462
463 @param hnd Handle for object
464 @param type Type of handle
465 @param call The function call
466 @param expect The expected result
467 */
468 #define expect_odbc(hnd, type, call, expect) \
469 do { \
470 SQLRETURN rc= (call); \
471 if (rc != (expect)) \
472 { \
473 print_diag(rc, (type), (hnd), #call, __FILE__, __LINE__); \
474 printf("# Expected %d, but got %d in %s on line %d\n", (expect), rc, \
475 __FILE__, __LINE__); \
476 return FAIL; \
477 } \
478 } while (0)
479
480
481 #define expect_env(env, call, expect) \
482 expect_odbc((env), SQL_HANDLE_STMT, (call), (expect))
483
484
485 #define expect_dbc(dbc, call, expect) \
486 expect_odbc((dbc), SQL_HANDLE_STMT, (call), (expect))
487
488
489 #define expect_stmt(statement, call, expect) \
490 expect_odbc((statement), SQL_HANDLE_STMT, (call), (expect))
491
492
493 #define expect_desc(desc, call, expect) \
494 expect_odbc((desc), SQL_HANDLE_DESC, (call), (expect))
495
496
497 /**
498 Verify that the results of an ODBC function call on an environment handle
499 was SQL_SUCCESS or SQL_SUCCESS_WITH_INFO.
500
501 @param environ Handle for environment
502 @param call The function call
503 */
504 #define ok_env(environ, call) \
505 do { \
506 SQLRETURN rc= (call); \
507 print_diag(rc, SQL_HANDLE_ENV, (environ), #call, __FILE__, __LINE__); \
508 if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) \
509 return FAIL; \
510 } while (0)
511
512
513 /**
514 Verify that the results of an ODBC function call on a connection handle
515 was SQL_SUCCESS or SQL_SUCCESS_WITH_INFO.
516
517 @param con Handle for database connection
518 @param call The function call
519 */
520 #define ok_con(con, call) \
521 do { \
522 SQLRETURN rc= (call); \
523 print_diag(rc, SQL_HANDLE_DBC, (con), #call, __FILE__, __LINE__); \
524 if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) \
525 return FAIL; \
526 } while (0)
527
528
529 /**
530 Verify that the results of an ODBC function call on an environment handle
531 was SQL_SUCCESS or SQL_SUCCESS_WITH_INFO.
532
533 @param call The function call
534 */
535 #define ok_install(call) \
536 do { \
537 BOOL rc= (call); \
538 print_diag_installer(rc, #call, __FILE__, __LINE__); \
539 if (!rc) \
540 return FAIL; \
541 } while (0)
542
543
544 /**
545 Verify that a Boolean expression is true.
546 It's recommended to use is_num, is_str, etc macros instead of "is(a==b)",
547 since those will show values being compared, in a log.
548
549 @param a The expression to check
550 */
551 #define is(a) \
552 do { \
553 if (!(a)) { \
554 printf("# !(%s) in %s on line %d\n", \
555 #a, __FILE__, __LINE__); \
556 return FAIL; \
557 } \
558 } while (0);
559
560
561 #define myassert(a) is(a)
562 #define my_assert(a) is(a)
563
564
565 /**
566 Verify that a string (char *) matches an expected value.
567
568 @param a The string to compare
569 @param b The string to compare against
570 @param c The number of characters to compare
571 */
572 #define is_str(a, b, c) \
573 do { \
574 char *val_a= (char *)(a), *val_b= (char *)(b); \
575 int val_len= (int)(c); \
576 if (strncmp(val_a, val_b, val_len) != 0) { \
577 printf("# %s ('%*s') != '%*s' in %s on line %d\n", \
578 #a, val_len, val_a, val_len, val_b, __FILE__, __LINE__); \
579 return FAIL; \
580 } \
581 } while (0);
582
583
584 /**
585 Verify that a wide string (wchar_t *) matches an expected value.
586
587 @param a The string to compare
588 @param b The string to compare against
589 @param c The number of characters to compare
590 */
591 #define is_wstr(a, b, c) \
592 do { \
593 wchar_t *val_a= (a), *val_b= (b); \
594 int val_len= (int)(c); \
595 if (memcmp(val_a, val_b, val_len * sizeof(wchar_t)) != 0) { \
596 printf("# %s ('%*ls') != '%*ls' in %s on line %d\n", \
597 #a, val_len, val_a, val_len, val_b, __FILE__, __LINE__); \
598 return FAIL; \
599 } \
600 } while (0);
601
602
603 /**
604 Verify that a number (long integer) matches an expected value.
605
606 @param a The number to compare
607 @param b The number to compare against
608 */
609 #define is_num(a, b) \
610 do { \
611 long long a1= (a), a2= (b); \
612 if (a1 != a2) { \
613 printf("# %s (%lld) != %lld in %s on line %d\n", \
614 #a, a1, a2, __FILE__, __LINE__); \
615 return FAIL; \
616 } \
617 } while (0)
618
619
620 /* convenience macro for using statement */
621 #define check_sqlstate(stmt, sqlstate) \
622 check_sqlstate_ex((stmt), SQL_HANDLE_STMT, (sqlstate))
623
624
check_sqlstate_ex(SQLHANDLE hnd,SQLSMALLINT hndtype,char * sqlstate)625 int check_sqlstate_ex(SQLHANDLE hnd, SQLSMALLINT hndtype, char *sqlstate)
626 {
627 SQLCHAR sql_state[6];
628 SQLINTEGER err_code= 0;
629 SQLCHAR err_msg[SQL_MAX_MESSAGE_LENGTH]= {0};
630 SQLSMALLINT err_len= 0;
631
632 memset(err_msg, 'C', SQL_MAX_MESSAGE_LENGTH);
633 SQLGetDiagRec(hndtype, hnd, 1, sql_state, &err_code, err_msg,
634 SQL_MAX_MESSAGE_LENGTH - 1, &err_len);
635
636 is_str(sql_state, (SQLCHAR *)sqlstate, 5);
637
638 return OK;
639 }
640
641
642 /**
643 Print error and diagnostic information for ODBC API functions that did not
644 finish with SQL_SUCCESS(_WITH_INFO) result
645 */
print_diag(SQLRETURN rc,SQLSMALLINT htype,SQLHANDLE handle,const char * text,const char * file,int line)646 static void print_diag(SQLRETURN rc, SQLSMALLINT htype, SQLHANDLE handle,
647 const char *text, const char *file, int line)
648 {
649 if (rc != SQL_SUCCESS)
650 {
651 SQLCHAR sqlstate[6], message[SQL_MAX_MESSAGE_LENGTH];
652 SQLINTEGER native_error;
653 SQLSMALLINT length;
654 SQLRETURN drc;
655
656 /** @todo map rc to SQL_SUCCESS_WITH_INFO, etc */
657 printf("# %s = %d\n", text, rc);
658
659 /** @todo Handle multiple diagnostic records. */
660 drc= SQLGetDiagRec(htype, handle, 1, sqlstate, &native_error,
661 message, SQL_MAX_MESSAGE_LENGTH - 1, &length);
662
663 if (SQL_SUCCEEDED(drc))
664 printf("# [%6s] %*s in %s on line %d\n",
665 sqlstate, length, message, file, line);
666 else
667 printf("# Did not get expected diagnostics from SQLGetDiagRec() = %d"
668 " in file %s on line %d\n", drc, file, line);
669 }
670 }
671
672
673 /**
674 Print error and diagnostic information for ODBC INSTALLER API functions
675 that did not return TRUE (1)
676 */
print_diag_installer(BOOL is_success,const char * text,const char * file,int line)677 static void print_diag_installer(BOOL is_success, const char *text,
678 const char *file, int line)
679 {
680 if (!is_success)
681 {
682 SQLCHAR message[SQL_MAX_MESSAGE_LENGTH];
683 SQLINTEGER error_code;
684 SQLSMALLINT length;
685 SQLRETURN drc;
686
687 drc= SQLInstallerError(1, &error_code, message, SQL_MAX_MESSAGE_LENGTH - 1, &length);
688
689 if (SQL_SUCCEEDED(drc))
690 printf("# [%s] %s in %s on line %d\n",
691 text, message, file, line);
692 else
693 printf("# Did not get expected diagnostics from SQLInstallerError() = %d"
694 " in file %s on line %d\n", drc, file, line);
695 }
696 }
697
698
699 /* UTILITY MACROS */
700 #define myenv(henv,r) \
701 do { \
702 print_diag(r, SQL_HANDLE_ENV, (henv), "myenv(henv,r)", \
703 __FILE__, __LINE__); \
704 if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) \
705 return FAIL; \
706 } while (0)
707
708 #define myenv_r(henv,r) \
709 do { \
710 print_diag(r, SQL_HANDLE_ENV, (henv), "myenv(henv_r,r)", \
711 __FILE__, __LINE__); \
712 if (r != SQL_ERROR) \
713 return FAIL; \
714 } while (0)
715
716 #define myenv_err(henv,r,rc) \
717 do { \
718 print_diag(rc, SQL_HANDLE_ENV, (henv), "myenv_err(henv,r)",\
719 __FILE__, __LINE__); \
720 if (!r) \
721 return FAIL; \
722 } while (0)
723
724 #define mycon(hdbc,r) \
725 do { \
726 print_diag(r, SQL_HANDLE_DBC, (hdbc), "mycon(hdbc,r)", \
727 __FILE__, __LINE__); \
728 if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) \
729 return FAIL; \
730 } while (0)
731
732 #define mycon_r(hdbc,r) \
733 do { \
734 print_diag(r, SQL_HANDLE_DBC, (hdbc), "mycon_r(hdbc,r)", \
735 __FILE__, __LINE__); \
736 if (r != SQL_ERROR) \
737 return FAIL; \
738 } while (0)
739
740 #define mycon_err(hdbc,r,rc) \
741 do { \
742 print_diag(rc, SQL_HANDLE_DBC, (hdbc), "mycon_err(hdbc,r)", \
743 __FILE__, __LINE__); \
744 if (!r) \
745 return FAIL; \
746 } while (0)
747
748 #define mystmt(hstmt,r) \
749 do { \
750 print_diag(r, SQL_HANDLE_STMT, (hstmt), "mystmt(hstmt,r)", \
751 __FILE__, __LINE__); \
752 if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) \
753 return FAIL; \
754 } while (0)
755
756 #define mystmt_r(hstmt,r) \
757 do { \
758 print_diag(r, SQL_HANDLE_STMT, (hstmt), "mystmt_r(hstmt,r)", \
759 __FILE__, __LINE__); \
760 if (r != SQL_ERROR) \
761 return FAIL; \
762 } while (0)
763
764 #define mystmt_err(hstmt,r,rc) \
765 do { \
766 print_diag(rc, SQL_HANDLE_STMT, (hstmt), "mystmt_err(hstmt,r)", \
767 __FILE__, __LINE__); \
768 if (!r) \
769 return FAIL; \
770 } while (0)
771
772
773 /**
774 Print resultset dashes
775 */
my_print_dashes(SQLHSTMT hstmt,SQLSMALLINT nCol)776 static int my_print_dashes(SQLHSTMT hstmt, SQLSMALLINT nCol)
777 {
778 SQLLEN disp_size, nullable;
779 SQLCHAR ColName[MAX_NAME_LEN+1];
780 SQLUSMALLINT field_count, i, j;
781 SQLSMALLINT col_len;
782
783 field_count= (SQLUSMALLINT)nCol;
784 fprintf(stdout, "# ");
785 fprintf(stdout, "+");
786
787 for (i=1; i<= field_count; i++)
788 {
789 nullable = 0;
790 ok_stmt(hstmt, SQLColAttribute(hstmt, i, SQL_DESC_BASE_COLUMN_NAME,
791 &ColName, MAX_NAME_LEN, &col_len, NULL));
792 ok_stmt(hstmt, SQLColAttribute(hstmt, i, SQL_DESC_DISPLAY_SIZE,
793 NULL, 0, NULL, &disp_size));
794 ok_stmt(hstmt, SQLColAttribute(hstmt, i, SQL_DESC_NULLABLE,
795 NULL, 0, NULL, &nullable));
796
797 if (disp_size < col_len)
798 disp_size = col_len;
799 if (disp_size < 4 && nullable)
800 disp_size = 4;
801 /*
802 We cap disp_size to avoid problems when we have problems with
803 it being very large, such as 64-bit issues in the driver.
804 */
805 disp_size= (disp_size > 512) ? 512 : disp_size;
806 for (j=1; j < disp_size+3; j++)
807 fprintf(stdout, "-");
808 fprintf(stdout, "+");
809 }
810 fprintf(stdout, "\n");
811
812 return OK;
813 }
814
815
my_print_data(SQLHSTMT hstmt,SQLUSMALLINT index,SQLCHAR * data,SQLLEN length)816 static int my_print_data(SQLHSTMT hstmt, SQLUSMALLINT index,
817 SQLCHAR *data, SQLLEN length)
818 {
819 SQLLEN disp_size, nullable= 0;
820 SQLCHAR ColName[MAX_NAME_LEN+1];
821 SQLSMALLINT col_len;
822
823 nullable= 0;
824 ok_stmt(hstmt, SQLColAttribute(hstmt, index, SQL_DESC_BASE_COLUMN_NAME,
825 &ColName, MAX_NAME_LEN, &col_len, NULL));
826 ok_stmt(hstmt, SQLColAttribute(hstmt, index, SQL_DESC_DISPLAY_SIZE,
827 NULL, 0, NULL, &disp_size));
828 ok_stmt(hstmt, SQLColAttribute(hstmt, index, SQL_DESC_NULLABLE,
829 NULL, 0, NULL, &nullable));
830
831 if (disp_size < length)
832 disp_size = length;
833 if (disp_size < col_len)
834 disp_size = col_len;
835 if (disp_size < 4 && nullable)
836 disp_size = 4;
837 /*
838 We cap disp_size to avoid problems when we have problems with
839 it being very large, such as 64-bit issues in the driver.
840 */
841 disp_size= (disp_size > 512) ? 512 : disp_size;
842 if (length == SQL_NULL_DATA)
843 fprintf(stdout, "%-*s |", (int)disp_size, "NULL");
844 else
845 fprintf(stdout, "%-*s |", (int)disp_size, data);
846
847 return OK;
848 }
849
850
851 /* If we just return FAIL from my_print_non_format_result - it will
852 considered as 1 row by caller */
853 #define mystmt_rows(hstmt,r, row) \
854 do { \
855 print_diag(r, SQL_HANDLE_STMT, (hstmt), "mystmt_row(hstmt,r,row)", \
856 __FILE__, __LINE__); \
857 if (!SQL_SUCCEEDED(r)) \
858 return row; \
859 } while (0)
860 /**
861 RESULT SET
862 */
my_print_non_format_result(SQLHSTMT hstmt)863 int my_print_non_format_result(SQLHSTMT hstmt)
864 {
865 SQLRETURN rc;
866 SQLUINTEGER nRowCount=0;
867 SQLULEN pcColDef;
868 SQLCHAR szColName[MAX_NAME_LEN+1];
869 SQLCHAR szData[MAX_COLUMNS][MAX_ROW_DATA_LEN]={{0}};
870 SQLSMALLINT nIndex,ncol= 0,pfSqlType, pcbScale, pfNullable;
871 SQLLEN ind_strlen;
872
873 rc = SQLNumResultCols(hstmt,&ncol);
874
875 mystmt_rows(hstmt,rc,-1);
876
877 for (nIndex = 1; nIndex <= ncol; ++nIndex)
878 {
879 rc = SQLDescribeCol(hstmt,nIndex,szColName, MAX_NAME_LEN, NULL,
880 &pfSqlType,&pcColDef,&pcbScale,&pfNullable);
881 /* Returning in case of an error -nIndex we will see in the log column# */
882 mystmt_rows(hstmt,rc,-nIndex);
883
884
885 fprintf(stdout, "%s\t", szColName);
886
887 rc = SQLBindCol(hstmt,nIndex, SQL_C_CHAR, szData[nIndex-1],
888 MAX_ROW_DATA_LEN+1,&ind_strlen);
889 mystmt_rows(hstmt,rc,-nIndex);
890 }
891
892 fprintf(stdout,"\n");
893
894 rc = SQLFetch(hstmt);
895 while (SQL_SUCCEEDED(rc))
896 {
897 ++nRowCount;
898 for (nIndex=0; nIndex< ncol; ++nIndex)
899 fprintf(stdout, "%s\t", szData[nIndex]);
900
901 fprintf(stdout, "\n");
902 rc = SQLFetch(hstmt);
903 }
904
905 SQLFreeStmt(hstmt,SQL_UNBIND);
906 SQLFreeStmt(hstmt,SQL_CLOSE);
907
908 fprintf(stdout, "# Total rows fetched: %d\n", (int)nRowCount);
909
910 return nRowCount;
911 }
912
913 /**
914 RESULT SET
915 */
myresult(SQLHSTMT hstmt)916 SQLINTEGER myresult(SQLHSTMT hstmt)
917 {
918 SQLRETURN rc;
919 SQLUINTEGER nRowCount;
920 SQLCHAR ColName[MAX_NAME_LEN+1];
921 SQLCHAR Data[MAX_ROW_DATA_LEN+1];
922 SQLLEN pcbLength;
923 SQLUSMALLINT nIndex;
924 SQLSMALLINT ncol;
925
926 rc = SQLNumResultCols(hstmt,&ncol);
927 mystmt(hstmt,rc);
928
929 if (ncol > 10)
930 return my_print_non_format_result(hstmt);
931
932 if (my_print_dashes(hstmt, ncol) != OK)
933 return -1;
934 fprintf(stdout, "# |");
935
936 for (nIndex = 1; nIndex <= ncol; ++nIndex)
937 {
938 ok_stmt(hstmt, SQLColAttribute(hstmt, nIndex, SQL_DESC_BASE_COLUMN_NAME,
939 ColName, MAX_NAME_LEN, NULL, NULL));
940 if (my_print_data(hstmt, nIndex, ColName, 0) != OK)
941 return -1;
942 }
943 fprintf(stdout, "\n");
944 if (my_print_dashes(hstmt, ncol) != OK)
945 return -1;
946
947 nRowCount= 0;
948
949 rc = SQLFetch(hstmt);
950 while (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO)
951 {
952 nRowCount++;
953 fprintf(stdout, "# |");
954
955 for (nIndex=1; nIndex<= ncol; ++nIndex)
956 {
957 rc = SQLGetData(hstmt, nIndex, SQL_C_CHAR, Data,
958 MAX_ROW_DATA_LEN,&pcbLength);
959 mystmt(hstmt,rc);
960 if (my_print_data(hstmt, nIndex, Data, pcbLength) != OK)
961 return -1;
962 }
963 fprintf(stdout,"\n");
964 rc = SQLFetch(hstmt);
965 }
966 if (my_print_dashes(hstmt, ncol) != OK)
967 return -1;
968 SQLFreeStmt(hstmt,SQL_UNBIND);
969 SQLFreeStmt(hstmt,SQL_CLOSE);
970
971 fprintf(stdout, "# Total rows fetched: %d\n", (int)nRowCount);
972 return nRowCount;
973 }
974
975 /**
976 ROWCOUNT
977 */
myrowcount(SQLHSTMT hstmt)978 SQLUINTEGER myrowcount(SQLHSTMT hstmt)
979 {
980 SQLRETURN rc;
981 SQLUINTEGER nRowCount= 0;
982
983 rc = SQLFetch(hstmt);
984 while (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO)
985 {
986 ++nRowCount;
987 rc = SQLFetch(hstmt);
988 }
989 SQLFreeStmt(hstmt,SQL_UNBIND);
990 fprintf(stdout, "# Total rows fetched: %d\n", (int)nRowCount);
991 return(nRowCount);
992 }
993 /**
994 SQLExecDirect
995 */
tmysql_exec(SQLHSTMT hstmt,char * sql_stmt)996 SQLRETURN tmysql_exec(SQLHSTMT hstmt, char *sql_stmt)
997 {
998 return(SQLExecDirect(hstmt,(SQLCHAR *)sql_stmt,SQL_NTS));
999 }
1000 /**
1001 SQLPrepare
1002 */
tmysql_prepare(SQLHSTMT hstmt,char * sql_stmt)1003 SQLRETURN tmysql_prepare(SQLHSTMT hstmt, char *sql_stmt)
1004 {
1005 return(SQLPrepare(hstmt, (SQLCHAR *)sql_stmt, SQL_NTS));
1006 }
1007
1008
1009 /**
1010 return integer data by fetching it
1011 */
my_fetch_int(SQLHSTMT hstmt,SQLUSMALLINT icol)1012 SQLINTEGER my_fetch_int(SQLHSTMT hstmt, SQLUSMALLINT icol)
1013 {
1014 SQLINTEGER nData;
1015 SQLLEN len;
1016
1017 SQLGetData(hstmt, icol, SQL_INTEGER, &nData, 0, &len);
1018 if (len == SQL_NULL_DATA)
1019 {
1020 printMessage("my_fetch_int: NULL");
1021 }
1022 else
1023 {
1024 printMessage("my_fetch_int: %ld (%ld)", (long int)nData, len);
1025 return nData;
1026 }
1027 return 0;
1028 }
1029
1030
1031 /**
1032 return unsigned integer data by fetching it
1033 */
my_fetch_uint(SQLHSTMT hstmt,SQLUSMALLINT icol)1034 SQLUINTEGER my_fetch_uint(SQLHSTMT hstmt, SQLUSMALLINT icol)
1035 {
1036 SQLUINTEGER nData;
1037 SQLLEN len;
1038
1039 SQLGetData(hstmt, icol, SQL_C_ULONG, &nData, 0, &len);
1040 printMessage("my_fetch_int: %ld (%ld)", (long int)nData, len);
1041 return (len != SQL_NULL_DATA) ? nData : 0;
1042 }
1043
1044
1045 /**
1046 return string data, by fetching it
1047 */
my_fetch_str(SQLHSTMT hstmt,SQLCHAR * szData,SQLUSMALLINT icol)1048 const char *my_fetch_str(SQLHSTMT hstmt, SQLCHAR *szData,SQLUSMALLINT icol)
1049 {
1050 SQLLEN nLen;
1051
1052 SQLGetData(hstmt,icol,SQL_CHAR,szData,MAX_ROW_DATA_LEN+1,&nLen);
1053 /* If Null value - putting down smth meaningful. also that allows caller to
1054 better/(in more easy way) test the value */
1055 if (nLen < 0)
1056 {
1057 strcpy(szData, "(Null)");
1058 }
1059 printMessage(" my_fetch_str: %s(%ld)", szData, nLen);
1060 return((const char *)szData);
1061 }
1062
1063
1064 /**
1065 Convert a SQLWCHAR to wchar_t
1066 */
sqlwchar_to_wchar_t(SQLWCHAR * in)1067 wchar_t *sqlwchar_to_wchar_t(SQLWCHAR *in)
1068 {
1069 static wchar_t buff[2048];
1070 wchar_t *to= buff;
1071
1072 if (sizeof(wchar_t) == sizeof(SQLWCHAR))
1073 return (wchar_t *)in;
1074
1075 for ( ; *in && to < buff + sizeof(buff) - 2; in++)
1076 to+= utf16toutf32((UTF16 *)in, (UTF32 *)to);
1077
1078 *to= L'\0';
1079
1080 return buff;
1081 }
1082
1083
1084 /**
1085 return wide string data, by fetching it and possibly converting it to wchar_t
1086 */
my_fetch_wstr(SQLHSTMT hstmt,SQLWCHAR * buffer,SQLUSMALLINT icol)1087 wchar_t *my_fetch_wstr(SQLHSTMT hstmt, SQLWCHAR *buffer, SQLUSMALLINT icol)
1088 {
1089 SQLRETURN rc;
1090 SQLLEN nLen;
1091
1092 rc= SQLGetData(hstmt, icol, SQL_WCHAR, buffer, MAX_ROW_DATA_LEN + 1, &nLen);
1093 if (!SQL_SUCCEEDED(rc))
1094 return L"";
1095
1096 buffer[nLen/sizeof(SQLWCHAR)]= 0;
1097
1098 return sqlwchar_to_wchar_t(buffer);
1099 }
1100
1101
1102 /*
1103 Check if driver supports SQLSetPos
1104 */
driver_supports_setpos(SQLHDBC hdbc)1105 int driver_supports_setpos(SQLHDBC hdbc)
1106 {
1107 SQLRETURN rc;
1108 SQLUSMALLINT status= TRUE;
1109
1110 rc = SQLGetFunctions(hdbc, SQL_API_SQLSETPOS, &status);
1111 mycon(hdbc,rc);
1112
1113 if (!status)
1114 return FALSE;
1115 return TRUE;
1116 }
1117
1118 /*
1119 Check for minimal MySQL version
1120 */
mysql_min_version(SQLHDBC hdbc,char * min_version,unsigned int length)1121 int mysql_min_version(SQLHDBC hdbc, char *min_version, unsigned int length)
1122 {
1123 SQLCHAR server_version[MYSQL_NAME_LEN+1];
1124 SQLRETURN rc;
1125
1126 rc = SQLGetInfo(hdbc,SQL_DBMS_VER,server_version,MYSQL_NAME_LEN,NULL);
1127 mycon(hdbc, rc);
1128
1129 {
1130 unsigned int major1= 0, major2= 0, minor1= 0, minor2= 0, build1= 0, build2= 0;
1131
1132 sscanf(server_version, "%u.%u.%u", &major1, &minor1, &build1);
1133 sscanf(min_version, "%u.%u.%u", &major2, &minor2, &build2);
1134
1135 if ( major1 > major2 ||
1136 major1 == major2 && (minor1 > minor2 ||
1137 minor1 == minor2 && build1 >= build2))
1138 {
1139 return TRUE;
1140 }
1141 }
1142
1143 return FALSE;;
1144 }
1145
1146 /*
1147 Check if server supports transactions
1148 */
server_supports_trans(SQLHDBC hdbc)1149 int server_supports_trans(SQLHDBC hdbc)
1150 {
1151 SQLSMALLINT trans;
1152 SQLRETURN rc;
1153
1154 rc = SQLGetInfo(hdbc,SQL_TXN_CAPABLE,&trans,0,NULL);
1155 mycon(hdbc,rc);
1156
1157 if (trans != SQL_TC_NONE)
1158 return TRUE;
1159 return FALSE;
1160 }
1161
1162
1163 /**
1164 DRV CONNECTION
1165 */
mydrvconnect(SQLHENV * henv,SQLHDBC * hdbc,SQLHSTMT * hstmt,SQLCHAR * connIn)1166 int mydrvconnect(SQLHENV *henv, SQLHDBC *hdbc, SQLHSTMT *hstmt, SQLCHAR *connIn)
1167 {
1168 SQLCHAR connOut[MAX_NAME_LEN+1];
1169 SQLSMALLINT len;
1170
1171 ok_env(*henv, SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, henv));
1172
1173 ok_env(*henv, SQLSetEnvAttr(*henv, SQL_ATTR_ODBC_VERSION,
1174 (SQLPOINTER)SQL_OV_ODBC3, 0));
1175
1176 ok_env(*henv, SQLAllocHandle(SQL_HANDLE_DBC, *henv, hdbc));
1177
1178 ok_con(*hdbc, SQLDriverConnect(*hdbc, NULL, connIn, SQL_NTS, connOut,
1179 MAX_NAME_LEN, &len, SQL_DRIVER_NOPROMPT));
1180
1181 ok_con(*hdbc, SQLSetConnectAttr(*hdbc, SQL_ATTR_AUTOCOMMIT,
1182 (SQLPOINTER)SQL_AUTOCOMMIT_ON, 0));
1183
1184 ok_con(*hdbc, SQLAllocHandle(SQL_HANDLE_STMT, *hdbc, hstmt));
1185
1186 return OK;
1187 }
1188
1189
1190 /* Helper function for tests to get (additional) connection
1191 If dsn, uid, pwd or options is null - they defualt to mydsn, myuid, mypwd
1192 and my_str_options, respectively.
1193 myoption, mysock and myport values are used. */
get_connection(SQLHDBC * hdbc,const SQLCHAR * dsn,const SQLCHAR * uid,const SQLCHAR * pwd,const SQLCHAR * db,const SQLCHAR * options)1194 int get_connection(SQLHDBC *hdbc, const SQLCHAR *dsn, const SQLCHAR *uid,
1195 const SQLCHAR *pwd, const SQLCHAR *db,
1196 const SQLCHAR *options)
1197 {
1198 /* Buffers have to be large enough to contain SSL options and long names */
1199 SQLCHAR connIn[4096], connOut[4096];
1200 SQLCHAR dsn_buf[MAX_NAME_LEN]= {0}, socket_buf[MAX_NAME_LEN]= {0};
1201 /* ";database="+ we make buffer bigger for one certain test */
1202 SQLCHAR db_buf[4096]= {0};
1203 /* Should fit 8 byte + ";port=" */
1204 SQLCHAR port_buf[32]= {0};
1205 SQLSMALLINT len;
1206 SQLRETURN rc;
1207 SQLCHAR driver_name[16]; /* Should be enough for myodbc library file name */
1208
1209 /* We never set the custom DSN, but sometimes use DRIVER instead */
1210 if (dsn == NULL)
1211 sprintf((char *)dsn_buf, "DSN=%s", (char *)mydsn);
1212 else if (dsn == USE_DRIVER)
1213 sprintf((char *)dsn_buf, "DRIVER=%s", (char *)mydriver);
1214 else
1215 sprintf((char *)dsn_buf, "DSN=%s", (char *)dsn);
1216
1217 /* We never set the custom DSN, but sometimes use DRIVER instead */
1218 if (dsn == NULL)
1219 sprintf((char *)dsn_buf, "DSN=%s", (char *)mydsn);
1220 else if (dsn == USE_DRIVER)
1221 sprintf((char *)dsn_buf, "DRIVER=%s", (char *)mydriver);
1222 else
1223 sprintf((char *)dsn_buf, "DSN=%s", (char *)dsn);
1224
1225 /* Defaults */
1226 if (uid == NULL) uid= myuid;
1227 if (pwd == NULL) pwd= mypwd;
1228 if (db == NULL) db= mydb;
1229 if (options == NULL) options= my_str_options;
1230
1231 sprintf((char *)connIn, "%s;UID=%s;PWD=%s;OPTION=%d",
1232 (char *)dsn_buf, (char *)uid, (char *)pwd, myoption);
1233
1234 if (mysock && mysock[0])
1235 {
1236 sprintf((char *)socket_buf, ";SOCKET=%s", (char *)mysock);
1237 strcat((char *)connIn, socket_buf);
1238 }
1239 if (db && db[0])
1240 {
1241 sprintf((char *)db_buf, ";DATABASE=%s", (char *)db);
1242 strcat((char *)connIn, (char *)db_buf);
1243 }
1244 if (myport)
1245 {
1246 sprintf(port_buf, ";PORT=%d", myport);
1247 strcat((char *)connIn, port_buf);
1248 }
1249
1250 if (options != NULL && options[0] > 0)
1251 {
1252 strcat(connIn, ";");
1253 strcat(connIn, options);
1254 }
1255
1256 #if MYSQL_VERSION_ID >= 50507
1257 if (init_auth_plugin)
1258 {
1259 init_auth_plugin= 0; /* reset the plugin init flag */
1260 if (myauth && myauth[0])
1261 {
1262 strcat((char *)connIn, ";DEFAULTAUTH=");
1263 strcat((char *)connIn, (char *)myauth);
1264 }
1265 if (myplugindir && myplugindir[0])
1266 {
1267 strcat((char *)connIn, ";PLUGINDIR=");
1268 strcat((char *)connIn, (char *)myplugindir);
1269 }
1270 }
1271 #endif
1272
1273 rc= SQLDriverConnect(*hdbc, NULL, connIn, SQL_NTS, connOut,
1274 MAX_NAME_LEN, &len, SQL_DRIVER_NOPROMPT);
1275
1276 if (!SQL_SUCCEEDED(rc))
1277 {
1278 /* re-build and print the connection string with hidden password */
1279 printf("# Connection failed with the following Connection string: " \
1280 "\n%s;UID=%s;PWD=*******%s%s%s;%s\n",
1281 dsn_buf, uid, socket_buf, db_buf, port_buf, options);
1282 return rc;
1283 }
1284
1285 /* Let's neglect possibility that error returned by get_connection() can be
1286 in fact error of turning autocommit on */
1287 rc= SQLSetConnectAttr(*hdbc, SQL_ATTR_AUTOCOMMIT,
1288 (SQLPOINTER)SQL_AUTOCOMMIT_ON, 0);
1289 if (!SQL_SUCCEEDED(rc))
1290 {
1291 return rc;
1292 }
1293
1294 if (unicode_driver < 0)
1295 {
1296 rc= SQLGetInfo(*hdbc, SQL_DRIVER_NAME, driver_name, sizeof(driver_name), NULL);
1297
1298 if (SQL_SUCCEEDED(rc))
1299 {
1300 /* ANSI driver file name contains 5a.{dll|so} */
1301 unicode_driver= strstr((char*)driver_name, "a.") == NULL ? 1 : 0;
1302 }
1303 }
1304
1305 return rc;
1306 }
1307
1308
alloc_basic_handles_with_opt(SQLHENV * henv,SQLHDBC * hdbc,SQLHSTMT * hstmt,const SQLCHAR * dsn,const SQLCHAR * uid,const SQLCHAR * pwd,const SQLCHAR * db,const SQLCHAR * options)1309 int alloc_basic_handles_with_opt(SQLHENV *henv, SQLHDBC *hdbc,
1310 SQLHSTMT *hstmt, const SQLCHAR *dsn,
1311 const SQLCHAR *uid, const SQLCHAR *pwd,
1312 const SQLCHAR *db, const SQLCHAR *options)
1313 {
1314 if (myenable_pooling)
1315 {
1316 SQLSetEnvAttr(NULL, SQL_ATTR_CONNECTION_POOLING,
1317 (SQLPOINTER)SQL_CP_ONE_PER_DRIVER, 0);
1318 }
1319
1320 ok_env(*henv, SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, henv));
1321
1322 ok_env(*henv, SQLSetEnvAttr(*henv, SQL_ATTR_ODBC_VERSION,
1323 (SQLPOINTER)SQL_OV_ODBC3, 0));
1324 if (myenable_pooling)
1325 {
1326 SQLRETURN rc= SQLSetEnvAttr(*henv, SQL_ATTR_CP_MATCH, (SQLPOINTER)SQL_CP_STRICT_MATCH, 0);
1327
1328 if( !SQL_SUCCEEDED(rc))
1329 {
1330 /* No DM case? */
1331 is_num(check_sqlstate_ex(*henv, SQL_HANDLE_ENV, "HYC00"), OK);
1332 }
1333 }
1334
1335 ok_env(*henv, SQLAllocHandle(SQL_HANDLE_DBC, *henv, hdbc));
1336
1337 /* ok_con(*hdbc, SQLConnect(*hdbc, mydsn, strlen(mydsn), myuid, strlen(myuid), mypwd, strlen(mypwd))); */
1338 ok_con(*hdbc, get_connection(hdbc, dsn, uid, pwd, db, options));
1339
1340 ok_con(*hdbc, SQLAllocHandle(SQL_HANDLE_STMT, *hdbc, hstmt));
1341
1342 return OK;
1343 }
1344
1345
alloc_basic_handles(SQLHENV * henv,SQLHDBC * hdbc,SQLHSTMT * hstmt)1346 int alloc_basic_handles(SQLHENV *henv, SQLHDBC *hdbc, SQLHSTMT *hstmt)
1347 {
1348 return alloc_basic_handles_with_opt(henv, hdbc, hstmt, (SQLCHAR *)mydsn,
1349 (SQLCHAR *)myuid, (SQLCHAR *)mypwd,
1350 (SQLCHAR *)mydb,
1351 (SQLCHAR *)my_str_options);
1352 }
1353
1354
free_basic_handles(SQLHENV * henv,SQLHDBC * hdbc,SQLHSTMT * hstmt)1355 int free_basic_handles(SQLHENV *henv,SQLHDBC *hdbc, SQLHSTMT *hstmt)
1356 {
1357 /* We don't care if this succeeds, the connection may have gone away. */
1358 (void)SQLEndTran(SQL_HANDLE_DBC, *hdbc, SQL_COMMIT);
1359
1360 if(hstmt && *hstmt)
1361 {
1362 ok_stmt(*hstmt, SQLFreeStmt(*hstmt, SQL_DROP));
1363 }
1364
1365 if(hdbc && *hdbc)
1366 {
1367 ok_con(*hdbc, SQLDisconnect(*hdbc));
1368 ok_con(*hdbc, SQLFreeConnect(*hdbc));
1369 }
1370
1371 if(henv && *henv)
1372 {
1373 ok_env(*henv, SQLFreeEnv(*henv));
1374 }
1375
1376 return OK;
1377 }
1378
1379
1380 /*
1381 Allocate size bytes and return a pointer
1382 to allocated memory with storing in
1383 garbage collector
1384 */
gc_alloc(size_t len)1385 void *gc_alloc(size_t len)
1386 {
1387 if (gc_blk.counter >= MAX_MEM_BLOCK_ELEMENTS || len <= 0)
1388 {
1389 printf("# GC Memory reached maximum limit counter: %d " \
1390 "or length:%d less then equal to 0 in %s on line %d\n",
1391 gc_blk.counter, (int)len, __FILE__, __LINE__); \
1392 return NULL;
1393 }
1394
1395 gc_blk.blk[gc_blk.counter]= malloc(len);
1396 return gc_blk.blk[gc_blk.counter++];
1397 }
1398
1399
1400 /*
1401 Free allocated memory collected by
1402 garbage collector
1403 */
mem_gc_flush()1404 int mem_gc_flush()
1405 {
1406 int i= 0;
1407 if (gc_blk.counter <= 0)
1408 {
1409 return FAIL;
1410 }
1411
1412 while (i < gc_blk.counter)
1413 {
1414 free(gc_blk.blk[i]);
1415 gc_blk.blk[i++]= 0;
1416 }
1417
1418 return OK;
1419 }
1420
1421
1422 /**
1423 Helper for possibly converting a (wchar_t *) to a (SQLWCHAR *).
1424 TODO: [almost?] all uses of those macros in tests lead to memore leak,
1425 as resulting pointer is not remembered and thus memory never freed
1426 */
1427 #define W(string) dup_wchar_t_as_sqlwchar((string), \
1428 sizeof(string) / sizeof(wchar_t))
1429 #define WL(string, len) dup_wchar_t_as_sqlwchar((string), (len))
1430
1431
1432 /**
1433 Convert a wchar_t * to a SQLWCHAR * if a wchar_t is not the same as
1434 SQLWCHAR. New space is allocated and never freed. Because this is used in
1435 short-lived test programs, this is okay, if not ideal.
1436 */
dup_wchar_t_as_sqlwchar(wchar_t * from,size_t len)1437 SQLWCHAR *dup_wchar_t_as_sqlwchar(wchar_t *from, size_t len)
1438 {
1439 if (sizeof(wchar_t) == sizeof(SQLWCHAR))
1440 {
1441 SQLWCHAR *to= gc_alloc(len * sizeof(SQLWCHAR));
1442 memcpy(to, from, len * sizeof(wchar_t));
1443 return to;
1444 }
1445 else
1446 {
1447 size_t i;
1448 SQLWCHAR *to= gc_alloc(2 * len * sizeof(SQLWCHAR));
1449 SQLWCHAR *out= to;
1450 for (i= 0; i < len; i++)
1451 to+= utf32toutf16((UTF32)from[i], (UTF16 *)to);
1452 *to= 0;
1453 return out;
1454 }
1455 }
1456
1457
1458 /**
1459 Helper for converting a (char *) to a (SQLWCHAR *)
1460 */
1461 #define WC(string) dup_char_as_sqlwchar((string))
1462
1463
1464 /**
1465 Convert a char * to a SQLWCHAR *. New space is allocated and never freed.
1466 Because this is used in short-lived test programs, this is okay, if not
1467 ideal.
1468 */
dup_char_as_sqlwchar(SQLCHAR * from)1469 SQLWCHAR *dup_char_as_sqlwchar(SQLCHAR *from)
1470 {
1471 SQLWCHAR *to= gc_alloc((strlen((char *)from) + 1) * sizeof(SQLWCHAR));
1472 SQLWCHAR *out= to;
1473 while (from && *from)
1474 *(to++)= (SQLWCHAR)*(from++);
1475 *to= 0;
1476 return out;
1477 }
1478
1479
1480 /**
1481 Check if we are using a driver manager for testing.
1482
1483 @param[in] hdbc Connection handle
1484
1485 @return 0 if the connection is using a driver manager, 1 if not.
1486 */
using_dm(HDBC hdbc)1487 int using_dm(HDBC hdbc)
1488 {
1489 SQLCHAR val[20];
1490 SQLSMALLINT len;
1491
1492 if (SQLGetInfo(hdbc, SQL_DM_VER, val, sizeof(val), &len) == SQL_ERROR)
1493 return 0;
1494
1495 return 1;
1496 }
1497
1498 /*
1499 Check if we are using the unixODBC version specified
1500 */
using_unixodbc_version(SQLHANDLE henv,SQLCHAR * ver)1501 int using_unixodbc_version(SQLHANDLE henv, SQLCHAR *ver)
1502 {
1503 #ifdef SQL_ATTR_UNIXODBC_VERSION
1504 SQLCHAR buf[10];
1505 if(SQLGetEnvAttr(henv, SQL_ATTR_UNIXODBC_VERSION, buf, 10, NULL) != SQL_SUCCESS)
1506 return 0;
1507 if(!strcmp(buf, ver))
1508 return 1;
1509 #endif /* SQL_ATTR_UNIXODBC_VERSION */
1510 return 0;
1511 }
1512