From 1144c5cfd8dcf3f7125174327f94587ad4820050 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 26 Nov 2002 14:18:16 +0100 Subject: [PATCH 1/3] Pass thd as an argument to yyparse(), getting rid of all current_thd in the parser. BitKeeper/etc/ignore: Added bkpull.log.4 bkpull.log.5 bkpull.log.6 bkpush.log sql/sql_yacc.output to the ignore list --- .bzrignore | 5 ++++ sql/sql_parse.cc | 4 ++-- sql/sql_prepare.cc | 4 ++-- sql/sql_yacc.yy | 59 ++++++++++++++++++++++++++-------------------- 4 files changed, 42 insertions(+), 30 deletions(-) diff --git a/.bzrignore b/.bzrignore index 978926c8c37..88995ac7c65 100644 --- a/.bzrignore +++ b/.bzrignore @@ -562,3 +562,8 @@ bkpull.log.2 bkpull.log.3 build.log sql/safe_to_cache_query.txt +bkpull.log.4 +bkpull.log.5 +bkpull.log.6 +bkpush.log +sql/sql_yacc.output diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 86333552837..0ca62fd4f52 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -51,7 +51,7 @@ #define TRANS_MEM_ROOT_BLOCK_SIZE 4096 #define TRANS_MEM_ROOT_PREALLOC 4096 -extern int yyparse(void); +extern int yyparse(void *thd); extern "C" pthread_mutex_t THR_LOCK_keycache; #ifdef SOLARIS extern "C" int gethostname(char *name, int namelen); @@ -2951,7 +2951,7 @@ mysql_parse(THD *thd, char *inBuf, uint length) if (query_cache_send_result_to_client(thd, inBuf, length) <= 0) { LEX *lex=lex_start(thd, (uchar*) inBuf, length); - if (!yyparse() && ! thd->fatal_error) + if (!yyparse((void *)thd) && ! thd->fatal_error) { if (mqh_used && thd->user_connect && check_mqh(thd, lex->sql_command)) diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index a3a1f93a829..ee97283760d 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -56,7 +56,7 @@ Long data handling: #define IS_PARAM_NULL(pos, param_no) pos[param_no/8] & (1 << param_no & 7) -extern int yyparse(void); +extern int yyparse(void *thd); /* Find prepared statement in thd @@ -605,7 +605,7 @@ static bool parse_prepare_query(PREP_STMT *stmt, LEX *lex=lex_start(thd, (uchar*) packet, length); lex->safe_to_cache_query= 0; - if (!yyparse() && !thd->fatal_error) + if (!yyparse((void *)thd) && !thd->fatal_error) error= send_prepare_results(stmt); lex_end(lex); DBUG_RETURN(error); diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 4465a6d8695..1385f94a6ce 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -17,10 +17,16 @@ /* sql_yacc.yy */ %{ +/* Pass thd as an arg to yyparse(). The type will be void*, so it +** must be cast to (THD*) when used. Use the YYTHD macro for this. +*/ +#define YYPARSE_PARAM yythd +#define YYTHD ((THD *)yythd) + #define MYSQL_YACC #define YYINITDEPTH 100 #define YYMAXDEPTH 3200 /* Because of 64K stack */ -#define Lex current_lex +#define Lex (&(YYTHD->lex)) #define Select Lex->current_select #include "mysql_priv.h" #include "slave.h" @@ -35,9 +41,9 @@ int yylex(void *yylval); #define yyoverflow(A,B,C,D,E,F) if (my_yyoverflow((B),(D),(int*) (F))) { yyerror((char*) (A)); return 2; } -inline Item *or_or_concat(Item* A, Item* B) +inline Item *or_or_concat(THD *thd, Item* A, Item* B) { - return (current_thd->sql_mode & MODE_PIPES_AS_CONCAT ? + return (thd->sql_mode & MODE_PIPES_AS_CONCAT ? (Item*) new Item_func_concat(A,B) : (Item*) new Item_cond_or(A,B)); } @@ -661,11 +667,11 @@ END_OF_INPUT query: END_OF_INPUT { - THD *thd=current_thd; + THD *thd= YYTHD; if (!thd->bootstrap && (!(thd->lex.select_lex.options & OPTION_FOUND_COMMENT))) { - send_error(current_thd,ER_EMPTY_QUERY); + send_error(thd,ER_EMPTY_QUERY); YYABORT; } else @@ -791,7 +797,7 @@ master_def: create: CREATE opt_table_options TABLE_SYM opt_if_not_exists table_ident { - THD *thd=current_thd; + THD *thd= YYTHD; LEX *lex=Lex; lex->sql_command= SQLCOM_CREATE_TABLE; if (!lex->select_lex.add_table_to_list($5, @@ -1075,7 +1081,7 @@ type: | TIME_SYM { $$=FIELD_TYPE_TIME; } | TIMESTAMP { - if (current_thd->sql_mode & MODE_SAPDB) + if (YYTHD->sql_mode & MODE_SAPDB) $$=FIELD_TYPE_DATETIME; else $$=FIELD_TYPE_TIMESTAMP; @@ -1146,7 +1152,7 @@ int_type: | BIGINT { $$=FIELD_TYPE_LONGLONG; }; real_type: - REAL { $$= current_thd->sql_mode & MODE_REAL_AS_FLOAT ? + REAL { $$= YYTHD->sql_mode & MODE_REAL_AS_FLOAT ? FIELD_TYPE_FLOAT : FIELD_TYPE_DOUBLE; } | DOUBLE_SYM { $$=FIELD_TYPE_DOUBLE; } | DOUBLE_SYM PRECISION { $$=FIELD_TYPE_DOUBLE; }; @@ -1211,7 +1217,7 @@ charset_name: { if (!($$=get_charset_by_name("binary",MYF(0)))) { - net_printf(current_thd,ER_UNKNOWN_CHARACTER_SET,"binary"); + net_printf(YYTHD,ER_UNKNOWN_CHARACTER_SET,"binary"); YYABORT; } } @@ -1219,7 +1225,7 @@ charset_name: { if (!($$=get_charset_by_name($1.str,MYF(0)))) { - net_printf(current_thd,ER_UNKNOWN_CHARACTER_SET,$1.str); + net_printf(YYTHD,ER_UNKNOWN_CHARACTER_SET,$1.str); YYABORT; } }; @@ -1247,6 +1253,7 @@ opt_binary: opt_primary: /* empty */ | PRIMARY_SYM + ; references: REFERENCES table_ident @@ -1347,7 +1354,7 @@ string_list: alter: ALTER opt_ignore TABLE_SYM table_ident { - THD *thd=current_thd; + THD *thd= YYTHD; LEX *lex=&thd->lex; lex->sql_command = SQLCOM_ALTER_TABLE; lex->name=0; @@ -1776,7 +1783,7 @@ expr_expr: { $$= new Item_func_between($1,$3,$5); } | expr NOT BETWEEN_SYM no_and_expr AND expr { $$= new Item_func_not(new Item_func_between($1,$4,$6)); } - | expr OR_OR_CONCAT expr { $$= or_or_concat($1,$3); } + | expr OR_OR_CONCAT expr { $$= or_or_concat(YYTHD, $1,$3); } | expr OR expr { $$= new Item_cond_or($1,$3); } | expr XOR expr { $$= new Item_cond_xor($1,$3); } | expr AND expr { $$= new Item_cond_and($1,$3); } @@ -1818,7 +1825,7 @@ no_in_expr: { $$= new Item_func_between($1,$3,$5); } | no_in_expr NOT BETWEEN_SYM no_and_expr AND expr { $$= new Item_func_not(new Item_func_between($1,$4,$6)); } - | no_in_expr OR_OR_CONCAT expr { $$= or_or_concat($1,$3); } + | no_in_expr OR_OR_CONCAT expr { $$= or_or_concat(YYTHD, $1,$3); } | no_in_expr OR expr { $$= new Item_cond_or($1,$3); } | no_in_expr XOR expr { $$= new Item_cond_xor($1,$3); } | no_in_expr AND expr { $$= new Item_cond_and($1,$3); } @@ -1863,7 +1870,7 @@ no_and_expr: { $$= new Item_func_between($1,$3,$5); } | no_and_expr NOT BETWEEN_SYM no_and_expr AND expr { $$= new Item_func_not(new Item_func_between($1,$4,$6)); } - | no_and_expr OR_OR_CONCAT expr { $$= or_or_concat($1,$3); } + | no_and_expr OR_OR_CONCAT expr { $$= or_or_concat(YYTHD, $1,$3); } | no_and_expr OR expr { $$= new Item_cond_or($1,$3); } | no_and_expr XOR expr { $$= new Item_cond_xor($1,$3); } | no_and_expr LIKE simple_expr opt_escape { $$= new Item_func_like($1,$3,$4); } @@ -3009,7 +3016,7 @@ update_list: }; opt_low_priority: - /* empty */ { $$= current_thd->update_lock_default; } + /* empty */ { $$= YYTHD->update_lock_default; } | LOW_PRIORITY { $$= TL_WRITE_LOW_PRIORITY; }; /* Delete rows from a table */ @@ -3193,7 +3200,7 @@ show_param: { Lex->sql_command= SQLCOM_SHOW_PROCESSLIST;} | opt_var_type VARIABLES wild { - THD *thd= current_thd; + THD *thd= YYTHD; thd->lex.sql_command= SQLCOM_SHOW_VARIABLES; thd->lex.option_type= (enum_var_type) $1; } @@ -3404,7 +3411,7 @@ opt_local: | LOCAL_SYM { $$=1;}; load_data_lock: - /* empty */ { $$= current_thd->update_lock_default; } + /* empty */ { $$= YYTHD->update_lock_default; } | CONCURRENT { $$= TL_WRITE_CONCURRENT_INSERT ; } | LOW_PRIORITY { $$= TL_WRITE_LOW_PRIORITY; }; @@ -3453,13 +3460,13 @@ opt_ignore_lines: /* Common definitions */ text_literal: - TEXT_STRING { $$ = new Item_string($1.str,$1.length,current_thd->thd_charset); } + TEXT_STRING { $$ = new Item_string($1.str,$1.length,YYTHD->thd_charset); } | UNDERSCORE_CHARSET TEXT_STRING { $$ = new Item_string($2.str,$2.length,Lex->charset); } | text_literal TEXT_STRING { ((Item_string*) $1)->append($2.str,$2.length); }; text_string: - TEXT_STRING { $$= new String($1.str,$1.length,current_thd->thd_charset); } + TEXT_STRING { $$= new String($1.str,$1.length,YYTHD->thd_charset); } | HEX_NUM { Item *tmp = new Item_varbinary($1.str,$1.length); @@ -3469,7 +3476,7 @@ param_marker: '?' { LEX *lex=Lex; - if (current_thd->prepare_command) + if (YYTHD->prepare_command) { lex->param_list.push_back($$=new Item_param()); lex->param_count++; @@ -3505,7 +3512,7 @@ insert_ident: table_wild: ident '.' '*' { $$ = new Item_field(NullS,$1.str,"*"); } | ident '.' ident '.' '*' - { $$ = new Item_field((current_thd->client_capabilities & + { $$ = new Item_field((YYTHD->client_capabilities & CLIENT_NO_SCHEMA ? NullS : $1.str),$3.str,"*"); }; order_ident: @@ -3530,7 +3537,7 @@ simple_ident: | ident '.' ident '.' ident { SELECT_LEX_NODE *sel=Select; - $$ = !sel->create_refs || sel->get_in_sum_expr() > 0 ? (Item*) new Item_field((current_thd->client_capabilities & CLIENT_NO_SCHEMA ? NullS :$1.str),$3.str,$5.str) : (Item*) new Item_ref((current_thd->client_capabilities & CLIENT_NO_SCHEMA ? NullS :$1.str),$3.str,$5.str); + $$ = !sel->create_refs || sel->get_in_sum_expr() > 0 ? (Item*) new Item_field((YYTHD->client_capabilities & CLIENT_NO_SCHEMA ? NullS :$1.str),$3.str,$5.str) : (Item*) new Item_ref((YYTHD->client_capabilities & CLIENT_NO_SCHEMA ? NullS :$1.str),$3.str,$5.str); }; @@ -3813,7 +3820,7 @@ option_value: } | PASSWORD equal text_or_password { - THD *thd=current_thd; + THD *thd=YYTHD; LEX_USER *user; if (!(user=(LEX_USER*) sql_alloc(sizeof(LEX_USER)))) YYABORT; @@ -3895,7 +3902,7 @@ table_lock: lock_option: READ_SYM { $$=TL_READ_NO_INSERT; } - | WRITE_SYM { $$=current_thd->update_lock_default; } + | WRITE_SYM { $$=YYTHD->update_lock_default; } | LOW_PRIORITY WRITE_SYM { $$=TL_WRITE_LOW_PRIORITY; } | READ_SYM LOCAL_SYM { $$= TL_READ; } ; @@ -4332,7 +4339,7 @@ singleval_subselect: singleval_subselect_init: select_init { - $$= new Item_singleval_subselect(current_thd, + $$= new Item_singleval_subselect(YYTHD, Lex->current_select->master_unit()-> first_select()); }; @@ -4347,7 +4354,7 @@ exists_subselect: exists_subselect_init: select_init { - $$= new Item_exists_subselect(current_thd, + $$= new Item_exists_subselect(YYTHD, Lex->current_select->master_unit()-> first_select()); }; From 4adb15f3fa83c2ca5b0d5586fa90d2b50dbedb61 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 27 Nov 2002 03:49:35 +0500 Subject: [PATCH 2/3] add new tests, new functions sql-bench/crash-me.sh: Add tests: - If double double quotes are allowed in identifiers. - Rollback rolls back meta data - NULL sort and NULL sort perserve. - remove one check of "serial". - (Column,Table,Named constraints) new test to crash me if the check syntax is only supported by the parser, but not done for real. - For all ..USER tests, (like current_user), add an extra test if ...USER() is supported. - Add tests for constants TRUE and FALSE - Add test of LIMIT # OFFSET (PostgreSQL syntax) - tests of a lot of new functions --- sql-bench/crash-me.sh | 249 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 228 insertions(+), 21 deletions(-) diff --git a/sql-bench/crash-me.sh b/sql-bench/crash-me.sh index 02e3072a3f9..5fa67773566 100644 --- a/sql-bench/crash-me.sh +++ b/sql-bench/crash-me.sh @@ -38,7 +38,7 @@ # as such, and clarify ones such as "mediumint" with comments such as # "3-byte int" or "same as xxx". -$version="1.58"; +$version="1.59"; use DBI; use Getopt::Long; @@ -253,6 +253,9 @@ check_and_report("\` as identifier quote",'quote_ident_with_`',[], 'select `A` from crash_me',[],"1",0); check_and_report("[] as identifier quote",'quote_ident_with_[',[], 'select [A] from crash_me',[],"1",0); +report('Double "" in identifiers as "','quote_ident_with_dbl_"', + 'create table crash_me1 ("abc""d" integer)', + 'drop table crash_me1'); report("Column alias","column_alias","select a as ab from crash_me"); report("Table alias","table_alias","select b.a from crash_me as b"); @@ -301,6 +304,7 @@ try_and_report("LIMIT number of rows","select_limit", ["with TOP", "select TOP 1 * from crash_me"]); report("SELECT with LIMIT #,#","select_limit2", "select * from crash_me limit 1,1"); +report("SELECT with LIMIT # OFFSET #","select_limit3", "select * from crash_me limit 1 offset 1"); # The following alter table commands MUST be kept together! if ($dbh->do("create table crash_q (a integer, b integer,c1 CHAR(10))")) @@ -434,6 +438,9 @@ report("hex strings (x'1ace')","hex_strings","select x'1ace' $end_query"); report_result("Value of logical operation (1=1)","logical_value", "select (1=1) $end_query"); +report_result("Value of TRUE","value_of_true","select TRUE $end_query"); +report_result("Value of FALSE","value_of_false","select FALSE $end_query"); + $logical_value= $limits{'logical_value'}; $false=0; @@ -584,7 +591,7 @@ print "$limits{'query_size'}\n"; "int not null identity,unique(q)", # postgres types "box","bool","circle","polygon","point","line","lseg","path", - "interval", "serial", "inet", "cidr", "macaddr", + "interval", "inet", "cidr", "macaddr", # oracle types "varchar2(16)","nvarchar2(16)","number(9,2)","number(9)", @@ -769,7 +776,6 @@ try_and_report("Automatic row id", "automatic_rowid", ["CURRENT_DATE","current_date","current_date",0,2], ["CURRENT_TIME","current_time","current_time",0,2], ["CURRENT_TIMESTAMP","current_timestamp","current_timestamp",0,2], - ["CURRENT_USER","current_user","current_user",0,2], ["EXTRACT","extract_sql","extract(minute from timestamp '2000-02-23 18:43:12.987')",43,0], ["LOCALTIME","localtime","localtime",0,2], ["LOCALTIMESTAMP","localtimestamp","localtimestamp",0,2], @@ -778,11 +784,8 @@ try_and_report("Automatic row id", "automatic_rowid", ["NULLIF with numbers","nullif_num","NULLIF(NULLIF(1,2),1)",undef(),4], ["OCTET_LENGTH","octet_length","octet_length('abc')",3,0], ["POSITION","position","position('ll' in 'hello')",3,0], - ["SESSION_USER","session_user","session_user",0,2], - ["SYSTEM_USER","system_user","system_user",0,2], ["TRIM","trim","trim(trailing from trim(LEADING FROM ' abc '))","abc",3], ["UPPER","upper","UPPER('abc')","ABC",1], - ["USER","user","user"], ["concatenation with ||","concat_as_||","'abc' || 'def'","abcdef",1], ); @@ -960,8 +963,61 @@ try_and_report("Automatic row id", "automatic_rowid", ["automatic num->string convert","auto_num2string","concat('a',2)","a2",1], ["automatic string->num convert","auto_string2num","'1'+2",3,0], ["concatenation with +","concat_as_+","'abc' + 'def'","abcdef",1], + ["SUBSTR (2 arg)",'substr2arg',"substr('abcd',2)",'bcd',1], #sapdb func + ["SUBSTR (3 arg)",'substr3arg',"substr('abcd',2,2)",'bc',1], + ["LFILL (3 arg)",'lfill3arg',"lfill('abcd','.',6)",'..abcd',1], + ["RFILL (3 arg)",'rfill3arg',"rfill('abcd','.',6)",'abcd..',1], + ["RPAD (4 arg)",'rpad4arg',"rpad('abcd',2,'+-',8)",'abcd+-+-',1], + ["LPAD (4 arg)",'rpad4arg',"lpad('abcd',2,'+-',8)",'+-+-abcd',1], + ["SAPDB compatible TRIM (1 arg)",'trim1arg',"trim(' abcd ')",'abcd',1], + ["SAPDB compatible TRIM (2 arg)",'trim2arg',"trim('..abcd..','.')",'abcd',1], + ["LTRIM (2 arg)",'ltrim2arg',"ltrim('..abcd..','.')",'abcd..',1], + ["RTRIM (2 arg)",'rtrim2arg',"rtrim('..abcd..','.')",'..abcd',1], + ["EXPAND",'expand2arg',"expand('abcd',6)",'abcd ',0], + ["REPLACE (2 arg) ",'replace2arg',"replace('AbCd','bC')",'Ad',1], + ["MAPCHAR",'mapchar',"mapchar('Aâ')",'Aa',1], + ["ALPHA",'alpha',"alpha('Aâ',2)",'AA',1], + ["ASCII in string cast",'ascii_string',"ascii('a')",'a',1], + ["EBCDIC in string cast",'ebcdic_string',"ebcdic('a')",'a',1], + ["TRUNC (1 arg)",'trunc1arg',"trunc(222.6)",222,0], + ["NOROUND",'noround',"noround(222.6)",222.6,0], + ["FIXED",'fixed',"fixed(222.6666,10,2)",'222.67',0], + ["FLOAT",'float',"float(6666.66,4)",6667,0], + ["LENGTH",'length',"length(1)",2,0], + ["INDEX",'index',"index('abcdefg','cd',1,1)",3,0], + ["ADDDATE",'adddate',"ADDDATE('20021201',3)",'20021204',0], + ["SUBDATE",'subdate',"SUBDATE('20021204',3)",'20021201',0], + ["DATEDIFF (2 arg)",'datediff2arg',"DATEDIFF('20021204','20021201')",'3',0], # sapdb + ["DAYOFWEEK with sapdb internal date as arg",'dayofweek_sapdb',"DAYOFWEEK('19630816')",'5',0], + ["WEEKOFYEAR",'weekofyear',"WEEKOFYEAR('19630816')",'33',0], + ["DAYOFMONTH with sapdb internal date as arg",'dayofmonth_sapdb',"dayofmonth('19630816')",'16',0], + ["DAYOFYEAR with sapdb internal date as arg",'dayofyear_sapdb',"DAYOFYEAR('19630816')",'228',0], + ["MAKEDATE",'makedate',"MAKEDATE(1963,228)",'19630816',0], + ["DAYNAME with sapdb internal date as arg",'dayname_sapdb',"DAYNAME('19630816')",'Friday',0], + ["MONTHNAME with sapdb internal date as arg",'monthname_sapdb',"MONTHNAME('19630816')",'August',0], + ["ADDTIME",'addtime',"ADDTIME('00200212','00000300')",'00200215',0], + ["SUBTIME",'subdate',"SUBDATE('00200215','00000300')",'00200212',0], + ["TIMEDIFF",'timediff',"TIMEDIFF('00200215','00200212')",'00000003',0], + ["MAKETIME",'maketime',"MAKETIME(20,02,12)",'00200212',0], + ["YEAR with sapdb internal date as arg",'year_sapdb',"YEAR('20021201')",'2002',0], + ["MONTH with sapdb internal date as arg",'month_sapdb',"MONTH('20021201')",'12',0], + ["DAY",'day',"DAY('20021201')",1,0], + ["HOUR with sapdb internal time as arg",'hour_sapdb',"HOUR('00200212')",20,0], + ["MINUTE with sapdb internal time as arg",'minute_sapdb',"MINUTE('00200212')",2,0], + ["SECOND with sapdb internal time as arg",'second_sapdb',"SECOND('00200212')",12,0], + ["MICROSECOND",'microsecond',"MICROSECOND('19630816200212111111')",'111111',0], + ["TIMESTAMP",'timestamp',"timestamp('19630816','00200212')",'19630816200212000000',0], + ["TIME",'time',"time('00200212')",'00200212',0], + ["DATE",'date',"date('19630816')",'19630816',0], + ["VALUE",'value',"value(NULL,'WALRUS')",'WALRUS',0], + ["DECODE",'decode',"DECODE('S-103','T72',1,'S-103',2,'Leopard',3)",2,0], + ["NUM",'num',"NUM('2123')",2123,0], + ["CHAR (conversation date)",'char_date',"CHAR(DATE('19630816'),EUR)",'16.08.1963',0], + ["CHR (any type to string)",'chr_str',"CHR(67)",'67',0], + ["HEX",'hex',"HEX('A')",41,0], ); + @sql_group_functions= ( ["AVG","avg","avg(a)",1,0], @@ -1131,6 +1187,20 @@ else } +if ($limits{'func_extra_noround'} eq 'yes') +{ + report("Ignoring NOROUND","ignoring_noround", + "create table crash_q (a int)", + "insert into crash_q values(noround(10.22))", + "drop table crash_q $drop_attr"); +} + +check_parenthesis("func_sql_","CURRENT_USER"); +check_parenthesis("func_sql_","SESSION_USER"); +check_parenthesis("func_sql_","SYSTEM_USER"); +check_parenthesis("func_sql_","USER"); + + report("LIKE on numbers","like_with_number", "create table crash_q (a int,b int)", "insert into crash_q values(10,10)", @@ -1561,19 +1631,29 @@ if (!defined($limits{"transactions"})) { my ($limit,$type); $limit="transactions"; + $limit_r="rollback_metadata"; print "$limit: "; foreach $type (('', 'type=bdb', 'type=innodb', 'type=gemini')) { undef($limits{$limit}); - last if (!report_trans($limit, + if (!report_trans($limit, [create_table("crash_q",["a integer not null"],[], $type), "insert into crash_q values (1)"], "select * from crash_q", "drop table crash_q $drop_attr" - )); + )) + { + report_rollback($limit_r, + [create_table("crash_q",["a integer not null"],[], + $type)], + "insert into crash_q values (1)", + "drop table crash_q $drop_attr" ); + last; + }; } print "$limits{$limit}\n"; + print "$limit_r: $limits{$limit_r}\n"; } report("atomic updates","atomic_updates", @@ -1644,14 +1724,29 @@ report("Column constraints","constraint_check", "create table crash_q (a int check (a>0))", "drop table crash_q $drop_attr"); +report("Ignoring column constraints","ignoring_constraint_check", + "create table crash_q (a int check (a>0))", + "insert into crash_q values(0)", + "drop table crash_q $drop_attr") if ($limits{'constraint_check'} eq 'yes'); + report("Table constraints","constraint_check_table", "create table crash_q (a int ,b int, check (a>b))", "drop table crash_q $drop_attr"); -report("Named constraints","constraint_check", +report("Ignoring table constraints","ignoring_constraint_check_table", + "create table crash_q (a int ,b int, check (a>b))", + "insert into crash_q values(0,0)", + "drop table crash_q $drop_attr") if ($limits{'constraint_check_table'} eq 'yes'); + +report("Named constraints","constraint_check_named", "create table crash_q (a int ,b int, constraint abc check (a>b))", "drop table crash_q $drop_attr"); +report("Ignoring named constraints","ignoring_constraint_check_named", + "create table crash_q (a int ,b int, constraint abc check (a>b))", + "insert into crash_q values(0,0)", + "drop table crash_q $drop_attr") if ($limits{'constraint_check_named'} eq 'yes'); + report("NULL constraint (SyBase style)","constraint_null", "create table crash_q (a int null)", "drop table crash_q $drop_attr"); @@ -2018,7 +2113,7 @@ $key="safe_decimal_arithmetic"; if (!defined($limits{$key})) { print "$prompt="; - save_incomplete($limit,$prompt); + save_incomplete($key,$prompt); if (!safe_query($server->create("crash_me_a",["a decimal(10,2)","b decimal(10,2)"]))) { print DBI->errstr(); @@ -2045,6 +2140,53 @@ if (!defined($limits{$key})) print "$prompt=$limits{$key} (cached)\n"; } +# Check where is null values in sorted recordset +if (!safe_query($server->create("crash_me_n",["i integer","r integer"]))) + { + print DBI->errstr(); + die "Can't create table 'crash_me_n' $DBI::errstr\n"; + }; +assert("insert into crash_me_n (i) values(1)"); +assert("insert into crash_me_n values(2,2)"); +assert("insert into crash_me_n values(3,3)"); +assert("insert into crash_me_n values(4,4)"); +assert("insert into crash_me_n (i) values(5)"); + +$key = "position_of_null"; +$prompt ="Where is null values in sorted recordset"; +if (!defined($limits{$key})) +{ + save_incomplete($key,$prompt); + print "$prompt="; + $sth=$dbh->prepare("select r from crash_me_n order by r "); + $sth->execute; + $limit= detect_null_position($sth); + $sth->finish; + print "$limit\n"; + save_config_data($key,$limit,$prompt); +} else { + print "$prompt=$limits{$key} (cache)\n"; +} + +$key = "position_of_null_desc"; +$prompt ="Where is null values in sorted recordset (DESC)"; +if (!defined($limits{$key})) +{ + save_incomplete($key,$prompt); + print "$prompt="; + $sth=$dbh->prepare("select r from crash_me_n order by r desc"); + $sth->execute; + $limit= detect_null_position($sth); + $sth->finish; + print "$limit\n"; + save_config_data($key,$limit,$prompt); +} else { + print "$prompt=$limits{$key} (cache)\n"; +} + + +assert("drop table crash_me_n $drop_attr"); + # # End of test @@ -2059,6 +2201,41 @@ $dbh->disconnect || warn $dbh->errstr; save_all_config_data(); exit 0; +# Check where is nulls in the sorted result (for) +# it expects exactly 5 rows in the result + +sub detect_null_position +{ + my $sth = shift; + my ($z,$r1,$r2,$r3,$r4,$r5); + $r1 = $sth->fetchrow_array; + $r2 = $sth->fetchrow_array; + $r3 = $sth->fetchrow_array; + $r4 = $sth->fetchrow_array; + $r5 = $sth->fetchrow_array; + return "first" if ( !defined($r1) && !defined($r2) && defined($r3)); + return "last" if ( !defined($r5) && !defined($r4) && defined($r3)); + return "random"; +} + +sub check_parenthesis { + my $prefix=shift; + my $fn=shift; + my $resultat='no'; + my $param_name=$prefix.lc($fn); + + save_incomplete($param_name,$fn); + if (safe_query("select $fn $end_query") == 1) + { + $resultat="yes"; + } + elsif ( safe_query("select $fn() $end_query") == 1) + { + $resultat="with_parenthesis"; + } + save_config_data($param_name,$resultat,$fn); +} + sub usage { print <rollback; - if ($rc) { - $dbh->{AutoCommit} = 1; + $dbh->rollback; + $dbh->{AutoCommit} = 1; if (safe_query_result($check,"","")) { save_config_data($limit,"yes",$limit); } safe_query($clear); - } else { - $dbh->{AutoCommit} = 1; - save_config_data($limit,"error",$limit); - } } else { save_config_data($limit,"error",$limit); } @@ -2603,6 +2775,39 @@ sub report_trans return $limits{$limit} ne "yes"; } +sub report_rollback +{ + my ($limit,$queries,$check,$clear)=@_; + if (!defined($limits{$limit})) + { + save_incomplete($limit,$prompt); + eval {undef($dbh->{AutoCommit})}; + if (!$@) + { + if (safe_query(\@$queries)) + { + $dbh->rollback; + $dbh->{AutoCommit} = 1; + if (safe_query($check)) { + save_config_data($limit,"no",$limit); + } else { + save_config_data($limit,"yes",$limit); + }; + safe_query($clear); + } else { + save_config_data($limit,"error",$limit); + } + } + else + { + save_config_data($limit,"error",$limit); + } + safe_query($clear); + } + $dbh->{AutoCommit} = 1; + return $limits{$limit} ne "yes"; +} + sub check_and_report { @@ -2929,7 +3134,7 @@ sub read_config_data { if ($key !~ /restart/i) { - $limits{$key}=$limit; + $limits{$key}=$limit eq "null"? undef : $limit; $prompts{$key}=length($prompt) ? substr($prompt,2) : ""; delete $limits{'restart'}; } @@ -2959,7 +3164,8 @@ sub save_config_data return if (defined($limits{$key}) && $limits{$key} eq $limit); if (!defined($limit) || $limit eq "") { - die "Undefined limit for $key\n"; +# die "Undefined limit for $key\n"; + $limit = 'null'; } print CONFIG_FILE "$key=$limit\t# $prompt\n"; $limits{$key}=$limit; @@ -3613,5 +3819,6 @@ sub check_query } + ### TODO: # OID test instead of / in addition to _rowid From 4826ed009186289b1b3f7a39a8bd0076cb85b712 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 26 Nov 2002 18:51:38 -0800 Subject: [PATCH 3/3] =?UTF-8?q?select=5Ftest.c,=20insert=5Ftest.c:=20=20?= =?UTF-8?q?=20Added=20my=5Fglobal.h=20to=20compile=20after=20my=5Flist.h?= =?UTF-8?q?=20is=20added=20to=20mysql.h=20sql=5Fprepare.cc:=20=20=20Handle?= =?UTF-8?q?=20close=20stmt=20from=20client=20=20=20Minor=20fixups=20to=20m?= =?UTF-8?q?ake=20SET=20variable=3D=3F=20to=20work=20sql=5Fparse.cc:=20=20?= =?UTF-8?q?=20Added=20missed=20COM=5FCLOSE=5FSTMT=20mysql=5Fpriv.h:=20=20?= =?UTF-8?q?=20Change=20mysql=5Fstmt=5Fclose=20to=20mysql=5Fstmt=5Ffree=20t?= =?UTF-8?q?o=20not=20to=20conflict=20with=20client=20type=20libmysql.c:=20?= =?UTF-8?q?=20=20Clean=20all=20open=20stmts=20during=20mysql=5Fclose()=20i?= =?UTF-8?q?mplicitly?= libmysql/libmysql.c: Clean all open stmts during mysql_close() implicitly sql/mysql_priv.h: Handle close_stmt from client Change mysql_stmt_close to mysql_stmt_free to not to conflict with client type sql/sql_parse.cc: Added missed COM_CLOSE_STMT sql/sql_prepare.cc: Handle close stmt from client Change mysql_stmt_close to mysql_stmt_free to not to conflict with client type Minor fixups to make SET variable=? to work client/insert_test.c: Added my_global.h to compile after my_list.h is added to mysql.h client/select_test.c: Added my_global.h to compile after my_list.h is added to mysql.h --- client/insert_test.c | 1 + client/select_test.c | 1 + include/mysql.h | 9 +++++++-- libmysql/libmysql.c | 43 ++++++++++++++++++++++++++++++++++-------- sql/mysql_priv.h | 2 +- sql/sql_parse.cc | 7 ++++++- sql/sql_prepare.cc | 45 +++++++++++++++++++++++++++----------------- 7 files changed, 79 insertions(+), 29 deletions(-) diff --git a/client/insert_test.c b/client/insert_test.c index 42691df6875..fb4890faf73 100644 --- a/client/insert_test.c +++ b/client/insert_test.c @@ -16,6 +16,7 @@ #include #include +#include #include "mysql.h" #define INSERT_QUERY "insert into test (name,num) values ('item %d', %d)" diff --git a/client/select_test.c b/client/select_test.c index ee2a9192865..d7f18c0f1f0 100644 --- a/client/select_test.c +++ b/client/select_test.c @@ -19,6 +19,7 @@ #endif #include #include +#include "my_global.h" #include "mysql.h" #define SELECT_QUERY "select name from test where num = %d" diff --git a/include/mysql.h b/include/mysql.h index 230c0aad9df..67558e39cdb 100644 --- a/include/mysql.h +++ b/include/mysql.h @@ -61,6 +61,8 @@ typedef int my_socket; #define CHECK_EXTRA_ARGUMENTS #endif +#include "my_list.h" /* for LISTs used in 'MYSQL' and 'MYSQL_STMT' */ + extern unsigned int mysql_port; extern char *mysql_unix_port; @@ -213,6 +215,8 @@ typedef struct st_mysql struct st_mysql* last_used_slave; /* needed for round-robin slave pick */ /* needed for send/read/store/use result to work correctly with replication */ struct st_mysql* last_used_con; + + LIST *stmts; /* list of all statements */ } MYSQL; @@ -457,6 +461,7 @@ typedef struct st_mysql_stmt MYSQL_RES *result; /* resultset */ MYSQL_BIND *bind; /* row binding */ MYSQL_FIELD *fields; /* prepare meta info */ + LIST list; /* list to keep track of all stmts */ char *query; /* query buffer */ MEM_ROOT mem_root; /* root allocations */ MYSQL_RES tmp_result; /* Used by mysql_prepare_result */ @@ -469,8 +474,8 @@ typedef struct st_mysql_stmt char last_error[MYSQL_ERRMSG_SIZE]; /* error message */ my_bool long_alloced; /* flag to indicate long alloced */ my_bool send_types_to_server; /* to indicate types supply to server */ - my_bool param_buffers; /* to indicate the param bound buffers */ - my_bool res_buffers; /* to indicate the result bound buffers */ + my_bool param_buffers; /* to indicate the param bound buffers */ + my_bool res_buffers; /* to indicate the output bound buffers */ } MYSQL_STMT; diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index 410be65660f..352ac520fed 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -114,6 +114,7 @@ static my_bool send_file_to_server(MYSQL *mysql,const char *filename); static sig_handler pipe_sig_handler(int sig); static ulong mysql_sub_escape_string(CHARSET_INFO *charset_info, char *to, const char *from, ulong length); +static my_bool stmt_close(MYSQL_STMT *stmt, my_bool skip_list); static my_bool org_my_init_done=0; @@ -2436,6 +2437,16 @@ mysql_close(MYSQL *mysql) } mysql->rpl_pivot=0; } + if (mysql->stmts) + { + /* Free any open prepared statements */ + LIST *element, *next_element; + for (element= mysql->stmts; element; element= next_element) + { + next_element= element->next; + stmt_close((MYSQL_STMT *)element->data, 0); + } + } if (mysql != mysql->master) mysql_close(mysql->master); if (mysql->free_me) @@ -3675,18 +3686,20 @@ mysql_prepare(MYSQL *mysql, const char *query, ulong length) } if (simple_command(mysql, COM_PREPARE, query, length, 1)) { - mysql_stmt_close(stmt); + stmt_close(stmt, 1); DBUG_RETURN(0); } init_alloc_root(&stmt->mem_root,8192,0); if (read_prepare_result(mysql, stmt)) { - mysql_stmt_close(stmt); + stmt_close(stmt, 1); DBUG_RETURN(0); } stmt->state= MY_ST_PREPARE; stmt->mysql= mysql; + mysql->stmts= list_add(mysql->stmts, &stmt->list); + stmt->list.data= stmt; DBUG_PRINT("info", ("Parameter count: %ld", stmt->param_count)); DBUG_RETURN(stmt); } @@ -4304,7 +4317,6 @@ my_bool STDCALL mysql_bind_result(MYSQL_STMT *stmt, MYSQL_BIND *bind) DBUG_RETURN(0); } - /* Fetch row data to bind buffers */ @@ -4387,27 +4399,42 @@ int STDCALL mysql_fetch(MYSQL_STMT *stmt) *********************************************************************/ /* - Close the statement handle by freeing all resources -*/ + Close the statement handle by freeing all alloced resources -my_bool STDCALL mysql_stmt_close(MYSQL_STMT *stmt) + SYNOPSIS + mysql_stmt_close() + stmt Statement handle + skip_list Flag to indicate delete from list or not + RETURN VALUES + 0 ok + 1 error +*/ +static my_bool stmt_close(MYSQL_STMT *stmt, my_bool skip_list) { my_bool error=0; DBUG_ENTER("mysql_stmt_close"); - if (stmt->state != MY_ST_UNKNOWN) + DBUG_ASSERT(stmt != 0); + if (stmt->state == MY_ST_PREPARE || stmt->state == MY_ST_EXECUTE) { char buff[4]; int4store(buff, stmt->stmt_id); - error= simple_command(stmt->mysql, COM_CLOSE_STMT, buff, 4, 0); + error= simple_command(stmt->mysql, COM_CLOSE_STMT, buff, 4, 1); } mysql_free_result(stmt->result); free_root(&stmt->mem_root, MYF(0)); my_free((gptr) stmt->query, MYF(MY_WME | MY_ALLOW_ZERO_PTR)); + if (!skip_list) + stmt->mysql->stmts= list_delete(stmt->mysql->stmts, &stmt->list); my_free((gptr) stmt, MYF(MY_WME)); DBUG_RETURN(error); } +my_bool STDCALL mysql_stmt_close(MYSQL_STMT *stmt) +{ + return stmt_close(stmt, 0); +} + /* Return statement error code */ diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 3ba88d493bd..d8c602d69fb 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -516,7 +516,7 @@ int compare_prep_stmt(void *not_used, PREP_STMT *stmt, ulong *key); void free_prep_stmt(PREP_STMT *stmt, TREE_FREE mode, void *not_used); bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length); void mysql_stmt_execute(THD *thd, char *packet); -void mysql_stm_close(THD *thd, char *packet); +void mysql_stmt_free(THD *thd, char *packet); void mysql_stmt_get_longdata(THD *thd, char *pos, ulong packet_length); int check_insert_fields(THD *thd,TABLE *table,List &fields, List &values, ulong counter); diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 263ac50120d..b1bdb3f6d0f 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -74,7 +74,7 @@ const char *command_name[]={ "Drop DB", "Refresh", "Shutdown", "Statistics", "Processlist", "Connect","Kill","Debug","Ping","Time","Delayed_insert","Change user", "Binlog Dump","Table Dump", "Connect Out", "Register Slave", - "Prepare", "Prepare Execute", "Long Data" + "Prepare", "Prepare Execute", "Long Data", "Close stmt" }; static char empty_c_string[1]= {0}; // Used for not defined 'db' @@ -1004,6 +1004,11 @@ bool dispatch_command(enum enum_server_command command, THD *thd, mysql_stmt_prepare(thd, packet, packet_length); break; } + case COM_CLOSE_STMT: + { + mysql_stmt_free(thd, packet); + break; + } case COM_QUERY: { if (alloc_query(thd, packet, packet_length)) diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 3ec12177778..fcae61d698e 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -20,32 +20,47 @@ This file contains the implementation of prepare and executes. Prepare: - - Server gets the query from client with command 'COM_PREPARE' + - Server gets the query from client with command 'COM_PREPARE'; + in the following format: + [COM_PREPARE:1] [query] - Parse the query and recognize any parameter markers '?' and - store its information list lex->param_list + store its information list in lex->param_list + - Allocate a new statement for this prepare; and keep this in + 'thd->prepared_statements' pool. - Without executing the query, return back to client the total number of parameters along with result-set metadata information - (if any) + (if any) in the following format: + [STMT_ID:4][Columns:2][Param_count:2][Columns meta info][Params meta info] Prepare-execute: - Server gets the command 'COM_EXECUTE' to execute the previously prepared query. If there is any param markers; then client will send the data in the following format: - [null_bits][types_specified(0/1)][[length][data]][[length][data] .. [length][data]. + [COM_EXECUTE:1] + [STMT_ID:4] + [NULL_BITS:(param_count+7)/8)] + [TYPES_SUPPLIED_BY_CLIENT(0/1):1] + [[length]data] + [[length]data] .. [[length]data]. + (Note: Except for string/binary types; all other types will not be + supplied with length field) - Replace the param items with this new data. If it is a first execute or types altered by client; then setup the conversion routines. - Execute the query without re-parsing and send back the results to client Long data handling: + - Server gets the long data in pieces with command type 'COM_LONG_DATA'. - The packet recieved will have the format as: - [COM_LONG_DATA:1][parameter_number:2][type:2][data] + [COM_LONG_DATA:1][STMT_ID:4][parameter_number:2][type:2][data] - Checks if the type is specified by client, and if yes reads the type, and stores the data in that format. - It's up to the client to check for read data ended. The server doesn't - care. + care; and also server doesn't notify to the client that it got the + data or not; if there is any error; then during execute; the error + will be returned ***********************************************************************/ @@ -238,9 +253,9 @@ static void setup_param_str(Item_param *param, uchar **pos) *pos+=len; } -static void setup_param_functions(Item_param *param, uchar read_pos) +static void setup_param_functions(Item_param *param, uchar param_type) { - switch (read_pos) { + switch (param_type) { case FIELD_TYPE_TINY: param->setup_param_func= setup_param_tiny; param->item_result_type = INT_RESULT; @@ -286,7 +301,6 @@ static bool setup_params_data(PREP_STMT *stmt) uchar *pos=(uchar*) thd->net.read_pos+1+MYSQL_STMT_HEADER; //skip header uchar *read_pos= pos+(stmt->param_count+7) / 8; //skip null bits - ulong param_no; if (*read_pos++) //types supplied / first execute { @@ -304,7 +318,7 @@ static bool setup_params_data(PREP_STMT *stmt) } param_iterator.rewind(); } - param_no= 0; + ulong param_no= 0; while ((param= (Item_param *)param_iterator++)) { if (!param->long_data_supplied) @@ -319,7 +333,6 @@ static bool setup_params_data(PREP_STMT *stmt) DBUG_RETURN(0); } - /* Validates insert fields */ @@ -473,7 +486,7 @@ static bool mysql_test_select_fields(PREP_STMT *stmt, TABLE_LIST *tables, List all_fields(fields); DBUG_ENTER("mysql_test_select_fields"); - if (!(table = open_ltable(thd,tables,tables->lock_type))) + if (!(table = open_ltable(thd,tables,TL_READ))) DBUG_RETURN(1); thd->used_tables=0; // Updated by setup_fields @@ -627,8 +640,8 @@ static bool init_param_items(THD *thd, PREP_STMT *stmt) { DBUG_PRINT("info",("param: %lx", to)); } - return 0; #endif + return 0; } /* @@ -671,7 +684,6 @@ bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length) stmt.mem_root= thd->mem_root; tree_insert(&thd->prepared_statements, (void *)&stmt, 0, (void *)0); thd->mem_root= thd_root; // restore main mem_root - thd->last_prepared_stmt= &stmt; DBUG_RETURN(0); err: @@ -722,7 +734,6 @@ void mysql_stmt_execute(THD *thd, char *packet) have re-check on setup_* and other things .. */ mysql_execute_command(stmt->thd); - thd->last_prepared_stmt= stmt; if (!(specialflag & SPECIAL_NO_PRIOR)) my_pthread_setprio(pthread_self(), WAIT_PRIOR); @@ -775,11 +786,11 @@ void mysql_stmt_reset(THD *thd, char *packet) Delete a prepared statement from memory */ -void mysql_stmt_close(THD *thd, char *packet) +void mysql_stmt_free(THD *thd, char *packet) { ulong stmt_id= uint4korr(packet); PREP_STMT *stmt; - DBUG_ENTER("mysql_stmt_close"); + DBUG_ENTER("mysql_stmt_free"); if (!(stmt=find_prepared_statement(thd, stmt_id, "close"))) {