MDEV-36326 Convert HASH interface from uchar* to void*#5098
Conversation
Change the my_hash_get_key typedef return type from `const uchar *` to `const void *`. This eliminates forced reinterpret_casts at all ~50 callback implementations, since the returned pointers are opaque key data that the hash infrastructure passes directly to charset comparison functions. Update all my_hash_get_key callback implementations across sql/, mysys/, storage/, client/, extra/, sql-common/, and plugin/ to return `const void *`. Callers that assign my_hash_search/my_hash_element results to typed pointers retain their existing casts (now from void* instead of uchar*, which is well-defined).
The initial commit missed the storage/perfschema/ callbacks because the local build used -DPLUGIN_PERFSCHEMA=NO. Apply the same uchar* → void* conversion to all 9 perfschema get_key callbacks and remove the now-unnecessary reinterpret_casts on their return values. All new code of the whole pull request, including one or several files that are either new files or modified ones, are contributed under the BSD-new license. I am contributing on behalf of my employer Amazon Web Services, Inc.
The my_hash_get_key typedef return type changed from const uchar* to const void* as part of the HASH interface conversion. The Mroonga storage engine wraps my_hash_init via mrn_my_hash_init and passes three get_key callbacks that still returned const uchar*, causing -Wincompatible-function-pointer-types errors when PLUGIN_MROONGA is enabled. Update mrn_open_tables_get_key, mrn_long_term_share_get_key, and mrn_allocated_thds_get_key to return const void* and remove the unnecessary reinterpret_cast/static_cast on their return values. All new code of the whole pull request, including one or several files that are either new files or modified ones, are contributed under the BSD-new license. I am contributing on behalf of my employer Amazon Web Services, Inc.
|
Nam Mai seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account. You have signed the CLA already but the status is still pending? Let us recheck it. |
There was a problem hiding this comment.
Code Review
This pull request refactors various hash-related functions across the codebase to use void* instead of uchar* for keys and data, improving type consistency. The review feedback suggests using static_cast instead of C-style casts for pointer conversions and removing redundant reinterpret_cast operations to improve code readability and safety.
| { | ||
| if (hash->get_key) | ||
| return (*hash->get_key)(record, length, 0); | ||
| return (const uchar*) (*hash->get_key)(record, length, 0); |
There was a problem hiding this comment.
In C++ files, static_cast is preferred over C-style casts for converting from void* to other pointer types. This improves type safety and adheres to modern C++ standards.
return static_cast<const uchar*>((*hash->get_key)(record, length, 0));References
- In C++ files, static_cast is preferred over C-style casts for converting from void* to other pointer types. (link)
There was a problem hiding this comment.
+1. You are making it more compatible. Please use one of the cast templates.
| const uchar *key= query_cache_query_get_key(block, &length, 0); | ||
| uchar* val = my_hash_search(&queries, key, length); | ||
| if ((reinterpret_cast<uchar *>(block)) != val) | ||
| const uchar *key= (const uchar*) query_cache_query_get_key(block, &length, 0); |
There was a problem hiding this comment.
In C++ files, static_cast is preferred over C-style casts for converting from void* to other pointer types.
const uchar *key= static_cast<const uchar*>(query_cache_query_get_key(block, &length, 0));References
- In C++ files, static_cast is preferred over C-style casts for converting from void* to other pointer types. (link)
There was a problem hiding this comment.
and here: do not merge. just change the type of key to const void *
| if ((reinterpret_cast<uchar *>(block)) != val) | ||
| const uchar *key= (const uchar*) query_cache_query_get_key(block, &length, 0); | ||
| void* val = my_hash_search(&queries, key, length); | ||
| if ((reinterpret_cast<void *>(block)) != val) |
There was a problem hiding this comment.
The reinterpret_cast<void *> is redundant here. In C++, a pointer can be implicitly converted to void* for comparison. Removing the cast improves readability and avoids using reinterpret_cast for a standard conversion.
if (block != val)References
- A pointer can be implicitly converted to void* for comparison. Removing redundant reinterpret_cast improves readability. (link)
| const uchar *key= query_cache_table_get_key(block, &length, 0); | ||
| uchar* val = my_hash_search(&tables, key, length); | ||
| if (reinterpret_cast<uchar *>(block) != val) | ||
| const uchar *key= (const uchar*) query_cache_table_get_key(block, &length, 0); |
There was a problem hiding this comment.
In C++ files, static_cast is preferred over C-style casts for converting from void* to other pointer types.
const uchar *key= static_cast<const uchar*>(query_cache_table_get_key(block, &length, 0));References
- In C++ files, static_cast is preferred over C-style casts for converting from void* to other pointer types. (link)
There was a problem hiding this comment.
ditto: use const void * for key
| if (reinterpret_cast<uchar *>(block) != val) | ||
| const uchar *key= (const uchar*) query_cache_table_get_key(block, &length, 0); | ||
| void* val = my_hash_search(&tables, key, length); | ||
| if (reinterpret_cast<void *>(block) != val) |
There was a problem hiding this comment.
The reinterpret_cast<void *> is redundant here as well. The comparison between block and val (which is now a void*) does not require an explicit cast in C++.
if (block != val)References
- A pointer can be implicitly converted to void* for comparison. Removing redundant reinterpret_cast improves readability. (link)
| size_t key_len= 0; | ||
| const uchar *key_ptr= info->get_key(info, &key_len, 1); | ||
| uchar *rec= my_hash_search(hash, key_ptr, key_len); | ||
| const uchar *key_ptr= (const uchar *) info->get_key(info, &key_len, 1); |
There was a problem hiding this comment.
In C++ code, static_cast is preferred over C-style casts for converting from void* to other pointer types. This improves type safety and makes the intent clearer.
const uchar *key_ptr= static_cast<const uchar *>(info->get_key(info, &key_len, 1));References
- In C++ files, static_cast is preferred over C-style casts for converting from void* to other pointer types. (link)
There was a problem hiding this comment.
please change the key_ptr type to void *
|
Nice!
Could, as a separate PR - prefix this test with: Overall the gemini code assist has some reasonable suggestions. I think not trap future coders, show of the good example, and simplify the merge if the majority of this can be backported to 10.11. There's some features that you've patches that exist in later versions - json_schema, json_array_intersect, hnsw that can be PRs against the versions where they where added (rounded up to currently maintained versions like 11.4, 11.8, 12.3, main) as draft, and we'll wait for the main HASH interface to merge up to those branches before merging. |
gkodinov
left a comment
There was a problem hiding this comment.
Thank you for your contribution! This is a preliminary review.
Please merge all of your 3 commits into a single one.
And there are some further cleanups below to consider.
Also, if you are using any AI tool that requires attribution, please add a "Co-Authored-by:" mention for it in the commit message.
| { | ||
| if (hash->get_key) | ||
| return (*hash->get_key)(record, length, 0); | ||
| return (const uchar*) (*hash->get_key)(record, length, 0); |
There was a problem hiding this comment.
+1. You are making it more compatible. Please use one of the cast templates.
| const uchar *key; | ||
| size_t key_length; | ||
| key=query_cache_table_get_key( block, &key_length, 0); | ||
| const uchar *key= (const uchar *) |
There was a problem hiding this comment.
Why merge the initialization and the declaration?
Also why not declare key to be const void *key?
| size_t key_length; | ||
| key=query_cache_query_get_key( block, &key_length, 0); | ||
| const uchar *key= (const uchar *) | ||
| query_cache_query_get_key( block, &key_length, 0); |
| const uchar *key= query_cache_query_get_key(block, &length, 0); | ||
| uchar* val = my_hash_search(&queries, key, length); | ||
| if ((reinterpret_cast<uchar *>(block)) != val) | ||
| const uchar *key= (const uchar*) query_cache_query_get_key(block, &length, 0); |
There was a problem hiding this comment.
and here: do not merge. just change the type of key to const void *
| if ((reinterpret_cast<uchar *>(block)) != val) | ||
| const uchar *key= (const uchar*) query_cache_query_get_key(block, &length, 0); | ||
| void* val = my_hash_search(&queries, key, length); | ||
| if ((reinterpret_cast<void *>(block)) != val) |
| const uchar *key= query_cache_table_get_key(block, &length, 0); | ||
| uchar* val = my_hash_search(&tables, key, length); | ||
| if (reinterpret_cast<uchar *>(block) != val) | ||
| const uchar *key= (const uchar*) query_cache_table_get_key(block, &length, 0); |
There was a problem hiding this comment.
ditto: use const void * for key
| if (reinterpret_cast<uchar *>(block) != val) | ||
| const uchar *key= (const uchar*) query_cache_table_get_key(block, &length, 0); | ||
| void* val = my_hash_search(&tables, key, length); | ||
| if (reinterpret_cast<void *>(block) != val) |
| size_t key_len= 0; | ||
| const uchar *key_ptr= info->get_key(info, &key_len, 1); | ||
| uchar *rec= my_hash_search(hash, key_ptr, key_len); | ||
| const uchar *key_ptr= (const uchar *) info->get_key(info, &key_len, 1); |
There was a problem hiding this comment.
please change the key_ptr type to void *
| { | ||
| size_t key_len= 0; | ||
| const uchar *key_ptr= get_xid_hash_key(xid, &key_len, 1); | ||
| const uchar *key_ptr= (const uchar*) get_xid_hash_key(xid, &key_len, 1); |
| xid_elem *e= nullptr; | ||
| size_t key_len= 0; | ||
| const uchar *key_ptr= get_xid_hash_key(xid, &key_len, 1); | ||
| const uchar *key_ptr= (const uchar*) get_xid_hash_key(xid, &key_len, 1); |
Summary
my_hash_get_keytypedef return type fromconst uchar *toconst void *HASH_LINK.datafromuchar *tovoid *my_hash_insert,my_hash_delete,my_hash_update,my_hash_replace,my_hash_element,my_hash_search,my_hash_first,my_hash_first_from_hash_value, andmy_hash_nextto usevoid *const void *reinterpret_cast<const uchar *>casts at callback return sites and caller insert/delete sitesMotivation
The HASH interface used
uchar *as a generic pointer type for storing and retrieving arbitrary record types. This forced every caller to cast through(uchar *)orreinterpret_cast<const uchar *>when inserting, deleting, or implementing get_key callbacks — adding noise with no type safety benefit.Converting to
void *leverages implicit pointer conversion in C and well-defined static_cast in C++, making the intent clearer at every call site.Key byte-buffer parameters (
const uchar *keyinmy_hash_search,my_hash_first,my_hash_next, and themy_hash_functiontypedef) are leftunchanged since they represent actual byte data used for hashing and comparison.
How can this PR be tested?
No new MTR tests are added since this is a refactor and we only need to make sure all functionalities are unchanged.
MTR test run with these cmd:
Need to run as a non-root user as test
roles.set_default_role_invalid_skip_name_resolvewould fail when running as root user.Basing the PR against the correct MariaDB version
Copyright
All new code of the whole pull request, including one or several files that are either new files or modified ones, are contributed under the BSD-new license. I am contributing on behalf of my employer Amazon Web Services, Inc.