1. 19 Jan, 2022 3 commits
    • Dmitry Shulga's avatar
      MDEV-24827: MariaDB 10.5.5 crash (sig 11) during a SELECT · 810ef911
      Dmitry Shulga authored
      Running a query using cursor could lead to a server crash on
      building a temporary table used for handling the query.
      
      For example, the following cursor
      
      DECLARE cur1 CURSOR FOR
        SELECT t2.c1 AS c1 FROM t1 LEFT JOIN t2 ON t1.c1 = t2.c1
        WHERE EXISTS (SELECT 1 FROM t1 WHERE c2 = -1) ORDER BY c1;
      
      declared and executed inside a stored routine could result in server
      crash on creating a temporary table used for handling the ORDER BY clause.
      
      Crash occurred on attempt to create the temporary table's fields based
      on fields whose data located in a memory root that already freed.
      
      It happens inside the function return_zero_rows() where the method
      Select_materialize::send_result_set_metadata() is invoked for cursor case.
      This method calls the st_select_lex_unit::get_column_types() in order to
      get a list of items with types of columns for the temporary table being created.
      The method st_select_lex_unit::get_column_types() returns
        first_select()->join->fields
      in case it is invoked for a cursor. Unfortunately, this memory has been already
      deallocated bit earlier by calling
        join->join_free();
      inside the function return_zero_rows().
      
      In case the query listed in the example is run in conventional way (without
      using cursor) the method st_select_lex_unit::get_column_types()
      returns first_select()->item_list that is not touched by invocation
      of the method join->join_free() so everything is fine for that.
      
      So, to fix the issue the resources allocated for the JOIN class should be
      released after any activities with the JOIN class has been completed,
      that is as the last statement before returning from the function
      return_zero_rows().
      
      This patch includes tests both for the case when a cursor is run explicitly
      from within a stored routine and for the case when a cursor is opened
      implicitly as prescribed by the STMT_ATTR_CURSOR_TYPE attribute of
      binary protocol (the case of prepared statement).
      810ef911
    • Anel Husakovic's avatar
      MDEV-18284: JSON casting using JSON_COMPACT doesn't always work with values from subqueries · 9cd6ecfe
      Anel Husakovic authored
      - Cherry-pick 2fcff310 (MDEV-21902)
      - Closed PR #1145
      Reviewed by: holyfoot@mariadb.com
      9cd6ecfe
    • Daniel Black's avatar
      MDEV-27467: innodb to enforce the minimum innodb_buffer_pool_size in SET GLOBAL · 410c4ede
      Daniel Black authored
      .. to be the same as startup.
      
      In resolving MDEV-27461, BUF_LRU_MIN_LEN (256) is the minimum number of
      pages for the innodb buffer pool size. Obviously we need more than just
      flushing pages. Taking the 16k page size and its default minimum, an
      extra 25% is needed on top of the flushing pages to make a workable buffer
      pool.
      
      The minimum innodb_buffer_pool_chunk_size (1M) restricts the minimum
      otherwise we'd have a pool made up of different chunk sizes.
      
      The resulting minimum innodb buffer pool sizes are:
      
      Page Size, Previously minimum (startup), with change.
              4k                            5M           2M
              8k                            5M           3M
             16k                            5M           5M
             32k                           24M          10M
             64k                           24M          20M
      
      With this patch, SET GLOBAL innodb_buffer_pool_size minimums are
      enforced.
      
      The evident minimum system variable size for innodb_buffer_pool_size
      is 2M, however this is only setable if using 4k page size. As
      the order of the page_size and buffer_pool_size aren't fixed, we can't
      hide this change.
      
      Subsequent changes:
      * innodb_buffer_pool_resize_with_chunks.test - raised of pool resize due to new
        minimums. Chunk size also needed increase as the test was for
        pool_size < chunk_size to generate a warning.
      * Removed srv_buf_pool_min_size and replaced use with MYSQL_SYSVAR_NAME(buffer_pool_size).min_val
      * Removed srv_buf_pool_def_size and replaced constant defination in
        MYSQL_SYSVAR_LONGLONG(buffer_pool_size)
      * Reordered ha_innodb to allow for direct use of MYSQL_SYSVAR_NAME(buffer_pool_size).min_val
      * Moved buf_pool_size_align into ha_innodb to access to MYSQL_SYSVAR_NAME(buffer_pool_size).min_val
      * loose-innodb_disable_resize_buffer_pool_debug is needed in the
        innodb.restart.opt test so that under debug mode, resizing of the
        innodb buffer pool can occur.
      410c4ede
  2. 18 Jan, 2022 2 commits
  3. 17 Jan, 2022 1 commit
  4. 14 Jan, 2022 5 commits
  5. 11 Jan, 2022 7 commits
    • Vladislav Vaintroub's avatar
      MDEV-21252 ER_HOST_IS_BLOCKED returns packet sequence 1 instead of 0 · a3267c11
      Vladislav Vaintroub authored
      Fix regression introduced in MDEV-19893
      
      Some errors must be sent with seqno = 0, e.g those that are detected
      before server sends its first "welcome" packet (e.g too many connections)
      This was not taken into account originally in MDEV-19893 fix.
      
      We need to check sql_errno, before fixing sequence number, to see
      if the error we send is really an out-of-bound, e.g a KILL.
      a3267c11
    • Jan Lindström's avatar
      MDEV-25201 : Assertion `thd->wsrep_trx_meta.gtid.seqno == (-1)' failed in int... · a38b937b
      Jan Lindström authored
      MDEV-25201 : Assertion `thd->wsrep_trx_meta.gtid.seqno == (-1)' failed in int wsrep_to_isolation_begin(THD*, const char*, const char*, const TABLE_LIST*, Alter_info*)
      
      Test case does not assert anymore but works incorrectly. We should
      not replicate PREPARE using TOI.
      a38b937b
    • Jan Lindström's avatar
      Changing wsrep_slave_threads parameter requires that cluster · e32c21cb
      Jan Lindström authored
      is connected so moved test here.
      e32c21cb
    • Jan Lindström's avatar
      MDEV-25549 : Assertion `*new_engine' failed in bool check_engine(THD*, const... · ce415be2
      Jan Lindström authored
      MDEV-25549 : Assertion `*new_engine' failed in bool check_engine(THD*, const char*, const char*, HA_CREATE_INFO*)
      
      In Galera case we call check_engine that could set create_info->db_type
      to NULL e.g. if TEMPORARY is not supported by storage engine. Thus,
      we need to restore it after that call because it is needed later
      on mysql_create_table that will also call check_engine.
      ce415be2
    • Jan Lindström's avatar
      MDEV-25856 : SIGSEGV in ha_myisammrg::append_create_info · c430f612
      Jan Lindström authored
      For MERGE-tables we need to init children list before calling
      show_create_table and then detach children before we continue
      normal mysql_create_like_table execution.
      c430f612
    • Jan Lindström's avatar
      MDEV-25472 : Server crashes when wsrep_cluster_address set to unkown address... · d0ca2415
      Jan Lindström authored
      MDEV-25472 : Server crashes when wsrep_cluster_address set to unkown address and wsrep_slave_threads to 0
      
      Return failure if we are not connected when slave threads are set
      d0ca2415
    • Dmitry Shulga's avatar
      MDEV-20325: Assertion `outer_context || !*from_field || *from_field ==... · 89c870b2
      Dmitry Shulga authored
      MDEV-20325: Assertion `outer_context || !*from_field || *from_field == not_found_field' failed in Item_field::fix_outer_field | `!derived->is_excluded()' failed in TABLE_LIST::set_check_materialized | SIGEGV in st_select_lex::mark_as_dependent (optimized builds)
      
      Re-execution of a query containing subquery in the FROM clause results
      in assert failure in case the query is run as part of a stored routine or
      as a prepared statement AND derived table merge optimization is off.
      As an example, the following test case
        CREATE TABLE t1 (a INT) ;
        CREATE PROCEDURE sp() SELECT * FROM (SELECT a FROM t1) tb;
        CALL sp();
        SET optimizer_switch='derived_merge=off';
        CALL sp();
      results in assert failure on the second invocation of the 'sp' stored routine.
      
      The reason for assertion failure is that the expression
        derived->is_excluded()
      returns the value true where the value false expected.
      
      The method is_excluded() returns the value true for a derived table
      that has been merged to a parent select. Such transformation happens as part
      of Derived Table Merge Optimization that is performed on first invocation of
      a stored routine or a prepared statement containing a query with subquery
      in the FROM clause of the main SELECT.
      
      When the same routine or prepared statement is run the second time and
      Derived Table Merge Optimization is OFF the MariaDB server tries to materialize
      a derived table specified by the subquery that fails since this subquery
      has already been merged to the top-most SELECT. This transformation is permanent
      and can't be reverted. That is the reason why the assert
        DBUG_ASSERT(!derived->is_excluded());
      fails inside the function TABLE_LIST::set_check_materialized().
      
      Similar behaviour can be observed in case a stored routine or prepared statement
      containing a SELECT statement with subquery in the FROM clause, first is run
      with the optimizer_switch option set to derived_merge=off and re-run after this
      option has been switched to derived_merge=on. In this case a derived table for
      subquery is materialized on the first execution and marked as merged derived
      table on the second execution that results in error with misleading error
      message:
      
      MariaDB [test]> CALL sp1();
      ERROR 1030 (HY000): Got error 1 "Operation not permitted" from storage engine MEMORY
      
      To fix the issue, a derived table that has been already optimized shouldn't be
      re-marked for one more round of optimization.
      
      One significant consequence following from suggested change is that the data
      member TABLE_LIST::derived_type is not updated once the table optimization
      has been done. This fact should be taken into account when Prepared Statement
      being handled since once a table listed in a query has been optimized on
      execution of the statement PREPARE FROM it won't be touched anymore on handling
      the statement EXECUTE.
      
      One side effect caused by this change could be observed for the following
      test case:
        CREATE TABLE t1 (s1 INT);
        CREATE VIEW v1 AS
          SELECT s1,s2 FROM (SELECT s1 as s2 FROM t1 WHERE s1 <100) x, t1 WHERE t1.s1=x.s2;
        INSERT INTO v1 (s1) VALUES (-300);
      
        PREPARE stmt FROM "INSERT INTO v1 (s1) VALUES (-300)";
        EXECUTE stmt;
      
      Execution of the above EXECUTE statement results in issuing the error
      ER_COLUMNACCESS_DENIED_ERROR since table_ref->is_merged_derived() is false
      and check_column_grant_in_table_ref() called for a temporary table that
      shouldn't be. To fix this issue the function find_field_in_tables has been
      modified in such a way that the function check_column_grant_in_table_ref()
      is not called for a temporary table.
      89c870b2
  6. 10 Jan, 2022 3 commits
    • Igor Babaev's avatar
      MDEV-25631 Crash executing query with VIEW, aggregate and subquery · 7692cec5
      Igor Babaev authored
      This bug could cause a crash of the server for queries with a derived table
      whose specification contained the set function using a subquery over a view
      as its only argument. The crash could happen if the specification of the
      view contained an outer reference. In this case the aggregation select
      could be determined incorrectly.
      The crash also could be observed if a CTE is used instead of the view, but
      only for queries having at least two references to the CTE.
      7692cec5
    • Igor Babaev's avatar
      MDEV-25086 Stored Procedure Crashes Server · 6dec0332
      Igor Babaev authored
      The cause of this bug is the same as of the bug MDEV-24454.
      This bug manifested itself at the second execution of the queries that
      contained a set function whose only argument was outer reference to
      a column of a mergeable view or derived table or CTE. The first execution
      of such query worked fine, but the second execution of the query caused
      a crash of the server because the aggregation select for the used set
      function was determined incorrectly at the name resolution phase of the
      second execution.
      6dec0332
    • Igor Babaev's avatar
      Revert "MDEV-24454 Crash at change_item_tree" · d6ee351b
      Igor Babaev authored
      This patch reverts the fixes of the bugs MDEV-24454 and MDEV-25631 from
      the commit 3690c549.
      It leaves the changes in plugin/feedback/feedback.cc and corresponding
      test files introduced in this commit intact.
      
      Proper fixes for the bug MDEV-24454 and MDEV-25631 will follow immediately.
      d6ee351b
  7. 09 Jan, 2022 2 commits
  8. 08 Jan, 2022 2 commits
  9. 07 Jan, 2022 2 commits
  10. 04 Jan, 2022 1 commit
    • Brandon Nesterenko's avatar
      MDEV-16091: Seconds_Behind_Master spikes to millions of seconds · 96de6bfd
      Brandon Nesterenko authored
      Problem:
      ========
      A slave’s relay log format description event is used when
      calculating Seconds_Behind_Master (SBM). This forces the SBM
      value to spike when processing these events, as their creation
      date is set to the timestamp that the IO thread begins.
      
      Solution:
      ========
      When the slave generates a format description event, mark the
      event as a relay log event so it does not update the
      rli->last_master_timestamp variable.
      
      Reviewed By:
      ============
      Andrei Elkin <andrei.elkin@mariadb.com>
      96de6bfd
  11. 03 Jan, 2022 1 commit
    • Rucha Deodhar's avatar
      MDEV-26698: Incorrect row number upon INSERT .. SELECT from the same · 452c9a4d
      Rucha Deodhar authored
      table: rows are counted twice
      
      Analysis: When the table we are trying to insert into and the SELECT table
      are same for INSERT ... SELECT, rows from the SELECT table are copied into
      internal temporary table and then to the INSERT table. We only want to
      count the rows when we start inserting into the table.
      Fix: Reset the counter to 1 before starting to copy from internal temporary
      table to select table and then increment the counter.
      452c9a4d
  12. 30 Dec, 2021 1 commit
    • Daniel Black's avatar
      MDEV-27386: cpack rpm libsepol installed detects verison incorrectly · 5d57e04b
      Daniel Black authored
      ... when two packages are installed.
      
      (fc35 with i686 and x86_64 packages of libsepol installed).
      $ rpm -q --qf "%{VERSION}" libsepol
      3.33.3
      
      Restricting the version to the current achitecture generates
      a much more obtainable version dependency.
      
      $ rpm -q --qf "%{VERSION}" libsepol.x86_64
      3.3
      
      This make dependency resolution easier preventing:
      $ sudo dnf localinstall  MariaDB-server-10.8.0-1.fc35.x86_64.rpm ...
      Last metadata expiration check: 2:06:49 ago on Thu 30 Dec 2021 14:02:32.
      Error:
       Problem 1: conflicting requests
        - nothing provides libsepol >= 3.33.3 needed by MariaDB-server-10.8.0-1.fc35.x86_64
      
      The CMAKE_SYSTEM_PROCESSOR is used in the generation of architecture
      filenames so its preduent to just use the same version.
      5d57e04b
  13. 29 Dec, 2021 2 commits
  14. 28 Dec, 2021 1 commit
    • Rucha Deodhar's avatar
      MDEV-25460: Assertion `!is_set() || (m_status == DA_OK_BULK && is_bulk_op())' · fad1d153
      Rucha Deodhar authored
      failed in Diagnostics_area::set_ok_status in my_ok from
      mysql_sql_stmt_prepare
      
      Analysis: Before PREPARE is executed, binlog_format is STATEMENT.
      This PREPARE had SET STATEMENT which sets binlog_format to ROW. Now after
      PREPARE is done we reset the binlog_format (back to STATEMENT). But we have
      temporary table, it doesn't let changing binlog_format=ROW to
      binlog_format=STATEMENT and gives error which goes unreported. This
      unreported error eventually causes assertion failure.
      Fix: Change return type for LEX::restore_set_statement_var() to bool and
      make it return error state.
      fad1d153
  15. 27 Dec, 2021 1 commit
  16. 24 Dec, 2021 1 commit
    • Igor Babaev's avatar
      MDEV-27262 Unexpected index intersection with full index scan for an index · 42fea34d
      Igor Babaev authored
      If when extracting a range condition for an index from the WHERE condition
      Range Optimizer sees that the range condition covers the whole index then
      such condition should be discarded because it cannot be used in any range
      scan. In some cases Range Optimizer really does it, but there remained some
      conditions for which it was not done. As a result the optimizer could
      produce index merge plans with the full index scan for one of the indexes
      participating in the index merge.
      This could be observed in one of the test cases from index_merge1.inc
      where a plan with index_merge_sort_union was produced and in the test case
      reported for this bug where a plan with index_merge_sort_intersect was
      produced. In both cases one of two index scans participating in index merge
      ran over the whole index.
      The patch slightly changes the original above mentioned test case from
      index_merge1.inc to be able to produce an intended plan employing
      index_merge_sort_union. The original query was left to show that index
      merge is not used for it anymore.
      It should be noted that for the plan with index_merge_sort_intersect could
      be chosen for execution only due to a defect in the InnoDB code that
      returns wrong estimates for the cardinality of big ranges.
      
      This bug led to serious problems in 10.4+ where the optimization using
      Rowid filters is employed (see mdev-26446).
      
      Approved by Sergey Petrunia <sergey@mariadb.com>
      42fea34d
  17. 23 Dec, 2021 1 commit
    • Julius Goryavsky's avatar
      MDEV-24097: galera[_3nodes] suite tests in MTR sporadically fails · b5cbe506
      Julius Goryavsky authored
      This is the first part of the fixes for MDEV-24097. This commit
      contains the fixes for instability when testing Galera and when
      restarting nodes quickly:
      
      1) Protection against a "stuck" old SST process during the execution
         of the new SST (after restarting the node) is now implemented for
         mariabackup / xtrabackup, which should help to avoid almost all
         conflicts due to the use of the same ports - both during testing
         with mtr, so and when restarting nodes quickly in a production
         environment.
      2) Added more protection to scripts against unexpected return of
         the rc != 0 (in the commands for deleting temporary files, etc).
      3) Added protection against unexpected crashes during binlog transfer
         (in SST scripts for rsync).
      4) Spaces and some special characters in binlog filenames shouldn't
         be a problem now (at the script level).
      5) Daemon process termination tracking has been made more robust
         against crashes due to unexpected termination of the previous SST
         process while new scripts are running.
      6) Reading ssl encryption parameters has been moved from specific
         SST scripts to a common wsrep_sst_common.sh script, which allows
         unified error handling, unified diagnostics and simplifies script
         revisions in the future.
      7) Improved diagnostics of errors related to the use of openssl.
      8) Corrections have been made for xtrabackup-v2 (both in tests and in
         the script code) that restore the work of xtrabackup with updated
         versions of innodb.
      9) Fixed some tests for galera_3nodes, although the complete solution
         for the problem of starting three nodes at the same time on fast
         machines will be done in a separate commit.
      
      No additional tests are required as this commit fixes problems with
      existing tests.
      b5cbe506
  18. 22 Dec, 2021 1 commit
    • Daniel Black's avatar
      MDEV-23175: my_timer_milliseconds clock_gettime for multiple platfomrs · 12087d67
      Daniel Black authored
      Small postfix to MDEV-23175 to ensure faster option on FreeBSD
      and compatibility to Solaris that isn't high resolution.
      
      ftime is left as a backup in case an implementation doesn't
      contain any of these clocks.
      
      FreeBSD
          $ ./unittest/mysys/my_rdtsc-t
          1..11
          # ----- Routine ---------------
          # myt.cycles.routine          :             5
          # myt.nanoseconds.routine     :            11
          # myt.microseconds.routine    :            13
          # myt.milliseconds.routine    :            11
          # myt.ticks.routine           :            17
          # ----- Frequency -------------
          # myt.cycles.frequency        :    3610295566
          # myt.nanoseconds.frequency   :    1000000000
          # myt.microseconds.frequency  :       1000000
          # myt.milliseconds.frequency  :           899
          # myt.ticks.frequency         :           136
          # ----- Resolution ------------
          # myt.cycles.resolution       :             1
          # myt.nanoseconds.resolution  :             1
          # myt.microseconds.resolution :             1
          # myt.milliseconds.resolution :             7
          # myt.ticks.resolution        :             1
          # ----- Overhead --------------
          # myt.cycles.overhead         :            26
          # myt.nanoseconds.overhead    :         19140
          # myt.microseconds.overhead   :         19036
          # myt.milliseconds.overhead   :           578
          # myt.ticks.overhead          :         21544
          ok 1 - my_timer_init() did not crash
          ok 2 - The cycle timer is strictly increasing
          ok 3 - The cycle timer is implemented
          ok 4 - The nanosecond timer is increasing
          ok 5 - The nanosecond timer is implemented
          ok 6 - The microsecond timer is increasing
          ok 7 - The microsecond timer is implemented
          ok 8 - The millisecond timer is increasing
          ok 9 - The millisecond timer is implemented
          ok 10 - The tick timer is increasing
          ok 11 - The tick timer is implemented
      12087d67
  19. 17 Dec, 2021 1 commit
  20. 16 Dec, 2021 1 commit
    • Dmitry Shulga's avatar
      MDEV-21866: Assertion `!result' failed in convert_const_to_int upon 2nd execution of PS · fff8ac2e
      Dmitry Shulga authored
      Consider the following use case:
      MariaDB [test]> CREATE TABLE t1 (field1 BIGINT DEFAULT -1);
      MariaDB [test]> CREATE VIEW v1 AS SELECT DISTINCT field1 FROM t1;
      
      Repeated execution of the following query as a Prepared Statement
      
      MariaDB [test]> PREPARE stmt FROM 'SELECT * FROM v1 WHERE field1 <=> NULL';
      MariaDB [test]> EXECUTE stmt;
      
      results in a crash for a server built with DEBUG.
      
      MariaDB [test]> EXECUTE stmt;
      ERROR 2013 (HY000): Lost connection to MySQL server during query
      
      Assertion failed: (!result), function convert_const_to_int, file item_cmpfunc.cc, line 476.
      Abort trap: 6 (core dumped)
      
      The crash inside the function convert_const_to_int() happens by the reason
      that the value -1 is stored in an instance of the class Field_longlong
      on restoring its original value in the statement
        result= field->store(orig_field_val, TRUE);
      that leads to assigning the value 1 to the variable 'result' with subsequent
      crash in the DBUG_ASSERT statement following it
        DBUG_ASSERT(!result);
      
      The main matter here is why this assertion failure happens on the second
      execution of the prepared statement and doens't on the first one.
      On first handling of the statement
        'EXECUTE stmt;'
      a temporary table is created for serving the query involving the view 'v1'.
      The table is created by the function create_tmp_table() in the following
      calls trace: (trace #1)
        JOIN::prepare (at sql_select.cc:725)
          st_select_lex::handle_derived
            LEX::handle_list_of_derived
              TABLE_LIST::handle_derived
                mysql_handle_single_derived
                  mysql_derived_prepare
                    select_union::create_result_table
                      create_tmp_table
      
      Note, that the data member TABLE::status of a TABLE instance returned by the
      function create_tmp_table() has the value 0.
      
      Later the function setup_table_map() is called on the TABLE instance just
      created for the sake of the temporary table (calls trace #2 is below):
        JOIN::prepare (at sql_select.cc:737)
          setup_tables_and_check_access
            setup_tables
              setup_table_map
      where the data member TABLE::status is set to the value STATUS_NO_RECORD.
      
      After that when execution of the method JOIN::prepare reaches calling of
      the function setup_without_group() the following calls trace is invoked
        JOIN::prepare
          setup_without_group
            setup_conds
              Item_func::fix_fields
                Item_func_equal::fix_length_and_dec
                  Item_bool_rowready_func2::fix_length_and_dec
                    Item_func::setup_args_and_comparator
                      Item_func::convert_const_compared_to_int_field
                        convert_const_to_int
      
      There is the following code snippet in the function convert_const_to_int()
      at the line item_cmpfunc.cc:448
          bool save_field_value= (field_item->const_item() ||
                                  !(field->table->status & STATUS_NO_RECORD));
      Since field->table->status has bits STATUS_NO_RECORD set the variable
      save_field_value is false and therefore neither the method
      Field_longlong::val_int() nor the method Field_longlong::store is called
      on the Field instance that has the numeric value -1.
      That is the reason why first execution of the Prepared Statement for the query
        'SELECT * FROM v1 WHERE field1 <=> NULL'
      is successful.
      
      On second running of the statement 'EXECUTE stmt' a new temporary tables
      is also created by running the calls trace #1 but the trace #2 is not executed
      by the reason that data member SELECT_LEX::first_cond_optimization has been set
      to false on first execution of the prepared statemet (in the method
      JOIN::optimize_inner()). As a consequence, the data member TABLE::status for
      a temporary table just created doesn't have the flags STATUS_NO_RECORD set and
      therefore on re-execution of the prepared statement the methods
      Field_longlong::val_int() and Field_longlong::store() are called for the field
      having the value -1 and the DBUG_ASSERT(!result) is fired.
      
      To fix the issue the data member TABLE::status has to be assigned the value
      STATUS_NO_RECORD in every place where the macros empty_record() is called
      to emptify a record for just instantiated TABLE object created on behalf
      the new temporary table.
      fff8ac2e
  21. 15 Dec, 2021 1 commit