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

Generated by: LCOV version 1.13