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.
opts->parameters[ipar].paramType = fParamType;
opts->parameters[ipar].CType = fCType;
opts->parameters[ipar].SQLType = fSqlType;
- opts->parameters[ipar].precision = cbColDef;
- opts->parameters[ipar].scale = ibScale;
+ opts->parameters[ipar].column_size = cbColDef;
+ opts->parameters[ipar].decimal_digits = ibScale;
/*
* If rebinding a parameter that had data-at-exec stuff in it, then
*pfSqlType = opts->parameters[ipar].SQLType;
if (pcbColDef)
- *pcbColDef = opts->parameters[ipar].precision;
+ *pcbColDef = opts->parameters[ipar].column_size;
if (pibScale)
- *pibScale = opts->parameters[ipar].scale;
+ *pibScale = opts->parameters[ipar].decimal_digits;
if (pfNullable)
*pfNullable = pgtype_nullable(stmt, opts->parameters[ipar].paramType);
self->parameters[ipar].EXEC_buffer = NULL;
}
self->parameters[ipar].SQLType = 0;
- self->parameters[ipar].precision = 0;
- self->parameters[ipar].scale = 0;
+ self->parameters[ipar].column_size = 0;
+ self->parameters[ipar].decimal_digits = 0;
self->parameters[ipar].data_at_exec = FALSE;
self->parameters[ipar].lobj_oid = 0;
}
Int2 paramType;
Int2 CType;
Int2 SQLType;
- UInt4 precision;
- Int2 scale;
+ UInt4 column_size;
+ Int2 decimal_digits;
Oid lobj_oid;
Int4 *EXEC_used; /* amount of data OR the oid of the large
* object */
rv->pg_version_minor = 0;
rv->ms_jet = 0;
rv->unicode = 0;
+ rv->result_uncommitted = 0;
#ifdef MULTIBYTE
rv->client_encoding = NULL;
rv->server_encoding = NULL;
}
-void CC_on_commit(ConnectionClass *conn, BOOL set_no_trans)
+void CC_on_commit(ConnectionClass *conn)
{
if (CC_is_in_trans(conn))
{
- if (set_no_trans)
- CC_set_no_trans(conn);
+#ifdef DRIVER_CURSOR_IMPLEMENT
+ 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)
{
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)
CC_set_no_trans(conn);
}
+ conn->result_uncommitted = 0;
}
/*
}
}
else if (strnicmp(cmdbuffer, "COMMIT", 6) == 0)
- CC_on_commit(self, TRUE);
+ CC_on_commit(self);
else if (strnicmp(cmdbuffer, "ROLLBACK", 8) == 0)
CC_on_abort(self, TRUE);
else if (strnicmp(cmdbuffer, "END", 3) == 0)
- CC_on_commit(self, TRUE);
+ CC_on_commit(self);
else if (strnicmp(cmdbuffer, "ABORT", 5) == 0)
CC_on_abort(self, TRUE);
Int2 pg_version_minor;
char ms_jet;
char unicode;
+ char result_uncommitted;
#ifdef MULTIBYTE
char *client_encoding;
char *server_encoding;
void CC_initialize_pg_version(ConnectionClass *conn);
void CC_log_error(const char *func, const char *desc, 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 ProcessRollback(ConnectionClass *conn, BOOL undo);
/* CC_send_query_options */
#define CLEAR_RESULT_ON_ABORT 1L
int i;
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)
{
sprintf(precstr, ".%09d", st->fr);
case PG_TYPE_DATETIME:
case PG_TYPE_TIMESTAMP:
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)
{
BOOL bZone = (field_type != PG_TYPE_TIMESTAMP_NO_TMZONE && PG_VERSION_GE(SC_get_conn(stmt), 7.2));
* It does not zero out SIMPLE_TIME in case it is desired to initialize it with a value
*/
char
-parse_datetime(char *buf, SIMPLE_TIME *st)
+parse_datetime(const char *buf, SIMPLE_TIME *st)
{
int y,
m,
typedef struct
{
+ int infinity;
int m;
int d;
int y;
int convert_escape(const char *value, StatementClass *stmt,
int *npos, int *stsize, const char **val_resume);
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_special_chars(const char *si, char *dst, int used, BOOL convlf,int ccsc);
*
* 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 $
*
*/
void IPDFields_free(IPDFields *self);
void ARD_unbind_cols(ARDFields *self, BOOL freeall);
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
SQLSMALLINT *StringLength)
{
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 */
mylog("[SQLSetDescFieldW]");
if (BufferLength > 0)
{
- uval = ucs2_to_utf8(Value, BufferLength / 2, &vallen);
- val_alloced = TRUE;
+ switch (FieldIdentifier)
+ {
+ 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;
vallen = BufferLength;
SQLINTEGER *pcbValue)
{
RETCODE ret;
- char *qstr = NULL, *mtxt = NULL;
+ BOOL alloced = FALSE;
+ SQLINTEGER blen, bMax, *pcbV;
+ char *rgbV = NULL;
mylog("[SQLGetDescFieldW]");
- ret = PGAPI_GetDescField(hdesc, iRecord, iField, rgbValue,
- cbValueMax, pcbValue);
+ switch (iField)
+ {
+ 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;
}
SQLINTEGER *pfDesc)
{
RETCODE ret;
+ BOOL alloced = FALSE;
+ SQLSMALLINT *rgbL, blen, bMax;
+ char *rgbD = NULL;
mylog("[SQLColAttributeW]");
switch (fDescType)
case SQL_DESC_TABLE_NAME:
case SQL_DESC_TYPE_NAME:
case SQL_COLUMN_NAME:
+ alloced = TRUE;
+ bMax = cbDescMax * 3 / 2;
+ rgbD = malloc(bMax + 1);
+ rgbL = &blen;
break;
+ default:
+ rgbD = rgbDesc;
+ bMax = cbDescMax;
+ rgbL = pcbDesc;
+ break;
}
- ret = PGAPI_ColAttributes(hstmt, icol, fDescType, rgbDesc,
- cbDescMax, pcbDesc, pfDesc);
+ ret = PGAPI_ColAttributes(hstmt, icol, fDescType, rgbD,
+ 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;
}
in_on = FALSE,
in_from = FALSE,
in_where = FALSE,
- in_table = FALSE;
+ in_table = FALSE,
+ out_table = TRUE;
char in_field = FALSE,
in_expr = FALSE,
in_func = FALSE,
if (in_from)
{
- if (!in_table)
+ if (token[0] == ';')
{
- if (!token[0])
+ in_from = FALSE;
+ break;
+ }
+ switch (token[0])
+ {
+ case '\0':
continue;
- if (token[0] == ';')
- break;
+ case ',':
+ out_table = TRUE;
+ continue;
+ }
+ if (out_table && !in_table) /* new table */
+ {
if (!(stmt->ntab % TAB_INCR))
{
mylog("got table = '%s'\n", ti[stmt->ntab]->name);
if (delim == ',')
+ {
+ out_table = TRUE;
mylog("more than 1 tables\n");
+ }
else
+ {
+ out_table = FALSE;
in_table = TRUE;
+ }
stmt->ntab++;
continue;
}
- if (token[0] == ';')
- break;
- if (stricmp(token, "as"))
+ if (!dquote && stricmp(token, "JOIN") == 0)
+ {
+ 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);
mylog("alias for table '%s' is '%s'\n", ti[stmt->ntab - 1]->name, ti[stmt->ntab - 1]->alias);
in_table = FALSE;
if (delim == ',')
+ {
+ out_table = TRUE;
mylog("more than 1 tables\n");
+ }
}
} /* in_from */
}
#include "descriptor.h"
#include "pgapifunc.h"
-static HSTMT statementHandleFromDescHandle(HSTMT, SQLINTEGER *descType);
+static HSTMT statementHandleFromDescHandle(SQLHDESC, SQLINTEGER *descType);
/* SQLError -> SQLDiagRec */
RETCODE SQL_API
PGAPI_GetDiagRec(SQLSMALLINT HandleType, SQLHANDLE Handle,
PTR DiagInfoPtr, SQLSMALLINT BufferLength,
SQLSMALLINT *StringLengthPtr)
{
- RETCODE ret = SQL_SUCCESS;
+ RETCODE ret = SQL_ERROR;
static const char *func = "PGAPI_GetDiagField";
mylog("%s entering rec=%d", func, RecNumber);
case SQL_DIAG_NUMBER:
case SQL_DIAG_RETURNCODE:
case SQL_DIAG_SERVER_NAME:
+ break;
case SQL_DIAG_SQLSTATE:
break;
}
*((SQLUINTEGER *) Value) = SQL_FALSE;
break;
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;
case SQL_ATTR_CONNECTION_TIMEOUT:
*((SQLUINTEGER *) Value) = 0;
return ret;
}
-static HSTMT
+static SQLHDESC
descHandleFromStatementHandle(HSTMT StatementHandle, SQLINTEGER descType)
{
switch (descType)
return (HSTMT) 0;
}
static HSTMT
-statementHandleFromDescHandle(HSTMT DescHandle, SQLINTEGER *descType)
+statementHandleFromDescHandle(SQLHDESC DescHandle, SQLINTEGER *descType)
{
SQLUINTEGER res = (SQLUINTEGER) DescHandle % 4;
if (descType)
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)
{
int i;
apdopts->parameters[RecNumber - 1].paramType = (Int2) Value;
break;
case SQL_DESC_SCALE:
- apdopts->parameters[RecNumber - 1].scale = (Int2) Value;
+ apdopts->parameters[RecNumber - 1].decimal_digits = (Int2) Value;
break;
case SQL_DESC_ALLOC_TYPE: /* read-only */
case SQL_DESC_CASE_SENSITIVE: /* read-only */
SQLINTEGER *StringLength)
{
RETCODE ret = SQL_SUCCESS;
- SQLINTEGER len, ival;
+ SQLINTEGER len, ival, rettype = 0;
PTR ptr = NULL;
const ARDFields *opts = SC_get_ARD(stmt);
ival = opts->rowset_size;
break;
case SQL_DESC_ARRAY_STATUS_PTR:
+ rettype = SQL_IS_POINTER;
ptr = opts->row_operation_ptr;
break;
case SQL_DESC_BIND_OFFSET_PTR:
+ rettype = SQL_IS_POINTER;
ptr = opts->row_offset_ptr;
break;
case SQL_DESC_BIND_TYPE:
ival = opts->bindings[RecNumber - 1].returntype;
break;
case SQL_DESC_DATA_PTR:
+ rettype = SQL_IS_POINTER;
if (!RecNumber)
ptr = opts->bookmark->buffer;
else
}
break;
case SQL_DESC_INDICATOR_PTR:
+ rettype = SQL_IS_POINTER;
if (!RecNumber)
ptr = opts->bookmark->used;
else
}
break;
case SQL_DESC_OCTET_LENGTH_PTR:
+ rettype = SQL_IS_POINTER;
if (!RecNumber)
ptr = opts->bookmark->used;
else
default:ret = SQL_ERROR;
stmt->errornumber = STMT_INVALID_DESCRIPTOR_IDENTIFIER;
}
- switch (BufferLength)
+ switch (rettype)
{
case 0:
case SQL_IS_INTEGER:
len = 4;
*((SQLINTEGER *) Value) = ival;
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:
len = 4;
*((void **) Value) = ptr;
SQLINTEGER *StringLength)
{
RETCODE ret = SQL_SUCCESS;
- SQLINTEGER ival = 0, len;
+ SQLINTEGER ival = 0, len, rettype = 0;
PTR ptr = NULL;
const APDFields *opts = SC_get_APD(stmt);
switch (FieldIdentifier)
{
case SQL_DESC_ARRAY_SIZE:
+ rettype = SQL_IS_POINTER;
ival = opts->paramset_size;
break;
case SQL_DESC_ARRAY_STATUS_PTR:
+ rettype = SQL_IS_POINTER;
ptr = opts->param_operation_ptr;
break;
case SQL_DESC_BIND_OFFSET_PTR:
+ rettype = SQL_IS_POINTER;
ptr = opts->param_offset_ptr;
break;
case SQL_DESC_BIND_TYPE:
ival = opts->parameters[RecNumber - 1].CType;
break;
case SQL_DESC_DATA_PTR:
+ rettype = SQL_IS_POINTER;
ptr = opts->parameters[RecNumber - 1].buffer;
break;
case SQL_DESC_INDICATOR_PTR:
+ rettype = SQL_IS_POINTER;
ptr = opts->parameters[RecNumber - 1].used;
break;
case SQL_DESC_OCTET_LENGTH:
ival = opts->parameters[RecNumber - 1].buflen;
break;
case SQL_DESC_OCTET_LENGTH_PTR:
+ rettype = SQL_IS_POINTER;
ptr = opts->parameters[RecNumber - 1].used;
break;
case SQL_DESC_COUNT:
case SQL_DESC_ALLOC_TYPE: /* read-only */
ival = SQL_DESC_ALLOC_AUTO;
break;
+ case SQL_DESC_PRECISION:
+ case SQL_DESC_SCALE:
case SQL_DESC_DATETIME_INTERVAL_PRECISION:
case SQL_DESC_LENGTH:
case SQL_DESC_NUM_PREC_RADIX:
- case SQL_DESC_PRECISION:
- case SQL_DESC_SCALE:
default:ret = SQL_ERROR;
stmt->errornumber = STMT_INVALID_DESCRIPTOR_IDENTIFIER;
}
- switch (BufferLength)
+ switch (rettype)
{
case 0:
case SQL_IS_INTEGER:
len = 4;
*((Int4 *) Value) = ival;
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:
len = 4;
*((void **) Value) = ptr;
SQLINTEGER *StringLength)
{
RETCODE ret = SQL_SUCCESS;
- SQLINTEGER ival = 0, len;
+ SQLINTEGER ival = 0, len, rettype = 0;
PTR ptr = NULL;
+ BOOL bCallColAtt = FALSE;
const IRDFields *opts = SC_get_IRD(stmt);
switch (FieldIdentifier)
{
case SQL_DESC_ARRAY_STATUS_PTR:
+ rettype = SQL_IS_POINTER;
ptr = opts->rowStatusArray;
break;
case SQL_DESC_ROWS_PROCESSED_PTR:
+ rettype = SQL_IS_POINTER;
ptr = opts->rowsFetched;
break;
case SQL_DESC_ALLOC_TYPE: /* read-only */
+ ival = SQL_DESC_ALLOC_AUTO;
+ break;
case SQL_DESC_COUNT: /* 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_CATALOG_NAME: /* read-only */
case SQL_DESC_CONCISE_TYPE: /* read-only */
case SQL_DESC_DATETIME_INTERVAL_CODE: /* read-only */
case SQL_DESC_DATETIME_INTERVAL_PRECISION: /* read-only */
case SQL_DESC_DISPLAY_SIZE: /* 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_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_NUM_PREC_RADIX: /* read-only */
case SQL_DESC_OCTET_LENGTH: /* read-only */
case SQL_DESC_ROWVER: /* read-only */
#endif /* ODBCVER */
case SQL_DESC_SCALE: /* read-only */
- case SQL_DESC_SCHEMA_NAME: /* 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_NAME: /* read-only */
case SQL_DESC_UNNAMED: /* read-only */
case SQL_DESC_UNSIGNED: /* 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;
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 SQL_IS_INTEGER:
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:
len = 4;
*((void **) Value) = ptr;
SQLINTEGER *StringLength)
{
RETCODE ret = SQL_SUCCESS;
- SQLINTEGER ival = 0, len;
+ SQLINTEGER ival = 0, len, rettype = 0;
PTR ptr = NULL;
const IPDFields *ipdopts = SC_get_IPD(stmt);
const APDFields *apdopts = SC_get_APD(stmt);
switch (FieldIdentifier)
{
case SQL_DESC_ARRAY_STATUS_PTR:
+ rettype = SQL_IS_POINTER;
ptr = ipdopts->param_status_ptr;
break;
case SQL_DESC_ROWS_PROCESSED_PTR:
+ rettype = SQL_IS_POINTER;
ptr = ipdopts->param_processed_ptr;
break;
case SQL_DESC_UNNAMED: /* only SQL_UNNAMED is allowed */
case SQL_DESC_PARAMETER_TYPE:
ival = apdopts->parameters[RecNumber - 1].paramType;
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:
- 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;
case SQL_DESC_ALLOC_TYPE: /* read-only */
ival = SQL_DESC_ALLOC_AUTO;
case SQL_DESC_NULLABLE: /* read-only */
case SQL_DESC_NUM_PREC_RADIX:
case SQL_DESC_OCTET_LENGTH:
- case SQL_DESC_PRECISION:
#if (ODBCVER >= 0x0350)
case SQL_DESC_ROWVER: /* read-only */
#endif /* ODBCVER */
default:ret = SQL_ERROR;
stmt->errornumber = STMT_INVALID_DESCRIPTOR_IDENTIFIER;
}
- switch (BufferLength)
+ switch (rettype)
{
case 0:
case SQL_IS_INTEGER:
len = 4;
*((Int4 *) Value) = ival;
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:
len = 4;
*((void **)Value) = ptr;
SQLSMALLINT RecNumber, SQLCHAR *Sqlstate,
SQLINTEGER *NativeError, SQLCHAR *MessageText,
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,
SQLINTEGER Attribute, PTR Value,
SQLINTEGER BufferLength, SQLINTEGER *StringLength);
*
* 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 $
*
*/
rv->rowset_size = 1;
rv->haskeyset = 0;
rv->keyset = NULL;
+ rv->rb_alloc = 0;
rv->rb_count = 0;
rv->rollback = NULL;
}
if (self->rollback)
{
free(self->rollback);
+ self->rb_alloc = 0;
self->rb_count = 0;
self->rollback = NULL;
}
char aborted; /* was aborted? */
char haskeyset; /* this result contains 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;
};
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)
{
SC_log_error(func, "", stmt);
return SQL_ERROR;
}
- field_type = irdflds->fi[col_idx]->type;
- if (field_type > 0)
- parse_ok = TRUE;
+ if (irdflds->fi[col_idx])
+ {
+ field_type = irdflds->fi[col_idx]->type;
+ if (field_type > 0)
+ parse_ok = TRUE;
+ }
}
}
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);
if (len >= cbDescMax)
#endif /* DRIVER_CURSOR_IMPLEMENT */
else
*(rgfRowStatus + i) = SQL_ROW_SUCCESS;
-if (rgfRowStatus[i] != SQL_ROW_SUCCESS)
-inolog("rgfRowStatus[%d]=%d\n", i, rgfRowStatus[i]);
}
}
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 USE_INSERTED_TID (1L << 1)
static QResultClass *
ret = SQL_SUCCESS_WITH_INFO;
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;
}
}
num_cols,
upd_cols;
QResultClass *res;
+ ConnectionClass *conn = SC_get_conn(stmt);
ARDFields *opts = SC_get_ARD(stmt);
IRDFields *irdflds = SC_get_IRD(stmt);
BindInfoClass *bindings = opts->bindings;
sprintf(updstr, "%s where ctid = '(%u, %u)' and oid = %u", updstr,
blocknum, pgoffset, oid);
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;
qstmt = (StatementClass *) hstmt;
apdopts = SC_get_APD(qstmt);
}
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);
+ }
else
res->keyset[global_ridx].status |= (SQL_ROW_UPDATED | CURS_SELF_UPDATED);
}
{
UWORD offset;
QResultClass *res, *qres;
+ ConnectionClass *conn = SC_get_conn(stmt);
ARDFields *opts = SC_get_ARD(stmt);
IRDFields *irdflds = SC_get_IRD(stmt);
BindInfoClass *bindings = opts->bindings;
char dltstr[4096];
RETCODE ret;
- /*const char *oidval;*/
UInt4 oid, blocknum;
mylog("POS DELETE ti=%x\n", stmt->ti);
stmt->ti[0]->name, blocknum, offset, oid);
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;
if (qres && QR_command_successful(qres))
{
QR_Destructor(qres);
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);
+ }
else
res->keyset[global_ridx].status |= (SQL_ROW_DELETED | CURS_SELF_DELETED);
}
num_cols = irdflds->nfields;
conn = SC_get_conn(stmt);
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;
if (opts->row_offset_ptr)
offset = *opts->row_offset_ptr;
PGAPI_FreeStmt(hstmt, SQL_DROP);
if (SQL_SUCCESS == ret && res->keyset)
{
+ int global_ridx = res->fcount - 1;
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
- 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 (irdflds->rowStatusArray)
int i;
for (i = 0; i < self->ntab; i++)
- if (self->ti)
- free(self->ti);
+ if (self->ti[i])
+ free(self->ti[i]);
self->ti = NULL;
self->ntab = 0;
}