LCOV - code coverage report
Current view: top level - src/odbc/unittests - common.c (source / functions) Hit Total Coverage
Test: FreeTDS coverage Lines: 284 461 61.6 %
Date: 2026-03-24 22:22:09 Functions: 35 38 92.1 %

          Line data    Source code
       1             : #include "common.h"
       2             : 
       3             : #include <stdarg.h>
       4             : #include <assert.h>
       5             : #include <ctype.h>
       6             : 
       7             : #ifdef __VMS
       8             : #include <unixlib.h>
       9             : #endif
      10             : 
      11             : #if HAVE_SYS_SOCKET_H
      12             : #include <sys/socket.h>
      13             : #endif /* HAVE_SYS_SOCKET_H */
      14             : 
      15             : #if HAVE_SYS_STAT_H
      16             : #include <sys/stat.h>
      17             : #endif /* HAVE_SYS_STAT_H */
      18             : 
      19             : #if HAVE_NETINET_IN_H
      20             : #include <netinet/in.h>
      21             : #endif /* HAVE_NETINET_IN_H */
      22             : 
      23             : #if defined(UNIXODBC) || defined(_WIN32)
      24             : #include <odbcinst.h>
      25             : #endif
      26             : 
      27             : #include <odbcss.h>
      28             : #include <freetds/sysdep_private.h>
      29             : #include <freetds/replacements.h>
      30             : 
      31             : struct odbc_buf{
      32             :         struct odbc_buf *next;
      33             :         void *buf;
      34             : };
      35             : 
      36             : HENV odbc_env;
      37             : HDBC odbc_conn;
      38             : HSTMT odbc_stmt;
      39             : bool odbc_use_version3 = false;
      40             : void (*odbc_set_conn_attr)(void) = NULL;
      41             : const char *odbc_conn_additional_params = NULL;
      42             : 
      43             : static int freetds_driver = -1;
      44             : static int tds_version = -1;
      45             : static char db_str_version[32];
      46             : 
      47             : static bool
      48        1136 : check_lib(char *path, const char *file)
      49             : {
      50        1136 :         size_t len = strlen(path);
      51             :         FILE *f;
      52             : 
      53        1136 :         strcat(path, file);
      54        1136 :         f = fopen(path, "rb");
      55        1136 :         if (f) {
      56        1136 :                 fclose(f);
      57        1136 :                 return true;
      58             :         }
      59           0 :         path[len] = 0;
      60           0 :         return false;
      61             : }
      62             : 
      63             : /* this should be extended with all possible systems... */
      64             : static const char *const search_driver[] = {
      65             :         ".libs/libtdsodbc.so",
      66             :         ".libs/libtdsodbc.sl",
      67             :         ".libs/libtdsodbc.dylib",
      68             :         ".libs/libtdsodbc.dll",
      69             :         "_libs/libtdsodbc.dll",
      70             :         "_libs/libtdsodbc.exe",       /* VMS */
      71             :         "debug/tdsodbc.dll",
      72             :         "release/tdsodbc.dll",
      73             :         "libtdsodbc.so",
      74             :         "tdsodbc.dll",
      75             :         NULL
      76             : };
      77             : 
      78             : int
      79        1136 : odbc_read_login_info(void)
      80             : {
      81        1136 :         const char *PWD = DEFAULT_PWD_PATH;
      82             : #if !defined(_WIN32) || defined(TDS_NO_DM)
      83        1136 :         FILE *in = NULL;
      84             : #endif
      85             :         char *s1;
      86             :         const char *const *search_p;
      87             :         char path[1024];
      88             :         size_t len;
      89        1136 :         bool ini_override = true;
      90             : #if defined(_WIN32) && !defined(TDS_NO_DM)
      91             :         UWORD old_config_mode;
      92             : #endif
      93             : 
      94        1136 :         setbuf(stdout, NULL);
      95        1136 :         setbuf(stderr, NULL);
      96             : 
      97        1136 :         PWD = try_read_login_info_base(&common_pwd, PWD);
      98        1136 :         if (!PWD && !read_login_info_base(&common_pwd, "PWD"))
      99             :                 return 1;
     100             : 
     101             :         /*
     102             :          * Some of the ODBC tests "go in the front door", i.e. call
     103             :          * SQLDriverConnect() which will look up an entry in ODBCINST.INI .
     104             :          * In "connect" and "timeout3" they look up the entry FreeTDS.
     105             :          * However your system ODBCINST.INI probably doesn't point to
     106             :          * the driver we just built and are trying to test.
     107             :          *
     108             :          * So here we are finding the ODBC driver we just built and saving it
     109             :          * into a custom field common_pwd.driver, and those tests have code to
     110             :          * build a dummy ODBCINST.INI with an entry called FreeTDS and using
     111             :          * common_pwd.driver sa the driver.
     112             :          */
     113             : #ifndef _WIN32
     114        1136 :         if (!getcwd(path, sizeof(path)))
     115             : #else
     116             :         if (!_getcwd(path, sizeof(path)))
     117             : #endif
     118             :                 return 0;
     119             : #ifdef __VMS
     120             :         {
     121             :                 /* A hard-coded driver path has to be in unix syntax to be recognized as such. */
     122             :                 const char *unixspec = decc$translate_vms(path);
     123             : 
     124             :                 if ((int) unixspec != 0 && (int) unixspec != -1)
     125             :                         strcpy(path, unixspec);
     126             :         }
     127             : #endif
     128        1136 :         len = strlen(path);
     129        1136 :         if (len < 10 || (strcasecmp(path + len - 10, "/unittests") != 0
     130             : #ifdef _WIN32
     131             :             && strcasecmp(path + len - 10, "\\unittests") != 0
     132             : #endif
     133             :             ))
     134             :                 return 0;
     135        1136 :         path[len - 9] = 0;
     136        1136 :         for (search_p = search_driver; *search_p; ++search_p) {
     137        1136 :                 if (check_lib(path, *search_p))
     138             :                         break;
     139             :         }
     140        1136 :         if (!*search_p)
     141             :                 return 0;
     142        1136 :         strcpy(common_pwd.driver, path);
     143             : 
     144        1136 :         s1 = getenv("TDSINIOVERRIDE");
     145        1136 :         if (s1 && atoi(s1) == 0)
     146           0 :                 ini_override = false;
     147             : 
     148             : #if !defined(_WIN32) || defined(TDS_NO_DM)
     149             :         /* craft out odbc.ini, avoid to read wrong one */
     150        1136 :         sprintf(path, "odbc.ini.%d", (int) getpid());
     151        1136 :         in = fopen(path, "w");
     152        1136 :         if (in) {
     153        1136 :                 fprintf(in,
     154             :                         "[%s]\nDriver = %s\nDatabase = %s\nServername = %s\n",
     155             :                         common_pwd.server, common_pwd.driver, common_pwd.database, common_pwd.server);
     156        1136 :                 fclose(in);
     157        1136 :                 if (ini_override) {
     158        1136 :                         setenv("ODBCINI", "./odbc.ini", 1);
     159        1136 :                         setenv("SYSODBCINI", "./odbc.ini", 1);
     160        1136 :                         rename(path, "odbc.ini");
     161             :                 }
     162        1136 :                 unlink(path);
     163             :         }
     164             : #else
     165             :         if (ini_override && SQLGetConfigMode(&old_config_mode)) {
     166             :                 ODBC_BUF *odbc_buf = NULL;
     167             :                 LPCTSTR server = (LPCTSTR) T(common_pwd.server);
     168             :                 LPCTSTR filename = (LPCTSTR) T("odbc.ini");
     169             :                 SQLSetConfigMode(ODBC_USER_DSN);
     170             :                 SQLWritePrivateProfileString(server, (LPCTSTR) T("Driver"), (void *) T(common_pwd.driver), filename);
     171             :                 SQLWritePrivateProfileString(server, (LPCTSTR) T("Database"), (LPCTSTR) T(common_pwd.database), filename);
     172             :                 SQLWritePrivateProfileString(server, (LPCTSTR) T("Servername"), (LPCTSTR) T(common_pwd.server), filename);
     173             :                 SQLSetConfigMode(old_config_mode);
     174             :                 ODBC_FREE();
     175             :         }
     176             : #endif
     177             :         return 0;
     178             : }
     179             : 
     180             : void
     181           0 : odbc_report_error(const char *errmsg, int line, const char *file)
     182             : {
     183             :         SQLSMALLINT handletype;
     184             :         SQLHANDLE handle;
     185             :         SQLRETURN ret;
     186             :         SQLTCHAR sqlstate[6];
     187             :         SQLTCHAR msg[256];
     188           0 :         ODBC_BUF *odbc_buf = NULL;
     189             : 
     190           0 :         if (odbc_stmt) {
     191             :                 handletype = SQL_HANDLE_STMT;
     192             :                 handle = odbc_stmt;
     193           0 :         } else if (odbc_conn) {
     194             :                 handletype = SQL_HANDLE_DBC;
     195             :                 handle = odbc_conn;
     196             :         } else {
     197           0 :                 handletype = SQL_HANDLE_ENV;
     198           0 :                 handle = odbc_env;
     199             :         }
     200           0 :         if (errmsg[0]) {
     201           0 :                 if (line)
     202           0 :                         fprintf(stderr, "%s:%d %s\n", file, line, errmsg);
     203             :                 else
     204           0 :                         fprintf(stderr, "%s\n", errmsg);
     205             :         }
     206           0 :         ret = SQLGetDiagRec(handletype, handle, 1, sqlstate, NULL, msg, TDS_VECTOR_SIZE(msg), NULL);
     207           0 :         if (ret == SQL_SUCCESS || ret == SQL_SUCCESS_WITH_INFO)
     208           0 :                 fprintf(stderr, "SQL error %s -- %s\n", C(sqlstate), C(msg));
     209           0 :         odbc_disconnect();
     210           0 :         ODBC_FREE();
     211           0 :         exit(1);
     212             : }
     213             : 
     214             : static void
     215           0 : ReportODBCError(const char *errmsg, SQLSMALLINT handletype, SQLHANDLE handle, SQLRETURN rc, int line, const char *file)
     216             : {
     217             :         SQLRETURN ret;
     218             :         SQLTCHAR sqlstate[6];
     219             :         SQLTCHAR msg[256];
     220           0 :         ODBC_BUF *odbc_buf = NULL;
     221             : 
     222           0 :         if (errmsg[0]) {
     223           0 :                 if (line)
     224           0 :                         fprintf(stderr, "%s:%d rc=%d %s\n", file, line, (int) rc, errmsg);
     225             :                 else
     226           0 :                         fprintf(stderr, "rc=%d %s\n", (int) rc, errmsg);
     227             :         }
     228           0 :         ret = SQLGetDiagRec(handletype, handle, 1, sqlstate, NULL, msg, TDS_VECTOR_SIZE(msg), NULL);
     229           0 :         if (ret == SQL_SUCCESS || ret == SQL_SUCCESS_WITH_INFO)
     230           0 :                 fprintf(stderr, "SQL error %s -- %s\n", C(sqlstate), C(msg));
     231           0 :         odbc_disconnect();
     232           0 :         ODBC_FREE();
     233           0 :         exit(1);
     234             : }
     235             : 
     236             : int
     237        1086 : odbc_connect(void)
     238             : {
     239        1086 :         ODBC_BUF *odbc_buf = NULL;
     240             :         char command[512+10];
     241             :         const char *p;
     242             : 
     243        1086 :         if (odbc_read_login_info())
     244           0 :                 exit(1);
     245             : 
     246        1086 :         if (odbc_use_version3) {
     247         586 :                 CHKAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &odbc_env, "S");
     248         586 :                 SQLSetEnvAttr(odbc_env, SQL_ATTR_ODBC_VERSION, (SQLPOINTER) (SQL_OV_ODBC3), SQL_IS_UINTEGER);
     249         586 :                 CHKAllocHandle(SQL_HANDLE_DBC, odbc_env, &odbc_conn, "S");
     250             :         } else {
     251         500 :                 CHKAllocEnv(&odbc_env, "S");
     252         500 :                 CHKAllocConnect(&odbc_conn, "S");
     253             :         }
     254             : 
     255        1086 :         printf("odbctest\n--------\n\n");
     256        1086 :         printf("connection parameters:\nserver:   '%s'\nuser:     '%s'\npassword: '%s'\ndatabase: '%s'\n",
     257             :                common_pwd.server, common_pwd.user, "????" /* common_pwd.password */ , common_pwd.database);
     258             : 
     259        1086 :         p = getenv("ODBC_MARS");
     260        1629 :         if (p && atoi(p) != 0)
     261         543 :                 SQLSetConnectAttr(odbc_conn, 1224 /*SQL_COPT_SS_MARS_ENABLED*/, (SQLPOINTER) 1 /*SQL_MARS_ENABLED_YES*/, SQL_IS_UINTEGER);
     262        1086 :         if (odbc_set_conn_attr)
     263          64 :                 (*odbc_set_conn_attr)();
     264             : 
     265        1086 :         if (!odbc_conn_additional_params) {
     266         996 :                 CHKConnect(T(common_pwd.server), SQL_NTS, T(common_pwd.user), SQL_NTS, T(common_pwd.password), SQL_NTS, "SI");
     267             :         } else {
     268             :                 char *params;
     269             :                 SQLSMALLINT len;
     270             : 
     271          90 :                 assert(asprintf(&params, "DSN=%s;UID=%s;PWD=%s;DATABASE=%s;%s",
     272             :                                 common_pwd.server, common_pwd.user,
     273             :                                 common_pwd.password, common_pwd.database, odbc_conn_additional_params)
     274             :                        >= 0);
     275          90 :                 assert(params);
     276          90 :                 CHKDriverConnect(NULL, T(params), SQL_NTS, (SQLTCHAR *) command, sizeof(command)/sizeof(SQLTCHAR),
     277             :                                  &len, SQL_DRIVER_NOPROMPT, "SI");
     278          90 :                 free(params);
     279             :         }
     280             : 
     281        1086 :         CHKAllocStmt(&odbc_stmt, "S");
     282             : 
     283        1086 :         sprintf(command, "use %s", common_pwd.database);
     284        1086 :         printf("%s\n", command);
     285             : 
     286        1086 :         CHKExecDirect(T(command), SQL_NTS, "SI");
     287             : 
     288             : #ifndef TDS_NO_DM
     289             :         /* unixODBC seems to require it */
     290             :         SQLMoreResults(odbc_stmt);
     291             : #endif
     292        1086 :         ODBC_FREE();
     293        1086 :         return 0;
     294             : }
     295             : 
     296             : int
     297        1206 : odbc_disconnect(void)
     298             : {
     299        1206 :         if (odbc_stmt) {
     300        1088 :                 SQLFreeStmt(odbc_stmt, SQL_DROP);
     301        1088 :                 odbc_stmt = SQL_NULL_HSTMT;
     302             :         }
     303             : 
     304        1206 :         if (odbc_conn) {
     305        1206 :                 SQLDisconnect(odbc_conn);
     306        1206 :                 SQLFreeConnect(odbc_conn);
     307        1206 :                 odbc_conn = SQL_NULL_HDBC;
     308             :         }
     309             : 
     310        1206 :         ODBC_FREE();
     311        1206 :         if (odbc_env) {
     312        1206 :                 SQLFreeEnv(odbc_env);
     313        1206 :                 odbc_env = SQL_NULL_HENV;
     314             :         }
     315        1206 :         ODBC_FREE();
     316             : 
     317        1206 :         freetds_driver = -1;
     318        1206 :         tds_version = -1;
     319        1206 :         db_str_version[0] = 0;
     320        1206 :         return 0;
     321             : }
     322             : 
     323             : SQLRETURN
     324        1050 : odbc_command_with_result(HSTMT stmt, const char *command)
     325             : {
     326             :         SQLRETURN ret;
     327        1050 :         ODBC_BUF *odbc_buf = NULL;
     328             : 
     329        1050 :         printf("%s\n", command);
     330        1050 :         ret = SQLExecDirect(stmt, T(command), SQL_NTS);
     331        1050 :         ODBC_FREE();
     332        1050 :         return ret;
     333             : }
     334             : 
     335             : static int ms_db = -1;
     336             : bool
     337        2940 : odbc_db_is_microsoft(void)
     338             : {
     339        2940 :         ODBC_BUF *odbc_buf = NULL;
     340             :         SQLTCHAR buf[64];
     341             :         SQLSMALLINT len;
     342             :         int i;
     343             : 
     344        2940 :         if (ms_db < 0) {
     345         268 :                 buf[0] = 0;
     346         268 :                 CHKGetInfo(SQL_DBMS_NAME, buf, sizeof(buf), &len, "S");
     347        5128 :                 for (i = 0; buf[i]; ++i)
     348        7200 :                         buf[i] = tolower(buf[i]);
     349         268 :                 ms_db = (strstr(C(buf), "microsoft") != NULL);
     350             :         }
     351        2940 :         ODBC_FREE();
     352        2940 :         return !!ms_db;
     353             : }
     354             : 
     355             : bool
     356        1658 : odbc_driver_is_freetds(void)
     357             : {
     358        1658 :         ODBC_BUF *odbc_buf = NULL;
     359             :         SQLTCHAR buf[64];
     360             :         SQLSMALLINT len;
     361             :         int i;
     362             : 
     363        1658 :         if (freetds_driver < 0) {
     364         346 :                 buf[0] = 0;
     365         346 :                 CHKGetInfo(SQL_DRIVER_NAME, buf, sizeof(buf), &len, "S");
     366        4844 :                 for (i = 0; buf[i]; ++i)
     367        6682 :                         buf[i] = tolower(buf[i]);
     368         346 :                 freetds_driver = (strstr(C(buf), "tds") != NULL);
     369             :         }
     370        1658 :         ODBC_FREE();
     371        1658 :         return !!freetds_driver;
     372             : }
     373             : 
     374             : /* Detect protocol version using queries
     375             :  * This to make possible protocol discovery on drivers like MS
     376             :  */
     377             : static int
     378           0 : odbc_tds_version_long(void)
     379             : {
     380             :         SQLRETURN ret;
     381             :         SQLSMALLINT scale, nullable, type;
     382             :         SQLULEN prec;
     383           0 :         ODBC_BUF *odbc_buf = NULL;
     384             : 
     385             :         /* statement must be in a consistent state to do the check */
     386           0 :         CHKExecDirect(T("select 1"), SQL_NTS, "S");
     387           0 :         odbc_reset_statement();
     388             : 
     389             :         /* select cast(123 as sql_variant) -> nvarchar('123') is 7.0 failure query is 5.0 ?? */
     390           0 :         ret = CHKExecDirect(T("select cast('123' as sql_variant)"), SQL_NTS, "SNoE");
     391           0 :         odbc_reset_statement();
     392           0 :         if (ret == SQL_ERROR) {
     393           0 :                 ODBC_FREE();
     394           0 :                 return 0x500;
     395             :         }
     396             : 
     397             :         /* see how bigint is returned, numeric means 7.0 */
     398           0 :         CHKExecDirect(T("select cast('123' as bigint)"), SQL_NTS, "S");
     399           0 :         CHKDescribeCol(1, NULL, 0, NULL, &type, &prec, &scale, &nullable, "S");
     400           0 :         odbc_reset_statement();
     401           0 :         if (type == SQL_NUMERIC || type == SQL_DECIMAL) {
     402           0 :                 ODBC_FREE();
     403           0 :                 return 0x700;
     404             :         }
     405           0 :         if (type != SQL_BIGINT) {
     406           0 :                 fprintf(stderr, "Strange type returned trying to detect protocol version\n");
     407           0 :                 odbc_disconnect();
     408           0 :                 ODBC_FREE();
     409           0 :                 exit(1);
     410             :         }
     411             : 
     412             :         /* select cast('123' as varchar(max)) -> ??? SQL_VARCHAR is 7.2 ?? */
     413           0 :         ret = CHKExecDirect(T("select cast('123' as varchar(max))"), SQL_NTS, "SE");
     414           0 :         if (ret == SQL_ERROR) {
     415           0 :                 odbc_reset_statement();
     416           0 :                 ODBC_FREE();
     417           0 :                 return 0x701;
     418             :         }
     419           0 :         CHKDescribeCol(1, NULL, 0, NULL, &type, &prec, &scale, &nullable, "S");
     420           0 :         odbc_reset_statement();
     421           0 :         if (type == SQL_LONGVARCHAR) {
     422           0 :                 ODBC_FREE();
     423           0 :                 return 0x701;
     424             :         }
     425           0 :         if (type != SQL_VARCHAR) {
     426           0 :                 fprintf(stderr, "Strange type returned trying to detect protocol version\n");
     427           0 :                 odbc_disconnect();
     428           0 :                 ODBC_FREE();
     429           0 :                 exit(1);
     430             :         }
     431             : 
     432             :         /* select cast('12:13:14.1234' as time(4)) -> NVARCHAR('12:13:14.1234') is 7.2 else 7.3 */
     433           0 :         ret = CHKExecDirect(T("select cast('12:13:14.1234' as time(4))"), SQL_NTS, "SE");
     434           0 :         if (ret == SQL_ERROR) {
     435           0 :                 odbc_reset_statement();
     436           0 :                 ODBC_FREE();
     437           0 :                 return 0x702;
     438             :         }
     439           0 :         CHKDescribeCol(1, NULL, 0, NULL, &type, &prec, &scale, &nullable, "S");
     440           0 :         odbc_reset_statement();
     441           0 :         if (scale == 0 && type == SQL_WVARCHAR) {
     442           0 :                 ODBC_FREE();
     443           0 :                 return 0x702;
     444             :         }
     445           0 :         if (scale != 4) {
     446           0 :                 fprintf(stderr, "Strange scale returned trying to detect protocol version\n");
     447           0 :                 odbc_disconnect();
     448           0 :                 ODBC_FREE();
     449           0 :                 exit(1);
     450             :         }
     451             : 
     452             :         /* select convert(varchar(10), 'hi' collate Latin1_General_100_CI_AI_SC_UTF8) ->
     453             :          * NVARCHAR('hi') is 7.3 else 7.4, at least from MSSQL 2019 */
     454           0 :         ret = CHKExecDirect(T("select convert(varchar(10), 'hi' collate Latin1_General_100_CI_AI_SC_UTF8)"), SQL_NTS, "SE");
     455           0 :         if (ret == SQL_ERROR) {
     456           0 :                 odbc_reset_statement();
     457           0 :                 ODBC_FREE();
     458           0 :                 return 0x703;
     459             :         }
     460           0 :         CHKDescribeCol(1, NULL, 0, NULL, &type, &prec, &scale, &nullable, "S");
     461           0 :         odbc_reset_statement();
     462           0 :         if (type == SQL_WVARCHAR) {
     463           0 :                 ODBC_FREE();
     464           0 :                 return 0x703;
     465             :         }
     466           0 :         if (type != SQL_VARCHAR) {
     467           0 :                 fprintf(stderr, "Strange type returned trying to detect protocol version\n");
     468           0 :                 odbc_disconnect();
     469           0 :                 ODBC_FREE();
     470           0 :                 exit(1);
     471             :         }
     472             : 
     473           0 :         ODBC_FREE();
     474           0 :         return 0x704;
     475             : }
     476             : 
     477             : int
     478         268 : odbc_tds_version(void)
     479             : {
     480         268 :         ODBC_BUF *odbc_buf = NULL;
     481             :         SQLUINTEGER version;
     482             :         SQLSMALLINT len;
     483             : 
     484         268 :         if (odbc_driver_is_freetds() && tds_version < 0) {
     485         124 :                 version = 0;
     486         124 :                 len = 0;
     487         124 :                 CHKGetInfo(1300 /* SQL_INFO_FREETDS_TDS_VERSION */, &version, sizeof(version), &len, "S");
     488         124 :                 if (len == sizeof(version))
     489         124 :                         tds_version = (version >> 16) << 8 | (version & 0xff);
     490             :         }
     491         268 :         if (tds_version < 0) {
     492           0 :                 tds_version = odbc_tds_version_long();
     493             :         }
     494         268 :         ODBC_FREE();
     495         268 :         return tds_version;
     496             : }
     497             : 
     498             : const char *
     499         358 : odbc_db_version(void)
     500             : {
     501         358 :         if (!db_str_version[0]) {
     502          98 :                 ODBC_BUF *odbc_buf = NULL;
     503             :                 SQLTCHAR buf[32];
     504             :                 SQLSMALLINT version_len;
     505             : 
     506          98 :                 CHKGetInfo(SQL_DBMS_VER, buf, sizeof(buf), &version_len, "S");
     507          98 :                 strcpy(db_str_version, C(buf));
     508          98 :                 ODBC_FREE();
     509             :         }
     510             : 
     511         358 :         return db_str_version;
     512             : }
     513             : 
     514             : unsigned int
     515         348 : odbc_db_version_int(void)
     516             : {
     517             :         unsigned int h, l;
     518         348 :         if (sscanf(odbc_db_version(), "%u.%u.", &h, &l) != 2) {
     519           0 :                 fprintf(stderr, "Wrong db version: %s\n", odbc_db_version());
     520           0 :                 odbc_disconnect();
     521           0 :                 exit(1);
     522             :         }
     523             : 
     524         348 :         return (h << 24) | ((l & 0xFFu) << 16);
     525             : }
     526             : 
     527             : void
     528         268 : odbc_check_cols(int n, int line, const char * file)
     529             : {
     530             :         SQLSMALLINT cols;
     531             : 
     532         268 :         if (n < 0) {
     533           0 :                 CHKNumResultCols(&cols, "E");
     534           0 :                 return;
     535             :         }
     536         268 :         CHKNumResultCols(&cols, "S");
     537         268 :         if (cols != n) {
     538           0 :                 fprintf(stderr, "%s:%d: Expected %d columns returned %d\n", file, line, n, (int) cols);
     539           0 :                 odbc_disconnect();
     540           0 :                 exit(1);
     541             :         }
     542             : }
     543             : 
     544             : void
     545         570 : odbc_check_rows(int n, int line, const char * file)
     546             : {
     547             :         SQLLEN rows;
     548             : 
     549         570 :         if (n < -1) {
     550           0 :                 CHKRowCount(&rows, "E");
     551           0 :                 return;
     552             :         }
     553             : 
     554         570 :         CHKRowCount(&rows, "S");
     555         570 :         if (rows != n) {
     556           0 :                 fprintf(stderr, "%s:%d: Expected %d rows returned %d\n", file, line, n, (int) rows);
     557           0 :                 odbc_disconnect();
     558           0 :                 exit(1);
     559             :         }
     560             : }
     561             : 
     562             : void
     563       16312 : odbc_reset_statement_proc(SQLHSTMT *stmt, const char *file, int line)
     564             : {
     565       16312 :         SQLFreeStmt(*stmt, SQL_DROP);
     566       16312 :         *stmt = SQL_NULL_HSTMT;
     567       16312 :         odbc_check_res(file, line, SQLAllocStmt(odbc_conn, stmt), SQL_HANDLE_DBC, odbc_conn, "SQLAllocStmt", "S");
     568       16312 : }
     569             : 
     570             : void
     571          68 : odbc_test_skipped(void)
     572             : {
     573          68 :         const char *p = getenv("TDS_SKIP_SUCCESS");
     574          70 :         if (p && atoi(p) != 0)
     575           2 :                 exit(0);
     576          66 :         exit(77);
     577             : }
     578             : 
     579             : void
     580         130 : odbc_check_cursor(void)
     581             : {
     582             :         SQLRETURN retcode;
     583         130 :         ODBC_BUF *odbc_buf = NULL;
     584             : 
     585         130 :         retcode = SQLSetStmtAttr(odbc_stmt, SQL_ATTR_CONCURRENCY, (SQLPOINTER) SQL_CONCUR_ROWVER, 0);
     586         130 :         if (retcode != SQL_SUCCESS) {
     587             :                 SQLTCHAR output[256];
     588             :                 SQLTCHAR sqlstate[6];
     589             : 
     590          26 :                 CHKGetDiagRec(SQL_HANDLE_STMT, odbc_stmt, 1, sqlstate, NULL, output, TDS_VECTOR_SIZE(output), NULL, "S");
     591          26 :                 sqlstate[5] = 0;
     592          26 :                 if (strcmp(C(sqlstate), "01S02") == 0) {
     593          26 :                         printf("Your connection seems to not support cursors, probably you are using wrong protocol version or Sybase\n");
     594          26 :                         odbc_disconnect();
     595          26 :                         ODBC_FREE();
     596          26 :                         odbc_test_skipped();
     597             :                 }
     598           0 :                 ReportODBCError("SQLSetStmtAttr", SQL_HANDLE_STMT, odbc_stmt, retcode, __LINE__, __FILE__);
     599             :         }
     600         104 :         odbc_reset_statement();
     601         104 :         ODBC_FREE();
     602         104 : }
     603             : 
     604             : SQLRETURN
     605      142664 : odbc_check_res(const char *file, int line, SQLRETURN rc, SQLSMALLINT handle_type, SQLHANDLE handle, const char *func, const char *res)
     606             : {
     607      142664 :         const char *p = res;
     608             :         for (;;) {
     609      160289 :                 if (*p == 'S') {
     610      124476 :                         if (rc == SQL_SUCCESS)
     611             :                                 return rc;
     612       16263 :                         ++p;
     613       35813 :                 } else if (*p == 'I') {
     614        4314 :                         if (rc == SQL_SUCCESS_WITH_INFO)
     615             :                                 return rc;
     616        1126 :                         ++p;
     617       31499 :                 } else if (*p == 'E') {
     618        1611 :                         if (rc == SQL_ERROR)
     619             :                                 return rc;
     620         234 :                         ++p;
     621       29888 :                 } else if (strncmp(p, "No", 2) == 0) {
     622       29384 :                         if (rc == SQL_NO_DATA)
     623             :                                 return rc;
     624           2 :                         p += 2;
     625         504 :                 } else if (strncmp(p, "Ne", 2) == 0) {
     626         464 :                         if (rc == SQL_NEED_DATA)
     627             :                                 return rc;
     628           0 :                         p += 2;
     629          40 :                 } else if (*p == 'V') {
     630          40 :                         if (rc == SQL_INVALID_HANDLE)
     631             :                                 return rc;
     632           0 :                         ++p;
     633           0 :                 } else if (!*p) {
     634             :                         break;
     635             :                 } else {
     636           0 :                         odbc_report_error("Wrong results specified", line, file);
     637             :                         return rc;
     638             :                 }
     639             :         }
     640           0 :         ReportODBCError(func, handle_type, handle, rc, line, file);
     641             :         return rc;
     642             : }
     643             : 
     644             : SQLSMALLINT
     645         184 : odbc_alloc_handle_err_type(SQLSMALLINT type)
     646             : {
     647         184 :         switch (type) {
     648             :         case SQL_HANDLE_DESC:
     649             :                 return SQL_HANDLE_STMT;
     650             :         case SQL_HANDLE_STMT:
     651             :                 return SQL_HANDLE_DBC;
     652             :         case SQL_HANDLE_DBC:
     653             :                 return SQL_HANDLE_ENV;
     654             :         }
     655             :         return 0;
     656             : }
     657             : 
     658             : SQLRETURN
     659       22684 : odbc_command_proc(HSTMT stmt, const char *command, const char *file, int line, const char *res)
     660             : {
     661             :         SQLRETURN ret;
     662       22684 :         ODBC_BUF *odbc_buf = NULL;
     663             : 
     664       22684 :         if (command[0] == '@')
     665          40 :                 ++command;
     666             :         else
     667       22644 :                 printf("%s\n", command);
     668             : 
     669       22684 :         ret = odbc_check_res(file, line, SQLExecDirect(stmt, T(command), SQL_NTS), SQL_HANDLE_STMT, stmt, "odbc_command", res);
     670       22684 :         ODBC_FREE();
     671       22684 :         return ret;
     672             : }
     673             : 
     674             : char odbc_err[512];
     675             : char odbc_sqlstate[6];
     676             : 
     677             : void
     678         259 : odbc_read_error(void)
     679             : {
     680         259 :         ODBC_BUF *odbc_buf = NULL;
     681         259 :         SQLTCHAR *err = (SQLTCHAR *) ODBC_GET(sizeof(odbc_err)*sizeof(SQLTCHAR));
     682         259 :         SQLTCHAR *state = (SQLTCHAR *) ODBC_GET(sizeof(odbc_sqlstate)*sizeof(SQLTCHAR));
     683             : 
     684         259 :         memset(odbc_err, 0, sizeof(odbc_err));
     685         259 :         memset(odbc_sqlstate, 0, sizeof(odbc_sqlstate));
     686         259 :         if (odbc_stmt != SQL_NULL_HSTMT)
     687         257 :                 CHKGetDiagRec(SQL_HANDLE_STMT, odbc_stmt, 1, state, NULL, err, sizeof(odbc_err), NULL, "SI");
     688             :         else
     689           2 :                 CHKGetDiagRec(SQL_HANDLE_DBC, odbc_conn, 1, state, NULL, err, sizeof(odbc_err), NULL, "SI");
     690         259 :         strcpy(odbc_err, C(err));
     691         259 :         strcpy(odbc_sqlstate, C(state));
     692         259 :         ODBC_FREE();
     693         259 :         printf("Message: '%s' %s\n", odbc_sqlstate, odbc_err);
     694         259 : }
     695             : 
     696             : SQLLEN
     697          64 : odbc_to_sqlwchar(SQLWCHAR *dst, const char *src, SQLLEN n)
     698             : {
     699          64 :         SQLLEN i = n;
     700     1936876 :         while (--i >= 0)
     701     1919012 :                 dst[i] = (unsigned char) src[i];
     702          64 :         return n * sizeof(SQLWCHAR);
     703             : }
     704             : 
     705             : SQLLEN
     706        4371 : odbc_from_sqlwchar(char *dst, const SQLWCHAR *src, SQLLEN n)
     707             : {
     708             :         SQLLEN i;
     709        4371 :         if (n < 0) {
     710             :                 const SQLWCHAR *p = src;
     711           0 :                 for (n=1; *p++ != 0; ++n)
     712           0 :                         continue;
     713             :         }
     714     2327830 :         for (i = 0; i < n; ++i) {
     715     2323459 :                 assert(src[i] < 256);
     716     2323459 :                 dst[i] = (char) src[i];
     717             :         }
     718        4371 :         return n;
     719             : }
     720             : 
     721             : ODBC_BUF *odbc_buf = NULL;
     722             : 
     723             : void *
     724       23899 : odbc_buf_add(ODBC_BUF** buf, void *ptr)
     725             : {
     726       23899 :         ODBC_BUF *p = (ODBC_BUF*) calloc(1, sizeof(ODBC_BUF));
     727       23899 :         assert(ptr);
     728       23899 :         assert(p);
     729       23899 :         p->buf = ptr;
     730       23899 :         p->next = *buf;
     731       23899 :         *buf = p;
     732       23899 :         return p->buf;
     733             : }
     734             : 
     735             : void *
     736        1384 : odbc_buf_get(ODBC_BUF** buf, size_t s)
     737             : {
     738       23449 :         return odbc_buf_add(buf, malloc(s));
     739             : }
     740             : 
     741             : void
     742       45011 : odbc_buf_free(ODBC_BUF** buf)
     743             : {
     744       45011 :         ODBC_BUF *cur = *buf;
     745       45011 :         *buf = NULL;
     746      113921 :         while (cur) {
     747       23899 :                 ODBC_BUF *next = cur->next;
     748       23899 :                 free(cur->buf);
     749       23899 :                 free(cur);
     750       23899 :                 cur = next;
     751             :         }
     752       45011 : }
     753             : 
     754             : SQLWCHAR *
     755       17904 : odbc_get_sqlwchar(ODBC_BUF** buf, const char *s)
     756             : {
     757             :         size_t l;
     758             :         SQLWCHAR *buffer;
     759             : 
     760       17904 :         if (!s) return NULL;
     761       17736 :         l = strlen(s) + 1;
     762       35472 :         buffer = (SQLWCHAR*) odbc_buf_get(buf, l * sizeof(SQLWCHAR));
     763       17736 :         odbc_to_sqlwchar(buffer, s, l);
     764             :         return buffer;
     765             : }
     766             : 
     767             : char*
     768        3811 : odbc_get_sqlchar(ODBC_BUF** buf, SQLWCHAR *s)
     769             : {
     770             :         int n;
     771        3811 :         const SQLWCHAR *p = s;
     772             :         char *out;
     773             : 
     774       82899 :         for (n=1; *p++ != 0; ++n)
     775       79088 :                 continue;
     776        7622 :         out = (char *) odbc_buf_get(buf, n);
     777        3811 :         odbc_from_sqlwchar(out, s, n);
     778        3811 :         return out;
     779             : }
     780             : 
     781             : char *
     782         450 : odbc_buf_asprintf(ODBC_BUF** buf, const char *fmt, ...)
     783             : {
     784             :         va_list ap;
     785         450 :         char *ret = NULL;
     786             : 
     787         450 :         va_start(ap, fmt);
     788         450 :         assert(vasprintf(&ret, fmt, ap) >= 0);
     789         450 :         va_end(ap);
     790             : 
     791         450 :         return (char *) odbc_buf_add(buf, ret);
     792             : }
     793             : 
     794             : typedef union {
     795             :         struct sockaddr sa;
     796             :         struct sockaddr_in sin;
     797             :         char dummy[256];
     798             : } long_sockaddr;
     799             : 
     800             : static int
     801       81680 : fd_is_socket(int fd)
     802             : {
     803             :         long_sockaddr addr;
     804             :         socklen_t addr_len;
     805             : 
     806             : #ifndef _WIN32
     807             :         struct stat file_stat;
     808             : 
     809       81680 :         if (fstat(fd, &file_stat))
     810             :                 return 0;
     811         104 :         if ((file_stat.st_mode & S_IFSOCK) != S_IFSOCK)
     812             :                 return 0;
     813             : #endif
     814             : 
     815           0 :         addr_len = sizeof(addr);
     816           0 :         if (tds_getpeername((TDS_SYS_SOCKET) fd, &addr.sa, &addr_len))
     817             :                 return 0;
     818             : 
     819           0 :         addr_len = sizeof(addr);
     820           0 :         if (tds_getsockname((TDS_SYS_SOCKET) fd, &addr.sa, &addr_len))
     821             :                 return 0;
     822             : 
     823           0 :         return 1;
     824             : }
     825             : 
     826             : enum {NUM_FDS = 4096*4};
     827             : static unsigned char fd_bitmask[NUM_FDS / 8];
     828             : 
     829             : static int
     830             : mark_fd(int fd)
     831             : {
     832             :         unsigned shift;
     833             :         unsigned char mask;
     834             : 
     835           0 :         if (fd < 0 || fd >= NUM_FDS)
     836             :                 return 0;
     837             : 
     838           0 :         shift = fd & 7;
     839           0 :         mask = fd_bitmask[fd >> 3];
     840           0 :         fd_bitmask[fd >> 3] = mask | (1 << shift);
     841             : 
     842           0 :         return (mask >> shift) & 1;
     843             : }
     844             : 
     845             : #ifdef _WIN32
     846             : #define FOR_ALL_SOCKETS(i) for (i = 4; i <= (4096*4); i += 4)
     847             : #else
     848             : #define FOR_ALL_SOCKETS(i) for (i = 3; i < 1024; ++i)
     849             : #endif
     850             : 
     851             : void
     852          80 : odbc_mark_sockets_opened(void)
     853             : {
     854             :         int i;
     855             : 
     856          80 :         memset(fd_bitmask, 0, sizeof(fd_bitmask));
     857       81760 :         FOR_ALL_SOCKETS(i) {
     858       81680 :                 if (fd_is_socket(i))
     859             :                         mark_fd(i);
     860             :         }
     861          80 : }
     862             : 
     863             : TDS_SYS_SOCKET
     864          80 : odbc_find_last_socket(void)
     865             : {
     866             :         typedef struct {
     867             :                 TDS_SYS_SOCKET sock;
     868             :                 int local_port;
     869             :                 int remote_port;
     870             :         } sock_info;
     871             :         sock_info found[8];
     872          80 :         unsigned num_found = 0, n;
     873             :         int i;
     874             : 
     875          80 :         SQLULEN sock = 0;
     876             :         SQLSMALLINT len;
     877          80 :         if (odbc_driver_is_freetds()
     878          80 :             && SQLGetInfo(odbc_conn, 1301 /* SQL_INFO_FREETDS_SOCKET */, &sock, sizeof(sock), &len) == SQL_SUCCESS
     879          80 :             && len == sizeof(sock))
     880          80 :                 return (TDS_SYS_SOCKET) sock;
     881             : 
     882           0 :         FOR_ALL_SOCKETS(i) {
     883             :                 long_sockaddr remote_addr, local_addr;
     884             :                 struct sockaddr_in *in;
     885             :                 socklen_t remote_addr_len, local_addr_len;
     886             :                 sock_info *info;
     887             : 
     888             :                 /* check if is a socket */
     889           0 :                 if (!fd_is_socket(i))
     890           0 :                         continue;
     891           0 :                 if (mark_fd(i))
     892           0 :                         continue;
     893             : 
     894           0 :                 remote_addr_len = sizeof(remote_addr);
     895           0 :                 if (tds_getpeername((TDS_SYS_SOCKET) i, &remote_addr.sa, &remote_addr_len))
     896           0 :                         continue;
     897           0 :                 if (remote_addr.sa.sa_family != AF_INET
     898             : #ifdef AF_INET6
     899           0 :                     && remote_addr.sa.sa_family != AF_INET6
     900             : #endif
     901             :                     )
     902           0 :                         continue;
     903           0 :                 local_addr_len = sizeof(local_addr);
     904           0 :                 if (tds_getsockname((TDS_SYS_SOCKET) i, &local_addr.sa, &local_addr_len))
     905           0 :                         continue;
     906             : 
     907             :                 /* save in the array */
     908           0 :                 if (num_found >= 8) {
     909           0 :                         memmove(found, found+1, sizeof(found) - sizeof(found[0]));
     910           0 :                         num_found = 7;
     911             :                 }
     912           0 :                 info = &found[num_found++];
     913           0 :                 info->sock = (TDS_SYS_SOCKET) i;
     914           0 :                 info->local_port = -1;
     915           0 :                 info->remote_port = -1;
     916             : 
     917             :                 /* now check if is a socketpair */
     918           0 :                 in = &remote_addr.sin;
     919           0 :                 if (in->sin_family != AF_INET)
     920           0 :                         continue;
     921           0 :                 if (in->sin_addr.s_addr != htonl(INADDR_LOOPBACK))
     922           0 :                         continue;
     923           0 :                 info->remote_port = ntohs(in->sin_port);
     924           0 :                 in = &local_addr.sin;
     925           0 :                 if (in->sin_family != AF_INET)
     926           0 :                         continue;
     927           0 :                 if (in->sin_addr.s_addr != htonl(INADDR_LOOPBACK))
     928           0 :                         continue;
     929           0 :                 info->local_port = ntohs(in->sin_port);
     930           0 :                 for (n = 0; n < num_found - 1; ++n) {
     931           0 :                         if (found[n].remote_port != info->local_port
     932           0 :                             || found[n].local_port != info->remote_port)
     933           0 :                                 continue;
     934           0 :                         --num_found;
     935           0 :                         memmove(found+n, found+n+1, num_found-n-1);
     936           0 :                         --num_found;
     937           0 :                         break;
     938             :                 }
     939             :         }
     940             : 
     941             :         /* return last */
     942           0 :         if (num_found == 0)
     943             :                 return INVALID_SOCKET;
     944           0 :         return found[num_found-1].sock;
     945             : }
     946             : 
     947             : void
     948         742 : odbc_check_no_row(const char *query)
     949             : {
     950             :         SQLRETURN rc;
     951             : 
     952         742 :         rc = CHKExecDirect(T(query), SQL_NTS, "SINo");
     953         742 :         if (rc == SQL_NO_DATA)
     954             :                 return;
     955             : 
     956             :         do {
     957             :                 SQLSMALLINT cols;
     958             : 
     959         444 :                 CHKNumResultCols(&cols, "S");
     960         444 :                 if (cols != 0) {
     961           0 :                         fprintf(stderr, "Data not expected here, query:\n\t%s\n", query);
     962           0 :                         odbc_disconnect();
     963           0 :                         exit(1);
     964             :                 }
     965         444 :         } while (CHKMoreResults("SNo") == SQL_SUCCESS);
     966             : }
     967             : 
     968             : int
     969        1360 : odbc_lookup(const char *name, const struct odbc_lookup_int *table, int def)
     970             : {
     971        3790 :         for (; table->name; ++table)
     972        3790 :                 if (strcmp(table->name, name) == 0)
     973        1360 :                         return table->value;
     974             : 
     975             :         return def;
     976             : }
     977             : 
     978             : const char*
     979         250 : odbc_lookup_value(int value, const struct odbc_lookup_int *table, const char *def)
     980             : {
     981        4700 :         for (; table->name; ++table)
     982        4700 :                 if (table->value == value)
     983             :                         return table->name;
     984             : 
     985             :         return def;
     986             : }
     987             : 
     988             : struct odbc_lookup_int odbc_sql_c_types[] = {
     989             : #define TYPE(s) { #s, s }
     990             :         TYPE(SQL_C_NUMERIC),
     991             :         TYPE(SQL_C_BINARY),
     992             :         TYPE(SQL_C_CHAR),
     993             :         TYPE(SQL_C_WCHAR),
     994             :         TYPE(SQL_C_LONG),
     995             :         TYPE(SQL_C_SBIGINT),
     996             :         TYPE(SQL_C_SHORT),
     997             :         TYPE(SQL_C_TIMESTAMP),
     998             :         TYPE(SQL_C_FLOAT),
     999             :         TYPE(SQL_C_DOUBLE),
    1000             :         TYPE(SQL_C_DEFAULT),
    1001             :         TYPE(SQL_C_DATE),
    1002             :         TYPE(SQL_C_TIME),
    1003             :         TYPE(SQL_C_TYPE_DATE),
    1004             :         TYPE(SQL_C_TYPE_TIME),
    1005             :         TYPE(SQL_C_TYPE_TIMESTAMP),
    1006             :         TYPE(SQL_C_INTERVAL_YEAR),
    1007             :         TYPE(SQL_C_INTERVAL_MONTH),
    1008             :         TYPE(SQL_C_INTERVAL_DAY),
    1009             :         TYPE(SQL_C_INTERVAL_HOUR),
    1010             :         TYPE(SQL_C_INTERVAL_MINUTE),
    1011             :         TYPE(SQL_C_INTERVAL_SECOND),
    1012             :         TYPE(SQL_C_INTERVAL_YEAR_TO_MONTH),
    1013             :         TYPE(SQL_C_INTERVAL_DAY_TO_HOUR),
    1014             :         TYPE(SQL_C_INTERVAL_DAY_TO_MINUTE),
    1015             :         TYPE(SQL_C_INTERVAL_DAY_TO_SECOND),
    1016             :         TYPE(SQL_C_INTERVAL_HOUR_TO_MINUTE),
    1017             :         TYPE(SQL_C_INTERVAL_HOUR_TO_SECOND),
    1018             :         TYPE(SQL_C_INTERVAL_MINUTE_TO_SECOND),
    1019             :         TYPE(SQL_C_BIT),
    1020             :         TYPE(SQL_C_UBIGINT),
    1021             :         TYPE(SQL_C_TINYINT),
    1022             :         TYPE(SQL_C_SLONG),
    1023             :         TYPE(SQL_C_SSHORT),
    1024             :         TYPE(SQL_C_STINYINT),
    1025             :         TYPE(SQL_C_ULONG),
    1026             :         TYPE(SQL_C_USHORT),
    1027             :         TYPE(SQL_C_UTINYINT),
    1028             :         TYPE(SQL_C_GUID),
    1029             : #undef TYPE
    1030             :         { NULL, 0 }
    1031             : };
    1032             : 
    1033             : struct odbc_lookup_int odbc_sql_types[] = {
    1034             : #define TYPE(s) { #s, s }
    1035             :         TYPE(SQL_CHAR),
    1036             :         TYPE(SQL_VARCHAR),
    1037             :         TYPE(SQL_LONGVARCHAR),
    1038             :         TYPE(SQL_WCHAR),
    1039             :         TYPE(SQL_WVARCHAR),
    1040             :         TYPE(SQL_WLONGVARCHAR),
    1041             :         TYPE(SQL_DECIMAL),
    1042             :         TYPE(SQL_NUMERIC),
    1043             :         TYPE(SQL_SMALLINT),
    1044             :         TYPE(SQL_INTEGER),
    1045             :         TYPE(SQL_REAL),
    1046             :         TYPE(SQL_FLOAT),
    1047             :         TYPE(SQL_DOUBLE),
    1048             :         TYPE(SQL_BIT),
    1049             :         TYPE(SQL_TINYINT),
    1050             :         TYPE(SQL_BIGINT),
    1051             :         TYPE(SQL_BINARY),
    1052             :         TYPE(SQL_VARBINARY),
    1053             :         TYPE(SQL_LONGVARBINARY),
    1054             :         TYPE(SQL_DATE),
    1055             :         TYPE(SQL_TIME),
    1056             :         TYPE(SQL_TIMESTAMP),
    1057             :         TYPE(SQL_TYPE_DATE),
    1058             :         TYPE(SQL_TYPE_TIME),
    1059             :         TYPE(SQL_TYPE_TIMESTAMP),
    1060             :         TYPE(SQL_DATETIME),
    1061             :         TYPE(SQL_SS_VARIANT),
    1062             :         TYPE(SQL_SS_UDT),
    1063             :         TYPE(SQL_SS_XML),
    1064             :         TYPE(SQL_SS_TABLE),
    1065             :         TYPE(SQL_SS_TIME2),
    1066             :         TYPE(SQL_SS_TIMESTAMPOFFSET),
    1067             : #ifdef SQL_GUID
    1068             :         TYPE(SQL_GUID),
    1069             : #endif
    1070             : #undef TYPE
    1071             :         { NULL, 0 }
    1072             : };
    1073             : 
    1074             : #ifdef _MSC_VER
    1075             : /* See https://learn.microsoft.com/en-us/cpp/preprocessor/warning?view=msvc-170 */
    1076             : #pragma warning(push)
    1077             : #pragma warning(disable:4996)
    1078             : #endif
    1079             : SQLRETURN
    1080           8 : SQLSetStmtOption_nowarning(SQLHSTMT hstmt, SQLSMALLINT option, SQLULEN param)
    1081             : {
    1082           8 :         return SQLSetStmtOption(hstmt, option, param);
    1083             : }
    1084             : #ifdef _MSC_VER
    1085             : #pragma warning(pop)
    1086             : #endif
    1087             : 
    1088             : void
    1089         866 : odbc_swap_stmts(SQLHSTMT *a, SQLHSTMT *b)
    1090             : {
    1091         866 :         SQLHSTMT tmp = *a;
    1092         866 :         *a = *b;
    1093         866 :         *b = tmp;
    1094         866 : }

Generated by: LCOV version 1.13