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

Generated by: LCOV version 1.13