mirror of
https://github.com/mdbtools/mdbtools.git
synced 2025-10-14 19:05:06 +08:00
Use correct bind types for SQLBindCol / SQLFetch (#242)
SQLFetch / SQLExtendedFetch now skip the mdb_sql machinery and use SQLGetData on their bound columns instead. We rely on mdb_fetch_row to skip to the correct page without any bindings and then SQLGetData will do the rest. SQLFetch will now correctly return SQL_SUCCESS_WITH_INFO if one or more bound columns have their data truncated, and will return several kinds of errors (provided by SQLGetData) that were previously ignored. Updated the unit test with a SQL_C_LONG type for demonstration purposes. Fixes #23
This commit is contained in:
@@ -41,7 +41,6 @@ static int _odbc_fix_literals(struct _hstmt *stmt);
|
|||||||
//static int _odbc_get_server_type(int clt_type);
|
//static int _odbc_get_server_type(int clt_type);
|
||||||
static int _odbc_get_string_size(int size, SQLCHAR *str);
|
static int _odbc_get_string_size(int size, SQLCHAR *str);
|
||||||
|
|
||||||
static void bind_columns (struct _hstmt*);
|
|
||||||
static void unbind_columns (struct _hstmt*);
|
static void unbind_columns (struct _hstmt*);
|
||||||
|
|
||||||
#define FILL_FIELD(f,v,s) mdb_fill_temp_field(f,v,s,0,0,0,0)
|
#define FILL_FIELD(f,v,s) mdb_fill_temp_field(f,v,s,0,0,0,0)
|
||||||
@@ -291,6 +290,7 @@ SQLRETURN SQL_API SQLExtendedFetch(
|
|||||||
SQLUSMALLINT *rgfRowStatus)
|
SQLUSMALLINT *rgfRowStatus)
|
||||||
{
|
{
|
||||||
struct _hstmt *stmt = (struct _hstmt *) hstmt;
|
struct _hstmt *stmt = (struct _hstmt *) hstmt;
|
||||||
|
struct _sql_bind_info *cur = stmt->bind_head;
|
||||||
|
|
||||||
TRACE("SQLExtendedFetch");
|
TRACE("SQLExtendedFetch");
|
||||||
if (fFetchType!=SQL_FETCH_NEXT) {
|
if (fFetchType!=SQL_FETCH_NEXT) {
|
||||||
@@ -302,11 +302,21 @@ SQLRETURN SQL_API SQLExtendedFetch(
|
|||||||
if (rgfRowStatus)
|
if (rgfRowStatus)
|
||||||
*rgfRowStatus = SQL_SUCCESS; /* what is the row status value? */
|
*rgfRowStatus = SQL_SUCCESS; /* what is the row status value? */
|
||||||
|
|
||||||
bind_columns(stmt);
|
|
||||||
|
|
||||||
if (mdb_fetch_row(stmt->sql->cur_table)) {
|
if (mdb_fetch_row(stmt->sql->cur_table)) {
|
||||||
|
SQLRETURN final_retval = SQL_SUCCESS;
|
||||||
|
while (cur && (final_retval == SQL_SUCCESS || final_retval == SQL_SUCCESS_WITH_INFO)) {
|
||||||
|
/* log error ? */
|
||||||
|
SQLLEN lenbind = 0;
|
||||||
|
SQLRETURN this_retval = SQLGetData(hstmt, cur->column_number, cur->column_bindtype,
|
||||||
|
cur->varaddr, cur->column_bindlen, &lenbind);
|
||||||
|
if (cur->column_lenbind)
|
||||||
|
*(cur->column_lenbind) = lenbind;
|
||||||
|
if (this_retval != SQL_SUCCESS)
|
||||||
|
final_retval = this_retval;
|
||||||
|
cur = cur->next;
|
||||||
|
}
|
||||||
stmt->rows_affected++;
|
stmt->rows_affected++;
|
||||||
return SQL_SUCCESS;
|
return final_retval;
|
||||||
} else {
|
} else {
|
||||||
return SQL_NO_DATA_FOUND;
|
return SQL_NO_DATA_FOUND;
|
||||||
}
|
}
|
||||||
@@ -1031,25 +1041,6 @@ SQLRETURN SQL_API SQLExecDirectW(
|
|||||||
}
|
}
|
||||||
#endif // ENABLE_ODBC_W
|
#endif // ENABLE_ODBC_W
|
||||||
|
|
||||||
static void
|
|
||||||
bind_columns(struct _hstmt *stmt)
|
|
||||||
{
|
|
||||||
struct _sql_bind_info *cur;
|
|
||||||
|
|
||||||
TRACE("bind_columns");
|
|
||||||
|
|
||||||
if (stmt->rows_affected==0) {
|
|
||||||
cur = stmt->bind_head;
|
|
||||||
while (cur) {
|
|
||||||
if (mdb_sql_bind_column(stmt->sql, cur->column_number,
|
|
||||||
cur->varaddr, cur->column_lenbind) == -1) {
|
|
||||||
/* log error ? */
|
|
||||||
}
|
|
||||||
cur = cur->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
unbind_columns(struct _hstmt *stmt)
|
unbind_columns(struct _hstmt *stmt)
|
||||||
{
|
{
|
||||||
@@ -1071,26 +1062,28 @@ SQLRETURN SQL_API SQLFetch(
|
|||||||
SQLHSTMT hstmt)
|
SQLHSTMT hstmt)
|
||||||
{
|
{
|
||||||
struct _hstmt *stmt = (struct _hstmt *) hstmt;
|
struct _hstmt *stmt = (struct _hstmt *) hstmt;
|
||||||
|
struct _sql_bind_info *cur = stmt->bind_head;
|
||||||
|
|
||||||
TRACE("SQLFetch");
|
TRACE("SQLFetch");
|
||||||
/* if we bound columns, transfer them to res_info now that we have one */
|
|
||||||
bind_columns(stmt);
|
|
||||||
//cur = stmt->bind_head;
|
|
||||||
//while (cur) {
|
|
||||||
//if (cur->column_number>0 &&
|
|
||||||
//cur->column_number <= stmt->sql->num_columns) {
|
|
||||||
// if (cur->column_lenbind) *(cur->column_lenbind) = 4;
|
|
||||||
//}
|
|
||||||
//cur = cur->next;
|
|
||||||
//}
|
|
||||||
if ( stmt->sql->limit >= 0 && stmt->rows_affected == stmt->sql->limit ) {
|
if ( stmt->sql->limit >= 0 && stmt->rows_affected == stmt->sql->limit ) {
|
||||||
return SQL_NO_DATA_FOUND;
|
return SQL_NO_DATA_FOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mdb_fetch_row(stmt->sql->cur_table)) {
|
if (mdb_fetch_row(stmt->sql->cur_table)) {
|
||||||
|
SQLRETURN final_retval = SQL_SUCCESS;
|
||||||
|
while (cur && (final_retval == SQL_SUCCESS || final_retval == SQL_SUCCESS_WITH_INFO)) {
|
||||||
|
/* log error ? */
|
||||||
|
SQLLEN lenbind = 0;
|
||||||
|
SQLRETURN this_retval = SQLGetData(hstmt, cur->column_number, cur->column_bindtype,
|
||||||
|
cur->varaddr, cur->column_bindlen, &lenbind);
|
||||||
|
if (cur->column_lenbind)
|
||||||
|
*(cur->column_lenbind) = lenbind;
|
||||||
|
if (this_retval != SQL_SUCCESS)
|
||||||
|
final_retval = this_retval;
|
||||||
|
cur = cur->next;
|
||||||
|
}
|
||||||
stmt->rows_affected++;
|
stmt->rows_affected++;
|
||||||
stmt->pos=0;
|
stmt->pos=0;
|
||||||
return SQL_SUCCESS;
|
return final_retval;
|
||||||
} else {
|
} else {
|
||||||
return SQL_NO_DATA_FOUND;
|
return SQL_NO_DATA_FOUND;
|
||||||
}
|
}
|
||||||
@@ -2379,4 +2372,4 @@ static const char * _odbc_get_client_type_name(MdbColumn *col)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @}*/
|
/** @}*/
|
||||||
|
@@ -160,6 +160,7 @@ int i;
|
|||||||
|
|
||||||
if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
|
if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
|
||||||
{
|
{
|
||||||
|
long id_value;
|
||||||
UCHAR szCol1[60];
|
UCHAR szCol1[60];
|
||||||
SQLLEN length;
|
SQLLEN length;
|
||||||
|
|
||||||
@@ -179,8 +180,8 @@ int i;
|
|||||||
szSqlState, szErrorMsg);
|
szSqlState, szErrorMsg);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
SQLBindCol(hstmt, 1, SQL_C_LONG, &id_value, sizeof(id_value), NULL);
|
||||||
SQLBindCol(hstmt, 3, SQL_CHAR, szCol1, sizeof(szCol1), &length);
|
SQLBindCol(hstmt, 3, SQL_CHAR, szCol1, sizeof(szCol1), &length);
|
||||||
//SQLBindCol(hstmt, 1, SQL_CHAR, szCol1, 60, NULL);
|
|
||||||
|
|
||||||
/* Execute statement with first row. */
|
/* Execute statement with first row. */
|
||||||
|
|
||||||
@@ -188,7 +189,7 @@ int i;
|
|||||||
while ((retcode = SQLFetch(hstmt)) == SQL_SUCCESS)
|
while ((retcode = SQLFetch(hstmt)) == SQL_SUCCESS)
|
||||||
{
|
{
|
||||||
i++;
|
i++;
|
||||||
printf("%d: szCol1 = %s (%d)\n", i, szCol1, (int)length);
|
printf("%d: id = %ld szCol1 = %s (%d)\n", i, id_value, szCol1, (int)length);
|
||||||
}
|
}
|
||||||
if (retcode != SQL_NO_DATA_FOUND)
|
if (retcode != SQL_NO_DATA_FOUND)
|
||||||
{
|
{
|
||||||
|
Reference in New Issue
Block a user