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

Generated by: LCOV version 1.13