4 * Description: This module contains routines related to binding
5 * columns and parameters.
7 * Classes: BindInfoClass, ParameterInfoClass
9 * API functions: SQLBindParameter, SQLBindCol, SQLDescribeParam, SQLNumParams,
12 * Comments: See "notice.txt" for copyright and license information.
19 #include "statement.h"
33 #include "pgapifunc.h"
36 /* Bind parameters on a statement handle */
50 StatementClass *stmt = (StatementClass *) hstmt;
51 static char *func = "PGAPI_BindParameter";
53 mylog("%s: entering...\n", func);
57 SC_log_error(func, "", NULL);
58 return SQL_INVALID_HANDLE;
62 if (stmt->parameters_allocated < ipar)
64 ParameterInfoClass *old_parameters;
66 old_parameters_allocated;
68 old_parameters = stmt->parameters;
69 old_parameters_allocated = stmt->parameters_allocated;
71 stmt->parameters = (ParameterInfoClass *) malloc(sizeof(ParameterInfoClass) * (ipar));
72 if (!stmt->parameters)
74 stmt->errornumber = STMT_NO_MEMORY_ERROR;
75 stmt->errormsg = "Could not allocate memory for statement parameters";
76 SC_log_error(func, "", stmt);
80 stmt->parameters_allocated = ipar;
82 /* copy the old parameters over */
83 for (i = 0; i < old_parameters_allocated; i++)
85 /* a structure copy should work */
86 stmt->parameters[i] = old_parameters[i];
89 /* get rid of the old parameters, if there were any */
94 * zero out the newly allocated parameters (in case they skipped
97 /* so we don't accidentally try to use them later) */
98 for (; i < stmt->parameters_allocated; i++)
100 stmt->parameters[i].buflen = 0;
101 stmt->parameters[i].buffer = 0;
102 stmt->parameters[i].used = 0;
103 stmt->parameters[i].paramType = 0;
104 stmt->parameters[i].CType = 0;
105 stmt->parameters[i].SQLType = 0;
106 stmt->parameters[i].precision = 0;
107 stmt->parameters[i].scale = 0;
108 stmt->parameters[i].data_at_exec = FALSE;
109 stmt->parameters[i].lobj_oid = 0;
110 stmt->parameters[i].EXEC_used = NULL;
111 stmt->parameters[i].EXEC_buffer = NULL;
115 /* use zero based column numbers for the below part */
118 /* store the given info */
119 stmt->parameters[ipar].buflen = cbValueMax;
120 stmt->parameters[ipar].buffer = rgbValue;
121 stmt->parameters[ipar].used = pcbValue;
122 stmt->parameters[ipar].paramType = fParamType;
123 stmt->parameters[ipar].CType = fCType;
124 stmt->parameters[ipar].SQLType = fSqlType;
125 stmt->parameters[ipar].precision = cbColDef;
126 stmt->parameters[ipar].scale = ibScale;
129 * If rebinding a parameter that had data-at-exec stuff in it, then
132 if (stmt->parameters[ipar].EXEC_used)
134 free(stmt->parameters[ipar].EXEC_used);
135 stmt->parameters[ipar].EXEC_used = NULL;
138 if (stmt->parameters[ipar].EXEC_buffer)
140 if (stmt->parameters[ipar].SQLType != SQL_LONGVARBINARY)
141 free(stmt->parameters[ipar].EXEC_buffer);
142 stmt->parameters[ipar].EXEC_buffer = NULL;
145 /* Data at exec macro only valid for C char/binary data */
146 if (pcbValue && (*pcbValue == SQL_DATA_AT_EXEC ||
147 *pcbValue <= SQL_LEN_DATA_AT_EXEC_OFFSET))
148 stmt->parameters[ipar].data_at_exec = TRUE;
150 stmt->parameters[ipar].data_at_exec = FALSE;
152 /* Clear premature result */
153 if (stmt->status == STMT_PREMATURE)
154 SC_recycle_statement(stmt);
156 mylog("PGAPI_BindParamater: ipar=%d, paramType=%d, fCType=%d, fSqlType=%d, cbColDef=%d, ibScale=%d, rgbValue=%d, *pcbValue = %d, data_at_exec = %d\n", ipar, fParamType, fCType, fSqlType, cbColDef, ibScale, rgbValue, pcbValue ? *pcbValue : -777, stmt->parameters[ipar].data_at_exec);
162 /* Associate a user-supplied buffer with a database column. */
170 SDWORD FAR *pcbValue)
172 StatementClass *stmt = (StatementClass *) hstmt;
173 static char *func = "PGAPI_BindCol";
175 mylog("%s: entering...\n", func);
177 mylog("**** PGAPI_BindCol: stmt = %u, icol = %d\n", stmt, icol);
178 mylog("**** : fCType=%d rgb=%x valusMax=%d pcb=%x\n", fCType, rgbValue, cbValueMax, pcbValue);
182 SC_log_error(func, "", NULL);
183 return SQL_INVALID_HANDLE;
187 SC_clear_error(stmt);
189 if (stmt->status == STMT_EXECUTING)
191 stmt->errormsg = "Can't bind columns while statement is still executing.";
192 stmt->errornumber = STMT_SEQUENCE_ERROR;
193 SC_log_error(func, "", stmt);
197 /* If the bookmark column is being bound, then just save it */
200 if (rgbValue == NULL)
202 stmt->bookmark.buffer = NULL;
203 stmt->bookmark.used = NULL;
207 /* Make sure it is the bookmark data type */
208 if (fCType != SQL_C_BOOKMARK)
210 stmt->errormsg = "Column 0 is not of type SQL_C_BOOKMARK";
211 stmt->errornumber = STMT_PROGRAM_TYPE_OUT_OF_RANGE;
212 SC_log_error(func, "", stmt);
216 stmt->bookmark.buffer = rgbValue;
217 stmt->bookmark.used = pcbValue;
223 * Allocate enough bindings if not already done. Most likely,
224 * execution of a statement would have setup the necessary bindings.
225 * But some apps call BindCol before any statement is executed.
227 if (icol > stmt->bindings_allocated)
228 extend_bindings(stmt, icol);
230 /* check to see if the bindings were allocated */
233 stmt->errormsg = "Could not allocate memory for bindings.";
234 stmt->errornumber = STMT_NO_MEMORY_ERROR;
235 SC_log_error(func, "", stmt);
239 /* use zero based col numbers from here out */
242 /* Reset for SQLGetData */
243 stmt->bindings[icol].data_left = -1;
245 if (rgbValue == NULL)
247 /* we have to unbind the column */
248 stmt->bindings[icol].buflen = 0;
249 stmt->bindings[icol].buffer = NULL;
250 stmt->bindings[icol].used = NULL;
251 stmt->bindings[icol].returntype = SQL_C_CHAR;
255 /* ok, bind that column */
256 stmt->bindings[icol].buflen = cbValueMax;
257 stmt->bindings[icol].buffer = rgbValue;
258 stmt->bindings[icol].used = pcbValue;
259 stmt->bindings[icol].returntype = fCType;
261 mylog(" bound buffer[%d] = %u\n", icol, stmt->bindings[icol].buffer);
269 * Returns the description of a parameter marker.
270 * This function is listed as not being supported by SQLGetFunctions() because it is
271 * used to describe "parameter markers" (not bound parameters), in which case,
272 * the dbms should return info on the markers. Since Postgres doesn't support that,
273 * it is best to say this function is not supported and let the application assume a
274 * data type (most likely varchar).
280 SWORD FAR *pfSqlType,
281 UDWORD FAR *pcbColDef,
283 SWORD FAR *pfNullable)
285 StatementClass *stmt = (StatementClass *) hstmt;
286 static char *func = "PGAPI_DescribeParam";
288 mylog("%s: entering...\n", func);
292 SC_log_error(func, "", NULL);
293 return SQL_INVALID_HANDLE;
295 SC_clear_error(stmt);
297 if ((ipar < 1) || (ipar > stmt->parameters_allocated))
299 stmt->errormsg = "Invalid parameter number for PGAPI_DescribeParam.";
300 stmt->errornumber = STMT_BAD_PARAMETER_NUMBER_ERROR;
301 SC_log_error(func, "", stmt);
308 * This implementation is not very good, since it is supposed to
311 /* parameter markers, not bound parameters. */
313 *pfSqlType = stmt->parameters[ipar].SQLType;
316 *pcbColDef = stmt->parameters[ipar].precision;
319 *pibScale = stmt->parameters[ipar].scale;
322 *pfNullable = pgtype_nullable(stmt, stmt->parameters[ipar].paramType);
328 /* Sets multiple values (arrays) for the set of parameter markers. */
335 static char *func = "PGAPI_ParamOptions";
336 StatementClass *stmt = (StatementClass *) hstmt;
338 mylog("%s: entering... %d %x\n", func, crow, pirow);
340 if (crow == 1) /* temporary solution and must be rewritten later */
346 stmt->errornumber = CONN_UNSUPPORTED_OPTION;
347 stmt->errormsg = "Function not implemented";
348 SC_log_error(func, "Function not implemented", (StatementClass *) hstmt);
354 * This function should really talk to the dbms to determine the number of
355 * "parameter markers" (not bound parameters) in the statement. But, since
356 * Postgres doesn't support that, the driver should just count the number of markers
357 * and return that. The reason the driver just can't say this function is unsupported
358 * like it does for SQLDescribeParam is that some applications don't care and try
360 * If the statement does not have parameters, it should just return 0.
367 StatementClass *stmt = (StatementClass *) hstmt;
368 char in_quote = FALSE;
370 static char *func = "PGAPI_NumParams";
372 mylog("%s: entering...\n", func);
376 SC_log_error(func, "", NULL);
377 return SQL_INVALID_HANDLE;
379 SC_clear_error(stmt);
385 SC_log_error(func, "pcpar was null", stmt);
390 if (!stmt->statement)
392 /* no statement has been allocated */
393 stmt->errormsg = "PGAPI_NumParams called with no statement ready.";
394 stmt->errornumber = STMT_SEQUENCE_ERROR;
395 SC_log_error(func, "", stmt);
400 for (i = 0; i < strlen(stmt->statement); i++)
402 if (stmt->statement[i] == '?' && !in_quote)
406 if (stmt->statement[i] == '\'')
407 in_quote = (in_quote ? FALSE : TRUE);
416 * Bindings Implementation
419 create_empty_bindings(int num_columns)
421 BindInfoClass *new_bindings;
424 new_bindings = (BindInfoClass *) malloc(num_columns * sizeof(BindInfoClass));
428 for (i = 0; i < num_columns; i++)
430 new_bindings[i].buflen = 0;
431 new_bindings[i].buffer = NULL;
432 new_bindings[i].used = NULL;
433 new_bindings[i].data_left = -1;
441 extend_bindings(StatementClass *stmt, int num_columns)
443 static char *func = "extend_bindings";
444 BindInfoClass *new_bindings;
447 mylog("%s: entering ... stmt=%u, bindings_allocated=%d, num_columns=%d\n", func, stmt, stmt->bindings_allocated, num_columns);
450 * if we have too few, allocate room for more, and copy the old
451 * entries into the new structure
453 if (stmt->bindings_allocated < num_columns)
455 new_bindings = create_empty_bindings(num_columns);
458 mylog("%s: unable to create %d new bindings from %d old bindings\n", func, num_columns, stmt->bindings_allocated);
462 free(stmt->bindings);
463 stmt->bindings = NULL;
465 stmt->bindings_allocated = 0;
471 for (i = 0; i < stmt->bindings_allocated; i++)
472 new_bindings[i] = stmt->bindings[i];
474 free(stmt->bindings);
477 stmt->bindings = new_bindings;
478 stmt->bindings_allocated = num_columns;
482 * There is no reason to zero out extra bindings if there are more
483 * than needed. If an app has allocated extra bindings, let it worry
484 * about it by unbinding those columns.
487 /* SQLBindCol(1..) ... SQLBindCol(10...) # got 10 bindings */
488 /* SQLExecDirect(...) # returns 5 cols */
489 /* SQLExecDirect(...) # returns 10 cols (now OK) */
491 mylog("exit extend_bindings\n");