LCOV - code coverage report
Current view: top level - src/odbc/unittests - describeparam.c (source / functions) Hit Total Coverage
Test: FreeTDS coverage Lines: 154 164 93.9 %
Date: 2025-02-21 09:36:06 Functions: 3 3 100.0 %

          Line data    Source code
       1             : /* Test SQLDescribeParam */
       2             : 
       3             : #include "common.h"
       4             : 
       5             : static void
       6          82 : check_int(bool cond, long int value, const char *msg, int line)
       7             : {
       8          82 :         if (cond)
       9          82 :                 return;
      10           0 :         fprintf(stderr, "Invalid value %ld at line %d, check: %s\n", value, line, msg);
      11           0 :         exit(1);
      12             : }
      13             : 
      14             : #define check_int(value, cond, expected) \
      15             :         check_int(value cond expected, value, #value " " #cond " " #expected, __LINE__)
      16             : 
      17             : static void
      18          32 : check_type(bool cond, SQLSMALLINT value, const char *msg, int line)
      19             : {
      20          32 :         if (cond)
      21          32 :                 return;
      22           0 :         fprintf(stderr, "Invalid value %d(%s) at line %d, check: %s\n",
      23             :                 value, odbc_lookup_value(value, odbc_sql_types, "???"), line, msg);
      24           0 :         exit(1);
      25             : }
      26             : 
      27             : #define check_type(value, cond, expected) \
      28             :         check_type(value cond expected, value, #value " " #cond " " #expected, __LINE__)
      29             : 
      30             : int
      31          10 : main(void)
      32             : {
      33             :         SQLSMALLINT num_params;
      34             :         SQLSMALLINT sql_type;
      35             :         SQLULEN size;
      36             :         SQLSMALLINT digits, scale, nullable, count;
      37             :         SQLHDESC ipd, apd;
      38             :         SQLINTEGER ind;
      39          10 :         SQLLEN sql_nts = SQL_NTS;
      40             :         SQLINTEGER id;
      41             :         const char *env;
      42             : 
      43          10 :         odbc_use_version3 = 1;
      44          10 :         odbc_connect();
      45             : 
      46          10 :         if (!odbc_db_is_microsoft() || odbc_db_version_int() < 0x0b000000u) {
      47           8 :                 odbc_disconnect();
      48           8 :                 printf("SQLDescribeParam implementation requires MSSQL 2012+\n");
      49           8 :                 odbc_test_skipped();
      50           0 :                 return 0;
      51             :         }
      52             : 
      53           2 :         odbc_command("IF OBJECT_ID('describe') IS NOT NULL DROP TABLE describe");
      54           2 :         odbc_command("CREATE TABLE describe(i int NOT NULL, vc VARCHAR(100) NULL, "
      55             :                      "vb VARBINARY(100) NULL, num NUMERIC(17,5) NULL)");
      56           2 :         odbc_reset_statement();
      57             : 
      58           2 :         CHKPrepare(T("INSERT INTO describe(i, vc, num) VALUES(?, ?, ?)"), SQL_NTS, "S");
      59             : 
      60             :         /* we prepared a query with 3 parameters, we should have 3 parameters */
      61           2 :         CHKNumParams(&num_params, "S");
      62           2 :         check_int(num_params, ==, 3);
      63             : 
      64           2 :         CHKGetStmtAttr(SQL_ATTR_IMP_PARAM_DESC, &ipd, sizeof(ipd), &ind, "S");
      65           2 :         CHKGetStmtAttr(SQL_ATTR_APP_PARAM_DESC, &apd, sizeof(apd), &ind, "S");
      66             : 
      67             :         /* check we have no parameters on IPD and APD */
      68           2 :         CHKGetDescField(ipd, 0, SQL_DESC_COUNT, &count, sizeof(count), &ind, "S");
      69           2 :         check_int(count, ==, 0);
      70           2 :         CHKGetDescField(apd, 0, SQL_DESC_COUNT, &count, sizeof(count), &ind, "S");
      71           2 :         check_int(count, ==, 0);
      72             : 
      73             :         /* get some parameters */
      74           2 :         CHKDescribeParam(0, &sql_type, &size, &digits, &nullable, "E");
      75           2 :         CHKDescribeParam(1, &sql_type, &size, &digits, &nullable, "S");
      76           2 :         check_type(sql_type, ==, SQL_INTEGER);
      77           2 :         check_int(size, ==, 10);
      78           2 :         check_int(digits, ==, 0);
      79           2 :         check_int(nullable, ==, SQL_TRUE);
      80           2 :         CHKGetDescField(ipd, 1, SQL_DESC_TYPE, &sql_type, sizeof(SQLSMALLINT), &ind, "S");
      81           2 :         check_type(sql_type, ==, SQL_INTEGER);
      82           2 :         CHKGetDescField(ipd, 1, SQL_DESC_CONCISE_TYPE, &sql_type, sizeof(SQLSMALLINT), &ind, "S");
      83           2 :         check_type(sql_type, ==, SQL_INTEGER);
      84           2 :         CHKGetDescField(ipd, 1, SQL_DESC_LENGTH, &size, sizeof(SQLULEN), &ind, "S");
      85           2 :         check_int(size, ==, 10);
      86           2 :         CHKGetDescField(ipd, 1, SQL_DESC_PRECISION, &digits, sizeof(SQLSMALLINT), &ind, "S");
      87             :         /* TODO sligthly difference with MS driver about descriptor handling */
      88           2 :         if (!odbc_driver_is_freetds())
      89           0 :                 check_int(digits, ==, 10);
      90           2 :         CHKGetDescField(ipd, 1, SQL_DESC_SCALE, &scale, sizeof(SQLSMALLINT), &ind, "S");
      91           2 :         check_int(scale, ==, 0);
      92             : 
      93           2 :         CHKDescribeParam(2, &sql_type, &size, &digits, &nullable, "S");
      94           2 :         check_type(sql_type, ==, SQL_VARCHAR);
      95           2 :         check_int(size, ==, 100);
      96           2 :         check_int(digits, ==, 0);
      97           2 :         check_int(nullable, ==, SQL_TRUE);
      98           2 :         CHKGetDescField(ipd, 2, SQL_DESC_TYPE, &sql_type, sizeof(SQLSMALLINT), &ind, "S");
      99           2 :         check_type(sql_type, ==, SQL_VARCHAR);
     100           2 :         CHKGetDescField(ipd, 2, SQL_DESC_CONCISE_TYPE, &sql_type, sizeof(SQLSMALLINT), &ind, "S");
     101           2 :         check_type(sql_type, ==, SQL_VARCHAR);
     102           2 :         CHKGetDescField(ipd, 2, SQL_DESC_LENGTH, &size, sizeof(SQLULEN), &ind, "S");
     103           2 :         check_int(size, ==, 100);
     104           2 :         CHKGetDescField(ipd, 2, SQL_DESC_PRECISION, &digits, sizeof(SQLSMALLINT), &ind, "S");
     105           2 :         if (!odbc_driver_is_freetds())
     106           0 :                 check_int(digits, ==, 100);
     107           2 :         CHKGetDescField(ipd, 2, SQL_DESC_SCALE, &scale, sizeof(SQLSMALLINT), &ind, "S");
     108           2 :         check_int(scale, ==, 0);
     109             : 
     110           2 :         CHKDescribeParam(3, &sql_type, &size, &digits, &nullable, "S");
     111           2 :         check_type(sql_type, ==, SQL_NUMERIC);
     112           2 :         check_int(size, ==, 17);
     113           2 :         check_int(digits, ==, 5);
     114           2 :         check_int(nullable, ==, SQL_TRUE);
     115           2 :         CHKGetDescField(ipd, 3, SQL_DESC_TYPE, &sql_type, sizeof(SQLSMALLINT), &ind, "S");
     116           2 :         check_type(sql_type, ==, SQL_NUMERIC);
     117           2 :         CHKGetDescField(ipd, 3, SQL_DESC_CONCISE_TYPE, &sql_type, sizeof(SQLSMALLINT), &ind, "S");
     118           2 :         check_type(sql_type, ==, SQL_NUMERIC);
     119           2 :         CHKGetDescField(ipd, 3, SQL_DESC_LENGTH, &size, sizeof(SQLULEN), &ind, "S");
     120           2 :         check_int(size, ==, 17);
     121           2 :         CHKGetDescField(ipd, 3, SQL_DESC_PRECISION, &digits, sizeof(SQLSMALLINT), &ind, "S");
     122           2 :         check_int(digits, ==, 17);
     123           2 :         CHKGetDescField(ipd, 3, SQL_DESC_SCALE, &scale, sizeof(SQLSMALLINT), &ind, "S");
     124           2 :         check_int(scale, ==, 5);
     125             : 
     126           2 :         CHKDescribeParam(4, &sql_type, &size, &digits, &nullable, "E");
     127             : 
     128             :         /* check parameters were filled on IPD */
     129           2 :         CHKGetDescField(ipd, 0, SQL_DESC_COUNT, &count, sizeof(count), &ind, "S");
     130           2 :         check_int(count, ==, 3);
     131             :         /* APD is not filled */
     132           2 :         CHKGetDescField(apd, 0, SQL_DESC_COUNT, &count, sizeof(count), &ind, "S");
     133           2 :         check_int(count, ==, 0);
     134             : 
     135             :         /*****************************************************************/
     136             : 
     137             :         /* preparing another query  */
     138           2 :         CHKPrepare(T("INSERT INTO describe(i) VALUES(?)"), SQL_NTS, "S");
     139             : 
     140             :         /* we prepared a query with 1 parameter, we should have 1 parameter */
     141           2 :         CHKNumParams(&num_params, "S");
     142           2 :         check_int(num_params, ==, 1);
     143             : 
     144           2 :         CHKPrepare(T("INSERT INTO describe(i, vc) VALUES(?, ?)"), SQL_NTS, "S");
     145             : 
     146             :         /* check we have no parameters on IPD and APD */
     147             :         /* SQLPrepare should clear them */
     148           2 :         CHKGetDescField(ipd, 0, SQL_DESC_COUNT, &count, sizeof(count), &ind, "S");
     149           2 :         check_int(count, ==, 0);
     150           2 :         CHKGetDescField(apd, 0, SQL_DESC_COUNT, &count, sizeof(count), &ind, "S");
     151           2 :         check_int(count, ==, 0);
     152             : 
     153           2 :         CHKNumParams(&num_params, "S");
     154             : 
     155             :         /* check we have no parameters on IPD and APD */
     156             :         /* SQLNumParams does not affect them */
     157           2 :         CHKGetDescField(ipd, 0, SQL_DESC_COUNT, &count, sizeof(count), &ind, "S");
     158           2 :         check_int(count, ==, 0);
     159           2 :         CHKGetDescField(apd, 0, SQL_DESC_COUNT, &count, sizeof(count), &ind, "S");
     160           2 :         check_int(count, ==, 0);
     161             : 
     162           2 :         CHKDescribeParam(1, &sql_type, &size, &digits, &nullable, "S");
     163           2 :         check_type(sql_type, ==, SQL_INTEGER);
     164             : 
     165             :         /* check parameters were filled on IPD */
     166           2 :         CHKGetDescField(ipd, 0, SQL_DESC_COUNT, &count, sizeof(count), &ind, "S");
     167           2 :         check_int(count, ==, 2);
     168             :         /* APD is not filled */
     169           2 :         CHKGetDescField(apd, 0, SQL_DESC_COUNT, &count, sizeof(count), &ind, "S");
     170           2 :         check_int(count, ==, 0);
     171             : 
     172             :         /*****************************************************************/
     173             : 
     174             :         /* bind a parameter, see if affects SQLDescribeParam */
     175           2 :         CHKBindParameter(1, SQL_PARAM_INPUT, SQL_C_LONG, SQL_FLOAT, 10, 0, &id, 0, &sql_nts, "S");
     176           2 :         CHKGetDescField(apd, 0, SQL_DESC_COUNT, &count, sizeof(count), &ind, "S");
     177           2 :         check_int(count, ==, 1);
     178             : 
     179             :         /* what happens preparing another query ? */
     180           2 :         CHKPrepare(T("INSERT INTO describe(vc, i, vb) VALUES(?, ?, ?)"), SQL_NTS, "S");
     181             : 
     182             :         /* type do not change, set one stays */
     183           2 :         CHKDescribeParam(1, &sql_type, &size, &digits, &nullable, "S");
     184           2 :         check_type(sql_type, ==, SQL_FLOAT);
     185             :         /* even this parameter remains */
     186           2 :         CHKDescribeParam(2, &sql_type, &size, &digits, &nullable, "S");
     187           2 :         check_type(sql_type, ==, SQL_VARCHAR);
     188             :         /* additional parameter are not read from server */
     189             :         /* "SQL error 07009 -- [Microsoft][ODBC Driver 18 for SQL Server]Invalid Descriptor Index" */
     190           2 :         CHKDescribeParam(3, &sql_type, &size, &digits, &nullable, "E");
     191             : 
     192           2 :         CHKGetDescField(ipd, 0, SQL_DESC_COUNT, &count, sizeof(count), &ind, "S");
     193           2 :         check_int(count, ==, 2);
     194             :         /* APD remains */
     195           2 :         CHKGetDescField(apd, 0, SQL_DESC_COUNT, &count, sizeof(count), &ind, "S");
     196           2 :         check_int(count, ==, 1);
     197             : 
     198             :         /*****************************************************************/
     199             : 
     200             :         /* try to reset APD */
     201           2 :         CHKSetDescField(apd, 1, SQL_DESC_COUNT, (SQLPOINTER) 0, SQL_IS_SMALLINT, "S");
     202             : 
     203           2 :         CHKPrepare(T("INSERT INTO describe(i) VALUES(?)"), SQL_NTS, "S");
     204             : 
     205             :         /* parameter is not overridden */
     206           2 :         CHKDescribeParam(1, &sql_type, &size, &digits, &nullable, "S");
     207           2 :         check_type(sql_type, ==, SQL_FLOAT);
     208             : 
     209           2 :         CHKGetDescField(ipd, 0, SQL_DESC_COUNT, &count, sizeof(count), &ind, "S");
     210           2 :         check_int(count, ==, 2);
     211           2 :         CHKGetDescField(apd, 0, SQL_DESC_COUNT, &count, sizeof(count), &ind, "S");
     212           2 :         check_int(count, ==, 0);
     213             : 
     214             :         /*****************************************************************/
     215             : 
     216             :         /* try to reset parameters */
     217           2 :         CHKFreeStmt(SQL_RESET_PARAMS, "S");
     218             : 
     219           2 :         CHKPrepare(T("INSERT INTO describe(i) VALUES(?)"), SQL_NTS, "S");
     220             : 
     221             :         /* parameter is overridden */
     222           2 :         CHKDescribeParam(1, &sql_type, &size, &digits, &nullable, "S");
     223           2 :         check_type(sql_type, ==, SQL_INTEGER);
     224             : 
     225           2 :         CHKGetDescField(ipd, 0, SQL_DESC_COUNT, &count, sizeof(count), &ind, "S");
     226           2 :         check_int(count, ==, 1);
     227           2 :         CHKGetDescField(apd, 0, SQL_DESC_COUNT, &count, sizeof(count), &ind, "S");
     228           2 :         check_int(count, ==, 0);
     229             : 
     230             :         /*****************************************************************/
     231             : 
     232             :         /* check what happens if connection is busy (no MARS, pending data) */
     233           2 :         env = getenv("ODBC_MARS");
     234           3 :         if (!env || atoi(env) == 0) {
     235             :                 SQLHSTMT stmt;
     236             : 
     237           1 :                 CHKAllocStmt(&stmt, "S");
     238             : 
     239           1 :                 SWAP_STMT(stmt);
     240           1 :                 CHKExecDirect(T("SELECT * FROM sysobjects"), SQL_NTS, "S");
     241             : 
     242           1 :                 SWAP_STMT(stmt);
     243           1 :                 CHKPrepare(T("INSERT INTO describe(vc) VALUES(?)"), SQL_NTS, "S");
     244             : 
     245           1 :                 CHKDescribeParam(1, &sql_type, &size, &digits, &nullable, "E");
     246           1 :                 odbc_read_error();
     247           1 :                 if (strcmp(odbc_sqlstate, "07009") != 0) {
     248           0 :                         fprintf(stderr, "Unexpected sql state returned: %s\n", odbc_sqlstate);
     249           0 :                         odbc_disconnect();
     250           0 :                         exit(1);
     251             :                 }
     252             : 
     253           1 :                 SWAP_STMT(stmt);
     254           1 :                 CHKMoreResults("SNo");
     255           1 :                 CHKMoreResults("No");
     256           1 :                 CHKFreeStmt(SQL_DROP, "S");
     257             : 
     258           1 :                 SWAP_STMT(stmt);
     259             :         }
     260             : 
     261             :         /*****************************************************************/
     262             : 
     263             :         /* prepare a stored procedure */
     264           2 :         CHKPrepare(T("{?=call sp_tables(?)}"), SQL_NTS, "S");
     265             : 
     266           2 :         CHKDescribeParam(1, &sql_type, &size, &digits, &nullable, "S");
     267           2 :         check_type(sql_type, ==, SQL_INTEGER);
     268           2 :         check_int(size, ==, 10);
     269           2 :         check_int(digits, ==, 0);
     270           2 :         check_int(nullable, ==, SQL_TRUE);
     271           2 :         CHKDescribeParam(2, &sql_type, &size, &digits, &nullable, "S");
     272           2 :         check_type(sql_type, ==, SQL_WVARCHAR);
     273           2 :         check_int(size, ==, 384);
     274           2 :         check_int(digits, ==, 0);
     275           2 :         check_int(nullable, ==, SQL_TRUE);
     276             : 
     277             :         /*****************************************************************/
     278             : 
     279             :         /* cleanup */
     280           2 :         odbc_command("DROP TABLE describe");
     281             : 
     282           2 :         odbc_disconnect();
     283           2 :         return 0;
     284             : }

Generated by: LCOV version 1.13