Commit 9e3382df authored by Marc G. Fournier's avatar Marc G. Fournier

Replace old PostODBC driver with new one...

This one is based on an older PostODBC driver, rewritten and maintained by
InsightDist(?)
parent d4d26f9c
/* Module: bind.c
*
* Description: This module contains routines related to binding
* columns and parameters.
*
* Classes: BindInfoClass, ParameterInfoClass
*
* API functions: SQLBindParameter, SQLBindCol, SQLDescribeParam, SQLNumParams,
* SQLParamOptions(NI)
*
* Comments: See "notice.txt" for copyright and license information.
*
*/
#include "bind.h"
#include "environ.h"
#include "statement.h"
#include "qresult.h"
#include "pgtypes.h"
#include <stdlib.h>
#include <malloc.h>
#include <sql.h>
#include <sqlext.h>
// Bind parameters on a statement handle
RETCODE SQL_API SQLBindParameter(
HSTMT hstmt,
UWORD ipar,
SWORD fParamType,
SWORD fCType,
SWORD fSqlType,
UDWORD cbColDef,
SWORD ibScale,
PTR rgbValue,
SDWORD cbValueMax,
SDWORD FAR *pcbValue)
{
StatementClass *stmt = (StatementClass *) hstmt;
if( ! stmt)
return SQL_INVALID_HANDLE;
if(stmt->parameters_allocated < ipar) {
ParameterInfoClass *old_parameters;
int i, old_parameters_allocated;
old_parameters = stmt->parameters;
old_parameters_allocated = stmt->parameters_allocated;
stmt->parameters = (ParameterInfoClass *) malloc(sizeof(ParameterInfoClass)*(ipar));
if ( ! stmt->parameters) {
stmt->errornumber = STMT_NO_MEMORY_ERROR;
stmt->errormsg = "Could not allocate memory for statement parameters";
return SQL_ERROR;
}
stmt->parameters_allocated = ipar;
// copy the old parameters over
for(i = 0; i < old_parameters_allocated; i++) {
// a structure copy should work
stmt->parameters[i] = old_parameters[i];
}
// get rid of the old parameters, if there were any
if(old_parameters)
free(old_parameters);
// zero out the newly allocated parameters (in case they skipped some,
// so we don't accidentally try to use them later)
for(; i < stmt->parameters_allocated; i++) {
stmt->parameters[i].buflen = 0;
stmt->parameters[i].buffer = 0;
stmt->parameters[i].used = 0;
stmt->parameters[i].paramType = 0;
stmt->parameters[i].CType = 0;
stmt->parameters[i].SQLType = 0;
stmt->parameters[i].precision = 0;
stmt->parameters[i].scale = 0;
stmt->parameters[i].data_at_exec = FALSE;
stmt->parameters[i].EXEC_used = NULL;
stmt->parameters[i].EXEC_buffer = NULL;
}
}
ipar--; /* use zero based column numbers for the below part */
// store the given info
stmt->parameters[ipar].buflen = cbValueMax;
stmt->parameters[ipar].buffer = rgbValue;
stmt->parameters[ipar].used = pcbValue;
stmt->parameters[ipar].paramType = fParamType;
stmt->parameters[ipar].CType = fCType;
stmt->parameters[ipar].SQLType = fSqlType;
stmt->parameters[ipar].precision = cbColDef;
stmt->parameters[ipar].scale = ibScale;
/* If rebinding a parameter that had data-at-exec stuff in it,
then free that stuff
*/
if (stmt->parameters[ipar].EXEC_used) {
free(stmt->parameters[ipar].EXEC_used);
stmt->parameters[ipar].EXEC_used = NULL;
}
if (stmt->parameters[ipar].EXEC_buffer) {
free(stmt->parameters[ipar].EXEC_buffer);
stmt->parameters[ipar].EXEC_buffer = NULL;
}
if (pcbValue && *pcbValue <= SQL_LEN_DATA_AT_EXEC_OFFSET)
stmt->parameters[ipar].data_at_exec = TRUE;
else
stmt->parameters[ipar].data_at_exec = FALSE;
return SQL_SUCCESS;
}
// - - - - - - - - -
// Associate a user-supplied buffer with a database column.
RETCODE SQL_API SQLBindCol(
HSTMT hstmt,
UWORD icol,
SWORD fCType,
PTR rgbValue,
SDWORD cbValueMax,
SDWORD FAR *pcbValue)
{
StatementClass *stmt = (StatementClass *) hstmt;
Int2 numcols;
mylog("**** SQLBindCol: stmt = %u, icol = %d\n", stmt, icol);
if ( ! stmt)
return SQL_INVALID_HANDLE;
if (icol < 1) {
/* currently we do not support bookmarks */
stmt->errormsg = "Bookmarks are not currently supported.";
stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR;
return SQL_ERROR;
}
icol--; /* use zero based col numbers */
SC_clear_error(stmt);
if( ! stmt->result) {
stmt->errormsg = "Can't bind columns with a NULL query result structure.";
stmt->errornumber = STMT_SEQUENCE_ERROR;
return SQL_ERROR;
}
if( stmt->status == STMT_EXECUTING) {
stmt->errormsg = "Can't bind columns while statement is still executing.";
stmt->errornumber = STMT_SEQUENCE_ERROR;
return SQL_ERROR;
}
numcols = QR_NumResultCols(stmt->result);
mylog("SQLBindCol: numcols = %d\n", numcols);
if (icol >= numcols) {
stmt->errornumber = STMT_COLNUM_ERROR;
stmt->errormsg = "Column number too big";
return SQL_ERROR;
}
if ( ! stmt->bindings) {
stmt->errormsg = "Bindings were not allocated properly.";
stmt->errornumber = STMT_SEQUENCE_ERROR;
return SQL_ERROR;
}
if ((cbValueMax == 0) || (rgbValue == NULL)) {
/* we have to unbind the column */
stmt->bindings[icol].buflen = 0;
stmt->bindings[icol].buffer = NULL;
stmt->bindings[icol].used = NULL;
stmt->bindings[icol].returntype = SQL_C_CHAR;
} else {
/* ok, bind that column */
stmt->bindings[icol].buflen = cbValueMax;
stmt->bindings[icol].buffer = rgbValue;
stmt->bindings[icol].used = pcbValue;
stmt->bindings[icol].returntype = fCType;
}
return SQL_SUCCESS;
}
// - - - - - - - - -
// Returns the description of a parameter marker.
RETCODE SQL_API SQLDescribeParam(
HSTMT hstmt,
UWORD ipar,
SWORD FAR *pfSqlType,
UDWORD FAR *pcbColDef,
SWORD FAR *pibScale,
SWORD FAR *pfNullable)
{
StatementClass *stmt = (StatementClass *) hstmt;
if( ! stmt)
return SQL_INVALID_HANDLE;
if( (ipar < 1) || (ipar > stmt->parameters_allocated) ) {
stmt->errormsg = "Invalid parameter number for SQLDescribeParam.";
stmt->errornumber = STMT_BAD_PARAMETER_NUMBER_ERROR;
return SQL_ERROR;
}
ipar--;
if(pfSqlType)
*pfSqlType = stmt->parameters[ipar].SQLType;
if(pcbColDef)
*pcbColDef = stmt->parameters[ipar].precision;
if(pibScale)
*pibScale = stmt->parameters[ipar].scale;
if(pfNullable)
*pfNullable = pgtype_nullable(stmt->parameters[ipar].paramType);
return SQL_SUCCESS;
}
// - - - - - - - - -
// Sets multiple values (arrays) for the set of parameter markers.
RETCODE SQL_API SQLParamOptions(
HSTMT hstmt,
UDWORD crow,
UDWORD FAR *pirow)
{
return SQL_ERROR;
}
// - - - - - - - - -
// Returns the number of parameter markers.
RETCODE SQL_API SQLNumParams(
HSTMT hstmt,
SWORD FAR *pcpar)
{
StatementClass *stmt = (StatementClass *) hstmt;
unsigned int i;
// I guess this is the number of actual parameter markers
// in the statement, not the number of parameters that are bound.
// why does this have to be driver-specific?
if(!stmt)
return SQL_INVALID_HANDLE;
if(!stmt->statement) {
// no statement has been allocated
*pcpar = 0;
stmt->errormsg = "SQLNumParams called with no statement ready.";
stmt->errornumber = STMT_SEQUENCE_ERROR;
return SQL_ERROR;
} else {
*pcpar = 0;
for(i=0; i < strlen(stmt->statement); i++) {
if(stmt->statement[i] == '?')
(*pcpar)++;
}
return SQL_SUCCESS;
}
}
/********************************************************************
* Bindings Implementation
*/
BindInfoClass *
create_empty_bindings(int num_columns)
{
BindInfoClass *new_bindings;
int i;
new_bindings = (BindInfoClass *)malloc(num_columns * sizeof(BindInfoClass));
if(!new_bindings) {
return 0;
}
for(i=0; i < num_columns; i++) {
new_bindings[i].buflen = 0;
new_bindings[i].buffer = NULL;
new_bindings[i].used = NULL;
}
return new_bindings;
}
void
extend_bindings(StatementClass *stmt, int num_columns)
{
BindInfoClass *new_bindings;
int i;
mylog("in extend_bindings\n");
/* if we have too few, allocate room for more, and copy the old */
/* entries into the new structure */
if(stmt->bindings_allocated < num_columns) {
new_bindings = create_empty_bindings(num_columns);
if(stmt->bindings) {
for(i=0; i<stmt->bindings_allocated; i++)
new_bindings[i] = stmt->bindings[i];
free(stmt->bindings);
}
stmt->bindings = new_bindings; // null indicates error
} else {
/* if we have too many, make sure the extra ones are emptied out */
/* so we don't accidentally try to use them for anything */
for(i = num_columns; i < stmt->bindings_allocated; i++) {
stmt->bindings[i].buflen = 0;
stmt->bindings[i].buffer = NULL;
stmt->bindings[i].used = NULL;
}
}
mylog("exit extend_bindings\n");
}
/* File: bind.h
*
* Description: See "bind.c"
*
* Comments: See "notice.txt" for copyright and license information.
*
*/
#ifndef __BIND_H__
#define __BIND_H__
#include "psqlodbc.h"
/*
* BindInfoClass -- stores information about a bound column
*/
struct BindInfoClass_ {
Int4 buflen; /* size of buffer */
char *buffer; /* pointer to the buffer */
Int4 *used; /* used space in the buffer (for strings not counting the '\0') */
Int2 returntype; /* kind of conversion to be applied when returning (SQL_C_DEFAULT, SQL_C_CHAR...) */
};
/*
* ParameterInfoClass -- stores information about a bound parameter
*/
struct ParameterInfoClass_ {
Int4 buflen;
char *buffer;
Int4 *used;
Int2 paramType;
Int2 CType;
Int2 SQLType;
UInt4 precision;
Int2 scale;
Int4 *EXEC_used;
char *EXEC_buffer;
char data_at_exec;
};
BindInfoClass *create_empty_bindings(int num_columns);
void extend_bindings(StatementClass *stmt, int num_columns);
#endif
/* Module: columninfo.c
*
* Description: This module contains routines related to
* reading and storing the field information from a query.
*
* Classes: ColumnInfoClass (Functions prefix: "CI_")
*
* API functions: none
*
* Comments: See "notice.txt" for copyright and license information.
*
*/
#include "columninfo.h"
#include "socket.h"
#include <stdlib.h>
#include <malloc.h>
ColumnInfoClass *
CI_Constructor()
{
ColumnInfoClass *rv;
rv = (ColumnInfoClass *) malloc(sizeof(ColumnInfoClass));
if (rv) {
rv->num_fields = 0;
rv->name = NULL;
rv->adtid = NULL;
rv->adtsize = NULL;
}
return rv;
}
void
CI_Destructor(ColumnInfoClass *self)
{
CI_free_memory(self);
free(self);
}
/* Read in field descriptions.
If self is not null, then also store the information.
If self is null, then just read, don't store.
*/
char
CI_read_fields(ColumnInfoClass *self, SocketClass *sock)
{
Int2 lf;
int new_num_fields;
Oid new_adtid;
Int2 new_adtsize;
char new_field_name[MAX_MESSAGE_LEN+1];
/* at first read in the number of fields that are in the query */
new_num_fields = (Int2) SOCK_get_int(sock, sizeof(Int2));
mylog("num_fields = %d\n", new_num_fields);
if (self) { /* according to that allocate memory */
CI_set_num_fields(self, new_num_fields);
}
/* now read in the descriptions */
for(lf = 0; lf < new_num_fields; lf++) {
SOCK_get_string(sock, new_field_name, MAX_MESSAGE_LEN);
new_adtid = (Oid) SOCK_get_int(sock, 4);
new_adtsize = (Int2) SOCK_get_int(sock, 2);
mylog("CI_read_fields: fieldname='%s', adtid=%d, adtsize=%d\n", new_field_name, new_adtid, new_adtsize);
if (self)
CI_set_field_info(self, lf, new_field_name, new_adtid, new_adtsize);
}
return (SOCK_get_errcode(sock) == 0);
}
void
CI_free_memory(ColumnInfoClass *self)
{
register Int2 lf;
int num_fields = self->num_fields;
for (lf = 0; lf < num_fields; lf++) {
if( self->name[lf])
free (self->name[lf]);
}
/* Safe to call even if null */
free(self->name);
free(self->adtid);
free(self->adtsize);
}
void
CI_set_num_fields(ColumnInfoClass *self, int new_num_fields)
{
CI_free_memory(self); /* always safe to call */
self->num_fields = new_num_fields;
self->name = (char **) malloc (sizeof(char *) * self->num_fields);
self->adtid = (Oid *) malloc (sizeof(Oid) * self->num_fields);
self->adtsize = (Int2 *) malloc (sizeof(Int2) * self->num_fields);
}
void
CI_set_field_info(ColumnInfoClass *self, int field_num, char *new_name,
Oid new_adtid, Int2 new_adtsize)
{
// check bounds
if((field_num < 0) || (field_num >= self->num_fields)) {
return;
}
// store the info
self->name[field_num] = strdup(new_name);
self->adtid[field_num] = new_adtid;
self->adtsize[field_num] = new_adtsize;
}
char *
CI_get_fieldname(ColumnInfoClass *self, Int2 which)
{
char *rv = NULL;
if ( ! self->name)
return NULL;
if ((which >= 0) && (which < self->num_fields))
rv = self->name[which];
return rv;
}
Int2
CI_get_fieldsize(ColumnInfoClass *self, Int2 which)
{
Int2 rv = 0;
if ( ! self->adtsize)
return 0;
if ((which >= 0) && (which < self->num_fields))
rv = self->adtsize[which];
return rv;
}
/* File: columninfo.h
*
* Description: See "columninfo.c"
*
* Comments: See "notice.txt" for copyright and license information.
*
*/
#ifndef __COLUMNINFO_H__
#define __COLUMNINFO_H__
#include "psqlodbc.h"
struct ColumnInfoClass_ {
Int2 num_fields;
char **name; /* list of type names */
Oid *adtid; /* list of type ids */
Int2 *adtsize; /* list type sizes */
};
#define CI_get_num_fields(self) (self->num_fields)
#define CI_get_oid(self, col) (self->adtid[col])
ColumnInfoClass *CI_Constructor();
void CI_Destructor(ColumnInfoClass *self);
char CI_read_fields(ColumnInfoClass *self, SocketClass *sock);
/* functions for setting up the fields from within the program, */
/* without reading from a socket */
void CI_set_num_fields(ColumnInfoClass *self, int new_num_fields);
void CI_set_field_info(ColumnInfoClass *self, int field_num, char *new_name,
Oid new_adtid, Int2 new_adtsize);
char *CI_get_fieldname(ColumnInfoClass *self, Int2 which);
Int2 CI_get_fieldsize(ColumnInfoClass *self, Int2 which);
void CI_free_memory(ColumnInfoClass *self);
#endif
This diff is collapsed.
/* File: connection.h
*
* Description: See "connection.c"
*
* Comments: See "notice.txt" for copyright and license information.
*
*/
#ifndef __CONNECTION_H__
#define __CONNECTION_H__
#include <windows.h>
#include <sql.h>
#include "psqlodbc.h"
typedef enum {
CONN_NOT_CONNECTED, /* Connection has not been established */
CONN_CONNECTED, /* Connection is up and has been established */
CONN_DOWN, /* Connection is broken */
CONN_EXECUTING /* the connection is currently executing a statement */
} CONN_Status;
/* These errors have general sql error state */
#define CONNECTION_SERVER_NOT_REACHED 1
#define CONNECTION_MSG_TOO_LONG 3
#define CONNECTION_COULD_NOT_SEND 4
#define CONNECTION_NO_SUCH_DATABASE 5
#define CONNECTION_BACKEND_CRAZY 6
#define CONNECTION_NO_RESPONSE 7
#define CONNECTION_SERVER_REPORTED_ERROR 8
#define CONNECTION_COULD_NOT_RECEIVE 9
#define CONNECTION_SERVER_REPORTED_WARNING 10
#define CONNECTION_NEED_PASSWORD 12
/* These errors correspond to specific SQL states */
#define CONN_INIREAD_ERROR 1
#define CONN_OPENDB_ERROR 2
#define CONN_STMT_ALLOC_ERROR 3
#define CONN_IN_USE 4
#define CONN_UNSUPPORTED_OPTION 5
/* Used by SetConnectoption to indicate unsupported options */
#define CONN_INVALID_ARGUMENT_NO 6
/* SetConnectOption: corresponds to ODBC--"S1009" */
#define CONN_TRANSACT_IN_PROGRES 7
#define CONN_NO_MEMORY_ERROR 8
#define CONN_NOT_IMPLEMENTED_ERROR 9
#define CONN_INVALID_AUTHENTICATION 10
#define CONN_AUTH_TYPE_UNSUPPORTED 11
/* Conn_status defines */
#define CONN_IN_AUTOCOMMIT 0x01
#define CONN_IN_TRANSACTION 0x02
/* AutoCommit functions */
#define CC_set_autocommit_off(x) (x->transact_status &= ~CONN_IN_AUTOCOMMIT)
#define CC_set_autocommit_on(x) (x->transact_status |= CONN_IN_AUTOCOMMIT)
#define CC_is_in_autocommit(x) (x->transact_status & CONN_IN_AUTOCOMMIT)
/* Transaction in/not functions */
#define CC_set_in_trans(x) (x->transact_status |= CONN_IN_TRANSACTION)
#define CC_set_no_trans(x) (x->transact_status &= ~CONN_IN_TRANSACTION)
#define CC_is_in_trans(x) (x->transact_status & CONN_IN_TRANSACTION)
/* Authentication types */
#define AUTH_REQ_OK 0
#define AUTH_REQ_KRB4 1
#define AUTH_REQ_KRB5 2
#define AUTH_REQ_PASSWORD 3
#define AUTH_REQ_CRYPT 4
/* Startup Packet sizes */
#define SM_DATABASE 64
#define SM_USER 32
#define SM_OPTIONS 64
#define SM_UNUSED 64
#define SM_TTY 64
/* Old 6.2 protocol defines */
#define NO_AUTHENTICATION 7
#define PATH_SIZE 64
#define ARGV_SIZE 64
#define NAMEDATALEN 16
typedef unsigned int ProtocolVersion;
#define PG_PROTOCOL(major, minor) (((major) << 16) | (minor))
#define PG_PROTOCOL_LATEST PG_PROTOCOL(1, 0)
#define PG_PROTOCOL_EARLIEST PG_PROTOCOL(0, 0)
/* This startup packet is to support latest Postgres protocol (6.3) */
typedef struct _StartupPacket
{
ProtocolVersion protoVersion;
char database[SM_DATABASE];
char user[SM_USER];
char options[SM_OPTIONS];
char unused[SM_UNUSED];
char tty[SM_TTY];
} StartupPacket;
/* This startup packet is to support pre-Postgres 6.3 protocol */
typedef struct _StartupPacket6_2
{
unsigned int authtype;
char database[PATH_SIZE];
char user[NAMEDATALEN];
char options[ARGV_SIZE];
char execfile[ARGV_SIZE];
char tty[PATH_SIZE];
} StartupPacket6_2;
/* Structure to hold all the connection attributes for a specific
connection (used for both registry and file, DSN and DRIVER)
*/
typedef struct {
char dsn[MEDIUM_REGISTRY_LEN];
char driver[MEDIUM_REGISTRY_LEN];
char server[MEDIUM_REGISTRY_LEN];
char database[MEDIUM_REGISTRY_LEN];
char username[MEDIUM_REGISTRY_LEN];
char password[MEDIUM_REGISTRY_LEN];
char conn_settings[LARGE_REGISTRY_LEN];
char protocol[SMALL_REGISTRY_LEN];
char port[SMALL_REGISTRY_LEN];
char readonly[SMALL_REGISTRY_LEN];
char focus_password;
} ConnInfo;
/* Macro to determine is the connection using 6.2 protocol? */
#define PROTOCOL_62(conninfo_) (strncmp((conninfo_)->protocol, PG62, strlen(PG62)) == 0)
/******* The Connection handle ************/
struct ConnectionClass_ {
HENV henv; /* environment this connection was created on */
char *errormsg;
int errornumber;
CONN_Status status;
ConnInfo connInfo;
StatementClass **stmts;
int num_stmts;
SocketClass *sock;
char transact_status; /* Is a transaction is currently in progress */
char errormsg_created; /* has an informative error msg been created? */
};
/* Accessor functions */
#define CC_get_socket(x) (x->sock)
#define CC_get_database(x) (x->connInfo.database)
#define CC_get_server(x) (x->connInfo.server)
#define CC_get_DSN(x) (x->connInfo.dsn)
#define CC_get_username(x) (x->connInfo.username)
#define CC_is_readonly(x) (x->connInfo.readonly[0] == '1')
/* for CC_DSN_info */
#define CONN_DONT_OVERWRITE 0
#define CONN_OVERWRITE 1
/* prototypes */
ConnectionClass *CC_Constructor();
char CC_Destructor(ConnectionClass *self);
char CC_cleanup(ConnectionClass *self);
char CC_abort(ConnectionClass *self);
void CC_DSN_info(ConnectionClass *self, char overwrite);
void CC_set_defaults(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);
char CC_get_error(ConnectionClass *self, int *number, char **message);
QResultClass *CC_send_query(ConnectionClass *self, char *query, QResultClass *result_in, char *cursor);
void CC_clear_error(ConnectionClass *self);
char *CC_create_errormsg(ConnectionClass *self);
char CC_send_settings(ConnectionClass *self);
#endif
This diff is collapsed.
/* File: convert.h
*
* Description: See "convert.c"
*
* Comments: See "notice.txt" for copyright and license information.
*
*/
#ifndef __CONVERT_H__
#define __CONVERT_H__
#include "psqlodbc.h"
/* copy_and_convert results */
#define COPY_OK 0
#define COPY_UNSUPPORTED_TYPE 1
#define COPY_UNSUPPORTED_CONVERSION 2
#define COPY_RESULT_TRUNCATED 3
typedef struct {
int m;
int d;
int y;
int hh;
int mm;
int ss;
} SIMPLE_TIME;
int copy_and_convert_field_bindinfo(Int4 field_type, void *value, BindInfoClass *bic);
int copy_and_convert_field(Int4 field_type, void *value,
Int2 fCType, PTR rgbValue, SDWORD cbValueMax, SDWORD *pcbValue);
int copy_statement_with_parameters(StatementClass *stmt);
char *convert_escape(char *value);
char *convert_money(char *s);
int monthToNumber(char *mon);
char *convert_time(SIMPLE_TIME *st);
char parse_datetime(char *buf, SIMPLE_TIME *st);
char *convert_linefeeds(char *s, char *dst, size_t max);
char *convert_returns(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);
#endif
/* Module: drvconn.c
*
* Description: This module contains only routines related to
* implementing SQLDriverConnect.
*
* Classes: n/a
*
* API functions: SQLDriverConnect
*
* Comments: See "notice.txt" for copyright and license information.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include "psqlodbc.h"
#include "connection.h"
#include <winsock.h>
#include <sqlext.h>
#include <string.h>
#include <windows.h>
#include <windowsx.h>
#include <odbcinst.h>
#include "resource.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);
extern HINSTANCE NEAR s_hModule; /* Saved module handle. */
extern GLOBAL_VALUES globals;
RETCODE SQL_API SQLDriverConnect(
HDBC hdbc,
HWND hwnd,
UCHAR FAR *szConnStrIn,
SWORD cbConnStrIn,
UCHAR FAR *szConnStrOut,
SWORD cbConnStrOutMax,
SWORD FAR *pcbConnStrOut,
UWORD fDriverCompletion)
{
ConnectionClass *conn = (ConnectionClass *) hdbc;
ConnInfo *ci;
RETCODE dialog_result;
char connect_string[MAX_CONNECT_STRING];
int retval;
char password_required = FALSE;
mylog("**** SQLDriverConnect: fDriverCompletion=%d, connStrIn='%s'\n", fDriverCompletion, szConnStrIn);
if ( ! conn)
return SQL_INVALID_HANDLE;
qlog("conn=%u, SQLDriverConnect( in)='%s'\n", conn, szConnStrIn);
ci = &(conn->connInfo);
// Parse the connect string and fill in conninfo for this hdbc.
dconn_get_connect_attributes(szConnStrIn, ci);
// If the ConnInfo in the hdbc is missing anything,
// this function will fill them in from the registry (assuming
// of course there is a DSN given -- if not, it does nothing!)
CC_DSN_info(conn, CONN_DONT_OVERWRITE);
// Fill in any default parameters if they are not there.
CC_set_defaults(conn);
dialog:
ci->focus_password = password_required;
switch(fDriverCompletion) {
case SQL_DRIVER_PROMPT:
dialog_result = dconn_DoDialog(hwnd, ci);
if(dialog_result != SQL_SUCCESS) {
return dialog_result;
}
break;
case SQL_DRIVER_COMPLETE:
case SQL_DRIVER_COMPLETE_REQUIRED:
/* Password is not a required parameter. */
if( ci->username[0] == '\0' ||
ci->server[0] == '\0' ||
ci->database[0] == '\0' ||
ci->port[0] == '\0' ||
password_required) {
dialog_result = dconn_DoDialog(hwnd, ci);
if(dialog_result != SQL_SUCCESS) {
return dialog_result;
}
}
break;
case SQL_DRIVER_NOPROMPT:
break;
}
/* Password is not a required parameter unless authentication asks for it.
For now, I think its better to just let the application ask over and over until
a password is entered (the user can always hit Cancel to get out)
*/
if( ci->username[0] == '\0' ||
ci->server[0] == '\0' ||
ci->database[0] == '\0' ||
ci->port[0] == '\0') {
// (password_required && ci->password[0] == '\0'))
return SQL_NO_DATA_FOUND;
}
if(szConnStrOut) {
// return the completed string to the caller.
char got_dsn = (ci->dsn[0] != '\0');
sprintf(connect_string, "%s=%s;DATABASE=%s;SERVER=%s;PORT=%s;UID=%s;READONLY=%s;PWD=%s;PROTOCOL=%s;CONNSETTINGS=%s",
got_dsn ? "DSN" : "DRIVER",
got_dsn ? ci->dsn : ci->driver,
ci->database,
ci->server,
ci->port,
ci->username,
ci->readonly,
ci->password,
ci->protocol,
ci->conn_settings);
if(pcbConnStrOut) {
*pcbConnStrOut = strlen(connect_string);
}
strncpy_null(szConnStrOut, connect_string, cbConnStrOutMax);
}
mylog("szConnStrOut = '%s'\n", szConnStrOut);
qlog("conn=%u, SQLDriverConnect(out)='%s'\n", conn, szConnStrOut);
// do the actual connect
retval = CC_connect(conn, password_required);
if (retval < 0) { /* need a password */
if (fDriverCompletion == SQL_DRIVER_NOPROMPT)
return SQL_ERROR; /* need a password but not allowed to prompt so error */
else {
password_required = TRUE;
goto dialog;
}
}
else if (retval == 0) {
// error msg filled in above
return SQL_ERROR;
}
mylog("SQLDRiverConnect: returning success\n");
return SQL_SUCCESS;
}
RETCODE dconn_DoDialog(HWND hwnd, ConnInfo *ci)
{
int dialog_result;
mylog("dconn_DoDialog: ci = %u\n", ci);
if(hwnd) {
dialog_result = DialogBoxParam(s_hModule, MAKEINTRESOURCE(DRIVERCONNDIALOG),
hwnd, dconn_FDriverConnectProc, (LPARAM) ci);
if(!dialog_result || (dialog_result == -1)) {
return SQL_NO_DATA_FOUND;
} else {
return SQL_SUCCESS;
}
}
return SQL_ERROR;
}
BOOL FAR PASCAL dconn_FDriverConnectProc(
HWND hdlg,
UINT wMsg,
WPARAM wParam,
LPARAM lParam)
{
static ConnInfo *ci;
switch (wMsg) {
case WM_INITDIALOG:
ci = (ConnInfo *) lParam; // Save the ConnInfo for the "OK"
SetDlgItemText(hdlg, SERVER_EDIT, ci->server);
SetDlgItemText(hdlg, DATABASE_EDIT, ci->database);
SetDlgItemText(hdlg, USERNAME_EDIT, ci->username);
SetDlgItemText(hdlg, PASSWORD_EDIT, ci->password);
SetDlgItemText(hdlg, PORT_EDIT, ci->port);
CheckDlgButton(hdlg, READONLY_EDIT, atoi(ci->readonly));
CheckDlgButton(hdlg, PG62_EDIT, PROTOCOL_62(ci));
/* The driver connect dialog box allows manipulating this global variable */
CheckDlgButton(hdlg, COMMLOG_EDIT, globals.commlog);
if (ci->database[0] == '\0')
; /* default focus */
else if (ci->server[0] == '\0')
SetFocus(GetDlgItem(hdlg, SERVER_EDIT));
else if (ci->port[0] == '\0')
SetFocus(GetDlgItem(hdlg, PORT_EDIT));
else if (ci->username[0] == '\0')
SetFocus(GetDlgItem(hdlg, USERNAME_EDIT));
else if (ci->focus_password)
SetFocus(GetDlgItem(hdlg, PASSWORD_EDIT));
break;
case WM_COMMAND:
switch (GET_WM_COMMAND_ID(wParam, lParam)) {
case IDOK:
GetDlgItemText(hdlg, SERVER_EDIT, ci->server, sizeof(ci->server));
GetDlgItemText(hdlg, DATABASE_EDIT, ci->database, sizeof(ci->database));
GetDlgItemText(hdlg, USERNAME_EDIT, ci->username, sizeof(ci->username));
GetDlgItemText(hdlg, PASSWORD_EDIT, ci->password, sizeof(ci->password));
GetDlgItemText(hdlg, PORT_EDIT, ci->port, sizeof(ci->port));
sprintf(ci->readonly, "%d", IsDlgButtonChecked(hdlg, READONLY_EDIT));
if (IsDlgButtonChecked(hdlg, PG62_EDIT))
strcpy(ci->protocol, PG62);
else
ci->protocol[0] = '\0';
/* The driver connect dialog box allows manipulating this global variable */
globals.commlog = IsDlgButtonChecked(hdlg, COMMLOG_EDIT);
updateGlobals();
case IDCANCEL:
EndDialog(hdlg, GET_WM_COMMAND_ID(wParam, lParam) == IDOK);
return TRUE;
}
}
return FALSE;
}
void dconn_get_connect_attributes(UCHAR FAR *connect_string, ConnInfo *ci)
{
char *our_connect_string;
char *pair, *attribute, *value, *equals;
char *strtok_arg;
memset(ci, 0, sizeof(ConnInfo));
our_connect_string = strdup(connect_string);
strtok_arg = our_connect_string;
mylog("our_connect_string = '%s'\n", our_connect_string);
while(1) {
pair = strtok(strtok_arg, ";");
if(strtok_arg) {
strtok_arg = 0;
}
if(!pair) {
break;
}
equals = strchr(pair, '=');
if ( ! equals)
continue;
*equals = '\0';
attribute = pair; // ex. DSN
value = equals + 1; // ex. 'CEO co1'
mylog("attribute = '%s', value = '%s'\n", attribute, value);
if( !attribute || !value)
continue;
/*********************************************************/
/* PARSE ATTRIBUTES */
/*********************************************************/
if(stricmp(attribute, "DSN") == 0)
strcpy(ci->dsn, value);
else if(stricmp(attribute, "driver") == 0)
strcpy(ci->driver, value);
else if(stricmp(attribute, "uid") == 0)
strcpy(ci->username, value);
else if(stricmp(attribute, "pwd") == 0)
strcpy(ci->password, value);
else if ((stricmp(attribute, "server") == 0) ||
(stricmp(attribute, "servername") == 0))
strcpy(ci->server, value);
else if(stricmp(attribute, "port") == 0)
strcpy(ci->port, value);
else if(stricmp(attribute, "database") == 0)
strcpy(ci->database, value);
else if (stricmp(attribute, "readonly") == 0)
strcpy(ci->readonly, value);
else if (stricmp(attribute, "protocol") == 0)
strcpy(ci->protocol, value);
else if (stricmp(attribute, "connsettings") == 0)
strcpy(ci->conn_settings, value);
}
free(our_connect_string);
}
This diff is collapsed.
/* File: environ.h
*
* Description: See "environ.c"
*
* Comments: See "notice.txt" for copyright and license information.
*
*/
#ifndef __ENVIRON_H__
#define __ENVIRON_H__
#include "psqlodbc.h"
#include <windows.h>
#include <sql.h>
#define ENV_ALLOC_ERROR 1
/********** Environment Handle *************/
struct EnvironmentClass_ {
char *errormsg;
int errornumber;
};
/* Environment prototypes */
EnvironmentClass *EN_Constructor(void);
char EN_Destructor(EnvironmentClass *self);
char EN_get_error(EnvironmentClass *self, int *number, char **message);
char EN_add_connection(EnvironmentClass *self, ConnectionClass *conn);
char EN_remove_connection(EnvironmentClass *self, ConnectionClass *conn);
#endif
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
/* Module: misc.c
*
* Description: This module contains miscellaneous routines
* such as for debugging/logging and string functions.
*
* Classes: n/a
*
* API functions: none
*
* Comments: See "notice.txt" for copyright and license information.
*
*/
#include <stdio.h>
#include <windows.h>
#include <sql.h>
#include "psqlodbc.h"
extern GLOBAL_VALUES globals;
#ifdef MY_LOG
#include <varargs.h>
void
mylog(va_alist)
va_dcl
{
char *fmt;
char *args;
static FILE *LOGFP = 0;
if ( globals.debug) {
va_start(args);
fmt = va_arg(args, char *);
if (! LOGFP) {
LOGFP = fopen("c:\\mylog.log", "w");
setbuf(LOGFP, NULL);
}
if (LOGFP)
vfprintf(LOGFP, fmt, args);
va_end(args);
}
}
#endif
#ifdef Q_LOG
#include <varargs.h>
void qlog(va_alist)
va_dcl
{
char *fmt;
char *args;
static FILE *LOGFP = 0;
if ( globals.commlog) {
va_start(args);
fmt = va_arg(args, char *);
if (! LOGFP) {
LOGFP = fopen("c:\\psqlodbc.log", "w");
setbuf(LOGFP, NULL);
}
if (LOGFP)
vfprintf(LOGFP, fmt, args);
va_end(args);
}
}
#endif
/* returns STRCPY_FAIL, STRCPY_TRUNCATED, or #bytes copied (not including null term) */
int
my_strcpy(char *dst, size_t dst_len, char *src, size_t src_len)
{
if (dst_len <= 0)
return STRCPY_FAIL;
if (src_len == SQL_NULL_DATA) {
dst[0] = '\0';
return STRCPY_NULL;
}
else if (src_len == SQL_NTS) {
if (src_len < dst_len)
strcpy(dst, src);
else {
memcpy(dst, src, dst_len-1);
dst[dst_len-1] = '\0'; /* truncated */
return STRCPY_TRUNCATED;
}
}
else if (src_len <= 0)
return STRCPY_FAIL;
else {
if (src_len < dst_len) {
memcpy(dst, src, src_len);
dst[src_len] = '\0';
}
else {
memcpy(dst, src, dst_len-1);
dst[dst_len-1] = '\0'; /* truncated */
return STRCPY_TRUNCATED;
}
}
return strlen(dst);
}
// strncpy copies up to len characters, and doesn't terminate
// the destination string if src has len characters or more.
// instead, I want it to copy up to len-1 characters and always
// terminate the destination string.
char *strncpy_null(char *dst, const char *src, size_t len)
{
unsigned int i;
if (NULL != dst) {
/* Just in case, check for special lengths */
if (len == SQL_NULL_DATA) {
dst[0] = '\0';
return NULL;
}
else if (len == SQL_NTS)
len = strlen(src) + 1;
for(i = 0; src[i] && i < len - 1; i++) {
dst[i] = src[i];
}
if(len > 0) {
dst[i] = '\0';
}
}
return dst;
}
// Create a null terminated string (handling the SQL_NTS thing):
// 1. If buf is supplied, place the string in there (assumes enough space) and return buf.
// 2. If buf is not supplied, malloc space and return this string
char *
make_string(char *s, int len, char *buf)
{
int length;
char *str;
if(s && (len > 0 || len == SQL_NTS)) {
length = (len > 0) ? len : strlen(s);
if (buf) {
strncpy_null(buf, s, length+1);
return buf;
}
str = malloc(length + 1);
if ( ! str)
return NULL;
strncpy_null(str, s, length+1);
return str;
}
return NULL;
}
// Concatenate a single formatted argument to a given buffer handling the SQL_NTS thing.
// "fmt" must contain somewhere in it the single form '%.*s'
// This is heavily used in creating queries for info routines (SQLTables, SQLColumns).
// This routine could be modified to use vsprintf() to handle multiple arguments.
char *
my_strcat(char *buf, char *fmt, char *s, int len)
{
if (s && (len > 0 || (len == SQL_NTS && strlen(s) > 0))) {
int length = (len > 0) ? len : strlen(s);
int pos = strlen(buf);
sprintf(&buf[pos], fmt, length, s);
return buf;
}
return NULL;
}
void remove_newlines(char *string)
{
unsigned int i;
for(i=0; i < strlen(string); i++) {
if((string[i] == '\n') ||
(string[i] == '\r')) {
string[i] = ' ';
}
}
}
char *
trim(char *s)
{
int i;
for (i = strlen(s) - 1; i >= 0; i--) {
if (s[i] == ' ')
s[i] = '\0';
else
break;
}
return s;
}
/* File: misc.h
*
* Description: See "misc.c"
*
* Comments: See "notice.txt" for copyright and license information.
*
*/
#ifndef __MISC_H__
#define __MISC_H__
#include <stdio.h>
/* Uncomment MY_LOG define to compile in the mylog() statements.
Then, debug logging will occur if 'Debug' is set to 1 in the ODBCINST.INI
portion of the registry. You may have to manually add this key.
This logfile is intended for development use, not for an end user!
*/
// #define MY_LOG
/* Uncomment Q_LOG to compile in the qlog() statements (Communications log, i.e. CommLog).
This logfile contains serious log statements that are intended for an
end user to be able to read and understand. It is controlled by the
'CommLog' flag in the ODBCINST.INI portion of the registry (see above),
which is manipulated on the setup/connection dialog boxes.
*/
#define Q_LOG
#ifdef MY_LOG
void mylog(); /* prototype */
#else
#define mylog // mylog
#endif
#ifdef Q_LOG
void qlog(); /* prototype */
#else
#define qlog // qlog
#endif
void remove_newlines(char *string);
char *strncpy_null(char *dst, const char *src, size_t len);
char *trim(char *string);
char *make_string(char *s, int len, char *buf);
char *my_strcat(char *buf, char *fmt, char *s, int len);
/* defines for return value of my_strcpy */
#define STRCPY_SUCCESS 1
#define STRCPY_FAIL 0
#define STRCPY_TRUNCATED -1
#define STRCPY_NULL -2
int my_strcpy(char *dst, size_t dst_len, char *src, size_t src_len);
#endif
/********************************************************************
PSQLODBC.DLL - A library to talk to the PostgreSQL DBMS using ODBC.
Copyright (C) 1998; Insight Distribution Systems
The code contained in this library is based on code written by
Christian Czezatke and Dan McGuirk, (C) 1996.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This library is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTIBILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library (see "license.txt"); if not, write to
the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA
02139, USA.
How to contact the author:
email: byronn@insightdist.com (Byron Nikolaidis)
***********************************************************************/
/* Module: options.c
*
* Description: This module contains routines for getting/setting
* connection and statement options.
*
* Classes: n/a
*
* API functions: SQLSetConnectOption, SQLSetStmtOption, SQLGetConnectOption,
* SQLGetStmtOption
*
* Comments: See "notice.txt" for copyright and license information.
*
*/
#include "psqlodbc.h"
#include <windows.h>
#include <sql.h>
#include "environ.h"
#include "connection.h"
#include "statement.h"
/* Implements only SQL_AUTOCOMMIT */
RETCODE SQL_API SQLSetConnectOption(
HDBC hdbc,
UWORD fOption,
UDWORD vParam)
{
ConnectionClass *conn = (ConnectionClass *) hdbc;
if ( ! conn)
return SQL_INVALID_HANDLE;
switch (fOption) {
case SQL_AUTOCOMMIT:
/* Since we are almost always in a transaction, this is now ok.
Even if we were, the logic will handle it by sending a commit
after the statement.
if (CC_is_in_trans(conn)) {
conn->errormsg = "Cannot switch commit mode while a transaction is in progres";
conn->errornumber = CONN_TRANSACT_IN_PROGRES;
return SQL_ERROR;
}
*/
mylog("SQLSetConnectOption: AUTOCOMMIT: transact_status=%d, vparam=%d\n", conn->transact_status, vParam);
switch(vParam) {
case SQL_AUTOCOMMIT_OFF:
CC_set_autocommit_off(conn);
break;
case SQL_AUTOCOMMIT_ON:
CC_set_autocommit_on(conn);
break;
default:
conn->errormsg = "Illegal parameter value for SQL_AUTOCOMMIT";
conn->errornumber = CONN_INVALID_ARGUMENT_NO;
return SQL_ERROR;
}
break;
case SQL_LOGIN_TIMEOUT:
break;
case SQL_ACCESS_MODE:
break;
default:
conn->errormsg = "This option is currently unsupported by the driver";
conn->errornumber = CONN_UNSUPPORTED_OPTION;
return SQL_ERROR;
}
return SQL_SUCCESS;
}
// - - - - - - - - -
RETCODE SQL_API SQLSetStmtOption(
HSTMT hstmt,
UWORD fOption,
UDWORD vParam)
{
StatementClass *stmt = (StatementClass *) hstmt;
// thought we could fake Access out by just returning SQL_SUCCESS
// all the time, but it tries to set a huge value for SQL_MAX_LENGTH
// and expects the driver to reduce it to the real value
if( ! stmt) {
return SQL_INVALID_HANDLE;
}
switch(fOption) {
case SQL_QUERY_TIMEOUT:
mylog("SetStmtOption: vParam = %d\n", vParam);
/*
stmt->errornumber = STMT_OPTION_VALUE_CHANGED;
stmt->errormsg = "Query Timeout: value changed to 0";
return SQL_SUCCESS_WITH_INFO;
*/
return SQL_SUCCESS;
break;
case SQL_MAX_LENGTH:
/* CC: Some apps consider returning SQL_SUCCESS_WITH_INFO to be an error */
/* so if we're going to return SQL_SUCCESS, we better not set an */
/* error message. (otherwise, if a subsequent function call returns */
/* SQL_ERROR without setting a message, things can get confused.) */
/*
stmt->errormsg = "Requested value changed.";
stmt->errornumber = STMT_OPTION_VALUE_CHANGED;
*/
return SQL_SUCCESS;
break;
case SQL_MAX_ROWS:
mylog("SetStmtOption(): SQL_MAX_ROWS = %d, returning success\n", vParam);
stmt->maxRows = vParam;
return SQL_SUCCESS;
break;
default:
return SQL_ERROR;
}
return SQL_SUCCESS;
}
// - - - - - - - - -
/* This function just can tell you whether you are in Autcommit mode or not */
RETCODE SQL_API SQLGetConnectOption(
HDBC hdbc,
UWORD fOption,
PTR pvParam)
{
ConnectionClass *conn = (ConnectionClass *) hdbc;
if (! conn)
return SQL_INVALID_HANDLE;
switch (fOption) {
case SQL_AUTOCOMMIT:
/* CC 28.05.96: Do not set fOption, but pvParam */
*((UDWORD *)pvParam) = (UDWORD)( CC_is_in_autocommit(conn) ?
SQL_AUTOCOMMIT_ON : SQL_AUTOCOMMIT_OFF);
break;
/* we don't use qualifiers */
case SQL_CURRENT_QUALIFIER:
if(pvParam) {
strcpy(pvParam, "");
}
break;
default:
conn->errormsg = "This option is currently unsupported by the driver";
conn->errornumber = CONN_UNSUPPORTED_OPTION;
return SQL_ERROR;
break;
}
return SQL_SUCCESS;
}
// - - - - - - - - -
RETCODE SQL_API SQLGetStmtOption(
HSTMT hstmt,
UWORD fOption,
PTR pvParam)
{
StatementClass *stmt = (StatementClass *) hstmt;
// thought we could fake Access out by just returning SQL_SUCCESS
// all the time, but it tries to set a huge value for SQL_MAX_LENGTH
// and expects the driver to reduce it to the real value
if( ! stmt) {
return SQL_INVALID_HANDLE;
}
switch(fOption) {
case SQL_QUERY_TIMEOUT:
// how long we wait on a query before returning to the
// application (0 == forever)
*((SDWORD *)pvParam) = 0;
break;
case SQL_MAX_LENGTH:
// what is the maximum length that will be returned in
// a single column
*((SDWORD *)pvParam) = 4096;
break;
case SQL_MAX_ROWS:
*((SDWORD *)pvParam) = stmt->maxRows;
mylog("GetSmtOption: MAX_ROWS, returning %d\n", stmt->maxRows);
break;
default:
return SQL_ERROR;
}
return SQL_SUCCESS;
}
// - - - - - - - - -
This diff is collapsed.
/* File: pgtypes.h
*
* Description: See "pgtypes.c"
*
* Comments: See "notice.txt" for copyright and license information.
*
*/
#ifndef __PGTYPES_H__
#define __PGTYPES_H__
/* the type numbers are defined by the OID's of the types' rows */
/* in table pg_type */
#define PG_UNKNOWN -666 /* returned only from pgtype_to_sqltype() */
#define PG_TYPE_BOOL 16
#define PG_TYPE_BYTEA 17
#define PG_TYPE_CHAR 18
#define PG_TYPE_NAME 19
#define PG_TYPE_CHAR16 20
#define PG_TYPE_INT2 21
#define PG_TYPE_INT28 22
#define PG_TYPE_INT4 23
#define PG_TYPE_REGPROC 24
#define PG_TYPE_TEXT 25
#define PG_TYPE_OID 26
#define PG_TYPE_TID 27
#define PG_TYPE_XID 28
#define PG_TYPE_CID 29
#define PG_TYPE_OID8 30
#define PG_TYPE_SET 32
#define PG_TYPE_CHAR2 409
#define PG_TYPE_CHAR4 410
#define PG_TYPE_CHAR8 411
#define PG_TYPE_POINT 600
#define PG_TYPE_LSEG 601
#define PG_TYPE_PATH 602
#define PG_TYPE_BOX 603
#define PG_TYPE_POLYGON 604
#define PG_TYPE_FILENAME 605
#define PG_TYPE_FLOAT4 700
#define PG_TYPE_FLOAT8 701
#define PG_TYPE_ABSTIME 702
#define PG_TYPE_RELTIME 703
#define PG_TYPE_TINTERVAL 704
#define PG_TYPE_UNKNOWN 705
#define PG_TYPE_MONEY 790
#define PG_TYPE_OIDINT2 810
#define PG_TYPE_OIDINT4 910
#define PG_TYPE_OIDNAME 911
#define PG_TYPE_BPCHAR 1042
#define PG_TYPE_VARCHAR 1043
#define PG_TYPE_DATE 1082
#define PG_TYPE_TIME 1083
#define PG_TYPE_DATETIME 1184
extern Int4 pgtypes_defined[];
Int2 pgtype_to_sqltype(Int4 type);
Int2 pgtype_to_ctype(Int4 type);
char *pgtype_to_name(Int4 type);
Int4 pgtype_precision(Int4 type);
Int4 pgtype_length(Int4 type);
Int2 pgtype_scale(Int4 type);
Int2 pgtype_radix(Int4 type);
Int2 pgtype_nullable(Int4 type);
Int2 pgtype_auto_increment(Int4 type);
Int2 pgtype_case_sensitive(Int4 type);
Int2 pgtype_money(Int4 type);
Int2 pgtype_searchable(Int4 type);
Int2 pgtype_unsigned(Int4 type);
char *pgtype_literal_prefix(Int4 type);
char *pgtype_literal_suffix(Int4 type);
char *pgtype_create_params(Int4 type);
Int2 sqltype_to_default_ctype(Int2 sqltype);
#endif
/* Module: psqlodbc.c
*
* Description: This module contains the main entry point (DllMain) for the library.
* It also contains functions to get and set global variables for the
* driver in the registry.
*
* Classes: n/a
*
* API functions: none
*
* Comments: See "notice.txt" for copyright and license information.
*
*/
#include "psqlodbc.h"
#include <winsock.h>
#include <windows.h>
#include <sql.h>
#include <odbcinst.h>
HINSTANCE NEAR s_hModule; /* Saved module handle. */
GLOBAL_VALUES globals;
/* This function reads the ODBCINST.INI portion of
the registry and gets any driver defaults.
*/
void getGlobalDefaults(void)
{
char temp[128];
// Fetch Count is stored in driver section
SQLGetPrivateProfileString(DBMS_NAME, INI_FETCH, "",
temp, sizeof(temp), ODBCINST_INI);
if ( temp[0] )
globals.fetch_max = atoi(temp);
else
globals.fetch_max = FETCH_MAX;
// Socket Buffersize is stored in driver section
SQLGetPrivateProfileString(DBMS_NAME, INI_SOCKET, "",
temp, sizeof(temp), ODBCINST_INI);
if ( temp[0] )
globals.socket_buffersize = atoi(temp);
else
globals.socket_buffersize = SOCK_BUFFER_SIZE;
// Debug is stored in the driver section
SQLGetPrivateProfileString(DBMS_NAME, INI_DEBUG, "0",
temp, sizeof(temp), ODBCINST_INI);
globals.debug = atoi(temp);
// CommLog is stored in the driver section
SQLGetPrivateProfileString(DBMS_NAME, INI_COMMLOG, "0",
temp, sizeof(temp), ODBCINST_INI);
globals.commlog = atoi(temp);
// Optimizer is stored in the driver section only (OFF, ON, or ON=x)
SQLGetPrivateProfileString(DBMS_NAME, INI_OPTIMIZER, "",
globals.optimizer, sizeof(globals.optimizer), ODBCINST_INI);
// ConnSettings is stored in the driver section and per datasource for override
SQLGetPrivateProfileString(DBMS_NAME, INI_CONNSETTINGS, "",
globals.conn_settings, sizeof(globals.conn_settings), ODBCINST_INI);
}
/* This function writes any global parameters (that can be manipulated)
to the ODBCINST.INI portion of the registry
*/
void updateGlobals(void)
{
char tmp[128];
sprintf(tmp, "%d", globals.commlog);
SQLWritePrivateProfileString(DBMS_NAME,
INI_COMMLOG, tmp, ODBCINST_INI);
}
/* This is where the Driver Manager attaches to this Driver */
BOOL WINAPI DllMain(HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved)
{
WORD wVersionRequested;
WSADATA wsaData;
switch (ul_reason_for_call) {
case DLL_PROCESS_ATTACH:
s_hModule = hInst; /* Save for dialog boxes */
/* Load the WinSock Library */
wVersionRequested = MAKEWORD(1, 1);
if ( WSAStartup(wVersionRequested, &wsaData))
return FALSE;
/* Verify that this is the minimum version of WinSock */
if ( LOBYTE( wsaData.wVersion ) != 1 ||
HIBYTE( wsaData.wVersion ) != 1 ) {
WSACleanup();
return FALSE;
}
getGlobalDefaults();
break;
case DLL_THREAD_ATTACH:
break;
case DLL_PROCESS_DETACH:
WSACleanup();
return TRUE;
case DLL_THREAD_DETACH:
break;
default:
break;
}
return TRUE;
UNREFERENCED_PARAMETER(lpReserved);
}
/* 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
Driver Manager do this. Also, the ordinal values of the
functions must match the value of fFunction in SQLGetFunctions()
*/
RETCODE SQL_API SQLDummyOrdinal(void)
{
return SQL_SUCCESS;
}
LIBRARY psqlodbc
EXPORTS
SQLAllocConnect @1
SQLAllocEnv @2
SQLAllocStmt @3
SQLBindCol @4
SQLCancel @5
SQLColAttributes @6
SQLConnect @7
SQLDescribeCol @8
SQLDisconnect @9
SQLError @10
SQLExecDirect @11
SQLExecute @12
SQLFetch @13
SQLFreeConnect @14
SQLFreeEnv @15
SQLFreeStmt @16
SQLGetCursorName @17
SQLNumResultCols @18
SQLPrepare @19
SQLRowCount @20
SQLSetCursorName @21
SQLTransact @23
SQLColumns @40
SQLDriverConnect @41
SQLGetConnectOption @42
SQLGetData @43
SQLGetFunctions @44
SQLGetInfo @45
SQLGetStmtOption @46
SQLGetTypeInfo @47
SQLParamData @48
SQLPutData @49
SQLSetConnectOption @50
SQLSetStmtOption @51
SQLSpecialColumns @52
SQLStatistics @53
SQLTables @54
SQLBrowseConnect @55
SQLColumnPrivileges @56
SQLDescribeParam @58
SQLExtendedFetch @59
SQLForeignKeys @60
SQLMoreResults @61
SQLNativeSql @62
SQLNumParams @63
SQLParamOptions @64
SQLPrimaryKeys @65
SQLProcedureColumns @66
SQLProcedures @67
SQLSetPos @68
SQLSetScrollOptions @69
SQLTablePrivileges @70
SQLBindParameter @72
SQLDummyOrdinal @199
dconn_FDriverConnectProc @200
DllMain @201
ConfigDSN @202
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
//{{NO_DEPENDENCIES}}
// Microsoft Developer Studio generated include file.
// Used by psqlodbc.rc
//
#define IDS_BADDSN 1
#define IDS_MSGTITLE 2
#define DRIVERCONNDIALOG 101
#define IDC_DSNAME 400
#define IDC_DSNAMETEXT 401
#define IDC_DESC 404
#define IDC_SERVER 407
#define IDC_DATABASE 408
#define CONFIGDSN 1001
#define IDC_PORT 1002
#define IDC_USER 1006
#define IDC_PASSWORD 1009
#define IDC_READONLY 1011
#define READONLY_EDIT 1012
#define SAVEPASSWORD_EDIT 1013
#define IDC_COMMLOG 1014
#define COMMLOG_EDIT 1015
#define IDC_PG62 1016
#define PG62_EDIT 1017
#define SERVER_EDIT 1501
#define PORT_EDIT 1502
#define DATABASE_EDIT 1503
#define USERNAME_EDIT 1504
#define PASSWORD_EDIT 1505
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 102
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1018
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
/* File: tuple.h
*
* Description: See "tuple.c"
*
* Important NOTE: The TupleField structure is used both to hold backend data and
* manual result set data. The "set_" functions and the TupleNode
* structure are only used for manual result sets by info routines.
*
* Comments: See "notice.txt" for copyright and license information.
*
*/
#ifndef __TUPLE_H__
#define __TUPLE_H__
#include "psqlodbc.h"
/* Used by backend data AND manual result sets */
struct TupleField_ {
Int4 len; /* length of the current Tuple */
void *value; /* an array representing the value */
};
/* Used ONLY for manual result sets */
struct TupleNode_ {
struct TupleNode_ *prev, *next;
TupleField tuple[1];
};
/* These macros are wrappers for the corresponding set_tuplefield functions
but these handle automatic NULL determination and call set_tuplefield_null()
if appropriate for the datatype (used by SQLGetTypeInfo).
*/
#define set_nullfield_string(FLD, VAL) (VAL ? set_tuplefield_string(FLD, VAL) : set_tuplefield_null(FLD))
#define set_nullfield_int2(FLD, VAL) (VAL != -1 ? set_tuplefield_int2(FLD, VAL) : set_tuplefield_null(FLD))
#define set_nullfield_int4(FLD, VAL) (VAL != -1 ? set_tuplefield_int4(FLD, VAL) : set_tuplefield_null(FLD))
void set_tuplefield_null(TupleField *tuple_field);
void set_tuplefield_string(TupleField *tuple_field, char *string);
void set_tuplefield_int2(TupleField *tuple_field, Int2 value);
void set_tuplefield_int4(TupleField *tuple_field, Int4 value);
#endif
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment