From 5acf83802d2098a5be9848f4cadafa68709391ea Mon Sep 17 00:00:00 2001 From: "Sinisa@sinisa.nasamreza.org" <> Date: Thu, 13 Feb 2003 17:56:01 +0200 Subject: [PATCH] fix a bug in derived tables UNION's bug fixes and code clean-up --- mysql-test/r/subselect.result | 2 +- scripts/fill_func_tables.sh | 234 ++++++++++++++++++++++++++++++++++ sql/sql_derived.cc | 2 +- sql/sql_lex.h | 2 +- sql/sql_union.cc | 120 ++++++++++------- sql/sql_yacc.yy | 4 +- 6 files changed, 311 insertions(+), 53 deletions(-) create mode 100755 scripts/fill_func_tables.sh diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index 0d8c96fea85..47f24a340cd 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -1000,7 +1000,7 @@ CREATE TABLE t1 SELECT (SELECT 1 as a UNION SELECT 1+1 limit 1,1) as a; SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( - `a` bigint(17) NOT NULL default '0' + `a` bigint(1) NOT NULL default '0' ) TYPE=MyISAM CHARSET=latin1 drop table t1; create table t1 (a int); diff --git a/scripts/fill_func_tables.sh b/scripts/fill_func_tables.sh new file mode 100755 index 00000000000..459afee2fe1 --- /dev/null +++ b/scripts/fill_func_tables.sh @@ -0,0 +1,234 @@ +#!/usr/bin/perl +# fill_func_tables - parse ../Docs/manual.texi + +# Original version by vva + +my $cat_name= ""; +my $func_name= ""; +my $text= ""; +my $example= ""; + +local $mode= ""; + +sub prepare_name +{ + my ($a)= @_; + + $a =~ s/(\@itemize \@bullet)/ /g; + $a =~ s/(\@end itemize)/ /g; + $a =~ s/(\@end multitable)/ /g; + $a =~ s/(\@end table)/ /g; + $a =~ s/(\@cindex(.*?)\n)/ /g; + $a =~ s/(\@multitable \@columnfractions(.*?)\n)/ /g; + $a =~ s/(\@node(.*?)\n)/ /g; + $a =~ s/(\@tab)/\t/g; + $a =~ s/\@item/ /g; + $a =~ s/\@code\{((.|\n)+?)\}/$1/go; + $a =~ s/\@strong\{(.+?)\}/$1/go; + $a =~ s/\@samp\{(.+?)\}/$1/go; + $a =~ s/\@emph\{((.|\n)+?)\}/\/$1\//go; + $a =~ s/\@xref\{((.|\n)+?)\}/See also : [$1]/go; + $a =~ s/\@ref\{((.|\n)+?)\}/[$1]/go; + $a =~ s/\'/\'\'/g; + $a =~ s/\\/\\\\/g; + $a =~ s/\`/\`\`/g; + + $a =~ s/\@table \@code/ /g; + + $a =~ s/\(\)//g; + + $a =~ s/((\w|\s)+)\(([\+-=><\/%*!<>\s]+)\)/$3/gxs; #$a =~ s/((\w|\s)+)\(([\+-=><\/%*!<>\s]+)\)/$3 $1/gxs; + $a =~ s/([\+-=><\/%*!<>\s]+)\(((\w|\s)+)\)/$1/gxs;#$a =~ s/([\+-=><\/%*!<>\s]+)\(((\w|\s)+)\)/$1 $2/gxs; + $a =~ s/((\w|\s)+)\((.+)\)/$1/gxs; + + return $a; +} + +sub prepare_text +{ + my ($a)= @_; + + $a =~ s/(\@itemize \@bullet)/ /g; + $a =~ s/(\@end itemize)/ /g; + $a =~ s/(\@end multitable)/ /g; + $a =~ s/(\@end table)/ /g; + $a =~ s/(\@cindex(.*?)\n)/ /g; + $a =~ s/(\@multitable \@columnfractions(.*?)\n)/ /g; + $a =~ s/(\@node(.*?)\n)/ /g; + $a =~ s/(\@tab)/\t/g; + $a =~ s/\@itemx/ /g; + $a =~ s/\@item/ /g; + $a =~ s/\@code\{((.|\n)+?)\}/$1/go; + $a =~ s/\@strong\{(.+?)\}/$1/go; + $a =~ s/\@samp\{(.+?)\}/$1/go; + $a =~ s/\@emph\{((.|\n)+?)\}/\/$1\//go; + $a =~ s/\@xref\{((.|\n)+?)\}/See also : [$1]/go; + $a =~ s/\@ref\{((.|\n)+?)\}/[$1]/go; + $a =~ s/\'/\'\'/g; + $a =~ s/\\/\\\\/g; + $a =~ s/\`/\`\`/g; + $a =~ s/(\n*?)$//g; + $a =~ s/\n/\\n/g; + + $a =~ s/\@table \@code/ /g; + + return $a; +} + +sub prepare_example +{ + my ($a)= @_; + + $a =~ s/\'/\'\'/g; + $a =~ s/\\/\\\\/g; + $a =~ s/\`/\`\`/g; + $a =~ s/(\n*?)$//g; + $a =~ s/\n/\\n/g; + + return $a; +} + +sub flush_all +{ + my ($mode) = @_; + + if ($mode eq ""){return;} + + $func_name= prepare_name($func_name); + $text= prepare_text($text); + $example= prepare_example($example); + + if ($func_name ne "" && $text ne "" && !($func_name =~ /[abcdefghikjlmnopqrstuvwxyz]/)){ + print "INSERT INTO function (name,description,example) VALUES ("; + print "'$func_name',"; + print "'$text',"; + print "'$example'"; + print ");\n"; + print "INSERT INTO function_category (cat_id,func_id) VALUES (\@cur_category,LAST_INSERT_ID());\n"; + } + + $func_name= ""; + $text= ""; + $example= ""; + $mode= ""; +} + +sub new_category +{ + my ($category)= @_; + + $category= prepare_text($category); + + print "INSERT INTO function_category_name (name) VALUES (\'$category\');\n"; + print "SELECT \@cur_category:=LAST_INSERT_ID();\n"; +} + +print "INSERT INTO db (Host,DB,User,Select_priv) VALUES ('%','mysql_help','','Y');\n"; +print "CREATE DATABASE mysql_help;\n"; + +print "USE mysql_help;\n"; + +print "DROP TABLE IF EXISTS function;\n"; +print "CREATE TABLE function ("; +print " func_id int unsigned not null auto_increment,"; +print " name varchar(64) not null,"; +print " url varchar(128) not null,"; +print " description text not null,"; +print " example text not null,"; +print " min_args tinyint not null,"; +print " max_args tinyint,"; +print " date_created datetime not null,"; +print " last_modified timestamp not null,"; +print " primary key (func_id)"; +print ") type=myisam;\n\n"; + +print "DROP TABLE IF EXISTS function_category_name;\n"; +print "CREATE TABLE function_category_name ("; +print " cat_id smallint unsigned not null auto_increment,"; +print " name varchar(64) not null,"; +print " url varchar(128) not null,"; +print " date_created datetime not null,"; +print " last_modified timestamp not null,"; +print " primary key (cat_id)"; +print ") type=myisam;\n\n"; + +print "DROP TABLE IF EXISTS function_category;\n"; +print "CREATE TABLE function_category ("; +print " cat_id smallint unsigned not null references function_category_name,"; +print " func_id int unsigned not null references function,"; +print " primary key (cat_id, func_id)"; +print ") type=myisam;\n\n"; + +print "DELETE FROM function_category_name;\n"; +print "DELETE FROM function_category;\n"; +print "DELETE FROM function;\n"; +print "SELECT \@cur_category:=null;\n\n"; + +my $in_section_6_3= 0; + +for(<>) +{ + if ($_=~/\@section Functions for Use in \@code{SELECT} and \@code{WHERE} Clauses/ && + !$in_section_6_3){ + $in_section_6_3= 1; + next; + } + + if ($_=~/\@section/ && $in_section_6_3){ + $in_section_6_3= 0; + next; + } + + if (!$in_section_6_3) { next; } + + my $c_name= ""; + + ($c_name)=m|\@c for_mysql_help,(.+?)$|; + if (!($c_name eq "") && ! ($c_name =~ m/$cat_name/i)){ + ($cat_name)= $c_name; + new_category($cat_name); + next; + } + + ($c_name)=m|\@subsubsection (.+?)$|; + if (!($c_name eq "") && ! ($c_name =~ m/$cat_name/i)){ + ($cat_name)= $c_name; + new_category($cat_name); + next; + } + + ($c_name)=m|\@subsection (.+?)$|; + if (!($c_name eq "") && ! ($c_name =~ m/$cat_name/i)){ + ($cat_name)= $c_name; + new_category($cat_name); + next; + } + + ($f_name)=m|\@findex (.+?)$|; + if (!($f_name eq "")){ + flush_all($mode); + ($func_name)= ($f_name); + $mode= "text"; + next; + } + + if ($_=~/\@example/ && ($mode eq "text")){ + $mode= "example"; + next; + } + + if ($_=~/\@end example/ && ($mode eq "example")){ + flush_all($mode); + next; + } + + if ($mode eq "text") { $text .= $_; } + if ($mode eq "example") { $example .= $_; } +} + + +print "DELETE function_category_name "; +print "FROM function_category_name "; +print "LEFT JOIN function_category ON function_category.cat_id=function_category_name.cat_id "; +print "WHERE function_category.cat_id is null;" + diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index 528bdb7b6f5..c288a1d728f 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -189,7 +189,7 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, tables->table_list->table=tables->table; } else - unit->exclude(); + unit->exclude_level(); org_table_list->db= (char *)""; #ifndef DBUG_OFF /* Try to catch errors if this is accessed */ diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 00852f302d8..448ab5fa344 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -289,7 +289,7 @@ protected: bool describe, found_rows_for_union, prepared, // prepare phase already performed for UNION (unit) optimized, // optimize phase already performed for UNION (unit) - executed; // already executed + executed, t_and_f; // already executed public: /* Pointer to 'last' select or pointer to unit where stored diff --git a/sql/sql_union.cc b/sql/sql_union.cc index bc1449aeda0..79a39fa44d4 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -120,6 +120,7 @@ int st_select_lex_unit::prepare(THD *thd, select_result *result, found_rows_for_union= 0; TMP_TABLE_PARAM tmp_table_param; this->result= result; + t_and_f=tables_and_fields_initied; SELECT_LEX_NODE *lex_select_save= thd->lex.current_select; SELECT_LEX *sl; @@ -132,7 +133,7 @@ int st_select_lex_unit::prepare(THD *thd, select_result *result, if (found_rows_for_union) first_select()->options ^= OPTION_FOUND_ROWS; } - if (tables_and_fields_initied) + if (t_and_f) { // Item list and tables will be initialized by mysql_derived item_list= sl->item_list; @@ -154,7 +155,7 @@ int st_select_lex_unit::prepare(THD *thd, select_result *result, setup_fields(thd, sl->ref_pointer_array, first_table, item_list, 0, 0, 1)) goto err; - tables_and_fields_initied= 1; + t_and_f= 1; } bzero((char*) &tmp_table_param,sizeof(tmp_table_param)); @@ -177,35 +178,36 @@ int st_select_lex_unit::prepare(THD *thd, select_result *result, union_result->not_describe=1; union_result->tmp_table_param=&tmp_table_param; - - // prepare selects - for (sl= first_select(); sl; sl= sl->next_select()) + if (thd->lex.describe) { - JOIN *join= new JOIN(thd, sl->item_list, - sl->options | thd->options | SELECT_NO_UNLOCK, - union_result); - thd->lex.current_select= sl; - offset_limit_cnt= sl->offset_limit; - select_limit_cnt= sl->select_limit+sl->offset_limit; - if (select_limit_cnt < sl->select_limit) - select_limit_cnt= HA_POS_ERROR; // no limit - if (select_limit_cnt == HA_POS_ERROR) - sl->options&= ~OPTION_FOUND_ROWS; - - res= join->prepare(&sl->ref_pointer_array, - (TABLE_LIST*) sl->table_list.first, sl->with_wild, - sl->where, - ((sl->braces) ? sl->order_list.elements : 0) + - sl->group_list.elements, - (sl->braces) ? - (ORDER *)sl->order_list.first : (ORDER *) 0, - (ORDER*) sl->group_list.first, - sl->having, - (ORDER*) NULL, - sl, this, 0, tables_and_fields_initied); - tables_and_fields_initied= 0; - if (res | thd->is_fatal_error) - goto err; + for (SELECT_LEX *sl= first_select(); sl; sl= sl->next_select()) + { + JOIN *join= new JOIN(thd, sl->item_list, + sl->options | thd->options | SELECT_NO_UNLOCK, + union_result); + thd->lex.current_select= sl; + offset_limit_cnt= sl->offset_limit; + select_limit_cnt= sl->select_limit+sl->offset_limit; + if (select_limit_cnt < sl->select_limit) + select_limit_cnt= HA_POS_ERROR; // no limit + if (select_limit_cnt == HA_POS_ERROR) + sl->options&= ~OPTION_FOUND_ROWS; + + res= join->prepare(&sl->ref_pointer_array, + (TABLE_LIST*) sl->table_list.first, sl->with_wild, + sl->where, + ((sl->braces) ? sl->order_list.elements : 0) + + sl->group_list.elements, + (sl->braces) ? + (ORDER *)sl->order_list.first : (ORDER *) 0, + (ORDER*) sl->group_list.first, + sl->having, + (ORDER*) NULL, + sl, this, 0, t_and_f); + t_and_f=0; + if (res | thd->is_fatal_error) + goto err; + } } item_list.empty(); thd->lex.current_select= lex_select_save; @@ -246,23 +248,49 @@ int st_select_lex_unit::exec() } for (SELECT_LEX *sl= first_select(); sl; sl= sl->next_select()) { - thd->lex.current_select= sl; - offset_limit_cnt= sl->offset_limit; - select_limit_cnt= sl->select_limit+sl->offset_limit; - if (select_limit_cnt < sl->select_limit) - select_limit_cnt= HA_POS_ERROR; // no limit - if (select_limit_cnt == HA_POS_ERROR) - sl->options&= ~OPTION_FOUND_ROWS; - - if (!optimized) - res= sl->join->optimize(); - else + if (optimized) res= sl->join->reinit(); - + else + { + JOIN *join= new JOIN(thd, sl->item_list, + sl->options | thd->options | SELECT_NO_UNLOCK, + union_result); + thd->lex.current_select= sl; + offset_limit_cnt= sl->offset_limit; + select_limit_cnt= sl->select_limit+sl->offset_limit; + if (select_limit_cnt < sl->select_limit) + select_limit_cnt= HA_POS_ERROR; // no limit + if (select_limit_cnt == HA_POS_ERROR) + sl->options&= ~OPTION_FOUND_ROWS; + + res= join->prepare(&sl->ref_pointer_array, + (TABLE_LIST*) sl->table_list.first, sl->with_wild, + sl->where, + ((sl->braces) ? sl->order_list.elements : 0) + + sl->group_list.elements, + (sl->braces) ? + (ORDER *)sl->order_list.first : (ORDER *) 0, + (ORDER*) sl->group_list.first, + sl->having, + (ORDER*) NULL, + sl, this, 0, t_and_f); + t_and_f=0; + if (res | thd->is_fatal_error) + { + thd->lex.current_select= lex_select_save; + DBUG_RETURN(res); + } + res= sl->join->optimize(); + } if (!res) { sl->join->exec(); res= sl->join->error; + if (!res && union_result->flush()) + { + thd->lex.current_select= lex_select_save; + DBUG_RETURN(1); + } } if (res) { @@ -270,14 +298,8 @@ int st_select_lex_unit::exec() DBUG_RETURN(res); } } - optimized= 1; - } - - if (union_result->flush()) - { - thd->lex.current_select= lex_select_save; - DBUG_RETURN(1); } + optimized= 1; /* Send result to 'result' */ diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index b9c0167bc05..a6ee411cb70 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1775,7 +1775,8 @@ select_part2: SELECT_LEX * sel= lex->current_select->select_lex(); if (lex->current_select == &lex->select_lex) lex->lock_option= TL_READ; /* Only for global SELECT */ - mysql_init_select(lex); + if (sel->linkage != UNION_TYPE) + mysql_init_select(lex); } select_options select_item_list select_into select_lock_type; @@ -4656,6 +4657,7 @@ union_list: } if (mysql_new_select(lex, 0)) YYABORT; + mysql_init_select(lex); lex->current_select->linkage=UNION_TYPE; } select_init {}