ft_optimization: identical queries merging. collection -> fulltext. Bugs fixed.

**************** !!! NOTE EVERYBODY: SYNTAX CHANGED !!! ********************
There's no COLLECTIONs now, full-text indexes can be created via the word
FULLTEXT, which should be used like UNIQUE.
parent 6236dfc7
......@@ -11670,7 +11670,6 @@ to restart @code{mysqld} with @code{--skip-grant-tables} to be able to run
* GRANT:: @code{GRANT} and @code{REVOKE} syntax
* CREATE INDEX:: @code{CREATE INDEX} syntax
* DROP INDEX:: @code{DROP INDEX} syntax
* CREATE COLLECTION:: @code{CREATE COLLECTION} syntax
* Comments:: Comment syntax
* CREATE FUNCTION:: @code{CREATE FUNCTION} syntax
* Reserved words:: Is @strong{MySQL} picky about reserved words?
......@@ -13436,9 +13435,9 @@ mysql> CREATE TABLE test (
For @code{BLOB} and @code{TEXT} columns, you must index a prefix of the
column, you cannot index the entire thing.
In @strong{MySQL} 3.23.23 or later, you can also create special indexes
called @strong{collections}. They are used for full-text search. Only
@code{MyISAM} table type supports collections. Collection can be created
In @strong{MySQL} 3.23.23 or later, you can also create special
@strong{fulltext} indexes. They are used for full-text search. Only
@code{MyISAM} table type supports fulltext indexes. They can be created
only from @code{VARCHAR}, @code{BLOB}, and @code{TEXT} columns.
Indexing always happens over the entire column, partial indexing is not
supported. See @ref{MySQL full-text search} for details of operation.
......@@ -14165,7 +14164,7 @@ mysql> select STRCMP('text', 'text');
relevance - similarity measure between the text in columns
@code{(col1,col2,...)} and the query @code{expr}. Relevance is a
positive floating point number. Zero relevance means no similarity.
For @code{MATCH ... AGAINST()} to work, a @code{COLLECTION}
For @code{MATCH ... AGAINST()} to work, a @strong{fulltext index}
must be created first. @xref{CREATE TABLE, , @code{CREATE TABLE}}.
@code{MATCH ... AGAINST()} is available in @code{MySQL} 3.23.23 or later.
For details and usage examples see @xref{MySQL full-text search}.
......@@ -16178,7 +16177,7 @@ create_definition:
or KEY [index_name] (index_col_name,...)
or INDEX [index_name] (index_col_name,...)
or UNIQUE [INDEX] [index_name] (index_col_name,...)
or COLLECTION [collection_name] (collection_col_name,...)
or FULLTEXT [INDEX] [index_name] (index_col_name,...)
or [CONSTRAINT symbol] FOREIGN KEY index_name (index_col_name,...)
[reference_definition]
or CHECK (expr)
......@@ -16422,10 +16421,10 @@ When you use @code{ORDER BY} or @code{GROUP BY} with a @code{TEXT} or
@xref{BLOB, , @code{BLOB}}.
@item
In @strong{MySQL} 3.23.23 or later, you can also create special indexes
called @strong{collections}. They are used for full-text search. Only
@code{MyISAM} table type supports collections. Collection can be created
from any mix of @code{VARCHAR}, @code{BLOB}, and @code{TEXT} columns.
In @strong{MySQL} 3.23.23 or later, you can also create special
@strong{fulltext} indexes. They are used for full-text search. Only
@code{MyISAM} table type supports fulltext indexes. They can be created
only from @code{VARCHAR}, @code{BLOB}, and @code{TEXT} columns.
Indexing always happens over the entire column, partial indexing is not
supported. See @ref{MySQL full-text search} for details of operation.
......@@ -16598,7 +16597,7 @@ alter_specification:
or ADD INDEX [index_name] (index_col_name,...)
or ADD PRIMARY KEY (index_col_name,...)
or ADD UNIQUE [index_name] (index_col_name,...)
or ADD COLLECTION [collection_name] (collection_col_name,...)
or ADD FULLTEXT [index_name] (index_col_name,...)
or ALTER [COLUMN] col_name @{SET DEFAULT literal | DROP DEFAULT@}
or CHANGE [COLUMN] old_col_name create_definition
or MODIFY [COLUMN] create_definition
......@@ -19769,7 +19768,7 @@ dropped only with explicit @code{REVOKE} commands or by manipulating the
@section @code{CREATE INDEX} syntax
@example
CREATE [UNIQUE] INDEX index_name ON tbl_name (col_name[(length)],... )
CREATE [UNIQUE|FULLTEXT] INDEX index_name ON tbl_name (col_name[(length)],... )
@end example
The @code{CREATE INDEX} statement doesn't do anything in @strong{MySQL} prior
......@@ -19803,15 +19802,19 @@ which could save a lot of disk space and might also speed up @code{INSERT}
operations!
Note that you can only add an index on a column that can have @code{NULL}
values or on a @code{BLOB}/@code{TEXT} column if you are useing
values or on a @code{BLOB}/@code{TEXT} column if you are using
@strong{MySQL} version 3.23.2 or newer and are using the @code{MyISAM}
table type.
For more information about how @strong{MySQL} uses indexes, see
@ref{MySQL indexes, , @strong{MySQL} indexes}.
Fulltext indexes can index only @code{VARCHAR}, @code{BLOB}, and
@code{TEXT} columns, and only in @code{MyISAM} tables. Fulltext indexes
are available from @strong{MySQL} 3.23.23. @ref{MySQL full-text search}.
@findex DROP INDEX
@node DROP INDEX, CREATE COLLECTION, CREATE INDEX, Reference
@node DROP INDEX, Comments, CREATE INDEX, Reference
@section @code{DROP INDEX} syntax
@example
......@@ -19824,30 +19827,8 @@ prior to version 3.22. In 3.22 or later, @code{DROP INDEX} is mapped to an
@code{ALTER TABLE} statement to drop the index.
@xref{ALTER TABLE, , @code{ALTER TABLE}}.
@findex CREATE COLLECTION
@node CREATE COLLECTION, Comments, DROP INDEX, Reference
@section @code{CREATE COLLECTION} syntax
@example
CREATE COLLECTION collection_name ON tbl_name (col_name,... )
@end example
@code{CREATE COLLECTION} statement is mapped to an
@code{ALTER TABLE} statement to create collections.
@xref{ALTER TABLE, , @code{ALTER TABLE}}.
A column list of the form @code{(col1,col2,...)} creates a
multiple-column collection. Search in such a collection means a search
over the concatenated columns that comprise the collection.
There is no special @code{DROP COLLECTION} statement.
@code{DROP INDEX} should be used to drop collections instead.
Only @code{VARCHAR}, @code{BLOB}, and @code{TEXT} columns can be part
of the collection. See @ref{MySQL full-text search} for details of operation.
@findex Comment syntax
@node Comments, CREATE FUNCTION, CREATE COLLECTION, Reference
@node Comments, CREATE FUNCTION, DROP INDEX, Reference
@section Comment syntax
The @strong{MySQL} server supports the @code{# to end of line}, @code{--
......@@ -34106,14 +34087,14 @@ DELAYED} threads.
@section MySQL full-text search
Since version 3.23.23, @strong{MySQL} has support for full-text indexing
and searching. Full-text index in @strong{MySQL} is a special type of index
called @strong{collection}. Collections can be created from @code{VARCHAR},
@code{TEXT}, and @code{BLOB} columns at @code{CREATE TABLE}
time or added later with @code{ALTER TABLE} or @code{CREATE COLLECTION}.
Collection is queried with @code{MATCH} function.
and searching. Full-text index in @strong{MySQL} is an
index of type @code{FULLTEXT}. Fulltext indexes can be created from
@code{VARCHAR}, @code{TEXT}, and @code{BLOB} columns at
@code{CREATE TABLE} time or added later with @code{ALTER TABLE} or
@code{CREATE INDEX}. Full-text search is performed with @code{MATCH} function.
@example
mysql> CREATE TABLE t (a VARCHAR(200), b TEXT, COLLECTION (a,b));
mysql> CREATE TABLE t (a VARCHAR(200), b TEXT, FULLTEXT (a,b));
Query OK, 0 rows affected (0.00 sec)
mysql> INSERT INTO t VALUES
-> ('MySQL has now support', 'for full-text search'),
......@@ -34145,15 +34126,16 @@ mysql> SELECT *,MATCH a,b AGAINST ('collections support') as x FROM t;
@end example
Function @code{MATCH} matches a natural language query @code{AGAINST} a
text collection. For every row in a table it returns relevance -
text collection (which is simply the columns that are covered
by fulltext index). For every row in a table it returns relevance -
similarity measure between the text in that row (in the columns, that
are part of the collection) and the query. When it used in a @code{WHERE}
clause (see example above) the rows returned are automatically sorted
with relevance decreasing. Relevance is a non-negative floating point
number. Zero relevance means no similarity. Relevance is computed based
on number of words in the row and number of unique words in that row,
total number of words in the collection, number of documents (rows),
that contain a particular word, etc.
are part of the collection) and the query. When it used in a
@code{WHERE} clause (see example above) the rows returned are
automatically sorted with relevance decreasing. Relevance is a non-
negative floating point number. Zero relevance means no similarity.
Relevance is computed based on number of words in the row and number of
unique words in that row, total number of words in the collection,
number of documents (rows), that contain a particular word, etc.
MySQL uses very simple parser to split text into words. "Word" is
any sequence of letters, numbers, @code{'}, and @code{_}. Any "word"
......@@ -158,6 +158,7 @@ FT_DOCLIST * ft_init_search(void *info, uint keynr, byte *key,
ALL_IN_ONE aio;
FT_DOCLIST *dlist;
FT_DOC *dptr;
my_off_t saved_lastpos;
/* black magic ON */
if ((int) (keynr = _mi_check_index((MI_INFO *)info,keynr)) < 0)
......@@ -173,6 +174,8 @@ FT_DOCLIST * ft_init_search(void *info, uint keynr, byte *key,
aio.keyinfo=aio.info->s->keyinfo+keynr;
aio.key_root=aio.info->s->state.key_root[keynr];
saved_lastpos=aio.info->lastpos;
if(!(wtree=ft_parse(NULL,key,key_len))) return NULL;
init_tree(&aio.dtree,0,sizeof(FT_SUPERDOC),(qsort_cmp)&FT_SUPERDOC_cmp,0,
......@@ -199,6 +202,7 @@ FT_DOCLIST * ft_init_search(void *info, uint keynr, byte *key,
}
err:
aio.info->lastpos=saved_lastpos;
delete_tree(&aio.dtree);
delete_tree(wtree);
free(wtree);
......@@ -217,7 +221,8 @@ int ft_read_next(FT_DOCLIST *handler, char *record)
info->update&= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
if (!(*info->read_record)(info,handler->doc[handler->curdoc].dpos,record))
info->lastpos=handler->doc[handler->curdoc].dpos;
if (!(*info->read_record)(info,info->lastpos,record))
{
info->update|= HA_STATE_AKTIV; /* Record is read */
return 0;
......
......@@ -1141,7 +1141,13 @@ int mi_repair(MI_CHECK *param, register MI_INFO *info,
for (i=0 ; i < share->state.header.max_block_size ; i++)
share->state.key_del[i]= HA_OFFSET_ERROR;
share->state.key_map= ((ulonglong)1L << share->base.keys)-1; /* Should I ? */
/* I think mi_repair and mi_repair_by_sort should do the same
(according, e.g. to ha_myisam::repair), but as mi_repair doesn't
touch key_map it cannot be used to T_CREATE_MISSING_KEYS.
That is the next line for... (serg)
*/
share->state.key_map= ((ulonglong)1L << share->base.keys)-1;
info->state->key_file_length=share->base.keystart;
......@@ -1935,6 +1941,11 @@ static int sort_key_read(SORT_INFO *sort_info, void *key)
"Found too many records; Can`t continue");
DBUG_RETURN(1);
}
/* Hmm, repair_by_sort uses find_all_keys, and find_all_keys strictly
implies "one row - one key per keynr", while for ft_key one row/keynr
can produce as many keys as the number of unique words in the text
that's why I disabled repair_by_sort for ft-keys. (serg)
*/
if (sort_info->keyinfo->flag & HA_FULLTEXT )
{
mi_check_print_error(sort_info->param,
......@@ -3009,6 +3020,13 @@ my_bool mi_test_if_sort_rep(MI_INFO *info, ha_rows rows)
return FALSE; /* Can't use sort */
for (i=0 ; i < share->base.keys ; i++,key++)
{
/* It's to disable repair_by_sort for ft-keys.
Another solution would be to make ft-keys just too_big_key_for_sort,
but then they won't be disabled by dectivate_non_unique_index
and so they will be created at the first stage. As ft-key creation
is very time-consuming process, it's better to leave it to repair stage
but this repair shouldn't be repair_by_sort (serg)
*/
if (mi_too_big_key_for_sort(key,rows) || (key->flag & HA_FULLTEXT))
return FALSE;
}
......
......@@ -1837,26 +1837,8 @@ err:
double Item_func_match::val()
{
my_off_t docid=table->file->row_position(); // HAVE to do it here...
if (first_call)
{
if (join_key=(table->file->get_index() == key &&
(ft_handler=(FT_DOCLIST *)table->file->ft_handler)))
;
else
{
/* join won't use this ft-key, but we must to init it anyway */
String *ft_tmp=0;
char tmp1[FT_QUERY_MAXLEN];
String tmp2(tmp1,sizeof(tmp1));
ft_tmp=key_item()->val_str(&tmp2);
ft_handler=(FT_DOCLIST *)
table->file->ft_init_ext(key, (byte*) ft_tmp->ptr(), ft_tmp->length());
}
first_call=0;
}
init_search();
// Don't know how to return an error from val(), so NULL will be returned
if ((null_value=(ft_handler==NULL)))
......@@ -1873,6 +1855,7 @@ double Item_func_match::val()
int a,b,c;
FT_DOC *docs=ft_handler->doc;
my_off_t docid=table->file->row_position();
if ((null_value=(docid==HA_OFFSET_ERROR)))
return 0.0;
......@@ -1893,6 +1876,36 @@ double Item_func_match::val()
}
}
void Item_func_match::init_search()
{
if (!first_call)
return;
first_call=false;
if (master)
{
master->init_search();
ft_handler=master->ft_handler;
join_key=master->join_key;
return;
}
if (join_key)
{
ft_handler=((FT_DOCLIST *)table->file->ft_handler);
return;
}
/* join won't use this ft-key, but we must to init it anyway */
String *ft_tmp=0;
char tmp1[FT_QUERY_MAXLEN];
String tmp2(tmp1,sizeof(tmp1));
ft_tmp=key_item()->val_str(&tmp2);
ft_handler=(FT_DOCLIST *)
table->file->ft_init_ext(key, (byte*) ft_tmp->ptr(), ft_tmp->length());
}
bool Item_func_match::fix_fields(THD *thd,struct st_table_list *tlist)
{
List_iterator<Item> li(fields);
......@@ -1982,6 +1995,24 @@ bool Item_func_match::fix_index()
this->key=max_key;
first_call=1;
maybe_null=1;
join_key=0;
return 0;
}
bool Item_func_match::eq(const Item *item) const
{
if (item->type() != FUNC_ITEM)
return 0;
if (func_name() != ((Item_func*)item)->func_name())
return 0;
Item_func_match *ifm=(Item_func_match*) item;
if (key == ifm->key && table == ifm->table &&
key_item()->eq(ifm->key_item()))
return 1;
return 0;
}
......
......@@ -839,19 +839,28 @@ public:
TABLE *table;
uint key;
bool first_call, join_key;
Item_func_match *master;
FT_DOCLIST *ft_handler;
Item_func_match(List<Item> &a, Item *b): Item_real_func(b),
fields(a), table(0), ft_handler(0)
{}
~Item_func_match() { ft_close_search(ft_handler);
if(join_key) table->file->ft_handler=0; }
fields(a), table(0), ft_handler(0), master(0) {}
~Item_func_match()
{
if (!master)
{
ft_close_search(ft_handler);
if(join_key)
table->file->ft_handler=0;
}
}
const char *func_name() const { return "match"; }
enum Functype functype() const { return FT_FUNC; }
void update_used_tables() {}
bool fix_fields(THD *thd,struct st_table_list *tlist);
bool fix_index();
bool eq(const Item *) const;
double val();
longlong val_int() { return val()!=0.0; }
bool fix_index();
void init_search();
};
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
......@@ -81,7 +81,6 @@ static SYMBOL symbols[] = {
{ "CHANGED", SYM(CHANGED),0,0},
{ "CHECK", SYM(CHECK_SYM),0,0},
{ "CHECKSUM", SYM(CHECKSUM_SYM),0,0},
{ "COLLECTION", SYM(COLLECTION),0,0},
{ "COLUMN", SYM(COLUMN_SYM),0,0},
{ "COLUMNS", SYM(COLUMNS),0,0},
{ "COMMENT", SYM(COMMENT_SYM),0,0},
......@@ -142,6 +141,7 @@ static SYMBOL symbols[] = {
{ "FROM", SYM(FROM),0,0},
{ "FOR", SYM(FOR_SYM),0,0},
{ "FULL", SYM(FULL),0,0},
{ "FULLTEXT", SYM(FULLTEXT_SYM),0,0},
{ "FUNCTION", SYM(UDF_SYM),0,0},
{ "GRANT", SYM(GRANT),0,0},
{ "GRANTS", SYM(GRANTS),0,0},
......@@ -191,14 +191,14 @@ static SYMBOL symbols[] = {
{ "LONGBLOB", SYM(LONGBLOB),0,0},
{ "LONGTEXT", SYM(LONGTEXT),0,0},
{ "LOW_PRIORITY", SYM(LOW_PRIORITY),0,0},
{ "MASTER", SYM(MASTER_SYM),0,0},
{ "MASTER_CONNECT_RETRY", SYM(MASTER_CONNECT_RETRY_SYM),0,0},
{ "MASTER_HOST", SYM(MASTER_HOST_SYM),0,0},
{ "MASTER_LOG_FILE", SYM(MASTER_LOG_FILE_SYM),0,0},
{ "MASTER_LOG_POS", SYM(MASTER_LOG_POS_SYM),0,0},
{ "MASTER_PASSWORD", SYM(MASTER_PASSWORD_SYM),0,0},
{ "MASTER_PORT", SYM(MASTER_PORT_SYM),0,0},
{ "MASTER_USER", SYM(MASTER_USER_SYM),0,0},
{ "MASTER", SYM(MASTER_SYM),0,0},
{ "MASTER_CONNECT_RETRY", SYM(MASTER_CONNECT_RETRY_SYM),0,0},
{ "MASTER_HOST", SYM(MASTER_HOST_SYM),0,0},
{ "MASTER_LOG_FILE", SYM(MASTER_LOG_FILE_SYM),0,0},
{ "MASTER_LOG_POS", SYM(MASTER_LOG_POS_SYM),0,0},
{ "MASTER_PASSWORD", SYM(MASTER_PASSWORD_SYM),0,0},
{ "MASTER_PORT", SYM(MASTER_PORT_SYM),0,0},
{ "MASTER_USER", SYM(MASTER_USER_SYM),0,0},
{ "MAX_ROWS", SYM(MAX_ROWS),0,0},
{ "MATCH", SYM(MATCH),0,0},
{ "MEDIUMBLOB", SYM(MEDIUMBLOB),0,0},
......
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
......@@ -58,7 +58,7 @@ static int send_file(THD *thd)
// the job
old_timeout = thd->net.timeout;
thd->net.timeout = thd->inactive_timeout;
// we need net_flush here because the client will not know it needs to send
// us the file name until it has processed the load event entry
if (net_flush(net) || (packet_len = my_net_read(net)) == packet_error)
......@@ -67,16 +67,16 @@ static int send_file(THD *thd)
goto err;
}
fn_format(fname, (char*)net->read_pos + 1, "", "", 4);
fn_format(fname, (char*)net->read_pos + 1, "", "", 4);
if(!strcmp(fname,"/dev/null")) goto end; // this is needed to make replicate-ignore-db
// work on the well-known system that does not have a /dev/null :-)
if ((fd = my_open(fname, O_RDONLY, MYF(MY_WME))) < 0)
{
errmsg = "Failed on my_open()";
goto err;
}
while ((bytes = (int) my_read(fd, (byte*) buf, sizeof(buf),
MYF(MY_WME))) > 0)
{
......@@ -87,7 +87,7 @@ static int send_file(THD *thd)
}
}
end:
end:
if (my_net_write(net, "", 0) || net_flush(net) ||
(my_net_read(net) == packet_error))
{
......@@ -95,7 +95,7 @@ static int send_file(THD *thd)
goto err;
}
error = 0;
err:
thd->net.timeout = old_timeout;
if(fd >= 0)
......@@ -104,7 +104,7 @@ static int send_file(THD *thd)
{
sql_print_error("failed in send_file() : %s", errmsg);
DBUG_PRINT("error", (errmsg));
}
}
DBUG_RETURN(error);
}
......@@ -195,12 +195,12 @@ void mysql_binlog_send(THD* thd, char* log_ident, ulong pos, ushort flags)
errmsg = "Binary log is not open";
goto err;
}
if(log_ident[0])
mysql_bin_log.make_log_name(search_file_name, log_ident);
else
search_file_name[0] = 0;
if(mysql_bin_log.find_first_log(&linfo, search_file_name))
{
errmsg = "Could not find first log";
......@@ -219,8 +219,8 @@ void mysql_binlog_send(THD* thd, char* log_ident, ulong pos, ushort flags)
errmsg = "Error on fseek()";
goto err;
}
packet->length(0);
packet->append("\0", 1); // we need to start a packet with something other than 255
// to distiquish it from error
......@@ -251,7 +251,7 @@ void mysql_binlog_send(THD* thd, char* log_ident, ulong pos, ushort flags)
errmsg = "error reading log event";
goto err;
}
if(!(flags & BINLOG_DUMP_NON_BLOCK) && mysql_bin_log.is_active(log_file_name))
// block until there is more data in the log
// unless non-blocking mode requested
......@@ -267,10 +267,10 @@ void mysql_binlog_send(THD* thd, char* log_ident, ulong pos, ushort flags)
// if we did not miss anything, we just wait for other threads
// to signal us
{
pthread_mutex_t *log_lock = mysql_bin_log.get_log_lock();
pthread_mutex_t *log_lock = mysql_bin_log.get_log_lock();
clearerr(log);
// tell the kill thread how to wake us up
// tell the kill thread how to wake us up
pthread_mutex_lock(&thd->mysys_var->mutex);
thd->mysys_var->current_mutex = log_lock;
thd->mysys_var->current_cond = &COND_binlog_update;
......@@ -283,7 +283,7 @@ void mysql_binlog_send(THD* thd, char* log_ident, ulong pos, ushort flags)
pthread_mutex_lock(log_lock); // no one will update the log while we are reading
// now, but we'll be quick and just read one record
switch(Log_event::read_log_event(log, packet))
{
case 0:
......@@ -300,7 +300,7 @@ void mysql_binlog_send(THD* thd, char* log_ident, ulong pos, ushort flags)
}
pthread_mutex_unlock(log_lock);
pthread_mutex_lock(&thd->mysys_var->mutex);
thd->mysys_var->current_mutex= 0;
thd->mysys_var->current_cond= 0;
......@@ -314,7 +314,7 @@ void mysql_binlog_send(THD* thd, char* log_ident, ulong pos, ushort flags)
errmsg = "Failed on my_net_write()";
goto err;
}
if((*packet)[LOG_EVENT_OFFSET+1] == LOAD_EVENT)
{
if(send_file(thd))
......@@ -334,14 +334,14 @@ void mysql_binlog_send(THD* thd, char* log_ident, ulong pos, ushort flags)
errmsg = "error reading log entry";
goto err;
}
clearerr(log);
}
}
else
{
bool loop_breaker = 0; // need this to break out of the for loop from switch
switch(mysql_bin_log.find_next_log(&linfo))
{
case LOG_INFO_EOF:
......@@ -367,12 +367,12 @@ void mysql_binlog_send(THD* thd, char* log_ident, ulong pos, ushort flags)
char header[9];
memset(header, 0, 4); // when does not matter
header[4] = ROTATE_EVENT;
char* p = strrchr(log_file_name, FN_LIBCHAR); // find the last slash
char* p = strrchr(log_file_name, FN_LIBCHAR); // find the last slash
if(p)
p++;
else
p = log_file_name;
uint ident_len = (uint) strlen(p);
ulong event_len = ident_len + sizeof(header);
int4store(header + 5, event_len);
......@@ -388,9 +388,9 @@ void mysql_binlog_send(THD* thd, char* log_ident, ulong pos, ushort flags)
}
}
}
(void)my_fclose(log, MYF(MY_WME));
send_eof(&thd->net);
DBUG_VOID_RETURN;
err:
......@@ -646,7 +646,7 @@ void close_thread_tables(THD *thd, bool locked)
VOID(pthread_mutex_lock(&LOCK_open));
DBUG_PRINT("info", ("thd->open_tables=%p", thd->open_tables));
for (table=thd->open_tables ; table ; table=next)
{
next=table->next;
......@@ -820,7 +820,7 @@ TABLE *unlink_open_table(THD *thd, TABLE *list, TABLE *find)
}
/*
/*
When we call the following function we must have a lock on
LOCK_OPEN ; This lock will be unlocked on return.
*/
......@@ -957,7 +957,7 @@ TABLE *open_table(THD *thd,const char *db,const char *table_name,
{
MEM_ROOT* glob_alloc;
LINT_INIT(glob_alloc);
if(errno == ENOENT &&
(glob_alloc = my_pthread_getspecific_ptr(MEM_ROOT*,THR_MALLOC)))
// Sasha: needed for replication
......@@ -1288,7 +1288,7 @@ bool wait_for_tables(THD *thd)
while (table_is_used(thd->open_tables) && ! thd->killed)
{
(void) pthread_cond_wait(&COND_refresh,&LOCK_open);
(void) pthread_cond_wait(&COND_refresh,&LOCK_open);
}
if (thd->killed)
......@@ -1298,7 +1298,7 @@ bool wait_for_tables(THD *thd)
/* Now we can open all tables without any interference */
thd->proc_info="Reopen tables";
result=reopen_tables(thd,0,0);
}
}
pthread_mutex_unlock(&LOCK_open);
thd->proc_info=0;
DBUG_RETURN(result);
......@@ -1744,7 +1744,7 @@ find_item_in_list(Item *find,List<Item> &items)
}
}
}
else if (!table_name && (item->eq(find) ||
else if (!table_name && (item->eq(find) ||
find->name &&
!my_strcasecmp(item->name,find->name)))
{
......@@ -1824,7 +1824,7 @@ int setup_fields(THD *thd, TABLE_LIST *tables, List<Item> &fields,
}
DBUG_RETURN(test(thd->fatal_error));
}
static key_map get_key_map_from_key_list(THD *thd, TABLE *table,
List<String> *index_list)
......@@ -2172,18 +2172,22 @@ bool remove_table_from_cache(THD *thd, const char *db,const char *table_name)
DBUG_RETURN(result);
}
/*
Will be used for ft-query optimization someday.
SerG.
*/
int setup_ftfuncs(THD *thd,TABLE_LIST *tables, List<Item_func_match> &ftfuncs)
{
List_iterator<Item_func_match> li(ftfuncs);
Item_func_match *ftf;
List_iterator<Item_func_match> li(ftfuncs), li2(ftfuncs);
Item_func_match *ftf, *ftf2;
while ((ftf=li++))
{
if (ftf->fix_index())
return 1;
li2.rewind();
while ((ftf2=li2++) != ftf)
{
if (ftf->eq(ftf2) && !ftf2->master)
ftf2->master=ftf;
}
}
return 0;
}
......@@ -1284,11 +1284,11 @@ add_ft_keys(DYNAMIC_ARRAY *keyuse_array,
KEYUSE keyuse;
keyuse.table= cond_func->table;
keyuse.val = cond_func->key_item();
keyuse.val = cond_func;
keyuse.key = cond_func->key;
#define FT_KEYPART (MAX_REF_PARTS+10)
keyuse.keypart=FT_KEYPART;
keyuse.used_tables=keyuse.val->used_tables();
keyuse.used_tables=cond_func->key_item()->used_tables();
VOID(insert_dynamic(keyuse_array,(gptr) &keyuse));
}
......@@ -1670,7 +1670,7 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
else
tmp=best_time; // Do nothing
}
} /* not ftkey */
} /* not ft_key */
if (tmp < best_time - records/(double) TIME_FOR_COMPARE)
{
best_time=tmp + records/(double) TIME_FOR_COMPARE;
......@@ -1882,26 +1882,29 @@ get_best_combination(JOIN *join)
keyinfo=table->key_info+key;
if (ftkey)
{
ft_tmp=keyuse->val->val_str(&tmp2);
Item_func_match *ifm=(Item_func_match *)keyuse->val;
ft_tmp=ifm->key_item()->val_str(&tmp2);
length=ft_tmp->length();
keyparts=1;
ifm->join_key=1;
}
else
{
keyparts=length=0;
do
{
if (!((~used_tables) & keyuse->used_tables))
{
if (keyparts == keyuse->keypart)
{
keyparts++;
length+=keyinfo->key_part[keyuse->keypart].length +
test(keyinfo->key_part[keyuse->keypart].null_bit);
}
}
keyuse++;
} while (keyuse->table == table && keyuse->key == key);
keyparts=length=0;
do
{
if (!((~used_tables) & keyuse->used_tables))
{
if (keyparts == keyuse->keypart)
{
keyparts++;
length+=keyinfo->key_part[keyuse->keypart].length +
test(keyinfo->key_part[keyuse->keypart].null_bit);
}
}
keyuse++;
} while (keyuse->table == table && keyuse->key == key);
} /* not ftkey */
/* set up fieldref */
......@@ -1924,7 +1927,7 @@ get_best_combination(JOIN *join)
byte *key_buff=j->ref.key_buff;
if (ftkey)
{
j->ref.items[0]=keyuse->val;
j->ref.items[0]=((Item_func*)(keyuse->val))->key_item();
if (!keyuse->used_tables &&
!(join->select_options & SELECT_DESCRIBE))
{
......
......@@ -137,7 +137,6 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token CHANGED_FILES
%token CHECKSUM_SYM
%token CHECK_SYM
%token COLLECTION
%token COLUMNS
%token COLUMN_SYM
%token CONSTRAINT
......@@ -162,6 +161,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token FOREIGN
%token FROM
%token FULL
%token FULLTEXT_SYM
%token GRANT
%token GRANTS
%token GREATEST_SYM
......@@ -457,7 +457,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
expr_list udf_expr_list when_list ident_list
%type <key_type>
key_type opt_unique
key_type opt_unique_or_fulltext
%type <string_list>
key_usage_list
......@@ -628,7 +628,7 @@ create:
}
create2
| CREATE opt_unique INDEX ident ON table_ident
| CREATE opt_unique_or_fulltext INDEX ident ON table_ident
{
Lex->sql_command= SQLCOM_CREATE_INDEX;
if (!add_table_to_list($6,NULL))
......@@ -643,21 +643,6 @@ create:
Lex->key_list.push_back(new Key($2,$4.str,Lex->col_list));
Lex->col_list.empty();
}
| CREATE COLLECTION ident ON table_ident
{
Lex->sql_command= SQLCOM_CREATE_INDEX;
if (!add_table_to_list($5,NULL))
YYABORT;
Lex->create_list.empty();
Lex->key_list.empty();
Lex->col_list.empty();
Lex->change=NullS;
}
'(' key_list ')'
{
Lex->key_list.push_back(new Key(Key::FULLTEXT,$3.str,Lex->col_list));
Lex->col_list.empty();
}
| CREATE DATABASE opt_if_not_exists ident
{
Lex->sql_command=SQLCOM_CREATE_DB;
......@@ -964,7 +949,8 @@ delete_option:
key_type:
opt_constraint PRIMARY_SYM KEY_SYM { $$= Key::PRIMARY; }
| key_or_index { $$= Key::MULTIPLE; }
| COLLECTION { $$= Key::FULLTEXT; }
| FULLTEXT_SYM { $$= Key::FULLTEXT; }
| FULLTEXT_SYM key_or_index { $$= Key::FULLTEXT; }
| opt_constraint UNIQUE_SYM { $$= Key::UNIQUE; }
| opt_constraint UNIQUE_SYM key_or_index { $$= Key::UNIQUE; }
......@@ -976,9 +962,10 @@ keys_or_index:
KEYS {}
| INDEX {}
opt_unique:
opt_unique_or_fulltext:
/* empty */ { $$= Key::MULTIPLE; }
| UNIQUE_SYM { $$= Key::UNIQUE; }
| FULLTEXT_SYM { $$= Key::FULLTEXT; }
key_list:
key_list ',' key_part order_dir { Lex->col_list.push_back($3); }
......@@ -2443,7 +2430,6 @@ keyword:
| WORK_SYM {}
| YEAR_SYM {}
| SLAVE {}
| COLLECTION {}
/* Option functions */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment