提交 594e97b7 编写于 作者: B Bruce Momjian

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

protocol. I have left in Tom's SOCK_get_next_byte() fix, and the new
win32.mak file addition.  I have also left in the 'X' connection close
fix.
上级 18b04ae1
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
# #
# GNUMakefile for psqlodbc (Postgres ODBC driver) # GNUMakefile for psqlodbc (Postgres ODBC driver)
# #
# $Header: /cvsroot/pgsql/src/interfaces/odbc/Attic/GNUmakefile,v 1.12 2001/02/10 16:51:40 petere Exp $ # $Header: /cvsroot/pgsql/src/interfaces/odbc/Attic/GNUmakefile,v 1.13 2001/02/14 05:45:38 momjian Exp $
# #
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
...@@ -24,6 +24,7 @@ OBJS = info.o bind.o columninfo.o connection.o convert.o drvconn.o \ ...@@ -24,6 +24,7 @@ OBJS = info.o bind.o columninfo.o connection.o convert.o drvconn.o \
gpps.o tuple.o tuplelist.o dlg_specific.o $(OBJX) gpps.o tuple.o tuplelist.o dlg_specific.o $(OBJX)
SHLIB_LINK = $(filter -lm, $(LIBS)) SHLIB_LINK = $(filter -lm, $(LIBS))
all: all-lib all: all-lib
# Shared library stuff # Shared library stuff
...@@ -32,7 +33,6 @@ include $(top_srcdir)/src/Makefile.shlib ...@@ -32,7 +33,6 @@ include $(top_srcdir)/src/Makefile.shlib
# Symbols must be resolved to the version in the shared library because # Symbols must be resolved to the version in the shared library because
# the driver manager (e.g., iodbc) provides some symbols with the same # the driver manager (e.g., iodbc) provides some symbols with the same
# names and we don't want those. (This issue is probably ELF specific.) # names and we don't want those. (This issue is probably ELF specific.)
LINK.shared += $(shlib_symbolic) LINK.shared += $(shlib_symbolic)
odbc_headers = isql.h isqlext.h iodbc.h odbc_headers = isql.h isqlext.h iodbc.h
......
/* 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.
* *
*/ */
...@@ -33,44 +34,39 @@ ...@@ -33,44 +34,39 @@
#include "sqlext.h" #include "sqlext.h"
#endif #endif
/* Bind parameters on a statement handle */ /* Bind parameters on a statement handle */
RETCODE SQL_API RETCODE SQL_API SQLBindParameter(
SQLBindParameter( HSTMT hstmt,
HSTMT hstmt, UWORD ipar,
UWORD ipar, SWORD fParamType,
SWORD fParamType, SWORD fCType,
SWORD fCType, SWORD fSqlType,
SWORD fSqlType, UDWORD cbColDef,
UDWORD cbColDef, SWORD ibScale,
SWORD ibScale, PTR rgbValue,
PTR rgbValue, SDWORD cbValueMax,
SDWORD cbValueMax, SDWORD FAR *pcbValue)
SDWORD FAR *pcbValue)
{ {
StatementClass *stmt = (StatementClass *) hstmt; StatementClass *stmt = (StatementClass *) hstmt;
static char *func = "SQLBindParameter"; static char *func="SQLBindParameter";
mylog("%s: entering...\n", func); mylog( "%s: entering...\n", func);
if (!stmt) if( ! stmt) {
{
SC_log_error(func, "", NULL); SC_log_error(func, "", NULL);
return SQL_INVALID_HANDLE; return SQL_INVALID_HANDLE;
} }
if (stmt->parameters_allocated < ipar) if(stmt->parameters_allocated < ipar) {
{
ParameterInfoClass *old_parameters; ParameterInfoClass *old_parameters;
int i, int i, old_parameters_allocated;
old_parameters_allocated;
old_parameters = stmt->parameters; old_parameters = stmt->parameters;
old_parameters_allocated = stmt->parameters_allocated; old_parameters_allocated = stmt->parameters_allocated;
stmt->parameters = (ParameterInfoClass *) malloc(sizeof(ParameterInfoClass) * (ipar)); stmt->parameters = (ParameterInfoClass *) malloc(sizeof(ParameterInfoClass)*(ipar));
if (!stmt->parameters) if ( ! stmt->parameters) {
{
stmt->errornumber = STMT_NO_MEMORY_ERROR; stmt->errornumber = STMT_NO_MEMORY_ERROR;
stmt->errormsg = "Could not allocate memory for statement parameters"; stmt->errormsg = "Could not allocate memory for statement parameters";
SC_log_error(func, "", stmt); SC_log_error(func, "", stmt);
...@@ -80,23 +76,18 @@ SQLBindParameter( ...@@ -80,23 +76,18 @@ SQLBindParameter(
stmt->parameters_allocated = ipar; stmt->parameters_allocated = ipar;
/* copy the old parameters over */ /* copy the old parameters over */
for (i = 0; i < old_parameters_allocated; i++) for(i = 0; i < old_parameters_allocated; i++) {
{
/* a structure copy should work */ /* a structure copy should work */
stmt->parameters[i] = old_parameters[i]; stmt->parameters[i] = old_parameters[i];
} }
/* get rid of the old parameters, if there were any */ /* get rid of the old parameters, if there were any */
if (old_parameters) if(old_parameters)
free(old_parameters); free(old_parameters);
/* /* zero out the newly allocated parameters (in case they skipped some, */
* zero out the newly allocated parameters (in case they skipped
* some,
*/
/* so we don't accidentally try to use them later) */ /* so we don't accidentally try to use them later) */
for (; i < stmt->parameters_allocated; i++) for(; i < stmt->parameters_allocated; i++) {
{
stmt->parameters[i].buflen = 0; stmt->parameters[i].buflen = 0;
stmt->parameters[i].buffer = 0; stmt->parameters[i].buffer = 0;
stmt->parameters[i].used = 0; stmt->parameters[i].used = 0;
...@@ -112,8 +103,7 @@ SQLBindParameter( ...@@ -112,8 +103,7 @@ SQLBindParameter(
} }
} }
ipar--; /* use zero based column numbers for the ipar--; /* use zero based column numbers for the below part */
* below part */
/* store the given info */ /* store the given info */
stmt->parameters[ipar].buflen = cbValueMax; stmt->parameters[ipar].buflen = cbValueMax;
...@@ -125,83 +115,74 @@ SQLBindParameter( ...@@ -125,83 +115,74 @@ SQLBindParameter(
stmt->parameters[ipar].precision = cbColDef; stmt->parameters[ipar].precision = cbColDef;
stmt->parameters[ipar].scale = ibScale; stmt->parameters[ipar].scale = ibScale;
/* /* If rebinding a parameter that had data-at-exec stuff in it,
* If rebinding a parameter that had data-at-exec stuff in it, then then free that stuff
* free that stuff */
*/ if (stmt->parameters[ipar].EXEC_used) {
if (stmt->parameters[ipar].EXEC_used)
{
free(stmt->parameters[ipar].EXEC_used); free(stmt->parameters[ipar].EXEC_used);
stmt->parameters[ipar].EXEC_used = NULL; stmt->parameters[ipar].EXEC_used = NULL;
} }
if (stmt->parameters[ipar].EXEC_buffer) if (stmt->parameters[ipar].EXEC_buffer) {
{
if (stmt->parameters[ipar].SQLType != SQL_LONGVARBINARY) if (stmt->parameters[ipar].SQLType != SQL_LONGVARBINARY)
free(stmt->parameters[ipar].EXEC_buffer); free(stmt->parameters[ipar].EXEC_buffer);
stmt->parameters[ipar].EXEC_buffer = NULL; stmt->parameters[ipar].EXEC_buffer = NULL;
} }
/* Data at exec macro only valid for C char/binary data */ /* Data at exec macro only valid for C char/binary data */
if ((fSqlType == SQL_LONGVARBINARY || fSqlType == SQL_LONGVARCHAR) && pcbValue && *pcbValue <= SQL_LEN_DATA_AT_EXEC_OFFSET) if ((fSqlType == SQL_LONGVARBINARY || fSqlType == SQL_LONGVARCHAR) && 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, paramType=%d, fCType=%d, fSqlType=%d, cbColDef=%d, ibScale=%d, rgbValue=%d, *pcbValue = %d, data_at_exec = %d\n", ipar, fParamType, fCType, fSqlType, cbColDef, ibScale, rgbValue, pcbValue ? *pcbValue : -777, stmt->parameters[ipar].data_at_exec); mylog("SQLBindParamater: ipar=%d, paramType=%d, fCType=%d, fSqlType=%d, cbColDef=%d, ibScale=%d, rgbValue=%d, *pcbValue = %d, data_at_exec = %d\n", ipar, fParamType, fCType, fSqlType, cbColDef, ibScale, rgbValue, pcbValue ? *pcbValue: -777, stmt->parameters[ipar].data_at_exec);
return SQL_SUCCESS; return SQL_SUCCESS;
} }
/* - - - - - - - - - */ /* - - - - - - - - - */
/* Associate a user-supplied buffer with a database column. */
RETCODE SQL_API
SQLBindCol(
HSTMT hstmt,
UWORD icol,
SWORD fCType,
PTR rgbValue,
SDWORD cbValueMax,
SDWORD FAR *pcbValue)
{
StatementClass *stmt = (StatementClass *) hstmt;
static char *func = "SQLBindCol";
mylog("%s: entering...\n", func); /* Associate a user-supplied buffer with a database column. */
RETCODE SQL_API SQLBindCol(
HSTMT hstmt,
UWORD icol,
SWORD fCType,
PTR rgbValue,
SDWORD cbValueMax,
SDWORD FAR *pcbValue)
{
StatementClass *stmt = (StatementClass *) hstmt;
static char *func="SQLBindCol";
mylog("**** SQLBindCol: stmt = %u, icol = %d\n", stmt, icol); mylog( "%s: entering...\n", func);
mylog("**** SQLBindCol: stmt = %u, icol = %d\n", stmt, icol);
if (!stmt) if ( ! stmt) {
{
SC_log_error(func, "", NULL); SC_log_error(func, "", NULL);
return SQL_INVALID_HANDLE; return SQL_INVALID_HANDLE;
} }
SC_clear_error(stmt); SC_clear_error(stmt);
if (stmt->status == STMT_EXECUTING) if( stmt->status == STMT_EXECUTING) {
{
stmt->errormsg = "Can't bind columns while statement is still executing."; stmt->errormsg = "Can't bind columns while statement is still executing.";
stmt->errornumber = STMT_SEQUENCE_ERROR; stmt->errornumber = STMT_SEQUENCE_ERROR;
SC_log_error(func, "", stmt); SC_log_error(func, "", stmt);
return SQL_ERROR; return SQL_ERROR;
} }
/* If the bookmark column is being bound, then just save it */ /* If the bookmark column is being bound, then just save it */
if (icol == 0) if (icol == 0) {
{
if (rgbValue == NULL) if (rgbValue == NULL) {
{
stmt->bookmark.buffer = NULL; stmt->bookmark.buffer = NULL;
stmt->bookmark.used = NULL; stmt->bookmark.used = NULL;
} }
else else {
{ /* Make sure it is the bookmark data type */
/* Make sure it is the bookmark data type */ if ( fCType != SQL_C_BOOKMARK) {
if (fCType != SQL_C_BOOKMARK)
{
stmt->errormsg = "Column 0 is not of type SQL_C_BOOKMARK"; stmt->errormsg = "Column 0 is not of type SQL_C_BOOKMARK";
stmt->errornumber = STMT_PROGRAM_TYPE_OUT_OF_RANGE; stmt->errornumber = STMT_PROGRAM_TYPE_OUT_OF_RANGE;
SC_log_error(func, "", stmt); SC_log_error(func, "", stmt);
...@@ -214,42 +195,37 @@ SQLBindCol( ...@@ -214,42 +195,37 @@ SQLBindCol(
return SQL_SUCCESS; return SQL_SUCCESS;
} }
/* allocate enough bindings if not already done */ /* allocate enough bindings if not already done */
/* Most likely, execution of a statement would have setup the */ /* Most likely, execution of a statement would have setup the */
/* necessary bindings. But some apps call BindCol before any */ /* necessary bindings. But some apps call BindCol before any */
/* statement is executed. */ /* statement is executed. */
if (icol > stmt->bindings_allocated) if ( icol > stmt->bindings_allocated)
extend_bindings(stmt, icol); extend_bindings(stmt, icol);
/* check to see if the bindings were allocated */ /* check to see if the bindings were allocated */
if (!stmt->bindings) if ( ! stmt->bindings) {
{
stmt->errormsg = "Could not allocate memory for bindings."; stmt->errormsg = "Could not allocate memory for bindings.";
stmt->errornumber = STMT_NO_MEMORY_ERROR; stmt->errornumber = STMT_NO_MEMORY_ERROR;
SC_log_error(func, "", stmt); SC_log_error(func, "", stmt);
return SQL_ERROR; return SQL_ERROR;
} }
icol--; /* use zero based col numbers from here icol--; /* use zero based col numbers from here out */
* out */
/* Reset for SQLGetData */ /* Reset for SQLGetData */
stmt->bindings[icol].data_left = -1; stmt->bindings[icol].data_left = -1;
if (rgbValue == NULL) if (rgbValue == NULL) {
{
/* we have to unbind the column */ /* we have to unbind the column */
stmt->bindings[icol].buflen = 0; stmt->bindings[icol].buflen = 0;
stmt->bindings[icol].buffer = NULL; stmt->bindings[icol].buffer = NULL;
stmt->bindings[icol].used = NULL; stmt->bindings[icol].used = NULL;
stmt->bindings[icol].returntype = SQL_C_CHAR; stmt->bindings[icol].returntype = SQL_C_CHAR;
} } else {
else
{
/* ok, bind that column */ /* ok, bind that column */
stmt->bindings[icol].buflen = cbValueMax; stmt->bindings[icol].buflen = cbValueMax;
stmt->bindings[icol].buffer = rgbValue; stmt->bindings[icol].buffer = rgbValue;
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); mylog(" bound buffer[%d] = %u\n", icol, stmt->bindings[icol].buffer);
...@@ -258,37 +234,34 @@ SQLBindCol( ...@@ -258,37 +234,34 @@ SQLBindCol(
return SQL_SUCCESS; return SQL_SUCCESS;
} }
/* - - - - - - - - - */ /* - - - - - - - - - */
/* Returns the description of a parameter marker. */ /* Returns the description of a parameter marker. */
/* This function is listed as not being supported by SQLGetFunctions() because it is */ /* This function is listed as not being supported by SQLGetFunctions() because it is */
/* used to describe "parameter markers" (not bound parameters), in which case, */ /* used to describe "parameter markers" (not bound parameters), in which case, */
/* the dbms should return info on the markers. Since Postgres doesn't support that, */ /* the dbms should return info on the markers. Since Postgres doesn't support that, */
/* it is best to say this function is not supported and let the application assume a */ /* it is best to say this function is not supported and let the application assume a */
/* data type (most likely varchar). */ /* data type (most likely varchar). */
RETCODE SQL_API RETCODE SQL_API SQLDescribeParam(
SQLDescribeParam( HSTMT hstmt,
HSTMT hstmt, UWORD ipar,
UWORD ipar, SWORD FAR *pfSqlType,
SWORD FAR *pfSqlType, UDWORD FAR *pcbColDef,
UDWORD FAR *pcbColDef, SWORD FAR *pibScale,
SWORD FAR *pibScale, SWORD FAR *pfNullable)
SWORD FAR *pfNullable)
{ {
StatementClass *stmt = (StatementClass *) hstmt; StatementClass *stmt = (StatementClass *) hstmt;
static char *func = "SQLDescribeParam"; static char *func = "SQLDescribeParam";
mylog("%s: entering...\n", func); mylog( "%s: entering...\n", func);
if (!stmt) if( ! stmt) {
{
SC_log_error(func, "", NULL); SC_log_error(func, "", NULL);
return SQL_INVALID_HANDLE; return SQL_INVALID_HANDLE;
} }
if ((ipar < 1) || (ipar > stmt->parameters_allocated)) if( (ipar < 1) || (ipar > stmt->parameters_allocated) ) {
{
stmt->errormsg = "Invalid parameter number for SQLDescribeParam."; stmt->errormsg = "Invalid parameter number for SQLDescribeParam.";
stmt->errornumber = STMT_BAD_PARAMETER_NUMBER_ERROR; stmt->errornumber = STMT_BAD_PARAMETER_NUMBER_ERROR;
SC_log_error(func, "", stmt); SC_log_error(func, "", stmt);
...@@ -297,45 +270,41 @@ SQLDescribeParam( ...@@ -297,45 +270,41 @@ SQLDescribeParam(
ipar--; ipar--;
/* /* This implementation is not very good, since it is supposed to describe */
* This implementation is not very good, since it is supposed to /* parameter markers, not bound parameters. */
* describe if(pfSqlType)
*/
/* parameter markers, not bound parameters. */
if (pfSqlType)
*pfSqlType = stmt->parameters[ipar].SQLType; *pfSqlType = stmt->parameters[ipar].SQLType;
if (pcbColDef) if(pcbColDef)
*pcbColDef = stmt->parameters[ipar].precision; *pcbColDef = stmt->parameters[ipar].precision;
if (pibScale) if(pibScale)
*pibScale = stmt->parameters[ipar].scale; *pibScale = stmt->parameters[ipar].scale;
if (pfNullable) if(pfNullable)
*pfNullable = pgtype_nullable(stmt, stmt->parameters[ipar].paramType); *pfNullable = pgtype_nullable(stmt, stmt->parameters[ipar].paramType);
return SQL_SUCCESS; return SQL_SUCCESS;
} }
/* - - - - - - - - - */ /* - - - - - - - - - */
/* Sets multiple values (arrays) for the set of parameter markers. */ /* Sets multiple values (arrays) for the set of parameter markers. */
RETCODE SQL_API RETCODE SQL_API SQLParamOptions(
SQLParamOptions( HSTMT hstmt,
HSTMT hstmt, UDWORD crow,
UDWORD crow, UDWORD FAR *pirow)
UDWORD FAR *pirow)
{ {
static char *func = "SQLParamOptions"; static char *func = "SQLParamOptions";
mylog("%s: entering...\n", func); mylog( "%s: entering...\n", func);
SC_log_error(func, "Function not implemented", (StatementClass *) hstmt); SC_log_error(func, "Function not implemented", (StatementClass *) hstmt);
return SQL_ERROR; return SQL_ERROR;
} }
/* - - - - - - - - - */ /* - - - - - - - - - */
/* This function should really talk to the dbms to determine the number of */ /* This function should really talk to the dbms to determine the number of */
/* "parameter markers" (not bound parameters) in the statement. But, since */ /* "parameter markers" (not bound parameters) in the statement. But, since */
...@@ -344,49 +313,43 @@ SQLParamOptions( ...@@ -344,49 +313,43 @@ SQLParamOptions(
/* like it does for SQLDescribeParam is that some applications don't care and try */ /* like it does for SQLDescribeParam is that some applications don't care and try */
/* to call it anyway. */ /* to call it anyway. */
/* If the statement does not have parameters, it should just return 0. */ /* If the statement does not have parameters, it should just return 0. */
RETCODE SQL_API RETCODE SQL_API SQLNumParams(
SQLNumParams( HSTMT hstmt,
HSTMT hstmt, SWORD FAR *pcpar)
SWORD FAR *pcpar)
{ {
StatementClass *stmt = (StatementClass *) hstmt; StatementClass *stmt = (StatementClass *) hstmt;
char in_quote = FALSE; char in_quote = FALSE;
unsigned int i; unsigned int i;
static char *func = "SQLNumParams"; static char *func = "SQLNumParams";
mylog("%s: entering...\n", func); mylog( "%s: entering...\n", func);
if (!stmt) if(!stmt) {
{
SC_log_error(func, "", NULL); SC_log_error(func, "", NULL);
return SQL_INVALID_HANDLE; return SQL_INVALID_HANDLE;
} }
if (pcpar) if (pcpar)
*pcpar = 0; *pcpar = 0;
else else {
{
SC_log_error(func, "pcpar was null", stmt); SC_log_error(func, "pcpar was null", stmt);
return SQL_ERROR; return SQL_ERROR;
} }
if (!stmt->statement) if(!stmt->statement) {
{
/* no statement has been allocated */ /* no statement has been allocated */
stmt->errormsg = "SQLNumParams called with no statement ready."; stmt->errormsg = "SQLNumParams called with no statement ready.";
stmt->errornumber = STMT_SEQUENCE_ERROR; stmt->errornumber = STMT_SEQUENCE_ERROR;
SC_log_error(func, "", stmt); SC_log_error(func, "", stmt);
return SQL_ERROR; return SQL_ERROR;
} } else {
else
{ for(i=0; i < strlen(stmt->statement); i++) {
for (i = 0; i < strlen(stmt->statement); i++)
{ if(stmt->statement[i] == '?' && !in_quote)
if (stmt->statement[i] == '?' && !in_quote)
(*pcpar)++; (*pcpar)++;
else else {
{
if (stmt->statement[i] == '\'') if (stmt->statement[i] == '\'')
in_quote = (in_quote ? FALSE : TRUE); in_quote = (in_quote ? FALSE : TRUE);
} }
...@@ -397,20 +360,20 @@ SQLNumParams( ...@@ -397,20 +360,20 @@ SQLNumParams(
} }
/******************************************************************** /********************************************************************
* Bindings Implementation * Bindings Implementation
*/ */
BindInfoClass * BindInfoClass *
create_empty_bindings(int num_columns) create_empty_bindings(int num_columns)
{ {
BindInfoClass *new_bindings; BindInfoClass *new_bindings;
int i; int i;
new_bindings = (BindInfoClass *) malloc(num_columns * sizeof(BindInfoClass)); new_bindings = (BindInfoClass *)malloc(num_columns * sizeof(BindInfoClass));
if (!new_bindings) if(!new_bindings) {
return 0; return 0;
}
for (i = 0; i < num_columns; i++) for(i=0; i < num_columns; i++) {
{
new_bindings[i].buflen = 0; new_bindings[i].buflen = 0;
new_bindings[i].buffer = NULL; new_bindings[i].buffer = NULL;
new_bindings[i].used = NULL; new_bindings[i].used = NULL;
...@@ -423,23 +386,21 @@ create_empty_bindings(int num_columns) ...@@ -423,23 +386,21 @@ create_empty_bindings(int num_columns)
void void
extend_bindings(StatementClass *stmt, int num_columns) extend_bindings(StatementClass *stmt, int num_columns)
{ {
static char *func = "extend_bindings"; static char *func="extend_bindings";
BindInfoClass *new_bindings; BindInfoClass *new_bindings;
int i; int i;
mylog("%s: entering ... stmt=%u, bindings_allocated=%d, num_columns=%d\n", func, stmt, stmt->bindings_allocated, num_columns); mylog("%s: entering ... stmt=%u, bindings_allocated=%d, num_columns=%d\n", func, 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 */
if (stmt->bindings_allocated < num_columns) if(stmt->bindings_allocated < num_columns) {
{
new_bindings = create_empty_bindings(num_columns); new_bindings = create_empty_bindings(num_columns);
if (!new_bindings) if ( ! new_bindings) {
{ mylog("%s: unable to create %d new bindings from %d old bindings\n", func, num_columns, stmt->bindings_allocated);
mylog("%s: unable to create %d new bindings from %d old bindings\n", func, num_columns, stmt->bindings_allocated);
if (stmt->bindings) if (stmt->bindings) {
{
free(stmt->bindings); free(stmt->bindings);
stmt->bindings = NULL; stmt->bindings = NULL;
} }
...@@ -447,9 +408,8 @@ extend_bindings(StatementClass *stmt, int num_columns) ...@@ -447,9 +408,8 @@ extend_bindings(StatementClass *stmt, int num_columns)
return; return;
} }
if (stmt->bindings) if(stmt->bindings) {
{ for(i=0; i<stmt->bindings_allocated; i++)
for (i = 0; i < stmt->bindings_allocated; i++)
new_bindings[i] = stmt->bindings[i]; new_bindings[i] = stmt->bindings[i];
free(stmt->bindings); free(stmt->bindings);
...@@ -457,14 +417,15 @@ extend_bindings(StatementClass *stmt, int num_columns) ...@@ -457,14 +417,15 @@ extend_bindings(StatementClass *stmt, int num_columns)
stmt->bindings = new_bindings; stmt->bindings = new_bindings;
stmt->bindings_allocated = num_columns; stmt->bindings_allocated = num_columns;
}
/* There is no reason to zero out extra bindings if there are */
/* more than needed. If an app has allocated extra bindings, */
/* let it worry about it by unbinding those columns. */
/* SQLBindCol(1..) ... SQLBindCol(10...) # got 10 bindings */ }
/* SQLExecDirect(...) # returns 5 cols */ /* There is no reason to zero out extra bindings if there are */
/* SQLExecDirect(...) # returns 10 cols (now OK) */ /* more than needed. If an app has allocated extra bindings, */
/* let it worry about it by unbinding those columns. */
/* SQLBindCol(1..) ... SQLBindCol(10...) # got 10 bindings */
/* SQLExecDirect(...) # returns 5 cols */
/* SQLExecDirect(...) # returns 10 cols (now OK) */
mylog("exit extend_bindings\n"); mylog("exit extend_bindings\n");
} }
/* 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.
* *
*/ */
...@@ -15,40 +15,33 @@ ...@@ -15,40 +15,33 @@
/* /*
* BindInfoClass -- stores information about a bound column * BindInfoClass -- stores information about a bound column
*/ */
struct BindInfoClass_ struct BindInfoClass_ {
{ Int4 buflen; /* size of buffer */
Int4 buflen; /* size of buffer */ Int4 data_left; /* amount of data left to read (SQLGetData) */
Int4 data_left; /* amount of data left to read char *buffer; /* pointer to the buffer */
* (SQLGetData) */ Int4 *used; /* used space in the buffer (for strings not counting the '\0') */
char *buffer; /* pointer to the buffer */ Int2 returntype; /* kind of conversion to be applied when returning (SQL_C_DEFAULT, SQL_C_CHAR...) */
Int4 *used; /* used space in the buffer (for strings
* not counting the '\0') */
Int2 returntype; /* kind of conversion to be applied when
* returning (SQL_C_DEFAULT,
* SQL_C_CHAR...) */
}; };
/* /*
* ParameterInfoClass -- stores information about a bound parameter * ParameterInfoClass -- stores information about a bound parameter
*/ */
struct ParameterInfoClass_ struct ParameterInfoClass_ {
{ Int4 buflen;
Int4 buflen; char *buffer;
char *buffer; Int4 *used;
Int4 *used; Int2 paramType;
Int2 paramType; Int2 CType;
Int2 CType; Int2 SQLType;
Int2 SQLType; UInt4 precision;
UInt4 precision; Int2 scale;
Int2 scale; Oid lobj_oid;
Oid lobj_oid; Int4 *EXEC_used; /* amount of data OR the oid of the large object */
Int4 *EXEC_used; /* amount of data OR the oid of the large char *EXEC_buffer; /* the data or the FD of the large object */
* 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);
void extend_bindings(StatementClass *stmt, int num_columns); void extend_bindings(StatementClass *stmt, int num_columns);
#endif #endif
/* Module: columninfo.c
/* Module: columninfo.c
* *
* Description: This module contains routines related to * Description: This module contains routines related to
* reading and storing the field information from a query. * reading and storing the field information from a query.
* *
* Classes: ColumnInfoClass (Functions prefix: "CI_") * Classes: ColumnInfoClass (Functions prefix: "CI_")
* *
* API functions: none * API functions: none
* *
* Comments: See "notice.txt" for copyright and license information. * Comments: See "notice.txt" for copyright and license information.
* *
*/ */
...@@ -20,12 +21,11 @@ ...@@ -20,12 +21,11 @@
ColumnInfoClass * ColumnInfoClass *
CI_Constructor() CI_Constructor()
{ {
ColumnInfoClass *rv; ColumnInfoClass *rv;
rv = (ColumnInfoClass *) malloc(sizeof(ColumnInfoClass)); rv = (ColumnInfoClass *) malloc(sizeof(ColumnInfoClass));
if (rv) if (rv) {
{
rv->num_fields = 0; rv->num_fields = 0;
rv->name = NULL; rv->name = NULL;
rv->adtid = NULL; rv->adtid = NULL;
...@@ -45,21 +45,21 @@ CI_Destructor(ColumnInfoClass *self) ...@@ -45,21 +45,21 @@ CI_Destructor(ColumnInfoClass *self)
free(self); free(self);
} }
/* Read in field descriptions. /* Read in field descriptions.
If self is not null, then also store the information. If self is not null, then also store the information.
If self is null, then just read, don't store. If self is null, then just read, don't store.
*/ */
char char
CI_read_fields(ColumnInfoClass *self, ConnectionClass *conn) CI_read_fields(ColumnInfoClass *self, ConnectionClass *conn)
{ {
Int2 lf; Int2 lf;
int new_num_fields; int new_num_fields;
Oid new_adtid; Oid new_adtid;
Int2 new_adtsize; Int2 new_adtsize;
Int4 new_atttypmod = -1; Int4 new_atttypmod = -1;
char new_field_name[MAX_MESSAGE_LEN + 1]; char new_field_name[MAX_MESSAGE_LEN+1];
SocketClass *sock; SocketClass *sock;
ConnInfo *ci; ConnInfo *ci;
sock = CC_get_socket(conn); sock = CC_get_socket(conn);
ci = &conn->connInfo; ci = &conn->connInfo;
...@@ -69,28 +69,28 @@ CI_read_fields(ColumnInfoClass *self, ConnectionClass *conn) ...@@ -69,28 +69,28 @@ CI_read_fields(ColumnInfoClass *self, ConnectionClass *conn)
mylog("num_fields = %d\n", new_num_fields); mylog("num_fields = %d\n", new_num_fields);
if (self) if (self) { /* according to that allocate memory */
{ /* according to that allocate memory */
CI_set_num_fields(self, new_num_fields); CI_set_num_fields(self, new_num_fields);
} }
/* now read in the descriptions */ /* now read in the descriptions */
for (lf = 0; lf < new_num_fields; lf++) for(lf = 0; lf < new_num_fields; lf++) {
{
SOCK_get_string(sock, new_field_name, MAX_MESSAGE_LEN); SOCK_get_string(sock, new_field_name, MAX_MESSAGE_LEN);
new_adtid = (Oid) SOCK_get_int(sock, 4); new_adtid = (Oid) SOCK_get_int(sock, 4);
new_adtsize = (Int2) SOCK_get_int(sock, 2); new_adtsize = (Int2) SOCK_get_int(sock, 2);
/* If 6.4 protocol, then read the atttypmod field */ /* If 6.4 protocol, then read the atttypmod field */
if (PG_VERSION_GE(conn, 6.4)) if (PG_VERSION_GE(conn, 6.4)) {
{
mylog("READING ATTTYPMOD\n"); mylog("READING ATTTYPMOD\n");
new_atttypmod = (Int4) SOCK_get_int(sock, 4); new_atttypmod = (Int4) SOCK_get_int(sock, 4);
/* Subtract the header length */ /* Subtract the header length */
new_atttypmod -= 4; new_atttypmod -= 4;
if (new_atttypmod < 0) if (new_atttypmod < 0)
new_atttypmod = -1; new_atttypmod = -1;
} }
mylog("CI_read_fields: fieldname='%s', adtid=%d, adtsize=%d, atttypmod=%d\n", new_field_name, new_adtid, new_adtsize, new_atttypmod); mylog("CI_read_fields: fieldname='%s', adtid=%d, adtsize=%d, atttypmod=%d\n", new_field_name, new_adtid, new_adtsize, new_atttypmod);
...@@ -107,16 +107,15 @@ CI_read_fields(ColumnInfoClass *self, ConnectionClass *conn) ...@@ -107,16 +107,15 @@ CI_read_fields(ColumnInfoClass *self, ConnectionClass *conn)
void void
CI_free_memory(ColumnInfoClass *self) CI_free_memory(ColumnInfoClass *self)
{ {
register Int2 lf; register Int2 lf;
int num_fields = self->num_fields; int num_fields = self->num_fields;
for (lf = 0; lf < num_fields; lf++) for (lf = 0; lf < num_fields; lf++) {
{ if( self->name[lf])
if (self->name[lf]) free (self->name[lf]);
free(self->name[lf]);
} }
/* 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);
...@@ -128,30 +127,33 @@ CI_free_memory(ColumnInfoClass *self) ...@@ -128,30 +127,33 @@ CI_free_memory(ColumnInfoClass *self)
void void
CI_set_num_fields(ColumnInfoClass *self, int new_num_fields) CI_set_num_fields(ColumnInfoClass *self, int new_num_fields)
{ {
CI_free_memory(self); /* always safe to call */ CI_free_memory(self); /* always safe to call */
self->num_fields = new_num_fields; self->num_fields = 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); self->display_size = (Int2 *) malloc(sizeof(Int2) * self->num_fields);
self->atttypmod = (Int4 *) malloc(sizeof(Int4) * self->num_fields); self->atttypmod = (Int4 *) malloc(sizeof(Int4) * self->num_fields);
} }
void void
CI_set_field_info(ColumnInfoClass *self, int field_num, char *new_name, CI_set_field_info(ColumnInfoClass *self, int field_num, char *new_name,
Oid new_adtid, Int2 new_adtsize, Int4 new_atttypmod) Oid new_adtid, Int2 new_adtsize, Int4 new_atttypmod)
{ {
/* check bounds */ /* check bounds */
if ((field_num < 0) || (field_num >= self->num_fields)) if((field_num < 0) || (field_num >= self->num_fields)) {
return; return;
}
/* store the info */ /* store the info */
self->name[field_num] = strdup(new_name); self->name[field_num] = strdup(new_name);
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->atttypmod[field_num] = new_atttypmod; self->atttypmod[field_num] = new_atttypmod;
self->display_size[field_num] = 0; self->display_size[field_num] = 0;
} }
/* 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.
* *
*/ */
...@@ -12,14 +12,13 @@ ...@@ -12,14 +12,13 @@
#include "psqlodbc.h" #include "psqlodbc.h"
struct ColumnInfoClass_ struct ColumnInfoClass_ {
{ Int2 num_fields;
Int2 num_fields; char **name; /* list of type names */
char **name; /* list of type names */ Oid *adtid; /* list of type ids */
Oid *adtid; /* list of type ids */ Int2 *adtsize; /* list type sizes */
Int2 *adtsize; /* list type sizes */ Int2 *display_size; /* the display size (longest row) */
Int2 *display_size; /* the display size (longest row) */ Int4 *atttypmod; /* the length of bpchar/varchar */
Int4 *atttypmod; /* the length of bpchar/varchar */
}; };
#define CI_get_num_fields(self) (self->num_fields) #define CI_get_num_fields(self) (self->num_fields)
...@@ -30,15 +29,15 @@ struct ColumnInfoClass_ ...@@ -30,15 +29,15 @@ struct ColumnInfoClass_
#define CI_get_atttypmod(self, col) (self->atttypmod[col]) #define CI_get_atttypmod(self, col) (self->atttypmod[col])
ColumnInfoClass *CI_Constructor(void); ColumnInfoClass *CI_Constructor(void);
void CI_Destructor(ColumnInfoClass *self); void CI_Destructor(ColumnInfoClass *self);
void CI_free_memory(ColumnInfoClass *self); void CI_free_memory(ColumnInfoClass *self);
char CI_read_fields(ColumnInfoClass *self, ConnectionClass *conn); char CI_read_fields(ColumnInfoClass *self, ConnectionClass *conn);
/* functions for setting up the fields from within the program, */ /* functions for setting up the fields from within the program, */
/* without reading from a socket */ /* without reading from a socket */
void CI_set_num_fields(ColumnInfoClass *self, int new_num_fields); 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, Int4 atttypmod); Oid new_adtid, Int2 new_adtsize, Int4 atttypmod);
#endif #endif
此差异已折叠。
/* 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.
* *
*/ */
...@@ -27,14 +27,11 @@ ...@@ -27,14 +27,11 @@
#endif #endif
typedef enum typedef enum {
{ CONN_NOT_CONNECTED, /* Connection has not been established */
CONN_NOT_CONNECTED, /* Connection has not been established */ CONN_CONNECTED, /* Connection is up and has been established */
CONN_CONNECTED, /* Connection is up and has been CONN_DOWN, /* Connection is broken */
* established */ CONN_EXECUTING /* the connection is currently executing a statement */
CONN_DOWN, /* Connection is broken */
CONN_EXECUTING /* the connection is currently executing a
* statement */
} CONN_Status; } CONN_Status;
/* These errors have general sql error state */ /* These errors have general sql error state */
...@@ -53,7 +50,7 @@ typedef enum ...@@ -53,7 +50,7 @@ typedef enum
#define CONN_INIREAD_ERROR 201 #define CONN_INIREAD_ERROR 201
#define CONN_OPENDB_ERROR 202 #define CONN_OPENDB_ERROR 202
#define CONN_STMT_ALLOC_ERROR 203 #define CONN_STMT_ALLOC_ERROR 203
#define CONN_IN_USE 204 #define CONN_IN_USE 204
#define CONN_UNSUPPORTED_OPTION 205 #define CONN_UNSUPPORTED_OPTION 205
/* Used by SetConnectoption to indicate unsupported options */ /* Used by SetConnectoption to indicate unsupported options */
#define CONN_INVALID_ARGUMENT_NO 206 #define CONN_INVALID_ARGUMENT_NO 206
...@@ -93,11 +90,11 @@ typedef enum ...@@ -93,11 +90,11 @@ typedef enum
#define AUTH_REQ_CRYPT 4 #define AUTH_REQ_CRYPT 4
/* Startup Packet sizes */ /* Startup Packet sizes */
#define SM_DATABASE 64 #define SM_DATABASE 64
#define SM_USER 32 #define SM_USER 32
#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
...@@ -109,44 +106,63 @@ typedef unsigned int ProtocolVersion; ...@@ -109,44 +106,63 @@ typedef unsigned int ProtocolVersion;
#define PG_PROTOCOL(major, minor) (((major) << 16) | (minor)) #define PG_PROTOCOL(major, minor) (((major) << 16) | (minor))
#define PG_PROTOCOL_LATEST PG_PROTOCOL(2, 0) #define PG_PROTOCOL_LATEST PG_PROTOCOL(2, 0)
#define PG_PROTOCOL_63 PG_PROTOCOL(1, 0)
#define PG_PROTOCOL_62 PG_PROTOCOL(0, 0)
/* This startup packet is to support latest Postgres protocol */ /* This startup packet is to support latest Postgres protocol (6.4, 6.3) */
typedef struct _StartupPacket typedef struct _StartupPacket
{ {
ProtocolVersion protoVersion; ProtocolVersion protoVersion;
char database[SM_DATABASE]; char database[SM_DATABASE];
char user[SM_USER]; char user[SM_USER];
char options[SM_OPTIONS]; char options[SM_OPTIONS];
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 */
typedef struct _StartupPacket6_2
{
unsigned int authtype;
char database[PATH_SIZE];
char user[NAMEDATALEN];
char options[ARGV_SIZE];
char execfile[ARGV_SIZE];
char tty[PATH_SIZE];
} StartupPacket6_2;
/* Structure to hold all the connection attributes for a specific /* Structure to hold all the connection attributes for a specific
connection (used for both registry and file, DSN and DRIVER) connection (used for both registry and file, DSN and DRIVER)
*/ */
typedef struct typedef struct {
{ char dsn[MEDIUM_REGISTRY_LEN];
char dsn[MEDIUM_REGISTRY_LEN]; char desc[MEDIUM_REGISTRY_LEN];
char desc[MEDIUM_REGISTRY_LEN]; char driver[MEDIUM_REGISTRY_LEN];
char driver[MEDIUM_REGISTRY_LEN]; 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 onlyread[SMALL_REGISTRY_LEN];
char onlyread[SMALL_REGISTRY_LEN]; char fake_oid_index[SMALL_REGISTRY_LEN];
char fake_oid_index[SMALL_REGISTRY_LEN]; char show_oid_column[SMALL_REGISTRY_LEN];
char show_oid_column[SMALL_REGISTRY_LEN]; char row_versioning[SMALL_REGISTRY_LEN];
char row_versioning[SMALL_REGISTRY_LEN]; char show_system_tables[SMALL_REGISTRY_LEN];
char show_system_tables[SMALL_REGISTRY_LEN]; char translation_dll[MEDIUM_REGISTRY_LEN];
char translation_dll[MEDIUM_REGISTRY_LEN]; char translation_option[SMALL_REGISTRY_LEN];
char translation_option[SMALL_REGISTRY_LEN]; char focus_password;
char focus_password;
} ConnInfo; } ConnInfo;
/* Macro to determine is the connection using 6.2 protocol? */
#define PROTOCOL_62(conninfo_) (strncmp((conninfo_)->protocol, PG62, strlen(PG62)) == 0)
/* Macro to determine is the connection using 6.3 protocol? */
#define PROTOCOL_63(conninfo_) (strncmp((conninfo_)->protocol, PG63, strlen(PG63)) == 0)
/* /*
* Macros to compare the server's version with a specified version * Macros to compare the server's version with a specified version
* 1st parameter: pointer to a ConnectionClass object * 1st parameter: pointer to a ConnectionClass object
...@@ -164,15 +180,15 @@ typedef struct ...@@ -164,15 +180,15 @@ typedef struct
#define SERVER_VERSION_LE(conn, major, minor) (! SERVER_VERSION_GT(conn, major, minor)) #define SERVER_VERSION_LE(conn, major, minor) (! SERVER_VERSION_GT(conn, major, minor))
#define SERVER_VERSION_LT(conn, major, minor) (! SERVER_VERSION_GE(conn, major, minor)) #define SERVER_VERSION_LT(conn, major, minor) (! SERVER_VERSION_GE(conn, major, minor))
/*#if ! defined(HAVE_CONFIG_H) || defined(HAVE_STRINGIZE)*/ /*#if ! defined(HAVE_CONFIG_H) || defined(HAVE_STRINGIZE)*/
#define STRING_AFTER_DOT(string) (strchr(#string, '.') + 1) #define STRING_AFTER_DOT(string) (strchr(#string, '.') + 1)
/*#else /*#else
#define STRING_AFTER_DOT(str) (strchr("str", '.') + 1) #define STRING_AFTER_DOT(str) (strchr("str", '.') + 1)
#endif*/ #endif*/
/* /*
* Simplified macros to compare the server's version with a * Simplified macros to compare the server's version with a
* specified version * specified version
* Note: Never pass a variable as the second parameter. * Note: Never pass a variable as the second parameter.
* It must be a decimal constant of the form %d.%d . * It must be a decimal constant of the form %d.%d .
*/ */
#define PG_VERSION_GT(conn, ver) \ #define PG_VERSION_GT(conn, ver) \
(SERVER_VERSION_GT(conn, (int) ver, atoi(STRING_AFTER_DOT(ver)))) (SERVER_VERSION_GT(conn, (int) ver, atoi(STRING_AFTER_DOT(ver))))
...@@ -184,10 +200,9 @@ typedef struct ...@@ -184,10 +200,9 @@ typedef struct
#define PG_VERSION_LT(conn, ver) (! PG_VERSION_GE(conn, ver)) #define PG_VERSION_LT(conn, ver) (! PG_VERSION_GE(conn, ver))
/* This is used to store cached table information in the connection */ /* This is used to store cached table information in the connection */
struct col_info struct col_info {
{ QResultClass *result;
QResultClass *result; char name[MAX_TABLE_LEN+1];
char name[MAX_TABLE_LEN + 1];
}; };
/* Translation DLL entry points */ /* Translation DLL entry points */
...@@ -199,95 +214,89 @@ struct col_info ...@@ -199,95 +214,89 @@ struct col_info
#define HINSTANCE void * #define HINSTANCE void *
#endif #endif
typedef BOOL (FAR WINAPI * DataSourceToDriverProc) (UDWORD, typedef BOOL (FAR WINAPI *DataSourceToDriverProc) (UDWORD,
SWORD, SWORD,
PTR, PTR,
SDWORD, SDWORD,
PTR, PTR,
SDWORD, SDWORD,
SDWORD FAR *, SDWORD FAR *,
UCHAR FAR *, UCHAR FAR *,
SWORD, SWORD,
SWORD FAR *); SWORD FAR *);
typedef BOOL (FAR WINAPI * DriverToDataSourceProc) (UDWORD, typedef BOOL (FAR WINAPI *DriverToDataSourceProc) (UDWORD,
SWORD, SWORD,
PTR, PTR,
SDWORD, SDWORD,
PTR, PTR,
SDWORD, SDWORD,
SDWORD FAR *, SDWORD FAR *,
UCHAR FAR *, UCHAR FAR *,
SWORD, SWORD,
SWORD FAR *); SWORD FAR *);
/******* The Connection handle ************/ /******* The Connection handle ************/
struct ConnectionClass_ struct ConnectionClass_ {
{ HENV henv; /* environment this connection was created on */
HENV henv; /* environment this connection was created
* on */
StatementOptions stmtOptions; StatementOptions stmtOptions;
char *errormsg; char *errormsg;
int errornumber; int errornumber;
CONN_Status status; CONN_Status status;
ConnInfo connInfo; ConnInfo connInfo;
StatementClass **stmts; StatementClass **stmts;
int num_stmts; int num_stmts;
SocketClass *sock; SocketClass *sock;
int lobj_type; int lobj_type;
int ntables; int ntables;
COL_INFO **col_info; COL_INFO **col_info;
long translation_option; long translation_option;
HINSTANCE translation_handle; HINSTANCE translation_handle;
DataSourceToDriverProc DataSourceToDriver; DataSourceToDriverProc DataSourceToDriver;
DriverToDataSourceProc DriverToDataSource; DriverToDataSourceProc DriverToDataSource;
char transact_status;/* Is a transaction is currently in char transact_status; /* Is a transaction is currently in progress */
* progress */ char errormsg_created; /* has an informative error msg been created? */
char errormsg_created; /* has an informative error msg char pg_version[MAX_INFO_STRING]; /* Version of PostgreSQL we're connected to - DJP 25-1-2001 */
* been created? */ float pg_version_number;
char pg_version[MAX_INFO_STRING]; /* Version of PostgreSQL Int2 pg_version_major;
* we're connected to - Int2 pg_version_minor;
* DJP 25-1-2001 */
float pg_version_number;
Int2 pg_version_major;
Int2 pg_version_minor;
}; };
/* Accessor functions */ /* Accessor functions */
#define CC_get_socket(x) (x->sock) #define CC_get_socket(x) (x->sock)
#define CC_get_database(x) (x->connInfo.database) #define CC_get_database(x) (x->connInfo.database)
#define CC_get_server(x) (x->connInfo.server) #define CC_get_server(x) (x->connInfo.server)
#define CC_get_DSN(x) (x->connInfo.dsn) #define CC_get_DSN(x) (x->connInfo.dsn)
#define CC_get_username(x) (x->connInfo.username) #define CC_get_username(x) (x->connInfo.username)
#define CC_is_onlyread(x) (x->connInfo.onlyread[0] == '1') #define CC_is_onlyread(x) (x->connInfo.onlyread[0] == '1')
/* 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(void); ConnectionClass *CC_Constructor(void);
char CC_Destructor(ConnectionClass *self); char CC_Destructor(ConnectionClass *self);
int CC_cursor_count(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);
int CC_set_translation(ConnectionClass *self); int CC_set_translation (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);
char CC_get_error(ConnectionClass *self, int *number, char **message); char CC_get_error(ConnectionClass *self, int *number, char **message);
QResultClass *CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi); QResultClass *CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi);
void CC_clear_error(ConnectionClass *self); void CC_clear_error(ConnectionClass *self);
char *CC_create_errormsg(ConnectionClass *self); char *CC_create_errormsg(ConnectionClass *self);
int CC_send_function(ConnectionClass *conn, int fnid, void *result_buf, int *actual_result_len, int result_is_int, LO_ARG *argv, int nargs); 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); char CC_send_settings(ConnectionClass *self);
void CC_lookup_lo(ConnectionClass *conn); void CC_lookup_lo(ConnectionClass *conn);
void CC_lookup_pg_version(ConnectionClass *conn); void CC_lookup_pg_version(ConnectionClass *conn);
void CC_initialize_pg_version(ConnectionClass *conn); void CC_initialize_pg_version(ConnectionClass *conn);
void CC_log_error(char *func, char *desc, ConnectionClass *self); void CC_log_error(char *func, char *desc, ConnectionClass *self);
#endif #endif
此差异已折叠。
/* 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.
* *
*/ */
...@@ -13,40 +13,39 @@ ...@@ -13,40 +13,39 @@
#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_GENERAL_ERROR 4
#define COPY_NO_DATA_FOUND 5 #define COPY_NO_DATA_FOUND 5
typedef struct typedef struct {
{ int m;
int m; int d;
int d; int y;
int y; int hh;
int hh; int mm;
int mm; int ss;
int ss;
} SIMPLE_TIME; } SIMPLE_TIME;
int copy_and_convert_field_bindinfo(StatementClass *stmt, Int4 field_type, void *value, int col); int copy_and_convert_field_bindinfo(StatementClass *stmt, Int4 field_type, void *value, int col);
int copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2 fCType, int copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2 fCType,
PTR rgbValue, SDWORD cbValueMax, SDWORD *pcbValue); PTR rgbValue, SDWORD cbValueMax, SDWORD *pcbValue);
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);
char parse_datetime(char *buf, SIMPLE_TIME *st); char parse_datetime(char *buf, SIMPLE_TIME *st);
int convert_linefeeds(char *s, char *dst, size_t max); int convert_linefeeds(char *s, char *dst, size_t max);
char *convert_special_chars(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);
void encode(char *in, char *out); void encode(char *in, char *out);
void decode(char *in, char *out); void decode(char *in, char *out);
int convert_lo(StatementClass *stmt, void *value, Int2 fCType, PTR rgbValue, int convert_lo(StatementClass *stmt, void *value, Int2 fCType, PTR rgbValue,
SDWORD cbValueMax, SDWORD *pcbValue); SDWORD cbValueMax, SDWORD *pcbValue);
#endif #endif
此差异已折叠。
/* File: dlg_specific.h /* File: dlg_specific.h
* *
* Description: See "dlg_specific.c" * Description: See "dlg_specific.c"
* *
* Comments: See "notice.txt" for copyright and license information. * Comments: See "notice.txt" for copyright and license information.
* *
*/ */
...@@ -31,50 +31,41 @@ ...@@ -31,50 +31,41 @@
/* INI File Stuff */ /* INI File Stuff */
#ifndef WIN32 #ifndef WIN32
#define ODBC_INI ".odbc.ini" # define ODBC_INI ".odbc.ini"
#ifdef ODBCINSTDIR # ifdef ODBCINSTDIR
#define ODBCINST_INI ODBCINSTDIR "/odbcinst.ini" # define ODBCINST_INI ODBCINSTDIR "/odbcinst.ini"
#else # else
#define ODBCINST_INI "/etc/odbcinst.ini" # define ODBCINST_INI "/etc/odbcinst.ini"
#warning "location of odbcinst.ini file defaulted to /etc" # warning "location of odbcinst.ini file defaulted to /etc"
#endif # endif
#else /* WIN32 */ #else /* WIN32 */
#define ODBC_INI "ODBC.INI" /* ODBC initialization file */ # define ODBC_INI "ODBC.INI" /* ODBC initialization file */
#define ODBCINST_INI "ODBCINST.INI" /* ODBC Installation file */ # define ODBCINST_INI "ODBCINST.INI" /* ODBC Installation file */
#endif /* WIN32 */ #endif /* WIN32 */
#define INI_DSN DBMS_NAME /* Name of default Datasource in #define INI_DSN DBMS_NAME /* Name of default Datasource in ini file (not used?) */
* ini file (not used?) */ #define INI_KDESC "Description" /* Data source description */
#define INI_KDESC "Description" /* Data source description */ #define INI_SERVER "Servername" /* Name of Server running the Postgres service */
#define INI_SERVER "Servername" /* Name of Server running #define INI_PORT "Port" /* Port on which the Postmaster is listening */
* the Postgres service */ #define INI_DATABASE "Database" /* Database Name */
#define INI_PORT "Port" /* Port on which the Postmaster is #define INI_USER "Username" /* Default User Name */
* listening */ #define INI_PASSWORD "Password" /* Default Password */
#define INI_DATABASE "Database" /* Database Name */ #define INI_DEBUG "Debug" /* Debug flag */
#define INI_USER "Username" /* Default User Name */ #define INI_FETCH "Fetch" /* Fetch Max Count */
#define INI_PASSWORD "Password" /* Default Password */ #define INI_SOCKET "Socket" /* Socket buffer size */
#define INI_DEBUG "Debug" /* Debug flag */ #define INI_READONLY "ReadOnly" /* Database is read only */
#define INI_FETCH "Fetch" /* Fetch Max Count */ #define INI_COMMLOG "CommLog" /* Communication to backend logging */
#define INI_SOCKET "Socket" /* Socket buffer size */ #define INI_PROTOCOL "Protocol" /* What protocol (6.2) */
#define INI_READONLY "ReadOnly" /* Database is read only */ #define INI_OPTIMIZER "Optimizer" /* Use backend genetic optimizer */
#define INI_COMMLOG "CommLog" /* Communication to backend #define INI_KSQO "Ksqo" /* Keyset query optimization */
* logging */ #define INI_CONNSETTINGS "ConnSettings" /* Anything to send to backend on successful connection */
#define INI_PROTOCOL "Protocol" /* What protocol (6.2) */ #define INI_UNIQUEINDEX "UniqueIndex" /* Recognize unique indexes */
#define INI_OPTIMIZER "Optimizer" /* Use backend genetic optimizer */ #define INI_UNKNOWNSIZES "UnknownSizes" /* How to handle unknown result set sizes */
#define INI_KSQO "Ksqo" /* Keyset query optimization */
#define INI_CONNSETTINGS "ConnSettings" /* Anything to send to #define INI_CANCELASFREESTMT "CancelAsFreeStmt"
* backend on successful
* connection */ #define INI_USEDECLAREFETCH "UseDeclareFetch" /* Use Declare/Fetch cursors */
#define INI_UNIQUEINDEX "UniqueIndex" /* Recognize unique
* indexes */
#define INI_UNKNOWNSIZES "UnknownSizes" /* How to handle unknown
* result set sizes */
#define INI_CANCELASFREESTMT "CancelAsFreeStmt"
#define INI_USEDECLAREFETCH "UseDeclareFetch" /* Use Declare/Fetch
* cursors */
/* More ini stuff */ /* More ini stuff */
#define INI_TEXTASLONGVARCHAR "TextAsLongVarchar" #define INI_TEXTASLONGVARCHAR "TextAsLongVarchar"
...@@ -91,16 +82,15 @@ ...@@ -91,16 +82,15 @@
#define INI_PARSE "Parse" #define INI_PARSE "Parse"
#define INI_EXTRASYSTABLEPREFIXES "ExtraSysTablePrefixes" #define INI_EXTRASYSTABLEPREFIXES "ExtraSysTablePrefixes"
#define INI_TRANSLATIONNAME "TranslationName" #define INI_TRANSLATIONNAME "TranslationName"
#define INI_TRANSLATIONDLL "TranslationDLL" #define INI_TRANSLATIONDLL "TranslationDLL"
#define INI_TRANSLATIONOPTION "TranslationOption" #define INI_TRANSLATIONOPTION "TranslationOption"
/* Connection Defaults */ /* Connection Defaults */
#define DEFAULT_PORT "5432" #define DEFAULT_PORT "5432"
#define DEFAULT_READONLY 1 #define DEFAULT_READONLY 1
#define DEFAULT_PROTOCOL "6.4" /* the latest protocol is #define DEFAULT_PROTOCOL "6.4" /* the latest protocol is the default */
* the default */
#define DEFAULT_USEDECLAREFETCH 0 #define DEFAULT_USEDECLAREFETCH 0
#define DEFAULT_TEXTASLONGVARCHAR 1 #define DEFAULT_TEXTASLONGVARCHAR 1
#define DEFAULT_UNKNOWNSASLONGVARCHAR 0 #define DEFAULT_UNKNOWNSASLONGVARCHAR 0
...@@ -124,30 +114,29 @@ ...@@ -124,30 +114,29 @@
#define DEFAULT_EXTRASYSTABLEPREFIXES "dd_;" #define DEFAULT_EXTRASYSTABLEPREFIXES "dd_;"
/* prototypes */ /* prototypes */
void getGlobalDefaults(char *section, char *filename, char override); void getGlobalDefaults(char *section, char *filename, char override);
#ifdef WIN32 #ifdef WIN32
void SetDlgStuff(HWND hdlg, ConnInfo *ci); void SetDlgStuff(HWND hdlg, ConnInfo *ci);
void GetDlgStuff(HWND hdlg, ConnInfo *ci); void GetDlgStuff(HWND hdlg, ConnInfo *ci);
int CALLBACK driver_optionsProc(HWND hdlg, int CALLBACK driver_optionsProc(HWND hdlg,
WORD wMsg, WORD wMsg,
WPARAM wParam, WPARAM wParam,
LPARAM lParam); LPARAM lParam);
int CALLBACK ds_optionsProc(HWND hdlg, int CALLBACK ds_optionsProc(HWND hdlg,
WORD wMsg, WORD wMsg,
WPARAM wParam, WPARAM wParam,
LPARAM lParam); LPARAM lParam);
#endif /* WIN32 */
#endif /* WIN32 */
void updateGlobals(void);
void updateGlobals(void); void writeDSNinfo(ConnInfo *ci);
void writeDSNinfo(ConnInfo *ci); void getDSNdefaults(ConnInfo *ci);
void getDSNdefaults(ConnInfo *ci); void getDSNinfo(ConnInfo *ci, char overwrite);
void getDSNinfo(ConnInfo *ci, char overwrite); void makeConnectString(char *connect_string, ConnInfo *ci);
void makeConnectString(char *connect_string, ConnInfo *ci); void copyAttributes(ConnInfo *ci, char *attribute, char *value);
void copyAttributes(ConnInfo *ci, char *attribute, char *value);
#endif #endif
此差异已折叠。
此差异已折叠。
/* 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.
* *
*/ */
...@@ -29,18 +29,17 @@ ...@@ -29,18 +29,17 @@
#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);
char EN_get_error(EnvironmentClass *self, int *number, char **message); char EN_get_error(EnvironmentClass *self, int *number, char **message);
char EN_add_connection(EnvironmentClass *self, ConnectionClass *conn); char EN_add_connection(EnvironmentClass *self, ConnectionClass *conn);
char EN_remove_connection(EnvironmentClass *self, ConnectionClass *conn); char EN_remove_connection(EnvironmentClass *self, ConnectionClass *conn);
void EN_log_error(char *func, char *desc, EnvironmentClass *self); void EN_log_error(char *func, char *desc, EnvironmentClass *self);
#endif #endif
此差异已折叠。
此差异已折叠。
...@@ -13,30 +13,25 @@ ...@@ -13,30 +13,25 @@
#endif #endif
#ifdef __cplusplus #ifdef __cplusplus
extern "C" extern "C" {
{
#endif #endif
DWORD GetPrivateProfileString(char *theSection, /* section name */ DWORD
char *theKey, /* search key name */ GetPrivateProfileString(char *theSection, /* section name */
char *theDefault, /* default value if not char *theKey, /* search key name */
* found */ char *theDefault, /* default value if not found */
char *theReturnBuffer, /* return valuse stored char *theReturnBuffer, /* return valuse stored here */
* here */ size_t theBufferLength, /* byte length of return buffer */
size_t theBufferLength, /* byte length of return char *theIniFileName); /* pathname of ini file to search */
* buffer */
char *theIniFileName); /* pathname of ini file
* to search */
DWORD WritePrivateProfileString(char *theSection, /* section name */ DWORD
char *theKey, /* write key name */ WritePrivateProfileString(char *theSection, /* section name */
char *theBuffer, /* input buffer */ char *theKey, /* write key name */
char *theIniFileName); /* pathname of ini file char *theBuffer, /* input buffer */
* to write */ char *theIniFileName); /* pathname of ini file to write */
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
#ifndef WIN32 #ifndef WIN32
......
此差异已折叠。
#ifndef _IODBC_H #ifndef _IODBC_H
#define _IODBC_H #define _IODBC_H
#if !defined(WIN32) && !defined(WIN32_SYSTEM) # if !defined(WIN32) && !defined(WIN32_SYSTEM)
#define _UNIX_ # define _UNIX_
#include <stdlib.h> # include <stdlib.h>
#include <sys/types.h> # include <sys/types.h>
#define MEM_ALLOC(size) (malloc((size_t)(size))) # define MEM_ALLOC(size) (malloc((size_t)(size)))
#define MEM_FREE(ptr) {if(ptr) free(ptr);} # define MEM_FREE(ptr) {if(ptr) free(ptr);}
#define STRCPY(t, s) (strcpy((char*)(t), (char*)(s))) # define STRCPY(t, s) (strcpy((char*)(t), (char*)(s)))
#define STRNCPY(t,s,n) (strncpy((char*)(t), (char*)(s), (size_t)(n))) # define STRNCPY(t,s,n) (strncpy((char*)(t), (char*)(s), (size_t)(n)))
#define STRCAT(t, s) (strcat((char*)(t), (char*)(s))) # define STRCAT(t, s) (strcat((char*)(t), (char*)(s)))
#define STRNCAT(t,s,n) (strncat((char*)(t), (char*)(s), (size_t)(n))) # define STRNCAT(t,s,n) (strncat((char*)(t), (char*)(s), (size_t)(n)))
#define STREQ(a, b) (strcmp((char*)(a), (char*)(b)) == 0) # define STREQ(a, b) (strcmp((char*)(a), (char*)(b)) == 0)
#define STRLEN(str) ((str)? strlen((char*)(str)):0) # define STRLEN(str) ((str)? strlen((char*)(str)):0)
#define EXPORT # define EXPORT
#define CALLBACK # define CALLBACK
#define FAR # define FAR
typedef signed short SSHOR; typedef signed short SSHOR;
typedef short WORD; typedef short WORD;
typedef long DWORD; typedef long DWORD;
typedef WORD WPARAM; typedef WORD WPARAM;
typedef DWORD LPARAM; typedef DWORD LPARAM;
typedef void *HWND; typedef void* HWND;
typedef int BOOL; typedef int BOOL;
#endif /* _UNIX_ */ # endif /* _UNIX_ */
#if defined(WIN32) || defined(WIN32_SYSTEM) # if defined(WIN32) || defined(WIN32_SYSTEM)
#include <windows.h> # include <windows.h>
#include <windowsx.h> # include <windowsx.h>
#ifdef _MSVC_ # ifdef _MSVC_
#define MEM_ALLOC(size) (fmalloc((size_t)(size))) # define MEM_ALLOC(size) (fmalloc((size_t)(size)))
#define MEM_FREE(ptr) ((ptr)? ffree((PTR)(ptr)):0)) # define MEM_FREE(ptr) ((ptr)? ffree((PTR)(ptr)):0))
#define STRCPY(t, s) (fstrcpy((char FAR*)(t), (char FAR*)(s))) # define STRCPY(t, s) (fstrcpy((char FAR*)(t), (char FAR*)(s)))
#define STRNCPY(t,s,n) (fstrncpy((char FAR*)(t), (char FAR*)(s), (size_t)(n))) # define STRNCPY(t,s,n) (fstrncpy((char FAR*)(t), (char FAR*)(s), (size_t)(n)))
#define STRLEN(str) ((str)? fstrlen((char FAR*)(str)):0) # define STRLEN(str) ((str)? fstrlen((char FAR*)(str)):0)
#define STREQ(a, b) (fstrcmp((char FAR*)(a), (char FAR*)(b) == 0) # define STREQ(a, b) (fstrcmp((char FAR*)(a), (char FAR*)(b) == 0)
#endif # endif
#ifdef _BORLAND_ # ifdef _BORLAND_
#define MEM_ALLOC(size) (farmalloc((unsigned long)(size)) # define MEM_ALLOC(size) (farmalloc((unsigned long)(size))
#define MEM_FREE(ptr) ((ptr)? farfree((void far*)(ptr)):0) # define MEM_FREE(ptr) ((ptr)? farfree((void far*)(ptr)):0)
#define STRCPY(t, s) (_fstrcpy((char FAR*)(t), (char FAR*)(s))) # define STRCPY(t, s) (_fstrcpy((char FAR*)(t), (char FAR*)(s)))
#define STRNCPY(t,s,n) (_fstrncpy((char FAR*)(t), (char FAR*)(s), (size_t)(n))) # define STRNCPY(t,s,n) (_fstrncpy((char FAR*)(t), (char FAR*)(s), (size_t)(n)))
#define STRLEN(str) ((str)? _fstrlen((char FAR*)(str)):0) # define STRLEN(str) ((str)? _fstrlen((char FAR*)(str)):0)
#define STREQ(a, b) (_fstrcmp((char FAR*)(a), (char FAR*)(b) == 0) # define STREQ(a, b) (_fstrcmp((char FAR*)(a), (char FAR*)(b) == 0)
#endif # endif
#endif /* WIN32 */ # endif /* WIN32 */
#define SYSERR (-1) # define SYSERR (-1)
#ifndef NULL # ifndef NULL
#define NULL ((void FAR*)0UL) # define NULL ((void FAR*)0UL)
#endif # endif
#endif #endif
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册