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(void)
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 :
|