1) Revise the handling of descriptors and implement SQLCopyDesc.
2) Handle data_at_execution columns for SQLSetPos or SQLBulkOperations.
    CSTR func = "PGAPI_BindParameter";
    APDFields   *apdopts;
    IPDFields   *ipdopts;
+   PutDataInfo *pdata_info;
 
    mylog("%s: entering...\n", func);
 
    }
    SC_clear_error(stmt);
 
-   apdopts = SC_get_APD(stmt);
+   apdopts = SC_get_APDF(stmt);
    if (apdopts->allocated < ipar)
        extend_parameter_bindings(apdopts, ipar);
-   ipdopts = SC_get_IPD(stmt);
+   ipdopts = SC_get_IPDF(stmt);
    if (ipdopts->allocated < ipar)
        extend_iparameter_bindings(ipdopts, ipar);
+   pdata_info = SC_get_PDTI(stmt);
+   if (pdata_info->allocated < ipar)
+       extend_putdata_info(pdata_info, ipar, FALSE);
 
    /* use zero based column numbers for the below part */
    ipar--;
    apdopts->parameters[ipar].buflen = cbValueMax;
    apdopts->parameters[ipar].buffer = rgbValue;
    apdopts->parameters[ipar].used = pcbValue;
-   apdopts->parameters[ipar].paramType = fParamType;
    apdopts->parameters[ipar].CType = fCType;
    ipdopts->parameters[ipar].SQLType = fSqlType;
    ipdopts->parameters[ipar].paramType = fParamType;
     * If rebinding a parameter that had data-at-exec stuff in it, then
     * free that stuff
     */
-   if (apdopts->parameters[ipar].EXEC_used)
+   if (pdata_info->pdata[ipar].EXEC_used)
    {
-       free(apdopts->parameters[ipar].EXEC_used);
-       apdopts->parameters[ipar].EXEC_used = NULL;
+       free(pdata_info->pdata[ipar].EXEC_used);
+       pdata_info->pdata[ipar].EXEC_used = NULL;
    }
 
-   if (apdopts->parameters[ipar].EXEC_buffer)
+   if (pdata_info->pdata[ipar].EXEC_buffer)
    {
-       free(apdopts->parameters[ipar].EXEC_buffer);
-       apdopts->parameters[ipar].EXEC_buffer = NULL;
+       free(pdata_info->pdata[ipar].EXEC_buffer);
+       pdata_info->pdata[ipar].EXEC_buffer = NULL;
    }
 
    if (pcbValue && apdopts->param_offset_ptr)
    StatementClass *stmt = (StatementClass *) hstmt;
    CSTR func = "PGAPI_BindCol";
    ARDFields   *opts;
+   GetDataInfo *gdata_info;
+   BindInfoClass   *bookmark;
 
    mylog("%s: entering...\n", func);
 
        return SQL_INVALID_HANDLE;
    }
 
-
-
-   opts = SC_get_ARD(stmt);
+   opts = SC_get_ARDF(stmt);
    if (stmt->status == STMT_EXECUTING)
    {
        SC_set_error(stmt, STMT_SEQUENCE_ERROR, "Can't bind columns while statement is still executing.");
    /* If the bookmark column is being bound, then just save it */
    if (icol == 0)
    {
+       bookmark = opts->bookmark;
        if (rgbValue == NULL)
        {
-           opts->bookmark->buffer = NULL;
-           opts->bookmark->used = NULL;
+           if (bookmark)
+           {
+               bookmark->buffer = NULL;
+               bookmark->used = NULL;
+           }
        }
        else
        {
                    return SQL_ERROR;
            }
 
-           opts->bookmark->buffer = rgbValue;
-           opts->bookmark->used = pcbValue;
-           opts->bookmark->buflen = cbValueMax;
-           opts->bookmark->returntype = fCType;
+           bookmark = ARD_AllocBookmark(opts);
+           bookmark->buffer = rgbValue;
+           bookmark->used = pcbValue;
+           bookmark->buflen = cbValueMax;
+           bookmark->returntype = fCType;
        }
        return SQL_SUCCESS;
    }
     */
    if (icol > opts->allocated)
        extend_column_bindings(opts, icol);
+   gdata_info = SC_get_GDTI(stmt);
+   if (icol > gdata_info->allocated)
+       extend_getdata_info(gdata_info, icol, FALSE);
 
    /* check to see if the bindings were allocated */
    if (!opts->bindings)
    icol--;
 
    /* Reset for SQLGetData */
-   opts->bindings[icol].data_left = -1;
+   gdata_info->gdata[icol].data_left = -1;
 
    if (rgbValue == NULL)
    {
        opts->bindings[icol].buffer = NULL;
        opts->bindings[icol].used = NULL;
        opts->bindings[icol].returntype = SQL_C_CHAR;
-       if (opts->bindings[icol].ttlbuf)
-           free(opts->bindings[icol].ttlbuf);
-       opts->bindings[icol].ttlbuf = NULL;
-       opts->bindings[icol].ttlbuflen = 0;
-       opts->bindings[icol].ttlbufused = 0;
        opts->bindings[icol].precision = 0;
        opts->bindings[icol].scale = 0;
+       if (gdata_info->gdata[icol].ttlbuf)
+           free(gdata_info->gdata[icol].ttlbuf);
+       gdata_info->gdata[icol].ttlbuf = NULL;
+       gdata_info->gdata[icol].ttlbuflen = 0;
+       gdata_info->gdata[icol].ttlbufused = 0;
    }
    else
    {
    }
    SC_clear_error(stmt);
 
-   apdopts = SC_get_APD(stmt);
+   apdopts = SC_get_APDF(stmt);
    if ((ipar < 1) || (ipar > apdopts->allocated))
    {
        SC_set_error(stmt, STMT_BAD_PARAMETER_NUMBER_ERROR, "Invalid parameter number for PGAPI_DescribeParam.");
        SC_log_error(func, "", stmt);
        return SQL_ERROR;
    }
-   ipdopts = SC_get_IPD(stmt);
+   ipdopts = SC_get_IPDF(stmt);
 
    ipar--;
 
        *pibScale = ipdopts->parameters[ipar].decimal_digits;
 
    if (pfNullable)
-       *pfNullable = pgtype_nullable(stmt, apdopts->parameters[ipar].paramType);
+       *pfNullable = pgtype_nullable(stmt, ipdopts->parameters[ipar].paramType);
 
    return SQL_SUCCESS;
 }
 
    mylog("%s: entering... %d %x\n", func, crow, pirow);
 
-   apdopts = SC_get_APD(stmt);
+   apdopts = SC_get_APDF(stmt);
    apdopts->paramset_size = crow;
-   SC_get_IPD(stmt)->param_processed_ptr = (UInt4 *) pirow;
+   SC_get_IPDF(stmt)->param_processed_ptr = (UInt4 *) pirow;
    return SQL_SUCCESS;
 }
 
 /*
  *  Bindings Implementation
  */
-BindInfoClass *
+static BindInfoClass *
 create_empty_bindings(int num_columns)
 {
    BindInfoClass *new_bindings;
        new_bindings[i].buflen = 0;
        new_bindings[i].buffer = NULL;
        new_bindings[i].used = NULL;
-       new_bindings[i].data_left = -1;
-       new_bindings[i].ttlbuf = NULL;
-       new_bindings[i].ttlbuflen = 0;
-       new_bindings[i].ttlbufused = 0;
    }
 
    return new_bindings;
    self->parameters[ipar].buflen = 0;
    self->parameters[ipar].buffer = 0;
    self->parameters[ipar].used = 0;
-   self->parameters[ipar].paramType = 0;
    self->parameters[ipar].CType = 0;
    self->parameters[ipar].data_at_exec = FALSE;
-   if (self->parameters[ipar].EXEC_used)
-   {
-       free(self->parameters[ipar].EXEC_used);
-       self->parameters[ipar].EXEC_used = NULL;
-   }
-
-   if (self->parameters[ipar].EXEC_buffer)
-   {
-       free(self->parameters[ipar].EXEC_buffer);
-       self->parameters[ipar].EXEC_buffer = NULL;
-   }
-   self->parameters[ipar].lobj_oid = 0;
    self->parameters[ipar].precision = 0;
    self->parameters[ipar].scale = 0;
 }
 void
 APD_free_params(APDFields *apdopts, char option)
 {
-   int         i;
-
    mylog("APD_free_params:  ENTER, self=%d\n", apdopts);
 
    if (!apdopts->parameters)
        return;
 
-   for (i = 0; i < apdopts->allocated; i++)
-   {
-       if (apdopts->parameters[i].data_at_exec)
-       {
-           if (apdopts->parameters[i].EXEC_used)
-           {
-               free(apdopts->parameters[i].EXEC_used);
-               apdopts->parameters[i].EXEC_used = NULL;
-           }
-           if (apdopts->parameters[i].EXEC_buffer)
-           {
-               free(apdopts->parameters[i].EXEC_buffer);
-               apdopts->parameters[i].EXEC_buffer = NULL;
-           }
-       }
-   }
-
    if (option == STMT_FREE_PARAMS_ALL)
    {
        if (apdopts->parameters)
    mylog("APD_free_params:  EXIT\n");
 }
 
+void
+PDATA_free_params(PutDataInfo *pdata, char option)
+{
+   int         i;
+
+   mylog("PDATA_free_params:  ENTER, self=%d\n", pdata);
+
+   if (!pdata->pdata)
+       return;
+
+   for (i = 0; i < pdata->allocated; i++)
+   {
+       if (pdata->pdata[i].EXEC_used)
+       {
+           free(pdata->pdata[i].EXEC_used);
+           pdata->pdata[i].EXEC_used = NULL;
+       }
+       if (pdata->pdata[i].EXEC_buffer)
+       {
+           free(pdata->pdata[i].EXEC_buffer);
+           pdata->pdata[i].EXEC_buffer = NULL;
+       }
+   }
+
+   if (option == STMT_FREE_PARAMS_ALL)
+   {
+       if (pdata->pdata)
+           free(pdata->pdata);
+       pdata->pdata = NULL;
+       pdata->allocated = 0;
+   }
+
+   mylog("PDATA_free_params:  EXIT\n");
+}
+
 /*
  * Free parameters and free the memory.
  */
 reset_a_column_binding(ARDFields *self, int icol)
 {
    CSTR func = "reset_a_column_binding";
+   BindInfoClass   *bookmark;
 
    mylog("%s: entering ... self=%u, bindings_allocated=%d, icol=%d\n", func, self, self->allocated, icol);
 
    /* use zero based col numbers from here out */
    if (0 == icol)
    {
-       self->bookmark->buffer = NULL;
-       self->bookmark->used = NULL;
+       if (bookmark = self->bookmark, bookmark != NULL)
+       {
+           bookmark->buffer = NULL;
+           bookmark->used = NULL;
+       }
    }
    else
    {
        self->bindings[icol].buflen = 0;
        self->bindings[icol].buffer = NULL;
        self->bindings[icol].used = NULL;
-       self->bindings[icol].data_left = -1;
        self->bindings[icol].returntype = SQL_C_CHAR;
-       if (self->bindings[icol].ttlbuf)
-           free(self->bindings[icol].ttlbuf);
-       self->bindings[icol].ttlbuf = NULL;
-       self->bindings[icol].ttlbuflen = 0;
-       self->bindings[icol].ttlbufused = 0;
    }
 }
 
 {
    Int2    lf;
 
+inolog("ARD_unbind_cols freeall=%d allocated=%d bindings=%x", freeall, self->allocated, self->bindings);
    for (lf = 1; lf <= self->allocated; lf++)
        reset_a_column_binding(self, lf);
    if (freeall)
        self->bindings = NULL;
        self->allocated = 0;
    }
-} 
+}
+void   GDATA_unbind_cols(GetDataInfo *self, BOOL freeall)
+{
+   Int2    lf;
+
+inolog("GDATA_unbind_cols freeall=%d allocated=%d gdata=%x", freeall, self->allocated, self->gdata);
+   for (lf = 1; lf <= self->allocated; lf++)
+       reset_a_getdata_info(self, lf);
+   if (freeall)
+   {
+       if (self->gdata)
+           free(self->gdata);
+       self->gdata = NULL;
+       self->allocated = 0;
+   }
+}
+
+void GetDataInfoInitialize(GetDataInfo *gdata_info)
+{
+   gdata_info->allocated = 0;
+   gdata_info->gdata = NULL;
+}
+static GetDataClass *
+create_empty_gdata(int num_columns)
+{
+   GetDataClass    *new_gdata;
+   int         i;
+
+   new_gdata = (GetDataClass *) malloc(num_columns * sizeof(GetDataClass));
+   if (!new_gdata)
+       return NULL;
+
+   for (i = 0; i < num_columns; i++)
+   {
+       new_gdata[i].data_left = -1;
+       new_gdata[i].ttlbuf = NULL;
+       new_gdata[i].ttlbuflen = 0;
+       new_gdata[i].ttlbufused = 0;
+   }
+
+   return new_gdata;
+}
+void
+extend_getdata_info(GetDataInfo *self, int num_columns, BOOL shrink)
+{
+   CSTR func = "extend_getdata_info";
+   GetDataClass    *new_gdata;
+   int         i;
+
+   mylog("%s: entering ... self=%u, gdata_allocated=%d, num_columns=%d\n", func, self, self->allocated, num_columns);
+
+   /*
+    * if we have too few, allocate room for more, and copy the old
+    * entries into the new structure
+    */
+   if (self->allocated < num_columns)
+   {
+       new_gdata = create_empty_gdata(num_columns);
+       if (!new_gdata)
+       {
+           mylog("%s: unable to create %d new gdata from %d old gdata\n", func, num_columns, self->allocated);
+
+           if (self->gdata)
+           {
+               free(self->gdata);
+               self->gdata = NULL;
+           }
+           self->allocated = 0;
+           return;
+       }
+       if (self->gdata)
+       {
+           for (i = 0; i < self->allocated; i++)
+               new_gdata[i] = self->gdata[i];
+           free(self->gdata);
+       }
+       self->gdata = new_gdata;
+       self->allocated = num_columns;
+   }
+   else if (shrink && self->allocated > num_columns)
+   {
+       for (i = self->allocated; i > num_columns; i--)
+           reset_a_getdata_info(self, i);
+       self->allocated = num_columns;
+       if (0 == num_columns)
+       {
+           free(self->gdata);
+           self->gdata = NULL;
+       }
+   } 
+
+   /*
+    * There is no reason to zero out extra gdata if there are more
+    * than needed.  If an app has allocated extra gdata, let it worry
+    * about it by unbinding those columns.
+    */
+
+   mylog("exit extend_gdata_info\n");
+}
+void   reset_a_getdata_info(GetDataInfo *gdata_info, int icol)
+{
+   if (icol < 1 || icol > gdata_info->allocated)
+       return;
+   icol--;
+   if (gdata_info->gdata[icol].ttlbuf)
+   {
+       free(gdata_info->gdata[icol].ttlbuf);
+       gdata_info->gdata[icol].ttlbuf = NULL;
+   }
+   gdata_info->gdata[icol].ttlbuflen =
+   gdata_info->gdata[icol].ttlbufused = 0;
+   gdata_info->gdata[icol].data_left = -1;
+}
+
+void PutDataInfoInitialize(PutDataInfo *pdata_info)
+{
+   pdata_info->allocated = 0;
+   pdata_info->pdata = NULL;
+}
+void
+extend_putdata_info(PutDataInfo *self, int num_params, BOOL shrink)
+{
+   CSTR func = "extend_putdata_info";
+   PutDataClass    *new_pdata;
+
+   mylog("%s: entering ... self=%u, parameters_allocated=%d, num_params=%d\n", func, self, self->allocated, num_params);
+
+   /*
+    * if we have too few, allocate room for more, and copy the old
+    * entries into the new structure
+    */
+   if (self->allocated < num_params)
+   {
+       new_pdata = (PutDataClass *) realloc(self->pdata, sizeof(PutDataClass) * num_params);
+       if (!new_pdata)
+       {
+           mylog("%s: unable to create %d new pdata from %d old pdata\n", func, num_params, self->allocated);
+
+           self->pdata = NULL;
+           self->allocated = 0;
+           return;
+       }
+       memset(&new_pdata[self->allocated], 0,
+           sizeof(PutDataClass) * (num_params - self->allocated));
+
+       self->pdata = new_pdata;
+       self->allocated = num_params;
+   }
+   else if (shrink && self->allocated > num_params)
+   {
+       int i;
+
+       for (i = self->allocated; i > num_params; i--)
+           reset_a_putdata_info(self, i);
+       self->allocated = num_params;
+       if (0 == num_params)
+       {
+           free(self->pdata);
+           self->pdata = NULL;
+       }
+   }
+
+   mylog("exit extend_putdata_info\n");
+}
+void   reset_a_putdata_info(PutDataInfo *pdata_info, int ipar)
+{
+   if (ipar < 1 || ipar > pdata_info->allocated)
+       return;
+   ipar--;
+   if (pdata_info->pdata[ipar].EXEC_used)
+   {
+       free(pdata_info->pdata[ipar].EXEC_used);
+       pdata_info->pdata[ipar].EXEC_used = NULL;
+   }
+   if (pdata_info->pdata[ipar].EXEC_buffer)
+   {
+       free(pdata_info->pdata[ipar].EXEC_buffer);
+       pdata_info->pdata[ipar].EXEC_buffer = NULL;
+   }
+   pdata_info->pdata[ipar].lobj_oid = 0;
+}
 
  */
 struct BindInfoClass_
 {
-   Int4        buflen;         /* size of buffer */
-   Int4        data_left;      /* amount of data left to read
-                                * (SQLGetData) */
-   char       *buffer;         /* pointer to the buffer */
-   Int4       *used;           /* used space in the buffer (for strings
-                                * not counting the '\0') */
-   char       *ttlbuf;         /* to save the large result */
-   Int4        ttlbuflen;      /* the buffer length */
-   Int4        ttlbufused;     /* used length of the buffer */
-   Int2        returntype;     /* kind of conversion to be applied when
-                                * returning (SQL_C_DEFAULT,
-                                * SQL_C_CHAR...) */
+   Int4    buflen;         /* size of buffer */
+   char    *buffer;        /* pointer to the buffer */
+   Int4    *used;          /* used space in the buffer (for strings
+                    * not counting the '\0') */
+   Int2    returntype;     /* kind of conversion to be applied when
+                    * returning (SQL_C_DEFAULT,
+                    * SQL_C_CHAR... etc) */
    Int2    precision;      /* the precision for numeric or timestamp type */
    Int2    scale;          /* the scale for numeric type */
+   /* area for work variables */
+   char    dummy_data;     /* currently not used */        
 };
+typedef struct
+{
+   char    *ttlbuf;        /* to save the large result */
+   Int4    ttlbuflen;      /* the buffer length */
+   Int4    ttlbufused;     /* used length of the buffer */
+   Int4    data_left;      /* amount of data left to read
+                    * (SQLGetData) */
+}  GetDataClass;
 
 /*
  * ParameterInfoClass -- stores information about a bound parameter
  */
 struct ParameterInfoClass_
 {
-   Int4        buflen;
-   char       *buffer;
-   Int4       *used;
-   Int2        paramType;
-   Int2        CType;
-   Oid         lobj_oid;
-   Int4       *EXEC_used;      /* amount of data */
-   char       *EXEC_buffer;    /* the data */
-   Int2        precision;  /* the precision for numeric or timestamp type */
-   Int2        scale;      /* the scale for numeric type */
-   char        data_at_exec;
+   Int4    buflen;
+   char    *buffer;
+   Int4    *used;
+   Int2    CType;
+   Int2    precision;  /* the precision for numeric or timestamp type */
+   Int2    scale;      /* the scale for numeric type */
+   /* area for work variables */
+   char    data_at_exec;
 };
 
+typedef struct 
+{
+   Int4    *EXEC_used; /* amount of data */
+   char    *EXEC_buffer;   /* the data */
+   Oid lobj_oid;
+}  PutDataClass;
+
 /*
  * ParameterImplClass -- stores implemntation information about a parameter
  */
    Int2        scale;      /* the scale for numeric type */
 };
 
-BindInfoClass *create_empty_bindings(int num_columns);
+typedef struct
+{
+   Int4        allocated;
+   GetDataClass    *gdata;
+}  GetDataInfo;
+typedef struct
+{
+   Int4        allocated;
+   PutDataClass    *pdata;
+}  PutDataInfo;
+
 void   extend_column_bindings(ARDFields *opts, int num_columns);
 void   reset_a_column_binding(ARDFields *opts, int icol);
-void   extend_parameter_bindings(APDFields *opts, int num_columns);
-void   extend_iparameter_bindings(IPDFields *opts, int num_columns);
+void   extend_parameter_bindings(APDFields *opts, int num_params);
+void   extend_iparameter_bindings(IPDFields *opts, int num_params);
 void   reset_a_parameter_binding(APDFields *opts, int ipar);
 void   reset_a_iparameter_binding(IPDFields *opts, int ipar);
+void   GetDataInfoInitialize(GetDataInfo *gdata);
+void   extend_getdata_info(GetDataInfo *gdata, int num_columns, BOOL shrink);
+void   reset_a_getdata_info(GetDataInfo *gdata, int icol);
+void   GDATA_unbind_cols(GetDataInfo *gdata, BOOL freeall);
+void   PutDataInfoInitialize(PutDataInfo *pdata);
+void   extend_putdata_info(PutDataInfo *pdata, int num_params, BOOL shrink);
+void   reset_a_putdata_info(PutDataInfo *pdata, int ipar);
+void   PDATA_free_params(PutDataInfo *pdata, char option);
 
 #endif
 
        memset(rv->stmts, 0, sizeof(StatementClass *) * STMT_INCREMENT);
 
        rv->num_stmts = STMT_INCREMENT;
+#if (ODBCVER >= 0x0300)
+       rv->descs = (DescriptorClass **) malloc(sizeof(DescriptorClass *) * STMT_INCREMENT);
+       if (!rv->descs)
+           return NULL;
+       memset(rv->descs, 0, sizeof(DescriptorClass *) * STMT_INCREMENT);
+
+       rv->num_descs = STMT_INCREMENT;
+#endif /* ODBCVER */
 
        rv->lobj_type = PG_TYPE_LO_UNDEFINED;
 
        free(self->stmts);
        self->stmts = NULL;
    }
+#if (ODBCVER >= 0x0300)
+   if (self->descs)
+   {
+       free(self->descs);
+       self->descs = NULL;
+   }
+#endif /* ODBCVER */
    mylog("after free statement holders\n");
 
    if (self->__error_message)
 {
    int         i;
    StatementClass *stmt;
+   DescriptorClass *desc;
 
    if (self->status == CONN_EXECUTING)
        return FALSE;
            self->stmts[i] = NULL;
        }
    }
+#if (ODBCVER >= 0x0300)
+   /* Free all the descs on this connection */
+   for (i = 0; i < self->num_descs; i++)
+   {
+       desc = self->descs[i];
+       if (desc)
+       {
+           DC_get_conn(desc) = NULL;   /* prevent any more dbase interactions */
+           DC_Destructor(desc);
+           free(desc);
+           self->descs[i] = NULL;
+       }
+   }
+#endif /* ODBCVER */
 
    /* Check for translation dll */
 #ifdef WIN32
  * (i.e., C3326857) for SQL select statements.  This cursor is then used in future
  * 'declare cursor C3326857 for ...' and 'fetch 100 in C3326857' statements.
  */
-
-
 QResultClass *
 CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, UDWORD flag)
 {
    stmt->internal = TRUE;      /* ensure no BEGIN/COMMIT/ABORT stuff */
 
    /* Set the Datestyle to the format the driver expects it to be in */
-   result = PGAPI_ExecDirect(hstmt, "set DateStyle to 'ISO'", SQL_NTS);
+   result = PGAPI_ExecDirect(hstmt, "set DateStyle to 'ISO'", SQL_NTS, 0);
    if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
        status = FALSE;
 
    /* Disable genetic optimizer based on global flag */
    if (ci->drivers.disable_optimizer)
    {
-       result = PGAPI_ExecDirect(hstmt, "set geqo to 'OFF'", SQL_NTS);
+       result = PGAPI_ExecDirect(hstmt, "set geqo to 'OFF'", SQL_NTS, 0);
        if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
            status = FALSE;
 
    /* KSQO (not applicable to 7.1+ - DJP 21/06/2002) */
    if (ci->drivers.ksqo && PG_VERSION_LT(self, 7.1))
    {
-       result = PGAPI_ExecDirect(hstmt, "set ksqo to 'ON'", SQL_NTS);
+       result = PGAPI_ExecDirect(hstmt, "set ksqo to 'ON'", SQL_NTS, 0);
        if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
            status = FALSE;
 
    /* extra_float_digits (applicable since 7.4) */
    if (PG_VERSION_GT(self, 7.3))
    {
-       result = PGAPI_ExecDirect(hstmt, "set extra_float_digits to 2", SQL_NTS);
+       result = PGAPI_ExecDirect(hstmt, "set extra_float_digits to 2", SQL_NTS, 0);
        if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
            status = FALSE;
 
 #endif /* HAVE_STRTOK_R */
        while (ptr)
        {
-           result = PGAPI_ExecDirect(hstmt, ptr, SQL_NTS);
+           result = PGAPI_ExecDirect(hstmt, ptr, SQL_NTS, 0);
            if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
                status = FALSE;
 
 #endif /* HAVE_STRTOK_R */
        while (ptr)
        {
-           result = PGAPI_ExecDirect(hstmt, ptr, SQL_NTS);
+           result = PGAPI_ExecDirect(hstmt, ptr, SQL_NTS, 0);
            if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
                status = FALSE;
 
        return;
    stmt = (StatementClass *) hstmt;
 
-   result = PGAPI_ExecDirect(hstmt, "select oid from pg_type where typname='" PG_TYPE_LO_NAME "'", SQL_NTS);
+   result = PGAPI_ExecDirect(hstmt, "select oid from pg_type where typname='" PG_TYPE_LO_NAME "'", SQL_NTS, 0);
    if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
    {
        PGAPI_FreeStmt(hstmt, SQL_DROP);
    stmt = (StatementClass *) hstmt;
 
    /* get the server's version if possible  */
-   result = PGAPI_ExecDirect(hstmt, "select version()", SQL_NTS);
+   result = PGAPI_ExecDirect(hstmt, "select version()", SQL_NTS, 0);
    if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
    {
        PGAPI_FreeStmt(hstmt, SQL_DROP);
 
    int     be_key; /* auth code needed to send cancel */
    UInt4       isolation;
    char        *current_schema;
+#if (ODBCVER >= 0x0300)
+   int     num_descs;
+   DescriptorClass **descs;
+#endif /* ODBCVER */
 #if defined(WIN_MULTITHREAD_SUPPORT)
    CRITICAL_SECTION    cs;
 #elif defined(POSIX_MULTITHREAD_SUPPORT)
 #define CC_get_DSN(x)                      (x->connInfo.dsn)
 #define CC_get_username(x)                 (x->connInfo.username)
 #define CC_is_onlyread(x)                  (x->connInfo.onlyread[0] == '1')
-
+ 
 /* for CC_DSN_info */
 #define CONN_DONT_OVERWRITE        0
 #define CONN_OVERWRITE         1
 int            CC_set_translation(ConnectionClass *self);
 char       CC_connect(ConnectionClass *self, char password_req, char *salt);
 char       CC_add_statement(ConnectionClass *self, StatementClass *stmt);
-char       CC_remove_statement(ConnectionClass *self, StatementClass *stmt);
+char       CC_remove_statement(ConnectionClass *self, StatementClass *stmt)
+;
+#if (ODBCVER >= 0x0300)
+char       CC_add_descriptor(ConnectionClass *self, DescriptorClass *desc);
+char       CC_remove_descriptor(ConnectionClass *self, DescriptorClass *desc);
+#endif /* ODBCVER */
 void       CC_set_error(ConnectionClass *self, int number, const char *message);
 void       CC_set_errormsg(ConnectionClass *self, const char *message);
 char       CC_get_error(ConnectionClass *self, int *number, char **message);
 void       CC_lookup_pg_version(ConnectionClass *conn);
 void       CC_initialize_pg_version(ConnectionClass *conn);
 void       CC_log_error(const char *func, const char *desc, const ConnectionClass *self);
-int            CC_get_max_query_len(const ConnectionClass *self);
+int        CC_get_max_query_len(const ConnectionClass *self);
 int        CC_send_cancel_request(const ConnectionClass *conn);
 void       CC_on_commit(ConnectionClass *conn);
 void       CC_on_abort(ConnectionClass *conn, UDWORD opt);
 
 int
 copy_and_convert_field_bindinfo(StatementClass *stmt, Int4 field_type, void *value, int col)
 {
-   ARDFields *opts = SC_get_ARD(stmt);
+   ARDFields *opts = SC_get_ARDF(stmt);
    BindInfoClass *bic = &(opts->bindings[col]);
    UInt4   offset = opts->row_offset_ptr ? *opts->row_offset_ptr : 0;
 
                       PTR rgbValue, SDWORD cbValueMax, SDWORD *pcbValue)
 {
    CSTR func = "copy_and_convert_field";
-   ARDFields   *opts = SC_get_ARD(stmt);
+   ARDFields   *opts = SC_get_ARDF(stmt);
+   GetDataInfo *gdata = SC_get_GDTI(stmt);
    Int4        len = 0,
                copy_len = 0;
    SIMPLE_TIME std_time;
    const char *neut_str = value;
    char        midtemp[2][32];
    int         mtemp_cnt = 0;
-   static BindInfoClass sbic;
-   BindInfoClass *pbic;
+   static GetDataClass sgdc;
+   GetDataClass *pgdc;
 #ifdef UNICODE_SUPPORT
    BOOL    wchanged =   FALSE;
 #endif /* UNICODE_SUPPORT */
 
    if (stmt->current_col >= 0)
    {
-       pbic = &opts->bindings[stmt->current_col];
-       if (pbic->data_left == -2)
-           pbic->data_left = (cbValueMax > 0) ? 0 : -1; /* This seems to be *
+       if (stmt->current_col >= opts->allocated)
+       {
+           return SQL_ERROR;
+       }
+       if (gdata->allocated != opts->allocated)
+           extend_getdata_info(gdata, opts->allocated, TRUE);
+       pgdc = &gdata->gdata[stmt->current_col];
+       if (pgdc->data_left == -2)
+           pgdc->data_left = (cbValueMax > 0) ? 0 : -1; /* This seems to be *
                         * needed by ADO ? */
-       if (pbic->data_left == 0)
+       if (pgdc->data_left == 0)
        {
-           if (pbic->ttlbuf != NULL)
+           if (pgdc->ttlbuf != NULL)
            {
-               free(pbic->ttlbuf);
-               pbic->ttlbuf = NULL;
-               pbic->ttlbuflen = 0;
+               free(pgdc->ttlbuf);
+               pgdc->ttlbuf = NULL;
+               pgdc->ttlbuflen = 0;
            }
-           pbic->data_left = -2;       /* needed by ADO ? */
+           pgdc->data_left = -2;       /* needed by ADO ? */
            return COPY_NO_DATA_FOUND;
        }
    }
            default:
                if (stmt->current_col < 0)
                {
-                   pbic = &sbic;
-                   pbic->data_left = -1;
+                   pgdc = &sgdc;
+                   pgdc->data_left = -1;
                }
                else
-                   pbic = &opts->bindings[stmt->current_col];
-               if (pbic->data_left < 0)
+                   pgdc = &gdata->gdata[stmt->current_col];
+               if (pgdc->data_left < 0)
                {
                    BOOL lf_conv = conn->connInfo.lf_conversion;
 #ifdef UNICODE_SUPPORT
 #endif /* WIN_UNICODE_SUPPORT */
                        break;
                    }
-                   if (!pbic->ttlbuf)
-                       pbic->ttlbuflen = 0;
+                   if (!pgdc->ttlbuf)
+                       pgdc->ttlbuflen = 0;
                    if (changed || len >= cbValueMax)
                    {
-                       if (len >= (int) pbic->ttlbuflen)
+                       if (len >= (int) pgdc->ttlbuflen)
                        {
-                           pbic->ttlbuf = realloc(pbic->ttlbuf, len + 1);
-                           pbic->ttlbuflen = len + 1;
+                           pgdc->ttlbuf = realloc(pgdc->ttlbuf, len + 1);
+                           pgdc->ttlbuflen = len + 1;
                        }
 #ifdef UNICODE_SUPPORT
                        if (fCType == SQL_C_WCHAR)
                        {
-                           utf8_to_ucs2_lf(neut_str, -1, lf_conv, (SQLWCHAR *) pbic->ttlbuf, len / 2);
+                           utf8_to_ucs2_lf(neut_str, -1, lf_conv, (SQLWCHAR *) pgdc->ttlbuf, len / 2);
                        }
                        else
 #endif /* UNICODE_SUPPORT */
                        if (PG_TYPE_BYTEA == field_type)
                        {
-                           len = convert_from_pgbinary(neut_str, pbic->ttlbuf, pbic->ttlbuflen);
-                           pg_bin2hex(pbic->ttlbuf, pbic->ttlbuf, len);
+                           len = convert_from_pgbinary(neut_str, pgdc->ttlbuf, pgdc->ttlbuflen);
+                           pg_bin2hex(pgdc->ttlbuf, pgdc->ttlbuf, len);
                            len *= 2; 
                        }
                        else
 #ifdef WIN_UNICODE_SUPPORT
                        if (fCType == SQL_C_CHAR)
                        {
-                           len = WideCharToMultiByte(CP_ACP, 0, allocbuf, wstrlen, pbic->ttlbuf, pbic->ttlbuflen, NULL, NULL);
+                           len = WideCharToMultiByte(CP_ACP, 0, allocbuf, wstrlen, pgdc->ttlbuf, pgdc->ttlbuflen, NULL, NULL);
                            free(allocbuf);
                            allocbuf = NULL;
                        }
                        else
 #endif /* WIN_UNICODE_SUPPORT */
-                           convert_linefeeds(neut_str, pbic->ttlbuf, pbic->ttlbuflen, lf_conv, &changed);
-                       ptr = pbic->ttlbuf;
-                       pbic->ttlbufused = len;
+                           convert_linefeeds(neut_str, pgdc->ttlbuf, pgdc->ttlbuflen, lf_conv, &changed);
+                       ptr = pgdc->ttlbuf;
+                       pgdc->ttlbufused = len;
                    }
                    else
                    {
-                       if (pbic->ttlbuf)
+                       if (pgdc->ttlbuf)
                        {
-                           free(pbic->ttlbuf);
-                           pbic->ttlbuf = NULL;
+                           free(pgdc->ttlbuf);
+                           pgdc->ttlbuf = NULL;
                        }
                        ptr = neut_str;
                    }
                }
                else
                {
-                   ptr = pbic->ttlbuf;
-                   len = pbic->ttlbufused;
+                   ptr = pgdc->ttlbuf;
+                   len = pgdc->ttlbufused;
                }
 
                mylog("DEFAULT: len = %d, ptr = '%s'\n", len, ptr);
 
                if (stmt->current_col >= 0)
                {
-                   if (pbic->data_left > 0)
+                   if (pgdc->data_left > 0)
                    {
-                       ptr += len - pbic->data_left;
-                       len = pbic->data_left;
+                       ptr += len - pgdc->data_left;
+                       len = pgdc->data_left;
                    }
                    else
-                       pbic->data_left = len;
+                       pgdc->data_left = len;
                }
 
                if (cbValueMax > 0)
 
                    /* Adjust data_left for next time */
                    if (stmt->current_col >= 0)
-                       pbic->data_left -= copy_len;
+                       pgdc->data_left -= copy_len;
                }
 
                /*
                    result = COPY_RESULT_TRUNCATED;
                else
                {
-                   if (pbic->ttlbuf != NULL)
+                   if (pgdc->ttlbuf != NULL)
                    {
-                       free(pbic->ttlbuf);
-                       pbic->ttlbuf = NULL;
+                       free(pgdc->ttlbuf);
+                       pgdc->ttlbuf = NULL;
                    }
                }
 
 
                if (stmt->current_col < 0)
                {
-                   pbic = &sbic;
-                   pbic->data_left = -1;
+                   pgdc = &sgdc;
+                   pgdc->data_left = -1;
                }
                else
-                   pbic = &opts->bindings[stmt->current_col];
-               if (!pbic->ttlbuf)
-                   pbic->ttlbuflen = 0;
-               if (pbic->data_left < 0)
+                   pgdc = &gdata->gdata[stmt->current_col];
+               if (!pgdc->ttlbuf)
+                   pgdc->ttlbuflen = 0;
+               if (pgdc->data_left < 0)
                {
                    if (cbValueMax <= 0)
                    {
                        result = COPY_RESULT_TRUNCATED;
                        break;
                    }
-                   if (len = strlen(neut_str), len >= (int) pbic->ttlbuflen)
+                   if (len = strlen(neut_str), len >= (int) pgdc->ttlbuflen)
                    {
-                       pbic->ttlbuf = realloc(pbic->ttlbuf, len + 1);
-                       pbic->ttlbuflen = len + 1;
+                       pgdc->ttlbuf = realloc(pgdc->ttlbuf, len + 1);
+                       pgdc->ttlbuflen = len + 1;
                    }
-                   len = convert_from_pgbinary(neut_str, pbic->ttlbuf, pbic->ttlbuflen);
-                   pbic->ttlbufused = len;
+                   len = convert_from_pgbinary(neut_str, pgdc->ttlbuf, pgdc->ttlbuflen);
+                   pgdc->ttlbufused = len;
                }
                else
-                   len = pbic->ttlbufused;
-               ptr = pbic->ttlbuf;
+                   len = pgdc->ttlbufused;
+               ptr = pgdc->ttlbuf;
 
                if (stmt->current_col >= 0)
                {
                     * Second (or more) call to SQLGetData so move the
                     * pointer
                     */
-                   if (pbic->data_left > 0)
+                   if (pgdc->data_left > 0)
                    {
-                       ptr += len - pbic->data_left;
-                       len = pbic->data_left;
+                       ptr += len - pgdc->data_left;
+                       len = pgdc->data_left;
                    }
 
                    /* First call to SQLGetData so initialize data_left */
                    else
-                       pbic->data_left = len;
+                       pgdc->data_left = len;
 
                }
 
 
                    /* Adjust data_left for next time */
                    if (stmt->current_col >= 0)
-                       pbic->data_left -= copy_len;
+                       pgdc->data_left -= copy_len;
                }
 
                /*
                 */
                if (len > cbValueMax)
                    result = COPY_RESULT_TRUNCATED;
-               else if (pbic->ttlbuf)
+               else if (pgdc->ttlbuf)
                {
-                   free(pbic->ttlbuf);
-                   pbic->ttlbuf = NULL;
+                   free(pgdc->ttlbuf);
+                   pgdc->ttlbuf = NULL;
                }
                mylog("SQL_C_BINARY: len = %d, copy_len = %d\n", len, copy_len);
                break;
        *((SDWORD *) pcbValueBindRow) = len;
 
    if (result == COPY_OK && stmt->current_col >= 0)
-       opts->bindings[stmt->current_col].data_left = 0;
+       gdata->gdata[stmt->current_col].data_left = 0;
    return result;
 
 }
    int param_number;
    APDFields *apdopts;
    IPDFields *ipdopts;
+   PutDataInfo *pdata;
    UInt4   load_stmt_len;
    UInt4   flags;
    BOOL    lf_conv;
    qb->stmt = stmt;
    qb->apdopts = NULL;
    qb->ipdopts = NULL;
+   qb->pdata = NULL;
    if (conn)
        qb->conn = conn;
    else if (stmt)
    {
-       qb->apdopts = SC_get_APD(stmt);
-       qb->ipdopts = SC_get_IPD(stmt);
+       qb->apdopts = SC_get_APDF(stmt);
+       qb->ipdopts = SC_get_IPDF(stmt);
+       qb->pdata = SC_get_PDTI(stmt);
        qb->conn = SC_get_conn(stmt);
        if (stmt->pre_executing)
            qb->flags |= FLGB_PRE_EXECUTING;
        chrform[newlen++] = '-';
    for (i = len - 1; i >= ns->scale; i--)
        chrform[newlen++] = calv[i] + '0';
-    if (!newlen)
-        chrform[newlen++] = '0';
-    if (ns->scale > 0)
+   if (ns->scale > 0)
    {
        chrform[newlen++] = '.';
        for (; i >= 0; i--)
    ConnInfo   *ci = &(conn->connInfo);
    const APDFields *apdopts = qb->apdopts;
    const IPDFields *ipdopts = qb->ipdopts;
+   PutDataInfo *pdata = qb->pdata;
 
    int     param_number;
    char        param_string[128], tmp[256],
            return SQL_ERROR;
        }
    }
-   if (SQL_PARAM_OUTPUT == apdopts->parameters[param_number].paramType)
+   if (SQL_PARAM_OUTPUT == ipdopts->parameters[param_number].paramType)
    {
        qb->errormsg = "Output parameter isn't available";
        qb->errornumber = STMT_NOT_IMPLEMENTED_ERROR;
    /* Assign correct buffers based on data at exec param or not */
    if (apdopts->parameters[param_number].data_at_exec)
    {
-       used = apdopts->parameters[param_number].EXEC_used ? *apdopts->parameters[param_number].EXEC_used : SQL_NTS;
-       buffer = apdopts->parameters[param_number].EXEC_buffer;
-       if (apdopts->parameters[param_number].lobj_oid)
+       if (pdata->allocated != apdopts->allocated)
+           extend_putdata_info(pdata, apdopts->allocated, TRUE);
+       used = pdata->pdata[param_number].EXEC_used ? *pdata->pdata[param_number].EXEC_used : SQL_NTS;
+       buffer = pdata->pdata[param_number].EXEC_buffer;
+       if (pdata->pdata[param_number].lobj_oid)
            handling_large_object = TRUE;
    }
    else
        case SQL_C_BINARY:
            buf = buffer;
            break;
-
        case SQL_C_CHAR:
 #ifdef WIN_UNICODE_SUPPORT
-           if (SQL_NTS == used)
-               used = strlen(buffer);
-           allocbuf = malloc(2 * (used + 1));
-           used = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, buffer,
-               used, (LPWSTR) allocbuf, used + 1);
-           buf = ucs2_to_utf8((SQLWCHAR *) allocbuf, used, &used, FALSE);
-           free(allocbuf);
-           allocbuf = buf;
+           switch (param_sqltype)
+           {
+               case SQL_WCHAR:
+               case SQL_WVARCHAR:
+               case SQL_WLONGVARCHAR:
+                   if (SQL_NTS == used)
+                       used = strlen(buffer);
+                   allocbuf = malloc(2 * (used + 1));
+                   used = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, buffer,
+                       used, (LPWSTR) allocbuf, used + 1);
+                   buf = ucs2_to_utf8((SQLWCHAR *) allocbuf, used, &used, FALSE);
+                   free(allocbuf);
+                   allocbuf = buf;
+                   break;
+               default:
+                   buf = buffer;
+           }
 #else
            buf = buffer;
 #endif /* WIN_UNICODE_SUPPORT */
            }
 
            if (apdopts->parameters[param_number].data_at_exec)
-               lobj_oid = apdopts->parameters[param_number].lobj_oid;
+               lobj_oid = pdata->pdata[param_number].lobj_oid;
            else
            {
                /* begin transaction if needed */
    int         retval,
                result,
                left = -1;
-   BindInfoClass *bindInfo = NULL;
+   GetDataClass *gdata = NULL;
    ConnectionClass *conn = SC_get_conn(stmt);
    ConnInfo   *ci = &(conn->connInfo);
-   ARDFields   *opts = SC_get_ARD(stmt);
+   GetDataInfo *gdata_info = SC_get_GDTI(stmt);
    int         factor;
 
    switch (fCType)
    /* If using SQLGetData, then current_col will be set */
    if (stmt->current_col >= 0)
    {
-       bindInfo = &opts->bindings[stmt->current_col];
-       left = bindInfo->data_left;
+       gdata = &gdata_info->gdata[stmt->current_col];
+       left = gdata->data_left;
    }
 
    /*
     * for reading
     */
 
-   if (!bindInfo || bindInfo->data_left == -1)
+   if (!gdata || gdata->data_left == -1)
    {
        /* begin transaction if needed */
        if (!CC_is_in_trans(conn))
        if (retval >= 0)
        {
            left = lo_tell(conn, stmt->lobj_fd);
-           if (bindInfo)
-               bindInfo->data_left = left;
+           if (gdata)
+               gdata->data_left = left;
 
            /* return to beginning */
            lo_lseek(conn, stmt->lobj_fd, 0L, SEEK_SET);
    if (pcbValue)
        *pcbValue = left < 0 ? SQL_NO_TOTAL : left * factor;
 
-   if (bindInfo && bindInfo->data_left > 0)
-       bindInfo->data_left -= retval;
+   if (gdata && gdata->data_left > 0)
+       gdata->data_left -= retval;
 
-   if (!bindInfo || bindInfo->data_left == 0)
+   if (!gdata || gdata->data_left == 0)
    {
        lo_close(conn, stmt->lobj_fd);
 
 
--- /dev/null
+/*-------
+ * Module:         descriptor.c
+ *
+ * Description:        This module contains functions related to creating
+ *                 and manipulating a statement.
+ *
+ * Classes:            DescriptorClass (Functions prefix: "DC_")
+ *
+ *
+ * Comments:       See "notice.txt" for copyright and license information.
+ *-------
+ */
+
+#include "environ.h"
+#include "connection.h"
+#include "descriptor.h"
+#include "statement.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "pgapifunc.h"
+
+
+void   DC_Constructor(DescriptorClass *self, BOOL embedded, StatementClass *stmt)
+{
+   memset(self, 0, sizeof(DescriptorClass));
+   self->embedded = embedded;
+}
+
+static void ARDFields_free(ARDFields * self)
+{
+inolog("ARDFields_free %x bookmark=%x", self, self->bookmark);
+   if (self->bookmark)
+   {
+       free(self->bookmark);
+       self->bookmark = NULL;
+   }
+   /*
+    * the memory pointed to by the bindings is not deallocated by the
+    * driver but by the application that uses that driver, so we don't
+    * have to care
+    */
+   ARD_unbind_cols(self, TRUE);
+}
+
+static void APDFields_free(APDFields * self)
+{
+   if (self->bookmark)
+   {
+       free(self->bookmark);
+       self->bookmark = NULL;
+   }
+   /* param bindings */
+   APD_free_params(self, STMT_FREE_PARAMS_ALL);
+}
+
+static void IRDFields_free(IRDFields * self)
+{
+   /* Free the parsed field information */
+   if (self->fi)
+   {
+       int         i;
+
+       for (i = 0; i < (int) self->nfields; i++)
+       {
+           if (self->fi[i])
+           {
+               if (self->fi[i]->schema)
+                   free(self->fi[i]->schema);
+               free(self->fi[i]);
+           }
+       }
+       free(self->fi);
+       self->fi = NULL;
+   }
+}
+
+static void IPDFields_free(IPDFields * self)
+{
+   /* param bindings */
+   IPD_free_params(self, STMT_FREE_PARAMS_ALL);
+}
+
+void   DC_Destructor(DescriptorClass *self)
+{
+   if (self->__error_message)
+   {
+       free(self->__error_message);
+       self->__error_message = NULL;
+   }
+   if (self->pgerror)
+   {
+       ER_Destructor(self->pgerror);
+       self->pgerror = NULL;
+   }
+   if (self->type_defined)
+   {
+       switch (self->desc_type)
+       {
+           case SQL_ATTR_APP_ROW_DESC:
+               ARDFields_free((ARDFields *) (self + 1));
+               break;
+           case SQL_ATTR_APP_PARAM_DESC:
+               APDFields_free((APDFields *) (self + 1));
+               break;
+           case SQL_ATTR_IMP_ROW_DESC:
+               IRDFields_free((IRDFields *) (self + 1));
+               break;
+           case SQL_ATTR_IMP_PARAM_DESC:
+               IPDFields_free((IPDFields *) (self + 1));
+               break;
+       }
+   }
+}
+
+void InitializeEmbeddedDescriptor(DescriptorClass *desc, StatementClass *stmt,
+        UInt4 desc_type) 
+{
+   DC_Constructor(desc, TRUE, stmt);
+   DC_get_conn(desc) = SC_get_conn(stmt);
+   desc->type_defined = TRUE;
+   desc->desc_type = desc_type;
+   switch (desc_type)
+   {
+       case SQL_ATTR_APP_ROW_DESC:
+           memset(desc + 1, 0, sizeof(ARDFields));
+           stmt->ard = (ARDClass *) desc;
+           break; 
+       case SQL_ATTR_APP_PARAM_DESC:
+           memset(desc + 1, 0, sizeof(APDFields));
+           stmt->apd = (APDClass *) desc;
+           break; 
+       case SQL_ATTR_IMP_ROW_DESC:
+           memset(desc + 1, 0, sizeof(IRDFields));
+           stmt->ird = (IRDClass *) desc;
+           stmt->ird->irdopts.stmt = stmt;
+           break; 
+       case SQL_ATTR_IMP_PARAM_DESC:
+           memset(desc + 1, 0, sizeof(IPDFields));
+           stmt->ipd = (IPDClass *) desc;
+           break; 
+   }
+}
+
+/*
+ * ARDFields initialize
+ */
+void
+InitializeARDFields(ARDFields *opt)
+{
+   memset(opt, 0, sizeof(ARDFields));
+#if (ODBCVER >= 0x0300)
+   opt->size_of_rowset = 1;
+#endif /* ODBCVER */
+   opt->bind_size = 0;     /* default is to bind by column */
+   opt->size_of_rowset_odbc2 = 1;
+}
+/*
+ * APDFields initialize
+ */
+void
+InitializeAPDFields(APDFields *opt)
+{
+   memset(opt, 0, sizeof(APDFields));
+   opt->paramset_size = 1;
+   opt->param_bind_type = 0;   /* default is to bind by column */
+   opt->paramset_size_dummy = 1;   /* dummy setting */
+}
+
+BindInfoClass  *ARD_AllocBookmark(ARDFields *ardopts)
+{
+   if (!ardopts->bookmark)
+   {
+       ardopts->bookmark = (BindInfoClass *) malloc(sizeof(BindInfoClass));
+       memset(ardopts->bookmark, 0, sizeof(BindInfoClass));
+   }
+   return ardopts->bookmark;
+}
+
+#if (ODBCVER >= 0x0300)
+
+#define    DESC_INCREMENT  10
+char CC_add_descriptor(ConnectionClass *self, DescriptorClass *desc)
+{
+   int i;
+
+   mylog("CC_add_descriptor: self=%u, desc=%u\n", self, desc);
+
+   for (i = 0; i < self->num_descs; i++)
+   {
+       if (!self->descs[i])
+       {
+           DC_get_conn(desc) = self;
+           self->descs[i] = desc;
+           return TRUE;
+       }
+   }
+        /* no more room -- allocate more memory */
+   self->descs = (DescriptorClass **) realloc(self->descs, sizeof(DescriptorClass *) * (DESC_INCREMENT + self->num_descs));
+   if (!self->descs)
+       return FALSE;
+
+   memset(&self->descs[self->num_descs], 0, sizeof(DescriptorClass *) *
+               DESC_INCREMENT);
+        DC_get_conn(desc) = self;
+   self->descs[self->num_descs] = desc;
+   self->num_descs += DESC_INCREMENT;
+
+   return TRUE;
+}
+
+/*
+ * This API allocates a Application descriptor.
+ */
+RETCODE SQL_API PGAPI_AllocDesc(HDBC ConnectionHandle,
+                   SQLHDESC *DescriptorHandle)
+{
+   CSTR func = "PGAPI_AllocDesc";
+   ConnectionClass *conn = (ConnectionClass *) ConnectionHandle;
+   RETCODE ret = SQL_SUCCESS;
+   DescriptorClass *desc = (DescriptorClass *) malloc(sizeof(DescriptorAlloc));
+
+   mylog("%s: entering...\n", func);
+   if (desc)
+   {
+       memset(desc, 0, sizeof(DescriptorAlloc));
+       DC_get_conn(desc) = conn;
+       if (CC_add_descriptor(conn, desc))
+           *DescriptorHandle = desc;
+       else
+       {
+           free(desc);
+           CC_set_error(conn, CONN_STMT_ALLOC_ERROR, "Maximum number of descriptors exceeded");
+           ret = SQL_ERROR;
+       } 
+   }
+   else
+   {
+       CC_set_error(conn, CONN_STMT_ALLOC_ERROR, "No more memory ti allocate a further descriptor");
+       ret = SQL_ERROR;
+   }
+   return ret;
+}
+
+RETCODE SQL_API PGAPI_FreeDesc(SQLHDESC DescriptorHandle)
+{
+   CSTR func = "PGAPI_FreeDesc";
+   DescriptorClass *desc = (DescriptorClass *) DescriptorHandle;
+   RETCODE ret = SQL_SUCCESS;
+
+   mylog("%s: entering...\n", func);
+   DC_Destructor(desc);
+   if (!desc->embedded)
+   {
+       int i;
+       ConnectionClass *conn = DC_get_conn(desc);
+
+       for (i = 0; i < conn->num_descs; i++)
+       {
+           if (conn->descs[i] == desc)
+           {
+               conn->descs[i] = NULL;
+               break;
+           }
+       }
+       free(desc);
+   }
+   return ret;
+}
+
+static void BindInfoClass_copy(const BindInfoClass *src, BindInfoClass *target)
+{
+   memcpy(target, src, sizeof(BindInfoClass));
+}
+static void ARDFields_copy(const ARDFields *src, ARDFields *target)
+{
+   memcpy(target, src, sizeof(ARDFields));
+   target->bookmark = NULL;
+   if (src->bookmark)
+   {
+       BindInfoClass *bookmark = ARD_AllocBookmark(target);
+       BindInfoClass_copy(src->bookmark, bookmark);
+   }
+   if (src->allocated <= 0)
+   {
+       target->allocated = 0;
+       target->bindings = NULL;
+   }
+   else
+   {
+       int i;
+
+       target->bindings = malloc(target->allocated * sizeof(BindInfoClass));
+       for (i = 0; i < target->allocated; i++)
+           BindInfoClass_copy(&src->bindings[i], &target->bindings[i]);
+   }
+}
+
+static void ParameterInfoClass_copy(const ParameterInfoClass *src, ParameterInfoClass *target)
+{
+   memcpy(target, src, sizeof(ParameterInfoClass));
+}
+static void APDFields_copy(const APDFields *src, APDFields *target)
+{
+   memcpy(target, src, sizeof(APDFields));
+   if (src->bookmark)
+   {
+       target->bookmark = malloc(sizeof(BindInfoClass));
+       ParameterInfoClass_copy(src->bookmark, target->bookmark);
+   }
+   if (src->allocated <= 0)
+   {
+       target->allocated = 0;
+       target->parameters = NULL;
+   }
+   else
+   {
+       int i;
+
+       target->parameters = malloc(target->allocated * sizeof(ParameterInfoClass));
+       for (i = 0; i < target->allocated; i++)
+           ParameterInfoClass_copy(&src->parameters[i], &target->parameters[i]);
+   }
+}
+
+static void ParameterImplClass_copy(const ParameterImplClass *src, ParameterImplClass *target)
+{
+   memcpy(target, src, sizeof(ParameterImplClass));
+}
+static void IPDFields_copy(const IPDFields *src, IPDFields *target)
+{
+   memcpy(target, src, sizeof(IPDFields));
+   if (src->allocated <= 0)
+   {
+       target->allocated = 0;
+       target->parameters = NULL;
+   }
+   else
+   {
+       int i;
+
+       target->parameters = (ParameterImplClass *) malloc(target->allocated * sizeof(ParameterInfoClass));
+       for (i = 0; i < target->allocated; i++)
+           ParameterImplClass_copy(&src->parameters[i], &target->parameters[i]);
+   }
+}
+
+RETCODE    SQL_API
+PGAPI_CopyDesc(SQLHDESC SourceDescHandle,
+           SQLHDESC TargetDescHandle)
+{
+   CSTR func = "PGAPI_CopyDesc";
+   RETCODE ret = SQL_ERROR;
+   DescriptorClass *src, *target;
+   ARDFields   *ard_src, *ard_tgt;
+   APDFields   *apd_src, *apd_tgt;
+   IPDFields   *ipd_src, *ipd_tgt;
+
+   mylog("%s: entering...\n", func);
+   src = (DescriptorClass *) SourceDescHandle;
+   target = (DescriptorClass *) TargetDescHandle;
+   if (!src->type_defined)
+   {
+       mylog("source type undefined\n");
+       DC_set_error(target, DESC_EXEC_ERROR, "source handle type undefined");
+       return ret;
+   }
+   if (target->type_defined)
+   {
+inolog("CopyDesc source type=%d -> target type=%d\n", src->desc_type, target->desc_type);
+       if (SQL_ATTR_IMP_ROW_DESC == target->desc_type)
+       {
+           mylog("can't modify IRD\n");
+           DC_set_error(target, DESC_EXEC_ERROR, "can't copy to IRD");
+           return ret;
+       }
+       else if (target->desc_type != src->desc_type)
+       {
+           mylog("src type != target type\n");
+           DC_set_error(target, DESC_EXEC_ERROR, "src descriptor != target type");
+           return ret;
+       }
+       DC_Destructor(target);
+   }
+   ret = SQL_SUCCESS;
+   switch (src->desc_type)
+   {
+       case SQL_ATTR_APP_ROW_DESC:
+inolog("src=%x target=%x type=%d", src, target, src->desc_type);
+           if (!target->type_defined)
+           {
+               target->desc_type = src->desc_type;
+           }
+           ard_src = (ARDFields *) (src + 1);
+inolog(" rowset_size=%d bind_size=%d ope_ptr=%x off_ptr=%x\n",
+ard_src->size_of_rowset, ard_src->bind_size,
+ard_src->row_operation_ptr, ard_src->row_offset_ptr);
+           ard_tgt = (ARDFields *) (target + 1);
+inolog(" target=%x", ard_tgt);
+           ARDFields_copy(ard_src, ard_tgt);
+inolog(" offset_ptr=%x\n", ard_tgt->row_offset_ptr);
+           break;
+       case SQL_ATTR_APP_PARAM_DESC:
+           if (!target->type_defined)
+           {
+               target->desc_type = src->desc_type;
+           }
+           apd_src = (APDFields *) (src + 1);
+           apd_tgt = (APDFields *) (target + 1);
+           APDFields_copy(apd_src, apd_tgt);
+           break;
+       case SQL_ATTR_IMP_PARAM_DESC:
+           if (!target->type_defined)
+           {
+               target->desc_type = src->desc_type;
+           }
+           ipd_src = (IPDFields *) (src + 1);
+           ipd_tgt = (IPDFields *) (target + 1);
+           IPDFields_copy(ipd_src, ipd_tgt);
+           break;
+       default:
+           mylog("invalid descriptor handle type=%d\n", src->desc_type);
+           DC_set_error(target, DESC_EXEC_ERROR, "invalid descriptor type");
+           ret = SQL_ERROR;
+   }
+
+   if (SQL_SUCCESS == ret)
+       target->type_defined = TRUE;
+        return ret;
+}
+
+void   DC_clear_error(DescriptorClass *self)
+{
+   if (self->__error_message)
+   {
+       free(self->__error_message);
+       self->__error_message = NULL;
+   }
+   if (self->pgerror)
+   {
+       ER_Destructor(self->pgerror);
+       self->pgerror = NULL;
+   }
+   self->__error_number = 0;
+   self->error_row = 0;
+   self->error_index = 0;
+}
+
+void    DC_set_error(DescriptorClass *desc, int errornumber, const char *errormsg)
+{
+   if (desc->__error_message)
+       free(desc->__error_message);
+   desc->__error_number = errornumber;
+   desc->__error_message = errormsg ? strdup(errormsg) : NULL;
+}
+void    DC_set_errormsg(DescriptorClass *desc, const char *errormsg)
+{
+   if (desc->__error_message)
+       free(desc->__error_message);
+   desc->__error_message = errormsg ? strdup(errormsg) : NULL;
+}
+const char *DC_get_errormsg(const DescriptorClass *desc)
+{
+        return desc->__error_message;
+}
+int    DC_get_errornumber(const DescriptorClass *desc)
+{
+        return desc->__error_number;
+}
+
+/* Map sql commands to statement types */
+static struct
+{
+   int number;
+   const   char    * ver3str;
+   const   char    * ver2str;
+}  Descriptor_sqlstate[] =
+
+{
+   { DESC_OK,  "00000", "00000" }, /* OK */
+   { DESC_EXEC_ERROR, "HY000", "S1000" }, /* also a general error */
+   { DESC_STATUS_ERROR, "HY010", "S1010" },
+   { DESC_SEQUENCE_ERROR, "HY010", "S1010" }, /* Function sequence error */
+   { DESC_NO_MEMORY_ERROR, "HY001", "S1001" }, /* memory allocation failure */
+   { DESC_COLNUM_ERROR, "07009", "S1002" }, /* invalid column number */
+   { DESC_NO_STMTSTRING, "HY001", "S1001" }, /* having no stmtstring is also a malloc problem */
+   { DESC_ERROR_TAKEN_FROM_BACKEND, "HY000", "S1000" }, /* general error */
+   { DESC_INTERNAL_ERROR, "HY000", "S1000" }, /* general error */
+   { DESC_STILL_EXECUTING, "HY010", "S1010" },
+   { DESC_NOT_IMPLEMENTED_ERROR, "HYC00", "S1C00" }, /* == 'driver not 
+                             * capable' */
+   { DESC_BAD_PARAMETER_NUMBER_ERROR, "07009", "S1093" },
+   { DESC_OPTION_OUT_OF_RANGE_ERROR, "HY092", "S1092" },
+   { DESC_INVALID_COLUMN_NUMBER_ERROR, "07009", "S1002" },
+   { DESC_RESTRICTED_DATA_TYPE_ERROR, "07006", "07006" },
+   { DESC_INVALID_CURSOR_STATE_ERROR, "07005", "24000" },
+   { DESC_OPTION_VALUE_CHANGED, "01S02", "01S02" },
+   { DESC_CREATE_TABLE_ERROR, "42S01", "S0001" }, /* table already exists */
+   { DESC_NO_CURSOR_NAME, "S1015", "S1015" },
+   { DESC_INVALID_CURSOR_NAME, "34000", "34000" },
+   { DESC_INVALID_ARGUMENT_NO, "HY024", "S1009" }, /* invalid argument value */
+   { DESC_ROW_OUT_OF_RANGE, "HY107", "S1107" },
+   { DESC_OPERATION_CANCELLED, "HY008", "S1008" },
+   { DESC_INVALID_CURSOR_POSITION, "HY109", "S1109" },
+   { DESC_VALUE_OUT_OF_RANGE, "HY019", "22003" },
+   { DESC_OPERATION_INVALID, "HY011", "S1011" },
+   { DESC_PROGRAM_TYPE_OUT_OF_RANGE, "?????", "?????" }, 
+   { DESC_BAD_ERROR, "08S01", "08S01" }, /* communication link failure */
+   { DESC_INVALID_OPTION_IDENTIFIER, "HY092", "HY092" },
+   { DESC_RETURN_NULL_WITHOUT_INDICATOR, "22002", "22002" },
+   { DESC_ERROR_IN_ROW, "01S01", "01S01" },
+   { DESC_INVALID_DESCRIPTOR_IDENTIFIER, "HY091", "HY091" },
+   { DESC_OPTION_NOT_FOR_THE_DRIVER, "HYC00", "HYC00" },
+   { DESC_FETCH_OUT_OF_RANGE, "HY106", "S1106" },
+   { DESC_COUNT_FIELD_INCORRECT, "07002", "07002" },
+};
+
+static PG_ErrorInfo    *DC_create_errorinfo(const DescriptorClass *desc)
+{
+   PG_ErrorInfo    *error;
+   ConnectionClass *conn;
+   EnvironmentClass    *env;
+   Int4    errornum;
+
+   if (desc->pgerror)
+       return desc->pgerror;
+   errornum = desc->__error_number;
+   error = ER_Constructor(errornum, desc->__error_message);
+   if (!error)
+       return error;
+   conn = DC_get_conn(desc);
+   env = (EnvironmentClass *) conn->henv;
+   if (errornum < 0 ||
+       errornum >= sizeof(Descriptor_sqlstate) / sizeof(Descriptor_sqlstate[0]))
+       errornum = 1;
+   strcpy(error->sqlstate, EN_is_odbc3(env) ? Descriptor_sqlstate[errornum].ver3str : Descriptor_sqlstate[errornum].ver2str); 
+        return error;
+}
+void
+DC_log_error(const char *func, const char *desc, const DescriptorClass *self)
+{
+#define nullcheck(a) (a ? a : "(NULL)")
+   if (self)
+   {
+       qlog("DESCRIPTOR ERROR: func=%s, desc='%s', errnum=%d, errmsg='%s'\n", func, desc, self->__error_number, nullcheck(self->__error_message));
+       mylog("DESCRIPTOR ERROR: func=%s, desc='%s', errnum=%d, errmsg='%s'\n", func, desc, self->__error_number, nullcheck(self->__error_message));
+   }
+}
+
+/*     Returns the next SQL error information. */
+RETCODE        SQL_API
+PGAPI_DescError(   SQLHDESC hdesc,
+           SWORD   RecNumber,
+           UCHAR FAR * szSqlState,
+           SDWORD FAR * pfNativeError,
+           UCHAR FAR * szErrorMsg,
+           SWORD cbErrorMsgMax,
+           SWORD FAR * pcbErrorMsg,
+           UWORD flag)
+{
+   /* CC: return an error of a hdesc  */
+   DescriptorClass *desc = (DescriptorClass *) hdesc;
+
+   desc->pgerror = DC_create_errorinfo(desc);
+   return ER_ReturnError(desc->pgerror, RecNumber, szSqlState,
+               pfNativeError, szErrorMsg, cbErrorMsgMax,
+               pcbErrorMsg, flag);
+}
+
+#endif /* ODBCVER */
 
  *
  * Comments:       See "notice.txt" for copyright and license information.
  *
- * $Id: descriptor.h,v 1.10 2003/07/31 01:57:50 hinoue Exp $
+ * $Id: descriptor.h,v 1.11 2003/10/25 04:19:19 hinoue Exp $
  *
  */
 
 Int4 FI_precision(const FIELD_INFO *);
 Int4 FI_scale(const FIELD_INFO *);
 
+typedef struct DescriptorHeader_
+{
+   ConnectionClass *conn_conn;
+   char    embedded;
+   char    type_defined;
+   UInt4   desc_type;
+   UInt4   error_row;  /* 1-based row */
+   UInt4   error_index;    /* 1-based index */
+   Int4    __error_number;
+   char    *__error_message;
+   PG_ErrorInfo    *pgerror;
+} DescriptorClass;
+
+/*
+ * ARD and APD are(must be) of the same format
+ */
 struct ARDFields_
 {
-   StatementClass  *stmt;
 #if (ODBCVER >= 0x0300)
-   int     size_of_rowset; /* for ODBC3 fetch operations */
+   int     size_of_rowset; /* for ODBC3 fetch operation */
 #endif /* ODBCVER */
-   int     bind_size;  /* size of each structure if using Row
-                           * Binding */
+   int     bind_size;  /* size of each structure if using
+                    * Row-wise Binding */
    UInt2       *row_operation_ptr;
    UInt4       *row_offset_ptr;
    BindInfoClass   *bookmark;
    int     size_of_rowset_odbc2; /* for SQLExtendedFetch */
 };
 
+/*
+ * APD must be of the same format as ARD
+ */
 struct APDFields_
 {
-   StatementClass  *stmt;
    int     paramset_size;
-   int     param_bind_type; /* size of each structure if using Param
-                       * Binding */
-   UInt2           *param_operation_ptr;
-   UInt4           *param_offset_ptr;
+   int     param_bind_type; /* size of each structure if using
+                     * Row-wsie Parameter Binding */
+   UInt2       *param_operation_ptr;
+   UInt4       *param_offset_ptr;
+   ParameterInfoClass  *bookmark; /* dummy item to fit APD to ARD */
    ParameterInfoClass  *parameters;
-   int         allocated;
+   int     allocated;
+   int     paramset_size_dummy; /* dummy item to fit APD to ARD */
 };
 
 struct IRDFields_
 
 struct IPDFields_
 {
-   StatementClass  *stmt;
    UInt4       *param_processed_ptr;
    UInt2       *param_status_ptr;
    ParameterImplClass  *parameters;
    int         allocated;
 };
 
+typedef    struct
+{
+   DescriptorClass deschd;
+   union {
+       ARDFields   ard;
+       APDFields   apd;
+       IRDFields   ird;
+       IPDFields   ipd;
+   } flds;
+}  DescriptorAlloc;
+typedef struct
+{
+   DescriptorClass deschd;
+   ARDFields   ardopts;
+}  ARDClass;
+typedef struct
+{
+   DescriptorClass deschd;
+   APDFields   apdopts;
+}  APDClass;
+typedef struct
+{
+   DescriptorClass deschd;
+   IRDFields   irdopts;
+}  IRDClass;
+typedef struct
+{
+   DescriptorClass deschd;
+   IPDFields   ipdopts;
+}  IPDClass;
+
+#define    DC_get_conn(a)  (a->conn_conn)
+
+void InitializeEmbeddedDescriptor(DescriptorClass *, StatementClass *stmt,
+               UInt4 desc_type);
+void   DC_Destructor(desc);
 void   InitializeARDFields(ARDFields *self);
 void   InitializeAPDFields(APDFields *self);
 /* void    InitializeIRDFields(IRDFields *self);
 void   InitializeIPDFiedls(IPDFields *self); */
-void   ARDFields_free(ARDFields *self);
-void   APDFields_free(APDFields *self);
-void   IRDFields_free(IRDFields *self);
-void   IPDFields_free(IPDFields *self);
+BindInfoClass  *ARD_AllocBookmark(ARDFields *self);
 void   ARD_unbind_cols(ARDFields *self, BOOL freeall);
 void   APD_free_params(APDFields *self, char option);
 void   IPD_free_params(IPDFields *self, char option);
 #if (ODBCVER >= 0x0300)
-void   Desc_set_error(SQLHDESC hdesc, int errornumber, const char * errormsg);
+RETCODE    DC_set_stmt(DescriptorClass *desc, StatementClass *stmt);
+void   DC_clear_error(DescriptorClass *desc);
+void   DC_set_error(DescriptorClass *desc, int errornumber, const char * errormsg);
+void   DC_set_errormsg(DescriptorClass *desc, const char * errormsg);
+PG_ErrorInfo *DC_get_error(DescriptorClass *self);
+int    DC_get_errornumber(const DescriptorClass *self);
+const char *DC_get_errormsg(const DescriptorClass *self);
+void   DC_log_error(const char *func, const char *desc, const DescriptorClass *self);
 #endif /* ODBCVER */
 
-#endif
+/* Error numbers about descriptor handle */
+#define DESC_OK                        0
+#define DESC_EXEC_ERROR                    1
+#define DESC_STATUS_ERROR              2
+#define DESC_SEQUENCE_ERROR                3
+#define DESC_NO_MEMORY_ERROR               4
+#define DESC_COLNUM_ERROR              5
+#define DESC_NO_STMTSTRING             6
+#define DESC_ERROR_TAKEN_FROM_BACKEND          7
+#define DESC_INTERNAL_ERROR                8
+#define DESC_STILL_EXECUTING               9
+#define DESC_NOT_IMPLEMENTED_ERROR         10
+#define DESC_BAD_PARAMETER_NUMBER_ERROR            11
+#define DESC_OPTION_OUT_OF_RANGE_ERROR         12
+#define DESC_INVALID_COLUMN_NUMBER_ERROR       13
+#define DESC_RESTRICTED_DATA_TYPE_ERROR            14
+#define DESC_INVALID_CURSOR_STATE_ERROR            15
+#define DESC_OPTION_VALUE_CHANGED          16
+#define DESC_CREATE_TABLE_ERROR                17
+#define DESC_NO_CURSOR_NAME                18
+#define DESC_INVALID_CURSOR_NAME           19
+#define DESC_INVALID_ARGUMENT_NO           20
+#define DESC_ROW_OUT_OF_RANGE              21
+#define DESC_OPERATION_CANCELLED           22
+#define DESC_INVALID_CURSOR_POSITION           23
+#define DESC_VALUE_OUT_OF_RANGE                24
+#define DESC_OPERATION_INVALID             25
+#define DESC_PROGRAM_TYPE_OUT_OF_RANGE         26
+#define DESC_BAD_ERROR                 27
+#define DESC_INVALID_OPTION_IDENTIFIER         28
+#define DESC_RETURN_NULL_WITHOUT_INDICATOR     29
+#define DESC_ERROR_IN_ROW              30
+#define DESC_INVALID_DESCRIPTOR_IDENTIFIER     31
+#define DESC_OPTION_NOT_FOR_THE_DRIVER         32
+#define DESC_FETCH_OUT_OF_RANGE                33
+#define DESC_COUNT_FIELD_INCORRECT         34
+
+#endif /* __DESCRIPTOR_H__ */
 
    strcpy(szSqlState, EN_is_odbc3(env) ? ver3str : ver2str);
 }
 
+PG_ErrorInfo   *ER_Constructor(SDWORD errnumber, const char *msg)
+{
+   PG_ErrorInfo    *error;
+   Int4        aladd, errsize;
+
+   if (DESC_OK == errnumber)
+       return NULL;
+   if (msg)
+   {
+       errsize = strlen(msg);
+       aladd = errsize;
+   }
+   else
+   {
+       errsize = -1;
+       aladd = 0;
+   }
+   error = (PG_ErrorInfo *) malloc(sizeof(PG_ErrorInfo) + aladd);
+   if (error)
+   {
+       memset(error, 0, sizeof(PG_ErrorInfo));
+       error->status = errnumber;
+       error->errorsize = errsize;
+       if (errsize > 0)
+           memcpy(error->__error_message, msg, errsize);
+       error->__error_message[aladd] = '\0';
+           error->recsize = -1;
+   }
+   return error;
+}
+void
+ER_Destructor(PG_ErrorInfo *self)
+{
+        if (self->__error_message)
+                free(self->__error_message);
+   free(self);
+}
+
+#define    DRVMNGRDIV  511
+/*     Returns the next SQL error information. */
+RETCODE        SQL_API
+ER_ReturnError(PG_ErrorInfo *error,
+       SWORD   RecNumber,
+       UCHAR FAR * szSqlState,
+       SDWORD FAR * pfNativeError,
+       UCHAR FAR * szErrorMsg,
+       SWORD cbErrorMsgMax,
+       SWORD FAR * pcbErrorMsg,
+       UWORD flag)
+{
+   /* CC: return an error of a hstmt  */
+   BOOL        partial_ok = ((flag & PODBC_ALLOW_PARTIAL_EXTRACT) != 0),
+           clear_str = ((flag & PODBC_ERROR_CLEAR) != 0);
+   const char  *msg;
+   SWORD       msglen, stapos, wrtlen, pcblen;
+
+   if (!error)
+       return SQL_NO_DATA_FOUND;
+   msg = error->__error_message;
+   mylog("ER_GetError: status = %d, msg = #%s#\n", error->status, msg);
+   msglen = (SWORD) strlen(msg);
+   /*
+    *  Even though an application specifies a larger error message
+    *  buffer, the driver manager changes it silently.
+    *  Therefore we divide the error message into ... 
+    */
+   if (error->recsize < 0)
+   {
+       if (cbErrorMsgMax > 0)
+           error->recsize = cbErrorMsgMax - 1; /* apply the first request */
+       else
+           error->recsize = DRVMNGRDIV;
+   }
+   if (RecNumber < 0)
+   {
+       if (0 == error->errorpos)
+           RecNumber = 1;
+       else
+           RecNumber = 2 + (error->errorpos - 1) / error->recsize;
+   }
+   stapos = (RecNumber - 1) * error->recsize;
+   if (stapos > msglen)
+       return SQL_NO_DATA_FOUND; 
+   pcblen = wrtlen = msglen - stapos;
+   if (pcblen > error->recsize)
+       pcblen = error->recsize;
+   if (0 == cbErrorMsgMax)
+       wrtlen = 0; 
+   else if (wrtlen >= cbErrorMsgMax)
+   {
+       if (partial_ok)
+           wrtlen = cbErrorMsgMax - 1;
+       else if (cbErrorMsgMax <= error->recsize)
+           wrtlen = 0;
+       else 
+           wrtlen = error->recsize;
+   }
+   if (wrtlen > pcblen)
+       wrtlen = pcblen;
+   if (NULL != pcbErrorMsg)
+       *pcbErrorMsg = pcblen;
+
+   if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0))
+   {
+       memcpy(szErrorMsg, msg + stapos, wrtlen);
+       szErrorMsg[wrtlen] = '\0';
+   }
+
+   if (NULL != pfNativeError)
+       *pfNativeError = error->status;
+
+   if (NULL != szSqlState)
+       strncpy(szSqlState, error->sqlstate, 6);
+
+   mylog("      szSqlState = '%s',len=%d, szError='%s'\n", szSqlState, pcblen, szErrorMsg);
+   if (clear_str)
+   {
+       error->errorpos = stapos + wrtlen;
+       if (error->errorpos >= msglen)
+           ER_Destructor(error);
+   }
+   if (wrtlen == 0)
+       return SQL_SUCCESS_WITH_INFO;
+   else
+       return SQL_SUCCESS;
+}
+
 #define    DRVMNGRDIV  511
 /*     Returns the next SQL error information. */
 RETCODE        SQL_API
 
    CSTR func = "PGAPI_Prepare";
    StatementClass *self = (StatementClass *) hstmt;
 
-   mylog("%s: entering... len=%d\n", func, cbSqlStr);
+   mylog("%s: entering...\n", func);
 
    if (!self)
    {
 PGAPI_ExecDirect(
                 HSTMT hstmt,
                 UCHAR FAR * szSqlStr,
-                SDWORD cbSqlStr)
+                SDWORD cbSqlStr,
+                UWORD flag)
 {
    StatementClass *stmt = (StatementClass *) hstmt;
    RETCODE     result;
 
    mylog("%s: calling PGAPI_Execute...\n", func);
 
-   result = PGAPI_Execute(hstmt);
+   result = PGAPI_Execute(hstmt, flag);
 
    mylog("%s: returned %hd from PGAPI_Execute\n", func, result);
    return result;
 
        if (kres = res->next, kres)
        {
-           if (kres->fields)
-               CI_Destructor(kres->fields);
            kres->fields = res->fields;
            res->fields = NULL;
            kres->num_fields = res->num_fields;
        }
    }
 #if (ODBCVER >= 0x0300)
-   ipdopts = SC_get_IPD(stmt);
+   ipdopts = SC_get_IPDF(stmt);
    if (ipdopts->param_status_ptr)
    {
        switch (retval)
 #endif /* ODBCVER */
    if (end_row = stmt->exec_end_row, end_row < 0)
    {
-       apdopts = SC_get_APD(stmt);
+       apdopts = SC_get_APDF(stmt);
        end_row = apdopts->paramset_size - 1;
    }
    if (stmt->inaccurate_result ||
 
 /* Execute a prepared SQL statement */
 RETCODE        SQL_API
-PGAPI_Execute(
-             HSTMT hstmt)
+PGAPI_Execute(HSTMT hstmt, UWORD flag)
 {
    CSTR func = "PGAPI_Execute";
    StatementClass *stmt = (StatementClass *) hstmt;
        return SQL_INVALID_HANDLE;
    }
 
-   apdopts = SC_get_APD(stmt);
+   apdopts = SC_get_APDF(stmt);
    /*
     * If the statement is premature, it means we already executed it from
     * an SQLPrepare/SQLDescribeCol type of scenario.  So just return
        end_row = apdopts->paramset_size - 1; 
    if (stmt->exec_current_row < 0)
        stmt->exec_current_row = start_row;
-   ipdopts = SC_get_IPD(stmt);
+   ipdopts = SC_get_IPDF(stmt);
    if (stmt->exec_current_row == start_row)
    {
        if (ipdopts->param_processed_ptr)
    stmt->data_at_exec = -1;
    stmt->current_exec_param = -1;
    stmt->put_data = FALSE;
+   cancelNeedDataState(stmt);
 
    return SQL_SUCCESS;
 }
                PTR FAR * prgbValue)
 {
    CSTR func = "PGAPI_ParamData";
-   StatementClass *stmt = (StatementClass *) hstmt;
+   StatementClass *stmt = (StatementClass *) hstmt, *estmt;
    APDFields   *apdopts;
    IPDFields   *ipdopts;
-   int         i,
-               retval;
+   RETCODE     retval;
+   int     i;
    ConnInfo   *ci;
 
    mylog("%s: entering...\n", func);
        return SQL_INVALID_HANDLE;
    }
    ci = &(SC_get_conn(stmt)->connInfo);
-   apdopts = SC_get_APD(stmt);
 
-   mylog("%s: data_at_exec=%d, params_alloc=%d\n", func, stmt->data_at_exec, apdopts->allocated);
+   estmt = stmt->execute_delegate ? stmt->execute_delegate : stmt;
+   apdopts = SC_get_APDF(estmt);
+   mylog("%s: data_at_exec=%d, params_alloc=%d\n", func, estmt->data_at_exec, apdopts->allocated);
 
-   if (stmt->data_at_exec < 0)
+   if (estmt->data_at_exec < 0)
    {
        SC_set_error(stmt, STMT_SEQUENCE_ERROR, "No execution-time parameters for this statement");
        SC_log_error(func, "", stmt);
        return SQL_ERROR;
    }
 
-   if (stmt->data_at_exec > apdopts->allocated)
+   if (estmt->data_at_exec > apdopts->allocated)
    {
        SC_set_error(stmt, STMT_SEQUENCE_ERROR, "Too many execution-time parameters were present");
        SC_log_error(func, "", stmt);
    }
 
    /* close the large object */
-   if (stmt->lobj_fd >= 0)
+   if (estmt->lobj_fd >= 0)
    {
-       lo_close(stmt->hdbc, stmt->lobj_fd);
+       lo_close(estmt->hdbc, estmt->lobj_fd);
 
        /* commit transaction if needed */
-       if (!ci->drivers.use_declarefetch && CC_is_in_autocommit(stmt->hdbc))
+       if (!ci->drivers.use_declarefetch && CC_is_in_autocommit(estmt->hdbc))
        {
-           if (!CC_commit(stmt->hdbc))
+           if (!CC_commit(estmt->hdbc))
            {
                SC_set_error(stmt, STMT_EXEC_ERROR, "Could not commit (in-line) a transaction");
                SC_log_error(func, "", stmt);
                return SQL_ERROR;
            }
        }
-       stmt->lobj_fd = -1;
+       estmt->lobj_fd = -1;
    }
 
    /* Done, now copy the params and then execute the statement */
-   ipdopts = SC_get_IPD(stmt);
-   if (stmt->data_at_exec == 0)
+   ipdopts = SC_get_IPDF(estmt);
+   if (estmt->data_at_exec == 0)
    {
        BOOL    exec_end;
 
-       retval = Exec_with_parameters_resolved(stmt, &exec_end);
+       retval = Exec_with_parameters_resolved(estmt, &exec_end);
        if (exec_end)
-           return retval;
-       if (retval = PGAPI_Execute(stmt), SQL_NEED_DATA != retval)
+       {
+           stmt->execute_delegate = NULL;
+           return dequeueNeedDataCallback(retval, stmt);
+       }
+       if (retval = PGAPI_Execute(estmt, 0), SQL_NEED_DATA != retval)
            return retval;
    }
 
     * Set beginning param;  if first time SQLParamData is called , start
     * at 0. Otherwise, start at the last parameter + 1.
     */
-   i = stmt->current_exec_param >= 0 ? stmt->current_exec_param + 1 : 0;
+   i = estmt->current_exec_param >= 0 ? estmt->current_exec_param + 1 : 0;
 
    /* At least 1 data at execution parameter, so Fill in the token value */
    for (; i < apdopts->allocated; i++)
    {
        if (apdopts->parameters[i].data_at_exec)
        {
-           stmt->data_at_exec--;
-           stmt->current_exec_param = i;
-           stmt->put_data = FALSE;
-           *prgbValue = apdopts->parameters[i].buffer; /* token */
+           estmt->data_at_exec--;
+           estmt->current_exec_param = i;
+           estmt->put_data = FALSE;
+           if (prgbValue)
+           {
+               /* returns token here */
+               if (stmt->execute_delegate)
+               {
+                   UInt4   offset = apdopts->param_offset_ptr ? *apdopts->param_offset_ptr : 0;
+                   UInt4   perrow = apdopts->param_bind_type > 0 ? apdopts->param_bind_type : apdopts->parameters[i].buflen; 
+
+                   *prgbValue = apdopts->parameters[i].buffer + offset + estmt->exec_current_row * perrow;
+               }
+               else
+                   *prgbValue = apdopts->parameters[i].buffer;
+           }
            break;
        }
    }
              SDWORD cbValue)
 {
    CSTR func = "PGAPI_PutData";
-   StatementClass *stmt = (StatementClass *) hstmt;
+   StatementClass *stmt = (StatementClass *) hstmt, *estmt;
    ConnectionClass *conn;
    APDFields   *apdopts;
    IPDFields   *ipdopts;
+   PutDataInfo *pdata;
    int         old_pos,
                retval;
    ParameterInfoClass *current_param;
    ParameterImplClass *current_iparam;
+   PutDataClass    *current_pdata;
    char       *buffer, *putbuf, *allocbuf = NULL;
    Int2        ctype;
-   SDWORD      putlen;
+   SDWORD          putlen;
    BOOL        lenset = FALSE;
 
    mylog("%s: entering...\n", func);
        return SQL_INVALID_HANDLE;
    }
 
-   apdopts = SC_get_APD(stmt);
-   if (stmt->current_exec_param < 0)
+   estmt = stmt->execute_delegate ? stmt->execute_delegate : stmt;
+   apdopts = SC_get_APDF(estmt);
+   if (estmt->current_exec_param < 0)
    {
        SC_set_error(stmt, STMT_SEQUENCE_ERROR, "Previous call was not SQLPutData or SQLParamData");
        SC_log_error(func, "", stmt);
        return SQL_ERROR;
    }
 
-   current_param = &(apdopts->parameters[stmt->current_exec_param]);
-   ipdopts = SC_get_IPD(stmt);
-   current_iparam = &(ipdopts->parameters[stmt->current_exec_param]);
+   current_param = &(apdopts->parameters[estmt->current_exec_param]);
+   ipdopts = SC_get_IPDF(estmt);
+   current_iparam = &(ipdopts->parameters[estmt->current_exec_param]);
+   pdata = SC_get_PDTI(estmt);
+   current_pdata = &(pdata->pdata[estmt->current_exec_param]);
    ctype = current_param->CType;
 
-   conn = SC_get_conn(stmt);
+   conn = SC_get_conn(estmt);
    if (ctype == SQL_C_DEFAULT)
        ctype = sqltype_to_default_ctype(conn, current_iparam->SQLType);
    if (SQL_NTS == cbValue)
        }
    }
 
-   if (!stmt->put_data)
+   if (!estmt->put_data)
    {                           /* first call */
        mylog("PGAPI_PutData: (1) cbValue = %d\n", cbValue);
 
-       stmt->put_data = TRUE;
+       estmt->put_data = TRUE;
 
-       current_param->EXEC_used = (SDWORD *) malloc(sizeof(SDWORD));
-       if (!current_param->EXEC_used)
+       current_pdata->EXEC_used = (SDWORD *) malloc(sizeof(SDWORD));
+       if (!current_pdata->EXEC_used)
        {
            SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Out of memory in PGAPI_PutData (1)");
            SC_log_error(func, "", stmt);
            return SQL_ERROR;
        }
 
-       *current_param->EXEC_used = putlen;
+       *current_pdata->EXEC_used = putlen;
 
        if (cbValue == SQL_NULL_DATA)
            return SQL_SUCCESS;
        if (current_iparam->PGType == conn->lobj_type)
        {
            /* begin transaction if needed */
-           if (!CC_is_in_trans(stmt->hdbc))
+           if (!CC_is_in_trans(conn))
            {
-               if (!CC_begin(stmt->hdbc))
+               if (!CC_begin(conn))
                {
                    SC_set_error(stmt, STMT_EXEC_ERROR, "Could not begin (in-line) a transaction");
                    SC_log_error(func, "", stmt);
            }
 
            /* store the oid */
-           current_param->lobj_oid = lo_creat(stmt->hdbc, INV_READ | INV_WRITE);
-           if (current_param->lobj_oid == 0)
+           current_pdata->lobj_oid = lo_creat(conn, INV_READ | INV_WRITE);
+           if (current_pdata->lobj_oid == 0)
            {
                SC_set_error(stmt, STMT_EXEC_ERROR, "Couldnt create large object.");
                SC_log_error(func, "", stmt);
            /***current_param->EXEC_buffer = (char *) ¤t_param->lobj_oid;***/
 
            /* store the fd */
-           stmt->lobj_fd = lo_open(stmt->hdbc, current_param->lobj_oid, INV_WRITE);
-           if (stmt->lobj_fd < 0)
+           estmt->lobj_fd = lo_open(conn, current_pdata->lobj_oid, INV_WRITE);
+           if (estmt->lobj_fd < 0)
            {
                SC_set_error(stmt, STMT_EXEC_ERROR, "Couldnt open large object for writing.");
                SC_log_error(func, "", stmt);
                return SQL_ERROR;
            }
 
-           retval = lo_write(stmt->hdbc, stmt->lobj_fd, putbuf, putlen);
+           retval = lo_write(conn, estmt->lobj_fd, putbuf, putlen);
            mylog("lo_write: cbValue=%d, wrote %d bytes\n", putlen, retval);
        }
        else
        {
-           current_param->EXEC_buffer = malloc(putlen + 1);
-           if (!current_param->EXEC_buffer)
+           current_pdata->EXEC_buffer = malloc(putlen + 1);
+           if (!current_pdata->EXEC_buffer)
            {
                SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Out of memory in PGAPI_PutData (2)");
                SC_log_error(func, "", stmt);
                return SQL_ERROR;
            }
-           memcpy(current_param->EXEC_buffer, putbuf, putlen);
-           current_param->EXEC_buffer[putlen] = '\0';
+           memcpy(current_pdata->EXEC_buffer, putbuf, putlen);
+           current_pdata->EXEC_buffer[putlen] = '\0';
        }
    }
    else
        if (current_iparam->PGType == conn->lobj_type)
        {
            /* the large object fd is in EXEC_buffer */
-           retval = lo_write(stmt->hdbc, stmt->lobj_fd, putbuf, putlen);
+           retval = lo_write(conn, estmt->lobj_fd, putbuf, putlen);
            mylog("lo_write(2): cbValue = %d, wrote %d bytes\n", putlen, retval);
 
-           *current_param->EXEC_used += putlen;
+           *current_pdata->EXEC_used += putlen;
        }
        else
        {
-           buffer = current_param->EXEC_buffer;
-           old_pos = *current_param->EXEC_used;
+           buffer = current_pdata->EXEC_buffer;
+           old_pos = *current_pdata->EXEC_used;
            if (putlen > 0)
            {
-               *current_param->EXEC_used += putlen;
+               *current_pdata->EXEC_used += putlen;
 
-               mylog("        cbValue = %d, old_pos = %d, *used = %d\n", putlen, old_pos, *current_param->EXEC_used);
+               mylog("        cbValue = %d, old_pos = %d, *used = %d\n", putlen, old_pos, *current_pdata->EXEC_used);
 
                /* dont lose the old pointer in case out of memory */
-               buffer = realloc(current_param->EXEC_buffer, *current_param->EXEC_used + 1);
+               buffer = realloc(current_pdata->EXEC_buffer, *current_pdata->EXEC_used + 1);
                if (!buffer)
                {
                    SC_set_error(stmt, STMT_NO_MEMORY_ERROR,"Out of memory in PGAPI_PutData (3)");
                }
 
                memcpy(&buffer[old_pos], putbuf, putlen);
-               buffer[*current_param->EXEC_used] = '\0';
+               buffer[*current_pdata->EXEC_used] = '\0';
 
                /* reassign buffer incase realloc moved it */
-               current_param->EXEC_buffer = buffer;
+               current_pdata->EXEC_buffer = buffer;
            }
            else
            {
 
 #else
    result_cols = 15;
 #endif /* ODBCVER */
-   extend_column_bindings(SC_get_ARD(stmt), result_cols);
+   extend_column_bindings(SC_get_ARDF(stmt), result_cols);
 
    QR_set_num_fields(res, result_cols);
    QR_set_field_info(res, 0, "TYPE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
                case SQL_API_SQLSETCURSORNAME:
                    *pfExists = TRUE;
                    break;
+#if (ODBCVER < 0x0300)
                case SQL_API_SQLSETPARAM:
                    *pfExists = FALSE;
                    break;      /* odbc 1.0 */
                case SQL_API_SQLTRANSACT:
                    *pfExists = TRUE;
                    break;
+#endif /* ODBCVER */
 
                    /* ODBC level 1 functions */
                case SQL_API_SQLBINDPARAMETER:
                case SQL_API_SQLNUMPARAMS:
                    *pfExists = TRUE;
                    break;
+#if (ODBCVER < 0x0300)
                case SQL_API_SQLPARAMOPTIONS:
                    *pfExists = TRUE;
                    break;
+#endif /* ODBCVER */
                case SQL_API_SQLPRIMARYKEYS:
                    *pfExists = TRUE;
                    break;
                case SQL_API_SQLSETPOS:
                    *pfExists = TRUE;
                    break;
+#if (ODBCVER < 0x0300)
                case SQL_API_SQLSETSCROLLOPTIONS:
                    *pfExists = TRUE;
                    break;      /* odbc 1.0 */
+#endif /* ODBCVER */
                case SQL_API_SQLTABLEPRIVILEGES:
                    *pfExists = TRUE;
                    break;
    else
        strcat(tables_query, " and usesysid = relowner order by relname");
 
-   result = PGAPI_ExecDirect(htbl_stmt, tables_query, strlen(tables_query));
+   result = PGAPI_ExecDirect(htbl_stmt, tables_query, SQL_NTS, 0);
    if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
    {
        SC_full_error_copy(stmt, htbl_stmt);
     * a statement is actually executed, so we'll have to do this
     * ourselves.
     */
-   extend_column_bindings(SC_get_ARD(stmt), 5);
+   extend_column_bindings(SC_get_ARDF(stmt), 5);
 
    /* set the field names */
    QR_set_num_fields(res, 5);
    ConnectionClass *conn;
    SWORD       internal_asis_type = SQL_C_CHAR;
    const char *likeeq = "like";
-   const char *mzTableOwner = szTableOwner, *mzTableName = szTableName,
-       *mzColumnName = szColumnName;
 
    mylog("%s: entering...stmt=%u scnm=%x len=%d\n", func, stmt, szTableOwner, cbTableOwner);
 
 
    if ((flag & PODBC_NOT_SEARCH_PATTERN) != 0) 
    {
-       likeeq = "=";
-   }
-   else
-   {
-   }
-   if ((flag & PODBC_NOT_SEARCH_PATTERN) != 0) 
-   {
-       my_strcat1(columns_query, " and c.relname %s '%.*s'", likeeq, mzTableName, cbTableName);
+       my_strcat(columns_query, " and c.relname = '%.*s'", szTableName, cbTableName);
        if (conn->schema_support)
-           schema_strcat1(columns_query, " and u.nspname %s '%.*s'", likeeq, mzTableOwner, cbTableOwner, mzTableName, cbTableName, conn);
+           schema_strcat(columns_query, " and u.nspname = '%.*s'", szTableOwner, cbTableOwner, szTableName, cbTableName, conn);
        else
-           my_strcat1(columns_query, " and u.usename %s '%.*s'", likeeq, mzTableOwner, cbTableOwner);
-       my_strcat1(columns_query, " and a.attname %s '%.*s'", likeeq, mzColumnName, cbColumnName);
+           my_strcat(columns_query, " and u.usename = '%.*s'", szTableOwner, cbTableOwner);
+       my_strcat(columns_query, " and a.attname = '%.*s'", szColumnName, cbColumnName);
    }
    else
    {
        int escTbnamelen;
 
        escTbnamelen = reallyEscapeCatalogEscapes(szTableName, cbTableName, esc_table_name, sizeof(esc_table_name), conn->ccsc);
-       mzTableName = esc_table_name;
-       my_strcat1(columns_query, " and c.relname %s '%.*s'", likeeq, mzTableName, escTbnamelen);
+       my_strcat1(columns_query, " and c.relname %s '%.*s'", likeeq, esc_table_name, escTbnamelen);
        if (conn->schema_support)
-           schema_strcat1(columns_query, " and u.nspname %s '%.*s'", likeeq, szTableOwner, cbTableOwner, mzTableName, cbTableName, conn);
+           schema_strcat1(columns_query, " and u.nspname %s '%.*s'", likeeq, szTableOwner, cbTableOwner, szTableName, cbTableName, conn);
        else
-           my_strcat1(columns_query, " and u.usename %s '%.*s'", likeeq, mzTableOwner, cbTableOwner);
-       my_strcat1(columns_query, " and a.attname %s '%.*s'", likeeq, mzColumnName, cbColumnName);
+           my_strcat1(columns_query, " and u.usename %s '%.*s'", likeeq, szTableOwner, cbTableOwner);
+       my_strcat1(columns_query, " and a.attname %s '%.*s'", likeeq, szColumnName, cbColumnName);
    }
 
    /*
 
    mylog("%s: hcol_stmt = %u, col_stmt = %u\n", func, hcol_stmt, col_stmt);
 
-   result = PGAPI_ExecDirect(hcol_stmt, columns_query,
-                             strlen(columns_query));
+   result = PGAPI_ExecDirect(hcol_stmt, columns_query, SQL_NTS, 0);
    if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
    {
        SC_full_error_copy(stmt, col_stmt);
    reserved_cols = 12;
 #endif /* ODBCVER */
    result_cols = reserved_cols + 2;
-   extend_column_bindings(SC_get_ARD(stmt), result_cols);
+   extend_column_bindings(SC_get_ARDF(stmt), result_cols);
 
    /* set the field names */
    QR_set_num_fields(res, result_cols);
 
    mylog("%s: hcol_stmt = %u, col_stmt = %u\n", func, hcol_stmt, col_stmt);
 
-   result = PGAPI_ExecDirect(hcol_stmt, columns_query,
-                             strlen(columns_query));
+   result = PGAPI_ExecDirect(hcol_stmt, columns_query, SQL_NTS, 0);
    if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
    {
        SC_full_error_copy(stmt, col_stmt);
 
    res = QR_Constructor();
    SC_set_Result(stmt, res);
-   extend_column_bindings(SC_get_ARD(stmt), 8);
+   extend_column_bindings(SC_get_ARDF(stmt), 8);
 
    QR_set_num_fields(res, 8);
    QR_set_field_info(res, 0, "SCOPE", PG_TYPE_INT2, 2);
     * a statement is actually executed, so we'll have to do this
     * ourselves.
     */
-   extend_column_bindings(SC_get_ARD(stmt), 13);
+   extend_column_bindings(SC_get_ARDF(stmt), 13);
 
    /* set the field names */
    QR_set_num_fields(res, 13);
    else
        strcat(index_query, " i.indisunique, c.relname");
 
-   result = PGAPI_ExecDirect(hindx_stmt, index_query, strlen(index_query));
+   result = PGAPI_ExecDirect(hindx_stmt, index_query, SQL_NTS, 0);
    if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
    {
        /*
     * ourselves.
     */
    result_cols = 6;
-   extend_column_bindings(SC_get_ARD(stmt), result_cols);
+   extend_column_bindings(SC_get_ARDF(stmt), result_cols);
 
    /* set the field names */
    QR_set_num_fields(res, result_cols);
        }
        mylog("%s: tables_query='%s'\n", func, tables_query);
 
-       result = PGAPI_ExecDirect(htbl_stmt, tables_query, strlen(tables_query));
+       result = PGAPI_ExecDirect(htbl_stmt, tables_query, SQL_NTS, 0);
        if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
        {
            SC_full_error_copy(stmt, tbl_stmt);
 #else
    result_cols = 14;
 #endif /* ODBCVER */
-   extend_column_bindings(SC_get_ARD(stmt), result_cols);
+   extend_column_bindings(SC_get_ARDF(stmt), result_cols);
 
    /* set the field names */
    QR_set_num_fields(res, result_cols);
                "AND (pt.tgconstrrelid=pc1.oid)) ",
                fk_table_needed);
 
-       result = PGAPI_ExecDirect(htbl_stmt, tables_query, strlen(tables_query));
+       result = PGAPI_ExecDirect(htbl_stmt, tables_query, SQL_NTS, 0);
 
        if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
        {
                "       )",
                pk_table_needed);
 
-       result = PGAPI_ExecDirect(htbl_stmt, tables_query, strlen(tables_query));
+       result = PGAPI_ExecDirect(htbl_stmt, tables_query, SQL_NTS, 0);
        if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
        {
            SC_error_copy(stmt, tbl_stmt);
 #else
    result_cols = 13;
 #endif /* ODBCVER */
-   extend_column_bindings(SC_get_ARD(stmt), result_cols);
+   extend_column_bindings(SC_get_ARDF(stmt), result_cols);
 
    /* set the field names */
    QR_set_num_fields(res, result_cols);
     * results can be retrieved.
     */
    stmt->status = STMT_FINISHED;
-   extend_column_bindings(SC_get_ARD(stmt), 8);
+   extend_column_bindings(SC_get_ARDF(stmt), 8);
    /* set up the current tuple pointer for SQLFetch */
    stmt->currTuple = -1;
    stmt->rowset_start = -1;
     * ourselves.
     */
    result_cols = 7;
-   extend_column_bindings(SC_get_ARD(stmt), result_cols);
+   extend_column_bindings(SC_get_ARDF(stmt), result_cols);
 
    /* set the field names */
    stmt->manual_result = TRUE;
 
 }
 
 #ifdef MY_LOG
+static FILE *LOGFP = NULL;
 void
 mylog(char *fmt,...)
 {
    va_list     args;
    char        filebuf[80];
-   static FILE *LOGFP = NULL;
 
    ENTER_MYLOG_CS;
    if (mylog_on)
 
    if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
        return encstr;
 
-   result = PGAPI_ExecDirect(hstmt, "Show Client_Encoding", SQL_NTS);
+   result = PGAPI_ExecDirect(hstmt, "Show Client_Encoding", SQL_NTS, 0);
    if (result == SQL_SUCCESS_WITH_INFO)
    {
        char sqlState[8], errormsg[128], enc[32];
 
    mylog("[SQLExecDirect]");
    ENTER_STMT_CS(stmt);
    SC_clear_error(stmt);
-   ret = PGAPI_ExecDirect(StatementHandle, StatementText, TextLength);
+   ret = PGAPI_ExecDirect(StatementHandle, StatementText, TextLength, 0);
    LEAVE_STMT_CS(stmt);
    return ret;
 }
    mylog("[SQLExecute]");
    ENTER_STMT_CS(stmt);
    SC_clear_error(stmt);
-   ret = PGAPI_Execute(StatementHandle);
+   ret = PGAPI_Execute(StatementHandle, 0);
    LEAVE_STMT_CS(stmt);
    return ret;
 }
 #if (ODBCVER >= 0x0300)
    if (SC_get_conn(stmt)->driver_version >= 0x0300)
    {
-       IRDFields   *irdopts = SC_get_IRD(stmt);
-       ARDFields   *ardopts = SC_get_ARD(stmt);
+       IRDFields   *irdopts = SC_get_IRDF(stmt);
+       ARDFields   *ardopts = SC_get_ARDF(stmt);
        SQLUSMALLINT *rowStatusArray = irdopts->rowStatusArray;
        SQLINTEGER *pcRow = irdopts->rowsFetched;
 
    mylog("[SQLExtendedFetch]");
    ENTER_STMT_CS(stmt);
    SC_clear_error(stmt);
-   ret = PGAPI_ExtendedFetch(hstmt, fFetchType, irow, pcrow, rgfRowStatus, 0, SC_get_ARD(stmt)->size_of_rowset_odbc2);
+   ret = PGAPI_ExtendedFetch(hstmt, fFetchType, irow, pcrow, rgfRowStatus, 0, SC_get_ARDF(stmt)->size_of_rowset_odbc2);
    stmt->transition_status = 7;
    LEAVE_STMT_CS(stmt);
    return ret;
 
        case SQL_HANDLE_DESC:
            conn = (ConnectionClass *) InputHandle;
            ENTER_CONN_CS(conn);
-           CC_set_error(conn, CONN_NOT_IMPLEMENTED_ERROR, "can't alloc Desc Handle yet"); 
+           ret = PGAPI_AllocDesc(InputHandle, OutputHandle);
            LEAVE_CONN_CS(conn);
-           ret = SQL_ERROR;
+           mylog("Descriptor OutputHandle=%x\n", *OutputHandle);
            break;
        default:
            ret = SQL_ERROR;
    return ret;
 }
 
-static HSTMT
-descHandleFromStatementHandle(HSTMT StatementHandle, SQLINTEGER descType) 
-{
-   switch (descType)
-   {
-       case SQL_ATTR_APP_ROW_DESC:     /* 10010 */
-           return StatementHandle; /* this is bogus */
-       case SQL_ATTR_APP_PARAM_DESC:   /* 10011 */
-           return (HSTMT) ((SQLUINTEGER) StatementHandle + 1) ; /* this is bogus */
-       case SQL_ATTR_IMP_ROW_DESC:     /* 10012 */
-           return (HSTMT) ((SQLUINTEGER) StatementHandle + 2); /* this is bogus */
-       case SQL_ATTR_IMP_PARAM_DESC:   /* 10013 */
-           return (HSTMT) ((SQLUINTEGER) StatementHandle + 3); /* this is bogus */
-   }
-   return (HSTMT) 0;
-}
-static HSTMT
-statementHandleFromDescHandle(HSTMT DescHandle, SQLINTEGER *descType) 
-{
-   SQLUINTEGER res = (SQLUINTEGER) DescHandle % 4;
-   switch (res)
-   {
-       case 0: *descType = SQL_ATTR_APP_ROW_DESC; /* 10010 */
-           break;
-       case 1: *descType = SQL_ATTR_APP_PARAM_DESC; /* 10011 */
-           break;
-       case 2: *descType = SQL_ATTR_IMP_ROW_DESC; /* 10012 */
-           break;
-       case 3: *descType = SQL_ATTR_IMP_PARAM_DESC; /* 10013 */
-           break;
-   }
-   return (HSTMT) ((SQLUINTEGER) DescHandle - res);
-}
-
 /* new function */
 RETCODE        SQL_API
 SQLCopyDesc(SQLHDESC SourceDescHandle,
            SQLHDESC TargetDescHandle)
 {
+   RETCODE ret;
+
    mylog("[[SQLCopyDesc]]\n");
-   mylog("Error not implemented\n");
-   return SQL_ERROR;
+   DC_clear_error((DescriptorClass *) TargetDescHandle);
+   ret = PGAPI_CopyDesc(SourceDescHandle, TargetDescHandle);
+   return ret;
 }
 
 /* SQLTransact -> SQLEndTran */
    CSTR func = "SQLFetchScroll";
    StatementClass *stmt = (StatementClass *) StatementHandle;
    RETCODE     ret = SQL_SUCCESS;
-   IRDFields   *irdopts = SC_get_IRD(stmt);
+   IRDFields   *irdopts = SC_get_IRDF(stmt);
    SQLUSMALLINT *rowStatusArray = irdopts->rowStatusArray;
    SQLINTEGER *pcRow = irdopts->rowsFetched, bkmarkoff = 0;
 
    }
    if (SQL_SUCCESS == ret)
    {
-       ARDFields   *opts = SC_get_ARD(stmt);
+       ARDFields   *opts = SC_get_ARDF(stmt);
 
        ret = PGAPI_ExtendedFetch(StatementHandle, FetchOrientation, FetchOffset,
                pcRow, rowStatusArray, bkmarkoff, opts->size_of_rowset);
        case SQL_HANDLE_STMT:
            ret = PGAPI_FreeStmt(Handle, SQL_DROP);
            break;
+       case SQL_HANDLE_DESC:
+           ret = PGAPI_FreeDesc(Handle);
+           break;
        default:
            ret = SQL_ERROR;
            break;
    RETCODE ret;
 
    mylog("[[SQLGetDescField]]\n");
+   DC_clear_error((DescriptorClass *) DescriptorHandle);
    ret = PGAPI_GetDescField(DescriptorHandle, RecNumber, FieldIdentifier,
            Value, BufferLength, StringLength);
    return ret;
 {
    mylog("[[SQLGetDescRec]]\n");
    mylog("Error not implemented\n");
+   DC_clear_error((DescriptorClass *) DescriptorHandle);
    return SQL_ERROR;
 }
 
    RETCODE     ret;
 
    mylog("[[SQLSetDescField]] h=%u rec=%d field=%d val=%x\n", DescriptorHandle, RecNumber, FieldIdentifier, Value);
+   DC_clear_error((DescriptorClass *) DescriptorHandle);
    ret = PGAPI_SetDescField(DescriptorHandle, RecNumber, FieldIdentifier,
                Value, BufferLength);
    return ret;
 
    mylog("[[SQLSetDescRec]]\n");
    mylog("Error not implemented\n");
+   DC_clear_error((DescriptorClass *) DescriptorHandle);
    return SQL_ERROR;
 }
 
    SQL_FUNC_ESET(pfExists, SQL_API_SQLSTATISTICS);     /* 53 */
    SQL_FUNC_ESET(pfExists, SQL_API_SQLTABLES); /* 54 */
    if (ci->drivers.lie)
-       SQL_FUNC_ESET(pfExists, SQL_API_SQLBROWSECONNECT); /* 55 not implemented yet */
+       SQL_FUNC_ESET(pfExists, SQL_API_SQLBROWSECONNECT); /* 55 not implmented yet */
    if (ci->drivers.lie)
        SQL_FUNC_ESET(pfExists, SQL_API_SQLCOLUMNPRIVILEGES); /* 56 not implemented yet */ 
    SQL_FUNC_ESET(pfExists, SQL_API_SQLDATASOURCES);    /* 57 */
    SQL_FUNC_ESET(pfExists, SQL_API_SQLALLOCHANDLE);    /* 1001 */
    SQL_FUNC_ESET(pfExists, SQL_API_SQLBINDPARAM);      /* 1002 */
    SQL_FUNC_ESET(pfExists, SQL_API_SQLCLOSECURSOR);    /* 1003 */
-   if (ci->drivers.lie)
-       SQL_FUNC_ESET(pfExists, SQL_API_SQLCOPYDESC); /* 1004 not implemented yet */
+   SQL_FUNC_ESET(pfExists, SQL_API_SQLCOPYDESC);       /* 1004 */
    SQL_FUNC_ESET(pfExists, SQL_API_SQLENDTRAN);        /* 1005 */
    SQL_FUNC_ESET(pfExists, SQL_API_SQLFREEHANDLE);     /* 1006 */
    SQL_FUNC_ESET(pfExists, SQL_API_SQLGETCONNECTATTR); /* 1007 */
 
        if (SQL_SUCCESS == ret && blen * 2 > cbValueMax)
        {
            ret = SQL_SUCCESS_WITH_INFO;
-           Desc_set_error(hdesc, STMT_TRUNCATED, "The buffer was too small for the rgbDesc.");
+           DC_set_error(hdesc, STMT_TRUNCATED, "The buffer was too small for the rgbDesc.");
        }
        if (pcbValue)
            *pcbValue = blen * 2;
 
    mylog("[SQLExecDirectW]");
    stxt = ucs2_to_utf8(StatementText, TextLength, &slen, FALSE);
    ENTER_STMT_CS((StatementClass *) StatementHandle);
-   ret = PGAPI_ExecDirect(StatementHandle, stxt, slen);
+   ret = PGAPI_ExecDirect(StatementHandle, stxt, slen, 0);
    LEAVE_STMT_CS((StatementClass *) StatementHandle);
    if (stxt)
        free(stxt);
 
            if (conn)
                conn->ardOptions.bind_size = vParam;
            if (stmt)
-               SC_get_ARD(stmt)->bind_size = vParam;
+               SC_get_ARDF(stmt)->bind_size = vParam;
            break;
 
        case SQL_CONCURRENCY:
             */
 
            if (stmt && stmt->save_rowset_size <= 0 && stmt->last_fetch_count > 0)
-               stmt->save_rowset_size = SC_get_ARD(stmt)->size_of_rowset_odbc2;
+               stmt->save_rowset_size = SC_get_ARDF(stmt)->size_of_rowset_odbc2;
 
            if (vParam < 1)
            {
            if (conn)
                conn->ardOptions.size_of_rowset_odbc2 = vParam;
            if (stmt)
-               SC_get_ARD(stmt)->size_of_rowset_odbc2 = vParam;
+               SC_get_ARDF(stmt)->size_of_rowset_odbc2 = vParam;
            break;
 
        case SQL_SIMULATE_CURSOR:       /* NOT SUPPORTED */
            break;
 
        case SQL_BIND_TYPE:
-           *((SDWORD *) pvParam) = SC_get_ARD(stmt)->bind_size;
+           *((SDWORD *) pvParam) = SC_get_ARDF(stmt)->bind_size;
            break;
 
        case SQL_CONCURRENCY:   /* NOT REALLY SUPPORTED */
            break;
 
        case SQL_ROWSET_SIZE:
-           *((SDWORD *) pvParam) = SC_get_ARD(stmt)->size_of_rowset_odbc2;
+           *((SDWORD *) pvParam) = SC_get_ARDF(stmt)->size_of_rowset_odbc2;
            break;
 
        case SQL_SIMULATE_CURSOR:       /* NOT SUPPORTED */
 
    ConnectionClass *conn = stmt->hdbc;
    HSTMT       hcol_stmt;
    StatementClass *col_stmt;
-   IRDFields   *irdflds = SC_get_IRD(stmt);
+   IRDFields   *irdflds = SC_get_IRDF(stmt);
    RETCODE     result;
    BOOL        updatable = TRUE;
 
 
 #include "qresult.h"
 #include "pgapifunc.h"
 
-static HSTMT statementHandleFromDescHandle(SQLHDESC, SQLINTEGER *descType); 
 /* SQLError -> SQLDiagRec */
 RETCODE        SQL_API
 PGAPI_GetDiagRec(SQLSMALLINT HandleType, SQLHANDLE Handle,
                    TextLength, 0);
            break;
        case SQL_HANDLE_DESC:
-           ret = PGAPI_StmtError(statementHandleFromDescHandle(Handle, NULL),
-                   RecNumber, Sqlstate, NativeError,
+           ret = PGAPI_DescError(Handle, RecNumber, Sqlstate,
+                   NativeError,
                    MessageText, BufferLength,
                    TextLength, 0);
            break;
 {
    RETCODE     ret = SQL_ERROR, rtn;
    ConnectionClass *conn;
-   SQLHANDLE   stmtHandle;
    StatementClass  *stmt;
    SDWORD      rc;
    SWORD       pcbErrm;
                        *StringLengthPtr = sizeof(SQLINTEGER);
                    ret = SQL_SUCCESS;
                    break;
-               case SQL_DIAG_ROW_NUMBER:
+                                case SQL_DIAG_ROW_NUMBER:
                    *((SQLINTEGER *) DiagInfoPtr) = SQL_ROW_NUMBER_UNKNOWN;
                    if (StringLengthPtr)
                        *StringLengthPtr = sizeof(SQLINTEGER);
                    ret = SQL_SUCCESS;
                    break;
-               case SQL_DIAG_COLUMN_NUMBER:
+                                case SQL_DIAG_COLUMN_NUMBER:
                    *((SQLINTEGER *) DiagInfoPtr) = SQL_COLUMN_NUMBER_UNKNOWN;
                    if (StringLengthPtr)
                        *StringLengthPtr = sizeof(SQLINTEGER);
            }
            break;
        case SQL_HANDLE_DESC:
-           stmtHandle = statementHandleFromDescHandle(Handle, NULL); 
-           conn = (ConnectionClass *) SC_get_conn(((StatementClass *) stmtHandle)); 
+           conn = DC_get_conn(((DescriptorClass *) Handle)); 
            switch (DiagIdentifier)
            {
                case SQL_DIAG_CLASS_ORIGIN:
                case SQL_DIAG_NATIVE:
                case SQL_DIAG_NUMBER:
                case SQL_DIAG_SQLSTATE:
-                   ret = PGAPI_GetDiagField(SQL_HANDLE_STMT,
-                       stmtHandle, RecNumber,
-                       DiagIdentifier, DiagInfoPtr,
-                       BufferLength, StringLengthPtr);
+                   ret = PGAPI_DescError(Handle, RecNumber,
+                                   DiagInfoPtr, NULL, NULL,
+                       0, NULL, 0);
+                   if (StringLengthPtr)  
+                       *StringLengthPtr = 5;
+                   if (SQL_SUCCESS_WITH_INFO == ret)  
+                       ret = SQL_SUCCESS;
                    break;
                case SQL_DIAG_RETURNCODE: /* driver manager returns */
                    break;
 static SQLHDESC
 descHandleFromStatementHandle(HSTMT StatementHandle, SQLINTEGER descType) 
 {
+   StatementClass  *stmt = (StatementClass *) StatementHandle;
+
    switch (descType)
    {
        case SQL_ATTR_APP_ROW_DESC:     /* 10010 */
-           return StatementHandle; /* this is bogus */
-       case SQL_ATTR_APP_PARAM_DESC:   /* 10011 */
-           return (HSTMT) ((SQLUINTEGER) StatementHandle + 1) ; /* this is bogus */
+           return (HSTMT) stmt->ard;
+       case SQL_ATTR_APP_PARAM_DESC:       /* 10011 */
+           return (HSTMT) stmt->apd;
        case SQL_ATTR_IMP_ROW_DESC:     /* 10012 */
-           return (HSTMT) ((SQLUINTEGER) StatementHandle + 2); /* this is bogus */
-       case SQL_ATTR_IMP_PARAM_DESC:   /* 10013 */
-           return (HSTMT) ((SQLUINTEGER) StatementHandle + 3); /* this is bogus */
+           return (HSTMT) stmt->ird;
+       case SQL_ATTR_IMP_PARAM_DESC:       /* 10013 */
+           return (HSTMT) stmt->ipd;
    }
    return (HSTMT) 0;
 }
-static HSTMT
-statementHandleFromDescHandle(SQLHDESC DescHandle, SQLINTEGER *descType) 
-{
-   SQLUINTEGER res = (SQLUINTEGER) DescHandle % 4;
-   if (descType)
-   {
-       switch (res)
-       {
-           case 0: *descType = SQL_ATTR_APP_ROW_DESC; /* 10010 */
-               break;
-           case 1: *descType = SQL_ATTR_APP_PARAM_DESC; /* 10011 */
-               break;
-           case 2: *descType = SQL_ATTR_IMP_ROW_DESC; /* 10012 */
-               break;
-           case 3: *descType = SQL_ATTR_IMP_PARAM_DESC; /* 10013 */
-               break;
-       }
-   }
-   return (HSTMT) ((SQLUINTEGER) DescHandle - res);
-}
-
-void   Desc_set_error(SQLHDESC hdesc, int errornumber, const char *errormsg)
-{
-   SQLINTEGER  descType;
-   HSTMT   hstmt = statementHandleFromDescHandle(hdesc, &descType);
-   StatementClass  *stmt;
-
-   if (!hstmt)
-       return;
-   stmt = (StatementClass *) hstmt;
-   SC_set_error(stmt, errornumber, errormsg);
-}
 
 static  void column_bindings_set(ARDFields *opts, int cols, BOOL maxset)
 {
 }
 
 static RETCODE SQL_API
-ARDSetField(StatementClass *stmt, SQLSMALLINT RecNumber,
+ARDSetField(DescriptorClass *desc, SQLSMALLINT RecNumber,
        SQLSMALLINT FieldIdentifier, PTR Value, SQLINTEGER BufferLength)
 {
    RETCODE     ret = SQL_SUCCESS;
    PTR     tptr;
-   ARDFields   *opts = SC_get_ARD(stmt);
+   ARDFields   *opts = (ARDFields *) (desc + 1);
    SQLSMALLINT row_idx;
 
    switch (FieldIdentifier)
    }
    if (RecNumber < 0 || RecNumber > opts->allocated)
    {
-       SC_set_errornumber(stmt, STMT_INVALID_COLUMN_NUMBER_ERROR);
+       DC_set_error(desc, STMT_INVALID_COLUMN_NUMBER_ERROR, "invalid column number");
        return SQL_ERROR;
    }
    if (0 == RecNumber) /* bookmark column */
    {
+       BindInfoClass   *bookmark = ARD_AllocBookmark(opts);
+
        switch (FieldIdentifier)
        {
            case SQL_DESC_DATA_PTR:
-               opts->bookmark->buffer = Value;
+               bookmark->buffer = Value;
                break;
            case SQL_DESC_INDICATOR_PTR:
-               tptr = opts->bookmark->used;
+               tptr = bookmark->used;
                if (Value != tptr)
                {
-                   SC_set_error(stmt, STMT_INVALID_DESCRIPTOR_IDENTIFIER, "INDICATOR != OCTET_LENGTH_PTR"); 
+                   DC_set_error(desc, STMT_INVALID_DESCRIPTOR_IDENTIFIER, "INDICATOR != OCTET_LENGTH_PTR"); 
                    ret = SQL_ERROR;
                }
                break;
            case SQL_DESC_OCTET_LENGTH_PTR:
-               opts->bookmark->used = Value;
+               bookmark->used = Value;
                break;
            default:
-               SC_set_errornumber(stmt, STMT_INVALID_COLUMN_NUMBER_ERROR);
+               DC_set_error(desc, STMT_INVALID_COLUMN_NUMBER_ERROR, "invalid column number");
                ret = SQL_ERROR;
        }
        return ret;
            if (Value != tptr)
            {
                ret = SQL_ERROR;
-               SC_set_error(stmt, STMT_INVALID_DESCRIPTOR_IDENTIFIER, "INDICATOR != OCTET_LENGTH_PTR"); 
+               DC_set_error(desc, STMT_INVALID_DESCRIPTOR_IDENTIFIER, "INDICATOR != OCTET_LENGTH_PTR"); 
            }
            break;
        case SQL_DESC_OCTET_LENGTH_PTR:
        case SQL_DESC_LENGTH:
        case SQL_DESC_NUM_PREC_RADIX:
        default:ret = SQL_ERROR;
-           SC_set_errornumber(stmt, STMT_INVALID_DESCRIPTOR_IDENTIFIER); 
+           DC_set_error(desc, STMT_INVALID_DESCRIPTOR_IDENTIFIER,
+               "invalid descriptor identifier"); 
    }
    return ret;
 }
 }
 
 static RETCODE SQL_API
-APDSetField(StatementClass *stmt, SQLSMALLINT RecNumber,
+APDSetField(DescriptorClass *desc, SQLSMALLINT RecNumber,
        SQLSMALLINT FieldIdentifier, PTR Value, SQLINTEGER BufferLength)
 {
    RETCODE     ret = SQL_SUCCESS;
-   APDFields   *opts = SC_get_APD(stmt);
+   APDFields   *opts = (APDFields *) (desc + 1);
    SQLSMALLINT para_idx;
 
    switch (FieldIdentifier)
    }
    if (RecNumber <=0 || RecNumber > opts->allocated)
    {
-       SC_set_errornumber(stmt, STMT_BAD_PARAMETER_NUMBER_ERROR);
+       DC_set_error(desc, STMT_BAD_PARAMETER_NUMBER_ERROR,
+               "bad parameter number");
        return SQL_ERROR;
    }
    para_idx = RecNumber - 1; 
            if (Value != opts->parameters[para_idx].used)
            {
                ret = SQL_ERROR;
-               SC_set_error(stmt, STMT_INVALID_DESCRIPTOR_IDENTIFIER, "INDICATOR != OCTET_LENGTH_PTR"); 
+               DC_set_error(desc, STMT_INVALID_DESCRIPTOR_IDENTIFIER, "INDICATOR != OCTET_LENGTH_PTR"); 
            }
            break;
        case SQL_DESC_OCTET_LENGTH:
        case SQL_DESC_LENGTH:
        case SQL_DESC_NUM_PREC_RADIX:
        default:ret = SQL_ERROR;
-           SC_set_errornumber(stmt, STMT_INVALID_DESCRIPTOR_IDENTIFIER); 
+           DC_set_error(desc, STMT_INVALID_DESCRIPTOR_IDENTIFIER,
+               "invaid descriptor identifier"); 
    }
    return ret;
 }
 
 static RETCODE SQL_API
-IRDSetField(StatementClass *stmt, SQLSMALLINT RecNumber,
+IRDSetField(DescriptorClass *desc, SQLSMALLINT RecNumber,
        SQLSMALLINT FieldIdentifier, PTR Value, SQLINTEGER BufferLength)
 {
    RETCODE     ret = SQL_SUCCESS;
-   IRDFields   *opts = SC_get_IRD(stmt);
+   IRDFields   *opts = (IRDFields *) (desc + 1);
 
    switch (FieldIdentifier)
    {
        case SQL_DESC_UNSIGNED: /* read-only */
        case SQL_DESC_UPDATABLE: /* read-only */
        default:ret = SQL_ERROR;
-           SC_set_errornumber(stmt, STMT_INVALID_DESCRIPTOR_IDENTIFIER); 
+           DC_set_error(desc, STMT_INVALID_DESCRIPTOR_IDENTIFIER,
+               "invalid descriptor identifier"); 
    }
    return ret;
 }
 
 static RETCODE SQL_API
-IPDSetField(StatementClass *stmt, SQLSMALLINT RecNumber,
+IPDSetField(DescriptorClass *desc, SQLSMALLINT RecNumber,
        SQLSMALLINT FieldIdentifier, PTR Value, SQLINTEGER BufferLength)
 {
    RETCODE     ret = SQL_SUCCESS;
-   IPDFields   *ipdopts = SC_get_IPD(stmt);
+   IPDFields   *ipdopts = (IPDFields *) (desc + 1);
    SQLSMALLINT para_idx;
 
    switch (FieldIdentifier)
            if (SQL_UNNAMED !=  (SQLUINTEGER) Value)
            {
                ret = SQL_ERROR;
-               SC_set_errornumber(stmt, STMT_INVALID_DESCRIPTOR_IDENTIFIER);
+               DC_set_error(desc, STMT_INVALID_DESCRIPTOR_IDENTIFIER,
+                   "invalid descriptor identifier");
            }
            return ret;
        case SQL_DESC_COUNT:
    }
    if (RecNumber <= 0 || RecNumber > ipdopts->allocated)
    {
-       SC_set_errornumber(stmt, STMT_BAD_PARAMETER_NUMBER_ERROR);
+       DC_set_error(desc, STMT_BAD_PARAMETER_NUMBER_ERROR,
+               "bad parameter number");
        return SQL_ERROR;
    }
    para_idx = RecNumber - 1;
        case SQL_DESC_TYPE_NAME: /* read-only */
        case SQL_DESC_UNSIGNED: /* read-only */
        default:ret = SQL_ERROR;
-           SC_set_errornumber(stmt, STMT_INVALID_DESCRIPTOR_IDENTIFIER); 
+           DC_set_error(desc, STMT_INVALID_DESCRIPTOR_IDENTIFIER,
+               "invalid descriptor identifier"); 
    }
    return ret;
 }
 
 
 static RETCODE SQL_API
-ARDGetField(StatementClass *stmt, SQLSMALLINT RecNumber,
+ARDGetField(DescriptorClass *desc, SQLSMALLINT RecNumber,
        SQLSMALLINT FieldIdentifier, PTR Value, SQLINTEGER BufferLength,
        SQLINTEGER *StringLength)
 {
    RETCODE     ret = SQL_SUCCESS;
    SQLINTEGER  len, ival, rettype = 0;
    PTR     ptr = NULL;
-   const ARDFields *opts = SC_get_ARD(stmt);
+   const ARDFields *opts = (ARDFields *) (desc + 1);
    SQLSMALLINT row_idx;
 
    len = 4;
    if (0 == RecNumber) /* bookmark */
    {
+       BindInfoClass   *bookmark = opts->bookmark;
        switch (FieldIdentifier)
        {
            case SQL_DESC_DATA_PTR:
                rettype = SQL_IS_POINTER;
-               ptr = opts->bookmark->buffer;
+               ptr = bookmark ? bookmark->buffer : NULL;
                break;
            case SQL_DESC_INDICATOR_PTR:
                rettype = SQL_IS_POINTER;
-               ptr = opts->bookmark->used;
+               ptr = bookmark ? bookmark->used : NULL;
                break;
            case SQL_DESC_OCTET_LENGTH_PTR:
                rettype = SQL_IS_POINTER;
-               ptr = opts->bookmark->used;
+               ptr = bookmark ? bookmark->used : NULL;
                break;
        }
        if (ptr)
        default:
            if (RecNumber <= 0 || RecNumber > opts->allocated)
            {
-               SC_set_errornumber(stmt, STMT_INVALID_COLUMN_NUMBER_ERROR);
+               DC_set_error(desc, STMT_INVALID_COLUMN_NUMBER_ERROR,
+                   "invalid column number");
                return SQL_ERROR;
            }
    }
            ival = opts->bindings[row_idx].buflen;
            break;
        case SQL_DESC_ALLOC_TYPE: /* read-only */
-           ival = SQL_DESC_ALLOC_AUTO;
+           if (desc->embedded)
+               ival = SQL_DESC_ALLOC_AUTO;
+           else
+               ival = SQL_DESC_ALLOC_USER;
            break;
        case SQL_DESC_PRECISION:
            ival = opts->bindings[row_idx].precision;
        case SQL_DESC_DATETIME_INTERVAL_PRECISION:
        case SQL_DESC_LENGTH:
        default:ret = SQL_ERROR;
-           SC_set_errornumber(stmt, STMT_INVALID_DESCRIPTOR_IDENTIFIER); 
+           DC_set_error(desc, STMT_INVALID_DESCRIPTOR_IDENTIFIER,
+               "invalid descriptor identifier"); 
    }
    switch (rettype)
    {
 }
 
 static RETCODE SQL_API
-APDGetField(StatementClass *stmt, SQLSMALLINT RecNumber,
+APDGetField(DescriptorClass *desc, SQLSMALLINT RecNumber,
        SQLSMALLINT FieldIdentifier, PTR Value, SQLINTEGER BufferLength,
        SQLINTEGER *StringLength)
 {
    RETCODE     ret = SQL_SUCCESS;
    SQLINTEGER  ival = 0, len, rettype = 0;
    PTR     ptr = NULL;
-   const APDFields *opts = SC_get_APD(stmt);
+   const APDFields *opts = (const APDFields *) (desc + 1);
    SQLSMALLINT para_idx;
 
    len = 4;
            break; 
        default:if (RecNumber <= 0 || RecNumber > opts->allocated)
            {
-               SC_set_errornumber(stmt, STMT_BAD_PARAMETER_NUMBER_ERROR);
+               DC_set_error(desc, STMT_BAD_PARAMETER_NUMBER_ERROR,
+                   "bad parameter number");
                return SQL_ERROR;
            } 
    }
            ival = opts->allocated;
            break; 
        case SQL_DESC_ALLOC_TYPE: /* read-only */
-           ival = SQL_DESC_ALLOC_AUTO;
+           if (desc->embedded)
+               ival = SQL_DESC_ALLOC_AUTO;
+           else
+               ival = SQL_DESC_ALLOC_USER;
            break;
        case SQL_DESC_NUM_PREC_RADIX:
            ival = 10;
        case SQL_DESC_DATETIME_INTERVAL_PRECISION:
        case SQL_DESC_LENGTH:
        default:ret = SQL_ERROR;
-           SC_set_errornumber(stmt, STMT_INVALID_DESCRIPTOR_IDENTIFIER); 
+           DC_set_error(desc, STMT_INVALID_DESCRIPTOR_IDENTIFIER,
+                   "invalid descriptor identifer"); 
    }
    switch (rettype)
    {
 }
 
 static RETCODE SQL_API
-IRDGetField(StatementClass *stmt, SQLSMALLINT RecNumber,
+IRDGetField(DescriptorClass *desc, SQLSMALLINT RecNumber,
        SQLSMALLINT FieldIdentifier, PTR Value, SQLINTEGER BufferLength,
        SQLINTEGER *StringLength)
 {
    SQLINTEGER  ival = 0, len, rettype = 0;
    PTR     ptr = NULL;
    BOOL        bCallColAtt = FALSE;
-   const IRDFields *opts = SC_get_IRD(stmt);
+   const IRDFields *opts = (IRDFields *) (desc + 1);
 
    switch (FieldIdentifier)
    {
            bCallColAtt = TRUE;
            break; 
        default:ret = SQL_ERROR;
-           SC_set_errornumber(stmt, STMT_INVALID_DESCRIPTOR_IDENTIFIER); 
+           DC_set_error(desc, STMT_INVALID_DESCRIPTOR_IDENTIFIER,
+               "invalid descriptor identifier"); 
    }
    if (bCallColAtt)
    {
        SQLSMALLINT pcbL;
+       StatementClass  *stmt;
 
+       stmt = opts->stmt;
        ret = PGAPI_ColAttributes(stmt, RecNumber,
            FieldIdentifier, Value, (SQLSMALLINT) BufferLength,
                &pcbL, &ival);
 }
 
 static RETCODE SQL_API
-IPDGetField(StatementClass *stmt, SQLSMALLINT RecNumber,
+IPDGetField(DescriptorClass *desc, SQLSMALLINT RecNumber,
        SQLSMALLINT FieldIdentifier, PTR Value, SQLINTEGER BufferLength,
        SQLINTEGER *StringLength)
 {
    RETCODE     ret = SQL_SUCCESS;
    SQLINTEGER  ival = 0, len, rettype = 0;
    PTR     ptr = NULL;
-   const IPDFields *ipdopts = SC_get_IPD(stmt);
+   const IPDFields *ipdopts = (const IPDFields *) (desc + 1);
    SQLSMALLINT para_idx;
 
    switch (FieldIdentifier)
            break; 
        default:if (RecNumber <= 0 || RecNumber > ipdopts->allocated)
            {
-               SC_set_errornumber(stmt, STMT_BAD_PARAMETER_NUMBER_ERROR);
+               DC_set_error(desc, STMT_BAD_PARAMETER_NUMBER_ERROR,
+                   "bad parameter number");
                return SQL_ERROR;
            }
    }
        case SQL_DESC_TYPE_NAME: /* read-only */
        case SQL_DESC_UNSIGNED: /* read-only */
        default:ret = SQL_ERROR;
-           SC_set_errornumber(stmt, STMT_INVALID_DESCRIPTOR_IDENTIFIER); 
+           DC_set_error(desc, STMT_INVALID_DESCRIPTOR_IDENTIFIER,
+               "invalid descriptor identifier"); 
    }
    switch (rettype)
    {
            len = 4;
            break;
        case SQL_ATTR_PARAM_BIND_OFFSET_PTR:    /* 17 */
-           *((SQLUINTEGER **) Value) = SC_get_APD(stmt)->param_offset_ptr;
+           *((SQLUINTEGER **) Value) = SC_get_APDF(stmt)->param_offset_ptr;
            len = 4;
            break;
        case SQL_ATTR_PARAM_BIND_TYPE:  /* 18 */
-           *((SQLUINTEGER *) Value) = SC_get_APD(stmt)->param_bind_type;
+           *((SQLUINTEGER *) Value) = SC_get_APDF(stmt)->param_bind_type;
            len = 4;
            break;
        case SQL_ATTR_PARAM_OPERATION_PTR:      /* 19 */
-           *((SQLUSMALLINT **) Value) = SC_get_APD(stmt)->param_operation_ptr;
+           *((SQLUSMALLINT **) Value) = SC_get_APDF(stmt)->param_operation_ptr;
            len = 4;
            break;
        case SQL_ATTR_PARAM_STATUS_PTR: /* 20 */
-           *((SQLUSMALLINT **) Value) = SC_get_IPD(stmt)->param_status_ptr;
+           *((SQLUSMALLINT **) Value) = SC_get_IPDF(stmt)->param_status_ptr;
            len = 4;
            break;
        case SQL_ATTR_PARAMS_PROCESSED_PTR:     /* 21 */
-           *((SQLUINTEGER **) Value) = SC_get_IPD(stmt)->param_processed_ptr;
+           *((SQLUINTEGER **) Value) = SC_get_IPDF(stmt)->param_processed_ptr;
            len = 4;
            break;
        case SQL_ATTR_PARAMSET_SIZE:    /* 22 */
-           *((SQLUINTEGER *) Value) = SC_get_APD(stmt)->paramset_size;
+           *((SQLUINTEGER *) Value) = SC_get_APDF(stmt)->paramset_size;
            len = 4;
            break;
        case SQL_ATTR_ROW_BIND_OFFSET_PTR:      /* 23 */
-           *((SQLUINTEGER **) Value) = SC_get_ARD(stmt)->row_offset_ptr;
+           *((SQLUINTEGER **) Value) = SC_get_ARDF(stmt)->row_offset_ptr;
            len = 4;
            break;
        case SQL_ATTR_ROW_OPERATION_PTR:        /* 24 */
-           *((SQLUSMALLINT **) Value) = SC_get_ARD(stmt)->row_operation_ptr;
+           *((SQLUSMALLINT **) Value) = SC_get_ARDF(stmt)->row_operation_ptr;
            len = 4;
            break;
        case SQL_ATTR_ROW_STATUS_PTR:   /* 25 */
-           *((SQLUSMALLINT **) Value) = SC_get_IRD(stmt)->rowStatusArray;
+           *((SQLUSMALLINT **) Value) = SC_get_IRDF(stmt)->rowStatusArray;
            len = 4;
            break;
        case SQL_ATTR_ROWS_FETCHED_PTR: /* 26 */
-           *((SQLUINTEGER **) Value) = SC_get_IRD(stmt)->rowsFetched;
+           *((SQLUINTEGER **) Value) = SC_get_IRDF(stmt)->rowsFetched;
            len = 4;
            break;
        case SQL_ATTR_ROW_ARRAY_SIZE:   /* 27 */
-           *((SQLUINTEGER *) Value) = SC_get_ARD(stmt)->size_of_rowset;
+           *((SQLUINTEGER *) Value) = SC_get_ARDF(stmt)->size_of_rowset;
            len = 4;
            break;
        case SQL_ATTR_APP_ROW_DESC:     /* 10010 */
            PTR Value, SQLINTEGER BufferLength,
            SQLINTEGER *StringLength)
 {
-   RETCODE     ret = SQL_SUCCESS;
-   HSTMT       hstmt;
-   SQLUINTEGER descType;
-   StatementClass *stmt;
    CSTR func = "PGAPI_GetDescField";
+   RETCODE     ret = SQL_SUCCESS;
+   DescriptorClass *desc = (DescriptorClass *) DescriptorHandle;
 
    mylog("%s h=%u rec=%d field=%d blen=%d\n", func, DescriptorHandle, RecNumber, FieldIdentifier, BufferLength);
-   hstmt = statementHandleFromDescHandle(DescriptorHandle, &descType);
-   mylog("stmt=%x type=%d\n", hstmt, descType);
-   stmt = (StatementClass *) hstmt;
-   switch (descType)
+   switch (desc->desc_type)
    {
        case SQL_ATTR_APP_ROW_DESC:
-           ret = ARDGetField(stmt, RecNumber, FieldIdentifier, Value, BufferLength, StringLength);
+           ret = ARDGetField(desc, RecNumber, FieldIdentifier, Value, BufferLength, StringLength);
            break;
        case SQL_ATTR_APP_PARAM_DESC:
-           ret = APDGetField(stmt, RecNumber, FieldIdentifier, Value, BufferLength, StringLength);
+           ret = APDGetField(desc, RecNumber, FieldIdentifier, Value, BufferLength, StringLength);
            break;
        case SQL_ATTR_IMP_ROW_DESC:
-           ret = IRDGetField(stmt, RecNumber, FieldIdentifier, Value, BufferLength, StringLength);
+           ret = IRDGetField(desc, RecNumber, FieldIdentifier, Value, BufferLength, StringLength);
            break;
        case SQL_ATTR_IMP_PARAM_DESC:
-           ret = IPDGetField(stmt, RecNumber, FieldIdentifier, Value, BufferLength, StringLength);
+           ret = IPDGetField(desc, RecNumber, FieldIdentifier, Value, BufferLength, StringLength);
            break;
        default:ret = SQL_ERROR;
-           SC_set_error(stmt, STMT_INTERNAL_ERROR, "Error not implemented");
+           DC_set_error(desc, STMT_INTERNAL_ERROR, "Error not implemented");
    }
    if (ret == SQL_ERROR)
    {
-       if (!SC_get_errormsg(stmt))
+       if (!DC_get_errormsg(desc))
        {
-           switch (SC_get_errornumber(stmt))
+           switch (DC_get_errornumber(desc))
            {
                case STMT_INVALID_DESCRIPTOR_IDENTIFIER:
-                   SC_set_errormsg(stmt, "can't SQLGetDescField for this descriptor identifier");
+                   DC_set_errormsg(desc, "can't SQLGetDescField for this descriptor identifier");
                    break;
                case STMT_INVALID_COLUMN_NUMBER_ERROR:
-                   SC_set_errormsg(stmt, "can't SQLGetDescField for this column number");
+                   DC_set_errormsg(desc, "can't SQLGetDescField for this column number");
                    break;
                case STMT_BAD_PARAMETER_NUMBER_ERROR:
-                   SC_set_errormsg(stmt, "can't SQLGetDescField for this parameter number");
+                   DC_set_errormsg(desc, "can't SQLGetDescField for this parameter number");
                    break;
            }
        } 
-       SC_log_error(func, "", stmt);
+       DC_log_error(func, "", desc);
    }
    return ret;
 }
            SQLSMALLINT RecNumber, SQLSMALLINT FieldIdentifier,
            PTR Value, SQLINTEGER BufferLength)
 {
-   RETCODE     ret = SQL_SUCCESS;
-   HSTMT       hstmt;
-   SQLUINTEGER descType;
-   StatementClass *stmt;
    CSTR func = "PGAPI_SetDescField";
+   RETCODE     ret = SQL_SUCCESS;
+   DescriptorClass *desc = (DescriptorClass *) DescriptorHandle;
 
    mylog("%s h=%u rec=%d field=%d val=%x,%d\n", func, DescriptorHandle, RecNumber, FieldIdentifier, Value, BufferLength);
-   hstmt = statementHandleFromDescHandle(DescriptorHandle, &descType);
-   mylog("stmt=%x type=%d\n", hstmt, descType);
-   stmt = (StatementClass *) hstmt;
-   switch (descType)
+   switch (desc->desc_type)
    {
        case SQL_ATTR_APP_ROW_DESC:
-           ret = ARDSetField(stmt, RecNumber, FieldIdentifier, Value, BufferLength);
+           ret = ARDSetField(desc, RecNumber, FieldIdentifier, Value, BufferLength);
            break;
        case SQL_ATTR_APP_PARAM_DESC:
-           ret = APDSetField(stmt, RecNumber, FieldIdentifier, Value, BufferLength);
+           ret = APDSetField(desc, RecNumber, FieldIdentifier, Value, BufferLength);
            break;
        case SQL_ATTR_IMP_ROW_DESC:
-           ret = IRDSetField(stmt, RecNumber, FieldIdentifier, Value, BufferLength);
+           ret = IRDSetField(desc, RecNumber, FieldIdentifier, Value, BufferLength);
            break;
        case SQL_ATTR_IMP_PARAM_DESC:
-           ret = IPDSetField(stmt, RecNumber, FieldIdentifier, Value, BufferLength);
+           ret = IPDSetField(desc, RecNumber, FieldIdentifier, Value, BufferLength);
            break;
        default:ret = SQL_ERROR;
-           SC_set_error(stmt, STMT_INTERNAL_ERROR, "Error not implemented");
+           DC_set_error(desc, STMT_INTERNAL_ERROR, "Error not implemented");
    }
    if (ret == SQL_ERROR)
    {
-       if (!SC_get_errormsg(stmt))
+       if (!DC_get_errormsg(desc))
        {
-           switch (SC_get_errornumber(stmt))
+           switch (DC_get_errornumber(desc))
            {
                case STMT_INVALID_DESCRIPTOR_IDENTIFIER:
-                   SC_set_errormsg(stmt, "can't SQLSetDescField for this descriptor identifier");
+                   DC_set_errormsg(desc, "can't SQLSetDescField for this descriptor identifier");
                case STMT_INVALID_COLUMN_NUMBER_ERROR:
-                   SC_set_errormsg(stmt, "can't SQLSetDescField for this column number");
+                   DC_set_errormsg(desc, "can't SQLSetDescField for this column number");
                    break;
                case STMT_BAD_PARAMETER_NUMBER_ERROR:
-                   SC_set_errormsg(stmt, "can't SQLSetDescField for this parameter number");
+                   DC_set_errormsg(desc, "can't SQLSetDescField for this parameter number");
                    break;
                break;
            }
        } 
-       SC_log_error(func, "", stmt);
+       DC_log_error(func, "", desc);
    }
    return ret;
 }
        SQLINTEGER Attribute, PTR Value,
        SQLINTEGER StringLength)
 {
+   RETCODE ret = SQL_SUCCESS;
    CSTR func = "PGAPI_SetStmtAttr";
    StatementClass *stmt = (StatementClass *) StatementHandle;
 
 
        case SQL_ATTR_ENABLE_AUTO_IPD:  /* 15 */
 
-       case SQL_ATTR_APP_ROW_DESC:     /* 10010 */
-       case SQL_ATTR_APP_PARAM_DESC:   /* 10011 */
        case SQL_ATTR_AUTO_IPD: /* 10001 */
        /* case SQL_ATTR_ROW_BIND_TYPE: ** == SQL_BIND_TYPE(ODBC2.0) */
        case SQL_ATTR_IMP_ROW_DESC: /* 10012 (read-only) */
            return SQL_ERROR;
 
        case SQL_ATTR_METADATA_ID:      /* 10014 */
-           stmt->options.metadata_id = (SQLUINTEGER) Value;
+           stmt->options.metadata_id = (SQLUINTEGER) Value; 
+           break;
+       case SQL_ATTR_APP_ROW_DESC:     /* 10010 */
+           if (SQL_NULL_HDESC == Value)
+           {
+               stmt->ard = &(stmt->ardi);
+           }
+           else
+           { 
+               stmt->ard = (ARDClass *) Value;
+           }
+           break;
+       case SQL_ATTR_APP_PARAM_DESC:   /* 10011 */
+           if (SQL_NULL_HDESC == Value)
+           {
+               stmt->apd = &(stmt->apdi);
+           }
+           else
+           { 
+               stmt->apd = (APDClass *) Value;
+           }
            break;
        case SQL_ATTR_FETCH_BOOKMARK_PTR:       /* 16 */
            stmt->options.bookmark_ptr = Value;
            break;
        case SQL_ATTR_PARAM_BIND_OFFSET_PTR:    /* 17 */
-           SC_get_APD(stmt)->param_offset_ptr = (SQLUINTEGER *) Value;
+           SC_get_APDF(stmt)->param_offset_ptr = (SQLUINTEGER *) Value;
            break;
        case SQL_ATTR_PARAM_BIND_TYPE:  /* 18 */
-           SC_get_APD(stmt)->param_bind_type = (SQLUINTEGER) Value;
+           SC_get_APDF(stmt)->param_bind_type = (SQLUINTEGER) Value;
            break;
        case SQL_ATTR_PARAM_OPERATION_PTR:      /* 19 */
-           SC_get_APD(stmt)->param_operation_ptr = Value;
+           SC_get_APDF(stmt)->param_operation_ptr = Value;
            break;
        case SQL_ATTR_PARAM_STATUS_PTR:         /* 20 */
-           SC_get_IPD(stmt)->param_status_ptr = (SQLUSMALLINT *) Value;
+           SC_get_IPDF(stmt)->param_status_ptr = (SQLUSMALLINT *) Value;
            break;
        case SQL_ATTR_PARAMS_PROCESSED_PTR:     /* 21 */
-           SC_get_IPD(stmt)->param_processed_ptr = (SQLUINTEGER *) Value;
+           SC_get_IPDF(stmt)->param_processed_ptr = (SQLUINTEGER *) Value;
            break;
        case SQL_ATTR_PARAMSET_SIZE:    /* 22 */
-           SC_get_APD(stmt)->paramset_size = (SQLUINTEGER) Value;
+           SC_get_APDF(stmt)->paramset_size = (SQLUINTEGER) Value;
            break;
        case SQL_ATTR_ROW_BIND_OFFSET_PTR:      /* 23 */
-           SC_get_ARD(stmt)->row_offset_ptr = (SQLUINTEGER *) Value;
+           SC_get_ARDF(stmt)->row_offset_ptr = (SQLUINTEGER *) Value;
            break;
        case SQL_ATTR_ROW_OPERATION_PTR:        /* 24 */
-           SC_get_ARD(stmt)->row_operation_ptr = Value;
+           SC_get_ARDF(stmt)->row_operation_ptr = Value;
            break;
        case SQL_ATTR_ROW_STATUS_PTR:   /* 25 */
-           SC_get_IRD(stmt)->rowStatusArray = (SQLUSMALLINT *) Value;
+           SC_get_IRDF(stmt)->rowStatusArray = (SQLUSMALLINT *) Value;
            break;
        case SQL_ATTR_ROWS_FETCHED_PTR: /* 26 */
-           SC_get_IRD(stmt)->rowsFetched = (SQLUINTEGER *) Value;
+           SC_get_IRDF(stmt)->rowsFetched = (SQLUINTEGER *) Value;
            break;
        case SQL_ATTR_ROW_ARRAY_SIZE:   /* 27 */
-           SC_get_ARD(stmt)->size_of_rowset = (SQLUINTEGER) Value;
+           SC_get_ARDF(stmt)->size_of_rowset = (SQLUINTEGER) Value;
            break;
        default:
            return PGAPI_SetStmtOption(StatementHandle, (UWORD) Attribute, (UDWORD) Value);
    (book->buffer + offset + \
    (bind_size > 0 ? bind_size : (SQL_C_VARBOOKMARK == book->returntype ? book->buflen : sizeof(UInt4))) * index)       
 
-RETCODE    SQL_API
-PGAPI_BulkOperations(HSTMT hstmt, SQLSMALLINT operation)
+/* SQL_NEED_DATA callback for PGAPI_BulkOperations */
+typedef struct
 {
-   CSTR func = "PGAPI_BulkOperations";
-   StatementClass  *stmt = (StatementClass *) hstmt;
-   ARDFields   *opts = SC_get_ARD(stmt);
-   RETCODE     ret;
-   UInt4       offset, bind_size = opts->bind_size,
-           global_idx;
-   int     i, processed;
+   StatementClass  *stmt;
+   SQLSMALLINT operation;
+   char        need_data_callback;
+   char        auto_commit_needed;
+   ARDFields   *opts;
+   int     idx, processed;
+}  bop_cdata;
+
+static 
+RETCODE    bulk_ope_callback(RETCODE retcode, bop_cdata *s)
+{
+   RETCODE ret = retcode;
+   UInt4       offset, bind_size, global_idx;
    ConnectionClass *conn;
-   BOOL        auto_commit_needed = FALSE;
    QResultClass    *res;
+   IRDFields   *irdflds;
    BindInfoClass   *bookmark;
 
-   mylog("%s operation = %d\n", func, operation);
-   SC_clear_error(stmt);
-   offset = opts->row_offset_ptr ? *opts->row_offset_ptr : 0;
-   
-   if (SQL_FETCH_BY_BOOKMARK != operation)
+   if (s->need_data_callback)
    {
-       conn = SC_get_conn(stmt);
-       if (auto_commit_needed = CC_is_in_autocommit(conn), auto_commit_needed)
-           PGAPI_SetConnectOption(conn, SQL_AUTOCOMMIT, SQL_AUTOCOMMIT_OFF);
+       mylog("bulk_ope_callback in\n");
+       s->processed++;
+       s->idx++;
    }
-   if (SQL_ADD != operation)
+   else
    {
-       if (!(bookmark = opts->bookmark) || !(bookmark->buffer))
-       {
-           SC_set_error(stmt, STMT_INVALID_OPTION_IDENTIFIER, "bookmark isn't specified");
-           return SQL_ERROR;
-       }
+       s->idx = s->processed = 0;
    }
-   for (i = 0, processed = 0; i < opts->size_of_rowset; i++)
+   s->need_data_callback = FALSE;
+   bookmark = s->opts->bookmark;
+   offset = s->opts->row_offset_ptr ? *(s->opts->row_offset_ptr) : 0;
+   bind_size = s->opts->bind_size;
+   for (; SQL_ERROR != ret && s->idx < s->opts->size_of_rowset; s->idx++)
    {
-       if (SQL_ADD != operation)
+       if (SQL_ADD != s->operation)
        {
-           memcpy(&global_idx, CALC_BOOKMARK_ADDR(bookmark, offset, bind_size, i), sizeof(UInt4));
+           memcpy(&global_idx, CALC_BOOKMARK_ADDR(bookmark, offset, bind_size, s->idx), sizeof(UInt4));
            global_idx--;
        }
        /* Note opts->row_operation_ptr is ignored */
-       switch (operation)
+       switch (s->operation)
        {
            case SQL_ADD:
-               ret = SC_pos_add(stmt, (UWORD) i);
+               ret = SC_pos_add(s->stmt, (UWORD) s->idx);
                break;
            case SQL_UPDATE_BY_BOOKMARK:
-               ret = SC_pos_update(stmt, (UWORD) i, global_idx);
+               ret = SC_pos_update(s->stmt, (UWORD) s->idx, global_idx);
                break;
            case SQL_DELETE_BY_BOOKMARK:
-               ret = SC_pos_delete(stmt, (UWORD) i, global_idx);
+               ret = SC_pos_delete(s->stmt, (UWORD) s->idx, global_idx);
                break;
            case SQL_FETCH_BY_BOOKMARK:
-               ret = SC_pos_refresh(stmt, (UWORD) i, global_idx);
+               ret = SC_pos_refresh(s->stmt, (UWORD) s->idx, global_idx);
                break;
        }
-       processed++;
-       if (SQL_ERROR == ret)
-           break;
+       if (SQL_NEED_DATA == ret)
+       {
+           bop_cdata *cbdata = (bop_cdata *) malloc(sizeof(bop_cdata));
+           memcpy(cbdata, s, sizeof(bop_cdata));
+           cbdata->need_data_callback = TRUE;
+           enqueueNeedDataCallback(s->stmt, bulk_ope_callback, cbdata);
+           return ret;
+       }
+       s->processed++;
    }
-   if (auto_commit_needed)
+   conn = SC_get_conn(s->stmt);
+   if (s->auto_commit_needed)
        PGAPI_SetConnectOption(conn, SQL_AUTOCOMMIT, SQL_AUTOCOMMIT_ON);
-   if (SC_get_IRD(stmt)->rowsFetched)
-       *(SC_get_IRD(stmt)->rowsFetched) = processed;
+   irdflds = SC_get_IRDF(s->stmt);
+   if (irdflds->rowsFetched)
+       *(irdflds->rowsFetched) = s->processed;
+
+   if (res = SC_get_Curres(s->stmt), res)
+       res->recent_processed_row_count = s->stmt->diag_row_count = s->processed;
+   return ret;
+}
+
+RETCODE    SQL_API
+PGAPI_BulkOperations(HSTMT hstmt, SQLSMALLINT operationX)
+{
+   CSTR func = "PGAPI_BulkOperations";
+   bop_cdata   s;
+   RETCODE     ret;
+   ConnectionClass *conn;
+   BindInfoClass   *bookmark;
+
+   mylog("%s operation = %d\n", func, operationX);
+   s.stmt = (StatementClass *) hstmt;
+   s.operation = operationX;
+   SC_clear_error(s.stmt);
+   s.opts = SC_get_ARDF(s.stmt);
+   
+   s.auto_commit_needed = FALSE;
+   if (SQL_FETCH_BY_BOOKMARK != s.operation)
+   {
+       conn = SC_get_conn(s.stmt);
+       if (s.auto_commit_needed = (char) CC_is_in_autocommit(conn), s.auto_commit_needed)
+           PGAPI_SetConnectOption(conn, SQL_AUTOCOMMIT, SQL_AUTOCOMMIT_OFF);
+   }
+   if (SQL_ADD != s.operation)
+   {
+       if (!(bookmark = s.opts->bookmark) || !(bookmark->buffer))
+       {
+           SC_set_error(s.stmt, STMT_INVALID_OPTION_IDENTIFIER, "bookmark isn't specified");
+           return SQL_ERROR;
+       }
+   }
 
-   if (res = SC_get_Curres(stmt), res)
-       res->recent_processed_row_count = stmt->diag_row_count = processed;
+   s.need_data_callback = FALSE;
+   ret = bulk_ope_callback(SQL_SUCCESS, &s);
    return ret;
 }  
 #endif /* DRIVER_CURSOR_IMPLEMENT */
 
 
 /* Internal flags for catalog functions */
 #define    PODBC_NOT_SEARCH_PATTERN    1L
+/* Internal flags for PGAPI_Exec... functions */
+#define    PODBC_WITH_HOLD         1L
 /* Flags for the error handling */
 #define    PODBC_ALLOW_PARTIAL_EXTRACT 1L
 #define    PODBC_ERROR_CLEAR       (1L << 1)
            SQLSMALLINT *TextLength, UWORD flag);
 
 RETCODE SQL_API PGAPI_ExecDirect(HSTMT StatementHandle,
-                SQLCHAR *StatementText, SQLINTEGER TextLength);
-RETCODE SQL_API PGAPI_Execute(HSTMT StatementHandle);
+       SQLCHAR *StatementText, SQLINTEGER TextLength, UWORD flag);
+RETCODE SQL_API PGAPI_Execute(HSTMT StatementHandle, UWORD flag);
 RETCODE SQL_API PGAPI_Fetch(HSTMT StatementHandle);
 RETCODE SQL_API PGAPI_FreeConnect(HDBC ConnectionHandle);
 RETCODE SQL_API PGAPI_FreeEnv(HENV EnvironmentHandle);
        SQLINTEGER StringLength);
 RETCODE SQL_API PGAPI_BulkOperations(HSTMT StatementHandle,
            SQLSMALLINT operation);
+RETCODE SQL_API PGAPI_AllocDesc(HDBC ConnectionHandle,
+               SQLHDESC *DescriptorHandle);
+RETCODE SQL_API PGAPI_FreeDesc(SQLHDESC DescriptorHandle);
+RETCODE SQL_API PGAPI_CopyDesc(SQLHDESC SourceDescHandle,
+               SQLHDESC TargetDescHandle);
 RETCODE SQL_API PGAPI_SetDescField(SQLHDESC DescriptorHandle,
            SQLSMALLINT RecNumber, SQLSMALLINT FieldIdentifier,
            PTR Value, SQLINTEGER BufferLength);
 RETCODE SQL_API PGAPI_GetDescField(SQLHDESC DescriptorHandle,
            SQLSMALLINT RecNumber, SQLSMALLINT FieldIdentifier,
            PTR Value, SQLINTEGER BufferLength, SQLINTEGER *StringLength);
+RETCODE SQL_API PGAPI_DescError(SQLHDESC DescriptorHandle, SWORD RecNumber,
+           SQLCHAR *Sqlstate, SQLINTEGER *NativeError,
+           SQLCHAR *MessageText, SQLSMALLINT BufferLength,
+           SQLSMALLINT *TextLength, UWORD flag);
 #endif /* ODBCVER */
 #endif   /* define_PG_API_FUNC_H__ */
 
  *
  * Comments:       See "notice.txt" for copyright and license information.
  *
- * $Id: psqlodbc.h,v 1.78 2003/08/27 10:17:53 hinoue Exp $
+ * $Id: psqlodbc.h,v 1.79 2003/10/25 04:19:22 hinoue Exp $
  *
  */
 
 #define snprintf _snprintf
 #endif
 
+#ifndef    SQL_ATTR_APP_ROW_DESC
+#define    SQL_ATTR_APP_ROW_DESC   10010
+#endif
+#ifndef    SQL_ATTR_APP_PARAM_DESC
+#define    SQL_ATTR_APP_PARAM_DESC 10011
+#endif
+#ifndef    SQL_ATTR_IMP_ROW_DESC
+#define    SQL_ATTR_IMP_ROW_DESC   10012
+#endif
+#ifndef    SQL_ATTR_IMP_PARAM_DESC
+#define    SQL_ATTR_IMP_PARAM_DESC 10013
+#endif
+
 /* Driver stuff */
 
 #define DRIVERNAME             "PostgreSQL ODBC"
    char       *cursor;
 } QueryInfo;
 
+/* Used to save the error information */
+typedef struct
+{
+        SDWORD  status;
+        SDWORD  errorsize;
+        SWORD   recsize;
+        SWORD   errorpos;
+        char    sqlstate[8];
+        Int4    diag_row_count;
+        char    __error_message[1];
+}       PG_ErrorInfo;
+PG_ErrorInfo   *ER_Constructor(SDWORD errornumber, const char *errormsg);
+void ER_Destructor(PG_ErrorInfo *);
+RETCODE SQL_API ER_ReturnError(PG_ErrorInfo *, SWORD, UCHAR FAR *,
+           SDWORD FAR *, UCHAR FAR *, SWORD, SWORD FAR *, UWORD);
+
 void       logs_on_off(int cnopen, int, int);
 
 #define PG_TYPE_LO_UNDEFINED           (-999)      /* hack until permanent
 
        if (stmt->parse_status != STMT_PARSE_FATAL)
        {
            parse_ok = TRUE;
-           *pccol = SC_get_IRD(stmt)->nfields;
+           *pccol = SC_get_IRDF(stmt)->nfields;
            mylog("PARSE: PGAPI_NumResultCols: *pccol = %d\n", *pccol);
        }
    }
 
    SC_clear_error(stmt);
 
-   irdflds = SC_get_IRD(stmt);
+   irdflds = SC_get_IRDF(stmt);
 #if (ODBCVER >= 0x0300)
    if (0 == icol) /* bookmark column */
    {
 
    if (pcbDesc)
        *pcbDesc = 0;
-   irdflds = SC_get_IRD(stmt);
+   irdflds = SC_get_IRDF(stmt);
    conn = SC_get_conn(stmt);
    ci = &(conn->connInfo);
 
    StatementClass *stmt = (StatementClass *) hstmt;
    ARDFields   *opts;
    QResultClass *res;
+   BindInfoClass   *bookmark;
 
    mylog("PGAPI_Fetch: stmt = %u, stmt->result= %u\n", stmt, SC_get_Curres(stmt));
 
    }
 
    /* Not allowed to bind a bookmark column when using SQLFetch. */
-   opts = SC_get_ARD(stmt);
-   if (opts->bookmark->buffer)
+   opts = SC_get_ARDF(stmt);
+   if ((bookmark = opts->bookmark) && bookmark->buffer)
    {
        SC_set_error(stmt, STMT_COLNUM_ERROR, "Not allowed to bind a bookmark column when using PGAPI_Fetch");
        SC_log_error(func, "", stmt);
    StatementClass *stmt = (StatementClass *) hstmt;
    ARDFields   *opts;
    QResultClass *res;
+   BindInfoClass   *bookmark;
    int         num_tuples,
                i,
                save_rowset_size,
        return SQL_ERROR;
    }
 
-   opts = SC_get_ARD(stmt);
+   opts = SC_get_ARDF(stmt);
    /*
     * If a bookmark colunmn is bound but bookmark usage is off, then
     * error
     */
-   if (opts->bookmark->buffer && stmt->options.use_bookmarks == SQL_UB_OFF)
+   if ((bookmark = opts->bookmark) && bookmark->buffer && stmt->options.use_bookmarks == SQL_UB_OFF)
    {
        SC_set_error(stmt, STMT_COLNUM_ERROR, "Attempt to retrieve bookmark with bookmark usage disabled");
        SC_log_error(func, "", stmt);
    UInt4       oid, blocknum;
    QResultClass *res,
               *qres;
-   IRDFields   *irdflds = SC_get_IRD(stmt);
+   IRDFields   *irdflds = SC_get_IRDF(stmt);
    RETCODE     ret = SQL_ERROR;
    char        tidval[32];
 
    Int4        i, limitrow;
    UWORD       qcount;
    QResultClass    *res;
-   IRDFields   *irdflds = SC_get_IRD(stmt);
+   IRDFields   *irdflds = SC_get_IRDF(stmt);
    RETCODE     ret = SQL_ERROR;
    ConnectionClass *conn = SC_get_conn(stmt);
    UInt4       oid, blocknum, lodlen;
    }
    return ret;
 }
+
+/* SQL_NEED_DATA callback for SC_pos_update */
+typedef struct
+{
+   BOOL        updyes;
+   QResultClass    *res;
+   StatementClass  *stmt, *qstmt;
+   IRDFields   *irdflds;
+   UWORD       irow;
+   UDWORD      global_ridx;
+}  pup_cdata;
+static RETCODE
+pos_update_callback(RETCODE retcode, pup_cdata *s)
+{
+   RETCODE ret = retcode;
+
+   if (s->updyes)
+   {
+       mylog("pos_update_callback in\n");
+       ret = irow_update(ret, s->stmt, s->qstmt, s->irow, s->global_ridx);
+       PGAPI_FreeStmt(s->qstmt, SQL_DROP);
+   }
+   s->updyes = FALSE;
+   if (SQL_SUCCESS == ret && s->res->keyset)
+   {
+       ConnectionClass *conn = SC_get_conn(s->stmt);
+
+       if (CC_is_in_trans(conn))
+       {
+           s->res->keyset[s->global_ridx].status |= (SQL_ROW_UPDATED  | CURS_SELF_UPDATING);
+       }
+       else
+           s->res->keyset[s->global_ridx].status |= (SQL_ROW_UPDATED  | CURS_SELF_UPDATED);
+   }
+#if (ODBCVER >= 0x0300)
+   if (s->irdflds->rowStatusArray)
+   {
+       switch (ret)
+       {
+           case SQL_SUCCESS:
+               s->irdflds->rowStatusArray[s->irow] = SQL_ROW_UPDATED;
+               break;
+           default:
+               s->irdflds->rowStatusArray[s->irow] = ret;
+       }
+   }
+#endif /* ODBCVER */
+
+   return ret;
+}
 RETCODE
 SC_pos_update(StatementClass *stmt,
              UWORD irow, UDWORD global_ridx)
    int         i,
                num_cols,
                upd_cols;
-   QResultClass *res;
-   ConnectionClass *conn = SC_get_conn(stmt);
-   ARDFields   *opts = SC_get_ARD(stmt);
-   IRDFields   *irdflds = SC_get_IRD(stmt);
+   pup_cdata   s;
+   ConnectionClass *conn;
+   ARDFields   *opts = SC_get_ARDF(stmt);
    BindInfoClass *bindings = opts->bindings;
-   FIELD_INFO  **fi = SC_get_IRD(stmt)->fi;
+   FIELD_INFO  **fi;
    char        updstr[4096];
    RETCODE     ret;
    UInt4   oid, offset, blocknum;
    UInt2   pgoffset;
    Int4    *used, bind_size = opts->bind_size;
 
-   if (!(res = SC_get_Curres(stmt)))
+   s.stmt = stmt;
+   s.irow = irow;
+   s.global_ridx = global_ridx;
+   s.irdflds = SC_get_IRDF(s.stmt);
+   fi = s.irdflds->fi;
+   if (!(s.res = SC_get_Curres(s.stmt)))
    {
-       SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Null statement result in SC_pos_update.");
+       SC_set_error(s.stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Null statement result in SC_pos_update.");
        return SQL_ERROR;
    }
-   mylog("POS UPDATE %d+%d fi=%x ti=%x\n", irow, res->base, fi, stmt->ti);
-   if (!stmt->ti)
-       parse_statement(stmt);  /* not preferable */
-   if (!stmt->updatable)
+   mylog("POS UPDATE %d+%d fi=%x ti=%x\n", s.irow, s.res->base, fi, s.stmt->ti);
+   if (!s.stmt->ti)
+       parse_statement(s.stmt);    /* not preferable */
+   if (!s.stmt->updatable)
    {
-       stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
-       SC_set_error(stmt, STMT_INVALID_OPTION_IDENTIFIER, "the statement is read-only");
+       s.stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
+       SC_set_error(s.stmt, STMT_INVALID_OPTION_IDENTIFIER, "the statement is read-only");
        return SQL_ERROR;
    }
-   if (!(oid = getOid(res, global_ridx)))
+   if (!(oid = getOid(s.res, s.global_ridx)))
    {
-       SC_set_error(stmt, STMT_INVALID_CURSOR_POSITION, "The row is already deleted ?");
+       SC_set_error(s.stmt, STMT_INVALID_CURSOR_POSITION, "The row is already deleted ?");
        return SQL_ERROR;
    }
-   getTid(res, global_ridx, &blocknum, &pgoffset);
+   getTid(s.res, s.global_ridx, &blocknum, &pgoffset);
 
-   if (stmt->ti[0]->schema[0])
-       sprintf(updstr, "update \"%s\".\"%s\" set", stmt->ti[0]->schema, stmt->ti[0]->name);
+   if (s.stmt->ti[0]->schema[0])
+       sprintf(updstr, "update \"%s\".\"%s\" set", s.stmt->ti[0]->schema, s.stmt->ti[0]->name);
    else
-       sprintf(updstr, "update \"%s\" set", stmt->ti[0]->name);
-   num_cols = irdflds->nfields;
+       sprintf(updstr, "update \"%s\" set", s.stmt->ti[0]->name);
+   num_cols = s.irdflds->nfields;
    offset = opts->row_offset_ptr ? *opts->row_offset_ptr : 0;
    for (i = upd_cols = 0; i < num_cols; i++)
    {
        {
            used += (offset >> 2);
            if (bind_size > 0)
-               used += (bind_size * irow / 4);
+               used += (bind_size * s.irow / 4);
            else    
-               used += irow; 
+               used += s.irow; 
            mylog("%d used=%d,%x\n", i, *used, used);
            if (*used != SQL_IGNORE && fi[i]->updatable)
            {
        else
            mylog("%d null bind\n", i);
    }
+   conn = SC_get_conn(s.stmt);
+   s.updyes = FALSE;
    if (upd_cols > 0)
    {
        HSTMT       hstmt;
        int         j;
-       int         res_cols = QR_NumResultCols(res);
+       int         res_cols = QR_NumResultCols(s.res);
        ConnInfo    *ci = &(conn->connInfo);
-       StatementClass *qstmt;
        APDFields   *apdopts;
        Int4        fieldtype = 0;
 
        mylog("updstr=%s\n", updstr);
        if (PGAPI_AllocStmt(conn, &hstmt) != SQL_SUCCESS)
        {
-           SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "internal AllocStmt error");
+           SC_set_error(s.stmt, STMT_NO_MEMORY_ERROR, "internal AllocStmt error");
            return SQL_ERROR;
        }
-       qstmt = (StatementClass *) hstmt;
-       apdopts = SC_get_APD(qstmt);
+       s.qstmt = (StatementClass *) hstmt;
+       apdopts = SC_get_APDF(s.qstmt);
        apdopts->param_bind_type = opts->bind_size;
        apdopts->param_offset_ptr = opts->row_offset_ptr;
        for (i = j = 0; i < num_cols; i++)
            {
                used += (offset >> 2);
                if (bind_size > 0)
-                   used += (bind_size * irow / 4);
+                   used += (bind_size * s.irow / 4);
                else
-                   used += irow;
+                   used += s.irow;
                mylog("%d used=%d\n", i, *used);
                if (*used != SQL_IGNORE && fi[i]->updatable)
                {
-                   fieldtype = QR_get_field_type(res, i);
-                   PGAPI_BindParameter(hstmt, (SQLUSMALLINT) ++j,
-                                SQL_PARAM_INPUT, bindings[i].returntype,
-                     pgtype_to_concise_type(stmt, fieldtype),
-                                                           fi[i]->column_size > 0 ? fi[i]->column_size : pgtype_column_size(stmt, fieldtype, i, ci->drivers.unknown_sizes),
-                                   (SQLSMALLINT) fi[i]->decimal_digits,
-                                       bindings[i].buffer,
-                                       bindings[i].buflen,
-                                       bindings[i].used);
+                   fieldtype = QR_get_field_type(s.res, i);
+                   PGAPI_BindParameter(hstmt,
+                       (SQLUSMALLINT) ++j,
+                       SQL_PARAM_INPUT,
+                       bindings[i].returntype,
+                       pgtype_to_concise_type(s.stmt, fieldtype),
+                                                               fi[i]->column_size > 0 ? fi[i]->column_size : pgtype_column_size(s.stmt, fieldtype, i, ci->drivers.unknown_sizes),
+                       (SQLSMALLINT) fi[i]->decimal_digits,
+                       bindings[i].buffer,
+                       bindings[i].buflen,
+                       bindings[i].used);
                }
            }
        }
-       qstmt->exec_start_row = qstmt->exec_end_row = irow; 
-       ret = PGAPI_ExecDirect(hstmt, updstr, strlen(updstr));
+       s.qstmt->exec_start_row = s.qstmt->exec_end_row = s.irow;
+       s.updyes = TRUE; 
+       ret = PGAPI_ExecDirect(hstmt, updstr, SQL_NTS, 0);
        if (ret == SQL_ERROR)
        {
-           SC_error_copy(stmt, qstmt);
+           SC_error_copy(s.stmt, s.qstmt);
        }
        else if (ret == SQL_NEED_DATA)  /* must be fixed */
        {
-           stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
-           SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "SetPos with data_at_exec not yet supported");
-           ret = SQL_ERROR;
+           pup_cdata *cbdata = (pup_cdata *) malloc(sizeof(pup_cdata));
+           memcpy(cbdata, &s, sizeof(pup_cdata));
+           s.stmt->execute_delegate = s.qstmt;
+           enqueueNeedDataCallback(s.stmt, pos_update_callback, cbdata);
+           return ret;
        }
-       ret = irow_update(ret, stmt, qstmt, irow, global_ridx);
-       PGAPI_FreeStmt(hstmt, SQL_DROP);
    }
    else
    {
        ret = SQL_SUCCESS_WITH_INFO;
-       SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "update list null");
-   }
-   if (SQL_SUCCESS == ret && res->keyset)
-   {
-       if (CC_is_in_trans(conn))
-       {
-           res->keyset[global_ridx].status |= (SQL_ROW_UPDATED  | CURS_SELF_UPDATING);
-       }
-       else
-           res->keyset[global_ridx].status |= (SQL_ROW_UPDATED  | CURS_SELF_UPDATED);
+       SC_set_error(s.stmt, STMT_INVALID_CURSOR_STATE_ERROR, "update list null");
    }
-#if (ODBCVER >= 0x0300)
-   if (irdflds->rowStatusArray)
-   {
-       switch (ret)
-       {
-           case SQL_SUCCESS:
-               irdflds->rowStatusArray[irow] = SQL_ROW_UPDATED;
-               break;
-           default:
-               irdflds->rowStatusArray[irow] = ret;
-       }
-   }
-#endif /* ODBCVER */
 
+   ret = pos_update_callback(ret, &s);
    return ret;
 }
 RETCODE
    UWORD       offset;
    QResultClass *res, *qres;
    ConnectionClass *conn = SC_get_conn(stmt);
-   ARDFields   *opts = SC_get_ARD(stmt);
-   IRDFields   *irdflds = SC_get_IRD(stmt);
+   ARDFields   *opts = SC_get_ARDF(stmt);
+   IRDFields   *irdflds = SC_get_IRDF(stmt);
    BindInfoClass *bindings = opts->bindings;
    char        dltstr[4096];
    RETCODE     ret;
    {
        int     addcnt;
        UInt4       oid;
-       ARDFields   *opts = SC_get_ARD(stmt);
+       ARDFields   *opts = SC_get_ARDF(stmt);
        QResultClass    *ires = SC_get_Curres(istmt);
        const char *cmdstr;
        BindInfoClass   *bookmark;
                    return qret;
            }
            bookmark = opts->bookmark;
-           if (bookmark->buffer)
+           if (bookmark && bookmark->buffer)
            {
                char    buf[32];
                UInt4   offset = opts->row_offset_ptr ? *opts->row_offset_ptr : 0;
    }
    return ret;
 }
+
+/* SQL_NEED_DATA callback for SC_pos_add */
+typedef struct
+{
+   BOOL        updyes;
+   QResultClass    *res;
+   StatementClass  *stmt, *qstmt;
+   IRDFields   *irdflds;
+   UWORD       irow;
+}  padd_cdata;
+
+static RETCODE
+pos_add_callback(RETCODE retcode, padd_cdata *s)
+{
+   RETCODE ret = retcode;
+
+   if (s->updyes)
+   {
+       int brow_save;
+       
+       mylog("pos_add_callback in\n");
+       brow_save = s->stmt->bind_row; 
+       s->stmt->bind_row = s->irow; 
+       ret = irow_insert(ret, s->stmt, s->qstmt, s->res->num_total_rows);
+       s->stmt->bind_row = brow_save;
+   }
+   s->updyes = FALSE; 
+   PGAPI_FreeStmt((HSTMT) s->qstmt, SQL_DROP);
+   if (SQL_SUCCESS == ret && s->res->keyset)
+   {
+       int global_ridx = s->res->num_total_rows - 1;
+       ConnectionClass *conn = SC_get_conn(s->stmt);
+
+       if (CC_is_in_trans(conn))
+       {
+
+           AddRollback(conn, s->res, global_ridx, NULL);
+           s->res->keyset[global_ridx].status |= (SQL_ROW_ADDED | CURS_SELF_ADDING);
+       }
+       else
+           s->res->keyset[global_ridx].status |= (SQL_ROW_ADDED | CURS_SELF_ADDED);
+   }
+#if (ODBCVER >= 0x0300)
+   if (s->irdflds->rowStatusArray)
+   {
+       switch (ret)
+       {
+           case SQL_SUCCESS:
+               s->irdflds->rowStatusArray[s->irow] = SQL_ROW_ADDED;
+               break;
+           default:
+               s->irdflds->rowStatusArray[s->irow] = ret;
+       }
+   }
+#endif /* ODBCVER */
+
+   return ret;
+}
+
 RETCODE
 SC_pos_add(StatementClass *stmt,
           UWORD irow)
                add_cols,
                i;
    HSTMT       hstmt;
-   StatementClass *qstmt;
+
+   padd_cdata  s;
    ConnectionClass *conn;
    ConnInfo    *ci;
-   QResultClass *res;
-   ARDFields   *opts = SC_get_ARD(stmt);
-   IRDFields   *irdflds = SC_get_IRD(stmt);
+   ARDFields   *opts = SC_get_ARDF(stmt);
    APDFields   *apdopts;
    BindInfoClass *bindings = opts->bindings;
-   FIELD_INFO  **fi = SC_get_IRD(stmt)->fi;
+   FIELD_INFO  **fi = SC_get_IRDF(stmt)->fi;
    char        addstr[4096];
    RETCODE     ret;
    UInt4       offset;
    Int4        fieldtype;
 
    mylog("POS ADD fi=%x ti=%x\n", fi, stmt->ti);
-   if (!(res = SC_get_Curres(stmt)))
+   s.stmt = stmt;
+   s.irow = irow;
+   if (!(s.res = SC_get_Curres(s.stmt)))
    {
-       SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Null statement result in SC_pos_add.");
+       SC_set_error(s.stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Null statement result in SC_pos_add.");
        return SQL_ERROR;
    }
-   if (!stmt->ti)
-       parse_statement(stmt);  /* not preferable */
-   if (!stmt->updatable)
+   if (!s.stmt->ti)
+       parse_statement(s.stmt);    /* not preferable */
+   if (!s.stmt->updatable)
    {
-       stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
-       SC_set_error(stmt, STMT_INVALID_OPTION_IDENTIFIER, "the statement is read-only");
+       s.stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
+       SC_set_error(s.stmt, STMT_INVALID_OPTION_IDENTIFIER, "the statement is read-only");
        return SQL_ERROR;
    }
-   num_cols = irdflds->nfields;
-   conn = SC_get_conn(stmt);
-   if (stmt->ti[0]->schema[0])
-       sprintf(addstr, "insert into \"%s\".\"%s\" (", stmt->ti[0]->schema, stmt->ti[0]->name);
+   s.irdflds = SC_get_IRDF(s.stmt);
+   num_cols = s.irdflds->nfields;
+   conn = SC_get_conn(s.stmt);
+   if (s.stmt->ti[0]->schema[0])
+       sprintf(addstr, "insert into \"%s\".\"%s\" (", s.stmt->ti[0]->schema, s.stmt->ti[0]->name);
    else
-       sprintf(addstr, "insert into \"%s\" (", stmt->ti[0]->name);
+       sprintf(addstr, "insert into \"%s\" (", s.stmt->ti[0]->name);
    if (PGAPI_AllocStmt(conn, &hstmt) != SQL_SUCCESS)
    {
-       SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "internal AllocStmt error");
+       SC_set_error(s.stmt, STMT_NO_MEMORY_ERROR, "internal AllocStmt error");
        return SQL_ERROR;
    }
    if (opts->row_offset_ptr)
        offset = *opts->row_offset_ptr;
    else
        offset = 0;
-   qstmt = (StatementClass *) hstmt;
-   apdopts = SC_get_APD(qstmt);
+   s.qstmt = (StatementClass *) hstmt;
+   apdopts = SC_get_APDF(s.qstmt);
    apdopts->param_bind_type = opts->bind_size;
    apdopts->param_offset_ptr = opts->row_offset_ptr;
    ci = &(conn->connInfo);
        {
            used += (offset >> 2);
            if (bind_size > 0)
-               used += (bind_size * irow / 4);
+               used += (bind_size * s.irow / 4);
            else
-               used += irow;
+               used += s.irow;
            mylog("%d used=%d\n", i, *used);
            if (*used != SQL_IGNORE && fi[i]->updatable)
            {
-               fieldtype = QR_get_field_type(res, i);
+               fieldtype = QR_get_field_type(s.res, i);
                if (add_cols)
                    sprintf(addstr, "%s, \"%s\"", addstr, fi[i]->name);
                else
                    sprintf(addstr, "%s\"%s\"", addstr, fi[i]->name);
-               PGAPI_BindParameter(hstmt, (SQLUSMALLINT) ++add_cols,
-                                SQL_PARAM_INPUT, bindings[i].returntype,
-                     pgtype_to_concise_type(stmt, fieldtype),
-                                                           fi[i]->column_size > 0 ? fi[i]->column_size : pgtype_column_size(stmt, fieldtype, i, ci->drivers.unknown_sizes),
-                                   (SQLSMALLINT) fi[i]->decimal_digits,
-                                   bindings[i].buffer,
-                                   bindings[i].buflen,
-                                   bindings[i].used);
+               PGAPI_BindParameter(hstmt,
+                   (SQLUSMALLINT) ++add_cols,
+                   SQL_PARAM_INPUT,
+                   bindings[i].returntype,
+                   pgtype_to_concise_type(s.stmt, fieldtype),
+                                                           fi[i]->column_size > 0 ? fi[i]->column_size : pgtype_column_size(s.stmt, fieldtype, i, ci->drivers.unknown_sizes),
+                   (SQLSMALLINT) fi[i]->decimal_digits,
+                   bindings[i].buffer,
+                   bindings[i].buflen,
+                   bindings[i].used);
            }
        }
        else
            mylog("%d null bind\n", i);
    }
+   s.updyes = FALSE;
    if (add_cols > 0)
    {
-       int brow_save;
-
        sprintf(addstr, "%s) values (", addstr);
        for (i = 0; i < add_cols; i++)
        {
        }
        strcat(addstr, ")");
        mylog("addstr=%s\n", addstr);
-       qstmt->exec_start_row = qstmt->exec_end_row = irow; 
-       ret = PGAPI_ExecDirect(hstmt, addstr, strlen(addstr));
+       s.qstmt->exec_start_row = s.qstmt->exec_end_row = s.irow;
+       s.updyes = TRUE; 
+       ret = PGAPI_ExecDirect(hstmt, addstr, SQL_NTS, 0);
        if (ret == SQL_ERROR)
        {
-           SC_error_copy(stmt, qstmt);
+           SC_error_copy(s.stmt, s.qstmt);
        }
        else if (ret == SQL_NEED_DATA)      /* must be fixed */
        {
-           stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
-           SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "SetPos with data_at_exec not yet supported");
-           ret = SQL_ERROR;
+           padd_cdata *cbdata = (padd_cdata *) malloc(sizeof(padd_cdata));
+           memcpy(cbdata, &s, sizeof(padd_cdata));
+           s.stmt->execute_delegate = s.qstmt;
+           enqueueNeedDataCallback(s.stmt, pos_add_callback, cbdata);
+           return ret;
        }
-       brow_save = stmt->bind_row; 
-       stmt->bind_row = irow; 
-       ret = irow_insert(ret, stmt, qstmt, res->num_total_rows);
-       stmt->bind_row = brow_save; 
    }
    else
    {
        ret = SQL_SUCCESS_WITH_INFO;
-       SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "insert list null");
+       SC_set_error(s.stmt, STMT_INVALID_CURSOR_STATE_ERROR, "insert list null");
    }
-   PGAPI_FreeStmt(hstmt, SQL_DROP);
-   if (SQL_SUCCESS == ret && res->keyset)
-   {
-       int global_ridx = res->num_total_rows - 1;
-       if (CC_is_in_trans(conn))
-       {
 
-           AddRollback(conn, res, global_ridx, NULL);
-           res->keyset[global_ridx].status |= (SQL_ROW_ADDED | CURS_SELF_ADDING);
-       }
-       else
-           res->keyset[global_ridx].status |= (SQL_ROW_ADDED | CURS_SELF_ADDED);
-   }
-#if (ODBCVER >= 0x0300)
-   if (irdflds->rowStatusArray)
-   {
-       switch (ret)
-       {
-           case SQL_SUCCESS:
-               irdflds->rowStatusArray[irow] = SQL_ROW_ADDED;
-               break;
-           default:
-               irdflds->rowStatusArray[irow] = ret;
-       }
-   }
-#endif /* ODBCVER */
+   ret = pos_add_callback(ret, &s);
 
    return ret;
 }
 {
    RETCODE ret;
 #if (ODBCVER >= 0x0300)
-   IRDFields   *irdflds = SC_get_IRD(stmt);
+   IRDFields   *irdflds = SC_get_IRDF(stmt);
 #endif /* ODBCVER */
    /* save the last_fetch_count */
    int     last_fetch = stmt->last_fetch_count;
    return SQL_SUCCESS;
 }
 
+/* SQL_NEED_DATA callback for PGAPI_SetPos */
+typedef struct
+{
+   BOOL        need_data_callback, auto_commit_needed;
+   QResultClass    *res;
+   StatementClass  *stmt;
+   ARDFields   *opts;
+   GetDataInfo *gdata;
+   int idx, start_row, end_row, processed, ridx;
+   UWORD   fOption, irow, nrow;
+}  spos_cdata;
+static 
+RETCODE spos_callback(RETCODE retcode, spos_cdata *s)
+{
+   RETCODE ret;
+   ConnectionClass *conn;
+   UDWORD  global_ridx;
+
+   ret = retcode;
+   if (s->need_data_callback)
+   {
+       mylog("spos_callback in\n");
+       s->processed++;
+       if (SQL_ERROR != retcode)
+       {
+           s->nrow++;
+           s->idx++;
+       }
+   }
+   else
+   {
+       s->ridx = -1;
+       s->idx = s->nrow = s->processed = 0;
+   }
+   s->need_data_callback = FALSE;
+   for (; SQL_ERROR != ret && s->nrow <= s->end_row; s->idx++)
+   {
+       global_ridx = RowIdx2GIdx(s->idx, s->stmt);
+       if (SQL_ADD != s->fOption)
+       {
+           if ((int) global_ridx >= s->res->num_total_rows)
+               break;
+#ifdef DRIVER_CURSOR_IMPLEMENT
+           if (s->res->keyset) /* the row may be deleted and not in the rowset */
+           {
+               if (0 == (s->res->keyset[global_ridx].status & CURS_IN_ROWSET))
+                   continue;
+           }
+#endif   /* DRIVER_CURSOR_IMPLEMENT */
+       }
+       if (s->nrow < s->start_row)
+       {
+           s->nrow++;
+           continue;
+       }   
+       s->ridx = s->nrow;
+#if (ODBCVER >= 0x0300)
+       if (0 != s->irow || !s->opts->row_operation_ptr || s->opts->row_operation_ptr[s->nrow] == SQL_ROW_PROCEED)
+       {
+#endif /* ODBCVER */
+           switch (s->fOption)
+           {
+#ifdef DRIVER_CURSOR_IMPLEMENT
+               case SQL_UPDATE:
+                   ret = SC_pos_update(s->stmt, s->nrow, global_ridx);
+                   break;
+               case SQL_DELETE:
+                   ret = SC_pos_delete(s->stmt, s->nrow, global_ridx);
+                   break;
+               case SQL_ADD:
+                   ret = SC_pos_add(s->stmt, s->nrow);
+                   break;
+#endif   /* DRIVER_CURSOR_IMPLEMENT */
+               case SQL_REFRESH:
+                   ret = SC_pos_refresh(s->stmt, s->nrow, global_ridx);
+                   break;
+           }
+           if (SQL_NEED_DATA == ret)
+           {
+               spos_cdata *cbdata = (spos_cdata *) malloc(sizeof(spos_cdata));
+
+               memcpy(cbdata, s, sizeof(spos_cdata));
+               cbdata->need_data_callback = TRUE;
+               enqueueNeedDataCallback(s->stmt, spos_callback, cbdata);
+               return ret;
+           }
+           s->processed++;
+#if (ODBCVER >= 0x0300)
+       }
+#endif /* ODBCVER */
+       if (SQL_ERROR != ret)
+           s->nrow++;
+   }
+   conn = SC_get_conn(s->stmt);
+   if (SQL_ERROR == ret)
+       CC_abort(conn);
+   if (s->auto_commit_needed)
+       PGAPI_SetConnectOption(conn, SQL_AUTOCOMMIT, SQL_AUTOCOMMIT_ON);
+   if (s->irow > 0)
+   {
+       if (SQL_ADD != s->fOption && s->ridx >= 0) /* for SQLGetData */
+       { 
+           s->stmt->currTuple = RowIdx2GIdx(s->ridx, s->stmt);
+           QR_set_position(s->res, s->ridx);
+       }
+   }
+   else if (SC_get_IRDF(s->stmt)->rowsFetched)
+       *(SC_get_IRDF(s->stmt)->rowsFetched) = s->processed;
+   s->res->recent_processed_row_count = s->stmt->diag_row_count = s->processed;
+   return ret;
+}
+ 
 /*
  * This positions the cursor within a rowset, that was positioned using SQLExtendedFetch.
  * This will be useful (so far) only when using SQLGetData after SQLExtendedFetch.
 {
    CSTR func = "PGAPI_SetPos";
    RETCODE ret;
-   StatementClass *stmt = (StatementClass *) hstmt;
-   ConnectionClass *conn = SC_get_conn(stmt);
-   QResultClass *res;
-   int     num_cols, i, start_row, end_row, processed, ridx;
-   UWORD       nrow;
-   ARDFields   *opts;
-   BindInfoClass *bindings;
-   UDWORD      global_ridx, rowsetSize;
-   BOOL        auto_commit_needed = FALSE;
+   ConnectionClass *conn;
+   int     num_cols, i, rowsetSize;
+   GetDataClass    *gdata = NULL;
+   spos_cdata  s;
 
-   if (!stmt)
+   s.stmt = (StatementClass *) hstmt;
+   if (!s.stmt)
    {
        SC_log_error(func, "", NULL);
        return SQL_INVALID_HANDLE;
    }
 
-   opts = SC_get_ARD(stmt);
-   bindings = opts->bindings;
+   s.irow = irow;
+   s.fOption = fOption;
+   s.auto_commit_needed = FALSE;
+   s.opts = SC_get_ARDF(s.stmt);
+   gdata = SC_get_GDTI(s.stmt)->gdata;
 #ifdef DRIVER_CURSOR_IMPLEMENT
-   mylog("%s fOption=%d irow=%d lock=%d currt=%d\n", func, fOption, irow, fLock, stmt->currTuple);
-   if (stmt->options.scroll_concurrency != SQL_CONCUR_READ_ONLY)
+   mylog("%s fOption=%d irow=%d lock=%d currt=%d\n", func, s.fOption, s.irow, fLock, s.stmt->currTuple);
+   if (s.stmt->options.scroll_concurrency != SQL_CONCUR_READ_ONLY)
        ;
    else
 #endif   /* DRIVER_CURSOR_IMPLEMENT */
-   if (fOption != SQL_POSITION && fOption != SQL_REFRESH)
+   if (s.fOption != SQL_POSITION && s.fOption != SQL_REFRESH)
    {
-       SC_set_error(stmt, STMT_NOT_IMPLEMENTED_ERROR, "Only SQL_POSITION/REFRESH is supported for PGAPI_SetPos");
-       SC_log_error(func, "", stmt);
+       SC_set_error(s.stmt, STMT_NOT_IMPLEMENTED_ERROR, "Only SQL_POSITION/REFRESH is supported for PGAPI_SetPos");
+       SC_log_error(func, "", s.stmt);
        return SQL_ERROR;
    }
 
-   if (!(res = SC_get_Curres(stmt)))
+   if (!(s.res = SC_get_Curres(s.stmt)))
    {
-       SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Null statement result in PGAPI_SetPos.");
-       SC_log_error(func, "", stmt);
+       SC_set_error(s.stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Null statement result in PGAPI_SetPos.");
+       SC_log_error(func, "", s.stmt);
        return SQL_ERROR;
    }
 
 #if (ODBCVER >= 0x0300)
-   rowsetSize = (stmt->transition_status == 7 ? opts->size_of_rowset_odbc2 : opts->size_of_rowset);
+   rowsetSize = (s.stmt->transition_status == 7 ? s.opts->size_of_rowset_odbc2 : s.opts->size_of_rowset);
 #else
-   rowsetSize = opts->size_of_rowset_odbc2;
+   rowsetSize = s.opts->size_of_rowset_odbc2;
 #endif /* ODBCVER */
-   if (irow == 0) /* bulk operation */
+   if (s.irow == 0) /* bulk operation */
    {
-       if (SQL_POSITION == fOption)
+       if (SQL_POSITION == s.fOption)
        {
-           SC_set_error(stmt, STMT_INVALID_CURSOR_POSITION, "Bulk Position operations not allowed.");
-           SC_log_error(func, "", stmt);
+           SC_set_error(s.stmt, STMT_INVALID_CURSOR_POSITION, "Bulk Position operations not allowed.");
+           SC_log_error(func, "", s.stmt);
            return SQL_ERROR;
        }
-       start_row = 0;
-       end_row = rowsetSize - 1;
+       s.start_row = 0;
+       s.end_row = rowsetSize - 1;
    }
    else
    {
-       if (SQL_ADD != fOption && irow > stmt->last_fetch_count)
+       if (SQL_ADD != s.fOption && s.irow > s.stmt->last_fetch_count)
        {
-           SC_set_error(stmt, STMT_ROW_OUT_OF_RANGE, "Row value out of range");
-           SC_log_error(func, "", stmt);
+           SC_set_error(s.stmt, STMT_ROW_OUT_OF_RANGE, "Row value out of range");
+           SC_log_error(func, "", s.stmt);
            return SQL_ERROR;
        }
-       start_row = end_row = irow - 1;
+       s.start_row = s.end_row = s.irow - 1;
    }
 
-   num_cols = QR_NumResultCols(res);
+   num_cols = QR_NumResultCols(s.res);
    /* Reset for SQLGetData */
-   if (bindings)
+   if (gdata)
        for (i = 0; i < num_cols; i++)
-           bindings[i].data_left = -1;
+           gdata[i].data_left = -1;
    ret = SQL_SUCCESS;
 #ifdef DRIVER_CURSOR_IMPLEMENT
-   switch (fOption)
+   conn = SC_get_conn(s.stmt);
+   switch (s.fOption)
    {
        case SQL_UPDATE:
        case SQL_DELETE:
        case SQL_ADD:
-           if (auto_commit_needed = CC_is_in_autocommit(conn), auto_commit_needed)
+           if (s.auto_commit_needed = CC_is_in_autocommit(conn), s.auto_commit_needed)
                PGAPI_SetConnectOption(conn, SQL_AUTOCOMMIT, SQL_AUTOCOMMIT_OFF);
            break;
    }
 #endif   /* DRIVER_CURSOR_IMPLEMENT */
+
+   s.need_data_callback = FALSE;
+   return spos_callback(SQL_SUCCESS, &s);
+#ifdef NOT_USED
    ridx = -1;
    for (i = nrow = 0, processed = 0; nrow <= end_row; i++)
    {
                    ret = SC_pos_refresh(stmt, nrow, global_ridx);
                    break;
            }
+           if (SQL_NEED_DATA == ret)
+               return ret;
            processed++;
            if (SQL_ERROR == ret)
                break;
            QR_set_position(res, ridx);
        }
    }
-   else if (SC_get_IRD(stmt)->rowsFetched)
-       *(SC_get_IRD(stmt)->rowsFetched) = processed;
+   else if (SC_get_IRDF(stmt)->rowsFetched)
+       *(SC_get_IRDF(stmt)->rowsFetched) = processed;
    res->recent_processed_row_count = stmt->diag_row_count = processed;
-   return ret; 
+   return ret;
+#endif /* NOT_USED */ 
 }
 
 
 
    CSTR func = "PGAPI_AllocStmt";
    ConnectionClass *conn = (ConnectionClass *) hdbc;
    StatementClass *stmt;
+   ARDFields   *ardopts;
+   BindInfoClass   *bookmark;
 
    mylog("%s: entering...\n", func);
 
 
    /* Copy default statement options based from Connection options */
    stmt->options = stmt->options_orig = conn->stmtOptions;
-   stmt->ardopts = conn->ardOptions;
-   stmt->ardopts.bookmark = (BindInfoClass *) malloc(sizeof(BindInfoClass));
-   stmt->ardopts.bookmark->buffer = NULL;
-   stmt->ardopts.bookmark->used = NULL;
+   stmt->ardi.ardopts = conn->ardOptions;
+   ardopts = SC_get_ARDF(stmt);
+   bookmark = ARD_AllocBookmark(ardopts);
 
    stmt->stmt_size_limit = CC_get_max_query_len(conn);
    /* Save the handle for later */
 }
 
 
-/*
- * ARDFields initialize
- */
-void
-InitializeARDFields(ARDFields *opt)
-{
-   memset(opt, 0, sizeof(ARDFields));
-#if (ODBCVER >= 0x0300)
-   opt->size_of_rowset = 1;
-#endif /* ODBCVER */
-   opt->bind_size = 0;     /* default is to bind by column */
-   opt->size_of_rowset_odbc2 = 1;
-}
-/*
- * APDFields initialize
- */
-void
-InitializeAPDFields(APDFields *opt)
-{
-   memset(opt, 0, sizeof(APDFields));
-   opt->paramset_size = 1;
-   opt->param_bind_type = 0;   /* default is to bind by column */
-}
-
-
 StatementClass *
 SC_Constructor(void)
 {
 
        /* Clear Statement Options -- defaults will be set in AllocStmt */
        memset(&rv->options, 0, sizeof(StatementOptions));
-       memset(&rv->ardopts, 0, sizeof(ARDFields));
-       memset(&rv->apdopts, 0, sizeof(APDFields));
-       memset(&rv->irdopts, 0, sizeof(IRDFields));
-       memset(&rv->ipdopts, 0, sizeof(IPDFields));
+       InitializeEmbeddedDescriptor((DescriptorClass *)&(rv->ardi),
+               rv, SQL_ATTR_APP_ROW_DESC);
+       InitializeEmbeddedDescriptor((DescriptorClass *)&(rv->apdi),
+               rv, SQL_ATTR_APP_PARAM_DESC);
+       InitializeEmbeddedDescriptor((DescriptorClass *)&(rv->irdi),
+               rv, SQL_ATTR_IMP_ROW_DESC);
+       InitializeEmbeddedDescriptor((DescriptorClass *)&(rv->ipdi),
+               rv, SQL_ATTR_IMP_PARAM_DESC);
 
        rv->pre_executing = FALSE;
        rv->inaccurate_result = FALSE;
        rv->error_recsize = -1;
        rv->diag_row_count = 0;
        rv->stmt_time = 0;
+       rv->execute_delegate = NULL;
+       rv->allocated_callbacks = 0;
+       rv->num_callbacks = 0;
+       rv->callbacks = NULL;
+       GetDataInfoInitialize(SC_get_GDTI(rv));
+       PutDataInfoInitialize(SC_get_PDTI(rv));
        INIT_STMT_CS(rv);
    }
    return rv;
 }
 
-
-void ARDFields_free(ARDFields * self)
-{
-   if (self->bookmark)
-   {
-       free(self->bookmark);
-       self->bookmark = NULL;
-   }
-   /*
-    * the memory pointed to by the bindings is not deallocated by the
-    * driver but by the application that uses that driver, so we don't
-    * have to care
-    */
-   ARD_unbind_cols(self, TRUE);
-}
-
-void APDFields_free(APDFields * self)
-{
-   /* param bindings */
-   APD_free_params(self, STMT_FREE_PARAMS_ALL);
-}
-
-void IRDFields_free(IRDFields * self)
-{
-   /* Free the parsed field information */
-   if (self->fi)
-   {
-       int         i;
-
-       for (i = 0; i < (int) self->nfields; i++)
-       {
-           if (self->fi[i])
-           {
-               if (self->fi[i]->schema)
-                   free(self->fi[i]->schema);
-               free(self->fi[i]);
-           }
-       }
-       free(self->fi);
-       self->fi = NULL;
-   }
-}
-
-void IPDFields_free(IPDFields * self)
-{
-   /* param bindings */
-   IPD_free_params(self, STMT_FREE_PARAMS_ALL);
-}
-
 char
 SC_Destructor(StatementClass *self)
 {
    }
 
    /* Free the parsed field information */
-   ARDFields_free(&(self->ardopts));
-   APDFields_free(&(self->apdopts));
-   IRDFields_free(&(self->irdopts));
-   IPDFields_free(&(self->ipdopts));
+   DC_Destructor(SC_get_ARDi(self));
+   DC_Destructor(SC_get_APDi(self));
+   DC_Destructor(SC_get_IRDi(self));
+   DC_Destructor(SC_get_IPDi(self));
    
    if (self->__error_message)
        free(self->__error_message);
+   cancelNeedDataState(self);
+   if (self->callbacks)
+       free(self->callbacks);
+
    DELETE_STMT_CS(self);
    free(self);
 
 void
 SC_free_params(StatementClass *self, char option)
 {
-   APD_free_params(SC_get_APD(self), option);
-   IPD_free_params(SC_get_IPD(self), option);
+   APD_free_params(SC_get_APDF(self), option);
+   IPD_free_params(SC_get_IPDF(self), option);
+   PDATA_free_params(SC_get_PDTI(self), option);
    self->data_at_exec = -1;
    self->current_exec_param = -1;
    self->put_data = FALSE;
        self->ntab = 0;
    }
    /* Free the parsed field information */
-   IRDFields_free(SC_get_IRD(self));
+   DC_Destructor(SC_get_IRD(self));
 
    self->parse_status = STMT_PARSE_NONE;
    self->updatable = FALSE;
     */
    SC_free_params(self, STMT_FREE_PARAMS_DATA_AT_EXEC_ONLY);
    SC_initialize_stmts(self, FALSE);
+   cancelNeedDataState(self);
    /*
     *  reset the current attr setting to the original one.
     */
            self->pre_executing = TRUE;
            self->inaccurate_result = FALSE;
 
-           PGAPI_Execute(self);
+           PGAPI_Execute(self, 0);
 
            self->pre_executing = old_pre_executing;
 
 char
 SC_unbind_cols(StatementClass *self)
 {
-   ARDFields   *opts = SC_get_ARD(self);
+   ARDFields   *opts = SC_get_ARDF(self);
+   GetDataInfo *gdata = SC_get_GDTI(self);
+   BindInfoClass   *bookmark;
 
    ARD_unbind_cols(opts, FALSE);
-   opts->bookmark->buffer = NULL;
-   opts->bookmark->used = NULL;
+   GDATA_unbind_cols(gdata, FALSE);
+   if (bookmark = opts->bookmark, bookmark != NULL)
+   {
+       bookmark->buffer = NULL;
+       bookmark->used = NULL;
+   }
 
    return 1;
 }
    CSTR func = "SC_fetch";
    QResultClass *res = SC_get_Curres(self);
    ARDFields   *opts;
+   GetDataInfo *gdata;
    int         retval,
                result;
 
    Oid         type;
    char       *value;
    ColumnInfoClass *coli;
+   BindInfoClass   *bookmark;
 
    /* TupleField *tupleField; */
    ConnInfo   *ci = &(SC_get_conn(self)->connInfo);
    self->last_fetch_count++;
    self->last_fetch_count_include_ommitted++;
 
-   opts = SC_get_ARD(self);
+   opts = SC_get_ARDF(self);
    /*
     * If the bookmark column was bound then return a bookmark. Since this
     * is used with SQLExtendedFetch, and the rowset size may be greater
     * than 1, and an application can use row or column wise binding, use
     * the code in copy_and_convert_field() to handle that.
     */
-   if (opts->bookmark->buffer)
+   if ((bookmark = opts->bookmark) && bookmark->buffer)
    {
        char        buf[32];
        UInt4   offset = opts->row_offset_ptr ? *opts->row_offset_ptr : 0;
 
        sprintf(buf, "%ld", SC_get_bookmark(self));
        result = copy_and_convert_field(self, 0, buf,
-            SQL_C_ULONG, opts->bookmark->buffer + offset, 0,
-           opts->bookmark->used ? opts->bookmark->used + (offset >> 2) : NULL);
+            SQL_C_ULONG, bookmark->buffer + offset, 0,
+           bookmark->used ? bookmark->used + (offset >> 2) : NULL);
    }
 
    if (self->options.retrieve_data == SQL_RD_OFF)      /* data isn't required */
        return SQL_SUCCESS;
+   gdata = SC_get_GDTI(self);
+   if (gdata->allocated != opts->allocated)
+       extend_getdata_info(gdata, opts->allocated, TRUE);
    for (lf = 0; lf < num_cols; lf++)
    {
        mylog("fetch: cols=%d, lf=%d, opts = %u, opts->bindings = %u, buffer[] = %u\n", num_cols, lf, opts, opts->bindings, opts->bindings[lf].buffer);
 
        /* reset for SQLGetData */
-       opts->bindings[lf].data_left = -1;
+       gdata->gdata[lf].data_left = -1;
 
        if (opts->bindings[lf].buffer != NULL)
        {
 {
    CSTR func = "SC_execute";
    ConnectionClass *conn;
-   APDFields   *apdopts;
-   char        was_ok, was_nonfatal, was_rows_affected = 1;
-   /* was_rows_affected is set to 0 iff an UPDATE or DELETE affects 
-    * no rows. In this instance the driver should return
-    * SQL_NO_DATA_FOUND instead of SQL_SUCCESS.
-    */
- 
+   IPDFields   *ipdopts;
+   char        was_ok, was_nonfatal;
    QResultClass    *res = NULL;
    Int2        oldstatus,
                numcols;
    {
        was_ok = QR_command_successful(res);
        was_nonfatal = QR_command_nonfatal(res);
-       if (res->command &&
-           (strncmp(res->command, "UPDATE", 6) == 0 ||
-           strncmp(res->command, "DELETE", 6) == 0) &&
-           strtoul(res->command + 7, NULL, 0) == 0)
-       {
-           was_rows_affected = 0;
-       }
 
        if (was_ok)
            SC_set_errornumber(self, STMT_OK);
            /* now allocate the array to hold the binding info */
            if (numcols > 0)
            {
-               ARDFields   *opts = SC_get_ARD(self);
+               ARDFields   *opts = SC_get_ARDF(self);
                extend_column_bindings(opts, numcols);
                if (opts->bindings == NULL)
                {
        last->next = res;
    }
 
-   apdopts = SC_get_APD(self);
+   ipdopts = SC_get_IPDF(self);
    if (self->statement_type == STMT_TYPE_PROCCALL &&
        (SC_get_errornumber(self) == STMT_OK ||
         SC_get_errornumber(self) == STMT_INFO_ONLY) &&
-       apdopts->parameters &&
-       apdopts->parameters[0].buffer &&
-       apdopts->parameters[0].paramType == SQL_PARAM_OUTPUT)
+       ipdopts->parameters &&
+       ipdopts->parameters[0].paramType == SQL_PARAM_OUTPUT)
    {                           /* get the return value of the procedure
                                 * call */
        RETCODE     ret;
        ret = SC_fetch(hstmt);
        if (ret == SQL_SUCCESS || ret == SQL_SUCCESS_WITH_INFO)
        {
+           APDFields   *apdopts = SC_get_APDF(self);
+
            ret = PGAPI_GetData(hstmt, 1, apdopts->parameters[0].CType, apdopts->parameters[0].buffer, apdopts->parameters[0].buflen, apdopts->parameters[0].used);
            if (ret != SQL_SUCCESS)
            {
        }
    }
    if (SC_get_errornumber(self) == STMT_OK)
-       if (was_rows_affected)
-           return SQL_SUCCESS;
-       else
-           return SQL_NO_DATA_FOUND;
+       return SQL_SUCCESS;
    else if (SC_get_errornumber(self) == STMT_INFO_ONLY)
        return SQL_SUCCESS_WITH_INFO;
    else
    }
 }
 
+#define    CALLBACK_ALLOC_ONCE 4
+int enqueueNeedDataCallback(StatementClass *stmt, NeedDataCallfunc func, void *data)
+{
+   if (stmt->num_callbacks >= stmt->allocated_callbacks)
+   {
+       stmt->callbacks = (NeedDataCallback *) realloc(stmt->callbacks,
+           sizeof(NeedDataCallback) * (stmt->allocated_callbacks +
+               CALLBACK_ALLOC_ONCE));
+       stmt->allocated_callbacks += CALLBACK_ALLOC_ONCE;
+   }
+   stmt->callbacks[stmt->num_callbacks].func = func;
+   stmt->callbacks[stmt->num_callbacks].data = data;
+   stmt->num_callbacks++;
+
+inolog("enqueueNeedDataCallack stmt=%x, func=%x, count=%d\n", stmt, func, stmt->num_callbacks);
+   return stmt->num_callbacks;
+}
+
+RETCODE dequeueNeedDataCallback(RETCODE retcode, StatementClass *stmt)
+{
+   RETCODE         ret;
+   NeedDataCallfunc    func;
+   void            *data;
+   int         i, cnt;
+
+   mylog("dequeueNeedDataCallback ret=%d count=%d\n", retcode, stmt->num_callbacks);
+   if (SQL_NEED_DATA == retcode)
+       return retcode;
+   if (stmt->num_callbacks <= 0)
+       return retcode;
+   func = stmt->callbacks[0].func;
+   data = stmt->callbacks[0].data;
+   for (i = 1; i < stmt->num_callbacks; i++)
+       stmt->callbacks[i - 1] = stmt->callbacks[i];
+   cnt = --stmt->num_callbacks;
+   ret = (*func)(retcode, data);
+   free(data);
+   if (SQL_NEED_DATA != ret && cnt > 0)
+       ret = dequeueNeedDataCallback(ret, stmt);
+   return ret;
+}
+
+void   cancelNeedDataState(StatementClass *stmt)
+{
+   int cnt = stmt->num_callbacks, i;
+
+   stmt->num_callbacks = 0;
+   for (i = 0; i < cnt; i++)
+   {
+       if (stmt->callbacks[i].data)
+           free(stmt->callbacks[i].data);
+   }
+   stmt->execute_delegate = NULL;
+}
 
 void
 SC_log_error(const char *func, const char *desc, const StatementClass *self)
    if (self)
    {
        QResultClass *res = SC_get_Result(self);
-       const ARDFields *opts = SC_get_ARD(self);
-       const APDFields *apdopts = SC_get_APD(self);
+       const ARDFields *opts = SC_get_ARDF(self);
+       const APDFields *apdopts = SC_get_APDF(self);
        int rowsetSize;
 
 #if (ODBCVER >= 0x0300)
    }
 #undef PRN_NULLCHECK
 }
+
+/* Map sql commands to statement types */
+static struct
+{
+   int number;
+   const   char    * ver3str;
+   const   char    * ver2str;
+}  Descriptor_sqlstate[] =
+
+{
+   { STMT_OK,  "00000", "00000" }, /* OK */
+   { STMT_EXEC_ERROR, "HY000", "S1000" }, /* also a general error */
+   { STMT_STATUS_ERROR, "HY010", "S1010" },
+   { STMT_SEQUENCE_ERROR, "HY010", "S1010" }, /* Function sequence error */
+   { STMT_NO_MEMORY_ERROR, "HY001", "S1001" }, /* memory allocation failure */
+   { STMT_COLNUM_ERROR, "07009", "S1002" }, /* invalid column number */
+   { STMT_NO_STMTSTRING, "HY001", "S1001" }, /* having no stmtstring is also a malloc problem */
+   { STMT_ERROR_TAKEN_FROM_BACKEND, "HY000", "S1000" }, /* general error */
+   { STMT_INTERNAL_ERROR, "HY000", "S1000" }, /* general error */
+   { STMT_STILL_EXECUTING, "HY010", "S1010" },
+   { STMT_NOT_IMPLEMENTED_ERROR, "HYC00", "S1C00" }, /* == 'driver not 
+                             * capable' */
+   { STMT_BAD_PARAMETER_NUMBER_ERROR, "07009", "S1093" },
+   { STMT_OPTION_OUT_OF_RANGE_ERROR, "HY092", "S1092" },
+   { STMT_INVALID_COLUMN_NUMBER_ERROR, "07009", "S1002" },
+   { STMT_RESTRICTED_DATA_TYPE_ERROR, "07006", "07006" },
+   { STMT_INVALID_CURSOR_STATE_ERROR, "07005", "24000" },
+   { STMT_OPTION_VALUE_CHANGED, "01S02", "01S02" },
+   { STMT_CREATE_TABLE_ERROR, "42S01", "S0001" }, /* table already exists */
+   { STMT_NO_CURSOR_NAME, "S1015", "S1015" },
+   { STMT_INVALID_CURSOR_NAME, "34000", "34000" },
+   { STMT_INVALID_ARGUMENT_NO, "HY024", "S1009" }, /* invalid argument value */
+   { STMT_ROW_OUT_OF_RANGE, "HY107", "S1107" },
+   { STMT_OPERATION_CANCELLED, "HY008", "S1008" },
+   { STMT_INVALID_CURSOR_POSITION, "HY109", "S1109" },
+   { STMT_VALUE_OUT_OF_RANGE, "HY019", "22003" },
+   { STMT_OPERATION_INVALID, "HY011", "S1011" },
+   { STMT_PROGRAM_TYPE_OUT_OF_RANGE, "?????", "?????" }, 
+   { STMT_BAD_ERROR, "08S01", "08S01" }, /* communication link failure */
+   { STMT_INVALID_OPTION_IDENTIFIER, "HY092", "HY092" },
+   { STMT_RETURN_NULL_WITHOUT_INDICATOR, "22002", "22002" },
+   { STMT_ERROR_IN_ROW, "01S01", "01S01" },
+   { STMT_INVALID_DESCRIPTOR_IDENTIFIER, "HY091", "HY091" },
+   { STMT_OPTION_NOT_FOR_THE_DRIVER, "HYC00", "HYC00" },
+   { STMT_FETCH_OUT_OF_RANGE, "HY106", "S1106" },
+   { STMT_COUNT_FIELD_INCORRECT, "07002", "07002" },
+
+
+   { STMT_ROW_VERSION_CHANGED,  "01001", "01001" }, /* data changed */
+   { STMT_TRUNCATED, "01004", "01004" }, /* data truncated */
+   { STMT_INFO_ONLY, "00000", "00000" }, /* just information that is returned, no error */
+   { STMT_POS_BEFORE_RECORDSET, "01S06", "01S06" },
+};
+
 
    STMT_FETCH_EXTENDED
 };
 
+typedef    RETCODE (*NeedDataCallfunc)(RETCODE, void *);
+typedef    struct
+{
+   NeedDataCallfunc    func;
+   void            *data;
+}  NeedDataCallback;
 
 /********  Statement Handle    ***********/
 struct StatementClass_
    HSTMT FAR  *phstmt;
    StatementOptions options;
    StatementOptions options_orig;
-   ARDFields ardopts;
-   IRDFields irdopts;
-   APDFields apdopts;
-   IPDFields ipdopts;
+   /* attached descriptor handles */
+   ARDClass    *ard;
+   APDClass    *apd;
+   IRDClass    *ird;
+   IPDClass    *ipd;
+   /* implicit descriptor handles */
+   ARDClass    ardi;
+   IRDClass    irdi;
+   APDClass    apdi;
+   IPDClass    ipdi;
 
    STMT_Status status;
    char       *__error_message;
 
    Int4        currTuple;      /* current absolute row number (GetData,
                                 * SetPos, SQLFetch) */
+   GetDataInfo gdata_info;
    int         save_rowset_size;       /* saved rowset size in case of
                                         * change/FETCH_NEXT */
    Int4            rowset_start;   /* start of rowset (an absolute row
    int         data_at_exec;   /* Number of params needing SQLPutData */
    int         current_exec_param;     /* The current parameter for
                                         * SQLPutData */
+   PutDataInfo pdata_info;
 
    char        put_data;       /* Has SQLPutData been called yet? */
 
                         * prepared at the server ? */
    char        internal;       /* Is this statement being called
                                 * internally? */
+
    char        transition_status;  /* Transition status */
    char        cursor_name[MAX_CURSOR_LEN + 1];
 
    Int4        where_pos;
    Int4        last_fetch_count_include_ommitted;
    time_t      stmt_time;
+   /* SQL_NEED_DATA Callback list */
+   StatementClass  *execute_delegate;
+   UInt2       allocated_callbacks;
+   UInt2       num_callbacks;
+   NeedDataCallback    *callbacks;
 #if defined(WIN_MULTITHREAD_SUPPORT)
    CRITICAL_SECTION    cs;
 #elif defined(POSIX_MULTITHREAD_SUPPORT)
 #define SC_get_Result(a)  (a->result)
 #define SC_set_Curres(a, b)  (a->curres = b)
 #define SC_get_Curres(a)  (a->curres)
-#define SC_get_ARD(a)  (&(a->ardopts))
-#define SC_get_APD(a)  (&(a->apdopts))
-#define SC_get_IRD(a)  (&(a->irdopts))
-#define SC_get_IPD(a)  (&(a->ipdopts))
+#define SC_get_ARD(a)  (a->ard)
+#define SC_get_APD(a)  (a->apd)
+#define SC_get_IRD(a)  (a->ird)
+#define SC_get_IPD(a)  (a->ipd)
+#define SC_get_ARDF(a)  (&(SC_get_ARD(a)->ardopts))
+#define SC_get_APDF(a)  (&(SC_get_APD(a)->apdopts))
+#define SC_get_IRDF(a)  (&(SC_get_IRD(a)->irdopts))
+#define SC_get_IPDF(a)  (&(SC_get_IPD(a)->ipdopts))
+#define SC_get_ARDi(a)  (&(a->ardi))
+#define SC_get_APDi(a)  (&(a->apdi))
+#define SC_get_IRDi(a)  (&(a->irdi))
+#define SC_get_IPDi(a)  (&(a->ipdi))
+#define SC_get_GDTI(a)  (&(a->gdata_info))
+#define SC_get_PDTI(a)  (&(a->pdata_info))
 
 #define    SC_get_errornumber(a) (a->__error_number)
 #define    SC_set_errornumber(a, n) (a->__error_number = n)
 #define    SC_get_errormsg(a) (a->__error_message)
 #if (ODBCVER >= 0x0300)
-#define    SC_is_lower_case(a, b) (a->options.metadata_id || b->connInfo.lower_case_identifier)
+#define    SC_is_lower_case(a, b) (a->options.metadata_id, b->connInfo.lower_case_identifier)
 #else
 #define    SC_is_lower_case(a, b) (b->connInfo.lower_case_identifier)
 #endif /* ODBCVER */
 RETCODE        SC_pos_refresh(StatementClass *self, UWORD irow, UDWORD index);
 RETCODE        SC_pos_add(StatementClass *self, UWORD irow);
 
+DescriptorClass    *SC_set_ARD(StatementClass *stmt, DescriptorClass *desc);
+DescriptorClass    *SC_set_APD(StatementClass *stmt, DescriptorClass *desc);
+int        enqueueNeedDataCallback(StatementClass *self, NeedDataCallfunc, void *);
+RETCODE        dequeueNeedDataCallback(RETCODE, StatementClass *self);
+void       cancelNeedDataState(StatementClass *self);
+
 /*
  * Macros to convert global index <-> relative index in resultset/rowset
  */
 
 #ifndef __VERSION_H__
 #define __VERSION_H__
 
-#define POSTGRESDRIVERVERSION      "07.03.0200"
-#define POSTGRES_RESOURCE_VERSION  "07.03.0200\0"
-#define PG_DRVFILE_VERSION     7,3,2,0
+#define POSTGRESDRIVERVERSION      "07.03.0201"
+#define POSTGRES_RESOURCE_VERSION  "07.03.0201\0"
+#define PG_DRVFILE_VERSION     7,3,2,01
 
 #endif
 
    -@erase "$(INTDIR)\odbcapi.obj"
    -@erase "$(INTDIR)\odbcapi30.obj"
    -@erase "$(INTDIR)\pgapi30.obj"
+   -@erase "$(INTDIR)\descriptor.obj"
    -@erase "$(INTDIR)\vc60.idb"
    -@erase "$(OUTDIR)\psqlodbc.dll"
    -@erase "$(OUTDIR)\psqlodbc.exp"
    "$(INTDIR)\odbcapi.obj" \
    "$(INTDIR)\odbcapi30.obj" \
    "$(INTDIR)\pgapi30.obj" \
+   "$(INTDIR)\descriptor.obj" \
    "$(INTDIR)\psqlodbc.res"
 
 "$(OUTDIRBIN)\psqlodbc.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
    -@erase "$(INTDIR)\odbcapi.obj"
    -@erase "$(INTDIR)\odbcapi30.obj"
    -@erase "$(INTDIR)\pgapi30.obj"
+   -@erase "$(INTDIR)\descriptor.obj"
    -@erase "$(INTDIR)\vc60.idb"
    -@erase "$(INTDIR)\vc60.pdb"
    -@erase "$(OUTDIR)\psqlodbc.dll"
    "$(INTDIR)\odbcapi.obj" \
    "$(INTDIR)\odbcapi30.obj" \
    "$(INTDIR)\pgapi30.obj" \
+   "$(INTDIR)\descriptor.obj" \
    "$(INTDIR)\psqlodbc.res"
 
 "$(OUTDIR)\psqlodbc.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
 "$(INTDIR)\pgapi30.obj" : $(SOURCE) "$(INTDIR)"
    $(CPP) $(CPP_PROJ) $(SOURCE)
 
+SOURCE=descriptor.c
+
+"$(INTDIR)\descriptor.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
 
 !ENDIF 
 
    -@erase "$(INTDIR)\tuple.obj"
    -@erase "$(INTDIR)\tuplelist.obj"
    -@erase "$(INTDIR)\odbcapi.obj"
+   -@erase "$(INTDIR)\descriptor.obj"
    -@erase "$(INTDIR)\vc60.idb"
    -@erase "$(OUTDIR)\psqlodbc25.dll"
    -@erase "$(OUTDIR)\psqlodbc.exp"
    "$(INTDIR)\tuple.obj" \
    "$(INTDIR)\tuplelist.obj" \
    "$(INTDIR)\odbcapi.obj" \
+   "$(INTDIR)\descriptor.obj" \
    "$(INTDIR)\psqlodbc.res"
 
 "$(OUTDIRBIN)\psqlodbc25.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
    -@erase "$(INTDIR)\tuple.obj"
    -@erase "$(INTDIR)\tuplelist.obj"
    -@erase "$(INTDIR)\odbcapi.obj"
+   -@erase "$(INTDIR)\descriptor.obj"
    -@erase "$(INTDIR)\vc60.idb"
    -@erase "$(INTDIR)\vc60.pdb"
    -@erase "$(OUTDIR)\psqlodbc25.dll"
    "$(INTDIR)\tuple.obj" \
    "$(INTDIR)\tuplelist.obj" \
    "$(INTDIR)\odbcapi.obj" \
+   "$(INTDIR)\descriptor.obj" \
    "$(INTDIR)\psqlodbc.res"
 
 "$(OUTDIR)\psqlodbc25.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
 "$(INTDIR)\odbcapi.obj" : $(SOURCE) "$(INTDIR)"
    $(CPP) $(CPP_PROJ) $(SOURCE)
 
+SOURCE=descriptor.c
+
+"$(INTDIR)\descriptor.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
 
 
 
 
    -@erase "$(INTDIR)\tuplelist.obj"
    -@erase "$(INTDIR)\odbcapi.obj"
    -@erase "$(INTDIR)\odbcapi30.obj"
+   -@erase "$(INTDIR)\descriptor.obj"
    -@erase "$(INTDIR)\vc60.idb"
    -@erase "$(OUTDIR)\psqlodbc30w.dll"
    -@erase "$(OUTDIR)\psqlodbc.exp"
    "$(INTDIR)\tuplelist.obj" \
    "$(INTDIR)\odbcapi.obj" \
    "$(INTDIR)\odbcapi30.obj" \
+   "$(INTDIR)\descriptor.obj" \
    "$(INTDIR)\psqlodbc.res"
 
 "$(OUTDIRBIN)\psqlodbc30w.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
    -@erase "$(INTDIR)\tuplelist.obj"
    -@erase "$(INTDIR)\odbcapi.obj"
    -@erase "$(INTDIR)\odbcapi30.obj"
+   -@erase "$(INTDIR)\descriptor.obj"
    -@erase "$(INTDIR)\vc60.idb"
    -@erase "$(INTDIR)\vc60.pdb"
    -@erase "$(OUTDIR)\psqlodbc30w.dll"
    "$(INTDIR)\tuplelist.obj" \
    "$(INTDIR)\odbcapi.obj" \
    "$(INTDIR)\odbcapi30.obj" \
+   "$(INTDIR)\descriptor.obj" \
    "$(INTDIR)\psqlodbc.res"
 
 "$(OUTDIR)\psqlodbc30w.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
 "$(INTDIR)\odbcapi30.obj" : $(SOURCE) "$(INTDIR)"
    $(CPP) $(CPP_PROJ) $(SOURCE)
 
+SOURCE=descriptor.c
 
+"$(INTDIR)\descriptor.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
 
 
 !ENDIF