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: 2024-03-23 09:12:27 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 const struct attribute *attr, int expected
     221             : typedef int (*get_attr_t) (ATTR_PARAMS);
     222             : 
     223             : static int
     224          48 : get_attr_stmt(ATTR_PARAMS)
     225             : {
     226             :         SQLINTEGER i, ind;
     227             :         SQLSMALLINT si;
     228             :         SQLLEN li;
     229             :         SQLRETURN ret;
     230             : 
     231          48 :         ret = SQL_ERROR;
     232          48 :         switch (attr->type) {
     233          48 :         case type_INTEGER:
     234             :         case type_UINTEGER:
     235          48 :                 i = 0xdeadbeef;
     236          48 :                 ret = SQLGetStmtAttr(odbc_stmt, attr->value, (SQLPOINTER) & i, sizeof(SQLINTEGER), &ind);
     237          48 :                 break;
     238           0 :         case type_SMALLINT:
     239           0 :                 si = 0xbeef;
     240           0 :                 ret = SQLGetStmtAttr(odbc_stmt, attr->value, (SQLPOINTER) & si, sizeof(SQLSMALLINT), &ind);
     241           0 :                 i = si;
     242           0 :                 break;
     243           0 :         case type_LEN:
     244           0 :                 li = 0xdeadbeef;
     245           0 :                 ret = SQLGetStmtAttr(odbc_stmt, attr->value, (SQLPOINTER) & li, sizeof(SQLLEN), &ind);
     246           0 :                 i = li;
     247           0 :                 break;
     248           0 :         case type_VOIDP:
     249             :         case type_DESC:
     250             :         case type_CHARP:
     251           0 :                 fatal("Line %u: CHAR* check still not supported\n", line_num);
     252             :                 break;
     253             :         }
     254          48 :         if (!SQL_SUCCEEDED(ret))
     255           0 :                 fatal("Line %u: failure not expected\n", line_num);
     256          48 :         return i;
     257             : }
     258             : 
     259             : #if 0
     260             : /* do not retry any attribute just return expected value so to make caller happy */
     261             : static int
     262             : get_attr_none(ATTR_PARAMS)
     263             : {
     264             :         return expected;
     265             : }
     266             : #endif
     267             : 
     268             : int
     269           8 : main(int argc, char *argv[])
     270             : {
     271             : #define TEST_FILE "attributes.in"
     272           8 :         const char *in_file = FREETDS_SRCDIR "/" TEST_FILE;
     273             :         FILE *f;
     274             :         char buf[256];
     275             :         SQLINTEGER i;
     276             :         SQLLEN len;
     277           8 :         get_attr_t get_attr_p = get_attr_stmt;
     278             : 
     279           8 :         odbc_connect();
     280             :         /* TODO find another way */
     281           8 :         odbc_check_cursor();
     282           6 :         odbc_command("SET TEXTSIZE 4096");
     283             : 
     284           6 :         SQLBindCol(odbc_stmt, 1, SQL_C_SLONG, &i, sizeof(i), &len);
     285             : 
     286           6 :         f = fopen(in_file, "r");
     287           6 :         if (!f)
     288           0 :                 f = fopen(TEST_FILE, "r");
     289           6 :         if (!f) {
     290           0 :                 fprintf(stderr, "error opening test file\n");
     291           0 :                 exit(1);
     292             :         }
     293             : 
     294           6 :         line_num = 0;
     295         102 :         while (fgets(buf, sizeof(buf), f)) {
     296          90 :                 char *p = buf, *cmd;
     297             : 
     298          90 :                 ++line_num;
     299             : 
     300         198 :                 while (isspace((unsigned char) *p))
     301          18 :                         ++p;
     302          90 :                 cmd = strtok(p, SEP);
     303             : 
     304             :                 /* skip comments */
     305          90 :                 if (!cmd || cmd[0] == '#' || cmd[0] == 0 || cmd[0] == '\n')
     306          24 :                         continue;
     307             : 
     308          66 :                 if (strcmp(cmd, "odbc") == 0) {
     309           6 :                         int odbc3 = get_int(strtok(NULL, SEP)) == 3 ? 1 : 0;
     310             : 
     311           6 :                         if (odbc_use_version3 != odbc3) {
     312           6 :                                 odbc_use_version3 = odbc3;
     313           6 :                                 odbc_disconnect();
     314           6 :                                 odbc_connect();
     315           6 :                                 odbc_command("SET TEXTSIZE 4096");
     316           6 :                                 SQLBindCol(odbc_stmt, 1, SQL_C_SLONG, &i, sizeof(i), &len);
     317             :                         }
     318           6 :                         continue;
     319             :                 }
     320             : 
     321             :                 /* set attribute */
     322          60 :                 if (strcmp(cmd, "set") == 0) {
     323           6 :                         const struct attribute *attr = lookup_attr(strtok(NULL, SEP));
     324           6 :                         char *value = strtok(NULL, SEP);
     325             :                         SQLRETURN ret;
     326             : 
     327           6 :                         if (!value)
     328           0 :                                 fatal("Line %u: value not defined\n", line_num);
     329             : 
     330           6 :                         ret = SQL_ERROR;
     331           6 :                         switch (attr->type) {
     332           6 :                         case type_UINTEGER:
     333             :                         case type_INTEGER:
     334           6 :                                 ret = SQLSetStmtAttr(odbc_stmt, attr->value, TDS_INT2PTR(lookup(value, attr->lookup)),
     335             :                                                       sizeof(SQLINTEGER));
     336           6 :                                 break;
     337           0 :                         case type_SMALLINT:
     338           0 :                                 ret = SQLSetStmtAttr(odbc_stmt, attr->value, TDS_INT2PTR(lookup(value, attr->lookup)),
     339             :                                                       sizeof(SQLSMALLINT));
     340           0 :                                 break;
     341           0 :                         case type_LEN:
     342           0 :                                 ret = SQLSetStmtAttr(odbc_stmt, attr->value, TDS_INT2PTR(lookup(value, attr->lookup)),
     343             :                                                       sizeof(SQLLEN));
     344           0 :                                 break;
     345           0 :                         case type_CHARP:
     346           0 :                                 ret = SQLSetStmtAttr(odbc_stmt, attr->value, (SQLPOINTER) value, SQL_NTS);
     347           0 :                                 break;
     348           0 :                         case type_VOIDP:
     349             :                         case type_DESC:
     350           0 :                                 fatal("Line %u: not implemented\n");
     351             :                         }
     352           6 :                         if (!SQL_SUCCEEDED(ret))
     353           0 :                                 fatal("Line %u: failure not expected setting statement attribute\n", line_num);
     354           6 :                         get_attr_p = get_attr_stmt;
     355           6 :                         continue;
     356             :                 }
     357             : 
     358             :                 /* test attribute */
     359          54 :                 if (strcmp(cmd, "attr") == 0) {
     360          48 :                         const struct attribute *attr = lookup_attr(strtok(NULL, SEP));
     361          48 :                         char *value = strtok(NULL, SEP);
     362          48 :                         int i, expected = lookup(value, attr->lookup);
     363             : 
     364          48 :                         if (!value)
     365           0 :                                 fatal("Line %u: value not defined\n", line_num);
     366             : 
     367          48 :                         i = get_attr_p(attr, expected);
     368          48 :                         if (i != expected) {
     369           0 :                                 g_result = 1;
     370           0 :                                 fprintf(stderr, "Line %u: invalid %s got %d(%s) expected %s\n", line_num, attr->name, i, unlookup(i, attr->lookup), value);
     371             :                         }
     372          48 :                         continue;
     373             :                 }
     374             : 
     375           6 :                 if (strcmp(cmd, "reset") == 0) {
     376           6 :                         odbc_reset_statement();
     377           6 :                         continue;
     378             :                 }
     379             : 
     380           0 :                 fatal("Line %u: command '%s' not handled\n", line_num, cmd);
     381             :         }
     382             : 
     383           6 :         fclose(f);
     384           6 :         odbc_disconnect();
     385             : 
     386           6 :         printf("Done.\n");
     387           6 :         return g_result;
     388             : }

Generated by: LCOV version 1.13