List:Commits« Previous MessageNext Message »
From:Mattias Jonsson Date:November 18 2010 9:57am
Subject:Re: bzr commit into mysql-5.5-bugteam branch (chris.powers:3128)
Bug#35333
View as plain text  
Hi Chris,

Patch approved after minor changes, see below.

On 2010-11-18 01.23, Christopher Powers wrote:
> #At file:///home/cpowers/work/dev/mysql-5.5-bugteam/ based on
> revid:davi.arnaut@stripped
>
>   3128 Christopher Powers	2010-11-17
>        Bug#35333, "If Federated table can't connect to remote host, can't retrieve
> metadata"
>
>        Improved error handling such that queries against Information_Schema.Tables
> won't
>        fail if a federated table can't make a remote connection.
>       @ sql/sql_show.cc
>          If get_schema_tables_record() encounters an error, push a warning,
>          set the TABLE COMMENT column with the error text, and clear the
>          error so that the operation can continue.
>
>      added:
>        mysql-test/suite/federated/federated_bug_35333.result
>        mysql-test/suite/federated/federated_bug_35333.test
>      modified:
>        sql/sql_show.cc
> === added file 'mysql-test/suite/federated/federated_bug_35333.result'
> --- a/mysql-test/suite/federated/federated_bug_35333.result	1970-01-01 00:00:00
> +0000
> +++ b/mysql-test/suite/federated/federated_bug_35333.result	2010-11-18 00:22:58
> +0000
> @@ -0,0 +1,23 @@
> +CREATE DATABASE federated;
> +CREATE DATABASE federated;
> +CREATE DATABASE IF NOT EXISTS realdb;

Why two CREATE federated and one CREATE IF NOT EXISTS realdb ? (be 
consistent). Ah, relates to --source federated.inc, see below.

> +DROP TABLE IF EXISTS realdb.t0;
> +DROP TABLE IF EXISTS federated.t0;
> +CREATE TABLE realdb.t0 (a text, b text) ENGINE=MYISAM;
> +CREATE TABLE federated.t0 (a text, b text) ENGINE=FEDERATED
> +CONNECTION='mysql://root@stripped:3333/realdb/t0';

Hmm, maybe another port? I know that 3333 is not a common port, but I 
think an even higher port, perhaps >= 49152 (see 
http://www.iana.org/assignments/port-numbers), is even more unlikely to 
be used by another service.

> +SELECT TABLE_SCHEMA, TABLE_NAME, TABLE_TYPE, ENGINE, ROW_FORMAT, TABLE_ROWS,
> DATA_LENGTH, TABLE_COMMENT
> +FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'realdb' or TABLE_SCHEMA =
> 'federated';
>
> +TABLE_SCHEMA	TABLE_NAME	TABLE_TYPE	ENGINE	ROW_FORMAT	TABLE_ROWS	DATA_LENGTH	TABLE_COMMENT
> +federated	t0	BASE TABLE	FEDERATED		NULL	0	Unable to connect to foreign data source:
> Can't connect to MySQL server on '127.0.0.1' (111)
> +realdb	t0	BASE TABLE	MyISAM	Dynamic	0	0	
> +Warnings:
> +Warning	1429	Unable to connect to foreign data source: Can't connect to MySQL server
> on '127.0.0.1' (111)
> +SHOW WARNINGS;
> +Level	Code	Message
> +Warning	1429	Unable to connect to foreign data source: Can't connect to MySQL server
> on '127.0.0.1' (111)

Could you do:
let $MYSQLD_DATADIR= `SELECT @@datadir`;
--remove_file $MYSQLD_DATADIR/realdb/t0.MYD
--remove_file $MYSQLD_DATADIR/realdb/t0.MYI
and a new I_S query on the realdb.t0 table? To have a reference to the 
non federated behavior.

> +DROP DATABASE realdb;
> +DROP TABLE IF EXISTS federated.t1;
> +DROP DATABASE federated;
> +DROP TABLE IF EXISTS federated.t1;
> +DROP DATABASE federated;

Double dropping, DROP DATABASE is enough, it should delete all files in 
that directory IIRC. (Ah it comes from a master+slave setup, would have 
been good if it did --echo # on Master + --echo # on Slave first, but 
see below how to fix it.

>
> === added file 'mysql-test/suite/federated/federated_bug_35333.test'
> --- a/mysql-test/suite/federated/federated_bug_35333.test	1970-01-01 00:00:00 +0000
> +++ b/mysql-test/suite/federated/federated_bug_35333.test	2010-11-18 00:22:58 +0000
> @@ -0,0 +1,58 @@
> +# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
> +#
> +# This program is free software; you can redistribute it and/or modify
> +# it under the terms of the GNU General Public License as published by
> +# the Free Software Foundation; version 2 of the License.
> +#
> +# This program is distributed in the hope that it will be useful,
> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +# GNU General Public License for more details.
> +#
> +# You should have received a copy of the GNU General Public License
> +# along with this program; if not, write to the Free Software Foundation,
> +# 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */

Not sure if the test really needs the GPL text (at least I never include 
it in any tests).

> +
> +# Test for Federated Engine
> +
> +--source federated.inc

Use --source suite/federated/have_federated_db.inc instead. Will also 
remove the 'CREATE DATABASE federated' and removes the master+slave setup.

> +
> +# Bug 35333 "If a Federated table can't connect to the remote hose, can't retrieve
> metadata"
> +#
> +# Queries such as SHOW TABLE STATUS and SELECT * FROM INFORMATION_SCHEMA.TABLES
> fail
> +# when encountering a federated table that cannot connect to its remote table.
> +#
> +# The fix is to store the error text in the TABLE COMMENTS column of I_S.TABLES,
> clear
> +# the remote connection error and push a warning instead. This allows the SELECT
> operation
> +# to complete while still indicating a problem.
> +
> +--disable_warnings
> +CREATE DATABASE IF NOT EXISTS realdb;
> +DROP TABLE IF EXISTS realdb.t0;
> +# Federated database already exists

If removing --source federated.inc, add CREATE DATABASE IF NOT EXISTS 
federated.

> +DROP TABLE IF EXISTS federated.t0;
> +--enable_warnings
> +
> +#
> +# Create the base table to be referenced
> +#

You can add '--echo ' before the '#' so it also turns up in the result file.

> +CREATE TABLE realdb.t0 (a text, b text) ENGINE=MYISAM;
> +
> +#
> +# Create a federated table with a bogus port number
> +#
> +CREATE TABLE federated.t0 (a text, b text) ENGINE=FEDERATED
> +    CONNECTION='mysql://root@stripped:3333/realdb/t0';
> +
> +#--warning ER_CONNECT_TO_FOREIGN_DATA_SOURCE
> +
> +SELECT TABLE_SCHEMA, TABLE_NAME, TABLE_TYPE, ENGINE, ROW_FORMAT, TABLE_ROWS,
> DATA_LENGTH, TABLE_COMMENT
> +       FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'realdb' or TABLE_SCHEMA
> = 'federated';
> +
> +SHOW WARNINGS;
> +
> +#
> +# Cleanup
> +#
> +DROP DATABASE realdb;
> +source federated_cleanup.inc;

If --source ... have_federated_db.inc is used instead of federated.inc, 
you can replace this with 'DROP DATABASE federated'.

>
> === modified file 'sql/sql_show.cc'
> --- a/sql/sql_show.cc	2010-11-02 14:02:16 +0000
> +++ b/sql/sql_show.cc	2010-11-18 00:22:58 +0000
> @@ -3778,6 +3778,7 @@ static int get_schema_tables_record(THD
>   {
>     const char *tmp_buff;
>     MYSQL_TIME time;
> +   int info_error= 0;
>     CHARSET_INFO *cs= system_charset_info;
>     DBUG_ENTER("get_schema_tables_record");
>
> @@ -3785,20 +3786,16 @@ static int get_schema_tables_record(THD
>     table->field[0]->store(STRING_WITH_LEN("def"), cs);
>     table->field[1]->store(db_name->str, db_name->length, cs);
>     table->field[2]->store(table_name->str, table_name->length, cs);
> +
>     if (res)
>     {
> -    /*
> -      there was errors during opening tables
> -    */
> -    const char *error= thd->is_error() ? thd->stmt_da->message() : "";
> +    /* There was a table open error, so set the table type and fall through */
>       if (tables->view)
>         table->field[3]->store(STRING_WITH_LEN("VIEW"), cs);
>       else if (tables->schema_table)
>         table->field[3]->store(STRING_WITH_LEN("SYSTEM VIEW"), cs);
>       else
>         table->field[3]->store(STRING_WITH_LEN("BASE TABLE"), cs);
> -    table->field[20]->store(error, strlen(error), cs);
> -    thd->clear_error();

Perhaps also add 'goto err;' to prevent future problems if one wants to 
add code before the 'err:' label.

>     }
>     else if (tables->view)
>     {
> @@ -3815,6 +3812,7 @@ static int get_schema_tables_record(THD
>   #ifdef WITH_PARTITION_STORAGE_ENGINE
>       bool is_partitioned= FALSE;
>   #endif
> +
>       if (share->tmp_table == SYSTEM_TMP_TABLE)
>         table->field[3]->store(STRING_WITH_LEN("SYSTEM VIEW"), cs);
>       else if (share->tmp_table)
> @@ -3828,6 +3826,11 @@ static int get_schema_tables_record(THD
>           continue;
>         table->field[i]->set_notnull();
>       }
> +
> +    /*
> +       Collect table info from the table share
> +     */
> +
>   #ifdef WITH_PARTITION_STORAGE_ENGINE
>       if (share->db_type() == partition_hton&&
>           share->partition_info_str_len)
> @@ -3836,62 +3839,82 @@ static int get_schema_tables_record(THD
>         is_partitioned= TRUE;
>       }
>   #endif

Below, not really needed for the patch to add the extra empty lines, but 
is OK by the coding guidelines. So OK to add if it helps readability.

> +
>       tmp_buff= (char *) ha_resolve_storage_engine_name(tmp_db_type);
>       table->field[4]->store(tmp_buff, strlen(tmp_buff), cs);
>       table->field[5]->store((longlong) share->frm_version, TRUE);
>
>       ptr=option_buff;
> +
>       if (share->min_rows)
>       {
>         ptr=strmov(ptr," min_rows=");
>         ptr=longlong10_to_str(share->min_rows,ptr,10);
>       }
> +
>       if (share->max_rows)
>       {
>         ptr=strmov(ptr," max_rows=");
>         ptr=longlong10_to_str(share->max_rows,ptr,10);
>       }
> +
>       if (share->avg_row_length)
>       {
>         ptr=strmov(ptr," avg_row_length=");
>         ptr=longlong10_to_str(share->avg_row_length,ptr,10);
>       }
> +
>       if (share->db_create_options&  HA_OPTION_PACK_KEYS)
>         ptr=strmov(ptr," pack_keys=1");
> +
>       if (share->db_create_options&  HA_OPTION_NO_PACK_KEYS)
>         ptr=strmov(ptr," pack_keys=0");
> +
>       /* We use CHECKSUM, instead of TABLE_CHECKSUM, for backward compability */
>       if (share->db_create_options&  HA_OPTION_CHECKSUM)
>         ptr=strmov(ptr," checksum=1");
> +
>       if (share->db_create_options&  HA_OPTION_DELAY_KEY_WRITE)
>         ptr=strmov(ptr," delay_key_write=1");
> +
>       if (share->row_type != ROW_TYPE_DEFAULT)
>         ptr=strxmov(ptr, " row_format=",
>                     ha_row_type[(uint) share->row_type],
>                     NullS);
> +
>       if (share->key_block_size)
>       {
>         ptr= strmov(ptr, " KEY_BLOCK_SIZE=");
>         ptr= longlong10_to_str(share->key_block_size, ptr, 10);
>       }
> +
>   #ifdef WITH_PARTITION_STORAGE_ENGINE
>       if (is_partitioned)
>         ptr= strmov(ptr, " partitioned");
>   #endif
> +
>       table->field[19]->store(option_buff+1,
>                               (ptr == option_buff ? 0 :
>                                (uint) (ptr-option_buff)-1), cs);
>
>       tmp_buff= (share->table_charset ?
>                  share->table_charset->name : "default");
> +
>       table->field[17]->store(tmp_buff, strlen(tmp_buff), cs);
>
>       if (share->comment.str)
>         table->field[20]->store(share->comment.str,
> share->comment.length, cs);
>
> +    /*
> +       Collect table info from the storage engine
> +     */
> +

Move the */ one step to the left... Or since it is now OK to use C++ 
comments, use a single line comment, //.

>       if(file)
>       {
> -      file->info(HA_STATUS_VARIABLE | HA_STATUS_TIME | HA_STATUS_AUTO);
xxx12345678901234567890123456789012345678901234567890123456789012345678901234567890
> +      /* If info() returns an error, then there's nothing else to do except return
> */
> +      if ((info_error= file->info(HA_STATUS_VARIABLE | HA_STATUS_TIME |
> HA_STATUS_AUTO)) != 0)

To long lines...

> +        goto err;
> +
>         enum row_type row_type = file->get_row_type();
>         switch (row_type) {
>         case ROW_TYPE_NOT_USED:
> @@ -3920,7 +3943,9 @@ static int get_schema_tables_record(THD
>           tmp_buff= "Paged";
>           break;
>         }
> +
>         table->field[6]->store(tmp_buff, strlen(tmp_buff), cs);
> +
>         if (!tables->schema_table)
>         {
>           table->field[7]->store((longlong) file->stats.records, TRUE);
> @@ -3969,6 +3994,26 @@ static int get_schema_tables_record(THD
>         }
>       }
>     }
> +
> +err:
> +  if (res || info_error)
> +  {
> +    /*
> +       If an error was encountered, push a warning, set the TABLE COMMENT
> +       column with the error text, and clear the error so that the operation
> +       can continue.
> +     */

indent the */ one column to the left.

> +    const char *error= thd->is_error() ? thd->stmt_da->message() : "";
> +    table->field[20]->store(error, strlen(error), cs);
> +
> +    if (thd->is_error())
> +    {
> +      push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
> +                   thd->stmt_da->sql_errno(), thd->stmt_da->message());
> +      thd->clear_error();
> +    }
> +  }
> +
>     DBUG_RETURN(schema_table_store_record(thd, table));
>   }

Regards Mattias
Thread
bzr commit into mysql-5.5-bugteam branch (chris.powers:3128) Bug#35333Christopher Powers18 Nov
  • Re: bzr commit into mysql-5.5-bugteam branch (chris.powers:3128)Bug#35333Mattias Jonsson18 Nov