LCOV - code coverage report
Current view: top level - src/odbc/unittests - describecol.c (source / functions) Hit Total Coverage
Test: FreeTDS coverage Lines: 118 182 64.8 %
Date: 2025-04-15 09:57:00 Functions: 7 9 77.8 %

          Line data    Source code
       1             : #include "common.h"
       2             : #include <ctype.h>
       3             : #include "parser.h"
       4             : #include <freetds/bool.h>
       5             : 
       6             : /*
       7             :  * SQLDescribeCol test for precision
       8             :  * test what say SQLDescribeCol about precision using some type
       9             :  */
      10             : 
      11             : static int g_result = 0;
      12             : 
      13             : static int
      14        4106 : get_int(const char *s, odbc_parser *parser)
      15             : {
      16             :         char *end;
      17             :         long l;
      18             : 
      19        4106 :         if (!s)
      20           0 :                 odbc_fatal(parser, ": NULL int\n");
      21        4106 :         l = strtol(s, &end, 0);
      22        4106 :         if (end[0])
      23           0 :                 odbc_fatal(parser, ": Invalid int\n");
      24        4106 :         return (int) l;
      25             : }
      26             : 
      27             : static int
      28        4454 : lookup(const char *name, const struct odbc_lookup_int *table, odbc_parser *parser)
      29             : {
      30        4454 :         if (!table)
      31        4096 :                 return get_int(name, parser);
      32             : 
      33        4600 :         for (; table->name; ++table)
      34        4958 :                 if (strcmp(table->name, name) == 0)
      35         358 :                         return table->value;
      36             : 
      37           0 :         return get_int(name, parser);
      38             : }
      39             : 
      40             : static const char*
      41           0 : unlookup(SQLLEN value, const struct odbc_lookup_int *table)
      42             : {
      43             :         static char buf[32];
      44             : 
      45           0 :         sprintf(buf, "%ld", (long) value);
      46           0 :         if (!table)
      47             :                 return buf;
      48             : 
      49           0 :         return odbc_lookup_value(value, table, buf);
      50             : }
      51             : 
      52             : static struct odbc_lookup_int sql_bools[] = {
      53             :         { "SQL_TRUE",  SQL_TRUE  },
      54             :         { "SQL_FALSE", SQL_FALSE },
      55             :         { NULL, 0 }
      56             : };
      57             : 
      58             : typedef enum
      59             : {
      60             :         type_INTEGER,
      61             :         type_SMALLINT,
      62             :         type_LEN,
      63             :         type_CHARP
      64             : } test_type_t;
      65             : 
      66             : struct attribute
      67             : {
      68             :         const char *name;
      69             :         int value;
      70             :         test_type_t type;
      71             :         const struct odbc_lookup_int *lookup;
      72             : };
      73             : 
      74             : static const struct attribute attributes[] = {
      75             : #define ATTR(s,t) { #s, s, type_##t, NULL }
      76             : #define ATTR2(s,t,l) { #s, s, type_##t, l }
      77             :         ATTR(SQL_COLUMN_LENGTH, INTEGER),
      78             :         ATTR(SQL_COLUMN_PRECISION, INTEGER),
      79             :         ATTR(SQL_COLUMN_SCALE, INTEGER),
      80             :         ATTR(SQL_DESC_LENGTH, LEN),
      81             :         ATTR(SQL_DESC_OCTET_LENGTH, LEN),
      82             :         ATTR(SQL_DESC_PRECISION, SMALLINT),
      83             :         ATTR(SQL_DESC_SCALE, SMALLINT),
      84             :         ATTR(SQL_DESC_DISPLAY_SIZE, INTEGER),
      85             :         ATTR(SQL_DESC_TYPE_NAME, CHARP),
      86             :         ATTR2(SQL_DESC_CONCISE_TYPE, SMALLINT, odbc_sql_types),
      87             :         ATTR2(SQL_DESC_TYPE, SMALLINT, odbc_sql_types),
      88             :         ATTR2(SQL_DESC_UNSIGNED, SMALLINT, sql_bools)
      89             : #undef ATTR2
      90             : #undef ATTR
      91             : };
      92             : 
      93             : static const struct attribute *
      94        6130 : lookup_attr(const char *name, odbc_parser *parser)
      95             : {
      96             :         unsigned int i;
      97             : 
      98        6130 :         if (!name)
      99           0 :                 odbc_fatal(parser, ": NULL attribute\n");
     100       28290 :         for (i = 0; i < TDS_VECTOR_SIZE(attributes); ++i)
     101       34420 :                 if (strcmp(attributes[i].name, name) == 0 || strcmp(attributes[i].name + 4, name) == 0)
     102        6130 :                         return &attributes[i];
     103           0 :         odbc_fatal(parser, ": attribute %s not found\n", name);
     104             :         return NULL;
     105             : }
     106             : 
     107             : #define ATTR_PARAMS \
     108             :         const struct attribute *attr TDS_UNUSED, \
     109             :         const char *expected_values[] TDS_UNUSED, \
     110             :         odbc_parser *parser TDS_UNUSED
     111             : typedef void (*check_attr_t) (ATTR_PARAMS);
     112             : 
     113             : static bool
     114             : is_contained(const char *s, const char *list[])
     115             : {
     116           0 :         for (;*list; ++list) {
     117         144 :                 if (strcmp(s, *list) == 0)
     118             :                         return true;
     119             :         }
     120             :         return false;
     121             : }
     122             : 
     123             : static bool
     124             : is_contained_lookup(SQLLEN i, const char *list[], const struct odbc_lookup_int *table, odbc_parser *parser)
     125             : {
     126          32 :         for (;*list; ++list) {
     127        4334 :                 if (i == lookup(*list, table, parser))
     128             :                         return true;
     129             :         }
     130             :         return false;
     131             : }
     132             : 
     133             : static void
     134           0 : print_values(FILE* f, const char *list[])
     135             : {
     136           0 :         const char *sep = "[";
     137           0 :         for (;*list; ++list, sep = ", ")
     138           0 :                 fprintf(f, "%s%s", sep, *list);
     139           0 :         fprintf(f, "]\n");
     140           0 : }
     141             : 
     142             : static void
     143        4436 : check_attr_ird(ATTR_PARAMS)
     144             : {
     145             :         SQLLEN i;
     146             :         SQLRETURN ret;
     147             : 
     148        4436 :         if (attr->type == type_CHARP) {
     149             :                 char buf[256];
     150             :                 SQLSMALLINT len;
     151             : 
     152         144 :                 ret = SQLColAttribute(odbc_stmt, 1, attr->value, buf, sizeof(buf), &len, NULL);
     153         144 :                 if (!SQL_SUCCEEDED(ret))
     154           0 :                         odbc_fatal(parser, ": failure not expected\n");
     155         144 :                 buf[sizeof(buf)-1] = 0;
     156         216 :                 if (!is_contained(C((SQLTCHAR*) buf), expected_values)) {
     157           0 :                         g_result = 1;
     158           0 :                         fprintf(stderr, "Line %u: invalid %s got %s expected ", odbc_line_num(parser), attr->name, buf);
     159           0 :                         print_values(stderr, expected_values);
     160             :                 }
     161             :                 return;
     162             :         }
     163             : 
     164        4292 :         i = 0xdeadbeef;
     165        4292 :         ret = SQLColAttribute(odbc_stmt, 1, attr->value, NULL, SQL_IS_INTEGER, NULL, &i);
     166        4292 :         if (!SQL_SUCCEEDED(ret))
     167           0 :                 odbc_fatal(parser, ": failure not expected\n");
     168             :         /* SQL_DESC_LENGTH is the same of SQLDescribeCol len */
     169        4292 :         if (attr->value == SQL_DESC_LENGTH) {
     170             :                 SQLSMALLINT scale, si;
     171             :                 SQLULEN prec;
     172         516 :                 CHKDescribeCol(1, NULL, 0, NULL, &si, &prec, &scale, &si, "S");
     173         516 :                 if (i != prec)
     174           0 :                         odbc_fatal(parser, ": attr %s SQLDescribeCol len %ld != SQLColAttribute len %ld\n",
     175             :                                    attr->name, (long) prec, (long) i);
     176             :         }
     177        4292 :         if (attr->value == SQL_DESC_SCALE) {
     178             :                 SQLSMALLINT scale, si;
     179             :                 SQLULEN prec;
     180         516 :                 CHKDescribeCol(1, NULL, 0, NULL, &si, &prec, &scale, &si, "S");
     181         516 :                 if (i != scale)
     182           0 :                         odbc_fatal(parser, ": attr %s SQLDescribeCol scale %ld != SQLColAttribute len %ld\n",
     183             :                                    attr->name, (long) scale, (long) i);
     184             :         }
     185        8584 :         if (!is_contained_lookup(i, expected_values, attr->lookup, parser)) {
     186           0 :                 g_result = 1;
     187           0 :                 fprintf(stderr, "Line %u: invalid %s got %s expected ", odbc_line_num(parser), attr->name, unlookup(i, attr->lookup));
     188           0 :                 print_values(stderr, expected_values);
     189             :         }
     190             : }
     191             : 
     192             : static void
     193          10 : check_attr_ard(ATTR_PARAMS)
     194             : {
     195             :         SQLINTEGER i, ind;
     196             :         SQLSMALLINT si;
     197             :         SQLLEN li;
     198             :         SQLRETURN ret;
     199          10 :         SQLHDESC desc = SQL_NULL_HDESC;
     200             :         char buf[256];
     201             : 
     202             :         /* get ARD */
     203          10 :         SQLGetStmtAttr(odbc_stmt, SQL_ATTR_APP_ROW_DESC, &desc, sizeof(desc), &ind);
     204             : 
     205          10 :         ret = SQL_ERROR;
     206          10 :         switch (attr->type) {
     207           0 :         case type_INTEGER:
     208           0 :                 i = 0xdeadbeef;
     209           0 :                 ret = SQLGetDescField(desc, 1, attr->value, (SQLPOINTER) & i, sizeof(SQLINTEGER), &ind);
     210           0 :                 li = i;
     211           0 :                 break;
     212          10 :         case type_SMALLINT:
     213          10 :                 si = 0xbeef;
     214          10 :                 ret = SQLGetDescField(desc, 1, attr->value, (SQLPOINTER) & si, sizeof(SQLSMALLINT), &ind);
     215          10 :                 li = si;
     216          10 :                 break;
     217           0 :         case type_LEN:
     218           0 :                 li = 0xdeadbeef;
     219           0 :                 ret = SQLGetDescField(desc, 1, attr->value, (SQLPOINTER) & li, sizeof(SQLLEN), &ind);
     220           0 :                 break;
     221           0 :         case type_CHARP:
     222           0 :                 ret = SQLGetDescField(desc, 1, attr->value, buf, sizeof(buf), &ind);
     223           0 :                 if (!SQL_SUCCEEDED(ret))
     224           0 :                         odbc_fatal(parser, ": failure not expected\n");
     225           0 :                 if (!is_contained(C((SQLTCHAR*) buf), expected_values)) {
     226           0 :                         g_result = 1;
     227           0 :                         fprintf(stderr, "Line %u: invalid %s got %s expected ", odbc_line_num(parser), attr->name, buf);
     228           0 :                         print_values(stderr, expected_values);
     229             :                 }
     230           0 :                 return;
     231             :         }
     232          10 :         if (!SQL_SUCCEEDED(ret))
     233           0 :                 odbc_fatal(parser, ": failure not expected\n");
     234          20 :         if (!is_contained_lookup(li, expected_values, attr->lookup, parser)) {
     235           0 :                 g_result = 1;
     236           0 :                 fprintf(stderr, "Line %u: invalid %s got %s expected ", odbc_line_num(parser), attr->name,
     237             :                         unlookup(li, attr->lookup));
     238           0 :                 print_values(stderr, expected_values);
     239             :         }
     240             : }
     241             : 
     242             : /* do not retry any attribute just return expected value so to make caller happy */
     243             : static void
     244         438 : check_attr_none(ATTR_PARAMS)
     245             : {
     246         438 : }
     247             : 
     248          10 : TEST_MAIN()
     249             : {
     250          10 :         bool cond = true;
     251             : #define TEST_FILE "describecol.in"
     252          10 :         const char *in_file = FREETDS_SRCDIR "/" TEST_FILE;
     253             :         FILE *f;
     254             :         SQLINTEGER i;
     255             :         SQLLEN len;
     256          10 :         check_attr_t check_attr_p = check_attr_none;
     257             :         odbc_parser *parser;
     258             : 
     259          10 :         odbc_connect();
     260          10 :         odbc_command("SET TEXTSIZE 4096");
     261             : 
     262          10 :         SQLBindCol(odbc_stmt, 1, SQL_C_SLONG, &i, sizeof(i), &len);
     263             : 
     264          10 :         f = fopen(in_file, "r");
     265          10 :         if (!f)
     266           0 :                 f = fopen(TEST_FILE, "r");
     267          10 :         if (!f) {
     268           0 :                 fprintf(stderr, "error opening test file\n");
     269           0 :                 exit(1);
     270             :         }
     271             : 
     272             :         /* cache version */
     273          10 :         odbc_tds_version();
     274             : 
     275          10 :         parser = odbc_init_parser(f);
     276             :         for (;;) {
     277             :                 char *p;
     278             :                 const char *cmd;
     279             : 
     280        6850 :                 cmd = odbc_get_cmd_line(parser, &p, &cond);
     281        6850 :                 if (!cmd)
     282             :                         break;
     283             : 
     284        6840 :                 ODBC_FREE();
     285             : 
     286        6840 :                 if (strcmp(cmd, "odbc") == 0) {
     287          10 :                         int odbc3 = get_int(odbc_get_tok(&p), parser) == 3 ? 1 : 0;
     288             : 
     289        1312 :                         if (!cond) continue;
     290             : 
     291          10 :                         if (odbc_use_version3 != odbc3) {
     292          10 :                                 odbc_use_version3 = odbc3;
     293          10 :                                 odbc_disconnect();
     294          10 :                                 odbc_connect();
     295          10 :                                 odbc_command("SET TEXTSIZE 4096");
     296          10 :                                 SQLBindCol(odbc_stmt, 1, SQL_C_SLONG, &i, sizeof(i), &len);
     297             :                         }
     298             :                 }
     299             : 
     300             :                 /* select type */
     301        6840 :                 if (strcmp(cmd, "select") == 0) {
     302         700 :                         const char *type = odbc_get_str(parser, &p);
     303         700 :                         const char *value = odbc_get_str(parser, &p);
     304             :                         char sql[1024];
     305             : 
     306         876 :                         if (!cond) continue;
     307             : 
     308         574 :                         SQLMoreResults(odbc_stmt);
     309         574 :                         odbc_reset_statement();
     310             : 
     311         574 :                         snprintf(sql, sizeof(sql), "SELECT CONVERT(%s, %s) AS col", type, value);
     312             : 
     313             :                         /* ignore error, we only need precision of known types */
     314         574 :                         check_attr_p = check_attr_none;
     315         574 :                         if (odbc_command_with_result(odbc_stmt, sql) != SQL_SUCCESS) {
     316          50 :                                 odbc_reset_statement();
     317          50 :                                 SQLBindCol(odbc_stmt, 1, SQL_C_SLONG, &i, sizeof(i), &len);
     318          50 :                                 continue;
     319             :                         }
     320             : 
     321         524 :                         CHKFetch("SI");
     322         524 :                         SQLBindCol(odbc_stmt, 1, SQL_C_SLONG, &i, sizeof(i), &len);
     323         524 :                         check_attr_p = check_attr_ird;
     324             :                 }
     325             : 
     326             :                 /* set attribute */
     327        6664 :                 if (strcmp(cmd, "set") == 0) {
     328         280 :                         const struct attribute *attr = lookup_attr(odbc_get_tok(&p), parser);
     329         280 :                         const char *value = odbc_get_str(parser, &p);
     330             :                         SQLHDESC desc;
     331             :                         SQLRETURN ret;
     332             :                         SQLINTEGER ind;
     333             : 
     334         280 :                         if (!value)
     335           0 :                                 odbc_fatal(parser, ": value not defined\n");
     336             : 
     337         280 :                         if (!cond) continue;
     338             : 
     339             :                         /* get ARD */
     340         120 :                         SQLGetStmtAttr(odbc_stmt, SQL_ATTR_APP_ROW_DESC, &desc, sizeof(desc), &ind);
     341             : 
     342         120 :                         ret = SQL_ERROR;
     343         120 :                         switch (attr->type) {
     344           0 :                         case type_INTEGER:
     345           0 :                                 ret = SQLSetDescField(desc, 1, attr->value, TDS_INT2PTR(lookup(value, attr->lookup, parser)),
     346             :                                                       sizeof(SQLINTEGER));
     347           0 :                                 break;
     348         120 :                         case type_SMALLINT:
     349         120 :                                 ret = SQLSetDescField(desc, 1, attr->value, TDS_INT2PTR(lookup(value, attr->lookup, parser)),
     350             :                                                       sizeof(SQLSMALLINT));
     351         120 :                                 break;
     352           0 :                         case type_LEN:
     353           0 :                                 ret = SQLSetDescField(desc, 1, attr->value, TDS_INT2PTR(lookup(value, attr->lookup, parser)),
     354             :                                                       sizeof(SQLLEN));
     355           0 :                                 break;
     356           0 :                         case type_CHARP:
     357           0 :                                 ret = SQLSetDescField(desc, 1, attr->value, (SQLPOINTER) value, SQL_NTS);
     358           0 :                                 break;
     359             :                         }
     360         120 :                         if (!SQL_SUCCEEDED(ret))
     361           0 :                                 odbc_fatal(parser, ": failure not expected setting ARD attribute\n");
     362         120 :                         check_attr_p = check_attr_ard;
     363             :                 }
     364             : 
     365             :                 /* test attribute */
     366        6504 :                 if (strcmp(cmd, "attr") == 0) {
     367        5850 :                         const struct attribute *attr = lookup_attr(odbc_get_tok(&p), parser);
     368             :                         const char *expected[10];
     369             :                         int i;
     370             : 
     371        5850 :                         expected[0] = odbc_get_str(parser, &p);
     372             : 
     373        5850 :                         if (!expected[0])
     374           0 :                                 odbc_fatal(parser, ": value not defined\n");
     375             : 
     376        5850 :                         if (!cond) continue;
     377             : 
     378          40 :                         for (i = 1; ;++i) {
     379        4964 :                                 if (i >= 10)
     380           0 :                                         odbc_fatal(parser, "Too many values in attribute\n");
     381        4924 :                                 p += strspn(p, " \t");
     382        4924 :                                 if (!*p) {
     383        4884 :                                         expected[i] = NULL;
     384             :                                         break;
     385             :                                 }
     386          40 :                                 expected[i] = odbc_get_str(parser, &p);
     387             :                         }
     388        4884 :                         check_attr_p(attr, expected, parser);
     389             :                 }
     390             :         }
     391             : 
     392          10 :         fclose(f);
     393          10 :         odbc_free_parser(parser);
     394          10 :         odbc_disconnect();
     395             : 
     396          10 :         printf("Done.\n");
     397          10 :         return g_result;
     398             : }

Generated by: LCOV version 1.13