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

Generated by: LCOV version 1.13