summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorunknown <serg@infomag.ape.relarn.ru>2000-08-28 17:43:58 +0400
committerunknown <serg@infomag.ape.relarn.ru>2000-08-28 17:43:58 +0400
commitca04c0eca770ebc50bb336f3ec3d66eb2fe46b58 (patch)
tree485c3b99b43fae8c2b58b7a5ab72b383265423d2 /sql
parentfe26eac2198e79de6e23c17c5033a5c7bc8e1d41 (diff)
downloadmariadb-git-ca04c0eca770ebc50bb336f3ec3d66eb2fe46b58.tar.gz
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
Diffstat (limited to 'sql')
-rw-r--r--sql/item_func.cc69
-rw-r--r--sql/item_func.h21
-rw-r--r--sql/lex.h24
-rw-r--r--sql/sql_base.cc84
-rw-r--r--sql/sql_select.cc41
-rw-r--r--sql/sql_yacc.yy28
6 files changed, 150 insertions, 117 deletions
diff --git a/sql/item_func.cc b/sql/item_func.cc
index 66e03e72f6b..65677690ed3 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -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;
}
diff --git a/sql/item_func.h b/sql/item_func.h
index efee77c7be2..4af3e604f38 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -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();
};
diff --git a/sql/lex.h b/sql/lex.h
index a88bbe76fdd..a5c802e761c 100644
--- a/sql/lex.h
+++ b/sql/lex.h
@@ -1,15 +1,15 @@
/* 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},
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index e6468890ed6..6bf44f7d7d6 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -1,15 +1,15 @@
/* 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;
}
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index c779b9f555a..6578e3b717a 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -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))
{
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index b39299a54e6..a79531535c7 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -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 */