diff options
author | Marc G. Fournier | 2002-08-22 22:43:14 +0000 |
---|---|---|
committer | Marc G. Fournier | 2002-08-22 22:43:14 +0000 |
commit | 5a303f878ecd597c1524f7cb0b844d17cb9da266 (patch) | |
tree | ba28968f533df8a53f8759ee73b40efb9b44140a /src/interfaces | |
parent | 03a7625a3a1d7adb9a49295d7447a0e3d224845d (diff) |
Remove all traces of the ODBC driver, which is now on GBorg as the psqlodbc
project ...
Diffstat (limited to 'src/interfaces')
81 files changed, 2 insertions, 39755 deletions
diff --git a/src/interfaces/Makefile b/src/interfaces/Makefile index 8fa11e0aff9..113670bbebf 100644 --- a/src/interfaces/Makefile +++ b/src/interfaces/Makefile @@ -4,7 +4,7 @@ # # Copyright (c) 1994, Regents of the University of California # -# $Header: /cvsroot/pgsql/src/interfaces/Makefile,v 1.46 2002/08/22 00:15:10 scrappy Exp $ +# $Header: /cvsroot/pgsql/src/interfaces/Makefile,v 1.47 2002/08/22 22:43:11 scrappy Exp $ # #------------------------------------------------------------------------- @@ -14,11 +14,7 @@ include $(top_builddir)/src/Makefile.global DIRS := libpq ecpg libpgeasy -ALLDIRS := $(DIRS) odbc libpgtcl perl5 python jdbc - -ifeq ($(enable_odbc), yes) -DIRS += odbc -endif +ALLDIRS := $(DIRS) libpgtcl perl5 python jdbc ifeq ($(with_tcl), yes) DIRS += libpgtcl diff --git a/src/interfaces/odbc/GNUmakefile b/src/interfaces/odbc/GNUmakefile deleted file mode 100644 index 8d62f9079a2..00000000000 --- a/src/interfaces/odbc/GNUmakefile +++ /dev/null @@ -1,72 +0,0 @@ -#------------------------------------------------------------------------- -# -# GNUMakefile for psqlodbc (Postgres ODBC driver) -# -# $Header: /cvsroot/pgsql/src/interfaces/odbc/Attic/GNUmakefile,v 1.23 2001/11/12 00:54:28 inoue Exp $ -# -#------------------------------------------------------------------------- - -subdir = src/interfaces/odbc -top_builddir = ../../.. -include $(top_builddir)/src/Makefile.global - -# Shared library parameters -ifeq ($(with_unixodbc),yes) -NAME = odbcpsql -else -NAME = psqlodbc -endif -SO_MAJOR_VERSION = 0 -SO_MINOR_VERSION = 27 - -override CPPFLAGS := -I$(srcdir) $(CPPFLAGS) -DFRONTEND -DMD5_ODBC - - -OBJS = info.o bind.o columninfo.o connection.o convert.o drvconn.o \ - environ.o execute.o lobj.o md5.o misc.o options.o \ - pgtypes.o psqlodbc.o qresult.o results.o socket.o parse.o statement.o \ - tuple.o tuplelist.o dlg_specific.o odbcapi.o - -ifdef MULTIBYTE -OBJS += multibyte.o -endif - -SHLIB_LINK += $(filter -lm -lnsl -lsocket, $(LIBS)) -ifeq ($(with_unixodbc),yes) -SHLIB_LINK += -lodbcinst -endif -ifeq ($(with_iodbc),yes) -SHLIB_LINK += -liodbcinst -endif -ifeq ($(with_unixodbc)$(with_iodbc),nono) -OBJS += gpps.o -override CPPFLAGS += -DODBCINSTDIR='"$(odbcinst_ini_dir)"' -endif - -all: all-lib odbc-drop.sql - -# Shared library stuff -include $(top_srcdir)/src/Makefile.shlib - -# Symbols must be resolved to the version in the shared library because -# 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.) -LINK.shared += $(shlib_symbolic) - -odbc-drop.sql: odbc.sql - sed -n '/^CREATE OR REPLACE FUNCTION/s/CREATE OR REPLACE FUNCTION \([^ (][^ (]*([^)]*)\).*/DROP FUNCTION \1;/p' $< >$@ - -install: all installdirs - $(INSTALL_DATA) $(srcdir)/odbc.sql $(DESTDIR)$(datadir)/odbc.sql - $(INSTALL_DATA) odbc-drop.sql $(DESTDIR)$(datadir)/odbc-drop.sql - $(MAKE) install-lib - -installdirs: - $(mkinstalldirs) $(DESTDIR)$(libdir) $(DESTDIR)$(datadir) - -uninstall: uninstall-lib - rm -f $(DESTDIR)$(datadir)/odbc.sql $(DESTDIR)$(datadir)/odbc-drop.sql - -clean distclean maintainer-clean: clean-lib - rm -f $(OBJS) - rm -f odbc-drop.sql diff --git a/src/interfaces/odbc/bind.c b/src/interfaces/odbc/bind.c deleted file mode 100644 index e6deedaa8b6..00000000000 --- a/src/interfaces/odbc/bind.c +++ /dev/null @@ -1,638 +0,0 @@ -/*------- - * Module: bind.c - * - * Description: This module contains routines related to binding - * columns and parameters. - * - * Classes: BindInfoClass, ParameterInfoClass - * - * API functions: SQLBindParameter, SQLBindCol, SQLDescribeParam, SQLNumParams, - * SQLParamOptions - * - * Comments: See "notice.txt" for copyright and license information. - *------- - */ - -#include "bind.h" - -#include "environ.h" -#include "statement.h" -#include "descriptor.h" -#include "qresult.h" -#include "pgtypes.h" -#include <stdlib.h> -#include <string.h> - -#include "pgapifunc.h" - - -/* Bind parameters on a statement handle */ -RETCODE SQL_API -PGAPI_BindParameter( - HSTMT hstmt, - UWORD ipar, - SWORD fParamType, - SWORD fCType, - SWORD fSqlType, - UDWORD cbColDef, - SWORD ibScale, - PTR rgbValue, - SDWORD cbValueMax, - SDWORD FAR * pcbValue) -{ - StatementClass *stmt = (StatementClass *) hstmt; - static char *func = "PGAPI_BindParameter"; - APDFields *opts; - - mylog("%s: entering...\n", func); - - if (!stmt) - { - SC_log_error(func, "", NULL); - return SQL_INVALID_HANDLE; - } - SC_clear_error(stmt); - - opts = SC_get_APD(stmt); - if (opts->allocated < ipar) - extend_parameter_bindings(opts, ipar); - - /* use zero based column numbers for the below part */ - ipar--; - - /* store the given info */ - opts->parameters[ipar].buflen = cbValueMax; - opts->parameters[ipar].buffer = rgbValue; - opts->parameters[ipar].used = pcbValue; - opts->parameters[ipar].paramType = fParamType; - opts->parameters[ipar].CType = fCType; - opts->parameters[ipar].SQLType = fSqlType; - opts->parameters[ipar].column_size = cbColDef; - opts->parameters[ipar].decimal_digits = ibScale; - opts->parameters[ipar].precision = 0; - opts->parameters[ipar].scale = 0; -#if (ODBCVER >= 0x0300) - switch (fCType) - { - case SQL_C_NUMERIC: - if (cbColDef > 0) - opts->parameters[ipar].precision = (UInt2) cbColDef; - if (ibScale > 0) - opts->parameters[ipar].scale = ibScale; - break; - case SQL_C_TYPE_TIMESTAMP: - if (ibScale > 0) - opts->parameters[ipar].precision = ibScale; - break; - } -#endif /* ODBCVER */ - - /* - * If rebinding a parameter that had data-at-exec stuff in it, then - * free that stuff - */ - if (opts->parameters[ipar].EXEC_used) - { - free(opts->parameters[ipar].EXEC_used); - opts->parameters[ipar].EXEC_used = NULL; - } - - if (opts->parameters[ipar].EXEC_buffer) - { - if (opts->parameters[ipar].SQLType != SQL_LONGVARBINARY) - free(opts->parameters[ipar].EXEC_buffer); - opts->parameters[ipar].EXEC_buffer = NULL; - } - - if (pcbValue && opts->param_offset_ptr) - pcbValue += (*opts->param_offset_ptr >> 2); - /* Data at exec macro only valid for C char/binary data */ - if (pcbValue && (*pcbValue == SQL_DATA_AT_EXEC || - *pcbValue <= SQL_LEN_DATA_AT_EXEC_OFFSET)) - opts->parameters[ipar].data_at_exec = TRUE; - else - opts->parameters[ipar].data_at_exec = FALSE; - - /* Clear premature result */ - if (stmt->status == STMT_PREMATURE) - SC_recycle_statement(stmt); - - mylog("PGAPI_BindParamater: ipar=%d, paramType=%d, fCType=%d, fSqlType=%d, cbColDef=%d, ibScale=%d, rgbValue=%d, *pcbValue = %d, data_at_exec = %d\n", ipar, fParamType, fCType, fSqlType, cbColDef, ibScale, rgbValue, pcbValue ? *pcbValue : -777, opts->parameters[ipar].data_at_exec); - - return SQL_SUCCESS; -} - - -/* Associate a user-supplied buffer with a database column. */ -RETCODE SQL_API -PGAPI_BindCol( - HSTMT hstmt, - UWORD icol, - SWORD fCType, - PTR rgbValue, - SDWORD cbValueMax, - SDWORD FAR * pcbValue) -{ - StatementClass *stmt = (StatementClass *) hstmt; - static char *func = "PGAPI_BindCol"; - ARDFields *opts; - - mylog("%s: entering...\n", func); - - mylog("**** PGAPI_BindCol: stmt = %u, icol = %d\n", stmt, icol); - mylog("**** : fCType=%d rgb=%x valusMax=%d pcb=%x\n", fCType, rgbValue, cbValueMax, pcbValue); - - if (!stmt) - { - SC_log_error(func, "", NULL); - return SQL_INVALID_HANDLE; - } - - - - opts = SC_get_ARD(stmt); - if (stmt->status == STMT_EXECUTING) - { - stmt->errormsg = "Can't bind columns while statement is still executing."; - stmt->errornumber = STMT_SEQUENCE_ERROR; - SC_log_error(func, "", stmt); - return SQL_ERROR; - } - - SC_clear_error(stmt); - /* If the bookmark column is being bound, then just save it */ - if (icol == 0) - { - if (rgbValue == NULL) - { - opts->bookmark->buffer = NULL; - opts->bookmark->used = NULL; - } - else - { - /* Make sure it is the bookmark data type */ - if (fCType == SQL_C_BOOKMARK) - switch (fCType) - { - case SQL_C_BOOKMARK: -#if (ODBCVER >= 0x0300) - case SQL_C_VARBOOKMARK: -#endif /* ODBCVER */ - break; - default: - stmt->errormsg = "Column 0 is not of type SQL_C_BOOKMARK"; -inolog("Column 0 is type %d not of type SQL_C_BOOKMARK", fCType); - stmt->errornumber = STMT_PROGRAM_TYPE_OUT_OF_RANGE; - SC_log_error(func, "", stmt); - return SQL_ERROR; - } - - opts->bookmark->buffer = rgbValue; - opts->bookmark->used = pcbValue; - } - return SQL_SUCCESS; - } - - /* - * Allocate enough bindings if not already done. Most likely, - * execution of a statement would have setup the necessary bindings. - * But some apps call BindCol before any statement is executed. - */ - if (icol > opts->allocated) - extend_column_bindings(opts, icol); - - /* check to see if the bindings were allocated */ - if (!opts->bindings) - { - stmt->errormsg = "Could not allocate memory for bindings."; - stmt->errornumber = STMT_NO_MEMORY_ERROR; - SC_log_error(func, "", stmt); - return SQL_ERROR; - } - - /* use zero based col numbers from here out */ - icol--; - - /* Reset for SQLGetData */ - opts->bindings[icol].data_left = -1; - - if (rgbValue == NULL) - { - /* we have to unbind the column */ - opts->bindings[icol].buflen = 0; - opts->bindings[icol].buffer = NULL; - opts->bindings[icol].used = NULL; - opts->bindings[icol].returntype = SQL_C_CHAR; - if (opts->bindings[icol].ttlbuf) - free(opts->bindings[icol].ttlbuf); - opts->bindings[icol].ttlbuf = NULL; - opts->bindings[icol].ttlbuflen = 0; - opts->bindings[icol].precision = 0; - opts->bindings[icol].scale = 0; - } - else - { - /* ok, bind that column */ - opts->bindings[icol].buflen = cbValueMax; - opts->bindings[icol].buffer = rgbValue; - opts->bindings[icol].used = pcbValue; - opts->bindings[icol].returntype = fCType; -#if (ODBCVER >= 0x0300) - if (SQL_C_NUMERIC == fCType) - opts->bindings[icol].precision = 32; - else -#endif /* ODBCVER */ - opts->bindings[icol].precision = 0; - opts->bindings[icol].scale = 0; - - mylog(" bound buffer[%d] = %u\n", icol, opts->bindings[icol].buffer); - } - - return SQL_SUCCESS; -} - - -/* - * Returns the description of a parameter marker. - * This function is listed as not being supported by SQLGetFunctions() because it is - * used to describe "parameter markers" (not bound parameters), in which case, - * the dbms should return info on the markers. Since Postgres doesn't support that, - * it is best to say this function is not supported and let the application assume a - * data type (most likely varchar). - */ -RETCODE SQL_API -PGAPI_DescribeParam( - HSTMT hstmt, - UWORD ipar, - SWORD FAR * pfSqlType, - UDWORD FAR * pcbColDef, - SWORD FAR * pibScale, - SWORD FAR * pfNullable) -{ - StatementClass *stmt = (StatementClass *) hstmt; - static char *func = "PGAPI_DescribeParam"; - APDFields *opts; - - mylog("%s: entering...\n", func); - - if (!stmt) - { - SC_log_error(func, "", NULL); - return SQL_INVALID_HANDLE; - } - SC_clear_error(stmt); - - opts = SC_get_APD(stmt); - if ((ipar < 1) || (ipar > opts->allocated)) - { - stmt->errormsg = "Invalid parameter number for PGAPI_DescribeParam."; - stmt->errornumber = STMT_BAD_PARAMETER_NUMBER_ERROR; - SC_log_error(func, "", stmt); - return SQL_ERROR; - } - - ipar--; - - /* - * This implementation is not very good, since it is supposed to - * describe - */ - /* parameter markers, not bound parameters. */ - if (pfSqlType) - *pfSqlType = opts->parameters[ipar].SQLType; - - if (pcbColDef) - *pcbColDef = opts->parameters[ipar].column_size; - - if (pibScale) - *pibScale = opts->parameters[ipar].decimal_digits; - - if (pfNullable) - *pfNullable = pgtype_nullable(stmt, opts->parameters[ipar].paramType); - - return SQL_SUCCESS; -} - - -/* Sets multiple values (arrays) for the set of parameter markers. */ -RETCODE SQL_API -PGAPI_ParamOptions( - HSTMT hstmt, - UDWORD crow, - UDWORD FAR * pirow) -{ - static char *func = "PGAPI_ParamOptions"; - StatementClass *stmt = (StatementClass *) hstmt; - APDFields *opts; - - mylog("%s: entering... %d %x\n", func, crow, pirow); - - opts = SC_get_APD(stmt); - opts->paramset_size = crow; - SC_get_IPD(stmt)->param_processed_ptr = (UInt4 *) pirow; - return SQL_SUCCESS; -} - - -/* - * This function should really talk to the dbms to determine the number of - * "parameter markers" (not bound parameters) in the statement. But, since - * Postgres doesn't support that, the driver should just count the number of markers - * and return that. The reason the driver just can't say this function is unsupported - * like it does for SQLDescribeParam is that some applications don't care and try - * to call it anyway. - * If the statement does not have parameters, it should just return 0. - */ -RETCODE SQL_API -PGAPI_NumParams( - HSTMT hstmt, - SWORD FAR * pcpar) -{ - StatementClass *stmt = (StatementClass *) hstmt; - char in_quote = FALSE; - unsigned int i; - static char *func = "PGAPI_NumParams"; - - mylog("%s: entering...\n", func); - - if (!stmt) - { - SC_log_error(func, "", NULL); - return SQL_INVALID_HANDLE; - } - SC_clear_error(stmt); - - if (pcpar) - *pcpar = 0; - else - { - SC_log_error(func, "pcpar was null", stmt); - return SQL_ERROR; - } - - - if (!stmt->statement) - { - /* no statement has been allocated */ - stmt->errormsg = "PGAPI_NumParams called with no statement ready."; - stmt->errornumber = STMT_SEQUENCE_ERROR; - SC_log_error(func, "", stmt); - return SQL_ERROR; - } - else - { - for (i = 0; i < strlen(stmt->statement); i++) - { - if (stmt->statement[i] == '?' && !in_quote) - (*pcpar)++; - else - { - if (stmt->statement[i] == '\'') - in_quote = (in_quote ? FALSE : TRUE); - } - } - return SQL_SUCCESS; - } -} - - -/* - * Bindings Implementation - */ -BindInfoClass * -create_empty_bindings(int num_columns) -{ - BindInfoClass *new_bindings; - int i; - - new_bindings = (BindInfoClass *) malloc(num_columns * sizeof(BindInfoClass)); - if (!new_bindings) - return 0; - - for (i = 0; i < num_columns; i++) - { - new_bindings[i].buflen = 0; - new_bindings[i].buffer = NULL; - new_bindings[i].used = NULL; - new_bindings[i].data_left = -1; - new_bindings[i].ttlbuf = NULL; - new_bindings[i].ttlbuflen = 0; - } - - return new_bindings; -} - -void -extend_parameter_bindings(APDFields *self, int num_params) -{ - static char *func = "extend_parameter_bindings"; - ParameterInfoClass *new_bindings; - - mylog("%s: entering ... self=%u, parameters_allocated=%d, num_params=%d\n", func, self, self->allocated, num_params); - - /* - * if we have too few, allocate room for more, and copy the old - * entries into the new structure - */ - if (self->allocated < num_params) - { - new_bindings = (ParameterInfoClass *) realloc(self->parameters, sizeof(ParameterInfoClass) * num_params); - if (!new_bindings) - { - mylog("%s: unable to create %d new bindings from %d old bindings\n", func, num_params, self->allocated); - - self->parameters = NULL; - self->allocated = 0; - return; - } - memset(&new_bindings[self->allocated], 0, - sizeof(ParameterInfoClass) * (num_params - self->allocated)); - - self->parameters = new_bindings; - self->allocated = num_params; - } - - mylog("exit extend_parameter_bindings\n"); -} - -void -reset_a_parameter_binding(APDFields *self, int ipar) -{ - static char *func = "reset_a_parameter_binding"; - - mylog("%s: entering ... self=%u, parameters_allocated=%d, ipar=%d\n", func, self, self->allocated, ipar); - - if (ipar < 1 || ipar > self->allocated) - return; - - ipar--; - self->parameters[ipar].buflen = 0; - self->parameters[ipar].buffer = 0; - self->parameters[ipar].used = 0; - self->parameters[ipar].paramType = 0; - self->parameters[ipar].CType = 0; - if (self->parameters[ipar].EXEC_used) - { - free(self->parameters[ipar].EXEC_used); - self->parameters[ipar].EXEC_used = NULL; - } - - if (self->parameters[ipar].EXEC_buffer) - { - if (self->parameters[ipar].SQLType != SQL_LONGVARBINARY) - free(self->parameters[ipar].EXEC_buffer); - self->parameters[ipar].EXEC_buffer = NULL; - } - self->parameters[ipar].SQLType = 0; - self->parameters[ipar].column_size = 0; - self->parameters[ipar].decimal_digits = 0; - self->parameters[ipar].precision = 0; - self->parameters[ipar].scale = 0; - self->parameters[ipar].data_at_exec = FALSE; - self->parameters[ipar].lobj_oid = 0; -} - -/* - * Free parameters and free the memory. - */ -void -APD_free_params(APDFields *self, char option) -{ - int i; - - mylog("APD_free_params: ENTER, self=%d\n", self); - - if (!self->parameters) - return; - - for (i = 0; i < self->allocated; i++) - { - if (self->parameters[i].data_at_exec) - { - if (self->parameters[i].EXEC_used) - { - free(self->parameters[i].EXEC_used); - self->parameters[i].EXEC_used = NULL; - } - - if (self->parameters[i].EXEC_buffer) - { - if (self->parameters[i].SQLType != SQL_LONGVARBINARY) - free(self->parameters[i].EXEC_buffer); - self->parameters[i].EXEC_buffer = NULL; - } - } - } - - if (option == STMT_FREE_PARAMS_ALL) - { - if (self->parameters); - free(self->parameters); - self->parameters = NULL; - self->allocated = 0; - } - - mylog("APD_free_params: EXIT\n"); -} - -void -extend_column_bindings(ARDFields *self, int num_columns) -{ - static char *func = "extend_column_bindings"; - BindInfoClass *new_bindings; - int i; - - mylog("%s: entering ... self=%u, bindings_allocated=%d, num_columns=%d\n", func, self, self->allocated, num_columns); - - /* - * if we have too few, allocate room for more, and copy the old - * entries into the new structure - */ - if (self->allocated < num_columns) - { - new_bindings = create_empty_bindings(num_columns); - if (!new_bindings) - { - mylog("%s: unable to create %d new bindings from %d old bindings\n", func, num_columns, self->allocated); - - if (self->bindings) - { - free(self->bindings); - self->bindings = NULL; - } - self->allocated = 0; - return; - } - - if (self->bindings) - { - for (i = 0; i < self->allocated; i++) - new_bindings[i] = self->bindings[i]; - - free(self->bindings); - } - - self->bindings = new_bindings; - self->allocated = num_columns; - } - - /* - * There is no reason to zero out extra bindings if there are more - * than needed. If an app has allocated extra bindings, let it worry - * about it by unbinding those columns. - */ - - /* SQLBindCol(1..) ... SQLBindCol(10...) # got 10 bindings */ - /* SQLExecDirect(...) # returns 5 cols */ - /* SQLExecDirect(...) # returns 10 cols (now OK) */ - - mylog("exit extend_column_bindings\n"); -} - -void -reset_a_column_binding(ARDFields *self, int icol) -{ - static char *func = "reset_a_column_binding"; - - mylog("%s: entering ... self=%u, bindings_allocated=%d, icol=%d\n", func, self, self->allocated, icol); - - if (icol > self->allocated) - return; - - /* use zero based col numbers from here out */ - if (0 == icol) - { - self->bookmark->buffer = NULL; - self->bookmark->used = NULL; - } - else - { - icol--; - - /* we have to unbind the column */ - self->bindings[icol].buflen = 0; - self->bindings[icol].buffer = NULL; - self->bindings[icol].used = NULL; - self->bindings[icol].data_left = -1; - self->bindings[icol].returntype = SQL_C_CHAR; - if (self->bindings[icol].ttlbuf) - free(self->bindings[icol].ttlbuf); - self->bindings[icol].ttlbuf = NULL; - self->bindings[icol].ttlbuflen = 0; - } -} - -void ARD_unbind_cols(ARDFields *self, BOOL freeall) -{ - Int2 lf; - - for (lf = 1; lf <= self->allocated; lf++) - reset_a_column_binding(self, lf); - if (freeall) - { - if (self->bindings) - free(self->bindings); - self->bindings = NULL; - self->allocated = 0; - } -} diff --git a/src/interfaces/odbc/bind.h b/src/interfaces/odbc/bind.h deleted file mode 100644 index f2467c7713a..00000000000 --- a/src/interfaces/odbc/bind.h +++ /dev/null @@ -1,62 +0,0 @@ -/* File: bind.h - * - * Description: See "bind.c" - * - * Comments: See "notice.txt" for copyright and license information. - * - */ - -#ifndef __BIND_H__ -#define __BIND_H__ - -#include "psqlodbc.h" - -/* - * BindInfoClass -- stores information about a bound column - */ -struct BindInfoClass_ -{ - Int4 buflen; /* size of buffer */ - Int4 data_left; /* amount of data left to read - * (SQLGetData) */ - char *buffer; /* pointer to the buffer */ - Int4 *used; /* used space in the buffer (for strings - * not counting the '\0') */ - char *ttlbuf; /* to save the large result */ - Int4 ttlbuflen; /* the buffer length */ - Int2 returntype; /* kind of conversion to be applied when - * returning (SQL_C_DEFAULT, - * SQL_C_CHAR...) */ - Int2 precision; /* the precision for numeric or timestamp type */ - Int2 scale; /* the scale for numeric type */ -}; - -/* - * ParameterInfoClass -- stores information about a bound parameter - */ -struct ParameterInfoClass_ -{ - Int4 buflen; - char *buffer; - Int4 *used; - Int2 paramType; - Int2 CType; - Int2 SQLType; - Int2 decimal_digits; - UInt4 column_size; - Oid lobj_oid; - Int4 *EXEC_used; /* amount of data OR the oid of the large - * object */ - char *EXEC_buffer; /* the data or the FD of the large object */ - Int2 precision; /* the precision for numeric or timestamp type */ - Int2 scale; /* the scale for numeric type */ - char data_at_exec; -}; - -BindInfoClass *create_empty_bindings(int num_columns); -void extend_column_bindings(ARDFields *opts, int num_columns); -void reset_a_column_binding(ARDFields *opts, int icol); -void extend_parameter_bindings(APDFields *opts, int num_columns); -void reset_a_parameter_binding(APDFields *opts, int ipar); - -#endif diff --git a/src/interfaces/odbc/columninfo.c b/src/interfaces/odbc/columninfo.c deleted file mode 100644 index 7fe72d3f6d1..00000000000 --- a/src/interfaces/odbc/columninfo.c +++ /dev/null @@ -1,191 +0,0 @@ -/*------- - * Module: columninfo.c - * - * Description: This module contains routines related to - * reading and storing the field information from a query. - * - * Classes: ColumnInfoClass (Functions prefix: "CI_") - * - * API functions: none - * - * Comments: See "notice.txt" for copyright and license information. - *------- - */ - -#include "pgtypes.h" -#include "columninfo.h" - -#include "connection.h" -#include "socket.h" -#include <stdlib.h> -#include <string.h> -#include "pgapifunc.h" - -ColumnInfoClass * -CI_Constructor() -{ - ColumnInfoClass *rv; - - rv = (ColumnInfoClass *) malloc(sizeof(ColumnInfoClass)); - - if (rv) - { - rv->num_fields = 0; - rv->name = NULL; - rv->adtid = NULL; - rv->adtsize = NULL; - rv->display_size = NULL; - rv->atttypmod = NULL; - } - - return rv; -} - - -void -CI_Destructor(ColumnInfoClass *self) -{ - CI_free_memory(self); - - free(self); -} - - -/* - * Read in field descriptions. - * If self is not null, then also store the information. - * If self is null, then just read, don't store. - */ -char -CI_read_fields(ColumnInfoClass *self, ConnectionClass *conn) -{ - Int2 lf; - int new_num_fields; - Oid new_adtid; - Int2 new_adtsize; - Int4 new_atttypmod = -1; - - /* MAX_COLUMN_LEN may be sufficient but for safety */ - char new_field_name[2 * MAX_COLUMN_LEN + 1]; - SocketClass *sock; - ConnInfo *ci; - - sock = CC_get_socket(conn); - ci = &conn->connInfo; - - /* at first read in the number of fields that are in the query */ - new_num_fields = (Int2) SOCK_get_int(sock, sizeof(Int2)); - - mylog("num_fields = %d\n", new_num_fields); - - if (self) - /* according to that allocate memory */ - CI_set_num_fields(self, new_num_fields); - - /* now read in the descriptions */ - for (lf = 0; lf < new_num_fields; lf++) - { - SOCK_get_string(sock, new_field_name, 2 * MAX_COLUMN_LEN); - new_adtid = (Oid) SOCK_get_int(sock, 4); - new_adtsize = (Int2) SOCK_get_int(sock, 2); - - /* If 6.4 protocol, then read the atttypmod field */ - if (PG_VERSION_GE(conn, 6.4)) - { - mylog("READING ATTTYPMOD\n"); - new_atttypmod = (Int4) SOCK_get_int(sock, 4); - - /* Subtract the header length */ - switch (new_adtid) - { - case PG_TYPE_DATETIME: - case PG_TYPE_TIMESTAMP_NO_TMZONE: - case PG_TYPE_TIME: - case PG_TYPE_TIME_WITH_TMZONE: - break; - default: - new_atttypmod -= 4; - } - if (new_atttypmod < 0) - 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); - - if (self) - CI_set_field_info(self, lf, new_field_name, new_adtid, new_adtsize, new_atttypmod); - } - - return (SOCK_get_errcode(sock) == 0); -} - - -void -CI_free_memory(ColumnInfoClass *self) -{ - register Int2 lf; - int num_fields = self->num_fields; - - for (lf = 0; lf < num_fields; lf++) - { - if (self->name[lf]) - { - free(self->name[lf]); - self->name[lf] = NULL; - } - } - - /* Safe to call even if null */ - self->num_fields = 0; - if (self->name) - free(self->name); - self->name = NULL; - if (self->adtid) - free(self->adtid); - self->adtid = NULL; - if (self->adtsize) - free(self->adtsize); - self->adtsize = NULL; - if (self->display_size) - free(self->display_size); - self->display_size = NULL; - - if (self->atttypmod) - free(self->atttypmod); - self->atttypmod = NULL; -} - - -void -CI_set_num_fields(ColumnInfoClass *self, int new_num_fields) -{ - CI_free_memory(self); /* always safe to call */ - - self->num_fields = new_num_fields; - - self->name = (char **) malloc(sizeof(char *) * self->num_fields); - memset(self->name, 0, sizeof(char *) * self->num_fields); - self->adtid = (Oid *) malloc(sizeof(Oid) * self->num_fields); - self->adtsize = (Int2 *) malloc(sizeof(Int2) * self->num_fields); - self->display_size = (Int2 *) malloc(sizeof(Int2) * self->num_fields); - self->atttypmod = (Int4 *) malloc(sizeof(Int4) * self->num_fields); -} - - -void -CI_set_field_info(ColumnInfoClass *self, int field_num, char *new_name, - Oid new_adtid, Int2 new_adtsize, Int4 new_atttypmod) -{ - /* check bounds */ - if ((field_num < 0) || (field_num >= self->num_fields)) - return; - - /* store the info */ - self->name[field_num] = strdup(new_name); - self->adtid[field_num] = new_adtid; - self->adtsize[field_num] = new_adtsize; - self->atttypmod[field_num] = new_atttypmod; - - self->display_size[field_num] = 0; -} diff --git a/src/interfaces/odbc/columninfo.h b/src/interfaces/odbc/columninfo.h deleted file mode 100644 index 41e9400dcea..00000000000 --- a/src/interfaces/odbc/columninfo.h +++ /dev/null @@ -1,42 +0,0 @@ -/* File: columninfo.h - * - * Description: See "columninfo.c" - * - * Comments: See "notice.txt" for copyright and license information. - * - */ - -#ifndef __COLUMNINFO_H__ -#define __COLUMNINFO_H__ - -#include "psqlodbc.h" - -struct ColumnInfoClass_ -{ - Int2 num_fields; - char **name; /* list of type names */ - Oid *adtid; /* list of type ids */ - Int2 *adtsize; /* list type sizes */ - Int2 *display_size; /* the display size (longest row) */ - Int4 *atttypmod; /* the length of bpchar/varchar */ -}; - -#define CI_get_num_fields(self) (self->num_fields) -#define CI_get_oid(self, col) (self->adtid[col]) -#define CI_get_fieldname(self, col) (self->name[col]) -#define CI_get_fieldsize(self, col) (self->adtsize[col]) -#define CI_get_display_size(self, col) (self->display_size[col]) -#define CI_get_atttypmod(self, col) (self->atttypmod[col]) - -ColumnInfoClass *CI_Constructor(void); -void CI_Destructor(ColumnInfoClass *self); -void CI_free_memory(ColumnInfoClass *self); -char CI_read_fields(ColumnInfoClass *self, ConnectionClass *conn); - -/* functions for setting up the fields from within the program, */ -/* without reading from a socket */ -void CI_set_num_fields(ColumnInfoClass *self, int new_num_fields); -void CI_set_field_info(ColumnInfoClass *self, int field_num, char *new_name, - Oid new_adtid, Int2 new_adtsize, Int4 atttypmod); - -#endif diff --git a/src/interfaces/odbc/connection.c b/src/interfaces/odbc/connection.c deleted file mode 100644 index e3c0563ec2d..00000000000 --- a/src/interfaces/odbc/connection.c +++ /dev/null @@ -1,2154 +0,0 @@ -/*------ - * Module: connection.c - * - * Description: This module contains routines related to - * connecting to and disconnecting from the Postgres DBMS. - * - * Classes: ConnectionClass (Functions prefix: "CC_") - * - * API functions: SQLAllocConnect, SQLConnect, SQLDisconnect, SQLFreeConnect, - * SQLBrowseConnect(NI) - * - * Comments: See "notice.txt" for copyright and license information. - *------- - */ -/* Multibyte support Eiji Tokuya 2001-03-15 */ - -#include "connection.h" - -#include <stdio.h> -#include <string.h> -#include <ctype.h> -#ifndef WIN32 -#include <errno.h> -#endif /* WIN32 */ - -#include "environ.h" -#include "socket.h" -#include "statement.h" -#include "qresult.h" -#include "lobj.h" -#include "dlg_specific.h" - -#ifdef MULTIBYTE -#include "multibyte.h" -#endif - -#include "pgapifunc.h" -#include "md5.h" - -#define STMT_INCREMENT 16 /* how many statement holders to allocate - * at a time */ - -#define PRN_NULLCHECK - -extern GLOBAL_VALUES globals; - - -RETCODE SQL_API -PGAPI_AllocConnect( - HENV henv, - HDBC FAR * phdbc) -{ - EnvironmentClass *env = (EnvironmentClass *) henv; - ConnectionClass *conn; - static char *func = "PGAPI_AllocConnect"; - - mylog("%s: entering...\n", func); - - conn = CC_Constructor(); - mylog("**** %s: henv = %u, conn = %u\n", func, henv, conn); - - if (!conn) - { - env->errormsg = "Couldn't allocate memory for Connection object."; - env->errornumber = ENV_ALLOC_ERROR; - *phdbc = SQL_NULL_HDBC; - EN_log_error(func, "", env); - return SQL_ERROR; - } - - if (!EN_add_connection(env, conn)) - { - env->errormsg = "Maximum number of connections exceeded."; - env->errornumber = ENV_ALLOC_ERROR; - CC_Destructor(conn); - *phdbc = SQL_NULL_HDBC; - EN_log_error(func, "", env); - return SQL_ERROR; - } - - if (phdbc) - *phdbc = (HDBC) conn; - - return SQL_SUCCESS; -} - - -RETCODE SQL_API -PGAPI_Connect( - HDBC hdbc, - UCHAR FAR * szDSN, - SWORD cbDSN, - UCHAR FAR * szUID, - SWORD cbUID, - UCHAR FAR * szAuthStr, - SWORD cbAuthStr) -{ - ConnectionClass *conn = (ConnectionClass *) hdbc; - ConnInfo *ci; - static char *func = "PGAPI_Connect"; - - mylog("%s: entering...\n", func); - - if (!conn) - { - CC_log_error(func, "", NULL); - return SQL_INVALID_HANDLE; - } - - ci = &conn->connInfo; - - make_string(szDSN, cbDSN, ci->dsn); - - /* get the values for the DSN from the registry */ - memcpy(&ci->drivers, &globals, sizeof(globals)); - getDSNinfo(ci, CONN_OVERWRITE); - logs_on_off(1, ci->drivers.debug, ci->drivers.commlog); - /* initialize pg_version from connInfo.protocol */ - CC_initialize_pg_version(conn); - - /* - * override values from DSN info with UID and authStr(pwd) This only - * occurs if the values are actually there. - */ - make_string(szUID, cbUID, ci->username); - make_string(szAuthStr, cbAuthStr, ci->password); - - /* fill in any defaults */ - getDSNdefaults(ci); - - qlog("conn = %u, %s(DSN='%s', UID='%s', PWD='%s')\n", conn, func, ci->dsn, ci->username, ci->password); - - if (CC_connect(conn, AUTH_REQ_OK, NULL) <= 0) - { - /* Error messages are filled in */ - CC_log_error(func, "Error on CC_connect", conn); - return SQL_ERROR; - } - - mylog("%s: returning...\n", func); - - return SQL_SUCCESS; -} - - -RETCODE SQL_API -PGAPI_BrowseConnect( - HDBC hdbc, - UCHAR FAR * szConnStrIn, - SWORD cbConnStrIn, - UCHAR FAR * szConnStrOut, - SWORD cbConnStrOutMax, - SWORD FAR * pcbConnStrOut) -{ - static char *func = "PGAPI_BrowseConnect"; - - mylog("%s: entering...\n", func); - - return SQL_SUCCESS; -} - - -/* Drop any hstmts open on hdbc and disconnect from database */ -RETCODE SQL_API -PGAPI_Disconnect( - HDBC hdbc) -{ - ConnectionClass *conn = (ConnectionClass *) hdbc; - static char *func = "PGAPI_Disconnect"; - - - mylog("%s: entering...\n", func); - - if (!conn) - { - CC_log_error(func, "", NULL); - return SQL_INVALID_HANDLE; - } - - qlog("conn=%u, %s\n", conn, func); - - if (conn->status == CONN_EXECUTING) - { - conn->errornumber = CONN_IN_USE; - conn->errormsg = "A transaction is currently being executed"; - CC_log_error(func, "", conn); - return SQL_ERROR; - } - - logs_on_off(-1, conn->connInfo.drivers.debug, conn->connInfo.drivers.commlog); - mylog("%s: about to CC_cleanup\n", func); - - /* Close the connection and free statements */ - CC_cleanup(conn); - - mylog("%s: done CC_cleanup\n", func); - mylog("%s: returning...\n", func); - - return SQL_SUCCESS; -} - - -RETCODE SQL_API -PGAPI_FreeConnect( - HDBC hdbc) -{ - ConnectionClass *conn = (ConnectionClass *) hdbc; - static char *func = "PGAPI_FreeConnect"; - - mylog("%s: entering...\n", func); - mylog("**** in %s: hdbc=%u\n", func, hdbc); - - if (!conn) - { - CC_log_error(func, "", NULL); - return SQL_INVALID_HANDLE; - } - - /* Remove the connection from the environment */ - if (!EN_remove_connection(conn->henv, conn)) - { - conn->errornumber = CONN_IN_USE; - conn->errormsg = "A transaction is currently being executed"; - CC_log_error(func, "", conn); - return SQL_ERROR; - } - - CC_Destructor(conn); - - mylog("%s: returning...\n", func); - - return SQL_SUCCESS; -} - - -void -CC_conninfo_init(ConnInfo *conninfo) -{ - memset(conninfo, 0, sizeof(ConnInfo)); - conninfo->disallow_premature = -1; - conninfo->allow_keyset = -1; - conninfo->lf_conversion = -1; - conninfo->true_is_minus1 = -1; - conninfo->int8_as = -101; - memcpy(&(conninfo->drivers), &globals, sizeof(globals)); -} -/* - * IMPLEMENTATION CONNECTION CLASS - */ -ConnectionClass * -CC_Constructor() -{ - ConnectionClass *rv; - - rv = (ConnectionClass *) malloc(sizeof(ConnectionClass)); - - if (rv != NULL) - { - rv->henv = NULL; /* not yet associated with an environment */ - - rv->errormsg = NULL; - rv->errornumber = 0; - rv->errormsg_created = FALSE; - - rv->status = CONN_NOT_CONNECTED; - rv->transact_status = CONN_IN_AUTOCOMMIT; /* autocommit by default */ - - CC_conninfo_init(&(rv->connInfo)); - rv->sock = SOCK_Constructor(rv); - if (!rv->sock) - return NULL; - - rv->stmts = (StatementClass **) malloc(sizeof(StatementClass *) * STMT_INCREMENT); - if (!rv->stmts) - return NULL; - memset(rv->stmts, 0, sizeof(StatementClass *) * STMT_INCREMENT); - - rv->num_stmts = STMT_INCREMENT; - - rv->lobj_type = PG_TYPE_LO; - - rv->ntables = 0; - rv->col_info = NULL; - - rv->translation_option = 0; - rv->translation_handle = NULL; - rv->DataSourceToDriver = NULL; - rv->DriverToDataSource = NULL; - rv->driver_version = ODBCVER; - memset(rv->pg_version, 0, sizeof(rv->pg_version)); - rv->pg_version_number = .0; - rv->pg_version_major = 0; - rv->pg_version_minor = 0; - rv->ms_jet = 0; - rv->unicode = 0; - rv->result_uncommitted = 0; - rv->schema_support = 0; - rv->isolation = SQL_TXN_READ_COMMITTED; -#ifdef MULTIBYTE - rv->client_encoding = NULL; - rv->server_encoding = NULL; -#endif /* MULTIBYTE */ - rv->current_schema = NULL; - - - /* Initialize statement options to defaults */ - /* Statements under this conn will inherit these options */ - - InitializeStatementOptions(&rv->stmtOptions); - InitializeARDFields(&rv->ardOptions); - InitializeAPDFields(&rv->apdOptions); - } - return rv; -} - - -char -CC_Destructor(ConnectionClass *self) -{ - mylog("enter CC_Destructor, self=%u\n", self); - - if (self->status == CONN_EXECUTING) - return 0; - - CC_cleanup(self); /* cleanup socket and statements */ - - mylog("after CC_Cleanup\n"); - - /* Free up statement holders */ - if (self->stmts) - { - free(self->stmts); - self->stmts = NULL; - } - mylog("after free statement holders\n"); - - free(self); - - mylog("exit CC_Destructor\n"); - - return 1; -} - - -/* Return how many cursors are opened on this connection */ -int -CC_cursor_count(ConnectionClass *self) -{ - StatementClass *stmt; - int i, - count = 0; - - mylog("CC_cursor_count: self=%u, num_stmts=%d\n", self, self->num_stmts); - - for (i = 0; i < self->num_stmts; i++) - { - stmt = self->stmts[i]; - if (stmt && SC_get_Result(stmt) && SC_get_Result(stmt)->cursor) - count++; - } - - mylog("CC_cursor_count: returning %d\n", count); - - return count; -} - - -void -CC_clear_error(ConnectionClass *self) -{ - self->errornumber = 0; - self->errormsg = NULL; - self->errormsg_created = FALSE; -} - - -/* - * Used to begin a transaction. - */ -char -CC_begin(ConnectionClass *self) -{ - char ret = TRUE; - if (!CC_is_in_trans(self)) - { - QResultClass *res = CC_send_query(self, "BEGIN", NULL, CLEAR_RESULT_ON_ABORT); - mylog("CC_begin: sending BEGIN!\n"); - - if (res != NULL) - { - ret = QR_command_maybe_successful(res); - QR_Destructor(res); - } - else - return FALSE; - } - - return ret; -} - -/* - * Used to commit a transaction. - * We are almost always in the middle of a transaction. - */ -char -CC_commit(ConnectionClass *self) -{ - char ret = FALSE; - if (CC_is_in_trans(self)) - { - QResultClass *res = CC_send_query(self, "COMMIT", NULL, CLEAR_RESULT_ON_ABORT); - mylog("CC_commit: sending COMMIT!\n"); - if (res != NULL) - { - ret = QR_command_maybe_successful(res); - QR_Destructor(res); - } - else - return FALSE; - } - - return ret; -} - -/* - * Used to cancel a transaction. - * We are almost always in the middle of a transaction. - */ -char -CC_abort(ConnectionClass *self) -{ - if (CC_is_in_trans(self)) - { - QResultClass *res = CC_send_query(self, "ROLLBACK", NULL, CLEAR_RESULT_ON_ABORT); - mylog("CC_abort: sending ABORT!\n"); - if (res != NULL) - QR_Destructor(res); - else - return FALSE; - } - - return TRUE; -} - - -/* This is called by SQLDisconnect also */ -char -CC_cleanup(ConnectionClass *self) -{ - int i; - StatementClass *stmt; - - if (self->status == CONN_EXECUTING) - return FALSE; - - mylog("in CC_Cleanup, self=%u\n", self); - - /* Cancel an ongoing transaction */ - /* We are always in the middle of a transaction, */ - /* even if we are in auto commit. */ - if (self->sock) - CC_abort(self); - - mylog("after CC_abort\n"); - - /* This actually closes the connection to the dbase */ - if (self->sock) - { - SOCK_Destructor(self->sock); - self->sock = NULL; - } - - mylog("after SOCK destructor\n"); - - /* Free all the stmts on this connection */ - for (i = 0; i < self->num_stmts; i++) - { - stmt = self->stmts[i]; - if (stmt) - { - stmt->hdbc = NULL; /* prevent any more dbase interactions */ - - SC_Destructor(stmt); - - self->stmts[i] = NULL; - } - } - - /* Check for translation dll */ -#ifdef WIN32 - if (self->translation_handle) - { - FreeLibrary(self->translation_handle); - self->translation_handle = NULL; - } -#endif - - self->status = CONN_NOT_CONNECTED; - self->transact_status = CONN_IN_AUTOCOMMIT; - CC_conninfo_init(&(self->connInfo)); -#ifdef MULTIBYTE - if (self->client_encoding) - free(self->client_encoding); - self->client_encoding = NULL; - if (self->server_encoding) - free(self->server_encoding); - self->server_encoding = NULL; -#endif /* MULTIBYTE */ - if (self->current_schema) - free(self->current_schema); - self->current_schema = NULL; - /* Free cached table info */ - if (self->col_info) - { - int i; - - for (i = 0; i < self->ntables; i++) - { - if (self->col_info[i]->result) /* Free the SQLColumns result structure */ - QR_Destructor(self->col_info[i]->result); - - if (self->col_info[i]->schema) - free(self->col_info[i]->schema); - free(self->col_info[i]); - } - free(self->col_info); - self->col_info = NULL; - } - self->ntables = 0; - mylog("exit CC_Cleanup\n"); - return TRUE; -} - - -int -CC_set_translation(ConnectionClass *self) -{ - -#ifdef WIN32 - - if (self->translation_handle != NULL) - { - FreeLibrary(self->translation_handle); - self->translation_handle = NULL; - } - - if (self->connInfo.translation_dll[0] == 0) - return TRUE; - - self->translation_option = atoi(self->connInfo.translation_option); - self->translation_handle = LoadLibrary(self->connInfo.translation_dll); - - if (self->translation_handle == NULL) - { - self->errornumber = CONN_UNABLE_TO_LOAD_DLL; - self->errormsg = "Could not load the translation DLL."; - return FALSE; - } - - self->DataSourceToDriver - = (DataSourceToDriverProc) GetProcAddress(self->translation_handle, - "SQLDataSourceToDriver"); - - self->DriverToDataSource - = (DriverToDataSourceProc) GetProcAddress(self->translation_handle, - "SQLDriverToDataSource"); - - if (self->DataSourceToDriver == NULL || self->DriverToDataSource == NULL) - { - self->errornumber = CONN_UNABLE_TO_LOAD_DLL; - self->errormsg = "Could not find translation DLL functions."; - return FALSE; - } -#endif - return TRUE; -} - -static int -md5_auth_send(ConnectionClass *self, const char *salt) -{ - char *pwd1 = NULL, *pwd2 = NULL; - ConnInfo *ci = &(self->connInfo); - SocketClass *sock = self->sock; - - if (!(pwd1 = malloc(MD5_PASSWD_LEN + 1))) - return 1; - if (!EncryptMD5(ci->password, ci->username, strlen(ci->username), pwd1)) - { - free(pwd1); - return 1; - } - if (!(pwd2 = malloc(MD5_PASSWD_LEN + 1))) - { - free(pwd1); - return 1; - } - if (!EncryptMD5(pwd1 + strlen("md5"), salt, 4, pwd2)) - { - free(pwd2); - free(pwd1); - return 1; - } - free(pwd1); - SOCK_put_int(sock, 4 + strlen(pwd2) + 1, 4); - SOCK_put_n_char(sock, pwd2, strlen(pwd2) + 1); - SOCK_flush_output(sock); - free(pwd2); - return 0; -} - -char -CC_connect(ConnectionClass *self, char password_req, char *salt_para) -{ - StartupPacket sp; - StartupPacket6_2 sp62; - QResultClass *res; - SocketClass *sock; - ConnInfo *ci = &(self->connInfo); - int areq = -1; - int beresp; - static char msgbuffer[ERROR_MSG_LENGTH]; - char salt[5], notice[512]; - static char *func = "CC_connect"; - -#ifdef MULTIBYTE - char *encoding; -#endif /* MULTIBYTE */ - - mylog("%s: entering...\n", func); - - if (password_req != AUTH_REQ_OK) - - sock = self->sock; /* already connected, just authenticate */ - - else - { - qlog("Global Options: Version='%s', fetch=%d, socket=%d, unknown_sizes=%d, max_varchar_size=%d, max_longvarchar_size=%d\n", - POSTGRESDRIVERVERSION, - ci->drivers.fetch_max, - ci->drivers.socket_buffersize, - ci->drivers.unknown_sizes, - ci->drivers.max_varchar_size, - ci->drivers.max_longvarchar_size); - qlog(" disable_optimizer=%d, ksqo=%d, unique_index=%d, use_declarefetch=%d\n", - ci->drivers.disable_optimizer, - ci->drivers.ksqo, - ci->drivers.unique_index, - ci->drivers.use_declarefetch); - qlog(" text_as_longvarchar=%d, unknowns_as_longvarchar=%d, bools_as_char=%d NAMEDATALEN=%d\n", - ci->drivers.text_as_longvarchar, - ci->drivers.unknowns_as_longvarchar, - ci->drivers.bools_as_char, - MAX_TABLE_LEN); - -#ifdef MULTIBYTE - encoding = check_client_encoding(ci->conn_settings); - if (encoding && strcmp(encoding, "OTHER")) - self->client_encoding = strdup(encoding); - else - { - encoding = check_client_encoding(ci->drivers.conn_settings); - if (encoding && strcmp(encoding, "OTHER")) - self->client_encoding = strdup(encoding); - } - if (self->client_encoding) - self->ccsc = pg_CS_code(self->client_encoding); - qlog(" extra_systable_prefixes='%s', conn_settings='%s' conn_encoding='%s'\n", - ci->drivers.extra_systable_prefixes, - ci->drivers.conn_settings, - encoding ? encoding : ""); -#else - qlog(" extra_systable_prefixes='%s', conn_settings='%s'\n", - ci->drivers.extra_systable_prefixes, - ci->drivers.conn_settings); -#endif - - if (self->status != CONN_NOT_CONNECTED) - { - self->errormsg = "Already connected."; - self->errornumber = CONN_OPENDB_ERROR; - return 0; - } - - if (ci->server[0] == '\0' || ci->port[0] == '\0' || ci->database[0] == '\0') - { - self->errornumber = CONN_INIREAD_ERROR; - self->errormsg = "Missing server name, port, or database name in call to CC_connect."; - return 0; - } - - mylog("CC_connect(): DSN = '%s', server = '%s', port = '%s', database = '%s', username = '%s', password='%s'\n", ci->dsn, ci->server, ci->port, ci->database, ci->username, ci->password); - -another_version_retry: - - /* - * If the socket was closed for some reason (like a SQLDisconnect, - * but no SQLFreeConnect then create a socket now. - */ - if (!self->sock) - { - self->sock = SOCK_Constructor(self); - if (!self->sock) - { - self->errornumber = CONNECTION_SERVER_NOT_REACHED; - self->errormsg = "Could not open a socket to the server"; - return 0; - } - } - - sock = self->sock; - - mylog("connecting to the server socket...\n"); - - SOCK_connect_to(sock, (short) atoi(ci->port), ci->server); - if (SOCK_get_errcode(sock) != 0) - { - mylog("connection to the server socket failed.\n"); - self->errornumber = CONNECTION_SERVER_NOT_REACHED; - self->errormsg = "Could not connect to the server"; - return 0; - } - mylog("connection to the server socket succeeded.\n"); - - if (PROTOCOL_62(ci)) - { - sock->reverse = TRUE; /* make put_int and get_int work - * for 6.2 */ - - memset(&sp62, 0, sizeof(StartupPacket6_2)); - SOCK_put_int(sock, htonl(4 + sizeof(StartupPacket6_2)), 4); - sp62.authtype = htonl(NO_AUTHENTICATION); - strncpy(sp62.database, ci->database, PATH_SIZE); - strncpy(sp62.user, ci->username, USRNAMEDATALEN); - SOCK_put_n_char(sock, (char *) &sp62, sizeof(StartupPacket6_2)); - SOCK_flush_output(sock); - } - else - { - memset(&sp, 0, sizeof(StartupPacket)); - - mylog("sizeof startup packet = %d\n", sizeof(StartupPacket)); - - /* Send length of Authentication Block */ - SOCK_put_int(sock, 4 + sizeof(StartupPacket), 4); - - if (PROTOCOL_63(ci)) - sp.protoVersion = (ProtocolVersion) htonl(PG_PROTOCOL_63); - else - sp.protoVersion = (ProtocolVersion) htonl(PG_PROTOCOL_LATEST); - - strncpy(sp.database, ci->database, SM_DATABASE); - strncpy(sp.user, ci->username, SM_USER); - - SOCK_put_n_char(sock, (char *) &sp, sizeof(StartupPacket)); - SOCK_flush_output(sock); - } - - mylog("sent the authentication block.\n"); - - if (sock->errornumber != 0) - { - mylog("couldn't send the authentication block properly.\n"); - self->errornumber = CONN_INVALID_AUTHENTICATION; - self->errormsg = "Sending the authentication packet failed"; - return 0; - } - mylog("sent the authentication block successfully.\n"); - } - - - mylog("gonna do authentication\n"); - - - /* - * Now get the authentication request from backend - */ - - if (!PROTOCOL_62(ci)) - { - BOOL before_64 = PG_VERSION_LT(self, 6.4), - ReadyForQuery = FALSE; - - do - { - if (password_req != AUTH_REQ_OK) - beresp = 'R'; - else - { - beresp = SOCK_get_char(sock); - mylog("auth got '%c'\n", beresp); - } - - switch (beresp) - { - case 'E': - - SOCK_get_string(sock, msgbuffer, ERROR_MSG_LENGTH); - self->errornumber = CONN_INVALID_AUTHENTICATION; - self->errormsg = msgbuffer; - qlog("ERROR from backend during authentication: '%s'\n", self->errormsg); - if (strncmp(msgbuffer, "Unsupported frontend protocol", 29) == 0) - { /* retry older version */ - if (PROTOCOL_63(ci)) - strcpy(ci->protocol, PG62); - else - strcpy(ci->protocol, PG63); - SOCK_Destructor(sock); - self->sock = (SocketClass *) 0; - CC_initialize_pg_version(self); - goto another_version_retry; - } - - return 0; - case 'R': - - if (password_req != AUTH_REQ_OK) - { - mylog("in 'R' password_req=%s\n", ci->password); - areq = password_req; - if (salt_para) - memcpy(salt, salt_para, sizeof(salt)); - password_req = AUTH_REQ_OK; - } - else - { - - areq = SOCK_get_int(sock, 4); - if (areq == AUTH_REQ_MD5) - SOCK_get_n_char(sock, salt, 4); - else if (areq == AUTH_REQ_CRYPT) - SOCK_get_n_char(sock, salt, 2); - - mylog("areq = %d\n", areq); - } - switch (areq) - { - case AUTH_REQ_OK: - break; - - case AUTH_REQ_KRB4: - self->errormsg = "Kerberos 4 authentication not supported"; - self->errornumber = CONN_AUTH_TYPE_UNSUPPORTED; - return 0; - - case AUTH_REQ_KRB5: - self->errormsg = "Kerberos 5 authentication not supported"; - self->errornumber = CONN_AUTH_TYPE_UNSUPPORTED; - return 0; - - case AUTH_REQ_PASSWORD: - mylog("in AUTH_REQ_PASSWORD\n"); - - if (ci->password[0] == '\0') - { - self->errornumber = CONNECTION_NEED_PASSWORD; - self->errormsg = "A password is required for this connection."; - return -areq; /* need password */ - } - - mylog("past need password\n"); - - SOCK_put_int(sock, 4 + strlen(ci->password) + 1, 4); - SOCK_put_n_char(sock, ci->password, strlen(ci->password) + 1); - SOCK_flush_output(sock); - - mylog("past flush\n"); - break; - - case AUTH_REQ_CRYPT: - self->errormsg = "Password crypt authentication not supported"; - self->errornumber = CONN_AUTH_TYPE_UNSUPPORTED; - return 0; - case AUTH_REQ_MD5: - mylog("in AUTH_REQ_MD5\n"); - if (ci->password[0] == '\0') - { - self->errornumber = CONNECTION_NEED_PASSWORD; - self->errormsg = "A password is required for this connection."; - if (salt_para) - memcpy(salt_para, salt, sizeof(salt)); - return -areq; /* need password */ - } - if (md5_auth_send(self, salt)) - { - self->errormsg = "md5 hashing failed"; - self->errornumber = CONN_INVALID_AUTHENTICATION; - return 0; - } - break; - - case AUTH_REQ_SCM_CREDS: - self->errormsg = "Unix socket credential authentication not supported"; - self->errornumber = CONN_AUTH_TYPE_UNSUPPORTED; - return 0; - - default: - self->errormsg = "Unknown authentication type"; - self->errornumber = CONN_AUTH_TYPE_UNSUPPORTED; - return 0; - } - break; - case 'K': /* Secret key (6.4 protocol) */ - self->be_pid = SOCK_get_int(sock, 4); /* pid */ - self->be_key = SOCK_get_int(sock, 4); /* key */ - - break; - case 'Z': /* Backend is ready for new query (6.4) */ - ReadyForQuery = TRUE; - break; - case 'N': /* Notices may come */ - while (SOCK_get_string(sock, notice, sizeof(notice) - 1)) ; - break; - default: - self->errormsg = "Unexpected protocol character during authentication"; - self->errornumber = CONN_INVALID_AUTHENTICATION; - return 0; - } - - /* - * There were no ReadyForQuery responce before 6.4. - */ - if (before_64 && areq == AUTH_REQ_OK) - ReadyForQuery = TRUE; - } while (!ReadyForQuery); - } - - - CC_clear_error(self); /* clear any password error */ - - /* - * send an empty query in order to find out whether the specified - * database really exists on the server machine - */ - mylog("sending an empty query...\n"); - - res = CC_send_query(self, " ", NULL, CLEAR_RESULT_ON_ABORT); - if (res == NULL || QR_get_status(res) != PGRES_EMPTY_QUERY) - { - mylog("got no result from the empty query. (probably database does not exist)\n"); - self->errornumber = CONNECTION_NO_SUCH_DATABASE; - self->errormsg = "The database does not exist on the server\nor user authentication failed."; - if (res != NULL) - QR_Destructor(res); - return 0; - } - if (res) - QR_Destructor(res); - - mylog("empty query seems to be OK.\n"); - - CC_set_translation(self); - - /* - * Send any initial settings - */ - - /* - * Get the version number first so we can check it before sending options - * that are now obsolete. DJP 21/06/2002 - */ - - CC_lookup_pg_version(self); /* Get PostgreSQL version for - SQLGetInfo use */ - /* - * Since these functions allocate statements, and since the connection - * is not established yet, it would violate odbc state transition - * rules. Therefore, these functions call the corresponding local - * function instead. - */ - CC_send_settings(self); - CC_lookup_lo(self); /* a hack to get the oid of - our large object oid type */ - - /* - * Multibyte handling is available ? - */ -#ifdef MULTIBYTE - if (PG_VERSION_GE(self, 6.4)) - { - CC_lookup_characterset(self); - if (self->errornumber != 0) - return 0; -#ifdef UNICODE_SUPPORT - if (self->unicode) - { - if (!self->client_encoding || - stricmp(self->client_encoding, "UNICODE")) - { - QResultClass *res; - if (PG_VERSION_LT(self, 7.1)) - { - self->errornumber = CONN_NOT_IMPLEMENTED_ERROR; - self->errormsg = "UTF-8 conversion isn't implemented before 7.1"; - return 0; - } - if (self->client_encoding) - free(self->client_encoding); - self->client_encoding = NULL; - if (res = CC_send_query(self, "set client_encoding to 'UTF8'", NULL, CLEAR_RESULT_ON_ABORT), res) - { - self->client_encoding = strdup("UNICODE"); - self->ccsc = pg_CS_code(self->client_encoding); - QR_Destructor(res); - - } - } - } -#else - { - } -#endif /* UNICODE_SUPPORT */ - } -#ifdef UNICODE_SUPPORT - else if (self->unicode) - { - self->errornumber = CONN_NOT_IMPLEMENTED_ERROR; - self->errormsg = "Unicode isn't supported before 6.4"; - return 0; - } -#endif /* UNICODE_SUPPORT */ -#endif /* MULTIBYTE */ - ci->updatable_cursors = 0; -#ifdef DRIVER_CURSOR_IMPLEMENT - if (!ci->drivers.use_declarefetch && - PG_VERSION_GE(self, 7.0)) /* Tid scan since 7.0 */ - ci->updatable_cursors = ci->allow_keyset; -#endif /* DRIVER_CURSOR_IMPLEMENT */ - - CC_clear_error(self); /* clear any initial command errors */ - self->status = CONN_CONNECTED; - - mylog("%s: returning...\n", func); - - return 1; - -} - - -char -CC_add_statement(ConnectionClass *self, StatementClass *stmt) -{ - int i; - - mylog("CC_add_statement: self=%u, stmt=%u\n", self, stmt); - - for (i = 0; i < self->num_stmts; i++) - { - if (!self->stmts[i]) - { - stmt->hdbc = self; - self->stmts[i] = stmt; - return TRUE; - } - } - - /* no more room -- allocate more memory */ - self->stmts = (StatementClass **) realloc(self->stmts, sizeof(StatementClass *) * (STMT_INCREMENT + self->num_stmts)); - if (!self->stmts) - return FALSE; - - memset(&self->stmts[self->num_stmts], 0, sizeof(StatementClass *) * STMT_INCREMENT); - - stmt->hdbc = self; - self->stmts[self->num_stmts] = stmt; - - self->num_stmts += STMT_INCREMENT; - - return TRUE; -} - - -char -CC_remove_statement(ConnectionClass *self, StatementClass *stmt) -{ - int i; - - for (i = 0; i < self->num_stmts; i++) - { - if (self->stmts[i] == stmt && stmt->status != STMT_EXECUTING) - { - self->stmts[i] = NULL; - return TRUE; - } - } - - return FALSE; -} - - -/* - * Create a more informative error message by concatenating the connection - * error message with its socket error message. - */ -char * -CC_create_errormsg(ConnectionClass *self) -{ - SocketClass *sock = self->sock; - int pos; - static char msg[4096]; - - mylog("enter CC_create_errormsg\n"); - - msg[0] = '\0'; - - if (self->errormsg) - strcpy(msg, self->errormsg); - - mylog("msg = '%s'\n", msg); - - if (sock && sock->errormsg && sock->errormsg[0] != '\0') - { - pos = strlen(msg); - sprintf(&msg[pos], ";\n%s", sock->errormsg); - } - - mylog("exit CC_create_errormsg\n"); - return msg; -} - - -char -CC_get_error(ConnectionClass *self, int *number, char **message) -{ - int rv; - - mylog("enter CC_get_error\n"); - - /* Create a very informative errormsg if it hasn't been done yet. */ - if (!self->errormsg_created) - { - self->errormsg = CC_create_errormsg(self); - self->errormsg_created = TRUE; - } - - if (self->errornumber) - { - *number = self->errornumber; - *message = self->errormsg; - } - rv = (self->errornumber != 0); - - self->errornumber = 0; /* clear the error */ - - mylog("exit CC_get_error\n"); - - return rv; -} - - -void CC_on_commit(ConnectionClass *conn) -{ - if (CC_is_in_trans(conn)) - { -#ifdef DRIVER_CURSOR_IMPLEMENT - if (conn->result_uncommitted) - ProcessRollback(conn, FALSE); -#endif /* DRIVER_CURSOR_IMPLEMENT */ - CC_set_no_trans(conn); - } - conn->result_uncommitted = 0; -} -void CC_on_abort(ConnectionClass *conn, UDWORD opt) -{ - if (CC_is_in_trans(conn)) - { -#ifdef DRIVER_CURSOR_IMPLEMENT - if (conn->result_uncommitted) - ProcessRollback(conn, TRUE); -#endif /* DRIVER_CURSOR_IMPLEMENT */ - if (0 != (opt & NO_TRANS)) - CC_set_no_trans(conn); - } - if (0 != (opt & CONN_DEAD)) - conn->status = CONN_DOWN; - conn->result_uncommitted = 0; -} - -/* - * The "result_in" is only used by QR_next_tuple() to fetch another group of rows into - * the same existing QResultClass (this occurs when the tuple cache is depleted and - * needs to be re-filled). - * - * The "cursor" is used by SQLExecute to associate a statement handle as the cursor name - * (i.e., C3326857) for SQL select statements. This cursor is then used in future - * 'declare cursor C3326857 for ...' and 'fetch 100 in C3326857' statements. - */ -QResultClass * -CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, UDWORD flag) -{ - QResultClass *cmdres = NULL, - *retres = NULL, - *res = NULL; - BOOL clear_result_on_abort = ((flag & CLEAR_RESULT_ON_ABORT) != 0), - create_keyset = ((flag & CREATE_KEYSET) != 0), - issue_begin = ((flag & GO_INTO_TRANSACTION) != 0 && !CC_is_in_trans(self)); - char swallow, *wq, *ptr; - int id; - SocketClass *sock = self->sock; - int maxlen, - empty_reqs; - BOOL msg_truncated, - ReadyToReturn, - query_completed = FALSE, - before_64 = PG_VERSION_LT(self, 6.4), - aborted = FALSE, - used_passed_result_object = FALSE; - UDWORD abort_opt; - - /* ERROR_MSG_LENGTH is suffcient */ - static char msgbuffer[ERROR_MSG_LENGTH + 1]; - - /* QR_set_command() dups this string so doesn't need static */ - char cmdbuffer[ERROR_MSG_LENGTH + 1]; - - mylog("send_query(): conn=%u, query='%s'\n", self, query); - qlog("conn=%u, query='%s'\n", self, query); - - /* Indicate that we are sending a query to the backend */ - maxlen = CC_get_max_query_len(self); - if (maxlen > 0 && maxlen < (int) strlen(query) + 1) - { - self->errornumber = CONNECTION_MSG_TOO_LONG; - self->errormsg = "Query string is too long"; - return NULL; - } - - if ((NULL == query) || (query[0] == '\0')) - return NULL; - - if (SOCK_get_errcode(sock) != 0) - { - self->errornumber = CONNECTION_COULD_NOT_SEND; - self->errormsg = "Could not send Query to backend"; - CC_on_abort(self, NO_TRANS | CONN_DEAD); - return NULL; - } - - SOCK_put_char(sock, 'Q'); - if (SOCK_get_errcode(sock) != 0) - { - self->errornumber = CONNECTION_COULD_NOT_SEND; - self->errormsg = "Could not send Query to backend"; - CC_on_abort(self, NO_TRANS | CONN_DEAD); - return NULL; - } - - if (issue_begin) - SOCK_put_n_char(sock, "begin;", 6); - SOCK_put_string(sock, query); - SOCK_flush_output(sock); - - if (SOCK_get_errcode(sock) != 0) - { - self->errornumber = CONNECTION_COULD_NOT_SEND; - self->errormsg = "Could not send Query to backend"; - CC_on_abort(self, NO_TRANS | CONN_DEAD); - return NULL; - } - - mylog("send_query: done sending query\n"); - - ReadyToReturn = FALSE; - empty_reqs = 0; - for (wq = query; isspace((unsigned char) *wq); wq++) - ; - if (*wq == '\0') - empty_reqs = 1; - cmdres = qi ? qi->result_in : NULL; - if (cmdres) - used_passed_result_object = TRUE; - else - { - cmdres = QR_Constructor(); - if (!cmdres) - { - self->errornumber = CONNECTION_COULD_NOT_RECEIVE; - self->errormsg = "Could not create result info in send_query."; - return NULL; - } - } - res = cmdres; - while (!ReadyToReturn) - { - /* what type of message is coming now ? */ - id = SOCK_get_char(sock); - - if ((SOCK_get_errcode(sock) != 0) || (id == EOF)) - { - self->errornumber = CONNECTION_NO_RESPONSE; - self->errormsg = "No response from the backend"; - - mylog("send_query: 'id' - %s\n", self->errormsg); - CC_on_abort(self, NO_TRANS | CONN_DEAD); - ReadyToReturn = TRUE; - retres = NULL; - break; - } - - mylog("send_query: got id = '%c'\n", id); - - switch (id) - { - case 'A': /* Asynchronous Messages are ignored */ - (void) SOCK_get_int(sock, 4); /* id of notification */ - SOCK_get_string(sock, msgbuffer, ERROR_MSG_LENGTH); - /* name of the relation the message comes from */ - break; - case 'C': /* portal query command, no tuples - * returned */ - /* read in the return message from the backend */ - SOCK_get_string(sock, cmdbuffer, ERROR_MSG_LENGTH); - if (SOCK_get_errcode(sock) != 0) - { - self->errornumber = CONNECTION_NO_RESPONSE; - self->errormsg = "No response from backend while receiving a portal query command"; - mylog("send_query: 'C' - %s\n", self->errormsg); - CC_on_abort(self, NO_TRANS | CONN_DEAD); - ReadyToReturn = TRUE; - retres = NULL; - } - else - { - mylog("send_query: ok - 'C' - %s\n", cmdbuffer); - - if (query_completed) /* allow for "show" style notices */ - { - res->next = QR_Constructor(); - res = res->next; - } - - mylog("send_query: setting cmdbuffer = '%s'\n", cmdbuffer); - - if (strnicmp(cmdbuffer, "BEGIN", 5) == 0) - { - CC_set_in_trans(self); - if (issue_begin) - { - issue_begin = FALSE; - continue; - } - } - else if (strnicmp(cmdbuffer, "COMMIT", 6) == 0) - CC_on_commit(self); - else if (strnicmp(cmdbuffer, "ROLLBACK", 8) == 0) - CC_on_abort(self, NO_TRANS); - else if (strnicmp(cmdbuffer, "END", 3) == 0) - CC_on_commit(self); - else if (strnicmp(cmdbuffer, "ABORT", 5) == 0) - CC_on_abort(self, NO_TRANS); - else - { - trim(cmdbuffer); /* get rid of trailing space */ - ptr = strrchr(cmdbuffer, ' '); - if (ptr) - res->recent_processed_row_count = atoi(ptr + 1); - else - res->recent_processed_row_count = -1; - } - - if (QR_command_successful(res)) - QR_set_status(res, PGRES_COMMAND_OK); - QR_set_command(res, cmdbuffer); - query_completed = TRUE; - mylog("send_query: returning res = %u\n", res); - if (!before_64) - break; - - /* - * (Quotation from the original comments) since - * backend may produce more than one result for some - * commands we need to poll until clear so we send an - * empty query, and keep reading out of the pipe until - * an 'I' is received - */ - - if (empty_reqs == 0) - { - SOCK_put_string(sock, "Q "); - SOCK_flush_output(sock); - empty_reqs++; - } - } - break; - case 'Z': /* Backend is ready for new query (6.4) */ - if (empty_reqs == 0) - { - ReadyToReturn = TRUE; - if (aborted || query_completed) - retres = cmdres; - else - ReadyToReturn = FALSE; - } - break; - case 'N': /* NOTICE: */ - msg_truncated = SOCK_get_string(sock, cmdbuffer, ERROR_MSG_LENGTH); - if (QR_command_successful(res)) - QR_set_status(res, PGRES_NONFATAL_ERROR); - QR_set_notice(res, cmdbuffer); /* will dup this string */ - mylog("~~~ NOTICE: '%s'\n", cmdbuffer); - qlog("NOTICE from backend during send_query: '%s'\n", cmdbuffer); - while (msg_truncated) - msg_truncated = SOCK_get_string(sock, cmdbuffer, ERROR_MSG_LENGTH); - - continue; /* dont return a result -- continue - * reading */ - - case 'I': /* The server sends an empty query */ - /* There is a closing '\0' following the 'I', so we eat it */ - swallow = SOCK_get_char(sock); - if ((swallow != '\0') || SOCK_get_errcode(sock) != 0) - { - self->errornumber = CONNECTION_BACKEND_CRAZY; - QR_set_message(res, "Unexpected protocol character from backend (send_query - I)"); - QR_set_status(res, PGRES_FATAL_ERROR); - ReadyToReturn = TRUE; - retres = cmdres; - break; - } - else - { - /* We return the empty query */ - QR_set_status(res, PGRES_EMPTY_QUERY); - } - if (empty_reqs > 0) - { - if (--empty_reqs == 0) - query_completed = TRUE; - } - break; - case 'E': - msg_truncated = SOCK_get_string(sock, msgbuffer, ERROR_MSG_LENGTH); - - /* Remove a newline */ - if (msgbuffer[0] != '\0' && msgbuffer[strlen(msgbuffer) - 1] == '\n') - msgbuffer[strlen(msgbuffer) - 1] = '\0'; - - - mylog("send_query: 'E' - %s\n", msgbuffer); - qlog("ERROR from backend during send_query: '%s'\n", msgbuffer); - - /* We should report that an error occured. Zoltan */ - abort_opt = 0; - if (!strncmp(msgbuffer, "FATAL", 5)) - { - self->errornumber = CONNECTION_SERVER_REPORTED_ERROR; - abort_opt = NO_TRANS | CONN_DEAD; - } - else - self->errornumber = CONNECTION_SERVER_REPORTED_WARNING; - CC_on_abort(self, abort_opt); - QR_set_status(res, PGRES_FATAL_ERROR); - QR_set_message(res, msgbuffer); - QR_set_aborted(res, TRUE); - aborted = TRUE; - while (msg_truncated) - msg_truncated = SOCK_get_string(sock, cmdbuffer, ERROR_MSG_LENGTH); - - query_completed = TRUE; - break; - - case 'P': /* get the Portal name */ - SOCK_get_string(sock, msgbuffer, ERROR_MSG_LENGTH); - break; - case 'T': /* Tuple results start here */ - if (query_completed) - { - res->next = QR_Constructor(); - if (!res->next) - { - self->errornumber = CONNECTION_COULD_NOT_RECEIVE; - self->errormsg = "Could not create result info in send_query."; - ReadyToReturn = TRUE; - retres = NULL; - break; - } - if (create_keyset) - QR_set_haskeyset(res->next); - mylog("send_query: 'T' no result_in: res = %u\n", res->next); - res = res->next; - - if (qi) - QR_set_cache_size(res, qi->row_size); - } - if (!used_passed_result_object) - { - if (create_keyset) - QR_set_haskeyset(res); - if (!QR_fetch_tuples(res, self, qi ? qi->cursor : NULL)) - { - self->errornumber = CONNECTION_COULD_NOT_RECEIVE; - self->errormsg = QR_get_message(res); - ReadyToReturn = TRUE; - if (PGRES_FATAL_ERROR == QR_get_status(res)) - retres = cmdres; - else - retres = NULL; - break; - } - query_completed = TRUE; - } - else - { /* next fetch, so reuse an existing result */ - - /* - * called from QR_next_tuple and must return - * immediately. - */ - ReadyToReturn = TRUE; - if (!QR_fetch_tuples(res, NULL, NULL)) - { - self->errornumber = CONNECTION_COULD_NOT_RECEIVE; - self->errormsg = QR_get_message(res); - retres = NULL; - break; - } - retres = cmdres; - } - break; - case 'D': /* Copy in command began successfully */ - if (query_completed) - { - res->next = QR_Constructor(); - res = res->next; - } - QR_set_status(res, PGRES_COPY_IN); - ReadyToReturn = TRUE; - retres = cmdres; - break; - case 'B': /* Copy out command began successfully */ - if (query_completed) - { - res->next = QR_Constructor(); - res = res->next; - } - QR_set_status(res, PGRES_COPY_OUT); - ReadyToReturn = TRUE; - retres = cmdres; - break; - default: - self->errornumber = CONNECTION_BACKEND_CRAZY; - self->errormsg = "Unexpected protocol character from backend (send_query)"; - CC_on_abort(self, NO_TRANS | CONN_DEAD); - - mylog("send_query: error - %s\n", self->errormsg); - ReadyToReturn = TRUE; - retres = NULL; - break; - } - - /* - * There were no ReadyForQuery response before 6.4. - */ - if (before_64) - { - if (empty_reqs == 0 && query_completed) - break; - } - } - - /* - * Break before being ready to return. - */ - if (!ReadyToReturn) - retres = cmdres; - - /* - * Cleanup garbage results before returning. - */ - if (cmdres && retres != cmdres && !used_passed_result_object) - QR_Destructor(cmdres); - /* - * Cleanup the aborted result if specified - */ - if (retres) - { - if (aborted) - { - if (clear_result_on_abort) - { - if (!used_passed_result_object) - { - QR_Destructor(retres); - retres = NULL; - } - } - if (retres) - { - /* - * discard results other than errors. - */ - QResultClass *qres; - for (qres = retres; qres->next; qres = retres) - { - if (QR_get_aborted(qres)) - break; - retres = qres->next; - qres->next = NULL; - QR_Destructor(qres); - } - /* - * If error message isn't set - */ - if (retres && (!self->errormsg || !self->errormsg[0])) - self->errormsg = QR_get_message(retres); - } - } - } - return retres; -} - - -int -CC_send_function(ConnectionClass *self, int fnid, void *result_buf, int *actual_result_len, int result_is_int, LO_ARG *args, int nargs) -{ - char id, - c, - done; - SocketClass *sock = self->sock; - - /* ERROR_MSG_LENGTH is sufficient */ - static char msgbuffer[ERROR_MSG_LENGTH + 1]; - int i; - - mylog("send_function(): conn=%u, fnid=%d, result_is_int=%d, nargs=%d\n", self, fnid, result_is_int, nargs); - - if (SOCK_get_errcode(sock) != 0) - { - self->errornumber = CONNECTION_COULD_NOT_SEND; - self->errormsg = "Could not send function to backend"; - CC_on_abort(self, NO_TRANS | CONN_DEAD); - return FALSE; - } - - SOCK_put_string(sock, "F "); - if (SOCK_get_errcode(sock) != 0) - { - self->errornumber = CONNECTION_COULD_NOT_SEND; - self->errormsg = "Could not send function to backend"; - CC_on_abort(self, NO_TRANS | CONN_DEAD); - return FALSE; - } - - SOCK_put_int(sock, fnid, 4); - SOCK_put_int(sock, nargs, 4); - - - mylog("send_function: done sending function\n"); - - for (i = 0; i < nargs; ++i) - { - mylog(" arg[%d]: len = %d, isint = %d, integer = %d, ptr = %u\n", i, args[i].len, args[i].isint, args[i].u.integer, args[i].u.ptr); - - SOCK_put_int(sock, args[i].len, 4); - if (args[i].isint) - SOCK_put_int(sock, args[i].u.integer, 4); - else - SOCK_put_n_char(sock, (char *) args[i].u.ptr, args[i].len); - - - } - - mylog(" done sending args\n"); - - SOCK_flush_output(sock); - mylog(" after flush output\n"); - - done = FALSE; - while (!done) - { - id = SOCK_get_char(sock); - mylog(" got id = %c\n", id); - - switch (id) - { - case 'V': - done = TRUE; - break; /* ok */ - - case 'N': - SOCK_get_string(sock, msgbuffer, ERROR_MSG_LENGTH); - mylog("send_function(V): 'N' - %s\n", msgbuffer); - /* continue reading */ - break; - - case 'E': - SOCK_get_string(sock, msgbuffer, ERROR_MSG_LENGTH); - self->errormsg = msgbuffer; - CC_on_abort(self, 0); - - mylog("send_function(V): 'E' - %s\n", self->errormsg); - qlog("ERROR from backend during send_function: '%s'\n", self->errormsg); - - return FALSE; - - case 'Z': - break; - - default: - self->errornumber = CONNECTION_BACKEND_CRAZY; - self->errormsg = "Unexpected protocol character from backend (send_function, args)"; - CC_on_abort(self, NO_TRANS | CONN_DEAD); - - mylog("send_function: error - %s\n", self->errormsg); - return FALSE; - } - } - - id = SOCK_get_char(sock); - for (;;) - { - switch (id) - { - case 'G': /* function returned properly */ - mylog(" got G!\n"); - - *actual_result_len = SOCK_get_int(sock, 4); - mylog(" actual_result_len = %d\n", *actual_result_len); - - if (result_is_int) - *((int *) result_buf) = SOCK_get_int(sock, 4); - else - SOCK_get_n_char(sock, (char *) result_buf, *actual_result_len); - - mylog(" after get result\n"); - - c = SOCK_get_char(sock); /* get the last '0' */ - - mylog(" after get 0\n"); - - return TRUE; - - case 'E': - SOCK_get_string(sock, msgbuffer, ERROR_MSG_LENGTH); - self->errormsg = msgbuffer; - CC_on_abort(self, 0); - mylog("send_function(G): 'E' - %s\n", self->errormsg); - qlog("ERROR from backend during send_function: '%s'\n", self->errormsg); - - return FALSE; - - case 'N': - SOCK_get_string(sock, msgbuffer, ERROR_MSG_LENGTH); - - mylog("send_function(G): 'N' - %s\n", msgbuffer); - qlog("NOTICE from backend during send_function: '%s'\n", msgbuffer); - - continue; /* dont return a result -- continue - * reading */ - - case '0': /* empty result */ - return TRUE; - - default: - self->errornumber = CONNECTION_BACKEND_CRAZY; - self->errormsg = "Unexpected protocol character from backend (send_function, result)"; - CC_on_abort(self, NO_TRANS | CONN_DEAD); - - mylog("send_function: error - %s\n", self->errormsg); - return FALSE; - } - } -} - - -char -CC_send_settings(ConnectionClass *self) -{ - /* char ini_query[MAX_MESSAGE_LEN]; */ - ConnInfo *ci = &(self->connInfo); - -/* QResultClass *res; */ - HSTMT hstmt; - StatementClass *stmt; - RETCODE result; - char status = TRUE; - char *cs, - *ptr; - static char *func = "CC_send_settings"; - - - mylog("%s: entering...\n", func); - -/* - * This function must use the local odbc API functions since the odbc state - * has not transitioned to "connected" yet. - */ - - result = PGAPI_AllocStmt(self, &hstmt); - if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) - return FALSE; - stmt = (StatementClass *) hstmt; - - stmt->internal = TRUE; /* ensure no BEGIN/COMMIT/ABORT stuff */ - - /* Set the Datestyle to the format the driver expects it to be in */ - result = PGAPI_ExecDirect(hstmt, "set DateStyle to 'ISO'", SQL_NTS); - if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) - status = FALSE; - - mylog("%s: result %d, status %d from set DateStyle\n", func, result, status); - - /* Disable genetic optimizer based on global flag */ - if (ci->drivers.disable_optimizer) - { - result = PGAPI_ExecDirect(hstmt, "set geqo to 'OFF'", SQL_NTS); - if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) - status = FALSE; - - mylog("%s: result %d, status %d from set geqo\n", func, result, status); - - } - - /* KSQO (not applicable to 7.1+ - DJP 21/06/2002) */ - if (ci->drivers.ksqo && PG_VERSION_LT(self, 7.1)) - { - result = PGAPI_ExecDirect(hstmt, "set ksqo to 'ON'", SQL_NTS); - if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) - status = FALSE; - - mylog("%s: result %d, status %d from set ksqo\n", func, result, status); - - } - - /* Global settings */ - if (ci->drivers.conn_settings[0] != '\0') - { - cs = strdup(ci->drivers.conn_settings); - ptr = strtok(cs, ";"); - while (ptr) - { - result = PGAPI_ExecDirect(hstmt, ptr, SQL_NTS); - if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) - status = FALSE; - - mylog("%s: result %d, status %d from '%s'\n", func, result, status, ptr); - - ptr = strtok(NULL, ";"); - } - - free(cs); - } - - /* Per Datasource settings */ - if (ci->conn_settings[0] != '\0') - { - cs = strdup(ci->conn_settings); - ptr = strtok(cs, ";"); - while (ptr) - { - result = PGAPI_ExecDirect(hstmt, ptr, SQL_NTS); - if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) - status = FALSE; - - mylog("%s: result %d, status %d from '%s'\n", func, result, status, ptr); - - ptr = strtok(NULL, ";"); - } - - free(cs); - } - - - PGAPI_FreeStmt(hstmt, SQL_DROP); - - return status; -} - - -/* - * This function is just a hack to get the oid of our Large Object oid type. - * If a real Large Object oid type is made part of Postgres, this function - * will go away and the define 'PG_TYPE_LO' will be updated. - */ -void -CC_lookup_lo(ConnectionClass *self) -{ - HSTMT hstmt; - StatementClass *stmt; - RETCODE result; - static char *func = "CC_lookup_lo"; - - mylog("%s: entering...\n", func); - -/* - * This function must use the local odbc API functions since the odbc state - * has not transitioned to "connected" yet. - */ - result = PGAPI_AllocStmt(self, &hstmt); - if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) - return; - stmt = (StatementClass *) hstmt; - - result = PGAPI_ExecDirect(hstmt, "select oid from pg_type where typname='" PG_TYPE_LO_NAME "'", SQL_NTS); - if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) - { - PGAPI_FreeStmt(hstmt, SQL_DROP); - return; - } - - result = PGAPI_Fetch(hstmt); - if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) - { - PGAPI_FreeStmt(hstmt, SQL_DROP); - return; - } - - result = PGAPI_GetData(hstmt, 1, SQL_C_SLONG, &self->lobj_type, sizeof(self->lobj_type), NULL); - if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) - { - PGAPI_FreeStmt(hstmt, SQL_DROP); - return; - } - - mylog("Got the large object oid: %d\n", self->lobj_type); - qlog(" [ Large Object oid = %d ]\n", self->lobj_type); - - result = PGAPI_FreeStmt(hstmt, SQL_DROP); -} - - -/* - * This function initializes the version of PostgreSQL from - * connInfo.protocol that we're connected to. - * h-inoue 01-2-2001 - */ -void -CC_initialize_pg_version(ConnectionClass *self) -{ - strcpy(self->pg_version, self->connInfo.protocol); - if (PROTOCOL_62(&self->connInfo)) - { - self->pg_version_number = (float) 6.2; - self->pg_version_major = 6; - self->pg_version_minor = 2; - } - else if (PROTOCOL_63(&self->connInfo)) - { - self->pg_version_number = (float) 6.3; - self->pg_version_major = 6; - self->pg_version_minor = 3; - } - else - { - self->pg_version_number = (float) 6.4; - self->pg_version_major = 6; - self->pg_version_minor = 4; - } -} - - -/* - * This function gets the version of PostgreSQL that we're connected to. - * This is used to return the correct info in SQLGetInfo - * DJP - 25-1-2001 - */ -void -CC_lookup_pg_version(ConnectionClass *self) -{ - HSTMT hstmt; - StatementClass *stmt; - RETCODE result; - char szVersion[32]; - int major, - minor; - static char *func = "CC_lookup_pg_version"; - - mylog("%s: entering...\n", func); - -/* - * This function must use the local odbc API functions since the odbc state - * has not transitioned to "connected" yet. - */ - result = PGAPI_AllocStmt(self, &hstmt); - if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) - return; - stmt = (StatementClass *) hstmt; - - /* get the server's version if possible */ - result = PGAPI_ExecDirect(hstmt, "select version()", SQL_NTS); - if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) - { - PGAPI_FreeStmt(hstmt, SQL_DROP); - return; - } - - result = PGAPI_Fetch(hstmt); - if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) - { - PGAPI_FreeStmt(hstmt, SQL_DROP); - return; - } - - result = PGAPI_GetData(hstmt, 1, SQL_C_CHAR, self->pg_version, MAX_INFO_STRING, NULL); - if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) - { - PGAPI_FreeStmt(hstmt, SQL_DROP); - return; - } - - /* - * Extract the Major and Minor numbers from the string. This assumes - * the string starts 'Postgresql X.X' - */ - strcpy(szVersion, "0.0"); - if (sscanf(self->pg_version, "%*s %d.%d", &major, &minor) >= 2) - { - sprintf(szVersion, "%d.%d", major, minor); - self->pg_version_major = major; - self->pg_version_minor = minor; - } - self->pg_version_number = (float) atof(szVersion); - if (PG_VERSION_GE(self, 7.3)) - self->schema_support = 1; - - mylog("Got the PostgreSQL version string: '%s'\n", self->pg_version); - mylog("Extracted PostgreSQL version number: '%1.1f'\n", self->pg_version_number); - qlog(" [ PostgreSQL version string = '%s' ]\n", self->pg_version); - qlog(" [ PostgreSQL version number = '%1.1f' ]\n", self->pg_version_number); - - result = PGAPI_FreeStmt(hstmt, SQL_DROP); -} - - -void -CC_log_error(const char *func, const char *desc, const ConnectionClass *self) -{ -#ifdef PRN_NULLCHECK -#define nullcheck(a) (a ? a : "(NULL)") -#endif - - if (self) - { - qlog("CONN ERROR: func=%s, desc='%s', errnum=%d, errmsg='%s'\n", func, desc, self->errornumber, nullcheck(self->errormsg)); - mylog("CONN ERROR: func=%s, desc='%s', errnum=%d, errmsg='%s'\n", func, desc, self->errornumber, nullcheck(self->errormsg)); - qlog(" ------------------------------------------------------------\n"); - qlog(" henv=%u, conn=%u, status=%u, num_stmts=%d\n", self->henv, self, self->status, self->num_stmts); - qlog(" sock=%u, stmts=%u, lobj_type=%d\n", self->sock, self->stmts, self->lobj_type); - - qlog(" ---------------- Socket Info -------------------------------\n"); - if (self->sock) - { - SocketClass *sock = self->sock; - - qlog(" socket=%d, reverse=%d, errornumber=%d, errormsg='%s'\n", sock->socket, sock->reverse, sock->errornumber, nullcheck(sock->errormsg)); - qlog(" buffer_in=%u, buffer_out=%u\n", sock->buffer_in, sock->buffer_out); - qlog(" buffer_filled_in=%d, buffer_filled_out=%d, buffer_read_in=%d\n", sock->buffer_filled_in, sock->buffer_filled_out, sock->buffer_read_in); - } - } - else -{ - qlog("INVALID CONNECTION HANDLE ERROR: func=%s, desc='%s'\n", func, desc); - mylog("INVALID CONNECTION HANDLE ERROR: func=%s, desc='%s'\n", func, desc); -} -#undef PRN_NULLCHECK -} - -int -CC_get_max_query_len(const ConnectionClass *conn) -{ - int value; - - /* Long Queries in 7.0+ */ - if (PG_VERSION_GE(conn, 7.0)) - value = 0 /* MAX_STATEMENT_LEN */ ; - /* Prior to 7.0 we used 2*BLCKSZ */ - else if (PG_VERSION_GE(conn, 6.5)) - value = (2 * BLCKSZ); - else - /* Prior to 6.5 we used BLCKSZ */ - value = BLCKSZ; - return value; -} - -/* - * This deosn't really return the CURRENT SCHEMA - * but there's no alternative. - */ -const char * -CC_get_current_schema(ConnectionClass *conn) -{ - if (!conn->current_schema && conn->schema_support) - { - QResultClass *res; - - if (res = CC_send_query(conn, "select current_schema()", NULL, CLEAR_RESULT_ON_ABORT), res) - { - if (QR_get_num_total_tuples(res) == 1) - conn->current_schema = strdup(QR_get_value_backend_row(res, 0, 0)); - QR_Destructor(res); - } - } - return (const char *) conn->current_schema; -} - -int -CC_send_cancel_request(const ConnectionClass *conn) -{ -#ifdef WIN32 - int save_errno = (WSAGetLastError()); -#else - int save_errno = errno; -#endif - int tmpsock = -1; - struct - { - uint32 packetlen; - CancelRequestPacket cp; - } crp; - - /* Check we have an open connection */ - if (!conn) - return FALSE; - - if (conn->sock == NULL ) - { - return FALSE; - } - - /* - * We need to open a temporary connection to the postmaster. Use the - * information saved by connectDB to do this with only kernel calls. - */ - if ((tmpsock = socket(AF_INET, SOCK_STREAM, 0)) < 0) - { - return FALSE; - } - if (connect(tmpsock, (struct sockaddr *)&(conn->sock->sadr), - sizeof(conn->sock->sadr)) < 0) - { - return FALSE; - } - - /* - * We needn't set nonblocking I/O or NODELAY options here. - */ - crp.packetlen = htonl((uint32) sizeof(crp)); - crp.cp.cancelRequestCode = (MsgType) htonl(CANCEL_REQUEST_CODE); - crp.cp.backendPID = htonl(conn->be_pid); - crp.cp.cancelAuthCode = htonl(conn->be_key); - - if (send(tmpsock, (char *) &crp, sizeof(crp), 0) != (int) sizeof(crp)) - { - return FALSE; - } - - /* Sent it, done */ - closesocket(tmpsock); -#ifdef WIN32 - WSASetLastError(save_errno); -#else - errno = save_errno; -#endif - return TRUE; -} diff --git a/src/interfaces/odbc/connection.h b/src/interfaces/odbc/connection.h deleted file mode 100644 index 133b4920c00..00000000000 --- a/src/interfaces/odbc/connection.h +++ /dev/null @@ -1,359 +0,0 @@ -/* File: connection.h - * - * Description: See "connection.c" - * - * Comments: See "notice.txt" for copyright and license information. - * - */ - -#ifndef __CONNECTION_H__ -#define __CONNECTION_H__ - -#include "psqlodbc.h" - -#include <stdlib.h> -#include <string.h> -#include "descriptor.h" - - -typedef enum -{ - CONN_NOT_CONNECTED, /* Connection has not been established */ - CONN_CONNECTED, /* Connection is up and has been - * established */ - CONN_DOWN, /* Connection is broken */ - CONN_EXECUTING /* the connection is currently executing a - * statement */ -} CONN_Status; - -/* These errors have general sql error state */ -#define CONNECTION_SERVER_NOT_REACHED 101 -#define CONNECTION_MSG_TOO_LONG 103 -#define CONNECTION_COULD_NOT_SEND 104 -#define CONNECTION_NO_SUCH_DATABASE 105 -#define CONNECTION_BACKEND_CRAZY 106 -#define CONNECTION_NO_RESPONSE 107 -#define CONNECTION_SERVER_REPORTED_ERROR 108 -#define CONNECTION_COULD_NOT_RECEIVE 109 -#define CONNECTION_SERVER_REPORTED_WARNING 110 -#define CONNECTION_NEED_PASSWORD 112 - -/* These errors correspond to specific SQL states */ -#define CONN_INIREAD_ERROR 201 -#define CONN_OPENDB_ERROR 202 -#define CONN_STMT_ALLOC_ERROR 203 -#define CONN_IN_USE 204 -#define CONN_UNSUPPORTED_OPTION 205 -/* Used by SetConnectoption to indicate unsupported options */ -#define CONN_INVALID_ARGUMENT_NO 206 -/* SetConnectOption: corresponds to ODBC--"S1009" */ -#define CONN_TRANSACT_IN_PROGRES 207 -#define CONN_NO_MEMORY_ERROR 208 -#define CONN_NOT_IMPLEMENTED_ERROR 209 -#define CONN_INVALID_AUTHENTICATION 210 -#define CONN_AUTH_TYPE_UNSUPPORTED 211 -#define CONN_UNABLE_TO_LOAD_DLL 212 - -#define CONN_OPTION_VALUE_CHANGED 213 -#define CONN_VALUE_OUT_OF_RANGE 214 - -#define CONN_TRUNCATED 215 - -/* Conn_status defines */ -#define CONN_IN_AUTOCOMMIT 0x01 -#define CONN_IN_TRANSACTION 0x02 - -/* AutoCommit functions */ -#define CC_set_autocommit_off(x) (x->transact_status &= ~CONN_IN_AUTOCOMMIT) -#define CC_set_autocommit_on(x) (x->transact_status |= CONN_IN_AUTOCOMMIT) -#define CC_is_in_autocommit(x) (x->transact_status & CONN_IN_AUTOCOMMIT) - -/* Transaction in/not functions */ -#define CC_set_in_trans(x) (x->transact_status |= CONN_IN_TRANSACTION) -#define CC_set_no_trans(x) (x->transact_status &= ~CONN_IN_TRANSACTION) -#define CC_is_in_trans(x) (x->transact_status & CONN_IN_TRANSACTION) - - -/* Authentication types */ -#define AUTH_REQ_OK 0 -#define AUTH_REQ_KRB4 1 -#define AUTH_REQ_KRB5 2 -#define AUTH_REQ_PASSWORD 3 -#define AUTH_REQ_CRYPT 4 -#define AUTH_REQ_MD5 5 -#define AUTH_REQ_SCM_CREDS 6 - -/* Startup Packet sizes */ -#define SM_DATABASE 64 -#define SM_USER 32 -#define SM_OPTIONS 64 -#define SM_UNUSED 64 -#define SM_TTY 64 - -/* Old 6.2 protocol defines */ -#define NO_AUTHENTICATION 7 -#define PATH_SIZE 64 -#define ARGV_SIZE 64 -#define USRNAMEDATALEN 16 - -typedef unsigned int ProtocolVersion; - -#define PG_PROTOCOL(major, minor) (((major) << 16) | (minor)) -#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 (6.4, 6.3) */ -typedef struct _StartupPacket -{ - ProtocolVersion protoVersion; - char database[SM_DATABASE]; - char user[SM_USER]; - char options[SM_OPTIONS]; - char unused[SM_UNUSED]; - char tty[SM_TTY]; -} 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[USRNAMEDATALEN]; - char options[ARGV_SIZE]; - char execfile[ARGV_SIZE]; - char tty[PATH_SIZE]; -} StartupPacket6_2; - -/* Transferred from pqcomm.h: */ - - -typedef ProtocolVersion MsgType; - -#define PG_PROTOCOL(m,n) (((m) << 16) | (n)) -#define CANCEL_REQUEST_CODE PG_PROTOCOL(1234,5678) - -typedef struct CancelRequestPacket -{ - /* Note that each field is stored in network byte order! */ - MsgType cancelRequestCode; /* code to identify a cancel request */ - unsigned int backendPID; /* PID of client's backend */ - unsigned int cancelAuthCode; /* secret key to authorize cancel */ -} CancelRequestPacket; - -/* Structure to hold all the connection attributes for a specific - connection (used for both registry and file, DSN and DRIVER) -*/ -typedef struct -{ - char dsn[MEDIUM_REGISTRY_LEN]; - char desc[MEDIUM_REGISTRY_LEN]; - char driver[MEDIUM_REGISTRY_LEN]; - char server[MEDIUM_REGISTRY_LEN]; - char database[MEDIUM_REGISTRY_LEN]; - char username[MEDIUM_REGISTRY_LEN]; - char password[MEDIUM_REGISTRY_LEN]; - char conn_settings[LARGE_REGISTRY_LEN]; - char protocol[SMALL_REGISTRY_LEN]; - char port[SMALL_REGISTRY_LEN]; - char onlyread[SMALL_REGISTRY_LEN]; - char fake_oid_index[SMALL_REGISTRY_LEN]; - char show_oid_column[SMALL_REGISTRY_LEN]; - char row_versioning[SMALL_REGISTRY_LEN]; - char show_system_tables[SMALL_REGISTRY_LEN]; - char translation_dll[MEDIUM_REGISTRY_LEN]; - char translation_option[SMALL_REGISTRY_LEN]; - char focus_password; - char disallow_premature; - char allow_keyset; - char updatable_cursors; - char lf_conversion; - char true_is_minus1; - char int8_as; - GLOBAL_VALUES drivers; /* moved from driver's option */ -} 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 - * 1st parameter: pointer to a ConnectionClass object - * 2nd parameter: major version number - * 3rd parameter: minor version number - */ -#define SERVER_VERSION_GT(conn, major, minor) \ - ((conn)->pg_version_major > major || \ - ((conn)->pg_version_major == major && (conn)->pg_version_minor > minor)) -#define SERVER_VERSION_GE(conn, major, minor) \ - ((conn)->pg_version_major > major || \ - ((conn)->pg_version_major == major && (conn)->pg_version_minor >= minor)) -#define SERVER_VERSION_EQ(conn, major, minor) \ - ((conn)->pg_version_major == major && (conn)->pg_version_minor == minor) -#define SERVER_VERSION_LE(conn, major, minor) (! SERVER_VERSION_GT(conn, major, minor)) -#define SERVER_VERSION_LT(conn, major, minor) (! SERVER_VERSION_GE(conn, major, minor)) -/*#if ! defined(HAVE_CONFIG_H) || defined(HAVE_STRINGIZE)*/ -#define STRING_AFTER_DOT(string) (strchr(#string, '.') + 1) -/*#else -#define STRING_AFTER_DOT(str) (strchr("str", '.') + 1) -#endif*/ -/* - * Simplified macros to compare the server's version with a - * specified version - * Note: Never pass a variable as the second parameter. - * It must be a decimal constant of the form %d.%d . - */ -#define PG_VERSION_GT(conn, ver) \ - (SERVER_VERSION_GT(conn, (int) ver, atoi(STRING_AFTER_DOT(ver)))) -#define PG_VERSION_GE(conn, ver) \ - (SERVER_VERSION_GE(conn, (int) ver, atoi(STRING_AFTER_DOT(ver)))) -#define PG_VERSION_EQ(conn, ver) \ - (SERVER_VERSION_EQ(conn, (int) ver, atoi(STRING_AFTER_DOT(ver)))) -#define PG_VERSION_LE(conn, ver) (! PG_VERSION_GT(conn, ver)) -#define PG_VERSION_LT(conn, ver) (! PG_VERSION_GE(conn, ver)) - -/* This is used to store cached table information in the connection */ -struct col_info -{ - QResultClass *result; - char *schema; - char name[MAX_TABLE_LEN + 1]; -}; - - /* Translation DLL entry points */ -#ifdef WIN32 -#define DLLHANDLE HINSTANCE -#else -#define WINAPI CALLBACK -#define DLLHANDLE void * -#define HINSTANCE void * -#endif - -typedef BOOL (FAR WINAPI * DataSourceToDriverProc) (UDWORD, - SWORD, - PTR, - SDWORD, - PTR, - SDWORD, - SDWORD FAR *, - UCHAR FAR *, - SWORD, - SWORD FAR *); - -typedef BOOL (FAR WINAPI * DriverToDataSourceProc) (UDWORD, - SWORD, - PTR, - SDWORD, - PTR, - SDWORD, - SDWORD FAR *, - UCHAR FAR *, - SWORD, - SWORD FAR *); - -/******* The Connection handle ************/ -struct ConnectionClass_ -{ - HENV henv; /* environment this connection was created - * on */ - StatementOptions stmtOptions; - ARDFields ardOptions; - APDFields apdOptions; - char *errormsg; - int errornumber; - CONN_Status status; - ConnInfo connInfo; - StatementClass **stmts; - int num_stmts; - SocketClass *sock; - int lobj_type; - int ntables; - COL_INFO **col_info; - long translation_option; - HINSTANCE translation_handle; - DataSourceToDriverProc DataSourceToDriver; - DriverToDataSourceProc DriverToDataSource; - Int2 driver_version; /* prepared for ODBC3.0 */ - char transact_status;/* Is a transaction is currently in - * progress */ - char errormsg_created; /* has an informative error msg - * been created? */ - char pg_version[MAX_INFO_STRING]; /* Version of PostgreSQL - * we're connected to - - * DJP 25-1-2001 */ - float pg_version_number; - Int2 pg_version_major; - Int2 pg_version_minor; - char ms_jet; - char unicode; - char result_uncommitted; - char schema_support; -#ifdef MULTIBYTE - char *client_encoding; - char *server_encoding; -#endif /* MULTIBYTE */ - int ccsc; - int be_pid; /* pid returned by backend */ - int be_key; /* auth code needed to send cancel */ - UInt4 isolation; - char *current_schema; -}; - - -/* Accessor functions */ -#define CC_get_socket(x) (x->sock) -#define CC_get_database(x) (x->connInfo.database) -#define CC_get_server(x) (x->connInfo.server) -#define CC_get_DSN(x) (x->connInfo.dsn) -#define CC_get_username(x) (x->connInfo.username) -#define CC_is_onlyread(x) (x->connInfo.onlyread[0] == '1') - - -/* for CC_DSN_info */ -#define CONN_DONT_OVERWRITE 0 -#define CONN_OVERWRITE 1 - - -/* prototypes */ -ConnectionClass *CC_Constructor(void); -void CC_conninfo_init(ConnInfo *conninfo); -char CC_Destructor(ConnectionClass *self); -int CC_cursor_count(ConnectionClass *self); -char CC_cleanup(ConnectionClass *self); -char CC_begin(ConnectionClass *self); -char CC_commit(ConnectionClass *self); -char CC_abort(ConnectionClass *self); -int CC_set_translation(ConnectionClass *self); -char CC_connect(ConnectionClass *self, char password_req, char *salt); -char CC_add_statement(ConnectionClass *self, StatementClass *stmt); -char CC_remove_statement(ConnectionClass *self, StatementClass *stmt); -char CC_get_error(ConnectionClass *self, int *number, char **message); -QResultClass *CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, UDWORD flag); -void CC_clear_error(ConnectionClass *self); -char *CC_create_errormsg(ConnectionClass *self); -int CC_send_function(ConnectionClass *conn, int fnid, void *result_buf, int *actual_result_len, int result_is_int, LO_ARG *argv, int nargs); -char CC_send_settings(ConnectionClass *self); -void CC_lookup_lo(ConnectionClass *conn); -void CC_lookup_pg_version(ConnectionClass *conn); -void CC_initialize_pg_version(ConnectionClass *conn); -void CC_log_error(const char *func, const char *desc, const ConnectionClass *self); -int CC_get_max_query_len(const ConnectionClass *self); -int CC_send_cancel_request(const ConnectionClass *conn); -void CC_on_commit(ConnectionClass *conn); -void CC_on_abort(ConnectionClass *conn, UDWORD opt); -void ProcessRollback(ConnectionClass *conn, BOOL undo); -const char *CC_get_current_schema(ConnectionClass *conn); - -/* CC_send_query options */ -#define CLEAR_RESULT_ON_ABORT 1L -#define CREATE_KEYSET (1L << 1) /* create keyset for updatable curosrs */ -#define GO_INTO_TRANSACTION (1L << 2) /* issue begin in advance */ -/* CC_on_abort options */ -#define NO_TRANS 1L -#define CONN_DEAD (1L << 1) /* connection is no longer valid */ - -#endif /* __CONNECTION_H__ */ diff --git a/src/interfaces/odbc/convert.c b/src/interfaces/odbc/convert.c deleted file mode 100644 index 2b586192320..00000000000 --- a/src/interfaces/odbc/convert.c +++ /dev/null @@ -1,3578 +0,0 @@ -/*------- - * Module: convert.c - * - * Description: This module contains routines related to - * converting parameters and columns into requested data types. - * Parameters are converted from their SQL_C data types into - * the appropriate postgres type. Columns are converted from - * their postgres type (SQL type) into the appropriate SQL_C - * data type. - * - * Classes: n/a - * - * API functions: none - * - * Comments: See "notice.txt" for copyright and license information. - *------- - */ -/* Multibyte support Eiji Tokuya 2001-03-15 */ - -#include "convert.h" - -#include <stdio.h> -#include <string.h> -#include <ctype.h> - -#ifdef MULTIBYTE -#include "multibyte.h" -#endif - -#include <time.h> -#ifdef HAVE_LOCALE_H -#include <locale.h> -#endif -#include <math.h> -#include <stdlib.h> -#include "statement.h" -#include "qresult.h" -#include "bind.h" -#include "pgtypes.h" -#include "lobj.h" -#include "connection.h" -#include "pgapifunc.h" - -#ifdef __CYGWIN__ -#define TIMEZONE_GLOBAL _timezone -#elif defined(WIN32) || defined(HAVE_INT_TIMEZONE) -#define TIMEZONE_GLOBAL timezone -#endif - -/* - * How to map ODBC scalar functions {fn func(args)} to Postgres. - * This is just a simple substitution. List augmented from: - * http://www.merant.com/datadirect/download/docs/odbc16/Odbcref/rappc.htm - * - thomas 2000-04-03 - */ -char *mapFuncs[][2] = { -/* { "ASCII", "ascii" }, built_in */ - {"CHAR", "chr($*)" }, - {"CONCAT", "textcat($*)" }, -/* { "DIFFERENCE", "difference" }, how to ? */ - {"INSERT", "substring($1 from 1 for $2 - 1) || $4 || substring($1 from $2 + $3)" }, - {"LCASE", "lower($*)" }, - {"LEFT", "ltrunc($*)" }, - {"%2LOCATE", "strpos($2, $1)" }, /* 2 parameters */ - {"%3LOCATE", "strpos(substring($2 from $3), $1) + $3 - 1" }, /* 3 parameters */ - {"LENGTH", "char_length($*)"}, -/* { "LTRIM", "ltrim" }, built_in */ - {"RIGHT", "rtrunc($*)" }, - {"SPACE", "repeat('' '', $1)" }, -/* { "REPEAT", "repeat" }, built_in */ -/* { "REPLACE", "replace" }, ??? */ -/* { "RTRIM", "rtrim" }, built_in */ -/* { "SOUNDEX", "soundex" }, how to ? */ - {"SUBSTRING", "substr($*)" }, - {"UCASE", "upper($*)" }, - -/* { "ABS", "abs" }, built_in */ -/* { "ACOS", "acos" }, built_in */ -/* { "ASIN", "asin" }, built_in */ -/* { "ATAN", "atan" }, built_in */ -/* { "ATAN2", "atan2" }, bui;t_in */ - {"CEILING", "ceil($*)" }, -/* { "COS", "cos" }, built_in */ -/* { "COT", "cot" }, built_in */ -/* { "DEGREES", "degrees" }, built_in */ -/* { "EXP", "exp" }, built_in */ -/* { "FLOOR", "floor" }, built_in */ - {"LOG", "ln($*)" }, - {"LOG10", "log($*)" }, -/* { "MOD", "mod" }, built_in */ -/* { "PI", "pi" }, built_in */ - {"POWER", "pow($*)" }, -/* { "RADIANS", "radians" }, built_in */ - {"%0RAND", "random()" }, /* 0 parameters */ - {"%1RAND", "(setseed($1) * .0 + random())" }, /* 1 parameters */ -/* { "ROUND", "round" }, built_in */ -/* { "SIGN", "sign" }, built_in */ -/* { "SIN", "sin" }, built_in */ -/* { "SQRT", "sqrt" }, built_in */ -/* { "TAN", "tan" }, built_in */ - {"TRUNCATE", "trunc($*)" }, - - {"CURRENT_DATE", "current_date" }, - {"CURRENT_TIME", "current_time" }, - {"CURRENT_TIMESTAMP", "current_timestamp" }, - {"LOCALTIME", "localtime" }, - {"LOCALTIMESTAMP", "localtimestamp" }, - {"CURRENT_USER", "cast(current_user as text)" }, - {"SESSION_USER", "cast(session_user as text)" }, - {"CURDATE", "current_date" }, - {"CURTIME", "current_time" }, - {"DAYNAME", "to_char($1, 'Day')" }, - {"DAYOFMONTH", "cast(extract(day from $1) as integer)" }, - {"DAYOFWEEK", "(cast(extract(dow from $1) as integer) + 1)" }, - {"DAYOFYEAR", "cast(extract(doy from $1) as integer)" }, - {"HOUR", "cast(extract(hour from $1) as integer)" }, - {"MINUTE", "cast(extract(minute from $1) as integer)" }, - {"MONTH", "cast(extract(month from $1) as integer)" }, - {"MONTHNAME", " to_char($1, 'Month')" }, -/* { "NOW", "now" }, built_in */ - {"QUARTER", "cast(extract(quarter from $1) as integer)" }, - {"SECOND", "cast(extract(second from $1) as integer)" }, - {"WEEK", "cast(extract(week from $1) as integer)" }, - {"YEAR", "cast(extract(year from $1) as integer)" }, - -/* { "DATABASE", "database" }, */ - {"IFNULL", "coalesce($*)" }, - {"USER", "cast(current_user as text)" }, - {0, 0} -}; - -static const char *mapFunction(const char *func, int param_count); -static unsigned int conv_from_octal(const unsigned char *s); -static unsigned int conv_from_hex(const unsigned char *s); -static char *conv_to_octal(unsigned char val); - -/*--------- - * A Guide for date/time/timestamp conversions - * - * field_type fCType Output - * ---------- ------ ---------- - * PG_TYPE_DATE SQL_C_DEFAULT SQL_C_DATE - * PG_TYPE_DATE SQL_C_DATE SQL_C_DATE - * PG_TYPE_DATE SQL_C_TIMESTAMP SQL_C_TIMESTAMP (time = 0 (midnight)) - * PG_TYPE_TIME SQL_C_DEFAULT SQL_C_TIME - * PG_TYPE_TIME SQL_C_TIME SQL_C_TIME - * PG_TYPE_TIME SQL_C_TIMESTAMP SQL_C_TIMESTAMP (date = current date) - * PG_TYPE_ABSTIME SQL_C_DEFAULT SQL_C_TIMESTAMP - * PG_TYPE_ABSTIME SQL_C_DATE SQL_C_DATE (time is truncated) - * PG_TYPE_ABSTIME SQL_C_TIME SQL_C_TIME (date is truncated) - * PG_TYPE_ABSTIME SQL_C_TIMESTAMP SQL_C_TIMESTAMP - *--------- - */ - - - -/* - * TIMESTAMP <-----> SIMPLE_TIME - * precision support since 7.2. - * time zone support is unavailable(the stuff is unreliable) - */ -static BOOL -timestamp2stime(const char *str, SIMPLE_TIME *st, BOOL *bZone, int *zone) -{ - char rest[64], - *ptr; - int scnt, - i; -#if defined(WIN32) || defined(HAVE_INT_TIMEZONE) - long timediff; -#endif - BOOL withZone = *bZone; - - *bZone = FALSE; - *zone = 0; - st->fr = 0; - st->infinity = 0; - if ((scnt = sscanf(str, "%4d-%2d-%2d %2d:%2d:%2d%s", &st->y, &st->m, &st->d, &st->hh, &st->mm, &st->ss, rest)) < 6) - return FALSE; - else if (scnt == 6) - return TRUE; - switch (rest[0]) - { - case '+': - *bZone = TRUE; - *zone = atoi(&rest[1]); - break; - case '-': - *bZone = TRUE; - *zone = -atoi(&rest[1]); - break; - case '.': - if ((ptr = strchr(rest, '+')) != NULL) - { - *bZone = TRUE; - *zone = atoi(&ptr[1]); - *ptr = '\0'; - } - else if ((ptr = strchr(rest, '-')) != NULL) - { - *bZone = TRUE; - *zone = -atoi(&ptr[1]); - *ptr = '\0'; - } - for (i = 1; i < 10; i++) - { - if (!isdigit((unsigned char) rest[i])) - break; - } - for (; i < 10; i++) - rest[i] = '0'; - rest[i] = '\0'; - st->fr = atoi(&rest[1]); - break; - default: - return TRUE; - } - if (!withZone || !*bZone || st->y < 1970) - return TRUE; -#if defined(WIN32) || defined(HAVE_INT_TIMEZONE) - if (!tzname[0] || !tzname[0][0]) - { - *bZone = FALSE; - return TRUE; - } - timediff = TIMEZONE_GLOBAL + (*zone) * 3600; - if (!daylight && timediff == 0) /* the same timezone */ - return TRUE; - else - { - struct tm tm, - *tm2; - time_t time0; - - *bZone = FALSE; - tm.tm_year = st->y - 1900; - tm.tm_mon = st->m - 1; - tm.tm_mday = st->d; - tm.tm_hour = st->hh; - tm.tm_min = st->mm; - tm.tm_sec = st->ss; - tm.tm_isdst = -1; - time0 = mktime(&tm); - if (time0 < 0) - return TRUE; - if (tm.tm_isdst > 0) - timediff -= 3600; - if (timediff == 0) /* the same time zone */ - return TRUE; - time0 -= timediff; - if (time0 >= 0 && (tm2 = localtime(&time0)) != NULL) - { - st->y = tm2->tm_year + 1900; - st->m = tm2->tm_mon + 1; - st->d = tm2->tm_mday; - st->hh = tm2->tm_hour; - st->mm = tm2->tm_min; - st->ss = tm2->tm_sec; - *bZone = TRUE; - } - } -#endif /* WIN32 */ - return TRUE; -} - -static BOOL -stime2timestamp(const SIMPLE_TIME *st, char *str, BOOL bZone, BOOL precision) -{ - char precstr[16], - zonestr[16]; - int i; - - precstr[0] = '\0'; - if (st->infinity > 0) - { - strcpy(str, "Infinity"); - return TRUE; - } - else if (st->infinity < 0) - { - strcpy(str, "-Infinity"); - return TRUE; - } - if (precision && st->fr) - { - sprintf(precstr, ".%09d", st->fr); - for (i = 9; i > 0; i--) - { - if (precstr[i] != '0') - break; - precstr[i] = '\0'; - } - } - zonestr[0] = '\0'; -#if defined(WIN32) || defined(HAVE_INT_TIMEZONE) - if (bZone && tzname[0] && tzname[0][0] && st->y >= 1970) - { - long zoneint; - struct tm tm; - time_t time0; - - zoneint = TIMEZONE_GLOBAL; - if (daylight && st->y >= 1900) - { - tm.tm_year = st->y - 1900; - tm.tm_mon = st->m - 1; - tm.tm_mday = st->d; - tm.tm_hour = st->hh; - tm.tm_min = st->mm; - tm.tm_sec = st->ss; - tm.tm_isdst = -1; - time0 = mktime(&tm); - if (time0 >= 0 && tm.tm_isdst > 0) - zoneint -= 3600; - } - if (zoneint > 0) - sprintf(zonestr, "-%02d", (int) zoneint / 3600); - else - sprintf(zonestr, "+%02d", -(int) zoneint / 3600); - } -#endif /* WIN32 */ - sprintf(str, "%.4d-%.2d-%.2d %.2d:%.2d:%.2d%s%s", st->y, st->m, st->d, st->hh, st->mm, st->ss, precstr, zonestr); - return TRUE; -} - -/* This is called by SQLFetch() */ -int -copy_and_convert_field_bindinfo(StatementClass *stmt, Int4 field_type, void *value, int col) -{ - ARDFields *opts = SC_get_ARD(stmt); - BindInfoClass *bic = &(opts->bindings[col]); - UInt4 offset = opts->row_offset_ptr ? *opts->row_offset_ptr : 0; - - return copy_and_convert_field(stmt, field_type, value, (Int2) bic->returntype, (PTR) (bic->buffer + offset), - (SDWORD) bic->buflen, (SDWORD *) (bic->used + (offset >> 2))); -} - - -/* This is called by SQLGetData() */ -int -copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2 fCType, - PTR rgbValue, SDWORD cbValueMax, SDWORD *pcbValue) -{ - static char *func = "copy_and_convert_field"; - ARDFields *opts = SC_get_ARD(stmt); - Int4 len = 0, - copy_len = 0; - SIMPLE_TIME st; - time_t t = time(NULL); - struct tm *tim; - int pcbValueOffset, - rgbValueOffset; - char *rgbValueBindRow; - const char *ptr; - int bind_row = stmt->bind_row; - int bind_size = opts->bind_size; - int result = COPY_OK; -#ifdef HAVE_LOCALE_H - char saved_locale[256]; -#endif /* HAVE_LOCALE_H */ - BOOL changed, true_is_minus1 = FALSE; - const char *neut_str = value; - char midtemp[2][32]; - int mtemp_cnt = 0; - static BindInfoClass sbic; - BindInfoClass *pbic; -#ifdef UNICODE_SUPPORT - BOOL wchanged = FALSE; -#endif /* UNICODE_SUPPORT */ - - if (stmt->current_col >= 0) - { - pbic = &opts->bindings[stmt->current_col]; - if (pbic->data_left == -2) - pbic->data_left = (cbValueMax > 0) ? 0 : -1; /* This seems to be * - * needed by ADO ? */ - if (pbic->data_left == 0) - { - if (pbic->ttlbuf != NULL) - { - free(pbic->ttlbuf); - pbic->ttlbuf = NULL; - pbic->ttlbuflen = 0; - } - pbic->data_left = -2; /* needed by ADO ? */ - return COPY_NO_DATA_FOUND; - } - } - /*--------- - * rgbValueOffset is *ONLY* for character and binary data. - * pcbValueOffset is for computing any pcbValue location - *--------- - */ - - if (bind_size > 0) - pcbValueOffset = rgbValueOffset = (bind_size * bind_row); - else - { - pcbValueOffset = bind_row * sizeof(SDWORD); - rgbValueOffset = bind_row * cbValueMax; - - } - - memset(&st, 0, sizeof(SIMPLE_TIME)); - - /* Initialize current date */ - tim = localtime(&t); - st.m = tim->tm_mon + 1; - st.d = tim->tm_mday; - st.y = tim->tm_year + 1900; - - mylog("copy_and_convert: field_type = %d, fctype = %d, value = '%s', cbValueMax=%d\n", field_type, fCType, (value == NULL) ? "<NULL>" : value, cbValueMax); - - if (!value) - { - /* - * handle a null just by returning SQL_NULL_DATA in pcbValue, and - * doing nothing to the buffer. - */ - if (pcbValue) - { - *(SDWORD *) ((char *) pcbValue + pcbValueOffset) = SQL_NULL_DATA; - return COPY_OK; - } - else - { - stmt->errornumber = STMT_RETURN_NULL_WITHOUT_INDICATOR; - stmt->errormsg = "StrLen_or_IndPtr was a null pointer and NULL data was retrieved"; - SC_log_error(func, "", stmt); - return SQL_ERROR; - } - } - - if (stmt->hdbc->DataSourceToDriver != NULL) - { - int length = strlen(value); - - stmt->hdbc->DataSourceToDriver(stmt->hdbc->translation_option, - SQL_CHAR, - value, length, - value, length, NULL, - NULL, 0, NULL); - } - - /* - * First convert any specific postgres types into more useable data. - * - * NOTE: Conversions from PG char/varchar of a date/time/timestamp value - * to SQL_C_DATE,SQL_C_TIME, SQL_C_TIMESTAMP not supported - */ - switch (field_type) - { - /* - * $$$ need to add parsing for date/time/timestamp strings in - * PG_TYPE_CHAR,VARCHAR $$$ - */ - case PG_TYPE_DATE: - sscanf(value, "%4d-%2d-%2d", &st.y, &st.m, &st.d); - break; - - case PG_TYPE_TIME: - sscanf(value, "%2d:%2d:%2d", &st.hh, &st.mm, &st.ss); - break; - - case PG_TYPE_ABSTIME: - case PG_TYPE_DATETIME: - case PG_TYPE_TIMESTAMP_NO_TMZONE: - case PG_TYPE_TIMESTAMP: - st.fr = 0; - st.infinity = 0; - if (strnicmp(value, "infinity", 8) == 0) - { - st.infinity = 1; - st.m = 12; - st.d = 31; - st.y = 9999; - st.hh = 23; - st.mm = 59; - st.ss = 59; - } - if (strnicmp(value, "-infinity", 9) == 0) - { - st.infinity = -1; - st.m = 0; - st.d = 0; - st.y = 0; - st.hh = 0; - st.mm = 0; - st.ss = 0; - } - if (strnicmp(value, "invalid", 7) != 0) - { - BOOL bZone = (field_type != PG_TYPE_TIMESTAMP_NO_TMZONE && PG_VERSION_GE(SC_get_conn(stmt), 7.2)); - int zone; - - /* - * sscanf(value, "%4d-%2d-%2d %2d:%2d:%2d", &st.y, &st.m, - * &st.d, &st.hh, &st.mm, &st.ss); - */ - bZone = FALSE; /* time zone stuff is unreliable */ - timestamp2stime(value, &st, &bZone, &zone); - } - else - { - /* - * The timestamp is invalid so set something conspicuous, - * like the epoch - */ - t = 0; - tim = localtime(&t); - st.m = tim->tm_mon + 1; - st.d = tim->tm_mday; - st.y = tim->tm_year + 1900; - st.hh = tim->tm_hour; - st.mm = tim->tm_min; - st.ss = tim->tm_sec; - } - break; - - case PG_TYPE_BOOL: - { /* change T/F to 1/0 */ - char *s; - - s = midtemp[mtemp_cnt]; - switch (((char *)value)[0]) - { - case 'f': - case 'F': - case 'n': - case 'N': - case '0': - strcpy(s, "0"); - break; - default: - if (true_is_minus1) - strcpy(s, "-1"); - else - strcpy(s, "1"); - } - neut_str = midtemp[mtemp_cnt]; - mtemp_cnt++; - } - break; - - /* This is for internal use by SQLStatistics() */ - case PG_TYPE_INT2VECTOR: - { - int nval, - i; - const char *vp; - - /* this is an array of eight integers */ - short *short_array = (short *) ((char *) rgbValue + rgbValueOffset); - - len = 32; - vp = value; - nval = 0; - mylog("index=("); - for (i = 0; i < 16; i++) - { - if (sscanf(vp, "%hd", &short_array[i]) != 1) - break; - - mylog(" %d", short_array[i]); - nval++; - - /* skip the current token */ - while ((*vp != '\0') && (!isspace((unsigned char) *vp))) - vp++; - /* and skip the space to the next token */ - while ((*vp != '\0') && (isspace((unsigned char) *vp))) - vp++; - if (*vp == '\0') - break; - } - mylog(") nval = %d\n", nval); - - for (i = nval; i < 16; i++) - short_array[i] = 0; - -#if 0 - sscanf(value, "%hd %hd %hd %hd %hd %hd %hd %hd", - &short_array[0], - &short_array[1], - &short_array[2], - &short_array[3], - &short_array[4], - &short_array[5], - &short_array[6], - &short_array[7]); -#endif - - /* There is no corresponding fCType for this. */ - if (pcbValue) - *(SDWORD *) ((char *) pcbValue + pcbValueOffset) = len; - - return COPY_OK; /* dont go any further or the data will be - * trashed */ - } - - /* - * This is a large object OID, which is used to store - * LONGVARBINARY objects. - */ - case PG_TYPE_LO: - - return convert_lo(stmt, value, fCType, ((char *) rgbValue + rgbValueOffset), cbValueMax, (SDWORD *) ((char *) pcbValue + pcbValueOffset)); - - default: - - if (field_type == stmt->hdbc->lobj_type) /* hack until permanent - * type available */ - return convert_lo(stmt, value, fCType, ((char *) rgbValue + rgbValueOffset), cbValueMax, (SDWORD *) ((char *) pcbValue + pcbValueOffset)); - } - - /* Change default into something useable */ - if (fCType == SQL_C_DEFAULT) - { - fCType = pgtype_to_ctype(stmt, field_type); - - mylog("copy_and_convert, SQL_C_DEFAULT: fCType = %d\n", fCType); - } - - rgbValueBindRow = (char *) rgbValue + rgbValueOffset; - -#ifdef UNICODE_SUPPORT - if (fCType == SQL_C_CHAR || fCType == SQL_C_WCHAR) -#else - if (fCType == SQL_C_CHAR) -#endif /* UNICODE_SUPPORT */ - { - /* Special character formatting as required */ - - /* - * These really should return error if cbValueMax is not big - * enough. - */ - switch (field_type) - { - case PG_TYPE_DATE: - len = 10; - if (cbValueMax > len) - sprintf(rgbValueBindRow, "%.4d-%.2d-%.2d", st.y, st.m, st.d); - break; - - case PG_TYPE_TIME: - len = 8; - if (cbValueMax > len) - sprintf(rgbValueBindRow, "%.2d:%.2d:%.2d", st.hh, st.mm, st.ss); - break; - - case PG_TYPE_ABSTIME: - case PG_TYPE_DATETIME: - case PG_TYPE_TIMESTAMP_NO_TMZONE: - case PG_TYPE_TIMESTAMP: - len = 19; - if (cbValueMax > len) - sprintf(rgbValueBindRow, "%.4d-%.2d-%.2d %.2d:%.2d:%.2d", - st.y, st.m, st.d, st.hh, st.mm, st.ss); - break; - - case PG_TYPE_BOOL: - len = strlen(neut_str); - if (cbValueMax > len) - { - strcpy(rgbValueBindRow, neut_str); - mylog("PG_TYPE_BOOL: rgbValueBindRow = '%s'\n", rgbValueBindRow); - } - break; - - /* - * Currently, data is SILENTLY TRUNCATED for BYTEA and - * character data types if there is not enough room in - * cbValueMax because the driver can't handle multiple - * calls to SQLGetData for these, yet. Most likely, the - * buffer passed in will be big enough to handle the - * maximum limit of postgres, anyway. - * - * LongVarBinary types are handled correctly above, observing - * truncation and all that stuff since there is - * essentially no limit on the large object used to store - * those. - */ - case PG_TYPE_BYTEA:/* convert binary data to hex strings - * (i.e, 255 = "FF") */ - len = convert_pgbinary_to_char(neut_str, rgbValueBindRow, cbValueMax); - - /***** THIS IS NOT PROPERLY IMPLEMENTED *****/ - break; - - default: - if (stmt->current_col < 0) - { - pbic = &sbic; - pbic->data_left = -1; - } - else - pbic = &opts->bindings[stmt->current_col]; - if (pbic->data_left < 0) - { - BOOL lf_conv = SC_get_conn(stmt)->connInfo.lf_conversion; -#ifdef UNICODE_SUPPORT - if (fCType == SQL_C_WCHAR) - { - len = utf8_to_ucs2_lf(neut_str, -1, lf_conv, NULL, 0); - len *= 2; - wchanged = changed = TRUE; - } - else -#endif /* UNICODE_SUPPORT */ - /* convert linefeeds to carriage-return/linefeed */ - len = convert_linefeeds(neut_str, NULL, 0, lf_conv, &changed); - if (cbValueMax == 0) /* just returns length - * info */ - { - result = COPY_RESULT_TRUNCATED; - break; - } - if (!pbic->ttlbuf) - pbic->ttlbuflen = 0; - if (changed || len >= cbValueMax) - { - if (len >= (int) pbic->ttlbuflen) - { - pbic->ttlbuf = realloc(pbic->ttlbuf, len + 1); - pbic->ttlbuflen = len + 1; - } -#ifdef UNICODE_SUPPORT - if (fCType == SQL_C_WCHAR) - { - utf8_to_ucs2_lf(neut_str, -1, lf_conv, (SQLWCHAR *) pbic->ttlbuf, len / 2); - } - else -#endif /* UNICODE_SUPPORT */ - convert_linefeeds(neut_str, pbic->ttlbuf, pbic->ttlbuflen, lf_conv, &changed); - ptr = pbic->ttlbuf; - } - else - { - if (pbic->ttlbuf) - { - free(pbic->ttlbuf); - pbic->ttlbuf = NULL; - } - ptr = neut_str; - } - } - else - ptr = pbic->ttlbuf; - - mylog("DEFAULT: len = %d, ptr = '%s'\n", len, ptr); - - if (stmt->current_col >= 0) - { - if (pbic->data_left > 0) - { - ptr += strlen(ptr) - pbic->data_left; - len = pbic->data_left; - } - else - pbic->data_left = len; - } - - if (cbValueMax > 0) - { - copy_len = (len >= cbValueMax) ? cbValueMax - 1 : len; - -#ifdef HAVE_LOCALE_H - switch (field_type) - { - case PG_TYPE_FLOAT4: - case PG_TYPE_FLOAT8: - case PG_TYPE_NUMERIC: - { - struct lconv *lc; - char *new_string; - int i, j; - - new_string = malloc( cbValueMax ); - lc = localeconv(); - for (i = 0, j = 0; ptr[i]; i++) - if (ptr[i] == '.') - { - strncpy(&new_string[j], lc->decimal_point, strlen(lc->decimal_point)); - j += strlen(lc->decimal_point); - } - else - new_string[j++] = ptr[i]; - new_string[j] = '\0'; - strncpy_null(rgbValueBindRow, new_string, copy_len + 1); - free(new_string); - break; - } - default: - /* Copy the data */ - strncpy_null(rgbValueBindRow, ptr, copy_len + 1); - } -#else /* HAVE_LOCALE_H */ - /* Copy the data */ - memcpy(rgbValueBindRow, ptr, copy_len); - rgbValueBindRow[copy_len] = '\0'; -#endif /* HAVE_LOCALE_H */ - - /* Adjust data_left for next time */ - if (stmt->current_col >= 0) - pbic->data_left -= copy_len; - } - - /* - * Finally, check for truncation so that proper status can - * be returned - */ - if (cbValueMax > 0 && len >= cbValueMax) - result = COPY_RESULT_TRUNCATED; - else - { - if (pbic->ttlbuf != NULL) - { - free(pbic->ttlbuf); - pbic->ttlbuf = NULL; - } - } - - - mylog(" SQL_C_CHAR, default: len = %d, cbValueMax = %d, rgbValueBindRow = '%s'\n", len, cbValueMax, rgbValueBindRow); - break; - } -#ifdef UNICODE_SUPPORT - if (SQL_C_WCHAR == fCType && ! wchanged) - { - if (cbValueMax > 2 * len) - { - char *str = strdup(rgbValueBindRow); - UInt4 ucount = utf8_to_ucs2(str, len, (SQLWCHAR *) rgbValueBindRow, cbValueMax / 2); - if (cbValueMax < 2 * (SDWORD) ucount) - result = COPY_RESULT_TRUNCATED; - len = ucount * 2; - free(str); - } - else - { - len *= 2; - result = COPY_RESULT_TRUNCATED; - } - } -#endif /* UNICODE_SUPPORT */ - - } - else - { - /* - * for SQL_C_CHAR, it's probably ok to leave currency symbols in. - * But to convert to numeric types, it is necessary to get rid of - * those. - */ - if (field_type == PG_TYPE_MONEY) - { - if (convert_money(neut_str, midtemp[mtemp_cnt], sizeof(midtemp[0]))) - { - neut_str = midtemp[mtemp_cnt]; - mtemp_cnt++; - } - else - return COPY_UNSUPPORTED_TYPE; - } - - switch (fCType) - { - case SQL_C_DATE: -#if (ODBCVER >= 0x0300) - case SQL_C_TYPE_DATE: /* 91 */ -#endif - len = 6; - { - DATE_STRUCT *ds; - - if (bind_size > 0) - ds = (DATE_STRUCT *) ((char *) rgbValue + (bind_row * bind_size)); - else - ds = (DATE_STRUCT *) rgbValue + bind_row; - ds->year = st.y; - ds->month = st.m; - ds->day = st.d; - } - break; - - case SQL_C_TIME: -#if (ODBCVER >= 0x0300) - case SQL_C_TYPE_TIME: /* 92 */ -#endif - len = 6; - { - TIME_STRUCT *ts; - - if (bind_size > 0) - ts = (TIME_STRUCT *) ((char *) rgbValue + (bind_row * bind_size)); - else - ts = (TIME_STRUCT *) rgbValue + bind_row; - ts->hour = st.hh; - ts->minute = st.mm; - ts->second = st.ss; - } - break; - - case SQL_C_TIMESTAMP: -#if (ODBCVER >= 0x0300) - case SQL_C_TYPE_TIMESTAMP: /* 93 */ -#endif - len = 16; - { - TIMESTAMP_STRUCT *ts; - - if (bind_size > 0) - ts = (TIMESTAMP_STRUCT *) ((char *) rgbValue + (bind_row * bind_size)); - else - ts = (TIMESTAMP_STRUCT *) rgbValue + bind_row; - ts->year = st.y; - ts->month = st.m; - ts->day = st.d; - ts->hour = st.hh; - ts->minute = st.mm; - ts->second = st.ss; - ts->fraction = st.fr; - } - break; - - case SQL_C_BIT: - len = 1; - if (bind_size > 0) - *(UCHAR *) ((char *) rgbValue + (bind_row * bind_size)) = atoi(neut_str); - else - *((UCHAR *) rgbValue + bind_row) = atoi(neut_str); - - /* - * mylog("SQL_C_BIT: bind_row = %d val = %d, cb = %d, - * rgb=%d\n", bind_row, atoi(neut_str), cbValueMax, - * *((UCHAR *)rgbValue)); - */ - break; - - case SQL_C_STINYINT: - case SQL_C_TINYINT: - len = 1; - if (bind_size > 0) - *(SCHAR *) ((char *) rgbValue + (bind_row * bind_size)) = atoi(neut_str); - else - *((SCHAR *) rgbValue + bind_row) = atoi(neut_str); - break; - - case SQL_C_UTINYINT: - len = 1; - if (bind_size > 0) - *(UCHAR *) ((char *) rgbValue + (bind_row * bind_size)) = atoi(neut_str); - else - *((UCHAR *) rgbValue + bind_row) = atoi(neut_str); - break; - - case SQL_C_FLOAT: -#ifdef HAVE_LOCALE_H - strcpy(saved_locale, setlocale(LC_ALL, NULL)); - setlocale(LC_ALL, "C"); -#endif /* HAVE_LOCALE_H */ - len = 4; - if (bind_size > 0) - *(SFLOAT *) ((char *) rgbValue + (bind_row * bind_size)) = (float) atof(neut_str); - else - *((SFLOAT *) rgbValue + bind_row) = (float) atof(neut_str); -#ifdef HAVE_LOCALE_H - setlocale(LC_ALL, saved_locale); -#endif /* HAVE_LOCALE_H */ - break; - - case SQL_C_DOUBLE: -#ifdef HAVE_LOCALE_H - strcpy(saved_locale, setlocale(LC_ALL, NULL)); - setlocale(LC_ALL, "C"); -#endif /* HAVE_LOCALE_H */ - len = 8; - if (bind_size > 0) - *(SDOUBLE *) ((char *) rgbValue + (bind_row * bind_size)) = atof(neut_str); - else - *((SDOUBLE *) rgbValue + bind_row) = atof(neut_str); -#ifdef HAVE_LOCALE_H - setlocale(LC_ALL, saved_locale); -#endif /* HAVE_LOCALE_H */ - break; - -#if (ODBCVER >= 0x0300) - case SQL_C_NUMERIC: -#ifdef HAVE_LOCALE_H - /* strcpy(saved_locale, setlocale(LC_ALL, NULL)); - setlocale(LC_ALL, "C"); not needed currently */ -#endif /* HAVE_LOCALE_H */ - { - SQL_NUMERIC_STRUCT *ns; - int i, nlen, bit, hval, tv, dig, sta, olen; - char calv[SQL_MAX_NUMERIC_LEN * 3], *wv; - BOOL dot_exist; - - len = sizeof(SQL_NUMERIC_STRUCT); - if (bind_size > 0) - ns = (SQL_NUMERIC_STRUCT *) ((char *) rgbValue + (bind_row * bind_size)); - else - ns = (SQL_NUMERIC_STRUCT *) rgbValue + bind_row; - for (wv = neut_str; *wv && isspace(*wv); wv++) - ; - ns->sign = 1; - if (*wv == '-') - { - ns->sign = 0; - wv++; - } - else if (*wv == '+') - wv++; - while (*wv == '0') wv++; - ns->precision = 0; - ns->scale = 0; - for (nlen = 0, dot_exist = FALSE;; wv++) - { - if (*wv == '.') - { - if (dot_exist) - break; - dot_exist = TRUE; - } - else if (!isdigit(*wv)) - break; - else - { - if (dot_exist) - ns->scale++; - else - ns->precision++; - calv[nlen++] = *wv; - } - } - memset(ns->val, 0, sizeof(ns->val)); - for (hval = 0, bit = 1L, sta = 0, olen = 0; sta < nlen;) - { - for (dig = 0, i = sta; i < nlen; i++) - { - tv = dig * 10 + calv[i] - '0'; - dig = tv % 2; - calv[i] = tv / 2 + '0'; - if (i == sta && tv < 2) - sta++; - } - if (dig > 0) - hval |= bit; - bit <<= 1; - if (bit >= (1L << 8)) - { - ns->val[olen++] = hval; - hval = 0; - bit = 1L; - if (olen >= SQL_MAX_NUMERIC_LEN - 1) - { - ns->scale = sta - ns->precision; - break; - } - } - } - if (hval && olen < SQL_MAX_NUMERIC_LEN - 1) - ns->val[olen++] = hval; - } -#ifdef HAVE_LOCALE_H - /* setlocale(LC_ALL, saved_locale); */ -#endif /* HAVE_LOCALE_H */ - break; -#endif /* ODBCVER */ - - case SQL_C_SSHORT: - case SQL_C_SHORT: - len = 2; - if (bind_size > 0) - *(SWORD *) ((char *) rgbValue + (bind_row * bind_size)) = atoi(neut_str); - else - *((SWORD *) rgbValue + bind_row) = atoi(neut_str); - break; - - case SQL_C_USHORT: - len = 2; - if (bind_size > 0) - *(UWORD *) ((char *) rgbValue + (bind_row * bind_size)) = atoi(neut_str); - else - *((UWORD *) rgbValue + bind_row) = atoi(neut_str); - break; - - case SQL_C_SLONG: - case SQL_C_LONG: - len = 4; - if (bind_size > 0) - *(SDWORD *) ((char *) rgbValue + (bind_row * bind_size)) = atol(neut_str); - else - *((SDWORD *) rgbValue + bind_row) = atol(neut_str); - break; - - case SQL_C_ULONG: - len = 4; - if (bind_size > 0) - *(UDWORD *) ((char *) rgbValue + (bind_row * bind_size)) = atol(neut_str); - else - *((UDWORD *) rgbValue + bind_row) = atol(neut_str); - break; - -#if (ODBCVER >= 0x0300) && defined(ODBCINT64) -#ifdef WIN32 - case SQL_C_SBIGINT: - len = 8; - if (bind_size > 0) - *(SQLBIGINT *) ((char *) rgbValue + (bind_row * bind_size)) = _atoi64(neut_str); - else - *((SQLBIGINT *) rgbValue + bind_row) = _atoi64(neut_str); - break; - - case SQL_C_UBIGINT: - len = 8; - if (bind_size > 0) - *(SQLUBIGINT *) ((char *) rgbValue + (bind_row * bind_size)) = _atoi64(neut_str); - else - *((SQLUBIGINT *) rgbValue + bind_row) = _atoi64(neut_str); - break; - -#endif /* WIN32 */ -#endif /* ODBCINT64 */ - case SQL_C_BINARY: - - /* truncate if necessary */ - /* convert octal escapes to bytes */ - - if (stmt->current_col < 0) - { - pbic = &sbic; - pbic->data_left = -1; - } - else - pbic = &opts->bindings[stmt->current_col]; - if (!pbic->ttlbuf) - pbic->ttlbuflen = 0; - if (len = strlen(neut_str), len >= (int) pbic->ttlbuflen) - { - pbic->ttlbuf = realloc(pbic->ttlbuf, len + 1); - pbic->ttlbuflen = len + 1; - } - len = convert_from_pgbinary(neut_str, pbic->ttlbuf, pbic->ttlbuflen); - ptr = pbic->ttlbuf; - - if (stmt->current_col >= 0) - { - /* - * Second (or more) call to SQLGetData so move the - * pointer - */ - if (pbic->data_left > 0) - { - ptr += len - pbic->data_left; - len = pbic->data_left; - } - - /* First call to SQLGetData so initialize data_left */ - else - pbic->data_left = len; - - } - - if (cbValueMax > 0) - { - copy_len = (len > cbValueMax) ? cbValueMax : len; - - /* Copy the data */ - memcpy(rgbValueBindRow, ptr, copy_len); - - /* Adjust data_left for next time */ - if (stmt->current_col >= 0) - pbic->data_left -= copy_len; - } - - /* - * Finally, check for truncation so that proper status can - * be returned - */ - if (len > cbValueMax) - result = COPY_RESULT_TRUNCATED; - - if (pbic->ttlbuf) - { - free(pbic->ttlbuf); - pbic->ttlbuf = NULL; - } - mylog("SQL_C_BINARY: len = %d, copy_len = %d\n", len, copy_len); - break; - - default: - return COPY_UNSUPPORTED_TYPE; - } - } - - /* store the length of what was copied, if there's a place for it */ - if (pcbValue) - *(SDWORD *) ((char *) pcbValue + pcbValueOffset) = len; - - if (result == COPY_OK && stmt->current_col >= 0) - opts->bindings[stmt->current_col].data_left = 0; - return result; - -} - - -/*-------------------------------------------------------------------- - * Functions/Macros to get rid of query size limit. - * - * I always used the follwoing macros to convert from - * old_statement to new_statement. Please improve it - * if you have a better way. Hiroshi 2001/05/22 - *-------------------------------------------------------------------- - */ - -#define FLGP_PREPARE_DUMMY_CURSOR 1L -#define FLGP_CURSOR_CHECK_OK (1L << 1) -#define FLGP_SELECT_INTO (1L << 2) -#define FLGP_SELECT_FOR_UPDATE (1L << 3) -typedef struct _QueryParse { - const char *statement; - int statement_type; - UInt4 opos; - int from_pos; - int where_pos; - UInt4 stmt_len; - BOOL in_quote, in_dquote, in_escape; - char token_save[64]; - int token_len; - BOOL prev_token_end; - BOOL proc_no_param; - unsigned int declare_pos; - UInt4 flags; -#ifdef MULTIBYTE - encoded_str encstr; -#endif /* MULTIBYTE */ -} QueryParse; - -static int -QP_initialize(QueryParse *q, const StatementClass *stmt) -{ - q->statement = stmt->statement; - q->statement_type = stmt->statement_type; - q->opos = 0; - q->from_pos = -1; - q->where_pos = -1; - q->stmt_len = (q->statement) ? strlen(q->statement) : -1; - q->in_quote = q->in_dquote = q->in_escape = FALSE; - q->token_save[0] = '\0'; - q->token_len = 0; - q->prev_token_end = TRUE; - q->proc_no_param = TRUE; - q->declare_pos = 0; - q->flags = 0; -#ifdef MULTIBYTE - make_encoded_str(&q->encstr, SC_get_conn(stmt), q->statement); -#endif /* MULTIBYTE */ - - return q->stmt_len; -} - -#define FLGB_PRE_EXECUTING 1L -#define FLGB_INACCURATE_RESULT (1L << 1) -#define FLGB_CREATE_KEYSET (1L << 2) -#define FLGB_KEYSET_DRIVEN (1L << 3) -typedef struct _QueryBuild { - char *query_statement; - UInt4 str_size_limit; - UInt4 str_alsize; - UInt4 npos; - int current_row; - int param_number; - APDFields *apdopts; - UInt4 load_stmt_len; - UInt4 flags; - BOOL lf_conv; - int ccsc; - int errornumber; - const char *errormsg; - - ConnectionClass *conn; /* mainly needed for LO handling */ - StatementClass *stmt; /* needed to set error info in ENLARGE_.. */ -} QueryBuild; - -#define INIT_MIN_ALLOC 4096 -static int -QB_initialize(QueryBuild *qb, UInt4 size, StatementClass *stmt, ConnectionClass *conn) -{ - UInt4 newsize = 0; - - qb->flags = 0; - qb->load_stmt_len = 0; - qb->stmt = stmt; - qb->apdopts = NULL; - if (conn) - qb->conn = conn; - else if (stmt) - { - qb->apdopts = SC_get_APD(stmt); - qb->conn = SC_get_conn(stmt); - if (stmt->pre_executing) - qb->flags |= FLGB_PRE_EXECUTING; - } - else - { - qb->conn = NULL; - return -1; - } - qb->lf_conv = qb->conn->connInfo.lf_conversion; - qb->ccsc = qb->conn->ccsc; - - if (stmt) - qb->str_size_limit = stmt->stmt_size_limit; - else - qb->str_size_limit = -1; - if (qb->str_size_limit > 0) - { - if (size > qb->str_size_limit) - return -1; - newsize = qb->str_size_limit; - } - else - { - newsize = INIT_MIN_ALLOC; - while (newsize <= size) - newsize *= 2; - } - if ((qb->query_statement = malloc(newsize)) == NULL) - { - qb->str_alsize = 0; - return -1; - } - qb->query_statement[0] = '\0'; - qb->str_alsize = newsize; - qb->npos = 0; - qb->current_row = stmt->exec_current_row < 0 ? 0 : stmt->exec_current_row; - qb->param_number = -1; - qb->errornumber = 0; - qb->errormsg = NULL; - - return newsize; -} - -static int -QB_initialize_copy(QueryBuild *qb_to, const QueryBuild *qb_from, UInt4 size) -{ - memcpy(qb_to, qb_from, sizeof(QueryBuild)); - - if (qb_to->str_size_limit > 0) - { - if (size > qb_to->str_size_limit) - return -1; - } - if ((qb_to->query_statement = malloc(size)) == NULL) - { - qb_to->str_alsize = 0; - return -1; - } - qb_to->query_statement[0] = '\0'; - qb_to->str_alsize = size; - qb_to->npos = 0; - - return size; -} - -static void -QB_Destructor(QueryBuild *qb) -{ - if (qb->query_statement) - { - free(qb->query_statement); - qb->query_statement = NULL; - qb->str_alsize = 0; - } -} - -/* - * New macros (Aceto) - *-------------------- - */ - -#define F_OldChar(qp) \ -qp->statement[qp->opos] - -#define F_OldPtr(qp) \ -(qp->statement + qp->opos) - -#define F_OldNext(qp) \ -(++qp->opos) - -#define F_OldPrior(qp) \ -(--qp->opos) - -#define F_OldPos(qp) \ -qp->opos - -#define F_ExtractOldTo(qp, buf, ch, maxsize) \ -do { \ - unsigned int c = 0; \ - while (qp->statement[qp->opos] != '\0' && qp->statement[qp->opos] != ch) \ - { \ - buf[c++] = qp->statement[qp->opos++]; \ - if (c >= maxsize) \ - break; \ - } \ - if (qp->statement[qp->opos] == '\0') \ - return SQL_ERROR; \ - buf[c] = '\0'; \ -} while (0) - -#define F_NewChar(qb) \ -qb->query_statement[qb->npos] - -#define F_NewPtr(qb) \ -(qb->query_statement + qb->npos) - -#define F_NewNext(qb) \ -(++qb->npos) - -#define F_NewPos(qb) \ -(qb->npos) - - -static int -convert_escape(QueryParse *qp, QueryBuild *qb); -static int -inner_process_tokens(QueryParse *qp, QueryBuild *qb); -static int -ResolveOneParam(QueryBuild *qb); -static int -processParameters(QueryParse *qp, QueryBuild *qb, -UInt4 *output_count, Int4 param_pos[][2]); - -static int -enlarge_query_statement(QueryBuild *qb, unsigned int newsize) -{ - unsigned int newalsize = INIT_MIN_ALLOC; - static char *func = "enlarge_statement"; - - if (qb->str_size_limit > 0 && qb->str_size_limit < (int) newsize) - { - free(qb->query_statement); - qb->query_statement = NULL; - qb->str_alsize = 0; - if (qb->stmt) - { - qb->stmt->errormsg = "Query buffer overflow in copy_statement_with_parameters"; - qb->stmt->errornumber = STMT_EXEC_ERROR; - SC_log_error(func, "", qb->stmt); - } - else - { - qb->errormsg = "Query buffer overflow in copy_statement_with_parameters"; - qb->errornumber = STMT_EXEC_ERROR; - } - return -1; - } - while (newalsize <= newsize) - newalsize *= 2; - if (!(qb->query_statement = realloc(qb->query_statement, newalsize))) - { - qb->str_alsize = 0; - if (qb->stmt) - { - qb->stmt->errormsg = "Query buffer allocate error in copy_statement_with_parameters"; - qb->stmt->errornumber = STMT_EXEC_ERROR; - } - else - { - qb->errormsg = "Query buffer allocate error in copy_statement_with_parameters"; - qb->errornumber = STMT_EXEC_ERROR; - } - return 0; - } - qb->str_alsize = newalsize; - return newalsize; -} - -/*---------- - * Enlarge stmt_with_params if necessary. - *---------- - */ -#define ENLARGE_NEWSTATEMENT(qb, newpos) \ - if (newpos >= qb->str_alsize) \ - { \ - if (enlarge_query_statement(qb, newpos) <= 0) \ - return SQL_ERROR; \ - } - -/*---------- - * Terminate the stmt_with_params string with NULL. - *---------- - */ -#define CVT_TERMINATE(qb) \ -do { \ - qb->query_statement[qb->npos] = '\0'; \ -} while (0) - -/*---------- - * Append a data. - *---------- - */ -#define CVT_APPEND_DATA(qb, s, len) \ -do { \ - unsigned int newpos = qb->npos + len; \ - ENLARGE_NEWSTATEMENT(qb, newpos) \ - memcpy(&qb->query_statement[qb->npos], s, len); \ - qb->npos = newpos; \ - qb->query_statement[newpos] = '\0'; \ -} while (0) - -/*---------- - * Append a string. - *---------- - */ -#define CVT_APPEND_STR(qb, s) \ -do { \ - unsigned int len = strlen(s); \ - CVT_APPEND_DATA(qb, s, len); \ -} while (0) - -/*---------- - * Append a char. - *---------- - */ -#define CVT_APPEND_CHAR(qb, c) \ -do { \ - ENLARGE_NEWSTATEMENT(qb, qb->npos + 1); \ - qb->query_statement[qb->npos++] = c; \ -} while (0) - -/*---------- - * Append a binary data. - * Newly reqeuired size may be overestimated currently. - *---------- - */ -#define CVT_APPEND_BINARY(qb, buf, used) \ -do { \ - unsigned int newlimit = qb->npos + 5 * used; \ - ENLARGE_NEWSTATEMENT(qb, newlimit); \ - qb->npos += convert_to_pgbinary(buf, &qb->query_statement[qb->npos], used); \ -} while (0) - -/*---------- - * - *---------- - */ -#define CVT_SPECIAL_CHARS(qb, buf, used) \ -do { \ - int cnvlen = convert_special_chars(buf, NULL, used, qb->lf_conv, qb->ccsc); \ - unsigned int newlimit = qb->npos + cnvlen; \ -\ - ENLARGE_NEWSTATEMENT(qb, newlimit); \ - convert_special_chars(buf, &qb->query_statement[qb->npos], used, qb->lf_conv, qb->ccsc); \ - qb->npos += cnvlen; \ -} while (0) - -/*---------- - * Check if the statement is - * SELECT ... INTO table FROM ..... - * This isn't really a strict check but ... - *---------- - */ -static BOOL -into_table_from(const char *stmt) -{ - if (strnicmp(stmt, "into", 4)) - return FALSE; - stmt += 4; - if (!isspace((unsigned char) *stmt)) - return FALSE; - while (isspace((unsigned char) *(++stmt))); - switch (*stmt) - { - case '\0': - case ',': - case '\'': - return FALSE; - case '\"': /* double quoted table name ? */ - do - { - do - while (*(++stmt) != '\"' && *stmt); - while (*stmt && *(++stmt) == '\"'); - while (*stmt && !isspace((unsigned char) *stmt) && *stmt != '\"') - stmt++; - } - while (*stmt == '\"'); - break; - default: - while (!isspace((unsigned char) *(++stmt))); - break; - } - if (!*stmt) - return FALSE; - while (isspace((unsigned char) *(++stmt))); - if (strnicmp(stmt, "from", 4)) - return FALSE; - return isspace((unsigned char) stmt[4]); -} - -/*---------- - * Check if the statement is - * SELECT ... FOR UPDATE ..... - * This isn't really a strict check but ... - *---------- - */ -static BOOL -table_for_update(const char *stmt, int *endpos) -{ - const char *wstmt = stmt; - - while (isspace((unsigned char) *(++wstmt))); - if (!*wstmt) - return FALSE; - if (strnicmp(wstmt, "update", 6)) - return FALSE; - wstmt += 6; - *endpos = wstmt - stmt; - return !wstmt[0] || isspace((unsigned char) wstmt[0]); -} - -/*---------- - * Check if the statement is - * INSERT INTO ... () VALUES () - * This isn't really a strict check but ... - *---------- - */ -static BOOL -insert_without_target(const char *stmt, int *endpos) -{ - const char *wstmt = stmt; - - while (isspace((unsigned char) *(++wstmt))); - if (!*wstmt) - return FALSE; - if (strnicmp(wstmt, "VALUES", 6)) - return FALSE; - wstmt += 6; - if (!wstmt[0] || !isspace((unsigned char) wstmt[0])) - return FALSE; - while (isspace((unsigned char) *(++wstmt))); - if (*wstmt != '(' || *(++wstmt) != ')') - return FALSE; - wstmt++; - *endpos = wstmt - stmt; - return !wstmt[0] || isspace((unsigned char) wstmt[0]) - || ';' == wstmt[0]; -} - -#ifdef MULTIBYTE -#define my_strchr(conn, s1,c1) pg_mbschr(conn->ccsc, s1,c1) -#else -#define my_strchr(conn, s1,c1) strchr(s1,c1) -#endif -/* - * This function inserts parameters into an SQL statements. - * It will also modify a SELECT statement for use with declare/fetch cursors. - * This function does a dynamic memory allocation to get rid of query size limit! - */ -int -copy_statement_with_parameters(StatementClass *stmt) -{ - static char *func = "copy_statement_with_parameters"; - RETCODE retval; - QueryParse query_org, *qp; - QueryBuild query_crt, *qb; - - char *new_statement; - - BOOL begin_first = FALSE, prepare_dummy_cursor = FALSE; - ConnectionClass *conn = SC_get_conn(stmt); - ConnInfo *ci = &(conn->connInfo); - int current_row; - - if (!stmt->statement) - { - SC_log_error(func, "No statement string", stmt); - return SQL_ERROR; - } - - current_row = stmt->exec_current_row < 0 ? 0 : stmt->exec_current_row; - qp = &query_org; - QP_initialize(qp, stmt); - - if (ci->disallow_premature) - prepare_dummy_cursor = stmt->pre_executing; - if (prepare_dummy_cursor); - qp->flags |= FLGP_PREPARE_DUMMY_CURSOR; - - -#ifdef DRIVER_CURSOR_IMPLEMENT - if (stmt->statement_type != STMT_TYPE_SELECT) - { - stmt->options.cursor_type = SQL_CURSOR_FORWARD_ONLY; - stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY; - } - else if (stmt->options.cursor_type == SQL_CURSOR_FORWARD_ONLY) - stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY; - else if (stmt->options.scroll_concurrency != SQL_CONCUR_READ_ONLY) - { - if (stmt->parse_status == STMT_PARSE_NONE) - parse_statement(stmt); - if (stmt->parse_status == STMT_PARSE_FATAL) - { - stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY; - return SQL_ERROR; - } - else if (!stmt->updatable) - { - stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY; - stmt->options.cursor_type = SQL_CURSOR_STATIC; - } - else - { - qp->from_pos = stmt->from_pos; - qp->where_pos = stmt->where_pos; - } - } -#else - stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY; - if (stmt->options.cursor_type == SQL_CURSOR_KEYSET_DRIVEN) - stmt->options.cursor_type = SQL_CURSOR_STATIC; -#endif /* DRIVER_CURSOR_IMPLEMENT */ - - /* If the application hasn't set a cursor name, then generate one */ - if (stmt->cursor_name[0] == '\0') - sprintf(stmt->cursor_name, "SQL_CUR%p", stmt); - if (stmt->stmt_with_params) - { - free(stmt->stmt_with_params); - stmt->stmt_with_params = NULL; - } - qb = &query_crt; - if (QB_initialize(qb, qp->stmt_len, stmt, NULL) < 0) - return SQL_ERROR; - new_statement = qb->query_statement; - - stmt->miscinfo = 0; - /* For selects, prepend a declare cursor to the statement */ - if (stmt->statement_type == STMT_TYPE_SELECT) - { - SC_set_pre_executable(stmt); - if (prepare_dummy_cursor || ci->drivers.use_declarefetch) - { - if (prepare_dummy_cursor) - { - if (!CC_is_in_trans(conn) && PG_VERSION_GE(conn, 7.1)) - { - strcpy(new_statement, "BEGIN;"); - begin_first = TRUE; - } - } - else if (ci->drivers.use_declarefetch) - SC_set_fetchcursor(stmt); - sprintf(new_statement, "%sdeclare %s cursor for ", - new_statement, stmt->cursor_name); - qb->npos = strlen(new_statement); - qp->flags |= FLGP_CURSOR_CHECK_OK; - qp->declare_pos = qb->npos; - } - else if (SQL_CONCUR_READ_ONLY != stmt->options.scroll_concurrency) - { - qb->flags |= FLGB_CREATE_KEYSET; - if (SQL_CURSOR_KEYSET_DRIVEN == stmt->options.cursor_type) - qb->flags |= FLGB_KEYSET_DRIVEN; - } - } - - for (qp->opos = 0; qp->opos < qp->stmt_len; qp->opos++) - { - retval = inner_process_tokens(qp, qb); - if (SQL_ERROR == retval) - { - if (0 == stmt->errornumber) - { - stmt->errornumber = qb->errornumber; - stmt->errormsg = qb->errormsg; - } - SC_log_error(func, "", stmt); - QB_Destructor(qb); - return retval; - } - } - /* make sure new_statement is always null-terminated */ - CVT_TERMINATE(qb); - - new_statement = qb->query_statement; - stmt->statement_type = qp->statement_type; - stmt->inaccurate_result = (0 != (qb->flags & FLGB_INACCURATE_RESULT)); - if (0 != (qp->flags & FLGP_SELECT_INTO)) - { - SC_no_pre_executable(stmt); - SC_no_fetchcursor(stmt); - stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY; - } - if (0 != (qp->flags & FLGP_SELECT_FOR_UPDATE)) - { - SC_no_fetchcursor(stmt); - stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY; - } - - if (conn->DriverToDataSource != NULL) - { - int length = strlen(new_statement); - - conn->DriverToDataSource(conn->translation_option, - SQL_CHAR, - new_statement, length, - new_statement, length, NULL, - NULL, 0, NULL); - } - -#ifdef DRIVER_CURSOR_IMPLEMENT - if (!stmt->load_statement && qp->from_pos >= 0) - { - UInt4 npos = qb->load_stmt_len; - - if (0 == npos) - { - npos = qb->npos; - for (; npos > 0; npos--) - { - if (isspace(new_statement[npos - 1])) - continue; - if (';' != new_statement[npos - 1]) - break; - } - if (0 != (qb->flags & FLGB_KEYSET_DRIVEN)) - { - qb->npos = npos; - /* ---------- - * 1st query is for field information - * 2nd query is keyset gathering - */ - CVT_APPEND_STR(qb, " where ctid = '(,)';select ctid, oid from "); - CVT_APPEND_DATA(qb, qp->statement + qp->from_pos + 5, npos - qp->from_pos - 5); - } - } - stmt->load_statement = malloc(npos + 1); - memcpy(stmt->load_statement, qb->query_statement, npos); - stmt->load_statement[npos] = '\0'; - } -#endif /* DRIVER_CURSOR_IMPLEMENT */ - if (prepare_dummy_cursor && SC_is_pre_executable(stmt)) - { - char fetchstr[128]; - - sprintf(fetchstr, ";fetch backward in %s;close %s;", - stmt->cursor_name, stmt->cursor_name); - if (begin_first && CC_is_in_autocommit(conn)) - strcat(fetchstr, "COMMIT;"); - CVT_APPEND_STR(qb, fetchstr); - stmt->inaccurate_result = TRUE; - } - - stmt->stmt_with_params = qb->query_statement; - return SQL_SUCCESS; -} - -static int -inner_process_tokens(QueryParse *qp, QueryBuild *qb) -{ - static char *func = "inner_process_tokens"; - BOOL lf_conv = qb->lf_conv; - - RETCODE retval; - char oldchar; - - if (qp->from_pos == (Int4) qp->opos) - { - CVT_APPEND_STR(qb, ", CTID, OID "); - } - else if (qp->where_pos == (Int4) qp->opos) - { - qb->load_stmt_len = qb->npos; - if (0 != (qb->flags & FLGB_KEYSET_DRIVEN)) - { - CVT_APPEND_STR(qb, "where ctid = '(,)';select CTID, OID from "); - CVT_APPEND_DATA(qb, qp->statement + qp->from_pos + 5, qp->where_pos - qp->from_pos - 5); - } - } -#ifdef MULTIBYTE - oldchar = encoded_byte_check(&qp->encstr, qp->opos); - if (ENCODE_STATUS(qp->encstr) != 0) - { - CVT_APPEND_CHAR(qb, oldchar); - return SQL_SUCCESS; - } - - /* - * From here we are guaranteed to handle a 1-byte character. - */ -#else - oldchar = qp->statement[qp->opos]; -#endif - - if (qp->in_escape) /* escape check */ - { - qp->in_escape = FALSE; - CVT_APPEND_CHAR(qb, oldchar); - return SQL_SUCCESS; - } - else if (qp->in_quote || qp->in_dquote) /* quote/double quote check */ - { - if (oldchar == '\\') - qp->in_escape = TRUE; - else if (oldchar == '\'' && qp->in_quote) - qp->in_quote = FALSE; - else if (oldchar == '\"' && qp->in_dquote) - qp->in_dquote = FALSE; - CVT_APPEND_CHAR(qb, oldchar); - return SQL_SUCCESS; - } - - /* - * From here we are guranteed to be in neither an escape, a quote - * nor a double quote. - */ - /* Squeeze carriage-return/linefeed pairs to linefeed only */ - else if (lf_conv && oldchar == '\r' && qp->opos + 1 < qp->stmt_len && - qp->statement[qp->opos + 1] == '\n') - return SQL_SUCCESS; - - /* - * Handle literals (date, time, timestamp) and ODBC scalar - * functions - */ - else if (oldchar == '{') - { - if (SQL_ERROR == convert_escape(qp, qb)) - { - if (0 == qb->errornumber) - { - qb->errornumber = STMT_EXEC_ERROR; - qb->errormsg = "ODBC escape convert error"; - } - mylog("%s convert_escape error\n", func); - return SQL_ERROR; - } - if (isalnum(F_OldPtr(qp)[1])) - CVT_APPEND_CHAR(qb, ' '); - return SQL_SUCCESS; - } - /* End of an escape sequence */ - else if (oldchar == '}') - { - if (qp->statement_type == STMT_TYPE_PROCCALL) - { - if (qp->proc_no_param) - CVT_APPEND_STR(qb, "()"); - } - else if (!isspace(F_OldPtr(qp)[1])) - CVT_APPEND_CHAR(qb, ' '); - return SQL_SUCCESS; - } - - /* - * Can you have parameter markers inside of quotes? I dont think - * so. All the queries I've seen expect the driver to put quotes - * if needed. - */ - else if (oldchar != '?') - { - if (oldchar == '\'') - qp->in_quote = TRUE; - else if (oldchar == '\\') - qp->in_escape = TRUE; - else if (oldchar == '\"') - qp->in_dquote = TRUE; - else - { - if (isspace((unsigned char) oldchar)) - { - if (!qp->prev_token_end) - { - qp->prev_token_end = TRUE; - qp->token_save[qp->token_len] = '\0'; - if (qp->token_len == 4) - { - if (0 != (qp->flags & FLGP_CURSOR_CHECK_OK) && - into_table_from(&qp->statement[qp->opos - qp->token_len])) - { - qp->flags |= FLGP_SELECT_INTO; - qp->flags &= ~FLGP_CURSOR_CHECK_OK; - qb->flags &= ~FLGB_KEYSET_DRIVEN; - qp->statement_type = STMT_TYPE_CREATE; - memmove(qb->query_statement, qb->query_statement + qp->declare_pos, qb->npos - qp->declare_pos); - qb->npos -= qp->declare_pos; - } - } - else if (qp->token_len == 3) - { - int endpos; - - if (0 != (qp->flags & FLGP_CURSOR_CHECK_OK) && - strnicmp(qp->token_save, "for", 3) == 0 && - table_for_update(&qp->statement[qp->opos], &endpos)) - { - qp->flags |= FLGP_SELECT_FOR_UPDATE; - qp->flags &= ~FLGP_CURSOR_CHECK_OK; - if (qp->flags & FLGP_PREPARE_DUMMY_CURSOR) - { - qb->npos -= 4; - qp->opos += endpos; - } - else - { - memmove(qb->query_statement, qb->query_statement + qp->declare_pos, qb->npos - qp->declare_pos); - qb->npos -= qp->declare_pos; - } - } - } - else if (qp->token_len == 2) - { - int endpos; - - if (STMT_TYPE_INSERT == qp->statement_type && - strnicmp(qp->token_save, "()", 2) == 0 && - insert_without_target(&qp->statement[qp->opos], &endpos)) - { - qb->npos -= 2; - CVT_APPEND_STR(qb, "DEFAULT VALUES"); - qp->opos += endpos; - return SQL_SUCCESS; - } - } - } - } - else if (qp->prev_token_end) - { - qp->prev_token_end = FALSE; - qp->token_save[0] = oldchar; - qp->token_len = 1; - } - else if (qp->token_len + 1 < sizeof(qp->token_save)) - qp->token_save[qp->token_len++] = oldchar; - } - CVT_APPEND_CHAR(qb, oldchar); - return SQL_SUCCESS; - } - - /* - * Its a '?' parameter alright - */ - if (retval = ResolveOneParam(qb), retval < 0) - return retval; - - return SQL_SUCCESS; -} - -#if (ODBCVER >= 0x0300) -static BOOL -ResolveNumericParam(const SQL_NUMERIC_STRUCT *ns, char *chrform) -{ - static int prec[] = {1, 3, 5, 8, 10, 13, 15, 17, 20, 22, 25, 29, 32, 34, 37, 39}; - Int4 i, j, k, ival, vlen, len, newlen; - unsigned char calv[40]; - const unsigned char *val = (const unsigned char *) ns->val; - BOOL next_figure; - - if (0 == ns->precision) - { - strcpy(chrform, "0"); - return TRUE; - } - else if (ns->precision < prec[sizeof(Int4)]) - { - for (i = 0, ival = 0; i < sizeof(Int4) && prec[i] <= ns->precision; i++) - { - ival += (val[i] << (8 * i)); /* ns->val is little endian */ - } - if (0 == ns->scale) - { - if (0 == ns->sign) - ival *= -1; - sprintf(chrform, "%d", ival); - } - else if (ns->scale > 0) - { - Int4 i, div, o1val, o2val; - - for (i = 0, div = 1; i < ns->scale; i++) - div *= 10; - o1val = ival / div; - o2val = ival % div; - if (0 == ns->sign) - o1val *= -1; - sprintf(chrform, "%d.%0.*d", o1val, ns->scale, o2val); - } - return TRUE; - } - - for (i = 0; i < SQL_MAX_NUMERIC_LEN && prec[i] <= ns->precision; i++) - ; - vlen = i; - len = 0; - memset(calv, 0, sizeof(calv)); - for (i = vlen - 1; i >= 0; i--) - { - for (j = len - 1; j >= 0; j--) - { - if (!calv[j]) - continue; - ival = (((Int4)calv[j]) << 8); - calv[j] = (ival % 10); - ival /= 10; - calv[j + 1] += (ival % 10); - ival /= 10; - calv[j + 2] += (ival % 10); - ival /= 10; - calv[j + 3] += ival; - for (k = j;; k++) - { - next_figure = FALSE; - if (calv[k] > 0) - { - if (k >= len) - len = k + 1; - while (calv[k] > 9) - { - calv[k + 1]++; - calv[k] -= 10; - next_figure = TRUE; - } - } - if (k >= j + 3 && !next_figure) - break; - } - } - ival = val[i]; - if (!ival) - continue; - calv[0] += (ival % 10); - ival /= 10; - calv[1] += (ival % 10); - ival /= 10; - calv[2] += ival; - for (j = 0;; j++) - { - next_figure = FALSE; - if (calv[j] > 0) - { - if (j >= len) - len = j + 1; - while (calv[j] > 9) - { - calv[j + 1]++; - calv[j] -= 10; - next_figure = TRUE; - } - } - if (j >= 2 && !next_figure) - break; - } - } - newlen = 0; - if (0 == ns->sign) - chrform[newlen++] = '-'; - for (i = len - 1; i >= ns->scale; i--) - chrform[newlen++] = calv[i] + '0'; - if (ns->scale > 0) - { - chrform[newlen++] = '.'; - for (; i >= 0; i--) - chrform[newlen++] = calv[i] + '0'; - } - chrform[newlen] = '\0'; - return TRUE; -} -#endif /* ODBCVER */ - -/* - * - */ -static int -ResolveOneParam(QueryBuild *qb) -{ - const char *func = "ResolveOneParam"; - - ConnectionClass *conn = qb->conn; - ConnInfo *ci = &(conn->connInfo); - APDFields *opts = qb->apdopts; - - int param_number; - char param_string[128], tmp[256], - cbuf[PG_NUMERIC_MAX_PRECISION * 2]; /* seems big enough to handle the data in this function */ - Int2 param_ctype, param_sqltype; - SIMPLE_TIME st; - time_t t; - struct tm *tim; - SDWORD used; - char *buffer, *buf, *allocbuf; - Oid lobj_oid; - int lobj_fd, retval; - UInt4 offset = opts->param_offset_ptr ? *opts->param_offset_ptr : 0; - UInt4 current_row = qb->current_row; - - /* - * Its a '?' parameter alright - */ - param_number = ++qb->param_number; - - if (param_number >= opts->allocated) - { - if (0 != (qb->flags & FLGB_PRE_EXECUTING)) - { - CVT_APPEND_STR(qb, "NULL"); - qb->flags |= FLGB_INACCURATE_RESULT; - return SQL_SUCCESS; - } - else - { - CVT_APPEND_CHAR(qb, '?'); - return SQL_SUCCESS; - } - } - - /* Assign correct buffers based on data at exec param or not */ - if (opts->parameters[param_number].data_at_exec) - { - used = opts->parameters[param_number].EXEC_used ? *opts->parameters[param_number].EXEC_used : SQL_NTS; - buffer = opts->parameters[param_number].EXEC_buffer; - } - else - { - UInt4 bind_size = opts->param_bind_type; - UInt4 ctypelen; - - buffer = opts->parameters[param_number].buffer + offset; - if (current_row > 0) - { - if (bind_size > 0) - buffer += (bind_size * current_row); - else if (ctypelen = ctype_length(opts->parameters[param_number].CType), ctypelen > 0) - buffer += current_row * ctypelen; - else - buffer += current_row * opts->parameters[param_number].buflen; - } - if (opts->parameters[param_number].used) - { - UInt4 p_offset = offset; - if (bind_size > 0) - p_offset = offset + bind_size * current_row; - else - p_offset = offset + sizeof(SDWORD) * current_row; - used = *(SDWORD *)((char *)opts->parameters[param_number].used + p_offset); - } - else - used = SQL_NTS; - } - - /* Handle NULL parameter data */ - if (used == SQL_NULL_DATA) - { - CVT_APPEND_STR(qb, "NULL"); - return SQL_SUCCESS; - } - - /* - * If no buffer, and it's not null, then what the hell is it? Just - * leave it alone then. - */ - if (!buffer) - { - if (0 != (qb->flags & FLGB_PRE_EXECUTING)) - { - CVT_APPEND_STR(qb, "NULL"); - qb->flags |= FLGB_INACCURATE_RESULT; - return SQL_SUCCESS; - } - else - { - CVT_APPEND_CHAR(qb, '?'); - return SQL_SUCCESS; - } - } - - param_ctype = opts->parameters[param_number].CType; - param_sqltype = opts->parameters[param_number].SQLType; - - mylog("%s: from(fcType)=%d, to(fSqlType)=%d\n", func, - param_ctype, param_sqltype); - - /* replace DEFAULT with something we can use */ - if (param_ctype == SQL_C_DEFAULT) - param_ctype = sqltype_to_default_ctype(param_sqltype); - - allocbuf = buf = NULL; - param_string[0] = '\0'; - cbuf[0] = '\0'; - memset(&st, 0, sizeof(st)); - t = time(NULL); - tim = localtime(&t); - st.m = tim->tm_mon + 1; - st.d = tim->tm_mday; - st.y = tim->tm_year + 1900; - - /* Convert input C type to a neutral format */ - switch (param_ctype) - { - case SQL_C_BINARY: - case SQL_C_CHAR: - buf = buffer; - break; - -#ifdef UNICODE_SUPPORT - case SQL_C_WCHAR: - buf = allocbuf = ucs2_to_utf8((SQLWCHAR *) buffer, used / 2, &used); - used *= 2; - break; -#endif /* UNICODE_SUPPORT */ - - case SQL_C_DOUBLE: - sprintf(param_string, "%.15g", - *((SDOUBLE *) buffer)); - break; - - case SQL_C_FLOAT: - sprintf(param_string, "%.6g", - *((SFLOAT *) buffer)); - break; - - case SQL_C_SLONG: - case SQL_C_LONG: - sprintf(param_string, "%ld", - *((SDWORD *) buffer)); - break; - -#if (ODBCVER >= 0x0300) && defined(ODBCINT64) -#ifdef WIN32 - case SQL_C_SBIGINT: - sprintf(param_string, "%I64d", - *((SQLBIGINT *) buffer)); - break; - - case SQL_C_UBIGINT: - sprintf(param_string, "%I64u", - *((SQLUBIGINT *) buffer)); - break; - -#endif /* WIN32 */ -#endif /* ODBCINT64 */ - case SQL_C_SSHORT: - case SQL_C_SHORT: - sprintf(param_string, "%d", - *((SWORD *) buffer)); - break; - - case SQL_C_STINYINT: - case SQL_C_TINYINT: - sprintf(param_string, "%d", - *((SCHAR *) buffer)); - break; - - case SQL_C_ULONG: - sprintf(param_string, "%lu", - *((UDWORD *) buffer)); - break; - - case SQL_C_USHORT: - sprintf(param_string, "%u", - *((UWORD *) buffer)); - break; - - case SQL_C_UTINYINT: - sprintf(param_string, "%u", - *((UCHAR *) buffer)); - break; - - case SQL_C_BIT: - { - int i = *((UCHAR *) buffer); - - sprintf(param_string, "%d", i ? 1 : 0); - break; - } - - case SQL_C_DATE: -#if (ODBCVER >= 0x0300) - case SQL_C_TYPE_DATE: /* 91 */ -#endif - { - DATE_STRUCT *ds = (DATE_STRUCT *) buffer; - - st.m = ds->month; - st.d = ds->day; - st.y = ds->year; - - break; - } - - case SQL_C_TIME: -#if (ODBCVER >= 0x0300) - case SQL_C_TYPE_TIME: /* 92 */ -#endif - { - TIME_STRUCT *ts = (TIME_STRUCT *) buffer; - - st.hh = ts->hour; - st.mm = ts->minute; - st.ss = ts->second; - - break; - } - - case SQL_C_TIMESTAMP: -#if (ODBCVER >= 0x0300) - case SQL_C_TYPE_TIMESTAMP: /* 93 */ -#endif - { - TIMESTAMP_STRUCT *tss = (TIMESTAMP_STRUCT *) buffer; - - st.m = tss->month; - st.d = tss->day; - st.y = tss->year; - st.hh = tss->hour; - st.mm = tss->minute; - st.ss = tss->second; - st.fr = tss->fraction; - - mylog("m=%d,d=%d,y=%d,hh=%d,mm=%d,ss=%d\n", st.m, st.d, st.y, st.hh, st.mm, st.ss); - - break; - - } -#if (ODBCVER >= 0x0300) - case SQL_C_NUMERIC: - if (ResolveNumericParam((SQL_NUMERIC_STRUCT *) buffer, param_string)) - break; -#endif - default: - /* error */ - qb->errormsg = "Unrecognized C_parameter type in copy_statement_with_parameters"; - qb->errornumber = STMT_NOT_IMPLEMENTED_ERROR; - CVT_TERMINATE(qb); /* just in case */ - return SQL_ERROR; - } - - /* - * Now that the input data is in a neutral format, convert it to - * the desired output format (sqltype) - */ - - switch (param_sqltype) - { - case SQL_CHAR: - case SQL_VARCHAR: - case SQL_LONGVARCHAR: -#ifdef UNICODE_SUPPORT - case SQL_WCHAR: - case SQL_WVARCHAR: - case SQL_WLONGVARCHAR: -#endif /* UNICODE_SUPPORT */ - - CVT_APPEND_CHAR(qb, '\''); /* Open Quote */ - - /* it was a SQL_C_CHAR */ - if (buf) - CVT_SPECIAL_CHARS(qb, buf, used); - - /* it was a numeric type */ - else if (param_string[0] != '\0') - CVT_APPEND_STR(qb, param_string); - - /* it was date,time,timestamp -- use m,d,y,hh,mm,ss */ - else - { - sprintf(tmp, "%.4d-%.2d-%.2d %.2d:%.2d:%.2d", - st.y, st.m, st.d, st.hh, st.mm, st.ss); - - CVT_APPEND_STR(qb, tmp); - } - - CVT_APPEND_CHAR(qb, '\''); /* Close Quote */ - - break; - - case SQL_DATE: -#if (ODBCVER >= 0x0300) - case SQL_TYPE_DATE: /* 91 */ -#endif - if (buf) - { /* copy char data to time */ - my_strcpy(cbuf, sizeof(cbuf), buf, used); - parse_datetime(cbuf, &st); - } - - sprintf(tmp, "'%.4d-%.2d-%.2d'::date", st.y, st.m, st.d); - - CVT_APPEND_STR(qb, tmp); - break; - - case SQL_TIME: -#if (ODBCVER >= 0x0300) - case SQL_TYPE_TIME: /* 92 */ -#endif - if (buf) - { /* copy char data to time */ - my_strcpy(cbuf, sizeof(cbuf), buf, used); - parse_datetime(cbuf, &st); - } - - sprintf(tmp, "'%.2d:%.2d:%.2d'::time", st.hh, st.mm, st.ss); - - CVT_APPEND_STR(qb, tmp); - break; - - case SQL_TIMESTAMP: -#if (ODBCVER >= 0x0300) - case SQL_TYPE_TIMESTAMP: /* 93 */ -#endif - - if (buf) - { - my_strcpy(cbuf, sizeof(cbuf), buf, used); - parse_datetime(cbuf, &st); - } - - /* - * sprintf(tmp, "'%.4d-%.2d-%.2d %.2d:%.2d:%.2d'", st.y, - * st.m, st.d, st.hh, st.mm, st.ss); - */ - tmp[0] = '\''; - /* Time zone stuff is unreliable */ - stime2timestamp(&st, tmp + 1, USE_ZONE, PG_VERSION_GE(conn, 7.2)); - strcat(tmp, "'::timestamp"); - - CVT_APPEND_STR(qb, tmp); - - break; - - case SQL_BINARY: - case SQL_VARBINARY:/* non-ascii characters should be - * converted to octal */ - CVT_APPEND_CHAR(qb, '\''); /* Open Quote */ - - mylog("SQL_VARBINARY: about to call convert_to_pgbinary, used = %d\n", used); - - CVT_APPEND_BINARY(qb, buf, used); - - CVT_APPEND_CHAR(qb, '\''); /* Close Quote */ - - break; - - case SQL_LONGVARBINARY: - - if (opts->parameters[param_number].data_at_exec) - lobj_oid = opts->parameters[param_number].lobj_oid; - else - { - /* begin transaction if needed */ - if (!CC_is_in_trans(conn)) - { - if (!CC_begin(conn)) - { - qb->errormsg = "Could not begin (in-line) a transaction"; - qb->errornumber = STMT_EXEC_ERROR; - return SQL_ERROR; - } - } - - /* store the oid */ - lobj_oid = lo_creat(conn, INV_READ | INV_WRITE); - if (lobj_oid == 0) - { - qb->errornumber = STMT_EXEC_ERROR; - qb->errormsg = "Couldnt create (in-line) large object."; - return SQL_ERROR; - } - - /* store the fd */ - lobj_fd = lo_open(conn, lobj_oid, INV_WRITE); - if (lobj_fd < 0) - { - qb->errornumber = STMT_EXEC_ERROR; - qb->errormsg = "Couldnt open (in-line) large object for writing."; - return SQL_ERROR; - } - - retval = lo_write(conn, lobj_fd, buffer, used); - - lo_close(conn, lobj_fd); - - /* commit transaction if needed */ - if (!ci->drivers.use_declarefetch && CC_is_in_autocommit(conn)) - { - if (!CC_commit(conn)) - { - qb->errormsg = "Could not commit (in-line) a transaction"; - qb->errornumber = STMT_EXEC_ERROR; - return SQL_ERROR; - } - } - } - - /* - * the oid of the large object -- just put that in for the - * parameter marker -- the data has already been sent to - * the large object - */ - sprintf(param_string, "'%d'", lobj_oid); - CVT_APPEND_STR(qb, param_string); - - break; - - /* - * because of no conversion operator for bool and int4, - * SQL_BIT - */ - /* must be quoted (0 or 1 is ok to use inside the quotes) */ - - case SQL_REAL: - if (buf) - my_strcpy(param_string, sizeof(param_string), buf, used); - sprintf(tmp, "'%s'::float4", param_string); - CVT_APPEND_STR(qb, tmp); - break; - case SQL_FLOAT: - case SQL_DOUBLE: - if (buf) - my_strcpy(param_string, sizeof(param_string), buf, used); - sprintf(tmp, "'%s'::float8", param_string); - CVT_APPEND_STR(qb, tmp); - break; - case SQL_NUMERIC: - if (buf) - { - cbuf[0] = '\''; - my_strcpy(cbuf + 1, sizeof(cbuf) - 3, buf, used); /* 3 = 1('\'') + - * strlen("'") - * + 1('\0') */ - strcat(cbuf, "'"); - } - else - sprintf(cbuf, "'%s'", param_string); - CVT_APPEND_STR(qb, cbuf); - break; - default: /* a numeric type or SQL_BIT */ - if (param_sqltype == SQL_BIT) - CVT_APPEND_CHAR(qb, '\''); /* Open Quote */ - - if (buf) - { - switch (used) - { - case SQL_NULL_DATA: - break; - case SQL_NTS: - CVT_APPEND_STR(qb, buf); - break; - default: - CVT_APPEND_DATA(qb, buf, used); - } - } - else - CVT_APPEND_STR(qb, param_string); - - if (param_sqltype == SQL_BIT) - CVT_APPEND_CHAR(qb, '\''); /* Close Quote */ - - break; - } -#ifdef UNICODE_SUPPORT - if (allocbuf) - free(allocbuf); -#endif /* UNICODE_SUPPORT */ - return SQL_SUCCESS; -} - - -static const char * -mapFunction(const char *func, int param_count) -{ - int i; - - for (i = 0; mapFuncs[i][0]; i++) - { - if (mapFuncs[i][0][0] == '%') - { - if (mapFuncs[i][0][1] - '0' == param_count && - !stricmp(mapFuncs[i][0] + 2, func)) - return mapFuncs[i][1]; - } - else if (!stricmp(mapFuncs[i][0], func)) - return mapFuncs[i][1]; - } - - return NULL; -} - -/* - * processParameters() - * Process function parameters and work with embedded escapes sequences. - */ -static int -processParameters(QueryParse *qp, QueryBuild *qb, - UInt4 *output_count, Int4 param_pos[][2]) -{ - static const char *func = "processParameters"; - int retval, innerParenthesis, param_count; - BOOL stop; - - /* begin with outer '(' */ - innerParenthesis = 0; - param_count = 0; - stop = FALSE; - for (; F_OldPos(qp) < qp->stmt_len; F_OldNext(qp)) - { - retval = inner_process_tokens(qp, qb); - if (retval == SQL_ERROR) - return retval; -#ifdef MULTIBYTE - if (ENCODE_STATUS(qp->encstr) != 0) - continue; -#endif - if (qp->in_dquote || qp->in_quote || qp->in_escape) - continue; - - switch (F_OldChar(qp)) - { - case ',': - if (1 == innerParenthesis) - { - param_pos[param_count][1] = F_NewPos(qb) - 2; - param_count++; - param_pos[param_count][0] = F_NewPos(qb); - param_pos[param_count][1] = -1; - } - break; - case '(': - if (0 == innerParenthesis) - { - param_pos[param_count][0] = F_NewPos(qb); - param_pos[param_count][1] = -1; - } - innerParenthesis++; - break; - - case ')': - innerParenthesis--; - if (0 == innerParenthesis) - { - param_pos[param_count][1] = F_NewPos(qb) - 2; - param_count++; - param_pos[param_count][0] = - param_pos[param_count][1] = -1; - } - if (output_count) - *output_count = F_NewPos(qb); - break; - - case '}': - stop = (0 == innerParenthesis); - break; - - } - if (stop) /* returns with the last } position */ - break; - } - if (param_pos[param_count][0] >= 0) - { - mylog("%s closing ) not found %d\n", func, innerParenthesis); - qb->errornumber = STMT_EXEC_ERROR; - qb->errormsg = "processParameters closing ) not found"; - return SQL_ERROR; - } - else if (1 == param_count) /* the 1 parameter is really valid ? */ - { - BOOL param_exist = FALSE; - int i; - - for (i = param_pos[0][0]; i <= param_pos[0][1]; i++) - { - if (!isspace(qb->query_statement[i])) - { - param_exist = TRUE; - break; - } - } - if (!param_exist) - { - param_pos[0][0] = param_pos[0][1] = -1; - } - } - - return SQL_SUCCESS; -} - -/* - * convert_escape() - * This function doesn't return a pointer to static memory any longer ! - */ -static int -convert_escape(QueryParse *qp, QueryBuild *qb) -{ - static const char *func = "convert_escape"; - RETCODE retval = SQL_SUCCESS; - char buf[1024], key[65]; - unsigned char ucv; - UInt4 prtlen; - - if (F_OldChar(qp) == '{') /* skip the first { */ - F_OldNext(qp); - /* Separate off the key, skipping leading and trailing whitespace */ - while ((ucv = F_OldChar(qp)) != '\0' && isspace(ucv)) - F_OldNext(qp); - /* - * procedure calls - */ - if (qp->statement_type == STMT_TYPE_PROCCALL) - { - int lit_call_len = 4; - ConnectionClass *conn = qb->conn; - - /* '?=' to accept return values exists ? */ - if (F_OldChar(qp) == '?') - { - qb->param_number++; - while (isspace((unsigned char) qp->statement[++qp->opos])); - if (F_OldChar(qp) != '=') - { - F_OldPrior(qp); - return SQL_SUCCESS; - } - while (isspace((unsigned char) qp->statement[++qp->opos])); - } - if (strnicmp(F_OldPtr(qp), "call", lit_call_len) || - !isspace((unsigned char) F_OldPtr(qp)[lit_call_len])) - { - F_OldPrior(qp); - return SQL_SUCCESS; - } - qp->opos += lit_call_len; - CVT_APPEND_STR(qb, "SELECT "); - if (my_strchr(conn, F_OldPtr(qp), '(')) - qp->proc_no_param = FALSE; - return SQL_SUCCESS; - } - - sscanf(F_OldPtr(qp), "%32s", key); - while ((ucv = F_OldChar(qp)) != '\0' && (!isspace(ucv))) - F_OldNext(qp); - while ((ucv = F_OldChar(qp)) != '\0' && isspace(ucv)) - F_OldNext(qp); - - /* Avoid the concatenation of the function name with the previous word. Aceto */ - - if (F_NewPos(qb) > 0 && isalnum(F_NewPtr(qb)[-1])) - CVT_APPEND_CHAR(qb, ' '); - - if (strcmp(key, "d") == 0) - { - /* Literal; return the escape part adding type cast */ - F_ExtractOldTo(qp, buf, '}', sizeof(buf)); - prtlen = snprintf(buf, sizeof(buf), "%s::date ", buf); - CVT_APPEND_DATA(qb, buf, prtlen); - } - else if (strcmp(key, "t") == 0) - { - /* Literal; return the escape part adding type cast */ - F_ExtractOldTo(qp, buf, '}', sizeof(buf)); - prtlen = snprintf(buf, sizeof(buf), "%s::time", buf); - CVT_APPEND_DATA(qb, buf, prtlen); - } - else if (strcmp(key, "ts") == 0) - { - /* Literal; return the escape part adding type cast */ - F_ExtractOldTo(qp, buf, '}', sizeof(buf)); - if (PG_VERSION_LT(qb->conn, 7.1)) - prtlen = snprintf(buf, sizeof(buf), "%s::datetime", buf); - else - prtlen = snprintf(buf, sizeof(buf), "%s::timestamp", buf); - CVT_APPEND_DATA(qb, buf, prtlen); - } - else if (strcmp(key, "oj") == 0) /* {oj syntax support for 7.1 * servers */ - { - F_OldPrior(qp); - return SQL_SUCCESS; /* Continue at inner_process_tokens loop */ - } - else if (strcmp(key, "fn") == 0) - { - QueryBuild nqb; - const char *mapExpr; - int i, param_count; - UInt4 param_consumed; - Int4 param_pos[16][2]; - - /* Separate off the func name, skipping leading and trailing whitespace */ - i = 0; - while ((ucv = F_OldChar(qp)) != '\0' && ucv != '(' && - (!isspace(ucv))) - { - if (i < sizeof(key)-1) - key[i++] = ucv; - F_OldNext(qp); - } - key[i] = '\0'; - while ((ucv = F_OldChar(qp)) != '\0' && isspace(ucv)) - F_OldNext(qp); - - /* - * We expect left parenthesis here, else return fn body as-is - * since it is one of those "function constants". - */ - if (F_OldChar(qp) != '(') - { - CVT_APPEND_STR(qb, key); - return SQL_SUCCESS; - } - - /* - * Process parameter list and inner escape - * sequences - * Aceto 2002-01-29 - */ - - QB_initialize_copy(&nqb, qb, 1024); - if (retval = processParameters(qp, &nqb, ¶m_consumed, param_pos), retval == SQL_ERROR) - { - qb->errornumber = nqb.errornumber; - qb->errormsg = nqb.errormsg; - QB_Destructor(&nqb); - return retval; - } - - for (param_count = 0;; param_count++) - { - if (param_pos[param_count][0] < 0) - break; - } - if (param_count == 1 && - param_pos[0][1] < param_pos[0][0]) - param_count = 0; - - mapExpr = mapFunction(key, param_count); - if (mapExpr == NULL) - { - CVT_APPEND_STR(qb, key); - CVT_APPEND_DATA(qb, nqb.query_statement, nqb.npos); - } - else - { - const char *mapptr; - int from, to, pidx, paramlen; - - for (prtlen = 0, mapptr = mapExpr; *mapptr; mapptr++) - { - if (*mapptr != '$') - { - CVT_APPEND_CHAR(qb, *mapptr); - continue; - } - mapptr++; - if (*mapptr == '*') - { - from = 1; - to = param_consumed - 2; - } - else if (isdigit(*mapptr)) - { - pidx = *mapptr - '0' - 1; - if (pidx < 0 || - param_pos[pidx][0] < 0) - { - qb->errornumber = STMT_EXEC_ERROR; - qb->errormsg = "param not found"; - qlog("%s %dth param not found for the expression %s\n", pidx + 1, mapExpr); - retval = SQL_ERROR; - break; - } - from = param_pos[pidx][0]; - to = param_pos[pidx][1]; - } - else - { - qb->errornumber = STMT_EXEC_ERROR; - qb->errormsg = "internal expression error"; - qlog("%s internal expression error %s\n", func, mapExpr); - retval = SQL_ERROR; - break; - } - paramlen = to - from + 1; - if (paramlen > 0) - CVT_APPEND_DATA(qb, nqb.query_statement+ from, paramlen); - } - } - if (0 == qb->errornumber) - { - qb->errornumber = nqb.errornumber; - qb->errormsg = nqb.errormsg; - } - if (SQL_ERROR != retval) - { - qb->param_number = nqb.param_number; - qb->flags = nqb.flags; - } - QB_Destructor(&nqb); - } - else - { - /* Bogus key, leave untranslated */ - return SQL_ERROR; - } - - return retval; -} - -BOOL -convert_money(const char *s, char *sout, size_t soutmax) -{ - size_t i = 0, - out = 0; - - for (i = 0; s[i]; i++) - { - if (s[i] == '$' || s[i] == ',' || s[i] == ')') - ; /* skip these characters */ - else - { - if (out + 1 >= soutmax) - return FALSE; /* sout is too short */ - if (s[i] == '(') - sout[out++] = '-'; - else - sout[out++] = s[i]; - } - } - sout[out] = '\0'; - return TRUE; -} - - -/* - * This function parses a character string for date/time info and fills in SIMPLE_TIME - * It does not zero out SIMPLE_TIME in case it is desired to initialize it with a value - */ -char -parse_datetime(const char *buf, SIMPLE_TIME *st) -{ - int y, - m, - d, - hh, - mm, - ss; - int nf; - - y = m = d = hh = mm = ss = 0; - st->fr = 0; - st->infinity = 0; - - /* escape sequence ? */ - if (buf[0] == '{') - { - while (*(++buf) && *buf != '\''); - if (!(*buf)) - return FALSE; - buf++; - } - if (buf[4] == '-') /* year first */ - nf = sscanf(buf, "%4d-%2d-%2d %2d:%2d:%2d", &y, &m, &d, &hh, &mm, &ss); - else - nf = sscanf(buf, "%2d-%2d-%4d %2d:%2d:%2d", &m, &d, &y, &hh, &mm, &ss); - - if (nf == 5 || nf == 6) - { - st->y = y; - st->m = m; - st->d = d; - st->hh = hh; - st->mm = mm; - st->ss = ss; - - return TRUE; - } - - if (buf[4] == '-') /* year first */ - nf = sscanf(buf, "%4d-%2d-%2d", &y, &m, &d); - else - nf = sscanf(buf, "%2d-%2d-%4d", &m, &d, &y); - - if (nf == 3) - { - st->y = y; - st->m = m; - st->d = d; - - return TRUE; - } - - nf = sscanf(buf, "%2d:%2d:%2d", &hh, &mm, &ss); - if (nf == 2 || nf == 3) - { - st->hh = hh; - st->mm = mm; - st->ss = ss; - - return TRUE; - } - - return FALSE; -} - - -/* Change linefeed to carriage-return/linefeed */ -int -convert_linefeeds(const char *si, char *dst, size_t max, BOOL convlf, BOOL *changed) -{ - size_t i = 0, - out = 0; - - if (max == 0) - max = 0xffffffff; - *changed = FALSE; - for (i = 0; si[i] && out < max - 1; i++) - { - if (convlf && si[i] == '\n') - { - /* Only add the carriage-return if needed */ - if (i > 0 && si[i - 1] == '\r') - { - if (dst) - dst[out++] = si[i]; - else - out++; - continue; - } - *changed = TRUE; - - if (dst) - { - dst[out++] = '\r'; - dst[out++] = '\n'; - } - else - out += 2; - } - else - { - if (dst) - dst[out++] = si[i]; - else - out++; - } - } - if (dst) - dst[out] = '\0'; - return out; -} - - -/* - * Change carriage-return/linefeed to just linefeed - * Plus, escape any special characters. - */ -int -convert_special_chars(const char *si, char *dst, int used, BOOL convlf, int ccsc) -{ - size_t i = 0, - out = 0, - max; - char *p = NULL; -#ifdef MULTIBYTE - encoded_str encstr; -#endif - - - if (used == SQL_NTS) - max = strlen(si); - else - max = used; - if (dst) - { - p = dst; - p[0] = '\0'; - } -#ifdef MULTIBYTE - encoded_str_constr(&encstr, ccsc, si); -#endif - - for (i = 0; i < max && si[i]; i++) - { -#ifdef MULTIBYTE - encoded_nextchar(&encstr); - if (ENCODE_STATUS(encstr) != 0) - { - if (p) - p[out] = si[i]; - out++; - continue; - } -#endif - if (convlf && si[i] == '\r' && si[i + 1] == '\n') - continue; - else if (si[i] == '\'' || si[i] == '\\') - { - if (p) - p[out++] = '\\'; - else - out++; - } - if (p) - p[out++] = si[i]; - else - out++; - } - if (p) - p[out] = '\0'; - return out; -} - - -/* !!! Need to implement this function !!! */ -int -convert_pgbinary_to_char(const char *value, char *rgbValue, int cbValueMax) -{ - mylog("convert_pgbinary_to_char: value = '%s'\n", value); - - strncpy_null(rgbValue, value, cbValueMax); - return 0; -} - - -static unsigned int -conv_from_octal(const unsigned char *s) -{ - int i, - y = 0; - - for (i = 1; i <= 3; i++) - y += (s[i] - '0') << (3 * (3 - i)); - - return y; - -} - - -static unsigned int -conv_from_hex(const unsigned char *s) -{ - int i, - y = 0, - val; - - for (i = 1; i <= 2; i++) - { - if (s[i] >= 'a' && s[i] <= 'f') - val = s[i] - 'a' + 10; - else if (s[i] >= 'A' && s[i] <= 'F') - val = s[i] - 'A' + 10; - else - val = s[i] - '0'; - - y += val << (4 * (2 - i)); - } - - return y; -} - - -/* convert octal escapes to bytes */ -int -convert_from_pgbinary(const unsigned char *value, unsigned char *rgbValue, int cbValueMax) -{ - size_t i, - ilen = strlen(value); - int o = 0; - - - for (i = 0; i < ilen;) - { - if (value[i] == '\\') - { - if (value[i + 1] == '\\') - { - rgbValue[o] = value[i]; - i += 2; - } - else - { - rgbValue[o] = conv_from_octal(&value[i]); - i += 4; - } - } - else - rgbValue[o] = value[i++]; - mylog("convert_from_pgbinary: i=%d, rgbValue[%d] = %d, %c\n", i, o, rgbValue[o], rgbValue[o]); - o++; - } - - rgbValue[o] = '\0'; /* extra protection */ - - return o; -} - - -static char * -conv_to_octal(unsigned char val) -{ - int i; - static char x[6]; - - x[0] = '\\'; - x[1] = '\\'; - x[5] = '\0'; - - for (i = 4; i > 1; i--) - { - x[i] = (val & 7) + '0'; - val >>= 3; - } - - return x; -} - - -/* convert non-ascii bytes to octal escape sequences */ -int -convert_to_pgbinary(const unsigned char *in, char *out, int len) -{ - int i, - o = 0; - - for (i = 0; i < len; i++) - { - mylog("convert_to_pgbinary: in[%d] = %d, %c\n", i, in[i], in[i]); - if (isalnum(in[i]) || in[i] == ' ') - out[o++] = in[i]; - else - { - strcpy(&out[o], conv_to_octal(in[i])); - o += 5; - } - } - - mylog("convert_to_pgbinary: returning %d, out='%.*s'\n", o, o, out); - - return o; -} - - -void -encode(const char *in, char *out) -{ - unsigned int i, - ilen = strlen(in), - o = 0; - - for (i = 0; i < ilen; i++) - { - if (in[i] == '+') - { - sprintf(&out[o], "%%2B"); - o += 3; - } - else if (isspace((unsigned char) in[i])) - out[o++] = '+'; - else if (!isalnum((unsigned char) in[i])) - { - sprintf(&out[o], "%%%02x", (unsigned char) in[i]); - o += 3; - } - else - out[o++] = in[i]; - } - out[o++] = '\0'; -} - - -void -decode(const char *in, char *out) -{ - unsigned int i, - ilen = strlen(in), - o = 0; - - for (i = 0; i < ilen; i++) - { - if (in[i] == '+') - out[o++] = ' '; - else if (in[i] == '%') - { - sprintf(&out[o++], "%c", conv_from_hex(&in[i])); - i += 2; - } - else - out[o++] = in[i]; - } - out[o++] = '\0'; -} - -static const char *hextbl = "0123456789ABCDEF"; -static int -pg_bin2hex(UCHAR *src, UCHAR *dst, int length) -{ - UCHAR chr, - *src_wk, - *dst_wk; - BOOL backwards; - int i; - - backwards = FALSE; - if (dst < src) - { - if (dst + length > src + 1) - return -1; - } - else if (dst < src + length) - backwards = TRUE; - if (backwards) - { - for (i = 0, src_wk = src + length - 1, dst_wk = dst + 2 * length - 1; i < length; i++, src_wk--) - { - chr = *src_wk; - *dst_wk-- = hextbl[chr % 16]; - *dst_wk-- = hextbl[chr >> 4]; - } - } - else - { - for (i = 0, src_wk = src, dst_wk = dst; i < length; i++, src_wk++) - { - chr = *src_wk; - *dst_wk++ = hextbl[chr >> 4]; - *dst_wk++ = hextbl[chr % 16]; - } - } - dst[2 * length] = '\0'; - return length; -} - -/*------- - * 1. get oid (from 'value') - * 2. open the large object - * 3. read from the large object (handle multiple GetData) - * 4. close when read less than requested? -OR- - * lseek/read each time - * handle case where application receives truncated and - * decides not to continue reading. - * - * CURRENTLY, ONLY LONGVARBINARY is handled, since that is the only - * data type currently mapped to a PG_TYPE_LO. But, if any other types - * are desired to map to a large object (PG_TYPE_LO), then that would - * need to be handled here. For example, LONGVARCHAR could possibly be - * mapped to PG_TYPE_LO someday, instead of PG_TYPE_TEXT as it is now. - *------- - */ -int -convert_lo(StatementClass *stmt, const void *value, Int2 fCType, PTR rgbValue, - SDWORD cbValueMax, SDWORD *pcbValue) -{ - Oid oid; - int retval, - result, - left = -1; - BindInfoClass *bindInfo = NULL; - ConnectionClass *conn = SC_get_conn(stmt); - ConnInfo *ci = &(conn->connInfo); - ARDFields *opts = SC_get_ARD(stmt); - int factor = (fCType == SQL_C_CHAR ? 2 : 1); - - /* If using SQLGetData, then current_col will be set */ - if (stmt->current_col >= 0) - { - bindInfo = &opts->bindings[stmt->current_col]; - left = bindInfo->data_left; - } - - /* - * if this is the first call for this column, open the large object - * for reading - */ - - if (!bindInfo || bindInfo->data_left == -1) - { - /* begin transaction if needed */ - if (!CC_is_in_trans(conn)) - { - if (!CC_begin(conn)) - { - stmt->errormsg = "Could not begin (in-line) a transaction"; - stmt->errornumber = STMT_EXEC_ERROR; - return COPY_GENERAL_ERROR; - } - } - - oid = atoi(value); - stmt->lobj_fd = lo_open(conn, oid, INV_READ); - if (stmt->lobj_fd < 0) - { - stmt->errornumber = STMT_EXEC_ERROR; - stmt->errormsg = "Couldnt open large object for reading."; - return COPY_GENERAL_ERROR; - } - - /* Get the size */ - retval = lo_lseek(conn, stmt->lobj_fd, 0L, SEEK_END); - if (retval >= 0) - { - left = lo_tell(conn, stmt->lobj_fd); - if (bindInfo) - bindInfo->data_left = left; - - /* return to beginning */ - lo_lseek(conn, stmt->lobj_fd, 0L, SEEK_SET); - } - } - mylog("lo data left = %d\n", left); - - if (left == 0) - return COPY_NO_DATA_FOUND; - - if (stmt->lobj_fd < 0) - { - stmt->errornumber = STMT_EXEC_ERROR; - stmt->errormsg = "Large object FD undefined for multiple read."; - return COPY_GENERAL_ERROR; - } - - retval = lo_read(conn, stmt->lobj_fd, (char *) rgbValue, factor > 1 ? (cbValueMax - 1) / factor : cbValueMax); - if (retval < 0) - { - lo_close(conn, stmt->lobj_fd); - - /* commit transaction if needed */ - if (!ci->drivers.use_declarefetch && CC_is_in_autocommit(conn)) - { - if (!CC_commit(conn)) - { - stmt->errormsg = "Could not commit (in-line) a transaction"; - stmt->errornumber = STMT_EXEC_ERROR; - return COPY_GENERAL_ERROR; - } - } - - stmt->lobj_fd = -1; - - stmt->errornumber = STMT_EXEC_ERROR; - stmt->errormsg = "Error reading from large object."; - return COPY_GENERAL_ERROR; - } - - if (factor > 1) - pg_bin2hex((char *) rgbValue, (char *) rgbValue, retval); - if (retval < left) - result = COPY_RESULT_TRUNCATED; - else - result = COPY_OK; - - if (pcbValue) - *pcbValue = left < 0 ? SQL_NO_TOTAL : left * factor; - - if (bindInfo && bindInfo->data_left > 0) - bindInfo->data_left -= retval; - - if (!bindInfo || bindInfo->data_left == 0) - { - lo_close(conn, stmt->lobj_fd); - - /* commit transaction if needed */ - if (!ci->drivers.use_declarefetch && CC_is_in_autocommit(conn)) - { - if (!CC_commit(conn)) - { - stmt->errormsg = "Could not commit (in-line) a transaction"; - stmt->errornumber = STMT_EXEC_ERROR; - return COPY_GENERAL_ERROR; - } - } - - stmt->lobj_fd = -1; /* prevent further reading */ - } - - return result; -} diff --git a/src/interfaces/odbc/convert.h b/src/interfaces/odbc/convert.h deleted file mode 100644 index 8f65472e1f2..00000000000 --- a/src/interfaces/odbc/convert.h +++ /dev/null @@ -1,56 +0,0 @@ -/* File: convert.h - * - * Description: See "convert.c" - * - * Comments: See "notice.txt" for copyright and license information. - * - */ - -#ifndef __CONVERT_H__ -#define __CONVERT_H__ - -#include "psqlodbc.h" - -/* copy_and_convert results */ -#define COPY_OK 0 -#define COPY_UNSUPPORTED_TYPE 1 -#define COPY_UNSUPPORTED_CONVERSION 2 -#define COPY_RESULT_TRUNCATED 3 -#define COPY_GENERAL_ERROR 4 -#define COPY_NO_DATA_FOUND 5 -/* convert_escape results */ -#define CONVERT_ESCAPE_OK 0 -#define CONVERT_ESCAPE_OVERFLOW 1 -#define CONVERT_ESCAPE_ERROR -1 - -typedef struct -{ - int infinity; - int m; - int d; - int y; - int hh; - int mm; - int ss; - int fr; -} SIMPLE_TIME; - -int copy_and_convert_field_bindinfo(StatementClass *stmt, Int4 field_type, void *value, int col); -int copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2 fCType, - PTR rgbValue, SDWORD cbValueMax, SDWORD *pcbValue); - -int copy_statement_with_parameters(StatementClass *stmt); -BOOL convert_money(const char *s, char *sout, size_t soutmax); -char parse_datetime(const char *buf, SIMPLE_TIME *st); -int convert_linefeeds(const char *s, char *dst, size_t max, BOOL convlf, BOOL *changed); -int convert_special_chars(const char *si, char *dst, int used, BOOL convlf,int ccsc); - -int convert_pgbinary_to_char(const char *value, char *rgbValue, int cbValueMax); -int convert_from_pgbinary(const unsigned char *value, unsigned char *rgbValue, int cbValueMax); -int convert_to_pgbinary(const unsigned char *in, char *out, int len); -void encode(const char *in, char *out); -void decode(const char *in, char *out); -int convert_lo(StatementClass *stmt, const void *value, Int2 fCType, PTR rgbValue, - SDWORD cbValueMax, SDWORD *pcbValue); - -#endif diff --git a/src/interfaces/odbc/descriptor.h b/src/interfaces/odbc/descriptor.h deleted file mode 100644 index c3f016a7dca..00000000000 --- a/src/interfaces/odbc/descriptor.h +++ /dev/null @@ -1,104 +0,0 @@ -/* File: descriptor.h - * - * Description: This file contains defines and declarations that are related to - * the entire driver. - * - * Comments: See "notice.txt" for copyright and license information. - * - * $Id: descriptor.h,v 1.6 2002/06/06 04:50:47 inoue Exp $ - * - */ - -#ifndef __DESCRIPTOR_H__ -#define __DESCRIPTOR_H__ - -#include "psqlodbc.h" - -typedef struct -{ - COL_INFO *col_info; /* cached SQLColumns info for this table */ - char schema[MAX_SCHEMA_LEN + 1]; - char name[MAX_TABLE_LEN + 1]; - char alias[MAX_TABLE_LEN + 1]; - char updatable; -} TABLE_INFO; - -typedef struct -{ - TABLE_INFO *ti; /* resolve to explicit table names */ - int column_size; /* precision in 2.x */ - int decimal_digits; /* scale in 2.x */ - int display_size; - int length; - int type; - char nullable; - char func; - char expr; - char quote; - char dquote; - char numeric; - char updatable; - char dot[MAX_TABLE_LEN + 1]; - char name[MAX_COLUMN_LEN + 1]; - char alias[MAX_COLUMN_LEN + 1]; - char *schema; -} FIELD_INFO; -Int4 FI_precision(const FIELD_INFO *); -Int4 FI_scale(const FIELD_INFO *); - -struct ARDFields_ -{ - StatementClass *stmt; - int rowset_size; - int bind_size; /* size of each structure if using Row - * Binding */ - UInt2 *row_operation_ptr; - UInt4 *row_offset_ptr; - BindInfoClass *bookmark; - BindInfoClass *bindings; - int allocated; -}; - -struct APDFields_ -{ - StatementClass *stmt; - int paramset_size; - int param_bind_type; /* size of each structure if using Param - * Binding */ - UInt2 *param_operation_ptr; - UInt4 *param_offset_ptr; - ParameterInfoClass *parameters; - int allocated; -}; - -struct IRDFields_ -{ - StatementClass *stmt; - UInt4 *rowsFetched; - UInt2 *rowStatusArray; - UInt4 nfields; - FIELD_INFO **fi; -}; - -struct IPDFields_ -{ - StatementClass *stmt; - UInt4 *param_processed_ptr; - UInt2 *param_status_ptr; -}; - -void InitializeARDFields(ARDFields *self); -void InitializeAPDFields(APDFields *self); -/* void InitializeIRDFields(IRDFields *self); -void InitializeIPDFiedls(IPDFields *self); */ -void ARDFields_free(ARDFields *self); -void APDFields_free(APDFields *self); -void IRDFields_free(IRDFields *self); -void IPDFields_free(IPDFields *self); -void ARD_unbind_cols(ARDFields *self, BOOL freeall); -void APD_free_params(APDFields *self, char option); -#if (ODBCVER >= 0x0300) -void Desc_set_error(SQLHDESC hdesc, int errornumber, const char * errormsg); -#endif /* ODBCVER */ - -#endif diff --git a/src/interfaces/odbc/dlg_specific.c b/src/interfaces/odbc/dlg_specific.c deleted file mode 100644 index 4f96a6f7c56..00000000000 --- a/src/interfaces/odbc/dlg_specific.c +++ /dev/null @@ -1,971 +0,0 @@ -/*------- - * Module: dlg_specific.c - * - * Description: This module contains any specific code for handling - * dialog boxes such as driver/datasource options. Both the - * ConfigDSN() and the SQLDriverConnect() functions use - * functions in this module. If you were to add a new option - * to any dialog box, you would most likely only have to change - * things in here rather than in 2 separate places as before. - * - * Classes: none - * - * API functions: none - * - * Comments: See "notice.txt" for copyright and license information. - *------- - */ -/* Multibyte support Eiji Tokuya 2001-03-15 */ - -#include "dlg_specific.h" - -#include "convert.h" - -#ifdef MULTIBYTE -#include "multibyte.h" -#endif -#include "pgapifunc.h" - -#ifndef BOOL -#define BOOL int -#endif -#ifndef FALSE -#define FALSE (BOOL)0 -#endif -#ifndef TRUE -#define TRUE (BOOL)1 -#endif - -extern GLOBAL_VALUES globals; - -void -makeConnectString(char *connect_string, const ConnInfo *ci, UWORD len) -{ - char got_dsn = (ci->dsn[0] != '\0'); - char encoded_conn_settings[LARGE_REGISTRY_LEN]; - UWORD hlen; - /*BOOL abbrev = (len <= 400);*/ - BOOL abbrev = (len < 1024); - - /* fundamental info */ - sprintf(connect_string, "%s=%s;DATABASE=%s;SERVER=%s;PORT=%s;UID=%s;PWD=%s", - got_dsn ? "DSN" : "DRIVER", - got_dsn ? ci->dsn : ci->driver, - ci->database, - ci->server, - ci->port, - ci->username, - ci->password); - - encode(ci->conn_settings, encoded_conn_settings); - - /* extra info */ - hlen = strlen(connect_string); - if (!abbrev) - sprintf(&connect_string[hlen], - ";%s=%s;%s=%s;%s=%s;%s=%s;%s=%s;%s=%s;%s=%s;%s=%d;%s=%d;%s=%d;%s=%d;%s=%d;%s=%d;%s=%d;%s=%d;%s=%d;%s=%d;%s=%d;%s=%d;%s=%d;%s=%d;%s=%d;%s=%s;%s=%d;%s=%d;%s=%d;%s=%d;%s=%d", - INI_READONLY, - ci->onlyread, - INI_PROTOCOL, - ci->protocol, - INI_FAKEOIDINDEX, - ci->fake_oid_index, - INI_SHOWOIDCOLUMN, - ci->show_oid_column, - INI_ROWVERSIONING, - ci->row_versioning, - INI_SHOWSYSTEMTABLES, - ci->show_system_tables, - INI_CONNSETTINGS, - encoded_conn_settings, - INI_FETCH, - ci->drivers.fetch_max, - INI_SOCKET, - ci->drivers.socket_buffersize, - INI_UNKNOWNSIZES, - ci->drivers.unknown_sizes, - INI_MAXVARCHARSIZE, - ci->drivers.max_varchar_size, - INI_MAXLONGVARCHARSIZE, - ci->drivers.max_longvarchar_size, - INI_DEBUG, - ci->drivers.debug, - INI_COMMLOG, - ci->drivers.commlog, - INI_OPTIMIZER, - ci->drivers.disable_optimizer, - INI_KSQO, - ci->drivers.ksqo, - INI_USEDECLAREFETCH, - ci->drivers.use_declarefetch, - INI_TEXTASLONGVARCHAR, - ci->drivers.text_as_longvarchar, - INI_UNKNOWNSASLONGVARCHAR, - ci->drivers.unknowns_as_longvarchar, - INI_BOOLSASCHAR, - ci->drivers.bools_as_char, - INI_PARSE, - ci->drivers.parse, - INI_CANCELASFREESTMT, - ci->drivers.cancel_as_freestmt, - INI_EXTRASYSTABLEPREFIXES, - ci->drivers.extra_systable_prefixes, - INI_LFCONVERSION, - ci->lf_conversion, - INI_UPDATABLECURSORS, - ci->allow_keyset, - INI_DISALLOWPREMATURE, - ci->disallow_premature, - INI_TRUEISMINUS1, - ci->true_is_minus1, - INI_INT8AS, - ci->true_is_minus1); - /* Abbrebiation is needed ? */ - if (abbrev || strlen(connect_string) >= len) - { - unsigned long flag = 0; - if (ci->disallow_premature) - flag |= BIT_DISALLOWPREMATURE; - if (ci->allow_keyset) - flag |= BIT_UPDATABLECURSORS; - if (ci->lf_conversion) - flag |= BIT_LFCONVERSION; - if (ci->drivers.unique_index) - flag |= BIT_UNIQUEINDEX; - if (strncmp(ci->protocol, PG64, strlen(PG64)) == 0) - flag |= BIT_PROTOCOL_64; - else if (strncmp(ci->protocol, PG63, strlen(PG63)) == 0) - flag |= BIT_PROTOCOL_63; - switch (ci->drivers.unknown_sizes) - { - case UNKNOWNS_AS_DONTKNOW: - flag |= BIT_UNKNOWN_DONTKNOW; - break; - case UNKNOWNS_AS_MAX: - flag |= BIT_UNKNOWN_ASMAX; - break; - } - if (ci->drivers.disable_optimizer) - flag |= BIT_OPTIMIZER; - if (ci->drivers.ksqo) - flag |= BIT_KSQO; - if (ci->drivers.commlog) - flag |= BIT_COMMLOG; - if (ci->drivers.debug) - flag |= BIT_DEBUG; - if (ci->drivers.parse) - flag |= BIT_PARSE; - if (ci->drivers.cancel_as_freestmt) - flag |= BIT_CANCELASFREESTMT; - if (ci->drivers.use_declarefetch) - flag |= BIT_USEDECLAREFETCH; - if (ci->onlyread[0] == '1') - flag |= BIT_READONLY; - if (ci->drivers.text_as_longvarchar) - flag |= BIT_TEXTASLONGVARCHAR; - if (ci->drivers.unknowns_as_longvarchar) - flag |= BIT_UNKNOWNSASLONGVARCHAR; - if (ci->drivers.bools_as_char) - flag |= BIT_BOOLSASCHAR; - if (ci->row_versioning[0] == '1') - flag |= BIT_ROWVERSIONING; - if (ci->show_system_tables[0] == '1') - flag |= BIT_SHOWSYSTEMTABLES; - if (ci->show_oid_column[0] == '1') - flag |= BIT_SHOWOIDCOLUMN; - if (ci->fake_oid_index[0] == '1') - flag |= BIT_FAKEOIDINDEX; - if (ci->true_is_minus1) - flag |= BIT_TRUEISMINUS1; - - sprintf(&connect_string[hlen], - ";A6=%s;A7=%d;A8=%d;B0=%d;B1=%d;%s=%d;C2=%s;CX=%02x%lx", - encoded_conn_settings, - ci->drivers.fetch_max, - ci->drivers.socket_buffersize, - ci->drivers.max_varchar_size, - ci->drivers.max_longvarchar_size, - INI_INT8AS, - ci->int8_as, - ci->drivers.extra_systable_prefixes, - EFFECTIVE_BIT_COUNT, - flag); - } -} - -static void -unfoldCXAttribute(ConnInfo *ci, const char *value) -{ - int count; - unsigned long flag; - - if (strlen(value) < 2) - { - count = 3; - sscanf(value, "%lx", &flag); - } - else - { - char cnt[8]; - memcpy(cnt, value, 2); - cnt[2] = '\0'; - sscanf(cnt, "%x", &count); - sscanf(value + 2, "%lx", &flag); - } - ci->disallow_premature = (char)((flag & BIT_DISALLOWPREMATURE) != 0); - ci->allow_keyset = (char)((flag & BIT_UPDATABLECURSORS) != 0); - ci->lf_conversion = (char)((flag & BIT_LFCONVERSION) != 0); - if (count < 4) - return; - ci->drivers.unique_index = (char)((flag & BIT_UNIQUEINDEX) != 0); - if ((flag & BIT_PROTOCOL_64) != 0) - strcpy(ci->protocol, PG64); - else if ((flag & BIT_PROTOCOL_63) != 0) - strcpy(ci->protocol, PG63); - else - strcpy(ci->protocol, PG62); - if ((flag & BIT_UNKNOWN_DONTKNOW) != 0) - ci->drivers.unknown_sizes = UNKNOWNS_AS_DONTKNOW; - else if ((flag & BIT_UNKNOWN_ASMAX) != 0) - ci->drivers.unknown_sizes = UNKNOWNS_AS_MAX; - else - ci->drivers.unknown_sizes = UNKNOWNS_AS_LONGEST; - ci->drivers.disable_optimizer = (char)((flag & BIT_OPTIMIZER) != 0); - ci->drivers.ksqo = (char)((flag & BIT_KSQO) != 0); - ci->drivers.commlog = (char)((flag & BIT_COMMLOG) != 0); - ci->drivers.debug = (char)((flag & BIT_DEBUG) != 0); - ci->drivers.parse = (char)((flag & BIT_PARSE) != 0); - ci->drivers.cancel_as_freestmt = (char)((flag & BIT_CANCELASFREESTMT) != 0); - ci->drivers.use_declarefetch = (char)((flag & BIT_USEDECLAREFETCH) != 0); - sprintf(ci->onlyread, "%d", (char)((flag & BIT_READONLY) != 0)); - ci->drivers.text_as_longvarchar = (char)((flag & BIT_TEXTASLONGVARCHAR) !=0); - ci->drivers.unknowns_as_longvarchar = (char)((flag & BIT_UNKNOWNSASLONGVARCHAR) !=0); - ci->drivers.bools_as_char = (char)((flag & BIT_BOOLSASCHAR) != 0); - sprintf(ci->row_versioning, "%d", (char)((flag & BIT_ROWVERSIONING) != 0)); - sprintf(ci->show_system_tables, "%d", (char)((flag & BIT_SHOWSYSTEMTABLES) != 0)); - sprintf(ci->show_oid_column, "%d", (char)((flag & BIT_SHOWOIDCOLUMN) != 0)); - sprintf(ci->fake_oid_index, "%d", (char)((flag & BIT_FAKEOIDINDEX) != 0)); - ci->true_is_minus1 = (char)((flag & BIT_TRUEISMINUS1) != 0); -} -void -copyAttributes(ConnInfo *ci, const char *attribute, const char *value) -{ - if (stricmp(attribute, "DSN") == 0) - strcpy(ci->dsn, value); - - else if (stricmp(attribute, "driver") == 0) - strcpy(ci->driver, value); - - else if (stricmp(attribute, INI_DATABASE) == 0) - strcpy(ci->database, value); - - else if (stricmp(attribute, INI_SERVER) == 0 || stricmp(attribute, "server") == 0) - strcpy(ci->server, value); - - else if (stricmp(attribute, INI_USER) == 0 || stricmp(attribute, "uid") == 0) - strcpy(ci->username, value); - - else if (stricmp(attribute, INI_PASSWORD) == 0 || stricmp(attribute, "pwd") == 0) - strcpy(ci->password, value); - - else if (stricmp(attribute, INI_PORT) == 0) - strcpy(ci->port, value); - - else if (stricmp(attribute, INI_READONLY) == 0 || stricmp(attribute, "A0") == 0) - strcpy(ci->onlyread, value); - - else if (stricmp(attribute, INI_PROTOCOL) == 0 || stricmp(attribute, "A1") == 0) - strcpy(ci->protocol, value); - - else if (stricmp(attribute, INI_SHOWOIDCOLUMN) == 0 || stricmp(attribute, "A3") == 0) - strcpy(ci->show_oid_column, value); - - else if (stricmp(attribute, INI_FAKEOIDINDEX) == 0 || stricmp(attribute, "A2") == 0) - strcpy(ci->fake_oid_index, value); - - else if (stricmp(attribute, INI_ROWVERSIONING) == 0 || stricmp(attribute, "A4") == 0) - strcpy(ci->row_versioning, value); - - else if (stricmp(attribute, INI_SHOWSYSTEMTABLES) == 0 || stricmp(attribute, "A5") == 0) - strcpy(ci->show_system_tables, value); - - else if (stricmp(attribute, INI_CONNSETTINGS) == 0 || stricmp(attribute, "A6") == 0) - { - decode(value, ci->conn_settings); - /* strcpy(ci->conn_settings, value); */ - } - else if (stricmp(attribute, INI_DISALLOWPREMATURE) == 0 || stricmp(attribute, "C3") == 0) - ci->disallow_premature = atoi(value); - else if (stricmp(attribute, INI_UPDATABLECURSORS) == 0 || stricmp(attribute, "C4") == 0) - ci->allow_keyset = atoi(value); - else if (stricmp(attribute, INI_LFCONVERSION) == 0) - ci->lf_conversion = atoi(value); - else if (stricmp(attribute, INI_TRUEISMINUS1) == 0) - ci->true_is_minus1 = atoi(value); - else if (stricmp(attribute, INI_INT8AS) == 0) - ci->int8_as = atoi(value); - else if (stricmp(attribute, "CX") == 0) - unfoldCXAttribute(ci, value); - - mylog("copyAttributes: DSN='%s',server='%s',dbase='%s',user='%s',passwd='%s',port='%s',onlyread='%s',protocol='%s',conn_settings='%s',disallow_premature=%d)\n", ci->dsn, ci->server, ci->database, ci->username, ci->password, ci->port, ci->onlyread, ci->protocol, ci->conn_settings, ci->disallow_premature); -} - -void -copyCommonAttributes(ConnInfo *ci, const char *attribute, const char *value) -{ - if (stricmp(attribute, INI_FETCH) == 0 || stricmp(attribute, "A7") == 0) - ci->drivers.fetch_max = atoi(value); - else if (stricmp(attribute, INI_SOCKET) == 0 || stricmp(attribute, "A8") == 0) - ci->drivers.socket_buffersize = atoi(value); - else if (stricmp(attribute, INI_DEBUG) == 0 || stricmp(attribute, "B2") == 0) - ci->drivers.debug = atoi(value); - else if (stricmp(attribute, INI_COMMLOG) == 0 || stricmp(attribute, "B3") == 0) - ci->drivers.commlog = atoi(value); - else if (stricmp(attribute, INI_OPTIMIZER) == 0 || stricmp(attribute, "B4") == 0) - ci->drivers.disable_optimizer = atoi(value); - else if (stricmp(attribute, INI_KSQO) == 0 || stricmp(attribute, "B5") == 0) - ci->drivers.ksqo = atoi(value); - - /* - * else if (stricmp(attribute, INI_UNIQUEINDEX) == 0 || - * stricmp(attribute, "UIX") == 0) ci->drivers.unique_index = - * atoi(value); - */ - else if (stricmp(attribute, INI_UNKNOWNSIZES) == 0 || stricmp(attribute, "A9") == 0) - ci->drivers.unknown_sizes = atoi(value); - else if (stricmp(attribute, INI_LIE) == 0) - ci->drivers.lie = atoi(value); - else if (stricmp(attribute, INI_PARSE) == 0 || stricmp(attribute, "C0") == 0) - ci->drivers.parse = atoi(value); - else if (stricmp(attribute, INI_CANCELASFREESTMT) == 0 || stricmp(attribute, "C1") == 0) - ci->drivers.cancel_as_freestmt = atoi(value); - else if (stricmp(attribute, INI_USEDECLAREFETCH) == 0 || stricmp(attribute, "B6") == 0) - ci->drivers.use_declarefetch = atoi(value); - else if (stricmp(attribute, INI_MAXVARCHARSIZE) == 0 || stricmp(attribute, "B0") == 0) - ci->drivers.max_varchar_size = atoi(value); - else if (stricmp(attribute, INI_MAXLONGVARCHARSIZE) == 0 || stricmp(attribute, "B1") == 0) - ci->drivers.max_longvarchar_size = atoi(value); - else if (stricmp(attribute, INI_TEXTASLONGVARCHAR) == 0 || stricmp(attribute, "B7") == 0) - ci->drivers.text_as_longvarchar = atoi(value); - else if (stricmp(attribute, INI_UNKNOWNSASLONGVARCHAR) == 0 || stricmp(attribute, "B8") == 0) - ci->drivers.unknowns_as_longvarchar = atoi(value); - else if (stricmp(attribute, INI_BOOLSASCHAR) == 0 || stricmp(attribute, "B9") == 0) - ci->drivers.bools_as_char = atoi(value); - else if (stricmp(attribute, INI_EXTRASYSTABLEPREFIXES) == 0 || stricmp(attribute, "C2") == 0) - strcpy(ci->drivers.extra_systable_prefixes, value); - mylog("CopyCommonAttributes: A7=%d;A8=%d;A9=%d;B0=%d;B1=%d;B2=%d;B3=%d;B4=%d;B5=%d;B6=%d;B7=%d;B8=%d;B9=%d;C0=%d;C1=%d;C2=%s", - ci->drivers.fetch_max, - ci->drivers.socket_buffersize, - ci->drivers.unknown_sizes, - ci->drivers.max_varchar_size, - ci->drivers.max_longvarchar_size, - ci->drivers.debug, - ci->drivers.commlog, - ci->drivers.disable_optimizer, - ci->drivers.ksqo, - ci->drivers.use_declarefetch, - ci->drivers.text_as_longvarchar, - ci->drivers.unknowns_as_longvarchar, - ci->drivers.bools_as_char, - ci->drivers.parse, - ci->drivers.cancel_as_freestmt, - ci->drivers.extra_systable_prefixes); -} - - -void -getDSNdefaults(ConnInfo *ci) -{ - if (ci->port[0] == '\0') - strcpy(ci->port, DEFAULT_PORT); - - if (ci->onlyread[0] == '\0') - sprintf(ci->onlyread, "%d", globals.onlyread); - - if (ci->protocol[0] == '\0') - strcpy(ci->protocol, globals.protocol); - - if (ci->fake_oid_index[0] == '\0') - sprintf(ci->fake_oid_index, "%d", DEFAULT_FAKEOIDINDEX); - - if (ci->show_oid_column[0] == '\0') - sprintf(ci->show_oid_column, "%d", DEFAULT_SHOWOIDCOLUMN); - - if (ci->show_system_tables[0] == '\0') - sprintf(ci->show_system_tables, "%d", DEFAULT_SHOWSYSTEMTABLES); - - if (ci->row_versioning[0] == '\0') - sprintf(ci->row_versioning, "%d", DEFAULT_ROWVERSIONING); - - if (ci->disallow_premature < 0) - ci->disallow_premature = DEFAULT_DISALLOWPREMATURE; - if (ci->allow_keyset < 0) - ci->allow_keyset = DEFAULT_UPDATABLECURSORS; - if (ci->lf_conversion < 0) - ci->lf_conversion = DEFAULT_LFCONVERSION; - if (ci->true_is_minus1 < 0) - ci->true_is_minus1 = DEFAULT_TRUEISMINUS1; - if (ci->int8_as < -100) - ci->int8_as = DEFAULT_INT8AS; -} - - -void -getDSNinfo(ConnInfo *ci, char overwrite) -{ - char *DSN = ci->dsn; - char encoded_conn_settings[LARGE_REGISTRY_LEN], - temp[SMALL_REGISTRY_LEN]; - -/* - * 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[0] == '\0') - { - if (ci->driver[0] != '\0') - return; - else - strcpy(DSN, INI_DSN); - } - - /* brute-force chop off trailing blanks... */ - while (*(DSN + strlen(DSN) - 1) == ' ') - *(DSN + strlen(DSN) - 1) = '\0'; - - /* Proceed with getting info for the given DSN. */ - - if (ci->desc[0] == '\0' || overwrite) - SQLGetPrivateProfileString(DSN, INI_KDESC, "", ci->desc, sizeof(ci->desc), ODBC_INI); - - if (ci->server[0] == '\0' || overwrite) - SQLGetPrivateProfileString(DSN, INI_SERVER, "", ci->server, sizeof(ci->server), ODBC_INI); - - if (ci->database[0] == '\0' || overwrite) - SQLGetPrivateProfileString(DSN, INI_DATABASE, "", ci->database, sizeof(ci->database), ODBC_INI); - - if (ci->username[0] == '\0' || overwrite) - SQLGetPrivateProfileString(DSN, INI_USER, "", ci->username, sizeof(ci->username), ODBC_INI); - - if (ci->password[0] == '\0' || overwrite) - SQLGetPrivateProfileString(DSN, INI_PASSWORD, "", ci->password, sizeof(ci->password), ODBC_INI); - - if (ci->port[0] == '\0' || overwrite) - SQLGetPrivateProfileString(DSN, INI_PORT, "", ci->port, sizeof(ci->port), ODBC_INI); - - if (ci->onlyread[0] == '\0' || overwrite) - SQLGetPrivateProfileString(DSN, INI_READONLY, "", ci->onlyread, sizeof(ci->onlyread), ODBC_INI); - - if (ci->show_oid_column[0] == '\0' || overwrite) - SQLGetPrivateProfileString(DSN, INI_SHOWOIDCOLUMN, "", ci->show_oid_column, sizeof(ci->show_oid_column), ODBC_INI); - - if (ci->fake_oid_index[0] == '\0' || overwrite) - SQLGetPrivateProfileString(DSN, INI_FAKEOIDINDEX, "", ci->fake_oid_index, sizeof(ci->fake_oid_index), ODBC_INI); - - if (ci->row_versioning[0] == '\0' || overwrite) - SQLGetPrivateProfileString(DSN, INI_ROWVERSIONING, "", ci->row_versioning, sizeof(ci->row_versioning), ODBC_INI); - - if (ci->show_system_tables[0] == '\0' || overwrite) - SQLGetPrivateProfileString(DSN, INI_SHOWSYSTEMTABLES, "", ci->show_system_tables, sizeof(ci->show_system_tables), ODBC_INI); - - if (ci->protocol[0] == '\0' || overwrite) - SQLGetPrivateProfileString(DSN, INI_PROTOCOL, "", ci->protocol, sizeof(ci->protocol), ODBC_INI); - - if (ci->conn_settings[0] == '\0' || overwrite) - { - SQLGetPrivateProfileString(DSN, INI_CONNSETTINGS, "", encoded_conn_settings, sizeof(encoded_conn_settings), ODBC_INI); - decode(encoded_conn_settings, ci->conn_settings); - } - - if (ci->translation_dll[0] == '\0' || overwrite) - SQLGetPrivateProfileString(DSN, INI_TRANSLATIONDLL, "", ci->translation_dll, sizeof(ci->translation_dll), ODBC_INI); - - if (ci->translation_option[0] == '\0' || overwrite) - SQLGetPrivateProfileString(DSN, INI_TRANSLATIONOPTION, "", ci->translation_option, sizeof(ci->translation_option), ODBC_INI); - - if (ci->disallow_premature < 0 || overwrite) - { - SQLGetPrivateProfileString(DSN, INI_DISALLOWPREMATURE, "", temp, sizeof(temp), ODBC_INI); - if (temp[0]) - ci->disallow_premature = atoi(temp); - } - - if (ci->allow_keyset < 0 || overwrite) - { - SQLGetPrivateProfileString(DSN, INI_UPDATABLECURSORS, "", temp, sizeof(temp), ODBC_INI); - if (temp[0]) - ci->allow_keyset = atoi(temp); - } - - if (ci->lf_conversion < 0 || overwrite) - { - SQLGetPrivateProfileString(DSN, INI_LFCONVERSION, "", temp, sizeof(temp), ODBC_INI); - if (temp[0]) - ci->lf_conversion = atoi(temp); - } - - if (ci->true_is_minus1 < 0 || overwrite) - { - SQLGetPrivateProfileString(DSN, INI_TRUEISMINUS1, "", temp, sizeof(temp), ODBC_INI); - if (temp[0]) - ci->true_is_minus1 = atoi(temp); - } - - if (ci->int8_as < -100 || overwrite) - { - SQLGetPrivateProfileString(DSN, INI_INT8AS, "", temp, sizeof(temp), ODBC_INI); - if (temp[0]) - ci->int8_as = atoi(temp); - } - - /* Allow override of odbcinst.ini parameters here */ - getCommonDefaults(DSN, ODBC_INI, ci); - - qlog("DSN info: DSN='%s',server='%s',port='%s',dbase='%s',user='%s',passwd='%s'\n", - DSN, - ci->server, - ci->port, - ci->database, - ci->username, - ci->password); - qlog(" onlyread='%s',protocol='%s',showoid='%s',fakeoidindex='%s',showsystable='%s'\n", - ci->onlyread, - ci->protocol, - ci->show_oid_column, - ci->fake_oid_index, - ci->show_system_tables); - -#ifdef MULTIBYTE - check_client_encoding(ci->conn_settings); - qlog(" conn_settings='%s',conn_encoding='%s'\n", - ci->conn_settings, - check_client_encoding(ci->conn_settings)); -#else - qlog(" conn_settings='%s'\n", - ci->conn_settings); -#endif - - qlog(" translation_dll='%s',translation_option='%s'\n", - ci->translation_dll, - ci->translation_option); -} - -/* - * This function writes any global parameters (that can be manipulated) - * to the ODBCINST.INI portion of the registry - */ -void -writeDriverCommoninfo(const ConnInfo *ci) -{ - const char *sectionName; - const char *fileName; - const GLOBAL_VALUES *comval; - char tmp[128]; - - if (ci) - if (ci->dsn && ci->dsn[0]) - { - mylog("DSN=%s updating\n", ci->dsn); - comval = &(ci->drivers); - sectionName = ci->dsn; - fileName = ODBC_INI; - } - else - { - mylog("ci but dsn==NULL\n"); - return; - } - else - { - mylog("drivers updating\n"); - comval = &globals; - sectionName = DBMS_NAME; - fileName = ODBCINST_INI; - } - sprintf(tmp, "%d", comval->fetch_max); - SQLWritePrivateProfileString(sectionName, - INI_FETCH, tmp, fileName); - - sprintf(tmp, "%d", comval->commlog); - SQLWritePrivateProfileString(sectionName, - INI_COMMLOG, tmp, fileName); - - sprintf(tmp, "%d", comval->debug); - SQLWritePrivateProfileString(sectionName, - INI_DEBUG, tmp, fileName); - - sprintf(tmp, "%d", comval->disable_optimizer); - SQLWritePrivateProfileString(sectionName, - INI_OPTIMIZER, tmp, fileName); - - sprintf(tmp, "%d", comval->ksqo); - SQLWritePrivateProfileString(sectionName, - INI_KSQO, tmp, fileName); - - sprintf(tmp, "%d", comval->unique_index); - SQLWritePrivateProfileString(sectionName, INI_UNIQUEINDEX, tmp, fileName); - /* - * Never update the onlyread from this module. - */ - if (!ci) - { - sprintf(tmp, "%d", comval->onlyread); - SQLWritePrivateProfileString(sectionName, INI_READONLY, tmp, - fileName); - } - - sprintf(tmp, "%d", comval->use_declarefetch); - SQLWritePrivateProfileString(sectionName, - INI_USEDECLAREFETCH, tmp, fileName); - - sprintf(tmp, "%d", comval->unknown_sizes); - SQLWritePrivateProfileString(sectionName, - INI_UNKNOWNSIZES, tmp, fileName); - - sprintf(tmp, "%d", comval->text_as_longvarchar); - SQLWritePrivateProfileString(sectionName, - INI_TEXTASLONGVARCHAR, tmp, fileName); - - sprintf(tmp, "%d", comval->unknowns_as_longvarchar); - SQLWritePrivateProfileString(sectionName, - INI_UNKNOWNSASLONGVARCHAR, tmp, fileName); - - sprintf(tmp, "%d", comval->bools_as_char); - SQLWritePrivateProfileString(sectionName, - INI_BOOLSASCHAR, tmp, fileName); - - sprintf(tmp, "%d", comval->parse); - SQLWritePrivateProfileString(sectionName, - INI_PARSE, tmp, fileName); - - sprintf(tmp, "%d", comval->cancel_as_freestmt); - SQLWritePrivateProfileString(sectionName, - INI_CANCELASFREESTMT, tmp, fileName); - - sprintf(tmp, "%d", comval->max_varchar_size); - SQLWritePrivateProfileString(sectionName, - INI_MAXVARCHARSIZE, tmp, fileName); - - sprintf(tmp, "%d", comval->max_longvarchar_size); - SQLWritePrivateProfileString(sectionName, - INI_MAXLONGVARCHARSIZE, tmp, fileName); - - SQLWritePrivateProfileString(sectionName, - INI_EXTRASYSTABLEPREFIXES, comval->extra_systable_prefixes, fileName); - - /* - * Never update the conn_setting from this module - * SQLWritePrivateProfileString(sectionName, INI_CONNSETTINGS, - * comval->conn_settings, fileName); - */ -} - -/* This is for datasource based options only */ -void -writeDSNinfo(const ConnInfo *ci) -{ - const char *DSN = ci->dsn; - char encoded_conn_settings[LARGE_REGISTRY_LEN], - temp[SMALL_REGISTRY_LEN]; - - encode(ci->conn_settings, encoded_conn_settings); - - SQLWritePrivateProfileString(DSN, - INI_KDESC, - ci->desc, - ODBC_INI); - - SQLWritePrivateProfileString(DSN, - INI_DATABASE, - ci->database, - ODBC_INI); - - SQLWritePrivateProfileString(DSN, - INI_SERVER, - ci->server, - ODBC_INI); - - SQLWritePrivateProfileString(DSN, - INI_PORT, - ci->port, - ODBC_INI); - - SQLWritePrivateProfileString(DSN, - INI_USER, - ci->username, - ODBC_INI); - - SQLWritePrivateProfileString(DSN, - INI_PASSWORD, - ci->password, - ODBC_INI); - - SQLWritePrivateProfileString(DSN, - INI_READONLY, - ci->onlyread, - ODBC_INI); - - SQLWritePrivateProfileString(DSN, - INI_SHOWOIDCOLUMN, - ci->show_oid_column, - ODBC_INI); - - SQLWritePrivateProfileString(DSN, - INI_FAKEOIDINDEX, - ci->fake_oid_index, - ODBC_INI); - - SQLWritePrivateProfileString(DSN, - INI_ROWVERSIONING, - ci->row_versioning, - ODBC_INI); - - SQLWritePrivateProfileString(DSN, - INI_SHOWSYSTEMTABLES, - ci->show_system_tables, - ODBC_INI); - - SQLWritePrivateProfileString(DSN, - INI_PROTOCOL, - ci->protocol, - ODBC_INI); - - SQLWritePrivateProfileString(DSN, - INI_CONNSETTINGS, - encoded_conn_settings, - ODBC_INI); - - sprintf(temp, "%d", ci->disallow_premature); - SQLWritePrivateProfileString(DSN, - INI_DISALLOWPREMATURE, - temp, - ODBC_INI); - sprintf(temp, "%d", ci->allow_keyset); - SQLWritePrivateProfileString(DSN, - INI_UPDATABLECURSORS, - temp, - ODBC_INI); - sprintf(temp, "%d", ci->lf_conversion); - SQLWritePrivateProfileString(DSN, - INI_LFCONVERSION, - temp, - ODBC_INI); - sprintf(temp, "%d", ci->true_is_minus1); - SQLWritePrivateProfileString(DSN, - INI_TRUEISMINUS1, - temp, - ODBC_INI); - sprintf(temp, "%d", ci->int8_as); - SQLWritePrivateProfileString(DSN, - INI_INT8AS, - temp, - ODBC_INI); -} - - -/* - * This function reads the ODBCINST.INI portion of - * the registry and gets any driver defaults. - */ -void -getCommonDefaults(const char *section, const char *filename, ConnInfo *ci) -{ - char temp[256]; - GLOBAL_VALUES *comval; - - if (ci) - comval = &(ci->drivers); - else - comval = &globals; - /* Fetch Count is stored in driver section */ - SQLGetPrivateProfileString(section, INI_FETCH, "", - temp, sizeof(temp), filename); - if (temp[0]) - { - comval->fetch_max = atoi(temp); - /* sanity check if using cursors */ - if (comval->fetch_max <= 0) - comval->fetch_max = FETCH_MAX; - } - else if (!ci) - comval->fetch_max = FETCH_MAX; - - /* Socket Buffersize is stored in driver section */ - SQLGetPrivateProfileString(section, INI_SOCKET, "", - temp, sizeof(temp), filename); - if (temp[0]) - comval->socket_buffersize = atoi(temp); - else if (!ci) - comval->socket_buffersize = SOCK_BUFFER_SIZE; - - /* Debug is stored in the driver section */ - SQLGetPrivateProfileString(section, INI_DEBUG, "", - temp, sizeof(temp), filename); - if (temp[0]) - comval->debug = atoi(temp); - else if (!ci) - comval->debug = DEFAULT_DEBUG; - - /* CommLog is stored in the driver section */ - SQLGetPrivateProfileString(section, INI_COMMLOG, "", - temp, sizeof(temp), filename); - if (temp[0]) - comval->commlog = atoi(temp); - else if (!ci) - comval->commlog = DEFAULT_COMMLOG; - - if (!ci) - logs_on_off(0, 0, 0); - /* Optimizer is stored in the driver section only */ - SQLGetPrivateProfileString(section, INI_OPTIMIZER, "", - temp, sizeof(temp), filename); - if (temp[0]) - comval->disable_optimizer = atoi(temp); - else if (!ci) - comval->disable_optimizer = DEFAULT_OPTIMIZER; - - /* KSQO is stored in the driver section only */ - SQLGetPrivateProfileString(section, INI_KSQO, "", - temp, sizeof(temp), filename); - if (temp[0]) - comval->ksqo = atoi(temp); - else if (!ci) - comval->ksqo = DEFAULT_KSQO; - - /* Recognize Unique Index is stored in the driver section only */ - SQLGetPrivateProfileString(section, INI_UNIQUEINDEX, "", - temp, sizeof(temp), filename); - if (temp[0]) - comval->unique_index = atoi(temp); - else if (!ci) - comval->unique_index = DEFAULT_UNIQUEINDEX; - - - /* Unknown Sizes is stored in the driver section only */ - SQLGetPrivateProfileString(section, INI_UNKNOWNSIZES, "", - temp, sizeof(temp), filename); - if (temp[0]) - comval->unknown_sizes = atoi(temp); - else if (!ci) - comval->unknown_sizes = DEFAULT_UNKNOWNSIZES; - - - /* Lie about supported functions? */ - SQLGetPrivateProfileString(section, INI_LIE, "", - temp, sizeof(temp), filename); - if (temp[0]) - comval->lie = atoi(temp); - else if (!ci) - comval->lie = DEFAULT_LIE; - - /* Parse statements */ - SQLGetPrivateProfileString(section, INI_PARSE, "", - temp, sizeof(temp), filename); - if (temp[0]) - comval->parse = atoi(temp); - else if (!ci) - comval->parse = DEFAULT_PARSE; - - /* SQLCancel calls SQLFreeStmt in Driver Manager */ - SQLGetPrivateProfileString(section, INI_CANCELASFREESTMT, "", - temp, sizeof(temp), filename); - if (temp[0]) - comval->cancel_as_freestmt = atoi(temp); - else if (!ci) - comval->cancel_as_freestmt = DEFAULT_CANCELASFREESTMT; - - /* UseDeclareFetch is stored in the driver section only */ - SQLGetPrivateProfileString(section, INI_USEDECLAREFETCH, "", - temp, sizeof(temp), filename); - if (temp[0]) - comval->use_declarefetch = atoi(temp); - else if (!ci) - comval->use_declarefetch = DEFAULT_USEDECLAREFETCH; - - /* Max Varchar Size */ - SQLGetPrivateProfileString(section, INI_MAXVARCHARSIZE, "", - temp, sizeof(temp), filename); - if (temp[0]) - comval->max_varchar_size = atoi(temp); - else if (!ci) - comval->max_varchar_size = MAX_VARCHAR_SIZE; - - /* Max TextField Size */ - SQLGetPrivateProfileString(section, INI_MAXLONGVARCHARSIZE, "", - temp, sizeof(temp), filename); - if (temp[0]) - comval->max_longvarchar_size = atoi(temp); - else if (!ci) - comval->max_longvarchar_size = TEXT_FIELD_SIZE; - - /* Text As LongVarchar */ - SQLGetPrivateProfileString(section, INI_TEXTASLONGVARCHAR, "", - temp, sizeof(temp), filename); - if (temp[0]) - comval->text_as_longvarchar = atoi(temp); - else if (!ci) - comval->text_as_longvarchar = DEFAULT_TEXTASLONGVARCHAR; - - /* Unknowns As LongVarchar */ - SQLGetPrivateProfileString(section, INI_UNKNOWNSASLONGVARCHAR, "", - temp, sizeof(temp), filename); - if (temp[0]) - comval->unknowns_as_longvarchar = atoi(temp); - else if (!ci) - comval->unknowns_as_longvarchar = DEFAULT_UNKNOWNSASLONGVARCHAR; - - /* Bools As Char */ - SQLGetPrivateProfileString(section, INI_BOOLSASCHAR, "", - temp, sizeof(temp), filename); - if (temp[0]) - comval->bools_as_char = atoi(temp); - else if (!ci) - comval->bools_as_char = DEFAULT_BOOLSASCHAR; - - /* Extra Systable prefixes */ - - /* - * Use @@@ to distinguish between blank extra prefixes and no key - * entry - */ - SQLGetPrivateProfileString(section, INI_EXTRASYSTABLEPREFIXES, "@@@", - temp, sizeof(temp), filename); - if (strcmp(temp, "@@@")) - strcpy(comval->extra_systable_prefixes, temp); - else if (!ci) - strcpy(comval->extra_systable_prefixes, DEFAULT_EXTRASYSTABLEPREFIXES); - - mylog("globals.extra_systable_prefixes = '%s'\n", comval->extra_systable_prefixes); - - - /* Dont allow override of an override! */ - if (!ci) - { - /* - * ConnSettings is stored in the driver section and per datasource - * for override - */ - SQLGetPrivateProfileString(section, INI_CONNSETTINGS, "", - comval->conn_settings, sizeof(comval->conn_settings), filename); - - /* Default state for future DSN's Readonly attribute */ - SQLGetPrivateProfileString(section, INI_READONLY, "", - temp, sizeof(temp), filename); - if (temp[0]) - comval->onlyread = atoi(temp); - else - comval->onlyread = DEFAULT_READONLY; - - /* - * Default state for future DSN's protocol attribute This isn't a - * real driver option YET. This is more intended for - * customization from the install. - */ - SQLGetPrivateProfileString(section, INI_PROTOCOL, "@@@", - temp, sizeof(temp), filename); - if (strcmp(temp, "@@@")) - strcpy(comval->protocol, temp); - else - strcpy(comval->protocol, DEFAULT_PROTOCOL); - } -} diff --git a/src/interfaces/odbc/dlg_specific.h b/src/interfaces/odbc/dlg_specific.h deleted file mode 100644 index 99005d3a338..00000000000 --- a/src/interfaces/odbc/dlg_specific.h +++ /dev/null @@ -1,200 +0,0 @@ -/* File: dlg_specific.h - * - * Description: See "dlg_specific.c" - * - * Comments: See "notice.txt" for copyright and license information. - * - */ - -#ifndef __DLG_SPECIFIC_H__ -#define __DLG_SPECIFIC_H__ - -#include "psqlodbc.h" -#include "connection.h" - -#ifdef WIN32 -#include <windowsx.h> -#include "resource.h" -#endif - -/* Unknown data type sizes */ -#define UNKNOWNS_AS_MAX 0 -#define UNKNOWNS_AS_DONTKNOW 1 -#define UNKNOWNS_AS_LONGEST 2 - -/* ODBC initialization files */ -#ifndef WIN32 -#define ODBC_INI ".odbc.ini" -#define ODBCINST_INI "odbcinst.ini" -#else -#define ODBC_INI "ODBC.INI" -#define ODBCINST_INI "ODBCINST.INI" -#endif - - -#define INI_DSN DBMS_NAME /* Name of default - * Datasource in ini - * file (not used?) */ -#define INI_KDESC "Description" /* Data source - * description */ -#define INI_SERVER "Servername" /* Name of Server - * running the Postgres - * service */ -#define INI_PORT "Port" /* Port on which the - * Postmaster is listening */ -#define INI_DATABASE "Database" /* Database Name */ -#define INI_USER "Username" /* Default User Name */ -#define INI_PASSWORD "Password" /* Default Password */ -#define INI_DEBUG "Debug" /* Debug flag */ -#define INI_FETCH "Fetch" /* Fetch Max Count */ -#define INI_SOCKET "Socket" /* Socket buffer size */ -#define INI_READONLY "ReadOnly" /* Database is read only */ -#define INI_COMMLOG "CommLog" /* Communication to - * backend logging */ -#define INI_PROTOCOL "Protocol" /* What protocol (6.2) */ -#define INI_OPTIMIZER "Optimizer" /* Use backend genetic - * optimizer */ -#define INI_KSQO "Ksqo" /* Keyset query - * optimization */ -#define INI_CONNSETTINGS "ConnSettings" /* Anything to send to - * backend on successful - * connection */ -#define INI_UNIQUEINDEX "UniqueIndex" /* Recognize unique - * indexes */ -#define INI_UNKNOWNSIZES "UnknownSizes" /* How to handle unknown - * result set sizes */ - -#define INI_CANCELASFREESTMT "CancelAsFreeStmt" - -#define INI_USEDECLAREFETCH "UseDeclareFetch" /* Use Declare/Fetch - * cursors */ - -/* More ini stuff */ -#define INI_TEXTASLONGVARCHAR "TextAsLongVarchar" -#define INI_UNKNOWNSASLONGVARCHAR "UnknownsAsLongVarchar" -#define INI_BOOLSASCHAR "BoolsAsChar" -#define INI_MAXVARCHARSIZE "MaxVarcharSize" -#define INI_MAXLONGVARCHARSIZE "MaxLongVarcharSize" - -#define INI_FAKEOIDINDEX "FakeOidIndex" -#define INI_SHOWOIDCOLUMN "ShowOidColumn" -#define INI_ROWVERSIONING "RowVersioning" -#define INI_SHOWSYSTEMTABLES "ShowSystemTables" -#define INI_LIE "Lie" -#define INI_PARSE "Parse" -#define INI_EXTRASYSTABLEPREFIXES "ExtraSysTablePrefixes" - -#define INI_TRANSLATIONNAME "TranslationName" -#define INI_TRANSLATIONDLL "TranslationDLL" -#define INI_TRANSLATIONOPTION "TranslationOption" -#define INI_DISALLOWPREMATURE "DisallowPremature" -#define INI_UPDATABLECURSORS "UpdatableCursors" -#define INI_LFCONVERSION "LFConversion" -#define INI_TRUEISMINUS1 "TrueIsMinus1" -#define INI_INT8AS "BI" -/* Bit representaion for abbreviated connection strings */ -#define BIT_LFCONVERSION (1L) -#define BIT_UPDATABLECURSORS (1L<<1) -#define BIT_DISALLOWPREMATURE (1L<<2) -#define BIT_UNIQUEINDEX (1L<<3) -#define BIT_PROTOCOL_63 (1L<<4) -#define BIT_PROTOCOL_64 (1L<<5) -#define BIT_UNKNOWN_DONTKNOW (1L<<6) -#define BIT_UNKNOWN_ASMAX (1L<<7) -#define BIT_OPTIMIZER (1L<<8) -#define BIT_KSQO (1L<<9) -#define BIT_COMMLOG (1L<<10) -#define BIT_DEBUG (1L<<11) -#define BIT_PARSE (1L<<12) -#define BIT_CANCELASFREESTMT (1L<<13) -#define BIT_USEDECLAREFETCH (1L<<14) -#define BIT_READONLY (1L<<15) -#define BIT_TEXTASLONGVARCHAR (1L<<16) -#define BIT_UNKNOWNSASLONGVARCHAR (1L<<17) -#define BIT_BOOLSASCHAR (1L<<18) -#define BIT_ROWVERSIONING (1L<<19) -#define BIT_SHOWSYSTEMTABLES (1L<<20) -#define BIT_SHOWOIDCOLUMN (1L<<21) -#define BIT_FAKEOIDINDEX (1L<<22) -#define BIT_TRUEISMINUS1 (1L<<23) - -#define EFFECTIVE_BIT_COUNT 24 - - -/* Connection Defaults */ -#define DEFAULT_PORT "5432" -#define DEFAULT_READONLY 0 -#define DEFAULT_PROTOCOL "6.4" /* the latest protocol is - * the default */ -#define DEFAULT_USEDECLAREFETCH 0 -#define DEFAULT_TEXTASLONGVARCHAR 1 -#define DEFAULT_UNKNOWNSASLONGVARCHAR 0 -#define DEFAULT_BOOLSASCHAR 1 -#define DEFAULT_OPTIMIZER 1 /* disable */ -#define DEFAULT_KSQO 1 /* on */ -#define DEFAULT_UNIQUEINDEX 1 /* dont recognize */ -#define DEFAULT_COMMLOG 0 /* dont log */ -#define DEFAULT_DEBUG 0 -#define DEFAULT_UNKNOWNSIZES UNKNOWNS_AS_MAX - - -#define DEFAULT_FAKEOIDINDEX 0 -#define DEFAULT_SHOWOIDCOLUMN 0 -#define DEFAULT_ROWVERSIONING 0 -#define DEFAULT_SHOWSYSTEMTABLES 0 /* dont show system tables */ -#define DEFAULT_LIE 0 -#define DEFAULT_PARSE 0 - -#define DEFAULT_CANCELASFREESTMT 0 - -#define DEFAULT_EXTRASYSTABLEPREFIXES "dd_;" - -#define DEFAULT_DISALLOWPREMATURE 0 -#define DEFAULT_TRUEISMINUS1 0 -#ifdef DRIVER_CURSOR_IMPLEMENT -#define DEFAULT_UPDATABLECURSORS 1 -#else -#define DEFAULT_UPDATABLECURSORS 0 -#endif /* DRIVER_CURSOR_IMPLEMENT */ -#ifdef WIN32 -#define DEFAULT_LFCONVERSION 1 -#else -#define DEFAULT_LFCONVERSION 0 -#endif /* WIN32 */ -#define DEFAULT_INT8AS 0 - -/* prototypes */ -void getCommonDefaults(const char *section, const char *filename, ConnInfo *ci); - -#ifdef WIN32 -void SetDlgStuff(HWND hdlg, const ConnInfo *ci); -void GetDlgStuff(HWND hdlg, ConnInfo *ci); - -int CALLBACK driver_optionsProc(HWND hdlg, - UINT wMsg, - WPARAM wParam, - LPARAM lParam); -int CALLBACK global_optionsProc(HWND hdlg, - UINT wMsg, - WPARAM wParam, - LPARAM lParam); -int CALLBACK ds_options1Proc(HWND hdlg, - UINT wMsg, - WPARAM wParam, - LPARAM lParam); -int CALLBACK ds_options2Proc(HWND hdlg, - UINT wMsg, - WPARAM wParam, - LPARAM lParam); -#endif /* WIN32 */ - -void updateGlobals(void); -void writeDriverCommoninfo(const ConnInfo *ci); -void writeDSNinfo(const ConnInfo *ci); -void getDSNdefaults(ConnInfo *ci); -void getDSNinfo(ConnInfo *ci, char overwrite); -void makeConnectString(char *connect_string, const ConnInfo *ci, UWORD); -void copyAttributes(ConnInfo *ci, const char *attribute, const char *value); -void copyCommonAttributes(ConnInfo *ci, const char *attribute, const char *value); - -#endif diff --git a/src/interfaces/odbc/dlg_wingui.c b/src/interfaces/odbc/dlg_wingui.c deleted file mode 100644 index 88c2e9f4c45..00000000000 --- a/src/interfaces/odbc/dlg_wingui.c +++ /dev/null @@ -1,523 +0,0 @@ -#ifdef WIN32 -/*------- - * Module: dlg_wingui.c - * - * Description: This module contains any specific code for handling - * dialog boxes such as driver/datasource options. Both the - * ConfigDSN() and the SQLDriverConnect() functions use - * functions in this module. If you were to add a new option - * to any dialog box, you would most likely only have to change - * things in here rather than in 2 separate places as before. - * - * Classes: none - * - * API functions: none - * - * Comments: See "notice.txt" for copyright and license information. - *------- - */ -/* Multibyte support Eiji Tokuya 2001-03-15 */ - -#include "dlg_specific.h" - -#include "convert.h" - -#ifdef MULTIBYTE -#include "multibyte.h" -#endif -#include "pgapifunc.h" - -#ifndef BOOL -#define BOOL int -#endif -#ifndef FALSE -#define FALSE (BOOL)0 -#endif -#ifndef TRUE -#define TRUE (BOOL)1 -#endif - -extern GLOBAL_VALUES globals; - -extern HINSTANCE NEAR s_hModule; -static int driver_optionsDraw(HWND, const ConnInfo *, int src, BOOL enable); -static int driver_options_update(HWND hdlg, ConnInfo *ci, BOOL); - -void -SetDlgStuff(HWND hdlg, const ConnInfo *ci) -{ - /* - * 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_DESC, ci->desc); - } - - SetDlgItemText(hdlg, IDC_DATABASE, ci->database); - SetDlgItemText(hdlg, IDC_SERVER, ci->server); - SetDlgItemText(hdlg, IDC_USER, ci->username); - SetDlgItemText(hdlg, IDC_PASSWORD, ci->password); - SetDlgItemText(hdlg, IDC_PORT, ci->port); -} - - -void -GetDlgStuff(HWND hdlg, ConnInfo *ci) -{ - GetDlgItemText(hdlg, IDC_DESC, ci->desc, sizeof(ci->desc)); - - GetDlgItemText(hdlg, IDC_DATABASE, ci->database, sizeof(ci->database)); - GetDlgItemText(hdlg, IDC_SERVER, ci->server, sizeof(ci->server)); - GetDlgItemText(hdlg, IDC_USER, ci->username, sizeof(ci->username)); - GetDlgItemText(hdlg, IDC_PASSWORD, ci->password, sizeof(ci->password)); - GetDlgItemText(hdlg, IDC_PORT, ci->port, sizeof(ci->port)); -} - - -static int -driver_optionsDraw(HWND hdlg, const ConnInfo *ci, int src, BOOL enable) -{ - const GLOBAL_VALUES *comval; - static BOOL defset = FALSE; - static GLOBAL_VALUES defval; - - switch (src) - { - case 0: /* driver common */ - comval = &globals; - break; - case 1: /* dsn specific */ - comval = &(ci->drivers); - break; - case 2: /* default */ - if (!defset) - { - defval.commlog = DEFAULT_COMMLOG; - defval.disable_optimizer = DEFAULT_OPTIMIZER; - defval.ksqo = DEFAULT_KSQO; - defval.unique_index = DEFAULT_UNIQUEINDEX; - defval.onlyread = DEFAULT_READONLY; - defval.use_declarefetch = DEFAULT_USEDECLAREFETCH; - - defval.parse = DEFAULT_PARSE; - defval.cancel_as_freestmt = DEFAULT_CANCELASFREESTMT; - defval.debug = DEFAULT_DEBUG; - - /* Unknown Sizes */ - defval.unknown_sizes = DEFAULT_UNKNOWNSIZES; - defval.text_as_longvarchar = DEFAULT_TEXTASLONGVARCHAR; - defval.unknowns_as_longvarchar = DEFAULT_UNKNOWNSASLONGVARCHAR; - defval.bools_as_char = DEFAULT_BOOLSASCHAR; - } - defset = TRUE; - comval = &defval; - break; - } - - ShowWindow(GetDlgItem(hdlg, DRV_MSG_LABEL2), enable ? SW_SHOW : SW_HIDE); - CheckDlgButton(hdlg, DRV_COMMLOG, comval->commlog); -#ifndef Q_LOG - EnableWindow(GetDlgItem(hdlg, DRV_COMMLOG), FALSE); -#endif /* Q_LOG */ - CheckDlgButton(hdlg, DRV_OPTIMIZER, comval->disable_optimizer); - CheckDlgButton(hdlg, DRV_KSQO, comval->ksqo); - CheckDlgButton(hdlg, DRV_UNIQUEINDEX, comval->unique_index); - /* EnableWindow(GetDlgItem(hdlg, DRV_UNIQUEINDEX), enable); */ - CheckDlgButton(hdlg, DRV_READONLY, comval->onlyread); - EnableWindow(GetDlgItem(hdlg, DRV_READONLY), enable); - CheckDlgButton(hdlg, DRV_USEDECLAREFETCH, comval->use_declarefetch); - - /* Unknown Sizes clear */ - CheckDlgButton(hdlg, DRV_UNKNOWN_DONTKNOW, 0); - CheckDlgButton(hdlg, DRV_UNKNOWN_LONGEST, 0); - CheckDlgButton(hdlg, DRV_UNKNOWN_MAX, 0); - /* Unknown (Default) Data Type sizes */ - switch (comval->unknown_sizes) - { - case UNKNOWNS_AS_DONTKNOW: - CheckDlgButton(hdlg, DRV_UNKNOWN_DONTKNOW, 1); - break; - case UNKNOWNS_AS_LONGEST: - CheckDlgButton(hdlg, DRV_UNKNOWN_LONGEST, 1); - break; - case UNKNOWNS_AS_MAX: - default: - CheckDlgButton(hdlg, DRV_UNKNOWN_MAX, 1); - break; - } - - CheckDlgButton(hdlg, DRV_TEXT_LONGVARCHAR, comval->text_as_longvarchar); - CheckDlgButton(hdlg, DRV_UNKNOWNS_LONGVARCHAR, comval->unknowns_as_longvarchar); - CheckDlgButton(hdlg, DRV_BOOLS_CHAR, comval->bools_as_char); - CheckDlgButton(hdlg, DRV_PARSE, comval->parse); - CheckDlgButton(hdlg, DRV_CANCELASFREESTMT, comval->cancel_as_freestmt); - CheckDlgButton(hdlg, DRV_DEBUG, comval->debug); -#ifndef MY_LOG - EnableWindow(GetDlgItem(hdlg, DRV_DEBUG), FALSE); -#endif /* MY_LOG */ - SetDlgItemInt(hdlg, DRV_CACHE_SIZE, comval->fetch_max, FALSE); - SetDlgItemInt(hdlg, DRV_VARCHAR_SIZE, comval->max_varchar_size, FALSE); - SetDlgItemInt(hdlg, DRV_LONGVARCHAR_SIZE, comval->max_longvarchar_size, TRUE); - SetDlgItemText(hdlg, DRV_EXTRASYSTABLEPREFIXES, comval->extra_systable_prefixes); - - /* Driver Connection Settings */ - SetDlgItemText(hdlg, DRV_CONNSETTINGS, comval->conn_settings); - EnableWindow(GetDlgItem(hdlg, DRV_CONNSETTINGS), enable); - ShowWindow(GetDlgItem(hdlg, IDPREVPAGE), enable ? SW_HIDE : SW_SHOW); - ShowWindow(GetDlgItem(hdlg, IDNEXTPAGE), enable ? SW_HIDE : SW_SHOW); - return 0; -} -static int -driver_options_update(HWND hdlg, ConnInfo *ci, BOOL updateProfile) -{ - GLOBAL_VALUES *comval; - - if (ci) - comval = &(ci->drivers); - else - comval = &globals; - comval->commlog = IsDlgButtonChecked(hdlg, DRV_COMMLOG); - comval->disable_optimizer = IsDlgButtonChecked(hdlg, DRV_OPTIMIZER); - comval->ksqo = IsDlgButtonChecked(hdlg, DRV_KSQO); - comval->unique_index = IsDlgButtonChecked(hdlg, DRV_UNIQUEINDEX); - if (!ci) - { - comval->onlyread = IsDlgButtonChecked(hdlg, DRV_READONLY); - } - comval->use_declarefetch = IsDlgButtonChecked(hdlg, DRV_USEDECLAREFETCH); - - /* Unknown (Default) Data Type sizes */ - if (IsDlgButtonChecked(hdlg, DRV_UNKNOWN_MAX)) - comval->unknown_sizes = UNKNOWNS_AS_MAX; - else if (IsDlgButtonChecked(hdlg, DRV_UNKNOWN_DONTKNOW)) - comval->unknown_sizes = UNKNOWNS_AS_DONTKNOW; - else if (IsDlgButtonChecked(hdlg, DRV_UNKNOWN_LONGEST)) - comval->unknown_sizes = UNKNOWNS_AS_LONGEST; - else - comval->unknown_sizes = UNKNOWNS_AS_MAX; - - comval->text_as_longvarchar = IsDlgButtonChecked(hdlg, DRV_TEXT_LONGVARCHAR); - comval->unknowns_as_longvarchar = IsDlgButtonChecked(hdlg, DRV_UNKNOWNS_LONGVARCHAR); - comval->bools_as_char = IsDlgButtonChecked(hdlg, DRV_BOOLS_CHAR); - - comval->parse = IsDlgButtonChecked(hdlg, DRV_PARSE); - - comval->cancel_as_freestmt = IsDlgButtonChecked(hdlg, DRV_CANCELASFREESTMT); - comval->debug = IsDlgButtonChecked(hdlg, DRV_DEBUG); - - comval->fetch_max = GetDlgItemInt(hdlg, DRV_CACHE_SIZE, NULL, FALSE); - comval->max_varchar_size = GetDlgItemInt(hdlg, DRV_VARCHAR_SIZE, NULL, FALSE); - comval->max_longvarchar_size = GetDlgItemInt(hdlg, DRV_LONGVARCHAR_SIZE, NULL, TRUE); /* allows for - * SQL_NO_TOTAL */ - - GetDlgItemText(hdlg, DRV_EXTRASYSTABLEPREFIXES, comval->extra_systable_prefixes, sizeof(comval->extra_systable_prefixes)); - - /* Driver Connection Settings */ - if (!ci) - GetDlgItemText(hdlg, DRV_CONNSETTINGS, comval->conn_settings, sizeof(comval->conn_settings)); - - if (updateProfile) - writeDriverCommoninfo(ci); - - /* fall through */ - return 0; -} - -int CALLBACK -driver_optionsProc(HWND hdlg, - UINT wMsg, - WPARAM wParam, - LPARAM lParam) -{ - ConnInfo *ci; - - switch (wMsg) - { - case WM_INITDIALOG: - SetWindowLong(hdlg, DWL_USER, lParam); /* save for OK etc */ - ci = (ConnInfo *) lParam; - SetWindowText(hdlg, "Advanced Options (Default)"); - SetWindowText(GetDlgItem(hdlg, IDOK), "Save"); - ShowWindow(GetDlgItem(hdlg, IDAPPLY), SW_HIDE); - driver_optionsDraw(hdlg, ci, 0, TRUE); - break; - - case WM_COMMAND: - switch (GET_WM_COMMAND_ID(wParam, lParam)) - { - case IDOK: - ci = (ConnInfo *) GetWindowLong(hdlg, DWL_USER); - driver_options_update(hdlg, NULL, - ci && ci->dsn && ci->dsn[0]); - - case IDCANCEL: - EndDialog(hdlg, GET_WM_COMMAND_ID(wParam, lParam) == IDOK); - return TRUE; - - case IDDEFAULTS: - driver_optionsDraw(hdlg, NULL, 2, TRUE); - break; - } - } - - return FALSE; -} - -int CALLBACK -global_optionsProc(HWND hdlg, - UINT wMsg, - WPARAM wParam, - LPARAM lParam) -{ - - switch (wMsg) - { - case WM_INITDIALOG: - CheckDlgButton(hdlg, DRV_COMMLOG, globals.commlog); -#ifndef Q_LOG - EnableWindow(GetDlgItem(hdlg, DRV_COMMLOG), FALSE); -#endif /* Q_LOG */ - CheckDlgButton(hdlg, DRV_DEBUG, globals.debug); -#ifndef MY_LOG - EnableWindow(GetDlgItem(hdlg, DRV_DEBUG), FALSE); -#endif /* MY_LOG */ - break; - - case WM_COMMAND: - switch (GET_WM_COMMAND_ID(wParam, lParam)) - { - case IDOK: - globals.commlog = IsDlgButtonChecked(hdlg, DRV_COMMLOG); - globals.debug = IsDlgButtonChecked(hdlg, DRV_DEBUG); - driver_options_update(hdlg, NULL, TRUE); - - case IDCANCEL: - EndDialog(hdlg, GET_WM_COMMAND_ID(wParam, lParam) == IDOK); - return TRUE; - } - } - - return FALSE; -} - -int CALLBACK -ds_options1Proc(HWND hdlg, - UINT wMsg, - WPARAM wParam, - LPARAM lParam) -{ - ConnInfo *ci; - - switch (wMsg) - { - case WM_INITDIALOG: - SetWindowLong(hdlg, DWL_USER, lParam); /* save for OK etc */ - ci = (ConnInfo *) lParam; - if (ci && ci->dsn && ci->dsn[0]) - SetWindowText(hdlg, "Advanced Options (DSN 1/2)"); - else - { - SetWindowText(hdlg, "Advanced Options (Connection 1/2)"); - ShowWindow(GetDlgItem(hdlg, IDAPPLY), SW_HIDE); - } - driver_optionsDraw(hdlg, ci, 1, FALSE); - break; - - case WM_COMMAND: - ci = (ConnInfo *) GetWindowLong(hdlg, DWL_USER); - switch (GET_WM_COMMAND_ID(wParam, lParam)) - { - case IDOK: - driver_options_update(hdlg, ci, FALSE); - - case IDCANCEL: - EndDialog(hdlg, GET_WM_COMMAND_ID(wParam, lParam) == IDOK); - return TRUE; - - case IDAPPLY: - driver_options_update(hdlg, ci, FALSE); - SendMessage(GetWindow(hdlg, GW_OWNER), WM_COMMAND, wParam, lParam); - break; - - case IDDEFAULTS: - driver_optionsDraw(hdlg, ci, 0, FALSE); - break; - - case IDNEXTPAGE: - driver_options_update(hdlg, ci, FALSE); - - EndDialog(hdlg, FALSE); - DialogBoxParam(s_hModule, - MAKEINTRESOURCE(DLG_OPTIONS_DS), - hdlg, ds_options2Proc, (LPARAM) -ci); - break; - } - } - - return FALSE; -} - - -int CALLBACK -ds_options2Proc(HWND hdlg, - UINT wMsg, - WPARAM wParam, - LPARAM lParam) -{ - ConnInfo *ci; - char buf[128]; - DWORD cmd; - - switch (wMsg) - { - case WM_INITDIALOG: - ci = (ConnInfo *) lParam; - SetWindowLong(hdlg, DWL_USER, lParam); /* save for OK */ - - /* Change window caption */ - if (ci->driver[0]) - { - SetWindowText(hdlg, "Advanced Options (Connection 2/2)"); - ShowWindow(GetDlgItem(hdlg, IDAPPLY), SW_HIDE); } - else - { - sprintf(buf, "Advanced Options (%s) 2/2", ci->dsn); - SetWindowText(hdlg, buf); - } - - /* Readonly */ - CheckDlgButton(hdlg, DS_READONLY, atoi(ci->onlyread)); - - /* 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); - - /* Int8 As */ - switch (ci->int8_as) - { - case SQL_BIGINT: - CheckDlgButton(hdlg, DS_INT8_AS_BIGINT, 1); - break; - case SQL_NUMERIC: - CheckDlgButton(hdlg, DS_INT8_AS_NUMERIC, 1); - break; - case SQL_VARCHAR: - CheckDlgButton(hdlg, DS_INT8_AS_VARCHAR, 1); - break; - case SQL_DOUBLE: - CheckDlgButton(hdlg, DS_INT8_AS_DOUBLE, 1); - break; - case SQL_INTEGER: - CheckDlgButton(hdlg, DS_INT8_AS_INT4, 1); - break; - default: - CheckDlgButton(hdlg, DS_INT8_AS_DEFAULT, 1); - } - - CheckDlgButton(hdlg, DS_SHOWOIDCOLUMN, atoi(ci->show_oid_column)); - CheckDlgButton(hdlg, DS_FAKEOIDINDEX, atoi(ci->fake_oid_index)); - CheckDlgButton(hdlg, DS_ROWVERSIONING, atoi(ci->row_versioning)); - CheckDlgButton(hdlg, DS_SHOWSYSTEMTABLES, atoi(ci->show_system_tables)); - CheckDlgButton(hdlg, DS_DISALLOWPREMATURE, ci->disallow_premature); - CheckDlgButton(hdlg, DS_LFCONVERSION, ci->lf_conversion); - CheckDlgButton(hdlg, DS_TRUEISMINUS1, ci->true_is_minus1); - CheckDlgButton(hdlg, DS_UPDATABLECURSORS, ci->allow_keyset); -#ifndef DRIVER_CURSOR_IMPLEMENT - EnableWindow(GetDlgItem(hdlg, DS_UPDATABLECURSORS), FALSE); -#endif /* DRIVER_CURSOR_IMPLEMENT */ - - EnableWindow(GetDlgItem(hdlg, DS_FAKEOIDINDEX), atoi(ci->show_oid_column)); - - /* Datasource Connection Settings */ - SetDlgItemText(hdlg, DS_CONNSETTINGS, ci->conn_settings); - break; - - case WM_COMMAND: - switch (cmd = GET_WM_COMMAND_ID(wParam, lParam)) - { - case DS_SHOWOIDCOLUMN: - mylog("WM_COMMAND: DS_SHOWOIDCOLUMN\n"); - EnableWindow(GetDlgItem(hdlg, DS_FAKEOIDINDEX), IsDlgButtonChecked(hdlg, DS_SHOWOIDCOLUMN)); - return TRUE; - - case IDOK: - case IDAPPLY: - case IDPREVPAGE: - ci = (ConnInfo *) GetWindowLong(hdlg, DWL_USER); - mylog("IDOK: got ci = %u\n", ci); - - /* Readonly */ - sprintf(ci->onlyread, "%d", IsDlgButtonChecked(hdlg, DS_READONLY)); - - /* 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); - - /* Int8 As */ - if (IsDlgButtonChecked(hdlg, DS_INT8_AS_DEFAULT)) - ci->int8_as = 0; - else if (IsDlgButtonChecked(hdlg, DS_INT8_AS_BIGINT)) - ci->int8_as = SQL_BIGINT; - else if (IsDlgButtonChecked(hdlg, DS_INT8_AS_NUMERIC)) - ci->int8_as = SQL_NUMERIC; - else if (IsDlgButtonChecked(hdlg, DS_INT8_AS_DOUBLE)) - ci->int8_as = SQL_DOUBLE; - else if (IsDlgButtonChecked(hdlg, DS_INT8_AS_INT4)) - ci->int8_as = SQL_INTEGER; - else - ci->int8_as = SQL_VARCHAR; - - sprintf(ci->show_system_tables, "%d", IsDlgButtonChecked(hdlg, DS_SHOWSYSTEMTABLES)); - - sprintf(ci->row_versioning, "%d", IsDlgButtonChecked(hdlg, DS_ROWVERSIONING)); - ci->disallow_premature = IsDlgButtonChecked(hdlg, DS_DISALLOWPREMATURE); - ci->lf_conversion = IsDlgButtonChecked(hdlg, DS_LFCONVERSION); - ci->true_is_minus1 = IsDlgButtonChecked(hdlg, DS_TRUEISMINUS1); -#ifdef DRIVER_CURSOR_IMPLEMENT - ci->allow_keyset = IsDlgButtonChecked(hdlg, DS_UPDATABLECURSORS); -#endif /* DRIVER_CURSOR_IMPLEMENT */ - - /* OID Options */ - sprintf(ci->fake_oid_index, "%d", IsDlgButtonChecked(hdlg, DS_FAKEOIDINDEX)); - sprintf(ci->show_oid_column, "%d", IsDlgButtonChecked(hdlg, DS_SHOWOIDCOLUMN)); - - /* Datasource Connection Settings */ - GetDlgItemText(hdlg, DS_CONNSETTINGS, ci->conn_settings, sizeof(ci->conn_settings)); - if (IDAPPLY == cmd) - { - SendMessage(GetWindow(hdlg, GW_OWNER), WM_COMMAND, wParam, lParam); - break; - } - - EndDialog(hdlg, cmd == IDOK); - if (IDOK == cmd) - return TRUE; - DialogBoxParam(s_hModule, - MAKEINTRESOURCE(DLG_OPTIONS_DRV), - hdlg, ds_options1Proc, (LPARAM) ci); - break; - - case IDCANCEL: - EndDialog(hdlg, GET_WM_COMMAND_ID(wParam, lParam) == IDOK); - return TRUE; - } - } - - return FALSE; -} - -#endif /* WIN32 */ diff --git a/src/interfaces/odbc/drvconn.c b/src/interfaces/odbc/drvconn.c deleted file mode 100644 index 6c08376ac4b..00000000000 --- a/src/interfaces/odbc/drvconn.c +++ /dev/null @@ -1,435 +0,0 @@ -/*------- - Module: drvconn.c - * - * Description: This module contains only routines related to - * implementing SQLDriverConnect. - * - * Classes: n/a - * - * API functions: SQLDriverConnect - * - * Comments: See "notice.txt" for copyright and license information. - *------- - */ - -#include "psqlodbc.h" - -#include <stdio.h> -#include <stdlib.h> - -#include "connection.h" - -#ifndef WIN32 -#include <sys/types.h> -#include <sys/socket.h> -#define NEAR -#else -#include <winsock.h> -#endif - -#include <string.h> - -#ifdef WIN32 -#include <windowsx.h> -#include "resource.h" -#endif -#include "pgapifunc.h" - -#ifndef TRUE -#define TRUE (BOOL)1 -#endif -#ifndef FALSE -#define FALSE (BOOL)0 -#endif - -#include "dlg_specific.h" - -/* prototypes */ -void dconn_get_connect_attributes(const UCHAR FAR * connect_string, ConnInfo *ci); -static void dconn_get_common_attributes(const UCHAR FAR * connect_string, ConnInfo *ci); - -#ifdef WIN32 -BOOL FAR PASCAL dconn_FDriverConnectProc(HWND hdlg, UINT wMsg, WPARAM wParam, LPARAM lParam); -RETCODE dconn_DoDialog(HWND hwnd, ConnInfo *ci); - -extern HINSTANCE NEAR s_hModule; /* Saved module handle. */ -#endif - - -RETCODE SQL_API -PGAPI_DriverConnect( - HDBC hdbc, - HWND hwnd, - UCHAR FAR * szConnStrIn, - SWORD cbConnStrIn, - UCHAR FAR * szConnStrOut, - SWORD cbConnStrOutMax, - SWORD FAR * pcbConnStrOut, - UWORD fDriverCompletion) -{ - static char *func = "PGAPI_DriverConnect"; - ConnectionClass *conn = (ConnectionClass *) hdbc; - ConnInfo *ci; - -#ifdef WIN32 - RETCODE dialog_result; -#endif - RETCODE result; - char connStrIn[MAX_CONNECT_STRING]; - char connStrOut[MAX_CONNECT_STRING]; - int retval; - char salt[5]; - char password_required = AUTH_REQ_OK; - int len = 0; - SWORD lenStrout; - - - mylog("%s: entering...\n", func); - - if (!conn) - { - CC_log_error(func, "", NULL); - return SQL_INVALID_HANDLE; - } - - make_string(szConnStrIn, cbConnStrIn, connStrIn); - - mylog("**** PGAPI_DriverConnect: fDriverCompletion=%d, connStrIn='%s'\n", fDriverCompletion, connStrIn); - qlog("conn=%u, PGAPI_DriverConnect( in)='%s', fDriverCompletion=%d\n", conn, connStrIn, fDriverCompletion); - - ci = &(conn->connInfo); - - /* Parse the connect string and fill in conninfo for this hdbc. */ - dconn_get_connect_attributes(connStrIn, ci); - - /* - * If the ConnInfo in the hdbc is missing anything, this function will - * fill them in from the registry (assuming of course there is a DSN - * given -- if not, it does nothing!) - */ - getDSNinfo(ci, CONN_DONT_OVERWRITE); - dconn_get_common_attributes(connStrIn, ci); - logs_on_off(1, ci->drivers.debug, ci->drivers.commlog); - - /* Fill in any default parameters if they are not there. */ - getDSNdefaults(ci); - /* initialize pg_version */ - CC_initialize_pg_version(conn); - salt[0] = '\0'; - -#ifdef WIN32 -dialog: -#endif - ci->focus_password = password_required; - - switch (fDriverCompletion) - { -#ifdef WIN32 - case SQL_DRIVER_PROMPT: - dialog_result = dconn_DoDialog(hwnd, ci); - if (dialog_result != SQL_SUCCESS) - return dialog_result; - break; - - case SQL_DRIVER_COMPLETE_REQUIRED: - - /* Fall through */ - - case SQL_DRIVER_COMPLETE: - - /* Password is not a required parameter. */ - if (ci->username[0] == '\0' || - ci->server[0] == '\0' || - ci->database[0] == '\0' || - ci->port[0] == '\0' || - password_required) - { - dialog_result = dconn_DoDialog(hwnd, ci); - if (dialog_result != SQL_SUCCESS) - return dialog_result; - } - break; -#else - case SQL_DRIVER_PROMPT: - case SQL_DRIVER_COMPLETE: - case SQL_DRIVER_COMPLETE_REQUIRED: -#endif - case SQL_DRIVER_NOPROMPT: - break; - } - - /* - * Password is not a required parameter unless authentication asks for - * it. For now, I think it's better to just let the application ask - * over and over until a password is entered (the user can always hit - * Cancel to get out) - */ - if (ci->username[0] == '\0' || - ci->server[0] == '\0' || - ci->database[0] == '\0' || - ci->port[0] == '\0') - { - /* (password_required && ci->password[0] == '\0')) */ - - return SQL_NO_DATA_FOUND; - } - - /* do the actual connect */ - retval = CC_connect(conn, password_required, salt); - if (retval < 0) - { /* need a password */ - if (fDriverCompletion == SQL_DRIVER_NOPROMPT) - { - CC_log_error(func, "Need password but Driver_NoPrompt", conn); - return SQL_ERROR; /* need a password but not allowed to - * prompt so error */ - } - else - { -#ifdef WIN32 - password_required = -retval; - goto dialog; -#else - return SQL_ERROR; /* until a better solution is found. */ -#endif - } - } - else if (retval == 0) - { - /* error msg filled in above */ - CC_log_error(func, "Error from CC_Connect", conn); - return SQL_ERROR; - } - - /* - * Create the Output Connection String - */ - result = SQL_SUCCESS; - - lenStrout = cbConnStrOutMax; - if (conn->ms_jet && lenStrout > 255) - lenStrout = 255; - makeConnectString(connStrOut, ci, lenStrout); - len = strlen(connStrOut); - - if (szConnStrOut) - { - /* - * Return the completed string to the caller. The correct method - * is to only construct the connect string if a dialog was put up, - * otherwise, it should just copy the connection input string to - * the output. However, it seems ok to just always construct an - * output string. There are possible bad side effects on working - * applications (Access) by implementing the correct behavior, - * anyway. - */ - strncpy_null(szConnStrOut, connStrOut, cbConnStrOutMax); - - if (len >= cbConnStrOutMax) - { - int clen; - - for (clen = strlen(szConnStrOut) - 1; clen >= 0 && szConnStrOut[clen] != ';'; clen--) - szConnStrOut[clen] = '\0'; - result = SQL_SUCCESS_WITH_INFO; - conn->errornumber = CONN_TRUNCATED; - conn->errormsg = "The buffer was too small for the ConnStrOut."; - } - } - - if (pcbConnStrOut) - *pcbConnStrOut = len; - - mylog("szConnStrOut = '%s' len=%d,%d\n", szConnStrOut, len, cbConnStrOutMax); - qlog("conn=%u, PGAPI_DriverConnect(out)='%s'\n", conn, szConnStrOut); - - - mylog("PGAPI_DriverConnect: returning %d\n", result); - return result; -} - - -#ifdef WIN32 -RETCODE -dconn_DoDialog(HWND hwnd, ConnInfo *ci) -{ - int dialog_result; - - mylog("dconn_DoDialog: ci = %u\n", ci); - - if (hwnd) - { - dialog_result = DialogBoxParam(s_hModule, MAKEINTRESOURCE(DLG_CONFIG), - hwnd, dconn_FDriverConnectProc, (LPARAM) ci); - if (!dialog_result || (dialog_result == -1)) - return SQL_NO_DATA_FOUND; - else - return SQL_SUCCESS; - } - - return SQL_ERROR; -} - - -BOOL FAR PASCAL -dconn_FDriverConnectProc( - HWND hdlg, - UINT wMsg, - WPARAM wParam, - LPARAM lParam) -{ - ConnInfo *ci; - - switch (wMsg) - { - case WM_INITDIALOG: - ci = (ConnInfo *) lParam; - - /* Change the caption for the setup dialog */ - SetWindowText(hdlg, "PostgreSQL Connection"); - - SetWindowText(GetDlgItem(hdlg, IDC_DATASOURCE), "Connection"); - - /* Hide the DSN and description fields */ - ShowWindow(GetDlgItem(hdlg, IDC_DSNAMETEXT), SW_HIDE); - ShowWindow(GetDlgItem(hdlg, IDC_DSNAME), SW_HIDE); - ShowWindow(GetDlgItem(hdlg, IDC_DESCTEXT), SW_HIDE); - ShowWindow(GetDlgItem(hdlg, IDC_DESC), SW_HIDE); - ShowWindow(GetDlgItem(hdlg, IDC_DRIVER), SW_HIDE); - - SetWindowLong(hdlg, DWL_USER, lParam); /* Save the ConnInfo for - * the "OK" */ - SetDlgStuff(hdlg, ci); - - if (ci->database[0] == '\0') - ; /* default focus */ - else if (ci->server[0] == '\0') - SetFocus(GetDlgItem(hdlg, IDC_SERVER)); - else if (ci->port[0] == '\0') - SetFocus(GetDlgItem(hdlg, IDC_PORT)); - else if (ci->username[0] == '\0') - SetFocus(GetDlgItem(hdlg, IDC_USER)); - else if (ci->focus_password) - SetFocus(GetDlgItem(hdlg, IDC_PASSWORD)); - break; - - case WM_COMMAND: - switch (GET_WM_COMMAND_ID(wParam, lParam)) - { - case IDOK: - ci = (ConnInfo *) GetWindowLong(hdlg, DWL_USER); - - GetDlgStuff(hdlg, ci); - - case IDCANCEL: - EndDialog(hdlg, GET_WM_COMMAND_ID(wParam, lParam) == IDOK); - return TRUE; - - case IDC_DATASOURCE: - ci = (ConnInfo *) GetWindowLong(hdlg, DWL_USER); - DialogBoxParam(s_hModule, MAKEINTRESOURCE(DLG_OPTIONS_DRV), - hdlg, ds_options1Proc, (LPARAM) ci); - break; - - case IDC_DRIVER: - ci = (ConnInfo *) GetWindowLong(hdlg, DWL_USER); - DialogBoxParam(s_hModule, MAKEINTRESOURCE(DLG_OPTIONS_DRV), - hdlg, driver_optionsProc, (LPARAM) ci); - break; - } - } - - return FALSE; -} -#endif /* WIN32 */ - - -void -dconn_get_connect_attributes(const UCHAR FAR * connect_string, ConnInfo *ci) -{ - char *our_connect_string; - char *pair, - *attribute, - *value, - *equals; - char *strtok_arg; - - CC_conninfo_init(ci); - - our_connect_string = strdup(connect_string); - strtok_arg = our_connect_string; - - mylog("our_connect_string = '%s'\n", our_connect_string); - - while (1) - { - pair = strtok(strtok_arg, ";"); - if (strtok_arg) - strtok_arg = 0; - if (!pair) - break; - - equals = strchr(pair, '='); - if (!equals) - continue; - - *equals = '\0'; - attribute = pair; /* ex. DSN */ - value = equals + 1; /* ex. 'CEO co1' */ - - mylog("attribute = '%s', value = '%s'\n", attribute, value); - - if (!attribute || !value) - continue; - - /* Copy the appropriate value to the conninfo */ - copyAttributes(ci, attribute, value); - - } - - free(our_connect_string); -} - -static void -dconn_get_common_attributes(const UCHAR FAR * connect_string, ConnInfo *ci) -{ - char *our_connect_string; - char *pair, - *attribute, - *value, - *equals; - char *strtok_arg; - - our_connect_string = strdup(connect_string); - strtok_arg = our_connect_string; - - mylog("our_connect_string = '%s'\n", our_connect_string); - - while (1) - { - pair = strtok(strtok_arg, ";"); - if (strtok_arg) - strtok_arg = 0; - if (!pair) - break; - - equals = strchr(pair, '='); - if (!equals) - continue; - - *equals = '\0'; - attribute = pair; /* ex. DSN */ - value = equals + 1; /* ex. 'CEO co1' */ - - mylog("attribute = '%s', value = '%s'\n", attribute, value); - - if (!attribute || !value) - continue; - - /* Copy the appropriate value to the conninfo */ - copyCommonAttributes(ci, attribute, value); - - } - - free(our_connect_string); -} diff --git a/src/interfaces/odbc/environ.c b/src/interfaces/odbc/environ.c deleted file mode 100644 index 9ac8f8eb6cf..00000000000 --- a/src/interfaces/odbc/environ.c +++ /dev/null @@ -1,661 +0,0 @@ -/*------- - * Module: environ.c - * - * Description: This module contains routines related to - * the environment, such as storing connection handles, - * and returning errors. - * - * Classes: EnvironmentClass (Functions prefix: "EN_") - * - * API functions: SQLAllocEnv, SQLFreeEnv, SQLError - * - * Comments: See "notice.txt" for copyright and license information. - *------- - */ - -#include "environ.h" - -#include "connection.h" -#include "dlg_specific.h" -#include "statement.h" -#include <stdlib.h> -#include <string.h> -#include "pgapifunc.h" - -extern GLOBAL_VALUES globals; - -/* The one instance of the handles */ -ConnectionClass *conns[MAX_CONNECTIONS]; - - -RETCODE SQL_API -PGAPI_AllocEnv(HENV FAR * phenv) -{ - static char *func = "PGAPI_AllocEnv"; - - mylog("**** in PGAPI_AllocEnv ** \n"); - - /* - * Hack for systems on which none of the constructor-making techniques - * in psqlodbc.c work: if globals appears not to have been - * initialized, then cause it to be initialized. Since this should be - * the first function called in this shared library, doing it here - * should work. - */ - if (globals.socket_buffersize <= 0) - getCommonDefaults(DBMS_NAME, ODBCINST_INI, NULL); - - *phenv = (HENV) EN_Constructor(); - if (!*phenv) - { - *phenv = SQL_NULL_HENV; - EN_log_error(func, "Error allocating environment", NULL); - return SQL_ERROR; - } - - mylog("** exit PGAPI_AllocEnv: phenv = %u **\n", *phenv); - return SQL_SUCCESS; -} - - -RETCODE SQL_API -PGAPI_FreeEnv(HENV henv) -{ - static char *func = "PGAPI_FreeEnv"; - EnvironmentClass *env = (EnvironmentClass *) henv; - - mylog("**** in PGAPI_FreeEnv: env = %u ** \n", env); - - if (env && EN_Destructor(env)) - { - mylog(" ok\n"); - return SQL_SUCCESS; - } - - mylog(" error\n"); - EN_log_error(func, "Error freeing environment", env); - return SQL_ERROR; -} - - -static void -pg_sqlstate_set(const EnvironmentClass *env, UCHAR *szSqlState, const UCHAR *ver3str, const UCHAR *ver2str) -{ - strcpy(szSqlState, EN_is_odbc3(env) ? ver3str : ver2str); -} - -#define DRVMNGRDIV 511 -/* Returns the next SQL error information. */ -RETCODE SQL_API -PGAPI_StmtError( HSTMT hstmt, - SWORD RecNumber, - UCHAR FAR * szSqlState, - SDWORD FAR * pfNativeError, - UCHAR FAR * szErrorMsg, - SWORD cbErrorMsgMax, - SWORD FAR * pcbErrorMsg, - UWORD flag) -{ - /* CC: return an error of a hstmt */ - StatementClass *stmt = (StatementClass *) hstmt; - EnvironmentClass *env = (EnvironmentClass *) SC_get_conn(stmt)->henv; - char *msg; - int status; - BOOL partial_ok = ((flag & PODBC_ALLOW_PARTIAL_EXTRACT) != 0), - clear_str = ((flag & PODBC_ERROR_CLEAR) != 0); - SWORD msglen, stapos, wrtlen, pcblen; - - mylog("**** PGAPI_StmtError: hstmt=%u <%d>\n", hstmt, cbErrorMsgMax); - - if (cbErrorMsgMax < 0) - return SQL_ERROR; - - if (!SC_get_error(stmt, &status, &msg) || NULL == msg || !msg[0]) - { - mylog("SC_Get_error returned nothing.\n"); - if (NULL != szSqlState) - strcpy(szSqlState, "00000"); - if (NULL != pcbErrorMsg) - *pcbErrorMsg = 0; - if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0)) - szErrorMsg[0] = '\0'; - - return SQL_NO_DATA_FOUND; - } - mylog("SC_get_error: status = %d, msg = #%s#\n", status, msg); - msglen = (SWORD) strlen(msg); - /* - * Even though an application specifies a larger error message - * buffer, the driver manager changes it silently. - * Therefore we divide the error message into ... - */ - if (stmt->error_recsize < 0) - { - if (cbErrorMsgMax > 0) - stmt->error_recsize = cbErrorMsgMax - 1; /* apply the first request */ - else - stmt->error_recsize = DRVMNGRDIV; - } - if (RecNumber < 0) - { - if (0 == stmt->errorpos) - RecNumber = 1; - else - RecNumber = 2 + (stmt->errorpos - 1) / stmt->error_recsize; - } - stapos = (RecNumber - 1) * stmt->error_recsize; - if (stapos > msglen) - return SQL_NO_DATA_FOUND; - pcblen = wrtlen = msglen - stapos; - if (pcblen > stmt->error_recsize) - pcblen = stmt->error_recsize; - if (0 == cbErrorMsgMax) - wrtlen = 0; - else if (wrtlen >= cbErrorMsgMax) - { - if (partial_ok) - wrtlen = cbErrorMsgMax - 1; - else if (cbErrorMsgMax <= stmt->error_recsize) - wrtlen = 0; - else - wrtlen = stmt->error_recsize; - } - if (wrtlen > pcblen) - wrtlen = pcblen; - if (NULL != pcbErrorMsg) - *pcbErrorMsg = pcblen; - - if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0)) - { - memcpy(szErrorMsg, msg + stapos, wrtlen); - szErrorMsg[wrtlen] = '\0'; - } - - if (NULL != pfNativeError) - *pfNativeError = status; - - if (NULL != szSqlState) - - switch (status) - { - /* now determine the SQLSTATE to be returned */ - case STMT_ROW_VERSION_CHANGED: - pg_sqlstate_set(env, szSqlState, "01001", "01001"); - /* data truncated */ - break; - case STMT_TRUNCATED: - pg_sqlstate_set(env, szSqlState, "01004", "01004"); - /* data truncated */ - break; - case STMT_INFO_ONLY: - pg_sqlstate_set(env, szSqlState, "00000", "0000"); - /* just information that is returned, no error */ - break; - case STMT_BAD_ERROR: - pg_sqlstate_set(env, szSqlState, "08S01", "08S01"); - /* communication link failure */ - break; - case STMT_CREATE_TABLE_ERROR: - pg_sqlstate_set(env, szSqlState, "42S01", "S0001"); - /* table already exists */ - break; - case STMT_STATUS_ERROR: - case STMT_SEQUENCE_ERROR: - pg_sqlstate_set(env, szSqlState, "HY010", "S1010"); - /* Function sequence error */ - break; - case STMT_NO_MEMORY_ERROR: - pg_sqlstate_set(env, szSqlState, "HY001", "S1001"); - /* memory allocation failure */ - break; - case STMT_COLNUM_ERROR: - pg_sqlstate_set(env, szSqlState, "07009", "S1002"); - /* invalid column number */ - break; - case STMT_NO_STMTSTRING: - pg_sqlstate_set(env, szSqlState, "HY001", "S1001"); - /* having no stmtstring is also a malloc problem */ - break; - case STMT_ERROR_TAKEN_FROM_BACKEND: - pg_sqlstate_set(env, szSqlState, "HY000", "S1000"); - /* general error */ - break; - case STMT_INTERNAL_ERROR: - pg_sqlstate_set(env, szSqlState, "HY000", "S1000"); - /* general error */ - break; - case STMT_FETCH_OUT_OF_RANGE: - pg_sqlstate_set(env, szSqlState, "HY106", "S1106"); - break; - - case STMT_ROW_OUT_OF_RANGE: - pg_sqlstate_set(env, szSqlState, "HY107", "S1107"); - break; - - case STMT_OPERATION_CANCELLED: - pg_sqlstate_set(env, szSqlState, "HY008", "S1008"); - break; - - case STMT_NOT_IMPLEMENTED_ERROR: - pg_sqlstate_set(env, szSqlState, "HYC00", "S1C00"); /* == 'driver not - * capable' */ - break; - case STMT_OPTION_OUT_OF_RANGE_ERROR: - pg_sqlstate_set(env, szSqlState, "HY092", "S1092"); - break; - case STMT_BAD_PARAMETER_NUMBER_ERROR: - pg_sqlstate_set(env, szSqlState, "07009", "S1093"); - break; - case STMT_INVALID_COLUMN_NUMBER_ERROR: - pg_sqlstate_set(env, szSqlState, "07009", "S1002"); - break; - case STMT_RESTRICTED_DATA_TYPE_ERROR: - pg_sqlstate_set(env, szSqlState, "07006", "07006"); - break; - case STMT_INVALID_CURSOR_STATE_ERROR: - pg_sqlstate_set(env, szSqlState, "07005", "24000"); - break; - case STMT_ERROR_IN_ROW: - pg_sqlstate_set(env, szSqlState, "01S01", "01S01"); - break; - case STMT_OPTION_VALUE_CHANGED: - pg_sqlstate_set(env, szSqlState, "01S02", "01S02"); - break; - case STMT_POS_BEFORE_RECORDSET: - pg_sqlstate_set(env, szSqlState, "01S06", "01S06"); - break; - case STMT_INVALID_CURSOR_NAME: - pg_sqlstate_set(env, szSqlState, "34000", "34000"); - break; - case STMT_NO_CURSOR_NAME: - pg_sqlstate_set(env, szSqlState, "S1015", "S1015"); - break; - case STMT_INVALID_ARGUMENT_NO: - pg_sqlstate_set(env, szSqlState, "HY024", "S1009"); - /* invalid argument value */ - break; - case STMT_INVALID_CURSOR_POSITION: - pg_sqlstate_set(env, szSqlState, "HY109", "S1109"); - break; - case STMT_RETURN_NULL_WITHOUT_INDICATOR: - pg_sqlstate_set(env, szSqlState, "22002", "22002"); - break; - case STMT_VALUE_OUT_OF_RANGE: - pg_sqlstate_set(env, szSqlState, "HY019", "22003"); - break; - case STMT_OPERATION_INVALID: - pg_sqlstate_set(env, szSqlState, "HY011", "S1011"); - break; - case STMT_INVALID_DESCRIPTOR_IDENTIFIER: - pg_sqlstate_set(env, szSqlState, "HY091", "HY091"); - break; - case STMT_INVALID_OPTION_IDENTIFIER: - pg_sqlstate_set(env, szSqlState, "HY092", "HY092"); - break; - case STMT_OPTION_NOT_FOR_THE_DRIVER: - pg_sqlstate_set(env, szSqlState, "HYC00", "HYC00"); - break; - case STMT_EXEC_ERROR: - default: - pg_sqlstate_set(env, szSqlState, "HY000", "S1000"); - /* also a general error */ - break; - } - mylog(" szSqlState = '%s',len=%d, szError='%s'\n", szSqlState, pcblen, szErrorMsg); - if (clear_str) - { - stmt->errorpos = stapos + wrtlen; - if (stmt->errorpos >= msglen) - SC_clear_error(stmt); - } - if (wrtlen == 0) - return SQL_SUCCESS_WITH_INFO; - else - return SQL_SUCCESS; -} - -RETCODE SQL_API -PGAPI_ConnectError( HDBC hdbc, - SWORD RecNumber, - UCHAR FAR * szSqlState, - SDWORD FAR * pfNativeError, - UCHAR FAR * szErrorMsg, - SWORD cbErrorMsgMax, - SWORD FAR * pcbErrorMsg, - UWORD flag) -{ - ConnectionClass *conn = (ConnectionClass *) hdbc; - EnvironmentClass *env = (EnvironmentClass *) conn->henv; - char *msg; - int status; - BOOL once_again = FALSE; - SWORD msglen; - - mylog("**** PGAPI_ConnectError: hdbc=%u <%d>\n", hdbc, cbErrorMsgMax); - if (RecNumber != 1 && RecNumber != -1) - return SQL_NO_DATA_FOUND; - if (cbErrorMsgMax < 0) - return SQL_ERROR; - if (!CC_get_error(conn, &status, &msg) || NULL == msg) - { - mylog("CC_Get_error returned nothing.\n"); - if (NULL != szSqlState) - strcpy(szSqlState, "00000"); - if (NULL != pcbErrorMsg) - *pcbErrorMsg = 0; - if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0)) - szErrorMsg[0] = '\0'; - - return SQL_NO_DATA_FOUND; - } - mylog("CC_get_error: status = %d, msg = #%s#\n", status, msg); - - msglen = strlen(msg); - if (NULL != pcbErrorMsg) - { - *pcbErrorMsg = msglen; - if (cbErrorMsgMax == 0) - once_again = TRUE; - else if (msglen >= cbErrorMsgMax) - *pcbErrorMsg = cbErrorMsgMax - 1; - } - if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0)) - strncpy_null(szErrorMsg, msg, cbErrorMsgMax); - if (NULL != pfNativeError) - *pfNativeError = status; - - if (NULL != szSqlState) - switch (status) - { - case STMT_OPTION_VALUE_CHANGED: - case CONN_OPTION_VALUE_CHANGED: - pg_sqlstate_set(env, szSqlState, "01S02", "01S02"); - break; - case STMT_TRUNCATED: - case CONN_TRUNCATED: - pg_sqlstate_set(env, szSqlState, "01004", "01004"); - /* data truncated */ - break; - case CONN_INIREAD_ERROR: - pg_sqlstate_set(env, szSqlState, "IM002", "IM002"); - /* data source not found */ - break; - case CONNECTION_SERVER_NOT_REACHED: - case CONN_OPENDB_ERROR: - pg_sqlstate_set(env, szSqlState, "08001", "08001"); - /* unable to connect to data source */ - break; - case CONN_INVALID_AUTHENTICATION: - case CONN_AUTH_TYPE_UNSUPPORTED: - pg_sqlstate_set(env, szSqlState, "28000", "28000"); - break; - case CONN_STMT_ALLOC_ERROR: - pg_sqlstate_set(env, szSqlState, "HY001", "S1001"); - /* memory allocation failure */ - break; - case CONN_IN_USE: - pg_sqlstate_set(env, szSqlState, "HY000", "S1000"); - /* general error */ - break; - case CONN_UNSUPPORTED_OPTION: - pg_sqlstate_set(env, szSqlState, "IM001", "IM001"); - /* driver does not support this function */ - case CONN_INVALID_ARGUMENT_NO: - pg_sqlstate_set(env, szSqlState, "HY009", "S1009"); - /* invalid argument value */ - break; - case CONN_TRANSACT_IN_PROGRES: - pg_sqlstate_set(env, szSqlState, "HY010", "S1010"); - - /* - * when the user tries to switch commit mode in a - * transaction - */ - /* -> function sequence error */ - break; - case CONN_NO_MEMORY_ERROR: - pg_sqlstate_set(env, szSqlState, "HY001", "S1001"); - break; - case CONN_NOT_IMPLEMENTED_ERROR: - case STMT_NOT_IMPLEMENTED_ERROR: - pg_sqlstate_set(env, szSqlState, "HYC00", "S1C00"); - break; - case STMT_RETURN_NULL_WITHOUT_INDICATOR: - pg_sqlstate_set(env, szSqlState, "22002", "22002"); - break; - case CONN_VALUE_OUT_OF_RANGE: - case STMT_VALUE_OUT_OF_RANGE: - pg_sqlstate_set(env, szSqlState, "HY019", "22003"); - break; - default: - pg_sqlstate_set(env, szSqlState, "HY000", "S1000"); - /* general error */ - break; - } - - mylog(" szSqlState = '%s',len=%d, szError='%s'\n", szSqlState, msglen, szErrorMsg); - if (once_again) - { - conn->errornumber = status; - return SQL_SUCCESS_WITH_INFO; - } - else - return SQL_SUCCESS; -} - -RETCODE SQL_API -PGAPI_EnvError( HENV henv, - SWORD RecNumber, - UCHAR FAR * szSqlState, - SDWORD FAR * pfNativeError, - UCHAR FAR * szErrorMsg, - SWORD cbErrorMsgMax, - SWORD FAR * pcbErrorMsg, - UWORD flag) -{ - EnvironmentClass *env = (EnvironmentClass *) henv; - char *msg; - int status; - - mylog("**** PGAPI_EnvError: henv=%u <%d>\n", henv, cbErrorMsgMax); - if (RecNumber != 1 && RecNumber != -1) - return SQL_NO_DATA_FOUND; - if (cbErrorMsgMax < 0) - return SQL_ERROR; - if (!EN_get_error(env, &status, &msg) || NULL == msg) - { - mylog("EN_get_error: status = %d, msg = #%s#\n", status, msg); - - if (NULL != szSqlState) - pg_sqlstate_set(env, szSqlState, "00000", "00000"); - if (NULL != pcbErrorMsg) - *pcbErrorMsg = 0; - if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0)) - szErrorMsg[0] = '\0'; - - return SQL_NO_DATA_FOUND; - } - mylog("EN_get_error: status = %d, msg = #%s#\n", status, msg); - - if (NULL != pcbErrorMsg) - *pcbErrorMsg = (SWORD) strlen(msg); - if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0)) - strncpy_null(szErrorMsg, msg, cbErrorMsgMax); - if (NULL != pfNativeError) - *pfNativeError = status; - - if (szSqlState) - { - switch (status) - { - case ENV_ALLOC_ERROR: - /* memory allocation failure */ - pg_sqlstate_set(env, szSqlState, "HY001", "S1001"); - break; - default: - pg_sqlstate_set(env, szSqlState, "HY000", "S1000"); - /* general error */ - break; - } - } - - return SQL_SUCCESS; -} - - -/* Returns the next SQL error information. */ -RETCODE SQL_API -PGAPI_Error( - HENV henv, - HDBC hdbc, - HSTMT hstmt, - UCHAR FAR * szSqlState, - SDWORD FAR * pfNativeError, - UCHAR FAR * szErrorMsg, - SWORD cbErrorMsgMax, - SWORD FAR * pcbErrorMsg) -{ - RETCODE ret; - UWORD flag = PODBC_ALLOW_PARTIAL_EXTRACT | PODBC_ERROR_CLEAR; - - mylog("**** PGAPI_Error: henv=%u, hdbc=%u hstmt=%d\n", henv, hdbc, hstmt); - - if (cbErrorMsgMax < 0) - return SQL_ERROR; - if (SQL_NULL_HSTMT != hstmt) - ret = PGAPI_StmtError(hstmt, -1, szSqlState, pfNativeError, - szErrorMsg, cbErrorMsgMax, pcbErrorMsg, flag); - else if (SQL_NULL_HDBC != hdbc) - ret = PGAPI_ConnectError(hdbc, -1, szSqlState, pfNativeError, - szErrorMsg, cbErrorMsgMax, pcbErrorMsg, flag); - else if (SQL_NULL_HENV != hdbc) - ret = PGAPI_EnvError(henv, -1, szSqlState, pfNativeError, - szErrorMsg, cbErrorMsgMax, pcbErrorMsg, flag); - else - { - if (NULL != szSqlState) - strcpy(szSqlState, "00000"); - if (NULL != pcbErrorMsg) - *pcbErrorMsg = 0; - if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0)) - szErrorMsg[0] = '\0'; - - ret = SQL_NO_DATA_FOUND; - } - mylog("**** PGAPI_Error exit code=%d\n", ret); - return ret; -} - -/* - * EnvironmentClass implementation - */ -EnvironmentClass * -EN_Constructor(void) -{ - EnvironmentClass *rv; - - rv = (EnvironmentClass *) malloc(sizeof(EnvironmentClass)); - if (rv) - { - rv->errormsg = 0; - rv->errornumber = 0; - rv->flag = 0; - } - - return rv; -} - - -char -EN_Destructor(EnvironmentClass *self) -{ - int lf; - char rv = 1; - - mylog("in EN_Destructor, self=%u\n", self); - - /* - * the error messages are static strings distributed throughout the - * source--they should not be freed - */ - - /* Free any connections belonging to this environment */ - for (lf = 0; lf < MAX_CONNECTIONS; lf++) - { - if (conns[lf] && conns[lf]->henv == self) - rv = rv && CC_Destructor(conns[lf]); - } - free(self); - - mylog("exit EN_Destructor: rv = %d\n", rv); -#ifdef _MEMORY_DEBUG_ - debug_memory_check(); -#endif /* _MEMORY_DEBUG_ */ - return rv; -} - - -char -EN_get_error(EnvironmentClass *self, int *number, char **message) -{ - if (self && self->errormsg && self->errornumber) - { - *message = self->errormsg; - *number = self->errornumber; - self->errormsg = 0; - self->errornumber = 0; - return 1; - } - else - return 0; -} - - -char -EN_add_connection(EnvironmentClass *self, ConnectionClass *conn) -{ - int i; - - mylog("EN_add_connection: self = %u, conn = %u\n", self, conn); - - for (i = 0; i < MAX_CONNECTIONS; i++) - { - if (!conns[i]) - { - conn->henv = self; - conns[i] = conn; - - mylog(" added at i =%d, conn->henv = %u, conns[i]->henv = %u\n", i, conn->henv, conns[i]->henv); - - return TRUE; - } - } - - return FALSE; -} - - -char -EN_remove_connection(EnvironmentClass *self, ConnectionClass *conn) -{ - int i; - - for (i = 0; i < MAX_CONNECTIONS; i++) - if (conns[i] == conn && conns[i]->status != CONN_EXECUTING) - { - conns[i] = NULL; - return TRUE; - } - - return FALSE; -} - - -void -EN_log_error(char *func, char *desc, EnvironmentClass *self) -{ - if (self) - qlog("ENVIRON ERROR: func=%s, desc='%s', errnum=%d, errmsg='%s'\n", func, desc, self->errornumber, self->errormsg); - else - qlog("INVALID ENVIRON HANDLE ERROR: func=%s, desc='%s'\n", func, desc); -} diff --git a/src/interfaces/odbc/environ.h b/src/interfaces/odbc/environ.h deleted file mode 100644 index 24b456d4899..00000000000 --- a/src/interfaces/odbc/environ.h +++ /dev/null @@ -1,38 +0,0 @@ -/* File: environ.h - * - * Description: See "environ.c" - * - * Comments: See "notice.txt" for copyright and license information. - * - */ - -#ifndef __ENVIRON_H__ -#define __ENVIRON_H__ - -#include "psqlodbc.h" - -#define ENV_ALLOC_ERROR 1 - -/********** Environment Handle *************/ -struct EnvironmentClass_ -{ - char *errormsg; - int errornumber; - Int4 flag; -}; - -/* Environment prototypes */ -EnvironmentClass *EN_Constructor(void); -char EN_Destructor(EnvironmentClass *self); -char EN_get_error(EnvironmentClass *self, int *number, char **message); -char EN_add_connection(EnvironmentClass *self, ConnectionClass *conn); -char EN_remove_connection(EnvironmentClass *self, ConnectionClass *conn); -void EN_log_error(char *func, char *desc, EnvironmentClass *self); - -#define EN_OV_ODBC2 1L -#define EN_is_odbc2(env) ((env->flag & EN_OV_ODBC2) != 0) -#define EN_is_odbc3(env) ((env->flag & EN_OV_ODBC2) == 0) -#define EN_set_odbc2(env) (env->flag |= EN_OV_ODBC2) -#define EN_set_odbc3(env) (env->flag &= EN_OV_ODBC2) - -#endif diff --git a/src/interfaces/odbc/execute.c b/src/interfaces/odbc/execute.c deleted file mode 100644 index 598c2a2f61a..00000000000 --- a/src/interfaces/odbc/execute.c +++ /dev/null @@ -1,1090 +0,0 @@ -/*------- - * Module: execute.c - * - * Description: This module contains routines related to - * preparing and executing an SQL statement. - * - * Classes: n/a - * - * API functions: SQLPrepare, SQLExecute, SQLExecDirect, SQLTransact, - * SQLCancel, SQLNativeSql, SQLParamData, SQLPutData - * - * Comments: See "notice.txt" for copyright and license information. - *------- - */ - -#include "psqlodbc.h" - -#include <stdio.h> -#include <string.h> - -#include "connection.h" -#include "statement.h" -#include "qresult.h" -#include "convert.h" -#include "bind.h" -#include "pgtypes.h" -#include "lobj.h" -#include "pgapifunc.h" - -/*extern GLOBAL_VALUES globals;*/ - - -/* Perform a Prepare on the SQL statement */ -RETCODE SQL_API -PGAPI_Prepare(HSTMT hstmt, - UCHAR FAR * szSqlStr, - SDWORD cbSqlStr) -{ - static char *func = "PGAPI_Prepare"; - StatementClass *self = (StatementClass *) hstmt; - - mylog("%s: entering...\n", func); - - if (!self) - { - SC_log_error(func, "", NULL); - return SQL_INVALID_HANDLE; - } - - /* - * According to the ODBC specs it is valid to call SQLPrepare mulitple - * times. In that case, the bound SQL statement is replaced by the new - * one - */ - - switch (self->status) - { - case STMT_PREMATURE: - mylog("**** PGAPI_Prepare: STMT_PREMATURE, recycle\n"); - SC_recycle_statement(self); /* recycle the statement, but do - * not remove parameter bindings */ - break; - - case STMT_FINISHED: - mylog("**** PGAPI_Prepare: STMT_FINISHED, recycle\n"); - SC_recycle_statement(self); /* recycle the statement, but do - * not remove parameter bindings */ - break; - - case STMT_ALLOCATED: - mylog("**** PGAPI_Prepare: STMT_ALLOCATED, copy\n"); - self->status = STMT_READY; - break; - - case STMT_READY: - mylog("**** PGAPI_Prepare: STMT_READY, change SQL\n"); - break; - - case STMT_EXECUTING: - mylog("**** PGAPI_Prepare: STMT_EXECUTING, error!\n"); - - self->errornumber = STMT_SEQUENCE_ERROR; - self->errormsg = "PGAPI_Prepare(): The handle does not point to a statement that is ready to be executed"; - SC_log_error(func, "", self); - - return SQL_ERROR; - - default: - self->errornumber = STMT_INTERNAL_ERROR; - self->errormsg = "An Internal Error has occured -- Unknown statement status."; - SC_log_error(func, "", self); - return SQL_ERROR; - } - - if (self->statement) - free(self->statement); - if (self->stmt_with_params) - free(self->stmt_with_params); - self->stmt_with_params = NULL; - if (self->load_statement) - free(self->load_statement); - self->load_statement = NULL; - - self->statement = make_string(szSqlStr, cbSqlStr, NULL); - if (!self->statement) - { - self->errornumber = STMT_NO_MEMORY_ERROR; - self->errormsg = "No memory available to store statement"; - SC_log_error(func, "", self); - return SQL_ERROR; - } - - self->prepare = TRUE; - self->statement_type = statement_type(self->statement); - - /* Check if connection is onlyread (only selects are allowed) */ - if (CC_is_onlyread(self->hdbc) && STMT_UPDATE(self)) - { - self->errornumber = STMT_EXEC_ERROR; - self->errormsg = "Connection is readonly, only select statements are allowed."; - SC_log_error(func, "", self); - return SQL_ERROR; - } - - return SQL_SUCCESS; -} - - -/* Performs the equivalent of SQLPrepare, followed by SQLExecute. */ -RETCODE SQL_API -PGAPI_ExecDirect( - HSTMT hstmt, - UCHAR FAR * szSqlStr, - SDWORD cbSqlStr) -{ - StatementClass *stmt = (StatementClass *) hstmt; - RETCODE result; - static char *func = "PGAPI_ExecDirect"; - - mylog("%s: entering...\n", func); - - if (!stmt) - { - SC_log_error(func, "", NULL); - return SQL_INVALID_HANDLE; - } - - if (stmt->statement) - free(stmt->statement); - if (stmt->stmt_with_params) - free(stmt->stmt_with_params); - stmt->stmt_with_params = NULL; - if (stmt->load_statement) - free(stmt->load_statement); - stmt->load_statement = NULL; - - /* - * keep a copy of the un-parametrized statement, in case they try to - * execute this statement again - */ - stmt->statement = make_string(szSqlStr, cbSqlStr, NULL); - if (!stmt->statement) - { - stmt->errornumber = STMT_NO_MEMORY_ERROR; - stmt->errormsg = "No memory available to store statement"; - SC_log_error(func, "", stmt); - return SQL_ERROR; - } - - mylog("**** %s: hstmt=%u, statement='%s'\n", func, hstmt, stmt->statement); - - stmt->prepare = FALSE; - - /* - * If an SQLPrepare was performed prior to this, but was left in the - * premature state because an error occurred prior to SQLExecute then - * set the statement to finished so it can be recycled. - */ - if (stmt->status == STMT_PREMATURE) - stmt->status = STMT_FINISHED; - - stmt->statement_type = statement_type(stmt->statement); - - /* Check if connection is onlyread (only selects are allowed) */ - if (CC_is_onlyread(stmt->hdbc) && STMT_UPDATE(stmt)) - { - stmt->errornumber = STMT_EXEC_ERROR; - stmt->errormsg = "Connection is readonly, only select statements are allowed."; - SC_log_error(func, "", stmt); - return SQL_ERROR; - } - - mylog("%s: calling PGAPI_Execute...\n", func); - - result = PGAPI_Execute(hstmt); - - mylog("%s: returned %hd from PGAPI_Execute\n", func, result); - return result; -} - - -/* Execute a prepared SQL statement */ -RETCODE SQL_API -PGAPI_Execute( - HSTMT hstmt) -{ - static char *func = "PGAPI_Execute"; - StatementClass *stmt = (StatementClass *) hstmt; - APDFields *opts; - IPDFields *ipdopts; - ConnectionClass *conn; - int i, - retval, start_row, end_row; - int cursor_type, scroll_concurrency; - QResultClass *res; - - mylog("%s: entering...\n", func); - - if (!stmt) - { - SC_log_error(func, "", NULL); - mylog("%s: NULL statement so return SQL_INVALID_HANDLE\n", func); - return SQL_INVALID_HANDLE; - } - - opts = SC_get_APD(stmt); - cursor_type = stmt->options.cursor_type; - scroll_concurrency = stmt->options.scroll_concurrency; - /* - * If the statement is premature, it means we already executed it from - * an SQLPrepare/SQLDescribeCol type of scenario. So just return - * success. - */ - if (stmt->prepare && stmt->status == STMT_PREMATURE) - { - if (stmt->inaccurate_result) - { - stmt->exec_current_row = -1; - SC_recycle_statement(stmt); - } - else - { - stmt->status = STMT_FINISHED; - if (stmt->errormsg == NULL) - { - mylog("%s: premature statement but return SQL_SUCCESS\n", func); - return SQL_SUCCESS; - } - else - { - SC_log_error(func, "", stmt); - mylog("%s: premature statement so return SQL_ERROR\n", func); - return SQL_ERROR; - } - } - } - - mylog("%s: clear errors...\n", func); - - SC_clear_error(stmt); - - conn = SC_get_conn(stmt); - if (conn->status == CONN_EXECUTING) - { - stmt->errormsg = "Connection is already in use."; - stmt->errornumber = STMT_SEQUENCE_ERROR; - SC_log_error(func, "", stmt); - mylog("%s: problem with connection\n", func); - return SQL_ERROR; - } - - if (!stmt->statement) - { - stmt->errornumber = STMT_NO_STMTSTRING; - stmt->errormsg = "This handle does not have a SQL statement stored in it"; - SC_log_error(func, "", stmt); - mylog("%s: problem with handle\n", func); - return SQL_ERROR; - } - - /* - * If SQLExecute is being called again, recycle the statement. Note - * this should have been done by the application in a call to - * SQLFreeStmt(SQL_CLOSE) or SQLCancel. - */ - if (stmt->status == STMT_FINISHED) - { - mylog("%s: recycling statement (should have been done by app)...\n", func); -/******** Is this really NEEDED ? ******/ - SC_recycle_statement(stmt); - } - - /* Check if the statement is in the correct state */ - if ((stmt->prepare && stmt->status != STMT_READY) || - (stmt->status != STMT_ALLOCATED && stmt->status != STMT_READY)) - { - stmt->errornumber = STMT_STATUS_ERROR; - stmt->errormsg = "The handle does not point to a statement that is ready to be executed"; - SC_log_error(func, "", stmt); - mylog("%s: problem with statement\n", func); - return SQL_ERROR; - } - - if (start_row = stmt->exec_start_row, start_row < 0) - start_row = 0; - if (end_row = stmt->exec_end_row, end_row < 0) - end_row = opts->paramset_size - 1; - if (stmt->exec_current_row < 0) - stmt->exec_current_row = start_row; - ipdopts = SC_get_IPD(stmt); - if (stmt->exec_current_row == start_row) - { - if (ipdopts->param_processed_ptr) - *ipdopts->param_processed_ptr = 0; - SC_recycle_statement(stmt); - } - -next_param_row: -#if (ODBCVER >= 0x0300) - if (opts->param_operation_ptr) - { - while (opts->param_operation_ptr[stmt->exec_current_row] == SQL_PARAM_IGNORE) - { - if (ipdopts->param_status_ptr) - ipdopts->param_status_ptr[stmt->exec_current_row] = SQL_PARAM_UNUSED; - if (stmt->exec_current_row >= end_row) - { - stmt->exec_current_row = -1; - return SQL_SUCCESS; - } - ++stmt->exec_current_row; - } - } -#endif /* ODBCVER */ - /* - * Check if statement has any data-at-execute parameters when it is - * not in SC_pre_execute. - */ - if (!stmt->pre_executing) - { - /* - * The bound parameters could have possibly changed since the last - * execute of this statement? Therefore check for params and - * re-copy. - */ - UInt4 offset = opts->param_offset_ptr ? *opts->param_offset_ptr : 0; - Int4 bind_size = opts->param_bind_type; - Int4 current_row = stmt->exec_current_row < 0 ? 0 : stmt->exec_current_row; - - stmt->data_at_exec = -1; - for (i = 0; i < opts->allocated; i++) - { - Int4 *pcVal = opts->parameters[i].used; - - opts->parameters[i].data_at_exec = FALSE; - if (pcVal) - { - if (bind_size > 0) - pcVal = (Int4 *)((char *)pcVal + offset + bind_size * current_row); - else - pcVal = (Int4 *)((char *)pcVal + offset + sizeof(SDWORD) * current_row); - if (*pcVal == SQL_DATA_AT_EXEC || *pcVal <= SQL_LEN_DATA_AT_EXEC_OFFSET) - opts->parameters[i].data_at_exec = TRUE; - } - /* Check for data at execution parameters */ - if (opts->parameters[i].data_at_exec) - { - if (stmt->data_at_exec < 0) - stmt->data_at_exec = 1; - else - stmt->data_at_exec++; - } - } - - /* - * If there are some data at execution parameters, return need - * data - */ - - /* - * SQLParamData and SQLPutData will be used to send params and - * execute the statement. - */ - if (stmt->data_at_exec > 0) - return SQL_NEED_DATA; - - } - - - mylog("%s: copying statement params: trans_status=%d, len=%d, stmt='%s'\n", func, conn->transact_status, strlen(stmt->statement), stmt->statement); - - /* Create the statement with parameters substituted. */ - retval = copy_statement_with_parameters(stmt); - if (retval != SQL_SUCCESS) - /* error msg passed from above */ - return retval; - - mylog(" stmt_with_params = '%s'\n", stmt->stmt_with_params); - - if (!stmt->inaccurate_result || !conn->connInfo.disallow_premature) - { - retval = SC_execute(stmt); - if (retval != SQL_ERROR) - { - if (ipdopts->param_processed_ptr) - (*ipdopts->param_processed_ptr)++; - /* special handling of result for keyset driven cursors */ - if (SQL_CURSOR_KEYSET_DRIVEN == stmt->options.cursor_type && - SQL_CONCUR_READ_ONLY != stmt->options.scroll_concurrency) - { - QResultClass *kres; - - res = SC_get_Result(stmt); - if (kres = res->next, kres) - { - kres->fields = res->fields; - res->fields = NULL; - kres->num_fields = res->num_fields; - res->next = NULL; - QR_Destructor(res); - SC_set_Result(stmt, kres); - } - } - } -#if (ODBCVER >= 0x0300) - if (ipdopts->param_status_ptr) - { - switch (retval) - { - case SQL_SUCCESS: - ipdopts->param_status_ptr[stmt->exec_current_row] = SQL_PARAM_SUCCESS; - break; - case SQL_SUCCESS_WITH_INFO: - ipdopts->param_status_ptr[stmt->exec_current_row] = SQL_PARAM_SUCCESS_WITH_INFO; - break; - default: - ipdopts->param_status_ptr[stmt->exec_current_row] = SQL_PARAM_ERROR; - break; - } - } -#endif /* ODBCVER */ - if (retval == SQL_ERROR || - stmt->inaccurate_result || - stmt->exec_current_row >= end_row) - { - stmt->exec_current_row = -1; - return retval; - } - stmt->exec_current_row++; - goto next_param_row; - } - /* - * Get the field info for the prepared query using dummy backward - * fetch. - */ - if (SC_is_pre_executable(stmt)) - { - BOOL in_trans = CC_is_in_trans(conn); - BOOL issued_begin = FALSE, - begin_included = FALSE; - QResultClass *curres; - - if (strnicmp(stmt->stmt_with_params, "BEGIN;", 6) == 0) - begin_included = TRUE; - else if (!in_trans) - { - if (issued_begin = CC_begin(conn), !issued_begin) - { - stmt->errornumber = STMT_EXEC_ERROR; - stmt->errormsg = "Handle prepare error"; - return SQL_ERROR; - } - } - /* we are now in a transaction */ - res = CC_send_query(conn, stmt->stmt_with_params, NULL, CLEAR_RESULT_ON_ABORT); - if (!res) - { - CC_abort(conn); - stmt->errornumber = STMT_EXEC_ERROR; - stmt->errormsg = "Handle prepare error"; - return SQL_ERROR; - } - SC_set_Result(stmt, res); - for (curres = res; !curres->num_fields; curres = curres->next) - ; - SC_set_Curres(stmt, curres); - if (CC_is_in_autocommit(conn)) - { - if (issued_begin) - CC_commit(conn); - } - stmt->status = STMT_FINISHED; - return SQL_SUCCESS; - } - if (res = SC_get_Curres(stmt), res) - stmt->diag_row_count = res->recent_processed_row_count; - if (stmt->options.cursor_type != cursor_type || - stmt->options.scroll_concurrency != scroll_concurrency) - { - stmt->errornumber = STMT_OPTION_VALUE_CHANGED; - stmt->errormsg = "cursor updatability changed"; - return SQL_SUCCESS_WITH_INFO; - } - else - return SQL_SUCCESS; -} - - -RETCODE SQL_API -PGAPI_Transact( - HENV henv, - HDBC hdbc, - UWORD fType) -{ - static char *func = "PGAPI_Transact"; - extern ConnectionClass *conns[]; - ConnectionClass *conn; - QResultClass *res; - char ok, - *stmt_string; - int lf; - - mylog("entering %s: hdbc=%u, henv=%u\n", func, hdbc, henv); - - if (hdbc == SQL_NULL_HDBC && henv == SQL_NULL_HENV) - { - CC_log_error(func, "", NULL); - return SQL_INVALID_HANDLE; - } - - /* - * If hdbc is null and henv is valid, it means transact all - * connections on that henv. - */ - if (hdbc == SQL_NULL_HDBC && henv != SQL_NULL_HENV) - { - for (lf = 0; lf < MAX_CONNECTIONS; lf++) - { - conn = conns[lf]; - - if (conn && conn->henv == henv) - if (PGAPI_Transact(henv, (HDBC) conn, fType) != SQL_SUCCESS) - return SQL_ERROR; - } - return SQL_SUCCESS; - } - - conn = (ConnectionClass *) hdbc; - - if (fType == SQL_COMMIT) - stmt_string = "COMMIT"; - else if (fType == SQL_ROLLBACK) - stmt_string = "ROLLBACK"; - else - { - conn->errornumber = CONN_INVALID_ARGUMENT_NO; - conn->errormsg = "PGAPI_Transact can only be called with SQL_COMMIT or SQL_ROLLBACK as parameter"; - CC_log_error(func, "", conn); - return SQL_ERROR; - } - - /* If manual commit and in transaction, then proceed. */ - if (!CC_is_in_autocommit(conn) && CC_is_in_trans(conn)) - { - mylog("PGAPI_Transact: sending on conn %d '%s'\n", conn, stmt_string); - - res = CC_send_query(conn, stmt_string, NULL, CLEAR_RESULT_ON_ABORT); - if (!res) - { - /* error msg will be in the connection */ - CC_on_abort(conn, NO_TRANS); - CC_log_error(func, "", conn); - return SQL_ERROR; - } - - ok = QR_command_maybe_successful(res); - QR_Destructor(res); - - if (!ok) - { - CC_on_abort(conn, NO_TRANS); - CC_log_error(func, "", conn); - return SQL_ERROR; - } - } - return SQL_SUCCESS; -} - - -RETCODE SQL_API -PGAPI_Cancel( - HSTMT hstmt) /* Statement to cancel. */ -{ - static char *func = "PGAPI_Cancel"; - StatementClass *stmt = (StatementClass *) hstmt; - ConnectionClass *conn; - RETCODE result; - ConnInfo *ci; - -#ifdef WIN32 - HMODULE hmodule; - FARPROC addr; -#endif - - mylog("%s: entering...\n", func); - - /* Check if this can handle canceling in the middle of a SQLPutData? */ - if (!stmt) - { - SC_log_error(func, "", NULL); - return SQL_INVALID_HANDLE; - } - conn = SC_get_conn(stmt); - ci = &(conn->connInfo); - - /* - * Not in the middle of SQLParamData/SQLPutData so cancel like a - * close. - */ - if (stmt->data_at_exec < 0) - { - /* - * Tell the Backend that we're cancelling this request - */ - if (stmt->status == STMT_EXECUTING) - CC_send_cancel_request(conn); - /* - * MAJOR HACK for Windows to reset the driver manager's cursor - * state: Because of what seems like a bug in the Odbc driver - * manager, SQLCancel does not act like a SQLFreeStmt(CLOSE), as - * many applications depend on this behavior. So, this brute - * force method calls the driver manager's function on behalf of - * the application. - */ - -#ifdef WIN32 - if (ci->drivers.cancel_as_freestmt) - { - hmodule = GetModuleHandle("ODBC32"); - addr = GetProcAddress(hmodule, "SQLFreeStmt"); - result = addr((char *) (stmt->phstmt) - 96, SQL_CLOSE); - } - else - result = PGAPI_FreeStmt(hstmt, SQL_CLOSE); -#else - result = PGAPI_FreeStmt(hstmt, SQL_CLOSE); -#endif - - mylog("PGAPI_Cancel: PGAPI_FreeStmt returned %d\n", result); - - SC_clear_error(hstmt); - return SQL_SUCCESS; - } - - /* In the middle of SQLParamData/SQLPutData, so cancel that. */ - - /* - * Note, any previous data-at-exec buffers will be freed in the - * recycle - */ - /* if they call SQLExecDirect or SQLExecute again. */ - - stmt->data_at_exec = -1; - stmt->current_exec_param = -1; - stmt->put_data = FALSE; - - return SQL_SUCCESS; -} - - -/* - * Returns the SQL string as modified by the driver. - * Currently, just copy the input string without modification - * observing buffer limits and truncation. - */ -RETCODE SQL_API -PGAPI_NativeSql( - HDBC hdbc, - UCHAR FAR * szSqlStrIn, - SDWORD cbSqlStrIn, - UCHAR FAR * szSqlStr, - SDWORD cbSqlStrMax, - SDWORD FAR * pcbSqlStr) -{ - static char *func = "PGAPI_NativeSql"; - int len = 0; - char *ptr; - ConnectionClass *conn = (ConnectionClass *) hdbc; - RETCODE result; - - mylog("%s: entering...cbSqlStrIn=%d\n", func, cbSqlStrIn); - - ptr = (cbSqlStrIn == 0) ? "" : make_string(szSqlStrIn, cbSqlStrIn, NULL); - if (!ptr) - { - conn->errornumber = CONN_NO_MEMORY_ERROR; - conn->errormsg = "No memory available to store native sql string"; - CC_log_error(func, "", conn); - return SQL_ERROR; - } - - result = SQL_SUCCESS; - len = strlen(ptr); - - if (szSqlStr) - { - strncpy_null(szSqlStr, ptr, cbSqlStrMax); - - if (len >= cbSqlStrMax) - { - result = SQL_SUCCESS_WITH_INFO; - conn->errornumber = STMT_TRUNCATED; - conn->errormsg = "The buffer was too small for the NativeSQL."; - } - } - - if (pcbSqlStr) - *pcbSqlStr = len; - - if (cbSqlStrIn) - free(ptr); - - return result; -} - - -/* - * Supplies parameter data at execution time. - * Used in conjuction with SQLPutData. - */ -RETCODE SQL_API -PGAPI_ParamData( - HSTMT hstmt, - PTR FAR * prgbValue) -{ - static char *func = "PGAPI_ParamData"; - StatementClass *stmt = (StatementClass *) hstmt; - APDFields *opts; - IPDFields *ipdopts; - int i, - retval; - ConnInfo *ci; - - mylog("%s: entering...\n", func); - - if (!stmt) - { - SC_log_error(func, "", NULL); - return SQL_INVALID_HANDLE; - } - ci = &(SC_get_conn(stmt)->connInfo); - opts = SC_get_APD(stmt); - - mylog("%s: data_at_exec=%d, params_alloc=%d\n", func, stmt->data_at_exec, opts->allocated); - - if (stmt->data_at_exec < 0) - { - stmt->errornumber = STMT_SEQUENCE_ERROR; - stmt->errormsg = "No execution-time parameters for this statement"; - SC_log_error(func, "", stmt); - return SQL_ERROR; - } - - if (stmt->data_at_exec > opts->allocated) - { - stmt->errornumber = STMT_SEQUENCE_ERROR; - stmt->errormsg = "Too many execution-time parameters were present"; - SC_log_error(func, "", stmt); - return SQL_ERROR; - } - - /* close the large object */ - if (stmt->lobj_fd >= 0) - { - lo_close(stmt->hdbc, stmt->lobj_fd); - - /* commit transaction if needed */ - if (!ci->drivers.use_declarefetch && CC_is_in_autocommit(stmt->hdbc)) - { - if (!CC_commit(stmt->hdbc)) - { - stmt->errormsg = "Could not commit (in-line) a transaction"; - stmt->errornumber = STMT_EXEC_ERROR; - SC_log_error(func, "", stmt); - return SQL_ERROR; - } - } - stmt->lobj_fd = -1; - } - - /* Done, now copy the params and then execute the statement */ - ipdopts = SC_get_IPD(stmt); - if (stmt->data_at_exec == 0) - { - int end_row; - - retval = copy_statement_with_parameters(stmt); - if (retval != SQL_SUCCESS) - return retval; - - stmt->current_exec_param = -1; - - retval = SC_execute(stmt); - if (retval != SQL_ERROR) - { - if (ipdopts->param_processed_ptr) - (*ipdopts->param_processed_ptr)++; - } -#if (ODBCVER >= 0x0300) - if (ipdopts->param_status_ptr) - { - switch (retval) - { - case SQL_SUCCESS: - ipdopts->param_status_ptr[stmt->exec_current_row] = SQL_PARAM_SUCCESS; - break; - case SQL_SUCCESS_WITH_INFO: - ipdopts->param_status_ptr[stmt->exec_current_row] = SQL_PARAM_SUCCESS_WITH_INFO; - break; - default: - ipdopts->param_status_ptr[stmt->exec_current_row] = SQL_PARAM_ERROR; - break; - } - } -#endif /* ODBCVER */ - end_row = stmt->exec_end_row; - if (end_row < 0) - end_row = opts->paramset_size - 1; - if (retval == SQL_ERROR || - stmt->exec_current_row >= end_row) - { - stmt->exec_current_row = -1; - return retval; - } - stmt->exec_current_row++; - return PGAPI_Execute(stmt); - } - - /* - * Set beginning param; if first time SQLParamData is called , start - * at 0. Otherwise, start at the last parameter + 1. - */ - i = stmt->current_exec_param >= 0 ? stmt->current_exec_param + 1 : 0; - - /* At least 1 data at execution parameter, so Fill in the token value */ - for (; i < opts->allocated; i++) - { - if (opts->parameters[i].data_at_exec) - { - stmt->data_at_exec--; - stmt->current_exec_param = i; - stmt->put_data = FALSE; - *prgbValue = opts->parameters[i].buffer; /* token */ - break; - } - } - - return SQL_NEED_DATA; -} - - -/* - * Supplies parameter data at execution time. - * Used in conjunction with SQLParamData. - */ -RETCODE SQL_API -PGAPI_PutData( - HSTMT hstmt, - PTR rgbValue, - SDWORD cbValue) -{ - static char *func = "PGAPI_PutData"; - StatementClass *stmt = (StatementClass *) hstmt; - APDFields *opts; - int old_pos, - retval; - ParameterInfoClass *current_param; - char *buffer; - - mylog("%s: entering...\n", func); - - if (!stmt) - { - SC_log_error(func, "", NULL); - return SQL_INVALID_HANDLE; - } - - opts = SC_get_APD(stmt); - if (stmt->current_exec_param < 0) - { - stmt->errornumber = STMT_SEQUENCE_ERROR; - stmt->errormsg = "Previous call was not SQLPutData or SQLParamData"; - SC_log_error(func, "", stmt); - return SQL_ERROR; - } - - current_param = &(opts->parameters[stmt->current_exec_param]); - - if (!stmt->put_data) - { /* first call */ - mylog("PGAPI_PutData: (1) cbValue = %d\n", cbValue); - - stmt->put_data = TRUE; - - current_param->EXEC_used = (SDWORD *) malloc(sizeof(SDWORD)); - if (!current_param->EXEC_used) - { - stmt->errornumber = STMT_NO_MEMORY_ERROR; - stmt->errormsg = "Out of memory in PGAPI_PutData (1)"; - SC_log_error(func, "", stmt); - return SQL_ERROR; - } - - *current_param->EXEC_used = cbValue; - - if (cbValue == SQL_NULL_DATA) - return SQL_SUCCESS; - - /* Handle Long Var Binary with Large Objects */ - if (current_param->SQLType == SQL_LONGVARBINARY) - { - /* begin transaction if needed */ - if (!CC_is_in_trans(stmt->hdbc)) - { - if (!CC_begin(stmt->hdbc)) - { - stmt->errormsg = "Could not begin (in-line) a transaction"; - stmt->errornumber = STMT_EXEC_ERROR; - SC_log_error(func, "", stmt); - return SQL_ERROR; - } - } - - /* store the oid */ - current_param->lobj_oid = lo_creat(stmt->hdbc, INV_READ | INV_WRITE); - if (current_param->lobj_oid == 0) - { - stmt->errornumber = STMT_EXEC_ERROR; - stmt->errormsg = "Couldnt create large object."; - SC_log_error(func, "", stmt); - return SQL_ERROR; - } - - /* - * major hack -- to allow convert to see somethings there have - * to modify convert to handle this better - */ - current_param->EXEC_buffer = (char *) ¤t_param->lobj_oid; - - /* store the fd */ - stmt->lobj_fd = lo_open(stmt->hdbc, current_param->lobj_oid, INV_WRITE); - if (stmt->lobj_fd < 0) - { - stmt->errornumber = STMT_EXEC_ERROR; - stmt->errormsg = "Couldnt open large object for writing."; - SC_log_error(func, "", stmt); - return SQL_ERROR; - } - - retval = lo_write(stmt->hdbc, stmt->lobj_fd, rgbValue, cbValue); - mylog("lo_write: cbValue=%d, wrote %d bytes\n", cbValue, retval); - } - else - { - Int2 ctype = current_param->CType; - if (ctype == SQL_C_DEFAULT) - ctype = sqltype_to_default_ctype(current_param->SQLType); - -#ifdef UNICODE_SUPPORT - if (SQL_NTS == cbValue && SQL_C_WCHAR == ctype) - cbValue = 2 * ucs2strlen((SQLWCHAR *) rgbValue); -#endif /* UNICODE_SUPPORT */ - /* for handling fields */ - if (cbValue == SQL_NTS) - { - current_param->EXEC_buffer = strdup(rgbValue); - if (!current_param->EXEC_buffer) - { - stmt->errornumber = STMT_NO_MEMORY_ERROR; - stmt->errormsg = "Out of memory in PGAPI_PutData (2)"; - SC_log_error(func, "", stmt); - return SQL_ERROR; - } - } - else - { -#ifdef UNICODE_SUPPORT - if (ctype == SQL_C_CHAR || ctype == SQL_C_BINARY || ctype == SQL_C_WCHAR) -#else - if (ctype == SQL_C_CHAR || ctype == SQL_C_BINARY) -#endif /* UNICODE_SUPPORT */ - { - current_param->EXEC_buffer = malloc(cbValue + 1); - if (!current_param->EXEC_buffer) - { - stmt->errornumber = STMT_NO_MEMORY_ERROR; - stmt->errormsg = "Out of memory in PGAPI_PutData (2)"; - SC_log_error(func, "", stmt); - return SQL_ERROR; - } - memcpy(current_param->EXEC_buffer, rgbValue, cbValue); - current_param->EXEC_buffer[cbValue] = '\0'; - } - else - { - Int4 used = ctype_length(ctype); - - current_param->EXEC_buffer = malloc(used); - if (!current_param->EXEC_buffer) - { - stmt->errornumber = STMT_NO_MEMORY_ERROR; - stmt->errormsg = "Out of memory in PGAPI_PutData (2)"; - SC_log_error(func, "", stmt); - return SQL_ERROR; - } - memcpy(current_param->EXEC_buffer, rgbValue, used); - } - } - } - } - else - { - /* calling SQLPutData more than once */ - mylog("PGAPI_PutData: (>1) cbValue = %d\n", cbValue); - - if (current_param->SQLType == SQL_LONGVARBINARY) - { - /* the large object fd is in EXEC_buffer */ - retval = lo_write(stmt->hdbc, stmt->lobj_fd, rgbValue, cbValue); - mylog("lo_write(2): cbValue = %d, wrote %d bytes\n", cbValue, retval); - - *current_param->EXEC_used += cbValue; - } - else - { - Int2 ctype = current_param->CType; - - if (ctype == SQL_C_DEFAULT) - ctype = sqltype_to_default_ctype(current_param->SQLType); - buffer = current_param->EXEC_buffer; - if (old_pos = *current_param->EXEC_used, SQL_NTS == old_pos) - { -#ifdef UNICODE_SUPPORT - if (SQL_C_WCHAR == ctype) - old_pos = 2 * ucs2strlen((SQLWCHAR *) buffer); - else -#endif /* UNICODE_SUPPORT */ - old_pos = strlen(buffer); - } - if (SQL_NTS == cbValue) - { -#ifdef UNICODE_SUPPORT - if (SQL_C_WCHAR == ctype) - cbValue = 2 * ucs2strlen((SQLWCHAR *) rgbValue); - else -#endif /* UNICODE_SUPPORT */ - cbValue = strlen(rgbValue); - } - if (cbValue > 0) - { - *current_param->EXEC_used += cbValue; - - mylog(" cbValue = %d, old_pos = %d, *used = %d\n", cbValue, old_pos, *current_param->EXEC_used); - - /* dont lose the old pointer in case out of memory */ - buffer = realloc(current_param->EXEC_buffer, *current_param->EXEC_used + 1); - if (!buffer) - { - stmt->errornumber = STMT_NO_MEMORY_ERROR; - stmt->errormsg = "Out of memory in PGAPI_PutData (3)"; - SC_log_error(func, "", stmt); - return SQL_ERROR; - } - - memcpy(&buffer[old_pos], rgbValue, cbValue); - buffer[*current_param->EXEC_used] = '\0'; - - /* reassign buffer incase realloc moved it */ - current_param->EXEC_buffer = buffer; - } - else - { - SC_log_error(func, "bad cbValue", stmt); - return SQL_ERROR; - } - } - } - - return SQL_SUCCESS; -} diff --git a/src/interfaces/odbc/gpps.c b/src/interfaces/odbc/gpps.c deleted file mode 100644 index ee73a23eb4e..00000000000 --- a/src/interfaces/odbc/gpps.c +++ /dev/null @@ -1,454 +0,0 @@ -/*------- - * GetPrivateProfileString() - * - * approximate implementation of - * Windows NT System Services version of GetPrivateProfileString() - * probably doesn't handle the NULL key for section name or value key - * correctly also, doesn't provide Microsoft backwards compatability - * wrt TAB characters in the value string - * - * Microsoft terminates value - * at the first TAB, but I couldn't discover what the behavior should - * be regarding TABS in quoted strings so, I treat tabs like any other - * characters - * - * NO comments following value string separated by a TAB - * are allowed (that is an anachronism anyway) - * Added code to search for ODBC_INI file in users home directory on - * Unix - *------- - */ - -#if !defined(WIN32) && !defined(WITH_UNIXODBC) && !defined(WITH_IODBC) - -#include "gpps.h" - -#include <stdio.h> -#include <unistd.h> -#include <ctype.h> - -#if HAVE_PWD_H -#include <pwd.h> -#endif - -#include <sys/types.h> -#include <string.h> -#include "misc.h" -#include "dlg_specific.h" - -#ifndef TRUE -#define TRUE ((BOOL)1) -#endif -#ifndef FALSE -#define FALSE ((BOOL)0) -#endif - -#ifndef ODBCINSTDIR -#error "ODBCINSTDIR must be defined to compile this file" -#endif - - -/* - * theIniFileName is searched for in: - * $HOME/theIniFileName - * theIniFileName - * ODBCINSTDIR/ODBCINST_INI - */ -DWORD -GetPrivateProfileString(const char *theSection, /* section name */ - const char *theKey, /* search key name */ - const char *theDefault, /* default value if not - * found */ - char *theReturnBuffer, /* return value stored - * here */ - size_t theReturnBufferLength, /* byte length of return - * buffer */ - const char *theIniFileName) /* pathname of ini file - * to search */ -{ - char buf[MAXPGPATH]; - char *ptr = 0; - FILE *aFile = 0; - size_t aLength; - char aLine[2048]; - char *aValue; - char *aStart; - char *aString; - size_t aLineLength; - size_t aReturnLength = 0; - BOOL aSectionFound = FALSE; - BOOL aKeyFound = FALSE; - - ptr = (char *) getpwuid(getuid()); /* get user info */ - - if (ptr == NULL || (((struct passwd *) ptr)->pw_dir) == NULL || *(((struct passwd *) ptr)->pw_dir) == '\0') - ptr = "/home"; - else - ptr = ((struct passwd *) ptr)->pw_dir; /* get user home dir */ - - /* - * If it can't be opened because the paths are too long, then skip it, - * don't just truncate the path string... The truncated path might - * accidently be an existing file. The default value will be returned - * instead. - */ - if (MAXPGPATH - 1 >= strlen(ptr) + 1 + strlen(theIniFileName)) - { - sprintf(buf, "%s/%s", ptr, theIniFileName); - aFile = (FILE *) fopen(buf, PG_BINARY_R); - } - - /* - * This code makes it so that a file in the users home dir overrides a - * the "default" file as passed in - */ - if (!aFile) - { - aFile = (FILE *) fopen(theIniFileName, PG_BINARY_R); - if (!aFile) - aFile = (FILE *) fopen(ODBCINSTDIR "/" ODBCINST_INI, PG_BINARY_R); - } - - aLength = (theDefault == NULL) ? 0 : strlen(theDefault); - - if (theReturnBufferLength == 0 || theReturnBuffer == NULL) - { - if (aFile) - fclose(aFile); - return 0; - } - - if (aFile == NULL) - { - /* no ini file specified, return the default */ - ++aLength; /* room for NULL char */ - aLength = theReturnBufferLength < aLength ? - theReturnBufferLength : aLength; - strncpy(theReturnBuffer, theDefault, aLength); - theReturnBuffer[aLength - 1] = '\0'; - return aLength - 1; - } - - while (fgets(aLine, sizeof(aLine), aFile) != NULL) - { - aLineLength = strlen(aLine); - /* strip final '\n' */ - if (aLineLength > 0 && aLine[aLineLength - 1] == '\n') - aLine[aLineLength - 1] = '\0'; - switch (*aLine) - { - case ' ': /* blank line */ - case ';': /* comment line */ - continue; - break; - - case '[': /* section marker */ - if ((aString = strchr(aLine, ']'))) - { - aStart = aLine + 1; - aString--; - while (isspace((unsigned char) *aStart)) - aStart++; - while (isspace((unsigned char) *aString)) - aString--; - *(aString + 1) = '\0'; - - /* accept as matched if NULL key or exact match */ - if (!theSection || !strcmp(aStart, theSection)) - aSectionFound = TRUE; - else - aSectionFound = FALSE; - } - break; - - default: - - /* try to match value keys if in proper section */ - if (aSectionFound) - { - /* try to match requested key */ - if ((aString = aValue = strchr(aLine, '='))) - { - *aValue = '\0'; - ++aValue; - - /* strip leading blanks in value field */ - while (*aValue == ' ' && aValue < aLine + sizeof(aLine)) - *aValue++ = '\0'; - if (aValue >= aLine + sizeof(aLine)) - aValue = ""; - } - else - aValue = ""; - - aStart = aLine; - while (isspace((unsigned char) *aStart)) - aStart++; - - /* strip trailing blanks from key */ - if (aString) - { - while (--aString >= aStart && *aString == ' ') - *aString = '\0'; - } - - /* see if key is matched */ - if (theKey == NULL || !strcmp(theKey, aStart)) - { - /* matched -- first, terminate value part */ - aKeyFound = TRUE; - aLength = strlen(aValue); - - /* remove trailing blanks from aValue if any */ - aString = aValue + aLength - 1; - - while (--aString > aValue && *aString == ' ') - { - *aString = '\0'; - --aLength; - } - - /* unquote value if quoted */ - if (aLength >= 2 && aValue[0] == '"' && - aValue[aLength - 1] == '"') - { - /* string quoted with double quotes */ - - aValue[aLength - 1] = '\0'; - ++aValue; - aLength -= 2; - } - else - { - /* single quotes allowed also... */ - if (aLength >= 2 && aValue[0] == '\'' && - aValue[aLength - 1] == '\'') - { - aValue[aLength - 1] = '\0'; - ++aValue; - aLength -= 2; - } - } - - /* compute maximum length copyable */ - aLineLength = (aLength < - theReturnBufferLength - aReturnLength) ? aLength : - theReturnBufferLength - aReturnLength; - - /* do the copy to return buffer */ - if (aLineLength) - { - strncpy(&theReturnBuffer[aReturnLength], - aValue, aLineLength); - aReturnLength += aLineLength; - if (aReturnLength < theReturnBufferLength) - { - theReturnBuffer[aReturnLength] = '\0'; - ++aReturnLength; - } - } - if (aFile) - { - fclose(aFile); - aFile = NULL; - } - return aReturnLength > 0 ? aReturnLength - 1 : 0; - } - } - break; - } - } - - if (aFile) - fclose(aFile); - - if (!aKeyFound) - { - /* key wasn't found return default */ - ++aLength; /* room for NULL char */ - aLength = theReturnBufferLength < aLength ? - theReturnBufferLength : aLength; - strncpy(theReturnBuffer, theDefault, aLength); - theReturnBuffer[aLength - 1] = '\0'; - aReturnLength = aLength - 1; - } - return aReturnLength > 0 ? aReturnLength - 1 : 0; -} - - -DWORD -WritePrivateProfileString(const char *theSection, /* section name */ - const char *theKey, /* write key name */ - const char *theBuffer, /* input buffer */ - const char *theIniFileName) /* pathname of ini file - * to write */ -{ - return 0; -} - - -#if NOT_USED -/* - * Ok. What the hell's the default behaviour for a null input buffer, and null - * section name. For now if either are null I ignore the request, until - * I find out different. - */ -DWORD -WritePrivateProfileString(char *theSection, /* section name */ - char *theKey, /* write key name */ - char *theBuffer, /* input buffer */ - char *theIniFileName) /* pathname of ini file to - * write */ -{ - char buf[MAXPGPATH]; - char *ptr = 0; - FILE *aFile = 0; - size_t aLength; - char aLine[2048]; - char *aValue; - char *aString; - size_t aLineLength; - size_t aReturnLength = 0; - - BOOL aSectionFound = FALSE; - BOOL keyFound = FALSE; - int j = 0; - - /* If this isn't correct processing we'll change it later */ - if (theSection == NULL || theKey == NULL || theBuffer == NULL || - theIniFileName == NULL) - return 0; - - aLength = strlen(theBuffer); - if (aLength == 0) - return 0; - - j = strlen(theIniFileName) + 1; - ptr = (char *) getpwuid(getuid()); /* get user info */ - - if (ptr == NULL) - { - if (MAXPGPATH - 1 < j) - theIniFileName[MAXPGPATH - 1] = '\0'; - - sprintf(buf, "%s", theIniFileName); - } - ptr = ((struct passwd *) ptr)->pw_dir; /* get user home dir */ - if (ptr == NULL || *ptr == '\0') - ptr = "/home"; - - /* - * This doesn't make it so we find an ini file but allows normal - * processing to continue further on down. The likelihood is that the - * file won't be found and thus the default value will be returned. - */ - if (MAXPGPATH - 1 < strlen(ptr) + j) - { - if (MAXPGPATH - 1 < strlen(ptr)) - ptr[MAXPGPATH - 1] = '\0'; - else - theIniFileName[MAXPGPATH - 1 - strlen(ptr)] = '\0'; - } - - sprintf(buf, "%s/%s", ptr, theIniFileName); - - /* - * This code makes it so that a file in the users home dir overrides a - * the "default" file as passed in - */ - aFile = (FILE *) (buf ? fopen(buf, "r+") : NULL); - if (!aFile) - { - sprintf(buf, "%s", theIniFileName); - aFile = (FILE *) (buf ? fopen(buf, "r+") : NULL); - if (!aFile) - return 0; - } - - aLength = strlen(theBuffer); - - /* - * We have to search for theKey, because if it already exists we have - * to overwrite it. If it doesn't exist we just write a new line to - * the file. - */ - while (fgets(aLine, sizeof(aLine), aFile) != NULL) - { - aLineLength = strlen(aLine); - /* strip final '\n' */ - if (aLineLength > 0 && aLine[aLineLength - 1] == '\n') - aLine[aLineLength - 1] = '\0'; - switch (*aLine) - { - case ' ': /* blank line */ - case ';': /* comment line */ - continue; - break; - - case '[': /* section marker */ - if ((aString = strchr(aLine, ']'))) - { - *aString = '\0'; - - /* accept as matched if key exact match */ - - if (!strcmp(aLine + 1, theSection)) - aSectionFound = TRUE; - } - break; - - default: - /* try to match value keys if in proper section */ - if (aSectionFound) - { - /* try to match requested key */ - - if ((aString = aValue = strchr(aLine, '='))) - { - *aValue = '\0'; - ++aValue; - - /* strip leading blanks in value field */ - while (*aValue == ' ' && aValue < aLine + sizeof(aLine)) - *aValue++ = '\0'; - if (aValue >= aLine + sizeof(aLine)) - aValue = ""; - } - else - aValue = ""; - - /* strip trailing blanks from key */ - if (aString) - { - while (--aString >= aLine && *aString == ' ') - *aString = '\0'; - } - - /* see if key is matched */ - if (!strcmp(theKey, aLine)) - { - keyFound = TRUE; - /* matched -- first, terminate value part */ - - /* overwrite current value */ - fseek(aFile, -aLineLength, SEEK_CUR); - /* overwrite key and value */ - sprintf(aLine, "%s = %s\n", theKey, theBuffer); - fputs(aLine, aFile); - } - } - } - break; - } -} - -if (!keyFound) -{ /* theKey wasn't in file so */ - if (aFile) - fclose(aFile); - - return aReturnLength > 0 ? aReturnLength - 1 : 0; -} -#endif /* NOT_USED */ - -#endif /* not WIN32 */ diff --git a/src/interfaces/odbc/gpps.h b/src/interfaces/odbc/gpps.h deleted file mode 100644 index ab133a82d4c..00000000000 --- a/src/interfaces/odbc/gpps.h +++ /dev/null @@ -1,48 +0,0 @@ -/* GetPrivateProfileString - * for UNIX use - */ -#ifndef GPPS_H -#define GPPS_H - -#include "psqlodbc.h" - -#ifndef WIN32 -#include <sys/types.h> -#endif - -#define SQLGetPrivateProfileString(a,b,c,d,e,f) GetPrivateProfileString(a,b,c,d,e,f) -#define SQLWritePrivateProfileString(a,b,c,d) WritePrivateProfileString(a,b,c,d) - -#ifdef __cplusplus -extern "C" -{ -#endif - -DWORD -GetPrivateProfileString(const char *theSection, /* section name */ - const char *theKey, /* search key name */ - const char *theDefault, /* default value if not - * found */ - char *theReturnBuffer, /* return valuse stored - * here */ - size_t theBufferLength, /* byte length of return - * buffer */ - const char *theIniFileName); /* pathname of ini file - * to search */ - -DWORD -WritePrivateProfileString(const char *theSection, /* section name */ - const char *theKey, /* write key name */ - const char *theBuffer, /* input buffer */ - const char *theIniFileName); /* pathname of ini file - * to write */ - -#ifdef __cplusplus -} -#endif - -#ifndef WIN32 -#undef DWORD -#endif - -#endif diff --git a/src/interfaces/odbc/info.c b/src/interfaces/odbc/info.c deleted file mode 100644 index 3a3cda32ce4..00000000000 --- a/src/interfaces/odbc/info.c +++ /dev/null @@ -1,4509 +0,0 @@ -/*-------- - * Module: info.c - * - * Description: This module contains routines related to - * ODBC informational functions. - * - * Classes: n/a - * - * API functions: SQLGetInfo, SQLGetTypeInfo, SQLGetFunctions, - * SQLTables, SQLColumns, SQLStatistics, SQLSpecialColumns, - * SQLPrimaryKeys, SQLForeignKeys, - * SQLProcedureColumns(NI), SQLProcedures, - * SQLTablePrivileges, SQLColumnPrivileges(NI) - * - * Comments: See "notice.txt" for copyright and license information. - *-------- - */ - -#include "psqlodbc.h" - -#include <string.h> -#include <stdio.h> - -#ifndef WIN32 -#include <ctype.h> -#endif - -#include "tuple.h" -#include "pgtypes.h" - -#include "environ.h" -#include "connection.h" -#include "statement.h" -#include "qresult.h" -#include "bind.h" -#include "misc.h" -#include "pgtypes.h" -#include "pgapifunc.h" -#ifdef MULTIBYTE -#include "multibyte.h" -#endif - - -/* Trigger related stuff for SQLForeign Keys */ -#define TRIGGER_SHIFT 3 -#define TRIGGER_MASK 0x03 -#define TRIGGER_DELETE 0x01 -#define TRIGGER_UPDATE 0x02 - - -/* extern GLOBAL_VALUES globals; */ - - - -RETCODE SQL_API -PGAPI_GetInfo( - HDBC hdbc, - UWORD fInfoType, - PTR rgbInfoValue, - SWORD cbInfoValueMax, - SWORD FAR * pcbInfoValue) -{ - static char *func = "PGAPI_GetInfo"; - ConnectionClass *conn = (ConnectionClass *) hdbc; - ConnInfo *ci; - char *p = NULL, - tmp[MAX_INFO_STRING]; - int len = 0, - value = 0; - RETCODE result; - - mylog("%s: entering...fInfoType=%d\n", func, fInfoType); - - if (!conn) - { - CC_log_error(func, "", NULL); - return SQL_INVALID_HANDLE; - } - - ci = &(conn->connInfo); - - switch (fInfoType) - { - case SQL_ACCESSIBLE_PROCEDURES: /* ODBC 1.0 */ - p = "N"; - break; - - case SQL_ACCESSIBLE_TABLES: /* ODBC 1.0 */ - p = "N"; - break; - - case SQL_ACTIVE_CONNECTIONS: /* ODBC 1.0 */ - len = 2; - value = MAX_CONNECTIONS; - break; - - case SQL_ACTIVE_STATEMENTS: /* ODBC 1.0 */ - len = 2; - value = 0; - break; - - case SQL_ALTER_TABLE: /* ODBC 2.0 */ - len = 4; - value = SQL_AT_ADD_COLUMN; - break; - - case SQL_BOOKMARK_PERSISTENCE: /* ODBC 2.0 */ - /* very simple bookmark support */ - len = 4; - value = ci->drivers.use_declarefetch ? 0 : (SQL_BP_SCROLL | SQL_BP_DELETE | SQL_BP_UPDATE | SQL_BP_TRANSACTION); - break; - - case SQL_COLUMN_ALIAS: /* ODBC 2.0 */ - p = "N"; - break; - - case SQL_CONCAT_NULL_BEHAVIOR: /* ODBC 1.0 */ - len = 2; - value = SQL_CB_NON_NULL; - break; - - case SQL_CONVERT_BIGINT: - case SQL_CONVERT_BINARY: - case SQL_CONVERT_BIT: - case SQL_CONVERT_CHAR: - case SQL_CONVERT_DATE: - case SQL_CONVERT_DECIMAL: - case SQL_CONVERT_DOUBLE: - case SQL_CONVERT_FLOAT: - case SQL_CONVERT_INTEGER: - case SQL_CONVERT_LONGVARBINARY: - case SQL_CONVERT_LONGVARCHAR: - case SQL_CONVERT_NUMERIC: - case SQL_CONVERT_REAL: - case SQL_CONVERT_SMALLINT: - case SQL_CONVERT_TIME: - case SQL_CONVERT_TIMESTAMP: - case SQL_CONVERT_TINYINT: - case SQL_CONVERT_VARBINARY: - case SQL_CONVERT_VARCHAR: /* ODBC 1.0 */ - len = 4; - value = fInfoType; - break; - - case SQL_CONVERT_FUNCTIONS: /* ODBC 1.0 */ - len = 4; - value = 0; - break; - - case SQL_CORRELATION_NAME: /* ODBC 1.0 */ - - /* - * Saying no correlation name makes Query not work right. - * value = SQL_CN_NONE; - */ - len = 2; - value = SQL_CN_ANY; - break; - - case SQL_CURSOR_COMMIT_BEHAVIOR: /* ODBC 1.0 */ - len = 2; - value = SQL_CB_CLOSE; - if (ci->updatable_cursors) - if (!ci->drivers.use_declarefetch) - value = SQL_CB_PRESERVE; - break; - - case SQL_CURSOR_ROLLBACK_BEHAVIOR: /* ODBC 1.0 */ - len = 2; - value = SQL_CB_CLOSE; - if (ci->updatable_cursors) - if (!ci->drivers.use_declarefetch) - value = SQL_CB_PRESERVE; - break; - - case SQL_DATA_SOURCE_NAME: /* ODBC 1.0 */ - p = CC_get_DSN(conn); - break; - - case SQL_DATA_SOURCE_READ_ONLY: /* ODBC 1.0 */ - p = CC_is_onlyread(conn) ? "Y" : "N"; - break; - - case SQL_DATABASE_NAME: /* Support for old ODBC 1.0 Apps */ - - /* - * Returning the database name causes problems in MS Query. It - * generates query like: "SELECT DISTINCT a FROM byronnbad3 - * bad3" - * - * p = CC_get_database(conn); - */ - p = ""; - break; - - case SQL_DBMS_NAME: /* ODBC 1.0 */ - p = DBMS_NAME; - break; - - case SQL_DBMS_VER: /* ODBC 1.0 */ - - /* - * The ODBC spec wants ##.##.#### ...whatever... so prepend - * the driver - */ - /* version number to the dbms version string */ - sprintf(tmp, "%s %s", POSTGRESDRIVERVERSION, conn->pg_version); - p = tmp; - break; - - case SQL_DEFAULT_TXN_ISOLATION: /* ODBC 1.0 */ - len = 4; - if (PG_VERSION_LT(conn, 6.5)) - value = SQL_TXN_SERIALIZABLE; - else - value = SQL_TXN_READ_COMMITTED; - break; - - case SQL_DRIVER_NAME: /* ODBC 1.0 */ - p = DRIVER_FILE_NAME; - break; - - case SQL_DRIVER_ODBC_VER: - p = DRIVER_ODBC_VER; - break; - - case SQL_DRIVER_VER: /* ODBC 1.0 */ - p = POSTGRESDRIVERVERSION; - break; - - case SQL_EXPRESSIONS_IN_ORDERBY: /* ODBC 1.0 */ - p = "N"; - break; - - case SQL_FETCH_DIRECTION: /* ODBC 1.0 */ - len = 4; - value = ci->drivers.use_declarefetch ? (SQL_FD_FETCH_NEXT) : - (SQL_FD_FETCH_NEXT | - SQL_FD_FETCH_FIRST | - SQL_FD_FETCH_LAST | - SQL_FD_FETCH_PRIOR | - SQL_FD_FETCH_ABSOLUTE | - SQL_FD_FETCH_RELATIVE | - SQL_FD_FETCH_BOOKMARK); - break; - - case SQL_FILE_USAGE: /* ODBC 2.0 */ - len = 2; - value = SQL_FILE_NOT_SUPPORTED; - break; - - case SQL_GETDATA_EXTENSIONS: /* ODBC 2.0 */ - len = 4; - value = (SQL_GD_ANY_COLUMN | SQL_GD_ANY_ORDER | SQL_GD_BOUND | SQL_GD_BLOCK); - break; - - case SQL_GROUP_BY: /* ODBC 2.0 */ - len = 2; - value = SQL_GB_GROUP_BY_EQUALS_SELECT; - break; - - case SQL_IDENTIFIER_CASE: /* ODBC 1.0 */ - - /* - * are identifiers case-sensitive (yes, but only when quoted. - * If not quoted, they default to lowercase) - */ - len = 2; - value = SQL_IC_LOWER; - break; - - case SQL_IDENTIFIER_QUOTE_CHAR: /* ODBC 1.0 */ - /* the character used to quote "identifiers" */ - p = PG_VERSION_LE(conn, 6.2) ? " " : "\""; - break; - - case SQL_KEYWORDS: /* ODBC 2.0 */ - p = ""; - break; - - case SQL_LIKE_ESCAPE_CLAUSE: /* ODBC 2.0 */ - - /* - * is there a character that escapes '%' and '_' in a LIKE - * clause? not as far as I can tell - */ - p = "N"; - break; - - case SQL_LOCK_TYPES: /* ODBC 2.0 */ - len = 4; - value = ci->drivers.lie ? (SQL_LCK_NO_CHANGE | SQL_LCK_EXCLUSIVE | SQL_LCK_UNLOCK) : SQL_LCK_NO_CHANGE; - break; - - case SQL_MAX_BINARY_LITERAL_LEN: /* ODBC 2.0 */ - len = 4; - value = 0; - break; - - case SQL_MAX_CHAR_LITERAL_LEN: /* ODBC 2.0 */ - len = 4; - value = 0; - break; - - case SQL_MAX_COLUMN_NAME_LEN: /* ODBC 1.0 */ - len = 2; - value = MAX_COLUMN_LEN; - break; - - case SQL_MAX_COLUMNS_IN_GROUP_BY: /* ODBC 2.0 */ - len = 2; - value = 0; - break; - - case SQL_MAX_COLUMNS_IN_INDEX: /* ODBC 2.0 */ - len = 2; - value = 0; - break; - - case SQL_MAX_COLUMNS_IN_ORDER_BY: /* ODBC 2.0 */ - len = 2; - value = 0; - break; - - case SQL_MAX_COLUMNS_IN_SELECT: /* ODBC 2.0 */ - len = 2; - value = 0; - break; - - case SQL_MAX_COLUMNS_IN_TABLE: /* ODBC 2.0 */ - len = 2; - value = 0; - break; - - case SQL_MAX_CURSOR_NAME_LEN: /* ODBC 1.0 */ - len = 2; - value = MAX_CURSOR_LEN; - break; - - case SQL_MAX_INDEX_SIZE: /* ODBC 2.0 */ - len = 4; - value = 0; - break; - - case SQL_MAX_OWNER_NAME_LEN: /* ODBC 1.0 */ - len = 2; - value = 0; - if (conn->schema_support) - value = MAX_SCHEMA_LEN; - break; - - case SQL_MAX_PROCEDURE_NAME_LEN: /* ODBC 1.0 */ - len = 2; - value = 0; - break; - - case SQL_MAX_QUALIFIER_NAME_LEN: /* ODBC 1.0 */ - len = 2; - value = 0; - break; - - case SQL_MAX_ROW_SIZE: /* ODBC 2.0 */ - len = 4; - if (PG_VERSION_GE(conn, 7.1)) - { - /* Large Rowa in 7.1+ */ - value = MAX_ROW_SIZE; - } - else - { - /* Without the Toaster we're limited to the blocksize */ - value = BLCKSZ; - } - break; - - case SQL_MAX_ROW_SIZE_INCLUDES_LONG: /* ODBC 2.0 */ - - /* - * does the preceding value include LONGVARCHAR and - * LONGVARBINARY fields? Well, it does include longvarchar, - * but not longvarbinary. - */ - p = "Y"; - break; - - case SQL_MAX_STATEMENT_LEN: /* ODBC 2.0 */ - /* maybe this should be 0? */ - len = 4; - value = CC_get_max_query_len(conn); - break; - - case SQL_MAX_TABLE_NAME_LEN: /* ODBC 1.0 */ - len = 2; - value = MAX_TABLE_LEN; - break; - - case SQL_MAX_TABLES_IN_SELECT: /* ODBC 2.0 */ - len = 2; - value = 0; - break; - - case SQL_MAX_USER_NAME_LEN: - len = 2; - value = 0; - break; - - case SQL_MULT_RESULT_SETS: /* ODBC 1.0 */ - /* Don't support multiple result sets but say yes anyway? */ - p = "Y"; - break; - - case SQL_MULTIPLE_ACTIVE_TXN: /* ODBC 1.0 */ - p = "Y"; - break; - - case SQL_NEED_LONG_DATA_LEN: /* ODBC 2.0 */ - - /* - * Don't need the length, SQLPutData can handle any size and - * multiple calls - */ - p = "N"; - break; - - case SQL_NON_NULLABLE_COLUMNS: /* ODBC 1.0 */ - len = 2; - value = SQL_NNC_NON_NULL; - break; - - case SQL_NULL_COLLATION: /* ODBC 2.0 */ - /* where are nulls sorted? */ - len = 2; - value = SQL_NC_END; - break; - - case SQL_NUMERIC_FUNCTIONS: /* ODBC 1.0 */ - len = 4; - value = 0; - break; - - case SQL_ODBC_API_CONFORMANCE: /* ODBC 1.0 */ - len = 2; - value = SQL_OAC_LEVEL1; - break; - - case SQL_ODBC_SAG_CLI_CONFORMANCE: /* ODBC 1.0 */ - len = 2; - value = SQL_OSCC_NOT_COMPLIANT; - break; - - case SQL_ODBC_SQL_CONFORMANCE: /* ODBC 1.0 */ - len = 2; - value = SQL_OSC_CORE; - break; - - case SQL_ODBC_SQL_OPT_IEF: /* ODBC 1.0 */ - p = "N"; - break; - - case SQL_OJ_CAPABILITIES: /* ODBC 2.01 */ - len = 4; - if (PG_VERSION_GE(conn, 7.1)) - { - /* OJs in 7.1+ */ - value = (SQL_OJ_LEFT | - SQL_OJ_RIGHT | - SQL_OJ_FULL | - SQL_OJ_NESTED | - SQL_OJ_NOT_ORDERED | - SQL_OJ_INNER | - SQL_OJ_ALL_COMPARISON_OPS); - } - else - /* OJs not in <7.1 */ - value = 0; - break; - - case SQL_ORDER_BY_COLUMNS_IN_SELECT: /* ODBC 2.0 */ - p = (PG_VERSION_LE(conn, 6.3)) ? "Y" : "N"; - break; - - case SQL_OUTER_JOINS: /* ODBC 1.0 */ - if (PG_VERSION_GE(conn, 7.1)) - /* OJs in 7.1+ */ - p = "Y"; - else - /* OJs not in <7.1 */ - p = "N"; - break; - - case SQL_OWNER_TERM: /* ODBC 1.0 */ - if (conn->schema_support) - p = "schema"; - else - p = "owner"; - break; - - case SQL_OWNER_USAGE: /* ODBC 2.0 */ - len = 4; - value = 0; - if (conn->schema_support) - value = SQL_OU_DML_STATEMENTS - | SQL_OU_TABLE_DEFINITION - | SQL_OU_INDEX_DEFINITION - | SQL_OU_PRIVILEGE_DEFINITION - ; - break; - - case SQL_POS_OPERATIONS: /* ODBC 2.0 */ - len = 4; - value = (SQL_POS_POSITION | SQL_POS_REFRESH); -#ifdef DRIVER_CURSOR_IMPLEMENT - if (ci->updatable_cursors) - value |= (SQL_POS_UPDATE | SQL_POS_DELETE | SQL_POS_ADD); -#endif /* DRIVER_CURSOR_IMPLEMENT */ - break; - - case SQL_POSITIONED_STATEMENTS: /* ODBC 2.0 */ - len = 4; - value = ci->drivers.lie ? (SQL_PS_POSITIONED_DELETE | - SQL_PS_POSITIONED_UPDATE | - SQL_PS_SELECT_FOR_UPDATE) : 0; - break; - - case SQL_PROCEDURE_TERM: /* ODBC 1.0 */ - p = "procedure"; - break; - - case SQL_PROCEDURES: /* ODBC 1.0 */ - p = "Y"; - break; - - case SQL_QUALIFIER_LOCATION: /* ODBC 2.0 */ - len = 2; - value = SQL_QL_START; - break; - - case SQL_QUALIFIER_NAME_SEPARATOR: /* ODBC 1.0 */ - p = ""; - break; - - case SQL_QUALIFIER_TERM: /* ODBC 1.0 */ - p = ""; - break; - - case SQL_QUALIFIER_USAGE: /* ODBC 2.0 */ - len = 4; - value = 0; - break; - - case SQL_QUOTED_IDENTIFIER_CASE: /* ODBC 2.0 */ - /* are "quoted" identifiers case-sensitive? YES! */ - len = 2; - value = SQL_IC_SENSITIVE; - break; - - case SQL_ROW_UPDATES: /* ODBC 1.0 */ - - /* - * Driver doesn't support keyset-driven or mixed cursors, so - * not much point in saying row updates are supported - */ - p = (ci->updatable_cursors) ? "Y" : "N"; - break; - - case SQL_SCROLL_CONCURRENCY: /* ODBC 1.0 */ - len = 4; - value = SQL_SCCO_READ_ONLY; -#ifdef DRIVER_CURSOR_IMPLEMENT - if (ci->updatable_cursors) - value |= SQL_SCCO_OPT_ROWVER; -#endif /* DRIVER_CURSOR_IMPLEMENT */ - if (ci->drivers.lie) - value |= (SQL_SCCO_LOCK | SQL_SCCO_OPT_VALUES); - break; - - case SQL_SCROLL_OPTIONS: /* ODBC 1.0 */ - len = 4; - value = SQL_SO_FORWARD_ONLY; - if (!ci->drivers.use_declarefetch) - value |= SQL_SO_STATIC; - if (ci->updatable_cursors) - value |= SQL_SO_KEYSET_DRIVEN; - if (ci->drivers.lie) - value |= (SQL_SO_DYNAMIC | SQL_SO_MIXED); - break; - - case SQL_SEARCH_PATTERN_ESCAPE: /* ODBC 1.0 */ - if (PG_VERSION_GE(conn, 6.5)) - p = "\\"; - else - p = ""; - break; - - case SQL_SERVER_NAME: /* ODBC 1.0 */ - p = CC_get_server(conn); - break; - - case SQL_SPECIAL_CHARACTERS: /* ODBC 2.0 */ - p = "_"; - break; - - case SQL_STATIC_SENSITIVITY: /* ODBC 2.0 */ - len = 4; - value = 0; -#ifdef DRIVER_CURSOR_IMPLEMENT - if (ci->updatable_cursors) - value |= (SQL_SS_ADDITIONS | SQL_SS_DELETIONS | SQL_SS_UPDATES); -#endif /* DRIVER_CURSOR_IMPLEMENT */ - break; - - case SQL_STRING_FUNCTIONS: /* ODBC 1.0 */ - len = 4; - value = (SQL_FN_STR_CONCAT | - SQL_FN_STR_LCASE | - SQL_FN_STR_LENGTH | - SQL_FN_STR_LOCATE | - SQL_FN_STR_LTRIM | - SQL_FN_STR_RTRIM | - SQL_FN_STR_SUBSTRING | - SQL_FN_STR_UCASE); - break; - - case SQL_SUBQUERIES: /* ODBC 2.0 */ - /* postgres 6.3 supports subqueries */ - len = 4; - value = (SQL_SQ_QUANTIFIED | - SQL_SQ_IN | - SQL_SQ_EXISTS | - SQL_SQ_COMPARISON); - break; - - case SQL_SYSTEM_FUNCTIONS: /* ODBC 1.0 */ - len = 4; - value = 0; - break; - - case SQL_TABLE_TERM: /* ODBC 1.0 */ - p = "table"; - break; - - case SQL_TIMEDATE_ADD_INTERVALS: /* ODBC 2.0 */ - len = 4; - value = 0; - break; - - case SQL_TIMEDATE_DIFF_INTERVALS: /* ODBC 2.0 */ - len = 4; - value = 0; - break; - - case SQL_TIMEDATE_FUNCTIONS: /* ODBC 1.0 */ - len = 4; - value = (SQL_FN_TD_NOW); - break; - - case SQL_TXN_CAPABLE: /* ODBC 1.0 */ - - /* - * Postgres can deal with create or drop table statements in a - * transaction - */ - len = 2; - value = SQL_TC_ALL; - break; - - case SQL_TXN_ISOLATION_OPTION: /* ODBC 1.0 */ - len = 4; - if (PG_VERSION_LT(conn, 6.5)) - value = SQL_TXN_SERIALIZABLE; - else if (PG_VERSION_GE(conn, 7.1)) - value = SQL_TXN_READ_COMMITTED | SQL_TXN_SERIALIZABLE; - else - value = SQL_TXN_READ_COMMITTED; - break; - - case SQL_UNION: /* ODBC 2.0 */ - /* unions with all supported in postgres 6.3 */ - len = 4; - value = (SQL_U_UNION | SQL_U_UNION_ALL); - break; - - case SQL_USER_NAME: /* ODBC 1.0 */ - p = CC_get_username(conn); - break; - - default: - /* unrecognized key */ - conn->errormsg = "Unrecognized key passed to PGAPI_GetInfo."; - conn->errornumber = CONN_NOT_IMPLEMENTED_ERROR; - return SQL_ERROR; - } - - result = SQL_SUCCESS; - - mylog("%s: p='%s', len=%d, value=%d, cbMax=%d\n", func, p ? p : "<NULL>", len, value, cbInfoValueMax); - - /* - * NOTE, that if rgbInfoValue is NULL, then no warnings or errors - * should result and just pcbInfoValue is returned, which indicates - * what length would be required if a real buffer had been passed in. - */ - if (p) - { - /* char/binary data */ - len = strlen(p); - - if (rgbInfoValue) - { -#ifdef UNICODE_SUPPORT - if (conn->unicode) - { - len = utf8_to_ucs2(p, len, (SQLWCHAR *) rgbInfoValue, cbInfoValueMax / 2); - len *= 2; - } - else -#endif /* UNICODE_SUPPORT */ - strncpy_null((char *) rgbInfoValue, p, (size_t) cbInfoValueMax); - - if (len >= cbInfoValueMax) - { - result = SQL_SUCCESS_WITH_INFO; - conn->errornumber = CONN_TRUNCATED; - conn->errormsg = "The buffer was too small for tthe InfoValue."; - } - } - } - else - { - /* numeric data */ - if (rgbInfoValue) - { - if (len == 2) - *((WORD *) rgbInfoValue) = (WORD) value; - else if (len == 4) - *((DWORD *) rgbInfoValue) = (DWORD) value; - } - } - - if (pcbInfoValue) - *pcbInfoValue = len; - - return result; -} - - -RETCODE SQL_API -PGAPI_GetTypeInfo( - HSTMT hstmt, - SWORD fSqlType) -{ - static char *func = "PGAPI_GetTypeInfo"; - StatementClass *stmt = (StatementClass *) hstmt; - QResultClass *res; - TupleNode *row; - int i; - - /* Int4 type; */ - Int4 pgType; - Int2 sqlType; - - mylog("%s: entering...fSqlType = %d\n", func, fSqlType); - - if (!stmt) - { - SC_log_error(func, "", NULL); - return SQL_INVALID_HANDLE; - } - - stmt->manual_result = TRUE; - if (res = QR_Constructor(), !res) - { - SC_log_error(func, "Error creating result.", stmt); - return SQL_ERROR; - } - SC_set_Result(stmt, res); - -#if (ODBCVER >= 0x0399) - extend_column_bindings(SC_get_ARD(stmt), 19); -#else - extend_column_bindings(SC_get_ARD(stmt), 15); -#endif /* ODBCVER */ - - QR_set_num_fields(res, 15); - QR_set_field_info(res, 0, "TYPE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING); - QR_set_field_info(res, 1, "DATA_TYPE", PG_TYPE_INT2, 2); - QR_set_field_info(res, 2, "PRECISION", PG_TYPE_INT4, 4); - QR_set_field_info(res, 3, "LITERAL_PREFIX", PG_TYPE_TEXT, MAX_INFO_STRING); - QR_set_field_info(res, 4, "LITERAL_SUFFIX", PG_TYPE_TEXT, MAX_INFO_STRING); - QR_set_field_info(res, 5, "CREATE_PARAMS", PG_TYPE_TEXT, MAX_INFO_STRING); - QR_set_field_info(res, 6, "NULLABLE", PG_TYPE_INT2, 2); - QR_set_field_info(res, 7, "CASE_SENSITIVE", PG_TYPE_INT2, 2); - QR_set_field_info(res, 8, "SEARCHABLE", PG_TYPE_INT2, 2); - QR_set_field_info(res, 9, "UNSIGNED_ATTRIBUTE", PG_TYPE_INT2, 2); - QR_set_field_info(res, 10, "MONEY", PG_TYPE_INT2, 2); - QR_set_field_info(res, 11, "AUTO_INCREMENT", PG_TYPE_INT2, 2); - QR_set_field_info(res, 12, "LOCAL_TYPE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING); - QR_set_field_info(res, 13, "MINIMUM_SCALE", PG_TYPE_INT2, 2); - QR_set_field_info(res, 14, "MAXIMUM_SCALE", PG_TYPE_INT2, 2); -#if (ODBCVER >=0x0399) - QR_set_field_info(res, 15, "SQL_DATA_TYPE", PG_TYPE_INT2, 2); - QR_set_field_info(res, 16, "SQL_DATATIME_SUB", PG_TYPE_INT2, 2); - QR_set_field_info(res, 17, "NUM_PREC_RADIX", PG_TYPE_INT4, 4); - QR_set_field_info(res, 18, "INTERVAL_PRECISION", PG_TYPE_INT2, 2); -#endif /* ODBCVER */ - - for (i = 0, sqlType = sqlTypes[0]; sqlType; sqlType = sqlTypes[++i]) - { - pgType = sqltype_to_pgtype(stmt, sqlType); - - if (fSqlType == SQL_ALL_TYPES || fSqlType == sqlType) - { - row = (TupleNode *) malloc(sizeof(TupleNode) + (15 - 1) *sizeof(TupleField)); - - /* These values can't be NULL */ - set_tuplefield_string(&row->tuple[0], pgtype_to_name(stmt, pgType)); - set_tuplefield_int2(&row->tuple[1], (Int2) sqlType); - set_tuplefield_int2(&row->tuple[6], pgtype_nullable(stmt, pgType)); - set_tuplefield_int2(&row->tuple[7], pgtype_case_sensitive(stmt, pgType)); - set_tuplefield_int2(&row->tuple[8], pgtype_searchable(stmt, pgType)); - set_tuplefield_int2(&row->tuple[10], pgtype_money(stmt, pgType)); - - /* - * Localized data-source dependent data type name (always - * NULL) - */ - set_tuplefield_null(&row->tuple[12]); - - /* These values can be NULL */ - set_nullfield_int4(&row->tuple[2], pgtype_column_size(stmt, pgType, PG_STATIC, PG_STATIC)); - set_nullfield_string(&row->tuple[3], pgtype_literal_prefix(stmt, pgType)); - set_nullfield_string(&row->tuple[4], pgtype_literal_suffix(stmt, pgType)); - set_nullfield_string(&row->tuple[5], pgtype_create_params(stmt, pgType)); - set_nullfield_int2(&row->tuple[9], pgtype_unsigned(stmt, pgType)); - set_nullfield_int2(&row->tuple[11], pgtype_auto_increment(stmt, pgType)); - set_nullfield_int2(&row->tuple[13], pgtype_scale(stmt, pgType, PG_STATIC)); - set_nullfield_int2(&row->tuple[14], pgtype_scale(stmt, pgType, PG_STATIC)); -#if (ODBCVER >=0x0399) - set_nullfield_int2(&row->tuple[15], pgtype_sqldesctype(stmt, pgType)); - set_nullfield_int2(&row->tuple[16], pgtype_datetime_sub(stmt, pgType)); - set_nullfield_int4(&row->tuple[17], pgtype_radix(stmt, pgType)); - set_nullfield_int4(&row->tuple[18], 0); -#endif /* ODBCVER */ - - QR_add_tuple(res, row); - } - } - - stmt->status = STMT_FINISHED; - stmt->currTuple = -1; - stmt->rowset_start = -1; - stmt->current_col = -1; - - return SQL_SUCCESS; -} - - -RETCODE SQL_API -PGAPI_GetFunctions( - HDBC hdbc, - UWORD fFunction, - UWORD FAR * pfExists) -{ - static char *func = "PGAPI_GetFunctions"; - ConnectionClass *conn = (ConnectionClass *) hdbc; - ConnInfo *ci = &(conn->connInfo); - - mylog("%s: entering...%u\n", func, fFunction); - - if (fFunction == SQL_API_ALL_FUNCTIONS) - { -#if (ODBCVER < 0x0300) - if (ci->drivers.lie) - { - int i; - - memset(pfExists, 0, sizeof(UWORD) * 100); - - pfExists[SQL_API_SQLALLOCENV] = TRUE; - pfExists[SQL_API_SQLFREEENV] = TRUE; - for (i = SQL_API_SQLALLOCCONNECT; i <= SQL_NUM_FUNCTIONS; i++) - pfExists[i] = TRUE; - for (i = SQL_EXT_API_START; i <= SQL_EXT_API_LAST; i++) - pfExists[i] = TRUE; - } - else -#endif - { - memset(pfExists, 0, sizeof(UWORD) * 100); - - /* ODBC core functions */ - pfExists[SQL_API_SQLALLOCCONNECT] = TRUE; - pfExists[SQL_API_SQLALLOCENV] = TRUE; - pfExists[SQL_API_SQLALLOCSTMT] = TRUE; - pfExists[SQL_API_SQLBINDCOL] = TRUE; - pfExists[SQL_API_SQLCANCEL] = TRUE; - pfExists[SQL_API_SQLCOLATTRIBUTES] = TRUE; - pfExists[SQL_API_SQLCONNECT] = TRUE; - pfExists[SQL_API_SQLDESCRIBECOL] = TRUE; /* partial */ - pfExists[SQL_API_SQLDISCONNECT] = TRUE; - pfExists[SQL_API_SQLERROR] = TRUE; - pfExists[SQL_API_SQLEXECDIRECT] = TRUE; - pfExists[SQL_API_SQLEXECUTE] = TRUE; - pfExists[SQL_API_SQLFETCH] = TRUE; - pfExists[SQL_API_SQLFREECONNECT] = TRUE; - pfExists[SQL_API_SQLFREEENV] = TRUE; - pfExists[SQL_API_SQLFREESTMT] = TRUE; - pfExists[SQL_API_SQLGETCURSORNAME] = TRUE; - pfExists[SQL_API_SQLNUMRESULTCOLS] = TRUE; - pfExists[SQL_API_SQLPREPARE] = TRUE; /* complete? */ - pfExists[SQL_API_SQLROWCOUNT] = TRUE; - pfExists[SQL_API_SQLSETCURSORNAME] = TRUE; - pfExists[SQL_API_SQLSETPARAM] = FALSE; /* odbc 1.0 */ - pfExists[SQL_API_SQLTRANSACT] = TRUE; - - /* ODBC level 1 functions */ - pfExists[SQL_API_SQLBINDPARAMETER] = TRUE; - pfExists[SQL_API_SQLCOLUMNS] = TRUE; - pfExists[SQL_API_SQLDRIVERCONNECT] = TRUE; - pfExists[SQL_API_SQLGETCONNECTOPTION] = TRUE; /* partial */ - pfExists[SQL_API_SQLGETDATA] = TRUE; - pfExists[SQL_API_SQLGETFUNCTIONS] = TRUE; - pfExists[SQL_API_SQLGETINFO] = TRUE; - pfExists[SQL_API_SQLGETSTMTOPTION] = TRUE; /* partial */ - pfExists[SQL_API_SQLGETTYPEINFO] = TRUE; - pfExists[SQL_API_SQLPARAMDATA] = TRUE; - pfExists[SQL_API_SQLPUTDATA] = TRUE; - pfExists[SQL_API_SQLSETCONNECTOPTION] = TRUE; /* partial */ - pfExists[SQL_API_SQLSETSTMTOPTION] = TRUE; - pfExists[SQL_API_SQLSPECIALCOLUMNS] = TRUE; - pfExists[SQL_API_SQLSTATISTICS] = TRUE; - pfExists[SQL_API_SQLTABLES] = TRUE; - - /* ODBC level 2 functions */ - pfExists[SQL_API_SQLBROWSECONNECT] = FALSE; - pfExists[SQL_API_SQLCOLUMNPRIVILEGES] = FALSE; - pfExists[SQL_API_SQLDATASOURCES] = FALSE; /* only implemented by - * DM */ - pfExists[SQL_API_SQLDESCRIBEPARAM] = FALSE; /* not properly - * implemented */ - pfExists[SQL_API_SQLDRIVERS] = FALSE; /* only implemented by - * DM */ - pfExists[SQL_API_SQLEXTENDEDFETCH] = TRUE; - pfExists[SQL_API_SQLFOREIGNKEYS] = TRUE; - pfExists[SQL_API_SQLMORERESULTS] = TRUE; - pfExists[SQL_API_SQLNATIVESQL] = TRUE; - pfExists[SQL_API_SQLNUMPARAMS] = TRUE; - pfExists[SQL_API_SQLPARAMOPTIONS] = TRUE; - pfExists[SQL_API_SQLPRIMARYKEYS] = TRUE; - pfExists[SQL_API_SQLPROCEDURECOLUMNS] = FALSE; - if (PG_VERSION_LT(conn, 6.5)) - pfExists[SQL_API_SQLPROCEDURES] = FALSE; - else - pfExists[SQL_API_SQLPROCEDURES] = TRUE; - pfExists[SQL_API_SQLSETPOS] = TRUE; - pfExists[SQL_API_SQLSETSCROLLOPTIONS] = TRUE; /* odbc 1.0 */ - pfExists[SQL_API_SQLTABLEPRIVILEGES] = TRUE; - } - } - else - { - if (ci->drivers.lie) - *pfExists = TRUE; - else - { - switch (fFunction) - { - case SQL_API_SQLALLOCCONNECT: - *pfExists = TRUE; - break; - case SQL_API_SQLALLOCENV: - *pfExists = TRUE; - break; - case SQL_API_SQLALLOCSTMT: - *pfExists = TRUE; - break; - case SQL_API_SQLBINDCOL: - *pfExists = TRUE; - break; - case SQL_API_SQLCANCEL: - *pfExists = TRUE; - break; - case SQL_API_SQLCOLATTRIBUTES: - *pfExists = TRUE; - break; - case SQL_API_SQLCONNECT: - *pfExists = TRUE; - break; - case SQL_API_SQLDESCRIBECOL: - *pfExists = TRUE; - break; /* partial */ - case SQL_API_SQLDISCONNECT: - *pfExists = TRUE; - break; - case SQL_API_SQLERROR: - *pfExists = TRUE; - break; - case SQL_API_SQLEXECDIRECT: - *pfExists = TRUE; - break; - case SQL_API_SQLEXECUTE: - *pfExists = TRUE; - break; - case SQL_API_SQLFETCH: - *pfExists = TRUE; - break; - case SQL_API_SQLFREECONNECT: - *pfExists = TRUE; - break; - case SQL_API_SQLFREEENV: - *pfExists = TRUE; - break; - case SQL_API_SQLFREESTMT: - *pfExists = TRUE; - break; - case SQL_API_SQLGETCURSORNAME: - *pfExists = TRUE; - break; - case SQL_API_SQLNUMRESULTCOLS: - *pfExists = TRUE; - break; - case SQL_API_SQLPREPARE: - *pfExists = TRUE; - break; - case SQL_API_SQLROWCOUNT: - *pfExists = TRUE; - break; - case SQL_API_SQLSETCURSORNAME: - *pfExists = TRUE; - break; - case SQL_API_SQLSETPARAM: - *pfExists = FALSE; - break; /* odbc 1.0 */ - case SQL_API_SQLTRANSACT: - *pfExists = TRUE; - break; - - /* ODBC level 1 functions */ - case SQL_API_SQLBINDPARAMETER: - *pfExists = TRUE; - break; - case SQL_API_SQLCOLUMNS: - *pfExists = TRUE; - break; - case SQL_API_SQLDRIVERCONNECT: - *pfExists = TRUE; - break; - case SQL_API_SQLGETCONNECTOPTION: - *pfExists = TRUE; - break; /* partial */ - case SQL_API_SQLGETDATA: - *pfExists = TRUE; - break; - case SQL_API_SQLGETFUNCTIONS: - *pfExists = TRUE; - break; - case SQL_API_SQLGETINFO: - *pfExists = TRUE; - break; - case SQL_API_SQLGETSTMTOPTION: - *pfExists = TRUE; - break; /* partial */ - case SQL_API_SQLGETTYPEINFO: - *pfExists = TRUE; - break; - case SQL_API_SQLPARAMDATA: - *pfExists = TRUE; - break; - case SQL_API_SQLPUTDATA: - *pfExists = TRUE; - break; - case SQL_API_SQLSETCONNECTOPTION: - *pfExists = TRUE; - break; /* partial */ - case SQL_API_SQLSETSTMTOPTION: - *pfExists = TRUE; - break; - case SQL_API_SQLSPECIALCOLUMNS: - *pfExists = TRUE; - break; - case SQL_API_SQLSTATISTICS: - *pfExists = TRUE; - break; - case SQL_API_SQLTABLES: - *pfExists = TRUE; - break; - - /* ODBC level 2 functions */ - case SQL_API_SQLBROWSECONNECT: - *pfExists = FALSE; - break; - case SQL_API_SQLCOLUMNPRIVILEGES: - *pfExists = FALSE; - break; - case SQL_API_SQLDATASOURCES: - *pfExists = FALSE; - break; /* only implemented by DM */ - case SQL_API_SQLDESCRIBEPARAM: - *pfExists = FALSE; - break; /* not properly implemented */ - case SQL_API_SQLDRIVERS: - *pfExists = FALSE; - break; /* only implemented by DM */ - case SQL_API_SQLEXTENDEDFETCH: - *pfExists = TRUE; - break; - case SQL_API_SQLFOREIGNKEYS: - *pfExists = TRUE; - break; - case SQL_API_SQLMORERESULTS: - *pfExists = TRUE; - break; - case SQL_API_SQLNATIVESQL: - *pfExists = TRUE; - break; - case SQL_API_SQLNUMPARAMS: - *pfExists = TRUE; - break; - case SQL_API_SQLPARAMOPTIONS: - *pfExists = TRUE; - break; - case SQL_API_SQLPRIMARYKEYS: - *pfExists = TRUE; - break; - case SQL_API_SQLPROCEDURECOLUMNS: - *pfExists = FALSE; - break; - case SQL_API_SQLPROCEDURES: - if (PG_VERSION_LT(conn, 6.5)) - *pfExists = FALSE; - else - *pfExists = TRUE; - break; - case SQL_API_SQLSETPOS: - *pfExists = TRUE; - break; - case SQL_API_SQLSETSCROLLOPTIONS: - *pfExists = TRUE; - break; /* odbc 1.0 */ - case SQL_API_SQLTABLEPRIVILEGES: - *pfExists = TRUE; - break; - } - } - } - return SQL_SUCCESS; -} - - -RETCODE SQL_API -PGAPI_Tables( - HSTMT hstmt, - UCHAR FAR * szTableQualifier, - SWORD cbTableQualifier, - UCHAR FAR * szTableOwner, - SWORD cbTableOwner, - UCHAR FAR * szTableName, - SWORD cbTableName, - UCHAR FAR * szTableType, - SWORD cbTableType) -{ - static char *func = "PGAPI_Tables"; - StatementClass *stmt = (StatementClass *) hstmt; - StatementClass *tbl_stmt; - QResultClass *res; - TupleNode *row; - HSTMT htbl_stmt; - RETCODE result; - char *tableType; - char tables_query[INFO_INQUIRY_LEN]; - char table_name[MAX_INFO_STRING], - table_owner[MAX_INFO_STRING], - relkind_or_hasrules[MAX_INFO_STRING]; - ConnectionClass *conn; - ConnInfo *ci; - char *prefix[32], - prefixes[MEDIUM_REGISTRY_LEN]; - char *table_type[32], - table_types[MAX_INFO_STRING]; - char show_system_tables, - show_regular_tables, - show_views; - char regular_table, - view, - systable; - int i; - - mylog("%s: entering...stmt=%u scnm=%x len=%d\n", func, stmt, szTableOwner, cbTableOwner); - - if (!stmt) - { - SC_log_error(func, "", NULL); - return SQL_INVALID_HANDLE; - } - - stmt->manual_result = TRUE; - stmt->errormsg_created = TRUE; - - conn = SC_get_conn(stmt); - ci = &(conn->connInfo); - - result = PGAPI_AllocStmt(stmt->hdbc, &htbl_stmt); - if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) - { - stmt->errornumber = STMT_NO_MEMORY_ERROR; - stmt->errormsg = "Couldn't allocate statement for PGAPI_Tables result."; - SC_log_error(func, "", stmt); - return SQL_ERROR; - } - tbl_stmt = (StatementClass *) htbl_stmt; - - /* - * Create the query to find out the tables - */ - if (conn->schema_support) - { - /* view is represented by its relkind since 7.1 */ - strcpy(tables_query, "select relname, nspname, relkind from pg_class, pg_namespace"); - strcat(tables_query, " where relkind in ('r', 'v')"); - } - else if (PG_VERSION_GE(conn, 7.1)) - { - /* view is represented by its relkind since 7.1 */ - strcpy(tables_query, "select relname, usename, relkind from pg_class, pg_user"); - strcat(tables_query, " where relkind in ('r', 'v')"); - } - else - { - strcpy(tables_query, "select relname, usename, relhasrules from pg_class, pg_user"); - strcat(tables_query, " where relkind = 'r'"); - } - - if (conn->schema_support) - schema_strcat(tables_query, " and nspname like '%.*s'", szTableOwner, cbTableOwner, szTableName, cbTableName, conn); - else - my_strcat(tables_query, " and usename like '%.*s'", szTableOwner, cbTableOwner); - my_strcat(tables_query, " and relname like '%.*s'", szTableName, cbTableName); - - /* Parse the extra systable prefix */ - strcpy(prefixes, ci->drivers.extra_systable_prefixes); - i = 0; - prefix[i] = strtok(prefixes, ";"); - while (prefix[i] && i < 32) - prefix[++i] = strtok(NULL, ";"); - - /* Parse the desired table types to return */ - show_system_tables = FALSE; - show_regular_tables = FALSE; - show_views = FALSE; - - /* make_string mallocs memory */ - tableType = make_string(szTableType, cbTableType, NULL); - if (tableType) - { - strcpy(table_types, tableType); - free(tableType); - i = 0; - table_type[i] = strtok(table_types, ","); - while (table_type[i] && i < 32) - table_type[++i] = strtok(NULL, ","); - - /* Check for desired table types to return */ - i = 0; - while (table_type[i]) - { - if (strstr(table_type[i], "SYSTEM TABLE")) - show_system_tables = TRUE; - else if (strstr(table_type[i], "TABLE")) - show_regular_tables = TRUE; - else if (strstr(table_type[i], "VIEW")) - show_views = TRUE; - i++; - } - } - else - { - show_regular_tables = TRUE; - show_views = TRUE; - } - - /* - * If not interested in SYSTEM TABLES then filter them out to save - * some time on the query. If treating system tables as regular - * tables, then dont filter either. - */ - if (!atoi(ci->show_system_tables) && !show_system_tables) - { - strcat(tables_query, " and relname !~ '^" POSTGRES_SYS_PREFIX); - - /* Also filter out user-defined system table types */ - i = 0; - while (prefix[i]) - { - strcat(tables_query, "|^"); - strcat(tables_query, prefix[i]); - i++; - } - strcat(tables_query, "'"); - } - - /* match users */ - if (PG_VERSION_LT(conn, 7.1)) - /* filter out large objects in older versions */ - strcat(tables_query, " and relname !~ '^xinv[0-9]+'"); - - if (conn->schema_support) - strcat(tables_query, " and pg_namespace.oid = relnamespace order by nspname, relname"); - else - strcat(tables_query, " and usesysid = relowner order by relname"); - - result = PGAPI_ExecDirect(htbl_stmt, tables_query, strlen(tables_query)); - if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) - { - stmt->errormsg = SC_create_errormsg(htbl_stmt); - stmt->errornumber = tbl_stmt->errornumber; - SC_log_error(func, "", stmt); - PGAPI_FreeStmt(htbl_stmt, SQL_DROP); - return SQL_ERROR; - } - - result = PGAPI_BindCol(htbl_stmt, 1, SQL_C_CHAR, - table_name, MAX_INFO_STRING, NULL); - if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) - { - stmt->errormsg = tbl_stmt->errormsg; - stmt->errornumber = tbl_stmt->errornumber; - SC_log_error(func, "", stmt); - PGAPI_FreeStmt(htbl_stmt, SQL_DROP); - return SQL_ERROR; - } - - result = PGAPI_BindCol(htbl_stmt, 2, SQL_C_CHAR, - table_owner, MAX_INFO_STRING, NULL); - if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) - { - stmt->errormsg = tbl_stmt->errormsg; - stmt->errornumber = tbl_stmt->errornumber; - SC_log_error(func, "", stmt); - PGAPI_FreeStmt(htbl_stmt, SQL_DROP); - return SQL_ERROR; - } - result = PGAPI_BindCol(htbl_stmt, 3, SQL_C_CHAR, - relkind_or_hasrules, MAX_INFO_STRING, NULL); - if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) - { - stmt->errormsg = tbl_stmt->errormsg; - stmt->errornumber = tbl_stmt->errornumber; - SC_log_error(func, "", stmt); - PGAPI_FreeStmt(htbl_stmt, SQL_DROP); - return SQL_ERROR; - } - - if (res = QR_Constructor(), !res) - { - stmt->errormsg = "Couldn't allocate memory for PGAPI_Tables result."; - stmt->errornumber = STMT_NO_MEMORY_ERROR; - SC_log_error(func, "", stmt); - PGAPI_FreeStmt(htbl_stmt, SQL_DROP); - return SQL_ERROR; - } - SC_set_Result(stmt, res); - - /* the binding structure for a statement is not set up until */ - - /* - * a statement is actually executed, so we'll have to do this - * ourselves. - */ - extend_column_bindings(SC_get_ARD(stmt), 5); - - /* set the field names */ - QR_set_num_fields(res, 5); - QR_set_field_info(res, 0, "TABLE_QUALIFIER", PG_TYPE_TEXT, MAX_INFO_STRING); - QR_set_field_info(res, 1, "TABLE_OWNER", PG_TYPE_TEXT, MAX_INFO_STRING); - QR_set_field_info(res, 2, "TABLE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING); - QR_set_field_info(res, 3, "TABLE_TYPE", PG_TYPE_TEXT, MAX_INFO_STRING); - QR_set_field_info(res, 4, "REMARKS", PG_TYPE_TEXT, 254); - - /* add the tuples */ - result = PGAPI_Fetch(htbl_stmt); - while ((result == SQL_SUCCESS) || (result == SQL_SUCCESS_WITH_INFO)) - { - /* - * Determine if this table name is a system table. If treating - * system tables as regular tables, then no need to do this test. - */ - systable = FALSE; - if (!atoi(ci->show_system_tables)) - { - if (strncmp(table_name, POSTGRES_SYS_PREFIX, strlen(POSTGRES_SYS_PREFIX)) == 0) - systable = TRUE; - - else - { - /* Check extra system table prefixes */ - i = 0; - while (prefix[i]) - { - mylog("table_name='%s', prefix[%d]='%s'\n", table_name, i, prefix[i]); - if (strncmp(table_name, prefix[i], strlen(prefix[i])) == 0) - { - systable = TRUE; - break; - } - i++; - } - } - } - - /* Determine if the table name is a view */ - if (PG_VERSION_GE(conn, 7.1)) - /* view is represented by its relkind since 7.1 */ - view = (relkind_or_hasrules[0] == 'v'); - else - view = (relkind_or_hasrules[0] == '1'); - - /* It must be a regular table */ - regular_table = (!systable && !view); - - - /* Include the row in the result set if meets all criteria */ - - /* - * NOTE: Unsupported table types (i.e., LOCAL TEMPORARY, ALIAS, - * etc) will return nothing - */ - if ((systable && show_system_tables) || - (view && show_views) || - (regular_table && show_regular_tables)) - { - row = (TupleNode *) malloc(sizeof(TupleNode) + (5 - 1) *sizeof(TupleField)); - - /*set_tuplefield_string(&row->tuple[0], "");*/ - set_tuplefield_null(&row->tuple[0]); - - /* - * I have to hide the table owner from Access, otherwise it - * insists on referring to the table as 'owner.table'. (this - * is valid according to the ODBC SQL grammar, but Postgres - * won't support it.) - * - * set_tuplefield_string(&row->tuple[1], table_owner); - */ - - mylog("%s: table_name = '%s'\n", func, table_name); - - if (conn->schema_support) - set_tuplefield_string(&row->tuple[1], GET_SCHEMA_NAME(table_owner)); - else - /* set_tuplefield_string(&row->tuple[1], ""); */ - set_tuplefield_null(&row->tuple[1]); - set_tuplefield_string(&row->tuple[2], table_name); - set_tuplefield_string(&row->tuple[3], systable ? "SYSTEM TABLE" : (view ? "VIEW" : "TABLE")); - /*set_tuplefield_string(&row->tuple[4], "");*/ - set_tuplefield_string(&row->tuple[4], "TABLE"); - - QR_add_tuple(res, row); - } - result = PGAPI_Fetch(htbl_stmt); - } - if (result != SQL_NO_DATA_FOUND) - { - stmt->errormsg = SC_create_errormsg(htbl_stmt); - stmt->errornumber = tbl_stmt->errornumber; - SC_log_error(func, "", stmt); - PGAPI_FreeStmt(htbl_stmt, SQL_DROP); - return SQL_ERROR; - } - - /* - * also, things need to think that this statement is finished so the - * results can be retrieved. - */ - stmt->status = STMT_FINISHED; - - /* set up the current tuple pointer for SQLFetch */ - stmt->currTuple = -1; - stmt->rowset_start = -1; - stmt->current_col = -1; - - PGAPI_FreeStmt(htbl_stmt, SQL_DROP); - mylog("%s: EXIT, stmt=%u\n", func, stmt); - return SQL_SUCCESS; -} - - -/* - * PostgreSQL needs 2 '\\' to escape '_' and '%'. - */ -static int -reallyEscapeCatalogEscapes(const char *src, int srclen, char *dest, int dst_len, int ccsc) -{ - int i, outlen; - const char *in; - BOOL escape_in = FALSE; -#ifdef MULTIBYTE - encoded_str encstr; -#endif - - if (srclen == SQL_NULL_DATA) - { - dest[0] = '\0'; - return STRCPY_NULL; - } - else if (srclen == SQL_NTS) - srclen = strlen(src); - if (srclen <= 0) - return STRCPY_FAIL; -#ifdef MULTIBYTE - encoded_str_constr(&encstr, ccsc, src); -#endif - for (i = 0, in = src, outlen = 0; i < srclen && outlen < dst_len; i++, in++) - { -#ifdef MULTIBYTE - encoded_nextchar(&encstr); - if (ENCODE_STATUS(encstr) != 0) - { - dest[outlen++] = *in; - continue; - } -#endif - if (escape_in) - { - switch (*in) - { - case '%': - case '_': - dest[outlen++] = '\\'; /* needs 1 more */ - break; - default: - dest[outlen++] = '\\'; - if (outlen < dst_len) - dest[outlen++] = '\\'; - if (outlen < dst_len) - dest[outlen++] = '\\'; - break; - } - } - if (*in == '\\') - escape_in = TRUE; - else - escape_in = FALSE; - if (outlen < dst_len) - dest[outlen++] = *in; - } - if (outlen < dst_len) - dest[outlen] = '\0'; - return outlen; -} - -RETCODE SQL_API -PGAPI_Columns( - HSTMT hstmt, - UCHAR FAR * szTableQualifier, - SWORD cbTableQualifier, - UCHAR FAR * szTableOwner, - SWORD cbTableOwner, - UCHAR FAR * szTableName, - SWORD cbTableName, - UCHAR FAR * szColumnName, - SWORD cbColumnName, - UWORD flag) -{ - static char *func = "PGAPI_Columns"; - StatementClass *stmt = (StatementClass *) hstmt; - QResultClass *res; - TupleNode *row; - HSTMT hcol_stmt; - StatementClass *col_stmt; - char columns_query[INFO_INQUIRY_LEN]; - RETCODE result; - char table_owner[MAX_INFO_STRING], - table_name[MAX_INFO_STRING], - field_name[MAX_INFO_STRING], - field_type_name[MAX_INFO_STRING]; - Int2 field_number, sqltype, - reserved_cols, - result_cols, - decimal_digits; - Int4 field_type, - the_type, - field_length, - mod_length, - column_size, - ordinal; - char useStaticPrecision; - char not_null[MAX_INFO_STRING], - relhasrules[MAX_INFO_STRING]; - ConnInfo *ci; - ConnectionClass *conn; - - - mylog("%s: entering...stmt=%u scnm=%x len=%d\n", func, stmt, szTableOwner, cbTableOwner); - - if (!stmt) - { - SC_log_error(func, "", NULL); - return SQL_INVALID_HANDLE; - } - - stmt->manual_result = TRUE; - stmt->errormsg_created = TRUE; - - conn = SC_get_conn(stmt); - ci = &(conn->connInfo); - - /* - * Create the query to find out the columns (Note: pre 6.3 did not - * have the atttypmod field) - */ - if (conn->schema_support) - sprintf(columns_query, "select u.nspname, c.relname, a.attname, a.atttypid" - ", t.typname, a.attnum, a.attlen, %s, a.attnotnull, c.relhasrules" - " from pg_namespace u, pg_class c, pg_attribute a, pg_type t" - " where u.oid = c.relnamespace" - " and c.oid= a.attrelid and a.atttypid = t.oid and (a.attnum > 0)", - "a.atttypmod"); - else - sprintf(columns_query, "select u.usename, c.relname, a.attname, a.atttypid" - ", t.typname, a.attnum, a.attlen, %s, a.attnotnull, c.relhasrules" - " from pg_user u, pg_class c, pg_attribute a, pg_type t" - " where u.usesysid = c.relowner" - " and c.oid= a.attrelid and a.atttypid = t.oid and (a.attnum > 0)", - PG_VERSION_LE(conn, 6.2) ? "a.attlen" : "a.atttypmod"); - - if ((flag & PODBC_NOT_SEARCH_PATTERN) != 0) - { - my_strcat(columns_query, " and c.relname = '%.*s'", szTableName, cbTableName); - if (conn->schema_support) - schema_strcat(columns_query, " and u.nspname = '%.*s'", szTableOwner, cbTableOwner, szTableName, cbTableName, conn); - else - my_strcat(columns_query, " and u.usename = '%.*s'", szTableOwner, cbTableOwner); - my_strcat(columns_query, " and a.attname = '%.*s'", szColumnName, cbColumnName); - } - else - { - char esc_table_name[MAX_TABLE_LEN * 2]; - int escTbnamelen; - - escTbnamelen = reallyEscapeCatalogEscapes(szTableName, cbTableName, esc_table_name, sizeof(esc_table_name), conn->ccsc); - my_strcat(columns_query, " and c.relname like '%.*s'", esc_table_name, escTbnamelen); - if (conn->schema_support) - schema_strcat(columns_query, " and u.nspname like '%.*s'", szTableOwner, cbTableOwner, szTableName, cbTableName, conn); - else - my_strcat(columns_query, " and u.usename like '%.*s'", szTableOwner, cbTableOwner); - my_strcat(columns_query, " and a.attname like '%.*s'", szColumnName, cbColumnName); - } - - /* - * give the output in the order the columns were defined when the - * table was created - */ - if (conn->schema_support) - strcat(columns_query, " order by u.nspname, c.relname, attnum"); - else - strcat(columns_query, " order by c.relname, attnum"); - - result = PGAPI_AllocStmt(stmt->hdbc, &hcol_stmt); - if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) - { - stmt->errornumber = STMT_NO_MEMORY_ERROR; - stmt->errormsg = "Couldn't allocate statement for PGAPI_Columns result."; - SC_log_error(func, "", stmt); - return SQL_ERROR; - } - col_stmt = (StatementClass *) hcol_stmt; - - mylog("%s: hcol_stmt = %u, col_stmt = %u\n", func, hcol_stmt, col_stmt); - - result = PGAPI_ExecDirect(hcol_stmt, columns_query, - strlen(columns_query)); - if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) - { - stmt->errormsg = SC_create_errormsg(hcol_stmt); - stmt->errornumber = col_stmt->errornumber; - SC_log_error(func, "", stmt); - PGAPI_FreeStmt(hcol_stmt, SQL_DROP); - return SQL_ERROR; - } - - result = PGAPI_BindCol(hcol_stmt, 1, SQL_C_CHAR, - table_owner, MAX_INFO_STRING, NULL); - if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) - { - stmt->errormsg = col_stmt->errormsg; - stmt->errornumber = col_stmt->errornumber; - SC_log_error(func, "", stmt); - PGAPI_FreeStmt(hcol_stmt, SQL_DROP); - return SQL_ERROR; - } - - result = PGAPI_BindCol(hcol_stmt, 2, SQL_C_CHAR, - table_name, MAX_INFO_STRING, NULL); - if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) - { - stmt->errormsg = col_stmt->errormsg; - stmt->errornumber = col_stmt->errornumber; - SC_log_error(func, "", stmt); - PGAPI_FreeStmt(hcol_stmt, SQL_DROP); - return SQL_ERROR; - } - - result = PGAPI_BindCol(hcol_stmt, 3, SQL_C_CHAR, - field_name, MAX_INFO_STRING, NULL); - if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) - { - stmt->errormsg = col_stmt->errormsg; - stmt->errornumber = col_stmt->errornumber; - SC_log_error(func, "", stmt); - PGAPI_FreeStmt(hcol_stmt, SQL_DROP); - return SQL_ERROR; - } - - result = PGAPI_BindCol(hcol_stmt, 4, SQL_C_LONG, - &field_type, 4, NULL); - if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) - { - stmt->errormsg = col_stmt->errormsg; - stmt->errornumber = col_stmt->errornumber; - SC_log_error(func, "", stmt); - PGAPI_FreeStmt(hcol_stmt, SQL_DROP); - return SQL_ERROR; - } - - result = PGAPI_BindCol(hcol_stmt, 5, SQL_C_CHAR, - field_type_name, MAX_INFO_STRING, NULL); - if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) - { - stmt->errormsg = col_stmt->errormsg; - stmt->errornumber = col_stmt->errornumber; - SC_log_error(func, "", stmt); - PGAPI_FreeStmt(hcol_stmt, SQL_DROP); - return SQL_ERROR; - } - - result = PGAPI_BindCol(hcol_stmt, 6, SQL_C_SHORT, - &field_number, MAX_INFO_STRING, NULL); - if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) - { - stmt->errormsg = col_stmt->errormsg; - stmt->errornumber = col_stmt->errornumber; - SC_log_error(func, "", stmt); - PGAPI_FreeStmt(hcol_stmt, SQL_DROP); - return SQL_ERROR; - } - - result = PGAPI_BindCol(hcol_stmt, 7, SQL_C_LONG, - &field_length, MAX_INFO_STRING, NULL); - if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) - { - stmt->errormsg = col_stmt->errormsg; - stmt->errornumber = col_stmt->errornumber; - SC_log_error(func, "", stmt); - PGAPI_FreeStmt(hcol_stmt, SQL_DROP); - return SQL_ERROR; - } - - result = PGAPI_BindCol(hcol_stmt, 8, SQL_C_LONG, - &mod_length, MAX_INFO_STRING, NULL); - if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) - { - stmt->errormsg = col_stmt->errormsg; - stmt->errornumber = col_stmt->errornumber; - SC_log_error(func, "", stmt); - PGAPI_FreeStmt(hcol_stmt, SQL_DROP); - return SQL_ERROR; - } - - result = PGAPI_BindCol(hcol_stmt, 9, SQL_C_CHAR, - not_null, MAX_INFO_STRING, NULL); - if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) - { - stmt->errormsg = col_stmt->errormsg; - stmt->errornumber = col_stmt->errornumber; - SC_log_error(func, "", stmt); - PGAPI_FreeStmt(hcol_stmt, SQL_DROP); - return SQL_ERROR; - } - - result = PGAPI_BindCol(hcol_stmt, 10, SQL_C_CHAR, - relhasrules, MAX_INFO_STRING, NULL); - if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) - { - stmt->errormsg = col_stmt->errormsg; - stmt->errornumber = col_stmt->errornumber; - SC_log_error(func, "", stmt); - PGAPI_FreeStmt(hcol_stmt, SQL_DROP); - return SQL_ERROR; - } - - if (res = QR_Constructor(), !res) - { - stmt->errormsg = "Couldn't allocate memory for PGAPI_Columns result."; - stmt->errornumber = STMT_NO_MEMORY_ERROR; - SC_log_error(func, "", stmt); - PGAPI_FreeStmt(hcol_stmt, SQL_DROP); - return SQL_ERROR; - } - SC_set_Result(stmt, res); - - /* the binding structure for a statement is not set up until */ - - /* - * a statement is actually executed, so we'll have to do this - * ourselves. - */ -#if (ODBCVER >= 0x0300) - reserved_cols = 18; -#else - reserved_cols = 12; -#endif /* ODBCVER */ - result_cols = reserved_cols + 2; - extend_column_bindings(SC_get_ARD(stmt), result_cols); - - /* set the field names */ - QR_set_num_fields(res, result_cols); - QR_set_field_info(res, 0, "TABLE_QUALIFIER", PG_TYPE_TEXT, MAX_INFO_STRING); - QR_set_field_info(res, 1, "TABLE_OWNER", PG_TYPE_TEXT, MAX_INFO_STRING); - QR_set_field_info(res, 2, "TABLE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING); - QR_set_field_info(res, 3, "COLUMN_NAME", PG_TYPE_TEXT, MAX_INFO_STRING); - QR_set_field_info(res, 4, "DATA_TYPE", PG_TYPE_INT2, 2); - QR_set_field_info(res, 5, "TYPE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING); - QR_set_field_info(res, 6, "PRECISION", PG_TYPE_INT4, 4); /* COLUMN_SIZE */ - QR_set_field_info(res, 7, "LENGTH", PG_TYPE_INT4, 4); /* BUFFER_LENGTH */ - QR_set_field_info(res, 8, "SCALE", PG_TYPE_INT2, 2); /* DECIMAL_DIGITS ***/ - QR_set_field_info(res, 9, "RADIX", PG_TYPE_INT2, 2); - QR_set_field_info(res, 10, "NULLABLE", PG_TYPE_INT2, 2); - QR_set_field_info(res, 11, "REMARKS", PG_TYPE_TEXT, 254); - - /* User defined fields */ -#if (ODBCVER >= 0x0300) - QR_set_field_info(res, 12, "COLUMN_DEF", PG_TYPE_INT4, 254); - QR_set_field_info(res, 13, "SQL_DATA_TYPE", PG_TYPE_INT2, 2); - QR_set_field_info(res, 14, "SQL_DATETIME_SUB", PG_TYPE_INT2, 2); - QR_set_field_info(res, 15, "CHAR_OCTET_LENGTH", PG_TYPE_INT4, 4); - QR_set_field_info(res, 16, "ORDINAL_POSITION", PG_TYPE_INT4, 4); - QR_set_field_info(res, 17, "IS_NULLABLE", PG_TYPE_TEXT, 254); -#endif /* ODBCVER */ - QR_set_field_info(res, reserved_cols, "DISPLAY_SIZE", PG_TYPE_INT4, 4); - QR_set_field_info(res, reserved_cols + 1, "FIELD_TYPE", PG_TYPE_INT4, 4); - - ordinal = 1; - result = PGAPI_Fetch(hcol_stmt); - - /* - * Only show oid if option AND there are other columns AND it's not - * being called by SQLStatistics . Always show OID if it's a system - * table - */ - - if (result != SQL_ERROR && !stmt->internal) - { - if (relhasrules[0] != '1' && - (atoi(ci->show_oid_column) || - strncmp(table_name, POSTGRES_SYS_PREFIX, strlen(POSTGRES_SYS_PREFIX)) == 0)) - { - /* For OID fields */ - the_type = PG_TYPE_OID; - row = (TupleNode *) malloc(sizeof(TupleNode) + - (result_cols - 1) *sizeof(TupleField)); - - set_tuplefield_string(&row->tuple[0], ""); - /* see note in SQLTables() */ - if (conn->schema_support) - set_tuplefield_string(&row->tuple[1], GET_SCHEMA_NAME(table_owner)); - else - set_tuplefield_string(&row->tuple[1], ""); - set_tuplefield_string(&row->tuple[2], table_name); - set_tuplefield_string(&row->tuple[3], "oid"); - sqltype = pgtype_to_concise_type(stmt, the_type); - set_tuplefield_int2(&row->tuple[4], sqltype); - set_tuplefield_string(&row->tuple[5], "OID"); - - set_tuplefield_int4(&row->tuple[6], pgtype_column_size(stmt, the_type, PG_STATIC, PG_STATIC)); - set_tuplefield_int4(&row->tuple[7], pgtype_buffer_length(stmt, the_type, PG_STATIC, PG_STATIC)); - set_nullfield_int2(&row->tuple[8], pgtype_decimal_digits(stmt, the_type, PG_STATIC)); - set_nullfield_int2(&row->tuple[9], pgtype_radix(stmt, the_type)); - set_tuplefield_int2(&row->tuple[10], SQL_NO_NULLS); - set_tuplefield_string(&row->tuple[11], ""); - -#if (ODBCVER >= 0x0300) - set_tuplefield_null(&row->tuple[12]); - set_tuplefield_int2(&row->tuple[13], sqltype); - set_tuplefield_null(&row->tuple[14]); - set_tuplefield_int4(&row->tuple[15], pgtype_transfer_octet_length(stmt, the_type, PG_STATIC, PG_STATIC)); - set_tuplefield_int4(&row->tuple[16], ordinal); - set_tuplefield_string(&row->tuple[17], "No"); -#endif /* ODBCVER */ - set_tuplefield_int4(&row->tuple[reserved_cols], pgtype_display_size(stmt, the_type, PG_STATIC, PG_STATIC)); - set_tuplefield_int4(&row->tuple[reserved_cols + 1], the_type); - - QR_add_tuple(res, row); - ordinal++; - } - } - - while ((result == SQL_SUCCESS) || (result == SQL_SUCCESS_WITH_INFO)) - { - row = (TupleNode *) malloc(sizeof(TupleNode) + - (result_cols - 1) *sizeof(TupleField)); - - - set_tuplefield_string(&row->tuple[0], ""); - /* see note in SQLTables() */ - if (conn->schema_support) - set_tuplefield_string(&row->tuple[1], GET_SCHEMA_NAME(table_owner)); - else - set_tuplefield_string(&row->tuple[1], ""); - set_tuplefield_string(&row->tuple[2], table_name); - set_tuplefield_string(&row->tuple[3], field_name); - sqltype = pgtype_to_concise_type(stmt, field_type); - set_tuplefield_int2(&row->tuple[4], sqltype); - set_tuplefield_string(&row->tuple[5], field_type_name); - - - /*---------- - * Some Notes about Postgres Data Types: - * - * VARCHAR - the length is stored in the pg_attribute.atttypmod field - * BPCHAR - the length is also stored as varchar is - * - * NUMERIC - the decimal_digits is stored in atttypmod as follows: - * - * column_size =((atttypmod - VARHDRSZ) >> 16) & 0xffff - * decimal_digits = (atttypmod - VARHDRSZ) & 0xffff - * - *---------- - */ - qlog("PGAPI_Columns: table='%s',field_name='%s',type=%d,name='%s'\n", - table_name, field_name, field_type, field_type_name); - - useStaticPrecision = TRUE; - - if (field_type == PG_TYPE_NUMERIC) - { - if (mod_length >= 4) - mod_length -= 4; /* the length is in atttypmod - 4 */ - - if (mod_length >= 0) - { - useStaticPrecision = FALSE; - - column_size = (mod_length >> 16) & 0xffff; - decimal_digits = mod_length & 0xffff; - - mylog("%s: field type is NUMERIC: field_type = %d, mod_length=%d, precision=%d, scale=%d\n", func, field_type, mod_length, column_size, decimal_digits); - - set_tuplefield_int4(&row->tuple[6], column_size); - set_tuplefield_int4(&row->tuple[7], column_size + 2); /* sign+dec.point */ - set_nullfield_int2(&row->tuple[8], decimal_digits); -#if (ODBCVER >= 0x0300) - set_tuplefield_null(&row->tuple[15]); -#endif /* ODBCVER */ - set_tuplefield_int4(&row->tuple[reserved_cols], column_size + 2); /* sign+dec.point */ - } - } - - if ((field_type == PG_TYPE_VARCHAR) || - (field_type == PG_TYPE_BPCHAR)) - { - useStaticPrecision = FALSE; - - if (mod_length >= 4) - mod_length -= 4; /* the length is in atttypmod - 4 */ - - if (mod_length > ci->drivers.max_varchar_size || mod_length <= 0) - mod_length = ci->drivers.max_varchar_size; - - mylog("%s: field type is VARCHAR,BPCHAR: field_type = %d, mod_length = %d\n", func, field_type, mod_length); - - set_tuplefield_int4(&row->tuple[6], mod_length); - set_tuplefield_int4(&row->tuple[7], mod_length); - set_nullfield_int2(&row->tuple[8], pgtype_decimal_digits(stmt, field_type, PG_STATIC)); -#if (ODBCVER >= 0x0300) - set_tuplefield_int4(&row->tuple[15], pgtype_transfer_octet_length(stmt, field_type, PG_STATIC, PG_STATIC)); -#endif /* ODBCVER */ - set_tuplefield_int4(&row->tuple[reserved_cols], mod_length); - } - - if (useStaticPrecision) - { - mylog("%s: field type is OTHER: field_type = %d, pgtype_length = %d\n", func, field_type, pgtype_buffer_length(stmt, field_type, PG_STATIC, PG_STATIC)); - - set_tuplefield_int4(&row->tuple[6], pgtype_column_size(stmt, field_type, PG_STATIC, PG_STATIC)); - set_tuplefield_int4(&row->tuple[7], pgtype_buffer_length(stmt, field_type, PG_STATIC, PG_STATIC)); - set_nullfield_int2(&row->tuple[8], pgtype_decimal_digits(stmt, field_type, PG_STATIC)); -#if (ODBCVER >= 0x0300) - set_tuplefield_null(&row->tuple[15]); -#endif /* ODBCVER */ - set_tuplefield_int4(&row->tuple[reserved_cols], pgtype_display_size(stmt, field_type, PG_STATIC, PG_STATIC)); - } - - set_nullfield_int2(&row->tuple[9], pgtype_radix(stmt, field_type)); - set_tuplefield_int2(&row->tuple[10], (Int2) (not_null[0] == '1' ? SQL_NO_NULLS : pgtype_nullable(stmt, field_type))); - set_tuplefield_string(&row->tuple[11], ""); -#if (ODBCVER >= 0x0300) - set_tuplefield_null(&row->tuple[12]); - set_tuplefield_int2(&row->tuple[13], pgtype_to_sqldesctype(stmt, field_type)); - set_nullfield_int2(&row->tuple[14], pgtype_to_datetime_sub(stmt, field_type)); - set_tuplefield_int4(&row->tuple[16], ordinal); - set_tuplefield_null(&row->tuple[17]); -#endif /* ODBCVER */ - set_tuplefield_int4(&row->tuple[reserved_cols + 1], field_type); - - QR_add_tuple(res, row); - ordinal++; - - result = PGAPI_Fetch(hcol_stmt); - - } - if (result != SQL_NO_DATA_FOUND) - { - stmt->errormsg = SC_create_errormsg(hcol_stmt); - stmt->errornumber = col_stmt->errornumber; - SC_log_error(func, "", stmt); - PGAPI_FreeStmt(hcol_stmt, SQL_DROP); - return SQL_ERROR; - } - - /* - * Put the row version column at the end so it might not be mistaken - * for a key field. - */ - if (relhasrules[0] != '1' && !stmt->internal && atoi(ci->row_versioning)) - { - /* For Row Versioning fields */ - the_type = PG_TYPE_INT4; - - row = (TupleNode *) malloc(sizeof(TupleNode) + - (result_cols - 1) *sizeof(TupleField)); - - set_tuplefield_string(&row->tuple[0], ""); - if (conn->schema_support) - set_tuplefield_string(&row->tuple[1], GET_SCHEMA_NAME(table_owner)); - else - set_tuplefield_string(&row->tuple[1], ""); - set_tuplefield_string(&row->tuple[2], table_name); - set_tuplefield_string(&row->tuple[3], "xmin"); - sqltype = pgtype_to_concise_type(stmt, the_type); - set_tuplefield_int2(&row->tuple[4], sqltype); - set_tuplefield_string(&row->tuple[5], pgtype_to_name(stmt, the_type)); - set_tuplefield_int4(&row->tuple[6], pgtype_column_size(stmt, the_type, PG_STATIC, PG_STATIC)); - set_tuplefield_int4(&row->tuple[7], pgtype_buffer_length(stmt, the_type, PG_STATIC, PG_STATIC)); - set_nullfield_int2(&row->tuple[8], pgtype_decimal_digits(stmt, the_type, PG_STATIC)); - set_nullfield_int2(&row->tuple[9], pgtype_radix(stmt, the_type)); - set_tuplefield_int2(&row->tuple[10], SQL_NO_NULLS); - set_tuplefield_string(&row->tuple[11], ""); -#if (ODBCVER >= 0x0300) - set_tuplefield_null(&row->tuple[12]); - set_tuplefield_int2(&row->tuple[13], sqltype); - set_tuplefield_null(&row->tuple[14]); - set_tuplefield_int4(&row->tuple[15], pgtype_transfer_octet_length(stmt, the_type, PG_STATIC, PG_STATIC)); - set_tuplefield_int4(&row->tuple[16], ordinal); - set_tuplefield_string(&row->tuple[17], "No"); -#endif /* ODBCVER */ - set_tuplefield_int4(&row->tuple[reserved_cols], pgtype_display_size(stmt, the_type, PG_STATIC, PG_STATIC)); - set_tuplefield_int4(&row->tuple[reserved_cols + 1], the_type); - - QR_add_tuple(res, row); - ordinal++; - } - - /* - * also, things need to think that this statement is finished so the - * results can be retrieved. - */ - stmt->status = STMT_FINISHED; - - /* set up the current tuple pointer for SQLFetch */ - stmt->currTuple = -1; - stmt->rowset_start = -1; - stmt->current_col = -1; - - PGAPI_FreeStmt(hcol_stmt, SQL_DROP); - mylog("%s: EXIT, stmt=%u\n", func, stmt); - return SQL_SUCCESS; -} - - -RETCODE SQL_API -PGAPI_SpecialColumns( - HSTMT hstmt, - UWORD fColType, - UCHAR FAR * szTableQualifier, - SWORD cbTableQualifier, - UCHAR FAR * szTableOwner, - SWORD cbTableOwner, - UCHAR FAR * szTableName, - SWORD cbTableName, - UWORD fScope, - UWORD fNullable) -{ - static char *func = "PGAPI_SpecialColumns"; - TupleNode *row; - StatementClass *stmt = (StatementClass *) hstmt; - ConnectionClass *conn; - QResultClass *res; - ConnInfo *ci; - HSTMT hcol_stmt; - StatementClass *col_stmt; - char columns_query[INFO_INQUIRY_LEN]; - RETCODE result; - char relhasrules[MAX_INFO_STRING]; - - mylog("%s: entering...stmt=%u scnm=%x len=%d colType=%d\n", func, stmt, szTableOwner, cbTableOwner, fColType); - - if (!stmt) - { - SC_log_error(func, "", NULL); - return SQL_INVALID_HANDLE; - } - conn = SC_get_conn(stmt); - ci = &(conn->connInfo); - - stmt->manual_result = TRUE; - - /* - * Create the query to find out if this is a view or not... - */ - if (conn->schema_support) - sprintf(columns_query, "select c.relhasrules " - "from pg_namespace u, pg_class c where " - "u.oid = c.relnamespace"); - else - sprintf(columns_query, "select c.relhasrules " - "from pg_user u, pg_class c where " - "u.usesysid = c.relowner"); - - /* TableName cannot contain a string search pattern */ - my_strcat(columns_query, " and c.relname = '%.*s'", szTableName, cbTableName); - /* SchemaName cannot contain a string search pattern */ - if (conn->schema_support) - schema_strcat(columns_query, " and u.nspname = '%.*s'", szTableOwner, cbTableOwner, szTableName, cbTableName, conn); - else - my_strcat(columns_query, " and u.usename = '%.*s'", szTableOwner, cbTableOwner); - - - result = PGAPI_AllocStmt(stmt->hdbc, &hcol_stmt); - if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) - { - stmt->errornumber = STMT_NO_MEMORY_ERROR; - stmt->errormsg = "Couldn't allocate statement for SQLSpecialColumns result."; - SC_log_error(func, "", stmt); - return SQL_ERROR; - } - col_stmt = (StatementClass *) hcol_stmt; - - mylog("%s: hcol_stmt = %u, col_stmt = %u\n", func, hcol_stmt, col_stmt); - - result = PGAPI_ExecDirect(hcol_stmt, columns_query, - strlen(columns_query)); - if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) - { - stmt->errormsg = SC_create_errormsg(hcol_stmt); - stmt->errornumber = col_stmt->errornumber; - SC_log_error(func, "", stmt); - PGAPI_FreeStmt(hcol_stmt, SQL_DROP); - return SQL_ERROR; - } - - result = PGAPI_BindCol(hcol_stmt, 1, SQL_C_CHAR, - relhasrules, MAX_INFO_STRING, NULL); - if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) - { - stmt->errormsg = col_stmt->errormsg; - stmt->errornumber = col_stmt->errornumber; - SC_log_error(func, "", stmt); - PGAPI_FreeStmt(hcol_stmt, SQL_DROP); - return SQL_ERROR; - } - - result = PGAPI_Fetch(hcol_stmt); - PGAPI_FreeStmt(hcol_stmt, SQL_DROP); - - res = QR_Constructor(); - SC_set_Result(stmt, res); - extend_column_bindings(SC_get_ARD(stmt), 8); - - QR_set_num_fields(res, 8); - QR_set_field_info(res, 0, "SCOPE", PG_TYPE_INT2, 2); - QR_set_field_info(res, 1, "COLUMN_NAME", PG_TYPE_TEXT, MAX_INFO_STRING); - QR_set_field_info(res, 2, "DATA_TYPE", PG_TYPE_INT2, 2); - QR_set_field_info(res, 3, "TYPE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING); - QR_set_field_info(res, 4, "PRECISION", PG_TYPE_INT4, 4); - QR_set_field_info(res, 5, "LENGTH", PG_TYPE_INT4, 4); - QR_set_field_info(res, 6, "SCALE", PG_TYPE_INT2, 2); - QR_set_field_info(res, 7, "PSEUDO_COLUMN", PG_TYPE_INT2, 2); - - if (relhasrules[0] != '1') - { - /* use the oid value for the rowid */ - if (fColType == SQL_BEST_ROWID) - { - row = (TupleNode *) malloc(sizeof(TupleNode) + (8 - 1) *sizeof(TupleField)); - - set_tuplefield_int2(&row->tuple[0], SQL_SCOPE_SESSION); - set_tuplefield_string(&row->tuple[1], "oid"); - set_tuplefield_int2(&row->tuple[2], pgtype_to_concise_type(stmt, PG_TYPE_OID)); - set_tuplefield_string(&row->tuple[3], "OID"); - set_tuplefield_int4(&row->tuple[4], pgtype_column_size(stmt, PG_TYPE_OID, PG_STATIC, PG_STATIC)); - set_tuplefield_int4(&row->tuple[5], pgtype_buffer_length(stmt, PG_TYPE_OID, PG_STATIC, PG_STATIC)); - set_tuplefield_int2(&row->tuple[6], pgtype_decimal_digits(stmt, PG_TYPE_OID, PG_STATIC)); - set_tuplefield_int2(&row->tuple[7], SQL_PC_PSEUDO); - - QR_add_tuple(res, row); - - } - else if (fColType == SQL_ROWVER) - { - Int2 the_type = PG_TYPE_INT4; - - if (atoi(ci->row_versioning)) - { - row = (TupleNode *) malloc(sizeof(TupleNode) + (8 - 1) *sizeof(TupleField)); - - set_tuplefield_null(&row->tuple[0]); - set_tuplefield_string(&row->tuple[1], "xmin"); - set_tuplefield_int2(&row->tuple[2], pgtype_to_concise_type(stmt, the_type)); - set_tuplefield_string(&row->tuple[3], pgtype_to_name(stmt, the_type)); - set_tuplefield_int4(&row->tuple[4], pgtype_column_size(stmt, the_type, PG_STATIC, PG_STATIC)); - set_tuplefield_int4(&row->tuple[5], pgtype_buffer_length(stmt, the_type, PG_STATIC, PG_STATIC)); - set_tuplefield_int2(&row->tuple[6], pgtype_decimal_digits(stmt, the_type, PG_STATIC)); - set_tuplefield_int2(&row->tuple[7], SQL_PC_PSEUDO); - - QR_add_tuple(res, row); - } - } - } - else - { - /* use the oid value for the rowid */ - if (fColType == SQL_BEST_ROWID) - { - row = (TupleNode *) malloc(sizeof(TupleNode) + (8 - 1) *sizeof(TupleField)); - - set_tuplefield_int2(&row->tuple[0], SQL_SCOPE_SESSION); - set_tuplefield_string(&row->tuple[1], "oid"); - set_tuplefield_int2(&row->tuple[2], pgtype_to_concise_type(stmt, PG_TYPE_OID)); - set_tuplefield_string(&row->tuple[3], "OID"); - set_tuplefield_int4(&row->tuple[4], pgtype_column_size(stmt, PG_TYPE_OID, PG_STATIC, PG_STATIC)); - set_tuplefield_int4(&row->tuple[5], pgtype_buffer_length(stmt, PG_TYPE_OID, PG_STATIC, PG_STATIC)); - set_tuplefield_int2(&row->tuple[6], pgtype_decimal_digits(stmt, PG_TYPE_OID, PG_STATIC)); - set_tuplefield_int2(&row->tuple[7], SQL_PC_NOT_PSEUDO); - - QR_add_tuple(res, row); - - } - else if (fColType == SQL_ROWVER) - { - Int2 the_type = PG_TYPE_TID; - - row = (TupleNode *) malloc(sizeof(TupleNode) + (8 - 1) *sizeof(TupleField)); - - set_tuplefield_null(&row->tuple[0]); - set_tuplefield_string(&row->tuple[1], "ctid"); - set_tuplefield_int2(&row->tuple[2], pgtype_to_concise_type(stmt, the_type)); - set_tuplefield_string(&row->tuple[3], pgtype_to_name(stmt, the_type)); - set_tuplefield_int4(&row->tuple[4], pgtype_column_size(stmt, the_type, PG_STATIC, PG_STATIC)); - set_tuplefield_int4(&row->tuple[5], pgtype_buffer_length(stmt, the_type, PG_STATIC, PG_STATIC)); - set_tuplefield_int2(&row->tuple[6], pgtype_decimal_digits(stmt, the_type, PG_STATIC)); - set_tuplefield_int2(&row->tuple[7], SQL_PC_NOT_PSEUDO); - - QR_add_tuple(res, row); - } - } - - stmt->status = STMT_FINISHED; - stmt->currTuple = -1; - stmt->rowset_start = -1; - stmt->current_col = -1; - - mylog("%s: EXIT, stmt=%u\n", func, stmt); - return SQL_SUCCESS; -} - - -RETCODE SQL_API -PGAPI_Statistics( - HSTMT hstmt, - UCHAR FAR * szTableQualifier, - SWORD cbTableQualifier, - UCHAR FAR * szTableOwner, - SWORD cbTableOwner, - UCHAR FAR * szTableName, - SWORD cbTableName, - UWORD fUnique, - UWORD fAccuracy) -{ - static char *func = "PGAPI_Statistics"; - StatementClass *stmt = (StatementClass *) hstmt; - ConnectionClass *conn; - QResultClass *res; - char index_query[INFO_INQUIRY_LEN]; - HSTMT hindx_stmt; - RETCODE result; - char *table_name; - char index_name[MAX_INFO_STRING]; - short fields_vector[16]; - char isunique[10], - isclustered[10], - ishash[MAX_INFO_STRING]; - SDWORD index_name_len, - fields_vector_len; - TupleNode *row; - int i; - HSTMT hcol_stmt; - StatementClass *col_stmt, - *indx_stmt; - char column_name[MAX_INFO_STRING], - table_qualifier[MAX_INFO_STRING], - relhasrules[10]; - char **column_names = 0; - SQLINTEGER column_name_len; - int total_columns = 0; - char error = TRUE; - ConnInfo *ci; - char buf[256]; - - mylog("%s: entering...stmt=%u scnm=%x len=%d\n", func, stmt, szTableOwner, cbTableOwner); - - if (!stmt) - { - SC_log_error(func, "", NULL); - return SQL_INVALID_HANDLE; - } - - stmt->manual_result = TRUE; - stmt->errormsg_created = TRUE; - - conn = SC_get_conn(stmt); - ci = &(conn->connInfo); - - if (res = QR_Constructor(), !res) - { - stmt->errormsg = "Couldn't allocate memory for PGAPI_Statistics result."; - stmt->errornumber = STMT_NO_MEMORY_ERROR; - SC_log_error(func, "", stmt); - return SQL_ERROR; - } - SC_set_Result(stmt, res); - - /* the binding structure for a statement is not set up until */ - - /* - * a statement is actually executed, so we'll have to do this - * ourselves. - */ - extend_column_bindings(SC_get_ARD(stmt), 13); - - /* set the field names */ - QR_set_num_fields(res, 13); - QR_set_field_info(res, 0, "TABLE_QUALIFIER", PG_TYPE_TEXT, MAX_INFO_STRING); - QR_set_field_info(res, 1, "TABLE_OWNER", PG_TYPE_TEXT, MAX_INFO_STRING); - QR_set_field_info(res, 2, "TABLE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING); - QR_set_field_info(res, 3, "NON_UNIQUE", PG_TYPE_INT2, 2); - QR_set_field_info(res, 4, "INDEX_QUALIFIER", PG_TYPE_TEXT, MAX_INFO_STRING); - QR_set_field_info(res, 5, "INDEX_NAME", PG_TYPE_TEXT, MAX_INFO_STRING); - QR_set_field_info(res, 6, "TYPE", PG_TYPE_INT2, 2); - QR_set_field_info(res, 7, "SEQ_IN_INDEX", PG_TYPE_INT2, 2); - QR_set_field_info(res, 8, "COLUMN_NAME", PG_TYPE_TEXT, MAX_INFO_STRING); - QR_set_field_info(res, 9, "COLLATION", PG_TYPE_CHAR, 1); - QR_set_field_info(res, 10, "CARDINALITY", PG_TYPE_INT4, 4); - QR_set_field_info(res, 11, "PAGES", PG_TYPE_INT4, 4); - QR_set_field_info(res, 12, "FILTER_CONDITION", PG_TYPE_TEXT, MAX_INFO_STRING); - - /* - * only use the table name... the owner should be redundant, and we - * never use qualifiers. - */ - table_name = make_string(szTableName, cbTableName, NULL); - if (!table_name) - { - stmt->errormsg = "No table name passed to PGAPI_Statistics."; - stmt->errornumber = STMT_INTERNAL_ERROR; - SC_log_error(func, "", stmt); - return SQL_ERROR; - } - table_qualifier[0] = '\0'; - if (conn->schema_support) - schema_strcat(table_qualifier, "%.*s", szTableOwner, cbTableOwner, szTableName, cbTableName, conn); - - /* - * we need to get a list of the field names first, so we can return - * them later. - */ - result = PGAPI_AllocStmt(stmt->hdbc, &hcol_stmt); - if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) - { - stmt->errormsg = "PGAPI_AllocStmt failed in PGAPI_Statistics for columns."; - stmt->errornumber = STMT_NO_MEMORY_ERROR; - goto SEEYA; - } - - col_stmt = (StatementClass *) hcol_stmt; - - /* - * "internal" prevents SQLColumns from returning the oid if it is - * being shown. This would throw everything off. - */ - col_stmt->internal = TRUE; - /* - * table_name parameter cannot contain a string search pattern. - */ - result = PGAPI_Columns(hcol_stmt, "", 0, table_qualifier, SQL_NTS, - table_name, SQL_NTS, "", 0, PODBC_NOT_SEARCH_PATTERN); - col_stmt->internal = FALSE; - - if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) - { - stmt->errormsg = col_stmt->errormsg; /* "SQLColumns failed in - * SQLStatistics."; */ - stmt->errornumber = col_stmt->errornumber; /* STMT_EXEC_ERROR; */ - PGAPI_FreeStmt(hcol_stmt, SQL_DROP); - goto SEEYA; - } - result = PGAPI_BindCol(hcol_stmt, 4, SQL_C_CHAR, - column_name, sizeof(column_name), &column_name_len); - if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) - { - stmt->errormsg = col_stmt->errormsg; - stmt->errornumber = col_stmt->errornumber; - PGAPI_FreeStmt(hcol_stmt, SQL_DROP); - goto SEEYA; - - } - - result = PGAPI_Fetch(hcol_stmt); - while ((result == SQL_SUCCESS) || (result == SQL_SUCCESS_WITH_INFO)) - { - total_columns++; - - column_names = - (char **) realloc(column_names, - total_columns * sizeof(char *)); - column_names[total_columns - 1] = - (char *) malloc(strlen(column_name) + 1); - strcpy(column_names[total_columns - 1], column_name); - - mylog("%s: column_name = '%s'\n", func, column_name); - - result = PGAPI_Fetch(hcol_stmt); - } - - if (result != SQL_NO_DATA_FOUND || total_columns == 0) - { - stmt->errormsg = SC_create_errormsg(hcol_stmt); /* "Couldn't get column - * names in - * SQLStatistics."; */ - stmt->errornumber = col_stmt->errornumber; - PGAPI_FreeStmt(hcol_stmt, SQL_DROP); - goto SEEYA; - - } - - PGAPI_FreeStmt(hcol_stmt, SQL_DROP); - - /* get a list of indexes on this table */ - result = PGAPI_AllocStmt(stmt->hdbc, &hindx_stmt); - if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) - { - stmt->errormsg = "PGAPI_AllocStmt failed in SQLStatistics for indices."; - stmt->errornumber = STMT_NO_MEMORY_ERROR; - goto SEEYA; - - } - indx_stmt = (StatementClass *) hindx_stmt; - - if (conn->schema_support) - sprintf(index_query, "select c.relname, i.indkey, i.indisunique" - ", i.indisclustered, a.amname, c.relhasrules, n.nspname" - " from pg_index i, pg_class c, pg_class d, pg_am a, pg_namespace n" - " where d.relname = '%s'" - " and n.nspname = '%s'" - " and n.oid = d.relnamespace" - " and d.oid = i.indrelid" - " and i.indexrelid = c.oid" - " and c.relam = a.oid order by" - ,table_name, table_qualifier); - else - sprintf(index_query, "select c.relname, i.indkey, i.indisunique" - ", i.indisclustered, a.amname, c.relhasrules" - " from pg_index i, pg_class c, pg_class d, pg_am a" - " where d.relname = '%s'" - " and d.oid = i.indrelid" - " and i.indexrelid = c.oid" - " and c.relam = a.oid order by" - ,table_name); - if (PG_VERSION_GT(SC_get_conn(stmt), 6.4)) - strcat(index_query, " i.indisprimary desc,"); - if (conn->schema_support) - strcat(index_query, " i.indisunique, n.nspname, c.relname"); - else - strcat(index_query, " i.indisunique, c.relname"); - - result = PGAPI_ExecDirect(hindx_stmt, index_query, strlen(index_query)); - if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) - { - /* - * "Couldn't execute index query (w/SQLExecDirect) in - * SQLStatistics."; - */ - stmt->errormsg = SC_create_errormsg(hindx_stmt); - - stmt->errornumber = indx_stmt->errornumber; - PGAPI_FreeStmt(hindx_stmt, SQL_DROP); - goto SEEYA; - } - - /* bind the index name column */ - result = PGAPI_BindCol(hindx_stmt, 1, SQL_C_CHAR, - index_name, MAX_INFO_STRING, &index_name_len); - if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) - { - stmt->errormsg = indx_stmt->errormsg; /* "Couldn't bind column - * in SQLStatistics."; */ - stmt->errornumber = indx_stmt->errornumber; - PGAPI_FreeStmt(hindx_stmt, SQL_DROP); - goto SEEYA; - - } - /* bind the vector column */ - result = PGAPI_BindCol(hindx_stmt, 2, SQL_C_DEFAULT, - fields_vector, 32, &fields_vector_len); - if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) - { - stmt->errormsg = indx_stmt->errormsg; /* "Couldn't bind column - * in SQLStatistics."; */ - stmt->errornumber = indx_stmt->errornumber; - PGAPI_FreeStmt(hindx_stmt, SQL_DROP); - goto SEEYA; - - } - /* bind the "is unique" column */ - result = PGAPI_BindCol(hindx_stmt, 3, SQL_C_CHAR, - isunique, sizeof(isunique), NULL); - if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) - { - stmt->errormsg = indx_stmt->errormsg; /* "Couldn't bind column - * in SQLStatistics."; */ - stmt->errornumber = indx_stmt->errornumber; - PGAPI_FreeStmt(hindx_stmt, SQL_DROP); - goto SEEYA; - } - - /* bind the "is clustered" column */ - result = PGAPI_BindCol(hindx_stmt, 4, SQL_C_CHAR, - isclustered, sizeof(isclustered), NULL); - if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) - { - stmt->errormsg = indx_stmt->errormsg; /* "Couldn't bind column - * in SQLStatistics."; */ - stmt->errornumber = indx_stmt->errornumber; - PGAPI_FreeStmt(hindx_stmt, SQL_DROP); - goto SEEYA; - - } - - /* bind the "is hash" column */ - result = PGAPI_BindCol(hindx_stmt, 5, SQL_C_CHAR, - ishash, sizeof(ishash), NULL); - if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) - { - stmt->errormsg = indx_stmt->errormsg; /* "Couldn't bind column - * in SQLStatistics."; */ - stmt->errornumber = indx_stmt->errornumber; - PGAPI_FreeStmt(hindx_stmt, SQL_DROP); - goto SEEYA; - - } - - result = PGAPI_BindCol(hindx_stmt, 6, SQL_C_CHAR, - relhasrules, sizeof(relhasrules), NULL); - if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) - { - stmt->errormsg = indx_stmt->errormsg; - stmt->errornumber = indx_stmt->errornumber; - PGAPI_FreeStmt(hindx_stmt, SQL_DROP); - goto SEEYA; - } - - /* fake index of OID */ - if (relhasrules[0] != '1' && atoi(ci->show_oid_column) && atoi(ci->fake_oid_index)) - { - row = (TupleNode *) malloc(sizeof(TupleNode) + - (13 - 1) *sizeof(TupleField)); - - /* no table qualifier */ - set_tuplefield_string(&row->tuple[0], ""); - /* don't set the table owner, else Access tries to use it */ - set_tuplefield_string(&row->tuple[1], GET_SCHEMA_NAME(table_qualifier)); - set_tuplefield_string(&row->tuple[2], table_name); - - /* non-unique index? */ - set_tuplefield_int2(&row->tuple[3], (Int2) (ci->drivers.unique_index ? FALSE : TRUE)); - - /* no index qualifier */ - set_tuplefield_string(&row->tuple[4], ""); - - sprintf(buf, "%s_idx_fake_oid", table_name); - set_tuplefield_string(&row->tuple[5], buf); - - /* - * Clustered/HASH index? - */ - set_tuplefield_int2(&row->tuple[6], (Int2) SQL_INDEX_OTHER); - set_tuplefield_int2(&row->tuple[7], (Int2) 1); - - set_tuplefield_string(&row->tuple[8], "oid"); - set_tuplefield_string(&row->tuple[9], "A"); - set_tuplefield_null(&row->tuple[10]); - set_tuplefield_null(&row->tuple[11]); - set_tuplefield_null(&row->tuple[12]); - - QR_add_tuple(res, row); - } - - result = PGAPI_Fetch(hindx_stmt); - while ((result == SQL_SUCCESS) || (result == SQL_SUCCESS_WITH_INFO)) - { - /* If only requesting unique indexs, then just return those. */ - if (fUnique == SQL_INDEX_ALL || - (fUnique == SQL_INDEX_UNIQUE && atoi(isunique))) - { - i = 0; - /* add a row in this table for each field in the index */ - while (i < 16 && fields_vector[i] != 0) - { - row = (TupleNode *) malloc(sizeof(TupleNode) + - (13 - 1) *sizeof(TupleField)); - - /* no table qualifier */ - set_tuplefield_string(&row->tuple[0], ""); - /* don't set the table owner, else Access tries to use it */ - set_tuplefield_string(&row->tuple[1], GET_SCHEMA_NAME(table_qualifier)); - set_tuplefield_string(&row->tuple[2], table_name); - - /* non-unique index? */ - if (ci->drivers.unique_index) - set_tuplefield_int2(&row->tuple[3], (Int2) (atoi(isunique) ? FALSE : TRUE)); - else - set_tuplefield_int2(&row->tuple[3], TRUE); - - /* no index qualifier */ - set_tuplefield_string(&row->tuple[4], ""); - set_tuplefield_string(&row->tuple[5], index_name); - - /* - * Clustered/HASH index? - */ - set_tuplefield_int2(&row->tuple[6], (Int2) - (atoi(isclustered) ? SQL_INDEX_CLUSTERED : - (!strncmp(ishash, "hash", 4)) ? SQL_INDEX_HASHED : SQL_INDEX_OTHER)); - set_tuplefield_int2(&row->tuple[7], (Int2) (i + 1)); - - if (fields_vector[i] == OID_ATTNUM) - { - set_tuplefield_string(&row->tuple[8], "oid"); - mylog("%s: column name = oid\n", func); - } - else if (fields_vector[i] < 0 || fields_vector[i] > total_columns) - { - set_tuplefield_string(&row->tuple[8], "UNKNOWN"); - mylog("%s: column name = UNKNOWN\n", func); - } - else - { - set_tuplefield_string(&row->tuple[8], column_names[fields_vector[i] - 1]); - mylog("%s: column name = '%s'\n", func, column_names[fields_vector[i] - 1]); - } - - set_tuplefield_string(&row->tuple[9], "A"); - set_tuplefield_null(&row->tuple[10]); - set_tuplefield_null(&row->tuple[11]); - set_tuplefield_null(&row->tuple[12]); - - QR_add_tuple(res, row); - i++; - } - } - - result = PGAPI_Fetch(hindx_stmt); - } - if (result != SQL_NO_DATA_FOUND) - { - /* "SQLFetch failed in SQLStatistics."; */ - stmt->errormsg = SC_create_errormsg(hindx_stmt); - stmt->errornumber = indx_stmt->errornumber; - PGAPI_FreeStmt(hindx_stmt, SQL_DROP); - goto SEEYA; - } - - PGAPI_FreeStmt(hindx_stmt, SQL_DROP); - - /* - * also, things need to think that this statement is finished so the - * results can be retrieved. - */ - stmt->status = STMT_FINISHED; - - /* set up the current tuple pointer for SQLFetch */ - stmt->currTuple = -1; - stmt->rowset_start = -1; - stmt->current_col = -1; - - error = FALSE; - -SEEYA: - /* These things should be freed on any error ALSO! */ - free(table_name); - for (i = 0; i < total_columns; i++) - free(column_names[i]); - free(column_names); - - mylog("%s: EXIT, %s, stmt=%u\n", func, error ? "error" : "success", stmt); - - if (error) - { - SC_log_error(func, "", stmt); - return SQL_ERROR; - } - else - return SQL_SUCCESS; -} - - -RETCODE SQL_API -PGAPI_ColumnPrivileges( - HSTMT hstmt, - UCHAR FAR * szTableQualifier, - SWORD cbTableQualifier, - UCHAR FAR * szTableOwner, - SWORD cbTableOwner, - UCHAR FAR * szTableName, - SWORD cbTableName, - UCHAR FAR * szColumnName, - SWORD cbColumnName) -{ - static char *func = "PGAPI_ColumnPrivileges"; - StatementClass *stmt = (StatementClass *) hstmt; - - mylog("%s: entering...\n", func); - - /* Neither Access or Borland care about this. */ - - stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR; - stmt->errormsg = "not implemented"; - SC_log_error(func, "Function not implemented", stmt); - return SQL_ERROR; -} - - -/* - * SQLPrimaryKeys() - * - * Retrieve the primary key columns for the specified table. - */ -RETCODE SQL_API -PGAPI_PrimaryKeys( - HSTMT hstmt, - UCHAR FAR * szTableQualifier, - SWORD cbTableQualifier, - UCHAR FAR * szTableOwner, - SWORD cbTableOwner, - UCHAR FAR * szTableName, - SWORD cbTableName) -{ - static char *func = "PGAPI_PrimaryKeys"; - StatementClass *stmt = (StatementClass *) hstmt; - QResultClass *res; - ConnectionClass *conn; - TupleNode *row; - RETCODE result; - int seq = 0; - HSTMT htbl_stmt; - StatementClass *tbl_stmt; - char tables_query[INFO_INQUIRY_LEN]; - char attname[MAX_INFO_STRING]; - SDWORD attname_len; - char pktab[MAX_TABLE_LEN + 1], pkscm[MAX_TABLE_LEN + 1]; - Int2 result_cols; - int qno, - qstart, - qend; - - mylog("%s: entering...stmt=%u scnm=%x len=%d\n", func, stmt, szTableOwner, cbTableOwner); - - if (!stmt) - { - SC_log_error(func, "", NULL); - return SQL_INVALID_HANDLE; - } - stmt->manual_result = TRUE; - stmt->errormsg_created = TRUE; - - if (res = QR_Constructor(), !res) - { - stmt->errormsg = "Couldn't allocate memory for PGAPI_PrimaryKeys result."; - stmt->errornumber = STMT_NO_MEMORY_ERROR; - SC_log_error(func, "", stmt); - return SQL_ERROR; - } - SC_set_Result(stmt, res); - - /* the binding structure for a statement is not set up until */ - - /* - * a statement is actually executed, so we'll have to do this - * ourselves. - */ - result_cols = 6; - extend_column_bindings(SC_get_ARD(stmt), result_cols); - - /* set the field names */ - QR_set_num_fields(res, result_cols); - QR_set_field_info(res, 0, "TABLE_QUALIFIER", PG_TYPE_TEXT, MAX_INFO_STRING); - QR_set_field_info(res, 1, "TABLE_OWNER", PG_TYPE_TEXT, MAX_INFO_STRING); - QR_set_field_info(res, 2, "TABLE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING); - QR_set_field_info(res, 3, "COLUMN_NAME", PG_TYPE_TEXT, MAX_INFO_STRING); - QR_set_field_info(res, 4, "KEY_SEQ", PG_TYPE_INT2, 2); - QR_set_field_info(res, 5, "PK_NAME", PG_TYPE_TEXT, MAX_INFO_STRING); - - - result = PGAPI_AllocStmt(stmt->hdbc, &htbl_stmt); - if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) - { - stmt->errornumber = STMT_NO_MEMORY_ERROR; - stmt->errormsg = "Couldn't allocate statement for Primary Key result."; - SC_log_error(func, "", stmt); - return SQL_ERROR; - } - tbl_stmt = (StatementClass *) htbl_stmt; - - conn = SC_get_conn(stmt); - pktab[0] = '\0'; - make_string(szTableName, cbTableName, pktab); - if (pktab[0] == '\0') - { - stmt->errormsg = "No Table specified to PGAPI_PrimaryKeys."; - stmt->errornumber = STMT_INTERNAL_ERROR; - SC_log_error(func, "", stmt); - PGAPI_FreeStmt(htbl_stmt, SQL_DROP); - return SQL_ERROR; - } - pkscm[0] = '\0'; - if (conn->schema_support) - schema_strcat(pkscm, "%.*s", szTableOwner, cbTableOwner, szTableName, cbTableName, conn); - - result = PGAPI_BindCol(htbl_stmt, 1, SQL_C_CHAR, - attname, MAX_INFO_STRING, &attname_len); - if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) - { - stmt->errormsg = tbl_stmt->errormsg; - stmt->errornumber = tbl_stmt->errornumber; - SC_log_error(func, "", stmt); - PGAPI_FreeStmt(htbl_stmt, SQL_DROP); - return SQL_ERROR; - } - - if (PG_VERSION_LE(conn, 6.4)) - qstart = 2; - else - qstart = 1; - qend = 2; - for (qno = qstart; qno <= qend; qno++) - { - switch (qno) - { - case 1: - - /* - * Simplified query to remove assumptions about number of - * possible index columns. Courtesy of Tom Lane - thomas - * 2000-03-21 - */ - if (conn->schema_support) - sprintf(tables_query, "select ta.attname, ia.attnum" - " from pg_attribute ta, pg_attribute ia, pg_class c, pg_index i, pg_namespace n" - " where c.relname = '%s'" - " AND n.nspname = '%s'" - " AND c.oid = i.indrelid" - " AND n.oid = c.relnamespace" - " AND i.indisprimary = 't'" - " AND ia.attrelid = i.indexrelid" - " AND ta.attrelid = i.indrelid" - " AND ta.attnum = i.indkey[ia.attnum-1]" - " order by ia.attnum", pktab, pkscm); - else - sprintf(tables_query, "select ta.attname, ia.attnum" - " from pg_attribute ta, pg_attribute ia, pg_class c, pg_index i" - " where c.relname = '%s'" - " AND c.oid = i.indrelid" - " AND i.indisprimary = 't'" - " AND ia.attrelid = i.indexrelid" - " AND ta.attrelid = i.indrelid" - " AND ta.attnum = i.indkey[ia.attnum-1]" - " order by ia.attnum", pktab); - break; - case 2: - - /* - * Simplified query to search old fashoned primary key - */ - if (conn->schema_support) - sprintf(tables_query, "select ta.attname, ia.attnum" - " from pg_attribute ta, pg_attribute ia, pg_class c, pg_index i, pg_namespace n" - " where c.relname = '%s_pkey'" - " AND n.nspname = '%s'" - " AND c.oid = i.indexrelid" - " AND n.oid = c.relnamespace" - " AND ia.attrelid = i.indexrelid" - " AND ta.attrelid = i.indrelid" - " AND ta.attnum = i.indkey[ia.attnum-1]" - " order by ia.attnum", pktab, pkscm); - else - sprintf(tables_query, "select ta.attname, ia.attnum" - " from pg_attribute ta, pg_attribute ia, pg_class c, pg_index i" - " where c.relname = '%s_pkey'" - " AND c.oid = i.indexrelid" - " AND ia.attrelid = i.indexrelid" - " AND ta.attrelid = i.indrelid" - " AND ta.attnum = i.indkey[ia.attnum-1]" - " order by ia.attnum", pktab); - break; - } - mylog("%s: tables_query='%s'\n", func, tables_query); - - result = PGAPI_ExecDirect(htbl_stmt, tables_query, strlen(tables_query)); - if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) - { - stmt->errormsg = SC_create_errormsg(htbl_stmt); - stmt->errornumber = tbl_stmt->errornumber; - SC_log_error(func, "", stmt); - PGAPI_FreeStmt(htbl_stmt, SQL_DROP); - return SQL_ERROR; - } - - result = PGAPI_Fetch(htbl_stmt); - if (result != SQL_NO_DATA_FOUND) - break; - } - - while ((result == SQL_SUCCESS) || (result == SQL_SUCCESS_WITH_INFO)) - { - row = (TupleNode *) malloc(sizeof(TupleNode) + (result_cols - 1) *sizeof(TupleField)); - - set_tuplefield_null(&row->tuple[0]); - - /* - * I have to hide the table owner from Access, otherwise it - * insists on referring to the table as 'owner.table'. (this is - * valid according to the ODBC SQL grammar, but Postgres won't - * support it.) - */ - set_tuplefield_string(&row->tuple[1], GET_SCHEMA_NAME(pkscm)); - set_tuplefield_string(&row->tuple[2], pktab); - set_tuplefield_string(&row->tuple[3], attname); - set_tuplefield_int2(&row->tuple[4], (Int2) (++seq)); - set_tuplefield_null(&row->tuple[5]); - - QR_add_tuple(res, row); - - mylog(">> primaryKeys: pktab = '%s', attname = '%s', seq = %d\n", pktab, attname, seq); - - result = PGAPI_Fetch(htbl_stmt); - } - - if (result != SQL_NO_DATA_FOUND) - { - stmt->errormsg = SC_create_errormsg(htbl_stmt); - stmt->errornumber = tbl_stmt->errornumber; - SC_log_error(func, "", stmt); - PGAPI_FreeStmt(htbl_stmt, SQL_DROP); - return SQL_ERROR; - } - - PGAPI_FreeStmt(htbl_stmt, SQL_DROP); - - - /* - * also, things need to think that this statement is finished so the - * results can be retrieved. - */ - stmt->status = STMT_FINISHED; - - /* set up the current tuple pointer for SQLFetch */ - stmt->currTuple = -1; - stmt->rowset_start = -1; - stmt->current_col = -1; - - mylog("%s: EXIT, stmt=%u\n", func, stmt); - return SQL_SUCCESS; -} - - -#ifdef MULTIBYTE -/* - * Multibyte support stuff for SQLForeignKeys(). - * There may be much more effective way in the - * future version. The way is very forcible currently. - */ -static BOOL -isMultibyte(const unsigned char *str) -{ - for (; *str; str++) - { - if (*str >= 0x80) - return TRUE; - } - return FALSE; -} -#ifdef NOT_USED -static char * -getClientTableName(ConnectionClass *conn, const char *serverSchemaName, char *serverTableName, BOOL *nameAlloced) -{ - char query[1024], - saveoid[24], - *ret = serverTableName; - BOOL continueExec = TRUE, - bError = FALSE; - QResultClass *res; - - *nameAlloced = FALSE; - if (!conn->client_encoding || !isMultibyte(serverTableName)) - return ret; - if (!conn->server_encoding) - { - if (res = CC_send_query(conn, "select getdatabaseencoding()", NULL, CLEAR_RESULT_ON_ABORT), res) - { - if (QR_get_num_tuples(res) > 0) - conn->server_encoding = strdup(QR_get_value_backend_row(res, 0, 0)); - QR_Destructor(res); - } - } - if (!conn->server_encoding) - return ret; - sprintf(query, "SET CLIENT_ENCODING TO '%s'", conn->server_encoding); - bError = (CC_send_query(conn, query, NULL, CLEAR_RESULT_ON_ABORT) == NULL); - if (!bError && continueExec) - { - if (conn->schema_support) - sprintf(query, "select OID from pg_class where relname = '%s' and pg_namespace.oid = relnamespace and pg_namespace.nspname = '%s'", serverTableName, serverSchemaName); - else - sprintf(query, "select OID from pg_class where relname = '%s'", serverTableName); - if (res = CC_send_query(conn, query, NULL, CLEAR_RESULT_ON_ABORT), res) - { - if (QR_get_num_tuples(res) > 0) - strcpy(saveoid, QR_get_value_backend_row(res, |