Skip to content

MDEV-36326 Convert HASH interface from uchar* to void*#5098

Open
nam-m wants to merge 3 commits into
MariaDB:mainfrom
nam-m:mdev-39603
Open

MDEV-36326 Convert HASH interface from uchar* to void*#5098
nam-m wants to merge 3 commits into
MariaDB:mainfrom
nam-m:mdev-39603

Conversation

@nam-m
Copy link
Copy Markdown

@nam-m nam-m commented May 19, 2026

Summary

  • Change my_hash_get_key typedef return type from const uchar * to const void *
  • Change HASH_LINK.data from uchar * to void *
  • Change record pointer parameters and return types in 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, and my_hash_next to use void *
  • Update all ~50 get_key callback implementations across 67 files to return const void *
  • Remove unnecessary reinterpret_cast<const uchar *> casts at callback return sites and caller insert/delete sites

Motivation

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 *) or reinterpret_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 *key in my_hash_search, my_hash_first, my_hash_next, and the my_hash_function typedef) are left
unchanged 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_resolve would fail when running as root user.

useradd -m mtruser
chown -R mtruser:mtruser /quick-rebuilds/build/mysql-test/var
su - mtruser -c "cd /quick-rebuilds && ./build/mysql-test/mysql-test-run.pl --force --parallel=auto \
    --suite=main,rpl,roles,plugins,json,handler,csv,federated,maria,perfschema,client,spider,mroonga"
The servers were restarted 908 times
Spent 2775.394 of 486 seconds executing testcases

Completed: All 2952 tests were successful.

524 tests were skipped, 133 by the test itself.

Basing the PR against the correct MariaDB version

  • This is a refactoring change, and the PR is based against the main MariaDB development branch.

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.

Nam Mai added 3 commits May 14, 2026 02:03
  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.
@CLAassistant
Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.


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.

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread mysys/lf_hash.cc
{
if (hash->get_key)
return (*hash->get_key)(record, length, 0);
return (const uchar*) (*hash->get_key)(record, length, 0);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

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
  1. In C++ files, static_cast is preferred over C-style casts for converting from void* to other pointer types. (link)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1. You are making it more compatible. Please use one of the cast templates.

Comment thread sql/sql_cache.cc
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);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

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
  1. In C++ files, static_cast is preferred over C-style casts for converting from void* to other pointer types. (link)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and here: do not merge. just change the type of key to const void *

Comment thread sql/sql_cache.cc
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)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

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
  1. A pointer can be implicitly converted to void* for comparison. Removing redundant reinterpret_cast improves readability. (link)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1.

Comment thread sql/sql_cache.cc
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);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

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
  1. In C++ files, static_cast is preferred over C-style casts for converting from void* to other pointer types. (link)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto: use const void * for key

Comment thread sql/sql_cache.cc
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)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

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
  1. A pointer can be implicitly converted to void* for comparison. Removing redundant reinterpret_cast improves readability. (link)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1: remove reinterpret cast.

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);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

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
  1. In C++ files, static_cast is preferred over C-style casts for converting from void* to other pointer types. (link)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please change the key_ptr type to void *

@grooverdan
Copy link
Copy Markdown
Member

Nice!

roles.set_default_role_invalid_skip_name_resolve would fail when running as root user.

Could, as a separate PR - prefix this test with: -- source include/not_as_root.inc

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 gkodinov added the External Contribution All PRs from entities outside of MariaDB Foundation, Corporation, Codership agreements. label May 20, 2026
@gkodinov gkodinov self-assigned this May 20, 2026
Copy link
Copy Markdown
Member

@gkodinov gkodinov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread mysys/lf_hash.cc
{
if (hash->get_key)
return (*hash->get_key)(record, length, 0);
return (const uchar*) (*hash->get_key)(record, length, 0);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1. You are making it more compatible. Please use one of the cast templates.

Comment thread sql/sql_cache.cc
const uchar *key;
size_t key_length;
key=query_cache_table_get_key( block, &key_length, 0);
const uchar *key= (const uchar *)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why merge the initialization and the declaration?
Also why not declare key to be const void *key?

Comment thread sql/sql_cache.cc
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);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto here

Comment thread sql/sql_cache.cc
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);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and here: do not merge. just change the type of key to const void *

Comment thread sql/sql_cache.cc
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)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1.

Comment thread sql/sql_cache.cc
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);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto: use const void * for key

Comment thread sql/sql_cache.cc
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)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1: remove reinterpret cast.

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);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cost void * for key_ptr.

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);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

const void * for key_ptr

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

External Contribution All PRs from entities outside of MariaDB Foundation, Corporation, Codership agreements.

Development

Successfully merging this pull request may close these issues.

4 participants