mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-09-28 18:11:49 +02:00
Version 06-30-0248
This commit is contained in:
parent
2a67742412
commit
6e66468f3a
44
src/interfaces/odbc/Config.mk
Normal file
44
src/interfaces/odbc/Config.mk
Normal file
@ -0,0 +1,44 @@
|
||||
|
||||
#
|
||||
#
|
||||
#
|
||||
|
||||
#============ Default for all system ==============
|
||||
OS = UNX
|
||||
SHELL = /bin/sh
|
||||
AR = ar r
|
||||
DLSUFFIX= so
|
||||
INCDIR = /include
|
||||
OBJX =
|
||||
RANLIB = ranlib
|
||||
INSTALL = /usr/bin/install
|
||||
INSTALL_DATA = $(INSTALL) -c -m 644
|
||||
MKDIR = mkdir
|
||||
DESTDIR = /usr/local
|
||||
LIBDIR = /lib
|
||||
INSTHEADERS = isql.h isqlext.h iodbc.h
|
||||
DESTLIBDIR = $(DESTDIR)$(LIBDIR)
|
||||
DESTINCDIR = $(DESTDIR)$(INCDIR)/iodbc
|
||||
ODBCSYSTEMDIR = /usr/home/gryschuk
|
||||
|
||||
# Remove the comment characters from the section you want to
|
||||
# use below, make sure all other sections are commented out.
|
||||
|
||||
#============== Linux ELF =========================
|
||||
CC = gcc
|
||||
PIC = -fPIC
|
||||
CFLAGSX = -g
|
||||
#CFLAGSX = -g -Wall -DMY_LOG -DQ_LOG
|
||||
LDFLAGS = -shared
|
||||
LIBS = -ldl
|
||||
|
||||
#============= FreeBSD 2.x ========================
|
||||
# I don't know if this would work but you can always just try it.
|
||||
# PIC = -fPIC
|
||||
# CFLAGSX = -g -Wall
|
||||
# LDFLAGS = -Bshareable
|
||||
# LIBS =
|
||||
|
||||
#===| end of file 'Config.mk' |===
|
||||
|
||||
|
85
src/interfaces/odbc/Makefile.unx
Normal file
85
src/interfaces/odbc/Makefile.unx
Normal file
@ -0,0 +1,85 @@
|
||||
|
||||
# .include "Version.mk"
|
||||
# .include "Config.mk"
|
||||
include Version.mk
|
||||
include Config.mk
|
||||
#==============================================================================
|
||||
# Makefile
|
||||
#
|
||||
# UNIX Makefile to build the CLI for PostgreSQL/Postgres95
|
||||
#
|
||||
#==============================================================================
|
||||
# Site specific configuration (UNIX)
|
||||
#==============================================================================
|
||||
#
|
||||
# option switches
|
||||
#
|
||||
# debug: select this to enable debugging of the software
|
||||
#DEBUG = -D_DEBUG
|
||||
#
|
||||
#==============================================================================
|
||||
|
||||
#---| definitions |------------------------------------------------------------
|
||||
|
||||
# NAME = cli
|
||||
NAME = psqlodbc
|
||||
|
||||
OBJECTS = info.o bind.o columninfo.o connection.o convert.o drvconn.o \
|
||||
environ.o execute.o lobj.o misc.o options.o \
|
||||
pgtypes.o psqlodbc.o qresult.o results.o socket.o statement.o \
|
||||
gpps.o tuple.o tuplelist.o dlg_specific.o $(OBJX)
|
||||
|
||||
#CFLAGS = -c $(DEBUG) -D$(PG_ENV) -O $(PIC) $(ANSI) -I$(PG_INCLUDE) \
|
||||
# -I$(ODBC_INCLUDE) -D$(DLDAPI) $(CFLAGSX) -DHAVE_CONFIG_H \
|
||||
# -DVERSION=\"$(VERSION)$(EXTVER)\"
|
||||
CFLAGS = -g -c -Wall $(DEBUG) -O $(PIC) $(ANSI) -I. -I.. \
|
||||
-I$(PG_INCLUDE) -I$(ODBC_INCLUDE) $(CFLAGSX) -DHAVE_CONFIG_H
|
||||
|
||||
shlib = lib$(NAME)-$(VERSION).$(DLSUFFIX)
|
||||
DESTDIR = /usr/local
|
||||
LIBDIR = /lib
|
||||
|
||||
#---| global dependencies |----------------------------------------------------
|
||||
|
||||
#all: $(OBJECTS) lib dll
|
||||
|
||||
all: $(OBJECTS) dll
|
||||
|
||||
clean:
|
||||
-rm -f core *.o *~ *.core
|
||||
|
||||
delete: clean
|
||||
|
||||
delete_all: delete
|
||||
-rm -f /usr/local/lib/lib$(NAME)_$(MSQL_ENV).a
|
||||
-rm -f /usr/local/lib/lib$(NAME)_$(MSQL_ENV).$(DLSUFFIX)
|
||||
|
||||
#---| local dependencies |-----------------------------------------------------
|
||||
#log.o: ../SRC_LOG/log.c ../SRC_LOG/log.h
|
||||
# $(CC) $(CFLAGS) -I../SRC_LOG ../SRC_LOG/log.c
|
||||
|
||||
lib:
|
||||
$(AR) lib$(NAME)$(PG_ENV).a $(OBJECTS)
|
||||
$(RANLIB) lib$(NAME)$(PG_ENV).a
|
||||
|
||||
dll: $(OBJECTS)
|
||||
$(LD) $(LDFLAGS) -L$(PG_LIBPATH) $(OBJECTS) \
|
||||
-o $(shlib) $(LIBS) $(PG_LIBS)
|
||||
|
||||
install-shlib: $(shlib)
|
||||
$(INSTALL_DATA) $(shlib) $(DESTDIR)$(LIBDIR)/$(shlib)
|
||||
rm -f $(DESTDIR)$(LIBDIR)/lib$(NAME).so
|
||||
ln -sf $(shlib) $(DESTDIR)$(LIBDIR)/lib$(NAME).so
|
||||
|
||||
install-headers: $(INSTHEADERS)
|
||||
if [ -d $(DESTDIR)$(INCDIR)/iodbc ]; then : ; else $(MKDIR) $(DESTDIR)$(INCDIR)/iodbc; fi
|
||||
$(INSTALL_DATA) $(INSTHEADERS) $(DESTDIR)$(INCDIR)/iodbc
|
||||
|
||||
install-ini: odbcinst.ini
|
||||
$(INSTALL_DATA) odbcinst.ini /etc
|
||||
|
||||
install: install-headers install-shlib install-ini
|
||||
|
||||
#==============================================================================
|
||||
|
||||
|
113
src/interfaces/odbc/README.Linux
Normal file
113
src/interfaces/odbc/README.Linux
Normal file
@ -0,0 +1,113 @@
|
||||
|
||||
Unix port of psqlodbc, brought to you by:
|
||||
Gerald Gryschuk(ggryschuk@home.com)
|
||||
|
||||
This is the first release of a port of psqlodbc to Unix(specifically Linux),
|
||||
as such the installation may not be as straight forward as it could be(then
|
||||
again it might be). As well the only testing of the driver has been with
|
||||
the real project I'm working on, since it seems to be working there I assumed
|
||||
it was ready to go out. This port works with Ke Jin's iodbc driver manager
|
||||
although there is no theoretical reason why it couldn't work with other
|
||||
driver managers for UNIX(I know of none though). The FreeODBC site
|
||||
(http://users.ids.net/~bjepson/freeODBC/) has a link to download the current
|
||||
version of iodbc(iodbc-2.12).
|
||||
|
||||
This driver has been successfully compiled and tested on a RedHat 4.1 system
|
||||
using both gcc 2.7.2 and egcs 1.0.2.
|
||||
|
||||
INSTALLATION:
|
||||
|
||||
If you have a system any where close to mine this will be easy, just
|
||||
copy Makefile.lnx to Makefile then type 'make' and see what happens. Note
|
||||
that if you have not enabled logging(read the file misc.h) then you
|
||||
may get alot of warning messages, just ignore these, they shouldn't be
|
||||
a problem. If this doesn't work, well... I don't know what to say, see if
|
||||
you can figure out what's wrong,fix it and send me a message. If everything
|
||||
makes o.k. you can 'make install' which will install the shared library
|
||||
(in /usr/local/lib) and a WINDOWS type INI file in /etc (called odbcinst.ini,
|
||||
see CONFIGURATION below). If you want to program using this driver do a
|
||||
'make install-headers' which will install programming header files in
|
||||
/usr/local/include/iodbc. If you don't like these install locations edit
|
||||
Config.mk and change the environment variable DESTDIR(and possible DESTINCDIR
|
||||
to get rid of the /iodbc) to suit your system.
|
||||
|
||||
CONFIGURATION:
|
||||
|
||||
The psqlodbc driver reads two Windows type INI files for configuration,
|
||||
one called odbcinst.ini located in /etc which is used for system wide
|
||||
configuration of the driver and one in the users home directory called
|
||||
.odbc.ini, which can be used to override the system wide settings. Note that
|
||||
the location of odbcinst is currently hardcoded into the source so if you
|
||||
want to change this you have to change it in the source as well. This latter
|
||||
file is also searched for by iodbc and is where
|
||||
the DataSource definitions are placed. The format of both files is exactly
|
||||
like that of a Windows INI file using key,value pairs. A DataSource definition
|
||||
is started with a section name enclosed in square brackets i.e. [PostODBC].
|
||||
Comments are started using a ';' character and are restricted to being
|
||||
only on seperate lines(i.e. no comments are allowed on definition lines).
|
||||
The important keywords for psqlodbc are:
|
||||
Driver = (location where the psqlodbc library was installed)
|
||||
ex. Driver = /usr/local/lib/libpspqlodbc.so
|
||||
|
||||
ServerName = hostname or ip-address of postgreSQL server
|
||||
ex. ServerName = simpsons.springfield.com
|
||||
or ServerName = 192.1.1.1
|
||||
|
||||
Database = name of database to connect to
|
||||
ex. Database = template1
|
||||
|
||||
Port = tcp port that the postgreSQL server is listening on, note
|
||||
that this need not be set as the driver defaults to the
|
||||
default postgreSQL port of 5432. Of course if your server
|
||||
is listening on a different port than you need to say
|
||||
what it is here.
|
||||
|
||||
Username = name of authorized postgreSQL user
|
||||
ex. Username = homer
|
||||
|
||||
Password = the password for the user named in Username. Note
|
||||
that if you have password checking on in postgreSQL
|
||||
you have to have this field. Unfortunately this means
|
||||
storing clear text passwords in a file. If this bothers
|
||||
you, well... write a dialog box routine and send it
|
||||
to me.
|
||||
ex. Password = Doh!
|
||||
|
||||
ReadOnly = 0 or 1. Default is 1 => database IS readonly. If
|
||||
set to 0, database is read-write.
|
||||
ex. ReadOnly = 0
|
||||
|
||||
Protocol = 6.2 to force the use of Postgres 6.2 protocol
|
||||
|
||||
The odbcinst.ini file is where sytem wide settings are kept. There are
|
||||
quite a number of these, all of which have built-in defaults. Since I'm
|
||||
not even sure what they are all for I won't try to describe them, check
|
||||
the file dlg_specific.h for a list and some explanation. Two that I found
|
||||
useful are Debug and CommLog, which can be used to tailor logging of messages
|
||||
by the driver(note that you have to have defined MY_LOG and Q_LOG during
|
||||
compilation of the driver, see the file misc.h for an explanation). If
|
||||
you have logging On(ie. CommLog = 1 and/or Debug = 1) then logging will
|
||||
occur to the files /tmp/mylog.log(Debug, only developers will be
|
||||
interested) and /tmp/psqlodbc.log(end user log file).
|
||||
|
||||
USE:
|
||||
run an ODBC enabled application :-) .
|
||||
|
||||
O.k. Well, the only ODBC compliant applications that I can
|
||||
"guarantee" to work are those that are compiled using the following
|
||||
headers that come with this driver, iodbc.h, isql.h and isqlext.h.
|
||||
|
||||
BUGS,etc.
|
||||
|
||||
If you have problems with compiling/installing or making this
|
||||
package send e-mail to me at:
|
||||
gerald.gryschuk@home.com or to the pgsql-interfaces mailing list
|
||||
pgsql-interfaces@postgresql.org .
|
||||
|
||||
Ports to different Unices are greatly appreciated and can probably be
|
||||
sent to me for now(although this may change shortly).
|
||||
|
||||
Bugs of a general nature should still be sent to the current
|
||||
maintainer or to the interfaces list.
|
||||
|
||||
|
3
src/interfaces/odbc/Version.mk
Normal file
3
src/interfaces/odbc/Version.mk
Normal file
@ -0,0 +1,3 @@
|
||||
VERSION = 0.24
|
||||
EXTVER = .2
|
||||
|
@ -12,6 +12,11 @@
|
||||
* Comments: See "notice.txt" for copyright and license information.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include "bind.h"
|
||||
#include "environ.h"
|
||||
#include "statement.h"
|
||||
@ -19,8 +24,15 @@
|
||||
#include "pgtypes.h"
|
||||
#include <stdlib.h>
|
||||
#include <malloc.h>
|
||||
|
||||
#ifdef HAVE_IODBC
|
||||
#include "iodbc.h"
|
||||
#include "isql.h"
|
||||
#include "isqlext.h"
|
||||
#else
|
||||
#include <sql.h>
|
||||
#include <sqlext.h>
|
||||
#endif
|
||||
|
||||
// Bind parameters on a statement handle
|
||||
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include "socket.h"
|
||||
#include <stdlib.h>
|
||||
#include <malloc.h>
|
||||
#include <string.h>
|
||||
|
||||
ColumnInfoClass *
|
||||
CI_Constructor()
|
||||
|
5
src/interfaces/odbc/config.h
Normal file
5
src/interfaces/odbc/config.h
Normal file
@ -0,0 +1,5 @@
|
||||
#define HAVE_IODBC 1
|
||||
#define UNIX 1
|
||||
#define HAVE_PARAM_H 1
|
||||
#define HAVE_PWD_H 1
|
||||
#define HAVE_STRICMP 0
|
@ -21,7 +21,11 @@
|
||||
#include "lobj.h"
|
||||
#include "dlg_specific.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifndef UNIX
|
||||
#include <odbcinst.h>
|
||||
#endif
|
||||
|
||||
#define STMT_INCREMENT 16 /* how many statement holders to allocate at a time */
|
||||
|
||||
@ -99,7 +103,7 @@ char *func = "SQLConnect";
|
||||
/* fill in any defaults */
|
||||
getDSNdefaults(ci);
|
||||
|
||||
qlog("conn = %u, SQLConnect(DSN='%s', UID='%s', PWD='%s')\n", ci->dsn, ci->username, ci->password);
|
||||
qlog("conn = %u, SQLConnect(DSN='%s', UID='%s', PWD='%s')\n", conn, ci->dsn, ci->username, ci->password);
|
||||
|
||||
if ( CC_connect(conn, FALSE) <= 0) {
|
||||
// Error messages are filled in
|
||||
@ -229,6 +233,14 @@ ConnectionClass *rv;
|
||||
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;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
@ -254,6 +266,19 @@ CC_Destructor(ConnectionClass *self)
|
||||
}
|
||||
mylog("after free statement holders\n");
|
||||
|
||||
/* 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);
|
||||
|
||||
free(self->col_info[i]);
|
||||
}
|
||||
free(self->col_info);
|
||||
}
|
||||
|
||||
|
||||
free(self);
|
||||
|
||||
mylog("exit CC_Destructor\n");
|
||||
@ -354,11 +379,54 @@ StatementClass *stmt;
|
||||
self->stmts[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for translation dll */
|
||||
if ( self->translation_handle) {
|
||||
FreeLibrary (self->translation_handle);
|
||||
self->translation_handle = NULL;
|
||||
}
|
||||
|
||||
mylog("exit CC_Cleanup\n");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int
|
||||
CC_set_translation (ConnectionClass *self)
|
||||
{
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
char
|
||||
CC_connect(ConnectionClass *self, char do_password)
|
||||
@ -587,15 +655,17 @@ char salt[2];
|
||||
|
||||
mylog("empty query seems to be OK.\n");
|
||||
|
||||
CC_set_translation (self);
|
||||
|
||||
/**********************************************/
|
||||
/******* Send any initial settings *********/
|
||||
/**********************************************/
|
||||
|
||||
// The Unix iodbc errors out on this call because it allocates a statement
|
||||
// before the connection is established. Therefore, don't check for error here.
|
||||
/* 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 */
|
||||
|
||||
// CC_test(self);
|
||||
@ -1074,6 +1144,7 @@ int i;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
char
|
||||
CC_send_settings(ConnectionClass *self)
|
||||
{
|
||||
@ -1085,7 +1156,10 @@ StatementClass *stmt;
|
||||
RETCODE result;
|
||||
SWORD cols = 0;
|
||||
|
||||
result = SQLAllocStmt( self, &hstmt);
|
||||
/* This function must use the local odbc API functions since the odbc state
|
||||
has not transitioned to "connected" yet.
|
||||
*/
|
||||
result = _SQLAllocStmt( self, &hstmt);
|
||||
if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
|
||||
return FALSE;
|
||||
}
|
||||
@ -1116,13 +1190,13 @@ SWORD cols = 0;
|
||||
if (ini_query[0] != '\0') {
|
||||
mylog("Sending Initial Connection query: '%s'\n", ini_query);
|
||||
|
||||
result = SQLExecDirect(hstmt, ini_query, SQL_NTS);
|
||||
result = _SQLExecDirect(hstmt, ini_query, SQL_NTS);
|
||||
if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
|
||||
SQLFreeStmt(hstmt, SQL_DROP);
|
||||
_SQLFreeStmt(hstmt, SQL_DROP);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
SQLFreeStmt(hstmt, SQL_DROP);
|
||||
_SQLFreeStmt(hstmt, SQL_DROP);
|
||||
|
||||
}
|
||||
return TRUE;
|
||||
@ -1139,36 +1213,39 @@ HSTMT hstmt;
|
||||
StatementClass *stmt;
|
||||
RETCODE result;
|
||||
|
||||
result = SQLAllocStmt( self, &hstmt);
|
||||
/* This function must use the local odbc API functions since the odbc state
|
||||
has not transitioned to "connected" yet.
|
||||
*/
|
||||
result = _SQLAllocStmt( self, &hstmt);
|
||||
if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
|
||||
return;
|
||||
}
|
||||
stmt = (StatementClass *) hstmt;
|
||||
|
||||
result = SQLExecDirect(hstmt, "select oid from pg_type where typname='" \
|
||||
result = _SQLExecDirect(hstmt, "select oid from pg_type where typname='" \
|
||||
PG_TYPE_LO_NAME \
|
||||
"'", SQL_NTS);
|
||||
if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
|
||||
SQLFreeStmt(hstmt, SQL_DROP);
|
||||
_SQLFreeStmt(hstmt, SQL_DROP);
|
||||
return;
|
||||
}
|
||||
|
||||
result = SQLFetch(hstmt);
|
||||
result = _SQLFetch(hstmt);
|
||||
if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
|
||||
SQLFreeStmt(hstmt, SQL_DROP);
|
||||
_SQLFreeStmt(hstmt, SQL_DROP);
|
||||
return;
|
||||
}
|
||||
|
||||
result = SQLGetData(hstmt, 1, SQL_C_SLONG, &self->lobj_type, sizeof(self->lobj_type), NULL);
|
||||
result = _SQLGetData(hstmt, 1, SQL_C_SLONG, &self->lobj_type, sizeof(self->lobj_type), NULL);
|
||||
if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
|
||||
SQLFreeStmt(hstmt, SQL_DROP);
|
||||
_SQLFreeStmt(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 = SQLFreeStmt(hstmt, SQL_DROP);
|
||||
result = _SQLFreeStmt(hstmt, SQL_DROP);
|
||||
}
|
||||
|
||||
void
|
||||
@ -1201,29 +1278,38 @@ RETCODE result;
|
||||
SDWORD pcbValue;
|
||||
UDWORD pcrow;
|
||||
UWORD rgfRowStatus;
|
||||
char buf[255];
|
||||
SDWORD buflen;
|
||||
DATE_STRUCT *ds;
|
||||
char name[255], type[255];
|
||||
SDWORD namelen, typelen;
|
||||
SWORD cols;
|
||||
|
||||
result = SQLAllocStmt( self, &hstmt1);
|
||||
if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
|
||||
return;
|
||||
}
|
||||
|
||||
result = SQLExecDirect(hstmt1, "select * from cpar", SQL_NTS);
|
||||
qlog("exec result = %d\n", result);
|
||||
result = SQLTables(hstmt1, "", SQL_NTS, "", SQL_NTS, "", SQL_NTS, "", SQL_NTS);
|
||||
qlog("SQLTables result = %d\n", result);
|
||||
|
||||
result = SQLBindCol(hstmt1, 2, SQL_C_DATE, buf, 0, &buflen);
|
||||
result = SQLNumResultCols(hstmt1, &cols);
|
||||
qlog("cols SQLTables result = %d\n", result);
|
||||
|
||||
result = SQLBindCol(hstmt1, 3, SQL_C_CHAR, name, sizeof(name), &namelen);
|
||||
qlog("bind result = %d\n", result);
|
||||
|
||||
result = SQLBindCol(hstmt1, 4, SQL_C_CHAR, type, sizeof(type), &typelen);
|
||||
qlog("bind result = %d\n", result);
|
||||
|
||||
result = SQLFetch(hstmt1);
|
||||
qlog("SQLFetch result = %d\n", result);
|
||||
while (result != SQL_NO_DATA_FOUND) {
|
||||
ds = (DATE_STRUCT *) buf;
|
||||
qlog("fetch on stmt1: result=%d, buflen=%d: year=%d, month=%d, day=%d\n", result, buflen, ds->year, ds->month, ds->day);
|
||||
qlog("fetch on stmt1: result=%d, namelen=%d: name='%s', typelen=%d, type='%s'\n", result, namelen, name, typelen, type);
|
||||
|
||||
result = SQLFetch(hstmt1);
|
||||
}
|
||||
qlog("SQLFetch result = %d\n", result);
|
||||
SQLFreeStmt(hstmt1, SQL_DROP);
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
|
@ -10,9 +10,20 @@
|
||||
#ifndef __CONNECTION_H__
|
||||
#define __CONNECTION_H__
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_IODBC
|
||||
#include "iodbc.h"
|
||||
#include "isql.h"
|
||||
#include "isqlext.h"
|
||||
#else
|
||||
#include <windows.h>
|
||||
#include <sql.h>
|
||||
#include <sqlext.h>
|
||||
#endif
|
||||
|
||||
#include "psqlodbc.h"
|
||||
|
||||
typedef enum {
|
||||
@ -48,6 +59,7 @@ typedef enum {
|
||||
#define CONN_NOT_IMPLEMENTED_ERROR 9
|
||||
#define CONN_INVALID_AUTHENTICATION 10
|
||||
#define CONN_AUTH_TYPE_UNSUPPORTED 11
|
||||
#define CONN_UNABLE_TO_LOAD_DLL 12
|
||||
|
||||
|
||||
/* Conn_status defines */
|
||||
@ -83,7 +95,7 @@ typedef enum {
|
||||
#define NO_AUTHENTICATION 7
|
||||
#define PATH_SIZE 64
|
||||
#define ARGV_SIZE 64
|
||||
#define NAMEDATALEN 32
|
||||
#define NAMEDATALEN 16
|
||||
|
||||
typedef unsigned int ProtocolVersion;
|
||||
|
||||
@ -130,11 +142,12 @@ typedef struct {
|
||||
char protocol[SMALL_REGISTRY_LEN];
|
||||
char port[SMALL_REGISTRY_LEN];
|
||||
char readonly[SMALL_REGISTRY_LEN];
|
||||
// char unknown_sizes[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;
|
||||
} ConnInfo;
|
||||
|
||||
@ -143,6 +156,35 @@ typedef struct {
|
||||
|
||||
|
||||
|
||||
/* This is used to store cached table information in the connection */
|
||||
struct col_info {
|
||||
QResultClass *result;
|
||||
char name[MAX_TABLE_LEN+1];
|
||||
};
|
||||
|
||||
/* Translation DLL entry points */
|
||||
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 */
|
||||
@ -154,6 +196,12 @@ struct ConnectionClass_ {
|
||||
int num_stmts;
|
||||
SocketClass *sock;
|
||||
int lobj_type;
|
||||
int ntables;
|
||||
COL_INFO **col_info;
|
||||
long translation_option;
|
||||
HINSTANCE translation_handle;
|
||||
DataSourceToDriverProc DataSourceToDriver;
|
||||
DriverToDataSourceProc DriverToDataSource;
|
||||
char transact_status; /* Is a transaction is currently in progress */
|
||||
char errormsg_created; /* has an informative error msg been created? */
|
||||
};
|
||||
@ -179,6 +227,7 @@ char CC_Destructor(ConnectionClass *self);
|
||||
int CC_cursor_count(ConnectionClass *self);
|
||||
char CC_cleanup(ConnectionClass *self);
|
||||
char CC_abort(ConnectionClass *self);
|
||||
int CC_set_translation (ConnectionClass *self);
|
||||
char CC_connect(ConnectionClass *self, char do_password);
|
||||
char CC_add_statement(ConnectionClass *self, StatementClass *stmt);
|
||||
char CC_remove_statement(ConnectionClass *self, StatementClass *stmt);
|
||||
@ -191,4 +240,5 @@ char CC_send_settings(ConnectionClass *self);
|
||||
void CC_lookup_lo(ConnectionClass *conn);
|
||||
void CC_log_error(char *func, char *desc, ConnectionClass *self);
|
||||
|
||||
|
||||
#endif
|
||||
|
@ -16,11 +16,23 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef HAVE_IODBC
|
||||
#include "iodbc.h"
|
||||
#include "isql.h"
|
||||
#include "isqlext.h"
|
||||
#else
|
||||
#include <windows.h>
|
||||
#include <sql.h>
|
||||
#include <sqlext.h>
|
||||
#endif
|
||||
|
||||
#include <time.h>
|
||||
#include <math.h>
|
||||
#include "convert.h"
|
||||
@ -30,6 +42,16 @@
|
||||
#include "lobj.h"
|
||||
#include "connection.h"
|
||||
|
||||
#ifdef UNIX
|
||||
#if !HAVE_STRICMP
|
||||
#define stricmp(s1,s2) strcasecmp(s1,s2)
|
||||
#define strnicmp(s1,s2,n) strncasecmp(s1,s2,n)
|
||||
#endif
|
||||
#ifndef SCHAR
|
||||
typedef signed char SCHAR;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
extern GLOBAL_VALUES globals;
|
||||
|
||||
/* How to map ODBC scalar functions {fn func(args)} to Postgres */
|
||||
@ -104,6 +126,15 @@ struct tm *tim;
|
||||
return COPY_OK;
|
||||
}
|
||||
|
||||
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.
|
||||
@ -738,6 +769,15 @@ char in_quote = FALSE;
|
||||
// make sure new_statement is always null-terminated
|
||||
new_statement[npos] = '\0';
|
||||
|
||||
if(stmt->hdbc->DriverToDataSource != NULL) {
|
||||
int length = strlen (new_statement);
|
||||
stmt->hdbc->DriverToDataSource (stmt->hdbc->translation_option,
|
||||
SQL_CHAR,
|
||||
new_statement, length,
|
||||
new_statement, length, NULL,
|
||||
NULL, 0, NULL);
|
||||
}
|
||||
|
||||
return SQL_SUCCESS;
|
||||
}
|
||||
|
||||
@ -881,6 +921,12 @@ char *p;
|
||||
|
||||
for (i = 0; i < strlen(si) && out < max; i++) {
|
||||
if (si[i] == '\n') {
|
||||
/* Only add the carriage-return if needed */
|
||||
if (i > 0 && si[i-1] == '\r') {
|
||||
p[out++] = si[i];
|
||||
continue;
|
||||
}
|
||||
|
||||
p[out++] = '\r';
|
||||
p[out++] = '\n';
|
||||
}
|
||||
@ -945,6 +991,26 @@ int i, y=0;
|
||||
|
||||
}
|
||||
|
||||
unsigned int
|
||||
conv_from_hex(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 * (int) pow(16, 2-i);
|
||||
}
|
||||
|
||||
return y;
|
||||
}
|
||||
|
||||
// convert octal escapes to bytes
|
||||
int
|
||||
convert_from_pgbinary(unsigned char *value, unsigned char *rgbValue, int cbValueMax)
|
||||
@ -1009,6 +1075,50 @@ int i, o=0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
encode(char *in, char *out)
|
||||
{
|
||||
unsigned int i, o = 0;
|
||||
|
||||
for (i = 0; i < strlen(in); i++) {
|
||||
if ( in[i] == '+') {
|
||||
sprintf(&out[o], "%%2B");
|
||||
o += 3;
|
||||
}
|
||||
else if ( isspace(in[i])) {
|
||||
out[o++] = '+';
|
||||
}
|
||||
else if ( ! isalnum(in[i])) {
|
||||
sprintf(&out[o], "%%%02x", in[i]);
|
||||
o += 3;
|
||||
}
|
||||
else
|
||||
out[o++] = in[i];
|
||||
}
|
||||
out[o++] = '\0';
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
decode(char *in, char *out)
|
||||
{
|
||||
unsigned int i, o = 0;
|
||||
|
||||
for (i = 0; i < strlen(in); 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';
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* 1. get oid (from 'value')
|
||||
2. open the large object
|
||||
3. read from the large object (handle multiple GetData)
|
||||
|
@ -43,6 +43,8 @@ char *convert_special_chars(char *si, char *dst, int used);
|
||||
int convert_pgbinary_to_char(char *value, char *rgbValue, int cbValueMax);
|
||||
int convert_from_pgbinary(unsigned char *value, unsigned char *rgbValue, int cbValueMax);
|
||||
int convert_to_pgbinary(unsigned char *in, char *out, int len);
|
||||
void encode(char *in, char *out);
|
||||
void decode(char *in, char *out);
|
||||
int convert_lo(StatementClass *stmt, void *value, Int2 fCType, PTR rgbValue,
|
||||
SDWORD cbValueMax, SDWORD *pcbValue, char multiple);
|
||||
|
||||
|
@ -16,10 +16,27 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#ifdef UNIX
|
||||
#include <string.h>
|
||||
#include "gpps.h"
|
||||
#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)
|
||||
#if !HAVE_STRICMP
|
||||
#define stricmp(s1,s2) strcasecmp(s1,s2)
|
||||
#define strnicmp(s1,s2,n) strncasecmp(s1,s2,n)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "dlg_specific.h"
|
||||
#include "convert.h"
|
||||
|
||||
extern GLOBAL_VALUES globals;
|
||||
|
||||
#ifndef UNIX /* best to find a #ifdef for WINDOWS */
|
||||
void
|
||||
SetDlgStuff(HWND hdlg, ConnInfo *ci)
|
||||
{
|
||||
@ -82,6 +99,8 @@ int CALLBACK driver_optionsProc(HWND hdlg,
|
||||
CheckDlgButton(hdlg, DRV_UNKNOWNS_LONGVARCHAR, globals.unknowns_as_longvarchar);
|
||||
CheckDlgButton(hdlg, DRV_BOOLS_CHAR, globals.bools_as_char);
|
||||
|
||||
CheckDlgButton(hdlg, DRV_PARSE, globals.parse);
|
||||
|
||||
SetDlgItemInt(hdlg, DRV_CACHE_SIZE, globals.fetch_max, FALSE);
|
||||
SetDlgItemInt(hdlg, DRV_VARCHAR_SIZE, globals.max_varchar_size, FALSE);
|
||||
SetDlgItemInt(hdlg, DRV_LONGVARCHAR_SIZE, globals.max_longvarchar_size, TRUE);
|
||||
@ -117,6 +136,8 @@ int CALLBACK driver_optionsProc(HWND hdlg,
|
||||
globals.unknowns_as_longvarchar = IsDlgButtonChecked(hdlg, DRV_UNKNOWNS_LONGVARCHAR);
|
||||
globals.bools_as_char = IsDlgButtonChecked(hdlg, DRV_BOOLS_CHAR);
|
||||
|
||||
globals.parse = IsDlgButtonChecked(hdlg, DRV_PARSE);
|
||||
|
||||
globals.fetch_max = GetDlgItemInt(hdlg, DRV_CACHE_SIZE, NULL, FALSE);
|
||||
globals.max_varchar_size = GetDlgItemInt(hdlg, DRV_VARCHAR_SIZE, NULL, FALSE);
|
||||
globals.max_longvarchar_size= GetDlgItemInt(hdlg, DRV_LONGVARCHAR_SIZE, NULL, TRUE); // allows for SQL_NO_TOTAL
|
||||
@ -141,6 +162,8 @@ int CALLBACK driver_optionsProc(HWND hdlg,
|
||||
CheckDlgButton(hdlg, DRV_READONLY, DEFAULT_READONLY);
|
||||
CheckDlgButton(hdlg, DRV_USEDECLAREFETCH, DEFAULT_USEDECLAREFETCH);
|
||||
|
||||
CheckDlgButton(hdlg, DRV_PARSE, DEFAULT_PARSE);
|
||||
|
||||
/* Unknown Sizes */
|
||||
CheckDlgButton(hdlg, DRV_UNKNOWN_DONTKNOW, 0);
|
||||
CheckDlgButton(hdlg, DRV_UNKNOWN_LONGEST, 0);
|
||||
@ -185,7 +208,6 @@ int CALLBACK ds_optionsProc(HWND hdlg,
|
||||
{
|
||||
ConnInfo *ci;
|
||||
char buf[128];
|
||||
// int unknown_sizes;
|
||||
|
||||
switch (wMsg) {
|
||||
case WM_INITDIALOG:
|
||||
@ -209,20 +231,6 @@ char buf[128];
|
||||
else
|
||||
CheckDlgButton(hdlg, DS_PG62, 0);
|
||||
|
||||
/* Unknown Data Type sizes -- currently only needed in Driver options.
|
||||
switch (atoi(ci->unknown_sizes)) {
|
||||
case UNKNOWNS_AS_DONTKNOW:
|
||||
CheckDlgButton(hdlg, DS_UNKNOWN_DONTKNOW, 1);
|
||||
break;
|
||||
case UNKNOWNS_AS_LONGEST:
|
||||
CheckDlgButton(hdlg, DS_UNKNOWN_LONGEST, 1);
|
||||
break;
|
||||
case UNKNOWNS_AS_MAX:
|
||||
default:
|
||||
CheckDlgButton(hdlg, DS_UNKNOWN_MAX, 1);
|
||||
break;
|
||||
}
|
||||
*/
|
||||
|
||||
CheckDlgButton(hdlg, DS_SHOWOIDCOLUMN, atoi(ci->show_oid_column));
|
||||
CheckDlgButton(hdlg, DS_FAKEOIDINDEX, atoi(ci->fake_oid_index));
|
||||
@ -259,18 +267,6 @@ char buf[128];
|
||||
ci->protocol[0] = '\0';
|
||||
|
||||
|
||||
/* Unknown Data Type sizes -- currently only needed in Driver options.
|
||||
if (IsDlgButtonChecked(hdlg, DS_UNKNOWN_MAX))
|
||||
unknown_sizes = UNKNOWNS_AS_MAX;
|
||||
else if (IsDlgButtonChecked(hdlg, DS_UNKNOWN_DONTKNOW))
|
||||
unknown_sizes = UNKNOWNS_AS_DONTKNOW;
|
||||
else if (IsDlgButtonChecked(hdlg, DS_UNKNOWN_LONGEST))
|
||||
unknown_sizes = UNKNOWNS_AS_LONGEST;
|
||||
else
|
||||
unknown_sizes = UNKNOWNS_AS_MAX;
|
||||
|
||||
sprintf(ci->unknown_sizes, "%d", unknown_sizes);
|
||||
*/
|
||||
|
||||
sprintf(ci->show_system_tables, "%d", IsDlgButtonChecked(hdlg, DS_SHOWSYSTEMTABLES));
|
||||
|
||||
@ -295,27 +291,36 @@ char buf[128];
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
#endif /* !UNIX */
|
||||
|
||||
void
|
||||
makeConnectString(char *connect_string, ConnInfo *ci)
|
||||
{
|
||||
char got_dsn = (ci->dsn[0] != '\0');
|
||||
char encoded_conn_settings[LARGE_REGISTRY_LEN];
|
||||
|
||||
sprintf(connect_string, "%s=%s;DATABASE=%s;SERVER=%s;PORT=%s;UID=%s;READONLY=%s;PWD=%s;PROTOCOL=%s;FAKEOIDINDEX=%s;SHOWOIDCOLUMN=%s;ROWVERSIONING=%s;SHOWSYSTEMTABLES=%s;CONNSETTINGS=%s",
|
||||
/* 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 */
|
||||
sprintf(&connect_string[strlen(connect_string)],
|
||||
";READONLY=%s;PROTOCOL=%s;FAKEOIDINDEX=%s;SHOWOIDCOLUMN=%s;ROWVERSIONING=%s;SHOWSYSTEMTABLES=%s;CONNSETTINGS=%s",
|
||||
ci->readonly,
|
||||
ci->password,
|
||||
ci->protocol,
|
||||
// ci->unknown_sizes, -- currently only needed in Driver options.
|
||||
ci->fake_oid_index,
|
||||
ci->show_oid_column,
|
||||
ci->row_versioning,
|
||||
ci->show_system_tables,
|
||||
ci->conn_settings);
|
||||
encoded_conn_settings);
|
||||
}
|
||||
|
||||
void
|
||||
@ -349,10 +354,6 @@ copyAttributes(ConnInfo *ci, char *attribute, char *value)
|
||||
else if (stricmp(attribute, INI_PROTOCOL) == 0)
|
||||
strcpy(ci->protocol, value);
|
||||
|
||||
/*
|
||||
else if (stricmp(attribute, INI_UNKNOWNSIZES) == 0)
|
||||
strcpy(ci->unknown_sizes, value);
|
||||
*/
|
||||
else if (stricmp(attribute, INI_SHOWOIDCOLUMN) == 0)
|
||||
strcpy(ci->show_oid_column, value);
|
||||
|
||||
@ -365,9 +366,10 @@ copyAttributes(ConnInfo *ci, char *attribute, char *value)
|
||||
else if (stricmp(attribute, INI_SHOWSYSTEMTABLES) == 0)
|
||||
strcpy(ci->show_system_tables, value);
|
||||
|
||||
else if (stricmp(attribute, INI_CONNSETTINGS) == 0)
|
||||
strcpy(ci->conn_settings, value);
|
||||
|
||||
else if (stricmp(attribute, INI_CONNSETTINGS) == 0) {
|
||||
decode(value, ci->conn_settings);
|
||||
// strcpy(ci->conn_settings, value);
|
||||
}
|
||||
|
||||
mylog("copyAttributes: DSN='%s',server='%s',dbase='%s',user='%s',passwd='%s',port='%s',readonly='%s',protocol='%s', conn_settings='%s')\n",
|
||||
ci->dsn,
|
||||
@ -378,7 +380,6 @@ copyAttributes(ConnInfo *ci, char *attribute, char *value)
|
||||
ci->port,
|
||||
ci->readonly,
|
||||
ci->protocol,
|
||||
// ci->unknown_sizes,
|
||||
ci->conn_settings);
|
||||
|
||||
}
|
||||
@ -392,10 +393,6 @@ getDSNdefaults(ConnInfo *ci)
|
||||
if (ci->readonly[0] == '\0')
|
||||
sprintf(ci->readonly, "%d", globals.readonly);
|
||||
|
||||
/* -- currently only needed in Driver options.
|
||||
if (ci->unknown_sizes[0] == '\0')
|
||||
sprintf(ci->unknown_sizes, "%d", globals.unknown_sizes);
|
||||
*/
|
||||
if (ci->fake_oid_index[0] == '\0')
|
||||
sprintf(ci->fake_oid_index, "%d", DEFAULT_FAKEOIDINDEX);
|
||||
|
||||
@ -414,6 +411,7 @@ void
|
||||
getDSNinfo(ConnInfo *ci, char overwrite)
|
||||
{
|
||||
char *DSN = ci->dsn;
|
||||
char encoded_conn_settings[LARGE_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.
|
||||
@ -447,10 +445,6 @@ char *DSN = ci->dsn;
|
||||
if ( ci->readonly[0] == '\0' || overwrite)
|
||||
SQLGetPrivateProfileString(DSN, INI_READONLY, "", ci->readonly, sizeof(ci->readonly), ODBC_INI);
|
||||
|
||||
/* -- currently only needed in Driver options.
|
||||
if ( ci->unknown_sizes[0] == '\0' || overwrite)
|
||||
SQLGetPrivateProfileString(DSN, INI_UNKNOWNSIZES, "", ci->unknown_sizes, sizeof(ci->unknown_sizes), 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);
|
||||
|
||||
@ -466,8 +460,16 @@ char *DSN = ci->dsn;
|
||||
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, "", ci->conn_settings, sizeof(ci->conn_settings), 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);
|
||||
|
||||
qlog("DSN info: DSN='%s',server='%s',port='%s',dbase='%s',user='%s',passwd='%s'\n",
|
||||
DSN,
|
||||
@ -481,10 +483,13 @@ char *DSN = ci->dsn;
|
||||
ci->protocol,
|
||||
ci->show_oid_column,
|
||||
ci->fake_oid_index,
|
||||
// ci->unknown_sizes,
|
||||
ci->show_system_tables);
|
||||
qlog(" conn_settings='%s'\n",
|
||||
ci->conn_settings);
|
||||
qlog(" translation_dll='%s',translation_option='%s'\n",
|
||||
ci->translation_dll,
|
||||
ci->translation_option);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -493,6 +498,9 @@ void
|
||||
writeDSNinfo(ConnInfo *ci)
|
||||
{
|
||||
char *DSN = ci->dsn;
|
||||
char encoded_conn_settings[LARGE_REGISTRY_LEN];
|
||||
|
||||
encode(ci->conn_settings, encoded_conn_settings);
|
||||
|
||||
SQLWritePrivateProfileString(DSN,
|
||||
INI_KDESC,
|
||||
@ -529,12 +537,6 @@ char *DSN = ci->dsn;
|
||||
ci->readonly,
|
||||
ODBC_INI);
|
||||
|
||||
/* -- currently only needed in Driver options.
|
||||
SQLWritePrivateProfileString(DSN,
|
||||
INI_UNKNOWNSIZES,
|
||||
ci->unknown_sizes,
|
||||
ODBC_INI);
|
||||
*/
|
||||
SQLWritePrivateProfileString(DSN,
|
||||
INI_SHOWOIDCOLUMN,
|
||||
ci->show_oid_column,
|
||||
@ -562,7 +564,7 @@ char *DSN = ci->dsn;
|
||||
|
||||
SQLWritePrivateProfileString(DSN,
|
||||
INI_CONNSETTINGS,
|
||||
ci->conn_settings,
|
||||
encoded_conn_settings,
|
||||
ODBC_INI);
|
||||
}
|
||||
|
||||
@ -631,7 +633,7 @@ char temp[128];
|
||||
globals.unique_index = atoi(temp);
|
||||
|
||||
|
||||
// Unknown Sizes is stored in the driver section AND per datasource
|
||||
// Unknown Sizes is stored in the driver section only
|
||||
SQLGetPrivateProfileString(DBMS_NAME, INI_UNKNOWNSIZES, "",
|
||||
temp, sizeof(temp), ODBCINST_INI);
|
||||
if ( temp[0] == '\0')
|
||||
@ -648,6 +650,13 @@ char temp[128];
|
||||
else
|
||||
globals.lie = atoi(temp);
|
||||
|
||||
// Parse statements
|
||||
SQLGetPrivateProfileString(DBMS_NAME, INI_PARSE, "",
|
||||
temp, sizeof(temp), ODBCINST_INI);
|
||||
if ( temp[0] == '\0')
|
||||
globals.parse = DEFAULT_PARSE;
|
||||
else
|
||||
globals.parse = atoi(temp);
|
||||
|
||||
// Readonly is stored in the driver section AND per datasource
|
||||
SQLGetPrivateProfileString(DBMS_NAME, INI_READONLY, "",
|
||||
@ -772,6 +781,10 @@ char tmp[128];
|
||||
SQLWritePrivateProfileString(DBMS_NAME,
|
||||
INI_BOOLSASCHAR, tmp, ODBCINST_INI);
|
||||
|
||||
sprintf(tmp, "%d", globals.parse);
|
||||
SQLWritePrivateProfileString(DBMS_NAME,
|
||||
INI_PARSE, tmp, ODBCINST_INI);
|
||||
|
||||
sprintf(tmp, "%d", globals.max_varchar_size);
|
||||
SQLWritePrivateProfileString(DBMS_NAME,
|
||||
INI_MAXVARCHARSIZE, tmp, ODBCINST_INI);
|
||||
|
@ -10,12 +10,19 @@
|
||||
#ifndef __DLG_SPECIFIC_H__
|
||||
#define __DLG_SPECIFIC_H__
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include "psqlodbc.h"
|
||||
#include "connection.h"
|
||||
|
||||
#ifndef UNIX
|
||||
#include <windows.h>
|
||||
#include <windowsx.h>
|
||||
#include <odbcinst.h>
|
||||
#include "resource.h"
|
||||
#endif
|
||||
|
||||
/* Unknown data type sizes */
|
||||
#define UNKNOWNS_AS_MAX 0
|
||||
@ -23,8 +30,13 @@
|
||||
#define UNKNOWNS_AS_LONGEST 2
|
||||
|
||||
/* INI File Stuff */
|
||||
#ifdef UNIX
|
||||
#define ODBC_INI ".odbc.ini"
|
||||
#define ODBCINST_INI "/etc/odbcinst.ini"
|
||||
#else
|
||||
#define ODBC_INI "ODBC.INI" /* ODBC initialization file */
|
||||
#define ODBCINST_INI "ODBCINST.INI" /* ODBC Installation file */
|
||||
#endif
|
||||
|
||||
#define INI_DSN DBMS_NAME /* Name of default Datasource in ini file (not used?) */
|
||||
#define INI_KDESC "Description" /* Data source description */
|
||||
@ -58,8 +70,14 @@
|
||||
#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"
|
||||
|
||||
|
||||
/* Connection Defaults */
|
||||
#define DEFAULT_PORT "5432"
|
||||
#define DEFAULT_READONLY 1
|
||||
@ -78,13 +96,14 @@
|
||||
#define DEFAULT_ROWVERSIONING 0
|
||||
#define DEFAULT_SHOWSYSTEMTABLES 0 // dont show system tables
|
||||
#define DEFAULT_LIE 0
|
||||
#define DEFAULT_PARSE 0
|
||||
|
||||
#define DEFAULT_EXTRASYSTABLEPREFIXES "dd_;"
|
||||
|
||||
/* prototypes */
|
||||
void updateGlobals(void);
|
||||
void getGlobalDefaults(void);
|
||||
|
||||
#ifndef UNIX
|
||||
void SetDlgStuff(HWND hdlg, ConnInfo *ci);
|
||||
void GetDlgStuff(HWND hdlg, ConnInfo *ci);
|
||||
|
||||
@ -96,12 +115,14 @@ int CALLBACK ds_optionsProc(HWND hdlg,
|
||||
WORD wMsg,
|
||||
WPARAM wParam,
|
||||
LPARAM lParam);
|
||||
#endif /* ! UNIX */
|
||||
|
||||
void updateGlobals(void);
|
||||
void writeDSNinfo(ConnInfo *ci);
|
||||
void getDSNdefaults(ConnInfo *ci);
|
||||
void getDSNinfo(ConnInfo *ci, char overwrite);
|
||||
void makeConnectString(char *connect_string, ConnInfo *ci);
|
||||
void copyAttributes(ConnInfo *ci, char *attribute, char *value);
|
||||
void getDSNdefaults(ConnInfo *ci);
|
||||
|
||||
void getDSNinfo(ConnInfo *ci, char overwrite);
|
||||
void writeDSNinfo(ConnInfo *ci);
|
||||
|
||||
#endif
|
||||
|
@ -12,28 +12,56 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "psqlodbc.h"
|
||||
#include "connection.h"
|
||||
|
||||
#ifdef UNIX
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#define NEAR
|
||||
#else
|
||||
#include <winsock.h>
|
||||
#include <sqlext.h>
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#ifdef UNIX
|
||||
#define stricmp(s1,s2) strcasecmp(s1,s2)
|
||||
#define strnicmp(s1,s2,n) strncasecmp(s1,s2,n)
|
||||
#else
|
||||
#include <windows.h>
|
||||
#include <windowsx.h>
|
||||
#include <odbcinst.h>
|
||||
#include "resource.h"
|
||||
#endif
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE (BOOL)1
|
||||
#endif
|
||||
#ifndef FALSE
|
||||
#define FALSE (BOOL)0
|
||||
#endif
|
||||
|
||||
#include "dlg_specific.h"
|
||||
|
||||
/* prototypes */
|
||||
BOOL FAR PASCAL dconn_FDriverConnectProc(HWND hdlg, UINT wMsg, WPARAM wParam, LPARAM lParam);
|
||||
RETCODE dconn_DoDialog(HWND hwnd, ConnInfo *ci);
|
||||
void dconn_get_connect_attributes(UCHAR FAR *connect_string, ConnInfo *ci);
|
||||
|
||||
#ifndef UNIX /* should be something like ifdef WINDOWS */
|
||||
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
|
||||
|
||||
extern GLOBAL_VALUES globals;
|
||||
|
||||
|
||||
@ -51,23 +79,25 @@ char *func = "SQLDriverConnect";
|
||||
ConnectionClass *conn = (ConnectionClass *) hdbc;
|
||||
ConnInfo *ci;
|
||||
RETCODE dialog_result;
|
||||
char connect_string[MAX_CONNECT_STRING];
|
||||
char connStrIn[MAX_CONNECT_STRING];
|
||||
char connStrOut[MAX_CONNECT_STRING];
|
||||
int retval;
|
||||
char password_required = FALSE;
|
||||
|
||||
mylog("**** SQLDriverConnect: fDriverCompletion=%d, connStrIn='%s'\n", fDriverCompletion, szConnStrIn);
|
||||
|
||||
if ( ! conn) {
|
||||
CC_log_error(func, "", NULL);
|
||||
return SQL_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
qlog("conn=%u, SQLDriverConnect( in)='%s'\n", conn, szConnStrIn);
|
||||
make_string(szConnStrIn, cbConnStrIn, connStrIn);
|
||||
|
||||
mylog("**** SQLDriverConnect: fDriverCompletion=%d, connStrIn='%s'\n", fDriverCompletion, connStrIn);
|
||||
qlog("conn=%u, SQLDriverConnect( 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(szConnStrIn, ci);
|
||||
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
|
||||
@ -81,6 +111,7 @@ dialog:
|
||||
ci->focus_password = password_required;
|
||||
|
||||
switch(fDriverCompletion) {
|
||||
#ifndef UNIX /* again should be ifdef WINDOWS like */
|
||||
case SQL_DRIVER_PROMPT:
|
||||
dialog_result = dconn_DoDialog(hwnd, ci);
|
||||
if(dialog_result != SQL_SUCCESS) {
|
||||
@ -88,8 +119,12 @@ dialog:
|
||||
}
|
||||
break;
|
||||
|
||||
case SQL_DRIVER_COMPLETE:
|
||||
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' ||
|
||||
@ -103,6 +138,11 @@ dialog:
|
||||
}
|
||||
}
|
||||
break;
|
||||
#else
|
||||
case SQL_DRIVER_PROMPT:
|
||||
case SQL_DRIVER_COMPLETE:
|
||||
case SQL_DRIVER_COMPLETE_REQUIRED:
|
||||
#endif
|
||||
case SQL_DRIVER_NOPROMPT:
|
||||
break;
|
||||
}
|
||||
@ -122,14 +162,16 @@ dialog:
|
||||
|
||||
if(szConnStrOut) {
|
||||
|
||||
// return the completed string to the caller.
|
||||
|
||||
makeConnectString(connect_string, ci);
|
||||
/* Return the completed string to the caller.
|
||||
Only construct the connect string if a dialog was put up,
|
||||
otherwise, just copy the connection input string to the output.
|
||||
*/
|
||||
makeConnectString(connStrOut, ci);
|
||||
|
||||
if(pcbConnStrOut) {
|
||||
*pcbConnStrOut = strlen(connect_string);
|
||||
*pcbConnStrOut = strlen(connStrOut);
|
||||
}
|
||||
strncpy_null(szConnStrOut, connect_string, cbConnStrOutMax);
|
||||
strncpy_null(szConnStrOut, connStrOut, cbConnStrOutMax);
|
||||
}
|
||||
|
||||
mylog("szConnStrOut = '%s'\n", szConnStrOut);
|
||||
@ -143,8 +185,12 @@ dialog:
|
||||
return SQL_ERROR; /* need a password but not allowed to prompt so error */
|
||||
}
|
||||
else {
|
||||
#ifndef UNIX
|
||||
password_required = TRUE;
|
||||
goto dialog;
|
||||
#else
|
||||
return SQL_ERROR; /* until a better solution is found. */
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else if (retval == 0) {
|
||||
@ -157,7 +203,7 @@ dialog:
|
||||
return SQL_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
#ifndef UNIX /* yet another candidate for ifdef WINDOWS */
|
||||
RETCODE dconn_DoDialog(HWND hwnd, ConnInfo *ci)
|
||||
{
|
||||
int dialog_result;
|
||||
@ -216,6 +262,7 @@ ConnInfo *ci;
|
||||
else if (ci->focus_password)
|
||||
SetFocus(GetDlgItem(hdlg, IDC_PASSWORD));
|
||||
|
||||
|
||||
break;
|
||||
|
||||
case WM_COMMAND:
|
||||
@ -252,7 +299,7 @@ ConnInfo *ci;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
#endif /* ! UNIX */
|
||||
|
||||
void dconn_get_connect_attributes(UCHAR FAR *connect_string, ConnInfo *ci)
|
||||
{
|
||||
|
@ -10,10 +10,21 @@
|
||||
#ifndef __ENVIRON_H__
|
||||
#define __ENVIRON_H__
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include "psqlodbc.h"
|
||||
|
||||
#ifdef HAVE_IODBC
|
||||
#include "iodbc.h"
|
||||
#include "isql.h"
|
||||
#include "isqlext.h"
|
||||
#else
|
||||
#include <windows.h>
|
||||
#include <sql.h>
|
||||
#include <sqlext.h>
|
||||
#endif
|
||||
|
||||
#define ENV_ALLOC_ERROR 1
|
||||
|
||||
|
@ -13,11 +13,21 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include "psqlodbc.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef HAVE_IODBC
|
||||
#include "iodbc.h"
|
||||
#include "isqlext.h"
|
||||
#else
|
||||
#include <windows.h>
|
||||
#include <sqlext.h>
|
||||
#endif
|
||||
|
||||
#include "connection.h"
|
||||
#include "statement.h"
|
||||
@ -27,6 +37,15 @@
|
||||
#include "lobj.h"
|
||||
|
||||
|
||||
RETCODE SQL_API SQLExecDirect(
|
||||
HSTMT hstmt,
|
||||
UCHAR FAR *szSqlStr,
|
||||
SDWORD cbSqlStr)
|
||||
{
|
||||
return _SQLExecDirect(hstmt, szSqlStr, cbSqlStr);
|
||||
}
|
||||
|
||||
|
||||
// Perform a Prepare on the SQL statement
|
||||
RETCODE SQL_API SQLPrepare(HSTMT hstmt,
|
||||
UCHAR FAR *szSqlStr,
|
||||
@ -111,7 +130,7 @@ StatementClass *self = (StatementClass *) hstmt;
|
||||
|
||||
// Performs the equivalent of SQLPrepare, followed by SQLExecute.
|
||||
|
||||
RETCODE SQL_API SQLExecDirect(
|
||||
RETCODE SQL_API _SQLExecDirect(
|
||||
HSTMT hstmt,
|
||||
UCHAR FAR *szSqlStr,
|
||||
SDWORD cbSqlStr)
|
||||
@ -359,6 +378,8 @@ StatementClass *stmt = (StatementClass *) hstmt;
|
||||
stmt->current_exec_param = -1;
|
||||
stmt->put_data = FALSE;
|
||||
|
||||
return SQL_SUCCESS;
|
||||
|
||||
}
|
||||
|
||||
// - - - - - - - - -
|
||||
|
475
src/interfaces/odbc/gpps.c
Normal file
475
src/interfaces/odbc/gpps.c
Normal file
@ -0,0 +1,475 @@
|
||||
// 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
|
||||
|
||||
#ifndef WIN32
|
||||
|
||||
#if HAVE_CONFIG_H
|
||||
#include <config.h> // produced by configure
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#if HAVE_PWD_H
|
||||
#include <pwd.h>
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <string.h>
|
||||
#include "gpps.h"
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE ((BOOL)1)
|
||||
#endif
|
||||
#ifndef FALSE
|
||||
#define FALSE ((BOOL)0)
|
||||
#endif
|
||||
|
||||
#if HAVE_PARAM_H
|
||||
#include <sys/param.h>
|
||||
#else
|
||||
#define MAXPATHLEN 255
|
||||
#endif
|
||||
|
||||
DWORD
|
||||
GetPrivateProfileString(char *theSection, // section name
|
||||
char *theKey, // search key name
|
||||
char *theDefault, // default value if not found
|
||||
char *theReturnBuffer, // return value stored here
|
||||
size_t theReturnBufferLength, // byte length of return buffer
|
||||
char *theIniFileName) // pathname of ini file to search
|
||||
{
|
||||
char buf[MAXPATHLEN+1];
|
||||
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 aKeyFound = FALSE;
|
||||
int j = 0;
|
||||
|
||||
j = strlen(theIniFileName) + 1;
|
||||
ptr = (char*)getpwuid(getuid()); // get user info
|
||||
|
||||
if( ptr == NULL)
|
||||
{
|
||||
if( MAXPATHLEN < j )
|
||||
theIniFileName[MAXPATHLEN] = '\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( MAXPATHLEN < strlen(ptr) + j )
|
||||
{
|
||||
if( MAXPATHLEN < strlen(ptr) )
|
||||
ptr[MAXPATHLEN] = '\0';
|
||||
else
|
||||
theIniFileName[MAXPATHLEN-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);
|
||||
}
|
||||
|
||||
|
||||
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, ']')) )
|
||||
{
|
||||
*aString = '\0';
|
||||
|
||||
// accept as matched if NULL key or exact match
|
||||
|
||||
if(!theSection || !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(theKey == NULL || !strcmp(theKey, aLine))
|
||||
{
|
||||
// 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(char *theSection, // section name
|
||||
char *theKey, // write key name
|
||||
char *theBuffer, // input buffer
|
||||
char *theIniFileName) // pathname of ini file to write
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 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[MAXPATHLEN+1];
|
||||
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( MAXPATHLEN < j )
|
||||
theIniFileName[MAXPATHLEN] = '\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( MAXPATHLEN < strlen(ptr) + j )
|
||||
{
|
||||
if( MAXPATHLEN < strlen(ptr) )
|
||||
ptr[MAXPATHLEN] = '\0';
|
||||
else
|
||||
theIniFileName[MAXPATHLEN-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
|
40
src/interfaces/odbc/gpps.h
Normal file
40
src/interfaces/odbc/gpps.h
Normal file
@ -0,0 +1,40 @@
|
||||
// GetPrivateProfileString
|
||||
// for UNIX use
|
||||
#ifndef GPPS_H
|
||||
#define GPPS_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#ifdef UNIX
|
||||
#include <sys/types.h>
|
||||
#include "iodbc.h"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
DWORD
|
||||
GetPrivateProfileString(char *theSection, // section name
|
||||
char *theKey, // search key name
|
||||
char *theDefault, // default value if not found
|
||||
char *theReturnBuffer, // return valuse stored here
|
||||
size_t theBufferLength, // byte length of return buffer
|
||||
char *theIniFileName); // pathname of ini file to search
|
||||
|
||||
DWORD
|
||||
WritePrivateProfileString(char *theSection, // section name
|
||||
char *theKey, // write key name
|
||||
char *theBuffer, // input buffer
|
||||
char *theIniFileName); // pathname of ini file to write
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef UNIX
|
||||
#undef DWORD
|
||||
#endif
|
||||
#endif
|
@ -16,12 +16,24 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include "psqlodbc.h"
|
||||
|
||||
#ifdef HAVE_IODBC
|
||||
#include "iodbc.h"
|
||||
#include "isql.h"
|
||||
#include "isqlext.h"
|
||||
#else
|
||||
#include <windows.h>
|
||||
#include <sql.h>
|
||||
#include <sqlext.h>
|
||||
#endif
|
||||
|
||||
#include "tuple.h"
|
||||
#include "pgtypes.h"
|
||||
|
||||
@ -282,7 +294,7 @@ char *p;
|
||||
// examples of identifiers. it says return a blank for no
|
||||
// quote character, we'll try that...
|
||||
if (pcbInfoValue) *pcbInfoValue = 1;
|
||||
strncpy_null((char *)rgbInfoValue, " ", (size_t)cbInfoValueMax);
|
||||
strncpy_null((char *)rgbInfoValue, "\"", (size_t)cbInfoValueMax);
|
||||
break;
|
||||
|
||||
case SQL_KEYWORDS: /* ODBC 2.0 */
|
||||
@ -325,7 +337,7 @@ char *p;
|
||||
|
||||
case SQL_MAX_COLUMN_NAME_LEN: /* ODBC 1.0 */
|
||||
// maximum length of a column name
|
||||
*((WORD *)rgbInfoValue) = 32;
|
||||
*((WORD *)rgbInfoValue) = MAX_COLUMN_LEN;
|
||||
if(pcbInfoValue) { *pcbInfoValue = 2; }
|
||||
break;
|
||||
|
||||
@ -358,7 +370,7 @@ char *p;
|
||||
break;
|
||||
|
||||
case SQL_MAX_CURSOR_NAME_LEN: /* ODBC 1.0 */
|
||||
*((WORD *)rgbInfoValue) = 32;
|
||||
*((WORD *)rgbInfoValue) = MAX_CURSOR_LEN;
|
||||
if(pcbInfoValue) { *pcbInfoValue = 2; }
|
||||
break;
|
||||
|
||||
@ -405,7 +417,7 @@ char *p;
|
||||
break;
|
||||
|
||||
case SQL_MAX_TABLE_NAME_LEN: /* ODBC 1.0 */
|
||||
*((WORD *)rgbInfoValue) = 32;
|
||||
*((WORD *)rgbInfoValue) = MAX_TABLE_LEN;
|
||||
if(pcbInfoValue) { *pcbInfoValue = 2; }
|
||||
break;
|
||||
|
||||
@ -1036,7 +1048,7 @@ mylog("**** SQLTables(): ENTER, stmt=%u\n", stmt);
|
||||
show_regular_tables = FALSE;
|
||||
show_views = FALSE;
|
||||
|
||||
// make_string mallocs memory
|
||||
/* make_string mallocs memory */
|
||||
tableType = make_string(szTableType, cbTableType, NULL);
|
||||
if (tableType) {
|
||||
strcpy(table_types, tableType);
|
||||
@ -1059,7 +1071,10 @@ mylog("**** SQLTables(): ENTER, stmt=%u\n", stmt);
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
show_regular_tables = TRUE;
|
||||
show_views = TRUE;
|
||||
}
|
||||
|
||||
/* If not interested in SYSTEM TABLES then filter them out
|
||||
@ -1228,6 +1243,9 @@ mylog("**** SQLTables(): ENTER, stmt=%u\n", stmt);
|
||||
return SQL_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
RETCODE SQL_API SQLColumns(
|
||||
HSTMT hstmt,
|
||||
UCHAR FAR * szTableQualifier,
|
||||
@ -1247,9 +1265,8 @@ StatementClass *col_stmt;
|
||||
char columns_query[MAX_STATEMENT_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, field_length, mod_length;
|
||||
Int4 field_type;
|
||||
Int2 the_type;
|
||||
Int2 field_number, field_length, mod_length, result_cols;
|
||||
Int4 field_type, the_type;
|
||||
char not_null[MAX_INFO_STRING];
|
||||
ConnInfo *ci;
|
||||
|
||||
@ -1403,10 +1420,11 @@ mylog("**** SQLColumns(): ENTER, stmt=%u\n", stmt);
|
||||
|
||||
// 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_bindings(stmt, 12);
|
||||
result_cols = 14;
|
||||
extend_bindings(stmt, result_cols);
|
||||
|
||||
// set the field names
|
||||
QR_set_num_fields(stmt->result, 12);
|
||||
QR_set_num_fields(stmt->result, result_cols);
|
||||
QR_set_field_info(stmt->result, 0, "TABLE_QUALIFIER", PG_TYPE_TEXT, MAX_INFO_STRING);
|
||||
QR_set_field_info(stmt->result, 1, "TABLE_OWNER", PG_TYPE_TEXT, MAX_INFO_STRING);
|
||||
QR_set_field_info(stmt->result, 2, "TABLE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
|
||||
@ -1420,6 +1438,10 @@ mylog("**** SQLColumns(): ENTER, stmt=%u\n", stmt);
|
||||
QR_set_field_info(stmt->result, 10, "NULLABLE", PG_TYPE_INT2, 2);
|
||||
QR_set_field_info(stmt->result, 11, "REMARKS", PG_TYPE_TEXT, 254);
|
||||
|
||||
// User defined fields
|
||||
QR_set_field_info(stmt->result, 12, "DISPLAY_SIZE", PG_TYPE_INT4, 4);
|
||||
QR_set_field_info(stmt->result, 13, "FIELD_TYPE", PG_TYPE_INT4, 4);
|
||||
|
||||
|
||||
result = SQLFetch(hcol_stmt);
|
||||
|
||||
@ -1435,7 +1457,7 @@ mylog("**** SQLColumns(): ENTER, stmt=%u\n", stmt);
|
||||
/* For OID fields */
|
||||
the_type = PG_TYPE_OID;
|
||||
row = (TupleNode *)malloc(sizeof(TupleNode) +
|
||||
(12 - 1) * sizeof(TupleField));
|
||||
(result_cols - 1) * sizeof(TupleField));
|
||||
|
||||
set_tuplefield_string(&row->tuple[0], "");
|
||||
// see note in SQLTables()
|
||||
@ -1446,16 +1468,17 @@ mylog("**** SQLColumns(): ENTER, stmt=%u\n", stmt);
|
||||
set_tuplefield_int2(&row->tuple[4], pgtype_to_sqltype(stmt, the_type));
|
||||
set_tuplefield_string(&row->tuple[5], "OID");
|
||||
|
||||
set_tuplefield_int4(&row->tuple[7], pgtype_length(stmt, the_type, PG_STATIC,
|
||||
PG_STATIC));
|
||||
set_tuplefield_int4(&row->tuple[6], pgtype_precision(stmt, the_type, PG_STATIC,
|
||||
PG_STATIC));
|
||||
set_tuplefield_int4(&row->tuple[7], pgtype_length(stmt, the_type, PG_STATIC, PG_STATIC));
|
||||
set_tuplefield_int4(&row->tuple[6], pgtype_precision(stmt, the_type, PG_STATIC, PG_STATIC));
|
||||
|
||||
set_nullfield_int2(&row->tuple[8], pgtype_scale(stmt, the_type));
|
||||
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], "");
|
||||
|
||||
set_tuplefield_int4(&row->tuple[12], pgtype_display_size(stmt, the_type, PG_STATIC, PG_STATIC));
|
||||
set_tuplefield_int4(&row->tuple[13], the_type);
|
||||
|
||||
QR_add_tuple(stmt->result, row);
|
||||
}
|
||||
|
||||
@ -1463,7 +1486,7 @@ mylog("**** SQLColumns(): ENTER, stmt=%u\n", stmt);
|
||||
|
||||
while((result == SQL_SUCCESS) || (result == SQL_SUCCESS_WITH_INFO)) {
|
||||
row = (TupleNode *)malloc(sizeof(TupleNode) +
|
||||
(12 - 1) * sizeof(TupleField));
|
||||
(result_cols - 1) * sizeof(TupleField));
|
||||
|
||||
set_tuplefield_string(&row->tuple[0], "");
|
||||
// see note in SQLTables()
|
||||
@ -1494,11 +1517,13 @@ mylog("**** SQLColumns(): ENTER, stmt=%u\n", stmt);
|
||||
|
||||
set_tuplefield_int4(&row->tuple[7], mod_length);
|
||||
set_tuplefield_int4(&row->tuple[6], mod_length);
|
||||
set_tuplefield_int4(&row->tuple[12], mod_length);
|
||||
} else {
|
||||
mylog("SQLColumns: field type is OTHER: field_type = %d, pgtype_length = %d\n", field_type, pgtype_length(stmt, field_type, PG_STATIC, PG_STATIC));
|
||||
|
||||
set_tuplefield_int4(&row->tuple[7], pgtype_length(stmt, field_type, PG_STATIC, PG_STATIC));
|
||||
set_tuplefield_int4(&row->tuple[6], pgtype_precision(stmt, field_type, PG_STATIC, PG_STATIC));
|
||||
set_tuplefield_int4(&row->tuple[12], pgtype_display_size(stmt, field_type, PG_STATIC, PG_STATIC));
|
||||
|
||||
}
|
||||
|
||||
@ -1506,6 +1531,7 @@ mylog("**** SQLColumns(): ENTER, stmt=%u\n", stmt);
|
||||
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], "");
|
||||
set_tuplefield_int4(&row->tuple[13], field_type);
|
||||
|
||||
QR_add_tuple(stmt->result, row);
|
||||
|
||||
@ -1526,7 +1552,7 @@ mylog("**** SQLColumns(): ENTER, stmt=%u\n", stmt);
|
||||
the_type = PG_TYPE_INT4;
|
||||
|
||||
row = (TupleNode *)malloc(sizeof(TupleNode) +
|
||||
(12 - 1) * sizeof(TupleField));
|
||||
(result_cols - 1) * sizeof(TupleField));
|
||||
|
||||
set_tuplefield_string(&row->tuple[0], "");
|
||||
set_tuplefield_string(&row->tuple[1], "");
|
||||
@ -1540,6 +1566,8 @@ mylog("**** SQLColumns(): ENTER, stmt=%u\n", stmt);
|
||||
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], "");
|
||||
set_tuplefield_int4(&row->tuple[12], pgtype_display_size(stmt, the_type, PG_STATIC, PG_STATIC));
|
||||
set_tuplefield_int4(&row->tuple[13], the_type);
|
||||
|
||||
QR_add_tuple(stmt->result, row);
|
||||
}
|
||||
|
66
src/interfaces/odbc/iodbc.h
Normal file
66
src/interfaces/odbc/iodbc.h
Normal file
@ -0,0 +1,66 @@
|
||||
#ifndef _IODBC_H
|
||||
#define _IODBC_H
|
||||
|
||||
# if !defined(WINDOWS) && !defined(WIN32_SYSTEM)
|
||||
# define _UNIX_
|
||||
|
||||
# include <stdlib.h>
|
||||
# include <sys/types.h>
|
||||
|
||||
# define MEM_ALLOC(size) (malloc((size_t)(size)))
|
||||
# define MEM_FREE(ptr) {if(ptr) free(ptr);}
|
||||
|
||||
# define STRCPY(t, s) (strcpy((char*)(t), (char*)(s)))
|
||||
# define STRNCPY(t,s,n) (strncpy((char*)(t), (char*)(s), (size_t)(n)))
|
||||
# define STRCAT(t, s) (strcat((char*)(t), (char*)(s)))
|
||||
# define STRNCAT(t,s,n) (strncat((char*)(t), (char*)(s), (size_t)(n)))
|
||||
# define STREQ(a, b) (strcmp((char*)(a), (char*)(b)) == 0)
|
||||
# define STRLEN(str) ((str)? strlen((char*)(str)):0)
|
||||
|
||||
# define EXPORT
|
||||
# define CALLBACK
|
||||
# define FAR
|
||||
|
||||
typedef signed short SSHOR;
|
||||
typedef short WORD;
|
||||
typedef long DWORD;
|
||||
|
||||
typedef WORD WPARAM;
|
||||
typedef DWORD LPARAM;
|
||||
typedef void* HWND;
|
||||
typedef int BOOL;
|
||||
|
||||
# endif /* _UNIX_ */
|
||||
|
||||
# if defined(WINDOWS) || defined(WIN32_SYSTEM)
|
||||
|
||||
# include <windows.h>
|
||||
# include <windowsx.h>
|
||||
|
||||
# ifdef _MSVC_
|
||||
# define MEM_ALLOC(size) (fmalloc((size_t)(size)))
|
||||
# define MEM_FREE(ptr) ((ptr)? ffree((PTR)(ptr)):0))
|
||||
# define STRCPY(t, s) (fstrcpy((char FAR*)(t), (char FAR*)(s)))
|
||||
# define STRNCPY(t,s,n) (fstrncpy((char FAR*)(t), (char FAR*)(s), (size_t)(n)))
|
||||
# define STRLEN(str) ((str)? fstrlen((char FAR*)(str)):0)
|
||||
# define STREQ(a, b) (fstrcmp((char FAR*)(a), (char FAR*)(b) == 0)
|
||||
# endif
|
||||
|
||||
# ifdef _BORLAND_
|
||||
# define MEM_ALLOC(size) (farmalloc((unsigned long)(size))
|
||||
# define MEM_FREE(ptr) ((ptr)? farfree((void far*)(ptr)):0)
|
||||
# define STRCPY(t, s) (_fstrcpy((char FAR*)(t), (char FAR*)(s)))
|
||||
# define STRNCPY(t,s,n) (_fstrncpy((char FAR*)(t), (char FAR*)(s), (size_t)(n)))
|
||||
# define STRLEN(str) ((str)? _fstrlen((char FAR*)(str)):0)
|
||||
# define STREQ(a, b) (_fstrcmp((char FAR*)(a), (char FAR*)(b) == 0)
|
||||
# endif
|
||||
|
||||
# endif /* WINDOWS */
|
||||
|
||||
# define SYSERR (-1)
|
||||
|
||||
# ifndef NULL
|
||||
# define NULL ((void FAR*)0UL)
|
||||
# endif
|
||||
|
||||
#endif
|
237
src/interfaces/odbc/isql.h
Normal file
237
src/interfaces/odbc/isql.h
Normal file
@ -0,0 +1,237 @@
|
||||
/* Modified isql.h file from iodbc. This file should be placed in the
|
||||
* include path to be used to create ODBC compliant applications.
|
||||
*/
|
||||
#ifndef _INTRINSIC_SQL_H
|
||||
# define _INTRINSIC_SQL_H
|
||||
|
||||
typedef unsigned char UCHAR;
|
||||
typedef long int SDWORD;
|
||||
typedef short int SWORD;
|
||||
typedef unsigned long int UDWORD;
|
||||
typedef unsigned short int UWORD;
|
||||
|
||||
typedef void FAR* PTR;
|
||||
|
||||
typedef void FAR* HENV;
|
||||
typedef void FAR* HDBC;
|
||||
typedef void FAR* HSTMT;
|
||||
|
||||
typedef signed short RETCODE;
|
||||
|
||||
# ifdef WIN32
|
||||
# define SQL_API __stdcall
|
||||
# else
|
||||
# define SQL_API EXPORT CALLBACK
|
||||
# endif
|
||||
|
||||
# define ODBCVER 0x0200
|
||||
|
||||
# define SQL_MAX_MESSAGE_LENGTH 512
|
||||
# define SQL_MAX_DSN_LENGTH 32
|
||||
|
||||
/* return code */
|
||||
# define SQL_INVALID_HANDLE (-2)
|
||||
# define SQL_ERROR (-1)
|
||||
# define SQL_SUCCESS 0
|
||||
# define SQL_SUCCESS_WITH_INFO 1
|
||||
# define SQL_NO_DATA_FOUND 100
|
||||
|
||||
/* standard SQL datatypes (agree with ANSI type numbering) */
|
||||
# define SQL_CHAR 1
|
||||
# define SQL_NUMERIC 2
|
||||
# define SQL_DECIMAL 3
|
||||
# define SQL_INTEGER 4
|
||||
# define SQL_SMALLINT 5
|
||||
# define SQL_FLOAT 6
|
||||
# define SQL_REAL 7
|
||||
# define SQL_DOUBLE 8
|
||||
# define SQL_VARCHAR 12
|
||||
|
||||
# define SQL_TYPE_MIN SQL_CHAR
|
||||
# define SQL_TYPE_NULL 0
|
||||
# define SQL_TYPE_MAX SQL_VARCHAR
|
||||
|
||||
/* C to SQL datatype mapping */
|
||||
# define SQL_C_CHAR SQL_CHAR
|
||||
# define SQL_C_LONG SQL_INTEGER
|
||||
# define SQL_C_SHORT SQL_SMALLINT
|
||||
# define SQL_C_FLOAT SQL_REAL
|
||||
# define SQL_C_DOUBLE SQL_DOUBLE
|
||||
# define SQL_C_DEFAULT 99
|
||||
|
||||
# define SQL_NO_NULLS 0
|
||||
# define SQL_NULLABLE 1
|
||||
# define SQL_NULLABLE_UNKNOWN 2
|
||||
|
||||
/* some special length values */
|
||||
# define SQL_NULL_DATA (-1)
|
||||
# define SQL_DATA_AT_EXEC (-2)
|
||||
# define SQL_NTS (-3)
|
||||
|
||||
/* SQLFreeStmt flag values */
|
||||
# define SQL_CLOSE 0
|
||||
# define SQL_DROP 1
|
||||
# define SQL_UNBIND 2
|
||||
# define SQL_RESET_PARAMS 3
|
||||
|
||||
/* SQLTransact flag values */
|
||||
# define SQL_COMMIT 0
|
||||
# define SQL_ROLLBACK 1
|
||||
|
||||
/* SQLColAttributes flag values */
|
||||
# define SQL_COLUMN_COUNT 0
|
||||
# define SQL_COLUMN_LABEL 18
|
||||
# define SQL_COLATT_OPT_MAX SQL_COLUMN_LABEL
|
||||
# define SQL_COLUMN_DRIVER_START 1000
|
||||
|
||||
# define SQL_COLATT_OPT_MIN SQL_COLUMN_COUNT
|
||||
|
||||
/* Null handles */
|
||||
# define SQL_NULL_HENV 0
|
||||
# define SQL_NULL_HDBC 0
|
||||
# define SQL_NULL_HSTMT 0
|
||||
|
||||
/* All code below has been added to the original isql.h coming from iodbc */
|
||||
typedef unsigned char BYTE;
|
||||
|
||||
/* More SQLColAttributes flag values */
|
||||
#define SQL_COLUMN_NAME 1
|
||||
#define SQL_COLUMN_TYPE 2
|
||||
#define SQL_COLUMN_LENGTH 3
|
||||
#define SQL_COLUMN_PRECISION 4
|
||||
#define SQL_COLUMN_SCALE 5
|
||||
#define SQL_COLUMN_DISPLAY_SIZE 6
|
||||
#define SQL_COLUMN_NULLABLE 7
|
||||
#define SQL_COLUMN_UNSIGNED 8
|
||||
#define SQL_COLUMN_MONEY 9
|
||||
#define SQL_COLUMN_UPDATABLE 10
|
||||
#define SQL_COLUMN_AUTO_INCREMENT 11
|
||||
#define SQL_COLUMN_CASE_SENSITIVE 12
|
||||
#define SQL_COLUMN_SEARCHABLE 13
|
||||
#define SQL_COLUMN_TYPE_NAME 14
|
||||
#define SQL_COLUMN_TABLE_NAME 15
|
||||
#define SQL_COLUMN_OWNER_NAME 16
|
||||
#define SQL_COLUMN_QUALIFIER_NAME 17
|
||||
|
||||
/* SQLColAttributes Searchable flags */
|
||||
#define SQL_UNSEARCHABLE 0
|
||||
#define SQL_LIKE_ONLY 1
|
||||
#define SQL_ALL_EXCEPT_LIKE 2
|
||||
#define SQL_SEARCHABLE 3
|
||||
#define SQL_PRED_SEARCHABLE SQL_SEARCHABLE
|
||||
|
||||
/* SQLColAttributes Updateable flags */
|
||||
#define SQL_ATTR_READONLY 0
|
||||
#define SQL_ATTR_WRITE 1
|
||||
#define SQL_ATTR_READWRITE_UNKNOWN 2
|
||||
|
||||
/*
|
||||
* function prototypes previously not contained in isql.h
|
||||
*/
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
RETCODE SQL_API SQLAllocConnect (HENV henv,
|
||||
HDBC FAR * phdbc);
|
||||
RETCODE SQL_API SQLAllocEnv (HENV FAR * phenv);
|
||||
RETCODE SQL_API SQLAllocStmt (HDBC hdbc,
|
||||
HSTMT FAR * phstmt);
|
||||
RETCODE SQL_API SQLBindCol (HSTMT hstmt,
|
||||
UWORD icol,
|
||||
SWORD fCType,
|
||||
PTR rgbValue,
|
||||
SDWORD cbValueMax,
|
||||
SDWORD FAR * pcbValue);
|
||||
|
||||
RETCODE SQL_API SQLCancel (HSTMT hstmt);
|
||||
|
||||
RETCODE SQL_API SQLColAttributes (HSTMT hstmt,
|
||||
UWORD icol,
|
||||
UWORD fDescType,
|
||||
PTR rgbDesc,
|
||||
SWORD cbDescMax,
|
||||
SWORD FAR * pcbDesc,
|
||||
SDWORD FAR * pfDesc);
|
||||
|
||||
RETCODE SQL_API SQLConnect (HDBC hdbc,
|
||||
UCHAR FAR * szDSN,
|
||||
SWORD cbDSN,
|
||||
UCHAR FAR * szUID,
|
||||
SWORD cbUID,
|
||||
UCHAR FAR * szAuthStr,
|
||||
SWORD cbAuthStr);
|
||||
|
||||
RETCODE SQL_API SQLDescribeCol (HSTMT hstmt,
|
||||
UWORD icol,
|
||||
UCHAR FAR * szColName,
|
||||
SWORD cbColNameMax,
|
||||
SWORD FAR * pcbColName,
|
||||
SWORD FAR * pfSqlType,
|
||||
UDWORD FAR * pcbColDef,
|
||||
SWORD FAR * pibScale,
|
||||
SWORD FAR * pfNullable);
|
||||
|
||||
RETCODE SQL_API SQLDisconnect (HDBC hdbc);
|
||||
|
||||
RETCODE SQL_API SQLError (HENV henv,
|
||||
HDBC hdbc,
|
||||
HSTMT hstmt,
|
||||
UCHAR FAR * szSqlState,
|
||||
SDWORD FAR * pfNativeError,
|
||||
UCHAR FAR * szErrorMsg,
|
||||
SWORD cbErrorMsgMax,
|
||||
SWORD FAR * pcbErrorMsg);
|
||||
|
||||
RETCODE SQL_API SQLExecDirect (HSTMT hstmt,
|
||||
UCHAR FAR * szSqlStr,
|
||||
SDWORD cbSqlStr);
|
||||
|
||||
RETCODE SQL_API SQLExecute (HSTMT hstmt);
|
||||
|
||||
RETCODE SQL_API SQLFetch (HSTMT hstmt);
|
||||
|
||||
RETCODE SQL_API SQLFreeConnect (HDBC hdbc);
|
||||
|
||||
RETCODE SQL_API SQLFreeEnv (HENV henv);
|
||||
|
||||
RETCODE SQL_API SQLFreeStmt (HSTMT hstmt,
|
||||
UWORD fOption);
|
||||
|
||||
RETCODE SQL_API SQLGetCursorName (HSTMT hstmt,
|
||||
UCHAR FAR * szCursor,
|
||||
SWORD cbCursorMax,
|
||||
SWORD FAR * pcbCursor);
|
||||
|
||||
RETCODE SQL_API SQLNumResultCols (HSTMT hstmt,
|
||||
SWORD FAR * pccol);
|
||||
|
||||
RETCODE SQL_API SQLPrepare (HSTMT hstmt,
|
||||
UCHAR FAR * szSqlStr,
|
||||
SDWORD cbSqlStr);
|
||||
|
||||
RETCODE SQL_API SQLRowCount (HSTMT hstmt,
|
||||
SDWORD FAR * pcrow);
|
||||
|
||||
RETCODE SQL_API SQLSetCursorName (HSTMT hstmt,
|
||||
UCHAR FAR * szCursor,
|
||||
SWORD cbCursor);
|
||||
|
||||
RETCODE SQL_API SQLTransact (HENV henv,
|
||||
HDBC hdbc,
|
||||
UWORD fType);
|
||||
|
||||
RETCODE SQL_API SQLSetParam (HSTMT hstmt,
|
||||
UWORD ipar,
|
||||
SWORD fCType,
|
||||
SWORD fSqlType,
|
||||
UDWORD cbColDef,
|
||||
SWORD ibScale,
|
||||
PTR rgbValue,
|
||||
SDWORD FAR * pcbValue);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
1539
src/interfaces/odbc/isqlext.h
Normal file
1539
src/interfaces/odbc/isqlext.h
Normal file
File diff suppressed because it is too large
Load Diff
@ -13,7 +13,7 @@
|
||||
|
||||
#include "psqlodbc.h"
|
||||
|
||||
typedef struct lo_arg {
|
||||
struct lo_arg {
|
||||
int isint;
|
||||
int len;
|
||||
union
|
||||
|
@ -37,7 +37,7 @@ static FILE *LOGFP = 0;
|
||||
fmt = va_arg(args, char *);
|
||||
|
||||
if (! LOGFP) {
|
||||
LOGFP = fopen("c:\\mylog.log", "w");
|
||||
LOGFP = fopen(MYLOGFILE, "w");
|
||||
setbuf(LOGFP, NULL);
|
||||
}
|
||||
|
||||
@ -64,7 +64,7 @@ static FILE *LOGFP = 0;
|
||||
fmt = va_arg(args, char *);
|
||||
|
||||
if (! LOGFP) {
|
||||
LOGFP = fopen("c:\\psqlodbc.log", "w");
|
||||
LOGFP = fopen(QLOGFILE, "w");
|
||||
setbuf(LOGFP, NULL);
|
||||
}
|
||||
|
||||
@ -77,12 +77,24 @@ static FILE *LOGFP = 0;
|
||||
#endif
|
||||
|
||||
/* Undefine these because windows.h will redefine and cause a warning */
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#ifndef UNIX
|
||||
#undef va_start
|
||||
#undef va_end
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef HAVE_IODBC
|
||||
#include "iodbc.h"
|
||||
#include "isql.h"
|
||||
#else
|
||||
#include <windows.h>
|
||||
#include <sql.h>
|
||||
#endif
|
||||
|
||||
|
||||
/* returns STRCPY_FAIL, STRCPY_TRUNCATED, or #bytes copied (not including null term) */
|
||||
int
|
||||
@ -155,7 +167,7 @@ make_string(char *s, int len, char *buf)
|
||||
int length;
|
||||
char *str;
|
||||
|
||||
if(s && (len > 0 || len == SQL_NTS)) {
|
||||
if(s && (len > 0 || (len == SQL_NTS && strlen(s) > 0))) {
|
||||
length = (len > 0) ? len : strlen(s);
|
||||
|
||||
if (buf) {
|
||||
|
@ -10,6 +10,15 @@
|
||||
#ifndef __MISC_H__
|
||||
#define __MISC_H__
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#ifdef UNIX
|
||||
#include "gpps.h"
|
||||
#define SQLGetPrivateProfileString(a,b,c,d,e,f) GetPrivateProfileString(a,b,c,d,e,f)
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
/* Uncomment MY_LOG define to compile in the mylog() statements.
|
||||
@ -30,12 +39,22 @@
|
||||
|
||||
|
||||
#ifdef MY_LOG
|
||||
#ifdef UNIX
|
||||
#define MYLOGFILE "/tmp/mylog.log"
|
||||
#else
|
||||
#define MYLOGFILE "c:\\mylog.log"
|
||||
#endif
|
||||
void mylog(); /* prototype */
|
||||
#else
|
||||
#define mylog // mylog
|
||||
#endif
|
||||
|
||||
#ifdef Q_LOG
|
||||
#ifdef UNIX
|
||||
#define QLOGFILE "/tmp/psqlodbc.log"
|
||||
#else
|
||||
#define QLOGFILE "c:\\psqlodbc.log"
|
||||
#endif
|
||||
void qlog(); /* prototype */
|
||||
#else
|
||||
#define qlog // qlog
|
||||
|
3
src/interfaces/odbc/odbcinst.ini
Normal file
3
src/interfaces/odbc/odbcinst.ini
Normal file
@ -0,0 +1,3 @@
|
||||
[PostgreSQL]
|
||||
Debug = 0
|
||||
CommLog = 1
|
@ -13,10 +13,22 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include "psqlodbc.h"
|
||||
|
||||
#ifdef HAVE_IODBC
|
||||
#include "iodbc.h"
|
||||
#include "isql.h"
|
||||
#include "isqlext.h"
|
||||
#else
|
||||
#include <windows.h>
|
||||
#include <sql.h>
|
||||
#include <sqlext.h>
|
||||
#endif
|
||||
|
||||
#include "environ.h"
|
||||
#include "connection.h"
|
||||
#include "statement.h"
|
||||
@ -81,12 +93,15 @@ ConnectionClass *conn = (ConnectionClass *) hdbc;
|
||||
case SQL_ACCESS_MODE:
|
||||
break;
|
||||
|
||||
case SQL_TXN_ISOLATION:
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
char option[32];
|
||||
conn->errormsg = "This option is currently unsupported by the driver";
|
||||
char option[64];
|
||||
conn->errormsg = "Driver does not support setting this connect option";
|
||||
conn->errornumber = CONN_UNSUPPORTED_OPTION;
|
||||
sprintf(option, "fOption=%d", fOption);
|
||||
sprintf(option, "fOption=%d, vParam=%d", fOption, vParam);
|
||||
CC_log_error(func, option, conn);
|
||||
return SQL_ERROR;
|
||||
}
|
||||
@ -126,8 +141,8 @@ ConnectionClass *conn = (ConnectionClass *) hdbc;
|
||||
|
||||
default:
|
||||
{
|
||||
char option[32];
|
||||
conn->errormsg = "This option is currently unsupported by the driver";
|
||||
char option[64];
|
||||
conn->errormsg = "Driver does not support getting this connect option";
|
||||
conn->errornumber = CONN_UNSUPPORTED_OPTION;
|
||||
sprintf(option, "fOption=%d", fOption);
|
||||
CC_log_error(func, option, conn);
|
||||
@ -242,10 +257,10 @@ char changed = FALSE;
|
||||
|
||||
default:
|
||||
{
|
||||
char option[32];
|
||||
char option[64];
|
||||
stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR;
|
||||
stmt->errormsg = "Driver does not support this statement option";
|
||||
sprintf(option, "fOption=%d", fOption);
|
||||
stmt->errormsg = "Driver does not support setting this statement option";
|
||||
sprintf(option, "fOption=%d, vParam=%d", fOption, vParam);
|
||||
SC_log_error(func, option, stmt);
|
||||
return SQL_ERROR;
|
||||
}
|
||||
@ -326,9 +341,9 @@ StatementClass *stmt = (StatementClass *) hstmt;
|
||||
|
||||
default:
|
||||
{
|
||||
char option[32];
|
||||
char option[64];
|
||||
stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR;
|
||||
stmt->errormsg = "Driver does not support this statement option";
|
||||
stmt->errormsg = "Driver does not support getting this statement option";
|
||||
sprintf(option, "fOption=%d", fOption);
|
||||
SC_log_error(func, option, stmt);
|
||||
return SQL_ERROR;
|
||||
|
775
src/interfaces/odbc/parse.c
Normal file
775
src/interfaces/odbc/parse.c
Normal file
@ -0,0 +1,775 @@
|
||||
|
||||
/* Module: parse.c
|
||||
*
|
||||
* Description: This module contains routines related to parsing SQL statements.
|
||||
* This can be useful for two reasons:
|
||||
*
|
||||
* 1. So the query does not actually have to be executed to return data about it
|
||||
*
|
||||
* 2. To be able to return information about precision, nullability, aliases, etc.
|
||||
* in the functions SQLDescribeCol and SQLColAttributes. Currently, Postgres
|
||||
* doesn't return any information about these things in a query.
|
||||
*
|
||||
* Classes: none
|
||||
*
|
||||
* API functions: none
|
||||
*
|
||||
* Comments: See "notice.txt" for copyright and license information.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "statement.h"
|
||||
#include "connection.h"
|
||||
#include "qresult.h"
|
||||
#include "pgtypes.h"
|
||||
|
||||
#ifdef UNIX
|
||||
#if !HAVE_STRICMP
|
||||
#define stricmp(s1,s2) strcasecmp(s1,s2)
|
||||
#define strnicmp(s1,s2,n) strncasecmp(s1,s2,n)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define FLD_INCR 32
|
||||
#define TAB_INCR 8
|
||||
#define COL_INCR 16
|
||||
|
||||
char *
|
||||
getNextToken(char *s, char *token, int smax, char *delim, char *quote, char *dquote, char *numeric)
|
||||
{
|
||||
int i = 0;
|
||||
int out = 0;
|
||||
char qc, in_escape = FALSE;
|
||||
|
||||
if (smax <= 1)
|
||||
return NULL;
|
||||
|
||||
smax--;
|
||||
|
||||
/* skip leading delimiters */
|
||||
while (isspace(s[i]) || s[i] == ',') {
|
||||
// mylog("skipping '%c'\n", s[i]);
|
||||
i++;
|
||||
}
|
||||
|
||||
if (s[0] == '\0') {
|
||||
token[0] = '\0';
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (quote) *quote = FALSE;
|
||||
if (dquote) *dquote = FALSE;
|
||||
if (numeric) *numeric = FALSE;
|
||||
|
||||
/* get the next token */
|
||||
while ( ! isspace(s[i]) && s[i] != ',' && s[i] != '\0' && out != smax) {
|
||||
|
||||
/* Handle quoted stuff */
|
||||
if ( out == 0 && (s[i] == '\"' || s[i] == '\'')) {
|
||||
qc = s[i];
|
||||
if (qc == '\"') {
|
||||
if (dquote) *dquote = TRUE;
|
||||
}
|
||||
if (qc == '\'') {
|
||||
if (quote) *quote = TRUE;
|
||||
}
|
||||
|
||||
i++; /* dont return the quote */
|
||||
while (s[i] != '\0' && out != smax) {
|
||||
if (s[i] == qc && ! in_escape) {
|
||||
break;
|
||||
}
|
||||
if (s[i] == '\\' && ! in_escape) {
|
||||
in_escape = TRUE;
|
||||
}
|
||||
else {
|
||||
in_escape = FALSE;
|
||||
token[out++] = s[i];
|
||||
}
|
||||
i++;
|
||||
}
|
||||
if (s[i] == qc)
|
||||
i++;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Check for numeric literals */
|
||||
if ( out == 0 && isdigit(s[i])) {
|
||||
if (numeric) *numeric = TRUE;
|
||||
token[out++] = s[i++];
|
||||
while ( isalnum(s[i]) || s[i] == '.')
|
||||
token[out++] = s[i++];
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if ( ispunct(s[i])) {
|
||||
if (out == 0) {
|
||||
token[out++] = s[i++];
|
||||
break;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
if (out != smax)
|
||||
token[out++] = s[i];
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
// mylog("done -- s[%d] = '%c'\n", i, s[i]);
|
||||
|
||||
token[out] = '\0';
|
||||
|
||||
/* find the delimiter */
|
||||
while ( isspace(s[i]))
|
||||
i++;
|
||||
|
||||
/* return the most priority delimiter */
|
||||
if (s[i] == ',') {
|
||||
if (delim) *delim = s[i];
|
||||
}
|
||||
else if (s[i] == '\0') {
|
||||
if (delim) *delim = '\0';
|
||||
}
|
||||
else {
|
||||
if (delim) *delim = ' ';
|
||||
}
|
||||
|
||||
/* skip trailing blanks */
|
||||
while ( isspace(s[i])) {
|
||||
i++;
|
||||
}
|
||||
|
||||
return &s[i];
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
QR_set_num_fields(stmt->result, 14);
|
||||
QR_set_field_info(stmt->result, 0, "TABLE_QUALIFIER", PG_TYPE_TEXT, MAX_INFO_STRING);
|
||||
QR_set_field_info(stmt->result, 1, "TABLE_OWNER", PG_TYPE_TEXT, MAX_INFO_STRING);
|
||||
QR_set_field_info(stmt->result, 2, "TABLE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
|
||||
QR_set_field_info(stmt->result, 3, "COLUMN_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
|
||||
QR_set_field_info(stmt->result, 4, "DATA_TYPE", PG_TYPE_INT2, 2);
|
||||
QR_set_field_info(stmt->result, 5, "TYPE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
|
||||
QR_set_field_info(stmt->result, 6, "PRECISION", PG_TYPE_INT4, 4);
|
||||
QR_set_field_info(stmt->result, 7, "LENGTH", PG_TYPE_INT4, 4);
|
||||
QR_set_field_info(stmt->result, 8, "SCALE", PG_TYPE_INT2, 2);
|
||||
QR_set_field_info(stmt->result, 9, "RADIX", PG_TYPE_INT2, 2);
|
||||
QR_set_field_info(stmt->result, 10, "NULLABLE", PG_TYPE_INT2, 2);
|
||||
QR_set_field_info(stmt->result, 11, "REMARKS", PG_TYPE_TEXT, 254);
|
||||
// User defined fields
|
||||
QR_set_field_info(stmt->result, 12, "DISPLAY_SIZE", PG_TYPE_INT4, 4);
|
||||
QR_set_field_info(stmt->result, 13, "FIELD_TYPE", PG_TYPE_INT4, 4);
|
||||
*/
|
||||
|
||||
void
|
||||
getColInfo(COL_INFO *col_info, FIELD_INFO *fi, int k)
|
||||
{
|
||||
if (fi->name[0] == '\0')
|
||||
strcpy(fi->name, QR_get_value_manual(col_info->result, k, 3));
|
||||
|
||||
fi->type = atoi( QR_get_value_manual(col_info->result, k, 13));
|
||||
fi->precision = atoi( QR_get_value_manual(col_info->result, k, 6));
|
||||
fi->length = atoi( QR_get_value_manual(col_info->result, k, 7));
|
||||
fi->nullable = atoi( QR_get_value_manual(col_info->result, k, 10));
|
||||
fi->display_size = atoi( QR_get_value_manual(col_info->result, k, 12));
|
||||
}
|
||||
|
||||
char
|
||||
searchColInfo(COL_INFO *col_info, FIELD_INFO *fi)
|
||||
{
|
||||
int k;
|
||||
char *col;
|
||||
|
||||
|
||||
for (k = 0; k < QR_get_num_tuples(col_info->result); k++) {
|
||||
col = QR_get_value_manual(col_info->result, k, 3);
|
||||
if ( ! strcmp(col, fi->name)) {
|
||||
getColInfo(col_info, fi, k);
|
||||
|
||||
mylog("PARSE: searchColInfo: \n");
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
char
|
||||
parse_statement(StatementClass *stmt)
|
||||
{
|
||||
char token[256];
|
||||
char delim, quote, dquote, numeric, unquoted;
|
||||
char *ptr;
|
||||
char in_select = FALSE, in_distinct = FALSE, in_on = FALSE, in_from = FALSE, in_where = FALSE, in_table = FALSE;
|
||||
char in_field = FALSE, in_expr = FALSE, in_func = FALSE, in_dot = FALSE, in_as = FALSE;
|
||||
int j, i, k, n, blevel = 0;
|
||||
FIELD_INFO **fi;
|
||||
TABLE_INFO **ti;
|
||||
char parse;
|
||||
ConnectionClass *conn = stmt->hdbc;
|
||||
HSTMT hcol_stmt;
|
||||
StatementClass *col_stmt;
|
||||
RETCODE result;
|
||||
|
||||
|
||||
ptr = stmt->statement;
|
||||
fi = stmt->fi;
|
||||
ti = stmt->ti;
|
||||
|
||||
stmt->nfld = 0;
|
||||
stmt->ntab = 0;
|
||||
|
||||
while (ptr = getNextToken(ptr, token, sizeof(token), &delim, "e, &dquote, &numeric)) {
|
||||
|
||||
unquoted = ! ( quote || dquote );
|
||||
|
||||
mylog("unquoted=%d, quote=%d, dquote=%d, numeric=%d, delim='%c', token='%s', ptr='%s'\n", unquoted, quote, dquote, numeric, delim, token, ptr);
|
||||
|
||||
if ( unquoted && ! stricmp(token, "select")) {
|
||||
in_select = TRUE;
|
||||
|
||||
mylog("SELECT\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( unquoted && in_select && ! stricmp(token, "distinct")) {
|
||||
in_distinct = TRUE;
|
||||
|
||||
mylog("DISTINCT\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( unquoted && ! stricmp(token, "into")) {
|
||||
in_select = FALSE;
|
||||
|
||||
mylog("INTO\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( unquoted && ! stricmp(token, "from")) {
|
||||
in_select = FALSE;
|
||||
in_from = TRUE;
|
||||
|
||||
mylog("FROM\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( unquoted && (! stricmp(token, "where") ||
|
||||
! stricmp(token, "union") ||
|
||||
! stricmp(token, "order") ||
|
||||
! stricmp(token, "group") ||
|
||||
! stricmp(token, "having"))) {
|
||||
|
||||
in_select = FALSE;
|
||||
in_from = FALSE;
|
||||
in_where = TRUE;
|
||||
|
||||
mylog("WHERE...\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (in_select) {
|
||||
|
||||
if ( in_distinct) {
|
||||
mylog("in distinct\n");
|
||||
|
||||
if (unquoted && ! stricmp(token, "on")) {
|
||||
in_on = TRUE;
|
||||
mylog("got on\n");
|
||||
continue;
|
||||
}
|
||||
if (in_on) {
|
||||
in_distinct = FALSE;
|
||||
in_on = FALSE;
|
||||
continue; /* just skip the unique on field */
|
||||
}
|
||||
mylog("done distinct\n");
|
||||
in_distinct = FALSE;
|
||||
}
|
||||
|
||||
if ( in_expr || in_func) { /* just eat the expression */
|
||||
mylog("in_expr=%d or func=%d\n", in_expr, in_func);
|
||||
if (quote || dquote)
|
||||
continue;
|
||||
|
||||
if (in_expr && blevel == 0 && delim == ',') {
|
||||
mylog("**** in_expr and Got comma\n");
|
||||
in_expr = FALSE;
|
||||
in_field = FALSE;
|
||||
}
|
||||
|
||||
else if (token[0] == '(') {
|
||||
blevel++;
|
||||
mylog("blevel++ = %d\n", blevel);
|
||||
}
|
||||
else if (token[0] == ')') {
|
||||
blevel--;
|
||||
mylog("blevel-- = %d\n", blevel);
|
||||
if (delim==',') {
|
||||
in_func = FALSE;
|
||||
in_expr = FALSE;
|
||||
in_field = FALSE;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( ! in_field) {
|
||||
|
||||
if ( ! token[0])
|
||||
continue;
|
||||
|
||||
if ( ! (stmt->nfld % FLD_INCR)) {
|
||||
mylog("reallocing at nfld=%d\n", stmt->nfld);
|
||||
fi = (FIELD_INFO **) realloc(fi, (stmt->nfld + FLD_INCR) * sizeof(FIELD_INFO *));
|
||||
if ( ! fi) {
|
||||
stmt->parse_status = STMT_PARSE_FATAL;
|
||||
return FALSE;
|
||||
}
|
||||
stmt->fi = fi;
|
||||
}
|
||||
|
||||
fi[stmt->nfld] = (FIELD_INFO *) malloc( sizeof(FIELD_INFO));
|
||||
if (fi[stmt->nfld] == NULL) {
|
||||
stmt->parse_status = STMT_PARSE_FATAL;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Initialize the field info */
|
||||
memset(fi[stmt->nfld], 0, sizeof(FIELD_INFO));
|
||||
|
||||
/* double quotes are for qualifiers */
|
||||
if (dquote)
|
||||
fi[stmt->nfld]->dquote = TRUE;
|
||||
|
||||
if (quote) {
|
||||
fi[stmt->nfld++]->quote = TRUE;
|
||||
continue;
|
||||
}
|
||||
else if (numeric) {
|
||||
mylog("**** got numeric: nfld = %d\n", stmt->nfld);
|
||||
fi[stmt->nfld]->numeric = TRUE;
|
||||
}
|
||||
else if (token[0] == '(') { /* expression */
|
||||
mylog("got EXPRESSION\n");
|
||||
fi[stmt->nfld++]->expr = TRUE;
|
||||
in_expr = TRUE;
|
||||
blevel = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
else {
|
||||
strcpy(fi[stmt->nfld]->name, token);
|
||||
fi[stmt->nfld]->dot[0] = '\0';
|
||||
}
|
||||
mylog("got field='%s', dot='%s'\n", fi[stmt->nfld]->name, fi[stmt->nfld]->dot);
|
||||
|
||||
if (delim == ',') {
|
||||
mylog("comma (1)\n");
|
||||
}
|
||||
else {
|
||||
in_field = TRUE;
|
||||
}
|
||||
stmt->nfld++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/**************************/
|
||||
/* We are in a field now */
|
||||
/**************************/
|
||||
if (in_dot) {
|
||||
stmt->nfld--;
|
||||
strcpy(fi[stmt->nfld]->dot, fi[stmt->nfld]->name);
|
||||
strcpy(fi[stmt->nfld]->name, token);
|
||||
stmt->nfld++;
|
||||
in_dot = FALSE;
|
||||
|
||||
if (delim == ',') {
|
||||
mylog("in_dot: got comma\n");
|
||||
in_field = FALSE;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (in_as) {
|
||||
stmt->nfld--;
|
||||
strcpy(fi[stmt->nfld]->alias, token);
|
||||
mylog("alias for field '%s' is '%s'\n", fi[stmt->nfld]->name, fi[stmt->nfld]->alias);
|
||||
in_as = FALSE;
|
||||
in_field = FALSE;
|
||||
|
||||
stmt->nfld++;
|
||||
|
||||
if (delim == ',') {
|
||||
mylog("comma(2)\n");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Function */
|
||||
if (token[0] == '(') {
|
||||
in_func = TRUE;
|
||||
blevel = 1;
|
||||
fi[stmt->nfld-1]->func = TRUE;
|
||||
/* name will have the function name -- maybe useful some day */
|
||||
mylog("**** got function = '%s'\n", fi[stmt->nfld-1]->name);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (token[0] == '.') {
|
||||
in_dot = TRUE;
|
||||
mylog("got dot\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( ! stricmp(token, "as")) {
|
||||
in_as = TRUE;
|
||||
mylog("got AS\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
/* otherwise, its probably an expression */
|
||||
in_expr = TRUE;
|
||||
fi[stmt->nfld-1]->expr = TRUE;
|
||||
fi[stmt->nfld-1]->name[0] = '\0';
|
||||
mylog("*** setting expression\n");
|
||||
|
||||
}
|
||||
|
||||
if (in_from) {
|
||||
|
||||
if ( ! in_table) {
|
||||
if ( ! token[0])
|
||||
continue;
|
||||
|
||||
if ( ! (stmt->ntab % TAB_INCR)) {
|
||||
ti = (TABLE_INFO **) realloc(ti, (stmt->ntab + TAB_INCR) * sizeof(TABLE_INFO *));
|
||||
if ( ! ti) {
|
||||
stmt->parse_status = STMT_PARSE_FATAL;
|
||||
return FALSE;
|
||||
}
|
||||
stmt->ti = ti;
|
||||
}
|
||||
ti[stmt->ntab] = (TABLE_INFO *) malloc(sizeof(TABLE_INFO));
|
||||
if (ti[stmt->ntab] == NULL) {
|
||||
stmt->parse_status = STMT_PARSE_FATAL;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ti[stmt->ntab]->alias[0] = '\0';
|
||||
|
||||
strcpy(ti[stmt->ntab]->name, token);
|
||||
mylog("got table = '%s'\n", ti[stmt->ntab]->name);
|
||||
|
||||
if (delim == ',') {
|
||||
mylog("more than 1 tables\n");
|
||||
}
|
||||
else {
|
||||
in_table = TRUE;
|
||||
}
|
||||
stmt->ntab++;
|
||||
continue;
|
||||
}
|
||||
|
||||
strcpy(ti[stmt->ntab-1]->alias, token);
|
||||
mylog("alias for table '%s' is '%s'\n", ti[stmt->ntab-1]->name, ti[stmt->ntab-1]->alias);
|
||||
in_table = FALSE;
|
||||
if (delim == ',') {
|
||||
mylog("more than 1 tables\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*************************************************/
|
||||
/* Resolve any possible field names with tables */
|
||||
/*************************************************/
|
||||
|
||||
parse = TRUE;
|
||||
|
||||
/* Resolve field names with tables */
|
||||
for (i = 0; i < stmt->nfld; i++) {
|
||||
|
||||
if (fi[i]->func || fi[i]->expr || fi[i]->numeric) {
|
||||
fi[i]->ti = NULL;
|
||||
fi[i]->type = -1;
|
||||
parse = FALSE;
|
||||
continue;
|
||||
}
|
||||
|
||||
else if (fi[i]->quote) { /* handle as text */
|
||||
fi[i]->ti = NULL;
|
||||
fi[i]->type = PG_TYPE_TEXT;
|
||||
fi[i]->precision = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* its a dot, resolve to table or alias */
|
||||
else if (fi[i]->dot[0]) {
|
||||
for (k = 0; k < stmt->ntab; k++) {
|
||||
if ( ! stricmp(ti[k]->name, fi[i]->dot)) {
|
||||
fi[i]->ti = ti[k];
|
||||
break;
|
||||
}
|
||||
else if ( ! stricmp(ti[k]->alias, fi[i]->dot)) {
|
||||
fi[i]->ti = ti[k];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (stmt->ntab == 1)
|
||||
fi[i]->ti = ti[0];
|
||||
}
|
||||
|
||||
mylog("--------------------------------------------\n");
|
||||
mylog("nfld=%d, ntab=%d\n", stmt->nfld, stmt->ntab);
|
||||
|
||||
for (i=0; i < stmt->nfld; i++) {
|
||||
mylog("Field %d: expr=%d, func=%d, quote=%d, dquote=%d, numeric=%d, name='%s', alias='%s', dot='%s'\n", i, fi[i]->expr, fi[i]->func, fi[i]->quote, fi[i]->dquote, fi[i]->numeric, fi[i]->name, fi[i]->alias, fi[i]->dot);
|
||||
if (fi[i]->ti)
|
||||
mylog(" ----> table_name='%s', table_alias='%s'\n", fi[i]->ti->name, fi[i]->ti->alias);
|
||||
}
|
||||
|
||||
for (i=0; i < stmt->ntab; i++) {
|
||||
mylog("Table %d: name='%s', alias='%s'\n", i, ti[i]->name, ti[i]->alias);
|
||||
}
|
||||
|
||||
|
||||
/******************************************************/
|
||||
/* Now save the SQLColumns Info for the parse tables */
|
||||
/******************************************************/
|
||||
|
||||
|
||||
/* Call SQLColumns for each table and store the result */
|
||||
for (i = 0; i < stmt->ntab; i++) {
|
||||
|
||||
/* See if already got it */
|
||||
char found = FALSE;
|
||||
for (k = 0; k < conn->ntables; k++) {
|
||||
if ( ! stricmp(conn->col_info[k]->name, ti[i]->name)) {
|
||||
mylog("FOUND col_info table='%s'\n", ti[i]->name);
|
||||
found = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! found) {
|
||||
|
||||
mylog("PARSE: Getting SQLColumns for table[%d]='%s'\n", i, ti[i]->name);
|
||||
|
||||
result = SQLAllocStmt( stmt->hdbc, &hcol_stmt);
|
||||
if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
|
||||
stmt->errormsg = "SQLAllocStmt failed in parse_statement for columns.";
|
||||
stmt->errornumber = STMT_NO_MEMORY_ERROR;
|
||||
stmt->parse_status = STMT_PARSE_FATAL;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
col_stmt = (StatementClass *) hcol_stmt;
|
||||
col_stmt->internal = TRUE;
|
||||
|
||||
result = SQLColumns(hcol_stmt, "", 0, "", 0,
|
||||
ti[i]->name, (SWORD) strlen(ti[i]->name), "", 0);
|
||||
|
||||
mylog(" Past SQLColumns\n");
|
||||
if (result == SQL_SUCCESS) {
|
||||
mylog(" Success\n");
|
||||
if ( ! (conn->ntables % COL_INCR)) {
|
||||
|
||||
mylog("PARSE: Allocing col_info at ntables=%d\n", conn->ntables);
|
||||
|
||||
conn->col_info = (COL_INFO **) realloc(conn->col_info, (conn->ntables + COL_INCR) * sizeof(COL_INFO *));
|
||||
if ( ! conn->col_info) {
|
||||
stmt->parse_status = STMT_PARSE_FATAL;
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
mylog("PARSE: malloc at conn->col_info[%d]\n", conn->ntables);
|
||||
conn->col_info[conn->ntables] = (COL_INFO *) malloc(sizeof(COL_INFO));
|
||||
if ( ! conn->col_info[conn->ntables]) {
|
||||
stmt->parse_status = STMT_PARSE_FATAL;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Store the table name and the SQLColumns result structure */
|
||||
strcpy(conn->col_info[conn->ntables]->name, ti[i]->name);
|
||||
conn->col_info[conn->ntables]->result = col_stmt->result;
|
||||
|
||||
/* The connection will now free the result structures, so make
|
||||
sure that the statement doesn't free it
|
||||
*/
|
||||
col_stmt->result = NULL;
|
||||
|
||||
conn->ntables++;
|
||||
|
||||
SQLFreeStmt(hcol_stmt, SQL_DROP);
|
||||
mylog("Created col_info table='%s', ntables=%d\n", ti[i]->name, conn->ntables);
|
||||
}
|
||||
else {
|
||||
SQLFreeStmt(hcol_stmt, SQL_DROP);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Associate a table from the statement with a SQLColumn info */
|
||||
ti[i]->col_info = conn->col_info[k];
|
||||
mylog("associate col_info: i=%d, k=%d\n", i, k);
|
||||
}
|
||||
|
||||
|
||||
mylog("Done SQLColumns\n");
|
||||
|
||||
/******************************************************/
|
||||
/* Now resolve the fields to point to column info */
|
||||
/******************************************************/
|
||||
|
||||
|
||||
|
||||
for (i = 0; i < stmt->nfld;) {
|
||||
|
||||
/* Dont worry about functions or quotes */
|
||||
if (fi[i]->func || fi[i]->quote || fi[i]->numeric) {
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Stars get expanded to all fields in the table */
|
||||
else if (fi[i]->name[0] == '*') {
|
||||
|
||||
char do_all_tables;
|
||||
int total_cols, old_size, need, cols;
|
||||
|
||||
mylog("expanding field %d\n", i);
|
||||
|
||||
total_cols = 0;
|
||||
|
||||
if (fi[i]->ti) /* The star represents only the qualified table */
|
||||
total_cols = QR_get_num_tuples(fi[i]->ti->col_info->result);
|
||||
|
||||
else { /* The star represents all tables */
|
||||
|
||||
/* Calculate the total number of columns after expansion */
|
||||
for (k = 0; k < stmt->ntab; k++) {
|
||||
total_cols += QR_get_num_tuples(ti[k]->col_info->result);
|
||||
}
|
||||
}
|
||||
total_cols--; /* makes up for the star */
|
||||
|
||||
/* Allocate some more field pointers if necessary */
|
||||
//-------------------------------------------------------------
|
||||
old_size = (stmt->nfld / FLD_INCR * FLD_INCR + FLD_INCR);
|
||||
need = total_cols - (old_size - stmt->nfld);
|
||||
|
||||
mylog("k=%d, total_cols=%d, old_size=%d, need=%d\n", k,total_cols,old_size,need);
|
||||
|
||||
if (need > 0) {
|
||||
int new_size = need / FLD_INCR * FLD_INCR + FLD_INCR;
|
||||
mylog("need more cols: new_size = %d\n", new_size);
|
||||
fi = (FIELD_INFO **) realloc(fi, (old_size + new_size) * sizeof(FIELD_INFO *));
|
||||
if ( ! fi) {
|
||||
stmt->parse_status = STMT_PARSE_FATAL;
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------
|
||||
// copy any other fields (if there are any) up past the expansion
|
||||
for (j = stmt->nfld - 1; j > i; j--) {
|
||||
mylog("copying field %d to %d\n", j, total_cols + j);
|
||||
fi[total_cols + j] = fi[j];
|
||||
}
|
||||
mylog("done copying fields\n");
|
||||
|
||||
//-------------------------------------------------------------
|
||||
// Set the new number of fields
|
||||
stmt->nfld += total_cols;
|
||||
mylog("stmt->nfld now at %d\n", stmt->nfld);
|
||||
|
||||
|
||||
//-------------------------------------------------------------
|
||||
// copy the new field info
|
||||
|
||||
|
||||
do_all_tables = (fi[i]->ti ? FALSE : TRUE);
|
||||
|
||||
for (k = 0; k < (do_all_tables ? stmt->ntab : 1); k++) {
|
||||
|
||||
TABLE_INFO *the_ti = do_all_tables ? ti[k] : fi[i]->ti;
|
||||
|
||||
cols = QR_get_num_tuples(the_ti->col_info->result);
|
||||
|
||||
for (n = 0; n < cols; n++) {
|
||||
mylog("creating field info: n=%d\n", n);
|
||||
// skip malloc (already did it for the Star)
|
||||
if (k > 0 || n > 0) {
|
||||
mylog("allocating field info at %d\n", n + i);
|
||||
fi[n + i] = (FIELD_INFO *) malloc( sizeof(FIELD_INFO));
|
||||
if (fi[n + i] == NULL) {
|
||||
stmt->parse_status = STMT_PARSE_FATAL;
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
/* Initialize the new space (or the * field) */
|
||||
memset(fi[n + i], 0, sizeof(FIELD_INFO));
|
||||
fi[n + i]->ti = the_ti;
|
||||
|
||||
mylog("about to copy at %d\n", n + i);
|
||||
|
||||
getColInfo(the_ti->col_info, fi[n + i], n);
|
||||
|
||||
mylog("done copying\n");
|
||||
}
|
||||
|
||||
i += cols;
|
||||
mylog("i now at %d\n", i);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------
|
||||
}
|
||||
|
||||
/* We either know which table the field was in because it was qualified
|
||||
with a table name or alias -OR- there was only 1 table.
|
||||
*/
|
||||
else if (fi[i]->ti) {
|
||||
|
||||
if ( ! searchColInfo(fi[i]->ti->col_info, fi[i]))
|
||||
parse = FALSE;
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
/* Don't know the table -- search all tables in "from" list */
|
||||
else {
|
||||
parse = FALSE;
|
||||
for (k = 0; k < stmt->ntab; k++) {
|
||||
if ( searchColInfo(ti[k]->col_info, fi[i])) {
|
||||
fi[i]->ti = ti[k]; /* now know the table */
|
||||
parse = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ( ! parse)
|
||||
stmt->parse_status = STMT_PARSE_INCOMPLETE;
|
||||
else
|
||||
stmt->parse_status = STMT_PARSE_COMPLETE;
|
||||
|
||||
|
||||
mylog("done parse_statement: parse=%d, parse_status=%d\n", parse, stmt->parse_status);
|
||||
return parse;
|
||||
}
|
||||
|
@ -15,15 +15,26 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include "psqlodbc.h"
|
||||
#include "dlg_specific.h"
|
||||
#include "pgtypes.h"
|
||||
#include "statement.h"
|
||||
#include "connection.h"
|
||||
#include "qresult.h"
|
||||
|
||||
#ifdef HAVE_IODBC
|
||||
#include "iodbc.h"
|
||||
#include "isql.h"
|
||||
#include "isqlext.h"
|
||||
#else
|
||||
#include <windows.h>
|
||||
#include <sql.h>
|
||||
#include <sqlext.h>
|
||||
#endif
|
||||
|
||||
|
||||
extern GLOBAL_VALUES globals;
|
||||
@ -223,7 +234,7 @@ mylog("getCharPrecision: type=%d, col=%d, unknown = %d\n", type,col,handle_unkno
|
||||
if (stmt->manual_result) {
|
||||
flds = result->fields;
|
||||
if (flds)
|
||||
return flds->typlen[col];
|
||||
return flds->adtsize[col];
|
||||
else
|
||||
return maxsize;
|
||||
}
|
||||
|
@ -13,16 +13,28 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include "psqlodbc.h"
|
||||
#include "dlg_specific.h"
|
||||
|
||||
#ifdef HAVE_IODBC
|
||||
#include "iodbc.h"
|
||||
#include "isql.h"
|
||||
#include "isqlext.h"
|
||||
#else
|
||||
#include <winsock.h>
|
||||
#include <windows.h>
|
||||
#include <sql.h>
|
||||
#include <odbcinst.h>
|
||||
#endif
|
||||
|
||||
HINSTANCE NEAR s_hModule; /* Saved module handle. */
|
||||
GLOBAL_VALUES globals;
|
||||
|
||||
#ifndef UNIX /* again find a WINDOWS #ifdef */
|
||||
HINSTANCE NEAR s_hModule; /* Saved module handle. */
|
||||
|
||||
/* This is where the Driver Manager attaches to this Driver */
|
||||
BOOL WINAPI DllMain(HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved)
|
||||
@ -72,6 +84,33 @@ WSADATA wsaData;
|
||||
UNREFERENCED_PARAMETER(lpReserved);
|
||||
}
|
||||
|
||||
#else /* UNIX */
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE (BOOL)1
|
||||
#endif
|
||||
#ifndef FALSE
|
||||
#define FALSE (BOOL)0
|
||||
#endif
|
||||
|
||||
/* These two functions do shared library initialziation on UNIX, well at least
|
||||
* on Linux. I don't know about other systems.
|
||||
*/
|
||||
BOOL
|
||||
_init(void)
|
||||
{
|
||||
getGlobalDefaults();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL
|
||||
_fini(void)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* This function is used to cause the Driver Manager to
|
||||
call functions by number rather than name, which is faster.
|
||||
The ordinal value of this function must be 199 to have the
|
||||
|
@ -11,10 +11,23 @@
|
||||
#ifndef __PSQLODBC_H__
|
||||
#define __PSQLODBC_H__
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#ifdef UNIX
|
||||
#define Int4 long int
|
||||
#define UInt4 unsigned int
|
||||
#define Int2 short
|
||||
#define UInt2 unsigned short
|
||||
typedef float SFLOAT;
|
||||
typedef double SDOUBLE;
|
||||
#else
|
||||
#define Int4 int
|
||||
#define UInt4 unsigned int
|
||||
#define Int2 short
|
||||
#define UInt2 unsigned short
|
||||
#endif
|
||||
|
||||
typedef UInt4 Oid;
|
||||
|
||||
@ -31,6 +44,10 @@ typedef UInt4 Oid;
|
||||
#define BYTELEN 8
|
||||
#define VARHDRSZ sizeof(Int4)
|
||||
|
||||
#define MAX_TABLE_LEN 32
|
||||
#define MAX_COLUMN_LEN 32
|
||||
#define MAX_CURSOR_LEN 32
|
||||
|
||||
/* Registry length limits */
|
||||
#define LARGE_REGISTRY_LEN 4096 /* used for special cases */
|
||||
#define MEDIUM_REGISTRY_LEN 256 /* normal size for user,database,etc. */
|
||||
@ -50,10 +67,14 @@ typedef UInt4 Oid;
|
||||
/* Driver stuff */
|
||||
#define DRIVERNAME "PostgreSQL ODBC"
|
||||
#define DBMS_NAME "PostgreSQL"
|
||||
#define DBMS_VERSION "06.30.0246 PostgreSQL 6.3"
|
||||
#define POSTGRESDRIVERVERSION "06.30.0246"
|
||||
#define DRIVER_FILE_NAME "PSQLODBC.DLL"
|
||||
#define DBMS_VERSION "06.30.0248 PostgreSQL 6.3"
|
||||
#define POSTGRESDRIVERVERSION "06.30.0248"
|
||||
|
||||
#ifndef UNIX
|
||||
#define DRIVER_FILE_NAME "PSQLODBC.DLL"
|
||||
#else
|
||||
#define DRIVER_FILE_NAME "libpsqlodbc.so"
|
||||
#endif
|
||||
|
||||
#define PG62 "6.2" /* "Protocol" key setting to force Postgres 6.2 */
|
||||
|
||||
@ -70,6 +91,7 @@ typedef struct EnvironmentClass_ EnvironmentClass;
|
||||
typedef struct TupleNode_ TupleNode;
|
||||
typedef struct TupleField_ TupleField;
|
||||
|
||||
typedef struct col_info COL_INFO;
|
||||
typedef struct lo_arg LO_ARG;
|
||||
|
||||
typedef struct GlobalValues_
|
||||
@ -89,6 +111,7 @@ typedef struct GlobalValues_
|
||||
char unknowns_as_longvarchar;
|
||||
char bools_as_char;
|
||||
char lie;
|
||||
char parse;
|
||||
char extra_systable_prefixes[MEDIUM_REGISTRY_LEN];
|
||||
char conn_settings[LARGE_REGISTRY_LEN];
|
||||
} GLOBAL_VALUES;
|
||||
|
@ -74,7 +74,8 @@ BEGIN
|
||||
EDITTEXT IDC_PASSWORD,175,55,72,12,ES_PASSWORD | ES_AUTOHSCROLL
|
||||
DEFPUSHBUTTON "OK",IDOK,25,90,40,14,WS_GROUP
|
||||
PUSHBUTTON "Cancel",IDCANCEL,80,90,40,14
|
||||
GROUPBOX "Options (Advanced):",IDC_STATIC,140,74,140,35,BS_CENTER
|
||||
GROUPBOX "Options (Advanced):",IDC_OPTIONS,140,74,140,35,
|
||||
BS_CENTER
|
||||
PUSHBUTTON "Driver",IDC_DRIVER,160,90,50,14
|
||||
PUSHBUTTON "DataSource",IDC_DATASOURCE,220,90,50,14
|
||||
CTEXT "Please supply any missing information needed to connect.",
|
||||
@ -96,6 +97,8 @@ BEGIN
|
||||
BS_AUTOCHECKBOX | WS_TABSTOP,140,25,80,10
|
||||
CONTROL "&Use Declare/Fetch",DRV_USEDECLAREFETCH,"Button",
|
||||
BS_AUTOCHECKBOX | WS_TABSTOP,15,40,80,10
|
||||
CONTROL "P&arse Statements",DRV_PARSE,"Button",BS_AUTOCHECKBOX |
|
||||
WS_TABSTOP,140,40,80,10
|
||||
GROUPBOX "Unknown Sizes",IDC_STATIC,10,55,175,25
|
||||
CONTROL "Maximum",DRV_UNKNOWN_MAX,"Button",BS_AUTORADIOBUTTON |
|
||||
WS_GROUP | WS_TABSTOP,15,65,45,10
|
||||
@ -200,8 +203,8 @@ END
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 6,30,2,46
|
||||
PRODUCTVERSION 6,30,2,46
|
||||
FILEVERSION 6,30,2,48
|
||||
PRODUCTVERSION 6,30,2,48
|
||||
FILEFLAGSMASK 0x3L
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
@ -219,12 +222,12 @@ BEGIN
|
||||
VALUE "Comments", "PostgreSQL ODBC driver for Windows 95\0"
|
||||
VALUE "CompanyName", "Insight Distribution Systems\0"
|
||||
VALUE "FileDescription", "PostgreSQL Driver\0"
|
||||
VALUE "FileVersion", " 6.30.0246\0"
|
||||
VALUE "FileVersion", " 6.30.0248\0"
|
||||
VALUE "InternalName", "psqlodbc\0"
|
||||
VALUE "LegalTrademarks", "ODBC(TM) is a trademark of Microsoft Corporation. Microsoft® is a registered trademark of Microsoft Corporation. Windows(TM) is a trademark of Microsoft Corporation.\0"
|
||||
VALUE "OriginalFilename", "psqlodbc.dll\0"
|
||||
VALUE "ProductName", "Microsoft Open Database Connectivity\0"
|
||||
VALUE "ProductVersion", " 6.30.0246\0"
|
||||
VALUE "ProductVersion", " 6.30.0248\0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
@ -21,6 +21,14 @@
|
||||
#include "qresult.h"
|
||||
#include "misc.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE (BOOL)1
|
||||
#endif
|
||||
#ifndef FALSE
|
||||
#define FALSE (BOOL)0
|
||||
#endif
|
||||
|
||||
extern GLOBAL_VALUES globals;
|
||||
|
||||
@ -232,6 +240,7 @@ QR_fetch_tuples(QResultClass *self, ConnectionClass *conn, char *cursor)
|
||||
QR_set_message(self, "Error reading field information");
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -46,6 +46,8 @@
|
||||
#define DS_SHOWSYSTEMTABLES 1051
|
||||
#define DRV_EXTRASYSTABLEPREFIXES 1051
|
||||
#define DS_ROWVERSIONING 1052
|
||||
#define DRV_PARSE 1052
|
||||
#define IDC_OPTIONS 1054
|
||||
|
||||
// Next default values for new objects
|
||||
//
|
||||
@ -53,7 +55,7 @@
|
||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
#define _APS_NEXT_RESOURCE_VALUE 104
|
||||
#define _APS_NEXT_COMMAND_VALUE 40001
|
||||
#define _APS_NEXT_CONTROL_VALUE 1054
|
||||
#define _APS_NEXT_CONTROL_VALUE 1055
|
||||
#define _APS_NEXT_SYMED_VALUE 101
|
||||
#endif
|
||||
#endif
|
||||
|
@ -15,6 +15,10 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
#include "psqlodbc.h"
|
||||
#include "dlg_specific.h"
|
||||
@ -27,11 +31,34 @@
|
||||
#include "pgtypes.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef HAVE_IODBC
|
||||
#include "iodbc.h"
|
||||
#include "isqlext.h"
|
||||
#else
|
||||
#include <windows.h>
|
||||
#include <sqlext.h>
|
||||
#endif
|
||||
|
||||
extern GLOBAL_VALUES globals;
|
||||
|
||||
RETCODE SQL_API SQLFetch(HSTMT hstmt)
|
||||
{
|
||||
return _SQLFetch(hstmt);
|
||||
}
|
||||
|
||||
RETCODE SQL_API SQLGetData(
|
||||
HSTMT hstmt,
|
||||
UWORD icol,
|
||||
SWORD fCType,
|
||||
PTR rgbValue,
|
||||
SDWORD cbValueMax,
|
||||
SDWORD FAR *pcbValue)
|
||||
{
|
||||
|
||||
return _SQLGetData(hstmt, icol, fCType, rgbValue, cbValueMax, pcbValue);
|
||||
}
|
||||
|
||||
RETCODE SQL_API SQLRowCount(
|
||||
HSTMT hstmt,
|
||||
SDWORD FAR *pcrow)
|
||||
@ -93,6 +120,7 @@ RETCODE SQL_API SQLNumResultCols(
|
||||
char *func="SQLNumResultCols";
|
||||
StatementClass *stmt = (StatementClass *) hstmt;
|
||||
QResultClass *result;
|
||||
char parse_ok;
|
||||
|
||||
if ( ! stmt) {
|
||||
SC_log_error(func, "", NULL);
|
||||
@ -101,14 +129,24 @@ QResultClass *result;
|
||||
|
||||
SC_clear_error(stmt);
|
||||
|
||||
/* CC: Now check for the "prepared, but not executed" situation, that enables us to
|
||||
deal with "SQLPrepare -- SQLDescribeCol -- ... -- SQLExecute" situations.
|
||||
(AutoCAD 13 ASE/ASI just _loves_ that ;-) )
|
||||
*/
|
||||
mylog("**** SQLNumResultCols: calling SC_pre_execute\n");
|
||||
parse_ok = FALSE;
|
||||
if (globals.parse && stmt->statement_type == STMT_TYPE_SELECT) {
|
||||
|
||||
if (stmt->parse_status == STMT_PARSE_NONE) {
|
||||
mylog("SQLNumResultCols: calling parse_statement on stmt=%u\n", stmt);
|
||||
parse_statement(stmt);
|
||||
}
|
||||
|
||||
if (stmt->parse_status != STMT_PARSE_FATAL) {
|
||||
parse_ok = TRUE;
|
||||
*pccol = stmt->nfld;
|
||||
mylog("PARSE: SQLNumResultCols: *pccol = %d\n", *pccol);
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! parse_ok) {
|
||||
|
||||
SC_pre_execute(stmt);
|
||||
|
||||
result = SC_get_Result(stmt);
|
||||
|
||||
mylog("SQLNumResultCols: result = %u, status = %d, numcols = %d\n", result, stmt->status, result != NULL ? QR_NumResultCols(result) : -1);
|
||||
@ -121,6 +159,7 @@ QResultClass *result;
|
||||
}
|
||||
|
||||
*pccol = QR_NumResultCols(result);
|
||||
}
|
||||
|
||||
return SQL_SUCCESS;
|
||||
}
|
||||
@ -128,6 +167,8 @@ QResultClass *result;
|
||||
|
||||
// - - - - - - - - -
|
||||
|
||||
|
||||
|
||||
// Return information about the database column the user wants
|
||||
// information about.
|
||||
RETCODE SQL_API SQLDescribeCol(
|
||||
@ -145,10 +186,11 @@ char *func="SQLDescribeCol";
|
||||
/* gets all the information about a specific column */
|
||||
StatementClass *stmt = (StatementClass *) hstmt;
|
||||
QResultClass *result;
|
||||
char *name;
|
||||
char *col_name;
|
||||
Int4 fieldtype;
|
||||
int p;
|
||||
int precision;
|
||||
ConnInfo *ci;
|
||||
char parse_ok;
|
||||
|
||||
if ( ! stmt) {
|
||||
SC_log_error(func, "", NULL);
|
||||
@ -159,24 +201,6 @@ ConnInfo *ci;
|
||||
|
||||
SC_clear_error(stmt);
|
||||
|
||||
/* CC: Now check for the "prepared, but not executed" situation, that enables us to
|
||||
deal with "SQLPrepare -- SQLDescribeCol -- ... -- SQLExecute" situations.
|
||||
(AutoCAD 13 ASE/ASI just _loves_ that ;-) )
|
||||
*/
|
||||
|
||||
SC_pre_execute(stmt);
|
||||
|
||||
|
||||
result = SC_get_Result(stmt);
|
||||
mylog("**** SQLDescribeCol: result = %u, stmt->status = %d, !finished=%d, !premature=%d\n", result, stmt->status, stmt->status != STMT_FINISHED, stmt->status != STMT_PREMATURE);
|
||||
if ( (NULL == result) || ((stmt->status != STMT_FINISHED) && (stmt->status != STMT_PREMATURE))) {
|
||||
/* no query has been executed on this statement */
|
||||
stmt->errornumber = STMT_SEQUENCE_ERROR;
|
||||
stmt->errormsg = "No query has been assigned to this statement.";
|
||||
SC_log_error(func, "", stmt);
|
||||
return SQL_ERROR;
|
||||
}
|
||||
|
||||
if(icol < 1) {
|
||||
// we do not support bookmarks
|
||||
stmt->errormsg = "Bookmarks are not currently supported.";
|
||||
@ -187,60 +211,106 @@ ConnInfo *ci;
|
||||
|
||||
icol--; /* use zero based column numbers */
|
||||
|
||||
if (cbColNameMax >= 1) {
|
||||
name = QR_get_fieldname(result, icol);
|
||||
mylog("describeCol: col %d fieldname = '%s'\n", icol, name);
|
||||
/* our indices start from 0 whereas ODBC defines indices starting from 1 */
|
||||
if (NULL != pcbColName) {
|
||||
// we want to get the total number of bytes in the column name
|
||||
if (NULL == name)
|
||||
*pcbColName = 0;
|
||||
else
|
||||
*pcbColName = strlen(name);
|
||||
|
||||
parse_ok = FALSE;
|
||||
if (globals.parse && stmt->statement_type == STMT_TYPE_SELECT) {
|
||||
|
||||
if (stmt->parse_status == STMT_PARSE_NONE) {
|
||||
mylog("SQLDescribeCol: calling parse_statement on stmt=%u\n", stmt);
|
||||
parse_statement(stmt);
|
||||
}
|
||||
if (NULL != szColName) {
|
||||
// get the column name into the buffer if there is one
|
||||
if (NULL == name)
|
||||
szColName[0] = '\0';
|
||||
else
|
||||
strncpy_null(szColName, name, cbColNameMax);
|
||||
|
||||
|
||||
mylog("PARSE: DescribeCol: icol=%d, stmt=%u, stmt->nfld=%d, stmt->fi=%u\n", icol, stmt, stmt->nfld, stmt->fi);
|
||||
|
||||
if (stmt->parse_status != STMT_PARSE_FATAL && stmt->fi && stmt->fi[icol]) {
|
||||
|
||||
if (icol >= stmt->nfld) {
|
||||
stmt->errornumber = STMT_INVALID_COLUMN_NUMBER_ERROR;
|
||||
stmt->errormsg = "Invalid column number in DescribeCol.";
|
||||
SC_log_error(func, "", stmt);
|
||||
return SQL_ERROR;
|
||||
}
|
||||
mylog("DescribeCol: getting info for icol=%d\n", icol);
|
||||
|
||||
fieldtype = stmt->fi[icol]->type;
|
||||
col_name = stmt->fi[icol]->name;
|
||||
precision = stmt->fi[icol]->precision;
|
||||
|
||||
mylog("PARSE: fieldtype=%d, col_name='%s', precision=%d\n", fieldtype, col_name, precision);
|
||||
if (fieldtype > 0)
|
||||
parse_ok = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* If couldn't parse it OR the field being described was not parsed (i.e., because
|
||||
it was a function or expression, etc, then do it the old fashioned way.
|
||||
*/
|
||||
if ( ! parse_ok) {
|
||||
SC_pre_execute(stmt);
|
||||
|
||||
result = SC_get_Result(stmt);
|
||||
|
||||
mylog("**** SQLDescribeCol: result = %u, stmt->status = %d, !finished=%d, !premature=%d\n", result, stmt->status, stmt->status != STMT_FINISHED, stmt->status != STMT_PREMATURE);
|
||||
if ( (NULL == result) || ((stmt->status != STMT_FINISHED) && (stmt->status != STMT_PREMATURE))) {
|
||||
/* no query has been executed on this statement */
|
||||
stmt->errornumber = STMT_SEQUENCE_ERROR;
|
||||
stmt->errormsg = "No query has been assigned to this statement.";
|
||||
SC_log_error(func, "", stmt);
|
||||
return SQL_ERROR;
|
||||
}
|
||||
|
||||
if (icol >= QR_NumResultCols(result)) {
|
||||
stmt->errornumber = STMT_INVALID_COLUMN_NUMBER_ERROR;
|
||||
stmt->errormsg = "Invalid column number in DescribeCol.";
|
||||
SC_log_error(func, "", stmt);
|
||||
return SQL_ERROR;
|
||||
}
|
||||
|
||||
col_name = QR_get_fieldname(result, icol);
|
||||
fieldtype = QR_get_field_type(result, icol);
|
||||
mylog("describeCol: col %d fieldtype = %d\n", icol, fieldtype);
|
||||
|
||||
if (NULL != pfSqlType) {
|
||||
precision = pgtype_precision(stmt, fieldtype, icol, globals.unknown_sizes); // atoi(ci->unknown_sizes)
|
||||
}
|
||||
|
||||
mylog("describeCol: col %d fieldname = '%s'\n", icol, col_name);
|
||||
mylog("describeCol: col %d fieldtype = %d\n", icol, fieldtype);
|
||||
mylog("describeCol: col %d precision = %d\n", icol, precision);
|
||||
|
||||
if (cbColNameMax >= 1) {
|
||||
if (pcbColName) {
|
||||
if (col_name)
|
||||
*pcbColName = strlen(col_name);
|
||||
else
|
||||
*pcbColName = 0;
|
||||
}
|
||||
if (szColName) {
|
||||
if (col_name)
|
||||
strncpy_null(szColName, col_name, cbColNameMax);
|
||||
else
|
||||
szColName[0] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (pfSqlType) {
|
||||
*pfSqlType = pgtype_to_sqltype(stmt, fieldtype);
|
||||
|
||||
mylog("describeCol: col %d *pfSqlType = %d\n", icol, *pfSqlType);
|
||||
}
|
||||
|
||||
if (NULL != pcbColDef) {
|
||||
if (pcbColDef) {
|
||||
|
||||
/* If type is BPCHAR, then precision is length of column because all
|
||||
columns in the result set will be blank padded to the column length.
|
||||
if ( precision < 0)
|
||||
precision = 0; // "I dont know"
|
||||
|
||||
If type is VARCHAR or TEXT, then precision can not be accurately
|
||||
determined. Possibilities are:
|
||||
1. return 0 (I dont know -- seems to work ok with Borland)
|
||||
2. return MAXIMUM PRECISION for that datatype (Borland bad!)
|
||||
3. return longest column thus far (that would be the longest
|
||||
strlen of any row in the tuple cache, which may not be a
|
||||
good representation if the result set is more than one
|
||||
tuple cache long.)
|
||||
*/
|
||||
|
||||
p = pgtype_precision(stmt, fieldtype, icol, globals.unknown_sizes); // atoi(ci->unknown_sizes)
|
||||
if ( p < 0)
|
||||
p = 0; // "I dont know"
|
||||
|
||||
*pcbColDef = p;
|
||||
*pcbColDef = precision;
|
||||
|
||||
mylog("describeCol: col %d *pcbColDef = %d\n", icol, *pcbColDef);
|
||||
}
|
||||
|
||||
if (NULL != pibScale) {
|
||||
if (pibScale) {
|
||||
Int2 scale;
|
||||
scale = pgtype_scale(stmt, fieldtype);
|
||||
if(scale == -1) { scale = 0; }
|
||||
@ -249,8 +319,12 @@ ConnInfo *ci;
|
||||
mylog("describeCol: col %d *pibScale = %d\n", icol, *pibScale);
|
||||
}
|
||||
|
||||
if (NULL != pfNullable) {
|
||||
if (pfNullable) {
|
||||
if (parse_ok)
|
||||
*pfNullable = stmt->fi[icol]->nullable;
|
||||
else
|
||||
*pfNullable = pgtype_nullable(stmt, fieldtype);
|
||||
|
||||
mylog("describeCol: col %d *pfNullable = %d\n", icol, *pfNullable);
|
||||
}
|
||||
|
||||
@ -274,6 +348,9 @@ char *value;
|
||||
Int4 field_type;
|
||||
ConnInfo *ci;
|
||||
int unknown_sizes;
|
||||
int cols;
|
||||
char parse_ok;
|
||||
|
||||
|
||||
if( ! stmt) {
|
||||
SC_log_error(func, "", NULL);
|
||||
@ -282,10 +359,46 @@ int unknown_sizes;
|
||||
|
||||
ci = &(stmt->hdbc->connInfo);
|
||||
|
||||
/* CC: Now check for the "prepared, but not executed" situation, that enables us to
|
||||
deal with "SQLPrepare -- SQLDescribeCol -- ... -- SQLExecute" situations.
|
||||
(AutoCAD 13 ASE/ASI just _loves_ that ;-) )
|
||||
*/
|
||||
if(icol < 1) {
|
||||
// we do not support bookmarks
|
||||
stmt->errormsg = "Bookmarks are not currently supported.";
|
||||
stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR;
|
||||
SC_log_error(func, "", stmt);
|
||||
return SQL_ERROR;
|
||||
}
|
||||
|
||||
icol--;
|
||||
|
||||
unknown_sizes = globals.unknown_sizes; // atoi(ci->unknown_sizes);
|
||||
if (unknown_sizes == UNKNOWNS_AS_DONTKNOW) // not appropriate for SQLColAttributes()
|
||||
unknown_sizes = UNKNOWNS_AS_MAX;
|
||||
|
||||
parse_ok = FALSE;
|
||||
if (globals.parse && stmt->statement_type == STMT_TYPE_SELECT) {
|
||||
|
||||
if (stmt->parse_status == STMT_PARSE_NONE) {
|
||||
mylog("SQLColAttributes: calling parse_statement\n");
|
||||
parse_statement(stmt);
|
||||
}
|
||||
|
||||
cols = stmt->nfld;
|
||||
|
||||
if (stmt->parse_status != STMT_PARSE_FATAL && stmt->fi && stmt->fi[icol]) {
|
||||
|
||||
if (icol >= cols) {
|
||||
stmt->errornumber = STMT_INVALID_COLUMN_NUMBER_ERROR;
|
||||
stmt->errormsg = "Invalid column number in DescribeCol.";
|
||||
SC_log_error(func, "", stmt);
|
||||
return SQL_ERROR;
|
||||
}
|
||||
|
||||
field_type = stmt->fi[icol]->type;
|
||||
if (field_type > 0)
|
||||
parse_ok = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! parse_ok) {
|
||||
SC_pre_execute(stmt);
|
||||
|
||||
mylog("**** SQLColAtt: result = %u, status = %d, numcols = %d\n", stmt->result, stmt->status, stmt->result != NULL ? QR_NumResultCols(stmt->result) : -1);
|
||||
@ -297,26 +410,22 @@ int unknown_sizes;
|
||||
return SQL_ERROR;
|
||||
}
|
||||
|
||||
if(icol < 1) {
|
||||
// we do not support bookmarks
|
||||
stmt->errormsg = "Bookmarks are not currently supported.";
|
||||
stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR;
|
||||
cols = QR_NumResultCols(stmt->result);
|
||||
if (icol >= cols) {
|
||||
stmt->errornumber = STMT_INVALID_COLUMN_NUMBER_ERROR;
|
||||
stmt->errormsg = "Invalid column number in DescribeCol.";
|
||||
SC_log_error(func, "", stmt);
|
||||
return SQL_ERROR;
|
||||
}
|
||||
|
||||
icol -= 1;
|
||||
field_type = QR_get_field_type(stmt->result, icol);
|
||||
}
|
||||
|
||||
mylog("colAttr: col %d field_type = %d\n", icol, field_type);
|
||||
|
||||
unknown_sizes = globals.unknown_sizes; // atoi(ci->unknown_sizes);
|
||||
if (unknown_sizes == UNKNOWNS_AS_DONTKNOW) // not appropriate for SQLColAttributes()
|
||||
unknown_sizes = UNKNOWNS_AS_MAX;
|
||||
|
||||
switch(fDescType) {
|
||||
case SQL_COLUMN_AUTO_INCREMENT:
|
||||
if (NULL != pfDesc) {
|
||||
if (pfDesc) {
|
||||
*pfDesc = pgtype_auto_increment(stmt, field_type);
|
||||
if (*pfDesc == -1) /* non-numeric becomes FALSE (ODBC Doc) */
|
||||
*pfDesc = FALSE;
|
||||
@ -325,17 +434,20 @@ int unknown_sizes;
|
||||
break;
|
||||
|
||||
case SQL_COLUMN_CASE_SENSITIVE:
|
||||
if (NULL != pfDesc)
|
||||
if (pfDesc)
|
||||
*pfDesc = pgtype_case_sensitive(stmt, field_type);
|
||||
break;
|
||||
|
||||
case SQL_COLUMN_COUNT:
|
||||
if (NULL != pfDesc)
|
||||
*pfDesc = QR_NumResultCols(stmt->result);
|
||||
if (pfDesc)
|
||||
*pfDesc = cols;
|
||||
break;
|
||||
|
||||
case SQL_COLUMN_DISPLAY_SIZE:
|
||||
if (NULL != pfDesc) {
|
||||
if (pfDesc) {
|
||||
if (parse_ok)
|
||||
*pfDesc = stmt->fi[icol]->display_size;
|
||||
else
|
||||
*pfDesc = pgtype_display_size(stmt, field_type, icol, unknown_sizes);
|
||||
}
|
||||
|
||||
@ -344,39 +456,66 @@ int unknown_sizes;
|
||||
break;
|
||||
|
||||
case SQL_COLUMN_LABEL:
|
||||
if (parse_ok && stmt->fi[icol]->alias[0] != '\0') {
|
||||
strncpy_null((char *)rgbDesc, stmt->fi[icol]->alias, cbDescMax);
|
||||
if (pcbDesc)
|
||||
*pcbDesc = strlen(stmt->fi[icol]->alias);
|
||||
|
||||
break;
|
||||
|
||||
mylog("SQLColAttr: COLUMN_LABEL = '%s'\n", rgbDesc);
|
||||
} // otherwise same as column name
|
||||
|
||||
case SQL_COLUMN_NAME:
|
||||
|
||||
if (parse_ok)
|
||||
value = stmt->fi[icol]->name;
|
||||
else
|
||||
value = QR_get_fieldname(stmt->result, icol);
|
||||
|
||||
strncpy_null((char *)rgbDesc, value, cbDescMax);
|
||||
|
||||
if (NULL != pcbDesc)
|
||||
if (pcbDesc)
|
||||
*pcbDesc = strlen(value);
|
||||
|
||||
mylog("SQLColAttr: COLUMN_NAME = '%s'\n", rgbDesc);
|
||||
break;
|
||||
|
||||
case SQL_COLUMN_LENGTH:
|
||||
if (NULL != pfDesc) {
|
||||
if (pfDesc) {
|
||||
if (parse_ok)
|
||||
*pfDesc = stmt->fi[icol]->length;
|
||||
else
|
||||
*pfDesc = pgtype_length(stmt, field_type, icol, unknown_sizes);
|
||||
}
|
||||
mylog("SQLColAttributes: col %d, length = %d\n", icol, *pfDesc);
|
||||
break;
|
||||
|
||||
case SQL_COLUMN_MONEY:
|
||||
if (NULL != pfDesc)
|
||||
if (pfDesc)
|
||||
*pfDesc = pgtype_money(stmt, field_type);
|
||||
break;
|
||||
|
||||
case SQL_COLUMN_NULLABLE:
|
||||
if (NULL != pfDesc)
|
||||
if (pfDesc) {
|
||||
if (parse_ok)
|
||||
*pfDesc = stmt->fi[icol]->nullable;
|
||||
else
|
||||
*pfDesc = pgtype_nullable(stmt, field_type);
|
||||
}
|
||||
break;
|
||||
|
||||
case SQL_COLUMN_OWNER_NAME:
|
||||
strncpy_null((char *)rgbDesc, "", cbDescMax);
|
||||
if (NULL != pcbDesc)
|
||||
if (pcbDesc)
|
||||
*pcbDesc = 0;
|
||||
break;
|
||||
|
||||
case SQL_COLUMN_PRECISION:
|
||||
if (NULL != pfDesc) {
|
||||
if (pfDesc) {
|
||||
if (parse_ok)
|
||||
*pfDesc = stmt->fi[icol]->precision;
|
||||
else
|
||||
*pfDesc = pgtype_precision(stmt, field_type, icol, unknown_sizes);
|
||||
}
|
||||
mylog("SQLColAttributes: col %d, precision = %d\n", icol, *pfDesc);
|
||||
@ -384,28 +523,37 @@ int unknown_sizes;
|
||||
|
||||
case SQL_COLUMN_QUALIFIER_NAME:
|
||||
strncpy_null((char *)rgbDesc, "", cbDescMax);
|
||||
if (NULL != pcbDesc)
|
||||
if (pcbDesc)
|
||||
*pcbDesc = 0;
|
||||
break;
|
||||
|
||||
case SQL_COLUMN_SCALE:
|
||||
if (NULL != pfDesc)
|
||||
if (pfDesc)
|
||||
*pfDesc = pgtype_scale(stmt, field_type);
|
||||
break;
|
||||
|
||||
case SQL_COLUMN_SEARCHABLE:
|
||||
if (NULL != pfDesc)
|
||||
if (pfDesc)
|
||||
*pfDesc = pgtype_searchable(stmt, field_type);
|
||||
break;
|
||||
|
||||
case SQL_COLUMN_TABLE_NAME:
|
||||
if (parse_ok && stmt->fi[icol]->ti) {
|
||||
strncpy_null((char *)rgbDesc, stmt->fi[icol]->ti->name, cbDescMax);
|
||||
if (pcbDesc)
|
||||
*pcbDesc = strlen(stmt->fi[icol]->ti->name);
|
||||
}
|
||||
else {
|
||||
strncpy_null((char *)rgbDesc, "", cbDescMax);
|
||||
if (NULL != pcbDesc)
|
||||
if (pcbDesc)
|
||||
*pcbDesc = 0;
|
||||
}
|
||||
|
||||
mylog("SQLColAttr: TABLE_NAME = '%s'\n", rgbDesc);
|
||||
break;
|
||||
|
||||
case SQL_COLUMN_TYPE:
|
||||
if (NULL != pfDesc) {
|
||||
if (pfDesc) {
|
||||
*pfDesc = pgtype_to_sqltype(stmt, field_type);
|
||||
}
|
||||
break;
|
||||
@ -413,12 +561,12 @@ int unknown_sizes;
|
||||
case SQL_COLUMN_TYPE_NAME:
|
||||
value = pgtype_to_name(stmt, field_type);
|
||||
strncpy_null((char *)rgbDesc, value, cbDescMax);
|
||||
if (NULL != pcbDesc)
|
||||
if (pcbDesc)
|
||||
*pcbDesc = strlen(value);
|
||||
break;
|
||||
|
||||
case SQL_COLUMN_UNSIGNED:
|
||||
if (NULL != pfDesc) {
|
||||
if (pfDesc) {
|
||||
*pfDesc = pgtype_unsigned(stmt, field_type);
|
||||
if(*pfDesc == -1) /* non-numeric becomes TRUE (ODBC Doc) */
|
||||
*pfDesc = TRUE;
|
||||
@ -426,17 +574,16 @@ int unknown_sizes;
|
||||
break;
|
||||
|
||||
case SQL_COLUMN_UPDATABLE:
|
||||
// everything should be updatable, I guess, unless access permissions
|
||||
// prevent it--are we supposed to check for that here? seems kind
|
||||
// of complicated. hmm...
|
||||
if (NULL != pfDesc) {
|
||||
if (pfDesc) {
|
||||
/* Neither Access or Borland care about this.
|
||||
|
||||
if (field_type == PG_TYPE_OID)
|
||||
*pfDesc = SQL_ATTR_READONLY;
|
||||
else
|
||||
*/
|
||||
|
||||
*pfDesc = SQL_ATTR_WRITE;
|
||||
mylog("SQLColAttr: UPDATEABLE = %d\n", *pfDesc);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -446,7 +593,7 @@ int unknown_sizes;
|
||||
|
||||
// Returns result data for a single column in the current row.
|
||||
|
||||
RETCODE SQL_API SQLGetData(
|
||||
RETCODE SQL_API _SQLGetData(
|
||||
HSTMT hstmt,
|
||||
UWORD icol,
|
||||
SWORD fCType,
|
||||
@ -590,7 +737,7 @@ mylog("SQLGetData: enter, stmt=%u\n", stmt);
|
||||
// Returns data for bound columns in the current row ("hstmt->iCursor"),
|
||||
// advances the cursor.
|
||||
|
||||
RETCODE SQL_API SQLFetch(
|
||||
RETCODE SQL_API _SQLFetch(
|
||||
HSTMT hstmt)
|
||||
{
|
||||
char *func = "SQLFetch";
|
||||
@ -863,8 +1010,11 @@ RETCODE SQL_API SQLSetPos(
|
||||
UWORD fLock)
|
||||
{
|
||||
char *func = "SQLSetPos";
|
||||
char buf[128];
|
||||
|
||||
SC_log_error(func, "Function not implemented", (StatementClass *) hstmt);
|
||||
sprintf(buf, "SQLSetPos not implemented: irow=%d, fOption=%d, fLock=%d\n", irow, fOption, fLock);
|
||||
|
||||
SC_log_error(func, buf, (StatementClass *) hstmt);
|
||||
return SQL_ERROR;
|
||||
}
|
||||
|
||||
|
@ -12,10 +12,33 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include "socket.h"
|
||||
|
||||
#ifdef UNIX
|
||||
#include <stdlib.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <string.h> /* for memset */
|
||||
#endif
|
||||
|
||||
extern GLOBAL_VALUES globals;
|
||||
|
||||
#ifndef BOOL
|
||||
#define BOOL int
|
||||
#endif
|
||||
#ifndef TRUE
|
||||
#define TRUE (BOOL)1
|
||||
#endif
|
||||
#ifndef FALSE
|
||||
#define FALSE (BOOL)0
|
||||
#endif
|
||||
|
||||
|
||||
void
|
||||
SOCK_clear_error(SocketClass *self)
|
||||
{
|
||||
@ -31,7 +54,7 @@ SocketClass *rv;
|
||||
rv = (SocketClass *) malloc(sizeof(SocketClass));
|
||||
|
||||
if (rv != NULL) {
|
||||
rv->socket = (SOCKET) -1;
|
||||
rv->socket = (SOCKETFD) -1;
|
||||
rv->buffer_filled_in = 0;
|
||||
rv->buffer_filled_out = 0;
|
||||
rv->buffer_read_in = 0;
|
||||
@ -119,7 +142,7 @@ unsigned long iaddr;
|
||||
self->errornumber = SOCKET_COULD_NOT_CONNECT;
|
||||
self->errormsg = "Could not connect to remote socket.";
|
||||
closesocket(self->socket);
|
||||
self->socket = (SOCKET) -1;
|
||||
self->socket = (SOCKETFD) -1;
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
|
@ -10,7 +10,23 @@
|
||||
#ifndef __SOCKET_H__
|
||||
#define __SOCKET_H__
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#ifdef UNIX
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
#define closesocket(xxx) close(xxx)
|
||||
#define SOCKETFD int
|
||||
#else
|
||||
#include <winsock.h>
|
||||
#define SOCKETFD SOCKET
|
||||
#endif
|
||||
|
||||
#include "psqlodbc.h"
|
||||
|
||||
#define SOCKET_ALREADY_CONNECTED 1
|
||||
@ -33,7 +49,7 @@ struct SocketClass_ {
|
||||
unsigned char *buffer_in;
|
||||
unsigned char *buffer_out;
|
||||
|
||||
SOCKET socket;
|
||||
SOCKETFD socket;
|
||||
|
||||
char *errormsg;
|
||||
int errornumber;
|
||||
|
@ -12,6 +12,10 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include "statement.h"
|
||||
#include "bind.h"
|
||||
#include "connection.h"
|
||||
@ -19,12 +23,25 @@
|
||||
#include "convert.h"
|
||||
#include "environ.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef HAVE_IODBC
|
||||
#include "iodbc.h"
|
||||
#include "isql.h"
|
||||
#else
|
||||
#include <windows.h>
|
||||
#include <sql.h>
|
||||
#endif
|
||||
|
||||
extern GLOBAL_VALUES globals;
|
||||
|
||||
#ifdef UNIX
|
||||
#if !HAVE_STRICMP
|
||||
#define stricmp(s1,s2) strcasecmp(s1,s2)
|
||||
#define strnicmp(s1,s2,n) strncasecmp(s1,s2,n)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Map sql commands to statement types */
|
||||
static struct {
|
||||
int type;
|
||||
@ -45,6 +62,19 @@ static struct {
|
||||
|
||||
RETCODE SQL_API SQLAllocStmt(HDBC hdbc,
|
||||
HSTMT FAR *phstmt)
|
||||
{
|
||||
return _SQLAllocStmt(hdbc, phstmt);
|
||||
}
|
||||
|
||||
RETCODE SQL_API SQLFreeStmt(HSTMT hstmt,
|
||||
UWORD fOption)
|
||||
{
|
||||
return _SQLFreeStmt(hstmt, fOption);
|
||||
}
|
||||
|
||||
|
||||
RETCODE SQL_API _SQLAllocStmt(HDBC hdbc,
|
||||
HSTMT FAR *phstmt)
|
||||
{
|
||||
char *func="SQLAllocStmt";
|
||||
ConnectionClass *conn = (ConnectionClass *) hdbc;
|
||||
@ -82,7 +112,7 @@ StatementClass *stmt;
|
||||
}
|
||||
|
||||
|
||||
RETCODE SQL_API SQLFreeStmt(HSTMT hstmt,
|
||||
RETCODE SQL_API _SQLFreeStmt(HSTMT hstmt,
|
||||
UWORD fOption)
|
||||
{
|
||||
char *func="SQLFreeStmt";
|
||||
@ -145,6 +175,7 @@ StatementClass *stmt = (StatementClass *) hstmt;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* StatementClass implementation
|
||||
*/
|
||||
@ -185,6 +216,12 @@ StatementClass *rv;
|
||||
rv->lobj_fd = -1;
|
||||
rv->internal = FALSE;
|
||||
rv->cursor_name[0] = '\0';
|
||||
|
||||
rv->ti = NULL;
|
||||
rv->fi = NULL;
|
||||
rv->ntab = 0;
|
||||
rv->nfld = 0;
|
||||
rv->parse_status = STMT_PARSE_NONE;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
@ -218,6 +255,27 @@ SC_Destructor(StatementClass *self)
|
||||
if (self->bindings)
|
||||
free(self->bindings);
|
||||
|
||||
|
||||
/* Free the parsed table information */
|
||||
if (self->ti) {
|
||||
int i;
|
||||
for (i = 0; i < self->ntab; i++) {
|
||||
free(self->ti[i]);
|
||||
}
|
||||
|
||||
free(self->ti);
|
||||
}
|
||||
|
||||
/* Free the parsed field information */
|
||||
if (self->fi) {
|
||||
int i;
|
||||
for (i = 0; i < self->nfld; i++) {
|
||||
free(self->fi[i]);
|
||||
}
|
||||
free(self->fi);
|
||||
}
|
||||
|
||||
|
||||
free(self);
|
||||
|
||||
mylog("SC_Destructor: EXIT\n");
|
||||
@ -266,7 +324,6 @@ int i;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int
|
||||
statement_type(char *statement)
|
||||
{
|
||||
@ -279,6 +336,7 @@ int i;
|
||||
return STMT_TYPE_OTHER;
|
||||
}
|
||||
|
||||
|
||||
/* Called from SQLPrepare if STMT_PREMATURE, or
|
||||
from SQLExecute if STMT_FINISHED, or
|
||||
from SQLFreeStmt(SQL_CLOSE)
|
||||
@ -328,6 +386,29 @@ ConnectionClass *conn;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Free the parsed table information */
|
||||
if (self->ti) {
|
||||
int i;
|
||||
for (i = 0; i < self->ntab; i++) {
|
||||
free(self->ti[i]);
|
||||
}
|
||||
|
||||
free(self->ti);
|
||||
self->ti = NULL;
|
||||
self->ntab = 0;
|
||||
}
|
||||
|
||||
/* Free the parsed field information */
|
||||
if (self->fi) {
|
||||
int i;
|
||||
for (i = 0; i < self->nfld; i++) {
|
||||
free(self->fi[i]);
|
||||
}
|
||||
free(self->fi);
|
||||
self->fi = NULL;
|
||||
self->nfld = 0;
|
||||
}
|
||||
self->parse_status = STMT_PARSE_NONE;
|
||||
|
||||
/* Free any cursors */
|
||||
if (self->result) {
|
||||
@ -515,6 +596,7 @@ Int2 oldstatus, numcols;
|
||||
|
||||
mylog(" Sending SELECT statement on stmt=%u, cursor_name='%s'\n", self, self->cursor_name);
|
||||
|
||||
|
||||
/* send the declare/select */
|
||||
self->result = CC_send_query(conn, self->stmt_with_params, NULL, NULL);
|
||||
|
||||
|
@ -10,10 +10,27 @@
|
||||
#ifndef __STATEMENT_H__
|
||||
#define __STATEMENT_H__
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_IODBC
|
||||
#include "iodbc.h"
|
||||
#include "isql.h"
|
||||
#else
|
||||
#include <windows.h>
|
||||
#include <sql.h>
|
||||
#endif
|
||||
|
||||
#include "psqlodbc.h"
|
||||
|
||||
#ifndef FALSE
|
||||
#define FALSE (BOOL)0
|
||||
#endif
|
||||
#ifndef TRUE
|
||||
#define TRUE (BOOL)1
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
STMT_ALLOCATED, /* The statement handle is allocated, but not used so far */
|
||||
STMT_READY, /* the statement is waiting to be executed */
|
||||
@ -66,6 +83,40 @@ enum {
|
||||
|
||||
#define STMT_UPDATE(stmt) (stmt->statement_type > STMT_TYPE_SELECT)
|
||||
|
||||
|
||||
/* Parsing status */
|
||||
enum {
|
||||
STMT_PARSE_NONE = 0,
|
||||
STMT_PARSE_COMPLETE,
|
||||
STMT_PARSE_INCOMPLETE,
|
||||
STMT_PARSE_FATAL,
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
COL_INFO *col_info; /* cached SQLColumns info for this table */
|
||||
char name[MAX_TABLE_LEN+1];
|
||||
char alias[MAX_TABLE_LEN+1];
|
||||
} TABLE_INFO;
|
||||
|
||||
typedef struct {
|
||||
TABLE_INFO *ti; /* resolve to explicit table names */
|
||||
int precision;
|
||||
int display_size;
|
||||
int length;
|
||||
int type;
|
||||
char nullable;
|
||||
char func;
|
||||
char expr;
|
||||
char quote;
|
||||
char dquote;
|
||||
char numeric;
|
||||
char dot[MAX_TABLE_LEN+1];
|
||||
char name[MAX_COLUMN_LEN+1];
|
||||
char alias[MAX_COLUMN_LEN+1];
|
||||
} FIELD_INFO;
|
||||
|
||||
|
||||
|
||||
/******** Statement Handle ***********/
|
||||
struct StatementClass_ {
|
||||
ConnectionClass *hdbc; /* pointer to ConnectionClass this statement belongs to */
|
||||
@ -95,6 +146,13 @@ struct StatementClass_ {
|
||||
|
||||
char *statement; /* if non--null pointer to the SQL statement that has been executed */
|
||||
|
||||
TABLE_INFO **ti;
|
||||
FIELD_INFO **fi;
|
||||
int nfld;
|
||||
int ntab;
|
||||
|
||||
int parse_status;
|
||||
|
||||
int statement_type; /* According to the defines above */
|
||||
int data_at_exec; /* Number of params needing SQLPutData */
|
||||
int current_exec_param; /* The current parameter for SQLPutData */
|
||||
@ -107,7 +165,8 @@ struct StatementClass_ {
|
||||
|
||||
char internal; /* Is this statement being called internally? */
|
||||
|
||||
char cursor_name[32];
|
||||
char cursor_name[MAX_CURSOR_LEN+1];
|
||||
|
||||
char stmt_with_params[65536 /* MAX_STATEMENT_LEN */]; /* statement after parameter substitution */
|
||||
|
||||
};
|
||||
@ -123,6 +182,7 @@ struct StatementClass_ {
|
||||
StatementClass *SC_Constructor();
|
||||
char SC_Destructor(StatementClass *self);
|
||||
int statement_type(char *statement);
|
||||
char parse_statement(StatementClass *stmt);
|
||||
void SC_pre_execute(StatementClass *self);
|
||||
char SC_unbind_cols(StatementClass *self);
|
||||
char SC_recycle_statement(StatementClass *self);
|
||||
@ -134,4 +194,16 @@ RETCODE SC_execute(StatementClass *stmt);
|
||||
void SC_free_params(StatementClass *self, char option);
|
||||
void SC_log_error(char *func, char *desc, StatementClass *self);
|
||||
|
||||
RETCODE SQL_API _SQLAllocStmt(HDBC hdbc, HSTMT FAR *phstmt);
|
||||
RETCODE SQL_API _SQLFreeStmt(HSTMT hstmt, UWORD fOption);
|
||||
RETCODE SQL_API _SQLExecDirect(HSTMT hstmt, UCHAR FAR *szSqlStr, SDWORD cbSqlStr);
|
||||
RETCODE SQL_API _SQLFetch(HSTMT hstmt);
|
||||
RETCODE SQL_API _SQLGetData(
|
||||
HSTMT hstmt,
|
||||
UWORD icol,
|
||||
SWORD fCType,
|
||||
PTR rgbValue,
|
||||
SDWORD cbValueMax,
|
||||
SDWORD FAR *pcbValue);
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user