diff --git a/BitKeeper/etc/logging_ok b/BitKeeper/etc/logging_ok index 092b6f3f2a5..89f03d96369 100644 --- a/BitKeeper/etc/logging_ok +++ b/BitKeeper/etc/logging_ok @@ -44,6 +44,7 @@ jorge@linux.jorge.mysql.com kaj@work.mysql.com lenz@kallisto.mysql.com lenz@mysql.com +miguel@hegel.(none) miguel@hegel.br miguel@hegel.local miguel@light. @@ -84,6 +85,7 @@ sasha@mysql.sashanet.com serg@build.mysql2.com serg@serg.mylan serg@serg.mysql.com +serg@sergbook.mylan serg@sergbook.mysql.com sinisa@rhols221.adsl.netsonic.fi tfr@beta.frontier86.ee diff --git a/acinclude.m4 b/acinclude.m4 index 4d7900acc3d..abeb2024f4a 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -711,7 +711,7 @@ AC_DEFUN(MYSQL_FIND_OPENSSL, [ done for d in /usr/ssl/lib /usr/local/ssl/lib /usr/lib/openssl \ -/usr/lib /opt/ssl/lib /opt/openssl/lib /usr/local/lib/ ; do +/usr/lib /usr/lib64 /opt/ssl/lib /opt/openssl/lib /usr/local/lib/ ; do if test -f $d/libssl.a ; then OPENSSL_LIB=$d fi @@ -721,7 +721,7 @@ AC_DEFUN(MYSQL_FIND_OPENSSL, [ echo "Could not find an installation of OpenSSL" if test -n "$OPENSSL_LIB" ; then if test "$IS_LINUX" = "true"; then - echo "Looks like you've forgotted to install OpenSSL development RPM" + echo "Looks like you've forgotten to install OpenSSL development RPM" fi fi exit 1 diff --git a/client/mysqlbinlog.cc b/client/mysqlbinlog.cc index 75b875b4f4e..9ef340197a7 100644 --- a/client/mysqlbinlog.cc +++ b/client/mysqlbinlog.cc @@ -396,8 +396,8 @@ static int check_header(IO_CACHE* file) if (buf[4] == START_EVENT) { uint event_len; - event_len = uint4korr(buf + 4); - old_format = (event_len < LOG_EVENT_HEADER_LEN + START_HEADER_LEN); + event_len = uint4korr(buf + EVENT_LEN_OFFSET); + old_format = (event_len < (LOG_EVENT_HEADER_LEN + START_HEADER_LEN)); } } my_b_seek(file, pos); diff --git a/configure.in b/configure.in index 9b6a174b0fb..a33ccd4a311 100644 --- a/configure.in +++ b/configure.in @@ -757,7 +757,7 @@ AC_CHECK_LIB(crypt, crypt) AC_CHECK_FUNC(crypt, AC_DEFINE(HAVE_CRYPT)) # For sem_xxx functions on Solaris 2.6 -AC_CHECK_FUNC(sem_init, , AC_CHECK_LIB(posix4)) +AC_CHECK_FUNC(sem_init, , AC_CHECK_LIB(posix4, sem_init)) # For compress in zlib MYSQL_CHECK_ZLIB_WITH_COMPRESS($with_named_zlib) diff --git a/innobase/dict/dict0dict.c b/innobase/dict/dict0dict.c index 2fc05b1923f..b1d7b5f762e 100644 --- a/innobase/dict/dict0dict.c +++ b/innobase/dict/dict0dict.c @@ -494,6 +494,46 @@ dict_index_get_nth_col_pos( return(ULINT_UNDEFINED); } +/************************************************************************ +Returns TRUE if the index contains a column or a prefix of that column. */ + +ibool +dict_index_contains_col_or_prefix( +/*==============================*/ + /* out: TRUE if contains the column or its + prefix */ + dict_index_t* index, /* in: index */ + ulint n) /* in: column number */ +{ + dict_field_t* field; + dict_col_t* col; + ulint pos; + ulint n_fields; + + ut_ad(index); + ut_ad(index->magic_n == DICT_INDEX_MAGIC_N); + + if (index->type & DICT_CLUSTERED) { + + return(TRUE); + } + + col = dict_table_get_nth_col(index->table, n); + + n_fields = dict_index_get_n_fields(index); + + for (pos = 0; pos < n_fields; pos++) { + field = dict_index_get_nth_field(index, pos); + + if (col == field->col) { + + return(TRUE); + } + } + + return(FALSE); +} + /************************************************************************ Looks for a matching field in an index. The column and the prefix len have to be the same. */ diff --git a/innobase/include/dict0dict.h b/innobase/include/dict0dict.h index e88c6a52bcb..b5ec5381db2 100644 --- a/innobase/include/dict0dict.h +++ b/innobase/include/dict0dict.h @@ -569,6 +569,16 @@ dict_index_get_nth_col_pos( dict_index_t* index, /* in: index */ ulint n); /* in: column number */ /************************************************************************ +Returns TRUE if the index contains a column or a prefix of that column. */ + +ibool +dict_index_contains_col_or_prefix( +/*==============================*/ + /* out: TRUE if contains the column or its + prefix */ + dict_index_t* index, /* in: index */ + ulint n); /* in: column number */ +/************************************************************************ Looks for a matching field in an index. The column and the prefix len has to be the same. */ diff --git a/innobase/page/page0page.c b/innobase/page/page0page.c index ef5dad60c08..e087941a970 100644 --- a/innobase/page/page0page.c +++ b/innobase/page/page0page.c @@ -446,7 +446,6 @@ page_copy_rec_list_end_no_locks( page_cur_move_to_next(&cur1); } - /* Track a memory corruption bug in Windows */ ut_a(mach_read_from_2(new_page + UNIV_PAGE_SIZE - 10) == PAGE_INFIMUM); page_cur_set_before_first(new_page, &cur2); @@ -456,11 +455,23 @@ page_copy_rec_list_end_no_locks( sup = page_get_supremum_rec(page); while (sup != page_cur_get_rec(&cur1)) { - ut_a( - page_cur_rec_insert(&cur2, page_cur_get_rec(&cur1), mtr)); + if (!page_cur_rec_insert(&cur2, + page_cur_get_rec(&cur1), mtr)) { + /* Track an assertion failure reported on the mailing + list on June 18th, 2003 */ + + buf_page_print(new_page); + buf_page_print(page); + ut_print_timestamp(stderr); + + fprintf(stderr, +"InnoDB: rec offset %lu, cur1 offset %lu, cur2 offset %lu\n", + (ulint)(rec - page), + (ulint)(page_cur_get_rec(&cur1) - page), + (ulint)(page_cur_get_rec(&cur2) - new_page)); + ut_a(0); + } - ut_a(mach_read_from_2(new_page + UNIV_PAGE_SIZE - 10) - == PAGE_INFIMUM); page_cur_move_to_next(&cur1); page_cur_move_to_next(&cur2); } diff --git a/innobase/row/row0ins.c b/innobase/row/row0ins.c index 23da0b9b93c..e02859bc851 100644 --- a/innobase/row/row0ins.c +++ b/innobase/row/row0ins.c @@ -791,27 +791,30 @@ row_ins_foreign_check_on_constraint( mem_heap_free(tmp_heap); clust_rec = btr_pcur_get_rec(cascade->pcur); - } - if (!page_rec_is_user_rec(clust_rec)) { - fprintf(stderr, + if (!page_rec_is_user_rec(clust_rec) + || btr_pcur_get_low_match(cascade->pcur) + < dict_index_get_n_unique(clust_index)) { + + fprintf(stderr, "InnoDB: error in cascade of a foreign key op\n" "InnoDB: index %s table %s\n", index->name, index->table->name); - rec_sprintf(err_buf, 900, rec); - fprintf(stderr, "InnoDB: record %s\n", err_buf); + rec_sprintf(err_buf, 900, rec); + fprintf(stderr, "InnoDB: record %s\n", err_buf); - rec_sprintf(err_buf, 900, clust_rec); - fprintf(stderr, "InnoDB: clustered record %s\n", err_buf); - - fprintf(stderr, + rec_sprintf(err_buf, 900, clust_rec); + fprintf(stderr, "InnoDB: clustered record %s\n", + err_buf); + fprintf(stderr, "InnoDB: Make a detailed bug report and send it\n"); - fprintf(stderr, "InnoDB: to mysql@lists.mysql.com\n"); + fprintf(stderr, "InnoDB: to mysql@lists.mysql.com\n"); - err = DB_SUCCESS; + err = DB_SUCCESS; - goto nonstandard_exit_func; + goto nonstandard_exit_func; + } } /* Set an X-lock on the row to delete or update in the child table */ diff --git a/innobase/row/row0sel.c b/innobase/row/row0sel.c index 114ebf870b0..a263de74e3e 100644 --- a/innobase/row/row0sel.c +++ b/innobase/row/row0sel.c @@ -609,7 +609,29 @@ row_sel_get_clust_rec( clust_rec = btr_pcur_get_rec(&(plan->clust_pcur)); - ut_ad(page_rec_is_user_rec(clust_rec)); + /* Note: only if the search ends up on a non-infimum record is the + low_match value the real match to the search tuple */ + + if (!page_rec_is_user_rec(clust_rec) + || btr_pcur_get_low_match(&(plan->clust_pcur)) + < dict_index_get_n_unique(index)) { + + ut_a(rec_get_deleted_flag(rec)); + ut_a(node->read_view); + + /* In a rare case it is possible that no clust rec is found + for a delete-marked secondary index record: if in row0umod.c + in row_undo_mod_remove_clust_low() we have already removed + the clust rec, while purge is still cleaning and removing + secondary index records associated with earlier versions of + the clustered index record. In that case we know that the + clustered index record did not exist in the read view of + trx. */ + + clust_rec = NULL; + + goto func_exit; + } if (!node->read_view) { /* Try to place a lock on the index record */ @@ -672,6 +694,7 @@ row_sel_get_clust_rec( row_sel_fetch_columns(index, clust_rec, UT_LIST_GET_FIRST(plan->columns)); +func_exit: *out_rec = clust_rec; return(DB_SUCCESS); @@ -1253,6 +1276,8 @@ rec_loop: /* PHASE 3: Get previous version in a consistent read */ + cons_read_requires_clust_rec = FALSE; + if (consistent_read) { /* This is a non-locking consistent read: if necessary, fetch a previous version of the record */ @@ -2269,7 +2294,10 @@ row_sel_get_clust_rec_for_mysql( /* out: DB_SUCCESS or error code */ row_prebuilt_t* prebuilt,/* in: prebuilt struct in the handle */ dict_index_t* sec_index,/* in: secondary index where rec resides */ - rec_t* rec, /* in: record in a non-clustered index */ + rec_t* rec, /* in: record in a non-clustered index; if + this is a locking read, then rec is not + allowed to be delete-marked, and that would + not make sense either */ que_thr_t* thr, /* in: query thread */ rec_t** out_rec,/* out: clustered record or an old version of it, NULL if the old version did not exist @@ -2285,7 +2313,7 @@ row_sel_get_clust_rec_for_mysql( ulint err; trx_t* trx; char err_buf[1000]; - + *out_rec = NULL; row_build_row_ref_in_tuple(prebuilt->clust_ref, sec_index, rec); @@ -2298,26 +2326,47 @@ row_sel_get_clust_rec_for_mysql( clust_rec = btr_pcur_get_rec(prebuilt->clust_pcur); - if (!page_rec_is_user_rec(clust_rec)) { - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: error clustered record for sec rec not found\n" - "InnoDB: index %s table %s\n", sec_index->name, - sec_index->table->name); + /* Note: only if the search ends up on a non-infimum record is the + low_match value the real match to the search tuple */ - rec_sprintf(err_buf, 900, rec); - fprintf(stderr, "InnoDB: sec index record %s\n", err_buf); + if (!page_rec_is_user_rec(clust_rec) + || btr_pcur_get_low_match(prebuilt->clust_pcur) + < dict_index_get_n_unique(clust_index)) { + + /* In a rare case it is possible that no clust rec is found + for a delete-marked secondary index record: if in row0umod.c + in row_undo_mod_remove_clust_low() we have already removed + the clust rec, while purge is still cleaning and removing + secondary index records associated with earlier versions of + the clustered index record. In that case we know that the + clustered index record did not exist in the read view of + trx. */ - rec_sprintf(err_buf, 900, clust_rec); - fprintf(stderr, "InnoDB: clust index record %s\n", err_buf); + if (!rec_get_deleted_flag(rec) + || prebuilt->select_lock_type != LOCK_NONE) { - trx = thr_get_trx(thr); - trx_print(err_buf, trx); + ut_print_timestamp(stderr); + fprintf(stderr, + " InnoDB: error clustered record for sec rec not found\n" + "InnoDB: index %s table %s\n", sec_index->name, + sec_index->table->name); - fprintf(stderr, - "%s\nInnoDB: Make a detailed bug report and send it\n", - err_buf); - fprintf(stderr, "InnoDB: to mysql@lists.mysql.com\n"); + rec_sprintf(err_buf, 900, rec); + fprintf(stderr, + "InnoDB: sec index record %s\n", err_buf); + + rec_sprintf(err_buf, 900, clust_rec); + fprintf(stderr, + "InnoDB: clust index record %s\n", err_buf); + + trx = thr_get_trx(thr); + trx_print(err_buf, trx); + + fprintf(stderr, + "%s\nInnoDB: Make a detailed bug report and send it\n", + err_buf); + fprintf(stderr, "InnoDB: to mysql@lists.mysql.com\n"); + } clust_rec = NULL; @@ -2989,8 +3038,6 @@ rec_loop: /*-------------------------------------------------------------*/ /* PHASE 4: Look for matching records in a loop */ - cons_read_requires_clust_rec = FALSE; - rec = btr_pcur_get_rec(pcur); /* printf("Using index %s cnt %lu ", index->name, cnt); @@ -3145,6 +3192,8 @@ rec_loop: /* We are ready to look at a possible new index entry in the result set: the cursor is now placed on a user record */ + cons_read_requires_clust_rec = FALSE; + if (prebuilt->select_lock_type != LOCK_NONE) { /* Try to place a lock on the index record; note that delete marked records are a special case in a unique search. If there @@ -3170,8 +3219,6 @@ rec_loop: /* This is a non-locking consistent read: if necessary, fetch a previous version of the record */ - cons_read_requires_clust_rec = FALSE; - if (trx->isolation_level == TRX_ISO_READ_UNCOMMITTED) { /* Do nothing: we let a non-locking SELECT read the @@ -3215,7 +3262,7 @@ rec_loop: if (rec_get_deleted_flag(rec) && !cons_read_requires_clust_rec) { - /* The record is delete marked: we can skip it if this is + /* The record is delete-marked: we can skip it if this is not a consistent read which might see an earlier version of a non-clustered index record */ @@ -3324,7 +3371,7 @@ got_row: goto normal_return; next_rec: - /*-------------------------------------------------------------*/ + /*-------------------------------------------------------------*/ /* PHASE 5: Move the cursor to the next index record */ if (mtr_has_extra_clust_latch) { diff --git a/innobase/row/row0vers.c b/innobase/row/row0vers.c index 91aaba40812..d4a463d8a96 100644 --- a/innobase/row/row0vers.c +++ b/innobase/row/row0vers.c @@ -59,7 +59,6 @@ row_vers_impl_x_locked_off_kernel( ibool rec_del; ulint err; mtr_t mtr; - char err_buf[1000]; ut_ad(mutex_own(&kernel_mutex)); ut_ad(!rw_lock_own(&(purge_sys->latch), RW_LOCK_SHARED)); @@ -77,22 +76,20 @@ row_vers_impl_x_locked_off_kernel( clust_rec = row_get_clust_rec(BTR_SEARCH_LEAF, rec, index, &clust_index, &mtr); if (!clust_rec) { - rec_sprintf(err_buf, 900, rec); + /* In a rare case it is possible that no clust rec is found + for a secondary index record: if in row0umod.c + row_undo_mod_remove_clust_low() we have already removed the + clust rec, while purge is still cleaning and removing + secondary index records associated with earlier versions of + the clustered index record. In that case there cannot be + any implicit lock on the secondary index record, because + an active transaction which has modified the secondary index + record has also modified the clustered index record. And in + a rollback we always undo the modifications to secondary index + records before the clustered index record. */ - ut_print_timestamp(stderr); - fprintf(stderr, -" InnoDB: Error: cannot find the clustered index record\n" -"InnoDB: for a secondary index record in table %s index %s.\n" -"InnoDB: Secondary index record %s.\n" -"InnoDB: The table is probably corrupt. Please run CHECK TABLE on it.\n" -"InnoDB: You can try to repair the table by dump + drop + reimport.\n" -"InnoDB: Send a detailed bug report to mysql@lists.mysql.com.\n", - index->table_name, index->name, err_buf); - mutex_enter(&kernel_mutex); - mtr_commit(&mtr); - - /* We assume there is no lock on the record, though this - is not certain because the table is apparently corrupt */ + mutex_enter(&kernel_mutex); + mtr_commit(&mtr); return(NULL); } diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index c008d625900..3c8ac9f3387 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -40,14 +40,17 @@ #include #include #ifdef HAVE_SELECT_H -# include +#include #endif #ifdef HAVE_SYS_SELECT_H #include #endif +#ifdef HAVE_POLL +#include #endif +#endif /* !defined(MSDOS) && !defined(__WIN__) */ #ifdef HAVE_SYS_UN_H -# include +#include #endif #if defined(THREAD) && !defined(__WIN__) #include /* because of signal() */ @@ -148,9 +151,12 @@ static MYSQL* spawn_init(MYSQL* parent, const char* host, const char* user, const char* passwd); +#if !(defined(__WIN__) || defined(OS2) || defined(__NETWARE__)) +static int wait_for_data(my_socket fd, uint timeout); +#endif /**************************************************************************** - A modified version of connect(). connect2() allows you to specify + A modified version of connect(). my_connect() allows you to specify a timeout value, in seconds, that we should wait until we derermine we can't connect to a particular host. If timeout is 0, my_connect() will behave exactly like connect(). @@ -158,17 +164,13 @@ static MYSQL* spawn_init(MYSQL* parent, const char* host, Base version coded by Steve Bernacki, Jr. *****************************************************************************/ -int my_connect(my_socket s, const struct sockaddr *name, uint namelen, +int my_connect(my_socket fd, const struct sockaddr *name, uint namelen, uint timeout) { #if defined(__WIN__) || defined(OS2) || defined(__NETWARE__) - return connect(s, (struct sockaddr*) name, namelen); + return connect(fd, (struct sockaddr*) name, namelen); #else int flags, res, s_err; - SOCKOPT_OPTLEN_TYPE s_err_size = sizeof(uint); - fd_set sfds; - struct timeval tv; - time_t start_time, now_time; /* If they passed us a timeout of zero, we should behave @@ -176,30 +178,68 @@ int my_connect(my_socket s, const struct sockaddr *name, uint namelen, */ if (timeout == 0) - return connect(s, (struct sockaddr*) name, namelen); + return connect(fd, (struct sockaddr*) name, namelen); - flags = fcntl(s, F_GETFL, 0); /* Set socket to not block */ + flags = fcntl(fd, F_GETFL, 0); /* Set socket to not block */ #ifdef O_NONBLOCK - fcntl(s, F_SETFL, flags | O_NONBLOCK); /* and save the flags.. */ + fcntl(fd, F_SETFL, flags | O_NONBLOCK); /* and save the flags.. */ #endif - res = connect(s, (struct sockaddr*) name, namelen); - s_err = errno; /* Save the error... */ - fcntl(s, F_SETFL, flags); + res= connect(fd, (struct sockaddr*) name, namelen); + s_err= errno; /* Save the error... */ + fcntl(fd, F_SETFL, flags); if ((res != 0) && (s_err != EINPROGRESS)) { - errno = s_err; /* Restore it */ + errno= s_err; /* Restore it */ return(-1); } if (res == 0) /* Connected quickly! */ return(0); + return wait_for_data(fd, timeout); +#endif +} + + +/* + Wait up to timeout seconds for a connection to be established. + + We prefer to do this with poll() as there is no limitations with this. + If not, we will use select() +*/ + +#if !(defined(__WIN__) || defined(OS2) || defined(__NETWARE__)) + +static int wait_for_data(my_socket fd, uint timeout) +{ +#ifdef HAVE_POLL + struct pollfd ufds; + int res; + + ufds.fd= fd; + ufds.events= POLLIN | POLLPRI; + if (!(res= poll(&ufds, 1, (int) timeout*1000))) + { + errno= EINTR; + return -1; + } + if (res < 0 || !(ufds.revents & (POLLIN | POLLPRI))) + return -1; + return 0; +#else + SOCKOPT_OPTLEN_TYPE s_err_size = sizeof(uint); + fd_set sfds; + struct timeval tv; + time_t start_time, now_time; + int res, s_err; + + if (fd >= FD_SETSIZE) /* Check if wrong error */ + return 0; /* Can't use timeout */ /* - Otherwise, our connection is "in progress." We can use - the select() call to wait up to a specified period of time - for the connection to suceed. If select() returns 0 - (after waiting howevermany seconds), our socket never became - writable (host is probably unreachable.) Otherwise, if + Our connection is "in progress." We can use the select() call to wait + up to a specified period of time for the connection to suceed. + If select() returns 0 (after waiting howevermany seconds), our socket + never became writable (host is probably unreachable.) Otherwise, if select() returns 1, then one of two conditions exist: 1. An error occured. We use getsockopt() to check for this. @@ -212,7 +252,7 @@ int my_connect(my_socket s, const struct sockaddr *name, uint namelen, */ FD_ZERO(&sfds); - FD_SET(s, &sfds); + FD_SET(fd, &sfds); /* select could be interrupted by a signal, and if it is, the timeout should be adjusted and the select restarted @@ -226,10 +266,10 @@ int my_connect(my_socket s, const struct sockaddr *name, uint namelen, tv.tv_sec = (long) timeout; tv.tv_usec = 0; #if defined(HPUX10) && defined(THREAD) - if ((res = select(s+1, NULL, (int*) &sfds, NULL, &tv)) > 0) + if ((res = select(fd+1, NULL, (int*) &sfds, NULL, &tv)) > 0) break; #else - if ((res = select(s+1, NULL, &sfds, NULL, &tv)) > 0) + if ((res = select(fd+1, NULL, &sfds, NULL, &tv)) > 0) break; #endif if (res == 0) /* timeout */ @@ -247,7 +287,7 @@ int my_connect(my_socket s, const struct sockaddr *name, uint namelen, */ s_err=0; - if (getsockopt(s, SOL_SOCKET, SO_ERROR, (char*) &s_err, &s_err_size) != 0) + if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (char*) &s_err, &s_err_size) != 0) return(-1); if (s_err) @@ -256,9 +296,9 @@ int my_connect(my_socket s, const struct sockaddr *name, uint namelen, return(-1); /* but return an error... */ } return (0); /* ok */ - -#endif +#endif /* HAVE_POLL */ } +#endif /* defined(__WIN__) || defined(OS2) || defined(__NETWARE__) */ /* Create a named pipe connection diff --git a/mysql-test/mysql-test-run.sh b/mysql-test/mysql-test-run.sh index 1d25a4d0e3d..55adc3d88fc 100644 --- a/mysql-test/mysql-test-run.sh +++ b/mysql-test/mysql-test-run.sh @@ -569,7 +569,9 @@ error () { } error_is () { - $CAT < $TIMEFILE | $SED -e 's/.* At line \(.*\)\: \(.*\)/ \>\> Error at line \1: \2<\ var/slave-data/master.info; system chmod 000 var/slave-data/master.info; connection slave; drop table if exists t1, t2, t3, t4; +# START SLAVE will fail because it can't read the file (mode 000) (system error 13) --error 1201 slave start; system chmod 600 var/slave-data/master.info; +# It will fail again because the file is empty so the slave cannot get valuable +# info about how to connect to the master from it (failure in +# init_strvar_from_file() in init_master_info()). --error 1201 slave start; --replace_result 3306 MASTER_PORT 9306 MASTER_PORT 3334 MASTER_PORT 3336 MASTER_PORT -# Will get error 13 on Unix systems becasue file is not readable -!eval change master to master_host='127.0.0.1',master_port=$MASTER_MYPORT, master_user='root'; +# CHANGE MASTER will fail because it first parses master.info before changing it +# (so when master.info is bad, people have to use RESET SLAVE first). +--error 1201 +eval change master to master_host='127.0.0.1',master_port=$MASTER_MYPORT, master_user='root'; reset slave; --replace_result 3306 MASTER_PORT 9306 MASTER_PORT 3334 MASTER_PORT 3336 MASTER_PORT eval change master to master_host='127.0.0.1',master_port=$MASTER_MYPORT, master_user='root'; @@ -73,12 +79,9 @@ insert into t2 values(1234); #same value on the master connection master; -save_master_pos; set insert_id=1234; insert into t2 values(NULL); connection slave; -sync_with_master; - wait_for_slave_to_stop; #restart slave skipping one event diff --git a/mysql-test/t/sel000100.test b/mysql-test/t/sel000100.test index cedb78b17e7..d587fa4ebd0 100644 --- a/mysql-test/t/sel000100.test +++ b/mysql-test/t/sel000100.test @@ -29,3 +29,18 @@ GROUP BY t1.id ORDER BY link; drop table t1,t2; + +# +# test case for #674 +# +CREATE TABLE t1 ( + html varchar(5) default NULL, + rin int(11) default '0', + out int(11) default '0' +) TYPE=MyISAM; + +INSERT INTO t1 VALUES ('1',1,0); + +SELECT DISTINCT html,SUM(out)/(SUM(rin)+1) as 'prod' FROM t1 GROUP BY rin; + +drop table t1; diff --git a/mysys/mf_pack.c b/mysys/mf_pack.c index 8fba14f626b..b3aa347006e 100644 --- a/mysys/mf_pack.c +++ b/mysys/mf_pack.c @@ -253,15 +253,27 @@ void symdirget(char *dir) } #endif /* USE_SYMDIR */ - /* Unpacks dirname to name that can be used by open... */ - /* Make that last char of to is '/' if from not empty and - from doesn't end in FN_DEVCHAR */ - /* Uses cleanup_dirname and changes ~/.. to home_dir/.. */ - /* Returns length of new directory */ + +/* + Fixes a directroy name so that can be used by open() + + SYNOPSIS + unpack_dirname() + to Store result here. May be = from + from 'Packed' directory name (may contain ~) + + IMPLEMENTATION + Make that last char of to is '/' if from not empty and + from doesn't end in FN_DEVCHAR + Uses cleanup_dirname and changes ~/.. to home_dir/.. + + Changes a UNIX filename to system filename (replaces / with \ on windows) + + RETURN + Length of new directory name (= length of to) +*/ uint unpack_dirname(my_string to, const char *from) - - /* to may be == from */ { uint length,h_length; char buff[FN_REFLEN+1+4],*suffix,*tilde_expansion; diff --git a/sql/Makefile.am b/sql/Makefile.am index a589f1379f9..e2494e50d96 100644 --- a/sql/Makefile.am +++ b/sql/Makefile.am @@ -114,8 +114,8 @@ sql_yacc.o: sql_yacc.cc sql_yacc.h $(CXXCOMPILE) $(LM_CFLAGS) -c $< lex_hash.h: lex.h gen_lex_hash.cc sql_yacc.h - $(MAKE) gen_lex_hash - ./gen_lex_hash > $@ + $(MAKE) gen_lex_hash$(EXEEXT) + ./gen_lex_hash$(EXEEXT) > $@ # Hack to ensure that lex_hash.h is built early sql_lex.o: lex_hash.h diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 795cffc0776..6e5a14cfb05 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -1863,7 +1863,11 @@ build_template( if (prebuilt->read_just_key) { /* MySQL has instructed us that it is enough to - fetch the columns in the key */ + fetch the columns in the key; looks like MySQL + can set this flag also when there is only a + prefix of the column in the key: in that case we + retrieve the whole column from the clustered + index */ fetch_all_in_key = TRUE; } else { @@ -1924,9 +1928,8 @@ build_template( field = table->field[i]; if (templ_type == ROW_MYSQL_REC_FIELDS - && !(fetch_all_in_key && - ULINT_UNDEFINED != dict_index_get_nth_col_pos( - index, i)) + && !(fetch_all_in_key + && dict_index_contains_col_or_prefix(index, i)) && thd->query_id != field->query_id && thd->query_id != (field->query_id ^ MAX_ULONG_BIT) && thd->query_id != @@ -4127,6 +4130,12 @@ ha_innobase::analyze( return(0); } + +int ha_innobase::optimize(THD* thd, HA_CHECK_OPT* check_opt) +{ + return ha_innobase::analyze(thd,check_opt); +} + /*********************************************************************** Tries to check that an InnoDB table is not corrupted. If corruption is noticed, prints to stderr information about it. In case of corruption diff --git a/sql/ha_innodb.h b/sql/ha_innodb.h index a3fe56f6bcd..86f409aff67 100644 --- a/sql/ha_innodb.h +++ b/sql/ha_innodb.h @@ -159,6 +159,7 @@ class ha_innobase: public handler void position(const byte *record); void info(uint); int analyze(THD* thd,HA_CHECK_OPT* check_opt); + int optimize(THD* thd,HA_CHECK_OPT* check_opt); int extra(enum ha_extra_function operation); int reset(void); int external_lock(THD *thd, int lock_type); diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 208be1ecd7f..9d4f7641b1d 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -1539,37 +1539,46 @@ void Item_func_elt::update_used_tables() double Item_func_elt::val() { uint tmp; + null_value=1; if ((tmp=(uint) item->val_int()) == 0 || tmp > arg_count) - { - null_value=1; return 0.0; - } + + double result= args[tmp-1]->val(); + if (args[tmp-1]->is_null()) + return 0.0; + null_value=0; - return args[tmp-1]->val(); + return result; } longlong Item_func_elt::val_int() { uint tmp; + null_value=1; if ((tmp=(uint) item->val_int()) == 0 || tmp > arg_count) - { - null_value=1; return 0; - } + + int result= args[tmp-1]->val_int(); + if (args[tmp-1]->is_null()) + return 0; + null_value=0; - return args[tmp-1]->val_int(); + return result; } String *Item_func_elt::val_str(String *str) { uint tmp; + null_value=1; if ((tmp=(uint) item->val_int()) == 0 || tmp > arg_count) - { - null_value=1; return NULL; - } + + String *result= args[tmp-1]->val_str(str); + if (args[tmp-1]->is_null()) + return NULL; + null_value=0; - return args[tmp-1]->val_str(str); + return result; } diff --git a/sql/log_event.cc b/sql/log_event.cc index ff968babcf0..53289888242 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -100,7 +100,7 @@ static void pretty_print_str(String* packet, char* str, int len) static inline char* slave_load_file_stem(char*buf, uint file_id, int event_server_id) { - fn_format(buf,"SQL_LOAD-",slave_load_tmpdir,"",0); /* 4+32); */ + fn_format(buf,"SQL_LOAD-",slave_load_tmpdir, "", MY_UNPACK_FILENAME); buf = strend(buf); buf = int10_to_str(::server_id, buf, 10); *buf++ = '-'; @@ -168,19 +168,22 @@ static void cleanup_load_tmpdir() uint i; if (!(dirp=my_dir(slave_load_tmpdir,MYF(MY_WME)))) return; - + char fname[FN_REFLEN]; for (i=0 ; i < (uint)dirp->number_off_files; i++) { file=dirp->dir_entry+i; if (is_prefix(file->name,"SQL_LOAD-")) - my_delete(file->name, MYF(0)); + { + fn_format(fname,file->name,slave_load_tmpdir,"",MY_UNPACK_FILENAME); + my_delete(fname, MYF(0)); + } } my_dirend(dirp); } - #endif + Log_event::Log_event(const char* buf, bool old_format) :temp_buf(0), cached_event_len(0), cache_stmt(0) { @@ -813,7 +816,7 @@ Rotate_log_event::Rotate_log_event(const char* buf, int event_len, int Rotate_log_event::write_data(IO_CACHE* file) { char buf[ROTATE_HEADER_LEN]; - int8store(buf, pos + R_POS_OFFSET); + int8store(buf + R_POS_OFFSET, pos); return (my_b_safe_write(file, (byte*)buf, ROTATE_HEADER_LEN) || my_b_safe_write(file, (byte*)new_log_ident, (uint) ident_len)); } diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 0f3500248c0..5613f1eeb07 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -2322,6 +2322,12 @@ The server will not act as a slave."); opt_binlog_index_name,LOG_BIN); using_update_log=1; } + else if (opt_log_slave_updates) + { + sql_print_error("\ +Warning: you need to use --log-bin to make --log-slave-updates work. \ +Now disabling --log-slave-updates."); + } if (opt_bootstrap) { @@ -3179,7 +3185,8 @@ enum options { OPT_BDB_CACHE_SIZE, OPT_BDB_LOG_BUFFER_SIZE, OPT_BDB_MAX_LOCK, - OPT_ERROR_LOG_FILE + OPT_ERROR_LOG_FILE, + OPT_DEFAULT_WEEK_FORMAT }; @@ -3988,6 +3995,11 @@ replicating a LOAD DATA INFILE command", (gptr*) &global_system_variables.net_wait_timeout, (gptr*) &max_system_variables.net_wait_timeout, 0, GET_ULONG, REQUIRED_ARG, NET_WAIT_TIMEOUT, 1, LONG_TIMEOUT, 0, 1, 0}, + { "default-week-format", OPT_DEFAULT_WEEK_FORMAT, + "The default week format used by WEEK() functions.", + (gptr*) &global_system_variables.default_week_format, + (gptr*) &max_system_variables.default_week_format, + 0, GET_ULONG, REQUIRED_ARG, 0, 0, 3L, 0, 1, 0}, {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} }; diff --git a/sql/nt_servc.cc b/sql/nt_servc.cc index b917c91ce15..b18d3d00d88 100644 --- a/sql/nt_servc.cc +++ b/sql/nt_servc.cc @@ -462,7 +462,7 @@ BOOL NTService::SeekStatus(LPCSTR szInternName, int OperationType) { /* a remove operation */ if (!(service = OpenService(scm,szInternName, SERVICE_ALL_ACCESS ))) - printf("The service doesn't exists!\n"); + printf("The service doesn't exist!\n"); else { SERVICE_STATUS ss; diff --git a/sql/set_var.cc b/sql/set_var.cc index 1da187598c4..32603ec51d9 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -296,6 +296,8 @@ static sys_var_slave_skip_counter sys_slave_skip_counter("sql_slave_skip_counter static sys_var_rand_seed1 sys_rand_seed1("rand_seed1"); static sys_var_rand_seed2 sys_rand_seed2("rand_seed2"); +static sys_var_thd_ulong sys_default_week_format("default_week_format", + &SV::default_week_format); /* List of all variables for initialisation and storage in hash @@ -316,6 +318,7 @@ sys_var *sys_variables[]= &sys_bulk_insert_buff_size, &sys_concurrent_insert, &sys_connect_timeout, + &sys_default_week_format, &sys_convert_charset, &sys_delay_key_write, &sys_delayed_insert_limit, @@ -421,6 +424,7 @@ struct show_var_st init_vars[]= { {sys_connect_timeout.name, (char*) &sys_connect_timeout, SHOW_SYS}, {sys_convert_charset.name, (char*) &sys_convert_charset, SHOW_SYS}, {"datadir", mysql_real_data_home, SHOW_CHAR}, + {"default_week_format", (char*) &sys_default_week_format, SHOW_SYS}, {sys_delay_key_write.name, (char*) &sys_delay_key_write, SHOW_SYS}, {sys_delayed_insert_limit.name, (char*) &sys_delayed_insert_limit,SHOW_SYS}, {sys_delayed_insert_timeout.name, (char*) &sys_delayed_insert_timeout, SHOW_SYS}, diff --git a/sql/slave.cc b/sql/slave.cc index dc9ce9715d8..fe668900da0 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -134,7 +134,7 @@ int init_slave() goto err; } - if(init_master_info(active_mi,master_info_file,relay_log_info_file, + if (init_master_info(active_mi,master_info_file,relay_log_info_file, !master_host)) { sql_print_error("Failed to initialize the master info structure"); @@ -1644,6 +1644,7 @@ int show_master_info(THD* thd, MASTER_INFO* mi) if (mi->host[0]) { + DBUG_PRINT("info",("host is set: '%s'", mi->host)); String *packet= &thd->packet; packet->length(0); @@ -1776,18 +1777,17 @@ int st_relay_log_info::wait_for_pos(THD* thd, String* log_name, pthread_mutex_lock(&data_lock); /* - This function will abort when it notices that - some CHANGE MASTER or RESET MASTER has changed - the master info. To catch this, these commands - modify abort_pos_wait ; we just monitor abort_pos_wait - and see if it has changed. - Why do we have this mechanism instead of simply monitoring slave_running in - the loop (we do this too), as CHANGE MASTER/RESET SLAVE require that the - SQL thread be stopped? This is in case + This function will abort when it notices that some CHANGE MASTER or + RESET MASTER has changed the master info. + To catch this, these commands modify abort_pos_wait ; We just monitor + abort_pos_wait and see if it has changed. + Why do we have this mechanism instead of simply monitoring slave_running + in the loop (we do this too), as CHANGE MASTER/RESET SLAVE require that + the SQL thread be stopped? + This is becasue if someones does: STOP SLAVE;CHANGE MASTER/RESET SLAVE; START SLAVE; - happens very quickly between the moment pthread_cond_wait() wakes up and - the while() is evaluated: in that case slave_running is again 1 when the - while() is evaluated. + the change may happen very quickly and we may not notice that + slave_running briefly switches between 1/0/1. */ init_abort_pos_wait= abort_pos_wait; @@ -1808,7 +1808,7 @@ int st_relay_log_info::wait_for_pos(THD* thd, String* log_name, error= -2; //means improper arguments goto err; } - //p points to '.' + /* p points to '.' */ log_name_extension= strtoul(++p, &p_end, 10); /* p_end points to the first invalid character. @@ -1821,14 +1821,9 @@ int st_relay_log_info::wait_for_pos(THD* thd, String* log_name, goto err; } - //"compare and wait" main loop + /* The "compare and wait" main loop */ while (!thd->killed && init_abort_pos_wait == abort_pos_wait && - /* - formerly we tested mi->slave_running, but what we care about is - rli->slave_running (because this concerns the SQL thread, while - mi->slave_running concerns the I/O thread). - */ slave_running) { bool pos_reached; diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 12ea3a94464..6b7cfa7dc9e 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -1,4 +1,4 @@ -/* Copyright (C) 2000 MySQL AB +/* Copyright (C) 2000-2003 MySQL AB 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 @@ -193,7 +193,7 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables) host.db= get_field(&mem, table,1); host.access= get_access(table,2); host.access= fix_rights_for_db(host.access); - host.sort= get_sort(2,host.host.hostname,host.db); + host.sort= get_sort(2,host.host.hostname,host.db); #ifndef TO_BE_REMOVED if (table->fields == 8) { // Without grant @@ -213,8 +213,7 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables) if (table->field[2]->field_length == 8 && protocol_version == PROTOCOL_VERSION) { - sql_print_error( - "Old 'user' table. (Check README or the Reference manual). Continuing --old-protocol"); /* purecov: tested */ + sql_print_error("Old 'user' table. (Check README or the Reference manual). Continuing --old-protocol"); /* purecov: tested */ protocol_version=9; /* purecov: tested */ } @@ -247,7 +246,7 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables) user.sort=get_sort(2,user.host.hostname,user.user); user.hostname_length= (user.host.hostname ? (uint) strlen(user.host.hostname) : 0); - if (table->fields >= 31) /* Starting from 4.0.2 we have more fields */ + if (table->fields >= 31) /* Starting from 4.0.2 we have more fields */ { char *ssl_type=get_field(&mem, table, 24); if (!ssl_type) @@ -259,7 +258,7 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables) else /* !strcmp(ssl_type, "SPECIFIED") */ user.ssl_type=SSL_TYPE_SPECIFIED; - user.ssl_cipher= get_field(&mem, table, 25); + user.ssl_cipher= get_field(&mem, table, 25); user.x509_issuer= get_field(&mem, table, 26); user.x509_subject= get_field(&mem, table, 27); @@ -368,7 +367,14 @@ void acl_free(bool end) } } - /* Reload acl list if possible */ + +/* + Forget current privileges and read new privileges from the privilege tables + + SYNOPSIS + acl_reload() + thd Thread handle +*/ void acl_reload(THD *thd) { @@ -493,8 +499,8 @@ static int acl_compare(ACL_ACCESS *a,ACL_ACCESS *b) ulong acl_getroot(THD *thd, const char *host, const char *ip, const char *user, const char *password,const char *message, - char **priv_user, char *priv_host, - bool old_ver, USER_RESOURCES *mqh) + char **priv_user, char *priv_host, + bool old_ver, USER_RESOURCES *mqh) { ulong user_access=NO_ACCESS; *priv_user=(char*) user; @@ -526,15 +532,15 @@ ulong acl_getroot(THD *thd, const char *host, const char *ip, const char *user, { #ifdef HAVE_OPENSSL Vio *vio=thd->net.vio; - /* + /* In this point we know that user is allowed to connect from given host by given username/password pair. Now we check if SSL is required, if user is using SSL and if X509 certificate attributes are OK */ - switch (acl_user->ssl_type) { + switch (acl_user->ssl_type) { case SSL_TYPE_NOT_SPECIFIED: // Impossible - case SSL_TYPE_NONE: /* SSL is not required to connect */ + case SSL_TYPE_NONE: /* SSL is not required to connect */ user_access=acl_user->access; break; case SSL_TYPE_ANY: /* Any kind of SSL is good enough */ @@ -544,7 +550,7 @@ ulong acl_getroot(THD *thd, const char *host, const char *ip, const char *user, case SSL_TYPE_X509: /* Client should have any valid certificate. */ /* We need to check for absence of SSL because without SSL - we should reject connection. + we should reject connection. */ if (vio_type(vio) == VIO_TYPE_SSL && SSL_get_peer_certificate(vio->ssl_)) user_access=acl_user->access; @@ -653,12 +659,12 @@ static byte* check_get_key(ACL_USER *buff,uint *length, } static void acl_update_user(const char *user, const char *host, - const char *password, + const char *password, enum SSL_type ssl_type, const char *ssl_cipher, const char *x509_issuer, const char *x509_subject, - USER_RESOURCES *mqh, + USER_RESOURCES *mqh, ulong privileges) { for (uint i=0 ; i < acl_users.elements ; i++) @@ -707,7 +713,7 @@ static void acl_update_user(const char *user, const char *host, static void acl_insert_user(const char *user, const char *host, - const char *password, + const char *password, enum SSL_type ssl_type, const char *ssl_cipher, const char *x509_issuer, @@ -805,9 +811,10 @@ static void acl_insert_db(const char *user, const char *host, const char *db, } -/***************************************************************************** -** Get privilege for a host, user and db combination -*****************************************************************************/ + +/* + Get privilege for a host, user and db combination +*/ ulong acl_get(const char *host, const char *ip, const char *bin_ip, const char *user, const char *db) @@ -929,11 +936,14 @@ int wild_case_compare(const char *str,const char *wildstr) DBUG_RETURN (*str != '\0'); } -/***************************************************************************** -** check if there are any possible matching entries for this host -** All host names without wild cards are stored in a hash table, -** entries with wildcards are stored in a dynamic array -*****************************************************************************/ + +/* + Check if there are any possible matching entries for this host + + NOTES + All host names without wild cards are stored in a hash table, + entries with wildcards are stored in a dynamic array +*/ static void init_check_host(void) { @@ -1006,10 +1016,6 @@ bool acl_check_host(const char *host, const char *ip) return 1; // Host is not allowed } -/***************************************************************************** - Change password for the user if it's not an anonymous user - Note: This should write the error directly to the client! -*****************************************************************************/ /* Check if the user is allowed to change password @@ -1021,8 +1027,8 @@ bool acl_check_host(const char *host, const char *ip) user user name RETURN VALUE - 0 OK - 1 ERROR ; In this case the error is sent to the client. + 0 OK + 1 ERROR ; In this case the error is sent to the client. */ bool check_change_password(THD *thd, const char *host, const char *user) @@ -1061,7 +1067,7 @@ bool check_change_password(THD *thd, const char *host, const char *user) RETURN VALUES 0 ok 1 ERROR; In this case the error is sent to the client. -*/ +*/ bool change_password(THD *thd, const char *host, const char *user, char *new_password) @@ -1127,7 +1133,7 @@ find_acl_user(const char *host, const char *user) { ACL_USER *acl_user=dynamic_element(&acl_users,i,ACL_USER*); DBUG_PRINT("info",("strcmp('%s','%s'), compare_hostname('%s','%s'),", - user,acl_user->user,(host),(acl_user->host))); + user,acl_user->user,(host),(acl_user->host))); if (!acl_user->user && !user[0] || acl_user->user && !strcmp(user,acl_user->user)) { @@ -1140,15 +1146,18 @@ find_acl_user(const char *host, const char *user) DBUG_RETURN(0); } -/***************************************************************************** - Handle comparing of hostname - A hostname may be of type: - hostname (May include wildcards); monty.pp.sci.fi - ip (May include wildcards); 192.168.0.0 - ip/netmask 192.168.0.0/255.255.255.0 - A net mask of 0.0.0.0 is not allowed. -*****************************************************************************/ +/* + Comparing of hostnames + + NOTES + A hostname may be of type: + hostname (May include wildcards); monty.pp.sci.fi + ip (May include wildcards); 192.168.0.0 + ip/netmask 192.168.0.0/255.255.255.0 + + A net mask of 0.0.0.0 is not allowed. +*/ static const char *calc_ip(const char *ip, long *val, char end) { @@ -1195,9 +1204,9 @@ static bool compare_hostname(const acl_host_and_ip *host, const char *hostname, } -/**************************************************************************** - Code to update grants in the user and database privilege tables -****************************************************************************/ +/* + Update grants in the user and database privilege tables +*/ static bool update_user_table(THD *thd, const char *host, const char *user, const char *new_password) @@ -1263,7 +1272,7 @@ static bool test_if_create_new_users(THD *thd) /**************************************************************************** -** Handle GRANT commands + Handle GRANT commands ****************************************************************************/ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo, @@ -1285,8 +1294,8 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo, if (combo.password.length != HASH_PASSWORD_LENGTH) { my_printf_error(ER_PASSWORD_NO_MATCH, - "Password hash should be a %d-digit hexadecimal number", - MYF(0),HASH_PASSWORD_LENGTH); + "Password hash should be a %d-digit hexadecimal number", + MYF(0),HASH_PASSWORD_LENGTH); DBUG_RETURN(-1); } password=combo.password.str; @@ -1459,7 +1468,7 @@ static int replace_db_table(TABLE *table, const char *db, char what= (revoke_grant) ? 'N' : 'Y'; DBUG_ENTER("replace_db_table"); - // is there such a user in user table in memory ???? + /* Check if there is such a user in user table in memory? */ if (!initialized || !find_acl_user(combo.host.str,combo.user.str)) { my_error(ER_PASSWORD_NO_MATCH,MYF(0)); @@ -1471,7 +1480,7 @@ static int replace_db_table(TABLE *table, const char *db, table->field[2]->store(combo.user.str,combo.user.length); table->file->index_init(0); if (table->file->index_read(table->record[0],(byte*) table->field[0]->ptr,0, - HA_READ_KEY_EXACT)) + HA_READ_KEY_EXACT)) { if (what == 'N') { // no row, no revoke @@ -1502,7 +1511,7 @@ static int replace_db_table(TABLE *table, const char *db, if (old_row_exists) { - // update old existing row + /* update old existing row */ if (rights) { if ((error=table->file->update_row(table->record[1],table->record[0]))) @@ -1529,11 +1538,11 @@ static int replace_db_table(TABLE *table, const char *db, DBUG_RETURN(0); /* This could only happen if the grant tables got corrupted */ - table_error: +table_error: table->file->print_error(error,MYF(0)); /* purecov: deadcode */ table->file->index_end(); - abort: +abort: DBUG_RETURN(-1); } @@ -1649,7 +1658,7 @@ public: if (!(mem_check = new GRANT_COLUMN(*res, fix_rights_for_column(priv)))) { - // Don't use this entry + /* Don't use this entry */ privs = cols = 0; /* purecov: deadcode */ return; /* purecov: deadcode */ } @@ -1827,7 +1836,7 @@ static int replace_column_table(GRANT_TABLE *g_t, key_length, HA_READ_KEY_EXACT)) goto end; - // Scan trough all rows with the same host,db,user and table + /* Scan through all rows with the same host,db,user and table */ do { ulong privileges = (ulong) table->field[6]->val_int(); @@ -1877,7 +1886,7 @@ static int replace_column_table(GRANT_TABLE *g_t, !key_cmp(table,key,0,key_length)); } - end: +end: table->file->index_end(); DBUG_RETURN(result); } @@ -1947,7 +1956,7 @@ static int replace_table_table(THD *thd, GRANT_TABLE *grant_table, if (revoke_grant) { - // column rights are already fixed in mysql_table_grant ! + /* column rights are already fixed in mysql_table_grant */ store_table_rights=j & ~store_table_rights; } else @@ -1983,7 +1992,7 @@ static int replace_table_table(THD *thd, GRANT_TABLE *grant_table, if (rights | col_rights) { grant_table->privs= rights; - grant_table->cols= col_rights; + grant_table->cols= col_rights; } else { @@ -1991,19 +2000,36 @@ static int replace_table_table(THD *thd, GRANT_TABLE *grant_table, } DBUG_RETURN(0); - /* This should never happen */ - table_error: + /* This should never happen */ +table_error: table->file->print_error(error,MYF(0)); /* purecov: deadcode */ DBUG_RETURN(-1); /* purecov: deadcode */ } +/* + Store table level and column level grants in the privilege tables + + SYNOPSIS + mysql_table_grant() + thd Thread handle + table_list List of tables to give grant + user_list List of users to give grant + columns List of columns to give grant + rights Table level grant + revoke_grant Set to 1 if this is a REVOKE command + + RETURN + 0 ok + 1 error +*/ + int mysql_table_grant(THD *thd, TABLE_LIST *table_list, List &user_list, List &columns, ulong rights, bool revoke_grant) { - ulong column_priv = 0; + ulong column_priv= 0; List_iterator str_list (user_list); LEX_USER *Str; TABLE_LIST tables[3]; @@ -2024,21 +2050,21 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list, if (columns.elements && !revoke_grant) { TABLE *table; - class LEX_COLUMN *check; - List_iterator iter(columns); + class LEX_COLUMN *column; + List_iterator column_iter(columns); if (!(table=open_ltable(thd,table_list,TL_READ))) DBUG_RETURN(-1); - while ((check = iter++)) + while ((column = column_iter++)) { - if (!find_field_in_table(thd,table,check->column.ptr(), - check->column.length(),0,0)) + if (!find_field_in_table(thd,table,column->column.ptr(), + column->column.length(),0,0)) { my_printf_error(ER_BAD_FIELD_ERROR,ER(ER_BAD_FIELD_ERROR),MYF(0), - check->column.c_ptr(), table_list->alias); + column->column.c_ptr(), table_list->alias); DBUG_RETURN(-1); } - column_priv |= check->rights | (rights & COL_ACLS); + column_priv|= column->rights; } close_thread_tables(thd); } @@ -2148,21 +2174,21 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list, /* If revoke_grant, calculate the new column privilege for tables_priv */ if (revoke_grant) { - class LEX_COLUMN *check; - List_iterator iter(columns); + class LEX_COLUMN *column; + List_iterator column_iter(columns); GRANT_COLUMN *grant_column; /* Fix old grants */ - while ((check = iter++)) + while ((column = column_iter++)) { grant_column = column_hash_search(grant_table, - check->column.ptr(), - check->column.length()); + column->column.ptr(), + column->column.length()); if (grant_column) - grant_column->rights&= ~(check->rights | rights); + grant_column->rights&= ~(column->rights | rights); } /* scan trough all columns to get new column grant */ - column_priv=0; + column_priv= 0; for (uint idx=0 ; idx < grant_table->hash_columns.records ; idx++) { grant_column= (GRANT_COLUMN*) hash_element(&grant_table->hash_columns, @@ -2259,7 +2285,7 @@ int mysql_grant (THD *thd, const char *db, List &list, if (!revoke_grant) create_new_users= test_if_create_new_users(thd); - // go through users in user_list + /* go through users in user_list */ pthread_mutex_lock(&LOCK_grant); VOID(pthread_mutex_lock(&acl_cache->lock)); grant_version++; @@ -2280,7 +2306,7 @@ int mysql_grant (THD *thd, const char *db, List &list, continue; } if ((replace_user_table(thd, - tables[0].table, + tables[0].table, *Str, (!db ? rights : 0), revoke_grant, create_new_users))) @@ -2410,7 +2436,16 @@ end: } -/* Reload grant array if possible */ +/* + Reload grant array if possible + + SYNOPSIS + grant_reload() + thd Thread handler + + NOTES + Locked tables are checked by acl_init and doesn't have to be checked here +*/ void grant_reload(THD *thd) { @@ -2419,8 +2454,6 @@ void grant_reload(THD *thd) MEM_ROOT old_mem; DBUG_ENTER("grant_reload"); - // Locked tables are checked by acl_init and doesn't have to be checked here - pthread_mutex_lock(&LOCK_grant); grant_version++; old_hash_tables=hash_tables; @@ -2496,13 +2529,13 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables, pthread_mutex_unlock(&LOCK_grant); return 0; - err: +err: pthread_mutex_unlock(&LOCK_grant); if (!no_errors) // Not a silent skip of table { const char *command=""; if (want_access & SELECT_ACL) - command ="select"; + command ="select"; else if (want_access & INSERT_ACL) command = "insert"; else if (want_access & UPDATE_ACL) @@ -2543,7 +2576,7 @@ bool check_grant_column(THD *thd,TABLE *table, const char *name, pthread_mutex_lock(&LOCK_grant); - // reload table if someone has modified any grants + /* reload table if someone has modified any grants */ if (table->grant.version != grant_version) { @@ -2603,7 +2636,7 @@ bool check_grant_all_columns(THD *thd, ulong want_access, TABLE *table) pthread_mutex_lock(&LOCK_grant); - // reload table if someone has modified any grants + /* reload table if someone has modified any grants */ if (table->grant.version != grant_version) { @@ -2613,7 +2646,7 @@ bool check_grant_all_columns(THD *thd, ulong want_access, TABLE *table) table->real_name,0); /* purecov: inspected */ table->grant.version=grant_version; /* purecov: inspected */ } - // The following should always be true + /* The following should always be true */ if (!(grant_table=table->grant.grant_table)) goto err; /* purecov: inspected */ @@ -2628,7 +2661,7 @@ bool check_grant_all_columns(THD *thd, ulong want_access, TABLE *table) return 0; /* We must use my_printf_error() here! */ - err: +err: pthread_mutex_unlock(&LOCK_grant); const char *command=""; @@ -2648,11 +2681,11 @@ bool check_grant_all_columns(THD *thd, ulong want_access, TABLE *table) } -/**************************************************************************** +/* Check if a user has the right to access a database Access is accepted if he has a grant for any table in the database Return 1 if access is denied -****************************************************************************/ +*/ bool check_grant_db(THD *thd,const char *db) { @@ -2692,7 +2725,7 @@ ulong get_table_grant(THD *thd, TABLE_LIST *table) pthread_mutex_lock(&LOCK_grant); grant_table = table_hash_search(thd->host,thd->ip,db,user, - table->real_name,0); + table->real_name, 0); table->grant.grant_table=grant_table; // Remember for column test table->grant.version=grant_version; if (grant_table) @@ -2710,7 +2743,7 @@ ulong get_column_grant(THD *thd, TABLE_LIST *table, Field *field) ulong priv; pthread_mutex_lock(&LOCK_grant); - // reload table if someone has modified any grants + /* reload table if someone has modified any grants */ if (table->grant.version != grant_version) { table->grant.grant_table= @@ -2735,11 +2768,20 @@ ulong get_column_grant(THD *thd, TABLE_LIST *table, Field *field) return priv; } +/* Help function for mysql_show_grants */ -/***************************************************************************** - SHOW GRANTS : send to client grant-like strings depicting user@host - privileges -*****************************************************************************/ +static void add_user_option(String *grant, ulong value, const char *name) +{ + if (value) + { + char buff[22], *p; // just as in int2str + grant->append(' '); + grant->append(name, strlen(name)); + grant->append(' '); + p=int10_to_str(value, buff, 10); + grant->append(buff,p-buff); + } +} static const char *command_array[]= { @@ -2748,13 +2790,21 @@ static const char *command_array[]= "SUPER", "CREATE TEMPORARY TABLES", "LOCK TABLES", "EXECUTE", "REPLICATION SLAVE", "REPLICATION CLIENT", }; + static uint command_lengths[]= { 6,6,6,6,6,4,6,8,7,4,5,10,5,5,14,5,23,11,7,17,18 }; -int mysql_show_grants(THD *thd,LEX_USER *lex_user) +/* + SHOW GRANTS; Send grants for a user to the client + + IMPLEMENTATION + Send to client grant-like strings depicting user@host privileges +*/ + +int mysql_show_grants(THD *thd,LEX_USER *lex_user) { ulong want_access; uint counter,index; @@ -2793,7 +2843,7 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user) !my_strcasecmp(lex_user->host.str,host)) break; } - if (counter == acl_users.elements) + if (counter == acl_users.elements) { my_printf_error(ER_NONEXISTING_GRANT,ER(ER_NONEXISTING_GRANT), MYF(0),lex_user->user.str,lex_user->host.str); @@ -2824,13 +2874,13 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user) global.append("ALL PRIVILEGES",14); else if (!(want_access & ~GRANT_ACL)) global.append("USAGE",5); - else + else { bool found=0; ulong j,test_access= want_access & ~GRANT_ACL; for (counter=0, j = SELECT_ACL;j <= GLOBAL_ACLS;counter++,j <<= 1) { - if (test_access & j) + if (test_access & j) { if (found) global.append(", ",2); @@ -2840,7 +2890,7 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user) } } global.append (" ON *.* TO '",12); - global.append(lex_user->user.str,lex_user->user.length); + global.append(lex_user->user.str,lex_user->user.length); global.append ("'@'",3); global.append(lex_user->host.str,lex_user->host.length); global.append ('\''); @@ -2863,25 +2913,25 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user) global.append(" REQUIRE ",9); if (acl_user->x509_issuer) { - ssl_options++; - global.append("ISSUER \'",8); - global.append(acl_user->x509_issuer,strlen(acl_user->x509_issuer)); + ssl_options++; + global.append("ISSUER \'",8); + global.append(acl_user->x509_issuer,strlen(acl_user->x509_issuer)); global.append('\''); } if (acl_user->x509_subject) { - if (ssl_options++) - global.append(' '); - global.append("SUBJECT \'",9); - global.append(acl_user->x509_subject,strlen(acl_user->x509_subject)); + if (ssl_options++) + global.append(' '); + global.append("SUBJECT \'",9); + global.append(acl_user->x509_subject,strlen(acl_user->x509_subject)); global.append('\''); } if (acl_user->ssl_cipher) { - if (ssl_options++) - global.append(' '); - global.append("CIPHER '",8); - global.append(acl_user->ssl_cipher,strlen(acl_user->ssl_cipher)); + if (ssl_options++) + global.append(' '); + global.append("CIPHER '",8); + global.append(acl_user->ssl_cipher,strlen(acl_user->ssl_cipher)); global.append('\''); } } @@ -2889,30 +2939,15 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user) (acl_user->user_resource.questions | acl_user->user_resource.updates | acl_user->user_resource.connections)) { - global.append(" WITH",5); + global.append(" WITH",5); if (want_access & GRANT_ACL) - global.append(" GRANT OPTION",13); - if (acl_user->user_resource.questions) - { - char buff[22], *p; // just as in int2str - global.append(" MAX_QUERIES_PER_HOUR ",22); - p=int10_to_str(acl_user->user_resource.questions,buff,10); - global.append(buff,p-buff); - } - if (acl_user->user_resource.updates) - { - char buff[22], *p; // just as in int2str - global.append(" MAX_UPDATES_PER_HOUR ",22); - p=int10_to_str(acl_user->user_resource.updates,buff,10); - global.append(buff,p-buff); - } - if (acl_user->user_resource.connections) - { - char buff[22], *p; // just as in int2str - global.append(" MAX_CONNECTIONS_PER_HOUR ",26); - p=int10_to_str(acl_user->user_resource.connections,buff,10); - global.append(buff,p-buff); - } + global.append(" GRANT OPTION",13); + add_user_option(&global, acl_user->user_resource.questions, + "MAX_QUERIES_PER_HOUR"); + add_user_option(&global, acl_user->user_resource.updates, + "MAX_UPDATES_PER_HOUR"); + add_user_option(&global, acl_user->user_resource.connections, + "MAX_CONNECTIONS_PER_HOUR"); } thd->packet.length(0); net_store_data(&thd->packet,global.ptr(),global.length()); @@ -2938,7 +2973,7 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user) !my_strcasecmp(lex_user->host.str,host)) { want_access=acl_db->access; - if (want_access) + if (want_access) { String db(buff,sizeof(buff)); db.length(0); @@ -2947,7 +2982,7 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user) if (test_all_bits(want_access,(DB_ACLS & ~GRANT_ACL))) db.append("ALL PRIVILEGES",14); else if (!(want_access & ~GRANT_ACL)) - db.append("USAGE",5); + db.append("USAGE",5); else { int found=0, cnt; @@ -2963,13 +2998,13 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user) } } } - db.append (" ON `",5); + db.append(" ON `",5); db.append(acl_db->db); - db.append ("`.* TO '",8); - db.append(lex_user->user.str,lex_user->user.length); - db.append ("'@'",3); + db.append("`.* TO '",8); + db.append(lex_user->user.str,lex_user->user.length); + db.append("'@'",3); db.append(lex_user->host.str, lex_user->host.length); - db.append ('\''); + db.append('\''); if (want_access & GRANT_ACL) db.append(" WITH GRANT OPTION",18); thd->packet.length(0); @@ -2988,7 +3023,7 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user) for (index=0 ; index < hash_tables.records ; index++) { const char *user,*host; - GRANT_TABLE *grant_table= (GRANT_TABLE*) hash_element(&hash_tables,index); + GRANT_TABLE *grant_table= (GRANT_TABLE*) hash_element(&hash_tables,index); if (!(user=grant_table->user)) user=""; @@ -2998,44 +3033,54 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user) if (!strcmp(lex_user->user.str,user) && !my_strcasecmp(lex_user->host.str,host)) { - want_access=grant_table->privs; - if ((want_access | grant_table->cols) != 0) + ulong table_access= grant_table->privs; + if ((table_access | grant_table->cols) != 0) { String global(buff,sizeof(buff)); global.length(0); global.append("GRANT ",6); - if (test_all_bits(grant_table->privs,(TABLE_ACLS & ~GRANT_ACL))) + if (test_all_bits(table_access, (TABLE_ACLS & ~GRANT_ACL))) global.append("ALL PRIVILEGES",14); - else + else { - int found=0; - ulong j,test_access= (want_access | grant_table->cols) & ~GRANT_ACL; + int found= 0; + ulong j,test_access= (table_access | grant_table->cols) & ~GRANT_ACL; - for (counter=0, j = SELECT_ACL;j <= TABLE_ACLS; counter++,j <<= 1) + for (counter= 0, j= SELECT_ACL; j <= TABLE_ACLS; counter++, j<<= 1) { - if (test_access & j) + if (test_access & j) { if (found) global.append(", ",2); - found = 1; + found= 1; global.append(command_array[counter],command_lengths[counter]); - if (grant_table->cols) + if (grant_table->cols) { - uint found_col=0; + uint found_col= 0; for (uint col_index=0 ; col_index < grant_table->hash_columns.records ; col_index++) { GRANT_COLUMN *grant_column = (GRANT_COLUMN*) hash_element(&grant_table->hash_columns,col_index); - if (grant_column->rights & j) + if (grant_column->rights & j) { - if (!found_col) + if (!found_col) { + found_col= 1; + /* + If we have a duplicated table level privilege, we + must write the access privilege name again. + */ + if (table_access & j) + { + global.append(", ", 2); + global.append(command_array[counter], + command_lengths[counter]); + } global.append(" (",2); - found_col=1; } else global.append(", ",2); @@ -3054,12 +3099,12 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user) global.append("`.`",3); global.append(grant_table->tname); global.append("` TO '",6); - global.append(lex_user->user.str,lex_user->user.length); + global.append(lex_user->user.str,lex_user->user.length); global.append("'@'",3); - global.append(lex_user->host.str,lex_user->host.length); + global.append(lex_user->host.str,lex_user->host.length); global.append('\''); - if (want_access & GRANT_ACL) - global.append(" WITH GRANT OPTION",18); + if (table_access & GRANT_ACL) + global.append(" WITH GRANT OPTION",18); thd->packet.length(0); net_store_data(&thd->packet,global.ptr(),global.length()); if (my_net_write(&thd->net,(char*) thd->packet.ptr(), @@ -3072,7 +3117,7 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user) } } - end: +end: VOID(pthread_mutex_unlock(&acl_cache->lock)); pthread_mutex_unlock(&LOCK_grant); diff --git a/sql/sql_acl.h b/sql/sql_acl.h index 1d074fe6001..bf269e5a7e3 100644 --- a/sql/sql_acl.h +++ b/sql/sql_acl.h @@ -76,8 +76,8 @@ #define get_rights_for_db(A) (((A) & 63) | (((A) & DB_CHUNK1) >> 4) | (((A) & DB_CHUNK2) >> 6)) #define fix_rights_for_table(A) (((A) & 63) | (((A) & ~63) << 4)) #define get_rights_for_table(A) (((A) & 63) | (((A) & ~63) >> 4)) -#define fix_rights_for_column(A) (((A) & COL_ACLS) | ((A & ~COL_ACLS) << 7)) -#define get_rights_for_column(A) (((A) & COL_ACLS) | ((A & ~COL_ACLS) >> 7)) +#define fix_rights_for_column(A) (((A) & 7) | (((A) & ~7) << 8)) +#define get_rights_for_column(A) (((A) & 7) | ((A) >> 8)) /* prototypes */ diff --git a/sql/sql_class.h b/sql/sql_class.h index 9857774fb84..a8a24451ecc 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -309,6 +309,7 @@ struct system_variables ulong tmp_table_size; ulong tx_isolation; ulong table_type; + ulong default_week_format; my_bool log_warnings; my_bool low_priority_updates; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 4e389b6d3f6..4570576afef 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -584,6 +584,11 @@ check_connections(THD *thd) if (thd->client_capabilities & CLIENT_SSL) { /* Do the SSL layering. */ + if (!ssl_acceptor_fd) + { + inc_host_errors(&thd->remote.sin_addr); + return(ER_HANDSHAKE_ERROR); + } DBUG_PRINT("info", ("IO layer change in progress...")); if (sslaccept(ssl_acceptor_fd, net->vio, thd->variables.net_wait_timeout)) { diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index a651d8002fd..ae9bd8b7727 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -51,7 +51,7 @@ int check_binlog_magic(IO_CACHE* log, const char** errmsg) } static int fake_rotate_event(NET* net, String* packet, char* log_file_name, - const char**errmsg) + ulonglong position, const char**errmsg) { char header[LOG_EVENT_HEADER_LEN], buf[ROTATE_HEADER_LEN]; memset(header, 0, 4); // when does not matter @@ -68,9 +68,7 @@ static int fake_rotate_event(NET* net, String* packet, char* log_file_name, int4store(header + LOG_POS_OFFSET, 0); packet->append(header, sizeof(header)); - /* We need to split the next statement because of problem with cxx */ - int4store(buf,4); // tell slave to skip magic number - int4store(buf+4,0); + int8store(buf+R_POS_OFFSET,position); packet->append(buf, ROTATE_HEADER_LEN); packet->append(p,ident_len); if (my_net_write(net, (char*)packet->ptr(), packet->length())) @@ -382,17 +380,30 @@ impossible position"; */ packet->set("\0", 1); - // if we are at the start of the log - if (pos == BIN_LOG_HEADER_SIZE) + /* + Before 4.0.14 we called fake_rotate_event below only if + (pos == BIN_LOG_HEADER_SIZE), because if this is false then the slave + already knows the binlog's name. + Now we always call fake_rotate_event; if the slave already knew the log's + name (ex: CHANGE MASTER TO MASTER_LOG_FILE=...) this is useless but does not + harm much. It is nice for 3.23 (>=.58) slaves which test Rotate events + to see if the master is 4.0 (then they choose to stop because they can't + replicate 4.0); by always calling fake_rotate_event we are sure that 3.23.58 + and newer will detect the problem as soon as replication starts (BUG#198). + Always calling fake_rotate_event makes sending of normal + (=from-binlog) Rotate events a priori unneeded, but it is not so simple: the + 2 Rotate events are not equivalent, the normal one is before the Stop event, + the fake one is after. If we don't send the normal one, then the Stop event + will be interpreted (by existing 4.0 slaves) as "the master stopped", which + is wrong. So for safety, given that we want minimum modification of 4.0, we + send the normal and fake Rotates. + */ + if (fake_rotate_event(net, packet, log_file_name, pos, &errmsg)) { - // tell the client log name with a fake rotate_event - if (fake_rotate_event(net, packet, log_file_name, &errmsg)) - { - my_errno= ER_MASTER_FATAL_ERROR_READING_BINLOG; - goto err; - } - packet->set("\0", 1); + my_errno= ER_MASTER_FATAL_ERROR_READING_BINLOG; + goto err; } + packet->set("\0", 1); while (!net->error && net->vio != 0 && !thd->killed) { @@ -585,10 +596,12 @@ Increase max_allowed_packet on master"; end_io_cache(&log); (void) my_close(file, MYF(MY_WME)); - // fake Rotate_log event just in case it did not make it to the log - // otherwise the slave make get confused about the offset + /* + Even if the previous log contained a Rotate_log_event, we still fake + one. + */ if ((file=open_binlog(&log, log_file_name, &errmsg)) < 0 || - fake_rotate_event(net, packet, log_file_name, &errmsg)) + fake_rotate_event(net, packet, log_file_name, BIN_LOG_HEADER_SIZE, &errmsg)) { my_errno= ER_MASTER_FATAL_ERROR_READING_BINLOG; goto err; @@ -828,7 +841,7 @@ int change_master(THD* thd, MASTER_INFO* mi) // TODO: see if needs re-write if (init_master_info(mi, master_info_file, relay_log_info_file, 0)) { - send_error(&thd->net, 0, "Could not initialize master info"); + send_error(&thd->net, ER_MASTER_INFO); unlock_slave_threads(mi); DBUG_RETURN(1); } diff --git a/sql/sql_select.cc b/sql/sql_select.cc index c2c4070956c..6c2d06051d4 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -453,6 +453,9 @@ mysql_select(THD *thd,TABLE_LIST *tables,List &fields,COND *conds, goto err; thd->proc_info="preparing"; + + select_distinct= select_distinct && (join.const_tables != join.tables); + if (result->initialize_tables(&join)) goto err; if (join.const_table_map != join.found_const_table_map && @@ -1634,6 +1637,9 @@ add_key_part(DYNAMIC_ARRAY *keyuse_array,KEY_FIELD *key_field) key_field->field->table->reginfo.not_exists_optimize=1; } + +#define FT_KEYPART (MAX_REF_PARTS+10) + static void add_ft_keys(DYNAMIC_ARRAY *keyuse_array, JOIN_TAB *stat,COND *cond,table_map usable_tables) @@ -1692,23 +1698,20 @@ add_ft_keys(DYNAMIC_ARRAY *keyuse_array, } } - if (!cond_func || cond_func->key == NO_SUCH_KEY) - return; - - if (!(usable_tables & cond_func->table->map)) + if ((!cond_func || cond_func->key == NO_SUCH_KEY) || + (!(usable_tables & cond_func->table->map))) return; KEYUSE keyuse; - keyuse.table= cond_func->table; keyuse.val = cond_func; keyuse.key = cond_func->key; -#define FT_KEYPART (MAX_REF_PARTS+10) - keyuse.keypart=FT_KEYPART; + keyuse.keypart= FT_KEYPART; keyuse.used_tables=cond_func->key_item()->used_tables(); VOID(insert_dynamic(keyuse_array,(gptr) &keyuse)); } + static int sort_keyuse(KEYUSE *a,KEYUSE *b) { diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index af0921825fc..39fa49773f1 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -2016,7 +2016,11 @@ simple_expr: | USER '(' ')' { $$= new Item_func_user(); current_thd->safe_to_cache_query=0; } | WEEK_SYM '(' expr ')' - { $$= new Item_func_week($3,new Item_int((char*) "0",0,1)); } + { + LEX *lex=Lex; + $$= new Item_func_week($3,new Item_int((char*) "0", + lex->thd->variables.default_week_format,1)); + } | WEEK_SYM '(' expr ',' expr ')' { $$= new Item_func_week($3,$5); } | YEAR_SYM '(' expr ')'