diff options
author | unknown <monty@narttu.mysql.fi> | 2002-08-30 12:40:40 +0300 |
---|---|---|
committer | unknown <monty@narttu.mysql.fi> | 2002-08-30 12:40:40 +0300 |
commit | 9421f1dae99e0f2d6100b31a3641b2cd0ad68e58 (patch) | |
tree | 1bb81fd601075133af9ee99bd7ac94baf5ffc46c /myisam | |
parent | cfc861537da2f256f11823b3a4997a033eec73dc (diff) | |
parent | 1895448e66b39542d58a77e705449b92414ff3f7 (diff) | |
download | mariadb-git-9421f1dae99e0f2d6100b31a3641b2cd0ad68e58.tar.gz |
Merge with 4.0.3
Some simple optimzations, more comments and indentation changes.
Add ` around database in 'use database' in binary log.
Moved max_error_count and max_warning_count to variables struct.
Removed SHOW_WARNS_COUNT and SHOW_ERRORS_COUNT calls.
Changed string functions to use character set of first string argument as default return characterset
(Each string function can change the above assumption if needed)
BitKeeper/etc/ignore:
auto-union
BitKeeper/etc/logging_ok:
auto-union
BUILD/SETUP.sh:
Auto merged
BitKeeper/deleted/.del-getopt.h~a9ae679fa84f395:
Auto merged
BitKeeper/deleted/.del-getvar.c~2a29ff383970fd31:
Auto merged
Docs/manual.texi:
Auto merged
SSL/cacert.pem:
Auto merged
SSL/client-cert.pem:
Auto merged
SSL/client-key.pem:
Auto merged
SSL/server-cert.pem:
Auto merged
SSL/server-key.pem:
Auto merged
client/mysqldump.c:
Auto merged
include/my_base.h:
Auto merged
include/my_sys.h:
Auto merged
include/mysql_com.h:
Auto merged
isam/isamlog.c:
Auto merged
isam/pack_isam.c:
Auto merged
libmysqld/lib_sql.cc:
Auto merged
myisam/ft_dump.c:
Auto merged
myisam/ft_parser.c:
Auto merged
myisam/ft_static.c:
Auto merged
myisam/ft_test1.c:
Auto merged
myisam/ft_update.c:
Auto merged
myisam/mi_create.c:
Auto merged
myisam/mi_key.c:
Auto merged
myisam/mi_open.c:
Auto merged
myisam/mi_static.c:
Auto merged
myisam/mi_test1.c:
Auto merged
myisam/mi_test2.c:
Auto merged
myisam/mi_test3.c:
Auto merged
myisam/mi_update.c:
Auto merged
myisam/mi_write.c:
Auto merged
myisam/myisamchk.c:
Auto merged
myisam/myisamdef.h:
Auto merged
myisam/myisamlog.c:
Auto merged
myisam/myisampack.c:
Auto merged
mysql-test/mysql-test-run.sh:
Auto merged
mysql-test/r/create.result:
Auto merged
mysql-test/r/fulltext.result:
Auto merged
mysql-test/r/func_math.result:
Auto merged
mysql-test/r/innodb.result:
Auto merged
mysql-test/r/merge.result:
Auto merged
mysql-test/r/myisam.result:
Auto merged
mysql-test/r/select.result:
Auto merged
mysql-test/r/select_found.result:
Auto merged
mysql-test/r/union.result:
Auto merged
mysql-test/t/create.test:
Auto merged
mysql-test/t/myisam.test:
Auto merged
mysql-test/t/select_found.test:
Auto merged
mysql-test/t/union.test:
Auto merged
mysys/default.c:
Auto merged
mysys/mf_iocache2.c:
Auto merged
mysys/my_error.c:
Auto merged
mysys/my_init.c:
Auto merged
scripts/mysql_config.sh:
Auto merged
sql/convert.cc:
Auto merged
sql/filesort.cc:
Auto merged
sql/gen_lex_hash.cc:
Auto merged
sql/ha_berkeley.cc:
Auto merged
sql/ha_innodb.cc:
Auto merged
sql/ha_myisam.cc:
Auto merged
sql/handler.cc:
Auto merged
sql/handler.h:
Auto merged
sql/hostname.cc:
Auto merged
sql/item.cc:
Auto merged
sql/item_sum.cc:
Auto merged
sql/item_sum.h:
Auto merged
sql/item_timefunc.cc:
Auto merged
sql/item_timefunc.h:
Auto merged
sql/key.cc:
Auto merged
sql/log.cc:
Auto merged
sql/net_pkg.cc:
Auto merged
sql/opt_range.cc:
Auto merged
sql/opt_range.h:
Auto merged
sql/opt_sum.cc:
Auto merged
sql/repl_failsafe.cc:
Auto merged
sql/slave.cc:
Auto merged
sql/sql_cache.cc:
Auto merged
sql/sql_db.cc:
Auto merged
sql/sql_handler.cc:
Auto merged
sql/sql_insert.cc:
Auto merged
sql/sql_lex.cc:
Auto merged
sql/sql_load.cc:
Auto merged
sql/sql_string.cc:
Auto merged
sql/sql_table.cc:
Auto merged
sql/sql_test.cc:
Auto merged
sql/time.cc:
Auto merged
sql/unireg.cc:
Auto merged
strings/Makefile.am:
Auto merged
strings/ctype-latin1_de.c:
Auto merged
strings/ctype-tis620.c:
Auto merged
tools/mysqlmanager.c:
Auto merged
BitKeeper/deleted/.del-sslopt-case.h~224c80e75dad4997:
merge with 4.0.3
BitKeeper/triggers/post-commit:
merge with 4.0.3
client/mysql.cc:
merge with 4.0.3 + simple optimsation
client/mysqltest.c:
merge with 4.0.3 (Indentation change)
configure.in:
merge with 4.0.3
extra/resolve_stack_dump.c:
merge with 4.0.3 (Indentation change)
include/Makefile.am:
merge with 4.0.3
include/myisam.h:
merge with 4.0.3 (Indentation change)
include/mysql.h:
merge with 4.0.3 (removed not used structure)
include/mysqld_error.h:
merge with 4.0.3
libmysql/Makefile.shared:
merge with 4.0.3
libmysql/libmysql.c:
merge with 4.0.3 (Indentation change)
libmysqld/Makefile.am:
merge with 4.0.3
myisam/ft_boolean_search.c:
merge with 4.0.3 (Indentation change)
myisam/ft_nlq_search.c:
merge with 4.0.3 (Indentation change)
myisam/mi_check.c:
merge with 4.0.3
myisam/mi_search.c:
merge with 4.0.3
myisam/mi_unique.c:
merge with 4.0.3
mysys/Makefile.am:
merge with 4.0.3
mysys/mf_casecnv.c:
merge with 4.0.3
sql-bench/server-cfg.sh:
Removed 8000 max row limit for Innodb
sql/Makefile.am:
merge with 4.0.3
sql/field.cc:
Indentation cleanup
Changed sprintf -> my_sprintf
sql/field.h:
merge with 4.0.3
sql/ha_heap.cc:
merge with 4.0.3 (Indentation change)
sql/item.h:
merge with 4.0.3 (Indentation change)
sql/item_cmpfunc.cc:
merge with 4.0.3
sql/item_cmpfunc.h:
Removed size_of() from items
Indentation cleanup
sql/item_create.cc:
merge
sql/item_create.h:
merge
sql/item_func.cc:
Added comments
Changed string functions to use character set of first string argument as default return characterset
Simple optimizations.
Removed return of uninitalized variable.
sql/item_func.h:
merge
sql/item_strfunc.cc:
merge with 4.0.3 (Indentation change)
sql/item_strfunc.h:
removed size_of()
sql/item_uniq.h:
removed size_of()
sql/lex.h:
merge with 4.0.3 (Indentation change)
sql/log_event.cc:
Add ` around database in 'use database' in binary log.
sql/mysql_priv.h:
merge with 4.0.3
sql/mysqld.cc:
merge with 4.0.3 (Indentation change)
sql/share/czech/errmsg.txt:
merge
sql/share/danish/errmsg.txt:
merge
sql/share/dutch/errmsg.txt:
merge
sql/share/english/errmsg.txt:
merge
sql/share/estonian/errmsg.txt:
merge
sql/share/french/errmsg.txt:
merge
sql/share/german/errmsg.txt:
merge
sql/share/greek/errmsg.txt:
merge
sql/share/hungarian/errmsg.txt:
merge
sql/share/italian/errmsg.txt:
merge
sql/share/japanese/errmsg.txt:
merge
sql/share/korean/errmsg.txt:
merge
sql/share/norwegian-ny/errmsg.txt:
merge
sql/share/norwegian/errmsg.txt:
merge
sql/share/polish/errmsg.txt:
merge
sql/share/portuguese/errmsg.txt:
merge
sql/share/romanian/errmsg.txt:
merge
sql/share/russian/errmsg.txt:
merge
sql/share/slovak/errmsg.txt:
merge
sql/share/spanish/errmsg.txt:
merge
sql/share/swedish/errmsg.txt:
merge
sql/share/ukrainian/errmsg.txt:
merge
sql/sql_acl.cc:
merge with 4.0.3
sql/sql_base.cc:
More comments
Fixed bug in send_fields() when using convert
sql/sql_class.cc:
merge
sql/sql_class.h:
Merge with 4.0.3
Moved max_error_count and max_warning_count to variables struct.
sql/sql_delete.cc:
merge with 4.0.3 (Indentation change)
sql/sql_lex.h:
merge with 4.0.3
sql/sql_parse.cc:
Removed SHOW_WARNS_COUNT and SHOW_ERRORS_COUNT.
(Should be retrived from variables)
sql/sql_select.cc:
merge with 4.0.3
sql/sql_show.cc:
merge with 4.0.3
sql/sql_union.cc:
merge with 4.0.3
sql/sql_update.cc:
merge with 4.0.3
sql/sql_yacc.yy:
merge with 4.0.3
Indentation cleanup
sql/structs.h:
merge with 4.0.3
sql/table.cc:
merge with 4.0.3
sql/table.h:
merge with 4.0.3
Diffstat (limited to 'myisam')
46 files changed, 3956 insertions, 588 deletions
diff --git a/myisam/.cvsignore b/myisam/.cvsignore index d9adcedd308..ef6d92c6e18 100644 --- a/myisam/.cvsignore +++ b/myisam/.cvsignore @@ -7,6 +7,8 @@ ft_test1 mi_test1 mi_test2 mi_test3 +rt_test +sp_test myisamchk myisamlog myisampack diff --git a/myisam/Makefile.am b/myisam/Makefile.am index 6802bcb115f..ee13d0b1fad 100644 --- a/myisam/Makefile.am +++ b/myisam/Makefile.am @@ -25,14 +25,16 @@ bin_PROGRAMS = myisamchk myisamlog myisampack myisamchk_DEPENDENCIES= $(LIBRARIES) myisamlog_DEPENDENCIES= $(LIBRARIES) myisampack_DEPENDENCIES=$(LIBRARIES) -noinst_PROGRAMS = mi_test1 mi_test2 mi_test3 ft_dump #ft_test1 ft_eval -noinst_HEADERS = myisamdef.h fulltext.h ftdefs.h ft_test1.h ft_eval.h +noinst_PROGRAMS = mi_test1 mi_test2 mi_test3 rt_test sp_test ft_dump #ft_test1 ft_eval +noinst_HEADERS = myisamdef.h rt_index.h rt_key.h rt_mbr.h sp_defs.h fulltext.h ftdefs.h ft_test1.h ft_eval.h mi_test1_DEPENDENCIES= $(LIBRARIES) mi_test2_DEPENDENCIES= $(LIBRARIES) mi_test3_DEPENDENCIES= $(LIBRARIES) #ft_test1_DEPENDENCIES= $(LIBRARIES) #ft_eval_DEPENDENCIES= $(LIBRARIES) ft_dump_DEPENDENCIES= $(LIBRARIES) +rt_test_DEPENDENCIES= $(LIBRARIES) +sp_test_DEPENDENCIES= $(LIBRARIES) libmyisam_a_SOURCES = mi_open.c mi_extra.c mi_info.c mi_rkey.c \ mi_rnext.c mi_rnext_same.c \ mi_search.c mi_page.c mi_key.c mi_locking.c \ @@ -46,8 +48,9 @@ libmyisam_a_SOURCES = mi_open.c mi_extra.c mi_info.c mi_rkey.c \ mi_changed.c mi_static.c mi_delete_all.c \ mi_delete_table.c mi_rename.c mi_check.c \ ft_parser.c ft_stopwords.c ft_static.c \ - ft_update.c ft_boolean_search.c ft_nlq_search.c sort.c -CLEANFILES = test?.MY? FT?.MY? isam.log mi_test_all + ft_update.c ft_boolean_search.c ft_nlq_search.c sort.c \ + rt_index.c rt_key.c rt_mbr.c rt_split.c sp_key.c +CLEANFILES = test?.MY? FT?.MY? isam.log mi_test_all rt_test.MY? sp_test.MY? DEFS = -DMAP_TO_USE_RAID # Omit dependency for ../mit-pthreads/include/sys that only exits if # mit-pthreads are used diff --git a/myisam/ft_boolean_search.c b/myisam/ft_boolean_search.c index 13f596cb282..1a70113f0ad 100644 --- a/myisam/ft_boolean_search.c +++ b/myisam/ft_boolean_search.c @@ -118,7 +118,7 @@ static int FTB_WORD_cmp(my_off_t *v, FTB_WORD *a, FTB_WORD *b) static int FTB_WORD_cmp_list(CHARSET_INFO *cs, FTB_WORD **a, FTB_WORD **b) { /* ORDER BY word DESC, ndepth DESC */ - int i=_mi_compare_text(cs, (*b)->word+1,(*b)->len-1, + int i= mi_compare_text(cs, (*b)->word+1,(*b)->len-1, (*a)->word+1,(*a)->len-1,0); if (!i) i=CMP_NUM((*b)->ndepth,(*a)->ndepth); @@ -250,7 +250,7 @@ static void _ftb_init_index_search(FT_INFO *ftb) SEARCH_FIND | SEARCH_BIGGER, keyroot); if (!r) { - r=_mi_compare_text(ftb->charset, + r= mi_compare_text(ftb->charset, info->lastkey + (ftbw->flags&FTB_FLAG_TRUNC), ftbw->len - (ftbw->flags&FTB_FLAG_TRUNC), ftbw->word + (ftbw->flags&FTB_FLAG_TRUNC), @@ -458,7 +458,7 @@ int ft_boolean_read_next(FT_INFO *ftb, char *record) (curdoc=((FTB_WORD *)queue_top(& ftb->queue))->docid[0]) != HA_POS_ERROR) { - while (curdoc==(ftbw=(FTB_WORD *)queue_top(& ftb->queue))->docid[0]) + while (curdoc == (ftbw=(FTB_WORD *)queue_top(& ftb->queue))->docid[0]) { _ftb_climb_the_tree(ftb, ftbw, 0); @@ -467,7 +467,7 @@ int ft_boolean_read_next(FT_INFO *ftb, char *record) SEARCH_BIGGER , keyroot); if (!r) { - r=_mi_compare_text(ftb->charset, + r= mi_compare_text(ftb->charset, info->lastkey + (ftbw->flags&FTB_FLAG_TRUNC), ftbw->len - (ftbw->flags&FTB_FLAG_TRUNC), ftbw->word + (ftbw->flags&FTB_FLAG_TRUNC), @@ -499,12 +499,14 @@ int ft_boolean_read_next(FT_INFO *ftb, char *record) ftbe->yesses>=(ftbe->ythresh-ftbe->yweaks) && !ftbe->nos) { /* curdoc matched ! */ - if (is_tree_inited(& ftb->no_dupes) && - tree_insert(& ftb->no_dupes, &curdoc, 0)->count >1) + if (is_tree_inited(&ftb->no_dupes) && + tree_insert(&ftb->no_dupes, &curdoc, 0, + ftb->no_dupes.custom_arg)->count >1) /* but it managed to get past this line once */ continue; info->lastpos=curdoc; + /* Clear all states, except that the table was updated */ info->update&= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED); if (!(*info->read_record)(info,curdoc,record)) @@ -558,9 +560,9 @@ float ft_boolean_find_relevance(FT_INFO *ftb, byte *record, uint length) for (a=0, b=ftb->queue.elements, c=(a+b)/2; b-a>1; c=(a+b)/2) { ftbw=(FTB_WORD *)(ftb->list[c]); - if (_mi_compare_text(ftb->charset, word.pos, word.len, - (uchar*) ftbw->word+1, ftbw->len-1, - (my_bool) (ftbw->flags&FTB_FLAG_TRUNC)) >0) + if (mi_compare_text(ftb->charset, word.pos, word.len, + (uchar*) ftbw->word+1, ftbw->len-1, + (my_bool) (ftbw->flags&FTB_FLAG_TRUNC)) >0) b=c; else a=c; @@ -568,9 +570,9 @@ float ft_boolean_find_relevance(FT_INFO *ftb, byte *record, uint length) for (; c>=0; c--) { ftbw=(FTB_WORD *)(ftb->list[c]); - if (_mi_compare_text(ftb->charset, word.pos,word.len, - (uchar*) ftbw->word+1,ftbw->len-1, - (my_bool) (ftbw->flags&FTB_FLAG_TRUNC))) + if (mi_compare_text(ftb->charset, word.pos,word.len, + (uchar*) ftbw->word+1,ftbw->len-1, + (my_bool) (ftbw->flags&FTB_FLAG_TRUNC))) break; if (ftbw->docid[1] == docid) continue; diff --git a/myisam/ft_dump.c b/myisam/ft_dump.c index d95e719e234..d430b611836 100644 --- a/myisam/ft_dump.c +++ b/myisam/ft_dump.c @@ -131,7 +131,7 @@ int main(int argc,char *argv[]) #endif snprintf(buf,MAX_LEN,"%.*s",(int) keylen,info->lastkey+1); - casedn_str(buf); + my_casedn_str(default_charset_info,buf); total++; lengths[keylen]++; diff --git a/myisam/ft_eval.h b/myisam/ft_eval.h index 68be3a39f33..5501fe9d34b 100644 --- a/myisam/ft_eval.h +++ b/myisam/ft_eval.h @@ -33,7 +33,7 @@ FILE *df,*qf; MI_COLUMNDEF recinfo[3]; MI_KEYDEF keyinfo[2]; -MI_KEYSEG keyseg[10]; +HA_KEYSEG keyseg[10]; #define SWL_INIT 500 #define SWL_PLUS 50 diff --git a/myisam/ft_nlq_search.c b/myisam/ft_nlq_search.c index 5670edde7c0..f3fa8865bc6 100644 --- a/myisam/ft_nlq_search.c +++ b/myisam/ft_nlq_search.c @@ -98,9 +98,10 @@ static int walk_and_match(FT_WORD *word, uint32 count, ALL_IN_ONE *aio) while (!r) { - if (_mi_compare_text(aio->charset, - aio->info->lastkey,keylen, - aio->keybuff,keylen,0)) break; + if (mi_compare_text(aio->charset, + aio->info->lastkey,keylen, + aio->keybuff,keylen,0)) + break; #if HA_FT_WTYPE == HA_KEYTYPE_FLOAT #ifdef EVAL_RUN @@ -120,7 +121,7 @@ static int walk_and_match(FT_WORD *word, uint32 count, ALL_IN_ONE *aio) sdoc.doc.dpos=aio->info->lastpos; /* saving document matched into dtree */ - if (!(selem=tree_insert(&aio->dtree, &sdoc, 0))) + if (!(selem=tree_insert(&aio->dtree, &sdoc, 0, aio->dtree.custom_arg))) return 1; sptr=(FT_SUPERDOC *)ELEMENT_KEY((&aio->dtree), selem); diff --git a/myisam/ft_parser.c b/myisam/ft_parser.c index 283216762e1..583518089ba 100644 --- a/myisam/ft_parser.c +++ b/myisam/ft_parser.c @@ -37,8 +37,8 @@ typedef struct st_ft_docstat { static int FT_WORD_cmp(CHARSET_INFO* cs, FT_WORD *w1, FT_WORD *w2) { - return _mi_compare_text(cs, (uchar*) w1->pos, w1->len, - (uchar*) w2->pos, w2->len, 0); + return mi_compare_text(cs, (uchar*) w1->pos, w1->len, + (uchar*) w2->pos, w2->len, 0); } static int walk_and_copy(FT_WORD *word,uint32 count,FT_DOCSTAT *docstat) @@ -105,13 +105,13 @@ FT_WORD * ft_linearize(TREE *wtree) DBUG_RETURN(wlist); } -#define true_word_char(X) (isalnum(X) || (X)=='_') +#define true_word_char(s,X) (my_isalnum(s,X) || (X)=='_') #ifdef HYPHEN_IS_DELIM #define misc_word_char(X) ((X)=='\'') #else #define misc_word_char(X) ((X)=='\'' || (X)=='-') #endif -#define word_char(X) (true_word_char(X) || misc_word_char(X)) +#define word_char(s,X) (true_word_char(s,X) || misc_word_char(s,X)) /* returns: @@ -132,7 +132,11 @@ byte ft_get_word(byte **start, byte *end, FT_WORD *word, FTB_PARAM *param) { for (;doc<end;doc++) { - if (true_word_char(*doc)) break; + /* + BAR TODO: discuss with Serge how to remove + default_charset_info correctly + */ + if (true_word_char(default_charset_info,*doc)) break; if (*doc == FTB_RQUOT && param->quot) { param->quot=doc; *start=doc+1; @@ -162,7 +166,7 @@ byte ft_get_word(byte **start, byte *end, FT_WORD *word, FTB_PARAM *param) mwc=0; for (word->pos=doc; doc<end; doc++) - if (true_word_char(*doc)) + if (true_word_char(default_charset_info,*doc)) mwc=0; else if (!misc_word_char(*doc) || mwc++) break; @@ -191,12 +195,12 @@ byte ft_simple_get_word(byte **start, byte *end, FT_WORD *word) { for (;doc<end;doc++) { - if (true_word_char(*doc)) break; + if (true_word_char(default_charset_info,*doc)) break; } mwc=0; for(word->pos=doc; doc<end; doc++) - if (true_word_char(*doc)) + if (true_word_char(default_charset_info,*doc)) mwc=0; else if (!misc_word_char(*doc) || mwc++) break; @@ -226,7 +230,7 @@ int ft_parse(TREE *wtree, byte *doc, int doclen) while (ft_simple_get_word(&doc,end,&w)) { - if (!tree_insert(wtree, &w, 0)) + if (!tree_insert(wtree, &w, 0, wtree->custom_arg)) goto err; } return 0; diff --git a/myisam/ft_static.c b/myisam/ft_static.c index e2a4fd8c0b1..0b22d296206 100644 --- a/myisam/ft_static.c +++ b/myisam/ft_static.c @@ -23,7 +23,7 @@ ulong ft_max_word_len=HA_FT_MAXLEN; ulong ft_max_word_len_for_sort=20; const char *ft_boolean_syntax="+ -><()~*:\"\"&|"; -const MI_KEYSEG ft_keysegs[FT_SEGS]={ +const HA_KEYSEG ft_keysegs[FT_SEGS]={ { HA_KEYTYPE_VARTEXT, /* type */ 7, /* language (will be overwritten) */ diff --git a/myisam/ft_stopwords.c b/myisam/ft_stopwords.c index 9c2047c3b56..170442c71de 100644 --- a/myisam/ft_stopwords.c +++ b/myisam/ft_stopwords.c @@ -28,9 +28,9 @@ static TREE *stopwords3=NULL; static int FT_STOPWORD_cmp(void* cmp_arg __attribute__((unused)), FT_STOPWORD *w1, FT_STOPWORD *w2) { - return _mi_compare_text(default_charset_info, - (uchar *)w1->pos,w1->len, - (uchar *)w2->pos,w2->len,0); + return mi_compare_text(default_charset_info, + (uchar *)w1->pos,w1->len, + (uchar *)w2->pos,w2->len,0); } int ft_init_stopwords(const char **sws) @@ -50,7 +50,7 @@ int ft_init_stopwords(const char **sws) for(;*sws;sws++) { if( (sw.len= (uint) strlen(sw.pos=*sws)) < ft_min_word_len) continue; - if(!tree_insert(stopwords3, &sw, 0)) + if(!tree_insert(stopwords3, &sw, 0, stopwords3->custom_arg)) { delete_tree(stopwords3); /* purecov: inspected */ return -1; /* purecov: inspected */ @@ -64,7 +64,7 @@ int is_stopword(char *word, uint len) FT_STOPWORD sw; sw.pos=word; sw.len=len; - return tree_search(stopwords3,&sw) != NULL; + return tree_search(stopwords3, &sw, stopwords3->custom_arg) != NULL; } diff --git a/myisam/ft_test1.c b/myisam/ft_test1.c index cb0b6054f0a..f4884f8ca39 100644 --- a/myisam/ft_test1.c +++ b/myisam/ft_test1.c @@ -64,7 +64,7 @@ int main(int argc, char *argv[]) static MI_COLUMNDEF recinfo[3]; static MI_KEYDEF keyinfo[2]; -static MI_KEYSEG keyseg[10]; +static HA_KEYSEG keyseg[10]; static int run_test(const char *filename) { diff --git a/myisam/ft_update.c b/myisam/ft_update.c index a68cc2a4cf4..41876028104 100644 --- a/myisam/ft_update.c +++ b/myisam/ft_update.c @@ -163,8 +163,8 @@ int _mi_ft_cmp(MI_INFO *info, uint keynr, const byte *rec1, const byte *rec2) { if ((ftsi1.pos != ftsi2.pos) && (!ftsi1.pos || !ftsi2.pos || - _mi_compare_text(cs, (uchar*) ftsi1.pos,ftsi1.len, - (uchar*) ftsi2.pos,ftsi2.len,0))) + mi_compare_text(cs, (uchar*) ftsi1.pos,ftsi1.len, + (uchar*) ftsi2.pos,ftsi2.len,0))) return THOSE_TWO_DAMN_KEYS_ARE_REALLY_DIFFERENT; } return GEE_THEY_ARE_ABSOLUTELY_IDENTICAL; @@ -190,7 +190,7 @@ int _mi_ft_update(MI_INFO *info, uint keynr, byte *keybuf, error=0; while(old_word->pos && new_word->pos) { - cmp=_mi_compare_text(cs, (uchar*) old_word->pos,old_word->len, + cmp= mi_compare_text(cs, (uchar*) old_word->pos,old_word->len, (uchar*) new_word->pos,new_word->len,0); cmp2= cmp ? 0 : (fabs(old_word->weight - new_word->weight) > 1.e-5); diff --git a/myisam/ftdefs.h b/myisam/ftdefs.h index a1352a13150..22a81ca4f9c 100644 --- a/myisam/ftdefs.h +++ b/myisam/ftdefs.h @@ -125,7 +125,7 @@ byte ft_simple_get_word(byte **, byte *, FT_WORD *); typedef struct _st_ft_seg_iterator { uint num, len; - MI_KEYSEG *seg; + HA_KEYSEG *seg; const byte *rec, *pos; } FT_SEG_ITERATOR; diff --git a/myisam/fulltext.h b/myisam/fulltext.h index f787c9bcfe8..39801c1c87e 100644 --- a/myisam/fulltext.h +++ b/myisam/fulltext.h @@ -32,7 +32,7 @@ #define FT_SEGS 2 #endif /* EVAL_RUN */ -extern const MI_KEYSEG ft_keysegs[FT_SEGS]; +extern const HA_KEYSEG ft_keysegs[FT_SEGS]; int _mi_ft_cmp(MI_INFO *, uint, const byte *, const byte *); int _mi_ft_add(MI_INFO *, uint, byte *, const byte *, my_off_t); diff --git a/myisam/mi_check.c b/myisam/mi_check.c index 0ae700df8c2..49f6f31f96e 100644 --- a/myisam/mi_check.c +++ b/myisam/mi_check.c @@ -583,8 +583,8 @@ static int chk_index(MI_CHECK *param, MI_INFO *info, MI_KEYDEF *keyinfo, goto err; } if ((*keys)++ && - (flag=_mi_key_cmp(keyinfo->seg,info->lastkey,key,key_length, - comp_flag, ¬_used)) >=0) + (flag=ha_key_cmp(keyinfo->seg,info->lastkey,key,key_length, + comp_flag, ¬_used)) >=0) { DBUG_DUMP("old",(byte*) info->lastkey, info->lastkey_length); DBUG_DUMP("new",(byte*) key, key_length); @@ -601,8 +601,8 @@ static int chk_index(MI_CHECK *param, MI_INFO *info, MI_KEYDEF *keyinfo, if (*keys != 1L) /* not first_key */ { uint diff; - _mi_key_cmp(keyinfo->seg,info->lastkey,key,USE_WHOLE_KEY,SEARCH_FIND, - &diff); + ha_key_cmp(keyinfo->seg,info->lastkey,key,USE_WHOLE_KEY,SEARCH_FIND, + &diff); param->unique_count[diff-1]++; } } @@ -669,7 +669,7 @@ static ha_checksum calc_checksum(ha_rows count) static uint isam_key_length(MI_INFO *info, register MI_KEYDEF *keyinfo) { uint length; - MI_KEYSEG *keyseg; + HA_KEYSEG *keyseg; DBUG_ENTER("isam_key_length"); length= info->s->rec_reflength; @@ -3052,8 +3052,8 @@ static int sort_key_cmp(MI_SORT_PARAM *sort_param, const void *a, const void *b) { uint not_used; - return (_mi_key_cmp(sort_param->keyinfo->seg,*((uchar**) a),*((uchar**) b), - USE_WHOLE_KEY, SEARCH_SAME,¬_used)); + return (ha_key_cmp(sort_param->keyinfo->seg, *((uchar**) a), *((uchar**) b), + USE_WHOLE_KEY, SEARCH_SAME,¬_used)); } /* sort_key_cmp */ @@ -3067,9 +3067,9 @@ static int sort_key_write(MI_SORT_PARAM *sort_param, const void *a) if (sort_info->key_block->inited) { - cmp=_mi_key_cmp(sort_param->keyinfo->seg, sort_info->key_block->lastkey, - (uchar*) a, USE_WHOLE_KEY, SEARCH_FIND | SEARCH_UPDATE, - &diff_pos); + cmp=ha_key_cmp(sort_param->keyinfo->seg,sort_info->key_block->lastkey, + (uchar*) a, USE_WHOLE_KEY,SEARCH_FIND | SEARCH_UPDATE, + &diff_pos); sort_param->unique[diff_pos-1]++; } else @@ -3080,13 +3080,16 @@ static int sort_key_write(MI_SORT_PARAM *sort_param, const void *a) { sort_info->dupp++; sort_info->info->lastpos=get_record_for_key(sort_info->info, - sort_param->keyinfo, - (uchar*) a); + sort_parm->keyinfo, + (uchar*) a); mi_check_print_warning(param, - "Duplicate key for record at %10s against record at %10s", - llstr(sort_info->info->lastpos,llbuff), - llstr(get_record_for_key(sort_info->info, sort_param->keyinfo, - sort_info->key_block->lastkey), llbuff2)); + "Duplicate key for record at %10s against record at %10s", + llstr(sort_info->info->lastpos,llbuff), + llstr(get_record_for_key(sort_info->info, + sort_param->keyinfo, + sort_info->key_block-> + lastkey), + llbuff2)); param->testflag|=T_RETRY_WITHOUT_QUICK; if (sort_info->param->testflag & T_VERBOSE) _mi_print_key(stdout,sort_param->keyinfo->seg,(uchar*) a, USE_WHOLE_KEY); @@ -3342,7 +3345,7 @@ int recreate_table(MI_CHECK *param, MI_INFO **org_info, char *filename) MI_INFO info; MYISAM_SHARE share; MI_KEYDEF *keyinfo,*key,*key_end; - MI_KEYSEG *keysegs,*keyseg; + HA_KEYSEG *keysegs,*keyseg; MI_COLUMNDEF *recdef,*rec,*end; MI_UNIQUEDEF *uniquedef,*u_ptr,*u_end; MI_STATUS_INFO status_info; @@ -3364,7 +3367,7 @@ int recreate_table(MI_CHECK *param, MI_INFO **org_info, char *filename) (size_t) (sizeof(MI_KEYDEF)*share.base.keys)); key_parts= share.base.all_key_parts; - if (!(keysegs=(MI_KEYSEG*) my_alloca(sizeof(MI_KEYSEG)* + if (!(keysegs=(HA_KEYSEG*) my_alloca(sizeof(HA_KEYSEG)* (key_parts+share.base.keys)))) { my_afree((gptr) keyinfo); @@ -3400,7 +3403,7 @@ int recreate_table(MI_CHECK *param, MI_INFO **org_info, char *filename) /* Change the new key to point at the saved key segments */ memcpy((byte*) keysegs,(byte*) share.keyparts, - (size_t) (sizeof(MI_KEYSEG)*(key_parts+share.base.keys+ + (size_t) (sizeof(HA_KEYSEG)*(key_parts+share.base.keys+ share.state.header.uniques))); keyseg=keysegs; for (key=keyinfo,key_end=keyinfo+share.base.keys; key != key_end ; key++) diff --git a/myisam/mi_create.c b/myisam/mi_create.c index 2202587702b..ea26ed373d3 100644 --- a/myisam/mi_create.c +++ b/myisam/mi_create.c @@ -17,6 +17,8 @@ /* Create a MyISAM table */ #include "fulltext.h" +#include "sp_defs.h" + #if defined(MSDOS) || defined(__WIN__) #ifdef __WIN__ #include <fcntl.h> @@ -51,7 +53,7 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs, MYISAM_SHARE share; MI_KEYDEF *keydef,tmp_keydef; MI_UNIQUEDEF *uniquedef; - MI_KEYSEG *keyseg,tmp_keyseg; + HA_KEYSEG *keyseg,tmp_keyseg; MI_COLUMNDEF *rec; ulong *rec_per_key_part; my_off_t key_root[MI_MAX_POSSIBLE_KEY],key_del[MI_MAX_KEY_BLOCK_SIZE]; @@ -233,11 +235,42 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs, for (i=0, keydef=keydefs ; i < keys ; i++ , keydef++) { - share.state.key_root[i]= HA_OFFSET_ERROR; + share.state.key_root[i]= HA_OFFSET_ERROR; min_key_length_skipp=length=0; key_length=pointer; + if (keydef->flag & HA_SPATIAL) + { + /* BAR TODO to support 3D and more dimensions in the future */ + uint sp_segs=SPDIMS*2; + keydef->flag=HA_SPATIAL; + if (flags & HA_DONT_TOUCH_DATA) + { + /* + called by myisamchk - i.e. table structure was taken from + MYI file and SPATIAL key *do has* additional sp_segs keysegs. + We'd better delete them now + */ + keydef->keysegs-=sp_segs; + } + + for (j=0, keyseg=keydef->seg ; (int) j < keydef->keysegs ; + j++, keyseg++) + { + if (keyseg->type != HA_KEYTYPE_BINARY && + keyseg->type != HA_KEYTYPE_VARBINARY) + { + my_errno=HA_WRONG_CREATE_OPTION; + goto err; + } + } + keydef->keysegs+=sp_segs; + key_length+=SPLEN*sp_segs; + length++; /* At least one length byte */ + min_key_length_skipp+=SPLEN*2*SPDIMS; + } + else if (keydef->flag & HA_FULLTEXT) /* SerG */ { keydef->flag=HA_FULLTEXT | HA_PACK_KEY | HA_VAR_LENGTH_KEY; @@ -410,7 +443,7 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs, info_length=base_pos+(uint) (MI_BASE_INFO_SIZE+ keys * MI_KEYDEF_SIZE+ uniques * MI_UNIQUEDEF_SIZE + - (key_segs + unique_key_parts)*MI_KEYSEG_SIZE+ + (key_segs + unique_key_parts)*HA_KEYSEG_SIZE+ columns*MI_COLUMNDEF_SIZE); bmove(share.state.header.file_version,(byte*) myisam_file_magic,4); @@ -557,19 +590,35 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs, for (i=0 ; i < share.base.keys - uniques; i++) { uint ft_segs=(keydefs[i].flag & HA_FULLTEXT) ? FT_SEGS : 0; + uint sp_segs=(keydefs[i].flag & HA_SPATIAL) ? 2*SPDIMS : 0; if (mi_keydef_write(file, &keydefs[i])) goto err; - for (j=0 ; j < keydefs[i].keysegs-ft_segs ; j++) + for (j=0 ; j < keydefs[i].keysegs-ft_segs-sp_segs ; j++) if (mi_keyseg_write(file, &keydefs[i].seg[j])) - goto err; + goto err; for (j=0 ; j < ft_segs ; j++) { - MI_KEYSEG seg=ft_keysegs[j]; + HA_KEYSEG seg=ft_keysegs[j]; seg.language= keydefs[i].seg[0].language; if (mi_keyseg_write(file, &seg)) goto err; } + for (j=0 ; j < sp_segs ; j++) + { + HA_KEYSEG sseg; + sseg.type=SPTYPE; + sseg.language= 7; + sseg.null_bit=0; + sseg.bit_start=0; + sseg.bit_end=0; + sseg.length=SPLEN; + sseg.null_pos=0; + sseg.start=j*SPLEN; + sseg.flag= HA_SWAP_KEY; + if (mi_keyseg_write(file, &sseg)) + goto err; + } } /* Create extra keys for unique definitions */ offset=reclength-uniques*MI_UNIQUE_HASH_LENGTH; diff --git a/myisam/mi_dbug.c b/myisam/mi_dbug.c index 482287938c0..6548b38c135 100644 --- a/myisam/mi_dbug.c +++ b/myisam/mi_dbug.c @@ -20,7 +20,7 @@ /* Print a key in user understandable format */ -void _mi_print_key(FILE *stream, register MI_KEYSEG *keyseg, +void _mi_print_key(FILE *stream, register HA_KEYSEG *keyseg, const uchar *key, uint length) { int flag; diff --git a/myisam/mi_delete.c b/myisam/mi_delete.c index 6f94e3c4256..ff723303228 100644 --- a/myisam/mi_delete.c +++ b/myisam/mi_delete.c @@ -17,6 +17,8 @@ /* Remove a row from a MyISAM table */ #include "fulltext.h" +#include "rt_index.h" + #ifdef __WIN__ #include <errno.h> #endif @@ -79,9 +81,9 @@ int mi_delete(MI_INFO *info,const byte *record) } else { - uint key_length=_mi_make_key(info,i,old_key,record,info->lastpos); - if (_mi_ck_delete(info,i,old_key,key_length)) - goto err; + if (info->s->keyinfo[i].ck_delete(info,i,old_key, + _mi_make_key(info,i,old_key,record,info->lastpos))) + goto err; } } } diff --git a/myisam/mi_key.c b/myisam/mi_key.c index 9ec1ca99e0e..00a64bca269 100644 --- a/myisam/mi_key.c +++ b/myisam/mi_key.c @@ -18,6 +18,7 @@ #include "myisamdef.h" #include "m_ctype.h" +#include "sp_defs.h" #ifdef HAVE_IEEEFP_H #include <ieeefp.h> #endif @@ -36,9 +37,17 @@ uint _mi_make_key(register MI_INFO *info, uint keynr, uchar *key, { byte *pos,*end; uchar *start; - reg1 MI_KEYSEG *keyseg; + reg1 HA_KEYSEG *keyseg; DBUG_ENTER("_mi_make_key"); + if(info->s->keyinfo[keynr].flag & HA_SPATIAL) + { + /* + TODO: nulls processing + */ + return sp_make_key(info,keynr,key,record,filepos); + } + start=key; for (keyseg=info->s->keyinfo[keynr].seg ; keyseg->type ;keyseg++) { @@ -144,7 +153,7 @@ uint _mi_pack_key(register MI_INFO *info, uint keynr, uchar *key, uchar *old, { uint length; uchar *pos,*end,*start_key=key; - reg1 MI_KEYSEG *keyseg; + reg1 HA_KEYSEG *keyseg; enum ha_base_keytype type; DBUG_ENTER("_mi_pack_key"); @@ -243,7 +252,7 @@ static int _mi_put_key_in_record(register MI_INFO *info, uint keynr, { reg2 byte *key; byte *pos,*key_end; - reg1 MI_KEYSEG *keyseg; + reg1 HA_KEYSEG *keyseg; byte *blob_ptr; DBUG_ENTER("_mi_put_key_in_record"); @@ -377,7 +386,7 @@ int _mi_read_key_record(MI_INFO *info, my_off_t filepos, byte *buf) void update_auto_increment(MI_INFO *info,const byte *record) { ulonglong value; - MI_KEYSEG *keyseg=info->s->keyinfo[info->s->base.auto_key-1].seg; + HA_KEYSEG *keyseg=info->s->keyinfo[info->s->base.auto_key-1].seg; const uchar *key=(uchar*) record+keyseg->start; switch (keyseg->type) { diff --git a/myisam/mi_open.c b/myisam/mi_open.c index f621e4b760c..b05a8175a6e 100644 --- a/myisam/mi_open.c +++ b/myisam/mi_open.c @@ -17,6 +17,8 @@ /* open a isam-database */ #include "fulltext.h" +#include "sp_defs.h" +#include "rt_index.h" #include <m_ctype.h> #if defined(MSDOS) || defined(__WIN__) @@ -65,7 +67,7 @@ static MI_INFO *test_if_reopen(char *filename) MI_INFO *mi_open(const char *name, int mode, uint open_flags) { - int lock_error,kfile,open_mode,save_errno; + int lock_error,kfile,open_mode,save_errno,have_rtree=0; uint i,j,len,errpos,head_length,base_pos,offset,info_length,keys, key_parts,unique_key_parts,tmp_length,uniques; char name_buff[FN_REFLEN], org_name [FN_REFLEN], index_name[FN_REFLEN], @@ -254,7 +256,7 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags) &share->uniqueinfo,uniques*sizeof(MI_UNIQUEDEF), &share->keyparts, (key_parts+unique_key_parts+keys+uniques) * - sizeof(MI_KEYSEG), + sizeof(HA_KEYSEG), &share->rec, (share->base.fields+1)*sizeof(MI_COLUMNDEF), &share->blobs,sizeof(MI_BLOB)*share->base.blobs, @@ -284,7 +286,7 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags) share->blocksize=min(IO_SIZE,myisam_block_size); { - MI_KEYSEG *pos=share->keyparts; + HA_KEYSEG *pos=share->keyparts; for (i=0 ; i < keys ; i++) { disk_pos=mi_keydef_read(disk_pos, &share->keyinfo[i]); @@ -293,6 +295,7 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags) for (j=0 ; j < share->keyinfo[i].keysegs; j++,pos++) { disk_pos=mi_keyseg_read(disk_pos, pos); + if (pos->type == HA_KEYTYPE_TEXT || pos->type == HA_KEYTYPE_VARTEXT) { if (!pos->language) @@ -304,7 +307,12 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags) } } } - if (share->keyinfo[i].flag & HA_FULLTEXT) + if (share->keyinfo[i].flag & HA_SPATIAL) + { + uint sp_segs=SPDIMS*2; + share->keyinfo[i].seg=pos-sp_segs; + share->keyinfo[i].keysegs--; + } else if (share->keyinfo[i].flag & HA_FULLTEXT) { share->keyinfo[i].seg=pos-FT_SEGS; share->fulltext_index=1; @@ -342,7 +350,11 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags) } } for (i=0 ; i < keys ; i++) + { + if (share->keyinfo[i].key_alg == HA_KEY_ALG_RTREE) + have_rtree=1; setup_key_functions(share->keyinfo+i); + } for (i=j=offset=0 ; i < share->base.fields ; i++) { @@ -421,7 +433,8 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags) ((share->options & (HA_OPTION_READ_ONLY_DATA | HA_OPTION_TMP_TABLE | HA_OPTION_COMPRESS_RECORD | HA_OPTION_TEMP_COMPRESS_RECORD)) || - (open_flags & HA_OPEN_TMP_TABLE)) ? 0 : 1; + (open_flags & HA_OPEN_TMP_TABLE) || + have_rtree) ? 0 : 1; if (share->concurrent_insert) { share->lock.get_status=mi_get_status; @@ -451,6 +464,7 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags) &info.blobs,sizeof(MI_BLOB)*share->base.blobs, &info.buff,(share->base.max_key_block_length*2+ share->base.max_key_length), + &info.rtree_recursion_state,have_rtree ? 1024 : 0, &info.lastkey,share->base.max_key_length*3+1, &info.filename,strlen(org_name)+1, NullS)) @@ -649,6 +663,16 @@ void mi_setup_functions(register MYISAM_SHARE *share) static void setup_key_functions(register MI_KEYDEF *keyinfo) { + if (keyinfo->key_alg == HA_KEY_ALG_RTREE) + { + keyinfo->ck_insert = rtree_insert; + keyinfo->ck_delete = rtree_delete; + } + else + { + keyinfo->ck_insert = _mi_ck_write; + keyinfo->ck_delete = _mi_ck_delete; + } if (keyinfo->flag & HA_BINARY_PACK_KEY) { /* Simple prefix compression */ keyinfo->bin_search=_mi_seq_search; @@ -914,7 +938,7 @@ uint mi_keydef_write(File file, MI_KEYDEF *keydef) uchar *ptr=buff; *ptr++ = (uchar) keydef->keysegs; - *ptr++ = 0; /* not used */ + *ptr++ = keydef->key_alg; /* Rtree or Btree */ mi_int2store(ptr,keydef->flag); ptr +=2; mi_int2store(ptr,keydef->block_length); ptr +=2; mi_int2store(ptr,keydef->keylength); ptr +=2; @@ -926,7 +950,8 @@ uint mi_keydef_write(File file, MI_KEYDEF *keydef) char *mi_keydef_read(char *ptr, MI_KEYDEF *keydef) { keydef->keysegs = (uint) *ptr++; - ptr++; + keydef->key_alg = *ptr++; /* Rtree or Btree */ + keydef->flag = mi_uint2korr(ptr); ptr +=2; keydef->block_length = mi_uint2korr(ptr); ptr +=2; keydef->keylength = mi_uint2korr(ptr); ptr +=2; @@ -942,9 +967,9 @@ char *mi_keydef_read(char *ptr, MI_KEYDEF *keydef) ** mi_keyseg ***************************************************************************/ -int mi_keyseg_write(File file, const MI_KEYSEG *keyseg) +int mi_keyseg_write(File file, const HA_KEYSEG *keyseg) { - uchar buff[MI_KEYSEG_SIZE]; + uchar buff[HA_KEYSEG_SIZE]; uchar *ptr=buff; *ptr++ =keyseg->type; @@ -962,7 +987,7 @@ int mi_keyseg_write(File file, const MI_KEYSEG *keyseg) } -char *mi_keyseg_read(char *ptr, MI_KEYSEG *keyseg) +char *mi_keyseg_read(char *ptr, HA_KEYSEG *keyseg) { keyseg->type = *ptr++; keyseg->language = *ptr++; diff --git a/myisam/mi_range.c b/myisam/mi_range.c index 70694bf4620..4b98b48199a 100644 --- a/myisam/mi_range.c +++ b/myisam/mi_range.c @@ -20,6 +20,7 @@ */ #include "myisamdef.h" +#include "rt_index.h" static ha_rows _mi_record_pos(MI_INFO *info,const byte *key,uint key_len, enum ha_rkey_function search_flag); @@ -39,7 +40,7 @@ ha_rows mi_records_in_range(MI_INFO *info, int inx, const byte *start_key, const byte *end_key, uint end_key_len, enum ha_rkey_function end_search_flag) { - ha_rows start_pos,end_pos; + ha_rows start_pos,end_pos,res; DBUG_ENTER("mi_records_in_range"); if ((inx = _mi_check_index(info,inx)) < 0) @@ -50,20 +51,39 @@ ha_rows mi_records_in_range(MI_INFO *info, int inx, const byte *start_key, info->update&= (HA_STATE_CHANGED+HA_STATE_ROW_CHANGED); if (info->s->concurrent_insert) rw_rdlock(&info->s->key_root_lock[inx]); - start_pos= (start_key ? + + switch(info->s->keyinfo[inx].key_alg){ + case HA_KEY_ALG_RTREE: + { + uchar * key_buff; + if (start_key_len == 0) + start_key_len=USE_WHOLE_KEY; + key_buff=info->lastkey+info->s->base.max_key_length; + start_key_len=_mi_pack_key(info,inx,key_buff,(uchar*) start_key,start_key_len); + res=rtree_estimate(info, inx, key_buff, start_key_len, myisam_read_vec[start_search_flag]); + res=res?res:1; + break; + } + case HA_KEY_ALG_BTREE: + default: + start_pos= (start_key ? _mi_record_pos(info,start_key,start_key_len,start_search_flag) : (ha_rows) 0); - end_pos= (end_key ? + end_pos= (end_key ? _mi_record_pos(info,end_key,end_key_len,end_search_flag) : info->state->records+ (ha_rows) 1); + res=end_pos < start_pos ? (ha_rows) 0 : + (end_pos == start_pos ? (ha_rows) 1 : end_pos-start_pos); + if (start_pos == HA_POS_ERROR || end_pos == HA_POS_ERROR) + res=HA_POS_ERROR; + } + if (info->s->concurrent_insert) rw_unlock(&info->s->key_root_lock[inx]); fast_mi_writeinfo(info); - if (start_pos == HA_POS_ERROR || end_pos == HA_POS_ERROR) - DBUG_RETURN(HA_POS_ERROR); - DBUG_PRINT("info",("records: %ld",(ulong) (end_pos-start_pos))); - DBUG_RETURN(end_pos < start_pos ? (ha_rows) 0 : - (end_pos == start_pos ? (ha_rows) 1 : end_pos-start_pos)); + + DBUG_PRINT("info",("records: %ld",(ulong) (res))); + DBUG_RETURN(res); } diff --git a/myisam/mi_rkey.c b/myisam/mi_rkey.c index 86547d3ef04..cefb7a74dd1 100644 --- a/myisam/mi_rkey.c +++ b/myisam/mi_rkey.c @@ -17,7 +17,7 @@ /* Read record based on a key */ #include "myisamdef.h" - +#include "rt_index.h" /* Read a record using key */ /* Ordinary search_flag is 0 ; Give error if no record with key */ @@ -36,6 +36,7 @@ int mi_rkey(MI_INFO *info, byte *buf, int inx, const byte *key, uint key_len, DBUG_RETURN(my_errno); info->update&= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED); + info->last_key_func=search_flag; if (!info->use_packed_key) { @@ -65,22 +66,33 @@ int mi_rkey(MI_INFO *info, byte *buf, int inx, const byte *key, uint key_len, if (!(nextflag & (SEARCH_FIND | SEARCH_NO_FIND | SEARCH_LAST))) use_key_length=USE_WHOLE_KEY; - if (!_mi_search(info,info->s->keyinfo+inx,key_buff,use_key_length, + switch(info->s->keyinfo[inx].key_alg){ + case HA_KEY_ALG_RTREE: + if(rtree_find_first(info,inx,key_buff,use_key_length,nextflag)<0) + { + my_errno=HA_ERR_CRASHED; + goto err; + } + break; + case HA_KEY_ALG_BTREE: + default: + if (!_mi_search(info,info->s->keyinfo+inx,key_buff,use_key_length, myisam_read_vec[search_flag],info->s->state.key_root[inx])) - { - while (info->lastpos >= info->state->data_file_length) { - /* - Skip rows that are inserted by other threads since we got a lock - Note that this can only happen if we are not searching after an - exact key, because the keys are sorted according to position - */ - - if (_mi_search_next(info,info->s->keyinfo+inx,info->lastkey, + while (info->lastpos >= info->state->data_file_length) + { + /* + Skip rows that are inserted by other threads since we got a lock + Note that this can only happen if we are not searching after an + exact key, because the keys are sorted according to position + */ + + if (_mi_search_next(info,info->s->keyinfo+inx,info->lastkey, info->lastkey_length, myisam_readnext_vec[search_flag], info->s->state.key_root[inx])) - break; + break; + } } } if (share->concurrent_insert) diff --git a/myisam/mi_rnext.c b/myisam/mi_rnext.c index 6d135462f96..daab7c5f085 100644 --- a/myisam/mi_rnext.c +++ b/myisam/mi_rnext.c @@ -16,6 +16,8 @@ #include "myisamdef.h" +#include "rt_index.h" + /* Read next row with the same key as previous read One may have done a write, update or delete of the previous row. @@ -42,27 +44,55 @@ int mi_rnext(MI_INFO *info, byte *buf, int inx) changed=_mi_test_if_changed(info); if (!flag) { - error=_mi_search_first(info,info->s->keyinfo+inx, - info->s->state.key_root[inx]); + switch(info->s->keyinfo[inx].key_alg){ + case HA_KEY_ALG_RTREE: + error=rtree_get_first(info,inx,info->lastkey_length); + break; + case HA_KEY_ALG_BTREE: + default: + error=_mi_search_first(info,info->s->keyinfo+inx, + info->s->state.key_root[inx]); + break; + } } - else if (!changed) - error=_mi_search_next(info,info->s->keyinfo+inx,info->lastkey, - info->lastkey_length,flag, - info->s->state.key_root[inx]); else - error=_mi_search(info,info->s->keyinfo+inx,info->lastkey, - USE_WHOLE_KEY,flag, info->s->state.key_root[inx]); - - if (!error) { - while (info->lastpos >= info->state->data_file_length) + switch(info->s->keyinfo[inx].key_alg) { - /* Skip rows that are inserted by other threads since we got a lock */ - if ((error=_mi_search_next(info,info->s->keyinfo+inx,info->lastkey, + case HA_KEY_ALG_RTREE: + /* + Note that rtree doesn't support that the table + may be changed since last call, so we do need + to skip rows inserted by other threads like in btree + */ + error=rtree_get_next(info,inx,info->lastkey_length); + break; + + case HA_KEY_ALG_BTREE: + default: + if (!changed) + { + error=_mi_search_next(info,info->s->keyinfo+inx,info->lastkey, + info->lastkey_length,flag, + info->s->state.key_root[inx]); + } + else + { + error=_mi_search(info,info->s->keyinfo+inx,info->lastkey, + USE_WHOLE_KEY,flag, info->s->state.key_root[inx]); + } + if (!error) + { + while (info->lastpos >= info->state->data_file_length) + { + /* Skip rows that are inserted by other threads since we got a lock */ + if ((error=_mi_search_next(info,info->s->keyinfo+inx,info->lastkey, info->lastkey_length, SEARCH_BIGGER, info->s->state.key_root[inx]))) - break; + break; + } + } } } diff --git a/myisam/mi_rnext_same.c b/myisam/mi_rnext_same.c index 662bdb154b3..88146c89f85 100644 --- a/myisam/mi_rnext_same.c +++ b/myisam/mi_rnext_same.c @@ -15,6 +15,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "myisamdef.h" +#include "rt_index.h" /* Read next row with the same key as previous read, but abort if @@ -38,26 +39,39 @@ int mi_rnext_same(MI_INFO *info, byte *buf) if (fast_mi_readinfo(info)) DBUG_RETURN(my_errno); - memcpy(info->lastkey2,info->lastkey,info->last_rkey_length); if (info->s->concurrent_insert) rw_rdlock(&info->s->key_root_lock[inx]); - for (;;) + + switch(keyinfo->key_alg) { - if ((error=_mi_search_next(info,keyinfo,info->lastkey, + case HA_KEY_ALG_RTREE: + if((error=rtree_find_next(info,inx,myisam_read_vec[info->last_key_func]))) + { + /* FIXME: What to do?*/ + } + break; + case HA_KEY_ALG_BTREE: + default: + + memcpy(info->lastkey2,info->lastkey,info->last_rkey_length); + for (;;) + { + if ((error=_mi_search_next(info,keyinfo,info->lastkey, info->lastkey_length,flag, info->s->state.key_root[inx]))) - break; - if (_mi_key_cmp(keyinfo->seg,info->lastkey2,info->lastkey, + break; + if (ha_key_cmp(keyinfo->seg,info->lastkey2,info->lastkey, info->last_rkey_length, SEARCH_FIND, ¬_used)) - { - error=1; - my_errno=HA_ERR_END_OF_FILE; - info->lastpos= HA_OFFSET_ERROR; - break; - } - /* Skip rows that are inserted by other threads since we got a lock */ - if (info->lastpos < info->state->data_file_length) - break; + { + error=1; + my_errno=HA_ERR_END_OF_FILE; + info->lastpos= HA_OFFSET_ERROR; + break; + } + /* Skip rows that are inserted by other threads since we got a lock */ + if (info->lastpos < info->state->data_file_length) + break; + } } if (info->s->concurrent_insert) rw_unlock(&info->s->key_root_lock[inx]); diff --git a/myisam/mi_search.c b/myisam/mi_search.c index d57fd1bb5b2..46d1cd19142 100644 --- a/myisam/mi_search.c +++ b/myisam/mi_search.c @@ -133,7 +133,7 @@ int _mi_search(register MI_INFO *info, register MI_KEYDEF *keyinfo, &info->lastkey_length)) goto err; if ((nextflag & SEARCH_LAST) && - _mi_key_cmp(keyinfo->seg, info->lastkey, key, key_len, SEARCH_FIND, + ha_key_cmp(keyinfo->seg, info->lastkey, key, key_len, SEARCH_FIND, ¬_used)) { my_errno=HA_ERR_KEY_NOT_FOUND; /* Didn't find key */ @@ -191,7 +191,7 @@ int _mi_bin_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page, while (start != end) { mid= (start+end)/2; - if ((flag=_mi_key_cmp(keyinfo->seg,page+(uint) mid*totlength,key,key_len, + if ((flag=ha_key_cmp(keyinfo->seg,page+(uint) mid*totlength,key,key_len, comp_flag,¬_used)) >= 0) end=mid; @@ -199,7 +199,7 @@ int _mi_bin_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page, start=mid+1; } if (mid != start) - flag=_mi_key_cmp(keyinfo->seg,page+(uint) start*totlength,key,key_len, + flag=ha_key_cmp(keyinfo->seg,page+(uint) start*totlength,key,key_len, comp_flag,¬_used); if (flag < 0) start++; /* point at next, bigger key */ @@ -239,7 +239,7 @@ int _mi_seq_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page, length,page,end)); DBUG_RETURN(MI_FOUND_WRONG_KEY); } - if ((flag=_mi_key_cmp(keyinfo->seg,t_buff,key,key_len,comp_flag, + if ((flag=ha_key_cmp(keyinfo->seg,t_buff,key,key_len,comp_flag, ¬_used)) >= 0) break; #ifdef EXTRA_DEBUG @@ -262,7 +262,7 @@ int _mi_prefix_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page, { /* my_flag is raw comparison result to be changed according to SEARCH_NO_FIND,SEARCH_LAST and HA_REVERSE_SORT flags. - flag is the value returned by _mi_key_cmp and as treated as final */ + flag is the value returned by ha_key_cmp and as treated as final */ int flag=0, my_flag=-1; uint nod_flag, length, len, matched, cmplen, kseg_len; uint prefix_len,suffix_len; @@ -351,7 +351,7 @@ int _mi_prefix_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page, DBUG_PRINT("loop",("page: '%.*s%.*s'",prefix_len,t_buff+seg_len_pack,suffix_len,vseg)); { uchar *from=vseg+suffix_len; - MI_KEYSEG *keyseg; + HA_KEYSEG *keyseg; uint l; for (keyseg=keyinfo->seg+1 ; keyseg->type ; keyseg++ ) @@ -423,7 +423,7 @@ int _mi_prefix_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page, else if (key_len_left>0) { uint not_used; - if ((flag = _mi_key_cmp(keyinfo->seg+1,vseg, + if ((flag = ha_key_cmp(keyinfo->seg+1,vseg, k,key_len_left,nextflag,¬_used)) >= 0) break; } @@ -651,389 +651,6 @@ void _mi_dpointer(MI_INFO *info, uchar *buff, my_off_t pos) } /* _mi_dpointer */ -int _mi_compare_text(CHARSET_INFO *charset_info, uchar *a, uint a_length, - uchar *b, uint b_length, my_bool part_key) -{ - int flag; - -#ifdef USE_STRCOLL - if (use_strcoll(charset_info)) - { - if (part_key && b_length < a_length) - a_length=b_length; - return my_strnncoll(charset_info, a, a_length, b, b_length); - } - else -#endif - { - uint length= min(a_length,b_length); - uchar *end= a+ length; - uchar *sort_order=charset_info->sort_order; - while (a < end) - if ((flag= (int) sort_order[*a++] - (int) sort_order[*b++])) - return flag; - } - if (part_key && b_length < a_length) - return 0; - return (int) (a_length-b_length); -} - - -static int compare_bin(uchar *a, uint a_length, uchar *b, uint b_length, - my_bool part_key) -{ - uint length= min(a_length,b_length); - uchar *end= a+ length; - int flag; - - while (a < end) - if ((flag= (int) *a++ - (int) *b++)) - return flag; - if (part_key && b_length < a_length) - return 0; - return (int) (a_length-b_length); -} - - - /* - ** Compare two keys - ** Returns <0, 0, >0 acording to which is bigger - ** Key_length specifies length of key to use. Number-keys can't - ** be splited - ** If flag <> SEARCH_FIND compare also position - */ - -#define FCMP(A,B) ((int) (A) - (int) (B)) - -int _mi_key_cmp(register MI_KEYSEG *keyseg, register uchar *a, - register uchar *b, uint key_length, uint nextflag, - uint *diff_pos) -{ - int flag; - int16 s_1,s_2; - int32 l_1,l_2; - uint32 u_1,u_2; - float f_1,f_2; - double d_1,d_2; - uint next_key_length; - - *diff_pos=0; - for ( ; (int) key_length >0 ; key_length=next_key_length, keyseg++) - { - uchar *end; - uint piks=! (keyseg->flag & HA_NO_SORT); - (*diff_pos)++; - - /* Handle NULL part */ - if (keyseg->null_bit) - { - key_length--; - if (*a != *b && piks) - { - flag = (int) *a - (int) *b; - return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); - } - b++; - if (!*a++) /* If key was NULL */ - { - if (nextflag == (SEARCH_FIND | SEARCH_UPDATE)) - nextflag=SEARCH_SAME; /* Allow duplicate keys */ - next_key_length=key_length; - continue; /* To next key part */ - } - } - end= a+ min(keyseg->length,key_length); - next_key_length=key_length-keyseg->length; - - switch ((enum ha_base_keytype) keyseg->type) { - case HA_KEYTYPE_TEXT: /* Ascii; Key is converted */ - if (keyseg->flag & HA_SPACE_PACK) - { - int a_length,b_length,pack_length; - get_key_length(a_length,a); - get_key_pack_length(b_length,pack_length,b); - next_key_length=key_length-b_length-pack_length; - - if (piks && - (flag=_mi_compare_text(keyseg->charset,a,a_length,b,b_length, - (my_bool) ((nextflag & SEARCH_PREFIX) && next_key_length <= 0)))) - return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); - a+=a_length; - b+=b_length; - break; - } - else - { - uint length=(uint) (end-a), a_length=length, b_length=length; - if (!(nextflag & SEARCH_PREFIX)) - { - while (a_length && a[a_length-1] == ' ') - a_length--; - while (b_length && b[b_length-1] == ' ') - b_length--; - } - if (piks && - (flag=_mi_compare_text(keyseg->charset,a,a_length,b,b_length, - (my_bool) ((nextflag & SEARCH_PREFIX) && next_key_length <= 0)))) - return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); - a=end; - b+=length; - } - break; - case HA_KEYTYPE_BINARY: - if (keyseg->flag & HA_SPACE_PACK) - { - int a_length,b_length,pack_length; - get_key_length(a_length,a); - get_key_pack_length(b_length,pack_length,b); - next_key_length=key_length-b_length-pack_length; - - if (piks && - (flag=compare_bin(a,a_length,b,b_length, - (my_bool) ((nextflag & SEARCH_PREFIX) && next_key_length <= 0)))) - return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); - a+=a_length; - b+=b_length; - break; - } - else - { - uint length=keyseg->length; - if (piks && - (flag=compare_bin(a,length,b,length, - (my_bool) ((nextflag & SEARCH_PREFIX) && next_key_length <= 0)))) - return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); - a+=length; - b+=length; - } - break; - case HA_KEYTYPE_VARTEXT: - { - int a_length,b_length,pack_length; - get_key_length(a_length,a); - get_key_pack_length(b_length,pack_length,b); - next_key_length=key_length-b_length-pack_length; - - if (piks && - (flag=_mi_compare_text(keyseg->charset,a,a_length,b,b_length, - (my_bool) ((nextflag & SEARCH_PREFIX) && next_key_length <= 0)))) - return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); - a+=a_length; - b+=b_length; - break; - } - break; - case HA_KEYTYPE_VARBINARY: - { - int a_length,b_length,pack_length; - get_key_length(a_length,a); - get_key_pack_length(b_length,pack_length,b); - next_key_length=key_length-b_length-pack_length; - - if (piks && - (flag=compare_bin(a,a_length,b,b_length, - (my_bool) ((nextflag & SEARCH_PREFIX) && next_key_length <= 0)))) - return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); - a+=a_length; - b+=b_length; - break; - } - break; - case HA_KEYTYPE_INT8: - { - int i_1= (int) *((signed char*) a); - int i_2= (int) *((signed char*) b); - if (piks && (flag = CMP_NUM(i_1,i_2))) - return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); - a= end; - b++; - break; - } - case HA_KEYTYPE_SHORT_INT: - s_1= mi_sint2korr(a); - s_2= mi_sint2korr(b); - if (piks && (flag = CMP_NUM(s_1,s_2))) - return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); - a= end; - b+= 2; /* sizeof(short int); */ - break; - case HA_KEYTYPE_USHORT_INT: - { - uint16 us_1,us_2; - us_1= mi_sint2korr(a); - us_2= mi_sint2korr(b); - if (piks && (flag = CMP_NUM(us_1,us_2))) - return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); - a= end; - b+=2; /* sizeof(short int); */ - break; - } - case HA_KEYTYPE_LONG_INT: - l_1= mi_sint4korr(a); - l_2= mi_sint4korr(b); - if (piks && (flag = CMP_NUM(l_1,l_2))) - return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); - a= end; - b+= 4; /* sizeof(long int); */ - break; - case HA_KEYTYPE_ULONG_INT: - u_1= mi_sint4korr(a); - u_2= mi_sint4korr(b); - if (piks && (flag = CMP_NUM(u_1,u_2))) - return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); - a= end; - b+= 4; /* sizeof(long int); */ - break; - case HA_KEYTYPE_INT24: - l_1=mi_sint3korr(a); - l_2=mi_sint3korr(b); - if (piks && (flag = CMP_NUM(l_1,l_2))) - return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); - a= end; - b+= 3; - break; - case HA_KEYTYPE_UINT24: - l_1=mi_uint3korr(a); - l_2=mi_uint3korr(b); - if (piks && (flag = CMP_NUM(l_1,l_2))) - return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); - a= end; - b+= 3; - break; - case HA_KEYTYPE_FLOAT: - mi_float4get(f_1,a); - mi_float4get(f_2,b); - if (piks && (flag = CMP_NUM(f_1,f_2))) - return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); - a= end; - b+= 4; /* sizeof(float); */ - break; - case HA_KEYTYPE_DOUBLE: - mi_float8get(d_1,a); - mi_float8get(d_2,b); - if (piks && (flag = CMP_NUM(d_1,d_2))) - return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); - a= end; - b+= 8; /* sizeof(double); */ - break; - case HA_KEYTYPE_NUM: /* Numeric key */ - { - int swap_flag= 0; - int alength,blength; - - if (keyseg->flag & HA_REVERSE_SORT) - { - swap(uchar*,a,b); - swap_flag=1; /* Remember swap of a & b */ - end= a+ (int) (end-b); - } - if (keyseg->flag & HA_SPACE_PACK) - { - alength= *a++; blength= *b++; - end=a+alength; - next_key_length=key_length-blength-1; - } - else - { - alength= (int) (end-a); - blength=keyseg->length; - /* remove pre space from keys */ - for ( ; alength && *a == ' ' ; a++, alength--) ; - for ( ; blength && *b == ' ' ; b++, blength--) ; - } - if (piks) - { - if (*a == '-') - { - if (*b != '-') - return -1; - a++; b++; - swap(uchar*,a,b); - swap(int,alength,blength); - swap_flag=1-swap_flag; - alength--; blength--; - end=a+alength; - } - else if (*b == '-') - return 1; - while (alength && (*a == '+' || *a == '0')) - { - a++; alength--; - } - while (blength && (*b == '+' || *b == '0')) - { - b++; blength--; - } - if (alength != blength) - return (alength < blength) ? -1 : 1; - while (a < end) - if (*a++ != *b++) - return ((int) a[-1] - (int) b[-1]); - } - else - { - b+=(end-a); - a=end; - } - - if (swap_flag) /* Restore pointers */ - swap(uchar*,a,b); - break; - } -#ifdef HAVE_LONG_LONG - case HA_KEYTYPE_LONGLONG: - { - longlong ll_a,ll_b; - ll_a= mi_sint8korr(a); - ll_b= mi_sint8korr(b); - if (piks && (flag = CMP_NUM(ll_a,ll_b))) - return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); - a= end; - b+= 8; - break; - } - case HA_KEYTYPE_ULONGLONG: - { - ulonglong ll_a,ll_b; - ll_a= mi_uint8korr(a); - ll_b= mi_uint8korr(b); - if (piks && (flag = CMP_NUM(ll_a,ll_b))) - return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); - a= end; - b+= 8; - break; - } -#endif - case HA_KEYTYPE_END: /* Ready */ - goto end; /* diff_pos is incremented */ - } - } - (*diff_pos)++; -end: - if (!(nextflag & SEARCH_FIND)) - { - uint i; - if (nextflag & (SEARCH_NO_FIND | SEARCH_LAST)) /* Find record after key */ - return (nextflag & (SEARCH_BIGGER | SEARCH_LAST)) ? -1 : 1; - flag=0; - for (i=keyseg->length ; i-- > 0 ; ) - { - if (*a++ != *b++) - { - flag= FCMP(a[-1],b[-1]); - break; - } - } - if (nextflag & SEARCH_SAME) - return (flag); /* read same */ - if (nextflag & SEARCH_BIGGER) - return (flag <= 0 ? -1 : 1); /* read next */ - return (flag < 0 ? -1 : 1); /* read previous */ - } - return 0; -} /* _mi_key_cmp */ - - /* Get key from key-block */ /* page points at previous key; its advanced to point at next key */ /* key should contain previous key */ @@ -1057,7 +674,7 @@ uint _mi_get_static_key(register MI_KEYDEF *keyinfo, uint nod_flag, uint _mi_get_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag, register uchar **page_pos, register uchar *key) { - reg1 MI_KEYSEG *keyseg; + reg1 HA_KEYSEG *keyseg; uchar *start_key,*page=*page_pos; uint length; @@ -1190,7 +807,7 @@ uint _mi_get_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag, uint _mi_get_binary_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag, register uchar **page_pos, register uchar *key) { - reg1 MI_KEYSEG *keyseg; + reg1 HA_KEYSEG *keyseg; uchar *start_key,*page=*page_pos,*page_end,*from,*from_end; uint length,tmp; @@ -1389,7 +1006,7 @@ uchar *_mi_get_last_key(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *page, uint _mi_keylength(MI_KEYDEF *keyinfo, register uchar *key) { - reg1 MI_KEYSEG *keyseg; + reg1 HA_KEYSEG *keyseg; uchar *start; if (! (keyinfo->flag & (HA_VAR_LENGTH_KEY | HA_BINARY_PACK_KEY))) @@ -1655,7 +1272,7 @@ _mi_calc_var_pack_key_length(MI_KEYDEF *keyinfo,uint nod_flag,uchar *next_key, uchar *org_key, uchar *prev_key, uchar *key, MI_KEY_PARAM *s_temp) { - reg1 MI_KEYSEG *keyseg; + reg1 HA_KEYSEG *keyseg; int length; uint key_length,ref_length,org_key_length=0, length_pack,new_key_length,diff_flag,pack_marker; diff --git a/myisam/mi_static.c b/myisam/mi_static.c index 37b9ac04b7a..57683a36920 100644 --- a/myisam/mi_static.c +++ b/myisam/mi_static.c @@ -51,7 +51,8 @@ uint NEAR myisam_read_vec[]= { SEARCH_FIND, SEARCH_FIND | SEARCH_BIGGER, SEARCH_FIND | SEARCH_SMALLER, SEARCH_NO_FIND | SEARCH_BIGGER, SEARCH_NO_FIND | SEARCH_SMALLER, - SEARCH_FIND | SEARCH_PREFIX, SEARCH_LAST + SEARCH_FIND | SEARCH_PREFIX, SEARCH_LAST, + MBR_CONTAIN, MBR_INTERSECT, MBR_WITHIN, MBR_DISJOINT, MBR_EQUAL }; uint NEAR myisam_readnext_vec[]= diff --git a/myisam/mi_test1.c b/myisam/mi_test1.c index bcb9cd172ec..1c2b3f13baa 100644 --- a/myisam/mi_test1.c +++ b/myisam/mi_test1.c @@ -36,8 +36,8 @@ static my_bool key_cacheing, null_fields, silent, skip_update, opt_unique, verbose; static MI_COLUMNDEF recinfo[4]; static MI_KEYDEF keyinfo[10]; -static MI_KEYSEG keyseg[10]; -static MI_KEYSEG uniqueseg[10]; +static HA_KEYSEG keyseg[10]; +static HA_KEYSEG uniqueseg[10]; static int run_test(const char *filename); static void get_options(int argc, char *argv[]); @@ -92,6 +92,7 @@ int run_test(const char *filename) /* Define a key over the first column */ keyinfo[0].seg=keyseg; keyinfo[0].keysegs=1; + keyinfo[0].key_alg=HA_KEY_ALG_BTREE; keyinfo[0].seg[0].type= key_type; keyinfo[0].seg[0].flag= pack_seg; keyinfo[0].seg[0].start=1; @@ -460,19 +461,19 @@ static void update_record(char *record) ptr=blob_key; memcpy_fixed(pos+4,&ptr,sizeof(char*)); /* Store pointer to new key */ if (keyinfo[0].seg[0].type != HA_KEYTYPE_NUM) - casedn(blob_key,length); + my_casedn(default_charset_info,blob_key,length); pos+=recinfo[1].length; } else if (recinfo[1].type == FIELD_VARCHAR) { uint length=uint2korr(pos); - casedn(pos+2,length); + my_casedn(default_charset_info,pos+2,length); pos+=recinfo[1].length; } else { if (keyinfo[0].seg[0].type != HA_KEYTYPE_NUM) - casedn(pos,keyinfo[0].seg[0].length); + my_casedn(default_charset_info,pos,keyinfo[0].seg[0].length); pos+=recinfo[1].length; } diff --git a/myisam/mi_test2.c b/myisam/mi_test2.c index 93538e3ead7..b5da87355c6 100644 --- a/myisam/mi_test2.c +++ b/myisam/mi_test2.c @@ -55,7 +55,7 @@ static uint use_blob=0; static uint16 key1[1001],key3[5000]; static char record[300],record2[300],key[100],key2[100], read_record[300],read_record2[300],read_record3[300]; -static MI_KEYSEG glob_keyseg[MYISAM_KEYS][MAX_PARTS]; +static HA_KEYSEG glob_keyseg[MYISAM_KEYS][MAX_PARTS]; /* Test program */ @@ -91,6 +91,7 @@ int main(int argc, char *argv[]) keyinfo[0].seg[0].flag=(uint8) pack_seg; keyinfo[0].seg[0].null_bit=0; keyinfo[0].seg[0].null_pos=0; + keyinfo[0].key_alg=HA_KEY_ALG_BTREE; keyinfo[0].keysegs=1; keyinfo[0].flag = pack_type; keyinfo[1].seg= &glob_keyseg[1][0]; @@ -106,6 +107,7 @@ int main(int argc, char *argv[]) keyinfo[1].seg[1].flag=HA_REVERSE_SORT; keyinfo[1].seg[1].null_bit=0; keyinfo[1].seg[1].null_pos=0; + keyinfo[1].key_alg=HA_KEY_ALG_BTREE; keyinfo[1].keysegs=2; keyinfo[1].flag =0; keyinfo[2].seg= &glob_keyseg[2][0]; @@ -115,6 +117,7 @@ int main(int argc, char *argv[]) keyinfo[2].seg[0].flag=HA_REVERSE_SORT; keyinfo[2].seg[0].null_bit=0; keyinfo[2].seg[0].null_pos=0; + keyinfo[2].key_alg=HA_KEY_ALG_BTREE; keyinfo[2].keysegs=1; keyinfo[2].flag =HA_NOSAME; keyinfo[3].seg= &glob_keyseg[3][0]; @@ -125,6 +128,7 @@ int main(int argc, char *argv[]) keyinfo[3].seg[0].flag=(uint8) pack_seg; keyinfo[3].seg[0].null_bit=0; keyinfo[3].seg[0].null_pos=0; + keyinfo[3].key_alg=HA_KEY_ALG_BTREE; keyinfo[3].keysegs=1; keyinfo[3].flag = pack_type; keyinfo[4].seg= &glob_keyseg[4][0]; @@ -135,6 +139,7 @@ int main(int argc, char *argv[]) keyinfo[4].seg[0].flag=0; keyinfo[4].seg[0].null_bit=0; keyinfo[4].seg[0].null_pos=0; + keyinfo[4].key_alg=HA_KEY_ALG_BTREE; keyinfo[4].keysegs=1; keyinfo[4].flag = pack_type; keyinfo[5].seg= &glob_keyseg[5][0]; @@ -145,6 +150,7 @@ int main(int argc, char *argv[]) keyinfo[5].seg[0].flag=pack_seg; keyinfo[5].seg[0].null_bit=0; keyinfo[5].seg[0].null_pos=0; + keyinfo[5].key_alg=HA_KEY_ALG_BTREE; keyinfo[5].keysegs=1; keyinfo[5].flag = pack_type; @@ -1013,7 +1019,7 @@ static void put_blob_in_record(char *blob_pos, char **blob_buffer) static void copy_key(MI_INFO *info,uint inx,uchar *rec,uchar *key_buff) { - MI_KEYSEG *keyseg; + HA_KEYSEG *keyseg; for (keyseg=info->s->keyinfo[inx].seg ; keyseg->type ; keyseg++) { diff --git a/myisam/mi_test3.c b/myisam/mi_test3.c index ac36f55a181..c2cee12978e 100644 --- a/myisam/mi_test3.c +++ b/myisam/mi_test3.c @@ -59,7 +59,7 @@ int main(int argc,char **argv) uint i=0; MI_KEYDEF keyinfo[10]; MI_COLUMNDEF recinfo[10]; - MI_KEYSEG keyseg[10][2]; + HA_KEYSEG keyseg[10][2]; MY_INIT(argv[0]); get_options(argc,argv); @@ -70,6 +70,7 @@ int main(int argc,char **argv) keyinfo[0].seg[0].length=8; keyinfo[0].seg[0].type=HA_KEYTYPE_TEXT; keyinfo[0].seg[0].flag=HA_SPACE_PACK; + keyinfo[0].key_alg=HA_KEY_ALG_BTREE; keyinfo[0].keysegs=1; keyinfo[0].flag = (uint8) HA_PACK_KEY; keyinfo[1].seg= &keyseg[1][0]; @@ -77,6 +78,7 @@ int main(int argc,char **argv) keyinfo[1].seg[0].length=4; /* Long is always 4 in myisam */ keyinfo[1].seg[0].type=HA_KEYTYPE_LONG_INT; keyinfo[1].seg[0].flag=0; + keyinfo[1].key_alg=HA_KEY_ALG_BTREE; keyinfo[1].keysegs=1; keyinfo[1].flag =HA_NOSAME; diff --git a/myisam/mi_unique.c b/myisam/mi_unique.c index b373693e6e0..2101c656324 100644 --- a/myisam/mi_unique.c +++ b/myisam/mi_unique.c @@ -70,7 +70,7 @@ ha_checksum mi_unique_hash(MI_UNIQUEDEF *def, const byte *record) { const byte *pos, *end; ha_checksum crc=0; - MI_KEYSEG *keyseg; + HA_KEYSEG *keyseg; for (keyseg=def->seg ; keyseg < def->end ; keyseg++) { @@ -99,11 +99,20 @@ ha_checksum mi_unique_hash(MI_UNIQUEDEF *def, const byte *record) end= pos+length; if (type == HA_KEYTYPE_TEXT || type == HA_KEYTYPE_VARTEXT) { - uchar *sort_order=keyseg->charset->sort_order; - while (pos != end) - crc=((crc << 8) + - (((uchar) sort_order[*(uchar*) pos++]))) + - (crc >> (8*sizeof(ha_checksum)-8)); + if (keyseg->charset->hash_sort) + { + ulong nr=1, nr2=4; + keyseg->charset->hash_sort(keyseg->charset,(const uchar*)pos,length,&nr, &nr2); + crc=nr; + } + else + { + uchar *sort_order=keyseg->charset->sort_order; + while (pos != end) + crc=((crc << 8) + + (((uchar) sort_order[*(uchar*) pos++]))) + + (crc >> (8*sizeof(ha_checksum)-8)); + } } else while (pos != end) @@ -122,7 +131,7 @@ int mi_unique_comp(MI_UNIQUEDEF *def, const byte *a, const byte *b, my_bool null_are_equal) { const byte *pos_a, *pos_b, *end; - MI_KEYSEG *keyseg; + HA_KEYSEG *keyseg; for (keyseg=def->seg ; keyseg < def->end ; keyseg++) { @@ -172,8 +181,8 @@ int mi_unique_comp(MI_UNIQUEDEF *def, const byte *a, const byte *b, } if (type == HA_KEYTYPE_TEXT || type == HA_KEYTYPE_VARTEXT) { - if (_mi_compare_text(keyseg->charset, (uchar *)pos_a, length, - (uchar *)pos_b, length, 0)) + if (mi_compare_text(keyseg->charset, (uchar *) pos_a, length, + (uchar *) pos_b, length, 0)) return 1; } else diff --git a/myisam/mi_update.c b/myisam/mi_update.c index 1614d6ca19d..81142ecabac 100644 --- a/myisam/mi_update.c +++ b/myisam/mi_update.c @@ -17,6 +17,8 @@ /* Update an old row in a MyISAM table */ #include "fulltext.h" +#include "rt_index.h" + #ifdef __WIN__ #include <errno.h> #endif @@ -61,6 +63,7 @@ int mi_update(register MI_INFO *info, const byte *oldrec, byte *newrec) goto err_end; /* Record has changed */ } + /* Calculate and check all unique constraints */ key_changed=0; for (i=0 ; i < share->state.header.uniques ; i++) @@ -111,8 +114,8 @@ int mi_update(register MI_INFO *info, const byte *oldrec, byte *newrec) key_changed|=HA_STATE_WRITTEN; /* Mark that keyfile changed */ changed|=((ulonglong) 1 << i); share->keyinfo[i].version++; - if (_mi_ck_delete(info,i,old_key,old_length)) goto err; - if (_mi_ck_write(info,i,new_key,new_length)) goto err; + if (share->keyinfo[i].ck_delete(info,i,old_key,old_length)) goto err; + if (share->keyinfo[i].ck_insert(info,i,new_key,new_length)) goto err; if (share->base.auto_key == i+1) auto_key_changed=1; } diff --git a/myisam/mi_write.c b/myisam/mi_write.c index cfacd0bc4d5..5d22ebfe5b5 100644 --- a/myisam/mi_write.c +++ b/myisam/mi_write.c @@ -17,6 +17,8 @@ /* Write a row to a MyISAM table */ #include "fulltext.h" +#include "rt_index.h" + #ifdef __WIN__ #include <errno.h> #endif @@ -121,17 +123,17 @@ int mi_write(MI_INFO *info, byte *record) } else { - uint key_length=_mi_make_key(info,i,buff,record,filepos); - if (_mi_ck_write(info,i,buff,key_length)) - { - if (local_lock_tree) - rw_unlock(&share->key_root_lock[i]); - DBUG_PRINT("error",("Got error: %d on write",my_errno)); - goto err; - } + if (share->keyinfo[i].ck_insert(info,i,buff, + _mi_make_key(info,i,buff,record,filepos))) + { + if (local_lock_tree) + rw_unlock(&share->key_root_lock[i]); + DBUG_PRINT("error",("Got error: %d on write",my_errno)); + goto err; + } } if (local_lock_tree) - rw_unlock(&share->key_root_lock[i]); + rw_unlock(&share->key_root_lock[i]); } } if (share->calc_checksum) @@ -751,7 +753,8 @@ int _mi_ck_write_tree(register MI_INFO *info, uint keynr, uchar *key, DBUG_ENTER("_mi_ck_write_tree"); error= tree_insert(&info->bulk_insert[keynr], key, - key_length + info->s->rec_reflength) ? 0 : HA_ERR_OUT_OF_MEM ; + key_length + info->s->rec_reflength, + info->bulk_insert[keynr].custom_arg) ? 0 : HA_ERR_OUT_OF_MEM ; DBUG_RETURN(error); } /* _mi_ck_write_tree */ @@ -762,7 +765,7 @@ int _mi_ck_write_tree(register MI_INFO *info, uint keynr, uchar *key, static int keys_compare(bulk_insert_param *param, uchar *key1, uchar *key2) { uint not_used; - return _mi_key_cmp(param->info->s->keyinfo[param->keynr].seg, + return ha_key_cmp(param->info->s->keyinfo[param->keynr].seg, key1, key2, USE_WHOLE_KEY, SEARCH_SAME, ¬_used); } diff --git a/myisam/myisamchk.c b/myisam/myisamchk.c index 33500da87dc..8cefd0d5ac1 100644 --- a/myisam/myisamchk.c +++ b/myisam/myisamchk.c @@ -1107,7 +1107,7 @@ static void descript(MI_CHECK *param, register MI_INFO *info, my_string name) { uint key,keyseg_nr,field,start; reg3 MI_KEYDEF *keyinfo; - reg2 MI_KEYSEG *keyseg; + reg2 HA_KEYSEG *keyseg; reg4 const char *text; char buff[160],length[10],*pos,*end; enum en_fieldtype type; diff --git a/myisam/myisamdef.h b/myisam/myisamdef.h index f0d6f740661..7f8b6dc41fd 100644 --- a/myisam/myisamdef.h +++ b/myisam/myisamdef.h @@ -96,7 +96,7 @@ typedef struct st_mi_state_info #define MI_STATE_EXTRA_SIZE ((MI_MAX_KEY+MI_MAX_KEY_BLOCK_SIZE)*MI_STATE_KEY_SIZE + MI_MAX_KEY*MI_MAX_KEY_SEG*MI_STATE_KEYSEG_SIZE) #define MI_KEYDEF_SIZE (2+ 5*2) #define MI_UNIQUEDEF_SIZE (2+1+1) -#define MI_KEYSEG_SIZE (6+ 2*2 + 4*2) +#define HA_KEYSEG_SIZE (6+ 2*2 + 4*2) #define MI_COLUMNDEF_SIZE (2*3+1) #define MI_BASE_INFO_SIZE (5*8 + 8*4 + 4 + 4*2 + 16) #define MI_INDEX_BLOCK_MARGIN 16 /* Safety margin for .MYI tables */ @@ -156,7 +156,7 @@ typedef struct st_mi_isam_share { /* Shared between opens */ MI_BASE_INFO base; MI_KEYDEF *keyinfo; /* Key definitions */ MI_UNIQUEDEF *uniqueinfo; /* unique definitions */ - MI_KEYSEG *keyparts; /* key part info */ + HA_KEYSEG *keyparts; /* key part info */ MI_COLUMNDEF *rec; /* Pointer to field information */ MI_PACK pack; /* Data about packed records */ MI_BLOB *blobs; /* Pointer to blobs */ @@ -251,6 +251,7 @@ struct st_myisam_info { int lastinx; /* Last used index */ uint lastkey_length; /* Length of key in lastkey */ uint last_rkey_length; /* Last length in mi_rkey() */ + enum ha_rkey_function last_key_func; /* CONTAIN, OVERLAP, etc */ uint save_lastkey_length; int errkey; /* Got last error on this key */ int lock_type; /* How database was locked */ @@ -270,6 +271,8 @@ struct st_myisam_info { #ifdef THREAD THR_LOCK_DATA lock; #endif + uchar * rtree_recursion_state; /* For RTREE */ + int rtree_recursion_depth; }; @@ -324,13 +327,6 @@ struct st_myisam_info { { *(key)=255; mi_int2store((key)+1,(length)); } \ } -#define get_key_length(length,key) \ -{ if ((uchar) *(key) != 255) \ - length= (uint) (uchar) *((key)++); \ - else \ - { length=mi_uint2korr((key)+1); (key)+=3; } \ -} - #define get_key_full_length(length,key) \ { if ((uchar) *(key) != 255) \ length= ((uint) (uchar) *((key)++))+1; \ @@ -338,13 +334,6 @@ struct st_myisam_info { { length=mi_uint2korr((key)+1)+3; (key)+=3; } \ } -#define get_key_pack_length(length,length_pack,key) \ -{ if ((uchar) *(key) != 255) \ - { length= (uint) (uchar) *((key)++); length_pack=1; }\ - else \ - { length=mi_uint2korr((key)+1); (key)+=3; length_pack=3; } \ -} - #define get_pack_length(length) ((length) >= 255 ? 3 : 1) #define MI_MIN_BLOCK_LENGTH 20 /* Because of delete-link */ @@ -365,7 +354,7 @@ struct st_myisam_info { #define PACK_TYPE_SELECTED 1 /* Bits in field->pack_type */ #define PACK_TYPE_SPACE_FIELDS 2 #define PACK_TYPE_ZERO_FILL 4 -#define MI_FOUND_WRONG_KEY 32738 /* Impossible value from _mi_key_cmp */ +#define MI_FOUND_WRONG_KEY 32738 /* Impossible value from ha_key_cmp */ #define MI_MAX_KEY_BLOCK_SIZE (MI_MAX_KEY_BLOCK_LENGTH/MI_MIN_KEY_BLOCK_LENGTH) #define MI_BLOCK_SIZE(key_length,data_pointer,key_pointer) ((((key_length+data_pointer+key_pointer)*4+key_pointer+2)/myisam_block_size+1)*myisam_block_size) @@ -482,14 +471,12 @@ extern int _mi_seq_search(MI_INFO *info,MI_KEYDEF *keyinfo,uchar *page, extern int _mi_prefix_search(MI_INFO *info,MI_KEYDEF *keyinfo,uchar *page, uchar *key,uint key_len,uint comp_flag, uchar **ret_pos,uchar *buff, my_bool *was_last_key); -extern int _mi_compare_text(CHARSET_INFO *, uchar *, uint, uchar *, uint , - my_bool); extern my_off_t _mi_kpos(uint nod_flag,uchar *after_key); extern void _mi_kpointer(MI_INFO *info,uchar *buff,my_off_t pos); extern my_off_t _mi_dpos(MI_INFO *info, uint nod_flag,uchar *after_key); extern my_off_t _mi_rec_pos(MYISAM_SHARE *info, uchar *ptr); extern void _mi_dpointer(MI_INFO *info, uchar *buff,my_off_t pos); -extern int _mi_key_cmp(MI_KEYSEG *keyseg, uchar *a,uchar *b, +extern int ha_key_cmp(HA_KEYSEG *keyseg, uchar *a,uchar *b, uint key_length,uint nextflag,uint *diff_length); extern uint _mi_get_static_key(MI_KEYDEF *keyinfo,uint nod_flag,uchar * *page, uchar *key); @@ -536,7 +523,7 @@ extern my_bool _mi_rec_check(MI_INFO *info,const char *record, byte *packpos); extern int _mi_write_part_record(MI_INFO *info,my_off_t filepos,ulong length, my_off_t next_filepos,byte **record, ulong *reclength,int *flag); -extern void _mi_print_key(FILE *stream,MI_KEYSEG *keyseg,const uchar *key, +extern void _mi_print_key(FILE *stream,HA_KEYSEG *keyseg,const uchar *key, uint length); extern my_bool _mi_read_pack_info(MI_INFO *info,pbool fix_keys); extern int _mi_read_pack_record(MI_INFO *info,my_off_t filepos,byte *buf); @@ -627,8 +614,8 @@ char *mi_state_info_read(char *ptr, MI_STATE_INFO *state); uint mi_state_info_read_dsk(File file, MI_STATE_INFO *state, my_bool pRead); uint mi_base_info_write(File file, MI_BASE_INFO *base); char *my_n_base_info_read(char *ptr, MI_BASE_INFO *base); -int mi_keyseg_write(File file, const MI_KEYSEG *keyseg); -char *mi_keyseg_read(char *ptr, MI_KEYSEG *keyseg); +int mi_keyseg_write(File file, const HA_KEYSEG *keyseg); +char *mi_keyseg_read(char *ptr, HA_KEYSEG *keyseg); uint mi_keydef_write(File file, MI_KEYDEF *keydef); char *mi_keydef_read(char *ptr, MI_KEYDEF *keydef); uint mi_uniquedef_write(File file, MI_UNIQUEDEF *keydef); diff --git a/myisam/myisamlog.c b/myisam/myisamlog.c index ceca8d2a0e3..d7fb3f24b85 100644 --- a/myisam/myisamlog.c +++ b/myisam/myisamlog.c @@ -345,7 +345,8 @@ static int examine_log(my_string file_name, char **table_names) if (!opt_processes) file_info.process=0; result= mi_uint2korr(head+7); - if ((curr_file_info=(struct file_info*) tree_search(&tree,&file_info))) + if ((curr_file_info=(struct file_info*) tree_search(&tree, &file_info, + tree.custom_arg))) { curr_file_info->accessed=access_time; if (update && curr_file_info->used && curr_file_info->closed) @@ -452,7 +453,7 @@ static int examine_log(my_string file_name, char **table_names) else file_info.isam->s->rnd= isamlog_process; } - VOID(tree_insert(&tree,(gptr) &file_info,0)); + VOID(tree_insert(&tree, (gptr) &file_info, 0, tree.custom_arg)); if (file_info.used) { if (verbose && !record_pos_file) @@ -471,7 +472,7 @@ static int examine_log(my_string file_name, char **table_names) { if (!curr_file_info->closed) files_open--; - VOID(tree_delete(&tree,(gptr) curr_file_info)); + VOID(tree_delete(&tree, (gptr) curr_file_info, tree.custom_arg)); } break; case MI_LOG_EXTRA: diff --git a/myisam/myisampack.c b/myisam/myisampack.c index cf0448a9062..a299e4eb00d 100644 --- a/myisam/myisampack.c +++ b/myisam/myisampack.c @@ -763,7 +763,8 @@ static int get_statistic(PACK_MRG_INFO *mrg,HUFF_COUNTS *huff_counts) if (count->tree_buff) { global_count=count; - if (!(element=tree_insert(&count->int_tree,pos,0)) || + if (!(element=tree_insert(&count->int_tree,pos, 0, + count->int_tree.custom_arg)) || (element->count == 1 && count->tree_buff + tree_buff_length < count->tree_pos + count->field_length) || @@ -1786,7 +1787,8 @@ static int compress_isam_file(PACK_MRG_INFO *mrg, HUFF_COUNTS *huff_counts) break; case FIELD_INTERVALL: global_count=count; - pos=(byte*) tree_search(&count->int_tree,start_pos); + pos=(byte*) tree_search(&count->int_tree, start_pos, + count->int_tree.custom_arg); intervall=(uint) (pos - count->tree_buff)/field_length; write_bits(tree->code[intervall],(uint) tree->code_len[intervall]); start_pos=end_pos; diff --git a/myisam/rt_index.c b/myisam/rt_index.c new file mode 100644 index 00000000000..d55d01fa4a3 --- /dev/null +++ b/myisam/rt_index.c @@ -0,0 +1,914 @@ +/* Copyright (C) 2000 MySQL AB & Ramil Kalimullin & 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 */ + +#include "myisamdef.h" + +#include "rt_index.h" +#include "rt_key.h" +#include "rt_mbr.h" + +#define REINSERT_BUFFER_INC 10 + +typedef struct st_page_level +{ + uint level; + my_off_t offs; +} stPageLevel; + +typedef struct st_page_list +{ + ulong n_pages; + ulong m_pages; + stPageLevel *pages; +} stPageList; + +/* +Find next key in r-tree according to search_flag recursively +Used in rtree_find_first() and rtree_find_next() +Result values: +-1 - error + 0 - found + 1 - not found +*/ +static int rtree_find_req(MI_INFO *info, MI_KEYDEF *keyinfo, uint search_flag, uint nod_cmp_flag, + my_off_t page, int level) +{ + uchar *k; + uchar *last; + uint nod_flag; + int res; + uchar *page_buf; + int k_len; + int *saved_key = (int*)(info->rtree_recursion_state + level * sizeof(int)); + + if (!(page_buf = (uchar*)my_alloca((uint)keyinfo->block_length))) + { + my_errno = HA_ERR_OUT_OF_MEM; + return -1; + } + if (!_mi_fetch_keypage(info, keyinfo, page, page_buf, 0)) + goto err1; + nod_flag = mi_test_if_nod(page_buf); + + k_len = keyinfo->keylength - info->s->base.rec_reflength; + + if(info->rtree_recursion_depth >= level) + { + k = page_buf + *saved_key; + if (!nod_flag) + { + /* Only leaf pages contain data references. */ + /* Need to check next key with data reference. */ + k = rt_PAGE_NEXT_KEY(k, k_len, nod_flag); + } + } + else + { + k = rt_PAGE_FIRST_KEY(page_buf, nod_flag); + } + last = rt_PAGE_END(page_buf); + + for (; k < last; k = rt_PAGE_NEXT_KEY(k, k_len, nod_flag)) + { + if (nod_flag) + { + /* this is an internal node in the tree */ + if (!(res = rtree_key_cmp(keyinfo->seg, info->lastkey2, k, + info->last_rkey_length, nod_cmp_flag))) + { + switch ((res = rtree_find_req(info, keyinfo, search_flag, nod_cmp_flag, + _mi_kpos(nod_flag, k), level + 1))) + { + case 0: /* found - exit from recursion */ + *saved_key = k - page_buf; + goto ok; + case 1: /* not found - continue searching */ + info->rtree_recursion_depth = level; + break; + default: /* error */ + case -1: + goto err1; + } + } + } + else + { + /* this is a leaf */ + if (!rtree_key_cmp(keyinfo->seg, info->lastkey2, k, + info->last_rkey_length, search_flag)) + { + uchar *after_key = rt_PAGE_NEXT_KEY(k, k_len, nod_flag); + info->lastpos = _mi_dpos(info, 0, after_key); + info->lastkey_length = k_len + info->s->base.rec_reflength; + memcpy(info->lastkey, k, k_len + info->s->base.rec_reflength); + + info->rtree_recursion_depth = level; + *saved_key = k - page_buf; + + if (after_key < last) + { + info->int_keypos = (uchar*)saved_key; + memcpy(info->buff, page_buf, keyinfo->block_length); + info->int_maxpos = rt_PAGE_END(info->buff); + info->buff_used = 0; + } + + res = 0; + goto ok; + } + } + } + info->lastpos = HA_OFFSET_ERROR; + my_errno = HA_ERR_KEY_NOT_FOUND; + res = 1; + +ok: + my_afree((byte*)page_buf); + return res; + +err1: + my_afree((byte*)page_buf); + info->lastpos = HA_OFFSET_ERROR; + return -1; +} + +/* +Find first key in r-tree according to search_flag condition +Result values: +-1 - error + 0 - found + 1 - not found +*/ +int rtree_find_first(MI_INFO *info, uint keynr, uchar *key, uint key_length, + uint search_flag) +{ + my_off_t root; + uint nod_cmp_flag; + MI_KEYDEF *keyinfo = info->s->keyinfo + keynr; + + if ((root = info->s->state.key_root[keynr]) == HA_OFFSET_ERROR) + return -1; + + /* Save searched key */ + memcpy(info->lastkey2, key, keyinfo->keylength - info->s->base.rec_reflength); + info->last_rkey_length = key_length; + + info->rtree_recursion_depth = -1; + info->buff_used = 1; + + nod_cmp_flag = ((search_flag & (MBR_EQUAL | MBR_WITHIN)) ? + MBR_WITHIN : MBR_INTERSECT); + return rtree_find_req(info, keyinfo, search_flag, nod_cmp_flag, root, 0); +} + +/* +Find next key in r-tree according to search_flag condition +Result values: +-1 - error + 0 - found + 1 - not found +*/ +int rtree_find_next(MI_INFO *info, uint keynr, uint search_flag) +{ + my_off_t root; + uint nod_cmp_flag; + MI_KEYDEF *keyinfo = info->s->keyinfo + keynr; + + if (!info->buff_used) + { + uint k_len = keyinfo->keylength - info->s->base.rec_reflength; + /* rt_PAGE_NEXT_KEY(info->int_keypos) */ + uchar *key = info->buff + *(int*)info->int_keypos + k_len + + info->s->base.rec_reflength; + + while (key < info->int_maxpos) + { + if (!rtree_key_cmp(keyinfo->seg, info->lastkey2, key, + info->last_rkey_length, search_flag)) + { + /* rt_PAGE_NEXT_KEY(key) */ + uchar *after_key = key + k_len + info->s->base.rec_reflength; + + info->lastpos = _mi_dpos(info, 0, after_key); + info->lastkey_length = k_len + info->s->base.rec_reflength; + memcpy(info->lastkey, key, k_len + info->s->base.rec_reflength); + + *(int*)info->int_keypos = key - info->buff; + if (after_key >= info->int_maxpos) + { + info->buff_used = 1; + } + + return 0; + } + else + { + key += k_len + info->s->base.rec_reflength; + } + } + } + if ((root = info->s->state.key_root[keynr]) == HA_OFFSET_ERROR) + return -1; + + nod_cmp_flag = ((search_flag & (MBR_EQUAL | MBR_WITHIN)) ? + MBR_WITHIN : MBR_INTERSECT); + return rtree_find_req(info, keyinfo, search_flag, nod_cmp_flag, root, 0); +} + +/* +Get next key in r-tree recursively +Used in rtree_get_first() and rtree_get_next() +Result values: +-1 - error + 0 - found + 1 - not found +*/ +static int rtree_get_req(MI_INFO *info, MI_KEYDEF *keyinfo, uint key_length, + my_off_t page, int level) +{ + uchar *k; + uchar *last; + uint nod_flag; + int res; + uchar *page_buf; + uint k_len; + int *saved_key = (int*)(info->rtree_recursion_state + level*sizeof(int)); + + if (!(page_buf = (uchar*)my_alloca((uint)keyinfo->block_length))) + return -1; + if (!_mi_fetch_keypage(info, keyinfo, page, page_buf, 0)) + goto err1; + nod_flag = mi_test_if_nod(page_buf); + + k_len = keyinfo->keylength - info->s->base.rec_reflength; + + if(info->rtree_recursion_depth >= level) + { + k = page_buf + *saved_key; + if (!nod_flag) + { + /* Only leaf pages contain data references. */ + /* Need to check next key with data reference. */ + k = rt_PAGE_NEXT_KEY(k, k_len, nod_flag); + } + } + else + { + k = rt_PAGE_FIRST_KEY(page_buf, nod_flag); + } + last = rt_PAGE_END(page_buf); + + for (; k < last; k = rt_PAGE_NEXT_KEY(k, k_len, nod_flag)) + { + if (nod_flag) + { + /* this is an internal node in the tree */ + switch ((res = rtree_get_req(info, keyinfo, key_length, + _mi_kpos(nod_flag, k), level + 1))) + { + case 0: /* found - exit from recursion */ + *saved_key = k - page_buf; + goto ok; + case 1: /* not found - continue searching */ + info->rtree_recursion_depth = level; + break; + default: + case -1: /* error */ + goto err1; + } + } + else + { + /* this is a leaf */ + uchar *after_key = rt_PAGE_NEXT_KEY(k, k_len, nod_flag); + info->lastpos = _mi_dpos(info, 0, after_key); + info->lastkey_length = k_len + info->s->base.rec_reflength; + memcpy(info->lastkey, k, k_len + info->s->base.rec_reflength); + + info->rtree_recursion_depth = level; + *saved_key = k - page_buf; + + if (after_key < last) + { + info->int_keypos = (uchar*)saved_key; + memcpy(info->buff, page_buf, keyinfo->block_length); + info->int_maxpos = rt_PAGE_END(info->buff); + info->buff_used = 0; + } + + res = 0; + goto ok; + } + } + info->lastpos = HA_OFFSET_ERROR; + my_errno = HA_ERR_KEY_NOT_FOUND; + res = 1; + +ok: + my_afree((byte*)page_buf); + return res; + +err1: + my_afree((byte*)page_buf); + info->lastpos = HA_OFFSET_ERROR; + return -1; +} + +/* +Get first key in r-tree +Result values: +-1 - error + 0 - found + 1 - not found +*/ +int rtree_get_first(MI_INFO *info, uint keynr, uint key_length) +{ + my_off_t root; + MI_KEYDEF *keyinfo = info->s->keyinfo + keynr; + + if ((root = info->s->state.key_root[keynr]) == HA_OFFSET_ERROR) + return -1; + + info->rtree_recursion_depth = -1; + info->buff_used = 1; + + return rtree_get_req(info, &keyinfo[keynr], key_length, root, 0); +} + +/* Get next key in r-tree +Result values: +-1 - error + 0 - found + 1 - not found +*/ +int rtree_get_next(MI_INFO *info, uint keynr, uint key_length) +{ + my_off_t root; + MI_KEYDEF *keyinfo = info->s->keyinfo + keynr; + + if (!info->buff_used) + { + uint k_len = keyinfo->keylength - info->s->base.rec_reflength; + /* rt_PAGE_NEXT_KEY(info->int_keypos) */ + uchar *key = info->buff + *(int*)info->int_keypos + k_len + + info->s->base.rec_reflength; + /* rt_PAGE_NEXT_KEY(key) */ + uchar *after_key = key + k_len + info->s->base.rec_reflength; + + info->lastpos = _mi_dpos(info, 0, after_key); + info->lastkey_length = k_len + info->s->base.rec_reflength; + memcpy(info->lastkey, key, k_len + info->s->base.rec_reflength); + + *(int*)info->int_keypos = key - info->buff; + if (after_key >= info->int_maxpos) + { + info->buff_used = 1; + } + + return 0; + } + else + { + if ((root = info->s->state.key_root[keynr]) == HA_OFFSET_ERROR) + return -1; + + return rtree_get_req(info, &keyinfo[keynr], key_length, root, 0); + } +} + +/* +Go down and insert key into tree +Result values: +-1 - error + 0 - child was not split + 1 - child was split +*/ +static int rtree_insert_req(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *key, + uint key_length, my_off_t page, my_off_t *new_page, + int ins_level, int level) +{ + uchar *k; + uint nod_flag; + uchar *page_buf; + int res; + + if (!(page_buf = (uchar*)my_alloca((uint)keyinfo->block_length + + MI_MAX_KEY_BUFF))) + { + my_errno = HA_ERR_OUT_OF_MEM; + return -1; + } + if (!_mi_fetch_keypage(info, keyinfo, page, page_buf, 0)) + goto err1; + nod_flag = mi_test_if_nod(page_buf); + + if ((ins_level == -1 && nod_flag) || /* key: go down to leaf */ + (ins_level > -1 && ins_level > level)) /* branch: go down to ins_level */ + { + if ((k = rtree_choose_key(info, keyinfo, key, key_length, page_buf, + nod_flag)) == NULL) + goto err1; + switch ((res = rtree_insert_req(info, keyinfo, key, key_length, + _mi_kpos(nod_flag, k), new_page, ins_level, level + 1))) + { + case 0: /* child was not split */ + { + rtree_combine_rect(keyinfo->seg, k, key, k, key_length); + if (_mi_write_keypage(info, keyinfo, page, page_buf)) + goto err1; + goto ok; + } + case 1: /* child was split */ + { + uchar *new_key = page_buf + keyinfo->block_length + nod_flag; + /* set proper MBR for key */ + if (rtree_set_key_mbr(info, keyinfo, k, key_length, + _mi_kpos(nod_flag, k))) + goto err1; + /* add new key for new page */ + _mi_kpointer(info, new_key - nod_flag, *new_page); + if (rtree_set_key_mbr(info, keyinfo, new_key, key_length, *new_page)) + goto err1; + res = rtree_add_key(info, keyinfo, new_key, key_length, + page_buf, new_page); + if (_mi_write_keypage(info, keyinfo, page, page_buf)) + goto err1; + goto ok; + } + default: + case -1: /* error */ + { + goto err1; + } + } + } + else + { + res = rtree_add_key(info, keyinfo, key, key_length, page_buf, new_page); + if (_mi_write_keypage(info, keyinfo, page, page_buf)) + goto err1; + goto ok; + } + +ok: + my_afree((byte*)page_buf); + return res; + +err1: + my_afree((byte*)page_buf); + return -1; +} + +/* +Insert key into the tree +Result values: +-1 - error + 0 - root was not split + 1 - root was split +*/ +static int rtree_insert_level(MI_INFO *info, uint keynr, uchar *key, + uint key_length, int ins_level) +{ + my_off_t old_root; + MI_KEYDEF *keyinfo = info->s->keyinfo + keynr; + int res; + my_off_t new_page; + + if ((old_root = info->s->state.key_root[keynr]) == HA_OFFSET_ERROR) + { + int res; + + if ((old_root = _mi_new(info, keyinfo)) == HA_OFFSET_ERROR) + return -1; + info->buff_used = 1; + mi_putint(info->buff, 2, 0); + res = rtree_add_key(info, keyinfo, key, key_length, info->buff, NULL); + if (_mi_write_keypage(info, keyinfo, old_root, info->buff)) + return 1; + info->s->state.key_root[keynr] = old_root; + return res; + } + + switch ((res = rtree_insert_req(info, &keyinfo[keynr], key, key_length, + old_root, &new_page, ins_level, 0))) + { + case 0: /* root was not split */ + { + break; + } + case 1: /* root was split, grow a new root */ + { + uchar *new_root_buf; + my_off_t new_root; + uchar *new_key; + uint nod_flag = info->s->base.key_reflength; + + if (!(new_root_buf = (uchar*)my_alloca((uint)keyinfo->block_length + + MI_MAX_KEY_BUFF))) + { + my_errno = HA_ERR_OUT_OF_MEM; + return -1; + } + + mi_putint(new_root_buf, 2, nod_flag); + if ((new_root = _mi_new(info, keyinfo)) == HA_OFFSET_ERROR) + goto err1; + + new_key = new_root_buf + keyinfo->block_length + nod_flag; + + _mi_kpointer(info, new_key - nod_flag, old_root); + if (rtree_set_key_mbr(info, keyinfo, new_key, key_length, old_root)) + goto err1; + if (rtree_add_key(info, keyinfo, new_key, key_length, new_root_buf, NULL) + == -1) + goto err1; + _mi_kpointer(info, new_key - nod_flag, new_page); + if (rtree_set_key_mbr(info, keyinfo, new_key, key_length, new_page)) + goto err1; + if (rtree_add_key(info, keyinfo, new_key, key_length, new_root_buf, NULL) + == -1) + goto err1; + if (_mi_write_keypage(info, keyinfo, new_root, new_root_buf)) + goto err1; + info->s->state.key_root[keynr] = new_root; + + my_afree((byte*)new_root_buf); + break; +err1: + my_afree((byte*)new_root_buf); + return -1; + } + default: + case -1: /* error */ + { + break; + } + } + return res; +} + +/* +Insert key into the tree - interface function +Result values: +-1 - error + 0 - OK +*/ +int rtree_insert(MI_INFO *info, uint keynr, uchar *key, uint key_length) +{ + return (rtree_insert_level(info, keynr, key, key_length, -1) == -1) ? -1 : 0; +} + +/* +Fill reinsert page buffer +*/ +static int rtree_fill_reinsert_list(stPageList *ReinsertList, my_off_t page, + int level) +{ + if (ReinsertList->n_pages == ReinsertList->m_pages) + { + ReinsertList->m_pages += REINSERT_BUFFER_INC; + if (!(ReinsertList->pages = (stPageLevel*)my_realloc((gptr)ReinsertList->pages, + ReinsertList->m_pages * sizeof(stPageLevel), MYF(MY_ALLOW_ZERO_PTR)))) + goto err1; + } + /* save page to ReinsertList */ + ReinsertList->pages[ReinsertList->n_pages].offs = page; + ReinsertList->pages[ReinsertList->n_pages].level = level; + ReinsertList->n_pages++; + return 0; + +err1: + return -1; +} + +/* +Go down and delete key from the tree +Result values: +-1 - error + 0 - deleted + 1 - not found + 2 - empty leaf +*/ +static int rtree_delete_req(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *key, + uint key_length, my_off_t page, uint *page_size, + stPageList *ReinsertList, int level) +{ + uchar *k; + uchar *last; + ulong i; + uint nod_flag; + uchar *page_buf; + int res; + + if (!(page_buf = (uchar*)my_alloca((uint)keyinfo->block_length))) + { + my_errno = HA_ERR_OUT_OF_MEM; + return -1; + } + if (!_mi_fetch_keypage(info, keyinfo, page, page_buf, 0)) + goto err1; + nod_flag = mi_test_if_nod(page_buf); + + k = rt_PAGE_FIRST_KEY(page_buf, nod_flag); + last = rt_PAGE_END(page_buf); + + for (i = 0; k < last; k = rt_PAGE_NEXT_KEY(k, key_length, nod_flag), ++i) + { + if (nod_flag) + { + /* not leaf */ + if (!rtree_key_cmp(keyinfo->seg, key, k, key_length, MBR_WITHIN)) + { + switch ((res = rtree_delete_req(info, keyinfo, key, key_length, + _mi_kpos(nod_flag, k), page_size, ReinsertList, level + 1))) + { + case 0: /* deleted */ + { + /* test page filling */ + if (*page_size + key_length >= rt_PAGE_MIN_SIZE(keyinfo->block_length)) + { + /* OK */ + if (rtree_set_key_mbr(info, keyinfo, k, key_length, + _mi_kpos(nod_flag, k))) + goto err1; + if (_mi_write_keypage(info, keyinfo, page, page_buf)) + goto err1; + } + else + { + /* too small: delete key & add it descendant to reinsert list */ + if (rtree_fill_reinsert_list(ReinsertList, _mi_kpos(nod_flag, k), + level + 1)) + goto err1; + rtree_delete_key(info, page_buf, k, key_length, nod_flag); + if (_mi_write_keypage(info, keyinfo, page, page_buf)) + goto err1; + *page_size = mi_getint(page_buf); + } + + goto ok; + } + case 1: /* not found - continue searching */ + { + break; + } + case 2: /* vacuous case: last key in the leaf */ + { + rtree_delete_key(info, page_buf, k, key_length, nod_flag); + if (_mi_write_keypage(info, keyinfo, page, page_buf)) + goto err1; + *page_size = mi_getint(page_buf); + res = 0; + goto ok; + } + default: /* error */ + case -1: + { + goto err1; + } + } + } + } + else + { + /* leaf */ + if (!rtree_key_cmp(keyinfo->seg, key, k, key_length, MBR_EQUAL | MBR_DATA)) + { + rtree_delete_key(info, page_buf, k, key_length, nod_flag); + *page_size = mi_getint(page_buf); + if (*page_size == 2) + { + /* last key in the leaf */ + res = 2; + if (_mi_dispose(info, keyinfo, page)) + goto err1; + } + else + { + res = 0; + if (_mi_write_keypage(info, keyinfo, page, page_buf)) + goto err1; + } + goto ok; + } + } + } + res = 1; + +ok: + my_afree((byte*)page_buf); + return res; + +err1: + my_afree((byte*)page_buf); + return -1; +} + +/* +Delete key - interface function +Result values: +-1 - error + 0 - deleted +*/ +int rtree_delete(MI_INFO *info, uint keynr, uchar *key, uint key_length) +{ + uint page_size; + stPageList ReinsertList; + my_off_t old_root; + MI_KEYDEF *keyinfo = info->s->keyinfo + keynr; + + if ((old_root = info->s->state.key_root[keynr]) == HA_OFFSET_ERROR) + { + my_errno = HA_ERR_KEY_NOT_FOUND; + return -1; + } + + ReinsertList.pages = NULL; + ReinsertList.n_pages = 0; + ReinsertList.m_pages = 0; + + switch (rtree_delete_req(info, keyinfo, key, key_length, old_root, + &page_size, &ReinsertList, 0)) + { + case 2: + { + info->s->state.key_root[keynr] = HA_OFFSET_ERROR; + return 0; + } + case 0: + { + uint nod_flag; + ulong i; + for (i = 0; i < ReinsertList.n_pages; ++i) + { + uchar *page_buf; + uint nod_flag; + uchar *k; + uchar *last; + + if (!(page_buf = (uchar*)my_alloca((uint)keyinfo->block_length))) + { + my_errno = HA_ERR_OUT_OF_MEM; + goto err1; + } + if (!_mi_fetch_keypage(info, keyinfo, ReinsertList.pages[i].offs, + page_buf, 0)) + goto err1; + nod_flag = mi_test_if_nod(page_buf); + k = rt_PAGE_FIRST_KEY(page_buf, nod_flag); + last = rt_PAGE_END(page_buf); + for (; k < last; k = rt_PAGE_NEXT_KEY(k, key_length, nod_flag)) + { + if (rtree_insert_level(info, keynr, k, key_length, + ReinsertList.pages[i].level) == -1) + { + my_afree((byte*)page_buf); + goto err1; + } + } + my_afree((byte*)page_buf); + if (_mi_dispose(info, keyinfo, ReinsertList.pages[i].offs)) + goto err1; + } + if (ReinsertList.pages) + free(ReinsertList.pages); + + /* check for redundant root (not leaf, 1 child) and eliminate */ + if ((old_root = info->s->state.key_root[keynr]) == HA_OFFSET_ERROR) + goto err1; + if (!_mi_fetch_keypage(info, keyinfo, old_root, info->buff, 0)) + goto err1; + nod_flag = mi_test_if_nod(info->buff); + page_size = mi_getint(info->buff); + if (nod_flag && (page_size == 2 + key_length + + (nod_flag ? nod_flag : info->s->base.rec_reflength))) + { + my_off_t new_root = _mi_kpos(nod_flag, + rt_PAGE_FIRST_KEY(info->buff, nod_flag)); + if (_mi_dispose(info, keyinfo, old_root)) + goto err1; + info->s->state.key_root[keynr] = new_root; + } + return 0; + +err1: + return -1; + } + case 1: /* not found */ + { + my_errno = HA_ERR_KEY_NOT_FOUND; + return -1; + } + default: + case -1: /* error */ + { + return -1; + } + } +} + +/* +Estimate number of suitable keys in the tree +*/ +ha_rows rtree_estimate(MI_INFO *info, uint keynr, uchar *key, + uint key_length, uint flag) +{ + MI_KEYDEF *keyinfo = info->s->keyinfo + keynr; + my_off_t root; + uint i = 0; + uchar *k; + uchar *last; + uint nod_flag; + uchar *page_buf; + uint k_len; + double area = 0; + ha_rows res = 0; + + if (flag & MBR_DISJOINT) + return info->state->records; + + if ((root = info->s->state.key_root[keynr]) == HA_OFFSET_ERROR) + return HA_POS_ERROR; + if (!(page_buf = (uchar*)my_alloca((uint)keyinfo->block_length))) + return HA_POS_ERROR; + if (!_mi_fetch_keypage(info, keyinfo, root, page_buf, 0)) + goto err1; + nod_flag = mi_test_if_nod(page_buf); + + k_len = keyinfo->keylength - info->s->base.rec_reflength; + + k = rt_PAGE_FIRST_KEY(page_buf, nod_flag); + last = rt_PAGE_END(page_buf); + + for (; k < last; k = rt_PAGE_NEXT_KEY(k, k_len, nod_flag), ++i) + { + if (nod_flag) + { + double k_area = rtree_rect_volume(keyinfo->seg, k, key_length); + + if (k_area == 0) + { + if (flag & (MBR_CONTAIN | MBR_INTERSECT)) + { + area += 1; + } + else if (flag & (MBR_WITHIN | MBR_EQUAL)) + { + if (!rtree_key_cmp(keyinfo->seg, key, k, key_length, MBR_WITHIN)) + area += 1; + } + else + goto err1; + } + else + { + if (flag & (MBR_CONTAIN | MBR_INTERSECT)) + { + area += rtree_overlapping_area(keyinfo->seg, key, k, key_length) / + k_area; + } + else if (flag & (MBR_WITHIN | MBR_EQUAL)) + { + if (!rtree_key_cmp(keyinfo->seg, key, k, key_length, MBR_WITHIN)) + area += rtree_rect_volume(keyinfo->seg, key, key_length) / + k_area; + } + else + goto err1; + } + } + else + { + if (!rtree_key_cmp(keyinfo->seg, key, k, key_length, flag)) + ++res; + } + } + if (nod_flag) + { + if (i) + res = (int)(area / i * info->state->records); + else + res = HA_POS_ERROR; + } + + my_afree((byte*)page_buf); + return res; + +err1: + my_afree((byte*)page_buf); + return HA_POS_ERROR; +} diff --git a/myisam/rt_index.h b/myisam/rt_index.h new file mode 100644 index 00000000000..1a0fce72a82 --- /dev/null +++ b/myisam/rt_index.h @@ -0,0 +1,44 @@ +/* Copyright (C) 2000 MySQL AB & Ramil Kalimullin & 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 */ + +#ifndef _rt_index_h +#define _rt_index_h + +#define rt_PAGE_FIRST_KEY(page, nod_flag) (page + 2 + nod_flag) +#define rt_PAGE_NEXT_KEY(key, key_length, nod_flag) (key + key_length + \ + (nod_flag ? nod_flag : info->s->base.rec_reflength)) +#define rt_PAGE_END(page) (page + mi_getint(page)) + +#define rt_PAGE_MIN_SIZE(block_length) ((uint)(block_length) / 2) + +int rtree_insert(MI_INFO *info, uint keynr, uchar *key, uint key_length); +int rtree_delete(MI_INFO *info, uint keynr, uchar *key, uint key_length); + +int rtree_find_first(MI_INFO *info, uint keynr, uchar *key, uint key_length, + uint search_flag); +int rtree_find_next(MI_INFO *info, uint keynr, uint search_flag); + +int rtree_get_first(MI_INFO *info, uint keynr, uint key_length); +int rtree_get_next(MI_INFO *info, uint keynr, uint key_length); + +ha_rows rtree_estimate(MI_INFO *info, uint keynr, uchar *key, + uint key_length, uint flag); + +int rtree_split_page(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *page, uchar *key, + uint key_length, my_off_t *new_page_offs); + +#endif /* _rt_index_h */ diff --git a/myisam/rt_key.c b/myisam/rt_key.c new file mode 100644 index 00000000000..c08e918c6db --- /dev/null +++ b/myisam/rt_key.c @@ -0,0 +1,154 @@ +/* Copyright (C) 2000 MySQL AB & Ramil Kalimullin & 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 */ + +#include "myisamdef.h" + +#include "rt_index.h" +#include "rt_key.h" +#include "rt_mbr.h" + +/* +Add key to the page +Result values: +-1 - error + 0 - not split + 1 - split +*/ +int rtree_add_key(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *key, + uint key_length, uchar *page_buf, my_off_t *new_page) +{ + uint page_size = mi_getint(page_buf); + uint nod_flag = mi_test_if_nod(page_buf); + + if (page_size + key_length + nod_flag <= keyinfo->block_length) + { + /* split won't be necessary */ + if (nod_flag) + { + /* save key */ + memcpy(rt_PAGE_END(page_buf), key - nod_flag, key_length + nod_flag); + page_size += key_length + nod_flag; + } + else + { + /* save key */ + memcpy(rt_PAGE_END(page_buf), key, key_length + + info->s->base.rec_reflength); + page_size += key_length + info->s->base.rec_reflength; + } + mi_putint(page_buf, page_size, nod_flag); + return 0; + } + else + { + if (rtree_split_page(info, keyinfo, page_buf, key, key_length, new_page)) + return -1; + else + return 1; + } +} + +/* +Delete key from the page +*/ +int rtree_delete_key(MI_INFO *info, uchar *page_buf, uchar *key, + uint key_length, uint nod_flag) +{ + uint16 page_size = mi_getint(page_buf); + uchar *key_start; + + if (nod_flag) + { + key_start = key - nod_flag; + } + else + { + key_start = key; + key_length += info->s->base.rec_reflength; + } + memmove(key_start, key + key_length, page_size - key_length - + (key - page_buf)); + page_size -= key_length + nod_flag; + + mi_putint(page_buf, page_size, nod_flag); + + return 0; +} + +/* +Calculate and store key MBR +*/ +int rtree_set_key_mbr(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *key, + uint key_length, my_off_t child_page) +{ + uchar *k; + uchar *last; + uint nod_flag; + + if (!_mi_fetch_keypage(info, keyinfo, child_page, info->buff, 0)) + goto err1; + nod_flag = mi_test_if_nod(info->buff); + + k = rt_PAGE_FIRST_KEY(info->buff, nod_flag); + last = rt_PAGE_END(info->buff); + + rtree_page_mbr(info, keyinfo->seg, info->buff, key, key_length); + + return 0; + +err1: + return -1; +} + +/* +Choose non-leaf better key for insertion +*/ +uchar *rtree_choose_key(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *key, + uint key_length, uchar *page_buf, uint nod_flag) +{ + double increase; + double best_incr = DBL_MAX; + double area; + double best_area; + uchar *best_key; + + uchar *k = rt_PAGE_FIRST_KEY(page_buf, nod_flag); + uchar *last = rt_PAGE_END(page_buf); + + for (; k < last; k = rt_PAGE_NEXT_KEY(k, key_length, nod_flag)) + { + if ((increase = rtree_area_increase(keyinfo->seg, key, k, key_length, + &area)) == -1) + return NULL; + if (increase < best_incr) + { + best_key = k; + best_area = area; + best_incr = increase; + } + else + { + if ((increase == best_incr) && (area < best_area)) + { + best_key = k; + best_area = area; + best_incr = increase; + } + } + } + return best_key; +} diff --git a/myisam/rt_key.h b/myisam/rt_key.h new file mode 100644 index 00000000000..dfd7b874b54 --- /dev/null +++ b/myisam/rt_key.h @@ -0,0 +1,31 @@ +/* Copyright (C) 2000 MySQL AB & Ramil Kalimullin & 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 */ + +/* Written by Ramil Kalimullin, who has a shared copyright to this code */ + +#ifndef _rt_key_h +#define _rt_key_h + +int rtree_add_key(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *key, + uint key_length, uchar *page_buf, my_off_t *new_page); +int rtree_delete_key(MI_INFO *info, uchar *page, uchar *key, + uint key_length, uint nod_flag); +int rtree_set_key_mbr(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *key, + uint key_length, my_off_t child_page); +uchar *rtree_choose_key(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *key, + uint key_length, uchar *page_buf, uint nod_flag); +#endif /* _rt_key_h */ diff --git a/myisam/rt_mbr.c b/myisam/rt_mbr.c new file mode 100644 index 00000000000..a6467500183 --- /dev/null +++ b/myisam/rt_mbr.c @@ -0,0 +1,758 @@ +/* Copyright (C) 2000 MySQL AB & Ramil Kalimullin & 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 */ + +#include "myisamdef.h" + +#include "rt_index.h" +#include "rt_mbr.h" + +#define INTERSECT_CMP(amin, amax, bmin, bmax) ((amin > bmax) || (bmin > amax)) +#define CONTAIN_CMP(amin, amax, bmin, bmax) ((bmin > amin) || (bmax < amax)) +#define WITHIN_CMP(amin, amax, bmin, bmax) ((amin > bmin) || (amax < bmax)) +#define DISJOINT_CMP(amin, amax, bmin, bmax) ((amin <= bmax) && (bmin <= amax)) +#define EQUAL_CMP(amix, amax, bmin, bmax) ((amix != bmin) || (amax != bmax)) + +#define FCMP(A, B) ((int)(A) - (int)(B)) +#define p_inc(A, B, X) {A += X; B += X;} + +#define RT_CMP(nextflag) \ + if (nextflag & MBR_INTERSECT) \ + { \ + if (INTERSECT_CMP(amin, amax, bmin, bmax)) \ + return 1; \ + } \ + else if (nextflag & MBR_CONTAIN) \ + { \ + if (CONTAIN_CMP(amin, amax, bmin, bmax)) \ + return 1; \ + } \ + else if (nextflag & MBR_WITHIN) \ + { \ + if (WITHIN_CMP(amin, amax, bmin, bmax)) \ + return 1; \ + } \ + else if (nextflag & MBR_EQUAL) \ + { \ + if (EQUAL_CMP(amin, amax, bmin, bmax)) \ + return 1; \ + } \ + else /* if (nextflag & MBR_DISJOINT) */ \ + { \ + if (DISJOINT_CMP(amin, amax, bmin, bmax)) \ + return 1; \ + } + +#define RT_CMP_KORR(type, korr_func, len, nextflag) \ +{ \ + type amin, amax, bmin, bmax; \ + amin = korr_func(a); \ + bmin = korr_func(b); \ + p_inc(a, b, len); \ + amax = korr_func(a); \ + bmax = korr_func(b); \ + RT_CMP(nextflag); \ + p_inc(a, b, len); \ + break; \ +} + +#define RT_CMP_GET(type, get_func, len, nextflag) \ +{ \ + type amin, amax, bmin, bmax; \ + get_func(amin, a); \ + get_func(bmin, b); \ + p_inc(a, b, len); \ + get_func(amax, a); \ + get_func(bmax, b); \ + RT_CMP(nextflag); \ + p_inc(a, b, len); \ + break; \ +} + +/* + Compares two keys a and b depending on nextflag + nextflag can contain these flags: + MBR_INTERSECT(a,b) a overlaps b + MBR_CONTAIN(a,b) a contains b + MBR_DISJOINT(a,b) a disjoint b + MBR_WITHIN(a,b) a within b + MBR_EQUAL(a,b) All coordinates of MBRs are equal + MBR_DATA(a,b) Data reference is the same + Returns 0 on success. +*/ +int rtree_key_cmp(HA_KEYSEG *keyseg, uchar *b, uchar *a, uint key_length, + uint nextflag) +{ + for (; (int) key_length > 0; keyseg += 2 ) + { + key_length -= keyseg->length * 2; + + switch ((enum ha_base_keytype) keyseg->type) { + case HA_KEYTYPE_TEXT: + case HA_KEYTYPE_BINARY: + case HA_KEYTYPE_VARTEXT: + case HA_KEYTYPE_VARBINARY: + case HA_KEYTYPE_NUM: + default: + return 1; + break; + case HA_KEYTYPE_INT8: + { + int amin,amax,bmin,bmax; + amin = (int)*((signed char *)a); + bmin = (int)*((signed char *)b); + p_inc(a, b, 1); + amax = (int)*((signed char *)a); + bmax = (int)*((signed char *)b); + RT_CMP(nextflag); + p_inc(a, b, 1); + break; + } + case HA_KEYTYPE_SHORT_INT: + RT_CMP_KORR(int16, mi_sint2korr, 2, nextflag); + case HA_KEYTYPE_USHORT_INT: + RT_CMP_KORR(uint16, mi_uint2korr, 2, nextflag); + case HA_KEYTYPE_INT24: + RT_CMP_KORR(int32, mi_sint3korr, 3, nextflag); + case HA_KEYTYPE_UINT24: + RT_CMP_KORR(uint32, mi_uint3korr, 3, nextflag); + case HA_KEYTYPE_LONG_INT: + RT_CMP_KORR(int32, mi_sint4korr, 4, nextflag); + case HA_KEYTYPE_ULONG_INT: + RT_CMP_KORR(uint32, mi_uint4korr, 4, nextflag); +#ifdef HAVE_LONG_LONG + case HA_KEYTYPE_LONGLONG: + RT_CMP_KORR(longlong, mi_sint8korr, 8, nextflag) + case HA_KEYTYPE_ULONGLONG: + RT_CMP_KORR(ulonglong, mi_uint8korr, 8, nextflag) +#endif + case HA_KEYTYPE_FLOAT: + RT_CMP_GET(float, mi_float4get, 4, nextflag); + case HA_KEYTYPE_DOUBLE: + RT_CMP_GET(double, mi_float8get, 8, nextflag); + case HA_KEYTYPE_END: + goto end; + } + } + +end: + if (nextflag & MBR_DATA) + { + uchar *end = a + keyseg->length; + do + { + if (*a++ != *b++) + return FCMP(a[-1], b[-1]); + } while (a != end); + } + return 0; +} + +#define RT_VOL_KORR(type, korr_func, len) \ +{ \ + type amin, amax; \ + amin = korr_func(a); \ + a += len; \ + amax = korr_func(a); \ + a += len; \ + res *= ((double)amax - (double)amin); \ + break; \ +} + +#define RT_VOL_GET(type, get_func, len) \ +{ \ + type amin, amax; \ + get_func(amin, a); \ + a += len; \ + get_func(amax, a); \ + a += len; \ + res *= ((double)amax - (double)amin); \ + break; \ +} + +/* + Calculates rectangle volume +*/ +double rtree_rect_volume(HA_KEYSEG *keyseg, uchar *a, uint key_length) +{ + double res = 1; + for (; (int)key_length > 0; keyseg += 2) + { + key_length -= keyseg->length * 2; + + switch ((enum ha_base_keytype) keyseg->type) { + case HA_KEYTYPE_TEXT: + case HA_KEYTYPE_BINARY: + case HA_KEYTYPE_VARTEXT: + case HA_KEYTYPE_VARBINARY: + case HA_KEYTYPE_NUM: + default: + return 1; + break; + case HA_KEYTYPE_INT8: + { + int amin, amax; + amin = (int)*((signed char *)a); + a += 1; + amax = (int)*((signed char *)a); + a += 1; + res *= ((double)amax - (double)amin); + break; + } + case HA_KEYTYPE_SHORT_INT: + RT_VOL_KORR(int16, mi_sint2korr, 2); + case HA_KEYTYPE_USHORT_INT: + RT_VOL_KORR(uint16, mi_uint2korr, 2); + case HA_KEYTYPE_INT24: + RT_VOL_KORR(int32, mi_sint3korr, 3); + case HA_KEYTYPE_UINT24: + RT_VOL_KORR(uint32, mi_uint3korr, 3); + case HA_KEYTYPE_LONG_INT: + RT_VOL_KORR(int32, mi_sint4korr, 4); + case HA_KEYTYPE_ULONG_INT: + RT_VOL_KORR(uint32, mi_uint4korr, 4); +#ifdef HAVE_LONG_LONG + case HA_KEYTYPE_LONGLONG: + RT_VOL_KORR(longlong, mi_sint8korr, 8); + case HA_KEYTYPE_ULONGLONG: + RT_VOL_KORR(ulonglong, mi_uint8korr, 8); +#endif + case HA_KEYTYPE_FLOAT: + RT_VOL_GET(float, mi_float4get, 4); + case HA_KEYTYPE_DOUBLE: + RT_VOL_GET(double, mi_float8get, 8); + case HA_KEYTYPE_END: + key_length = 0; + break; + } + } + return res; +} + +#define RT_D_MBR_KORR(type, korr_func, len) \ +{ \ + type amin, amax; \ + amin = korr_func(a); \ + a += len; \ + amax = korr_func(a); \ + a += len; \ + *res++ = (double)amin; \ + *res++ = (double)amax; \ + break; \ +} + +#define RT_D_MBR_GET(type, get_func, len) \ +{ \ + type amin, amax; \ + get_func(amin, a); \ + a += len; \ + get_func(amax, a); \ + a += len; \ + *res++ = (double)amin; \ + *res++ = (double)amax; \ + break; \ +} + +/* + Creates an MBR as an array of doubles. +*/ +int rtree_d_mbr(HA_KEYSEG *keyseg, uchar *a, uint key_length, double *res) +{ + for (; (int)key_length > 0; keyseg += 2) + { + key_length -= keyseg->length * 2; + + switch ((enum ha_base_keytype) keyseg->type) { + case HA_KEYTYPE_TEXT: + case HA_KEYTYPE_BINARY: + case HA_KEYTYPE_VARTEXT: + case HA_KEYTYPE_VARBINARY: + case HA_KEYTYPE_NUM: + default: + return 1; + break; + case HA_KEYTYPE_INT8: + { + int amin, amax; + amin = (int)*((signed char *)a); + a += 1; + amax = (int)*((signed char *)a); + a += 1; + *res++ = (double)amin; + *res++ = (double)amax; + break; + } + case HA_KEYTYPE_SHORT_INT: + RT_D_MBR_KORR(int16, mi_sint2korr, 2); + case HA_KEYTYPE_USHORT_INT: + RT_D_MBR_KORR(uint16, mi_uint2korr, 2); + case HA_KEYTYPE_INT24: + RT_D_MBR_KORR(int32, mi_sint3korr, 3); + case HA_KEYTYPE_UINT24: + RT_D_MBR_KORR(uint32, mi_uint3korr, 3); + case HA_KEYTYPE_LONG_INT: + RT_D_MBR_KORR(int32, mi_sint4korr, 4); + case HA_KEYTYPE_ULONG_INT: + RT_D_MBR_KORR(uint32, mi_uint4korr, 4); +#ifdef HAVE_LONG_LONG + case HA_KEYTYPE_LONGLONG: + RT_D_MBR_KORR(longlong, mi_sint8korr, 8); + case HA_KEYTYPE_ULONGLONG: + RT_D_MBR_KORR(ulonglong, mi_uint8korr, 8); +#endif + case HA_KEYTYPE_FLOAT: + RT_D_MBR_GET(float, mi_float4get, 4); + case HA_KEYTYPE_DOUBLE: + RT_D_MBR_GET(double, mi_float8get, 8); + case HA_KEYTYPE_END: + key_length = 0; + break; + } + } + return 0; +} + +#define RT_COMB_KORR(type, korr_func, store_func, len) \ +{ \ + type amin, amax, bmin, bmax; \ + amin = korr_func(a); \ + bmin = korr_func(b); \ + p_inc(a, b, len); \ + amax = korr_func(a); \ + bmax = korr_func(b); \ + p_inc(a, b, len); \ + amin = min(amin, bmin); \ + amax = max(amax, bmax); \ + store_func(c, amin); \ + c += len; \ + store_func(c, amax); \ + c += len; \ + break; \ +} + +#define RT_COMB_GET(type, get_func, store_func, len) \ +{ \ + type amin, amax, bmin, bmax; \ + get_func(amin, a); \ + get_func(bmin, b); \ + p_inc(a, b, len); \ + get_func(amax, a); \ + get_func(bmax, b); \ + p_inc(a, b, len); \ + amin = min(amin, bmin); \ + amax = max(amax, bmax); \ + store_func(c, amin); \ + c += len; \ + store_func(c, amax); \ + c += len; \ + break; \ +} + +/* +Creates common minimal bounding rectungle +for two input rectagnles a and b +Result is written to c +*/ +int rtree_combine_rect(HA_KEYSEG *keyseg, uchar* a, uchar* b, uchar* c, + uint key_length) +{ + + for ( ; (int) key_length > 0 ; keyseg += 2) + { + key_length -= keyseg->length * 2; + + switch ((enum ha_base_keytype) keyseg->type) { + case HA_KEYTYPE_TEXT: + case HA_KEYTYPE_BINARY: + case HA_KEYTYPE_VARTEXT: + case HA_KEYTYPE_VARBINARY: + case HA_KEYTYPE_NUM: + default: + return 1; + break; + case HA_KEYTYPE_INT8: + { + int amin, amax, bmin, bmax; + amin = (int)*((signed char *)a); + bmin = (int)*((signed char *)b); + p_inc(a, b, 1); + amax = (int)*((signed char *)a); + bmax = (int)*((signed char *)b); + p_inc(a, b, 1); + amin = min(amin, bmin); + amax = max(amax, bmax); + *((signed char*)c) = amin; + c += 1; + *((signed char*)c) = amax; + c += 1; + break; + } + case HA_KEYTYPE_SHORT_INT: + RT_COMB_KORR(int16, mi_sint2korr, mi_int2store, 2); + case HA_KEYTYPE_USHORT_INT: + RT_COMB_KORR(uint16, mi_uint2korr, mi_int2store, 2); + case HA_KEYTYPE_INT24: + RT_COMB_KORR(int32, mi_sint3korr, mi_int3store, 3); + case HA_KEYTYPE_UINT24: + RT_COMB_KORR(uint32, mi_uint3korr, mi_int3store, 3); + case HA_KEYTYPE_LONG_INT: + RT_COMB_KORR(int32, mi_sint4korr, mi_int4store, 4); + case HA_KEYTYPE_ULONG_INT: + RT_COMB_KORR(uint32, mi_uint4korr, mi_int4store, 4); +#ifdef HAVE_LONG_LONG + case HA_KEYTYPE_LONGLONG: + RT_COMB_KORR(longlong, mi_sint8korr, mi_int8store, 8); + case HA_KEYTYPE_ULONGLONG: + RT_COMB_KORR(ulonglong, mi_uint8korr, mi_int8store, 8); +#endif + case HA_KEYTYPE_FLOAT: + RT_COMB_GET(float, mi_float4get, mi_float4store, 4); + case HA_KEYTYPE_DOUBLE: + RT_COMB_GET(double, mi_float8get, mi_float8store, 8); + case HA_KEYTYPE_END: + return 0; + } + } + return 0; +} + +#define RT_OVL_AREA_KORR(type, korr_func, len) \ +{ \ + type amin, amax, bmin, bmax; \ + amin = korr_func(a); \ + bmin = korr_func(b); \ + p_inc(a, b, len); \ + amax = korr_func(a); \ + bmax = korr_func(b); \ + p_inc(a, b, len); \ + amin = max(amin, bmin); \ + amax = min(amax, bmax); \ + if (amin >= amax) \ + return 0; \ + res *= amax - amin; \ + break; \ +} + +#define RT_OVL_AREA_GET(type, get_func, len) \ +{ \ + type amin, amax, bmin, bmax; \ + get_func(amin, a); \ + get_func(bmin, b); \ + p_inc(a, b, len); \ + get_func(amax, a); \ + get_func(bmax, b); \ + p_inc(a, b, len); \ + amin = max(amin, bmin); \ + amax = min(amax, bmax); \ + if (amin >= amax) \ + return 0; \ + res *= amax - amin; \ + break; \ +} + +/* +Calculates overlapping area of two MBRs a & b +*/ +double rtree_overlapping_area(HA_KEYSEG *keyseg, uchar* a, uchar* b, + uint key_length) +{ + double res = 1; + for (; (int) key_length > 0 ; keyseg += 2) + { + key_length -= keyseg->length * 2; + + switch ((enum ha_base_keytype) keyseg->type) { + case HA_KEYTYPE_TEXT: + case HA_KEYTYPE_BINARY: + case HA_KEYTYPE_VARTEXT: + case HA_KEYTYPE_VARBINARY: + case HA_KEYTYPE_NUM: + default: + return -1; + break; + case HA_KEYTYPE_INT8: + { + int amin, amax, bmin, bmax; + amin = (int)*((signed char *)a); + bmin = (int)*((signed char *)b); + p_inc(a, b, 1); + amax = (int)*((signed char *)a); + bmax = (int)*((signed char *)b); + p_inc(a, b, 1); + amin = max(amin, bmin); + amax = min(amax, bmax); + if (amin >= amax) + return 0; + res *= amax - amin; + break; + } + case HA_KEYTYPE_SHORT_INT: + RT_OVL_AREA_KORR(int16, mi_sint2korr, 2); + case HA_KEYTYPE_USHORT_INT: + RT_OVL_AREA_KORR(uint16, mi_uint2korr, 2); + case HA_KEYTYPE_INT24: + RT_OVL_AREA_KORR(int32, mi_sint3korr, 3); + case HA_KEYTYPE_UINT24: + RT_OVL_AREA_KORR(uint32, mi_uint3korr, 3); + case HA_KEYTYPE_LONG_INT: + RT_OVL_AREA_KORR(int32, mi_sint4korr, 4); + case HA_KEYTYPE_ULONG_INT: + RT_OVL_AREA_KORR(uint32, mi_uint4korr, 4); +#ifdef HAVE_LONG_LONG + case HA_KEYTYPE_LONGLONG: + RT_OVL_AREA_KORR(longlong, mi_sint8korr, 8); + case HA_KEYTYPE_ULONGLONG: + RT_OVL_AREA_KORR(ulonglong, mi_uint8korr, 8); +#endif + case HA_KEYTYPE_FLOAT: + RT_OVL_AREA_GET(float, mi_float4get, 4); + case HA_KEYTYPE_DOUBLE: + RT_OVL_AREA_GET(double, mi_float8get, 8); + case HA_KEYTYPE_END: + return res; + } + } + return res; +} + +#define RT_AREA_INC_KORR(type, korr_func, len) \ +{ \ + type amin, amax, bmin, bmax; \ + amin = korr_func(a); \ + bmin = korr_func(b); \ + p_inc(a, b, len); \ + amax = korr_func(a); \ + bmax = korr_func(b); \ + p_inc(a, b, len); \ + a_area *= (((double)amax) - ((double)amin)); \ + *ab_area *= ((double)max(amax, bmax) - (double)min(amin, bmin)); \ + break; \ +} + +#define RT_AREA_INC_GET(type, get_func, len)\ +{\ + type amin, amax, bmin, bmax; \ + get_func(amin, a); \ + get_func(bmin, b); \ + p_inc(a, b, len); \ + get_func(amax, a); \ + get_func(bmax, b); \ + p_inc(a, b, len); \ + a_area *= (((double)amax) - ((double)amin)); \ + *ab_area *= ((double)max(amax, bmax) - (double)min(amin, bmin)); \ + break; \ +} + +/* +Calculates MBR_AREA(a+b) - MBR_AREA(a) +*/ +double rtree_area_increase(HA_KEYSEG *keyseg, uchar* a, uchar* b, + uint key_length, double *ab_area) +{ + double a_area = 1; + + *ab_area = 1; + for (; (int)key_length > 0; keyseg += 2) + { + key_length -= keyseg->length * 2; + + /* Handle NULL part */ + if (keyseg->null_bit) + { + return -1; + } + + switch ((enum ha_base_keytype) keyseg->type) { + case HA_KEYTYPE_TEXT: + case HA_KEYTYPE_BINARY: + case HA_KEYTYPE_VARTEXT: + case HA_KEYTYPE_VARBINARY: + case HA_KEYTYPE_NUM: + default: + return 1; + break; + case HA_KEYTYPE_INT8: + { + int amin, amax, bmin, bmax; + amin = (int)*((signed char *)a); + bmin = (int)*((signed char *)b); + p_inc(a, b, 1); + amax = (int)*((signed char *)a); + bmax = (int)*((signed char *)b); + p_inc(a, b, 1); + a_area *= (((double)amax) - ((double)amin)); + *ab_area *= ((double)max(amax, bmax) - (double)min(amin, bmin)); + break; + } + case HA_KEYTYPE_SHORT_INT: + RT_AREA_INC_KORR(int16, mi_sint2korr, 2); + case HA_KEYTYPE_USHORT_INT: + RT_AREA_INC_KORR(uint16, mi_uint2korr, 2); + case HA_KEYTYPE_INT24: + RT_AREA_INC_KORR(int32, mi_sint3korr, 3); + case HA_KEYTYPE_UINT24: + RT_AREA_INC_KORR(int32, mi_uint3korr, 3); + case HA_KEYTYPE_LONG_INT: + RT_AREA_INC_KORR(int32, mi_sint4korr, 4); + case HA_KEYTYPE_ULONG_INT: + RT_AREA_INC_KORR(uint32, mi_uint4korr, 4); +#ifdef HAVE_LONG_LONG + case HA_KEYTYPE_LONGLONG: + RT_AREA_INC_KORR(longlong, mi_sint8korr, 8); + case HA_KEYTYPE_ULONGLONG: + RT_AREA_INC_KORR(ulonglong, mi_uint8korr, 8); +#endif + case HA_KEYTYPE_FLOAT: + RT_AREA_INC_GET(float, mi_float4get, 4); + case HA_KEYTYPE_DOUBLE: + RT_AREA_INC_GET(double, mi_float8get, 8); + case HA_KEYTYPE_END: + return *ab_area - a_area; + } + } + return *ab_area - a_area; +} + +#define RT_PAGE_MBR_KORR(type, korr_func, store_func, len) \ +{ \ + type amin, amax, bmin, bmax; \ + amin = korr_func(k + inc); \ + amax = korr_func(k + inc + len); \ + k = rt_PAGE_NEXT_KEY(k, k_len, nod_flag); \ + for (; k < last; k = rt_PAGE_NEXT_KEY(k, k_len, nod_flag)) \ +{ \ + bmin = korr_func(k + inc); \ + bmax = korr_func(k + inc + len); \ + if (amin > bmin) \ + amin = bmin; \ + if (amax < bmax) \ + amax = bmax; \ +} \ + store_func(c, amin); \ + c += len; \ + store_func(c, amax); \ + c += len; \ + inc += 2 * len; \ + break; \ +} + +#define RT_PAGE_MBR_GET(type, get_func, store_func, len) \ +{ \ + type amin, amax, bmin, bmax; \ + get_func(amin, k + inc); \ + get_func(amax, k + inc + len); \ + k = rt_PAGE_NEXT_KEY(k, k_len, nod_flag); \ + for (; k < last; k = rt_PAGE_NEXT_KEY(k, k_len, nod_flag)) \ +{ \ + get_func(bmin, k + inc); \ + get_func(bmax, k + inc + len); \ + if (amin > bmin) \ + amin = bmin; \ + if (amax < bmax) \ + amax = bmax; \ +} \ + store_func(c, amin); \ + c += len; \ + store_func(c, amax); \ + c += len; \ + inc += 2 * len; \ + break; \ +} + +/* +Calculates key page total MBR = MBR(key1) + MBR(key2) + ... +*/ +int rtree_page_mbr(MI_INFO *info, HA_KEYSEG *keyseg, uchar *page_buf, + uchar *c, uint key_length) +{ + uint inc = 0; + uint k_len = key_length; + uint nod_flag = mi_test_if_nod(page_buf); + uchar *k; + uchar *last = rt_PAGE_END(page_buf); + + for (; (int)key_length > 0; keyseg += 2) + { + key_length -= keyseg->length * 2; + + /* Handle NULL part */ + if (keyseg->null_bit) + { + return 1; + } + + k = rt_PAGE_FIRST_KEY(page_buf, nod_flag); + + switch ((enum ha_base_keytype) keyseg->type) { + case HA_KEYTYPE_TEXT: + case HA_KEYTYPE_BINARY: + case HA_KEYTYPE_VARTEXT: + case HA_KEYTYPE_VARBINARY: + case HA_KEYTYPE_NUM: + default: + return 1; + break; + case HA_KEYTYPE_INT8: + { + int amin, amax, bmin, bmax; + amin = (int)*((signed char *)(k + inc)); + amax = (int)*((signed char *)(k + inc + 1)); + k = rt_PAGE_NEXT_KEY(k, k_len, nod_flag); + for (; k < last; k = rt_PAGE_NEXT_KEY(k, k_len, nod_flag)) + { + bmin = (int)*((signed char *)(k + inc)); + bmax = (int)*((signed char *)(k + inc + 1)); + + if (amin > bmin) + amin = bmin; + if (amax < bmax) + amax = bmax; + } + *((signed char*)c) = amin; + c += 1; + *((signed char*)c) = amax; + c += 1; + inc += 1 * 2; + break; + } + case HA_KEYTYPE_SHORT_INT: + RT_PAGE_MBR_KORR(int16, mi_sint2korr, mi_int2store, 2); + case HA_KEYTYPE_USHORT_INT: + RT_PAGE_MBR_KORR(uint16, mi_uint2korr, mi_int2store, 2); + case HA_KEYTYPE_INT24: + RT_PAGE_MBR_KORR(int32, mi_sint3korr, mi_int3store, 3); + case HA_KEYTYPE_UINT24: + RT_PAGE_MBR_KORR(uint32, mi_uint3korr, mi_int3store, 3); + case HA_KEYTYPE_LONG_INT: + RT_PAGE_MBR_KORR(int32, mi_sint4korr, mi_int4store, 4); + case HA_KEYTYPE_ULONG_INT: + RT_PAGE_MBR_KORR(uint32, mi_uint4korr, mi_int4store, 4); +#ifdef HAVE_LONG_LONG + case HA_KEYTYPE_LONGLONG: + RT_PAGE_MBR_KORR(longlong, mi_sint8korr, mi_int8store, 8); + case HA_KEYTYPE_ULONGLONG: + RT_PAGE_MBR_KORR(ulonglong, mi_uint8korr, mi_int8store, 8); +#endif + case HA_KEYTYPE_FLOAT: + RT_PAGE_MBR_GET(float, mi_float4get, mi_float4store, 4); + case HA_KEYTYPE_DOUBLE: + RT_PAGE_MBR_GET(double, mi_float8get, mi_float8store, 8); + case HA_KEYTYPE_END: + return 0; + } + } + return 0; +} diff --git a/myisam/rt_mbr.h b/myisam/rt_mbr.h new file mode 100644 index 00000000000..a68807370f9 --- /dev/null +++ b/myisam/rt_mbr.h @@ -0,0 +1,33 @@ +/* Copyright (C) 2000 MySQL AB & Ramil Kalimullin & 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 */ + +#ifndef _rt_mbr_h +#define _rt_mbr_h + +int rtree_key_cmp(HA_KEYSEG *keyseg, uchar *a, uchar *b, uint key_length, + uint nextflag); +int rtree_combine_rect(HA_KEYSEG *keyseg,uchar *, uchar *, uchar*, + uint key_length); +double rtree_rect_volume(HA_KEYSEG *keyseg, uchar*, uint key_length); +int rtree_d_mbr(HA_KEYSEG *keyseg, uchar *a, uint key_length, double *res); +double rtree_overlapping_area(HA_KEYSEG *keyseg, uchar *a, uchar *b, + uint key_length); +double rtree_area_increase(HA_KEYSEG *keyseg, uchar *a, uchar *b, + uint key_length, double *ab_area); +int rtree_page_mbr(MI_INFO *info, HA_KEYSEG *keyseg, uchar *page_buf, + uchar* c, uint key_length); +#endif /* _rt_mbr_h */ diff --git a/myisam/rt_split.c b/myisam/rt_split.c new file mode 100644 index 00000000000..3363bbe2d9b --- /dev/null +++ b/myisam/rt_split.c @@ -0,0 +1,343 @@ +/* Copyright (C) 2000 MySQL AB & Alexey Botchkov & 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 */ + +#include "myisamdef.h" + +#include "rt_index.h" +#include "rt_key.h" +#include "rt_mbr.h" + +typedef struct +{ + double square; + int n_node; + uchar *key; + double *coords; +} SplitStruct; + +inline static double *reserve_coords(double **d_buffer, int n_dim) +{ + double *coords = *d_buffer; + (*d_buffer) += n_dim * 2; + return coords; +} + +static void mbr_join(double *a, const double *b, int n_dim) +{ + double *end = a + n_dim * 2; + do + { + if (a[0] > b[0]) + a[0] = b[0]; + + if (a[1] < b[1]) + a[1] = b[1]; + + a += 2; + b += 2; + }while (a != end); +} + +/* +Counts the square of mbr which is a join of a and b +*/ +static double mbr_join_square(const double *a, const double *b, int n_dim) +{ + const double *end = a + n_dim * 2; + double square = 1.0; + do + { + square *= + ((a[1] < b[1]) ? b[1] : a[1]) - ((a[0] > b[0]) ? b[0] : a[0]); + + a += 2; + b += 2; + }while (a != end); + + return square; +} + +static double count_square(const double *a, int n_dim) +{ + const double *end = a + n_dim * 2; + double square = 1.0; + do + { + square *= a[1] - a[0]; + a += 2; + }while (a != end); + return square; +} + +inline static void copy_coords(double *dst, const double *src, int n_dim) +{ + memcpy(dst, src, sizeof(double) * (n_dim * 2)); +} + +/* +Select two nodes to collect group upon +*/ +static void pick_seeds(SplitStruct *node, int n_entries, + SplitStruct **seed_a, SplitStruct **seed_b, int n_dim) +{ + SplitStruct *cur1; + SplitStruct *lim1 = node + (n_entries - 1); + SplitStruct *cur2; + SplitStruct *lim2 = node + n_entries; + + double max_d = -DBL_MAX; + double d; + + for (cur1 = node; cur1 < lim1; ++cur1) + { + for (cur2=cur1 + 1; cur2 < lim2; ++cur2) + { + + d = mbr_join_square(cur1->coords, cur2->coords, n_dim) - cur1->square - + cur2->square; + if (d > max_d) + { + max_d = d; + *seed_a = cur1; + *seed_b = cur2; + } + } + } +} + +/* +Select next node and group where to add +*/ +static void pick_next(SplitStruct *node, int n_entries, double *g1, double *g2, + SplitStruct **choice, int *n_group, int n_dim) +{ + SplitStruct *cur = node; + SplitStruct *end = node + n_entries; + + double max_diff = -DBL_MAX; + + for (; cur<end; ++cur) + { + double diff; + double abs_diff; + + if (cur->n_node) + { + continue; + } + + diff = mbr_join_square(g1, cur->coords, n_dim) - + mbr_join_square(g2, cur->coords, n_dim); + + abs_diff = fabs(diff); + if (abs_diff > max_diff) + { + max_diff = abs_diff; + *n_group = 1 + (diff > 0); + *choice = cur; + } + } +} + +/* +Mark not-in-group entries as n_group +*/ +static void mark_all_entries(SplitStruct *node, int n_entries, int n_group) +{ + SplitStruct *cur = node; + SplitStruct *end = node + n_entries; + for (; cur<end; ++cur) + { + if (cur->n_node) + { + continue; + } + cur->n_node = n_group; + } +} + +static int split_rtree_node(SplitStruct *node, int n_entries, + int all_size, /* Total key's size */ + int key_size, + int min_size, /* Minimal group size */ + int size1, int size2 /* initial group sizes */, + double **d_buffer, int n_dim) +{ + SplitStruct *cur; + SplitStruct *a; + SplitStruct *b; + double *g1 = reserve_coords(d_buffer, n_dim); + double *g2 = reserve_coords(d_buffer, n_dim); + SplitStruct *next; + int next_node; + int i; + SplitStruct *end = node + n_entries; + + if (all_size < min_size * 2) + { + return 1; + } + + cur = node; + for (; cur<end; ++cur) + { + cur->square = count_square(cur->coords, n_dim); + cur->n_node = 0; + } + + pick_seeds(node, n_entries, &a, &b, n_dim); + a->n_node = 1; + b->n_node = 2; + + + copy_coords(g1, a->coords, n_dim); + size1 += key_size; + copy_coords(g2, b->coords, n_dim); + size2 += key_size; + + + for (i=n_entries - 2; i>0; --i) + { + if (all_size - (size2 + key_size) < min_size) /* Can't write into group 2 */ + { + mark_all_entries(node, n_entries, 1); + break; + } + + if (all_size - (size1 + key_size) < min_size) /* Can't write into group 1 */ + { + mark_all_entries(node, n_entries, 2); + break; + } + + pick_next(node, n_entries, g1, g2, &next, &next_node, n_dim); + if (next_node == 1) + { + size1 += key_size; + mbr_join(g1, next->coords, n_dim); + } + else + { + size2 += key_size; + mbr_join(g2, next->coords, n_dim); + } + next->n_node = next_node; + } + + return 0; +} + +int rtree_split_page(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *page, uchar *key, + uint key_length, my_off_t *new_page_offs) +{ + int n1, n2; /* Number of items in groups */ + + SplitStruct *task; + SplitStruct *cur; + SplitStruct *stop; + double *coord_buf; + double *next_coord; + double *old_coord; + int n_dim; + uchar *source_cur, *cur1, *cur2; + uchar *new_page; + int err_code = 0; + + uint nod_flag = mi_test_if_nod(page); + uint full_length = key_length + (nod_flag ? nod_flag : + info->s->base.rec_reflength); + + int max_keys = (mi_getint(page)-2) / (full_length); + + n_dim = (keyinfo->keysegs-1) / 2; + + { + int coord_buf_size = n_dim * 2 * sizeof(double) * (max_keys + 1 + 4); + coord_buf = + my_alloca(coord_buf_size + sizeof(SplitStruct) * (max_keys + 1)); + + task = (SplitStruct *)(((char *)coord_buf) + coord_buf_size); + } + next_coord = coord_buf; + + stop = task + max_keys; + source_cur = rt_PAGE_FIRST_KEY(page, nod_flag); + + for (cur = task; cur < stop; ++cur, source_cur = rt_PAGE_NEXT_KEY(source_cur, + key_length, nod_flag)) + { + cur->coords = reserve_coords(&next_coord, n_dim); + cur->key = source_cur; + rtree_d_mbr(keyinfo->seg, source_cur, key_length, cur->coords); + } + + cur->coords = reserve_coords(&next_coord, n_dim); + rtree_d_mbr(keyinfo->seg, key, key_length, cur->coords); + cur->key = key; + + old_coord = next_coord; + + if (split_rtree_node(task, max_keys + 1, + mi_getint(page) + full_length + 2, full_length, + rt_PAGE_MIN_SIZE(keyinfo->block_length), + 2, 2, &next_coord, n_dim)) + { + err_code = 1; + goto split_err; + } + + if (!(new_page = (uchar*)my_alloca((uint)keyinfo->block_length))) + return -1; + + stop = task + (max_keys + 1); + cur1 = rt_PAGE_FIRST_KEY(page, nod_flag); + cur2 = rt_PAGE_FIRST_KEY(new_page, nod_flag); + + n1 = 0; + n2 = 0; + for (cur = task; cur < stop; ++cur) + { + uchar *to; + if (cur->n_node == 1) + { + to = cur1; + cur1 = rt_PAGE_NEXT_KEY(cur1, key_length, nod_flag); + ++n1; + } + else + { + to = cur2; + cur2 = rt_PAGE_NEXT_KEY(cur2, key_length, nod_flag); + ++n2; + } + memcpy(to - nod_flag, cur->key - nod_flag, full_length); + } + + mi_putint(page, 2 + n1 * full_length, nod_flag); + mi_putint(new_page, 2 + n2 * full_length, nod_flag); + + *new_page_offs=_mi_new(info, keyinfo); + _mi_write_keypage(info, keyinfo, *new_page_offs, new_page); + my_afree((byte*)new_page); + +split_err: + my_afree((byte*)coord_buf); + return err_code; +} + + + diff --git a/myisam/rt_test.c b/myisam/rt_test.c new file mode 100644 index 00000000000..4cc60d63031 --- /dev/null +++ b/myisam/rt_test.c @@ -0,0 +1,417 @@ +/* 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 */ + +/* Testing of the basic functions of a MyISAM rtree table */ +/* Written by Alex Barkov who has a shared copyright to this code */ + + +#include "myisam.h" +#include "rt_index.h" + +#define MAX_REC_LENGTH 1024 +#define ndims 2 +#define KEYALG HA_KEY_ALG_RTREE + +static int read_with_pos(MI_INFO * file, int silent); +static void create_record(char *record,uint rownr); +static void create_record1(char *record,uint rownr); +static void print_record(char * record,my_off_t offs,const char * tail); +static int run_test(const char *filename); + + +int main(int argc,char *argv[]) +{ + MY_INIT(argv[0]); + exit(run_test("rt_test")); +} + + + +int run_test(const char *filename) +{ + MI_INFO *file; + MI_UNIQUEDEF uniquedef; + MI_CREATE_INFO create_info; + MI_COLUMNDEF recinfo[20]; + MI_KEYDEF keyinfo[20]; + HA_KEYSEG keyseg[20]; + + int silent=0; + int opt_unique=0; + int create_flag=0; + int key_type=HA_KEYTYPE_DOUBLE; + int key_length=8; + int null_fields=0; + int nrecords=30; + int rec_length=0; + int uniques=0; + int i; + int error; + int row_count=0; + char record[MAX_REC_LENGTH]; + char read_record[MAX_REC_LENGTH]; + int upd=10; + ha_rows hrows; + + + + /* Define a column for NULLs and DEL markers*/ + + recinfo[0].type=FIELD_NORMAL; + recinfo[0].length=1; /* For NULL bits */ + rec_length=1; + + + /* Define 2*ndims columns for coordinates*/ + + for (i=1; i<=2*ndims ;i++){ + recinfo[i].type=FIELD_NORMAL; + recinfo[i].length=key_length; + rec_length+=key_length; + } + + + /* Define a key with 2*ndims segments */ + + keyinfo[0].seg=keyseg; + keyinfo[0].keysegs=2*ndims; + keyinfo[0].flag=0; + keyinfo[0].key_alg=KEYALG; + + for (i=0; i<2*ndims; i++){ + keyinfo[0].seg[i].type= key_type; + keyinfo[0].seg[i].flag=0; /* Things like HA_REVERSE_SORT */ + keyinfo[0].seg[i].start= (key_length*i)+1; + keyinfo[0].seg[i].length=key_length; + keyinfo[0].seg[i].null_bit= null_fields ? 2 : 0; + keyinfo[0].seg[i].null_pos=0; + keyinfo[0].seg[i].language=MY_CHARSET_CURRENT; + } + + + if(!silent) + printf("- Creating isam-file\n"); + + bzero((char*) &create_info,sizeof(create_info)); + create_info.max_rows=10000000; + + if (mi_create(filename, + 1, /* keys */ + keyinfo, + 1+2*ndims+opt_unique, /* columns */ + recinfo,uniques,&uniquedef,&create_info,create_flag)) + goto err; + + + + + if(!silent) + printf("- Open isam-file\n"); + + if (!(file=mi_open(filename,2,HA_OPEN_ABORT_IF_LOCKED))) + goto err; + + + if (!silent) + printf("- Writing key:s\n"); + + for (i=0; i<nrecords; i++ ) + { + create_record(record,i); + error=mi_write(file,record); + print_record(record,mi_position(file),"\n"); + if (!error) + { + row_count++; + } + else + { + printf("mi_write: %d\n", error); + goto err; + } + } + + + if((error=read_with_pos(file,silent))) + goto err; + + + if (!silent) + printf("- Reading rows with key\n"); + + for (i=0 ; i < nrecords ; i++) + { + my_errno=0; + create_record(record,i); + + bzero((char*) read_record,MAX_REC_LENGTH); + error=mi_rkey(file,read_record,0,record+1,0,HA_READ_MBR_EQUAL); + + if(error && error!=HA_ERR_KEY_NOT_FOUND) + { + printf(" mi_rkey: %3d errno: %3d\n",error,my_errno); + goto err; + } + if(error == HA_ERR_KEY_NOT_FOUND) + { + print_record(record,mi_position(file)," NOT FOUND\n"); + continue; + } + print_record(read_record,mi_position(file),"\n"); + } + + + + + + if (!silent) + printf("- Deleting rows\n"); + for (i=0; i < nrecords/4; i++) + { + my_errno=0; + bzero((char*) read_record,MAX_REC_LENGTH); + error=mi_rrnd(file,read_record,i == 0 ? 0L : HA_OFFSET_ERROR); + if(error) + { + printf("pos: %2d mi_rrnd: %3d errno: %3d\n",i,error,my_errno); + goto err; + } + print_record(read_record,mi_position(file),"\n"); + + error=mi_delete(file,read_record); + if(error) + { + printf("pos: %2d mi_delete: %3d errno: %3d\n",i,error,my_errno); + goto err; + } + } + +/* + + if (!silent) + printf("- Updating rows with position\n"); + for (i=0; i < (nrecords - nrecords/4) ; i++) + { + my_errno=0; + bzero((char*) read_record,MAX_REC_LENGTH); + error=mi_rrnd(file,read_record,i == 0 ? 0L : HA_OFFSET_ERROR); + if(error) + { + if(error==HA_ERR_RECORD_DELETED) + continue; + printf("pos: %2d mi_rrnd: %3d errno: %3d\n",i,error,my_errno); + goto err; + } + print_record(read_record,mi_position(file),""); + create_record(record,i+nrecords*upd); + printf("\t-> "); + print_record(record,mi_position(file),"\n"); + error=mi_update(file,read_record,record); + if(error) + { + printf("pos: %2d mi_update: %3d errno: %3d\n",i,error,my_errno); + goto err; + } + } + +*/ + + + if((error=read_with_pos(file,silent))) + goto err; + + + + if (!silent) + printf("- Test mi_rkey then a sequence of mi_rnext_same\n"); + + create_record(record, nrecords*4/5); + print_record(record,0," search for\n"); + + if ((error=mi_rkey(file,read_record,0,record+1,0,HA_READ_MBR_INTERSECT))) + { + printf("mi_rkey: %3d errno: %3d\n",error,my_errno); + goto err; + } + print_record(read_record,mi_position(file)," mi_rkey\n"); + row_count=1; + + + do { + if((error=mi_rnext_same(file,read_record))) + { + if(error==HA_ERR_END_OF_FILE) + break; + printf("mi_next: %3d errno: %3d\n",error,my_errno); + goto err; + } + print_record(read_record,mi_position(file)," mi_rnext_same\n"); + row_count++; + }while(1); + printf(" %d rows\n",row_count); + + + + + + + if (!silent) + printf("- Test mi_rfirst then a sequence of mi_rnext\n"); + + error=mi_rfirst(file,read_record,0); + if (error) + { + printf("mi_rfirst: %3d errno: %3d\n",error,my_errno); + goto err; + } + row_count=1; + print_record(read_record,mi_position(file)," mi_frirst\n"); + + for(i=0;i<nrecords;i++) { + if((error=mi_rnext(file,read_record,0))) + { + if(error==HA_ERR_END_OF_FILE) + break; + printf("mi_next: %3d errno: %3d\n",error,my_errno); + goto err; + } + print_record(read_record,mi_position(file)," mi_rnext\n"); + row_count++; + } + printf(" %d rows\n",row_count); + + + if (!silent) + printf("- Test mi_records_in_range()\n"); + + create_record1(record, nrecords*4/5); + print_record(record,0,"\n"); + hrows=mi_records_in_range(file,0,record+1,0,HA_READ_MBR_INTERSECT,record+1,0,0); + printf(" %ld rows\n",hrows); + + + if (mi_close(file)) goto err; + my_end(MY_CHECK_ERROR); + + return 0; + +err: + printf("got error: %3d when using myisam-database\n",my_errno); + return 1; /* skipp warning */ +} + + + +static int read_with_pos (MI_INFO * file,int silent) +{ + int error; + int i; + char read_record[MAX_REC_LENGTH]; + + if (!silent) + printf("- Reading rows with position\n"); + for (i=0;;i++) + { + my_errno=0; + bzero((char*) read_record,MAX_REC_LENGTH); + error=mi_rrnd(file,read_record,i == 0 ? 0L : HA_OFFSET_ERROR); + if(error) + { + if(error==HA_ERR_END_OF_FILE) + break; + if(error==HA_ERR_RECORD_DELETED) + continue; + printf("pos: %2d mi_rrnd: %3d errno: %3d\n",i,error,my_errno); + return error; + } + print_record(read_record,mi_position(file),"\n"); + } + return 0; +} + + +static void bprint_record(char * record, my_off_t offs,const char * tail) +{ + int i; + char * pos; + i=(unsigned char)record[0]; + printf("%02X ",i); + + for( pos=record+1, i=0; i<32; i++,pos++){ + int b=(unsigned char)*pos; + printf("%02X",b); + } + printf("%s",tail); +} + +static void print_record(char * record, my_off_t offs,const char * tail) +{ + int i; + char * pos; + double c; + + printf(" rec=(%d)",(unsigned char)record[0]); + for ( pos=record+1, i=0; i<2*ndims; i++) + { + memcpy(&c,pos,sizeof(c)); + float8get(c,pos); + printf(" %.14g ",c); + pos+=sizeof(c); + } + printf("pos=%ld",(long int)offs); + printf("%s",tail); +} + + + +static void create_record1(char *record,uint rownr) +{ + int i; + char * pos; + double c=rownr+10; + + bzero((char*) record,MAX_REC_LENGTH); + record[0]=0x01; /* DEL marker */ + + for ( pos=record+1, i=0; i<2*ndims; i++) + { + memcpy(pos,&c,sizeof(c)); + float8store(pos,c); + pos+=sizeof(c); + } +} + + +static void create_record(char *record,uint rownr) +{ + int i; + char * pos; + double c=rownr+10; + double c0=0; + + bzero((char*) record,MAX_REC_LENGTH); + record[0]=0x01; /* DEL marker */ + + for ( pos=record+1, i=0; i<ndims; i++) + { + memcpy(pos,&c0,sizeof(c0)); + float8store(pos,c0); + pos+=sizeof(c0); + memcpy(pos,&c,sizeof(c)); + float8store(pos,c); + pos+=sizeof(c); + } +} diff --git a/myisam/sp_defs.h b/myisam/sp_defs.h new file mode 100644 index 00000000000..0acefe32f80 --- /dev/null +++ b/myisam/sp_defs.h @@ -0,0 +1,45 @@ +/* Copyright (C) 2000 MySQL AB & Ramil Kalimullin & 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 */ + +#ifndef _SP_DEFS_H +#define _SP_DEFS_H + +#define SPDIMS 2 +#define SPTYPE HA_KEYTYPE_DOUBLE +#define SPLEN 8 + +enum wkbType +{ + wkbPoint = 1, + wkbLineString = 2, + wkbPolygon = 3, + wkbMultiPoint = 4, + wkbMultiLineString = 5, + wkbMultiPolygon = 6, + wkbGeometryCollection = 7 +}; + +enum wkbByteOrder +{ + wkbXDR = 0, /* Big Endian */ + wkbNDR = 1 /* Little Endian */ +}; + +uint sp_make_key(register MI_INFO *info, uint keynr, uchar *key, + const byte *record, my_off_t filepos); + +#endif /* _SP_DEFS_H */ diff --git a/myisam/sp_key.c b/myisam/sp_key.c new file mode 100644 index 00000000000..2ab11f993c3 --- /dev/null +++ b/myisam/sp_key.c @@ -0,0 +1,256 @@ +/* Copyright (C) 2000 MySQL AB & Ramil Kalimullin & 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 */ + +#include "myisamdef.h" +#include "sp_defs.h" + +static int sp_add_point_to_mbr(uchar *(*wkb), uchar *end, uint n_dims, + uchar byte_order, double *mbr); +static int sp_get_point_mbr(uchar *(*wkb), uchar *end, uint n_dims, + uchar byte_order, double *mbr); +static int sp_get_linestring_mbr(uchar *(*wkb), uchar *end, uint n_dims, + uchar byte_order, double *mbr); +static int sp_get_polygon_mbr(uchar *(*wkb), uchar *end, uint n_dims, + uchar byte_order, double *mbr); +static int sp_get_geometry_mbr(uchar *(*wkb), uchar *end, uint n_dims, + double *mbr, int top); +static int sp_mbr_from_wkb(uchar (*wkb), uint size, uint n_dims, double *mbr); + +uint sp_make_key(register MI_INFO *info, uint keynr, uchar *key, + const byte *record, my_off_t filepos) +{ + HA_KEYSEG *keyseg; + MI_KEYDEF *keyinfo = &info->s->keyinfo[keynr]; + uint len = 0; + byte *pos; + uint dlen; + uchar *dptr; + double mbr[SPDIMS * 2]; + uint i; + + keyseg = &keyinfo->seg[-1]; + pos = (byte*)record + keyseg->start; + + dlen = _mi_calc_blob_length(keyseg->bit_start, pos); + memcpy_fixed(&dptr, pos + keyseg->bit_start, sizeof(char*)); + sp_mbr_from_wkb(dptr, dlen, SPDIMS, mbr); + + for (i = 0, keyseg = keyinfo->seg; keyseg->type; keyseg++, i++) + { + uint length = keyseg->length; + + pos = ((byte*)mbr) + keyseg->start; + if (keyseg->flag & HA_SWAP_KEY) + { + pos += length; + while (length--) + { + *key++ = *--pos; + } + } + else + { + memcpy((byte*)key, pos, length); + key += keyseg->length; + } + len += keyseg->length; + } + _mi_dpointer(info, key, filepos); + return len; +} + +/* +Calculate minimal bounding rectangle (mbr) of the spatial object +stored in "well-known binary representation" (wkb) format. +*/ +static int sp_mbr_from_wkb(uchar *wkb, uint size, uint n_dims, double *mbr) +{ + uint i; + + for (i=0; i < n_dims; ++i) + { + mbr[i * 2] = DBL_MAX; + mbr[i * 2 + 1] = -DBL_MAX; + } + + return sp_get_geometry_mbr(&wkb, wkb + size, n_dims, mbr, 1); +} + +/* +Add one point stored in wkb to mbr +*/ +static int sp_add_point_to_mbr(uchar *(*wkb), uchar *end, uint n_dims, + uchar byte_order, double *mbr) +{ + double ord; + double *mbr_end = mbr + n_dims * 2; + + while (mbr < mbr_end) + { + if ((*wkb) > end - 8) + return -1; + float8get(ord, (*wkb)); + (*wkb) += 8; + if (ord < *mbr) + *mbr = ord; + mbr++; + if (ord > *mbr) + *mbr = ord; + mbr++; + } + return 0; +} + +static int sp_get_point_mbr(uchar *(*wkb), uchar *end, uint n_dims, + uchar byte_order, double *mbr) +{ + return sp_add_point_to_mbr(wkb, end, n_dims, byte_order, mbr); +} + +static int sp_get_linestring_mbr(uchar *(*wkb), uchar *end, uint n_dims, + uchar byte_order, double *mbr) +{ + uint n_points; + + n_points = uint4korr(*wkb); + (*wkb) += 4; + for (; n_points > 0; --n_points) + { + /* Add next point to mbr */ + if (sp_add_point_to_mbr(wkb, end, n_dims, byte_order, mbr)) + return -1; + } + return 0; +} + +static int sp_get_polygon_mbr(uchar *(*wkb), uchar *end, uint n_dims, + uchar byte_order, double *mbr) +{ + uint n_linear_rings; + uint n_points; + + n_linear_rings = uint4korr((*wkb)); + (*wkb) += 4; + + for (; n_linear_rings > 0; --n_linear_rings) + { + n_points = uint4korr((*wkb)); + (*wkb) += 4; + for (; n_points > 0; --n_points) + { + /* Add next point to mbr */ + if (sp_add_point_to_mbr(wkb, end, n_dims, byte_order, mbr)) + return -1; + } + } + return 0; +} + +static int sp_get_geometry_mbr(uchar *(*wkb), uchar *end, uint n_dims, + double *mbr, int top) +{ + int res; + uchar byte_order; + uint wkb_type; + + byte_order = *(*wkb); + ++(*wkb); + + wkb_type = uint4korr((*wkb)); + (*wkb) += 4; + + switch ((enum wkbType) wkb_type) + { + case wkbPoint: + res = sp_get_point_mbr(wkb, end, n_dims, byte_order, mbr); + break; + case wkbLineString: + res = sp_get_linestring_mbr(wkb, end, n_dims, byte_order, mbr); + break; + case wkbPolygon: + res = sp_get_polygon_mbr(wkb, end, n_dims, byte_order, mbr); + break; + case wkbMultiPoint: + { + uint n_items; + n_items = uint4korr((*wkb)); + (*wkb) += 4; + for (; n_items > 0; --n_items) + { + byte_order = *(*wkb); + ++(*wkb); + (*wkb) += 4; + if (sp_get_point_mbr(wkb, end, n_dims, byte_order, mbr)) + return -1; + } + res = 0; + break; + } + case wkbMultiLineString: + { + uint n_items; + n_items = uint4korr((*wkb)); + (*wkb) += 4; + for (; n_items > 0; --n_items) + { + byte_order = *(*wkb); + ++(*wkb); + (*wkb) += 4; + if (sp_get_linestring_mbr(wkb, end, n_dims, byte_order, mbr)) + return -1; + } + res = 0; + break; + } + case wkbMultiPolygon: + { + uint n_items; + n_items = uint4korr((*wkb)); + (*wkb) += 4; + for (; n_items > 0; --n_items) + { + byte_order = *(*wkb); + ++(*wkb); + (*wkb) += 4; + if (sp_get_polygon_mbr(wkb, end, n_dims, byte_order, mbr)) + return -1; + } + res = 0; + break; + } + case wkbGeometryCollection: + { + uint n_items; + + if (!top) + return -1; + + n_items = uint4korr((*wkb)); + (*wkb) += 4; + for (; n_items > 0; --n_items) + { + if (sp_get_geometry_mbr(wkb, end, n_dims, mbr, 0)) + return -1; + } + res = 0; + break; + } + default: + res = -1; + } + return res; +} diff --git a/myisam/sp_test.c b/myisam/sp_test.c new file mode 100644 index 00000000000..9d32b3e623d --- /dev/null +++ b/myisam/sp_test.c @@ -0,0 +1,565 @@ +/* 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 */ + +/* Testing of the basic functions of a MyISAM spatial table */ +/* Written by Alex Barkov, who has a shared copyright to this code */ + +#include "myisam.h" +#include "sp_defs.h" + +#define MAX_REC_LENGTH 1024 +#define KEYALG HA_KEY_ALG_RTREE + +static void create_point(char *record,uint rownr); +static void create_linestring(char *record,uint rownr); +static void print_record(char * record,my_off_t offs,const char * tail); + +static void create_key(char *key,uint rownr); +static void print_key(const char *key,const char * tail); + +static int run_test(const char *filename); +static int read_with_pos(MI_INFO * file, int silent); + +static int rtree_CreatePointWKB(double *ords, uint n_dims, uchar *wkb); +static int rtree_CreateLineStringWKB(double *ords, uint n_dims, uint n_points, uchar *wkb); +static void rtree_PrintWKB(uchar *wkb, uint n_dims); + + +static char blob_key[MAX_REC_LENGTH]; + + +int main(int argc,char *argv[]) +{ + MY_INIT(argv[0]); + exit(run_test("sp_test")); +} + + + +int run_test(const char *filename) +{ + MI_INFO *file; + MI_UNIQUEDEF uniquedef; + MI_CREATE_INFO create_info; + MI_COLUMNDEF recinfo[20]; + MI_KEYDEF keyinfo[20]; + HA_KEYSEG keyseg[20]; + + int silent=0; + int create_flag=0; + int null_fields=0; + int nrecords=30; + int uniques=0; + int i; + int error; + int row_count=0; + char record[MAX_REC_LENGTH]; + char key[MAX_REC_LENGTH]; + char read_record[MAX_REC_LENGTH]; + int upd=10; + ha_rows hrows; + + /* Define a column for NULLs and DEL markers*/ + + recinfo[0].type=FIELD_NORMAL; + recinfo[0].length=1; /* For NULL bits */ + + + /* Define spatial column */ + + recinfo[1].type=FIELD_BLOB; + recinfo[1].length=4 + mi_portable_sizeof_char_ptr; + + + + /* Define a key with 1 spatial segment */ + + keyinfo[0].seg=keyseg; + keyinfo[0].keysegs=1; + keyinfo[0].flag=HA_SPATIAL; + keyinfo[0].key_alg=KEYALG; + + keyinfo[0].seg[0].type= HA_KEYTYPE_BINARY; + keyinfo[0].seg[0].flag=0; + keyinfo[0].seg[0].start= 1; + keyinfo[0].seg[0].length=1; /* Spatial ignores it anyway */ + keyinfo[0].seg[0].null_bit= null_fields ? 2 : 0; + keyinfo[0].seg[0].null_pos=0; + keyinfo[0].seg[0].language=MY_CHARSET_CURRENT; + keyinfo[0].seg[0].bit_start=4; /* Long BLOB */ + + + if(!silent) + printf("- Creating isam-file\n"); + + bzero((char*) &create_info,sizeof(create_info)); + create_info.max_rows=10000000; + + if (mi_create(filename, + 1, /* keys */ + keyinfo, + 2, /* columns */ + recinfo,uniques,&uniquedef,&create_info,create_flag)) + goto err; + + + + + if(!silent) + printf("- Open isam-file\n"); + + if (!(file=mi_open(filename,2,HA_OPEN_ABORT_IF_LOCKED))) + goto err; + + + + if (!silent) + printf("- Writing key:s\n"); + + for (i=0; i<nrecords; i++ ) + { + create_linestring(record,i); + error=mi_write(file,record); + print_record(record,mi_position(file),"\n"); + if (!error) + { + row_count++; + } + else + { + printf("mi_write: %d\n", error); + goto err; + } + } + + + if((error=read_with_pos(file,silent))) + goto err; + + + if (!silent) + printf("- Deleting rows with position\n"); + for (i=0; i < nrecords/4; i++) + { + my_errno=0; + bzero((char*) read_record,MAX_REC_LENGTH); + error=mi_rrnd(file,read_record,i == 0 ? 0L : HA_OFFSET_ERROR); + if(error) + { + printf("pos: %2d mi_rrnd: %3d errno: %3d\n",i,error,my_errno); + goto err; + } + print_record(read_record,mi_position(file),"\n"); + error=mi_delete(file,read_record); + if(error) + { + printf("pos: %2d mi_delete: %3d errno: %3d\n",i,error,my_errno); + goto err; + } + } + + + + + if (!silent) + printf("- Updating rows with position\n"); + for (i=0; i < nrecords/2 ; i++) + { + my_errno=0; + bzero((char*) read_record,MAX_REC_LENGTH); + error=mi_rrnd(file,read_record,i == 0 ? 0L : HA_OFFSET_ERROR); + if(error) + { + if(error==HA_ERR_RECORD_DELETED) + continue; + printf("pos: %2d mi_rrnd: %3d errno: %3d\n",i,error,my_errno); + goto err; + } + print_record(read_record,mi_position(file),""); + create_linestring(record,i+nrecords*upd); + printf("\t-> "); + print_record(record,mi_position(file),"\n"); + error=mi_update(file,read_record,record); + if(error) + { + printf("pos: %2d mi_update: %3d errno: %3d\n",i,error,my_errno); + goto err; + } + } + + + + if((error=read_with_pos(file,silent))) + goto err; + + + + if (!silent) + printf("- Test mi_rkey then a sequence of mi_rnext_same\n"); + + create_key(key, nrecords*4/5); + print_key(key," search for INTERSECT\n"); + + if ((error=mi_rkey(file,read_record,0,key,0,HA_READ_MBR_INTERSECT))) + { + printf("mi_rkey: %3d errno: %3d\n",error,my_errno); + goto err; + } + print_record(read_record,mi_position(file)," mi_rkey\n"); + row_count=1; + + + do { + if((error=mi_rnext_same(file,read_record))) + { + if(error==HA_ERR_END_OF_FILE) + break; + printf("mi_next: %3d errno: %3d\n",error,my_errno); + goto err; + } + print_record(read_record,mi_position(file)," mi_rnext_same\n"); + row_count++; + }while(1); + printf(" %d rows\n",row_count); + + + + + + + if (!silent) + printf("- Test mi_rfirst then a sequence of mi_rnext\n"); + + error=mi_rfirst(file,read_record,0); + if (error) + { + printf("mi_rfirst: %3d errno: %3d\n",error,my_errno); + goto err; + } + row_count=1; + print_record(read_record,mi_position(file)," mi_frirst\n"); + + for(i=0;i<nrecords;i++) { + if((error=mi_rnext(file,read_record,0))) + { + if(error==HA_ERR_END_OF_FILE) + break; + printf("mi_next: %3d errno: %3d\n",error,my_errno); + goto err; + } + print_record(read_record,mi_position(file)," mi_rnext\n"); + row_count++; + } + printf(" %d rows\n",row_count); + + + + + if (!silent) + printf("- Test mi_records_in_range()\n"); + + create_key(key, nrecords*upd); + print_key(key," INTERSECT\n"); + hrows=mi_records_in_range(file,0,key,0,HA_READ_MBR_INTERSECT,record+1,0,0); + printf(" %ld rows\n",hrows); + + + if (mi_close(file)) goto err; + my_end(MY_CHECK_ERROR); + + return 0; + +err: + printf("got error: %3d when using myisam-database\n",my_errno); + return 1; /* skipp warning */ +} + + + +static int read_with_pos (MI_INFO * file,int silent) +{ + int error; + int i; + char read_record[MAX_REC_LENGTH]; + int rows=0; + + if (!silent) + printf("- Reading rows with position\n"); + for (i=0;;i++) + { + my_errno=0; + bzero((char*) read_record,MAX_REC_LENGTH); + error=mi_rrnd(file,read_record,i == 0 ? 0L : HA_OFFSET_ERROR); + if(error) + { + if(error==HA_ERR_END_OF_FILE) + break; + if(error==HA_ERR_RECORD_DELETED) + continue; + printf("pos: %2d mi_rrnd: %3d errno: %3d\n",i,error,my_errno); + return error; + } + rows++; + print_record(read_record,mi_position(file),"\n"); + } + printf(" %d rows\n",rows); + return 0; +} + + +static void bprint_record(char * record, my_off_t offs,const char * tail) +{ + int i; + char * pos; + i=(unsigned char)record[0]; + printf("%02X ",i); + + for( pos=record+1, i=0; i<32; i++,pos++){ + int b=(unsigned char)*pos; + printf("%02X",b); + } + printf("%s",tail); +} + +static void print_record(char * record, my_off_t offs,const char * tail) +{ + char *pos; + char *ptr; + uint len; + + printf(" rec=(%d)",(unsigned char)record[0]); + pos=record+1; + len=sint4korr(pos); + pos+=4; + printf(" len=%d ",len); + memcpy_fixed(&ptr,pos,sizeof(char*)); + if(ptr) + rtree_PrintWKB(ptr,SPDIMS); + else + printf("<NULL> "); + printf(" offs=%ld ",(long int)offs); + printf("%s",tail); +} + + + +static void create_point(char *record,uint rownr) +{ + uint tmp; + char *ptr; + char *pos=record; + double x[200]; + int i; + + for(i=0;i<SPDIMS;i++) + x[i]=rownr; + + bzero((char*) record,MAX_REC_LENGTH); + *pos=0x01; /* DEL marker */ + pos++; + + memset(blob_key,0,sizeof(blob_key)); + tmp=rtree_CreatePointWKB(x,SPDIMS,blob_key); + + int4store(pos,tmp); + pos+=4; + + ptr=blob_key; + memcpy_fixed(pos,&ptr,sizeof(char*)); +} + + +static void create_linestring(char *record,uint rownr) +{ + uint tmp; + char *ptr; + char *pos=record; + double x[200]; + int i,j; + int npoints=2; + + for(j=0;j<npoints;j++) + for(i=0;i<SPDIMS;i++) + x[i+j*SPDIMS]=rownr*j; + + bzero((char*) record,MAX_REC_LENGTH); + *pos=0x01; /* DEL marker */ + pos++; + + memset(blob_key,0,sizeof(blob_key)); + tmp=rtree_CreateLineStringWKB(x,SPDIMS,npoints,blob_key); + + int4store(pos,tmp); + pos+=4; + + ptr=blob_key; + memcpy_fixed(pos,&ptr,sizeof(char*)); +} + + +static void create_key(char *key,uint rownr) +{ + double c=rownr; + char *pos; + uint i; + + bzero(key,MAX_REC_LENGTH); + for ( pos=key, i=0; i<2*SPDIMS; i++) + { + float8store(pos,c); + pos+=sizeof(c); + } +} + +static void print_key(const char *key,const char * tail) +{ + double c; + uint i; + + printf(" key="); + for (i=0; i<2*SPDIMS; i++) + { + float8get(c,key); + key+=sizeof(c); + printf("%.14g ",c); + } + printf("%s",tail); +} + + + +static int rtree_CreatePointWKB(double *ords, uint n_dims, uchar *wkb) +{ + uint i; + + *wkb = wkbXDR; + ++wkb; + int4store(wkb, wkbPoint); + wkb += 4; + + for (i=0; i < n_dims; ++i) + { + float8store(wkb, ords[i]); + wkb += 8; + } + return 5 + n_dims * 8; +} + +static int rtree_CreateLineStringWKB(double *ords, uint n_dims, uint n_points, uchar *wkb) +{ + uint i; + uint n_ords = n_dims * n_points; + + *wkb = wkbXDR; + ++wkb; + int4store(wkb, wkbLineString); + wkb += 4; + int4store(wkb, n_points); + wkb += 4; + for (i=0; i < n_ords; ++i) + { + float8store(wkb, ords[i]); + wkb += 8; + } + return 9 + n_points * n_dims * 8; +} + +static void rtree_PrintWKB(uchar *wkb, uint n_dims) +{ + uint wkb_type; + + ++wkb; + wkb_type = uint4korr(wkb); + wkb += 4; + + switch ((enum wkbType)wkb_type) + { + case wkbPoint: + { + uint i; + double ord; + + printf("POINT("); + for (i=0; i < n_dims; ++i) + { + float8get(ord, wkb); + wkb += 8; + printf("%.14g", ord); + if (i < n_dims - 1) + printf(" "); + else + printf(")"); + } + break; + } + case wkbLineString: + { + uint p, i; + uint n_points; + double ord; + + printf("LineString("); + n_points = uint4korr(wkb); + wkb += 4; + for (p=0; p < n_points; ++p) + { + for (i=0; i < n_dims; ++i) + { + float8get(ord, wkb); + wkb += 8; + printf("%.14g", ord); + if (i < n_dims - 1) + printf(" "); + } + if (p < n_points - 1) + printf(", "); + else + printf(")"); + } + break; + } + case wkbPolygon: + { + printf("POLYGON(...)"); + break; + } + case wkbMultiPoint: + { + printf("MULTIPOINT(...)"); + break; + } + case wkbMultiLineString: + { + printf("MULTILINESTRING(...)"); + break; + } + case wkbMultiPolygon: + { + printf("MULTIPOLYGON(...)"); + break; + } + case wkbGeometryCollection: + { + printf("GEOMETRYCOLLECTION(...)"); + break; + } + default: + { + printf("UNKNOWN GEOMETRY TYPE"); + break; + } + } +} |