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