Line data Source code
1 : /*
2 : * Purpose: Test remote procedure calls
3 : * Functions: dbretdata dbretlen dbretname dbretstatus dbrettype dbrpcinit dbrpcparam dbrpcsend
4 : */
5 :
6 : #include "common.h"
7 :
8 : #include <freetds/bool.h>
9 :
10 : static RETCODE init_proc(DBPROCESS * dbproc, const char *name);
11 :
12 : typedef struct {
13 : char *name, *value;
14 : int type, len;
15 : } RETPARAM;
16 :
17 : static RETPARAM* save_retparam(RETPARAM *param, char *name, char *value, int type, int len);
18 :
19 : static RETCODE
20 12 : init_proc(DBPROCESS * dbproc, const char *name)
21 : {
22 12 : RETCODE ret = FAIL;
23 :
24 12 : if (name[0] != '#') {
25 2 : printf("Dropping procedure %s\n", name);
26 2 : sql_cmd(dbproc);
27 2 : dbsqlexec(dbproc);
28 2 : while (dbresults(dbproc) != NO_MORE_RESULTS) {
29 : /* nop */
30 : }
31 : }
32 :
33 12 : printf("Creating procedure %s\n", name);
34 12 : sql_cmd(dbproc);
35 12 : if ((ret = dbsqlexec(dbproc)) == FAIL) {
36 2 : if (name[0] == '#')
37 2 : printf("Failed to create procedure %s. Wrong permission or not MSSQL.\n", name);
38 : else
39 0 : printf("Failed to create procedure %s. Wrong permission.\n", name);
40 : }
41 22 : while (dbresults(dbproc) != NO_MORE_RESULTS) {
42 : /* nop */
43 : }
44 12 : return ret;
45 : }
46 :
47 : static RETPARAM*
48 74 : save_retparam(RETPARAM *param, char *name, char *value, int type, int len)
49 : {
50 74 : free(param->name);
51 74 : free(param->value);
52 :
53 74 : param->name = strdup(name);
54 74 : param->value = strdup(value);
55 :
56 74 : param->type = type;
57 74 : param->len = len;
58 :
59 74 : return param;
60 : }
61 :
62 : static void
63 : free_retparam(RETPARAM *param)
64 : {
65 30 : free(param->name);
66 30 : free(param->value);
67 : param->name = param->value = NULL;
68 : }
69 :
70 : static bool failed = false;
71 :
72 : static int
73 28 : ignore_msg_handler(DBPROCESS * dbproc, DBINT msgno, int state, int severity, char *text, char *server, char *proc, int line)
74 : {
75 : int ret;
76 :
77 28 : dbsetuserdata(dbproc, (BYTE*) &msgno);
78 : /* printf("(ignoring message %d)\n", msgno); */
79 28 : ret = syb_msg_handler(dbproc, msgno, state, severity, text, server, proc, line);
80 28 : dbsetuserdata(dbproc, NULL);
81 28 : return ret;
82 : }
83 : /*
84 : * The bad procedure name message has severity 15, causing db-lib to call the error handler after calling the message handler.
85 : * This wrapper anticipates that behavior, and again sets the userdata, telling the handler this error is expected.
86 : */
87 : static int
88 38 : ignore_err_handler(DBPROCESS * dbproc, int severity, int dberr, int oserr, char *dberrstr, char *oserrstr)
89 : {
90 : int erc;
91 : static int recursion_depth = 0;
92 :
93 38 : if (dbproc == NULL) {
94 10 : printf("expected error %d: \"%s\"\n", dberr, dberrstr? dberrstr : "");
95 10 : return INT_CANCEL;
96 : }
97 :
98 28 : if (recursion_depth++) {
99 0 : printf("error %d: \"%s\"\n", dberr, dberrstr? dberrstr : "");
100 0 : printf("logic error: recursive call to ignore_err_handler\n");
101 0 : exit(1);
102 : }
103 28 : dbsetuserdata(dbproc, (BYTE*) &dberr);
104 : /* printf("(ignoring error %d)\n", dberr); */
105 28 : erc = syb_err_handler(dbproc, severity, dberr, oserr, dberrstr, oserrstr);
106 28 : dbsetuserdata(dbproc, NULL);
107 28 : recursion_depth--;
108 28 : return erc;
109 : }
110 :
111 : static int
112 860 : colwidth( DBPROCESS * dbproc, int icol )
113 : {
114 860 : int width = dbwillconvert(dbcoltype(dbproc, icol), SYBCHAR);
115 860 : return 255 == width? dbcollen(dbproc, icol) : width;
116 : }
117 :
118 : static char param_data1[64], param_data3[8000+1], param_data4[2 * 4000 + 1];
119 : static int param_data2, param_data5;
120 :
121 : struct parameters_t {
122 : const char *name;
123 : BYTE status;
124 : int type;
125 : DBINT maxlen;
126 : DBINT datalen;
127 : BYTE *value;
128 : };
129 :
130 : static struct parameters_t bindings[] = {
131 : { "@null_input", DBRPCRETURN, SYBCHAR, -1, 0, NULL }
132 : , { "@first_type", DBRPCRETURN, SYBCHAR, sizeof(param_data1), 0, (BYTE *) ¶m_data1 }
133 : , { "@nullout", DBRPCRETURN, SYBINT4, -1, 0, (BYTE *) ¶m_data2 }
134 : , { "@varchar_tds7_out", DBRPCRETURN, SYBVARCHAR, sizeof(param_data3), 0, (BYTE *) ¶m_data3 }
135 : , { "@nvarchar_tds7_out", DBRPCRETURN, 231, sizeof(param_data4), 0, (BYTE *) ¶m_data4 }
136 : , { "@nrows", DBRPCRETURN, SYBINT4, -1, -1, (BYTE *) ¶m_data5 }
137 : , { "@c_this_name_is_way_more_than_thirty_characters_charlie",
138 : 0, SYBVARCHAR, 0, 0, NULL }
139 : , { "@nv", 0, SYBVARCHAR, -1, 2, (BYTE *) "OK:" }
140 : , { NULL, 0, 0, 0, 0, NULL }
141 : };
142 :
143 : #define PARAM_STR(s) sizeof(s)-1, (BYTE*) s
144 : static struct parameters_t bindings_mssql1[] = {
145 : { "", 0, SYBVARCHAR, -1, PARAM_STR("set @a='test123'") }
146 : , { "", 0, SYBVARCHAR, -1, PARAM_STR("@a varchar(max) out") }
147 : , { "", DBRPCRETURN, SYBTEXT, sizeof(param_data3), 0, (BYTE *) ¶m_data3 }
148 : , { NULL, 0, 0, 0, 0, NULL }
149 : };
150 :
151 : static struct parameters_t bindings_mssql2[] = {
152 : { "", 0, SYBVARCHAR, -1, PARAM_STR("set @a=null") }
153 : , { "", 0, SYBVARCHAR, -1, PARAM_STR("@a bit out") }
154 : , { "", DBRPCRETURN, SYBBIT, sizeof(param_data3), 0, (BYTE *) ¶m_data3 }
155 : , { NULL, 0, 0, 0, 0, NULL }
156 : };
157 :
158 : static void
159 100 : bind_param(DBPROCESS *dbproc, struct parameters_t *pb)
160 : {
161 : RETCODE erc;
162 100 : const char *name = pb->name[0] ? pb->name : NULL;
163 :
164 100 : if ((erc = dbrpcparam(dbproc, name, pb->status, pb->type, pb->maxlen, pb->datalen, pb->value)) == FAIL) {
165 0 : fprintf(stderr, "Failed line %d: dbrpcparam\n", __LINE__);
166 0 : failed = true;
167 : }
168 100 : }
169 :
170 10 : TEST_MAIN()
171 : {
172 : LOGINREC *login;
173 : DBPROCESS *dbproc;
174 : RETPARAM save_param, save_varchar_tds7_param, save_nvarchar_tds7_param;
175 :
176 : char teststr[8000+1], abbrev_data[10+3+1], *output;
177 10 : char *retname = NULL;
178 : int i;
179 10 : int rettype = 0, retlen = 0, return_status = 0;
180 10 : char proc[] = "#t0022";
181 10 : char *proc_name = proc;
182 :
183 10 : int num_resultset = 0, num_empty_resultset = 0;
184 10 : int num_params = 6;
185 :
186 : struct parameters_t *pb;
187 :
188 : static const char dashes30[] = "------------------------------";
189 : static const char *dashes5 = dashes30 + (sizeof(dashes30) - 5),
190 : *dashes20 = dashes30 + (sizeof(dashes30) - 20);
191 :
192 : RETCODE erc, row_code;
193 :
194 10 : set_malloc_options();
195 :
196 10 : memset(&save_param, 0, sizeof(save_param));
197 10 : memset(&save_varchar_tds7_param, 0, sizeof(save_varchar_tds7_param));
198 10 : memset(&save_nvarchar_tds7_param, 0, sizeof(save_nvarchar_tds7_param));
199 :
200 10 : read_login_info(argc, argv);
201 :
202 10 : printf("Starting %s\n", argv[0]);
203 :
204 10 : dbinit();
205 :
206 10 : dberrhandle(syb_err_handler);
207 10 : dbmsghandle(syb_msg_handler);
208 :
209 10 : printf("About to logon\n");
210 :
211 10 : login = dblogin();
212 10 : DBSETLPWD(login, PASSWORD);
213 10 : DBSETLUSER(login, USER);
214 10 : DBSETLAPP(login, "rpc");
215 10 : dberrhandle(ignore_err_handler);
216 10 : DBSETLPACKET(login, -1);
217 10 : dberrhandle(syb_err_handler);
218 :
219 :
220 10 : printf("About to open %s.%s\n", SERVER, DATABASE);
221 :
222 10 : dbproc = dbopen(login, SERVER);
223 10 : if (strlen(DATABASE))
224 10 : dbuse(dbproc, DATABASE);
225 10 : dbloginfree(login);
226 :
227 10 : printf("Check if server support long identifiers\n");
228 10 : sql_cmd(dbproc);
229 10 : i = 103;
230 10 : dbsetuserdata(dbproc, (BYTE*) &i);
231 10 : dbsqlexec(dbproc);
232 30 : while (dbresults(dbproc) != NO_MORE_RESULTS)
233 20 : while (dbnextrow(dbproc) != NO_MORE_ROWS)
234 10 : continue;
235 10 : dbsetuserdata(dbproc, NULL);
236 10 : if (i == 0) {
237 0 : fprintf(stderr, "This server does not support long identifiers\n");
238 0 : dbexit();
239 0 : return 0;
240 : }
241 :
242 10 : dberrhandle(ignore_err_handler);
243 10 : dbmsghandle(ignore_msg_handler);
244 :
245 10 : printf("trying to create a temporary stored procedure\n");
246 10 : if (FAIL == init_proc(dbproc, proc_name)) {
247 2 : num_params = 4;
248 2 : printf("trying to create a permanent stored procedure\n");
249 2 : if (FAIL == init_proc(dbproc, ++proc_name))
250 0 : exit(EXIT_FAILURE);
251 : }
252 :
253 10 : dberrhandle(syb_err_handler);
254 10 : dbmsghandle(syb_msg_handler);
255 :
256 10 : printf("Created procedure %s\n", proc_name);
257 :
258 : /* set up and send the rpc */
259 10 : printf("executing dbrpcinit\n");
260 10 : erc = dbrpcinit(dbproc, proc_name, 0); /* no options */
261 10 : if (erc == FAIL) {
262 0 : fprintf(stderr, "Failed line %d: dbrpcinit\n", __LINE__);
263 0 : failed = true;
264 : }
265 :
266 90 : for (pb = bindings, i = 0; pb->name != NULL; pb++, i++) {
267 80 : printf("executing dbrpcparam for %s\n", pb->name);
268 80 : if (num_params == 4 && (i == 3 || i == 4))
269 4 : continue;
270 76 : bind_param(dbproc, pb);
271 : }
272 10 : printf("executing dbrpcsend\n");
273 10 : param_data5 = 0x11223344;
274 10 : erc = dbrpcsend(dbproc);
275 10 : if (erc == FAIL) {
276 0 : fprintf(stderr, "Failed line %d: dbrpcsend\n", __LINE__);
277 0 : exit(1);
278 : }
279 :
280 : /* wait for it to execute */
281 10 : printf("executing dbsqlok\n");
282 10 : erc = dbsqlok(dbproc);
283 10 : if (erc == FAIL) {
284 0 : fprintf(stderr, "Failed line %d: dbsqlok\n", __LINE__);
285 0 : exit(1);
286 : }
287 :
288 : /* retrieve outputs per usual */
289 10 : printf("fetching results\n");
290 10 : while ((erc = dbresults(dbproc)) != NO_MORE_RESULTS) {
291 40 : printf("fetched resultset %d %s:\n", 1+num_resultset, erc==SUCCEED? "successfully":"unsuccessfully");
292 40 : if (erc == SUCCEED) {
293 40 : const int ncol = dbnumcols(dbproc);
294 40 : int empty_resultset = 1, c;
295 : enum {buflen=1024, nbuf=5};
296 40 : char bound_buffers[nbuf][buflen] = { "one", "two", "three", "four", "five" };
297 :
298 40 : ++num_resultset;
299 :
300 130 : for( c=0; c < ncol && c < nbuf; c++ ) {
301 90 : printf("column %d (%s) is %d wide, ", c+1, dbcolname(dbproc, c+1), colwidth(dbproc, c+1));
302 90 : printf("buffer initialized to '%s'\n", bound_buffers[c]);
303 : }
304 90 : for( c=0; c < ncol && c < nbuf; c++ ) {
305 90 : erc = dbbind(dbproc, c+1, STRINGBIND, 0, (BYTE *) bound_buffers[c]);
306 90 : if (erc == FAIL) {
307 0 : fprintf(stderr, "Failed line %d: dbbind\n", __LINE__);
308 0 : exit(1);
309 : }
310 :
311 90 : printf("%-*s ", colwidth(dbproc, c+1), dbcolname(dbproc, c+1));
312 : }
313 40 : printf("\n");
314 :
315 40 : while ((row_code = dbnextrow(dbproc)) != NO_MORE_ROWS) {
316 340 : empty_resultset = 0;
317 340 : if (row_code == REG_ROW) {
318 : int c;
319 680 : for( c=0; c < ncol && c < nbuf; c++ ) {
320 680 : printf("%-*s ", colwidth(dbproc, c+1), bound_buffers[c]);
321 : }
322 340 : printf("\n");
323 : } else {
324 : /* not supporting computed rows in this unit test */
325 0 : failed = true;
326 0 : fprintf(stderr, "Failed. Expected a row\n");
327 0 : exit(1);
328 : }
329 : }
330 40 : printf("row count %d\n", (int) dbcount(dbproc));
331 40 : printf("hasretstatus %d\n", dbhasretstat(dbproc));
332 40 : if (num_resultset == 4 && !dbhasretstat(dbproc)) {
333 0 : fprintf(stderr, "dbnextrow should have set hasretstatus after last recordset\n");
334 0 : exit(1);
335 : }
336 40 : if (empty_resultset)
337 10 : ++num_empty_resultset;
338 : } else {
339 0 : fprintf(stderr, "Expected a result set.\n");
340 0 : exit(1);
341 : }
342 : } /* while dbresults */
343 :
344 : /* check return status */
345 10 : printf("retrieving return status...\n");
346 10 : if (dbhasretstat(dbproc) == TRUE) {
347 10 : printf("%d\n", return_status = dbretstatus(dbproc));
348 : } else {
349 0 : printf("none\n");
350 : }
351 :
352 : /*
353 : * Check output parameter values
354 : */
355 10 : if (dbnumrets(dbproc) != num_params) { /* dbnumrets missed something */
356 0 : fprintf(stderr, "Expected %d output parameters.\n", num_params);
357 0 : exit(1);
358 : }
359 10 : printf("retrieving output parameters...\n");
360 10 : printf("%-5s %-20s %5s %6s %-30s\n", "param", "name", "type", "length", "data");
361 10 : printf("%-5s %-20s %5s %5s- %-30s\n", dashes5, dashes20, dashes5, dashes5, dashes30);
362 66 : for (i = 1; i <= dbnumrets(dbproc); i++) {
363 56 : retname = dbretname(dbproc, i);
364 56 : rettype = dbrettype(dbproc, i);
365 56 : retlen = dbretlen(dbproc, i);
366 56 : dbconvert(dbproc, rettype, dbretdata(dbproc, i), retlen, SYBVARCHAR, (BYTE*) teststr, -1);
367 56 : if(retlen <= 10) {
368 : output = teststr;
369 : } else {
370 16 : memcpy(abbrev_data, teststr, 10);
371 16 : sprintf(&abbrev_data[10], "...");
372 16 : output = abbrev_data;
373 : }
374 56 : printf("%-5d %-20s %5d %6d %-30s\n", i, retname, rettype, retlen, output);
375 :
376 56 : save_retparam(&save_param, retname, teststr, rettype, retlen);
377 56 : if (i == 4) {
378 10 : save_retparam(&save_varchar_tds7_param, retname, teststr, rettype, retlen);
379 : }
380 56 : if (i == 5) {
381 8 : save_retparam(&save_nvarchar_tds7_param, retname, teststr, rettype, retlen);
382 : }
383 : }
384 :
385 : /*
386 : * Test the last parameter for expected outcome
387 : */
388 10 : if ((save_param.name == NULL) || strcmp(save_param.name, bindings[5].name)) {
389 0 : fprintf(stderr, "Expected retname to be '%s', got ", bindings[5].name);
390 0 : if (save_param.name == NULL)
391 0 : fprintf(stderr, "<NULL> instead.\n");
392 : else
393 0 : fprintf(stderr, "'%s' instead.\n", save_param.name);
394 0 : exit(1);
395 : }
396 10 : if (strcmp(save_param.value, "3")) {
397 0 : fprintf(stderr, "Expected retdata to be 3.\n");
398 0 : exit(1);
399 : }
400 10 : if (save_param.type != SYBINT4) {
401 0 : fprintf(stderr, "Expected rettype to be SYBINT4 was %d.\n", save_param.type);
402 0 : exit(1);
403 : }
404 10 : if (save_param.len != 4) {
405 0 : fprintf(stderr, "Expected retlen to be 4.\n");
406 0 : exit(1);
407 : }
408 :
409 10 : if (num_params == 6) {
410 : /*
411 : * Test name, size, contents of the VARCHAR(8000) output parameter
412 : */
413 8 : if ((save_varchar_tds7_param.name == NULL) || strcmp(save_varchar_tds7_param.name, bindings[3].name)) {
414 0 : fprintf(stderr, "Expected retname to be '%s', got ", bindings[3].name);
415 0 : if (save_varchar_tds7_param.name == NULL)
416 0 : fprintf(stderr, "<NULL> instead.\n");
417 : else
418 0 : fprintf(stderr, "'%s' instead.\n", save_varchar_tds7_param.name);
419 0 : exit(1);
420 : }
421 8 : if (save_varchar_tds7_param.type != SYBVARCHAR) {
422 0 : fprintf(stderr, "Expected rettype to be SYBVARCHAR was %d.\n", save_varchar_tds7_param.type);
423 0 : exit(1);
424 : }
425 8 : if (save_varchar_tds7_param.len != 8000) {
426 0 : fprintf(stderr, "Expected retlen to be 8000 was %d.\n", save_varchar_tds7_param.len);
427 0 : exit(1);
428 : }
429 :
430 : /*
431 : * Test name, size, contents of the NVARCHAR(4000) output parameter
432 : */
433 8 : if ((save_nvarchar_tds7_param.name == NULL) || strcmp(save_nvarchar_tds7_param.name, bindings[4].name)) {
434 0 : fprintf(stderr, "Expected retname to be '%s', got ", bindings[4].name);
435 0 : if (save_varchar_tds7_param.name == NULL)
436 0 : fprintf(stderr, "<NULL> instead.\n");
437 : else
438 0 : fprintf(stderr, "'%s' instead.\n", save_nvarchar_tds7_param.name);
439 0 : exit(1);
440 : }
441 8 : if (save_nvarchar_tds7_param.len != 4000) {
442 0 : fprintf(stderr, "Expected retlen to be 4000 was %d.\n", save_nvarchar_tds7_param.len);
443 0 : exit(1);
444 : }
445 : }
446 :
447 10 : if(42 != return_status) {
448 0 : fprintf(stderr, "Expected status to be 42.\n");
449 0 : exit(1);
450 : }
451 :
452 10 : printf("Good: Got 6 output parameters and 1 return status of %d.\n", return_status);
453 :
454 :
455 : /* Test number of result sets */
456 10 : if (num_resultset != 4) {
457 0 : fprintf(stderr, "Expected 4 resultset got %d.\n", num_resultset);
458 0 : exit(1);
459 : }
460 10 : if (num_empty_resultset != 1) {
461 0 : fprintf(stderr, "Expected an empty resultset got %d.\n", num_empty_resultset);
462 0 : exit(1);
463 : }
464 10 : printf("Good: Got %d resultsets and %d empty resultset.\n", num_resultset, num_empty_resultset);
465 :
466 :
467 :
468 10 : printf("Dropping procedure\n");
469 10 : sql_cmd(dbproc);
470 10 : dbsqlexec(dbproc);
471 10 : while (dbresults(dbproc) != NO_MORE_RESULTS) {
472 : /* nop */
473 : }
474 :
475 : /* additional tests for mssql */
476 : #if defined(DBTDS_7_2)
477 10 : if (num_params == 6 && dbtds(dbproc) >= DBTDS_7_2) {
478 4 : erc = dbrpcinit(dbproc, "sp_executesql", 0); /* no options */
479 4 : if (erc == FAIL) {
480 0 : fprintf(stderr, "Failed line %d: dbrpcinit\n", __LINE__);
481 0 : failed = true;
482 : }
483 12 : for (pb = bindings_mssql1; pb->name != NULL; pb++)
484 12 : bind_param(dbproc, pb);
485 4 : erc = dbrpcsend(dbproc);
486 4 : if (erc == FAIL) {
487 0 : fprintf(stderr, "Failed line %d: dbrpcsend\n", __LINE__);
488 0 : exit(1);
489 : }
490 4 : while (dbresults(dbproc) != NO_MORE_RESULTS)
491 0 : continue;
492 4 : if (dbnumrets(dbproc) != 1) { /* dbnumrets missed something */
493 0 : fprintf(stderr, "Expected 1 output parameters.\n");
494 0 : exit(1);
495 : }
496 4 : i = 1;
497 4 : retname = dbretname(dbproc, i);
498 4 : rettype = dbrettype(dbproc, i);
499 4 : retlen = dbretlen(dbproc, i);
500 4 : dbconvert(dbproc, rettype, dbretdata(dbproc, i), retlen, SYBVARCHAR, (BYTE*) teststr, -1);
501 4 : if (strcmp(teststr, "test123") != 0) {
502 0 : fprintf(stderr, "Unexpected '%s' results.\n", teststr);
503 0 : exit(1);
504 : }
505 :
506 4 : erc = dbrpcinit(dbproc, "sp_executesql", 0); /* no options */
507 4 : if (erc == FAIL) {
508 0 : fprintf(stderr, "Failed line %d: dbrpcinit\n", __LINE__);
509 0 : failed = true;
510 : }
511 12 : for (pb = bindings_mssql2; pb->name != NULL; pb++)
512 12 : bind_param(dbproc, pb);
513 4 : erc = dbrpcsend(dbproc);
514 4 : if (erc == FAIL) {
515 0 : fprintf(stderr, "Failed line %d: dbrpcsend\n", __LINE__);
516 0 : exit(1);
517 : }
518 4 : while (dbresults(dbproc) != NO_MORE_RESULTS)
519 0 : continue;
520 4 : if (dbnumrets(dbproc) != 1) { /* dbnumrets missed something */
521 0 : fprintf(stderr, "Expected 1 output parameters.\n");
522 0 : exit(1);
523 : }
524 4 : i = 1;
525 4 : retname = dbretname(dbproc, i);
526 4 : rettype = dbrettype(dbproc, i);
527 4 : retlen = dbretlen(dbproc, i);
528 4 : dbconvert(dbproc, rettype, dbretdata(dbproc, i), retlen, SYBVARCHAR, (BYTE*) teststr, -1);
529 4 : if (dbretdata(dbproc, i) != NULL || rettype != SYBBIT || retlen != 0) {
530 0 : fprintf(stderr, "Unexpected '%s' results.\n", teststr);
531 0 : exit(1);
532 : }
533 : }
534 : #endif
535 :
536 10 : dbexit();
537 :
538 10 : printf("%s %s\n", __FILE__, (failed ? "failed!" : "OK"));
539 :
540 10 : free_retparam(&save_param);
541 10 : free_retparam(&save_varchar_tds7_param);
542 10 : free_retparam(&save_nvarchar_tds7_param);
543 :
544 10 : return failed ? 1 : 0;
545 : }
|