LCOV - code coverage report
Current view: top level - src/odbc/unittests - attributes.c (source / functions) Hit Total Coverage
Test: FreeTDS coverage Lines: 79 125 63.2 %
Date: 2025-04-20 18:15:36 Functions: 5 6 83.3 %

          Line data    Source code
       1             : #include "common.h"
       2             : #include <ctype.h>
       3             : 
       4             : /*
       5             :  * SQLSetStmtAttr
       6             :  */
       7             : 
       8             : static int g_result = 0;
       9             : static unsigned int line_num;
      10             : 
      11             : #ifdef __GNUC__
      12             : static void fatal(const char *msg, ...) __attribute__((noreturn));
      13             : #endif
      14             : 
      15             : static void
      16           0 : fatal(const char *msg, ...)
      17             : {
      18             :         va_list ap;
      19             : 
      20           0 :         va_start(ap, msg);
      21           0 :         vfprintf(stderr, msg, ap);
      22           0 :         va_end(ap);
      23             : 
      24           0 :         exit(1);
      25             : }
      26             : 
      27             : static int
      28           8 : get_int(const char *s)
      29             : {
      30             :         char *end;
      31             :         long l;
      32             : 
      33           8 :         if (!s)
      34           0 :                 fatal("Line %u: NULL int\n", line_num);
      35           8 :         l = strtol(s, &end, 0);
      36           8 :         if (end[0])
      37           0 :                 fatal("Line %u: Invalid int\n", line_num);
      38           8 :         return (int) l;
      39             : }
      40             : 
      41             : static int
      42          72 : lookup(const char *name, const struct odbc_lookup_int *table)
      43             : {
      44          72 :         if (!table)
      45           0 :                 return get_int(name);
      46             : 
      47          56 :         for (; table->name; ++table)
      48         128 :                 if (strcmp(table->name, name) == 0)
      49          72 :                         return table->value;
      50             : 
      51           0 :         return get_int(name);
      52             : }
      53             : 
      54             : static const char *
      55             : unlookup(int value, const struct odbc_lookup_int *table)
      56             : {
      57           0 :         if (!table)
      58             :                 return "??";
      59             : 
      60           0 :         return odbc_lookup_value(value, table, "??");
      61             : }
      62             : 
      63             : static struct odbc_lookup_int concurrency[] = {
      64             : #define TYPE(s) { #s, s }
      65             :         TYPE(SQL_CONCUR_READ_ONLY),
      66             :         TYPE(SQL_CONCUR_LOCK),
      67             :         TYPE(SQL_CONCUR_ROWVER),
      68             :         TYPE(SQL_CONCUR_VALUES),
      69             : #undef TYPE
      70             :         { NULL, 0 }
      71             : };
      72             : 
      73             : static struct odbc_lookup_int scrollable[] = {
      74             : #define TYPE(s) { #s, s }
      75             :         TYPE(SQL_NONSCROLLABLE),
      76             :         TYPE(SQL_SCROLLABLE),
      77             : #undef TYPE
      78             :         { NULL, 0 }
      79             : };
      80             : 
      81             : static struct odbc_lookup_int sensitivity[] = {
      82             : #define TYPE(s) { #s, s }
      83             :         TYPE(SQL_UNSPECIFIED),
      84             :         TYPE(SQL_INSENSITIVE),
      85             :         TYPE(SQL_SENSITIVE),
      86             : #undef TYPE
      87             :         { NULL, 0 }
      88             : };
      89             : 
      90             : static struct odbc_lookup_int cursor_type[] = {
      91             : #define TYPE(s) { #s, s }
      92             :         TYPE(SQL_CURSOR_FORWARD_ONLY),
      93             :         TYPE(SQL_CURSOR_STATIC),
      94             :         TYPE(SQL_CURSOR_KEYSET_DRIVEN),
      95             :         TYPE(SQL_CURSOR_DYNAMIC),
      96             : #undef TYPE
      97             :         { NULL, 0 }
      98             : };
      99             : 
     100             : static struct odbc_lookup_int noscan[] = {
     101             : #define TYPE(s) { #s, s }
     102             :         TYPE(SQL_NOSCAN_OFF),
     103             :         TYPE(SQL_NOSCAN_ON),
     104             : #undef TYPE
     105             :         { NULL, 0 }
     106             : };
     107             : 
     108             : static struct odbc_lookup_int retrieve_data[] = {
     109             : #define TYPE(s) { #s, s }
     110             :         TYPE(SQL_RD_ON),
     111             :         TYPE(SQL_RD_OFF),
     112             : #undef TYPE
     113             :         { NULL, 0 }
     114             : };
     115             : 
     116             : static struct odbc_lookup_int simulate_cursor[] = {
     117             : #define TYPE(s) { #s, s }
     118             :         TYPE(SQL_SC_NON_UNIQUE),
     119             :         TYPE(SQL_SC_TRY_UNIQUE),
     120             :         TYPE(SQL_SC_UNIQUE),
     121             : #undef TYPE
     122             :         { NULL, 0 }
     123             : };
     124             : 
     125             : static struct odbc_lookup_int use_bookmarks[] = {
     126             : #define TYPE(s) { #s, s }
     127             :         TYPE(SQL_UB_OFF),
     128             :         TYPE(SQL_UB_VARIABLE),
     129             :         TYPE(SQL_UB_FIXED),
     130             : #undef TYPE
     131             :         { NULL, 0 }
     132             : };
     133             : 
     134             : typedef enum
     135             : {
     136             :         type_INTEGER,
     137             :         type_UINTEGER,
     138             :         type_SMALLINT,
     139             :         type_LEN,
     140             :         type_CHARP,
     141             :         type_DESC,
     142             :         type_VOIDP
     143             : } test_type_t;
     144             : 
     145             : struct attribute
     146             : {
     147             :         const char *name;
     148             :         int value;
     149             :         test_type_t type;
     150             :         const struct odbc_lookup_int *lookup;
     151             : };
     152             : 
     153             : static const struct attribute attributes[] = {
     154             : #define ATTR(s,t) { #s, s, type_##t, NULL }
     155             : #define ATTR2(s,t,l) { #s, s, type_##t, l }
     156             :         ATTR(SQL_ATTR_APP_PARAM_DESC, DESC),
     157             :         ATTR(SQL_ATTR_APP_ROW_DESC, DESC),
     158             :         ATTR(SQL_ATTR_ASYNC_ENABLE, UINTEGER),
     159             :         ATTR2(SQL_ATTR_CONCURRENCY, UINTEGER, concurrency),
     160             :         ATTR2(SQL_ATTR_CURSOR_SCROLLABLE, UINTEGER, scrollable),
     161             :         ATTR2(SQL_ATTR_CURSOR_SENSITIVITY, UINTEGER, sensitivity),
     162             :         ATTR2(SQL_ATTR_CURSOR_TYPE, UINTEGER, cursor_type),
     163             :         ATTR(SQL_ATTR_ENABLE_AUTO_IPD, UINTEGER),
     164             :         ATTR(SQL_ATTR_FETCH_BOOKMARK_PTR, VOIDP),
     165             :         ATTR(SQL_ATTR_IMP_PARAM_DESC, DESC),
     166             :         ATTR(SQL_ATTR_IMP_ROW_DESC, DESC),
     167             :         ATTR(SQL_ATTR_KEYSET_SIZE, UINTEGER),
     168             :         ATTR(SQL_ATTR_MAX_LENGTH, UINTEGER),
     169             :         ATTR(SQL_ATTR_MAX_ROWS, UINTEGER),
     170             :         ATTR(SQL_ATTR_METADATA_ID, UINTEGER),
     171             :         ATTR2(SQL_ATTR_NOSCAN, UINTEGER, noscan),
     172             :         ATTR(SQL_ATTR_PARAM_BIND_OFFSET_PTR, VOIDP),
     173             :         ATTR(SQL_ATTR_PARAM_BIND_OFFSET_PTR, VOIDP),
     174             :         ATTR(SQL_ATTR_PARAM_BIND_TYPE, UINTEGER),
     175             :         ATTR(SQL_ATTR_PARAM_OPERATION_PTR, VOIDP),
     176             :         ATTR(SQL_ATTR_PARAM_STATUS_PTR, VOIDP),
     177             :         ATTR(SQL_ATTR_PARAMS_PROCESSED_PTR, VOIDP),
     178             :         ATTR(SQL_ATTR_PARAMSET_SIZE, UINTEGER),
     179             :         ATTR(SQL_ATTR_QUERY_TIMEOUT, UINTEGER),
     180             :         ATTR2(SQL_ATTR_RETRIEVE_DATA, UINTEGER, retrieve_data),
     181             :         ATTR(SQL_ATTR_ROW_ARRAY_SIZE, UINTEGER),
     182             :         ATTR(SQL_ATTR_ROW_BIND_OFFSET_PTR, VOIDP),
     183             :         ATTR(SQL_ATTR_ROW_BIND_TYPE, UINTEGER),
     184             :         ATTR(SQL_ATTR_ROW_NUMBER, UINTEGER),
     185             :         ATTR(SQL_ATTR_ROW_OPERATION_PTR, VOIDP),
     186             :         ATTR(SQL_ATTR_ROW_STATUS_PTR, VOIDP),
     187             :         ATTR(SQL_ATTR_ROWS_FETCHED_PTR, VOIDP),
     188             :         ATTR2(SQL_ATTR_SIMULATE_CURSOR, UINTEGER, simulate_cursor),
     189             :         ATTR2(SQL_ATTR_USE_BOOKMARKS, UINTEGER, use_bookmarks),
     190             : #undef ATTR2
     191             : #undef ATTR
     192             : };
     193             : 
     194             : static const struct attribute *
     195          72 : lookup_attr(const char *name)
     196             : {
     197             :         unsigned int i;
     198             : 
     199          72 :         if (!name)
     200           0 :                 fatal("Line %u: NULL attribute\n", line_num);
     201         328 :         for (i = 0; i < TDS_VECTOR_SIZE(attributes); ++i)
     202         400 :                 if (strcmp(attributes[i].name, name) == 0 || strcmp(attributes[i].name + 4, name) == 0)
     203          72 :                         return &attributes[i];
     204           0 :         fatal("Line %u: attribute %s not found\n", line_num, name);
     205             :         return NULL;
     206             : }
     207             : 
     208             : #define SEP " \t\n"
     209             : 
     210             : #define ATTR_PARAMS \
     211             :         const struct attribute *attr TDS_UNUSED, \
     212             :         int expected TDS_UNUSED
     213             : typedef int (*get_attr_t) (ATTR_PARAMS);
     214             : 
     215             : static int
     216          64 : get_attr_stmt(ATTR_PARAMS)
     217             : {
     218             :         SQLINTEGER i, ind;
     219             :         SQLSMALLINT si;
     220             :         SQLLEN li;
     221             :         SQLRETURN ret;
     222             : 
     223          64 :         ret = SQL_ERROR;
     224          64 :         switch (attr->type) {
     225          64 :         case type_INTEGER:
     226             :         case type_UINTEGER:
     227          64 :                 i = 0xdeadbeef;
     228          64 :                 ret = SQLGetStmtAttr(odbc_stmt, attr->value, (SQLPOINTER) & i, sizeof(SQLINTEGER), &ind);
     229          64 :                 break;
     230           0 :         case type_SMALLINT:
     231           0 :                 si = 0xbeef;
     232           0 :                 ret = SQLGetStmtAttr(odbc_stmt, attr->value, (SQLPOINTER) & si, sizeof(SQLSMALLINT), &ind);
     233           0 :                 i = si;
     234           0 :                 break;
     235           0 :         case type_LEN:
     236           0 :                 li = 0xdeadbeef;
     237           0 :                 ret = SQLGetStmtAttr(odbc_stmt, attr->value, (SQLPOINTER) & li, sizeof(SQLLEN), &ind);
     238           0 :                 i = li;
     239           0 :                 break;
     240           0 :         case type_VOIDP:
     241             :         case type_DESC:
     242             :         case type_CHARP:
     243           0 :                 fatal("Line %u: CHAR* check still not supported\n", line_num);
     244             :                 break;
     245             :         }
     246          64 :         if (!SQL_SUCCEEDED(ret))
     247           0 :                 fatal("Line %u: failure not expected\n", line_num);
     248          64 :         return i;
     249             : }
     250             : 
     251             : #if 0
     252             : /* do not retry any attribute just return expected value so to make caller happy */
     253             : static int
     254             : get_attr_none(ATTR_PARAMS)
     255             : {
     256             :         return expected;
     257             : }
     258             : #endif
     259             : 
     260          10 : TEST_MAIN()
     261             : {
     262             : #define TEST_FILE "attributes.in"
     263          10 :         const char *in_file = FREETDS_SRCDIR "/" TEST_FILE;
     264             :         FILE *f;
     265             :         char buf[256];
     266             :         SQLINTEGER i;
     267             :         SQLLEN len;
     268          10 :         get_attr_t get_attr_p = get_attr_stmt;
     269             : 
     270          10 :         odbc_connect();
     271             :         /* TODO find another way */
     272          10 :         odbc_check_cursor();
     273           8 :         odbc_command("SET TEXTSIZE 4096");
     274             : 
     275           8 :         SQLBindCol(odbc_stmt, 1, SQL_C_SLONG, &i, sizeof(i), &len);
     276             : 
     277           8 :         f = fopen(in_file, "r");
     278           8 :         if (!f)
     279           0 :                 f = fopen(TEST_FILE, "r");
     280           8 :         if (!f) {
     281           0 :                 fprintf(stderr, "error opening test file\n");
     282           0 :                 exit(1);
     283             :         }
     284             : 
     285           8 :         line_num = 0;
     286         136 :         while (fgets(buf, sizeof(buf), f)) {
     287         120 :                 char *p = buf, *cmd;
     288             : 
     289         120 :                 ++line_num;
     290             : 
     291         264 :                 while (isspace((unsigned char) *p))
     292          24 :                         ++p;
     293         120 :                 cmd = strtok(p, SEP);
     294             : 
     295             :                 /* skip comments */
     296         120 :                 if (!cmd || cmd[0] == '#' || cmd[0] == 0 || cmd[0] == '\n')
     297          32 :                         continue;
     298             : 
     299          88 :                 if (strcmp(cmd, "odbc") == 0) {
     300           8 :                         int odbc3 = get_int(strtok(NULL, SEP)) == 3 ? 1 : 0;
     301             : 
     302           8 :                         if (odbc_use_version3 != odbc3) {
     303           8 :                                 odbc_use_version3 = odbc3;
     304           8 :                                 odbc_disconnect();
     305           8 :                                 odbc_connect();
     306           8 :                                 odbc_command("SET TEXTSIZE 4096");
     307           8 :                                 SQLBindCol(odbc_stmt, 1, SQL_C_SLONG, &i, sizeof(i), &len);
     308             :                         }
     309           8 :                         continue;
     310             :                 }
     311             : 
     312             :                 /* set attribute */
     313          80 :                 if (strcmp(cmd, "set") == 0) {
     314           8 :                         const struct attribute *attr = lookup_attr(strtok(NULL, SEP));
     315           8 :                         char *value = strtok(NULL, SEP);
     316             :                         SQLRETURN ret;
     317             : 
     318           8 :                         if (!value)
     319           0 :                                 fatal("Line %u: value not defined\n", line_num);
     320             : 
     321           8 :                         ret = SQL_ERROR;
     322           8 :                         switch (attr->type) {
     323           8 :                         case type_UINTEGER:
     324             :                         case type_INTEGER:
     325           8 :                                 ret = SQLSetStmtAttr(odbc_stmt, attr->value, TDS_INT2PTR(lookup(value, attr->lookup)),
     326             :                                                       sizeof(SQLINTEGER));
     327           8 :                                 break;
     328           0 :                         case type_SMALLINT:
     329           0 :                                 ret = SQLSetStmtAttr(odbc_stmt, attr->value, TDS_INT2PTR(lookup(value, attr->lookup)),
     330             :                                                       sizeof(SQLSMALLINT));
     331           0 :                                 break;
     332           0 :                         case type_LEN:
     333           0 :                                 ret = SQLSetStmtAttr(odbc_stmt, attr->value, TDS_INT2PTR(lookup(value, attr->lookup)),
     334             :                                                       sizeof(SQLLEN));
     335           0 :                                 break;
     336           0 :                         case type_CHARP:
     337           0 :                                 ret = SQLSetStmtAttr(odbc_stmt, attr->value, (SQLPOINTER) value, SQL_NTS);
     338           0 :                                 break;
     339           0 :                         case type_VOIDP:
     340             :                         case type_DESC:
     341           0 :                                 fatal("Line %u: not implemented\n");
     342             :                         }
     343           8 :                         if (!SQL_SUCCEEDED(ret))
     344           0 :                                 fatal("Line %u: failure not expected setting statement attribute\n", line_num);
     345           8 :                         get_attr_p = get_attr_stmt;
     346           8 :                         continue;
     347             :                 }
     348             : 
     349             :                 /* test attribute */
     350          72 :                 if (strcmp(cmd, "attr") == 0) {
     351          64 :                         const struct attribute *attr = lookup_attr(strtok(NULL, SEP));
     352          64 :                         char *value = strtok(NULL, SEP);
     353          64 :                         int i, expected = lookup(value, attr->lookup);
     354             : 
     355          64 :                         if (!value)
     356           0 :                                 fatal("Line %u: value not defined\n", line_num);
     357             : 
     358          64 :                         i = get_attr_p(attr, expected);
     359          64 :                         if (i != expected) {
     360           0 :                                 g_result = 1;
     361           0 :                                 fprintf(stderr, "Line %u: invalid %s got %d(%s) expected %s\n", line_num, attr->name, i, unlookup(i, attr->lookup), value);
     362             :                         }
     363          64 :                         continue;
     364             :                 }
     365             : 
     366           8 :                 if (strcmp(cmd, "reset") == 0) {
     367           8 :                         odbc_reset_statement();
     368           8 :                         continue;
     369             :                 }
     370             : 
     371           0 :                 fatal("Line %u: command '%s' not handled\n", line_num, cmd);
     372             :         }
     373             : 
     374           8 :         fclose(f);
     375           8 :         odbc_disconnect();
     376             : 
     377           8 :         printf("Done.\n");
     378           8 :         return g_result;
     379             : }

Generated by: LCOV version 1.13