Commit 01e32265 authored by Hiroshi Inoue's avatar Hiroshi Inoue

1) Internal improvements to handle updatable cursors(1st cut).

2) Fix a bug in SQLColAttribute().
parent f362dcec
...@@ -374,7 +374,7 @@ CC_begin(ConnectionClass *self) ...@@ -374,7 +374,7 @@ CC_begin(ConnectionClass *self)
char ret = TRUE; char ret = TRUE;
if (!CC_is_in_trans(self)) if (!CC_is_in_trans(self))
{ {
QResultClass *res = CC_send_query(self, "BEGIN", NULL, TRUE); QResultClass *res = CC_send_query(self, "BEGIN", NULL, CLEAR_RESULT_ON_ABORT);
mylog("CC_begin: sending BEGIN!\n"); mylog("CC_begin: sending BEGIN!\n");
if (res != NULL) if (res != NULL)
...@@ -401,7 +401,7 @@ CC_commit(ConnectionClass *self) ...@@ -401,7 +401,7 @@ CC_commit(ConnectionClass *self)
char ret = FALSE; char ret = FALSE;
if (CC_is_in_trans(self)) if (CC_is_in_trans(self))
{ {
QResultClass *res = CC_send_query(self, "COMMIT", NULL, TRUE); QResultClass *res = CC_send_query(self, "COMMIT", NULL, CLEAR_RESULT_ON_ABORT);
mylog("CC_commit: sending COMMIT!\n"); mylog("CC_commit: sending COMMIT!\n");
CC_set_no_trans(self); CC_set_no_trans(self);
...@@ -427,7 +427,7 @@ CC_abort(ConnectionClass *self) ...@@ -427,7 +427,7 @@ CC_abort(ConnectionClass *self)
{ {
if (CC_is_in_trans(self)) if (CC_is_in_trans(self))
{ {
QResultClass *res = CC_send_query(self, "ROLLBACK", NULL, TRUE); QResultClass *res = CC_send_query(self, "ROLLBACK", NULL, CLEAR_RESULT_ON_ABORT);
mylog("CC_abort: sending ABORT!\n"); mylog("CC_abort: sending ABORT!\n");
CC_set_no_trans(self); CC_set_no_trans(self);
...@@ -919,7 +919,7 @@ another_version_retry: ...@@ -919,7 +919,7 @@ another_version_retry:
*/ */
mylog("sending an empty query...\n"); mylog("sending an empty query...\n");
res = CC_send_query(self, " ", NULL, TRUE); res = CC_send_query(self, " ", NULL, CLEAR_RESULT_ON_ABORT);
if (res == NULL || QR_get_status(res) != PGRES_EMPTY_QUERY) if (res == NULL || QR_get_status(res) != PGRES_EMPTY_QUERY)
{ {
mylog("got no result from the empty query. (probably database does not exist)\n"); mylog("got no result from the empty query. (probably database does not exist)\n");
...@@ -956,7 +956,7 @@ another_version_retry: ...@@ -956,7 +956,7 @@ another_version_retry:
* Multibyte handling is available ? * Multibyte handling is available ?
*/ */
#ifdef MULTIBYTE #ifdef MULTIBYTE
if (PG_VERSION_GE(self, 7.0)) if (PG_VERSION_GE(self, 6.4))
{ {
CC_lookup_characterset(self); CC_lookup_characterset(self);
if (self->errornumber != 0) if (self->errornumber != 0)
...@@ -977,7 +977,7 @@ another_version_retry: ...@@ -977,7 +977,7 @@ another_version_retry:
if (self->client_encoding) if (self->client_encoding)
free(self->client_encoding); free(self->client_encoding);
self->client_encoding = NULL; self->client_encoding = NULL;
if (res = CC_send_query(self, "set client_encoding to 'UTF8'", NULL, TRUE), res) if (res = CC_send_query(self, "set client_encoding to 'UTF8'", NULL, CLEAR_RESULT_ON_ABORT), res)
{ {
self->client_encoding = strdup("UNICODE"); self->client_encoding = strdup("UNICODE");
QR_Destructor(res); QR_Destructor(res);
...@@ -991,7 +991,7 @@ another_version_retry: ...@@ -991,7 +991,7 @@ another_version_retry:
else if (self->unicode) else if (self->unicode)
{ {
self->errornumber = CONN_NOT_IMPLEMENTED_ERROR; self->errornumber = CONN_NOT_IMPLEMENTED_ERROR;
self->errormsg = "Unicode isn't supported before 7.0"; self->errormsg = "Unicode isn't supported before 6.4";
return 0; return 0;
} }
#endif /* UNICODE_SUPPORT */ #endif /* UNICODE_SUPPORT */
...@@ -1128,12 +1128,14 @@ CC_get_error(ConnectionClass *self, int *number, char **message) ...@@ -1128,12 +1128,14 @@ CC_get_error(ConnectionClass *self, int *number, char **message)
* 'declare cursor C3326857 for ...' and 'fetch 100 in C3326857' statements. * 'declare cursor C3326857 for ...' and 'fetch 100 in C3326857' statements.
*/ */
QResultClass * QResultClass *
CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, BOOL clear_result_on_abort) CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, UDWORD flag)
{ {
QResultClass *result_in = NULL, QResultClass *result_in = NULL,
*cmdres = NULL, *cmdres = NULL,
*retres = NULL, *retres = NULL,
*res = NULL; *res = NULL;
BOOL clear_result_on_abort = ((flag & CLEAR_RESULT_ON_ABORT) != 0),
create_keyset = ((flag & CREATE_KEYSET) != 0);
char swallow, char swallow,
*wq; *wq;
int id; int id;
...@@ -1376,6 +1378,8 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, BOOL clear_resu ...@@ -1376,6 +1378,8 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, BOOL clear_resu
if (query_completed) if (query_completed)
{ {
res->next = QR_Constructor(); res->next = QR_Constructor();
if (create_keyset)
QR_set_haskeyset(res->next);
mylog("send_query: 'T' no result_in: res = %u\n", res->next); mylog("send_query: 'T' no result_in: res = %u\n", res->next);
if (!res->next) if (!res->next)
{ {
...@@ -1392,6 +1396,8 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, BOOL clear_resu ...@@ -1392,6 +1396,8 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, BOOL clear_resu
} }
if (!used_passed_result_object) if (!used_passed_result_object)
{ {
if (create_keyset)
QR_set_haskeyset(res);
if (!QR_fetch_tuples(res, self, qi ? qi->cursor : NULL)) if (!QR_fetch_tuples(res, self, qi ? qi->cursor : NULL))
{ {
self->errornumber = CONNECTION_COULD_NOT_RECEIVE; self->errornumber = CONNECTION_COULD_NOT_RECEIVE;
......
...@@ -305,7 +305,7 @@ char CC_connect(ConnectionClass *self, char do_password); ...@@ -305,7 +305,7 @@ char CC_connect(ConnectionClass *self, char do_password);
char CC_add_statement(ConnectionClass *self, StatementClass *stmt); char CC_add_statement(ConnectionClass *self, StatementClass *stmt);
char CC_remove_statement(ConnectionClass *self, StatementClass *stmt); char CC_remove_statement(ConnectionClass *self, StatementClass *stmt);
char CC_get_error(ConnectionClass *self, int *number, char **message); char CC_get_error(ConnectionClass *self, int *number, char **message);
QResultClass *CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, BOOL); QResultClass *CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, UDWORD flag);
void CC_clear_error(ConnectionClass *self); void CC_clear_error(ConnectionClass *self);
char *CC_create_errormsg(ConnectionClass *self); char *CC_create_errormsg(ConnectionClass *self);
int CC_send_function(ConnectionClass *conn, int fnid, void *result_buf, int *actual_result_len, int result_is_int, LO_ARG *argv, int nargs); int CC_send_function(ConnectionClass *conn, int fnid, void *result_buf, int *actual_result_len, int result_is_int, LO_ARG *argv, int nargs);
...@@ -316,4 +316,7 @@ void CC_initialize_pg_version(ConnectionClass *conn); ...@@ -316,4 +316,7 @@ void CC_initialize_pg_version(ConnectionClass *conn);
void CC_log_error(const char *func, const char *desc, const ConnectionClass *self); void CC_log_error(const char *func, const char *desc, const ConnectionClass *self);
int CC_get_max_query_len(const ConnectionClass *self); int CC_get_max_query_len(const ConnectionClass *self);
/* CC_send_query_options */
#define CLEAR_RESULT_ON_ABORT 1L
#define CREATE_KEYSET (1L << 1) /* create keyset for updatable curosrs */
#endif #endif
...@@ -1291,6 +1291,7 @@ copy_statement_with_parameters(StatementClass *stmt) ...@@ -1291,6 +1291,7 @@ copy_statement_with_parameters(StatementClass *stmt)
#ifdef DRIVER_CURSOR_IMPLEMENT #ifdef DRIVER_CURSOR_IMPLEMENT
BOOL search_from_pos = FALSE; BOOL search_from_pos = FALSE;
#endif /* DRIVER_CURSOR_IMPLEMENT */ #endif /* DRIVER_CURSOR_IMPLEMENT */
Int4 from_pos = -1, where_pos = -1;
if (ci->disallow_premature) if (ci->disallow_premature)
prepare_dummy_cursor = stmt->pre_executing; prepare_dummy_cursor = stmt->pre_executing;
...@@ -1326,7 +1327,11 @@ copy_statement_with_parameters(StatementClass *stmt) ...@@ -1326,7 +1327,11 @@ copy_statement_with_parameters(StatementClass *stmt)
else if (!stmt->ti || stmt->ntab != 1) else if (!stmt->ti || stmt->ntab != 1)
stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY; stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
else else
search_from_pos = TRUE; {
/** search_from_pos = TRUE; **/
from_pos = stmt->from_pos;
where_pos = stmt->where_pos;
}
} }
#endif /* DRIVER_CURSOR_IMPLEMENT */ #endif /* DRIVER_CURSOR_IMPLEMENT */
...@@ -1366,9 +1371,18 @@ copy_statement_with_parameters(StatementClass *stmt) ...@@ -1366,9 +1371,18 @@ copy_statement_with_parameters(StatementClass *stmt)
#ifdef MULTIBYTE #ifdef MULTIBYTE
make_encoded_str(&encstr, conn, old_statement); make_encoded_str(&encstr, conn, old_statement);
#endif #endif
for (opos = 0; opos < oldstmtlen; opos++) for (opos = 0; opos < oldstmtlen; opos++)
{ {
if (from_pos == (Int4) opos)
{
CVT_APPEND_STR(", CTID, OID ");
}
else if (where_pos == (Int4) opos)
{
stmt->load_statement = malloc(npos + 1);
memcpy(stmt->load_statement, new_statement, npos);
stmt->load_statement[npos] = '\0';
}
#ifdef MULTIBYTE #ifdef MULTIBYTE
oldchar = encoded_byte_check(&encstr, opos); oldchar = encoded_byte_check(&encstr, opos);
if (ENCODE_STATUS(encstr) != 0) if (ENCODE_STATUS(encstr) != 0)
...@@ -2033,6 +2047,12 @@ copy_statement_with_parameters(StatementClass *stmt) ...@@ -2033,6 +2047,12 @@ copy_statement_with_parameters(StatementClass *stmt)
#ifdef DRIVER_CURSOR_IMPLEMENT #ifdef DRIVER_CURSOR_IMPLEMENT
if (search_from_pos) if (search_from_pos)
stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY; stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
if (!stmt->load_statement && from_pos >=0)
{
stmt->load_statement = malloc(npos + 1);
memcpy(stmt->load_statement, new_statement, npos);
stmt->load_statement[npos] = '\0';
}
#endif /* DRIVER_CURSOR_IMPLEMENT */ #endif /* DRIVER_CURSOR_IMPLEMENT */
if (prepare_dummy_cursor && SC_is_pre_executable(stmt)) if (prepare_dummy_cursor && SC_is_pre_executable(stmt))
{ {
......
...@@ -245,6 +245,9 @@ PGAPI_StmtError( HSTMT hstmt, ...@@ -245,6 +245,9 @@ PGAPI_StmtError( HSTMT hstmt,
case STMT_INVALID_CURSOR_STATE_ERROR: case STMT_INVALID_CURSOR_STATE_ERROR:
strcpy(szSqlState, "24000"); strcpy(szSqlState, "24000");
break; break;
case STMT_ERROR_IN_ROW:
strcpy(szSqlState, "01S01");
break;
case STMT_OPTION_VALUE_CHANGED: case STMT_OPTION_VALUE_CHANGED:
strcpy(szSqlState, "01S02"); strcpy(szSqlState, "01S02");
break; break;
......
...@@ -94,6 +94,12 @@ PGAPI_Prepare(HSTMT hstmt, ...@@ -94,6 +94,12 @@ PGAPI_Prepare(HSTMT hstmt,
if (self->statement) if (self->statement)
free(self->statement); free(self->statement);
if (self->stmt_with_params)
free(self->stmt_with_params);
self->stmt_with_params = NULL;
if (self->load_statement)
free(self->load_statement);
self->load_statement = NULL;
self->statement = make_string(szSqlStr, cbSqlStr, NULL); self->statement = make_string(szSqlStr, cbSqlStr, NULL);
if (!self->statement) if (!self->statement)
...@@ -141,6 +147,12 @@ PGAPI_ExecDirect( ...@@ -141,6 +147,12 @@ PGAPI_ExecDirect(
if (stmt->statement) if (stmt->statement)
free(stmt->statement); free(stmt->statement);
if (stmt->stmt_with_params)
free(stmt->stmt_with_params);
stmt->stmt_with_params = NULL;
if (stmt->load_statement)
free(stmt->load_statement);
stmt->load_statement = NULL;
/* /*
* keep a copy of the un-parametrized statement, in case they try to * keep a copy of the un-parametrized statement, in case they try to
...@@ -421,7 +433,7 @@ next_param_row: ...@@ -421,7 +433,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; QResultClass *res, *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;
...@@ -436,7 +448,7 @@ next_param_row: ...@@ -436,7 +448,7 @@ next_param_row:
} }
/* we are now in a transaction */ /* we are now in a transaction */
CC_set_in_trans(conn); CC_set_in_trans(conn);
res = CC_send_query(conn, stmt->stmt_with_params, NULL, TRUE); res = CC_send_query(conn, stmt->stmt_with_params, NULL, CLEAR_RESULT_ON_ABORT);
if (!res) if (!res)
{ {
CC_abort(conn); CC_abort(conn);
...@@ -445,6 +457,9 @@ next_param_row: ...@@ -445,6 +457,9 @@ next_param_row:
return SQL_ERROR; return SQL_ERROR;
} }
SC_set_Result(stmt, res); SC_set_Result(stmt, res);
for (curres = res; !curres->num_fields; curres = curres->next)
;
SC_set_Curres(stmt, curres);
if (CC_is_in_autocommit(conn)) if (CC_is_in_autocommit(conn))
{ {
if (issued_begin) if (issued_begin)
...@@ -518,7 +533,7 @@ PGAPI_Transact( ...@@ -518,7 +533,7 @@ PGAPI_Transact(
{ {
mylog("PGAPI_Transact: sending on conn %d '%s'\n", conn, stmt_string); mylog("PGAPI_Transact: sending on conn %d '%s'\n", conn, stmt_string);
res = CC_send_query(conn, stmt_string, NULL, TRUE); res = CC_send_query(conn, stmt_string, NULL, CLEAR_RESULT_ON_ABORT);
CC_set_no_trans(conn); CC_set_no_trans(conn);
if (!res) if (!res)
......
...@@ -2858,7 +2858,7 @@ getClientTableName(ConnectionClass *conn, char *serverTableName, BOOL *nameAlloc ...@@ -2858,7 +2858,7 @@ getClientTableName(ConnectionClass *conn, char *serverTableName, BOOL *nameAlloc
return ret; return ret;
if (!conn->server_encoding) if (!conn->server_encoding)
{ {
if (res = CC_send_query(conn, "select getdatabaseencoding()", NULL, TRUE), 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_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));
...@@ -2868,11 +2868,11 @@ getClientTableName(ConnectionClass *conn, char *serverTableName, BOOL *nameAlloc ...@@ -2868,11 +2868,11 @@ getClientTableName(ConnectionClass *conn, char *serverTableName, BOOL *nameAlloc
if (!conn->server_encoding) if (!conn->server_encoding)
return ret; return ret;
sprintf(query, "SET CLIENT_ENCODING TO '%s'", conn->server_encoding); sprintf(query, "SET CLIENT_ENCODING TO '%s'", conn->server_encoding);
bError = (CC_send_query(conn, query, NULL, TRUE) == NULL); bError = (CC_send_query(conn, query, NULL, CLEAR_RESULT_ON_ABORT) == NULL);
if (!bError && continueExec) if (!bError && continueExec)
{ {
sprintf(query, "select OID from pg_class where relname = '%s'", serverTableName); sprintf(query, "select OID from pg_class where relname = '%s'", serverTableName);
if (res = CC_send_query(conn, query, NULL, TRUE), 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_tuples(res) > 0)
strcpy(saveoid, QR_get_value_backend_row(res, 0, 0)); strcpy(saveoid, QR_get_value_backend_row(res, 0, 0));
...@@ -2891,11 +2891,11 @@ getClientTableName(ConnectionClass *conn, char *serverTableName, BOOL *nameAlloc ...@@ -2891,11 +2891,11 @@ getClientTableName(ConnectionClass *conn, char *serverTableName, BOOL *nameAlloc
} }
/* restore the client encoding */ /* restore the client encoding */
sprintf(query, "SET CLIENT_ENCODING TO '%s'", conn->client_encoding); sprintf(query, "SET CLIENT_ENCODING TO '%s'", conn->client_encoding);
bError = (CC_send_query(conn, query, NULL, TRUE) == NULL); bError = (CC_send_query(conn, query, NULL, CLEAR_RESULT_ON_ABORT) == NULL);
if (bError || !continueExec) if (bError || !continueExec)
return ret; return ret;
sprintf(query, "select relname from pg_class where OID = %s", saveoid); sprintf(query, "select relname from pg_class where OID = %s", saveoid);
if (res = CC_send_query(conn, query, NULL, TRUE), 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_tuples(res) > 0)
{ {
...@@ -2922,7 +2922,7 @@ getClientColumnName(ConnectionClass *conn, const char *serverTableName, char *se ...@@ -2922,7 +2922,7 @@ getClientColumnName(ConnectionClass *conn, const char *serverTableName, char *se
return ret; return ret;
if (!conn->server_encoding) if (!conn->server_encoding)
{ {
if (res = CC_send_query(conn, "select getdatabaseencoding()", NULL, TRUE), 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_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));
...@@ -2932,13 +2932,13 @@ getClientColumnName(ConnectionClass *conn, const char *serverTableName, char *se ...@@ -2932,13 +2932,13 @@ getClientColumnName(ConnectionClass *conn, const char *serverTableName, char *se
if (!conn->server_encoding) if (!conn->server_encoding)
return ret; return ret;
sprintf(query, "SET CLIENT_ENCODING TO '%s'", conn->server_encoding); sprintf(query, "SET CLIENT_ENCODING TO '%s'", conn->server_encoding);
bError = (CC_send_query(conn, query, NULL, TRUE) == NULL); bError = (CC_send_query(conn, query, NULL, CLEAR_RESULT_ON_ABORT) == NULL);
if (!bError && continueExec) if (!bError && continueExec)
{ {
sprintf(query, "select attrelid, attnum from pg_class, pg_attribute " sprintf(query, "select attrelid, attnum from pg_class, pg_attribute "
"where relname = '%s' and attrelid = pg_class.oid " "where relname = '%s' and attrelid = pg_class.oid "
"and attname = '%s'", serverTableName, serverColumnName); "and attname = '%s'", serverTableName, serverColumnName);
if (res = CC_send_query(conn, query, NULL, TRUE), 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_tuples(res) > 0)
{ {
...@@ -2960,11 +2960,11 @@ getClientColumnName(ConnectionClass *conn, const char *serverTableName, char *se ...@@ -2960,11 +2960,11 @@ getClientColumnName(ConnectionClass *conn, const char *serverTableName, char *se
} }
/* restore the cleint encoding */ /* restore the cleint encoding */
sprintf(query, "SET CLIENT_ENCODING TO '%s'", conn->client_encoding); sprintf(query, "SET CLIENT_ENCODING TO '%s'", conn->client_encoding);
bError = (CC_send_query(conn, query, NULL, TRUE) == NULL); bError = (CC_send_query(conn, query, NULL, CLEAR_RESULT_ON_ABORT) == NULL);
if (bError || !continueExec) if (bError || !continueExec)
return ret; return ret;
sprintf(query, "select attname from pg_attribute where attrelid = %s and attnum = %s", saveattrelid, saveattnum); sprintf(query, "select attname from pg_attribute where attrelid = %s and attnum = %s", saveattrelid, saveattnum);
if (res = CC_send_query(conn, query, NULL, TRUE), 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_tuples(res) > 0)
{ {
...@@ -3790,7 +3790,7 @@ PGAPI_Procedures( ...@@ -3790,7 +3790,7 @@ PGAPI_Procedures(
" case when prorettype = 0 then 1::int2 else 2::int2 end as " "PROCEDURE_TYPE" " from pg_proc"); " case when prorettype = 0 then 1::int2 else 2::int2 end as " "PROCEDURE_TYPE" " from pg_proc");
my_strcat(proc_query, " where proname like '%.*s'", szProcName, cbProcName); my_strcat(proc_query, " where proname like '%.*s'", szProcName, cbProcName);
if (res = CC_send_query(conn, proc_query, NULL, TRUE), !res) if (res = CC_send_query(conn, proc_query, NULL, CLEAR_RESULT_ON_ABORT), !res)
{ {
stmt->errornumber = STMT_EXEC_ERROR; stmt->errornumber = STMT_EXEC_ERROR;
stmt->errormsg = "PGAPI_Procedures query error"; stmt->errormsg = "PGAPI_Procedures query error";
...@@ -3927,7 +3927,7 @@ PGAPI_TablePrivileges( ...@@ -3927,7 +3927,7 @@ PGAPI_TablePrivileges(
my_strcat(proc_query, " relname like '%.*s' and", esc_table_name, escTbnamelen); my_strcat(proc_query, " relname like '%.*s' and", esc_table_name, escTbnamelen);
} }
strcat(proc_query, " pg_user.usesysid = relowner"); strcat(proc_query, " pg_user.usesysid = relowner");
if (res = CC_send_query(conn, proc_query, NULL, TRUE), !res) if (res = CC_send_query(conn, proc_query, NULL, CLEAR_RESULT_ON_ABORT), !res)
{ {
stmt->errornumber = STMT_EXEC_ERROR; stmt->errornumber = STMT_EXEC_ERROR;
stmt->errormsg = "PGAPI_TablePrivileges query error"; stmt->errormsg = "PGAPI_TablePrivileges query error";
...@@ -3935,7 +3935,7 @@ PGAPI_TablePrivileges( ...@@ -3935,7 +3935,7 @@ PGAPI_TablePrivileges(
} }
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_tuples(res);
if (allures = CC_send_query(conn, proc_query, NULL, TRUE), !allures) if (allures = CC_send_query(conn, proc_query, NULL, CLEAR_RESULT_ON_ABORT), !allures)
{ {
QR_Destructor(res); QR_Destructor(res);
stmt->errornumber = STMT_EXEC_ERROR; stmt->errornumber = STMT_EXEC_ERROR;
...@@ -3983,7 +3983,7 @@ PGAPI_TablePrivileges( ...@@ -3983,7 +3983,7 @@ PGAPI_TablePrivileges(
char *grolist, *uid, *delm; char *grolist, *uid, *delm;
snprintf(proc_query, sizeof(proc_query) - 1, "select grolist from pg_group where groname = '%s'", user); snprintf(proc_query, sizeof(proc_query) - 1, "select grolist from pg_group where groname = '%s'", user);
if (gres = CC_send_query(conn, proc_query, NULL, TRUE)) if (gres = CC_send_query(conn, proc_query, NULL, CLEAR_RESULT_ON_ABORT))
{ {
grolist = QR_get_value_backend_row(gres, 0, 0); grolist = QR_get_value_backend_row(gres, 0, 0);
if (grolist && grolist[0] == '{') if (grolist && grolist[0] == '{')
......
...@@ -47,14 +47,15 @@ PGAPI_GetInfo30(HDBC hdbc, UWORD fInfoType, PTR rgbInfoValue, ...@@ -47,14 +47,15 @@ PGAPI_GetInfo30(HDBC hdbc, UWORD fInfoType, PTR rgbInfoValue,
break; break;
case SQL_KEYSET_CURSOR_ATTRIBUTES1: case SQL_KEYSET_CURSOR_ATTRIBUTES1:
len = 4; len = 4;
value = SQL_CA1_NEXT | SQL_CA1_ABSOLUTE value = 0;
if (ci->updatable_cursors || ci->drivers.lie)
value |= (SQL_CA1_NEXT | SQL_CA1_ABSOLUTE
| SQL_CA1_RELATIVE | SQL_CA1_BOOKMARK | SQL_CA1_RELATIVE | SQL_CA1_BOOKMARK
| SQL_CA1_LOCK_NO_CHANGE | SQL_CA1_POS_POSITION | SQL_CA1_LOCK_NO_CHANGE | SQL_CA1_POS_POSITION
| SQL_CA1_POS_UPDATE | SQL_CA1_POS_DELETE | SQL_CA1_POS_UPDATE | SQL_CA1_POS_DELETE
| SQL_CA1_POS_REFRESH; | SQL_CA1_POS_REFRESH);
if (ci->drivers.lie) if (ci->drivers.lie)
value |= value |= (SQL_CA1_BULK_ADD
( SQL_CA1_BULK_ADD
| SQL_CA1_BULK_UPDATE_BY_BOOKMARK | SQL_CA1_BULK_UPDATE_BY_BOOKMARK
| SQL_CA1_BULK_DELETE_BY_BOOKMARK | SQL_CA1_BULK_DELETE_BY_BOOKMARK
| SQL_CA1_BULK_FETCH_BY_BOOKMARK | SQL_CA1_BULK_FETCH_BY_BOOKMARK
...@@ -68,13 +69,14 @@ PGAPI_GetInfo30(HDBC hdbc, UWORD fInfoType, PTR rgbInfoValue, ...@@ -68,13 +69,14 @@ PGAPI_GetInfo30(HDBC hdbc, UWORD fInfoType, PTR rgbInfoValue,
break; break;
case SQL_KEYSET_CURSOR_ATTRIBUTES2: case SQL_KEYSET_CURSOR_ATTRIBUTES2:
len = 4; len = 4;
value = SQL_CA2_OPT_ROWVER_CONCURRENCY value = 0;
if (ci->updatable_cursors || ci->drivers.lie)
value |= (SQL_CA2_OPT_ROWVER_CONCURRENCY
| SQL_CA2_SENSITIVITY_ADDITIONS | SQL_CA2_SENSITIVITY_ADDITIONS
| SQL_CA2_SENSITIVITY_DELETIONS | SQL_CA2_SENSITIVITY_DELETIONS
| SQL_CA2_SENSITIVITY_UPDATES; | SQL_CA2_SENSITIVITY_UPDATES);
if (ci->drivers.lie) if (ci->drivers.lie)
value |= value |= (SQL_CA2_READ_ONLY_CONCURRENCY
( SQL_CA2_READ_ONLY_CONCURRENCY
| SQL_CA2_LOCK_CONCURRENCY | SQL_CA2_LOCK_CONCURRENCY
| SQL_CA2_OPT_VALUES_CONCURRENCY | SQL_CA2_OPT_VALUES_CONCURRENCY
| SQL_CA2_MAX_ROWS_SELECT | SQL_CA2_MAX_ROWS_SELECT
...@@ -95,16 +97,19 @@ PGAPI_GetInfo30(HDBC hdbc, UWORD fInfoType, PTR rgbInfoValue, ...@@ -95,16 +97,19 @@ PGAPI_GetInfo30(HDBC hdbc, UWORD fInfoType, PTR rgbInfoValue,
len = 4; len = 4;
value = SQL_CA1_NEXT | SQL_CA1_ABSOLUTE value = SQL_CA1_NEXT | SQL_CA1_ABSOLUTE
| SQL_CA1_RELATIVE | SQL_CA1_BOOKMARK | SQL_CA1_RELATIVE | SQL_CA1_BOOKMARK
| SQL_CA1_LOCK_NO_CHANGE | SQL_CA1_POS_POSITION | SQL_CA1_LOCK_NO_CHANGE | SQL_CA1_POS_POSITION;
| SQL_CA1_POS_UPDATE | SQL_CA1_POS_DELETE if (ci->updatable_cursors)
| SQL_CA1_POS_REFRESH; value |= (SQL_CA1_POS_UPDATE | SQL_CA1_POS_DELETE
| SQL_CA1_POS_REFRESH);
break; break;
case SQL_STATIC_CURSOR_ATTRIBUTES2: case SQL_STATIC_CURSOR_ATTRIBUTES2:
len = 4; len = 4;
value = SQL_CA2_OPT_ROWVER_CONCURRENCY value = 0;
if (ci->updatable_cursors)
value |= (SQL_CA2_OPT_ROWVER_CONCURRENCY
| SQL_CA2_SENSITIVITY_ADDITIONS | SQL_CA2_SENSITIVITY_ADDITIONS
| SQL_CA2_SENSITIVITY_DELETIONS | SQL_CA2_SENSITIVITY_DELETIONS
| SQL_CA2_SENSITIVITY_UPDATES; | SQL_CA2_SENSITIVITY_UPDATES);
break; break;
case SQL_ODBC_INTERFACE_CONFORMANCE: case SQL_ODBC_INTERFACE_CONFORMANCE:
......
...@@ -300,7 +300,7 @@ CC_lookup_cs_new(ConnectionClass *self) ...@@ -300,7 +300,7 @@ CC_lookup_cs_new(ConnectionClass *self)
char *encstr = NULL; char *encstr = NULL;
QResultClass *res; QResultClass *res;
res = CC_send_query(self, "select pg_client_encoding()", NULL, TRUE); res = CC_send_query(self, "select pg_client_encoding()", NULL, CLEAR_RESULT_ON_ABORT);
if (res) if (res)
{ {
char *enc = QR_get_value_backend_row(res, 0, 0); char *enc = QR_get_value_backend_row(res, 0, 0);
......
...@@ -419,177 +419,17 @@ SQLSetConnectAttr(HDBC ConnectionHandle, ...@@ -419,177 +419,17 @@ SQLSetConnectAttr(HDBC ConnectionHandle,
return PGAPI_SetConnectOption(ConnectionHandle, (UWORD) Attribute, (UDWORD) Value); return PGAPI_SetConnectOption(ConnectionHandle, (UWORD) Attribute, (UDWORD) Value);
} }
static RETCODE SQL_API
ARDSetField(StatementClass *stmt, SQLSMALLINT RecNumber,
SQLSMALLINT FieldIdentifier, PTR Value, SQLINTEGER BufferLength)
{
RETCODE ret = SQL_SUCCESS;
PTR tptr;
switch (FieldIdentifier)
{
case SQL_DESC_ARRAY_SIZE:
stmt->options.rowset_size = (SQLUINTEGER) Value;
break;
case SQL_DESC_ARRAY_STATUS_PTR:
stmt->options.row_operation_ptr = Value;
break;
case SQL_DESC_BIND_OFFSET_PTR:
stmt->options.row_offset_ptr = Value;
break;
case SQL_DESC_BIND_TYPE:
stmt->options.bind_size = (SQLUINTEGER) Value;
break;
case SQL_DESC_DATA_PTR:
if (!RecNumber)
stmt->bookmark.buffer = Value;
else
stmt->bindings[RecNumber - 1].buffer = Value;
break;
case SQL_DESC_INDICATOR_PTR:
if (!RecNumber)
tptr = stmt->bookmark.used;
else
tptr = stmt->bindings[RecNumber - 1].used;
if (Value != tptr)
{
ret = SQL_ERROR;
stmt->errornumber = STMT_INVALID_OPTION_IDENTIFIER;
stmt->errormsg = "INDICATOR != OCTET_LENGTH_PTR";
}
break;
case SQL_DESC_OCTET_LENGTH_PTR:
if (!RecNumber)
stmt->bookmark.used = Value;
else
stmt->bindings[RecNumber - 1].used = Value;
break;
default:ret = SQL_ERROR;
stmt->errornumber = STMT_INVALID_OPTION_IDENTIFIER;
stmt->errormsg = "not implemedted yet";
}
return ret;
}
static RETCODE SQL_API
APDSetField(StatementClass *stmt, SQLSMALLINT RecNumber,
SQLSMALLINT FieldIdentifier, PTR Value, SQLINTEGER BufferLength)
{
RETCODE ret = SQL_SUCCESS;
switch (FieldIdentifier)
{
case SQL_DESC_ARRAY_SIZE:
stmt->options.paramset_size = (SQLUINTEGER) Value;
break;
case SQL_DESC_ARRAY_STATUS_PTR:
stmt->options.param_operation_ptr = Value;
break;
case SQL_DESC_BIND_OFFSET_PTR:
stmt->options.param_offset_ptr = Value;
break;
case SQL_DESC_BIND_TYPE:
stmt->options.param_bind_type = (SQLUINTEGER) Value;
break;
case SQL_DESC_DATA_PTR:
if (stmt->parameters_allocated < RecNumber)
PGAPI_BindParameter(stmt, RecNumber, 0, 0, 0, 0, 0, 0, 0, 0);
stmt->parameters[RecNumber - 1].buffer = Value;
break;
case SQL_DESC_INDICATOR_PTR:
if (stmt->parameters_allocated < RecNumber ||
Value != stmt->parameters[RecNumber - 1].used)
{
ret = SQL_ERROR;
stmt->errornumber = STMT_INVALID_OPTION_IDENTIFIER;
stmt->errormsg = "INDICATOR != OCTET_LENGTH_PTR";
}
break;
case SQL_DESC_OCTET_LENGTH_PTR:
if (stmt->parameters_allocated < RecNumber)
PGAPI_BindParameter(stmt, RecNumber, 0, 0, 0, 0, 0, 0, 0, 0);
stmt->parameters[RecNumber - 1].used = Value;
break;
default:ret = SQL_ERROR;
stmt->errornumber = STMT_INVALID_OPTION_IDENTIFIER;
}
return ret;
}
static RETCODE SQL_API
IRDSetField(StatementClass *stmt, SQLSMALLINT RecNumber,
SQLSMALLINT FieldIdentifier, PTR Value, SQLINTEGER BufferLength)
{
RETCODE ret = SQL_SUCCESS;
switch (FieldIdentifier)
{
case SQL_DESC_ARRAY_STATUS_PTR:
stmt->options.rowStatusArray = (SQLUSMALLINT *) Value;
break;
case SQL_DESC_ROWS_PROCESSED_PTR:
stmt->options.rowsFetched = (SQLUINTEGER *) Value;
break;
default:ret = SQL_ERROR;
stmt->errornumber = STMT_INVALID_OPTION_IDENTIFIER;
}
return ret;
}
static RETCODE SQL_API
IPDSetField(StatementClass *stmt, SQLSMALLINT RecNumber,
SQLSMALLINT FieldIdentifier, PTR Value, SQLINTEGER BufferLength)
{
RETCODE ret = SQL_SUCCESS;
switch (FieldIdentifier)
{
case SQL_DESC_ARRAY_STATUS_PTR:
stmt->options.param_status_ptr = (SQLUSMALLINT *) Value;
break;
case SQL_DESC_ROWS_PROCESSED_PTR:
stmt->options.param_processed_ptr = (SQLUINTEGER *) Value;
break;
default:ret = SQL_ERROR;
stmt->errornumber = STMT_INVALID_OPTION_IDENTIFIER;
}
return ret;
}
/* new function */ /* new function */
RETCODE SQL_API RETCODE SQL_API
SQLSetDescField(SQLHDESC DescriptorHandle, SQLSetDescField(SQLHDESC DescriptorHandle,
SQLSMALLINT RecNumber, SQLSMALLINT FieldIdentifier, SQLSMALLINT RecNumber, SQLSMALLINT FieldIdentifier,
PTR Value, SQLINTEGER BufferLength) PTR Value, SQLINTEGER BufferLength)
{ {
RETCODE ret = SQL_SUCCESS; RETCODE ret;
HSTMT hstmt;
SQLUINTEGER descType;
StatementClass *stmt;
static const char *func = "SQLSetDescField";
mylog("[[SQLSetDescField]] h=%u rec=%d field=%d val=%x\n", DescriptorHandle, RecNumber, FieldIdentifier, Value); mylog("[[SQLSetDescField]] h=%u rec=%d field=%d val=%x\n", DescriptorHandle, RecNumber, FieldIdentifier, Value);
hstmt = statementHandleFromDescHandle(DescriptorHandle, &descType); ret = PGAPI_SetDescField(DescriptorHandle, RecNumber, FieldIdentifier,
mylog("stmt=%x type=%d\n", hstmt, descType); Value, BufferLength);
stmt = (StatementClass *) hstmt;
switch (descType)
{
case SQL_ATTR_APP_ROW_DESC:
ret = ARDSetField(stmt, RecNumber, FieldIdentifier, Value, BufferLength);
break;
case SQL_ATTR_APP_PARAM_DESC:
ret = APDSetField(stmt, RecNumber, FieldIdentifier, Value, BufferLength);
break;
case SQL_ATTR_IMP_ROW_DESC:
ret = IRDSetField(stmt, RecNumber, FieldIdentifier, Value, BufferLength);
break;
case SQL_ATTR_IMP_PARAM_DESC:
ret = IPDSetField(stmt, RecNumber, FieldIdentifier, Value, BufferLength);
break;
default:ret = SQL_ERROR;
stmt->errornumber = STMT_INTERNAL_ERROR;
stmt->errormsg = "Error not implemented";
}
if (ret == SQL_ERROR)
SC_log_error(func, "", stmt);
return ret; return ret;
} }
...@@ -602,7 +442,7 @@ SQLSetDescRec(SQLHDESC DescriptorHandle, ...@@ -602,7 +442,7 @@ SQLSetDescRec(SQLHDESC DescriptorHandle,
PTR Data, SQLINTEGER *StringLength, PTR Data, SQLINTEGER *StringLength,
SQLINTEGER *Indicator) SQLINTEGER *Indicator)
{ {
const char *func = "SQLSetDescField"; const char *func = "SQLSetDescRec";
mylog("[[SQLSetDescRec]]\n"); mylog("[[SQLSetDescRec]]\n");
mylog("Error not implemented\n"); mylog("Error not implemented\n");
......
...@@ -39,6 +39,7 @@ set_statement_option(ConnectionClass *conn, ...@@ -39,6 +39,7 @@ set_statement_option(ConnectionClass *conn,
static char *func = "set_statement_option"; static char *func = "set_statement_option";
char changed = FALSE; char changed = FALSE;
ConnInfo *ci = NULL; ConnInfo *ci = NULL;
UDWORD setval;
if (conn) if (conn)
ci = &(conn->connInfo); ci = &(conn->connInfo);
...@@ -63,22 +64,21 @@ set_statement_option(ConnectionClass *conn, ...@@ -63,22 +64,21 @@ set_statement_option(ConnectionClass *conn,
* positioned update isn't supported so cursor concurrency is * positioned update isn't supported so cursor concurrency is
* read-only * read-only
*/ */
mylog("SetStmtOption(): SQL_CONCURRENCY = %d\n", vParam); mylog("SetStmtOption(): SQL_CONCURRENCY = %d ", vParam);
if (ci->drivers.lie || vParam == SQL_CONCUR_READ_ONLY || vParam == SQL_CONCUR_ROWVER) setval = SQL_CONCUR_READ_ONLY;
{ if (SQL_CONCUR_READ_ONLY == vParam)
if (conn) ;
conn->stmtOptions.scroll_concurrency = vParam; if (ci->drivers.lie)
if (stmt) setval = vParam;
stmt->options.scroll_concurrency = vParam; else if (ci->updatable_cursors)
} setval = SQL_CONCUR_ROWVER;
else if (conn)
{ conn->stmtOptions.scroll_concurrency = setval;
if (conn) else if (stmt)
conn->stmtOptions.scroll_concurrency = SQL_CONCUR_ROWVER; stmt->options.scroll_concurrency = setval;
if (stmt) if (setval != vParam)
stmt->options.scroll_concurrency = SQL_CONCUR_ROWVER;
changed = TRUE; changed = TRUE;
} mylog("-> %d\n", setval);
break; break;
case SQL_CURSOR_TYPE: case SQL_CURSOR_TYPE:
...@@ -87,47 +87,24 @@ set_statement_option(ConnectionClass *conn, ...@@ -87,47 +87,24 @@ set_statement_option(ConnectionClass *conn,
* if declare/fetch, then type can only be forward. otherwise, * if declare/fetch, then type can only be forward. otherwise,
* it can only be forward or static. * it can only be forward or static.
*/ */
mylog("SetStmtOption(): SQL_CURSOR_TYPE = %d\n", vParam); mylog("SetStmtOption(): SQL_CURSOR_TYPE = %d ", vParam);
setval = SQL_CURSOR_FORWARD_ONLY;
if (ci->drivers.lie) if (ci->drivers.lie)
{ setval = vParam;
if (conn) else if (ci->drivers.use_declarefetch)
conn->stmtOptions.cursor_type = vParam; ;
if (stmt) else if (SQL_CURSOR_STATIC == vParam)
stmt->options.cursor_type = vParam; setval = vParam;
} /** else if (SQL_CURSOR_KEYSET_DRIVEN == vParam && ci->updatable)
else setval = vParam; **/
{
if (ci->drivers.use_declarefetch)
{
if (conn)
conn->stmtOptions.cursor_type = SQL_CURSOR_FORWARD_ONLY;
if (stmt)
stmt->options.cursor_type = SQL_CURSOR_FORWARD_ONLY;
if (vParam != SQL_CURSOR_FORWARD_ONLY) if (conn)
changed = TRUE; conn->stmtOptions.cursor_type = setval;
} else if (stmt)
else stmt->options.cursor_type = setval;
{ if (setval != vParam)
if (vParam == SQL_CURSOR_FORWARD_ONLY || vParam == SQL_CURSOR_STATIC) changed = TRUE;
{ mylog("-> %d\n", setval);
if (conn)
conn->stmtOptions.cursor_type = vParam; /* valid type */
if (stmt)
stmt->options.cursor_type = vParam; /* valid type */
}
else
{
if (conn)
conn->stmtOptions.cursor_type = SQL_CURSOR_STATIC;
if (stmt)
stmt->options.cursor_type = SQL_CURSOR_STATIC;
changed = TRUE;
}
}
}
break; break;
case SQL_KEYSET_SIZE: /* ignored, but saved and returned */ case SQL_KEYSET_SIZE: /* ignored, but saved and returned */
......
...@@ -297,7 +297,6 @@ parse_statement(StatementClass *stmt) ...@@ -297,7 +297,6 @@ parse_statement(StatementClass *stmt)
in_distinct = FALSE, in_distinct = FALSE,
in_on = FALSE, in_on = FALSE,
in_from = FALSE, in_from = FALSE,
from_found = FALSE,
in_where = FALSE, in_where = FALSE,
in_table = FALSE; in_table = FALSE;
char in_field = FALSE, char in_field = FALSE,
...@@ -309,7 +308,6 @@ parse_statement(StatementClass *stmt) ...@@ -309,7 +308,6 @@ parse_statement(StatementClass *stmt)
i, i,
k = 0, k = 0,
n, n,
first_where = 0,
blevel = 0; blevel = 0;
FIELD_INFO **fi; FIELD_INFO **fi;
TABLE_INFO **ti; TABLE_INFO **ti;
...@@ -318,6 +316,7 @@ parse_statement(StatementClass *stmt) ...@@ -318,6 +316,7 @@ parse_statement(StatementClass *stmt)
HSTMT hcol_stmt; HSTMT hcol_stmt;
StatementClass *col_stmt; StatementClass *col_stmt;
RETCODE result; RETCODE result;
BOOL updatable = TRUE;
mylog("%s: entering...\n", func); mylog("%s: entering...\n", func);
...@@ -327,6 +326,8 @@ parse_statement(StatementClass *stmt) ...@@ -327,6 +326,8 @@ parse_statement(StatementClass *stmt)
stmt->nfld = 0; stmt->nfld = 0;
stmt->ntab = 0; stmt->ntab = 0;
stmt->from_pos = -1;
stmt->where_pos = -1;
#ifdef MULTIBYTE #ifdef MULTIBYTE
while (pptr = ptr, (ptr = getNextToken(conn->ccsc, pptr, token, sizeof(token), &delim, &quote, &dquote, &numeric)) != NULL) while (pptr = ptr, (ptr = getNextToken(conn->ccsc, pptr, token, sizeof(token), &delim, &quote, &dquote, &numeric)) != NULL)
...@@ -343,6 +344,7 @@ parse_statement(StatementClass *stmt) ...@@ -343,6 +344,7 @@ parse_statement(StatementClass *stmt)
if (!stricmp(token, "distinct")) if (!stricmp(token, "distinct"))
{ {
in_distinct = TRUE; in_distinct = TRUE;
updatable = FALSE;
mylog("DISTINCT\n"); mylog("DISTINCT\n");
continue; continue;
...@@ -359,11 +361,11 @@ parse_statement(StatementClass *stmt) ...@@ -359,11 +361,11 @@ parse_statement(StatementClass *stmt)
{ {
in_select = FALSE; in_select = FALSE;
in_from = TRUE; in_from = TRUE;
if (!from_found && if (stmt->from_pos < 0 &&
(!strnicmp(pptr, "from", 4))) (!strnicmp(pptr, "from", 4)))
{ {
mylog("First "); mylog("First ");
from_found = TRUE; stmt->from_pos = pptr - stmt->statement;
} }
mylog("FROM\n"); mylog("FROM\n");
...@@ -384,9 +386,13 @@ parse_statement(StatementClass *stmt) ...@@ -384,9 +386,13 @@ parse_statement(StatementClass *stmt)
in_from = FALSE; in_from = FALSE;
in_where = TRUE; in_where = TRUE;
if (!first_where && if (!stricmp(token, "where"))
(!stricmp(token, "where"))) {
first_where = ptr - stmt->statement; if (stmt->where_pos < 0)
stmt->where_pos = pptr - stmt->statement;
}
else if (stricmp(token, "order"))
updatable = FALSE;
mylog("WHERE...\n"); mylog("WHERE...\n");
break; break;
...@@ -733,6 +739,10 @@ parse_statement(StatementClass *stmt) ...@@ -733,6 +739,10 @@ parse_statement(StatementClass *stmt)
*/ */
/* Call SQLColumns for each table and store the result */ /* Call SQLColumns for each table and store the result */
if (stmt->ntab > 1)
updatable = FALSE;
else if (stmt->from_pos < 0)
updatable = FALSE;
for (i = 0; i < stmt->ntab; i++) for (i = 0; i < stmt->ntab; i++)
{ {
/* See if already got it */ /* See if already got it */
...@@ -828,9 +838,11 @@ parse_statement(StatementClass *stmt) ...@@ -828,9 +838,11 @@ parse_statement(StatementClass *stmt)
*/ */
for (i = 0; i < stmt->nfld;) for (i = 0; i < stmt->nfld;)
{ {
fi[i]->updatable = updatable;
/* Dont worry about functions or quotes */ /* Dont worry about functions or quotes */
if (fi[i]->func || fi[i]->quote || fi[i]->numeric) if (fi[i]->func || fi[i]->quote || fi[i]->numeric)
{ {
fi[i]->updatable = FALSE;
i++; i++;
continue; continue;
} }
...@@ -928,6 +940,7 @@ parse_statement(StatementClass *stmt) ...@@ -928,6 +940,7 @@ parse_statement(StatementClass *stmt)
mylog("about to copy at %d\n", n + i); mylog("about to copy at %d\n", n + i);
getColInfo(the_ti->col_info, fi[n + i], n); getColInfo(the_ti->col_info, fi[n + i], n);
fi[n + i]->updatable = updatable;
mylog("done copying\n"); mylog("done copying\n");
} }
...@@ -945,24 +958,29 @@ parse_statement(StatementClass *stmt) ...@@ -945,24 +958,29 @@ parse_statement(StatementClass *stmt)
else if (fi[i]->ti) else if (fi[i]->ti)
{ {
if (!searchColInfo(fi[i]->ti->col_info, fi[i])) if (!searchColInfo(fi[i]->ti->col_info, fi[i]))
{
parse = FALSE; parse = FALSE;
fi[i]->updatable = FALSE;
}
i++; i++;
} }
/* Don't know the table -- search all tables in "from" list */ /* Don't know the table -- search all tables in "from" list */
else else
{ {
parse = FALSE;
for (k = 0; k < stmt->ntab; k++) for (k = 0; k < stmt->ntab; k++)
{ {
if (searchColInfo(ti[k]->col_info, fi[i])) if (searchColInfo(ti[k]->col_info, fi[i]))
{ {
fi[i]->ti = ti[k]; /* now know the table */ fi[i]->ti = ti[k]; /* now know the table */
parse = TRUE;
break; break;
} }
} }
if (k >= stmt->ntab)
{
parse = FALSE;
fi[i]->updatable = FALSE;
}
i++; i++;
} }
} }
......
...@@ -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.59 2002/03/11 10:25:57 inoue Exp $ * $Id: psqlodbc.h,v 1.60 2002/03/14 05:42:03 inoue Exp $
* *
*/ */
...@@ -166,6 +166,7 @@ typedef struct TupleListClass_ TupleListClass; ...@@ -166,6 +166,7 @@ typedef struct TupleListClass_ TupleListClass;
typedef struct EnvironmentClass_ EnvironmentClass; typedef struct EnvironmentClass_ EnvironmentClass;
typedef struct TupleNode_ TupleNode; typedef struct TupleNode_ TupleNode;
typedef struct TupleField_ TupleField; typedef struct TupleField_ TupleField;
typedef struct KeySet_ KeySet;
typedef struct col_info COL_INFO; typedef struct col_info COL_INFO;
typedef struct lo_arg LO_ARG; typedef struct lo_arg LO_ARG;
......
...@@ -5,7 +5,7 @@ SQLAllocEnv @2 ...@@ -5,7 +5,7 @@ SQLAllocEnv @2
SQLAllocStmt @3 SQLAllocStmt @3
SQLBindCol @4 SQLBindCol @4
SQLCancel @5 SQLCancel @5
SQLColAttributes @6 ; SQLColAttributes @6 */
SQLConnect @7 SQLConnect @7
SQLDescribeCol @8 SQLDescribeCol @8
SQLDisconnect @9 SQLDisconnect @9
......
...@@ -5,7 +5,7 @@ SQLAllocEnv @2 ...@@ -5,7 +5,7 @@ SQLAllocEnv @2
SQLAllocStmt @3 SQLAllocStmt @3
SQLBindCol @4 SQLBindCol @4
SQLCancel @5 SQLCancel @5
SQLColAttributes @6 ; SQLColAttributes @6
SQLConnect @7 SQLConnect @7
SQLDescribeCol @8 SQLDescribeCol @8
SQLDisconnect @9 SQLDisconnect @9
......
...@@ -121,6 +121,8 @@ QR_Constructor() ...@@ -121,6 +121,8 @@ QR_Constructor()
rv->cache_size = 0; rv->cache_size = 0;
rv->rowset_size = 1; rv->rowset_size = 1;
rv->haskeyset = 0;
rv->keyset = NULL;
} }
mylog("exit QR_Constructor\n"); mylog("exit QR_Constructor\n");
...@@ -221,6 +223,11 @@ QR_free_memory(QResultClass *self) ...@@ -221,6 +223,11 @@ QR_free_memory(QResultClass *self)
free(self->backend_tuples); free(self->backend_tuples);
self->backend_tuples = NULL; self->backend_tuples = NULL;
} }
if (self->keyset)
{
free(self->keyset);
self->keyset = NULL;
}
self->fcount = 0; self->fcount = 0;
...@@ -296,6 +303,8 @@ QR_fetch_tuples(QResultClass *self, ConnectionClass *conn, char *cursor) ...@@ -296,6 +303,8 @@ QR_fetch_tuples(QResultClass *self, ConnectionClass *conn, char *cursor)
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_allocated = 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);
if (self->haskeyset)
self->keyset = (KeySet *) calloc(sizeof(KeySet), tuple_size);
if (!self->backend_tuples) if (!self->backend_tuples)
{ {
self->status = PGRES_FATAL_ERROR; self->status = PGRES_FATAL_ERROR;
...@@ -347,7 +356,7 @@ QR_close(QResultClass *self) ...@@ -347,7 +356,7 @@ QR_close(QResultClass *self)
sprintf(buf, "close %s", self->cursor); sprintf(buf, "close %s", self->cursor);
mylog("QResult: closing cursor: '%s'\n", buf); mylog("QResult: closing cursor: '%s'\n", buf);
res = CC_send_query(self->conn, buf, NULL, TRUE); res = CC_send_query(self->conn, buf, NULL, CLEAR_RESULT_ON_ABORT);
self->inTuples = FALSE; self->inTuples = FALSE;
self->currTuple = -1; self->currTuple = -1;
...@@ -482,6 +491,8 @@ QR_next_tuple(QResultClass *self) ...@@ -482,6 +491,8 @@ 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;
} }
if (self->haskeyset)
self->keyset = (KeySet *) realloc(self->keyset, sizeof(KeySet) * self->cache_size);
self->count_allocated = self->cache_size; self->count_allocated = self->cache_size;
} }
sprintf(fetch, "fetch %d in %s", fetch_size, self->cursor); sprintf(fetch, "fetch %d in %s", fetch_size, self->cursor);
...@@ -492,7 +503,7 @@ QR_next_tuple(QResultClass *self) ...@@ -492,7 +503,7 @@ QR_next_tuple(QResultClass *self)
qi.row_size = self->cache_size; qi.row_size = self->cache_size;
qi.result_in = self; qi.result_in = self;
qi.cursor = NULL; qi.cursor = NULL;
res = CC_send_query(self->conn, fetch, &qi, TRUE); res = CC_send_query(self->conn, fetch, &qi, CLEAR_RESULT_ON_ABORT);
if (res == NULL) if (res == NULL)
{ {
self->status = PGRES_FATAL_ERROR; self->status = PGRES_FATAL_ERROR;
...@@ -552,6 +563,8 @@ QR_next_tuple(QResultClass *self) ...@@ -552,6 +563,8 @@ 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;
} }
if (self->haskeyset)
self->keyset = (KeySet *) realloc(self->keyset, sizeof(KeySet) * tuple_size);
self->count_allocated = tuple_size; self->count_allocated = tuple_size;
} }
...@@ -626,6 +639,7 @@ QR_read_tuple(QResultClass *self, char binary) ...@@ -626,6 +639,7 @@ QR_read_tuple(QResultClass *self, char binary)
{ {
Int2 field_lf; Int2 field_lf;
TupleField *this_tuplefield; TupleField *this_tuplefield;
KeySet *this_keyset = NULL;
char bmp, char bmp,
bitmap[MAX_FIELDS]; /* Max. len of the bitmap */ bitmap[MAX_FIELDS]; /* Max. len of the bitmap */
Int2 bitmaplen; /* len of the bitmap in bytes */ Int2 bitmaplen; /* len of the bitmap in bytes */
...@@ -639,6 +653,11 @@ QR_read_tuple(QResultClass *self, char binary) ...@@ -639,6 +653,11 @@ 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 */
this_tuplefield = self->backend_tuples + (self->fcount * num_fields); this_tuplefield = self->backend_tuples + (self->fcount * num_fields);
if (self->haskeyset)
{
this_keyset = self->keyset + self->fcount;
this_keyset->status = 0;
}
bitmaplen = (Int2) num_fields / BYTELEN; bitmaplen = (Int2) num_fields / BYTELEN;
if ((num_fields % BYTELEN) > 0) if ((num_fields % BYTELEN) > 0)
...@@ -709,6 +728,15 @@ QR_read_tuple(QResultClass *self, char binary) ...@@ -709,6 +728,15 @@ QR_read_tuple(QResultClass *self, char binary)
else else
bmp <<= 1; bmp <<= 1;
} }
if (this_keyset)
{
if (this_tuplefield[num_fields - 2].value)
sscanf(this_tuplefield[num_fields - 2].value, "(%u,%hu)",
&this_keyset->blocknum, &this_keyset->offset);
if (this_tuplefield[num_fields - 1].value)
sscanf(this_tuplefield[num_fields - 1].value, "%u",
&this_keyset->oid);
}
self->currTuple++; self->currTuple++;
return TRUE; return TRUE;
} }
...@@ -72,6 +72,9 @@ struct QResultClass_ ...@@ -72,6 +72,9 @@ struct QResultClass_
char inTuples; /* is a fetch of rows from the backend in char inTuples; /* is a fetch of rows from the backend in
* progress? */ * progress? */
char aborted; /* was aborted? */ char aborted; /* was aborted? */
char haskeyset; /* this result contains keyset ? */
KeySet *keyset;
}; };
#define QR_get_fields(self) (self->fields) #define QR_get_fields(self) (self->fields)
...@@ -102,6 +105,7 @@ struct QResultClass_ ...@@ -102,6 +105,7 @@ struct QResultClass_
#define QR_set_status(self, condition) ( self->status = condition ) #define QR_set_status(self, condition) ( self->status = condition )
#define QR_set_message(self, message_) ( self->message = message_) #define QR_set_message(self, message_) ( self->message = message_)
#define QR_set_aborted(self, aborted_) ( self->aborted = aborted_) #define QR_set_aborted(self, aborted_) ( self->aborted = aborted_)
#define QR_set_haskeyset(self) (self->haskeyset = TRUE)
#define QR_get_message(self) (self->message) #define QR_get_message(self) (self->message)
#define QR_get_command(self) (self->command) #define QR_get_command(self) (self->command)
......
This diff is collapsed.
...@@ -242,6 +242,7 @@ SC_Constructor(void) ...@@ -242,6 +242,7 @@ SC_Constructor(void)
rv->statement = NULL; rv->statement = NULL;
rv->stmt_with_params = NULL; rv->stmt_with_params = NULL;
rv->load_statement = NULL;
rv->stmt_size_limit = -1; rv->stmt_size_limit = -1;
rv->statement_type = STMT_TYPE_UNKNOWN; rv->statement_type = STMT_TYPE_UNKNOWN;
...@@ -318,6 +319,8 @@ SC_Destructor(StatementClass *self) ...@@ -318,6 +319,8 @@ SC_Destructor(StatementClass *self)
free(self->stmt_with_params); free(self->stmt_with_params);
self->stmt_with_params = NULL; self->stmt_with_params = NULL;
} }
if (self->load_statement)
free(self->load_statement);
SC_free_params(self, STMT_FREE_PARAMS_ALL); SC_free_params(self, STMT_FREE_PARAMS_ALL);
...@@ -548,6 +551,12 @@ SC_recycle_statement(StatementClass *self) ...@@ -548,6 +551,12 @@ SC_recycle_statement(StatementClass *self)
* SQLParamData/SQLPutData is called. * SQLParamData/SQLPutData is called.
*/ */
SC_free_params(self, STMT_FREE_PARAMS_DATA_AT_EXEC_ONLY); SC_free_params(self, STMT_FREE_PARAMS_DATA_AT_EXEC_ONLY);
if (self->stmt_with_params)
free(self->stmt_with_params);
self->stmt_with_params = NULL;
if (self->load_statement)
free(self->load_statement);
self->load_statement = NULL;
return TRUE; return TRUE;
} }
...@@ -635,12 +644,16 @@ SC_create_errormsg(StatementClass *self) ...@@ -635,12 +644,16 @@ SC_create_errormsg(StatementClass *self)
QResultClass *res = SC_get_Curres(self); QResultClass *res = SC_get_Curres(self);
ConnectionClass *conn = self->hdbc; ConnectionClass *conn = self->hdbc;
int pos; int pos;
BOOL detailmsg = FALSE;
static char msg[4096]; static char msg[4096];
msg[0] = '\0'; msg[0] = '\0';
if (res && res->message) if (res && res->message)
{
strcpy(msg, res->message); strcpy(msg, res->message);
detailmsg = TRUE;
}
else if (self->errormsg) else if (self->errormsg)
strcpy(msg, self->errormsg); strcpy(msg, self->errormsg);
...@@ -660,10 +673,10 @@ SC_create_errormsg(StatementClass *self) ...@@ -660,10 +673,10 @@ SC_create_errormsg(StatementClass *self)
{ {
SocketClass *sock = conn->sock; SocketClass *sock = conn->sock;
if (conn->errormsg && conn->errormsg[0] != '\0') if (!detailmsg && conn->errormsg && conn->errormsg[0] != '\0')
{ {
pos = strlen(msg); pos = strlen(msg);
/*sprintf(&msg[pos], ";\n%s", conn->errormsg);*/ sprintf(&msg[pos], ";\n%s", conn->errormsg);
} }
if (sock && sock->errormsg && sock->errormsg[0] != '\0') if (sock && sock->errormsg && sock->errormsg[0] != '\0')
...@@ -722,9 +735,6 @@ SC_fetch(StatementClass *self) ...@@ -722,9 +735,6 @@ SC_fetch(StatementClass *self)
int retval, int retval,
result; result;
#ifdef DRIVER_CURSOR_IMPLEMENT
int updret;
#endif /* DRIVER_CURSOR_IMPLEMENT */
Int2 num_cols, Int2 num_cols,
lf; lf;
Oid type; Oid type;
...@@ -799,20 +809,13 @@ SC_fetch(StatementClass *self) ...@@ -799,20 +809,13 @@ SC_fetch(StatementClass *self)
} }
#ifdef DRIVER_CURSOR_IMPLEMENT #ifdef DRIVER_CURSOR_IMPLEMENT
updret = 0;
if (self->options.scroll_concurrency != SQL_CONCUR_READ_ONLY) if (self->options.scroll_concurrency != SQL_CONCUR_READ_ONLY)
{ {
if (!QR_get_value_backend_row(res, self->currTuple, num_cols - 1))
updret = SQL_ROW_DELETED;
num_cols -= 2; num_cols -= 2;
} }
#endif /* DRIVER_CURSOR_IMPLEMENT */ #endif /* DRIVER_CURSOR_IMPLEMENT */
if (self->options.retrieve_data == SQL_RD_OFF) /* data isn't required */ if (self->options.retrieve_data == SQL_RD_OFF) /* data isn't required */
#ifdef DRIVER_CURSOR_IMPLEMENT
return updret ? updret + 10 : SQL_SUCCESS;
#else
return SQL_SUCCESS; return SQL_SUCCESS;
#endif /* DRIVER_CURSOR_IMPLEMENT */
for (lf = 0; lf < num_cols; lf++) for (lf = 0; lf < num_cols; lf++)
{ {
mylog("fetch: cols=%d, lf=%d, self = %u, self->bindings = %u, buffer[] = %u\n", num_cols, lf, self, self->bindings, self->bindings[lf].buffer); mylog("fetch: cols=%d, lf=%d, self = %u, self->bindings = %u, buffer[] = %u\n", num_cols, lf, self, self->bindings, self->bindings[lf].buffer);
...@@ -893,10 +896,6 @@ SC_fetch(StatementClass *self) ...@@ -893,10 +896,6 @@ SC_fetch(StatementClass *self)
} }
} }
#ifdef DRIVER_CURSOR_IMPLEMENT
if (updret)
result = updret + 10;
#endif /* DRIVER_CURSOR_IMPLEMENT */
return result; return result;
} }
...@@ -955,11 +954,12 @@ SC_execute(StatementClass *self) ...@@ -955,11 +954,12 @@ SC_execute(StatementClass *self)
if (self->statement_type == STMT_TYPE_SELECT) if (self->statement_type == STMT_TYPE_SELECT)
{ {
char fetch[128]; char fetch[128];
UDWORD qflag = (SQL_CONCUR_ROWVER == self->options.scroll_concurrency ? CREATE_KEYSET : 0);
mylog(" Sending SELECT statement on stmt=%u, cursor_name='%s'\n", self, self->cursor_name); mylog(" Sending SELECT statement on stmt=%u, cursor_name='%s'\n", self, self->cursor_name);
/* send the declare/select */ /* send the declare/select */
res = CC_send_query(conn, self->stmt_with_params, NULL, FALSE); res = CC_send_query(conn, self->stmt_with_params, NULL, qflag);
if (SC_is_fetchcursor(self) && res != NULL && if (SC_is_fetchcursor(self) && res != NULL &&
QR_command_successful(res)) QR_command_successful(res))
{ {
...@@ -982,7 +982,7 @@ SC_execute(StatementClass *self) ...@@ -982,7 +982,7 @@ SC_execute(StatementClass *self)
*/ */
sprintf(fetch, "fetch %d in %s", qi.row_size, self->cursor_name); sprintf(fetch, "fetch %d in %s", qi.row_size, self->cursor_name);
res = CC_send_query(conn, fetch, &qi, FALSE); res = CC_send_query(conn, fetch, &qi, qflag);
} }
mylog(" done sending the query:\n"); mylog(" done sending the query:\n");
} }
...@@ -990,7 +990,7 @@ SC_execute(StatementClass *self) ...@@ -990,7 +990,7 @@ SC_execute(StatementClass *self)
{ {
/* not a SELECT statement so don't use a cursor */ /* not a SELECT statement so don't use a cursor */
mylog(" it's NOT a select statement: stmt=%u\n", self); mylog(" it's NOT a select statement: stmt=%u\n", self);
res = CC_send_query(conn, self->stmt_with_params, NULL, FALSE); res = CC_send_query(conn, self->stmt_with_params, NULL, 0);
/* /*
* We shouldn't send COMMIT. Postgres backend does the autocommit * We shouldn't send COMMIT. Postgres backend does the autocommit
......
...@@ -76,6 +76,7 @@ typedef enum ...@@ -76,6 +76,7 @@ typedef enum
#define STMT_BAD_ERROR 27 #define STMT_BAD_ERROR 27
#define STMT_INVALID_OPTION_IDENTIFIER 28 #define STMT_INVALID_OPTION_IDENTIFIER 28
#define STMT_RETURN_NULL_WITHOUT_INDICATOR 29 #define STMT_RETURN_NULL_WITHOUT_INDICATOR 29
#define STMT_ERROR_IN_ROW 30
/* statement types */ /* statement types */
enum enum
...@@ -135,6 +136,7 @@ typedef struct ...@@ -135,6 +136,7 @@ typedef struct
char quote; char quote;
char dquote; char dquote;
char numeric; char numeric;
char updatable;
char dot[MAX_TABLE_LEN + 1]; char dot[MAX_TABLE_LEN + 1];
char name[MAX_COLUMN_LEN + 1]; char name[MAX_COLUMN_LEN + 1];
char alias[MAX_COLUMN_LEN + 1]; char alias[MAX_COLUMN_LEN + 1];
...@@ -219,11 +221,15 @@ struct StatementClass_ ...@@ -219,11 +221,15 @@ struct StatementClass_
char miscinfo; char miscinfo;
SWORD errorpos; SWORD errorpos;
SWORD error_recsize; SWORD error_recsize;
char *load_statement; /* to (re)load updatable individual rows */
Int4 from_pos;
Int4 where_pos;
}; };
#define SC_get_conn(a) (a->hdbc) #define SC_get_conn(a) (a->hdbc)
#define SC_set_Result(a, b) (a->result = a->curres = b) #define SC_set_Result(a, b) (a->result = a->curres = b)
#define SC_get_Result(a) (a->result) #define SC_get_Result(a) (a->result)
#define SC_set_Curres(a, b) (a->curres = b)
#define SC_get_Curres(a) (a->curres) #define SC_get_Curres(a) (a->curres)
/* options for SC_free_params() */ /* options for SC_free_params() */
......
...@@ -30,6 +30,19 @@ struct TupleNode_ ...@@ -30,6 +30,19 @@ struct TupleNode_
TupleField tuple[1]; TupleField tuple[1];
}; };
/* keyset(TID + OID) info */
struct KeySet_
{
UWORD status;
UWORD offset;
UDWORD blocknum;
UDWORD oid;
};
#define KEYSET_INFO_PUBLIC 0x0f
#define DRV_SELF_ADDED (1L << 4)
#define DRV_SELF_DELETED (1L << 5)
#define DRV_SELF_UPDATED (1L << 6)
/* 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()
if appropriate for the datatype (used by SQLGetTypeInfo). if appropriate for the datatype (used by SQLGetTypeInfo).
......
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