LCOV - code coverage report
Current view: top level - src/odbc/unittests - describecol.c (source / functions) Hit Total Coverage
Test: FreeTDS coverage Lines: 118 183 64.5 %
Date: 2025-01-18 11:50:39 Functions: 7 9 77.8 %

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

Generated by: LCOV version 1.13