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 10 : init_proc(const char *name)
34 : {
35 : static char cmd[4096];
36 :
37 10 : if (name[0] != '#') {
38 10 : printf("Dropping procedure %s\n", name);
39 10 : sprintf(cmd, "if exists (select 1 from sysobjects where name = '%s' and type = 'P') "
40 : "DROP PROCEDURE %s", name, name);
41 10 : CHKExecDirect(T(cmd), SQL_NTS, "SI");
42 : }
43 :
44 10 : printf("Creating procedure %s\n", name);
45 10 : sprintf(cmd, procedure_sql, name);
46 :
47 : /* create procedure. Fails if wrong permission or not MSSQL */
48 10 : CHKExecDirect(T(cmd), SQL_NTS, "SI");
49 10 : }
50 :
51 : static void
52 10 : Test(const char *name)
53 : {
54 10 : int iresults=0, data_errors=0;
55 10 : int ipar=0;
56 10 : 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 10 : 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 10 : printf("executing SQLAllocStmt\n");
85 10 : CHKAllocStmt(&odbc_stmt, "S");
86 :
87 70 : for( ipar=0; ipar < TDS_VECTOR_SIZE(args); ipar++ ) {
88 60 : printf("executing SQLBindParameter for parameter %d\n", 1+ipar);
89 60 : if( args[ipar].BufferLength > 0 ) {
90 60 : args[ipar].ParameterValuePtr = (SQLPOINTER) ODBC_GET(args[ipar].BufferLength);
91 60 : assert(args[ipar].ParameterValuePtr != NULL);
92 60 : memset(args[ipar].ParameterValuePtr, 0, args[ipar].BufferLength);
93 60 : memset(args[ipar].ParameterValuePtr, 'a', args[ipar].BufferLength - 1);
94 : }
95 60 : 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 10 : sprintf(call_cmd, "{?=call %s(?,?,?,?,?)}", name );
109 10 : printf("executing SQLPrepare: %s\n", call_cmd);
110 10 : CHKPrepare(T(call_cmd), SQL_NTS, "S");
111 :
112 10 : printf("executing SQLExecute\n");
113 10 : CHKExecute("SI");
114 :
115 : do {
116 : static const char dashes[] = "------------------------------";
117 : int nrows;
118 : SQLSMALLINT icol, ncols;
119 30 : SQLTCHAR name[256] = {0};
120 : SQLSMALLINT namelen;
121 : SQLSMALLINT type;
122 : SQLSMALLINT scale;
123 : SQLSMALLINT nullable;
124 :
125 30 : printf("executing SQLNumResultCols for result set %d\n", ++iresults);
126 30 : CHKNumResultCols(&ncols, "S");
127 :
128 30 : printf("executing SQLDescribeCol for %d column%c\n", ncols, (ncols == 1? ' ' : 's'));
129 30 : printf("%-5.5s %-15.15s %5.5s %5.5s %5.5s %8.8s\n", "col", "name", "type", "size", "scale", "nullable");
130 30 : printf("%-5.5s %-15.15s %5.5s %5.5s %5.5s %8.8s\n", dashes, dashes, dashes, dashes, dashes, dashes);
131 :
132 60 : for (icol=ncols; icol > 0; icol--) {
133 : SQLULEN size;
134 30 : CHKDescribeCol(icol, name, TDS_VECTOR_SIZE(name),
135 : &namelen, &type, &size, &scale, &nullable, "S");
136 30 : printf("%-5d %-15s %5d %5ld %5d %8c\n", icol, C(name), type, (long int)size, scale, (nullable? 'Y' : 'N'));
137 : }
138 :
139 30 : printf("executing SQLFetch...\n");
140 30 : printf("\t%-30s\n\t%s\n", C(name), dashes);
141 386 : for (nrows=0; CHKFetch("SNo") == SQL_SUCCESS; nrows++) {
142 356 : const SQLINTEGER icol = 1;
143 : char buf[60];
144 : SQLLEN len;
145 356 : CHKGetData( icol
146 : , SQL_C_CHAR /* fCType */
147 : , buf /* rgbValue */
148 : , sizeof(buf) /* cbValueMax */
149 : , &len /* pcbValue */
150 : , "SI"
151 : );
152 356 : printf("\t%-30s\t(%2d bytes)\n", buf, (int) len);
153 : }
154 30 : printf("done.\n");
155 :
156 30 : switch (iresults) {
157 10 : case 1:
158 10 : printf("0 rows expected, %d found\n", nrows);
159 10 : data_errors += (nrows == 0)? 0 : 1;
160 10 : break;;
161 10 : case 2:
162 10 : printf("3 rows expected, %d found\n", nrows);
163 10 : data_errors += (nrows == 3)? 0 : 1;
164 10 : break;;
165 10 : case 3:
166 10 : printf("at least 15 rows expected, %d found\n", nrows);
167 10 : data_errors += (nrows > 15)? 0 : 1;
168 10 : break;;
169 : }
170 :
171 30 : printf("executing SQLMoreResults...\n");
172 30 : } while (CHKMoreResults("SNo") == SQL_SUCCESS);
173 10 : printf("done.\n");
174 :
175 70 : for( ipar=0; ipar < TDS_VECTOR_SIZE(args); ipar++ ) {
176 60 : if (args[ipar].InputOutputType == SQL_PARAM_INPUT)
177 10 : continue;
178 50 : printf("bound data for parameter %d is %ld bytes: ", 1+ipar, (long int)args[ipar].ind);
179 50 : switch( args[ipar].ValueType ) {
180 30 : case SQL_C_LONG:
181 30 : printf("%d.\n", (int)(*(SQLINTEGER *)args[ipar].ParameterValuePtr));
182 30 : break;
183 20 : case SQL_C_CHAR:
184 20 : printf("'%s'.\n", (char*)args[ipar].ParameterValuePtr);
185 20 : break;
186 0 : default:
187 0 : printf("type unsupported in this test\n");
188 0 : assert(0);
189 : break;
190 : }
191 : }
192 :
193 10 : printf("executing SQLFreeStmt\n");
194 10 : CHKFreeStmt(SQL_DROP, "S");
195 10 : odbc_stmt = SQL_NULL_HSTMT;
196 :
197 10 : ODBC_FREE();
198 :
199 10 : if (data_errors) {
200 0 : fprintf(stderr, "%d errors found in expected row count\n", data_errors);
201 0 : exit(1);
202 : }
203 10 : }
204 :
205 : int
206 10 : main(void)
207 : {
208 10 : const char proc_name[] = "freetds_odbc_rpc_test";
209 10 : char drop_proc[256] = "DROP PROCEDURE ";
210 :
211 10 : strcat(drop_proc, proc_name);
212 :
213 10 : printf("connecting\n");
214 10 : odbc_connect();
215 :
216 10 : init_proc(proc_name);
217 :
218 10 : printf("running test\n");
219 10 : Test(proc_name);
220 :
221 10 : printf("dropping procedure\n");
222 10 : odbc_command(drop_proc);
223 :
224 10 : odbc_disconnect();
225 :
226 10 : printf("Done.\n");
227 10 : ODBC_FREE();
228 : return 0;
229 : }
230 :
|