Commit 3c16d095 authored by Hiroshi Inoue's avatar Hiroshi Inoue

The version is now 7.01.0010.

1) Handle parameter array.
2) Allow re-use of the connection handle after SQLDisconnect.
3) Reject NULL if no indicator specified.
4) Improve the handling of '_' in table name.
5) Unify internal begin/commit/abort operations.
6) Change SQLTables() to return null not "" for the
   table_owner.
7) Fix a bug about parameter handling reported by Benoit Menendez.
8) Add cast in handling ODBC date/time escape sequences.
9) Fix a bug about cache_size handing in declare/fetch mode.

[ODBC3.0 related]
10) Improve the handling of descriptor handles(ODBC3.0).
11) Improve the type handling of some types for ODBC3.0.

[Thanks to Marcelo Aceto for his useful patches]
12) Allow nested ODBC escape.
13) Allow changing autocommit on/off inside the transaction
    block.
14) Improve the handling of ODBC scalar functions.
parent b6db89a0
...@@ -134,6 +134,8 @@ PGAPI_BindParameter( ...@@ -134,6 +134,8 @@ PGAPI_BindParameter(
stmt->parameters[ipar].EXEC_buffer = NULL; stmt->parameters[ipar].EXEC_buffer = NULL;
} }
if (pcbValue && stmt->options.param_offset_ptr)
pcbValue += (*stmt->options.param_offset_ptr >> 2);
/* Data at exec macro only valid for C char/binary data */ /* Data at exec macro only valid for C char/binary data */
if (pcbValue && (*pcbValue == SQL_DATA_AT_EXEC || if (pcbValue && (*pcbValue == SQL_DATA_AT_EXEC ||
*pcbValue <= SQL_LEN_DATA_AT_EXEC_OFFSET)) *pcbValue <= SQL_LEN_DATA_AT_EXEC_OFFSET))
......
...@@ -309,12 +309,6 @@ CC_Destructor(ConnectionClass *self) ...@@ -309,12 +309,6 @@ CC_Destructor(ConnectionClass *self)
mylog("after CC_Cleanup\n"); mylog("after CC_Cleanup\n");
#ifdef MULTIBYTE
if (self->client_encoding)
free(self->client_encoding);
if (self->server_encoding)
free(self->server_encoding);
#endif /* MULTIBYTE */
/* Free up statement holders */ /* Free up statement holders */
if (self->stmts) if (self->stmts)
{ {
...@@ -323,23 +317,6 @@ CC_Destructor(ConnectionClass *self) ...@@ -323,23 +317,6 @@ CC_Destructor(ConnectionClass *self)
} }
mylog("after free statement holders\n"); mylog("after free statement holders\n");
/* Free cached table info */
if (self->col_info)
{
int i;
for (i = 0; i < self->ntables; i++)
{
if (self->col_info[i]->result) /* Free the SQLColumns
* result structure */
QR_Destructor(self->col_info[i]->result);
free(self->col_info[i]);
}
free(self->col_info);
}
free(self); free(self);
mylog("exit CC_Destructor\n"); mylog("exit CC_Destructor\n");
...@@ -380,6 +357,59 @@ CC_clear_error(ConnectionClass *self) ...@@ -380,6 +357,59 @@ CC_clear_error(ConnectionClass *self)
} }
/*
* Used to begin a transaction.
*/
char
CC_begin(ConnectionClass *self)
{
char ret = TRUE;
if (!CC_is_in_trans(self))
{
QResultClass *res = CC_send_query(self, "BEGIN", NULL);
mylog("CC_begin: sending BEGIN!\n");
if (res != NULL)
{
ret = (!QR_aborted(res) && QR_command_successful(res));
QR_Destructor(res);
if (ret)
CC_set_in_trans(self);
}
else
ret = FALSE;
}
return ret;
}
/*
* Used to commit a transaction.
* We are almost always in the middle of a transaction.
*/
char
CC_commit(ConnectionClass *self)
{
char ret = FALSE;
if (CC_is_in_trans(self))
{
QResultClass *res = CC_send_query(self, "COMMIT", NULL);
mylog("CC_commit: sending COMMIT!\n");
CC_set_no_trans(self);
if (res != NULL)
{
ret = QR_command_successful(res);
QR_Destructor(res);
}
else
ret = FALSE;
}
return ret;
}
/* /*
* Used to cancel a transaction. * Used to cancel a transaction.
* We are almost always in the middle of a transaction. * We are almost always in the middle of a transaction.
...@@ -387,22 +417,17 @@ CC_clear_error(ConnectionClass *self) ...@@ -387,22 +417,17 @@ CC_clear_error(ConnectionClass *self)
char char
CC_abort(ConnectionClass *self) CC_abort(ConnectionClass *self)
{ {
QResultClass *res;
if (CC_is_in_trans(self)) if (CC_is_in_trans(self))
{ {
res = NULL; QResultClass *res = CC_send_query(self, "ROLLBACK", NULL);
mylog("CC_abort: sending ABORT!\n"); mylog("CC_abort: sending ABORT!\n");
res = CC_send_query(self, "ABORT", NULL);
CC_set_no_trans(self); CC_set_no_trans(self);
if (res != NULL) if (res != NULL)
QR_Destructor(res); QR_Destructor(res);
else else
return FALSE; return FALSE;
} }
return TRUE; return TRUE;
...@@ -461,6 +486,37 @@ CC_cleanup(ConnectionClass *self) ...@@ -461,6 +486,37 @@ CC_cleanup(ConnectionClass *self)
} }
#endif #endif
self->status = CONN_NOT_CONNECTED;
self->transact_status = CONN_IN_AUTOCOMMIT;
memset(&self->connInfo, 0, sizeof(ConnInfo));
#ifdef DRIVER_CURSOR_IMPLEMENT
self->connInfo.updatable_cursors = 1;
#endif /* DRIVER_CURSOR_IMPLEMENT */
memcpy(&(self->connInfo.drivers), &globals, sizeof(globals));
#ifdef MULTIBYTE
if (self->client_encoding)
free(self->client_encoding);
self->client_encoding = NULL;
if (self->server_encoding)
free(self->server_encoding);
self->server_encoding = NULL;
#endif /* MULTIBYTE */
/* Free cached table info */
if (self->col_info)
{
int i;
for (i = 0; i < self->ntables; i++)
{
if (self->col_info[i]->result) /* Free the SQLColumns result structure */
QR_Destructor(self->col_info[i]->result);
free(self->col_info[i]);
}
free(self->col_info);
self->col_info = NULL;
}
self->ntables = 0;
mylog("exit CC_Cleanup\n"); mylog("exit CC_Cleanup\n");
return TRUE; return TRUE;
} }
...@@ -516,7 +572,6 @@ md5_auth_send(ConnectionClass *self, const char *salt) ...@@ -516,7 +572,6 @@ md5_auth_send(ConnectionClass *self, const char *salt)
ConnInfo *ci = &(self->connInfo); ConnInfo *ci = &(self->connInfo);
SocketClass *sock = self->sock; SocketClass *sock = self->sock;
mylog("MD5 user=%s password=%s\n", ci->username, ci->password);
if (!(pwd1 = malloc(MD5_PASSWD_LEN + 1))) if (!(pwd1 = malloc(MD5_PASSWD_LEN + 1)))
return 1; return 1;
if (!EncryptMD5(ci->password, ci->username, strlen(ci->username), pwd1)) if (!EncryptMD5(ci->password, ci->username, strlen(ci->username), pwd1))
...@@ -601,9 +656,10 @@ CC_connect(ConnectionClass *self, char do_password) ...@@ -601,9 +656,10 @@ CC_connect(ConnectionClass *self, char do_password)
ci->drivers.conn_settings, ci->drivers.conn_settings,
encoding ? encoding : ""); encoding ? encoding : "");
#else #else
qlog(" extra_systable_prefixes='%s', conn_settings='%s'\n", qlog(" extra_systable_prefixes='%s', conn_settings='%s', protocol='%s'\n",
ci->drivers.extra_systable_prefixes, ci->drivers.extra_systable_prefixes,
ci->drivers.conn_settings); ci->drivers.conn_settings,
ci->protocol);
#endif #endif
if (self->status != CONN_NOT_CONNECTED) if (self->status != CONN_NOT_CONNECTED)
...@@ -1037,7 +1093,8 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi) ...@@ -1037,7 +1093,8 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi)
ReadyToReturn, ReadyToReturn,
tuples_return = FALSE, tuples_return = FALSE,
query_completed = FALSE, query_completed = FALSE,
before_64 = PG_VERSION_LT(self, 6.4); before_64 = PG_VERSION_LT(self, 6.4),
used_passed_result_object = FALSE;
/* ERROR_MSG_LENGTH is suffcient */ /* ERROR_MSG_LENGTH is suffcient */
static char msgbuffer[ERROR_MSG_LENGTH + 1]; static char msgbuffer[ERROR_MSG_LENGTH + 1];
...@@ -1289,6 +1346,7 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi) ...@@ -1289,6 +1346,7 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi)
else else
{ /* next fetch, so reuse an existing result */ { /* next fetch, so reuse an existing result */
used_passed_result_object = TRUE;
/* /*
* called from QR_next_tuple and must return * called from QR_next_tuple and must return
* immediately. * immediately.
...@@ -1373,9 +1431,7 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi) ...@@ -1373,9 +1431,7 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi)
QR_Destructor(res); QR_Destructor(res);
if (result_in && retres != result_in) if (result_in && retres != result_in)
{ {
if (qi && qi->result_in) if (!used_passed_result_object)
;
else
QR_Destructor(result_in); QR_Destructor(result_in);
} }
return retres; return retres;
......
...@@ -292,6 +292,8 @@ ConnectionClass *CC_Constructor(void); ...@@ -292,6 +292,8 @@ ConnectionClass *CC_Constructor(void);
char CC_Destructor(ConnectionClass *self); char CC_Destructor(ConnectionClass *self);
int CC_cursor_count(ConnectionClass *self); int CC_cursor_count(ConnectionClass *self);
char CC_cleanup(ConnectionClass *self); char CC_cleanup(ConnectionClass *self);
char CC_begin(ConnectionClass *self);
char CC_commit(ConnectionClass *self);
char CC_abort(ConnectionClass *self); char CC_abort(ConnectionClass *self);
int CC_set_translation(ConnectionClass *self); int CC_set_translation(ConnectionClass *self);
char CC_connect(ConnectionClass *self, char do_password); char CC_connect(ConnectionClass *self, char do_password);
......
This diff is collapsed.
...@@ -18,6 +18,10 @@ ...@@ -18,6 +18,10 @@
#define COPY_RESULT_TRUNCATED 3 #define COPY_RESULT_TRUNCATED 3
#define COPY_GENERAL_ERROR 4 #define COPY_GENERAL_ERROR 4
#define COPY_NO_DATA_FOUND 5 #define COPY_NO_DATA_FOUND 5
/* convert_escape results */
#define CONVERT_ESCAPE_OK 0
#define CONVERT_ESCAPE_OVERFLOW 1
#define CONVERT_ESCAPE_ERROR 2
typedef struct typedef struct
{ {
...@@ -35,7 +39,8 @@ int copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, I ...@@ -35,7 +39,8 @@ int copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, I
PTR rgbValue, SDWORD cbValueMax, SDWORD *pcbValue); PTR rgbValue, SDWORD cbValueMax, SDWORD *pcbValue);
int copy_statement_with_parameters(StatementClass *stmt); int copy_statement_with_parameters(StatementClass *stmt);
char *convert_escape(char *value); int convert_escape(const char *value, StatementClass *stmt,
int *npos, int *stsize, const char **val_resume);
BOOL convert_money(const char *s, char *sout, size_t soutmax); BOOL convert_money(const char *s, char *sout, size_t soutmax);
char parse_datetime(char *buf, SIMPLE_TIME *st); char parse_datetime(char *buf, SIMPLE_TIME *st);
int convert_linefeeds(const char *s, char *dst, size_t max, BOOL *changed); int convert_linefeeds(const char *s, char *dst, size_t max, BOOL *changed);
......
...@@ -233,6 +233,9 @@ PGAPI_Error( ...@@ -233,6 +233,9 @@ PGAPI_Error(
case STMT_INVALID_CURSOR_POSITION: case STMT_INVALID_CURSOR_POSITION:
strcpy(szSqlState, "S1109"); strcpy(szSqlState, "S1109");
break; break;
case STMT_RETURN_NULL_WITHOUT_INDICATOR:
strcpy(szSqlState, "22002");
break;
case STMT_VALUE_OUT_OF_RANGE: case STMT_VALUE_OUT_OF_RANGE:
strcpy(szSqlState, "22003"); strcpy(szSqlState, "22003");
break; break;
...@@ -376,6 +379,9 @@ PGAPI_Error( ...@@ -376,6 +379,9 @@ PGAPI_Error(
case STMT_NOT_IMPLEMENTED_ERROR: case STMT_NOT_IMPLEMENTED_ERROR:
strcpy(szSqlState, "S1C00"); strcpy(szSqlState, "S1C00");
break; break;
case STMT_RETURN_NULL_WITHOUT_INDICATOR:
strcpy(szSqlState, "22002");
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"); strcpy(szSqlState, "22003");
......
...@@ -196,7 +196,7 @@ PGAPI_Execute( ...@@ -196,7 +196,7 @@ PGAPI_Execute(
StatementClass *stmt = (StatementClass *) hstmt; StatementClass *stmt = (StatementClass *) hstmt;
ConnectionClass *conn; ConnectionClass *conn;
int i, int i,
retval; retval, start_row, end_row;
mylog("%s: entering...\n", func); mylog("%s: entering...\n", func);
...@@ -215,7 +215,10 @@ PGAPI_Execute( ...@@ -215,7 +215,10 @@ PGAPI_Execute(
if (stmt->prepare && stmt->status == STMT_PREMATURE) if (stmt->prepare && stmt->status == STMT_PREMATURE)
{ {
if (stmt->inaccurate_result) if (stmt->inaccurate_result)
{
stmt->exec_current_row = -1;
SC_recycle_statement(stmt); SC_recycle_statement(stmt);
}
else else
{ {
stmt->status = STMT_FINISHED; stmt->status = STMT_FINISHED;
...@@ -278,6 +281,35 @@ PGAPI_Execute( ...@@ -278,6 +281,35 @@ PGAPI_Execute(
return SQL_ERROR; return SQL_ERROR;
} }
if (start_row = stmt->exec_start_row, start_row < 0)
start_row = 0;
if (end_row = stmt->exec_end_row, end_row < 0)
end_row = stmt->options.paramset_size - 1;
if (stmt->exec_current_row < 0)
stmt->exec_current_row = start_row;
if (stmt->exec_current_row == start_row)
{
if (stmt->options.param_processed_ptr)
*stmt->options.param_processed_ptr = 0;
}
next_param_row:
#if (ODBCVER >= 0x0300)
if (stmt->options.param_operation_ptr)
{
while (stmt->options.param_operation_ptr[stmt->exec_current_row] == SQL_PARAM_IGNORE)
{
if (stmt->options.param_status_ptr)
stmt->options.param_status_ptr[stmt->exec_current_row] = SQL_PARAM_UNUSED;
if (stmt->exec_current_row >= end_row)
{
stmt->exec_current_row = -1;
return SQL_SUCCESS;
}
++stmt->exec_current_row;
}
}
#endif /* ODBCVER */
/* /*
* Check if statement has any data-at-execute parameters when it is * Check if statement has any data-at-execute parameters when it is
* not in SC_pre_execute. * not in SC_pre_execute.
...@@ -289,17 +321,27 @@ PGAPI_Execute( ...@@ -289,17 +321,27 @@ PGAPI_Execute(
* execute of this statement? Therefore check for params and * execute of this statement? Therefore check for params and
* re-copy. * re-copy.
*/ */
UInt4 offset = stmt->options.param_offset_ptr ? *stmt->options.param_offset_ptr : 0;
Int4 bind_size = stmt->options.param_bind_type;
Int4 current_row = stmt->exec_current_row < 0 ? 0 : stmt->exec_current_row;
stmt->data_at_exec = -1; stmt->data_at_exec = -1;
for (i = 0; i < stmt->parameters_allocated; i++) for (i = 0; i < stmt->parameters_allocated; i++)
{ {
Int4 *pcVal = stmt->parameters[i].used; Int4 *pcVal = stmt->parameters[i].used;
if (pcVal && (*pcVal == SQL_DATA_AT_EXEC || *pcVal <= SQL_LEN_DATA_AT_EXEC_OFFSET))
stmt->parameters[i].data_at_exec = TRUE;
else
stmt->parameters[i].data_at_exec = FALSE; stmt->parameters[i].data_at_exec = FALSE;
if (pcVal)
{
if (bind_size > 0)
pcVal = (Int4 *)((char *)pcVal + offset + bind_size * current_row);
else
pcVal = (Int4 *)((char *)pcVal + offset + sizeof(SDWORD) * current_row);
if (*pcVal == SQL_DATA_AT_EXEC || *pcVal <= SQL_LEN_DATA_AT_EXEC_OFFSET)
stmt->parameters[i].data_at_exec = TRUE;
}
/* Check for data at execution parameters */ /* Check for data at execution parameters */
if (stmt->parameters[i].data_at_exec == TRUE) if (stmt->parameters[i].data_at_exec)
{ {
if (stmt->data_at_exec < 0) if (stmt->data_at_exec < 0)
stmt->data_at_exec = 1; stmt->data_at_exec = 1;
...@@ -333,12 +375,45 @@ PGAPI_Execute( ...@@ -333,12 +375,45 @@ PGAPI_Execute(
mylog(" stmt_with_params = '%s'\n", stmt->stmt_with_params); mylog(" stmt_with_params = '%s'\n", stmt->stmt_with_params);
if (!stmt->inaccurate_result || !conn->connInfo.disallow_premature)
{
retval = SC_execute(stmt);
if (retval != SQL_ERROR)
{
if (stmt->options.param_processed_ptr)
(*stmt->options.param_processed_ptr)++;
}
#if (ODBCVER >= 0x0300)
if (stmt->options.param_status_ptr)
{
switch (retval)
{
case SQL_SUCCESS:
stmt->options.param_status_ptr[stmt->exec_current_row] = SQL_PARAM_SUCCESS;
break;
case SQL_SUCCESS_WITH_INFO:
stmt->options.param_status_ptr[stmt->exec_current_row] = SQL_PARAM_SUCCESS_WITH_INFO;
break;
default:
stmt->options.param_status_ptr[stmt->exec_current_row] = SQL_PARAM_ERROR;
break;
}
}
#endif /* ODBCVER */
if (retval == SQL_ERROR ||
stmt->inaccurate_result ||
stmt->exec_current_row >= end_row)
{
stmt->exec_current_row = -1;
return retval;
}
stmt->exec_current_row++;
goto next_param_row;
}
/* /*
* Get the field info for the prepared query using dummy backward * Get the field info for the prepared query using dummy backward
* fetch. * fetch.
*/ */
if (stmt->inaccurate_result && conn->connInfo.disallow_premature)
{
if (SC_is_pre_executable(stmt)) if (SC_is_pre_executable(stmt))
{ {
BOOL in_trans = CC_is_in_trans(conn); BOOL in_trans = CC_is_in_trans(conn);
...@@ -350,12 +425,7 @@ PGAPI_Execute( ...@@ -350,12 +425,7 @@ PGAPI_Execute(
begin_included = TRUE; begin_included = TRUE;
else if (!in_trans) else if (!in_trans)
{ {
res = CC_send_query(conn, "BEGIN", NULL); if (issued_begin = CC_begin(conn), !issued_begin)
if (res && !QR_aborted(res))
issued_begin = TRUE;
if (res)
QR_Destructor(res);
if (!issued_begin)
{ {
stmt->errornumber = STMT_EXEC_ERROR; stmt->errornumber = STMT_EXEC_ERROR;
stmt->errormsg = "Handle prepare error"; stmt->errormsg = "Handle prepare error";
...@@ -377,12 +447,7 @@ PGAPI_Execute( ...@@ -377,12 +447,7 @@ PGAPI_Execute(
if (CC_is_in_autocommit(conn)) if (CC_is_in_autocommit(conn))
{ {
if (issued_begin) if (issued_begin)
{ CC_commit(conn);
res = CC_send_query(conn, "COMMIT", NULL);
CC_set_no_trans(conn);
if (res)
QR_Destructor(res);
}
else if (!in_trans && begin_included) else if (!in_trans && begin_included)
CC_set_no_trans(conn); CC_set_no_trans(conn);
} }
...@@ -392,9 +457,6 @@ PGAPI_Execute( ...@@ -392,9 +457,6 @@ PGAPI_Execute(
} }
else else
return SQL_SUCCESS; return SQL_SUCCESS;
}
return SC_execute(stmt);
} }
...@@ -659,21 +721,7 @@ PGAPI_ParamData( ...@@ -659,21 +721,7 @@ PGAPI_ParamData(
/* commit transaction if needed */ /* commit transaction if needed */
if (!ci->drivers.use_declarefetch && CC_is_in_autocommit(stmt->hdbc)) if (!ci->drivers.use_declarefetch && CC_is_in_autocommit(stmt->hdbc))
{ {
QResultClass *res; if (!CC_commit(stmt->hdbc))
char ok;
res = CC_send_query(stmt->hdbc, "COMMIT", NULL);
if (!res)
{
stmt->errormsg = "Could not commit (in-line) a transaction";
stmt->errornumber = STMT_EXEC_ERROR;
SC_log_error(func, "", stmt);
return SQL_ERROR;
}
ok = QR_command_successful(res);
CC_set_no_trans(stmt->hdbc);
QR_Destructor(res);
if (!ok)
{ {
stmt->errormsg = "Could not commit (in-line) a transaction"; stmt->errormsg = "Could not commit (in-line) a transaction";
stmt->errornumber = STMT_EXEC_ERROR; stmt->errornumber = STMT_EXEC_ERROR;
...@@ -687,13 +735,47 @@ PGAPI_ParamData( ...@@ -687,13 +735,47 @@ PGAPI_ParamData(
/* Done, now copy the params and then execute the statement */ /* Done, now copy the params and then execute the statement */
if (stmt->data_at_exec == 0) if (stmt->data_at_exec == 0)
{ {
int end_row;
retval = copy_statement_with_parameters(stmt); retval = copy_statement_with_parameters(stmt);
if (retval != SQL_SUCCESS) if (retval != SQL_SUCCESS)
return retval; return retval;
stmt->current_exec_param = -1; stmt->current_exec_param = -1;
return SC_execute(stmt); retval = SC_execute(stmt);
if (retval != SQL_ERROR)
{
if (stmt->options.param_processed_ptr)
(*stmt->options.param_processed_ptr)++;
}
#if (ODBCVER >= 0x0300)
if (stmt->options.param_status_ptr)
{
switch (retval)
{
case SQL_SUCCESS:
stmt->options.param_status_ptr[stmt->exec_current_row] = SQL_PARAM_SUCCESS;
break;
case SQL_SUCCESS_WITH_INFO:
stmt->options.param_status_ptr[stmt->exec_current_row] = SQL_PARAM_SUCCESS_WITH_INFO;
break;
default:
stmt->options.param_status_ptr[stmt->exec_current_row] = SQL_PARAM_ERROR;
break;
}
}
#endif /* ODBCVER */
if (stmt->exec_end_row < 0)
end_row = stmt->options.paramset_size - 1;
if (retval == SQL_ERROR ||
stmt->exec_current_row >= end_row)
{
stmt->exec_current_row = -1;
return retval;
}
stmt->exec_current_row++;
return PGAPI_Execute(stmt);
} }
/* /*
...@@ -705,7 +787,7 @@ PGAPI_ParamData( ...@@ -705,7 +787,7 @@ PGAPI_ParamData(
/* At least 1 data at execution parameter, so Fill in the token value */ /* At least 1 data at execution parameter, so Fill in the token value */
for (; i < stmt->parameters_allocated; i++) for (; i < stmt->parameters_allocated; i++)
{ {
if (stmt->parameters[i].data_at_exec == TRUE) if (stmt->parameters[i].data_at_exec)
{ {
stmt->data_at_exec--; stmt->data_at_exec--;
stmt->current_exec_param = i; stmt->current_exec_param = i;
...@@ -780,28 +862,13 @@ PGAPI_PutData( ...@@ -780,28 +862,13 @@ PGAPI_PutData(
/* begin transaction if needed */ /* begin transaction if needed */
if (!CC_is_in_trans(stmt->hdbc)) if (!CC_is_in_trans(stmt->hdbc))
{ {
QResultClass *res; if (!CC_begin(stmt->hdbc))
char ok;
res = CC_send_query(stmt->hdbc, "BEGIN", NULL);
if (!res)
{
stmt->errormsg = "Could not begin (in-line) a transaction";
stmt->errornumber = STMT_EXEC_ERROR;
SC_log_error(func, "", stmt);
return SQL_ERROR;
}
ok = QR_command_successful(res);
QR_Destructor(res);
if (!ok)
{ {
stmt->errormsg = "Could not begin (in-line) a transaction"; stmt->errormsg = "Could not begin (in-line) a transaction";
stmt->errornumber = STMT_EXEC_ERROR; stmt->errornumber = STMT_EXEC_ERROR;
SC_log_error(func, "", stmt); SC_log_error(func, "", stmt);
return SQL_ERROR; return SQL_ERROR;
} }
CC_set_in_trans(stmt->hdbc);
} }
/* store the oid */ /* store the oid */
......
...@@ -36,6 +36,9 @@ ...@@ -36,6 +36,9 @@
#include "misc.h" #include "misc.h"
#include "pgtypes.h" #include "pgtypes.h"
#include "pgapifunc.h" #include "pgapifunc.h"
#ifdef MULTIBYTE
#include "multibyte.h"
#endif
/* Trigger related stuff for SQLForeign Keys */ /* Trigger related stuff for SQLForeign Keys */
...@@ -567,6 +570,9 @@ PGAPI_GetInfo( ...@@ -567,6 +570,9 @@ PGAPI_GetInfo(
break; break;
case SQL_SEARCH_PATTERN_ESCAPE: /* ODBC 1.0 */ case SQL_SEARCH_PATTERN_ESCAPE: /* ODBC 1.0 */
if (PG_VERSION_GE(conn, 6.5))
p = "\\";
else
p = ""; p = "";
break; break;
...@@ -1365,7 +1371,8 @@ PGAPI_Tables( ...@@ -1365,7 +1371,8 @@ PGAPI_Tables(
{ {
row = (TupleNode *) malloc(sizeof(TupleNode) + (5 - 1) *sizeof(TupleField)); row = (TupleNode *) malloc(sizeof(TupleNode) + (5 - 1) *sizeof(TupleField));
set_tuplefield_string(&row->tuple[0], ""); /*set_tuplefield_string(&row->tuple[0], "");*/
set_tuplefield_null(&row->tuple[0]);
/* /*
* I have to hide the table owner from Access, otherwise it * I have to hide the table owner from Access, otherwise it
...@@ -1378,7 +1385,8 @@ PGAPI_Tables( ...@@ -1378,7 +1385,8 @@ PGAPI_Tables(
mylog("%s: table_name = '%s'\n", func, table_name); mylog("%s: table_name = '%s'\n", func, table_name);
set_tuplefield_string(&row->tuple[1], ""); /* set_tuplefield_string(&row->tuple[1], ""); */
set_tuplefield_null(&row->tuple[1]);
set_tuplefield_string(&row->tuple[2], table_name); set_tuplefield_string(&row->tuple[2], table_name);
set_tuplefield_string(&row->tuple[3], systable ? "SYSTEM TABLE" : (view ? "VIEW" : "TABLE")); set_tuplefield_string(&row->tuple[3], systable ? "SYSTEM TABLE" : (view ? "VIEW" : "TABLE"));
set_tuplefield_string(&row->tuple[4], ""); set_tuplefield_string(&row->tuple[4], "");
...@@ -1413,6 +1421,66 @@ PGAPI_Tables( ...@@ -1413,6 +1421,66 @@ PGAPI_Tables(
} }
/*
* PostgreSQL needs 2 '\\' to escape '_' and '%'.
*/
static int
reallyEscapeCatalogEscapes(const char *src, int srclen, char *dest, int dst_len)
{
int i, outlen;
const char *in;
BOOL escape_in = FALSE;
if (srclen == SQL_NULL_DATA)
{
dest[0] = '\0';
return STRCPY_NULL;
}
else if (srclen == SQL_NTS)
srclen = strlen(src);
if (srclen <= 0)
return STRCPY_FAIL;
#ifdef MULTIBYTE
multibyte_init();
#endif
for (i = 0, in = src, outlen = 0; i < srclen && outlen < dst_len; i++, in++)
{
#ifdef MULTIBYTE
if (multibyte_char_check(*in) != 0)
{
dest[outlen++] = *in;
continue;
}
#endif
if (escape_in)
{
switch (*in)
{
case '%':
case '_':
dest[outlen++] = '\\'; /* needs 1 more */
break;
default:
dest[outlen++] = '\\';
if (outlen < dst_len)
dest[outlen++] = '\\';
if (outlen < dst_len)
dest[outlen++] = '\\';
break;
}
}
if (*in == '\\')
escape_in = TRUE;
else
escape_in = FALSE;
if (outlen < dst_len)
dest[outlen++] = *in;
}
if (outlen < dst_len)
dest[outlen] = '\0';
return outlen;
}
RETCODE SQL_API RETCODE SQL_API
PGAPI_Columns( PGAPI_Columns(
HSTMT hstmt, HSTMT hstmt,
...@@ -1423,7 +1491,8 @@ PGAPI_Columns( ...@@ -1423,7 +1491,8 @@ PGAPI_Columns(
UCHAR FAR * szTableName, UCHAR FAR * szTableName,
SWORD cbTableName, SWORD cbTableName,
UCHAR FAR * szColumnName, UCHAR FAR * szColumnName,
SWORD cbColumnName) SWORD cbColumnName,
UWORD flag)
{ {
static char *func = "PGAPI_Columns"; static char *func = "PGAPI_Columns";
StatementClass *stmt = (StatementClass *) hstmt; StatementClass *stmt = (StatementClass *) hstmt;
...@@ -1476,9 +1545,22 @@ PGAPI_Columns( ...@@ -1476,9 +1545,22 @@ PGAPI_Columns(
" and c.oid= a.attrelid and a.atttypid = t.oid and (a.attnum > 0)", " and c.oid= a.attrelid and a.atttypid = t.oid and (a.attnum > 0)",
PG_VERSION_LE(conn, 6.2) ? "a.attlen" : "a.atttypmod"); PG_VERSION_LE(conn, 6.2) ? "a.attlen" : "a.atttypmod");
my_strcat(columns_query, " and c.relname like '%.*s'", szTableName, cbTableName); if ((flag & PODBC_NOT_SEARCH_PATTERN) != 0)
{
my_strcat(columns_query, " and c.relname = '%.*s'", szTableName, cbTableName);
my_strcat(columns_query, " and u.usename = '%.*s'", szTableOwner, cbTableOwner);
my_strcat(columns_query, " and a.attname = '%.*s'", szColumnName, cbColumnName);
}
else
{
char esc_table_name[MAX_TABLE_LEN * 2];
int escTbnamelen;
escTbnamelen = reallyEscapeCatalogEscapes(szTableName, cbTableName, esc_table_name, sizeof(esc_table_name));
my_strcat(columns_query, " and c.relname like '%.*s'", esc_table_name, escTbnamelen);
my_strcat(columns_query, " and u.usename like '%.*s'", szTableOwner, cbTableOwner); my_strcat(columns_query, " and u.usename like '%.*s'", szTableOwner, cbTableOwner);
my_strcat(columns_query, " and a.attname like '%.*s'", szColumnName, cbColumnName); my_strcat(columns_query, " and a.attname like '%.*s'", szColumnName, cbColumnName);
}
/* /*
* give the output in the order the columns were defined when the * give the output in the order the columns were defined when the
...@@ -1730,7 +1812,7 @@ PGAPI_Columns( ...@@ -1730,7 +1812,7 @@ PGAPI_Columns(
*---------- *----------
*/ */
qlog("PGAPI_Columns: table='%s',field_name='%s',type=%d,sqltype=%d,name='%s'\n", qlog("PGAPI_Columns: table='%s',field_name='%s',type=%d,sqltype=%d,name='%s'\n",
table_name, field_name, field_type, pgtype_to_sqltype, field_type_name); table_name, field_name, field_type, pgtype_to_sqltype(stmt,field_type), field_type_name);
useStaticPrecision = TRUE; useStaticPrecision = TRUE;
...@@ -1892,8 +1974,10 @@ PGAPI_SpecialColumns( ...@@ -1892,8 +1974,10 @@ PGAPI_SpecialColumns(
"from pg_user u, pg_class c where " "from pg_user u, pg_class c where "
"u.usesysid = c.relowner"); "u.usesysid = c.relowner");
my_strcat(columns_query, " and c.relname like '%.*s'", szTableName, cbTableName); /* TableName cannot contain a string search pattern */
my_strcat(columns_query, " and u.usename like '%.*s'", szTableOwner, cbTableOwner); my_strcat(columns_query, " and c.relname = '%.*s'", szTableName, cbTableName);
/* SchemaName cannot contain a string search pattern */
my_strcat(columns_query, " and u.usename = '%.*s'", szTableOwner, cbTableOwner);
result = PGAPI_AllocStmt(stmt->hdbc, &hcol_stmt); result = PGAPI_AllocStmt(stmt->hdbc, &hcol_stmt);
...@@ -2114,8 +2198,11 @@ PGAPI_Statistics( ...@@ -2114,8 +2198,11 @@ PGAPI_Statistics(
* being shown. This would throw everything off. * being shown. This would throw everything off.
*/ */
col_stmt->internal = TRUE; col_stmt->internal = TRUE;
/*
* table_name parameter cannot contain a string search pattern.
*/
result = PGAPI_Columns(hcol_stmt, "", 0, "", 0, result = PGAPI_Columns(hcol_stmt, "", 0, "", 0,
table_name, (SWORD) strlen(table_name), "", 0); table_name, (SWORD) strlen(table_name), "", 0, PODBC_NOT_SEARCH_PATTERN);
col_stmt->internal = FALSE; col_stmt->internal = FALSE;
if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
...@@ -2725,9 +2812,7 @@ getClientTableName(ConnectionClass *conn, char *serverTableName, BOOL *nameAlloc ...@@ -2725,9 +2812,7 @@ getClientTableName(ConnectionClass *conn, char *serverTableName, BOOL *nameAlloc
continueExec = (continueExec && !bError); continueExec = (continueExec && !bError);
if (bError && CC_is_in_trans(conn)) if (bError && CC_is_in_trans(conn))
{ {
if (res = CC_send_query(conn, "abort", NULL), res) CC_abort(conn);
QR_Destructor(res);
CC_set_no_trans(conn);
bError = FALSE; bError = FALSE;
} }
/* restore the client encoding */ /* restore the client encoding */
...@@ -2811,9 +2896,7 @@ getClientColumnName(ConnectionClass *conn, const char *serverTableName, char *se ...@@ -2811,9 +2896,7 @@ getClientColumnName(ConnectionClass *conn, const char *serverTableName, char *se
continueExec = (continueExec && !bError); continueExec = (continueExec && !bError);
if (bError && CC_is_in_trans(conn)) if (bError && CC_is_in_trans(conn))
{ {
if (res = CC_send_query(conn, "abort", NULL), res) CC_abort(conn);
QR_Destructor(res);
CC_set_no_trans(conn);
bError = FALSE; bError = FALSE;
} }
/* restore the cleint encoding */ /* restore the cleint encoding */
...@@ -3647,7 +3730,7 @@ PGAPI_Procedures( ...@@ -3647,7 +3730,7 @@ PGAPI_Procedures(
" 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" ","
" 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);
res = CC_send_query(conn, proc_query, NULL); res = CC_send_query(conn, proc_query, NULL);
......
...@@ -85,7 +85,7 @@ SQLColumns(HSTMT StatementHandle, ...@@ -85,7 +85,7 @@ SQLColumns(HSTMT StatementHandle,
mylog("[SQLColumns]"); mylog("[SQLColumns]");
return PGAPI_Columns(StatementHandle, CatalogName, NameLength1, return PGAPI_Columns(StatementHandle, CatalogName, NameLength1,
SchemaName, NameLength2, TableName, NameLength3, SchemaName, NameLength2, TableName, NameLength3,
ColumnName, NameLength4); ColumnName, NameLength4, 0);
} }
...@@ -218,7 +218,7 @@ SQLFetch(HSTMT StatementHandle) ...@@ -218,7 +218,7 @@ SQLFetch(HSTMT StatementHandle)
RETCODE SQL_API RETCODE SQL_API
SQLFreeConnect(HDBC ConnectionHandle) SQLFreeConnect(HDBC ConnectionHandle)
{ {
mylog("[SQLFreeStmt]"); mylog("[SQLFreeConnect]");
return PGAPI_FreeConnect(ConnectionHandle); return PGAPI_FreeConnect(ConnectionHandle);
} }
......
This diff is collapsed.
...@@ -342,14 +342,12 @@ PGAPI_SetConnectOption( ...@@ -342,14 +342,12 @@ PGAPI_SetConnectOption(
break; break;
case SQL_AUTOCOMMIT: case SQL_AUTOCOMMIT:
if (vParam == SQL_AUTOCOMMIT_ON && CC_is_in_autocommit(conn))
break;
else if (vParam == SQL_AUTOCOMMIT_OFF && !CC_is_in_autocommit(conn))
break;
if (CC_is_in_trans(conn)) if (CC_is_in_trans(conn))
{ CC_commit(conn);
conn->errormsg = "Cannot switch commit mode while a transaction is in progress";
conn->errornumber = CONN_TRANSACT_IN_PROGRES;
CC_log_error(func, "", conn);
return SQL_ERROR;
}
mylog("PGAPI_SetConnectOption: AUTOCOMMIT: transact_status=%d, vparam=%d\n", conn->transact_status, vParam); mylog("PGAPI_SetConnectOption: AUTOCOMMIT: transact_status=%d, vparam=%d\n", conn->transact_status, vParam);
switch (vParam) switch (vParam)
...@@ -475,7 +473,7 @@ PGAPI_GetConnectOption( ...@@ -475,7 +473,7 @@ PGAPI_GetConnectOption(
break; break;
case SQL_TXN_ISOLATION: /* NOT SUPPORTED */ case SQL_TXN_ISOLATION: /* NOT SUPPORTED */
*((UDWORD *) pvParam) = SQL_TXN_SERIALIZABLE; *((UDWORD *) pvParam) = SQL_TXN_READ_COMMITTED;
break; break;
/* These options should be handled by driver manager */ /* These options should be handled by driver manager */
......
...@@ -742,7 +742,7 @@ parse_statement(StatementClass *stmt) ...@@ -742,7 +742,7 @@ parse_statement(StatementClass *stmt)
col_stmt->internal = TRUE; col_stmt->internal = TRUE;
result = PGAPI_Columns(hcol_stmt, "", 0, "", 0, result = PGAPI_Columns(hcol_stmt, "", 0, "", 0,
ti[i]->name, (SWORD) strlen(ti[i]->name), "", 0); ti[i]->name, (SWORD) strlen(ti[i]->name), "", 0, PODBC_NOT_SEARCH_PATTERN);
mylog(" Past PG_Columns\n"); mylog(" Past PG_Columns\n");
if (result == SQL_SUCCESS) if (result == SQL_SUCCESS)
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#define PODBC_NOT_SEARCH_PATTERN 1L
RETCODE SQL_API PGAPI_AllocConnect(HENV EnvironmentHandle, RETCODE SQL_API PGAPI_AllocConnect(HENV EnvironmentHandle,
HDBC FAR * ConnectionHandle); HDBC FAR * ConnectionHandle);
...@@ -25,7 +26,8 @@ RETCODE SQL_API PGAPI_Columns(HSTMT StatementHandle, ...@@ -25,7 +26,8 @@ RETCODE SQL_API PGAPI_Columns(HSTMT StatementHandle,
SQLCHAR *CatalogName, SQLSMALLINT NameLength1, SQLCHAR *CatalogName, SQLSMALLINT NameLength1,
SQLCHAR *SchemaName, SQLSMALLINT NameLength2, SQLCHAR *SchemaName, SQLSMALLINT NameLength2,
SQLCHAR *TableName, SQLSMALLINT NameLength3, SQLCHAR *TableName, SQLSMALLINT NameLength3,
SQLCHAR *ColumnName, SQLSMALLINT NameLength4); SQLCHAR *ColumnName, SQLSMALLINT NameLength4,
UWORD flag);
RETCODE SQL_API PGAPI_Connect(HDBC ConnectionHandle, RETCODE SQL_API PGAPI_Connect(HDBC ConnectionHandle,
SQLCHAR *ServerName, SQLSMALLINT NameLength1, SQLCHAR *ServerName, SQLSMALLINT NameLength1,
SQLCHAR *UserName, SQLSMALLINT NameLength2, SQLCHAR *UserName, SQLSMALLINT NameLength2,
......
...@@ -51,6 +51,7 @@ Int4 pgtypes_defined[] = { ...@@ -51,6 +51,7 @@ Int4 pgtypes_defined[] = {
PG_TYPE_BPCHAR, PG_TYPE_BPCHAR,
PG_TYPE_DATE, PG_TYPE_DATE,
PG_TYPE_TIME, PG_TYPE_TIME,
PG_TYPE_TIME_WITH_TMZONE,
PG_TYPE_DATETIME, PG_TYPE_DATETIME,
PG_TYPE_ABSTIME, PG_TYPE_ABSTIME,
PG_TYPE_TIMESTAMP, PG_TYPE_TIMESTAMP,
...@@ -227,7 +228,11 @@ pgtype_to_sqltype(StatementClass *stmt, Int4 type) ...@@ -227,7 +228,11 @@ pgtype_to_sqltype(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 (ODBCVER >= 0x0300)
return SQL_BIGINT;
#else
return SQL_CHAR; return SQL_CHAR;
#endif /* ODBCVER */
case PG_TYPE_NUMERIC: case PG_TYPE_NUMERIC:
return SQL_NUMERIC; return SQL_NUMERIC;
...@@ -273,7 +278,11 @@ pgtype_to_ctype(StatementClass *stmt, Int4 type) ...@@ -273,7 +278,11 @@ pgtype_to_ctype(StatementClass *stmt, Int4 type)
switch (type) switch (type)
{ {
case PG_TYPE_INT8: case PG_TYPE_INT8:
#if (ODBCVER >= 0x0300)
return SQL_C_SBIGINT;
#else
return SQL_C_CHAR; return SQL_C_CHAR;
#endif
case PG_TYPE_NUMERIC: case PG_TYPE_NUMERIC:
return SQL_C_CHAR; return SQL_C_CHAR;
case PG_TYPE_INT2: case PG_TYPE_INT2:
...@@ -287,13 +296,25 @@ pgtype_to_ctype(StatementClass *stmt, Int4 type) ...@@ -287,13 +296,25 @@ pgtype_to_ctype(StatementClass *stmt, Int4 type)
case PG_TYPE_FLOAT8: case PG_TYPE_FLOAT8:
return SQL_C_DOUBLE; return SQL_C_DOUBLE;
case PG_TYPE_DATE: case PG_TYPE_DATE:
#if (ODBCVER >= 0x0300)
return SQL_C_TYPE_DATE;
#else
return SQL_C_DATE; return SQL_C_DATE;
#endif /* ODBCVER */
case PG_TYPE_TIME: case PG_TYPE_TIME:
#if (ODBCVER >= 0x0300)
return SQL_C_TYPE_TIME;
#else
return SQL_C_TIME; return SQL_C_TIME;
#endif /* ODBCVER */
case PG_TYPE_ABSTIME: case PG_TYPE_ABSTIME:
case PG_TYPE_DATETIME: case PG_TYPE_DATETIME:
case PG_TYPE_TIMESTAMP: case PG_TYPE_TIMESTAMP:
#if (ODBCVER >= 0x0300)
return SQL_C_TYPE_TIMESTAMP;
#else
return SQL_C_TIMESTAMP; return SQL_C_TIMESTAMP;
#endif /* ODBCVER */
case PG_TYPE_MONEY: case PG_TYPE_MONEY:
return SQL_C_FLOAT; return SQL_C_FLOAT;
case PG_TYPE_BOOL: case PG_TYPE_BOOL:
...@@ -386,7 +407,7 @@ pgtype_to_name(StatementClass *stmt, Int4 type) ...@@ -386,7 +407,7 @@ pgtype_to_name(StatementClass *stmt, Int4 type)
static Int2 static Int2
getNumericScale(StatementClass *stmt, Int4 type, int col) getNumericScale(StatementClass *stmt, Int4 type, int col)
{ {
Int4 atttypmod; Int4 atttypmod = -1;
QResultClass *result; QResultClass *result;
ColumnInfoClass *flds; ColumnInfoClass *flds;
...@@ -405,11 +426,15 @@ getNumericScale(StatementClass *stmt, Int4 type, int col) ...@@ -405,11 +426,15 @@ getNumericScale(StatementClass *stmt, Int4 type, int col)
{ {
flds = result->fields; flds = result->fields;
if (flds) if (flds)
{
atttypmod = flds->atttypmod[col];
if (atttypmod < 0 && flds->adtsize[col] > 0)
return flds->adtsize[col]; return flds->adtsize[col];
else }
if (atttypmod < 0)
return PG_NUMERIC_MAX_SCALE; return PG_NUMERIC_MAX_SCALE;
} }
else
atttypmod = QR_get_atttypmod(result, col); atttypmod = QR_get_atttypmod(result, col);
if (atttypmod > -1) if (atttypmod > -1)
return (atttypmod & 0xffff); return (atttypmod & 0xffff);
...@@ -423,7 +448,7 @@ getNumericScale(StatementClass *stmt, Int4 type, int col) ...@@ -423,7 +448,7 @@ getNumericScale(StatementClass *stmt, Int4 type, int col)
static Int4 static Int4
getNumericPrecision(StatementClass *stmt, Int4 type, int col) getNumericPrecision(StatementClass *stmt, Int4 type, int col)
{ {
Int4 atttypmod; Int4 atttypmod = -1;
QResultClass *result; QResultClass *result;
ColumnInfoClass *flds; ColumnInfoClass *flds;
...@@ -442,16 +467,20 @@ getNumericPrecision(StatementClass *stmt, Int4 type, int col) ...@@ -442,16 +467,20 @@ getNumericPrecision(StatementClass *stmt, Int4 type, int col)
{ {
flds = result->fields; flds = result->fields;
if (flds) if (flds)
{
atttypmod = flds->atttypmod[col];
if (atttypmod < 0 && flds->adtsize[col] > 0)
return flds->adtsize[col]; return flds->adtsize[col];
else }
if (atttypmod < 0)
return PG_NUMERIC_MAX_PRECISION; return PG_NUMERIC_MAX_PRECISION;
} }
else
atttypmod = QR_get_atttypmod(result, col); atttypmod = QR_get_atttypmod(result, col);
if (atttypmod > -1) if (atttypmod > -1)
return (atttypmod >> 16) & 0xffff; return (atttypmod >> 16) & 0xffff;
else else
return (QR_get_display_size(result, col) >= 0 ? return (QR_get_display_size(result, col) > 0 ?
QR_get_display_size(result, col) : QR_get_display_size(result, col) :
PG_NUMERIC_MAX_PRECISION); PG_NUMERIC_MAX_PRECISION);
} }
...@@ -586,13 +615,19 @@ getTimestampPrecision(StatementClass *stmt, Int4 type, int col) ...@@ -586,13 +615,19 @@ getTimestampPrecision(StatementClass *stmt, Int4 type, int col)
fixed = 8; fixed = 8;
break; break;
case PG_TYPE_TIME_WITH_TMZONE: case PG_TYPE_TIME_WITH_TMZONE:
if (USE_ZONE)
fixed = 11; fixed = 11;
else
fixed = 8;
break; break;
case PG_TYPE_TIMESTAMP_NO_TMZONE: case PG_TYPE_TIMESTAMP_NO_TMZONE:
fixed = 19; fixed = 19;
break; break;
default: default:
if (USE_ZONE)
fixed = 22; fixed = 22;
else
fixed = 19;
break; break;
} }
scale = getTimestampScale(stmt, type, col); scale = getTimestampScale(stmt, type, col);
...@@ -677,6 +712,8 @@ pgtype_precision(StatementClass *stmt, Int4 type, int col, int handle_unknown_si ...@@ -677,6 +712,8 @@ pgtype_precision(StatementClass *stmt, Int4 type, int col, int handle_unknown_si
Int4 Int4
pgtype_display_size(StatementClass *stmt, Int4 type, int col, int handle_unknown_size_as) pgtype_display_size(StatementClass *stmt, Int4 type, int col, int handle_unknown_size_as)
{ {
int dsize;
switch (type) switch (type)
{ {
case PG_TYPE_INT2: case PG_TYPE_INT2:
...@@ -693,7 +730,8 @@ pgtype_display_size(StatementClass *stmt, Int4 type, int col, int handle_unknown ...@@ -693,7 +730,8 @@ pgtype_display_size(StatementClass *stmt, Int4 type, int col, int handle_unknown
return 20; /* signed: 19 digits + sign */ return 20; /* signed: 19 digits + sign */
case PG_TYPE_NUMERIC: case PG_TYPE_NUMERIC:
return getNumericPrecision(stmt, type, col) + 2; dsize = getNumericPrecision(stmt, type, col);
return dsize < 0 ? dsize : dsize + 2;
case PG_TYPE_MONEY: case PG_TYPE_MONEY:
return 15; /* ($9,999,999.99) */ return 15; /* ($9,999,999.99) */
...@@ -848,6 +886,7 @@ pgtype_auto_increment(StatementClass *stmt, Int4 type) ...@@ -848,6 +886,7 @@ pgtype_auto_increment(StatementClass *stmt, Int4 type)
case PG_TYPE_DATE: case PG_TYPE_DATE:
case PG_TYPE_TIME: case PG_TYPE_TIME:
case PG_TYPE_TIME_WITH_TMZONE:
case PG_TYPE_ABSTIME: case PG_TYPE_ABSTIME:
case PG_TYPE_DATETIME: case PG_TYPE_DATETIME:
case PG_TYPE_TIMESTAMP: case PG_TYPE_TIMESTAMP:
...@@ -1013,8 +1052,14 @@ sqltype_to_default_ctype(Int2 sqltype) ...@@ -1013,8 +1052,14 @@ sqltype_to_default_ctype(Int2 sqltype)
case SQL_LONGVARCHAR: case SQL_LONGVARCHAR:
case SQL_DECIMAL: case SQL_DECIMAL:
case SQL_NUMERIC: case SQL_NUMERIC:
#if (ODBCVER < 0x0300)
case SQL_BIGINT: case SQL_BIGINT:
return SQL_C_CHAR; return SQL_C_CHAR;
#else
return SQL_C_CHAR;
case SQL_BIGINT:
return SQL_C_SBIGINT;
#endif
case SQL_BIT: case SQL_BIT:
return SQL_C_BIT; return SQL_C_BIT;
...@@ -1041,13 +1086,25 @@ sqltype_to_default_ctype(Int2 sqltype) ...@@ -1041,13 +1086,25 @@ sqltype_to_default_ctype(Int2 sqltype)
return SQL_C_BINARY; return SQL_C_BINARY;
case SQL_DATE: case SQL_DATE:
#if (ODBCVER >= 0x0300)
return SQL_C_TYPE_DATE;
#else
return SQL_C_DATE; return SQL_C_DATE;
#endif /* ODBCVER */
case SQL_TIME: case SQL_TIME:
#if (ODBCVER >= 0x0300)
return SQL_C_TYPE_TIME;
#else
return SQL_C_TIME; return SQL_C_TIME;
#endif /* ODBCVER */
case SQL_TIMESTAMP: case SQL_TIMESTAMP:
#if (ODBCVER >= 0x0300)
return SQL_C_TYPE_TIMESTAMP;
#else
return SQL_C_TIMESTAMP; return SQL_C_TIMESTAMP;
#endif /* ODBCVER */
default: default:
/* should never happen */ /* should never happen */
...@@ -1091,12 +1148,21 @@ ctype_length(Int2 ctype) ...@@ -1091,12 +1148,21 @@ ctype_length(Int2 ctype)
return sizeof(UCHAR); return sizeof(UCHAR);
case SQL_C_DATE: case SQL_C_DATE:
#if (ODBCVER >= 0x0300)
case SQL_C_TYPE_DATE:
#endif /* ODBCVER */
return sizeof(DATE_STRUCT); return sizeof(DATE_STRUCT);
case SQL_C_TIME: case SQL_C_TIME:
#if (ODBCVER >= 0x0300)
case SQL_C_TYPE_TIME:
#endif /* ODBCVER */
return sizeof(TIME_STRUCT); return sizeof(TIME_STRUCT);
case SQL_C_TIMESTAMP: case SQL_C_TIMESTAMP:
#if (ODBCVER >= 0x0300)
case SQL_C_TYPE_TIMESTAMP:
#endif /* ODBCVER */
return sizeof(TIMESTAMP_STRUCT); return sizeof(TIMESTAMP_STRUCT);
case SQL_C_BINARY: case SQL_C_BINARY:
......
...@@ -96,4 +96,5 @@ char *pgtype_create_params(StatementClass *stmt, Int4 type); ...@@ -96,4 +96,5 @@ char *pgtype_create_params(StatementClass *stmt, Int4 type);
Int2 sqltype_to_default_ctype(Int2 sqltype); Int2 sqltype_to_default_ctype(Int2 sqltype);
Int4 ctype_length(Int2 ctype); Int4 ctype_length(Int2 ctype);
#define USE_ZONE FALSE
#endif #endif
...@@ -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.56 2001/11/05 17:46:38 momjian Exp $ * $Id: psqlodbc.h,v 1.57 2002/02/18 03:16:11 inoue Exp $
* *
*/ */
...@@ -72,6 +72,8 @@ typedef UInt4 Oid; ...@@ -72,6 +72,8 @@ typedef UInt4 Oid;
#ifndef WIN32 #ifndef WIN32
#define stricmp strcasecmp #define stricmp strcasecmp
#define strnicmp strncasecmp #define strnicmp strncasecmp
#else
#define snprintf _snprintf
#endif #endif
/* Driver stuff */ /* Driver stuff */
...@@ -85,7 +87,7 @@ typedef UInt4 Oid; ...@@ -85,7 +87,7 @@ typedef UInt4 Oid;
#define DBMS_NAME "PostgreSQL" #define DBMS_NAME "PostgreSQL"
#endif /* ODBCVER */ #endif /* ODBCVER */
#define POSTGRESDRIVERVERSION "07.01.0009" #define POSTGRESDRIVERVERSION "07.01.0010"
#ifdef WIN32 #ifdef WIN32
#if (ODBCVER >= 0x0300) #if (ODBCVER >= 0x0300)
......
...@@ -354,8 +354,8 @@ END ...@@ -354,8 +354,8 @@ END
// //
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 7,1,0,9 FILEVERSION 7,1,0,10
PRODUCTVERSION 7,1,0,9 PRODUCTVERSION 7,1,0,10
FILEFLAGSMASK 0x3L FILEFLAGSMASK 0x3L
#ifdef _DEBUG #ifdef _DEBUG
FILEFLAGS 0x1L FILEFLAGS 0x1L
...@@ -377,14 +377,14 @@ BEGIN ...@@ -377,14 +377,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.01.0009\0" VALUE "FileVersion", " 07.01.0010\0"
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.01.0009\0" VALUE "ProductVersion", " 07.01.0010\0"
VALUE "SpecialBuild", "\0" VALUE "SpecialBuild", "\0"
END END
END END
......
...@@ -279,7 +279,11 @@ QR_fetch_tuples(QResultClass *self, ConnectionClass *conn, char *cursor) ...@@ -279,7 +279,11 @@ QR_fetch_tuples(QResultClass *self, ConnectionClass *conn, char *cursor)
mylog("QR_fetch_tuples: past CI_read_fields: num_fields = %d\n", self->num_fields); mylog("QR_fetch_tuples: past CI_read_fields: num_fields = %d\n", self->num_fields);
if (fetch_cursor) if (fetch_cursor)
{
if (self->cache_size <= 0)
self->cache_size = ci->drivers.fetch_max;
tuple_size = self->cache_size; tuple_size = self->cache_size;
}
else else
tuple_size = TUPLE_MALLOC_INC; tuple_size = TUPLE_MALLOC_INC;
...@@ -359,17 +363,12 @@ QR_close(QResultClass *self) ...@@ -359,17 +363,12 @@ QR_close(QResultClass *self)
{ {
mylog("QResult: END transaction on conn=%u\n", self->conn); mylog("QResult: END transaction on conn=%u\n", self->conn);
res = CC_send_query(self->conn, "END", NULL); if (!CC_commit(self->conn))
CC_set_no_trans(self->conn);
if (res == NULL)
{ {
self->status = PGRES_FATAL_ERROR; self->status = PGRES_FATAL_ERROR;
QR_set_message(self, "Error ending transaction."); QR_set_message(self, "Error ending transaction.");
return FALSE; return FALSE;
} }
QR_Destructor(res);
} }
} }
......
...@@ -1296,7 +1296,7 @@ SC_pos_reload(StatementClass *stmt, UWORD irow, UWORD *count) ...@@ -1296,7 +1296,7 @@ SC_pos_reload(StatementClass *stmt, UWORD irow, UWORD *count)
if (rcnt == 1) if (rcnt == 1)
{ {
QR_set_position(qres, 0); QR_set_position(qres, 0);
tuplen = res->tupleField; tuplen = qres->tupleField;
for (i = 0; i < res->num_fields; i++) for (i = 0; i < res->num_fields; i++)
{ {
if (tupleo[i].value) if (tupleo[i].value)
...@@ -1416,6 +1416,8 @@ SC_pos_update(StatementClass *stmt, ...@@ -1416,6 +1416,8 @@ SC_pos_update(StatementClass *stmt,
RETCODE ret; RETCODE ret;
char *tidval, char *tidval,
*oidval; *oidval;
UInt4 offset;
Int4 *used;
mylog("POS UPDATE %d+%d fi=%x ti=%x\n", irow, stmt->result->base, stmt->fi, stmt->ti); mylog("POS UPDATE %d+%d fi=%x ti=%x\n", irow, stmt->result->base, stmt->fi, stmt->ti);
if (!(res = stmt->result)) if (!(res = stmt->result))
...@@ -1438,12 +1440,17 @@ SC_pos_update(StatementClass *stmt, ...@@ -1438,12 +1440,17 @@ SC_pos_update(StatementClass *stmt,
sprintf(updstr, "update \"%s\" set", stmt->ti[0]->name); sprintf(updstr, "update \"%s\" set", stmt->ti[0]->name);
num_cols = stmt->nfld; num_cols = stmt->nfld;
if (stmt->options.row_offset_ptr)
offset = *stmt->options.row_offset_ptr;
else
offset = 0;
for (i = upd_cols = 0; i < num_cols; i++) for (i = upd_cols = 0; i < num_cols; i++)
{ {
if (bindings[i].used) if (used = bindings[i].used, used != NULL)
{ {
mylog("%d used=%d\n", i, *bindings[i].used); used += (offset >> 2);
if (*bindings[i].used != SQL_IGNORE) mylog("%d used=%d\n", i, *used);
if (*used != SQL_IGNORE)
{ {
if (upd_cols) if (upd_cols)
sprintf(updstr, "%s, \"%s\" = ?", updstr, stmt->fi[i]->name); sprintf(updstr, "%s, \"%s\" = ?", updstr, stmt->fi[i]->name);
...@@ -1468,12 +1475,15 @@ SC_pos_update(StatementClass *stmt, ...@@ -1468,12 +1475,15 @@ SC_pos_update(StatementClass *stmt,
if (PGAPI_AllocStmt(SC_get_conn(stmt), &hstmt) != SQL_SUCCESS) if (PGAPI_AllocStmt(SC_get_conn(stmt), &hstmt) != SQL_SUCCESS)
return SQL_ERROR; return SQL_ERROR;
qstmt = (StatementClass *) hstmt; qstmt = (StatementClass *) hstmt;
qstmt->options.param_bind_type = stmt->options.bind_size;
qstmt->options.param_offset_ptr = stmt->options.row_offset_ptr;
for (i = j = 0; i < num_cols; i++) for (i = j = 0; i < num_cols; i++)
{ {
if (bindings[i].used) if (used = bindings[i].used, used != NULL)
{ {
mylog("%d used=%d\n", i, *bindings[i].used); used += (offset >> 2);
if (*bindings[i].used != SQL_IGNORE) mylog("%d used=%d\n", i, *used);
if (*used != SQL_IGNORE)
{ {
PGAPI_BindParameter(hstmt, (SQLUSMALLINT) ++j, PGAPI_BindParameter(hstmt, (SQLUSMALLINT) ++j,
SQL_PARAM_INPUT, bindings[i].returntype, SQL_PARAM_INPUT, bindings[i].returntype,
...@@ -1486,6 +1496,7 @@ SC_pos_update(StatementClass *stmt, ...@@ -1486,6 +1496,7 @@ SC_pos_update(StatementClass *stmt,
} }
} }
} }
qstmt->exec_start_row = qstmt->exec_end_row = irow;
ret = PGAPI_ExecDirect(hstmt, updstr, strlen(updstr)); ret = PGAPI_ExecDirect(hstmt, updstr, strlen(updstr));
if (ret == SQL_ERROR) if (ret == SQL_ERROR)
{ {
...@@ -1533,6 +1544,19 @@ SC_pos_update(StatementClass *stmt, ...@@ -1533,6 +1544,19 @@ SC_pos_update(StatementClass *stmt,
} }
else else
ret = SQL_SUCCESS_WITH_INFO; ret = SQL_SUCCESS_WITH_INFO;
if (stmt->options.rowStatusArray)
{
switch (ret)
{
case SQL_SUCCESS:
stmt->options.rowStatusArray[irow] = SQL_ROW_UPDATED;
break;
case SQL_SUCCESS_WITH_INFO:
stmt->options.rowStatusArray[irow] = SQL_ROW_SUCCESS_WITH_INFO;
break;
}
}
return ret; return ret;
} }
RETCODE SQL_API RETCODE SQL_API
...@@ -1606,6 +1630,18 @@ SC_pos_delete(StatementClass *stmt, ...@@ -1606,6 +1630,18 @@ SC_pos_delete(StatementClass *stmt,
} }
if (qres) if (qres)
QR_Destructor(qres); QR_Destructor(qres);
if (stmt->options.rowStatusArray)
{
switch (ret)
{
case SQL_SUCCESS:
stmt->options.rowStatusArray[irow] = SQL_ROW_DELETED;
break;
case SQL_SUCCESS_WITH_INFO:
stmt->options.rowStatusArray[irow] = SQL_ROW_SUCCESS_WITH_INFO;
break;
}
}
return ret; return ret;
} }
RETCODE SQL_API RETCODE SQL_API
...@@ -1616,10 +1652,13 @@ SC_pos_add(StatementClass *stmt, ...@@ -1616,10 +1652,13 @@ SC_pos_add(StatementClass *stmt,
add_cols, add_cols,
i; i;
HSTMT hstmt; HSTMT hstmt;
StatementClass *qstmt;
QResultClass *res; QResultClass *res;
BindInfoClass *bindings = stmt->bindings; BindInfoClass *bindings = stmt->bindings;
char addstr[4096]; char addstr[4096];
RETCODE ret; RETCODE ret;
UInt4 offset;
Int4 *used;
mylog("POS ADD fi=%x ti=%x\n", stmt->fi, stmt->ti); mylog("POS ADD fi=%x ti=%x\n", stmt->fi, stmt->ti);
if (!(res = stmt->result)) if (!(res = stmt->result))
...@@ -1635,12 +1674,20 @@ SC_pos_add(StatementClass *stmt, ...@@ -1635,12 +1674,20 @@ SC_pos_add(StatementClass *stmt,
sprintf(addstr, "insert into \"%s\" (", stmt->ti[0]->name); sprintf(addstr, "insert into \"%s\" (", stmt->ti[0]->name);
if (PGAPI_AllocStmt(SC_get_conn(stmt), &hstmt) != SQL_SUCCESS) if (PGAPI_AllocStmt(SC_get_conn(stmt), &hstmt) != SQL_SUCCESS)
return SQL_ERROR; return SQL_ERROR;
if (stmt->options.row_offset_ptr)
offset = *stmt->options.row_offset_ptr;
else
offset = 0;
qstmt = (StatementClass *) hstmt;
qstmt->options.param_bind_type = stmt->options.bind_size;
qstmt->options.param_offset_ptr = stmt->options.row_offset_ptr;
for (i = add_cols = 0; i < num_cols; i++) for (i = add_cols = 0; i < num_cols; i++)
{ {
if (bindings[i].used) if (used = bindings[i].used, used != NULL)
{ {
mylog("%d used=%d\n", i, *bindings[i].used); used += (offset >> 2);
if (*bindings[i].used != SQL_IGNORE) mylog("%d used=%d\n", i, *used);
if (*used != SQL_IGNORE)
{ {
if (add_cols) if (add_cols)
sprintf(addstr, "%s, \"%s\"", addstr, stmt->fi[i]->name); sprintf(addstr, "%s, \"%s\"", addstr, stmt->fi[i]->name);
...@@ -1661,7 +1708,6 @@ SC_pos_add(StatementClass *stmt, ...@@ -1661,7 +1708,6 @@ SC_pos_add(StatementClass *stmt,
} }
if (add_cols > 0) if (add_cols > 0)
{ {
StatementClass *qstmt = (StatementClass *) hstmt;
sprintf(addstr, "%s) values (", addstr); sprintf(addstr, "%s) values (", addstr);
for (i = 0; i < add_cols; i++) for (i = 0; i < add_cols; i++)
...@@ -1673,6 +1719,7 @@ SC_pos_add(StatementClass *stmt, ...@@ -1673,6 +1719,7 @@ SC_pos_add(StatementClass *stmt,
} }
strcat(addstr, ")"); strcat(addstr, ")");
mylog("addstr=%s\n", addstr); mylog("addstr=%s\n", addstr);
qstmt->exec_start_row = qstmt->exec_end_row = irow;
ret = PGAPI_ExecDirect(hstmt, addstr, strlen(addstr)); ret = PGAPI_ExecDirect(hstmt, addstr, strlen(addstr));
if (ret == SQL_NEED_DATA) /* must be fixed */ if (ret == SQL_NEED_DATA) /* must be fixed */
{ {
...@@ -1718,6 +1765,18 @@ SC_pos_add(StatementClass *stmt, ...@@ -1718,6 +1765,18 @@ SC_pos_add(StatementClass *stmt,
else else
ret = SQL_SUCCESS_WITH_INFO; ret = SQL_SUCCESS_WITH_INFO;
PGAPI_FreeStmt(hstmt, SQL_DROP); PGAPI_FreeStmt(hstmt, SQL_DROP);
if (stmt->options.rowStatusArray)
{
switch (ret)
{
case SQL_SUCCESS:
stmt->options.rowStatusArray[irow] = SQL_ROW_ADDED;
break;
case SQL_SUCCESS_WITH_INFO:
stmt->options.rowStatusArray[irow] = SQL_ROW_SUCCESS_WITH_INFO;
break;
}
}
return ret; return ret;
} }
......
...@@ -263,6 +263,9 @@ SC_Constructor(void) ...@@ -263,6 +263,9 @@ SC_Constructor(void)
rv->data_at_exec = -1; rv->data_at_exec = -1;
rv->current_exec_param = -1; rv->current_exec_param = -1;
rv->exec_start_row = -1;
rv->exec_end_row = -1;
rv->exec_current_row = -1;
rv->put_data = FALSE; rv->put_data = FALSE;
rv->lobj_fd = -1; rv->lobj_fd = -1;
...@@ -404,6 +407,9 @@ SC_free_params(StatementClass *self, char option) ...@@ -404,6 +407,9 @@ SC_free_params(StatementClass *self, char option)
free(self->parameters); free(self->parameters);
self->parameters = NULL; self->parameters = NULL;
self->parameters_allocated = 0; self->parameters_allocated = 0;
self->exec_start_row = -1;
self->exec_end_row = -1;
self->exec_current_row = -1;
} }
mylog("SC_free_params: EXIT\n"); mylog("SC_free_params: EXIT\n");
...@@ -778,10 +784,12 @@ SC_fetch(StatementClass *self) ...@@ -778,10 +784,12 @@ SC_fetch(StatementClass *self)
if (self->bookmark.buffer) if (self->bookmark.buffer)
{ {
char buf[32]; char buf[32];
UInt4 offset = self->options.row_offset_ptr ? *self->options.row_offset_ptr : 0;
sprintf(buf, "%ld", SC_get_bookmark(self)); sprintf(buf, "%ld", SC_get_bookmark(self));
result = copy_and_convert_field(self, 0, buf, result = copy_and_convert_field(self, 0, buf,
SQL_C_ULONG, self->bookmark.buffer, 0, self->bookmark.used); SQL_C_ULONG, self->bookmark.buffer + offset, 0,
self->bookmark.used ? self->bookmark.used + (offset >> 2) : NULL);
} }
#ifdef DRIVER_CURSOR_IMPLEMENT #ifdef DRIVER_CURSOR_IMPLEMENT
...@@ -892,10 +900,7 @@ SC_execute(StatementClass *self) ...@@ -892,10 +900,7 @@ SC_execute(StatementClass *self)
{ {
static char *func = "SC_execute"; static char *func = "SC_execute";
ConnectionClass *conn; ConnectionClass *conn;
QResultClass *res; char was_ok, was_nonfatal;
char ok,
was_ok,
was_nonfatal;
Int2 oldstatus, Int2 oldstatus,
numcols; numcols;
QueryInfo qi; QueryInfo qi;
...@@ -920,30 +925,13 @@ SC_execute(StatementClass *self) ...@@ -920,30 +925,13 @@ SC_execute(StatementClass *self)
(!CC_is_in_autocommit(conn) && self->statement_type != STMT_TYPE_OTHER))) (!CC_is_in_autocommit(conn) && self->statement_type != STMT_TYPE_OTHER)))
{ {
mylog(" about to begin a transaction on statement = %u\n", self); mylog(" about to begin a transaction on statement = %u\n", self);
res = CC_send_query(conn, "BEGIN", NULL); if (!CC_begin(conn))
if (QR_aborted(res))
{ {
self->errormsg = "Could not begin a transaction"; self->errormsg = "Could not begin a transaction";
self->errornumber = STMT_EXEC_ERROR; self->errornumber = STMT_EXEC_ERROR;
SC_log_error(func, "", self); SC_log_error(func, "", self);
return SQL_ERROR; return SQL_ERROR;
} }
ok = QR_command_successful(res);
mylog("SC_exec: begin ok = %d, status = %d\n", ok, QR_get_status(res));
QR_Destructor(res);
if (!ok)
{
self->errormsg = "Could not begin a transaction";
self->errornumber = STMT_EXEC_ERROR;
SC_log_error(func, "", self);
return SQL_ERROR;
}
else
CC_set_in_trans(conn);
} }
oldstatus = conn->status; oldstatus = conn->status;
...@@ -1008,11 +996,7 @@ SC_execute(StatementClass *self) ...@@ -1008,11 +996,7 @@ SC_execute(StatementClass *self)
* transactions must be committed. (Hiroshi, 02/11/2001) * transactions must be committed. (Hiroshi, 02/11/2001)
*/ */
if (!self->internal && CC_is_in_autocommit(conn) && CC_is_in_trans(conn)) if (!self->internal && CC_is_in_autocommit(conn) && CC_is_in_trans(conn))
{ CC_commit(conn);
res = CC_send_query(conn, "COMMIT", NULL);
QR_Destructor(res);
CC_set_no_trans(conn);
}
} }
conn->status = oldstatus; conn->status = oldstatus;
......
...@@ -75,6 +75,7 @@ typedef enum ...@@ -75,6 +75,7 @@ typedef enum
#define STMT_PROGRAM_TYPE_OUT_OF_RANGE 26 #define STMT_PROGRAM_TYPE_OUT_OF_RANGE 26
#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
/* statement types */ /* statement types */
enum enum
...@@ -207,6 +208,9 @@ struct StatementClass_ ...@@ -207,6 +208,9 @@ struct StatementClass_
char *stmt_with_params; /* statement after parameter char *stmt_with_params; /* statement after parameter
* substitution */ * substitution */
int stmt_size_limit; int stmt_size_limit;
int exec_start_row;
int exec_end_row;
int exec_current_row;
char pre_executing; /* This statement is prematurely executing */ char pre_executing; /* This statement is prematurely executing */
char inaccurate_result; /* Current status is PREMATURE but char inaccurate_result; /* Current status is PREMATURE but
......
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