Merge commit 'origin/master'
[versaplex.git] / vxodbc / bind.cc
blob62cd99a7fd7745b92575e2dafef92abdf66ca7f9
1 /*
2 * Description: This module contains routines related to binding
3 * columns and parameters.
4 */
5 #include <string.h>
6 #include <ctype.h>
7 #include "bind.h"
8 #include "misc.h"
10 #include "environ.h"
11 #include "statement.h"
12 #include "descriptor.h"
13 #include "qresult.h"
14 #include "pgtypes.h"
15 #include "multibyte.h"
17 #include "pgapifunc.h"
20 /* Bind parameters on a statement handle */
21 RETCODE SQL_API
22 PGAPI_BindParameter(HSTMT hstmt,
23 SQLUSMALLINT ipar,
24 SQLSMALLINT fParamType,
25 SQLSMALLINT fCType,
26 SQLSMALLINT fSqlType,
27 SQLULEN cbColDef,
28 SQLSMALLINT ibScale,
29 PTR rgbValue,
30 SQLLEN cbValueMax, SQLLEN FAR * pcbValue)
32 StatementClass *stmt = (StatementClass *) hstmt;
33 CSTR func = "PGAPI_BindParameter";
34 mylog("PGAPI_BindParameter not yet implemented");
35 SC_log_error(func, "PGAPI_BindParameter not yet implemented", stmt);
36 return SQL_ERROR;
40 /* Associate a user-supplied buffer with a database column. */
41 RETCODE SQL_API
42 PGAPI_BindCol(HSTMT hstmt,
43 SQLUSMALLINT icol,
44 SQLSMALLINT fCType,
45 PTR rgbValue, SQLLEN cbValueMax, SQLLEN FAR * pcbValue)
47 CSTR func = "PGAPI_BindCol";
48 StatementClass *stmt = (StatementClass *) hstmt;
49 ARDFields *opts;
50 GetDataInfo *gdata_info;
51 BindInfoClass *bookmark;
52 RETCODE ret = SQL_SUCCESS;
54 mylog("Entering(%p, %d)\n", stmt, icol);
55 mylog("fCType=%d rgb=%p valusMax=%d pcb=%p\n",
56 fCType, rgbValue, cbValueMax, pcbValue);
58 if (!stmt)
60 SC_log_error(func, "", NULL);
61 return SQL_INVALID_HANDLE;
64 opts = SC_get_ARDF(stmt);
65 if (stmt->status == STMT_EXECUTING)
67 SC_set_error(stmt, STMT_SEQUENCE_ERROR,
68 "Can't bind columns while statement is still executing.",
69 func);
70 return SQL_ERROR;
72 #define return DONT_CALL_RETURN_FROM_HERE ???
73 SC_clear_error(stmt);
74 /* If the bookmark column is being bound, then just save it */
75 if (icol == 0)
77 bookmark = opts->bookmark;
78 if (rgbValue == NULL)
80 if (bookmark)
82 bookmark->buffer = NULL;
83 bookmark->used = bookmark->indicator = NULL;
86 else
88 /* Make sure it is the bookmark data type */
89 switch (fCType)
91 case SQL_C_BOOKMARK:
92 case SQL_C_VARBOOKMARK:
93 break;
94 default:
95 SC_set_error(stmt, STMT_PROGRAM_TYPE_OUT_OF_RANGE,
96 "Bind column 0 is not of type SQL_C_BOOKMARK",
97 func);
98 inolog
99 ("Bind column 0 is type %d not of type SQL_C_BOOKMARK",
100 fCType);
101 ret = SQL_ERROR;
102 goto cleanup;
105 bookmark = ARD_AllocBookmark(opts);
106 bookmark->buffer = (char *)rgbValue;
107 bookmark->used = bookmark->indicator = pcbValue;
108 bookmark->buflen = cbValueMax;
109 bookmark->returntype = fCType;
111 goto cleanup;
115 * Allocate enough bindings if not already done. Most likely,
116 * execution of a statement would have setup the necessary bindings.
117 * But some apps call BindCol before any statement is executed.
119 if (icol > opts->allocated)
120 extend_column_bindings(opts, icol);
121 gdata_info = SC_get_GDTI(stmt);
122 if (icol > gdata_info->allocated)
123 extend_getdata_info(gdata_info, icol, FALSE);
125 /* check to see if the bindings were allocated */
126 if (!opts->bindings)
128 SC_set_error(stmt, STMT_NO_MEMORY_ERROR,
129 "Could not allocate memory for bindings.", func);
130 ret = SQL_ERROR;
131 goto cleanup;
134 /* use zero based col numbers from here out */
135 icol--;
137 /* Reset for SQLGetData */
138 gdata_info->gdata[icol].data_left = -1;
140 if (rgbValue == NULL)
142 /* we have to unbind the column */
143 opts->bindings[icol].buflen = 0;
144 opts->bindings[icol].buffer = NULL;
145 opts->bindings[icol].used =
146 opts->bindings[icol].indicator = NULL;
147 opts->bindings[icol].returntype = SQL_C_CHAR;
148 opts->bindings[icol].precision = 0;
149 opts->bindings[icol].scale = 0;
150 if (gdata_info->gdata[icol].ttlbuf)
151 free(gdata_info->gdata[icol].ttlbuf);
152 gdata_info->gdata[icol].ttlbuf = NULL;
153 gdata_info->gdata[icol].ttlbuflen = 0;
154 gdata_info->gdata[icol].ttlbufused = 0;
156 else
158 /* ok, bind that column */
159 opts->bindings[icol].buflen = cbValueMax;
160 opts->bindings[icol].buffer = (char *)rgbValue;
161 opts->bindings[icol].used =
162 opts->bindings[icol].indicator = pcbValue;
163 opts->bindings[icol].returntype = fCType;
164 if (SQL_C_NUMERIC == fCType)
165 opts->bindings[icol].precision = 32;
166 else
167 opts->bindings[icol].precision = 0;
168 opts->bindings[icol].scale = 0;
170 mylog("bound buffer[%d] = %p\n", icol,
171 opts->bindings[icol].buffer);
174 cleanup:
175 #undef return
176 if (stmt->internal)
177 ret = DiscardStatementSvp(stmt, ret, FALSE);
178 return ret;
183 * Returns the description of a parameter marker.
184 * This function is listed as not being supported by SQLGetFunctions() because it is
185 * used to describe "parameter markers" (not bound parameters), in which case,
186 * the dbms should return info on the markers. Since Postgres doesn't support that,
187 * it is best to say this function is not supported and let the application assume a
188 * data type (most likely varchar).
190 RETCODE SQL_API
191 PGAPI_DescribeParam(HSTMT hstmt,
192 SQLUSMALLINT ipar,
193 SQLSMALLINT FAR * pfSqlType,
194 SQLULEN FAR * pcbParamDef,
195 SQLSMALLINT FAR * pibScale,
196 SQLSMALLINT FAR * pfNullable)
198 StatementClass *stmt = (StatementClass *) hstmt;
199 CSTR func = "PGAPI_DescribeParam";
200 SC_set_error(stmt, STMT_EXEC_ERROR,
201 "SQLDescribeParam is not yet supported", func);
202 return SQL_ERROR;
207 * This function should really talk to the dbms to determine the number of
208 * "parameter markers" (not bound parameters) in the statement. But, since
209 * Postgres doesn't support that, the driver should just count the number
210 * of markers and return that. The reason the driver just can't say this
211 * function is unsupported like it does for SQLDescribeParam is that some
212 * applications don't care and try to call it anyway. If the statement does
213 * not have parameters, it should just return 0.
215 RETCODE SQL_API PGAPI_NumParams(HSTMT hstmt, SQLSMALLINT FAR * pcpar)
217 StatementClass *stmt = (StatementClass *) hstmt;
218 CSTR func = "PGAPI_NumParams";
220 SC_set_error(stmt, STMT_EXEC_ERROR,
221 "PGAPI_NumParams is not yet supported", func);
222 return SQL_ERROR;
227 * Bindings Implementation
229 static BindInfoClass *create_empty_bindings(int num_columns)
231 BindInfoClass *new_bindings;
232 int i;
234 new_bindings =
235 (BindInfoClass *) malloc(num_columns * sizeof(BindInfoClass));
236 if (!new_bindings)
237 return NULL;
239 for (i = 0; i < num_columns; i++)
241 new_bindings[i].buflen = 0;
242 new_bindings[i].buffer = NULL;
243 new_bindings[i].used = new_bindings[i].indicator = NULL;
246 return new_bindings;
250 int CountParameters(const StatementClass * self, Int2 * inputCount,
251 Int2 * ioCount, Int2 * outputCount)
253 IPDFields *ipdopts = SC_get_IPDF(self);
254 int i, num_params, valid_count;
256 if (inputCount)
257 *inputCount = 0;
258 if (ioCount)
259 *ioCount = 0;
260 if (outputCount)
261 *outputCount = 0;
262 if (!ipdopts)
263 return -1;
264 num_params = self->num_params;
265 if (ipdopts->allocated < num_params)
266 num_params = ipdopts->allocated;
267 for (i = 0, valid_count = 0; i < num_params; i++)
269 if (SQL_PARAM_OUTPUT == ipdopts->parameters[i].paramType)
271 if (outputCount)
273 (*outputCount)++;
274 valid_count++;
276 } else if (SQL_PARAM_INPUT_OUTPUT ==
277 ipdopts->parameters[i].paramType)
279 if (ioCount)
281 (*ioCount)++;
282 valid_count++;
284 } else if (inputCount)
286 (*inputCount)++;
287 valid_count++;
290 return valid_count;
294 * Free parameters and free the memory.
296 void APD_free_params(APDFields * apdopts, char option)
298 CSTR func = "APD_free_params";
299 mylog("%s: ENTER, self=%p\n", func, apdopts);
301 if (!apdopts->parameters)
302 return;
304 if (option == STMT_FREE_PARAMS_ALL)
306 free(apdopts->parameters);
307 apdopts->parameters = NULL;
308 apdopts->allocated = 0;
311 mylog("%s: EXIT\n", func);
315 * Free parameters and free the memory.
317 void IPD_free_params(IPDFields * ipdopts, char option)
319 CSTR func = "IPD_free_params";
321 mylog("%s: ENTER, self=%p\n", func, ipdopts);
323 if (!ipdopts->parameters)
324 return;
325 if (option == STMT_FREE_PARAMS_ALL)
327 free(ipdopts->parameters);
328 ipdopts->parameters = NULL;
329 ipdopts->allocated = 0;
332 mylog("%s: EXIT\n", func);
335 void extend_column_bindings(ARDFields * self, int num_columns)
337 CSTR func = "extend_column_bindings";
338 BindInfoClass *new_bindings;
339 int i;
341 mylog
342 ("%s: entering ... self=%p, bindings_allocated=%d, num_columns=%d\n",
343 func, self, self->allocated, num_columns);
346 * if we have too few, allocate room for more, and copy the old
347 * entries into the new structure
349 if (self->allocated < num_columns)
351 new_bindings = create_empty_bindings(num_columns);
352 if (!new_bindings)
354 mylog
355 ("%s: unable to create %d new bindings from %d old bindings\n",
356 func, num_columns, self->allocated);
358 if (self->bindings)
360 free(self->bindings);
361 self->bindings = NULL;
363 self->allocated = 0;
364 return;
367 if (self->bindings)
369 for (i = 0; i < self->allocated; i++)
370 new_bindings[i] = self->bindings[i];
372 free(self->bindings);
375 self->bindings = new_bindings;
376 self->allocated = num_columns;
380 * There is no reason to zero out extra bindings if there are more
381 * than needed. If an app has allocated extra bindings, let it worry
382 * about it by unbinding those columns.
385 /* SQLBindCol(1..) ... SQLBindCol(10...) # got 10 bindings */
386 /* SQLExecDirect(...) # returns 5 cols */
387 /* SQLExecDirect(...) # returns 10 cols (now OK) */
389 mylog("exit %s=%p\n", func, self->bindings);
392 void reset_a_column_binding(ARDFields * self, int icol)
394 BindInfoClass *bookmark;
396 mylog("self=%p, allocated=%d, icol=%d\n",
397 self, self->allocated, icol);
399 if (icol > self->allocated)
400 return;
402 /* use zero based col numbers from here out */
403 if (0 == icol)
405 if (bookmark = self->bookmark, bookmark != NULL)
407 bookmark->buffer = NULL;
408 bookmark->used = bookmark->indicator = NULL;
410 } else
412 icol--;
414 /* we have to unbind the column */
415 self->bindings[icol].buflen = 0;
416 self->bindings[icol].buffer = NULL;
417 self->bindings[icol].used =
418 self->bindings[icol].indicator = NULL;
419 self->bindings[icol].returntype = SQL_C_CHAR;
423 void ARD_unbind_cols(ARDFields * self, BOOL freeall)
425 Int2 lf;
427 inolog("ARD_unbind_cols freeall=%d allocated=%d bindings=%p",
428 freeall, self->allocated, self->bindings);
429 for (lf = 1; lf <= self->allocated; lf++)
430 reset_a_column_binding(self, lf);
431 if (freeall)
433 if (self->bindings)
434 free(self->bindings);
435 self->bindings = NULL;
436 self->allocated = 0;
439 void GDATA_unbind_cols(GetDataInfo * self, BOOL freeall)
441 Int2 lf;
443 inolog("GDATA_unbind_cols freeall=%d allocated=%d gdata=%p",
444 freeall, self->allocated, self->gdata);
445 if (self->fdata.ttlbuf)
447 free(self->fdata.ttlbuf);
448 self->fdata.ttlbuf = NULL;
450 self->fdata.ttlbuflen = self->fdata.ttlbufused = 0;
451 self->fdata.data_left = -1;
452 for (lf = 1; lf <= self->allocated; lf++)
453 reset_a_getdata_info(self, lf);
454 if (freeall)
456 if (self->gdata)
457 free(self->gdata);
458 self->gdata = NULL;
459 self->allocated = 0;
463 void GetDataInfoInitialize(GetDataInfo * gdata_info)
465 gdata_info->fdata.data_left = -1;
466 gdata_info->fdata.ttlbuf = NULL;
467 gdata_info->fdata.ttlbuflen = gdata_info->fdata.ttlbufused = 0;
468 gdata_info->allocated = 0;
469 gdata_info->gdata = NULL;
471 static GetDataClass *create_empty_gdata(int num_columns)
473 GetDataClass *new_gdata;
474 int i;
476 new_gdata =
477 (GetDataClass *) malloc(num_columns * sizeof(GetDataClass));
478 if (!new_gdata)
479 return NULL;
481 for (i = 0; i < num_columns; i++)
483 new_gdata[i].data_left = -1;
484 new_gdata[i].ttlbuf = NULL;
485 new_gdata[i].ttlbuflen = 0;
486 new_gdata[i].ttlbufused = 0;
489 return new_gdata;
492 void extend_getdata_info(GetDataInfo * self, int num_columns, BOOL shrink)
494 GetDataClass *new_gdata;
496 mylog("self=%p, allocated=%d, num_columns=%d\n",
497 self, self->allocated, num_columns);
500 * if we have too few, allocate room for more, and copy the old
501 * entries into the new structure
503 if (self->allocated < num_columns)
505 new_gdata = create_empty_gdata(num_columns);
506 if (!new_gdata)
508 mylog
509 ("unable to create %d new gdata from %d old gdata\n",
510 num_columns, self->allocated);
512 if (self->gdata)
514 free(self->gdata);
515 self->gdata = NULL;
517 self->allocated = 0;
518 return;
520 if (self->gdata)
522 size_t i;
524 for (i = 0; i < self->allocated; i++)
525 new_gdata[i] = self->gdata[i];
526 free(self->gdata);
528 self->gdata = new_gdata;
529 self->allocated = num_columns;
530 } else if (shrink && self->allocated > num_columns)
532 int i;
534 for (i = self->allocated; i > num_columns; i--)
535 reset_a_getdata_info(self, i);
536 self->allocated = num_columns;
537 if (0 == num_columns)
539 free(self->gdata);
540 self->gdata = NULL;
545 * There is no reason to zero out extra gdata if there are more
546 * than needed. If an app has allocated extra gdata, let it worry
547 * about it by unbinding those columns.
550 mylog("exit(%p)\n", self->gdata);
553 void reset_a_getdata_info(GetDataInfo * gdata_info, int icol)
555 if (icol < 1 || icol > gdata_info->allocated)
556 return;
557 icol--;
558 if (gdata_info->gdata[icol].ttlbuf)
560 free(gdata_info->gdata[icol].ttlbuf);
561 gdata_info->gdata[icol].ttlbuf = NULL;
563 gdata_info->gdata[icol].ttlbuflen =
564 gdata_info->gdata[icol].ttlbufused = 0;
565 gdata_info->gdata[icol].data_left = -1;