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