Commit b7d7ce3d authored by monty@work.mysql.com's avatar monty@work.mysql.com

Merge work.mysql.com:/home/bk/mysql-4.0

into work.mysql.com:/home/bk/mysql-4.1
parents 8a4b1298 9421897b
......@@ -5,6 +5,7 @@ Miguel@light.local
Sinisa@sinisa.nasamreza.org
ahlentz@co3064164-a.rochd1.qld.optusnet.com.au
arjen@co3064164-a.bitbike.com
bar@gw.udmsearch.izhnet.ru
bell@sanja.is.com.ua
davida@isil.mysql.com
heikki@donna.mysql.fi
......
......@@ -25,10 +25,10 @@ then
echo "Commit successful, notifying developers at $TO"
(
cat <<EOF
List-ID: <bk.mysql-4.0>
List-ID: <bk.mysql-4.1>
From: $FROM
To: $TO
Subject: bk commit - 4.0 tree
Subject: bk commit - 4.1 tree
EOF
bk changes -v -r+
......@@ -41,13 +41,13 @@ EOF
echo "Notifying internals list at $INTERNALS"
(
cat <<EOF
List-ID: <bk.mysql-4.0>
List-ID: <bk.mysql-4.1>
From: $FROM
To: $INTERNALS
Subject: bk commit into 4.0 tree
Subject: bk commit into 4.1 tree
Below is the list of changes that have just been committed into a
4.0 repository of $USER. When $USER does a push, they will be propogated to
4.1 repository of $USER. When $USER does a push, they will be propogated to
the main repository and within 24 hours after the push to the public repository.
For information on how to access the public repository
see http://www.mysql.com/doc/I/n/Installing_source_tree.html
......@@ -66,10 +66,10 @@ EOF
echo "Notifying docs list at $DOCS"
(
cat <<EOF
List-ID: <bk.mysql-4.0>
List-ID: <bk.mysql-4.1>
From: $FROM
To: $DOCS
Subject: bk commit - 4.0 tree (Manual)
Subject: bk commit - 4.1 tree (Manual)
EOF
bk changes -v -r+
......
......@@ -52,3 +52,4 @@ work for me. Why?' is not consider a valid bug report.
The mysqlbug script can be found in the 'scripts' directory in the
distribution, that is 'there-you-installed-mysql/scripts'.
......@@ -147,6 +147,8 @@ typedef struct st_mi_keydef /* Key definition with open & info */
struct st_mi_s_param *s_temp);
void (*store_key)(struct st_mi_keydef *keyinfo, uchar *key_pos,
struct st_mi_s_param *s_temp);
int (*ck_insert)(struct st_myisam_info *inf, uint k_nr, uchar *k, uint klen);
int (*ck_delete)(struct st_myisam_info *inf, uint k_nr, uchar *k, uint klen);
} MI_KEYDEF;
......
......@@ -7,6 +7,8 @@ ft_test1
mi_test1
mi_test2
mi_test3
rt_test
sp_test
myisamchk
myisamlog
myisampack
......@@ -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
......
......@@ -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>
......@@ -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;
......@@ -554,12 +587,13 @@ 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];
......@@ -567,6 +601,21 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs,
if (mi_keyseg_write(file, &seg))
goto err;
}
for (j=0 ; j < sp_segs ; j++)
{
MI_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;
......
......@@ -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;
}
}
}
......
......@@ -18,6 +18,7 @@
#include "myisamdef.h"
#include "m_ctype.h"
#include "sp_defs.h"
#ifdef HAVE_IEEEFP_H
#include <ieeefp.h>
#endif
......@@ -39,6 +40,14 @@ uint _mi_make_key(register MI_INFO *info, uint keynr, uchar *key,
reg1 MI_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++)
{
......
......@@ -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,extra,keys,
key_parts,unique_key_parts,tmp_length,uniques;
char name_buff[FN_REFLEN], org_name [FN_REFLEN], index_name[FN_REFLEN],
......@@ -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))
......@@ -631,6 +645,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;
......@@ -896,7 +920,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; /* +BAR 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;
......@@ -908,7 +932,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++; /* +BAR 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;
......
......@@ -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);
}
......
......@@ -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)
......
......@@ -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;
}
}
}
}
......
......@@ -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 (_mi_key_cmp(keyinfo->seg,info->lastkey2,info->lastkey,
info->last_rkey_length, SEARCH_FIND, &not_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]);
......
......@@ -49,7 +49,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[]=
......
......@@ -89,6 +89,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;
......
......@@ -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;
......
......@@ -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;
......
......@@ -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++)
......@@ -113,8 +116,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;
}
......
......@@ -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)
......
......@@ -253,6 +253,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 */
......@@ -272,6 +273,8 @@ struct st_myisam_info {
#ifdef THREAD
THR_LOCK_DATA lock;
#endif
uchar * rtree_recursion_state; /* For RTREE */
int rtree_recursion_depth;
};
......
This diff is collapsed.
/* 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 */
/* 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;
}
/* 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 */
This diff is collapsed.
/* 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(MI_KEYSEG *keyseg, uchar *a, uchar *b, uint key_length,
uint nextflag);
int rtree_combine_rect(MI_KEYSEG *keyseg,uchar *, uchar *, uchar*,
uint key_length);
double rtree_rect_volume(MI_KEYSEG *keyseg, uchar*, uint key_length);
int rtree_d_mbr(MI_KEYSEG *keyseg, uchar *a, uint key_length, double *res);
double rtree_overlapping_area(MI_KEYSEG *keyseg, uchar *a, uchar *b,
uint key_length);
double rtree_area_increase(MI_KEYSEG *keyseg, uchar *a, uchar *b,
uint key_length, double *ab_area);
int rtree_page_mbr(MI_INFO *info, MI_KEYSEG *keyseg, uchar *page_buf,
uchar* c, uint key_length);
#endif /* _rt_mbr_h */
/* 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;
}
/* 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];
MI_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);
}
}
/* 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 */
/* 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)
{
MI_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;
}
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment