diff options
author | unknown <serg@infomag.ape.relarn.ru> | 2000-08-28 17:43:58 +0400 |
---|---|---|
committer | unknown <serg@infomag.ape.relarn.ru> | 2000-08-28 17:43:58 +0400 |
commit | ca04c0eca770ebc50bb336f3ec3d66eb2fe46b58 (patch) | |
tree | 485c3b99b43fae8c2b58b7a5ab72b383265423d2 /sql | |
parent | fe26eac2198e79de6e23c17c5033a5c7bc8e1d41 (diff) | |
download | mariadb-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.cc | 69 | ||||
-rw-r--r-- | sql/item_func.h | 21 | ||||
-rw-r--r-- | sql/lex.h | 24 | ||||
-rw-r--r-- | sql/sql_base.cc | 84 | ||||
-rw-r--r-- | sql/sql_select.cc | 41 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 28 |
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 */ |