1 /*-------
2 * Module: bind.c
3 *
4 * Description: This module contains routines related to binding
5 * columns and parameters.
6 *
7 * Classes: BindInfoClass, ParameterInfoClass
8 *
9 * API functions: SQLBindParameter, SQLBindCol, SQLDescribeParam, SQLNumParams,
10 * SQLParamOptions
11 *
12 * Comments: See "readme.txt" for copyright and license information.
13 *-------
14 */
15
16 /* #include <stdlib.h> */
17 #include <string.h>
18 #include <ctype.h>
19 #include "bind.h"
20 #include "misc.h"
21
22 #include "environ.h"
23 #include "statement.h"
24 #include "descriptor.h"
25 #include "qresult.h"
26 #include "pgtypes.h"
27 #include "multibyte.h"
28
29 #include "pgapifunc.h"
30
31
32 /* Bind parameters on a statement handle */
33 RETCODE SQL_API
PGAPI_BindParameter(HSTMT hstmt,SQLUSMALLINT ipar,SQLSMALLINT fParamType,SQLSMALLINT fCType,SQLSMALLINT fSqlType,SQLULEN cbColDef,SQLSMALLINT ibScale,PTR rgbValue,SQLLEN cbValueMax,SQLLEN * pcbValue)34 PGAPI_BindParameter(HSTMT hstmt,
35 SQLUSMALLINT ipar,
36 SQLSMALLINT fParamType,
37 SQLSMALLINT fCType,
38 SQLSMALLINT fSqlType,
39 SQLULEN cbColDef,
40 SQLSMALLINT ibScale,
41 PTR rgbValue,
42 SQLLEN cbValueMax,
43 SQLLEN * pcbValue)
44 {
45 StatementClass *stmt = (StatementClass *) hstmt;
46 CSTR func = "PGAPI_BindParameter";
47 APDFields *apdopts;
48 IPDFields *ipdopts;
49 PutDataInfo *pdata_info;
50
51 MYLOG(0, "entering...\n");
52
53 if (!stmt)
54 {
55 SC_log_error(func, "", NULL);
56 return SQL_INVALID_HANDLE;
57 }
58 SC_clear_error(stmt);
59
60 apdopts = SC_get_APDF(stmt);
61 if (apdopts->allocated < ipar)
62 extend_parameter_bindings(apdopts, ipar);
63 ipdopts = SC_get_IPDF(stmt);
64 if (ipdopts->allocated < ipar)
65 extend_iparameter_bindings(ipdopts, ipar);
66 pdata_info = SC_get_PDTI(stmt);
67 if (pdata_info->allocated < ipar)
68 extend_putdata_info(pdata_info, ipar, FALSE);
69
70 /* use zero based column numbers for the below part */
71 ipar--;
72
73 /* store the given info */
74 apdopts->parameters[ipar].buflen = cbValueMax;
75 apdopts->parameters[ipar].buffer = rgbValue;
76 apdopts->parameters[ipar].used =
77 apdopts->parameters[ipar].indicator = pcbValue;
78 apdopts->parameters[ipar].CType = fCType;
79 ipdopts->parameters[ipar].SQLType = fSqlType;
80 ipdopts->parameters[ipar].paramType = fParamType;
81 ipdopts->parameters[ipar].column_size = cbColDef;
82 ipdopts->parameters[ipar].decimal_digits = ibScale;
83 ipdopts->parameters[ipar].precision = 0;
84 ipdopts->parameters[ipar].scale = 0;
85 switch (fCType)
86 {
87 case SQL_C_NUMERIC:
88 if (cbColDef > 0)
89 ipdopts->parameters[ipar].precision = (UInt2) cbColDef;
90 if (ibScale > 0)
91 ipdopts->parameters[ipar].scale = ibScale;
92 break;
93 case SQL_C_TYPE_TIMESTAMP:
94 if (ibScale > 0)
95 ipdopts->parameters[ipar].precision = ibScale;
96 break;
97 case SQL_C_INTERVAL_DAY_TO_SECOND:
98 case SQL_C_INTERVAL_HOUR_TO_SECOND:
99 case SQL_C_INTERVAL_MINUTE_TO_SECOND:
100 case SQL_C_INTERVAL_SECOND:
101 ipdopts->parameters[ipar].precision = 6;
102 break;
103 }
104 apdopts->parameters[ipar].precision = ipdopts->parameters[ipar].precision;
105 apdopts->parameters[ipar].scale = ipdopts->parameters[ipar].scale;
106
107 /*
108 * If rebinding a parameter that had data-at-exec stuff in it, then
109 * free that stuff
110 */
111 if (pdata_info->pdata[ipar].EXEC_used)
112 {
113 free(pdata_info->pdata[ipar].EXEC_used);
114 pdata_info->pdata[ipar].EXEC_used = NULL;
115 }
116
117 if (pdata_info->pdata[ipar].EXEC_buffer)
118 {
119 free(pdata_info->pdata[ipar].EXEC_buffer);
120 pdata_info->pdata[ipar].EXEC_buffer = NULL;
121 }
122
123 if (pcbValue && apdopts->param_offset_ptr)
124 pcbValue = LENADDR_SHIFT(pcbValue, *apdopts->param_offset_ptr);
125 #ifdef NOT_USED /* evaluation of pcbValue here is dangerous */
126 /* Data at exec macro only valid for C char/binary data */
127 if (pcbValue && (*pcbValue == SQL_DATA_AT_EXEC ||
128 *pcbValue <= SQL_LEN_DATA_AT_EXEC_OFFSET))
129 apdopts->parameters[ipar].data_at_exec = TRUE;
130 else
131 apdopts->parameters[ipar].data_at_exec = FALSE;
132 #endif /* NOT_USED */
133
134 /* Clear premature result */
135 if (stmt->status == STMT_DESCRIBED)
136 SC_recycle_statement(stmt);
137
138 MYLOG(0, "ipar=%d, paramType=%d, fCType=%d, fSqlType=%d, cbColDef=" FORMAT_ULEN ", ibScale=%d,", ipar, fParamType, fCType, fSqlType, cbColDef, ibScale);
139 MYPRINTF(0, "rgbValue=%p(" FORMAT_LEN "), pcbValue=%p\n", rgbValue, cbValueMax, pcbValue);
140
141 return SQL_SUCCESS;
142 }
143
144
145 /* Associate a user-supplied buffer with a database column. */
146 RETCODE SQL_API
PGAPI_BindCol(HSTMT hstmt,SQLUSMALLINT icol,SQLSMALLINT fCType,PTR rgbValue,SQLLEN cbValueMax,SQLLEN * pcbValue)147 PGAPI_BindCol(HSTMT hstmt,
148 SQLUSMALLINT icol,
149 SQLSMALLINT fCType,
150 PTR rgbValue,
151 SQLLEN cbValueMax,
152 SQLLEN * pcbValue)
153 {
154 StatementClass *stmt = (StatementClass *) hstmt;
155 CSTR func = "PGAPI_BindCol";
156 ARDFields *opts;
157 GetDataInfo *gdata_info;
158 BindInfoClass *bookmark;
159 RETCODE ret = SQL_SUCCESS;
160
161 MYLOG(0, "entering...\n");
162
163 MYLOG(0, "**** : stmt = %p, icol = %d\n", stmt, icol);
164 MYLOG(0, "**** : fCType=%d rgb=%p valusMax=" FORMAT_LEN " pcb=%p\n", fCType, rgbValue, cbValueMax, pcbValue);
165
166 if (!stmt)
167 {
168 SC_log_error(func, "", NULL);
169 return SQL_INVALID_HANDLE;
170 }
171
172 opts = SC_get_ARDF(stmt);
173 if (stmt->status == STMT_EXECUTING)
174 {
175 SC_set_error(stmt, STMT_SEQUENCE_ERROR, "Can't bind columns while statement is still executing.", func);
176 return SQL_ERROR;
177 }
178
179 #define return DONT_CALL_RETURN_FROM_HERE ???
180 SC_clear_error(stmt);
181 /* If the bookmark column is being bound, then just save it */
182 if (icol == 0)
183 {
184 bookmark = opts->bookmark;
185 if (rgbValue == NULL)
186 {
187 if (bookmark)
188 {
189 bookmark->buffer = NULL;
190 bookmark->used =
191 bookmark->indicator = NULL;
192 }
193 }
194 else
195 {
196 /* Make sure it is the bookmark data type */
197 switch (fCType)
198 {
199 case SQL_C_BOOKMARK:
200 case SQL_C_VARBOOKMARK:
201 break;
202 default:
203 SC_set_error(stmt, STMT_PROGRAM_TYPE_OUT_OF_RANGE, "Bind column 0 is not of type SQL_C_BOOKMARK", func);
204 MYLOG(DETAIL_LOG_LEVEL, "Bind column 0 is type %d not of type SQL_C_BOOKMARK\n", fCType);
205 ret = SQL_ERROR;
206 goto cleanup;
207 }
208
209 bookmark = ARD_AllocBookmark(opts);
210 bookmark->buffer = rgbValue;
211 bookmark->used =
212 bookmark->indicator = pcbValue;
213 bookmark->buflen = cbValueMax;
214 bookmark->returntype = fCType;
215 }
216 goto cleanup;
217 }
218
219 /*
220 * Allocate enough bindings if not already done. Most likely,
221 * execution of a statement would have setup the necessary bindings.
222 * But some apps call BindCol before any statement is executed.
223 */
224 if (icol > opts->allocated)
225 extend_column_bindings(opts, icol);
226 gdata_info = SC_get_GDTI(stmt);
227 if (icol > gdata_info->allocated)
228 extend_getdata_info(gdata_info, icol, FALSE);
229
230 /* check to see if the bindings were allocated */
231 if (!opts->bindings || !gdata_info->gdata)
232 {
233 SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Could not allocate memory for bindings.", func);
234 ret = SQL_ERROR;
235 goto cleanup;
236 }
237
238 /* use zero based col numbers from here out */
239 icol--;
240
241 /* Reset for SQLGetData */
242 GETDATA_RESET(gdata_info->gdata[icol]);
243
244 if (rgbValue == NULL)
245 {
246 /* we have to unbind the column */
247 opts->bindings[icol].buflen = 0;
248 opts->bindings[icol].buffer = NULL;
249 opts->bindings[icol].used =
250 opts->bindings[icol].indicator = NULL;
251 opts->bindings[icol].returntype = SQL_C_CHAR;
252 opts->bindings[icol].precision = 0;
253 opts->bindings[icol].scale = 0;
254 if (gdata_info->gdata[icol].ttlbuf)
255 free(gdata_info->gdata[icol].ttlbuf);
256 gdata_info->gdata[icol].ttlbuf = NULL;
257 gdata_info->gdata[icol].ttlbuflen = 0;
258 gdata_info->gdata[icol].ttlbufused = 0;
259 }
260 else
261 {
262 /* ok, bind that column */
263 opts->bindings[icol].buflen = cbValueMax;
264 opts->bindings[icol].buffer = rgbValue;
265 opts->bindings[icol].used =
266 opts->bindings[icol].indicator = pcbValue;
267 opts->bindings[icol].returntype = fCType;
268 opts->bindings[icol].precision = 0;
269 switch (fCType)
270 {
271 case SQL_C_NUMERIC:
272 opts->bindings[icol].precision = 32;
273 break;
274 case SQL_C_TIMESTAMP:
275 case SQL_C_INTERVAL_DAY_TO_SECOND:
276 case SQL_C_INTERVAL_HOUR_TO_SECOND:
277 case SQL_C_INTERVAL_MINUTE_TO_SECOND:
278 case SQL_C_INTERVAL_SECOND:
279 opts->bindings[icol].precision = 6;
280 break;
281 }
282 opts->bindings[icol].scale = 0;
283
284 MYLOG(0, " bound buffer[%d] = %p\n", icol, opts->bindings[icol].buffer);
285 }
286
287 cleanup:
288 #undef return
289 return ret;
290 }
291
292
293 /*
294 * Returns the description of a parameter marker.
295 * This function is listed as not being supported by SQLGetFunctions() because it is
296 * used to describe "parameter markers" (not bound parameters), in which case,
297 * the dbms should return info on the markers. Since Postgres doesn't support that,
298 * it is best to say this function is not supported and let the application assume a
299 * data type (most likely varchar).
300 */
301 RETCODE SQL_API
PGAPI_DescribeParam(HSTMT hstmt,SQLUSMALLINT ipar,SQLSMALLINT * pfSqlType,SQLULEN * pcbParamDef,SQLSMALLINT * pibScale,SQLSMALLINT * pfNullable)302 PGAPI_DescribeParam(HSTMT hstmt,
303 SQLUSMALLINT ipar,
304 SQLSMALLINT * pfSqlType,
305 SQLULEN * pcbParamDef,
306 SQLSMALLINT * pibScale,
307 SQLSMALLINT * pfNullable)
308 {
309 StatementClass *stmt = (StatementClass *) hstmt;
310 CSTR func = "PGAPI_DescribeParam";
311 IPDFields *ipdopts;
312 RETCODE ret = SQL_SUCCESS;
313 int num_params;
314 OID pgtype;
315 ConnectionClass *conn;
316
317 MYLOG(0, "entering...%d\n", ipar);
318
319 if (!stmt)
320 {
321 SC_log_error(func, "", NULL);
322 return SQL_INVALID_HANDLE;
323 }
324 conn = SC_get_conn(stmt);
325 SC_clear_error(stmt);
326
327 ipdopts = SC_get_IPDF(stmt);
328 /*if ((ipar < 1) || (ipar > ipdopts->allocated))*/
329 num_params = stmt->num_params;
330 if (num_params < 0)
331 {
332 SQLSMALLINT num_p;
333
334 PGAPI_NumParams(stmt, &num_p);
335 num_params = num_p;
336 }
337 if ((ipar < 1) || (ipar > num_params))
338 {
339 MYLOG(DETAIL_LOG_LEVEL, "num_params=%d\n", stmt->num_params);
340 SC_set_error(stmt, STMT_BAD_PARAMETER_NUMBER_ERROR, "Invalid parameter number for PGAPI_DescribeParam.", func);
341 return SQL_ERROR;
342 }
343 extend_iparameter_bindings(ipdopts, stmt->num_params);
344
345 #define return DONT_CALL_RETURN_FROM_HERE???
346 /* StartRollbackState(stmt); */
347 if (NOT_YET_PREPARED == stmt->prepared)
348 {
349 decideHowToPrepare(stmt, FALSE);
350 MYLOG(DETAIL_LOG_LEVEL, "howTo=%d\n", SC_get_prepare_method(stmt));
351 switch (SC_get_prepare_method(stmt))
352 {
353 case NAMED_PARSE_REQUEST:
354 case PARSE_TO_EXEC_ONCE:
355 case PARSE_REQ_FOR_INFO:
356 if (ret = prepareParameters(stmt, FALSE), SQL_ERROR == ret)
357 goto cleanup;
358 }
359 }
360
361 ipar--;
362 pgtype = PIC_get_pgtype(ipdopts->parameters[ipar]);
363 /*
364 * This implementation is not very good, since it is supposed to
365 * describe
366 */
367 /* parameter markers, not bound parameters. */
368 if (pfSqlType)
369 {
370 MYLOG(DETAIL_LOG_LEVEL, "[%d].SQLType=%d .PGType=%d\n", ipar, ipdopts->parameters[ipar].SQLType, pgtype);
371 if (ipdopts->parameters[ipar].SQLType)
372 *pfSqlType = ipdopts->parameters[ipar].SQLType;
373 else if (pgtype)
374 *pfSqlType = pgtype_attr_to_concise_type(conn, pgtype, PG_ATP_UNSET, PG_ADT_UNSET, PG_UNKNOWNS_UNSET);
375 else
376 {
377 ret = SQL_ERROR;
378 SC_set_error(stmt, STMT_EXEC_ERROR, "Unfortunatley couldn't get this paramater's info", func);
379 goto cleanup;
380 }
381 }
382
383 if (pcbParamDef)
384 {
385 *pcbParamDef = 0;
386 if (ipdopts->parameters[ipar].SQLType)
387 *pcbParamDef = ipdopts->parameters[ipar].column_size;
388 if (0 == *pcbParamDef && pgtype)
389 *pcbParamDef = pgtype_attr_column_size(conn, pgtype, PG_ATP_UNSET, PG_ADT_UNSET, PG_UNKNOWNS_UNSET);
390 }
391
392 if (pibScale)
393 {
394 *pibScale = 0;
395 if (ipdopts->parameters[ipar].SQLType)
396 *pibScale = ipdopts->parameters[ipar].decimal_digits;
397 else if (pgtype)
398 *pibScale = pgtype_scale(stmt, pgtype, -1);
399 }
400
401 if (pfNullable)
402 *pfNullable = pgtype_nullable(SC_get_conn(stmt), ipdopts->parameters[ipar].paramType);
403 cleanup:
404 #undef return
405 return ret;
406 }
407
408
409 /*
410 * This function should really talk to the dbms to determine the number of
411 * "parameter markers" (not bound parameters) in the statement. But, since
412 * Postgres doesn't support that, the driver should just count the number of markers
413 * and return that. The reason the driver just can't say this function is unsupported
414 * like it does for SQLDescribeParam is that some applications don't care and try
415 * to call it anyway.
416 * If the statement does not have parameters, it should just return 0.
417 */
418 RETCODE SQL_API
PGAPI_NumParams(HSTMT hstmt,SQLSMALLINT * pcpar)419 PGAPI_NumParams(HSTMT hstmt,
420 SQLSMALLINT * pcpar)
421 {
422 StatementClass *stmt = (StatementClass *) hstmt;
423 CSTR func = "PGAPI_NumParams";
424
425 MYLOG(0, "entering...\n");
426
427 if (!stmt)
428 {
429 SC_log_error(func, "", NULL);
430 return SQL_INVALID_HANDLE;
431 }
432
433 if (pcpar)
434 *pcpar = 0;
435 else
436 {
437 SC_set_error(stmt, STMT_EXEC_ERROR, "parameter count address is null", func);
438 return SQL_ERROR;
439 }
440 MYLOG(DETAIL_LOG_LEVEL, "num_params=%d,%d\n", stmt->num_params, stmt->proc_return);
441 if (stmt->num_params >= 0)
442 *pcpar = stmt->num_params;
443 else if (!stmt->statement)
444 {
445 /* no statement has been allocated */
446 SC_set_error(stmt, STMT_SEQUENCE_ERROR, "PGAPI_NumParams called with no statement ready.", func);
447 return SQL_ERROR;
448 }
449 else
450 {
451 po_ind_t multi = FALSE, proc_return = 0;
452
453 stmt->proc_return = 0;
454 SC_scanQueryAndCountParams(stmt->statement, SC_get_conn(stmt), NULL, pcpar, &multi, &proc_return);
455 stmt->num_params = *pcpar;
456 stmt->proc_return = proc_return;
457 stmt->multi_statement = multi;
458 }
459 MYLOG(DETAIL_LOG_LEVEL, "num_params=%d,%d\n", stmt->num_params, stmt->proc_return);
460 return SQL_SUCCESS;
461 }
462
463
464 /*
465 * Bindings Implementation
466 */
467 static BindInfoClass *
create_empty_bindings(int num_columns)468 create_empty_bindings(int num_columns)
469 {
470 BindInfoClass *new_bindings;
471 int i;
472
473 new_bindings = (BindInfoClass *) malloc(num_columns * sizeof(BindInfoClass));
474 if (!new_bindings)
475 return NULL;
476
477 for (i = 0; i < num_columns; i++)
478 {
479 new_bindings[i].buflen = 0;
480 new_bindings[i].buffer = NULL;
481 new_bindings[i].used =
482 new_bindings[i].indicator = NULL;
483 }
484
485 return new_bindings;
486 }
487
488 void
extend_parameter_bindings(APDFields * self,int num_params)489 extend_parameter_bindings(APDFields *self, int num_params)
490 {
491 ParameterInfoClass *new_bindings;
492
493 MYLOG(0, "entering ... self=%p, parameters_allocated=%d, num_params=%d,%p\n", self, self->allocated, num_params, self->parameters);
494
495 /*
496 * if we have too few, allocate room for more, and copy the old
497 * entries into the new structure
498 */
499 if (self->allocated < num_params)
500 {
501 new_bindings = (ParameterInfoClass *) realloc(self->parameters, sizeof(ParameterInfoClass) * num_params);
502 if (!new_bindings)
503 {
504 MYLOG(0, "unable to create %d new bindings from %d old bindings\n", num_params, self->allocated);
505
506 if (self->parameters)
507 free(self->parameters);
508 self->parameters = NULL;
509 self->allocated = 0;
510 return;
511 }
512 memset(&new_bindings[self->allocated], 0, sizeof(ParameterInfoClass) * (num_params - self->allocated));
513
514 self->parameters = new_bindings;
515 self->allocated = num_params;
516 }
517
518 MYLOG(0, "leaving %p\n", self->parameters);
519 }
520
521 void
extend_iparameter_bindings(IPDFields * self,int num_params)522 extend_iparameter_bindings(IPDFields *self, int num_params)
523 {
524 ParameterImplClass *new_bindings;
525
526 MYLOG(0, "entering ... self=%p, parameters_allocated=%d, num_params=%d\n", self, self->allocated, num_params);
527
528 /*
529 * if we have too few, allocate room for more, and copy the old
530 * entries into the new structure
531 */
532 if (self->allocated < num_params)
533 {
534 new_bindings = (ParameterImplClass *) realloc(self->parameters, sizeof(ParameterImplClass) * num_params);
535 if (!new_bindings)
536 {
537 MYLOG(0, "unable to create %d new bindings from %d old bindings\n", num_params, self->allocated);
538
539 if (self->parameters)
540 free(self->parameters);
541 self->parameters = NULL;
542 self->allocated = 0;
543 return;
544 }
545 memset(&new_bindings[self->allocated], 0,
546 sizeof(ParameterImplClass) * (num_params - self->allocated));
547
548 self->parameters = new_bindings;
549 self->allocated = num_params;
550 }
551
552 MYLOG(0, "leaving %p\n", self->parameters);
553 }
554
555 void
reset_a_parameter_binding(APDFields * self,int ipar)556 reset_a_parameter_binding(APDFields *self, int ipar)
557 {
558
559 MYLOG(0, "entering ... self=%p, parameters_allocated=%d, ipar=%d\n", self, self->allocated, ipar);
560
561 if (ipar < 1 || ipar > self->allocated)
562 return;
563
564 ipar--;
565 self->parameters[ipar].buflen = 0;
566 self->parameters[ipar].buffer = NULL;
567 self->parameters[ipar].used =
568 self->parameters[ipar].indicator = NULL;
569 self->parameters[ipar].CType = 0;
570 self->parameters[ipar].data_at_exec = FALSE;
571 self->parameters[ipar].precision = 0;
572 self->parameters[ipar].scale = 0;
573 }
574
575 void
reset_a_iparameter_binding(IPDFields * self,int ipar)576 reset_a_iparameter_binding(IPDFields *self, int ipar)
577 {
578 MYLOG(0, "entering ... self=%p, parameters_allocated=%d, ipar=%d\n", self, self->allocated, ipar);
579
580 if (ipar < 1 || ipar > self->allocated)
581 return;
582
583 ipar--;
584 NULL_THE_NAME(self->parameters[ipar].paramName);
585 self->parameters[ipar].paramType = 0;
586 self->parameters[ipar].SQLType = 0;
587 self->parameters[ipar].column_size = 0;
588 self->parameters[ipar].decimal_digits = 0;
589 self->parameters[ipar].precision = 0;
590 self->parameters[ipar].scale = 0;
591 PIC_set_pgtype(self->parameters[ipar], 0);
592 }
593
594 int
CountParameters(const StatementClass * self,Int2 * inputCount,Int2 * ioCount,Int2 * outputCount)595 CountParameters(const StatementClass *self, Int2 *inputCount, Int2 *ioCount, Int2 *outputCount)
596 {
597 IPDFields *ipdopts = SC_get_IPDF(self);
598 int i, num_params, valid_count;
599
600 if (inputCount)
601 *inputCount = 0;
602 if (ioCount)
603 *ioCount = 0;
604 if (outputCount)
605 *outputCount = 0;
606 if (!ipdopts) return -1;
607 num_params = self->num_params;
608 if (ipdopts->allocated < num_params)
609 num_params = ipdopts->allocated;
610 for (i = 0, valid_count = 0; i < num_params; i++)
611 {
612 if (SQL_PARAM_OUTPUT == ipdopts->parameters[i].paramType)
613 {
614 if (outputCount)
615 {
616 (*outputCount)++;
617 valid_count++;
618 }
619 }
620 else if (SQL_PARAM_INPUT_OUTPUT == ipdopts->parameters[i].paramType)
621 {
622 if (ioCount)
623 {
624 (*ioCount)++;
625 valid_count++;
626 }
627 }
628 else if (inputCount)
629 {
630 (*inputCount)++;
631 valid_count++;
632 }
633 }
634 return valid_count;
635 }
636
637 /*
638 * Free parameters and free the memory.
639 */
640 void
APD_free_params(APDFields * apdopts,char option)641 APD_free_params(APDFields *apdopts, char option)
642 {
643 MYLOG(0, "entering self=%p\n", apdopts);
644
645 if (!apdopts->parameters)
646 return;
647
648 if (option == STMT_FREE_PARAMS_ALL)
649 {
650 free(apdopts->parameters);
651 apdopts->parameters = NULL;
652 apdopts->allocated = 0;
653 }
654
655 MYLOG(0, "leaving\n");
656 }
657
658 void
PDATA_free_params(PutDataInfo * pdata,char option)659 PDATA_free_params(PutDataInfo *pdata, char option)
660 {
661 int i;
662
663 MYLOG(0, "entering self=%p\n", pdata);
664
665 if (!pdata->pdata)
666 return;
667
668 for (i = 0; i < pdata->allocated; i++)
669 {
670 if (pdata->pdata[i].EXEC_used)
671 {
672 free(pdata->pdata[i].EXEC_used);
673 pdata->pdata[i].EXEC_used = NULL;
674 }
675 if (pdata->pdata[i].EXEC_buffer)
676 {
677 free(pdata->pdata[i].EXEC_buffer);
678 pdata->pdata[i].EXEC_buffer = NULL;
679 }
680 }
681
682 if (option == STMT_FREE_PARAMS_ALL)
683 {
684 free(pdata->pdata);
685 pdata->pdata = NULL;
686 pdata->allocated = 0;
687 }
688
689 MYLOG(0, "leaving\n");
690 }
691
692 /*
693 * Free parameters and free the memory.
694 */
695 void
IPD_free_params(IPDFields * ipdopts,char option)696 IPD_free_params(IPDFields *ipdopts, char option)
697 {
698 MYLOG(0, "entering self=%p\n", ipdopts);
699
700 if (!ipdopts->parameters)
701 return;
702 if (option == STMT_FREE_PARAMS_ALL)
703 {
704 free(ipdopts->parameters);
705 ipdopts->parameters = NULL;
706 ipdopts->allocated = 0;
707 }
708
709 MYLOG(0, "leaving\n");
710 }
711
712 void
extend_column_bindings(ARDFields * self,int num_columns)713 extend_column_bindings(ARDFields *self, int num_columns)
714 {
715 BindInfoClass *new_bindings;
716 int i;
717
718 MYLOG(0, "entering ... self=%p, bindings_allocated=%d, num_columns=%d\n", self, self->allocated, num_columns);
719
720 /*
721 * if we have too few, allocate room for more, and copy the old
722 * entries into the new structure
723 */
724 if (self->allocated < num_columns)
725 {
726 new_bindings = create_empty_bindings(num_columns);
727 if (!new_bindings)
728 {
729 MYLOG(0, "unable to create %d new bindings from %d old bindings\n", num_columns, self->allocated);
730
731 if (self->bindings)
732 {
733 free(self->bindings);
734 self->bindings = NULL;
735 }
736 self->allocated = 0;
737 return;
738 }
739
740 if (self->bindings)
741 {
742 for (i = 0; i < self->allocated; i++)
743 new_bindings[i] = self->bindings[i];
744
745 free(self->bindings);
746 }
747
748 self->bindings = new_bindings;
749 self->allocated = num_columns;
750 }
751
752 /*
753 * There is no reason to zero out extra bindings if there are more
754 * than needed. If an app has allocated extra bindings, let it worry
755 * about it by unbinding those columns.
756 */
757
758 /* SQLBindCol(1..) ... SQLBindCol(10...) # got 10 bindings */
759 /* SQLExecDirect(...) # returns 5 cols */
760 /* SQLExecDirect(...) # returns 10 cols (now OK) */
761
762 MYLOG(0, "leaving %p\n", self->bindings);
763 }
764
765 void
reset_a_column_binding(ARDFields * self,int icol)766 reset_a_column_binding(ARDFields *self, int icol)
767 {
768 BindInfoClass *bookmark;
769
770 MYLOG(0, "entering ... self=%p, bindings_allocated=%d, icol=%d\n", self, self->allocated, icol);
771
772 if (icol > self->allocated)
773 return;
774
775 /* use zero based col numbers from here out */
776 if (0 == icol)
777 {
778 if (bookmark = self->bookmark, bookmark != NULL)
779 {
780 bookmark->buffer = NULL;
781 bookmark->used =
782 bookmark->indicator = NULL;
783 }
784 }
785 else
786 {
787 icol--;
788
789 /* we have to unbind the column */
790 self->bindings[icol].buflen = 0;
791 self->bindings[icol].buffer = NULL;
792 self->bindings[icol].used =
793 self->bindings[icol].indicator = NULL;
794 self->bindings[icol].returntype = SQL_C_CHAR;
795 }
796 }
797
ARD_unbind_cols(ARDFields * self,BOOL freeall)798 void ARD_unbind_cols(ARDFields *self, BOOL freeall)
799 {
800 Int2 lf;
801
802 MYLOG(DETAIL_LOG_LEVEL, "freeall=%d allocated=%d bindings=%p\n", freeall, self->allocated, self->bindings);
803 for (lf = 1; lf <= self->allocated; lf++)
804 reset_a_column_binding(self, lf);
805 if (freeall)
806 {
807 if (self->bindings)
808 free(self->bindings);
809 self->bindings = NULL;
810 self->allocated = 0;
811 }
812 }
GDATA_unbind_cols(GetDataInfo * self,BOOL freeall)813 void GDATA_unbind_cols(GetDataInfo *self, BOOL freeall)
814 {
815 Int2 lf;
816
817 MYLOG(DETAIL_LOG_LEVEL, "freeall=%d allocated=%d gdata=%p\n", freeall, self->allocated, self->gdata);
818 if (self->fdata.ttlbuf)
819 {
820 free(self->fdata.ttlbuf);
821 self->fdata.ttlbuf = NULL;
822 }
823 self->fdata.ttlbuflen = self->fdata.ttlbufused = 0;
824 GETDATA_RESET(self->fdata);
825 for (lf = 1; lf <= self->allocated; lf++)
826 reset_a_getdata_info(self, lf);
827 if (freeall)
828 {
829 if (self->gdata)
830 free(self->gdata);
831 self->gdata = NULL;
832 self->allocated = 0;
833 }
834 }
835
GetDataInfoInitialize(GetDataInfo * gdata_info)836 void GetDataInfoInitialize(GetDataInfo *gdata_info)
837 {
838 GETDATA_RESET(gdata_info->fdata);
839 gdata_info->fdata.ttlbuf = NULL;
840 gdata_info->fdata.ttlbuflen = gdata_info->fdata.ttlbufused = 0;
841 gdata_info->allocated = 0;
842 gdata_info->gdata = NULL;
843 }
844 static GetDataClass *
create_empty_gdata(int num_columns)845 create_empty_gdata(int num_columns)
846 {
847 GetDataClass *new_gdata;
848 int i;
849
850 new_gdata = (GetDataClass *) malloc(num_columns * sizeof(GetDataClass));
851 if (!new_gdata)
852 return NULL;
853 for (i = 0; i < num_columns; i++)
854 {
855 GETDATA_RESET(new_gdata[i]);
856 new_gdata[i].ttlbuf = NULL;
857 new_gdata[i].ttlbuflen = 0;
858 new_gdata[i].ttlbufused = 0;
859 }
860
861 return new_gdata;
862 }
863 void
extend_getdata_info(GetDataInfo * self,int num_columns,BOOL shrink)864 extend_getdata_info(GetDataInfo *self, int num_columns, BOOL shrink)
865 {
866 GetDataClass *new_gdata;
867
868 MYLOG(0, "entering ... self=%p, gdata_allocated=%d, num_columns=%d\n", self, self->allocated, num_columns);
869
870 /*
871 * if we have too few, allocate room for more, and copy the old
872 * entries into the new structure
873 */
874 if (self->allocated < num_columns)
875 {
876 new_gdata = create_empty_gdata(num_columns);
877 if (!new_gdata)
878 {
879 MYLOG(0, "unable to create %d new gdata from %d old gdata\n", num_columns, self->allocated);
880
881 if (self->gdata)
882 {
883 free(self->gdata);
884 self->gdata = NULL;
885 }
886 self->allocated = 0;
887 return;
888 }
889 if (self->gdata)
890 {
891 size_t i;
892
893 for (i = 0; i < self->allocated; i++)
894 new_gdata[i] = self->gdata[i];
895 free(self->gdata);
896 }
897 self->gdata = new_gdata;
898 self->allocated = num_columns;
899 }
900 else if (shrink && self->allocated > num_columns)
901 {
902 int i;
903
904 for (i = self->allocated; i > num_columns; i--)
905 reset_a_getdata_info(self, i);
906 self->allocated = num_columns;
907 if (0 == num_columns)
908 {
909 free(self->gdata);
910 self->gdata = NULL;
911 }
912 }
913
914 /*
915 * There is no reason to zero out extra gdata if there are more
916 * than needed. If an app has allocated extra gdata, let it worry
917 * about it by unbinding those columns.
918 */
919
920 MYLOG(0, "leaving %p\n", self->gdata);
921 }
reset_a_getdata_info(GetDataInfo * gdata_info,int icol)922 void reset_a_getdata_info(GetDataInfo *gdata_info, int icol)
923 {
924 if (icol < 1 || icol > gdata_info->allocated)
925 return;
926 icol--;
927 if (gdata_info->gdata[icol].ttlbuf)
928 {
929 free(gdata_info->gdata[icol].ttlbuf);
930 gdata_info->gdata[icol].ttlbuf = NULL;
931 }
932 gdata_info->gdata[icol].ttlbuflen =
933 gdata_info->gdata[icol].ttlbufused = 0;
934 GETDATA_RESET(gdata_info->gdata[icol]);
935 }
936
PutDataInfoInitialize(PutDataInfo * pdata_info)937 void PutDataInfoInitialize(PutDataInfo *pdata_info)
938 {
939 pdata_info->allocated = 0;
940 pdata_info->pdata = NULL;
941 }
942 void
extend_putdata_info(PutDataInfo * self,int num_params,BOOL shrink)943 extend_putdata_info(PutDataInfo *self, int num_params, BOOL shrink)
944 {
945 PutDataClass *new_pdata;
946
947 MYLOG(0, "entering ... self=%p, parameters_allocated=%d, num_params=%d\n", self, self->allocated, num_params);
948
949 /*
950 * if we have too few, allocate room for more, and copy the old
951 * entries into the new structure
952 */
953 if (self->allocated < num_params)
954 {
955 if (self->allocated <= 0 && self->pdata)
956 {
957 MYLOG(0, "??? pdata is not null while allocated == 0\n");
958 self->pdata = NULL;
959 }
960 new_pdata = (PutDataClass *) realloc(self->pdata, sizeof(PutDataClass) * num_params);
961 if (!new_pdata)
962 {
963 MYLOG(0, "unable to create %d new pdata from %d old pdata\n", num_params, self->allocated);
964
965 self->pdata = NULL;
966 self->allocated = 0;
967 return;
968 }
969 memset(&new_pdata[self->allocated], 0,
970 sizeof(PutDataClass) * (num_params - self->allocated));
971
972 self->pdata = new_pdata;
973 self->allocated = num_params;
974 }
975 else if (shrink && self->allocated > num_params)
976 {
977 int i;
978
979 for (i = self->allocated; i > num_params; i--)
980 reset_a_putdata_info(self, i);
981 self->allocated = num_params;
982 if (0 == num_params)
983 {
984 free(self->pdata);
985 self->pdata = NULL;
986 }
987 }
988
989 MYLOG(0, "leaving %p\n", self->pdata);
990 }
reset_a_putdata_info(PutDataInfo * pdata_info,int ipar)991 void reset_a_putdata_info(PutDataInfo *pdata_info, int ipar)
992 {
993 if (ipar < 1 || ipar > pdata_info->allocated)
994 return;
995 ipar--;
996 if (pdata_info->pdata[ipar].EXEC_used)
997 {
998 free(pdata_info->pdata[ipar].EXEC_used);
999 pdata_info->pdata[ipar].EXEC_used = NULL;
1000 }
1001 if (pdata_info->pdata[ipar].EXEC_buffer)
1002 {
1003 free(pdata_info->pdata[ipar].EXEC_buffer);
1004 pdata_info->pdata[ipar].EXEC_buffer = NULL;
1005 }
1006 pdata_info->pdata[ipar].lobj_oid = 0;
1007 }
1008
SC_param_next(const StatementClass * stmt,int * param_number,ParameterInfoClass ** apara,ParameterImplClass ** ipara)1009 void SC_param_next(const StatementClass *stmt, int *param_number, ParameterInfoClass **apara, ParameterImplClass **ipara)
1010 {
1011 int next;
1012 IPDFields *ipdopts = SC_get_IPDF(stmt);
1013
1014 if (*param_number < 0)
1015 next = stmt->proc_return;
1016 else
1017 next = *param_number + 1;
1018 if (stmt->discard_output_params)
1019 {
1020 for (;next < ipdopts->allocated && SQL_PARAM_OUTPUT == ipdopts->parameters[next].paramType; next++) ;
1021 }
1022 *param_number = next;
1023 if (ipara)
1024 {
1025 if (next < ipdopts->allocated)
1026 *ipara = ipdopts->parameters + next;
1027 else
1028 *ipara = NULL;
1029 }
1030 if (apara)
1031 {
1032 APDFields *apdopts = SC_get_APDF(stmt);
1033 if (next < apdopts->allocated)
1034 *apara = apdopts->parameters + next;
1035 else
1036 *apara = NULL;
1037 }
1038 }
1039