From 287661e66cc1fea6730b357bb56d48c6d065ef43 Mon Sep 17 00:00:00 2001 From: unknown <monty@mysql.com> Date: Thu, 11 Dec 2003 06:24:08 +0200 Subject: [PATCH] Fixed a possible memory leak on MacOSX when using the shared libmysql.so library (Bug #2061) mysql_server_init() now returns error code if something went wrong (Bug #2062) Don't use my_fopen() when reading symlink information as this may cause problems when a lot of files are opened. Free thread keys with pthread_key_delete() instead of relying on automatic free. (Bug #2062) Fixed bug in UNION statement with alias '*'. (Bug #1249) Fixed a bug in DELETE ... ORDER BY ... LIMIT where the rows where not deleted in the proper order. (Bug #1024). FOUND_ROWS() could return incorrect number of rows after a query with an impossible WHERE condition. HOW DATABASES doesn't anymore show .sym files (on windows) that doesn't point to a valid directory. (Bug #1385) include/config-win.h: Ensure that USE_SYMDIR is set for all windows versions (This is set in makefiles, so this is just an extra safety measure) include/my_pthread.h: Fixed a possible memory leak on MacOSX when using the shared libmysql.so library (Bug #2061) include/my_sys.h: my_init() now returns error code if something went wrong include/mysql.h: mysql_once_init() now returns error code if something went wrong include/mysql_com.h: my_init() now returns error code if something went wrong libmysql/libmysql.c: mysql_server_init() and mysql_once_init() now returns error code if something went wrong (Bug #2062) mysql-test/r/limit.result: Update results mysql-test/r/select_found.result: Update results mysql-test/r/union.result: Update results mysql-test/t/limit.test: Added test for DELETE ... ORDER BY ... LIMIT (bug #1024) mysql-test/t/select_found.test: Added test for problem with impossible WHERE (Bug #1468) mysql-test/t/union.test: Added test for problem with alias '*' (Bug #1249) mysys/mf_pack.c: Don't use my_fopen() when reading symlink information as this may cause problems when a lot of files are opened. mysys/my_init.c: my_init() now returns error code if something went wrong mysys/my_lib.c: More debug information mysys/my_thr_init.c: Free thread keys with pthread_key_delete() instead of relying on automatic free. (Bug #2062) sql/sql_base.cc: Fixed bug in UNION statement with alias '*'. (Bug #1249) sql/sql_delete.cc: Fixed a bug in DELETE ... ORDER BY ... LIMIT where the rows where not deleted in the proper order. (Bug #1024). sql/sql_select.cc: FOUND_ROWS() could return incorrect number of rows after a query with an impossible WHERE condition. sql/sql_show.cc: SHOW DATABASES doesn't anymore show .sym files (on windows) that doesn't point to a valid directory. (Bug #1385) sql/sql_yacc.yy: Allow syntax UNION DISTINCT --- include/config-win.h | 4 ++++ include/my_pthread.h | 3 +++ include/my_sys.h | 2 +- include/mysql.h | 2 +- include/mysql_com.h | 2 +- libmysql/libmysql.c | 22 ++++++++++++++++------ mysql-test/r/limit.result | 23 ++++++++++++++++++++--- mysql-test/r/select_found.result | 19 +++++++++++++++++++ mysql-test/r/union.result | 6 +++++- mysql-test/t/limit.test | 22 +++++++++++++++++++--- mysql-test/t/select_found.test | 14 ++++++++++++++ mysql-test/t/union.test | 9 ++++++++- mysys/mf_pack.c | 27 ++++++++++++++------------- mysys/my_init.c | 20 +++++++++++++++----- mysys/my_lib.c | 6 ++++-- mysys/my_thr_init.c | 26 ++++++++++++++++++++------ sql/sql_base.cc | 7 ++++++- sql/sql_delete.cc | 12 +++++++++--- sql/sql_select.cc | 2 ++ sql/sql_show.cc | 12 ++++++++++++ sql/sql_yacc.yy | 1 + 21 files changed, 194 insertions(+), 47 deletions(-) diff --git a/include/config-win.h b/include/config-win.h index b30f50f0ed..e6f03a10af 100644 --- a/include/config-win.h +++ b/include/config-win.h @@ -151,6 +151,10 @@ typedef uint rf_SetTimer; #define USE_MB_IDENT 1 #define USE_STRCOLL 1 +/* All windows servers should support .sym files */ +#undef USE_SYMDIR +#define USE_SYMDIR + /* If LOAD DATA LOCAL INFILE should be enabled by default */ #define ENABLED_LOCAL_INFILE 1 diff --git a/include/my_pthread.h b/include/my_pthread.h index 16a14ac503..59367ee903 100644 --- a/include/my_pthread.h +++ b/include/my_pthread.h @@ -115,6 +115,7 @@ void pthread_exit(void *a); /* was #define pthread_exit(A) ExitThread(A)*/ #undef SAFE_MUTEX /* This will cause conflicts */ #define pthread_key(T,V) DWORD V #define pthread_key_create(A,B) ((*A=TlsAlloc())==0xFFFFFFFF) +#define pthread_key_delete(A) TlsFree(A) #define pthread_getspecific(A) (TlsGetValue(A)) #define my_pthread_getspecific(T,A) ((T) TlsGetValue(A)) #define my_pthread_getspecific_ptr(T,V) ((T) TlsGetValue(V)) @@ -123,6 +124,7 @@ void pthread_exit(void *a); /* was #define pthread_exit(A) ExitThread(A)*/ #else #define pthread_key(T,V) __declspec(thread) T V #define pthread_key_create(A,B) pthread_dummy(0) +#define pthread_key_delete(A) pthread_dummy(0) #define pthread_getspecific(A) (&(A)) #define my_pthread_getspecific(T,A) (&(A)) #define my_pthread_getspecific_ptr(T,V) (V) @@ -178,6 +180,7 @@ extern int pthread_mutex_destroy (pthread_mutex_t *); typedef int pthread_attr_t; /* Needed by Unixware 7.0.0 */ #define pthread_key_create(A,B) thr_keycreate((A),(B)) +#define pthread_key_delete(A) thr_keydelete(A) #define pthread_handler_decl(A,B) void *A(void *B) #define pthread_key(T,V) pthread_key_t V diff --git a/include/my_sys.h b/include/my_sys.h index df8b9759e5..acb4c01b4f 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -577,7 +577,7 @@ extern int my_snprintf(char* to, size_t n, const char* fmt, ...); extern int my_message(uint my_err, const char *str,myf MyFlags); extern int my_message_no_curses(uint my_err, const char *str,myf MyFlags); extern int my_message_curses(uint my_err, const char *str,myf MyFlags); -extern void my_init(void); +extern my_bool my_init(void); extern void my_end(int infoflag); extern int my_redel(const char *from, const char *to, int MyFlags); extern int my_copystat(const char *from, const char *to, int MyFlags); diff --git a/include/mysql.h b/include/mysql.h index 0c91266e19..3ffc014c44 100644 --- a/include/mysql.h +++ b/include/mysql.h @@ -426,7 +426,7 @@ int STDCALL mysql_drop_db(MYSQL *mysql, const char *DB); int simple_command(MYSQL *mysql,enum enum_server_command command, const char *arg, unsigned long length, my_bool skipp_check); unsigned long net_safe_read(MYSQL* mysql); -void mysql_once_init(void); +int mysql_once_init(void); extern my_bool server_inited; diff --git a/include/mysql_com.h b/include/mysql_com.h index a874034ba4..e183a0ed42 100644 --- a/include/mysql_com.h +++ b/include/mysql_com.h @@ -241,7 +241,7 @@ void hash_password(unsigned long *result, const char *password); /* Some other useful functions */ -void my_init(void); +my_bool my_init(void); int load_defaults(const char *conf_file, const char **groups, int *argc, char ***argv); my_bool my_thread_init(void); diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index 5fcc3ba5ee..607d8af6e5 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -102,8 +102,7 @@ int STDCALL mysql_server_init(int argc __attribute__((unused)), char **argv __attribute__((unused)), char **groups __attribute__((unused))) { - mysql_once_init(); - return 0; + return (int) mysql_once_init(); } void STDCALL mysql_server_end() @@ -1436,7 +1435,8 @@ STDCALL mysql_rpl_query_type(const char* q, int len) MYSQL * STDCALL mysql_init(MYSQL *mysql) { - mysql_once_init(); + if (mysql_once_init()) + return 0; if (!mysql) { if (!(mysql=(MYSQL*) my_malloc(sizeof(*mysql),MYF(MY_WME | MY_ZEROFILL)))) @@ -1476,15 +1476,20 @@ mysql_init(MYSQL *mysql) This function is called by mysql_init() and indirectly called by mysql_query(), so one should never have to call this from an outside program. + + RETURN + 0 ok + 1 could not initialize environment (out of memory or thread keys) */ -void mysql_once_init(void) +int mysql_once_init(void) { if (!mysql_client_init) { mysql_client_init=1; org_my_init_done=my_init_done; - my_init(); /* Will init threads */ + if (my_init()) /* Will init threads */ + return 1; init_client_errs(); if (!mysql_port) { @@ -1518,10 +1523,15 @@ void mysql_once_init(void) } #ifdef THREAD else - my_thread_init(); /* Init if new thread */ + { + if (my_thread_init()) /* Init if new thread */ + return 1; + } #endif + return 0; } + /************************************************************************** Fill in SSL part of MYSQL structure and set 'use_ssl' flag. NB! Errors are not reported until you do mysql_real_connect. diff --git a/mysql-test/r/limit.result b/mysql-test/r/limit.result index 5a8edc99c1..c82105e6a4 100644 --- a/mysql-test/r/limit.result +++ b/mysql-test/r/limit.result @@ -36,9 +36,7 @@ a b 3 4 drop table t1; create table t1 (i int); -insert into t1 (i) values(1); -insert into t1 (i) values(1); -insert into t1 (i) values(1); +insert into t1 (i) values(1),(1),(1); delete from t1 limit 1; update t1 set i=2 limit 1; delete from t1 limit 0; @@ -50,3 +48,22 @@ i drop table t1; select 0 limit 0; 0 +CREATE TABLE t1(id int auto_increment primary key, id2 int, index(id2)); +INSERT INTO t1 (id2) values (0),(0),(0); +DELETE FROM t1 WHERE id=1; +INSERT INTO t1 SET id2=0; +SELECT * FROM t1; +id id2 +4 0 +2 0 +3 0 +DELETE FROM t1 WHERE id2 = 0 ORDER BY id LIMIT 1; +SELECT * FROM t1; +id id2 +4 0 +3 0 +DELETE FROM t1 WHERE id2 = 0 ORDER BY id desc LIMIT 1; +SELECT * FROM t1; +id id2 +3 0 +DROP TABLE t1; diff --git a/mysql-test/r/select_found.result b/mysql-test/r/select_found.result index 0a7f464cf7..419ffb73d5 100644 --- a/mysql-test/r/select_found.result +++ b/mysql-test/r/select_found.result @@ -169,3 +169,22 @@ SELECT FOUND_ROWS(); FOUND_ROWS() 2 drop table t1; +create table t1 (id int, primary key (id)); +insert into t1 values (1), (2), (3), (4), (5); +select SQL_CALC_FOUND_ROWS * from t1 where id > 3 limit 0, 1; +id +4 +select FOUND_ROWS(); +FOUND_ROWS() +2 +select SQL_CALC_FOUND_ROWS * from t1 where id > 3 AND 1=2 limit 0, 1; +id +select FOUND_ROWS(); +FOUND_ROWS() +0 +select SQL_CALC_FOUND_ROWS * from t1 where id > 6 limit 0, 1; +id +select FOUND_ROWS(); +FOUND_ROWS() +0 +drop table t1; diff --git a/mysql-test/r/union.result b/mysql-test/r/union.result index cd5d600edf..fc5aa1ad0c 100644 --- a/mysql-test/r/union.result +++ b/mysql-test/r/union.result @@ -3,7 +3,7 @@ CREATE TABLE t1 (a int not null, b char (10) not null); insert into t1 values(1,'a'),(2,'b'),(3,'c'),(3,'c'); CREATE TABLE t2 (a int not null, b char (10) not null); insert into t2 values (3,'c'),(4,'d'),(5,'f'),(6,'e'); -select a,b from t1 union select a,b from t2; +select a,b from t1 union distinct select a,b from t2; a b 1 a 2 b @@ -423,3 +423,7 @@ create temporary table t1 select a from t1 union select a from t2; create table t1 select a from t1 union select a from t2; INSERT TABLE 't1' isn't allowed in FROM table list drop table t1,t2; +select length(version()) > 1 as `*` UNION select 2; +* +1 +2 diff --git a/mysql-test/t/limit.test b/mysql-test/t/limit.test index d4f6ce186c..32962073ee 100644 --- a/mysql-test/t/limit.test +++ b/mysql-test/t/limit.test @@ -19,9 +19,7 @@ select * from t1; drop table t1; create table t1 (i int); -insert into t1 (i) values(1); -insert into t1 (i) values(1); -insert into t1 (i) values(1); +insert into t1 (i) values(1),(1),(1); delete from t1 limit 1; update t1 set i=2 limit 1; delete from t1 limit 0; @@ -29,4 +27,22 @@ update t1 set i=3 limit 0; select * from t1; drop table t1; +# LIMIT 0 + select 0 limit 0; + +# +# Test with DELETE, ORDER BY and limit (bug #1024) +# + +CREATE TABLE t1(id int auto_increment primary key, id2 int, index(id2)); +INSERT INTO t1 (id2) values (0),(0),(0); +DELETE FROM t1 WHERE id=1; +INSERT INTO t1 SET id2=0; +SELECT * FROM t1; +DELETE FROM t1 WHERE id2 = 0 ORDER BY id LIMIT 1; +# should have deleted WHERE id=2 +SELECT * FROM t1; +DELETE FROM t1 WHERE id2 = 0 ORDER BY id desc LIMIT 1; +SELECT * FROM t1; +DROP TABLE t1; diff --git a/mysql-test/t/select_found.test b/mysql-test/t/select_found.test index 0a483c860c..f5ee4d5c01 100644 --- a/mysql-test/t/select_found.test +++ b/mysql-test/t/select_found.test @@ -85,3 +85,17 @@ INSERT INTO t1 (titre,maxnumrep) VALUES SELECT SQL_CALC_FOUND_ROWS titre,numeropost,maxnumrep FROM t1 WHERE numeropost IN (1,2) ORDER BY maxnumrep DESC LIMIT 0, 1; SELECT FOUND_ROWS(); drop table t1; + +# +# Test problem with impossible WHERE (Bug #1468) +# + +create table t1 (id int, primary key (id)); +insert into t1 values (1), (2), (3), (4), (5); +select SQL_CALC_FOUND_ROWS * from t1 where id > 3 limit 0, 1; +select FOUND_ROWS(); +select SQL_CALC_FOUND_ROWS * from t1 where id > 3 AND 1=2 limit 0, 1; +select FOUND_ROWS(); +select SQL_CALC_FOUND_ROWS * from t1 where id > 6 limit 0, 1; +select FOUND_ROWS(); +drop table t1; diff --git a/mysql-test/t/union.test b/mysql-test/t/union.test index ba4673e9a8..badfe4b9a3 100644 --- a/mysql-test/t/union.test +++ b/mysql-test/t/union.test @@ -8,7 +8,7 @@ insert into t1 values(1,'a'),(2,'b'),(3,'c'),(3,'c'); CREATE TABLE t2 (a int not null, b char (10) not null); insert into t2 values (3,'c'),(4,'d'),(5,'f'),(6,'e'); -select a,b from t1 union select a,b from t2; +select a,b from t1 union distinct select a,b from t2; select a,b from t1 union all select a,b from t2; select a,b from t1 union all select a,b from t2 order by b; select a,b from t1 union all select a,b from t2 union select 7,'g'; @@ -227,3 +227,10 @@ create temporary table t1 select a from t1 union select a from t2; --error 1093 create table t1 select a from t1 union select a from t2; drop table t1,t2; + +# +# Problem with alias '*' (BUG #1249) +# + +select length(version()) > 1 as `*` UNION select 2; + diff --git a/mysys/mf_pack.c b/mysys/mf_pack.c index b3aa347006..e2e811fe89 100644 --- a/mysys/mf_pack.c +++ b/mysys/mf_pack.c @@ -210,13 +210,13 @@ uint cleanup_dirname(register my_string to, const char *from) } /* cleanup_dirname */ - /* - On system where you don't have symbolic links, the following - code will allow you to create a file: - directory-name.lnk that should contain the real path - to the directory. This will be used if the directory name - doesn't exists - */ +/* + On system where you don't have symbolic links, the following + code will allow you to create a file: + directory-name.sym that should contain the real path + to the directory. This will be used if the directory name + doesn't exists +*/ my_bool my_use_symdir=0; /* Set this if you want to use symdirs */ @@ -228,16 +228,17 @@ void symdirget(char *dir) char *pos=strend(dir); if (dir[0] && pos[-1] != FN_DEVCHAR && access(dir, F_OK)) { - FILE *fp; + File file; + uint length; char temp= *(--pos); /* May be "/" or "\" */ strmov(pos,".sym"); - fp = my_fopen(dir, O_RDONLY,MYF(0)); + file= my_open(dir, O_RDONLY, MYF(0)); *pos++=temp; *pos=0; /* Restore old filename */ - if (fp) + if (file >= 0) { - if (fgets(buff, sizeof(buff)-1, fp)) + if ((length= my_read(file, buff, sizeof(buff), MYF(0))) > 0) { - for (pos=strend(buff); + for (pos= buff + length ; pos > buff && (iscntrl(pos[-1]) || isspace(pos[-1])) ; pos --); @@ -247,7 +248,7 @@ void symdirget(char *dir) strmake(dir,buff, (uint) (pos-buff)); } - my_fclose(fp,MYF(0)); + my_close(file, MYF(0)); } } } diff --git a/mysys/my_init.c b/mysys/my_init.c index a8a184a2cb..8d4ba2c97b 100644 --- a/mysys/my_init.c +++ b/mysys/my_init.c @@ -62,13 +62,22 @@ static ulong atoi_octal(const char *str) } - /* Init my_sys functions and my_sys variabels */ +/* + Init my_sys functions and my_sys variabels + + SYNOPSIS + my_init() -void my_init(void) + RETURN + 0 ok + 1 Couldn't initialize environment +*/ + +my_bool my_init(void) { my_string str; if (my_init_done) - return; + return 0; my_init_done=1; #if defined(THREAD) && defined(SAFE_MUTEX) safe_mutex_global_init(); /* Must be called early */ @@ -78,7 +87,8 @@ void my_init(void) #if defined(HAVE_PTHREAD_INIT) pthread_init(); /* Must be called before DBUG_ENTER */ #endif - my_thread_global_init(); + if (my_thread_global_init()) + return 1; #if !defined( __WIN__) && !defined(OS2) && !defined(__NETWARE__) sigfillset(&my_signals); /* signals blocked by mf_brkhant */ #endif @@ -110,7 +120,7 @@ void my_init(void) #ifdef __WIN__ win32_init_tcp_ip(); #endif - DBUG_VOID_RETURN; + DBUG_RETURN(0); } } /* my_init */ diff --git a/mysys/my_lib.c b/mysys/my_lib.c index 035bafd07b..426acedc64 100644 --- a/mysys/my_lib.c +++ b/mysys/my_lib.c @@ -602,9 +602,11 @@ MY_STAT *my_stat(const char *path, MY_STAT *stat_area, myf my_flags) if ((m_used= (stat_area == NULL))) if (!(stat_area = (MY_STAT *) my_malloc(sizeof(MY_STAT), my_flags))) goto error; - if ( ! stat((my_string) path, (struct stat *) stat_area) ) + if (! stat((my_string) path, (struct stat *) stat_area) ) DBUG_RETURN(stat_area); - my_errno=errno; + + DBUG_PRINT("error",("Got errno: %d from stat", errno)); + my_errno= errno; if (m_used) /* Free if new area */ my_free((gptr) stat_area,MYF(0)); diff --git a/mysys/my_thr_init.c b/mysys/my_thr_init.c index 9f64e9dcb6..3827b24ac3 100644 --- a/mysys/my_thr_init.c +++ b/mysys/my_thr_init.c @@ -44,12 +44,23 @@ pthread_mutexattr_t my_fast_mutexattr; pthread_mutexattr_t my_errchk_mutexattr; #endif +/* + initialize thread environment + + SYNOPSIS + my_thread_global_init() + + RETURN + 0 ok + 1 error (Couldn't create THR_KEY_mysys) +*/ + my_bool my_thread_global_init(void) { - if (pthread_key_create(&THR_KEY_mysys,free)) + if (pthread_key_create(&THR_KEY_mysys,0)) { fprintf(stderr,"Can't initialize threads: error %d\n",errno); - exit(1); + return 1; } #ifdef PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP pthread_mutexattr_init(&my_fast_mutexattr); @@ -79,15 +90,18 @@ my_bool my_thread_global_init(void) #ifndef HAVE_GETHOSTBYNAME_R pthread_mutex_init(&LOCK_gethostbyname_r,MY_MUTEX_INIT_SLOW); #endif - return my_thread_init(); + if (my_thread_init()) + { + my_thread_global_end(); /* Clean up */ + return 1; + } + return 0; } void my_thread_global_end(void) { -#if defined(USE_TLS) - (void) TlsFree(THR_KEY_mysys); -#endif + pthread_key_delete(THR_KEY_mysys); #ifdef PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP pthread_mutexattr_destroy(&my_fast_mutexattr); #endif diff --git a/sql/sql_base.cc b/sql/sql_base.cc index e4694adb9a..dd80062d6e 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1868,8 +1868,13 @@ int setup_fields(THD *thd, TABLE_LIST *tables, List<Item> &fields, while ((item=it++)) { + /* + Expand * to all fields if this is not the temporary table for an + a UNION result + */ if (item->type() == Item::FIELD_ITEM && - ((Item_field*) item)->field_name[0] == '*') + ((Item_field*) item)->field_name[0] == '*' && + !((Item_field*) item)->field) { uint elem=fields.elements; if (insert_fields(thd,tables,((Item_field*) item)->db_name, diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 34a79ecd78..ee2b720907 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -78,7 +78,7 @@ int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ORDER *order, DBUG_RETURN(-1); if ((select && select->check_quick(thd, test(thd->options & OPTION_SAFE_UPDATES), - limit)) || + limit)) || !limit) { delete select; @@ -117,13 +117,19 @@ int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ORDER *order, if (setup_order(thd, &tables, fields, all_fields, order) || !(sortorder=make_unireg_sortorder(order, &length)) || (table->found_records = filesort(table, sortorder, length, - (SQL_SELECT *) 0, 0L, HA_POS_ERROR, + select, 0L, HA_POS_ERROR, &examined_rows)) == HA_POS_ERROR) { delete select; - DBUG_RETURN(-1); // This will force out message + DBUG_RETURN(-1); // This will force out message } + /* + Filesort has already found and selected the rows we want to delete, + so we don't need the where clause + */ + delete select; + select= 0; } init_read_record(&info,thd,table,select,1,1); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index df4b0226ff..892ad02bb5 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -3273,6 +3273,8 @@ return_zero_rows(JOIN *join, select_result *result,TABLE_LIST *tables, } result->send_eof(); // Should be safe } + /* Update results for FOUND_ROWS */ + join->thd->limit_found_rows= join->thd->examined_row_count= 0; DBUG_RETURN(0); } diff --git a/sql/sql_show.cc b/sql/sql_show.cc index a7de04d0bf..cb6cd18b7c 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -197,7 +197,19 @@ mysql_find_files(THD *thd,List<char> *files, const char *db,const char *path, #ifdef USE_SYMDIR char *ext; if (my_use_symdir && !strcmp(ext=fn_ext(file->name), ".sym")) + { + /* Only show the sym file if it points to a directory */ + char buff[FN_REFLEN], *end; + MY_STAT status; *ext=0; /* Remove extension */ + unpack_dirname(buff, file->name); + end= strend(buff); + if (end != buff && end[-1] == FN_LIBCHAR) + end[-1]= 0; // Remove end FN_LIBCHAR + if (!my_stat(buff, &status, MYF(0)) || + !MY_S_ISDIR(status.st_mode)) + continue; + } else #endif { diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 0383730090..b5b9a4cdfb 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -4014,5 +4014,6 @@ optional_order_or_limit: union_option: /* empty */ {} + | DISTINCT {} | ALL { Lex->union_option=1; } ; -- 2.30.9