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