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