Commit 6df395f6 authored by Hiroshi Inoue's avatar Hiroshi Inoue

1) Add rollback functionality to updatable cursors.

2) Implement some options for SQLGetDescField().
3) Handle *Inifinity* timestamp for SQL_C_CHAR type output.
4) Separate Unicode conversions from common implementations.
5) Improve internal parse_statement() function.
parent 87b08080
...@@ -67,8 +67,8 @@ PGAPI_BindParameter( ...@@ -67,8 +67,8 @@ PGAPI_BindParameter(
opts->parameters[ipar].paramType = fParamType; opts->parameters[ipar].paramType = fParamType;
opts->parameters[ipar].CType = fCType; opts->parameters[ipar].CType = fCType;
opts->parameters[ipar].SQLType = fSqlType; opts->parameters[ipar].SQLType = fSqlType;
opts->parameters[ipar].precision = cbColDef; opts->parameters[ipar].column_size = cbColDef;
opts->parameters[ipar].scale = ibScale; opts->parameters[ipar].decimal_digits = ibScale;
/* /*
* If rebinding a parameter that had data-at-exec stuff in it, then * If rebinding a parameter that had data-at-exec stuff in it, then
...@@ -276,10 +276,10 @@ PGAPI_DescribeParam( ...@@ -276,10 +276,10 @@ PGAPI_DescribeParam(
*pfSqlType = opts->parameters[ipar].SQLType; *pfSqlType = opts->parameters[ipar].SQLType;
if (pcbColDef) if (pcbColDef)
*pcbColDef = opts->parameters[ipar].precision; *pcbColDef = opts->parameters[ipar].column_size;
if (pibScale) if (pibScale)
*pibScale = opts->parameters[ipar].scale; *pibScale = opts->parameters[ipar].decimal_digits;
if (pfNullable) if (pfNullable)
*pfNullable = pgtype_nullable(stmt, opts->parameters[ipar].paramType); *pfNullable = pgtype_nullable(stmt, opts->parameters[ipar].paramType);
...@@ -458,8 +458,8 @@ reset_a_parameter_binding(APDFields *self, int ipar) ...@@ -458,8 +458,8 @@ reset_a_parameter_binding(APDFields *self, int ipar)
self->parameters[ipar].EXEC_buffer = NULL; self->parameters[ipar].EXEC_buffer = NULL;
} }
self->parameters[ipar].SQLType = 0; self->parameters[ipar].SQLType = 0;
self->parameters[ipar].precision = 0; self->parameters[ipar].column_size = 0;
self->parameters[ipar].scale = 0; self->parameters[ipar].decimal_digits = 0;
self->parameters[ipar].data_at_exec = FALSE; self->parameters[ipar].data_at_exec = FALSE;
self->parameters[ipar].lobj_oid = 0; self->parameters[ipar].lobj_oid = 0;
} }
......
...@@ -40,8 +40,8 @@ struct ParameterInfoClass_ ...@@ -40,8 +40,8 @@ struct ParameterInfoClass_
Int2 paramType; Int2 paramType;
Int2 CType; Int2 CType;
Int2 SQLType; Int2 SQLType;
UInt4 precision; UInt4 column_size;
Int2 scale; Int2 decimal_digits;
Oid lobj_oid; Oid lobj_oid;
Int4 *EXEC_used; /* amount of data OR the oid of the large Int4 *EXEC_used; /* amount of data OR the oid of the large
* object */ * object */
......
...@@ -288,6 +288,7 @@ CC_Constructor() ...@@ -288,6 +288,7 @@ CC_Constructor()
rv->pg_version_minor = 0; rv->pg_version_minor = 0;
rv->ms_jet = 0; rv->ms_jet = 0;
rv->unicode = 0; rv->unicode = 0;
rv->result_uncommitted = 0;
#ifdef MULTIBYTE #ifdef MULTIBYTE
rv->client_encoding = NULL; rv->client_encoding = NULL;
rv->server_encoding = NULL; rv->server_encoding = NULL;
...@@ -1110,21 +1111,30 @@ CC_get_error(ConnectionClass *self, int *number, char **message) ...@@ -1110,21 +1111,30 @@ CC_get_error(ConnectionClass *self, int *number, char **message)
} }
void CC_on_commit(ConnectionClass *conn, BOOL set_no_trans) void CC_on_commit(ConnectionClass *conn)
{ {
if (CC_is_in_trans(conn)) if (CC_is_in_trans(conn))
{ {
if (set_no_trans) #ifdef DRIVER_CURSOR_IMPLEMENT
CC_set_no_trans(conn); if (conn->result_uncommitted)
ProcessRollback(conn, FALSE);
#endif /* DRIVER_CURSOR_IMPLEMENT */
CC_set_no_trans(conn);
} }
conn->result_uncommitted = 0;
} }
void CC_on_abort(ConnectionClass *conn, BOOL set_no_trans) void CC_on_abort(ConnectionClass *conn, BOOL set_no_trans)
{ {
if (CC_is_in_trans(conn)) if (CC_is_in_trans(conn))
{ {
#ifdef DRIVER_CURSOR_IMPLEMENT
if (conn->result_uncommitted)
ProcessRollback(conn, TRUE);
#endif /* DRIVER_CURSOR_IMPLEMENT */
if (set_no_trans) if (set_no_trans)
CC_set_no_trans(conn); CC_set_no_trans(conn);
} }
conn->result_uncommitted = 0;
} }
/* /*
...@@ -1293,11 +1303,11 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, UDWORD flag) ...@@ -1293,11 +1303,11 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, UDWORD flag)
} }
} }
else if (strnicmp(cmdbuffer, "COMMIT", 6) == 0) else if (strnicmp(cmdbuffer, "COMMIT", 6) == 0)
CC_on_commit(self, TRUE); CC_on_commit(self);
else if (strnicmp(cmdbuffer, "ROLLBACK", 8) == 0) else if (strnicmp(cmdbuffer, "ROLLBACK", 8) == 0)
CC_on_abort(self, TRUE); CC_on_abort(self, TRUE);
else if (strnicmp(cmdbuffer, "END", 3) == 0) else if (strnicmp(cmdbuffer, "END", 3) == 0)
CC_on_commit(self, TRUE); CC_on_commit(self);
else if (strnicmp(cmdbuffer, "ABORT", 5) == 0) else if (strnicmp(cmdbuffer, "ABORT", 5) == 0)
CC_on_abort(self, TRUE); CC_on_abort(self, TRUE);
......
...@@ -272,6 +272,7 @@ struct ConnectionClass_ ...@@ -272,6 +272,7 @@ struct ConnectionClass_
Int2 pg_version_minor; Int2 pg_version_minor;
char ms_jet; char ms_jet;
char unicode; char unicode;
char result_uncommitted;
#ifdef MULTIBYTE #ifdef MULTIBYTE
char *client_encoding; char *client_encoding;
char *server_encoding; char *server_encoding;
...@@ -318,8 +319,9 @@ void CC_lookup_pg_version(ConnectionClass *conn); ...@@ -318,8 +319,9 @@ 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(const char *func, const char *desc, const ConnectionClass *self); void CC_log_error(const char *func, const char *desc, const ConnectionClass *self);
int CC_get_max_query_len(const ConnectionClass *self); int CC_get_max_query_len(const ConnectionClass *self);
void CC_on_commit(ConnectionClass *conn, BOOL set_no_trans); void CC_on_commit(ConnectionClass *conn);
void CC_on_abort(ConnectionClass *conn, BOOL set_no_trans); void CC_on_abort(ConnectionClass *conn, BOOL set_no_trans);
void ProcessRollback(ConnectionClass *conn, BOOL undo);
/* CC_send_query_options */ /* CC_send_query_options */
#define CLEAR_RESULT_ON_ABORT 1L #define CLEAR_RESULT_ON_ABORT 1L
......
...@@ -265,6 +265,16 @@ stime2timestamp(const SIMPLE_TIME *st, char *str, BOOL bZone, BOOL precision) ...@@ -265,6 +265,16 @@ stime2timestamp(const SIMPLE_TIME *st, char *str, BOOL bZone, BOOL precision)
int i; int i;
precstr[0] = '\0'; precstr[0] = '\0';
if (st->infinity > 0)
{
strcpy(str, "Infinity");
return TRUE;
}
else if (st->infinity < 0)
{
strcpy(str, "-Infinity");
return TRUE;
}
if (precision && st->fr) if (precision && st->fr)
{ {
sprintf(precstr, ".%09d", st->fr); sprintf(precstr, ".%09d", st->fr);
...@@ -447,6 +457,27 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2 ...@@ -447,6 +457,27 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2
case PG_TYPE_DATETIME: case PG_TYPE_DATETIME:
case PG_TYPE_TIMESTAMP: case PG_TYPE_TIMESTAMP:
st.fr = 0; st.fr = 0;
st.infinity = 0;
if (strnicmp(value, "infinity", 8) == 0)
{
st.infinity = 1;
st.m = 12;
st.d = 31;
st.y = 9999;
st.hh = 24;
st.mm = 0;
st.ss = 0;
}
if (strnicmp(value, "-infinity", 9) == 0)
{
st.infinity = -1;
st.m = 0;
st.d = 0;
st.y = 0;
st.hh = 0;
st.mm = 0;
st.ss = 0;
}
if (strnicmp(value, "invalid", 7) != 0) if (strnicmp(value, "invalid", 7) != 0)
{ {
BOOL bZone = (field_type != PG_TYPE_TIMESTAMP_NO_TMZONE && PG_VERSION_GE(SC_get_conn(stmt), 7.2)); BOOL bZone = (field_type != PG_TYPE_TIMESTAMP_NO_TMZONE && PG_VERSION_GE(SC_get_conn(stmt), 7.2));
...@@ -2495,7 +2526,7 @@ convert_money(const char *s, char *sout, size_t soutmax) ...@@ -2495,7 +2526,7 @@ convert_money(const char *s, char *sout, size_t soutmax)
* It does not zero out SIMPLE_TIME in case it is desired to initialize it with a value * It does not zero out SIMPLE_TIME in case it is desired to initialize it with a value
*/ */
char char
parse_datetime(char *buf, SIMPLE_TIME *st) parse_datetime(const char *buf, SIMPLE_TIME *st)
{ {
int y, int y,
m, m,
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
typedef struct typedef struct
{ {
int infinity;
int m; int m;
int d; int d;
int y; int y;
...@@ -42,7 +43,7 @@ int copy_statement_with_parameters(StatementClass *stmt); ...@@ -42,7 +43,7 @@ int copy_statement_with_parameters(StatementClass *stmt);
int convert_escape(const char *value, StatementClass *stmt, int convert_escape(const char *value, StatementClass *stmt,
int *npos, int *stsize, const char **val_resume); int *npos, int *stsize, const char **val_resume);
BOOL convert_money(const char *s, char *sout, size_t soutmax); BOOL convert_money(const char *s, char *sout, size_t soutmax);
char parse_datetime(char *buf, SIMPLE_TIME *st); char parse_datetime(const char *buf, SIMPLE_TIME *st);
int convert_linefeeds(const char *s, char *dst, size_t max, BOOL convlf, BOOL *changed); int convert_linefeeds(const char *s, char *dst, size_t max, BOOL convlf, BOOL *changed);
int convert_special_chars(const char *si, char *dst, int used, BOOL convlf,int ccsc); int convert_special_chars(const char *si, char *dst, int used, BOOL convlf,int ccsc);
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
* *
* Comments: See "notice.txt" for copyright and license information. * Comments: See "notice.txt" for copyright and license information.
* *
* $Id: descriptor.h,v 1.1 2002/03/28 08:08:02 inoue Exp $ * $Id: descriptor.h,v 1.2 2002/04/01 03:01:14 inoue Exp $
* *
*/ */
...@@ -92,5 +92,8 @@ void IRDFields_free(IRDFields *self); ...@@ -92,5 +92,8 @@ void IRDFields_free(IRDFields *self);
void IPDFields_free(IPDFields *self); void IPDFields_free(IPDFields *self);
void ARD_unbind_cols(ARDFields *self, BOOL freeall); void ARD_unbind_cols(ARDFields *self, BOOL freeall);
void APD_free_params(APDFields *self, char option); void APD_free_params(APDFields *self, char option);
#if (ODBCVER >= 0x0300)
void Desc_set_error(SQLHDESC hdesc, int errornumber, const char * errormsg);
#endif /* ODBCVER */
#endif #endif
...@@ -235,7 +235,8 @@ SQLGetDiagField(SQLSMALLINT HandleType, SQLHANDLE Handle, ...@@ -235,7 +235,8 @@ SQLGetDiagField(SQLSMALLINT HandleType, SQLHANDLE Handle,
SQLSMALLINT *StringLength) SQLSMALLINT *StringLength)
{ {
mylog("[[SQLGetDiagField]] Handle=(%u,%x) Rec=%d Id=%d\n", HandleType, Handle, RecNumber, DiagIdentifier); mylog("[[SQLGetDiagField]] Handle=(%u,%x) Rec=%d Id=%d\n", HandleType, Handle, RecNumber, DiagIdentifier);
return SQL_ERROR; return PGAPI_GetDiagField(HandleType, Handle, RecNumber, DiagIdentifier,
DiagInfo, BufferLength, StringLength);
} }
/* SQLError -> SQLDiagRec */ /* SQLError -> SQLDiagRec */
......
...@@ -89,10 +89,25 @@ SQLSetDescFieldW(SQLHDESC DescriptorHandle, SQLSMALLINT RecNumber, ...@@ -89,10 +89,25 @@ SQLSetDescFieldW(SQLHDESC DescriptorHandle, SQLSMALLINT RecNumber,
mylog("[SQLSetDescFieldW]"); mylog("[SQLSetDescFieldW]");
if (BufferLength > 0) if (BufferLength > 0)
{ {
uval = ucs2_to_utf8(Value, BufferLength / 2, &vallen); switch (FieldIdentifier)
val_alloced = TRUE; {
case SQL_DESC_BASE_COLUMN_NAME:
case SQL_DESC_BASE_TABLE_NAME:
case SQL_DESC_CATALOG_NAME:
case SQL_DESC_LABEL:
case SQL_DESC_LITERAL_PREFIX:
case SQL_DESC_LITERAL_SUFFIX:
case SQL_DESC_LOCAL_TYPE_NAME:
case SQL_DESC_NAME:
case SQL_DESC_SCHEMA_NAME:
case SQL_DESC_TABLE_NAME:
case SQL_DESC_TYPE_NAME:
uval = ucs2_to_utf8(Value, BufferLength / 2, &vallen);
val_alloced = TRUE;
break;
}
} }
else if (!val_alloced)
{ {
uval = Value; uval = Value;
vallen = BufferLength; vallen = BufferLength;
...@@ -109,11 +124,49 @@ SQLGetDescFieldW(SQLHDESC hdesc, SQLSMALLINT iRecord, SQLSMALLINT iField, ...@@ -109,11 +124,49 @@ SQLGetDescFieldW(SQLHDESC hdesc, SQLSMALLINT iRecord, SQLSMALLINT iField,
SQLINTEGER *pcbValue) SQLINTEGER *pcbValue)
{ {
RETCODE ret; RETCODE ret;
char *qstr = NULL, *mtxt = NULL; BOOL alloced = FALSE;
SQLINTEGER blen, bMax, *pcbV;
char *rgbV = NULL;
mylog("[SQLGetDescFieldW]"); mylog("[SQLGetDescFieldW]");
ret = PGAPI_GetDescField(hdesc, iRecord, iField, rgbValue, switch (iField)
cbValueMax, pcbValue); {
case SQL_DESC_BASE_COLUMN_NAME:
case SQL_DESC_BASE_TABLE_NAME:
case SQL_DESC_CATALOG_NAME:
case SQL_DESC_LABEL:
case SQL_DESC_LITERAL_PREFIX:
case SQL_DESC_LITERAL_SUFFIX:
case SQL_DESC_LOCAL_TYPE_NAME:
case SQL_DESC_NAME:
case SQL_DESC_SCHEMA_NAME:
case SQL_DESC_TABLE_NAME:
case SQL_DESC_TYPE_NAME:
alloced = TRUE;
bMax = cbValueMax * 3 / 2;
rgbV = malloc(bMax + 1);
pcbV = &blen;
break;
default:
rgbV = rgbValue;
bMax = cbValueMax;
pcbV = pcbValue;
break;
}
ret = PGAPI_GetDescField(hdesc, iRecord, iField, rgbV, bMax, pcbV);
if (alloced)
{
blen = utf8_to_ucs2(rgbV, blen, (SQLWCHAR *) rgbValue, cbValueMax / 2);
if (SQL_SUCCESS == ret && blen * 2 > cbValueMax)
{
ret = SQL_SUCCESS_WITH_INFO;
Desc_set_error(hdesc, STMT_TRUNCATED, "The buffer was too small for the rgbDesc.");
}
if (pcbValue)
*pcbValue = blen * 2;
free(rgbV);
}
return ret; return ret;
} }
...@@ -171,6 +224,9 @@ RETCODE SQL_API SQLColAttributeW( ...@@ -171,6 +224,9 @@ RETCODE SQL_API SQLColAttributeW(
SQLINTEGER *pfDesc) SQLINTEGER *pfDesc)
{ {
RETCODE ret; RETCODE ret;
BOOL alloced = FALSE;
SQLSMALLINT *rgbL, blen, bMax;
char *rgbD = NULL;
mylog("[SQLColAttributeW]"); mylog("[SQLColAttributeW]");
switch (fDescType) switch (fDescType)
...@@ -187,11 +243,35 @@ RETCODE SQL_API SQLColAttributeW( ...@@ -187,11 +243,35 @@ RETCODE SQL_API SQLColAttributeW(
case SQL_DESC_TABLE_NAME: case SQL_DESC_TABLE_NAME:
case SQL_DESC_TYPE_NAME: case SQL_DESC_TYPE_NAME:
case SQL_COLUMN_NAME: case SQL_COLUMN_NAME:
alloced = TRUE;
bMax = cbDescMax * 3 / 2;
rgbD = malloc(bMax + 1);
rgbL = &blen;
break; break;
default:
rgbD = rgbDesc;
bMax = cbDescMax;
rgbL = pcbDesc;
break;
} }
ret = PGAPI_ColAttributes(hstmt, icol, fDescType, rgbDesc, ret = PGAPI_ColAttributes(hstmt, icol, fDescType, rgbD,
cbDescMax, pcbDesc, pfDesc); bMax, rgbL, pfDesc);
if (alloced)
{
blen = utf8_to_ucs2(rgbD, blen, (SQLWCHAR *) rgbDesc, cbDescMax / 2);
if (SQL_SUCCESS == ret && blen * 2 > cbDescMax)
{
StatementClass *stmt = (StatementClass *) hstmt;
ret = SQL_SUCCESS_WITH_INFO;
stmt->errornumber = STMT_TRUNCATED;
stmt->errormsg = "The buffer was too small for the rgbDesc.";
}
if (pcbDesc)
*pcbDesc = blen * 2;
free(rgbD);
}
return ret; return ret;
} }
...@@ -304,7 +304,8 @@ parse_statement(StatementClass *stmt) ...@@ -304,7 +304,8 @@ parse_statement(StatementClass *stmt)
in_on = FALSE, in_on = FALSE,
in_from = FALSE, in_from = FALSE,
in_where = FALSE, in_where = FALSE,
in_table = FALSE; in_table = FALSE,
out_table = TRUE;
char in_field = FALSE, char in_field = FALSE,
in_expr = FALSE, in_expr = FALSE,
in_func = FALSE, in_func = FALSE,
...@@ -610,12 +611,21 @@ parse_statement(StatementClass *stmt) ...@@ -610,12 +611,21 @@ parse_statement(StatementClass *stmt)
if (in_from) if (in_from)
{ {
if (!in_table) if (token[0] == ';')
{ {
if (!token[0]) in_from = FALSE;
break;
}
switch (token[0])
{
case '\0':
continue; continue;
if (token[0] == ';') case ',':
break; out_table = TRUE;
continue;
}
if (out_table && !in_table) /* new table */
{
if (!(stmt->ntab % TAB_INCR)) if (!(stmt->ntab % TAB_INCR))
{ {
...@@ -660,22 +670,47 @@ parse_statement(StatementClass *stmt) ...@@ -660,22 +670,47 @@ parse_statement(StatementClass *stmt)
mylog("got table = '%s'\n", ti[stmt->ntab]->name); mylog("got table = '%s'\n", ti[stmt->ntab]->name);
if (delim == ',') if (delim == ',')
{
out_table = TRUE;
mylog("more than 1 tables\n"); mylog("more than 1 tables\n");
}
else else
{
out_table = FALSE;
in_table = TRUE; in_table = TRUE;
}
stmt->ntab++; stmt->ntab++;
continue; continue;
} }
if (token[0] == ';') if (!dquote && stricmp(token, "JOIN") == 0)
break; {
if (stricmp(token, "as")) in_table = FALSE;
out_table = TRUE;
continue;
}
if (in_table && stricmp(token, "as"))
{ {
if (!dquote)
{
if (stricmp(token, "LEFT") == 0 ||
stricmp(token, "RIGHT") == 0 ||
stricmp(token, "OUTER") == 0 ||
stricmp(token, "FULL") == 0 ||
stricmp(token, "ON") == 0)
{
in_table = FALSE;
continue;
}
}
strcpy(ti[stmt->ntab - 1]->alias, token); strcpy(ti[stmt->ntab - 1]->alias, token);
mylog("alias for table '%s' is '%s'\n", ti[stmt->ntab - 1]->name, ti[stmt->ntab - 1]->alias); mylog("alias for table '%s' is '%s'\n", ti[stmt->ntab - 1]->name, ti[stmt->ntab - 1]->alias);
in_table = FALSE; in_table = FALSE;
if (delim == ',') if (delim == ',')
{
out_table = TRUE;
mylog("more than 1 tables\n"); mylog("more than 1 tables\n");
}
} }
} /* in_from */ } /* in_from */
} }
......
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
#include "descriptor.h" #include "descriptor.h"
#include "pgapifunc.h" #include "pgapifunc.h"
static HSTMT statementHandleFromDescHandle(HSTMT, SQLINTEGER *descType); static HSTMT statementHandleFromDescHandle(SQLHDESC, SQLINTEGER *descType);
/* SQLError -> SQLDiagRec */ /* SQLError -> SQLDiagRec */
RETCODE SQL_API RETCODE SQL_API
PGAPI_GetDiagRec(SQLSMALLINT HandleType, SQLHANDLE Handle, PGAPI_GetDiagRec(SQLSMALLINT HandleType, SQLHANDLE Handle,
...@@ -75,7 +75,7 @@ PGAPI_GetDiagField(SQLSMALLINT HandleType, SQLHANDLE Handle, ...@@ -75,7 +75,7 @@ PGAPI_GetDiagField(SQLSMALLINT HandleType, SQLHANDLE Handle,
PTR DiagInfoPtr, SQLSMALLINT BufferLength, PTR DiagInfoPtr, SQLSMALLINT BufferLength,
SQLSMALLINT *StringLengthPtr) SQLSMALLINT *StringLengthPtr)
{ {
RETCODE ret = SQL_SUCCESS; RETCODE ret = SQL_ERROR;
static const char *func = "PGAPI_GetDiagField"; static const char *func = "PGAPI_GetDiagField";
mylog("%s entering rec=%d", func, RecNumber); mylog("%s entering rec=%d", func, RecNumber);
...@@ -122,6 +122,7 @@ PGAPI_GetDiagField(SQLSMALLINT HandleType, SQLHANDLE Handle, ...@@ -122,6 +122,7 @@ PGAPI_GetDiagField(SQLSMALLINT HandleType, SQLHANDLE Handle,
case SQL_DIAG_NUMBER: case SQL_DIAG_NUMBER:
case SQL_DIAG_RETURNCODE: case SQL_DIAG_RETURNCODE:
case SQL_DIAG_SERVER_NAME: case SQL_DIAG_SERVER_NAME:
break;
case SQL_DIAG_SQLSTATE: case SQL_DIAG_SQLSTATE:
break; break;
} }
...@@ -154,7 +155,12 @@ PGAPI_GetConnectAttr(HDBC ConnectionHandle, ...@@ -154,7 +155,12 @@ PGAPI_GetConnectAttr(HDBC ConnectionHandle,
*((SQLUINTEGER *) Value) = SQL_FALSE; *((SQLUINTEGER *) Value) = SQL_FALSE;
break; break;
case SQL_ATTR_CONNECTION_DEAD: case SQL_ATTR_CONNECTION_DEAD:
*((SQLUINTEGER *) Value) = SQL_CD_FALSE; if (CC_is_in_trans(conn))
*((SQLUINTEGER *) Value) = SQL_CD_FALSE;
else if (conn->num_stmts > 0)
*((SQLUINTEGER *) Value) = SQL_CD_FALSE;
else
*((SQLUINTEGER *) Value) = SQL_CD_FALSE;
break; break;
case SQL_ATTR_CONNECTION_TIMEOUT: case SQL_ATTR_CONNECTION_TIMEOUT:
*((SQLUINTEGER *) Value) = 0; *((SQLUINTEGER *) Value) = 0;
...@@ -172,7 +178,7 @@ PGAPI_GetConnectAttr(HDBC ConnectionHandle, ...@@ -172,7 +178,7 @@ PGAPI_GetConnectAttr(HDBC ConnectionHandle,
return ret; return ret;
} }
static HSTMT static SQLHDESC
descHandleFromStatementHandle(HSTMT StatementHandle, SQLINTEGER descType) descHandleFromStatementHandle(HSTMT StatementHandle, SQLINTEGER descType)
{ {
switch (descType) switch (descType)
...@@ -189,7 +195,7 @@ descHandleFromStatementHandle(HSTMT StatementHandle, SQLINTEGER descType) ...@@ -189,7 +195,7 @@ descHandleFromStatementHandle(HSTMT StatementHandle, SQLINTEGER descType)
return (HSTMT) 0; return (HSTMT) 0;
} }
static HSTMT static HSTMT
statementHandleFromDescHandle(HSTMT DescHandle, SQLINTEGER *descType) statementHandleFromDescHandle(SQLHDESC DescHandle, SQLINTEGER *descType)
{ {
SQLUINTEGER res = (SQLUINTEGER) DescHandle % 4; SQLUINTEGER res = (SQLUINTEGER) DescHandle % 4;
if (descType) if (descType)
...@@ -209,6 +215,19 @@ statementHandleFromDescHandle(HSTMT DescHandle, SQLINTEGER *descType) ...@@ -209,6 +215,19 @@ statementHandleFromDescHandle(HSTMT DescHandle, SQLINTEGER *descType)
return (HSTMT) ((SQLUINTEGER) DescHandle - res); return (HSTMT) ((SQLUINTEGER) DescHandle - res);
} }
void Desc_set_error(SQLHDESC hdesc, int errornumber, const char *errormsg)
{
SQLINTEGER descType;
HSTMT hstmt = statementHandleFromDescHandle(hdesc, &descType);
StatementClass *stmt;
if (!hstmt)
return;
stmt = (StatementClass *) hstmt;
stmt->errornumber = errornumber;
stmt->errormsg = errormsg; /* should be static */
}
static void column_bindings_set(ARDFields *opts, int cols, BOOL maxset) static void column_bindings_set(ARDFields *opts, int cols, BOOL maxset)
{ {
int i; int i;
...@@ -568,7 +587,7 @@ IPDSetField(StatementClass *stmt, SQLSMALLINT RecNumber, ...@@ -568,7 +587,7 @@ IPDSetField(StatementClass *stmt, SQLSMALLINT RecNumber,
apdopts->parameters[RecNumber - 1].paramType = (Int2) Value; apdopts->parameters[RecNumber - 1].paramType = (Int2) Value;
break; break;
case SQL_DESC_SCALE: case SQL_DESC_SCALE:
apdopts->parameters[RecNumber - 1].scale = (Int2) Value; apdopts->parameters[RecNumber - 1].decimal_digits = (Int2) Value;
break; break;
case SQL_DESC_ALLOC_TYPE: /* read-only */ case SQL_DESC_ALLOC_TYPE: /* read-only */
case SQL_DESC_CASE_SENSITIVE: /* read-only */ case SQL_DESC_CASE_SENSITIVE: /* read-only */
...@@ -599,7 +618,7 @@ ARDGetField(StatementClass *stmt, SQLSMALLINT RecNumber, ...@@ -599,7 +618,7 @@ ARDGetField(StatementClass *stmt, SQLSMALLINT RecNumber,
SQLINTEGER *StringLength) SQLINTEGER *StringLength)
{ {
RETCODE ret = SQL_SUCCESS; RETCODE ret = SQL_SUCCESS;
SQLINTEGER len, ival; SQLINTEGER len, ival, rettype = 0;
PTR ptr = NULL; PTR ptr = NULL;
const ARDFields *opts = SC_get_ARD(stmt); const ARDFields *opts = SC_get_ARD(stmt);
...@@ -610,9 +629,11 @@ ARDGetField(StatementClass *stmt, SQLSMALLINT RecNumber, ...@@ -610,9 +629,11 @@ ARDGetField(StatementClass *stmt, SQLSMALLINT RecNumber,
ival = opts->rowset_size; ival = opts->rowset_size;
break; break;
case SQL_DESC_ARRAY_STATUS_PTR: case SQL_DESC_ARRAY_STATUS_PTR:
rettype = SQL_IS_POINTER;
ptr = opts->row_operation_ptr; ptr = opts->row_operation_ptr;
break; break;
case SQL_DESC_BIND_OFFSET_PTR: case SQL_DESC_BIND_OFFSET_PTR:
rettype = SQL_IS_POINTER;
ptr = opts->row_offset_ptr; ptr = opts->row_offset_ptr;
break; break;
case SQL_DESC_BIND_TYPE: case SQL_DESC_BIND_TYPE:
...@@ -651,6 +672,7 @@ ARDGetField(StatementClass *stmt, SQLSMALLINT RecNumber, ...@@ -651,6 +672,7 @@ ARDGetField(StatementClass *stmt, SQLSMALLINT RecNumber,
ival = opts->bindings[RecNumber - 1].returntype; ival = opts->bindings[RecNumber - 1].returntype;
break; break;
case SQL_DESC_DATA_PTR: case SQL_DESC_DATA_PTR:
rettype = SQL_IS_POINTER;
if (!RecNumber) if (!RecNumber)
ptr = opts->bookmark->buffer; ptr = opts->bookmark->buffer;
else else
...@@ -659,6 +681,7 @@ ARDGetField(StatementClass *stmt, SQLSMALLINT RecNumber, ...@@ -659,6 +681,7 @@ ARDGetField(StatementClass *stmt, SQLSMALLINT RecNumber,
} }
break; break;
case SQL_DESC_INDICATOR_PTR: case SQL_DESC_INDICATOR_PTR:
rettype = SQL_IS_POINTER;
if (!RecNumber) if (!RecNumber)
ptr = opts->bookmark->used; ptr = opts->bookmark->used;
else else
...@@ -667,6 +690,7 @@ ARDGetField(StatementClass *stmt, SQLSMALLINT RecNumber, ...@@ -667,6 +690,7 @@ ARDGetField(StatementClass *stmt, SQLSMALLINT RecNumber,
} }
break; break;
case SQL_DESC_OCTET_LENGTH_PTR: case SQL_DESC_OCTET_LENGTH_PTR:
rettype = SQL_IS_POINTER;
if (!RecNumber) if (!RecNumber)
ptr = opts->bookmark->used; ptr = opts->bookmark->used;
else else
...@@ -694,25 +718,13 @@ ARDGetField(StatementClass *stmt, SQLSMALLINT RecNumber, ...@@ -694,25 +718,13 @@ ARDGetField(StatementClass *stmt, SQLSMALLINT RecNumber,
default:ret = SQL_ERROR; default:ret = SQL_ERROR;
stmt->errornumber = STMT_INVALID_DESCRIPTOR_IDENTIFIER; stmt->errornumber = STMT_INVALID_DESCRIPTOR_IDENTIFIER;
} }
switch (BufferLength) switch (rettype)
{ {
case 0: case 0:
case SQL_IS_INTEGER: case SQL_IS_INTEGER:
len = 4; len = 4;
*((SQLINTEGER *) Value) = ival; *((SQLINTEGER *) Value) = ival;
break; break;
case SQL_IS_UINTEGER:
len = 4;
*((UInt4 *) Value) = ival;
break;
case SQL_IS_SMALLINT:
len = 2;
*((SQLSMALLINT *) Value) = (SQLSMALLINT) ival;
break;
case SQL_IS_USMALLINT:
len = 2;
*((SQLUSMALLINT *) Value) = (SQLUSMALLINT) ival;
break;
case SQL_IS_POINTER: case SQL_IS_POINTER:
len = 4; len = 4;
*((void **) Value) = ptr; *((void **) Value) = ptr;
...@@ -730,7 +742,7 @@ APDGetField(StatementClass *stmt, SQLSMALLINT RecNumber, ...@@ -730,7 +742,7 @@ APDGetField(StatementClass *stmt, SQLSMALLINT RecNumber,
SQLINTEGER *StringLength) SQLINTEGER *StringLength)
{ {
RETCODE ret = SQL_SUCCESS; RETCODE ret = SQL_SUCCESS;
SQLINTEGER ival = 0, len; SQLINTEGER ival = 0, len, rettype = 0;
PTR ptr = NULL; PTR ptr = NULL;
const APDFields *opts = SC_get_APD(stmt); const APDFields *opts = SC_get_APD(stmt);
...@@ -738,12 +750,15 @@ APDGetField(StatementClass *stmt, SQLSMALLINT RecNumber, ...@@ -738,12 +750,15 @@ APDGetField(StatementClass *stmt, SQLSMALLINT RecNumber,
switch (FieldIdentifier) switch (FieldIdentifier)
{ {
case SQL_DESC_ARRAY_SIZE: case SQL_DESC_ARRAY_SIZE:
rettype = SQL_IS_POINTER;
ival = opts->paramset_size; ival = opts->paramset_size;
break; break;
case SQL_DESC_ARRAY_STATUS_PTR: case SQL_DESC_ARRAY_STATUS_PTR:
rettype = SQL_IS_POINTER;
ptr = opts->param_operation_ptr; ptr = opts->param_operation_ptr;
break; break;
case SQL_DESC_BIND_OFFSET_PTR: case SQL_DESC_BIND_OFFSET_PTR:
rettype = SQL_IS_POINTER;
ptr = opts->param_offset_ptr; ptr = opts->param_offset_ptr;
break; break;
case SQL_DESC_BIND_TYPE: case SQL_DESC_BIND_TYPE:
...@@ -783,15 +798,18 @@ APDGetField(StatementClass *stmt, SQLSMALLINT RecNumber, ...@@ -783,15 +798,18 @@ APDGetField(StatementClass *stmt, SQLSMALLINT RecNumber,
ival = opts->parameters[RecNumber - 1].CType; ival = opts->parameters[RecNumber - 1].CType;
break; break;
case SQL_DESC_DATA_PTR: case SQL_DESC_DATA_PTR:
rettype = SQL_IS_POINTER;
ptr = opts->parameters[RecNumber - 1].buffer; ptr = opts->parameters[RecNumber - 1].buffer;
break; break;
case SQL_DESC_INDICATOR_PTR: case SQL_DESC_INDICATOR_PTR:
rettype = SQL_IS_POINTER;
ptr = opts->parameters[RecNumber - 1].used; ptr = opts->parameters[RecNumber - 1].used;
break; break;
case SQL_DESC_OCTET_LENGTH: case SQL_DESC_OCTET_LENGTH:
ival = opts->parameters[RecNumber - 1].buflen; ival = opts->parameters[RecNumber - 1].buflen;
break; break;
case SQL_DESC_OCTET_LENGTH_PTR: case SQL_DESC_OCTET_LENGTH_PTR:
rettype = SQL_IS_POINTER;
ptr = opts->parameters[RecNumber - 1].used; ptr = opts->parameters[RecNumber - 1].used;
break; break;
case SQL_DESC_COUNT: case SQL_DESC_COUNT:
...@@ -800,33 +818,21 @@ APDGetField(StatementClass *stmt, SQLSMALLINT RecNumber, ...@@ -800,33 +818,21 @@ APDGetField(StatementClass *stmt, SQLSMALLINT RecNumber,
case SQL_DESC_ALLOC_TYPE: /* read-only */ case SQL_DESC_ALLOC_TYPE: /* read-only */
ival = SQL_DESC_ALLOC_AUTO; ival = SQL_DESC_ALLOC_AUTO;
break; break;
case SQL_DESC_PRECISION:
case SQL_DESC_SCALE:
case SQL_DESC_DATETIME_INTERVAL_PRECISION: case SQL_DESC_DATETIME_INTERVAL_PRECISION:
case SQL_DESC_LENGTH: case SQL_DESC_LENGTH:
case SQL_DESC_NUM_PREC_RADIX: case SQL_DESC_NUM_PREC_RADIX:
case SQL_DESC_PRECISION:
case SQL_DESC_SCALE:
default:ret = SQL_ERROR; default:ret = SQL_ERROR;
stmt->errornumber = STMT_INVALID_DESCRIPTOR_IDENTIFIER; stmt->errornumber = STMT_INVALID_DESCRIPTOR_IDENTIFIER;
} }
switch (BufferLength) switch (rettype)
{ {
case 0: case 0:
case SQL_IS_INTEGER: case SQL_IS_INTEGER:
len = 4; len = 4;
*((Int4 *) Value) = ival; *((Int4 *) Value) = ival;
break; break;
case SQL_IS_UINTEGER:
len = 4;
*((UInt4 *) Value) = ival;
break;
case SQL_IS_SMALLINT:
len = 2;
*((SQLSMALLINT *) Value) = (SQLSMALLINT) ival;
break;
case SQL_IS_USMALLINT:
len = 2;
*((SQLUSMALLINT *) Value) = (SQLUSMALLINT) ival;
break;
case SQL_IS_POINTER: case SQL_IS_POINTER:
len = 4; len = 4;
*((void **) Value) = ptr; *((void **) Value) = ptr;
...@@ -844,36 +850,33 @@ IRDGetField(StatementClass *stmt, SQLSMALLINT RecNumber, ...@@ -844,36 +850,33 @@ IRDGetField(StatementClass *stmt, SQLSMALLINT RecNumber,
SQLINTEGER *StringLength) SQLINTEGER *StringLength)
{ {
RETCODE ret = SQL_SUCCESS; RETCODE ret = SQL_SUCCESS;
SQLINTEGER ival = 0, len; SQLINTEGER ival = 0, len, rettype = 0;
PTR ptr = NULL; PTR ptr = NULL;
BOOL bCallColAtt = FALSE;
const IRDFields *opts = SC_get_IRD(stmt); const IRDFields *opts = SC_get_IRD(stmt);
switch (FieldIdentifier) switch (FieldIdentifier)
{ {
case SQL_DESC_ARRAY_STATUS_PTR: case SQL_DESC_ARRAY_STATUS_PTR:
rettype = SQL_IS_POINTER;
ptr = opts->rowStatusArray; ptr = opts->rowStatusArray;
break; break;
case SQL_DESC_ROWS_PROCESSED_PTR: case SQL_DESC_ROWS_PROCESSED_PTR:
rettype = SQL_IS_POINTER;
ptr = opts->rowsFetched; ptr = opts->rowsFetched;
break; break;
case SQL_DESC_ALLOC_TYPE: /* read-only */ case SQL_DESC_ALLOC_TYPE: /* read-only */
ival = SQL_DESC_ALLOC_AUTO;
break;
case SQL_DESC_COUNT: /* read-only */ case SQL_DESC_COUNT: /* read-only */
case SQL_DESC_AUTO_UNIQUE_VALUE: /* read-only */ case SQL_DESC_AUTO_UNIQUE_VALUE: /* read-only */
case SQL_DESC_BASE_COLUMN_NAME: /* read-only */
case SQL_DESC_BASE_TABLE_NAME: /* read-only */
case SQL_DESC_CASE_SENSITIVE: /* read-only */ case SQL_DESC_CASE_SENSITIVE: /* read-only */
case SQL_DESC_CATALOG_NAME: /* read-only */
case SQL_DESC_CONCISE_TYPE: /* read-only */ case SQL_DESC_CONCISE_TYPE: /* read-only */
case SQL_DESC_DATETIME_INTERVAL_CODE: /* read-only */ case SQL_DESC_DATETIME_INTERVAL_CODE: /* read-only */
case SQL_DESC_DATETIME_INTERVAL_PRECISION: /* read-only */ case SQL_DESC_DATETIME_INTERVAL_PRECISION: /* read-only */
case SQL_DESC_DISPLAY_SIZE: /* read-only */ case SQL_DESC_DISPLAY_SIZE: /* read-only */
case SQL_DESC_FIXED_PREC_SCALE: /* read-only */ case SQL_DESC_FIXED_PREC_SCALE: /* read-only */
case SQL_DESC_LABEL: /* read-only */
case SQL_DESC_LENGTH: /* read-only */ case SQL_DESC_LENGTH: /* read-only */
case SQL_DESC_LITERAL_PREFIX: /* read-only */
case SQL_DESC_LITERAL_SUFFIX: /* read-only */
case SQL_DESC_LOCAL_TYPE_NAME: /* read-only */
case SQL_DESC_NAME: /* read-only */
case SQL_DESC_NULLABLE: /* read-only */ case SQL_DESC_NULLABLE: /* read-only */
case SQL_DESC_NUM_PREC_RADIX: /* read-only */ case SQL_DESC_NUM_PREC_RADIX: /* read-only */
case SQL_DESC_OCTET_LENGTH: /* read-only */ case SQL_DESC_OCTET_LENGTH: /* read-only */
...@@ -882,18 +885,40 @@ IRDGetField(StatementClass *stmt, SQLSMALLINT RecNumber, ...@@ -882,18 +885,40 @@ IRDGetField(StatementClass *stmt, SQLSMALLINT RecNumber,
case SQL_DESC_ROWVER: /* read-only */ case SQL_DESC_ROWVER: /* read-only */
#endif /* ODBCVER */ #endif /* ODBCVER */
case SQL_DESC_SCALE: /* read-only */ case SQL_DESC_SCALE: /* read-only */
case SQL_DESC_SCHEMA_NAME: /* read-only */
case SQL_DESC_SEARCHABLE: /* read-only */ case SQL_DESC_SEARCHABLE: /* read-only */
case SQL_DESC_TABLE_NAME: /* read-only */
case SQL_DESC_TYPE: /* read-only */ case SQL_DESC_TYPE: /* read-only */
case SQL_DESC_TYPE_NAME: /* read-only */
case SQL_DESC_UNNAMED: /* read-only */ case SQL_DESC_UNNAMED: /* read-only */
case SQL_DESC_UNSIGNED: /* read-only */ case SQL_DESC_UNSIGNED: /* read-only */
case SQL_DESC_UPDATABLE: /* read-only */ case SQL_DESC_UPDATABLE: /* read-only */
bCallColAtt = TRUE;
break;
case SQL_DESC_BASE_COLUMN_NAME: /* read-only */
case SQL_DESC_BASE_TABLE_NAME: /* read-only */
case SQL_DESC_CATALOG_NAME: /* read-only */
case SQL_DESC_LABEL: /* read-only */
case SQL_DESC_LITERAL_PREFIX: /* read-only */
case SQL_DESC_LITERAL_SUFFIX: /* read-only */
case SQL_DESC_LOCAL_TYPE_NAME: /* read-only */
case SQL_DESC_NAME: /* read-only */
case SQL_DESC_SCHEMA_NAME: /* read-only */
case SQL_DESC_TABLE_NAME: /* read-only */
case SQL_DESC_TYPE_NAME: /* read-only */
rettype = SQL_NTS;
bCallColAtt = TRUE;
break;
default:ret = SQL_ERROR; default:ret = SQL_ERROR;
stmt->errornumber = STMT_INVALID_DESCRIPTOR_IDENTIFIER; stmt->errornumber = STMT_INVALID_DESCRIPTOR_IDENTIFIER;
} }
switch (BufferLength) if (bCallColAtt)
{
SQLSMALLINT pcbL;
ret = PGAPI_ColAttributes(stmt, RecNumber,
FieldIdentifier, Value, (SQLSMALLINT) BufferLength,
&pcbL, &ival);
len = pcbL;
}
switch (rettype)
{ {
case 0: case 0:
case SQL_IS_INTEGER: case SQL_IS_INTEGER:
...@@ -904,14 +929,6 @@ IRDGetField(StatementClass *stmt, SQLSMALLINT RecNumber, ...@@ -904,14 +929,6 @@ IRDGetField(StatementClass *stmt, SQLSMALLINT RecNumber,
len = 4; len = 4;
*((UInt4 *) Value) = ival; *((UInt4 *) Value) = ival;
break; break;
case SQL_IS_SMALLINT:
len = 2;
*((SQLSMALLINT *) Value) = (SQLSMALLINT) ival;
break;
case SQL_IS_USMALLINT:
len = 2;
*((SQLUSMALLINT *) Value) = (SQLUSMALLINT) ival;
break;
case SQL_IS_POINTER: case SQL_IS_POINTER:
len = 4; len = 4;
*((void **) Value) = ptr; *((void **) Value) = ptr;
...@@ -929,7 +946,7 @@ IPDGetField(StatementClass *stmt, SQLSMALLINT RecNumber, ...@@ -929,7 +946,7 @@ IPDGetField(StatementClass *stmt, SQLSMALLINT RecNumber,
SQLINTEGER *StringLength) SQLINTEGER *StringLength)
{ {
RETCODE ret = SQL_SUCCESS; RETCODE ret = SQL_SUCCESS;
SQLINTEGER ival = 0, len; SQLINTEGER ival = 0, len, rettype = 0;
PTR ptr = NULL; PTR ptr = NULL;
const IPDFields *ipdopts = SC_get_IPD(stmt); const IPDFields *ipdopts = SC_get_IPD(stmt);
const APDFields *apdopts = SC_get_APD(stmt); const APDFields *apdopts = SC_get_APD(stmt);
...@@ -937,9 +954,11 @@ IPDGetField(StatementClass *stmt, SQLSMALLINT RecNumber, ...@@ -937,9 +954,11 @@ IPDGetField(StatementClass *stmt, SQLSMALLINT RecNumber,
switch (FieldIdentifier) switch (FieldIdentifier)
{ {
case SQL_DESC_ARRAY_STATUS_PTR: case SQL_DESC_ARRAY_STATUS_PTR:
rettype = SQL_IS_POINTER;
ptr = ipdopts->param_status_ptr; ptr = ipdopts->param_status_ptr;
break; break;
case SQL_DESC_ROWS_PROCESSED_PTR: case SQL_DESC_ROWS_PROCESSED_PTR:
rettype = SQL_IS_POINTER;
ptr = ipdopts->param_processed_ptr; ptr = ipdopts->param_processed_ptr;
break; break;
case SQL_DESC_UNNAMED: /* only SQL_UNNAMED is allowed */ case SQL_DESC_UNNAMED: /* only SQL_UNNAMED is allowed */
...@@ -981,8 +1000,24 @@ IPDGetField(StatementClass *stmt, SQLSMALLINT RecNumber, ...@@ -981,8 +1000,24 @@ IPDGetField(StatementClass *stmt, SQLSMALLINT RecNumber,
case SQL_DESC_PARAMETER_TYPE: case SQL_DESC_PARAMETER_TYPE:
ival = apdopts->parameters[RecNumber - 1].paramType; ival = apdopts->parameters[RecNumber - 1].paramType;
break; break;
case SQL_DESC_PRECISION:
switch (apdopts->parameters[RecNumber - 1].CType)
{
case SQL_C_TYPE_DATE:
case SQL_C_TYPE_TIME:
case SQL_C_TYPE_TIMESTAMP:
case SQL_DATETIME:
ival = apdopts->parameters[RecNumber - 1].decimal_digits;
break;
}
break;
case SQL_DESC_SCALE: case SQL_DESC_SCALE:
ival = apdopts->parameters[RecNumber - 1].scale ; switch (apdopts->parameters[RecNumber - 1].CType)
{
case SQL_C_NUMERIC:
ival = apdopts->parameters[RecNumber - 1].decimal_digits;
break;
}
break; break;
case SQL_DESC_ALLOC_TYPE: /* read-only */ case SQL_DESC_ALLOC_TYPE: /* read-only */
ival = SQL_DESC_ALLOC_AUTO; ival = SQL_DESC_ALLOC_AUTO;
...@@ -996,7 +1031,6 @@ IPDGetField(StatementClass *stmt, SQLSMALLINT RecNumber, ...@@ -996,7 +1031,6 @@ IPDGetField(StatementClass *stmt, SQLSMALLINT RecNumber,
case SQL_DESC_NULLABLE: /* read-only */ case SQL_DESC_NULLABLE: /* read-only */
case SQL_DESC_NUM_PREC_RADIX: case SQL_DESC_NUM_PREC_RADIX:
case SQL_DESC_OCTET_LENGTH: case SQL_DESC_OCTET_LENGTH:
case SQL_DESC_PRECISION:
#if (ODBCVER >= 0x0350) #if (ODBCVER >= 0x0350)
case SQL_DESC_ROWVER: /* read-only */ case SQL_DESC_ROWVER: /* read-only */
#endif /* ODBCVER */ #endif /* ODBCVER */
...@@ -1005,25 +1039,13 @@ IPDGetField(StatementClass *stmt, SQLSMALLINT RecNumber, ...@@ -1005,25 +1039,13 @@ IPDGetField(StatementClass *stmt, SQLSMALLINT RecNumber,
default:ret = SQL_ERROR; default:ret = SQL_ERROR;
stmt->errornumber = STMT_INVALID_DESCRIPTOR_IDENTIFIER; stmt->errornumber = STMT_INVALID_DESCRIPTOR_IDENTIFIER;
} }
switch (BufferLength) switch (rettype)
{ {
case 0: case 0:
case SQL_IS_INTEGER: case SQL_IS_INTEGER:
len = 4; len = 4;
*((Int4 *) Value) = ival; *((Int4 *) Value) = ival;
break; break;
case SQL_IS_UINTEGER:
len = 4;
*((UInt4 *) Value) = ival;
break;
case SQL_IS_SMALLINT:
len = 2;
*((SQLSMALLINT *) Value) = (SQLSMALLINT) ival;
break;
case SQL_IS_USMALLINT:
len = 2;
*((SQLUSMALLINT *) Value) = (SQLUSMALLINT) ival;
break;
case SQL_IS_POINTER: case SQL_IS_POINTER:
len = 4; len = 4;
*((void **)Value) = ptr; *((void **)Value) = ptr;
......
...@@ -265,6 +265,10 @@ RETCODE SQL_API PGAPI_GetDiagRec(SQLSMALLINT HandleType, SQLHANDLE Handle, ...@@ -265,6 +265,10 @@ RETCODE SQL_API PGAPI_GetDiagRec(SQLSMALLINT HandleType, SQLHANDLE Handle,
SQLSMALLINT RecNumber, SQLCHAR *Sqlstate, SQLSMALLINT RecNumber, SQLCHAR *Sqlstate,
SQLINTEGER *NativeError, SQLCHAR *MessageText, SQLINTEGER *NativeError, SQLCHAR *MessageText,
SQLSMALLINT BufferLength, SQLSMALLINT *TextLength); SQLSMALLINT BufferLength, SQLSMALLINT *TextLength);
RETCODE SQL_API PGAPI_GetDiagField(SQLSMALLINT HandleType, SQLHANDLE Handle,
SQLSMALLINT RecNumber, SQLSMALLINT DiagIdentifier,
PTR DiagInfoPtr, SQLSMALLINT BufferLength,
SQLSMALLINT *StringLengthPtr);
RETCODE SQL_API PGAPI_GetConnectAttr(HDBC ConnectionHandle, RETCODE SQL_API PGAPI_GetConnectAttr(HDBC ConnectionHandle,
SQLINTEGER Attribute, PTR Value, SQLINTEGER Attribute, PTR Value,
SQLINTEGER BufferLength, SQLINTEGER *StringLength); SQLINTEGER BufferLength, SQLINTEGER *StringLength);
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
* *
* Comments: See "notice.txt" for copyright and license information. * Comments: See "notice.txt" for copyright and license information.
* *
* $Id: psqlodbc.h,v 1.61 2002/03/28 08:08:06 inoue Exp $ * $Id: psqlodbc.h,v 1.62 2002/04/01 03:01:15 inoue Exp $
* *
*/ */
......
...@@ -123,6 +123,7 @@ QR_Constructor() ...@@ -123,6 +123,7 @@ QR_Constructor()
rv->rowset_size = 1; rv->rowset_size = 1;
rv->haskeyset = 0; rv->haskeyset = 0;
rv->keyset = NULL; rv->keyset = NULL;
rv->rb_alloc = 0;
rv->rb_count = 0; rv->rb_count = 0;
rv->rollback = NULL; rv->rollback = NULL;
} }
...@@ -233,6 +234,7 @@ QR_free_memory(QResultClass *self) ...@@ -233,6 +234,7 @@ QR_free_memory(QResultClass *self)
if (self->rollback) if (self->rollback)
{ {
free(self->rollback); free(self->rollback);
self->rb_alloc = 0;
self->rb_count = 0; self->rb_count = 0;
self->rollback = NULL; self->rollback = NULL;
} }
......
...@@ -74,7 +74,8 @@ struct QResultClass_ ...@@ -74,7 +74,8 @@ struct QResultClass_
char aborted; /* was aborted? */ char aborted; /* was aborted? */
char haskeyset; /* this result contains keyset ? */ char haskeyset; /* this result contains keyset ? */
KeySet *keyset; KeySet *keyset;
UInt4 rb_count; /* count of rollback info */ UInt2 rb_alloc; /* count of allocated rollback info */
UInt2 rb_count; /* count of rollback info */
Rollback *rollback; Rollback *rollback;
}; };
......
...@@ -491,7 +491,7 @@ PGAPI_ColAttributes( ...@@ -491,7 +491,7 @@ PGAPI_ColAttributes(
return SQL_SUCCESS; return SQL_SUCCESS;
} }
if (stmt->parse_status != STMT_PARSE_FATAL && irdflds->fi && irdflds->fi[col_idx]) if (stmt->parse_status != STMT_PARSE_FATAL && irdflds->fi)
{ {
if (col_idx >= cols) if (col_idx >= cols)
{ {
...@@ -500,9 +500,12 @@ PGAPI_ColAttributes( ...@@ -500,9 +500,12 @@ PGAPI_ColAttributes(
SC_log_error(func, "", stmt); SC_log_error(func, "", stmt);
return SQL_ERROR; return SQL_ERROR;
} }
field_type = irdflds->fi[col_idx]->type; if (irdflds->fi[col_idx])
if (field_type > 0) {
parse_ok = TRUE; field_type = irdflds->fi[col_idx]->type;
if (field_type > 0)
parse_ok = TRUE;
}
} }
} }
...@@ -756,14 +759,6 @@ inolog("COLUMN_TYPE=%d\n", value); ...@@ -756,14 +759,6 @@ inolog("COLUMN_TYPE=%d\n", value);
if (rgbDesc) if (rgbDesc)
{ {
#ifdef UNICODE_SUPPORT
if (conn->unicode)
{
len = utf8_to_ucs2(p, len, (SQLWCHAR *) rgbDesc, cbDescMax / 2);
len *= 2;
}
else
#endif /* UNICODE_SUPPORT */
strncpy_null((char *) rgbDesc, p, (size_t) cbDescMax); strncpy_null((char *) rgbDesc, p, (size_t) cbDescMax);
if (len >= cbDescMax) if (len >= cbDescMax)
...@@ -1343,8 +1338,6 @@ PGAPI_ExtendedFetch( ...@@ -1343,8 +1338,6 @@ PGAPI_ExtendedFetch(
#endif /* DRIVER_CURSOR_IMPLEMENT */ #endif /* DRIVER_CURSOR_IMPLEMENT */
else else
*(rgfRowStatus + i) = SQL_ROW_SUCCESS; *(rgfRowStatus + i) = SQL_ROW_SUCCESS;
if (rgfRowStatus[i] != SQL_ROW_SUCCESS)
inolog("rgfRowStatus[%d]=%d\n", i, rgfRowStatus[i]);
} }
} }
...@@ -1426,6 +1419,121 @@ static void KeySetSet(const TupleField *tuple, int num_fields, KeySet *keyset) ...@@ -1426,6 +1419,121 @@ static void KeySetSet(const TupleField *tuple, int num_fields, KeySet *keyset)
sscanf(tuple[num_fields - 1].value, "%u", &keyset->oid); sscanf(tuple[num_fields - 1].value, "%u", &keyset->oid);
} }
static void AddRollback(ConnectionClass *conn, QResultClass *res, int index, const KeySet *keyset)
{
Rollback *rollback;
if (!res->rollback)
{
res->rb_count = 0;
res->rb_alloc = 10;
rollback = res->rollback = malloc(sizeof(Rollback) * res->rb_alloc);
}
else
{
if (res->rb_count >= res->rb_alloc)
{
res->rb_alloc *= 2;
if (rollback = realloc(res->rollback, sizeof(Rollback) * res->rb_alloc), !rollback)
{
res->rb_alloc = res->rb_count = 0;
return;
}
res->rollback = rollback;
}
rollback = res->rollback + res->rb_count;
}
rollback->index = index;
if (keyset)
{
rollback->blocknum = keyset[index].blocknum;
rollback->offset = keyset[index].offset;
}
else
{
rollback->offset = 0;
rollback->blocknum = 0;
}
conn->result_uncommitted = 1;
res->rb_count++;
}
static void DiscardRollback(QResultClass *res)
{
int i, index;
UWORD status;
Rollback *rollback;
KeySet *keyset;
if (0 == res->rb_count || NULL == res->rollback)
return;
rollback = res->rollback;
keyset = res->keyset;
for (i = 0; i < res->rb_count; i++)
{
index = rollback[i].index;
status = keyset[index].status;
keyset[index].status &= ~(CURS_SELF_DELETING | CURS_SELF_UPDATING | CURS_SELF_ADDING);
keyset[index].status |= ((status & (CURS_SELF_DELETING | CURS_SELF_UPDATING | CURS_SELF_ADDING)) << 3);
}
free(rollback);
res->rollback = NULL;
res->rb_count = res->rb_alloc = 0;
}
static void UndoRollback(QResultClass *res)
{
int i, index;
UWORD status;
Rollback *rollback;
KeySet *keyset;
if (0 == res->rb_count || NULL == res->rollback)
return;
rollback = res->rollback;
keyset = res->keyset;
for (i = res->rb_count - 1; i >= 0; i--)
{
index = rollback[i].index;
status = keyset[index].status;
if ((status & CURS_SELF_ADDING) != 0)
{
if (index < res->fcount)
res->fcount = index;
}
else
{
keyset[index].status &= ~(CURS_SELF_DELETING | CURS_SELF_UPDATING | CURS_SELF_ADDING | KEYSET_INFO_PUBLIC);
keyset[index].blocknum = rollback[i].blocknum;
keyset[index].offset = rollback[i].offset;
}
}
free(rollback);
res->rollback = NULL;
res->rb_count = res->rb_alloc = 0;
}
void ProcessRollback(ConnectionClass *conn, BOOL undo)
{
int i;
StatementClass *stmt;
QResultClass *res;
for (i = 0; i < conn->num_stmts; i++)
{
if (stmt = conn->stmts[i], !stmt)
continue;
for (res = SC_get_Result(stmt); res; res = res->next)
{
if (undo)
UndoRollback(res);
else
DiscardRollback(res);
}
}
}
#define LATEST_TUPLE_LOAD 1L #define LATEST_TUPLE_LOAD 1L
#define USE_INSERTED_TID (1L << 1) #define USE_INSERTED_TID (1L << 1)
static QResultClass * static QResultClass *
...@@ -1534,7 +1642,8 @@ SC_pos_reload(StatementClass *stmt, UWORD irow, UDWORD global_ridx, UWORD *count ...@@ -1534,7 +1642,8 @@ SC_pos_reload(StatementClass *stmt, UWORD irow, UDWORD global_ridx, UWORD *count
ret = SQL_SUCCESS_WITH_INFO; ret = SQL_SUCCESS_WITH_INFO;
if (stmt->options.cursor_type == SQL_CURSOR_KEYSET_DRIVEN) if (stmt->options.cursor_type == SQL_CURSOR_KEYSET_DRIVEN)
{ {
res->keyset[global_ridx].oid = 0; res->keyset[global_ridx].blocknum = 0;
res->keyset[global_ridx].offset = 0;
res->keyset[global_ridx].status |= SQL_ROW_DELETED; res->keyset[global_ridx].status |= SQL_ROW_DELETED;
} }
} }
...@@ -1670,6 +1779,7 @@ SC_pos_update(StatementClass *stmt, ...@@ -1670,6 +1779,7 @@ SC_pos_update(StatementClass *stmt,
num_cols, num_cols,
upd_cols; upd_cols;
QResultClass *res; QResultClass *res;
ConnectionClass *conn = SC_get_conn(stmt);
ARDFields *opts = SC_get_ARD(stmt); ARDFields *opts = SC_get_ARD(stmt);
IRDFields *irdflds = SC_get_IRD(stmt); IRDFields *irdflds = SC_get_IRD(stmt);
BindInfoClass *bindings = opts->bindings; BindInfoClass *bindings = opts->bindings;
...@@ -1735,7 +1845,7 @@ SC_pos_update(StatementClass *stmt, ...@@ -1735,7 +1845,7 @@ SC_pos_update(StatementClass *stmt,
sprintf(updstr, "%s where ctid = '(%u, %u)' and oid = %u", updstr, sprintf(updstr, "%s where ctid = '(%u, %u)' and oid = %u", updstr,
blocknum, pgoffset, oid); blocknum, pgoffset, oid);
mylog("updstr=%s\n", updstr); mylog("updstr=%s\n", updstr);
if (PGAPI_AllocStmt(SC_get_conn(stmt), &hstmt) != SQL_SUCCESS) if (PGAPI_AllocStmt(conn, &hstmt) != SQL_SUCCESS)
return SQL_ERROR; return SQL_ERROR;
qstmt = (StatementClass *) hstmt; qstmt = (StatementClass *) hstmt;
apdopts = SC_get_APD(qstmt); apdopts = SC_get_APD(qstmt);
...@@ -1788,8 +1898,11 @@ SC_pos_update(StatementClass *stmt, ...@@ -1788,8 +1898,11 @@ SC_pos_update(StatementClass *stmt,
} }
if (SQL_SUCCESS == ret && res->keyset) if (SQL_SUCCESS == ret && res->keyset)
{ {
if (CC_is_in_trans(SC_get_conn(stmt))) if (CC_is_in_trans(conn))
{
AddRollback(conn, res, global_ridx, res->keyset);
res->keyset[global_ridx].status |= (SQL_ROW_UPDATED | CURS_SELF_UPDATING); res->keyset[global_ridx].status |= (SQL_ROW_UPDATED | CURS_SELF_UPDATING);
}
else else
res->keyset[global_ridx].status |= (SQL_ROW_UPDATED | CURS_SELF_UPDATED); res->keyset[global_ridx].status |= (SQL_ROW_UPDATED | CURS_SELF_UPDATED);
} }
...@@ -1815,12 +1928,12 @@ SC_pos_delete(StatementClass *stmt, ...@@ -1815,12 +1928,12 @@ SC_pos_delete(StatementClass *stmt,
{ {
UWORD offset; UWORD offset;
QResultClass *res, *qres; QResultClass *res, *qres;
ConnectionClass *conn = SC_get_conn(stmt);
ARDFields *opts = SC_get_ARD(stmt); ARDFields *opts = SC_get_ARD(stmt);
IRDFields *irdflds = SC_get_IRD(stmt); IRDFields *irdflds = SC_get_IRD(stmt);
BindInfoClass *bindings = opts->bindings; BindInfoClass *bindings = opts->bindings;
char dltstr[4096]; char dltstr[4096];
RETCODE ret; RETCODE ret;
/*const char *oidval;*/
UInt4 oid, blocknum; UInt4 oid, blocknum;
mylog("POS DELETE ti=%x\n", stmt->ti); mylog("POS DELETE ti=%x\n", stmt->ti);
...@@ -1844,7 +1957,7 @@ SC_pos_delete(StatementClass *stmt, ...@@ -1844,7 +1957,7 @@ SC_pos_delete(StatementClass *stmt,
stmt->ti[0]->name, blocknum, offset, oid); stmt->ti[0]->name, blocknum, offset, oid);
mylog("dltstr=%s\n", dltstr); mylog("dltstr=%s\n", dltstr);
qres = CC_send_query(SC_get_conn(stmt), dltstr, NULL, CLEAR_RESULT_ON_ABORT); qres = CC_send_query(conn, dltstr, NULL, CLEAR_RESULT_ON_ABORT);
ret = SQL_SUCCESS; ret = SQL_SUCCESS;
if (qres && QR_command_successful(qres)) if (qres && QR_command_successful(qres))
{ {
...@@ -1881,8 +1994,11 @@ SC_pos_delete(StatementClass *stmt, ...@@ -1881,8 +1994,11 @@ SC_pos_delete(StatementClass *stmt,
QR_Destructor(qres); QR_Destructor(qres);
if (SQL_SUCCESS == ret && res->keyset) if (SQL_SUCCESS == ret && res->keyset)
{ {
if (CC_is_in_trans(SC_get_conn(stmt))) if (CC_is_in_trans(conn))
{
AddRollback(conn, res, global_ridx, res->keyset);
res->keyset[global_ridx].status |= (SQL_ROW_DELETED | CURS_SELF_DELETING); res->keyset[global_ridx].status |= (SQL_ROW_DELETED | CURS_SELF_DELETING);
}
else else
res->keyset[global_ridx].status |= (SQL_ROW_DELETED | CURS_SELF_DELETED); res->keyset[global_ridx].status |= (SQL_ROW_DELETED | CURS_SELF_DELETED);
} }
...@@ -1988,7 +2104,7 @@ SC_pos_add(StatementClass *stmt, ...@@ -1988,7 +2104,7 @@ SC_pos_add(StatementClass *stmt,
num_cols = irdflds->nfields; num_cols = irdflds->nfields;
conn = SC_get_conn(stmt); conn = SC_get_conn(stmt);
sprintf(addstr, "insert into \"%s\" (", stmt->ti[0]->name); sprintf(addstr, "insert into \"%s\" (", stmt->ti[0]->name);
if (PGAPI_AllocStmt(SC_get_conn(stmt), &hstmt) != SQL_SUCCESS) if (PGAPI_AllocStmt(conn, &hstmt) != SQL_SUCCESS)
return SQL_ERROR; return SQL_ERROR;
if (opts->row_offset_ptr) if (opts->row_offset_ptr)
offset = *opts->row_offset_ptr; offset = *opts->row_offset_ptr;
...@@ -2068,10 +2184,15 @@ SC_pos_add(StatementClass *stmt, ...@@ -2068,10 +2184,15 @@ SC_pos_add(StatementClass *stmt,
PGAPI_FreeStmt(hstmt, SQL_DROP); PGAPI_FreeStmt(hstmt, SQL_DROP);
if (SQL_SUCCESS == ret && res->keyset) if (SQL_SUCCESS == ret && res->keyset)
{ {
int global_ridx = res->fcount - 1;
if (CC_is_in_trans(conn)) if (CC_is_in_trans(conn))
res->keyset[res->fcount - 1].status |= (SQL_ROW_ADDED | CURS_SELF_ADDING); {
AddRollback(conn, res, global_ridx, NULL);
res->keyset[global_ridx].status |= (SQL_ROW_ADDED | CURS_SELF_ADDING);
}
else else
res->keyset[res->fcount - 1].status |= (SQL_ROW_ADDED | CURS_SELF_ADDED); res->keyset[global_ridx].status |= (SQL_ROW_ADDED | CURS_SELF_ADDED);
} }
#if (ODBCVER >= 0x0300) #if (ODBCVER >= 0x0300)
if (irdflds->rowStatusArray) if (irdflds->rowStatusArray)
......
...@@ -503,8 +503,8 @@ SC_recycle_statement(StatementClass *self) ...@@ -503,8 +503,8 @@ SC_recycle_statement(StatementClass *self)
int i; int i;
for (i = 0; i < self->ntab; i++) for (i = 0; i < self->ntab; i++)
if (self->ti) if (self->ti[i])
free(self->ti); free(self->ti[i]);
self->ti = NULL; self->ti = NULL;
self->ntab = 0; self->ntab = 0;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment