Bug #4681 mysql-test-run fails 'union' test on Solaris x86 with Forte compiler
Submitted: 21 Jul 2004 18:32 Modified: 30 Aug 2004 10:34
Reporter: Alan Burlison Email Updates:
Status: Closed Impact on me:
None 
Category:MySQL Server: Installing Severity:S2 (Serious)
Version:4.0.20 OS:Solaris (Solaris 10)
Assigned to: Sergei Golubchik CPU Architecture:Any

[21 Jul 2004 18:32] Alan Burlison
Description:
OS: Solaris 10 build 63, x86 (Opteron)
Compiler: Sun C 5.5 Patch 112761-06 2004/01/13

The 'union' test fails with the following errors.  I suspect this is some sort of 32 bit signed/unsigned wraparound problem as, for example in the first test failure,  -4294967288 = -2^32 + 8, where 8 is the expected row count.

----------
Errors are (from /home1/mysql/mysql-test/var/log/mysqltest-time) :
/home1/mysql/bin/mysqltest: At line 239: Result length mismatch
(the last line(s) may be the ones that caused the die() in mysqltest)
Below are the diffs between actual and expected results:
-------------------------------------------------------
*** r/union.result	Wed Jul 21 17:00:23 2004
--- r/union.reject	Wed Jul 21 17:41:08 2004
***************
*** 102,108 ****
  2	b
  select found_rows();
  found_rows()
! 8
  explain select a,b from t1 union all select a,b from t2;
  table	type	possible_keys	key	key_len	ref	rows	Extra
  t1	ALL	NULL	NULL	NULL	NULL	4	
--- 102,108 ----
  2	b
  select found_rows();
  found_rows()
! -4294967288
  explain select a,b from t1 union all select a,b from t2;
  table	type	possible_keys	key	key_len	ref	rows	Extra
  t1	ALL	NULL	NULL	NULL	NULL	4	
***************
*** 335,341 ****
  1
  select found_rows();
  found_rows()
! 4
  SELECT SQL_CALC_FOUND_ROWS * FROM t1 LIMIT 1 UNION all SELECT * FROM t2 LIMIT 2;
  a
  1
--- 335,341 ----
  1
  select found_rows();
  found_rows()
! -4294967292
  SELECT SQL_CALC_FOUND_ROWS * FROM t1 LIMIT 1 UNION all SELECT * FROM t2 LIMIT 2;
  a
  1
***************
*** 342,348 ****
  3
  select found_rows();
  found_rows()
! 6
  SELECT SQL_CALC_FOUND_ROWS * FROM t1 UNION all SELECT * FROM t2 LIMIT 2;
  a
  1
--- 342,348 ----
  3
  select found_rows();
  found_rows()
! -8589934586
  SELECT SQL_CALC_FOUND_ROWS * FROM t1 UNION all SELECT * FROM t2 LIMIT 2;
  a
  1
***************
*** 349,355 ****
  2
  select found_rows();
  found_rows()
! 6
  SELECT SQL_CALC_FOUND_ROWS * FROM t1 UNION SELECT * FROM t2 LIMIT 2;
  a
  1
--- 349,355 ----
  2
  select found_rows();
  found_rows()
! -4294967290
  SELECT SQL_CALC_FOUND_ROWS * FROM t1 UNION SELECT * FROM t2 LIMIT 2;
  a
  1
***************
*** 356,362 ****
  2
  select found_rows();
  found_rows()
! 6
  SELECT SQL_CALC_FOUND_ROWS * FROM t1 UNION SELECT * FROM t2 LIMIT 100;
  a
  1
--- 356,362 ----
  2
  select found_rows();
  found_rows()
! -4294967290
  SELECT SQL_CALC_FOUND_ROWS * FROM t1 UNION SELECT * FROM t2 LIMIT 100;
  a
  1
***************
*** 366,372 ****
  5
  select found_rows();
  found_rows()
! 6
  SELECT SQL_CALC_FOUND_ROWS * FROM t1 LIMIT 100 UNION SELECT * FROM t2;
  a
  1
--- 366,372 ----
  5
  select found_rows();
  found_rows()
! -4294967290
  SELECT SQL_CALC_FOUND_ROWS * FROM t1 LIMIT 100 UNION SELECT * FROM t2;
  a
  1
***************
*** 376,382 ****
  5
  select found_rows();
  found_rows()
! 5
  SELECT SQL_CALC_FOUND_ROWS * FROM t1 LIMIT 1 UNION SELECT * FROM t2;
  a
  1
--- 376,382 ----
  5
  select found_rows();
  found_rows()
! -4294967291
  SELECT SQL_CALC_FOUND_ROWS * FROM t1 LIMIT 1 UNION SELECT * FROM t2;
  a
  1
***************
*** 385,391 ****
  5
  select found_rows();
  found_rows()
! 6
  SELECT SQL_CALC_FOUND_ROWS * FROM t1 LIMIT 1 UNION SELECT * FROM t2 LIMIT 2;
  a
  1
--- 385,391 ----
  5
  select found_rows();
  found_rows()
! -4294967290
  SELECT SQL_CALC_FOUND_ROWS * FROM t1 LIMIT 1 UNION SELECT * FROM t2 LIMIT 2;
  a
  1
***************
*** 392,398 ****
  3
  select found_rows();
  found_rows()
! 6
  SELECT SQL_CALC_FOUND_ROWS * FROM t1 UNION SELECT * FROM t2 LIMIT 2,2;
  a
  3
--- 392,398 ----
  3
  select found_rows();
  found_rows()
! -8589934586
  SELECT SQL_CALC_FOUND_ROWS * FROM t1 UNION SELECT * FROM t2 LIMIT 2,2;
  a
  3
***************
*** 399,405 ****
  4
  select found_rows();
  found_rows()
! 6
  SELECT SQL_CALC_FOUND_ROWS * FROM t1 limit 2,2 UNION SELECT * FROM t2;
  a
  3
--- 399,405 ----
  4
  select found_rows();
  found_rows()
! -4294967290
  SELECT SQL_CALC_FOUND_ROWS * FROM t1 limit 2,2 UNION SELECT * FROM t2;
  a
  3
***************
*** 407,413 ****
  5
  select found_rows();
  found_rows()
! 5
  SELECT * FROM t1 UNION SELECT * FROM t2 ORDER BY a desc LIMIT 1;
  a
  5
--- 407,413 ----
  5
  select found_rows();
  found_rows()
! -4294967291
  SELECT * FROM t1 UNION SELECT * FROM t2 ORDER BY a desc LIMIT 1;
  a
  5
-------------------------------------------------------
Please follow the instructions outlined at
http://www.mysql.com/doc/en/Reporting_mysqltest_bugs.html
to find the reason to this problem and how to report this.

Aborting. To continue, re-run with '--force'.
----------

How to repeat:
Configure and build as above, run test suite.
[22 Jul 2004 21:54] Alan Burlison
Please close this bug as 'not a bug'.

This problem was in fact caused by a bug a bug in the x86 Forte optimizer rather than anything in MySQL.  Using any optimization level higher than '-xO1' triggers the problem.  The affected statement is at line 211 of sql_union.cc:

      add_rows+= (ulonglong) (thd->limit_found_rows - (table->file->records -
                                                       records_at_start));

The bug causes the high-order 32 bits of add_rows to be set to 'FFFFFFFF' instead of '00000000'.  I've logged a bug against the compiler, the Sun bugid is 5077233.  Note that this bug only appears in the x86 compiler, the sparc one gives the correct result.

There are three possible workarounds, any of them will avoid the problem:

1. Don't use the optimizer - you need to modify OPTIMIZE_CFLAGS, OPTIMIZE_CXXFLAGS. MAX_C_OPTIMIZE and MAX_CXX_OPTIMIZE in configure to do this - by default the optimizer is on ('-O') on Solaris.

2. Compile MySQL with '-DBIG_TABLES' in CFLAGS and CXXFLAGS

3. Apply the following patch to the MySQL source:

*** sql/sql_union.cc.orig	Thu Jul 22 18:46:17 2004
--- sql/sql_union.cc	Thu Jul 22 18:46:57 2004
***************
*** 32,38 ****
    List<Item> item_list;
    TABLE *table;
    int res;
!   ulonglong add_rows= 0;
    ulong found_rows_for_union= lex->select_lex.options & OPTION_FOUND_ROWS;
    ulong describe= lex->select_lex.options & SELECT_DESCRIBE;
    TABLE_LIST result_table_list;
--- 32,38 ----
    List<Item> item_list;
    TABLE *table;
    int res;
!   ha_rows add_rows= 0;
    ulong found_rows_for_union= lex->select_lex.options & OPTION_FOUND_ROWS;
    ulong describe= lex->select_lex.options & SELECT_DESCRIBE;
    TABLE_LIST result_table_list;
[23 Jul 2004 18:45] Sergei Golubchik
Thank you for your bug report. This issue has been committed to our
source repository of that product and will be incorporated into the
next release.

If necessary, you can access the source repository and build the latest
available version, including the bugfix, yourself. More information 
about accessing the source trees is available at
    http://www.mysql.com/doc/en/Installing_source_tree.html

Additional info:

Thank you for the great report!

I think for now we will go with the -DBIG_TABLES solution.

About your third workaround, as in the

      add_rows+= (ulonglong) (thd->limit_found_rows - (table->file->records -
						       records_at_start));

thd->limit_found_rows is also ulonglong, then I think this cast may (or may not :) help

      add_rows+=  thd->limit_found_rows -
                             (ulonglong)(table->file->records - records_at_start);

I'm afraid we don't have Sun FORTE compiler on our Solarix/x86 box, so I cannot test whether it helps :(
[23 Jul 2004 19:18] Alan Burlison
Unfortunately the additonal cast doesn't help - the result of (table->file->records - records_at_start) is ulong, so the compiler is already going to have to promote it to ulonglong to subtract it from thd->limit_found_rows which is a ulonglong - the additional cast just tells the compiler to do the conversion it already know it has to do - the problem is it does it incorrectly.

Nice try though ;-)
[30 Aug 2004 10:34] Sergei Golubchik
fixed in 4.0.21
[22 Oct 2005 1:02] 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/internals/31299