LCOV - code coverage report
Current view: top level - src/odbc/unittests - rpc.c (source / functions) Hit Total Coverage
Test: FreeTDS coverage Lines: 92 97 94.8 %
Date: 2024-03-23 09:12:27 Functions: 3 3 100.0 %

          Line data    Source code
       1             : /* 
       2             :  * Purpose: Test remote procedure calls
       3             :  * Functions:  
       4             :  */
       5             : 
       6             : #include "common.h"
       7             : #include <assert.h>
       8             : 
       9             : static const char procedure_sql[] = 
      10             :                 "CREATE PROCEDURE %s \n"
      11             :                         "  @null_input varchar(30) OUTPUT \n"
      12             :                         ", @first_type varchar(30) OUTPUT \n"
      13             :                         ", @nullout int OUTPUT\n"
      14             :                         ", @nrows int OUTPUT \n"
      15             :                         ", @c varchar(20)\n"
      16             :                 "AS \n"
      17             :                 "BEGIN \n"
      18             :                         "select @null_input = max(convert(varchar(30), name)) from systypes \n"
      19             :                         "select @first_type = min(convert(varchar(30), name)) from systypes \n"
      20             :                         /* #1 empty result set: */
      21             :                         "select name from sysobjects where 0=1\n"
      22             :                         /* #2 3 rows: */
      23             :                         "select distinct convert(varchar(30), name) as 'type'  from systypes \n"
      24             :                                 "where name in ('int', 'char', 'text') \n"
      25             :                         "select @nrows = @@rowcount \n"
      26             :                         /* #3 many rows: */
      27             :                         "select distinct convert(varchar(30), name) as name  from systypes \n"
      28             :                         "return 42 \n"
      29             :                 "END \n";
      30             : 
      31             : 
      32             : static void
      33           8 : init_proc(const char *name)
      34             : {
      35             :         static char cmd[4096];
      36             : 
      37           8 :         if (name[0] != '#') {
      38           8 :                 printf("Dropping procedure %s\n", name);
      39           8 :                 sprintf(cmd, "if exists (select 1 from sysobjects where name = '%s' and type = 'P') "
      40             :                                 "DROP PROCEDURE %s", name, name);
      41           8 :                 CHKExecDirect(T(cmd), SQL_NTS, "SI");
      42             :         }
      43             : 
      44           8 :         printf("Creating procedure %s\n", name);
      45           8 :         sprintf(cmd, procedure_sql, name);
      46             : 
      47             :         /* create procedure. Fails if wrong permission or not MSSQL */
      48           8 :         CHKExecDirect(T(cmd), SQL_NTS, "SI");
      49           8 : }
      50             : 
      51             : static void
      52           8 : Test(const char *name)
      53             : {
      54           8 :         int iresults=0, data_errors=0;
      55           8 :         int ipar=0;
      56           8 :         HSTMT odbc_stmt = SQL_NULL_HSTMT;
      57             :         char call_cmd[128];
      58             :         struct Argument { 
      59             :                 SQLSMALLINT       InputOutputType;  /* fParamType */
      60             :                 SQLSMALLINT       ValueType;        /* fCType */
      61             :                 SQLSMALLINT       ParameterType;    /* fSqlType */
      62             :                 SQLUINTEGER       ColumnSize;       /* cbColDef */
      63             :                 SQLSMALLINT       DecimalDigits;    /* ibScale */
      64             :                 SQLPOINTER        ParameterValuePtr;/* rgbValue */
      65             :                 SQLINTEGER        BufferLength;     /* cbValueMax */
      66             :                 SQLLEN            ind;              /* pcbValue */
      67             :         };
      68           8 :         struct Argument args[] = {
      69             :                 /* InputOutputType        ValueType   ParamType    ColumnSize 
      70             :                                                                     | DecimalDigits 
      71             :                                                                     |  | ParameterValuePtr 
      72             :                                                                     |  |  |  BufferLength 
      73             :                                                                     |  |  |   |  ind */
      74             :                 { SQL_PARAM_OUTPUT,       SQL_C_LONG, SQL_INTEGER,  0, 0, 0,  4, 3 }, /* return status */
      75             :                 { SQL_PARAM_INPUT_OUTPUT, SQL_C_CHAR, SQL_VARCHAR, 30, 0, 0, 30, SQL_NULL_DATA }, 
      76             :                                                                                       /* @null_input varchar(30) OUTPUT */
      77             :                 { SQL_PARAM_INPUT_OUTPUT, SQL_C_CHAR, SQL_VARCHAR, 30, 0, 0, 30, 3 }, /* @first_type varchar(30) OUTPUT */
      78             :                 { SQL_PARAM_INPUT_OUTPUT, SQL_C_LONG, SQL_INTEGER,  0, 0, 0,  4, 4 }, /* @nullout int OUTPUT\ */
      79             :                 { SQL_PARAM_INPUT_OUTPUT, SQL_C_LONG, SQL_INTEGER,  0, 0, 0,  4, 4 }, /* @nrows int OUTPUT */
      80             :                 { SQL_PARAM_INPUT,        SQL_C_CHAR, SQL_VARCHAR, 20, 0, 0, 20, 3 }  /* @c varchar(20) */
      81             :         };
      82             : 
      83             : 
      84           8 :         printf("executing SQLAllocStmt\n");
      85           8 :         CHKAllocStmt(&odbc_stmt, "S");
      86             : 
      87          56 :         for( ipar=0; ipar < TDS_VECTOR_SIZE(args); ipar++ ) {
      88          48 :                 printf("executing SQLBindParameter for parameter %d\n", 1+ipar);
      89          48 :                 if( args[ipar].BufferLength > 0 ) {
      90          48 :                         args[ipar].ParameterValuePtr = (SQLPOINTER) ODBC_GET(args[ipar].BufferLength);
      91          48 :                         assert(args[ipar].ParameterValuePtr != NULL);
      92          48 :                         memset(args[ipar].ParameterValuePtr, 0, args[ipar].BufferLength);
      93          48 :                         memset(args[ipar].ParameterValuePtr, 'a', args[ipar].BufferLength - 1);
      94             :                 }
      95          48 :                 CHKBindParameter        ( 1+ipar
      96             :                                         , args[ipar].InputOutputType
      97             :                                         , args[ipar].ValueType
      98             :                                         , args[ipar].ParameterType
      99             :                                         , args[ipar].ColumnSize
     100             :                                         , args[ipar].DecimalDigits
     101             :                                         , args[ipar].ParameterValuePtr
     102             :                                         , args[ipar].BufferLength
     103             :                                         , &args[ipar].ind
     104             :                                         , "S"
     105             :                                         );
     106             :         }
     107             : 
     108           8 :         sprintf(call_cmd, "{?=call %s(?,?,?,?,?)}", name );
     109           8 :         printf("executing SQLPrepare: %s\n", call_cmd);
     110           8 :         CHKPrepare(T(call_cmd), SQL_NTS, "S");
     111             : 
     112           8 :         printf("executing SQLExecute\n");
     113           8 :         CHKExecute("SI");
     114             : 
     115             :         do {
     116             :                 static const char dashes[] = "------------------------------";
     117             :                 int nrows;
     118             :                 SQLSMALLINT  icol, ncols;
     119          24 :                 SQLTCHAR     name[256] = {0};
     120             :                 SQLSMALLINT  namelen;
     121             :                 SQLSMALLINT  type;
     122             :                 SQLSMALLINT  scale;
     123             :                 SQLSMALLINT  nullable;
     124             : 
     125          24 :                 printf("executing SQLNumResultCols for result set %d\n", ++iresults);
     126          24 :                 CHKNumResultCols(&ncols, "S");
     127             : 
     128          24 :                 printf("executing SQLDescribeCol for %d column%c\n", ncols, (ncols == 1? ' ' : 's'));
     129          24 :                 printf("%-5.5s %-15.15s %5.5s %5.5s %5.5s %8.8s\n", "col", "name", "type", "size", "scale", "nullable"); 
     130          24 :                 printf("%-5.5s %-15.15s %5.5s %5.5s %5.5s %8.8s\n", dashes, dashes, dashes, dashes, dashes, dashes); 
     131             :                 
     132          48 :                 for (icol=ncols; icol > 0; icol--) {
     133             :                         SQLULEN size;
     134          24 :                         CHKDescribeCol(icol, name, TDS_VECTOR_SIZE(name),
     135             :                                        &namelen, &type, &size, &scale, &nullable, "S");
     136          24 :                         printf("%-5d %-15s %5d %5ld %5d %8c\n", icol, C(name), type, (long int)size, scale, (nullable? 'Y' : 'N')); 
     137             :                 }
     138             : 
     139          24 :                 printf("executing SQLFetch...\n");
     140          24 :                 printf("\t%-30s\n\t%s\n", C(name), dashes);
     141         306 :                 for (nrows=0; CHKFetch("SNo") == SQL_SUCCESS; nrows++) {
     142         282 :                         const SQLINTEGER icol = 1;
     143             :                         char buf[60];
     144             :                         SQLLEN len;
     145         282 :                         CHKGetData( icol
     146             :                                         , SQL_C_CHAR    /* fCType */
     147             :                                         , buf           /* rgbValue */
     148             :                                         , sizeof(buf)   /* cbValueMax */
     149             :                                         , &len              /* pcbValue */  
     150             :                                         , "SI"
     151             :                                         );
     152         282 :                         printf("\t%-30s\t(%2d bytes)\n", buf, (int) len);
     153             :                 }
     154          24 :                 printf("done.\n");
     155             : 
     156          24 :                 switch (iresults) {
     157           8 :                 case 1:
     158           8 :                         printf("0 rows expected, %d found\n", nrows);
     159           8 :                         data_errors += (nrows == 0)? 0 : 1;
     160           8 :                         break;;
     161           8 :                 case 2:
     162           8 :                         printf("3 rows expected, %d found\n", nrows);
     163           8 :                         data_errors += (nrows == 3)? 0 : 1;
     164           8 :                         break;;
     165           8 :                 case 3:
     166           8 :                         printf("at least 15 rows expected, %d found\n", nrows);
     167           8 :                         data_errors += (nrows > 15)? 0 : 1;
     168           8 :                         break;;
     169             :                 }
     170             : 
     171          24 :                 printf("executing SQLMoreResults...\n");
     172          24 :         } while (CHKMoreResults("SNo") == SQL_SUCCESS);
     173           8 :         printf("done.\n");
     174             : 
     175          56 :         for( ipar=0; ipar < TDS_VECTOR_SIZE(args); ipar++ ) {
     176          48 :                 if (args[ipar].InputOutputType == SQL_PARAM_INPUT)
     177           8 :                         continue;
     178          40 :                 printf("bound data for parameter %d is %ld bytes: ", 1+ipar, (long int)args[ipar].ind);
     179          40 :                 switch( args[ipar].ValueType ) {
     180          24 :                 case SQL_C_LONG:
     181          24 :                         printf("%d.\n", (int)(*(SQLINTEGER *)args[ipar].ParameterValuePtr));
     182          24 :                         break;
     183          16 :                 case SQL_C_CHAR:
     184          16 :                         printf("'%s'.\n", (char*)args[ipar].ParameterValuePtr);
     185          16 :                         break;
     186           0 :                 default:
     187           0 :                         printf("type unsupported in this test\n");
     188           0 :                         assert(0);
     189             :                         break;
     190             :                 }
     191             :         }
     192             : 
     193           8 :         printf("executing SQLFreeStmt\n");
     194           8 :         CHKFreeStmt(SQL_DROP, "S");
     195           8 :         odbc_stmt = SQL_NULL_HSTMT;
     196             : 
     197           8 :         ODBC_FREE();
     198             : 
     199           8 :         if (data_errors) {
     200           0 :                 fprintf(stderr, "%d errors found in expected row count\n", data_errors);
     201           0 :                 exit(1);
     202             :         }
     203           8 : }
     204             : 
     205             : int
     206           8 : main(int argc, char *argv[])
     207             : {
     208           8 :         const char proc_name[] = "freetds_odbc_rpc_test";
     209           8 :         char drop_proc[256] = "DROP PROCEDURE ";
     210             :         
     211           8 :         strcat(drop_proc, proc_name);
     212             :         
     213           8 :         printf("connecting\n");
     214           8 :         odbc_connect();
     215             :         
     216           8 :         init_proc(proc_name);
     217             : 
     218           8 :         printf("running test\n");
     219           8 :         Test(proc_name);
     220             :         
     221           8 :         printf("dropping procedure\n");
     222           8 :         odbc_command(drop_proc);
     223             : 
     224           8 :         odbc_disconnect();
     225             : 
     226           8 :         printf("Done.\n");
     227           8 :         ODBC_FREE();
     228             :         return 0;
     229             : }
     230             : 

Generated by: LCOV version 1.13