Home - Waterfall Grid T-Grid Console Builders Recent Builds Buildslaves Changesources - JSON API - About

Console View


Categories: connectors experimental galera main
Legend:   Passed Failed Warnings Failed Again Running Exception Offline No data

connectors experimental galera main
Dmitry Shulga
MDEV-30645: CREATE TRIGGER FOR { STARTUP | SHUTDOWN }

Extended the system table mysql.event to support creation of
system triggers (startup, shutdown, logon, logoff) and ddl triggers.

The system table mysql.event is extended with three columns
  `kind`, `when`, `ddl_type`.
For the task MDEV-30645 only the column `kind` is required,
the other two columns are required for the tasks
  MENT-2355, MENT-2291
but since it is better to reduce a number of times the system table
is changed and as a consequences a number of upgrades to be run,
the entire set of columns is added at once.

Type of the columns `kind` and `ddl_type` are specifed as SET to allow
storing of triggers that handle several events.
bsrikanth-mariadb
MDEV-38701: hook records_in_range, and const tables

When the optimizer_record_context=ON save the following into the trace:
-
1. the records_in_range() call arguments, and its output records count in the
  method ror_scan_selectivity()
2. the const table rows from join_read_const() using an INSERT statement

Also, when the optimizer_replay_context is SET, read the stored
optimizer context from the trace, and do the following: -
1. execute the INSERT statements to add rows into the respective tables,
2. fetch output records count using the arguments to records_in_range() method
  and use them to instead of actually making a call to records_in_range() call
  from ror_scan_selectivity().
Yuchen Pei
MDEV-24813 Signal full scan to storage engines, with innodb implementation
Sergei Petrunia
Fixups for b6a84d69e996616da74c5c71073f049c0dcf92e9
Yuchen Pei
MDEV-24813 Signal full scan to storage engines, with innodb implementation

When doing a full table/index scan without a WHERE condition, tell the
storage engine so and the corresponding LIMIT.

Include a simple innodb side implementation for tests.
Sergei Petrunia
Cleanup in opt_store_replay_context.h: more comments, make it readable.
Oleg Smirnov
MDEV-38045 Refactor tests for combinations, add DML tests
Vladislav Vaintroub
wip
Marko Mäkelä
fixup! 52777e670e11645b00f175aef934cf2ba73232a8
Vladislav Vaintroub
wip
Alexey Botchkov
MDEV-37261 Basic XML data type.

XMLTYPE column added.
Type_handler::get_column_attributes() added so parser can check
if unexpected attributes were specified for the UDT column.
Yuchen Pei
MDEV-24813 Signal full scan to storage engines, with innodb implementation

When doing a full table/index scan without a WHERE condition, tell the
storage engine so and the corresponding LIMIT.

Include a simple innodb side implementation for tests.
Dmitry Shulga
MDEV-30645: CREATE TRIGGER FOR { STARTUP | SHUTDOWN }

Follow-up patch to the previous commit to update mtr result files
Thirunarayanan Balathandayuthapani
MDEV-19574: innodb_stats_method ignored with persistent statistics

Problem:
========
When persistent statistics are enabled (innodb_stats_persistent=ON),
the innodb_stats_method setting was not being properly passed
through the statistics calculation chain. This caused NULL handling
to always use the default behavior, regardless of the
configured stats method.

The issue affected query optimization for queries involving
NULL values, as the statistics collection wasn't respecting
the user's preference for NULL value treatment
(NULLS_EQUAL, NULLS_UNEQUAL, or NULLS_IGNORED).

Solution:
========
1. Passed innodb_stats_method parameter through the
statistics calculation chain:
- dict_stats_scan_page()
- dict_stats_analyze_index_below_cur()
- dict_stats_analyze_index_for_n_prefix()
- dict_stats_analyze_index_level
- dict_stats_analyze_index
- dict_stats_update_persistent
- dict_stats_save

2. Conditionally set n_non_null_key_vals based on the NULLS_IGNORED
method.

3. Introduced IndexLevelStats which is to collect statistics
at a specific B-tree level during index analysis

4. Introduced LeafPageStats which is to collect statistics
for leaf page analysis

5. IndexLevelStats, LeafPageStats replaces multiple individual
parameters in function signatures.

6. Add stats method name to stat_description in case of non
default innodb_stats_method variable value

7. Added the new stat name like n_nonnull_fld01, n_nonull_fld02 etc
with stats description to indicate how many non-nulls value exist
for nth field of the index. This value is properly retrieved and
stored in index statistics in dict_stats_fetch_index_stats_step().

8. When InnoDB scan the leaf page directly, assign leaf page
count as number of pages scanned in case of multi-level index.
For single page indexes, use 1. This change leads to multiple
changes in existing test case.
Yuchen Pei
MDEV-24813 Signal full scan to storage engines, with innodb implementation

When starting to do a full table/index scan without a WHERE or JOIN
condition, tell the storage engine so and the corresponding LIMIT.

Include a simple innodb side implementation for tests.
Yuchen Pei
MDEV-24813 [to-squash] fix extra_opt signature

TODO: what about storage engines not in the server codebase?
Yuchen Pei
MDEV-24813 Signal full scan to storage engines, with innodb implementation

When starting to do a full table/index scan without a WHERE or JOIN
condition, tell the storage engine so and the corresponding LIMIT.

Include a simple innodb side implementation for tests.
Oleg Smirnov
MDEV-38045: Implement implicit query block names for optimizer hints

This patch implements support for implicit query block (QB) names in
optimizer hints, allowing hints to reference query blocks and tables
within derived tables, views and CTEs without requiring explicit
QB_NAME hints.

Examples.
-- Addressing a table inside a derived table using implicit QB name
select /*+ no_index(t1@dt) */ *
  from (select * from t1 where a > 10) as DT;
-- this is an equivalent to:
select /*+ no_index(t1@dt) */ * from
  (select /*+ qb_name(dt)*/ * from t1 where a > 10) as DT;
-- Addressing a query block corresponding to the derived table
select /*+ no_bnl(@dt) */ *
  from (select * from t1, t2 where t.1.a > t2.a) as DT;

-- View
create view v1 as select * from t1 where a > 10 and b > 100;
-- referencing a table inside a view by implicit QB name:
select /*+ index_merge(t1@v1 idx_a, idx_b) */ *
  from v1, t2 where v1.a = t2.a;
-- equivalent to:
create view v1 as select /*+ qb_name(qb_v1) */ *
  from t1 where a > 10 and b > 100;
select /*+ index_merge(t1@qb_v1 idx_a, idx_b) */ *
  from v1, t2 where v1.a = t2.a;

-- CTE
with aless100 as (select a from t1 where b <100)
  select /*+ index(t1@aless100) */ * from aless100;
-- equivalent to:
with aless100 as (select /*+ qb_name(aless100) */ a from t1 where b <100)
  select /*+ index(t1@aless100) */ * from aless100;

Key changes:

1. Two-stage hint resolution
  - Introduced hint_resolution_stage enum (EARLY/LATE) to control
    when different hint types are resolved:
    - EARLY stage: first-order hints (QB_NAME, MERGE hints)
    - LATE stage: second-order hints (all other hints)

2. Implicit QB name support
  - Derived table/view/CTE aliases can now be used as implicit query
    block names in hint syntax: @alias, table@alias
  - Derived tables inside views can be addressed from outer queries
    using their aliases
Yuchen Pei
MDEV-24813 Signal full scan to storage engines, with innodb implementation

When doing a full table/index scan without a WHERE condition, tell the
storage engine so and the corresponding LIMIT.

Include a simple innodb side implementation for tests.
Michael Widenius
Disable flag -Wno-format-truncate in BUILD scripts
Thirunarayanan Balathandayuthapani
MDEV-36436  Assertion "unexpected references" == 0 after ALTER IGNORE TABLE

Problem:
=========
An assertion failure occurs in InnoDB during consecutive
ALTER TABLE operations using the COPY algorithm. The crash
happens during the table rename phase because the
source table (dict_table_t::n_ref_count) is non-zero, despite
the thread holding an exclusive Metadata Lock (MDL).

Reason:
========
When ALTER IGNORE TABLE is executed via the COPY algorithm,
it generates undo logs for every row inserted into the
intermediate table (e.g., #sql-alter-...). The background Purge
Thread, responsible for cleaning up these undo logs, attempts
to take an MDL on the table to prevent the table from
being dropped while in use.

Race condition:
==================
First ALTER: Creates #sql-alter-, copies data, and renames it to t1.

Purge Activation: The Purge thread picks up the undo logs from step 1.
It takes an MDL on the temporary name (#sql-alter-) and increments
the table's n_ref_count.

Identity Shift: InnoDB renames the physical table object to t1, but
the Purge thread still holds a reference to this object.

Second ALTER: Starts a new copy process. When it attempts to rename
the "new" t1 to a backup name, it checks if n_ref_count == 0.
Because the Purge thread is still "pinning" the object to
clean up logs from the first ALTER, the count is > 0,
triggering the assertion failure.

Solution:
========
ALTER IGNORE TABLE needs row-level undo logging to easily
roll back the last inserted row in case of duplicate key errors.
By discarding the last undo log record after inserting each row,
purge will not process any log records generated by
ALTER IGNORE TABLE, preventing unexpected access from the purge
subsystem during subsequent DDL operations.

Make skip_alter_undo (1-bit) to (2-bit enum)
to support different ALTER operation modes:

- NO_UNDO (0): Normal mode with standard undo logging
- SKIP_UNDO (1): ALTER mode that skips undo logging
- IGNORE_UNDO (2): ALTER IGNORE mode that rewrites undo blocks

trx_undo_report_row_operation(): Add ALTER IGNORE undo
rewriting logic. Store old undo record info before writing
new records for IGNORE_UNDO mode. Reset undo top_offset
to maintain only latest insert undo
Yuchen Pei
MDEV-24813 Signal full scan to storage engines, with innodb implementation

When starting to do a full table/index scan without a WHERE or JOIN
condition, tell the storage engine so and the corresponding LIMIT.

Include a simple innodb side implementation for tests.
Yuchen Pei
MDEV-24813 [to-squash] fix extra_opt signature

TODO: what about storage engines not in the server codebase?
Dmitry Shulga
MDEV-30645: CREATE TRIGGER FOR { STARTUP | SHUTDOWN }

Core implementation

- Extended the sql grammar to support creation of system triggers
  (startup, shutdown, logon, logoff) and ddl triggers.
- System triggers metadata is loaded from the table mysql.event
- System triggers can be created only by users with the SUPER privilege
Monty
Add detection of partial matches for strnncoll

This is achived by changing the 'is_prefix' parameter to strncoll
from a my_bool to my_bool*. This parameter is null if not specified by
the caller. If the is_prefix parameter is set to point to a my_bool
variable, this variable will be set to 1 if the second argument is
a prefix of the first.

This is needed by TO_DATE to be able to detect partial uniqiue matches of
months etc.  find_type() did this for latin1 strings, but we did not
do this for utf8mb4 strings.
This patch fixes this incompatibility.
Marko Mäkelä
MDEV-38807 Uninitialized return value from ibuf_upgrade_needed()

ibuf_upgrade_needed(): If there is no error and the pages were
recovered based on the redo log (rather than by reading the pages
from a data file), return DB_SUCCESS instead of an uninitialized value.
Marko Mäkelä
Implement multi-file recovery (almost)

recv_sys_t::archive_logs: The archive log files that will be used during
recovery.

FIXME: Open the last log file in read-write mode if needed.

FIXME: Make more use of recv_sys.archive_logs when opening log files.
Vlad Lesin
MDEV-31956 SSD based InnoDB buffer pool extension

In one of the practical cloud MariaDB setups, a server node accesses its
datadir over the network, but also has a fast local SSD storage for
temporary data. The content of such temporary storage is lost when the
server container is destroyed.

The commit uses this ephemeral fast local storage (SSD) as an extension of
the portion of InnoDB buffer pool (DRAM) that caches persistent data
pages. This cache is separated from the persistent storage of data files
and ib_logfile0 and ignored during backup.

The following system variables were introduced:

innodb_extended_buffer_pool_size - the size of external buffer pool
file, if it equals to 0, external buffer pool will not be used;

innodb_extended_buffer_pool_path - the path to external buffer pool
file.

If innodb_extended_buffer_pool_size is not equal to 0, external buffer
pool file will be created on startup.

Only clean pages will be flushed to external buffer pool file. There is
no need to flush dirty pages, as such pages will become clean after
flushing, and then will be evicted when they reach the tail of LRU list.

The general idea of this commit is to flush clean pages to external
buffer pool file when they are evicted.

A page can be evicted either by transaction thread or by background
thread of page cleaner. In some cases transaction thread is waiting for
page cleaner thread to finish its job. We can't do flushing in external
buffer pool file when transaction threads are waithing for eviction,
that would heart performance. That's why the only case for flushing is
when page cleaner thread evicts pages in background and there are no
waiters. For this purprose buf_pool_t::done_flush_list_waiters_count
variable was introduced, we flush evicted clean pages only if the
variable is zeroed.

Clean pages are evicted in buf_flush_LRU_list_batch() to keep some
amount of pages in buffer pool's free list. That's why we flush every
second page to external buffer pool file, otherwise there could be not
enought amount of pages in free list to let transaction threads to
allocate buffer pool pages without page cleaner waiting. This might be
not a good solution, but this is enought for prototyping.

External buffer pool page is introduced to store information in buffer
pool page hash about the certain page can be read from external buffer
pool file. The first several members of such page must be the same as the
members of internal page. External page frame must be equal to the
certain value to disthinguish external page from internal one. External
buffer pages are preallocated on startup in external pages array. We
could get rid of the frame in external page, and check if the page's
address belongs to the array to distinguish external and internal pages.

There are also external pages free and LRU lists. When some internal page
is decided to be flushed in external buffer pool file, a new external
page is allocated eighter from the head of external free list, or from
the tail of external LRU list. Both lists are protected with
buf_pool.mutex. It makes sense, because a page is removed from internal
LRU list during eviction under buf_pool.mutex.

Then internal page is locked and the allocated external page is attached
to io request for external buffer pool file, and when write request is
completed, the internal page is replaced with external one in page hash,
external page is pushed to the head of external LRU list and internal
page is unlocked. After internal page was removed from external free list,
it was not placed in external LRU, and placed there only
after write completion, so the page can't be used by the other threads
until write is completed.

Page hash chain get element function has additional template parameter,
which notifies the function if external pages must be ignored or not. We
don't ignore external pages in page hash in two cases, when some page is
initialized for read and when one is reinitialized for new page creating.

When an internal page is initialized for read and external page with the
same page id is found in page hash, the internal page is locked,
the external page in replaced with newly initialized internal page in the
page hash chain, the external page is removed from external LRU list and
attached to io request to external buffer pool file. When the io request
is completed, external page is returned to external free list,
internal page is unlocked. So during read external page absents in both
external LRU and free lists and can't be reused.

When an internal page is initialized for new page creating and external
pages with the same page id is found in page hash, we just remove external
page from the page hash chain and external LRU list and push it to the
head of external free list. So the external page can be used for future
flushing.

The pages are flushed to and read from external buffer pool file with
the same manner as they are flushed to their spaces, i.e. compressed and
encrypted pages stay compressed and encrypted in external buffer pool
file.

Reviewed by: Marko Mäkelä
Monty
Set current_stmt_binlog_format= BINLOG_FORMAT_UNSPEC if binlog is off.

THD::binlog_state is a new variable that simplifies testing if replication
is permanently off, is on or temporarly off (for a sub statement).

Code changes this allows us to do:

One does not need to test for mysql_bin_log.is_open() if one also tests
for thd->is_current_stmt_binlog_format_stmt() or
thd->is_current_stmt_binlog_format_row().

The code also allows the following transformations:

(WSREP(thd) && wsrep_emulate_bin_log) || mysql_bin_log.is_open() &&
(thd->variables.option_bits & OPTION_BIN_LOG)
->
BINLOG_USABLE(thd->binlog_state)

mysql_bin_log.is_open() &&
(thd->variables.option_bits & OPTION_BIN_LOG)
->
BINLOG_USABLE_NO_WSREP

Other transformation are easy to do by using the bits set in binlog_state
set by decide_binlog_format()
Yuchen Pei
MDEV-24813 [to-squash] implement UPDATE/DELETE

Also add more testcases
Marko Mäkelä
Validate the archive log file size
Sergei Petrunia
Cleanup in sql_json_lib.{h,cc}

Make it readable.
Rename read_all_elements() -> json_read_object().
Put json_read_object()'s auxiliary classes and functions
into namespace json_reader.
Sergei Petrunia
Cleanup (2)

In Optimizer_context_replay, rename saved_tablestats_list to saved_table_stats.
Improve readability.
Michael Widenius
MDEV-19683 Add support for Oracle TO_DATE()

Syntax:
TO_DATE(string_expression [DEFAULT string_expression ON CONVERSION ERROR],
        format_string [,NLS_FORMAT_STRING])
The format_string has the same format elements as TO_CHAR(), except a
few elements that are not supported/usable for TO_DATE().
TO_DATE() returns a datetime or date value, depending on if the format
element FF is used.

Allowed separators, same as TO_CHAR():
space, tab and any of !#%'()*+,-./:;<=>

'&' can also be used if next character is not a character a-z or A-Z
"text' indicates a text string that is verbatim in the format. One cannot
use " as a separator.

Format elements supported by TO_DATE():
AD          Anno Domini ("in the year of the Lord")
AD_DOT      Anno Domini ("in the year of the Lord")
AM          Meridian indicator (Before midday)
AM_DOT      Meridian indicator (Before midday)
DAY        Name of day
DD          Day (1-31)
DDD        Day of year (1-336)
DY          Abbreviated name of day
FF[1-6]    Fractional seconds
HH          Hour (1-12)
HH12        Hour (1-12)
HH24        Hour (0-23)
MI          Minutes (0-59)
MM          Month (1-12)
MON        Abbreviated name of month
MONTH      Name of Month
PM          Meridian indicator (After midday)
PM_DOT      Meridian indicator (After midday)
RR          20th century dates in the 21st century. 2 digits
            50-99 is assumed from 2000, 0-49 is assumed from 1900.
RRRR        20th century dates in the 21st century. 4 digits
SS          Seconds
SYYYY      Signed 4 digit year; MariaDB only supports positive years
Y          1 digit year
YY          2 digits year
YYY        3 digits year
YYYY        4 digits year

Note that if there is a missing part of the date, the current date is used!
For example if 'MM-DD HH-MM-SS' then the current year will be used.
(Oracle behaviour)

Not supported options:
- BC, D, DL, DS, E, EE, FM, FX, RM, SSSSS, TS, TZD, TZH, TZR, X,SY
  BC is not supported by MariaDB datetime.
- Most of the other are exotic formats does not make sence in MariaDB as
  we return datetime or datetime with fractions, not string.
- D (day-of-week) is not supported as it is not clear exactly how it would
  map to MariaDB. This element depends on the NLS territory of the session.
- RR only works with 2 digit years (In Oracle RR can also work with 4
  digit years in some context but the rules are not clear).

Extensions / differences compared to Oracle;
- MariaDB supports FF (fractional seconds).  If FF[#] is used,
  then TO_DATE will return a datetime with # of subseconds.
  If FF is not used a datetime will be returned.
  There is warning (no error) if string contains more digts than what
  is specified with F(#]
- Names can be shortened to it's unique prefix. For example January and Ja
  works fine.
- No error if the date string is shorter format_string and the next
  not used character is not a number.. This is useful to get a date
  from a mixed set of strings in date or datetime format.
  Oracle gives an error if date string is too short.
- MariaDB supports short locales as language names
- NLS_DATE_FORMAT can use both " and ' for quoting.
- NLS_DATE_FORMAT must be a constant string.
  - This is to ensure that the server knows which locale to use
    when executing the function.

New formats handled by TO_CHAR():
FF[1-6]    Fractional seconds
DDD        Daynumber 1-366
IW          Week 1-53 according to ISO 8601
I          1 digit year according to ISO 8601
IY          2 digit year according to ISO 8601
IYY        3 digit year according to ISO 8601
IYYY        4 digit year according to ISO 8601
SYYY        4 digit year according to ISO 8601 (Oracle can do signed)

Supported NLS_FORMAT_STRING options are:
NLS_CALENDAR=GREGORIAN
NLS_DATE_LANGUAGE=language

Support languages are:
- All MariaDB short locales, like en_AU.
- The following Oracle language names:
ALBANIAN, AMERICAN, ARABIC, BASQUE, BELARUSIAN, BRAZILIAN PORTUGUESE
BULGARIAN, CANADIAN FRENCH, CATALAN, CROATIAN, CYRILLIC SERBIAN CZECH,
DANISH, DUTCH, ENGLISH, ESTONIAN, FINNISH, FRENCH, GERMAN,
GREEK, HEBREW, HINDI, HUNGARIAN, ICELANDIC, INDONESIAN ITALIAN,
JAPANESE, KANNADA, KOREAN, LATIN AMERICAN SPANISH, LATVIAN,
LITHUANIAN, MACEDONIAN, MALAY, MEXICAN SPANISH, NORWEGIAN, POLISH,
PORTUGUESE, ROMANIAN, RUSSIAN, SIMPLIFIED CHINESE, SLOVAK, SLOVENIAN,
SPANISH, SWAHILI, SWEDISH, TAMIL, THAI, TRADITIONAL CHINESE, TURKISH,
UKRAINIAN, VIETNAMESE

Development bugs fixed:
MDEV-38403 Server crashes in Item_func_to_date::fix_length_and_dec upon
          using an invalid argument
MDEV-38400 compat/oracle.func_to_date fails with PS protocol and cursor
          protocol (Fixed by Serg)
MDEV-38404 TO_DATE: MTR coverage omissions, round 1
MDEV-38509 TO_DATE: AD_DOT does not appear to be supported
MDEV-38513 TO_DATE: NULL value for format string causes assertion failure
MDEV-38521 TO_DATE: Date strings with non-ASCII symbols cause warnings
          and wrong results
MDEV-38578 TO_DATE: Possibly unexpected results upon wrong input
MDEV-38582 TO_DATE: NLS_DATE_LANGUAGE=JAPANESE does not parse values
          which work in Oracle
MDEV-38584 TO_DATE: NLS_DATE_LANGUAGE=VIETNAMESE does not parse values
          which work in Oracle
MDEV-38703 TO_DATE: Quotation for multi-word NLS_DATE_LANGUAGE leads
          to syntax error in view definition
MDEV-38675 TO_DATE: MSAN/Valgrind/UBSAN errors in
          extract_oracle_date_time
MDEV-38635 TO_DATE: UBSAN errors in item_timefunc.h upon comparison with
          a view column
MDEV-38719 TO_DATE: Assertion `&my_charset_bin != charset()' failed in
          String::append_for_single_quote_using_mb_wc
MDEV-38756 TO_DATE: MSAN/Valgrind errors in
            Item_func_to_date::fix_length_and_dec upon PREPARE with
            parameters

Known issues:
- Format string character matches inside quotes are done
  one-letter-to-one-letter, like in LIKE predicate. That means things
  like expansions and contractions do not work.
  For example 'ss' does not match 'ß' in collations which treat them
  as equal for the comparison operator.
  Match is done taking into account case and accent sensitivity
  of the subject argument collation, so for example this now works:
  MariaDB [test]> SELECT TO_DATE('1920á12','YYYY"a"MM') AS c;
  +---------------------+
  | c                  |
  +---------------------+
  | 1920-12-17 00:00:00 |
  +---------------------+

Co-author and reviewer: Alexander Barkov <[email protected]>
Yuchen Pei
MDEV-24813 Signal full scan to storage engines, with innodb implementation

When doing a full table/index scan without a WHERE condition, tell the
storage engine so and the corresponding LIMIT.

Include a simple innodb side implementation for tests.
Sergei Golubchik
MDEV-38359 disable slow log tests in --cursor until MDEV-38612
Oleg Smirnov
MDEV-38045 Address code review comments (commit to squash)
Sergei Petrunia
Fixups for b6a84d69e996616da74c5c71073f049c0dcf92e9 part 2
Thirunarayanan Balathandayuthapani
MDEV-36436  Assertion "unexpected references" == 0 after ALTER IGNORE TABLE

Problem:
=========
An assertion failure occurs in InnoDB during consecutive
ALTER TABLE operations using the COPY algorithm. The crash
happens during the table rename phase because the
source table (dict_table_t::n_ref_count) is non-zero, despite
the thread holding an exclusive Metadata Lock (MDL).

Reason:
========
When ALTER IGNORE TABLE is executed via the COPY algorithm,
it generates undo logs for every row inserted into the
intermediate table (e.g., #sql-alter-...). The background Purge
Thread, responsible for cleaning up these undo logs, attempts
to take an MDL on the table to prevent the table from
being dropped while in use.

Race condition:
==================
First ALTER: Creates #sql-alter-, copies data, and renames it to t1.

Purge Activation: The Purge thread picks up the undo logs from step 1.
It takes an MDL on the temporary name (#sql-alter-) and increments
the table's n_ref_count.

Identity Shift: InnoDB renames the physical table object to t1, but
the Purge thread still holds a reference to this object.

Second ALTER: Starts a new copy process. When it attempts to rename
the "new" t1 to a backup name, it checks if n_ref_count == 0.
Because the Purge thread is still "pinning" the object to
clean up logs from the first ALTER, the count is > 0,
triggering the assertion failure.

Solution:
========
ALTER IGNORE TABLE needs row-level undo logging to easily
roll back the last inserted row in case of duplicate key errors.
By discarding the last undo log record after inserting each row,
purge will not process any log records generated by
ALTER IGNORE TABLE, preventing unexpected access from the purge
subsystem during subsequent DDL operations.

Make skip_alter_undo (1-bit) to (2-bit enum)
to support different ALTER operation modes:

- NO_UNDO (0): Normal mode with standard undo logging
- SKIP_UNDO (1): ALTER mode that skips undo logging
- IGNORE_UNDO (2): ALTER IGNORE mode that rewrites undo blocks

trx_undo_report_row_operation(): Add ALTER IGNORE undo
rewriting logic. Store old undo record info before writing
new records for IGNORE_UNDO mode. Reset undo top_offset
to maintain only latest insert undo