1
0
mirror of https://github.com/postgres/postgres.git synced 2025-05-02 11:44:50 +03:00

Back out all ODBC formatting changes, and back out removal of <6.4

protocol. I have left in Tom's SOCK_get_next_byte() fix, and the new
win32.mak file addition.  I have also left in the 'X' connection close
fix.
This commit is contained in:
Bruce Momjian 2001-02-14 05:45:46 +00:00
parent 18b04ae131
commit 594e97b72f
45 changed files with 9580 additions and 11060 deletions

@ -2,7 +2,7 @@
# #
# GNUMakefile for psqlodbc (Postgres ODBC driver) # GNUMakefile for psqlodbc (Postgres ODBC driver)
# #
# $Header: /cvsroot/pgsql/src/interfaces/odbc/Attic/GNUmakefile,v 1.12 2001/02/10 16:51:40 petere Exp $ # $Header: /cvsroot/pgsql/src/interfaces/odbc/Attic/GNUmakefile,v 1.13 2001/02/14 05:45:38 momjian Exp $
# #
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
@ -24,6 +24,7 @@ OBJS = info.o bind.o columninfo.o connection.o convert.o drvconn.o \
gpps.o tuple.o tuplelist.o dlg_specific.o $(OBJX) gpps.o tuple.o tuplelist.o dlg_specific.o $(OBJX)
SHLIB_LINK = $(filter -lm, $(LIBS)) SHLIB_LINK = $(filter -lm, $(LIBS))
all: all-lib all: all-lib
# Shared library stuff # Shared library stuff
@ -32,7 +33,6 @@ include $(top_srcdir)/src/Makefile.shlib
# Symbols must be resolved to the version in the shared library because # Symbols must be resolved to the version in the shared library because
# the driver manager (e.g., iodbc) provides some symbols with the same # the driver manager (e.g., iodbc) provides some symbols with the same
# names and we don't want those. (This issue is probably ELF specific.) # names and we don't want those. (This issue is probably ELF specific.)
LINK.shared += $(shlib_symbolic) LINK.shared += $(shlib_symbolic)
odbc_headers = isql.h isqlext.h iodbc.h odbc_headers = isql.h isqlext.h iodbc.h

@ -1,3 +1,4 @@
/* Module: bind.c /* Module: bind.c
* *
* Description: This module contains routines related to binding * Description: This module contains routines related to binding
@ -35,8 +36,7 @@
/* Bind parameters on a statement handle */ /* Bind parameters on a statement handle */
RETCODE SQL_API RETCODE SQL_API SQLBindParameter(
SQLBindParameter(
HSTMT hstmt, HSTMT hstmt,
UWORD ipar, UWORD ipar,
SWORD fParamType, SWORD fParamType,
@ -53,24 +53,20 @@ SQLBindParameter(
mylog( "%s: entering...\n", func); mylog( "%s: entering...\n", func);
if (!stmt) if( ! stmt) {
{
SC_log_error(func, "", NULL); SC_log_error(func, "", NULL);
return SQL_INVALID_HANDLE; return SQL_INVALID_HANDLE;
} }
if (stmt->parameters_allocated < ipar) if(stmt->parameters_allocated < ipar) {
{
ParameterInfoClass *old_parameters; ParameterInfoClass *old_parameters;
int i, int i, old_parameters_allocated;
old_parameters_allocated;
old_parameters = stmt->parameters; old_parameters = stmt->parameters;
old_parameters_allocated = stmt->parameters_allocated; old_parameters_allocated = stmt->parameters_allocated;
stmt->parameters = (ParameterInfoClass *) malloc(sizeof(ParameterInfoClass)*(ipar)); stmt->parameters = (ParameterInfoClass *) malloc(sizeof(ParameterInfoClass)*(ipar));
if (!stmt->parameters) if ( ! stmt->parameters) {
{
stmt->errornumber = STMT_NO_MEMORY_ERROR; stmt->errornumber = STMT_NO_MEMORY_ERROR;
stmt->errormsg = "Could not allocate memory for statement parameters"; stmt->errormsg = "Could not allocate memory for statement parameters";
SC_log_error(func, "", stmt); SC_log_error(func, "", stmt);
@ -80,8 +76,7 @@ SQLBindParameter(
stmt->parameters_allocated = ipar; stmt->parameters_allocated = ipar;
/* copy the old parameters over */ /* copy the old parameters over */
for (i = 0; i < old_parameters_allocated; i++) for(i = 0; i < old_parameters_allocated; i++) {
{
/* a structure copy should work */ /* a structure copy should work */
stmt->parameters[i] = old_parameters[i]; stmt->parameters[i] = old_parameters[i];
} }
@ -90,13 +85,9 @@ SQLBindParameter(
if(old_parameters) if(old_parameters)
free(old_parameters); free(old_parameters);
/* /* zero out the newly allocated parameters (in case they skipped some, */
* zero out the newly allocated parameters (in case they skipped
* some,
*/
/* so we don't accidentally try to use them later) */ /* so we don't accidentally try to use them later) */
for (; i < stmt->parameters_allocated; i++) for(; i < stmt->parameters_allocated; i++) {
{
stmt->parameters[i].buflen = 0; stmt->parameters[i].buflen = 0;
stmt->parameters[i].buffer = 0; stmt->parameters[i].buffer = 0;
stmt->parameters[i].used = 0; stmt->parameters[i].used = 0;
@ -112,8 +103,7 @@ SQLBindParameter(
} }
} }
ipar--; /* use zero based column numbers for the ipar--; /* use zero based column numbers for the below part */
* below part */
/* store the given info */ /* store the given info */
stmt->parameters[ipar].buflen = cbValueMax; stmt->parameters[ipar].buflen = cbValueMax;
@ -125,18 +115,15 @@ SQLBindParameter(
stmt->parameters[ipar].precision = cbColDef; stmt->parameters[ipar].precision = cbColDef;
stmt->parameters[ipar].scale = ibScale; stmt->parameters[ipar].scale = ibScale;
/* /* If rebinding a parameter that had data-at-exec stuff in it,
* If rebinding a parameter that had data-at-exec stuff in it, then then free that stuff
* free that stuff
*/ */
if (stmt->parameters[ipar].EXEC_used) if (stmt->parameters[ipar].EXEC_used) {
{
free(stmt->parameters[ipar].EXEC_used); free(stmt->parameters[ipar].EXEC_used);
stmt->parameters[ipar].EXEC_used = NULL; stmt->parameters[ipar].EXEC_used = NULL;
} }
if (stmt->parameters[ipar].EXEC_buffer) if (stmt->parameters[ipar].EXEC_buffer) {
{
if (stmt->parameters[ipar].SQLType != SQL_LONGVARBINARY) if (stmt->parameters[ipar].SQLType != SQL_LONGVARBINARY)
free(stmt->parameters[ipar].EXEC_buffer); free(stmt->parameters[ipar].EXEC_buffer);
stmt->parameters[ipar].EXEC_buffer = NULL; stmt->parameters[ipar].EXEC_buffer = NULL;
@ -156,8 +143,7 @@ SQLBindParameter(
/* - - - - - - - - - */ /* - - - - - - - - - */
/* Associate a user-supplied buffer with a database column. */ /* Associate a user-supplied buffer with a database column. */
RETCODE SQL_API RETCODE SQL_API SQLBindCol(
SQLBindCol(
HSTMT hstmt, HSTMT hstmt,
UWORD icol, UWORD icol,
SWORD fCType, SWORD fCType,
@ -172,8 +158,7 @@ SQLBindCol(
mylog("**** SQLBindCol: stmt = %u, icol = %d\n", stmt, icol); mylog("**** SQLBindCol: stmt = %u, icol = %d\n", stmt, icol);
if (!stmt) if ( ! stmt) {
{
SC_log_error(func, "", NULL); SC_log_error(func, "", NULL);
return SQL_INVALID_HANDLE; return SQL_INVALID_HANDLE;
} }
@ -181,8 +166,7 @@ SQLBindCol(
SC_clear_error(stmt); SC_clear_error(stmt);
if (stmt->status == STMT_EXECUTING) if( stmt->status == STMT_EXECUTING) {
{
stmt->errormsg = "Can't bind columns while statement is still executing."; stmt->errormsg = "Can't bind columns while statement is still executing.";
stmt->errornumber = STMT_SEQUENCE_ERROR; stmt->errornumber = STMT_SEQUENCE_ERROR;
SC_log_error(func, "", stmt); SC_log_error(func, "", stmt);
@ -190,18 +174,15 @@ SQLBindCol(
} }
/* If the bookmark column is being bound, then just save it */ /* If the bookmark column is being bound, then just save it */
if (icol == 0) if (icol == 0) {
{
if (rgbValue == NULL) if (rgbValue == NULL) {
{
stmt->bookmark.buffer = NULL; stmt->bookmark.buffer = NULL;
stmt->bookmark.used = NULL; stmt->bookmark.used = NULL;
} }
else else {
{
/* Make sure it is the bookmark data type */ /* Make sure it is the bookmark data type */
if (fCType != SQL_C_BOOKMARK) if ( fCType != SQL_C_BOOKMARK) {
{
stmt->errormsg = "Column 0 is not of type SQL_C_BOOKMARK"; stmt->errormsg = "Column 0 is not of type SQL_C_BOOKMARK";
stmt->errornumber = STMT_PROGRAM_TYPE_OUT_OF_RANGE; stmt->errornumber = STMT_PROGRAM_TYPE_OUT_OF_RANGE;
SC_log_error(func, "", stmt); SC_log_error(func, "", stmt);
@ -222,30 +203,25 @@ SQLBindCol(
extend_bindings(stmt, icol); extend_bindings(stmt, icol);
/* check to see if the bindings were allocated */ /* check to see if the bindings were allocated */
if (!stmt->bindings) if ( ! stmt->bindings) {
{
stmt->errormsg = "Could not allocate memory for bindings."; stmt->errormsg = "Could not allocate memory for bindings.";
stmt->errornumber = STMT_NO_MEMORY_ERROR; stmt->errornumber = STMT_NO_MEMORY_ERROR;
SC_log_error(func, "", stmt); SC_log_error(func, "", stmt);
return SQL_ERROR; return SQL_ERROR;
} }
icol--; /* use zero based col numbers from here icol--; /* use zero based col numbers from here out */
* out */
/* Reset for SQLGetData */ /* Reset for SQLGetData */
stmt->bindings[icol].data_left = -1; stmt->bindings[icol].data_left = -1;
if (rgbValue == NULL) if (rgbValue == NULL) {
{
/* we have to unbind the column */ /* we have to unbind the column */
stmt->bindings[icol].buflen = 0; stmt->bindings[icol].buflen = 0;
stmt->bindings[icol].buffer = NULL; stmt->bindings[icol].buffer = NULL;
stmt->bindings[icol].used = NULL; stmt->bindings[icol].used = NULL;
stmt->bindings[icol].returntype = SQL_C_CHAR; stmt->bindings[icol].returntype = SQL_C_CHAR;
} } else {
else
{
/* ok, bind that column */ /* ok, bind that column */
stmt->bindings[icol].buflen = cbValueMax; stmt->bindings[icol].buflen = cbValueMax;
stmt->bindings[icol].buffer = rgbValue; stmt->bindings[icol].buffer = rgbValue;
@ -267,8 +243,7 @@ SQLBindCol(
/* it is best to say this function is not supported and let the application assume a */ /* it is best to say this function is not supported and let the application assume a */
/* data type (most likely varchar). */ /* data type (most likely varchar). */
RETCODE SQL_API RETCODE SQL_API SQLDescribeParam(
SQLDescribeParam(
HSTMT hstmt, HSTMT hstmt,
UWORD ipar, UWORD ipar,
SWORD FAR *pfSqlType, SWORD FAR *pfSqlType,
@ -281,14 +256,12 @@ SQLDescribeParam(
mylog( "%s: entering...\n", func); mylog( "%s: entering...\n", func);
if (!stmt) if( ! stmt) {
{
SC_log_error(func, "", NULL); SC_log_error(func, "", NULL);
return SQL_INVALID_HANDLE; return SQL_INVALID_HANDLE;
} }
if ((ipar < 1) || (ipar > stmt->parameters_allocated)) if( (ipar < 1) || (ipar > stmt->parameters_allocated) ) {
{
stmt->errormsg = "Invalid parameter number for SQLDescribeParam."; stmt->errormsg = "Invalid parameter number for SQLDescribeParam.";
stmt->errornumber = STMT_BAD_PARAMETER_NUMBER_ERROR; stmt->errornumber = STMT_BAD_PARAMETER_NUMBER_ERROR;
SC_log_error(func, "", stmt); SC_log_error(func, "", stmt);
@ -297,10 +270,7 @@ SQLDescribeParam(
ipar--; ipar--;
/* /* This implementation is not very good, since it is supposed to describe */
* This implementation is not very good, since it is supposed to
* describe
*/
/* parameter markers, not bound parameters. */ /* parameter markers, not bound parameters. */
if(pfSqlType) if(pfSqlType)
*pfSqlType = stmt->parameters[ipar].SQLType; *pfSqlType = stmt->parameters[ipar].SQLType;
@ -321,8 +291,7 @@ SQLDescribeParam(
/* Sets multiple values (arrays) for the set of parameter markers. */ /* Sets multiple values (arrays) for the set of parameter markers. */
RETCODE SQL_API RETCODE SQL_API SQLParamOptions(
SQLParamOptions(
HSTMT hstmt, HSTMT hstmt,
UDWORD crow, UDWORD crow,
UDWORD FAR *pirow) UDWORD FAR *pirow)
@ -344,8 +313,7 @@ SQLParamOptions(
/* like it does for SQLDescribeParam is that some applications don't care and try */ /* like it does for SQLDescribeParam is that some applications don't care and try */
/* to call it anyway. */ /* to call it anyway. */
/* If the statement does not have parameters, it should just return 0. */ /* If the statement does not have parameters, it should just return 0. */
RETCODE SQL_API RETCODE SQL_API SQLNumParams(
SQLNumParams(
HSTMT hstmt, HSTMT hstmt,
SWORD FAR *pcpar) SWORD FAR *pcpar)
{ {
@ -356,37 +324,32 @@ SQLNumParams(
mylog( "%s: entering...\n", func); mylog( "%s: entering...\n", func);
if (!stmt) if(!stmt) {
{
SC_log_error(func, "", NULL); SC_log_error(func, "", NULL);
return SQL_INVALID_HANDLE; return SQL_INVALID_HANDLE;
} }
if (pcpar) if (pcpar)
*pcpar = 0; *pcpar = 0;
else else {
{
SC_log_error(func, "pcpar was null", stmt); SC_log_error(func, "pcpar was null", stmt);
return SQL_ERROR; return SQL_ERROR;
} }
if (!stmt->statement) if(!stmt->statement) {
{
/* no statement has been allocated */ /* no statement has been allocated */
stmt->errormsg = "SQLNumParams called with no statement ready."; stmt->errormsg = "SQLNumParams called with no statement ready.";
stmt->errornumber = STMT_SEQUENCE_ERROR; stmt->errornumber = STMT_SEQUENCE_ERROR;
SC_log_error(func, "", stmt); SC_log_error(func, "", stmt);
return SQL_ERROR; return SQL_ERROR;
} } else {
else
{ for(i=0; i < strlen(stmt->statement); i++) {
for (i = 0; i < strlen(stmt->statement); i++)
{
if(stmt->statement[i] == '?' && !in_quote) if(stmt->statement[i] == '?' && !in_quote)
(*pcpar)++; (*pcpar)++;
else else {
{
if (stmt->statement[i] == '\'') if (stmt->statement[i] == '\'')
in_quote = (in_quote ? FALSE : TRUE); in_quote = (in_quote ? FALSE : TRUE);
} }
@ -406,11 +369,11 @@ create_empty_bindings(int num_columns)
int i; int i;
new_bindings = (BindInfoClass *)malloc(num_columns * sizeof(BindInfoClass)); new_bindings = (BindInfoClass *)malloc(num_columns * sizeof(BindInfoClass));
if (!new_bindings) if(!new_bindings) {
return 0; return 0;
}
for (i = 0; i < num_columns; i++) for(i=0; i < num_columns; i++) {
{
new_bindings[i].buflen = 0; new_bindings[i].buflen = 0;
new_bindings[i].buffer = NULL; new_bindings[i].buffer = NULL;
new_bindings[i].used = NULL; new_bindings[i].used = NULL;
@ -431,15 +394,13 @@ extend_bindings(StatementClass *stmt, int num_columns)
/* if we have too few, allocate room for more, and copy the old */ /* if we have too few, allocate room for more, and copy the old */
/* entries into the new structure */ /* entries into the new structure */
if (stmt->bindings_allocated < num_columns) if(stmt->bindings_allocated < num_columns) {
{
new_bindings = create_empty_bindings(num_columns); new_bindings = create_empty_bindings(num_columns);
if (!new_bindings) if ( ! new_bindings) {
{
mylog("%s: unable to create %d new bindings from %d old bindings\n", func, num_columns, stmt->bindings_allocated); mylog("%s: unable to create %d new bindings from %d old bindings\n", func, num_columns, stmt->bindings_allocated);
if (stmt->bindings) if (stmt->bindings) {
{
free(stmt->bindings); free(stmt->bindings);
stmt->bindings = NULL; stmt->bindings = NULL;
} }
@ -447,8 +408,7 @@ extend_bindings(StatementClass *stmt, int num_columns)
return; return;
} }
if (stmt->bindings) if(stmt->bindings) {
{
for(i=0; i<stmt->bindings_allocated; i++) for(i=0; i<stmt->bindings_allocated; i++)
new_bindings[i] = stmt->bindings[i]; new_bindings[i] = stmt->bindings[i];
@ -457,6 +417,7 @@ extend_bindings(StatementClass *stmt, int num_columns)
stmt->bindings = new_bindings; stmt->bindings = new_bindings;
stmt->bindings_allocated = num_columns; stmt->bindings_allocated = num_columns;
} }
/* There is no reason to zero out extra bindings if there are */ /* There is no reason to zero out extra bindings if there are */
/* more than needed. If an app has allocated extra bindings, */ /* more than needed. If an app has allocated extra bindings, */

@ -15,24 +15,18 @@
/* /*
* BindInfoClass -- stores information about a bound column * BindInfoClass -- stores information about a bound column
*/ */
struct BindInfoClass_ struct BindInfoClass_ {
{
Int4 buflen; /* size of buffer */ Int4 buflen; /* size of buffer */
Int4 data_left; /* amount of data left to read Int4 data_left; /* amount of data left to read (SQLGetData) */
* (SQLGetData) */
char *buffer; /* pointer to the buffer */ char *buffer; /* pointer to the buffer */
Int4 *used; /* used space in the buffer (for strings Int4 *used; /* used space in the buffer (for strings not counting the '\0') */
* not counting the '\0') */ Int2 returntype; /* kind of conversion to be applied when returning (SQL_C_DEFAULT, SQL_C_CHAR...) */
Int2 returntype; /* kind of conversion to be applied when
* returning (SQL_C_DEFAULT,
* SQL_C_CHAR...) */
}; };
/* /*
* ParameterInfoClass -- stores information about a bound parameter * ParameterInfoClass -- stores information about a bound parameter
*/ */
struct ParameterInfoClass_ struct ParameterInfoClass_ {
{
Int4 buflen; Int4 buflen;
char *buffer; char *buffer;
Int4 *used; Int4 *used;
@ -42,8 +36,7 @@ struct ParameterInfoClass_
UInt4 precision; UInt4 precision;
Int2 scale; Int2 scale;
Oid lobj_oid; Oid lobj_oid;
Int4 *EXEC_used; /* amount of data OR the oid of the large Int4 *EXEC_used; /* amount of data OR the oid of the large object */
* object */
char *EXEC_buffer; /* the data or the FD of the large object */ char *EXEC_buffer; /* the data or the FD of the large object */
char data_at_exec; char data_at_exec;
}; };

@ -1,3 +1,4 @@
/* Module: columninfo.c /* Module: columninfo.c
* *
* Description: This module contains routines related to * Description: This module contains routines related to
@ -24,8 +25,7 @@ CI_Constructor()
rv = (ColumnInfoClass *) malloc(sizeof(ColumnInfoClass)); rv = (ColumnInfoClass *) malloc(sizeof(ColumnInfoClass));
if (rv) if (rv) {
{
rv->num_fields = 0; rv->num_fields = 0;
rv->name = NULL; rv->name = NULL;
rv->adtid = NULL; rv->adtid = NULL;
@ -69,21 +69,20 @@ CI_read_fields(ColumnInfoClass *self, ConnectionClass *conn)
mylog("num_fields = %d\n", new_num_fields); mylog("num_fields = %d\n", new_num_fields);
if (self) if (self) { /* according to that allocate memory */
{ /* according to that allocate memory */
CI_set_num_fields(self, new_num_fields); CI_set_num_fields(self, new_num_fields);
} }
/* now read in the descriptions */ /* now read in the descriptions */
for (lf = 0; lf < new_num_fields; lf++) for(lf = 0; lf < new_num_fields; lf++) {
{
SOCK_get_string(sock, new_field_name, MAX_MESSAGE_LEN); SOCK_get_string(sock, new_field_name, MAX_MESSAGE_LEN);
new_adtid = (Oid) SOCK_get_int(sock, 4); new_adtid = (Oid) SOCK_get_int(sock, 4);
new_adtsize = (Int2) SOCK_get_int(sock, 2); new_adtsize = (Int2) SOCK_get_int(sock, 2);
/* If 6.4 protocol, then read the atttypmod field */ /* If 6.4 protocol, then read the atttypmod field */
if (PG_VERSION_GE(conn, 6.4)) if (PG_VERSION_GE(conn, 6.4)) {
{
mylog("READING ATTTYPMOD\n"); mylog("READING ATTTYPMOD\n");
new_atttypmod = (Int4) SOCK_get_int(sock, 4); new_atttypmod = (Int4) SOCK_get_int(sock, 4);
@ -91,6 +90,7 @@ CI_read_fields(ColumnInfoClass *self, ConnectionClass *conn)
new_atttypmod -= 4; new_atttypmod -= 4;
if (new_atttypmod < 0) if (new_atttypmod < 0)
new_atttypmod = -1; new_atttypmod = -1;
} }
mylog("CI_read_fields: fieldname='%s', adtid=%d, adtsize=%d, atttypmod=%d\n", new_field_name, new_adtid, new_adtsize, new_atttypmod); mylog("CI_read_fields: fieldname='%s', adtid=%d, adtsize=%d, atttypmod=%d\n", new_field_name, new_adtid, new_adtsize, new_atttypmod);
@ -110,8 +110,7 @@ CI_free_memory(ColumnInfoClass *self)
register Int2 lf; register Int2 lf;
int num_fields = self->num_fields; int num_fields = self->num_fields;
for (lf = 0; lf < num_fields; lf++) for (lf = 0; lf < num_fields; lf++) {
{
if( self->name[lf]) if( self->name[lf])
free (self->name[lf]); free (self->name[lf]);
} }
@ -143,9 +142,11 @@ void
CI_set_field_info(ColumnInfoClass *self, int field_num, char *new_name, CI_set_field_info(ColumnInfoClass *self, int field_num, char *new_name,
Oid new_adtid, Int2 new_adtsize, Int4 new_atttypmod) Oid new_adtid, Int2 new_adtsize, Int4 new_atttypmod)
{ {
/* check bounds */ /* check bounds */
if ((field_num < 0) || (field_num >= self->num_fields)) if((field_num < 0) || (field_num >= self->num_fields)) {
return; return;
}
/* store the info */ /* store the info */
self->name[field_num] = strdup(new_name); self->name[field_num] = strdup(new_name);
@ -155,3 +156,4 @@ CI_set_field_info(ColumnInfoClass *self, int field_num, char *new_name,
self->display_size[field_num] = 0; self->display_size[field_num] = 0;
} }

@ -12,8 +12,7 @@
#include "psqlodbc.h" #include "psqlodbc.h"
struct ColumnInfoClass_ struct ColumnInfoClass_ {
{
Int2 num_fields; Int2 num_fields;
char **name; /* list of type names */ char **name; /* list of type names */
Oid *adtid; /* list of type ids */ Oid *adtid; /* list of type ids */

File diff suppressed because it is too large Load Diff

@ -27,14 +27,11 @@
#endif #endif
typedef enum typedef enum {
{
CONN_NOT_CONNECTED, /* Connection has not been established */ CONN_NOT_CONNECTED, /* Connection has not been established */
CONN_CONNECTED, /* Connection is up and has been CONN_CONNECTED, /* Connection is up and has been established */
* established */
CONN_DOWN, /* Connection is broken */ CONN_DOWN, /* Connection is broken */
CONN_EXECUTING /* the connection is currently executing a CONN_EXECUTING /* the connection is currently executing a statement */
* statement */
} CONN_Status; } CONN_Status;
/* These errors have general sql error state */ /* These errors have general sql error state */
@ -109,8 +106,10 @@ typedef unsigned int ProtocolVersion;
#define PG_PROTOCOL(major, minor) (((major) << 16) | (minor)) #define PG_PROTOCOL(major, minor) (((major) << 16) | (minor))
#define PG_PROTOCOL_LATEST PG_PROTOCOL(2, 0) #define PG_PROTOCOL_LATEST PG_PROTOCOL(2, 0)
#define PG_PROTOCOL_63 PG_PROTOCOL(1, 0)
#define PG_PROTOCOL_62 PG_PROTOCOL(0, 0)
/* This startup packet is to support latest Postgres protocol */ /* This startup packet is to support latest Postgres protocol (6.4, 6.3) */
typedef struct _StartupPacket typedef struct _StartupPacket
{ {
ProtocolVersion protoVersion; ProtocolVersion protoVersion;
@ -122,11 +121,22 @@ typedef struct _StartupPacket
} StartupPacket; } StartupPacket;
/* This startup packet is to support pre-Postgres 6.3 protocol */
typedef struct _StartupPacket6_2
{
unsigned int authtype;
char database[PATH_SIZE];
char user[NAMEDATALEN];
char options[ARGV_SIZE];
char execfile[ARGV_SIZE];
char tty[PATH_SIZE];
} StartupPacket6_2;
/* Structure to hold all the connection attributes for a specific /* Structure to hold all the connection attributes for a specific
connection (used for both registry and file, DSN and DRIVER) connection (used for both registry and file, DSN and DRIVER)
*/ */
typedef struct typedef struct {
{
char dsn[MEDIUM_REGISTRY_LEN]; char dsn[MEDIUM_REGISTRY_LEN];
char desc[MEDIUM_REGISTRY_LEN]; char desc[MEDIUM_REGISTRY_LEN];
char driver[MEDIUM_REGISTRY_LEN]; char driver[MEDIUM_REGISTRY_LEN];
@ -147,6 +157,12 @@ typedef struct
char focus_password; char focus_password;
} ConnInfo; } ConnInfo;
/* Macro to determine is the connection using 6.2 protocol? */
#define PROTOCOL_62(conninfo_) (strncmp((conninfo_)->protocol, PG62, strlen(PG62)) == 0)
/* Macro to determine is the connection using 6.3 protocol? */
#define PROTOCOL_63(conninfo_) (strncmp((conninfo_)->protocol, PG63, strlen(PG63)) == 0)
/* /*
* Macros to compare the server's version with a specified version * Macros to compare the server's version with a specified version
* 1st parameter: pointer to a ConnectionClass object * 1st parameter: pointer to a ConnectionClass object
@ -184,8 +200,7 @@ typedef struct
#define PG_VERSION_LT(conn, ver) (! PG_VERSION_GE(conn, ver)) #define PG_VERSION_LT(conn, ver) (! PG_VERSION_GE(conn, ver))
/* This is used to store cached table information in the connection */ /* This is used to store cached table information in the connection */
struct col_info struct col_info {
{
QResultClass *result; QResultClass *result;
char name[MAX_TABLE_LEN+1]; char name[MAX_TABLE_LEN+1];
}; };
@ -222,10 +237,8 @@ typedef BOOL (FAR WINAPI * DriverToDataSourceProc) (UDWORD,
SWORD FAR *); SWORD FAR *);
/******* The Connection handle ************/ /******* The Connection handle ************/
struct ConnectionClass_ struct ConnectionClass_ {
{ HENV henv; /* environment this connection was created on */
HENV henv; /* environment this connection was created
* on */
StatementOptions stmtOptions; StatementOptions stmtOptions;
char *errormsg; char *errormsg;
int errornumber; int errornumber;
@ -241,13 +254,9 @@ struct ConnectionClass_
HINSTANCE translation_handle; HINSTANCE translation_handle;
DataSourceToDriverProc DataSourceToDriver; DataSourceToDriverProc DataSourceToDriver;
DriverToDataSourceProc DriverToDataSource; DriverToDataSourceProc DriverToDataSource;
char transact_status;/* Is a transaction is currently in char transact_status; /* Is a transaction is currently in progress */
* progress */ char errormsg_created; /* has an informative error msg been created? */
char errormsg_created; /* has an informative error msg char pg_version[MAX_INFO_STRING]; /* Version of PostgreSQL we're connected to - DJP 25-1-2001 */
* been created? */
char pg_version[MAX_INFO_STRING]; /* Version of PostgreSQL
* we're connected to -
* DJP 25-1-2001 */
float pg_version_number; float pg_version_number;
Int2 pg_version_major; Int2 pg_version_major;
Int2 pg_version_minor; Int2 pg_version_minor;

File diff suppressed because it is too large Load Diff

@ -20,8 +20,7 @@
#define COPY_GENERAL_ERROR 4 #define COPY_GENERAL_ERROR 4
#define COPY_NO_DATA_FOUND 5 #define COPY_NO_DATA_FOUND 5
typedef struct typedef struct {
{
int m; int m;
int d; int d;
int y; int y;

@ -1,3 +1,4 @@
/* Module: dlg_specific.c /* Module: dlg_specific.c
* *
* Description: This module contains any specific code for handling * Description: This module contains any specific code for handling
@ -49,13 +50,8 @@ extern GLOBAL_VALUES globals;
void void
SetDlgStuff(HWND hdlg, ConnInfo *ci) SetDlgStuff(HWND hdlg, ConnInfo *ci)
{ {
/* If driver attribute NOT present, then set the datasource name and description */
/* if (ci->driver[0] == '\0') {
* If driver attribute NOT present, then set the datasource name and
* description
*/
if (ci->driver[0] == '\0')
{
SetDlgItemText(hdlg, IDC_DSNAME, ci->dsn); SetDlgItemText(hdlg, IDC_DSNAME, ci->dsn);
SetDlgItemText(hdlg, IDC_DESC, ci->desc); SetDlgItemText(hdlg, IDC_DESC, ci->desc);
} }
@ -81,14 +77,12 @@ GetDlgStuff(HWND hdlg, ConnInfo *ci)
int CALLBACK int CALLBACK driver_optionsProc(HWND hdlg,
driver_optionsProc(HWND hdlg,
WORD wMsg, WORD wMsg,
WPARAM wParam, WPARAM wParam,
LPARAM lParam) LPARAM lParam)
{ {
switch (wMsg) switch (wMsg) {
{
case WM_INITDIALOG: case WM_INITDIALOG:
CheckDlgButton(hdlg, DRV_COMMLOG, globals.commlog); CheckDlgButton(hdlg, DRV_COMMLOG, globals.commlog);
@ -99,8 +93,7 @@ driver_optionsProc(HWND hdlg,
CheckDlgButton(hdlg, DRV_USEDECLAREFETCH, globals.use_declarefetch); CheckDlgButton(hdlg, DRV_USEDECLAREFETCH, globals.use_declarefetch);
/* Unknown (Default) Data Type sizes */ /* Unknown (Default) Data Type sizes */
switch (globals.unknown_sizes) switch(globals.unknown_sizes) {
{
case UNKNOWNS_AS_DONTKNOW: case UNKNOWNS_AS_DONTKNOW:
CheckDlgButton(hdlg, DRV_UNKNOWN_DONTKNOW, 1); CheckDlgButton(hdlg, DRV_UNKNOWN_DONTKNOW, 1);
break; break;
@ -133,8 +126,7 @@ driver_optionsProc(HWND hdlg,
break; break;
case WM_COMMAND: case WM_COMMAND:
switch (GET_WM_COMMAND_ID(wParam, lParam)) switch (GET_WM_COMMAND_ID(wParam, lParam)) {
{
case IDOK: case IDOK:
globals.commlog = IsDlgButtonChecked(hdlg, DRV_COMMLOG); globals.commlog = IsDlgButtonChecked(hdlg, DRV_COMMLOG);
@ -164,8 +156,7 @@ driver_optionsProc(HWND hdlg,
globals.fetch_max = GetDlgItemInt(hdlg, DRV_CACHE_SIZE, NULL, FALSE); globals.fetch_max = GetDlgItemInt(hdlg, DRV_CACHE_SIZE, NULL, FALSE);
globals.max_varchar_size = GetDlgItemInt(hdlg, DRV_VARCHAR_SIZE, NULL, FALSE); globals.max_varchar_size = GetDlgItemInt(hdlg, DRV_VARCHAR_SIZE, NULL, FALSE);
globals.max_longvarchar_size = GetDlgItemInt(hdlg, DRV_LONGVARCHAR_SIZE, NULL, TRUE); /* allows for globals.max_longvarchar_size= GetDlgItemInt(hdlg, DRV_LONGVARCHAR_SIZE, NULL, TRUE); /* allows for SQL_NO_TOTAL */
* SQL_NO_TOTAL */
GetDlgItemText(hdlg, DRV_EXTRASYSTABLEPREFIXES, globals.extra_systable_prefixes, sizeof(globals.extra_systable_prefixes)); GetDlgItemText(hdlg, DRV_EXTRASYSTABLEPREFIXES, globals.extra_systable_prefixes, sizeof(globals.extra_systable_prefixes));
@ -195,8 +186,7 @@ driver_optionsProc(HWND hdlg,
CheckDlgButton(hdlg, DRV_UNKNOWN_DONTKNOW, 0); CheckDlgButton(hdlg, DRV_UNKNOWN_DONTKNOW, 0);
CheckDlgButton(hdlg, DRV_UNKNOWN_LONGEST, 0); CheckDlgButton(hdlg, DRV_UNKNOWN_LONGEST, 0);
CheckDlgButton(hdlg, DRV_UNKNOWN_MAX, 0); CheckDlgButton(hdlg, DRV_UNKNOWN_MAX, 0);
switch (DEFAULT_UNKNOWNSIZES) switch(DEFAULT_UNKNOWNSIZES) {
{
case UNKNOWNS_AS_DONTKNOW: case UNKNOWNS_AS_DONTKNOW:
CheckDlgButton(hdlg, DRV_UNKNOWN_DONTKNOW, 1); CheckDlgButton(hdlg, DRV_UNKNOWN_DONTKNOW, 1);
break; break;
@ -223,13 +213,13 @@ driver_optionsProc(HWND hdlg,
break; break;
} }
} }
return FALSE; return FALSE;
} }
int CALLBACK int CALLBACK ds_optionsProc(HWND hdlg,
ds_optionsProc(HWND hdlg,
WORD wMsg, WORD wMsg,
WPARAM wParam, WPARAM wParam,
LPARAM lParam) LPARAM lParam)
@ -237,8 +227,7 @@ ds_optionsProc(HWND hdlg,
ConnInfo *ci; ConnInfo *ci;
char buf[128]; char buf[128];
switch (wMsg) switch (wMsg) {
{
case WM_INITDIALOG: case WM_INITDIALOG:
ci = (ConnInfo *) lParam; ci = (ConnInfo *) lParam;
SetWindowLong(hdlg, DWL_USER, lParam); /* save for OK */ SetWindowLong(hdlg, DWL_USER, lParam); /* save for OK */
@ -246,8 +235,7 @@ ds_optionsProc(HWND hdlg,
/* Change window caption */ /* Change window caption */
if (ci->driver[0]) if (ci->driver[0])
SetWindowText(hdlg, "Advanced Options (Connection)"); SetWindowText(hdlg, "Advanced Options (Connection)");
else else {
{
sprintf(buf, "Advanced Options (%s)", ci->dsn); sprintf(buf, "Advanced Options (%s)", ci->dsn);
SetWindowText(hdlg, buf); SetWindowText(hdlg, buf);
} }
@ -256,6 +244,11 @@ ds_optionsProc(HWND hdlg,
CheckDlgButton(hdlg, DS_READONLY, atoi(ci->onlyread)); CheckDlgButton(hdlg, DS_READONLY, atoi(ci->onlyread));
/* Protocol */ /* Protocol */
if (strncmp(ci->protocol, PG62, strlen(PG62)) == 0)
CheckDlgButton(hdlg, DS_PG62, 1);
else if (strncmp(ci->protocol, PG63, strlen(PG63)) == 0)
CheckDlgButton(hdlg, DS_PG63, 1);
else /* latest */
CheckDlgButton(hdlg, DS_PG64, 1); CheckDlgButton(hdlg, DS_PG64, 1);
@ -273,8 +266,7 @@ ds_optionsProc(HWND hdlg,
case WM_COMMAND: case WM_COMMAND:
switch (GET_WM_COMMAND_ID(wParam, lParam)) switch (GET_WM_COMMAND_ID(wParam, lParam)) {
{
case DS_SHOWOIDCOLUMN: case DS_SHOWOIDCOLUMN:
mylog("WM_COMMAND: DS_SHOWOIDCOLUMN\n"); mylog("WM_COMMAND: DS_SHOWOIDCOLUMN\n");
EnableWindow(GetDlgItem(hdlg, DS_FAKEOIDINDEX), IsDlgButtonChecked(hdlg, DS_SHOWOIDCOLUMN)); EnableWindow(GetDlgItem(hdlg, DS_FAKEOIDINDEX), IsDlgButtonChecked(hdlg, DS_SHOWOIDCOLUMN));
@ -290,6 +282,11 @@ ds_optionsProc(HWND hdlg,
sprintf(ci->onlyread, "%d", IsDlgButtonChecked(hdlg, DS_READONLY)); sprintf(ci->onlyread, "%d", IsDlgButtonChecked(hdlg, DS_READONLY));
/* Protocol */ /* Protocol */
if ( IsDlgButtonChecked(hdlg, DS_PG62))
strcpy(ci->protocol, PG62);
else if ( IsDlgButtonChecked(hdlg, DS_PG63))
strcpy(ci->protocol, PG63);
else /* latest */
strcpy(ci->protocol, PG64); strcpy(ci->protocol, PG64);
sprintf(ci->show_system_tables, "%d", IsDlgButtonChecked(hdlg, DS_SHOWSYSTEMTABLES)); sprintf(ci->show_system_tables, "%d", IsDlgButtonChecked(hdlg, DS_SHOWSYSTEMTABLES));
@ -350,6 +347,7 @@ makeConnectString(char *connect_string, ConnInfo *ci)
void void
copyAttributes(ConnInfo *ci, char *attribute, char *value) copyAttributes(ConnInfo *ci, char *attribute, char *value)
{ {
if(stricmp(attribute, "DSN") == 0) if(stricmp(attribute, "DSN") == 0)
strcpy(ci->dsn, value); strcpy(ci->dsn, value);
@ -389,13 +387,13 @@ copyAttributes(ConnInfo *ci, char *attribute, char *value)
else if (stricmp(attribute, INI_SHOWSYSTEMTABLES) == 0) else if (stricmp(attribute, INI_SHOWSYSTEMTABLES) == 0)
strcpy(ci->show_system_tables, value); strcpy(ci->show_system_tables, value);
else if (stricmp(attribute, INI_CONNSETTINGS) == 0) else if (stricmp(attribute, INI_CONNSETTINGS) == 0) {
{
decode(value, ci->conn_settings); decode(value, ci->conn_settings);
/* strcpy(ci->conn_settings, value); */ /* strcpy(ci->conn_settings, value); */
} }
mylog("copyAttributes: DSN='%s',server='%s',dbase='%s',user='%s',passwd='%s',port='%s',onlyread='%s',protocol='%s', conn_settings='%s')\n", ci->dsn, ci->server,ci->database,ci->username,ci->password,ci->port,ci->onlyread,ci->protocol,ci->conn_settings); mylog("copyAttributes: DSN='%s',server='%s',dbase='%s',user='%s',passwd='%s',port='%s',onlyread='%s',protocol='%s', conn_settings='%s')\n", ci->dsn, ci->server,ci->database,ci->username,ci->password,ci->port,ci->onlyread,ci->protocol,ci->conn_settings);
} }
void void
@ -432,8 +430,7 @@ getDSNinfo(ConnInfo *ci, char overwrite)
/* If a driver keyword was present, then dont use a DSN and return. */ /* If a driver keyword was present, then dont use a DSN and return. */
/* If DSN is null and no driver, then use the default datasource. */ /* If DSN is null and no driver, then use the default datasource. */
if (DSN[0] == '\0') if ( DSN[0] == '\0') {
{
if ( ci->driver[0] != '\0') if ( ci->driver[0] != '\0')
return; return;
else else
@ -441,8 +438,7 @@ getDSNinfo(ConnInfo *ci, char overwrite)
} }
/* brute-force chop off trailing blanks... */ /* brute-force chop off trailing blanks... */
while (*(DSN + strlen(DSN) - 1) == ' ') while (*(DSN+strlen(DSN)-1) == ' ') *(DSN+strlen(DSN)-1) = '\0';
*(DSN + strlen(DSN) - 1) = '\0';
/* Proceed with getting info for the given DSN. */ /* Proceed with getting info for the given DSN. */
@ -482,8 +478,7 @@ getDSNinfo(ConnInfo *ci, char overwrite)
if ( ci->protocol[0] == '\0' || overwrite) if ( ci->protocol[0] == '\0' || overwrite)
SQLGetPrivateProfileString(DSN, INI_PROTOCOL, "", ci->protocol, sizeof(ci->protocol), ODBC_INI); SQLGetPrivateProfileString(DSN, INI_PROTOCOL, "", ci->protocol, sizeof(ci->protocol), ODBC_INI);
if (ci->conn_settings[0] == '\0' || overwrite) if ( ci->conn_settings[0] == '\0' || overwrite) {
{
SQLGetPrivateProfileString(DSN, INI_CONNSETTINGS, "", encoded_conn_settings, sizeof(encoded_conn_settings), ODBC_INI); SQLGetPrivateProfileString(DSN, INI_CONNSETTINGS, "", encoded_conn_settings, sizeof(encoded_conn_settings), ODBC_INI);
decode(encoded_conn_settings, ci->conn_settings); decode(encoded_conn_settings, ci->conn_settings);
} }
@ -517,6 +512,7 @@ getDSNinfo(ConnInfo *ci, char overwrite)
qlog(" translation_dll='%s',translation_option='%s'\n", qlog(" translation_dll='%s',translation_option='%s'\n",
ci->translation_dll, ci->translation_dll,
ci->translation_option); ci->translation_option);
} }
@ -599,8 +595,7 @@ writeDSNinfo(ConnInfo *ci)
/* This function reads the ODBCINST.INI portion of /* This function reads the ODBCINST.INI portion of
the registry and gets any driver defaults. the registry and gets any driver defaults.
*/ */
void void getGlobalDefaults(char *section, char *filename, char override)
getGlobalDefaults(char *section, char *filename, char override)
{ {
char temp[256]; char temp[256];
@ -608,8 +603,7 @@ getGlobalDefaults(char *section, char *filename, char override)
/* Fetch Count is stored in driver section */ /* Fetch Count is stored in driver section */
SQLGetPrivateProfileString(section, INI_FETCH, "", SQLGetPrivateProfileString(section, INI_FETCH, "",
temp, sizeof(temp), filename); temp, sizeof(temp), filename);
if (temp[0]) if ( temp[0] ) {
{
globals.fetch_max = atoi(temp); globals.fetch_max = atoi(temp);
/* sanity check if using cursors */ /* sanity check if using cursors */
if (globals.fetch_max <= 0) if (globals.fetch_max <= 0)
@ -756,11 +750,7 @@ getGlobalDefaults(char *section, char *filename, char override)
globals.bools_as_char = DEFAULT_BOOLSASCHAR; globals.bools_as_char = DEFAULT_BOOLSASCHAR;
/* Extra Systable prefixes */ /* Extra Systable prefixes */
/* Use @@@ to distinguish between blank extra prefixes and no key entry */
/*
* Use @@@ to distinguish between blank extra prefixes and no key
* entry
*/
SQLGetPrivateProfileString(section, INI_EXTRASYSTABLEPREFIXES, "@@@", SQLGetPrivateProfileString(section, INI_EXTRASYSTABLEPREFIXES, "@@@",
temp, sizeof(temp), filename); temp, sizeof(temp), filename);
if ( strcmp(temp, "@@@" )) if ( strcmp(temp, "@@@" ))
@ -772,13 +762,9 @@ getGlobalDefaults(char *section, char *filename, char override)
/* Dont allow override of an override! */ /* Dont allow override of an override! */
if (!override) if ( ! override) {
{
/* /* ConnSettings is stored in the driver section and per datasource for override */
* ConnSettings is stored in the driver section and per datasource
* for override
*/
SQLGetPrivateProfileString(section, INI_CONNSETTINGS, "", SQLGetPrivateProfileString(section, INI_CONNSETTINGS, "",
globals.conn_settings, sizeof(globals.conn_settings), filename); globals.conn_settings, sizeof(globals.conn_settings), filename);
@ -790,10 +776,9 @@ getGlobalDefaults(char *section, char *filename, char override)
else else
globals.onlyread = DEFAULT_READONLY; globals.onlyread = DEFAULT_READONLY;
/* /* Default state for future DSN's protocol attribute
* Default state for future DSN's protocol attribute This isn't a This isn't a real driver option YET. This is more
* real driver option YET. This is more intended for intended for customization from the install.
* customization from the install.
*/ */
SQLGetPrivateProfileString(section, INI_PROTOCOL, "@@@", SQLGetPrivateProfileString(section, INI_PROTOCOL, "@@@",
temp, sizeof(temp), filename); temp, sizeof(temp), filename);
@ -801,6 +786,7 @@ getGlobalDefaults(char *section, char *filename, char override)
strcpy(globals.protocol, temp); strcpy(globals.protocol, temp);
else else
strcpy(globals.protocol, DEFAULT_PROTOCOL); strcpy(globals.protocol, DEFAULT_PROTOCOL);
} }
} }
@ -808,8 +794,7 @@ getGlobalDefaults(char *section, char *filename, char override)
/* This function writes any global parameters (that can be manipulated) /* This function writes any global parameters (that can be manipulated)
to the ODBCINST.INI portion of the registry to the ODBCINST.INI portion of the registry
*/ */
void void updateGlobals(void)
updateGlobals(void)
{ {
char tmp[128]; char tmp[128];

@ -44,13 +44,10 @@
#endif /* WIN32 */ #endif /* WIN32 */
#define INI_DSN DBMS_NAME /* Name of default Datasource in #define INI_DSN DBMS_NAME /* Name of default Datasource in ini file (not used?) */
* ini file (not used?) */
#define INI_KDESC "Description" /* Data source description */ #define INI_KDESC "Description" /* Data source description */
#define INI_SERVER "Servername" /* Name of Server running #define INI_SERVER "Servername" /* Name of Server running the Postgres service */
* the Postgres service */ #define INI_PORT "Port" /* Port on which the Postmaster is listening */
#define INI_PORT "Port" /* Port on which the Postmaster is
* listening */
#define INI_DATABASE "Database" /* Database Name */ #define INI_DATABASE "Database" /* Database Name */
#define INI_USER "Username" /* Default User Name */ #define INI_USER "Username" /* Default User Name */
#define INI_PASSWORD "Password" /* Default Password */ #define INI_PASSWORD "Password" /* Default Password */
@ -58,23 +55,17 @@
#define INI_FETCH "Fetch" /* Fetch Max Count */ #define INI_FETCH "Fetch" /* Fetch Max Count */
#define INI_SOCKET "Socket" /* Socket buffer size */ #define INI_SOCKET "Socket" /* Socket buffer size */
#define INI_READONLY "ReadOnly" /* Database is read only */ #define INI_READONLY "ReadOnly" /* Database is read only */
#define INI_COMMLOG "CommLog" /* Communication to backend #define INI_COMMLOG "CommLog" /* Communication to backend logging */
* logging */
#define INI_PROTOCOL "Protocol" /* What protocol (6.2) */ #define INI_PROTOCOL "Protocol" /* What protocol (6.2) */
#define INI_OPTIMIZER "Optimizer" /* Use backend genetic optimizer */ #define INI_OPTIMIZER "Optimizer" /* Use backend genetic optimizer */
#define INI_KSQO "Ksqo" /* Keyset query optimization */ #define INI_KSQO "Ksqo" /* Keyset query optimization */
#define INI_CONNSETTINGS "ConnSettings" /* Anything to send to #define INI_CONNSETTINGS "ConnSettings" /* Anything to send to backend on successful connection */
* backend on successful #define INI_UNIQUEINDEX "UniqueIndex" /* Recognize unique indexes */
* connection */ #define INI_UNKNOWNSIZES "UnknownSizes" /* How to handle unknown result set sizes */
#define INI_UNIQUEINDEX "UniqueIndex" /* Recognize unique
* indexes */
#define INI_UNKNOWNSIZES "UnknownSizes" /* How to handle unknown
* result set sizes */
#define INI_CANCELASFREESTMT "CancelAsFreeStmt" #define INI_CANCELASFREESTMT "CancelAsFreeStmt"
#define INI_USEDECLAREFETCH "UseDeclareFetch" /* Use Declare/Fetch #define INI_USEDECLAREFETCH "UseDeclareFetch" /* Use Declare/Fetch cursors */
* cursors */
/* More ini stuff */ /* More ini stuff */
#define INI_TEXTASLONGVARCHAR "TextAsLongVarchar" #define INI_TEXTASLONGVARCHAR "TextAsLongVarchar"
@ -99,8 +90,7 @@
/* Connection Defaults */ /* Connection Defaults */
#define DEFAULT_PORT "5432" #define DEFAULT_PORT "5432"
#define DEFAULT_READONLY 1 #define DEFAULT_READONLY 1
#define DEFAULT_PROTOCOL "6.4" /* the latest protocol is #define DEFAULT_PROTOCOL "6.4" /* the latest protocol is the default */
* the default */
#define DEFAULT_USEDECLAREFETCH 0 #define DEFAULT_USEDECLAREFETCH 0
#define DEFAULT_TEXTASLONGVARCHAR 1 #define DEFAULT_TEXTASLONGVARCHAR 1
#define DEFAULT_UNKNOWNSASLONGVARCHAR 0 #define DEFAULT_UNKNOWNSASLONGVARCHAR 0
@ -139,7 +129,6 @@ int CALLBACK ds_optionsProc(HWND hdlg,
WORD wMsg, WORD wMsg,
WPARAM wParam, WPARAM wParam,
LPARAM lParam); LPARAM lParam);
#endif /* WIN32 */ #endif /* WIN32 */
void updateGlobals(void); void updateGlobals(void);

@ -1,3 +1,4 @@
/* Module: drvconn.c /* Module: drvconn.c
* *
* Description: This module contains only routines related to * Description: This module contains only routines related to
@ -59,14 +60,12 @@ BOOL FAR PASCAL dconn_FDriverConnectProc(HWND hdlg, UINT wMsg, WPARAM wParam, LP
RETCODE dconn_DoDialog(HWND hwnd, ConnInfo *ci); RETCODE dconn_DoDialog(HWND hwnd, ConnInfo *ci);
extern HINSTANCE NEAR s_hModule; /* Saved module handle. */ extern HINSTANCE NEAR s_hModule; /* Saved module handle. */
#endif #endif
extern GLOBAL_VALUES globals; extern GLOBAL_VALUES globals;
RETCODE SQL_API RETCODE SQL_API SQLDriverConnect(
SQLDriverConnect(
HDBC hdbc, HDBC hdbc,
HWND hwnd, HWND hwnd,
UCHAR FAR *szConnStrIn, UCHAR FAR *szConnStrIn,
@ -79,10 +78,8 @@ SQLDriverConnect(
static char *func = "SQLDriverConnect"; static char *func = "SQLDriverConnect";
ConnectionClass *conn = (ConnectionClass *) hdbc; ConnectionClass *conn = (ConnectionClass *) hdbc;
ConnInfo *ci; ConnInfo *ci;
#ifdef WIN32 #ifdef WIN32
RETCODE dialog_result; RETCODE dialog_result;
#endif #endif
RETCODE result; RETCODE result;
char connStrIn[MAX_CONNECT_STRING]; char connStrIn[MAX_CONNECT_STRING];
@ -94,8 +91,7 @@ SQLDriverConnect(
mylog("%s: entering...\n", func); mylog("%s: entering...\n", func);
if (!conn) if ( ! conn) {
{
CC_log_error(func, "", NULL); CC_log_error(func, "", NULL);
return SQL_INVALID_HANDLE; return SQL_INVALID_HANDLE;
} }
@ -125,13 +121,13 @@ dialog:
#endif #endif
ci->focus_password = password_required; ci->focus_password = password_required;
switch (fDriverCompletion) switch(fDriverCompletion) {
{
#ifdef WIN32 #ifdef WIN32
case SQL_DRIVER_PROMPT: case SQL_DRIVER_PROMPT:
dialog_result = dconn_DoDialog(hwnd, ci); dialog_result = dconn_DoDialog(hwnd, ci);
if (dialog_result != SQL_SUCCESS) if(dialog_result != SQL_SUCCESS) {
return dialog_result; return dialog_result;
}
break; break;
case SQL_DRIVER_COMPLETE_REQUIRED: case SQL_DRIVER_COMPLETE_REQUIRED:
@ -145,12 +141,13 @@ dialog:
ci->server[0] == '\0' || ci->server[0] == '\0' ||
ci->database[0] == '\0' || ci->database[0] == '\0' ||
ci->port[0] == '\0' || ci->port[0] == '\0' ||
password_required) password_required) {
{
dialog_result = dconn_DoDialog(hwnd, ci); dialog_result = dconn_DoDialog(hwnd, ci);
if (dialog_result != SQL_SUCCESS) if(dialog_result != SQL_SUCCESS) {
return dialog_result; return dialog_result;
} }
}
break; break;
#else #else
case SQL_DRIVER_PROMPT: case SQL_DRIVER_PROMPT:
@ -161,17 +158,14 @@ dialog:
break; break;
} }
/* /* Password is not a required parameter unless authentication asks for it.
* Password is not a required parameter unless authentication asks for For now, I think it's better to just let the application ask over and over until
* it. For now, I think it's better to just let the application ask a password is entered (the user can always hit Cancel to get out)
* over and over until a password is entered (the user can always hit
* Cancel to get out)
*/ */
if( ci->username[0] == '\0' || if( ci->username[0] == '\0' ||
ci->server[0] == '\0' || ci->server[0] == '\0' ||
ci->database[0] == '\0' || ci->database[0] == '\0' ||
ci->port[0] == '\0') ci->port[0] == '\0') {
{
/* (password_required && ci->password[0] == '\0')) */ /* (password_required && ci->password[0] == '\0')) */
return SQL_NO_DATA_FOUND; return SQL_NO_DATA_FOUND;
@ -180,16 +174,12 @@ dialog:
/* do the actual connect */ /* do the actual connect */
retval = CC_connect(conn, password_required); retval = CC_connect(conn, password_required);
if (retval < 0) if (retval < 0) { /* need a password */
{ /* need a password */ if (fDriverCompletion == SQL_DRIVER_NOPROMPT) {
if (fDriverCompletion == SQL_DRIVER_NOPROMPT)
{
CC_log_error(func, "Need password but Driver_NoPrompt", conn); CC_log_error(func, "Need password but Driver_NoPrompt", conn);
return SQL_ERROR; /* need a password but not allowed to return SQL_ERROR; /* need a password but not allowed to prompt so error */
* prompt so error */
} }
else else {
{
#ifdef WIN32 #ifdef WIN32
password_required = TRUE; password_required = TRUE;
goto dialog; goto dialog;
@ -198,8 +188,7 @@ dialog:
#endif #endif
} }
} }
else if (retval == 0) else if (retval == 0) {
{
/* error msg filled in above */ /* error msg filled in above */
CC_log_error(func, "Error from CC_Connect", conn); CC_log_error(func, "Error from CC_Connect", conn);
return SQL_ERROR; return SQL_ERROR;
@ -213,22 +202,18 @@ dialog:
makeConnectString(connStrOut, ci); makeConnectString(connStrOut, ci);
len = strlen(connStrOut); len = strlen(connStrOut);
if (szConnStrOut) if(szConnStrOut) {
{
/* /* Return the completed string to the caller. The correct method is to
* Return the completed string to the caller. The correct method only construct the connect string if a dialog was put up, otherwise,
* is to only construct the connect string if a dialog was put up, it should just copy the connection input string to the output.
* otherwise, it should just copy the connection input string to However, it seems ok to just always construct an output string. There
* the output. However, it seems ok to just always construct an are possible bad side effects on working applications (Access) by
* output string. There are possible bad side effects on working implementing the correct behavior, anyway.
* applications (Access) by implementing the correct behavior,
* anyway.
*/ */
strncpy_null(szConnStrOut, connStrOut, cbConnStrOutMax); strncpy_null(szConnStrOut, connStrOut, cbConnStrOutMax);
if (len >= cbConnStrOutMax) if (len >= cbConnStrOutMax) {
{
result = SQL_SUCCESS_WITH_INFO; result = SQL_SUCCESS_WITH_INFO;
conn->errornumber = CONN_TRUNCATED; conn->errornumber = CONN_TRUNCATED;
conn->errormsg = "The buffer was too small for the result."; conn->errormsg = "The buffer was too small for the result.";
@ -247,29 +232,27 @@ dialog:
} }
#ifdef WIN32 #ifdef WIN32
RETCODE RETCODE dconn_DoDialog(HWND hwnd, ConnInfo *ci)
dconn_DoDialog(HWND hwnd, ConnInfo *ci)
{ {
int dialog_result; int dialog_result;
mylog("dconn_DoDialog: ci = %u\n", ci); mylog("dconn_DoDialog: ci = %u\n", ci);
if (hwnd) if(hwnd) {
{
dialog_result = DialogBoxParam(s_hModule, MAKEINTRESOURCE(DLG_CONFIG), dialog_result = DialogBoxParam(s_hModule, MAKEINTRESOURCE(DLG_CONFIG),
hwnd, dconn_FDriverConnectProc, (LPARAM) ci); hwnd, dconn_FDriverConnectProc, (LPARAM) ci);
if (!dialog_result || (dialog_result == -1)) if(!dialog_result || (dialog_result == -1)) {
return SQL_NO_DATA_FOUND; return SQL_NO_DATA_FOUND;
else } else {
return SQL_SUCCESS; return SQL_SUCCESS;
} }
}
return SQL_ERROR; return SQL_ERROR;
} }
BOOL FAR PASCAL BOOL FAR PASCAL dconn_FDriverConnectProc(
dconn_FDriverConnectProc(
HWND hdlg, HWND hdlg,
UINT wMsg, UINT wMsg,
WPARAM wParam, WPARAM wParam,
@ -277,8 +260,7 @@ dconn_FDriverConnectProc(
{ {
ConnInfo *ci; ConnInfo *ci;
switch (wMsg) switch (wMsg) {
{
case WM_INITDIALOG: case WM_INITDIALOG:
ci = (ConnInfo *) lParam; ci = (ConnInfo *) lParam;
@ -293,8 +275,7 @@ dconn_FDriverConnectProc(
ShowWindow(GetDlgItem(hdlg, IDC_DESCTEXT), SW_HIDE); ShowWindow(GetDlgItem(hdlg, IDC_DESCTEXT), SW_HIDE);
ShowWindow(GetDlgItem(hdlg, IDC_DESC), SW_HIDE); ShowWindow(GetDlgItem(hdlg, IDC_DESC), SW_HIDE);
SetWindowLong(hdlg, DWL_USER, lParam); /* Save the ConnInfo for SetWindowLong(hdlg, DWL_USER, lParam);/* Save the ConnInfo for the "OK" */
* the "OK" */
SetDlgStuff(hdlg, ci); SetDlgStuff(hdlg, ci);
@ -313,8 +294,7 @@ dconn_FDriverConnectProc(
break; break;
case WM_COMMAND: case WM_COMMAND:
switch (GET_WM_COMMAND_ID(wParam, lParam)) switch (GET_WM_COMMAND_ID(wParam, lParam)) {
{
case IDOK: case IDOK:
ci = (ConnInfo *) GetWindowLong(hdlg, DWL_USER); ci = (ConnInfo *) GetWindowLong(hdlg, DWL_USER);
@ -349,14 +329,10 @@ dconn_FDriverConnectProc(
#endif /* WIN32 */ #endif /* WIN32 */
void void dconn_get_connect_attributes(UCHAR FAR *connect_string, ConnInfo *ci)
dconn_get_connect_attributes(UCHAR FAR *connect_string, ConnInfo *ci)
{ {
char *our_connect_string; char *our_connect_string;
char *pair, char *pair, *attribute, *value, *equals;
*attribute,
*value,
*equals;
char *strtok_arg; char *strtok_arg;
memset(ci, 0, sizeof(ConnInfo)); memset(ci, 0, sizeof(ConnInfo));
@ -366,13 +342,14 @@ dconn_get_connect_attributes(UCHAR FAR *connect_string, ConnInfo *ci)
mylog("our_connect_string = '%s'\n", our_connect_string); mylog("our_connect_string = '%s'\n", our_connect_string);
while (1) while(1) {
{
pair = strtok(strtok_arg, ";"); pair = strtok(strtok_arg, ";");
if (strtok_arg) if(strtok_arg) {
strtok_arg = 0; strtok_arg = 0;
if (!pair) }
if(!pair) {
break; break;
}
equals = strchr(pair, '='); equals = strchr(pair, '=');
if ( ! equals) if ( ! equals)
@ -389,8 +366,10 @@ dconn_get_connect_attributes(UCHAR FAR *connect_string, ConnInfo *ci)
/* Copy the appropriate value to the conninfo */ /* Copy the appropriate value to the conninfo */
copyAttributes(ci, attribute, value); copyAttributes(ci, attribute, value);
} }
free(our_connect_string); free(our_connect_string);
} }

@ -1,3 +1,4 @@
/* Module: environ.c /* Module: environ.c
* *
* Description: This module contains routines related to * Description: This module contains routines related to
@ -22,16 +23,14 @@
ConnectionClass *conns[MAX_CONNECTIONS]; ConnectionClass *conns[MAX_CONNECTIONS];
RETCODE SQL_API RETCODE SQL_API SQLAllocEnv(HENV FAR *phenv)
SQLAllocEnv(HENV FAR *phenv)
{ {
static char *func = "SQLAllocEnv"; static char *func = "SQLAllocEnv";
mylog("**** in SQLAllocEnv ** \n"); mylog("**** in SQLAllocEnv ** \n");
*phenv = (HENV) EN_Constructor(); *phenv = (HENV) EN_Constructor();
if (!*phenv) if ( ! *phenv) {
{
*phenv = SQL_NULL_HENV; *phenv = SQL_NULL_HENV;
EN_log_error(func, "Error allocating environment", NULL); EN_log_error(func, "Error allocating environment", NULL);
return SQL_ERROR; return SQL_ERROR;
@ -41,16 +40,14 @@ SQLAllocEnv(HENV FAR *phenv)
return SQL_SUCCESS; return SQL_SUCCESS;
} }
RETCODE SQL_API RETCODE SQL_API SQLFreeEnv(HENV henv)
SQLFreeEnv(HENV henv)
{ {
static char *func = "SQLFreeEnv"; static char *func = "SQLFreeEnv";
EnvironmentClass *env = (EnvironmentClass *) henv; EnvironmentClass *env = (EnvironmentClass *) henv;
mylog("**** in SQLFreeEnv: env = %u ** \n", env); mylog("**** in SQLFreeEnv: env = %u ** \n", env);
if (env && EN_Destructor(env)) if (env && EN_Destructor(env)) {
{
mylog(" ok\n"); mylog(" ok\n");
return SQL_SUCCESS; return SQL_SUCCESS;
} }
@ -62,8 +59,7 @@ SQLFreeEnv(HENV henv)
/* Returns the next SQL error information. */ /* Returns the next SQL error information. */
RETCODE SQL_API RETCODE SQL_API SQLError(
SQLError(
HENV henv, HENV henv,
HDBC hdbc, HDBC hdbc,
HSTMT hstmt, HSTMT hstmt,
@ -78,16 +74,13 @@ SQLError(
mylog("**** SQLError: henv=%u, hdbc=%u, hstmt=%u\n", henv, hdbc, hstmt); mylog("**** SQLError: henv=%u, hdbc=%u, hstmt=%u\n", henv, hdbc, hstmt);
if (SQL_NULL_HSTMT != hstmt) if (SQL_NULL_HSTMT != hstmt) {
{
/* CC: return an error of a hstmt */ /* CC: return an error of a hstmt */
StatementClass *stmt = (StatementClass *) hstmt; StatementClass *stmt = (StatementClass *) hstmt;
if (SC_get_error(stmt, &status, &msg)) if (SC_get_error(stmt, &status, &msg)) {
{
mylog("SC_get_error: status = %d, msg = #%s#\n", status, msg); mylog("SC_get_error: status = %d, msg = #%s#\n", status, msg);
if (NULL == msg) if (NULL == msg) {
{
if (NULL != szSqlState) if (NULL != szSqlState)
strcpy(szSqlState, "00000"); strcpy(szSqlState, "00000");
if (NULL != pcbErrorMsg) if (NULL != pcbErrorMsg)
@ -108,8 +101,7 @@ SQLError(
if (NULL != szSqlState) if (NULL != szSqlState)
switch (status) switch (status) {
{
/* now determine the SQLSTATE to be returned */ /* now determine the SQLSTATE to be returned */
case STMT_TRUNCATED: case STMT_TRUNCATED:
strcpy(szSqlState, "01004"); strcpy(szSqlState, "01004");
@ -161,8 +153,7 @@ SQLError(
break; break;
case STMT_NOT_IMPLEMENTED_ERROR: case STMT_NOT_IMPLEMENTED_ERROR:
strcpy(szSqlState, "S1C00"); /* == 'driver not strcpy(szSqlState, "S1C00"); /* == 'driver not capable' */
* capable' */
break; break;
case STMT_OPTION_OUT_OF_RANGE_ERROR: case STMT_OPTION_OUT_OF_RANGE_ERROR:
strcpy(szSqlState, "S1092"); strcpy(szSqlState, "S1092");
@ -212,9 +203,8 @@ SQLError(
} }
mylog(" szSqlState = '%s', szError='%s'\n", szSqlState, szErrorMsg); mylog(" szSqlState = '%s', szError='%s'\n", szSqlState, szErrorMsg);
}
else } else {
{
if (NULL != szSqlState) if (NULL != szSqlState)
strcpy(szSqlState, "00000"); strcpy(szSqlState, "00000");
if (NULL != pcbErrorMsg) if (NULL != pcbErrorMsg)
@ -226,17 +216,14 @@ SQLError(
return SQL_NO_DATA_FOUND; return SQL_NO_DATA_FOUND;
} }
return SQL_SUCCESS; return SQL_SUCCESS;
}
else if (SQL_NULL_HDBC != hdbc) } else if (SQL_NULL_HDBC != hdbc) {
{
ConnectionClass *conn = (ConnectionClass *) hdbc; ConnectionClass *conn = (ConnectionClass *) hdbc;
mylog("calling CC_get_error\n"); mylog("calling CC_get_error\n");
if (CC_get_error(conn, &status, &msg)) if (CC_get_error(conn, &status, &msg)) {
{
mylog("CC_get_error: status = %d, msg = #%s#\n", status, msg); mylog("CC_get_error: status = %d, msg = #%s#\n", status, msg);
if (NULL == msg) if (NULL == msg) {
{
if (NULL != szSqlState) if (NULL != szSqlState)
strcpy(szSqlState, "00000"); strcpy(szSqlState, "00000");
if (NULL != pcbErrorMsg) if (NULL != pcbErrorMsg)
@ -255,8 +242,7 @@ SQLError(
*pfNativeError = status; *pfNativeError = status;
if (NULL != szSqlState) if (NULL != szSqlState)
switch (status) switch(status) {
{
case STMT_OPTION_VALUE_CHANGED: case STMT_OPTION_VALUE_CHANGED:
case CONN_OPTION_VALUE_CHANGED: case CONN_OPTION_VALUE_CHANGED:
strcpy(szSqlState, "01S02"); strcpy(szSqlState, "01S02");
@ -295,11 +281,7 @@ SQLError(
break; break;
case CONN_TRANSACT_IN_PROGRES: case CONN_TRANSACT_IN_PROGRES:
strcpy(szSqlState, "S1010"); strcpy(szSqlState, "S1010");
/* when the user tries to switch commit mode in a transaction */
/*
* when the user tries to switch commit mode in a
* transaction
*/
/* -> function sequence error */ /* -> function sequence error */
break; break;
case CONN_NO_MEMORY_ERROR: case CONN_NO_MEMORY_ERROR:
@ -320,9 +302,8 @@ SQLError(
/* general error */ /* general error */
break; break;
} }
}
else } else {
{
mylog("CC_Get_error returned nothing.\n"); mylog("CC_Get_error returned nothing.\n");
if (NULL != szSqlState) if (NULL != szSqlState)
strcpy(szSqlState, "00000"); strcpy(szSqlState, "00000");
@ -334,16 +315,12 @@ SQLError(
return SQL_NO_DATA_FOUND; return SQL_NO_DATA_FOUND;
} }
return SQL_SUCCESS; return SQL_SUCCESS;
}
else if (SQL_NULL_HENV != henv)
{
EnvironmentClass *env = (EnvironmentClass *) henv;
if (EN_get_error(env, &status, &msg)) } else if (SQL_NULL_HENV != henv) {
{ EnvironmentClass *env = (EnvironmentClass *)henv;
if(EN_get_error(env, &status, &msg)) {
mylog("EN_get_error: status = %d, msg = #%s#\n", status, msg); mylog("EN_get_error: status = %d, msg = #%s#\n", status, msg);
if (NULL == msg) if (NULL == msg) {
{
if (NULL != szSqlState) if (NULL != szSqlState)
strcpy(szSqlState, "00000"); strcpy(szSqlState, "00000");
if (NULL != pcbErrorMsg) if (NULL != pcbErrorMsg)
@ -361,10 +338,8 @@ SQLError(
if (NULL != pfNativeError) if (NULL != pfNativeError)
*pfNativeError = status; *pfNativeError = status;
if (szSqlState) if(szSqlState) {
{ switch(status) {
switch (status)
{
case ENV_ALLOC_ERROR: case ENV_ALLOC_ERROR:
/* memory allocation failure */ /* memory allocation failure */
strcpy(szSqlState, "S1001"); strcpy(szSqlState, "S1001");
@ -375,9 +350,7 @@ SQLError(
break; break;
} }
} }
} } else {
else
{
if (NULL != szSqlState) if (NULL != szSqlState)
strcpy(szSqlState, "00000"); strcpy(szSqlState, "00000");
if (NULL != pcbErrorMsg) if (NULL != pcbErrorMsg)
@ -410,14 +383,12 @@ SQLError(
EnvironmentClass EnvironmentClass
* *EN_Constructor(void)
EN_Constructor(void)
{ {
EnvironmentClass *rv; EnvironmentClass *rv;
rv = (EnvironmentClass *) malloc(sizeof(EnvironmentClass)); rv = (EnvironmentClass *) malloc(sizeof(EnvironmentClass));
if (rv) if( rv) {
{
rv->errormsg = 0; rv->errormsg = 0;
rv->errornumber = 0; rv->errornumber = 0;
} }
@ -438,8 +409,7 @@ EN_Destructor(EnvironmentClass *self)
/* the source--they should not be freed */ /* the source--they should not be freed */
/* Free any connections belonging to this environment */ /* Free any connections belonging to this environment */
for (lf = 0; lf < MAX_CONNECTIONS; lf++) for (lf = 0; lf < MAX_CONNECTIONS; lf++) {
{
if (conns[lf] && conns[lf]->henv == self) if (conns[lf] && conns[lf]->henv == self)
rv = rv && CC_Destructor(conns[lf]); rv = rv && CC_Destructor(conns[lf]);
} }
@ -451,17 +421,16 @@ EN_Destructor(EnvironmentClass *self)
char char
EN_get_error(EnvironmentClass *self, int *number, char **message) EN_get_error(EnvironmentClass *self, int *number, char **message)
{ {
if (self && self->errormsg && self->errornumber) if(self && self->errormsg && self->errornumber) {
{
*message = self->errormsg; *message = self->errormsg;
*number = self->errornumber; *number = self->errornumber;
self->errormsg = 0; self->errormsg = 0;
self->errornumber = 0; self->errornumber = 0;
return 1; return 1;
} } else {
else
return 0; return 0;
} }
}
char char
EN_add_connection(EnvironmentClass *self, ConnectionClass *conn) EN_add_connection(EnvironmentClass *self, ConnectionClass *conn)
@ -470,10 +439,8 @@ EN_add_connection(EnvironmentClass *self, ConnectionClass *conn)
mylog("EN_add_connection: self = %u, conn = %u\n", self, conn); mylog("EN_add_connection: self = %u, conn = %u\n", self, conn);
for (i = 0; i < MAX_CONNECTIONS; i++) for (i = 0; i < MAX_CONNECTIONS; i++) {
{ if ( ! conns[i]) {
if (!conns[i])
{
conn->henv = self; conn->henv = self;
conns[i] = conn; conns[i] = conn;
@ -492,8 +459,7 @@ EN_remove_connection(EnvironmentClass *self, ConnectionClass *conn)
int i; int i;
for (i = 0; i < MAX_CONNECTIONS; i++) for (i = 0; i < MAX_CONNECTIONS; i++)
if (conns[i] == conn && conns[i]->status != CONN_EXECUTING) if (conns[i] == conn && conns[i]->status != CONN_EXECUTING) {
{
conns[i] = NULL; conns[i] = NULL;
return TRUE; return TRUE;
} }
@ -504,8 +470,9 @@ EN_remove_connection(EnvironmentClass *self, ConnectionClass *conn)
void void
EN_log_error(char *func, char *desc, EnvironmentClass *self) EN_log_error(char *func, char *desc, EnvironmentClass *self)
{ {
if (self) if (self) {
qlog("ENVIRON ERROR: func=%s, desc='%s', errnum=%d, errmsg='%s'\n", func, desc, self->errornumber, self->errormsg); qlog("ENVIRON ERROR: func=%s, desc='%s', errnum=%d, errmsg='%s'\n", func, desc, self->errornumber, self->errormsg);
}
else else
qlog("INVALID ENVIRON HANDLE ERROR: func=%s, desc='%s'\n", func, desc); qlog("INVALID ENVIRON HANDLE ERROR: func=%s, desc='%s'\n", func, desc);
} }

@ -29,8 +29,7 @@
#define ENV_ALLOC_ERROR 1 #define ENV_ALLOC_ERROR 1
/********** Environment Handle *************/ /********** Environment Handle *************/
struct EnvironmentClass_ struct EnvironmentClass_ {
{
char *errormsg; char *errormsg;
int errornumber; int errornumber;
}; };

@ -1,3 +1,4 @@
/* Module: execute.c /* Module: execute.c
* *
* Description: This module contains routines related to * Description: This module contains routines related to
@ -39,8 +40,7 @@ extern GLOBAL_VALUES globals;
/* Perform a Prepare on the SQL statement */ /* Perform a Prepare on the SQL statement */
RETCODE SQL_API RETCODE SQL_API SQLPrepare(HSTMT hstmt,
SQLPrepare(HSTMT hstmt,
UCHAR FAR *szSqlStr, UCHAR FAR *szSqlStr,
SDWORD cbSqlStr) SDWORD cbSqlStr)
{ {
@ -49,30 +49,24 @@ SQLPrepare(HSTMT hstmt,
mylog( "%s: entering...\n", func); mylog( "%s: entering...\n", func);
if (!self) if ( ! self) {
{
SC_log_error(func, "", NULL); SC_log_error(func, "", NULL);
return SQL_INVALID_HANDLE; return SQL_INVALID_HANDLE;
} }
/* /* According to the ODBC specs it is valid to call SQLPrepare mulitple times.
* According to the ODBC specs it is valid to call SQLPrepare mulitple In that case, the bound SQL statement is replaced by the new one
* times. In that case, the bound SQL statement is replaced by the new
* one
*/ */
switch (self->status) switch(self->status) {
{
case STMT_PREMATURE: case STMT_PREMATURE:
mylog("**** SQLPrepare: STMT_PREMATURE, recycle\n"); mylog("**** SQLPrepare: STMT_PREMATURE, recycle\n");
SC_recycle_statement(self); /* recycle the statement, but do SC_recycle_statement(self); /* recycle the statement, but do not remove parameter bindings */
* not remove parameter bindings */
break; break;
case STMT_FINISHED: case STMT_FINISHED:
mylog("**** SQLPrepare: STMT_FINISHED, recycle\n"); mylog("**** SQLPrepare: STMT_FINISHED, recycle\n");
SC_recycle_statement(self); /* recycle the statement, but do SC_recycle_statement(self); /* recycle the statement, but do not remove parameter bindings */
* not remove parameter bindings */
break; break;
case STMT_ALLOCATED: case STMT_ALLOCATED:
@ -104,8 +98,7 @@ SQLPrepare(HSTMT hstmt,
free(self->statement); free(self->statement);
self->statement = make_string(szSqlStr, cbSqlStr, NULL); self->statement = make_string(szSqlStr, cbSqlStr, NULL);
if (!self->statement) if ( ! self->statement) {
{
self->errornumber = STMT_NO_MEMORY_ERROR; self->errornumber = STMT_NO_MEMORY_ERROR;
self->errormsg = "No memory available to store statement"; self->errormsg = "No memory available to store statement";
SC_log_error(func, "", self); SC_log_error(func, "", self);
@ -116,8 +109,7 @@ SQLPrepare(HSTMT hstmt,
self->statement_type = statement_type(self->statement); self->statement_type = statement_type(self->statement);
/* Check if connection is onlyread (only selects are allowed) */ /* Check if connection is onlyread (only selects are allowed) */
if (CC_is_onlyread(self->hdbc) && STMT_UPDATE(self)) if ( CC_is_onlyread(self->hdbc) && STMT_UPDATE(self)) {
{
self->errornumber = STMT_EXEC_ERROR; self->errornumber = STMT_EXEC_ERROR;
self->errormsg = "Connection is readonly, only select statements are allowed."; self->errormsg = "Connection is readonly, only select statements are allowed.";
SC_log_error(func, "", self); SC_log_error(func, "", self);
@ -133,8 +125,7 @@ SQLPrepare(HSTMT hstmt,
/* Performs the equivalent of SQLPrepare, followed by SQLExecute. */ /* Performs the equivalent of SQLPrepare, followed by SQLExecute. */
RETCODE SQL_API RETCODE SQL_API SQLExecDirect(
SQLExecDirect(
HSTMT hstmt, HSTMT hstmt,
UCHAR FAR *szSqlStr, UCHAR FAR *szSqlStr,
SDWORD cbSqlStr) SDWORD cbSqlStr)
@ -145,8 +136,7 @@ SQLExecDirect(
mylog( "%s: entering...\n", func); mylog( "%s: entering...\n", func);
if (!stmt) if ( ! stmt) {
{
SC_log_error(func, "", NULL); SC_log_error(func, "", NULL);
return SQL_INVALID_HANDLE; return SQL_INVALID_HANDLE;
} }
@ -157,8 +147,7 @@ SQLExecDirect(
/* keep a copy of the un-parametrized statement, in case */ /* keep a copy of the un-parametrized statement, in case */
/* they try to execute this statement again */ /* they try to execute this statement again */
stmt->statement = make_string(szSqlStr, cbSqlStr, NULL); stmt->statement = make_string(szSqlStr, cbSqlStr, NULL);
if (!stmt->statement) if ( ! stmt->statement) {
{
stmt->errornumber = STMT_NO_MEMORY_ERROR; stmt->errornumber = STMT_NO_MEMORY_ERROR;
stmt->errormsg = "No memory available to store statement"; stmt->errormsg = "No memory available to store statement";
SC_log_error(func, "", stmt); SC_log_error(func, "", stmt);
@ -178,8 +167,7 @@ SQLExecDirect(
stmt->statement_type = statement_type(stmt->statement); stmt->statement_type = statement_type(stmt->statement);
/* Check if connection is onlyread (only selects are allowed) */ /* Check if connection is onlyread (only selects are allowed) */
if (CC_is_onlyread(stmt->hdbc) && STMT_UPDATE(stmt)) if ( CC_is_onlyread(stmt->hdbc) && STMT_UPDATE(stmt)) {
{
stmt->errornumber = STMT_EXEC_ERROR; stmt->errornumber = STMT_EXEC_ERROR;
stmt->errormsg = "Connection is readonly, only select statements are allowed."; stmt->errormsg = "Connection is readonly, only select statements are allowed.";
SC_log_error(func, "", stmt); SC_log_error(func, "", stmt);
@ -195,41 +183,34 @@ SQLExecDirect(
} }
/* Execute a prepared SQL statement */ /* Execute a prepared SQL statement */
RETCODE SQL_API RETCODE SQL_API SQLExecute(
SQLExecute(
HSTMT hstmt) HSTMT hstmt)
{ {
static char *func="SQLExecute"; static char *func="SQLExecute";
StatementClass *stmt = (StatementClass *) hstmt; StatementClass *stmt = (StatementClass *) hstmt;
ConnectionClass *conn; ConnectionClass *conn;
int i, int i, retval;
retval;
mylog("%s: entering...\n", func); mylog("%s: entering...\n", func);
if (!stmt) if ( ! stmt) {
{
SC_log_error(func, "", NULL); SC_log_error(func, "", NULL);
mylog("%s: NULL statement so return SQL_INVALID_HANDLE\n", func); mylog("%s: NULL statement so return SQL_INVALID_HANDLE\n", func);
return SQL_INVALID_HANDLE; return SQL_INVALID_HANDLE;
} }
/* /* If the statement is premature, it means we already executed
* If the statement is premature, it means we already executed it from it from an SQLPrepare/SQLDescribeCol type of scenario. So
* an SQLPrepare/SQLDescribeCol type of scenario. So just return just return success.
* success.
*/ */
if (stmt->prepare && stmt->status == STMT_PREMATURE) if ( stmt->prepare && stmt->status == STMT_PREMATURE) {
{
stmt->status = STMT_FINISHED; stmt->status = STMT_FINISHED;
if (stmt->errormsg == NULL) if (stmt->errormsg == NULL) {
{
mylog("%s: premature statement but return SQL_SUCCESS\n", func); mylog("%s: premature statement but return SQL_SUCCESS\n", func);
return SQL_SUCCESS; return SQL_SUCCESS;
} }
else else {
{
SC_log_error(func, "", stmt); SC_log_error(func, "", stmt);
mylog("%s: premature statement so return SQL_ERROR\n", func); mylog("%s: premature statement so return SQL_ERROR\n", func);
return SQL_ERROR; return SQL_ERROR;
@ -241,8 +222,7 @@ SQLExecute(
SC_clear_error(stmt); SC_clear_error(stmt);
conn = SC_get_conn(stmt); conn = SC_get_conn(stmt);
if (conn->status == CONN_EXECUTING) if (conn->status == CONN_EXECUTING) {
{
stmt->errormsg = "Connection is already in use."; stmt->errormsg = "Connection is already in use.";
stmt->errornumber = STMT_SEQUENCE_ERROR; stmt->errornumber = STMT_SEQUENCE_ERROR;
SC_log_error(func, "", stmt); SC_log_error(func, "", stmt);
@ -250,8 +230,7 @@ SQLExecute(
return SQL_ERROR; return SQL_ERROR;
} }
if (!stmt->statement) if ( ! stmt->statement) {
{
stmt->errornumber = STMT_NO_STMTSTRING; stmt->errornumber = STMT_NO_STMTSTRING;
stmt->errormsg = "This handle does not have a SQL statement stored in it"; stmt->errormsg = "This handle does not have a SQL statement stored in it";
SC_log_error(func, "", stmt); SC_log_error(func, "", stmt);
@ -259,21 +238,19 @@ SQLExecute(
return SQL_ERROR; return SQL_ERROR;
} }
/* /* If SQLExecute is being called again, recycle the statement.
* If SQLExecute is being called again, recycle the statement. Note Note this should have been done by the application in a call
* this should have been done by the application in a call to to SQLFreeStmt(SQL_CLOSE) or SQLCancel.
* SQLFreeStmt(SQL_CLOSE) or SQLCancel.
*/ */
if (stmt->status == STMT_FINISHED) if (stmt->status == STMT_FINISHED) {
{
mylog("%s: recycling statement (should have been done by app)...\n", func); mylog("%s: recycling statement (should have been done by app)...\n", func);
SC_recycle_statement(stmt); SC_recycle_statement(stmt);
} }
/* Check if the statement is in the correct state */ /* Check if the statement is in the correct state */
if ((stmt->prepare && stmt->status != STMT_READY) || if ((stmt->prepare && stmt->status != STMT_READY) ||
(stmt->status != STMT_ALLOCATED && stmt->status != STMT_READY)) (stmt->status != STMT_ALLOCATED && stmt->status != STMT_READY)) {
{
stmt->errornumber = STMT_STATUS_ERROR; stmt->errornumber = STMT_STATUS_ERROR;
stmt->errormsg = "The handle does not point to a statement that is ready to be executed"; stmt->errormsg = "The handle does not point to a statement that is ready to be executed";
SC_log_error(func, "", stmt); SC_log_error(func, "", stmt);
@ -282,16 +259,13 @@ SQLExecute(
} }
/* /* The bound parameters could have possibly changed since the last execute
* The bound parameters could have possibly changed since the last of this statement? Therefore check for params and re-copy.
* execute of this statement? Therefore check for params and re-copy.
*/ */
stmt->data_at_exec = -1; stmt->data_at_exec = -1;
for (i = 0; i < stmt->parameters_allocated; i++) for (i = 0; i < stmt->parameters_allocated; i++) {
{
/* Check for data at execution parameters */ /* Check for data at execution parameters */
if (stmt->parameters[i].data_at_exec == TRUE) if ( stmt->parameters[i].data_at_exec == TRUE) {
{
if (stmt->data_at_exec < 0) if (stmt->data_at_exec < 0)
stmt->data_at_exec = 1; stmt->data_at_exec = 1;
else else
@ -299,11 +273,7 @@ SQLExecute(
} }
} }
/* If there are some data at execution parameters, return need data */ /* If there are some data at execution parameters, return need data */
/* SQLParamData and SQLPutData will be used to send params and execute the statement. */
/*
* SQLParamData and SQLPutData will be used to send params and execute
* the statement.
*/
if (stmt->data_at_exec > 0) if (stmt->data_at_exec > 0)
return SQL_NEED_DATA; return SQL_NEED_DATA;
@ -320,14 +290,14 @@ SQLExecute(
return SC_execute(stmt); return SC_execute(stmt);
} }
/* - - - - - - - - - */ /* - - - - - - - - - */
RETCODE SQL_API RETCODE SQL_API SQLTransact(
SQLTransact(
HENV henv, HENV henv,
HDBC hdbc, HDBC hdbc,
UWORD fType) UWORD fType)
@ -336,43 +306,40 @@ SQLTransact(
extern ConnectionClass *conns[]; extern ConnectionClass *conns[];
ConnectionClass *conn; ConnectionClass *conn;
QResultClass *res; QResultClass *res;
char ok, char ok, *stmt_string;
*stmt_string;
int lf; int lf;
mylog("entering %s: hdbc=%u, henv=%u\n", func, hdbc, henv); mylog("entering %s: hdbc=%u, henv=%u\n", func, hdbc, henv);
if (hdbc == SQL_NULL_HDBC && henv == SQL_NULL_HENV) if (hdbc == SQL_NULL_HDBC && henv == SQL_NULL_HENV) {
{
CC_log_error(func, "", NULL); CC_log_error(func, "", NULL);
return SQL_INVALID_HANDLE; return SQL_INVALID_HANDLE;
} }
/* /* If hdbc is null and henv is valid,
* If hdbc is null and henv is valid, it means transact all it means transact all connections on that henv.
* connections on that henv.
*/ */
if (hdbc == SQL_NULL_HDBC && henv != SQL_NULL_HENV) if (hdbc == SQL_NULL_HDBC && henv != SQL_NULL_HENV) {
{ for (lf=0; lf <MAX_CONNECTIONS; lf++) {
for (lf = 0; lf < MAX_CONNECTIONS; lf++)
{
conn = conns[lf]; conn = conns[lf];
if (conn && conn->henv == henv) if (conn && conn->henv == henv)
if ( SQLTransact(henv, (HDBC) conn, fType) != SQL_SUCCESS) if ( SQLTransact(henv, (HDBC) conn, fType) != SQL_SUCCESS)
return SQL_ERROR; return SQL_ERROR;
} }
return SQL_SUCCESS; return SQL_SUCCESS;
} }
conn = (ConnectionClass *) hdbc; conn = (ConnectionClass *) hdbc;
if (fType == SQL_COMMIT) if (fType == SQL_COMMIT) {
stmt_string = "COMMIT"; stmt_string = "COMMIT";
else if (fType == SQL_ROLLBACK)
} else if (fType == SQL_ROLLBACK) {
stmt_string = "ROLLBACK"; stmt_string = "ROLLBACK";
else
{ } else {
conn->errornumber = CONN_INVALID_ARGUMENT_NO; conn->errornumber = CONN_INVALID_ARGUMENT_NO;
conn->errormsg ="SQLTransact can only be called with SQL_COMMIT or SQL_ROLLBACK as parameter"; conn->errormsg ="SQLTransact can only be called with SQL_COMMIT or SQL_ROLLBACK as parameter";
CC_log_error(func, "", conn); CC_log_error(func, "", conn);
@ -380,15 +347,14 @@ SQLTransact(
} }
/* If manual commit and in transaction, then proceed. */ /* If manual commit and in transaction, then proceed. */
if (!CC_is_in_autocommit(conn) && CC_is_in_trans(conn)) if ( ! CC_is_in_autocommit(conn) && CC_is_in_trans(conn)) {
{
mylog("SQLTransact: sending on conn %d '%s'\n", conn, stmt_string); mylog("SQLTransact: sending on conn %d '%s'\n", conn, stmt_string);
res = CC_send_query(conn, stmt_string, NULL); res = CC_send_query(conn, stmt_string, NULL);
CC_set_no_trans(conn); CC_set_no_trans(conn);
if (!res) if ( ! res) {
{
/* error msg will be in the connection */ /* error msg will be in the connection */
CC_log_error(func, "", conn); CC_log_error(func, "", conn);
return SQL_ERROR; return SQL_ERROR;
@ -397,8 +363,7 @@ SQLTransact(
ok = QR_command_successful(res); ok = QR_command_successful(res);
QR_Destructor(res); QR_Destructor(res);
if (!ok) if (!ok) {
{
CC_log_error(func, "", conn); CC_log_error(func, "", conn);
return SQL_ERROR; return SQL_ERROR;
} }
@ -408,54 +373,46 @@ SQLTransact(
/* - - - - - - - - - */ /* - - - - - - - - - */
RETCODE SQL_API RETCODE SQL_API SQLCancel(
SQLCancel(
HSTMT hstmt) /* Statement to cancel. */ HSTMT hstmt) /* Statement to cancel. */
{ {
static char *func="SQLCancel"; static char *func="SQLCancel";
StatementClass *stmt = (StatementClass *) hstmt; StatementClass *stmt = (StatementClass *) hstmt;
RETCODE result; RETCODE result;
#ifdef WIN32 #ifdef WIN32
HMODULE hmodule; HMODULE hmodule;
FARPROC addr; FARPROC addr;
#endif #endif
mylog( "%s: entering...\n", func); mylog( "%s: entering...\n", func);
/* Check if this can handle canceling in the middle of a SQLPutData? */ /* Check if this can handle canceling in the middle of a SQLPutData? */
if (!stmt) if ( ! stmt) {
{
SC_log_error(func, "", NULL); SC_log_error(func, "", NULL);
return SQL_INVALID_HANDLE; return SQL_INVALID_HANDLE;
} }
/* /* Not in the middle of SQLParamData/SQLPutData so cancel like a close. */
* Not in the middle of SQLParamData/SQLPutData so cancel like a if (stmt->data_at_exec < 0) {
* close.
*/
if (stmt->data_at_exec < 0)
{
/*
* MAJOR HACK for Windows to reset the driver manager's cursor /* MAJOR HACK for Windows to reset the driver manager's cursor state:
* state: Because of what seems like a bug in the Odbc driver Because of what seems like a bug in the Odbc driver manager,
* manager, SQLCancel does not act like a SQLFreeStmt(CLOSE), as SQLCancel does not act like a SQLFreeStmt(CLOSE), as many
* many applications depend on this behavior. So, this brute applications depend on this behavior. So, this
* force method calls the driver manager's function on behalf of brute force method calls the driver manager's function on
* the application. behalf of the application.
*/ */
#ifdef WIN32 #ifdef WIN32
if (globals.cancel_as_freestmt) if (globals.cancel_as_freestmt) {
{
hmodule = GetModuleHandle("ODBC32"); hmodule = GetModuleHandle("ODBC32");
addr = GetProcAddress(hmodule, "SQLFreeStmt"); addr = GetProcAddress(hmodule, "SQLFreeStmt");
result = addr( (char *) (stmt->phstmt) - 96, SQL_CLOSE); result = addr( (char *) (stmt->phstmt) - 96, SQL_CLOSE);
} }
else else {
result = SQLFreeStmt( hstmt, SQL_CLOSE); result = SQLFreeStmt( hstmt, SQL_CLOSE);
}
#else #else
result = SQLFreeStmt( hstmt, SQL_CLOSE); result = SQLFreeStmt( hstmt, SQL_CLOSE);
#endif #endif
@ -467,11 +424,7 @@ SQLCancel(
} }
/* In the middle of SQLParamData/SQLPutData, so cancel that. */ /* In the middle of SQLParamData/SQLPutData, so cancel that. */
/* Note, any previous data-at-exec buffers will be freed in the recycle */
/*
* Note, any previous data-at-exec buffers will be freed in the
* recycle
*/
/* if they call SQLExecDirect or SQLExecute again. */ /* if they call SQLExecDirect or SQLExecute again. */
stmt->data_at_exec = -1; stmt->data_at_exec = -1;
@ -479,6 +432,7 @@ SQLCancel(
stmt->put_data = FALSE; stmt->put_data = FALSE;
return SQL_SUCCESS; return SQL_SUCCESS;
} }
/* - - - - - - - - - */ /* - - - - - - - - - */
@ -486,8 +440,7 @@ SQLCancel(
/* Returns the SQL string as modified by the driver. */ /* Returns the SQL string as modified by the driver. */
/* Currently, just copy the input string without modification */ /* Currently, just copy the input string without modification */
/* observing buffer limits and truncation. */ /* observing buffer limits and truncation. */
RETCODE SQL_API RETCODE SQL_API SQLNativeSql(
SQLNativeSql(
HDBC hdbc, HDBC hdbc,
UCHAR FAR *szSqlStrIn, UCHAR FAR *szSqlStrIn,
SDWORD cbSqlStrIn, SDWORD cbSqlStrIn,
@ -504,8 +457,7 @@ SQLNativeSql(
mylog( "%s: entering...cbSqlStrIn=%d\n", func, cbSqlStrIn); mylog( "%s: entering...cbSqlStrIn=%d\n", func, cbSqlStrIn);
ptr = (cbSqlStrIn == 0) ? "" : make_string(szSqlStrIn, cbSqlStrIn, NULL); ptr = (cbSqlStrIn == 0) ? "" : make_string(szSqlStrIn, cbSqlStrIn, NULL);
if (!ptr) if ( ! ptr) {
{
conn->errornumber = CONN_NO_MEMORY_ERROR; conn->errornumber = CONN_NO_MEMORY_ERROR;
conn->errormsg = "No memory available to store native sql string"; conn->errormsg = "No memory available to store native sql string";
CC_log_error(func, "", conn); CC_log_error(func, "", conn);
@ -515,12 +467,10 @@ SQLNativeSql(
result = SQL_SUCCESS; result = SQL_SUCCESS;
len = strlen(ptr); len = strlen(ptr);
if (szSqlStr) if (szSqlStr) {
{
strncpy_null(szSqlStr, ptr, cbSqlStrMax); strncpy_null(szSqlStr, ptr, cbSqlStrMax);
if (len >= cbSqlStrMax) if (len >= cbSqlStrMax) {
{
result = SQL_SUCCESS_WITH_INFO; result = SQL_SUCCESS_WITH_INFO;
conn->errornumber = STMT_TRUNCATED; conn->errornumber = STMT_TRUNCATED;
conn->errormsg = "The buffer was too small for the result."; conn->errormsg = "The buffer was too small for the result.";
@ -540,36 +490,31 @@ SQLNativeSql(
/* Supplies parameter data at execution time. Used in conjuction with */ /* Supplies parameter data at execution time. Used in conjuction with */
/* SQLPutData. */ /* SQLPutData. */
RETCODE SQL_API RETCODE SQL_API SQLParamData(
SQLParamData(
HSTMT hstmt, HSTMT hstmt,
PTR FAR *prgbValue) PTR FAR *prgbValue)
{ {
static char *func = "SQLParamData"; static char *func = "SQLParamData";
StatementClass *stmt = (StatementClass *) hstmt; StatementClass *stmt = (StatementClass *) hstmt;
int i, int i, retval;
retval;
mylog( "%s: entering...\n", func); mylog( "%s: entering...\n", func);
if (!stmt) if ( ! stmt) {
{
SC_log_error(func, "", NULL); SC_log_error(func, "", NULL);
return SQL_INVALID_HANDLE; return SQL_INVALID_HANDLE;
} }
mylog("%s: data_at_exec=%d, params_alloc=%d\n", func, stmt->data_at_exec, stmt->parameters_allocated); mylog("%s: data_at_exec=%d, params_alloc=%d\n", func, stmt->data_at_exec, stmt->parameters_allocated);
if (stmt->data_at_exec < 0) if (stmt->data_at_exec < 0) {
{
stmt->errornumber = STMT_SEQUENCE_ERROR; stmt->errornumber = STMT_SEQUENCE_ERROR;
stmt->errormsg = "No execution-time parameters for this statement"; stmt->errormsg = "No execution-time parameters for this statement";
SC_log_error(func, "", stmt); SC_log_error(func, "", stmt);
return SQL_ERROR; return SQL_ERROR;
} }
if (stmt->data_at_exec > stmt->parameters_allocated) if (stmt->data_at_exec > stmt->parameters_allocated) {
{
stmt->errornumber = STMT_SEQUENCE_ERROR; stmt->errornumber = STMT_SEQUENCE_ERROR;
stmt->errormsg = "Too many execution-time parameters were present"; stmt->errormsg = "Too many execution-time parameters were present";
SC_log_error(func, "", stmt); SC_log_error(func, "", stmt);
@ -577,19 +522,16 @@ SQLParamData(
} }
/* close the large object */ /* close the large object */
if (stmt->lobj_fd >= 0) if ( stmt->lobj_fd >= 0) {
{
lo_close(stmt->hdbc, stmt->lobj_fd); lo_close(stmt->hdbc, stmt->lobj_fd);
/* commit transaction if needed */ /* commit transaction if needed */
if (!globals.use_declarefetch && CC_is_in_autocommit(stmt->hdbc)) if (!globals.use_declarefetch && CC_is_in_autocommit(stmt->hdbc)) {
{
QResultClass *res; QResultClass *res;
char ok; char ok;
res = CC_send_query(stmt->hdbc, "COMMIT", NULL); res = CC_send_query(stmt->hdbc, "COMMIT", NULL);
if (!res) if (!res) {
{
stmt->errormsg = "Could not commit (in-line) a transaction"; stmt->errormsg = "Could not commit (in-line) a transaction";
stmt->errornumber = STMT_EXEC_ERROR; stmt->errornumber = STMT_EXEC_ERROR;
SC_log_error(func, "", stmt); SC_log_error(func, "", stmt);
@ -597,8 +539,7 @@ SQLParamData(
} }
ok = QR_command_successful(res); ok = QR_command_successful(res);
QR_Destructor(res); QR_Destructor(res);
if (!ok) if (!ok) {
{
stmt->errormsg = "Could not commit (in-line) a transaction"; stmt->errormsg = "Could not commit (in-line) a transaction";
stmt->errornumber = STMT_EXEC_ERROR; stmt->errornumber = STMT_EXEC_ERROR;
SC_log_error(func, "", stmt); SC_log_error(func, "", stmt);
@ -613,8 +554,7 @@ SQLParamData(
/* Done, now copy the params and then execute the statement */ /* Done, now copy the params and then execute the statement */
if (stmt->data_at_exec == 0) if (stmt->data_at_exec == 0) {
{
retval = copy_statement_with_parameters(stmt); retval = copy_statement_with_parameters(stmt);
if (retval != SQL_SUCCESS) if (retval != SQL_SUCCESS)
return retval; return retval;
@ -624,17 +564,14 @@ SQLParamData(
return SC_execute(stmt); return SC_execute(stmt);
} }
/* /* Set beginning param; if first time SQLParamData is called , start at 0.
* Set beginning param; if first time SQLParamData is called , start Otherwise, start at the last parameter + 1.
* at 0. Otherwise, start at the last parameter + 1.
*/ */
i = stmt->current_exec_param >= 0 ? stmt->current_exec_param+1 : 0; i = stmt->current_exec_param >= 0 ? stmt->current_exec_param+1 : 0;
/* At least 1 data at execution parameter, so Fill in the token value */ /* At least 1 data at execution parameter, so Fill in the token value */
for (; i < stmt->parameters_allocated; i++) for ( ; i < stmt->parameters_allocated; i++) {
{ if (stmt->parameters[i].data_at_exec == TRUE) {
if (stmt->parameters[i].data_at_exec == TRUE)
{
stmt->data_at_exec--; stmt->data_at_exec--;
stmt->current_exec_param = i; stmt->current_exec_param = i;
stmt->put_data = FALSE; stmt->put_data = FALSE;
@ -651,30 +588,26 @@ SQLParamData(
/* Supplies parameter data at execution time. Used in conjunction with */ /* Supplies parameter data at execution time. Used in conjunction with */
/* SQLParamData. */ /* SQLParamData. */
RETCODE SQL_API RETCODE SQL_API SQLPutData(
SQLPutData(
HSTMT hstmt, HSTMT hstmt,
PTR rgbValue, PTR rgbValue,
SDWORD cbValue) SDWORD cbValue)
{ {
static char *func = "SQLPutData"; static char *func = "SQLPutData";
StatementClass *stmt = (StatementClass *) hstmt; StatementClass *stmt = (StatementClass *) hstmt;
int old_pos, int old_pos, retval;
retval;
ParameterInfoClass *current_param; ParameterInfoClass *current_param;
char *buffer; char *buffer;
mylog( "%s: entering...\n", func); mylog( "%s: entering...\n", func);
if (!stmt) if ( ! stmt) {
{
SC_log_error(func, "", NULL); SC_log_error(func, "", NULL);
return SQL_INVALID_HANDLE; return SQL_INVALID_HANDLE;
} }
if (stmt->current_exec_param < 0) if (stmt->current_exec_param < 0) {
{
stmt->errornumber = STMT_SEQUENCE_ERROR; stmt->errornumber = STMT_SEQUENCE_ERROR;
stmt->errormsg = "Previous call was not SQLPutData or SQLParamData"; stmt->errormsg = "Previous call was not SQLPutData or SQLParamData";
SC_log_error(func, "", stmt); SC_log_error(func, "", stmt);
@ -683,16 +616,14 @@ SQLPutData(
current_param = &(stmt->parameters[stmt->current_exec_param]); current_param = &(stmt->parameters[stmt->current_exec_param]);
if (!stmt->put_data) if ( ! stmt->put_data) { /* first call */
{ /* first call */
mylog("SQLPutData: (1) cbValue = %d\n", cbValue); mylog("SQLPutData: (1) cbValue = %d\n", cbValue);
stmt->put_data = TRUE; stmt->put_data = TRUE;
current_param->EXEC_used = (SDWORD *) malloc(sizeof(SDWORD)); current_param->EXEC_used = (SDWORD *) malloc(sizeof(SDWORD));
if (!current_param->EXEC_used) if ( ! current_param->EXEC_used) {
{
stmt->errornumber = STMT_NO_MEMORY_ERROR; stmt->errornumber = STMT_NO_MEMORY_ERROR;
stmt->errormsg = "Out of memory in SQLPutData (1)"; stmt->errormsg = "Out of memory in SQLPutData (1)";
SC_log_error(func, "", stmt); SC_log_error(func, "", stmt);
@ -706,17 +637,15 @@ SQLPutData(
/* Handle Long Var Binary with Large Objects */ /* Handle Long Var Binary with Large Objects */
if (current_param->SQLType == SQL_LONGVARBINARY) if ( current_param->SQLType == SQL_LONGVARBINARY) {
{
/* begin transaction if needed */ /* begin transaction if needed */
if (!CC_is_in_trans(stmt->hdbc)) if(!CC_is_in_trans(stmt->hdbc)) {
{
QResultClass *res; QResultClass *res;
char ok; char ok;
res = CC_send_query(stmt->hdbc, "BEGIN", NULL); res = CC_send_query(stmt->hdbc, "BEGIN", NULL);
if (!res) if (!res) {
{
stmt->errormsg = "Could not begin (in-line) a transaction"; stmt->errormsg = "Could not begin (in-line) a transaction";
stmt->errornumber = STMT_EXEC_ERROR; stmt->errornumber = STMT_EXEC_ERROR;
SC_log_error(func, "", stmt); SC_log_error(func, "", stmt);
@ -724,8 +653,7 @@ SQLPutData(
} }
ok = QR_command_successful(res); ok = QR_command_successful(res);
QR_Destructor(res); QR_Destructor(res);
if (!ok) if (!ok) {
{
stmt->errormsg = "Could not begin (in-line) a transaction"; stmt->errormsg = "Could not begin (in-line) a transaction";
stmt->errornumber = STMT_EXEC_ERROR; stmt->errornumber = STMT_EXEC_ERROR;
SC_log_error(func, "", stmt); SC_log_error(func, "", stmt);
@ -737,8 +665,7 @@ SQLPutData(
/* store the oid */ /* store the oid */
current_param->lobj_oid = lo_creat(stmt->hdbc, INV_READ | INV_WRITE); current_param->lobj_oid = lo_creat(stmt->hdbc, INV_READ | INV_WRITE);
if (current_param->lobj_oid == 0) if (current_param->lobj_oid == 0) {
{
stmt->errornumber = STMT_EXEC_ERROR; stmt->errornumber = STMT_EXEC_ERROR;
stmt->errormsg = "Couldnt create large object."; stmt->errormsg = "Couldnt create large object.";
SC_log_error(func, "", stmt); SC_log_error(func, "", stmt);
@ -751,8 +678,7 @@ SQLPutData(
/* store the fd */ /* store the fd */
stmt->lobj_fd = lo_open(stmt->hdbc, current_param->lobj_oid, INV_WRITE); stmt->lobj_fd = lo_open(stmt->hdbc, current_param->lobj_oid, INV_WRITE);
if (stmt->lobj_fd < 0) if ( stmt->lobj_fd < 0) {
{
stmt->errornumber = STMT_EXEC_ERROR; stmt->errornumber = STMT_EXEC_ERROR;
stmt->errormsg = "Couldnt open large object for writing."; stmt->errormsg = "Couldnt open large object for writing.";
SC_log_error(func, "", stmt); SC_log_error(func, "", stmt);
@ -761,27 +687,22 @@ SQLPutData(
retval = lo_write(stmt->hdbc, stmt->lobj_fd, rgbValue, cbValue); retval = lo_write(stmt->hdbc, stmt->lobj_fd, rgbValue, cbValue);
mylog("lo_write: cbValue=%d, wrote %d bytes\n", cbValue, retval); mylog("lo_write: cbValue=%d, wrote %d bytes\n", cbValue, retval);
}
else
{ /* for handling text fields and small
* binaries */
if (cbValue == SQL_NTS) }
{ else { /* for handling text fields and small binaries */
if (cbValue == SQL_NTS) {
current_param->EXEC_buffer = strdup(rgbValue); current_param->EXEC_buffer = strdup(rgbValue);
if (!current_param->EXEC_buffer) if ( ! current_param->EXEC_buffer) {
{
stmt->errornumber = STMT_NO_MEMORY_ERROR; stmt->errornumber = STMT_NO_MEMORY_ERROR;
stmt->errormsg = "Out of memory in SQLPutData (2)"; stmt->errormsg = "Out of memory in SQLPutData (2)";
SC_log_error(func, "", stmt); SC_log_error(func, "", stmt);
return SQL_ERROR; return SQL_ERROR;
} }
} }
else else {
{
current_param->EXEC_buffer = malloc(cbValue + 1); current_param->EXEC_buffer = malloc(cbValue + 1);
if (!current_param->EXEC_buffer) if ( ! current_param->EXEC_buffer) {
{
stmt->errornumber = STMT_NO_MEMORY_ERROR; stmt->errornumber = STMT_NO_MEMORY_ERROR;
stmt->errormsg = "Out of memory in SQLPutData (2)"; stmt->errormsg = "Out of memory in SQLPutData (2)";
SC_log_error(func, "", stmt); SC_log_error(func, "", stmt);
@ -793,28 +714,25 @@ SQLPutData(
} }
} }
else else { /* calling SQLPutData more than once */
{ /* calling SQLPutData more than once */
mylog("SQLPutData: (>1) cbValue = %d\n", cbValue); mylog("SQLPutData: (>1) cbValue = %d\n", cbValue);
if (current_param->SQLType == SQL_LONGVARBINARY) if (current_param->SQLType == SQL_LONGVARBINARY) {
{
/* the large object fd is in EXEC_buffer */ /* the large object fd is in EXEC_buffer */
retval = lo_write(stmt->hdbc, stmt->lobj_fd, rgbValue, cbValue); retval = lo_write(stmt->hdbc, stmt->lobj_fd, rgbValue, cbValue);
mylog("lo_write(2): cbValue = %d, wrote %d bytes\n", cbValue, retval); mylog("lo_write(2): cbValue = %d, wrote %d bytes\n", cbValue, retval);
*current_param->EXEC_used += cbValue; *current_param->EXEC_used += cbValue;
}
else } else {
{
buffer = current_param->EXEC_buffer; buffer = current_param->EXEC_buffer;
if (cbValue == SQL_NTS) if (cbValue == SQL_NTS) {
{
buffer = realloc(buffer, strlen(buffer) + strlen(rgbValue) + 1); buffer = realloc(buffer, strlen(buffer) + strlen(rgbValue) + 1);
if (!buffer) if ( ! buffer) {
{
stmt->errornumber = STMT_NO_MEMORY_ERROR; stmt->errornumber = STMT_NO_MEMORY_ERROR;
stmt->errormsg = "Out of memory in SQLPutData (3)"; stmt->errormsg = "Out of memory in SQLPutData (3)";
SC_log_error(func, "", stmt); SC_log_error(func, "", stmt);
@ -828,9 +746,10 @@ SQLPutData(
/* reassign buffer incase realloc moved it */ /* reassign buffer incase realloc moved it */
current_param->EXEC_buffer = buffer; current_param->EXEC_buffer = buffer;
} }
else if (cbValue > 0) else if (cbValue > 0) {
{
old_pos = *current_param->EXEC_used; old_pos = *current_param->EXEC_used;
*current_param->EXEC_used += cbValue; *current_param->EXEC_used += cbValue;
@ -839,8 +758,7 @@ SQLPutData(
/* dont lose the old pointer in case out of memory */ /* dont lose the old pointer in case out of memory */
buffer = realloc(current_param->EXEC_buffer, *current_param->EXEC_used + 1); buffer = realloc(current_param->EXEC_buffer, *current_param->EXEC_used + 1);
if (!buffer) if ( ! buffer) {
{
stmt->errornumber = STMT_NO_MEMORY_ERROR; stmt->errornumber = STMT_NO_MEMORY_ERROR;
stmt->errormsg = "Out of memory in SQLPutData (3)"; stmt->errormsg = "Out of memory in SQLPutData (3)";
SC_log_error(func, "", stmt); SC_log_error(func, "", stmt);
@ -852,12 +770,13 @@ SQLPutData(
/* reassign buffer incase realloc moved it */ /* reassign buffer incase realloc moved it */
current_param->EXEC_buffer = buffer; current_param->EXEC_buffer = buffer;
} }
else else {
{
SC_log_error(func, "bad cbValue", stmt); SC_log_error(func, "bad cbValue", stmt);
return SQL_ERROR; return SQL_ERROR;
} }
} }
} }

@ -40,14 +40,10 @@
DWORD DWORD
GetPrivateProfileString(char *theSection, /* section name */ GetPrivateProfileString(char *theSection, /* section name */
char *theKey, /* search key name */ char *theKey, /* search key name */
char *theDefault, /* default value if not char *theDefault, /* default value if not found */
* found */ char *theReturnBuffer, /* return value stored here */
char *theReturnBuffer, /* return value stored size_t theReturnBufferLength, /* byte length of return buffer */
* here */ char *theIniFileName) /* pathname of ini file to search */
size_t theReturnBufferLength, /* byte length of return
* buffer */
char *theIniFileName) /* pathname of ini file to
* search */
{ {
char buf[MAXPGPATH]; char buf[MAXPGPATH];
char* ptr = 0; char* ptr = 0;
@ -78,10 +74,10 @@ GetPrivateProfileString(char *theSection, /* section name */
if( ptr == NULL || *ptr == '\0' ) if( ptr == NULL || *ptr == '\0' )
ptr = "/home"; ptr = "/home";
/* /* This doesn't make it so we find an ini file but allows normal
* This doesn't make it so we find an ini file but allows normal * processing to continue further on down. The likelihood is that
* processing to continue further on down. The likelihood is that the * the file won't be found and thus the default value will be
* file won't be found and thus the default value will be returned. * returned.
*/ */
if( MAXPGPATH-1 < strlen(ptr) + j ) if( MAXPGPATH-1 < strlen(ptr) + j )
{ {
@ -93,13 +89,11 @@ GetPrivateProfileString(char *theSection, /* section name */
sprintf( buf, "%s/%s",ptr,theIniFileName ); sprintf( buf, "%s/%s",ptr,theIniFileName );
/* /* This code makes it so that a file in the users home dir
* This code makes it so that a file in the users home dir overrides a * overrides a the "default" file as passed in
* the "default" file as passed in
*/ */
aFile = (FILE*)(buf ? fopen(buf, PG_BINARY_R) : NULL); aFile = (FILE*)(buf ? fopen(buf, PG_BINARY_R) : NULL);
if (!aFile) if(!aFile) {
{
sprintf(buf,"%s",theIniFileName); sprintf(buf,"%s",theIniFileName);
aFile = (FILE*)(buf ? fopen(buf, PG_BINARY_R) : NULL); aFile = (FILE*)(buf ? fopen(buf, PG_BINARY_R) : NULL);
} }
@ -110,7 +104,9 @@ GetPrivateProfileString(char *theSection, /* section name */
if(theReturnBufferLength == 0 || theReturnBuffer == NULL) if(theReturnBufferLength == 0 || theReturnBuffer == NULL)
{ {
if(aFile) if(aFile)
{
fclose(aFile); fclose(aFile);
}
return 0; return 0;
} }
@ -132,7 +128,9 @@ GetPrivateProfileString(char *theSection, /* section name */
aLineLength = strlen(aLine); aLineLength = strlen(aLine);
/* strip final '\n' */ /* strip final '\n' */
if(aLineLength > 0 && aLine[aLineLength - 1] == '\n') if(aLineLength > 0 && aLine[aLineLength - 1] == '\n')
{
aLine[aLineLength - 1] = '\0'; aLine[aLineLength - 1] = '\0';
}
switch(*aLine) switch(*aLine)
{ {
case ' ': /* blank line */ case ' ': /* blank line */
@ -146,17 +144,17 @@ GetPrivateProfileString(char *theSection, /* section name */
{ {
aStart = aLine + 1; aStart = aLine + 1;
aString--; aString--;
while (isspace((unsigned char) *aStart)) while (isspace((unsigned char) *aStart)) aStart++;
aStart++; while (isspace((unsigned char) *aString)) aString--;
while (isspace((unsigned char) *aString))
aString--;
*(aString+1) = '\0'; *(aString+1) = '\0';
/* accept as matched if NULL key or exact match */ /* accept as matched if NULL key or exact match */
if(!theSection || !strcmp(aStart, theSection)) if(!theSection || !strcmp(aStart, theSection))
{
aSectionFound = TRUE; aSectionFound = TRUE;
} }
}
break; break;
@ -176,24 +174,31 @@ GetPrivateProfileString(char *theSection, /* section name */
/* strip leading blanks in value field */ /* strip leading blanks in value field */
while(*aValue == ' ' && aValue < aLine + sizeof(aLine)) while(*aValue == ' ' && aValue < aLine + sizeof(aLine))
{
*aValue++ = '\0'; *aValue++ = '\0';
}
if(aValue >= aLine + sizeof(aLine)) if(aValue >= aLine + sizeof(aLine))
{
aValue = ""; aValue = "";
} }
}
else else
{
aValue = ""; aValue = "";
}
aStart = aLine; aStart = aLine;
while (isspace((unsigned char) *aStart)) while (isspace((unsigned char) *aStart)) aStart++;
aStart++;
/* strip trailing blanks from key */ /* strip trailing blanks from key */
if(aString) if(aString)
{ {
while(--aString >= aStart && *aString == ' ') while(--aString >= aStart && *aString == ' ')
{
*aString = '\0'; *aString = '\0';
} }
}
/* see if key is matched */ /* see if key is matched */
@ -272,10 +277,11 @@ GetPrivateProfileString(char *theSection, /* section name */
} }
if(aFile) if(aFile)
{
fclose(aFile); fclose(aFile);
}
if (!aKeyFound) if(!aKeyFound) { /* key wasn't found return default */
{ /* key wasn't found return default */
++aLength; /* room for NULL char */ ++aLength; /* room for NULL char */
aLength = theReturnBufferLength < aLength ? aLength = theReturnBufferLength < aLength ?
theReturnBufferLength : aLength; theReturnBufferLength : aLength;
@ -290,8 +296,7 @@ DWORD
WritePrivateProfileString(char *theSection, /* section name */ WritePrivateProfileString(char *theSection, /* section name */
char *theKey, /* write key name */ char *theKey, /* write key name */
char *theBuffer, /* input buffer */ char *theBuffer, /* input buffer */
char *theIniFileName) /* pathname of ini file to char *theIniFileName) /* pathname of ini file to write */
* write */
{ {
return 0; return 0;
} }
@ -305,8 +310,7 @@ DWORD
WritePrivateProfileString(char *theSection, /* section name */ WritePrivateProfileString(char *theSection, /* section name */
char *theKey, /* write key name */ char *theKey, /* write key name */
char *theBuffer, /* input buffer */ char *theBuffer, /* input buffer */
char *theIniFileName) /* pathname of ini file to char *theIniFileName) /* pathname of ini file to write */
* write */
{ {
char buf[MAXPGPATH]; char buf[MAXPGPATH];
char* ptr = 0; char* ptr = 0;
@ -324,12 +328,10 @@ WritePrivateProfileString(char *theSection, /* section name */
/* If this isn't correct processing we'll change it later */ /* If this isn't correct processing we'll change it later */
if(theSection == NULL || theKey == NULL || theBuffer == NULL || if(theSection == NULL || theKey == NULL || theBuffer == NULL ||
theIniFileName == NULL) theIniFileName == NULL) return 0;
return 0;
aLength = strlen(theBuffer); aLength = strlen(theBuffer);
if (aLength == 0) if(aLength == 0) return 0;
return 0;
j = strlen(theIniFileName) + 1; j = strlen(theIniFileName) + 1;
ptr = (char*)getpwuid(getuid()); /* get user info */ ptr = (char*)getpwuid(getuid()); /* get user info */
@ -364,12 +366,10 @@ WritePrivateProfileString(char *theSection, /* section name */
/* overrides a the "default" file as passed in */ /* overrides a the "default" file as passed in */
/* */ /* */
aFile = (FILE*)(buf ? fopen(buf, "r+") : NULL); aFile = (FILE*)(buf ? fopen(buf, "r+") : NULL);
if (!aFile) if(!aFile) {
{
sprintf(buf,"%s",theIniFileName); sprintf(buf,"%s",theIniFileName);
aFile = (FILE*)(buf ? fopen(buf, "r+") : NULL); aFile = (FILE*)(buf ? fopen(buf, "r+") : NULL);
if (!aFile) if(!aFile) return 0;
return 0;
} }
@ -384,7 +384,9 @@ WritePrivateProfileString(char *theSection, /* section name */
aLineLength = strlen(aLine); aLineLength = strlen(aLine);
/* strip final '\n' */ /* strip final '\n' */
if(aLineLength > 0 && aLine[aLineLength - 1] == '\n') if(aLineLength > 0 && aLine[aLineLength - 1] == '\n')
{
aLine[aLineLength - 1] = '\0'; aLine[aLineLength - 1] = '\0';
}
switch(*aLine) switch(*aLine)
{ {
case ' ': /* blank line */ case ' ': /* blank line */
@ -401,8 +403,10 @@ WritePrivateProfileString(char *theSection, /* section name */
/* accept as matched if key exact match */ /* accept as matched if key exact match */
if(!strcmp(aLine + 1, theSection)) if(!strcmp(aLine + 1, theSection))
{
aSectionFound = TRUE; aSectionFound = TRUE;
} }
}
break; break;
@ -422,20 +426,28 @@ WritePrivateProfileString(char *theSection, /* section name */
/* strip leading blanks in value field */ /* strip leading blanks in value field */
while(*aValue == ' ' && aValue < aLine + sizeof(aLine)) while(*aValue == ' ' && aValue < aLine + sizeof(aLine))
{
*aValue++ = '\0'; *aValue++ = '\0';
}
if(aValue >= aLine + sizeof(aLine)) if(aValue >= aLine + sizeof(aLine))
{
aValue = ""; aValue = "";
} }
}
else else
{
aValue = ""; aValue = "";
}
/* strip trailing blanks from key */ /* strip trailing blanks from key */
if(aString) if(aString)
{ {
while(--aString >= aLine && *aString == ' ') while(--aString >= aLine && *aString == ' ')
{
*aString = '\0'; *aString = '\0';
} }
}
/* see if key is matched */ /* see if key is matched */
@ -457,14 +469,14 @@ WritePrivateProfileString(char *theSection, /* section name */
} }
} }
if (!keyFound) if(!keyFound) { /* theKey wasn't in file so */
{ /* theKey wasn't in file so */
if(aFile) if(aFile)
{
fclose(aFile); fclose(aFile);
}
return aReturnLength > 0 ? aReturnLength - 1 : 0; return aReturnLength > 0 ? aReturnLength - 1 : 0;
} }
#endif #endif

@ -13,30 +13,25 @@
#endif #endif
#ifdef __cplusplus #ifdef __cplusplus
extern "C" extern "C" {
{
#endif #endif
DWORD GetPrivateProfileString(char *theSection, /* section name */ DWORD
GetPrivateProfileString(char *theSection, /* section name */
char *theKey, /* search key name */ char *theKey, /* search key name */
char *theDefault, /* default value if not char *theDefault, /* default value if not found */
* found */ char *theReturnBuffer, /* return valuse stored here */
char *theReturnBuffer, /* return valuse stored size_t theBufferLength, /* byte length of return buffer */
* here */ char *theIniFileName); /* pathname of ini file to search */
size_t theBufferLength, /* byte length of return
* buffer */
char *theIniFileName); /* pathname of ini file
* to search */
DWORD WritePrivateProfileString(char *theSection, /* section name */ DWORD
WritePrivateProfileString(char *theSection, /* section name */
char *theKey, /* write key name */ char *theKey, /* write key name */
char *theBuffer, /* input buffer */ char *theBuffer, /* input buffer */
char *theIniFileName); /* pathname of ini file char *theIniFileName); /* pathname of ini file to write */
* to write */
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
#ifndef WIN32 #ifndef WIN32

File diff suppressed because it is too large Load Diff

@ -48,7 +48,7 @@ typedef signed short RETCODE;
# define SQL_VARCHAR 12 # define SQL_VARCHAR 12
# define SQL_TYPE_MIN SQL_CHAR # define SQL_TYPE_MIN SQL_CHAR
#define SQL_TYPE_NUL 0 # define SQL_TYPE_NULL 0
# define SQL_TYPE_MAX SQL_VARCHAR # define SQL_TYPE_MAX SQL_VARCHAR
/* C to SQL datatype mapping */ /* C to SQL datatype mapping */
@ -133,9 +133,11 @@ extern "C"
{ {
#endif #endif
RETCODE SQL_API SQLAllocConnect(HENV henv, HDBC FAR *phdbc); RETCODE SQL_API SQLAllocConnect (HENV henv,
HDBC FAR * phdbc);
RETCODE SQL_API SQLAllocEnv (HENV FAR * phenv); RETCODE SQL_API SQLAllocEnv (HENV FAR * phenv);
RETCODE SQL_API SQLAllocStmt(HDBC hdbc, HSTMT FAR *phstmt); RETCODE SQL_API SQLAllocStmt (HDBC hdbc,
HSTMT FAR * phstmt);
RETCODE SQL_API SQLBindCol (HSTMT hstmt, RETCODE SQL_API SQLBindCol (HSTMT hstmt,
UWORD icol, UWORD icol,
SWORD fCType, SWORD fCType,
@ -202,17 +204,22 @@ extern "C"
SWORD cbCursorMax, SWORD cbCursorMax,
SWORD FAR * pcbCursor); SWORD FAR * pcbCursor);
RETCODE SQL_API SQLNumResultCols(HSTMT hstmt, SWORD FAR *pccol); RETCODE SQL_API SQLNumResultCols (HSTMT hstmt,
SWORD FAR * pccol);
RETCODE SQL_API SQLPrepare(HSTMT hstmt, UCHAR FAR *szSqlStr, RETCODE SQL_API SQLPrepare (HSTMT hstmt,
UCHAR FAR * szSqlStr,
SDWORD cbSqlStr); SDWORD cbSqlStr);
RETCODE SQL_API SQLRowCount(HSTMT hstmt, SDWORD FAR *pcrow); RETCODE SQL_API SQLRowCount (HSTMT hstmt,
SDWORD FAR * pcrow);
RETCODE SQL_API SQLSetCursorName(HSTMT hstmt, UCHAR FAR *szCursor, RETCODE SQL_API SQLSetCursorName (HSTMT hstmt,
UCHAR FAR * szCursor,
SWORD cbCursor); SWORD cbCursor);
RETCODE SQL_API SQLTransact(HENV henv, HDBC hdbc, RETCODE SQL_API SQLTransact (HENV henv,
HDBC hdbc,
UWORD fType); UWORD fType);
RETCODE SQL_API SQLSetParam (HSTMT hstmt, RETCODE SQL_API SQLSetParam (HSTMT hstmt,
@ -226,6 +233,5 @@ extern "C"
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
#endif #endif

@ -362,41 +362,33 @@ typedef long long int ODBCINT64;
typedef unsigned ODBCINT64 SQLUBIGINT; typedef unsigned ODBCINT64 SQLUBIGINT;
typedef ODBCINT64 SQLBIGINT; typedef ODBCINT64 SQLBIGINT;
#else /* Used even on platforms with 64 bit ints #else /* Used even on platforms with 64 bit ints but not GCC */
* but not GCC */
typedef struct typedef struct {
{
SQLUINTEGER dwLowWord; SQLUINTEGER dwLowWord;
SQLUINTEGER dwHighWord; SQLUINTEGER dwHighWord;
} SQLUBIGINT; } SQLUBIGINT;
typedef struct typedef struct {
{
SQLUINTEGER dwLowWord; SQLUINTEGER dwLowWord;
SQLINTEGER dwHighWord; SQLINTEGER dwHighWord;
} SQLBIGINT; } SQLBIGINT;
#endif /* GCC */ #endif /* GCC */
typedef struct tagDATE_STRUCT typedef struct tagDATE_STRUCT {
{
SQLSMALLINT year; SQLSMALLINT year;
SQLUSMALLINT month; SQLUSMALLINT month;
SQLUSMALLINT day; SQLUSMALLINT day;
} DATE_STRUCT, } DATE_STRUCT,SQL_DATE_STRUCT;
SQL_DATE_STRUCT;
typedef struct tagTIME_STRUCT typedef struct tagTIME_STRUCT {
{
SQLUSMALLINT hour; SQLUSMALLINT hour;
SQLUSMALLINT minute; SQLUSMALLINT minute;
SQLUSMALLINT second; SQLUSMALLINT second;
} TIME_STRUCT, } TIME_STRUCT,SQL_TIME_STRUCT;
SQL_TIME_STRUCT;
typedef struct tagTIMESTAMP_STRUCT typedef struct tagTIMESTAMP_STRUCT {
{
SQLSMALLINT year; SQLSMALLINT year;
SQLUSMALLINT month; SQLUSMALLINT month;
SQLUSMALLINT day; SQLUSMALLINT day;
@ -404,8 +396,7 @@ typedef struct tagTIMESTAMP_STRUCT
SQLUSMALLINT minute; SQLUSMALLINT minute;
SQLUSMALLINT second; SQLUSMALLINT second;
SQLUINTEGER fraction; SQLUINTEGER fraction;
} TIMESTAMP_STRUCT, } TIMESTAMP_STRUCT,SQL_TIMESTAMP_STRUCT;
SQL_TIMESTAMP_STRUCT;
/* postodbc doesn't use these but what the heck */ /* postodbc doesn't use these but what the heck */
/* Don't know what SQL_MAX_NUMERIC_LEN should be so I can't include this. It's /* Don't know what SQL_MAX_NUMERIC_LEN should be so I can't include this. It's
@ -420,16 +411,14 @@ typedef struct tagSQL_NUMERIC_STRUCT {
*/ */
typedef struct tagSQLGUID typedef struct tagSQLGUID {
{
DWORD Data1; DWORD Data1;
WORD Data2; WORD Data2;
WORD Data3; WORD Data3;
BYTE Data4[8]; BYTE Data4[8];
} SQLGUID; } SQLGUID;
typedef enum typedef enum {
{
SQL_IS_YEAR = 1, SQL_IS_YEAR = 1,
SQL_IS_MONTH = 2, SQL_IS_MONTH = 2,
SQL_IS_DAY = 3, SQL_IS_DAY = 3,
@ -445,14 +434,12 @@ typedef enum
SQL_IS_MINUTE_TO_SECOND = 13 SQL_IS_MINUTE_TO_SECOND = 13
} SQLINTERVAL; } SQLINTERVAL;
typedef struct tagSQL_YEAR_MONTH typedef struct tagSQL_YEAR_MONTH {
{
SQLUINTEGER year; SQLUINTEGER year;
SQLUINTEGER month; SQLUINTEGER month;
} SQL_YEAR_MONTH_STRUCT; } SQL_YEAR_MONTH_STRUCT;
typedef struct tagSQL_DAY_SECOND typedef struct tagSQL_DAY_SECOND {
{
SQLUINTEGER day; SQLUINTEGER day;
SQLUINTEGER hour; SQLUINTEGER hour;
SQLUINTEGER minute; SQLUINTEGER minute;
@ -460,12 +447,10 @@ typedef struct tagSQL_DAY_SECOND
SQLUINTEGER fraction; SQLUINTEGER fraction;
} SQL_DAY_SECOND_STRUCT; } SQL_DAY_SECOND_STRUCT;
typedef struct tagSQL_INTERVAL_STRUCT typedef struct tagSQL_INTERVAL_STRUCT {
{
SQLINTERVAL interval_type; SQLINTERVAL interval_type;
SQLSMALLINT interval_sign; SQLSMALLINT interval_sign;
union union {
{
SQL_YEAR_MONTH_STRUCT year_month; SQL_YEAR_MONTH_STRUCT year_month;
SQL_DAY_SECOND_STRUCT day_second; SQL_DAY_SECOND_STRUCT day_second;
} intval; } intval;
@ -1333,8 +1318,7 @@ typedef struct tagSQL_INTERVAL_STRUCT
"VALUE,,VARCHAR,VARYING,VIEW,WHEN,WHENEVER,WHERE,WITH,WORK,YEAR" "VALUE,,VARCHAR,VARYING,VIEW,WHEN,WHENEVER,WHERE,WITH,WORK,YEAR"
# ifdef __cplusplus # ifdef __cplusplus
extern "C" extern "C" {
{
# endif # endif
RETCODE SQL_API SQLSetConnectOption (HDBC, UWORD, UDWORD); RETCODE SQL_API SQLSetConnectOption (HDBC, UWORD, UDWORD);
@ -1550,7 +1534,6 @@ extern "C"
# ifdef __cplusplus # ifdef __cplusplus
} }
# endif # endif
#endif #endif

@ -1,3 +1,4 @@
/* Module: lobj.c /* Module: lobj.c
* *
* Description: This module contains routines related to manipulating * Description: This module contains routines related to manipulating
@ -19,8 +20,7 @@ Oid
lo_creat(ConnectionClass *conn, int mode) lo_creat(ConnectionClass *conn, int mode)
{ {
LO_ARG argv[1]; LO_ARG argv[1];
int retval, int retval, result_len;
result_len;
argv[0].isint = 1; argv[0].isint = 1;
argv[0].len = 4; argv[0].len = 4;
@ -63,8 +63,7 @@ int
lo_close(ConnectionClass *conn, int fd) lo_close(ConnectionClass *conn, int fd)
{ {
LO_ARG argv[1]; LO_ARG argv[1];
int retval, int retval, result_len;
result_len;
argv[0].isint = 1; argv[0].isint = 1;
@ -76,6 +75,7 @@ lo_close(ConnectionClass *conn, int fd)
else else
return retval; return retval;
} }
@ -105,8 +105,7 @@ int
lo_write(ConnectionClass *conn, int fd, char *buf, int len) lo_write(ConnectionClass *conn, int fd, char *buf, int len)
{ {
LO_ARG argv[2]; LO_ARG argv[2];
int retval, int retval, result_len;
result_len;
if (len <= 0) if (len <= 0)
@ -131,8 +130,7 @@ int
lo_lseek(ConnectionClass *conn, int fd, int offset, int whence) lo_lseek(ConnectionClass *conn, int fd, int offset, int whence)
{ {
LO_ARG argv[3]; LO_ARG argv[3];
int retval, int retval, result_len;
result_len;
argv[0].isint = 1; argv[0].isint = 1;
@ -158,8 +156,7 @@ int
lo_tell(ConnectionClass *conn, int fd) lo_tell(ConnectionClass *conn, int fd)
{ {
LO_ARG argv[1]; LO_ARG argv[1];
int retval, int retval, result_len;
result_len;
argv[0].isint = 1; argv[0].isint = 1;
@ -177,8 +174,7 @@ int
lo_unlink(ConnectionClass *conn, Oid lobjId) lo_unlink(ConnectionClass *conn, Oid lobjId)
{ {
LO_ARG argv[1]; LO_ARG argv[1];
int retval, int retval, result_len;
result_len;
argv[0].isint = 1; argv[0].isint = 1;
@ -191,3 +187,11 @@ lo_unlink(ConnectionClass *conn, Oid lobjId)
else else
return retval; return retval;
} }

@ -13,8 +13,7 @@
#include "psqlodbc.h" #include "psqlodbc.h"
struct lo_arg struct lo_arg {
{
int isint; int isint;
int len; int len;
union union
@ -46,3 +45,4 @@ int lo_tell(ConnectionClass *conn, int fd);
int lo_unlink(ConnectionClass *conn, Oid lobjId); int lo_unlink(ConnectionClass *conn, Oid lobjId);
#endif #endif

@ -1,3 +1,4 @@
/* Module: misc.c /* Module: misc.c
* *
* Description: This module contains miscellaneous routines * Description: This module contains miscellaneous routines
@ -24,8 +25,7 @@
#include <sys/types.h> #include <sys/types.h>
#include <unistd.h> #include <unistd.h>
#else #else
#include <process.h> /* Byron: is this where Windows keeps def. #include <process.h> /* Byron: is this where Windows keeps def. of getpid ? */
* of getpid ? */
#endif #endif
extern GLOBAL_VALUES globals; extern GLOBAL_VALUES globals;
@ -35,10 +35,8 @@ void
generate_filename(char* dirname,char* prefix,char* filename) generate_filename(char* dirname,char* prefix,char* filename)
{ {
int pid = 0; int pid = 0;
#ifndef WIN32 #ifndef WIN32
struct passwd *ptr = 0; struct passwd *ptr = 0;
ptr = getpwuid(getuid()); ptr = getpwuid(getuid());
#endif #endif
pid = getpid(); pid = getpid();
@ -65,12 +63,10 @@ mylog(char *fmt,...)
char filebuf[80]; char filebuf[80];
FILE* LOGFP = globals.mylogFP; FILE* LOGFP = globals.mylogFP;
if (globals.debug) if ( globals.debug) {
{
va_start(args, fmt); va_start(args, fmt);
if (!LOGFP) if (! LOGFP) {
{
generate_filename(MYLOGDIR,MYLOGFILE,filebuf); generate_filename(MYLOGDIR,MYLOGFILE,filebuf);
LOGFP = fopen(filebuf, PG_BINARY_W); LOGFP = fopen(filebuf, PG_BINARY_W);
globals.mylogFP = LOGFP; globals.mylogFP = LOGFP;
@ -83,7 +79,6 @@ mylog(char *fmt,...)
va_end(args); va_end(args);
} }
} }
#endif #endif
@ -96,12 +91,10 @@ qlog(char *fmt,...)
char filebuf[80]; char filebuf[80];
FILE* LOGFP = globals.qlogFP; FILE* LOGFP = globals.qlogFP;
if (globals.commlog) if ( globals.commlog) {
{
va_start(args, fmt); va_start(args, fmt);
if (!LOGFP) if (! LOGFP) {
{
generate_filename(QLOGDIR,QLOGFILE,filebuf); generate_filename(QLOGDIR,QLOGFILE,filebuf);
LOGFP = fopen(filebuf, PG_BINARY_W); LOGFP = fopen(filebuf, PG_BINARY_W);
globals.qlogFP = LOGFP; globals.qlogFP = LOGFP;
@ -114,7 +107,6 @@ qlog(char *fmt,...)
va_end(args); va_end(args);
} }
} }
#endif #endif
/* Undefine these because windows.h will redefine and cause a warning */ /* Undefine these because windows.h will redefine and cause a warning */
@ -144,8 +136,7 @@ my_strcpy(char *dst, int dst_len, char *src, int src_len)
if (dst_len <= 0) if (dst_len <= 0)
return STRCPY_FAIL; return STRCPY_FAIL;
if (src_len == SQL_NULL_DATA) if (src_len == SQL_NULL_DATA) {
{
dst[0] = '\0'; dst[0] = '\0';
return STRCPY_NULL; return STRCPY_NULL;
} }
@ -155,15 +146,12 @@ my_strcpy(char *dst, int dst_len, char *src, int src_len)
if (src_len <= 0) if (src_len <= 0)
return STRCPY_FAIL; return STRCPY_FAIL;
else else {
{ if (src_len < dst_len) {
if (src_len < dst_len)
{
memcpy(dst, src, src_len); memcpy(dst, src, src_len);
dst[src_len] = '\0'; dst[src_len] = '\0';
} }
else else {
{
memcpy(dst, src, dst_len-1); memcpy(dst, src, dst_len-1);
dst[dst_len-1] = '\0'; /* truncated */ dst[dst_len-1] = '\0'; /* truncated */
return STRCPY_TRUNCATED; return STRCPY_TRUNCATED;
@ -177,29 +165,29 @@ my_strcpy(char *dst, int dst_len, char *src, int src_len)
/* the destination string if src has len characters or more. */ /* the destination string if src has len characters or more. */
/* instead, I want it to copy up to len-1 characters and always */ /* instead, I want it to copy up to len-1 characters and always */
/* terminate the destination string. */ /* terminate the destination string. */
char * char *strncpy_null(char *dst, const char *src, int len)
strncpy_null(char *dst, const char *src, int len)
{ {
int i; int i;
if (NULL != dst) if (NULL != dst) {
{
/* Just in case, check for special lengths */ /* Just in case, check for special lengths */
if (len == SQL_NULL_DATA) if (len == SQL_NULL_DATA) {
{
dst[0] = '\0'; dst[0] = '\0';
return NULL; return NULL;
} }
else if (len == SQL_NTS) else if (len == SQL_NTS)
len = strlen(src) + 1; len = strlen(src) + 1;
for (i = 0; src[i] && i < len - 1; i++) for(i = 0; src[i] && i < len - 1; i++) {
dst[i] = src[i]; dst[i] = src[i];
}
if (len > 0) if(len > 0) {
dst[i] = '\0'; dst[i] = '\0';
} }
}
return dst; return dst;
} }
@ -212,12 +200,10 @@ make_string(char *s, int len, char *buf)
int length; int length;
char *str; char *str;
if (s && (len > 0 || (len == SQL_NTS && strlen(s) > 0))) if(s && (len > 0 || (len == SQL_NTS && strlen(s) > 0))) {
{
length = (len > 0) ? len : strlen(s); length = (len > 0) ? len : strlen(s);
if (buf) if (buf) {
{
strncpy_null(buf, s, length+1); strncpy_null(buf, s, length+1);
return buf; return buf;
} }
@ -240,8 +226,8 @@ make_string(char *s, int len, char *buf)
char * char *
my_strcat(char *buf, char *fmt, char *s, int len) my_strcat(char *buf, char *fmt, char *s, int len)
{ {
if (s && (len > 0 || (len == SQL_NTS && strlen(s) > 0)))
{ if (s && (len > 0 || (len == SQL_NTS && strlen(s) > 0))) {
int length = (len > 0) ? len : strlen(s); int length = (len > 0) ? len : strlen(s);
int pos = strlen(buf); int pos = strlen(buf);
@ -252,26 +238,24 @@ my_strcat(char *buf, char *fmt, char *s, int len)
return NULL; return NULL;
} }
void void remove_newlines(char *string)
remove_newlines(char *string)
{ {
unsigned int i; unsigned int i;
for (i = 0; i < strlen(string); i++) for(i=0; i < strlen(string); i++) {
{
if((string[i] == '\n') || if((string[i] == '\n') ||
(string[i] == '\r')) (string[i] == '\r')) {
string[i] = ' '; string[i] = ' ';
} }
} }
}
char * char *
trim(char *s) trim(char *s)
{ {
int i; int i;
for (i = strlen(s) - 1; i >= 0; i--) for (i = strlen(s) - 1; i >= 0; i--) {
{
if (s[i] == ' ') if (s[i] == ' ')
s[i] = '\0'; s[i] = '\0';
else else

@ -46,7 +46,6 @@
#define MYLOGDIR "c:" #define MYLOGDIR "c:"
#endif #endif
extern void mylog(char * fmt, ...); extern void mylog(char * fmt, ...);
#else #else
#ifndef WIN32 #ifndef WIN32
#define mylog(args...) /* GNU convention for variable arguments */ #define mylog(args...) /* GNU convention for variable arguments */
@ -63,7 +62,6 @@ extern void mylog(char *fmt,...);
#define QLOGDIR "c:" #define QLOGDIR "c:"
#endif #endif
extern void qlog(char * fmt, ...); extern void qlog(char * fmt, ...);
#else #else
#ifndef WIN32 #ifndef WIN32
#define qlog(args...) /* GNU convention for variable arguments */ #define qlog(args...) /* GNU convention for variable arguments */

@ -1,3 +1,4 @@
/* Module: options.c /* Module: options.c
* *
* Description: This module contains routines for getting/setting * Description: This module contains routines for getting/setting
@ -44,8 +45,7 @@ RETCODE set_statement_option(ConnectionClass *conn,
RETCODE RETCODE set_statement_option(ConnectionClass *conn,
set_statement_option(ConnectionClass *conn,
StatementClass *stmt, StatementClass *stmt,
UWORD fOption, UWORD fOption,
UDWORD vParam) UDWORD vParam)
@ -54,86 +54,70 @@ set_statement_option(ConnectionClass *conn,
char changed = FALSE; char changed = FALSE;
switch (fOption) switch(fOption) {
{
case SQL_ASYNC_ENABLE:/* ignored */ case SQL_ASYNC_ENABLE:/* ignored */
break; break;
case SQL_BIND_TYPE: case SQL_BIND_TYPE:
/* now support multi-column and multi-row binding */ /* now support multi-column and multi-row binding */
if (conn) if (conn) conn->stmtOptions.bind_size = vParam;
conn->stmtOptions.bind_size = vParam; if (stmt) stmt->options.bind_size = vParam;
if (stmt)
stmt->options.bind_size = vParam;
break; break;
case SQL_CONCURRENCY: case SQL_CONCURRENCY:
/* positioned update isn't supported so cursor concurrency is read-only */
/* if (conn) conn->stmtOptions.scroll_concurrency = vParam;
* positioned update isn't supported so cursor concurrency is if (stmt) stmt->options.scroll_concurrency = vParam;
* read-only
*/
if (conn)
conn->stmtOptions.scroll_concurrency = vParam;
if (stmt)
stmt->options.scroll_concurrency = vParam;
break; break;
/* /*
* if (globals.lie) { if (conn) if (globals.lie) {
* conn->stmtOptions.scroll_concurrency = vParam; if (stmt) if (conn) conn->stmtOptions.scroll_concurrency = vParam;
* stmt->options.scroll_concurrency = vParam; } else { if (stmt) stmt->options.scroll_concurrency = vParam;
* }
* if (conn) conn->stmtOptions.scroll_concurrency = else {
* SQL_CONCUR_READ_ONLY; if (stmt)
* stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY; if (conn) conn->stmtOptions.scroll_concurrency = SQL_CONCUR_READ_ONLY;
* if (stmt) stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
* if (vParam != SQL_CONCUR_READ_ONLY) changed = TRUE; } break;
if (vParam != SQL_CONCUR_READ_ONLY)
changed = TRUE;
}
break;
*/ */
case SQL_CURSOR_TYPE: case SQL_CURSOR_TYPE:
/* if declare/fetch, then type can only be forward.
/* otherwise, it can only be forward or static.
* if declare/fetch, then type can only be forward. otherwise,
* it can only be forward or static.
*/ */
mylog("SetStmtOption(): SQL_CURSOR_TYPE = %d\n", vParam); mylog("SetStmtOption(): SQL_CURSOR_TYPE = %d\n", vParam);
if (globals.lie) if (globals.lie) {
{
if (conn) if (conn) conn->stmtOptions.cursor_type = vParam;
conn->stmtOptions.cursor_type = vParam; if (stmt) stmt->options.cursor_type = vParam;
if (stmt)
stmt->options.cursor_type = vParam;
} }
else else {
{ if (globals.use_declarefetch) {
if (globals.use_declarefetch)
{ if (conn) conn->stmtOptions.cursor_type = SQL_CURSOR_FORWARD_ONLY;
if (conn) if (stmt) stmt->options.cursor_type = SQL_CURSOR_FORWARD_ONLY;
conn->stmtOptions.cursor_type = SQL_CURSOR_FORWARD_ONLY;
if (stmt)
stmt->options.cursor_type = SQL_CURSOR_FORWARD_ONLY;
if (vParam != SQL_CURSOR_FORWARD_ONLY) if (vParam != SQL_CURSOR_FORWARD_ONLY)
changed = TRUE; changed = TRUE;
} }
else else {
{ if (vParam == SQL_CURSOR_FORWARD_ONLY || vParam == SQL_CURSOR_STATIC) {
if (vParam == SQL_CURSOR_FORWARD_ONLY || vParam == SQL_CURSOR_STATIC)
{ if (conn) conn->stmtOptions.cursor_type = vParam; /* valid type */
if (conn) if (stmt) stmt->options.cursor_type = vParam; /* valid type */
conn->stmtOptions.cursor_type = vParam; /* valid type */
if (stmt)
stmt->options.cursor_type = vParam; /* valid type */
} }
else else {
{
if (conn) if (conn) conn->stmtOptions.cursor_type = SQL_CURSOR_STATIC;
conn->stmtOptions.cursor_type = SQL_CURSOR_STATIC; if (stmt) stmt->options.cursor_type = SQL_CURSOR_STATIC;
if (stmt)
stmt->options.cursor_type = SQL_CURSOR_STATIC;
changed = TRUE; changed = TRUE;
} }
@ -144,34 +128,32 @@ set_statement_option(ConnectionClass *conn,
case SQL_KEYSET_SIZE: /* ignored, but saved and returned */ case SQL_KEYSET_SIZE: /* ignored, but saved and returned */
mylog("SetStmtOption(): SQL_KEYSET_SIZE, vParam = %d\n", vParam); mylog("SetStmtOption(): SQL_KEYSET_SIZE, vParam = %d\n", vParam);
if (conn) if (conn) conn->stmtOptions.keyset_size = vParam;
conn->stmtOptions.keyset_size = vParam; if (stmt) stmt->options.keyset_size = vParam;
if (stmt)
stmt->options.keyset_size = vParam;
break; break;
/* /*
* if (globals.lie) stmt->keyset_size = vParam; else { if (globals.lie)
* stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR; stmt->keyset_size = vParam;
* stmt->errormsg = "Driver does not support keyset size else {
* option"; SC_log_error(func, "", stmt); return SQL_ERROR; } stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR;
stmt->errormsg = "Driver does not support keyset size option";
SC_log_error(func, "", stmt);
return SQL_ERROR;
}
*/ */
case SQL_MAX_LENGTH:/* ignored, but saved */ case SQL_MAX_LENGTH:/* ignored, but saved */
mylog("SetStmtOption(): SQL_MAX_LENGTH, vParam = %d\n", vParam); mylog("SetStmtOption(): SQL_MAX_LENGTH, vParam = %d\n", vParam);
if (conn) if (conn) conn->stmtOptions.maxLength = vParam;
conn->stmtOptions.maxLength = vParam; if (stmt) stmt->options.maxLength = vParam;
if (stmt)
stmt->options.maxLength = vParam;
break; break;
case SQL_MAX_ROWS: /* ignored, but saved */ case SQL_MAX_ROWS: /* ignored, but saved */
mylog("SetStmtOption(): SQL_MAX_ROWS, vParam = %d\n", vParam); mylog("SetStmtOption(): SQL_MAX_ROWS, vParam = %d\n", vParam);
if (conn) if (conn) conn->stmtOptions.maxRows = vParam;
conn->stmtOptions.maxRows = vParam; if (stmt) stmt->options.maxRows = vParam;
if (stmt)
stmt->options.maxRows = vParam;
break; break;
case SQL_NOSCAN: /* ignored */ case SQL_NOSCAN: /* ignored */
@ -185,47 +167,39 @@ set_statement_option(ConnectionClass *conn,
case SQL_RETRIEVE_DATA: /* ignored, but saved */ case SQL_RETRIEVE_DATA: /* ignored, but saved */
mylog("SetStmtOption(): SQL_RETRIEVE_DATA, vParam = %d\n", vParam); mylog("SetStmtOption(): SQL_RETRIEVE_DATA, vParam = %d\n", vParam);
if (conn) if (conn) conn->stmtOptions.retrieve_data = vParam;
conn->stmtOptions.retrieve_data = vParam; if (stmt) stmt->options.retrieve_data = vParam;
if (stmt)
stmt->options.retrieve_data = vParam;
break; break;
case SQL_ROWSET_SIZE: case SQL_ROWSET_SIZE:
mylog("SetStmtOption(): SQL_ROWSET_SIZE, vParam = %d\n", vParam); mylog("SetStmtOption(): SQL_ROWSET_SIZE, vParam = %d\n", vParam);
/* /* Save old rowset size for SQLExtendedFetch purposes
* Save old rowset size for SQLExtendedFetch purposes If the If the rowset_size is being changed since the last call
* rowset_size is being changed since the last call to fetch to fetch rows.
* rows.
*/ */
if (stmt && stmt->save_rowset_size <= 0 && stmt->last_fetch_count > 0 ) if (stmt && stmt->save_rowset_size <= 0 && stmt->last_fetch_count > 0 )
stmt->save_rowset_size = stmt->options.rowset_size; stmt->save_rowset_size = stmt->options.rowset_size;
if (vParam < 1) if (vParam < 1) {
{
vParam = 1; vParam = 1;
changed = TRUE; changed = TRUE;
} }
if (conn) if (conn) conn->stmtOptions.rowset_size = vParam;
conn->stmtOptions.rowset_size = vParam; if (stmt) stmt->options.rowset_size = vParam;
if (stmt)
stmt->options.rowset_size = vParam;
break; break;
case SQL_SIMULATE_CURSOR: /* NOT SUPPORTED */ case SQL_SIMULATE_CURSOR: /* NOT SUPPORTED */
if (stmt) if (stmt) {
{
stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR; stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR;
stmt->errormsg = "Simulated positioned update/delete not supported. Use the cursor library."; stmt->errormsg = "Simulated positioned update/delete not supported. Use the cursor library.";
SC_log_error(func, "", stmt); SC_log_error(func, "", stmt);
} }
if (conn) if (conn) {
{
conn->errornumber = STMT_NOT_IMPLEMENTED_ERROR; conn->errornumber = STMT_NOT_IMPLEMENTED_ERROR;
conn->errormsg = "Simulated positioned update/delete not supported. Use the cursor library."; conn->errormsg = "Simulated positioned update/delete not supported. Use the cursor library.";
CC_log_error(func, "", conn); CC_log_error(func, "", conn);
@ -234,25 +208,21 @@ set_statement_option(ConnectionClass *conn,
case SQL_USE_BOOKMARKS: case SQL_USE_BOOKMARKS:
if (stmt) if (stmt) stmt->options.use_bookmarks = vParam;
stmt->options.use_bookmarks = vParam; if (conn) conn->stmtOptions.use_bookmarks = vParam;
if (conn)
conn->stmtOptions.use_bookmarks = vParam;
break; break;
default: default:
{ {
char option[64]; char option[64];
if (stmt) if (stmt) {
{
stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR; stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR;
stmt->errormsg = "Unknown statement option (Set)"; stmt->errormsg = "Unknown statement option (Set)";
sprintf(option, "fOption=%d, vParam=%ld", fOption, vParam); sprintf(option, "fOption=%d, vParam=%ld", fOption, vParam);
SC_log_error(func, option, stmt); SC_log_error(func, option, stmt);
} }
if (conn) if (conn) {
{
conn->errornumber = STMT_NOT_IMPLEMENTED_ERROR; conn->errornumber = STMT_NOT_IMPLEMENTED_ERROR;
conn->errormsg = "Unknown statement option (Set)"; conn->errormsg = "Unknown statement option (Set)";
sprintf(option, "fOption=%d, vParam=%ld", fOption, vParam); sprintf(option, "fOption=%d, vParam=%ld", fOption, vParam);
@ -263,15 +233,12 @@ set_statement_option(ConnectionClass *conn,
} }
} }
if (changed) if (changed) {
{ if (stmt) {
if (stmt)
{
stmt->errormsg = "Requested value changed."; stmt->errormsg = "Requested value changed.";
stmt->errornumber = STMT_OPTION_VALUE_CHANGED; stmt->errornumber = STMT_OPTION_VALUE_CHANGED;
} }
if (conn) if (conn) {
{
conn->errormsg = "Requested value changed."; conn->errormsg = "Requested value changed.";
conn->errornumber = STMT_OPTION_VALUE_CHANGED; conn->errornumber = STMT_OPTION_VALUE_CHANGED;
} }
@ -284,8 +251,7 @@ set_statement_option(ConnectionClass *conn,
/* Implements only SQL_AUTOCOMMIT */ /* Implements only SQL_AUTOCOMMIT */
RETCODE SQL_API RETCODE SQL_API SQLSetConnectOption(
SQLSetConnectOption(
HDBC hdbc, HDBC hdbc,
UWORD fOption, UWORD fOption,
UDWORD vParam) UDWORD vParam)
@ -298,19 +264,15 @@ SQLSetConnectOption(
mylog("%s: entering...\n", func); mylog("%s: entering...\n", func);
if (!conn) if ( ! conn) {
{
CC_log_error(func, "", NULL); CC_log_error(func, "", NULL);
return SQL_INVALID_HANDLE; return SQL_INVALID_HANDLE;
} }
switch (fOption) switch (fOption) {
{ /* Statement Options
(apply to all stmts on the connection and become defaults for new stmts)
/*
* Statement Options (apply to all stmts on the connection and
* become defaults for new stmts)
*/ */
case SQL_ASYNC_ENABLE: case SQL_ASYNC_ENABLE:
case SQL_BIND_TYPE: case SQL_BIND_TYPE:
@ -327,16 +289,13 @@ SQLSetConnectOption(
case SQL_USE_BOOKMARKS: case SQL_USE_BOOKMARKS:
/* Affect all current Statements */ /* Affect all current Statements */
for (i = 0; i < conn->num_stmts; i++) for (i = 0; i < conn->num_stmts; i++) {
{ if ( conn->stmts[i]) {
if (conn->stmts[i])
set_statement_option(NULL, conn->stmts[i], fOption, vParam); set_statement_option(NULL, conn->stmts[i], fOption, vParam);
} }
}
/* /* Become the default for all future statements on this connection */
* Become the default for all future statements on this
* connection
*/
retval = set_statement_option(conn, NULL, fOption, vParam); retval = set_statement_option(conn, NULL, fOption, vParam);
if (retval == SQL_SUCCESS_WITH_INFO) if (retval == SQL_SUCCESS_WITH_INFO)
@ -355,8 +314,7 @@ SQLSetConnectOption(
case SQL_AUTOCOMMIT: case SQL_AUTOCOMMIT:
if (CC_is_in_trans(conn)) if (CC_is_in_trans(conn)) {
{
conn->errormsg = "Cannot switch commit mode while a transaction is in progress"; conn->errormsg = "Cannot switch commit mode while a transaction is in progress";
conn->errornumber = CONN_TRANSACT_IN_PROGRES; conn->errornumber = CONN_TRANSACT_IN_PROGRES;
CC_log_error(func, "", conn); CC_log_error(func, "", conn);
@ -365,8 +323,7 @@ SQLSetConnectOption(
mylog("SQLSetConnectOption: AUTOCOMMIT: transact_status=%d, vparam=%d\n", conn->transact_status, vParam); mylog("SQLSetConnectOption: AUTOCOMMIT: transact_status=%d, vparam=%d\n", conn->transact_status, vParam);
switch (vParam) switch(vParam) {
{
case SQL_AUTOCOMMIT_OFF: case SQL_AUTOCOMMIT_OFF:
CC_set_autocommit_off(conn); CC_set_autocommit_off(conn);
break; break;
@ -411,17 +368,16 @@ SQLSetConnectOption(
default: default:
{ {
char option[64]; char option[64];
conn->errormsg = "Unknown connect option (Set)"; conn->errormsg = "Unknown connect option (Set)";
conn->errornumber = CONN_UNSUPPORTED_OPTION; conn->errornumber = CONN_UNSUPPORTED_OPTION;
sprintf(option, "fOption=%d, vParam=%ld", fOption, vParam); sprintf(option, "fOption=%d, vParam=%ld", fOption, vParam);
CC_log_error(func, option, conn); CC_log_error(func, option, conn);
return SQL_ERROR; return SQL_ERROR;
} }
} }
if (changed) if (changed) {
{
conn->errornumber = CONN_OPTION_VALUE_CHANGED; conn->errornumber = CONN_OPTION_VALUE_CHANGED;
conn->errormsg = "Requested value changed."; conn->errormsg = "Requested value changed.";
return SQL_SUCCESS_WITH_INFO; return SQL_SUCCESS_WITH_INFO;
@ -433,8 +389,7 @@ SQLSetConnectOption(
/* - - - - - - - - - */ /* - - - - - - - - - */
/* This function just can tell you whether you are in Autcommit mode or not */ /* This function just can tell you whether you are in Autcommit mode or not */
RETCODE SQL_API RETCODE SQL_API SQLGetConnectOption(
SQLGetConnectOption(
HDBC hdbc, HDBC hdbc,
UWORD fOption, UWORD fOption,
PTR pvParam) PTR pvParam)
@ -444,14 +399,12 @@ SQLGetConnectOption(
mylog("%s: entering...\n", func); mylog("%s: entering...\n", func);
if (!conn) if (! conn) {
{
CC_log_error(func, "", NULL); CC_log_error(func, "", NULL);
return SQL_INVALID_HANDLE; return SQL_INVALID_HANDLE;
} }
switch (fOption) switch (fOption) {
{
case SQL_ACCESS_MODE:/* NOT SUPPORTED */ case SQL_ACCESS_MODE:/* NOT SUPPORTED */
*((UDWORD *) pvParam) = SQL_MODE_READ_WRITE; *((UDWORD *) pvParam) = SQL_MODE_READ_WRITE;
break; break;
@ -495,7 +448,6 @@ SQLGetConnectOption(
default: default:
{ {
char option[64]; char option[64];
conn->errormsg = "Unknown connect option (Get)"; conn->errormsg = "Unknown connect option (Get)";
conn->errornumber = CONN_UNSUPPORTED_OPTION; conn->errornumber = CONN_UNSUPPORTED_OPTION;
sprintf(option, "fOption=%d", fOption); sprintf(option, "fOption=%d", fOption);
@ -503,6 +455,7 @@ SQLGetConnectOption(
return SQL_ERROR; return SQL_ERROR;
break; break;
} }
} }
return SQL_SUCCESS; return SQL_SUCCESS;
@ -510,8 +463,7 @@ SQLGetConnectOption(
/* - - - - - - - - - */ /* - - - - - - - - - */
RETCODE SQL_API RETCODE SQL_API SQLSetStmtOption(
SQLSetStmtOption(
HSTMT hstmt, HSTMT hstmt,
UWORD fOption, UWORD fOption,
UDWORD vParam) UDWORD vParam)
@ -525,8 +477,7 @@ SQLSetStmtOption(
/* all the time, but it tries to set a huge value for SQL_MAX_LENGTH */ /* all the time, but it tries to set a huge value for SQL_MAX_LENGTH */
/* and expects the driver to reduce it to the real value */ /* and expects the driver to reduce it to the real value */
if (!stmt) if( ! stmt) {
{
SC_log_error(func, "", NULL); SC_log_error(func, "", NULL);
return SQL_INVALID_HANDLE; return SQL_INVALID_HANDLE;
} }
@ -537,8 +488,7 @@ SQLSetStmtOption(
/* - - - - - - - - - */ /* - - - - - - - - - */
RETCODE SQL_API RETCODE SQL_API SQLGetStmtOption(
SQLGetStmtOption(
HSTMT hstmt, HSTMT hstmt,
UWORD fOption, UWORD fOption,
PTR pvParam) PTR pvParam)
@ -553,35 +503,29 @@ SQLGetStmtOption(
/* all the time, but it tries to set a huge value for SQL_MAX_LENGTH */ /* all the time, but it tries to set a huge value for SQL_MAX_LENGTH */
/* and expects the driver to reduce it to the real value */ /* and expects the driver to reduce it to the real value */
if (!stmt) if( ! stmt) {
{
SC_log_error(func, "", NULL); SC_log_error(func, "", NULL);
return SQL_INVALID_HANDLE; return SQL_INVALID_HANDLE;
} }
switch (fOption) switch(fOption) {
{
case SQL_GET_BOOKMARK: case SQL_GET_BOOKMARK:
case SQL_ROW_NUMBER: case SQL_ROW_NUMBER:
res = stmt->result; res = stmt->result;
if (stmt->manual_result || !globals.use_declarefetch) if ( stmt->manual_result || ! globals.use_declarefetch) {
{
/* make sure we're positioned on a valid row */ /* make sure we're positioned on a valid row */
if((stmt->currTuple < 0) || if((stmt->currTuple < 0) ||
(stmt->currTuple >= QR_get_num_tuples(res))) (stmt->currTuple >= QR_get_num_tuples(res))) {
{
stmt->errormsg = "Not positioned on a valid row."; stmt->errormsg = "Not positioned on a valid row.";
stmt->errornumber = STMT_INVALID_CURSOR_STATE_ERROR; stmt->errornumber = STMT_INVALID_CURSOR_STATE_ERROR;
SC_log_error(func, "", stmt); SC_log_error(func, "", stmt);
return SQL_ERROR; return SQL_ERROR;
} }
} }
else else {
{ if (stmt->currTuple == -1 || ! res || ! res->tupleField) {
if (stmt->currTuple == -1 || !res || !res->tupleField)
{
stmt->errormsg = "Not positioned on a valid row."; stmt->errormsg = "Not positioned on a valid row.";
stmt->errornumber = STMT_INVALID_CURSOR_STATE_ERROR; stmt->errornumber = STMT_INVALID_CURSOR_STATE_ERROR;
SC_log_error(func, "", stmt); SC_log_error(func, "", stmt);
@ -589,8 +533,7 @@ SQLGetStmtOption(
} }
} }
if (fOption == SQL_GET_BOOKMARK && stmt->options.use_bookmarks == SQL_UB_OFF) if (fOption == SQL_GET_BOOKMARK && stmt->options.use_bookmarks == SQL_UB_OFF) {
{
stmt->errormsg = "Operation invalid because use bookmarks not enabled."; stmt->errormsg = "Operation invalid because use bookmarks not enabled.";
stmt->errornumber = STMT_OPERATION_INVALID; stmt->errornumber = STMT_OPERATION_INVALID;
SC_log_error(func, "", stmt); SC_log_error(func, "", stmt);
@ -660,7 +603,6 @@ SQLGetStmtOption(
default: default:
{ {
char option[64]; char option[64];
stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR; stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR;
stmt->errormsg = "Unknown statement option (Get)"; stmt->errormsg = "Unknown statement option (Get)";
sprintf(option, "fOption=%d", fOption); sprintf(option, "fOption=%d", fOption);

@ -1,3 +1,4 @@
/* Module: parse.c /* Module: parse.c
* *
* Description: This module contains routines related to parsing SQL statements. * Description: This module contains routines related to parsing SQL statements.
@ -46,8 +47,7 @@ getNextToken(char *s, char *token, int smax, char *delim, char *quote, char *dqu
{ {
int i = 0; int i = 0;
int out = 0; int out = 0;
char qc, char qc, in_escape = FALSE;
in_escape = FALSE;
if (smax <= 1) if (smax <= 1)
return NULL; return NULL;
@ -55,53 +55,43 @@ getNextToken(char *s, char *token, int smax, char *delim, char *quote, char *dqu
smax--; smax--;
/* skip leading delimiters */ /* skip leading delimiters */
while (isspace((unsigned char) s[i]) || s[i] == ',') while (isspace((unsigned char) s[i]) || s[i] == ',') {
{
/* mylog("skipping '%c'\n", s[i]); */ /* mylog("skipping '%c'\n", s[i]); */
i++; i++;
} }
if (s[0] == '\0') if (s[0] == '\0') {
{
token[0] = '\0'; token[0] = '\0';
return NULL; return NULL;
} }
if (quote) if (quote) *quote = FALSE;
*quote = FALSE; if (dquote) *dquote = FALSE;
if (dquote) if (numeric) *numeric = FALSE;
*dquote = FALSE;
if (numeric)
*numeric = FALSE;
/* get the next token */ /* get the next token */
while ( ! isspace((unsigned char) s[i]) && s[i] != ',' && while ( ! isspace((unsigned char) s[i]) && s[i] != ',' &&
s[i] != '\0' && out != smax) s[i] != '\0' && out != smax) {
{
/* Handle quoted stuff */ /* Handle quoted stuff */
if (out == 0 && (s[i] == '\"' || s[i] == '\'')) if ( out == 0 && (s[i] == '\"' || s[i] == '\'')) {
{
qc = s[i]; qc = s[i];
if (qc == '\"') if (qc == '\"') {
{ if (dquote) *dquote = TRUE;
if (dquote)
*dquote = TRUE;
} }
if (qc == '\'') if (qc == '\'') {
{ if (quote) *quote = TRUE;
if (quote)
*quote = TRUE;
} }
i++; /* dont return the quote */ i++; /* dont return the quote */
while (s[i] != '\0' && out != smax) while (s[i] != '\0' && out != smax) {
{ if (s[i] == qc && ! in_escape) {
if (s[i] == qc && !in_escape)
break; break;
if (s[i] == '\\' && !in_escape) }
if (s[i] == '\\' && ! in_escape) {
in_escape = TRUE; in_escape = TRUE;
else }
{ else {
in_escape = FALSE; in_escape = FALSE;
token[out++] = s[i]; token[out++] = s[i];
} }
@ -113,10 +103,8 @@ getNextToken(char *s, char *token, int smax, char *delim, char *quote, char *dqu
} }
/* Check for numeric literals */ /* Check for numeric literals */
if (out == 0 && isdigit((unsigned char) s[i])) if ( out == 0 && isdigit((unsigned char) s[i])) {
{ if (numeric) *numeric = TRUE;
if (numeric)
*numeric = TRUE;
token[out++] = s[i++]; token[out++] = s[i++];
while ( isalnum((unsigned char) s[i]) || s[i] == '.') while ( isalnum((unsigned char) s[i]) || s[i] == '.')
token[out++] = s[i++]; token[out++] = s[i++];
@ -124,12 +112,10 @@ getNextToken(char *s, char *token, int smax, char *delim, char *quote, char *dqu
break; break;
} }
if (ispunct((unsigned char) s[i]) && s[i] != '_') if ( ispunct((unsigned char) s[i]) && s[i] != '_') {
{
mylog("got ispunct: s[%d] = '%c'\n", i, s[i]); mylog("got ispunct: s[%d] = '%c'\n", i, s[i]);
if (out == 0) if (out == 0) {
{
token[out++] = s[i++]; token[out++] = s[i++];
break; break;
} }
@ -152,25 +138,20 @@ getNextToken(char *s, char *token, int smax, char *delim, char *quote, char *dqu
i++; i++;
/* return the most priority delimiter */ /* return the most priority delimiter */
if (s[i] == ',') if (s[i] == ',') {
{ if (delim) *delim = s[i];
if (delim)
*delim = s[i];
} }
else if (s[i] == '\0') else if (s[i] == '\0') {
{ if (delim) *delim = '\0';
if (delim)
*delim = '\0';
} }
else else {
{ if (delim) *delim = ' ';
if (delim)
*delim = ' ';
} }
/* skip trailing blanks */ /* skip trailing blanks */
while (isspace((unsigned char) s[i])) while ( isspace((unsigned char) s[i])) {
i++; i++;
}
return &s[i]; return &s[i];
} }
@ -215,11 +196,9 @@ searchColInfo(COL_INFO *col_info, FIELD_INFO *fi)
char *col; char *col;
for (k = 0; k < QR_get_num_tuples(col_info->result); k++) for (k = 0; k < QR_get_num_tuples(col_info->result); k++) {
{
col = QR_get_value_manual(col_info->result, k, 3); col = QR_get_value_manual(col_info->result, k, 3);
if (!strcmp(col, fi->name)) if ( ! strcmp(col, fi->name)) {
{
getColInfo(col_info, fi, k); getColInfo(col_info, fi, k);
mylog("PARSE: searchColInfo: \n"); mylog("PARSE: searchColInfo: \n");
@ -236,28 +215,11 @@ parse_statement(StatementClass *stmt)
{ {
static char *func="parse_statement"; static char *func="parse_statement";
char token[256]; char token[256];
char delim, char delim, quote, dquote, numeric, unquoted;
quote,
dquote,
numeric,
unquoted;
char *ptr; char *ptr;
char in_select = FALSE, char in_select = FALSE, in_distinct = FALSE, in_on = FALSE, in_from = FALSE, in_where = FALSE, in_table = FALSE;
in_distinct = FALSE, char in_field = FALSE, in_expr = FALSE, in_func = FALSE, in_dot = FALSE, in_as = FALSE;
in_on = FALSE, int j, i, k = 0, n, blevel = 0;
in_from = FALSE,
in_where = FALSE,
in_table = FALSE;
char in_field = FALSE,
in_expr = FALSE,
in_func = FALSE,
in_dot = FALSE,
in_as = FALSE;
int j,
i,
k = 0,
n,
blevel = 0;
FIELD_INFO **fi; FIELD_INFO **fi;
TABLE_INFO **ti; TABLE_INFO **ti;
char parse; char parse;
@ -276,38 +238,34 @@ parse_statement(StatementClass *stmt)
stmt->nfld = 0; stmt->nfld = 0;
stmt->ntab = 0; stmt->ntab = 0;
while ((ptr = getNextToken(ptr, token, sizeof(token), &delim, &quote, &dquote, &numeric)) != NULL) while ((ptr = getNextToken(ptr, token, sizeof(token), &delim, &quote, &dquote, &numeric)) != NULL) {
{
unquoted = ! ( quote || dquote ); unquoted = ! ( quote || dquote );
mylog("unquoted=%d, quote=%d, dquote=%d, numeric=%d, delim='%c', token='%s', ptr='%s'\n", unquoted, quote, dquote, numeric, delim, token, ptr); mylog("unquoted=%d, quote=%d, dquote=%d, numeric=%d, delim='%c', token='%s', ptr='%s'\n", unquoted, quote, dquote, numeric, delim, token, ptr);
if (unquoted && !stricmp(token, "select")) if ( unquoted && ! stricmp(token, "select")) {
{
in_select = TRUE; in_select = TRUE;
mylog("SELECT\n"); mylog("SELECT\n");
continue; continue;
} }
if (unquoted && in_select && !stricmp(token, "distinct")) if ( unquoted && in_select && ! stricmp(token, "distinct")) {
{
in_distinct = TRUE; in_distinct = TRUE;
mylog("DISTINCT\n"); mylog("DISTINCT\n");
continue; continue;
} }
if (unquoted && !stricmp(token, "into")) if ( unquoted && ! stricmp(token, "into")) {
{
in_select = FALSE; in_select = FALSE;
mylog("INTO\n"); mylog("INTO\n");
continue; continue;
} }
if (unquoted && !stricmp(token, "from")) if ( unquoted && ! stricmp(token, "from")) {
{
in_select = FALSE; in_select = FALSE;
in_from = TRUE; in_from = TRUE;
@ -319,8 +277,8 @@ parse_statement(StatementClass *stmt)
! stricmp(token, "union") || ! stricmp(token, "union") ||
! stricmp(token, "order") || ! stricmp(token, "order") ||
! stricmp(token, "group") || ! stricmp(token, "group") ||
!stricmp(token, "having"))) ! stricmp(token, "having"))) {
{
in_select = FALSE; in_select = FALSE;
in_from = FALSE; in_from = FALSE;
in_where = TRUE; in_where = TRUE;
@ -329,20 +287,17 @@ parse_statement(StatementClass *stmt)
break; break;
} }
if (in_select) if (in_select) {
{
if (in_distinct) if ( in_distinct) {
{
mylog("in distinct\n"); mylog("in distinct\n");
if (unquoted && !stricmp(token, "on")) if (unquoted && ! stricmp(token, "on")) {
{
in_on = TRUE; in_on = TRUE;
mylog("got on\n"); mylog("got on\n");
continue; continue;
} }
if (in_on) if (in_on) {
{
in_distinct = FALSE; in_distinct = FALSE;
in_on = FALSE; in_on = FALSE;
continue; /* just skip the unique on field */ continue; /* just skip the unique on field */
@ -351,30 +306,25 @@ parse_statement(StatementClass *stmt)
in_distinct = FALSE; in_distinct = FALSE;
} }
if (in_expr || in_func) if ( in_expr || in_func) { /* just eat the expression */
{ /* just eat the expression */
mylog("in_expr=%d or func=%d\n", in_expr, in_func); mylog("in_expr=%d or func=%d\n", in_expr, in_func);
if (quote || dquote) if (quote || dquote)
continue; continue;
if (in_expr && blevel == 0 && delim == ',') if (in_expr && blevel == 0 && delim == ',') {
{
mylog("**** in_expr and Got comma\n"); mylog("**** in_expr and Got comma\n");
in_expr = FALSE; in_expr = FALSE;
in_field = FALSE; in_field = FALSE;
} }
else if (token[0] == '(') else if (token[0] == '(') {
{
blevel++; blevel++;
mylog("blevel++ = %d\n", blevel); mylog("blevel++ = %d\n", blevel);
} }
else if (token[0] == ')') else if (token[0] == ')') {
{
blevel--; blevel--;
mylog("blevel-- = %d\n", blevel); mylog("blevel-- = %d\n", blevel);
if (delim == ',') if (delim==',') {
{
in_func = FALSE; in_func = FALSE;
in_expr = FALSE; in_expr = FALSE;
in_field = FALSE; in_field = FALSE;
@ -383,17 +333,15 @@ parse_statement(StatementClass *stmt)
continue; continue;
} }
if (!in_field) if ( ! in_field) {
{
if ( ! token[0]) if ( ! token[0])
continue; continue;
if (!(stmt->nfld % FLD_INCR)) if ( ! (stmt->nfld % FLD_INCR)) {
{
mylog("reallocing at nfld=%d\n", stmt->nfld); mylog("reallocing at nfld=%d\n", stmt->nfld);
fi = (FIELD_INFO **) realloc(fi, (stmt->nfld + FLD_INCR) * sizeof(FIELD_INFO *)); fi = (FIELD_INFO **) realloc(fi, (stmt->nfld + FLD_INCR) * sizeof(FIELD_INFO *));
if (!fi) if ( ! fi) {
{
stmt->parse_status = STMT_PARSE_FATAL; stmt->parse_status = STMT_PARSE_FATAL;
return FALSE; return FALSE;
} }
@ -401,8 +349,7 @@ parse_statement(StatementClass *stmt)
} }
fi[stmt->nfld] = (FIELD_INFO *) malloc( sizeof(FIELD_INFO)); fi[stmt->nfld] = (FIELD_INFO *) malloc( sizeof(FIELD_INFO));
if (fi[stmt->nfld] == NULL) if (fi[stmt->nfld] == NULL) {
{
stmt->parse_status = STMT_PARSE_FATAL; stmt->parse_status = STMT_PARSE_FATAL;
return FALSE; return FALSE;
} }
@ -414,18 +361,15 @@ parse_statement(StatementClass *stmt)
if (dquote) if (dquote)
fi[stmt->nfld]->dquote = TRUE; fi[stmt->nfld]->dquote = TRUE;
if (quote) if (quote) {
{
fi[stmt->nfld++]->quote = TRUE; fi[stmt->nfld++]->quote = TRUE;
continue; continue;
} }
else if (numeric) else if (numeric) {
{
mylog("**** got numeric: nfld = %d\n", stmt->nfld); mylog("**** got numeric: nfld = %d\n", stmt->nfld);
fi[stmt->nfld]->numeric = TRUE; fi[stmt->nfld]->numeric = TRUE;
} }
else if (token[0] == '(') else if (token[0] == '(') { /* expression */
{ /* expression */
mylog("got EXPRESSION\n"); mylog("got EXPRESSION\n");
fi[stmt->nfld++]->expr = TRUE; fi[stmt->nfld++]->expr = TRUE;
in_expr = TRUE; in_expr = TRUE;
@ -433,17 +377,18 @@ parse_statement(StatementClass *stmt)
continue; continue;
} }
else else {
{
strcpy(fi[stmt->nfld]->name, token); strcpy(fi[stmt->nfld]->name, token);
fi[stmt->nfld]->dot[0] = '\0'; fi[stmt->nfld]->dot[0] = '\0';
} }
mylog("got field='%s', dot='%s'\n", fi[stmt->nfld]->name, fi[stmt->nfld]->dot); mylog("got field='%s', dot='%s'\n", fi[stmt->nfld]->name, fi[stmt->nfld]->dot);
if (delim == ',') if (delim == ',') {
mylog("comma (1)\n"); mylog("comma (1)\n");
else }
else {
in_field = TRUE; in_field = TRUE;
}
stmt->nfld++; stmt->nfld++;
continue; continue;
} }
@ -451,16 +396,14 @@ parse_statement(StatementClass *stmt)
/**************************/ /**************************/
/* We are in a field now */ /* We are in a field now */
/**************************/ /**************************/
if (in_dot) if (in_dot) {
{
stmt->nfld--; stmt->nfld--;
strcpy(fi[stmt->nfld]->dot, fi[stmt->nfld]->name); strcpy(fi[stmt->nfld]->dot, fi[stmt->nfld]->name);
strcpy(fi[stmt->nfld]->name, token); strcpy(fi[stmt->nfld]->name, token);
stmt->nfld++; stmt->nfld++;
in_dot = FALSE; in_dot = FALSE;
if (delim == ',') if (delim == ',') {
{
mylog("in_dot: got comma\n"); mylog("in_dot: got comma\n");
in_field = FALSE; in_field = FALSE;
} }
@ -468,8 +411,7 @@ parse_statement(StatementClass *stmt)
continue; continue;
} }
if (in_as) if (in_as) {
{
stmt->nfld--; stmt->nfld--;
strcpy(fi[stmt->nfld]->alias, token); strcpy(fi[stmt->nfld]->alias, token);
mylog("alias for field '%s' is '%s'\n", fi[stmt->nfld]->name, fi[stmt->nfld]->alias); mylog("alias for field '%s' is '%s'\n", fi[stmt->nfld]->name, fi[stmt->nfld]->alias);
@ -478,35 +420,29 @@ parse_statement(StatementClass *stmt)
stmt->nfld++; stmt->nfld++;
if (delim == ',') if (delim == ',') {
mylog("comma(2)\n"); mylog("comma(2)\n");
}
continue; continue;
} }
/* Function */ /* Function */
if (token[0] == '(') if (token[0] == '(') {
{
in_func = TRUE; in_func = TRUE;
blevel = 1; blevel = 1;
fi[stmt->nfld-1]->func = TRUE; fi[stmt->nfld-1]->func = TRUE;
/* name will have the function name -- maybe useful some day */
/*
* name will have the function name -- maybe useful some
* day
*/
mylog("**** got function = '%s'\n", fi[stmt->nfld-1]->name); mylog("**** got function = '%s'\n", fi[stmt->nfld-1]->name);
continue; continue;
} }
if (token[0] == '.') if (token[0] == '.') {
{
in_dot = TRUE; in_dot = TRUE;
mylog("got dot\n"); mylog("got dot\n");
continue; continue;
} }
if (!stricmp(token, "as")) if ( ! stricmp(token, "as")) {
{
in_as = TRUE; in_as = TRUE;
mylog("got AS\n"); mylog("got AS\n");
continue; continue;
@ -517,28 +453,25 @@ parse_statement(StatementClass *stmt)
fi[stmt->nfld-1]->expr = TRUE; fi[stmt->nfld-1]->expr = TRUE;
fi[stmt->nfld-1]->name[0] = '\0'; fi[stmt->nfld-1]->name[0] = '\0';
mylog("*** setting expression\n"); mylog("*** setting expression\n");
} }
if (in_from) if (in_from) {
{
if (!in_table) if ( ! in_table) {
{
if ( ! token[0]) if ( ! token[0])
continue; continue;
if (!(stmt->ntab % TAB_INCR)) if ( ! (stmt->ntab % TAB_INCR)) {
{
ti = (TABLE_INFO **) realloc(ti, (stmt->ntab + TAB_INCR) * sizeof(TABLE_INFO *)); ti = (TABLE_INFO **) realloc(ti, (stmt->ntab + TAB_INCR) * sizeof(TABLE_INFO *));
if (!ti) if ( ! ti) {
{
stmt->parse_status = STMT_PARSE_FATAL; stmt->parse_status = STMT_PARSE_FATAL;
return FALSE; return FALSE;
} }
stmt->ti = ti; stmt->ti = ti;
} }
ti[stmt->ntab] = (TABLE_INFO *) malloc(sizeof(TABLE_INFO)); ti[stmt->ntab] = (TABLE_INFO *) malloc(sizeof(TABLE_INFO));
if (ti[stmt->ntab] == NULL) if (ti[stmt->ntab] == NULL) {
{
stmt->parse_status = STMT_PARSE_FATAL; stmt->parse_status = STMT_PARSE_FATAL;
return FALSE; return FALSE;
} }
@ -548,10 +481,12 @@ parse_statement(StatementClass *stmt)
strcpy(ti[stmt->ntab]->name, token); strcpy(ti[stmt->ntab]->name, token);
mylog("got table = '%s'\n", ti[stmt->ntab]->name); mylog("got table = '%s'\n", ti[stmt->ntab]->name);
if (delim == ',') if (delim == ',') {
mylog("more than 1 tables\n"); mylog("more than 1 tables\n");
else }
else {
in_table = TRUE; in_table = TRUE;
}
stmt->ntab++; stmt->ntab++;
continue; continue;
} }
@ -559,10 +494,11 @@ parse_statement(StatementClass *stmt)
strcpy(ti[stmt->ntab-1]->alias, token); strcpy(ti[stmt->ntab-1]->alias, token);
mylog("alias for table '%s' is '%s'\n", ti[stmt->ntab-1]->name, ti[stmt->ntab-1]->alias); mylog("alias for table '%s' is '%s'\n", ti[stmt->ntab-1]->name, ti[stmt->ntab-1]->alias);
in_table = FALSE; in_table = FALSE;
if (delim == ',') if (delim == ',') {
mylog("more than 1 tables\n"); mylog("more than 1 tables\n");
} }
} }
}
/*************************************************/ /*************************************************/
@ -572,18 +508,16 @@ parse_statement(StatementClass *stmt)
parse = TRUE; parse = TRUE;
/* Resolve field names with tables */ /* Resolve field names with tables */
for (i = 0; i < stmt->nfld; i++) for (i = 0; i < stmt->nfld; i++) {
{
if (fi[i]->func || fi[i]->expr || fi[i]->numeric) if (fi[i]->func || fi[i]->expr || fi[i]->numeric) {
{
fi[i]->ti = NULL; fi[i]->ti = NULL;
fi[i]->type = -1; fi[i]->type = -1;
parse = FALSE; parse = FALSE;
continue; continue;
} }
else if (fi[i]->quote) else if (fi[i]->quote) { /* handle as text */
{ /* handle as text */
fi[i]->ti = NULL; fi[i]->ti = NULL;
fi[i]->type = PG_TYPE_TEXT; fi[i]->type = PG_TYPE_TEXT;
fi[i]->precision = 0; fi[i]->precision = 0;
@ -591,17 +525,13 @@ parse_statement(StatementClass *stmt)
} }
/* it's a dot, resolve to table or alias */ /* it's a dot, resolve to table or alias */
else if (fi[i]->dot[0]) else if (fi[i]->dot[0]) {
{ for (k = 0; k < stmt->ntab; k++) {
for (k = 0; k < stmt->ntab; k++) if ( ! stricmp(ti[k]->name, fi[i]->dot)) {
{
if (!stricmp(ti[k]->name, fi[i]->dot))
{
fi[i]->ti = ti[k]; fi[i]->ti = ti[k];
break; break;
} }
else if (!stricmp(ti[k]->alias, fi[i]->dot)) else if ( ! stricmp(ti[k]->alias, fi[i]->dot)) {
{
fi[i]->ti = ti[k]; fi[i]->ti = ti[k];
break; break;
} }
@ -614,15 +544,15 @@ parse_statement(StatementClass *stmt)
mylog("--------------------------------------------\n"); mylog("--------------------------------------------\n");
mylog("nfld=%d, ntab=%d\n", stmt->nfld, stmt->ntab); mylog("nfld=%d, ntab=%d\n", stmt->nfld, stmt->ntab);
for (i = 0; i < stmt->nfld; i++) for (i=0; i < stmt->nfld; i++) {
{
mylog("Field %d: expr=%d, func=%d, quote=%d, dquote=%d, numeric=%d, name='%s', alias='%s', dot='%s'\n", i, fi[i]->expr, fi[i]->func, fi[i]->quote, fi[i]->dquote, fi[i]->numeric, fi[i]->name, fi[i]->alias, fi[i]->dot); mylog("Field %d: expr=%d, func=%d, quote=%d, dquote=%d, numeric=%d, name='%s', alias='%s', dot='%s'\n", i, fi[i]->expr, fi[i]->func, fi[i]->quote, fi[i]->dquote, fi[i]->numeric, fi[i]->name, fi[i]->alias, fi[i]->dot);
if (fi[i]->ti) if (fi[i]->ti)
mylog(" ----> table_name='%s', table_alias='%s'\n", fi[i]->ti->name, fi[i]->ti->alias); mylog(" ----> table_name='%s', table_alias='%s'\n", fi[i]->ti->name, fi[i]->ti->alias);
} }
for (i = 0; i < stmt->ntab; i++) for (i=0; i < stmt->ntab; i++) {
mylog("Table %d: name='%s', alias='%s'\n", i, ti[i]->name, ti[i]->alias); mylog("Table %d: name='%s', alias='%s'\n", i, ti[i]->name, ti[i]->alias);
}
/******************************************************/ /******************************************************/
@ -631,28 +561,24 @@ parse_statement(StatementClass *stmt)
/* Call SQLColumns for each table and store the result */ /* Call SQLColumns for each table and store the result */
for (i = 0; i < stmt->ntab; i++) for (i = 0; i < stmt->ntab; i++) {
{
/* See if already got it */ /* See if already got it */
char found = FALSE; char found = FALSE;
for (k = 0; k < conn->ntables; k++) {
for (k = 0; k < conn->ntables; k++) if ( ! stricmp(conn->col_info[k]->name, ti[i]->name)) {
{
if (!stricmp(conn->col_info[k]->name, ti[i]->name))
{
mylog("FOUND col_info table='%s'\n", ti[i]->name); mylog("FOUND col_info table='%s'\n", ti[i]->name);
found = TRUE; found = TRUE;
break; break;
} }
} }
if (!found) if ( ! found) {
{
mylog("PARSE: Getting SQLColumns for table[%d]='%s'\n", i, ti[i]->name); mylog("PARSE: Getting SQLColumns for table[%d]='%s'\n", i, ti[i]->name);
result = SQLAllocStmt( stmt->hdbc, &hcol_stmt); result = SQLAllocStmt( stmt->hdbc, &hcol_stmt);
if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
{
stmt->errormsg = "SQLAllocStmt failed in parse_statement for columns."; stmt->errormsg = "SQLAllocStmt failed in parse_statement for columns.";
stmt->errornumber = STMT_NO_MEMORY_ERROR; stmt->errornumber = STMT_NO_MEMORY_ERROR;
stmt->parse_status = STMT_PARSE_FATAL; stmt->parse_status = STMT_PARSE_FATAL;
@ -666,16 +592,14 @@ parse_statement(StatementClass *stmt)
ti[i]->name, (SWORD) strlen(ti[i]->name), "", 0); ti[i]->name, (SWORD) strlen(ti[i]->name), "", 0);
mylog(" Past SQLColumns\n"); mylog(" Past SQLColumns\n");
if (result == SQL_SUCCESS) if (result == SQL_SUCCESS) {
{
mylog(" Success\n"); mylog(" Success\n");
if (!(conn->ntables % COL_INCR)) if ( ! (conn->ntables % COL_INCR)) {
{
mylog("PARSE: Allocing col_info at ntables=%d\n", conn->ntables); mylog("PARSE: Allocing col_info at ntables=%d\n", conn->ntables);
conn->col_info = (COL_INFO **) realloc(conn->col_info, (conn->ntables + COL_INCR) * sizeof(COL_INFO *)); conn->col_info = (COL_INFO **) realloc(conn->col_info, (conn->ntables + COL_INCR) * sizeof(COL_INFO *));
if (!conn->col_info) if ( ! conn->col_info) {
{
stmt->parse_status = STMT_PARSE_FATAL; stmt->parse_status = STMT_PARSE_FATAL;
return FALSE; return FALSE;
} }
@ -683,22 +607,17 @@ parse_statement(StatementClass *stmt)
mylog("PARSE: malloc at conn->col_info[%d]\n", conn->ntables); mylog("PARSE: malloc at conn->col_info[%d]\n", conn->ntables);
conn->col_info[conn->ntables] = (COL_INFO *) malloc(sizeof(COL_INFO)); conn->col_info[conn->ntables] = (COL_INFO *) malloc(sizeof(COL_INFO));
if (!conn->col_info[conn->ntables]) if ( ! conn->col_info[conn->ntables]) {
{
stmt->parse_status = STMT_PARSE_FATAL; stmt->parse_status = STMT_PARSE_FATAL;
return FALSE; return FALSE;
} }
/* /* Store the table name and the SQLColumns result structure */
* Store the table name and the SQLColumns result
* structure
*/
strcpy(conn->col_info[conn->ntables]->name, ti[i]->name); strcpy(conn->col_info[conn->ntables]->name, ti[i]->name);
conn->col_info[conn->ntables]->result = col_stmt->result; conn->col_info[conn->ntables]->result = col_stmt->result;
/* /* The connection will now free the result structures, so make
* The connection will now free the result structures, so sure that the statement doesn't free it
* make sure that the statement doesn't free it
*/ */
col_stmt->result = NULL; col_stmt->result = NULL;
@ -707,8 +626,7 @@ parse_statement(StatementClass *stmt)
SQLFreeStmt(hcol_stmt, SQL_DROP); SQLFreeStmt(hcol_stmt, SQL_DROP);
mylog("Created col_info table='%s', ntables=%d\n", ti[i]->name, conn->ntables); mylog("Created col_info table='%s', ntables=%d\n", ti[i]->name, conn->ntables);
} }
else else {
{
SQLFreeStmt(hcol_stmt, SQL_DROP); SQLFreeStmt(hcol_stmt, SQL_DROP);
break; break;
} }
@ -728,39 +646,34 @@ parse_statement(StatementClass *stmt)
for (i = 0; i < stmt->nfld;) for (i = 0; i < stmt->nfld;) {
{
/* Dont worry about functions or quotes */ /* Dont worry about functions or quotes */
if (fi[i]->func || fi[i]->quote || fi[i]->numeric) if (fi[i]->func || fi[i]->quote || fi[i]->numeric) {
{
i++; i++;
continue; continue;
} }
/* Stars get expanded to all fields in the table */ /* Stars get expanded to all fields in the table */
else if (fi[i]->name[0] == '*') else if (fi[i]->name[0] == '*') {
{
char do_all_tables; char do_all_tables;
int total_cols, int total_cols, old_size, need, cols;
old_size,
need,
cols;
mylog("expanding field %d\n", i); mylog("expanding field %d\n", i);
total_cols = 0; total_cols = 0;
if (fi[i]->ti) /* The star represents only the qualified if (fi[i]->ti) /* The star represents only the qualified table */
* table */
total_cols = QR_get_num_tuples(fi[i]->ti->col_info->result); total_cols = QR_get_num_tuples(fi[i]->ti->col_info->result);
else else { /* The star represents all tables */
{ /* The star represents all tables */
/* Calculate the total number of columns after expansion */ /* Calculate the total number of columns after expansion */
for (k = 0; k < stmt->ntab; k++) for (k = 0; k < stmt->ntab; k++) {
total_cols += QR_get_num_tuples(ti[k]->col_info->result); total_cols += QR_get_num_tuples(ti[k]->col_info->result);
} }
}
total_cols--; /* makes up for the star */ total_cols--; /* makes up for the star */
/* Allocate some more field pointers if necessary */ /* Allocate some more field pointers if necessary */
@ -770,27 +683,19 @@ parse_statement(StatementClass *stmt)
mylog("k=%d, total_cols=%d, old_size=%d, need=%d\n", k,total_cols,old_size,need); mylog("k=%d, total_cols=%d, old_size=%d, need=%d\n", k,total_cols,old_size,need);
if (need > 0) if (need > 0) {
{
int new_size = need / FLD_INCR * FLD_INCR + FLD_INCR; int new_size = need / FLD_INCR * FLD_INCR + FLD_INCR;
mylog("need more cols: new_size = %d\n", new_size); mylog("need more cols: new_size = %d\n", new_size);
fi = (FIELD_INFO **) realloc(fi, (old_size + new_size) * sizeof(FIELD_INFO *)); fi = (FIELD_INFO **) realloc(fi, (old_size + new_size) * sizeof(FIELD_INFO *));
if (!fi) if ( ! fi) {
{
stmt->parse_status = STMT_PARSE_FATAL; stmt->parse_status = STMT_PARSE_FATAL;
return FALSE; return FALSE;
} }
} }
/*------------------------------------------------------------- */ /*------------------------------------------------------------- */
/* copy any other fields (if there are any) up past the expansion */
/* for (j = stmt->nfld - 1; j > i; j--) {
* copy any other fields (if there are any) up past the
* expansion
*/
for (j = stmt->nfld - 1; j > i; j--)
{
mylog("copying field %d to %d\n", j, total_cols + j); mylog("copying field %d to %d\n", j, total_cols + j);
fi[total_cols + j] = fi[j]; fi[total_cols + j] = fi[j];
} }
@ -808,22 +713,19 @@ parse_statement(StatementClass *stmt)
do_all_tables = (fi[i]->ti ? FALSE : TRUE); do_all_tables = (fi[i]->ti ? FALSE : TRUE);
for (k = 0; k < (do_all_tables ? stmt->ntab : 1); k++) for (k = 0; k < (do_all_tables ? stmt->ntab : 1); k++) {
{
TABLE_INFO *the_ti = do_all_tables ? ti[k] : fi[i]->ti; TABLE_INFO *the_ti = do_all_tables ? ti[k] : fi[i]->ti;
cols = QR_get_num_tuples(the_ti->col_info->result); cols = QR_get_num_tuples(the_ti->col_info->result);
for (n = 0; n < cols; n++) for (n = 0; n < cols; n++) {
{
mylog("creating field info: n=%d\n", n); mylog("creating field info: n=%d\n", n);
/* skip malloc (already did it for the Star) */ /* skip malloc (already did it for the Star) */
if (k > 0 || n > 0) if (k > 0 || n > 0) {
{
mylog("allocating field info at %d\n", n + i); mylog("allocating field info at %d\n", n + i);
fi[n + i] = (FIELD_INFO *) malloc( sizeof(FIELD_INFO)); fi[n + i] = (FIELD_INFO *) malloc( sizeof(FIELD_INFO));
if (fi[n + i] == NULL) if (fi[n + i] == NULL) {
{
stmt->parse_status = STMT_PARSE_FATAL; stmt->parse_status = STMT_PARSE_FATAL;
return FALSE; return FALSE;
} }
@ -846,13 +748,11 @@ parse_statement(StatementClass *stmt)
/*------------------------------------------------------------- */ /*------------------------------------------------------------- */
} }
/* /* We either know which table the field was in because it was qualified
* We either know which table the field was in because it was with a table name or alias -OR- there was only 1 table.
* qualified with a table name or alias -OR- there was only 1
* table.
*/ */
else if (fi[i]->ti) else if (fi[i]->ti) {
{
if ( ! searchColInfo(fi[i]->ti->col_info, fi[i])) if ( ! searchColInfo(fi[i]->ti->col_info, fi[i]))
parse = FALSE; parse = FALSE;
@ -860,13 +760,10 @@ parse_statement(StatementClass *stmt)
} }
/* Don't know the table -- search all tables in "from" list */ /* Don't know the table -- search all tables in "from" list */
else else {
{
parse = FALSE; parse = FALSE;
for (k = 0; k < stmt->ntab; k++) for (k = 0; k < stmt->ntab; k++) {
{ if ( searchColInfo(ti[k]->col_info, fi[i])) {
if (searchColInfo(ti[k]->col_info, fi[i]))
{
fi[i]->ti = ti[k]; /* now know the table */ fi[i]->ti = ti[k]; /* now know the table */
parse = TRUE; parse = TRUE;
break; break;
@ -886,3 +783,4 @@ parse_statement(StatementClass *stmt)
mylog("done parse_statement: parse=%d, parse_status=%d\n", parse, stmt->parse_status); mylog("done parse_statement: parse=%d, parse_status=%d\n", parse, stmt->parse_status);
return parse; return parse;
} }

@ -1,3 +1,4 @@
/* Module: pgtypes.c /* Module: pgtypes.c
* *
* Description: This module contains routines for getting information * Description: This module contains routines for getting information
@ -102,13 +103,12 @@ Int2 sqlTypes[] = {
0 0
}; };
Int4 Int4 sqltype_to_pgtype(SWORD fSqlType)
sqltype_to_pgtype(SWORD fSqlType)
{ {
Int4 pgType; Int4 pgType;
switch (fSqlType) switch(fSqlType) {
{
case SQL_BINARY: case SQL_BINARY:
pgType = PG_TYPE_BYTEA; pgType = PG_TYPE_BYTEA;
break; break;
@ -193,189 +193,122 @@ sqltype_to_pgtype(SWORD fSqlType)
know. This allows for supporting know. This allows for supporting
types that are unknown. All other pg routines in here return a suitable default. types that are unknown. All other pg routines in here return a suitable default.
*/ */
Int2 Int2 pgtype_to_sqltype(StatementClass *stmt, Int4 type)
pgtype_to_sqltype(StatementClass *stmt, Int4 type)
{
switch (type)
{ {
switch(type) {
case PG_TYPE_CHAR: case PG_TYPE_CHAR:
case PG_TYPE_CHAR2: case PG_TYPE_CHAR2:
case PG_TYPE_CHAR4: case PG_TYPE_CHAR4:
case PG_TYPE_CHAR8: case PG_TYPE_CHAR8:
case PG_TYPE_NAME: case PG_TYPE_NAME: return SQL_CHAR;
return SQL_CHAR;
case PG_TYPE_BPCHAR: case PG_TYPE_BPCHAR: return SQL_CHAR;
return SQL_CHAR;
case PG_TYPE_VARCHAR: case PG_TYPE_VARCHAR: return SQL_VARCHAR;
return SQL_VARCHAR;
case PG_TYPE_TEXT: case PG_TYPE_TEXT: return globals.text_as_longvarchar ? SQL_LONGVARCHAR : SQL_VARCHAR;
return globals.text_as_longvarchar ? SQL_LONGVARCHAR : SQL_VARCHAR;
case PG_TYPE_BYTEA: case PG_TYPE_BYTEA: return SQL_VARBINARY;
return SQL_VARBINARY; case PG_TYPE_LO: return SQL_LONGVARBINARY;
case PG_TYPE_LO:
return SQL_LONGVARBINARY;
case PG_TYPE_INT2: case PG_TYPE_INT2: return SQL_SMALLINT;
return SQL_SMALLINT;
case PG_TYPE_OID: case PG_TYPE_OID:
case PG_TYPE_XID: case PG_TYPE_XID:
case PG_TYPE_INT4: case PG_TYPE_INT4: return SQL_INTEGER;
return SQL_INTEGER;
/* Change this to SQL_BIGINT for ODBC v3 bjm 2001-01-23 */ /* Change this to SQL_BIGINT for ODBC v3 bjm 2001-01-23 */
case PG_TYPE_INT8: case PG_TYPE_INT8: return SQL_CHAR;
return SQL_CHAR;
case PG_TYPE_NUMERIC: case PG_TYPE_NUMERIC: return SQL_NUMERIC;
return SQL_NUMERIC;
case PG_TYPE_FLOAT4: case PG_TYPE_FLOAT4: return SQL_REAL;
return SQL_REAL; case PG_TYPE_FLOAT8: return SQL_FLOAT;
case PG_TYPE_FLOAT8: case PG_TYPE_DATE: return SQL_DATE;
return SQL_FLOAT; case PG_TYPE_TIME: return SQL_TIME;
case PG_TYPE_DATE:
return SQL_DATE;
case PG_TYPE_TIME:
return SQL_TIME;
case PG_TYPE_ABSTIME: case PG_TYPE_ABSTIME:
case PG_TYPE_DATETIME: case PG_TYPE_DATETIME:
case PG_TYPE_TIMESTAMP: case PG_TYPE_TIMESTAMP: return SQL_TIMESTAMP;
return SQL_TIMESTAMP; case PG_TYPE_MONEY: return SQL_FLOAT;
case PG_TYPE_MONEY: case PG_TYPE_BOOL: return globals.bools_as_char ? SQL_CHAR : SQL_BIT;
return SQL_FLOAT;
case PG_TYPE_BOOL:
return globals.bools_as_char ? SQL_CHAR : SQL_BIT;
default: default:
/* /* first, check to see if 'type' is in list. If not, look up with query.
* first, check to see if 'type' is in list. If not, look up Add oid, name to list. If it's already in list, just return.
* with query. Add oid, name to list. If it's already in
* list, just return.
*/ */
if (type == stmt->hdbc->lobj_type) /* hack until permanent if (type == stmt->hdbc->lobj_type) /* hack until permanent type is available */
* type is available */
return SQL_LONGVARBINARY; return SQL_LONGVARBINARY;
return globals.unknowns_as_longvarchar ? SQL_LONGVARCHAR : SQL_VARCHAR; return globals.unknowns_as_longvarchar ? SQL_LONGVARCHAR : SQL_VARCHAR;
} }
} }
Int2 Int2 pgtype_to_ctype(StatementClass *stmt, Int4 type)
pgtype_to_ctype(StatementClass *stmt, Int4 type)
{ {
switch (type) switch(type) {
{ case PG_TYPE_INT8: return SQL_C_CHAR;
case PG_TYPE_INT8: case PG_TYPE_NUMERIC: return SQL_C_CHAR;
return SQL_C_CHAR; case PG_TYPE_INT2: return SQL_C_SSHORT;
case PG_TYPE_NUMERIC:
return SQL_C_CHAR;
case PG_TYPE_INT2:
return SQL_C_SSHORT;
case PG_TYPE_OID: case PG_TYPE_OID:
case PG_TYPE_XID: case PG_TYPE_XID:
case PG_TYPE_INT4: case PG_TYPE_INT4: return SQL_C_SLONG;
return SQL_C_SLONG; case PG_TYPE_FLOAT4: return SQL_C_FLOAT;
case PG_TYPE_FLOAT4: case PG_TYPE_FLOAT8: return SQL_C_DOUBLE;
return SQL_C_FLOAT; case PG_TYPE_DATE: return SQL_C_DATE;
case PG_TYPE_FLOAT8: case PG_TYPE_TIME: return SQL_C_TIME;
return SQL_C_DOUBLE;
case PG_TYPE_DATE:
return SQL_C_DATE;
case PG_TYPE_TIME:
return SQL_C_TIME;
case PG_TYPE_ABSTIME: case PG_TYPE_ABSTIME:
case PG_TYPE_DATETIME: case PG_TYPE_DATETIME:
case PG_TYPE_TIMESTAMP: case PG_TYPE_TIMESTAMP: return SQL_C_TIMESTAMP;
return SQL_C_TIMESTAMP; case PG_TYPE_MONEY: return SQL_C_FLOAT;
case PG_TYPE_MONEY: case PG_TYPE_BOOL: return globals.bools_as_char ? SQL_C_CHAR : SQL_C_BIT;
return SQL_C_FLOAT;
case PG_TYPE_BOOL:
return globals.bools_as_char ? SQL_C_CHAR : SQL_C_BIT;
case PG_TYPE_BYTEA: case PG_TYPE_BYTEA: return SQL_C_BINARY;
return SQL_C_BINARY; case PG_TYPE_LO: return SQL_C_BINARY;
case PG_TYPE_LO:
return SQL_C_BINARY;
default: default:
if (type == stmt->hdbc->lobj_type) /* hack until permanent if (type == stmt->hdbc->lobj_type) /* hack until permanent type is available */
* type is available */
return SQL_C_BINARY; return SQL_C_BINARY;
return SQL_C_CHAR; return SQL_C_CHAR;
} }
} }
char * char *pgtype_to_name(StatementClass *stmt, Int4 type)
pgtype_to_name(StatementClass *stmt, Int4 type)
{
switch (type)
{ {
switch(type) {
case PG_TYPE_CHAR: return "char"; case PG_TYPE_CHAR: return "char";
case PG_TYPE_CHAR2: case PG_TYPE_CHAR2: return "char2";
return "char2"; case PG_TYPE_CHAR4: return "char4";
case PG_TYPE_CHAR4: case PG_TYPE_CHAR8: return "char8";
return "char4"; case PG_TYPE_INT8: return "int8";
case PG_TYPE_CHAR8: case PG_TYPE_NUMERIC: return "numeric";
return "char8"; case PG_TYPE_VARCHAR: return "varchar";
case PG_TYPE_INT8: case PG_TYPE_BPCHAR: return "char";
return "int8"; case PG_TYPE_TEXT: return "text";
case PG_TYPE_NUMERIC: case PG_TYPE_NAME: return "name";
return "numeric"; case PG_TYPE_INT2: return "int2";
case PG_TYPE_VARCHAR: case PG_TYPE_OID: return "oid";
return "varchar"; case PG_TYPE_INT4: return "int4";
case PG_TYPE_BPCHAR: case PG_TYPE_FLOAT4: return "float4";
return "char"; case PG_TYPE_FLOAT8: return "float8";
case PG_TYPE_TEXT: case PG_TYPE_DATE: return "date";
return "text"; case PG_TYPE_TIME: return "time";
case PG_TYPE_NAME: case PG_TYPE_ABSTIME: return "abstime";
return "name"; case PG_TYPE_DATETIME: return "datetime";
case PG_TYPE_INT2: case PG_TYPE_TIMESTAMP: return "timestamp";
return "int2"; case PG_TYPE_MONEY: return "money";
case PG_TYPE_OID: case PG_TYPE_BOOL: return "bool";
return "oid"; case PG_TYPE_BYTEA: return "bytea";
case PG_TYPE_INT4:
return "int4";
case PG_TYPE_FLOAT4:
return "float4";
case PG_TYPE_FLOAT8:
return "float8";
case PG_TYPE_DATE:
return "date";
case PG_TYPE_TIME:
return "time";
case PG_TYPE_ABSTIME:
return "abstime";
case PG_TYPE_DATETIME:
return "datetime";
case PG_TYPE_TIMESTAMP:
return "timestamp";
case PG_TYPE_MONEY:
return "money";
case PG_TYPE_BOOL:
return "bool";
case PG_TYPE_BYTEA:
return "bytea";
case PG_TYPE_LO: case PG_TYPE_LO: return PG_TYPE_LO_NAME;
return PG_TYPE_LO_NAME;
default: default:
if (type == stmt->hdbc->lobj_type) /* hack until permanent if (type == stmt->hdbc->lobj_type) /* hack until permanent type is available */
* type is available */
return PG_TYPE_LO_NAME; return PG_TYPE_LO_NAME;
/* /* "unknown" can actually be used in alter table because it is a real PG type! */
* "unknown" can actually be used in alter table because it is
* a real PG type!
*/
return "unknown"; return "unknown";
} }
} }
@ -394,12 +327,8 @@ getNumericScale(StatementClass *stmt, Int4 type, int col)
result = SC_get_Result(stmt); result = SC_get_Result(stmt);
/* /* Manual Result Sets -- use assigned column width (i.e., from set_tuplefield_string) */
* Manual Result Sets -- use assigned column width (i.e., from if (stmt->manual_result) {
* set_tuplefield_string)
*/
if (stmt->manual_result)
{
flds = result->fields; flds = result->fields;
if (flds) if (flds)
return flds->adtsize[col]; return flds->adtsize[col];
@ -430,12 +359,8 @@ getNumericPrecision(StatementClass *stmt, Int4 type, int col)
result = SC_get_Result(stmt); result = SC_get_Result(stmt);
/* /* Manual Result Sets -- use assigned column width (i.e., from set_tuplefield_string) */
* Manual Result Sets -- use assigned column width (i.e., from if (stmt->manual_result) {
* set_tuplefield_string)
*/
if (stmt->manual_result)
{
flds = result->fields; flds = result->fields;
if (flds) if (flds)
return flds->adtsize[col]; return flds->adtsize[col];
@ -455,16 +380,14 @@ getNumericPrecision(StatementClass *stmt, Int4 type, int col)
Int4 Int4
getCharPrecision(StatementClass *stmt, Int4 type, int col, int handle_unknown_size_as) getCharPrecision(StatementClass *stmt, Int4 type, int col, int handle_unknown_size_as)
{ {
int p = -1, int p = -1, maxsize;
maxsize;
QResultClass *result; QResultClass *result;
ColumnInfoClass *flds; ColumnInfoClass *flds;
mylog("getCharPrecision: type=%d, col=%d, unknown = %d\n", type,col,handle_unknown_size_as); mylog("getCharPrecision: type=%d, col=%d, unknown = %d\n", type,col,handle_unknown_size_as);
/* Assign Maximum size based on parameters */ /* Assign Maximum size based on parameters */
switch (type) switch(type) {
{
case PG_TYPE_TEXT: case PG_TYPE_TEXT:
if (globals.text_as_longvarchar) if (globals.text_as_longvarchar)
maxsize = globals.max_longvarchar_size; maxsize = globals.max_longvarchar_size;
@ -485,21 +408,16 @@ getCharPrecision(StatementClass *stmt, Int4 type, int col, int handle_unknown_si
break; break;
} }
/* /* Static Precision (i.e., the Maximum Precision of the datatype)
* Static Precision (i.e., the Maximum Precision of the datatype) This This has nothing to do with a result set.
* has nothing to do with a result set.
*/ */
if (col < 0) if (col < 0)
return maxsize; return maxsize;
result = SC_get_Result(stmt); result = SC_get_Result(stmt);
/* /* Manual Result Sets -- use assigned column width (i.e., from set_tuplefield_string) */
* Manual Result Sets -- use assigned column width (i.e., from if (stmt->manual_result) {
* set_tuplefield_string)
*/
if (stmt->manual_result)
{
flds = result->fields; flds = result->fields;
if (flds) if (flds)
return flds->adtsize[col]; return flds->adtsize[col];
@ -511,8 +429,7 @@ getCharPrecision(StatementClass *stmt, Int4 type, int col, int handle_unknown_si
if (QR_get_atttypmod(result, col) > -1) if (QR_get_atttypmod(result, col) > -1)
return QR_get_atttypmod(result, col); return QR_get_atttypmod(result, col);
if (type == PG_TYPE_BPCHAR || handle_unknown_size_as == UNKNOWNS_AS_LONGEST) if (type == PG_TYPE_BPCHAR || handle_unknown_size_as == UNKNOWNS_AS_LONGEST) {
{
p = QR_get_display_size(result, col); p = QR_get_display_size(result, col);
mylog("getCharPrecision: LONGEST: p = %d\n", p); mylog("getCharPrecision: LONGEST: p = %d\n", p);
} }
@ -529,64 +446,47 @@ getCharPrecision(StatementClass *stmt, Int4 type, int col, int handle_unknown_si
If col >= 0, then will attempt to get the info from the result set. If col >= 0, then will attempt to get the info from the result set.
This is used for functions SQLDescribeCol and SQLColAttributes. This is used for functions SQLDescribeCol and SQLColAttributes.
*/ */
Int4 Int4 pgtype_precision(StatementClass *stmt, Int4 type, int col, int handle_unknown_size_as)
pgtype_precision(StatementClass *stmt, Int4 type, int col, int handle_unknown_size_as)
{ {
switch (type)
{
case PG_TYPE_CHAR:
return 1;
case PG_TYPE_CHAR2:
return 2;
case PG_TYPE_CHAR4:
return 4;
case PG_TYPE_CHAR8:
return 8;
case PG_TYPE_NAME: switch(type) {
return NAME_FIELD_SIZE;
case PG_TYPE_INT2: case PG_TYPE_CHAR: return 1;
return 5; case PG_TYPE_CHAR2: return 2;
case PG_TYPE_CHAR4: return 4;
case PG_TYPE_CHAR8: return 8;
case PG_TYPE_NAME: return NAME_FIELD_SIZE;
case PG_TYPE_INT2: return 5;
case PG_TYPE_OID: case PG_TYPE_OID:
case PG_TYPE_XID: case PG_TYPE_XID:
case PG_TYPE_INT4: case PG_TYPE_INT4: return 10;
return 10;
case PG_TYPE_INT8: case PG_TYPE_INT8: return 19; /* signed */
return 19; /* signed */
case PG_TYPE_NUMERIC: case PG_TYPE_NUMERIC: return getNumericPrecision(stmt,type,col);
return getNumericPrecision(stmt, type, col);
case PG_TYPE_FLOAT4: case PG_TYPE_FLOAT4:
case PG_TYPE_MONEY: case PG_TYPE_MONEY: return 7;
return 7;
case PG_TYPE_FLOAT8: case PG_TYPE_FLOAT8: return 15;
return 15;
case PG_TYPE_DATE: case PG_TYPE_DATE: return 10;
return 10; case PG_TYPE_TIME: return 8;
case PG_TYPE_TIME:
return 8;
case PG_TYPE_ABSTIME: case PG_TYPE_ABSTIME:
case PG_TYPE_DATETIME: case PG_TYPE_DATETIME:
case PG_TYPE_TIMESTAMP: case PG_TYPE_TIMESTAMP: return 19;
return 19;
case PG_TYPE_BOOL: case PG_TYPE_BOOL: return 1;
return 1;
case PG_TYPE_LO: case PG_TYPE_LO: return SQL_NO_TOTAL;
return SQL_NO_TOTAL;
default: default:
if (type == stmt->hdbc->lobj_type) /* hack until permanent if (type == stmt->hdbc->lobj_type) /* hack until permanent type is available */
* type is available */
return SQL_NO_TOTAL; return SQL_NO_TOTAL;
/* Handle Character types and unknown types */ /* Handle Character types and unknown types */
@ -594,35 +494,26 @@ pgtype_precision(StatementClass *stmt, Int4 type, int col, int handle_unknown_si
} }
} }
Int4 Int4 pgtype_display_size(StatementClass *stmt, Int4 type, int col, int handle_unknown_size_as)
pgtype_display_size(StatementClass *stmt, Int4 type, int col, int handle_unknown_size_as)
{ {
switch (type)
{ switch(type) {
case PG_TYPE_INT2: case PG_TYPE_INT2: return 6;
return 6;
case PG_TYPE_OID: case PG_TYPE_OID:
case PG_TYPE_XID: case PG_TYPE_XID: return 10;
return 10;
case PG_TYPE_INT4: case PG_TYPE_INT4: return 11;
return 11;
case PG_TYPE_INT8: case PG_TYPE_INT8: return 20; /* signed: 19 digits + sign */
return 20; /* signed: 19 digits + sign */
case PG_TYPE_NUMERIC: case PG_TYPE_NUMERIC: return getNumericPrecision(stmt,type,col) + 2;
return getNumericPrecision(stmt, type, col) + 2;
case PG_TYPE_MONEY: case PG_TYPE_MONEY: return 15; /* ($9,999,999.99) */
return 15; /* ($9,999,999.99) */
case PG_TYPE_FLOAT4: case PG_TYPE_FLOAT4: return 13;
return 13;
case PG_TYPE_FLOAT8: case PG_TYPE_FLOAT8: return 22;
return 22;
/* Character types use regular precision */ /* Character types use regular precision */
default: default:
@ -633,40 +524,32 @@ pgtype_display_size(StatementClass *stmt, Int4 type, int col, int handle_unknown
/* For PG_TYPE_VARCHAR, PG_TYPE_BPCHAR, SQLColumns will /* For PG_TYPE_VARCHAR, PG_TYPE_BPCHAR, SQLColumns will
override this length with the atttypmod length from pg_attribute override this length with the atttypmod length from pg_attribute
*/ */
Int4 Int4 pgtype_length(StatementClass *stmt, Int4 type, int col, int handle_unknown_size_as)
pgtype_length(StatementClass *stmt, Int4 type, int col, int handle_unknown_size_as)
{ {
switch (type)
{ switch(type) {
case PG_TYPE_INT2:
return 2; case PG_TYPE_INT2: return 2;
case PG_TYPE_OID: case PG_TYPE_OID:
case PG_TYPE_XID: case PG_TYPE_XID:
case PG_TYPE_INT4: case PG_TYPE_INT4: return 4;
return 4;
case PG_TYPE_INT8: case PG_TYPE_INT8: return 20; /* signed: 19 digits + sign */
return 20; /* signed: 19 digits + sign */
case PG_TYPE_NUMERIC: case PG_TYPE_NUMERIC: return getNumericPrecision(stmt,type,col) + 2;
return getNumericPrecision(stmt, type, col) + 2;
case PG_TYPE_FLOAT4: case PG_TYPE_FLOAT4:
case PG_TYPE_MONEY: case PG_TYPE_MONEY: return 4;
return 4;
case PG_TYPE_FLOAT8: case PG_TYPE_FLOAT8: return 8;
return 8;
case PG_TYPE_DATE: case PG_TYPE_DATE:
case PG_TYPE_TIME: case PG_TYPE_TIME: return 6;
return 6;
case PG_TYPE_ABSTIME: case PG_TYPE_ABSTIME:
case PG_TYPE_DATETIME: case PG_TYPE_DATETIME:
case PG_TYPE_TIMESTAMP: case PG_TYPE_TIMESTAMP: return 16;
return 16;
/* Character types (and NUMERIC) use the default precision */ /* Character types (and NUMERIC) use the default precision */
@ -675,11 +558,10 @@ pgtype_length(StatementClass *stmt, Int4 type, int col, int handle_unknown_size_
} }
} }
Int2 Int2 pgtype_scale(StatementClass *stmt, Int4 type, int col)
pgtype_scale(StatementClass *stmt, Int4 type, int col)
{
switch (type)
{ {
switch(type) {
case PG_TYPE_INT2: case PG_TYPE_INT2:
case PG_TYPE_OID: case PG_TYPE_OID:
case PG_TYPE_XID: case PG_TYPE_XID:
@ -690,29 +572,21 @@ pgtype_scale(StatementClass *stmt, Int4 type, int col)
case PG_TYPE_MONEY: case PG_TYPE_MONEY:
case PG_TYPE_BOOL: case PG_TYPE_BOOL:
/* /* Number of digits to the right of the decimal point in "yyyy-mm=dd hh:mm:ss[.f...]" */
* Number of digits to the right of the decimal point in
* "yyyy-mm=dd hh:mm:ss[.f...]"
*/
case PG_TYPE_ABSTIME: case PG_TYPE_ABSTIME:
case PG_TYPE_DATETIME: case PG_TYPE_DATETIME:
case PG_TYPE_TIMESTAMP: case PG_TYPE_TIMESTAMP: return 0;
return 0;
case PG_TYPE_NUMERIC: case PG_TYPE_NUMERIC: return getNumericScale(stmt,type,col);
return getNumericScale(stmt, type, col);
default: default: return -1;
return -1;
} }
} }
Int2 Int2 pgtype_radix(StatementClass *stmt, Int4 type)
pgtype_radix(StatementClass *stmt, Int4 type)
{
switch (type)
{ {
switch(type) {
case PG_TYPE_INT2: case PG_TYPE_INT2:
case PG_TYPE_OID: case PG_TYPE_OID:
case PG_TYPE_INT4: case PG_TYPE_INT4:
@ -720,25 +594,21 @@ pgtype_radix(StatementClass *stmt, Int4 type)
case PG_TYPE_NUMERIC: case PG_TYPE_NUMERIC:
case PG_TYPE_FLOAT4: case PG_TYPE_FLOAT4:
case PG_TYPE_MONEY: case PG_TYPE_MONEY:
case PG_TYPE_FLOAT8: case PG_TYPE_FLOAT8: return 10;
return 10;
default: default: return -1;
return -1;
} }
} }
Int2 Int2 pgtype_nullable(StatementClass *stmt, Int4 type)
pgtype_nullable(StatementClass *stmt, Int4 type)
{ {
return SQL_NULLABLE; /* everything should be nullable */ return SQL_NULLABLE; /* everything should be nullable */
} }
Int2 Int2 pgtype_auto_increment(StatementClass *stmt, Int4 type)
pgtype_auto_increment(StatementClass *stmt, Int4 type)
{
switch (type)
{ {
switch(type) {
case PG_TYPE_INT2: case PG_TYPE_INT2:
case PG_TYPE_OID: case PG_TYPE_OID:
case PG_TYPE_XID: case PG_TYPE_XID:
@ -754,19 +624,15 @@ pgtype_auto_increment(StatementClass *stmt, Int4 type)
case PG_TYPE_TIME: case PG_TYPE_TIME:
case PG_TYPE_ABSTIME: case PG_TYPE_ABSTIME:
case PG_TYPE_DATETIME: case PG_TYPE_DATETIME:
case PG_TYPE_TIMESTAMP: case PG_TYPE_TIMESTAMP: return FALSE;
return FALSE;
default: default: return -1;
return -1;
} }
} }
Int2 Int2 pgtype_case_sensitive(StatementClass *stmt, Int4 type)
pgtype_case_sensitive(StatementClass *stmt, Int4 type)
{
switch (type)
{ {
switch(type) {
case PG_TYPE_CHAR: case PG_TYPE_CHAR:
case PG_TYPE_CHAR2: case PG_TYPE_CHAR2:
@ -776,31 +642,23 @@ pgtype_case_sensitive(StatementClass *stmt, Int4 type)
case PG_TYPE_VARCHAR: case PG_TYPE_VARCHAR:
case PG_TYPE_BPCHAR: case PG_TYPE_BPCHAR:
case PG_TYPE_TEXT: case PG_TYPE_TEXT:
case PG_TYPE_NAME: case PG_TYPE_NAME: return TRUE;
return TRUE;
default: default: return FALSE;
return FALSE;
} }
} }
Int2 Int2 pgtype_money(StatementClass *stmt, Int4 type)
pgtype_money(StatementClass *stmt, Int4 type)
{ {
switch (type) switch(type) {
{ case PG_TYPE_MONEY: return TRUE;
case PG_TYPE_MONEY: default: return FALSE;
return TRUE;
default:
return FALSE;
} }
} }
Int2 Int2 pgtype_searchable(StatementClass *stmt, Int4 type)
pgtype_searchable(StatementClass *stmt, Int4 type)
{
switch (type)
{ {
switch(type) {
case PG_TYPE_CHAR: case PG_TYPE_CHAR:
case PG_TYPE_CHAR2: case PG_TYPE_CHAR2:
case PG_TYPE_CHAR4: case PG_TYPE_CHAR4:
@ -809,22 +667,17 @@ pgtype_searchable(StatementClass *stmt, Int4 type)
case PG_TYPE_VARCHAR: case PG_TYPE_VARCHAR:
case PG_TYPE_BPCHAR: case PG_TYPE_BPCHAR:
case PG_TYPE_TEXT: case PG_TYPE_TEXT:
case PG_TYPE_NAME: case PG_TYPE_NAME: return SQL_SEARCHABLE;
return SQL_SEARCHABLE;
default: default: return SQL_ALL_EXCEPT_LIKE;
return SQL_ALL_EXCEPT_LIKE;
} }
} }
Int2 Int2 pgtype_unsigned(StatementClass *stmt, Int4 type)
pgtype_unsigned(StatementClass *stmt, Int4 type)
{
switch (type)
{ {
switch(type) {
case PG_TYPE_OID: case PG_TYPE_OID:
case PG_TYPE_XID: case PG_TYPE_XID: return TRUE;
return TRUE;
case PG_TYPE_INT2: case PG_TYPE_INT2:
case PG_TYPE_INT4: case PG_TYPE_INT4:
@ -832,19 +685,16 @@ pgtype_unsigned(StatementClass *stmt, Int4 type)
case PG_TYPE_NUMERIC: case PG_TYPE_NUMERIC:
case PG_TYPE_FLOAT4: case PG_TYPE_FLOAT4:
case PG_TYPE_FLOAT8: case PG_TYPE_FLOAT8:
case PG_TYPE_MONEY: case PG_TYPE_MONEY: return FALSE;
return FALSE;
default: default: return -1;
return -1;
} }
} }
char * char *pgtype_literal_prefix(StatementClass *stmt, Int4 type)
pgtype_literal_prefix(StatementClass *stmt, Int4 type)
{
switch (type)
{ {
switch(type) {
case PG_TYPE_INT2: case PG_TYPE_INT2:
case PG_TYPE_OID: case PG_TYPE_OID:
case PG_TYPE_XID: case PG_TYPE_XID:
@ -855,16 +705,14 @@ pgtype_literal_prefix(StatementClass *stmt, Int4 type)
case PG_TYPE_FLOAT8: case PG_TYPE_FLOAT8:
case PG_TYPE_MONEY: return NULL; case PG_TYPE_MONEY: return NULL;
default: default: return "'";
return "'";
} }
} }
char * char *pgtype_literal_suffix(StatementClass *stmt, Int4 type)
pgtype_literal_suffix(StatementClass *stmt, Int4 type)
{
switch (type)
{ {
switch(type) {
case PG_TYPE_INT2: case PG_TYPE_INT2:
case PG_TYPE_OID: case PG_TYPE_OID:
case PG_TYPE_XID: case PG_TYPE_XID:
@ -875,31 +723,25 @@ pgtype_literal_suffix(StatementClass *stmt, Int4 type)
case PG_TYPE_FLOAT8: case PG_TYPE_FLOAT8:
case PG_TYPE_MONEY: return NULL; case PG_TYPE_MONEY: return NULL;
default: default: return "'";
return "'";
} }
} }
char * char *pgtype_create_params(StatementClass *stmt, Int4 type)
pgtype_create_params(StatementClass *stmt, Int4 type)
{
switch (type)
{ {
switch(type) {
case PG_TYPE_CHAR: case PG_TYPE_CHAR:
case PG_TYPE_VARCHAR: return "max. length"; case PG_TYPE_VARCHAR: return "max. length";
default: default: return NULL;
return NULL;
} }
} }
Int2 Int2 sqltype_to_default_ctype(Int2 sqltype)
sqltype_to_default_ctype(Int2 sqltype)
{ {
/* from the table on page 623 of ODBC 2.0 Programmer's Reference */ /* from the table on page 623 of ODBC 2.0 Programmer's Reference */
/* (Appendix D) */ /* (Appendix D) */
switch (sqltype) switch(sqltype) {
{
case SQL_CHAR: case SQL_CHAR:
case SQL_VARCHAR: case SQL_VARCHAR:
case SQL_LONGVARCHAR: case SQL_LONGVARCHAR:
@ -945,3 +787,4 @@ sqltype_to_default_ctype(Int2 sqltype)
return SQL_C_CHAR; return SQL_C_CHAR;
} }
} }

@ -95,3 +95,4 @@ char *pgtype_create_params(StatementClass *stmt, Int4 type);
Int2 sqltype_to_default_ctype(Int2 sqltype); Int2 sqltype_to_default_ctype(Int2 sqltype);
#endif #endif

@ -1,3 +1,4 @@
/* Module: psqlodbc.c /* Module: psqlodbc.c
* *
* Description: This module contains the main entry point (DllMain) for the library. * Description: This module contains the main entry point (DllMain) for the library.
@ -38,14 +39,12 @@ RETCODE SQL_API SQLDummyOrdinal(void);
HINSTANCE NEAR s_hModule; /* Saved module handle. */ HINSTANCE NEAR s_hModule; /* Saved module handle. */
/* This is where the Driver Manager attaches to this Driver */ /* This is where the Driver Manager attaches to this Driver */
BOOL WINAPI BOOL WINAPI DllMain(HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved)
DllMain(HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved)
{ {
WORD wVersionRequested; WORD wVersionRequested;
WSADATA wsaData; WSADATA wsaData;
switch (ul_reason_for_call) switch (ul_reason_for_call) {
{
case DLL_PROCESS_ATTACH: case DLL_PROCESS_ATTACH:
s_hModule = hInst; /* Save for dialog boxes */ s_hModule = hInst; /* Save for dialog boxes */
@ -57,8 +56,8 @@ DllMain(HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved)
/* Verify that this is the minimum version of WinSock */ /* Verify that this is the minimum version of WinSock */
if ( LOBYTE( wsaData.wVersion ) != 1 || if ( LOBYTE( wsaData.wVersion ) != 1 ||
HIBYTE(wsaData.wVersion) != 1) HIBYTE( wsaData.wVersion ) != 1 ) {
{
WSACleanup(); WSACleanup();
return FALSE; return FALSE;
} }
@ -136,8 +135,8 @@ _fini(void)
Driver Manager do this. Also, the ordinal values of the Driver Manager do this. Also, the ordinal values of the
functions must match the value of fFunction in SQLGetFunctions() functions must match the value of fFunction in SQLGetFunctions()
*/ */
RETCODE SQL_API RETCODE SQL_API SQLDummyOrdinal(void)
SQLDummyOrdinal(void)
{ {
return SQL_SUCCESS; return SQL_SUCCESS;
} }

@ -6,7 +6,7 @@
* *
* Comments: See "notice.txt" for copyright and license information. * Comments: See "notice.txt" for copyright and license information.
* *
* $Id: psqlodbc.h,v 1.36 2001/02/11 13:53:42 momjian Exp $ * $Id: psqlodbc.h,v 1.37 2001/02/14 05:45:46 momjian Exp $
*/ */
#ifndef __PSQLODBC_H__ #ifndef __PSQLODBC_H__
@ -25,7 +25,6 @@
#define UInt2 unsigned short #define UInt2 unsigned short
typedef float SFLOAT; typedef float SFLOAT;
typedef double SDOUBLE; typedef double SDOUBLE;
#else #else
#define Int4 int #define Int4 int
#define UInt4 unsigned int #define UInt4 unsigned int
@ -42,7 +41,7 @@ typedef UInt4 Oid;
#define DRIVERNAME "PostgreSQL ODBC" #define DRIVERNAME "PostgreSQL ODBC"
#define DBMS_NAME "PostgreSQL" #define DBMS_NAME "PostgreSQL"
#define POSTGRESDRIVERVERSION "07.01.0003" #define POSTGRESDRIVERVERSION "07.01.0002"
#ifdef WIN32 #ifdef WIN32
#define DRIVER_FILE_NAME "PSQLODBC.DLL" #define DRIVER_FILE_NAME "PSQLODBC.DLL"
@ -55,17 +54,14 @@ typedef UInt4 Oid;
#define BLCKSZ 4096 #define BLCKSZ 4096
#endif #endif
#define MAX_MESSAGE_LEN 65536 /* This puts a limit on query size #define MAX_MESSAGE_LEN 65536 /* This puts a limit on query size but I don't */
* but I don't */
/* see an easy way round this - DJP 24-1-2001 */ /* see an easy way round this - DJP 24-1-2001 */
#define MAX_CONNECT_STRING 4096 #define MAX_CONNECT_STRING 4096
#define ERROR_MSG_LENGTH 4096 #define ERROR_MSG_LENGTH 4096
#define FETCH_MAX 100 /* default number of rows to cache #define FETCH_MAX 100 /* default number of rows to cache for declare/fetch */
* for declare/fetch */
#define TUPLE_MALLOC_INC 100 #define TUPLE_MALLOC_INC 100
#define SOCK_BUFFER_SIZE 4096 /* default socket buffer size */ #define SOCK_BUFFER_SIZE 4096 /* default socket buffer size */
#define MAX_CONNECTIONS 128 /* conns per environment #define MAX_CONNECTIONS 128 /* conns per environment (arbitrary) */
* (arbitrary) */
#define MAX_FIELDS 512 #define MAX_FIELDS 512
#define BYTELEN 8 #define BYTELEN 8
#define VARHDRSZ sizeof(Int4) #define VARHDRSZ sizeof(Int4)
@ -76,8 +72,7 @@ typedef UInt4 Oid;
/* Registry length limits */ /* Registry length limits */
#define LARGE_REGISTRY_LEN 4096 /* used for special cases */ #define LARGE_REGISTRY_LEN 4096 /* used for special cases */
#define MEDIUM_REGISTRY_LEN 256 /* normal size for #define MEDIUM_REGISTRY_LEN 256 /* normal size for user,database,etc. */
* user,database,etc. */
#define SMALL_REGISTRY_LEN 10 /* for 1/0 settings */ #define SMALL_REGISTRY_LEN 10 /* for 1/0 settings */
@ -88,17 +83,16 @@ typedef UInt4 Oid;
/* Info limits */ /* Info limits */
#define MAX_INFO_STRING 128 #define MAX_INFO_STRING 128
#define MAX_KEYPARTS 20 #define MAX_KEYPARTS 20
#define MAX_KEYLEN 512 /* max key of the form #define MAX_KEYLEN 512 /* max key of the form "date+outlet+invoice" */
* "date+outlet+invoice" */ #define MAX_ROW_SIZE 0 /* Unlimited rowsize with the Tuple Toaster */
#define MAX_ROW_SIZE 0 /* Unlimited rowsize with the #define MAX_STATEMENT_LEN 0 /* Unlimited statement size with 7.0 */
* Tuple Toaster */
#define MAX_STATEMENT_LEN 0 /* Unlimited statement size with
* 7.0 */
/* Previously, numerous query strings were defined of length MAX_STATEMENT_LEN */ /* Previously, numerous query strings were defined of length MAX_STATEMENT_LEN */
/* Now that's 0, lets use this instead. DJP 24-1-2001 */ /* Now that's 0, lets use this instead. DJP 24-1-2001 */
#define STD_STATEMENT_LEN MAX_MESSAGE_LEN #define STD_STATEMENT_LEN MAX_MESSAGE_LEN
#define PG62 "6.2" /* "Protocol" key setting to force Postgres 6.2 */
#define PG63 "6.3" /* "Protocol" key setting to force postgres 6.3 */
#define PG64 "6.4" #define PG64 "6.4"
typedef struct ConnectionClass_ ConnectionClass; typedef struct ConnectionClass_ ConnectionClass;
@ -128,8 +122,7 @@ typedef struct GlobalValues_
char disable_optimizer; char disable_optimizer;
char ksqo; char ksqo;
char unique_index; char unique_index;
char onlyread; /* readonly is reserved on Digital C++ char onlyread; /* readonly is reserved on Digital C++ compiler */
* compiler */
char use_declarefetch; char use_declarefetch;
char text_as_longvarchar; char text_as_longvarchar;
char unknowns_as_longvarchar; char unknowns_as_longvarchar;
@ -139,18 +132,13 @@ typedef struct GlobalValues_
char cancel_as_freestmt; char cancel_as_freestmt;
char extra_systable_prefixes[MEDIUM_REGISTRY_LEN]; char extra_systable_prefixes[MEDIUM_REGISTRY_LEN];
char conn_settings[LARGE_REGISTRY_LEN]; char conn_settings[LARGE_REGISTRY_LEN];
/*
* Protocol is not used anymore, but kept in case it is useful in the
* future. bjm 2001-02-10
*/
char protocol[SMALL_REGISTRY_LEN]; char protocol[SMALL_REGISTRY_LEN];
FILE* mylogFP; FILE* mylogFP;
FILE* qlogFP; FILE* qlogFP;
} GLOBAL_VALUES; } GLOBAL_VALUES;
typedef struct StatementOptions_ typedef struct StatementOptions_ {
{
int maxRows; int maxRows;
int maxLength; int maxLength;
int rowset_size; int rowset_size;
@ -158,33 +146,26 @@ typedef struct StatementOptions_
int cursor_type; int cursor_type;
int scroll_concurrency; int scroll_concurrency;
int retrieve_data; int retrieve_data;
int bind_size; /* size of each structure if using Row int bind_size; /* size of each structure if using Row Binding */
* Binding */
int use_bookmarks; int use_bookmarks;
} StatementOptions; } StatementOptions;
/* Used to pass extra query info to send_query */ /* Used to pass extra query info to send_query */
typedef struct QueryInfo_ typedef struct QueryInfo_ {
{
int row_size; int row_size;
QResultClass *result_in; QResultClass *result_in;
char *cursor; char *cursor;
} QueryInfo; } QueryInfo;
#define PG_TYPE_LO -999 /* hack until permanent #define PG_TYPE_LO -999 /* hack until permanent type available */
* type available */
#define PG_TYPE_LO_NAME "lo" #define PG_TYPE_LO_NAME "lo"
#define OID_ATTNUM -2 /* the attnum in pg_index of the #define OID_ATTNUM -2 /* the attnum in pg_index of the oid */
* oid */
/* sizes */ /* sizes */
#define TEXT_FIELD_SIZE 8190 /* size of text fields #define TEXT_FIELD_SIZE 8190 /* size of text fields (not including null term) */
* (not including null
* term) */
#define NAME_FIELD_SIZE 32 /* size of name fields */ #define NAME_FIELD_SIZE 32 /* size of name fields */
#define MAX_VARCHAR_SIZE 254 /* maximum size of a varchar (not #define MAX_VARCHAR_SIZE 254 /* maximum size of a varchar (not including null term) */
* including null term) */
#define PG_NUMERIC_MAX_PRECISION 1000 #define PG_NUMERIC_MAX_PRECISION 1000
#define PG_NUMERIC_MAX_SCALE 1000 #define PG_NUMERIC_MAX_SCALE 1000

@ -133,7 +133,7 @@ BEGIN
PUSHBUTTON "Defaults",IDDEFAULTS,185,205,50,15 PUSHBUTTON "Defaults",IDDEFAULTS,185,205,50,15
END END
DLG_OPTIONS_DS DIALOG DISCARDABLE 0, 0, 267, 125 DLG_OPTIONS_DS DIALOG DISCARDABLE 0, 0, 267, 161
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Advanced Options (DataSource)" CAPTION "Advanced Options (DataSource)"
FONT 8, "MS Sans Serif" FONT 8, "MS Sans Serif"
@ -144,16 +144,23 @@ BEGIN
BS_AUTOCHECKBOX | WS_TABSTOP,130,10,85,10 BS_AUTOCHECKBOX | WS_TABSTOP,130,10,85,10
CONTROL "Show System &Tables",DS_SHOWSYSTEMTABLES,"Button", CONTROL "Show System &Tables",DS_SHOWSYSTEMTABLES,"Button",
BS_AUTOCHECKBOX | WS_TABSTOP,25,25,85,10 BS_AUTOCHECKBOX | WS_TABSTOP,25,25,85,10
GROUPBOX "OID Options",IDC_STATIC,39,41,180,25 GROUPBOX "Protocol",IDC_STATIC,15,40,180,25
CONTROL "6.4+",DS_PG64,"Button",BS_AUTORADIOBUTTON | WS_GROUP,25,
50,35,10
CONTROL "6.3",DS_PG63,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,
75,50,26,10
CONTROL "6.2",DS_PG62,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,
130,50,26,10
GROUPBOX "OID Options",IDC_STATIC,15,70,180,25
CONTROL "Show &Column",DS_SHOWOIDCOLUMN,"Button",BS_AUTOCHECKBOX | CONTROL "Show &Column",DS_SHOWOIDCOLUMN,"Button",BS_AUTOCHECKBOX |
WS_GROUP | WS_TABSTOP,62,51,59,10 WS_GROUP | WS_TABSTOP,25,81,59,10
CONTROL "Fake &Index",DS_FAKEOIDINDEX,"Button",BS_AUTOCHECKBOX | CONTROL "Fake &Index",DS_FAKEOIDINDEX,"Button",BS_AUTOCHECKBOX |
WS_GROUP | WS_TABSTOP,151,51,51,10 WS_GROUP | WS_TABSTOP,115,81,51,10
RTEXT "Connect &Settings:",IDC_STATIC,11,73,35,25 RTEXT "Connect &Settings:",IDC_STATIC,10,105,35,25
EDITTEXT DS_CONNSETTINGS,49,73,200,20,ES_MULTILINE | EDITTEXT DS_CONNSETTINGS,50,105,200,20,ES_MULTILINE |
ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_WANTRETURN ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_WANTRETURN
DEFPUSHBUTTON "OK",IDOK,71,103,50,14,WS_GROUP DEFPUSHBUTTON "OK",IDOK,71,135,50,14,WS_GROUP
PUSHBUTTON "Cancel",IDCANCEL,145,103,50,14 PUSHBUTTON "Cancel",IDCANCEL,146,135,50,14
END END
@ -184,7 +191,7 @@ BEGIN
RIGHTMARGIN, 260 RIGHTMARGIN, 260
VERTGUIDE, 55 VERTGUIDE, 55
TOPMARGIN, 7 TOPMARGIN, 7
BOTTOMMARGIN, 118 BOTTOMMARGIN, 154
END END
END END
#endif // APSTUDIO_INVOKED #endif // APSTUDIO_INVOKED
@ -197,8 +204,8 @@ END
// //
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 7,1,0,3 FILEVERSION 7,1,0,2
PRODUCTVERSION 7,1,0,3 PRODUCTVERSION 7,1,0,2
FILEFLAGSMASK 0x3L FILEFLAGSMASK 0x3L
#ifdef _DEBUG #ifdef _DEBUG
FILEFLAGS 0x1L FILEFLAGS 0x1L
@ -216,14 +223,14 @@ BEGIN
VALUE "Comments", "PostgreSQL ODBC driver\0" VALUE "Comments", "PostgreSQL ODBC driver\0"
VALUE "CompanyName", "Insight Distribution Systems\0" VALUE "CompanyName", "Insight Distribution Systems\0"
VALUE "FileDescription", "PostgreSQL Driver\0" VALUE "FileDescription", "PostgreSQL Driver\0"
VALUE "FileVersion", " 07.01.0003\0" VALUE "FileVersion", " 07.01.0002\0"
VALUE "InternalName", "psqlodbc\0" VALUE "InternalName", "psqlodbc\0"
VALUE "LegalCopyright", "\0" VALUE "LegalCopyright", "\0"
VALUE "LegalTrademarks", "ODBC(TM) is a trademark of Microsoft Corporation. Microsoft® is a registered trademark of Microsoft Corporation. Windows(TM) is a trademark of Microsoft Corporation.\0" VALUE "LegalTrademarks", "ODBC(TM) is a trademark of Microsoft Corporation. Microsoft® is a registered trademark of Microsoft Corporation. Windows(TM) is a trademark of Microsoft Corporation.\0"
VALUE "OriginalFilename", "psqlodbc.dll\0" VALUE "OriginalFilename", "psqlodbc.dll\0"
VALUE "PrivateBuild", "\0" VALUE "PrivateBuild", "\0"
VALUE "ProductName", "Microsoft Open Database Connectivity\0" VALUE "ProductName", "Microsoft Open Database Connectivity\0"
VALUE "ProductVersion", " 07.01.0003\0" VALUE "ProductVersion", " 07.01.0002\0"
VALUE "SpecialBuild", "\0" VALUE "SpecialBuild", "\0"
END END
END END

@ -1,3 +1,4 @@
/* Module: qresult.c /* Module: qresult.c
* *
* Description: This module contains functions related to * Description: This module contains functions related to
@ -83,13 +84,11 @@ QR_Constructor(void)
mylog("in QR_Constructor\n"); mylog("in QR_Constructor\n");
rv = (QResultClass *) malloc(sizeof(QResultClass)); rv = (QResultClass *) malloc(sizeof(QResultClass));
if (rv != NULL) if (rv != NULL) {
{
rv->status = PGRES_EMPTY_QUERY; rv->status = PGRES_EMPTY_QUERY;
/* construct the column info */ /* construct the column info */
if (!(rv->fields = CI_Constructor())) if ( ! (rv->fields = CI_Constructor())) {
{
free(rv); free(rv);
return NULL; return NULL;
} }
@ -110,6 +109,7 @@ QR_Constructor(void)
rv->cache_size = globals.fetch_max; rv->cache_size = globals.fetch_max;
rv->rowset_size = 1; rv->rowset_size = 1;
} }
mylog("exit QR_Constructor\n"); mylog("exit QR_Constructor\n");
@ -151,6 +151,7 @@ QR_Destructor(QResultClass *self)
free(self); free(self);
mylog("QResult: exit DESTRUCTOR\n"); mylog("QResult: exit DESTRUCTOR\n");
} }
void void
@ -174,23 +175,19 @@ QR_set_notice(QResultClass *self, char *msg)
void void
QR_free_memory(QResultClass *self) QR_free_memory(QResultClass *self)
{ {
register int lf, register int lf, row;
row;
register TupleField *tuple = self->backend_tuples; register TupleField *tuple = self->backend_tuples;
int fcount = self->fcount; int fcount = self->fcount;
int num_fields = self->num_fields; int num_fields = self->num_fields;
mylog("QResult: free memory in, fcount=%d\n", fcount); mylog("QResult: free memory in, fcount=%d\n", fcount);
if (self->backend_tuples) if ( self->backend_tuples) {
{
for (row = 0; row < fcount; row++) for (row = 0; row < fcount; row++) {
{
mylog("row = %d, num_fields = %d\n", row, num_fields); mylog("row = %d, num_fields = %d\n", row, num_fields);
for (lf = 0; lf < num_fields; lf++) for (lf=0; lf < num_fields; lf++) {
{ if (tuple[lf].value != NULL) {
if (tuple[lf].value != NULL)
{
mylog("free [lf=%d] %u\n", lf, tuple[lf].value); mylog("free [lf=%d] %u\n", lf, tuple[lf].value);
free(tuple[lf].value); free(tuple[lf].value);
} }
@ -218,8 +215,7 @@ QR_fetch_tuples(QResultClass *self, ConnectionClass *conn, char *cursor)
/* and read the tuples. If conn is NULL, */ /* and read the tuples. If conn is NULL, */
/* it implies that we are being called from next_tuple(), */ /* it implies that we are being called from next_tuple(), */
/* like to get more rows so don't call next_tuple again! */ /* like to get more rows so don't call next_tuple again! */
if (conn != NULL) if (conn != NULL) {
{
self->conn = conn; self->conn = conn;
mylog("QR_fetch_tuples: cursor = '%s', self->cursor=%u\n", (cursor==NULL)?"":cursor, self->cursor); mylog("QR_fetch_tuples: cursor = '%s', self->cursor=%u\n", (cursor==NULL)?"":cursor, self->cursor);
@ -227,10 +223,8 @@ QR_fetch_tuples(QResultClass *self, ConnectionClass *conn, char *cursor)
if (self->cursor) if (self->cursor)
free(self->cursor); free(self->cursor);
if (globals.use_declarefetch) if ( globals.use_declarefetch) {
{ if (! cursor || cursor[0] == '\0') {
if (!cursor || cursor[0] == '\0')
{
self->status = PGRES_INTERNAL_ERROR; self->status = PGRES_INTERNAL_ERROR;
QR_set_message(self, "Internal Error -- no cursor for fetch"); QR_set_message(self, "Internal Error -- no cursor for fetch");
return FALSE; return FALSE;
@ -240,13 +234,11 @@ QR_fetch_tuples(QResultClass *self, ConnectionClass *conn, char *cursor)
/* Read the field attributes. */ /* Read the field attributes. */
/* $$$$ Should do some error control HERE! $$$$ */ /* $$$$ Should do some error control HERE! $$$$ */
if (CI_read_fields(self->fields, self->conn)) if ( CI_read_fields(self->fields, self->conn)) {
{
self->status = PGRES_FIELDS_OK; self->status = PGRES_FIELDS_OK;
self->num_fields = CI_get_num_fields(self->fields); self->num_fields = CI_get_num_fields(self->fields);
} }
else else {
{
self->status = PGRES_BAD_RESPONSE; self->status = PGRES_BAD_RESPONSE;
QR_set_message(self, "Error reading field information"); QR_set_message(self, "Error reading field information");
return FALSE; return FALSE;
@ -262,8 +254,7 @@ QR_fetch_tuples(QResultClass *self, ConnectionClass *conn, char *cursor)
/* allocate memory for the tuple cache */ /* allocate memory for the tuple cache */
mylog("MALLOC: tuple_size = %d, size = %d\n", tuple_size, self->num_fields * sizeof(TupleField) * tuple_size); mylog("MALLOC: tuple_size = %d, size = %d\n", tuple_size, self->num_fields * sizeof(TupleField) * tuple_size);
self->backend_tuples = (TupleField *) malloc(self->num_fields * sizeof(TupleField) * tuple_size); self->backend_tuples = (TupleField *) malloc(self->num_fields * sizeof(TupleField) * tuple_size);
if (!self->backend_tuples) if ( ! self->backend_tuples) {
{
self->status = PGRES_FATAL_ERROR; self->status = PGRES_FATAL_ERROR;
QR_set_message(self, "Could not get memory for tuple cache."); QR_set_message(self, "Could not get memory for tuple cache.");
return FALSE; return FALSE;
@ -279,13 +270,12 @@ QR_fetch_tuples(QResultClass *self, ConnectionClass *conn, char *cursor)
return QR_next_tuple(self); return QR_next_tuple(self);
} }
else else {
{
/* Always have to read the field attributes. */ /* Always have to read the field attributes. */
/* But we dont have to reallocate memory for them! */ /* But we dont have to reallocate memory for them! */
if (!CI_read_fields(NULL, self->conn)) if ( ! CI_read_fields(NULL, self->conn)) {
{
self->status = PGRES_BAD_RESPONSE; self->status = PGRES_BAD_RESPONSE;
QR_set_message(self, "Error reading field information"); QR_set_message(self, "Error reading field information");
return FALSE; return FALSE;
@ -301,8 +291,7 @@ QR_close(QResultClass *self)
{ {
QResultClass *res; QResultClass *res;
if (globals.use_declarefetch && self->conn && self->cursor) if (globals.use_declarefetch && self->conn && self->cursor) {
{
char buf[64]; char buf[64];
sprintf(buf, "close %s", self->cursor); sprintf(buf, "close %s", self->cursor);
@ -316,29 +305,27 @@ QR_close(QResultClass *self)
free(self->cursor); free(self->cursor);
self->cursor = NULL; self->cursor = NULL;
if (res == NULL) if (res == NULL) {
{
self->status = PGRES_FATAL_ERROR; self->status = PGRES_FATAL_ERROR;
QR_set_message(self, "Error closing cursor."); QR_set_message(self, "Error closing cursor.");
return FALSE; return FALSE;
} }
/* End the transaction if there are no cursors left on this conn */ /* End the transaction if there are no cursors left on this conn */
if (CC_cursor_count(self->conn) == 0) if (CC_cursor_count(self->conn) == 0) {
{
mylog("QResult: END transaction on conn=%u\n", self->conn); mylog("QResult: END transaction on conn=%u\n", self->conn);
res = CC_send_query(self->conn, "END", NULL); res = CC_send_query(self->conn, "END", NULL);
CC_set_no_trans(self->conn); CC_set_no_trans(self->conn);
if (res == NULL) if (res == NULL) {
{
self->status = PGRES_FATAL_ERROR; self->status = PGRES_FATAL_ERROR;
QR_set_message(self, "Error ending transaction."); QR_set_message(self, "Error ending transaction.");
return FALSE; return FALSE;
} }
} }
} }
return TRUE; return TRUE;
@ -351,59 +338,49 @@ QR_next_tuple(QResultClass *self)
int id; int id;
QResultClass *res; QResultClass *res;
SocketClass *sock; SocketClass *sock;
/* Speed up access */ /* Speed up access */
int fetch_count = self->fetch_count; int fetch_count = self->fetch_count;
int fcount = self->fcount; int fcount = self->fcount;
int fetch_size, int fetch_size, offset= 0;
offset = 0;
int end_tuple = self->rowset_size + self->base; int end_tuple = self->rowset_size + self->base;
char corrected = FALSE; char corrected = FALSE;
TupleField *the_tuples = self->backend_tuples; TupleField *the_tuples = self->backend_tuples;
static char msgbuffer[MAX_MESSAGE_LEN+1]; static char msgbuffer[MAX_MESSAGE_LEN+1];
char cmdbuffer[MAX_MESSAGE_LEN + 1]; /* QR_set_command() dups char cmdbuffer[MAX_MESSAGE_LEN+1]; /* QR_set_command() dups this string so dont need static */
* this string so dont
* need static */
char fetch[128]; char fetch[128];
QueryInfo qi; QueryInfo qi;
if (fetch_count < fcount) if (fetch_count < fcount) { /* return a row from cache */
{ /* return a row from cache */
mylog("next_tuple: fetch_count < fcount: returning tuple %d, fcount = %d\n", fetch_count, fcount); mylog("next_tuple: fetch_count < fcount: returning tuple %d, fcount = %d\n", fetch_count, fcount);
self->tupleField = the_tuples + (fetch_count * self->num_fields); /* next row */ self->tupleField = the_tuples + (fetch_count * self->num_fields); /* next row */
self->fetch_count++; self->fetch_count++;
return TRUE; return TRUE;
} }
else if (self->fcount < self->cache_size) else if (self->fcount < self->cache_size) { /* last row from cache */
{ /* last row from cache */
/* We are done because we didn't even get CACHE_SIZE tuples */ /* We are done because we didn't even get CACHE_SIZE tuples */
mylog("next_tuple: fcount < CACHE_SIZE: fcount = %d, fetch_count = %d\n", fcount, fetch_count); mylog("next_tuple: fcount < CACHE_SIZE: fcount = %d, fetch_count = %d\n", fcount, fetch_count);
self->tupleField = NULL; self->tupleField = NULL;
self->status = PGRES_END_TUPLES; self->status = PGRES_END_TUPLES;
return -1; /* end of tuples */ return -1; /* end of tuples */
} }
else else {
{ /* See if we need to fetch another group of rows.
We may be being called from send_query(), and
/* if so, don't send another fetch, just fall through
* See if we need to fetch another group of rows. We may be being and read the tuples.
* called from send_query(), and if so, don't send another fetch,
* just fall through and read the tuples.
*/ */
self->tupleField = NULL; self->tupleField = NULL;
if (!self->inTuples) if ( ! self->inTuples) {
{
if (!globals.use_declarefetch) if ( ! globals.use_declarefetch) {
{
mylog("next_tuple: ALL_ROWS: done, fcount = %d, fetch_count = %d\n", fcount, fetch_count); mylog("next_tuple: ALL_ROWS: done, fcount = %d, fetch_count = %d\n", fcount, fetch_count);
self->tupleField = NULL; self->tupleField = NULL;
self->status = PGRES_END_TUPLES; self->status = PGRES_END_TUPLES;
return -1; /* end of tuples */ return -1; /* end of tuples */
} }
if (self->base == fcount) if (self->base == fcount) { /* not a correction */
{ /* not a correction */
/* Determine the optimum cache size. */ /* Determine the optimum cache size. */
if (globals.fetch_max % self->rowset_size == 0) if (globals.fetch_max % self->rowset_size == 0)
@ -416,8 +393,7 @@ QR_next_tuple(QResultClass *self)
self->cache_size = fetch_size; self->cache_size = fetch_size;
self->fetch_count = 1; self->fetch_count = 1;
} }
else else { /* need to correct */
{ /* need to correct */
corrected = TRUE; corrected = TRUE;
@ -427,12 +403,12 @@ QR_next_tuple(QResultClass *self)
offset = self->fetch_count; offset = self->fetch_count;
self->fetch_count++; self->fetch_count++;
} }
self->backend_tuples = (TupleField *) realloc(self->backend_tuples, self->num_fields * sizeof(TupleField) * self->cache_size); self->backend_tuples = (TupleField *) realloc(self->backend_tuples, self->num_fields * sizeof(TupleField) * self->cache_size);
if (!self->backend_tuples) if ( ! self->backend_tuples) {
{
self->status = PGRES_FATAL_ERROR; self->status = PGRES_FATAL_ERROR;
QR_set_message(self, "Out of memory while reading tuples."); QR_set_message(self, "Out of memory while reading tuples.");
return FALSE; return FALSE;
@ -446,29 +422,24 @@ QR_next_tuple(QResultClass *self)
qi.result_in = self; qi.result_in = self;
qi.cursor = NULL; qi.cursor = NULL;
res = CC_send_query(self->conn, fetch, &qi); res = CC_send_query(self->conn, fetch, &qi);
if (res == NULL) if (res == NULL) {
{
self->status = PGRES_FATAL_ERROR; self->status = PGRES_FATAL_ERROR;
QR_set_message(self, "Error fetching next group."); QR_set_message(self, "Error fetching next group.");
return FALSE; return FALSE;
} }
self->inTuples = TRUE; self->inTuples = TRUE;
} }
else else {
{
mylog("next_tuple: inTuples = true, falling through: fcount = %d, fetch_count = %d\n", self->fcount, self->fetch_count); mylog("next_tuple: inTuples = true, falling through: fcount = %d, fetch_count = %d\n", self->fcount, self->fetch_count);
/* This is a pre-fetch (fetching rows right after query
/* but before any real SQLFetch() calls. This is done
* This is a pre-fetch (fetching rows right after query but so the field attributes are available.
* before any real SQLFetch() calls. This is done so the
* field attributes are available.
*/ */
self->fetch_count = 0; self->fetch_count = 0;
} }
} }
if (!corrected) if ( ! corrected) {
{
self->base = 0; self->base = 0;
self->fcount = 0; self->fcount = 0;
} }
@ -477,12 +448,11 @@ QR_next_tuple(QResultClass *self)
sock = CC_get_socket(self->conn); sock = CC_get_socket(self->conn);
self->tupleField = NULL; self->tupleField = NULL;
for (;;) for ( ; ;) {
{
id = SOCK_get_char(sock); id = SOCK_get_char(sock);
switch (id) switch (id) {
{
case 'T': /* Tuples within tuples cannot be handled */ case 'T': /* Tuples within tuples cannot be handled */
self->status = PGRES_BAD_RESPONSE; self->status = PGRES_BAD_RESPONSE;
QR_set_message(self, "Tuples within tuples cannot be handled"); QR_set_message(self, "Tuples within tuples cannot be handled");
@ -490,23 +460,19 @@ QR_next_tuple(QResultClass *self)
case 'B': /* Tuples in binary format */ case 'B': /* Tuples in binary format */
case 'D': /* Tuples in ASCII format */ case 'D': /* Tuples in ASCII format */
if (!globals.use_declarefetch && self->fcount > 0 && !(self->fcount % TUPLE_MALLOC_INC)) if ( ! globals.use_declarefetch && self->fcount > 0 && ! (self->fcount % TUPLE_MALLOC_INC)) {
{
size_t old_size = self->fcount * self->num_fields * sizeof(TupleField); size_t old_size = self->fcount * self->num_fields * sizeof(TupleField);
mylog("REALLOC: old_size = %d\n", old_size); mylog("REALLOC: old_size = %d\n", old_size);
self->backend_tuples = (TupleField *) realloc(self->backend_tuples, old_size + (self->num_fields * sizeof(TupleField) * TUPLE_MALLOC_INC)); self->backend_tuples = (TupleField *) realloc(self->backend_tuples, old_size + (self->num_fields * sizeof(TupleField) * TUPLE_MALLOC_INC));
if (!self->backend_tuples) if ( ! self->backend_tuples) {
{
self->status = PGRES_FATAL_ERROR; self->status = PGRES_FATAL_ERROR;
QR_set_message(self, "Out of memory while reading tuples."); QR_set_message(self, "Out of memory while reading tuples.");
return FALSE; return FALSE;
} }
} }
if (!QR_read_tuple(self, (char) (id == 0))) if ( ! QR_read_tuple(self, (char) (id == 0))) {
{
self->status = PGRES_BAD_RESPONSE; self->status = PGRES_BAD_RESPONSE;
QR_set_message(self, "Error reading the tuple"); QR_set_message(self, "Error reading the tuple");
return FALSE; return FALSE;
@ -523,8 +489,8 @@ QR_next_tuple(QResultClass *self)
mylog("end of tuple list -- setting inUse to false: this = %u\n", self); mylog("end of tuple list -- setting inUse to false: this = %u\n", self);
self->inTuples = FALSE; self->inTuples = FALSE;
if (self->fcount > 0) if (self->fcount > 0) {
{
qlog(" [ fetched %d rows ]\n", self->fcount); qlog(" [ fetched %d rows ]\n", self->fcount);
mylog("_next_tuple: 'C' fetch_max && fcount = %d\n", self->fcount); mylog("_next_tuple: 'C' fetch_max && fcount = %d\n", self->fcount);
@ -532,9 +498,7 @@ QR_next_tuple(QResultClass *self)
self->tupleField = self->backend_tuples + (offset * self->num_fields); self->tupleField = self->backend_tuples + (offset * self->num_fields);
return TRUE; return TRUE;
} }
else else { /* We are surely done here (we read 0 tuples) */
{ /* We are surely done here (we read 0
* tuples) */
qlog(" [ fetched 0 rows ]\n"); qlog(" [ fetched 0 rows ]\n");
mylog("_next_tuple: 'C': DONE (fcount == 0)\n"); mylog("_next_tuple: 'C': DONE (fcount == 0)\n");
return -1; /* end of tuples */ return -1; /* end of tuples */
@ -559,8 +523,7 @@ QR_next_tuple(QResultClass *self)
qlog("NOTICE from backend in next_tuple: '%s'\n", msgbuffer); qlog("NOTICE from backend in next_tuple: '%s'\n", msgbuffer);
continue; continue;
default: /* this should only happen if the backend default: /* this should only happen if the backend dumped core */
* dumped core */
mylog("QR_next_tuple: Unexpected result from backend: id = '%c' (%d)\n", id, id); mylog("QR_next_tuple: Unexpected result from backend: id = '%c' (%d)\n", id, id);
qlog("QR_next_tuple: Unexpected result from backend: id = '%c' (%d)\n", id, id); qlog("QR_next_tuple: Unexpected result from backend: id = '%c' (%d)\n", id, id);
QR_set_message(self, "Unexpected result from backend. It probably crashed"); QR_set_message(self, "Unexpected result from backend. It probably crashed");
@ -577,8 +540,7 @@ QR_read_tuple(QResultClass *self, char binary)
{ {
Int2 field_lf; Int2 field_lf;
TupleField *this_tuplefield; TupleField *this_tuplefield;
char bmp, char bmp, bitmap[MAX_FIELDS]; /* Max. len of the bitmap */
bitmap[MAX_FIELDS]; /* Max. len of the bitmap */
Int2 bitmaplen; /* len of the bitmap in bytes */ Int2 bitmaplen; /* len of the bitmap in bytes */
Int2 bitmap_pos; Int2 bitmap_pos;
Int2 bitcnt; Int2 bitcnt;
@ -597,8 +559,8 @@ QR_read_tuple(QResultClass *self, char binary)
bitmaplen++; bitmaplen++;
/* /*
* At first the server sends a bitmap that indicates which database At first the server sends a bitmap that indicates which
* fields are null database fields are null
*/ */
SOCK_get_n_char(sock, bitmap, bitmaplen); SOCK_get_n_char(sock, bitmap, bitmaplen);
@ -606,21 +568,16 @@ QR_read_tuple(QResultClass *self, char binary)
bitcnt = 0; bitcnt = 0;
bmp = bitmap[bitmap_pos]; bmp = bitmap[bitmap_pos];
for (field_lf = 0; field_lf < num_fields; field_lf++) for(field_lf = 0; field_lf < num_fields; field_lf++) {
{
/* Check if the current field is NULL */ /* Check if the current field is NULL */
if (!(bmp & 0200)) if(!(bmp & 0200)) {
{
/* YES, it is NULL ! */ /* YES, it is NULL ! */
this_tuplefield[field_lf].len = 0; this_tuplefield[field_lf].len = 0;
this_tuplefield[field_lf].value = 0; this_tuplefield[field_lf].value = 0;
} } else {
else
{
/* /*
* NO, the field is not null. so get at first the length of NO, the field is not null. so get at first the
* the field (four bytes) length of the field (four bytes)
*/ */
len = SOCK_get_int(sock, VARHDRSZ); len = SOCK_get_int(sock, VARHDRSZ);
if (!binary) if (!binary)
@ -635,31 +592,27 @@ QR_read_tuple(QResultClass *self, char binary)
this_tuplefield[field_lf].len = len; this_tuplefield[field_lf].len = len;
this_tuplefield[field_lf].value = buffer; this_tuplefield[field_lf].value = buffer;
/* /* This can be used to set the longest length of the column for any
* This can be used to set the longest length of the column row in the tuple cache. It would not be accurate for varchar and
* for any row in the tuple cache. It would not be accurate text fields to use this since a tuple cache is only 100 rows.
* for varchar and text fields to use this since a tuple cache Bpchar can be handled since the strlen of all rows is fixed,
* is only 100 rows. Bpchar can be handled since the strlen of assuming there are not 100 nulls in a row!
* all rows is fixed, assuming there are not 100 nulls in a
* row!
*/ */
flds = self->fields; flds = self->fields;
if (flds->display_size[field_lf] < len) if (flds->display_size[field_lf] < len)
flds->display_size[field_lf] = len; flds->display_size[field_lf] = len;
} }
/* /*
* Now adjust for the next bit to be scanned in the next loop. Now adjust for the next bit to be scanned in the
next loop.
*/ */
bitcnt++; bitcnt++;
if (BYTELEN == bitcnt) if (BYTELEN == bitcnt) {
{
bitmap_pos++; bitmap_pos++;
bmp = bitmap[bitmap_pos]; bmp = bitmap[bitmap_pos];
bitcnt = 0; bitcnt = 0;
} } else
else
bmp <<= 1; bmp <<= 1;
} }
self->currTuple++; self->currTuple++;

@ -17,8 +17,7 @@
#include "psqlodbc.h" #include "psqlodbc.h"
#include "tuple.h" #include "tuple.h"
enum QueryResultCode_ enum QueryResultCode_ {
{
PGRES_EMPTY_QUERY = 0, PGRES_EMPTY_QUERY = 0,
PGRES_COMMAND_OK, /* a query command that doesn't return */ PGRES_COMMAND_OK, /* a query command that doesn't return */
/* anything was executed properly by the backend */ /* anything was executed properly by the backend */
@ -27,24 +26,20 @@ enum QueryResultCode_
/* contains the resulttuples */ /* contains the resulttuples */
PGRES_COPY_OUT, PGRES_COPY_OUT,
PGRES_COPY_IN, PGRES_COPY_IN,
PGRES_BAD_RESPONSE, /* an unexpected response was recv'd from PGRES_BAD_RESPONSE, /* an unexpected response was recv'd from the backend */
* the backend */
PGRES_NONFATAL_ERROR, PGRES_NONFATAL_ERROR,
PGRES_FATAL_ERROR, PGRES_FATAL_ERROR,
PGRES_FIELDS_OK, /* field information from a query was PGRES_FIELDS_OK, /* field information from a query was successful */
* successful */
PGRES_END_TUPLES, PGRES_END_TUPLES,
PGRES_INTERNAL_ERROR PGRES_INTERNAL_ERROR
}; };
typedef enum QueryResultCode_ QueryResultCode; typedef enum QueryResultCode_ QueryResultCode;
struct QResultClass_ struct QResultClass_ {
{
ColumnInfoClass *fields; /* the Column information */ ColumnInfoClass *fields; /* the Column information */
TupleListClass *manual_tuples; /* manual result tuple list */ TupleListClass *manual_tuples; /* manual result tuple list */
ConnectionClass *conn; /* the connection this result is using ConnectionClass *conn; /* the connection this result is using (backend) */
* (backend) */
/* Stuff for declare/fetch tuples */ /* Stuff for declare/fetch tuples */
int fetch_count; /* logical rows read so far */ int fetch_count; /* logical rows read so far */
@ -59,16 +54,14 @@ struct QResultClass_
QueryResultCode status; QueryResultCode status;
char *message; char *message;
char *cursor; /* The name of the cursor for select char *cursor; /* The name of the cursor for select statements */
* statements */
char *command; char *command;
char *notice; char *notice;
TupleField *backend_tuples; /* data from the backend (the tuple cache) */ TupleField *backend_tuples; /* data from the backend (the tuple cache) */
TupleField *tupleField; /* current backend tuple being retrieved */ TupleField *tupleField; /* current backend tuple being retrieved */
char inTuples; /* is a fetch of rows from the backend in char inTuples; /* is a fetch of rows from the backend in progress? */
* progress? */
}; };
#define QR_get_fields(self) (self->fields) #define QR_get_fields(self) (self->fields)

@ -1,7 +1,7 @@
/* {{NO_DEPENDENCIES}} */ /* {{NO_DEPENDENCIES}} */
/* Microsoft Developer Studio generated include file. */ /* Microsoft Developer Studio generated include file. */
/* Used by psqlodbc.rc */ /* Used by psqlodbc.rc */
/* */
#define IDS_BADDSN 1 #define IDS_BADDSN 1
#define IDS_MSGTITLE 2 #define IDS_MSGTITLE 2
#define DLG_OPTIONS_DRV 102 #define DLG_OPTIONS_DRV 102
@ -19,6 +19,7 @@
#define DS_SHOWOIDCOLUMN 1012 #define DS_SHOWOIDCOLUMN 1012
#define DS_FAKEOIDINDEX 1013 #define DS_FAKEOIDINDEX 1013
#define DRV_COMMLOG 1014 #define DRV_COMMLOG 1014
#define DS_PG62 1016
#define IDC_DATASOURCE 1018 #define IDC_DATASOURCE 1018
#define DRV_OPTIMIZER 1019 #define DRV_OPTIMIZER 1019
#define DS_CONNSETTINGS 1020 #define DS_CONNSETTINGS 1020
@ -47,9 +48,10 @@
#define IDC_OPTIONS 1054 #define IDC_OPTIONS 1054
#define DRV_KSQO 1055 #define DRV_KSQO 1055
#define DS_PG64 1057 #define DS_PG64 1057
#define DS_PG63 1058
/* Next default values for new objects */ /* Next default values for new objects */
/* */
#ifdef APSTUDIO_INVOKED #ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS #ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 104 #define _APS_NEXT_RESOURCE_VALUE 104

File diff suppressed because it is too large Load Diff

@ -1,3 +1,4 @@
/* Module: setup.c /* Module: setup.c
* *
* Description: This module contains the setup functions for * Description: This module contains the setup functions for
@ -42,14 +43,14 @@ extern GLOBAL_VALUES globals;
/* Globals ----------------------------------------------------------------- */ /* Globals ----------------------------------------------------------------- */
/* NOTE: All these are used by the dialog procedures */ /* NOTE: All these are used by the dialog procedures */
typedef struct tagSETUPDLG typedef struct tagSETUPDLG {
{
HWND hwndParent; /* Parent window handle */ HWND hwndParent; /* Parent window handle */
LPCSTR lpszDrvr; /* Driver description */ LPCSTR lpszDrvr; /* Driver description */
ConnInfo ci; ConnInfo ci;
char szDSN[MAXDSNAME]; /* Original data source name */ char szDSN[MAXDSNAME]; /* Original data source name */
BOOL fNewDSN; /* New data source flag */ BOOL fNewDSN; /* New data source flag */
BOOL fDefault; /* Default data source flag */ BOOL fDefault; /* Default data source flag */
} SETUPDLG, FAR *LPSETUPDLG; } SETUPDLG, FAR *LPSETUPDLG;
@ -72,8 +73,7 @@ BOOL INTFUNC SetDSNAttributes(HWND hwnd, LPSETUPDLG lpsetupdlg);
Output : TRUE success, FALSE otherwise Output : TRUE success, FALSE otherwise
--------------------------------------------------------------------------*/ --------------------------------------------------------------------------*/
BOOL CALLBACK BOOL CALLBACK ConfigDSN (HWND hwnd,
ConfigDSN(HWND hwnd,
WORD fRequest, WORD fRequest,
LPCSTR lpszDriver, LPCSTR lpszDriver,
LPCSTR lpszAttributes) LPCSTR lpszAttributes)
@ -100,8 +100,7 @@ ConfigDSN(HWND hwnd,
lpsetupdlg->szDSN[0] = '\0'; lpsetupdlg->szDSN[0] = '\0';
/* Remove data source */ /* Remove data source */
if (ODBC_REMOVE_DSN == fRequest) if (ODBC_REMOVE_DSN == fRequest) {
{
/* Fail if no data source name was supplied */ /* Fail if no data source name was supplied */
if (!lpsetupdlg->ci.dsn[0]) if (!lpsetupdlg->ci.dsn[0])
fSuccess = FALSE; fSuccess = FALSE;
@ -112,20 +111,15 @@ ConfigDSN(HWND hwnd,
} }
/* Add or Configure data source */ /* Add or Configure data source */
else else {
{
/* Save passed variables for global access (e.g., dialog access) */ /* Save passed variables for global access (e.g., dialog access) */
lpsetupdlg->hwndParent = hwnd; lpsetupdlg->hwndParent = hwnd;
lpsetupdlg->lpszDrvr = lpszDriver; lpsetupdlg->lpszDrvr = lpszDriver;
lpsetupdlg->fNewDSN = (ODBC_ADD_DSN == fRequest); lpsetupdlg->fNewDSN = (ODBC_ADD_DSN == fRequest);
lpsetupdlg->fDefault = !lstrcmpi(lpsetupdlg->ci.dsn, INI_DSN); lpsetupdlg->fDefault = !lstrcmpi(lpsetupdlg->ci.dsn, INI_DSN);
/* /* Display the appropriate dialog (if parent window handle supplied) */
* Display the appropriate dialog (if parent window handle if (hwnd) {
* supplied)
*/
if (hwnd)
{
/* Display dialog(s) */ /* Display dialog(s) */
fSuccess = (IDOK == DialogBoxParam(s_hModule, fSuccess = (IDOK == DialogBoxParam(s_hModule,
MAKEINTRESOURCE(DLG_CONFIG), MAKEINTRESOURCE(DLG_CONFIG),
@ -152,15 +146,11 @@ ConfigDSN(HWND hwnd,
Input : hdlg -- Dialog window handle Input : hdlg -- Dialog window handle
Output : None Output : None
--------------------------------------------------------------------------*/ --------------------------------------------------------------------------*/
void INTFUNC void INTFUNC CenterDialog(HWND hdlg)
CenterDialog(HWND hdlg)
{ {
HWND hwndFrame; HWND hwndFrame;
RECT rcDlg, RECT rcDlg, rcScr, rcFrame;
rcScr, int cx, cy;
rcFrame;
int cx,
cy;
hwndFrame = GetParent(hdlg); hwndFrame = GetParent(hdlg);
@ -188,10 +178,8 @@ CenterDialog(HWND hdlg)
rcDlg.left = rcDlg.right - cx; rcDlg.left = rcDlg.right - cx;
} }
if (rcDlg.left < 0) if (rcDlg.left < 0) rcDlg.left = 0;
rcDlg.left = 0; if (rcDlg.top < 0) rcDlg.top = 0;
if (rcDlg.top < 0)
rcDlg.top = 0;
MoveWindow(hdlg, rcDlg.left, rcDlg.top, cx, cy, TRUE); MoveWindow(hdlg, rcDlg.left, rcDlg.top, cx, cy, TRUE);
return; return;
@ -207,14 +195,13 @@ CenterDialog(HWND hdlg)
--------------------------------------------------------------------------*/ --------------------------------------------------------------------------*/
int CALLBACK int CALLBACK ConfigDlgProc(HWND hdlg,
ConfigDlgProc(HWND hdlg,
WORD wMsg, WORD wMsg,
WPARAM wParam, WPARAM wParam,
LPARAM lParam) LPARAM lParam)
{ {
switch (wMsg)
{ switch (wMsg) {
/* Initialize the dialog */ /* Initialize the dialog */
case WM_INITDIALOG: case WM_INITDIALOG:
{ {
@ -227,10 +214,7 @@ ConfigDlgProc(HWND hdlg,
SetWindowLong(hdlg, DWL_USER, lParam); SetWindowLong(hdlg, DWL_USER, lParam);
CenterDialog(hdlg); /* Center dialog */ CenterDialog(hdlg); /* Center dialog */
/* /* NOTE: Values supplied in the attribute string will always */
* NOTE: Values supplied in the attribute string will
* always
*/
/* override settings in ODBC.INI */ /* override settings in ODBC.INI */
/* Get the rest of the common attributes */ /* Get the rest of the common attributes */
@ -244,8 +228,7 @@ ConfigDlgProc(HWND hdlg,
SetDlgStuff(hdlg, ci); SetDlgStuff(hdlg, ci);
if (lpsetupdlg->fDefault) if (lpsetupdlg->fDefault) {
{
EnableWindow(GetDlgItem(hdlg, IDC_DSNAME), FALSE); EnableWindow(GetDlgItem(hdlg, IDC_DSNAME), FALSE);
EnableWindow(GetDlgItem(hdlg, IDC_DSNAMETEXT), FALSE); EnableWindow(GetDlgItem(hdlg, IDC_DSNAMETEXT), FALSE);
} }
@ -262,13 +245,8 @@ ConfigDlgProc(HWND hdlg,
/* Process buttons */ /* Process buttons */
case WM_COMMAND: case WM_COMMAND:
switch (GET_WM_COMMAND_ID(wParam, lParam)) switch (GET_WM_COMMAND_ID(wParam, lParam)) {
{ /* Ensure the OK button is enabled only when a data source name */
/*
* Ensure the OK button is enabled only when a data
* source name
*/
/* is entered */ /* is entered */
case IDC_DSNAME: case IDC_DSNAME:
if (GET_WM_COMMAND_CMD(wParam, lParam) == EN_CHANGE) if (GET_WM_COMMAND_CMD(wParam, lParam) == EN_CHANGE)
@ -342,8 +320,7 @@ ConfigDlgProc(HWND hdlg,
Input : lpszAttributes - Pointer to attribute string Input : lpszAttributes - Pointer to attribute string
Output : None (global aAttr normally updated) Output : None (global aAttr normally updated)
--------------------------------------------------------------------------*/ --------------------------------------------------------------------------*/
void INTFUNC void INTFUNC ParseAttributes(LPCSTR lpszAttributes, LPSETUPDLG lpsetupdlg)
ParseAttributes(LPCSTR lpszAttributes, LPSETUPDLG lpsetupdlg)
{ {
LPCSTR lpsz; LPCSTR lpsz;
LPCSTR lpszStart; LPCSTR lpszStart;
@ -354,8 +331,7 @@ ParseAttributes(LPCSTR lpszAttributes, LPSETUPDLG lpsetupdlg)
memset(&lpsetupdlg->ci, 0, sizeof(ConnInfo)); memset(&lpsetupdlg->ci, 0, sizeof(ConnInfo));
for (lpsz=lpszAttributes; *lpsz; lpsz++) for (lpsz=lpszAttributes; *lpsz; lpsz++)
{ /* Extract key name (e.g., DSN), it must { /* Extract key name (e.g., DSN), it must be terminated by an equals */
* be terminated by an equals */
lpszStart = lpsz; lpszStart = lpsz;
for (;; lpsz++) for (;; lpsz++)
{ {
@ -368,6 +344,7 @@ ParseAttributes(LPCSTR lpszAttributes, LPSETUPDLG lpsetupdlg)
cbKey = lpsz - lpszStart; cbKey = lpsz - lpszStart;
if (cbKey < sizeof(aszKey)) if (cbKey < sizeof(aszKey))
{ {
_fmemcpy(aszKey, lpszStart, cbKey); _fmemcpy(aszKey, lpszStart, cbKey);
aszKey[cbKey] = '\0'; aszKey[cbKey] = '\0';
} }
@ -395,8 +372,7 @@ ParseAttributes(LPCSTR lpszAttributes, LPSETUPDLG lpsetupdlg)
Output : TRUE if successful, FALSE otherwise Output : TRUE if successful, FALSE otherwise
--------------------------------------------------------------------------*/ --------------------------------------------------------------------------*/
BOOL INTFUNC BOOL INTFUNC SetDSNAttributes(HWND hwndParent, LPSETUPDLG lpsetupdlg)
SetDSNAttributes(HWND hwndParent, LPSETUPDLG lpsetupdlg)
{ {
LPCSTR lpszDSN; /* Pointer to data source name */ LPCSTR lpszDSN; /* Pointer to data source name */
@ -429,6 +405,8 @@ SetDSNAttributes(HWND hwndParent, LPSETUPDLG lpsetupdlg)
/* If the data source name has changed, remove the old name */ /* If the data source name has changed, remove the old name */
if (lstrcmpi(lpsetupdlg->szDSN, lpsetupdlg->ci.dsn)) if (lstrcmpi(lpsetupdlg->szDSN, lpsetupdlg->ci.dsn))
{
SQLRemoveDSNFromIni(lpsetupdlg->szDSN); SQLRemoveDSNFromIni(lpsetupdlg->szDSN);
}
return TRUE; return TRUE;
} }

@ -1,3 +1,4 @@
/* Module: socket.c /* Module: socket.c
* *
* Description: This module contains functions for low level socket * Description: This module contains functions for low level socket
@ -49,8 +50,7 @@ SOCK_Constructor()
rv = (SocketClass *) malloc(sizeof(SocketClass)); rv = (SocketClass *) malloc(sizeof(SocketClass));
if (rv != NULL) if (rv != NULL) {
{
rv->socket = (SOCKETFD) -1; rv->socket = (SOCKETFD) -1;
rv->buffer_filled_in = 0; rv->buffer_filled_in = 0;
rv->buffer_filled_out = 0; rv->buffer_filled_out = 0;
@ -70,13 +70,13 @@ SOCK_Constructor()
rv->reverse = FALSE; rv->reverse = FALSE;
} }
return rv; return rv;
} }
void void
SOCK_Destructor(SocketClass *self) SOCK_Destructor(SocketClass *self)
{ {
if (self->socket != -1) if (self->socket != -1) {
{
SOCK_put_char(self, 'X'); SOCK_put_char(self, 'X');
SOCK_flush_output(self); SOCK_flush_output(self);
closesocket(self->socket); closesocket(self->socket);
@ -89,6 +89,7 @@ SOCK_Destructor(SocketClass *self)
free(self->buffer_out); free(self->buffer_out);
free(self); free(self);
} }
@ -99,8 +100,7 @@ SOCK_connect_to(SocketClass *self, unsigned short port, char *hostname)
struct sockaddr_in sadr; struct sockaddr_in sadr;
unsigned long iaddr; unsigned long iaddr;
if (self->socket != -1) if (self->socket != -1) {
{
self->errornumber = SOCKET_ALREADY_CONNECTED; self->errornumber = SOCKET_ALREADY_CONNECTED;
self->errormsg = "Socket is already connected"; self->errormsg = "Socket is already connected";
return 0; return 0;
@ -108,15 +108,13 @@ SOCK_connect_to(SocketClass *self, unsigned short port, char *hostname)
memset((char *)&sadr, 0, sizeof(sadr)); memset((char *)&sadr, 0, sizeof(sadr));
/* /* If it is a valid IP address, use it.
* If it is a valid IP address, use it. Otherwise use hostname lookup. Otherwise use hostname lookup.
*/ */
iaddr = inet_addr(hostname); iaddr = inet_addr(hostname);
if (iaddr == INADDR_NONE) if (iaddr == INADDR_NONE) {
{
host = gethostbyname(hostname); host = gethostbyname(hostname);
if (host == NULL) if (host == NULL) {
{
self->errornumber = SOCKET_HOST_NOT_FOUND; self->errornumber = SOCKET_HOST_NOT_FOUND;
self->errormsg = "Could not resolve hostname."; self->errormsg = "Could not resolve hostname.";
return 0; return 0;
@ -130,16 +128,15 @@ SOCK_connect_to(SocketClass *self, unsigned short port, char *hostname)
sadr.sin_port = htons(port); sadr.sin_port = htons(port);
self->socket = socket(AF_INET, SOCK_STREAM, 0); self->socket = socket(AF_INET, SOCK_STREAM, 0);
if (self->socket == -1) if (self->socket == -1) {
{
self->errornumber = SOCKET_COULD_NOT_CREATE_SOCKET; self->errornumber = SOCKET_COULD_NOT_CREATE_SOCKET;
self->errormsg = "Could not create Socket."; self->errormsg = "Could not create Socket.";
return 0; return 0;
} }
if ( connect(self->socket, (struct sockaddr *)&(sadr), if ( connect(self->socket, (struct sockaddr *)&(sadr),
sizeof(sadr)) < 0) sizeof(sadr)) < 0) {
{
self->errornumber = SOCKET_COULD_NOT_CONNECT; self->errornumber = SOCKET_COULD_NOT_CONNECT;
self->errormsg = "Could not connect to remote socket."; self->errormsg = "Could not connect to remote socket.";
closesocket(self->socket); closesocket(self->socket);
@ -155,8 +152,7 @@ SOCK_get_n_char(SocketClass *self, char *buffer, int len)
{ {
int lf; int lf;
if (!buffer) if ( ! buffer) {
{
self->errornumber = SOCKET_NULLPOINTER_PARAMETER; self->errornumber = SOCKET_NULLPOINTER_PARAMETER;
self->errormsg = "get_n_char was called with NULL-Pointer"; self->errormsg = "get_n_char was called with NULL-Pointer";
return; return;
@ -172,8 +168,7 @@ SOCK_put_n_char(SocketClass *self, char *buffer, int len)
{ {
int lf; int lf;
if (!buffer) if ( ! buffer) {
{
self->errornumber = SOCKET_NULLPOINTER_PARAMETER; self->errornumber = SOCKET_NULLPOINTER_PARAMETER;
self->errormsg = "put_n_char was called with NULL-Pointer"; self->errormsg = "put_n_char was called with NULL-Pointer";
return; return;
@ -218,8 +213,7 @@ SOCK_get_int(SocketClass *self, short len)
{ {
char buf[4]; char buf[4];
switch (len) switch (len) {
{
case 2: case 2:
SOCK_get_n_char(self, buf, len); SOCK_get_n_char(self, buf, len);
if (self->reverse) if (self->reverse)
@ -247,8 +241,7 @@ SOCK_put_int(SocketClass *self, int value, short len)
{ {
unsigned int rv; unsigned int rv;
switch (len) switch (len) {
{
case 2: case 2:
rv = self->reverse ? value : htons( (unsigned short) value); rv = self->reverse ? value : htons( (unsigned short) value);
SOCK_put_n_char(self, (char *) &rv, 2); SOCK_put_n_char(self, (char *) &rv, 2);
@ -273,8 +266,7 @@ SOCK_flush_output(SocketClass *self)
int written; int written;
written = send(self->socket, (char *)self->buffer_out, self->buffer_filled_out, 0); written = send(self->socket, (char *)self->buffer_out, self->buffer_filled_out, 0);
if (written != self->buffer_filled_out) if (written != self->buffer_filled_out) {
{
self->errornumber = SOCKET_WRITE_ERROR; self->errornumber = SOCKET_WRITE_ERROR;
self->errormsg = "Could not flush socket buffer."; self->errormsg = "Could not flush socket buffer.";
} }
@ -284,27 +276,23 @@ SOCK_flush_output(SocketClass *self)
unsigned char unsigned char
SOCK_get_next_byte(SocketClass *self) SOCK_get_next_byte(SocketClass *self)
{ {
if (self->buffer_read_in >= self->buffer_filled_in)
{ if (self->buffer_read_in >= self->buffer_filled_in) {
/* there are no more bytes left in the buffer, so */ /* there are no more bytes left in the buffer so */
/* reload the buffer */ /* reload the buffer */
self->buffer_read_in = 0; self->buffer_read_in = 0;
self->buffer_filled_in = recv(self->socket, (char *) self->buffer_in, self->buffer_filled_in = recv(self->socket, (char *)self->buffer_in, globals.socket_buffersize, 0);
globals.socket_buffersize, 0);
mylog("read %d, global_socket_buffersize=%d\n", mylog("read %d, global_socket_buffersize=%d\n", self->buffer_filled_in, globals.socket_buffersize);
self->buffer_filled_in, globals.socket_buffersize);
if (self->buffer_filled_in < 0) if (self->buffer_filled_in < 0) {
{
self->errornumber = SOCKET_READ_ERROR; self->errornumber = SOCKET_READ_ERROR;
self->errormsg = "Error while reading from the socket."; self->errormsg = "Error while reading from the socket.";
self->buffer_filled_in = 0; self->buffer_filled_in = 0;
return 0; return 0;
} }
if (self->buffer_filled_in == 0) if (self->buffer_filled_in == 0) {
{
self->errornumber = SOCKET_CLOSED; self->errornumber = SOCKET_CLOSED;
self->errormsg = "Socket has been closed."; self->errormsg = "Socket has been closed.";
self->buffer_filled_in = 0; self->buffer_filled_in = 0;
@ -321,12 +309,10 @@ SOCK_put_next_byte(SocketClass *self, unsigned char next_byte)
self->buffer_out[self->buffer_filled_out++] = next_byte; self->buffer_out[self->buffer_filled_out++] = next_byte;
if (self->buffer_filled_out == globals.socket_buffersize) if (self->buffer_filled_out == globals.socket_buffersize) {
{
/* buffer is full, so write it out */ /* buffer is full, so write it out */
bytes_sent = send(self->socket, (char *)self->buffer_out, globals.socket_buffersize, 0); bytes_sent = send(self->socket, (char *)self->buffer_out, globals.socket_buffersize, 0);
if (bytes_sent != globals.socket_buffersize) if (bytes_sent != globals.socket_buffersize) {
{
self->errornumber = SOCKET_WRITE_ERROR; self->errornumber = SOCKET_WRITE_ERROR;
self->errormsg = "Error while writing to the socket."; self->errormsg = "Error while writing to the socket.";
} }

@ -29,7 +29,6 @@
#ifndef _IN_ADDR_T #ifndef _IN_ADDR_T
#define _IN_ADDR_T #define _IN_ADDR_T
typedef unsigned int in_addr_t; typedef unsigned int in_addr_t;
#endif #endif
#define INADDR_NONE ((in_addr_t)-1) #define INADDR_NONE ((in_addr_t)-1)
#endif #endif
@ -53,8 +52,7 @@ typedef unsigned int in_addr_t;
#define SOCKET_CLOSED 10 #define SOCKET_CLOSED 10
struct SocketClass_ struct SocketClass_ {
{
int buffer_filled_in; int buffer_filled_in;
int buffer_filled_out; int buffer_filled_out;
@ -67,8 +65,7 @@ struct SocketClass_
char *errormsg; char *errormsg;
int errornumber; int errornumber;
char reverse; /* used to handle Postgres 6.2 protocol char reverse; /* used to handle Postgres 6.2 protocol (reverse byte order) */
* (reverse byte order) */
}; };

@ -1,3 +1,4 @@
/* Module: statement.c /* Module: statement.c
* *
* Description: This module contains functions related to creating * Description: This module contains functions related to creating
@ -45,48 +46,24 @@ extern GLOBAL_VALUES globals;
#define PRN_NULLCHECK #define PRN_NULLCHECK
/* Map sql commands to statement types */ /* Map sql commands to statement types */
static struct static struct {
{
int type; int type;
char *s; char *s;
} Statement_Type[] = } Statement_Type[] = {
{ STMT_TYPE_SELECT, "SELECT" },
{ { STMT_TYPE_INSERT, "INSERT" },
{ { STMT_TYPE_UPDATE, "UPDATE" },
STMT_TYPE_SELECT, "SELECT" { STMT_TYPE_DELETE, "DELETE" },
}, { STMT_TYPE_CREATE, "CREATE" },
{ { STMT_TYPE_ALTER, "ALTER" },
STMT_TYPE_INSERT, "INSERT" { STMT_TYPE_DROP, "DROP" },
}, { STMT_TYPE_GRANT, "GRANT" },
{ { STMT_TYPE_REVOKE, "REVOKE" },
STMT_TYPE_UPDATE, "UPDATE" { 0, NULL }
},
{
STMT_TYPE_DELETE, "DELETE"
},
{
STMT_TYPE_CREATE, "CREATE"
},
{
STMT_TYPE_ALTER, "ALTER"
},
{
STMT_TYPE_DROP, "DROP"
},
{
STMT_TYPE_GRANT, "GRANT"
},
{
STMT_TYPE_REVOKE, "REVOKE"
},
{
0, NULL
}
}; };
RETCODE SQL_API RETCODE SQL_API SQLAllocStmt(HDBC hdbc,
SQLAllocStmt(HDBC hdbc,
HSTMT FAR *phstmt) HSTMT FAR *phstmt)
{ {
static char *func="SQLAllocStmt"; static char *func="SQLAllocStmt";
@ -95,8 +72,7 @@ SQLAllocStmt(HDBC hdbc,
mylog("%s: entering...\n", func); mylog("%s: entering...\n", func);
if (!conn) if( ! conn) {
{
CC_log_error(func, "", NULL); CC_log_error(func, "", NULL);
return SQL_INVALID_HANDLE; return SQL_INVALID_HANDLE;
} }
@ -105,8 +81,7 @@ SQLAllocStmt(HDBC hdbc,
mylog("**** SQLAllocStmt: hdbc = %u, stmt = %u\n", hdbc, stmt); mylog("**** SQLAllocStmt: hdbc = %u, stmt = %u\n", hdbc, stmt);
if (!stmt) if ( ! stmt) {
{
conn->errornumber = CONN_STMT_ALLOC_ERROR; conn->errornumber = CONN_STMT_ALLOC_ERROR;
conn->errormsg = "No more memory to allocate a further SQL-statement"; conn->errormsg = "No more memory to allocate a further SQL-statement";
*phstmt = SQL_NULL_HSTMT; *phstmt = SQL_NULL_HSTMT;
@ -114,8 +89,7 @@ SQLAllocStmt(HDBC hdbc,
return SQL_ERROR; return SQL_ERROR;
} }
if (!CC_add_statement(conn, stmt)) if ( ! CC_add_statement(conn, stmt)) {
{
conn->errormsg = "Maximum number of connections exceeded."; conn->errormsg = "Maximum number of connections exceeded.";
conn->errornumber = CONN_STMT_ALLOC_ERROR; conn->errornumber = CONN_STMT_ALLOC_ERROR;
CC_log_error(func, "", conn); CC_log_error(func, "", conn);
@ -126,8 +100,7 @@ SQLAllocStmt(HDBC hdbc,
*phstmt = (HSTMT) stmt; *phstmt = (HSTMT) stmt;
/* /* Copy default statement options based from Connection options
* Copy default statement options based from Connection options
*/ */
stmt->options = conn->stmtOptions; stmt->options = conn->stmtOptions;
@ -139,8 +112,7 @@ SQLAllocStmt(HDBC hdbc,
} }
RETCODE SQL_API RETCODE SQL_API SQLFreeStmt(HSTMT hstmt,
SQLFreeStmt(HSTMT hstmt,
UWORD fOption) UWORD fOption)
{ {
static char *func="SQLFreeStmt"; static char *func="SQLFreeStmt";
@ -148,31 +120,25 @@ SQLFreeStmt(HSTMT hstmt,
mylog("%s: entering...hstmt=%u, fOption=%d\n", func, hstmt, fOption); mylog("%s: entering...hstmt=%u, fOption=%d\n", func, hstmt, fOption);
if (!stmt) if ( ! stmt) {
{
SC_log_error(func, "", NULL); SC_log_error(func, "", NULL);
return SQL_INVALID_HANDLE; return SQL_INVALID_HANDLE;
} }
if (fOption == SQL_DROP) if (fOption == SQL_DROP) {
{
ConnectionClass *conn = stmt->hdbc; ConnectionClass *conn = stmt->hdbc;
/* Remove the statement from the connection's statement list */ /* Remove the statement from the connection's statement list */
if (conn) if ( conn) {
{ if ( ! CC_remove_statement(conn, stmt)) {
if (!CC_remove_statement(conn, stmt))
{
stmt->errornumber = STMT_SEQUENCE_ERROR; stmt->errornumber = STMT_SEQUENCE_ERROR;
stmt->errormsg = "Statement is currently executing a transaction."; stmt->errormsg = "Statement is currently executing a transaction.";
SC_log_error(func, "", stmt); SC_log_error(func, "", stmt);
return SQL_ERROR; /* stmt may be executing a return SQL_ERROR; /* stmt may be executing a transaction */
* transaction */
} }
/* Free any cursors and discard any result info */ /* Free any cursors and discard any result info */
if (stmt->result) if (stmt->result) {
{
QR_Destructor(stmt->result); QR_Destructor(stmt->result);
stmt->result = NULL; stmt->result = NULL;
} }
@ -180,24 +146,23 @@ SQLFreeStmt(HSTMT hstmt,
/* Destroy the statement and free any results, cursors, etc. */ /* Destroy the statement and free any results, cursors, etc. */
SC_Destructor(stmt); SC_Destructor(stmt);
}
else if (fOption == SQL_UNBIND) } else if (fOption == SQL_UNBIND) {
SC_unbind_cols(stmt); SC_unbind_cols(stmt);
else if (fOption == SQL_CLOSE)
{ } else if (fOption == SQL_CLOSE) {
/* this should discard all the results, but leave the statement */ /* this should discard all the results, but leave the statement */
/* itself in place (it can be executed again) */ /* itself in place (it can be executed again) */
if (!SC_recycle_statement(stmt)) if (!SC_recycle_statement(stmt)) {
{
/* errormsg passed in above */ /* errormsg passed in above */
SC_log_error(func, "", stmt); SC_log_error(func, "", stmt);
return SQL_ERROR; return SQL_ERROR;
} }
}
else if (fOption == SQL_RESET_PARAMS) } else if(fOption == SQL_RESET_PARAMS) {
SC_free_params(stmt, STMT_FREE_PARAMS_ALL); SC_free_params(stmt, STMT_FREE_PARAMS_ALL);
else
{ } else {
stmt->errormsg = "Invalid option passed to SQLFreeStmt."; stmt->errormsg = "Invalid option passed to SQLFreeStmt.";
stmt->errornumber = STMT_OPTION_OUT_OF_RANGE_ERROR; stmt->errornumber = STMT_OPTION_OUT_OF_RANGE_ERROR;
SC_log_error(func, "", stmt); SC_log_error(func, "", stmt);
@ -232,8 +197,7 @@ SC_Constructor(void)
StatementClass *rv; StatementClass *rv;
rv = (StatementClass *) malloc(sizeof(StatementClass)); rv = (StatementClass *) malloc(sizeof(StatementClass));
if (rv) if (rv) {
{
rv->hdbc = NULL; /* no connection associated yet */ rv->hdbc = NULL; /* no connection associated yet */
rv->phstmt = NULL; rv->phstmt = NULL;
rv->result = NULL; rv->result = NULL;
@ -290,16 +254,15 @@ SC_Constructor(void)
char char
SC_Destructor(StatementClass *self) SC_Destructor(StatementClass *self)
{ {
mylog("SC_Destructor: self=%u, self->result=%u, self->hdbc=%u\n", self, self->result, self->hdbc); mylog("SC_Destructor: self=%u, self->result=%u, self->hdbc=%u\n", self, self->result, self->hdbc);
if (STMT_EXECUTING == self->status) if (STMT_EXECUTING == self->status) {
{
self->errornumber = STMT_SEQUENCE_ERROR; self->errornumber = STMT_SEQUENCE_ERROR;
self->errormsg = "Statement is currently executing a transaction."; self->errormsg = "Statement is currently executing a transaction.";
return FALSE; return FALSE;
} }
if (self->result) if (self->result) {
{
if ( ! self->hdbc) if ( ! self->hdbc)
self->result->conn = NULL; /* prevent any dbase activity */ self->result->conn = NULL; /* prevent any dbase activity */
@ -311,38 +274,29 @@ SC_Destructor(StatementClass *self)
SC_free_params(self, STMT_FREE_PARAMS_ALL); SC_free_params(self, STMT_FREE_PARAMS_ALL);
/* /* the memory pointed to by the bindings is not deallocated by the driver */
* the memory pointed to by the bindings is not deallocated by the /* by by the application that uses that driver, so we don't have to care */
* driver
*/
/*
* by by the application that uses that driver, so we don't have to
* care
*/
/* about that here. */ /* about that here. */
if (self->bindings) if (self->bindings)
free(self->bindings); free(self->bindings);
/* Free the parsed table information */ /* Free the parsed table information */
if (self->ti) if (self->ti) {
{
int i; int i;
for (i = 0; i < self->ntab; i++) {
for (i = 0; i < self->ntab; i++)
free(self->ti[i]); free(self->ti[i]);
}
free(self->ti); free(self->ti);
} }
/* Free the parsed field information */ /* Free the parsed field information */
if (self->fi) if (self->fi) {
{
int i; int i;
for (i = 0; i < self->nfld; i++) {
for (i = 0; i < self->nfld; i++)
free(self->fi[i]); free(self->fi[i]);
}
free(self->fi); free(self->fi);
} }
@ -367,18 +321,15 @@ SC_free_params(StatementClass *self, char option)
if( ! self->parameters) if( ! self->parameters)
return; return;
for (i = 0; i < self->parameters_allocated; i++) for (i = 0; i < self->parameters_allocated; i++) {
{ if (self->parameters[i].data_at_exec == TRUE) {
if (self->parameters[i].data_at_exec == TRUE)
{ if (self->parameters[i].EXEC_used) {
if (self->parameters[i].EXEC_used)
{
free(self->parameters[i].EXEC_used); free(self->parameters[i].EXEC_used);
self->parameters[i].EXEC_used = NULL; self->parameters[i].EXEC_used = NULL;
} }
if (self->parameters[i].EXEC_buffer) if (self->parameters[i].EXEC_buffer) {
{
if (self->parameters[i].SQLType != SQL_LONGVARBINARY) if (self->parameters[i].SQLType != SQL_LONGVARBINARY)
free(self->parameters[i].EXEC_buffer); free(self->parameters[i].EXEC_buffer);
self->parameters[i].EXEC_buffer = NULL; self->parameters[i].EXEC_buffer = NULL;
@ -389,8 +340,7 @@ SC_free_params(StatementClass *self, char option)
self->current_exec_param = -1; self->current_exec_param = -1;
self->put_data = FALSE; self->put_data = FALSE;
if (option == STMT_FREE_PARAMS_ALL) if (option == STMT_FREE_PARAMS_ALL) {
{
free(self->parameters); free(self->parameters);
self->parameters = NULL; self->parameters = NULL;
self->parameters_allocated = 0; self->parameters_allocated = 0;
@ -429,8 +379,7 @@ SC_recycle_statement(StatementClass *self)
mylog("recycle statement: self= %u\n", self); mylog("recycle statement: self= %u\n", self);
/* This would not happen */ /* This would not happen */
if (self->status == STMT_EXECUTING) if (self->status == STMT_EXECUTING) {
{
self->errornumber = STMT_SEQUENCE_ERROR; self->errornumber = STMT_SEQUENCE_ERROR;
self->errormsg = "Statement is currently executing a transaction."; self->errormsg = "Statement is currently executing a transaction.";
return FALSE; return FALSE;
@ -440,8 +389,7 @@ SC_recycle_statement(StatementClass *self)
self->errornumber = 0; self->errornumber = 0;
self->errormsg_created = FALSE; self->errormsg_created = FALSE;
switch (self->status) switch (self->status) {
{
case STMT_ALLOCATED: case STMT_ALLOCATED:
/* this statement does not need to be recycled */ /* this statement does not need to be recycled */
return TRUE; return TRUE;
@ -450,15 +398,12 @@ SC_recycle_statement(StatementClass *self)
break; break;
case STMT_PREMATURE: case STMT_PREMATURE:
/* Premature execution of the statement might have caused the start of a transaction.
/* If so, we have to rollback that transaction.
* Premature execution of the statement might have caused the
* start of a transaction. If so, we have to rollback that
* transaction.
*/ */
conn = SC_get_conn(self); conn = SC_get_conn(self);
if (!CC_is_in_autocommit(conn) && CC_is_in_trans(conn)) if ( ! CC_is_in_autocommit(conn) && CC_is_in_trans(conn)) {
{
CC_send_query(conn, "ABORT", NULL); CC_send_query(conn, "ABORT", NULL);
CC_set_no_trans(conn); CC_set_no_trans(conn);
} }
@ -474,12 +419,11 @@ SC_recycle_statement(StatementClass *self)
} }
/* Free the parsed table information */ /* Free the parsed table information */
if (self->ti) if (self->ti) {
{
int i; int i;
for (i = 0; i < self->ntab; i++) {
for (i = 0; i < self->ntab; i++)
free(self->ti[i]); free(self->ti[i]);
}
free(self->ti); free(self->ti);
self->ti = NULL; self->ti = NULL;
@ -487,12 +431,11 @@ SC_recycle_statement(StatementClass *self)
} }
/* Free the parsed field information */ /* Free the parsed field information */
if (self->fi) if (self->fi) {
{
int i; int i;
for (i = 0; i < self->nfld; i++) {
for (i = 0; i < self->nfld; i++)
free(self->fi[i]); free(self->fi[i]);
}
free(self->fi); free(self->fi);
self->fi = NULL; self->fi = NULL;
self->nfld = 0; self->nfld = 0;
@ -500,8 +443,7 @@ SC_recycle_statement(StatementClass *self)
self->parse_status = STMT_PARSE_NONE; self->parse_status = STMT_PARSE_NONE;
/* Free any cursors */ /* Free any cursors */
if (self->result) if (self->result) {
{
QR_Destructor(self->result); QR_Destructor(self->result);
self->result = NULL; self->result = NULL;
} }
@ -537,16 +479,15 @@ SC_recycle_statement(StatementClass *self)
void void
SC_pre_execute(StatementClass *self) SC_pre_execute(StatementClass *self)
{ {
mylog("SC_pre_execute: status = %d\n", self->status); mylog("SC_pre_execute: status = %d\n", self->status);
if (self->status == STMT_READY) if (self->status == STMT_READY) {
{
mylog(" preprocess: status = READY\n"); mylog(" preprocess: status = READY\n");
SQLExecute(self); SQLExecute(self);
if (self->status == STMT_FINISHED) if (self->status == STMT_FINISHED) {
{
mylog(" preprocess: after status = FINISHED, so set PREMATURE\n"); mylog(" preprocess: after status = FINISHED, so set PREMATURE\n");
self->status = STMT_PREMATURE; self->status = STMT_PREMATURE;
} }
@ -559,8 +500,7 @@ SC_unbind_cols(StatementClass *self)
{ {
Int2 lf; Int2 lf;
for (lf = 0; lf < self->bindings_allocated; lf++) for(lf = 0; lf < self->bindings_allocated; lf++) {
{
self->bindings[lf].data_left = -1; self->bindings[lf].data_left = -1;
self->bindings[lf].buflen = 0; self->bindings[lf].buflen = 0;
self->bindings[lf].buffer = NULL; self->bindings[lf].buffer = NULL;
@ -601,18 +541,15 @@ SC_create_errormsg(StatementClass *self)
else if (self->errormsg) else if (self->errormsg)
strcpy(msg, self->errormsg); strcpy(msg, self->errormsg);
if (conn) if (conn) {
{
SocketClass *sock = conn->sock; SocketClass *sock = conn->sock;
if (conn->errormsg && conn->errormsg[0] != '\0') if (conn->errormsg && conn->errormsg[0] != '\0') {
{
pos = strlen(msg); pos = strlen(msg);
sprintf(&msg[pos], ";\n%s", conn->errormsg); sprintf(&msg[pos], ";\n%s", conn->errormsg);
} }
if (sock && sock->errormsg && sock->errormsg[0] != '\0') if (sock && sock->errormsg && sock->errormsg[0] != '\0') {
{
pos = strlen(msg); pos = strlen(msg);
sprintf(&msg[pos], ";\n%s", sock->errormsg); sprintf(&msg[pos], ";\n%s", sock->errormsg);
} }
@ -627,14 +564,12 @@ SC_get_error(StatementClass *self, int *number, char **message)
char rv; char rv;
/* Create a very informative errormsg if it hasn't been done yet. */ /* Create a very informative errormsg if it hasn't been done yet. */
if (!self->errormsg_created) if ( ! self->errormsg_created) {
{
self->errormsg = SC_create_errormsg(self); self->errormsg = SC_create_errormsg(self);
self->errormsg_created = TRUE; self->errormsg_created = TRUE;
} }
if (self->errornumber) if ( self->errornumber) {
{
*number = self->errornumber; *number = self->errornumber;
*message = self->errormsg; *message = self->errormsg;
self->errormsg = NULL; self->errormsg = NULL;
@ -661,14 +596,11 @@ SC_fetch(StatementClass *self)
{ {
static char *func = "SC_fetch"; static char *func = "SC_fetch";
QResultClass *res = self->result; QResultClass *res = self->result;
int retval, int retval, result;
result; Int2 num_cols, lf;
Int2 num_cols,
lf;
Oid type; Oid type;
char *value; char *value;
ColumnInfoClass *ci; ColumnInfoClass *ci;
/* TupleField *tupleField; */ /* TupleField *tupleField; */
self->last_fetch_count = 0; self->last_fetch_count = 0;
@ -676,15 +608,13 @@ SC_fetch(StatementClass *self)
mylog("manual_result = %d, use_declarefetch = %d\n", self->manual_result, globals.use_declarefetch); mylog("manual_result = %d, use_declarefetch = %d\n", self->manual_result, globals.use_declarefetch);
if (self->manual_result || !globals.use_declarefetch) if ( self->manual_result || ! globals.use_declarefetch) {
{
if (self->currTuple >= QR_get_num_tuples(res) - 1 ||
(self->options.maxRows > 0 && self->currTuple == self->options.maxRows - 1))
{
/* if (self->currTuple >= QR_get_num_tuples(res) -1 ||
* if at the end of the tuples, return "no data found" and set (self->options.maxRows > 0 && self->currTuple == self->options.maxRows - 1)) {
* the cursor past the end of the result set
/* if at the end of the tuples, return "no data found"
and set the cursor past the end of the result set
*/ */
self->currTuple = QR_get_num_tuples(res); self->currTuple = QR_get_num_tuples(res);
return SQL_NO_DATA_FOUND; return SQL_NO_DATA_FOUND;
@ -693,20 +623,18 @@ SC_fetch(StatementClass *self)
mylog("**** SQLFetch: manual_result\n"); mylog("**** SQLFetch: manual_result\n");
(self->currTuple)++; (self->currTuple)++;
} }
else else {
{
/* read from the cache or the physical next tuple */ /* read from the cache or the physical next tuple */
retval = QR_next_tuple(res); retval = QR_next_tuple(res);
if (retval < 0) if (retval < 0) {
{
mylog("**** SQLFetch: end_tuples\n"); mylog("**** SQLFetch: end_tuples\n");
return SQL_NO_DATA_FOUND; return SQL_NO_DATA_FOUND;
} }
else if (retval > 0) else if (retval > 0)
(self->currTuple)++; /* all is well */ (self->currTuple)++; /* all is well */
else else {
{
mylog("SQLFetch: error\n"); mylog("SQLFetch: error\n");
self->errornumber = STMT_EXEC_ERROR; self->errornumber = STMT_EXEC_ERROR;
self->errormsg = "Error fetching next row"; self->errormsg = "Error fetching next row";
@ -720,14 +648,12 @@ SC_fetch(StatementClass *self)
result = SQL_SUCCESS; result = SQL_SUCCESS;
self->last_fetch_count = 1; self->last_fetch_count = 1;
/* /* If the bookmark column was bound then return a bookmark.
* If the bookmark column was bound then return a bookmark. Since this Since this is used with SQLExtendedFetch, and the rowset size
* is used with SQLExtendedFetch, and the rowset size may be greater may be greater than 1, and an application can use row or column wise
* than 1, and an application can use row or column wise binding, use binding, use the code in copy_and_convert_field() to handle that.
* the code in copy_and_convert_field() to handle that.
*/ */
if (self->bookmark.buffer) if (self->bookmark.buffer) {
{
char buf[32]; char buf[32];
sprintf(buf, "%ld", SC_get_bookmark(self)); sprintf(buf, "%ld", SC_get_bookmark(self));
@ -735,15 +661,14 @@ SC_fetch(StatementClass *self)
SQL_C_ULONG, self->bookmark.buffer, 0, self->bookmark.used); SQL_C_ULONG, self->bookmark.buffer, 0, self->bookmark.used);
} }
for (lf = 0; lf < num_cols; lf++) for (lf=0; lf < num_cols; lf++) {
{
mylog("fetch: cols=%d, lf=%d, self = %u, self->bindings = %u, buffer[] = %u\n", num_cols, lf, self, self->bindings, self->bindings[lf].buffer); mylog("fetch: cols=%d, lf=%d, self = %u, self->bindings = %u, buffer[] = %u\n", num_cols, lf, self, self->bindings, self->bindings[lf].buffer);
/* reset for SQLGetData */ /* reset for SQLGetData */
self->bindings[lf].data_left = -1; self->bindings[lf].data_left = -1;
if (self->bindings[lf].buffer != NULL) if (self->bindings[lf].buffer != NULL) {
{
/* this column has a binding */ /* this column has a binding */
/* type = QR_get_field_type(res, lf); */ /* type = QR_get_field_type(res, lf); */
@ -751,15 +676,15 @@ SC_fetch(StatementClass *self)
mylog("type = %d\n", type); mylog("type = %d\n", type);
if (self->manual_result) if (self->manual_result) {
{
value = QR_get_value_manual(res, self->currTuple, lf); value = QR_get_value_manual(res, self->currTuple, lf);
mylog("manual_result\n"); mylog("manual_result\n");
} }
else if (globals.use_declarefetch) else if (globals.use_declarefetch)
value = QR_get_value_backend(res, lf); value = QR_get_value_backend(res, lf);
else else {
value = QR_get_value_backend_row(res, self->currTuple, lf); value = QR_get_value_backend_row(res, self->currTuple, lf);
}
mylog("value = '%s'\n", (value==NULL)?"<NULL>":value); mylog("value = '%s'\n", (value==NULL)?"<NULL>":value);
@ -767,8 +692,7 @@ SC_fetch(StatementClass *self)
mylog("copy_and_convert: retval = %d\n", retval); mylog("copy_and_convert: retval = %d\n", retval);
switch (retval) switch(retval) {
{
case COPY_OK: case COPY_OK:
break; /* OK, do next bound column */ break; /* OK, do next bound column */
@ -792,8 +716,7 @@ SC_fetch(StatementClass *self)
result = SQL_SUCCESS_WITH_INFO; result = SQL_SUCCESS_WITH_INFO;
break; break;
case COPY_GENERAL_ERROR: /* error msg already case COPY_GENERAL_ERROR: /* error msg already filled in */
* filled in */
SC_log_error(func, "", self); SC_log_error(func, "", self);
result = SQL_ERROR; result = SQL_ERROR;
break; break;
@ -816,39 +739,35 @@ SC_fetch(StatementClass *self)
} }
RETCODE RETCODE SC_execute(StatementClass *self)
SC_execute(StatementClass *self)
{ {
static char *func="SC_execute"; static char *func="SC_execute";
ConnectionClass *conn; ConnectionClass *conn;
QResultClass *res; QResultClass *res;
char ok, char ok, was_ok, was_nonfatal;
was_ok, Int2 oldstatus, numcols;
was_nonfatal;
Int2 oldstatus,
numcols;
QueryInfo qi; QueryInfo qi;
conn = SC_get_conn(self); conn = SC_get_conn(self);
/* Begin a transaction if one is not already in progress */ /* Begin a transaction if one is not already in progress */
/* /*
* Basically we don't have to begin a transaction in autocommit mode Basically we don't have to begin a transaction in
* because Postgres backend runs in autocomit mode. We issue "BEGIN" autocommit mode because Postgres backend runs in
* in the following cases. 1) we use declare/fetch and the statement autocomit mode.
* is SELECT (because declare/fetch must be called in a transaction). We issue "BEGIN" in the following cases.
* 2) we are not in autocommit state and the statement is of type 1) we use declare/fetch and the statement is SELECT
* UPDATE. (because declare/fetch must be called in a transaction).
2) we are not in autocommit state and the statement
is of type UPDATE.
*/ */
if ( ! self->internal && ! CC_is_in_trans(conn) && if ( ! self->internal && ! CC_is_in_trans(conn) &&
((globals.use_declarefetch && self->statement_type == STMT_TYPE_SELECT) || (!CC_is_in_autocommit(conn) && STMT_UPDATE(self)))) ((globals.use_declarefetch && self->statement_type == STMT_TYPE_SELECT) || (! CC_is_in_autocommit(conn) && STMT_UPDATE(self)))) {
{
mylog(" about to begin a transaction on statement = %u\n", self); mylog(" about to begin a transaction on statement = %u\n", self);
res = CC_send_query(conn, "BEGIN", NULL); res = CC_send_query(conn, "BEGIN", NULL);
if (!res) if ( ! res) {
{
self->errormsg = "Could not begin a transaction"; self->errormsg = "Could not begin a transaction";
self->errornumber = STMT_EXEC_ERROR; self->errornumber = STMT_EXEC_ERROR;
SC_log_error(func, "", self); SC_log_error(func, "", self);
@ -861,8 +780,7 @@ SC_execute(StatementClass *self)
QR_Destructor(res); QR_Destructor(res);
if (!ok) if (!ok) {
{
self->errormsg = "Could not begin a transaction"; self->errormsg = "Could not begin a transaction";
self->errornumber = STMT_EXEC_ERROR; self->errornumber = STMT_EXEC_ERROR;
SC_log_error(func, "", self); SC_log_error(func, "", self);
@ -872,20 +790,18 @@ SC_execute(StatementClass *self)
CC_set_in_trans(conn); CC_set_in_trans(conn);
} }
oldstatus = conn->status; oldstatus = conn->status;
conn->status = CONN_EXECUTING; conn->status = CONN_EXECUTING;
self->status = STMT_EXECUTING; self->status = STMT_EXECUTING;
/* If it's a SELECT statement, use a cursor. */ /* If it's a SELECT statement, use a cursor. */
/* Note that the declare cursor has already been prepended to the statement */
/*
* Note that the declare cursor has already been prepended to the
* statement
*/
/* in copy_statement... */ /* in copy_statement... */
if (self->statement_type == STMT_TYPE_SELECT) if (self->statement_type == STMT_TYPE_SELECT) {
{
char fetch[128]; char fetch[128];
mylog(" Sending SELECT statement on stmt=%u, cursor_name='%s'\n", self, self->cursor_name); mylog(" Sending SELECT statement on stmt=%u, cursor_name='%s'\n", self, self->cursor_name);
@ -895,61 +811,55 @@ SC_execute(StatementClass *self)
self->result = CC_send_query(conn, self->stmt_with_params, NULL); self->result = CC_send_query(conn, self->stmt_with_params, NULL);
if (globals.use_declarefetch && self->result != NULL && if (globals.use_declarefetch && self->result != NULL &&
QR_command_successful(self->result)) QR_command_successful(self->result)) {
{
QR_Destructor(self->result); QR_Destructor(self->result);
/* /* That worked, so now send the fetch to start getting data back */
* That worked, so now send the fetch to start getting data
* back
*/
qi.result_in = NULL; qi.result_in = NULL;
qi.cursor = self->cursor_name; qi.cursor = self->cursor_name;
qi.row_size = globals.fetch_max; qi.row_size = globals.fetch_max;
/* /* Most likely the rowset size will not be set by the application until
* Most likely the rowset size will not be set by the after the statement is executed, so might as well use the cache size.
* application until after the statement is executed, so might The qr_next_tuple() function will correct for any discrepancies in
* as well use the cache size. The qr_next_tuple() function sizes and adjust the cache accordingly.
* will correct for any discrepancies in sizes and adjust the
* cache accordingly.
*/ */
sprintf(fetch, "fetch %d in %s", qi.row_size, self->cursor_name); sprintf(fetch, "fetch %d in %s", qi.row_size, self->cursor_name);
self->result = CC_send_query( conn, fetch, &qi); self->result = CC_send_query( conn, fetch, &qi);
} }
mylog(" done sending the query:\n"); mylog(" done sending the query:\n");
} }
else else { /* not a SELECT statement so don't use a cursor */
{ /* not a SELECT statement so don't use a
* cursor */
mylog(" it's NOT a select statement: stmt=%u\n", self); mylog(" it's NOT a select statement: stmt=%u\n", self);
self->result = CC_send_query(conn, self->stmt_with_params, NULL); self->result = CC_send_query(conn, self->stmt_with_params, NULL);
/* /* We shouldn't send COMMIT. Postgres backend does the
* We shouldn't send COMMIT. Postgres backend does the autocommit autocommit if neccessary. (Zoltan, 04/26/2000)
* if neccessary. (Zoltan, 04/26/2000)
*/ */
/* Even in case of autocommit, started transactions
/* must be committed. (Hiroshi, 09/02/2001)
* Even in case of autocommit, started transactions must be
* committed. (Hiroshi, 09/02/2001)
*/ */
if (!self->internal && CC_is_in_autocommit(conn) && CC_is_in_trans(conn) && STMT_UPDATE(self)) if ( ! self->internal && CC_is_in_autocommit(conn) && CC_is_in_trans(conn) && STMT_UPDATE(self)) {
{
res = CC_send_query(conn, "COMMIT", NULL); res = CC_send_query(conn, "COMMIT", NULL);
QR_Destructor(res); QR_Destructor(res);
CC_set_no_trans(conn); CC_set_no_trans(conn);
} }
} }
conn->status = oldstatus; conn->status = oldstatus;
self->status = STMT_FINISHED; self->status = STMT_FINISHED;
/* Check the status of the result */ /* Check the status of the result */
if (self->result) if (self->result) {
{
was_ok = QR_command_successful(self->result); was_ok = QR_command_successful(self->result);
was_nonfatal = QR_command_nonfatal(self->result); was_nonfatal = QR_command_nonfatal(self->result);
@ -958,8 +868,7 @@ SC_execute(StatementClass *self)
else else
self->errornumber = was_nonfatal ? STMT_INFO_ONLY : STMT_ERROR_TAKEN_FROM_BACKEND; self->errornumber = was_nonfatal ? STMT_INFO_ONLY : STMT_ERROR_TAKEN_FROM_BACKEND;
self->currTuple = -1; /* set cursor before the first tuple in self->currTuple = -1; /* set cursor before the first tuple in the list */
* the list */
self->current_col = -1; self->current_col = -1;
self->rowset_start = -1; self->rowset_start = -1;
@ -967,11 +876,9 @@ SC_execute(StatementClass *self)
numcols = QR_NumResultCols(self->result); numcols = QR_NumResultCols(self->result);
/* now allocate the array to hold the binding info */ /* now allocate the array to hold the binding info */
if (numcols > 0) if (numcols > 0) {
{
extend_bindings(self, numcols); extend_bindings(self, numcols);
if (self->bindings == NULL) if (self->bindings == NULL) {
{
self->errornumber = STMT_NO_MEMORY_ERROR; self->errornumber = STMT_NO_MEMORY_ERROR;
self->errormsg = "Could not get enough free memory to store the binding information"; self->errormsg = "Could not get enough free memory to store the binding information";
SC_log_error(func, "", self); SC_log_error(func, "", self);
@ -981,25 +888,18 @@ SC_execute(StatementClass *self)
/* in autocommit mode declare/fetch error must be aborted */ /* in autocommit mode declare/fetch error must be aborted */
if ( ! was_ok && ! self->internal && CC_is_in_autocommit(conn) && CC_is_in_trans(conn)) if ( ! was_ok && ! self->internal && CC_is_in_autocommit(conn) && CC_is_in_trans(conn))
CC_abort(conn); CC_abort(conn);
} } else { /* Bad Error -- The error message will be in the Connection */
else
{ /* Bad Error -- The error message will be
* in the Connection */
if (self->statement_type == STMT_TYPE_CREATE) if (self->statement_type == STMT_TYPE_CREATE) {
{
self->errornumber = STMT_CREATE_TABLE_ERROR; self->errornumber = STMT_CREATE_TABLE_ERROR;
self->errormsg = "Error creating the table"; self->errormsg = "Error creating the table";
/* This would allow the table to already exists, thus appending
/* rows to it. BUT, if the table didn't have the same attributes,
* This would allow the table to already exists, thus it would fail.
* appending rows to it. BUT, if the table didn't have the return SQL_SUCCESS_WITH_INFO;
* same attributes, it would fail. return
* SQL_SUCCESS_WITH_INFO;
*/ */
} }
else else {
{
self->errornumber = STMT_EXEC_ERROR; self->errornumber = STMT_EXEC_ERROR;
self->errormsg = "Error while executing the query"; self->errormsg = "Error while executing the query";
} }
@ -1011,8 +911,7 @@ SC_execute(StatementClass *self)
if (self->errornumber == STMT_OK) if (self->errornumber == STMT_OK)
return SQL_SUCCESS; return SQL_SUCCESS;
else else {
{
/* Modified, 2000-04-29, Zoltan */ /* Modified, 2000-04-29, Zoltan */
if (self->errornumber == STMT_INFO_ONLY) if (self->errornumber == STMT_INFO_ONLY)
self->errormsg = "Error while executing the query (non-fatal)"; self->errormsg = "Error while executing the query (non-fatal)";
@ -1029,8 +928,7 @@ SC_log_error(char *func, char *desc, StatementClass *self)
#ifdef PRN_NULLCHECK #ifdef PRN_NULLCHECK
#define nullcheck(a) (a ? a : "(NULL)") #define nullcheck(a) (a ? a : "(NULL)")
#endif #endif
if (self) if (self) {
{
qlog("STATEMENT ERROR: func=%s, desc='%s', errnum=%d, errmsg='%s'\n", func, desc, self->errornumber, nullcheck(self->errormsg)); qlog("STATEMENT ERROR: func=%s, desc='%s', errnum=%d, errmsg='%s'\n", func, desc, self->errornumber, nullcheck(self->errormsg));
mylog("STATEMENT ERROR: func=%s, desc='%s', errnum=%d, errmsg='%s'\n", func, desc, self->errornumber, nullcheck(self->errormsg)); mylog("STATEMENT ERROR: func=%s, desc='%s', errnum=%d, errmsg='%s'\n", func, desc, self->errornumber, nullcheck(self->errormsg));
qlog(" ------------------------------------------------------------\n"); qlog(" ------------------------------------------------------------\n");
@ -1047,10 +945,8 @@ SC_log_error(char *func, char *desc, StatementClass *self)
qlog(" ----------------QResult Info -------------------------------\n"); qlog(" ----------------QResult Info -------------------------------\n");
if (self->result) if (self->result) {
{
QResultClass *res = self->result; QResultClass *res = self->result;
qlog(" fields=%u, manual_tuples=%u, backend_tuples=%u, tupleField=%d, conn=%u\n", res->fields, res->manual_tuples, res->backend_tuples, res->tupleField, res->conn); qlog(" fields=%u, manual_tuples=%u, backend_tuples=%u, tupleField=%d, conn=%u\n", res->fields, res->manual_tuples, res->backend_tuples, res->tupleField, res->conn);
qlog(" fetch_count=%d, fcount=%d, num_fields=%d, cursor='%s'\n", res->fetch_count, res->fcount, res->num_fields, nullcheck(res->cursor)); qlog(" fetch_count=%d, fcount=%d, num_fields=%d, cursor='%s'\n", res->fetch_count, res->fcount, res->num_fields, nullcheck(res->cursor));
qlog(" message='%s', command='%s', notice='%s'\n", nullcheck(res->message), nullcheck(res->command), nullcheck(res->notice)); qlog(" message='%s', command='%s', notice='%s'\n", nullcheck(res->message), nullcheck(res->command), nullcheck(res->notice));
@ -1064,3 +960,4 @@ SC_log_error(char *func, char *desc, StatementClass *self)
qlog("INVALID STATEMENT HANDLE ERROR: func=%s, desc='%s'\n", func, desc); qlog("INVALID STATEMENT HANDLE ERROR: func=%s, desc='%s'\n", func, desc);
#undef PRN_NULLCHECK #undef PRN_NULLCHECK
} }

@ -33,28 +33,21 @@
#define TRUE (BOOL)1 #define TRUE (BOOL)1
#endif #endif
typedef enum typedef enum {
{ STMT_ALLOCATED, /* The statement handle is allocated, but not used so far */
STMT_ALLOCATED, /* The statement handle is allocated, but
* not used so far */
STMT_READY, /* the statement is waiting to be executed */ STMT_READY, /* the statement is waiting to be executed */
STMT_PREMATURE, /* ODBC states that it is legal to call STMT_PREMATURE, /* ODBC states that it is legal to call e.g. SQLDescribeCol before
* e.g. SQLDescribeCol before a call to a call to SQLExecute, but after SQLPrepare. To get all the necessary
* SQLExecute, but after SQLPrepare. To information in such a case, we simply execute the query _before_ the
* get all the necessary information in actual call to SQLExecute, so that statement is considered to be "premature".
* such a case, we simply execute the */
* query _before_ the actual call to
* SQLExecute, so that statement is
* considered to be "premature". */
STMT_FINISHED, /* statement execution has finished */ STMT_FINISHED, /* statement execution has finished */
STMT_EXECUTING /* statement execution is still going on */ STMT_EXECUTING /* statement execution is still going on */
} STMT_Status; } STMT_Status;
#define STMT_TRUNCATED (-2) #define STMT_TRUNCATED -2
#define STMT_INFO_ONLY (-1) /* not an error message, just a #define STMT_INFO_ONLY -1 /* not an error message, just a notification to be returned by SQLError */
* notification to be returned by SQLError */ #define STMT_OK 0 /* will be interpreted as "no error pending" */
#define STMT_OK 0 /* will be interpreted as "no error
* pending" */
#define STMT_EXEC_ERROR 1 #define STMT_EXEC_ERROR 1
#define STMT_STATUS_ERROR 2 #define STMT_STATUS_ERROR 2
#define STMT_SEQUENCE_ERROR 3 #define STMT_SEQUENCE_ERROR 3
@ -84,8 +77,7 @@ typedef enum
#define STMT_BAD_ERROR 27 #define STMT_BAD_ERROR 27
/* statement types */ /* statement types */
enum enum {
{
STMT_TYPE_UNKNOWN = -2, STMT_TYPE_UNKNOWN = -2,
STMT_TYPE_OTHER = -1, STMT_TYPE_OTHER = -1,
STMT_TYPE_SELECT = 0, STMT_TYPE_SELECT = 0,
@ -103,8 +95,7 @@ enum
/* Parsing status */ /* Parsing status */
enum enum {
{
STMT_PARSE_NONE = 0, STMT_PARSE_NONE = 0,
STMT_PARSE_COMPLETE, STMT_PARSE_COMPLETE,
STMT_PARSE_INCOMPLETE, STMT_PARSE_INCOMPLETE,
@ -112,22 +103,19 @@ enum
}; };
/* Result style */ /* Result style */
enum enum {
{
STMT_FETCH_NONE = 0, STMT_FETCH_NONE = 0,
STMT_FETCH_NORMAL, STMT_FETCH_NORMAL,
STMT_FETCH_EXTENDED, STMT_FETCH_EXTENDED,
}; };
typedef struct typedef struct {
{
COL_INFO *col_info; /* cached SQLColumns info for this table */ COL_INFO *col_info; /* cached SQLColumns info for this table */
char name[MAX_TABLE_LEN+1]; char name[MAX_TABLE_LEN+1];
char alias[MAX_TABLE_LEN+1]; char alias[MAX_TABLE_LEN+1];
} TABLE_INFO; } TABLE_INFO;
typedef struct typedef struct {
{
TABLE_INFO *ti; /* resolve to explicit table names */ TABLE_INFO *ti; /* resolve to explicit table names */
int precision; int precision;
int display_size; int display_size;
@ -146,10 +134,8 @@ typedef struct
/******** Statement Handle ***********/ /******** Statement Handle ***********/
struct StatementClass_ struct StatementClass_ {
{ ConnectionClass *hdbc; /* pointer to ConnectionClass this statement belongs to */
ConnectionClass *hdbc; /* pointer to ConnectionClass this
* statement belongs to */
QResultClass *result; /* result of the current statement */ QResultClass *result; /* result of the current statement */
HSTMT FAR *phstmt; HSTMT FAR *phstmt;
StatementOptions options; StatementOptions options;
@ -167,22 +153,15 @@ struct StatementClass_
int parameters_allocated; int parameters_allocated;
ParameterInfoClass *parameters; ParameterInfoClass *parameters;
Int4 currTuple; /* current absolute row number (GetData, Int4 currTuple; /* current absolute row number (GetData, SetPos, SQLFetch) */
* SetPos, SQLFetch) */ int save_rowset_size; /* saved rowset size in case of change/FETCH_NEXT */
int save_rowset_size; /* saved rowset size in case of int rowset_start; /* start of rowset (an absolute row number) */
* change/FETCH_NEXT */ int bind_row; /* current offset for Multiple row/column binding */
int rowset_start; /* start of rowset (an absolute row int last_fetch_count; /* number of rows retrieved in last fetch/extended fetch */
* number) */ int current_col; /* current column for GetData -- used to handle multiple calls */
int bind_row; /* current offset for Multiple row/column
* binding */
int last_fetch_count; /* number of rows retrieved in
* last fetch/extended fetch */
int current_col; /* current column for GetData -- used to
* handle multiple calls */
int lobj_fd; /* fd of the current large object */ int lobj_fd; /* fd of the current large object */
char *statement; /* if non--null pointer to the SQL char *statement; /* if non--null pointer to the SQL statement that has been executed */
* statement that has been executed */
TABLE_INFO **ti; TABLE_INFO **ti;
FIELD_INFO **fi; FIELD_INFO **fi;
@ -193,25 +172,19 @@ struct StatementClass_
int statement_type; /* According to the defines above */ int statement_type; /* According to the defines above */
int data_at_exec; /* Number of params needing SQLPutData */ int data_at_exec; /* Number of params needing SQLPutData */
int current_exec_param; /* The current parameter for int current_exec_param; /* The current parameter for SQLPutData */
* SQLPutData */
char put_data; /* Has SQLPutData been called yet? */ char put_data; /* Has SQLPutData been called yet? */
char errormsg_created; /* has an informative error msg char errormsg_created; /* has an informative error msg been created? */
* been created? */
char manual_result; /* Is the statement result manually built? */ char manual_result; /* Is the statement result manually built? */
char prepare; /* is this statement a prepared statement char prepare; /* is this statement a prepared statement or direct */
* or direct */
char internal; /* Is this statement being called char internal; /* Is this statement being called internally? */
* internally? */
char cursor_name[MAX_CURSOR_LEN+1]; char cursor_name[MAX_CURSOR_LEN+1];
char stmt_with_params[STD_STATEMENT_LEN]; /* statement after char stmt_with_params[STD_STATEMENT_LEN]; /* statement after parameter substitution */
* parameter
* substitution */
}; };

@ -1,3 +1,4 @@
/* Module: tuple.c /* Module: tuple.c
* *
* Description: This module contains functions for setting the data for individual * Description: This module contains functions for setting the data for individual
@ -18,15 +19,13 @@
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
void void set_tuplefield_null(TupleField *tuple_field)
set_tuplefield_null(TupleField *tuple_field)
{ {
tuple_field->len = 0; tuple_field->len = 0;
tuple_field->value = NULL; /* strdup(""); */ tuple_field->value = NULL; /* strdup(""); */
} }
void void set_tuplefield_string(TupleField *tuple_field, char *string)
set_tuplefield_string(TupleField *tuple_field, char *string)
{ {
tuple_field->len = strlen(string); tuple_field->len = strlen(string);
tuple_field->value = malloc(strlen(string)+1); tuple_field->value = malloc(strlen(string)+1);
@ -34,8 +33,7 @@ set_tuplefield_string(TupleField *tuple_field, char *string)
} }
void void set_tuplefield_int2(TupleField *tuple_field, Int2 value)
set_tuplefield_int2(TupleField *tuple_field, Int2 value)
{ {
char buffer[10]; char buffer[10];
@ -47,8 +45,7 @@ set_tuplefield_int2(TupleField *tuple_field, Int2 value)
tuple_field->value = strdup(buffer); tuple_field->value = strdup(buffer);
} }
void void set_tuplefield_int4(TupleField *tuple_field, Int4 value)
set_tuplefield_int4(TupleField *tuple_field, Int4 value)
{ {
char buffer[15]; char buffer[15];

@ -17,17 +17,14 @@
#include "psqlodbc.h" #include "psqlodbc.h"
/* Used by backend data AND manual result sets */ /* Used by backend data AND manual result sets */
struct TupleField_ struct TupleField_ {
{
Int4 len; /* length of the current Tuple */ Int4 len; /* length of the current Tuple */
void *value; /* an array representing the value */ void *value; /* an array representing the value */
}; };
/* Used ONLY for manual result sets */ /* Used ONLY for manual result sets */
struct TupleNode_ struct TupleNode_ {
{ struct TupleNode_ *prev, *next;
struct TupleNode_ *prev,
*next;
TupleField tuple[1]; TupleField tuple[1];
}; };

@ -1,3 +1,4 @@
/* Module: tuplelist.c /* Module: tuplelist.c
* *
* Description: This module contains functions for creating a manual result set * Description: This module contains functions for creating a manual result set
@ -23,8 +24,8 @@ TL_Constructor(UInt4 fieldcnt)
mylog("in TL_Constructor\n"); mylog("in TL_Constructor\n");
rv = (TupleListClass *) malloc(sizeof(TupleListClass)); rv = (TupleListClass *) malloc(sizeof(TupleListClass));
if (rv) if (rv) {
{
rv->num_fields = fieldcnt; rv->num_fields = fieldcnt;
rv->num_tuples = 0; rv->num_tuples = 0;
rv->list_start = NULL; rv->list_start = NULL;
@ -42,17 +43,16 @@ void
TL_Destructor(TupleListClass *self) TL_Destructor(TupleListClass *self)
{ {
int lf; int lf;
TupleNode *node, TupleNode *node, *tp;
*tp;
mylog("TupleList: in DESTRUCTOR\n"); mylog("TupleList: in DESTRUCTOR\n");
node = self->list_start; node = self->list_start;
while (node != NULL) while(node != NULL) {
{
for (lf=0; lf < self->num_fields; lf++) for (lf=0; lf < self->num_fields; lf++)
if (node->tuple[lf].value != NULL) if (node->tuple[lf].value != NULL) {
free(node->tuple[lf].value); free(node->tuple[lf].value);
}
tp = node->next; tp = node->next;
free(node); free(node);
node = tp; node = tp;
@ -68,10 +68,8 @@ void *
TL_get_fieldval(TupleListClass *self, Int4 tupleno, Int2 fieldno) TL_get_fieldval(TupleListClass *self, Int4 tupleno, Int2 fieldno)
{ {
Int4 lf; Int4 lf;
Int4 delta, Int4 delta, from_end;
from_end; char end_is_closer, start_is_closer;
char end_is_closer,
start_is_closer;
TupleNode *rv; TupleNode *rv;
if (self->last_indexed == -1) if (self->last_indexed == -1)
@ -87,10 +85,9 @@ TL_get_fieldval(TupleListClass *self, Int4 tupleno, Int2 fieldno)
/* illegel field number range */ /* illegel field number range */
return NULL; return NULL;
/* /* check if we are accessing the same tuple that was used in
* check if we are accessing the same tuple that was used in the last the last fetch (e.g: for fetching all the fields one after
* fetch (e.g: for fetching all the fields one after another. Do this another. Do this to speed things up
* to speed things up
*/ */
if (tupleno == self->last_indexed) if (tupleno == self->last_indexed)
return self->lastref->tuple[fieldno].value; return self->lastref->tuple[fieldno].value;
@ -98,76 +95,56 @@ TL_get_fieldval(TupleListClass *self, Int4 tupleno, Int2 fieldno)
/* now for the tricky part... */ /* now for the tricky part... */
/* /*
* Since random access is quite inefficient for linked lists we use Since random access is quite inefficient for linked lists we use
* the lastref pointer that points to the last element referenced by a the lastref pointer that points to the last element referenced
* get_fieldval() call in conjunction with the its index number that by a get_fieldval() call in conjunction with the its index number
* is stored in last_indexed. (So we use some locality of reference that is stored in last_indexed. (So we use some locality of
* principle to speed things up) reference principle to speed things up)
*/ */
delta = tupleno - self->last_indexed; delta = tupleno - self->last_indexed;
/* if delta is positive, we have to go forward */ /* if delta is positive, we have to go forward */
/* /* now check if we are closer to the start or the end of the list
* now check if we are closer to the start or the end of the list than than to our last_indexed pointer
* to our last_indexed pointer
*/ */
from_end = (self->num_tuples - 1) - tupleno; from_end = (self->num_tuples - 1) - tupleno;
start_is_closer = labs(delta) > tupleno; start_is_closer = labs(delta) > tupleno;
/* true if we are closer to the start of the list than to the
/* last_indexed pointer
* true if we are closer to the start of the list than to the
* last_indexed pointer
*/ */
end_is_closer = labs(delta) > from_end; end_is_closer = labs(delta) > from_end;
/* true if we are closer at the end of the list */ /* true if we are closer at the end of the list */
if (end_is_closer) if (end_is_closer) {
{
/* scanning from the end is the shortest way. so we do that... */ /* scanning from the end is the shortest way. so we do that... */
rv = self->list_end; rv = self->list_end;
for (lf=0; lf < from_end; lf++) for (lf=0; lf < from_end; lf++)
rv = rv->prev; rv = rv->prev;
} } else if (start_is_closer) {
else if (start_is_closer) /* the shortest way is to start the search from the head of the list */
{
/*
* the shortest way is to start the search from the head of the
* list
*/
rv = self->list_start; rv = self->list_start;
for (lf=0; lf < tupleno; lf++) for (lf=0; lf < tupleno; lf++)
rv = rv->next; rv = rv->next;
} } else {
else
{
/* the closest way is starting from our lastref - pointer */ /* the closest way is starting from our lastref - pointer */
rv = self->lastref; rv = self->lastref;
/* at first determine whether we have to search forward or backwards */
/* if (delta < 0) {
* at first determine whether we have to search forward or
* backwards
*/
if (delta < 0)
{
/* we have to search backwards */ /* we have to search backwards */
for(lf=0; lf < (-1)*delta; lf++) for(lf=0; lf < (-1)*delta; lf++)
rv = rv->prev; rv = rv->prev;
} } else {
else
{
/* ok, we have to search forward... */ /* ok, we have to search forward... */
for (lf=0; lf < delta; lf++) for (lf=0; lf < delta; lf++)
rv = rv->next; rv = rv->next;
} }
} }
/* /* now we have got our return pointer, so update the lastref
* now we have got our return pointer, so update the lastref and the and the last_indexed values
* last_indexed values
*/ */
self->lastref = rv; self->lastref = rv;
self->last_indexed = tupleno; self->last_indexed = tupleno;
@ -180,29 +157,22 @@ TL_get_fieldval(TupleListClass *self, Int4 tupleno, Int2 fieldno)
char char
TL_add_tuple(TupleListClass *self, TupleNode *new_field) TL_add_tuple(TupleListClass *self, TupleNode *new_field)
{ {
/* we append the tuple at the end of the doubly linked list
/* of the tuples we have already read in
* we append the tuple at the end of the doubly linked list of the
* tuples we have already read in
*/ */
new_field->prev = NULL; new_field->prev = NULL;
new_field->next = NULL; new_field->next = NULL;
if (self->list_start == NULL) if (self->list_start == NULL) {
{
/* the list is empty, we have to add the first tuple */ /* the list is empty, we have to add the first tuple */
self->list_start = new_field; self->list_start = new_field;
self->list_end = new_field; self->list_end = new_field;
self->lastref = new_field; self->lastref = new_field;
self->last_indexed = 0; self->last_indexed = 0;
} } else {
else /* there is already an element in the list, so add the new
{ one at the end of the list
/*
* there is already an element in the list, so add the new one at
* the end of the list
*/ */
self->list_end->next = new_field; self->list_end->next = new_field;
new_field->prev = self->list_end; new_field->prev = self->list_end;
@ -213,3 +183,5 @@ TL_add_tuple(TupleListClass *self, TupleNode *new_field)
/* this method of building a list cannot fail, so we return 1 */ /* this method of building a list cannot fail, so we return 1 */
return 1; return 1;
} }

@ -15,13 +15,10 @@
#include "psqlodbc.h" #include "psqlodbc.h"
struct TupleListClass_ struct TupleListClass_ {
{
Int4 num_fields; Int4 num_fields;
Int4 num_tuples; Int4 num_tuples;
TupleNode *list_start, TupleNode *list_start, *list_end, *lastref;
*list_end,
*lastref;
Int4 last_indexed; Int4 last_indexed;
}; };