Update odbc driver to current version V.0244
This commit is contained in:
parent
85f91d0e8e
commit
99d21d5b62
|
@ -1,17 +1,17 @@
|
||||||
|
|
||||||
/* Module: bind.c
|
/* Module: bind.c
|
||||||
*
|
*
|
||||||
* Description: This module contains routines related to binding
|
* Description: This module contains routines related to binding
|
||||||
* columns and parameters.
|
* columns and parameters.
|
||||||
*
|
*
|
||||||
* Classes: BindInfoClass, ParameterInfoClass
|
* Classes: BindInfoClass, ParameterInfoClass
|
||||||
*
|
*
|
||||||
* API functions: SQLBindParameter, SQLBindCol, SQLDescribeParam, SQLNumParams,
|
* API functions: SQLBindParameter, SQLBindCol, SQLDescribeParam, SQLNumParams,
|
||||||
* SQLParamOptions(NI)
|
* SQLParamOptions(NI)
|
||||||
*
|
*
|
||||||
* Comments: See "notice.txt" for copyright and license information.
|
* Comments: See "notice.txt" for copyright and license information.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
#include "bind.h"
|
#include "bind.h"
|
||||||
#include "environ.h"
|
#include "environ.h"
|
||||||
#include "statement.h"
|
#include "statement.h"
|
||||||
|
@ -19,8 +19,8 @@
|
||||||
#include "pgtypes.h"
|
#include "pgtypes.h"
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
#include <sql.h>
|
#include <sql.h>
|
||||||
#include <sqlext.h>
|
#include <sqlext.h>
|
||||||
|
|
||||||
// Bind parameters on a statement handle
|
// Bind parameters on a statement handle
|
||||||
|
|
||||||
|
@ -77,10 +77,11 @@ StatementClass *stmt = (StatementClass *) hstmt;
|
||||||
stmt->parameters[i].CType = 0;
|
stmt->parameters[i].CType = 0;
|
||||||
stmt->parameters[i].SQLType = 0;
|
stmt->parameters[i].SQLType = 0;
|
||||||
stmt->parameters[i].precision = 0;
|
stmt->parameters[i].precision = 0;
|
||||||
stmt->parameters[i].scale = 0;
|
stmt->parameters[i].scale = 0;
|
||||||
stmt->parameters[i].data_at_exec = FALSE;
|
stmt->parameters[i].data_at_exec = FALSE;
|
||||||
stmt->parameters[i].EXEC_used = NULL;
|
stmt->parameters[i].lobj_oid = 0;
|
||||||
stmt->parameters[i].EXEC_buffer = NULL;
|
stmt->parameters[i].EXEC_used = NULL;
|
||||||
|
stmt->parameters[i].EXEC_buffer = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,26 +95,28 @@ StatementClass *stmt = (StatementClass *) hstmt;
|
||||||
stmt->parameters[ipar].CType = fCType;
|
stmt->parameters[ipar].CType = fCType;
|
||||||
stmt->parameters[ipar].SQLType = fSqlType;
|
stmt->parameters[ipar].SQLType = fSqlType;
|
||||||
stmt->parameters[ipar].precision = cbColDef;
|
stmt->parameters[ipar].precision = cbColDef;
|
||||||
stmt->parameters[ipar].scale = ibScale;
|
stmt->parameters[ipar].scale = ibScale;
|
||||||
|
|
||||||
/* If rebinding a parameter that had data-at-exec stuff in it,
|
/* If rebinding a parameter that had data-at-exec stuff in it,
|
||||||
then free that stuff
|
then free that stuff
|
||||||
*/
|
*/
|
||||||
if (stmt->parameters[ipar].EXEC_used) {
|
if (stmt->parameters[ipar].EXEC_used) {
|
||||||
free(stmt->parameters[ipar].EXEC_used);
|
free(stmt->parameters[ipar].EXEC_used);
|
||||||
stmt->parameters[ipar].EXEC_used = NULL;
|
stmt->parameters[ipar].EXEC_used = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stmt->parameters[ipar].EXEC_buffer) {
|
if (stmt->parameters[ipar].EXEC_buffer) {
|
||||||
free(stmt->parameters[ipar].EXEC_buffer);
|
free(stmt->parameters[ipar].EXEC_buffer);
|
||||||
stmt->parameters[ipar].EXEC_buffer = NULL;
|
stmt->parameters[ipar].EXEC_buffer = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pcbValue && *pcbValue <= SQL_LEN_DATA_AT_EXEC_OFFSET)
|
if (pcbValue && *pcbValue <= SQL_LEN_DATA_AT_EXEC_OFFSET)
|
||||||
stmt->parameters[ipar].data_at_exec = TRUE;
|
stmt->parameters[ipar].data_at_exec = TRUE;
|
||||||
else
|
else
|
||||||
stmt->parameters[ipar].data_at_exec = FALSE;
|
stmt->parameters[ipar].data_at_exec = FALSE;
|
||||||
|
|
||||||
|
mylog("SQLBindParamater: ipar = %d, *pcbValue = %d, data_at_exec = %d\n",
|
||||||
|
ipar, pcbValue ? *pcbValue: -777, stmt->parameters[ipar].data_at_exec);
|
||||||
|
|
||||||
return SQL_SUCCESS;
|
return SQL_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -188,6 +191,8 @@ mylog("**** SQLBindCol: stmt = %u, icol = %d\n", stmt, icol);
|
||||||
stmt->bindings[icol].buffer = rgbValue;
|
stmt->bindings[icol].buffer = rgbValue;
|
||||||
stmt->bindings[icol].used = pcbValue;
|
stmt->bindings[icol].used = pcbValue;
|
||||||
stmt->bindings[icol].returntype = fCType;
|
stmt->bindings[icol].returntype = fCType;
|
||||||
|
|
||||||
|
mylog(" bound buffer[%d] = %u\n", icol, stmt->bindings[icol].buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
return SQL_SUCCESS;
|
return SQL_SUCCESS;
|
||||||
|
@ -228,7 +233,7 @@ StatementClass *stmt = (StatementClass *) hstmt;
|
||||||
*pibScale = stmt->parameters[ipar].scale;
|
*pibScale = stmt->parameters[ipar].scale;
|
||||||
|
|
||||||
if(pfNullable)
|
if(pfNullable)
|
||||||
*pfNullable = pgtype_nullable(stmt->parameters[ipar].paramType);
|
*pfNullable = pgtype_nullable(stmt, stmt->parameters[ipar].paramType);
|
||||||
|
|
||||||
return SQL_SUCCESS;
|
return SQL_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -247,37 +252,25 @@ RETCODE SQL_API SQLParamOptions(
|
||||||
|
|
||||||
// - - - - - - - - -
|
// - - - - - - - - -
|
||||||
|
|
||||||
// Returns the number of parameter markers.
|
// Returns the number of parameters in an SQL statement
|
||||||
|
|
||||||
RETCODE SQL_API SQLNumParams(
|
RETCODE SQL_API SQLNumParams(
|
||||||
HSTMT hstmt,
|
HSTMT hstmt,
|
||||||
SWORD FAR *pcpar)
|
SWORD FAR *pcpar)
|
||||||
{
|
{
|
||||||
StatementClass *stmt = (StatementClass *) hstmt;
|
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)
|
if(!stmt)
|
||||||
return SQL_INVALID_HANDLE;
|
return SQL_INVALID_HANDLE;
|
||||||
|
|
||||||
if(!stmt->statement) {
|
// If the statement does not have parameters, it should just return 0.
|
||||||
// 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;
|
if (pcpar) {
|
||||||
|
*pcpar = stmt->parameters_allocated;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return SQL_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/********************************************************************
|
/********************************************************************
|
||||||
|
@ -309,7 +302,7 @@ extend_bindings(StatementClass *stmt, int num_columns)
|
||||||
BindInfoClass *new_bindings;
|
BindInfoClass *new_bindings;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
mylog("in extend_bindings\n");
|
mylog("in extend_bindings: stmt=%u, bindings_allocated=%d, num_columns=%d\n", stmt, stmt->bindings_allocated, num_columns);
|
||||||
|
|
||||||
/* if we have too few, allocate room for more, and copy the old */
|
/* if we have too few, allocate room for more, and copy the old */
|
||||||
/* entries into the new structure */
|
/* entries into the new structure */
|
||||||
|
@ -325,6 +318,7 @@ int i;
|
||||||
}
|
}
|
||||||
|
|
||||||
stmt->bindings = new_bindings; // null indicates error
|
stmt->bindings = new_bindings; // null indicates error
|
||||||
|
stmt->bindings_allocated = num_columns;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
/* if we have too many, make sure the extra ones are emptied out */
|
/* if we have too many, make sure the extra ones are emptied out */
|
||||||
|
|
|
@ -1,20 +1,20 @@
|
||||||
|
|
||||||
/* File: bind.h
|
/* File: bind.h
|
||||||
*
|
*
|
||||||
* Description: See "bind.c"
|
* Description: See "bind.c"
|
||||||
*
|
*
|
||||||
* Comments: See "notice.txt" for copyright and license information.
|
* Comments: See "notice.txt" for copyright and license information.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __BIND_H__
|
#ifndef __BIND_H__
|
||||||
#define __BIND_H__
|
#define __BIND_H__
|
||||||
|
|
||||||
#include "psqlodbc.h"
|
#include "psqlodbc.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* BindInfoClass -- stores information about a bound column
|
* BindInfoClass -- stores information about a bound column
|
||||||
*/
|
*/
|
||||||
struct BindInfoClass_ {
|
struct BindInfoClass_ {
|
||||||
Int4 buflen; /* size of buffer */
|
Int4 buflen; /* size of buffer */
|
||||||
char *buffer; /* pointer to the buffer */
|
char *buffer; /* pointer to the buffer */
|
||||||
|
@ -33,10 +33,11 @@ struct ParameterInfoClass_ {
|
||||||
Int2 CType;
|
Int2 CType;
|
||||||
Int2 SQLType;
|
Int2 SQLType;
|
||||||
UInt4 precision;
|
UInt4 precision;
|
||||||
Int2 scale;
|
Int2 scale;
|
||||||
Int4 *EXEC_used;
|
Oid lobj_oid;
|
||||||
char *EXEC_buffer;
|
Int4 *EXEC_used; /* amount of data OR the oid of the large object */
|
||||||
char data_at_exec;
|
char *EXEC_buffer; /* the data or the FD of the large object */
|
||||||
|
char data_at_exec;
|
||||||
};
|
};
|
||||||
|
|
||||||
BindInfoClass *create_empty_bindings(int num_columns);
|
BindInfoClass *create_empty_bindings(int num_columns);
|
||||||
|
|
|
@ -1,18 +1,18 @@
|
||||||
|
|
||||||
/* 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"
|
/* 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 "socket.h"
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
|
@ -29,6 +29,7 @@ ColumnInfoClass *rv;
|
||||||
rv->name = NULL;
|
rv->name = NULL;
|
||||||
rv->adtid = NULL;
|
rv->adtid = NULL;
|
||||||
rv->adtsize = NULL;
|
rv->adtsize = NULL;
|
||||||
|
rv->display_size = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return rv;
|
return rv;
|
||||||
|
@ -54,7 +55,7 @@ int new_num_fields;
|
||||||
Oid new_adtid;
|
Oid new_adtid;
|
||||||
Int2 new_adtsize;
|
Int2 new_adtsize;
|
||||||
char new_field_name[MAX_MESSAGE_LEN+1];
|
char new_field_name[MAX_MESSAGE_LEN+1];
|
||||||
|
|
||||||
|
|
||||||
/* at first read in the number of fields that are in the query */
|
/* at first read in the number of fields that are in the query */
|
||||||
new_num_fields = (Int2) SOCK_get_int(sock, sizeof(Int2));
|
new_num_fields = (Int2) SOCK_get_int(sock, sizeof(Int2));
|
||||||
|
@ -93,11 +94,12 @@ int num_fields = self->num_fields;
|
||||||
if( self->name[lf])
|
if( self->name[lf])
|
||||||
free (self->name[lf]);
|
free (self->name[lf]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Safe to call even if null */
|
/* Safe to call even if null */
|
||||||
free(self->name);
|
free(self->name);
|
||||||
free(self->adtid);
|
free(self->adtid);
|
||||||
free(self->adtsize);
|
free(self->adtsize);
|
||||||
|
free(self->display_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -110,6 +112,7 @@ CI_set_num_fields(ColumnInfoClass *self, int new_num_fields)
|
||||||
self->name = (char **) malloc (sizeof(char *) * self->num_fields);
|
self->name = (char **) malloc (sizeof(char *) * self->num_fields);
|
||||||
self->adtid = (Oid *) malloc (sizeof(Oid) * self->num_fields);
|
self->adtid = (Oid *) malloc (sizeof(Oid) * self->num_fields);
|
||||||
self->adtsize = (Int2 *) malloc (sizeof(Int2) * self->num_fields);
|
self->adtsize = (Int2 *) malloc (sizeof(Int2) * self->num_fields);
|
||||||
|
self->display_size = (Int2 *) malloc(sizeof(Int2) * self->num_fields);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -126,34 +129,7 @@ CI_set_field_info(ColumnInfoClass *self, int field_num, char *new_name,
|
||||||
self->name[field_num] = strdup(new_name);
|
self->name[field_num] = strdup(new_name);
|
||||||
self->adtid[field_num] = new_adtid;
|
self->adtid[field_num] = new_adtid;
|
||||||
self->adtsize[field_num] = new_adtsize;
|
self->adtsize[field_num] = new_adtsize;
|
||||||
}
|
|
||||||
|
self->display_size[field_num] = 0;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
|
|
||||||
/* File: columninfo.h
|
/* File: columninfo.h
|
||||||
*
|
*
|
||||||
* Description: See "columninfo.c"
|
* Description: See "columninfo.c"
|
||||||
*
|
*
|
||||||
* Comments: See "notice.txt" for copyright and license information.
|
* Comments: See "notice.txt" for copyright and license information.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __COLUMNINFO_H__
|
#ifndef __COLUMNINFO_H__
|
||||||
#define __COLUMNINFO_H__
|
#define __COLUMNINFO_H__
|
||||||
|
@ -17,14 +17,18 @@ struct ColumnInfoClass_ {
|
||||||
char **name; /* list of type names */
|
char **name; /* list of type names */
|
||||||
Oid *adtid; /* list of type ids */
|
Oid *adtid; /* list of type ids */
|
||||||
Int2 *adtsize; /* list type sizes */
|
Int2 *adtsize; /* list type sizes */
|
||||||
|
Int2 *display_size; /* the display size (longest row) */
|
||||||
};
|
};
|
||||||
|
|
||||||
#define CI_get_num_fields(self) (self->num_fields)
|
#define CI_get_num_fields(self) (self->num_fields)
|
||||||
#define CI_get_oid(self, col) (self->adtid[col])
|
#define CI_get_oid(self, col) (self->adtid[col])
|
||||||
|
#define CI_get_fieldname(self, col) (self->name[col])
|
||||||
|
#define CI_get_fieldsize(self, col) (self->adtsize[col])
|
||||||
|
#define CI_get_display_size(self, col) (self->display_size[col])
|
||||||
|
|
||||||
ColumnInfoClass *CI_Constructor();
|
ColumnInfoClass *CI_Constructor();
|
||||||
void CI_Destructor(ColumnInfoClass *self);
|
void CI_Destructor(ColumnInfoClass *self);
|
||||||
|
void CI_free_memory(ColumnInfoClass *self);
|
||||||
char CI_read_fields(ColumnInfoClass *self, SocketClass *sock);
|
char CI_read_fields(ColumnInfoClass *self, SocketClass *sock);
|
||||||
|
|
||||||
/* functions for setting up the fields from within the program, */
|
/* functions for setting up the fields from within the program, */
|
||||||
|
@ -33,8 +37,5 @@ void CI_set_num_fields(ColumnInfoClass *self, int new_num_fields);
|
||||||
void CI_set_field_info(ColumnInfoClass *self, int field_num, char *new_name,
|
void CI_set_field_info(ColumnInfoClass *self, int field_num, char *new_name,
|
||||||
Oid new_adtid, Int2 new_adtsize);
|
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
|
#endif
|
||||||
|
|
|
@ -1,30 +1,33 @@
|
||||||
|
|
||||||
/* Module: connection.c
|
/* Module: connection.c
|
||||||
*
|
*
|
||||||
* Description: This module contains routines related to
|
* Description: This module contains routines related to
|
||||||
* connecting to and disconnecting from the Postgres DBMS.
|
* connecting to and disconnecting from the Postgres DBMS.
|
||||||
*
|
*
|
||||||
* Classes: ConnectionClass (Functions prefix: "CC_")
|
* Classes: ConnectionClass (Functions prefix: "CC_")
|
||||||
*
|
*
|
||||||
* API functions: SQLAllocConnect, SQLConnect, SQLDisconnect, SQLFreeConnect,
|
* API functions: SQLAllocConnect, SQLConnect, SQLDisconnect, SQLFreeConnect,
|
||||||
* SQLBrowseConnect(NI)
|
* SQLBrowseConnect(NI)
|
||||||
*
|
*
|
||||||
* Comments: See "notice.txt" for copyright and license information.
|
* Comments: See "notice.txt" for copyright and license information.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "environ.h"
|
#include "environ.h"
|
||||||
#include "connection.h"
|
#include "connection.h"
|
||||||
#include "socket.h"
|
#include "socket.h"
|
||||||
#include "statement.h"
|
#include "statement.h"
|
||||||
#include "qresult.h"
|
#include "qresult.h"
|
||||||
|
#include "lobj.h"
|
||||||
|
#include "dlg_specific.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <odbcinst.h>
|
#include <odbcinst.h>
|
||||||
|
|
||||||
#define STMT_INCREMENT 16 /* how many statement holders to allocate at a time */
|
#define STMT_INCREMENT 16 /* how many statement holders to allocate at a time */
|
||||||
|
|
||||||
extern GLOBAL_VALUES globals;
|
extern GLOBAL_VALUES globals;
|
||||||
|
|
||||||
|
// void CC_test(ConnectionClass *self);
|
||||||
|
|
||||||
RETCODE SQL_API SQLAllocConnect(
|
RETCODE SQL_API SQLAllocConnect(
|
||||||
HENV henv,
|
HENV henv,
|
||||||
|
@ -70,25 +73,28 @@ RETCODE SQL_API SQLConnect(
|
||||||
SWORD cbAuthStr)
|
SWORD cbAuthStr)
|
||||||
{
|
{
|
||||||
ConnectionClass *conn = (ConnectionClass *) hdbc;
|
ConnectionClass *conn = (ConnectionClass *) hdbc;
|
||||||
|
ConnInfo *ci;
|
||||||
|
|
||||||
if ( ! conn)
|
if ( ! conn)
|
||||||
return SQL_INVALID_HANDLE;
|
return SQL_INVALID_HANDLE;
|
||||||
|
|
||||||
make_string(szDSN, cbDSN, conn->connInfo.dsn);
|
ci = &conn->connInfo;
|
||||||
|
|
||||||
|
make_string(szDSN, cbDSN, ci->dsn);
|
||||||
|
|
||||||
/* get the values for the DSN from the registry */
|
/* get the values for the DSN from the registry */
|
||||||
CC_DSN_info(conn, CONN_OVERWRITE);
|
getDSNinfo(ci, CONN_OVERWRITE);
|
||||||
|
|
||||||
/* override values from DSN info with UID and authStr(pwd)
|
/* override values from DSN info with UID and authStr(pwd)
|
||||||
This only occurs if the values are actually there.
|
This only occurs if the values are actually there.
|
||||||
*/
|
*/
|
||||||
make_string(szUID, cbUID, conn->connInfo.username);
|
make_string(szUID, cbUID, ci->username);
|
||||||
make_string(szAuthStr, cbAuthStr, conn->connInfo.password);
|
make_string(szAuthStr, cbAuthStr, ci->password);
|
||||||
|
|
||||||
/* fill in any defaults */
|
/* fill in any defaults */
|
||||||
CC_set_defaults(conn);
|
getDSNdefaults(ci);
|
||||||
|
|
||||||
qlog("conn = %u, SQLConnect(DSN='%s', UID='%s', PWD='%s')\n", conn->connInfo.dsn, conn->connInfo.username, conn->connInfo.password);
|
qlog("conn = %u, SQLConnect(DSN='%s', UID='%s', PWD='%s')\n", ci->dsn, ci->username, ci->password);
|
||||||
|
|
||||||
if ( CC_connect(conn, FALSE) <= 0)
|
if ( CC_connect(conn, FALSE) <= 0)
|
||||||
// Error messages are filled in
|
// Error messages are filled in
|
||||||
|
@ -124,12 +130,12 @@ ConnectionClass *conn = (ConnectionClass *) hdbc;
|
||||||
return SQL_INVALID_HANDLE;
|
return SQL_INVALID_HANDLE;
|
||||||
|
|
||||||
qlog("conn=%u, SQLDisconnect\n", conn);
|
qlog("conn=%u, SQLDisconnect\n", conn);
|
||||||
|
|
||||||
if (conn->status == CONN_EXECUTING) {
|
if (conn->status == CONN_EXECUTING) {
|
||||||
conn->errornumber = CONN_IN_USE;
|
conn->errornumber = CONN_IN_USE;
|
||||||
conn->errormsg = "A transaction is currently being executed";
|
conn->errormsg = "A transaction is currently being executed";
|
||||||
return SQL_ERROR;
|
return SQL_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
mylog("SQLDisconnect: about to CC_cleanup\n");
|
mylog("SQLDisconnect: about to CC_cleanup\n");
|
||||||
|
|
||||||
|
@ -155,12 +161,12 @@ ConnectionClass *conn = (ConnectionClass *) hdbc;
|
||||||
if ( ! conn)
|
if ( ! conn)
|
||||||
return SQL_INVALID_HANDLE;
|
return SQL_INVALID_HANDLE;
|
||||||
|
|
||||||
/* Remove the connection from the environment */
|
/* Remove the connection from the environment */
|
||||||
if ( ! EN_remove_connection(conn->henv, conn)) {
|
if ( ! EN_remove_connection(conn->henv, conn)) {
|
||||||
conn->errornumber = CONN_IN_USE;
|
conn->errornumber = CONN_IN_USE;
|
||||||
conn->errormsg = "A transaction is currently being executed";
|
conn->errormsg = "A transaction is currently being executed";
|
||||||
return SQL_ERROR;
|
return SQL_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
CC_Destructor(conn);
|
CC_Destructor(conn);
|
||||||
|
|
||||||
|
@ -207,6 +213,7 @@ ConnectionClass *rv;
|
||||||
|
|
||||||
rv->num_stmts = STMT_INCREMENT;
|
rv->num_stmts = STMT_INCREMENT;
|
||||||
|
|
||||||
|
rv->lobj_type = PG_TYPE_LO;
|
||||||
}
|
}
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
@ -239,6 +246,26 @@ CC_Destructor(ConnectionClass *self)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Return how many cursors are opened on this connection */
|
||||||
|
int
|
||||||
|
CC_cursor_count(ConnectionClass *self)
|
||||||
|
{
|
||||||
|
StatementClass *stmt;
|
||||||
|
int i, count = 0;
|
||||||
|
|
||||||
|
mylog("CC_cursor_count: self=%u, num_stmts=%d\n", self, self->num_stmts);
|
||||||
|
|
||||||
|
for (i = 0; i < self->num_stmts; i++) {
|
||||||
|
stmt = self->stmts[i];
|
||||||
|
if (stmt && stmt->result && stmt->result->cursor)
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
mylog("CC_cursor_count: returning %d\n", count);
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CC_clear_error(ConnectionClass *self)
|
CC_clear_error(ConnectionClass *self)
|
||||||
{
|
{
|
||||||
|
@ -316,75 +343,12 @@ StatementClass *stmt;
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
CC_set_defaults(ConnectionClass *self)
|
|
||||||
{
|
|
||||||
ConnInfo *ci = &(self->connInfo);
|
|
||||||
|
|
||||||
if (ci->port[0] == '\0')
|
|
||||||
strcpy(ci->port, DEFAULT_PORT);
|
|
||||||
|
|
||||||
if (ci->readonly[0] == '\0')
|
|
||||||
strcpy(ci->readonly, DEFAULT_READONLY);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CC_DSN_info(ConnectionClass *self, char overwrite)
|
|
||||||
{
|
|
||||||
ConnInfo *ci = &(self->connInfo);
|
|
||||||
char *DSN = ci->dsn;
|
|
||||||
|
|
||||||
// If a driver keyword was present, then dont use a DSN and return.
|
|
||||||
// If DSN is null and no driver, then use the default datasource.
|
|
||||||
if ( DSN[0] == '\0') {
|
|
||||||
if ( ci->driver[0] != '\0')
|
|
||||||
return;
|
|
||||||
else
|
|
||||||
strcpy(DSN, "DEFAULT");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Proceed with getting info for the given DSN.
|
|
||||||
if ( ci->server[0] == '\0' || overwrite)
|
|
||||||
SQLGetPrivateProfileString(DSN, INI_SERVER, "", ci->server, sizeof(ci->server), ODBC_INI);
|
|
||||||
|
|
||||||
if ( ci->database[0] == '\0' || overwrite)
|
|
||||||
SQLGetPrivateProfileString(DSN, INI_DATABASE, "", ci->database, sizeof(ci->database), ODBC_INI);
|
|
||||||
|
|
||||||
if ( ci->username[0] == '\0' || overwrite)
|
|
||||||
SQLGetPrivateProfileString(DSN, INI_USER, "", ci->username, sizeof(ci->username), ODBC_INI);
|
|
||||||
|
|
||||||
if ( ci->password[0] == '\0' || overwrite)
|
|
||||||
SQLGetPrivateProfileString(DSN, INI_PASSWORD, "", ci->password, sizeof(ci->password), ODBC_INI);
|
|
||||||
|
|
||||||
if ( ci->port[0] == '\0' || overwrite)
|
|
||||||
SQLGetPrivateProfileString(DSN, INI_PORT, "", ci->port, sizeof(ci->port), ODBC_INI);
|
|
||||||
|
|
||||||
if ( ci->readonly[0] == '\0' || overwrite)
|
|
||||||
SQLGetPrivateProfileString(DSN, INI_READONLY, "", ci->readonly, sizeof(ci->readonly), ODBC_INI);
|
|
||||||
|
|
||||||
if ( ci->protocol[0] == '\0' || overwrite)
|
|
||||||
SQLGetPrivateProfileString(DSN, INI_PROTOCOL, "", ci->protocol, sizeof(ci->protocol), ODBC_INI);
|
|
||||||
|
|
||||||
if ( ci->conn_settings[0] == '\0' || overwrite)
|
|
||||||
SQLGetPrivateProfileString(DSN, INI_CONNSETTINGS, "", ci->conn_settings, sizeof(ci->conn_settings), ODBC_INI);
|
|
||||||
|
|
||||||
qlog("conn=%u, DSN info(DSN='%s',server='%s',dbase='%s',user='%s',passwd='%s',port='%s',readonly='%s',protocol='%s',conn_settings='%s')\n",
|
|
||||||
self, DSN,
|
|
||||||
ci->server,
|
|
||||||
ci->database,
|
|
||||||
ci->username,
|
|
||||||
ci->password,
|
|
||||||
ci->port,
|
|
||||||
ci->readonly,
|
|
||||||
ci->protocol,
|
|
||||||
ci->conn_settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
char
|
char
|
||||||
CC_connect(ConnectionClass *self, char do_password)
|
CC_connect(ConnectionClass *self, char do_password)
|
||||||
{
|
{
|
||||||
StartupPacket sp;
|
StartupPacket sp;
|
||||||
StartupPacket6_2 sp62;
|
StartupPacket6_2 sp62;
|
||||||
QResultClass *res;
|
QResultClass *res;
|
||||||
SocketClass *sock;
|
SocketClass *sock;
|
||||||
|
@ -392,7 +356,7 @@ ConnInfo *ci = &(self->connInfo);
|
||||||
int areq = -1;
|
int areq = -1;
|
||||||
int beresp;
|
int beresp;
|
||||||
char msgbuffer[ERROR_MSG_LENGTH];
|
char msgbuffer[ERROR_MSG_LENGTH];
|
||||||
char salt[2];
|
char salt[2];
|
||||||
|
|
||||||
if ( do_password)
|
if ( do_password)
|
||||||
|
|
||||||
|
@ -400,6 +364,24 @@ char salt[2];
|
||||||
|
|
||||||
else {
|
else {
|
||||||
|
|
||||||
|
qlog("Global Options: fetch=%d, socket=%d, unknown_sizes=%d, max_varchar_size=%d, max_longvarchar_size=%d\n",
|
||||||
|
globals.fetch_max,
|
||||||
|
globals.socket_buffersize,
|
||||||
|
globals.unknown_sizes,
|
||||||
|
globals.max_varchar_size,
|
||||||
|
globals.max_longvarchar_size);
|
||||||
|
qlog(" disable_optimizer=%d, unique_index=%d, use_declarefetch=%d\n",
|
||||||
|
globals.disable_optimizer,
|
||||||
|
globals.unique_index,
|
||||||
|
globals.use_declarefetch);
|
||||||
|
qlog(" text_as_longvarchar=%d, unknowns_as_longvarchar=%d, bools_as_char=%d\n",
|
||||||
|
globals.text_as_longvarchar,
|
||||||
|
globals.unknowns_as_longvarchar,
|
||||||
|
globals.bools_as_char);
|
||||||
|
qlog(" extra_systable_prefixes='%s', conn_settings='%s'\n",
|
||||||
|
globals.extra_systable_prefixes,
|
||||||
|
globals.conn_settings);
|
||||||
|
|
||||||
if (self->status != CONN_NOT_CONNECTED) {
|
if (self->status != CONN_NOT_CONNECTED) {
|
||||||
self->errormsg = "Already connected.";
|
self->errormsg = "Already connected.";
|
||||||
self->errornumber = CONN_OPENDB_ERROR;
|
self->errornumber = CONN_OPENDB_ERROR;
|
||||||
|
@ -439,18 +421,18 @@ char salt[2];
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
mylog("connection to the server socket succeeded.\n");
|
mylog("connection to the server socket succeeded.\n");
|
||||||
|
|
||||||
if ( PROTOCOL_62(ci)) {
|
if ( PROTOCOL_62(ci)) {
|
||||||
sock->reverse = TRUE; /* make put_int and get_int work for 6.2 */
|
sock->reverse = TRUE; /* make put_int and get_int work for 6.2 */
|
||||||
|
|
||||||
memset(&sp62, 0, sizeof(StartupPacket6_2));
|
memset(&sp62, 0, sizeof(StartupPacket6_2));
|
||||||
SOCK_put_int(sock, htonl(4+sizeof(StartupPacket6_2)), 4);
|
SOCK_put_int(sock, htonl(4+sizeof(StartupPacket6_2)), 4);
|
||||||
sp62.authtype = htonl(NO_AUTHENTICATION);
|
sp62.authtype = htonl(NO_AUTHENTICATION);
|
||||||
strncpy(sp62.database, ci->database, PATH_SIZE);
|
strncpy(sp62.database, ci->database, PATH_SIZE);
|
||||||
strncpy(sp62.user, ci->username, NAMEDATALEN);
|
strncpy(sp62.user, ci->username, NAMEDATALEN);
|
||||||
SOCK_put_n_char(sock, (char *) &sp62, sizeof(StartupPacket6_2));
|
SOCK_put_n_char(sock, (char *) &sp62, sizeof(StartupPacket6_2));
|
||||||
SOCK_flush_output(sock);
|
SOCK_flush_output(sock);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
memset(&sp, 0, sizeof(StartupPacket));
|
memset(&sp, 0, sizeof(StartupPacket));
|
||||||
|
|
||||||
|
@ -465,7 +447,7 @@ char salt[2];
|
||||||
|
|
||||||
SOCK_put_n_char(sock, (char *) &sp, sizeof(StartupPacket));
|
SOCK_put_n_char(sock, (char *) &sp, sizeof(StartupPacket));
|
||||||
SOCK_flush_output(sock);
|
SOCK_flush_output(sock);
|
||||||
}
|
}
|
||||||
|
|
||||||
mylog("sent the authentication block.\n");
|
mylog("sent the authentication block.\n");
|
||||||
|
|
||||||
|
@ -484,9 +466,9 @@ char salt[2];
|
||||||
|
|
||||||
// ***************************************************
|
// ***************************************************
|
||||||
// Now get the authentication request from backend
|
// Now get the authentication request from backend
|
||||||
// ***************************************************
|
// ***************************************************
|
||||||
|
|
||||||
if ( ! PROTOCOL_62(ci)) do {
|
if ( ! PROTOCOL_62(ci)) do {
|
||||||
|
|
||||||
if (do_password)
|
if (do_password)
|
||||||
beresp = 'R';
|
beresp = 'R';
|
||||||
|
@ -590,15 +572,19 @@ char salt[2];
|
||||||
|
|
||||||
mylog("empty query seems to be OK.\n");
|
mylog("empty query seems to be OK.\n");
|
||||||
|
|
||||||
|
|
||||||
/**********************************************/
|
|
||||||
/******* Send any initial settings *********/
|
|
||||||
/**********************************************/
|
|
||||||
|
|
||||||
CC_send_settings(self);
|
|
||||||
|
|
||||||
|
|
||||||
CC_clear_error(self); /* clear any initial command errors */
|
/**********************************************/
|
||||||
|
/******* Send any initial settings *********/
|
||||||
|
/**********************************************/
|
||||||
|
|
||||||
|
if ( ! CC_send_settings(self))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
CC_lookup_lo(self); /* a hack to get the oid of our large object oid type */
|
||||||
|
|
||||||
|
// CC_test(self);
|
||||||
|
|
||||||
|
CC_clear_error(self); /* clear any initial command errors */
|
||||||
self->status = CONN_CONNECTED;
|
self->status = CONN_CONNECTED;
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -650,8 +636,8 @@ int i;
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create a more informative error message by concatenating the connection
|
/* Create a more informative error message by concatenating the connection
|
||||||
error message with its socket error message.
|
error message with its socket error message.
|
||||||
*/
|
*/
|
||||||
char *
|
char *
|
||||||
CC_create_errormsg(ConnectionClass *self)
|
CC_create_errormsg(ConnectionClass *self)
|
||||||
|
@ -705,14 +691,14 @@ int rv;
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* The "result_in" is only used by QR_next_tuple() to fetch another group of rows into
|
/* The "result_in" is only used by QR_next_tuple() to fetch another group of rows into
|
||||||
the same existing QResultClass (this occurs when the tuple cache is depleted and
|
the same existing QResultClass (this occurs when the tuple cache is depleted and
|
||||||
needs to be re-filled).
|
needs to be re-filled).
|
||||||
|
|
||||||
The "cursor" is used by SQLExecute to associate a statement handle as the cursor name
|
The "cursor" is used by SQLExecute to associate a statement handle as the cursor name
|
||||||
(i.e., C3326857) for SQL select statements. This cursor is then used in future
|
(i.e., C3326857) for SQL select statements. This cursor is then used in future
|
||||||
'declare cursor C3326857 for ...' and 'fetch 100 in C3326857' statements.
|
'declare cursor C3326857 for ...' and 'fetch 100 in C3326857' statements.
|
||||||
*/
|
*/
|
||||||
QResultClass *
|
QResultClass *
|
||||||
CC_send_query(ConnectionClass *self, char *query, QResultClass *result_in, char *cursor)
|
CC_send_query(ConnectionClass *self, char *query, QResultClass *result_in, char *cursor)
|
||||||
|
@ -822,9 +808,16 @@ char cmdbuffer[MAX_MESSAGE_LEN+1]; // QR_set_command() dups this string so dont
|
||||||
SOCK_put_string(sock, "Q ");
|
SOCK_put_string(sock, "Q ");
|
||||||
SOCK_flush_output(sock);
|
SOCK_flush_output(sock);
|
||||||
while(!clear) {
|
while(!clear) {
|
||||||
SOCK_get_string(sock, cmdbuffer, ERROR_MSG_LENGTH);
|
SOCK_get_string(sock, cmdbuffer, ERROR_MSG_LENGTH);
|
||||||
mylog("send_query: read command '%s'\n", cmdbuffer);
|
mylog("send_query: read command '%s'\n", cmdbuffer);
|
||||||
clear = (cmdbuffer[0] == 'I');
|
clear = (cmdbuffer[0] == 'I');
|
||||||
|
|
||||||
|
if (cmdbuffer[0] == 'N')
|
||||||
|
qlog("NOTICE from backend during send_query: '%s'\n", &cmdbuffer[1]);
|
||||||
|
else if (cmdbuffer[0] == 'E')
|
||||||
|
qlog("ERROR from backend during send_query: '%s'\n", &cmdbuffer[1]);
|
||||||
|
else if (cmdbuffer[0] == 'C')
|
||||||
|
qlog("Command response: '%s'\n", &cmdbuffer[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
mylog("send_query: returning res = %u\n", res);
|
mylog("send_query: returning res = %u\n", res);
|
||||||
|
@ -925,55 +918,270 @@ char cmdbuffer[MAX_MESSAGE_LEN+1]; // QR_set_command() dups this string so dont
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
char
|
int
|
||||||
CC_send_settings(ConnectionClass *self)
|
CC_send_function(ConnectionClass *self, int fnid, void *result_buf, int *actual_result_len, int result_is_int, LO_ARG *args, int nargs)
|
||||||
{
|
{
|
||||||
char ini_query[MAX_MESSAGE_LEN];
|
char id, c, done;
|
||||||
ConnInfo *ci = &(self->connInfo);
|
SocketClass *sock = self->sock;
|
||||||
QResultClass *res;
|
static char msgbuffer[MAX_MESSAGE_LEN+1];
|
||||||
|
int i;
|
||||||
ini_query[0] = '\0';
|
|
||||||
|
mylog("send_function(): conn=%u, fnid=%d, result_is_int=%d, nargs=%d\n", self, fnid, result_is_int, nargs);
|
||||||
/* Turn on/off genetic optimizer based on global flag */
|
// qlog("conn=%u, func=%d\n", self, fnid);
|
||||||
if (globals.optimizer[0] != '\0')
|
|
||||||
sprintf(ini_query, "set geqo to '%s'", globals.optimizer);
|
if (SOCK_get_errcode(sock) != 0) {
|
||||||
|
self->errornumber = CONNECTION_COULD_NOT_SEND;
|
||||||
/* Global settings */
|
self->errormsg = "Could not send function to backend";
|
||||||
if (globals.conn_settings[0] != '\0')
|
CC_set_no_trans(self);
|
||||||
sprintf(&ini_query[strlen(ini_query)], "%s%s",
|
return FALSE;
|
||||||
ini_query[0] != '\0' ? "; " : "",
|
}
|
||||||
globals.conn_settings);
|
|
||||||
|
SOCK_put_string(sock, "F ");
|
||||||
/* Per Datasource settings */
|
if (SOCK_get_errcode(sock) != 0) {
|
||||||
if (ci->conn_settings[0] != '\0')
|
self->errornumber = CONNECTION_COULD_NOT_SEND;
|
||||||
sprintf(&ini_query[strlen(ini_query)], "%s%s",
|
self->errormsg = "Could not send function to backend";
|
||||||
ini_query[0] != '\0' ? "; " : "",
|
CC_set_no_trans(self);
|
||||||
ci->conn_settings);
|
return FALSE;
|
||||||
|
}
|
||||||
if (ini_query[0] != '\0') {
|
|
||||||
mylog("Sending Initial Connection query: '%s'\n", ini_query);
|
SOCK_put_int(sock, fnid, 4);
|
||||||
|
SOCK_put_int(sock, nargs, 4);
|
||||||
res = CC_send_query(self, ini_query, NULL, NULL);
|
|
||||||
if (res && QR_get_status(res) != PGRES_FATAL_ERROR) {
|
|
||||||
mylog("Initial Query response: '%s'\n", QR_get_notice(res));
|
mylog("send_function: done sending function\n");
|
||||||
}
|
|
||||||
|
for (i = 0; i < nargs; ++i) {
|
||||||
if ( res == NULL ||
|
|
||||||
QR_get_status(res) == PGRES_BAD_RESPONSE ||
|
mylog(" arg[%d]: len = %d, isint = %d, integer = %d, ptr = %u\n",
|
||||||
QR_get_status(res) == PGRES_FATAL_ERROR ||
|
i, args[i].len, args[i].isint, args[i].u.integer, args[i].u.ptr);
|
||||||
QR_get_status(res) == PGRES_INTERNAL_ERROR) {
|
|
||||||
|
SOCK_put_int(sock, args[i].len, 4);
|
||||||
self->errornumber = CONNECTION_COULD_NOT_SEND;
|
if (args[i].isint)
|
||||||
self->errormsg = "Error sending ConnSettings";
|
SOCK_put_int(sock, args[i].u.integer, 4);
|
||||||
if (res)
|
else
|
||||||
QR_Destructor(res);
|
SOCK_put_n_char(sock, (char *) args[i].u.ptr, args[i].len);
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
}
|
||||||
if (res)
|
|
||||||
QR_Destructor(res);
|
mylog(" done sending args\n");
|
||||||
}
|
|
||||||
return TRUE;
|
SOCK_flush_output(sock);
|
||||||
}
|
mylog(" after flush output\n");
|
||||||
|
|
||||||
|
done = FALSE;
|
||||||
|
while ( ! done) {
|
||||||
|
id = SOCK_get_char(sock);
|
||||||
|
mylog(" got id = %c\n", id);
|
||||||
|
|
||||||
|
switch(id) {
|
||||||
|
case 'V':
|
||||||
|
done = TRUE;
|
||||||
|
break; /* ok */
|
||||||
|
|
||||||
|
case 'N':
|
||||||
|
SOCK_get_string(sock, msgbuffer, ERROR_MSG_LENGTH);
|
||||||
|
mylog("send_function(V): 'N' - %s\n", msgbuffer);
|
||||||
|
/* continue reading */
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'E':
|
||||||
|
SOCK_get_string(sock, msgbuffer, ERROR_MSG_LENGTH);
|
||||||
|
self->errormsg = msgbuffer;
|
||||||
|
|
||||||
|
mylog("send_function(V): 'E' - %s\n", self->errormsg);
|
||||||
|
qlog("ERROR from backend during send_function: '%s'\n", self->errormsg);
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
default:
|
||||||
|
self->errornumber = CONNECTION_BACKEND_CRAZY;
|
||||||
|
self->errormsg = "Unexpected protocol character from backend";
|
||||||
|
CC_set_no_trans(self);
|
||||||
|
|
||||||
|
mylog("send_function: error - %s\n", self->errormsg);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
id = SOCK_get_char(sock);
|
||||||
|
for (;;) {
|
||||||
|
switch (id) {
|
||||||
|
case 'G': /* function returned properly */
|
||||||
|
mylog(" got G!\n");
|
||||||
|
|
||||||
|
*actual_result_len = SOCK_get_int(sock, 4);
|
||||||
|
mylog(" actual_result_len = %d\n", *actual_result_len);
|
||||||
|
|
||||||
|
if (result_is_int)
|
||||||
|
*((int *) result_buf) = SOCK_get_int(sock, 4);
|
||||||
|
else
|
||||||
|
SOCK_get_n_char(sock, (char *) result_buf, *actual_result_len);
|
||||||
|
|
||||||
|
mylog(" after get result\n");
|
||||||
|
|
||||||
|
c = SOCK_get_char(sock); /* get the last '0' */
|
||||||
|
|
||||||
|
mylog(" after get 0\n");
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
case 'E':
|
||||||
|
SOCK_get_string(sock, msgbuffer, ERROR_MSG_LENGTH);
|
||||||
|
self->errormsg = msgbuffer;
|
||||||
|
|
||||||
|
mylog("send_function(G): 'E' - %s\n", self->errormsg);
|
||||||
|
qlog("ERROR from backend during send_function: '%s'\n", self->errormsg);
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
case 'N':
|
||||||
|
SOCK_get_string(sock, msgbuffer, ERROR_MSG_LENGTH);
|
||||||
|
|
||||||
|
mylog("send_function(G): 'N' - %s\n", msgbuffer);
|
||||||
|
qlog("NOTICE from backend during send_function: '%s'\n", msgbuffer);
|
||||||
|
|
||||||
|
continue; // dont return a result -- continue reading
|
||||||
|
|
||||||
|
case '0': /* empty result */
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
default:
|
||||||
|
self->errornumber = CONNECTION_BACKEND_CRAZY;
|
||||||
|
self->errormsg = "Unexpected protocol character from backend";
|
||||||
|
CC_set_no_trans(self);
|
||||||
|
|
||||||
|
mylog("send_function: error - %s\n", self->errormsg);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char
|
||||||
|
CC_send_settings(ConnectionClass *self)
|
||||||
|
{
|
||||||
|
char ini_query[MAX_MESSAGE_LEN];
|
||||||
|
ConnInfo *ci = &(self->connInfo);
|
||||||
|
// QResultClass *res;
|
||||||
|
HSTMT hstmt;
|
||||||
|
StatementClass *stmt;
|
||||||
|
RETCODE result;
|
||||||
|
SWORD cols = 0;
|
||||||
|
|
||||||
|
result = SQLAllocStmt( self, &hstmt);
|
||||||
|
if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
stmt = (StatementClass *) hstmt;
|
||||||
|
|
||||||
|
ini_query[0] = '\0';
|
||||||
|
|
||||||
|
/* Set the Datestyle to the format the driver expects it to be in */
|
||||||
|
sprintf(ini_query, "set DateStyle to 'ISO'");
|
||||||
|
|
||||||
|
/* Disable genetic optimizer based on global flag */
|
||||||
|
if (globals.disable_optimizer)
|
||||||
|
sprintf(&ini_query[strlen(ini_query)], "%sset geqo to 'OFF'",
|
||||||
|
ini_query[0] != '\0' ? "; " : "");
|
||||||
|
|
||||||
|
/* Global settings */
|
||||||
|
if (globals.conn_settings[0] != '\0')
|
||||||
|
sprintf(&ini_query[strlen(ini_query)], "%s%s",
|
||||||
|
ini_query[0] != '\0' ? "; " : "",
|
||||||
|
globals.conn_settings);
|
||||||
|
|
||||||
|
/* Per Datasource settings */
|
||||||
|
if (ci->conn_settings[0] != '\0')
|
||||||
|
sprintf(&ini_query[strlen(ini_query)], "%s%s",
|
||||||
|
ini_query[0] != '\0' ? "; " : "",
|
||||||
|
ci->conn_settings);
|
||||||
|
|
||||||
|
if (ini_query[0] != '\0') {
|
||||||
|
mylog("Sending Initial Connection query: '%s'\n", ini_query);
|
||||||
|
|
||||||
|
result = SQLExecDirect(hstmt, ini_query, SQL_NTS);
|
||||||
|
if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
|
||||||
|
SQLFreeStmt(hstmt, SQL_DROP);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
SQLFreeStmt(hstmt, SQL_DROP);
|
||||||
|
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This function is just a hack to get the oid of our Large Object oid type.
|
||||||
|
If a real Large Object oid type is made part of Postgres, this function
|
||||||
|
will go away and the define 'PG_TYPE_LO' will be updated.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
CC_lookup_lo(ConnectionClass *self)
|
||||||
|
{
|
||||||
|
HSTMT hstmt;
|
||||||
|
StatementClass *stmt;
|
||||||
|
RETCODE result;
|
||||||
|
|
||||||
|
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='" \
|
||||||
|
PG_TYPE_LO_NAME \
|
||||||
|
"'", SQL_NTS);
|
||||||
|
if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
|
||||||
|
SQLFreeStmt(hstmt, SQL_DROP);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = SQLFetch(hstmt);
|
||||||
|
if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
|
||||||
|
SQLFreeStmt(hstmt, SQL_DROP);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
void
|
||||||
|
CC_test(ConnectionClass *self)
|
||||||
|
{
|
||||||
|
HSTMT hstmt1;
|
||||||
|
RETCODE result;
|
||||||
|
SDWORD pcbValue;
|
||||||
|
UDWORD pcrow;
|
||||||
|
UWORD rgfRowStatus;
|
||||||
|
char buf[255];
|
||||||
|
|
||||||
|
result = SQLAllocStmt( self, &hstmt1);
|
||||||
|
if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = SQLExtendedFetch(hstmt1, SQL_FETCH_ABSOLUTE, -2, &pcrow, &rgfRowStatus);
|
||||||
|
SQLGetData(hstmt1, 1, SQL_C_CHAR, buf, sizeof(buf), &pcbValue);
|
||||||
|
qlog("FETCH_ABSOLUTE, -2: result=%d, Col1 = '%s'\n", result, buf);
|
||||||
|
|
||||||
|
result = SQLFetch(hstmt1);
|
||||||
|
while (result != SQL_NO_DATA_FOUND) {
|
||||||
|
result = SQLFetch(hstmt1);
|
||||||
|
qlog("fetch on stmt1\n");
|
||||||
|
}
|
||||||
|
SQLFreeStmt(hstmt1, SQL_DROP);
|
||||||
|
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
|
@ -1,17 +1,18 @@
|
||||||
|
|
||||||
/* File: connection.h
|
/* File: connection.h
|
||||||
*
|
*
|
||||||
* Description: See "connection.c"
|
* Description: See "connection.c"
|
||||||
*
|
*
|
||||||
* Comments: See "notice.txt" for copyright and license information.
|
* Comments: See "notice.txt" for copyright and license information.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __CONNECTION_H__
|
#ifndef __CONNECTION_H__
|
||||||
#define __CONNECTION_H__
|
#define __CONNECTION_H__
|
||||||
|
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <sql.h>
|
#include <sql.h>
|
||||||
|
#include <sqlext.h>
|
||||||
#include "psqlodbc.h"
|
#include "psqlodbc.h"
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
@ -44,9 +45,9 @@ typedef enum {
|
||||||
/* SetConnectOption: corresponds to ODBC--"S1009" */
|
/* SetConnectOption: corresponds to ODBC--"S1009" */
|
||||||
#define CONN_TRANSACT_IN_PROGRES 7
|
#define CONN_TRANSACT_IN_PROGRES 7
|
||||||
#define CONN_NO_MEMORY_ERROR 8
|
#define CONN_NO_MEMORY_ERROR 8
|
||||||
#define CONN_NOT_IMPLEMENTED_ERROR 9
|
#define CONN_NOT_IMPLEMENTED_ERROR 9
|
||||||
#define CONN_INVALID_AUTHENTICATION 10
|
#define CONN_INVALID_AUTHENTICATION 10
|
||||||
#define CONN_AUTH_TYPE_UNSUPPORTED 11
|
#define CONN_AUTH_TYPE_UNSUPPORTED 11
|
||||||
|
|
||||||
|
|
||||||
/* Conn_status defines */
|
/* Conn_status defines */
|
||||||
|
@ -77,12 +78,12 @@ typedef enum {
|
||||||
#define SM_OPTIONS 64
|
#define SM_OPTIONS 64
|
||||||
#define SM_UNUSED 64
|
#define SM_UNUSED 64
|
||||||
#define SM_TTY 64
|
#define SM_TTY 64
|
||||||
|
|
||||||
/* Old 6.2 protocol defines */
|
/* Old 6.2 protocol defines */
|
||||||
#define NO_AUTHENTICATION 7
|
#define NO_AUTHENTICATION 7
|
||||||
#define PATH_SIZE 64
|
#define PATH_SIZE 64
|
||||||
#define ARGV_SIZE 64
|
#define ARGV_SIZE 64
|
||||||
#define NAMEDATALEN 16
|
#define NAMEDATALEN 16
|
||||||
|
|
||||||
typedef unsigned int ProtocolVersion;
|
typedef unsigned int ProtocolVersion;
|
||||||
|
|
||||||
|
@ -90,7 +91,7 @@ typedef unsigned int ProtocolVersion;
|
||||||
#define PG_PROTOCOL_LATEST PG_PROTOCOL(1, 0)
|
#define PG_PROTOCOL_LATEST PG_PROTOCOL(1, 0)
|
||||||
#define PG_PROTOCOL_EARLIEST PG_PROTOCOL(0, 0)
|
#define PG_PROTOCOL_EARLIEST PG_PROTOCOL(0, 0)
|
||||||
|
|
||||||
/* This startup packet is to support latest Postgres protocol (6.3) */
|
/* This startup packet is to support latest Postgres protocol (6.3) */
|
||||||
typedef struct _StartupPacket
|
typedef struct _StartupPacket
|
||||||
{
|
{
|
||||||
ProtocolVersion protoVersion;
|
ProtocolVersion protoVersion;
|
||||||
|
@ -100,41 +101,47 @@ typedef struct _StartupPacket
|
||||||
char unused[SM_UNUSED];
|
char unused[SM_UNUSED];
|
||||||
char tty[SM_TTY];
|
char tty[SM_TTY];
|
||||||
} StartupPacket;
|
} StartupPacket;
|
||||||
|
|
||||||
|
|
||||||
/* This startup packet is to support pre-Postgres 6.3 protocol */
|
/* This startup packet is to support pre-Postgres 6.3 protocol */
|
||||||
typedef struct _StartupPacket6_2
|
typedef struct _StartupPacket6_2
|
||||||
{
|
{
|
||||||
unsigned int authtype;
|
unsigned int authtype;
|
||||||
char database[PATH_SIZE];
|
char database[PATH_SIZE];
|
||||||
char user[NAMEDATALEN];
|
char user[NAMEDATALEN];
|
||||||
char options[ARGV_SIZE];
|
char options[ARGV_SIZE];
|
||||||
char execfile[ARGV_SIZE];
|
char execfile[ARGV_SIZE];
|
||||||
char tty[PATH_SIZE];
|
char tty[PATH_SIZE];
|
||||||
} StartupPacket6_2;
|
} StartupPacket6_2;
|
||||||
|
|
||||||
|
|
||||||
/* Structure to hold all the connection attributes for a specific
|
/* Structure to hold all the connection attributes for a specific
|
||||||
connection (used for both registry and file, DSN and DRIVER)
|
connection (used for both registry and file, DSN and DRIVER)
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char dsn[MEDIUM_REGISTRY_LEN];
|
char dsn[MEDIUM_REGISTRY_LEN];
|
||||||
|
char desc[MEDIUM_REGISTRY_LEN];
|
||||||
char driver[MEDIUM_REGISTRY_LEN];
|
char driver[MEDIUM_REGISTRY_LEN];
|
||||||
char server[MEDIUM_REGISTRY_LEN];
|
char server[MEDIUM_REGISTRY_LEN];
|
||||||
char database[MEDIUM_REGISTRY_LEN];
|
char database[MEDIUM_REGISTRY_LEN];
|
||||||
char username[MEDIUM_REGISTRY_LEN];
|
char username[MEDIUM_REGISTRY_LEN];
|
||||||
char password[MEDIUM_REGISTRY_LEN];
|
char password[MEDIUM_REGISTRY_LEN];
|
||||||
char conn_settings[LARGE_REGISTRY_LEN];
|
char conn_settings[LARGE_REGISTRY_LEN];
|
||||||
char protocol[SMALL_REGISTRY_LEN];
|
char protocol[SMALL_REGISTRY_LEN];
|
||||||
char port[SMALL_REGISTRY_LEN];
|
char port[SMALL_REGISTRY_LEN];
|
||||||
char readonly[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 show_system_tables[SMALL_REGISTRY_LEN];
|
||||||
char focus_password;
|
char focus_password;
|
||||||
} ConnInfo;
|
} ConnInfo;
|
||||||
|
|
||||||
/* Macro to determine is the connection using 6.2 protocol? */
|
/* Macro to determine is the connection using 6.2 protocol? */
|
||||||
#define PROTOCOL_62(conninfo_) (strncmp((conninfo_)->protocol, PG62, strlen(PG62)) == 0)
|
#define PROTOCOL_62(conninfo_) (strncmp((conninfo_)->protocol, PG62, strlen(PG62)) == 0)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/******* The Connection handle ************/
|
/******* The Connection handle ************/
|
||||||
struct ConnectionClass_ {
|
struct ConnectionClass_ {
|
||||||
HENV henv; /* environment this connection was created on */
|
HENV henv; /* environment this connection was created on */
|
||||||
|
@ -145,6 +152,7 @@ struct ConnectionClass_ {
|
||||||
StatementClass **stmts;
|
StatementClass **stmts;
|
||||||
int num_stmts;
|
int num_stmts;
|
||||||
SocketClass *sock;
|
SocketClass *sock;
|
||||||
|
int lobj_type;
|
||||||
char transact_status; /* Is a transaction is currently in progress */
|
char transact_status; /* Is a transaction is currently in progress */
|
||||||
char errormsg_created; /* has an informative error msg been created? */
|
char errormsg_created; /* has an informative error msg been created? */
|
||||||
};
|
};
|
||||||
|
@ -162,15 +170,14 @@ struct ConnectionClass_ {
|
||||||
/* for CC_DSN_info */
|
/* for CC_DSN_info */
|
||||||
#define CONN_DONT_OVERWRITE 0
|
#define CONN_DONT_OVERWRITE 0
|
||||||
#define CONN_OVERWRITE 1
|
#define CONN_OVERWRITE 1
|
||||||
|
|
||||||
|
|
||||||
/* prototypes */
|
/* prototypes */
|
||||||
ConnectionClass *CC_Constructor();
|
ConnectionClass *CC_Constructor();
|
||||||
char CC_Destructor(ConnectionClass *self);
|
char CC_Destructor(ConnectionClass *self);
|
||||||
|
int CC_cursor_count(ConnectionClass *self);
|
||||||
char CC_cleanup(ConnectionClass *self);
|
char CC_cleanup(ConnectionClass *self);
|
||||||
char CC_abort(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_connect(ConnectionClass *self, char do_password);
|
||||||
char CC_add_statement(ConnectionClass *self, StatementClass *stmt);
|
char CC_add_statement(ConnectionClass *self, StatementClass *stmt);
|
||||||
char CC_remove_statement(ConnectionClass *self, StatementClass *stmt);
|
char CC_remove_statement(ConnectionClass *self, StatementClass *stmt);
|
||||||
|
@ -178,6 +185,8 @@ char CC_get_error(ConnectionClass *self, int *number, char **message);
|
||||||
QResultClass *CC_send_query(ConnectionClass *self, char *query, QResultClass *result_in, char *cursor);
|
QResultClass *CC_send_query(ConnectionClass *self, char *query, QResultClass *result_in, char *cursor);
|
||||||
void CC_clear_error(ConnectionClass *self);
|
void CC_clear_error(ConnectionClass *self);
|
||||||
char *CC_create_errormsg(ConnectionClass *self);
|
char *CC_create_errormsg(ConnectionClass *self);
|
||||||
char CC_send_settings(ConnectionClass *self);
|
int CC_send_function(ConnectionClass *conn, int fnid, void *result_buf, int *actual_result_len, int result_is_int, LO_ARG *argv, int nargs);
|
||||||
|
char CC_send_settings(ConnectionClass *self);
|
||||||
|
void CC_lookup_lo(ConnectionClass *conn);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,11 +1,11 @@
|
||||||
|
|
||||||
/* File: convert.h
|
/* File: convert.h
|
||||||
*
|
*
|
||||||
* Description: See "convert.c"
|
* Description: See "convert.c"
|
||||||
*
|
*
|
||||||
* Comments: See "notice.txt" for copyright and license information.
|
* Comments: See "notice.txt" for copyright and license information.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __CONVERT_H__
|
#ifndef __CONVERT_H__
|
||||||
#define __CONVERT_H__
|
#define __CONVERT_H__
|
||||||
|
@ -13,10 +13,12 @@
|
||||||
#include "psqlodbc.h"
|
#include "psqlodbc.h"
|
||||||
|
|
||||||
/* copy_and_convert results */
|
/* copy_and_convert results */
|
||||||
#define COPY_OK 0
|
#define COPY_OK 0
|
||||||
#define COPY_UNSUPPORTED_TYPE 1
|
#define COPY_UNSUPPORTED_TYPE 1
|
||||||
#define COPY_UNSUPPORTED_CONVERSION 2
|
#define COPY_UNSUPPORTED_CONVERSION 2
|
||||||
#define COPY_RESULT_TRUNCATED 3
|
#define COPY_RESULT_TRUNCATED 3
|
||||||
|
#define COPY_GENERAL_ERROR 4
|
||||||
|
#define COPY_NO_DATA_FOUND 5
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int m;
|
int m;
|
||||||
|
@ -27,21 +29,21 @@ typedef struct {
|
||||||
int ss;
|
int ss;
|
||||||
} SIMPLE_TIME;
|
} SIMPLE_TIME;
|
||||||
|
|
||||||
int copy_and_convert_field_bindinfo(Int4 field_type, void *value, BindInfoClass *bic);
|
int copy_and_convert_field_bindinfo(StatementClass *stmt, Int4 field_type, void *value, int col);
|
||||||
int copy_and_convert_field(Int4 field_type, void *value,
|
int copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2 fCType,
|
||||||
Int2 fCType, PTR rgbValue, SDWORD cbValueMax, SDWORD *pcbValue);
|
PTR rgbValue, SDWORD cbValueMax, SDWORD *pcbValue, char multiple);
|
||||||
|
|
||||||
int copy_statement_with_parameters(StatementClass *stmt);
|
int copy_statement_with_parameters(StatementClass *stmt);
|
||||||
char *convert_escape(char *value);
|
char *convert_escape(char *value);
|
||||||
char *convert_money(char *s);
|
char *convert_money(char *s);
|
||||||
int monthToNumber(char *mon);
|
|
||||||
char *convert_time(SIMPLE_TIME *st);
|
|
||||||
char parse_datetime(char *buf, SIMPLE_TIME *st);
|
char parse_datetime(char *buf, SIMPLE_TIME *st);
|
||||||
char *convert_linefeeds(char *s, char *dst, size_t max);
|
char *convert_linefeeds(char *s, char *dst, size_t max);
|
||||||
char *convert_returns(char *si, char *dst, int used);
|
char *convert_special_chars(char *si, char *dst, int used);
|
||||||
|
|
||||||
int convert_pgbinary_to_char(char *value, char *rgbValue, int cbValueMax);
|
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_from_pgbinary(unsigned char *value, unsigned char *rgbValue, int cbValueMax);
|
||||||
int convert_to_pgbinary(unsigned char *in, char *out, int len);
|
int convert_to_pgbinary(unsigned char *in, char *out, int len);
|
||||||
|
int convert_lo(StatementClass *stmt, void *value, Int2 fCType, PTR rgbValue,
|
||||||
|
SDWORD cbValueMax, SDWORD *pcbValue, char multiple);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -0,0 +1,762 @@
|
||||||
|
|
||||||
|
/* Module: dlg_specific.c
|
||||||
|
*
|
||||||
|
* Description: This module contains any specific code for handling
|
||||||
|
* dialog boxes such as driver/datasource options. Both the
|
||||||
|
* ConfigDSN() and the SQLDriverConnect() functions use
|
||||||
|
* functions in this module. If you were to add a new option
|
||||||
|
* to any dialog box, you would most likely only have to change
|
||||||
|
* things in here rather than in 2 separate places as before.
|
||||||
|
*
|
||||||
|
* Classes: none
|
||||||
|
*
|
||||||
|
* API functions: none
|
||||||
|
*
|
||||||
|
* Comments: See "notice.txt" for copyright and license information.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "dlg_specific.h"
|
||||||
|
|
||||||
|
extern GLOBAL_VALUES globals;
|
||||||
|
|
||||||
|
void
|
||||||
|
SetDlgStuff(HWND hdlg, ConnInfo *ci)
|
||||||
|
{
|
||||||
|
/* If driver attribute NOT present, then set the datasource name and description */
|
||||||
|
if (ci->driver[0] == '\0') {
|
||||||
|
SetDlgItemText(hdlg, IDC_DSNAME, ci->dsn);
|
||||||
|
SetDlgItemText(hdlg, IDC_DESC, ci->desc);
|
||||||
|
}
|
||||||
|
|
||||||
|
SetDlgItemText(hdlg, IDC_DATABASE, ci->database);
|
||||||
|
SetDlgItemText(hdlg, IDC_SERVER, ci->server);
|
||||||
|
SetDlgItemText(hdlg, IDC_USER, ci->username);
|
||||||
|
SetDlgItemText(hdlg, IDC_PASSWORD, ci->password);
|
||||||
|
SetDlgItemText(hdlg, IDC_PORT, ci->port);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
GetDlgStuff(HWND hdlg, ConnInfo *ci)
|
||||||
|
{
|
||||||
|
GetDlgItemText(hdlg, IDC_DESC, ci->desc, sizeof(ci->desc));
|
||||||
|
|
||||||
|
GetDlgItemText(hdlg, IDC_DATABASE, ci->database, sizeof(ci->database));
|
||||||
|
GetDlgItemText(hdlg, IDC_SERVER, ci->server, sizeof(ci->server));
|
||||||
|
GetDlgItemText(hdlg, IDC_USER, ci->username, sizeof(ci->username));
|
||||||
|
GetDlgItemText(hdlg, IDC_PASSWORD, ci->password, sizeof(ci->password));
|
||||||
|
GetDlgItemText(hdlg, IDC_PORT, ci->port, sizeof(ci->port));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int CALLBACK driver_optionsProc(HWND hdlg,
|
||||||
|
WORD wMsg,
|
||||||
|
WPARAM wParam,
|
||||||
|
LPARAM lParam)
|
||||||
|
{
|
||||||
|
switch (wMsg) {
|
||||||
|
case WM_INITDIALOG:
|
||||||
|
|
||||||
|
CheckDlgButton(hdlg, DRV_COMMLOG, globals.commlog);
|
||||||
|
CheckDlgButton(hdlg, DRV_OPTIMIZER, globals.disable_optimizer);
|
||||||
|
CheckDlgButton(hdlg, DRV_UNIQUEINDEX, globals.unique_index);
|
||||||
|
CheckDlgButton(hdlg, DRV_READONLY, globals.readonly);
|
||||||
|
CheckDlgButton(hdlg, DRV_USEDECLAREFETCH, globals.use_declarefetch);
|
||||||
|
|
||||||
|
/* Unknown (Default) Data Type sizes */
|
||||||
|
switch(globals.unknown_sizes) {
|
||||||
|
case UNKNOWNS_AS_DONTKNOW:
|
||||||
|
CheckDlgButton(hdlg, DRV_UNKNOWN_DONTKNOW, 1);
|
||||||
|
break;
|
||||||
|
case UNKNOWNS_AS_LONGEST:
|
||||||
|
CheckDlgButton(hdlg, DRV_UNKNOWN_LONGEST, 1);
|
||||||
|
break;
|
||||||
|
case UNKNOWNS_AS_MAX:
|
||||||
|
default:
|
||||||
|
CheckDlgButton(hdlg, DRV_UNKNOWN_MAX, 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
CheckDlgButton(hdlg, DRV_TEXT_LONGVARCHAR, globals.text_as_longvarchar);
|
||||||
|
CheckDlgButton(hdlg, DRV_UNKNOWNS_LONGVARCHAR, globals.unknowns_as_longvarchar);
|
||||||
|
CheckDlgButton(hdlg, DRV_BOOLS_CHAR, globals.bools_as_char);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
SetDlgItemText(hdlg, DRV_EXTRASYSTABLEPREFIXES, globals.extra_systable_prefixes);
|
||||||
|
|
||||||
|
/* Driver Connection Settings */
|
||||||
|
SetDlgItemText(hdlg, DRV_CONNSETTINGS, globals.conn_settings);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WM_COMMAND:
|
||||||
|
switch (GET_WM_COMMAND_ID(wParam, lParam)) {
|
||||||
|
case IDOK:
|
||||||
|
|
||||||
|
globals.commlog = IsDlgButtonChecked(hdlg, DRV_COMMLOG);
|
||||||
|
globals.disable_optimizer = IsDlgButtonChecked(hdlg, DRV_OPTIMIZER);
|
||||||
|
globals.unique_index = IsDlgButtonChecked(hdlg, DRV_UNIQUEINDEX);
|
||||||
|
globals.readonly = IsDlgButtonChecked(hdlg, DRV_READONLY);
|
||||||
|
globals.use_declarefetch = IsDlgButtonChecked(hdlg, DRV_USEDECLAREFETCH);
|
||||||
|
|
||||||
|
/* Unknown (Default) Data Type sizes */
|
||||||
|
if (IsDlgButtonChecked(hdlg, DRV_UNKNOWN_MAX))
|
||||||
|
globals.unknown_sizes = UNKNOWNS_AS_MAX;
|
||||||
|
else if (IsDlgButtonChecked(hdlg, DRV_UNKNOWN_DONTKNOW))
|
||||||
|
globals.unknown_sizes = UNKNOWNS_AS_DONTKNOW;
|
||||||
|
else if (IsDlgButtonChecked(hdlg, DRV_UNKNOWN_LONGEST))
|
||||||
|
globals.unknown_sizes = UNKNOWNS_AS_LONGEST;
|
||||||
|
else
|
||||||
|
globals.unknown_sizes = UNKNOWNS_AS_MAX;
|
||||||
|
|
||||||
|
globals.text_as_longvarchar = IsDlgButtonChecked(hdlg, DRV_TEXT_LONGVARCHAR);
|
||||||
|
globals.unknowns_as_longvarchar = IsDlgButtonChecked(hdlg, DRV_UNKNOWNS_LONGVARCHAR);
|
||||||
|
globals.bools_as_char = IsDlgButtonChecked(hdlg, DRV_BOOLS_CHAR);
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
GetDlgItemText(hdlg, DRV_EXTRASYSTABLEPREFIXES, globals.extra_systable_prefixes, sizeof(globals.extra_systable_prefixes));
|
||||||
|
|
||||||
|
/* Driver Connection Settings */
|
||||||
|
GetDlgItemText(hdlg, DRV_CONNSETTINGS, globals.conn_settings, sizeof(globals.conn_settings));
|
||||||
|
|
||||||
|
updateGlobals();
|
||||||
|
|
||||||
|
// fall through
|
||||||
|
|
||||||
|
case IDCANCEL:
|
||||||
|
EndDialog(hdlg, GET_WM_COMMAND_ID(wParam, lParam) == IDOK);
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
case IDDEFAULTS:
|
||||||
|
CheckDlgButton(hdlg, DRV_COMMLOG, DEFAULT_COMMLOG);
|
||||||
|
CheckDlgButton(hdlg, DRV_OPTIMIZER, DEFAULT_OPTIMIZER);
|
||||||
|
CheckDlgButton(hdlg, DRV_UNIQUEINDEX, DEFAULT_UNIQUEINDEX);
|
||||||
|
CheckDlgButton(hdlg, DRV_READONLY, DEFAULT_READONLY);
|
||||||
|
CheckDlgButton(hdlg, DRV_USEDECLAREFETCH, DEFAULT_USEDECLAREFETCH);
|
||||||
|
|
||||||
|
/* Unknown Sizes */
|
||||||
|
CheckDlgButton(hdlg, DRV_UNKNOWN_DONTKNOW, 0);
|
||||||
|
CheckDlgButton(hdlg, DRV_UNKNOWN_LONGEST, 0);
|
||||||
|
CheckDlgButton(hdlg, DRV_UNKNOWN_MAX, 0);
|
||||||
|
switch(DEFAULT_UNKNOWNSIZES) {
|
||||||
|
case UNKNOWNS_AS_DONTKNOW:
|
||||||
|
CheckDlgButton(hdlg, DRV_UNKNOWN_DONTKNOW, 1);
|
||||||
|
break;
|
||||||
|
case UNKNOWNS_AS_LONGEST:
|
||||||
|
CheckDlgButton(hdlg, DRV_UNKNOWN_LONGEST, 1);
|
||||||
|
break;
|
||||||
|
case UNKNOWNS_AS_MAX:
|
||||||
|
CheckDlgButton(hdlg, DRV_UNKNOWN_MAX, 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
CheckDlgButton(hdlg, DRV_TEXT_LONGVARCHAR, DEFAULT_TEXTASLONGVARCHAR);
|
||||||
|
CheckDlgButton(hdlg, DRV_UNKNOWNS_LONGVARCHAR, DEFAULT_UNKNOWNSASLONGVARCHAR);
|
||||||
|
CheckDlgButton(hdlg, DRV_BOOLS_CHAR, DEFAULT_BOOLSASCHAR);
|
||||||
|
|
||||||
|
SetDlgItemInt(hdlg, DRV_CACHE_SIZE, FETCH_MAX, FALSE);
|
||||||
|
SetDlgItemInt(hdlg, DRV_VARCHAR_SIZE, MAX_VARCHAR_SIZE, FALSE);
|
||||||
|
SetDlgItemInt(hdlg, DRV_LONGVARCHAR_SIZE, TEXT_FIELD_SIZE, TRUE);
|
||||||
|
|
||||||
|
SetDlgItemText(hdlg, DRV_EXTRASYSTABLEPREFIXES, DEFAULT_EXTRASYSTABLEPREFIXES);
|
||||||
|
|
||||||
|
/* Driver Connection Settings */
|
||||||
|
SetDlgItemText(hdlg, DRV_CONNSETTINGS, "");
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CALLBACK ds_optionsProc(HWND hdlg,
|
||||||
|
WORD wMsg,
|
||||||
|
WPARAM wParam,
|
||||||
|
LPARAM lParam)
|
||||||
|
{
|
||||||
|
ConnInfo *ci;
|
||||||
|
char buf[128];
|
||||||
|
// int unknown_sizes;
|
||||||
|
|
||||||
|
switch (wMsg) {
|
||||||
|
case WM_INITDIALOG:
|
||||||
|
ci = (ConnInfo *) lParam;
|
||||||
|
SetWindowLong(hdlg, DWL_USER, lParam); // save for OK
|
||||||
|
|
||||||
|
/* Change window caption */
|
||||||
|
if (ci->driver[0])
|
||||||
|
SetWindowText(hdlg, "Advanced Options (Connection)");
|
||||||
|
else {
|
||||||
|
sprintf(buf, "Advanced Options (%s)", ci->dsn);
|
||||||
|
SetWindowText(hdlg, buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Readonly */
|
||||||
|
CheckDlgButton(hdlg, DS_READONLY, atoi(ci->readonly));
|
||||||
|
|
||||||
|
/* Protocol */
|
||||||
|
if (strncmp(ci->protocol, PG62, strlen(PG62)) == 0)
|
||||||
|
CheckDlgButton(hdlg, DS_PG62, 1);
|
||||||
|
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));
|
||||||
|
CheckDlgButton(hdlg, DS_SHOWSYSTEMTABLES, atoi(ci->show_system_tables));
|
||||||
|
|
||||||
|
EnableWindow(GetDlgItem(hdlg, DS_FAKEOIDINDEX), atoi(ci->show_oid_column));
|
||||||
|
|
||||||
|
/* Datasource Connection Settings */
|
||||||
|
SetDlgItemText(hdlg, DS_CONNSETTINGS, ci->conn_settings);
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
case WM_COMMAND:
|
||||||
|
switch (GET_WM_COMMAND_ID(wParam, lParam)) {
|
||||||
|
case DS_SHOWOIDCOLUMN:
|
||||||
|
mylog("WM_COMMAND: DS_SHOWOIDCOLUMN\n");
|
||||||
|
EnableWindow(GetDlgItem(hdlg, DS_FAKEOIDINDEX), IsDlgButtonChecked(hdlg, DS_SHOWOIDCOLUMN));
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
|
||||||
|
case IDOK:
|
||||||
|
|
||||||
|
ci = (ConnInfo *)GetWindowLong(hdlg, DWL_USER);
|
||||||
|
mylog("IDOK: got ci = %u\n", ci);
|
||||||
|
|
||||||
|
/* Readonly */
|
||||||
|
sprintf(ci->readonly, "%d", IsDlgButtonChecked(hdlg, DS_READONLY));
|
||||||
|
|
||||||
|
/* Protocol */
|
||||||
|
if ( IsDlgButtonChecked(hdlg, DS_PG62))
|
||||||
|
strcpy(ci->protocol, PG62);
|
||||||
|
else
|
||||||
|
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));
|
||||||
|
|
||||||
|
/* OID Options*/
|
||||||
|
sprintf(ci->fake_oid_index, "%d", IsDlgButtonChecked(hdlg, DS_FAKEOIDINDEX));
|
||||||
|
sprintf(ci->show_oid_column, "%d", IsDlgButtonChecked(hdlg, DS_SHOWOIDCOLUMN));
|
||||||
|
|
||||||
|
/* Datasource Connection Settings */
|
||||||
|
GetDlgItemText(hdlg, DS_CONNSETTINGS, ci->conn_settings, sizeof(ci->conn_settings));
|
||||||
|
|
||||||
|
|
||||||
|
// fall through
|
||||||
|
|
||||||
|
case IDCANCEL:
|
||||||
|
EndDialog(hdlg, GET_WM_COMMAND_ID(wParam, lParam) == IDOK);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
makeConnectString(char *connect_string, ConnInfo *ci)
|
||||||
|
{
|
||||||
|
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;FAKEOIDINDEX=%s;SHOWOIDCOLUMN=%s;SHOWSYSTEMTABLES=%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->unknown_sizes, -- currently only needed in Driver options.
|
||||||
|
ci->fake_oid_index,
|
||||||
|
ci->show_oid_column,
|
||||||
|
ci->show_system_tables,
|
||||||
|
ci->conn_settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
copyAttributes(ConnInfo *ci, char *attribute, char *value)
|
||||||
|
{
|
||||||
|
|
||||||
|
if(stricmp(attribute, "DSN") == 0)
|
||||||
|
strcpy(ci->dsn, value);
|
||||||
|
|
||||||
|
else if(stricmp(attribute, "driver") == 0)
|
||||||
|
strcpy(ci->driver, value);
|
||||||
|
|
||||||
|
else if(stricmp(attribute, INI_DATABASE) == 0)
|
||||||
|
strcpy(ci->database, value);
|
||||||
|
|
||||||
|
else if(stricmp(attribute, INI_SERVER) == 0 || stricmp(attribute, "server") == 0)
|
||||||
|
strcpy(ci->server, value);
|
||||||
|
|
||||||
|
else if(stricmp(attribute, INI_USER) == 0 || stricmp(attribute, "uid") == 0)
|
||||||
|
strcpy(ci->username, value);
|
||||||
|
|
||||||
|
else if(stricmp(attribute, INI_PASSWORD) == 0 || stricmp(attribute, "pwd") == 0)
|
||||||
|
strcpy(ci->password, value);
|
||||||
|
|
||||||
|
else if(stricmp(attribute, INI_PORT) == 0)
|
||||||
|
strcpy(ci->port, value);
|
||||||
|
|
||||||
|
else if (stricmp(attribute, INI_READONLY) == 0)
|
||||||
|
strcpy(ci->readonly, 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);
|
||||||
|
|
||||||
|
else if (stricmp(attribute, INI_FAKEOIDINDEX) == 0)
|
||||||
|
strcpy(ci->fake_oid_index, 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);
|
||||||
|
|
||||||
|
|
||||||
|
mylog("copyAttributes: DSN='%s',server='%s',dbase='%s',user='%s',passwd='%s',port='%s',readonly='%s',protocol='%s', conn_settings='%s')\n",
|
||||||
|
ci->dsn,
|
||||||
|
ci->server,
|
||||||
|
ci->database,
|
||||||
|
ci->username,
|
||||||
|
ci->password,
|
||||||
|
ci->port,
|
||||||
|
ci->readonly,
|
||||||
|
ci->protocol,
|
||||||
|
// ci->unknown_sizes,
|
||||||
|
ci->conn_settings);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
getDSNdefaults(ConnInfo *ci)
|
||||||
|
{
|
||||||
|
if (ci->port[0] == '\0')
|
||||||
|
strcpy(ci->port, DEFAULT_PORT);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
if (ci->show_oid_column[0] == '\0')
|
||||||
|
sprintf(ci->show_oid_column, "%d", DEFAULT_SHOWOIDCOLUMN);
|
||||||
|
|
||||||
|
if (ci->show_system_tables[0] == '\0')
|
||||||
|
sprintf(ci->show_system_tables, "%d", DEFAULT_SHOWSYSTEMTABLES);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
getDSNinfo(ConnInfo *ci, char overwrite)
|
||||||
|
{
|
||||||
|
char *DSN = ci->dsn;
|
||||||
|
|
||||||
|
// If a driver keyword was present, then dont use a DSN and return.
|
||||||
|
// If DSN is null and no driver, then use the default datasource.
|
||||||
|
if ( DSN[0] == '\0') {
|
||||||
|
if ( ci->driver[0] != '\0')
|
||||||
|
return;
|
||||||
|
else
|
||||||
|
strcpy(DSN, INI_DSN);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Proceed with getting info for the given DSN.
|
||||||
|
|
||||||
|
if ( ci->desc[0] == '\0' || overwrite)
|
||||||
|
SQLGetPrivateProfileString(DSN, INI_KDESC, "", ci->desc, sizeof(ci->desc), ODBC_INI);
|
||||||
|
|
||||||
|
if ( ci->server[0] == '\0' || overwrite)
|
||||||
|
SQLGetPrivateProfileString(DSN, INI_SERVER, "", ci->server, sizeof(ci->server), ODBC_INI);
|
||||||
|
|
||||||
|
if ( ci->database[0] == '\0' || overwrite)
|
||||||
|
SQLGetPrivateProfileString(DSN, INI_DATABASE, "", ci->database, sizeof(ci->database), ODBC_INI);
|
||||||
|
|
||||||
|
if ( ci->username[0] == '\0' || overwrite)
|
||||||
|
SQLGetPrivateProfileString(DSN, INI_USER, "", ci->username, sizeof(ci->username), ODBC_INI);
|
||||||
|
|
||||||
|
if ( ci->password[0] == '\0' || overwrite)
|
||||||
|
SQLGetPrivateProfileString(DSN, INI_PASSWORD, "", ci->password, sizeof(ci->password), ODBC_INI);
|
||||||
|
|
||||||
|
if ( ci->port[0] == '\0' || overwrite)
|
||||||
|
SQLGetPrivateProfileString(DSN, INI_PORT, "", ci->port, sizeof(ci->port), ODBC_INI);
|
||||||
|
|
||||||
|
if ( ci->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);
|
||||||
|
|
||||||
|
if ( ci->fake_oid_index[0] == '\0' || overwrite)
|
||||||
|
SQLGetPrivateProfileString(DSN, INI_FAKEOIDINDEX, "", ci->fake_oid_index, sizeof(ci->fake_oid_index), ODBC_INI);
|
||||||
|
|
||||||
|
if ( ci->show_system_tables[0] == '\0' || overwrite)
|
||||||
|
SQLGetPrivateProfileString(DSN, INI_SHOWSYSTEMTABLES, "", ci->show_system_tables, sizeof(ci->show_system_tables), ODBC_INI);
|
||||||
|
|
||||||
|
if ( ci->protocol[0] == '\0' || overwrite)
|
||||||
|
SQLGetPrivateProfileString(DSN, INI_PROTOCOL, "", ci->protocol, sizeof(ci->protocol), ODBC_INI);
|
||||||
|
|
||||||
|
if ( ci->conn_settings[0] == '\0' || overwrite)
|
||||||
|
SQLGetPrivateProfileString(DSN, INI_CONNSETTINGS, "", ci->conn_settings, sizeof(ci->conn_settings), ODBC_INI);
|
||||||
|
|
||||||
|
qlog("DSN info: DSN='%s',server='%s',port='%s',dbase='%s',user='%s',passwd='%s'\n",
|
||||||
|
DSN,
|
||||||
|
ci->server,
|
||||||
|
ci->port,
|
||||||
|
ci->database,
|
||||||
|
ci->username,
|
||||||
|
ci->password);
|
||||||
|
qlog(" readonly='%s',protocol='%s',showoid='%s',fakeoidindex='%s',showsystable='%s'\n",
|
||||||
|
ci->readonly,
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* This is for datasource based options only */
|
||||||
|
void
|
||||||
|
writeDSNinfo(ConnInfo *ci)
|
||||||
|
{
|
||||||
|
char *DSN = ci->dsn;
|
||||||
|
|
||||||
|
SQLWritePrivateProfileString(DSN,
|
||||||
|
INI_KDESC,
|
||||||
|
ci->desc,
|
||||||
|
ODBC_INI);
|
||||||
|
|
||||||
|
SQLWritePrivateProfileString(DSN,
|
||||||
|
INI_DATABASE,
|
||||||
|
ci->database,
|
||||||
|
ODBC_INI);
|
||||||
|
|
||||||
|
SQLWritePrivateProfileString(DSN,
|
||||||
|
INI_SERVER,
|
||||||
|
ci->server,
|
||||||
|
ODBC_INI);
|
||||||
|
|
||||||
|
SQLWritePrivateProfileString(DSN,
|
||||||
|
INI_PORT,
|
||||||
|
ci->port,
|
||||||
|
ODBC_INI);
|
||||||
|
|
||||||
|
SQLWritePrivateProfileString(DSN,
|
||||||
|
INI_USER,
|
||||||
|
ci->username,
|
||||||
|
ODBC_INI);
|
||||||
|
|
||||||
|
SQLWritePrivateProfileString(DSN,
|
||||||
|
INI_PASSWORD,
|
||||||
|
ci->password,
|
||||||
|
ODBC_INI);
|
||||||
|
|
||||||
|
SQLWritePrivateProfileString(DSN,
|
||||||
|
INI_READONLY,
|
||||||
|
ci->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,
|
||||||
|
ODBC_INI);
|
||||||
|
|
||||||
|
SQLWritePrivateProfileString(DSN,
|
||||||
|
INI_FAKEOIDINDEX,
|
||||||
|
ci->fake_oid_index,
|
||||||
|
ODBC_INI);
|
||||||
|
|
||||||
|
SQLWritePrivateProfileString(DSN,
|
||||||
|
INI_SHOWSYSTEMTABLES,
|
||||||
|
ci->show_system_tables,
|
||||||
|
ODBC_INI);
|
||||||
|
|
||||||
|
SQLWritePrivateProfileString(DSN,
|
||||||
|
INI_PROTOCOL,
|
||||||
|
ci->protocol,
|
||||||
|
ODBC_INI);
|
||||||
|
|
||||||
|
SQLWritePrivateProfileString(DSN,
|
||||||
|
INI_CONNSETTINGS,
|
||||||
|
ci->conn_settings,
|
||||||
|
ODBC_INI);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* 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);
|
||||||
|
/* sanity check if using cursors */
|
||||||
|
if (globals.fetch_max <= 0)
|
||||||
|
globals.fetch_max = FETCH_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
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, "",
|
||||||
|
temp, sizeof(temp), ODBCINST_INI);
|
||||||
|
if ( temp[0] == '\0')
|
||||||
|
globals.commlog = DEFAULT_COMMLOG;
|
||||||
|
else
|
||||||
|
globals.commlog = atoi(temp);
|
||||||
|
|
||||||
|
|
||||||
|
// Optimizer is stored in the driver section only
|
||||||
|
SQLGetPrivateProfileString(DBMS_NAME, INI_OPTIMIZER, "",
|
||||||
|
temp, sizeof(temp), ODBCINST_INI);
|
||||||
|
if ( temp[0] == '\0')
|
||||||
|
globals.disable_optimizer = DEFAULT_OPTIMIZER;
|
||||||
|
else
|
||||||
|
globals.disable_optimizer = atoi(temp);
|
||||||
|
|
||||||
|
|
||||||
|
// Recognize Unique Index is stored in the driver section only
|
||||||
|
SQLGetPrivateProfileString(DBMS_NAME, INI_UNIQUEINDEX, "",
|
||||||
|
temp, sizeof(temp), ODBCINST_INI);
|
||||||
|
if ( temp[0] == '\0')
|
||||||
|
globals.unique_index = DEFAULT_UNIQUEINDEX;
|
||||||
|
else
|
||||||
|
globals.unique_index = atoi(temp);
|
||||||
|
|
||||||
|
|
||||||
|
// Unknown Sizes is stored in the driver section AND per datasource
|
||||||
|
SQLGetPrivateProfileString(DBMS_NAME, INI_UNKNOWNSIZES, "",
|
||||||
|
temp, sizeof(temp), ODBCINST_INI);
|
||||||
|
if ( temp[0] == '\0')
|
||||||
|
globals.unknown_sizes = DEFAULT_UNKNOWNSIZES;
|
||||||
|
else
|
||||||
|
globals.unknown_sizes = atoi(temp);
|
||||||
|
|
||||||
|
|
||||||
|
// Readonly is stored in the driver section AND per datasource
|
||||||
|
SQLGetPrivateProfileString(DBMS_NAME, INI_READONLY, "",
|
||||||
|
temp, sizeof(temp), ODBCINST_INI);
|
||||||
|
if ( temp[0] == '\0')
|
||||||
|
globals.readonly = DEFAULT_READONLY;
|
||||||
|
else
|
||||||
|
globals.readonly = atoi(temp);
|
||||||
|
|
||||||
|
|
||||||
|
// UseDeclareFetch is stored in the driver section only
|
||||||
|
SQLGetPrivateProfileString(DBMS_NAME, INI_USEDECLAREFETCH, "",
|
||||||
|
temp, sizeof(temp), ODBCINST_INI);
|
||||||
|
if ( temp[0] == '\0')
|
||||||
|
globals.use_declarefetch = DEFAULT_USEDECLAREFETCH;
|
||||||
|
else
|
||||||
|
globals.use_declarefetch = atoi(temp);
|
||||||
|
|
||||||
|
|
||||||
|
// Max Varchar Size
|
||||||
|
SQLGetPrivateProfileString(DBMS_NAME, INI_MAXVARCHARSIZE, "",
|
||||||
|
temp, sizeof(temp), ODBCINST_INI);
|
||||||
|
if ( temp[0] == '\0')
|
||||||
|
globals.max_varchar_size = MAX_VARCHAR_SIZE;
|
||||||
|
else
|
||||||
|
globals.max_varchar_size = atoi(temp);
|
||||||
|
|
||||||
|
// Max TextField Size
|
||||||
|
SQLGetPrivateProfileString(DBMS_NAME, INI_MAXLONGVARCHARSIZE, "",
|
||||||
|
temp, sizeof(temp), ODBCINST_INI);
|
||||||
|
if ( temp[0] == '\0')
|
||||||
|
globals.max_longvarchar_size = TEXT_FIELD_SIZE;
|
||||||
|
else
|
||||||
|
globals.max_longvarchar_size = atoi(temp);
|
||||||
|
|
||||||
|
// Text As LongVarchar
|
||||||
|
SQLGetPrivateProfileString(DBMS_NAME, INI_TEXTASLONGVARCHAR, "",
|
||||||
|
temp, sizeof(temp), ODBCINST_INI);
|
||||||
|
if ( temp[0] == '\0')
|
||||||
|
globals.text_as_longvarchar = DEFAULT_TEXTASLONGVARCHAR;
|
||||||
|
else
|
||||||
|
globals.text_as_longvarchar = atoi(temp);
|
||||||
|
|
||||||
|
// Unknowns As LongVarchar
|
||||||
|
SQLGetPrivateProfileString(DBMS_NAME, INI_UNKNOWNSASLONGVARCHAR, "",
|
||||||
|
temp, sizeof(temp), ODBCINST_INI);
|
||||||
|
if ( temp[0] == '\0')
|
||||||
|
globals.unknowns_as_longvarchar = DEFAULT_UNKNOWNSASLONGVARCHAR;
|
||||||
|
else
|
||||||
|
globals.unknowns_as_longvarchar = atoi(temp);
|
||||||
|
|
||||||
|
// Bools As Char
|
||||||
|
SQLGetPrivateProfileString(DBMS_NAME, INI_BOOLSASCHAR, "",
|
||||||
|
temp, sizeof(temp), ODBCINST_INI);
|
||||||
|
if ( temp[0] == '\0')
|
||||||
|
globals.bools_as_char = DEFAULT_BOOLSASCHAR;
|
||||||
|
else
|
||||||
|
globals.bools_as_char = atoi(temp);
|
||||||
|
|
||||||
|
|
||||||
|
// Extra System Table prefixes
|
||||||
|
SQLGetPrivateProfileString(DBMS_NAME, INI_EXTRASYSTABLEPREFIXES, "@@@",
|
||||||
|
globals.extra_systable_prefixes, sizeof(globals.extra_systable_prefixes), ODBCINST_INI);
|
||||||
|
if ( ! strcmp(globals.extra_systable_prefixes, "@@@")) {
|
||||||
|
strcpy(globals.extra_systable_prefixes, DEFAULT_EXTRASYSTABLEPREFIXES);
|
||||||
|
}
|
||||||
|
mylog("globals.extra_systable_prefixes = '%s'\n", globals.extra_systable_prefixes);
|
||||||
|
|
||||||
|
|
||||||
|
// 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.fetch_max);
|
||||||
|
SQLWritePrivateProfileString(DBMS_NAME,
|
||||||
|
INI_FETCH, tmp, ODBCINST_INI);
|
||||||
|
|
||||||
|
sprintf(tmp, "%d", globals.commlog);
|
||||||
|
SQLWritePrivateProfileString(DBMS_NAME,
|
||||||
|
INI_COMMLOG, tmp, ODBCINST_INI);
|
||||||
|
|
||||||
|
sprintf(tmp, "%d", globals.disable_optimizer);
|
||||||
|
SQLWritePrivateProfileString(DBMS_NAME,
|
||||||
|
INI_OPTIMIZER, tmp, ODBCINST_INI);
|
||||||
|
|
||||||
|
sprintf(tmp, "%d", globals.unique_index);
|
||||||
|
SQLWritePrivateProfileString(DBMS_NAME,
|
||||||
|
INI_UNIQUEINDEX, tmp, ODBCINST_INI);
|
||||||
|
|
||||||
|
sprintf(tmp, "%d", globals.readonly);
|
||||||
|
SQLWritePrivateProfileString(DBMS_NAME,
|
||||||
|
INI_READONLY, tmp, ODBCINST_INI);
|
||||||
|
|
||||||
|
sprintf(tmp, "%d", globals.use_declarefetch);
|
||||||
|
SQLWritePrivateProfileString(DBMS_NAME,
|
||||||
|
INI_USEDECLAREFETCH, tmp, ODBCINST_INI);
|
||||||
|
|
||||||
|
sprintf(tmp, "%d", globals.unknown_sizes);
|
||||||
|
SQLWritePrivateProfileString(DBMS_NAME,
|
||||||
|
INI_UNKNOWNSIZES, tmp, ODBCINST_INI);
|
||||||
|
|
||||||
|
sprintf(tmp, "%d", globals.text_as_longvarchar);
|
||||||
|
SQLWritePrivateProfileString(DBMS_NAME,
|
||||||
|
INI_TEXTASLONGVARCHAR, tmp, ODBCINST_INI);
|
||||||
|
|
||||||
|
sprintf(tmp, "%d", globals.unknowns_as_longvarchar);
|
||||||
|
SQLWritePrivateProfileString(DBMS_NAME,
|
||||||
|
INI_UNKNOWNSASLONGVARCHAR, tmp, ODBCINST_INI);
|
||||||
|
|
||||||
|
sprintf(tmp, "%d", globals.bools_as_char);
|
||||||
|
SQLWritePrivateProfileString(DBMS_NAME,
|
||||||
|
INI_BOOLSASCHAR, tmp, ODBCINST_INI);
|
||||||
|
|
||||||
|
sprintf(tmp, "%d", globals.max_varchar_size);
|
||||||
|
SQLWritePrivateProfileString(DBMS_NAME,
|
||||||
|
INI_MAXVARCHARSIZE, tmp, ODBCINST_INI);
|
||||||
|
|
||||||
|
sprintf(tmp, "%d", globals.max_longvarchar_size);
|
||||||
|
SQLWritePrivateProfileString(DBMS_NAME,
|
||||||
|
INI_MAXLONGVARCHARSIZE, tmp, ODBCINST_INI);
|
||||||
|
|
||||||
|
SQLWritePrivateProfileString(DBMS_NAME,
|
||||||
|
INI_EXTRASYSTABLEPREFIXES, globals.extra_systable_prefixes, ODBCINST_INI);
|
||||||
|
|
||||||
|
SQLWritePrivateProfileString(DBMS_NAME,
|
||||||
|
INI_CONNSETTINGS, globals.conn_settings, ODBCINST_INI);
|
||||||
|
}
|
|
@ -0,0 +1,103 @@
|
||||||
|
|
||||||
|
/* File: dlg_specific.h
|
||||||
|
*
|
||||||
|
* Description: See "dlg_specific.c"
|
||||||
|
*
|
||||||
|
* Comments: See "notice.txt" for copyright and license information.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __DLG_SPECIFIC_H__
|
||||||
|
#define __DLG_SPECIFIC_H__
|
||||||
|
|
||||||
|
#include "psqlodbc.h"
|
||||||
|
#include "connection.h"
|
||||||
|
#include <windows.h>
|
||||||
|
#include <windowsx.h>
|
||||||
|
#include <odbcinst.h>
|
||||||
|
#include "resource.h"
|
||||||
|
|
||||||
|
/* Unknown data type sizes */
|
||||||
|
#define UNKNOWNS_AS_MAX 0
|
||||||
|
#define UNKNOWNS_AS_DONTKNOW 1
|
||||||
|
#define UNKNOWNS_AS_LONGEST 2
|
||||||
|
|
||||||
|
/* INI File Stuff */
|
||||||
|
#define ODBC_INI "ODBC.INI" /* ODBC initialization file */
|
||||||
|
#define ODBCINST_INI "ODBCINST.INI" /* ODBC Installation file */
|
||||||
|
|
||||||
|
#define INI_DSN DBMS_NAME /* Name of default Datasource in ini file (not used?) */
|
||||||
|
#define INI_KDESC "Description" /* Data source description */
|
||||||
|
#define INI_SERVER "Servername" /* Name of Server running the Postgres service */
|
||||||
|
#define INI_PORT "Port" /* Port on which the Postmaster is listening */
|
||||||
|
#define INI_DATABASE "Database" /* Database Name */
|
||||||
|
#define INI_USER "Username" /* Default User Name */
|
||||||
|
#define INI_PASSWORD "Password" /* Default Password */
|
||||||
|
#define INI_DEBUG "Debug" /* Debug flag */
|
||||||
|
#define INI_FETCH "Fetch" /* Fetch Max Count */
|
||||||
|
#define INI_SOCKET "Socket" /* Socket buffer size */
|
||||||
|
#define INI_READONLY "ReadOnly" /* Database is read only */
|
||||||
|
#define INI_COMMLOG "CommLog" /* Communication to backend logging */
|
||||||
|
#define INI_PROTOCOL "Protocol" /* What protocol (6.2) */
|
||||||
|
#define INI_OPTIMIZER "Optimizer" /* Use backend genetic optimizer */
|
||||||
|
#define INI_CONNSETTINGS "ConnSettings" /* Anything to send to backend on successful connection */
|
||||||
|
#define INI_UNIQUEINDEX "UniqueIndex" /* Recognize unique indexes */
|
||||||
|
#define INI_UNKNOWNSIZES "UnknownSizes" /* How to handle unknown result set sizes */
|
||||||
|
|
||||||
|
#define INI_USEDECLAREFETCH "UseDeclareFetch" /* Use Declare/Fetch cursors */
|
||||||
|
|
||||||
|
/* More ini stuff */
|
||||||
|
#define INI_TEXTASLONGVARCHAR "TextAsLongVarchar"
|
||||||
|
#define INI_UNKNOWNSASLONGVARCHAR "UnknownsAsLongVarchar"
|
||||||
|
#define INI_BOOLSASCHAR "BoolsAsChar"
|
||||||
|
#define INI_MAXVARCHARSIZE "MaxVarcharSize"
|
||||||
|
#define INI_MAXLONGVARCHARSIZE "MaxLongVarcharSize"
|
||||||
|
|
||||||
|
#define INI_FAKEOIDINDEX "FakeOidIndex"
|
||||||
|
#define INI_SHOWOIDCOLUMN "ShowOidColumn"
|
||||||
|
#define INI_SHOWSYSTEMTABLES "ShowSystemTables"
|
||||||
|
#define INI_EXTRASYSTABLEPREFIXES "ExtraSysTablePrefixes"
|
||||||
|
|
||||||
|
/* Connection Defaults */
|
||||||
|
#define DEFAULT_PORT "5432"
|
||||||
|
#define DEFAULT_READONLY 1
|
||||||
|
#define DEFAULT_USEDECLAREFETCH 1
|
||||||
|
#define DEFAULT_TEXTASLONGVARCHAR 1
|
||||||
|
#define DEFAULT_UNKNOWNSASLONGVARCHAR 0
|
||||||
|
#define DEFAULT_BOOLSASCHAR 1
|
||||||
|
#define DEFAULT_OPTIMIZER 1 // disable
|
||||||
|
#define DEFAULT_UNIQUEINDEX 0 // dont recognize
|
||||||
|
#define DEFAULT_COMMLOG 0 // dont log
|
||||||
|
#define DEFAULT_UNKNOWNSIZES UNKNOWNS_AS_MAX
|
||||||
|
|
||||||
|
|
||||||
|
#define DEFAULT_FAKEOIDINDEX 0
|
||||||
|
#define DEFAULT_SHOWOIDCOLUMN 0
|
||||||
|
#define DEFAULT_SHOWSYSTEMTABLES 0 // dont show system tables
|
||||||
|
|
||||||
|
#define DEFAULT_EXTRASYSTABLEPREFIXES "dd_;"
|
||||||
|
|
||||||
|
/* prototypes */
|
||||||
|
void updateGlobals(void);
|
||||||
|
void getGlobalDefaults(void);
|
||||||
|
|
||||||
|
void SetDlgStuff(HWND hdlg, ConnInfo *ci);
|
||||||
|
void GetDlgStuff(HWND hdlg, ConnInfo *ci);
|
||||||
|
|
||||||
|
int CALLBACK driver_optionsProc(HWND hdlg,
|
||||||
|
WORD wMsg,
|
||||||
|
WPARAM wParam,
|
||||||
|
LPARAM lParam);
|
||||||
|
int CALLBACK ds_optionsProc(HWND hdlg,
|
||||||
|
WORD wMsg,
|
||||||
|
WPARAM wParam,
|
||||||
|
LPARAM lParam);
|
||||||
|
|
||||||
|
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
|
|
@ -1,16 +1,16 @@
|
||||||
|
|
||||||
/* Module: drvconn.c
|
/* Module: drvconn.c
|
||||||
*
|
*
|
||||||
* Description: This module contains only routines related to
|
* Description: This module contains only routines related to
|
||||||
* implementing SQLDriverConnect.
|
* implementing SQLDriverConnect.
|
||||||
*
|
*
|
||||||
* Classes: n/a
|
* Classes: n/a
|
||||||
*
|
*
|
||||||
* API functions: SQLDriverConnect
|
* API functions: SQLDriverConnect
|
||||||
*
|
*
|
||||||
* Comments: See "notice.txt" for copyright and license information.
|
* Comments: See "notice.txt" for copyright and license information.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
@ -26,15 +26,17 @@
|
||||||
#include <odbcinst.h>
|
#include <odbcinst.h>
|
||||||
#include "resource.h"
|
#include "resource.h"
|
||||||
|
|
||||||
|
#include "dlg_specific.h"
|
||||||
|
|
||||||
/* prototypes */
|
/* prototypes */
|
||||||
BOOL FAR PASCAL dconn_FDriverConnectProc(HWND hdlg, UINT wMsg, WPARAM wParam, LPARAM lParam);
|
BOOL FAR PASCAL dconn_FDriverConnectProc(HWND hdlg, UINT wMsg, WPARAM wParam, LPARAM lParam);
|
||||||
RETCODE dconn_DoDialog(HWND hwnd, ConnInfo *ci);
|
RETCODE dconn_DoDialog(HWND hwnd, ConnInfo *ci);
|
||||||
void dconn_get_connect_attributes(UCHAR FAR *connect_string, ConnInfo *ci);
|
void dconn_get_connect_attributes(UCHAR FAR *connect_string, ConnInfo *ci);
|
||||||
|
|
||||||
|
|
||||||
extern HINSTANCE NEAR s_hModule; /* Saved module handle. */
|
extern HINSTANCE NEAR s_hModule; /* Saved module handle. */
|
||||||
extern GLOBAL_VALUES globals;
|
extern GLOBAL_VALUES globals;
|
||||||
|
|
||||||
|
|
||||||
RETCODE SQL_API SQLDriverConnect(
|
RETCODE SQL_API SQLDriverConnect(
|
||||||
HDBC hdbc,
|
HDBC hdbc,
|
||||||
HWND hwnd,
|
HWND hwnd,
|
||||||
|
@ -67,10 +69,10 @@ char password_required = FALSE;
|
||||||
// If the ConnInfo in the hdbc is missing anything,
|
// If the ConnInfo in the hdbc is missing anything,
|
||||||
// this function will fill them in from the registry (assuming
|
// this function will fill them in from the registry (assuming
|
||||||
// of course there is a DSN given -- if not, it does nothing!)
|
// of course there is a DSN given -- if not, it does nothing!)
|
||||||
CC_DSN_info(conn, CONN_DONT_OVERWRITE);
|
getDSNinfo(ci, CONN_DONT_OVERWRITE);
|
||||||
|
|
||||||
// Fill in any default parameters if they are not there.
|
// Fill in any default parameters if they are not there.
|
||||||
CC_set_defaults(conn);
|
getDSNdefaults(ci);
|
||||||
|
|
||||||
dialog:
|
dialog:
|
||||||
ci->focus_password = password_required;
|
ci->focus_password = password_required;
|
||||||
|
@ -102,14 +104,14 @@ dialog:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Password is not a required parameter unless authentication asks for it.
|
/* Password is not a required parameter unless authentication asks for it.
|
||||||
For now, I think its better to just let the application ask over and over until
|
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)
|
a password is entered (the user can always hit Cancel to get out)
|
||||||
*/
|
*/
|
||||||
if( ci->username[0] == '\0' ||
|
if( ci->username[0] == '\0' ||
|
||||||
ci->server[0] == '\0' ||
|
ci->server[0] == '\0' ||
|
||||||
ci->database[0] == '\0' ||
|
ci->database[0] == '\0' ||
|
||||||
ci->port[0] == '\0') {
|
ci->port[0] == '\0') {
|
||||||
// (password_required && ci->password[0] == '\0'))
|
// (password_required && ci->password[0] == '\0'))
|
||||||
|
|
||||||
return SQL_NO_DATA_FOUND;
|
return SQL_NO_DATA_FOUND;
|
||||||
|
@ -119,19 +121,7 @@ dialog:
|
||||||
|
|
||||||
// return the completed string to the caller.
|
// return the completed string to the caller.
|
||||||
|
|
||||||
char got_dsn = (ci->dsn[0] != '\0');
|
makeConnectString(connect_string, ci);
|
||||||
|
|
||||||
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) {
|
if(pcbConnStrOut) {
|
||||||
*pcbConnStrOut = strlen(connect_string);
|
*pcbConnStrOut = strlen(connect_string);
|
||||||
|
@ -169,7 +159,7 @@ int dialog_result;
|
||||||
mylog("dconn_DoDialog: ci = %u\n", ci);
|
mylog("dconn_DoDialog: ci = %u\n", ci);
|
||||||
|
|
||||||
if(hwnd) {
|
if(hwnd) {
|
||||||
dialog_result = DialogBoxParam(s_hModule, MAKEINTRESOURCE(DRIVERCONNDIALOG),
|
dialog_result = DialogBoxParam(s_hModule, MAKEINTRESOURCE(DLG_CONFIG),
|
||||||
hwnd, dconn_FDriverConnectProc, (LPARAM) ci);
|
hwnd, dconn_FDriverConnectProc, (LPARAM) ci);
|
||||||
if(!dialog_result || (dialog_result == -1)) {
|
if(!dialog_result || (dialog_result == -1)) {
|
||||||
return SQL_NO_DATA_FOUND;
|
return SQL_NO_DATA_FOUND;
|
||||||
|
@ -188,34 +178,37 @@ BOOL FAR PASCAL dconn_FDriverConnectProc(
|
||||||
WPARAM wParam,
|
WPARAM wParam,
|
||||||
LPARAM lParam)
|
LPARAM lParam)
|
||||||
{
|
{
|
||||||
static ConnInfo *ci;
|
ConnInfo *ci;
|
||||||
|
|
||||||
switch (wMsg) {
|
switch (wMsg) {
|
||||||
case WM_INITDIALOG:
|
case WM_INITDIALOG:
|
||||||
ci = (ConnInfo *) lParam; // Save the ConnInfo for the "OK"
|
ci = (ConnInfo *) lParam;
|
||||||
|
|
||||||
SetDlgItemText(hdlg, SERVER_EDIT, ci->server);
|
/* Change the caption for the setup dialog */
|
||||||
SetDlgItemText(hdlg, DATABASE_EDIT, ci->database);
|
SetWindowText(hdlg, "PostgreSQL Connection");
|
||||||
SetDlgItemText(hdlg, USERNAME_EDIT, ci->username);
|
|
||||||
SetDlgItemText(hdlg, PASSWORD_EDIT, ci->password);
|
SetWindowText(GetDlgItem(hdlg, IDC_DATASOURCE), "Connection");
|
||||||
SetDlgItemText(hdlg, PORT_EDIT, ci->port);
|
|
||||||
CheckDlgButton(hdlg, READONLY_EDIT, atoi(ci->readonly));
|
/* Hide the DSN and description fields */
|
||||||
|
ShowWindow(GetDlgItem(hdlg, IDC_DSNAMETEXT), SW_HIDE);
|
||||||
CheckDlgButton(hdlg, PG62_EDIT, PROTOCOL_62(ci));
|
ShowWindow(GetDlgItem(hdlg, IDC_DSNAME), SW_HIDE);
|
||||||
|
ShowWindow(GetDlgItem(hdlg, IDC_DESCTEXT), SW_HIDE);
|
||||||
/* The driver connect dialog box allows manipulating this global variable */
|
ShowWindow(GetDlgItem(hdlg, IDC_DESC), SW_HIDE);
|
||||||
CheckDlgButton(hdlg, COMMLOG_EDIT, globals.commlog);
|
|
||||||
|
SetWindowLong(hdlg, DWL_USER, lParam);// Save the ConnInfo for the "OK"
|
||||||
|
|
||||||
|
SetDlgStuff(hdlg, ci);
|
||||||
|
|
||||||
if (ci->database[0] == '\0')
|
if (ci->database[0] == '\0')
|
||||||
; /* default focus */
|
; /* default focus */
|
||||||
else if (ci->server[0] == '\0')
|
else if (ci->server[0] == '\0')
|
||||||
SetFocus(GetDlgItem(hdlg, SERVER_EDIT));
|
SetFocus(GetDlgItem(hdlg, IDC_SERVER));
|
||||||
else if (ci->port[0] == '\0')
|
else if (ci->port[0] == '\0')
|
||||||
SetFocus(GetDlgItem(hdlg, PORT_EDIT));
|
SetFocus(GetDlgItem(hdlg, IDC_PORT));
|
||||||
else if (ci->username[0] == '\0')
|
else if (ci->username[0] == '\0')
|
||||||
SetFocus(GetDlgItem(hdlg, USERNAME_EDIT));
|
SetFocus(GetDlgItem(hdlg, IDC_USER));
|
||||||
else if (ci->focus_password)
|
else if (ci->focus_password)
|
||||||
SetFocus(GetDlgItem(hdlg, PASSWORD_EDIT));
|
SetFocus(GetDlgItem(hdlg, IDC_PASSWORD));
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -223,26 +216,30 @@ static ConnInfo *ci;
|
||||||
switch (GET_WM_COMMAND_ID(wParam, lParam)) {
|
switch (GET_WM_COMMAND_ID(wParam, lParam)) {
|
||||||
case IDOK:
|
case IDOK:
|
||||||
|
|
||||||
GetDlgItemText(hdlg, SERVER_EDIT, ci->server, sizeof(ci->server));
|
ci = (ConnInfo *) GetWindowLong(hdlg, DWL_USER);
|
||||||
GetDlgItemText(hdlg, DATABASE_EDIT, ci->database, sizeof(ci->database));
|
|
||||||
GetDlgItemText(hdlg, USERNAME_EDIT, ci->username, sizeof(ci->username));
|
GetDlgStuff(hdlg, ci);
|
||||||
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:
|
case IDCANCEL:
|
||||||
EndDialog(hdlg, GET_WM_COMMAND_ID(wParam, lParam) == IDOK);
|
EndDialog(hdlg, GET_WM_COMMAND_ID(wParam, lParam) == IDOK);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
|
case IDC_DRIVER:
|
||||||
|
|
||||||
|
DialogBoxParam(s_hModule, MAKEINTRESOURCE(DLG_OPTIONS_DRV),
|
||||||
|
hdlg, driver_optionsProc, (LPARAM) NULL);
|
||||||
|
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case IDC_DATASOURCE:
|
||||||
|
|
||||||
|
ci = (ConnInfo *) GetWindowLong(hdlg, DWL_USER);
|
||||||
|
DialogBoxParam(s_hModule, MAKEINTRESOURCE(DLG_OPTIONS_DS),
|
||||||
|
hdlg, ds_optionsProc, (LPARAM) ci);
|
||||||
|
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -286,42 +283,12 @@ char *strtok_arg;
|
||||||
if( !attribute || !value)
|
if( !attribute || !value)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/*********************************************************/
|
// Copy the appropriate value to the conninfo
|
||||||
/* PARSE ATTRIBUTES */
|
copyAttributes(ci, attribute, value);
|
||||||
/*********************************************************/
|
|
||||||
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);
|
free(our_connect_string);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
|
|
||||||
/* Module: environ.c
|
/* Module: environ.c
|
||||||
*
|
*
|
||||||
* Description: This module contains routines related to
|
* Description: This module contains routines related to
|
||||||
* the environment, such as storing connection handles,
|
* the environment, such as storing connection handles,
|
||||||
* and returning errors.
|
* and returning errors.
|
||||||
*
|
*
|
||||||
* Classes: EnvironmentClass (Functions prefix: "EN_")
|
* Classes: EnvironmentClass (Functions prefix: "EN_")
|
||||||
*
|
*
|
||||||
* API functions: SQLAllocEnv, SQLFreeEnv, SQLError
|
* API functions: SQLAllocEnv, SQLFreeEnv, SQLError
|
||||||
*
|
*
|
||||||
* Comments: See "notice.txt" for copyright and license information.
|
* Comments: See "notice.txt" for copyright and license information.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "environ.h"
|
#include "environ.h"
|
||||||
#include "connection.h"
|
#include "connection.h"
|
||||||
|
@ -113,6 +113,10 @@ int status;
|
||||||
strcpy(szSqlState, "08S01");
|
strcpy(szSqlState, "08S01");
|
||||||
// communication link failure
|
// communication link failure
|
||||||
break;
|
break;
|
||||||
|
case STMT_CREATE_TABLE_ERROR:
|
||||||
|
strcpy(szSqlState, "S0001");
|
||||||
|
// table already exists
|
||||||
|
break;
|
||||||
case STMT_STATUS_ERROR:
|
case STMT_STATUS_ERROR:
|
||||||
case STMT_SEQUENCE_ERROR:
|
case STMT_SEQUENCE_ERROR:
|
||||||
strcpy(szSqlState, "S1010");
|
strcpy(szSqlState, "S1010");
|
||||||
|
@ -158,6 +162,12 @@ int status;
|
||||||
break;
|
break;
|
||||||
case STMT_OPTION_VALUE_CHANGED:
|
case STMT_OPTION_VALUE_CHANGED:
|
||||||
strcpy(szSqlState, "01S02");
|
strcpy(szSqlState, "01S02");
|
||||||
|
break;
|
||||||
|
case STMT_INVALID_CURSOR_NAME:
|
||||||
|
strcpy(szSqlState, "34000");
|
||||||
|
break;
|
||||||
|
case STMT_NO_CURSOR_NAME:
|
||||||
|
strcpy(szSqlState, "S1015");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
strcpy(szSqlState, "S1000");
|
strcpy(szSqlState, "S1000");
|
||||||
|
@ -213,10 +223,10 @@ int status;
|
||||||
case CONN_OPENDB_ERROR:
|
case CONN_OPENDB_ERROR:
|
||||||
strcpy(szSqlState, "08001");
|
strcpy(szSqlState, "08001");
|
||||||
// unable to connect to data source
|
// unable to connect to data source
|
||||||
break;
|
break;
|
||||||
case CONN_INVALID_AUTHENTICATION:
|
case CONN_INVALID_AUTHENTICATION:
|
||||||
case CONN_AUTH_TYPE_UNSUPPORTED:
|
case CONN_AUTH_TYPE_UNSUPPORTED:
|
||||||
strcpy(szSqlState, "28000");
|
strcpy(szSqlState, "28000");
|
||||||
break;
|
break;
|
||||||
case CONN_STMT_ALLOC_ERROR:
|
case CONN_STMT_ALLOC_ERROR:
|
||||||
strcpy(szSqlState, "S1001");
|
strcpy(szSqlState, "S1001");
|
||||||
|
@ -339,7 +349,7 @@ EnvironmentClass *rv;
|
||||||
rv->errormsg = 0;
|
rv->errormsg = 0;
|
||||||
rv->errornumber = 0;
|
rv->errornumber = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -356,7 +366,7 @@ char rv = 1;
|
||||||
// the source--they should not be freed
|
// the source--they should not be freed
|
||||||
|
|
||||||
/* Free any connections belonging to this environment */
|
/* Free any connections belonging to this environment */
|
||||||
for (lf = 0; lf < MAX_CONNECTIONS; lf++) {
|
for (lf = 0; lf < MAX_CONNECTIONS; lf++) {
|
||||||
if (conns[lf] && conns[lf]->henv == self)
|
if (conns[lf] && conns[lf]->henv == self)
|
||||||
rv = rv && CC_Destructor(conns[lf]);
|
rv = rv && CC_Destructor(conns[lf]);
|
||||||
}
|
}
|
||||||
|
@ -383,16 +393,16 @@ char
|
||||||
EN_add_connection(EnvironmentClass *self, ConnectionClass *conn)
|
EN_add_connection(EnvironmentClass *self, ConnectionClass *conn)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
mylog("EN_add_connection: self = %u, conn = %u\n", self, conn);
|
mylog("EN_add_connection: self = %u, conn = %u\n", self, conn);
|
||||||
|
|
||||||
for (i = 0; i < MAX_CONNECTIONS; i++) {
|
for (i = 0; i < MAX_CONNECTIONS; i++) {
|
||||||
if ( ! conns[i]) {
|
if ( ! conns[i]) {
|
||||||
conn->henv = self;
|
conn->henv = self;
|
||||||
conns[i] = conn;
|
conns[i] = conn;
|
||||||
|
|
||||||
mylog(" added at i =%d, conn->henv = %u, conns[i]->henv = %u\n",
|
mylog(" added at i =%d, conn->henv = %u, conns[i]->henv = %u\n",
|
||||||
i, conn->henv, conns[i]->henv);
|
i, conn->henv, conns[i]->henv);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
|
|
||||||
/* File: environ.h
|
/* File: environ.h
|
||||||
*
|
*
|
||||||
* Description: See "environ.c"
|
* Description: See "environ.c"
|
||||||
*
|
*
|
||||||
* Comments: See "notice.txt" for copyright and license information.
|
* Comments: See "notice.txt" for copyright and license information.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __ENVIRON_H__
|
#ifndef __ENVIRON_H__
|
||||||
#define __ENVIRON_H__
|
#define __ENVIRON_H__
|
||||||
|
@ -13,15 +13,16 @@
|
||||||
#include "psqlodbc.h"
|
#include "psqlodbc.h"
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <sql.h>
|
#include <sql.h>
|
||||||
|
#include <sqlext.h>
|
||||||
|
|
||||||
#define ENV_ALLOC_ERROR 1
|
#define ENV_ALLOC_ERROR 1
|
||||||
|
|
||||||
/********** Environment Handle *************/
|
/********** Environment Handle *************/
|
||||||
struct EnvironmentClass_ {
|
struct EnvironmentClass_ {
|
||||||
char *errormsg;
|
char *errormsg;
|
||||||
int errornumber;
|
int errornumber;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Environment prototypes */
|
/* Environment prototypes */
|
||||||
EnvironmentClass *EN_Constructor(void);
|
EnvironmentClass *EN_Constructor(void);
|
||||||
char EN_Destructor(EnvironmentClass *self);
|
char EN_Destructor(EnvironmentClass *self);
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
|
|
||||||
/* Module: execute.c
|
/* Module: execute.c
|
||||||
*
|
*
|
||||||
* Description: This module contains routines related to
|
* Description: This module contains routines related to
|
||||||
* preparing and executing an SQL statement.
|
* preparing and executing an SQL statement.
|
||||||
*
|
*
|
||||||
* Classes: n/a
|
* Classes: n/a
|
||||||
*
|
*
|
||||||
* API functions: SQLPrepare, SQLExecute, SQLExecDirect, SQLTransact,
|
* API functions: SQLPrepare, SQLExecute, SQLExecDirect, SQLTransact,
|
||||||
* SQLCancel, SQLNativeSql, SQLParamData, SQLPutData
|
* SQLCancel, SQLNativeSql, SQLParamData, SQLPutData
|
||||||
*
|
*
|
||||||
* Comments: See "notice.txt" for copyright and license information.
|
* Comments: See "notice.txt" for copyright and license information.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "psqlodbc.h"
|
#include "psqlodbc.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
@ -24,6 +24,7 @@
|
||||||
#include "qresult.h"
|
#include "qresult.h"
|
||||||
#include "convert.h"
|
#include "convert.h"
|
||||||
#include "bind.h"
|
#include "bind.h"
|
||||||
|
#include "lobj.h"
|
||||||
|
|
||||||
|
|
||||||
// Perform a Prepare on the SQL statement
|
// Perform a Prepare on the SQL statement
|
||||||
|
@ -36,72 +37,29 @@ StatementClass *self = (StatementClass *) hstmt;
|
||||||
if ( ! self)
|
if ( ! self)
|
||||||
return SQL_INVALID_HANDLE;
|
return SQL_INVALID_HANDLE;
|
||||||
|
|
||||||
/* CC: According to the ODBC specs it is valid to call SQLPrepare mulitple times. In that case,
|
/* According to the ODBC specs it is valid to call SQLPrepare mulitple times.
|
||||||
the bound SQL statement is replaced by the new one */
|
In that case, the bound SQL statement is replaced by the new one
|
||||||
|
*/
|
||||||
|
|
||||||
switch (self->status) {
|
switch(self->status) {
|
||||||
case STMT_PREMATURE:
|
case STMT_PREMATURE:
|
||||||
mylog("**** SQLPrepare: STMT_PREMATURE, recycle\n");
|
mylog("**** SQLPrepare: STMT_PREMATURE, recycle\n");
|
||||||
|
|
||||||
SC_recycle_statement(self); /* recycle the statement, but do not remove parameter bindings */
|
SC_recycle_statement(self); /* recycle the statement, but do not remove parameter bindings */
|
||||||
|
break;
|
||||||
|
|
||||||
/* NO Break! -- Contiue the same way as with a newly allocated statement ! */
|
case STMT_FINISHED:
|
||||||
|
mylog("**** SQLPrepare: STMT_FINISHED, recycle\n");
|
||||||
|
SC_recycle_statement(self); /* recycle the statement, but do not remove parameter bindings */
|
||||||
|
break;
|
||||||
|
|
||||||
case STMT_ALLOCATED:
|
case STMT_ALLOCATED:
|
||||||
// it is not really necessary to do any conversion of the statement
|
|
||||||
// here--just copy it, and deal with it when it's ready to be
|
|
||||||
// executed.
|
|
||||||
mylog("**** SQLPrepare: STMT_ALLOCATED, copy\n");
|
mylog("**** SQLPrepare: STMT_ALLOCATED, copy\n");
|
||||||
|
|
||||||
self->statement = make_string(szSqlStr, cbSqlStr, NULL);
|
|
||||||
if ( ! self->statement) {
|
|
||||||
self->errornumber = STMT_NO_MEMORY_ERROR;
|
|
||||||
self->errormsg = "No memory available to store statement";
|
|
||||||
return SQL_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
self->statement_type = statement_type(self->statement);
|
|
||||||
|
|
||||||
// Check if connection is readonly (only selects are allowed)
|
|
||||||
if ( CC_is_readonly(self->hdbc) && self->statement_type != STMT_TYPE_SELECT ) {
|
|
||||||
self->errornumber = STMT_EXEC_ERROR;
|
|
||||||
self->errormsg = "Connection is readonly, only select statements are allowed.";
|
|
||||||
return SQL_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
self->prepare = TRUE;
|
|
||||||
self->status = STMT_READY;
|
self->status = STMT_READY;
|
||||||
|
break;
|
||||||
|
|
||||||
return SQL_SUCCESS;
|
case STMT_READY:
|
||||||
|
|
||||||
case STMT_READY: /* SQLPrepare has already been called -- Just changed the SQL statement that is assigned to the handle */
|
|
||||||
mylog("**** SQLPrepare: STMT_READY, change SQL\n");
|
mylog("**** SQLPrepare: STMT_READY, change SQL\n");
|
||||||
|
break;
|
||||||
if (self->statement)
|
|
||||||
free(self->statement);
|
|
||||||
|
|
||||||
self->statement = make_string(szSqlStr, cbSqlStr, NULL);
|
|
||||||
if ( ! self->statement) {
|
|
||||||
self->errornumber = STMT_NO_MEMORY_ERROR;
|
|
||||||
self->errormsg = "No memory available to store statement";
|
|
||||||
return SQL_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
self->prepare = TRUE;
|
|
||||||
self->statement_type = statement_type(self->statement);
|
|
||||||
|
|
||||||
// Check if connection is readonly (only selects are allowed)
|
|
||||||
if ( CC_is_readonly(self->hdbc) && self->statement_type != STMT_TYPE_SELECT ) {
|
|
||||||
self->errornumber = STMT_EXEC_ERROR;
|
|
||||||
self->errormsg = "Connection is readonly, only select statements are allowed.";
|
|
||||||
return SQL_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
return SQL_SUCCESS;
|
|
||||||
|
|
||||||
case STMT_FINISHED:
|
|
||||||
mylog("**** SQLPrepare: STMT_FINISHED\n");
|
|
||||||
/* No BREAK: continue as with STMT_EXECUTING */
|
|
||||||
|
|
||||||
case STMT_EXECUTING:
|
case STMT_EXECUTING:
|
||||||
mylog("**** SQLPrepare: STMT_EXECUTING, error!\n");
|
mylog("**** SQLPrepare: STMT_EXECUTING, error!\n");
|
||||||
|
@ -116,6 +74,30 @@ StatementClass *self = (StatementClass *) hstmt;
|
||||||
self->errormsg = "An Internal Error has occured -- Unknown statement status.";
|
self->errormsg = "An Internal Error has occured -- Unknown statement status.";
|
||||||
return SQL_ERROR;
|
return SQL_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (self->statement)
|
||||||
|
free(self->statement);
|
||||||
|
|
||||||
|
self->statement = make_string(szSqlStr, cbSqlStr, NULL);
|
||||||
|
if ( ! self->statement) {
|
||||||
|
self->errornumber = STMT_NO_MEMORY_ERROR;
|
||||||
|
self->errormsg = "No memory available to store statement";
|
||||||
|
return SQL_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
self->prepare = TRUE;
|
||||||
|
self->statement_type = statement_type(self->statement);
|
||||||
|
|
||||||
|
// Check if connection is readonly (only selects are allowed)
|
||||||
|
if ( CC_is_readonly(self->hdbc) && STMT_UPDATE(self)) {
|
||||||
|
self->errornumber = STMT_EXEC_ERROR;
|
||||||
|
self->errormsg = "Connection is readonly, only select statements are allowed.";
|
||||||
|
return SQL_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SQL_SUCCESS;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - -
|
// - - - - - - - - -
|
||||||
|
@ -150,7 +132,7 @@ StatementClass *stmt = (StatementClass *) hstmt;
|
||||||
stmt->statement_type = statement_type(stmt->statement);
|
stmt->statement_type = statement_type(stmt->statement);
|
||||||
|
|
||||||
// Check if connection is readonly (only selects are allowed)
|
// Check if connection is readonly (only selects are allowed)
|
||||||
if ( CC_is_readonly(stmt->hdbc) && stmt->statement_type != STMT_TYPE_SELECT ) {
|
if ( CC_is_readonly(stmt->hdbc) && STMT_UPDATE(stmt)) {
|
||||||
stmt->errornumber = STMT_EXEC_ERROR;
|
stmt->errornumber = STMT_EXEC_ERROR;
|
||||||
stmt->errormsg = "Connection is readonly, only select statements are allowed.";
|
stmt->errormsg = "Connection is readonly, only select statements are allowed.";
|
||||||
return SQL_ERROR;
|
return SQL_ERROR;
|
||||||
|
@ -165,10 +147,10 @@ StatementClass *stmt = (StatementClass *) hstmt;
|
||||||
RETCODE SQL_API SQLExecute(
|
RETCODE SQL_API SQLExecute(
|
||||||
HSTMT hstmt)
|
HSTMT hstmt)
|
||||||
{
|
{
|
||||||
StatementClass *stmt = (StatementClass *) hstmt;
|
StatementClass *stmt = (StatementClass *) hstmt;
|
||||||
ConnectionClass *conn;
|
ConnectionClass *conn;
|
||||||
int i, retval;
|
int i, retval;
|
||||||
|
|
||||||
|
|
||||||
if ( ! stmt)
|
if ( ! stmt)
|
||||||
return SQL_INVALID_HANDLE;
|
return SQL_INVALID_HANDLE;
|
||||||
|
@ -212,45 +194,45 @@ int i, retval;
|
||||||
stmt->errornumber = STMT_STATUS_ERROR;
|
stmt->errornumber = STMT_STATUS_ERROR;
|
||||||
stmt->errormsg = "The handle does not point to a statement that is ready to be executed";
|
stmt->errormsg = "The handle does not point to a statement that is ready to be executed";
|
||||||
return SQL_ERROR;
|
return SQL_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* The bound parameters could have possibly changed since the last execute
|
/* The bound parameters could have possibly changed since the last execute
|
||||||
of this statement? Therefore check for params and re-copy.
|
of this statement? Therefore check for params and re-copy.
|
||||||
*/
|
*/
|
||||||
stmt->data_at_exec = -1;
|
stmt->data_at_exec = -1;
|
||||||
for (i = 0; i < stmt->parameters_allocated; i++) {
|
for (i = 0; i < stmt->parameters_allocated; i++) {
|
||||||
/* Check for data at execution parameters */
|
/* Check for data at execution parameters */
|
||||||
if ( stmt->parameters[i].data_at_exec == TRUE) {
|
if ( stmt->parameters[i].data_at_exec == TRUE) {
|
||||||
if (stmt->data_at_exec < 0)
|
if (stmt->data_at_exec < 0)
|
||||||
stmt->data_at_exec = 1;
|
stmt->data_at_exec = 1;
|
||||||
else
|
else
|
||||||
stmt->data_at_exec++;
|
stmt->data_at_exec++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// If there are some data at execution parameters, return need data
|
// If there are some data at execution parameters, return need data
|
||||||
// SQLParamData and SQLPutData will be used to send params and execute the statement.
|
// SQLParamData and SQLPutData will be used to send params and execute the statement.
|
||||||
if (stmt->data_at_exec > 0)
|
if (stmt->data_at_exec > 0)
|
||||||
return SQL_NEED_DATA;
|
return SQL_NEED_DATA;
|
||||||
|
|
||||||
|
|
||||||
mylog("SQLExecute: copying statement params: trans_status=%d, len=%d, stmt='%s'\n", conn->transact_status, strlen(stmt->statement), stmt->statement);
|
mylog("SQLExecute: copying statement params: trans_status=%d, len=%d, stmt='%s'\n", conn->transact_status, strlen(stmt->statement), stmt->statement);
|
||||||
|
|
||||||
// Create the statement with parameters substituted.
|
// Create the statement with parameters substituted.
|
||||||
retval = copy_statement_with_parameters(stmt);
|
retval = copy_statement_with_parameters(stmt);
|
||||||
if( retval != SQL_SUCCESS)
|
if( retval != SQL_SUCCESS)
|
||||||
/* error msg passed from above */
|
/* error msg passed from above */
|
||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
mylog(" stmt_with_params = '%s'\n", stmt->stmt_with_params);
|
mylog(" stmt_with_params = '%s'\n", stmt->stmt_with_params);
|
||||||
|
|
||||||
|
|
||||||
return SC_execute(stmt);
|
return SC_execute(stmt);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// - - - - - - - - -
|
// - - - - - - - - -
|
||||||
RETCODE SQL_API SQLTransact(
|
RETCODE SQL_API SQLTransact(
|
||||||
|
@ -325,24 +307,24 @@ mylog("**** SQLTransact: hdbc=%u, henv=%u\n", hdbc, henv);
|
||||||
RETCODE SQL_API SQLCancel(
|
RETCODE SQL_API SQLCancel(
|
||||||
HSTMT hstmt) // Statement to cancel.
|
HSTMT hstmt) // Statement to cancel.
|
||||||
{
|
{
|
||||||
StatementClass *stmt = (StatementClass *) hstmt;
|
StatementClass *stmt = (StatementClass *) hstmt;
|
||||||
|
|
||||||
// Check if this can handle canceling in the middle of a SQLPutData?
|
// Check if this can handle canceling in the middle of a SQLPutData?
|
||||||
if ( ! stmt)
|
if ( ! stmt)
|
||||||
return SQL_INVALID_HANDLE;
|
return SQL_INVALID_HANDLE;
|
||||||
|
|
||||||
// Not in the middle of SQLParamData/SQLPutData so cancel like a close.
|
// Not in the middle of SQLParamData/SQLPutData so cancel like a close.
|
||||||
if (stmt->data_at_exec < 0)
|
if (stmt->data_at_exec < 0)
|
||||||
return SQLFreeStmt(hstmt, SQL_CLOSE);
|
return SQLFreeStmt(hstmt, SQL_CLOSE);
|
||||||
|
|
||||||
// In the middle of SQLParamData/SQLPutData, so cancel that.
|
// In the middle of SQLParamData/SQLPutData, so cancel that.
|
||||||
// Note, any previous data-at-exec buffers will be freed in the recycle
|
// Note, any previous data-at-exec buffers will be freed in the recycle
|
||||||
// if they call SQLExecDirect or SQLExecute again.
|
// if they call SQLExecDirect or SQLExecute again.
|
||||||
|
|
||||||
stmt->data_at_exec = -1;
|
stmt->data_at_exec = -1;
|
||||||
stmt->current_exec_param = -1;
|
stmt->current_exec_param = -1;
|
||||||
stmt->put_data = FALSE;
|
stmt->put_data = FALSE;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - -
|
// - - - - - - - - -
|
||||||
|
@ -371,45 +353,63 @@ RETCODE SQL_API SQLNativeSql(
|
||||||
RETCODE SQL_API SQLParamData(
|
RETCODE SQL_API SQLParamData(
|
||||||
HSTMT hstmt,
|
HSTMT hstmt,
|
||||||
PTR FAR *prgbValue)
|
PTR FAR *prgbValue)
|
||||||
{
|
{
|
||||||
StatementClass *stmt = (StatementClass *) hstmt;
|
StatementClass *stmt = (StatementClass *) hstmt;
|
||||||
int i, retval;
|
int i, retval;
|
||||||
|
|
||||||
if ( ! stmt)
|
if ( ! stmt)
|
||||||
return SQL_INVALID_HANDLE;
|
return SQL_INVALID_HANDLE;
|
||||||
|
|
||||||
if (stmt->data_at_exec < 0) {
|
mylog("SQLParamData, enter: data_at_exec=%d, params_alloc=%d\n",
|
||||||
stmt->errornumber = STMT_SEQUENCE_ERROR;
|
stmt->data_at_exec, stmt->parameters_allocated);
|
||||||
stmt->errormsg = "No execution-time parameters for this statement";
|
|
||||||
return SQL_ERROR;
|
if (stmt->data_at_exec < 0) {
|
||||||
}
|
stmt->errornumber = STMT_SEQUENCE_ERROR;
|
||||||
|
stmt->errormsg = "No execution-time parameters for this statement";
|
||||||
if (stmt->data_at_exec > stmt->parameters_allocated) {
|
return SQL_ERROR;
|
||||||
stmt->errornumber = STMT_SEQUENCE_ERROR;
|
}
|
||||||
stmt->errormsg = "Too many execution-time parameters were present";
|
|
||||||
return SQL_ERROR;
|
if (stmt->data_at_exec > stmt->parameters_allocated) {
|
||||||
}
|
stmt->errornumber = STMT_SEQUENCE_ERROR;
|
||||||
|
stmt->errormsg = "Too many execution-time parameters were present";
|
||||||
/* Done, now copy the params and then execute the statement */
|
return SQL_ERROR;
|
||||||
if (stmt->data_at_exec == 0) {
|
}
|
||||||
retval = copy_statement_with_parameters(stmt);
|
|
||||||
if (retval != SQL_SUCCESS)
|
/* close the large object */
|
||||||
return retval;
|
if ( stmt->lobj_fd >= 0) {
|
||||||
|
lo_close(stmt->hdbc, stmt->lobj_fd);
|
||||||
return SC_execute(stmt);
|
stmt->lobj_fd = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* At least 1 data at execution parameter, so Fill in the token value */
|
|
||||||
for (i = 0; i < stmt->parameters_allocated; i++) {
|
/* Done, now copy the params and then execute the statement */
|
||||||
if (stmt->parameters[i].data_at_exec == TRUE) {
|
if (stmt->data_at_exec == 0) {
|
||||||
stmt->data_at_exec--;
|
retval = copy_statement_with_parameters(stmt);
|
||||||
stmt->current_exec_param = i;
|
if (retval != SQL_SUCCESS)
|
||||||
stmt->put_data = FALSE;
|
return retval;
|
||||||
*prgbValue = stmt->parameters[i].buffer; /* token */
|
|
||||||
}
|
stmt->current_exec_param = -1;
|
||||||
}
|
|
||||||
|
return SC_execute(stmt);
|
||||||
return SQL_NEED_DATA;
|
}
|
||||||
|
|
||||||
|
/* Set beginning param; if first time SQLParamData is called , start at 0.
|
||||||
|
Otherwise, start at the last parameter + 1.
|
||||||
|
*/
|
||||||
|
i = stmt->current_exec_param >= 0 ? stmt->current_exec_param+1 : 0;
|
||||||
|
|
||||||
|
/* At least 1 data at execution parameter, so Fill in the token value */
|
||||||
|
for ( ; i < stmt->parameters_allocated; i++) {
|
||||||
|
if (stmt->parameters[i].data_at_exec == TRUE) {
|
||||||
|
stmt->data_at_exec--;
|
||||||
|
stmt->current_exec_param = i;
|
||||||
|
stmt->put_data = FALSE;
|
||||||
|
*prgbValue = stmt->parameters[i].buffer; /* token */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return SQL_NEED_DATA;
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - -
|
// - - - - - - - - -
|
||||||
|
@ -422,114 +422,157 @@ RETCODE SQL_API SQLPutData(
|
||||||
PTR rgbValue,
|
PTR rgbValue,
|
||||||
SDWORD cbValue)
|
SDWORD cbValue)
|
||||||
{
|
{
|
||||||
StatementClass *stmt = (StatementClass *) hstmt;
|
StatementClass *stmt = (StatementClass *) hstmt;
|
||||||
char *buffer;
|
int old_pos, retval;
|
||||||
SDWORD *used;
|
ParameterInfoClass *current_param;
|
||||||
int old_pos;
|
char *buffer;
|
||||||
|
|
||||||
|
|
||||||
if ( ! stmt)
|
if ( ! stmt)
|
||||||
return SQL_INVALID_HANDLE;
|
return SQL_INVALID_HANDLE;
|
||||||
|
|
||||||
|
|
||||||
if (stmt->current_exec_param < 0) {
|
if (stmt->current_exec_param < 0) {
|
||||||
stmt->errornumber = STMT_SEQUENCE_ERROR;
|
stmt->errornumber = STMT_SEQUENCE_ERROR;
|
||||||
stmt->errormsg = "Previous call was not SQLPutData or SQLParamData";
|
stmt->errormsg = "Previous call was not SQLPutData or SQLParamData";
|
||||||
return SQL_ERROR;
|
return SQL_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( ! stmt->put_data) { /* first call */
|
current_param = &(stmt->parameters[stmt->current_exec_param]);
|
||||||
|
|
||||||
mylog("SQLPutData: (1) cbValue = %d\n", cbValue);
|
if ( ! stmt->put_data) { /* first call */
|
||||||
|
|
||||||
stmt->put_data = TRUE;
|
mylog("SQLPutData: (1) cbValue = %d\n", cbValue);
|
||||||
|
|
||||||
used = (SDWORD *) malloc(sizeof(SDWORD));
|
stmt->put_data = TRUE;
|
||||||
if ( ! used) {
|
|
||||||
stmt->errornumber = STMT_NO_MEMORY_ERROR;
|
current_param->EXEC_used = (SDWORD *) malloc(sizeof(SDWORD));
|
||||||
stmt->errormsg = "Out of memory in SQLPutData (1)";
|
if ( ! current_param->EXEC_used) {
|
||||||
return SQL_ERROR;
|
stmt->errornumber = STMT_NO_MEMORY_ERROR;
|
||||||
}
|
stmt->errormsg = "Out of memory in SQLPutData (1)";
|
||||||
|
return SQL_ERROR;
|
||||||
*used = cbValue;
|
}
|
||||||
stmt->parameters[stmt->current_exec_param].EXEC_used = used;
|
|
||||||
|
*current_param->EXEC_used = cbValue;
|
||||||
if (cbValue == SQL_NULL_DATA)
|
|
||||||
return SQL_SUCCESS;
|
if (cbValue == SQL_NULL_DATA)
|
||||||
|
return SQL_SUCCESS;
|
||||||
if (cbValue == SQL_NTS) {
|
|
||||||
buffer = strdup(rgbValue);
|
|
||||||
if ( ! buffer) {
|
/* Handle Long Var Binary with Large Objects */
|
||||||
stmt->errornumber = STMT_NO_MEMORY_ERROR;
|
if ( current_param->SQLType == SQL_LONGVARBINARY) {
|
||||||
stmt->errormsg = "Out of memory in SQLPutData (2)";
|
|
||||||
return SQL_ERROR;
|
/* store the oid */
|
||||||
}
|
current_param->lobj_oid = lo_creat(stmt->hdbc, INV_READ | INV_WRITE);
|
||||||
}
|
if (current_param->lobj_oid == 0) {
|
||||||
else {
|
stmt->errornumber = STMT_EXEC_ERROR;
|
||||||
buffer = malloc(cbValue + 1);
|
stmt->errormsg = "Couldnt create large object.";
|
||||||
if ( ! buffer) {
|
return SQL_ERROR;
|
||||||
stmt->errornumber = STMT_NO_MEMORY_ERROR;
|
}
|
||||||
stmt->errormsg = "Out of memory in SQLPutData (2)";
|
|
||||||
return SQL_ERROR;
|
/* major hack -- to allow convert to see somethings there */
|
||||||
}
|
/* have to modify convert to handle this better */
|
||||||
memcpy(buffer, rgbValue, cbValue);
|
current_param->EXEC_buffer = (char *) ¤t_param->lobj_oid;
|
||||||
buffer[cbValue] = '\0';
|
|
||||||
}
|
/* store the fd */
|
||||||
|
stmt->lobj_fd = lo_open(stmt->hdbc, current_param->lobj_oid, INV_WRITE);
|
||||||
stmt->parameters[stmt->current_exec_param].EXEC_buffer = buffer;
|
if ( stmt->lobj_fd < 0) {
|
||||||
}
|
stmt->errornumber = STMT_EXEC_ERROR;
|
||||||
|
stmt->errormsg = "Couldnt open large object for writing.";
|
||||||
else { /* calling SQLPutData more than once */
|
return SQL_ERROR;
|
||||||
|
}
|
||||||
mylog("SQLPutData: (>1) cbValue = %d\n", cbValue);
|
|
||||||
|
retval = lo_write(stmt->hdbc, stmt->lobj_fd, rgbValue, cbValue);
|
||||||
used = stmt->parameters[stmt->current_exec_param].EXEC_used;
|
mylog("lo_write: cbValue=%d, wrote %d bytes\n", cbValue, retval);
|
||||||
buffer = stmt->parameters[stmt->current_exec_param].EXEC_buffer;
|
|
||||||
|
}
|
||||||
if (cbValue == SQL_NTS) {
|
else { /* for handling text fields and small binaries */
|
||||||
buffer = realloc(buffer, strlen(buffer) + strlen(rgbValue) + 1);
|
|
||||||
if ( ! buffer) {
|
if (cbValue == SQL_NTS) {
|
||||||
stmt->errornumber = STMT_NO_MEMORY_ERROR;
|
current_param->EXEC_buffer = strdup(rgbValue);
|
||||||
stmt->errormsg = "Out of memory in SQLPutData (3)";
|
if ( ! current_param->EXEC_buffer) {
|
||||||
return SQL_ERROR;
|
stmt->errornumber = STMT_NO_MEMORY_ERROR;
|
||||||
}
|
stmt->errormsg = "Out of memory in SQLPutData (2)";
|
||||||
strcat(buffer, rgbValue);
|
return SQL_ERROR;
|
||||||
|
}
|
||||||
mylog(" cbValue = SQL_NTS: strlen(buffer) = %d\n", strlen(buffer));
|
}
|
||||||
|
else {
|
||||||
*used = cbValue;
|
current_param->EXEC_buffer = malloc(cbValue + 1);
|
||||||
|
if ( ! current_param->EXEC_buffer) {
|
||||||
}
|
stmt->errornumber = STMT_NO_MEMORY_ERROR;
|
||||||
else if (cbValue > 0) {
|
stmt->errormsg = "Out of memory in SQLPutData (2)";
|
||||||
|
return SQL_ERROR;
|
||||||
old_pos = *used;
|
}
|
||||||
|
memcpy(current_param->EXEC_buffer, rgbValue, cbValue);
|
||||||
*used += cbValue;
|
current_param->EXEC_buffer[cbValue] = '\0';
|
||||||
|
}
|
||||||
mylog(" cbValue = %d, old_pos = %d, *used = %d\n", cbValue, old_pos, *used);
|
}
|
||||||
|
}
|
||||||
buffer = realloc(buffer, *used + 1);
|
|
||||||
if ( ! buffer) {
|
else { /* calling SQLPutData more than once */
|
||||||
stmt->errornumber = STMT_NO_MEMORY_ERROR;
|
|
||||||
stmt->errormsg = "Out of memory in SQLPutData (3)";
|
mylog("SQLPutData: (>1) cbValue = %d\n", cbValue);
|
||||||
return SQL_ERROR;
|
|
||||||
}
|
if (current_param->SQLType == SQL_LONGVARBINARY) {
|
||||||
|
|
||||||
memcpy(&buffer[old_pos], rgbValue, cbValue);
|
/* the large object fd is in EXEC_buffer */
|
||||||
buffer[*used] = '\0';
|
retval = lo_write(stmt->hdbc, stmt->lobj_fd, rgbValue, cbValue);
|
||||||
|
mylog("lo_write(2): cbValue = %d, wrote %d bytes\n", cbValue, retval);
|
||||||
}
|
|
||||||
else
|
*current_param->EXEC_used += cbValue;
|
||||||
return SQL_ERROR;
|
|
||||||
|
} else {
|
||||||
|
|
||||||
/* reassign buffer incase realloc moved it */
|
buffer = current_param->EXEC_buffer;
|
||||||
stmt->parameters[stmt->current_exec_param].EXEC_buffer = buffer;
|
|
||||||
|
if (cbValue == SQL_NTS) {
|
||||||
}
|
buffer = realloc(buffer, strlen(buffer) + strlen(rgbValue) + 1);
|
||||||
|
if ( ! buffer) {
|
||||||
|
stmt->errornumber = STMT_NO_MEMORY_ERROR;
|
||||||
return SQL_SUCCESS;
|
stmt->errormsg = "Out of memory in SQLPutData (3)";
|
||||||
|
return SQL_ERROR;
|
||||||
|
}
|
||||||
|
strcat(buffer, rgbValue);
|
||||||
|
|
||||||
|
mylog(" cbValue = SQL_NTS: strlen(buffer) = %d\n", strlen(buffer));
|
||||||
|
|
||||||
|
*current_param->EXEC_used = cbValue;
|
||||||
|
|
||||||
|
/* reassign buffer incase realloc moved it */
|
||||||
|
current_param->EXEC_buffer = buffer;
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (cbValue > 0) {
|
||||||
|
|
||||||
|
old_pos = *current_param->EXEC_used;
|
||||||
|
|
||||||
|
*current_param->EXEC_used += cbValue;
|
||||||
|
|
||||||
|
mylog(" cbValue = %d, old_pos = %d, *used = %d\n", cbValue, old_pos, *current_param->EXEC_used);
|
||||||
|
|
||||||
|
/* dont lose the old pointer in case out of memory */
|
||||||
|
buffer = realloc(current_param->EXEC_buffer, *current_param->EXEC_used + 1);
|
||||||
|
if ( ! buffer) {
|
||||||
|
stmt->errornumber = STMT_NO_MEMORY_ERROR;
|
||||||
|
stmt->errormsg = "Out of memory in SQLPutData (3)";
|
||||||
|
return SQL_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(&buffer[old_pos], rgbValue, cbValue);
|
||||||
|
buffer[*current_param->EXEC_used] = '\0';
|
||||||
|
|
||||||
|
/* reassign buffer incase realloc moved it */
|
||||||
|
current_param->EXEC_buffer = buffer;
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return SQL_ERROR;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return SQL_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,28 +1,27 @@
|
||||||
|
|
||||||
/* Module: misc.c
|
/* Module: misc.c
|
||||||
*
|
*
|
||||||
* Description: This module contains miscellaneous routines
|
* Description: This module contains miscellaneous routines
|
||||||
* such as for debugging/logging and string functions.
|
* such as for debugging/logging and string functions.
|
||||||
*
|
*
|
||||||
* Classes: n/a
|
* Classes: n/a
|
||||||
*
|
*
|
||||||
* API functions: none
|
* API functions: none
|
||||||
*
|
*
|
||||||
* Comments: See "notice.txt" for copyright and license information.
|
* Comments: See "notice.txt" for copyright and license information.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <windows.h>
|
#include <varargs.h>
|
||||||
#include <sql.h>
|
|
||||||
|
|
||||||
#include "psqlodbc.h"
|
#include "psqlodbc.h"
|
||||||
|
|
||||||
|
|
||||||
extern GLOBAL_VALUES globals;
|
extern GLOBAL_VALUES globals;
|
||||||
|
|
||||||
|
|
||||||
#ifdef MY_LOG
|
#ifdef MY_LOG
|
||||||
#include <varargs.h>
|
|
||||||
|
|
||||||
void
|
void
|
||||||
mylog(va_alist)
|
mylog(va_alist)
|
||||||
|
@ -52,7 +51,6 @@ static FILE *LOGFP = 0;
|
||||||
|
|
||||||
|
|
||||||
#ifdef Q_LOG
|
#ifdef Q_LOG
|
||||||
#include <varargs.h>
|
|
||||||
|
|
||||||
void qlog(va_alist)
|
void qlog(va_alist)
|
||||||
va_dcl
|
va_dcl
|
||||||
|
@ -78,10 +76,17 @@ static FILE *LOGFP = 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Undefine these because windows.h will redefine and cause a warning */
|
||||||
|
#undef va_start
|
||||||
|
#undef va_end
|
||||||
|
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
#include <sql.h>
|
||||||
|
|
||||||
/* returns STRCPY_FAIL, STRCPY_TRUNCATED, or #bytes copied (not including null term) */
|
/* returns STRCPY_FAIL, STRCPY_TRUNCATED, or #bytes copied (not including null term) */
|
||||||
int
|
int
|
||||||
my_strcpy(char *dst, size_t dst_len, char *src, size_t src_len)
|
my_strcpy(char *dst, int dst_len, char *src, int src_len)
|
||||||
{
|
{
|
||||||
if (dst_len <= 0)
|
if (dst_len <= 0)
|
||||||
return STRCPY_FAIL;
|
return STRCPY_FAIL;
|
||||||
|
@ -90,31 +95,23 @@ my_strcpy(char *dst, size_t dst_len, char *src, size_t src_len)
|
||||||
dst[0] = '\0';
|
dst[0] = '\0';
|
||||||
return STRCPY_NULL;
|
return STRCPY_NULL;
|
||||||
}
|
}
|
||||||
|
else if (src_len == SQL_NTS)
|
||||||
|
src_len = strlen(src);
|
||||||
|
|
||||||
else if (src_len == SQL_NTS) {
|
if (src_len <= 0)
|
||||||
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;
|
return STRCPY_FAIL;
|
||||||
|
|
||||||
else {
|
else {
|
||||||
if (src_len < dst_len) {
|
if (src_len < dst_len) {
|
||||||
memcpy(dst, src, src_len);
|
memcpy(dst, src, src_len);
|
||||||
dst[src_len] = '\0';
|
dst[src_len] = '\0';
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
memcpy(dst, src, dst_len-1);
|
memcpy(dst, src, dst_len-1);
|
||||||
dst[dst_len-1] = '\0'; /* truncated */
|
dst[dst_len-1] = '\0'; /* truncated */
|
||||||
return STRCPY_TRUNCATED;
|
return STRCPY_TRUNCATED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return strlen(dst);
|
return strlen(dst);
|
||||||
}
|
}
|
||||||
|
@ -123,9 +120,9 @@ my_strcpy(char *dst, size_t dst_len, char *src, size_t src_len)
|
||||||
// the destination string if src has len characters or more.
|
// the destination string if src has len characters or more.
|
||||||
// instead, I want it to copy up to len-1 characters and always
|
// instead, I want it to copy up to len-1 characters and always
|
||||||
// terminate the destination string.
|
// terminate the destination string.
|
||||||
char *strncpy_null(char *dst, const char *src, size_t len)
|
char *strncpy_null(char *dst, const char *src, int len)
|
||||||
{
|
{
|
||||||
unsigned int i;
|
int i;
|
||||||
|
|
||||||
|
|
||||||
if (NULL != dst) {
|
if (NULL != dst) {
|
||||||
|
@ -138,7 +135,7 @@ unsigned int i;
|
||||||
else if (len == SQL_NTS)
|
else if (len == SQL_NTS)
|
||||||
len = strlen(src) + 1;
|
len = strlen(src) + 1;
|
||||||
|
|
||||||
for(i = 0; src[i] && i < len - 1; i++) {
|
for(i = 0; src[i] && i < len - 1; i++) {
|
||||||
dst[i] = src[i];
|
dst[i] = src[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
|
|
||||||
/* File: misc.h
|
/* File: misc.h
|
||||||
*
|
*
|
||||||
* Description: See "misc.c"
|
* Description: See "misc.c"
|
||||||
*
|
*
|
||||||
* Comments: See "notice.txt" for copyright and license information.
|
* Comments: See "notice.txt" for copyright and license information.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __MISC_H__
|
#ifndef __MISC_H__
|
||||||
#define __MISC_H__
|
#define __MISC_H__
|
||||||
|
@ -23,7 +23,7 @@
|
||||||
/* Uncomment Q_LOG to compile in the qlog() statements (Communications log, i.e. CommLog).
|
/* 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
|
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
|
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),
|
'CommLog' flag in the ODBCINST.INI portion of the registry (see above),
|
||||||
which is manipulated on the setup/connection dialog boxes.
|
which is manipulated on the setup/connection dialog boxes.
|
||||||
*/
|
*/
|
||||||
#define Q_LOG
|
#define Q_LOG
|
||||||
|
@ -42,7 +42,7 @@ void qlog(); /* prototype */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void remove_newlines(char *string);
|
void remove_newlines(char *string);
|
||||||
char *strncpy_null(char *dst, const char *src, size_t len);
|
char *strncpy_null(char *dst, const char *src, int len);
|
||||||
char *trim(char *string);
|
char *trim(char *string);
|
||||||
char *make_string(char *s, int len, char *buf);
|
char *make_string(char *s, int len, char *buf);
|
||||||
char *my_strcat(char *buf, char *fmt, char *s, int len);
|
char *my_strcat(char *buf, char *fmt, char *s, int len);
|
||||||
|
@ -53,6 +53,6 @@ char *my_strcat(char *buf, char *fmt, char *s, int len);
|
||||||
#define STRCPY_TRUNCATED -1
|
#define STRCPY_TRUNCATED -1
|
||||||
#define STRCPY_NULL -2
|
#define STRCPY_NULL -2
|
||||||
|
|
||||||
int my_strcpy(char *dst, size_t dst_len, char *src, size_t src_len);
|
int my_strcpy(char *dst, int dst_len, char *src, int src_len);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,35 +1,35 @@
|
||||||
|
|
||||||
/********************************************************************
|
/********************************************************************
|
||||||
|
|
||||||
PSQLODBC.DLL - A library to talk to the PostgreSQL DBMS using ODBC.
|
PSQLODBC.DLL - A library to talk to the PostgreSQL DBMS using ODBC.
|
||||||
|
|
||||||
|
|
||||||
Copyright (C) 1998; Insight Distribution Systems
|
Copyright (C) 1998; Insight Distribution Systems
|
||||||
|
|
||||||
The code contained in this library is based on code written by
|
The code contained in this library is based on code written by
|
||||||
Christian Czezatke and Dan McGuirk, (C) 1996.
|
Christian Czezatke and Dan McGuirk, (C) 1996.
|
||||||
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or modify
|
This library is free software; you can redistribute it and/or modify
|
||||||
it under the terms of the GNU Library General Public License as
|
it under the terms of the GNU Library General Public License as
|
||||||
published by the Free Software Foundation; either version 2 of the
|
published by the Free Software Foundation; either version 2 of the
|
||||||
License, or (at your option) any later version.
|
License, or (at your option) any later version.
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful, but
|
This library is distributed in the hope that it will be useful, but
|
||||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTIBILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTIBILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
Library General Public License for more details.
|
Library General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU Library General Public
|
You should have received a copy of the GNU Library General Public
|
||||||
License along with this library (see "license.txt"); if not, write to
|
License along with this library (see "license.txt"); if not, write to
|
||||||
the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA
|
the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA
|
||||||
02139, USA.
|
02139, USA.
|
||||||
|
|
||||||
|
|
||||||
How to contact the author:
|
How to contact the author:
|
||||||
|
|
||||||
email: byronn@insightdist.com (Byron Nikolaidis)
|
email: byronn@insightdist.com (Byron Nikolaidis)
|
||||||
|
|
||||||
|
|
||||||
***********************************************************************/
|
***********************************************************************/
|
||||||
|
|
||||||
|
|
|
@ -1,25 +1,30 @@
|
||||||
|
|
||||||
/* Module: options.c
|
/* Module: options.c
|
||||||
*
|
*
|
||||||
* Description: This module contains routines for getting/setting
|
* Description: This module contains routines for getting/setting
|
||||||
* connection and statement options.
|
* connection and statement options.
|
||||||
*
|
*
|
||||||
* Classes: n/a
|
* Classes: n/a
|
||||||
*
|
*
|
||||||
* API functions: SQLSetConnectOption, SQLSetStmtOption, SQLGetConnectOption,
|
* API functions: SQLSetConnectOption, SQLSetStmtOption, SQLGetConnectOption,
|
||||||
* SQLGetStmtOption
|
* SQLGetStmtOption
|
||||||
*
|
*
|
||||||
* Comments: See "notice.txt" for copyright and license information.
|
* Comments: See "notice.txt" for copyright and license information.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "psqlodbc.h"
|
#include "psqlodbc.h"
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <sql.h>
|
#include <sql.h>
|
||||||
|
#include <sqlext.h>
|
||||||
#include "environ.h"
|
#include "environ.h"
|
||||||
#include "connection.h"
|
#include "connection.h"
|
||||||
#include "statement.h"
|
#include "statement.h"
|
||||||
|
|
||||||
|
|
||||||
|
extern GLOBAL_VALUES globals;
|
||||||
|
|
||||||
|
|
||||||
/* Implements only SQL_AUTOCOMMIT */
|
/* Implements only SQL_AUTOCOMMIT */
|
||||||
RETCODE SQL_API SQLSetConnectOption(
|
RETCODE SQL_API SQLSetConnectOption(
|
||||||
HDBC hdbc,
|
HDBC hdbc,
|
||||||
|
@ -81,58 +86,6 @@ ConnectionClass *conn = (ConnectionClass *) hdbc;
|
||||||
|
|
||||||
// - - - - - - - - -
|
// - - - - - - - - -
|
||||||
|
|
||||||
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 */
|
/* This function just can tell you whether you are in Autcommit mode or not */
|
||||||
RETCODE SQL_API SQLGetConnectOption(
|
RETCODE SQL_API SQLGetConnectOption(
|
||||||
HDBC hdbc,
|
HDBC hdbc,
|
||||||
|
@ -141,32 +94,127 @@ RETCODE SQL_API SQLGetConnectOption(
|
||||||
{
|
{
|
||||||
ConnectionClass *conn = (ConnectionClass *) hdbc;
|
ConnectionClass *conn = (ConnectionClass *) hdbc;
|
||||||
|
|
||||||
if (! conn)
|
if (! conn)
|
||||||
return SQL_INVALID_HANDLE;
|
return SQL_INVALID_HANDLE;
|
||||||
|
|
||||||
switch (fOption) {
|
switch (fOption) {
|
||||||
case SQL_AUTOCOMMIT:
|
case SQL_AUTOCOMMIT:
|
||||||
/* CC 28.05.96: Do not set fOption, but pvParam */
|
*((UDWORD *)pvParam) = (UDWORD)( CC_is_in_autocommit(conn) ?
|
||||||
*((UDWORD *)pvParam) = (UDWORD)( CC_is_in_autocommit(conn) ?
|
SQL_AUTOCOMMIT_ON : SQL_AUTOCOMMIT_OFF);
|
||||||
SQL_AUTOCOMMIT_ON : SQL_AUTOCOMMIT_OFF);
|
break;
|
||||||
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;
|
|
||||||
|
|
||||||
}
|
/* don't use qualifiers */
|
||||||
|
case SQL_CURRENT_QUALIFIER:
|
||||||
|
if(pvParam)
|
||||||
|
strcpy(pvParam, "");
|
||||||
|
|
||||||
return SQL_SUCCESS;
|
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 SQLSetStmtOption(
|
||||||
|
HSTMT hstmt,
|
||||||
|
UWORD fOption,
|
||||||
|
UDWORD vParam)
|
||||||
|
{
|
||||||
|
StatementClass *stmt = (StatementClass *) hstmt;
|
||||||
|
char changed = FALSE;
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
// "0" returned in SQLGetStmtOption
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SQL_MAX_LENGTH:
|
||||||
|
// "4096" returned in SQLGetStmtOption
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SQL_MAX_ROWS:
|
||||||
|
mylog("SetStmtOption(): SQL_MAX_ROWS = %d, returning success\n", vParam);
|
||||||
|
stmt->maxRows = vParam;
|
||||||
|
return SQL_SUCCESS;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SQL_ROWSET_SIZE:
|
||||||
|
mylog("SetStmtOption(): SQL_ROWSET_SIZE = %d\n", vParam);
|
||||||
|
|
||||||
|
stmt->rowset_size = 1; // only support 1 row at a time
|
||||||
|
if (vParam != 1)
|
||||||
|
changed = TRUE;
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SQL_CONCURRENCY:
|
||||||
|
// positioned update isn't supported so cursor concurrency is read-only
|
||||||
|
mylog("SetStmtOption(): SQL_CONCURRENCY = %d\n", vParam);
|
||||||
|
|
||||||
|
stmt->scroll_concurrency = SQL_CONCUR_READ_ONLY;
|
||||||
|
if (vParam != SQL_CONCUR_READ_ONLY)
|
||||||
|
changed = TRUE;
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SQL_CURSOR_TYPE:
|
||||||
|
// if declare/fetch, then type can only be forward.
|
||||||
|
// otherwise, it can only be forward or static.
|
||||||
|
mylog("SetStmtOption(): SQL_CURSOR_TYPE = %d\n", vParam);
|
||||||
|
|
||||||
|
if (globals.use_declarefetch) {
|
||||||
|
stmt->cursor_type = SQL_CURSOR_FORWARD_ONLY;
|
||||||
|
if (vParam != SQL_CURSOR_FORWARD_ONLY)
|
||||||
|
changed = TRUE;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (vParam == SQL_CURSOR_FORWARD_ONLY || vParam == SQL_CURSOR_STATIC)
|
||||||
|
stmt->cursor_type = vParam; // valid type
|
||||||
|
else {
|
||||||
|
stmt->cursor_type = SQL_CURSOR_STATIC;
|
||||||
|
changed = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SQL_SIMULATE_CURSOR:
|
||||||
|
stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR;
|
||||||
|
stmt->errormsg = "Simulated positioned update/delete not supported";
|
||||||
|
return SQL_ERROR;
|
||||||
|
|
||||||
|
default:
|
||||||
|
stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR;
|
||||||
|
stmt->errormsg = "Driver does not support this statement option";
|
||||||
|
return SQL_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (changed) {
|
||||||
|
stmt->errormsg = "Requested value changed.";
|
||||||
|
stmt->errornumber = STMT_OPTION_VALUE_CHANGED;
|
||||||
|
return SQL_SUCCESS_WITH_INFO;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return SQL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// - - - - - - - - -
|
// - - - - - - - - -
|
||||||
|
|
||||||
RETCODE SQL_API SQLGetStmtOption(
|
RETCODE SQL_API SQLGetStmtOption(
|
||||||
|
@ -180,31 +228,54 @@ StatementClass *stmt = (StatementClass *) hstmt;
|
||||||
// all the time, but it tries to set a huge value for SQL_MAX_LENGTH
|
// all the time, but it tries to set a huge value for SQL_MAX_LENGTH
|
||||||
// and expects the driver to reduce it to the real value
|
// and expects the driver to reduce it to the real value
|
||||||
|
|
||||||
if( ! stmt) {
|
if( ! stmt)
|
||||||
return SQL_INVALID_HANDLE;
|
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;
|
||||||
|
|
||||||
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:
|
case SQL_MAX_ROWS:
|
||||||
*((SDWORD *)pvParam) = stmt->maxRows;
|
*((SDWORD *)pvParam) = stmt->maxRows;
|
||||||
mylog("GetSmtOption: MAX_ROWS, returning %d\n", stmt->maxRows);
|
mylog("GetSmtOption: MAX_ROWS, returning %d\n", stmt->maxRows);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
default:
|
|
||||||
return SQL_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
return SQL_SUCCESS;
|
case SQL_ROWSET_SIZE:
|
||||||
|
mylog("GetStmtOption(): SQL_ROWSET_SIZE\n");
|
||||||
|
*((SDWORD *)pvParam) = stmt->rowset_size;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SQL_CONCURRENCY:
|
||||||
|
mylog("GetStmtOption(): SQL_CONCURRENCY\n");
|
||||||
|
*((SDWORD *)pvParam) = stmt->scroll_concurrency;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SQL_CURSOR_TYPE:
|
||||||
|
mylog("GetStmtOption(): SQL_CURSOR_TYPE\n");
|
||||||
|
*((SDWORD *)pvParam) = stmt->cursor_type;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SQL_SIMULATE_CURSOR:
|
||||||
|
stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR;
|
||||||
|
stmt->errormsg = "Simulated positioned update/delete not supported";
|
||||||
|
return SQL_ERROR;
|
||||||
|
|
||||||
|
default:
|
||||||
|
stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR;
|
||||||
|
stmt->errormsg = "Driver does not support this statement option";
|
||||||
|
return SQL_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SQL_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - -
|
// - - - - - - - - -
|
||||||
|
|
|
@ -1,26 +1,34 @@
|
||||||
|
|
||||||
/* Module: pgtypes.c
|
/* Module: pgtypes.c
|
||||||
*
|
*
|
||||||
* Description: This module contains routines for getting information
|
* Description: This module contains routines for getting information
|
||||||
* about the supported Postgres data types. Only the function
|
* about the supported Postgres data types. Only the function
|
||||||
* pgtype_to_sqltype() returns an unknown condition. All other
|
* pgtype_to_sqltype() returns an unknown condition. All other
|
||||||
* functions return a suitable default so that even data types that
|
* functions return a suitable default so that even data types that
|
||||||
* are not directly supported can be used (it is handled as char data).
|
* are not directly supported can be used (it is handled as char data).
|
||||||
*
|
*
|
||||||
* Classes: n/a
|
* Classes: n/a
|
||||||
*
|
*
|
||||||
* API functions: none
|
* API functions: none
|
||||||
*
|
*
|
||||||
* Comments: See "notice.txt" for copyright and license information.
|
* Comments: See "notice.txt" for copyright and license information.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "psqlodbc.h"
|
#include "psqlodbc.h"
|
||||||
|
#include "dlg_specific.h"
|
||||||
#include "pgtypes.h"
|
#include "pgtypes.h"
|
||||||
|
#include "statement.h"
|
||||||
|
#include "connection.h"
|
||||||
|
#include "qresult.h"
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <sql.h>
|
#include <sql.h>
|
||||||
#include <sqlext.h>
|
#include <sqlext.h>
|
||||||
|
|
||||||
|
|
||||||
|
extern GLOBAL_VALUES globals;
|
||||||
|
|
||||||
|
|
||||||
/* these are the types we support. all of the pgtype_ functions should */
|
/* these are the types we support. all of the pgtype_ functions should */
|
||||||
/* return values for each one of these. */
|
/* return values for each one of these. */
|
||||||
|
|
||||||
|
@ -32,13 +40,14 @@ Int4 pgtypes_defined[] = {
|
||||||
PG_TYPE_CHAR2,
|
PG_TYPE_CHAR2,
|
||||||
PG_TYPE_CHAR4,
|
PG_TYPE_CHAR4,
|
||||||
PG_TYPE_CHAR8,
|
PG_TYPE_CHAR8,
|
||||||
PG_TYPE_BPCHAR,
|
PG_TYPE_CHAR16,
|
||||||
|
PG_TYPE_NAME,
|
||||||
PG_TYPE_VARCHAR,
|
PG_TYPE_VARCHAR,
|
||||||
|
PG_TYPE_BPCHAR,
|
||||||
PG_TYPE_DATE,
|
PG_TYPE_DATE,
|
||||||
PG_TYPE_TIME,
|
PG_TYPE_TIME,
|
||||||
PG_TYPE_ABSTIME, /* a timestamp, sort of */
|
PG_TYPE_ABSTIME, /* a timestamp, sort of */
|
||||||
PG_TYPE_TEXT,
|
PG_TYPE_TEXT,
|
||||||
PG_TYPE_NAME,
|
|
||||||
PG_TYPE_INT2,
|
PG_TYPE_INT2,
|
||||||
PG_TYPE_INT4,
|
PG_TYPE_INT4,
|
||||||
PG_TYPE_FLOAT4,
|
PG_TYPE_FLOAT4,
|
||||||
|
@ -46,9 +55,9 @@ Int4 pgtypes_defined[] = {
|
||||||
PG_TYPE_OID,
|
PG_TYPE_OID,
|
||||||
PG_TYPE_MONEY,
|
PG_TYPE_MONEY,
|
||||||
PG_TYPE_BOOL,
|
PG_TYPE_BOOL,
|
||||||
PG_TYPE_CHAR16,
|
PG_TYPE_DATETIME,
|
||||||
PG_TYPE_DATETIME,
|
PG_TYPE_BYTEA,
|
||||||
PG_TYPE_BYTEA,
|
PG_TYPE_LO,
|
||||||
0 };
|
0 };
|
||||||
|
|
||||||
|
|
||||||
|
@ -57,113 +66,197 @@ Int4 pgtypes_defined[] = {
|
||||||
2. When taking any type id (SQLColumns, SQLGetData)
|
2. When taking any type id (SQLColumns, SQLGetData)
|
||||||
|
|
||||||
The first type will always work because all the types defined are returned here.
|
The first type will always work because all the types defined are returned here.
|
||||||
The second type will return PG_UNKNOWN when it does not know. The calling
|
The second type will return a default based on global parameter when it does not
|
||||||
routine checks for this and changes it to a char type. This allows for supporting
|
know. This allows for supporting
|
||||||
types that are unknown. All other pg routines in here return a suitable default.
|
types that are unknown. All other pg routines in here return a suitable default.
|
||||||
*/
|
*/
|
||||||
Int2 pgtype_to_sqltype(Int4 type)
|
Int2 pgtype_to_sqltype(StatementClass *stmt, Int4 type)
|
||||||
{
|
{
|
||||||
switch(type) {
|
switch(type) {
|
||||||
case PG_TYPE_CHAR:
|
case PG_TYPE_CHAR:
|
||||||
case PG_TYPE_CHAR2:
|
case PG_TYPE_CHAR2:
|
||||||
case PG_TYPE_CHAR4:
|
case PG_TYPE_CHAR4:
|
||||||
case PG_TYPE_CHAR8:
|
case PG_TYPE_CHAR8:
|
||||||
case PG_TYPE_CHAR16: return SQL_CHAR;
|
case PG_TYPE_CHAR16:
|
||||||
|
case PG_TYPE_NAME: return SQL_CHAR;
|
||||||
|
|
||||||
case PG_TYPE_BPCHAR:
|
case PG_TYPE_BPCHAR: return SQL_CHAR; // temporary?
|
||||||
case PG_TYPE_NAME:
|
|
||||||
case PG_TYPE_VARCHAR: return SQL_VARCHAR;
|
|
||||||
|
|
||||||
case PG_TYPE_TEXT: return SQL_LONGVARCHAR;
|
case PG_TYPE_VARCHAR: return SQL_VARCHAR;
|
||||||
case PG_TYPE_BYTEA: return SQL_LONGVARBINARY;
|
|
||||||
|
|
||||||
case PG_TYPE_INT2: return SQL_SMALLINT;
|
case PG_TYPE_TEXT: return globals.text_as_longvarchar ? SQL_LONGVARCHAR : SQL_VARCHAR;
|
||||||
case PG_TYPE_OID:
|
|
||||||
case PG_TYPE_INT4: return SQL_INTEGER;
|
case PG_TYPE_BYTEA: return SQL_VARBINARY;
|
||||||
case PG_TYPE_FLOAT4: return SQL_REAL;
|
case PG_TYPE_LO: return SQL_LONGVARBINARY;
|
||||||
case PG_TYPE_FLOAT8: return SQL_FLOAT;
|
|
||||||
|
case PG_TYPE_INT2: return SQL_SMALLINT;
|
||||||
|
case PG_TYPE_OID:
|
||||||
|
case PG_TYPE_INT4: return SQL_INTEGER;
|
||||||
|
case PG_TYPE_FLOAT4: return SQL_REAL;
|
||||||
|
case PG_TYPE_FLOAT8: return SQL_FLOAT;
|
||||||
case PG_TYPE_DATE: return SQL_DATE;
|
case PG_TYPE_DATE: return SQL_DATE;
|
||||||
case PG_TYPE_TIME: return SQL_TIME;
|
case PG_TYPE_TIME: return SQL_TIME;
|
||||||
case PG_TYPE_ABSTIME:
|
case PG_TYPE_ABSTIME:
|
||||||
case PG_TYPE_DATETIME: return SQL_TIMESTAMP;
|
case PG_TYPE_DATETIME: return SQL_TIMESTAMP;
|
||||||
case PG_TYPE_MONEY: return SQL_FLOAT;
|
case PG_TYPE_MONEY: return SQL_FLOAT;
|
||||||
case PG_TYPE_BOOL: return SQL_CHAR;
|
case PG_TYPE_BOOL: return globals.bools_as_char ? SQL_CHAR : SQL_BIT;
|
||||||
|
|
||||||
default: return PG_UNKNOWN; /* check return for this */
|
default:
|
||||||
}
|
|
||||||
|
/* first, check to see if 'type' is in list. If not, look up with query.
|
||||||
|
Add oid, name to list. If its already in list, just return.
|
||||||
|
*/
|
||||||
|
if (type == stmt->hdbc->lobj_type) /* hack until permanent type is available */
|
||||||
|
return SQL_LONGVARBINARY;
|
||||||
|
|
||||||
|
return globals.unknowns_as_longvarchar ? SQL_LONGVARCHAR : SQL_VARCHAR;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Int2 pgtype_to_ctype(Int4 type)
|
Int2 pgtype_to_ctype(StatementClass *stmt, Int4 type)
|
||||||
{
|
{
|
||||||
switch(type) {
|
switch(type) {
|
||||||
case PG_TYPE_INT2: return SQL_C_SSHORT;
|
case PG_TYPE_INT2: return SQL_C_SSHORT;
|
||||||
case PG_TYPE_OID:
|
case PG_TYPE_OID:
|
||||||
case PG_TYPE_INT4: return SQL_C_SLONG;
|
case PG_TYPE_INT4: return SQL_C_SLONG;
|
||||||
case PG_TYPE_FLOAT4: return SQL_C_FLOAT;
|
case PG_TYPE_FLOAT4: return SQL_C_FLOAT;
|
||||||
case PG_TYPE_FLOAT8: return SQL_C_DOUBLE;
|
case PG_TYPE_FLOAT8: return SQL_C_DOUBLE;
|
||||||
case PG_TYPE_DATE: return SQL_C_DATE;
|
case PG_TYPE_DATE: return SQL_C_DATE;
|
||||||
case PG_TYPE_TIME: return SQL_C_TIME;
|
case PG_TYPE_TIME: return SQL_C_TIME;
|
||||||
case PG_TYPE_ABSTIME:
|
case PG_TYPE_ABSTIME:
|
||||||
case PG_TYPE_DATETIME: return SQL_C_TIMESTAMP;
|
case PG_TYPE_DATETIME: return SQL_C_TIMESTAMP;
|
||||||
case PG_TYPE_MONEY: return SQL_C_FLOAT;
|
case PG_TYPE_MONEY: return SQL_C_FLOAT;
|
||||||
case PG_TYPE_BOOL: return SQL_C_CHAR;
|
case PG_TYPE_BOOL: return globals.bools_as_char ? SQL_C_CHAR : SQL_C_BIT;
|
||||||
|
|
||||||
case PG_TYPE_BYTEA: return SQL_C_BINARY;
|
|
||||||
|
|
||||||
default: return SQL_C_CHAR;
|
case PG_TYPE_BYTEA: return SQL_C_BINARY;
|
||||||
}
|
case PG_TYPE_LO: return SQL_C_BINARY;
|
||||||
|
|
||||||
|
default:
|
||||||
|
|
||||||
|
if (type == stmt->hdbc->lobj_type) /* hack until permanent type is available */
|
||||||
|
return SQL_C_BINARY;
|
||||||
|
|
||||||
|
return SQL_C_CHAR;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
char *pgtype_to_name(Int4 type)
|
char *pgtype_to_name(StatementClass *stmt, Int4 type)
|
||||||
{
|
{
|
||||||
switch(type) {
|
switch(type) {
|
||||||
case PG_TYPE_CHAR: return "char";
|
case PG_TYPE_CHAR: return "char";
|
||||||
case PG_TYPE_CHAR2: return "char2";
|
case PG_TYPE_CHAR2: return "char2";
|
||||||
case PG_TYPE_CHAR4: return "char4";
|
case PG_TYPE_CHAR4: return "char4";
|
||||||
case PG_TYPE_CHAR8: return "char8";
|
case PG_TYPE_CHAR8: return "char8";
|
||||||
case PG_TYPE_CHAR16: return "char16";
|
case PG_TYPE_CHAR16: return "char16";
|
||||||
case PG_TYPE_VARCHAR: return "varchar";
|
case PG_TYPE_VARCHAR: return "varchar";
|
||||||
case PG_TYPE_BPCHAR: return "bpchar";
|
case PG_TYPE_BPCHAR: return "bpchar";
|
||||||
case PG_TYPE_TEXT: return "text";
|
case PG_TYPE_TEXT: return "text";
|
||||||
case PG_TYPE_NAME: return "name";
|
case PG_TYPE_NAME: return "name";
|
||||||
case PG_TYPE_INT2: return "int2";
|
case PG_TYPE_INT2: return "int2";
|
||||||
case PG_TYPE_OID: return "oid";
|
case PG_TYPE_OID: return "oid";
|
||||||
case PG_TYPE_INT4: return "int4";
|
case PG_TYPE_INT4: return "int4";
|
||||||
case PG_TYPE_FLOAT4: return "float4";
|
case PG_TYPE_FLOAT4: return "float4";
|
||||||
case PG_TYPE_FLOAT8: return "float8";
|
case PG_TYPE_FLOAT8: return "float8";
|
||||||
case PG_TYPE_DATE: return "date";
|
case PG_TYPE_DATE: return "date";
|
||||||
case PG_TYPE_TIME: return "time";
|
case PG_TYPE_TIME: return "time";
|
||||||
case PG_TYPE_ABSTIME: return "abstime";
|
case PG_TYPE_ABSTIME: return "abstime";
|
||||||
case PG_TYPE_DATETIME: return "datetime";
|
case PG_TYPE_DATETIME: return "datetime";
|
||||||
case PG_TYPE_MONEY: return "money";
|
case PG_TYPE_MONEY: return "money";
|
||||||
case PG_TYPE_BOOL: return "bool";
|
case PG_TYPE_BOOL: return "bool";
|
||||||
case PG_TYPE_BYTEA: return "bytea";
|
case PG_TYPE_BYTEA: return "bytea";
|
||||||
|
|
||||||
/* "unknown" can actually be used in alter table because it is a real PG type! */
|
case PG_TYPE_LO: return PG_TYPE_LO_NAME;
|
||||||
default: return "unknown";
|
|
||||||
}
|
default:
|
||||||
|
if (type == stmt->hdbc->lobj_type) /* hack until permanent type is available */
|
||||||
|
return PG_TYPE_LO_NAME;
|
||||||
|
|
||||||
|
/* "unknown" can actually be used in alter table because it is a real PG type! */
|
||||||
|
return "unknown";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* For PG_TYPE_VARCHAR, PG_TYPE_BPCHAR, SQLColumns will
|
Int4
|
||||||
override this length with the atttypmod length from pg_attribute
|
getCharPrecision(StatementClass *stmt, Int4 type, int col, int handle_unknown_size_as)
|
||||||
*/
|
|
||||||
Int4 pgtype_precision(Int4 type)
|
|
||||||
{
|
{
|
||||||
|
int p = -1, maxsize;
|
||||||
|
QResultClass *result;
|
||||||
|
ColumnInfoClass *flds;
|
||||||
|
|
||||||
|
mylog("getCharPrecision: type=%d, col=%d, unknown = %d\n", type,col,handle_unknown_size_as);
|
||||||
|
|
||||||
|
/* Assign Maximum size based on parameters */
|
||||||
|
switch(type) {
|
||||||
|
case PG_TYPE_TEXT:
|
||||||
|
if (globals.text_as_longvarchar)
|
||||||
|
maxsize = globals.max_longvarchar_size;
|
||||||
|
else
|
||||||
|
maxsize = globals.max_varchar_size;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PG_TYPE_VARCHAR:
|
||||||
|
case PG_TYPE_BPCHAR:
|
||||||
|
maxsize = globals.max_varchar_size;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
if (globals.unknowns_as_longvarchar)
|
||||||
|
maxsize = globals.max_longvarchar_size;
|
||||||
|
else
|
||||||
|
maxsize = globals.max_varchar_size;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Static Precision (i.e., the Maximum Precision of the datatype)
|
||||||
|
This has nothing to do with a result set.
|
||||||
|
*/
|
||||||
|
if (col < 0)
|
||||||
|
return maxsize;
|
||||||
|
|
||||||
|
result = SC_get_Result(stmt);
|
||||||
|
|
||||||
|
/* Manual Result Sets -- use assigned column width (i.e., from set_tuplefield_string) */
|
||||||
|
if (stmt->manual_result) {
|
||||||
|
flds = result->fields;
|
||||||
|
if (flds)
|
||||||
|
return flds->adtsize[col];
|
||||||
|
else
|
||||||
|
return maxsize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Size is unknown -- handle according to parameter */
|
||||||
|
if (type == PG_TYPE_BPCHAR || handle_unknown_size_as == UNKNOWNS_AS_LONGEST) {
|
||||||
|
p = QR_get_display_size(result, col);
|
||||||
|
mylog("getCharPrecision: LONGEST: p = %d\n", p);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p < 0 && handle_unknown_size_as == UNKNOWNS_AS_MAX)
|
||||||
|
return maxsize;
|
||||||
|
else
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* For PG_TYPE_VARCHAR, PG_TYPE_BPCHAR, SQLColumns will
|
||||||
|
override this length with the atttypmod length from pg_attribute .
|
||||||
|
|
||||||
|
If col >= 0, then will attempt to get the info from the result set.
|
||||||
|
This is used for functions SQLDescribeCol and SQLColAttributes.
|
||||||
|
*/
|
||||||
|
Int4 pgtype_precision(StatementClass *stmt, Int4 type, int col, int handle_unknown_size_as)
|
||||||
|
{
|
||||||
|
|
||||||
switch(type) {
|
switch(type) {
|
||||||
|
|
||||||
case PG_TYPE_CHAR: return 1;
|
case PG_TYPE_CHAR: return 1;
|
||||||
case PG_TYPE_CHAR2: return 2;
|
case PG_TYPE_CHAR2: return 2;
|
||||||
case PG_TYPE_CHAR4: return 4;
|
case PG_TYPE_CHAR4: return 4;
|
||||||
case PG_TYPE_CHAR8: return 8;
|
case PG_TYPE_CHAR8: return 8;
|
||||||
case PG_TYPE_CHAR16: return 16;
|
case PG_TYPE_CHAR16: return 16;
|
||||||
|
|
||||||
case PG_TYPE_NAME: return 32;
|
case PG_TYPE_NAME: return NAME_FIELD_SIZE;
|
||||||
|
|
||||||
case PG_TYPE_VARCHAR:
|
case PG_TYPE_INT2: return 5;
|
||||||
case PG_TYPE_BPCHAR: return MAX_VARCHAR_SIZE;
|
|
||||||
|
|
||||||
case PG_TYPE_INT2: return 5;
|
|
||||||
|
|
||||||
case PG_TYPE_OID:
|
case PG_TYPE_OID:
|
||||||
case PG_TYPE_INT4: return 10;
|
case PG_TYPE_INT4: return 10;
|
||||||
|
|
||||||
|
@ -180,29 +273,46 @@ Int4 pgtype_precision(Int4 type)
|
||||||
|
|
||||||
case PG_TYPE_BOOL: return 1;
|
case PG_TYPE_BOOL: return 1;
|
||||||
|
|
||||||
|
case PG_TYPE_LO: return SQL_NO_TOTAL;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return TEXT_FIELD_SIZE; /* text field types and unknown types */
|
|
||||||
|
if (type == stmt->hdbc->lobj_type) /* hack until permanent type is available */
|
||||||
|
return SQL_NO_TOTAL;
|
||||||
|
|
||||||
|
/* Handle Character types and unknown types */
|
||||||
|
return getCharPrecision(stmt, type, col, handle_unknown_size_as);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* For PG_TYPE_VARCHAR, PG_TYPE_BPCHAR, SQLColumns will
|
Int4 pgtype_display_size(StatementClass *stmt, Int4 type, int col, int handle_unknown_size_as)
|
||||||
override this length with the atttypmod length from pg_attribute
|
{
|
||||||
*/
|
switch(type) {
|
||||||
Int4 pgtype_length(Int4 type)
|
case PG_TYPE_INT2: return 6;
|
||||||
|
|
||||||
|
case PG_TYPE_OID: return 10;
|
||||||
|
|
||||||
|
case PG_TYPE_INT4: return 11;
|
||||||
|
|
||||||
|
case PG_TYPE_MONEY: return 15; /* ($9,999,999.99) */
|
||||||
|
|
||||||
|
case PG_TYPE_FLOAT4: return 13;
|
||||||
|
|
||||||
|
case PG_TYPE_FLOAT8: return 22;
|
||||||
|
|
||||||
|
/* Character types use regular precision */
|
||||||
|
default:
|
||||||
|
return pgtype_precision(stmt, type, col, handle_unknown_size_as);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* For PG_TYPE_VARCHAR, PG_TYPE_BPCHAR, SQLColumns will
|
||||||
|
override this length with the atttypmod length from pg_attribute
|
||||||
|
*/
|
||||||
|
Int4 pgtype_length(StatementClass *stmt, Int4 type, int col, int handle_unknown_size_as)
|
||||||
{
|
{
|
||||||
switch(type) {
|
switch(type) {
|
||||||
|
|
||||||
case PG_TYPE_CHAR: return 1;
|
|
||||||
case PG_TYPE_CHAR2: return 2;
|
|
||||||
case PG_TYPE_CHAR4: return 4;
|
|
||||||
case PG_TYPE_CHAR8: return 8;
|
|
||||||
case PG_TYPE_CHAR16: return 16;
|
|
||||||
|
|
||||||
case PG_TYPE_NAME: return 32;
|
|
||||||
|
|
||||||
case PG_TYPE_VARCHAR:
|
|
||||||
case PG_TYPE_BPCHAR: return MAX_VARCHAR_SIZE;
|
|
||||||
|
|
||||||
case PG_TYPE_INT2: return 2;
|
case PG_TYPE_INT2: return 2;
|
||||||
|
|
||||||
case PG_TYPE_OID:
|
case PG_TYPE_OID:
|
||||||
|
@ -219,14 +329,14 @@ Int4 pgtype_length(Int4 type)
|
||||||
case PG_TYPE_ABSTIME:
|
case PG_TYPE_ABSTIME:
|
||||||
case PG_TYPE_DATETIME: return 16;
|
case PG_TYPE_DATETIME: return 16;
|
||||||
|
|
||||||
case PG_TYPE_BOOL: return 1;
|
|
||||||
|
|
||||||
default:
|
/* Character types use the default precision */
|
||||||
return TEXT_FIELD_SIZE; /* text field types and unknown types */
|
default:
|
||||||
|
return pgtype_precision(stmt, type, col, handle_unknown_size_as);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Int2 pgtype_scale(Int4 type)
|
Int2 pgtype_scale(StatementClass *stmt, Int4 type)
|
||||||
{
|
{
|
||||||
switch(type) {
|
switch(type) {
|
||||||
|
|
||||||
|
@ -247,7 +357,7 @@ Int2 pgtype_scale(Int4 type)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Int2 pgtype_radix(Int4 type)
|
Int2 pgtype_radix(StatementClass *stmt, Int4 type)
|
||||||
{
|
{
|
||||||
switch(type) {
|
switch(type) {
|
||||||
case PG_TYPE_INT2:
|
case PG_TYPE_INT2:
|
||||||
|
@ -261,12 +371,12 @@ Int2 pgtype_radix(Int4 type)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Int2 pgtype_nullable(Int4 type)
|
Int2 pgtype_nullable(StatementClass *stmt, Int4 type)
|
||||||
{
|
{
|
||||||
return SQL_NULLABLE; /* everything should be nullable */
|
return SQL_NULLABLE; /* everything should be nullable */
|
||||||
}
|
}
|
||||||
|
|
||||||
Int2 pgtype_auto_increment(Int4 type)
|
Int2 pgtype_auto_increment(StatementClass *stmt, Int4 type)
|
||||||
{
|
{
|
||||||
switch(type) {
|
switch(type) {
|
||||||
|
|
||||||
|
@ -287,7 +397,7 @@ Int2 pgtype_auto_increment(Int4 type)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Int2 pgtype_case_sensitive(Int4 type)
|
Int2 pgtype_case_sensitive(StatementClass *stmt, Int4 type)
|
||||||
{
|
{
|
||||||
switch(type) {
|
switch(type) {
|
||||||
case PG_TYPE_CHAR:
|
case PG_TYPE_CHAR:
|
||||||
|
@ -306,7 +416,7 @@ Int2 pgtype_case_sensitive(Int4 type)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Int2 pgtype_money(Int4 type)
|
Int2 pgtype_money(StatementClass *stmt, Int4 type)
|
||||||
{
|
{
|
||||||
switch(type) {
|
switch(type) {
|
||||||
case PG_TYPE_MONEY: return TRUE;
|
case PG_TYPE_MONEY: return TRUE;
|
||||||
|
@ -314,7 +424,7 @@ Int2 pgtype_money(Int4 type)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Int2 pgtype_searchable(Int4 type)
|
Int2 pgtype_searchable(StatementClass *stmt, Int4 type)
|
||||||
{
|
{
|
||||||
switch(type) {
|
switch(type) {
|
||||||
case PG_TYPE_CHAR:
|
case PG_TYPE_CHAR:
|
||||||
|
@ -329,11 +439,10 @@ Int2 pgtype_searchable(Int4 type)
|
||||||
case PG_TYPE_NAME: return SQL_SEARCHABLE;
|
case PG_TYPE_NAME: return SQL_SEARCHABLE;
|
||||||
|
|
||||||
default: return SQL_ALL_EXCEPT_LIKE;
|
default: return SQL_ALL_EXCEPT_LIKE;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Int2 pgtype_unsigned(Int4 type)
|
Int2 pgtype_unsigned(StatementClass *stmt, Int4 type)
|
||||||
{
|
{
|
||||||
switch(type) {
|
switch(type) {
|
||||||
case PG_TYPE_OID: return TRUE;
|
case PG_TYPE_OID: return TRUE;
|
||||||
|
@ -348,7 +457,7 @@ Int2 pgtype_unsigned(Int4 type)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
char *pgtype_literal_prefix(Int4 type)
|
char *pgtype_literal_prefix(StatementClass *stmt, Int4 type)
|
||||||
{
|
{
|
||||||
switch(type) {
|
switch(type) {
|
||||||
|
|
||||||
|
@ -363,7 +472,7 @@ char *pgtype_literal_prefix(Int4 type)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
char *pgtype_literal_suffix(Int4 type)
|
char *pgtype_literal_suffix(StatementClass *stmt, Int4 type)
|
||||||
{
|
{
|
||||||
switch(type) {
|
switch(type) {
|
||||||
|
|
||||||
|
@ -378,7 +487,7 @@ char *pgtype_literal_suffix(Int4 type)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
char *pgtype_create_params(Int4 type)
|
char *pgtype_create_params(StatementClass *stmt, Int4 type)
|
||||||
{
|
{
|
||||||
switch(type) {
|
switch(type) {
|
||||||
case PG_TYPE_CHAR:
|
case PG_TYPE_CHAR:
|
||||||
|
|
|
@ -1,19 +1,22 @@
|
||||||
|
|
||||||
/* File: pgtypes.h
|
/* File: pgtypes.h
|
||||||
*
|
*
|
||||||
* Description: See "pgtypes.c"
|
* Description: See "pgtypes.c"
|
||||||
*
|
*
|
||||||
* Comments: See "notice.txt" for copyright and license information.
|
* Comments: See "notice.txt" for copyright and license information.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __PGTYPES_H__
|
#ifndef __PGTYPES_H__
|
||||||
#define __PGTYPES_H__
|
#define __PGTYPES_H__
|
||||||
|
|
||||||
|
#include "psqlodbc.h"
|
||||||
|
|
||||||
/* the type numbers are defined by the OID's of the types' rows */
|
/* the type numbers are defined by the OID's of the types' rows */
|
||||||
/* in table pg_type */
|
/* in table pg_type */
|
||||||
|
|
||||||
#define PG_UNKNOWN -666 /* returned only from pgtype_to_sqltype() */
|
|
||||||
|
// #define PG_TYPE_LO ???? /* waiting for permanent type */
|
||||||
|
|
||||||
#define PG_TYPE_BOOL 16
|
#define PG_TYPE_BOOL 16
|
||||||
#define PG_TYPE_BYTEA 17
|
#define PG_TYPE_BYTEA 17
|
||||||
|
@ -58,22 +61,30 @@
|
||||||
|
|
||||||
extern Int4 pgtypes_defined[];
|
extern Int4 pgtypes_defined[];
|
||||||
|
|
||||||
Int2 pgtype_to_sqltype(Int4 type);
|
/* Defines for pgtype_precision */
|
||||||
Int2 pgtype_to_ctype(Int4 type);
|
#define PG_STATIC -1
|
||||||
char *pgtype_to_name(Int4 type);
|
|
||||||
Int4 pgtype_precision(Int4 type);
|
|
||||||
Int4 pgtype_length(Int4 type);
|
Int2 pgtype_to_sqltype(StatementClass *stmt, Int4 type);
|
||||||
Int2 pgtype_scale(Int4 type);
|
Int2 pgtype_to_ctype(StatementClass *stmt, Int4 type);
|
||||||
Int2 pgtype_radix(Int4 type);
|
char *pgtype_to_name(StatementClass *stmt, Int4 type);
|
||||||
Int2 pgtype_nullable(Int4 type);
|
|
||||||
Int2 pgtype_auto_increment(Int4 type);
|
/* These functions can use static numbers or result sets(col parameter) */
|
||||||
Int2 pgtype_case_sensitive(Int4 type);
|
Int4 pgtype_precision(StatementClass *stmt, Int4 type, int col, int handle_unknown_size_as);
|
||||||
Int2 pgtype_money(Int4 type);
|
Int4 pgtype_display_size(StatementClass *stmt, Int4 type, int col, int handle_unknown_size_as);
|
||||||
Int2 pgtype_searchable(Int4 type);
|
Int4 pgtype_length(StatementClass *stmt, Int4 type, int col, int handle_unknown_size_as);
|
||||||
Int2 pgtype_unsigned(Int4 type);
|
|
||||||
char *pgtype_literal_prefix(Int4 type);
|
Int2 pgtype_scale(StatementClass *stmt, Int4 type);
|
||||||
char *pgtype_literal_suffix(Int4 type);
|
Int2 pgtype_radix(StatementClass *stmt, Int4 type);
|
||||||
char *pgtype_create_params(Int4 type);
|
Int2 pgtype_nullable(StatementClass *stmt, Int4 type);
|
||||||
|
Int2 pgtype_auto_increment(StatementClass *stmt, Int4 type);
|
||||||
|
Int2 pgtype_case_sensitive(StatementClass *stmt, Int4 type);
|
||||||
|
Int2 pgtype_money(StatementClass *stmt, Int4 type);
|
||||||
|
Int2 pgtype_searchable(StatementClass *stmt, Int4 type);
|
||||||
|
Int2 pgtype_unsigned(StatementClass *stmt, Int4 type);
|
||||||
|
char *pgtype_literal_prefix(StatementClass *stmt, Int4 type);
|
||||||
|
char *pgtype_literal_suffix(StatementClass *stmt, Int4 type);
|
||||||
|
char *pgtype_create_params(StatementClass *stmt, Int4 type);
|
||||||
|
|
||||||
Int2 sqltype_to_default_ctype(Int2 sqltype);
|
Int2 sqltype_to_default_ctype(Int2 sqltype);
|
||||||
|
|
||||||
|
|
|
@ -1,88 +1,28 @@
|
||||||
|
|
||||||
/* Module: psqlodbc.c
|
/* Module: psqlodbc.c
|
||||||
*
|
*
|
||||||
* Description: This module contains the main entry point (DllMain) for the library.
|
* Description: This module contains the main entry point (DllMain) for the library.
|
||||||
* It also contains functions to get and set global variables for the
|
* It also contains functions to get and set global variables for the
|
||||||
* driver in the registry.
|
* driver in the registry.
|
||||||
*
|
*
|
||||||
* Classes: n/a
|
* Classes: n/a
|
||||||
*
|
*
|
||||||
* API functions: none
|
* API functions: none
|
||||||
*
|
*
|
||||||
* Comments: See "notice.txt" for copyright and license information.
|
* Comments: See "notice.txt" for copyright and license information.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "psqlodbc.h"
|
#include "psqlodbc.h"
|
||||||
|
#include "dlg_specific.h"
|
||||||
#include <winsock.h>
|
#include <winsock.h>
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <sql.h>
|
#include <sql.h>
|
||||||
#include <odbcinst.h>
|
#include <odbcinst.h>
|
||||||
|
|
||||||
HINSTANCE NEAR s_hModule; /* Saved module handle. */
|
HINSTANCE NEAR s_hModule; /* Saved module handle. */
|
||||||
GLOBAL_VALUES globals;
|
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 */
|
/* This is where the Driver Manager attaches to this Driver */
|
||||||
BOOL WINAPI DllMain(HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved)
|
BOOL WINAPI DllMain(HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved)
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
|
|
||||||
/* File: psqlodbc.h
|
/* File: psqlodbc.h
|
||||||
*
|
*
|
||||||
* Description: This file contains defines and declarations that are related to
|
* Description: This file contains defines and declarations that are related to
|
||||||
* the entire driver.
|
* the entire driver.
|
||||||
*
|
*
|
||||||
* Comments: See "notice.txt" for copyright and license information.
|
* Comments: See "notice.txt" for copyright and license information.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __PSQLODBC_H__
|
#ifndef __PSQLODBC_H__
|
||||||
#define __PSQLODBC_H__
|
#define __PSQLODBC_H__
|
||||||
|
@ -21,27 +21,23 @@ typedef UInt4 Oid;
|
||||||
|
|
||||||
/* Limits */
|
/* Limits */
|
||||||
#define MAX_MESSAGE_LEN 8192
|
#define MAX_MESSAGE_LEN 8192
|
||||||
#define MAX_CONNECT_STRING 4096
|
#define MAX_CONNECT_STRING 4096
|
||||||
#define ERROR_MSG_LENGTH 4096
|
#define ERROR_MSG_LENGTH 4096
|
||||||
#define FETCH_MAX 100 /* default number of rows to cache for declare/fetch */
|
#define FETCH_MAX 100 /* default number of rows to cache for declare/fetch */
|
||||||
#define SOCK_BUFFER_SIZE 4096 /* default socket buffer size */
|
#define FETCH_INCR 1000
|
||||||
|
#define SOCK_BUFFER_SIZE 4096 /* default socket buffer size */
|
||||||
#define MAX_CONNECTIONS 128 /* conns per environment (arbitrary) */
|
#define MAX_CONNECTIONS 128 /* conns per environment (arbitrary) */
|
||||||
#define MAX_FIELDS 512
|
#define MAX_FIELDS 512
|
||||||
#define BYTELEN 8
|
#define BYTELEN 8
|
||||||
#define VARHDRSZ sizeof(Int4)
|
#define VARHDRSZ sizeof(Int4)
|
||||||
|
|
||||||
/* Registry length limits */
|
/* Registry length limits */
|
||||||
#define LARGE_REGISTRY_LEN 4096 /* used for special cases */
|
#define LARGE_REGISTRY_LEN 4096 /* used for special cases */
|
||||||
#define MEDIUM_REGISTRY_LEN 128 /* normal size for user,database,etc. */
|
#define MEDIUM_REGISTRY_LEN 256 /* normal size for user,database,etc. */
|
||||||
#define SMALL_REGISTRY_LEN 10 /* for 1/0 settings */
|
#define SMALL_REGISTRY_LEN 10 /* for 1/0 settings */
|
||||||
|
|
||||||
|
|
||||||
/* Connection Defaults */
|
|
||||||
#define DEFAULT_PORT "5432"
|
|
||||||
#define DEFAULT_READONLY "1"
|
|
||||||
|
|
||||||
/* These prefixes denote system tables */
|
/* These prefixes denote system tables */
|
||||||
#define INSIGHT_SYS_PREFIX "dd_"
|
|
||||||
#define POSTGRES_SYS_PREFIX "pg_"
|
#define POSTGRES_SYS_PREFIX "pg_"
|
||||||
#define KEYS_TABLE "dd_fkey"
|
#define KEYS_TABLE "dd_fkey"
|
||||||
|
|
||||||
|
@ -54,33 +50,13 @@ typedef UInt4 Oid;
|
||||||
/* Driver stuff */
|
/* Driver stuff */
|
||||||
#define DRIVERNAME "PostgreSQL ODBC"
|
#define DRIVERNAME "PostgreSQL ODBC"
|
||||||
#define DBMS_NAME "PostgreSQL"
|
#define DBMS_NAME "PostgreSQL"
|
||||||
#define DBMS_VERSION "06.30.0000 PostgreSQL 6.3"
|
#define DBMS_VERSION "06.30.0244 PostgreSQL 6.3"
|
||||||
#define POSTGRESDRIVERVERSION "06.30.0000"
|
#define POSTGRESDRIVERVERSION "06.30.0244"
|
||||||
#define DRIVER_FILE_NAME "PSQLODBC.DLL"
|
#define DRIVER_FILE_NAME "PSQLODBC.DLL"
|
||||||
|
|
||||||
|
|
||||||
#define PG62 "6.2" /* "Protocol" key setting to force Postgres 6.2 */
|
|
||||||
|
|
||||||
/* INI File Stuff */
|
|
||||||
#define ODBC_INI "ODBC.INI" /* ODBC initialization file */
|
|
||||||
#define ODBCINST_INI "ODBCINST.INI" /* ODBC Installation file */
|
|
||||||
|
|
||||||
#define INI_DSN DBMS_NAME /* Name of default Datasource in ini file (not used?) */
|
#define PG62 "6.2" /* "Protocol" key setting to force Postgres 6.2 */
|
||||||
#define INI_KDESC "Description" /* Data source description */
|
|
||||||
#define INI_SERVER "Servername" /* Name of Server running the Postgres service */
|
|
||||||
#define INI_PORT "Port" /* Port on which the Postmaster is listening */
|
|
||||||
#define INI_DATABASE "Database" /* Database Name */
|
|
||||||
#define INI_USER "Username" /* Default User Name */
|
|
||||||
#define INI_PASSWORD "Password" /* Default Password */
|
|
||||||
#define INI_DEBUG "Debug" /* Debug flag */
|
|
||||||
#define INI_FETCH "Fetch" /* Fetch Max Count */
|
|
||||||
#define INI_SOCKET "Socket" /* Socket buffer size */
|
|
||||||
#define INI_READONLY "ReadOnly" /* Database is read only */
|
|
||||||
#define INI_COMMLOG "CommLog" /* Communication to backend logging */
|
|
||||||
#define INI_PROTOCOL "Protocol" /* What protocol (6.2) */
|
|
||||||
#define INI_OPTIMIZER "Optimizer" /* Use backend genetic optimizer */
|
|
||||||
#define INI_CONNSETTINGS "ConnSettings" /* Anything to send to backend on successful connection */
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct ConnectionClass_ ConnectionClass;
|
typedef struct ConnectionClass_ ConnectionClass;
|
||||||
typedef struct StatementClass_ StatementClass;
|
typedef struct StatementClass_ StatementClass;
|
||||||
|
@ -93,27 +69,40 @@ typedef struct TupleListClass_ TupleListClass;
|
||||||
typedef struct EnvironmentClass_ EnvironmentClass;
|
typedef struct EnvironmentClass_ EnvironmentClass;
|
||||||
typedef struct TupleNode_ TupleNode;
|
typedef struct TupleNode_ TupleNode;
|
||||||
typedef struct TupleField_ TupleField;
|
typedef struct TupleField_ TupleField;
|
||||||
|
|
||||||
|
|
||||||
typedef struct GlobalValues_
|
|
||||||
{
|
|
||||||
int fetch_max;
|
|
||||||
int socket_buffersize;
|
|
||||||
int debug;
|
|
||||||
int commlog;
|
|
||||||
char optimizer[MEDIUM_REGISTRY_LEN];
|
|
||||||
char conn_settings[LARGE_REGISTRY_LEN];
|
|
||||||
} GLOBAL_VALUES;
|
|
||||||
|
|
||||||
|
|
||||||
/* sizes */
|
|
||||||
#define TEXT_FIELD_SIZE 4094 /* size of text fields (not including null term) */
|
|
||||||
#define MAX_VARCHAR_SIZE 254 /* maximum size of a varchar (not including null term) */
|
|
||||||
|
|
||||||
|
typedef struct lo_arg LO_ARG;
|
||||||
/* global prototypes */
|
|
||||||
void updateGlobals(void);
|
typedef struct GlobalValues_
|
||||||
|
{
|
||||||
|
int fetch_max;
|
||||||
|
int socket_buffersize;
|
||||||
|
int unknown_sizes;
|
||||||
|
int max_varchar_size;
|
||||||
|
int max_longvarchar_size;
|
||||||
|
char debug;
|
||||||
|
char commlog;
|
||||||
|
char disable_optimizer;
|
||||||
|
char unique_index;
|
||||||
|
char readonly;
|
||||||
|
char use_declarefetch;
|
||||||
|
char text_as_longvarchar;
|
||||||
|
char unknowns_as_longvarchar;
|
||||||
|
char bools_as_char;
|
||||||
|
char extra_systable_prefixes[MEDIUM_REGISTRY_LEN];
|
||||||
|
char conn_settings[LARGE_REGISTRY_LEN];
|
||||||
|
} GLOBAL_VALUES;
|
||||||
|
|
||||||
|
|
||||||
|
#define PG_TYPE_LO -999 /* hack until permanent type available */
|
||||||
|
#define PG_TYPE_LO_NAME "lo"
|
||||||
|
#define OID_ATTNUM -2 /* the attnum in pg_index of the oid */
|
||||||
|
|
||||||
|
/* sizes */
|
||||||
|
#define TEXT_FIELD_SIZE 4094 /* size of text fields (not including null term) */
|
||||||
|
#define NAME_FIELD_SIZE 32 /* size of name fields */
|
||||||
|
#define MAX_VARCHAR_SIZE 254 /* maximum size of a varchar (not including null term) */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#include "misc.h"
|
#include "misc.h"
|
||||||
|
|
||||||
|
|
|
@ -1,205 +1,262 @@
|
||||||
//Microsoft Developer Studio generated resource script.
|
//Microsoft Developer Studio generated resource script.
|
||||||
//
|
//
|
||||||
#include "resource.h"
|
#include "resource.h"
|
||||||
|
|
||||||
#define APSTUDIO_READONLY_SYMBOLS
|
#define APSTUDIO_READONLY_SYMBOLS
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// Generated from the TEXTINCLUDE 2 resource.
|
// Generated from the TEXTINCLUDE 2 resource.
|
||||||
//
|
//
|
||||||
#include "afxres.h"
|
#include "afxres.h"
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
#undef APSTUDIO_READONLY_SYMBOLS
|
#undef APSTUDIO_READONLY_SYMBOLS
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
// English (U.S.) resources
|
// English (U.S.) resources
|
||||||
|
|
||||||
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
|
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||||
#pragma code_page(1252)
|
#pragma code_page(1252)
|
||||||
#endif //_WIN32
|
#endif //_WIN32
|
||||||
|
|
||||||
#ifdef APSTUDIO_INVOKED
|
#ifdef APSTUDIO_INVOKED
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// TEXTINCLUDE
|
// TEXTINCLUDE
|
||||||
//
|
//
|
||||||
|
|
||||||
1 TEXTINCLUDE DISCARDABLE
|
1 TEXTINCLUDE DISCARDABLE
|
||||||
BEGIN
|
BEGIN
|
||||||
"resource.h\0"
|
"resource.h\0"
|
||||||
END
|
END
|
||||||
|
|
||||||
2 TEXTINCLUDE DISCARDABLE
|
2 TEXTINCLUDE DISCARDABLE
|
||||||
BEGIN
|
BEGIN
|
||||||
"#include ""afxres.h""\r\n"
|
"#include ""afxres.h""\r\n"
|
||||||
"\0"
|
"\0"
|
||||||
END
|
END
|
||||||
|
|
||||||
3 TEXTINCLUDE DISCARDABLE
|
3 TEXTINCLUDE DISCARDABLE
|
||||||
BEGIN
|
BEGIN
|
||||||
"\r\n"
|
"\r\n"
|
||||||
"\0"
|
"\0"
|
||||||
END
|
END
|
||||||
|
|
||||||
#endif // APSTUDIO_INVOKED
|
#endif // APSTUDIO_INVOKED
|
||||||
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// Dialog
|
// Dialog
|
||||||
//
|
//
|
||||||
|
|
||||||
DRIVERCONNDIALOG DIALOG DISCARDABLE 0, 0, 269, 133
|
DLG_CONFIG DIALOG DISCARDABLE 65, 43, 292, 116
|
||||||
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
|
STYLE DS_MODALFRAME | DS_3DLOOK | WS_POPUP | WS_VISIBLE | WS_CAPTION |
|
||||||
CAPTION "PostgreSQL Connection"
|
WS_SYSMENU
|
||||||
FONT 8, "MS Sans Serif"
|
CAPTION "PostgreSQL Driver Setup"
|
||||||
BEGIN
|
FONT 8, "MS Sans Serif"
|
||||||
RTEXT "&Database:",IDC_STATIC,16,25,37,8
|
BEGIN
|
||||||
EDITTEXT DATABASE_EDIT,55,25,72,12,ES_AUTOHSCROLL
|
RTEXT "&Data Source:",IDC_DSNAMETEXT,5,10,50,12,NOT WS_GROUP
|
||||||
RTEXT "&Server:",IDC_STATIC,26,40,27,8
|
EDITTEXT IDC_DSNAME,57,10,72,12,ES_AUTOHSCROLL | WS_GROUP
|
||||||
EDITTEXT SERVER_EDIT,55,40,72,12,ES_AUTOHSCROLL
|
RTEXT "Des&cription:",IDC_DESCTEXT,135,10,39,12,NOT WS_GROUP
|
||||||
RTEXT "&Port:",IDC_STATIC,150,40,20,8
|
EDITTEXT IDC_DESC,175,10,108,12,ES_AUTOHSCROLL
|
||||||
EDITTEXT PORT_EDIT,172,40,72,12,ES_AUTOHSCROLL
|
RTEXT "Data&base:",IDC_STATIC,17,25,38,12,NOT WS_GROUP
|
||||||
RTEXT "&User Name:",IDC_STATIC,16,56,37,8
|
EDITTEXT IDC_DATABASE,57,25,72,12,ES_AUTOHSCROLL
|
||||||
EDITTEXT USERNAME_EDIT,55,56,72,12,ES_AUTOHSCROLL
|
RTEXT "&Server:",IDC_STATIC,27,40,29,12,NOT WS_GROUP
|
||||||
RTEXT "Pass&word:",IDC_STATIC,137,56,33,8
|
EDITTEXT IDC_SERVER,57,40,72,12,ES_AUTOHSCROLL
|
||||||
EDITTEXT PASSWORD_EDIT,172,56,72,12,ES_PASSWORD | ES_AUTOHSCROLL
|
RTEXT "&Port:",IDC_STATIC,153,40,22,12
|
||||||
GROUPBOX "Options:",IDC_STATIC,25,71,200,25
|
EDITTEXT IDC_PORT,175,40,37,12,ES_AUTOHSCROLL
|
||||||
CONTROL "&ReadOnly:",READONLY_EDIT,"Button",BS_AUTOCHECKBOX |
|
RTEXT "&User Name:",IDC_STATIC,17,55,39,12
|
||||||
BS_LEFTTEXT | BS_RIGHT | WS_GROUP | WS_TABSTOP,45,80,45,
|
EDITTEXT IDC_USER,57,55,72,12,ES_AUTOHSCROLL
|
||||||
14
|
RTEXT "Pass&word:",IDC_STATIC,141,55,34,12
|
||||||
CONTROL "&CommLog (Global):",COMMLOG_EDIT,"Button",
|
EDITTEXT IDC_PASSWORD,175,55,72,12,ES_PASSWORD | ES_AUTOHSCROLL
|
||||||
BS_AUTOCHECKBOX | BS_LEFTTEXT | BS_RIGHT | WS_TABSTOP,
|
DEFPUSHBUTTON "OK",IDOK,25,90,40,14,WS_GROUP
|
||||||
100,80,75,14
|
PUSHBUTTON "Cancel",IDCANCEL,80,90,40,14
|
||||||
CONTROL "6.2",PG62_EDIT,"Button",BS_AUTOCHECKBOX | BS_LEFTTEXT |
|
GROUPBOX "Options (Advanced):",IDC_STATIC,140,74,140,35,BS_CENTER
|
||||||
BS_RIGHT | WS_TABSTOP,185,80,25,14
|
PUSHBUTTON "Driver",IDC_DRIVER,160,90,50,14
|
||||||
DEFPUSHBUTTON "OK",IDOK,84,108,40,14,WS_GROUP
|
PUSHBUTTON "DataSource",IDC_DATASOURCE,220,90,50,14
|
||||||
PUSHBUTTON "Cancel",IDCANCEL,146,108,40,14
|
CTEXT "Please supply any missing information needed to connect.",
|
||||||
CTEXT "Please supply any missing information needed to connect.",
|
DRV_MSG_LABEL,36,5,220,15
|
||||||
IDC_STATIC,40,7,188,11
|
END
|
||||||
END
|
|
||||||
|
DLG_OPTIONS_DRV DIALOG DISCARDABLE 0, 0, 287, 226
|
||||||
CONFIGDSN DIALOG DISCARDABLE 65, 43, 292, 151
|
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
|
||||||
STYLE DS_MODALFRAME | DS_3DLOOK | WS_POPUP | WS_VISIBLE | WS_CAPTION |
|
CAPTION "Advanced Options (Driver)"
|
||||||
WS_SYSMENU
|
FONT 8, "MS Sans Serif"
|
||||||
CAPTION "PostgreSQL Driver Setup"
|
BEGIN
|
||||||
FONT 8, "MS Sans Serif"
|
CONTROL "Disable Genetic &Optimizer",DRV_OPTIMIZER,"Button",
|
||||||
BEGIN
|
BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP,15,10,97,10
|
||||||
RTEXT "&Data Source:",IDC_DSNAMETEXT,5,30,50,12,NOT WS_GROUP
|
CONTROL "Comm&Log (C:\\psqlodbc.log)",DRV_COMMLOG,"Button",
|
||||||
EDITTEXT IDC_DSNAME,57,30,72,12,ES_AUTOHSCROLL | WS_GROUP
|
BS_AUTOCHECKBOX | WS_TABSTOP,140,10,113,10
|
||||||
RTEXT "Des&cription:",IDC_STATIC,135,30,39,12,NOT WS_GROUP
|
CONTROL "Recognize Unique &Indexes",DRV_UNIQUEINDEX,"Button",
|
||||||
EDITTEXT IDC_DESC,175,30,108,12,ES_AUTOHSCROLL
|
BS_AUTOCHECKBOX | WS_TABSTOP,15,25,101,10
|
||||||
RTEXT "Data&base:",IDC_STATIC,17,45,38,12,NOT WS_GROUP
|
CONTROL "&ReadOnly (Default)",DRV_READONLY,"Button",
|
||||||
EDITTEXT IDC_DATABASE,57,45,72,12,ES_AUTOHSCROLL
|
BS_AUTOCHECKBOX | WS_TABSTOP,140,25,80,10
|
||||||
RTEXT "&Server:",IDC_STATIC,27,60,29,12,NOT WS_GROUP
|
CONTROL "&Use Declare/Fetch",DRV_USEDECLAREFETCH,"Button",
|
||||||
EDITTEXT IDC_SERVER,57,60,72,12,ES_AUTOHSCROLL
|
BS_AUTOCHECKBOX | WS_TABSTOP,15,40,80,10
|
||||||
RTEXT "&Port:",IDC_STATIC,153,60,22,12
|
GROUPBOX "Unknown Sizes",IDC_STATIC,10,55,175,25
|
||||||
EDITTEXT IDC_PORT,175,60,37,12,ES_AUTOHSCROLL
|
CONTROL "Maximum",DRV_UNKNOWN_MAX,"Button",BS_AUTORADIOBUTTON |
|
||||||
RTEXT "&User Name:",IDC_STATIC,17,75,39,12
|
WS_GROUP | WS_TABSTOP,15,65,45,10
|
||||||
EDITTEXT IDC_USER,57,75,72,12,ES_AUTOHSCROLL
|
CONTROL "Don't Know",DRV_UNKNOWN_DONTKNOW,"Button",
|
||||||
RTEXT "Pass&word:",IDC_STATIC,141,75,34,12
|
BS_AUTORADIOBUTTON | WS_TABSTOP,70,65,53,10
|
||||||
EDITTEXT IDC_PASSWORD,175,75,72,12,ES_PASSWORD | ES_AUTOHSCROLL
|
CONTROL "Longest",DRV_UNKNOWN_LONGEST,"Button",
|
||||||
GROUPBOX "Options:",IDC_STATIC,35,92,205,25
|
BS_AUTORADIOBUTTON | WS_TABSTOP,130,65,50,10
|
||||||
CONTROL "&ReadOnly:",IDC_READONLY,"Button",BS_AUTOCHECKBOX |
|
GROUPBOX "Data Type Options",IDC_STATIC,10,85,270,25
|
||||||
BS_LEFTTEXT | BS_RIGHT | WS_GROUP | WS_TABSTOP,50,100,45,
|
CONTROL "Text as LongVarChar",DRV_TEXT_LONGVARCHAR,"Button",
|
||||||
14
|
BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP,15,95,80,10
|
||||||
CONTROL "&CommLog (Global):",IDC_COMMLOG,"Button",
|
CONTROL "Unknowns as LongVarChar",DRV_UNKNOWNS_LONGVARCHAR,
|
||||||
BS_AUTOCHECKBOX | BS_LEFTTEXT | BS_RIGHT | WS_TABSTOP,
|
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,105,95,100,10
|
||||||
105,100,75,14
|
CONTROL "Bools as Char",DRV_BOOLS_CHAR,"Button",BS_AUTOCHECKBOX |
|
||||||
CONTROL "6.2",IDC_PG62,"Button",BS_AUTOCHECKBOX | BS_LEFTTEXT |
|
WS_TABSTOP,215,95,60,10
|
||||||
BS_RIGHT | WS_TABSTOP,195,100,25,14
|
LTEXT "&Cache Size:",IDC_STATIC,10,120,40,10
|
||||||
DEFPUSHBUTTON "OK",IDOK,85,129,40,14,WS_GROUP
|
EDITTEXT DRV_CACHE_SIZE,50,120,35,12,ES_AUTOHSCROLL
|
||||||
PUSHBUTTON "Cancel",IDCANCEL,145,129,40,14
|
LTEXT "Max &Varchar:",IDC_STATIC,90,120,45,10
|
||||||
CTEXT "Change data source name, description, or options. Then choose OK.",
|
EDITTEXT DRV_VARCHAR_SIZE,135,120,35,12,ES_AUTOHSCROLL
|
||||||
IDC_STATIC,44,5,180,17
|
LTEXT "Max Lon&gVarChar:",IDC_STATIC,180,120,60,10
|
||||||
END
|
EDITTEXT DRV_LONGVARCHAR_SIZE,240,120,35,12,ES_AUTOHSCROLL
|
||||||
|
LTEXT "SysTable &Prefixes:",IDC_STATIC,15,135,35,20
|
||||||
|
EDITTEXT DRV_EXTRASYSTABLEPREFIXES,50,140,75,12,ES_AUTOHSCROLL
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
RTEXT "Connect &Settings:",IDC_STATIC,10,165,35,25
|
||||||
//
|
EDITTEXT DRV_CONNSETTINGS,50,160,225,35,ES_MULTILINE |
|
||||||
// DESIGNINFO
|
ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_WANTRETURN
|
||||||
//
|
DEFPUSHBUTTON "OK",IDOK,45,205,50,14,WS_GROUP
|
||||||
|
PUSHBUTTON "Cancel",IDCANCEL,115,205,50,14
|
||||||
#ifdef APSTUDIO_INVOKED
|
PUSHBUTTON "Defaults",IDDEFAULTS,185,205,50,15
|
||||||
GUIDELINES DESIGNINFO DISCARDABLE
|
END
|
||||||
BEGIN
|
|
||||||
DRIVERCONNDIALOG, DIALOG
|
DLG_OPTIONS_DS DIALOG DISCARDABLE 0, 0, 267, 170
|
||||||
BEGIN
|
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
|
||||||
RIGHTMARGIN, 268
|
CAPTION "Advanced Options (DataSource)"
|
||||||
END
|
FONT 8, "MS Sans Serif"
|
||||||
END
|
BEGIN
|
||||||
#endif // APSTUDIO_INVOKED
|
CONTROL "&ReadOnly",DS_READONLY,"Button",BS_AUTOCHECKBOX |
|
||||||
|
WS_GROUP | WS_TABSTOP,25,10,45,15
|
||||||
|
CONTROL "&6.2 Protocol",DS_PG62,"Button",BS_AUTOCHECKBOX |
|
||||||
#ifndef _MAC
|
WS_TABSTOP,130,10,60,14
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
CONTROL "Show System &Tables",DS_SHOWSYSTEMTABLES,"Button",
|
||||||
//
|
BS_AUTOCHECKBOX | WS_TABSTOP,25,30,85,10
|
||||||
// Version
|
GROUPBOX "OID Options",IDC_STATIC,15,50,180,25
|
||||||
//
|
CONTROL "Show &Column",DS_SHOWOIDCOLUMN,"Button",BS_AUTOCHECKBOX |
|
||||||
|
WS_GROUP | WS_TABSTOP,25,60,59,10
|
||||||
VS_VERSION_INFO VERSIONINFO
|
CONTROL "Fake &Index",DS_FAKEOIDINDEX,"Button",BS_AUTOCHECKBOX |
|
||||||
FILEVERSION 6,30,0,0
|
WS_GROUP | WS_TABSTOP,115,60,51,10
|
||||||
PRODUCTVERSION 6,30,0,0
|
RTEXT "Connect &Settings:",IDC_STATIC,10,90,35,25
|
||||||
FILEFLAGSMASK 0x3L
|
EDITTEXT DS_CONNSETTINGS,50,85,200,35,ES_MULTILINE |
|
||||||
#ifdef _DEBUG
|
ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_WANTRETURN
|
||||||
FILEFLAGS 0x1L
|
DEFPUSHBUTTON "OK",IDOK,65,130,50,14,WS_GROUP
|
||||||
#else
|
PUSHBUTTON "Cancel",IDCANCEL,140,130,50,14
|
||||||
FILEFLAGS 0x0L
|
GROUPBOX "Unknown Sizes",IDC_STATIC,10,145,175,25,NOT WS_VISIBLE
|
||||||
#endif
|
CONTROL "Maximum",DS_UNKNOWN_MAX,"Button",BS_AUTORADIOBUTTON |
|
||||||
FILEOS 0x4L
|
NOT WS_VISIBLE | WS_GROUP | WS_TABSTOP,15,155,45,10
|
||||||
FILETYPE 0x2L
|
CONTROL "Don't Know",DS_UNKNOWN_DONTKNOW,"Button",
|
||||||
FILESUBTYPE 0x0L
|
BS_AUTORADIOBUTTON | NOT WS_VISIBLE | WS_TABSTOP,70,155,
|
||||||
BEGIN
|
53,10
|
||||||
BLOCK "StringFileInfo"
|
CONTROL "Longest",DS_UNKNOWN_LONGEST,"Button",BS_AUTORADIOBUTTON |
|
||||||
BEGIN
|
NOT WS_VISIBLE | WS_TABSTOP,130,155,50,10
|
||||||
BLOCK "040904e4"
|
END
|
||||||
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.0000\0"
|
// DESIGNINFO
|
||||||
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"
|
#ifdef APSTUDIO_INVOKED
|
||||||
VALUE "ProductName", "Microsoft Open Database Connectivity\0"
|
GUIDELINES DESIGNINFO DISCARDABLE
|
||||||
VALUE "ProductVersion", " 6.30.0000\0"
|
BEGIN
|
||||||
END
|
DLG_CONFIG, DIALOG
|
||||||
END
|
BEGIN
|
||||||
BLOCK "VarFileInfo"
|
BOTTOMMARGIN, 115
|
||||||
BEGIN
|
END
|
||||||
VALUE "Translation", 0x409, 1252
|
|
||||||
END
|
DLG_OPTIONS_DRV, DIALOG
|
||||||
END
|
BEGIN
|
||||||
|
LEFTMARGIN, 7
|
||||||
#endif // !_MAC
|
RIGHTMARGIN, 280
|
||||||
|
TOPMARGIN, 7
|
||||||
|
BOTTOMMARGIN, 219
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
END
|
||||||
//
|
|
||||||
// String Table
|
DLG_OPTIONS_DS, DIALOG
|
||||||
//
|
BEGIN
|
||||||
|
LEFTMARGIN, 5
|
||||||
STRINGTABLE DISCARDABLE
|
RIGHTMARGIN, 260
|
||||||
BEGIN
|
VERTGUIDE, 55
|
||||||
IDS_BADDSN "Invalid DSN entry, please recheck."
|
TOPMARGIN, 7
|
||||||
IDS_MSGTITLE "Invalid DSN"
|
BOTTOMMARGIN, 163
|
||||||
END
|
END
|
||||||
|
END
|
||||||
#endif // English (U.S.) resources
|
#endif // APSTUDIO_INVOKED
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
|
#ifndef _MAC
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
#ifndef APSTUDIO_INVOKED
|
//
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
// Version
|
||||||
//
|
//
|
||||||
// Generated from the TEXTINCLUDE 3 resource.
|
|
||||||
//
|
VS_VERSION_INFO VERSIONINFO
|
||||||
|
FILEVERSION 6,30,2,44
|
||||||
|
PRODUCTVERSION 6,30,2,44
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
FILEFLAGSMASK 0x3L
|
||||||
#endif // not APSTUDIO_INVOKED
|
#ifdef _DEBUG
|
||||||
|
FILEFLAGS 0x1L
|
||||||
|
#else
|
||||||
|
FILEFLAGS 0x0L
|
||||||
|
#endif
|
||||||
|
FILEOS 0x4L
|
||||||
|
FILETYPE 0x2L
|
||||||
|
FILESUBTYPE 0x0L
|
||||||
|
BEGIN
|
||||||
|
BLOCK "StringFileInfo"
|
||||||
|
BEGIN
|
||||||
|
BLOCK "040904e4"
|
||||||
|
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.0244\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.0244\0"
|
||||||
|
END
|
||||||
|
END
|
||||||
|
BLOCK "VarFileInfo"
|
||||||
|
BEGIN
|
||||||
|
VALUE "Translation", 0x409, 1252
|
||||||
|
END
|
||||||
|
END
|
||||||
|
|
||||||
|
#endif // !_MAC
|
||||||
|
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// String Table
|
||||||
|
//
|
||||||
|
|
||||||
|
STRINGTABLE DISCARDABLE
|
||||||
|
BEGIN
|
||||||
|
IDS_BADDSN "Invalid DSN entry, please recheck."
|
||||||
|
IDS_MSGTITLE "Invalid DSN"
|
||||||
|
END
|
||||||
|
|
||||||
|
#endif // English (U.S.) resources
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef APSTUDIO_INVOKED
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Generated from the TEXTINCLUDE 3 resource.
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
#endif // not APSTUDIO_INVOKED
|
||||||
|
|
||||||
|
|
|
@ -1,22 +1,22 @@
|
||||||
|
|
||||||
/* Module: qresult.c
|
/* Module: qresult.c
|
||||||
*
|
*
|
||||||
* Description: This module contains functions related to
|
* Description: This module contains functions related to
|
||||||
* managing result information (i.e, fetching rows from the backend,
|
* managing result information (i.e, fetching rows from the backend,
|
||||||
* managing the tuple cache, etc.) and retrieving it.
|
* managing the tuple cache, etc.) and retrieving it.
|
||||||
* Depending on the situation, a QResultClass will hold either data
|
* Depending on the situation, a QResultClass will hold either data
|
||||||
* from the backend or a manually built result (see "qresult.h" to
|
* from the backend or a manually built result (see "qresult.h" to
|
||||||
* see which functions/macros are for manual or backend results.
|
* see which functions/macros are for manual or backend results.
|
||||||
* For manually built results, the QResultClass simply points to
|
* For manually built results, the QResultClass simply points to
|
||||||
* TupleList and ColumnInfo structures, which actually hold the data.
|
* TupleList and ColumnInfo structures, which actually hold the data.
|
||||||
*
|
*
|
||||||
* Classes: QResultClass (Functions prefix: "QR_")
|
* Classes: QResultClass (Functions prefix: "QR_")
|
||||||
*
|
*
|
||||||
* API functions: none
|
* API functions: none
|
||||||
*
|
*
|
||||||
* Comments: See "notice.txt" for copyright and license information.
|
* Comments: See "notice.txt" for copyright and license information.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "qresult.h"
|
#include "qresult.h"
|
||||||
#include "misc.h"
|
#include "misc.h"
|
||||||
|
@ -24,7 +24,7 @@
|
||||||
|
|
||||||
extern GLOBAL_VALUES globals;
|
extern GLOBAL_VALUES globals;
|
||||||
|
|
||||||
/* Used for building a Manual Result only */
|
/* Used for building a Manual Result only */
|
||||||
/* All info functions call this function to create the manual result set. */
|
/* All info functions call this function to create the manual result set. */
|
||||||
void
|
void
|
||||||
QR_set_num_fields(QResultClass *self, int new_num_fields)
|
QR_set_num_fields(QResultClass *self, int new_num_fields)
|
||||||
|
@ -84,7 +84,7 @@ QR_Destructor(QResultClass *self)
|
||||||
mylog("QResult: in DESTRUCTOR\n");
|
mylog("QResult: in DESTRUCTOR\n");
|
||||||
|
|
||||||
/* manual result set tuples */
|
/* manual result set tuples */
|
||||||
if (self->manual_tuples)
|
if (self->manual_tuples)
|
||||||
TL_Destructor(self->manual_tuples);
|
TL_Destructor(self->manual_tuples);
|
||||||
|
|
||||||
// If conn is defined, then we may have used "backend_tuples",
|
// If conn is defined, then we may have used "backend_tuples",
|
||||||
|
@ -183,12 +183,14 @@ QR_fetch_tuples(QResultClass *self, ConnectionClass *conn, char *cursor)
|
||||||
if (self->cursor)
|
if (self->cursor)
|
||||||
free(self->cursor);
|
free(self->cursor);
|
||||||
|
|
||||||
if ( ! cursor || cursor[0] == '\0') {
|
if ( globals.use_declarefetch) {
|
||||||
self->status = PGRES_INTERNAL_ERROR;
|
if (! cursor || cursor[0] == '\0') {
|
||||||
QR_set_message(self, "Internal Error -- no cursor for fetch");
|
self->status = PGRES_INTERNAL_ERROR;
|
||||||
return FALSE;
|
QR_set_message(self, "Internal Error -- no cursor for fetch");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
self->cursor = strdup(cursor);
|
||||||
}
|
}
|
||||||
self->cursor = strdup(cursor);
|
|
||||||
|
|
||||||
// Read the field attributes.
|
// Read the field attributes.
|
||||||
// $$$$ Should do some error control HERE! $$$$
|
// $$$$ Should do some error control HERE! $$$$
|
||||||
|
@ -205,6 +207,7 @@ QR_fetch_tuples(QResultClass *self, ConnectionClass *conn, char *cursor)
|
||||||
mylog("QR_fetch_tuples: past CI_read_fields: num_fields = %d\n", self->num_fields);
|
mylog("QR_fetch_tuples: past CI_read_fields: num_fields = %d\n", self->num_fields);
|
||||||
|
|
||||||
/* allocate memory for the tuple cache */
|
/* allocate memory for the tuple cache */
|
||||||
|
mylog("MALLOC: fetch_max = %d, size = %d\n", globals.fetch_max, self->num_fields * sizeof(TupleField) * globals.fetch_max);
|
||||||
self->backend_tuples = (TupleField *) malloc(self->num_fields * sizeof(TupleField) * globals.fetch_max);
|
self->backend_tuples = (TupleField *) malloc(self->num_fields * sizeof(TupleField) * globals.fetch_max);
|
||||||
if ( ! self->backend_tuples) {
|
if ( ! self->backend_tuples) {
|
||||||
self->status = PGRES_FATAL_ERROR;
|
self->status = PGRES_FATAL_ERROR;
|
||||||
|
@ -232,24 +235,23 @@ QR_fetch_tuples(QResultClass *self, ConnectionClass *conn, char *cursor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close the cursor and end the transaction
|
// Close the cursor and end the transaction (if no cursors left)
|
||||||
// We only close cursor/end the transaction if a cursor was used.
|
// We only close cursor/end the transaction if a cursor was used.
|
||||||
int
|
int
|
||||||
QR_close(QResultClass *self)
|
QR_close(QResultClass *self)
|
||||||
{
|
{
|
||||||
QResultClass *res;
|
QResultClass *res;
|
||||||
|
|
||||||
if (self->conn && self->cursor) {
|
if (globals.use_declarefetch && self->conn && self->cursor) {
|
||||||
char buf[64];
|
char buf[64];
|
||||||
|
|
||||||
sprintf(buf, "close %s; END", self->cursor);
|
sprintf(buf, "close %s", self->cursor);
|
||||||
|
|
||||||
mylog("QResult: closing cursor: '%s'\n", buf);
|
mylog("QResult: closing cursor: '%s'\n", buf);
|
||||||
|
|
||||||
res = CC_send_query(self->conn, buf, NULL, NULL);
|
res = CC_send_query(self->conn, buf, NULL, NULL);
|
||||||
CC_set_no_trans(self->conn);
|
|
||||||
|
|
||||||
self->inTuples = FALSE;
|
self->inTuples = FALSE;
|
||||||
|
|
||||||
free(self->cursor);
|
free(self->cursor);
|
||||||
self->cursor = NULL;
|
self->cursor = NULL;
|
||||||
|
|
||||||
|
@ -259,6 +261,21 @@ QResultClass *res;
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* End the transaction if there are no cursors left on this conn */
|
||||||
|
if (CC_cursor_count(self->conn) == 0) {
|
||||||
|
mylog("QResult: END transaction on conn=%u\n", self->conn);
|
||||||
|
|
||||||
|
res = CC_send_query(self->conn, "END", NULL, NULL);
|
||||||
|
|
||||||
|
CC_set_no_trans(self->conn);
|
||||||
|
|
||||||
|
if (res == NULL) {
|
||||||
|
self->status = PGRES_FATAL_ERROR;
|
||||||
|
QR_set_message(self, "Error ending transaction.");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
@ -301,6 +318,13 @@ char cmdbuffer[MAX_MESSAGE_LEN+1]; // QR_set_command() dups this string so dont
|
||||||
if ( ! self->inTuples) {
|
if ( ! self->inTuples) {
|
||||||
char fetch[128];
|
char fetch[128];
|
||||||
|
|
||||||
|
if ( ! globals.use_declarefetch) {
|
||||||
|
mylog("next_tuple: ALL_ROWS: done, fcount = %d, fetch_count = %d\n", fcount, fetch_count);
|
||||||
|
self->tupleField = NULL;
|
||||||
|
self->status = PGRES_END_TUPLES;
|
||||||
|
return -1; /* end of tuples */
|
||||||
|
}
|
||||||
|
|
||||||
sprintf(fetch, "fetch %d in %s", globals.fetch_max, self->cursor);
|
sprintf(fetch, "fetch %d in %s", globals.fetch_max, self->cursor);
|
||||||
|
|
||||||
mylog("next_tuple: sending actual fetch (%d) query '%s'\n", globals.fetch_max, fetch);
|
mylog("next_tuple: sending actual fetch (%d) query '%s'\n", globals.fetch_max, fetch);
|
||||||
|
@ -336,65 +360,81 @@ char cmdbuffer[MAX_MESSAGE_LEN+1]; // QR_set_command() dups this string so dont
|
||||||
|
|
||||||
id = SOCK_get_char(sock);
|
id = SOCK_get_char(sock);
|
||||||
switch (id) {
|
switch (id) {
|
||||||
case 'T': /* Tuples within tuples cannot be handled */
|
case 'T': /* Tuples within tuples cannot be handled */
|
||||||
self->status = PGRES_BAD_RESPONSE;
|
self->status = PGRES_BAD_RESPONSE;
|
||||||
QR_set_message(self, "Tuples within tuples cannot be handled");
|
QR_set_message(self, "Tuples within tuples cannot be handled");
|
||||||
return FALSE;
|
return FALSE;
|
||||||
case 'B': /* Tuples in binary format */
|
case 'B': /* Tuples in binary format */
|
||||||
case 'D': /* Tuples in ASCII format */
|
case 'D': /* Tuples in ASCII format */
|
||||||
if ( ! QR_read_tuple(self, (char) (id == 0))) {
|
|
||||||
self->status = PGRES_BAD_RESPONSE;
|
|
||||||
QR_set_message(self, "Error reading the tuple");
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
self->fcount++;
|
if ( ! globals.use_declarefetch && self->fcount > 0 && ! (self->fcount % globals.fetch_max)) {
|
||||||
break; // continue reading
|
size_t old_size = self->fcount * self->num_fields * sizeof(TupleField);
|
||||||
|
mylog("REALLOC: old_size = %d\n", old_size);
|
||||||
|
|
||||||
|
self->backend_tuples = (TupleField *) realloc(self->backend_tuples, old_size + (self->num_fields * sizeof(TupleField) * globals.fetch_max));
|
||||||
case 'C': /* End of tuple list */
|
if ( ! self->backend_tuples) {
|
||||||
SOCK_get_string(sock, cmdbuffer, MAX_MESSAGE_LEN);
|
self->status = PGRES_FATAL_ERROR;
|
||||||
QR_set_command(self, cmdbuffer);
|
QR_set_message(self, "Out of memory while reading tuples.");
|
||||||
|
return FALSE;
|
||||||
mylog("end of tuple list -- setting inUse to false: this = %u\n", self);
|
|
||||||
|
|
||||||
self->inTuples = FALSE;
|
|
||||||
if (self->fcount > 0) {
|
|
||||||
|
|
||||||
qlog(" [ fetched %d rows ]\n", self->fcount);
|
|
||||||
mylog("_next_tuple: 'C' fetch_max && fcount = %d\n", self->fcount);
|
|
||||||
|
|
||||||
/* set to first row */
|
|
||||||
self->tupleField = the_tuples;
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
else { // We are surely done here (we read 0 tuples)
|
|
||||||
qlog(" [ fetched 0 rows ]\n");
|
|
||||||
mylog("_next_tuple: 'C': DONE (fcount == 0)\n");
|
|
||||||
return -1; /* end of tuples */
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
case 'E': /* Error */
|
if ( ! QR_read_tuple(self, (char) (id == 0))) {
|
||||||
SOCK_get_string(sock, msgbuffer, ERROR_MSG_LENGTH);
|
self->status = PGRES_BAD_RESPONSE;
|
||||||
QR_set_message(self, msgbuffer);
|
QR_set_message(self, "Error reading the tuple");
|
||||||
self->status = PGRES_FATAL_ERROR;
|
return FALSE;
|
||||||
CC_set_no_trans(self->conn);
|
}
|
||||||
qlog("ERROR from backend in next_tuple: '%s'\n", msgbuffer);
|
|
||||||
|
self->fcount++;
|
||||||
|
break; // continue reading
|
||||||
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
case 'N': /* Notice */
|
case 'C': /* End of tuple list */
|
||||||
SOCK_get_string(sock, msgbuffer, ERROR_MSG_LENGTH);
|
SOCK_get_string(sock, cmdbuffer, MAX_MESSAGE_LEN);
|
||||||
QR_set_message(self, msgbuffer);
|
QR_set_command(self, cmdbuffer);
|
||||||
self->status = PGRES_NONFATAL_ERROR;
|
|
||||||
qlog("NOTICE from backend in next_tuple: '%s'\n", msgbuffer);
|
|
||||||
continue;
|
|
||||||
|
|
||||||
default: /* this should only happen if the backend dumped core */
|
mylog("end of tuple list -- setting inUse to false: this = %u\n", self);
|
||||||
QR_set_message(self, "Unexpected result from backend. It probably crashed");
|
|
||||||
self->status = PGRES_FATAL_ERROR;
|
self->inTuples = FALSE;
|
||||||
CC_set_no_trans(self->conn);
|
if (self->fcount > 0) {
|
||||||
return FALSE;
|
|
||||||
|
qlog(" [ fetched %d rows ]\n", self->fcount);
|
||||||
|
mylog("_next_tuple: 'C' fetch_max && fcount = %d\n", self->fcount);
|
||||||
|
|
||||||
|
/* set to first row */
|
||||||
|
self->tupleField = self->backend_tuples; // the_tuples;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
else { // We are surely done here (we read 0 tuples)
|
||||||
|
qlog(" [ fetched 0 rows ]\n");
|
||||||
|
mylog("_next_tuple: 'C': DONE (fcount == 0)\n");
|
||||||
|
return -1; /* end of tuples */
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'E': /* Error */
|
||||||
|
SOCK_get_string(sock, msgbuffer, ERROR_MSG_LENGTH);
|
||||||
|
QR_set_message(self, msgbuffer);
|
||||||
|
self->status = PGRES_FATAL_ERROR;
|
||||||
|
|
||||||
|
if ( ! strncmp(msgbuffer, "FATAL", 5))
|
||||||
|
CC_set_no_trans(self->conn);
|
||||||
|
|
||||||
|
qlog("ERROR from backend in next_tuple: '%s'\n", msgbuffer);
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
case 'N': /* Notice */
|
||||||
|
SOCK_get_string(sock, msgbuffer, ERROR_MSG_LENGTH);
|
||||||
|
QR_set_message(self, msgbuffer);
|
||||||
|
self->status = PGRES_NONFATAL_ERROR;
|
||||||
|
qlog("NOTICE from backend in next_tuple: '%s'\n", msgbuffer);
|
||||||
|
continue;
|
||||||
|
|
||||||
|
default: /* this should only happen if the backend dumped core */
|
||||||
|
QR_set_message(self, "Unexpected result from backend. It probably crashed");
|
||||||
|
self->status = PGRES_FATAL_ERROR;
|
||||||
|
CC_set_no_trans(self->conn);
|
||||||
|
return FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
@ -413,7 +453,8 @@ Int4 len;
|
||||||
char *buffer;
|
char *buffer;
|
||||||
int num_fields = self->num_fields; // speed up access
|
int num_fields = self->num_fields; // speed up access
|
||||||
SocketClass *sock = CC_get_socket(self->conn);
|
SocketClass *sock = CC_get_socket(self->conn);
|
||||||
|
ColumnInfoClass *flds;
|
||||||
|
|
||||||
|
|
||||||
/* set the current row to read the fields into */
|
/* set the current row to read the fields into */
|
||||||
this_tuplefield = self->backend_tuples + (self->fcount * num_fields);
|
this_tuplefield = self->backend_tuples + (self->fcount * num_fields);
|
||||||
|
@ -455,6 +496,17 @@ SocketClass *sock = CC_get_socket(self->conn);
|
||||||
|
|
||||||
this_tuplefield[field_lf].len = len;
|
this_tuplefield[field_lf].len = len;
|
||||||
this_tuplefield[field_lf].value = buffer;
|
this_tuplefield[field_lf].value = buffer;
|
||||||
|
|
||||||
|
/* This can be used to set the longest length of the column for any
|
||||||
|
row in the tuple cache. It would not be accurate for varchar and
|
||||||
|
text fields to use this since a tuple cache is only 100 rows.
|
||||||
|
Bpchar can be handled since the strlen of all rows is fixed,
|
||||||
|
assuming there are not 100 nulls in a row!
|
||||||
|
*/
|
||||||
|
|
||||||
|
flds = self->fields;
|
||||||
|
if (flds->display_size[field_lf] < len)
|
||||||
|
flds->display_size[field_lf] = len;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
Now adjust for the next bit to be scanned in the
|
Now adjust for the next bit to be scanned in the
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
|
|
||||||
/* File: qresult.h
|
/* File: qresult.h
|
||||||
*
|
*
|
||||||
* Description: See "qresult.c"
|
* Description: See "qresult.c"
|
||||||
*
|
*
|
||||||
* Comments: See "notice.txt" for copyright and license information.
|
* Comments: See "notice.txt" for copyright and license information.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __QRESULT_H__
|
#ifndef __QRESULT_H__
|
||||||
#define __QRESULT_H__
|
#define __QRESULT_H__
|
||||||
|
@ -43,7 +43,7 @@ struct QResultClass_ {
|
||||||
|
|
||||||
// Stuff for declare/fetch tuples
|
// Stuff for declare/fetch tuples
|
||||||
int fetch_count; // logical rows read so far
|
int fetch_count; // logical rows read so far
|
||||||
int fcount; // actual rows read in the fetch
|
int fcount; // actual rows read in the fetch
|
||||||
|
|
||||||
int num_fields; // number of fields in the result
|
int num_fields; // number of fields in the result
|
||||||
QueryResultCode status;
|
QueryResultCode status;
|
||||||
|
@ -63,19 +63,22 @@ struct QResultClass_ {
|
||||||
|
|
||||||
|
|
||||||
/* These functions are for retrieving data from the qresult */
|
/* These functions are for retrieving data from the qresult */
|
||||||
#define QR_get_value_manual(self, tupleno, fieldno) (TL_get_fieldval(self->manual_tuples, tupleno, fieldno))
|
#define QR_get_value_manual(self, tupleno, fieldno) (TL_get_fieldval(self->manual_tuples, tupleno, fieldno))
|
||||||
#define QR_get_value_backend(self, fieldno) (self->tupleField[fieldno].value)
|
#define QR_get_value_backend(self, fieldno) (self->tupleField[fieldno].value)
|
||||||
|
#define QR_get_value_backend_row(self, tupleno, fieldno) \
|
||||||
|
((self->backend_tuples + (tupleno * self->num_fields))[fieldno].value)
|
||||||
|
|
||||||
/* These functions are used by both manual and backend results */
|
/* These functions are used by both manual and backend results */
|
||||||
#define QR_NumResultCols(self) (CI_get_num_fields(self->fields))
|
#define QR_NumResultCols(self) (CI_get_num_fields(self->fields))
|
||||||
#define QR_get_fieldname(self, fieldno_) (CI_get_fieldname(self->fields, fieldno_))
|
#define QR_get_fieldname(self, fieldno_) (CI_get_fieldname(self->fields, fieldno_))
|
||||||
#define QR_get_fieldsize(self, fieldno_) (CI_get_fieldsize(self->fields, fieldno_))
|
#define QR_get_fieldsize(self, fieldno_) (CI_get_fieldsize(self->fields, fieldno_))
|
||||||
#define QR_get_field_type(self, fieldno_) (CI_get_oid(self->fields, fieldno_))
|
#define QR_get_display_size(self, fieldno_) (CI_get_display_size(self->fields, fieldno_))
|
||||||
|
#define QR_get_field_type(self, fieldno_) (CI_get_oid(self->fields, fieldno_))
|
||||||
|
|
||||||
/* These functions are used only for manual result sets */
|
/* These functions are used only for manual result sets */
|
||||||
#define QR_get_num_tuples(self) (self->manual_tuples ? TL_get_num_tuples(self->manual_tuples) : 0)
|
#define QR_get_num_tuples(self) (self->manual_tuples ? TL_get_num_tuples(self->manual_tuples) : self->fcount)
|
||||||
#define QR_add_tuple(self, new_tuple) (TL_add_tuple(self->manual_tuples, new_tuple))
|
#define QR_add_tuple(self, new_tuple) (TL_add_tuple(self->manual_tuples, new_tuple))
|
||||||
#define QR_set_field_info(self, field_num, name, adtid, adtsize) (CI_set_field_info(self->fields, field_num, name, adtid, adtsize))
|
#define QR_set_field_info(self, field_num, name, adtid, adtsize) (CI_set_field_info(self->fields, field_num, name, adtid, adtsize))
|
||||||
|
|
||||||
/* status macros */
|
/* status macros */
|
||||||
#define QR_command_successful(self) ( !(self->status == PGRES_BAD_RESPONSE || self->status == PGRES_NONFATAL_ERROR || self->status == PGRES_FATAL_ERROR))
|
#define QR_command_successful(self) ( !(self->status == PGRES_BAD_RESPONSE || self->status == PGRES_NONFATAL_ERROR || self->status == PGRES_FATAL_ERROR))
|
||||||
|
@ -98,7 +101,7 @@ int QR_close(QResultClass *self);
|
||||||
char QR_fetch_tuples(QResultClass *self, ConnectionClass *conn, char *cursor);
|
char QR_fetch_tuples(QResultClass *self, ConnectionClass *conn, char *cursor);
|
||||||
void QR_free_memory(QResultClass *self);
|
void QR_free_memory(QResultClass *self);
|
||||||
void QR_set_command(QResultClass *self, char *msg);
|
void QR_set_command(QResultClass *self, char *msg);
|
||||||
void QR_set_notice(QResultClass *self, char *msg);
|
void QR_set_notice(QResultClass *self, char *msg);
|
||||||
|
|
||||||
void QR_set_num_fields(QResultClass *self, int new_num_fields); /* manual result only */
|
void QR_set_num_fields(QResultClass *self, int new_num_fields); /* manual result only */
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,72 @@
|
||||||
|
|
||||||
|
Readme for psqlodbc.dll 4/15/98
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
Latest binary and source updates available at http://www.insightdist.com/psqlodbc
|
||||||
|
|
||||||
|
|
||||||
|
I. Building the Driver from the source code
|
||||||
|
|
||||||
|
This section describes how to build the PostgreSQL ODBC Driver (psqlodbc.dll).
|
||||||
|
Microsoft Visual C++ version 4.0 or higher is required. There is no manually
|
||||||
|
constructed Makefile. The visual C++ environment automatically generates one
|
||||||
|
during the build process. Thus, the project binary files (".ncb", ".mdp", ".aps")
|
||||||
|
nor the makefile are really distributed as part of the source code release
|
||||||
|
(although they are probably in there anyway).
|
||||||
|
|
||||||
|
1. Create a new project workspace with the type DLL. For the name, type in the
|
||||||
|
name "psqlodbc".
|
||||||
|
|
||||||
|
2. The above step creates the directory "psqlodbc" under the
|
||||||
|
"\<Visual C++ top level directory>\projects" path to hold the source files.
|
||||||
|
(example, \msdev\projects\psqlodbc). Now, either unzip the source code release
|
||||||
|
into this directory or just copy all the files into this directory.
|
||||||
|
|
||||||
|
3. Insert all of the source files (*.c, *.h, *.rc, *.def) into the Visual project
|
||||||
|
using the "Insert files into project" command. You may have to do 2 inserts --
|
||||||
|
the first to get the 'c' and header files, and the second to get the def file.
|
||||||
|
Don't forget the .def file since it is an important part of the release.
|
||||||
|
You can even insert ".txt" files into the projects -- they will do nothing.
|
||||||
|
|
||||||
|
4. Add the "wsock32.lib" library to the end of the list of libraries for linking
|
||||||
|
using the Build settings menu.
|
||||||
|
|
||||||
|
5. Select the type of build on the toolbar (i.e., Release or Debug). This is
|
||||||
|
one of the useful features of the visual c++ environment in that you can
|
||||||
|
browse the entire project if you build the "Debug" release. For release
|
||||||
|
purposes however, select "Release" build.
|
||||||
|
|
||||||
|
6. Build the dll by selecting Build from the build menu.
|
||||||
|
|
||||||
|
7. When complete, the "psqlodbc.dll" file is under the "Release" subdirectory.
|
||||||
|
(i.e., "\msdev\projects\psqlodbc\release\psqlodbc.dll")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
II. Using Large Objects for handling LongVarBinary (OLE Objects in Access)
|
||||||
|
|
||||||
|
Large objects are mapped to LONGVARBINARY in the driver to allow storing things like
|
||||||
|
OLE objects in Microsoft Access. Multiple SQLPutData and SQLGetData calls are usually
|
||||||
|
used to send and retrieve these objects. The driver creates a new large object and simply
|
||||||
|
inserts its 'identifier' into the respective table. However, since Postgres uses an 'Oid'
|
||||||
|
to identify a Large Object, it is necessary to create a new Postgres type to be able
|
||||||
|
to discriminate between an ordinary Oid and a Large Object Oid. Until this new type
|
||||||
|
becomes an official part of Postgres, it must be added into the desired database and
|
||||||
|
looked up for each connection. The type used in the driver is simply called "lo" and
|
||||||
|
here is the command used to create it:
|
||||||
|
|
||||||
|
create type lo (internallength=4,externallength=10,input=int4in,output=int4out,
|
||||||
|
default='',passedbyvalue);
|
||||||
|
|
||||||
|
Once this is done, simply use the new 'lo' type to define columns in that database. Note
|
||||||
|
that this must be done for each database you want to use large objects in with the driver.
|
||||||
|
When the driver sees an 'lo' type, it will handle it as LONGVARBINARY.
|
||||||
|
|
||||||
|
Another important note is that this new type is lacking in functionality. It will not
|
||||||
|
cleanup after itself on updates and deletes, thus leaving orphans around and using up
|
||||||
|
extra disk space. And currently, Postgres does not support the vacuuming of large
|
||||||
|
objects. Hopefully in the future, a real large object data type will be available.
|
||||||
|
|
||||||
|
But for now, it sure is fun to stick a Word document, Visio document, or avi of a dancing
|
||||||
|
baby into a database column, even if you will fill up your server's hard disk after a while!
|
||||||
|
|
||||||
|
|
|
@ -1,39 +1,58 @@
|
||||||
//{{NO_DEPENDENCIES}}
|
//{{NO_DEPENDENCIES}}
|
||||||
// Microsoft Developer Studio generated include file.
|
// Microsoft Developer Studio generated include file.
|
||||||
// Used by psqlodbc.rc
|
// Used by psqlodbc.rc
|
||||||
//
|
//
|
||||||
#define IDS_BADDSN 1
|
#define IDS_BADDSN 1
|
||||||
#define IDS_MSGTITLE 2
|
#define IDS_MSGTITLE 2
|
||||||
#define DRIVERCONNDIALOG 101
|
#define DLG_OPTIONS_DRV 102
|
||||||
#define IDC_DSNAME 400
|
#define DLG_OPTIONS_DS 103
|
||||||
#define IDC_DSNAMETEXT 401
|
#define IDC_DSNAME 400
|
||||||
#define IDC_DESC 404
|
#define IDC_DSNAMETEXT 401
|
||||||
#define IDC_SERVER 407
|
#define IDC_DESC 404
|
||||||
#define IDC_DATABASE 408
|
#define IDC_SERVER 407
|
||||||
#define CONFIGDSN 1001
|
#define IDC_DATABASE 408
|
||||||
#define IDC_PORT 1002
|
#define DLG_CONFIG 1001
|
||||||
#define IDC_USER 1006
|
#define IDC_PORT 1002
|
||||||
#define IDC_PASSWORD 1009
|
#define IDC_USER 1006
|
||||||
#define IDC_READONLY 1011
|
#define IDC_PASSWORD 1009
|
||||||
#define READONLY_EDIT 1012
|
#define DS_READONLY 1011
|
||||||
#define SAVEPASSWORD_EDIT 1013
|
#define DS_SHOWOIDCOLUMN 1012
|
||||||
#define IDC_COMMLOG 1014
|
#define DS_FAKEOIDINDEX 1013
|
||||||
#define COMMLOG_EDIT 1015
|
#define DRV_COMMLOG 1014
|
||||||
#define IDC_PG62 1016
|
#define DS_PG62 1016
|
||||||
#define PG62_EDIT 1017
|
#define IDC_DATASOURCE 1018
|
||||||
#define SERVER_EDIT 1501
|
#define DRV_OPTIMIZER 1019
|
||||||
#define PORT_EDIT 1502
|
#define DS_CONNSETTINGS 1020
|
||||||
#define DATABASE_EDIT 1503
|
#define IDC_DRIVER 1021
|
||||||
#define USERNAME_EDIT 1504
|
#define DS_UNKNOWN_MAX 1023
|
||||||
#define PASSWORD_EDIT 1505
|
#define DS_UNKNOWN_DONTKNOW 1024
|
||||||
|
#define DRV_CONNSETTINGS 1031
|
||||||
// Next default values for new objects
|
#define DRV_UNIQUEINDEX 1032
|
||||||
//
|
#define DRV_UNKNOWN_MAX 1035
|
||||||
#ifdef APSTUDIO_INVOKED
|
#define DRV_UNKNOWN_DONTKNOW 1036
|
||||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
#define DRV_READONLY 1037
|
||||||
#define _APS_NEXT_RESOURCE_VALUE 102
|
#define IDC_DESCTEXT 1039
|
||||||
#define _APS_NEXT_COMMAND_VALUE 40001
|
#define DRV_MSG_LABEL 1040
|
||||||
#define _APS_NEXT_CONTROL_VALUE 1018
|
#define DRV_UNKNOWN_LONGEST 1041
|
||||||
#define _APS_NEXT_SYMED_VALUE 101
|
#define DS_UNKNOWN_LONGEST 1042
|
||||||
#endif
|
#define DRV_TEXT_LONGVARCHAR 1043
|
||||||
#endif
|
#define DRV_UNKNOWNS_LONGVARCHAR 1044
|
||||||
|
#define DRV_CACHE_SIZE 1045
|
||||||
|
#define DRV_VARCHAR_SIZE 1046
|
||||||
|
#define DRV_LONGVARCHAR_SIZE 1047
|
||||||
|
#define IDDEFAULTS 1048
|
||||||
|
#define DRV_USEDECLAREFETCH 1049
|
||||||
|
#define DRV_BOOLS_CHAR 1050
|
||||||
|
#define DS_SHOWSYSTEMTABLES 1051
|
||||||
|
#define DRV_EXTRASYSTABLEPREFIXES 1051
|
||||||
|
|
||||||
|
// Next default values for new objects
|
||||||
|
//
|
||||||
|
#ifdef APSTUDIO_INVOKED
|
||||||
|
#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_SYMED_VALUE 101
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
|
@ -1,22 +1,23 @@
|
||||||
|
|
||||||
/* Module: results.c
|
/* Module: results.c
|
||||||
*
|
*
|
||||||
* Description: This module contains functions related to
|
* Description: This module contains functions related to
|
||||||
* retrieving result information through the ODBC API.
|
* retrieving result information through the ODBC API.
|
||||||
*
|
*
|
||||||
* Classes: n/a
|
* Classes: n/a
|
||||||
*
|
*
|
||||||
* API functions: SQLRowCount, SQLNumResultCols, SQLDescribeCol, SQLColAttributes,
|
* API functions: SQLRowCount, SQLNumResultCols, SQLDescribeCol, SQLColAttributes,
|
||||||
* SQLGetData, SQLFetch, SQLExtendedFetch,
|
* SQLGetData, SQLFetch, SQLExtendedFetch,
|
||||||
* SQLMoreResults(NI), SQLSetPos(NI), SQLSetScrollOptions(NI),
|
* SQLMoreResults(NI), SQLSetPos(NI), SQLSetScrollOptions(NI),
|
||||||
* SQLSetCursorName(NI), SQLGetCursorName(NI)
|
* SQLSetCursorName, SQLGetCursorName
|
||||||
*
|
*
|
||||||
* Comments: See "notice.txt" for copyright and license information.
|
* Comments: See "notice.txt" for copyright and license information.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "psqlodbc.h"
|
#include "psqlodbc.h"
|
||||||
|
#include "dlg_specific.h"
|
||||||
#include "environ.h"
|
#include "environ.h"
|
||||||
#include "connection.h"
|
#include "connection.h"
|
||||||
#include "statement.h"
|
#include "statement.h"
|
||||||
|
@ -29,6 +30,7 @@
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <sqlext.h>
|
#include <sqlext.h>
|
||||||
|
|
||||||
|
extern GLOBAL_VALUES globals;
|
||||||
|
|
||||||
RETCODE SQL_API SQLRowCount(
|
RETCODE SQL_API SQLRowCount(
|
||||||
HSTMT hstmt,
|
HSTMT hstmt,
|
||||||
|
@ -46,7 +48,7 @@ char *msg, *ptr;
|
||||||
res = SC_get_Result(stmt);
|
res = SC_get_Result(stmt);
|
||||||
|
|
||||||
if(res && pcrow) {
|
if(res && pcrow) {
|
||||||
*pcrow = QR_get_num_tuples(res);
|
*pcrow = globals.use_declarefetch ? 0 : QR_get_num_tuples(res);
|
||||||
return SQL_SUCCESS;
|
return SQL_SUCCESS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -115,11 +117,11 @@ QResultClass *result;
|
||||||
return SQL_SUCCESS;
|
return SQL_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// - - - - - - - - -
|
// - - - - - - - - -
|
||||||
|
|
||||||
// Return information about the database column the user wants
|
// Return information about the database column the user wants
|
||||||
// information about.
|
// information about.
|
||||||
/* CC: preliminary implementation */
|
|
||||||
RETCODE SQL_API SQLDescribeCol(
|
RETCODE SQL_API SQLDescribeCol(
|
||||||
HSTMT hstmt,
|
HSTMT hstmt,
|
||||||
UWORD icol,
|
UWORD icol,
|
||||||
|
@ -136,10 +138,14 @@ StatementClass *stmt = (StatementClass *) hstmt;
|
||||||
QResultClass *result;
|
QResultClass *result;
|
||||||
char *name;
|
char *name;
|
||||||
Int4 fieldtype;
|
Int4 fieldtype;
|
||||||
|
int p;
|
||||||
|
ConnInfo *ci;
|
||||||
|
|
||||||
if ( ! stmt)
|
if ( ! stmt)
|
||||||
return SQL_INVALID_HANDLE;
|
return SQL_INVALID_HANDLE;
|
||||||
|
|
||||||
|
ci = &(stmt->hdbc->connInfo);
|
||||||
|
|
||||||
SC_clear_error(stmt);
|
SC_clear_error(stmt);
|
||||||
|
|
||||||
/* CC: Now check for the "prepared, but not executed" situation, that enables us to
|
/* CC: Now check for the "prepared, but not executed" situation, that enables us to
|
||||||
|
@ -149,7 +155,7 @@ Int4 fieldtype;
|
||||||
|
|
||||||
SC_pre_execute(stmt);
|
SC_pre_execute(stmt);
|
||||||
|
|
||||||
|
|
||||||
result = SC_get_Result(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);
|
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))) {
|
if ( (NULL == result) || ((stmt->status != STMT_FINISHED) && (stmt->status != STMT_PREMATURE))) {
|
||||||
|
@ -159,9 +165,18 @@ Int4 fieldtype;
|
||||||
return SQL_ERROR;
|
return SQL_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(icol < 1) {
|
||||||
|
// 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 column numbers */
|
||||||
|
|
||||||
if (cbColNameMax >= 1) {
|
if (cbColNameMax >= 1) {
|
||||||
name = QR_get_fieldname(result, (Int2) (icol-1));
|
name = QR_get_fieldname(result, icol);
|
||||||
mylog("describeCol: col %d fieldname = '%s'\n", icol - 1, name);
|
mylog("describeCol: col %d fieldname = '%s'\n", icol, name);
|
||||||
/* our indices start from 0 whereas ODBC defines indices starting from 1 */
|
/* our indices start from 0 whereas ODBC defines indices starting from 1 */
|
||||||
if (NULL != pcbColName) {
|
if (NULL != pcbColName) {
|
||||||
// we want to get the total number of bytes in the column name
|
// we want to get the total number of bytes in the column name
|
||||||
|
@ -179,27 +194,51 @@ Int4 fieldtype;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fieldtype = QR_get_field_type(result, (Int2) (icol-1));
|
fieldtype = QR_get_field_type(result, icol);
|
||||||
mylog("describeCol: col %d fieldtype = %d\n", icol - 1, fieldtype);
|
mylog("describeCol: col %d fieldtype = %d\n", icol, fieldtype);
|
||||||
|
|
||||||
if (NULL != pfSqlType) {
|
if (NULL != pfSqlType) {
|
||||||
*pfSqlType = pgtype_to_sqltype(fieldtype);
|
*pfSqlType = pgtype_to_sqltype(stmt, fieldtype);
|
||||||
if (*pfSqlType == PG_UNKNOWN)
|
|
||||||
*pfSqlType = SQL_CHAR;
|
mylog("describeCol: col %d *pfSqlType = %d\n", icol, *pfSqlType);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (NULL != pcbColDef)
|
if (NULL != pcbColDef) {
|
||||||
*pcbColDef = pgtype_precision(fieldtype);
|
|
||||||
|
/* 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 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;
|
||||||
|
|
||||||
|
mylog("describeCol: col %d *pcbColDef = %d\n", icol, *pcbColDef);
|
||||||
|
}
|
||||||
|
|
||||||
if (NULL != pibScale) {
|
if (NULL != pibScale) {
|
||||||
Int2 scale;
|
Int2 scale;
|
||||||
scale = pgtype_scale(fieldtype);
|
scale = pgtype_scale(stmt, fieldtype);
|
||||||
if(scale == -1) { scale = 0; }
|
if(scale == -1) { scale = 0; }
|
||||||
|
|
||||||
*pibScale = scale;
|
*pibScale = scale;
|
||||||
|
mylog("describeCol: col %d *pibScale = %d\n", icol, *pibScale);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (NULL != pfNullable) {
|
if (NULL != pfNullable) {
|
||||||
*pfNullable = pgtype_nullable(fieldtype);
|
*pfNullable = pgtype_nullable(stmt, fieldtype);
|
||||||
|
mylog("describeCol: col %d *pfNullable = %d\n", icol, *pfNullable);
|
||||||
}
|
}
|
||||||
|
|
||||||
return SQL_SUCCESS;
|
return SQL_SUCCESS;
|
||||||
|
@ -219,132 +258,169 @@ RETCODE SQL_API SQLColAttributes(
|
||||||
StatementClass *stmt = (StatementClass *) hstmt;
|
StatementClass *stmt = (StatementClass *) hstmt;
|
||||||
char *value;
|
char *value;
|
||||||
Int4 field_type;
|
Int4 field_type;
|
||||||
|
ConnInfo *ci;
|
||||||
|
int unknown_sizes;
|
||||||
|
|
||||||
if( ! stmt) {
|
if( ! stmt)
|
||||||
return SQL_INVALID_HANDLE;
|
return SQL_INVALID_HANDLE;
|
||||||
}
|
|
||||||
|
ci = &(stmt->hdbc->connInfo);
|
||||||
|
|
||||||
/* CC: Now check for the "prepared, but not executed" situation, that enables us to
|
/* CC: Now check for the "prepared, but not executed" situation, that enables us to
|
||||||
deal with "SQLPrepare -- SQLDescribeCol -- ... -- SQLExecute" situations.
|
deal with "SQLPrepare -- SQLDescribeCol -- ... -- SQLExecute" situations.
|
||||||
(AutoCAD 13 ASE/ASI just _loves_ that ;-) )
|
(AutoCAD 13 ASE/ASI just _loves_ that ;-) )
|
||||||
*/
|
*/
|
||||||
SC_pre_execute(stmt);
|
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);
|
mylog("**** SQLColAtt: result = %u, status = %d, numcols = %d\n", stmt->result, stmt->status, stmt->result != NULL ? QR_NumResultCols(stmt->result) : -1);
|
||||||
|
|
||||||
if ( (NULL == stmt->result) || ((stmt->status != STMT_FINISHED) && (stmt->status != STMT_PREMATURE)) ) {
|
if ( (NULL == stmt->result) || ((stmt->status != STMT_FINISHED) && (stmt->status != STMT_PREMATURE)) ) {
|
||||||
stmt->errormsg = "Can't get column attributes: no result found.";
|
stmt->errormsg = "Can't get column attributes: no result found.";
|
||||||
stmt->errornumber = STMT_SEQUENCE_ERROR;
|
stmt->errornumber = STMT_SEQUENCE_ERROR;
|
||||||
return SQL_ERROR;
|
return SQL_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(icol < 1) {
|
if(icol < 1) {
|
||||||
// we do not support bookmarks
|
// we do not support bookmarks
|
||||||
stmt->errormsg = "Bookmarks are not currently supported.";
|
stmt->errormsg = "Bookmarks are not currently supported.";
|
||||||
stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR;
|
stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR;
|
||||||
return SQL_ERROR;
|
return SQL_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
icol -= 1;
|
||||||
|
field_type = QR_get_field_type(stmt->result, icol);
|
||||||
|
|
||||||
icol -= 1;
|
|
||||||
field_type = QR_get_field_type(stmt->result, icol);
|
|
||||||
mylog("colAttr: col %d field_type = %d\n", icol, field_type);
|
mylog("colAttr: col %d field_type = %d\n", icol, field_type);
|
||||||
switch(fDescType) {
|
|
||||||
case SQL_COLUMN_AUTO_INCREMENT:
|
|
||||||
if (NULL != pfDesc) {
|
|
||||||
*pfDesc = pgtype_auto_increment(field_type);
|
|
||||||
|
|
||||||
if(*pfDesc == -1) { /* "not applicable" becomes false */
|
unknown_sizes = globals.unknown_sizes; // atoi(ci->unknown_sizes);
|
||||||
*pfDesc = FALSE;
|
if (unknown_sizes == UNKNOWNS_AS_DONTKNOW) // not appropriate for SQLColAttributes()
|
||||||
}
|
unknown_sizes = UNKNOWNS_AS_MAX;
|
||||||
}
|
|
||||||
break;
|
|
||||||
case SQL_COLUMN_CASE_SENSITIVE:
|
|
||||||
if (NULL != pfDesc)
|
|
||||||
*pfDesc = pgtype_case_sensitive(field_type);
|
|
||||||
break;
|
|
||||||
case SQL_COLUMN_COUNT:
|
|
||||||
if (NULL != pfDesc)
|
|
||||||
*pfDesc = QR_NumResultCols(stmt->result);
|
|
||||||
break;
|
|
||||||
case SQL_COLUMN_DISPLAY_SIZE:
|
|
||||||
if (NULL != pfDesc)
|
|
||||||
*pfDesc = pgtype_precision(field_type);
|
|
||||||
|
|
||||||
mylog("colAttr: col %d fieldsize = %d\n", icol, *pfDesc);
|
|
||||||
|
|
||||||
break;
|
switch(fDescType) {
|
||||||
case SQL_COLUMN_LABEL:
|
case SQL_COLUMN_AUTO_INCREMENT:
|
||||||
case SQL_COLUMN_NAME:
|
if (NULL != pfDesc) {
|
||||||
value = QR_get_fieldname(stmt->result, icol);
|
*pfDesc = pgtype_auto_increment(stmt, field_type);
|
||||||
strncpy_null((char *)rgbDesc, value, cbDescMax);
|
if (*pfDesc == -1) /* non-numeric becomes FALSE (ODBC Doc) */
|
||||||
/* CC: Check for Nullpointesr */
|
*pfDesc = FALSE;
|
||||||
if (NULL != pcbDesc)
|
|
||||||
*pcbDesc = strlen(value);
|
|
||||||
break;
|
|
||||||
case SQL_COLUMN_LENGTH:
|
|
||||||
if (NULL != pfDesc)
|
|
||||||
*pfDesc = pgtype_precision(field_type);
|
|
||||||
return SQL_SUCCESS;
|
|
||||||
break;
|
|
||||||
case SQL_COLUMN_MONEY:
|
|
||||||
if (NULL != pfDesc)
|
|
||||||
*pfDesc = pgtype_money(field_type);
|
|
||||||
break;
|
|
||||||
case SQL_COLUMN_NULLABLE:
|
|
||||||
if (NULL != pfDesc)
|
|
||||||
*pfDesc = pgtype_nullable(field_type);
|
|
||||||
break;
|
|
||||||
case SQL_COLUMN_OWNER_NAME:
|
|
||||||
return SQL_ERROR;
|
|
||||||
break;
|
|
||||||
case SQL_COLUMN_PRECISION:
|
|
||||||
if (NULL != pfDesc)
|
|
||||||
*pfDesc = pgtype_precision(field_type);
|
|
||||||
break;
|
|
||||||
case SQL_COLUMN_QUALIFIER_NAME:
|
|
||||||
strncpy_null((char *)rgbDesc, "", cbDescMax);
|
|
||||||
if (NULL != pfDesc)
|
|
||||||
*pcbDesc = 1;
|
|
||||||
break;
|
|
||||||
case SQL_COLUMN_SCALE:
|
|
||||||
if (NULL != pfDesc)
|
|
||||||
*pfDesc = pgtype_scale(field_type);
|
|
||||||
break;
|
|
||||||
case SQL_COLUMN_SEARCHABLE:
|
|
||||||
if (NULL != pfDesc)
|
|
||||||
*pfDesc = pgtype_searchable(field_type);
|
|
||||||
break;
|
|
||||||
case SQL_COLUMN_TABLE_NAME:
|
|
||||||
return SQL_ERROR;
|
|
||||||
break;
|
|
||||||
case SQL_COLUMN_TYPE:
|
|
||||||
if (NULL != pfDesc) {
|
|
||||||
*pfDesc = pgtype_to_sqltype(field_type);
|
|
||||||
if (*pfDesc == PG_UNKNOWN)
|
|
||||||
*pfDesc = SQL_CHAR;
|
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SQL_COLUMN_CASE_SENSITIVE:
|
||||||
|
if (NULL != pfDesc)
|
||||||
|
*pfDesc = pgtype_case_sensitive(stmt, field_type);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SQL_COLUMN_COUNT:
|
||||||
|
if (NULL != pfDesc)
|
||||||
|
*pfDesc = QR_NumResultCols(stmt->result);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SQL_COLUMN_DISPLAY_SIZE:
|
||||||
|
if (NULL != pfDesc) {
|
||||||
|
*pfDesc = pgtype_display_size(stmt, field_type, icol, unknown_sizes);
|
||||||
|
}
|
||||||
|
|
||||||
|
mylog("SQLColAttributes: col %d, display_size= %d\n", icol, *pfDesc);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case SQL_COLUMN_TYPE_NAME:
|
|
||||||
value = pgtype_to_name(field_type);
|
case SQL_COLUMN_LABEL:
|
||||||
strncpy_null((char *)rgbDesc, value, cbDescMax);
|
case SQL_COLUMN_NAME:
|
||||||
if (NULL != pcbDesc)
|
value = QR_get_fieldname(stmt->result, icol);
|
||||||
*pcbDesc = strlen(value);
|
strncpy_null((char *)rgbDesc, value, cbDescMax);
|
||||||
|
|
||||||
|
if (NULL != pcbDesc)
|
||||||
|
*pcbDesc = strlen(value);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SQL_COLUMN_LENGTH:
|
||||||
|
if (NULL != pfDesc) {
|
||||||
|
*pfDesc = pgtype_length(stmt, field_type, icol, unknown_sizes);
|
||||||
|
}
|
||||||
|
mylog("SQLColAttributes: col %d, length = %d\n", icol, *pfDesc);
|
||||||
break;
|
break;
|
||||||
case SQL_COLUMN_UNSIGNED:
|
|
||||||
if (NULL != pfDesc) {
|
case SQL_COLUMN_MONEY:
|
||||||
*pfDesc = pgtype_unsigned(field_type);
|
if (NULL != pfDesc)
|
||||||
if(*pfDesc == -1) {
|
*pfDesc = pgtype_money(stmt, field_type);
|
||||||
*pfDesc = FALSE;
|
break;
|
||||||
}
|
|
||||||
}
|
case SQL_COLUMN_NULLABLE:
|
||||||
|
if (NULL != pfDesc)
|
||||||
|
*pfDesc = pgtype_nullable(stmt, field_type);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SQL_COLUMN_OWNER_NAME:
|
||||||
|
strncpy_null((char *)rgbDesc, "", cbDescMax);
|
||||||
|
if (NULL != pcbDesc)
|
||||||
|
*pcbDesc = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SQL_COLUMN_PRECISION:
|
||||||
|
if (NULL != pfDesc) {
|
||||||
|
*pfDesc = pgtype_precision(stmt, field_type, icol, unknown_sizes);
|
||||||
|
}
|
||||||
|
mylog("SQLColAttributes: col %d, precision = %d\n", icol, *pfDesc);
|
||||||
break;
|
break;
|
||||||
case SQL_COLUMN_UPDATABLE:
|
|
||||||
// everything should be updatable, I guess, unless access permissions
|
case SQL_COLUMN_QUALIFIER_NAME:
|
||||||
// prevent it--are we supposed to check for that here? seems kind
|
strncpy_null((char *)rgbDesc, "", cbDescMax);
|
||||||
// of complicated. hmm...
|
if (NULL != pcbDesc)
|
||||||
if (NULL != pfDesc)
|
*pcbDesc = 0;
|
||||||
*pfDesc = SQL_ATTR_WRITE;
|
break;
|
||||||
|
|
||||||
|
case SQL_COLUMN_SCALE:
|
||||||
|
if (NULL != pfDesc)
|
||||||
|
*pfDesc = pgtype_scale(stmt, field_type);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SQL_COLUMN_SEARCHABLE:
|
||||||
|
if (NULL != pfDesc)
|
||||||
|
*pfDesc = pgtype_searchable(stmt, field_type);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SQL_COLUMN_TABLE_NAME:
|
||||||
|
strncpy_null((char *)rgbDesc, "", cbDescMax);
|
||||||
|
if (NULL != pcbDesc)
|
||||||
|
*pcbDesc = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case SQL_COLUMN_TYPE:
|
||||||
|
if (NULL != pfDesc) {
|
||||||
|
*pfDesc = pgtype_to_sqltype(stmt, field_type);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SQL_COLUMN_TYPE_NAME:
|
||||||
|
value = pgtype_to_name(stmt, field_type);
|
||||||
|
strncpy_null((char *)rgbDesc, value, cbDescMax);
|
||||||
|
if (NULL != pcbDesc)
|
||||||
|
*pcbDesc = strlen(value);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SQL_COLUMN_UNSIGNED:
|
||||||
|
if (NULL != pfDesc) {
|
||||||
|
*pfDesc = pgtype_unsigned(stmt, field_type);
|
||||||
|
if(*pfDesc == -1) /* non-numeric becomes TRUE (ODBC Doc) */
|
||||||
|
*pfDesc = TRUE;
|
||||||
|
}
|
||||||
|
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) {
|
||||||
|
/* Neither Access or Borland care about this.
|
||||||
|
|
||||||
|
if (field_type == PG_TYPE_OID)
|
||||||
|
*pfDesc = SQL_ATTR_READONLY;
|
||||||
|
else
|
||||||
|
*/
|
||||||
|
*pfDesc = SQL_ATTR_WRITE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return SQL_SUCCESS;
|
return SQL_SUCCESS;
|
||||||
|
@ -366,6 +442,10 @@ int num_cols, num_rows;
|
||||||
Int4 field_type;
|
Int4 field_type;
|
||||||
void *value;
|
void *value;
|
||||||
int result;
|
int result;
|
||||||
|
char multiple;
|
||||||
|
|
||||||
|
|
||||||
|
mylog("SQLGetData: enter, stmt=%u\n", stmt);
|
||||||
|
|
||||||
if( ! stmt) {
|
if( ! stmt) {
|
||||||
return SQL_INVALID_HANDLE;
|
return SQL_INVALID_HANDLE;
|
||||||
|
@ -401,7 +481,7 @@ int result;
|
||||||
return SQL_ERROR;
|
return SQL_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( stmt->manual_result) {
|
if ( stmt->manual_result || ! globals.use_declarefetch) {
|
||||||
// make sure we're positioned on a valid row
|
// make sure we're positioned on a valid row
|
||||||
num_rows = QR_get_num_tuples(res);
|
num_rows = QR_get_num_tuples(res);
|
||||||
if((stmt->currTuple < 0) ||
|
if((stmt->currTuple < 0) ||
|
||||||
|
@ -410,7 +490,14 @@ int result;
|
||||||
stmt->errornumber = STMT_INVALID_CURSOR_STATE_ERROR;
|
stmt->errornumber = STMT_INVALID_CURSOR_STATE_ERROR;
|
||||||
return SQL_ERROR;
|
return SQL_ERROR;
|
||||||
}
|
}
|
||||||
value = QR_get_value_manual(res, stmt->currTuple, icol);
|
mylog(" num_rows = %d\n", num_rows);
|
||||||
|
if ( stmt->manual_result) {
|
||||||
|
value = QR_get_value_manual(res, stmt->currTuple, icol);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
value = QR_get_value_backend_row(res, stmt->currTuple, icol);
|
||||||
|
}
|
||||||
|
mylog(" value = '%s'\n", value);
|
||||||
}
|
}
|
||||||
else { /* its a SOCKET result (backend data) */
|
else { /* its a SOCKET result (backend data) */
|
||||||
if (stmt->currTuple == -1 || ! res || QR_end_tuples(res)) {
|
if (stmt->currTuple == -1 || ! res || QR_end_tuples(res)) {
|
||||||
|
@ -421,35 +508,52 @@ int result;
|
||||||
|
|
||||||
value = QR_get_value_backend(res, icol);
|
value = QR_get_value_backend(res, icol);
|
||||||
|
|
||||||
|
mylog(" socket: value = '%s'\n", value);
|
||||||
}
|
}
|
||||||
|
|
||||||
field_type = QR_get_field_type(res, icol);
|
field_type = QR_get_field_type(res, icol);
|
||||||
|
|
||||||
mylog("**** SQLGetData: icol = %d, fCType = %d, field_type = %d, value = '%s'\n", icol, fCType, field_type, value);
|
mylog("**** SQLGetData: icol = %d, fCType = %d, field_type = %d, value = '%s'\n", icol, fCType, field_type, value);
|
||||||
|
|
||||||
result = copy_and_convert_field(field_type, value,
|
/* Is this another call for the same column to retrieve more data? */
|
||||||
fCType, rgbValue, cbValueMax, pcbValue);
|
multiple = (icol == stmt->current_col) ? TRUE : FALSE;
|
||||||
|
|
||||||
|
result = copy_and_convert_field(stmt, field_type, value,
|
||||||
|
fCType, rgbValue, cbValueMax, pcbValue, multiple);
|
||||||
|
|
||||||
|
|
||||||
if(result == COPY_UNSUPPORTED_TYPE) {
|
stmt->current_col = icol;
|
||||||
stmt->errormsg = "Received an unsupported type from Postgres.";
|
|
||||||
stmt->errornumber = STMT_RESTRICTED_DATA_TYPE_ERROR;
|
switch(result) {
|
||||||
return SQL_ERROR;
|
case COPY_OK:
|
||||||
} else if(result == COPY_UNSUPPORTED_CONVERSION) {
|
return SQL_SUCCESS;
|
||||||
stmt->errormsg = "Couldn't handle the necessary data type conversion.";
|
|
||||||
stmt->errornumber = STMT_RESTRICTED_DATA_TYPE_ERROR;
|
case COPY_UNSUPPORTED_TYPE:
|
||||||
return SQL_ERROR;
|
stmt->errormsg = "Received an unsupported type from Postgres.";
|
||||||
} else if(result == COPY_RESULT_TRUNCATED) {
|
stmt->errornumber = STMT_RESTRICTED_DATA_TYPE_ERROR;
|
||||||
stmt->errornumber = STMT_TRUNCATED;
|
return SQL_ERROR;
|
||||||
stmt->errormsg = "The buffer was too small for the result.";
|
|
||||||
return SQL_SUCCESS_WITH_INFO;
|
case COPY_UNSUPPORTED_CONVERSION:
|
||||||
} else if(result != COPY_OK) {
|
stmt->errormsg = "Couldn't handle the necessary data type conversion.";
|
||||||
|
stmt->errornumber = STMT_RESTRICTED_DATA_TYPE_ERROR;
|
||||||
|
return SQL_ERROR;
|
||||||
|
|
||||||
|
case COPY_RESULT_TRUNCATED:
|
||||||
|
stmt->errornumber = STMT_TRUNCATED;
|
||||||
|
stmt->errormsg = "The buffer was too small for the result.";
|
||||||
|
return SQL_SUCCESS_WITH_INFO;
|
||||||
|
|
||||||
|
case COPY_GENERAL_ERROR: /* error msg already filled in */
|
||||||
|
return SQL_ERROR;
|
||||||
|
|
||||||
|
case COPY_NO_DATA_FOUND:
|
||||||
|
return SQL_NO_DATA_FOUND;
|
||||||
|
|
||||||
|
default:
|
||||||
stmt->errormsg = "Unrecognized return value from copy_and_convert_field.";
|
stmt->errormsg = "Unrecognized return value from copy_and_convert_field.";
|
||||||
stmt->errornumber = STMT_INTERNAL_ERROR;
|
stmt->errornumber = STMT_INTERNAL_ERROR;
|
||||||
return SQL_ERROR;
|
return SQL_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
return SQL_SUCCESS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns data for bound columns in the current row ("hstmt->iCursor"),
|
// Returns data for bound columns in the current row ("hstmt->iCursor"),
|
||||||
|
@ -465,120 +569,136 @@ Int2 num_cols, lf;
|
||||||
Oid type;
|
Oid type;
|
||||||
char *value;
|
char *value;
|
||||||
ColumnInfoClass *ci;
|
ColumnInfoClass *ci;
|
||||||
|
// TupleField *tupleField;
|
||||||
|
|
||||||
|
if ( ! stmt)
|
||||||
|
return SQL_INVALID_HANDLE;
|
||||||
|
|
||||||
|
SC_clear_error(stmt);
|
||||||
|
|
||||||
|
if ( ! (res = stmt->result)) {
|
||||||
|
stmt->errormsg = "Null statement result in SQLFetch.";
|
||||||
|
stmt->errornumber = STMT_SEQUENCE_ERROR;
|
||||||
|
return SQL_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
ci = QR_get_fields(res); /* the column info */
|
||||||
|
|
||||||
|
if (stmt->status == STMT_EXECUTING) {
|
||||||
|
stmt->errormsg = "Can't fetch while statement is still executing.";
|
||||||
|
stmt->errornumber = STMT_SEQUENCE_ERROR;
|
||||||
|
return SQL_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if ( ! stmt)
|
if (stmt->status != STMT_FINISHED) {
|
||||||
return SQL_INVALID_HANDLE;
|
stmt->errornumber = STMT_STATUS_ERROR;
|
||||||
|
stmt->errormsg = "Fetch can only be called after the successful execution on a SQL statement";
|
||||||
|
return SQL_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
SC_clear_error(stmt);
|
if (stmt->bindings == NULL) {
|
||||||
|
// just to avoid a crash if the user insists on calling this
|
||||||
if ( ! (res = stmt->result)) {
|
// function even if SQL_ExecDirect has reported an Error
|
||||||
stmt->errormsg = "Null statement result in SQLFetch.";
|
stmt->errormsg = "Bindings were not allocated properly.";
|
||||||
stmt->errornumber = STMT_SEQUENCE_ERROR;
|
stmt->errornumber = STMT_SEQUENCE_ERROR;
|
||||||
return SQL_ERROR;
|
return SQL_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
ci = QR_get_fields(res); /* the column info */
|
|
||||||
|
|
||||||
if (stmt->status == STMT_EXECUTING) {
|
|
||||||
stmt->errormsg = "Can't fetch while statement is still executing.";
|
|
||||||
stmt->errornumber = STMT_SEQUENCE_ERROR;
|
|
||||||
return SQL_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (stmt->status != STMT_FINISHED) {
|
|
||||||
stmt->errornumber = STMT_STATUS_ERROR;
|
|
||||||
stmt->errormsg = "Fetch can only be called after the successful execution on a SQL statement";
|
|
||||||
return SQL_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stmt->bindings == NULL) {
|
|
||||||
// just to avoid a crash if the user insists on calling this
|
|
||||||
// function even if SQL_ExecDirect has reported an Error
|
|
||||||
stmt->errormsg = "Bindings were not allocated properly.";
|
|
||||||
stmt->errornumber = STMT_SEQUENCE_ERROR;
|
|
||||||
return SQL_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
mylog("manual_result = %d, use_declarefetch = %d\n",
|
||||||
|
stmt->manual_result, globals.use_declarefetch);
|
||||||
|
|
||||||
if ( stmt->manual_result) {
|
if ( stmt->manual_result || ! globals.use_declarefetch) {
|
||||||
if (QR_get_num_tuples(res) -1 == stmt->currTuple ||
|
|
||||||
(stmt->maxRows > 0 && stmt->currTuple == stmt->maxRows - 1))
|
if (stmt->currTuple >= QR_get_num_tuples(res) -1 ||
|
||||||
/* if we are at the end of a tuple list, we return a "no data found" */
|
(stmt->maxRows > 0 && stmt->currTuple == stmt->maxRows - 1)) {
|
||||||
return SQL_NO_DATA_FOUND;
|
|
||||||
|
/* if at the end of the tuples, return "no data found"
|
||||||
|
and set the cursor past the end of the result set
|
||||||
|
*/
|
||||||
|
stmt->currTuple = QR_get_num_tuples(res);
|
||||||
|
return SQL_NO_DATA_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
mylog("**** SQLFetch: manual_result\n");
|
mylog("**** SQLFetch: manual_result\n");
|
||||||
(stmt->currTuple)++;
|
(stmt->currTuple)++;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
||||||
// read from the cache or the physical next tuple
|
// read from the cache or the physical next tuple
|
||||||
retval = QR_next_tuple(res);
|
retval = QR_next_tuple(res);
|
||||||
if (retval < 0) {
|
if (retval < 0) {
|
||||||
mylog("**** SQLFetch: end_tuples\n");
|
mylog("**** SQLFetch: end_tuples\n");
|
||||||
return SQL_NO_DATA_FOUND;
|
return SQL_NO_DATA_FOUND;
|
||||||
}
|
}
|
||||||
else if (retval > 0)
|
else if (retval > 0)
|
||||||
(stmt->currTuple)++; // all is well
|
(stmt->currTuple)++; // all is well
|
||||||
|
|
||||||
else {
|
else {
|
||||||
mylog("SQLFetch: error\n");
|
mylog("SQLFetch: error\n");
|
||||||
stmt->errornumber = STMT_EXEC_ERROR;
|
stmt->errornumber = STMT_EXEC_ERROR;
|
||||||
stmt->errormsg = "Error fetching next row";
|
stmt->errormsg = "Error fetching next row";
|
||||||
return SQL_ERROR;
|
return SQL_ERROR;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
num_cols = QR_NumResultCols(res);
|
||||||
|
|
||||||
num_cols = QR_NumResultCols(res);
|
for (lf=0; lf < num_cols; lf++) {
|
||||||
|
|
||||||
for (lf=0; lf < num_cols; lf++) {
|
mylog("fetch: cols=%d, lf=%d, stmt = %u, stmt->bindings = %u, buffer[] = %u\n",
|
||||||
|
num_cols, lf, stmt, stmt->bindings, stmt->bindings[lf].buffer);
|
||||||
|
|
||||||
mylog("fetch: cols=%d, lf=%d, buffer[] = %u\n",
|
if (stmt->bindings[lf].buffer != NULL) {
|
||||||
num_cols, lf, stmt->bindings[lf].buffer);
|
|
||||||
|
|
||||||
if (stmt->bindings[lf].buffer != NULL) {
|
|
||||||
// this column has a binding
|
// this column has a binding
|
||||||
|
|
||||||
// type = QR_get_field_type(res, lf);
|
// type = QR_get_field_type(res, lf);
|
||||||
type = CI_get_oid(ci, lf); /* speed things up */
|
type = CI_get_oid(ci, lf); /* speed things up */
|
||||||
|
|
||||||
|
mylog("type = %d\n", type);
|
||||||
|
|
||||||
if (stmt->manual_result)
|
if (stmt->manual_result)
|
||||||
value = QR_get_value_manual(res, stmt->currTuple, lf);
|
value = QR_get_value_manual(res, stmt->currTuple, lf);
|
||||||
else
|
else if (globals.use_declarefetch)
|
||||||
value = QR_get_value_backend(res, lf);
|
value = QR_get_value_backend(res, lf);
|
||||||
|
else {
|
||||||
|
value = QR_get_value_backend_row(res, stmt->currTuple, lf);
|
||||||
|
}
|
||||||
|
|
||||||
retval = copy_and_convert_field_bindinfo(type, value, &(stmt->bindings[lf]));
|
mylog("value = '%s'\n", value);
|
||||||
|
|
||||||
// check whether the complete result was copied
|
retval = copy_and_convert_field_bindinfo(stmt, type, value, lf);
|
||||||
if(retval == COPY_UNSUPPORTED_TYPE) {
|
|
||||||
stmt->errormsg = "Received an unsupported type from Postgres.";
|
|
||||||
stmt->errornumber = STMT_RESTRICTED_DATA_TYPE_ERROR;
|
|
||||||
return SQL_ERROR;
|
|
||||||
|
|
||||||
} else if(retval == COPY_UNSUPPORTED_CONVERSION) {
|
mylog("copy_and_convert: retval = %d\n", retval);
|
||||||
stmt->errormsg = "Couldn't handle the necessary data type conversion.";
|
|
||||||
stmt->errornumber = STMT_RESTRICTED_DATA_TYPE_ERROR;
|
|
||||||
return SQL_ERROR;
|
|
||||||
|
|
||||||
} else if(retval == COPY_RESULT_TRUNCATED) {
|
// check whether the complete result was copied
|
||||||
/* The result has been truncated during the copy */
|
if(retval == COPY_UNSUPPORTED_TYPE) {
|
||||||
/* this will generate a SQL_SUCCESS_WITH_INFO result */
|
stmt->errormsg = "Received an unsupported type from Postgres.";
|
||||||
stmt->errornumber = STMT_TRUNCATED;
|
stmt->errornumber = STMT_RESTRICTED_DATA_TYPE_ERROR;
|
||||||
stmt->errormsg = "A buffer was too small for the return value to fit in";
|
return SQL_ERROR;
|
||||||
|
|
||||||
|
} else if(retval == COPY_UNSUPPORTED_CONVERSION) {
|
||||||
|
stmt->errormsg = "Couldn't handle the necessary data type conversion.";
|
||||||
|
stmt->errornumber = STMT_RESTRICTED_DATA_TYPE_ERROR;
|
||||||
|
return SQL_ERROR;
|
||||||
|
|
||||||
|
} else if(retval == COPY_RESULT_TRUNCATED) {
|
||||||
|
/* The result has been truncated during the copy */
|
||||||
|
/* this will generate a SQL_SUCCESS_WITH_INFO result */
|
||||||
|
stmt->errornumber = STMT_TRUNCATED;
|
||||||
|
stmt->errormsg = "A buffer was too small for the return value to fit in";
|
||||||
return SQL_SUCCESS_WITH_INFO;
|
return SQL_SUCCESS_WITH_INFO;
|
||||||
|
|
||||||
} else if(retval != COPY_OK) {
|
} else if(retval != COPY_OK) {
|
||||||
stmt->errormsg = "Unrecognized return value from copy_and_convert_field.";
|
stmt->errormsg = "Unrecognized return value from copy_and_convert_field.";
|
||||||
stmt->errornumber = STMT_INTERNAL_ERROR;
|
stmt->errornumber = STMT_INTERNAL_ERROR;
|
||||||
return SQL_ERROR;
|
return SQL_ERROR;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return SQL_SUCCESS;
|
return SQL_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This fetchs a block of data (rowset).
|
// This fetchs a block of data (rowset).
|
||||||
|
@ -591,52 +711,91 @@ RETCODE SQL_API SQLExtendedFetch(
|
||||||
UWORD FAR *rgfRowStatus)
|
UWORD FAR *rgfRowStatus)
|
||||||
{
|
{
|
||||||
StatementClass *stmt = (StatementClass *) hstmt;
|
StatementClass *stmt = (StatementClass *) hstmt;
|
||||||
|
int num_tuples;
|
||||||
|
RETCODE result;
|
||||||
|
|
||||||
if ( ! stmt)
|
|
||||||
return SQL_INVALID_HANDLE;
|
|
||||||
|
|
||||||
/* Currently, only for manual results can this be done
|
mylog("SQLExtendedFetch: stmt=%u\n", stmt);
|
||||||
because not all the tuples are read in ahead of time.
|
|
||||||
*/
|
|
||||||
if ( ! stmt->manual_result)
|
|
||||||
return SQL_ERROR;
|
|
||||||
|
|
||||||
// CC: we currently only support fetches in one row bits
|
if ( ! stmt)
|
||||||
if (NULL != pcrow)
|
return SQL_INVALID_HANDLE;
|
||||||
*pcrow = 1;
|
|
||||||
if (NULL != rgfRowStatus)
|
if ( globals.use_declarefetch)
|
||||||
*rgfRowStatus = SQL_ROW_SUCCESS;
|
return SQL_ERROR;
|
||||||
|
|
||||||
|
/* Initialize to no rows fetched */
|
||||||
|
if (rgfRowStatus)
|
||||||
|
*rgfRowStatus = SQL_ROW_NOROW;
|
||||||
|
if (pcrow)
|
||||||
|
*pcrow = 0;
|
||||||
|
|
||||||
|
num_tuples = QR_get_num_tuples(stmt->result);
|
||||||
|
|
||||||
|
switch (fFetchType) {
|
||||||
|
case SQL_FETCH_NEXT:
|
||||||
|
mylog("SQL_FETCH_NEXT: num_tuples=%d, currtuple=%d\n", num_tuples, stmt->currTuple);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SQL_FETCH_PRIOR:
|
||||||
|
mylog("SQL_FETCH_PRIOR: num_tuples=%d, currtuple=%d\n", num_tuples, stmt->currTuple);
|
||||||
|
|
||||||
|
/* If already before result set, return no data found */
|
||||||
|
if (stmt->currTuple <= 0)
|
||||||
|
return SQL_NO_DATA_FOUND;
|
||||||
|
|
||||||
|
stmt->currTuple -= 2;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SQL_FETCH_FIRST:
|
||||||
|
mylog("SQL_FETCH_FIRST: num_tuples=%d, currtuple=%d\n", num_tuples, stmt->currTuple);
|
||||||
|
|
||||||
|
stmt->currTuple = -1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SQL_FETCH_LAST:
|
||||||
|
mylog("SQL_FETCH_LAST: num_tuples=%d, currtuple=%d\n", num_tuples, stmt->currTuple);
|
||||||
|
stmt->currTuple = num_tuples <= 0 ? -1 : (num_tuples - 2);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SQL_FETCH_ABSOLUTE:
|
||||||
|
mylog("SQL_FETCH_ABSOLUTE: num_tuples=%d, currtuple=%d, irow=%d\n", num_tuples, stmt->currTuple, irow);
|
||||||
|
|
||||||
|
/* Position before result set, but dont fetch anything */
|
||||||
|
if (irow == 0) {
|
||||||
|
stmt->currTuple = -1;
|
||||||
|
return SQL_NO_DATA_FOUND;
|
||||||
|
}
|
||||||
|
/* Position before the desired row */
|
||||||
|
else if (irow > 0) {
|
||||||
|
stmt->currTuple = irow-2;
|
||||||
|
}
|
||||||
|
/* Position with respect to the end of the result set */
|
||||||
|
else {
|
||||||
|
stmt->currTuple = num_tuples + irow - 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return SQL_ERROR;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
mylog("SQLExtendedFetch: new currTuple = %d\n", stmt->currTuple);
|
||||||
|
|
||||||
|
result = SQLFetch(hstmt);
|
||||||
|
|
||||||
|
if (result == SQL_SUCCESS) {
|
||||||
|
if (rgfRowStatus)
|
||||||
|
*rgfRowStatus = SQL_ROW_SUCCESS;
|
||||||
|
if (pcrow)
|
||||||
|
*pcrow = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
|
||||||
switch (fFetchType) {
|
|
||||||
case SQL_FETCH_NEXT:
|
|
||||||
return SQLFetch(hstmt);
|
|
||||||
case SQL_FETCH_PRIOR:
|
|
||||||
if (stmt->currTuple <= 0)
|
|
||||||
return SQL_ERROR;
|
|
||||||
stmt->currTuple--;
|
|
||||||
return SQLFetch(hstmt);
|
|
||||||
case SQL_FETCH_FIRST:
|
|
||||||
stmt->currTuple = -1;
|
|
||||||
return SQLFetch(hstmt);
|
|
||||||
case SQL_FETCH_LAST:
|
|
||||||
stmt->currTuple = QR_get_num_tuples(stmt->result)-1;
|
|
||||||
return SQLFetch(hstmt);
|
|
||||||
case SQL_FETCH_ABSOLUTE:
|
|
||||||
if (irow == 0) {
|
|
||||||
stmt->currTuple = stmt->currTuple > 0 ? stmt->currTuple-2 : -1;
|
|
||||||
} else if (irow > 0) {
|
|
||||||
stmt->currTuple = irow-2;
|
|
||||||
return SQLFetch(hstmt);
|
|
||||||
} else {
|
|
||||||
// CC: ??? not sure about the specification in that case
|
|
||||||
return SQL_ERROR;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return SQL_ERROR;
|
|
||||||
}
|
|
||||||
return SQL_SUCCESS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// This determines whether there are more results sets available for
|
// This determines whether there are more results sets available for
|
||||||
// the "hstmt".
|
// the "hstmt".
|
||||||
|
|
||||||
|
@ -677,7 +836,24 @@ RETCODE SQL_API SQLSetCursorName(
|
||||||
UCHAR FAR *szCursor,
|
UCHAR FAR *szCursor,
|
||||||
SWORD cbCursor)
|
SWORD cbCursor)
|
||||||
{
|
{
|
||||||
return SQL_SUCCESS;
|
StatementClass *stmt = (StatementClass *) hstmt;
|
||||||
|
int len;
|
||||||
|
|
||||||
|
mylog("SQLSetCursorName: hstmt=%u, szCursor=%u, cbCursorMax=%d\n",
|
||||||
|
hstmt, szCursor, cbCursor);
|
||||||
|
|
||||||
|
if ( ! stmt)
|
||||||
|
return SQL_INVALID_HANDLE;
|
||||||
|
|
||||||
|
len = (cbCursor == SQL_NTS) ? strlen(szCursor) : cbCursor;
|
||||||
|
mylog("cursor len = %d\n", len);
|
||||||
|
if (len <= 0 || len > sizeof(stmt->cursor_name) - 1) {
|
||||||
|
stmt->errornumber = STMT_INVALID_CURSOR_NAME;
|
||||||
|
stmt->errormsg = "Invalid Cursor Name";
|
||||||
|
return SQL_ERROR;
|
||||||
|
}
|
||||||
|
strncpy_null(stmt->cursor_name, szCursor, cbCursor);
|
||||||
|
return SQL_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the cursor name for a statement handle
|
// Return the cursor name for a statement handle
|
||||||
|
@ -688,7 +864,27 @@ RETCODE SQL_API SQLGetCursorName(
|
||||||
SWORD cbCursorMax,
|
SWORD cbCursorMax,
|
||||||
SWORD FAR *pcbCursor)
|
SWORD FAR *pcbCursor)
|
||||||
{
|
{
|
||||||
return SQL_ERROR;
|
StatementClass *stmt = (StatementClass *) hstmt;
|
||||||
|
|
||||||
|
mylog("SQLGetCursorName: hstmt=%u, szCursor=%u, cbCursorMax=%d, pcbCursor=%u\n",
|
||||||
|
hstmt, szCursor, cbCursorMax, pcbCursor);
|
||||||
|
|
||||||
|
if ( ! stmt)
|
||||||
|
return SQL_INVALID_HANDLE;
|
||||||
|
|
||||||
|
|
||||||
|
if ( stmt->cursor_name[0] == '\0') {
|
||||||
|
stmt->errornumber = STMT_NO_CURSOR_NAME;
|
||||||
|
stmt->errormsg = "No Cursor name available";
|
||||||
|
return SQL_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
strncpy_null(szCursor, stmt->cursor_name, cbCursorMax);
|
||||||
|
|
||||||
|
if (pcbCursor)
|
||||||
|
*pcbCursor = strlen(szCursor);
|
||||||
|
|
||||||
|
return SQL_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,95 +1,28 @@
|
||||||
|
|
||||||
/* Module: setup.c
|
|
||||||
*
|
|
||||||
* Description: This module contains the setup functions for
|
|
||||||
* adding/modifying a Data Source in the ODBC.INI portion
|
|
||||||
* of the registry.
|
|
||||||
*
|
|
||||||
* Classes: n/a
|
|
||||||
*
|
|
||||||
* API functions: ConfigDSN
|
|
||||||
*
|
|
||||||
* Comments: See "notice.txt" for copyright and license information.
|
|
||||||
*
|
|
||||||
*************************************************************************************/
|
|
||||||
|
|
||||||
/*
|
/* Module: setup.c
|
||||||
** SETUP.C - This is the ODBC sample driver code for
|
*
|
||||||
** setup.
|
* Description: This module contains the setup functions for
|
||||||
**
|
* adding/modifying a Data Source in the ODBC.INI portion
|
||||||
** This code is furnished on an as-is basis as part of the ODBC SDK and is
|
* of the registry.
|
||||||
** intended for example purposes only.
|
*
|
||||||
**
|
* Classes: n/a
|
||||||
*/
|
*
|
||||||
/*--------------------------------------------------------------------------
|
* API functions: ConfigDSN
|
||||||
setup.c -- Sample ODBC setup
|
*
|
||||||
|
* Comments: See "notice.txt" for copyright and license information.
|
||||||
|
*
|
||||||
|
*************************************************************************************/
|
||||||
|
|
||||||
This code demonstrates how to interact with the ODBC Installer. These
|
#include "psqlodbc.h"
|
||||||
functions may be part of your ODBC driver or in a separate DLL.
|
#include "connection.h"
|
||||||
|
|
||||||
The ODBC Installer allows a driver to control the management of
|
|
||||||
data sources by calling the ConfigDSN entry point in the appropriate
|
|
||||||
DLL. When called, ConfigDSN receives four parameters:
|
|
||||||
|
|
||||||
hwndParent ---- Handle of the parent window for any dialogs which
|
|
||||||
may need to be created. If this handle is NULL,
|
|
||||||
then no dialogs should be displayed (that is, the
|
|
||||||
request should be processed silently).
|
|
||||||
|
|
||||||
fRequest ------ Flag indicating the type of request (add, configure
|
|
||||||
(edit), or remove).
|
|
||||||
|
|
||||||
lpszDriver ---- Far pointer to a null-terminated string containing
|
|
||||||
the name of your driver. This is the same string you
|
|
||||||
supply in the ODBC.INF file as your section header
|
|
||||||
and which ODBC Setup displays to the user in lieu
|
|
||||||
of the actual driver filename. This string needs to
|
|
||||||
be passed back to the ODBC Installer when adding a
|
|
||||||
new data source name.
|
|
||||||
|
|
||||||
lpszAttributes- Far pointer to a list of null-terminated attribute
|
|
||||||
keywords. This list is similar to the list passed
|
|
||||||
to SQLDriverConnect, except that each key-value
|
|
||||||
pair is separated by a null-byte rather than a
|
|
||||||
semicolon. The entire list is then terminated with
|
|
||||||
a null-byte (that is, two consecutive null-bytes
|
|
||||||
mark the end of the list). The keywords accepted
|
|
||||||
should be those for SQLDriverConnect which are
|
|
||||||
applicable, any new keywords you define for ODBC.INI,
|
|
||||||
and any additional keywords you decide to document.
|
|
||||||
|
|
||||||
ConfigDSN should return TRUE if the requested operation succeeds and
|
|
||||||
FALSE otherwise. The complete prototype for ConfigDSN is:
|
|
||||||
|
|
||||||
BOOL FAR PASCAL ConfigDSN(HWND hwndParent,
|
|
||||||
WORD fRequest,
|
|
||||||
LPSTR lpszDriver,
|
|
||||||
LPCSTR lpszAttributes)
|
|
||||||
|
|
||||||
Your setup code should not write to ODBC.INI directly to add or remove
|
|
||||||
data source names. Instead, link with ODBCINST.LIB (the ODBC Installer
|
|
||||||
library) and call SQLWriteDSNToIni and SQLRemoveDSNFromIni.
|
|
||||||
Use SQLWriteDSNToIni to add data source names. If the data source name
|
|
||||||
already exists, SQLWriteDSNToIni will delete it (removing all of its
|
|
||||||
associated keys) and rewrite it. SQLRemoveDSNToIni removes a data
|
|
||||||
source name and all of its associated keys.
|
|
||||||
|
|
||||||
For NT compatibility, the driver code should not use the
|
|
||||||
Get/WritePrivateProfileString windows functions for ODBC.INI, but instead,
|
|
||||||
use SQLGet/SQLWritePrivateProfileString functions that are macros (16 bit) or
|
|
||||||
calls to the odbcinst.dll (32 bit).
|
|
||||||
|
|
||||||
--------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
|
|
||||||
// Includes ----------------------------------------------------------------
|
|
||||||
#include "psqlodbc.h" // Local include files
|
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <windowsx.h>
|
#include <windowsx.h>
|
||||||
#include <odbcinst.h> // ODBC installer prototypes
|
#include <odbcinst.h>
|
||||||
#include <string.h> // C include files
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include "resource.h"
|
#include "resource.h"
|
||||||
|
#include "dlg_specific.h"
|
||||||
|
|
||||||
|
|
||||||
#define INTFUNC __stdcall
|
#define INTFUNC __stdcall
|
||||||
|
|
||||||
|
@ -104,81 +37,27 @@ extern GLOBAL_VALUES globals;
|
||||||
#define MAXDESC (255+1) // Max description length
|
#define MAXDESC (255+1) // Max description length
|
||||||
#define MAXDSNAME (32+1) // Max data source name length
|
#define MAXDSNAME (32+1) // Max data source name length
|
||||||
|
|
||||||
static char far EMPTYSTR []= "";
|
|
||||||
static char far OPTIONON []= "Yes";
|
|
||||||
static char far OPTIONOFF []= "No";
|
|
||||||
|
|
||||||
// Attribute key indexes (into an array of Attr structs, see below)
|
|
||||||
#define KEY_DSN 0
|
|
||||||
#define KEY_DESC 1
|
|
||||||
#define KEY_PORT 2
|
|
||||||
#define KEY_SERVER 3
|
|
||||||
#define KEY_DATABASE 4
|
|
||||||
#define KEY_USER 5
|
|
||||||
#define KEY_PASSWORD 6
|
|
||||||
#define KEY_DEBUG 7
|
|
||||||
#define KEY_FETCH 8
|
|
||||||
#define KEY_READONLY 9
|
|
||||||
#define KEY_PROTOCOL 10
|
|
||||||
#define NUMOFKEYS 11 // Number of keys supported
|
|
||||||
|
|
||||||
// Attribute string look-up table (maps keys to associated indexes)
|
|
||||||
static struct {
|
|
||||||
char szKey[MAXKEYLEN];
|
|
||||||
int iKey;
|
|
||||||
} s_aLookup[] = { "DSN", KEY_DSN,
|
|
||||||
INI_KDESC, KEY_DESC,
|
|
||||||
INI_PORT, KEY_PORT,
|
|
||||||
INI_SERVER, KEY_SERVER,
|
|
||||||
INI_DATABASE, KEY_DATABASE,
|
|
||||||
INI_USER, KEY_USER,
|
|
||||||
INI_PASSWORD, KEY_PASSWORD,
|
|
||||||
INI_DEBUG, KEY_DEBUG,
|
|
||||||
INI_FETCH, KEY_FETCH,
|
|
||||||
INI_READONLY, KEY_READONLY,
|
|
||||||
INI_PROTOCOL, KEY_PROTOCOL,
|
|
||||||
"", 0
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Types -------------------------------------------------------------------
|
|
||||||
typedef struct tagAttr {
|
|
||||||
BOOL fSupplied;
|
|
||||||
char szAttr[MAXPATHLEN];
|
|
||||||
} Attr, FAR * LPAttr;
|
|
||||||
|
|
||||||
|
|
||||||
// Globals -----------------------------------------------------------------
|
// Globals -----------------------------------------------------------------
|
||||||
// NOTE: All these are used by the dialog procedures
|
// NOTE: All these are used by the dialog procedures
|
||||||
typedef struct tagSETUPDLG {
|
typedef struct tagSETUPDLG {
|
||||||
HWND hwndParent; // Parent window handle
|
HWND hwndParent; // Parent window handle
|
||||||
LPCSTR lpszDrvr; // Driver description
|
LPCSTR lpszDrvr; // Driver description
|
||||||
Attr aAttr[NUMOFKEYS]; // Attribute array
|
ConnInfo ci;
|
||||||
char szDSN[MAXDSNAME]; // Original data source name
|
char szDSN[MAXDSNAME]; // Original data source name
|
||||||
BOOL fNewDSN; // New data source flag
|
BOOL fNewDSN; // New data source flag
|
||||||
BOOL fDefault; // Default data source flag
|
BOOL fDefault; // Default data source flag
|
||||||
|
|
||||||
} SETUPDLG, FAR *LPSETUPDLG;
|
} SETUPDLG, FAR *LPSETUPDLG;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Prototypes --------------------------------------------------------------
|
// Prototypes --------------------------------------------------------------
|
||||||
void INTFUNC CenterDialog (HWND hdlg);
|
void INTFUNC CenterDialog(HWND hdlg);
|
||||||
|
int CALLBACK ConfigDlgProc(HWND hdlg, WORD wMsg, WPARAM wParam, LPARAM lParam);
|
||||||
|
void INTFUNC ParseAttributes (LPCSTR lpszAttributes, LPSETUPDLG lpsetupdlg);
|
||||||
|
BOOL INTFUNC SetDSNAttributes(HWND hwnd, LPSETUPDLG lpsetupdlg);
|
||||||
|
|
||||||
int CALLBACK ConfigDlgProc (HWND hdlg,
|
|
||||||
WORD wMsg,
|
|
||||||
WPARAM wParam,
|
|
||||||
LPARAM lParam);
|
|
||||||
void INTFUNC ParseAttributes (LPCSTR lpszAttributes, LPSETUPDLG lpsetupdlg);
|
|
||||||
|
|
||||||
/* CC: SetDSNAttributes is declared as "INTFUNC" below, but here it is declared as
|
|
||||||
"CALLBACK" -- Watcom complained about disagreeing modifiers. Changed
|
|
||||||
"CALLBACK" to "INTFUNC" here.
|
|
||||||
BOOL CALLBACK SetDSNAttributes(HWND hwnd, LPSETUPDLG lpsetupdlg);
|
|
||||||
*/
|
|
||||||
|
|
||||||
BOOL INTFUNC SetDSNAttributes(HWND hwnd, LPSETUPDLG lpsetupdlg);
|
|
||||||
|
|
||||||
/* ConfigDSN ---------------------------------------------------------------
|
/* ConfigDSN ---------------------------------------------------------------
|
||||||
Description: ODBC Setup entry point
|
Description: ODBC Setup entry point
|
||||||
|
@ -196,9 +75,9 @@ BOOL CALLBACK ConfigDSN (HWND hwnd,
|
||||||
LPCSTR lpszDriver,
|
LPCSTR lpszDriver,
|
||||||
LPCSTR lpszAttributes)
|
LPCSTR lpszAttributes)
|
||||||
{
|
{
|
||||||
BOOL fSuccess; // Success/fail flag
|
BOOL fSuccess; // Success/fail flag
|
||||||
GLOBALHANDLE hglbAttr;
|
GLOBALHANDLE hglbAttr;
|
||||||
LPSETUPDLG lpsetupdlg;
|
LPSETUPDLG lpsetupdlg;
|
||||||
|
|
||||||
|
|
||||||
// Allocate attribute array
|
// Allocate attribute array
|
||||||
|
@ -212,20 +91,20 @@ BOOL CALLBACK ConfigDSN (HWND hwnd,
|
||||||
ParseAttributes(lpszAttributes, lpsetupdlg);
|
ParseAttributes(lpszAttributes, lpsetupdlg);
|
||||||
|
|
||||||
// Save original data source name
|
// Save original data source name
|
||||||
if (lpsetupdlg->aAttr[KEY_DSN].fSupplied)
|
if (lpsetupdlg->ci.dsn[0])
|
||||||
lstrcpy(lpsetupdlg->szDSN, lpsetupdlg->aAttr[KEY_DSN].szAttr);
|
lstrcpy(lpsetupdlg->szDSN, lpsetupdlg->ci.dsn);
|
||||||
else
|
else
|
||||||
lpsetupdlg->szDSN[0] = '\0';
|
lpsetupdlg->szDSN[0] = '\0';
|
||||||
|
|
||||||
// Remove data source
|
// Remove data source
|
||||||
if (ODBC_REMOVE_DSN == fRequest) {
|
if (ODBC_REMOVE_DSN == fRequest) {
|
||||||
// Fail if no data source name was supplied
|
// Fail if no data source name was supplied
|
||||||
if (!lpsetupdlg->aAttr[KEY_DSN].fSupplied)
|
if (!lpsetupdlg->ci.dsn[0])
|
||||||
fSuccess = FALSE;
|
fSuccess = FALSE;
|
||||||
|
|
||||||
// Otherwise remove data source from ODBC.INI
|
// Otherwise remove data source from ODBC.INI
|
||||||
else
|
else
|
||||||
fSuccess = SQLRemoveDSNFromIni(lpsetupdlg->aAttr[KEY_DSN].szAttr);
|
fSuccess = SQLRemoveDSNFromIni(lpsetupdlg->ci.dsn);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add or Configure data source
|
// Add or Configure data source
|
||||||
|
@ -235,19 +114,19 @@ BOOL CALLBACK ConfigDSN (HWND hwnd,
|
||||||
lpsetupdlg->lpszDrvr = lpszDriver;
|
lpsetupdlg->lpszDrvr = lpszDriver;
|
||||||
lpsetupdlg->fNewDSN = (ODBC_ADD_DSN == fRequest);
|
lpsetupdlg->fNewDSN = (ODBC_ADD_DSN == fRequest);
|
||||||
lpsetupdlg->fDefault =
|
lpsetupdlg->fDefault =
|
||||||
!lstrcmpi(lpsetupdlg->aAttr[KEY_DSN].szAttr, INI_DSN);
|
!lstrcmpi(lpsetupdlg->ci.dsn, INI_DSN);
|
||||||
|
|
||||||
// Display the appropriate dialog (if parent window handle supplied)
|
// Display the appropriate dialog (if parent window handle supplied)
|
||||||
if (hwnd) {
|
if (hwnd) {
|
||||||
// Display dialog(s)
|
// Display dialog(s)
|
||||||
fSuccess = (IDOK == DialogBoxParam(s_hModule,
|
fSuccess = (IDOK == DialogBoxParam(s_hModule,
|
||||||
MAKEINTRESOURCE(CONFIGDSN),
|
MAKEINTRESOURCE(DLG_CONFIG),
|
||||||
hwnd,
|
hwnd,
|
||||||
ConfigDlgProc,
|
ConfigDlgProc,
|
||||||
(LONG)(LPSTR)lpsetupdlg));
|
(LONG)(LPSTR)lpsetupdlg));
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (lpsetupdlg->aAttr[KEY_DSN].fSupplied)
|
else if (lpsetupdlg->ci.dsn[0])
|
||||||
fSuccess = SetDSNAttributes(hwnd, lpsetupdlg);
|
fSuccess = SetDSNAttributes(hwnd, lpsetupdlg);
|
||||||
else
|
else
|
||||||
fSuccess = FALSE;
|
fSuccess = FALSE;
|
||||||
|
@ -314,208 +193,123 @@ void INTFUNC CenterDialog(HWND hdlg)
|
||||||
--------------------------------------------------------------------------*/
|
--------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
||||||
|
int CALLBACK ConfigDlgProc(HWND hdlg,
|
||||||
int CALLBACK ConfigDlgProc
|
WORD wMsg,
|
||||||
(HWND hdlg,
|
WPARAM wParam,
|
||||||
WORD wMsg,
|
LPARAM lParam)
|
||||||
WPARAM wParam,
|
|
||||||
LPARAM lParam)
|
|
||||||
{
|
{
|
||||||
|
|
||||||
switch (wMsg) {
|
switch (wMsg) {
|
||||||
// Initialize the dialog
|
// Initialize the dialog
|
||||||
case WM_INITDIALOG:
|
case WM_INITDIALOG:
|
||||||
{
|
{
|
||||||
LPSETUPDLG lpsetupdlg;
|
LPSETUPDLG lpsetupdlg = (LPSETUPDLG) lParam;
|
||||||
LPCSTR lpszDSN;
|
ConnInfo *ci = &lpsetupdlg->ci;
|
||||||
|
|
||||||
SetWindowLong(hdlg, DWL_USER, lParam);
|
/* Hide the driver connect message */
|
||||||
CenterDialog(hdlg); // Center dialog
|
ShowWindow(GetDlgItem(hdlg, DRV_MSG_LABEL), SW_HIDE);
|
||||||
|
|
||||||
lpsetupdlg = (LPSETUPDLG) lParam;
|
SetWindowLong(hdlg, DWL_USER, lParam);
|
||||||
lpszDSN = lpsetupdlg->aAttr[KEY_DSN].szAttr;
|
CenterDialog(hdlg); // Center dialog
|
||||||
// Initialize dialog fields
|
|
||||||
// NOTE: Values supplied in the attribute string will always
|
|
||||||
// override settings in ODBC.INI
|
|
||||||
SetDlgItemText(hdlg, IDC_DSNAME, lpszDSN);
|
|
||||||
|
|
||||||
// Description
|
// NOTE: Values supplied in the attribute string will always
|
||||||
if (!lpsetupdlg->aAttr[KEY_DESC].fSupplied)
|
// override settings in ODBC.INI
|
||||||
SQLGetPrivateProfileString(lpszDSN, INI_KDESC,
|
|
||||||
EMPTYSTR,
|
|
||||||
lpsetupdlg->aAttr[KEY_DESC].szAttr,
|
|
||||||
sizeof(lpsetupdlg->aAttr[KEY_DESC].szAttr),
|
|
||||||
ODBC_INI);
|
|
||||||
SetDlgItemText(hdlg, IDC_DESC, lpsetupdlg->aAttr[KEY_DESC].szAttr);
|
|
||||||
|
|
||||||
// Database
|
// Get the rest of the common attributes
|
||||||
if (!lpsetupdlg->aAttr[KEY_DATABASE].fSupplied)
|
getDSNinfo(ci, CONN_DONT_OVERWRITE);
|
||||||
SQLGetPrivateProfileString(lpszDSN, INI_DATABASE,
|
|
||||||
EMPTYSTR,
|
|
||||||
lpsetupdlg->aAttr[KEY_DATABASE].szAttr,
|
|
||||||
sizeof(lpsetupdlg->aAttr[KEY_DATABASE].szAttr),
|
|
||||||
ODBC_INI);
|
|
||||||
SetDlgItemText(hdlg, IDC_DATABASE, lpsetupdlg->aAttr[KEY_DATABASE].szAttr);
|
|
||||||
|
|
||||||
// Server
|
// Fill in any defaults
|
||||||
if (!lpsetupdlg->aAttr[KEY_SERVER].fSupplied)
|
getDSNdefaults(ci);
|
||||||
SQLGetPrivateProfileString(lpszDSN, INI_SERVER,
|
|
||||||
EMPTYSTR,
|
|
||||||
lpsetupdlg->aAttr[KEY_SERVER].szAttr,
|
|
||||||
sizeof(lpsetupdlg->aAttr[KEY_SERVER].szAttr),
|
|
||||||
ODBC_INI);
|
|
||||||
SetDlgItemText(hdlg, IDC_SERVER, lpsetupdlg->aAttr[KEY_SERVER].szAttr);
|
|
||||||
|
|
||||||
// Port
|
|
||||||
if (!lpsetupdlg->aAttr[KEY_PORT].fSupplied)
|
|
||||||
SQLGetPrivateProfileString(lpszDSN, INI_PORT,
|
|
||||||
EMPTYSTR,
|
|
||||||
lpsetupdlg->aAttr[KEY_PORT].szAttr,
|
|
||||||
sizeof(lpsetupdlg->aAttr[KEY_PORT].szAttr),
|
|
||||||
ODBC_INI);
|
|
||||||
if (lpsetupdlg->aAttr[KEY_PORT].szAttr[0] == '\0')
|
|
||||||
strcpy(lpsetupdlg->aAttr[KEY_PORT].szAttr, DEFAULT_PORT);
|
|
||||||
SetDlgItemText(hdlg, IDC_PORT, lpsetupdlg->aAttr[KEY_PORT].szAttr);
|
|
||||||
|
|
||||||
/* Username */
|
|
||||||
if (!lpsetupdlg->aAttr[KEY_USER].fSupplied)
|
|
||||||
SQLGetPrivateProfileString(lpszDSN, INI_USER,
|
|
||||||
EMPTYSTR,
|
|
||||||
lpsetupdlg->aAttr[KEY_USER].szAttr,
|
|
||||||
sizeof(lpsetupdlg->aAttr[KEY_USER].szAttr),
|
|
||||||
ODBC_INI);
|
|
||||||
SetDlgItemText(hdlg, IDC_USER, lpsetupdlg->aAttr[KEY_USER].szAttr);
|
|
||||||
|
|
||||||
// Password
|
|
||||||
if (!lpsetupdlg->aAttr[KEY_PASSWORD].fSupplied)
|
|
||||||
SQLGetPrivateProfileString(lpszDSN, INI_PASSWORD,
|
|
||||||
EMPTYSTR,
|
|
||||||
lpsetupdlg->aAttr[KEY_PASSWORD].szAttr,
|
|
||||||
sizeof(lpsetupdlg->aAttr[KEY_PASSWORD].szAttr),
|
|
||||||
ODBC_INI);
|
|
||||||
SetDlgItemText(hdlg, IDC_PASSWORD, lpsetupdlg->aAttr[KEY_PASSWORD].szAttr);
|
|
||||||
|
|
||||||
// ReadOnly Parameter
|
|
||||||
if (!lpsetupdlg->aAttr[KEY_READONLY].fSupplied) {
|
|
||||||
SQLGetPrivateProfileString(lpszDSN, INI_READONLY,
|
|
||||||
EMPTYSTR,
|
|
||||||
lpsetupdlg->aAttr[KEY_READONLY].szAttr,
|
|
||||||
sizeof(lpsetupdlg->aAttr[KEY_READONLY].szAttr),
|
|
||||||
ODBC_INI);
|
|
||||||
}
|
|
||||||
if (lpsetupdlg->aAttr[KEY_READONLY].szAttr[0] == '\0')
|
|
||||||
strcpy(lpsetupdlg->aAttr[KEY_READONLY].szAttr, DEFAULT_READONLY);
|
|
||||||
CheckDlgButton(hdlg, IDC_READONLY, atoi(lpsetupdlg->aAttr[KEY_READONLY].szAttr));
|
|
||||||
|
|
||||||
// Protocol Parameter
|
|
||||||
if (!lpsetupdlg->aAttr[KEY_PROTOCOL].fSupplied) {
|
|
||||||
SQLGetPrivateProfileString(lpszDSN, INI_PROTOCOL,
|
|
||||||
EMPTYSTR,
|
|
||||||
lpsetupdlg->aAttr[KEY_PROTOCOL].szAttr,
|
|
||||||
sizeof(lpsetupdlg->aAttr[KEY_PROTOCOL].szAttr),
|
|
||||||
ODBC_INI);
|
|
||||||
}
|
|
||||||
if (strncmp(lpsetupdlg->aAttr[KEY_PROTOCOL].szAttr, PG62, strlen(PG62)) == 0)
|
|
||||||
CheckDlgButton(hdlg, IDC_PG62, 1);
|
|
||||||
else
|
|
||||||
CheckDlgButton(hdlg, IDC_PG62, 0);
|
|
||||||
|
|
||||||
|
|
||||||
// CommLog Parameter (this is global)
|
|
||||||
CheckDlgButton(hdlg, IDC_COMMLOG, globals.commlog);
|
|
||||||
|
|
||||||
|
|
||||||
if (lpsetupdlg->fDefault)
|
// Initialize dialog fields
|
||||||
{
|
SetDlgStuff(hdlg, ci);
|
||||||
EnableWindow(GetDlgItem(hdlg, IDC_DSNAME), FALSE);
|
|
||||||
EnableWindow(GetDlgItem(hdlg, IDC_DSNAMETEXT), FALSE);
|
|
||||||
}
|
if (lpsetupdlg->fDefault) {
|
||||||
else
|
EnableWindow(GetDlgItem(hdlg, IDC_DSNAME), FALSE);
|
||||||
SendDlgItemMessage(hdlg, IDC_DSNAME,
|
EnableWindow(GetDlgItem(hdlg, IDC_DSNAMETEXT), FALSE);
|
||||||
EM_LIMITTEXT, (WPARAM)(MAXDSNAME-1), 0L);
|
}
|
||||||
SendDlgItemMessage(hdlg, IDC_DESC,
|
else
|
||||||
EM_LIMITTEXT, (WPARAM)(MAXDESC-1), 0L);
|
SendDlgItemMessage(hdlg, IDC_DSNAME,
|
||||||
return TRUE; // Focus was not set
|
EM_LIMITTEXT, (WPARAM)(MAXDSNAME-1), 0L);
|
||||||
|
|
||||||
|
SendDlgItemMessage(hdlg, IDC_DESC,
|
||||||
|
EM_LIMITTEXT, (WPARAM)(MAXDESC-1), 0L);
|
||||||
|
return TRUE; // Focus was not set
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Process buttons
|
// Process buttons
|
||||||
case WM_COMMAND:
|
case WM_COMMAND:
|
||||||
switch (GET_WM_COMMAND_ID(wParam, lParam)) {
|
|
||||||
// Ensure the OK button is enabled only when a data source name
|
|
||||||
// is entered
|
|
||||||
case IDC_DSNAME:
|
|
||||||
if (GET_WM_COMMAND_CMD(wParam, lParam) == EN_CHANGE)
|
|
||||||
{
|
|
||||||
char szItem[MAXDSNAME]; // Edit control text
|
|
||||||
|
|
||||||
// Enable/disable the OK button
|
switch (GET_WM_COMMAND_ID(wParam, lParam)) {
|
||||||
EnableWindow(GetDlgItem(hdlg, IDOK),
|
// Ensure the OK button is enabled only when a data source name
|
||||||
GetDlgItemText(hdlg, IDC_DSNAME,
|
// is entered
|
||||||
szItem, sizeof(szItem)));
|
case IDC_DSNAME:
|
||||||
return TRUE;
|
if (GET_WM_COMMAND_CMD(wParam, lParam) == EN_CHANGE)
|
||||||
}
|
{
|
||||||
break;
|
char szItem[MAXDSNAME]; // Edit control text
|
||||||
|
|
||||||
// Accept results
|
// Enable/disable the OK button
|
||||||
case IDOK:
|
EnableWindow(GetDlgItem(hdlg, IDOK),
|
||||||
{
|
GetDlgItemText(hdlg, IDC_DSNAME,
|
||||||
LPSETUPDLG lpsetupdlg;
|
szItem, sizeof(szItem)));
|
||||||
|
|
||||||
lpsetupdlg = (LPSETUPDLG)GetWindowLong(hdlg, DWL_USER);
|
return TRUE;
|
||||||
// Retrieve dialog values
|
}
|
||||||
if (!lpsetupdlg->fDefault)
|
break;
|
||||||
GetDlgItemText(hdlg, IDC_DSNAME,
|
|
||||||
lpsetupdlg->aAttr[KEY_DSN].szAttr,
|
|
||||||
sizeof(lpsetupdlg->aAttr[KEY_DSN].szAttr));
|
|
||||||
GetDlgItemText(hdlg, IDC_DESC,
|
|
||||||
lpsetupdlg->aAttr[KEY_DESC].szAttr,
|
|
||||||
sizeof(lpsetupdlg->aAttr[KEY_DESC].szAttr));
|
|
||||||
|
|
||||||
GetDlgItemText(hdlg, IDC_DATABASE,
|
|
||||||
lpsetupdlg->aAttr[KEY_DATABASE].szAttr,
|
|
||||||
sizeof(lpsetupdlg->aAttr[KEY_DATABASE].szAttr));
|
|
||||||
|
|
||||||
GetDlgItemText(hdlg, IDC_PORT,
|
|
||||||
lpsetupdlg->aAttr[KEY_PORT].szAttr,
|
|
||||||
sizeof(lpsetupdlg->aAttr[KEY_PORT].szAttr));
|
|
||||||
|
|
||||||
GetDlgItemText(hdlg, IDC_SERVER,
|
|
||||||
lpsetupdlg->aAttr[KEY_SERVER].szAttr,
|
|
||||||
sizeof(lpsetupdlg->aAttr[KEY_SERVER].szAttr));
|
|
||||||
|
|
||||||
GetDlgItemText(hdlg, IDC_USER,
|
|
||||||
lpsetupdlg->aAttr[KEY_USER].szAttr,
|
|
||||||
sizeof(lpsetupdlg->aAttr[KEY_USER].szAttr));
|
|
||||||
|
|
||||||
GetDlgItemText(hdlg, IDC_PASSWORD,
|
// Accept results
|
||||||
lpsetupdlg->aAttr[KEY_PASSWORD].szAttr,
|
case IDOK:
|
||||||
sizeof(lpsetupdlg->aAttr[KEY_PASSWORD].szAttr));
|
{
|
||||||
|
LPSETUPDLG lpsetupdlg;
|
||||||
if ( IsDlgButtonChecked(hdlg, IDC_PG62))
|
|
||||||
strcpy(lpsetupdlg->aAttr[KEY_PROTOCOL].szAttr, PG62);
|
|
||||||
else
|
|
||||||
lpsetupdlg->aAttr[KEY_PROTOCOL].szAttr[0] = '\0';
|
|
||||||
|
|
||||||
sprintf(lpsetupdlg->aAttr[KEY_READONLY].szAttr, "%d", IsDlgButtonChecked(hdlg, IDC_READONLY));
|
lpsetupdlg = (LPSETUPDLG)GetWindowLong(hdlg, DWL_USER);
|
||||||
|
// Retrieve dialog values
|
||||||
globals.commlog = IsDlgButtonChecked(hdlg, IDC_COMMLOG);
|
if (!lpsetupdlg->fDefault)
|
||||||
|
GetDlgItemText(hdlg, IDC_DSNAME,
|
||||||
|
lpsetupdlg->ci.dsn,
|
||||||
|
sizeof(lpsetupdlg->ci.dsn));
|
||||||
|
|
||||||
|
|
||||||
// Update ODBC.INI
|
// Get Dialog Values
|
||||||
SetDSNAttributes(hdlg, lpsetupdlg);
|
GetDlgStuff(hdlg, &lpsetupdlg->ci);
|
||||||
|
|
||||||
|
// Update ODBC.INI
|
||||||
|
SetDSNAttributes(hdlg, lpsetupdlg);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return to caller
|
// Return to caller
|
||||||
case IDCANCEL:
|
case IDCANCEL:
|
||||||
EndDialog(hdlg, wParam);
|
EndDialog(hdlg, wParam);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Message not processed
|
case IDC_DRIVER:
|
||||||
return FALSE;
|
|
||||||
|
DialogBoxParam(s_hModule, MAKEINTRESOURCE(DLG_OPTIONS_DRV),
|
||||||
|
hdlg, driver_optionsProc, (LPARAM) NULL);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
case IDC_DATASOURCE:
|
||||||
|
{
|
||||||
|
LPSETUPDLG lpsetupdlg;
|
||||||
|
|
||||||
|
lpsetupdlg = (LPSETUPDLG)GetWindowLong(hdlg, DWL_USER);
|
||||||
|
|
||||||
|
DialogBoxParam(s_hModule, MAKEINTRESOURCE(DLG_OPTIONS_DS),
|
||||||
|
hdlg, ds_optionsProc, (LPARAM) &lpsetupdlg->ci);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Message not processed
|
||||||
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -526,11 +320,13 @@ int CALLBACK ConfigDlgProc
|
||||||
--------------------------------------------------------------------------*/
|
--------------------------------------------------------------------------*/
|
||||||
void INTFUNC ParseAttributes(LPCSTR lpszAttributes, LPSETUPDLG lpsetupdlg)
|
void INTFUNC ParseAttributes(LPCSTR lpszAttributes, LPSETUPDLG lpsetupdlg)
|
||||||
{
|
{
|
||||||
LPCSTR lpsz;
|
LPCSTR lpsz;
|
||||||
LPCSTR lpszStart;
|
LPCSTR lpszStart;
|
||||||
char aszKey[MAXKEYLEN];
|
char aszKey[MAXKEYLEN];
|
||||||
int iElement;
|
int cbKey;
|
||||||
int cbKey;
|
char value[MAXPATHLEN];
|
||||||
|
|
||||||
|
memset(&lpsetupdlg->ci, 0, sizeof(ConnInfo));
|
||||||
|
|
||||||
for (lpsz=lpszAttributes; *lpsz; lpsz++)
|
for (lpsz=lpszAttributes; *lpsz; lpsz++)
|
||||||
{ // Extract key name (e.g., DSN), it must be terminated by an equals
|
{ // Extract key name (e.g., DSN), it must be terminated by an equals
|
||||||
|
@ -543,38 +339,26 @@ void INTFUNC ParseAttributes(LPCSTR lpszAttributes, LPSETUPDLG lpsetupdlg)
|
||||||
break; // Valid key found
|
break; // Valid key found
|
||||||
}
|
}
|
||||||
// Determine the key's index in the key table (-1 if not found)
|
// Determine the key's index in the key table (-1 if not found)
|
||||||
iElement = -1;
|
|
||||||
cbKey = lpsz - lpszStart;
|
cbKey = lpsz - lpszStart;
|
||||||
if (cbKey < sizeof(aszKey))
|
if (cbKey < sizeof(aszKey))
|
||||||
{
|
{
|
||||||
register int j;
|
|
||||||
|
|
||||||
_fmemcpy(aszKey, lpszStart, cbKey);
|
_fmemcpy(aszKey, lpszStart, cbKey);
|
||||||
aszKey[cbKey] = '\0';
|
aszKey[cbKey] = '\0';
|
||||||
for (j = 0; *s_aLookup[j].szKey; j++)
|
|
||||||
{
|
|
||||||
if (!lstrcmpi(s_aLookup[j].szKey, aszKey))
|
|
||||||
{
|
|
||||||
iElement = s_aLookup[j].iKey;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Locate end of key value
|
// Locate end of key value
|
||||||
lpszStart = ++lpsz;
|
lpszStart = ++lpsz;
|
||||||
for (; *lpsz; lpsz++);
|
for (; *lpsz; lpsz++);
|
||||||
|
|
||||||
// Save value if key is known
|
|
||||||
// NOTE: This code assumes the szAttr buffers in aAttr have been
|
// lpsetupdlg->aAttr[iElement].fSupplied = TRUE;
|
||||||
// zero initialized
|
_fmemcpy(value, lpszStart, MIN(lpsz-lpszStart+1, MAXPATHLEN));
|
||||||
if (iElement >= 0)
|
|
||||||
{
|
mylog("aszKey='%s', value='%s'\n", aszKey, value);
|
||||||
lpsetupdlg->aAttr[iElement].fSupplied = TRUE;
|
|
||||||
_fmemcpy(lpsetupdlg->aAttr[iElement].szAttr,
|
// Copy the appropriate value to the conninfo
|
||||||
lpszStart,
|
copyAttributes(&lpsetupdlg->ci, aszKey, value);
|
||||||
MIN(lpsz-lpszStart+1, sizeof(lpsetupdlg->aAttr[0].szAttr)-1));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -588,12 +372,12 @@ void INTFUNC ParseAttributes(LPCSTR lpszAttributes, LPSETUPDLG lpsetupdlg)
|
||||||
|
|
||||||
BOOL INTFUNC SetDSNAttributes(HWND hwndParent, LPSETUPDLG lpsetupdlg)
|
BOOL INTFUNC SetDSNAttributes(HWND hwndParent, LPSETUPDLG lpsetupdlg)
|
||||||
{
|
{
|
||||||
LPCSTR lpszDSN; // Pointer to data source name
|
LPCSTR lpszDSN; // Pointer to data source name
|
||||||
|
|
||||||
lpszDSN = lpsetupdlg->aAttr[KEY_DSN].szAttr;
|
lpszDSN = lpsetupdlg->ci.dsn;
|
||||||
|
|
||||||
// Validate arguments
|
// Validate arguments
|
||||||
if (lpsetupdlg->fNewDSN && !*lpsetupdlg->aAttr[KEY_DSN].szAttr)
|
if (lpsetupdlg->fNewDSN && !*lpsetupdlg->ci.dsn)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
// Write the data source name
|
// Write the data source name
|
||||||
|
@ -614,64 +398,11 @@ BOOL INTFUNC SetDSNAttributes(HWND hwndParent, LPSETUPDLG lpsetupdlg)
|
||||||
|
|
||||||
|
|
||||||
// Update ODBC.INI
|
// Update ODBC.INI
|
||||||
// Save the value if the data source is new, if it was edited, or if
|
writeDSNinfo(&lpsetupdlg->ci);
|
||||||
// it was explicitly supplied
|
|
||||||
if (hwndParent || lpsetupdlg->aAttr[KEY_DESC].fSupplied )
|
|
||||||
SQLWritePrivateProfileString(lpszDSN,
|
|
||||||
INI_KDESC,
|
|
||||||
lpsetupdlg->aAttr[KEY_DESC].szAttr,
|
|
||||||
ODBC_INI);
|
|
||||||
|
|
||||||
if (hwndParent || lpsetupdlg->aAttr[KEY_DATABASE].fSupplied )
|
|
||||||
SQLWritePrivateProfileString(lpszDSN,
|
|
||||||
INI_DATABASE,
|
|
||||||
lpsetupdlg->aAttr[KEY_DATABASE].szAttr,
|
|
||||||
ODBC_INI);
|
|
||||||
|
|
||||||
if (hwndParent || lpsetupdlg->aAttr[KEY_PORT].fSupplied )
|
|
||||||
SQLWritePrivateProfileString(lpszDSN,
|
|
||||||
INI_PORT,
|
|
||||||
lpsetupdlg->aAttr[KEY_PORT].szAttr,
|
|
||||||
ODBC_INI);
|
|
||||||
|
|
||||||
if (hwndParent || lpsetupdlg->aAttr[KEY_SERVER].fSupplied )
|
|
||||||
SQLWritePrivateProfileString(lpszDSN,
|
|
||||||
INI_SERVER,
|
|
||||||
lpsetupdlg->aAttr[KEY_SERVER].szAttr,
|
|
||||||
ODBC_INI);
|
|
||||||
|
|
||||||
if (hwndParent || lpsetupdlg->aAttr[KEY_USER].fSupplied )
|
|
||||||
SQLWritePrivateProfileString(lpszDSN,
|
|
||||||
INI_USER,
|
|
||||||
lpsetupdlg->aAttr[KEY_USER].szAttr,
|
|
||||||
ODBC_INI);
|
|
||||||
|
|
||||||
if (hwndParent || lpsetupdlg->aAttr[KEY_PASSWORD].fSupplied )
|
|
||||||
SQLWritePrivateProfileString(lpszDSN,
|
|
||||||
INI_PASSWORD,
|
|
||||||
lpsetupdlg->aAttr[KEY_PASSWORD].szAttr,
|
|
||||||
ODBC_INI);
|
|
||||||
|
|
||||||
if (hwndParent || lpsetupdlg->aAttr[KEY_READONLY].fSupplied )
|
|
||||||
SQLWritePrivateProfileString(lpszDSN,
|
|
||||||
INI_READONLY,
|
|
||||||
lpsetupdlg->aAttr[KEY_READONLY].szAttr,
|
|
||||||
ODBC_INI);
|
|
||||||
|
|
||||||
if (hwndParent || lpsetupdlg->aAttr[KEY_PROTOCOL].fSupplied )
|
|
||||||
SQLWritePrivateProfileString(lpszDSN,
|
|
||||||
INI_PROTOCOL,
|
|
||||||
lpsetupdlg->aAttr[KEY_PROTOCOL].szAttr,
|
|
||||||
ODBC_INI);
|
|
||||||
|
|
||||||
// CommLog Parameter -- write to ODBCINST_INI (for the whole driver)
|
|
||||||
if (hwndParent ) {
|
|
||||||
updateGlobals();
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the data source name has changed, remove the old name
|
// If the data source name has changed, remove the old name
|
||||||
if (lpsetupdlg->aAttr[KEY_DSN].fSupplied &&
|
if (lstrcmpi(lpsetupdlg->szDSN, lpsetupdlg->ci.dsn))
|
||||||
lstrcmpi(lpsetupdlg->szDSN, lpsetupdlg->aAttr[KEY_DSN].szAttr))
|
|
||||||
{
|
{
|
||||||
SQLRemoveDSNFromIni(lpsetupdlg->szDSN);
|
SQLRemoveDSNFromIni(lpsetupdlg->szDSN);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
|
|
||||||
/* Module: socket.c
|
/* Module: socket.c
|
||||||
*
|
*
|
||||||
* Description: This module contains functions for low level socket
|
* Description: This module contains functions for low level socket
|
||||||
* operations (connecting/reading/writing to the backend)
|
* operations (connecting/reading/writing to the backend)
|
||||||
*
|
*
|
||||||
* Classes: SocketClass (Functions prefix: "SOCK_")
|
* Classes: SocketClass (Functions prefix: "SOCK_")
|
||||||
*
|
*
|
||||||
* API functions: none
|
* API functions: none
|
||||||
*
|
*
|
||||||
* Comments: See "notice.txt" for copyright and license information.
|
* Comments: See "notice.txt" for copyright and license information.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "socket.h"
|
#include "socket.h"
|
||||||
|
|
||||||
|
@ -45,8 +45,8 @@ SocketClass *rv;
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
rv->errormsg = NULL;
|
rv->errormsg = NULL;
|
||||||
rv->errornumber = 0;
|
rv->errornumber = 0;
|
||||||
|
|
||||||
rv->reverse = FALSE;
|
rv->reverse = FALSE;
|
||||||
}
|
}
|
||||||
return rv;
|
return rv;
|
||||||
|
@ -77,6 +77,7 @@ SOCK_connect_to(SocketClass *self, unsigned short port, char *hostname)
|
||||||
{
|
{
|
||||||
struct hostent *host;
|
struct hostent *host;
|
||||||
struct sockaddr_in sadr;
|
struct sockaddr_in sadr;
|
||||||
|
unsigned long iaddr;
|
||||||
|
|
||||||
if (self->socket != -1) {
|
if (self->socket != -1) {
|
||||||
self->errornumber = SOCKET_ALREADY_CONNECTED;
|
self->errornumber = SOCKET_ALREADY_CONNECTED;
|
||||||
|
@ -84,15 +85,24 @@ struct sockaddr_in sadr;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
host = gethostbyname(hostname);
|
|
||||||
if (host == NULL) {
|
|
||||||
self->errornumber = SOCKET_HOST_NOT_FOUND;
|
|
||||||
self->errormsg = "Could not resolve hostname.";
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
memset((char *)&sadr, 0, sizeof(sadr));
|
memset((char *)&sadr, 0, sizeof(sadr));
|
||||||
memcpy(&(sadr.sin_addr), host->h_addr, host->h_length);
|
|
||||||
|
/* If it is a valid IP address, use it.
|
||||||
|
Otherwise use hostname lookup.
|
||||||
|
*/
|
||||||
|
iaddr = inet_addr(hostname);
|
||||||
|
if (iaddr == INADDR_NONE) {
|
||||||
|
host = gethostbyname(hostname);
|
||||||
|
if (host == NULL) {
|
||||||
|
self->errornumber = SOCKET_HOST_NOT_FOUND;
|
||||||
|
self->errormsg = "Could not resolve hostname.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
memcpy(&(sadr.sin_addr), host->h_addr, host->h_length);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
memcpy(&(sadr.sin_addr), (struct in_addr *) &iaddr, sizeof(iaddr));
|
||||||
|
|
||||||
sadr.sin_family = AF_INET;
|
sadr.sin_family = AF_INET;
|
||||||
sadr.sin_port = htons(port);
|
sadr.sin_port = htons(port);
|
||||||
|
|
||||||
|
@ -185,15 +195,15 @@ char buf[4];
|
||||||
switch (len) {
|
switch (len) {
|
||||||
case 2:
|
case 2:
|
||||||
SOCK_get_n_char(self, buf, len);
|
SOCK_get_n_char(self, buf, len);
|
||||||
if (self->reverse)
|
if (self->reverse)
|
||||||
return *((unsigned short *) buf);
|
return *((unsigned short *) buf);
|
||||||
else
|
else
|
||||||
return ntohs( *((unsigned short *) buf) );
|
return ntohs( *((unsigned short *) buf) );
|
||||||
|
|
||||||
case 4:
|
case 4:
|
||||||
SOCK_get_n_char(self, buf, len);
|
SOCK_get_n_char(self, buf, len);
|
||||||
if (self->reverse)
|
if (self->reverse)
|
||||||
return *((unsigned int *) buf);
|
return *((unsigned int *) buf);
|
||||||
else
|
else
|
||||||
return ntohl( *((unsigned int *) buf) );
|
return ntohl( *((unsigned int *) buf) );
|
||||||
|
|
||||||
|
@ -202,7 +212,7 @@ char buf[4];
|
||||||
self->errormsg = "Cannot read ints of that length";
|
self->errormsg = "Cannot read ints of that length";
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -211,12 +221,12 @@ SOCK_put_int(SocketClass *self, int value, short len)
|
||||||
unsigned int rv;
|
unsigned int rv;
|
||||||
|
|
||||||
switch (len) {
|
switch (len) {
|
||||||
case 2:
|
case 2:
|
||||||
rv = self->reverse ? value : htons( (unsigned short) value);
|
rv = self->reverse ? value : htons( (unsigned short) value);
|
||||||
SOCK_put_n_char(self, (char *) &rv, 2);
|
SOCK_put_n_char(self, (char *) &rv, 2);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case 4:
|
case 4:
|
||||||
rv = self->reverse ? value : htonl( (unsigned int) value);
|
rv = self->reverse ? value : htonl( (unsigned int) value);
|
||||||
SOCK_put_n_char(self, (char *) &rv, 4);
|
SOCK_put_n_char(self, (char *) &rv, 4);
|
||||||
return;
|
return;
|
||||||
|
@ -251,7 +261,7 @@ SOCK_get_next_byte(SocketClass *self)
|
||||||
// reload the buffer
|
// reload the buffer
|
||||||
|
|
||||||
self->buffer_read_in = 0;
|
self->buffer_read_in = 0;
|
||||||
self->buffer_filled_in = recv(self->socket, (char *)self->buffer_in, globals.socket_buffersize, 0);
|
self->buffer_filled_in = recv(self->socket, (char *)self->buffer_in, globals.socket_buffersize, 0);
|
||||||
|
|
||||||
mylog("read %d, global_socket_buffersize=%d\n", self->buffer_filled_in, globals.socket_buffersize);
|
mylog("read %d, global_socket_buffersize=%d\n", self->buffer_filled_in, globals.socket_buffersize);
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
|
|
||||||
/* File: socket.h
|
/* File: socket.h
|
||||||
*
|
*
|
||||||
* Description: See "socket.c"
|
* Description: See "socket.c"
|
||||||
*
|
*
|
||||||
* Comments: See "notice.txt" for copyright and license information.
|
* Comments: See "notice.txt" for copyright and license information.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __SOCKET_H__
|
#ifndef __SOCKET_H__
|
||||||
#define __SOCKET_H__
|
#define __SOCKET_H__
|
||||||
|
@ -36,8 +36,8 @@ struct SocketClass_ {
|
||||||
SOCKET socket;
|
SOCKET socket;
|
||||||
|
|
||||||
char *errormsg;
|
char *errormsg;
|
||||||
int errornumber;
|
int errornumber;
|
||||||
|
|
||||||
char reverse; /* used to handle Postgres 6.2 protocol (reverse byte order) */
|
char reverse; /* used to handle Postgres 6.2 protocol (reverse byte order) */
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -49,9 +49,9 @@ struct SocketClass_ {
|
||||||
/* error functions */
|
/* error functions */
|
||||||
#define SOCK_get_errcode(self) (self->errornumber)
|
#define SOCK_get_errcode(self) (self->errornumber)
|
||||||
#define SOCK_get_errmsg(self) (self->errormsg)
|
#define SOCK_get_errmsg(self) (self->errormsg)
|
||||||
|
|
||||||
|
|
||||||
/* Socket prototypes */
|
|
||||||
|
/* Socket prototypes */
|
||||||
SocketClass *SOCK_Constructor();
|
SocketClass *SOCK_Constructor();
|
||||||
void SOCK_Destructor(SocketClass *self);
|
void SOCK_Destructor(SocketClass *self);
|
||||||
char SOCK_connect_to(SocketClass *self, unsigned short port, char *hostname);
|
char SOCK_connect_to(SocketClass *self, unsigned short port, char *hostname);
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
|
|
||||||
/* Module: statement.c
|
/* Module: statement.c
|
||||||
*
|
*
|
||||||
* Description: This module contains functions related to creating
|
* Description: This module contains functions related to creating
|
||||||
* and manipulating a statement.
|
* and manipulating a statement.
|
||||||
*
|
*
|
||||||
* Classes: StatementClass (Functions prefix: "SC_")
|
* Classes: StatementClass (Functions prefix: "SC_")
|
||||||
*
|
*
|
||||||
* API functions: SQLAllocStmt, SQLFreeStmt
|
* API functions: SQLAllocStmt, SQLFreeStmt
|
||||||
*
|
*
|
||||||
* Comments: See "notice.txt" for copyright and license information.
|
* Comments: See "notice.txt" for copyright and license information.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "statement.h"
|
#include "statement.h"
|
||||||
#include "bind.h"
|
#include "bind.h"
|
||||||
|
@ -23,8 +23,25 @@
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <sql.h>
|
#include <sql.h>
|
||||||
|
|
||||||
extern GLOBAL_VALUES globals;
|
extern GLOBAL_VALUES globals;
|
||||||
|
|
||||||
|
/* Map sql commands to statement types */
|
||||||
|
static struct {
|
||||||
|
int type;
|
||||||
|
char *s;
|
||||||
|
} Statement_Type[] = {
|
||||||
|
{ STMT_TYPE_SELECT, "SELECT" },
|
||||||
|
{ STMT_TYPE_INSERT, "INSERT" },
|
||||||
|
{ STMT_TYPE_UPDATE, "UPDATE" },
|
||||||
|
{ STMT_TYPE_DELETE, "DELETE" },
|
||||||
|
{ STMT_TYPE_CREATE, "CREATE" },
|
||||||
|
{ STMT_TYPE_ALTER, "ALTER" },
|
||||||
|
{ STMT_TYPE_DROP, "DROP" },
|
||||||
|
{ STMT_TYPE_GRANT, "GRANT" },
|
||||||
|
{ STMT_TYPE_REVOKE, "REVOKE" },
|
||||||
|
{ 0, NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
RETCODE SQL_API SQLAllocStmt(HDBC hdbc,
|
RETCODE SQL_API SQLAllocStmt(HDBC hdbc,
|
||||||
HSTMT FAR *phstmt)
|
HSTMT FAR *phstmt)
|
||||||
|
@ -103,7 +120,7 @@ StatementClass *stmt = (StatementClass *) hstmt;
|
||||||
// errormsg passed in above
|
// errormsg passed in above
|
||||||
return SQL_ERROR;
|
return SQL_ERROR;
|
||||||
|
|
||||||
} else if(fOption == SQL_RESET_PARAMS) {
|
} else if(fOption == SQL_RESET_PARAMS) {
|
||||||
SC_free_params(stmt, STMT_FREE_PARAMS_ALL);
|
SC_free_params(stmt, STMT_FREE_PARAMS_ALL);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
@ -133,21 +150,28 @@ StatementClass *rv;
|
||||||
rv->prepare = FALSE;
|
rv->prepare = FALSE;
|
||||||
rv->status = STMT_ALLOCATED;
|
rv->status = STMT_ALLOCATED;
|
||||||
rv->maxRows = 0; // driver returns all rows
|
rv->maxRows = 0; // driver returns all rows
|
||||||
|
rv->rowset_size = 1;
|
||||||
|
rv->scroll_concurrency = SQL_CONCUR_READ_ONLY;
|
||||||
|
rv->cursor_type = SQL_CURSOR_FORWARD_ONLY;
|
||||||
rv->errormsg = NULL;
|
rv->errormsg = NULL;
|
||||||
rv->errornumber = 0;
|
rv->errornumber = 0;
|
||||||
rv->errormsg_created = FALSE;
|
rv->errormsg_created = FALSE;
|
||||||
rv->statement = NULL;
|
rv->statement = NULL;
|
||||||
rv->stmt_with_params[0] = '\0';
|
rv->stmt_with_params[0] = '\0';
|
||||||
rv->statement_type = STMT_TYPE_UNKNOWN;
|
rv->statement_type = STMT_TYPE_UNKNOWN;
|
||||||
rv->bindings = NULL;
|
rv->bindings = NULL;
|
||||||
rv->bindings_allocated = 0;
|
rv->bindings_allocated = 0;
|
||||||
rv->parameters_allocated = 0;
|
rv->parameters_allocated = 0;
|
||||||
rv->parameters = 0;
|
rv->parameters = 0;
|
||||||
rv->currTuple = -1;
|
rv->currTuple = -1;
|
||||||
|
rv->current_col = -1;
|
||||||
rv->result = 0;
|
rv->result = 0;
|
||||||
rv->data_at_exec = -1;
|
rv->data_at_exec = -1;
|
||||||
rv->current_exec_param = -1;
|
rv->current_exec_param = -1;
|
||||||
rv->put_data = FALSE;
|
rv->put_data = FALSE;
|
||||||
|
rv->lobj_fd = -1;
|
||||||
|
rv->internal = FALSE;
|
||||||
|
rv->cursor_name[0] = '\0';
|
||||||
}
|
}
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
@ -172,9 +196,9 @@ SC_Destructor(StatementClass *self)
|
||||||
|
|
||||||
if (self->statement)
|
if (self->statement)
|
||||||
free(self->statement);
|
free(self->statement);
|
||||||
|
|
||||||
SC_free_params(self, STMT_FREE_PARAMS_ALL);
|
SC_free_params(self, STMT_FREE_PARAMS_ALL);
|
||||||
|
|
||||||
/* the memory pointed to by the bindings is not deallocated by the driver */
|
/* the memory pointed to by the bindings is not deallocated by the driver */
|
||||||
/* by by the application that uses that driver, so we don't have to care */
|
/* by by the application that uses that driver, so we don't have to care */
|
||||||
/* about that here. */
|
/* about that here. */
|
||||||
|
@ -183,62 +207,63 @@ SC_Destructor(StatementClass *self)
|
||||||
|
|
||||||
free(self);
|
free(self);
|
||||||
|
|
||||||
|
mylog("SC_Destructor: EXIT\n");
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Free parameters and free the memory from the
|
/* Free parameters and free the memory from the
|
||||||
data-at-execution parameters that was allocated in SQLPutData.
|
data-at-execution parameters that was allocated in SQLPutData.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
SC_free_params(StatementClass *self, char option)
|
SC_free_params(StatementClass *self, char option)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if( ! self->parameters)
|
mylog("SC_free_params: ENTER, self=%d\n", self);
|
||||||
return;
|
|
||||||
|
if( ! self->parameters)
|
||||||
for (i = 0; i < self->parameters_allocated; i++) {
|
return;
|
||||||
if (self->parameters[i].data_at_exec == TRUE) {
|
|
||||||
|
for (i = 0; i < self->parameters_allocated; i++) {
|
||||||
if (self->parameters[i].EXEC_used) {
|
if (self->parameters[i].data_at_exec == TRUE) {
|
||||||
free(self->parameters[i].EXEC_used);
|
|
||||||
self->parameters[i].EXEC_used = NULL;
|
if (self->parameters[i].EXEC_used) {
|
||||||
}
|
free(self->parameters[i].EXEC_used);
|
||||||
|
self->parameters[i].EXEC_used = NULL;
|
||||||
if (self->parameters[i].EXEC_buffer) {
|
}
|
||||||
free(self->parameters[i].EXEC_buffer);
|
|
||||||
self->parameters[i].EXEC_buffer = NULL;
|
if (self->parameters[i].EXEC_buffer) {
|
||||||
}
|
free(self->parameters[i].EXEC_buffer);
|
||||||
}
|
self->parameters[i].EXEC_buffer = NULL;
|
||||||
}
|
}
|
||||||
self->data_at_exec = -1;
|
}
|
||||||
self->current_exec_param = -1;
|
}
|
||||||
self->put_data = FALSE;
|
self->data_at_exec = -1;
|
||||||
|
self->current_exec_param = -1;
|
||||||
if (option == STMT_FREE_PARAMS_ALL) {
|
self->put_data = FALSE;
|
||||||
free(self->parameters);
|
|
||||||
self->parameters = NULL;
|
if (option == STMT_FREE_PARAMS_ALL) {
|
||||||
self->parameters_allocated = 0;
|
free(self->parameters);
|
||||||
}
|
self->parameters = NULL;
|
||||||
}
|
self->parameters_allocated = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
mylog("SC_free_params: EXIT\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
statement_type(char *statement)
|
statement_type(char *statement)
|
||||||
{
|
{
|
||||||
if(strnicmp(statement, "SELECT", 6) == 0)
|
int i;
|
||||||
return STMT_TYPE_SELECT;
|
|
||||||
|
|
||||||
else if(strnicmp(statement, "INSERT", 6) == 0)
|
for (i = 0; Statement_Type[i].s; i++)
|
||||||
return STMT_TYPE_INSERT;
|
if ( ! strnicmp(statement, Statement_Type[i].s, strlen(Statement_Type[i].s)))
|
||||||
|
return Statement_Type[i].type;
|
||||||
|
|
||||||
else if(strnicmp(statement, "UPDATE", 6) == 0)
|
return STMT_TYPE_OTHER;
|
||||||
return STMT_TYPE_UPDATE;
|
|
||||||
|
|
||||||
else if(strnicmp(statement, "DELETE", 6) == 0)
|
|
||||||
return STMT_TYPE_DELETE;
|
|
||||||
|
|
||||||
else
|
|
||||||
return STMT_TYPE_OTHER;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Called from SQLPrepare if STMT_PREMATURE, or
|
/* Called from SQLPrepare if STMT_PREMATURE, or
|
||||||
|
@ -298,16 +323,21 @@ ConnectionClass *conn;
|
||||||
}
|
}
|
||||||
|
|
||||||
self->status = STMT_READY;
|
self->status = STMT_READY;
|
||||||
|
self->manual_result = FALSE; // very important
|
||||||
|
|
||||||
self->currTuple = -1;
|
self->currTuple = -1;
|
||||||
|
self->current_col = -1;
|
||||||
|
|
||||||
self->errormsg = NULL;
|
self->errormsg = NULL;
|
||||||
self->errornumber = 0;
|
self->errornumber = 0;
|
||||||
self->errormsg_created = FALSE;
|
self->errormsg_created = FALSE;
|
||||||
|
|
||||||
// Free any data at exec params before the statement is executed
|
self->lobj_fd = -1;
|
||||||
// again. If not, then there will be a memory leak when
|
|
||||||
// the next SQLParamData/SQLPutData is called.
|
// Free any data at exec params before the statement is executed
|
||||||
SC_free_params(self, STMT_FREE_PARAMS_DATA_AT_EXEC_ONLY);
|
// again. If not, then there will be a memory leak when
|
||||||
|
// the next SQLParamData/SQLPutData is called.
|
||||||
|
SC_free_params(self, STMT_FREE_PARAMS_DATA_AT_EXEC_ONLY);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
@ -414,132 +444,143 @@ char rv;
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
RETCODE SC_execute(StatementClass *self)
|
RETCODE SC_execute(StatementClass *self)
|
||||||
{
|
{
|
||||||
ConnectionClass *conn;
|
ConnectionClass *conn;
|
||||||
QResultClass *res;
|
QResultClass *res;
|
||||||
char ok, was_ok, was_nonfatal;
|
char ok, was_ok, was_nonfatal;
|
||||||
Int2 oldstatus, numcols;
|
Int2 oldstatus, numcols;
|
||||||
|
|
||||||
|
|
||||||
conn = SC_get_conn(self);
|
conn = SC_get_conn(self);
|
||||||
|
|
||||||
/* Begin a transaction if one is not already in progress */
|
/* Begin a transaction if one is not already in progress */
|
||||||
/* The reason is because we can't use declare/fetch cursors without
|
/* The reason is because we can't use declare/fetch cursors without
|
||||||
starting a transaction first.
|
starting a transaction first.
|
||||||
*/
|
*/
|
||||||
|
if ( ! CC_is_in_trans(conn) && (globals.use_declarefetch || STMT_UPDATE(self))) {
|
||||||
if ( ! CC_is_in_trans(conn)) {
|
|
||||||
mylog(" about to begin a transaction on statement = %u\n", self);
|
mylog(" about to begin a transaction on statement = %u\n", self);
|
||||||
res = CC_send_query(conn, "BEGIN", NULL, NULL);
|
res = CC_send_query(conn, "BEGIN", NULL, NULL);
|
||||||
if ( ! res) {
|
if ( ! res) {
|
||||||
self->errormsg = "Could not begin a transaction";
|
self->errormsg = "Could not begin a transaction";
|
||||||
self->errornumber = STMT_EXEC_ERROR;
|
self->errornumber = STMT_EXEC_ERROR;
|
||||||
return SQL_ERROR;
|
return SQL_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
ok = QR_command_successful(res);
|
ok = QR_command_successful(res);
|
||||||
|
|
||||||
mylog("SQLExecute: ok = %d, status = %d\n", ok, QR_get_status(res));
|
mylog("SQLExecute: ok = %d, status = %d\n", ok, QR_get_status(res));
|
||||||
|
|
||||||
QR_Destructor(res);
|
QR_Destructor(res);
|
||||||
|
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
self->errormsg = "Could not begin a transaction";
|
self->errormsg = "Could not begin a transaction";
|
||||||
self->errornumber = STMT_EXEC_ERROR;
|
self->errornumber = STMT_EXEC_ERROR;
|
||||||
return SQL_ERROR;
|
return SQL_ERROR;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
CC_set_in_trans(conn);
|
CC_set_in_trans(conn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
oldstatus = conn->status;
|
oldstatus = conn->status;
|
||||||
conn->status = CONN_EXECUTING;
|
conn->status = CONN_EXECUTING;
|
||||||
self->status = STMT_EXECUTING;
|
self->status = STMT_EXECUTING;
|
||||||
|
|
||||||
|
|
||||||
// If its a SELECT statement, use a cursor.
|
// If its a SELECT statement, use a cursor.
|
||||||
// Note that the declare cursor has already been prepended to the statement
|
// Note that the declare cursor has already been prepended to the statement
|
||||||
// in copy_statement...
|
// in copy_statement...
|
||||||
if (self->statement_type == STMT_TYPE_SELECT) {
|
if (self->statement_type == STMT_TYPE_SELECT) {
|
||||||
|
|
||||||
char cursor[32];
|
char fetch[128];
|
||||||
char fetch[64];
|
|
||||||
|
mylog(" Sending SELECT statement on stmt=%u, cursor_name='%s'\n", self, self->cursor_name);
|
||||||
sprintf(cursor, "C%u", self);
|
|
||||||
|
/* send the declare/select */
|
||||||
mylog(" Sending SELECT statement on stmt=%u\n", self);
|
self->result = CC_send_query(conn, self->stmt_with_params, NULL, NULL);
|
||||||
|
|
||||||
/* send the declare/select */
|
if (globals.use_declarefetch && self->result != NULL) {
|
||||||
self->result = CC_send_query(conn, self->stmt_with_params, NULL, NULL);
|
/* That worked, so now send the fetch to start getting data back */
|
||||||
if (self->result != NULL) {
|
sprintf(fetch, "fetch %d in %s", globals.fetch_max, self->cursor_name);
|
||||||
/* That worked, so now send the fetch to start getting data back */
|
|
||||||
sprintf(fetch, "fetch %d in %s", globals.fetch_max, cursor);
|
// Save the cursor in the result for later use
|
||||||
|
self->result = CC_send_query( conn, fetch, NULL, self->cursor_name);
|
||||||
// Save the cursor in the result for later use
|
}
|
||||||
self->result = CC_send_query( conn, fetch, NULL, cursor);
|
|
||||||
}
|
mylog(" done sending the query:\n");
|
||||||
|
|
||||||
mylog(" done sending the query:\n");
|
|
||||||
|
|
||||||
}
|
}
|
||||||
else { // not a SELECT statement so don't use a cursor
|
else { // not a SELECT statement so don't use a cursor
|
||||||
mylog(" its NOT a select statement: stmt=%u\n", self);
|
mylog(" its NOT a select statement: stmt=%u\n", self);
|
||||||
self->result = CC_send_query(conn, self->stmt_with_params, NULL, NULL);
|
self->result = CC_send_query(conn, self->stmt_with_params, NULL, NULL);
|
||||||
|
|
||||||
// If we are in autocommit, we must send the commit.
|
// If we are in autocommit, we must send the commit.
|
||||||
if (CC_is_in_autocommit(conn)) {
|
if (CC_is_in_autocommit(conn) && STMT_UPDATE(self)) {
|
||||||
CC_send_query(conn, "COMMIT", NULL, NULL);
|
CC_send_query(conn, "COMMIT", NULL, NULL);
|
||||||
CC_set_no_trans(conn);
|
CC_set_no_trans(conn);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
conn->status = oldstatus;
|
conn->status = oldstatus;
|
||||||
self->status = STMT_FINISHED;
|
self->status = STMT_FINISHED;
|
||||||
|
|
||||||
/* Check the status of the result */
|
/* Check the status of the result */
|
||||||
if (self->result) {
|
if (self->result) {
|
||||||
|
|
||||||
was_ok = QR_command_successful(self->result);
|
was_ok = QR_command_successful(self->result);
|
||||||
was_nonfatal = QR_command_nonfatal(self->result);
|
was_nonfatal = QR_command_nonfatal(self->result);
|
||||||
|
|
||||||
if ( was_ok)
|
if ( was_ok)
|
||||||
self->errornumber = STMT_OK;
|
self->errornumber = STMT_OK;
|
||||||
else
|
else
|
||||||
self->errornumber = was_nonfatal ? STMT_INFO_ONLY : STMT_ERROR_TAKEN_FROM_BACKEND;
|
self->errornumber = was_nonfatal ? STMT_INFO_ONLY : STMT_ERROR_TAKEN_FROM_BACKEND;
|
||||||
|
|
||||||
self->currTuple = -1; /* set cursor before the first tuple in the list */
|
self->currTuple = -1; /* set cursor before the first tuple in the list */
|
||||||
|
self->current_col = -1;
|
||||||
/* see if the query did return any result columns */
|
|
||||||
numcols = QR_NumResultCols(self->result);
|
/* see if the query did return any result columns */
|
||||||
|
numcols = QR_NumResultCols(self->result);
|
||||||
/* now allocate the array to hold the binding info */
|
|
||||||
if (numcols > 0) {
|
/* now allocate the array to hold the binding info */
|
||||||
extend_bindings(self, numcols);
|
if (numcols > 0) {
|
||||||
if (self->bindings == NULL) {
|
extend_bindings(self, numcols);
|
||||||
self->errornumber = STMT_NO_MEMORY_ERROR;
|
if (self->bindings == NULL) {
|
||||||
self->errormsg = "Could not get enough free memory to store the binding information";
|
self->errornumber = STMT_NO_MEMORY_ERROR;
|
||||||
return SQL_ERROR;
|
self->errormsg = "Could not get enough free memory to store the binding information";
|
||||||
}
|
return SQL_ERROR;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else { /* Bad Error -- The error message will be in the Connection */
|
|
||||||
|
} else { /* Bad Error -- The error message will be in the Connection */
|
||||||
self->errornumber = STMT_EXEC_ERROR;
|
|
||||||
self->errormsg = "Error while executing the query";
|
if (self->statement_type == STMT_TYPE_CREATE) {
|
||||||
|
self->errornumber = STMT_CREATE_TABLE_ERROR;
|
||||||
CC_abort(conn);
|
self->errormsg = "Error creating the table";
|
||||||
}
|
/* This would allow the table to already exists, thus appending
|
||||||
|
rows to it. BUT, if the table didn't have the same attributes,
|
||||||
if (self->errornumber == STMT_OK)
|
it would fail.
|
||||||
return SQL_SUCCESS;
|
return SQL_SUCCESS_WITH_INFO;
|
||||||
|
*/
|
||||||
else if (self->errornumber == STMT_INFO_ONLY)
|
}
|
||||||
return SQL_SUCCESS_WITH_INFO;
|
else {
|
||||||
|
self->errornumber = STMT_EXEC_ERROR;
|
||||||
else
|
self->errormsg = "Error while executing the query";
|
||||||
return SQL_ERROR;
|
}
|
||||||
}
|
CC_abort(conn);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self->errornumber == STMT_OK)
|
||||||
|
return SQL_SUCCESS;
|
||||||
|
|
||||||
|
else if (self->errornumber == STMT_INFO_ONLY)
|
||||||
|
return SQL_SUCCESS_WITH_INFO;
|
||||||
|
|
||||||
|
else
|
||||||
|
return SQL_ERROR;
|
||||||
|
}
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
|
|
||||||
/* File: statement.h
|
/* File: statement.h
|
||||||
*
|
*
|
||||||
* Description: See "statement.c"
|
* Description: See "statement.c"
|
||||||
*
|
*
|
||||||
* Comments: See "notice.txt" for copyright and license information.
|
* Comments: See "notice.txt" for copyright and license information.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __STATEMENT_H__
|
#ifndef __STATEMENT_H__
|
||||||
#define __STATEMENT_H__
|
#define __STATEMENT_H__
|
||||||
|
@ -45,18 +45,26 @@ typedef enum {
|
||||||
#define STMT_RESTRICTED_DATA_TYPE_ERROR 14
|
#define STMT_RESTRICTED_DATA_TYPE_ERROR 14
|
||||||
#define STMT_INVALID_CURSOR_STATE_ERROR 15
|
#define STMT_INVALID_CURSOR_STATE_ERROR 15
|
||||||
#define STMT_OPTION_VALUE_CHANGED 16
|
#define STMT_OPTION_VALUE_CHANGED 16
|
||||||
|
#define STMT_CREATE_TABLE_ERROR 17
|
||||||
|
#define STMT_NO_CURSOR_NAME 18
|
||||||
|
#define STMT_INVALID_CURSOR_NAME 19
|
||||||
|
|
||||||
/* statement types */
|
/* statement types */
|
||||||
#define STMT_TYPE_SELECT 0
|
enum {
|
||||||
#define STMT_TYPE_INSERT 1
|
STMT_TYPE_UNKNOWN = -2,
|
||||||
#define STMT_TYPE_UPDATE 2
|
STMT_TYPE_OTHER = -1,
|
||||||
#define STMT_TYPE_DELETE 3
|
STMT_TYPE_SELECT = 0,
|
||||||
#define STMT_TYPE_OTHER 4
|
STMT_TYPE_INSERT,
|
||||||
#define STMT_TYPE_UNKNOWN 666 // 'unknown' means we don't have the statement yet,
|
STMT_TYPE_UPDATE,
|
||||||
// or haven't looked at it to see what type it is.
|
STMT_TYPE_DELETE,
|
||||||
// 'other' means we looked, but couldn't tell.
|
STMT_TYPE_CREATE,
|
||||||
|
STMT_TYPE_ALTER,
|
||||||
|
STMT_TYPE_DROP,
|
||||||
|
STMT_TYPE_GRANT,
|
||||||
|
STMT_TYPE_REVOKE,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define STMT_UPDATE(stmt) (stmt->statement_type > STMT_TYPE_SELECT)
|
||||||
|
|
||||||
/******** Statement Handle ***********/
|
/******** Statement Handle ***********/
|
||||||
struct StatementClass_ {
|
struct StatementClass_ {
|
||||||
|
@ -68,6 +76,9 @@ struct StatementClass_ {
|
||||||
char *errormsg;
|
char *errormsg;
|
||||||
int errornumber;
|
int errornumber;
|
||||||
int maxRows;
|
int maxRows;
|
||||||
|
int rowset_size;
|
||||||
|
int cursor_type;
|
||||||
|
int scroll_concurrency;
|
||||||
|
|
||||||
/* information on bindings */
|
/* information on bindings */
|
||||||
BindInfoClass *bindings; /* array to store the binding information */
|
BindInfoClass *bindings; /* array to store the binding information */
|
||||||
|
@ -78,30 +89,35 @@ struct StatementClass_ {
|
||||||
ParameterInfoClass *parameters;
|
ParameterInfoClass *parameters;
|
||||||
|
|
||||||
Int4 currTuple;
|
Int4 currTuple;
|
||||||
|
int current_col; /* current column for GetData -- used to handle multiple calls */
|
||||||
|
int lobj_fd; /* fd of the current large object */
|
||||||
|
|
||||||
char *statement; /* if non--null pointer to the SQL statement that has been executed */
|
char *statement; /* if non--null pointer to the SQL statement that has been executed */
|
||||||
|
|
||||||
int statement_type; /* According to the defines above */
|
int statement_type; /* According to the defines above */
|
||||||
int data_at_exec; /* Number of params needing SQLPutData */
|
int data_at_exec; /* Number of params needing SQLPutData */
|
||||||
int current_exec_param; /* The current parameter for SQLPutData */
|
int current_exec_param; /* The current parameter for SQLPutData */
|
||||||
|
|
||||||
char put_data; /* Has SQLPutData been called yet? */
|
char put_data; /* Has SQLPutData been called yet? */
|
||||||
|
|
||||||
char errormsg_created; /* has an informative error msg been created? */
|
char errormsg_created; /* has an informative error msg been created? */
|
||||||
char manual_result; /* Is the statement result manually built? */
|
char manual_result; /* Is the statement result manually built? */
|
||||||
char prepare; /* is this statement a prepared statement or direct */
|
char prepare; /* is this statement a prepared statement or direct */
|
||||||
|
|
||||||
char stmt_with_params[65536 /* MAX_STATEMENT_LEN */]; /* statement after parameter substitution */
|
char internal; /* Is this statement being called internally? */
|
||||||
|
|
||||||
|
char cursor_name[32];
|
||||||
|
char stmt_with_params[65536 /* MAX_STATEMENT_LEN */]; /* statement after parameter substitution */
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#define SC_get_conn(a) (a->hdbc)
|
#define SC_get_conn(a) (a->hdbc)
|
||||||
#define SC_get_Result(a) (a->result);
|
#define SC_get_Result(a) (a->result);
|
||||||
|
|
||||||
/* options for SC_free_params() */
|
/* options for SC_free_params() */
|
||||||
#define STMT_FREE_PARAMS_ALL 0
|
#define STMT_FREE_PARAMS_ALL 0
|
||||||
#define STMT_FREE_PARAMS_DATA_AT_EXEC_ONLY 1
|
#define STMT_FREE_PARAMS_DATA_AT_EXEC_ONLY 1
|
||||||
|
|
||||||
/* Statement prototypes */
|
/* Statement prototypes */
|
||||||
StatementClass *SC_Constructor();
|
StatementClass *SC_Constructor();
|
||||||
char SC_Destructor(StatementClass *self);
|
char SC_Destructor(StatementClass *self);
|
||||||
|
@ -113,7 +129,7 @@ char SC_recycle_statement(StatementClass *self);
|
||||||
void SC_clear_error(StatementClass *self);
|
void SC_clear_error(StatementClass *self);
|
||||||
char SC_get_error(StatementClass *self, int *number, char **message);
|
char SC_get_error(StatementClass *self, int *number, char **message);
|
||||||
char *SC_create_errormsg(StatementClass *self);
|
char *SC_create_errormsg(StatementClass *self);
|
||||||
RETCODE SC_execute(StatementClass *stmt);
|
RETCODE SC_execute(StatementClass *stmt);
|
||||||
void SC_free_params(StatementClass *self, char option);
|
void SC_free_params(StatementClass *self, char option);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,19 +1,19 @@
|
||||||
|
|
||||||
/* Module: tuple.c
|
/* Module: tuple.c
|
||||||
*
|
*
|
||||||
* Description: This module contains functions for setting the data for individual
|
* Description: This module contains functions for setting the data for individual
|
||||||
* fields (TupleField structure) of a manual result set.
|
* fields (TupleField structure) of a manual result set.
|
||||||
*
|
*
|
||||||
* Important Note: These functions are ONLY used in building manual result sets for
|
* Important Note: These functions are ONLY used in building manual result sets for
|
||||||
* info functions (SQLTables, SQLColumns, etc.)
|
* info functions (SQLTables, SQLColumns, etc.)
|
||||||
*
|
*
|
||||||
* Classes: n/a
|
* Classes: n/a
|
||||||
*
|
*
|
||||||
* API functions: none
|
* API functions: none
|
||||||
*
|
*
|
||||||
* Comments: See "notice.txt" for copyright and license information.
|
* Comments: See "notice.txt" for copyright and license information.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "tuple.h"
|
#include "tuple.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
|
@ -1,27 +1,27 @@
|
||||||
|
|
||||||
/* File: tuple.h
|
/* File: tuple.h
|
||||||
*
|
*
|
||||||
* Description: See "tuple.c"
|
* Description: See "tuple.c"
|
||||||
*
|
*
|
||||||
* Important NOTE: The TupleField structure is used both to hold backend data and
|
* Important NOTE: The TupleField structure is used both to hold backend data and
|
||||||
* manual result set data. The "set_" functions and the TupleNode
|
* manual result set data. The "set_" functions and the TupleNode
|
||||||
* structure are only used for manual result sets by info routines.
|
* structure are only used for manual result sets by info routines.
|
||||||
*
|
*
|
||||||
* Comments: See "notice.txt" for copyright and license information.
|
* Comments: See "notice.txt" for copyright and license information.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __TUPLE_H__
|
#ifndef __TUPLE_H__
|
||||||
#define __TUPLE_H__
|
#define __TUPLE_H__
|
||||||
|
|
||||||
#include "psqlodbc.h"
|
#include "psqlodbc.h"
|
||||||
|
|
||||||
/* Used by backend data AND manual result sets */
|
/* Used by backend data AND manual result sets */
|
||||||
struct TupleField_ {
|
struct TupleField_ {
|
||||||
Int4 len; /* length of the current Tuple */
|
Int4 len; /* length of the current Tuple */
|
||||||
void *value; /* an array representing the value */
|
void *value; /* an array representing the value */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Used ONLY for manual result sets */
|
/* Used ONLY for manual result sets */
|
||||||
struct TupleNode_ {
|
struct TupleNode_ {
|
||||||
struct TupleNode_ *prev, *next;
|
struct TupleNode_ *prev, *next;
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
|
|
||||||
/* Module: tuplelist.c
|
/* Module: tuplelist.c
|
||||||
*
|
*
|
||||||
* Description: This module contains functions for creating a manual result set
|
* Description: This module contains functions for creating a manual result set
|
||||||
* (the TupleList) and retrieving data from it for a specific row/column.
|
* (the TupleList) and retrieving data from it for a specific row/column.
|
||||||
*
|
*
|
||||||
* Classes: TupleListClass (Functions prefix: "TL_")
|
* Classes: TupleListClass (Functions prefix: "TL_")
|
||||||
*
|
*
|
||||||
* API functions: none
|
* API functions: none
|
||||||
*
|
*
|
||||||
* Comments: See "notice.txt" for copyright and license information.
|
* Comments: See "notice.txt" for copyright and license information.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
|
@ -21,8 +21,8 @@ TupleListClass *
|
||||||
TL_Constructor(UInt4 fieldcnt)
|
TL_Constructor(UInt4 fieldcnt)
|
||||||
{
|
{
|
||||||
TupleListClass *rv;
|
TupleListClass *rv;
|
||||||
|
|
||||||
mylog("in TL_Constructor\n");
|
mylog("in TL_Constructor\n");
|
||||||
|
|
||||||
rv = (TupleListClass *) malloc(sizeof(TupleListClass));
|
rv = (TupleListClass *) malloc(sizeof(TupleListClass));
|
||||||
if (rv) {
|
if (rv) {
|
||||||
|
@ -35,8 +35,8 @@ TupleListClass *rv;
|
||||||
rv->last_indexed = -1;
|
rv->last_indexed = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
mylog("exit TL_Constructor\n");
|
mylog("exit TL_Constructor\n");
|
||||||
|
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,8 +46,8 @@ TL_Destructor(TupleListClass *self)
|
||||||
int lf;
|
int lf;
|
||||||
TupleNode *node, *tp;
|
TupleNode *node, *tp;
|
||||||
|
|
||||||
mylog("TupleList: in DESTRUCTOR\n");
|
mylog("TupleList: in DESTRUCTOR\n");
|
||||||
|
|
||||||
node = self->list_start;
|
node = self->list_start;
|
||||||
while(node != NULL) {
|
while(node != NULL) {
|
||||||
for (lf=0; lf < self->num_fields; lf++)
|
for (lf=0; lf < self->num_fields; lf++)
|
||||||
|
@ -57,11 +57,11 @@ TupleNode *node, *tp;
|
||||||
tp = node->next;
|
tp = node->next;
|
||||||
free(node);
|
free(node);
|
||||||
node = tp;
|
node = tp;
|
||||||
}
|
}
|
||||||
|
|
||||||
free(self);
|
|
||||||
|
|
||||||
mylog("TupleList: exit DESTRUCTOR\n");
|
free(self);
|
||||||
|
|
||||||
|
mylog("TupleList: exit DESTRUCTOR\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
|
|
||||||
/* File: tuplelist.h
|
/* File: tuplelist.h
|
||||||
*
|
*
|
||||||
* Description: See "tuplelist.c"
|
* Description: See "tuplelist.c"
|
||||||
*
|
*
|
||||||
* Important Note: This structure and its functions are ONLY used in building manual result
|
* Important Note: This structure and its functions are ONLY used in building manual result
|
||||||
* sets for info functions (SQLTables, SQLColumns, etc.)
|
* sets for info functions (SQLTables, SQLColumns, etc.)
|
||||||
*
|
*
|
||||||
* Comments: See "notice.txt" for copyright and license information.
|
* Comments: See "notice.txt" for copyright and license information.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __TUPLELIST_H__
|
#ifndef __TUPLELIST_H__
|
||||||
#define __TUPLELIST_H__
|
#define __TUPLELIST_H__
|
||||||
|
|
Loading…
Reference in New Issue