[PATCH v3 0/7] MR10669: odbc32: Implement sharing environment between connections.
-- v3: odbc32: Don't leak connection object if it's reused in connect functions. odbc32: Implement sharing environment handle between connections. https://gitlab.winehq.org/wine/wine/-/merge_requests/10669
From: Piotr Caban <piotr@codeweavers.com> --- dlls/odbc32/tests/odbc32.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dlls/odbc32/tests/odbc32.c b/dlls/odbc32/tests/odbc32.c index 1a4b06f6d91..378c79a2cd2 100644 --- a/dlls/odbc32/tests/odbc32.c +++ b/dlls/odbc32/tests/odbc32.c @@ -244,13 +244,13 @@ static SQLRETURN WINAPI driver_SQLBrowseConnect( SQLHDBC con, SQLCHAR *in_con, CHECK_EXPECT( driver_SQLBrowseConnect ); ok( (ULONG_PTR)con == SQL_HANDLE_DBC, "con = %p\n", con ); todo_wine ok( in_con_len == 17, "in_con_len = %d\n", in_con_len ); - todo_wine ok( !strcmp((char *)in_con, "DSN=winetest_dsn;"), "in_con = %s\n", in_con ); + todo_wine ok( !strncmp((char *)in_con, "DSN=winetest_dsn;", 17), "in_con = %s\n", in_con ); ok( out_con != NULL, "out_con = %p\n", out_con ); ok( out_con_max_len == 256, "out_con_max_len = %d\n", out_con_max_len ); ok( out_con_len != NULL, "out_con_len = %p\n", out_con_len ); - strcpy( (char *)out_con, (char *)in_con ); - *out_con_len = strlen( (char *)in_con ); + memcpy( out_con, in_con, in_con_len ); + *out_con_len = in_con_len; return SQL_SUCCESS; } @@ -930,7 +930,7 @@ static void test_SQLBrowseConnect( void ) todo_wine CHECK_CALLED( driver_SQLGetInfo ); ok( ret == SQL_SUCCESS, "got %d\n", ret ); if (ret == SQL_ERROR) diag( con, SQL_HANDLE_DBC ); - todo_wine ok( !strcmp( (const char *)str, "DSN=winetest_dsn;" ), "got '%s'\n", str ); + todo_wine ok( !strncmp( (const char *)str, "DSN=winetest_dsn;", 17 ), "got '%s'\n", str ); todo_wine ok( len == 17, "got %d\n", len ); SET_EXPECT( driver_SQLDisconnect ); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10669
From: Piotr Caban <piotr@codeweavers.com> --- dlls/odbc32/proxyodbc.c | 4 +++- dlls/odbc32/tests/odbc32.c | 12 +----------- 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/dlls/odbc32/proxyodbc.c b/dlls/odbc32/proxyodbc.c index 7ad1ec7fcae..7e97af63581 100644 --- a/dlls/odbc32/proxyodbc.c +++ b/dlls/odbc32/proxyodbc.c @@ -2338,7 +2338,9 @@ static SQLRETURN free_statement( struct statement *stmt, SQLUSMALLINT option ) } else if (stmt->hdr.win32_handle) { - if (stmt->hdr.win32_funcs->SQLFreeStmt) + if (option == SQL_DROP) + ret = free_handle( SQL_HANDLE_STMT, &stmt->hdr ); + else if (stmt->hdr.win32_funcs->SQLFreeStmt) ret = stmt->hdr.win32_funcs->SQLFreeStmt( stmt->hdr.win32_handle, option ); } diff --git a/dlls/odbc32/tests/odbc32.c b/dlls/odbc32/tests/odbc32.c index 378c79a2cd2..41e5494f269 100644 --- a/dlls/odbc32/tests/odbc32.c +++ b/dlls/odbc32/tests/odbc32.c @@ -524,9 +524,7 @@ static SQLRETURN WINAPI driver_SQLFreeStmt( SQLHSTMT stmt, SQLUSMALLINT option ) { CHECK_EXPECT( driver_SQLFreeStmt ); ok( (ULONG_PTR)stmt == SQL_HANDLE_STMT, "stmt = %p\n", stmt ); - todo_wine_if( option == SQL_DROP ) ok( option == SQL_UNBIND, "option = %d\n", option ); - if (option == SQL_DROP) - return driver_SQLFreeHandle( SQL_HANDLE_STMT, stmt ); + ok( option == SQL_UNBIND, "option = %d\n", option ); return SQL_SUCCESS; } @@ -1129,11 +1127,9 @@ static void test_SQLExecDirect( void ) ok( !id[0], "id not set\n" ); ok( len_id[0] == sizeof(id[0]), "got %d\n", (int)len_id[0] ); - SET_EXPECT( driver_SQLFreeStmt ); SET_EXPECT( driver_SQLFreeHandle_stmt ); ret = SQLFreeStmt( stmt, SQL_DROP ); CHECK_CALLED( driver_SQLFreeHandle_stmt ); - todo_wine CHECK_NOT_CALLED( driver_SQLFreeStmt ); ok( ret == SQL_SUCCESS, "got %d\n", ret ); SET_EXPECT( driver_SQLAllocHandle_stmt ); @@ -1189,11 +1185,9 @@ static void test_SQLExecDirect( void ) ok( len_name[0] == sizeof("John") - 1, "got %d\n", (int)len_name[0] ); ok( len_name[1] == sizeof("Mary") - 1, "got %d\n", (int)len_name[1] ); - SET_EXPECT( driver_SQLFreeStmt ); SET_EXPECT( driver_SQLFreeHandle_stmt ); ret = SQLFreeStmt( stmt, SQL_DROP ); CHECK_CALLED( driver_SQLFreeHandle_stmt ); - todo_wine CHECK_NOT_CALLED( driver_SQLFreeStmt ); ok( ret == SQL_SUCCESS, "got %d\n", ret ); SET_EXPECT( driver_SQLAllocHandle_stmt ); @@ -1240,11 +1234,9 @@ static void test_SQLExecDirect( void ) ret = SQLFreeStmt( stmt, SQL_UNBIND ); CHECK_CALLED( driver_SQLFreeStmt ); ok( ret == SQL_SUCCESS, "got %d\n", ret ); - SET_EXPECT( driver_SQLFreeStmt ); SET_EXPECT( driver_SQLFreeHandle_stmt ); ret = SQLFreeStmt( stmt, SQL_DROP ); CHECK_CALLED( driver_SQLFreeHandle_stmt ); - todo_wine CHECK_NOT_CALLED( driver_SQLFreeStmt ); ok( ret == SQL_SUCCESS, "got %d\n", ret ); SET_EXPECT( driver_SQLAllocHandle_stmt ); @@ -1288,11 +1280,9 @@ static void test_SQLExecDirect( void ) todo_wine CHECK_NOT_CALLED( driver_SQLSetStmtAttr ); ok( ret == SQL_ERROR, "got %d\n", ret ); - SET_EXPECT( driver_SQLFreeStmt ); SET_EXPECT( driver_SQLFreeHandle_stmt ); ret = SQLFreeStmt( stmt, SQL_DROP ); CHECK_CALLED( driver_SQLFreeHandle_stmt ); - todo_wine CHECK_NOT_CALLED( driver_SQLFreeStmt ); ok( ret == SQL_SUCCESS, "got %d\n", ret ); SET_EXPECT( driver_SQLDisconnect ); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10669
From: Piotr Caban <piotr@codeweavers.com> --- dlls/odbc32/proxyodbc.c | 12 +++++++++--- dlls/odbc32/tests/odbc32.c | 2 +- dlls/odbc32/unixlib.h | 2 ++ 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/dlls/odbc32/proxyodbc.c b/dlls/odbc32/proxyodbc.c index 7e97af63581..9fbe0f72d3c 100644 --- a/dlls/odbc32/proxyodbc.c +++ b/dlls/odbc32/proxyodbc.c @@ -439,7 +439,7 @@ static struct connection *create_connection( struct environment *env ) struct connection *ret; if (!(ret = calloc( 1, sizeof(*ret) ))) return NULL; init_object( &ret->hdr, SQL_HANDLE_DBC, &env->hdr ); - ret->attr_login_timeout = 15; + ret->attr_login_timeout = SQL_LOGIN_TIMEOUT_DEFAULT; return ret; } @@ -1439,9 +1439,11 @@ static SQLRETURN create_con( struct connection *con ) if ((ret = alloc_handle( SQL_HANDLE_DBC, con->hdr.parent, &con->hdr ))) return ret; - if (set_con_attr( con, SQL_ATTR_CONNECTION_TIMEOUT, INT_PTR(con->attr_con_timeout), 0 )) + if (con->con_timeout_set && + set_con_attr( con, SQL_ATTR_CONNECTION_TIMEOUT, INT_PTR(con->attr_con_timeout), 0 )) WARN( "failed to set connection timeout\n" ); - if (set_con_attr( con, SQL_ATTR_LOGIN_TIMEOUT, INT_PTR(con->attr_login_timeout), 0 )) + if (con->login_timeout_set && + set_con_attr( con, SQL_ATTR_LOGIN_TIMEOUT, INT_PTR(con->attr_login_timeout), 0 )) WARN( "failed to set login timeout\n" ); if (con->hdr.win32_handle) @@ -3680,10 +3682,12 @@ SQLRETURN WINAPI SQLSetConnectAttr(SQLHDBC ConnectionHandle, SQLINTEGER Attribut { case SQL_ATTR_CONNECTION_TIMEOUT: con->attr_con_timeout = (UINT32)(ULONG_PTR)Value; + con->con_timeout_set = TRUE; break; case SQL_ATTR_LOGIN_TIMEOUT: con->attr_login_timeout = (UINT32)(ULONG_PTR)Value; + con->login_timeout_set = TRUE; break; default: @@ -6994,10 +6998,12 @@ SQLRETURN WINAPI SQLSetConnectAttrW(SQLHDBC ConnectionHandle, SQLINTEGER Attribu { case SQL_ATTR_CONNECTION_TIMEOUT: con->attr_con_timeout = (UINT32)(ULONG_PTR)Value; + con->con_timeout_set = TRUE; break; case SQL_ATTR_LOGIN_TIMEOUT: con->attr_login_timeout = (UINT32)(ULONG_PTR)Value; + con->login_timeout_set = TRUE; break; default: diff --git a/dlls/odbc32/tests/odbc32.c b/dlls/odbc32/tests/odbc32.c index 41e5494f269..09fcf5b2d9f 100644 --- a/dlls/odbc32/tests/odbc32.c +++ b/dlls/odbc32/tests/odbc32.c @@ -175,7 +175,7 @@ static SQLRETURN WINAPI driver_SQLGetConnectAttr( SQLHDBC con, SQLINTEGER attr, static SQLRETURN WINAPI driver_SQLSetConnectAttr( SQLHDBC con, SQLINTEGER attr, SQLPOINTER val, SQLINTEGER len ) { - todo_wine ok( 0, "unexpected call\n" ); + ok( 0, "unexpected call\n" ); return SQL_ERROR; } diff --git a/dlls/odbc32/unixlib.h b/dlls/odbc32/unixlib.h index 637d88b096f..d4ff1e72ac3 100644 --- a/dlls/odbc32/unixlib.h +++ b/dlls/odbc32/unixlib.h @@ -212,7 +212,9 @@ struct connection struct object hdr; UINT32 driver_odbc_ver; /* attributes */ + BOOL con_timeout_set; UINT32 attr_con_timeout; + BOOL login_timeout_set; UINT32 attr_login_timeout; }; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10669
From: Piotr Caban <piotr@codeweavers.com> Environment attributes are handled by driver manager. --- dlls/odbc32/proxyodbc.c | 48 +++++++++----------------------------- dlls/odbc32/tests/odbc32.c | 7 ++++-- 2 files changed, 16 insertions(+), 39 deletions(-) diff --git a/dlls/odbc32/proxyodbc.c b/dlls/odbc32/proxyodbc.c index 9fbe0f72d3c..695b9548dcc 100644 --- a/dlls/odbc32/proxyodbc.c +++ b/dlls/odbc32/proxyodbc.c @@ -2984,21 +2984,6 @@ SQLRETURN WINAPI SQLGetDiagRec(SQLSMALLINT HandleType, SQLHANDLE Handle, SQLSMAL return ret; } -static SQLRETURN get_env_attr_unix( struct environment *env, SQLINTEGER attr, SQLPOINTER value, SQLINTEGER buflen, - SQLINTEGER *retlen ) -{ - struct SQLGetEnvAttr_params params = { env->hdr.unix_handle, attr, value, buflen, retlen }; - return ODBC_CALL( SQLGetEnvAttr, ¶ms ); -} - -static SQLRETURN get_env_attr_win32( struct environment *env, SQLINTEGER attr, SQLPOINTER value, SQLINTEGER buflen, - SQLINTEGER *retlen ) -{ - if (env->hdr.win32_funcs->SQLGetEnvAttr) - return env->hdr.win32_funcs->SQLGetEnvAttr( env->hdr.win32_handle, attr, value, buflen, retlen ); - return SQL_ERROR; -} - /************************************************************************* * SQLGetEnvAttr [ODBC32.037] */ @@ -3013,31 +2998,20 @@ SQLRETURN WINAPI SQLGetEnvAttr(SQLHENV EnvironmentHandle, SQLINTEGER Attribute, if (!env) return SQL_INVALID_HANDLE; - if (env->hdr.unix_handle) - { - ret = get_env_attr_unix( env, Attribute, Value, BufferLength, StringLength ); - } - else if (env->hdr.win32_handle) - { - ret = get_env_attr_win32( env, Attribute, Value, BufferLength, StringLength ); - } - else + switch (Attribute) { - switch (Attribute) - { - case SQL_ATTR_CONNECTION_POOLING: - *(SQLINTEGER *)Value = SQL_CP_OFF; - break; + case SQL_ATTR_CONNECTION_POOLING: + *(SQLINTEGER *)Value = SQL_CP_OFF; + break; - case SQL_ATTR_ODBC_VERSION: - *(SQLINTEGER *)Value = env->attr_version; - break; + case SQL_ATTR_ODBC_VERSION: + *(SQLINTEGER *)Value = env->attr_version; + break; - default: - FIXME( "unhandled attribute %d\n", Attribute ); - ret = SQL_ERROR; - break; - } + default: + FIXME( "unhandled attribute %d\n", Attribute ); + ret = SQL_ERROR; + break; } TRACE("Returning %d\n", ret); diff --git a/dlls/odbc32/tests/odbc32.c b/dlls/odbc32/tests/odbc32.c index 09fcf5b2d9f..3f105d22483 100644 --- a/dlls/odbc32/tests/odbc32.c +++ b/dlls/odbc32/tests/odbc32.c @@ -707,9 +707,8 @@ static void test_SQLConnect( void ) size = -1; ret = SQLGetEnvAttr( env, SQL_ATTR_ODBC_VERSION, &version, sizeof(version), &size ); ok( ret == SQL_SUCCESS, "got %d\n", ret ); - ok( version != -1, "version not set\n" ); + ok( version == SQL_OV_ODBC2, "version = %d\n", version ); ok( size == -1, "size set\n" ); - trace( "ODBC version %d\n", version ); pooling = -1; ret = SQLGetEnvAttr( env, SQL_ATTR_CONNECTION_POOLING, &pooling, sizeof(pooling), NULL ); @@ -762,6 +761,10 @@ static void test_SQLConnect( void ) ok (ret == SQL_SUCCESS, "got %d\n", ret ); if (ret == SQL_ERROR) diag( con, SQL_HANDLE_DBC ); + ret = SQLGetEnvAttr( env, SQL_ATTR_ODBC_VERSION, &version, sizeof(version), NULL ); + ok( ret == SQL_SUCCESS, "got %d\n", ret ); + ok( version == SQL_OV_ODBC2, "version = %d\n", version ); + timeout = 0xdeadbeef; SET_EXPECT( driver_SQLGetConnectAttr ); ret = SQLGetConnectAttr( con, SQL_ATTR_LOGIN_TIMEOUT, &timeout, sizeof(timeout), NULL ); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10669
From: Piotr Caban <piotr@codeweavers.com> --- dlls/odbc32/proxyodbc.c | 49 ++++++++++++-------------------------- dlls/odbc32/tests/odbc32.c | 3 +++ 2 files changed, 18 insertions(+), 34 deletions(-) diff --git a/dlls/odbc32/proxyodbc.c b/dlls/odbc32/proxyodbc.c index 695b9548dcc..566950d3faf 100644 --- a/dlls/odbc32/proxyodbc.c +++ b/dlls/odbc32/proxyodbc.c @@ -3911,19 +3911,6 @@ SQLRETURN WINAPI SQLSetDescRec(SQLHDESC DescriptorHandle, SQLSMALLINT RecNumber, return ret; } -static SQLRETURN set_env_attr_unix( struct environment *env, SQLINTEGER attr, SQLPOINTER value, SQLINTEGER len ) -{ - struct SQLSetEnvAttr_params params = { env->hdr.unix_handle, attr, value, len }; - return ODBC_CALL( SQLSetEnvAttr, ¶ms ); -} - -static SQLRETURN set_env_attr_win32( struct environment *env, SQLINTEGER attr, SQLPOINTER value, SQLINTEGER len ) -{ - if (env->hdr.win32_funcs->SQLSetEnvAttr) - return env->hdr.win32_funcs->SQLSetEnvAttr( env->hdr.win32_handle, attr, value, len ); - return SQL_ERROR; -} - /************************************************************************* * SQLSetEnvAttr [ODBC32.075] */ @@ -3942,31 +3929,25 @@ SQLRETURN WINAPI SQLSetEnvAttr(SQLHENV EnvironmentHandle, SQLINTEGER Attribute, return SQL_SUCCESS; } - if (env->hdr.unix_handle) - { - ret = set_env_attr_unix( env, Attribute, Value, StringLength ); - } - else if (env->hdr.win32_handle) - { - ret = set_env_attr_win32( env, Attribute, Value, StringLength ); - } - else + switch (Attribute) { - switch (Attribute) + case SQL_ATTR_ODBC_VERSION: + if (!list_empty( &env->hdr.children )) { - case SQL_ATTR_ODBC_VERSION: - env->attr_version = (UINT32)(ULONG_PTR)Value; - break; + FIXME( "report S1010 error\n" ); + return SQL_ERROR; + } + env->attr_version = (UINT32)(ULONG_PTR)Value; + break; - case SQL_ATTR_CONNECTION_POOLING: - FIXME("Ignore Pooling value\n"); - break; + case SQL_ATTR_CONNECTION_POOLING: + FIXME("Ignore Pooling value\n"); + break; - default: - FIXME( "unhandled attribute %d\n", Attribute ); - ret = SQL_ERROR; - break; - } + default: + FIXME( "unhandled attribute %d\n", Attribute ); + ret = SQL_ERROR; + break; } TRACE("Returning %d\n", ret); diff --git a/dlls/odbc32/tests/odbc32.c b/dlls/odbc32/tests/odbc32.c index 3f105d22483..0450ab5675a 100644 --- a/dlls/odbc32/tests/odbc32.c +++ b/dlls/odbc32/tests/odbc32.c @@ -761,6 +761,9 @@ static void test_SQLConnect( void ) ok (ret == SQL_SUCCESS, "got %d\n", ret ); if (ret == SQL_ERROR) diag( con, SQL_HANDLE_DBC ); + ret = SQLSetEnvAttr( env, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC2, 0 ); + ok( ret == SQL_ERROR, "got %d\n", ret ); + ret = SQLGetEnvAttr( env, SQL_ATTR_ODBC_VERSION, &version, sizeof(version), NULL ); ok( ret == SQL_SUCCESS, "got %d\n", ret ); ok( version == SQL_OV_ODBC2, "version = %d\n", version ); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10669
From: Piotr Caban <piotr@codeweavers.com> --- dlls/odbc32/proxyodbc.c | 465 +++++++++++++++++++++++++++++-------- dlls/odbc32/tests/odbc32.c | 18 +- dlls/odbc32/unixlib.h | 12 + 3 files changed, 381 insertions(+), 114 deletions(-) diff --git a/dlls/odbc32/proxyodbc.c b/dlls/odbc32/proxyodbc.c index 566950d3faf..8eb8f7999b6 100644 --- a/dlls/odbc32/proxyodbc.c +++ b/dlls/odbc32/proxyodbc.c @@ -468,6 +468,7 @@ static struct environment *create_environment( void ) struct environment *ret; if (!(ret = calloc( 1, sizeof(*ret) ))) return NULL; init_object( &ret->hdr, SQL_HANDLE_ENV, NULL ); + list_init( &ret->env_handles ); ret->attr_version = SQL_OV_ODBC2; return ret; } @@ -492,6 +493,12 @@ static SQLRETURN alloc_handle( SQLSMALLINT type, struct object *input, struct ob { SQLRETURN ret = SQL_ERROR; + if (type == SQL_HANDLE_ENV || type == SQL_HANDLE_DBC) + { + ERR( "invalid call\n" ); + return SQL_ERROR; + } + if (input->unix_handle) { struct SQLAllocHandle_params params = { type, input->unix_handle, &output->unix_handle }; @@ -505,14 +512,6 @@ static SQLRETURN alloc_handle( SQLSMALLINT type, struct object *input, struct ob { switch (type) { - case SQL_HANDLE_ENV: - if (input->win32_funcs->SQLAllocEnv) - ret = input->win32_funcs->SQLAllocEnv( &output->win32_handle ); - break; - case SQL_HANDLE_DBC: - if (input->win32_funcs->SQLAllocConnect) - ret = input->win32_funcs->SQLAllocConnect( input->win32_handle, &output->win32_handle ); - break; case SQL_HANDLE_STMT: if (input->win32_funcs->SQLAllocStmt) ret = input->win32_funcs->SQLAllocStmt( input->win32_handle, &output->win32_handle ); @@ -1261,56 +1260,108 @@ static int has_suffix( const WCHAR *str, const WCHAR *suffix ) return len >= len2 && !wcsicmp( str + len - len2, suffix ); } -static SQLRETURN set_env_attr( struct environment *env, SQLINTEGER attr, SQLPOINTER value, SQLINTEGER len ) +static SQLRETURN set_env_attr( struct env_handle *env, SQLINTEGER attr, SQLPOINTER value ) { SQLRETURN ret = SQL_ERROR; - if (env->hdr.unix_handle) + if (env->unix_handle) { - struct SQLSetEnvAttr_params params = { env->hdr.unix_handle, attr, value, len }; + struct SQLSetEnvAttr_params params = { env->unix_handle, attr, value, 0 }; ret = ODBC_CALL( SQLSetEnvAttr, ¶ms ); } - else if (env->hdr.win32_handle) + else { - if (env->hdr.win32_funcs->SQLSetEnvAttr) - ret = env->hdr.win32_funcs->SQLSetEnvAttr( env->hdr.win32_handle, attr, value, len ); + if (env->win32_funcs->SQLSetEnvAttr) + ret = env->win32_funcs->SQLSetEnvAttr( env->win32_handle, attr, value, 0 ); } return ret; } -static SQLRETURN alloc_env_handle( struct environment *env, BOOL is_unix ) +static SQLRETURN alloc_env_handle( struct env_handle *env ) { SQLRETURN ret = SQL_ERROR; - if (is_unix) + if (!env->win32_funcs) { - struct SQLAllocHandle_params params = { SQL_HANDLE_ENV, 0, &env->hdr.unix_handle }; + struct SQLAllocHandle_params params = { SQL_HANDLE_ENV, 0, &env->unix_handle }; ret = ODBC_CALL( SQLAllocHandle, ¶ms ); } else { - if (env->hdr.win32_funcs->SQLAllocHandle) - ret = env->hdr.win32_funcs->SQLAllocHandle( SQL_HANDLE_ENV, NULL, &env->hdr.win32_handle ); - else if (env->hdr.win32_funcs->SQLAllocEnv) - ret = env->hdr.win32_funcs->SQLAllocEnv( &env->hdr.win32_handle ); + if (env->win32_funcs->SQLAllocHandle) + ret = env->win32_funcs->SQLAllocHandle( SQL_HANDLE_ENV, NULL, &env->win32_handle ); + else if (env->win32_funcs->SQLAllocEnv) + ret = env->win32_funcs->SQLAllocEnv( &env->win32_handle ); } return ret; } -#define INT_PTR(val) (SQLPOINTER)(ULONG_PTR)val -static void prepare_env( struct environment *env ) +static void release_env( struct env_handle *env ) { - if (set_env_attr( env, SQL_ATTR_ODBC_VERSION, INT_PTR(env->attr_version), 0 )) - WARN( "failed to set ODBC version\n" ); + SQLRETURN ret = SQL_ERROR; + + if (!env || --env->ref) return; + + if (env->unix_handle) + { + struct SQLFreeHandle_params params = { SQL_HANDLE_ENV, env->unix_handle }; + ret = ODBC_CALL( SQLFreeHandle, ¶ms ); + } + else if (env->win32_funcs->SQLFreeHandle) + ret = env->win32_funcs->SQLFreeHandle( SQL_HANDLE_ENV, env->win32_handle ); + else if (env->win32_funcs->SQLFreeEnv) + ret = env->win32_funcs->SQLFreeEnv( env->win32_handle ); + + if (ret == SQL_SUCCESS) + { + list_remove( &env->entry ); + free( env ); + } } -static SQLRETURN create_env( struct environment *env, BOOL is_unix ) +#define INT_PTR(val) (SQLPOINTER)(ULONG_PTR)val +static SQLRETURN create_env( struct connection *con ) { + struct environment *env = (struct environment *)con->hdr.parent; + struct env_handle *cur; SQLRETURN ret; - if ((ret = alloc_env_handle( env, is_unix ))) return ret; - prepare_env( env ); + + EnterCriticalSection( &env->hdr.cs ); + + LIST_FOR_EACH_ENTRY( cur, &env->env_handles, struct env_handle, entry ) + { + if (con->hdr.win32_funcs == cur->win32_funcs) + { + cur->ref++; + release_env( con->env ); + con->env = cur; + LeaveCriticalSection( &env->hdr.cs ); + return SQL_SUCCESS; + } + } + + if (!(cur = calloc( 1, sizeof(*cur) ))) + { + LeaveCriticalSection( &env->hdr.cs ); + return SQL_ERROR; + } + cur->win32_funcs = con->hdr.win32_funcs; + cur->ref = 1; + ret = alloc_env_handle( cur ); + if (!SUCCESS(ret)) + { + free( cur ); + LeaveCriticalSection( &env->hdr.cs ); + return ret; + } + list_add_head( &env->env_handles, &cur->entry ); + con->env = cur; + LeaveCriticalSection( &env->hdr.cs ); + + if (set_env_attr( cur, SQL_ATTR_ODBC_VERSION, INT_PTR(env->attr_version) )) + WARN( "failed to set ODBC version\n" ); return SQL_SUCCESS; } @@ -1430,6 +1481,25 @@ static SQLRETURN get_info_win32_w( struct connection *con, SQLUSMALLINT type, SQ return ret; } +static SQLRETURN alloc_con_handle( struct connection *con ) +{ + SQLRETURN ret = SQL_ERROR; + + if (con->env->unix_handle) + { + struct SQLAllocHandle_params params = { SQL_HANDLE_DBC, con->env->unix_handle, &con->hdr.unix_handle }; + ret = ODBC_CALL( SQLAllocHandle, ¶ms ); + } + else + { + if (con->env->win32_funcs->SQLAllocHandle) + ret = con->env->win32_funcs->SQLAllocHandle( SQL_HANDLE_DBC, con->env->win32_handle, &con->hdr.win32_handle ); + else if (con->env->win32_funcs->SQLAllocConnect) + ret = con->env->win32_funcs->SQLAllocConnect( con->env->win32_handle, &con->hdr.win32_handle ); + } + + return ret; +} static SQLRETURN create_con( struct connection *con ) { @@ -1437,7 +1507,7 @@ static SQLRETURN create_con( struct connection *con ) SQLSMALLINT len; SQLRETURN ret; - if ((ret = alloc_handle( SQL_HANDLE_DBC, con->hdr.parent, &con->hdr ))) return ret; + if ((ret = alloc_con_handle( con ))) return ret; if (con->con_timeout_set && set_con_attr( con, SQL_ATTR_CONNECTION_TIMEOUT, INT_PTR(con->attr_con_timeout), 0 )) @@ -1518,23 +1588,26 @@ SQLRETURN WINAPI SQLConnect(SQLHDBC ConnectionHandle, SQLCHAR *ServerName, SQLSM if (has_suffix( filename, L".dll" )) { - if (!(con->hdr.win32_funcs = con->hdr.parent->win32_funcs = load_driver( filename ))) + con->hdr.unix_handle = 0; + if (!(con->hdr.win32_funcs = load_driver( filename ))) { WARN( "failed to load driver %s\n", debugstr_w(filename) ); goto done; } TRACE( "using Windows driver %s\n", debugstr_w(filename) ); - if (!SUCCESS((ret = create_env( (struct environment *)con->hdr.parent, FALSE )))) goto done; + if (!SUCCESS((ret = create_env( con )))) goto done; if (!SUCCESS((ret = create_con( con )))) goto done; ret = connect_win32_a( con, ServerName, NameLength1, UserName, NameLength2, Authentication, NameLength3 ); } else { + con->hdr.win32_handle = 0; + con->hdr.win32_funcs = NULL; TRACE( "using Unix driver %s\n", debugstr_w(filename) ); - if (!SUCCESS((ret = create_env( (struct environment *)con->hdr.parent, TRUE )))) goto done; + if (!SUCCESS((ret = create_env( con )))) goto done; if (!SUCCESS((ret = create_con( con )))) goto done; ret = connect_unix_a( con, ServerName, NameLength1, UserName, NameLength2, Authentication, NameLength3 ); @@ -1834,32 +1907,49 @@ SQLRETURN WINAPI SQLEndTran(SQLSMALLINT HandleType, SQLHANDLE Handle, SQLSMALLIN { ret = end_tran_win32( HandleType, obj, CompletionType ); } + else if (HandleType == SQL_HANDLE_ENV) + { + struct connection *con; + + LIST_FOR_EACH_ENTRY( con, &obj->children, struct connection, hdr.entry ) + { + EnterCriticalSection( &con->hdr.cs ); + /* TODO: we should call SQLEndTran depending on connection state */ + if (con->hdr.unix_handle) + ret = end_tran_unix( SQL_HANDLE_DBC, &con->hdr, CompletionType ); + else + ret = end_tran_win32( SQL_HANDLE_DBC, &con->hdr, CompletionType ); + LeaveCriticalSection( &con->hdr.cs ); + + if (ret != SQL_SUCCESS) break; + } + } TRACE("Returning %d\n", ret); unlock_object( obj ); return ret; } -static SQLRETURN error_unix_a( struct environment *env, struct connection *con, struct statement *stmt, SQLCHAR *state, +static SQLRETURN error_unix_a( struct env_handle *env, struct connection *con, struct statement *stmt, SQLCHAR *state, SQLINTEGER *native_err, SQLCHAR *msg, SQLSMALLINT buflen, SQLSMALLINT *retlen ) { - struct SQLError_params params = { env ? env->hdr.unix_handle : 0, con ? con->hdr.unix_handle : 0, + struct SQLError_params params = { env ? env->unix_handle : 0, con ? con->hdr.unix_handle : 0, stmt ? stmt->hdr.unix_handle : 0, state, native_err, msg, buflen, retlen }; return ODBC_CALL( SQLError, ¶ms ); } -static SQLRETURN error_win32_a( struct environment *env, struct connection *con, struct statement *stmt, SQLCHAR *state, +static SQLRETURN error_win32_a( struct env_handle *env, struct connection *con, struct statement *stmt, SQLCHAR *state, SQLINTEGER *native_err, SQLCHAR *msg, SQLSMALLINT buflen, SQLSMALLINT *retlen ) { const struct win32_funcs *win32_funcs; SQLRETURN ret = SQL_ERROR; - if (env) win32_funcs = env->hdr.win32_funcs; + if (env) win32_funcs = env->win32_funcs; else if (con) win32_funcs = con->hdr.win32_funcs; else win32_funcs = stmt->hdr.win32_funcs; if (win32_funcs->SQLError) - return win32_funcs->SQLError( env ? env->hdr.win32_handle : NULL, con ? con->hdr.win32_handle : NULL, + return win32_funcs->SQLError( env ? env->win32_handle : NULL, con ? con->hdr.win32_handle : NULL, stmt ? stmt->hdr.win32_handle : NULL, state, native_err, msg, buflen, retlen ); if (win32_funcs->SQLErrorW) @@ -1868,7 +1958,7 @@ static SQLRETURN error_win32_a( struct environment *env, struct connection *con, SQLSMALLINT lenW; if (!(msgW = malloc( buflen * sizeof(SQLWCHAR) ))) return SQL_ERROR; - ret = win32_funcs->SQLErrorW( env ? env->hdr.win32_handle : NULL, con ? con->hdr.win32_handle : NULL, + ret = win32_funcs->SQLErrorW( env ? env->win32_handle : NULL, con ? con->hdr.win32_handle : NULL, stmt ? stmt->hdr.win32_handle : NULL, stateW, native_err, msgW, buflen, &lenW ); if (SUCCESS( ret )) { @@ -1887,6 +1977,7 @@ static SQLRETURN error_win32_a( struct environment *env, struct connection *con, /************************************************************************* * SQLError [ODBC32.010] + * FIXME: implement proper error handling. */ SQLRETURN WINAPI SQLError(SQLHENV EnvironmentHandle, SQLHDBC ConnectionHandle, SQLHSTMT StatementHandle, SQLCHAR *SqlState, SQLINTEGER *NativeError, SQLCHAR *MessageText, @@ -1895,7 +1986,7 @@ SQLRETURN WINAPI SQLError(SQLHENV EnvironmentHandle, SQLHDBC ConnectionHandle, S struct environment *env = (struct environment *)lock_object( EnvironmentHandle, SQL_HANDLE_ENV ); struct connection *con = (struct connection *)lock_object( ConnectionHandle, SQL_HANDLE_DBC ); struct statement *stmt = (struct statement *)lock_object( StatementHandle, SQL_HANDLE_STMT ); - SQLRETURN ret = SQL_ERROR; + SQLRETURN ret = SQL_NO_DATA; TRACE("(EnvironmentHandle %p, ConnectionHandle %p, StatementHandle %p, SqlState %p, NativeError %p," " MessageText %p, BufferLength %d, TextLength %p)\n", EnvironmentHandle, ConnectionHandle, @@ -1903,13 +1994,33 @@ SQLRETURN WINAPI SQLError(SQLHENV EnvironmentHandle, SQLHDBC ConnectionHandle, S if (!env && !con && !stmt) return SQL_INVALID_HANDLE; - if ((env && env->hdr.unix_handle) || (con && con->hdr.unix_handle) || (stmt && stmt->hdr.unix_handle)) + if ((con && con->hdr.unix_handle) || (stmt && stmt->hdr.unix_handle)) { - ret = error_unix_a( env, con, stmt, SqlState, NativeError, MessageText, BufferLength, TextLength ); + ret = error_unix_a( NULL, con, stmt, SqlState, NativeError, MessageText, BufferLength, TextLength ); } - else if ((env && env->hdr.win32_handle) || (con && con->hdr.win32_handle) || (stmt && stmt->hdr.win32_handle)) + else if ((con && con->hdr.win32_handle) || (stmt && stmt->hdr.win32_handle)) { - ret = error_win32_a( env, con, stmt, SqlState, NativeError, MessageText, BufferLength, TextLength ); + ret = error_win32_a( NULL, con, stmt, SqlState, NativeError, MessageText, BufferLength, TextLength ); + } + else if (env) + { + struct env_handle *env_handle; + + LIST_FOR_EACH_ENTRY( env_handle, &env->env_handles, struct env_handle, entry ) + { + if (env_handle->unix_handle) + { + ret = error_unix_a( env_handle, NULL, NULL, SqlState, + NativeError, MessageText, BufferLength, TextLength ); + } + else + { + ret = error_win32_a( env_handle, NULL, NULL, SqlState, + NativeError, MessageText, BufferLength, TextLength ); + } + + if (ret != SQL_NO_DATA) break; + } } if (SUCCESS( ret )) @@ -2184,10 +2295,6 @@ static SQLRETURN free_handle( SQLSMALLINT type, struct object *obj ) { switch (type) { - case SQL_HANDLE_ENV: - if (obj->win32_funcs->SQLFreeEnv) - ret = obj->win32_funcs->SQLFreeEnv( obj->win32_handle ); - break; case SQL_HANDLE_DBC: if (obj->win32_funcs->SQLFreeConnect) ret = obj->win32_funcs->SQLFreeConnect( obj->win32_handle ); @@ -2220,6 +2327,7 @@ SQLRETURN WINAPI SQLFreeConnect(SQLHDBC ConnectionHandle) else { ret = free_handle( SQL_HANDLE_DBC, &con->hdr ); + cleanup_object( &con->hdr ); con->hdr.closed = TRUE; } @@ -2235,7 +2343,7 @@ SQLRETURN WINAPI SQLFreeConnect(SQLHDBC ConnectionHandle) SQLRETURN WINAPI SQLFreeEnv(SQLHENV EnvironmentHandle) { struct environment *env = (struct environment *)lock_object( EnvironmentHandle, SQL_HANDLE_ENV ); - SQLRETURN ret; + SQLRETURN ret = SQL_SUCCESS; TRACE("(EnvironmentHandle %p)\n", EnvironmentHandle); @@ -2244,10 +2352,7 @@ SQLRETURN WINAPI SQLFreeEnv(SQLHENV EnvironmentHandle) if (!list_empty( &env->hdr.children )) ret = SQL_ERROR; else { - ret = free_handle( SQL_HANDLE_ENV, &env->hdr ); - - RegCloseKey( env->drivers_key ); - RegCloseKey( env->sources_key ); + cleanup_object( &env->hdr ); env->hdr.closed = TRUE; } @@ -2290,6 +2395,13 @@ static void cleanup_object( struct object *obj ) env->drivers_idx = env->sources_idx = 0; break; } + case SQL_HANDLE_DBC: + { + struct connection *con = (struct connection *)obj;; + release_env( con->env ); + con->env = NULL; + break; + } case SQL_HANDLE_STMT: { struct statement *stmt = (struct statement *)obj; @@ -2863,7 +2975,7 @@ SQLRETURN WINAPI SQLGetDiagField(SQLSMALLINT HandleType, SQLHANDLE Handle, SQLSM SQLSMALLINT *StringLength) { struct object *obj = lock_object( Handle, HandleType ); - SQLRETURN ret = SQL_ERROR; + SQLRETURN ret = SQL_NO_DATA; TRACE("(HandleType %d, Handle %p, RecNumber %d, DiagIdentifier %d, DiagInfo %p, BufferLength %d," " StringLength %p)\n", HandleType, Handle, RecNumber, DiagIdentifier, DiagInfo, BufferLength, StringLength); @@ -2880,6 +2992,33 @@ SQLRETURN WINAPI SQLGetDiagField(SQLSMALLINT HandleType, SQLHANDLE Handle, SQLSM ret = get_diag_field_win32_a( HandleType, obj, RecNumber, DiagIdentifier, DiagInfo, BufferLength, StringLength ); } + else if (HandleType == SQL_HANDLE_ENV) + { + struct environment *env = (struct environment *)obj; + struct env_handle *env_handle; + + LIST_FOR_EACH_ENTRY( env_handle, &env->env_handles, struct env_handle, entry ) + { + struct object env_obj; + + env_obj.unix_handle = env_handle->unix_handle; + env_obj.win32_handle = env_handle->win32_handle; + env_obj.win32_funcs = env_handle->win32_funcs; + + if (env_handle->unix_handle) + { + ret = get_diag_field_unix_a( HandleType, &env_obj, RecNumber, + DiagIdentifier, DiagInfo, BufferLength, StringLength ); + } + else + { + ret = get_diag_field_win32_a( HandleType, &env_obj, RecNumber, + DiagIdentifier, DiagInfo, BufferLength, StringLength ); + } + + if (ret != SQL_NO_DATA) break; + } + } TRACE("Returning %d\n", ret); unlock_object( obj ); @@ -2978,6 +3117,33 @@ SQLRETURN WINAPI SQLGetDiagRec(SQLSMALLINT HandleType, SQLHANDLE Handle, SQLSMAL ret = get_diag_rec_win32_a( HandleType, obj, RecNumber, SqlState, NativeError, MessageText, BufferLength, TextLength ); } + else if (HandleType == SQL_HANDLE_ENV) + { + struct environment *env = (struct environment *)obj; + struct env_handle *env_handle; + + LIST_FOR_EACH_ENTRY( env_handle, &env->env_handles, struct env_handle, entry ) + { + struct object env_obj; + + env_obj.unix_handle = env_handle->unix_handle; + env_obj.win32_handle = env_handle->win32_handle; + env_obj.win32_funcs = env_handle->win32_funcs; + + if (env_handle->unix_handle) + { + ret = get_diag_rec_unix_a( HandleType, &env_obj, RecNumber, SqlState, + NativeError, MessageText, BufferLength, TextLength ); + } + else + { + ret = get_diag_rec_win32_a( HandleType, &env_obj, RecNumber, SqlState, + NativeError, MessageText, BufferLength, TextLength ); + } + + if (ret != SQL_NO_DATA) break; + } + } TRACE("Returning %d\n", ret); unlock_object( obj ); @@ -4424,28 +4590,21 @@ SQLRETURN WINAPI SQLTables(SQLHSTMT StatementHandle, SQLCHAR *CatalogName, SQLSM return ret; } -static SQLRETURN transact_unix( struct environment *env, struct connection *con, SQLUSMALLINT completion ) +static SQLRETURN transact_unix( struct connection *con, SQLUSMALLINT completion ) { - struct SQLTransact_params params = { env ? env->hdr.unix_handle : 0, con ? con->hdr.unix_handle : 0, completion }; + struct SQLTransact_params params = { 0, con->hdr.unix_handle, completion }; return ODBC_CALL( SQLTransact, ¶ms ); } -static SQLRETURN transact_win32( struct environment *env, struct connection *con, SQLUSMALLINT completion ) +static SQLRETURN transact_win32( struct connection *con, SQLUSMALLINT completion ) { - const struct win32_funcs *win32_funcs; + const struct win32_funcs *funcs = con->hdr.win32_funcs; - if (env) win32_funcs = env->hdr.win32_funcs; - else win32_funcs = con->hdr.win32_funcs; + if (funcs->SQLTransact) + return funcs->SQLTransact( NULL, con->hdr.win32_handle, completion ); - if (win32_funcs->SQLTransact) - return win32_funcs->SQLTransact( env ? env->hdr.win32_handle : NULL, con ? con->hdr.win32_handle : NULL, - completion ); - - if (win32_funcs->SQLEndTran) - { - if (con) return win32_funcs->SQLEndTran( SQL_HANDLE_DBC, con->hdr.win32_handle, completion ); - return win32_funcs->SQLEndTran( SQL_HANDLE_ENV, env->hdr.win32_handle, completion ); - } + if (funcs->SQLEndTran) + return funcs->SQLEndTran( SQL_HANDLE_DBC, con->hdr.win32_handle, completion ); return SQL_ERROR; } @@ -4457,20 +4616,37 @@ SQLRETURN WINAPI SQLTransact(SQLHENV EnvironmentHandle, SQLHDBC ConnectionHandle { struct environment *env = (struct environment *)lock_object( EnvironmentHandle, SQL_HANDLE_ENV ); struct connection *con = (struct connection *)lock_object( ConnectionHandle, SQL_HANDLE_DBC ); - SQLRETURN ret = SQL_ERROR; + SQLRETURN ret = SQL_SUCCESS; TRACE("(EnvironmentHandle %p, ConnectionHandle %p, CompletionType %d)\n", EnvironmentHandle, ConnectionHandle, CompletionType); if (!env && !con) return SQL_INVALID_HANDLE; - if ((env && env->hdr.unix_handle) || (con && con->hdr.unix_handle)) + if (con && con->hdr.unix_handle) { - ret = transact_unix( env, con, CompletionType ); + ret = transact_unix( con, CompletionType ); } - else if ((env && env->hdr.win32_handle) || (con && con->hdr.win32_handle)) + else if (con) { - ret = transact_win32( env, con, CompletionType ); + ret = transact_win32( con, CompletionType ); + } + else + { + struct connection *cur; + + LIST_FOR_EACH_ENTRY( cur, &env->hdr.children, struct connection, hdr.entry ) + { + EnterCriticalSection( &cur->hdr.cs ); + /* TODO: we should call SQLTransact depending on connection state */ + if (cur->hdr.unix_handle) + ret = transact_unix( cur, CompletionType ); + else + ret = transact_win32( cur, CompletionType ); + LeaveCriticalSection( &cur->hdr.cs ); + + if (ret != SQL_SUCCESS) break; + } } TRACE("Returning %d\n", ret); @@ -4697,23 +4873,26 @@ SQLRETURN WINAPI SQLBrowseConnect(SQLHDBC ConnectionHandle, SQLCHAR *InConnectio if (has_suffix( filename, L".dll" )) { - if (!(con->hdr.win32_funcs = con->hdr.parent->win32_funcs = load_driver( filename ))) + con->hdr.unix_handle = 0; + if (!(con->hdr.win32_funcs = load_driver( filename ))) { WARN( "failed to load driver %s\n", debugstr_w(filename) ); goto done; } TRACE( "using Windows driver %s\n", debugstr_w(filename) ); - if (!SUCCESS((ret = create_env( (struct environment *)con->hdr.parent, FALSE )))) goto done; + if (!SUCCESS((ret = create_env( con )))) goto done; if (!SUCCESS((ret = create_con( con )))) goto done; ret = browse_connect_win32_a( con, strA, StringLength1, OutConnectionString, BufferLength, StringLength2 ); } else { + con->hdr.win32_handle = 0; + con->hdr.win32_funcs = NULL; TRACE( "using Unix driver %s\n", debugstr_w(filename) ); - if (!SUCCESS((ret = create_env( (struct environment *)con->hdr.parent, TRUE )))) goto done; + if (!SUCCESS((ret = create_env( con )))) goto done; if (!SUCCESS((ret = create_con( con )))) goto done; ret = browse_connect_unix_a( con, strA, StringLength1, OutConnectionString, BufferLength, StringLength2 ); @@ -5846,14 +6025,15 @@ SQLRETURN WINAPI SQLDriverConnect(SQLHDBC ConnectionHandle, SQLHWND WindowHandle if (has_suffix( filename, L".dll" )) { - if (!(con->hdr.win32_funcs = con->hdr.parent->win32_funcs = load_driver( filename ))) + con->hdr.unix_handle = 0; + if (!(con->hdr.win32_funcs = load_driver( filename ))) { WARN( "failed to load driver %s\n", debugstr_w(filename) ); goto done; } TRACE( "using Windows driver %s\n", debugstr_w(filename) ); - if (!SUCCESS((ret = create_env( (struct environment *)con->hdr.parent, FALSE )))) goto done; + if (!SUCCESS((ret = create_env( con )))) goto done; if (!SUCCESS((ret = create_con( con )))) goto done; ret = driver_connect_win32_a( con, WindowHandle, strA, Length, OutConnectionString, BufferLength, Length2, @@ -5861,9 +6041,11 @@ SQLRETURN WINAPI SQLDriverConnect(SQLHDBC ConnectionHandle, SQLHWND WindowHandle } else { + con->hdr.win32_handle = 0; + con->hdr.win32_funcs = NULL; TRACE( "using Unix driver %s\n", debugstr_w(filename) ); - if (!SUCCESS((ret = create_env( (struct environment *)con->hdr.parent, TRUE )))) goto done; + if (!SUCCESS((ret = create_env( con )))) goto done; if (!SUCCESS((ret = create_con( con )))) goto done; ret = driver_connect_unix_a( con, WindowHandle, strA, Length, OutConnectionString, BufferLength, Length2, @@ -6067,23 +6249,26 @@ SQLRETURN WINAPI SQLConnectW(SQLHDBC ConnectionHandle, SQLWCHAR *ServerName, SQL if (has_suffix( filename, L".dll" )) { - if (!(con->hdr.win32_funcs = con->hdr.parent->win32_funcs = load_driver( filename ))) + con->hdr.unix_handle = 0; + if (!(con->hdr.win32_funcs = load_driver( filename ))) { WARN( "failed to load driver %s\n", debugstr_w(filename) ); goto done; } TRACE( "using Windows driver %s\n", debugstr_w(filename) ); - if (!SUCCESS((ret = create_env( (struct environment *)con->hdr.parent, FALSE )))) goto done; + if (!SUCCESS((ret = create_env( con )))) goto done; if (!SUCCESS((ret = create_con( con )))) goto done; ret = connect_win32_w( con, ServerName, NameLength1, UserName, NameLength2, Authentication, NameLength3 ); } else { + con->hdr.win32_handle = 0; + con->hdr.win32_funcs = NULL; TRACE( "using Unix driver %s\n", debugstr_w(filename) ); - if (!SUCCESS((ret = create_env( (struct environment *)con->hdr.parent, TRUE )))) goto done; + if (!SUCCESS((ret = create_env( con )))) goto done; if (!SUCCESS((ret = create_con( con )))) goto done; ret = connect_unix_w( con, ServerName, NameLength1, UserName, NameLength2, Authentication, NameLength3 ); @@ -6155,26 +6340,26 @@ SQLRETURN WINAPI SQLDescribeColW(SQLHSTMT StatementHandle, SQLUSMALLINT ColumnNu return ret; } -static SQLRETURN error_unix_w( struct environment *env, struct connection *con, struct statement *stmt, SQLWCHAR *state, +static SQLRETURN error_unix_w( struct env_handle *env, struct connection *con, struct statement *stmt, SQLWCHAR *state, SQLINTEGER *native_err, SQLWCHAR *msg, SQLSMALLINT buflen, SQLSMALLINT *retlen ) { - struct SQLErrorW_params params = { env ? env->hdr.unix_handle : 0, con ? con->hdr.unix_handle : 0, + struct SQLErrorW_params params = { env ? env->unix_handle : 0, con ? con->hdr.unix_handle : 0, stmt ? stmt->hdr.unix_handle : 0, state, native_err, msg, buflen, retlen }; return ODBC_CALL( SQLErrorW, ¶ms ); } -static SQLRETURN error_win32_w( struct environment *env, struct connection *con, struct statement *stmt, SQLWCHAR *state, +static SQLRETURN error_win32_w( struct env_handle *env, struct connection *con, struct statement *stmt, SQLWCHAR *state, SQLINTEGER *native_err, SQLWCHAR *msg, SQLSMALLINT buflen, SQLSMALLINT *retlen ) { const struct win32_funcs *win32_funcs; SQLRETURN ret; - if (env) win32_funcs = env->hdr.win32_funcs; + if (env) win32_funcs = env->win32_funcs; else if (con) win32_funcs = con->hdr.win32_funcs; else win32_funcs = stmt->hdr.win32_funcs; if (win32_funcs->SQLErrorW) - return win32_funcs->SQLErrorW( env ? env->hdr.win32_handle : NULL, con ? con->hdr.win32_handle : NULL, + return win32_funcs->SQLErrorW( env ? env->win32_handle : NULL, con ? con->hdr.win32_handle : NULL, stmt ? stmt->hdr.win32_handle : NULL, state, native_err, msg, buflen, retlen ); if (win32_funcs->SQLError) { @@ -6182,7 +6367,7 @@ static SQLRETURN error_win32_w( struct environment *env, struct connection *con, SQLSMALLINT lenA; if (!(msgA = malloc( buflen * sizeof(*msgA) ))) return SQL_ERROR; - ret = win32_funcs->SQLError( env ? env->hdr.win32_handle : NULL, con ? con->hdr.win32_handle : NULL, + ret = win32_funcs->SQLError( env ? env->win32_handle : NULL, con ? con->hdr.win32_handle : NULL, stmt ? stmt->hdr.win32_handle : NULL, stateA, native_err, msgA, buflen, &lenA ); if (SUCCESS( ret )) { @@ -6211,7 +6396,7 @@ SQLRETURN WINAPI SQLErrorW(SQLHENV EnvironmentHandle, SQLHDBC ConnectionHandle, struct environment *env = (struct environment *)lock_object( EnvironmentHandle, SQL_HANDLE_ENV ); struct connection *con = (struct connection *)lock_object( ConnectionHandle, SQL_HANDLE_DBC ); struct statement *stmt = (struct statement *)lock_object( StatementHandle, SQL_HANDLE_STMT ); - SQLRETURN ret = SQL_ERROR; + SQLRETURN ret = SQL_NO_DATA; TRACE("(EnvironmentHandle %p, ConnectionHandle %p, StatementHandle %p, SqlState %p, NativeError %p," " MessageText %p, BufferLength %d, TextLength %p)\n", EnvironmentHandle, ConnectionHandle, @@ -6219,13 +6404,33 @@ SQLRETURN WINAPI SQLErrorW(SQLHENV EnvironmentHandle, SQLHDBC ConnectionHandle, if (!env && !con && !stmt) return SQL_INVALID_HANDLE; - if ((env && env->hdr.unix_handle) || (con && con->hdr.unix_handle) || (stmt && stmt->hdr.unix_handle)) + if ((con && con->hdr.unix_handle) || (stmt && stmt->hdr.unix_handle)) { - ret = error_unix_w( env, con, stmt, SqlState, NativeError, MessageText, BufferLength, TextLength ); + ret = error_unix_w( NULL, con, stmt, SqlState, NativeError, MessageText, BufferLength, TextLength ); } - else if ((env && env->hdr.win32_handle) || (con && con->hdr.win32_handle) || (stmt && stmt->hdr.win32_handle)) + else if ((con && con->hdr.win32_handle) || (stmt && stmt->hdr.win32_handle)) { - ret = error_win32_w( env, con, stmt, SqlState, NativeError, MessageText, BufferLength, TextLength ); + ret = error_win32_w( NULL, con, stmt, SqlState, NativeError, MessageText, BufferLength, TextLength ); + } + else if (env) + { + struct env_handle *env_handle; + + LIST_FOR_EACH_ENTRY( env_handle, &env->env_handles, struct env_handle, entry ) + { + if (env_handle->unix_handle) + { + ret = error_unix_w( env_handle, NULL, NULL, SqlState, + NativeError, MessageText, BufferLength, TextLength ); + } + else + { + ret = error_win32_w( env_handle, NULL, NULL, SqlState, + NativeError, MessageText, BufferLength, TextLength ); + } + + if (ret != SQL_NO_DATA) break; + } } if (SUCCESS( ret )) @@ -6731,7 +6936,7 @@ SQLRETURN WINAPI SQLGetDiagFieldW(SQLSMALLINT HandleType, SQLHANDLE Handle, SQLS SQLSMALLINT *StringLength) { struct object *obj = lock_object( Handle, HandleType ); - SQLRETURN ret = SQL_ERROR; + SQLRETURN ret = SQL_NO_DATA; TRACE("(HandleType %d, Handle %p, RecNumber %d, DiagIdentifier %d, DiagInfo %p, BufferLength %d," " StringLength %p)\n", HandleType, Handle, RecNumber, DiagIdentifier, DiagInfo, BufferLength, StringLength); @@ -6748,6 +6953,33 @@ SQLRETURN WINAPI SQLGetDiagFieldW(SQLSMALLINT HandleType, SQLHANDLE Handle, SQLS ret = get_diag_field_win32_w( HandleType, obj, RecNumber, DiagIdentifier, DiagInfo, BufferLength, StringLength ); } + else if (HandleType == SQL_HANDLE_ENV) + { + struct environment *env = (struct environment *)obj; + struct env_handle *env_handle; + + LIST_FOR_EACH_ENTRY( env_handle, &env->env_handles, struct env_handle, entry ) + { + struct object env_obj; + + env_obj.unix_handle = env_handle->unix_handle; + env_obj.win32_handle = env_handle->win32_handle; + env_obj.win32_funcs = env_handle->win32_funcs; + + if (env_handle->unix_handle) + { + ret = get_diag_field_unix_w( HandleType, &env_obj, RecNumber, + DiagIdentifier, DiagInfo, BufferLength, StringLength ); + } + else + { + ret = get_diag_field_win32_w( HandleType, &env_obj, RecNumber, + DiagIdentifier, DiagInfo, BufferLength, StringLength ); + } + + if (ret != SQL_NO_DATA) break; + } + } TRACE("Returning %d\n", ret); unlock_object( obj ); @@ -6833,6 +7065,33 @@ SQLRETURN WINAPI SQLGetDiagRecW(SQLSMALLINT HandleType, SQLHANDLE Handle, SQLSMA ret = get_diag_rec_win32_w( HandleType, obj, RecNumber, SqlState, NativeError, MessageText, BufferLength, TextLength ); } + else if (HandleType == SQL_HANDLE_ENV) + { + struct environment *env = (struct environment *)obj; + struct env_handle *env_handle; + + LIST_FOR_EACH_ENTRY( env_handle, &env->env_handles, struct env_handle, entry ) + { + struct object env_obj; + + env_obj.unix_handle = env_handle->unix_handle; + env_obj.win32_handle = env_handle->win32_handle; + env_obj.win32_funcs = env_handle->win32_funcs; + + if (env_handle->unix_handle) + { + ret = get_diag_rec_unix_w( HandleType, &env_obj, RecNumber, SqlState, + NativeError, MessageText, BufferLength, TextLength ); + } + else + { + ret = get_diag_rec_win32_w( HandleType, &env_obj, RecNumber, SqlState, + NativeError, MessageText, BufferLength, TextLength ); + } + + if (ret != SQL_NO_DATA) break; + } + } TRACE("Returning %d\n", ret); unlock_object( obj ); @@ -7124,14 +7383,15 @@ SQLRETURN WINAPI SQLDriverConnectW(SQLHDBC ConnectionHandle, SQLHWND WindowHandl if (has_suffix( filename, L".dll" )) { - if (!(con->hdr.win32_funcs = con->hdr.parent->win32_funcs = load_driver( filename ))) + con->hdr.unix_handle = 0; + if (!(con->hdr.win32_funcs = load_driver( filename ))) { WARN( "failed to load driver %s\n", debugstr_w(filename) ); goto done; } TRACE( "using Windows driver %s\n", debugstr_w(filename) ); - if (!SUCCESS((ret = create_env( (struct environment *)con->hdr.parent, FALSE )))) goto done; + if (!SUCCESS((ret = create_env( con )))) goto done; if (!SUCCESS((ret = create_con( con )))) goto done; ret = driver_connect_win32_w( con, WindowHandle, InConnectionString, Length, OutConnectionString, @@ -7139,9 +7399,11 @@ SQLRETURN WINAPI SQLDriverConnectW(SQLHDBC ConnectionHandle, SQLHWND WindowHandl } else { + con->hdr.win32_handle = 0; + con->hdr.win32_funcs = NULL; TRACE( "using Unix driver %s\n", debugstr_w(filename) ); - if (!SUCCESS((ret = create_env( (struct environment *)con->hdr.parent, TRUE )))) goto done; + if (!SUCCESS((ret = create_env( con )))) goto done; if (!SUCCESS((ret = create_con( con )))) goto done; ret = driver_connect_unix_w( con, WindowHandle, InConnectionString, Length, OutConnectionString, @@ -7581,14 +7843,15 @@ SQLRETURN WINAPI SQLBrowseConnectW(SQLHDBC ConnectionHandle, SQLWCHAR *InConnect if (has_suffix( filename, L".dll" )) { - if (!(con->hdr.win32_funcs = con->hdr.parent->win32_funcs = load_driver( filename ))) + con->hdr.unix_handle = 0; + if (!(con->hdr.win32_funcs = load_driver( filename ))) { WARN( "failed to load driver %s\n", debugstr_w(filename) ); goto done; } TRACE( "using Windows driver %s\n", debugstr_w(filename) ); - if (!SUCCESS((ret = create_env( (struct environment *)con->hdr.parent, FALSE )))) goto done; + if (!SUCCESS((ret = create_env( con )))) goto done; if (!SUCCESS((ret = create_con( con )))) goto done; ret = browse_connect_win32_w( con, connect_string, StringLength1, OutConnectionString, BufferLength, @@ -7596,9 +7859,11 @@ SQLRETURN WINAPI SQLBrowseConnectW(SQLHDBC ConnectionHandle, SQLWCHAR *InConnect } else { + con->hdr.win32_handle = 0; + con->hdr.win32_funcs = NULL; TRACE( "using Unix driver %s\n", debugstr_w(filename) ); - if (!SUCCESS((ret = create_env( (struct environment *)con->hdr.parent, TRUE )))) goto done; + if (!SUCCESS((ret = create_env( con )))) goto done; if (!SUCCESS((ret = create_con( con )))) goto done; ret = browse_connect_unix_w( con, connect_string, StringLength1, OutConnectionString, BufferLength, diff --git a/dlls/odbc32/tests/odbc32.c b/dlls/odbc32/tests/odbc32.c index 0450ab5675a..14a39e08ec7 100644 --- a/dlls/odbc32/tests/odbc32.c +++ b/dlls/odbc32/tests/odbc32.c @@ -805,12 +805,10 @@ static void test_SQLConnect( void ) SET_EXPECT( driver_SQLFreeHandle_env ); ret = SQLFreeConnect( con ); CHECK_CALLED( driver_SQLFreeHandle_con ); - todo_wine CHECK_CALLED( driver_SQLFreeHandle_env ); + CHECK_CALLED( driver_SQLFreeHandle_env ); ok( ret == SQL_SUCCESS, "got %d\n", ret ); - SET_EXPECT( driver_SQLFreeHandle_env ); ret = SQLFreeEnv( env ); - todo_wine CHECK_NOT_CALLED( driver_SQLFreeHandle_env ); ok( ret == SQL_SUCCESS, "got %d\n", ret ); } @@ -870,8 +868,6 @@ static void test_SQLDriverConnect( void ) SET_EXPECT( driver_SQLGetInfo ); ret = SQLDriverConnect( con, NULL, (SQLCHAR *)"DSN=winetest_dsn;er\\9.99", strlen("DSN=winetest_dsn;er\\9.99"), str, sizeof(str), &len, 0 ); - todo_wine CHECK_NOT_CALLED( driver_SQLAllocHandle_env ); - todo_wine CHECK_NOT_CALLED( driver_SQLSetEnvAttr ); todo_wine CHECK_NOT_CALLED( driver_SQLAllocHandle_con ); todo_wine CHECK_NOT_CALLED( driver_SQLGetInfo_SQL_DRIVER_ODBC_VER ); CHECK_CALLED( driver_SQLDriverConnect ); @@ -892,12 +888,10 @@ static void test_SQLDriverConnect( void ) SET_EXPECT( driver_SQLFreeHandle_env ); ret = SQLFreeConnect( con ); CHECK_CALLED( driver_SQLFreeHandle_con ); - todo_wine CHECK_CALLED( driver_SQLFreeHandle_env ); + CHECK_CALLED( driver_SQLFreeHandle_env ); ok( ret == SQL_SUCCESS, "got %d\n", ret ); - SET_EXPECT( driver_SQLFreeHandle_env ); ret = SQLFreeEnv( env ); - todo_wine CHECK_NOT_CALLED( driver_SQLFreeHandle_env ); ok( ret == SQL_SUCCESS, "got %d\n", ret ); } @@ -946,12 +940,10 @@ static void test_SQLBrowseConnect( void ) SET_EXPECT( driver_SQLFreeHandle_env ); ret = SQLFreeConnect( con ); CHECK_CALLED( driver_SQLFreeHandle_con ); - todo_wine CHECK_CALLED( driver_SQLFreeHandle_env ); + CHECK_CALLED( driver_SQLFreeHandle_env ); ok( ret == SQL_SUCCESS, "got %d\n", ret ); - SET_EXPECT( driver_SQLFreeHandle_env ); ret = SQLFreeEnv( env ); - todo_wine CHECK_NOT_CALLED( driver_SQLFreeHandle_env ); ok( ret == SQL_SUCCESS, "got %d\n", ret ); } @@ -1300,12 +1292,10 @@ static void test_SQLExecDirect( void ) SET_EXPECT( driver_SQLFreeHandle_env ); ret = SQLFreeConnect( con ); CHECK_CALLED( driver_SQLFreeHandle_con ); - todo_wine CHECK_CALLED( driver_SQLFreeHandle_env ); + CHECK_CALLED( driver_SQLFreeHandle_env ); ok( ret == SQL_SUCCESS, "got %d\n", ret ); - SET_EXPECT( driver_SQLFreeHandle_env ); ret = SQLFreeEnv( env ); - todo_wine CHECK_NOT_CALLED( driver_SQLFreeHandle_env ); ok( ret == SQL_SUCCESS, "got %d\n", ret ); } diff --git a/dlls/odbc32/unixlib.h b/dlls/odbc32/unixlib.h index d4ff1e72ac3..48e34084274 100644 --- a/dlls/odbc32/unixlib.h +++ b/dlls/odbc32/unixlib.h @@ -194,9 +194,19 @@ struct object BOOL closed; }; +struct env_handle +{ + struct list entry; + int ref; + UINT64 unix_handle; + void *win32_handle; + const struct win32_funcs *win32_funcs; +}; + struct environment { struct object hdr; + struct list env_handles; /* list of connections env handles */ /* attributes */ UINT32 attr_version; /* drivers and data sources */ @@ -210,6 +220,8 @@ struct environment struct connection { struct object hdr; + struct env_handle *env; + /* win32 fields */ UINT32 driver_odbc_ver; /* attributes */ BOOL con_timeout_set; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10669
From: Piotr Caban <piotr@codeweavers.com> --- dlls/odbc32/proxyodbc.c | 252 ++++++++++++++----------------------- dlls/odbc32/tests/odbc32.c | 4 - 2 files changed, 91 insertions(+), 165 deletions(-) diff --git a/dlls/odbc32/proxyodbc.c b/dlls/odbc32/proxyodbc.c index 8eb8f7999b6..d7686f24dcc 100644 --- a/dlls/odbc32/proxyodbc.c +++ b/dlls/odbc32/proxyodbc.c @@ -1481,6 +1481,39 @@ static SQLRETURN get_info_win32_w( struct connection *con, SQLUSMALLINT type, SQ return ret; } +static SQLRETURN free_handle( SQLSMALLINT type, struct object *obj ) +{ + SQLRETURN ret = SQL_SUCCESS; + + if (obj->unix_handle) + { + struct SQLFreeHandle_params params = { type, obj->unix_handle }; + ret = ODBC_CALL( SQLFreeHandle, ¶ms ); + } + else if (obj->win32_handle) + { + if (obj->win32_funcs->SQLFreeHandle) + ret = obj->win32_funcs->SQLFreeHandle( type, obj->win32_handle ); + else + { + switch (type) + { + case SQL_HANDLE_DBC: + if (obj->win32_funcs->SQLFreeConnect) + ret = obj->win32_funcs->SQLFreeConnect( obj->win32_handle ); + break; + case SQL_HANDLE_STMT: + if (obj->win32_funcs->SQLFreeStmt) + ret = obj->win32_funcs->SQLFreeStmt( obj->win32_handle, SQL_DROP ); + break; + default: break; + } + } + } + + return ret; +} + static SQLRETURN alloc_con_handle( struct connection *con ) { SQLRETURN ret = SQL_ERROR; @@ -1562,6 +1595,52 @@ static SQLRETURN connect_unix_a( struct connection *con, SQLCHAR *servername, SQ return ODBC_CALL( SQLConnect, ¶ms ); } +static void cleanup_object( struct object *obj ); + +static SQLRETURN prepare_connection( WCHAR *filename, struct connection *con ) +{ + SQLRETURN ret; + + if (has_suffix( filename, L".dll" )) + { + const struct win32_funcs *funcs = load_driver( filename ); + + if (!funcs) + { + WARN( "failed to load driver %s\n", debugstr_w(filename) ); + return SQL_ERROR; + } + if (con->hdr.unix_handle || (con->hdr.win32_handle && funcs != con->hdr.win32_funcs)) + { + free_handle( SQL_HANDLE_DBC, &con->hdr ); + cleanup_object( &con->hdr ); + con->hdr.unix_handle = 0; + con->hdr.win32_handle = 0; + } + con->hdr.win32_funcs = funcs; + TRACE( "using Windows driver %s\n", debugstr_w(filename) ); + + if (!SUCCESS((ret = create_env( con )))) return ret; + if (!con->hdr.win32_handle && !SUCCESS((ret = create_con( con )))) return ret; + } + else + { + if (con->hdr.win32_handle) + { + free_handle( SQL_HANDLE_DBC, &con->hdr ); + cleanup_object( &con->hdr ); + con->hdr.win32_handle = 0; + con->hdr.win32_funcs = NULL; + } + TRACE( "using Unix driver %s\n", debugstr_w(filename) ); + + if (!SUCCESS((ret = create_env( con )))) return ret; + if (!con->hdr.unix_handle && !SUCCESS((ret = create_con( con )))) return ret; + } + + return SQL_SUCCESS; +} + /************************************************************************* * SQLConnect [ODBC32.007] */ @@ -1586,32 +1665,11 @@ SQLRETURN WINAPI SQLConnect(SQLHDBC ConnectionHandle, SQLCHAR *ServerName, SQLSM goto done; } - if (has_suffix( filename, L".dll" )) - { - con->hdr.unix_handle = 0; - if (!(con->hdr.win32_funcs = load_driver( filename ))) - { - WARN( "failed to load driver %s\n", debugstr_w(filename) ); - goto done; - } - TRACE( "using Windows driver %s\n", debugstr_w(filename) ); - - if (!SUCCESS((ret = create_env( con )))) goto done; - if (!SUCCESS((ret = create_con( con )))) goto done; - + if (!SUCCESS((ret = prepare_connection( filename, con )))) goto done; + if (con->hdr.win32_handle) ret = connect_win32_a( con, ServerName, NameLength1, UserName, NameLength2, Authentication, NameLength3 ); - } else - { - con->hdr.win32_handle = 0; - con->hdr.win32_funcs = NULL; - TRACE( "using Unix driver %s\n", debugstr_w(filename) ); - - if (!SUCCESS((ret = create_env( con )))) goto done; - if (!SUCCESS((ret = create_con( con )))) goto done; - ret = connect_unix_a( con, ServerName, NameLength1, UserName, NameLength2, Authentication, NameLength3 ); - } done: free( servername ); @@ -1825,8 +1883,6 @@ static SQLRETURN disconnect_win32( struct connection *con ) return SQL_ERROR; } -static void cleanup_object( struct object *obj ); - static void destroy_dependent_objects( struct connection *con ) { struct object *obj, *next; @@ -2278,39 +2334,6 @@ SQLRETURN WINAPI SQLFetchScroll(SQLHSTMT StatementHandle, SQLSMALLINT FetchOrien return ret; } -static SQLRETURN free_handle( SQLSMALLINT type, struct object *obj ) -{ - SQLRETURN ret = SQL_SUCCESS; - - if (obj->unix_handle) - { - struct SQLFreeHandle_params params = { type, obj->unix_handle }; - ret = ODBC_CALL( SQLFreeHandle, ¶ms ); - } - else if (obj->win32_handle) - { - if (obj->win32_funcs->SQLFreeHandle) - ret = obj->win32_funcs->SQLFreeHandle( type, obj->win32_handle ); - else - { - switch (type) - { - case SQL_HANDLE_DBC: - if (obj->win32_funcs->SQLFreeConnect) - ret = obj->win32_funcs->SQLFreeConnect( obj->win32_handle ); - break; - case SQL_HANDLE_STMT: - if (obj->win32_funcs->SQLFreeStmt) - ret = obj->win32_funcs->SQLFreeStmt( obj->win32_handle, SQL_DROP ); - break; - default: break; - } - } - } - - return ret; -} - /************************************************************************* * SQLFreeConnect [ODBC32.014] */ @@ -4871,32 +4894,11 @@ SQLRETURN WINAPI SQLBrowseConnect(SQLHDBC ConnectionHandle, SQLCHAR *InConnectio goto done; } - if (has_suffix( filename, L".dll" )) - { - con->hdr.unix_handle = 0; - if (!(con->hdr.win32_funcs = load_driver( filename ))) - { - WARN( "failed to load driver %s\n", debugstr_w(filename) ); - goto done; - } - TRACE( "using Windows driver %s\n", debugstr_w(filename) ); - - if (!SUCCESS((ret = create_env( con )))) goto done; - if (!SUCCESS((ret = create_con( con )))) goto done; - + if (!SUCCESS((ret = prepare_connection( filename, con )))) goto done; + if (con->hdr.win32_handle) ret = browse_connect_win32_a( con, strA, StringLength1, OutConnectionString, BufferLength, StringLength2 ); - } else - { - con->hdr.win32_handle = 0; - con->hdr.win32_funcs = NULL; - TRACE( "using Unix driver %s\n", debugstr_w(filename) ); - - if (!SUCCESS((ret = create_env( con )))) goto done; - if (!SUCCESS((ret = create_con( con )))) goto done; - ret = browse_connect_unix_a( con, strA, StringLength1, OutConnectionString, BufferLength, StringLength2 ); - } done: free( strA ); @@ -6023,31 +6025,14 @@ SQLRETURN WINAPI SQLDriverConnect(SQLHDBC ConnectionHandle, SQLHWND WindowHandle goto done; } - if (has_suffix( filename, L".dll" )) + if (!SUCCESS((ret = prepare_connection( filename, con )))) goto done; + if (con->hdr.win32_handle) { - con->hdr.unix_handle = 0; - if (!(con->hdr.win32_funcs = load_driver( filename ))) - { - WARN( "failed to load driver %s\n", debugstr_w(filename) ); - goto done; - } - TRACE( "using Windows driver %s\n", debugstr_w(filename) ); - - if (!SUCCESS((ret = create_env( con )))) goto done; - if (!SUCCESS((ret = create_con( con )))) goto done; - ret = driver_connect_win32_a( con, WindowHandle, strA, Length, OutConnectionString, BufferLength, Length2, DriverCompletion ); } else { - con->hdr.win32_handle = 0; - con->hdr.win32_funcs = NULL; - TRACE( "using Unix driver %s\n", debugstr_w(filename) ); - - if (!SUCCESS((ret = create_env( con )))) goto done; - if (!SUCCESS((ret = create_con( con )))) goto done; - ret = driver_connect_unix_a( con, WindowHandle, strA, Length, OutConnectionString, BufferLength, Length2, DriverCompletion ); } @@ -6247,32 +6232,11 @@ SQLRETURN WINAPI SQLConnectW(SQLHDBC ConnectionHandle, SQLWCHAR *ServerName, SQL goto done; } - if (has_suffix( filename, L".dll" )) - { - con->hdr.unix_handle = 0; - if (!(con->hdr.win32_funcs = load_driver( filename ))) - { - WARN( "failed to load driver %s\n", debugstr_w(filename) ); - goto done; - } - TRACE( "using Windows driver %s\n", debugstr_w(filename) ); - - if (!SUCCESS((ret = create_env( con )))) goto done; - if (!SUCCESS((ret = create_con( con )))) goto done; - + if (!SUCCESS((ret = prepare_connection( filename, con )))) goto done; + if (con->hdr.win32_handle) ret = connect_win32_w( con, ServerName, NameLength1, UserName, NameLength2, Authentication, NameLength3 ); - } else - { - con->hdr.win32_handle = 0; - con->hdr.win32_funcs = NULL; - TRACE( "using Unix driver %s\n", debugstr_w(filename) ); - - if (!SUCCESS((ret = create_env( con )))) goto done; - if (!SUCCESS((ret = create_con( con )))) goto done; - ret = connect_unix_w( con, ServerName, NameLength1, UserName, NameLength2, Authentication, NameLength3 ); - } done: free( filename ); @@ -7381,31 +7345,14 @@ SQLRETURN WINAPI SQLDriverConnectW(SQLHDBC ConnectionHandle, SQLHWND WindowHandl goto done; } - if (has_suffix( filename, L".dll" )) + if (!SUCCESS((ret = prepare_connection( filename, con )))) goto done; + if (con->hdr.win32_handle) { - con->hdr.unix_handle = 0; - if (!(con->hdr.win32_funcs = load_driver( filename ))) - { - WARN( "failed to load driver %s\n", debugstr_w(filename) ); - goto done; - } - TRACE( "using Windows driver %s\n", debugstr_w(filename) ); - - if (!SUCCESS((ret = create_env( con )))) goto done; - if (!SUCCESS((ret = create_con( con )))) goto done; - ret = driver_connect_win32_w( con, WindowHandle, InConnectionString, Length, OutConnectionString, BufferLength, Length2, DriverCompletion ); } else { - con->hdr.win32_handle = 0; - con->hdr.win32_funcs = NULL; - TRACE( "using Unix driver %s\n", debugstr_w(filename) ); - - if (!SUCCESS((ret = create_env( con )))) goto done; - if (!SUCCESS((ret = create_con( con )))) goto done; - ret = driver_connect_unix_w( con, WindowHandle, InConnectionString, Length, OutConnectionString, BufferLength, Length2, DriverCompletion ); } @@ -7841,31 +7788,14 @@ SQLRETURN WINAPI SQLBrowseConnectW(SQLHDBC ConnectionHandle, SQLWCHAR *InConnect goto done; } - if (has_suffix( filename, L".dll" )) + if (!SUCCESS((ret = prepare_connection( filename, con )))) goto done; + if (con->hdr.win32_handle) { - con->hdr.unix_handle = 0; - if (!(con->hdr.win32_funcs = load_driver( filename ))) - { - WARN( "failed to load driver %s\n", debugstr_w(filename) ); - goto done; - } - TRACE( "using Windows driver %s\n", debugstr_w(filename) ); - - if (!SUCCESS((ret = create_env( con )))) goto done; - if (!SUCCESS((ret = create_con( con )))) goto done; - ret = browse_connect_win32_w( con, connect_string, StringLength1, OutConnectionString, BufferLength, StringLength2 ); } else { - con->hdr.win32_handle = 0; - con->hdr.win32_funcs = NULL; - TRACE( "using Unix driver %s\n", debugstr_w(filename) ); - - if (!SUCCESS((ret = create_env( con )))) goto done; - if (!SUCCESS((ret = create_con( con )))) goto done; - ret = browse_connect_unix_w( con, connect_string, StringLength1, OutConnectionString, BufferLength, StringLength2 ); } diff --git a/dlls/odbc32/tests/odbc32.c b/dlls/odbc32/tests/odbc32.c index 14a39e08ec7..8b9b88d72db 100644 --- a/dlls/odbc32/tests/odbc32.c +++ b/dlls/odbc32/tests/odbc32.c @@ -861,15 +861,11 @@ static void test_SQLDriverConnect( void ) str[0] = 0; SET_EXPECT( driver_SQLAllocHandle_env ); SET_EXPECT( driver_SQLSetEnvAttr ); - SET_EXPECT( driver_SQLAllocHandle_con ); - SET_EXPECT( driver_SQLGetInfo_SQL_DRIVER_ODBC_VER ); SET_EXPECT( driver_SQLDriverConnect ); SET_EXPECT( driver_SQLGetDiagRec ); SET_EXPECT( driver_SQLGetInfo ); ret = SQLDriverConnect( con, NULL, (SQLCHAR *)"DSN=winetest_dsn;er\\9.99", strlen("DSN=winetest_dsn;er\\9.99"), str, sizeof(str), &len, 0 ); - todo_wine CHECK_NOT_CALLED( driver_SQLAllocHandle_con ); - todo_wine CHECK_NOT_CALLED( driver_SQLGetInfo_SQL_DRIVER_ODBC_VER ); CHECK_CALLED( driver_SQLDriverConnect ); todo_wine CHECK_CALLED( driver_SQLGetDiagRec ); todo_wine CHECK_CALLED( driver_SQLGetInfo ); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10669
Hans Leidekker (@hans) commented about dlls/odbc32/proxyodbc.c:
if (!env) return SQL_INVALID_HANDLE;
- if (env->hdr.unix_handle) - { - ret = get_env_attr_unix( env, Attribute, Value, BufferLength, StringLength ); - } - else if (env->hdr.win32_handle) - { - ret = get_env_attr_win32( env, Attribute, Value, BufferLength, StringLength ); - } - else
I guess this could use a test. The MySQL driver I have here exports SQLGet/SetEnvAttr(). -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10669#note_136508
On Thu Apr 16 14:05:55 2026 +0000, Hans Leidekker wrote:
I guess this could use a test. The MySQL driver I have here exports SQLGet/SetEnvAttr(). The test for this change are in the patch. The driver functions are used by driver manager in connect function family to obtain driver version and set application version. The change is needed because 1fd93db78f3736a80cdb602a43d4fafc256b548d changes the code to have multiple env driver handles inside one environment object.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10669#note_136709
On Fri Apr 17 11:10:40 2026 +0000, Piotr Caban wrote:
The test for this change are in the patch. The driver functions are used by driver manager in connect function family to obtain driver version and set application version. The change is needed because 1fd93db78f3736a80cdb602a43d4fafc256b548d changes the code to have multiple env driver handles inside one environment object. You're testing SQLGetEnvAttr() in this patch but guess I would have expected an additional test to show that the driver isn't called in that case, using the EXPECT mechanism.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10669#note_136720
This merge request was approved by Hans Leidekker. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10669
On Fri Apr 17 12:09:20 2026 +0000, Hans Leidekker wrote:
You're testing SQLGetEnvAttr() in this patch but guess I would have expected an additional test to show that the driver isn't called in that case, using the EXPECT mechanism. If the function calls into the driver, `driver_SQLSetEnvAttr` will be called. In that case `CHECK_EXPECT( driver_SQLSetEnvAttr )` test fails.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10669#note_136725
On Fri Apr 17 12:21:38 2026 +0000, Piotr Caban wrote:
If the function calls into the driver, `driver_SQLSetEnvAttr` will be called. In that case `CHECK_EXPECT( driver_SQLSetEnvAttr )` test fails. You have a test for SQLSetEnvAttr() but this patch is about SQLGetEnvAttr(). Anyway, I think it's fine like this.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10669#note_136730
participants (3)
-
Hans Leidekker (@hans) -
Piotr Caban -
Piotr Caban (@piotr)