LCOV - code coverage report
Current view: top level - src/odbc/unittests - funccall.c (source / functions) Hit Total Coverage
Test: FreeTDS coverage Lines: 113 126 89.7 %
Date: 2025-04-23 23:01:24 Functions: 3 3 100.0 %

          Line data    Source code
       1             : #include "common.h"
       2             : 
       3             : /* Test for {?=call store(?)} syntax and run */
       4             : 
       5             : static void test_with_conversions(void);
       6             : static void test_with_dbname(void);
       7             : 
       8          10 : TEST_MAIN()
       9             : {
      10             :         SQLINTEGER input, output;
      11             :         SQLLEN ind, ind2, ind3, ind4;
      12             :         SQLINTEGER out1;
      13             :         char out2[30];
      14             : 
      15          10 :         odbc_connect();
      16             : 
      17          10 :         odbc_command("IF OBJECT_ID('simpleresult') IS NOT NULL DROP PROC simpleresult");
      18             : 
      19          10 :         odbc_command("create proc simpleresult @i int as begin return @i end");
      20             : 
      21          10 :         CHKBindParameter(2, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &input, 0, &ind2, "S");
      22          10 :         CHKBindParameter(1, SQL_PARAM_OUTPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &output, 0, &ind, "S");
      23             : 
      24          10 :         CHKPrepare(T("{ \n?\t\r= call simpleresult(?)}"), SQL_NTS, "S");
      25             : 
      26          10 :         input = 123;
      27          10 :         ind2 = sizeof(input);
      28          10 :         output = 0xdeadbeef;
      29          10 :         CHKExecute("S");
      30             : 
      31          10 :         if (output != 123) {
      32           0 :                 printf("Invalid result\n");
      33           0 :                 exit(1);
      34             :         }
      35             : 
      36             :         /* should return "Invalid cursor state" */
      37          10 :         if (SQLFetch(odbc_stmt) != SQL_ERROR) {
      38           0 :                 printf("Data not expected\n");
      39           0 :                 exit(1);
      40             :         }
      41          10 :         ODBC_CHECK_COLS(0);
      42             : 
      43             :         /* just to reset some possible buffers */
      44          10 :         odbc_command("DECLARE @i INT");
      45             : 
      46             :         /* same test but with SQLExecDirect and same bindings */
      47          10 :         input = 567;
      48          10 :         ind2 = sizeof(input);
      49          10 :         output = 0xdeadbeef;
      50          10 :         CHKExecDirect(T("{?=call simpleresult(?)}"), SQL_NTS, "S");
      51             : 
      52          10 :         if (output != 567) {
      53           0 :                 fprintf(stderr, "Invalid result\n");
      54           0 :                 exit(1);
      55             :         }
      56             : 
      57             :         /* should return "Invalid cursor state" */
      58          10 :         CHKFetch("E");
      59             : 
      60          10 :         odbc_command("drop proc simpleresult");
      61             : 
      62          10 :         odbc_command("IF OBJECT_ID('simpleresult2') IS NOT NULL DROP PROC simpleresult2");
      63             : 
      64             :         /* force cursor close */
      65          10 :         SQLCloseCursor(odbc_stmt);
      66             : 
      67             :         /* test output parameter */
      68          10 :         odbc_command("create proc simpleresult2 @i int, @x int output, @y varchar(20) output as begin select @x = 6789 select @y = 'test foo' return @i end");
      69             : 
      70          10 :         CHKBindParameter(1, SQL_PARAM_OUTPUT, SQL_C_SLONG, SQL_INTEGER, 0,  0, &output, 0,            &ind,  "S");
      71          10 :         CHKBindParameter(2, SQL_PARAM_INPUT,  SQL_C_SLONG, SQL_INTEGER, 0,  0, &input,  0,            &ind2, "S");
      72          10 :         CHKBindParameter(3, SQL_PARAM_OUTPUT, SQL_C_SLONG, SQL_INTEGER, 0,  0, &out1,   0,            &ind3, "S");
      73          10 :         CHKBindParameter(4, SQL_PARAM_OUTPUT, SQL_C_CHAR,  SQL_VARCHAR, 20, 0, out2,    sizeof(out2), &ind4, "S");
      74             : 
      75          10 :         CHKPrepare(T("{ \n?\t\r= call simpleresult2(?,?,?)}"), SQL_NTS, "S");
      76             : 
      77          10 :         input = 987;
      78          10 :         ind2 = sizeof(input);
      79          10 :         out1 = 888;
      80          10 :         output = 0xdeadbeef;
      81          10 :         ind3 = SQL_DATA_AT_EXEC;
      82          10 :         ind4 = SQL_DEFAULT_PARAM;
      83          10 :         strcpy(out2, "bad!");
      84          10 :         CHKExecute("S");
      85             : 
      86          10 :         if (output != 987 || ind3 <= 0 || ind4 <= 0 || out1 != 6789 || strcmp(out2, "test foo") != 0) {
      87           0 :                 printf("ouput = %d ind3 = %d ind4 = %d out1 = %d out2 = %s\n", (int) output, (int) ind3, (int) ind4, (int) out1,
      88             :                        out2);
      89           0 :                 printf("Invalid result\n");
      90           0 :                 exit(1);
      91             :         }
      92             : 
      93             :         /* should return "Invalid cursor state" */
      94          10 :         CHKFetch("E");
      95             : 
      96          10 :         ODBC_CHECK_COLS(0);
      97             : 
      98          10 :         odbc_command("drop proc simpleresult2");
      99             : 
     100             :         /*
     101             :          * test from shiv kumar
     102             :          * Cfr ML 2006-11-21 "specifying a 0 for the StrLen_or_IndPtr in the
     103             :          * SQLBindParameter call is not working on AIX"
     104             :          */
     105          10 :         odbc_command("IF OBJECT_ID('rpc_read') IS NOT NULL DROP PROC rpc_read");
     106             : 
     107          10 :         odbc_reset_statement();
     108             : 
     109          10 :         odbc_command("create proc rpc_read @i int, @x timestamp as begin select 1 return 1234 end");
     110          10 :         SQLCloseCursor(odbc_stmt);
     111             : 
     112          10 :         CHKPrepare(T("{ ? = CALL rpc_read ( ?, ? ) }"), SQL_NTS, "S");
     113             : 
     114          10 :         ind = 0;
     115          10 :         CHKBindParameter(1, SQL_PARAM_OUTPUT, SQL_C_LONG, SQL_INTEGER, 0, 0, &output, 0, &ind, "S");
     116             : 
     117          10 :         ind2 = 0;
     118          10 :         CHKBindParameter(2, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER, 0, 0, &input, 0, &ind2, "S");
     119             : 
     120          10 :         ind3 = 8;
     121          10 :         CHKBindParameter(3, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_VARBINARY, 8, 0, out2, 8, &ind3, "S");
     122             : 
     123          10 :         CHKExecute("S");
     124             : 
     125          10 :         CHKFetch("S");
     126             : 
     127          10 :         CHKFetch("No");
     128             : 
     129          10 :         odbc_reset_statement();
     130          10 :         odbc_command("drop proc rpc_read");
     131             : 
     132             :         /*
     133             :          * Test from Joao Amaral
     134             :          * This test SQLExecute where a store procedure returns no result
     135             :          * This seems similar to a previous one but use set instead of select
     136             :          * (with is supported only by mssql and do not return all stuff as 
     137             :          * select does)
     138             :          */
     139          10 :         if (odbc_db_is_microsoft()) {
     140             : 
     141           8 :                 odbc_reset_statement();
     142             : 
     143           8 :                 odbc_command("IF OBJECT_ID('sp_test') IS NOT NULL DROP PROC sp_test");
     144           8 :                 odbc_command("create proc sp_test @res int output as set @res = 456");
     145             : 
     146           8 :                 odbc_reset_statement();
     147             : 
     148           8 :                 CHKPrepare(T("{ call sp_test(?)}"), SQL_NTS, "S");
     149           8 :                 CHKBindParameter(1, SQL_PARAM_OUTPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &output, 0, &ind, "S");
     150             : 
     151           8 :                 output = 0xdeadbeef;
     152           8 :                 CHKExecute("S");
     153             : 
     154           8 :                 if (output != 456) {
     155           0 :                         fprintf(stderr, "Invalid result %d(%x)\n", (int) output, (int) output);
     156           0 :                         return 1;
     157             :                 }
     158           8 :                 odbc_command("drop proc sp_test");
     159             :         }
     160          10 :         odbc_disconnect();
     161             : 
     162          10 :         if (odbc_db_is_microsoft()) {
     163           8 :                 odbc_use_version3 = 1;
     164           8 :                 odbc_connect();
     165             : 
     166           8 :                 test_with_conversions();
     167           8 :                 test_with_dbname();
     168           8 :                 odbc_disconnect();
     169             :         }
     170             : 
     171          10 :         printf("Done.\n");
     172          10 :         return 0;
     173             : }
     174             : 
     175             : static void
     176           8 : test_with_conversions(void)
     177             : {
     178             :         SQLLEN ind, ind2, ind3;
     179             :         char out2[30];
     180             : 
     181             :         /*
     182             :          * test from Bower, Wayne
     183             :          * Cfr ML 2012-03-02 "[freetds] [unixODBC][Driver Manager]Function sequence error (SQL-HY010)"
     184             :          */
     185           8 :         odbc_command("IF OBJECT_ID('TMP_SP_Test_ODBC') IS NOT NULL DROP PROC TMP_SP_Test_ODBC");
     186           8 :         odbc_command("create proc TMP_SP_Test_ODBC @i int,\n@o int output\nas\nset nocount on\nselect @o = 55\nreturn 9\n");
     187           8 :         odbc_reset_statement();
     188             : 
     189           8 :         CHKPrepare(T("{ ? = call TMP_SP_Test_ODBC (?, ?) }"), SQL_NTS, "S");
     190             : 
     191           8 :         ind2 = 2;
     192           8 :         CHKBindParameter(2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR, 80, 0, "10", 2, &ind2, "S");
     193           8 :         ind3 = SQL_NULL_DATA;
     194           8 :         strcpy(out2, " ");
     195           8 :         CHKBindParameter(3, SQL_PARAM_INPUT_OUTPUT, SQL_C_CHAR, SQL_VARCHAR, 0, 1, out2, 29, &ind3, "S");
     196           8 :         ind = 1;
     197           8 :         CHKBindParameter(1, SQL_PARAM_INPUT_OUTPUT, SQL_C_CHAR, SQL_VARCHAR, 0, 1, out2, 29, &ind, "S");
     198             : 
     199             :         /* mssql returns SUCCESS */
     200           8 :         CHKExecute("No");
     201             : 
     202           8 :         ODBC_CHECK_COLS(0);
     203             : 
     204           8 :         odbc_reset_statement();
     205           8 :         odbc_command("drop proc TMP_SP_Test_ODBC");
     206           8 : }
     207             : 
     208             : static void
     209           8 : test_with_dbname(void)
     210             : {
     211             :         SQLINTEGER len;
     212             :         SQLTCHAR out[512];
     213             :         char sql[1024];
     214             :         SQLINTEGER output;
     215             :         SQLLEN ind;
     216           8 :         ODBC_BUF *odbc_buf = NULL;
     217             : 
     218           8 :         len = sizeof(out);
     219           8 :         CHKGetConnectAttr(SQL_ATTR_CURRENT_CATALOG, (SQLPOINTER) out, sizeof(out), &len, "SI");
     220             : 
     221           8 :         odbc_command("IF OBJECT_ID('TMP_SP_Test_ODBC') IS NOT NULL DROP PROC TMP_SP_Test_ODBC");
     222           8 :         odbc_command("create proc TMP_SP_Test_ODBC @o int output\nas\nset @o=55\nreturn 3\n");
     223           8 :         odbc_reset_statement();
     224             : 
     225           8 :         sprintf(sql, "{call [%s]..TMP_SP_Test_ODBC(?)}", C(out));
     226           8 :         CHKBindParameter(1, SQL_PARAM_OUTPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &output, 0, &ind, "S");
     227           8 :         CHKPrepare(T(sql), SQL_NTS, "S");
     228             : 
     229           8 :         output = 123;
     230           8 :         ind = sizeof(output);
     231           8 :         CHKExecute("S");
     232             : 
     233           8 :         if (output != 55) {
     234           0 :                 printf("Invalid result\n");
     235           0 :                 exit(1);
     236             :         }
     237             : 
     238           8 :         odbc_reset_statement();
     239           8 :         odbc_command("drop proc TMP_SP_Test_ODBC");
     240           8 :         ODBC_FREE();
     241           8 : }

Generated by: LCOV version 1.13