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-02-21 09:36:06 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             : int
     261          10 : main(void)
     262             : {
     263             : #define TEST_FILE "attributes.in"
     264          10 :         const char *in_file = FREETDS_SRCDIR "/" TEST_FILE;
     265             :         FILE *f;
     266             :         char buf[256];
     267             :         SQLINTEGER i;
     268             :         SQLLEN len;
     269          10 :         get_attr_t get_attr_p = get_attr_stmt;
     270             : 
     271          10 :         odbc_connect();
     272             :         /* TODO find another way */
     273          10 :         odbc_check_cursor();
     274           8 :         odbc_command("SET TEXTSIZE 4096");
     275             : 
     276           8 :         SQLBindCol(odbc_stmt, 1, SQL_C_SLONG, &i, sizeof(i), &len);
     277             : 
     278           8 :         f = fopen(in_file, "r");
     279           8 :         if (!f)
     280           0 :                 f = fopen(TEST_FILE, "r");
     281           8 :         if (!f) {
     282           0 :                 fprintf(stderr, "error opening test file\n");
     283           0 :                 exit(1);
     284             :         }
     285             : 
     286           8 :         line_num = 0;
     287         136 :         while (fgets(buf, sizeof(buf), f)) {
     288         120 :                 char *p = buf, *cmd;
     289             : 
     290         120 :                 ++line_num;
     291             : 
     292         264 :                 while (isspace((unsigned char) *p))
     293          24 :                         ++p;
     294         120 :                 cmd = strtok(p, SEP);
     295             : 
     296             :                 /* skip comments */
     297         120 :                 if (!cmd || cmd[0] == '#' || cmd[0] == 0 || cmd[0] == '\n')
     298          32 :                         continue;
     299             : 
     300          88 :                 if (strcmp(cmd, "odbc") == 0) {
     301           8 :                         int odbc3 = get_int(strtok(NULL, SEP)) == 3 ? 1 : 0;
     302             : 
     303           8 :                         if (odbc_use_version3 != odbc3) {
     304           8 :                                 odbc_use_version3 = odbc3;
     305           8 :                                 odbc_disconnect();
     306           8 :                                 odbc_connect();
     307           8 :                                 odbc_command("SET TEXTSIZE 4096");
     308           8 :                                 SQLBindCol(odbc_stmt, 1, SQL_C_SLONG, &i, sizeof(i), &len);
     309             :                         }
     310           8 :                         continue;
     311             :                 }
     312             : 
     313             :                 /* set attribute */
     314          80 :                 if (strcmp(cmd, "set") == 0) {
     315           8 :                         const struct attribute *attr = lookup_attr(strtok(NULL, SEP));
     316           8 :                         char *value = strtok(NULL, SEP);
     317             :                         SQLRETURN ret;
     318             : 
     319           8 :                         if (!value)
     320           0 :                                 fatal("Line %u: value not defined\n", line_num);
     321             : 
     322           8 :                         ret = SQL_ERROR;
     323           8 :                         switch (attr->type) {
     324           8 :                         case type_UINTEGER:
     325             :                         case type_INTEGER:
     326           8 :                                 ret = SQLSetStmtAttr(odbc_stmt, attr->value, TDS_INT2PTR(lookup(value, attr->lookup)),
     327             :                                                       sizeof(SQLINTEGER));
     328           8 :                                 break;
     329           0 :                         case type_SMALLINT:
     330           0 :                                 ret = SQLSetStmtAttr(odbc_stmt, attr->value, TDS_INT2PTR(lookup(value, attr->lookup)),
     331             :                                                       sizeof(SQLSMALLINT));
     332           0 :                                 break;
     333           0 :                         case type_LEN:
     334           0 :                                 ret = SQLSetStmtAttr(odbc_stmt, attr->value, TDS_INT2PTR(lookup(value, attr->lookup)),
     335             :                                                       sizeof(SQLLEN));
     336           0 :                                 break;
     337           0 :                         case type_CHARP:
     338           0 :                                 ret = SQLSetStmtAttr(odbc_stmt, attr->value, (SQLPOINTER) value, SQL_NTS);
     339           0 :                                 break;
     340           0 :                         case type_VOIDP:
     341             :                         case type_DESC:
     342           0 :                                 fatal("Line %u: not implemented\n");
     343             :                         }
     344           8 :                         if (!SQL_SUCCEEDED(ret))
     345           0 :                                 fatal("Line %u: failure not expected setting statement attribute\n", line_num);
     346           8 :                         get_attr_p = get_attr_stmt;
     347           8 :                         continue;
     348             :                 }
     349             : 
     350             :                 /* test attribute */
     351          72 :                 if (strcmp(cmd, "attr") == 0) {
     352          64 :                         const struct attribute *attr = lookup_attr(strtok(NULL, SEP));
     353          64 :                         char *value = strtok(NULL, SEP);
     354          64 :                         int i, expected = lookup(value, attr->lookup);
     355             : 
     356          64 :                         if (!value)
     357           0 :                                 fatal("Line %u: value not defined\n", line_num);
     358             : 
     359          64 :                         i = get_attr_p(attr, expected);
     360          64 :                         if (i != expected) {
     361           0 :                                 g_result = 1;
     362           0 :                                 fprintf(stderr, "Line %u: invalid %s got %d(%s) expected %s\n", line_num, attr->name, i, unlookup(i, attr->lookup), value);
     363             :                         }
     364          64 :                         continue;
     365             :                 }
     366             : 
     367           8 :                 if (strcmp(cmd, "reset") == 0) {
     368           8 :                         odbc_reset_statement();
     369           8 :                         continue;
     370             :                 }
     371             : 
     372           0 :                 fatal("Line %u: command '%s' not handled\n", line_num, cmd);
     373             :         }
     374             : 
     375           8 :         fclose(f);
     376           8 :         odbc_disconnect();
     377             : 
     378           8 :         printf("Done.\n");
     379           8 :         return g_result;
     380             : }

Generated by: LCOV version 1.13