mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03:00
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. myisam/mi_check.c: comments added sql/lex.h: COLLECTION -> FULLTEXT sql/item_func.h: ft-optimization: identical queries merging sql/sql_select.cc: ft-optimization sql/item_func.cc: ft-optimization: identical queries merging sql/sql_base.cc: ft_optimization: identical queries merging sql/sql_yacc.yy: COLLECTION -> FULLTEXT myisam/ft_search.c: info->lastpot dealing Docs/manual.texi: COLLECTION -> FULLTEXT
This commit is contained in:
@ -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
|
* GRANT:: @code{GRANT} and @code{REVOKE} syntax
|
||||||
* CREATE INDEX:: @code{CREATE INDEX} syntax
|
* CREATE INDEX:: @code{CREATE INDEX} syntax
|
||||||
* DROP INDEX:: @code{DROP INDEX} syntax
|
* DROP INDEX:: @code{DROP INDEX} syntax
|
||||||
* CREATE COLLECTION:: @code{CREATE COLLECTION} syntax
|
|
||||||
* Comments:: Comment syntax
|
* Comments:: Comment syntax
|
||||||
* CREATE FUNCTION:: @code{CREATE FUNCTION} syntax
|
* CREATE FUNCTION:: @code{CREATE FUNCTION} syntax
|
||||||
* Reserved words:: Is @strong{MySQL} picky about reserved words?
|
* 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
|
For @code{BLOB} and @code{TEXT} columns, you must index a prefix of the
|
||||||
column, you cannot index the entire thing.
|
column, you cannot index the entire thing.
|
||||||
|
|
||||||
In @strong{MySQL} 3.23.23 or later, you can also create special indexes
|
In @strong{MySQL} 3.23.23 or later, you can also create special
|
||||||
called @strong{collections}. They are used for full-text search. Only
|
@strong{fulltext} indexes. They are used for full-text search. Only
|
||||||
@code{MyISAM} table type supports collections. Collection can be created
|
@code{MyISAM} table type supports fulltext indexes. They can be created
|
||||||
only from @code{VARCHAR}, @code{BLOB}, and @code{TEXT} columns.
|
only from @code{VARCHAR}, @code{BLOB}, and @code{TEXT} columns.
|
||||||
Indexing always happens over the entire column, partial indexing is not
|
Indexing always happens over the entire column, partial indexing is not
|
||||||
supported. See @ref{MySQL full-text search} for details of operation.
|
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
|
relevance - similarity measure between the text in columns
|
||||||
@code{(col1,col2,...)} and the query @code{expr}. Relevance is a
|
@code{(col1,col2,...)} and the query @code{expr}. Relevance is a
|
||||||
positive floating point number. Zero relevance means no similarity.
|
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}}.
|
must be created first. @xref{CREATE TABLE, , @code{CREATE TABLE}}.
|
||||||
@code{MATCH ... AGAINST()} is available in @code{MySQL} 3.23.23 or later.
|
@code{MATCH ... AGAINST()} is available in @code{MySQL} 3.23.23 or later.
|
||||||
For details and usage examples see @xref{MySQL full-text search}.
|
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 KEY [index_name] (index_col_name,...)
|
||||||
or INDEX [index_name] (index_col_name,...)
|
or INDEX [index_name] (index_col_name,...)
|
||||||
or UNIQUE [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,...)
|
or [CONSTRAINT symbol] FOREIGN KEY index_name (index_col_name,...)
|
||||||
[reference_definition]
|
[reference_definition]
|
||||||
or CHECK (expr)
|
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}}.
|
@xref{BLOB, , @code{BLOB}}.
|
||||||
|
|
||||||
@item
|
@item
|
||||||
In @strong{MySQL} 3.23.23 or later, you can also create special indexes
|
In @strong{MySQL} 3.23.23 or later, you can also create special
|
||||||
called @strong{collections}. They are used for full-text search. Only
|
@strong{fulltext} indexes. They are used for full-text search. Only
|
||||||
@code{MyISAM} table type supports collections. Collection can be created
|
@code{MyISAM} table type supports fulltext indexes. They can be created
|
||||||
from any mix of @code{VARCHAR}, @code{BLOB}, and @code{TEXT} columns.
|
only from @code{VARCHAR}, @code{BLOB}, and @code{TEXT} columns.
|
||||||
Indexing always happens over the entire column, partial indexing is not
|
Indexing always happens over the entire column, partial indexing is not
|
||||||
supported. See @ref{MySQL full-text search} for details of operation.
|
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 INDEX [index_name] (index_col_name,...)
|
||||||
or ADD PRIMARY KEY (index_col_name,...)
|
or ADD PRIMARY KEY (index_col_name,...)
|
||||||
or ADD UNIQUE [index_name] (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 ALTER [COLUMN] col_name @{SET DEFAULT literal | DROP DEFAULT@}
|
||||||
or CHANGE [COLUMN] old_col_name create_definition
|
or CHANGE [COLUMN] old_col_name create_definition
|
||||||
or MODIFY [COLUMN] 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
|
@section @code{CREATE INDEX} syntax
|
||||||
|
|
||||||
@example
|
@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
|
@end example
|
||||||
|
|
||||||
The @code{CREATE INDEX} statement doesn't do anything in @strong{MySQL} prior
|
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!
|
operations!
|
||||||
|
|
||||||
Note that you can only add an index on a column that can have @code{NULL}
|
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}
|
@strong{MySQL} version 3.23.2 or newer and are using the @code{MyISAM}
|
||||||
table type.
|
table type.
|
||||||
|
|
||||||
For more information about how @strong{MySQL} uses indexes, see
|
For more information about how @strong{MySQL} uses indexes, see
|
||||||
@ref{MySQL indexes, , @strong{MySQL} indexes}.
|
@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
|
@findex DROP INDEX
|
||||||
@node DROP INDEX, CREATE COLLECTION, CREATE INDEX, Reference
|
@node DROP INDEX, Comments, CREATE INDEX, Reference
|
||||||
@section @code{DROP INDEX} syntax
|
@section @code{DROP INDEX} syntax
|
||||||
|
|
||||||
@example
|
@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.
|
@code{ALTER TABLE} statement to drop the index.
|
||||||
@xref{ALTER TABLE, , @code{ALTER TABLE}}.
|
@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
|
@findex Comment syntax
|
||||||
@node Comments, CREATE FUNCTION, CREATE COLLECTION, Reference
|
@node Comments, CREATE FUNCTION, DROP INDEX, Reference
|
||||||
@section Comment syntax
|
@section Comment syntax
|
||||||
|
|
||||||
The @strong{MySQL} server supports the @code{# to end of line}, @code{--
|
The @strong{MySQL} server supports the @code{# to end of line}, @code{--
|
||||||
@ -34106,14 +34087,14 @@ DELAYED} threads.
|
|||||||
@section MySQL full-text search
|
@section MySQL full-text search
|
||||||
|
|
||||||
Since version 3.23.23, @strong{MySQL} has support for full-text indexing
|
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
|
and searching. Full-text index in @strong{MySQL} is an
|
||||||
called @strong{collection}. Collections can be created from @code{VARCHAR},
|
index of type @code{FULLTEXT}. Fulltext indexes can be created from
|
||||||
@code{TEXT}, and @code{BLOB} columns at @code{CREATE TABLE}
|
@code{VARCHAR}, @code{TEXT}, and @code{BLOB} columns at
|
||||||
time or added later with @code{ALTER TABLE} or @code{CREATE COLLECTION}.
|
@code{CREATE TABLE} time or added later with @code{ALTER TABLE} or
|
||||||
Collection is queried with @code{MATCH} function.
|
@code{CREATE INDEX}. Full-text search is performed with @code{MATCH} function.
|
||||||
|
|
||||||
@example
|
@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)
|
Query OK, 0 rows affected (0.00 sec)
|
||||||
mysql> INSERT INTO t VALUES
|
mysql> INSERT INTO t VALUES
|
||||||
-> ('MySQL has now support', 'for full-text search'),
|
-> ('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
|
@end example
|
||||||
|
|
||||||
Function @code{MATCH} matches a natural language query @code{AGAINST} a
|
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
|
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}
|
are part of the collection) and the query. When it used in a
|
||||||
clause (see example above) the rows returned are automatically sorted
|
@code{WHERE} clause (see example above) the rows returned are
|
||||||
with relevance decreasing. Relevance is a non-negative floating point
|
automatically sorted with relevance decreasing. Relevance is a non-
|
||||||
number. Zero relevance means no similarity. Relevance is computed based
|
negative floating point number. Zero relevance means no similarity.
|
||||||
on number of words in the row and number of unique words in that row,
|
Relevance is computed based on number of words in the row and number of
|
||||||
total number of words in the collection, number of documents (rows),
|
unique words in that row, total number of words in the collection,
|
||||||
that contain a particular word, etc.
|
number of documents (rows), that contain a particular word, etc.
|
||||||
|
|
||||||
MySQL uses very simple parser to split text into words. "Word" is
|
MySQL uses very simple parser to split text into words. "Word" is
|
||||||
any sequence of letters, numbers, @code{'}, and @code{_}. Any "word"
|
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;
|
ALL_IN_ONE aio;
|
||||||
FT_DOCLIST *dlist;
|
FT_DOCLIST *dlist;
|
||||||
FT_DOC *dptr;
|
FT_DOC *dptr;
|
||||||
|
my_off_t saved_lastpos;
|
||||||
|
|
||||||
/* black magic ON */
|
/* black magic ON */
|
||||||
if ((int) (keynr = _mi_check_index((MI_INFO *)info,keynr)) < 0)
|
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.keyinfo=aio.info->s->keyinfo+keynr;
|
||||||
aio.key_root=aio.info->s->state.key_root[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;
|
if(!(wtree=ft_parse(NULL,key,key_len))) return NULL;
|
||||||
|
|
||||||
init_tree(&aio.dtree,0,sizeof(FT_SUPERDOC),(qsort_cmp)&FT_SUPERDOC_cmp,0,
|
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:
|
err:
|
||||||
|
aio.info->lastpos=saved_lastpos;
|
||||||
delete_tree(&aio.dtree);
|
delete_tree(&aio.dtree);
|
||||||
delete_tree(wtree);
|
delete_tree(wtree);
|
||||||
free(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);
|
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 */
|
info->update|= HA_STATE_AKTIV; /* Record is read */
|
||||||
return 0;
|
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++)
|
for (i=0 ; i < share->state.header.max_block_size ; i++)
|
||||||
share->state.key_del[i]= HA_OFFSET_ERROR;
|
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;
|
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");
|
"Found too many records; Can`t continue");
|
||||||
DBUG_RETURN(1);
|
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 )
|
if (sort_info->keyinfo->flag & HA_FULLTEXT )
|
||||||
{
|
{
|
||||||
mi_check_print_error(sort_info->param,
|
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 */
|
return FALSE; /* Can't use sort */
|
||||||
for (i=0 ; i < share->base.keys ; i++,key++)
|
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))
|
if (mi_too_big_key_for_sort(key,rows) || (key->flag & HA_FULLTEXT))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
@ -1837,26 +1837,8 @@ err:
|
|||||||
|
|
||||||
double Item_func_match::val()
|
double Item_func_match::val()
|
||||||
{
|
{
|
||||||
my_off_t docid=table->file->row_position(); // HAVE to do it here...
|
|
||||||
|
|
||||||
if (first_call)
|
if (first_call)
|
||||||
{
|
init_search();
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Don't know how to return an error from val(), so NULL will be returned
|
// Don't know how to return an error from val(), so NULL will be returned
|
||||||
if ((null_value=(ft_handler==NULL)))
|
if ((null_value=(ft_handler==NULL)))
|
||||||
@ -1873,6 +1855,7 @@ double Item_func_match::val()
|
|||||||
|
|
||||||
int a,b,c;
|
int a,b,c;
|
||||||
FT_DOC *docs=ft_handler->doc;
|
FT_DOC *docs=ft_handler->doc;
|
||||||
|
my_off_t docid=table->file->row_position();
|
||||||
|
|
||||||
if ((null_value=(docid==HA_OFFSET_ERROR)))
|
if ((null_value=(docid==HA_OFFSET_ERROR)))
|
||||||
return 0.0;
|
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)
|
bool Item_func_match::fix_fields(THD *thd,struct st_table_list *tlist)
|
||||||
{
|
{
|
||||||
List_iterator<Item> li(fields);
|
List_iterator<Item> li(fields);
|
||||||
@ -1982,6 +1995,24 @@ bool Item_func_match::fix_index()
|
|||||||
this->key=max_key;
|
this->key=max_key;
|
||||||
first_call=1;
|
first_call=1;
|
||||||
maybe_null=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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -839,19 +839,28 @@ public:
|
|||||||
TABLE *table;
|
TABLE *table;
|
||||||
uint key;
|
uint key;
|
||||||
bool first_call, join_key;
|
bool first_call, join_key;
|
||||||
|
Item_func_match *master;
|
||||||
FT_DOCLIST *ft_handler;
|
FT_DOCLIST *ft_handler;
|
||||||
|
|
||||||
Item_func_match(List<Item> &a, Item *b): Item_real_func(b),
|
Item_func_match(List<Item> &a, Item *b): Item_real_func(b),
|
||||||
fields(a), table(0), ft_handler(0)
|
fields(a), table(0), ft_handler(0), master(0) {}
|
||||||
{}
|
~Item_func_match()
|
||||||
~Item_func_match() { ft_close_search(ft_handler);
|
{
|
||||||
if(join_key) table->file->ft_handler=0; }
|
if (!master)
|
||||||
|
{
|
||||||
|
ft_close_search(ft_handler);
|
||||||
|
if(join_key)
|
||||||
|
table->file->ft_handler=0;
|
||||||
|
}
|
||||||
|
}
|
||||||
const char *func_name() const { return "match"; }
|
const char *func_name() const { return "match"; }
|
||||||
enum Functype functype() const { return FT_FUNC; }
|
enum Functype functype() const { return FT_FUNC; }
|
||||||
void update_used_tables() {}
|
void update_used_tables() {}
|
||||||
bool fix_fields(THD *thd,struct st_table_list *tlist);
|
bool fix_fields(THD *thd,struct st_table_list *tlist);
|
||||||
bool fix_index();
|
bool eq(const Item *) const;
|
||||||
|
|
||||||
double val();
|
double val();
|
||||||
longlong val_int() { return val()!=0.0; }
|
longlong val_int() { return val()!=0.0; }
|
||||||
|
|
||||||
|
bool fix_index();
|
||||||
|
void init_search();
|
||||||
};
|
};
|
||||||
|
@ -81,7 +81,6 @@ static SYMBOL symbols[] = {
|
|||||||
{ "CHANGED", SYM(CHANGED),0,0},
|
{ "CHANGED", SYM(CHANGED),0,0},
|
||||||
{ "CHECK", SYM(CHECK_SYM),0,0},
|
{ "CHECK", SYM(CHECK_SYM),0,0},
|
||||||
{ "CHECKSUM", SYM(CHECKSUM_SYM),0,0},
|
{ "CHECKSUM", SYM(CHECKSUM_SYM),0,0},
|
||||||
{ "COLLECTION", SYM(COLLECTION),0,0},
|
|
||||||
{ "COLUMN", SYM(COLUMN_SYM),0,0},
|
{ "COLUMN", SYM(COLUMN_SYM),0,0},
|
||||||
{ "COLUMNS", SYM(COLUMNS),0,0},
|
{ "COLUMNS", SYM(COLUMNS),0,0},
|
||||||
{ "COMMENT", SYM(COMMENT_SYM),0,0},
|
{ "COMMENT", SYM(COMMENT_SYM),0,0},
|
||||||
@ -142,6 +141,7 @@ static SYMBOL symbols[] = {
|
|||||||
{ "FROM", SYM(FROM),0,0},
|
{ "FROM", SYM(FROM),0,0},
|
||||||
{ "FOR", SYM(FOR_SYM),0,0},
|
{ "FOR", SYM(FOR_SYM),0,0},
|
||||||
{ "FULL", SYM(FULL),0,0},
|
{ "FULL", SYM(FULL),0,0},
|
||||||
|
{ "FULLTEXT", SYM(FULLTEXT_SYM),0,0},
|
||||||
{ "FUNCTION", SYM(UDF_SYM),0,0},
|
{ "FUNCTION", SYM(UDF_SYM),0,0},
|
||||||
{ "GRANT", SYM(GRANT),0,0},
|
{ "GRANT", SYM(GRANT),0,0},
|
||||||
{ "GRANTS", SYM(GRANTS),0,0},
|
{ "GRANTS", SYM(GRANTS),0,0},
|
||||||
|
@ -2172,18 +2172,22 @@ bool remove_table_from_cache(THD *thd, const char *db,const char *table_name)
|
|||||||
DBUG_RETURN(result);
|
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)
|
int setup_ftfuncs(THD *thd,TABLE_LIST *tables, List<Item_func_match> &ftfuncs)
|
||||||
{
|
{
|
||||||
List_iterator<Item_func_match> li(ftfuncs);
|
List_iterator<Item_func_match> li(ftfuncs), li2(ftfuncs);
|
||||||
Item_func_match *ftf;
|
Item_func_match *ftf, *ftf2;
|
||||||
|
|
||||||
while ((ftf=li++))
|
while ((ftf=li++))
|
||||||
|
{
|
||||||
if (ftf->fix_index())
|
if (ftf->fix_index())
|
||||||
return 1;
|
return 1;
|
||||||
|
li2.rewind();
|
||||||
|
while ((ftf2=li2++) != ftf)
|
||||||
|
{
|
||||||
|
if (ftf->eq(ftf2) && !ftf2->master)
|
||||||
|
ftf2->master=ftf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1284,11 +1284,11 @@ add_ft_keys(DYNAMIC_ARRAY *keyuse_array,
|
|||||||
KEYUSE keyuse;
|
KEYUSE keyuse;
|
||||||
|
|
||||||
keyuse.table= cond_func->table;
|
keyuse.table= cond_func->table;
|
||||||
keyuse.val = cond_func->key_item();
|
keyuse.val = cond_func;
|
||||||
keyuse.key = cond_func->key;
|
keyuse.key = cond_func->key;
|
||||||
#define FT_KEYPART (MAX_REF_PARTS+10)
|
#define FT_KEYPART (MAX_REF_PARTS+10)
|
||||||
keyuse.keypart=FT_KEYPART;
|
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));
|
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
|
else
|
||||||
tmp=best_time; // Do nothing
|
tmp=best_time; // Do nothing
|
||||||
}
|
}
|
||||||
} /* not ftkey */
|
} /* not ft_key */
|
||||||
if (tmp < best_time - records/(double) TIME_FOR_COMPARE)
|
if (tmp < best_time - records/(double) TIME_FOR_COMPARE)
|
||||||
{
|
{
|
||||||
best_time=tmp + records/(double) TIME_FOR_COMPARE;
|
best_time=tmp + records/(double) TIME_FOR_COMPARE;
|
||||||
@ -1882,9 +1882,12 @@ get_best_combination(JOIN *join)
|
|||||||
keyinfo=table->key_info+key;
|
keyinfo=table->key_info+key;
|
||||||
if (ftkey)
|
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();
|
length=ft_tmp->length();
|
||||||
keyparts=1;
|
keyparts=1;
|
||||||
|
ifm->join_key=1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1924,7 +1927,7 @@ get_best_combination(JOIN *join)
|
|||||||
byte *key_buff=j->ref.key_buff;
|
byte *key_buff=j->ref.key_buff;
|
||||||
if (ftkey)
|
if (ftkey)
|
||||||
{
|
{
|
||||||
j->ref.items[0]=keyuse->val;
|
j->ref.items[0]=((Item_func*)(keyuse->val))->key_item();
|
||||||
if (!keyuse->used_tables &&
|
if (!keyuse->used_tables &&
|
||||||
!(join->select_options & SELECT_DESCRIBE))
|
!(join->select_options & SELECT_DESCRIBE))
|
||||||
{
|
{
|
||||||
|
@ -137,7 +137,6 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
|
|||||||
%token CHANGED_FILES
|
%token CHANGED_FILES
|
||||||
%token CHECKSUM_SYM
|
%token CHECKSUM_SYM
|
||||||
%token CHECK_SYM
|
%token CHECK_SYM
|
||||||
%token COLLECTION
|
|
||||||
%token COLUMNS
|
%token COLUMNS
|
||||||
%token COLUMN_SYM
|
%token COLUMN_SYM
|
||||||
%token CONSTRAINT
|
%token CONSTRAINT
|
||||||
@ -162,6 +161,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
|
|||||||
%token FOREIGN
|
%token FOREIGN
|
||||||
%token FROM
|
%token FROM
|
||||||
%token FULL
|
%token FULL
|
||||||
|
%token FULLTEXT_SYM
|
||||||
%token GRANT
|
%token GRANT
|
||||||
%token GRANTS
|
%token GRANTS
|
||||||
%token GREATEST_SYM
|
%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
|
expr_list udf_expr_list when_list ident_list
|
||||||
|
|
||||||
%type <key_type>
|
%type <key_type>
|
||||||
key_type opt_unique
|
key_type opt_unique_or_fulltext
|
||||||
|
|
||||||
%type <string_list>
|
%type <string_list>
|
||||||
key_usage_list
|
key_usage_list
|
||||||
@ -628,7 +628,7 @@ create:
|
|||||||
}
|
}
|
||||||
create2
|
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;
|
Lex->sql_command= SQLCOM_CREATE_INDEX;
|
||||||
if (!add_table_to_list($6,NULL))
|
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->key_list.push_back(new Key($2,$4.str,Lex->col_list));
|
||||||
Lex->col_list.empty();
|
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
|
| CREATE DATABASE opt_if_not_exists ident
|
||||||
{
|
{
|
||||||
Lex->sql_command=SQLCOM_CREATE_DB;
|
Lex->sql_command=SQLCOM_CREATE_DB;
|
||||||
@ -964,7 +949,8 @@ delete_option:
|
|||||||
key_type:
|
key_type:
|
||||||
opt_constraint PRIMARY_SYM KEY_SYM { $$= Key::PRIMARY; }
|
opt_constraint PRIMARY_SYM KEY_SYM { $$= Key::PRIMARY; }
|
||||||
| key_or_index { $$= Key::MULTIPLE; }
|
| 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::UNIQUE; }
|
||||||
| opt_constraint UNIQUE_SYM key_or_index { $$= Key::UNIQUE; }
|
| opt_constraint UNIQUE_SYM key_or_index { $$= Key::UNIQUE; }
|
||||||
|
|
||||||
@ -976,9 +962,10 @@ keys_or_index:
|
|||||||
KEYS {}
|
KEYS {}
|
||||||
| INDEX {}
|
| INDEX {}
|
||||||
|
|
||||||
opt_unique:
|
opt_unique_or_fulltext:
|
||||||
/* empty */ { $$= Key::MULTIPLE; }
|
/* empty */ { $$= Key::MULTIPLE; }
|
||||||
| UNIQUE_SYM { $$= Key::UNIQUE; }
|
| UNIQUE_SYM { $$= Key::UNIQUE; }
|
||||||
|
| FULLTEXT_SYM { $$= Key::FULLTEXT; }
|
||||||
|
|
||||||
key_list:
|
key_list:
|
||||||
key_list ',' key_part order_dir { Lex->col_list.push_back($3); }
|
key_list ',' key_part order_dir { Lex->col_list.push_back($3); }
|
||||||
@ -2443,7 +2430,6 @@ keyword:
|
|||||||
| WORK_SYM {}
|
| WORK_SYM {}
|
||||||
| YEAR_SYM {}
|
| YEAR_SYM {}
|
||||||
| SLAVE {}
|
| SLAVE {}
|
||||||
| COLLECTION {}
|
|
||||||
|
|
||||||
/* Option functions */
|
/* Option functions */
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user