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

Generated by: LCOV version 1.13