summaryrefslogtreecommitdiff
path: root/src/interfaces/odbc/bind.c
diff options
context:
space:
mode:
authorMarc G. Fournier <scrappy@hub.org>1998-04-13 15:02:05 +0000
committerMarc G. Fournier <scrappy@hub.org>1998-04-13 15:02:05 +0000
commit9e3382dfc5affce3b653534714343d5e546e1a3e (patch)
treee5627cb0e135d52c2e4af55a239795d18ba5e7f9 /src/interfaces/odbc/bind.c
parentd4d26f9c33791f7aefd667e3688d9a18400006e1 (diff)
Replace old PostODBC driver with new one...
This one is based on an older PostODBC driver, rewritten and maintained by InsightDist(?)
Diffstat (limited to 'src/interfaces/odbc/bind.c')
-rw-r--r--src/interfaces/odbc/bind.c340
1 files changed, 340 insertions, 0 deletions
diff --git a/src/interfaces/odbc/bind.c b/src/interfaces/odbc/bind.c
new file mode 100644
index 00000000000..c01f61ab7fd
--- /dev/null
+++ b/src/interfaces/odbc/bind.c
@@ -0,0 +1,340 @@
+
+/* Module: bind.c
+ *
+ * Description: This module contains routines related to binding
+ * columns and parameters.
+ *
+ * Classes: BindInfoClass, ParameterInfoClass
+ *
+ * API functions: SQLBindParameter, SQLBindCol, SQLDescribeParam, SQLNumParams,
+ * SQLParamOptions(NI)
+ *
+ * Comments: See "notice.txt" for copyright and license information.
+ *
+ */
+#include "bind.h"
+#include "environ.h"
+#include "statement.h"
+#include "qresult.h"
+#include "pgtypes.h"
+#include <stdlib.h>
+#include <malloc.h>
+#include <sql.h>
+#include <sqlext.h>
+
+// Bind parameters on a statement handle
+
+RETCODE SQL_API SQLBindParameter(
+ HSTMT hstmt,
+ UWORD ipar,
+ SWORD fParamType,
+ SWORD fCType,
+ SWORD fSqlType,
+ UDWORD cbColDef,
+ SWORD ibScale,
+ PTR rgbValue,
+ SDWORD cbValueMax,
+ SDWORD FAR *pcbValue)
+{
+StatementClass *stmt = (StatementClass *) hstmt;
+
+ if( ! stmt)
+ return SQL_INVALID_HANDLE;
+
+ if(stmt->parameters_allocated < ipar) {
+ ParameterInfoClass *old_parameters;
+ int i, old_parameters_allocated;
+
+ old_parameters = stmt->parameters;
+ old_parameters_allocated = stmt->parameters_allocated;
+
+ stmt->parameters = (ParameterInfoClass *) malloc(sizeof(ParameterInfoClass)*(ipar));
+ if ( ! stmt->parameters) {
+ stmt->errornumber = STMT_NO_MEMORY_ERROR;
+ stmt->errormsg = "Could not allocate memory for statement parameters";
+ return SQL_ERROR;
+ }
+
+ stmt->parameters_allocated = ipar;
+
+ // copy the old parameters over
+ for(i = 0; i < old_parameters_allocated; i++) {
+ // a structure copy should work
+ stmt->parameters[i] = old_parameters[i];
+ }
+
+ // get rid of the old parameters, if there were any
+ if(old_parameters)
+ free(old_parameters);
+
+ // zero out the newly allocated parameters (in case they skipped some,
+ // so we don't accidentally try to use them later)
+ for(; i < stmt->parameters_allocated; i++) {
+ stmt->parameters[i].buflen = 0;
+ stmt->parameters[i].buffer = 0;
+ stmt->parameters[i].used = 0;
+ stmt->parameters[i].paramType = 0;
+ stmt->parameters[i].CType = 0;
+ stmt->parameters[i].SQLType = 0;
+ stmt->parameters[i].precision = 0;
+ stmt->parameters[i].scale = 0;
+ stmt->parameters[i].data_at_exec = FALSE;
+ stmt->parameters[i].EXEC_used = NULL;
+ stmt->parameters[i].EXEC_buffer = NULL;
+ }
+ }
+
+ ipar--; /* use zero based column numbers for the below part */
+
+ // store the given info
+ stmt->parameters[ipar].buflen = cbValueMax;
+ stmt->parameters[ipar].buffer = rgbValue;
+ stmt->parameters[ipar].used = pcbValue;
+ stmt->parameters[ipar].paramType = fParamType;
+ stmt->parameters[ipar].CType = fCType;
+ stmt->parameters[ipar].SQLType = fSqlType;
+ stmt->parameters[ipar].precision = cbColDef;
+ stmt->parameters[ipar].scale = ibScale;
+
+ /* If rebinding a parameter that had data-at-exec stuff in it,
+ then free that stuff
+ */
+ if (stmt->parameters[ipar].EXEC_used) {
+ free(stmt->parameters[ipar].EXEC_used);
+ stmt->parameters[ipar].EXEC_used = NULL;
+ }
+
+ if (stmt->parameters[ipar].EXEC_buffer) {
+ free(stmt->parameters[ipar].EXEC_buffer);
+ stmt->parameters[ipar].EXEC_buffer = NULL;
+ }
+
+ if (pcbValue && *pcbValue <= SQL_LEN_DATA_AT_EXEC_OFFSET)
+ stmt->parameters[ipar].data_at_exec = TRUE;
+ else
+ stmt->parameters[ipar].data_at_exec = FALSE;
+
+
+ return SQL_SUCCESS;
+}
+
+// - - - - - - - - -
+
+// Associate a user-supplied buffer with a database column.
+RETCODE SQL_API SQLBindCol(
+ HSTMT hstmt,
+ UWORD icol,
+ SWORD fCType,
+ PTR rgbValue,
+ SDWORD cbValueMax,
+ SDWORD FAR *pcbValue)
+{
+StatementClass *stmt = (StatementClass *) hstmt;
+Int2 numcols;
+
+mylog("**** SQLBindCol: stmt = %u, icol = %d\n", stmt, icol);
+
+ if ( ! stmt)
+ return SQL_INVALID_HANDLE;
+
+ if (icol < 1) {
+ /* currently we do not support bookmarks */
+ stmt->errormsg = "Bookmarks are not currently supported.";
+ stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR;
+ return SQL_ERROR;
+ }
+
+ icol--; /* use zero based col numbers */
+
+ SC_clear_error(stmt);
+
+ if( ! stmt->result) {
+ stmt->errormsg = "Can't bind columns with a NULL query result structure.";
+ stmt->errornumber = STMT_SEQUENCE_ERROR;
+ return SQL_ERROR;
+ }
+
+ if( stmt->status == STMT_EXECUTING) {
+ stmt->errormsg = "Can't bind columns while statement is still executing.";
+ stmt->errornumber = STMT_SEQUENCE_ERROR;
+ return SQL_ERROR;
+ }
+
+ numcols = QR_NumResultCols(stmt->result);
+
+ mylog("SQLBindCol: numcols = %d\n", numcols);
+
+ if (icol >= numcols) {
+ stmt->errornumber = STMT_COLNUM_ERROR;
+ stmt->errormsg = "Column number too big";
+ return SQL_ERROR;
+ }
+
+ if ( ! stmt->bindings) {
+ stmt->errormsg = "Bindings were not allocated properly.";
+ stmt->errornumber = STMT_SEQUENCE_ERROR;
+ return SQL_ERROR;
+ }
+
+ if ((cbValueMax == 0) || (rgbValue == NULL)) {
+ /* we have to unbind the column */
+ stmt->bindings[icol].buflen = 0;
+ stmt->bindings[icol].buffer = NULL;
+ stmt->bindings[icol].used = NULL;
+ stmt->bindings[icol].returntype = SQL_C_CHAR;
+ } else {
+ /* ok, bind that column */
+ stmt->bindings[icol].buflen = cbValueMax;
+ stmt->bindings[icol].buffer = rgbValue;
+ stmt->bindings[icol].used = pcbValue;
+ stmt->bindings[icol].returntype = fCType;
+ }
+
+ return SQL_SUCCESS;
+}
+
+// - - - - - - - - -
+
+// Returns the description of a parameter marker.
+
+RETCODE SQL_API SQLDescribeParam(
+ HSTMT hstmt,
+ UWORD ipar,
+ SWORD FAR *pfSqlType,
+ UDWORD FAR *pcbColDef,
+ SWORD FAR *pibScale,
+ SWORD FAR *pfNullable)
+{
+StatementClass *stmt = (StatementClass *) hstmt;
+
+ if( ! stmt)
+ return SQL_INVALID_HANDLE;
+
+ if( (ipar < 1) || (ipar > stmt->parameters_allocated) ) {
+ stmt->errormsg = "Invalid parameter number for SQLDescribeParam.";
+ stmt->errornumber = STMT_BAD_PARAMETER_NUMBER_ERROR;
+ return SQL_ERROR;
+ }
+
+ ipar--;
+
+ if(pfSqlType)
+ *pfSqlType = stmt->parameters[ipar].SQLType;
+
+ if(pcbColDef)
+ *pcbColDef = stmt->parameters[ipar].precision;
+
+ if(pibScale)
+ *pibScale = stmt->parameters[ipar].scale;
+
+ if(pfNullable)
+ *pfNullable = pgtype_nullable(stmt->parameters[ipar].paramType);
+
+ return SQL_SUCCESS;
+}
+
+// - - - - - - - - -
+
+// Sets multiple values (arrays) for the set of parameter markers.
+
+RETCODE SQL_API SQLParamOptions(
+ HSTMT hstmt,
+ UDWORD crow,
+ UDWORD FAR *pirow)
+{
+ return SQL_ERROR;
+}
+
+// - - - - - - - - -
+
+// Returns the number of parameter markers.
+
+RETCODE SQL_API SQLNumParams(
+ HSTMT hstmt,
+ SWORD FAR *pcpar)
+{
+StatementClass *stmt = (StatementClass *) hstmt;
+unsigned int i;
+
+ // I guess this is the number of actual parameter markers
+ // in the statement, not the number of parameters that are bound.
+ // why does this have to be driver-specific?
+
+ if(!stmt)
+ return SQL_INVALID_HANDLE;
+
+ if(!stmt->statement) {
+ // no statement has been allocated
+ *pcpar = 0;
+ stmt->errormsg = "SQLNumParams called with no statement ready.";
+ stmt->errornumber = STMT_SEQUENCE_ERROR;
+ return SQL_ERROR;
+ } else {
+ *pcpar = 0;
+ for(i=0; i < strlen(stmt->statement); i++) {
+ if(stmt->statement[i] == '?')
+ (*pcpar)++;
+ }
+
+ return SQL_SUCCESS;
+ }
+}
+
+/********************************************************************
+ * Bindings Implementation
+ */
+BindInfoClass *
+create_empty_bindings(int num_columns)
+{
+BindInfoClass *new_bindings;
+int i;
+
+ new_bindings = (BindInfoClass *)malloc(num_columns * sizeof(BindInfoClass));
+ if(!new_bindings) {
+ return 0;
+ }
+
+ for(i=0; i < num_columns; i++) {
+ new_bindings[i].buflen = 0;
+ new_bindings[i].buffer = NULL;
+ new_bindings[i].used = NULL;
+ }
+
+ return new_bindings;
+}
+
+void
+extend_bindings(StatementClass *stmt, int num_columns)
+{
+BindInfoClass *new_bindings;
+int i;
+
+ mylog("in extend_bindings\n");
+
+ /* if we have too few, allocate room for more, and copy the old */
+ /* entries into the new structure */
+ if(stmt->bindings_allocated < num_columns) {
+
+ new_bindings = create_empty_bindings(num_columns);
+
+ if(stmt->bindings) {
+ for(i=0; i<stmt->bindings_allocated; i++)
+ new_bindings[i] = stmt->bindings[i];
+
+ free(stmt->bindings);
+ }
+
+ stmt->bindings = new_bindings; // null indicates error
+
+ } else {
+ /* if we have too many, make sure the extra ones are emptied out */
+ /* so we don't accidentally try to use them for anything */
+ for(i = num_columns; i < stmt->bindings_allocated; i++) {
+ stmt->bindings[i].buflen = 0;
+ stmt->bindings[i].buffer = NULL;
+ stmt->bindings[i].used = NULL;
+ }
+ }
+
+ mylog("exit extend_bindings\n");
+}