Bug #34758 Server crashes if database with views backed up using CS driver
Submitted: 22 Feb 2008 11:46 Modified: 11 Aug 2008 20:41
Reporter: Rafal Somla Email Updates:
Status: Closed Impact on me:
None 
Category:MySQL Server: Backup Severity:S2 (Serious)
Version:6.0.5 OS:Any
Assigned to: Jørgen Løland CPU Architecture:Any

[22 Feb 2008 11:46] Rafal Somla
Description:
The consistent snapshot backup driver crashes server if backing up a database which contains a view depending on another view. Here is a stack trace I obtained.

> #3  <signal handler called>
> #4  0x083722fd in JOIN::optimize (this=0x94411c8) at sql_select.cc:1522
> #5  0x08375f76 in mysql_select (thd=0x935cfd8, rref_pointer_array=0x9440840, tables=0x9440ed0, wild_num=0, 
>     fields=@0x94407d0, conds=0x0, og_num=0, order=0x0, group=0x0, having=0x0, proc_param=0x0, select_options=2417248768, 
>     result=0x9443b98, unit=0x94404b4, select_lex=0x944073c) at sql_select.cc:2929
> #6  0x08482a48 in mysql_derived_filling (thd=0x935cfd8, lex=0x935e084, orig_table_list=0x9440118) at sql_derived.cc:264
> #7  0x084827f3 in mysql_handle_derived (lex=0x935e084, 
>     processor=0x8482878 <mysql_derived_filling(THD*, st_lex*, TABLE_LIST*)>) at sql_derived.cc:56
> #8  0x0833dbef in open_and_lock_tables_derived (thd=0x935cfd8, tables=0x9420250, derived=true) at sql_base.cc:4886
> #9  0x082fbebe in open_and_lock_tables (thd=0x935cfd8, tables=0x9420250) at mysql_priv.h:1540
> #10 0x088d6e2d in snapshot_backup::Backup::get_data (this=0x93d6ce0, buf=@0x93dbd64) at be_snapshot.cc:105
> #11 0x088d1ff6 in backup::Backup_pump::pump (this=0x93dbd40, howmuch=0x44d4e01c) at data_backup.cc:1251
> #12 0x088d2d9f in backup::Scheduler::step (this=0x44d4e2d8) at data_backup.cc:761
> #13 0x088d3f71 in backup::write_table_data (thd=0x935cfd8, info=@0x44d4e40c, s=@0x938ec00) at data_backup.cc:670
> #14 0x088cbe97 in mysql_backup (thd=0x935cfd8, info=@0x44d4e40c, s=@0x938ec00) at kernel.cc:465
> #15 0x088cd227 in execute_backup_command (thd=0x935cfd8, lex=0x935e084) at kernel.cc:343

The crash happens in this place in sql_select.cc:

> 1519      /* Remove distinct if only const tables */
> 1520      select_distinct= select_distinct && (const_tables != tables);
> 1521      thd_proc_info(thd, "preparing");
> 1522      if (result->initialize_tables(this))
> 1523      {
> 1524        DBUG_PRINT("error",("Error: initialize_tables() failed"));

The pointers 'result' and 'this' are not NULL but apparently 'result' is a dangling pointer:

> (gdb) p *result
> $5 = {<Sql_alloc> = {<No data fields>}, _vptr.select_result = 0x8f8f8f8f, thd = 0x8f8f8f8f, unit = 0x8f8f8f8f}

This happens only if the CS driver is used in backup. If underlying table uses MyISAM engine so that the default backup driver is used, backup works correctly.

How to repeat:
Execute the following test case:

> --source include/have_innodb.inc
> 
> CREATE DATABASE db1;
>
> CREATE TABLE db1.t1(a int) ENGINE=INNODB;
> CREATE VIEW db1.v1 AS SELECT * FROM db1.t1;
> CREATE VIEW db1.v2 AS SELECT * FROM db1.v1;
>
> BACKUP DATABASE db1 TO 'test.bak';

The crash happens only if view v2 is defined. If its definition is commented-out, everything works fine.

Suggested fix:
No idea...
[19 May 2008 7:37] Philip Stoev
Falcon tables are also affected.
[20 May 2008 19:48] Lars Thalmann
Duplicate bug is BUG#35347.
[21 May 2008 9:40] Jørgen Løland
sql_select.cc#mysql_select is called on a derived table. For derived tables, result is not used in the join. The error happens in join->optimize because join->result is a dangling pointer in this case. 
Values on sql_select.cc:2889:
(gdb) p select_lex->linkage
$5 = DERIVED_TABLE_TYPE

(gdb) p *join->result
$11 = {<Sql_alloc> = {<No data fields>}, _vptr.select_result = 0x8f8f8f8f, 
  thd = 0x8f8f8f8f, unit = 0x8f8f8f8f}

with linkage DERIVED_TABLE_TYPE, the code block starting with 
2867> if (select_lex->linkage ...) 
is not executed.

#0  mysql_select (thd=0x9252068, rref_pointer_array=0x92e6e10, 
    tables=0x92e74a0, wild_num=0, fields=@0x92e6da0, conds=0x0, og_num=0, 
    order=0x0, group=0x0, having=0x0, proc_param=0x0, 
    select_options=2417248768, result=0x92ea168, unit=0x92e6a84, 
    select_lex=0x92e6d0c) at sql_select.cc:2889
#1  0x08490354 in mysql_derived_filling (thd=0x9252068, lex=0x925310c, 
    orig_table_list=0x92e66d0) at sql_derived.cc:264
#2  0x084900ff in mysql_handle_derived (lex=0x925310c, 
    processor=0x8490184 <mysql_derived_filling(THD*, st_lex*, TABLE_LIST*)>)
    at sql_derived.cc:56
#3  0x08334d22 in open_and_lock_tables_derived (thd=0x9252068, 
    tables=0x92b55f0, derived=true) at sql_base.cc:4807
#4  0x082f22a2 in open_and_lock_tables (thd=0x9252068, tables=0x92b55f0)
    at mysql_priv.h:1590
#5  0x088118e1 in snapshot_backup::Backup::get_data (this=0x92dde00, 
    buf=@0x92d6ac4) at be_snapshot.cc:106
#6  0x0880c890 in backup::Backup_pump::pump (this=0x92d6aa0, 
    howmuch=0xabe67cd4) at data_backup.cc:1261
#7  0x0880d63a in backup::Scheduler::step (this=0xabe67d38)
    at data_backup.cc:770
#8  0x0880e927 in backup::write_table_data (thd=0x9252068, info=@0x92cd5e8, 
    s=@0x92c3fd0) at data_backup.cc:679
#9  0x08806daa in Backup_restore_ctx::do_backup (this=0xabe680b4)
[29 May 2008 12:45] Jørgen Løland
When the CS driver opens tables, it currently uses mysql_priv.h#open_and_lock_tables. From the comments in mysql_priv.h, it seems that this method should be used to open derived tables whereas simple_open_n_lock_tables should be used to open non-derived tables. The following change seems to fix the bug:

sql/backup/be_snapshot.cc: 1.6 1.7 jl208045 08/05/20 20:34:41 (modified, needs delta)

@@ -103,7 +103,7 @@ result_t Backup::get_data(Buffer &buf)
   if (!tables_open && (locking_thd->lock_state == LOCK_ACQUIRED))
   {
     BACKUP_BREAKPOINT("backup_cs_open_tables");
-    open_and_lock_tables(locking_thd->m_thd, locking_thd->tables_in_backup);
+    simple_open_n_lock_tables(locking_thd->m_thd, locking_thd->tables_in_backup);
     tables_open= TRUE;
   }
   if (locking_thd->lock_state == LOCK_ACQUIRED)
[30 May 2008 14:35] Jørgen Løland
I think v1 is in the table list by mistake. Single-stepping in gdb reveals this:

#called by this line in sql_base.cc:
#  if (derived &&
#      (mysql_handle_derived(thd->lex, &mysql_derived_prepare) ||
#       (thd->fill_derived_tables() &&
#        mysql_handle_derived(thd->lex, &mysql_derived_filling))))

mysql_handle_derived (lex=0x925317c, 
    processor=0x84903b4 <mysql_derived_prepare(THD*, st_lex*, TABLE_LIST*)>)
    at sql_derived.cc:44
44        bool res= FALSE;
45        if (lex->derived_tables)
47          lex->thd->derived_tables_processing= TRUE;
48          for (SELECT_LEX *sl= lex->all_selects_list;
52            for (TABLE_LIST *cursor= sl->get_table_list();
56              if ((res= (*processor)(lex->thd, lex, cursor)))                             //p *cursor -> db1.t1
52            for (TABLE_LIST *cursor= sl->get_table_list();
59            if (lex->describe)
48          for (SELECT_LEX *sl= lex->all_selects_list;
52            for (TABLE_LIST *cursor= sl->get_table_list();
56              if ((res= (*processor)(lex->thd, lex, cursor)))                             //p *cursor -> db1.v1 NOTE THIS!
52            for (TABLE_LIST *cursor= sl->get_table_list();
59            if (lex->describe)
48          for (SELECT_LEX *sl= lex->all_selects_list;
52            for (TABLE_LIST *cursor= sl->get_table_list();
56              if ((res= (*processor)(lex->thd, lex, cursor)))                             //p *cursor -> db1.t1
52            for (TABLE_LIST *cursor= sl->get_table_list();
59            if (lex->describe)
48          for (SELECT_LEX *sl= lex->all_selects_list;
52            for (TABLE_LIST *cursor= sl->get_table_list();
59            if (lex->describe)
48          for (SELECT_LEX *sl= lex->all_selects_list;
71        lex->thd->derived_tables_processing= FALSE;
72        return res;

Then, when mysql_handle_derived is called with ...filling function pointer:
mysql_handle_derived (lex=0x925317c, 
    processor=0x84903b4 <mysql_derived_fill(THD*, st_lex*, TABLE_LIST*)>)
    at sql_derived.cc:44
44        bool res= FALSE;
45        if (lex->derived_tables)
47          lex->thd->derived_tables_processing= TRUE;
48          for (SELECT_LEX *sl= lex->all_selects_list;
52            for (TABLE_LIST *cursor= sl->get_table_list();
56              if ((res= (*processor)(lex->thd, lex, cursor)))                             //p *cursor -> db1.t1
52            for (TABLE_LIST *cursor= sl->get_table_list();
59            if (lex->describe)
48          for (SELECT_LEX *sl= lex->all_selects_list;
52            for (TABLE_LIST *cursor= sl->get_table_list();
56              if ((res= (*processor)(lex->thd, lex, cursor)))                             //p *cursor -> db1.v1 
#        (gdb) n -> ########## krasj ############

So the question is - why is v1 in the table list? Needs further digging
[2 Jun 2008 8:40] Jørgen Løland
The method st_lex::cleanup_after_one_table_open() (in sql_lex.cc) needs to be called between consecutive calls to open_and_lock_tables in the same transaction: "... It is necessary to clear thd->lex->derived_tables flag to prevent processing of derived tables during next open_and_lock_tables if next table is a real table". This is exactly what happens - the call to open_and_lock_tables tries to process the views that are in the select_lex of the backup transaction due to the write_preamble call in kernel.cc#do_backup.

Suggested fix:
cleanup the lex before calling open_and_lock_tables. Doing so makes the test case complete successfully. Restore then fails due to the same reason, but using the suggest fix also removes this bug.
[3 Jun 2008 9:47] Bugs System
A patch for this bug has been committed. After review, it may
be pushed to the relevant source trees for release in the next
version. You can access the patch from:

  http://lists.mysql.com/commits/47343

2626 Jorgen Loland	2008-06-03
      Bug#34758 "Server crashes if database with views backed up using CS driver"
      
      Cleanup lex before consecutive calls to open_and_lock_tables for backup and restore. Fixed this bug and a similar, unreported bug in restore.
      
      Detailed description:
      - st_lex::cleanup_after_one_table_open() needs to be called between consecutive calls to open_and_lock_tables to prevent processing of previously opened views.
      - added cleanup_after_one_table_open before call to open_and_lock_tables in do_backup.
      - fixed a similar bug in restore by applying the same fix in do_restore
[3 Jun 2008 11:14] Jørgen Løland
The patch passed all backup tests
[3 Jun 2008 16:09] Chuck Bell
Patch approved. See minor question in commit response email.
[4 Jun 2008 8:41] Bugs System
A patch for this bug has been committed. After review, it may
be pushed to the relevant source trees for release in the next
version. You can access the patch from:

  http://lists.mysql.com/commits/47402

2627 Jorgen Loland	2008-06-04
      Bug#34758 "Server crashes if database with views backed up using CS driver"
      
      Cleanup lex before consecutive calls to open_and_lock_tables for backup and restore. Fixed this bug and a similar, unreported bug in restore.
      
      Detailed description:
      - st_lex::cleanup_after_one_table_open() needs to be called between consecutive calls to open_and_lock_tables to prevent processing of previously opened views.
      - added cleanup_after_one_table_open before call to open_and_lock_tables in do_backup.
      - fixed a similar bug in restore by applying the same fix in do_restore
      - includes a test case that fails without the patch
[4 Jun 2008 12:49] Øystein Grøvlen
Patch approved.
Verified that supplied test fails without fix, but succeeds with the fix.
[4 Jun 2008 14:36] Bugs System
A patch for this bug has been committed. After review, it may
be pushed to the relevant source trees for release in the next
version. You can access the patch from:

  http://lists.mysql.com/commits/47444

2628 Jorgen Loland	2008-06-04
      Bug#34758 "Server crashes if database with views backed up using CS driver"
      
      Cleanup lex before consecutive calls to open_and_lock_tables for backup and restore. Fixed this bug and a similar, unreported bug in restore.
      
      Detailed description:
      - st_lex::cleanup_after_one_table_open() needs to be called between consecutive calls to open_and_lock_tables to prevent processing of previously opened views.
      - added cleanup_after_one_table_open before call to open_and_lock_tables in do_backup.
      - fixed a similar bug in restore by applying the same fix in do_restore
      - includes a test case that fails without the patch
[4 Jun 2008 14:38] Bugs System
A patch for this bug has been committed. After review, it may
be pushed to the relevant source trees for release in the next
version. You can access the patch from:

  http://lists.mysql.com/commits/47445

2629 Jorgen Loland	2008-06-04 [merge]
      Trying to reattach commit message:
      Bug#34758 "Server crashes if database with views backed up using CS driver"
            
      Cleanup lex before consecutive calls to open_and_lock_tables for backup and restore. Fixed this bug and a similar, unreported bug in restore.
            
      Detailed description:
      - st_lex::cleanup_after_one_table_open() needs to be called between consecutive calls to open_and_lock_tables to prevent processing of previously opened views.
      - added cleanup_after_one_table_open before call to open_and_lock_tables in do_backup.
      - fixed a similar bug in restore by applying the same fix in do_restore
      - includes a test case that fails without the patch

-- 
MySQL Code Commits Mailing List
For list archives: http://lists.mysql.com/commits
To unsubscribe:    http://lists.mysql.com/commits?unsub=commits@bugs.mysql.com
[4 Jun 2008 14:40] Bugs System
A patch for this bug has been committed. After review, it may
be pushed to the relevant source trees for release in the next
version. You can access the patch from:

  http://lists.mysql.com/commits/47446

2629 Jorgen Loland	2008-06-04 [merge]
      Trying to reattach commit message:
      Bug#34758 "Server crashes if database with views backed up using CS driver"
            
      Cleanup lex before consecutive calls to open_and_lock_tables for backup and restore. Fixed this bug and a similar, unreported bug in restore.
            
      Detailed description:
      - st_lex::cleanup_after_one_table_open() needs to be called between consecutive calls to open_and_lock_tables to prevent processing of previously opened views.
      - added cleanup_after_one_table_open before call to open_and_lock_tables in do_backup.
      - fixed a similar bug in restore by applying the same fix in do_restore
      - includes a test case that fails without the patch

-- 
MySQL Code Commits Mailing List
For list archives: http://lists.mysql.com/commits
To unsubscribe:    http://lists.mysql.com/commits?unsub=commits@bugs.mysql.com
[5 Jun 2008 12:35] Bugs System
A patch for this bug has been committed. After review, it may
be pushed to the relevant source trees for release in the next
version. You can access the patch from:

  http://lists.mysql.com/commits/47475

2631 Jorgen Loland	2008-06-05
      Bug#34758 - "Server crashes if database with views backed up using CS driver"
      
      Test fix followup.
      
      The backup_id in the test result file does not always match the actual number. Replacing the backup_id with '#' to make test pass
[5 Jun 2008 12:37] Bugs System
A patch for this bug has been committed. After review, it may
be pushed to the relevant source trees for release in the next
version. You can access the patch from:

  http://lists.mysql.com/commits/47476

2631 Jorgen Loland	2008-06-05
      Bug#34758 - "Server crashes if database with views backed up using CS driver"
      
      Test fix followup.
      
      The backup_id in the test result file does not always match the actual number. Replacing the backup_id with '#' to make test pass
[5 Aug 2008 15:47] Bugs System
A patch for this bug has been committed. After review, it may
be pushed to the relevant source trees for release in the next
version. You can access the patch from:

  http://lists.mysql.com/commits/50947

2675 Hema Sridharan	2008-08-05
      Modified backup_views.test and result file as bug#34758 is fixed.
[8 Aug 2008 15:38] Paul DuBois
Fix is pushed in 6.0.7.
[11 Aug 2008 20:41] Paul DuBois
Noted in 6.0.7 changelog.

BACKUP DATABASE caused a server crash if it attempted to back up a
view that depended on another view.
[8 Sep 2008 11:33] Sergey Vojtovich
BUG#37354 was marked as duplicate.
[13 Sep 2008 20:19] Bugs System
Pushed into 6.0.6-alpha  (revid:jorgen.loland@sun.com-20080604143859-srnnku60nbiddsyp) (version source revid:sergefp@mysql.com-20080611231653-nmuqmw6dedjra79i) (pib:3)
[3 Nov 2008 16:19] Rafal Somla
There is a comment in backup_objects test, requesting test modification when this bug is fixed. This should be done as a follow-up on this fix.
[26 Aug 2009 16:15] Hema Sridharan
backup_objects.test has been modified now to use InnoDB as default storage engine.