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 12:13:41 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)
      16             : {
      17             :         char *end;
      18             :         long l;
      19             : 
      20        3188 :         if (!s)
      21           0 :                 odbc_fatal(": NULL int\n");
      22        3188 :         l = strtol(s, &end, 0);
      23        3188 :         if (end[0])
      24           0 :                 odbc_fatal(": 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)
      36             : {
      37        3444 :         if (!table)
      38        3180 :                 return get_int(name);
      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);
      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)
     145             : {
     146             :         unsigned int i;
     147             : 
     148        4904 :         if (!name)
     149           0 :                 odbc_fatal(": 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(": attribute %s not found\n", name);
     154             :         return NULL;
     155             : }
     156             : 
     157             : #define ATTR_PARAMS const struct attribute *attr, const char *expected_values[]
     158             : typedef void (*check_attr_t) (ATTR_PARAMS);
     159             : 
     160             : static bool
     161             : is_contained(const char *s, const char *list[])
     162             : {
     163           0 :         for (;*list; ++list) {
     164         106 :                 if (strcmp(s, *list) == 0)
     165             :                         return true;
     166             :         }
     167             :         return false;
     168             : }
     169             : 
     170             : static bool
     171             : is_contained_lookup(SQLLEN i, const char *list[], const struct lookup_int *table)
     172             : {
     173          24 :         for (;*list; ++list) {
     174        3364 :                 if (i == lookup(*list, table))
     175             :                         return true;
     176             :         }
     177             :         return false;
     178             : }
     179             : 
     180             : static void
     181           0 : print_values(FILE* f, const char *list[])
     182             : {
     183           0 :         const char *sep = "[";
     184           0 :         for (;*list; ++list, sep = ", ")
     185           0 :                 fprintf(f, "%s%s", sep, *list);
     186           0 :         fprintf(f, "]\n");
     187           0 : }
     188             : 
     189             : static void
     190        3438 : check_attr_ird(ATTR_PARAMS)
     191             : {
     192             :         SQLLEN i;
     193             :         SQLRETURN ret;
     194             : 
     195        3438 :         if (attr->type == type_CHARP) {
     196             :                 char buf[256];
     197             :                 SQLSMALLINT len;
     198             : 
     199         106 :                 ret = SQLColAttribute(odbc_stmt, 1, attr->value, buf, sizeof(buf), &len, NULL);
     200         106 :                 if (!SQL_SUCCEEDED(ret))
     201           0 :                         odbc_fatal(": failure not expected\n");
     202         106 :                 buf[sizeof(buf)-1] = 0;
     203         159 :                 if (!is_contained(C((SQLTCHAR*) buf), expected_values)) {
     204           0 :                         g_result = 1;
     205           0 :                         fprintf(stderr, "Line %u: invalid %s got %s expected ", odbc_line_num, attr->name, buf);
     206           0 :                         print_values(stderr, expected_values);
     207             :                 }
     208             :                 return;
     209             :         }
     210             : 
     211        3332 :         i = 0xdeadbeef;
     212        3332 :         ret = SQLColAttribute(odbc_stmt, 1, attr->value, NULL, SQL_IS_INTEGER, NULL, &i);
     213        3332 :         if (!SQL_SUCCEEDED(ret))
     214           0 :                 odbc_fatal(": failure not expected\n");
     215             :         /* SQL_DESC_LENGTH is the same of SQLDescribeCol len */
     216        3332 :         if (attr->value == SQL_DESC_LENGTH) {
     217             :                 SQLSMALLINT scale, si;
     218             :                 SQLULEN prec;
     219         398 :                 CHKDescribeCol(1, NULL, 0, NULL, &si, &prec, &scale, &si, "S");
     220         398 :                 if (i != prec)
     221           0 :                         odbc_fatal(": attr %s SQLDescribeCol len %ld != SQLColAttribute len %ld\n", attr->name, (long) prec, (long) i);
     222             :         }
     223        3332 :         if (attr->value == SQL_DESC_SCALE) {
     224             :                 SQLSMALLINT scale, si;
     225             :                 SQLULEN prec;
     226         398 :                 CHKDescribeCol(1, NULL, 0, NULL, &si, &prec, &scale, &si, "S");
     227         398 :                 if (i != scale)
     228           0 :                         odbc_fatal(": attr %s SQLDescribeCol scale %ld != SQLColAttribute len %ld\n", attr->name, (long) scale, (long) i);
     229             :         }
     230        6664 :         if (!is_contained_lookup(i, expected_values, attr->lookup)) {
     231           0 :                 g_result = 1;
     232           0 :                 fprintf(stderr, "Line %u: invalid %s got %s expected ", odbc_line_num, attr->name, unlookup(i, attr->lookup));
     233           0 :                 print_values(stderr, expected_values);
     234             :         }
     235             : }
     236             : 
     237             : static void
     238           8 : check_attr_ard(ATTR_PARAMS)
     239             : {
     240             :         SQLINTEGER i, ind;
     241             :         SQLSMALLINT si;
     242             :         SQLLEN li;
     243             :         SQLRETURN ret;
     244           8 :         SQLHDESC desc = SQL_NULL_HDESC;
     245             :         char buf[256];
     246             : 
     247             :         /* get ARD */
     248           8 :         SQLGetStmtAttr(odbc_stmt, SQL_ATTR_APP_ROW_DESC, &desc, sizeof(desc), &ind);
     249             : 
     250           8 :         ret = SQL_ERROR;
     251           8 :         switch (attr->type) {
     252           0 :         case type_INTEGER:
     253           0 :                 i = 0xdeadbeef;
     254           0 :                 ret = SQLGetDescField(desc, 1, attr->value, (SQLPOINTER) & i, sizeof(SQLINTEGER), &ind);
     255           0 :                 li = i;
     256           0 :                 break;
     257           8 :         case type_SMALLINT:
     258           8 :                 si = 0xbeef;
     259           8 :                 ret = SQLGetDescField(desc, 1, attr->value, (SQLPOINTER) & si, sizeof(SQLSMALLINT), &ind);
     260           8 :                 li = si;
     261           8 :                 break;
     262           0 :         case type_LEN:
     263           0 :                 li = 0xdeadbeef;
     264           0 :                 ret = SQLGetDescField(desc, 1, attr->value, (SQLPOINTER) & li, sizeof(SQLLEN), &ind);
     265           0 :                 break;
     266           0 :         case type_CHARP:
     267           0 :                 ret = SQLGetDescField(desc, 1, attr->value, buf, sizeof(buf), &ind);
     268           0 :                 if (!SQL_SUCCEEDED(ret))
     269           0 :                         odbc_fatal(": failure not expected\n");
     270           0 :                 if (!is_contained(C((SQLTCHAR*) buf), expected_values)) {
     271           0 :                         g_result = 1;
     272           0 :                         fprintf(stderr, "Line %u: invalid %s got %s expected ", odbc_line_num, attr->name, buf);
     273           0 :                         print_values(stderr, expected_values);
     274             :                 }
     275           0 :                 return;
     276             :         }
     277           8 :         if (!SQL_SUCCEEDED(ret))
     278           0 :                 odbc_fatal(": failure not expected\n");
     279          16 :         if (!is_contained_lookup(li, expected_values, attr->lookup)) {
     280           0 :                 g_result = 1;
     281           0 :                 fprintf(stderr, "Line %u: invalid %s got %s expected ", odbc_line_num, attr->name, unlookup(li, attr->lookup));
     282           0 :                 print_values(stderr, expected_values);
     283             :         }
     284             : }
     285             : 
     286             : /* do not retry any attribute just return expected value so to make caller happy */
     287             : static void
     288         368 : check_attr_none(ATTR_PARAMS)
     289             : {
     290         368 : }
     291             : 
     292             : int
     293           8 : main(int argc, char *argv[])
     294             : {
     295           8 :         int cond = 1;
     296             : #define TEST_FILE "describecol.in"
     297           8 :         const char *in_file = FREETDS_SRCDIR "/" TEST_FILE;
     298             :         FILE *f;
     299             :         SQLINTEGER i;
     300             :         SQLLEN len;
     301           8 :         check_attr_t check_attr_p = check_attr_none;
     302             : 
     303           8 :         odbc_connect();
     304           8 :         odbc_init_bools();
     305           8 :         odbc_command("SET TEXTSIZE 4096");
     306             : 
     307           8 :         SQLBindCol(odbc_stmt, 1, SQL_C_SLONG, &i, sizeof(i), &len);
     308             : 
     309           8 :         f = fopen(in_file, "r");
     310           8 :         if (!f)
     311           0 :                 f = fopen(TEST_FILE, "r");
     312           8 :         if (!f) {
     313           0 :                 fprintf(stderr, "error opening test file\n");
     314           0 :                 exit(1);
     315             :         }
     316             : 
     317           8 :         odbc_init_parser(f);
     318             :         for (;;) {
     319             :                 char *p;
     320             :                 const char *cmd;
     321             : 
     322        5480 :                 cmd = odbc_get_cmd_line(&p, &cond);
     323        5480 :                 if (!cmd)
     324             :                         break;
     325             : 
     326        5472 :                 ODBC_FREE();
     327             : 
     328        5472 :                 if (strcmp(cmd, "odbc") == 0) {
     329           8 :                         int odbc3 = get_int(odbc_get_tok(&p)) == 3 ? 1 : 0;
     330             : 
     331        1174 :                         if (!cond) continue;
     332             : 
     333           8 :                         if (odbc_use_version3 != odbc3) {
     334           8 :                                 odbc_use_version3 = odbc3;
     335           8 :                                 odbc_disconnect();
     336           8 :                                 odbc_connect();
     337           8 :                                 odbc_command("SET TEXTSIZE 4096");
     338           8 :                                 SQLBindCol(odbc_stmt, 1, SQL_C_SLONG, &i, sizeof(i), &len);
     339             :                         }
     340             :                 }
     341             : 
     342             :                 /* select type */
     343        5472 :                 if (strcmp(cmd, "select") == 0) {
     344         560 :                         const char *type = odbc_get_str(&p);
     345         560 :                         const char *value = odbc_get_str(&p);
     346             :                         char sql[1024];
     347             : 
     348         716 :                         if (!cond) continue;
     349             : 
     350         446 :                         SQLMoreResults(odbc_stmt);
     351         446 :                         odbc_reset_statement();
     352             : 
     353         446 :                         snprintf(sql, sizeof(sql), "SELECT CONVERT(%s, %s) AS col", type, value);
     354             : 
     355             :                         /* ignore error, we only need precision of known types */
     356         446 :                         check_attr_p = check_attr_none;
     357         446 :                         if (odbc_command_with_result(odbc_stmt, sql) != SQL_SUCCESS) {
     358          42 :                                 odbc_reset_statement();
     359          42 :                                 SQLBindCol(odbc_stmt, 1, SQL_C_SLONG, &i, sizeof(i), &len);
     360          42 :                                 continue;
     361             :                         }
     362             : 
     363         404 :                         CHKFetch("SI");
     364         404 :                         SQLBindCol(odbc_stmt, 1, SQL_C_SLONG, &i, sizeof(i), &len);
     365         404 :                         check_attr_p = check_attr_ird;
     366             :                 }
     367             : 
     368             :                 /* set attribute */
     369        5316 :                 if (strcmp(cmd, "set") == 0) {
     370         224 :                         const struct attribute *attr = lookup_attr(odbc_get_tok(&p));
     371         224 :                         const char *value = odbc_get_str(&p);
     372             :                         SQLHDESC desc;
     373             :                         SQLRETURN ret;
     374             :                         SQLINTEGER ind;
     375             : 
     376         224 :                         if (!value)
     377           0 :                                 odbc_fatal(": value not defined\n");
     378             : 
     379         224 :                         if (!cond) continue;
     380             : 
     381             :                         /* get ARD */
     382          80 :                         SQLGetStmtAttr(odbc_stmt, SQL_ATTR_APP_ROW_DESC, &desc, sizeof(desc), &ind);
     383             : 
     384          80 :                         ret = SQL_ERROR;
     385          80 :                         switch (attr->type) {
     386           0 :                         case type_INTEGER:
     387           0 :                                 ret = SQLSetDescField(desc, 1, attr->value, TDS_INT2PTR(lookup(value, attr->lookup)),
     388             :                                                       sizeof(SQLINTEGER));
     389           0 :                                 break;
     390          80 :                         case type_SMALLINT:
     391          80 :                                 ret = SQLSetDescField(desc, 1, attr->value, TDS_INT2PTR(lookup(value, attr->lookup)),
     392             :                                                       sizeof(SQLSMALLINT));
     393          80 :                                 break;
     394           0 :                         case type_LEN:
     395           0 :                                 ret = SQLSetDescField(desc, 1, attr->value, TDS_INT2PTR(lookup(value, attr->lookup)),
     396             :                                                       sizeof(SQLLEN));
     397           0 :                                 break;
     398           0 :                         case type_CHARP:
     399           0 :                                 ret = SQLSetDescField(desc, 1, attr->value, (SQLPOINTER) value, SQL_NTS);
     400           0 :                                 break;
     401             :                         }
     402          80 :                         if (!SQL_SUCCEEDED(ret))
     403           0 :                                 odbc_fatal(": failure not expected setting ARD attribute\n");
     404          80 :                         check_attr_p = check_attr_ard;
     405             :                 }
     406             : 
     407             :                 /* test attribute */
     408        5172 :                 if (strcmp(cmd, "attr") == 0) {
     409        4680 :                         const struct attribute *attr = lookup_attr(odbc_get_tok(&p));
     410             :                         const char *expected[10];
     411             :                         int i;
     412             : 
     413        4680 :                         expected[0] = odbc_get_str(&p);
     414             : 
     415        4680 :                         if (!expected[0])
     416           0 :                                 odbc_fatal(": value not defined\n");
     417             : 
     418        4680 :                         if (!cond) continue;
     419             : 
     420          32 :                         for (i = 1; ;++i) {
     421        3878 :                                 if (i >= 10)
     422           0 :                                         odbc_fatal("Too many values in attribute\n");
     423        3846 :                                 p += strspn(p, " \t");
     424        3846 :                                 if (!*p) {
     425        3814 :                                         expected[i] = NULL;
     426             :                                         break;
     427             :                                 }
     428          32 :                                 expected[i] = odbc_get_str(&p);
     429             :                         }
     430        3814 :                         check_attr_p(attr, expected);
     431             :                 }
     432             :         }
     433             : 
     434           8 :         fclose(f);
     435           8 :         odbc_clear_bools();
     436           8 :         odbc_disconnect();
     437             : 
     438           8 :         printf("Done.\n");
     439           8 :         return g_result;
     440             : }

Generated by: LCOV version 1.13