Skip to content

MDEV-38796 Refactor: clean up THD::decide_logging_format() checks#5136

Draft
bnestere wants to merge 5 commits into
gtt-montyfrom
main-MDEV-38796
Draft

MDEV-38796 Refactor: clean up THD::decide_logging_format() checks#5136
bnestere wants to merge 5 commits into
gtt-montyfrom
main-MDEV-38796

Conversation

@bnestere
Copy link
Copy Markdown
Contributor

PR is ongoing & draft for now, making this a PR so I can get intermittent BB results.

Test binlog_spurious_ddl_errors is updated here because now
decide_logging_format doesn't error out when it can't log in statement
format, but just switches to row
(aa4b22c).

@@ -7259,7 +7262,15 @@ int THD::decide_logging_format(TABLE_LIST *tables)
                              wsrep_cs().mode() ==
                              wsrep::client_state::m_local),1))
          {
-            my_error((error= ER_BINLOG_STMT_MODE_AND_ROW_ENGINE), MYF(0), "");
+            if (is_current_stmt_binlog_format_stmt())
+            {
+              my_printf_error(ER_BINLOG_STMT_MODE_AND_ROW_ENGINE,
+                              "Statement cannot be logged as STATEMENT as at "
+                              "least one table is limited to row-based logging."
+                              " Switching temporarly to row format",
+                              MYF(ME_NOTE));
+              set_current_stmt_binlog_format_row();
+            }
          }
@bnestere bnestere self-assigned this May 27, 2026
@bnestere bnestere added MariaDB Corporation Replication Patches involved in replication labels May 27, 2026
@CLAassistant
Copy link
Copy Markdown

CLAassistant commented May 27, 2026

CLA assistant check
All committers have signed the CLA.

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 introduces Global Temporary Tables (GTT) support, implementing the syntax, lifecycle, transaction integration, and replication/binlogging adjustments. Review feedback highlights several critical issues: a debug fprintf statement was left active in thd_binlog_filter_ok(); the in-use check in drop_tmp_table_share() is bypassed when table is NULL; committed in All_tmp_tables_list and binlog_state in THD are uninitialized; thd->query() can return NULL in log_write_error(), potentially causing a crash; and table_ref->table should be passed to drop_tmp_table_share() during truncate table operations instead of NULL.

Comment thread sql/sql_class.cc Outdated
Comment on lines +6007 to +6014
bool new_value= !(thd->binlog_state & BINLOG_STATE_FILTER);
bool old_value= binlog_filter->db_ok(thd->db.str);
//if (filter_on != old_value_on)
fprintf(stderr,
"\n\tDB %s thd_binlog_filter return\n\t\tbinlog_state: %d "
"\n\t\tlegacy: %d\n",
thd->db.str, new_value, old_value);
return new_value;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

high

The debug fprintf statement is left active and will spam stderr for every call to thd_binlog_filter_ok(). This should be removed or placed under a debug macro.

  return !(thd->binlog_state & BINLOG_STATE_FILTER);

Comment thread sql/temporary_tables.cc
Comment on lines +774 to 788
if (table)
{
if (tab != table && tab->query_id != 0)
/* Table might be in use by some outer statement. */
All_share_tables_list::Iterator it(share->all_tmp_tables);
while ((tab= it++))
{
/* Found a table instance in use. This table cannot be be dropped. */
my_error(ER_CANT_REOPEN_TABLE, MYF(0), table->alias.c_ptr());
result= true;
goto end;
if (tab != table && tab->query_id != 0)
{
/* Found a table instance in use. This table cannot be dropped. */
my_error(ER_CANT_REOPEN_TABLE, MYF(0), table->alias.c_ptr());
result= true;
goto end;
}
}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

high

If table is NULL (which happens when called from global_tmp_drop_database or truncate_table), the check for active table instances in use is completely bypassed because of the if (table) guard. This can lead to use-after-free or crashes if any of the global temporary table instances are currently in use by an outer query. The check should be performed regardless of whether table is NULL or not, and if table is NULL, we should check all instances.

  /* Table might be in use by some outer statement. */
  All_share_tables_list::Iterator it(share->all_tmp_tables);
  while ((tab= it++))
  {
    if (tab != table && tab->query_id != 0)
    {
      /* Found a table instance in use. This table cannot be dropped. */
      my_error(ER_CANT_REOPEN_TABLE, MYF(0),
               table ? table->alias.c_ptr() : share->table_name.str);
      result= true;
      goto end;
    }
  }

Comment thread sql/sql_class.h
I_P_List_null_counter,
I_P_List_fast_push_back<TMP_TABLE_SHARE>>
{
bool committed;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

high

committed is not initialized in-class or via a constructor, which means it will contain an undefined/garbage value when All_tmp_tables_list is instantiated. It should be initialized to false.

  bool committed= false;

Comment thread sql/log.cc

void log_write_error(THD *thd, const char *msg)
{
my_error(ER_BINLOG_LOGGING_IMPOSSIBLE, MYF(ME_ERROR_LOG), msg, thd->query());
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

thd->query() can return NULL if there is no active query (e.g., in background or replication threads). Passing NULL to %s in my_error can lead to undefined behavior or crashes on some platforms. It should be guarded with a null check.

  my_error(ER_BINLOG_LOGGING_IMPOSSIBLE, MYF(ME_ERROR_LOG), msg, thd->query() ? thd->query() : "");

Comment thread sql/sql_truncate.cc
{
TABLE_SHARE *s= table_ref->table->s;
DBUG_ASSERT(s->tmp_table);
error= thd->drop_tmp_table_share(NULL, (TMP_TABLE_SHARE *)s, true);
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

We should pass table_ref->table instead of NULL to drop_tmp_table_share so that the function can correctly exclude the current table instance from the "in-use" check while still validating other active instances.

    error= thd->drop_tmp_table_share(table_ref->table, (TMP_TABLE_SHARE *)s, true);

Comment thread sql/sql_class.h
Describe the current state of binary logging for the current statement.
Includes state of binary logging and also what disables it
*/
enum_binlog_state binlog_state;
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

binlog_state is not initialized in-class, which can lead to undefined behavior if it is read before THD::init() is called. It should be initialized to BINLOG_STATE_NONE.

  enum_binlog_state binlog_state= BINLOG_STATE_NONE;

@bnestere bnestere changed the base branch from main to gtt-monty May 27, 2026 18:45
bnestere added 4 commits May 28, 2026 14:15
Addresses TODO

    - Update binlog_state with BINLOG_STATE_FILTER only when database or filter
      is changed.  This means we do not have to call binlog_filter->db_ok() for
      every statement in decide_binlog_format().
TODO Addressed:
   - Remove clear/reset xxx_binlog_local_stmt_filter() as this is now handled
      by binlog_state.
TODO addressed
    - Remove 'silent' option from mysql_create_db_internal and instead use
      tmp_disable_binlog() / reenable_binlog()
Addresses TODO

    - Remove all testing of mysql_bin_log.is_open(). Instead test for
      binlog_ready() in main code and add testing of is_open() when
      trying to commit the binary log.  This is needed as currently
      mysql_bin_log.is_open() is tested without a mutex which makes
      it unreliable.

And also adds tests for the binlog closing for various types of
statements in-between a thd->binlog_ready() check and the commit-time
acquiring of mysql_bin_log.LOCK_log.

Still TODO from the above request:
 * WSREP related mysql_bin_log.is_open() changes as a part of MDEV-38865
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

MariaDB Corporation Replication Patches involved in replication

Development

Successfully merging this pull request may close these issues.

2 participants