LCOV - code coverage report
Current view: top level - src/odbc/unittests - getdata.c (source / functions) Hit Total Coverage
Test: FreeTDS coverage Lines: 173 210 82.4 %
Date: 2026-07-19 14:02:14 Functions: 4 4 100.0 %

          Line data    Source code
       1             : /*
       2             :  * Test reading data with SQLGetData
       3             :  */
       4             : #include "common.h"
       5             : #include <assert.h>
       6             : 
       7             : /**
       8             :  * Test various errors from SQLGetData
       9             :  * @param data    string to return from server
      10             :  * @param c_type  destination SQL C type
      11             :  * @param state   expected SQL state
      12             :  */
      13             : static void
      14          50 : test_err(const char *data, int c_type, const char *state)
      15             : {
      16             :         char sql[128];
      17             :         SQLLEN ind;
      18          50 :         const unsigned int buf_size = 128;
      19          50 :         char *buf = (char *) malloc(buf_size);
      20             : 
      21          50 :         sprintf(sql, "SELECT '%s'", data);
      22          50 :         odbc_command(sql);
      23          50 :         SQLFetch(odbc_stmt);
      24          50 :         CHKGetData(1, c_type, buf, buf_size, &ind, "E");
      25          50 :         free(buf);
      26          50 :         odbc_read_error();
      27          50 :         if (strcmp(odbc_sqlstate, state) != 0) {
      28           0 :                 fprintf(stderr, "Unexpected sql state returned\n");
      29           0 :                 odbc_disconnect();
      30           0 :                 exit(1);
      31             :         }
      32          50 :         odbc_reset_statement();
      33          50 : }
      34             : 
      35             : static int type;
      36             : 
      37             : static inline int
      38             : compute_len_char(void)
      39             : {
      40         584 :         return type == SQL_C_CHAR ? 1 : (int) sizeof(SQLWCHAR);
      41             : }
      42             : 
      43             : #define lc compute_len_char()
      44             : 
      45             : static int
      46         144 : mycmp(const char *s1, const char *s2)
      47             : {
      48             :         size_t i, l;
      49             : 
      50         144 :         l = strlen(s2);
      51        1260 :         for (i = 0; i <= l; ++i) {
      52        1116 :                 SQLWCHAR wc = (type == SQL_C_CHAR) ? s1[i] : ((const SQLWCHAR *) s1)[i];
      53             : 
      54        1116 :                 if (s2[i] != wc)
      55             :                         return 1;
      56             :         }
      57             :         return 0;
      58             : }
      59             : 
      60             : /**
      61             :  * Test returning a string and splitting into multiple parts using SQLGetData
      62             :  * @param n_flag  Either "" or "N" to test Nxxx or xxx types (ie NVARCHAR/VARCHAR).
      63             :  */
      64             : static void
      65          36 : test_split(const char *n_flag)
      66             : {
      67             : #define CheckLen(x) do { \
      68             :         if (len != (x)) { \
      69             :                 fprintf(stderr, "Wrong len %ld at line %d expected %d\n", (long int) len, __LINE__, (x)); \
      70             :                 exit(1); \
      71             :         } \
      72             :         } while(0)
      73             : 
      74             :         char *sql;
      75          36 :         char *buf = NULL;
      76          36 :         const char *collate = "";
      77             :         SQLLEN len;
      78             : 
      79          36 :         if (odbc_db_is_microsoft())
      80          32 :                 collate = " COLLATE Latin1_General_CI_AS";
      81          36 :         sql = odbc_buf_asprintf(&odbc_buf, "SELECT CONVERT(%sTEXT,'Prova'%s + REPLICATE('x',500))%s", n_flag, collate, collate);
      82          36 :         odbc_command(sql);
      83             : 
      84          36 :         CHKFetch("S");
      85             : 
      86             :         /* these 2 tests test an old severe BUG in FreeTDS */
      87          36 :         buf = (char *) ODBC_GET(1);
      88          36 :         CHKGetData(1, type, buf, 0, &len, "I");
      89          36 :         if (len != SQL_NO_TOTAL)
      90          18 :                 CheckLen(505*lc);
      91          36 :         CHKGetData(1, type, buf, 0, &len, "I");
      92          36 :         if (len != SQL_NO_TOTAL)
      93          18 :                 CheckLen(505*lc);
      94          36 :         buf = (char *) ODBC_GET(3*lc);
      95          72 :         CHKGetData(1, type, buf, 3 * lc, &len, "I");
      96          36 :         if (len != SQL_NO_TOTAL)
      97          18 :                 CheckLen(505*lc);
      98          36 :         if (mycmp(buf, "Pr") != 0) {
      99           0 :                 printf("Wrong data result 1\n");
     100           0 :                 exit(1);
     101             :         }
     102             : 
     103          36 :         buf = (char *) ODBC_GET(16*lc);
     104          72 :         CHKGetData(1, type, buf, 16 * lc, &len, "I");
     105          36 :         if (len != SQL_NO_TOTAL)
     106          18 :                 CheckLen(503*lc);
     107          36 :         if (mycmp(buf, "ovaxxxxxxxxxxxx") != 0) {
     108           0 :                 printf("Wrong data result 2 res = '%s'\n", buf);
     109           0 :                 exit(1);
     110             :         }
     111             : 
     112          36 :         buf = (char *) ODBC_GET(256*lc);
     113          72 :         CHKGetData(1, type, buf, 256 * lc, &len, "I");
     114          36 :         if (len != SQL_NO_TOTAL)
     115          18 :                 CheckLen(488*lc);
     116          72 :         CHKGetData(1, type, buf, 256 * lc, &len, "S");
     117          36 :         CheckLen(233*lc);
     118          36 :         CHKGetData(1, type, buf, 256 * lc, &len, "No");
     119             : 
     120          36 :         odbc_reset_statement();
     121             : 
     122             :         /* test with varchar, not blob but variable */
     123          36 :         sql = odbc_buf_asprintf(&odbc_buf, "SELECT CONVERT(%sVARCHAR(100), 'Other test')", n_flag);
     124          36 :         odbc_command(sql);
     125             : 
     126          36 :         CHKFetch("S");
     127             : 
     128          36 :         buf = (char *) ODBC_GET(7*lc);
     129          72 :         CHKGetData(1, type, buf, 7 * lc, NULL, "I");
     130          36 :         if (mycmp(buf, "Other ") != 0) {
     131           0 :                 printf("Wrong data result 1\n");
     132           0 :                 exit(1);
     133             :         }
     134             : 
     135          36 :         buf = (char *) ODBC_GET(5*lc);
     136          36 :         CHKGetData(1, type, buf, 20, NULL, "S");
     137          36 :         if (mycmp(buf, "test") != 0) {
     138           0 :                 printf("Wrong data result 2 res = '%s'\n", buf);
     139           0 :                 exit(1);
     140             :         }
     141          36 :         ODBC_FREE();
     142             : 
     143          36 :         odbc_reset_statement();
     144          36 : }
     145             : 
     146          10 : TEST_MAIN()
     147             : {
     148             :         char buf[32];
     149             :         SQLINTEGER int_buf;
     150             :         SQLLEN len;
     151             :         SQLRETURN rc;
     152             :         TIMESTAMP_STRUCT tss;
     153             : 
     154          10 :         odbc_use_version3 = false;
     155          10 :         odbc_connect();
     156             : 
     157          10 :         type = SQL_C_CHAR;
     158          10 :         test_split("");
     159             : 
     160          10 :         type = SQL_C_WCHAR;
     161          10 :         test_split("");
     162             : 
     163          10 :         if (odbc_db_is_microsoft() && odbc_db_version_int() >= 0x07000000u) {
     164           8 :                 type = SQL_C_CHAR;
     165           8 :                 test_split("N");
     166             : 
     167           8 :                 type = SQL_C_WCHAR;
     168           8 :                 test_split("N");
     169             :         }
     170             : 
     171             :         /* test with fixed length */
     172          10 :         odbc_command("SELECT CONVERT(INT, 12345)");
     173             : 
     174          10 :         CHKFetch("S");
     175             : 
     176          10 :         int_buf = 0xdeadbeef;
     177          10 :         CHKGetData(1, SQL_C_SLONG, &int_buf, 0, NULL, "S");
     178          10 :         if (int_buf != 12345) {
     179           0 :                 printf("Wrong data result\n");
     180           0 :                 exit(1);
     181             :         }
     182             : 
     183          10 :         CHKGetData(1, SQL_C_SLONG, &int_buf, 0, NULL, "No");
     184          10 :         if (int_buf != 12345) {
     185           0 :                 printf("Wrong data result 2 res = %d\n", (int) int_buf);
     186           0 :                 exit(1);
     187             :         }
     188             : 
     189          10 :         odbc_reset_statement();
     190             : 
     191             :         /* test with numeric */
     192          10 :         odbc_command("SELECT CONVERT(NUMERIC(18,5), 1850000000000)");
     193             : 
     194          10 :         CHKFetch("S");
     195             : 
     196          10 :         memset(buf, 'x', sizeof(buf));
     197          10 :         CHKGetData(1, SQL_C_CHAR, buf, 14, NULL, "S");
     198          10 :         buf[sizeof(buf)-1] = 0;
     199          10 :         if (strcmp(buf, "1850000000000") != 0) {
     200           0 :                 printf("Wrong data result: %s\n", buf);
     201           0 :                 exit(1);
     202             :         }
     203             : 
     204             :         /* should give NO DATA */
     205          10 :         CHKGetData(1, SQL_C_CHAR, buf, 14, NULL, "No");
     206          10 :         buf[sizeof(buf)-1] = 0;
     207          10 :         if (strcmp(buf, "1850000000000") != 0) {
     208           0 :                 printf("Wrong data result 3 res = %s\n", buf);
     209           0 :                 exit(1);
     210             :         }
     211             : 
     212          10 :         odbc_reset_statement();
     213             : 
     214             : 
     215             :         /* test int to truncated string */
     216          10 :         odbc_command("SELECT CONVERT(INTEGER, 12345)");
     217          10 :         CHKFetch("S");
     218             : 
     219             :         /* error 22003 */
     220          10 :         memset(buf, 'x', sizeof(buf));
     221          10 :         CHKGetData(1, SQL_C_CHAR, buf, 4, NULL, "E");
     222             : #ifdef ENABLE_DEVELOPING
     223             :         buf[4] = 0;
     224             :         if (strcmp(buf, "xxxx") != 0) {
     225             :                 fprintf(stderr, "Wrong buffer result buf = %s\n", buf);
     226             :                 exit(1);
     227             :         }
     228             : #endif
     229          10 :         odbc_read_error();
     230          10 :         if (strcmp(odbc_sqlstate, "22003") != 0) {
     231           0 :                 fprintf(stderr, "Unexpected sql state %s returned\n", odbc_sqlstate);
     232           0 :                 odbc_disconnect();
     233           0 :                 exit(1);
     234             :         }
     235          10 :         CHKGetData(1, SQL_C_CHAR, buf, 2, NULL, "No");
     236          10 :         odbc_reset_statement();
     237             : 
     238             :         /* test unique identifier to truncated string */
     239          10 :         rc = odbc_command2("SELECT CONVERT(UNIQUEIDENTIFIER, 'AA7DF450-F119-11CD-8465-00AA00425D90')", "SENo");
     240          10 :         if (rc != SQL_ERROR) {
     241           8 :                 CHKFetch("S");
     242             : 
     243             :                 /* error 22003 */
     244           8 :                 CHKGetData(1, SQL_C_CHAR, buf, 17, NULL, "E");
     245           8 :                 odbc_read_error();
     246           8 :                 if (strcmp(odbc_sqlstate, "22003") != 0) {
     247           0 :                         fprintf(stderr, "Unexpected sql state %s returned\n", odbc_sqlstate);
     248           0 :                         odbc_disconnect();
     249           0 :                         exit(1);
     250             :                 }
     251           8 :                 CHKGetData(1, SQL_C_CHAR, buf, 2, NULL, "No");
     252             :         }
     253          10 :         odbc_reset_statement();
     254             : 
     255             : 
     256          10 :         odbc_disconnect();
     257             : 
     258          10 :         odbc_use_version3 = true;
     259          10 :         odbc_conn_additional_params = "ClientCharset=UTF-8;";
     260          10 :         odbc_connect();
     261             : 
     262             :         /* test error from SQLGetData */
     263             :         /* wrong constant, SQL_VARCHAR is invalid as C type */
     264          10 :         test_err("prova 123",           SQL_VARCHAR,     "HY003");
     265             :         /* use ARD but no ARD data column */
     266          10 :         test_err("prova 123",           SQL_ARD_TYPE,    "07009");
     267             :         /* wrong conversion, int */
     268          10 :         test_err("prova 123",           SQL_C_LONG,      "22018");
     269             :         /* wrong conversion, date */
     270          10 :         test_err("prova 123",           SQL_C_TIMESTAMP, "22018");
     271             :         /* overflow */
     272          10 :         test_err("1234567890123456789", SQL_C_LONG,      "22003");
     273             : 
     274             :         /* test datetime precision */
     275          10 :         odbc_command("SELECT CONVERT(DATETIME, '2018-08-15 12:34:56.007')");
     276             : 
     277          10 :         CHKFetch("S");
     278             : 
     279          10 :         memset(&tss, 'x', sizeof(tss));
     280          10 :         CHKGetData(1, SQL_C_TYPE_TIMESTAMP, &tss, sizeof(tss), NULL, "S");
     281          10 :         if (tss.fraction != 7000000) {
     282           0 :                 printf("Wrong data result: %lu\n", (unsigned long) tss.fraction);
     283           0 :                 exit(1);
     284             :         }
     285             : 
     286          10 :         odbc_reset_statement();
     287             : 
     288             :         /* test for empty string from mssql */
     289          10 :         if (odbc_db_is_microsoft()) {
     290           8 :                 type = SQL_C_CHAR;
     291             : 
     292           8 :                 for (;;) {
     293          16 :                         void *buf = ODBC_GET(lc);
     294             : 
     295          16 :                         odbc_command("SELECT CONVERT(TEXT,'' COLLATE Latin1_General_CI_AS)");
     296             : 
     297          16 :                         CHKFetch("S");
     298             : 
     299          16 :                         len = 1234;
     300          32 :                         CHKGetData(1, type, buf, lc, &len, "S");
     301             : 
     302          16 :                         if (len != 0) {
     303           0 :                                 fprintf(stderr, "Wrong len returned, returned %ld\n", (long) len);
     304           0 :                                 return 1;
     305             :                         }
     306             : 
     307          32 :                         CHKGetData(1, type, buf, lc, NULL, "No");
     308          16 :                         odbc_reset_statement();
     309          16 :                         ODBC_FREE();
     310             : 
     311          16 :                         buf = ODBC_GET(4096*lc);
     312             : 
     313          16 :                         odbc_command("SELECT CONVERT(TEXT,'' COLLATE Latin1_General_CI_AS)");
     314             : 
     315          16 :                         CHKFetch("S");
     316             : 
     317          16 :                         len = 1234;
     318          32 :                         CHKGetData(1, type, buf, lc*4096, &len, "S");
     319             : 
     320          16 :                         if (len != 0) {
     321           0 :                                 fprintf(stderr, "Wrong len returned, returned %ld\n", (long) len);
     322           0 :                                 return 1;
     323             :                         }
     324             : 
     325          32 :                         CHKGetData(1, type, buf, lc*4096, NULL, "No");
     326          16 :                         odbc_reset_statement();
     327          16 :                         ODBC_FREE();
     328             : 
     329          16 :                         if (type != SQL_C_CHAR)
     330             :                                 break;
     331           8 :                         type = SQL_C_WCHAR;
     332             :                 }       
     333             : 
     334           8 :                 odbc_command("SELECT CONVERT(TEXT,'' COLLATE Latin1_General_CI_AS)");
     335             : 
     336           8 :                 CHKFetch("S");
     337             : 
     338           8 :                 len = 1234;
     339           8 :                 CHKGetData(1, SQL_C_BINARY, buf, 1, &len, "S");
     340             : 
     341           8 :                 if (len != 0) {
     342           0 :                         fprintf(stderr, "Wrong len returned, returned %ld\n", (long) len);
     343           0 :                         return 1;
     344             :                 }
     345             : 
     346           8 :                 CHKGetData(1, SQL_C_BINARY, buf, 1, NULL, "No");
     347             :         }
     348             : 
     349          10 :         odbc_reset_statement();
     350             : 
     351             :         /* test splitting UTF-8 from mssql 2019 */
     352          10 :         if (odbc_driver_is_freetds() && odbc_db_is_microsoft() && odbc_db_version_int() >= 0x0f000000u
     353           2 :             && odbc_tds_version() >= 0x704) {
     354             :                 void *buf;
     355             : 
     356           2 :                 type = SQL_C_CHAR;
     357             : 
     358           2 :                 odbc_command("SELECT CONVERT(VARCHAR(100), CONVERT(NVARCHAR(10), 0xc200c300c4003200) "
     359             :                              "COLLATE Latin1_General_100_CI_AI_SC_UTF8)");
     360             : 
     361           2 :                 CHKFetch("S");
     362             : 
     363           2 :                 buf = ODBC_GET(4);
     364           2 :                 len = 1234;
     365           2 :                 CHKGetData(1, type, buf, 4, &len, "SI");
     366             : 
     367           2 :                 if (len != 7) {
     368           0 :                         fprintf(stderr, "Wrong len returned, returned %ld\n", (long) len);
     369           0 :                         return 1;
     370             :                 }
     371             : 
     372           2 :                 buf = ODBC_GET(10);
     373           2 :                 len = 1234;
     374           2 :                 CHKGetData(1, type, buf, 10, &len, "SI");
     375             : 
     376           2 :                 if (len != 4) {
     377           0 :                         fprintf(stderr, "Wrong len returned, returned %ld\n", (long) len);
     378           0 :                         return 1;
     379             :                 }
     380             : 
     381           4 :                 CHKGetData(1, type, buf, lc, NULL, "No");
     382           2 :                 odbc_reset_statement();
     383           2 :                 ODBC_FREE();
     384             :         }
     385             : 
     386          10 :         odbc_disconnect();
     387             : 
     388          10 :         printf("Done.\n");
     389          10 :         return 0;
     390             : }

Generated by: LCOV version 1.13