1. 26 Oct, 2022 1 commit
    • Oleg Smirnov's avatar
      MDEV-29662 Replace same values in 'IN' list with an equality · 5027cb2b
      Oleg Smirnov authored
      If all elements in the list of 'IN' or 'NOT IN' clause are equal
      and there are no NULLs then clause
      -  "a IN (e1,..,en)" can be converted to "a = e1"
      -  "a NOT IN (e1,..,en)" can be converted to "a <> e1".
      This means an object of Item_func_in can be replaced with an object
      of Item_func_eq for IN (e1,..,en) clause and Item_func_ne for
      NOT IN (e1,...,en). Such a replacement allows the optimizer to choose
      a better execution plan
      5027cb2b
  2. 04 Aug, 2022 2 commits
  3. 03 Aug, 2022 1 commit
    • Sergei Petrunia's avatar
      MDEV-23809: Server crash in JOIN_CACHE::free or ... · 2cd98c95
      Sergei Petrunia authored
      The problem was caused by use of COLLATION(AVG('x')). This is an
      item whose value is a constant.
      Name Resolution code called convert_const_to_int() which removed AVG('x').
      However, the item representing COLLATION(...) still had with_sum_func=1.
      
      This inconsistent state confused the code that handles grouping and
      DISTINCT: JOIN::get_best_combination() decided to use one temporary
      table and allocated one JOIN_TAB for it, but then
      JOIN::make_aggr_tables_info() attempted to use two and made writes
      beyond the end of the JOIN::join_tab array.
      
      The fix:
      - Do not replace constant expressions which contain aggregate functions.
      - Add JOIN::dbug_join_tab_array_size to catch attempts to use more
        JOIN_TAB objects than we've allocated.
      2cd98c95
  4. 26 Jul, 2022 5 commits
    • Sergei Petrunia's avatar
      MDEV-28929: Plan selection takes forever with MDEV-28852 ... · 8c2faad5
      Sergei Petrunia authored
      Part #2: Extend heuristic pruning to use multiple tables as the
      "Model tables".
      
      Before the patch, heuristic pruning uses only one "Model table":
      The table which had the best cost AND record became the "Model table".
      After that, if a table's cost and record were both worse than
      those of the Model Table, the table would be pruned away.
      
      This didn't work well when the first table (the optimizer sorts them
      by record_count) had low record_count but relatively high cost: nothing
      could be pruned afterwards.
      
      The patch adds the two additional "Model tables": one with the least
      cost and the other with the least record_count.
      (In both cases, a table can be pruned away if BOTH its cost and
      record_count are worse than those of a Model table)
      
      The new pruning is active when the number of tables to consider for
      the prefix is higher than @@optimizer_extra_pruning_depth.
      
      One can see the new pruning in the Optimizer Trace as
      - "pruned_by_heuristic":"min_record_count", or
      - "pruned_by_heuristic":"min_read_time".
      Old heuristic pruning shows as "pruned_by_heuristic":1.
      8c2faad5
    • Monty's avatar
      Reduced size of POSITION · 1f0187ff
      Monty authored
      Replaced Cost_estimate prefix_cost with a double as prefix_cost was
      only used to store and retrive total prefix cost.
      
      This also speeds up things (a bit) as don't have to call
      Cost_estimate::total_cost() for every access to the prefix_cost.
      
      Sizeof POSITION decreased from 304 to 256.
      1f0187ff
    • Monty's avatar
      Added EQ_REF chaining to the greedy_optimizer · 515b9ad0
      Monty authored
      MDEV-28073 Slow query performance in MariaDB when using many table
      
      The idea is to prefer and chain EQ_REF tables (tables that uses an
      unique key to find a row) when searching for the best table combination.
      This significantly reduces row combinations that has to be examined.
      This is optimization is enabled when setting optimizer_prune_level=2
      (which is now default).
      
      Implementation:
      - optimizer_prune_level has a new level, 2, which enables EQ_REF
        optimization in addition to the pruning done by level 1.
        Level 2 is now default.
      - Added JOIN::eq_ref_tables that contains bits of tables that could use
        potentially use EQ_REF access in the query.  This is calculated
        in sort_and_filter_keyuse()
      
      Under optimizer_prune_level=2:
      - When the greedy_optimizer notices that the preceding table was an
        EQ_REF table, it tries to add an EQ_REF table next. If an EQ_REF
        table exists, only this one will be considered at this level.
        We also collect all EQ_REF tables chained by the next levels and these
        are ignored on the starting level as we have already examined these.
        If no EQ_REF table exists, we continue as normal.
      
      This optimization speeds up the greedy_optimizer combination test with
      ~25%
      
      Other things:
      - I ported the changes in MySQL 5.7 to greedy_optimizer.test to MariaDB
        to be able to ensure we can handle all cases that MySQL can do.
      - I have run all tests with --mysqld=--optimizer_prune_level=1 to verify that
        there where no test changes.
      515b9ad0
    • Monty's avatar
      Added get_allowed_nj_tables() to speed up gready_search() · 318a74f1
      Monty authored
      "Get the tables that one is allowed to have as the next table in the
      current plan"
      
      Main author: Sergei Petrunia <sergey@mariadb.com>
      Co author: Monty
      318a74f1
    • Monty's avatar
      Improve pruning in greedy_search by sorting tables during search · b3c74bdc
      Monty authored
      MDEV-28073 Slow query performance in MariaDB when using many tables
      
      The faster we can find a good query plan, the more options we have for
      finding and pruning (ignoring) bad plans.
      
      This patch adds sorting of plans to best_extension_by_limited_search().
      The plans, from best_access_path() are sorted according to the numbers
      of found rows.  This allows us to faster find 'good tables' and we are
      thus able to eliminate 'bad plans' faster.
      
      One side effect of this patch is that if two tables have equal cost,
      the table that which was used earlier in the query is preferred.
      This allows users to improve plans by reordering eq_ref tables in the
      order they would like them to be uses.
      
      Result changes caused by the patch:
      - Traces are different as now we print the cost for using tables before
        we start considering them in the plan.
      - Table order are changed for some plans. In most cases this is because
        the plans are equal and tables are in this case sorted according to
        their usage in the original query.
      - A few plans was changed as the optimizer was able to find a better
        plan (that was pruned by the original code).
      
      Other things:
      
      - Added a new statistic variable: "optimizer_join_prefixes_check_calls",
        which counts number of calls to best_extension_by_limited_search().
        This can be used to check the prune efficiency in greedy_search().
      - Added variable "JOIN_TAB::embedded_dependent" to be able to handle
        XX IN (SELECT..) in the greedy_optimizer.  The idea is that we
        should prune a table if any of the tables in embedded_dependent is
        not yet read.
      - When using many tables in a query, there will be some additional
        memory usage as we need to pre-allocate table of
        table_count*table_count*sizeof(POSITION) objects (POSITION is 312
        bytes for now) to hold the pre-calculated best_access_path()
        information.  This memory usage is offset by the expected
        performance improvement when using many tables in a query.
      - Removed the code from an earlier patch to keep the table order in
        join->best_ref in the original order.  This is not needed anymore as we
        are now sorting the tables for each best_extension_by_limited_search()
        call.
      b3c74bdc
  5. 14 Jul, 2022 1 commit
  6. 07 Jun, 2022 3 commits
    • Michael Widenius's avatar
      Improve table pruning in optimizer with up to date key_dependent map · 432a4ebe
      Michael Widenius authored
      Part of:
      MDEV-28073 Slow query performance in MariaDB when using many tables
      
      s->key_dependent has a list of tables that are compared with key fields
      in the current table.  However it does not take into account if a key
      field could be resolved by another table.
      This is because MariaDB expands 'join_tab->keyuse' to include all generated
      comparisons.
      For example:
      SELECT * from t1,t2,t3 where t1.key=t2.key and t2.key=t3.key
      In this case keyuse for t1 includes t2.key and t3.key and key_dependent
      contains 't2.map | t3.map'
      If we in best_extension_by_limited_search() consider t2,t1 then t1's
      key is fully defined, but we cannot do any prune of plans as
      s->key_dependent indicates that t3 is still needed.
      
      Fixed by calculating in best_access_patch the current key_dependent map
      of tables that is needed to satisfy all keys. This allows us to prune
      more bad plans earlier as soon as all keys can be used.
      
      We also set key_dependent to 0 if we found an EQ_REF key, as this an
      optimal key for the table and there is no reason to check more keys.
      432a4ebe
    • Sergei Petrunia's avatar
      MDEV-28749: restore_prev_nj_state() doesn't update cur_sj_inner_tables correctly · f0ea7f7f
      Sergei Petrunia authored
      (Try 2)
      
      The code that updates semi-join optimization state for a join order prefix
      had several bugs. The visible effect was bad optimization for FirstMatch or
      LooseScan strategies: they either weren't considered when they should have
      been, or considered when they shouldn't have been.
      
      In order to hit the bug, the optimizer needs to consider several different
      join prefixes in a certain order. Queries with "obvious" query plans which
      prune all join orders except one are not affected.
      
      Internally, the bugs in updates of semi-join state were:
      1. restore_prev_sj_state() assumed that
        "we assume remaining_tables doesnt contain @tab"
        which wasn't true.
      2. Another bug in this function: it did remove bits from
         join->cur_sj_inner_tables but never added them.
      3. greedy_search() adds tables into the join prefix but neglects to update
         the semi-join optimization state. (It does update nested outer join
         state, see this call:
           check_interleaving_with_nj(best_table)
         but there's no matching call to update the semi-join state.
         (This wasn't visible because most of the state is in the POSITION
          structure which is updated. But there is also state in JOIN, too)
      
      The patch:
      - Fixes all of the above
      - Adds JOIN::dbug_verify_sj_inner_tables() which is used to verify the
        state is correct at every step.
      - Renames advance_sj_state() to optimize_semi_joins().
        = Introduces update_sj_state() which ideally should have been called
          "advance_sj_state" but I didn't reuse the name to not create confusion.
      f0ea7f7f
    • Sergei Petrunia's avatar
      MDEV-28749: restore_prev_nj_state() doesn't update cur_sj_inner_tables correctly · 19c72163
      Sergei Petrunia authored
      (Try 2) (Cherry-pick back into 10.3)
      
      The code that updates semi-join optimization state for a join order prefix
      had several bugs. The visible effect was bad optimization for FirstMatch or
      LooseScan strategies: they either weren't considered when they should have
      been, or considered when they shouldn't have been.
      
      In order to hit the bug, the optimizer needs to consider several different
      join prefixes in a certain order. Queries with "obvious" query plans which
      prune all join orders except one are not affected.
      
      Internally, the bugs in updates of semi-join state were:
      1. restore_prev_sj_state() assumed that
        "we assume remaining_tables doesnt contain @tab"
        which wasn't true.
      2. Another bug in this function: it did remove bits from
         join->cur_sj_inner_tables but never added them.
      3. greedy_search() adds tables into the join prefix but neglects to update
         the semi-join optimization state. (It does update nested outer join
         state, see this call:
           check_interleaving_with_nj(best_table)
         but there's no matching call to update the semi-join state.
         (This wasn't visible because most of the state is in the POSITION
          structure which is updated. But there is also state in JOIN, too)
      
      The patch:
      - Fixes all of the above
      - Adds JOIN::dbug_verify_sj_inner_tables() which is used to verify the
        state is correct at every step.
      - Renames advance_sj_state() to optimize_semi_joins().
        = Introduces update_sj_state() which ideally should have been called
          "advance_sj_state" but I didn't reuse the name to not create confusion.
      19c72163
  7. 12 May, 2022 1 commit
    • Monty's avatar
      MDEV-28073 Query performance degradation in newer MariaDB versions when using many tables · b729896d
      Monty authored
      The issue was that best_extension_by_limited_search() had to go through
      too many plans with the same cost as there where many EQ_REF tables.
      
      Fixed by shortcutting EQ_REF (AND REF) when the result only contains one
      row. This got the optimization time down from hours to sub seconds.
      
      The only known downside with this patch is that in some cases a table
      with ref and 1 record may be used before on EQ_REF table. The faster
      optimzation phase should compensate for this.
      b729896d
  8. 05 May, 2022 1 commit
    • Sergei Petrunia's avatar
      MDEV-28437: Assertion `!eliminated' failed in Item_subselect::exec · 8dbfaa2a
      Sergei Petrunia authored
      (This is the assert that was added in fix for MDEV-26047)
      
      Table elimination may remove an ON expression from an outer join.
      However SELECT_LEX::update_used_tables() will still call
      
        item->walk(&Item::eval_not_null_tables)
      
      for eliminated expressions. If the subquery is constant and cheap
      Item_cond_and will attempt to evaluate it, which will trigger an
      assert.
      The fix is not to call update_used_tables() or eval_not_null_tables()
      for ON expressions that were eliminated.
      8dbfaa2a
  9. 29 Apr, 2022 1 commit
  10. 08 Feb, 2022 1 commit
    • Monty's avatar
      MDEV-26585 Wrong query results when `using index for group-by` · 38058c04
      Monty authored
      The problem was that "group_min_max optimization" does not work if
      some aggregate functions, like COUNT(*), is used.
      The function get_best_group_min_max() is using the join->sum_funcs
      array to check which aggregate functions are used.
      The bug was that aggregates in HAVING where not yet added to
      join->sum_funcs at the time get_best_group_min_max() was called.
      
      Fixed by populate join->sum_funcs already in prepare, which means that
      all sum functions will be in join->sum_funcs in get_best_group_min_max().
      A benefit of this approach is that we can remove several calls to
      make_sum_func_list() from the code and simplify the function.
      
      I removed some wrong setting of 'sort_and_group'.
      This variable is set when alloc_group_fields() is called, as part
      of allocating the cache needed by end_send_group() and does not need
      to be set by other functions.
      
      One problematic thing was that Spider is using *join->sum_funcs to detect
      at which stage the optimizer is and do internal calculations of aggregate
      functions. Updating join->sum_funcs early caused Spider to fail when trying
      to find min/max values in opt_sum_query().
      Fixed by temporarily resetting sum_funcs during opt_sum_query().
      
      Reviewer: Sergei Petrunia
      38058c04
  11. 26 Jan, 2022 1 commit
    • Igor Babaev's avatar
      MDEV-27510 Query returns wrong result when using split optimization · 00412656
      Igor Babaev authored
      This bug may affect the queries that uses a grouping derived table with
      grouping list containing references to columns from different tables if
      the optimizer decides to employ the split optimization for the derived
      table. In some very specific cases it may affect queries with a grouping
      derived table that refers only one base table.
      This bug was caused by an improper fix for the bug MDEV-25128. The fix
      tried to get rid of the equality conditions pushed into the where clause
      of the grouping derived table T to which the split optimization had been
      applied. The fix erroneously assumed that only those pushed equalities
      that were used for ref access of the tables referenced by T were needed.
      In fact the function remove_const() that figures out what columns from the
      group list can be removed if the split optimization is applied can uses
      other pushed equalities as well.
      This patch actually provides a proper fix for MDEV-25128. Rather than
      trying to remove invalid pushed equalities referencing the fields of SJM
      tables with a look-up access the patch attempts not to push such equalities.
      
      Approved by Oleksandr Byelkin <sanja@mariadb.com>
      00412656
  12. 07 Dec, 2021 1 commit
  13. 05 Dec, 2021 1 commit
  14. 19 May, 2021 6 commits
    • Monty's avatar
      Fix all warnings given by UBSAN · cc125beb
      Monty authored
      The 'special' cases where we disable, suppress or circumvent UBSAN are:
      - ref10 source (as here we intentionally do some shifts that UBSAN
        complains about.
      - x86 version of optimized int#korr() methods. UBSAN do not like unaligned
        memory access of integers.  Fixed by using byte_order_generic.h when
        compiling with UBSAN
      - We use smaller thread stack with ASAN and UBSAN, which forced me to
        disable a few tests that prints the thread stack size.
      - Verifying class types does not work for shared libraries. I added
        suppression in mysql-test-run.pl for this case.
      - Added '#ifdef WITH_UBSAN' when using integer arithmetic where it is
        safe to have overflows (two cases, in item_func.cc).
      
      Things fixed:
      - Don't left shift signed values
        (byte_order_generic.h, mysqltest.c, item_sum.cc and many more)
      - Don't assign not non existing values to enum variables.
      - Ensure that bool and enum values are properly initialized in
        constructors.  This was needed as UBSAN checks that these types has
        correct values when one copies an object.
        (gcalc_tools.h, ha_partition.cc, item_sum.cc, partition_element.h ...)
      - Ensure we do not called handler functions on unallocated objects or
        deleted objects.
        (events.cc, sql_acl.cc).
      - Fixed bugs in Item_sp::Item_sp() where we did not call constructor
        on Query_arena object.
      - Fixed several cast of objects to an incompatible class!
        (Item.cc, Item_buff.cc, item_timefunc.cc, opt_subselect.cc, sql_acl.cc,
         sql_select.cc ...)
      - Ensure we do not do integer arithmetic that causes over or underflows.
        This includes also ++ and -- of integers.
        (Item_func.cc, Item_strfunc.cc, item_timefunc.cc, sql_base.cc ...)
      - Added JSON_VALUE_UNITIALIZED to json_value_types and ensure that
        value_type is initialized to this instead of to -1, which is not a valid
        enum value for json_value_types.
      - Ensure we do not call memcpy() when second argument could be null.
      
      Other things:
      
      - Changed struct st_position to an OBJECT and added an initialization
        function to it to ensure that we do not copy or use uninitialized
        members. The change to a class was also motived that we used "struct
        st_position" and POSITION randomly trough the code which was
        confusing.
      - Notably big rewrite in sql_acl.cc to avoid using deleted objects.
      - Changed in sql_partition to use '^' instead of '-'. This is safe as
        the operator is either 0 or 0x8000000000000000ULL.
      - Added check for select_nr < INT_MAX in JOIN::build_explain() to
        avoid bug when get_select() could return NULL.
      - Reordered elements in POSITION for better alignment.
      - Changed sql_test.cc::print_plan() to use pointers instead of objects.
      - Fixed bug in find_set() where could could execute '1 << -1'.
      - Added variable have_sanitizer, used by mtr.  (This variable was before
        only in 10.5 and up).  It can now have one of two values:
        ASAN or UBSAN.
      - Moved ~Archive_share() from ha_archive.cc to ha_archive.h and marked
        it virtual. This was an effort to get UBSAN to work with loaded storage
        engines. I kept the change as the new place is better.
      - Added in CONNECT engine COLBLK::SetName(), to get around a wrong cast
        in tabutil.cpp.
      
      Changes that should not be needed but had to be done to suppress warnings
      from UBSAN:
      
      - Added static_cast<<uint16_t>> around shift to get rid of a LOT of
        compiler warnings when using UBSAN.
      - Had to change some '/' of 2 base integers to shift to get rid of
        some compile time warnings.
      
      Fixes:
      
      MDEV-25505 Assertion `old_flags == ((my_flags & 0x10000U) ? 1 : 0)
      fixed (was caused by an old version if this commit).
      
      Reviewed by:
      - Json changes: Alexey Botchkov
      - Charset changes in ctype-uca.c: Alexander Barkov
      - InnoDB changes: Marko Mäkelä
      - sql_acl.cc changes: Vicențiu Ciorbaru
      - build_explain() changes: Sergey Petrunia
      Temporary commit to log changes for UBSAN
      cc125beb
    • Monty's avatar
      Improved code comment and removed nop test · db9398ba
      Monty authored
      db9398ba
    • Monty's avatar
      Remove some usage of Check_level_instant_set and Sql_mode_save · 08bc062e
      Monty authored
      The reason for the removal are:
      - Generates more code
        - Storing and retreving THD
        - Causes extra code and daata to be generated to handle possible throw
          exceptions (which never happens in MariaDB code)
      - Uses more stack space
      
      Other things:
      - Changed convert_const_to_int() to use item->save_in_field_no_warnings(),
        which made the code shorter and simpler.
      - Removed not needed code in Sp_handler::sp_create_routine()
      - Added thd as argument to store_key.copy() to make function simpler
      - Added thd as argument to some subselect* constructor that inherites
        from Item_subselect.
      08bc062e
    • Monty's avatar
      MDEV-24089 support oracle syntax: rownum · be093c81
      Monty authored
      The ROWNUM() function is for SELECT mapped to JOIN->accepted_rows, which is
      incremented for each accepted rows.
      For Filesort, update, insert, delete and load data, we map ROWNUM() to
      internal variables incremented when the table is changed.
      The connection between the row counter and Item_func_rownum is done
      in sql_select.cc::fix_items_after_optimize() and
      sql_insert.cc::fix_rownum_pointers()
      
      When ROWNUM() is used anywhere in query, the optimization to ignore ORDER
      BY in sub queries are disabled. This was done to get the following common
      Oracle query to work:
      select * from (select * from t1 order by a desc) as t where rownum() <= 2;
      MDEV-3926 "Wrong result with GROUP BY ... WITH ROLLUP" contains a discussion
      about this topic.
      
      LIMIT optimization is enabled when in a top level WHERE clause comparing
      ROWNUM() with a numerical constant using any of the following expressions:
      - ROWNUM() < #
      - ROWNUM() <= #
      - ROWNUM() = 1
      ROWNUM() can be also be the right argument to the comparison function.
      
      LIMIT optimization is done in two cases:
      - For the current sub query when the ROWNUM comparison is done on the top
        level:
        SELECT * from t1 WHERE rownum() <= 2 AND t1.a > 0
      - For an inner sub query, when the upper level has only a ROWNUM comparison
        in the WHERE clause:
        SELECT * from (select * from t1) as t WHERE rownum() <= 2
      
      In Oracle mode, one can also use ROWNUM without parentheses.
      
      Other things:
      - Fixed bug where the optimizer tries to optimize away sub queries
        with RAND_TABLE_BIT set (non-deterministic queries). Now these
        sub queries will not be converted to joins.  This bug fix was also
        needed to get rownum() working inside subqueries.
      - In remove_const() remove setting simple_order to FALSE if ROLLUP is
        USED. This code was disable a long time ago because of wrong assignment
        in the following code.  Instead we set simple_order to false if
        RAND_TABLE_BIT was used in the SELECT list.  This ensures that
        we don't delete ORDER BY if the result set is not deterministic, like
        in 'SELECT RAND() AS 'r' FROM t1 ORDER BY r';
      - Updated parameters for Sort_param::init_for_filesort() to be able
        to provide filesort with information where the number of accepted
        rows should be stored
      - Reordered fields in class Filesort to optimize storage layout
      - Added new error messsage to tell that a function can't be used in HAVING
      - Added field 'with_rownum' to THD to mark that ROWNUM() is used in the
        query.
      
      Co-author: Oleksandr Byelkin <sanja@mariadb.com>
                 LIMIT optimization for sub query
      be093c81
    • Monty's avatar
      Added override to all releveant methods in Item (and a few other classes) · 30f0a246
      Monty authored
      Other things:
      - Remove inline and virtual for methods that are overrides
      - Added a 'final' to some Item classes
      30f0a246
    • Michael Widenius's avatar
      Change bitfields in Item to an uint16 · 3105c9e7
      Michael Widenius authored
      The reason for the change is that neither clang or gcc can do efficient
      code when several bit fields are change at the same time or when copying
      one or more bits between identical bit fields.
      Updated bits explicitely with & and | is MUCH more efficient than what
      current compilers can do.
      3105c9e7
  15. 30 Apr, 2021 1 commit
    • Sergei Petrunia's avatar
      MDEV-23723: Crash when test_if_skip_sort_order() is checked for derived ... · 2820f30d
      Sergei Petrunia authored
      The problem was caused by the following scenario:
      
      Subquery's table has two indexes, KEY a(a), KEY a_b(a,b)
      
      - LATERAL DERIVED optimization decides to use index a.
        = The subquery uses ref access over key a.
      - test_if_skip_sort_order() sees that KEY a_b satisfies the
        subquery's GROUP BY clause, and attempts to switch to it.
        = It fails to do so, because KEYUSE objects for index a_b
          are switched off.
      
      Fixed by disallowing to change the ref access key if it uses KEYUSE
      objects injected by LATERAL DERIVED optimization.
      2820f30d
  16. 21 Apr, 2021 2 commits
    • Vicențiu Ciorbaru's avatar
      MDEV-23908: Implement SELECT ... OFFSET ... FETCH ... · 299b9353
      Vicențiu Ciorbaru authored
      This commit implements the standard SQL extension
      OFFSET start { ROW | ROWS }
      [FETCH { FIRST | NEXT } [ count ] { ROW | ROWS } { ONLY | WITH TIES }]
      
      To achieve this a reserved keyword OFFSET is introduced.
      
      The general logic for WITH TIES implies:
      1. The number of rows a query returns is no longer known during optimize
         phase. Adjust optimizations to no longer consider this.
      2. During end_send make use of an "order Cached_item"to compare if the
         ORDER BY columns changed. Keep returning rows until there is a
         change. This happens only after we reached the row limit.
      3. Within end_send_group, the order by clause was eliminated. It is
         still possible to keep the optimization of using end_send_group for
         producing the final result set.
      299b9353
    • Alexey Botchkov's avatar
      MDEV-17399 Add support for JSON_TABLE. · e9fd327e
      Alexey Botchkov authored
      The specific table handler for the table functions was introduced,
      and used to implement JSON_TABLE.
      e9fd327e
  17. 20 Apr, 2021 1 commit
    • Monty's avatar
      Fix all warnings given by UBSAN · 031f1171
      Monty authored
      The easiest way to compile and test the server with UBSAN is to run:
      ./BUILD/compile-pentium64-ubsan
      and then run mysql-test-run.
      After this commit, one should be able to run this without any UBSAN
      warnings. There is still a few compiler warnings that should be fixed
      at some point, but these do not expose any real bugs.
      
      The 'special' cases where we disable, suppress or circumvent UBSAN are:
      - ref10 source (as here we intentionally do some shifts that UBSAN
        complains about.
      - x86 version of optimized int#korr() methods. UBSAN do not like unaligned
        memory access of integers.  Fixed by using byte_order_generic.h when
        compiling with UBSAN
      - We use smaller thread stack with ASAN and UBSAN, which forced me to
        disable a few tests that prints the thread stack size.
      - Verifying class types does not work for shared libraries. I added
        suppression in mysql-test-run.pl for this case.
      - Added '#ifdef WITH_UBSAN' when using integer arithmetic where it is
        safe to have overflows (two cases, in item_func.cc).
      
      Things fixed:
      - Don't left shift signed values
        (byte_order_generic.h, mysqltest.c, item_sum.cc and many more)
      - Don't assign not non existing values to enum variables.
      - Ensure that bool and enum values are properly initialized in
        constructors.  This was needed as UBSAN checks that these types has
        correct values when one copies an object.
        (gcalc_tools.h, ha_partition.cc, item_sum.cc, partition_element.h ...)
      - Ensure we do not called handler functions on unallocated objects or
        deleted objects.
        (events.cc, sql_acl.cc).
      - Fixed bugs in Item_sp::Item_sp() where we did not call constructor
        on Query_arena object.
      - Fixed several cast of objects to an incompatible class!
        (Item.cc, Item_buff.cc, item_timefunc.cc, opt_subselect.cc, sql_acl.cc,
         sql_select.cc ...)
      - Ensure we do not do integer arithmetic that causes over or underflows.
        This includes also ++ and -- of integers.
        (Item_func.cc, Item_strfunc.cc, item_timefunc.cc, sql_base.cc ...)
      - Added JSON_VALUE_UNITIALIZED to json_value_types and ensure that
        value_type is initialized to this instead of to -1, which is not a valid
        enum value for json_value_types.
      - Ensure we do not call memcpy() when second argument could be null.
      - Fixed that Item_func_str::make_empty_result() creates an empty string
        instead of a null string (safer as it ensures we do not do arithmetic
        on null strings).
      
      Other things:
      
      - Changed struct st_position to an OBJECT and added an initialization
        function to it to ensure that we do not copy or use uninitialized
        members. The change to a class was also motived that we used "struct
        st_position" and POSITION randomly trough the code which was
        confusing.
      - Notably big rewrite in sql_acl.cc to avoid using deleted objects.
      - Changed in sql_partition to use '^' instead of '-'. This is safe as
        the operator is either 0 or 0x8000000000000000ULL.
      - Added check for select_nr < INT_MAX in JOIN::build_explain() to
        avoid bug when get_select() could return NULL.
      - Reordered elements in POSITION for better alignment.
      - Changed sql_test.cc::print_plan() to use pointers instead of objects.
      - Fixed bug in find_set() where could could execute '1 << -1'.
      - Added variable have_sanitizer, used by mtr.  (This variable was before
        only in 10.5 and up).  It can now have one of two values:
        ASAN or UBSAN.
      - Moved ~Archive_share() from ha_archive.cc to ha_archive.h and marked
        it virtual. This was an effort to get UBSAN to work with loaded storage
        engines. I kept the change as the new place is better.
      - Added in CONNECT engine COLBLK::SetName(), to get around a wrong cast
        in tabutil.cpp.
      - Added HAVE_REPLICATION around usage of rgi_slave, to get embedded
        server to compile with UBSAN. (Patch from Marko).
      - Added #ifdef for powerpc64 to avoid a bug in old gcc versions related
        to integer arithmetic.
      
      Changes that should not be needed but had to be done to suppress warnings
      from UBSAN:
      
      - Added static_cast<<uint16_t>> around shift to get rid of a LOT of
        compiler warnings when using UBSAN.
      - Had to change some '/' of 2 base integers to shift to get rid of
        some compile time warnings.
      
      Reviewed by:
      - Json changes: Alexey Botchkov
      - Charset changes in ctype-uca.c: Alexander Barkov
      - InnoDB changes & Embedded server: Marko Mäkelä
      - sql_acl.cc changes: Vicențiu Ciorbaru
      - build_explain() changes: Sergey Petrunia
      031f1171
  18. 26 Jan, 2021 1 commit
    • Nikita Malyavin's avatar
      MDEV-17556 Assertion `bitmap_is_set_all(&table->s->all_set)' failed · 21809f9a
      Nikita Malyavin authored
      The assertion failed in handler::ha_reset upon SELECT under
      READ UNCOMMITTED from table with index on virtual column.
      
      This was the debug-only failure, though the problem is mush wider:
      * MY_BITMAP is a structure containing my_bitmap_map, the latter is a raw
       bitmap.
      * read_set, write_set and vcol_set of TABLE are the pointers to MY_BITMAP
      * The rest of MY_BITMAPs are stored in TABLE and TABLE_SHARE
      * The pointers to the stored MY_BITMAPs, like orig_read_set etc, and
       sometimes all_set and tmp_set, are assigned to the pointers.
      * Sometimes tmp_use_all_columns is used to substitute the raw bitmap
       directly with all_set.bitmap
      * Sometimes even bitmaps are directly modified, like in
      TABLE::update_virtual_field(): bitmap_clear_all(&tmp_set) is called.
      
      The last three bullets in the list, when used together (which is mostly
      always) make the program flow cumbersome and impossible to follow,
      notwithstanding the errors they cause, like this MDEV-17556, where tmp_set
      pointer was assigned to read_set, write_set and vcol_set, then its bitmap
      was substituted with all_set.bitmap by dbug_tmp_use_all_columns() call,
      and then bitmap_clear_all(&tmp_set) was applied to all this.
      
      To untangle this knot, the rule should be applied:
      * Never substitute bitmaps! This patch is about this.
       orig_*, all_set bitmaps are never substituted already.
      
      This patch changes the following function prototypes:
      * tmp_use_all_columns, dbug_tmp_use_all_columns
       to accept MY_BITMAP** and to return MY_BITMAP * instead of my_bitmap_map*
      * tmp_restore_column_map, dbug_tmp_restore_column_maps to accept
       MY_BITMAP* instead of my_bitmap_map*
      
      These functions now will substitute read_set/write_set/vcol_set directly,
      and won't touch underlying bitmaps.
      21809f9a
  19. 08 Jan, 2021 1 commit
    • Nikita Malyavin's avatar
      MDEV-17556 Assertion `bitmap_is_set_all(&table->s->all_set)' failed · e25623e7
      Nikita Malyavin authored
      The assertion failed in handler::ha_reset upon SELECT under
      READ UNCOMMITTED from table with index on virtual column.
      
      This was the debug-only failure, though the problem is mush wider:
      * MY_BITMAP is a structure containing my_bitmap_map, the latter is a raw
       bitmap.
      * read_set, write_set and vcol_set of TABLE are the pointers to MY_BITMAP
      * The rest of MY_BITMAPs are stored in TABLE and TABLE_SHARE
      * The pointers to the stored MY_BITMAPs, like orig_read_set etc, and
       sometimes all_set and tmp_set, are assigned to the pointers.
      * Sometimes tmp_use_all_columns is used to substitute the raw bitmap
       directly with all_set.bitmap
      * Sometimes even bitmaps are directly modified, like in
      TABLE::update_virtual_field(): bitmap_clear_all(&tmp_set) is called.
      
      The last three bullets in the list, when used together (which is mostly
      always) make the program flow cumbersome and impossible to follow,
      notwithstanding the errors they cause, like this MDEV-17556, where tmp_set
      pointer was assigned to read_set, write_set and vcol_set, then its bitmap
      was substituted with all_set.bitmap by dbug_tmp_use_all_columns() call,
      and then bitmap_clear_all(&tmp_set) was applied to all this.
      
      To untangle this knot, the rule should be applied:
      * Never substitute bitmaps! This patch is about this.
       orig_*, all_set bitmaps are never substituted already.
      
      This patch changes the following function prototypes:
      * tmp_use_all_columns, dbug_tmp_use_all_columns
       to accept MY_BITMAP** and to return MY_BITMAP * instead of my_bitmap_map*
      * tmp_restore_column_map, dbug_tmp_restore_column_maps to accept
       MY_BITMAP* instead of my_bitmap_map*
      
      These functions now will substitute read_set/write_set/vcol_set directly,
      and won't touch underlying bitmaps.
      e25623e7
  20. 25 Nov, 2020 1 commit
  21. 27 Sep, 2020 1 commit
  22. 05 Aug, 2020 1 commit
    • Varun Gupta's avatar
      MDEV-17066: Bytes lost or Assertion `status_var.local_memory_used == 0 after... · 1e31d748
      Varun Gupta authored
      MDEV-17066: Bytes lost or Assertion `status_var.local_memory_used == 0 after DELETE with subquery with ROLLUP
      
      The issue here is when records are read from the temporary file
      (filesort result in this case) via a cache(rr_from_cache).
      The cache is initialized with init_rr_cache.
      For correlated subquery the cache allocation is happening at each execution
      of the subquery but the deallocation happens only once and that was
      when the query execution was done.
      
      So generally for subqueries we do two types of cleanup
      
      1) Full cleanup: we should free all resources of the query(like temp tables).
         This is done generally when the query execution is complete or the subquery
         re-execution is not needed (case with uncorrelated subquery)
      
      2) Partial cleanup: Minor cleanup that is required if
         the subquery needs recalculation. This is done for all the structures that
         need to be allocated for each execution (example SORT_INFO for filesort
         is allocated for each execution of the correlated subquery).
      
      The fix here would be free the cache used by rr_from_cache in the partial
      cleanup phase.
      1e31d748
  23. 08 Jul, 2020 1 commit
    • Varun Gupta's avatar
      MDEV-13694: Wrong result upon GROUP BY with orderby_uses_equalities=on · 7148b846
      Varun Gupta authored
      For the case when  the SJM scan table is the first table in the join order,
      then if we want to do the sorting on the SJM scan table, then we need to
      make sure that we unpack the values to base table fields in two cases:
          1) Reading the SJM table and writing the sort-keys inside the sort-buffer
          2) Reading the sorted data from the sort file
      7148b846
  24. 09 Jun, 2020 1 commit
  25. 25 May, 2020 1 commit
  26. 23 Mar, 2020 1 commit
  27. 10 Mar, 2020 1 commit