Commit graph

203,393 commits

Author SHA1 Message Date
Sergei Golubchik
cb31d7536b MDEV-38604 Assertion `thd->utime_after_query >= thd->utime_after_lock' failed in query_response_time_audit_notify on 2nd execution of SP with query cache
even when PS is served from a query cache, thd->utime_after_query
must be updated.

also, backport the assert from 11.8
2026-01-23 12:15:34 +01:00
Vladislav Vaintroub
9710638367 update C/C 2026-01-23 09:28:24 +01:00
Sergei Golubchik
929bb98595 MDEV-38532 Debian packages are missing many server include headers, such as handler.h
include headers needed to build plugins, same as in RPMs
2026-01-22 21:44:54 +01:00
Rex Johnston
b061b5ab1f MDEV-31632 Unresolvable outer reference causes null pointer exception
SELECT 1 union select 2 UNION SELECT 1 from a JOIN a b ON
  (SELECT 1 FROM dual WHERE AAA)

Crashes during fix_outer_field while resolving field item AAA

In our resolver, once we have determined that a field item isn't
local to our select, we call Item::fix_outer_field(), which
iterates outwards towards the top level select, looking for where
our Item_field might be resolvable.

In our example here, the item isn't resolvable and we expose
fragility in the loop, which i will detail here.

After we initialize the variable 'outer_context' (to a context
containing /* select#3 */ select 1 AS `1` from (a join a b on
((subquery#4))) ) we enter a loop

│     5927   for (;
│     5928        outer_context;
│     5929        outer_context= outer_context->outer_context)
│     5930   {
│     5931     select= outer_context->select_lex;
│     5932     Item_subselect *prev_subselect_item=
│     5933       last_checked_context->select_lex->master_unit()->item;
│     5934     last_checked_context= outer_context;

here 'last_checked_context' is the context inner to the current
'outer_context', and we initialize prev_subselect_item to the
Item enclosing the unit containing this inner select.

So for the first iteration of the loop,
  select: select #3
  last_checked_context: from select #4 to select #3.
  prev_subselect_item: item enclosing select #4 (where
    field item AAA is defined)

The rest of the loop calls find_field_in_tables() /
resolve_ref_in_select_and_group() in an attempt to
resolve this item with this 'outer_context'.

After the item fails resolution, we move to an outer context
  select: select #4294967295 (fake_select_lex)
  last_checked_context: from select #3 to the fake select lex
    containing the union (i.e. outermost)
  prev_subselect_item: null, there is no Item that contains this,
    it is the outermost select.

We still need to execute the rest of the loop to determine whether
AAA is resolvable here, but executing

│     5937     place= prev_subselect_item->parsing_place;

We are now following a null pointer.  We introduce a test for this
null pointer, indicating that we are now evaluating the outermost
select and we are not to try accessing the enclosing subselect item.

Approved by: Oleksandr "Sanja" Byelkin (sanja@mariadb.com)
2026-01-23 07:48:16 +13:00
bsrikanth-mariadb
be4e1ecdc2 MDEV-37510: crash when tracing with max_sel_arg_weight equal to 1
When the optimizer_max_sel_arg_weight is set to 1, a nested query
crashed while tracing.

SEL_ARG object has a field named 'field', that is not set when the
type is other than KEY_RANGE. But, the field was accessed to store
its name, and weight to the trace. This resulted in a crash due to NULL
pointer.

Added a check to access field if the type is KEY_RANGE, and if not, just
trace the type.
2026-01-22 17:57:50 +05:30
Oleg Smirnov
cd02709a31 MDEV-38574 Rename cloning functions of class Item and descendants
Rename `Item::clone_item()` to `clone_constant()`, and do
the same for any overloads in descendant items.
The function returns non-NULL only for items that represent
constant literals.
2026-01-22 12:57:48 +01:00
Oleg Smirnov
f2b48e565c MDEV-38574 Rename cloning functions of class Item and descendants
Rename cloning methods of class Item and its descendants
in the following way:

   (from)            (to)
do_build_clone  -> deep_copy
   build_clone  -> deep_copy_with_checks

do_get_copy  -> shallow_copy
   get_copy  -> shallow_copy_with_checks

to better reflect their functionality.

Also make Item::deep_copy() and shallow_copy() protected.
Outside users should call deep_copy_with_checks()
and shallow_copy_with_checks().
2026-01-22 12:57:48 +01:00
bsrikanth-mariadb
251f76d39e MDEV-36353: Crash with explain for connection
SHOW EXPLAIN FOR, and EXPLAIN/DESC FOR CONNECTION should behave
identically. However, for a query with an addition expression containing
INTERVAL and NOT IN sub-select SHOW EXPLAIN FOR was correctly throwing
parse error, where as EXPLAIN/DESC FOR CONNECTION was crashing.

The reason for the crash is that select block was not initialized and
was being accessed inside the NOT IN sub-select in the EXPLAIN/DESC FOR
CONNECTION case.
2026-01-22 16:20:33 +05:30
Alexander Barkov
a84b8ec5b1 MDEV-38626 Unexpected Data too long error on subselect as a multiplication argument
Item_singerow_subselect::fix_length_and_dec() incorrectly calculated
its Item::max_length when the underlying expression was Item_int.

The reason of the problem:
Item_int has an optimized max_length to make CONCAT(1) create a VARCHAR(1)
column rather than a VARCHAR(2) column. Its max_length does not include one
extra character for the sign in case the value is positive but the value
is not marked as Item::unsigned==true.

So copying max_length from the underlying Item_int (with value==9)
in cases like this:
  SELECT CONCAT((SELECT 9 FROM t0));
was not correct.

Implementing a new virtual method
  Type_handler::Item_type_std_attributes_generic(const Item *item)

- The default implementation just copies attributes from "item" as is.

- In case of Type_handler_int_result it evaluates max_length
  using item->decimal_precision() rather than item->max_length.
  This works correctly for both "optimized" items like Item_int and
  non-"optimized" Items whose max_length includes +1 for the sign
  in case of signed expressions.
2026-01-22 12:47:52 +04:00
Raghunandan Bhat
16b5bf03d7 MDEV-37474: Privilege check of information_schema.TRIGGERS does not correspond to the standards
According to SQL standard, rows from `INFORMATION_SCHEMA.TRIGGERS` table
should be visible to users with non-SELECT privileges on the columns.
`ACTION_CONDITION`, `ACTION_STATEMENT` and `DEFINER` columns should be
visible only if the user is the owner of the schema.
MariaDB uses `TRIGGER` privilege instead of owner, which controls the
visibilty of all columns, including those which only need non-SELECT
privileges.

This fix
- Allows users with non-SELECT privileges- INSERT, DELETE or UPDATE,
  to see rows in `INFORMATION_SCHEMA.TRIGGERS` table.
- Ensure `ACTION_CONDITION`, `ACTION_STATEMENT` and `DEFINER` columns
  are `NULL` unless the user is the owner of the schema or has `TRIGGER`
  privilege.
2026-01-22 10:43:18 +05:30
Brandon Nesterenko
11f228cbb2 MDEV-38506: Failed GRANT on a procedure breaks replication
When GRANT EXECUTE ON PROCEDURE fails on the master, it will
erroneously be replicated and executed successfully on the slave.
This both breaks replication and is a security violation.

The underlying issue is that a failed GRANT EXECUTE ON PROCEDURE will
still be replicated when sql_mode does not have NO_AUTO_CREATE_USER.
This is because the function mysql_routine_grant() does not check if an
error occured while performing the GRANT before binlogging, it simply
always binlogs.

This patch fixes this problem by checking if an error happened
previously before binlogging, and if so, then skip binlogging.

Note there is still a broader issue in this area leading to replication
divergence. Reported in MDEV-29848, a partially-completed GRANT
statment (where some earlier GRANTS succeed and a later fails) will not
binlog. Note this affects all grant types, whereas the issue addressed
in this patch is limited to GRANT EXECUTE ON PROCEDURE. This patch
makes GRANT EXECUTE ON PROCEDURE binlogging behavior consistent with
the other grant types. A separate follow-up patch will address the
broader MDEV-29848 issue.

Also note that a test case in rpl_do_grant.test took advantage of
MDEV-38506 so a partially-failing REVOKE EXECUTE ON PROCEDURE would
still replicate.  This test case is disabled with a TODO note to
re-enable it once MDEV-29848 is fixed

Reviewed-by: Sergei Golubchik <serg@mariadb.org>
Signed-off-by: Brandon Nesterenko <brandon.nesterenko@mariadb.com>
2026-01-21 14:31:21 -07:00
Vladislav Vaintroub
c882f9b25a MDEV-37527 Client plugins are underlinked
Provide test case
2026-01-21 21:44:51 +01:00
Rex Johnston
6a32ccc5b9 MDEV-38473 Incorrect Empty Set with HAVING clause when SELECT and GROUP BY use different aliases for the same column
MDEV-29300 fix causes a wrong result by incorrectly removing a wrapper to
an item that needed to be wrapped for the correct result.  Direct access
to the item causes an incorrect table reference to be used during
join evaluation.  We revert that fix.

Our original problem query is this
SELECT (SELECT 0 GROUP BY c1 HAVING (SELECT c1)) FROM t1 group by c1;

JOIN::prepare on
/* select#2 */ select 0 group by t1.c1 having (subquery#3)

fixing t1.c1 in group by clause, calls fix_outer_field()
this item is resolved in an outer select (#1) and it is a grouping select,
so we wrap it in Item_outer_ref and set this item to unfixed for later
fixing in fix_inner_refs().

JOIN::prepare continues onto the having clause and fixes (subquery#3) which
calls initiates the prepare series of calls, leading to setup_fields on the
fields in this JOIN, one of which is an outer reference c1.
This is resolved to the item in the next most outer select in the group by
clause. This item has been wrapped with an unfixed Item_outer_ref.
It is found in resolve_ref_in_select_and_group() is it expected that
this item will have already been fixed, hence this call in

Item_field::fix_outer_field()

DBUG_ASSERT(*ref && (*ref)->fixed());

but as explained above, it isn't fixed and debug builds assert here.

Because this wrapper cannot be resolved here for reasons detailed in
fix_inner_refs, and we cannot remove this wrapper without potentially
returning an incorrect result, we have to relax this assertion.

Approved by: Oleksandr "Sanja" Byelkin (sanja@mariadb.com)
2026-01-22 07:21:12 +13:00
Oleksandr Byelkin
b505b7421a 10.6 adjasts 2026-01-21 14:40:41 +01:00
KhaledR57
7ae02de3a5 MDEV-36107 MDEV-36108 Enhance mysqltest language with expression evaluation and variable substitutions
mysqltest had limited scripting capabilities, requiring complex
workarounds for mathematical calculations and string manipulations
in test cases. This commit solves these limitations by adding a new
`$(...)` syntax that enables direct evaluation of mathematical, logical,
and string expressions within test scripts.

Expression Evaluation (MDEV-36107):
- Recursive descent parser supporting arithmetic, logical, comparison,
  and bitwise operators with proper precedence
- Support for integers (decimal, hex, binary), booleans, strings, and
  NULL values
- Variable substitution within expressions
- Integration with existing mysqltest control flow

String Functions (MDEV-36108):
- Base conversion functions supporting bases 2-62
- String manipulation and processing functions
- Regular expression functions
- Conditional and numeric utility functions

The implementation enhances mysqltest's scripting capabilities while
maintaining full backward compatibility.
2026-01-21 14:40:41 +01:00
Oleksandr Byelkin
b17a182d7e New CC 3.4 2026-01-21 14:27:40 +01:00
Marko Mäkelä
5f6109abe5 MDEV-38618 Unused variable dict_table_t::fk_max_recusive_level
Ever since mysql/mysql-server@377774689b
was applied in commit 2e814d4702d71a04388386a9f591d14a35980bfed
the data member dict_table_t::fk_max_recusive_level is never being
read, only initialized as 0. Let us follow the lead of
mysql/mysql-server@b22ac19f10
and remove this useless field.
2026-01-21 14:33:31 +02:00
Marko Mäkelä
470487c1a6 MDEV-21816 Suboptimal implementation of my_convert()
my_convert(): Correctly identify unaligned access by invoking memcpy(),
which will be translated to a single x86 MOV instruction already by
GCC 4.8.5. Also, process the data 64 bits at a time when possible.

The use of memcpy() prevents GCC from emitting a SIMD instruction that
expects aligned memory (MDEV-37148, MDEV-37786, MDEV-38398) and
allows us to enable the fast path across all ISA.

Reviewed by: Alexander Barkov
Reviewed by: Vladislav Vaintroub
2026-01-21 14:16:00 +02:00
Oleksandr Byelkin
840ebde8b9 new CC 2026-01-21 13:14:25 +01:00
Jan Lindström
48d08d6e99 MDEV-38558 : MariaDB does not support writes during MySQL --> MariaDB migration
When MariaDB node has joined to MySQL Galera cluster if any writes
to existing tables are done cluster requests to use protocol
version 7 (max protocol version used by MySQL Galera cluster).
MariaDB had support to protocol version up to 4. While writeset
keys are prepared allow using protocol version 7, it has no
effect on writeset key format i.e. protocol version 4 and 7
are identical on that case.

Note that there is no mtr test case because currently there is no
way to test both MySQL and MariaDB in mtr.
2026-01-21 12:41:26 +02:00
Sergey Vojtovich
f0ffc5d432 MDEV-37862 - innodb.gap_locks test failure: 0 lock structs, 0 row locks
Test was affected by incompletely closed preceding connections.

Make test agnostic to concurrent connections by querying
InnoDB status only for connections that it uses.

This is an addition to 3b2169f0d1, which didn't handle a case when
preceding test has active transaction on disconnect.
2026-01-21 14:08:07 +04:00
Thirunarayanan Balathandayuthapani
e583a7724b MDEV-37042 innodb_undo_log_truncate=ON leads to out-of-bounds write
During undo tablespace truncation, pages with LSNs older than the
tablespace creation LSN may still exist in the buffer pool and get
submitted to the doublewrite buffer. When mtr_t::commit_shrink() is
invoked shortly after doublewrite batch submission,
this can lead to out-of-bounds write errors.

Fix:
===
buf_dblwr_t::flush_buffered_writes_completed() : skip doublewrite
processing for pages where the page LSN is older
than the tablespace creation LSN. Such pages belong to the old
tablespace before truncation and should not be written through the
doublewrite buffer.
2026-01-21 11:32:16 +05:30
Oleksandr Byelkin
8575b07f11 MDEV-35288 Assertion `!is_cond()' failed in virtual longlong Item_bool_func::val_int()
Boolean function now uses val_bool to get string result (val_str())
2026-01-20 16:58:08 +01:00
Jan Lindström
df50563513 MDEV-38598 : Galera test failure on MW-86-wait8
Test failure is caused by regression introduced by commit
4de773e90 that changed error code when function does not exists.
2026-01-20 17:23:53 +02:00
Vladislav Vaintroub
52b1d7eb7f libfmt 12.1 - Suppress warning, MSVC-specific
discarding return value of function with [[nodiscard]] attribute
for std::isalpha

This comes from libfmt templated code
2026-01-20 15:41:19 +01:00
Jan Lindström
540e6daeee MDEV-37984 : Test failure on galera.MDEV-34647
Make sure that both nodes uses intended auto_increment configuration,
all tables and rows are replicated and ordered correctly.
2026-01-20 16:16:56 +02:00
Vladislav Vaintroub
6c4aedae5e new HeidiSQL 2026-01-20 12:32:00 +01:00
Marko Mäkelä
e2c63a7062 MDEV-38595: Simplify InnoDB doublewrite buffer creation
buf_dblwr_t::create(): Create the doublewrite buffer in a single
atomic mini-transaction. Do not write any log records for
initializing any doublewrite buffer pages, in order to avoid
recovery failure with innodb_log_archive=ON starting from the
very beginning.

The mtr.commit() in buf_dblwr_t::create() was observed to
comprise 295 mtr_t::m_memo entries: 1 entry for the
fil_system.sys_space and the rest split between page 5 (TRX_SYS)
and page 0 (allocation metadata). We are nowhere near the
sux_lock::RECURSIVE_MAX limit of 65535 per page descriptor.

Reviewed by: Thirunarayanan Balathandayuthapani
Tested by: Saahil Alam
2026-01-20 12:41:27 +02:00
Vladislav Vaintroub
496767b310 pcre2 10.47 2026-01-20 11:07:04 +01:00
Raghunandan Bhat
a8471426f4 MDEV-38487: Prevent aggregate function cloning when pushing HAVING into WHERE
Problem:
  When building a pushable condition that can be pushed from HAVING into
  WHERE, the server tries to clone aggregate functions. This is not
  necessary because aggregate functions can not be pushed into WHERE
  anyway.

Fix:
  This fix introduces a check within `Item::build_pushable_cond` to skip
  cloning aggregate functions.

Also fixes assert failure in MDEV-38492, by adding a missing copy method
for `Item_aggregate_ref`.
2026-01-20 09:46:35 +01:00
Jan Lindström
e40277d29b MDEV-38218 : Galera test failure on galera_bf_abort_flush_for_export
Problem was in wsrep_handle_mdl_conflict function was comparing
thd->lex->sql_command variable for granted MDL-lock.

There is two possible schedules:

    (1) FLUSH TABLES ... FOR EXPORT that will take MDL-lock (granted_thd).
        INSERT from other node is conflicting operation (request_thd)
        and sees MDL-conflict. Because granted_thd has not executed anything
        else thd->lex->sql_command == SQLCOM_FLUSH and this case was
        correctly handled in wsrep_handle_mdl_conflict i.e. INSERT needs
        to wait.

    (2) FLUSH TABLES ... FOR EXPORT that will take MDL-lock (granted_thd).
        SET SESSION wsrep_sync_wait=0; (granted_thd)
        INSERT from other node is conflicting operation (request_thd)

        However, thd->lex->sql_command is not stored to taken MDL-lock. Now
        as granted_thd is executing SET thd->lex->sql_command != SQLCOM_FLUSH
        and INSERT that is BF will abort it and that means also FTFE is
        killed and MDL-lock relesed. This is incorrect as FTFE has written
        file on filesystem and it can't be really killed.

In this fix wsrep_handle_mdl_conflict is refactored not to use
thd->lex->sql_command as a variable used for decisions. Instead
connection state can be determined also via THD members. E.g.:

    * wsrep_thd_is_toi() || wsrep_thd_is_applying - ongoing TOI or applier
    * wsrep_thd_is_BF - thread is brute force
    * wsrep_thd_is_SR - thread is streaming replication thread
    * thd->current_backup_stage != BACKUP_FINISHED - there's ongoing BACKUP
    * thd->global_read_lock.is_acquired() - ongoing FTWRL
    * thd->locked_tables_mode == LTM_LOCK_TABLES - ongoing FTFE or LOCK TABLES
2026-01-20 10:23:44 +02:00
Marko Mäkelä
b241f97daa MDEV-32744 fixup: clang -Winstantiation-after-specialization 2026-01-20 08:57:39 +02:00
Marko Mäkelä
08c57c5ebf MDEV-37600 fixup: clang 21 -Wunterminated-string-initialization 2026-01-20 08:55:59 +02:00
Oleksandr Byelkin
f18ad925b8 Wolfssl v5.8.4-stable 2026-01-19 20:52:59 +01:00
Vladislav Vaintroub
f92337ac17 Fix MSVC warning
innodb_rbt-t.cc(9,1): warning C4722: 'ib::fatal_or_error::~fatal_or_error':
destructor never returns, potential memory leak
2026-01-19 17:09:05 +01:00
Vladislav Vaintroub
f2cb54849f MDEV-38203 fix build error on Windows 2026-01-19 16:36:55 +01:00
Vladislav Vaintroub
42c260bc0f MDEV-37997 vcpkg's FIND_PACKAGE throws error for zlib dependent packages
Build with vcpkg and WITH_ZLIB=bundled throws error
"Broken installation of vcpkg port zlib" in FIND_PACKAGE(CURL)

Set CMAKE_DISABLE_FIND_PACKAGE_ZLIB to workaround.

Previously, this workaround was hashicorp specific, now we need this also
for videx. Thus setting CMAKE_DISABLE_FIND_PACKAGE_ZLIB was moved to
correct place,  inside MYSQL_USE_BUNDLED_ZLIB macro.
2026-01-19 16:36:55 +01:00
Rucha Deodhar
8c6ebbacce MDEV-25148: Unexpected success and result set upon erroneous JSON_VALUE call
Analysis:
When scanning json and reaching a path, the path type is
JSON_PATH_ARRAY_WILD. So it should not return any value. But the code
does not check that.

Fix:
Use path_setup_nwc() to check for range queries because json_value() should
not accept range queries.
2026-01-18 20:14:53 +05:30
Vladislav Vaintroub
c69ea9b286 Skip main.mysql_options_err, if ha_example plugin is missing
This fixes Appveyor build.
2026-01-16 23:33:22 +01:00
Vladislav Vaintroub
eee6c91fdf Windows,CMake - remove invalid use of MESSAGE_ONCE 2026-01-16 20:20:48 +01:00
Kristian Nielsen
13aad4ed2b MDEV-20586: Incorrect commit of transaction in GTID table processing
The initial scanning of the GTID pos table in find_gtid_pos_tables_cb() used
the wrong call to commit the transaction, ha_commit_trans(thd, TRUE) instead
of trans_commit(thd). This could cause an assertion
  Assertion '!thd->in_active_multi_stmt_transaction() || thd->in_multi_stmt_transaction_mode()' failed in mysql_execute_command
and possibly other issues due to incorrect state in the SQL thread THD.

Similar problem in rpl_slave_state::truncate_state_table() also fixed.

Note there is a sister patch cd88b0831f
which applied this same pattern which fixed a hang due to locks
not being released in the ha_commit_trans(thd, TRUE) call.

Test-case-by: Alice Sherepa <alice.sherepa@gmail.com>
Reviewed-by: Brandon Nesterenko <brandon.nesterenko@mariadb.com>
Signed-off-by: Kristian Nielsen <knielsen@knielsen-hq.org>
2026-01-15 16:19:34 -07:00
Mohammad Tafzeel Shams
7fed014308 MDEV-38140: InnoDB index corruption after UPDATE affecting virtual
columns

Issue:
- Purge thread attempts to purge a secondary index record that is not
  delete-marked.

Root Cause:
- When a secondary index includes a virtual column whose v_pos is
  greater than the number of fields in the clustered index record, the
  virtual column is incorrectly skipped while reading from the undo
  record.
- This leads the purge logic to incorrectly assume it is safe to purge
  the secondary index record.
- The code also confuses the nth virtual column with the nth stored
  column when writing ordering columns at the end of the undo record.

Fix:
- In trx_undo_update_rec_get_update(): Skip a virtual column only
  when v_pos == FIL_NULL, not when v_pos is greater than the number
  of fields.
- In trx_undo_page_report_modify(): Ensure ordering columns are
  written based on the correct stored-column positions, without
  confusing them with virtual-column positions.
2026-01-15 12:19:48 +05:30
Sergei Golubchik
65720c604e MDEV-38110 Sever shutdown prevented by RocksDB setting rocksdb_pause_background_work
enable background threads on shutdown, so that they could
respond to signals and free resources
2026-01-14 19:44:54 +01:00
Sergei Golubchik
d12a5333fd MDEV-37888 unexpected type changing after changing AVG to MAX
set collation for AVG, like it's done for MAX
2026-01-14 19:44:54 +01:00
Sergei Golubchik
2c983b5ebb MDEV-38006 Inconsistent behaviors when casting into time
number-to-time conversion was too eagerly capping the value.

A string "9000090" was invalid time, because of 90 seconds.
But number-to-time was capping first, validating later,
to 9000090->time worked. Let's fix it.

also, let's make invalid time values in a string field include
the field name in the warning message, just like invalid time
values in a numeric field do.
2026-01-14 19:44:54 +01:00
Sergei Golubchik
5349220b2e MDEV-37979 sys.ps_setup_save does not restore SQL_LOG_BIN after error, causes replication discrepancy 2026-01-14 19:44:30 +01:00
Sergei Golubchik
0dcec66416 MDEV-38233 Inconsistent results for make_set of cast
if ((res=item->val_str(str)) != str)

is incorrect way to detect whether res can be safely used,
because Item_char_typecast::val_str() can return res
which is different from str, but shares the same buffer.
2026-01-14 19:44:30 +01:00
Sergei Golubchik
0db178da5e MDEV-38124 event scheduler spams the error log
event scheduler was printing a lot of info in [Note] in error log.

change to print its startup/shutdown notes only when log_warnings>0.
and runtime notes only when log_warnings>2.
one note was an abnormal error, change to [Error].
2026-01-14 19:44:30 +01:00
Sergei Golubchik
c26d7b9d0f MDEV-36668 main.mysqld--help-aria test failure when no MAC address
don't use such a greedy regex_replace pattern
2026-01-14 19:44:30 +01:00
Sergei Golubchik
32c846e9fc MDEV-38237 Incorrect BuildRequires entry in RHEL10 srpm
apparently a file can be present in *more than one* rpm,
e.g. /usr/bin/dtrace on rhel10 is present *both* in
systemtap-sdt-dtrace and in systemtap-sdt-devel.

Make sure there's a separator between entries.
2026-01-14 19:44:30 +01:00