From: Hans Leidekker hans@codeweavers.com
--- dlls/odbc32/proxyodbc.c | 137 ++++++++++++++++++++++++++++++++++--- dlls/odbc32/tests/odbc32.c | 25 ++++++- dlls/odbc32/unixlib.h | 2 + 3 files changed, 154 insertions(+), 10 deletions(-)
diff --git a/dlls/odbc32/proxyodbc.c b/dlls/odbc32/proxyodbc.c index 2a62fd88d64..0effe6c3186 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)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)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..208b35e97a3 100644 --- a/dlls/odbc32/tests/odbc32.c +++ b/dlls/odbc32/tests/odbc32.c @@ -317,10 +317,11 @@ 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; + SQLINTEGER id[2], err, size; SQLCHAR name[32], msg[32], state[6]; SQLSMALLINT len;
@@ -483,6 +484,26 @@ static void test_SQLExecDirect( void ) ret = SQLError( env, con, stmt, state, &err, msg, sizeof(msg), &len ); ok( ret == SQL_NO_DATA, "got %d\n", ret );
+ desc = (SQLHDESC)0xdeadbeef; + size = 0xdeadbeef; + ret = SQLGetStmtAttr( stmt, SQL_ATTR_APP_ROW_DESC, &desc, sizeof(desc), &size ); + ok( ret == SQL_SUCCESS, "got %d\n", ret ); + ok( desc != (SQLHDESC)0xdeadbeef, "desc not set\n" ); + ok( size == 0xdeadbeef, "got %d\n", size ); + + 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 = SQLSetStmtAttr( stmt, SQL_ATTR_APP_ROW_DESC, NULL, sizeof(desc) ); + ok( ret == SQL_SUCCESS, "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;