Commit 79420840 authored by Hiroshi Inoue's avatar Hiroshi Inoue

1) Support Keyset Driven driver cursors.

2) Supprt ARD precision/scale and SQL_C_NUEMRIC.
3) Minimal implementation of SQLGetDiagField().
4) SQLRowCount() reports the result of SQLSetPos and SQLBulkOperation.
5) int8 -> SQL_NUMERIC for Microsoft Jet.
6) Support isolation level change.
7) ODBC3.0 SQLSTATE code.
8) Append mode log files.
parent 6c6f395a
...@@ -69,6 +69,23 @@ PGAPI_BindParameter( ...@@ -69,6 +69,23 @@ PGAPI_BindParameter(
opts->parameters[ipar].SQLType = fSqlType; opts->parameters[ipar].SQLType = fSqlType;
opts->parameters[ipar].column_size = cbColDef; opts->parameters[ipar].column_size = cbColDef;
opts->parameters[ipar].decimal_digits = ibScale; opts->parameters[ipar].decimal_digits = ibScale;
opts->parameters[ipar].precision = 0;
opts->parameters[ipar].scale = 0;
#if (ODBCVER >= 0x0300)
switch (fCType)
{
case SQL_C_NUMERIC:
if (cbColDef > 0)
opts->parameters[ipar].precision = (UInt2) cbColDef;
if (ibScale > 0)
opts->parameters[ipar].scale = ibScale;
break;
case SQL_C_TYPE_TIMESTAMP:
if (ibScale > 0)
opts->parameters[ipar].precision = ibScale;
break;
}
#endif /* ODBCVER */
/* /*
* 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
...@@ -210,6 +227,8 @@ inolog("Column 0 is type %d not of type SQL_C_BOOKMARK", fCType); ...@@ -210,6 +227,8 @@ inolog("Column 0 is type %d not of type SQL_C_BOOKMARK", fCType);
free(opts->bindings[icol].ttlbuf); free(opts->bindings[icol].ttlbuf);
opts->bindings[icol].ttlbuf = NULL; opts->bindings[icol].ttlbuf = NULL;
opts->bindings[icol].ttlbuflen = 0; opts->bindings[icol].ttlbuflen = 0;
opts->bindings[icol].precision = 0;
opts->bindings[icol].scale = 0;
} }
else else
{ {
...@@ -218,6 +237,13 @@ inolog("Column 0 is type %d not of type SQL_C_BOOKMARK", fCType); ...@@ -218,6 +237,13 @@ inolog("Column 0 is type %d not of type SQL_C_BOOKMARK", fCType);
opts->bindings[icol].buffer = rgbValue; opts->bindings[icol].buffer = rgbValue;
opts->bindings[icol].used = pcbValue; opts->bindings[icol].used = pcbValue;
opts->bindings[icol].returntype = fCType; opts->bindings[icol].returntype = fCType;
#if (ODBCVER >= 0x0300)
if (SQL_C_NUMERIC == fCType)
opts->bindings[icol].precision = 32;
else
#endif /* ODBCVER */
opts->bindings[icol].precision = 0;
opts->bindings[icol].scale = 0;
mylog(" bound buffer[%d] = %u\n", icol, opts->bindings[icol].buffer); mylog(" bound buffer[%d] = %u\n", icol, opts->bindings[icol].buffer);
} }
...@@ -460,6 +486,8 @@ reset_a_parameter_binding(APDFields *self, int ipar) ...@@ -460,6 +486,8 @@ reset_a_parameter_binding(APDFields *self, int ipar)
self->parameters[ipar].SQLType = 0; self->parameters[ipar].SQLType = 0;
self->parameters[ipar].column_size = 0; self->parameters[ipar].column_size = 0;
self->parameters[ipar].decimal_digits = 0; self->parameters[ipar].decimal_digits = 0;
self->parameters[ipar].precision = 0;
self->parameters[ipar].scale = 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;
} }
......
...@@ -27,6 +27,8 @@ struct BindInfoClass_ ...@@ -27,6 +27,8 @@ struct BindInfoClass_
Int2 returntype; /* kind of conversion to be applied when Int2 returntype; /* kind of conversion to be applied when
* returning (SQL_C_DEFAULT, * returning (SQL_C_DEFAULT,
* SQL_C_CHAR...) */ * SQL_C_CHAR...) */
Int2 precision; /* the precision for numeric or timestamp type */
Int2 scale; /* the scale for numeric type */
}; };
/* /*
...@@ -40,12 +42,14 @@ struct ParameterInfoClass_ ...@@ -40,12 +42,14 @@ struct ParameterInfoClass_
Int2 paramType; Int2 paramType;
Int2 CType; Int2 CType;
Int2 SQLType; Int2 SQLType;
UInt4 column_size;
Int2 decimal_digits; Int2 decimal_digits;
UInt4 column_size;
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 */
char *EXEC_buffer; /* the data or the FD of the large object */ char *EXEC_buffer; /* the data or the FD of the large object */
Int2 precision; /* the precision for numeric or timestamp type */
Int2 scale; /* the scale for numeric type */
char data_at_exec; char data_at_exec;
}; };
......
...@@ -237,7 +237,7 @@ CC_conninfo_init(ConnInfo *conninfo) ...@@ -237,7 +237,7 @@ CC_conninfo_init(ConnInfo *conninfo)
{ {
memset(conninfo, 0, sizeof(ConnInfo)); memset(conninfo, 0, sizeof(ConnInfo));
conninfo->disallow_premature = -1; conninfo->disallow_premature = -1;
conninfo->updatable_cursors = -1; conninfo->allow_keyset = -1;
conninfo->lf_conversion = -1; conninfo->lf_conversion = -1;
conninfo->true_is_minus1 = -1; conninfo->true_is_minus1 = -1;
memcpy(&(conninfo->drivers), &globals, sizeof(globals)); memcpy(&(conninfo->drivers), &globals, sizeof(globals));
...@@ -293,6 +293,7 @@ CC_Constructor() ...@@ -293,6 +293,7 @@ CC_Constructor()
rv->unicode = 0; rv->unicode = 0;
rv->result_uncommitted = 0; rv->result_uncommitted = 0;
rv->schema_support = 0; rv->schema_support = 0;
rv->isolation = SQL_TXN_READ_COMMITTED;
#ifdef MULTIBYTE #ifdef MULTIBYTE
rv->client_encoding = NULL; rv->client_encoding = NULL;
rv->server_encoding = NULL; rv->server_encoding = NULL;
...@@ -996,6 +997,12 @@ another_version_retry: ...@@ -996,6 +997,12 @@ another_version_retry:
} }
#endif /* UNICODE_SUPPORT */ #endif /* UNICODE_SUPPORT */
#endif /* MULTIBYTE */ #endif /* MULTIBYTE */
ci->updatable_cursors = 0;
#ifdef DRIVER_CURSOR_IMPLEMENT
if (!ci->drivers.use_declarefetch &&
PG_VERSION_GE(self, 7.0)) /* Tid scan since 7.0 */
ci->updatable_cursors = ci->allow_keyset;
#endif /* DRIVER_CURSOR_IMPLEMENT */
CC_clear_error(self); /* clear any initial command errors */ CC_clear_error(self); /* clear any initial command errors */
self->status = CONN_CONNECTED; self->status = CONN_CONNECTED;
...@@ -1130,7 +1137,7 @@ void CC_on_commit(ConnectionClass *conn) ...@@ -1130,7 +1137,7 @@ void CC_on_commit(ConnectionClass *conn)
} }
conn->result_uncommitted = 0; conn->result_uncommitted = 0;
} }
void CC_on_abort(ConnectionClass *conn, BOOL set_no_trans) void CC_on_abort(ConnectionClass *conn, UDWORD opt)
{ {
if (CC_is_in_trans(conn)) if (CC_is_in_trans(conn))
{ {
...@@ -1138,9 +1145,11 @@ void CC_on_abort(ConnectionClass *conn, BOOL set_no_trans) ...@@ -1138,9 +1145,11 @@ void CC_on_abort(ConnectionClass *conn, BOOL set_no_trans)
if (conn->result_uncommitted) if (conn->result_uncommitted)
ProcessRollback(conn, TRUE); ProcessRollback(conn, TRUE);
#endif /* DRIVER_CURSOR_IMPLEMENT */ #endif /* DRIVER_CURSOR_IMPLEMENT */
if (set_no_trans) if (0 != (opt & NO_TRANS))
CC_set_no_trans(conn); CC_set_no_trans(conn);
} }
if (0 != (opt & CONN_DEAD))
conn->status = CONN_DOWN;
conn->result_uncommitted = 0; conn->result_uncommitted = 0;
} }
...@@ -1162,8 +1171,7 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, UDWORD flag) ...@@ -1162,8 +1171,7 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, UDWORD flag)
BOOL clear_result_on_abort = ((flag & CLEAR_RESULT_ON_ABORT) != 0), BOOL clear_result_on_abort = ((flag & CLEAR_RESULT_ON_ABORT) != 0),
create_keyset = ((flag & CREATE_KEYSET) != 0), create_keyset = ((flag & CREATE_KEYSET) != 0),
issue_begin = ((flag & GO_INTO_TRANSACTION) != 0 && !CC_is_in_trans(self)); issue_begin = ((flag & GO_INTO_TRANSACTION) != 0 && !CC_is_in_trans(self));
char swallow, char swallow, *wq, *ptr;
*wq;
int id; int id;
SocketClass *sock = self->sock; SocketClass *sock = self->sock;
int maxlen, int maxlen,
...@@ -1173,8 +1181,8 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, UDWORD flag) ...@@ -1173,8 +1181,8 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, UDWORD flag)
query_completed = FALSE, query_completed = FALSE,
before_64 = PG_VERSION_LT(self, 6.4), before_64 = PG_VERSION_LT(self, 6.4),
aborted = FALSE, aborted = FALSE,
used_passed_result_object = FALSE, used_passed_result_object = FALSE;
set_no_trans; UDWORD abort_opt;
/* ERROR_MSG_LENGTH is suffcient */ /* ERROR_MSG_LENGTH is suffcient */
static char msgbuffer[ERROR_MSG_LENGTH + 1]; static char msgbuffer[ERROR_MSG_LENGTH + 1];
...@@ -1201,7 +1209,7 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, UDWORD flag) ...@@ -1201,7 +1209,7 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, UDWORD flag)
{ {
self->errornumber = CONNECTION_COULD_NOT_SEND; self->errornumber = CONNECTION_COULD_NOT_SEND;
self->errormsg = "Could not send Query to backend"; self->errormsg = "Could not send Query to backend";
CC_on_abort(self, TRUE); CC_on_abort(self, NO_TRANS | CONN_DEAD);
return NULL; return NULL;
} }
...@@ -1210,7 +1218,7 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, UDWORD flag) ...@@ -1210,7 +1218,7 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, UDWORD flag)
{ {
self->errornumber = CONNECTION_COULD_NOT_SEND; self->errornumber = CONNECTION_COULD_NOT_SEND;
self->errormsg = "Could not send Query to backend"; self->errormsg = "Could not send Query to backend";
CC_on_abort(self, TRUE); CC_on_abort(self, NO_TRANS | CONN_DEAD);
return NULL; return NULL;
} }
...@@ -1223,7 +1231,7 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, UDWORD flag) ...@@ -1223,7 +1231,7 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, UDWORD flag)
{ {
self->errornumber = CONNECTION_COULD_NOT_SEND; self->errornumber = CONNECTION_COULD_NOT_SEND;
self->errormsg = "Could not send Query to backend"; self->errormsg = "Could not send Query to backend";
CC_on_abort(self, TRUE); CC_on_abort(self, NO_TRANS | CONN_DEAD);
return NULL; return NULL;
} }
...@@ -1260,7 +1268,7 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, UDWORD flag) ...@@ -1260,7 +1268,7 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, UDWORD flag)
self->errormsg = "No response from the backend"; self->errormsg = "No response from the backend";
mylog("send_query: 'id' - %s\n", self->errormsg); mylog("send_query: 'id' - %s\n", self->errormsg);
CC_on_abort(self, TRUE); CC_on_abort(self, NO_TRANS | CONN_DEAD);
ReadyToReturn = TRUE; ReadyToReturn = TRUE;
retres = NULL; retres = NULL;
break; break;
...@@ -1284,7 +1292,7 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, UDWORD flag) ...@@ -1284,7 +1292,7 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, UDWORD flag)
self->errornumber = CONNECTION_NO_RESPONSE; self->errornumber = CONNECTION_NO_RESPONSE;
self->errormsg = "No response from backend while receiving a portal query command"; self->errormsg = "No response from backend while receiving a portal query command";
mylog("send_query: 'C' - %s\n", self->errormsg); mylog("send_query: 'C' - %s\n", self->errormsg);
CC_on_abort(self, TRUE); CC_on_abort(self, NO_TRANS | CONN_DEAD);
ReadyToReturn = TRUE; ReadyToReturn = TRUE;
retres = NULL; retres = NULL;
} }
...@@ -1312,11 +1320,20 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, UDWORD flag) ...@@ -1312,11 +1320,20 @@ 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); 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, NO_TRANS);
else if (strnicmp(cmdbuffer, "END", 3) == 0) else if (strnicmp(cmdbuffer, "END", 3) == 0)
CC_on_commit(self); 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, NO_TRANS);
else
{
trim(cmdbuffer); /* get rid of trailing space */
ptr = strrchr(cmdbuffer, ' ');
if (ptr)
res->recent_processed_row_count = atoi(ptr + 1);
else
res->recent_processed_row_count = -1;
}
if (QR_command_successful(res)) if (QR_command_successful(res))
QR_set_status(res, PGRES_COMMAND_OK); QR_set_status(res, PGRES_COMMAND_OK);
...@@ -1400,15 +1417,15 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, UDWORD flag) ...@@ -1400,15 +1417,15 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, UDWORD flag)
qlog("ERROR from backend during send_query: '%s'\n", msgbuffer); qlog("ERROR from backend during send_query: '%s'\n", msgbuffer);
/* We should report that an error occured. Zoltan */ /* We should report that an error occured. Zoltan */
set_no_trans = FALSE; abort_opt = 0;
if (!strncmp(msgbuffer, "FATAL", 5)) if (!strncmp(msgbuffer, "FATAL", 5))
{ {
self->errornumber = CONNECTION_SERVER_REPORTED_ERROR; self->errornumber = CONNECTION_SERVER_REPORTED_ERROR;
set_no_trans = TRUE; abort_opt = NO_TRANS | CONN_DEAD;
} }
else else
self->errornumber = CONNECTION_SERVER_REPORTED_WARNING; self->errornumber = CONNECTION_SERVER_REPORTED_WARNING;
CC_on_abort(self, set_no_trans); CC_on_abort(self, abort_opt);
QR_set_status(res, PGRES_FATAL_ERROR); QR_set_status(res, PGRES_FATAL_ERROR);
QR_set_message(res, msgbuffer); QR_set_message(res, msgbuffer);
QR_set_aborted(res, TRUE); QR_set_aborted(res, TRUE);
...@@ -1497,7 +1514,7 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, UDWORD flag) ...@@ -1497,7 +1514,7 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, UDWORD flag)
default: default:
self->errornumber = CONNECTION_BACKEND_CRAZY; self->errornumber = CONNECTION_BACKEND_CRAZY;
self->errormsg = "Unexpected protocol character from backend (send_query)"; self->errormsg = "Unexpected protocol character from backend (send_query)";
CC_on_abort(self, TRUE); CC_on_abort(self, NO_TRANS | CONN_DEAD);
mylog("send_query: error - %s\n", self->errormsg); mylog("send_query: error - %s\n", self->errormsg);
ReadyToReturn = TRUE; ReadyToReturn = TRUE;
...@@ -1585,7 +1602,7 @@ CC_send_function(ConnectionClass *self, int fnid, void *result_buf, int *actual_ ...@@ -1585,7 +1602,7 @@ CC_send_function(ConnectionClass *self, int fnid, void *result_buf, int *actual_
{ {
self->errornumber = CONNECTION_COULD_NOT_SEND; self->errornumber = CONNECTION_COULD_NOT_SEND;
self->errormsg = "Could not send function to backend"; self->errormsg = "Could not send function to backend";
CC_on_abort(self, TRUE); CC_on_abort(self, NO_TRANS | CONN_DEAD);
return FALSE; return FALSE;
} }
...@@ -1594,7 +1611,7 @@ CC_send_function(ConnectionClass *self, int fnid, void *result_buf, int *actual_ ...@@ -1594,7 +1611,7 @@ CC_send_function(ConnectionClass *self, int fnid, void *result_buf, int *actual_
{ {
self->errornumber = CONNECTION_COULD_NOT_SEND; self->errornumber = CONNECTION_COULD_NOT_SEND;
self->errormsg = "Could not send function to backend"; self->errormsg = "Could not send function to backend";
CC_on_abort(self, TRUE); CC_on_abort(self, NO_TRANS | CONN_DEAD);
return FALSE; return FALSE;
} }
...@@ -1643,7 +1660,7 @@ CC_send_function(ConnectionClass *self, int fnid, void *result_buf, int *actual_ ...@@ -1643,7 +1660,7 @@ CC_send_function(ConnectionClass *self, int fnid, void *result_buf, int *actual_
case 'E': case 'E':
SOCK_get_string(sock, msgbuffer, ERROR_MSG_LENGTH); SOCK_get_string(sock, msgbuffer, ERROR_MSG_LENGTH);
self->errormsg = msgbuffer; self->errormsg = msgbuffer;
CC_on_abort(self, FALSE); CC_on_abort(self, 0);
mylog("send_function(V): 'E' - %s\n", self->errormsg); mylog("send_function(V): 'E' - %s\n", self->errormsg);
qlog("ERROR from backend during send_function: '%s'\n", self->errormsg); qlog("ERROR from backend during send_function: '%s'\n", self->errormsg);
...@@ -1656,7 +1673,7 @@ CC_send_function(ConnectionClass *self, int fnid, void *result_buf, int *actual_ ...@@ -1656,7 +1673,7 @@ CC_send_function(ConnectionClass *self, int fnid, void *result_buf, int *actual_
default: default:
self->errornumber = CONNECTION_BACKEND_CRAZY; self->errornumber = CONNECTION_BACKEND_CRAZY;
self->errormsg = "Unexpected protocol character from backend (send_function, args)"; self->errormsg = "Unexpected protocol character from backend (send_function, args)";
CC_on_abort(self, TRUE); CC_on_abort(self, NO_TRANS | CONN_DEAD);
mylog("send_function: error - %s\n", self->errormsg); mylog("send_function: error - %s\n", self->errormsg);
return FALSE; return FALSE;
...@@ -1690,7 +1707,7 @@ CC_send_function(ConnectionClass *self, int fnid, void *result_buf, int *actual_ ...@@ -1690,7 +1707,7 @@ CC_send_function(ConnectionClass *self, int fnid, void *result_buf, int *actual_
case 'E': case 'E':
SOCK_get_string(sock, msgbuffer, ERROR_MSG_LENGTH); SOCK_get_string(sock, msgbuffer, ERROR_MSG_LENGTH);
self->errormsg = msgbuffer; self->errormsg = msgbuffer;
CC_on_abort(self, FALSE); CC_on_abort(self, 0);
mylog("send_function(G): 'E' - %s\n", self->errormsg); mylog("send_function(G): 'E' - %s\n", self->errormsg);
qlog("ERROR from backend during send_function: '%s'\n", self->errormsg); qlog("ERROR from backend during send_function: '%s'\n", self->errormsg);
...@@ -1711,7 +1728,7 @@ CC_send_function(ConnectionClass *self, int fnid, void *result_buf, int *actual_ ...@@ -1711,7 +1728,7 @@ CC_send_function(ConnectionClass *self, int fnid, void *result_buf, int *actual_
default: default:
self->errornumber = CONNECTION_BACKEND_CRAZY; self->errornumber = CONNECTION_BACKEND_CRAZY;
self->errormsg = "Unexpected protocol character from backend (send_function, result)"; self->errormsg = "Unexpected protocol character from backend (send_function, result)";
CC_on_abort(self, TRUE); CC_on_abort(self, NO_TRANS | CONN_DEAD);
mylog("send_function: error - %s\n", self->errormsg); mylog("send_function: error - %s\n", self->errormsg);
return FALSE; return FALSE;
......
...@@ -166,6 +166,7 @@ typedef struct ...@@ -166,6 +166,7 @@ typedef struct
char translation_option[SMALL_REGISTRY_LEN]; char translation_option[SMALL_REGISTRY_LEN];
char focus_password; char focus_password;
char disallow_premature; char disallow_premature;
char allow_keyset;
char updatable_cursors; char updatable_cursors;
char lf_conversion; char lf_conversion;
char true_is_minus1; char true_is_minus1;
...@@ -296,6 +297,7 @@ struct ConnectionClass_ ...@@ -296,6 +297,7 @@ struct ConnectionClass_
int ccsc; int ccsc;
int be_pid; /* pid returned by backend */ int be_pid; /* pid returned by backend */
int be_key; /* auth code needed to send cancel */ int be_key; /* auth code needed to send cancel */
UInt4 isolation;
}; };
...@@ -339,11 +341,15 @@ void CC_log_error(const char *func, const char *desc, const ConnectionClass *se ...@@ -339,11 +341,15 @@ void CC_log_error(const char *func, const char *desc, const ConnectionClass *se
int CC_get_max_query_len(const ConnectionClass *self); int CC_get_max_query_len(const ConnectionClass *self);
int CC_send_cancel_request(const ConnectionClass *conn); int CC_send_cancel_request(const ConnectionClass *conn);
void CC_on_commit(ConnectionClass *conn); void CC_on_commit(ConnectionClass *conn);
void CC_on_abort(ConnectionClass *conn, BOOL set_no_trans); void CC_on_abort(ConnectionClass *conn, UDWORD opt);
void ProcessRollback(ConnectionClass *conn, BOOL undo); 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
#define CREATE_KEYSET (1L << 1) /* create keyset for updatable curosrs */ #define CREATE_KEYSET (1L << 1) /* create keyset for updatable curosrs */
#define GO_INTO_TRANSACTION (1L << 2) /* issue begin in advance */ #define GO_INTO_TRANSACTION (1L << 2) /* issue begin in advance */
#endif /* CC_on_abort options */
#define NO_TRANS 1L
#define CONN_DEAD (1L << 1) /* connection is no longer valid */
#endif /* __CONNECTION_H__ */
...@@ -371,7 +371,7 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2 ...@@ -371,7 +371,7 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2
pbic = &opts->bindings[stmt->current_col]; pbic = &opts->bindings[stmt->current_col];
if (pbic->data_left == -2) if (pbic->data_left == -2)
pbic->data_left = (cbValueMax > 0) ? 0 : -1; /* This seems to be * pbic->data_left = (cbValueMax > 0) ? 0 : -1; /* This seems to be *
* needed for ADO ? */ * needed by ADO ? */
if (pbic->data_left == 0) if (pbic->data_left == 0)
{ {
if (pbic->ttlbuf != NULL) if (pbic->ttlbuf != NULL)
...@@ -984,6 +984,90 @@ inolog("2stime fr=%d\n", st.fr); ...@@ -984,6 +984,90 @@ inolog("2stime fr=%d\n", st.fr);
#endif /* HAVE_LOCALE_H */ #endif /* HAVE_LOCALE_H */
break; break;
#if (ODBCVER >= 0x0300)
case SQL_C_NUMERIC:
#ifdef HAVE_LOCALE_H
/* strcpy(saved_locale, setlocale(LC_ALL, NULL));
setlocale(LC_ALL, "C"); not needed currently */
#endif /* HAVE_LOCALE_H */
{
SQL_NUMERIC_STRUCT *ns;
int i, nlen, bit, hval, tv, dig, sta, olen;
char calv[SQL_MAX_NUMERIC_LEN * 3], *wv;
BOOL dot_exist;
len = sizeof(SQL_NUMERIC_STRUCT);
if (bind_size > 0)
ns = (SQL_NUMERIC_STRUCT *) ((char *) rgbValue + (bind_row * bind_size));
else
ns = (SQL_NUMERIC_STRUCT *) rgbValue + bind_row;
for (wv = neut_str; *wv && isspace(*wv); wv++)
;
ns->sign = 1;
if (*wv == '-')
{
ns->sign = 0;
wv++;
}
else if (*wv == '+')
wv++;
while (*wv == '0') wv++;
ns->precision = 0;
ns->scale = 0;
for (nlen = 0, dot_exist = FALSE;; wv++)
{
if (*wv == '.')
{
if (dot_exist)
break;
dot_exist = TRUE;
}
else if (!isdigit(*wv))
break;
else
{
if (dot_exist)
ns->scale++;
else
ns->precision++;
calv[nlen++] = *wv;
}
}
memset(ns->val, 0, sizeof(ns->val));
for (hval = 0, bit = 1L, sta = 0, olen = 0; sta < nlen;)
{
for (dig = 0, i = sta; i < nlen; i++)
{
tv = dig * 10 + calv[i] - '0';
dig = tv % 2;
calv[i] = tv / 2 + '0';
if (i == sta && tv < 2)
sta++;
}
if (dig > 0)
hval |= bit;
bit <<= 1;
if (bit >= (1L << 8))
{
ns->val[olen++] = hval;
hval = 0;
bit = 1L;
if (olen >= SQL_MAX_NUMERIC_LEN - 1)
{
ns->scale = sta - ns->precision;
break;
}
}
}
if (hval && olen < SQL_MAX_NUMERIC_LEN - 1)
ns->val[olen++] = hval;
}
#ifdef HAVE_LOCALE_H
/* setlocale(LC_ALL, saved_locale); */
#endif /* HAVE_LOCALE_H */
break;
#endif /* ODBCVER */
case SQL_C_SSHORT: case SQL_C_SSHORT:
case SQL_C_SHORT: case SQL_C_SHORT:
len = 2; len = 2;
...@@ -1179,6 +1263,8 @@ QP_initialize(QueryParse *q, const StatementClass *stmt) ...@@ -1179,6 +1263,8 @@ QP_initialize(QueryParse *q, const StatementClass *stmt)
#define FLGB_PRE_EXECUTING 1L #define FLGB_PRE_EXECUTING 1L
#define FLGB_INACCURATE_RESULT (1L << 1) #define FLGB_INACCURATE_RESULT (1L << 1)
#define FLGB_CREATE_KEYSET (1L << 2)
#define FLGB_KEYSET_DRIVEN (1L << 3)
typedef struct _QueryBuild { typedef struct _QueryBuild {
char *query_statement; char *query_statement;
UInt4 str_size_limit; UInt4 str_size_limit;
...@@ -1589,10 +1675,16 @@ copy_statement_with_parameters(StatementClass *stmt) ...@@ -1589,10 +1675,16 @@ copy_statement_with_parameters(StatementClass *stmt)
{ {
if (stmt->parse_status == STMT_PARSE_NONE) if (stmt->parse_status == STMT_PARSE_NONE)
parse_statement(stmt); parse_statement(stmt);
/*if (stmt->parse_status != STMT_PARSE_COMPLETE) if (stmt->parse_status == STMT_PARSE_FATAL)
{
stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY; stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
else*/ if (!stmt->updatable) return SQL_ERROR;
}
else if (!stmt->updatable)
{
stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY; stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
stmt->options.cursor_type = SQL_CURSOR_STATIC;
}
else else
{ {
qp->from_pos = stmt->from_pos; qp->from_pos = stmt->from_pos;
...@@ -1602,7 +1694,7 @@ copy_statement_with_parameters(StatementClass *stmt) ...@@ -1602,7 +1694,7 @@ copy_statement_with_parameters(StatementClass *stmt)
#else #else
stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY; stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
if (stmt->options.cursor_type == SQL_CURSOR_KEYSET_DRIVEN) if (stmt->options.cursor_type == SQL_CURSOR_KEYSET_DRIVEN)
stmt->options.cursor_type = SQL_CURSOR_FORWARD_ONLY; stmt->options.cursor_type = SQL_CURSOR_STATIC;
#endif /* DRIVER_CURSOR_IMPLEMENT */ #endif /* DRIVER_CURSOR_IMPLEMENT */
/* If the application hasn't set a cursor name, then generate one */ /* If the application hasn't set a cursor name, then generate one */
...@@ -1641,6 +1733,12 @@ copy_statement_with_parameters(StatementClass *stmt) ...@@ -1641,6 +1733,12 @@ copy_statement_with_parameters(StatementClass *stmt)
qp->flags |= FLGP_CURSOR_CHECK_OK; qp->flags |= FLGP_CURSOR_CHECK_OK;
qp->declare_pos = qb->npos; qp->declare_pos = qb->npos;
} }
else if (SQL_CONCUR_READ_ONLY != stmt->options.scroll_concurrency)
{
qb->flags |= FLGB_CREATE_KEYSET;
if (SQL_CURSOR_KEYSET_DRIVEN == stmt->options.cursor_type)
qb->flags |= FLGB_KEYSET_DRIVEN;
}
} }
for (qp->opos = 0; qp->opos < qp->stmt_len; qp->opos++) for (qp->opos = 0; qp->opos < qp->stmt_len; qp->opos++)
...@@ -1693,12 +1791,28 @@ copy_statement_with_parameters(StatementClass *stmt) ...@@ -1693,12 +1791,28 @@ copy_statement_with_parameters(StatementClass *stmt)
UInt4 npos = qb->load_stmt_len; UInt4 npos = qb->load_stmt_len;
if (0 == npos) if (0 == npos)
{
npos = qb->npos; npos = qb->npos;
for (; npos > 0; npos--)
{
if (isspace(new_statement[npos - 1]))
continue;
if (';' != new_statement[npos - 1])
break;
}
if (0 != (qb->flags & FLGB_KEYSET_DRIVEN))
{
qb->npos = npos;
/* ----------
* 1st query is for field information
* 2nd query is keyset gathering
*/
CVT_APPEND_STR(qb, " where ctid = '(,)';select ctid, oid from ");
CVT_APPEND_DATA(qb, qp->statement + qp->from_pos + 5, npos - qp->from_pos - 5);
}
}
stmt->load_statement = malloc(npos + 1); stmt->load_statement = malloc(npos + 1);
memcpy(stmt->load_statement, new_statement, npos); memcpy(stmt->load_statement, qb->query_statement, npos);
if (stmt->load_statement[npos - 1] == ';')
stmt->load_statement[npos - 1] = '\0';
else
stmt->load_statement[npos] = '\0'; stmt->load_statement[npos] = '\0';
} }
#endif /* DRIVER_CURSOR_IMPLEMENT */ #endif /* DRIVER_CURSOR_IMPLEMENT */
...@@ -1732,7 +1846,14 @@ inner_process_tokens(QueryParse *qp, QueryBuild *qb) ...@@ -1732,7 +1846,14 @@ inner_process_tokens(QueryParse *qp, QueryBuild *qb)
CVT_APPEND_STR(qb, ", CTID, OID "); CVT_APPEND_STR(qb, ", CTID, OID ");
} }
else if (qp->where_pos == (Int4) qp->opos) else if (qp->where_pos == (Int4) qp->opos)
{
qb->load_stmt_len = qb->npos; qb->load_stmt_len = qb->npos;
if (0 != (qb->flags & FLGB_KEYSET_DRIVEN))
{
CVT_APPEND_STR(qb, "where ctid = '(,)';select CTID, OID from ");
CVT_APPEND_DATA(qb, qp->statement + qp->from_pos + 5, qp->where_pos - qp->from_pos - 5);
}
}
#ifdef MULTIBYTE #ifdef MULTIBYTE
oldchar = encoded_byte_check(&qp->encstr, qp->opos); oldchar = encoded_byte_check(&qp->encstr, qp->opos);
if (ENCODE_STATUS(qp->encstr) != 0) if (ENCODE_STATUS(qp->encstr) != 0)
...@@ -1836,6 +1957,7 @@ inner_process_tokens(QueryParse *qp, QueryBuild *qb) ...@@ -1836,6 +1957,7 @@ inner_process_tokens(QueryParse *qp, QueryBuild *qb)
{ {
qp->flags |= FLGP_SELECT_INTO; qp->flags |= FLGP_SELECT_INTO;
qp->flags &= ~FLGP_CURSOR_CHECK_OK; qp->flags &= ~FLGP_CURSOR_CHECK_OK;
qb->flags &= ~FLGB_KEYSET_DRIVEN;
qp->statement_type = STMT_TYPE_CREATE; qp->statement_type = STMT_TYPE_CREATE;
memmove(qb->query_statement, qb->query_statement + qp->declare_pos, qb->npos - qp->declare_pos); memmove(qb->query_statement, qb->query_statement + qp->declare_pos, qb->npos - qp->declare_pos);
qb->npos -= qp->declare_pos; qb->npos -= qp->declare_pos;
...@@ -1887,6 +2009,130 @@ inner_process_tokens(QueryParse *qp, QueryBuild *qb) ...@@ -1887,6 +2009,130 @@ inner_process_tokens(QueryParse *qp, QueryBuild *qb)
return SQL_SUCCESS; return SQL_SUCCESS;
} }
#if (ODBCVER >= 0x0300)
static BOOL
ResolveNumericParam(const SQL_NUMERIC_STRUCT *ns, char *chrform)
{
static int prec[] = {1, 3, 5, 8, 10, 13, 15, 17, 20, 22, 25, 29, 32, 34, 37, 39};
Int4 i, j, k, ival, vlen, len, newlen;
unsigned char calv[40];
const unsigned char *val = (const unsigned char *) ns->val;
BOOL next_figure;
if (0 == ns->precision)
{
strcpy(chrform, "0");
return TRUE;
}
else if (ns->precision < prec[sizeof(Int4)])
{
for (i = 0, ival = 0; i < sizeof(Int4) && prec[i] <= ns->precision; i++)
{
ival += (val[i] << (8 * i)); /* ns->val is little endian */
}
if (0 == ns->scale)
{
if (0 == ns->sign)
ival *= -1;
sprintf(chrform, "%d", ival);
}
else if (ns->scale > 0)
{
Int4 i, div, o1val, o2val;
for (i = 0, div = 1; i < ns->scale; i++)
div *= 10;
o1val = ival / div;
o2val = ival % div;
if (0 == ns->sign)
o1val *= -1;
sprintf(chrform, "%d.%0.*d", o1val, ns->scale, o2val);
}
return TRUE;
}
for (i = 0; i < SQL_MAX_NUMERIC_LEN && prec[i] <= ns->precision; i++)
;
vlen = i;
len = 0;
memset(calv, 0, sizeof(calv));
for (i = vlen - 1; i >= 0; i--)
{
for (j = len - 1; j >= 0; j--)
{
if (!calv[j])
continue;
ival = (((Int4)calv[j]) << 8);
calv[j] = (ival % 10);
ival /= 10;
calv[j + 1] += (ival % 10);
ival /= 10;
calv[j + 2] += (ival % 10);
ival /= 10;
calv[j + 3] += ival;
for (k = j;; k++)
{
next_figure = FALSE;
if (calv[k] > 0)
{
if (k >= len)
len = k + 1;
while (calv[k] > 9)
{
calv[k + 1]++;
calv[k] -= 10;
next_figure = TRUE;
}
}
if (k >= j + 3 && !next_figure)
break;
}
}
ival = val[i];
if (!ival)
continue;
calv[0] += (ival % 10);
ival /= 10;
calv[1] += (ival % 10);
ival /= 10;
calv[2] += ival;
for (j = 0;; j++)
{
next_figure = FALSE;
if (calv[j] > 0)
{
if (j >= len)
len = j + 1;
while (calv[j] > 9)
{
calv[j + 1]++;
calv[j] -= 10;
next_figure = TRUE;
}
}
if (j >= 2 && !next_figure)
break;
}
}
newlen = 0;
if (0 == ns->sign)
chrform[newlen++] = '-';
for (i = len - 1; i >= ns->scale; i--)
chrform[newlen++] = calv[i] + '0';
if (ns->scale > 0)
{
chrform[newlen++] = '.';
for (; i >= 0; i--)
chrform[newlen++] = calv[i] + '0';
}
chrform[newlen] = '\0';
return TRUE;
}
#endif /* ODBCVER */
/*
*
*/
static int static int
ResolveOneParam(QueryBuild *qb) ResolveOneParam(QueryBuild *qb)
{ {
...@@ -2138,6 +2384,11 @@ ResolveOneParam(QueryBuild *qb) ...@@ -2138,6 +2384,11 @@ ResolveOneParam(QueryBuild *qb)
break; break;
} }
#if (ODBCVER >= 0x0300)
case SQL_C_NUMERIC:
if (ResolveNumericParam((SQL_NUMERIC_STRUCT *) buffer, param_string))
break;
#endif
default: default:
/* error */ /* error */
qb->errormsg = "Unrecognized C_parameter type in copy_statement_with_parameters"; qb->errormsg = "Unrecognized C_parameter type in copy_statement_with_parameters";
...@@ -2336,13 +2587,13 @@ ResolveOneParam(QueryBuild *qb) ...@@ -2336,13 +2587,13 @@ ResolveOneParam(QueryBuild *qb)
if (buf) if (buf)
{ {
cbuf[0] = '\''; cbuf[0] = '\'';
my_strcpy(cbuf + 1, sizeof(cbuf) - 12, buf, used); /* 12 = 1('\'') + my_strcpy(cbuf + 1, sizeof(cbuf) - 3, buf, used); /* 3 = 1('\'') +
* strlen("'::numeric") * strlen("'")
* + 1('\0') */ * + 1('\0') */
strcat(cbuf, "'::numeric"); strcat(cbuf, "'");
} }
else else
sprintf(cbuf, "'%s'::numeric", param_string); sprintf(cbuf, "'%s'", param_string);
CVT_APPEND_STR(qb, cbuf); CVT_APPEND_STR(qb, cbuf);
break; break;
default: /* a numeric type or SQL_BIT */ default: /* a numeric type or SQL_BIT */
......
...@@ -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.4 2002/04/10 08:18:54 inoue Exp $ * $Id: descriptor.h,v 1.5 2002/05/22 05:51:03 inoue Exp $
* *
*/ */
...@@ -20,6 +20,7 @@ typedef struct ...@@ -20,6 +20,7 @@ typedef struct
char schema[MAX_SCHEMA_LEN + 1]; char schema[MAX_SCHEMA_LEN + 1];
char name[MAX_TABLE_LEN + 1]; char name[MAX_TABLE_LEN + 1];
char alias[MAX_TABLE_LEN + 1]; char alias[MAX_TABLE_LEN + 1];
char updatable;
} TABLE_INFO; } TABLE_INFO;
typedef struct typedef struct
...@@ -41,6 +42,8 @@ typedef struct ...@@ -41,6 +42,8 @@ typedef struct
char name[MAX_COLUMN_LEN + 1]; char name[MAX_COLUMN_LEN + 1];
char alias[MAX_COLUMN_LEN + 1]; char alias[MAX_COLUMN_LEN + 1];
} FIELD_INFO; } FIELD_INFO;
Int4 FI_precision(const FIELD_INFO *);
Int4 FI_scale(const FIELD_INFO *);
struct ARDFields_ struct ARDFields_
{ {
......
...@@ -340,7 +340,7 @@ ds_optionsProc(HWND hdlg, ...@@ -340,7 +340,7 @@ ds_optionsProc(HWND hdlg,
CheckDlgButton(hdlg, DS_DISALLOWPREMATURE, ci->disallow_premature); CheckDlgButton(hdlg, DS_DISALLOWPREMATURE, ci->disallow_premature);
CheckDlgButton(hdlg, DS_LFCONVERSION, ci->lf_conversion); CheckDlgButton(hdlg, DS_LFCONVERSION, ci->lf_conversion);
CheckDlgButton(hdlg, DS_TRUEISMINUS1, ci->true_is_minus1); CheckDlgButton(hdlg, DS_TRUEISMINUS1, ci->true_is_minus1);
CheckDlgButton(hdlg, DS_UPDATABLECURSORS, ci->updatable_cursors); CheckDlgButton(hdlg, DS_UPDATABLECURSORS, ci->allow_keyset);
#ifndef DRIVER_CURSOR_IMPLEMENT #ifndef DRIVER_CURSOR_IMPLEMENT
EnableWindow(GetDlgItem(hdlg, DS_UPDATABLECURSORS), FALSE); EnableWindow(GetDlgItem(hdlg, DS_UPDATABLECURSORS), FALSE);
#endif /* DRIVER_CURSOR_IMPLEMENT */ #endif /* DRIVER_CURSOR_IMPLEMENT */
...@@ -382,7 +382,7 @@ ds_optionsProc(HWND hdlg, ...@@ -382,7 +382,7 @@ ds_optionsProc(HWND hdlg,
ci->lf_conversion = IsDlgButtonChecked(hdlg, DS_LFCONVERSION); ci->lf_conversion = IsDlgButtonChecked(hdlg, DS_LFCONVERSION);
ci->true_is_minus1 = IsDlgButtonChecked(hdlg, DS_TRUEISMINUS1); ci->true_is_minus1 = IsDlgButtonChecked(hdlg, DS_TRUEISMINUS1);
#ifdef DRIVER_CURSOR_IMPLEMENT #ifdef DRIVER_CURSOR_IMPLEMENT
ci->updatable_cursors = IsDlgButtonChecked(hdlg, DS_UPDATABLECURSORS); ci->allow_keyset = IsDlgButtonChecked(hdlg, DS_UPDATABLECURSORS);
#endif /* DRIVER_CURSOR_IMPLEMENT */ #endif /* DRIVER_CURSOR_IMPLEMENT */
/* OID Options */ /* OID Options */
...@@ -590,7 +590,7 @@ makeConnectString(char *connect_string, const ConnInfo *ci, UWORD len) ...@@ -590,7 +590,7 @@ makeConnectString(char *connect_string, const ConnInfo *ci, UWORD len)
INI_LFCONVERSION, INI_LFCONVERSION,
ci->lf_conversion, ci->lf_conversion,
INI_UPDATABLECURSORS, INI_UPDATABLECURSORS,
ci->updatable_cursors, ci->allow_keyset,
INI_DISALLOWPREMATURE, INI_DISALLOWPREMATURE,
ci->disallow_premature, ci->disallow_premature,
INI_TRUEISMINUS1, INI_TRUEISMINUS1,
...@@ -601,7 +601,7 @@ makeConnectString(char *connect_string, const ConnInfo *ci, UWORD len) ...@@ -601,7 +601,7 @@ makeConnectString(char *connect_string, const ConnInfo *ci, UWORD len)
unsigned long flag = 0; unsigned long flag = 0;
if (ci->disallow_premature) if (ci->disallow_premature)
flag |= BIT_DISALLOWPREMATURE; flag |= BIT_DISALLOWPREMATURE;
if (ci->updatable_cursors) if (ci->allow_keyset)
flag |= BIT_UPDATABLECURSORS; flag |= BIT_UPDATABLECURSORS;
if (ci->lf_conversion) if (ci->lf_conversion)
flag |= BIT_LFCONVERSION; flag |= BIT_LFCONVERSION;
...@@ -686,7 +686,7 @@ unfoldCXAttribute(ConnInfo *ci, const char *value) ...@@ -686,7 +686,7 @@ unfoldCXAttribute(ConnInfo *ci, const char *value)
sscanf(value + 2, "%lx", &flag); sscanf(value + 2, "%lx", &flag);
} }
ci->disallow_premature = (char)((flag & BIT_DISALLOWPREMATURE) != 0); ci->disallow_premature = (char)((flag & BIT_DISALLOWPREMATURE) != 0);
ci->updatable_cursors = (char)((flag & BIT_UPDATABLECURSORS) != 0); ci->allow_keyset = (char)((flag & BIT_UPDATABLECURSORS) != 0);
ci->lf_conversion = (char)((flag & BIT_LFCONVERSION) != 0); ci->lf_conversion = (char)((flag & BIT_LFCONVERSION) != 0);
if (count < 4) if (count < 4)
return; return;
...@@ -770,7 +770,7 @@ copyAttributes(ConnInfo *ci, const char *attribute, const char *value) ...@@ -770,7 +770,7 @@ copyAttributes(ConnInfo *ci, const char *attribute, const char *value)
else if (stricmp(attribute, INI_DISALLOWPREMATURE) == 0 || stricmp(attribute, "C3") == 0) else if (stricmp(attribute, INI_DISALLOWPREMATURE) == 0 || stricmp(attribute, "C3") == 0)
ci->disallow_premature = atoi(value); ci->disallow_premature = atoi(value);
else if (stricmp(attribute, INI_UPDATABLECURSORS) == 0 || stricmp(attribute, "C4") == 0) else if (stricmp(attribute, INI_UPDATABLECURSORS) == 0 || stricmp(attribute, "C4") == 0)
ci->updatable_cursors = atoi(value); ci->allow_keyset = atoi(value);
else if (stricmp(attribute, INI_LFCONVERSION) == 0) else if (stricmp(attribute, INI_LFCONVERSION) == 0)
ci->lf_conversion = atoi(value); ci->lf_conversion = atoi(value);
else if (stricmp(attribute, INI_TRUEISMINUS1) == 0) else if (stricmp(attribute, INI_TRUEISMINUS1) == 0)
...@@ -870,8 +870,8 @@ getDSNdefaults(ConnInfo *ci) ...@@ -870,8 +870,8 @@ getDSNdefaults(ConnInfo *ci)
if (ci->disallow_premature < 0) if (ci->disallow_premature < 0)
ci->disallow_premature = DEFAULT_DISALLOWPREMATURE; ci->disallow_premature = DEFAULT_DISALLOWPREMATURE;
if (ci->updatable_cursors < 0) if (ci->allow_keyset < 0)
ci->updatable_cursors = DEFAULT_UPDATABLECURSORS; ci->allow_keyset = DEFAULT_UPDATABLECURSORS;
if (ci->lf_conversion < 0) if (ci->lf_conversion < 0)
ci->lf_conversion = DEFAULT_LFCONVERSION; ci->lf_conversion = DEFAULT_LFCONVERSION;
if (ci->true_is_minus1 < 0) if (ci->true_is_minus1 < 0)
...@@ -960,11 +960,11 @@ getDSNinfo(ConnInfo *ci, char overwrite) ...@@ -960,11 +960,11 @@ getDSNinfo(ConnInfo *ci, char overwrite)
ci->disallow_premature = atoi(temp); ci->disallow_premature = atoi(temp);
} }
if (ci->updatable_cursors < 0 || overwrite) if (ci->allow_keyset < 0 || overwrite)
{ {
SQLGetPrivateProfileString(DSN, INI_UPDATABLECURSORS, "", temp, sizeof(temp), ODBC_INI); SQLGetPrivateProfileString(DSN, INI_UPDATABLECURSORS, "", temp, sizeof(temp), ODBC_INI);
if (temp[0]) if (temp[0])
ci->updatable_cursors = atoi(temp); ci->allow_keyset = atoi(temp);
} }
if (ci->lf_conversion < 0 || overwrite) if (ci->lf_conversion < 0 || overwrite)
...@@ -1094,7 +1094,7 @@ writeDSNinfo(const ConnInfo *ci) ...@@ -1094,7 +1094,7 @@ writeDSNinfo(const ConnInfo *ci)
INI_DISALLOWPREMATURE, INI_DISALLOWPREMATURE,
temp, temp,
ODBC_INI); ODBC_INI);
sprintf(temp, "%d", ci->updatable_cursors); sprintf(temp, "%d", ci->allow_keyset);
SQLWritePrivateProfileString(DSN, SQLWritePrivateProfileString(DSN,
INI_UPDATABLECURSORS, INI_UPDATABLECURSORS,
temp, temp,
......
...@@ -78,6 +78,12 @@ PGAPI_FreeEnv(HENV henv) ...@@ -78,6 +78,12 @@ PGAPI_FreeEnv(HENV henv)
} }
static void
pg_sqlstate_set(const EnvironmentClass *env, UCHAR *szSqlState, const UCHAR *ver3str, const UCHAR *ver2str)
{
strcpy(szSqlState, EN_is_odbc3(env) ? ver3str : ver2str);
}
#define DRVMNGRDIV 511 #define DRVMNGRDIV 511
/* Returns the next SQL error information. */ /* Returns the next SQL error information. */
RETCODE SQL_API RETCODE SQL_API
...@@ -92,6 +98,7 @@ PGAPI_StmtError( HSTMT hstmt, ...@@ -92,6 +98,7 @@ PGAPI_StmtError( HSTMT hstmt,
{ {
/* CC: return an error of a hstmt */ /* CC: return an error of a hstmt */
StatementClass *stmt = (StatementClass *) hstmt; StatementClass *stmt = (StatementClass *) hstmt;
EnvironmentClass *env = (EnvironmentClass *) SC_get_conn(stmt)->henv;
char *msg; char *msg;
int status; int status;
BOOL partial_ok = ((flag & PODBC_ALLOW_PARTIAL_EXTRACT) != 0), BOOL partial_ok = ((flag & PODBC_ALLOW_PARTIAL_EXTRACT) != 0),
...@@ -173,120 +180,124 @@ PGAPI_StmtError( HSTMT hstmt, ...@@ -173,120 +180,124 @@ PGAPI_StmtError( HSTMT hstmt,
{ {
/* now determine the SQLSTATE to be returned */ /* now determine the SQLSTATE to be returned */
case STMT_ROW_VERSION_CHANGED: case STMT_ROW_VERSION_CHANGED:
strcpy(szSqlState, "01001"); pg_sqlstate_set(env, szSqlState, "01001", "01001");
/* data truncated */ /* data truncated */
break; break;
case STMT_TRUNCATED: case STMT_TRUNCATED:
strcpy(szSqlState, "01004"); pg_sqlstate_set(env, szSqlState, "01004", "01004");
/* data truncated */ /* data truncated */
break; break;
case STMT_INFO_ONLY: case STMT_INFO_ONLY:
strcpy(szSqlState, "00000"); pg_sqlstate_set(env, szSqlState, "00000", "0000");
/* just information that is returned, no error */ /* just information that is returned, no error */
break; break;
case STMT_BAD_ERROR: case STMT_BAD_ERROR:
strcpy(szSqlState, "08S01"); pg_sqlstate_set(env, szSqlState, "08S01", "08S01");
/* communication link failure */ /* communication link failure */
break; break;
case STMT_CREATE_TABLE_ERROR: case STMT_CREATE_TABLE_ERROR:
strcpy(szSqlState, "S0001"); pg_sqlstate_set(env, szSqlState, "42S01", "S0001");
/* table already exists */ /* table already exists */
break; break;
case STMT_STATUS_ERROR: case STMT_STATUS_ERROR:
case STMT_SEQUENCE_ERROR: case STMT_SEQUENCE_ERROR:
strcpy(szSqlState, "S1010"); pg_sqlstate_set(env, szSqlState, "HY010", "S1010");
/* Function sequence error */ /* Function sequence error */
break; break;
case STMT_NO_MEMORY_ERROR: case STMT_NO_MEMORY_ERROR:
strcpy(szSqlState, "S1001"); pg_sqlstate_set(env, szSqlState, "HY001", "S1001");
/* memory allocation failure */ /* memory allocation failure */
break; break;
case STMT_COLNUM_ERROR: case STMT_COLNUM_ERROR:
strcpy(szSqlState, "S1002"); pg_sqlstate_set(env, szSqlState, "07009", "S1002");
/* invalid column number */ /* invalid column number */
break; break;
case STMT_NO_STMTSTRING: case STMT_NO_STMTSTRING:
strcpy(szSqlState, "S1001"); pg_sqlstate_set(env, szSqlState, "HY001", "S1001");
/* having no stmtstring is also a malloc problem */ /* having no stmtstring is also a malloc problem */
break; break;
case STMT_ERROR_TAKEN_FROM_BACKEND: case STMT_ERROR_TAKEN_FROM_BACKEND:
strcpy(szSqlState, "S1000"); pg_sqlstate_set(env, szSqlState, "HY000", "S1000");
/* general error */ /* general error */
break; break;
case STMT_INTERNAL_ERROR: case STMT_INTERNAL_ERROR:
strcpy(szSqlState, "S1000"); pg_sqlstate_set(env, szSqlState, "HY000", "S1000");
/* general error */ /* general error */
break; break;
case STMT_FETCH_OUT_OF_RANGE:
pg_sqlstate_set(env, szSqlState, "HY106", "S1106");
break;
case STMT_ROW_OUT_OF_RANGE: case STMT_ROW_OUT_OF_RANGE:
strcpy(szSqlState, "S1107"); pg_sqlstate_set(env, szSqlState, "HY107", "S1107");
break; break;
case STMT_OPERATION_CANCELLED: case STMT_OPERATION_CANCELLED:
strcpy(szSqlState, "S1008"); pg_sqlstate_set(env, szSqlState, "HY008", "S1008");
break; break;
case STMT_NOT_IMPLEMENTED_ERROR: case STMT_NOT_IMPLEMENTED_ERROR:
strcpy(szSqlState, "S1C00"); /* == 'driver not pg_sqlstate_set(env, szSqlState, "HYC00", "S1C00"); /* == 'driver not
* capable' */ * capable' */
break; break;
case STMT_OPTION_OUT_OF_RANGE_ERROR: case STMT_OPTION_OUT_OF_RANGE_ERROR:
strcpy(szSqlState, "S1092"); pg_sqlstate_set(env, szSqlState, "HY092", "S1092");
break; break;
case STMT_BAD_PARAMETER_NUMBER_ERROR: case STMT_BAD_PARAMETER_NUMBER_ERROR:
strcpy(szSqlState, "S1093"); pg_sqlstate_set(env, szSqlState, "07009", "S1093");
break; break;
case STMT_INVALID_COLUMN_NUMBER_ERROR: case STMT_INVALID_COLUMN_NUMBER_ERROR:
strcpy(szSqlState, "S1002"); pg_sqlstate_set(env, szSqlState, "07009", "S1002");
break; break;
case STMT_RESTRICTED_DATA_TYPE_ERROR: case STMT_RESTRICTED_DATA_TYPE_ERROR:
strcpy(szSqlState, "07006"); pg_sqlstate_set(env, szSqlState, "07006", "07006");
break; break;
case STMT_INVALID_CURSOR_STATE_ERROR: case STMT_INVALID_CURSOR_STATE_ERROR:
strcpy(szSqlState, "24000"); pg_sqlstate_set(env, szSqlState, "07005", "24000");
break; break;
case STMT_ERROR_IN_ROW: case STMT_ERROR_IN_ROW:
strcpy(szSqlState, "01S01"); pg_sqlstate_set(env, szSqlState, "01S01", "01S01");
break; break;
case STMT_OPTION_VALUE_CHANGED: case STMT_OPTION_VALUE_CHANGED:
strcpy(szSqlState, "01S02"); pg_sqlstate_set(env, szSqlState, "01S02", "01S02");
break; break;
case STMT_POS_BEFORE_RECORDSET: case STMT_POS_BEFORE_RECORDSET:
strcpy(szSqlState, "01S06"); pg_sqlstate_set(env, szSqlState, "01S06", "01S06");
break; break;
case STMT_INVALID_CURSOR_NAME: case STMT_INVALID_CURSOR_NAME:
strcpy(szSqlState, "34000"); pg_sqlstate_set(env, szSqlState, "34000", "34000");
break; break;
case STMT_NO_CURSOR_NAME: case STMT_NO_CURSOR_NAME:
strcpy(szSqlState, "S1015"); pg_sqlstate_set(env, szSqlState, "S1015", "S1015");
break; break;
case STMT_INVALID_ARGUMENT_NO: case STMT_INVALID_ARGUMENT_NO:
strcpy(szSqlState, "S1009"); pg_sqlstate_set(env, szSqlState, "HY024", "S1009");
/* invalid argument value */ /* invalid argument value */
break; break;
case STMT_INVALID_CURSOR_POSITION: case STMT_INVALID_CURSOR_POSITION:
strcpy(szSqlState, "S1109"); pg_sqlstate_set(env, szSqlState, "HY109", "S1109");
break; break;
case STMT_RETURN_NULL_WITHOUT_INDICATOR: case STMT_RETURN_NULL_WITHOUT_INDICATOR:
strcpy(szSqlState, "22002"); pg_sqlstate_set(env, szSqlState, "22002", "22002");
break; break;
case STMT_VALUE_OUT_OF_RANGE: case STMT_VALUE_OUT_OF_RANGE:
strcpy(szSqlState, "22003"); pg_sqlstate_set(env, szSqlState, "HY019", "22003");
break; break;
case STMT_OPERATION_INVALID: case STMT_OPERATION_INVALID:
strcpy(szSqlState, "S1011"); pg_sqlstate_set(env, szSqlState, "HY011", "S1011");
break; break;
case STMT_INVALID_DESCRIPTOR_IDENTIFIER: case STMT_INVALID_DESCRIPTOR_IDENTIFIER:
strcpy(szSqlState, "HY091"); pg_sqlstate_set(env, szSqlState, "HY091", "HY091");
break; break;
case STMT_INVALID_OPTION_IDENTIFIER: case STMT_INVALID_OPTION_IDENTIFIER:
strcpy(szSqlState, "HY092"); pg_sqlstate_set(env, szSqlState, "HY092", "HY092");
break; break;
case STMT_OPTION_NOT_FOR_THE_DRIVER: case STMT_OPTION_NOT_FOR_THE_DRIVER:
strcpy(szSqlState, "HYC00"); pg_sqlstate_set(env, szSqlState, "HYC00", "HYC00");
break; break;
case STMT_EXEC_ERROR: case STMT_EXEC_ERROR:
default: default:
strcpy(szSqlState, "S1000"); pg_sqlstate_set(env, szSqlState, "HY000", "S1000");
/* also a general error */ /* also a general error */
break; break;
} }
...@@ -314,6 +325,7 @@ PGAPI_ConnectError( HDBC hdbc, ...@@ -314,6 +325,7 @@ PGAPI_ConnectError( HDBC hdbc,
UWORD flag) UWORD flag)
{ {
ConnectionClass *conn = (ConnectionClass *) hdbc; ConnectionClass *conn = (ConnectionClass *) hdbc;
EnvironmentClass *env = (EnvironmentClass *) conn->henv;
char *msg; char *msg;
int status; int status;
BOOL once_again = FALSE; BOOL once_again = FALSE;
...@@ -357,43 +369,43 @@ PGAPI_ConnectError( HDBC hdbc, ...@@ -357,43 +369,43 @@ PGAPI_ConnectError( HDBC hdbc,
{ {
case STMT_OPTION_VALUE_CHANGED: case STMT_OPTION_VALUE_CHANGED:
case CONN_OPTION_VALUE_CHANGED: case CONN_OPTION_VALUE_CHANGED:
strcpy(szSqlState, "01S02"); pg_sqlstate_set(env, szSqlState, "01S02", "01S02");
break; break;
case STMT_TRUNCATED: case STMT_TRUNCATED:
case CONN_TRUNCATED: case CONN_TRUNCATED:
strcpy(szSqlState, "01004"); pg_sqlstate_set(env, szSqlState, "01004", "01004");
/* data truncated */ /* data truncated */
break; break;
case CONN_INIREAD_ERROR: case CONN_INIREAD_ERROR:
strcpy(szSqlState, "IM002"); pg_sqlstate_set(env, szSqlState, "IM002", "IM002");
/* data source not found */ /* data source not found */
break; break;
case CONNECTION_SERVER_NOT_REACHED: case CONNECTION_SERVER_NOT_REACHED:
case CONN_OPENDB_ERROR: case CONN_OPENDB_ERROR:
strcpy(szSqlState, "08001"); pg_sqlstate_set(env, szSqlState, "08001", "08001");
/* unable to connect to data source */ /* unable to connect to data source */
break; break;
case CONN_INVALID_AUTHENTICATION: case CONN_INVALID_AUTHENTICATION:
case CONN_AUTH_TYPE_UNSUPPORTED: case CONN_AUTH_TYPE_UNSUPPORTED:
strcpy(szSqlState, "28000"); pg_sqlstate_set(env, szSqlState, "28000", "28000");
break; break;
case CONN_STMT_ALLOC_ERROR: case CONN_STMT_ALLOC_ERROR:
strcpy(szSqlState, "S1001"); pg_sqlstate_set(env, szSqlState, "HY001", "S1001");
/* memory allocation failure */ /* memory allocation failure */
break; break;
case CONN_IN_USE: case CONN_IN_USE:
strcpy(szSqlState, "S1000"); pg_sqlstate_set(env, szSqlState, "HY000", "S1000");
/* general error */ /* general error */
break; break;
case CONN_UNSUPPORTED_OPTION: case CONN_UNSUPPORTED_OPTION:
strcpy(szSqlState, "IM001"); pg_sqlstate_set(env, szSqlState, "IM001", "IM001");
/* driver does not support this function */ /* driver does not support this function */
case CONN_INVALID_ARGUMENT_NO: case CONN_INVALID_ARGUMENT_NO:
strcpy(szSqlState, "S1009"); pg_sqlstate_set(env, szSqlState, "HY009", "S1009");
/* invalid argument value */ /* invalid argument value */
break; break;
case CONN_TRANSACT_IN_PROGRES: case CONN_TRANSACT_IN_PROGRES:
strcpy(szSqlState, "S1010"); pg_sqlstate_set(env, szSqlState, "HY010", "S1010");
/* /*
* when the user tries to switch commit mode in a * when the user tries to switch commit mode in a
...@@ -402,21 +414,21 @@ PGAPI_ConnectError( HDBC hdbc, ...@@ -402,21 +414,21 @@ PGAPI_ConnectError( HDBC hdbc,
/* -> function sequence error */ /* -> function sequence error */
break; break;
case CONN_NO_MEMORY_ERROR: case CONN_NO_MEMORY_ERROR:
strcpy(szSqlState, "S1001"); pg_sqlstate_set(env, szSqlState, "HY001", "S1001");
break; break;
case CONN_NOT_IMPLEMENTED_ERROR: case CONN_NOT_IMPLEMENTED_ERROR:
case STMT_NOT_IMPLEMENTED_ERROR: case STMT_NOT_IMPLEMENTED_ERROR:
strcpy(szSqlState, "S1C00"); pg_sqlstate_set(env, szSqlState, "HYC00", "S1C00");
break; break;
case STMT_RETURN_NULL_WITHOUT_INDICATOR: case STMT_RETURN_NULL_WITHOUT_INDICATOR:
strcpy(szSqlState, "22002"); pg_sqlstate_set(env, szSqlState, "22002", "22002");
break; break;
case CONN_VALUE_OUT_OF_RANGE: case CONN_VALUE_OUT_OF_RANGE:
case STMT_VALUE_OUT_OF_RANGE: case STMT_VALUE_OUT_OF_RANGE:
strcpy(szSqlState, "22003"); pg_sqlstate_set(env, szSqlState, "HY019", "22003");
break; break;
default: default:
strcpy(szSqlState, "S1000"); pg_sqlstate_set(env, szSqlState, "HY000", "S1000");
/* general error */ /* general error */
break; break;
} }
...@@ -455,7 +467,7 @@ PGAPI_EnvError( HENV henv, ...@@ -455,7 +467,7 @@ PGAPI_EnvError( HENV henv,
mylog("EN_get_error: status = %d, msg = #%s#\n", status, msg); mylog("EN_get_error: status = %d, msg = #%s#\n", status, msg);
if (NULL != szSqlState) if (NULL != szSqlState)
strcpy(szSqlState, "00000"); pg_sqlstate_set(env, szSqlState, "00000", "00000");
if (NULL != pcbErrorMsg) if (NULL != pcbErrorMsg)
*pcbErrorMsg = 0; *pcbErrorMsg = 0;
if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0)) if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0))
...@@ -478,10 +490,10 @@ PGAPI_EnvError( HENV henv, ...@@ -478,10 +490,10 @@ PGAPI_EnvError( HENV henv,
{ {
case ENV_ALLOC_ERROR: case ENV_ALLOC_ERROR:
/* memory allocation failure */ /* memory allocation failure */
strcpy(szSqlState, "S1001"); pg_sqlstate_set(env, szSqlState, "HY001", "S1001");
break; break;
default: default:
strcpy(szSqlState, "S1000"); pg_sqlstate_set(env, szSqlState, "HY000", "S1000");
/* general error */ /* general error */
break; break;
} }
......
...@@ -212,6 +212,7 @@ PGAPI_Execute( ...@@ -212,6 +212,7 @@ PGAPI_Execute(
int i, int i,
retval, start_row, end_row; retval, start_row, end_row;
int cursor_type, scroll_concurrency; int cursor_type, scroll_concurrency;
QResultClass *res;
mylog("%s: entering...\n", func); mylog("%s: entering...\n", func);
...@@ -403,6 +404,23 @@ next_param_row: ...@@ -403,6 +404,23 @@ next_param_row:
{ {
if (ipdopts->param_processed_ptr) if (ipdopts->param_processed_ptr)
(*ipdopts->param_processed_ptr)++; (*ipdopts->param_processed_ptr)++;
/* special handling of result for keyset driven cursors */
if (SQL_CURSOR_KEYSET_DRIVEN == stmt->options.cursor_type &&
SQL_CONCUR_READ_ONLY != stmt->options.scroll_concurrency)
{
QResultClass *kres;
res = SC_get_Result(stmt);
if (kres = res->next, kres)
{
kres->fields = res->fields;
res->fields = NULL;
kres->num_fields = res->num_fields;
res->next = NULL;
QR_Destructor(res);
SC_set_Result(stmt, kres);
}
}
} }
#if (ODBCVER >= 0x0300) #if (ODBCVER >= 0x0300)
if (ipdopts->param_status_ptr) if (ipdopts->param_status_ptr)
...@@ -440,7 +458,7 @@ next_param_row: ...@@ -440,7 +458,7 @@ next_param_row:
BOOL in_trans = CC_is_in_trans(conn); BOOL in_trans = CC_is_in_trans(conn);
BOOL issued_begin = FALSE, BOOL issued_begin = FALSE,
begin_included = FALSE; begin_included = FALSE;
QResultClass *res, *curres; QResultClass *curres;
if (strnicmp(stmt->stmt_with_params, "BEGIN;", 6) == 0) if (strnicmp(stmt->stmt_with_params, "BEGIN;", 6) == 0)
begin_included = TRUE; begin_included = TRUE;
...@@ -474,7 +492,9 @@ next_param_row: ...@@ -474,7 +492,9 @@ next_param_row:
stmt->status = STMT_FINISHED; stmt->status = STMT_FINISHED;
return SQL_SUCCESS; return SQL_SUCCESS;
} }
else if (stmt->options.cursor_type != cursor_type || if (res = SC_get_Curres(stmt), res)
stmt->diag_row_count = res->recent_processed_row_count;
if (stmt->options.cursor_type != cursor_type ||
stmt->options.scroll_concurrency != scroll_concurrency) stmt->options.scroll_concurrency != scroll_concurrency)
{ {
stmt->errornumber = STMT_OPTION_VALUE_CHANGED; stmt->errornumber = STMT_OPTION_VALUE_CHANGED;
...@@ -548,7 +568,7 @@ PGAPI_Transact( ...@@ -548,7 +568,7 @@ PGAPI_Transact(
if (!res) if (!res)
{ {
/* error msg will be in the connection */ /* error msg will be in the connection */
CC_on_abort(conn, TRUE); CC_on_abort(conn, NO_TRANS);
CC_log_error(func, "", conn); CC_log_error(func, "", conn);
return SQL_ERROR; return SQL_ERROR;
} }
...@@ -558,7 +578,7 @@ PGAPI_Transact( ...@@ -558,7 +578,7 @@ PGAPI_Transact(
if (!ok) if (!ok)
{ {
CC_on_abort(conn, TRUE); CC_on_abort(conn, NO_TRANS);
CC_log_error(func, "", conn); CC_log_error(func, "", conn);
return SQL_ERROR; return SQL_ERROR;
} }
......
...@@ -210,7 +210,10 @@ PGAPI_GetInfo( ...@@ -210,7 +210,10 @@ PGAPI_GetInfo(
case SQL_DEFAULT_TXN_ISOLATION: /* ODBC 1.0 */ case SQL_DEFAULT_TXN_ISOLATION: /* ODBC 1.0 */
len = 4; len = 4;
value = SQL_TXN_READ_COMMITTED; /* SQL_TXN_SERIALIZABLE; */ if (PG_VERSION_LT(conn, 6.5))
value = SQL_TXN_SERIALIZABLE;
else
value = SQL_TXN_READ_COMMITTED;
break; break;
case SQL_DRIVER_NAME: /* ODBC 1.0 */ case SQL_DRIVER_NAME: /* ODBC 1.0 */
...@@ -505,7 +508,7 @@ PGAPI_GetInfo( ...@@ -505,7 +508,7 @@ PGAPI_GetInfo(
case SQL_POS_OPERATIONS: /* ODBC 2.0 */ case SQL_POS_OPERATIONS: /* ODBC 2.0 */
len = 4; len = 4;
value = ci->drivers.lie ? (SQL_POS_POSITION | SQL_POS_REFRESH | SQL_POS_UPDATE | SQL_POS_DELETE | SQL_POS_ADD) : (SQL_POS_POSITION | SQL_POS_REFRESH); value = (SQL_POS_POSITION | SQL_POS_REFRESH);
#ifdef DRIVER_CURSOR_IMPLEMENT #ifdef DRIVER_CURSOR_IMPLEMENT
if (ci->updatable_cursors) if (ci->updatable_cursors)
value |= (SQL_POS_UPDATE | SQL_POS_DELETE | SQL_POS_ADD); value |= (SQL_POS_UPDATE | SQL_POS_DELETE | SQL_POS_ADD);
...@@ -557,32 +560,29 @@ PGAPI_GetInfo( ...@@ -557,32 +560,29 @@ PGAPI_GetInfo(
* Driver doesn't support keyset-driven or mixed cursors, so * Driver doesn't support keyset-driven or mixed cursors, so
* not much point in saying row updates are supported * not much point in saying row updates are supported
*/ */
p = (ci->drivers.lie || ci->updatable_cursors) ? "Y" : "N"; p = (ci->updatable_cursors) ? "Y" : "N";
break; break;
case SQL_SCROLL_CONCURRENCY: /* ODBC 1.0 */ case SQL_SCROLL_CONCURRENCY: /* ODBC 1.0 */
len = 4; len = 4;
value = ci->drivers.lie ? (SQL_SCCO_READ_ONLY | value = SQL_SCCO_READ_ONLY;
SQL_SCCO_LOCK |
SQL_SCCO_OPT_ROWVER |
SQL_SCCO_OPT_VALUES) :
(SQL_SCCO_READ_ONLY);
#ifdef DRIVER_CURSOR_IMPLEMENT #ifdef DRIVER_CURSOR_IMPLEMENT
if (ci->updatable_cursors) if (ci->updatable_cursors)
value |= SQL_SCCO_OPT_ROWVER; value |= SQL_SCCO_OPT_ROWVER;
#endif /* DRIVER_CURSOR_IMPLEMENT */ #endif /* DRIVER_CURSOR_IMPLEMENT */
if (ci->drivers.lie)
value |= (SQL_SCCO_LOCK | SQL_SCCO_OPT_VALUES);
break; break;
case SQL_SCROLL_OPTIONS: /* ODBC 1.0 */ case SQL_SCROLL_OPTIONS: /* ODBC 1.0 */
len = 4; len = 4;
value = ci->drivers.lie ? (SQL_SO_FORWARD_ONLY | value = SQL_SO_FORWARD_ONLY;
SQL_SO_STATIC | if (!ci->drivers.use_declarefetch)
SQL_SO_KEYSET_DRIVEN | value |= SQL_SO_STATIC;
SQL_SO_DYNAMIC |
SQL_SO_MIXED)
: (ci->drivers.use_declarefetch ? SQL_SO_FORWARD_ONLY : (SQL_SO_FORWARD_ONLY | SQL_SO_STATIC));
if (ci->updatable_cursors) if (ci->updatable_cursors)
value |= 0; /* SQL_SO_KEYSET_DRIVEN in the furure */ value |= SQL_SO_KEYSET_DRIVEN;
if (ci->drivers.lie)
value |= (SQL_SO_DYNAMIC | SQL_SO_MIXED);
break; break;
case SQL_SEARCH_PATTERN_ESCAPE: /* ODBC 1.0 */ case SQL_SEARCH_PATTERN_ESCAPE: /* ODBC 1.0 */
...@@ -602,7 +602,7 @@ PGAPI_GetInfo( ...@@ -602,7 +602,7 @@ PGAPI_GetInfo(
case SQL_STATIC_SENSITIVITY: /* ODBC 2.0 */ case SQL_STATIC_SENSITIVITY: /* ODBC 2.0 */
len = 4; len = 4;
value = ci->drivers.lie ? (SQL_SS_ADDITIONS | SQL_SS_DELETIONS | SQL_SS_UPDATES) : 0; value = 0;
#ifdef DRIVER_CURSOR_IMPLEMENT #ifdef DRIVER_CURSOR_IMPLEMENT
if (ci->updatable_cursors) if (ci->updatable_cursors)
value |= (SQL_SS_ADDITIONS | SQL_SS_DELETIONS | SQL_SS_UPDATES); value |= (SQL_SS_ADDITIONS | SQL_SS_DELETIONS | SQL_SS_UPDATES);
...@@ -666,7 +666,12 @@ PGAPI_GetInfo( ...@@ -666,7 +666,12 @@ PGAPI_GetInfo(
case SQL_TXN_ISOLATION_OPTION: /* ODBC 1.0 */ case SQL_TXN_ISOLATION_OPTION: /* ODBC 1.0 */
len = 4; len = 4;
value = SQL_TXN_READ_COMMITTED; /* SQL_TXN_SERIALIZABLE; */ if (PG_VERSION_LT(conn, 6.5))
value = SQL_TXN_SERIALIZABLE;
else if (PG_VERSION_GE(conn, 7.1))
value = SQL_TXN_READ_COMMITTED | SQL_TXN_SERIALIZABLE;
else
value = SQL_TXN_READ_COMMITTED;
break; break;
case SQL_UNION: /* ODBC 2.0 */ case SQL_UNION: /* ODBC 2.0 */
...@@ -2097,7 +2102,7 @@ PGAPI_SpecialColumns( ...@@ -2097,7 +2102,7 @@ PGAPI_SpecialColumns(
RETCODE result; RETCODE result;
char relhasrules[MAX_INFO_STRING]; char relhasrules[MAX_INFO_STRING];
mylog("%s: entering...stmt=%u scnm=%x len=%d\n", func, stmt, szTableOwner, cbTableOwner); mylog("%s: entering...stmt=%u scnm=%x len=%d colType=%d\n", func, stmt, szTableOwner, cbTableOwner, fColType);
if (!stmt) if (!stmt)
{ {
...@@ -2221,6 +2226,43 @@ PGAPI_SpecialColumns( ...@@ -2221,6 +2226,43 @@ PGAPI_SpecialColumns(
} }
} }
} }
else
{
/* use the oid value for the rowid */
if (fColType == SQL_BEST_ROWID)
{
row = (TupleNode *) malloc(sizeof(TupleNode) + (8 - 1) *sizeof(TupleField));
set_tuplefield_int2(&row->tuple[0], SQL_SCOPE_SESSION);
set_tuplefield_string(&row->tuple[1], "oid");
set_tuplefield_int2(&row->tuple[2], pgtype_to_concise_type(stmt, PG_TYPE_OID));
set_tuplefield_string(&row->tuple[3], "OID");
set_tuplefield_int4(&row->tuple[4], pgtype_column_size(stmt, PG_TYPE_OID, PG_STATIC, PG_STATIC));
set_tuplefield_int4(&row->tuple[5], pgtype_buffer_length(stmt, PG_TYPE_OID, PG_STATIC, PG_STATIC));
set_tuplefield_int2(&row->tuple[6], pgtype_decimal_digits(stmt, PG_TYPE_OID, PG_STATIC));
set_tuplefield_int2(&row->tuple[7], SQL_PC_NOT_PSEUDO);
QR_add_tuple(res, row);
}
else if (fColType == SQL_ROWVER)
{
Int2 the_type = PG_TYPE_TID;
row = (TupleNode *) malloc(sizeof(TupleNode) + (8 - 1) *sizeof(TupleField));
set_tuplefield_null(&row->tuple[0]);
set_tuplefield_string(&row->tuple[1], "ctid");
set_tuplefield_int2(&row->tuple[2], pgtype_to_concise_type(stmt, the_type));
set_tuplefield_string(&row->tuple[3], pgtype_to_name(stmt, the_type));
set_tuplefield_int4(&row->tuple[4], pgtype_column_size(stmt, the_type, PG_STATIC, PG_STATIC));
set_tuplefield_int4(&row->tuple[5], pgtype_buffer_length(stmt, the_type, PG_STATIC, PG_STATIC));
set_tuplefield_int2(&row->tuple[6], pgtype_decimal_digits(stmt, the_type, PG_STATIC));
set_tuplefield_int2(&row->tuple[7], SQL_PC_NOT_PSEUDO);
QR_add_tuple(res, row);
}
}
stmt->status = STMT_FINISHED; stmt->status = STMT_FINISHED;
stmt->currTuple = -1; stmt->currTuple = -1;
...@@ -3124,7 +3166,7 @@ getClientColumnName(ConnectionClass *conn, UInt4 relid, char *serverColumnName, ...@@ -3124,7 +3166,7 @@ getClientColumnName(ConnectionClass *conn, UInt4 relid, char *serverColumnName,
{ {
if (res = CC_send_query(conn, "select getdatabaseencoding()", NULL, CLEAR_RESULT_ON_ABORT), res) if (res = CC_send_query(conn, "select getdatabaseencoding()", NULL, CLEAR_RESULT_ON_ABORT), res)
{ {
if (QR_get_num_tuples(res) > 0) if (QR_get_num_backend_tuples(res) > 0)
conn->server_encoding = strdup(QR_get_value_backend_row(res, 0, 0)); conn->server_encoding = strdup(QR_get_value_backend_row(res, 0, 0));
QR_Destructor(res); QR_Destructor(res);
} }
...@@ -3140,7 +3182,7 @@ getClientColumnName(ConnectionClass *conn, UInt4 relid, char *serverColumnName, ...@@ -3140,7 +3182,7 @@ getClientColumnName(ConnectionClass *conn, UInt4 relid, char *serverColumnName,
relid, serverColumnName); relid, serverColumnName);
if (res = CC_send_query(conn, query, NULL, CLEAR_RESULT_ON_ABORT), res) if (res = CC_send_query(conn, query, NULL, CLEAR_RESULT_ON_ABORT), res)
{ {
if (QR_get_num_tuples(res) > 0) if (QR_get_num_backend_tuples(res) > 0)
{ {
strcpy(saveattnum, QR_get_value_backend_row(res, 0, 0)); strcpy(saveattnum, QR_get_value_backend_row(res, 0, 0));
} }
...@@ -3165,7 +3207,7 @@ getClientColumnName(ConnectionClass *conn, UInt4 relid, char *serverColumnName, ...@@ -3165,7 +3207,7 @@ getClientColumnName(ConnectionClass *conn, UInt4 relid, char *serverColumnName,
sprintf(query, "select attname from pg_attribute where attrelid = %u and attnum = %s", relid, saveattnum); sprintf(query, "select attname from pg_attribute where attrelid = %u and attnum = %s", relid, saveattnum);
if (res = CC_send_query(conn, query, NULL, CLEAR_RESULT_ON_ABORT), res) if (res = CC_send_query(conn, query, NULL, CLEAR_RESULT_ON_ABORT), res)
{ {
if (QR_get_num_tuples(res) > 0) if (QR_get_num_backend_tuples(res) > 0)
{ {
ret = strdup(QR_get_value_backend_row(res, 0, 0)); ret = strdup(QR_get_value_backend_row(res, 0, 0));
*nameAlloced = TRUE; *nameAlloced = TRUE;
...@@ -4135,7 +4177,7 @@ PGAPI_Procedures( ...@@ -4135,7 +4177,7 @@ PGAPI_Procedures(
* The following seems the simplest implementation * The following seems the simplest implementation
*/ */
if (conn->schema_support) if (conn->schema_support)
strcpy(proc_query, "select '' as " "PROCEDURE_CAT" ", case when nspname = 'PUBLIC' then ''::text else nspname end as " "PROCEDURE_SCHEM" "," strcpy(proc_query, "select '' as " "PROCEDURE_CAT" ", nspname as " "PROCEDURE_SCHEM" ","
" proname as " "PROCEDURE_NAME" ", '' as " "NUM_INPUT_PARAMS" "," " proname as " "PROCEDURE_NAME" ", '' as " "NUM_INPUT_PARAMS" ","
" '' as " "NUM_OUTPUT_PARAMS" ", '' as " "NUM_RESULT_SETS" "," " '' as " "NUM_OUTPUT_PARAMS" ", '' as " "NUM_RESULT_SETS" ","
" '' as " "REMARKS" "," " '' as " "REMARKS" ","
...@@ -4204,7 +4246,7 @@ usracl_auth(char *usracl, const char *auth) ...@@ -4204,7 +4246,7 @@ usracl_auth(char *usracl, const char *auth)
static void static void
useracl_upd(char (*useracl)[ACLMAX], QResultClass *allures, const char *user, const char *auth) useracl_upd(char (*useracl)[ACLMAX], QResultClass *allures, const char *user, const char *auth)
{ {
int usercount = QR_get_num_tuples(allures), i, addcnt = 0; int usercount = QR_get_num_backend_tuples(allures), i, addcnt = 0;
mylog("user=%s auth=%s\n", user, auth); mylog("user=%s auth=%s\n", user, auth);
if (user[0]) if (user[0])
...@@ -4315,7 +4357,7 @@ PGAPI_TablePrivileges( ...@@ -4315,7 +4357,7 @@ PGAPI_TablePrivileges(
return SQL_ERROR; return SQL_ERROR;
} }
strncpy_null(proc_query, "select usename, usesysid, usesuper from pg_user", sizeof(proc_query)); strncpy_null(proc_query, "select usename, usesysid, usesuper from pg_user", sizeof(proc_query));
tablecount = QR_get_num_tuples(res); tablecount = QR_get_num_backend_tuples(res);
if (allures = CC_send_query(conn, proc_query, NULL, CLEAR_RESULT_ON_ABORT), !allures) if (allures = CC_send_query(conn, proc_query, NULL, CLEAR_RESULT_ON_ABORT), !allures)
{ {
QR_Destructor(res); QR_Destructor(res);
...@@ -4323,7 +4365,7 @@ PGAPI_TablePrivileges( ...@@ -4323,7 +4365,7 @@ PGAPI_TablePrivileges(
stmt->errormsg = "PGAPI_TablePrivileges query error"; stmt->errormsg = "PGAPI_TablePrivileges query error";
return SQL_ERROR; return SQL_ERROR;
} }
usercount = QR_get_num_tuples(allures); usercount = QR_get_num_backend_tuples(allures);
useracl = (char (*)[ACLMAX]) malloc(usercount * sizeof(char [ACLMAX])); useracl = (char (*)[ACLMAX]) malloc(usercount * sizeof(char [ACLMAX]));
for (i = 0; i < tablecount; i++) for (i = 0; i < tablecount; i++)
{ {
......
...@@ -38,12 +38,11 @@ PGAPI_GetInfo30(HDBC hdbc, UWORD fInfoType, PTR rgbInfoValue, ...@@ -38,12 +38,11 @@ PGAPI_GetInfo30(HDBC hdbc, UWORD fInfoType, PTR rgbInfoValue,
case SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES1: case SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES1:
len = 4; len = 4;
value = SQL_CA1_NEXT | SQL_CA1_ABSOLUTE | value = SQL_CA1_NEXT; /* others aren't allowed in ODBC spec */
SQL_CA1_RELATIVE | SQL_CA1_BOOKMARK;
break; break;
case SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES2: case SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES2:
len = 4; len = 4;
value = 0; value = SQL_CA2_READ_ONLY_CONCURRENCY;
break; break;
case SQL_KEYSET_CURSOR_ATTRIBUTES1: case SQL_KEYSET_CURSOR_ATTRIBUTES1:
len = 4; len = 4;
...@@ -71,6 +70,8 @@ PGAPI_GetInfo30(HDBC hdbc, UWORD fInfoType, PTR rgbInfoValue, ...@@ -71,6 +70,8 @@ PGAPI_GetInfo30(HDBC hdbc, UWORD fInfoType, PTR rgbInfoValue,
value = 0; value = 0;
if (ci->updatable_cursors || ci->drivers.lie) if (ci->updatable_cursors || ci->drivers.lie)
value |= (SQL_CA2_OPT_ROWVER_CONCURRENCY value |= (SQL_CA2_OPT_ROWVER_CONCURRENCY
/*| SQL_CA2_CRC_APPROXIMATE*/
| SQL_CA2_CRC_EXACT
| SQL_CA2_SENSITIVITY_DELETIONS | SQL_CA2_SENSITIVITY_DELETIONS
| SQL_CA2_SENSITIVITY_UPDATES | SQL_CA2_SENSITIVITY_UPDATES
/* | SQL_CA2_SENSITIVITY_ADDITIONS */ /* | SQL_CA2_SENSITIVITY_ADDITIONS */
...@@ -85,8 +86,6 @@ PGAPI_GetInfo30(HDBC hdbc, UWORD fInfoType, PTR rgbInfoValue, ...@@ -85,8 +86,6 @@ PGAPI_GetInfo30(HDBC hdbc, UWORD fInfoType, PTR rgbInfoValue,
| SQL_CA2_MAX_ROWS_UPDATE | SQL_CA2_MAX_ROWS_UPDATE
| SQL_CA2_MAX_ROWS_CATALOG | SQL_CA2_MAX_ROWS_CATALOG
| SQL_CA2_MAX_ROWS_AFFECTS_ALL | SQL_CA2_MAX_ROWS_AFFECTS_ALL
| SQL_CA2_CRC_EXACT
| SQL_CA2_CRC_APPROXIMATE
| SQL_CA2_SIMULATE_NON_UNIQUE | SQL_CA2_SIMULATE_NON_UNIQUE
| SQL_CA2_SIMULATE_TRY_UNIQUE | SQL_CA2_SIMULATE_TRY_UNIQUE
| SQL_CA2_SIMULATE_UNIQUE | SQL_CA2_SIMULATE_UNIQUE
...@@ -101,6 +100,7 @@ PGAPI_GetInfo30(HDBC hdbc, UWORD fInfoType, PTR rgbInfoValue, ...@@ -101,6 +100,7 @@ PGAPI_GetInfo30(HDBC hdbc, UWORD fInfoType, PTR rgbInfoValue,
| SQL_CA1_POS_REFRESH; | SQL_CA1_POS_REFRESH;
if (ci->updatable_cursors) if (ci->updatable_cursors)
value |= (SQL_CA1_POS_UPDATE | SQL_CA1_POS_DELETE value |= (SQL_CA1_POS_UPDATE | SQL_CA1_POS_DELETE
| SQL_CA1_BULK_ADD
); );
break; break;
case SQL_STATIC_CURSOR_ATTRIBUTES2: case SQL_STATIC_CURSOR_ATTRIBUTES2:
...@@ -108,6 +108,7 @@ PGAPI_GetInfo30(HDBC hdbc, UWORD fInfoType, PTR rgbInfoValue, ...@@ -108,6 +108,7 @@ PGAPI_GetInfo30(HDBC hdbc, UWORD fInfoType, PTR rgbInfoValue,
value = SQL_CA2_READ_ONLY_CONCURRENCY; value = SQL_CA2_READ_ONLY_CONCURRENCY;
if (ci->updatable_cursors) if (ci->updatable_cursors)
value |= (SQL_CA2_OPT_ROWVER_CONCURRENCY value |= (SQL_CA2_OPT_ROWVER_CONCURRENCY
| SQL_CA2_CRC_EXACT
/* | SQL_CA2_SENSITIVITY_ADDITIONS /* | SQL_CA2_SENSITIVITY_ADDITIONS
| SQL_CA2_SENSITIVITY_DELETIONS | SQL_CA2_SENSITIVITY_DELETIONS
| SQL_CA2_SENSITIVITY_UPDATES */ | SQL_CA2_SENSITIVITY_UPDATES */
...@@ -117,6 +118,8 @@ PGAPI_GetInfo30(HDBC hdbc, UWORD fInfoType, PTR rgbInfoValue, ...@@ -117,6 +118,8 @@ PGAPI_GetInfo30(HDBC hdbc, UWORD fInfoType, PTR rgbInfoValue,
case SQL_ODBC_INTERFACE_CONFORMANCE: case SQL_ODBC_INTERFACE_CONFORMANCE:
len = 4; len = 4;
value = SQL_OIC_CORE; value = SQL_OIC_CORE;
if (ci->drivers.lie)
value = SQL_OIC_LEVEL2;
break; break;
case SQL_ACTIVE_ENVIRONMENTS: case SQL_ACTIVE_ENVIRONMENTS:
len = 2; len = 2;
......
...@@ -105,7 +105,7 @@ mylog(char *fmt,...) ...@@ -105,7 +105,7 @@ mylog(char *fmt,...)
if (!LOGFP) if (!LOGFP)
{ {
generate_filename(MYLOGDIR, MYLOGFILE, filebuf); generate_filename(MYLOGDIR, MYLOGFILE, filebuf);
LOGFP = fopen(filebuf, PG_BINARY_W); LOGFP = fopen(filebuf, PG_BINARY_A);
setbuf(LOGFP, NULL); setbuf(LOGFP, NULL);
} }
...@@ -138,7 +138,7 @@ qlog(char *fmt,...) ...@@ -138,7 +138,7 @@ qlog(char *fmt,...)
if (!LOGFP) if (!LOGFP)
{ {
generate_filename(QLOGDIR, QLOGFILE, filebuf); generate_filename(QLOGDIR, QLOGFILE, filebuf);
LOGFP = fopen(filebuf, PG_BINARY_W); LOGFP = fopen(filebuf, PG_BINARY_A);
setbuf(LOGFP, NULL); setbuf(LOGFP, NULL);
} }
...@@ -284,8 +284,13 @@ schema_strcat(char *buf, const char *fmt, const char *s, int len, const char *tb ...@@ -284,8 +284,13 @@ schema_strcat(char *buf, const char *fmt, const char *s, int len, const char *tb
{ {
if (!s || 0 == len) if (!s || 0 == len)
{ {
if (tbname && (tbnmlen > 0 || tbnmlen == SQL_NTS)) /*
return my_strcat(buf, fmt, "public", 6); * I can find no appropriate way to find
* the CURRENT SCHEMA. If you are lucky
* you can get expected result.
*/
/***** if (tbname && (tbnmlen > 0 || tbnmlen == SQL_NTS))
return my_strcat(buf, fmt, "public", 6); *****/
return NULL; return NULL;
} }
return my_strcat(buf, fmt, s, len); return my_strcat(buf, fmt, s, len);
......
...@@ -77,10 +77,12 @@ extern void qlog(char *fmt,...); ...@@ -77,10 +77,12 @@ extern void qlog(char *fmt,...);
#define PG_BINARY O_BINARY #define PG_BINARY O_BINARY
#define PG_BINARY_R "rb" #define PG_BINARY_R "rb"
#define PG_BINARY_W "wb" #define PG_BINARY_W "wb"
#define PG_BINARY_A "ab"
#else #else
#define PG_BINARY 0 #define PG_BINARY 0
#define PG_BINARY_R "r" #define PG_BINARY_R "r"
#define PG_BINARY_W "w" #define PG_BINARY_W "w"
#define PG_BINARY_A "a"
#endif #endif
...@@ -91,7 +93,8 @@ char *make_string(const char *s, int len, char *buf); ...@@ -91,7 +93,8 @@ char *make_string(const char *s, int len, char *buf);
char *my_strcat(char *buf, const char *fmt, const char *s, int len); char *my_strcat(char *buf, const char *fmt, const char *s, int len);
char *schema_strcat(char *buf, const char *fmt, const char *s, int len, char *schema_strcat(char *buf, const char *fmt, const char *s, int len,
const char *, int); const char *, int);
#define GET_SCHEMA_NAME(nspname) (stricmp(nspname, "public") ? nspname : "") /* #define GET_SCHEMA_NAME(nspname) (stricmp(nspname, "public") ? nspname : "") */
#define GET_SCHEMA_NAME(nspname) (nspname)
/* defines for return value of my_strcpy */ /* defines for return value of my_strcpy */
#define STRCPY_SUCCESS 1 #define STRCPY_SUCCESS 1
......
...@@ -54,6 +54,7 @@ SQLAllocStmt(HDBC ConnectionHandle, ...@@ -54,6 +54,7 @@ SQLAllocStmt(HDBC ConnectionHandle,
HSTMT *StatementHandle) HSTMT *StatementHandle)
{ {
mylog("[SQLAllocStmt]"); mylog("[SQLAllocStmt]");
CC_clear_error((ConnectionClass *) ConnectionHandle);
return PGAPI_AllocStmt(ConnectionHandle, StatementHandle); return PGAPI_AllocStmt(ConnectionHandle, StatementHandle);
} }
...@@ -64,6 +65,7 @@ SQLBindCol(HSTMT StatementHandle, ...@@ -64,6 +65,7 @@ SQLBindCol(HSTMT StatementHandle,
SQLINTEGER *StrLen_or_Ind) SQLINTEGER *StrLen_or_Ind)
{ {
mylog("[SQLBindCol]"); mylog("[SQLBindCol]");
SC_clear_error((StatementClass *) StatementHandle);
return PGAPI_BindCol(StatementHandle, ColumnNumber, return PGAPI_BindCol(StatementHandle, ColumnNumber,
TargetType, TargetValue, BufferLength, StrLen_or_Ind); TargetType, TargetValue, BufferLength, StrLen_or_Ind);
} }
...@@ -72,6 +74,7 @@ RETCODE SQL_API ...@@ -72,6 +74,7 @@ RETCODE SQL_API
SQLCancel(HSTMT StatementHandle) SQLCancel(HSTMT StatementHandle)
{ {
mylog("[SQLCancel]"); mylog("[SQLCancel]");
SC_clear_error((StatementClass *) StatementHandle);
return PGAPI_Cancel(StatementHandle); return PGAPI_Cancel(StatementHandle);
} }
...@@ -83,6 +86,7 @@ SQLColumns(HSTMT StatementHandle, ...@@ -83,6 +86,7 @@ SQLColumns(HSTMT StatementHandle,
SQLCHAR *ColumnName, SQLSMALLINT NameLength4) SQLCHAR *ColumnName, SQLSMALLINT NameLength4)
{ {
mylog("[SQLColumns]"); mylog("[SQLColumns]");
SC_clear_error((StatementClass *) StatementHandle);
return PGAPI_Columns(StatementHandle, CatalogName, NameLength1, return PGAPI_Columns(StatementHandle, CatalogName, NameLength1,
SchemaName, NameLength2, TableName, NameLength3, SchemaName, NameLength2, TableName, NameLength3,
ColumnName, NameLength4, 0); ColumnName, NameLength4, 0);
...@@ -96,6 +100,7 @@ SQLConnect(HDBC ConnectionHandle, ...@@ -96,6 +100,7 @@ SQLConnect(HDBC ConnectionHandle,
SQLCHAR *Authentication, SQLSMALLINT NameLength3) SQLCHAR *Authentication, SQLSMALLINT NameLength3)
{ {
mylog("[SQLConnect]"); mylog("[SQLConnect]");
CC_clear_error((ConnectionClass *) ConnectionHandle);
return PGAPI_Connect(ConnectionHandle, ServerName, NameLength1, return PGAPI_Connect(ConnectionHandle, ServerName, NameLength1,
UserName, NameLength2, Authentication, NameLength3); UserName, NameLength2, Authentication, NameLength3);
} }
...@@ -111,6 +116,7 @@ SQLDriverConnect(HDBC hdbc, ...@@ -111,6 +116,7 @@ SQLDriverConnect(HDBC hdbc,
UWORD fDriverCompletion) UWORD fDriverCompletion)
{ {
mylog("[SQLDriverConnect]"); mylog("[SQLDriverConnect]");
CC_clear_error((ConnectionClass *) hdbc);
return PGAPI_DriverConnect(hdbc, hwnd, szConnStrIn, cbConnStrIn, return PGAPI_DriverConnect(hdbc, hwnd, szConnStrIn, cbConnStrIn,
szConnStrOut, cbConnStrOutMax, pcbConnStrOut, fDriverCompletion); szConnStrOut, cbConnStrOutMax, pcbConnStrOut, fDriverCompletion);
} }
...@@ -124,6 +130,7 @@ SQLBrowseConnect( ...@@ -124,6 +130,7 @@ SQLBrowseConnect(
SQLSMALLINT *pcbConnStrOut) SQLSMALLINT *pcbConnStrOut)
{ {
mylog("[SQLBrowseConnect]"); mylog("[SQLBrowseConnect]");
CC_clear_error((ConnectionClass *) hdbc);
return PGAPI_BrowseConnect(hdbc, szConnStrIn, cbConnStrIn, return PGAPI_BrowseConnect(hdbc, szConnStrIn, cbConnStrIn,
szConnStrOut, cbConnStrOutMax, pcbConnStrOut); szConnStrOut, cbConnStrOutMax, pcbConnStrOut);
} }
...@@ -153,6 +160,7 @@ SQLDescribeCol(HSTMT StatementHandle, ...@@ -153,6 +160,7 @@ SQLDescribeCol(HSTMT StatementHandle,
SQLSMALLINT *DecimalDigits, SQLSMALLINT *Nullable) SQLSMALLINT *DecimalDigits, SQLSMALLINT *Nullable)
{ {
mylog("[SQLDescribeCol]"); mylog("[SQLDescribeCol]");
SC_clear_error((StatementClass *) StatementHandle);
return PGAPI_DescribeCol(StatementHandle, ColumnNumber, return PGAPI_DescribeCol(StatementHandle, ColumnNumber,
ColumnName, BufferLength, NameLength, ColumnName, BufferLength, NameLength,
DataType, ColumnSize, DecimalDigits, Nullable); DataType, ColumnSize, DecimalDigits, Nullable);
...@@ -162,6 +170,7 @@ RETCODE SQL_API ...@@ -162,6 +170,7 @@ RETCODE SQL_API
SQLDisconnect(HDBC ConnectionHandle) SQLDisconnect(HDBC ConnectionHandle)
{ {
mylog("[SQLDisconnect]"); mylog("[SQLDisconnect]");
CC_clear_error((ConnectionClass *) ConnectionHandle);
return PGAPI_Disconnect(ConnectionHandle); return PGAPI_Disconnect(ConnectionHandle);
} }
...@@ -183,6 +192,7 @@ SQLExecDirect(HSTMT StatementHandle, ...@@ -183,6 +192,7 @@ SQLExecDirect(HSTMT StatementHandle,
SQLCHAR *StatementText, SQLINTEGER TextLength) SQLCHAR *StatementText, SQLINTEGER TextLength)
{ {
mylog("[SQLExecDirect]"); mylog("[SQLExecDirect]");
SC_clear_error((StatementClass *) StatementHandle);
return PGAPI_ExecDirect(StatementHandle, StatementText, TextLength); return PGAPI_ExecDirect(StatementHandle, StatementText, TextLength);
} }
...@@ -190,6 +200,7 @@ RETCODE SQL_API ...@@ -190,6 +200,7 @@ RETCODE SQL_API
SQLExecute(HSTMT StatementHandle) SQLExecute(HSTMT StatementHandle)
{ {
mylog("[SQLExecute]"); mylog("[SQLExecute]");
SC_clear_error((StatementClass *) StatementHandle);
return PGAPI_Execute(StatementHandle); return PGAPI_Execute(StatementHandle);
} }
...@@ -202,6 +213,7 @@ SQLFetch(HSTMT StatementHandle) ...@@ -202,6 +213,7 @@ SQLFetch(HSTMT StatementHandle)
StatementClass *stmt = (StatementClass *) StatementHandle; StatementClass *stmt = (StatementClass *) StatementHandle;
ConnectionClass *conn = SC_get_conn(stmt); ConnectionClass *conn = SC_get_conn(stmt);
SC_clear_error(stmt);
if (conn->driver_version >= 0x0300) if (conn->driver_version >= 0x0300)
{ {
IRDFields *irdopts = SC_get_IRD(stmt); IRDFields *irdopts = SC_get_IRD(stmt);
...@@ -210,7 +222,7 @@ SQLFetch(HSTMT StatementHandle) ...@@ -210,7 +222,7 @@ SQLFetch(HSTMT StatementHandle)
mylog("[[%s]]", func); mylog("[[%s]]", func);
return PGAPI_ExtendedFetch(StatementHandle, SQL_FETCH_NEXT, 0, return PGAPI_ExtendedFetch(StatementHandle, SQL_FETCH_NEXT, 0,
pcRow, rowStatusArray); pcRow, rowStatusArray, 0);
} }
#endif #endif
mylog("[%s]", func); mylog("[%s]", func);
...@@ -244,6 +256,7 @@ SQLGetConnectOption(HDBC ConnectionHandle, ...@@ -244,6 +256,7 @@ SQLGetConnectOption(HDBC ConnectionHandle,
SQLUSMALLINT Option, PTR Value) SQLUSMALLINT Option, PTR Value)
{ {
mylog("[SQLGetConnectOption]"); mylog("[SQLGetConnectOption]");
CC_clear_error((ConnectionClass *) ConnectionHandle);
return PGAPI_GetConnectOption(ConnectionHandle, Option, Value); return PGAPI_GetConnectOption(ConnectionHandle, Option, Value);
} }
RETCODE SQL_API RETCODE SQL_API
...@@ -252,6 +265,7 @@ SQLGetCursorName(HSTMT StatementHandle, ...@@ -252,6 +265,7 @@ SQLGetCursorName(HSTMT StatementHandle,
SQLSMALLINT *NameLength) SQLSMALLINT *NameLength)
{ {
mylog("[SQLGetCursorName]"); mylog("[SQLGetCursorName]");
SC_clear_error((StatementClass *) StatementHandle);
return PGAPI_GetCursorName(StatementHandle, CursorName, BufferLength, return PGAPI_GetCursorName(StatementHandle, CursorName, BufferLength,
NameLength); NameLength);
} }
...@@ -263,6 +277,7 @@ SQLGetData(HSTMT StatementHandle, ...@@ -263,6 +277,7 @@ SQLGetData(HSTMT StatementHandle,
SQLINTEGER *StrLen_or_Ind) SQLINTEGER *StrLen_or_Ind)
{ {
mylog("[SQLGetData]"); mylog("[SQLGetData]");
SC_clear_error((StatementClass *) StatementHandle);
return PGAPI_GetData(StatementHandle, ColumnNumber, TargetType, return PGAPI_GetData(StatementHandle, ColumnNumber, TargetType,
TargetValue, BufferLength, StrLen_or_Ind); TargetValue, BufferLength, StrLen_or_Ind);
} }
...@@ -272,6 +287,7 @@ SQLGetFunctions(HDBC ConnectionHandle, ...@@ -272,6 +287,7 @@ SQLGetFunctions(HDBC ConnectionHandle,
SQLUSMALLINT FunctionId, SQLUSMALLINT *Supported) SQLUSMALLINT FunctionId, SQLUSMALLINT *Supported)
{ {
mylog("[SQLGetFunctions]"); mylog("[SQLGetFunctions]");
CC_clear_error((ConnectionClass *) ConnectionHandle);
#if (ODBCVER >= 0x0300) #if (ODBCVER >= 0x0300)
if (FunctionId == SQL_API_ODBC3_ALL_FUNCTIONS) if (FunctionId == SQL_API_ODBC3_ALL_FUNCTIONS)
return PGAPI_GetFunctions30(ConnectionHandle, FunctionId, Supported); return PGAPI_GetFunctions30(ConnectionHandle, FunctionId, Supported);
...@@ -315,6 +331,7 @@ SQLGetStmtOption(HSTMT StatementHandle, ...@@ -315,6 +331,7 @@ SQLGetStmtOption(HSTMT StatementHandle,
SQLUSMALLINT Option, PTR Value) SQLUSMALLINT Option, PTR Value)
{ {
mylog("[SQLGetStmtOption]"); mylog("[SQLGetStmtOption]");
SC_clear_error((StatementClass *) StatementHandle);
return PGAPI_GetStmtOption(StatementHandle, Option, Value); return PGAPI_GetStmtOption(StatementHandle, Option, Value);
} }
...@@ -323,6 +340,7 @@ SQLGetTypeInfo(HSTMT StatementHandle, ...@@ -323,6 +340,7 @@ SQLGetTypeInfo(HSTMT StatementHandle,
SQLSMALLINT DataType) SQLSMALLINT DataType)
{ {
mylog("[SQLGetTypeInfo]"); mylog("[SQLGetTypeInfo]");
SC_clear_error((StatementClass *) StatementHandle);
return PGAPI_GetTypeInfo(StatementHandle, DataType); return PGAPI_GetTypeInfo(StatementHandle, DataType);
} }
...@@ -331,6 +349,7 @@ SQLNumResultCols(HSTMT StatementHandle, ...@@ -331,6 +349,7 @@ SQLNumResultCols(HSTMT StatementHandle,
SQLSMALLINT *ColumnCount) SQLSMALLINT *ColumnCount)
{ {
mylog("[SQLNumResultCols]"); mylog("[SQLNumResultCols]");
SC_clear_error((StatementClass *) StatementHandle);
return PGAPI_NumResultCols(StatementHandle, ColumnCount); return PGAPI_NumResultCols(StatementHandle, ColumnCount);
} }
...@@ -339,6 +358,7 @@ SQLParamData(HSTMT StatementHandle, ...@@ -339,6 +358,7 @@ SQLParamData(HSTMT StatementHandle,
PTR *Value) PTR *Value)
{ {
mylog("[SQLParamData]"); mylog("[SQLParamData]");
SC_clear_error((StatementClass *) StatementHandle);
return PGAPI_ParamData(StatementHandle, Value); return PGAPI_ParamData(StatementHandle, Value);
} }
...@@ -347,6 +367,7 @@ SQLPrepare(HSTMT StatementHandle, ...@@ -347,6 +367,7 @@ SQLPrepare(HSTMT StatementHandle,
SQLCHAR *StatementText, SQLINTEGER TextLength) SQLCHAR *StatementText, SQLINTEGER TextLength)
{ {
mylog("[SQLPrepare]"); mylog("[SQLPrepare]");
SC_clear_error((StatementClass *) StatementHandle);
return PGAPI_Prepare(StatementHandle, StatementText, TextLength); return PGAPI_Prepare(StatementHandle, StatementText, TextLength);
} }
...@@ -355,6 +376,7 @@ SQLPutData(HSTMT StatementHandle, ...@@ -355,6 +376,7 @@ SQLPutData(HSTMT StatementHandle,
PTR Data, SQLINTEGER StrLen_or_Ind) PTR Data, SQLINTEGER StrLen_or_Ind)
{ {
mylog("[SQLPutData]"); mylog("[SQLPutData]");
SC_clear_error((StatementClass *) StatementHandle);
return PGAPI_PutData(StatementHandle, Data, StrLen_or_Ind); return PGAPI_PutData(StatementHandle, Data, StrLen_or_Ind);
} }
...@@ -363,6 +385,7 @@ SQLRowCount(HSTMT StatementHandle, ...@@ -363,6 +385,7 @@ SQLRowCount(HSTMT StatementHandle,
SQLINTEGER *RowCount) SQLINTEGER *RowCount)
{ {
mylog("[SQLRowCount]"); mylog("[SQLRowCount]");
SC_clear_error((StatementClass *) StatementHandle);
return PGAPI_RowCount(StatementHandle, RowCount); return PGAPI_RowCount(StatementHandle, RowCount);
} }
...@@ -371,6 +394,7 @@ SQLSetConnectOption(HDBC ConnectionHandle, ...@@ -371,6 +394,7 @@ SQLSetConnectOption(HDBC ConnectionHandle,
SQLUSMALLINT Option, SQLUINTEGER Value) SQLUSMALLINT Option, SQLUINTEGER Value)
{ {
mylog("[SQLSetConnectionOption]"); mylog("[SQLSetConnectionOption]");
CC_clear_error((ConnectionClass *) ConnectionHandle);
return PGAPI_SetConnectOption(ConnectionHandle, Option, Value); return PGAPI_SetConnectOption(ConnectionHandle, Option, Value);
} }
...@@ -379,6 +403,7 @@ SQLSetCursorName(HSTMT StatementHandle, ...@@ -379,6 +403,7 @@ SQLSetCursorName(HSTMT StatementHandle,
SQLCHAR *CursorName, SQLSMALLINT NameLength) SQLCHAR *CursorName, SQLSMALLINT NameLength)
{ {
mylog("[SQLSetCursorName]"); mylog("[SQLSetCursorName]");
SC_clear_error((StatementClass *) StatementHandle);
return PGAPI_SetCursorName(StatementHandle, CursorName, NameLength); return PGAPI_SetCursorName(StatementHandle, CursorName, NameLength);
} }
...@@ -390,6 +415,7 @@ SQLSetParam(HSTMT StatementHandle, ...@@ -390,6 +415,7 @@ SQLSetParam(HSTMT StatementHandle,
SQLINTEGER *StrLen_or_Ind) SQLINTEGER *StrLen_or_Ind)
{ {
mylog("[SQLSetParam]"); mylog("[SQLSetParam]");
SC_clear_error((StatementClass *) StatementHandle);
/* /*
* return PGAPI_SetParam(StatementHandle, ParameterNumber, ValueType, * return PGAPI_SetParam(StatementHandle, ParameterNumber, ValueType,
...@@ -404,6 +430,7 @@ SQLSetStmtOption(HSTMT StatementHandle, ...@@ -404,6 +430,7 @@ SQLSetStmtOption(HSTMT StatementHandle,
SQLUSMALLINT Option, SQLUINTEGER Value) SQLUSMALLINT Option, SQLUINTEGER Value)
{ {
mylog("[SQLSetStmtOption]"); mylog("[SQLSetStmtOption]");
SC_clear_error((StatementClass *) StatementHandle);
return PGAPI_SetStmtOption(StatementHandle, Option, Value); return PGAPI_SetStmtOption(StatementHandle, Option, Value);
} }
...@@ -416,6 +443,7 @@ SQLSpecialColumns(HSTMT StatementHandle, ...@@ -416,6 +443,7 @@ SQLSpecialColumns(HSTMT StatementHandle,
SQLUSMALLINT Nullable) SQLUSMALLINT Nullable)
{ {
mylog("[SQLSpecialColumns]"); mylog("[SQLSpecialColumns]");
SC_clear_error((StatementClass *) StatementHandle);
return PGAPI_SpecialColumns(StatementHandle, IdentifierType, CatalogName, return PGAPI_SpecialColumns(StatementHandle, IdentifierType, CatalogName,
NameLength1, SchemaName, NameLength2, TableName, NameLength3, NameLength1, SchemaName, NameLength2, TableName, NameLength3,
Scope, Nullable); Scope, Nullable);
...@@ -429,6 +457,7 @@ SQLStatistics(HSTMT StatementHandle, ...@@ -429,6 +457,7 @@ SQLStatistics(HSTMT StatementHandle,
SQLUSMALLINT Unique, SQLUSMALLINT Reserved) SQLUSMALLINT Unique, SQLUSMALLINT Reserved)
{ {
mylog("[SQLStatistics]"); mylog("[SQLStatistics]");
SC_clear_error((StatementClass *) StatementHandle);
return PGAPI_Statistics(StatementHandle, CatalogName, NameLength1, return PGAPI_Statistics(StatementHandle, CatalogName, NameLength1,
SchemaName, NameLength2, TableName, NameLength3, Unique, SchemaName, NameLength2, TableName, NameLength3, Unique,
Reserved); Reserved);
...@@ -442,6 +471,7 @@ SQLTables(HSTMT StatementHandle, ...@@ -442,6 +471,7 @@ SQLTables(HSTMT StatementHandle,
SQLCHAR *TableType, SQLSMALLINT NameLength4) SQLCHAR *TableType, SQLSMALLINT NameLength4)
{ {
mylog("[SQLTables]"); mylog("[SQLTables]");
SC_clear_error((StatementClass *) StatementHandle);
return PGAPI_Tables(StatementHandle, CatalogName, NameLength1, return PGAPI_Tables(StatementHandle, CatalogName, NameLength1,
SchemaName, NameLength2, TableName, NameLength3, SchemaName, NameLength2, TableName, NameLength3,
TableType, NameLength4); TableType, NameLength4);
...@@ -466,6 +496,7 @@ SQLColAttributes( ...@@ -466,6 +496,7 @@ SQLColAttributes(
SQLINTEGER *pfDesc) SQLINTEGER *pfDesc)
{ {
mylog("[SQLColAttributes]"); mylog("[SQLColAttributes]");
SC_clear_error((StatementClass *) hstmt);
return PGAPI_ColAttributes(hstmt, icol, fDescType, rgbDesc, return PGAPI_ColAttributes(hstmt, icol, fDescType, rgbDesc,
cbDescMax, pcbDesc, pfDesc); cbDescMax, pcbDesc, pfDesc);
} }
...@@ -483,6 +514,7 @@ SQLColumnPrivileges( ...@@ -483,6 +514,7 @@ SQLColumnPrivileges(
SQLSMALLINT cbColumnName) SQLSMALLINT cbColumnName)
{ {
mylog("[SQLColumnPrivileges]"); mylog("[SQLColumnPrivileges]");
SC_clear_error((StatementClass *) hstmt);
return PGAPI_ColumnPrivileges(hstmt, szCatalogName, cbCatalogName, return PGAPI_ColumnPrivileges(hstmt, szCatalogName, cbCatalogName,
szSchemaName, cbSchemaName, szTableName, cbTableName, szSchemaName, cbSchemaName, szTableName, cbTableName,
szColumnName, cbColumnName); szColumnName, cbColumnName);
...@@ -498,6 +530,7 @@ SQLDescribeParam( ...@@ -498,6 +530,7 @@ SQLDescribeParam(
SQLSMALLINT *pfNullable) SQLSMALLINT *pfNullable)
{ {
mylog("[SQLDescribeParam]"); mylog("[SQLDescribeParam]");
SC_clear_error((StatementClass *) hstmt);
return PGAPI_DescribeParam(hstmt, ipar, pfSqlType, pcbParamDef, return PGAPI_DescribeParam(hstmt, ipar, pfSqlType, pcbParamDef,
pibScale, pfNullable); pibScale, pfNullable);
} }
...@@ -511,7 +544,8 @@ SQLExtendedFetch( ...@@ -511,7 +544,8 @@ SQLExtendedFetch(
SQLUSMALLINT *rgfRowStatus) SQLUSMALLINT *rgfRowStatus)
{ {
mylog("[SQLExtendedFetch]"); mylog("[SQLExtendedFetch]");
return PGAPI_ExtendedFetch(hstmt, fFetchType, irow, pcrow, rgfRowStatus); SC_clear_error((StatementClass *) hstmt);
return PGAPI_ExtendedFetch(hstmt, fFetchType, irow, pcrow, rgfRowStatus, 0);
} }
RETCODE SQL_API RETCODE SQL_API
...@@ -531,6 +565,7 @@ SQLForeignKeys( ...@@ -531,6 +565,7 @@ SQLForeignKeys(
SQLSMALLINT cbFkTableName) SQLSMALLINT cbFkTableName)
{ {
mylog("[SQLForeignKeys]"); mylog("[SQLForeignKeys]");
SC_clear_error((StatementClass *) hstmt);
return PGAPI_ForeignKeys(hstmt, szPkCatalogName, cbPkCatalogName, return PGAPI_ForeignKeys(hstmt, szPkCatalogName, cbPkCatalogName,
szPkSchemaName, cbPkSchemaName, szPkTableName, szPkSchemaName, cbPkSchemaName, szPkTableName,
cbPkTableName, szFkCatalogName, cbFkCatalogName, cbPkTableName, szFkCatalogName, cbFkCatalogName,
...@@ -541,6 +576,7 @@ RETCODE SQL_API ...@@ -541,6 +576,7 @@ RETCODE SQL_API
SQLMoreResults(HSTMT hstmt) SQLMoreResults(HSTMT hstmt)
{ {
mylog("[SQLMoreResults]"); mylog("[SQLMoreResults]");
SC_clear_error((StatementClass *) hstmt);
return PGAPI_MoreResults(hstmt); return PGAPI_MoreResults(hstmt);
} }
...@@ -554,6 +590,7 @@ SQLNativeSql( ...@@ -554,6 +590,7 @@ SQLNativeSql(
SQLINTEGER *pcbSqlStr) SQLINTEGER *pcbSqlStr)
{ {
mylog("[SQLNativeSql]"); mylog("[SQLNativeSql]");
CC_clear_error((ConnectionClass *) hdbc);
return PGAPI_NativeSql(hdbc, szSqlStrIn, cbSqlStrIn, szSqlStr, return PGAPI_NativeSql(hdbc, szSqlStrIn, cbSqlStrIn, szSqlStr,
cbSqlStrMax, pcbSqlStr); cbSqlStrMax, pcbSqlStr);
} }
...@@ -564,6 +601,7 @@ SQLNumParams( ...@@ -564,6 +601,7 @@ SQLNumParams(
SQLSMALLINT *pcpar) SQLSMALLINT *pcpar)
{ {
mylog("[SQLNumParams]"); mylog("[SQLNumParams]");
SC_clear_error((StatementClass *) hstmt);
return PGAPI_NumParams(hstmt, pcpar); return PGAPI_NumParams(hstmt, pcpar);
} }
...@@ -574,6 +612,7 @@ SQLParamOptions( ...@@ -574,6 +612,7 @@ SQLParamOptions(
SQLUINTEGER *pirow) SQLUINTEGER *pirow)
{ {
mylog("[SQLParamOptions]"); mylog("[SQLParamOptions]");
SC_clear_error((StatementClass *) hstmt);
return PGAPI_ParamOptions(hstmt, crow, pirow); return PGAPI_ParamOptions(hstmt, crow, pirow);
} }
...@@ -588,6 +627,7 @@ SQLPrimaryKeys( ...@@ -588,6 +627,7 @@ SQLPrimaryKeys(
SQLSMALLINT cbTableName) SQLSMALLINT cbTableName)
{ {
mylog("[SQLPrimaryKeys]"); mylog("[SQLPrimaryKeys]");
SC_clear_error((StatementClass *) hstmt);
return PGAPI_PrimaryKeys(hstmt, szCatalogName, cbCatalogName, return PGAPI_PrimaryKeys(hstmt, szCatalogName, cbCatalogName,
szSchemaName, cbSchemaName, szTableName, cbTableName); szSchemaName, cbSchemaName, szTableName, cbTableName);
} }
...@@ -605,6 +645,7 @@ SQLProcedureColumns( ...@@ -605,6 +645,7 @@ SQLProcedureColumns(
SQLSMALLINT cbColumnName) SQLSMALLINT cbColumnName)
{ {
mylog("[SQLProcedureColumns]"); mylog("[SQLProcedureColumns]");
SC_clear_error((StatementClass *) hstmt);
return PGAPI_ProcedureColumns(hstmt, szCatalogName, cbCatalogName, return PGAPI_ProcedureColumns(hstmt, szCatalogName, cbCatalogName,
szSchemaName, cbSchemaName, szProcName, cbProcName, szSchemaName, cbSchemaName, szProcName, cbProcName,
szColumnName, cbColumnName); szColumnName, cbColumnName);
...@@ -621,6 +662,7 @@ SQLProcedures( ...@@ -621,6 +662,7 @@ SQLProcedures(
SQLSMALLINT cbProcName) SQLSMALLINT cbProcName)
{ {
mylog("[SQLProcedures]"); mylog("[SQLProcedures]");
SC_clear_error((StatementClass *) hstmt);
return PGAPI_Procedures(hstmt, szCatalogName, cbCatalogName, return PGAPI_Procedures(hstmt, szCatalogName, cbCatalogName,
szSchemaName, cbSchemaName, szProcName, cbProcName); szSchemaName, cbSchemaName, szProcName, cbProcName);
} }
...@@ -633,6 +675,7 @@ SQLSetPos( ...@@ -633,6 +675,7 @@ SQLSetPos(
SQLUSMALLINT fLock) SQLUSMALLINT fLock)
{ {
mylog("[SQLSetPos]"); mylog("[SQLSetPos]");
SC_clear_error((StatementClass *) hstmt);
return PGAPI_SetPos(hstmt, irow, fOption, fLock); return PGAPI_SetPos(hstmt, irow, fOption, fLock);
} }
...@@ -647,6 +690,7 @@ SQLTablePrivileges( ...@@ -647,6 +690,7 @@ SQLTablePrivileges(
SQLSMALLINT cbTableName) SQLSMALLINT cbTableName)
{ {
mylog("[SQLTablePrivileges]"); mylog("[SQLTablePrivileges]");
SC_clear_error((StatementClass *) hstmt);
return PGAPI_TablePrivileges(hstmt, szCatalogName, cbCatalogName, return PGAPI_TablePrivileges(hstmt, szCatalogName, cbCatalogName,
szSchemaName, cbSchemaName, szTableName, cbTableName, 0); szSchemaName, cbSchemaName, szTableName, cbTableName, 0);
} }
...@@ -665,6 +709,7 @@ SQLBindParameter( ...@@ -665,6 +709,7 @@ SQLBindParameter(
SQLINTEGER *pcbValue) SQLINTEGER *pcbValue)
{ {
mylog("[SQLBindParameter]"); mylog("[SQLBindParameter]");
SC_clear_error((StatementClass *) hstmt);
return PGAPI_BindParameter(hstmt, ipar, fParamType, fCType, return PGAPI_BindParameter(hstmt, ipar, fParamType, fCType,
fSqlType, cbColDef, ibScale, rgbValue, cbValueMax, fSqlType, cbColDef, ibScale, rgbValue, cbValueMax,
pcbValue); pcbValue);
......
...@@ -61,6 +61,7 @@ SQLBindParam(HSTMT StatementHandle, ...@@ -61,6 +61,7 @@ SQLBindParam(HSTMT StatementHandle,
int BufferLength = 512; /* Is it OK ? */ int BufferLength = 512; /* Is it OK ? */
mylog("[[SQLBindParam]]"); mylog("[[SQLBindParam]]");
SC_clear_error((StatementClass *) StatementHandle);
return PGAPI_BindParameter(StatementHandle, ParameterNumber, SQL_PARAM_INPUT, ValueType, ParameterType, LengthPrecision, ParameterScale, ParameterValue, BufferLength, StrLen_or_Ind); return PGAPI_BindParameter(StatementHandle, ParameterNumber, SQL_PARAM_INPUT, ValueType, ParameterType, LengthPrecision, ParameterScale, ParameterValue, BufferLength, StrLen_or_Ind);
} }
...@@ -69,6 +70,7 @@ RETCODE SQL_API ...@@ -69,6 +70,7 @@ RETCODE SQL_API
SQLCloseCursor(HSTMT StatementHandle) SQLCloseCursor(HSTMT StatementHandle)
{ {
mylog("[[SQLCloseCursor]]"); mylog("[[SQLCloseCursor]]");
SC_clear_error((StatementClass *) StatementHandle);
return PGAPI_FreeStmt(StatementHandle, SQL_CLOSE); return PGAPI_FreeStmt(StatementHandle, SQL_CLOSE);
} }
...@@ -80,6 +82,7 @@ SQLColAttribute(HSTMT StatementHandle, ...@@ -80,6 +82,7 @@ SQLColAttribute(HSTMT StatementHandle,
SQLSMALLINT *StringLength, PTR NumericAttribute) SQLSMALLINT *StringLength, PTR NumericAttribute)
{ {
mylog("[[SQLColAttribute]]"); mylog("[[SQLColAttribute]]");
SC_clear_error((StatementClass *) StatementHandle);
return PGAPI_ColAttributes(StatementHandle, ColumnNumber, return PGAPI_ColAttributes(StatementHandle, ColumnNumber,
FieldIdentifier, CharacterAttribute, BufferLength, FieldIdentifier, CharacterAttribute, BufferLength,
StringLength, NumericAttribute); StringLength, NumericAttribute);
...@@ -140,6 +143,7 @@ SQLEndTran(SQLSMALLINT HandleType, SQLHANDLE Handle, ...@@ -140,6 +143,7 @@ SQLEndTran(SQLSMALLINT HandleType, SQLHANDLE Handle,
case SQL_HANDLE_ENV: case SQL_HANDLE_ENV:
return PGAPI_Transact(Handle, SQL_NULL_HDBC, CompletionType); return PGAPI_Transact(Handle, SQL_NULL_HDBC, CompletionType);
case SQL_HANDLE_DBC: case SQL_HANDLE_DBC:
CC_clear_error((ConnectionClass *) Handle);
return PGAPI_Transact(SQL_NULL_HENV, Handle, CompletionType); return PGAPI_Transact(SQL_NULL_HENV, Handle, CompletionType);
default: default:
break; break;
...@@ -157,16 +161,18 @@ SQLFetchScroll(HSTMT StatementHandle, ...@@ -157,16 +161,18 @@ SQLFetchScroll(HSTMT StatementHandle,
RETCODE ret; RETCODE ret;
IRDFields *irdopts = SC_get_IRD(stmt); IRDFields *irdopts = SC_get_IRD(stmt);
SQLUSMALLINT *rowStatusArray = irdopts->rowStatusArray; SQLUSMALLINT *rowStatusArray = irdopts->rowStatusArray;
SQLINTEGER *pcRow = irdopts->rowsFetched; SQLINTEGER *pcRow = irdopts->rowsFetched, bkmarkoff = 0;
mylog("[[%s]] %d,%d\n", func, FetchOrientation, FetchOffset); mylog("[[%s]] %d,%d\n", func, FetchOrientation, FetchOffset);
SC_clear_error(stmt);
if (FetchOrientation == SQL_FETCH_BOOKMARK) if (FetchOrientation == SQL_FETCH_BOOKMARK)
{ {
if (stmt->options.bookmark_ptr) if (stmt->options.bookmark_ptr)
{ {
FetchOffset += *((Int4 *) stmt->options.bookmark_ptr); bkmarkoff = FetchOffset;
mylog("real FetchOffset = %d\n", FetchOffset); FetchOffset = *((Int4 *) stmt->options.bookmark_ptr);
} mylog("bookmark=%u FetchOffset = %d\n", FetchOffset, bkmarkoff);
}
else else
{ {
stmt->errornumber = STMT_SEQUENCE_ERROR; stmt->errornumber = STMT_SEQUENCE_ERROR;
...@@ -176,7 +182,7 @@ mylog("real FetchOffset = %d\n", FetchOffset); ...@@ -176,7 +182,7 @@ mylog("real FetchOffset = %d\n", FetchOffset);
} }
} }
ret = PGAPI_ExtendedFetch(StatementHandle, FetchOrientation, FetchOffset, ret = PGAPI_ExtendedFetch(StatementHandle, FetchOrientation, FetchOffset,
pcRow, rowStatusArray); pcRow, rowStatusArray, bkmarkoff);
if (ret != SQL_SUCCESS) if (ret != SQL_SUCCESS)
mylog("%s return = %d\n", func, ret); mylog("%s return = %d\n", func, ret);
return ret; return ret;
...@@ -288,6 +294,7 @@ SQLGetConnectAttr(HDBC ConnectionHandle, ...@@ -288,6 +294,7 @@ SQLGetConnectAttr(HDBC ConnectionHandle,
SQLINTEGER BufferLength, SQLINTEGER *StringLength) SQLINTEGER BufferLength, SQLINTEGER *StringLength)
{ {
mylog("[[SQLGetConnectAttr]] %d\n", Attribute); mylog("[[SQLGetConnectAttr]] %d\n", Attribute);
CC_clear_error((ConnectionClass *) ConnectionHandle);
return PGAPI_GetConnectAttr(ConnectionHandle, Attribute,Value, return PGAPI_GetConnectAttr(ConnectionHandle, Attribute,Value,
BufferLength, StringLength); BufferLength, StringLength);
} }
...@@ -301,6 +308,7 @@ SQLGetStmtAttr(HSTMT StatementHandle, ...@@ -301,6 +308,7 @@ SQLGetStmtAttr(HSTMT StatementHandle,
static char *func = "SQLGetStmtAttr"; static char *func = "SQLGetStmtAttr";
mylog("[[%s]] Handle=%u %d\n", func, StatementHandle, Attribute); mylog("[[%s]] Handle=%u %d\n", func, StatementHandle, Attribute);
SC_clear_error((StatementClass *) StatementHandle);
return PGAPI_GetStmtAttr(StatementHandle, Attribute, Value, return PGAPI_GetStmtAttr(StatementHandle, Attribute, Value,
BufferLength, StringLength); BufferLength, StringLength);
} }
...@@ -314,6 +322,7 @@ SQLSetConnectAttr(HDBC ConnectionHandle, ...@@ -314,6 +322,7 @@ SQLSetConnectAttr(HDBC ConnectionHandle,
ConnectionClass *conn = (ConnectionClass *) ConnectionHandle; ConnectionClass *conn = (ConnectionClass *) ConnectionHandle;
mylog("[[SQLSetConnectAttr]] %d\n", Attribute); mylog("[[SQLSetConnectAttr]] %d\n", Attribute);
CC_clear_error(conn);
return PGAPI_SetConnectAttr(ConnectionHandle, Attribute, Value, return PGAPI_SetConnectAttr(ConnectionHandle, Attribute, Value,
StringLength); StringLength);
} }
...@@ -396,6 +405,7 @@ SQLSetStmtAttr(HSTMT StatementHandle, ...@@ -396,6 +405,7 @@ SQLSetStmtAttr(HSTMT StatementHandle,
StatementClass *stmt = (StatementClass *) StatementHandle; StatementClass *stmt = (StatementClass *) StatementHandle;
mylog("[[%s]] Handle=%u %d,%u\n", func, StatementHandle, Attribute, Value); mylog("[[%s]] Handle=%u %d,%u\n", func, StatementHandle, Attribute, Value);
SC_clear_error(stmt);
return PGAPI_SetStmtAttr(StatementHandle, Attribute, Value, StringLength); return PGAPI_SetStmtAttr(StatementHandle, Attribute, Value, StringLength);
} }
...@@ -409,6 +419,7 @@ PGAPI_GetFunctions30(HDBC hdbc, UWORD fFunction, UWORD FAR * pfExists) ...@@ -409,6 +419,7 @@ PGAPI_GetFunctions30(HDBC hdbc, UWORD fFunction, UWORD FAR * pfExists)
ConnectionClass *conn = (ConnectionClass *) hdbc; ConnectionClass *conn = (ConnectionClass *) hdbc;
ConnInfo *ci = &(conn->connInfo); ConnInfo *ci = &(conn->connInfo);
CC_clear_error(conn);
if (fFunction != SQL_API_ODBC3_ALL_FUNCTIONS) if (fFunction != SQL_API_ODBC3_ALL_FUNCTIONS)
return SQL_ERROR; return SQL_ERROR;
memset(pfExists, 0, sizeof(UWORD) * SQL_API_ODBC3_ALL_FUNCTIONS_SIZE); memset(pfExists, 0, sizeof(UWORD) * SQL_API_ODBC3_ALL_FUNCTIONS_SIZE);
...@@ -497,12 +508,12 @@ PGAPI_GetFunctions30(HDBC hdbc, UWORD fFunction, UWORD FAR * pfExists) ...@@ -497,12 +508,12 @@ PGAPI_GetFunctions30(HDBC hdbc, UWORD fFunction, UWORD FAR * pfExists)
SQL_FUNC_ESET(pfExists, SQL_API_SQLENDTRAN); /* 1005 */ SQL_FUNC_ESET(pfExists, SQL_API_SQLENDTRAN); /* 1005 */
SQL_FUNC_ESET(pfExists, SQL_API_SQLFREEHANDLE); /* 1006 */ SQL_FUNC_ESET(pfExists, SQL_API_SQLFREEHANDLE); /* 1006 */
SQL_FUNC_ESET(pfExists, SQL_API_SQLGETCONNECTATTR); /* 1007 */ SQL_FUNC_ESET(pfExists, SQL_API_SQLGETCONNECTATTR); /* 1007 */
SQL_FUNC_ESET(pfExists, SQL_API_SQLGETDESCFIELD); /* 1008 */
if (ci->drivers.lie) if (ci->drivers.lie)
{ {
SQL_FUNC_ESET(pfExists, SQL_API_SQLGETDESCFIELD); /* 1008 not implemented yet */
SQL_FUNC_ESET(pfExists, SQL_API_SQLGETDESCREC); /* 1009 not implemented yet */ SQL_FUNC_ESET(pfExists, SQL_API_SQLGETDESCREC); /* 1009 not implemented yet */
SQL_FUNC_ESET(pfExists, SQL_API_SQLGETDIAGFIELD); /* 1010 not implemented yet */
} }
SQL_FUNC_ESET(pfExists, SQL_API_SQLGETDIAGFIELD); /* 1010 minimal implementation */
SQL_FUNC_ESET(pfExists, SQL_API_SQLGETDIAGREC); /* 1011 */ SQL_FUNC_ESET(pfExists, SQL_API_SQLGETDIAGREC); /* 1011 */
SQL_FUNC_ESET(pfExists, SQL_API_SQLGETENVATTR); /* 1012 */ SQL_FUNC_ESET(pfExists, SQL_API_SQLGETENVATTR); /* 1012 */
SQL_FUNC_ESET(pfExists, SQL_API_SQLGETSTMTATTR); /* 1014 */ SQL_FUNC_ESET(pfExists, SQL_API_SQLGETSTMTATTR); /* 1014 */
...@@ -525,72 +536,15 @@ RETCODE SQL_API ...@@ -525,72 +536,15 @@ RETCODE SQL_API
SQLBulkOperations(HSTMT hstmt, SQLSMALLINT operation) SQLBulkOperations(HSTMT hstmt, SQLSMALLINT operation)
{ {
static char *func = "SQLBulkOperations"; static char *func = "SQLBulkOperations";
StatementClass *stmt = (StatementClass *) hstmt;
#ifndef DRIVER_CURSOR_IMPLEMENT #ifndef DRIVER_CURSOR_IMPLEMENT
StatementClass *stmt = (StatementClass *) hstmt;
stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR; stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR;
stmt->errormsg = "driver must be compiled with the DRIVER_CURSOR_IMPLEMENT option"; stmt->errormsg = "driver must be compiled with the DRIVER_CURSOR_IMPLEMENT option";
SC_log_error(func, "", stmt); SC_log_error(func, "", stmt);
return SQL_ERROR; return SQL_ERROR;
#else #else
ARDFields *opts = SC_get_ARD(stmt); mylog("[[%s]] Handle=%u %d\n", func, hstmt, operation);
RETCODE ret; SC_clear_error((StatementClass *) hstmt);
UInt4 offset, bind_size = opts->bind_size, *bmark; return PGAPI_BulkOperations(hstmt, operation);
int i, processed;
ConnectionClass *conn;
BOOL auto_commit_needed = FALSE;
mylog("[[%s]] operation = %d\n", func, operation);
offset = opts->row_offset_ptr ? *opts->row_offset_ptr : 0;
switch (operation)
{
case SQL_ADD:
ret = PGAPI_SetPos(hstmt, 0, operation, SQL_LOCK_NO_CHANGE);
break;
default:
if (SQL_FETCH_BY_BOOKMARK != operation)
{
conn = SC_get_conn(stmt);
if (auto_commit_needed = CC_is_in_autocommit(conn), auto_commit_needed)
PGAPI_SetConnectOption(conn, SQL_AUTOCOMMIT,
SQL_AUTOCOMMIT_OFF);
}
if (bmark = (UInt4 *) opts->bookmark->buffer, !bmark)
{
stmt->errormsg = "bookmark isn't specified";
return SQL_ERROR;
}
bmark += (offset >> 4);
for (i = 0, processed = 0; i < opts->rowset_size; i++)
{
if (!opts->row_operation_ptr || SQL_ROW_PROCEED == opts->row_operation_ptr[i])
{
switch (operation)
{
case SQL_UPDATE_BY_BOOKMARK:
ret = SC_pos_update(stmt, (UWORD) i, *bmark);
break;
case SQL_DELETE_BY_BOOKMARK:
ret = SC_pos_delete(stmt, (UWORD) i, *bmark);
break;
case SQL_FETCH_BY_BOOKMARK:
ret = SC_pos_refresh(stmt, (UWORD) i, *bmark);
break;
}
processed++;
if (SQL_ERROR == ret)
break;
if (bind_size > 0)
bmark += (bind_size >> 2);
else
bmark++;
}
}
if (auto_commit_needed)
PGAPI_SetConnectOption(conn, SQL_AUTOCOMMIT, SQL_AUTOCOMMIT_ON);
if (SC_get_IRD(stmt)->rowsFetched)
*SC_get_IRD(stmt)->rowsFetched = processed;
break;
}
return ret;
#endif /* DRIVER_CURSOR_IMPLEMENT */ #endif /* DRIVER_CURSOR_IMPLEMENT */
} }
...@@ -30,6 +30,7 @@ RETCODE SQL_API SQLGetStmtAttrW(SQLHSTMT hstmt, ...@@ -30,6 +30,7 @@ RETCODE SQL_API SQLGetStmtAttrW(SQLHSTMT hstmt,
RETCODE ret; RETCODE ret;
mylog("[SQLGetStmtAttrW]"); mylog("[SQLGetStmtAttrW]");
SC_clear_error((StatementClass *) hstmt);
ret = PGAPI_GetStmtAttr(hstmt, fAttribute, rgbValue, ret = PGAPI_GetStmtAttr(hstmt, fAttribute, rgbValue,
cbValueMax, pcbValue); cbValueMax, pcbValue);
return ret; return ret;
...@@ -43,6 +44,7 @@ RETCODE SQL_API SQLSetStmtAttrW(SQLHSTMT hstmt, ...@@ -43,6 +44,7 @@ RETCODE SQL_API SQLSetStmtAttrW(SQLHSTMT hstmt,
RETCODE ret; RETCODE ret;
mylog("[SQLSetStmtAttrW]"); mylog("[SQLSetStmtAttrW]");
SC_clear_error((StatementClass *) hstmt);
ret = PGAPI_SetStmtAttr(hstmt, fAttribute, rgbValue, ret = PGAPI_SetStmtAttr(hstmt, fAttribute, rgbValue,
cbValueMax); cbValueMax);
return ret; return ret;
...@@ -57,6 +59,7 @@ RETCODE SQL_API SQLGetConnectAttrW(HDBC hdbc, ...@@ -57,6 +59,7 @@ RETCODE SQL_API SQLGetConnectAttrW(HDBC hdbc,
RETCODE ret; RETCODE ret;
mylog("[SQLGetConnectAttrW]"); mylog("[SQLGetConnectAttrW]");
CC_clear_error((ConnectionClass *) hdbc);
ret = PGAPI_GetConnectAttr(hdbc, fAttribute, rgbValue, ret = PGAPI_GetConnectAttr(hdbc, fAttribute, rgbValue,
cbValueMax, pcbValue); cbValueMax, pcbValue);
return ret; return ret;
...@@ -70,6 +73,7 @@ RETCODE SQL_API SQLSetConnectAttrW(HDBC hdbc, ...@@ -70,6 +73,7 @@ RETCODE SQL_API SQLSetConnectAttrW(HDBC hdbc,
RETCODE ret; RETCODE ret;
mylog("[SQLSetConnectAttrW]"); mylog("[SQLSetConnectAttrW]");
CC_clear_error((ConnectionClass *) hdbc);
ret = PGAPI_SetConnectAttr(hdbc, fAttribute, rgbValue, ret = PGAPI_SetConnectAttr(hdbc, fAttribute, rgbValue,
cbValue); cbValue);
return ret; return ret;
...@@ -229,6 +233,7 @@ RETCODE SQL_API SQLColAttributeW( ...@@ -229,6 +233,7 @@ RETCODE SQL_API SQLColAttributeW(
char *rgbD = NULL; char *rgbD = NULL;
mylog("[SQLColAttributeW]"); mylog("[SQLColAttributeW]");
SC_clear_error((StatementClass *) hstmt);
switch (fDescType) switch (fDescType)
{ {
case SQL_DESC_BASE_COLUMN_NAME: case SQL_DESC_BASE_COLUMN_NAME:
......
...@@ -95,9 +95,13 @@ set_statement_option(ConnectionClass *conn, ...@@ -95,9 +95,13 @@ set_statement_option(ConnectionClass *conn,
; ;
else if (SQL_CURSOR_STATIC == vParam) else if (SQL_CURSOR_STATIC == vParam)
setval = vParam; setval = vParam;
/** else if (SQL_CURSOR_KEYSET_DRIVEN == vParam && ci->updatable) else if (SQL_CURSOR_KEYSET_DRIVEN == vParam)
setval = vParam; **/ {
if (ci->updatable_cursors)
setval = vParam;
else
setval = SQL_CURSOR_STATIC; /* at least scrollable */
}
if (conn) if (conn)
conn->stmtOptions.cursor_type = setval; conn->stmtOptions.cursor_type = setval;
else if (stmt) else if (stmt)
...@@ -372,6 +376,60 @@ PGAPI_SetConnectOption( ...@@ -372,6 +376,60 @@ PGAPI_SetConnectOption(
break; break;
case SQL_TXN_ISOLATION: /* ignored */ case SQL_TXN_ISOLATION: /* ignored */
retval = SQL_SUCCESS;
if (CC_is_in_trans(conn))
{
conn->errormsg = "Cannot switch isolation level while a transaction is in progress";
conn->errornumber = CONN_TRANSACT_IN_PROGRES;
CC_log_error(func, "", conn);
return SQL_ERROR;
}
if (conn->isolation == vParam)
break;
switch (vParam)
{
case SQL_TXN_SERIALIZABLE:
if (PG_VERSION_GE(conn, 6.5) &&
PG_VERSION_LE(conn, 7.0))
retval = SQL_ERROR;
break;
case SQL_TXN_READ_COMMITTED:
if (PG_VERSION_LT(conn, 6.5))
retval = SQL_ERROR;
break;
default:
retval = SQL_ERROR;
}
if (SQL_ERROR == retval)
{
conn->errornumber = CONN_INVALID_ARGUMENT_NO;
conn->errormsg = "Illegal parameter value for SQL_TXN_ISOLATION";
CC_log_error(func, "", conn);
return SQL_ERROR;
}
else
{
char *query;
QResultClass *res;
if (vParam == SQL_TXN_SERIALIZABLE)
query = "SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL SERIALIZABLE";
else
query = "SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL READ COMMITTED";
res = CC_send_query(conn, query, NULL, 0);
if (!res || !QR_command_maybe_successful(res))
retval = SQL_ERROR;
else
conn->isolation = vParam;
if (res)
QR_Destructor(res);
if (SQL_ERROR == retval)
{
conn->errornumber = STMT_EXEC_ERROR;
conn->errormsg = "ISOLATION change request to the server error";
return SQL_ERROR;
}
}
break; break;
/* These options should be handled by driver manager */ /* These options should be handled by driver manager */
...@@ -476,8 +534,8 @@ PGAPI_GetConnectOption( ...@@ -476,8 +534,8 @@ PGAPI_GetConnectOption(
*((UDWORD *) pvParam) = (UDWORD) NULL; *((UDWORD *) pvParam) = (UDWORD) NULL;
break; break;
case SQL_TXN_ISOLATION: /* NOT SUPPORTED */ case SQL_TXN_ISOLATION:
*((UDWORD *) pvParam) = SQL_TXN_READ_COMMITTED; *((UDWORD *) pvParam) = conn->isolation;
break; break;
/* These options should be handled by driver manager */ /* These options should be handled by driver manager */
...@@ -567,7 +625,7 @@ PGAPI_GetStmtOption( ...@@ -567,7 +625,7 @@ PGAPI_GetStmtOption(
{ {
/* make sure we're positioned on a valid row */ /* make sure we're positioned on a valid row */
if ((stmt->currTuple < 0) || if ((stmt->currTuple < 0) ||
(stmt->currTuple >= QR_get_num_tuples(res))) (stmt->currTuple >= QR_get_num_backend_tuples(res)))
{ {
stmt->errormsg = "Not positioned on a valid row."; stmt->errormsg = "Not positioned on a valid row.";
stmt->errornumber = STMT_INVALID_CURSOR_STATE_ERROR; stmt->errornumber = STMT_INVALID_CURSOR_STATE_ERROR;
......
...@@ -50,6 +50,29 @@ char *getNextToken(char *s, char *token, int smax, char *delim, char *quote, ...@@ -50,6 +50,29 @@ char *getNextToken(char *s, char *token, int smax, char *delim, char *quote,
void getColInfo(COL_INFO *col_info, FIELD_INFO *fi, int k); void getColInfo(COL_INFO *col_info, FIELD_INFO *fi, int k);
char searchColInfo(COL_INFO *col_info, FIELD_INFO *fi); char searchColInfo(COL_INFO *col_info, FIELD_INFO *fi);
Int4 FI_precision(const FIELD_INFO *fi)
{
if (!fi) return -1;
switch (fi->type)
{
case PG_TYPE_NUMERIC:
return fi->column_size;
case PG_TYPE_DATETIME:
case PG_TYPE_TIMESTAMP_NO_TMZONE:
return fi->decimal_digits;
}
return 0;
}
Int4 FI_scale(const FIELD_INFO *fi)
{
if (!fi) return -1;
switch (fi->type)
{
case PG_TYPE_NUMERIC:
return fi->decimal_digits;
}
return 0;
}
char * char *
getNextToken( getNextToken(
...@@ -265,7 +288,7 @@ searchColInfo(COL_INFO *col_info, FIELD_INFO *fi) ...@@ -265,7 +288,7 @@ searchColInfo(COL_INFO *col_info, FIELD_INFO *fi)
cmp; cmp;
char *col; char *col;
for (k = 0; k < QR_get_num_tuples(col_info->result); k++) for (k = 0; k < QR_get_num_backend_tuples(col_info->result); k++)
{ {
col = QR_get_value_manual(col_info->result, k, 3); col = QR_get_value_manual(col_info->result, k, 3);
if (fi->dquote) if (fi->dquote)
...@@ -291,7 +314,7 @@ char ...@@ -291,7 +314,7 @@ char
parse_statement(StatementClass *stmt) parse_statement(StatementClass *stmt)
{ {
static char *func = "parse_statement"; static char *func = "parse_statement";
char token[256]; char token[256], stoken[256];
char delim, char delim,
quote, quote,
dquote, dquote,
...@@ -315,7 +338,7 @@ parse_statement(StatementClass *stmt) ...@@ -315,7 +338,7 @@ parse_statement(StatementClass *stmt)
i, i,
k = 0, k = 0,
n, n,
blevel = 0; blevel = 0, old_blevel, subqlevel = 0;
FIELD_INFO **fi; FIELD_INFO **fi;
TABLE_INFO **ti; TABLE_INFO **ti;
char parse; char parse;
...@@ -347,7 +370,10 @@ parse_statement(StatementClass *stmt) ...@@ -347,7 +370,10 @@ parse_statement(StatementClass *stmt)
mylog("unquoted=%d, quote=%d, dquote=%d, numeric=%d, delim='%c', token='%s', ptr='%s'\n", unquoted, quote, dquote, numeric, delim, token, ptr); mylog("unquoted=%d, quote=%d, dquote=%d, numeric=%d, delim='%c', token='%s', ptr='%s'\n", unquoted, quote, dquote, numeric, delim, token, ptr);
if (in_select && unquoted && blevel == 0) old_blevel = blevel;
if (unquoted && blevel == 0)
{
if (in_select)
{ {
if (!stricmp(token, "distinct")) if (!stricmp(token, "distinct"))
{ {
...@@ -357,7 +383,7 @@ parse_statement(StatementClass *stmt) ...@@ -357,7 +383,7 @@ parse_statement(StatementClass *stmt)
mylog("DISTINCT\n"); mylog("DISTINCT\n");
continue; continue;
} }
if (!stricmp(token, "into")) else if (!stricmp(token, "into"))
{ {
in_select = FALSE; in_select = FALSE;
mylog("INTO\n"); mylog("INTO\n");
...@@ -365,7 +391,7 @@ parse_statement(StatementClass *stmt) ...@@ -365,7 +391,7 @@ parse_statement(StatementClass *stmt)
stmt->parse_status = STMT_PARSE_FATAL; stmt->parse_status = STMT_PARSE_FATAL;
return FALSE; return FALSE;
} }
if (!stricmp(token, "from")) else if (!stricmp(token, "from"))
{ {
in_select = FALSE; in_select = FALSE;
in_from = TRUE; in_from = TRUE;
...@@ -380,9 +406,7 @@ parse_statement(StatementClass *stmt) ...@@ -380,9 +406,7 @@ parse_statement(StatementClass *stmt)
continue; continue;
} }
} /* in_select && unquoted && blevel == 0 */ } /* in_select && unquoted && blevel == 0 */
if (unquoted && blevel == 0) else if ((!stricmp(token, "where") ||
{
if ((!stricmp(token, "where") ||
!stricmp(token, "union") || !stricmp(token, "union") ||
!stricmp(token, "intersect") || !stricmp(token, "intersect") ||
!stricmp(token, "except") || !stricmp(token, "except") ||
...@@ -390,7 +414,6 @@ parse_statement(StatementClass *stmt) ...@@ -390,7 +414,6 @@ parse_statement(StatementClass *stmt)
!stricmp(token, "group") || !stricmp(token, "group") ||
!stricmp(token, "having"))) !stricmp(token, "having")))
{ {
in_select = FALSE;
in_from = FALSE; in_from = FALSE;
in_where = TRUE; in_where = TRUE;
...@@ -406,24 +429,61 @@ parse_statement(StatementClass *stmt) ...@@ -406,24 +429,61 @@ parse_statement(StatementClass *stmt)
continue; continue;
} }
} /* unquoted && blevel == 0 */ } /* unquoted && blevel == 0 */
if (in_select && (in_expr || in_func)) /* check the change of blevel etc */
{
/* just eat the expression */
mylog("in_expr=%d or func=%d\n", in_expr, in_func);
if (unquoted) if (unquoted)
{ {
if (token[0] == '(') if (!stricmp(token, "select"))
{
stoken[0] = '\0';
if (0 == blevel)
{
in_select = TRUE;
mylog("SELECT\n");
continue;
}
else
{
mylog("SUBSELECT\n");
if (0 == subqlevel)
subqlevel = blevel;
}
}
else if (token[0] == '(')
{ {
blevel++; blevel++;
mylog("blevel++ = %d\n", blevel); mylog("blevel++ = %d\n", blevel);
/* aggregate function ? */
if (stoken[0] && updatable && 0 == subqlevel)
{
if (stricmp(stoken, "count") == 0 ||
stricmp(stoken, "sum") == 0 ||
stricmp(stoken, "avg") == 0 ||
stricmp(stoken, "max") == 0 ||
stricmp(stoken, "min") == 0 ||
stricmp(stoken, "variance") == 0 ||
stricmp(stoken, "stddev") == 0)
updatable = FALSE;
}
} }
else if (token[0] == ')') else if (token[0] == ')')
{ {
blevel--; blevel--;
mylog("blevel-- = %d\n", blevel); mylog("blevel-- = %d\n", blevel);
if (blevel < subqlevel)
subqlevel = 0;
} }
if (blevel >= old_blevel && ',' != delim)
strcpy(stoken, token);
else
stoken[0] = '\0';
} }
if (in_select)
{
if (in_expr || in_func)
{
/* just eat the expression */
mylog("in_expr=%d or func=%d\n", in_expr, in_func);
if (blevel == 0) if (blevel == 0)
{ {
if (delim == ',') if (delim == ',')
...@@ -443,17 +503,8 @@ parse_statement(StatementClass *stmt) ...@@ -443,17 +503,8 @@ parse_statement(StatementClass *stmt)
} }
} }
continue; continue;
} /* in_select && (in_expr || in_func) */ } /* (in_expr || in_func) && in_select */
if (unquoted && !stricmp(token, "select"))
{
in_select = TRUE;
mylog("SELECT\n");
continue;
}
if (in_select)
{
if (in_distinct) if (in_distinct)
{ {
mylog("in distinct\n"); mylog("in distinct\n");
...@@ -515,12 +566,11 @@ parse_statement(StatementClass *stmt) ...@@ -515,12 +566,11 @@ parse_statement(StatementClass *stmt)
mylog("**** got numeric: nfld = %d\n", irdflds->nfields); mylog("**** got numeric: nfld = %d\n", irdflds->nfields);
fi[irdflds->nfields]->numeric = TRUE; fi[irdflds->nfields]->numeric = TRUE;
} }
else if (token[0] == '(') else if (0 == old_blevel && blevel > 0)
{ /* expression */ { /* expression */
mylog("got EXPRESSION\n"); mylog("got EXPRESSION\n");
fi[irdflds->nfields++]->expr = TRUE; fi[irdflds->nfields++]->expr = TRUE;
in_expr = TRUE; in_expr = TRUE;
blevel = 1;
continue; continue;
} }
else else
...@@ -579,11 +629,10 @@ parse_statement(StatementClass *stmt) ...@@ -579,11 +629,10 @@ parse_statement(StatementClass *stmt)
} }
/* Function */ /* Function */
if (token[0] == '(') if (0 == old_blevel && blevel > 0)
{ {
in_dot = FALSE; in_dot = FALSE;
in_func = TRUE; in_func = TRUE;
blevel = 1;
fi[irdflds->nfields - 1]->func = TRUE; fi[irdflds->nfields - 1]->func = TRUE;
/* /*
...@@ -654,6 +703,7 @@ parse_statement(StatementClass *stmt) ...@@ -654,6 +703,7 @@ parse_statement(StatementClass *stmt)
ti[stmt->ntab]->schema[0] = '\0'; ti[stmt->ntab]->schema[0] = '\0';
ti[stmt->ntab]->alias[0] = '\0'; ti[stmt->ntab]->alias[0] = '\0';
ti[stmt->ntab]->updatable = 1;
strcpy(ti[stmt->ntab]->name, token); strcpy(ti[stmt->ntab]->name, token);
if (!dquote) if (!dquote)
...@@ -845,6 +895,37 @@ parse_statement(StatementClass *stmt) ...@@ -845,6 +895,37 @@ parse_statement(StatementClass *stmt)
col_stmt = (StatementClass *) hcol_stmt; col_stmt = (StatementClass *) hcol_stmt;
col_stmt->internal = TRUE; col_stmt->internal = TRUE;
if (!ti[i]->schema[0] && conn->schema_support)
{
QResultClass *res;
BOOL tblFound = FALSE;
/* Unfortunately CURRENT_SCHEMA doesn't exist
* in PostgreSQL and we have to check as follows.
*/
sprintf(token, "select nspname from pg_namespace n, pg_class c"
" where c.relnamespace=n.oid and c.oid='%s'::regclass", ti[i]->name);
res = CC_send_query(conn, token, NULL, CLEAR_RESULT_ON_ABORT);
if (res)
{
if (QR_get_num_total_tuples(res) == 1)
{
tblFound = TRUE;
strcpy(ti[i]->schema, QR_get_value_backend_row(res, 0, 0));
}
QR_Destructor(res);
}
else
CC_abort(conn);
if (!tblFound)
{
stmt->parse_status = STMT_PARSE_FATAL;
stmt->errornumber = STMT_EXEC_ERROR;
stmt->errormsg = "Table not found";
stmt->updatable = FALSE;
return FALSE;
}
}
result = PGAPI_Columns(hcol_stmt, "", 0, ti[i]->schema, result = PGAPI_Columns(hcol_stmt, "", 0, ti[i]->schema,
SQL_NTS, ti[i]->name, SQL_NTS, "", 0, PODBC_NOT_SEARCH_PATTERN); SQL_NTS, ti[i]->name, SQL_NTS, "", 0, PODBC_NOT_SEARCH_PATTERN);
...@@ -907,6 +988,8 @@ parse_statement(StatementClass *stmt) ...@@ -907,6 +988,8 @@ parse_statement(StatementClass *stmt)
/* /*
* Now resolve the fields to point to column info * Now resolve the fields to point to column info
*/ */
if (updatable && 1 == stmt->ntab)
updatable = stmt->ti[0]->updatable;
for (i = 0; i < (int) irdflds->nfields;) for (i = 0; i < (int) irdflds->nfields;)
{ {
fi[i]->updatable = updatable; fi[i]->updatable = updatable;
...@@ -934,14 +1017,14 @@ parse_statement(StatementClass *stmt) ...@@ -934,14 +1017,14 @@ parse_statement(StatementClass *stmt)
if (fi[i]->ti) /* The star represents only the qualified if (fi[i]->ti) /* The star represents only the qualified
* table */ * table */
total_cols = QR_get_num_tuples(fi[i]->ti->col_info->result); total_cols = QR_get_num_backend_tuples(fi[i]->ti->col_info->result);
else else
{ /* The star represents all tables */ { /* The star represents all tables */
/* Calculate the total number of columns after expansion */ /* Calculate the total number of columns after expansion */
for (k = 0; k < stmt->ntab; k++) for (k = 0; k < stmt->ntab; k++)
total_cols += QR_get_num_tuples(ti[k]->col_info->result); total_cols += QR_get_num_backend_tuples(ti[k]->col_info->result);
} }
increased_cols = total_cols - 1; increased_cols = total_cols - 1;
...@@ -988,7 +1071,7 @@ parse_statement(StatementClass *stmt) ...@@ -988,7 +1071,7 @@ parse_statement(StatementClass *stmt)
{ {
TABLE_INFO *the_ti = do_all_tables ? ti[k] : fi[i]->ti; TABLE_INFO *the_ti = do_all_tables ? ti[k] : fi[i]->ti;
cols = QR_get_num_tuples(the_ti->col_info->result); cols = QR_get_num_backend_tuples(the_ti->col_info->result);
for (n = 0; n < cols; n++) for (n = 0; n < cols; n++)
{ {
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include "connection.h" #include "connection.h"
#include "statement.h" #include "statement.h"
#include "descriptor.h" #include "descriptor.h"
#include "qresult.h"
#include "pgapifunc.h" #include "pgapifunc.h"
static HSTMT statementHandleFromDescHandle(SQLHDESC, SQLINTEGER *descType); static HSTMT statementHandleFromDescHandle(SQLHDESC, SQLINTEGER *descType);
...@@ -69,13 +70,22 @@ PGAPI_GetDiagRec(SQLSMALLINT HandleType, SQLHANDLE Handle, ...@@ -69,13 +70,22 @@ PGAPI_GetDiagRec(SQLSMALLINT HandleType, SQLHANDLE Handle,
return ret; return ret;
} }
/*
* Minimal implementation.
*
*/
RETCODE SQL_API RETCODE SQL_API
PGAPI_GetDiagField(SQLSMALLINT HandleType, SQLHANDLE Handle, PGAPI_GetDiagField(SQLSMALLINT HandleType, SQLHANDLE Handle,
SQLSMALLINT RecNumber, SQLSMALLINT DiagIdentifier, SQLSMALLINT RecNumber, SQLSMALLINT DiagIdentifier,
PTR DiagInfoPtr, SQLSMALLINT BufferLength, PTR DiagInfoPtr, SQLSMALLINT BufferLength,
SQLSMALLINT *StringLengthPtr) SQLSMALLINT *StringLengthPtr)
{ {
RETCODE ret = SQL_ERROR; RETCODE ret = SQL_ERROR, rtn;
ConnectionClass *conn;
SQLHANDLE stmtHandle;
StatementClass *stmt;
SDWORD rc;
SWORD pcbErrm;
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);
...@@ -87,43 +97,243 @@ PGAPI_GetDiagField(SQLSMALLINT HandleType, SQLHANDLE Handle, ...@@ -87,43 +97,243 @@ PGAPI_GetDiagField(SQLSMALLINT HandleType, SQLHANDLE Handle,
case SQL_DIAG_CLASS_ORIGIN: case SQL_DIAG_CLASS_ORIGIN:
case SQL_DIAG_SUBCLASS_ORIGIN: case SQL_DIAG_SUBCLASS_ORIGIN:
case SQL_DIAG_CONNECTION_NAME: case SQL_DIAG_CONNECTION_NAME:
case SQL_DIAG_SERVER_NAME:
strcpy((char *) DiagInfoPtr, "");
if (StringLengthPtr)
*StringLengthPtr = 0;
ret = SQL_SUCCESS;
break;
case SQL_DIAG_MESSAGE_TEXT: case SQL_DIAG_MESSAGE_TEXT:
ret = PGAPI_EnvError(Handle, RecNumber,
NULL, NULL, DiagInfoPtr,
BufferLength, StringLengthPtr, 0);
break;
case SQL_DIAG_NATIVE: case SQL_DIAG_NATIVE:
ret = PGAPI_EnvError(Handle, RecNumber,
NULL, DiagInfoPtr, NULL,
0, NULL, 0);
if (StringLengthPtr)
*StringLengthPtr = sizeof(SQLINTEGER);
if (SQL_SUCCESS_WITH_INFO == ret)
ret = SQL_SUCCESS;
break;
case SQL_DIAG_NUMBER: case SQL_DIAG_NUMBER:
case SQL_DIAG_RETURNCODE: ret = PGAPI_EnvError(Handle, RecNumber,
case SQL_DIAG_SERVER_NAME: NULL, NULL, NULL,
0, NULL, 0);
if (SQL_SUCCESS == ret ||
SQL_SUCCESS_WITH_INFO == ret)
{
*((SQLINTEGER *) DiagInfoPtr) = 1;
if (StringLengthPtr)
*StringLengthPtr = sizeof(SQLINTEGER);
ret = SQL_SUCCESS;
}
break;
case SQL_DIAG_SQLSTATE: case SQL_DIAG_SQLSTATE:
ret = PGAPI_EnvError(Handle, RecNumber,
DiagInfoPtr, NULL, NULL,
0, NULL, 0);
if (StringLengthPtr)
*StringLengthPtr = 5;
if (SQL_SUCCESS_WITH_INFO == ret)
ret = SQL_SUCCESS;
break;
case SQL_DIAG_RETURNCODE: /* driver manager returns */
break;
case SQL_DIAG_CURSOR_ROW_COUNT:
case SQL_DIAG_ROW_COUNT:
case SQL_DIAG_DYNAMIC_FUNCTION:
case SQL_DIAG_DYNAMIC_FUNCTION_CODE:
/* options for statement type only */
break; break;
} }
break; break;
case SQL_HANDLE_DBC: case SQL_HANDLE_DBC:
conn = (ConnectionClass *) Handle;
switch (DiagIdentifier) switch (DiagIdentifier)
{ {
case SQL_DIAG_CLASS_ORIGIN: case SQL_DIAG_CLASS_ORIGIN:
case SQL_DIAG_SUBCLASS_ORIGIN: case SQL_DIAG_SUBCLASS_ORIGIN:
case SQL_DIAG_CONNECTION_NAME: case SQL_DIAG_CONNECTION_NAME:
strcpy((char *) DiagInfoPtr, "");
if (StringLengthPtr)
*StringLengthPtr = 0;
ret = SQL_SUCCESS;
break;
case SQL_DIAG_SERVER_NAME:
strcpy((SQLCHAR *) DiagInfoPtr, CC_get_DSN(conn));
if (StringLengthPtr)
*StringLengthPtr = strlen(CC_get_DSN(conn));
ret = SQL_SUCCESS;
break;
case SQL_DIAG_MESSAGE_TEXT: case SQL_DIAG_MESSAGE_TEXT:
ret = PGAPI_ConnectError(Handle, RecNumber,
NULL, NULL, DiagInfoPtr,
BufferLength, StringLengthPtr, 0);
break;
case SQL_DIAG_NATIVE: case SQL_DIAG_NATIVE:
ret = PGAPI_ConnectError(Handle, RecNumber,
NULL, DiagInfoPtr, NULL,
0, NULL, 0);
if (StringLengthPtr)
*StringLengthPtr = sizeof(SQLINTEGER);
if (SQL_SUCCESS_WITH_INFO == ret)
ret = SQL_SUCCESS;
break;
case SQL_DIAG_NUMBER: case SQL_DIAG_NUMBER:
case SQL_DIAG_RETURNCODE: ret = PGAPI_ConnectError(Handle, RecNumber,
case SQL_DIAG_SERVER_NAME: NULL, NULL, NULL,
0, NULL, 0);
if (SQL_SUCCESS == ret ||
SQL_SUCCESS_WITH_INFO == ret)
{
*((SQLINTEGER *) DiagInfoPtr) = 1;
if (StringLengthPtr)
*StringLengthPtr = sizeof(SQLINTEGER);
ret = SQL_SUCCESS;
}
break;
case SQL_DIAG_SQLSTATE: case SQL_DIAG_SQLSTATE:
ret = PGAPI_ConnectError(Handle, RecNumber,
DiagInfoPtr, NULL, NULL,
0, NULL, 0);
if (StringLengthPtr)
*StringLengthPtr = 5;
if (SQL_SUCCESS_WITH_INFO == ret)
ret = SQL_SUCCESS;
break;
case SQL_DIAG_RETURNCODE: /* driver manager returns */
break;
case SQL_DIAG_CURSOR_ROW_COUNT:
case SQL_DIAG_ROW_COUNT:
case SQL_DIAG_DYNAMIC_FUNCTION:
case SQL_DIAG_DYNAMIC_FUNCTION_CODE:
/* options for statement type only */
break; break;
} }
break; break;
case SQL_HANDLE_STMT: case SQL_HANDLE_STMT:
conn = (ConnectionClass *) SC_get_conn(((StatementClass *) Handle));
switch (DiagIdentifier) switch (DiagIdentifier)
{ {
case SQL_DIAG_CLASS_ORIGIN: case SQL_DIAG_CLASS_ORIGIN:
case SQL_DIAG_SUBCLASS_ORIGIN: case SQL_DIAG_SUBCLASS_ORIGIN:
case SQL_DIAG_CONNECTION_NAME: case SQL_DIAG_CONNECTION_NAME:
strcpy((char *) DiagInfoPtr, "");
if (StringLengthPtr)
*StringLengthPtr = 0;
ret = SQL_SUCCESS;
break;
case SQL_DIAG_SERVER_NAME:
strcpy((SQLCHAR *) DiagInfoPtr, CC_get_DSN(conn));
if (StringLengthPtr)
*StringLengthPtr = strlen(CC_get_DSN(conn));
ret = SQL_SUCCESS;
break;
case SQL_DIAG_MESSAGE_TEXT: case SQL_DIAG_MESSAGE_TEXT:
ret = PGAPI_StmtError(Handle, RecNumber,
NULL, NULL, DiagInfoPtr,
BufferLength, StringLengthPtr, 0);
break;
case SQL_DIAG_NATIVE: case SQL_DIAG_NATIVE:
ret = PGAPI_StmtError(Handle, RecNumber,
NULL, DiagInfoPtr, NULL,
0, NULL, 0);
if (StringLengthPtr)
*StringLengthPtr = sizeof(SQLINTEGER);
if (SQL_SUCCESS_WITH_INFO == ret)
ret = SQL_SUCCESS;
break;
case SQL_DIAG_NUMBER: case SQL_DIAG_NUMBER:
case SQL_DIAG_RETURNCODE: *((SQLINTEGER *) DiagInfoPtr) = 0;
ret = SQL_NO_DATA_FOUND;
stmt = (StatementClass *) Handle;
do
{
rtn = PGAPI_StmtError(Handle, RecNumber,
NULL, NULL, NULL,
0, &pcbErrm, 0);
if (SQL_SUCCESS == rtn ||
SQL_SUCCESS_WITH_INFO == rtn)
{
*((SQLINTEGER *) DiagInfoPtr)++;
ret = SQL_SUCCESS;
}
} while (pcbErrm >= stmt->error_recsize);
if (StringLengthPtr)
*StringLengthPtr = sizeof(SQLINTEGER);
break;
case SQL_DIAG_SQLSTATE:
ret = PGAPI_StmtError(Handle, RecNumber,
DiagInfoPtr, NULL, NULL,
0, NULL, 0);
if (StringLengthPtr)
*StringLengthPtr = 5;
if (SQL_SUCCESS_WITH_INFO == ret)
ret = SQL_SUCCESS;
break;
case SQL_DIAG_CURSOR_ROW_COUNT:
stmt = (StatementClass *) Handle;
rc = -1;
if (stmt->status == STMT_FINISHED)
{
QResultClass *res = SC_get_Curres(stmt);
if (res && QR_NumResultCols(res) > 0 && !SC_is_fetchcursor(stmt))
rc = QR_get_num_total_tuples(res) - res->dl_count;
}
*((SQLINTEGER *) DiagInfoPtr) = rc;
if (StringLengthPtr)
*StringLengthPtr = sizeof(SQLINTEGER);
ret = SQL_SUCCESS;
break;
case SQL_DIAG_ROW_COUNT:
stmt = (StatementClass *) Handle;
*((SQLINTEGER *) DiagInfoPtr) = stmt->diag_row_count;
if (StringLengthPtr)
*StringLengthPtr = sizeof(SQLINTEGER);
ret = SQL_SUCCESS;
break;
case SQL_DIAG_RETURNCODE: /* driver manager returns */
break;
}
break;
case SQL_HANDLE_DESC:
stmtHandle = statementHandleFromDescHandle(Handle, NULL);
conn = (ConnectionClass *) SC_get_conn(((StatementClass *) stmtHandle));
switch (DiagIdentifier)
{
case SQL_DIAG_CLASS_ORIGIN:
case SQL_DIAG_SUBCLASS_ORIGIN:
case SQL_DIAG_CONNECTION_NAME:
strcpy((char *) DiagInfoPtr, "");
if (StringLengthPtr)
*StringLengthPtr = 0;
ret = SQL_SUCCESS;
break;
case SQL_DIAG_SERVER_NAME: case SQL_DIAG_SERVER_NAME:
strcpy((SQLCHAR *) DiagInfoPtr, CC_get_DSN(conn));
if (StringLengthPtr)
*StringLengthPtr = strlen(CC_get_DSN(conn));
ret = SQL_SUCCESS;
break; break;
case SQL_DIAG_MESSAGE_TEXT:
case SQL_DIAG_NATIVE:
case SQL_DIAG_NUMBER:
case SQL_DIAG_SQLSTATE: case SQL_DIAG_SQLSTATE:
ret = PGAPI_GetDiagField(SQL_HANDLE_STMT,
stmtHandle, RecNumber,
DiagIdentifier, DiagInfoPtr,
BufferLength, StringLengthPtr);
break;
case SQL_DIAG_RETURNCODE: /* driver manager returns */
break;
case SQL_DIAG_CURSOR_ROW_COUNT:
case SQL_DIAG_ROW_COUNT:
case SQL_DIAG_DYNAMIC_FUNCTION:
case SQL_DIAG_DYNAMIC_FUNCTION_CODE:
/* options for statement type only */
break; break;
} }
break; break;
...@@ -155,12 +365,7 @@ PGAPI_GetConnectAttr(HDBC ConnectionHandle, ...@@ -155,12 +365,7 @@ PGAPI_GetConnectAttr(HDBC ConnectionHandle,
*((SQLUINTEGER *) Value) = SQL_FALSE; *((SQLUINTEGER *) Value) = SQL_FALSE;
break; break;
case SQL_ATTR_CONNECTION_DEAD: case SQL_ATTR_CONNECTION_DEAD:
if (CC_is_in_trans(conn)) *((SQLUINTEGER *) Value) = (conn->status == CONN_NOT_CONNECTED || conn->status == CONN_DOWN);
*((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;
...@@ -348,12 +553,24 @@ ARDSetField(StatementClass *stmt, SQLSMALLINT RecNumber, ...@@ -348,12 +553,24 @@ ARDSetField(StatementClass *stmt, SQLSMALLINT RecNumber,
opts->bindings[RecNumber - 1].buflen = (Int4) Value; opts->bindings[RecNumber - 1].buflen = (Int4) Value;
} }
break; break;
case SQL_DESC_PRECISION:
if (RecNumber)
{
column_bindings_set(opts, RecNumber, TRUE);
opts->bindings[RecNumber - 1].precision = (Int2) Value;
}
break;
case SQL_DESC_SCALE:
if (RecNumber)
{
column_bindings_set(opts, RecNumber, TRUE);
opts->bindings[RecNumber - 1].scale = (Int4) Value;
}
break;
case SQL_DESC_ALLOC_TYPE: /* read-only */ case SQL_DESC_ALLOC_TYPE: /* read-only */
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;
} }
...@@ -460,12 +677,18 @@ APDSetField(StatementClass *stmt, SQLSMALLINT RecNumber, ...@@ -460,12 +677,18 @@ APDSetField(StatementClass *stmt, SQLSMALLINT RecNumber,
case SQL_DESC_COUNT: case SQL_DESC_COUNT:
parameter_bindings_set(opts, (SQLUINTEGER) Value, FALSE); parameter_bindings_set(opts, (SQLUINTEGER) Value, FALSE);
break; break;
case SQL_DESC_PRECISION:
parameter_bindings_set(opts, RecNumber, TRUE);
opts->parameters[RecNumber - 1].precision = (Int2) Value;
break;
case SQL_DESC_SCALE:
parameter_bindings_set(opts, RecNumber, TRUE);
opts->parameters[RecNumber - 1].scale = (Int2) Value;
break;
case SQL_DESC_ALLOC_TYPE: /* read-only */ case SQL_DESC_ALLOC_TYPE: /* read-only */
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;
} }
...@@ -710,11 +933,23 @@ ARDGetField(StatementClass *stmt, SQLSMALLINT RecNumber, ...@@ -710,11 +933,23 @@ ARDGetField(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_DATETIME_INTERVAL_PRECISION:
case SQL_DESC_LENGTH:
case SQL_DESC_NUM_PREC_RADIX:
case SQL_DESC_PRECISION: case SQL_DESC_PRECISION:
if (RecNumber)
{
ival = opts->bindings[RecNumber - 1].precision;
}
break;
case SQL_DESC_SCALE: case SQL_DESC_SCALE:
if (RecNumber)
{
ival = opts->bindings[RecNumber - 1].scale;
}
break;
case SQL_DESC_NUM_PREC_RADIX:
ival = 10;
break;
case SQL_DESC_DATETIME_INTERVAL_PRECISION:
case SQL_DESC_LENGTH:
default:ret = SQL_ERROR; default:ret = SQL_ERROR;
stmt->errornumber = STMT_INVALID_DESCRIPTOR_IDENTIFIER; stmt->errornumber = STMT_INVALID_DESCRIPTOR_IDENTIFIER;
} }
...@@ -818,11 +1053,17 @@ APDGetField(StatementClass *stmt, SQLSMALLINT RecNumber, ...@@ -818,11 +1053,17 @@ 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_NUM_PREC_RADIX:
ival = 10;
break;
case SQL_DESC_PRECISION: case SQL_DESC_PRECISION:
ival = opts->parameters[RecNumber - 1].precision;
break;
case SQL_DESC_SCALE: case SQL_DESC_SCALE:
ival = opts->parameters[RecNumber - 1].scale;
break;
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:
default:ret = SQL_ERROR; default:ret = SQL_ERROR;
stmt->errornumber = STMT_INVALID_DESCRIPTOR_IDENTIFIER; stmt->errornumber = STMT_INVALID_DESCRIPTOR_IDENTIFIER;
} }
...@@ -1339,3 +1580,77 @@ PGAPI_SetStmtAttr(HSTMT StatementHandle, ...@@ -1339,3 +1580,77 @@ PGAPI_SetStmtAttr(HSTMT StatementHandle,
} }
return SQL_SUCCESS; return SQL_SUCCESS;
} }
#ifdef DRIVER_CURSOR_IMPLEMENT
RETCODE SQL_API
PGAPI_BulkOperations(HSTMT hstmt, SQLSMALLINT operation)
{
static char *func = "PGAPI_BulkOperations";
StatementClass *stmt = (StatementClass *) hstmt;
ARDFields *opts = SC_get_ARD(stmt);
RETCODE ret;
UInt4 offset, bind_size = opts->bind_size, *bmark = NULL;
int i, processed;
ConnectionClass *conn;
BOOL auto_commit_needed = FALSE;
QResultClass *res;
mylog("%s operation = %d\n", func, operation);
SC_clear_error(stmt);
offset = opts->row_offset_ptr ? *opts->row_offset_ptr : 0;
if (SQL_FETCH_BY_BOOKMARK != operation)
{
conn = SC_get_conn(stmt);
if (auto_commit_needed = CC_is_in_autocommit(conn), auto_commit_needed)
PGAPI_SetConnectOption(conn, SQL_AUTOCOMMIT, SQL_AUTOCOMMIT_OFF);
}
if (SQL_ADD != operation)
{
if (bmark = (UInt4 *) opts->bookmark->buffer, !bmark)
{
stmt->errornumber = STMT_INVALID_OPTION_IDENTIFIER;
stmt->errormsg = "bookmark isn't specified";
return SQL_ERROR;
}
bmark += (offset >> 4);
}
for (i = 0, processed = 0; i < opts->rowset_size; i++)
{
/* Note opts->row_operation_ptr is ignored */
switch (operation)
{
case SQL_ADD:
ret = SC_pos_add(stmt, (UWORD) i);
break;
case SQL_UPDATE_BY_BOOKMARK:
ret = SC_pos_update(stmt, (UWORD) i, *bmark);
break;
case SQL_DELETE_BY_BOOKMARK:
ret = SC_pos_delete(stmt, (UWORD) i, *bmark);
break;
case SQL_FETCH_BY_BOOKMARK:
ret = SC_pos_refresh(stmt, (UWORD) i, *bmark);
break;
}
processed++;
if (SQL_ERROR == ret)
break;
if (SQL_ADD != operation)
{
if (bind_size > 0)
bmark += (bind_size >> 2);
else
bmark++;
}
}
if (auto_commit_needed)
PGAPI_SetConnectOption(conn, SQL_AUTOCOMMIT, SQL_AUTOCOMMIT_ON);
if (SC_get_IRD(stmt)->rowsFetched)
*(SC_get_IRD(stmt)->rowsFetched) = processed;
if (res = SC_get_Curres(stmt), res)
res->recent_processed_row_count = stmt->diag_row_count = processed;
return ret;
}
#endif /* DRIVER_CURSOR_IMPLEMENT */
...@@ -172,7 +172,8 @@ RETCODE SQL_API PGAPI_ExtendedFetch( ...@@ -172,7 +172,8 @@ RETCODE SQL_API PGAPI_ExtendedFetch(
SQLUSMALLINT fFetchType, SQLUSMALLINT fFetchType,
SQLINTEGER irow, SQLINTEGER irow,
SQLUINTEGER *pcrow, SQLUINTEGER *pcrow,
SQLUSMALLINT *rgfRowStatus); SQLUSMALLINT *rgfRowStatus,
SQLINTEGER FetchOffset);
RETCODE SQL_API PGAPI_ForeignKeys( RETCODE SQL_API PGAPI_ForeignKeys(
HSTMT hstmt, HSTMT hstmt,
SQLCHAR *szPkCatalogName, SQLCHAR *szPkCatalogName,
...@@ -281,6 +282,8 @@ RETCODE SQL_API PGAPI_SetConnectAttr(HDBC ConnectionHandle, ...@@ -281,6 +282,8 @@ RETCODE SQL_API PGAPI_SetConnectAttr(HDBC ConnectionHandle,
RETCODE SQL_API PGAPI_SetStmtAttr(HSTMT StatementHandle, RETCODE SQL_API PGAPI_SetStmtAttr(HSTMT StatementHandle,
SQLINTEGER Attribute, PTR Value, SQLINTEGER Attribute, PTR Value,
SQLINTEGER StringLength); SQLINTEGER StringLength);
RETCODE SQL_API PGAPI_BulkOperations(HSTMT StatementHandle,
SQLSMALLINT operation);
RETCODE SQL_API PGAPI_SetDescField(SQLHDESC DescriptorHandle, RETCODE SQL_API PGAPI_SetDescField(SQLHDESC DescriptorHandle,
SQLSMALLINT RecNumber, SQLSMALLINT FieldIdentifier, SQLSMALLINT RecNumber, SQLSMALLINT FieldIdentifier,
PTR Value, SQLINTEGER BufferLength); PTR Value, SQLINTEGER BufferLength);
......
...@@ -101,7 +101,8 @@ Int2 sqlTypes[] = { ...@@ -101,7 +101,8 @@ Int2 sqlTypes[] = {
}; };
#if (ODBCVER >= 0x0300) && defined(OBDCINT64) #if (ODBCVER >= 0x0300) && defined(OBDCINT64)
#define ALLOWED_C_BIGINT SQL_C_SBIGINT /* #define ALLOWED_C_BIGINT SQL_C_SBIGINT */
#define ALLOWED_C_BIGINT SQL_C_CHAR /* Delphi should be either ? */
#else #else
#define ALLOWED_C_BIGINT SQL_C_CHAR #define ALLOWED_C_BIGINT SQL_C_CHAR
#endif #endif
...@@ -286,11 +287,13 @@ pgtype_to_concise_type(StatementClass *stmt, Int4 type) ...@@ -286,11 +287,13 @@ pgtype_to_concise_type(StatementClass *stmt, Int4 type)
/* Change this to SQL_BIGINT for ODBC v3 bjm 2001-01-23 */ /* Change this to SQL_BIGINT for ODBC v3 bjm 2001-01-23 */
case PG_TYPE_INT8: case PG_TYPE_INT8:
if (conn->ms_jet)
return SQL_NUMERIC; /* maybe a little better than SQL_VARCHAR */
#if (ODBCVER >= 0x0300) #if (ODBCVER >= 0x0300)
if (!conn->ms_jet)
return SQL_BIGINT; return SQL_BIGINT;
#endif /* ODBCVER */ #else
return SQL_VARCHAR; return SQL_VARCHAR;
#endif /* ODBCVER */
case PG_TYPE_NUMERIC: case PG_TYPE_NUMERIC:
return SQL_NUMERIC; return SQL_NUMERIC;
......
...@@ -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.65 2002/04/15 02:46:00 inoue Exp $ * $Id: psqlodbc.h,v 1.66 2002/05/22 05:51:03 inoue Exp $
* *
*/ */
...@@ -20,6 +20,8 @@ ...@@ -20,6 +20,8 @@
#include <stdio.h> /* for FILE* pointers: see GLOBAL_VALUES */ #include <stdio.h> /* for FILE* pointers: see GLOBAL_VALUES */
#include "version.h"
/* Must come before sql.h */ /* Must come before sql.h */
#ifndef ODBCVER #ifndef ODBCVER
#define ODBCVER 0x0250 #define ODBCVER 0x0250
...@@ -87,8 +89,6 @@ typedef UInt4 Oid; ...@@ -87,8 +89,6 @@ typedef UInt4 Oid;
#define DBMS_NAME "PostgreSQL" #define DBMS_NAME "PostgreSQL"
#endif /* ODBCVER */ #endif /* ODBCVER */
#define POSTGRESDRIVERVERSION "07.02.0001"
#ifdef WIN32 #ifdef WIN32
#if (ODBCVER >= 0x0300) #if (ODBCVER >= 0x0300)
#ifdef UNICODE_SUPPORT #ifdef UNICODE_SUPPORT
......
//Microsoft Developer Studio generated resource script. //Microsoft Developer Studio generated resource script.
// //
#include "resource.h" #include "resource.h"
#include "version.h"
#define APSTUDIO_READONLY_SYMBOLS #define APSTUDIO_READONLY_SYMBOLS
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
...@@ -366,8 +367,8 @@ END ...@@ -366,8 +367,8 @@ END
// //
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 7,2,0,01 FILEVERSION PG_DRVFILE_VERSION
PRODUCTVERSION 7,2,0,01 PRODUCTVERSION PG_DRVFILE_VERSION
FILEFLAGSMASK 0x3L FILEFLAGSMASK 0x3L
#ifdef _DEBUG #ifdef _DEBUG
FILEFLAGS 0x1L FILEFLAGS 0x1L
...@@ -389,14 +390,14 @@ BEGIN ...@@ -389,14 +390,14 @@ BEGIN
VALUE "CompanyName", "Insight Distribution Systems\0" VALUE "CompanyName", "Insight Distribution Systems\0"
#endif #endif
VALUE "FileDescription", "PostgreSQL Driver\0" VALUE "FileDescription", "PostgreSQL Driver\0"
VALUE "FileVersion", " 07.02.0001\0" VALUE "FileVersion", POSTGRES_RESOURCE_VERSION
VALUE "InternalName", "psqlodbc\0" VALUE "InternalName", "psqlodbc\0"
VALUE "LegalCopyright", "\0" VALUE "LegalCopyright", "\0"
VALUE "LegalTrademarks", "ODBC(TM) is a trademark of Microsoft Corporation. Microsoft is a registered trademark of Microsoft Corporation. Windows(TM) is a trademark of Microsoft Corporation.\0" VALUE "LegalTrademarks", "ODBC(TM) is a trademark of Microsoft Corporation. Microsoft is a registered trademark of Microsoft Corporation. Windows(TM) is a trademark of Microsoft Corporation.\0"
VALUE "OriginalFilename", "psqlodbc.dll\0" VALUE "OriginalFilename", "psqlodbc.dll\0"
VALUE "PrivateBuild", "\0" VALUE "PrivateBuild", "\0"
VALUE "ProductName", "Microsoft Open Database Connectivity\0" VALUE "ProductName", "Microsoft Open Database Connectivity\0"
VALUE "ProductVersion", " 07.02.0001\0" VALUE "ProductVersion", POSTGRES_RESOURCE_VERSION
VALUE "SpecialBuild", "\0" VALUE "SpecialBuild", "\0"
END END
END END
......
...@@ -110,9 +110,13 @@ QR_Constructor() ...@@ -110,9 +110,13 @@ QR_Constructor()
rv->conn = NULL; rv->conn = NULL;
rv->next = NULL; rv->next = NULL;
rv->inTuples = FALSE; rv->inTuples = FALSE;
rv->fcount = 0; rv->count_backend_allocated = 0;
rv->count_keyset_allocated = 0;
rv->num_total_rows = 0;
rv->num_backend_rows = 0;
rv->fetch_count = 0; rv->fetch_count = 0;
rv->base = 0; rv->base = 0;
rv->recent_processed_row_count = -1;
rv->currTuple = -1; rv->currTuple = -1;
rv->num_fields = 0; rv->num_fields = 0;
rv->tupleField = NULL; rv->tupleField = NULL;
...@@ -126,6 +130,9 @@ QR_Constructor() ...@@ -126,6 +130,9 @@ QR_Constructor()
rv->rb_alloc = 0; rv->rb_alloc = 0;
rv->rb_count = 0; rv->rb_count = 0;
rv->rollback = NULL; rv->rollback = NULL;
rv->dl_alloc = 0;
rv->dl_count = 0;
rv->deleted = NULL;
} }
mylog("exit QR_Constructor\n"); mylog("exit QR_Constructor\n");
...@@ -202,14 +209,14 @@ QR_free_memory(QResultClass *self) ...@@ -202,14 +209,14 @@ QR_free_memory(QResultClass *self)
register int lf, register int lf,
row; row;
register TupleField *tuple = self->backend_tuples; register TupleField *tuple = self->backend_tuples;
int fcount = self->fcount; int num_backend_rows = self->num_backend_rows;
int num_fields = self->num_fields; int num_fields = self->num_fields;
mylog("QResult: free memory in, fcount=%d\n", fcount); mylog("QResult: free memory in, fcount=%d\n", num_backend_rows);
if (self->backend_tuples) if (self->backend_tuples)
{ {
for (row = 0; row < fcount; row++) for (row = 0; row < num_backend_rows; row++)
{ {
mylog("row = %d, num_fields = %d\n", row, num_fields); mylog("row = %d, num_fields = %d\n", row, num_fields);
for (lf = 0; lf < num_fields; lf++) for (lf = 0; lf < num_fields; lf++)
...@@ -224,12 +231,14 @@ QR_free_memory(QResultClass *self) ...@@ -224,12 +231,14 @@ QR_free_memory(QResultClass *self)
} }
free(self->backend_tuples); free(self->backend_tuples);
self->count_backend_allocated = 0;
self->backend_tuples = NULL; self->backend_tuples = NULL;
} }
if (self->keyset) if (self->keyset)
{ {
free(self->keyset); free(self->keyset);
self->keyset = NULL; self->keyset = NULL;
self->count_keyset_allocated = 0;
} }
if (self->rollback) if (self->rollback)
{ {
...@@ -238,8 +247,16 @@ QR_free_memory(QResultClass *self) ...@@ -238,8 +247,16 @@ QR_free_memory(QResultClass *self)
self->rb_count = 0; self->rb_count = 0;
self->rollback = NULL; self->rollback = NULL;
} }
if (self->deleted)
{
free(self->deleted);
self->dl_alloc = 0;
self->dl_count = 0;
self->deleted = NULL;
}
self->fcount = 0; self->num_total_rows = 0;
self->num_backend_rows = 0;
mylog("QResult: free memory out\n"); mylog("QResult: free memory out\n");
} }
...@@ -313,7 +330,7 @@ QR_fetch_tuples(QResultClass *self, ConnectionClass *conn, char *cursor) ...@@ -313,7 +330,7 @@ QR_fetch_tuples(QResultClass *self, ConnectionClass *conn, char *cursor)
/* allocate memory for the tuple cache */ /* allocate memory for the tuple cache */
mylog("MALLOC: tuple_size = %d, size = %d\n", tuple_size, self->num_fields * sizeof(TupleField) * tuple_size); mylog("MALLOC: tuple_size = %d, size = %d\n", tuple_size, self->num_fields * sizeof(TupleField) * tuple_size);
self->count_allocated = 0; self->count_backend_allocated = self->count_keyset_allocated = 0;
if (self->num_fields > 0) if (self->num_fields > 0)
{ {
self->backend_tuples = (TupleField *) malloc(self->num_fields * sizeof(TupleField) * tuple_size); self->backend_tuples = (TupleField *) malloc(self->num_fields * sizeof(TupleField) * tuple_size);
...@@ -323,15 +340,24 @@ QR_fetch_tuples(QResultClass *self, ConnectionClass *conn, char *cursor) ...@@ -323,15 +340,24 @@ QR_fetch_tuples(QResultClass *self, ConnectionClass *conn, char *cursor)
QR_set_message(self, "Could not get memory for tuple cache."); QR_set_message(self, "Could not get memory for tuple cache.");
return FALSE; return FALSE;
} }
self->count_backend_allocated = tuple_size;
} }
if (self->haskeyset) if (self->haskeyset)
self->keyset = (KeySet *) calloc(sizeof(KeySet), tuple_size); {
self->count_allocated = tuple_size; if (self->keyset = (KeySet *) calloc(sizeof(KeySet), tuple_size), !self->keyset)
{
self->status = PGRES_FATAL_ERROR;
QR_set_message(self, "Could not get memory for tuple cache.");
return FALSE;
}
self->count_keyset_allocated = tuple_size;
}
self->inTuples = TRUE; self->inTuples = TRUE;
/* Force a read to occur in next_tuple */ /* Force a read to occur in next_tuple */
self->fcount = tuple_size + 1; self->num_total_rows = tuple_size + 1;
self->num_backend_rows = tuple_size + 1;
self->fetch_count = tuple_size + 1; self->fetch_count = tuple_size + 1;
self->base = 0; self->base = 0;
...@@ -415,7 +441,7 @@ QR_next_tuple(QResultClass *self) ...@@ -415,7 +441,7 @@ QR_next_tuple(QResultClass *self)
/* Speed up access */ /* Speed up access */
int fetch_count = self->fetch_count; int fetch_count = self->fetch_count;
int fcount = self->fcount; int num_backend_rows = self->num_backend_rows;
int fetch_size, int fetch_size,
offset = 0; offset = 0;
int end_tuple = self->rowset_size + self->base; int end_tuple = self->rowset_size + self->base;
...@@ -430,21 +456,21 @@ QR_next_tuple(QResultClass *self) ...@@ -430,21 +456,21 @@ QR_next_tuple(QResultClass *self)
char fetch[128]; char fetch[128];
QueryInfo qi; QueryInfo qi;
ConnInfo *ci = NULL; ConnInfo *ci = NULL;
BOOL set_no_trans; UDWORD abort_opt;
if (fetch_count < fcount) if (fetch_count < num_backend_rows)
{ {
/* return a row from cache */ /* return a row from cache */
mylog("next_tuple: fetch_count < fcount: returning tuple %d, fcount = %d\n", fetch_count, fcount); mylog("next_tuple: fetch_count < fcount: returning tuple %d, fcount = %d\n", fetch_count, num_backend_rows);
self->tupleField = the_tuples + (fetch_count * self->num_fields); /* next row */ self->tupleField = the_tuples + (fetch_count * self->num_fields); /* next row */
self->fetch_count++; self->fetch_count++;
return TRUE; return TRUE;
} }
else if (self->fcount < self->cache_size) else if (self->num_backend_rows < self->cache_size)
{ {
/* last row from cache */ /* last row from cache */
/* We are done because we didn't even get CACHE_SIZE tuples */ /* We are done because we didn't even get CACHE_SIZE tuples */
mylog("next_tuple: fcount < CACHE_SIZE: fcount = %d, fetch_count = %d\n", fcount, fetch_count); mylog("next_tuple: fcount < CACHE_SIZE: fcount = %d, fetch_count = %d\n", num_backend_rows, fetch_count);
self->tupleField = NULL; self->tupleField = NULL;
self->status = PGRES_END_TUPLES; self->status = PGRES_END_TUPLES;
/* end of tuples */ /* end of tuples */
...@@ -464,13 +490,13 @@ QR_next_tuple(QResultClass *self) ...@@ -464,13 +490,13 @@ QR_next_tuple(QResultClass *self)
ci = &(self->conn->connInfo); ci = &(self->conn->connInfo);
if (!self->cursor || !ci->drivers.use_declarefetch) if (!self->cursor || !ci->drivers.use_declarefetch)
{ {
mylog("next_tuple: ALL_ROWS: done, fcount = %d, fetch_count = %d\n", fcount, fetch_count); mylog("next_tuple: ALL_ROWS: done, fcount = %d, fetch_count = %d\n", self->num_total_rows, fetch_count);
self->tupleField = NULL; self->tupleField = NULL;
self->status = PGRES_END_TUPLES; self->status = PGRES_END_TUPLES;
return -1; /* end of tuples */ return -1; /* end of tuples */
} }
if (self->base == fcount) if (self->base == num_backend_rows)
{ {
/* not a correction */ /* not a correction */
/* Determine the optimum cache size. */ /* Determine the optimum cache size. */
...@@ -489,7 +515,7 @@ QR_next_tuple(QResultClass *self) ...@@ -489,7 +515,7 @@ QR_next_tuple(QResultClass *self)
/* need to correct */ /* need to correct */
corrected = TRUE; corrected = TRUE;
fetch_size = end_tuple - fcount; fetch_size = end_tuple - num_backend_rows;
self->cache_size += fetch_size; self->cache_size += fetch_size;
...@@ -497,9 +523,9 @@ QR_next_tuple(QResultClass *self) ...@@ -497,9 +523,9 @@ QR_next_tuple(QResultClass *self)
self->fetch_count++; self->fetch_count++;
} }
if (!self->backend_tuples || self->cache_size > self->count_allocated) if (!self->backend_tuples || self->cache_size > self->count_backend_allocated)
{ {
self->count_allocated = 0; self->count_backend_allocated = 0;
if (self->num_fields > 0) if (self->num_fields > 0)
{ {
self->backend_tuples = (TupleField *) realloc(self->backend_tuples, self->backend_tuples = (TupleField *) realloc(self->backend_tuples,
...@@ -510,10 +536,14 @@ QR_next_tuple(QResultClass *self) ...@@ -510,10 +536,14 @@ QR_next_tuple(QResultClass *self)
QR_set_message(self, "Out of memory while reading tuples."); QR_set_message(self, "Out of memory while reading tuples.");
return FALSE; return FALSE;
} }
self->count_backend_allocated = self->cache_size;
} }
if (self->haskeyset) }
if (self->haskeyset && (!self->keyset || self->cache_size > self->count_keyset_allocated))
{
self->count_keyset_allocated = 0;
self->keyset = (KeySet *) realloc(self->keyset, sizeof(KeySet) * self->cache_size); self->keyset = (KeySet *) realloc(self->keyset, sizeof(KeySet) * self->cache_size);
self->count_allocated = self->cache_size; self->count_keyset_allocated = self->cache_size;
} }
sprintf(fetch, "fetch %d in %s", fetch_size, self->cursor); sprintf(fetch, "fetch %d in %s", fetch_size, self->cursor);
...@@ -534,7 +564,7 @@ QR_next_tuple(QResultClass *self) ...@@ -534,7 +564,7 @@ QR_next_tuple(QResultClass *self)
} }
else else
{ {
mylog("next_tuple: inTuples = true, falling through: fcount = %d, fetch_count = %d\n", self->fcount, self->fetch_count); mylog("next_tuple: inTuples = true, falling through: fcount = %d, fetch_count = %d\n", self->num_backend_rows, self->fetch_count);
/* /*
* This is a pre-fetch (fetching rows right after query but * This is a pre-fetch (fetching rows right after query but
...@@ -548,7 +578,8 @@ QR_next_tuple(QResultClass *self) ...@@ -548,7 +578,8 @@ QR_next_tuple(QResultClass *self)
if (!corrected) if (!corrected)
{ {
self->base = 0; self->base = 0;
self->fcount = 0; self->num_total_rows = 0; /* right ? */
self->num_backend_rows = 0;
} }
sock = CC_get_socket(self->conn); sock = CC_get_socket(self->conn);
...@@ -569,14 +600,15 @@ QR_next_tuple(QResultClass *self) ...@@ -569,14 +600,15 @@ QR_next_tuple(QResultClass *self)
case 'B': /* Tuples in binary format */ case 'B': /* Tuples in binary format */
case 'D': /* Tuples in ASCII format */ case 'D': /* Tuples in ASCII format */
if ((!self->cursor || !ci->drivers.use_declarefetch) && self->fcount >= self->count_allocated) if (!self->cursor || !ci->drivers.use_declarefetch)
{
if (self->num_fields > 0 &&
self->num_total_rows >= self->count_backend_allocated)
{ {
int tuple_size = self->count_allocated; int tuple_size = self->count_backend_allocated;
mylog("REALLOC: old_count = %d, size = %d\n", tuple_size, self->num_fields * sizeof(TupleField) * tuple_size); mylog("REALLOC: old_count = %d, size = %d\n", tuple_size, self->num_fields * sizeof(TupleField) * tuple_size);
tuple_size *= 2; tuple_size *= 2;
if (self->num_fields > 0)
{
self->backend_tuples = (TupleField *) realloc(self->backend_tuples, self->backend_tuples = (TupleField *) realloc(self->backend_tuples,
tuple_size * self->num_fields * sizeof(TupleField)); tuple_size * self->num_fields * sizeof(TupleField));
if (!self->backend_tuples) if (!self->backend_tuples)
...@@ -585,10 +617,16 @@ QR_next_tuple(QResultClass *self) ...@@ -585,10 +617,16 @@ QR_next_tuple(QResultClass *self)
QR_set_message(self, "Out of memory while reading tuples."); QR_set_message(self, "Out of memory while reading tuples.");
return FALSE; return FALSE;
} }
self->count_backend_allocated = tuple_size;
} }
if (self->haskeyset) if (self->haskeyset &&
self->num_total_rows >= self->count_keyset_allocated)
{
int tuple_size = self->count_keyset_allocated;
tuple_size *= 2;
self->keyset = (KeySet *) realloc(self->keyset, sizeof(KeySet) * tuple_size); self->keyset = (KeySet *) realloc(self->keyset, sizeof(KeySet) * tuple_size);
self->count_allocated = tuple_size; self->count_keyset_allocated = tuple_size;
}
} }
if (!QR_read_tuple(self, (char) (id == 0))) if (!QR_read_tuple(self, (char) (id == 0)))
...@@ -597,7 +635,9 @@ QR_next_tuple(QResultClass *self) ...@@ -597,7 +635,9 @@ QR_next_tuple(QResultClass *self)
QR_set_message(self, "Error reading the tuple"); QR_set_message(self, "Error reading the tuple");
return FALSE; return FALSE;
} }
self->fcount++; self->num_total_rows++;
if (self->num_fields > 0)
self->num_backend_rows++;
break; /* continue reading */ break; /* continue reading */
case 'C': /* End of tuple list */ case 'C': /* End of tuple list */
...@@ -607,10 +647,10 @@ QR_next_tuple(QResultClass *self) ...@@ -607,10 +647,10 @@ QR_next_tuple(QResultClass *self)
mylog("end of tuple list -- setting inUse to false: this = %u\n", self); mylog("end of tuple list -- setting inUse to false: this = %u\n", self);
self->inTuples = FALSE; self->inTuples = FALSE;
if (self->fcount > 0) if (self->num_total_rows > 0)
{ {
qlog(" [ fetched %d rows ]\n", self->fcount); qlog(" [ fetched %d rows ]\n", self->num_total_rows);
mylog("_next_tuple: 'C' fetch_max && fcount = %d\n", self->fcount); mylog("_next_tuple: 'C' fetch_max && fcount = %d\n", self->num_total_rows);
/* set to first row */ /* set to first row */
self->tupleField = self->backend_tuples + (offset * self->num_fields); self->tupleField = self->backend_tuples + (offset * self->num_fields);
...@@ -629,11 +669,15 @@ QR_next_tuple(QResultClass *self) ...@@ -629,11 +669,15 @@ QR_next_tuple(QResultClass *self)
QR_set_message(self, msgbuffer); QR_set_message(self, msgbuffer);
self->status = PGRES_FATAL_ERROR; self->status = PGRES_FATAL_ERROR;
set_no_trans = FALSE; abort_opt = 0;
if (!strncmp(msgbuffer, "FATAL", 5)) if (!strncmp(msgbuffer, "FATAL", 5))
set_no_trans = TRUE; abort_opt = NO_TRANS | CONN_DEAD;
CC_on_abort(self->conn, set_no_trans); CC_on_abort(self->conn, abort_opt);
QR_set_status(self, PGRES_FATAL_ERROR);
QR_set_message(self, msgbuffer);
QR_set_aborted(self, TRUE);
mylog("ERROR from backend in next_tuple: '%s'\n", msgbuffer);
qlog("ERROR from backend in next_tuple: '%s'\n", msgbuffer); qlog("ERROR from backend in next_tuple: '%s'\n", msgbuffer);
return FALSE; return FALSE;
...@@ -651,7 +695,7 @@ QR_next_tuple(QResultClass *self) ...@@ -651,7 +695,7 @@ QR_next_tuple(QResultClass *self)
qlog("QR_next_tuple: Unexpected result from backend: id = '%c' (%d)\n", id, id); qlog("QR_next_tuple: Unexpected result from backend: id = '%c' (%d)\n", id, id);
QR_set_message(self, "Unexpected result from backend. It probably crashed"); QR_set_message(self, "Unexpected result from backend. It probably crashed");
self->status = PGRES_FATAL_ERROR; self->status = PGRES_FATAL_ERROR;
CC_on_abort(self->conn, TRUE); CC_on_abort(self->conn, NO_TRANS | CONN_DEAD);
return FALSE; return FALSE;
} }
} }
...@@ -681,16 +725,16 @@ QR_read_tuple(QResultClass *self, char binary) ...@@ -681,16 +725,16 @@ QR_read_tuple(QResultClass *self, char binary)
/* set the current row to read the fields into */ /* set the current row to read the fields into */
effective_cols = ci_num_fields; effective_cols = ci_num_fields;
this_tuplefield = self->backend_tuples + (self->fcount * num_fields); this_tuplefield = self->backend_tuples + (self->num_backend_rows * num_fields);
if (self->haskeyset) if (self->haskeyset)
{ {
this_keyset = self->keyset + self->fcount; this_keyset = self->keyset + self->num_total_rows;
this_keyset->status = 0; this_keyset->status = 0;
effective_cols -= 2; effective_cols -= 2;
} }
bitmaplen = (Int2) num_fields / BYTELEN; bitmaplen = (Int2) ci_num_fields / BYTELEN;
if ((num_fields % BYTELEN) > 0) if ((ci_num_fields % BYTELEN) > 0)
bitmaplen++; bitmaplen++;
/* /*
......
...@@ -48,15 +48,18 @@ struct QResultClass_ ...@@ -48,15 +48,18 @@ struct QResultClass_
QResultClass *next; /* the following result class */ QResultClass *next; /* the following result class */
/* Stuff for declare/fetch tuples */ /* Stuff for declare/fetch tuples */
int count_allocated; /* m(re)alloced count */ int num_total_rows; /* total count of rows read in */
int count_backend_allocated;/* m(re)alloced count */
int count_keyset_allocated; /* m(re)alloced count */
int num_backend_rows; /* count of tuples kept in backend_tuples member */
int fetch_count; /* logical rows read so far */ int fetch_count; /* logical rows read so far */
int fcount; /* actual rows read in the fetch */
int currTuple; int currTuple;
int base; int base;
int num_fields; /* number of fields in the result */ int num_fields; /* number of fields in the result */
int cache_size; int cache_size;
int rowset_size; int rowset_size;
Int4 recent_processed_row_count;
QueryResultCode status; QueryResultCode status;
...@@ -77,6 +80,9 @@ struct QResultClass_ ...@@ -77,6 +80,9 @@ struct QResultClass_
UInt2 rb_alloc; /* count of allocated rollback info */ UInt2 rb_alloc; /* count of allocated rollback info */
UInt2 rb_count; /* count of rollback info */ UInt2 rb_count; /* count of rollback info */
Rollback *rollback; Rollback *rollback;
UInt2 dl_alloc; /* count of allocated deleted info */
UInt2 dl_count; /* count of deleted info */
UInt4 *deleted;
}; };
#define QR_get_fields(self) (self->fields) #define QR_get_fields(self) (self->fields)
...@@ -96,7 +102,8 @@ struct QResultClass_ ...@@ -96,7 +102,8 @@ struct QResultClass_
#define QR_get_field_type(self, fieldno_) (CI_get_oid(self->fields, fieldno_)) #define QR_get_field_type(self, fieldno_) (CI_get_oid(self->fields, fieldno_))
/* These functions are used only for manual result sets */ /* These functions are used only for manual result sets */
#define QR_get_num_tuples(self) (self->manual_tuples ? TL_get_num_tuples(self->manual_tuples) : self->fcount) #define QR_get_num_total_tuples(self) (self->manual_tuples ? TL_get_num_tuples(self->manual_tuples) : self->num_total_rows)
#define QR_get_num_backend_tuples(self) (self->manual_tuples ? TL_get_num_tuples(self->manual_tuples) : self->num_backend_rows)
#define QR_add_tuple(self, new_tuple) (TL_add_tuple(self->manual_tuples, new_tuple)) #define QR_add_tuple(self, new_tuple) (TL_add_tuple(self->manual_tuples, new_tuple))
#define QR_set_field_info(self, field_num, name, adtid, adtsize) (CI_set_field_info(self->fields, field_num, name, adtid, adtsize, -1)) #define QR_set_field_info(self, field_num, name, adtid, adtsize) (CI_set_field_info(self->fields, field_num, name, adtid, adtsize, -1))
......
...@@ -41,8 +41,6 @@ PGAPI_RowCount( ...@@ -41,8 +41,6 @@ PGAPI_RowCount(
static char *func = "PGAPI_RowCount"; static char *func = "PGAPI_RowCount";
StatementClass *stmt = (StatementClass *) hstmt; StatementClass *stmt = (StatementClass *) hstmt;
QResultClass *res; QResultClass *res;
char *msg,
*ptr;
ConnInfo *ci; ConnInfo *ci;
mylog("%s: entering...\n", func); mylog("%s: entering...\n", func);
...@@ -59,43 +57,32 @@ PGAPI_RowCount( ...@@ -59,43 +57,32 @@ PGAPI_RowCount(
return SQL_SUCCESS; return SQL_SUCCESS;
} }
if (stmt->statement_type == STMT_TYPE_SELECT)
{
if (stmt->status == STMT_FINISHED)
{
res = SC_get_Curres(stmt); res = SC_get_Curres(stmt);
if (res && pcrow) if (res && pcrow)
{ {
*pcrow = SC_is_fetchcursor(stmt) ? -1 : QR_get_num_tuples(res); if (stmt->status != STMT_FINISHED)
return SQL_SUCCESS;
}
}
}
else
{
res = SC_get_Curres(stmt);
if (res && pcrow)
{ {
msg = QR_get_command(res); stmt->errornumber = STMT_SEQUENCE_ERROR;
mylog("*** msg = '%s'\n", msg); stmt->errormsg = "Can't get row count while statement is still executing.";
trim(msg); /* get rid of trailing spaces */ SC_log_error(func, "", stmt);
ptr = strrchr(msg, ' '); return SQL_ERROR;
if (ptr) }
if (res->recent_processed_row_count >= 0)
{ {
*pcrow = atoi(ptr + 1); *pcrow = res->recent_processed_row_count;
mylog("**** PGAPI_RowCount(): THE ROWS: *pcrow = %d\n", *pcrow); mylog("**** PGAPI_RowCount(): THE ROWS: *pcrow = %d\n", *pcrow);
return SQL_SUCCESS;
} }
else else if (QR_NumResultCols(res) > 0)
{ {
*pcrow = -1; *pcrow = SC_is_fetchcursor(stmt) ? -1 : QR_get_num_total_tuples(res) - res->dl_count;
mylog("**** PGAPI_RowCount(): NO ROWS: *pcrow = %d\n", *pcrow); mylog("RowCount=%d\n", *pcrow);
}
return SQL_SUCCESS; return SQL_SUCCESS;
} }
} }
stmt->errornumber = STMT_SEQUENCE_ERROR;
SC_log_error(func, "Bad return value", stmt); SC_log_error(func, "Bad return value", stmt);
return SQL_ERROR; return SQL_ERROR;
} }
...@@ -685,6 +672,14 @@ inolog("COLUMN_TYPE=%d\n", value); ...@@ -685,6 +672,14 @@ inolog("COLUMN_TYPE=%d\n", value);
* else * else
*/ */
value = fi ? (fi->updatable ? SQL_ATTR_WRITE : SQL_ATTR_READONLY) : SQL_ATTR_READWRITE_UNKNOWN; value = fi ? (fi->updatable ? SQL_ATTR_WRITE : SQL_ATTR_READONLY) : SQL_ATTR_READWRITE_UNKNOWN;
if (SQL_ATTR_READONLY != value)
{
const char *name = fi ? fi->name : QR_get_fieldname(SC_get_Curres(stmt), col_idx);
if (stricmp(name, "oid") == 0 ||
stricmp(name, "ctid") == 0 ||
stricmp(name, "xmin") == 0)
value = SQL_ATTR_READONLY;
}
mylog("PGAPI_ColAttr: UPDATEABLE = %d\n", value); mylog("PGAPI_ColAttr: UPDATEABLE = %d\n", value);
break; break;
...@@ -714,7 +709,8 @@ inolog("COLUMN_TYPE=%d\n", value); ...@@ -714,7 +709,8 @@ inolog("COLUMN_TYPE=%d\n", value);
mylog("PGAPI_ColAttributes: col %d, octet_length = %d\n", col_idx, value); mylog("PGAPI_ColAttributes: col %d, octet_length = %d\n", col_idx, value);
break; break;
case SQL_DESC_PRECISION: /* different from SQL_COLUMN_PRECISION */ case SQL_DESC_PRECISION: /* different from SQL_COLUMN_PRECISION */
value = (fi && fi->column_size > 0) ? fi->column_size : pgtype_precision(stmt, field_type, col_idx, unknown_sizes); if (value = FI_precision(fi), value <= 0)
value = pgtype_precision(stmt, field_type, col_idx, unknown_sizes);
if (value < 0) if (value < 0)
value = 0; value = 0;
...@@ -881,7 +877,7 @@ inolog("Column 0 is type %d not of type SQL_C_BOOKMARK", fCType); ...@@ -881,7 +877,7 @@ inolog("Column 0 is type %d not of type SQL_C_BOOKMARK", fCType);
if (stmt->manual_result || !SC_is_fetchcursor(stmt)) if (stmt->manual_result || !SC_is_fetchcursor(stmt))
{ {
/* make sure we're positioned on a valid row */ /* make sure we're positioned on a valid row */
num_rows = QR_get_num_tuples(res); num_rows = QR_get_num_total_tuples(res);
if ((stmt->currTuple < 0) || if ((stmt->currTuple < 0) ||
(stmt->currTuple >= num_rows)) (stmt->currTuple >= num_rows))
{ {
...@@ -897,7 +893,12 @@ inolog("Column 0 is type %d not of type SQL_C_BOOKMARK", fCType); ...@@ -897,7 +893,12 @@ inolog("Column 0 is type %d not of type SQL_C_BOOKMARK", fCType);
if (stmt->manual_result) if (stmt->manual_result)
value = QR_get_value_manual(res, stmt->currTuple, icol); value = QR_get_value_manual(res, stmt->currTuple, icol);
else else
value = QR_get_value_backend_row(res, stmt->currTuple, icol); {
Int4 curt = res->base;
if (stmt->rowset_start >= 0)
curt += (stmt->currTuple - stmt->rowset_start);
value = QR_get_value_backend_row(res, curt, icol);
}
mylog(" value = '%s'\n", value); mylog(" value = '%s'\n", value);
} }
} }
...@@ -1046,11 +1047,92 @@ PGAPI_Fetch( ...@@ -1046,11 +1047,92 @@ PGAPI_Fetch(
} }
QR_set_rowset_size(res, 1); QR_set_rowset_size(res, 1);
QR_inc_base(res, stmt->last_fetch_count); QR_inc_base(res, stmt->last_fetch_count_include_ommitted);
return SC_fetch(stmt); return SC_fetch(stmt);
} }
#ifdef DRIVER_CURSOR_IMPLEMENT
static RETCODE SQL_API
SC_pos_reload_needed(StatementClass *stmt, UDWORD flag);
static Int4
getNthValid(QResultClass *res, Int4 sta, UWORD orientation, UInt4 nth, Int4 *nearest)
{
Int4 i, num_tuples = QR_get_num_total_tuples(res);
UInt4 count;
KeySet *keyset;
if (0 == res->dl_count)
{
if (SQL_FETCH_PRIOR == orientation)
{
if (sta + 1 >= (Int4) nth)
{
*nearest = sta + 1 - nth;
return nth;
}
*nearest = -1;
return -(Int4)(sta + 1);
}
else
{
if ((*nearest = sta + nth - 1) < num_tuples)
return nth;
*nearest = num_tuples;
return -(Int4)(num_tuples - sta);
}
}
count = 0;
if (SQL_FETCH_PRIOR == orientation)
{
for (i = sta, keyset = res->keyset + sta;
i >= 0; i--, keyset--)
{
if (0 == (keyset->status & (CURS_SELF_DELETING | CURS_SELF_DELETING | CURS_OTHER_DELETED)))
{
*nearest = i;
if (++count == nth)
return count;
}
}
*nearest = -1;
}
else
{
for (i = sta, keyset = res->keyset + sta;
i < num_tuples; i++, keyset++)
{
if (0 == (keyset->status & (CURS_SELF_DELETING | CURS_SELF_DELETING | CURS_OTHER_DELETED)))
{
*nearest = i;
if (++count == nth)
return count;
}
}
*nearest = num_tuples;
}
return -(Int4)count;
}
#endif /* DRIVER_CURSOR_IMPLEMENT */
/*
* return NO_DATA_FOUND macros
* save_rowset_start or num_tuples must be defined
*/
#define EXTFETCH_RETURN_BOF(stmt, res) \
{ \
stmt->rowset_start = -1; \
stmt->currTuple = -1; \
res->base += (stmt->rowset_start - save_rowset_start); \
return SQL_NO_DATA_FOUND; \
}
#define EXTFETCH_RETURN_EOF(stmt, res) \
{ \
stmt->rowset_start = num_tuples; \
stmt->currTuple = -1; \
res->base += (stmt->rowset_start - save_rowset_start); \
return SQL_NO_DATA_FOUND; \
}
/* This fetchs a block of data (rowset). */ /* This fetchs a block of data (rowset). */
RETCODE SQL_API RETCODE SQL_API
...@@ -1059,7 +1141,8 @@ PGAPI_ExtendedFetch( ...@@ -1059,7 +1141,8 @@ PGAPI_ExtendedFetch(
UWORD fFetchType, UWORD fFetchType,
SDWORD irow, SDWORD irow,
UDWORD FAR * pcrow, UDWORD FAR * pcrow,
UWORD FAR * rgfRowStatus) UWORD FAR * rgfRowStatus,
SQLINTEGER bookmark_offset)
{ {
static char *func = "PGAPI_ExtendedFetch"; static char *func = "PGAPI_ExtendedFetch";
StatementClass *stmt = (StatementClass *) hstmt; StatementClass *stmt = (StatementClass *) hstmt;
...@@ -1067,11 +1150,17 @@ PGAPI_ExtendedFetch( ...@@ -1067,11 +1150,17 @@ PGAPI_ExtendedFetch(
QResultClass *res; QResultClass *res;
int num_tuples, int num_tuples,
i, i,
save_rowset_size; save_rowset_size,
save_rowset_start,
progress_size;
RETCODE result; RETCODE result;
char truncated, char truncated,
error; error;
ConnInfo *ci; ConnInfo *ci;
DWORD currp;
#ifdef DRIVER_CURSOR_IMPLEMENT
UWORD pstatus;
#endif /* DRIVER_CURSOR_IMPLEMENT */
mylog("PGAPI_ExtendedFetch: stmt=%u\n", stmt); mylog("PGAPI_ExtendedFetch: stmt=%u\n", stmt);
...@@ -1082,12 +1171,13 @@ PGAPI_ExtendedFetch( ...@@ -1082,12 +1171,13 @@ PGAPI_ExtendedFetch(
} }
ci = &(SC_get_conn(stmt)->connInfo); ci = &(SC_get_conn(stmt)->connInfo);
if (SC_is_fetchcursor(stmt) && !stmt->manual_result) /* if (SC_is_fetchcursor(stmt) && !stmt->manual_result) */
if (SQL_CURSOR_FORWARD_ONLY == stmt->options.cursor_type && !stmt->manual_result)
{ {
if (fFetchType != SQL_FETCH_NEXT) if (fFetchType != SQL_FETCH_NEXT)
{ {
stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR; stmt->errornumber = STMT_FETCH_OUT_OF_RANGE;
stmt->errormsg = "Unsupported fetch type for PGAPI_ExtendedFetch with UseDeclareFetch option."; stmt->errormsg = "The fetch type for PGAPI_ExtendedFetch isn't allowed with ForwardOnly cursor.";
return SQL_ERROR; return SQL_ERROR;
} }
} }
...@@ -1149,9 +1239,10 @@ PGAPI_ExtendedFetch( ...@@ -1149,9 +1239,10 @@ PGAPI_ExtendedFetch(
if (pcrow) if (pcrow)
*pcrow = 0; *pcrow = 0;
num_tuples = QR_get_num_tuples(res); num_tuples = QR_get_num_total_tuples(res);
/* Save and discard the saved rowset size */ /* Save and discard the saved rowset size */
save_rowset_start = stmt->rowset_start;
save_rowset_size = stmt->save_rowset_size; save_rowset_size = stmt->save_rowset_size;
stmt->save_rowset_size = -1; stmt->save_rowset_size = -1;
...@@ -1165,11 +1256,29 @@ PGAPI_ExtendedFetch( ...@@ -1165,11 +1256,29 @@ PGAPI_ExtendedFetch(
* SQL_FETCH_FIRST. * SQL_FETCH_FIRST.
*/ */
progress_size = (save_rowset_size > 0 ? save_rowset_size : opts->rowset_size);
if (stmt->rowset_start < 0) if (stmt->rowset_start < 0)
stmt->rowset_start = 0; stmt->rowset_start = 0;
#ifdef DRIVER_CURSOR_IMPLEMENT
else if (res->keyset)
{
if (stmt->last_fetch_count <= progress_size)
{
stmt->rowset_start += stmt->last_fetch_count_include_ommitted;
progress_size -= stmt->last_fetch_count;
}
if (progress_size > 0 &&
getNthValid(res, stmt->rowset_start,
SQL_FETCH_NEXT, progress_size + 1,
&stmt->rowset_start) <= 0)
{
EXTFETCH_RETURN_EOF(stmt, res)
}
}
#endif /* DRIVER_CURSOR_IMPLEMENT */
else else
stmt->rowset_start += (save_rowset_size > 0 ? save_rowset_size : opts->rowset_size); stmt->rowset_start += progress_size;
mylog("SQL_FETCH_NEXT: num_tuples=%d, currtuple=%d\n", num_tuples, stmt->currTuple); mylog("SQL_FETCH_NEXT: num_tuples=%d, currtuple=%d\n", num_tuples, stmt->currTuple);
break; break;
...@@ -1182,6 +1291,10 @@ PGAPI_ExtendedFetch( ...@@ -1182,6 +1291,10 @@ PGAPI_ExtendedFetch(
* RESULT SET, then this should be equivalent to * RESULT SET, then this should be equivalent to
* SQL_FETCH_LAST. * SQL_FETCH_LAST.
*/ */
if (stmt->rowset_start <= 0)
{
EXTFETCH_RETURN_BOF(stmt, res)
}
if (stmt->rowset_start >= num_tuples) if (stmt->rowset_start >= num_tuples)
{ {
if (opts->rowset_size > num_tuples) if (opts->rowset_size > num_tuples)
...@@ -1194,12 +1307,27 @@ PGAPI_ExtendedFetch( ...@@ -1194,12 +1307,27 @@ PGAPI_ExtendedFetch(
} }
else else
{ {
#ifdef DRIVER_CURSOR_IMPLEMENT
if (i = getNthValid(res, stmt->rowset_start - 1, SQL_FETCH_PRIOR, opts->rowset_size, &stmt->rowset_start), i < -1)
{
stmt->errormsg = "fetch prior and before the beggining";
stmt->errornumber = STMT_POS_BEFORE_RECORDSET;
stmt->rowset_start = 0;
}
else if (i <= 0)
{
EXTFETCH_RETURN_BOF(stmt, res)
}
#else
if (stmt->rowset_start < opts->rowset_size) if (stmt->rowset_start < opts->rowset_size)
{ {
stmt->errormsg = "fetch prior and before the beggining"; stmt->errormsg = "fetch prior and before the beggining";
stmt->errornumber = STMT_POS_BEFORE_RECORDSET; stmt->errornumber = STMT_POS_BEFORE_RECORDSET;
stmt->rowset_start = 0;
} }
else
stmt->rowset_start -= opts->rowset_size; stmt->rowset_start -= opts->rowset_size;
#endif /* DRIVER_CURSOR_IMPLEMENT */
} }
break; break;
...@@ -1221,16 +1349,32 @@ PGAPI_ExtendedFetch( ...@@ -1221,16 +1349,32 @@ PGAPI_ExtendedFetch(
/* Position before result set, but dont fetch anything */ /* Position before result set, but dont fetch anything */
if (irow == 0) if (irow == 0)
{ {
stmt->rowset_start = -1; EXTFETCH_RETURN_BOF(stmt, res)
stmt->currTuple = -1;
return SQL_NO_DATA_FOUND;
} }
/* Position before the desired row */ /* Position before the desired row */
else if (irow > 0) else if (irow > 0)
#ifdef DRIVER_CURSOR_IMPLEMENT
{
if (getNthValid(res, 0, SQL_FETCH_NEXT, irow, &stmt->rowset_start) <= 0)
{
EXTFETCH_RETURN_EOF(stmt, res)
}
}
#else
stmt->rowset_start = irow - 1; stmt->rowset_start = irow - 1;
#endif /* DRIVER_CURSOR_IMPLEMENT */
/* Position with respect to the end of the result set */ /* Position with respect to the end of the result set */
else else
#ifdef DRIVER_CURSOR_IMPLEMENT
{
if (getNthValid(res, num_tuples - 1, SQL_FETCH_PRIOR, -irow, &stmt->rowset_start) <= 0)
{
EXTFETCH_RETURN_BOF(stmt, res)
}
}
#else
stmt->rowset_start = num_tuples + irow; stmt->rowset_start = num_tuples + irow;
#endif /* DRIVER_CURSOR_IMPLEMENT */
break; break;
case SQL_FETCH_RELATIVE: case SQL_FETCH_RELATIVE:
...@@ -1242,11 +1386,43 @@ PGAPI_ExtendedFetch( ...@@ -1242,11 +1386,43 @@ PGAPI_ExtendedFetch(
if (irow == 0) if (irow == 0)
break; break;
#ifdef DRIVER_CURSOR_IMPLEMENT
if (irow > 0)
{
if (getNthValid(res, stmt->rowset_start + 1, SQL_FETCH_NEXT, irow, &stmt->rowset_start) <= 0)
{
EXTFETCH_RETURN_EOF(stmt, res)
}
}
else
{
if (getNthValid(res, stmt->rowset_start - 1, SQL_FETCH_PRIOR, -irow, &stmt->rowset_start) <= 0)
{
EXTFETCH_RETURN_BOF(stmt, res)
}
}
#else
stmt->rowset_start += irow; stmt->rowset_start += irow;
#endif /* DRIVER_CURSOR_IMPLEMENT */
break; break;
case SQL_FETCH_BOOKMARK: case SQL_FETCH_BOOKMARK:
stmt->rowset_start = irow - 1; #ifdef DRIVER_CURSOR_IMPLEMENT
if (bookmark_offset > 0)
{
if (getNthValid(res, irow - 1, SQL_FETCH_NEXT, bookmark_offset + 1, &stmt->rowset_start) <= 0)
{
EXTFETCH_RETURN_EOF(stmt, res)
}
}
else if (getNthValid(res, irow - 1, SQL_FETCH_PRIOR, 1 - bookmark_offset, &stmt->rowset_start) <= 0)
{
stmt->currTuple = -1;
EXTFETCH_RETURN_BOF(stmt, res)
}
#else
stmt->rowset_start = irow + bookmark_offset - 1;
#endif /* DRIVER_CURSOR_IMPLEMENT */
break; break;
default: default:
...@@ -1272,8 +1448,7 @@ PGAPI_ExtendedFetch( ...@@ -1272,8 +1448,7 @@ PGAPI_ExtendedFetch(
/* If *new* rowset is after the result_set, return no data found */ /* If *new* rowset is after the result_set, return no data found */
if (stmt->rowset_start >= num_tuples) if (stmt->rowset_start >= num_tuples)
{ {
stmt->rowset_start = num_tuples; EXTFETCH_RETURN_EOF(stmt, res)
return SQL_NO_DATA_FOUND;
} }
} }
...@@ -1282,8 +1457,7 @@ PGAPI_ExtendedFetch( ...@@ -1282,8 +1457,7 @@ PGAPI_ExtendedFetch(
{ {
if (stmt->rowset_start + opts->rowset_size <= 0) if (stmt->rowset_start + opts->rowset_size <= 0)
{ {
stmt->rowset_start = -1; EXTFETCH_RETURN_BOF(stmt, res)
return SQL_NO_DATA_FOUND;
} }
else else
{ /* overlap with beginning of result set, { /* overlap with beginning of result set,
...@@ -1298,19 +1472,30 @@ PGAPI_ExtendedFetch( ...@@ -1298,19 +1472,30 @@ PGAPI_ExtendedFetch(
/* increment the base row in the tuple cache */ /* increment the base row in the tuple cache */
QR_set_rowset_size(res, opts->rowset_size); QR_set_rowset_size(res, opts->rowset_size);
if (SC_is_fetchcursor(stmt)) if (SC_is_fetchcursor(stmt))
QR_inc_base(res, stmt->last_fetch_count); QR_inc_base(res, stmt->last_fetch_count_include_ommitted);
else else
res->base = stmt->rowset_start; res->base = stmt->rowset_start;
#ifdef DRIVER_CURSOR_IMPLEMENT
if (res->keyset)
SC_pos_reload_needed(stmt, SQL_CURSOR_KEYSET_DRIVEN == stmt->options.cursor_type);
#endif /* DRIVER_CURSOR_IMPLEMENT */
/* Physical Row advancement occurs for each row fetched below */ /* Physical Row advancement occurs for each row fetched below */
mylog("PGAPI_ExtendedFetch: new currTuple = %d\n", stmt->currTuple); mylog("PGAPI_ExtendedFetch: new currTuple = %d\n", stmt->currTuple);
truncated = error = FALSE; truncated = error = FALSE;
for (i = 0; i < opts->rowset_size; i++) for (i = 0, currp = stmt->rowset_start; i < opts->rowset_size; currp++)
{ {
stmt->bind_row = i; /* set the binding location */ stmt->bind_row = i; /* set the binding location */
result = SC_fetch(stmt); result = SC_fetch(stmt);
#ifdef DRIVER_CURSOR_IMPLEMENT
if (SQL_SUCCESS_WITH_INFO == result && 0 == stmt->last_fetch_count && res->keyset)
{
res->keyset[stmt->currTuple].status &= ~CURS_IN_ROWSET;
continue;
}
#endif /* DRIVER_CURSOR_IMPLEMENT */
/* Determine Function status */ /* Determine Function status */
if (result == SQL_NO_DATA_FOUND) if (result == SQL_NO_DATA_FOUND)
...@@ -1328,26 +1513,28 @@ PGAPI_ExtendedFetch( ...@@ -1328,26 +1513,28 @@ PGAPI_ExtendedFetch(
#ifdef DRIVER_CURSOR_IMPLEMENT #ifdef DRIVER_CURSOR_IMPLEMENT
else if (res->keyset) else if (res->keyset)
{ {
DWORD currp = stmt->rowset_start + i; pstatus = (res->keyset[currp].status & KEYSET_INFO_PUBLIC);
UWORD pstatus = res->keyset[currp].status & KEYSET_INFO_PUBLIC; if (pstatus != 0 && pstatus != SQL_ROW_ADDED)
if (pstatus != 0)
{ {
rgfRowStatus[i] = pstatus; rgfRowStatus[i] = pstatus;
/* refresh the status */
if (SQL_ROW_DELETED != pstatus)
res->keyset[currp].status &= (~KEYSET_INFO_PUBLIC);
} }
else else
rgfRowStatus[i] = SQL_ROW_SUCCESS; rgfRowStatus[i] = SQL_ROW_SUCCESS;
res->keyset[currp].status |= CURS_IN_ROWSET;
/* refresh the status */
/* if (SQL_ROW_DELETED != pstatus) */
res->keyset[currp].status &= (~KEYSET_INFO_PUBLIC);
} }
#endif /* DRIVER_CURSOR_IMPLEMENT */ #endif /* DRIVER_CURSOR_IMPLEMENT */
else else
*(rgfRowStatus + i) = SQL_ROW_SUCCESS; *(rgfRowStatus + i) = SQL_ROW_SUCCESS;
} }
i++;
} }
/* Save the fetch count for SQLSetPos */ /* Save the fetch count for SQLSetPos */
stmt->last_fetch_count = i; stmt->last_fetch_count = i;
stmt->last_fetch_count_include_ommitted = currp - stmt->rowset_start;
/* Reset next binding row */ /* Reset next binding row */
stmt->bind_row = 0; stmt->bind_row = 0;
...@@ -1393,8 +1580,11 @@ PGAPI_MoreResults( ...@@ -1393,8 +1580,11 @@ PGAPI_MoreResults(
mylog("%s: entering...\n", func); mylog("%s: entering...\n", func);
if (stmt && (res = SC_get_Curres(stmt))) if (stmt && (res = SC_get_Curres(stmt)))
SC_set_Curres(stmt, res->next); SC_set_Curres(stmt, res->next);
if (SC_get_Curres(stmt)) if (res = SC_get_Curres(stmt), res)
{
stmt->diag_row_count = res->recent_processed_row_count;
return SQL_SUCCESS; return SQL_SUCCESS;
}
return SQL_NO_DATA_FOUND; return SQL_NO_DATA_FOUND;
} }
...@@ -1424,6 +1614,7 @@ static void KeySetSet(const TupleField *tuple, int num_fields, KeySet *keyset) ...@@ -1424,6 +1614,7 @@ 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 DiscardDeleted(QResultClass *res, int index);
static void AddRollback(ConnectionClass *conn, QResultClass *res, int index, const KeySet *keyset) static void AddRollback(ConnectionClass *conn, QResultClass *res, int index, const KeySet *keyset)
{ {
Rollback *rollback; Rollback *rollback;
...@@ -1479,6 +1670,8 @@ static void DiscardRollback(QResultClass *res) ...@@ -1479,6 +1670,8 @@ static void DiscardRollback(QResultClass *res)
{ {
index = rollback[i].index; index = rollback[i].index;
status = keyset[index].status; status = keyset[index].status;
if (0 != (status & CURS_SELF_DELETING))
DiscardDeleted(res, index);
keyset[index].status &= ~(CURS_SELF_DELETING | CURS_SELF_UPDATING | CURS_SELF_ADDING); 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); keyset[index].status |= ((status & (CURS_SELF_DELETING | CURS_SELF_UPDATING | CURS_SELF_ADDING)) << 3);
} }
...@@ -1487,9 +1680,9 @@ static void DiscardRollback(QResultClass *res) ...@@ -1487,9 +1680,9 @@ static void DiscardRollback(QResultClass *res)
res->rb_count = res->rb_alloc = 0; res->rb_count = res->rb_alloc = 0;
} }
static void UndoRollback(QResultClass *res) static void UndoRollback(StatementClass *stmt, QResultClass *res)
{ {
int i, index; int i, index, ridx;
UWORD status; UWORD status;
Rollback *rollback; Rollback *rollback;
KeySet *keyset; KeySet *keyset;
...@@ -1502,16 +1695,34 @@ static void UndoRollback(QResultClass *res) ...@@ -1502,16 +1695,34 @@ static void UndoRollback(QResultClass *res)
{ {
index = rollback[i].index; index = rollback[i].index;
status = keyset[index].status; status = keyset[index].status;
if ((status & CURS_SELF_ADDING) != 0) if (0 != (status & CURS_SELF_ADDING))
{
ridx = index - stmt->rowset_start + res->base;
if (ridx >=0 && ridx < res->num_backend_rows)
{
TupleField *tuple = res->backend_tuples + res->num_fields * ridx;
int j;
for (j = 0; j < res->num_fields; j++, tuple++)
{
if (tuple->len > 0 && tuple->value)
{ {
if (index < res->fcount) free(tuple->value);
res->fcount = index; tuple->value = NULL;
}
tuple->len = 0;
}
}
if (index < res->num_total_rows)
res->num_total_rows = index;
} }
else else
{ {
if (0 != (status & CURS_SELF_DELETING))
DiscardDeleted(res, index);
if (0 != (keyset[index].status & CURS_SELF_UPDATING))
keyset[index].status |= CURS_NEEDS_REREAD;
keyset[index].status &= ~(CURS_SELF_DELETING | CURS_SELF_UPDATING | CURS_SELF_ADDING | KEYSET_INFO_PUBLIC); 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); free(rollback);
...@@ -1532,13 +1743,66 @@ void ProcessRollback(ConnectionClass *conn, BOOL undo) ...@@ -1532,13 +1743,66 @@ void ProcessRollback(ConnectionClass *conn, BOOL undo)
for (res = SC_get_Result(stmt); res; res = res->next) for (res = SC_get_Result(stmt); res; res = res->next)
{ {
if (undo) if (undo)
UndoRollback(res); UndoRollback(stmt, res);
else else
DiscardRollback(res); DiscardRollback(res);
} }
} }
} }
static void AddDeleted(QResultClass *res, int index)
{
int i;
UInt4 *deleted;
if (!res->deleted)
{
res->dl_count = 0;
res->dl_alloc = 10;
deleted = res->deleted = malloc(sizeof(UInt4) * res->dl_alloc);
}
else
{
if (res->dl_count >= res->dl_alloc)
{
res->dl_alloc *= 2;
if (deleted = realloc(res->deleted, sizeof(UInt4) * res->dl_alloc), !deleted)
{
res->dl_alloc = res->dl_count = 0;
return;
}
res->deleted = deleted;
}
for (i = 0, deleted = res->deleted; i < res->dl_count; i++, deleted++)
{
if (index < (int) *deleted)
break;
}
memmove(deleted + 1, deleted, sizeof(UInt4) * (res->dl_count - i));
}
*deleted = index;
res->dl_count++;
}
static void DiscardDeleted(QResultClass *res, int index)
{
int i;
UInt4 *deleted;
if (!res->deleted)
return;
for (i = 0, deleted = res->deleted; i < res->dl_count; i++, deleted++)
{
if (index == (int) *deleted)
break;
}
if (i >= res->dl_count)
return;
memmove(deleted, deleted + 1, sizeof(UInt4) * (res->dl_count - i - 1));
res->dl_count--;
}
#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 *
...@@ -1555,7 +1819,14 @@ positioned_load(StatementClass *stmt, UInt4 flag, UInt4 oid, const char *tidval) ...@@ -1555,7 +1819,14 @@ positioned_load(StatementClass *stmt, UInt4 flag, UInt4 oid, const char *tidval)
len += 100; len += 100;
selstr = malloc(len); selstr = malloc(len);
if (latest) if (latest)
{
if (stmt->ti[0]->schema[0])
sprintf(selstr, "%s where ctid = currtid2('\"%s\".\"%s\"', '%s') and oid = %u",
stmt->load_statement, stmt->ti[0]->schema,
stmt->ti[0]->name, tidval, oid);
else
sprintf(selstr, "%s where ctid = currtid2('%s', '%s') and oid = %u", stmt->load_statement, stmt->ti[0]->name, tidval, oid); sprintf(selstr, "%s where ctid = currtid2('%s', '%s') and oid = %u", stmt->load_statement, stmt->ti[0]->name, tidval, oid);
}
else else
sprintf(selstr, "%s where ctid = '%s' and oid = %u", stmt->load_statement, tidval, oid); sprintf(selstr, "%s where ctid = '%s' and oid = %u", stmt->load_statement, tidval, oid);
} }
...@@ -1579,11 +1850,12 @@ positioned_load(StatementClass *stmt, UInt4 flag, UInt4 oid, const char *tidval) ...@@ -1579,11 +1850,12 @@ positioned_load(StatementClass *stmt, UInt4 flag, UInt4 oid, const char *tidval)
} }
RETCODE SQL_API RETCODE SQL_API
SC_pos_reload(StatementClass *stmt, UWORD irow, UDWORD global_ridx, UWORD *count) SC_pos_reload(StatementClass *stmt, UDWORD global_ridx, UWORD *count, BOOL logChanges)
{ {
int i, int i,
res_cols; res_cols;
UWORD rcnt, offset; UWORD rcnt, offset;
Int4 res_ridx;
UInt4 oid, blocknum; UInt4 oid, blocknum;
QResultClass *res, QResultClass *res,
*qres; *qres;
...@@ -1604,7 +1876,7 @@ SC_pos_reload(StatementClass *stmt, UWORD irow, UDWORD global_ridx, UWORD *count ...@@ -1604,7 +1876,7 @@ SC_pos_reload(StatementClass *stmt, UWORD irow, UDWORD global_ridx, UWORD *count
stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY; stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
return SQL_ERROR; return SQL_ERROR;
} }
global_ridx = irow + stmt->rowset_start; res_ridx = global_ridx - stmt->rowset_start + res->base;
if (!(oid = getOid(res, global_ridx))) if (!(oid = getOid(res, global_ridx)))
return SQL_SUCCESS_WITH_INFO; return SQL_SUCCESS_WITH_INFO;
getTid(res, global_ridx, &blocknum, &offset); getTid(res, global_ridx, &blocknum, &offset);
...@@ -1613,9 +1885,12 @@ SC_pos_reload(StatementClass *stmt, UWORD irow, UDWORD global_ridx, UWORD *count ...@@ -1613,9 +1885,12 @@ SC_pos_reload(StatementClass *stmt, UWORD irow, UDWORD global_ridx, UWORD *count
if (qres = positioned_load(stmt, LATEST_TUPLE_LOAD, oid, tidval), qres) if (qres = positioned_load(stmt, LATEST_TUPLE_LOAD, oid, tidval), qres)
{ {
TupleField *tupleo, *tuplen; TupleField *tupleo, *tuplen;
ConnectionClass *conn = SC_get_conn(stmt);
rcnt = QR_get_num_tuples(qres); rcnt = QR_get_num_backend_tuples(qres);
tupleo = res->backend_tuples + res->num_fields * global_ridx; tupleo = res->backend_tuples + res->num_fields * res_ridx;
if (logChanges && CC_is_in_trans(conn))
AddRollback(conn, res, global_ridx, res->keyset);
if (rcnt == 1) if (rcnt == 1)
{ {
int effective_fields = res_cols; int effective_fields = res_cols;
...@@ -1647,8 +1922,6 @@ SC_pos_reload(StatementClass *stmt, UWORD irow, UDWORD global_ridx, UWORD *count ...@@ -1647,8 +1922,6 @@ 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].blocknum = 0;
res->keyset[global_ridx].offset = 0;
res->keyset[global_ridx].status |= SQL_ROW_DELETED; res->keyset[global_ridx].status |= SQL_ROW_DELETED;
} }
} }
...@@ -1661,6 +1934,162 @@ SC_pos_reload(StatementClass *stmt, UWORD irow, UDWORD global_ridx, UWORD *count ...@@ -1661,6 +1934,162 @@ SC_pos_reload(StatementClass *stmt, UWORD irow, UDWORD global_ridx, UWORD *count
return ret; return ret;
} }
static RETCODE SQL_API
SC_pos_reload_needed(StatementClass *stmt, UDWORD flag)
{
Int4 i, limitrow;
UWORD qcount;
QResultClass *res;
IRDFields *irdflds = SC_get_IRD(stmt);
RETCODE ret = SQL_ERROR;
ConnectionClass *conn = SC_get_conn(stmt);
UInt4 oid, blocknum, lodlen;
char *qval = NULL, *sval;
Int4 rowc;
UWORD offset;
BOOL create_from_scratch = (0 != flag);
mylog("SC_pos_reload_needed\n");
if (!(res = SC_get_Curres(stmt)))
return SQL_ERROR;
if (!stmt->ti)
parse_statement(stmt); /* not preferable */
if (!stmt->updatable)
{
stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
return SQL_ERROR;
}
limitrow = stmt->rowset_start + res->rowset_size;
if (limitrow > res->num_total_rows)
limitrow = res->num_total_rows;
if (create_from_scratch)
{
int flds_cnt = res->num_backend_rows * res->num_fields,
brows;
for (i = 0; i < flds_cnt; i++)
{
if (res->backend_tuples[i].value)
free(res->backend_tuples[i].value);
}
brows = limitrow - stmt->rowset_start;
if (brows > res->count_backend_allocated)
{
res->backend_tuples = realloc(res->backend_tuples, sizeof(TupleField) * res->num_fields * brows);
res->count_backend_allocated = brows;
}
if (brows > 0)
memset(res->backend_tuples, 0, sizeof(TupleField) * res->num_fields * brows);
res->num_backend_rows = brows;
res->base = 0;
for (i = stmt->rowset_start; i < limitrow; i++)
{
if (0 == (res->keyset[i].status & (CURS_SELF_DELETING | CURS_SELF_DELETED | CURS_OTHER_DELETED)))
res->keyset[i].status |= CURS_NEEDS_REREAD;
}
}
for (i = stmt->rowset_start, rowc = 0;; i++)
{
if (i >= limitrow)
{
if (!rowc)
break;
rowc = -1; /* end of loop */
}
if (rowc < 0 || rowc >= 10)
{
QResultClass *qres;
strcpy(sval, ")");
qres = CC_send_query(conn, qval, NULL, CLEAR_RESULT_ON_ABORT | CREATE_KEYSET);
if (qres)
{
int j, k, l, m;
TupleField *tuple, *tuplew;
for (j = 0; j < qres->num_total_rows; j++)
{
oid = getOid(qres, j);
getTid(qres, j, &blocknum, &offset);
for (k = stmt->rowset_start; k < limitrow; k++)
{
if (oid == getOid(res, k))
{
l = k - stmt->rowset_start + res->base;
tuple = res->backend_tuples + res->num_fields * l;
tuplew = qres->backend_tuples + qres->num_fields * j;
for (m = 0; m < res->num_fields; m++, tuple++, tuplew++)
{
if (tuple->len > 0 && tuple->value)
free(tuple->value);
tuple->value = tuplew->value;
tuple->len = tuplew->len;
tuplew->value = NULL;
tuplew->len = 0;
}
res->keyset[k].status &= ~CURS_NEEDS_REREAD;
break;
}
}
}
QR_Destructor(qres);
}
if (rowc < 0)
break;
rowc = 0;
}
if (!rowc)
{
if (!qval)
{
UInt4 allen;
lodlen = strlen(stmt->load_statement);
allen = lodlen + 20 + 23 * 10;
qval = malloc(allen);
}
memcpy(qval, stmt->load_statement, lodlen);
sval = qval + lodlen;
sval[0]= '\0';
strcpy(sval, " where ctid in (");
sval = strchr(sval, '\0');
}
if (0 != (res->keyset[i].status & CURS_NEEDS_REREAD))
{
getTid(res, i, &blocknum, &offset);
if (rowc)
sprintf(sval, ", '(%u, %u)'", blocknum, offset);
else
sprintf(sval, "'(%u, %u)'", blocknum, offset);
sval = strchr(sval, '\0');
rowc++;
}
}
if (qval)
free(qval);
else
return SQL_SUCCESS;
for (i = stmt->rowset_start; i < limitrow; i++)
{
if (0 != (res->keyset[i].status & CURS_NEEDS_REREAD))
{
ret = SC_pos_reload(stmt, i, &qcount, FALSE);
if (SQL_ERROR == ret)
{
break;
}
if (SQL_ROW_DELETED == (res->keyset[i].status & KEYSET_INFO_PUBLIC))
{
res->keyset[i].status |= CURS_OTHER_DELETED;
}
res->keyset[i].status &= ~CURS_NEEDS_REREAD;
}
}
return ret;
}
RETCODE SQL_API RETCODE SQL_API
SC_pos_newload(StatementClass *stmt, UInt4 oid, BOOL tidRef) SC_pos_newload(StatementClass *stmt, UInt4 oid, BOOL tidRef)
{ {
...@@ -1681,22 +2110,36 @@ SC_pos_newload(StatementClass *stmt, UInt4 oid, BOOL tidRef) ...@@ -1681,22 +2110,36 @@ SC_pos_newload(StatementClass *stmt, UInt4 oid, BOOL tidRef)
if (qres = positioned_load(stmt, tidRef ? USE_INSERTED_TID : 0, oid, NULL), qres) if (qres = positioned_load(stmt, tidRef ? USE_INSERTED_TID : 0, oid, NULL), qres)
{ {
TupleField *tupleo, *tuplen; TupleField *tupleo, *tuplen;
int count = QR_get_num_tuples(qres); int count = QR_get_num_backend_tuples(qres);
QR_set_position(qres, 0); QR_set_position(qres, 0);
if (count == 1) if (count == 1)
{ {
int effective_fields = res->num_fields; int effective_fields = res->num_fields;
int tuple_size;
tuplen = qres->tupleField; tuplen = qres->tupleField;
if (res->fcount >= res->count_allocated) if (res->haskeyset &&
res->num_total_rows >= res->count_keyset_allocated)
{ {
int tuple_size;
if (!res->count_allocated) if (!res->count_keyset_allocated)
tuple_size = TUPLE_MALLOC_INC; tuple_size = TUPLE_MALLOC_INC;
else else
tuple_size = res->count_allocated * 2; tuple_size = res->count_keyset_allocated * 2;
res->keyset = (KeySet *) realloc(res->keyset, sizeof(KeySet) * tuple_size);
res->count_keyset_allocated = tuple_size;
}
KeySetSet(tuplen, qres->num_fields, res->keyset + res->num_total_rows);
if (res->num_total_rows == res->num_backend_rows - res->base + stmt->rowset_start)
{
if (res->num_backend_rows >= res->count_backend_allocated)
{
if (!res->count_backend_allocated)
tuple_size = TUPLE_MALLOC_INC;
else
tuple_size = res->count_backend_allocated * 2;
res->backend_tuples = (TupleField *) realloc( res->backend_tuples = (TupleField *) realloc(
res->backend_tuples, res->backend_tuples,
res->num_fields * sizeof(TupleField) * tuple_size); res->num_fields * sizeof(TupleField) * tuple_size);
...@@ -1707,12 +2150,9 @@ SC_pos_newload(StatementClass *stmt, UInt4 oid, BOOL tidRef) ...@@ -1707,12 +2150,9 @@ SC_pos_newload(StatementClass *stmt, UInt4 oid, BOOL tidRef)
QR_Destructor(qres); QR_Destructor(qres);
return SQL_ERROR; return SQL_ERROR;
} }
if (res->haskeyset) res->count_backend_allocated = tuple_size;
res->keyset = (KeySet *) realloc(res->keyset, sizeof(KeySet) * tuple_size);
res->count_allocated = tuple_size;
} }
tupleo = res->backend_tuples + res->num_fields * res->fcount; tupleo = res->backend_tuples + res->num_fields * res->num_backend_rows;
KeySetSet(tuplen, qres->num_fields, res->keyset + res->fcount);
for (i = 0; i < effective_fields; i++) for (i = 0; i < effective_fields; i++)
{ {
tupleo[i].len = tuplen[i].len; tupleo[i].len = tuplen[i].len;
...@@ -1725,7 +2165,9 @@ SC_pos_newload(StatementClass *stmt, UInt4 oid, BOOL tidRef) ...@@ -1725,7 +2165,9 @@ SC_pos_newload(StatementClass *stmt, UInt4 oid, BOOL tidRef)
tupleo[i].len = 0; tupleo[i].len = 0;
tupleo[i].value = NULL; tupleo[i].value = NULL;
} }
res->fcount++; res->num_backend_rows++;
}
res->num_total_rows++;
ret = SQL_SUCCESS; ret = SQL_SUCCESS;
} }
else if (0 == count) else if (0 == count)
...@@ -1737,7 +2179,7 @@ SC_pos_newload(StatementClass *stmt, UInt4 oid, BOOL tidRef) ...@@ -1737,7 +2179,7 @@ SC_pos_newload(StatementClass *stmt, UInt4 oid, BOOL tidRef)
ret = SQL_ERROR; ret = SQL_ERROR;
} }
QR_Destructor(qres); QR_Destructor(qres);
/* stmt->currTuple = stmt->rowset_start + irow; */ /* stmt->currTuple = stmt->rowset_start + ridx; */
} }
return ret; return ret;
} }
...@@ -1754,14 +2196,14 @@ irow_update(RETCODE ret, StatementClass *stmt, StatementClass *ustmt, UWORD irow ...@@ -1754,14 +2196,14 @@ irow_update(RETCODE ret, StatementClass *stmt, StatementClass *ustmt, UWORD irow
sscanf(cmdstr, "UPDATE %d", &updcnt) == 1) sscanf(cmdstr, "UPDATE %d", &updcnt) == 1)
{ {
if (updcnt == 1) if (updcnt == 1)
SC_pos_reload(stmt, irow, global_ridx, (UWORD *) 0); ret = SC_pos_reload(stmt, global_ridx, (UWORD *) 0, TRUE);
else if (updcnt == 0) else if (updcnt == 0)
{ {
stmt->errornumber = STMT_ROW_VERSION_CHANGED; stmt->errornumber = STMT_ROW_VERSION_CHANGED;
stmt->errormsg = "the content was changed before updation"; stmt->errormsg = "the content was changed before updation";
ret = SQL_ERROR; ret = SQL_ERROR;
if (stmt->options.cursor_type == SQL_CURSOR_KEYSET_DRIVEN) if (stmt->options.cursor_type == SQL_CURSOR_KEYSET_DRIVEN)
SC_pos_reload(stmt, irow, global_ridx, (UWORD *) 0); SC_pos_reload(stmt, global_ridx, (UWORD *) 0, FALSE);
} }
else else
ret = SQL_ERROR; ret = SQL_ERROR;
...@@ -1812,6 +2254,9 @@ SC_pos_update(StatementClass *stmt, ...@@ -1812,6 +2254,9 @@ SC_pos_update(StatementClass *stmt,
} }
getTid(res, global_ridx, &blocknum, &pgoffset); getTid(res, global_ridx, &blocknum, &pgoffset);
if (stmt->ti[0]->schema[0])
sprintf(updstr, "update \"%s\".\"%s\" set", stmt->ti[0]->schema, stmt->ti[0]->name);
else
sprintf(updstr, "update \"%s\" set", stmt->ti[0]->name); sprintf(updstr, "update \"%s\" set", stmt->ti[0]->name);
num_cols = irdflds->nfields; num_cols = irdflds->nfields;
offset = opts->row_offset_ptr ? *opts->row_offset_ptr : 0; offset = opts->row_offset_ptr ? *opts->row_offset_ptr : 0;
...@@ -1842,8 +2287,10 @@ SC_pos_update(StatementClass *stmt, ...@@ -1842,8 +2287,10 @@ SC_pos_update(StatementClass *stmt,
HSTMT hstmt; HSTMT hstmt;
int j; int j;
int res_cols = QR_NumResultCols(res); int res_cols = QR_NumResultCols(res);
ConnInfo *ci = &(conn->connInfo);
StatementClass *qstmt; StatementClass *qstmt;
APDFields *apdopts; APDFields *apdopts;
Int4 fieldtype = 0;
/*sprintf(updstr, "%s where ctid = '%s' and oid = %s", updstr, /*sprintf(updstr, "%s where ctid = '%s' and oid = %s", updstr,
tidval, oidval);*/ tidval, oidval);*/
...@@ -1868,10 +2315,11 @@ SC_pos_update(StatementClass *stmt, ...@@ -1868,10 +2315,11 @@ SC_pos_update(StatementClass *stmt,
mylog("%d used=%d\n", i, *used); mylog("%d used=%d\n", i, *used);
if (*used != SQL_IGNORE && fi[i]->updatable) if (*used != SQL_IGNORE && fi[i]->updatable)
{ {
fieldtype = QR_get_field_type(res, i);
PGAPI_BindParameter(hstmt, (SQLUSMALLINT) ++j, PGAPI_BindParameter(hstmt, (SQLUSMALLINT) ++j,
SQL_PARAM_INPUT, bindings[i].returntype, SQL_PARAM_INPUT, bindings[i].returntype,
pgtype_to_concise_type(stmt, QR_get_field_type(res, i)), pgtype_to_concise_type(stmt, fieldtype),
QR_get_fieldsize(res, i), fi[i]->column_size > 0 ? fi[i]->column_size : pgtype_column_size(stmt, fieldtype, i, ci->drivers.unknown_sizes),
(SQLSMALLINT) fi[i]->decimal_digits, (SQLSMALLINT) fi[i]->decimal_digits,
bindings[i].buffer, bindings[i].buffer,
bindings[i].buflen, bindings[i].buflen,
...@@ -1905,7 +2353,6 @@ SC_pos_update(StatementClass *stmt, ...@@ -1905,7 +2353,6 @@ SC_pos_update(StatementClass *stmt,
{ {
if (CC_is_in_trans(conn)) 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
...@@ -1939,7 +2386,7 @@ SC_pos_delete(StatementClass *stmt, ...@@ -1939,7 +2386,7 @@ SC_pos_delete(StatementClass *stmt,
BindInfoClass *bindings = opts->bindings; BindInfoClass *bindings = opts->bindings;
char dltstr[4096]; char dltstr[4096];
RETCODE ret; RETCODE ret;
UInt4 oid, blocknum; UInt4 oid, blocknum, qflag;
mylog("POS DELETE ti=%x\n", stmt->ti); mylog("POS DELETE ti=%x\n", stmt->ti);
if (!(res = SC_get_Curres(stmt))) if (!(res = SC_get_Curres(stmt)))
...@@ -1958,11 +2405,19 @@ SC_pos_delete(StatementClass *stmt, ...@@ -1958,11 +2405,19 @@ SC_pos_delete(StatementClass *stmt,
} }
getTid(res, global_ridx, &blocknum, &offset); getTid(res, global_ridx, &blocknum, &offset);
/*sprintf(dltstr, "delete from \"%s\" where ctid = '%s' and oid = %s",*/ /*sprintf(dltstr, "delete from \"%s\" where ctid = '%s' and oid = %s",*/
if (stmt->ti[0]->schema[0])
sprintf(dltstr, "delete from \"%s\".\"%s\" where ctid = '(%u, %u)' and oid = %u",
stmt->ti[0]->schema, stmt->ti[0]->name, blocknum, offset, oid);
else
sprintf(dltstr, "delete from \"%s\" where ctid = '(%u, %u)' and oid = %u", sprintf(dltstr, "delete from \"%s\" where ctid = '(%u, %u)' and oid = %u",
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(conn, dltstr, NULL, CLEAR_RESULT_ON_ABORT); qflag = CLEAR_RESULT_ON_ABORT;
if (!stmt->internal && !CC_is_in_trans(conn) &&
(!CC_is_in_autocommit(conn)))
qflag |= GO_INTO_TRANSACTION;
qres = CC_send_query(conn, dltstr, NULL, qflag);
ret = SQL_SUCCESS; ret = SQL_SUCCESS;
if (qres && QR_command_maybe_successful(qres)) if (qres && QR_command_maybe_successful(qres))
{ {
...@@ -1973,14 +2428,14 @@ SC_pos_delete(StatementClass *stmt, ...@@ -1973,14 +2428,14 @@ SC_pos_delete(StatementClass *stmt,
sscanf(cmdstr, "DELETE %d", &dltcnt) == 1) sscanf(cmdstr, "DELETE %d", &dltcnt) == 1)
{ {
if (dltcnt == 1) if (dltcnt == 1)
SC_pos_reload(stmt, irow, global_ridx, (UWORD *) 0); SC_pos_reload(stmt, global_ridx, (UWORD *) 0, TRUE);
else if (dltcnt == 0) else if (dltcnt == 0)
{ {
stmt->errornumber = STMT_ROW_VERSION_CHANGED; stmt->errornumber = STMT_ROW_VERSION_CHANGED;
stmt->errormsg = "the content was changed before deletion"; stmt->errormsg = "the content was changed before deletion";
ret = SQL_ERROR; ret = SQL_ERROR;
if (stmt->options.cursor_type == SQL_CURSOR_KEYSET_DRIVEN) if (stmt->options.cursor_type == SQL_CURSOR_KEYSET_DRIVEN)
SC_pos_reload(stmt, irow, global_ridx, (UWORD *) 0); SC_pos_reload(stmt, global_ridx, (UWORD *) 0, FALSE);
} }
else else
ret = SQL_ERROR; ret = SQL_ERROR;
...@@ -1999,9 +2454,9 @@ SC_pos_delete(StatementClass *stmt, ...@@ -1999,9 +2454,9 @@ SC_pos_delete(StatementClass *stmt,
QR_Destructor(qres); QR_Destructor(qres);
if (SQL_SUCCESS == ret && res->keyset) if (SQL_SUCCESS == ret && res->keyset)
{ {
AddDeleted(res, global_ridx);
if (CC_is_in_trans(conn)) 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
...@@ -2085,6 +2540,7 @@ SC_pos_add(StatementClass *stmt, ...@@ -2085,6 +2540,7 @@ SC_pos_add(StatementClass *stmt,
HSTMT hstmt; HSTMT hstmt;
StatementClass *qstmt; StatementClass *qstmt;
ConnectionClass *conn; ConnectionClass *conn;
ConnInfo *ci;
QResultClass *res; QResultClass *res;
ARDFields *opts = SC_get_ARD(stmt); ARDFields *opts = SC_get_ARD(stmt);
IRDFields *irdflds = SC_get_IRD(stmt); IRDFields *irdflds = SC_get_IRD(stmt);
...@@ -2095,6 +2551,7 @@ SC_pos_add(StatementClass *stmt, ...@@ -2095,6 +2551,7 @@ SC_pos_add(StatementClass *stmt,
RETCODE ret; RETCODE ret;
UInt4 offset; UInt4 offset;
Int4 *used, bind_size = opts->bind_size; Int4 *used, bind_size = opts->bind_size;
Int4 fieldtype;
mylog("POS ADD fi=%x ti=%x\n", fi, stmt->ti); mylog("POS ADD fi=%x ti=%x\n", fi, stmt->ti);
if (!(res = SC_get_Curres(stmt))) if (!(res = SC_get_Curres(stmt)))
...@@ -2108,6 +2565,9 @@ SC_pos_add(StatementClass *stmt, ...@@ -2108,6 +2565,9 @@ SC_pos_add(StatementClass *stmt,
} }
num_cols = irdflds->nfields; num_cols = irdflds->nfields;
conn = SC_get_conn(stmt); conn = SC_get_conn(stmt);
if (stmt->ti[0]->schema[0])
sprintf(addstr, "insert into \"%s\".\"%s\" (", stmt->ti[0]->schema, stmt->ti[0]->name);
else
sprintf(addstr, "insert into \"%s\" (", stmt->ti[0]->name); sprintf(addstr, "insert into \"%s\" (", stmt->ti[0]->name);
if (PGAPI_AllocStmt(conn, &hstmt) != SQL_SUCCESS) if (PGAPI_AllocStmt(conn, &hstmt) != SQL_SUCCESS)
return SQL_ERROR; return SQL_ERROR;
...@@ -2119,6 +2579,7 @@ SC_pos_add(StatementClass *stmt, ...@@ -2119,6 +2579,7 @@ SC_pos_add(StatementClass *stmt,
apdopts = SC_get_APD(qstmt); apdopts = SC_get_APD(qstmt);
apdopts->param_bind_type = opts->bind_size; apdopts->param_bind_type = opts->bind_size;
apdopts->param_offset_ptr = opts->row_offset_ptr; apdopts->param_offset_ptr = opts->row_offset_ptr;
ci = &(conn->connInfo);
for (i = add_cols = 0; i < num_cols; i++) for (i = add_cols = 0; i < num_cols; i++)
{ {
if (used = bindings[i].used, used != NULL) if (used = bindings[i].used, used != NULL)
...@@ -2131,14 +2592,15 @@ SC_pos_add(StatementClass *stmt, ...@@ -2131,14 +2592,15 @@ SC_pos_add(StatementClass *stmt,
mylog("%d used=%d\n", i, *used); mylog("%d used=%d\n", i, *used);
if (*used != SQL_IGNORE && fi[i]->updatable) if (*used != SQL_IGNORE && fi[i]->updatable)
{ {
fieldtype = QR_get_field_type(res, i);
if (add_cols) if (add_cols)
sprintf(addstr, "%s, \"%s\"", addstr, fi[i]->name); sprintf(addstr, "%s, \"%s\"", addstr, fi[i]->name);
else else
sprintf(addstr, "%s\"%s\"", addstr, fi[i]->name); sprintf(addstr, "%s\"%s\"", addstr, fi[i]->name);
PGAPI_BindParameter(hstmt, (SQLUSMALLINT) ++add_cols, PGAPI_BindParameter(hstmt, (SQLUSMALLINT) ++add_cols,
SQL_PARAM_INPUT, bindings[i].returntype, SQL_PARAM_INPUT, bindings[i].returntype,
pgtype_to_concise_type(stmt, QR_get_field_type(res, i)), pgtype_to_concise_type(stmt, fieldtype),
QR_get_fieldsize(res, i), fi[i]->column_size > 0 ? fi[i]->column_size : pgtype_column_size(stmt, fieldtype, i, ci->drivers.unknown_sizes),
(SQLSMALLINT) fi[i]->decimal_digits, (SQLSMALLINT) fi[i]->decimal_digits,
bindings[i].buffer, bindings[i].buffer,
bindings[i].buflen, bindings[i].buflen,
...@@ -2178,7 +2640,7 @@ SC_pos_add(StatementClass *stmt, ...@@ -2178,7 +2640,7 @@ SC_pos_add(StatementClass *stmt,
} }
brow_save = stmt->bind_row; brow_save = stmt->bind_row;
stmt->bind_row = irow; stmt->bind_row = irow;
ret = irow_insert(ret, stmt, qstmt, res->fcount); ret = irow_insert(ret, stmt, qstmt, res->num_total_rows);
stmt->bind_row = brow_save; stmt->bind_row = brow_save;
} }
else else
...@@ -2189,7 +2651,7 @@ SC_pos_add(StatementClass *stmt, ...@@ -2189,7 +2651,7 @@ 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; int global_ridx = res->num_total_rows + stmt->rowset_start - res->base - 1;
if (CC_is_in_trans(conn)) if (CC_is_in_trans(conn))
{ {
...@@ -2230,16 +2692,18 @@ SC_pos_refresh(StatementClass *stmt, UWORD irow , UDWORD global_ridx) ...@@ -2230,16 +2692,18 @@ SC_pos_refresh(StatementClass *stmt, UWORD irow , UDWORD global_ridx)
#endif /* ODBCVER */ #endif /* ODBCVER */
/* save the last_fetch_count */ /* save the last_fetch_count */
int last_fetch = stmt->last_fetch_count; int last_fetch = stmt->last_fetch_count;
int last_fetch2 = stmt->last_fetch_count_include_ommitted;
int bind_save = stmt->bind_row; int bind_save = stmt->bind_row;
#ifdef DRIVER_CURSOR_IMPLEMENT #ifdef DRIVER_CURSOR_IMPLEMENT
if (stmt->options.cursor_type == SQL_CURSOR_KEYSET_DRIVEN) if (stmt->options.cursor_type == SQL_CURSOR_KEYSET_DRIVEN)
SC_pos_reload(stmt, irow, global_ridx, (UWORD *) 0); SC_pos_reload(stmt, global_ridx, (UWORD *) 0, FALSE);
#endif /* DRIVER_CURSOR_IMPLEMENT */ #endif /* DRIVER_CURSOR_IMPLEMENT */
stmt->bind_row = irow; stmt->bind_row = irow;
ret = SC_fetch(stmt); ret = SC_fetch(stmt);
/* restore the last_fetch_count */ /* restore the last_fetch_count */
stmt->last_fetch_count = last_fetch; stmt->last_fetch_count = last_fetch;
stmt->last_fetch_count_include_ommitted = last_fetch2;
stmt->bind_row = bind_save; stmt->bind_row = bind_save;
#if (ODBCVER >= 0x0300) #if (ODBCVER >= 0x0300)
if (irdflds->rowStatusArray) if (irdflds->rowStatusArray)
...@@ -2252,6 +2716,7 @@ SC_pos_refresh(StatementClass *stmt, UWORD irow , UDWORD global_ridx) ...@@ -2252,6 +2716,7 @@ SC_pos_refresh(StatementClass *stmt, UWORD irow , UDWORD global_ridx)
case SQL_SUCCESS: case SQL_SUCCESS:
irdflds->rowStatusArray[irow] = SQL_ROW_SUCCESS; irdflds->rowStatusArray[irow] = SQL_ROW_SUCCESS;
break; break;
case SQL_SUCCESS_WITH_INFO:
default: default:
irdflds->rowStatusArray[irow] = ret; irdflds->rowStatusArray[irow] = ret;
break; break;
...@@ -2278,10 +2743,11 @@ PGAPI_SetPos( ...@@ -2278,10 +2743,11 @@ PGAPI_SetPos(
StatementClass *stmt = (StatementClass *) hstmt; StatementClass *stmt = (StatementClass *) hstmt;
ConnectionClass *conn = SC_get_conn(stmt); ConnectionClass *conn = SC_get_conn(stmt);
QResultClass *res; QResultClass *res;
int num_cols, i, start_row, end_row, processed; int num_cols, i, start_row, end_row, processed, ridx;
UWORD nrow;
ARDFields *opts; ARDFields *opts;
BindInfoClass *bindings; BindInfoClass *bindings;
UDWORD global_ridx, fcount; UDWORD global_ridx;
BOOL auto_commit_needed = FALSE; BOOL auto_commit_needed = FALSE;
if (!stmt) if (!stmt)
...@@ -2318,8 +2784,8 @@ PGAPI_SetPos( ...@@ -2318,8 +2784,8 @@ PGAPI_SetPos(
{ {
if (SQL_POSITION == fOption) if (SQL_POSITION == fOption)
{ {
stmt->errornumber = STMT_ROW_OUT_OF_RANGE; stmt->errornumber = STMT_INVALID_CURSOR_POSITION;
stmt->errormsg = "Bulk Fresh operations not allowed."; stmt->errormsg = "Bulk Position operations not allowed.";
SC_log_error(func, "", stmt); SC_log_error(func, "", stmt);
return SQL_ERROR; return SQL_ERROR;
} }
...@@ -2344,7 +2810,6 @@ PGAPI_SetPos( ...@@ -2344,7 +2810,6 @@ PGAPI_SetPos(
for (i = 0; i < num_cols; i++) for (i = 0; i < num_cols; i++)
bindings[i].data_left = -1; bindings[i].data_left = -1;
ret = SQL_SUCCESS; ret = SQL_SUCCESS;
fcount = res->fcount;
#ifdef DRIVER_CURSOR_IMPLEMENT #ifdef DRIVER_CURSOR_IMPLEMENT
switch (fOption) switch (fOption)
{ {
...@@ -2356,28 +2821,47 @@ PGAPI_SetPos( ...@@ -2356,28 +2821,47 @@ PGAPI_SetPos(
break; break;
} }
#endif /* DRIVER_CURSOR_IMPLEMENT */ #endif /* DRIVER_CURSOR_IMPLEMENT */
for (i = start_row, processed = 0; i <= end_row; i++) ridx = -1;
for (i = nrow = 0, processed = 0; nrow <= end_row; i++)
{
global_ridx = i + stmt->rowset_start;
if (SQL_ADD != fOption)
{
if ((int) global_ridx >= res->num_total_rows)
break;
#ifdef DRIVER_CURSOR_IMPLEMENT
if (res->keyset) /* the row may be deleted and not in the rowset */
{
if (0 == (res->keyset[global_ridx].status & CURS_IN_ROWSET))
continue;
}
#endif /* DRIVER_CURSOR_IMPLEMENT */
}
if (nrow < start_row)
{ {
nrow++;
continue;
}
ridx = nrow;
#if (ODBCVER >= 0x0300) #if (ODBCVER >= 0x0300)
if (0 != irow || !opts->row_operation_ptr || opts->row_operation_ptr[i] == SQL_ROW_PROCEED) if (0 != irow || !opts->row_operation_ptr || opts->row_operation_ptr[nrow] == SQL_ROW_PROCEED)
{ {
#endif /* ODBCVER */ #endif /* ODBCVER */
global_ridx = i + stmt->rowset_start;
switch (fOption) switch (fOption)
{ {
#ifdef DRIVER_CURSOR_IMPLEMENT #ifdef DRIVER_CURSOR_IMPLEMENT
case SQL_UPDATE: case SQL_UPDATE:
ret = SC_pos_update(stmt, (UWORD) i, global_ridx); ret = SC_pos_update(stmt, nrow, global_ridx);
break; break;
case SQL_DELETE: case SQL_DELETE:
ret = SC_pos_delete(stmt, (UWORD) i, global_ridx); ret = SC_pos_delete(stmt, nrow, global_ridx);
break; break;
case SQL_ADD: case SQL_ADD:
ret = SC_pos_add(stmt, (UWORD) i); ret = SC_pos_add(stmt, nrow);
break; break;
#endif /* DRIVER_CURSOR_IMPLEMENT */ #endif /* DRIVER_CURSOR_IMPLEMENT */
case SQL_REFRESH: case SQL_REFRESH:
ret = SC_pos_refresh(stmt, (UWORD) i, global_ridx); ret = SC_pos_refresh(stmt, nrow, global_ridx);
break; break;
} }
processed++; processed++;
...@@ -2386,21 +2870,23 @@ PGAPI_SetPos( ...@@ -2386,21 +2870,23 @@ PGAPI_SetPos(
#if (ODBCVER >= 0x0300) #if (ODBCVER >= 0x0300)
} }
#endif /* ODBCVER */ #endif /* ODBCVER */
nrow++;
} }
if (SQL_ERROR == ret) if (SQL_ERROR == ret)
res->fcount = fcount; /* restore the count */ CC_abort(conn);
if (auto_commit_needed) if (auto_commit_needed)
PGAPI_SetConnectOption(conn, SQL_AUTOCOMMIT, SQL_AUTOCOMMIT_ON); PGAPI_SetConnectOption(conn, SQL_AUTOCOMMIT, SQL_AUTOCOMMIT_ON);
if (irow > 0) if (irow > 0)
{ {
if (SQL_ADD != fOption) /* for SQLGetData */ if (SQL_ADD != fOption && ridx >= 0) /* for SQLGetData */
{ {
stmt->currTuple = stmt->rowset_start + irow - 1; stmt->currTuple = stmt->rowset_start + ridx;
QR_set_position(res, irow - 1); QR_set_position(res, ridx);
} }
} }
else if (SC_get_IRD(stmt)->rowsFetched) else if (SC_get_IRD(stmt)->rowsFetched)
*SC_get_IRD(stmt)->rowsFetched = processed; *(SC_get_IRD(stmt)->rowsFetched) = processed;
res->recent_processed_row_count = stmt->diag_row_count = processed;
inolog("rowset=%d processed=%d ret=%d\n", opts->rowset_size, processed, ret); inolog("rowset=%d processed=%d ret=%d\n", opts->rowset_size, processed, ret);
return ret; return ret;
} }
...@@ -2408,8 +2894,7 @@ inolog("rowset=%d processed=%d ret=%d\n", opts->rowset_size, processed, ret); ...@@ -2408,8 +2894,7 @@ inolog("rowset=%d processed=%d ret=%d\n", opts->rowset_size, processed, ret);
/* Sets options that control the behavior of cursors. */ /* Sets options that control the behavior of cursors. */
RETCODE SQL_API RETCODE SQL_API
PGAPI_SetScrollOptions( PGAPI_SetScrollOptions( HSTMT hstmt,
HSTMT hstmt,
UWORD fConcurrency, UWORD fConcurrency,
SDWORD crowKeyset, SDWORD crowKeyset,
UWORD crowRowset) UWORD crowRowset)
......
...@@ -272,7 +272,7 @@ SC_Constructor(void) ...@@ -272,7 +272,7 @@ SC_Constructor(void)
rv->rowset_start = -1; rv->rowset_start = -1;
rv->current_col = -1; rv->current_col = -1;
rv->bind_row = 0; rv->bind_row = 0;
rv->last_fetch_count = 0; rv->last_fetch_count = rv->last_fetch_count_include_ommitted = 0;
rv->save_rowset_size = -1; rv->save_rowset_size = -1;
rv->data_at_exec = -1; rv->data_at_exec = -1;
...@@ -302,6 +302,7 @@ SC_Constructor(void) ...@@ -302,6 +302,7 @@ SC_Constructor(void)
rv->miscinfo = 0; rv->miscinfo = 0;
rv->updatable = FALSE; rv->updatable = FALSE;
rv->error_recsize = -1; rv->error_recsize = -1;
rv->diag_row_count = 0;
} }
return rv; return rv;
} }
...@@ -533,7 +534,7 @@ SC_recycle_statement(StatementClass *self) ...@@ -533,7 +534,7 @@ SC_recycle_statement(StatementClass *self)
self->rowset_start = -1; self->rowset_start = -1;
self->current_col = -1; self->current_col = -1;
self->bind_row = 0; self->bind_row = 0;
self->last_fetch_count = 0; self->last_fetch_count = self->last_fetch_count_include_ommitted = 0;
self->errormsg = NULL; self->errormsg = NULL;
self->errornumber = 0; self->errornumber = 0;
...@@ -619,6 +620,7 @@ SC_clear_error(StatementClass *self) ...@@ -619,6 +620,7 @@ SC_clear_error(StatementClass *self)
self->errormsg_created = FALSE; self->errormsg_created = FALSE;
self->errorpos = 0; self->errorpos = 0;
self->error_recsize = -1; self->error_recsize = -1;
self->diag_row_count = 0;
} }
...@@ -733,21 +735,21 @@ SC_fetch(StatementClass *self) ...@@ -733,21 +735,21 @@ SC_fetch(StatementClass *self)
/* TupleField *tupleField; */ /* TupleField *tupleField; */
ConnInfo *ci = &(SC_get_conn(self)->connInfo); ConnInfo *ci = &(SC_get_conn(self)->connInfo);
self->last_fetch_count = 0; self->last_fetch_count = self->last_fetch_count_include_ommitted = 0;
coli = QR_get_fields(res); /* the column info */ coli = QR_get_fields(res); /* the column info */
mylog("manual_result = %d, use_declarefetch = %d\n", self->manual_result, ci->drivers.use_declarefetch); mylog("manual_result = %d, use_declarefetch = %d\n", self->manual_result, ci->drivers.use_declarefetch);
if (self->manual_result || !SC_is_fetchcursor(self)) if (self->manual_result || !SC_is_fetchcursor(self))
{ {
if (self->currTuple >= QR_get_num_tuples(res) - 1 || if (self->currTuple >= QR_get_num_total_tuples(res) - 1 ||
(self->options.maxRows > 0 && self->currTuple == self->options.maxRows - 1)) (self->options.maxRows > 0 && self->currTuple == self->options.maxRows - 1))
{ {
/* /*
* if at the end of the tuples, return "no data found" and set * if at the end of the tuples, return "no data found" and set
* the cursor past the end of the result set * the cursor past the end of the result set
*/ */
self->currTuple = QR_get_num_tuples(res); self->currTuple = QR_get_num_total_tuples(res);
return SQL_NO_DATA_FOUND; return SQL_NO_DATA_FOUND;
} }
...@@ -774,11 +776,23 @@ SC_fetch(StatementClass *self) ...@@ -774,11 +776,23 @@ SC_fetch(StatementClass *self)
return SQL_ERROR; return SQL_ERROR;
} }
} }
#ifdef DRIVER_CURSOR_IMPLEMENT
if (res->haskeyset)
{
UWORD pstatus = res->keyset[self->currTuple].status;
if (0 != (pstatus & (CURS_SELF_DELETING | CURS_SELF_DELETED)))
return SQL_SUCCESS_WITH_INFO;
if (SQL_ROW_DELETED != (pstatus & KEYSET_INFO_PUBLIC) &&
0 != (pstatus & CURS_OTHER_DELETED))
return SQL_SUCCESS_WITH_INFO;
}
#endif /* DRIVER_CURSOR_IMPLEMENT */
num_cols = QR_NumResultCols(res); num_cols = QR_NumResultCols(res);
result = SQL_SUCCESS; result = SQL_SUCCESS;
self->last_fetch_count = 1; self->last_fetch_count++;
self->last_fetch_count_include_ommitted++;
opts = SC_get_ARD(self); opts = SC_get_ARD(self);
/* /*
...@@ -830,7 +844,12 @@ SC_fetch(StatementClass *self) ...@@ -830,7 +844,12 @@ SC_fetch(StatementClass *self)
else if (SC_is_fetchcursor(self)) else if (SC_is_fetchcursor(self))
value = QR_get_value_backend(res, lf); value = QR_get_value_backend(res, lf);
else else
value = QR_get_value_backend_row(res, self->currTuple, lf); {
int curt = res->base;
if (self->rowset_start >= 0)
curt += (self->currTuple - self->rowset_start);
value = QR_get_value_backend_row(res, curt, lf);
}
mylog("value = '%s'\n", (value == NULL) ? "<NULL>" : value); mylog("value = '%s'\n", (value == NULL) ? "<NULL>" : value);
...@@ -1152,7 +1171,7 @@ SC_log_error(const char *func, const char *desc, const StatementClass *self) ...@@ -1152,7 +1171,7 @@ SC_log_error(const char *func, const char *desc, const StatementClass *self)
if (res) if (res)
{ {
qlog(" fields=%u, manual_tuples=%u, backend_tuples=%u, tupleField=%d, conn=%u\n", res->fields, res->manual_tuples, res->backend_tuples, res->tupleField, res->conn); qlog(" fields=%u, manual_tuples=%u, backend_tuples=%u, tupleField=%d, conn=%u\n", res->fields, res->manual_tuples, res->backend_tuples, res->tupleField, res->conn);
qlog(" fetch_count=%d, fcount=%d, num_fields=%d, cursor='%s'\n", res->fetch_count, res->fcount, res->num_fields, nullcheck(res->cursor)); qlog(" fetch_count=%d, num_total_rows=%d, num_fields=%d, cursor='%s'\n", res->fetch_count, res->num_total_rows, res->num_fields, nullcheck(res->cursor));
qlog(" message='%s', command='%s', notice='%s'\n", nullcheck(res->message), nullcheck(res->command), nullcheck(res->notice)); qlog(" message='%s', command='%s', notice='%s'\n", nullcheck(res->message), nullcheck(res->command), nullcheck(res->notice));
qlog(" status=%d, inTuples=%d\n", res->status, res->inTuples); qlog(" status=%d, inTuples=%d\n", res->status, res->inTuples);
} }
......
...@@ -80,6 +80,7 @@ typedef enum ...@@ -80,6 +80,7 @@ typedef enum
#define STMT_ERROR_IN_ROW 30 #define STMT_ERROR_IN_ROW 30
#define STMT_INVALID_DESCRIPTOR_IDENTIFIER 31 #define STMT_INVALID_DESCRIPTOR_IDENTIFIER 31
#define STMT_OPTION_NOT_FOR_THE_DRIVER 32 #define STMT_OPTION_NOT_FOR_THE_DRIVER 32
#define STMT_FETCH_OUT_OF_RANGE 33
/* statement types */ /* statement types */
enum enum
...@@ -137,15 +138,6 @@ struct StatementClass_ ...@@ -137,15 +138,6 @@ struct StatementClass_
char *errormsg; char *errormsg;
int errornumber; int errornumber;
/* information on bindings */
/*** BindInfoClass *bindings; ***/ /* array to store the binding information */
/*** BindInfoClass bookmark;
int bindings_allocated; ***/
/* information on statement parameters */
/*** int parameters_allocated;
ParameterInfoClass *parameters; ***/
Int4 currTuple; /* current absolute row number (GetData, Int4 currTuple; /* current absolute row number (GetData,
* SetPos, SQLFetch) */ * SetPos, SQLFetch) */
int save_rowset_size; /* saved rowset size in case of int save_rowset_size; /* saved rowset size in case of
...@@ -200,9 +192,11 @@ struct StatementClass_ ...@@ -200,9 +192,11 @@ struct StatementClass_
char updatable; char updatable;
SWORD errorpos; SWORD errorpos;
SWORD error_recsize; SWORD error_recsize;
Int4 diag_row_count;
char *load_statement; /* to (re)load updatable individual rows */ char *load_statement; /* to (re)load updatable individual rows */
Int4 from_pos; Int4 from_pos;
Int4 where_pos; Int4 where_pos;
Int4 last_fetch_count_include_ommitted;
}; };
#define SC_get_conn(a) (a->hdbc) #define SC_get_conn(a) (a->hdbc)
......
...@@ -53,6 +53,8 @@ struct Rollback_ ...@@ -53,6 +53,8 @@ struct Rollback_
#define CURS_SELF_DELETED (1L << 7) #define CURS_SELF_DELETED (1L << 7)
#define CURS_SELF_UPDATED (1L << 8) #define CURS_SELF_UPDATED (1L << 8)
#define CURS_NEEDS_REREAD (1L << 9) #define CURS_NEEDS_REREAD (1L << 9)
#define CURS_IN_ROWSET (1L << 10)
#define CURS_OTHER_DELETED (1L << 11)
/* These macros are wrappers for the corresponding set_tuplefield functions /* These macros are wrappers for the corresponding set_tuplefield functions
but these handle automatic NULL determination and call set_tuplefield_null() but these handle automatic NULL determination and call set_tuplefield_null()
......
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