LCOV - code coverage report
Current view: top level - src/odbc/unittests - getdata.c (source / functions) Hit Total Coverage
Test: FreeTDS coverage Lines: 172 209 82.3 %
Date: 2026-03-04 18:06:21 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_connect();
     155             : 
     156          10 :         type = SQL_C_CHAR;
     157          10 :         test_split("");
     158             : 
     159          10 :         type = SQL_C_WCHAR;
     160          10 :         test_split("");
     161             : 
     162          10 :         if (odbc_db_is_microsoft() && odbc_db_version_int() >= 0x07000000u) {
     163           8 :                 type = SQL_C_CHAR;
     164           8 :                 test_split("N");
     165             : 
     166           8 :                 type = SQL_C_WCHAR;
     167           8 :                 test_split("N");
     168             :         }
     169             : 
     170             :         /* test with fixed length */
     171          10 :         odbc_command("SELECT CONVERT(INT, 12345)");
     172             : 
     173          10 :         CHKFetch("S");
     174             : 
     175          10 :         int_buf = 0xdeadbeef;
     176          10 :         CHKGetData(1, SQL_C_SLONG, &int_buf, 0, NULL, "S");
     177          10 :         if (int_buf != 12345) {
     178           0 :                 printf("Wrong data result\n");
     179           0 :                 exit(1);
     180             :         }
     181             : 
     182          10 :         CHKGetData(1, SQL_C_SLONG, &int_buf, 0, NULL, "No");
     183          10 :         if (int_buf != 12345) {
     184           0 :                 printf("Wrong data result 2 res = %d\n", (int) int_buf);
     185           0 :                 exit(1);
     186             :         }
     187             : 
     188          10 :         odbc_reset_statement();
     189             : 
     190             :         /* test with numeric */
     191          10 :         odbc_command("SELECT CONVERT(NUMERIC(18,5), 1850000000000)");
     192             : 
     193          10 :         CHKFetch("S");
     194             : 
     195          10 :         memset(buf, 'x', sizeof(buf));
     196          10 :         CHKGetData(1, SQL_C_CHAR, buf, 14, NULL, "S");
     197          10 :         buf[sizeof(buf)-1] = 0;
     198          10 :         if (strcmp(buf, "1850000000000") != 0) {
     199           0 :                 printf("Wrong data result: %s\n", buf);
     200           0 :                 exit(1);
     201             :         }
     202             : 
     203             :         /* should give NO DATA */
     204          10 :         CHKGetData(1, SQL_C_CHAR, buf, 14, NULL, "No");
     205          10 :         buf[sizeof(buf)-1] = 0;
     206          10 :         if (strcmp(buf, "1850000000000") != 0) {
     207           0 :                 printf("Wrong data result 3 res = %s\n", buf);
     208           0 :                 exit(1);
     209             :         }
     210             : 
     211          10 :         odbc_reset_statement();
     212             : 
     213             : 
     214             :         /* test int to truncated string */
     215          10 :         odbc_command("SELECT CONVERT(INTEGER, 12345)");
     216          10 :         CHKFetch("S");
     217             : 
     218             :         /* error 22003 */
     219          10 :         memset(buf, 'x', sizeof(buf));
     220          10 :         CHKGetData(1, SQL_C_CHAR, buf, 4, NULL, "E");
     221             : #ifdef ENABLE_DEVELOPING
     222             :         buf[4] = 0;
     223             :         if (strcmp(buf, "xxxx") != 0) {
     224             :                 fprintf(stderr, "Wrong buffer result buf = %s\n", buf);
     225             :                 exit(1);
     226             :         }
     227             : #endif
     228          10 :         odbc_read_error();
     229          10 :         if (strcmp(odbc_sqlstate, "22003") != 0) {
     230           0 :                 fprintf(stderr, "Unexpected sql state %s returned\n", odbc_sqlstate);
     231           0 :                 odbc_disconnect();
     232           0 :                 exit(1);
     233             :         }
     234          10 :         CHKGetData(1, SQL_C_CHAR, buf, 2, NULL, "No");
     235          10 :         odbc_reset_statement();
     236             : 
     237             :         /* test unique identifier to truncated string */
     238          10 :         rc = odbc_command2("SELECT CONVERT(UNIQUEIDENTIFIER, 'AA7DF450-F119-11CD-8465-00AA00425D90')", "SENo");
     239          10 :         if (rc != SQL_ERROR) {
     240           8 :                 CHKFetch("S");
     241             : 
     242             :                 /* error 22003 */
     243           8 :                 CHKGetData(1, SQL_C_CHAR, buf, 17, NULL, "E");
     244           8 :                 odbc_read_error();
     245           8 :                 if (strcmp(odbc_sqlstate, "22003") != 0) {
     246           0 :                         fprintf(stderr, "Unexpected sql state %s returned\n", odbc_sqlstate);
     247           0 :                         odbc_disconnect();
     248           0 :                         exit(1);
     249             :                 }
     250           8 :                 CHKGetData(1, SQL_C_CHAR, buf, 2, NULL, "No");
     251             :         }
     252          10 :         odbc_reset_statement();
     253             : 
     254             : 
     255          10 :         odbc_disconnect();
     256             : 
     257          10 :         odbc_use_version3 = true;
     258          10 :         odbc_conn_additional_params = "ClientCharset=UTF-8;";
     259          10 :         odbc_connect();
     260             : 
     261             :         /* test error from SQLGetData */
     262             :         /* wrong constant, SQL_VARCHAR is invalid as C type */
     263          10 :         test_err("prova 123",           SQL_VARCHAR,     "HY003");
     264             :         /* use ARD but no ARD data column */
     265          10 :         test_err("prova 123",           SQL_ARD_TYPE,    "07009");
     266             :         /* wrong conversion, int */
     267          10 :         test_err("prova 123",           SQL_C_LONG,      "22018");
     268             :         /* wrong conversion, date */
     269          10 :         test_err("prova 123",           SQL_C_TIMESTAMP, "22018");
     270             :         /* overflow */
     271          10 :         test_err("1234567890123456789", SQL_C_LONG,      "22003");
     272             : 
     273             :         /* test datetime precision */
     274          10 :         odbc_command("SELECT CONVERT(DATETIME, '2018-08-15 12:34:56.007')");
     275             : 
     276          10 :         CHKFetch("S");
     277             : 
     278          10 :         memset(&tss, 'x', sizeof(tss));
     279          10 :         CHKGetData(1, SQL_C_TYPE_TIMESTAMP, &tss, sizeof(tss), NULL, "S");
     280          10 :         if (tss.fraction != 7000000) {
     281           0 :                 printf("Wrong data result: %lu\n", (unsigned long) tss.fraction);
     282           0 :                 exit(1);
     283             :         }
     284             : 
     285          10 :         odbc_reset_statement();
     286             : 
     287             :         /* test for empty string from mssql */
     288          10 :         if (odbc_db_is_microsoft()) {
     289           8 :                 type = SQL_C_CHAR;
     290             : 
     291           8 :                 for (;;) {
     292          16 :                         void *buf = ODBC_GET(lc);
     293             : 
     294          16 :                         odbc_command("SELECT CONVERT(TEXT,'' COLLATE Latin1_General_CI_AS)");
     295             : 
     296          16 :                         CHKFetch("S");
     297             : 
     298          16 :                         len = 1234;
     299          32 :                         CHKGetData(1, type, buf, lc, &len, "S");
     300             : 
     301          16 :                         if (len != 0) {
     302           0 :                                 fprintf(stderr, "Wrong len returned, returned %ld\n", (long) len);
     303           0 :                                 return 1;
     304             :                         }
     305             : 
     306          32 :                         CHKGetData(1, type, buf, lc, NULL, "No");
     307          16 :                         odbc_reset_statement();
     308          16 :                         ODBC_FREE();
     309             : 
     310          16 :                         buf = ODBC_GET(4096*lc);
     311             : 
     312          16 :                         odbc_command("SELECT CONVERT(TEXT,'' COLLATE Latin1_General_CI_AS)");
     313             : 
     314          16 :                         CHKFetch("S");
     315             : 
     316          16 :                         len = 1234;
     317          32 :                         CHKGetData(1, type, buf, lc*4096, &len, "S");
     318             : 
     319          16 :                         if (len != 0) {
     320           0 :                                 fprintf(stderr, "Wrong len returned, returned %ld\n", (long) len);
     321           0 :                                 return 1;
     322             :                         }
     323             : 
     324          32 :                         CHKGetData(1, type, buf, lc*4096, NULL, "No");
     325          16 :                         odbc_reset_statement();
     326          16 :                         ODBC_FREE();
     327             : 
     328          16 :                         if (type != SQL_C_CHAR)
     329             :                                 break;
     330           8 :                         type = SQL_C_WCHAR;
     331             :                 }       
     332             : 
     333           8 :                 odbc_command("SELECT CONVERT(TEXT,'' COLLATE Latin1_General_CI_AS)");
     334             : 
     335           8 :                 CHKFetch("S");
     336             : 
     337           8 :                 len = 1234;
     338           8 :                 CHKGetData(1, SQL_C_BINARY, buf, 1, &len, "S");
     339             : 
     340           8 :                 if (len != 0) {
     341           0 :                         fprintf(stderr, "Wrong len returned, returned %ld\n", (long) len);
     342           0 :                         return 1;
     343             :                 }
     344             : 
     345           8 :                 CHKGetData(1, SQL_C_BINARY, buf, 1, NULL, "No");
     346             :         }
     347             : 
     348          10 :         odbc_reset_statement();
     349             : 
     350             :         /* test splitting UTF-8 from mssql 2019 */
     351          10 :         if (odbc_driver_is_freetds() && odbc_db_is_microsoft() && odbc_db_version_int() >= 0x0f000000u
     352           2 :             && odbc_tds_version() >= 0x704) {
     353             :                 void *buf;
     354             : 
     355           2 :                 type = SQL_C_CHAR;
     356             : 
     357           2 :                 odbc_command("SELECT CONVERT(VARCHAR(100), CONVERT(NVARCHAR(10), 0xc200c300c4003200) "
     358             :                              "COLLATE Latin1_General_100_CI_AI_SC_UTF8)");
     359             : 
     360           2 :                 CHKFetch("S");
     361             : 
     362           2 :                 buf = ODBC_GET(4);
     363           2 :                 len = 1234;
     364           2 :                 CHKGetData(1, type, buf, 4, &len, "SI");
     365             : 
     366           2 :                 if (len != 7) {
     367           0 :                         fprintf(stderr, "Wrong len returned, returned %ld\n", (long) len);
     368           0 :                         return 1;
     369             :                 }
     370             : 
     371           2 :                 buf = ODBC_GET(10);
     372           2 :                 len = 1234;
     373           2 :                 CHKGetData(1, type, buf, 10, &len, "SI");
     374             : 
     375           2 :                 if (len != 4) {
     376           0 :                         fprintf(stderr, "Wrong len returned, returned %ld\n", (long) len);
     377           0 :                         return 1;
     378             :                 }
     379             : 
     380           4 :                 CHKGetData(1, type, buf, lc, NULL, "No");
     381           2 :                 odbc_reset_statement();
     382           2 :                 ODBC_FREE();
     383             :         }
     384             : 
     385          10 :         odbc_disconnect();
     386             : 
     387          10 :         printf("Done.\n");
     388          10 :         return 0;
     389             : }

Generated by: LCOV version 1.13