-- v3: odbc32: Add support for descriptor handles in SQLGet/SetStmtAttr().
From: Hans Leidekker hans@codeweavers.com
--- dlls/odbc32/proxyodbc.c | 137 ++++++++++++++++++++++++++++++++++--- dlls/odbc32/tests/odbc32.c | 44 +++++++++--- dlls/odbc32/unixlib.h | 2 + 3 files changed, 164 insertions(+), 19 deletions(-)
diff --git a/dlls/odbc32/proxyodbc.c b/dlls/odbc32/proxyodbc.c index 2a62fd88d64..299f1f8e08b 100644 --- a/dlls/odbc32/proxyodbc.c +++ b/dlls/odbc32/proxyodbc.c @@ -518,20 +518,48 @@ static SQLRETURN alloc_handle( SQLSMALLINT type, struct object *input, struct ob return ret; }
-static struct statement *create_statement( struct connection *con ) +static struct descriptor *create_descriptor( struct statement *stmt ) { - struct statement *ret; + struct descriptor *ret; if (!(ret = calloc( 1, sizeof(*ret) ))) return NULL; - init_object( &ret->hdr, SQL_HANDLE_STMT, &con->hdr ); - ret->row_count = 1; + init_object( &ret->hdr, SQL_HANDLE_DESC, &stmt->hdr ); return ret; }
-static struct descriptor *create_descriptor( struct statement *stmt ) +static void free_descriptors( struct statement *stmt ) { - struct descriptor *ret; + unsigned int i; + for (i = 0; i < ARRAY_SIZE(stmt->desc); i++) + { + if (stmt->desc[i]) destroy_object( &stmt->desc[i]->hdr ); + } +} + +static SQLRETURN alloc_descriptors( struct statement *stmt ) +{ + unsigned int i; + for (i = 0; i < ARRAY_SIZE(stmt->desc); i++) + { + if (!(stmt->desc[i] = create_descriptor( NULL ))) + { + free_descriptors( stmt ); + return SQL_ERROR; + } + } + return SQL_SUCCESS; +} + +static struct statement *create_statement( struct connection *con ) +{ + struct statement *ret; if (!(ret = calloc( 1, sizeof(*ret) ))) return NULL; - init_object( &ret->hdr, SQL_HANDLE_DESC, &stmt->hdr ); + init_object( &ret->hdr, SQL_HANDLE_STMT, &con->hdr ); + if (alloc_descriptors( ret )) + { + destroy_object( &ret->hdr ); + return NULL; + } + ret->row_count = 1; return ret; }
@@ -2070,6 +2098,7 @@ SQLRETURN WINAPI SQLFreeHandle(SQLSMALLINT HandleType, SQLHANDLE Handle) struct statement *stmt = (struct statement *)obj; free_col_bindings( stmt ); free_param_bindings( stmt ); + free_descriptors( stmt ); break; } default: break; @@ -2134,6 +2163,7 @@ SQLRETURN WINAPI SQLFreeStmt(SQLHSTMT StatementHandle, SQLUSMALLINT Option) default: free_col_bindings( stmt ); free_param_bindings( stmt ); + free_descriptors( stmt ); stmt->hdr.closed = TRUE; break; } @@ -2963,6 +2993,30 @@ SQLRETURN WINAPI SQLGetStmtAttr(SQLHSTMT StatementHandle, SQLINTEGER Attribute, ret = get_stmt_attr_win32_a( stmt, Attribute, Value, BufferLength, StringLength ); }
+ if (!ret) + { + switch (Attribute) + { + case SQL_ATTR_APP_ROW_DESC: + case SQL_ATTR_APP_PARAM_DESC: + case SQL_ATTR_IMP_ROW_DESC: + case SQL_ATTR_IMP_PARAM_DESC: + { + struct descriptor *desc = stmt->desc[Attribute - SQL_ATTR_APP_ROW_DESC]; + if (stmt->hdr.unix_handle) + { + if (sizeof(desc->hdr.unix_handle) > sizeof(SQLHDESC)) + ERR( "truncating descriptor handle, consider using a Windows driver\n" ); + desc->hdr.unix_handle = (ULONG_PTR)*(SQLHDESC *)Value; + } + else if (stmt->hdr.win32_handle) desc->hdr.win32_handle = *(SQLHDESC *)Value; + *(struct descriptor **)Value = desc; + break; + } + default: break; + } + } + TRACE("Returning %d\n", ret); unlock_object( &stmt->hdr ); return ret; @@ -3790,6 +3844,28 @@ SQLRETURN WINAPI SQLSetStmtAttr(SQLHSTMT StatementHandle, SQLINTEGER Attribute,
if (!stmt) return SQL_INVALID_HANDLE;
+ switch (Attribute) + { + case SQL_ATTR_APP_ROW_DESC: + case SQL_ATTR_APP_PARAM_DESC: + { + struct descriptor *desc = (struct descriptor *)lock_object( Value, SQL_HANDLE_DESC ); + if (desc) + { + if (stmt->hdr.unix_handle) + { + if (sizeof(desc->hdr.unix_handle) > sizeof(Value)) + ERR( "truncating descriptor handle, consider using a Windows driver\n" ); + Value = (SQLPOINTER)(ULONG_PTR)desc->hdr.unix_handle; + } + else Value = desc->hdr.win32_handle; + unlock_object( &desc->hdr ); + } + break; + } + default: break; + } + if (stmt->hdr.unix_handle) { ret = set_stmt_attr_unix_a( stmt, Attribute, Value, StringLength ); @@ -6228,7 +6304,6 @@ SQLRETURN WINAPI SQLGetStmtAttrW(SQLHSTMT StatementHandle, SQLINTEGER Attribute, TRACE("(StatementHandle %p, Attribute %d, Value %p, BufferLength %d, StringLength %p)\n", StatementHandle, Attribute, Value, BufferLength, StringLength);
- if (!Value) return SQL_ERROR; if (!stmt) return SQL_INVALID_HANDLE;
if (stmt->hdr.unix_handle) @@ -6240,6 +6315,28 @@ SQLRETURN WINAPI SQLGetStmtAttrW(SQLHSTMT StatementHandle, SQLINTEGER Attribute, ret = get_stmt_attr_win32_w( stmt, Attribute, Value, BufferLength, StringLength ); }
+ if (!ret) + { + switch (Attribute) + { + case SQL_ATTR_APP_ROW_DESC: + case SQL_ATTR_APP_PARAM_DESC: + { + struct descriptor *desc = stmt->desc[Attribute - SQL_ATTR_APP_ROW_DESC]; + if (stmt->hdr.unix_handle) + { + if (sizeof(desc->hdr.unix_handle) > sizeof(SQLHDESC)) + ERR( "truncating descriptor handle, consider using a Windows driver\n" ); + desc->hdr.unix_handle = (ULONG_PTR)*(SQLHDESC *)Value; + } + else if (stmt->hdr.win32_handle) desc->hdr.win32_handle = *(SQLHDESC *)Value; + *(struct descriptor **)Value = desc; + break; + } + default: break; + } + } + TRACE("Returning %d\n", ret); unlock_object( &stmt->hdr ); return ret; @@ -7450,6 +7547,30 @@ SQLRETURN WINAPI SQLSetStmtAttrW(SQLHSTMT StatementHandle, SQLINTEGER Attribute,
if (!stmt) return SQL_INVALID_HANDLE;
+ switch (Attribute) + { + case SQL_ATTR_APP_ROW_DESC: + case SQL_ATTR_APP_PARAM_DESC: + case SQL_ATTR_IMP_ROW_DESC: + case SQL_ATTR_IMP_PARAM_DESC: + { + struct descriptor *desc = (struct descriptor *)lock_object( Value, SQL_HANDLE_DESC ); + if (desc) + { + if (stmt->hdr.unix_handle) + { + if (sizeof(desc->hdr.unix_handle) > sizeof(Value)) + ERR( "truncating descriptor handle, consider using a Windows driver\n" ); + Value = (SQLPOINTER)(ULONG_PTR)desc->hdr.unix_handle; + } + else Value = desc->hdr.win32_handle; + unlock_object( &desc->hdr ); + } + break; + } + default: break; + } + if (stmt->hdr.unix_handle) { ret = set_stmt_attr_unix_w( stmt, Attribute, Value, StringLength ); diff --git a/dlls/odbc32/tests/odbc32.c b/dlls/odbc32/tests/odbc32.c index 3583e69e98e..7fdeb0ee75d 100644 --- a/dlls/odbc32/tests/odbc32.c +++ b/dlls/odbc32/tests/odbc32.c @@ -317,11 +317,12 @@ static void test_SQLExecDirect( void ) SQLHENV env; SQLHDBC con; SQLHSTMT stmt; + SQLHDESC desc; SQLRETURN ret; - SQLLEN count, len_id[2], len_name[2]; + SQLLEN count, len_id[2], len_name[2], len_octet; SQLULEN rows_fetched; - SQLINTEGER id[2], err; - SQLCHAR name[32], msg[32], state[6]; + SQLINTEGER id[2], err, size; + SQLCHAR name[32], msg[256], state[6]; SQLSMALLINT len;
ret = SQLAllocEnv( &env ); @@ -344,6 +345,18 @@ static void test_SQLExecDirect( void ) ret = SQLAllocStmt( con, &stmt ); ok( ret == SQL_SUCCESS, "got %d\n", ret );
+ ret = SQLError( NULL, NULL, NULL, state, &err, msg, sizeof(msg), &len ); + ok( ret == SQL_INVALID_HANDLE, "got %d\n", ret ); + + ret = SQLError( env, NULL, NULL, state, &err, msg, sizeof(msg), &len ); + ok( ret == SQL_NO_DATA, "got %d\n", ret ); + + ret = SQLError( env, con, NULL, state, &err, msg, sizeof(msg), &len ); + ok( ret == SQL_NO_DATA, "got %d\n", ret ); + + ret = SQLError( env, con, stmt, state, &err, msg, sizeof(msg), &len ); + ok( ret == SQL_NO_DATA, "got %d\n", ret ); + SQLExecDirect( stmt, (SQLCHAR *)"USE winetest", ARRAYSIZE("USE winetest") - 1 ); SQLExecDirect( stmt, (SQLCHAR *)"DROP TABLE winetest", ARRAYSIZE("DROP TABLE winetest") - 1 ); ret = SQLExecDirect( stmt, (SQLCHAR *)"CREATE TABLE winetest ( Id int, Name varchar(255) )", @@ -471,17 +484,26 @@ static void test_SQLExecDirect( void ) ret = SQLExecDirect( stmt, (SQLCHAR *)"DROP TABLE winetest", ARRAYSIZE("DROP TABLE winetest") - 1 ); ok( ret == SQL_SUCCESS, "got %d\n", ret );
- ret = SQLError( NULL, NULL, NULL, state, &err, msg, sizeof(msg), &len ); - ok( ret == SQL_INVALID_HANDLE, "got %d\n", ret ); + desc = (SQLHDESC)0xdeadbeef; + size = 0xdeadbeef; + ret = SQLGetStmtAttr( stmt, SQL_ATTR_APP_ROW_DESC, &desc, sizeof(desc), &size ); + if (ret == SQL_ERROR) diag( stmt, SQL_HANDLE_STMT ); + ok( ret == SQL_SUCCESS, "got %d\n", ret ); + ok( desc != (SQLHDESC)0xdeadbeef, "desc not set\n" ); + ok( size == 0xdeadbeef, "got %d\n", size );
- ret = SQLError( env, NULL, NULL, state, &err, msg, sizeof(msg), &len ); - ok( ret == SQL_NO_DATA, "got %d\n", ret ); + ret = SQLSetDescField( desc, 1, SQL_DESC_OCTET_LENGTH_PTR, &len_octet, 0 ); + if (ret == SQL_ERROR) diag( stmt, SQL_HANDLE_DESC ); + ok( ret == SQL_SUCCESS, "got %d\n", ret );
- ret = SQLError( env, con, NULL, state, &err, msg, sizeof(msg), &len ); - ok( ret == SQL_NO_DATA, "got %d\n", ret ); + ret = SQLSetStmtAttr( stmt, SQL_ATTR_APP_ROW_DESC, NULL, sizeof(desc) ); + ok( ret == SQL_SUCCESS, "got %d\n", ret );
- ret = SQLError( env, con, stmt, state, &err, msg, sizeof(msg), &len ); - ok( ret == SQL_NO_DATA, "got %d\n", ret ); + ret = SQLSetStmtAttr( stmt, SQL_ATTR_APP_ROW_DESC, desc, 0 ); + ok( ret == SQL_SUCCESS, "got %d\n", ret ); + + ret = SQLSetStmtAttr( stmt, SQL_ATTR_IMP_ROW_DESC, NULL, sizeof(desc) ); + ok( ret == SQL_ERROR, "got %d\n", ret );
ret = SQLFreeStmt( stmt, SQL_DROP ); ok( ret == SQL_SUCCESS, "got %d\n", ret ); diff --git a/dlls/odbc32/unixlib.h b/dlls/odbc32/unixlib.h index 23fb3640b41..bee789d131b 100644 --- a/dlls/odbc32/unixlib.h +++ b/dlls/odbc32/unixlib.h @@ -217,6 +217,8 @@ struct connection struct statement { struct object hdr; + /* descriptors */ + struct descriptor *desc[4]; /* parameter bindings */ struct param_binding bind_col; struct param_binding bind_parameter;
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The tests also ran into some preexisting test failures. If you know how to fix them that would be helpful. See the TestBot job for the details:
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=147712
Your paranoid android.
=== debian11b (64 bit WoW report) ===
ddraw: ddraw4.c:3969: Test failed: Expected message 0x5, but didn't receive it.
user32: input.c:4305: Test succeeded inside todo block: button_down_hwnd_todo 1: got MSG_TEST_WIN hwnd 0000000000B100F0, msg WM_LBUTTONDOWN, wparam 0x1, lparam 0x320032