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)
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.
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.
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().
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.
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.
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.
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>
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)
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.
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.
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
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.
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.
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.
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
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`.
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
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.
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.
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>
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.
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.
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.
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].
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.