merge
This commit is contained in:
commit
b5a145d872
17
.bzrignore
17
.bzrignore
@ -41,6 +41,7 @@ Docs/include.texi
|
||||
Docs/manual.aux
|
||||
Docs/manual.cp
|
||||
Docs/manual.cps
|
||||
Docs/manual.de.log
|
||||
Docs/manual.dvi
|
||||
Docs/manual.fn
|
||||
Docs/manual.fns
|
||||
@ -49,6 +50,8 @@ Docs/manual.ky
|
||||
Docs/manual.log
|
||||
Docs/manual.pdf
|
||||
Docs/manual.pg
|
||||
Docs/manual.texi.orig
|
||||
Docs/manual.texi.rej
|
||||
Docs/manual.toc
|
||||
Docs/manual.tp
|
||||
Docs/manual.txt
|
||||
@ -58,6 +61,8 @@ Docs/manual_letter.ps
|
||||
Docs/manual_toc.html
|
||||
Docs/my_sys.doc
|
||||
Docs/mysql.info
|
||||
Docs/mysql.xml
|
||||
Docs/safe-mysql.xml
|
||||
Docs/tex.fmt
|
||||
Docs/texi2dvi.out
|
||||
INSTALL-SOURCE
|
||||
@ -242,6 +247,7 @@ libmysqld/field.cc
|
||||
libmysqld/field_conv.cc
|
||||
libmysqld/filesort.cc
|
||||
libmysqld/get_password.c
|
||||
libmysqld/gstream.cc
|
||||
libmysqld/ha_berkeley.cc
|
||||
libmysqld/ha_heap.cc
|
||||
libmysqld/ha_innobase.cc
|
||||
@ -281,6 +287,7 @@ libmysqld/records.cc
|
||||
libmysqld/repl_failsafe.cc
|
||||
libmysqld/simple-test
|
||||
libmysqld/slave.cc
|
||||
libmysqld/spatial.cc
|
||||
libmysqld/sql_acl.cc
|
||||
libmysqld/sql_analyse.cc
|
||||
libmysqld/sql_base.cc
|
||||
@ -339,12 +346,15 @@ myisam/mi_test_all
|
||||
myisam/myisamchk
|
||||
myisam/myisamlog
|
||||
myisam/myisampack
|
||||
myisam/rt_test
|
||||
myisam/sp_test
|
||||
myisam/test1.MYD
|
||||
myisam/test1.MYI
|
||||
mysql-test/gmon.out
|
||||
mysql-test/install_test_db
|
||||
mysql-test/mysql-test-run
|
||||
mysql-test/r/*.reject
|
||||
mysql-test/r/rpl000001.eval
|
||||
mysql-test/r/rpl000002.eval
|
||||
mysql-test/r/rpl000014.eval
|
||||
mysql-test/r/rpl000015.eval
|
||||
@ -364,6 +374,7 @@ mysys/test_dir
|
||||
mysys/test_io_cache
|
||||
mysys/test_thr_alarm
|
||||
mysys/test_thr_lock
|
||||
mysys/test_vsnprintf
|
||||
mysys/testhash
|
||||
regex/re
|
||||
repl-tests/test-repl-ts/repl-timestamp.master.reject
|
||||
@ -431,6 +442,7 @@ sql/share/norwegian/errmsg.sys
|
||||
sql/sql_select.cc.orig
|
||||
sql/sql_yacc.cc
|
||||
sql/sql_yacc.h
|
||||
sql/sql_yacc.yy.orig
|
||||
stamp-h
|
||||
strings/conf_to_src
|
||||
strings/ctype_autoconf.c
|
||||
@ -458,8 +470,3 @@ vio/test-ssl
|
||||
vio/test-sslclient
|
||||
vio/test-sslserver
|
||||
vio/viotest-ssl
|
||||
Docs/mysql.xml
|
||||
mysql-test/r/rpl000001.eval
|
||||
Docs/safe-mysql.xml
|
||||
mysys/test_vsnprintf
|
||||
Docs/manual.de.log
|
||||
|
@ -8,6 +8,6 @@ c_warnings="$c_warnings $debug_extra_warnings"
|
||||
cxx_warnings="$cxx_warnings $debug_extra_warnings"
|
||||
extra_configs="$pentium_configs $debug_configs $static_link"
|
||||
|
||||
extra_configs="$extra_configs "
|
||||
extra_configs="$extra_configs $static_link"
|
||||
|
||||
. "$path/FINISH.sh"
|
||||
|
@ -6,6 +6,8 @@ Sinisa@sinisa.nasamreza.org
|
||||
ahlentz@co3064164-a.rochd1.qld.optusnet.com.au
|
||||
arjen@co3064164-a.bitbike.com
|
||||
arjen@fred.bitbike.com
|
||||
arjen@george.bitbike.com
|
||||
bar@gw.udmsearch.izhnet.ru
|
||||
bell@sanja.is.com.ua
|
||||
davida@isil.mysql.com
|
||||
heikki@donna.mysql.fi
|
||||
@ -51,4 +53,3 @@ tonu@x3.internalnet
|
||||
venu@work.mysql.com
|
||||
zak@balfor.local
|
||||
zak@linux.local
|
||||
arjen@george.bitbike.com
|
||||
|
@ -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+
|
||||
|
@ -48984,9 +48984,6 @@ Fixed bug in truncation operator for boolean full-text search.
|
||||
Allow value of @code{--user=#} option for @code{mysqld} to be specified
|
||||
as a numeric user ID.
|
||||
@item
|
||||
Fixed a bug where @code{SQL_CALC_ROWS} returned an incorrect value when used
|
||||
with one table and @code{ORDER BY} and with @code{InnoDB} tables.
|
||||
@item
|
||||
Fixed that @code{SELECT 0 LIMIT 0} doesn't hang thread.
|
||||
@item
|
||||
Fixed some problems with @code{USE/IGNORE INDEX} when using
|
||||
|
1
README
1
README
@ -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'.
|
||||
|
||||
|
38
acconfig.h
38
acconfig.h
@ -18,6 +18,9 @@
|
||||
|
||||
#undef CRAY_STACKSEG_END
|
||||
|
||||
/* Define the default charset name */
|
||||
#undef DEFAULT_CHARSET_NAME
|
||||
|
||||
/* Version of .frm files */
|
||||
#undef DOT_FRM_VERSION
|
||||
|
||||
@ -63,6 +66,41 @@
|
||||
/* READLINE: */
|
||||
#undef HAVE_BSD_SIGNALS
|
||||
|
||||
/* Define charsets you want */
|
||||
#undef HAVE_CHARSET_armscii8
|
||||
#undef HAVE_CHARSET_big5
|
||||
#undef HAVE_CHARSET_cp1251
|
||||
#undef HAVE_CHARSET_cp1257
|
||||
#undef HAVE_CHARSET_croat
|
||||
#undef HAVE_CHARSET_czech
|
||||
#undef HAVE_CHARSET_danish
|
||||
#undef HAVE_CHARSET_dec8
|
||||
#undef HAVE_CHARSET_dos
|
||||
#undef HAVE_CHARSET_estonia
|
||||
#undef HAVE_CHARSET_euc_kr
|
||||
#undef HAVE_CHARSET_gb2312
|
||||
#undef HAVE_CHARSET_gbk
|
||||
#undef HAVE_CHARSET_german1
|
||||
#undef HAVE_CHARSET_greek
|
||||
#undef HAVE_CHARSET_hebrew
|
||||
#undef HAVE_CHARSET_hp8
|
||||
#undef HAVE_CHARSET_hungarian
|
||||
#undef HAVE_CHARSET_koi8_ru
|
||||
#undef HAVE_CHARSET_koi8_ukr
|
||||
#undef HAVE_CHARSET_latin1
|
||||
#undef HAVE_CHARSET_latin1_de
|
||||
#undef HAVE_CHARSET_latin2
|
||||
#undef HAVE_CHARSET_latin5
|
||||
#undef HAVE_CHARSET_sjis
|
||||
#undef HAVE_CHARSET_swe7
|
||||
#undef HAVE_CHARSET_tis620
|
||||
#undef HAVE_CHARSET_ujis
|
||||
#undef HAVE_CHARSET_usa7
|
||||
#undef HAVE_CHARSET_utf8
|
||||
#undef HAVE_CHARSET_win1250
|
||||
#undef HAVE_CHARSET_win1251ukr
|
||||
#undef HAVE_CHARSET_win1251
|
||||
|
||||
/* ZLIB and compress: */
|
||||
#undef HAVE_COMPRESS
|
||||
|
||||
|
@ -342,6 +342,7 @@ int main(int argc,char *argv[])
|
||||
if (!status.batch)
|
||||
ignore_errors=1; // Don't abort monitor
|
||||
signal(SIGINT, mysql_end); // Catch SIGINT to clean up
|
||||
signal(SIGQUIT, mysql_end); // Catch SIGQUIT to clean up
|
||||
|
||||
/*
|
||||
** Run in interactive mode like the ingres/postgres monitor
|
||||
@ -915,14 +916,14 @@ static COMMANDS *find_command (char *name,char cmd_char)
|
||||
}
|
||||
else
|
||||
{
|
||||
while (isspace(*name))
|
||||
while (my_isspace(system_charset_info,*name))
|
||||
name++;
|
||||
if (strchr(name,';') || strstr(name,"\\g"))
|
||||
return ((COMMANDS *) 0);
|
||||
if ((end=strcont(name," \t")))
|
||||
{
|
||||
len=(uint) (end - name);
|
||||
while (isspace(*end))
|
||||
while (my_isspace(system_charset_info,*end))
|
||||
end++;
|
||||
if (!*end)
|
||||
end=0; // no arguments to function
|
||||
@ -934,7 +935,8 @@ static COMMANDS *find_command (char *name,char cmd_char)
|
||||
for (uint i= 0; commands[i].name; i++)
|
||||
{
|
||||
if (commands[i].func &&
|
||||
((name && !my_casecmp(name,commands[i].name,len) &&
|
||||
((name &&
|
||||
!my_strncasecmp(system_charset_info,name,commands[i].name,len) &&
|
||||
!commands[i].name[len] &&
|
||||
(!end || (end && commands[i].takes_params))) ||
|
||||
!name && commands[i].cmd_char == cmd_char))
|
||||
@ -962,12 +964,13 @@ static bool add_line(String &buffer,char *line,char *in_string)
|
||||
|
||||
for (pos=out=line ; (inchar= (uchar) *pos) ; pos++)
|
||||
{
|
||||
if (isspace(inchar) && out == line && buffer.is_empty())
|
||||
if (my_isspace(system_charset_info,inchar) && out == line &&
|
||||
buffer.is_empty())
|
||||
continue;
|
||||
#ifdef USE_MB
|
||||
int l;
|
||||
if (use_mb(default_charset_info) &&
|
||||
(l = my_ismbchar(default_charset_info, pos, strend))) {
|
||||
if (use_mb(system_charset_info) &&
|
||||
(l = my_ismbchar(system_charset_info, pos, strend))) {
|
||||
while (l--)
|
||||
*out++ = *pos++;
|
||||
pos--;
|
||||
@ -1030,7 +1033,7 @@ static bool add_line(String &buffer,char *line,char *in_string)
|
||||
}
|
||||
else if (!*in_string && (inchar == '#' ||
|
||||
inchar == '-' && pos[1] == '-' &&
|
||||
isspace(pos[2])))
|
||||
my_isspace(system_charset_info,pos[2])))
|
||||
break; // comment to end of line
|
||||
else
|
||||
{ // Add found char to buffer
|
||||
@ -1430,7 +1433,8 @@ com_go(String *buffer,char *line __attribute__((unused)))
|
||||
(void) com_print(buffer,0);
|
||||
|
||||
if (skip_updates &&
|
||||
(buffer->length() < 4 || my_sortcmp(buffer->ptr(),"SET ",4)))
|
||||
(buffer->length() < 4 || my_sortcmp(system_charset_info,buffer->ptr(),
|
||||
"SET ",4)))
|
||||
{
|
||||
(void) put_info("Ignoring query to other database",INFO_INFO);
|
||||
return 0;
|
||||
@ -1801,8 +1805,8 @@ safe_put_field(const char *pos,ulong length)
|
||||
{
|
||||
#ifdef USE_MB
|
||||
int l;
|
||||
if (use_mb(default_charset_info) &&
|
||||
(l = my_ismbchar(default_charset_info, pos, end))) {
|
||||
if (use_mb(system_charset_info) &&
|
||||
(l = my_ismbchar(system_charset_info, pos, end))) {
|
||||
while (l--)
|
||||
tee_putc(*pos++, PAGER);
|
||||
pos--;
|
||||
@ -1862,7 +1866,7 @@ com_tee(String *buffer, char *line __attribute__((unused)))
|
||||
|
||||
if (status.batch)
|
||||
return 0;
|
||||
while (isspace(*line))
|
||||
while (my_isspace(system_charset_info,*line))
|
||||
line++;
|
||||
if (!(param = strchr(line, ' '))) // if outfile wasn't given, use the default
|
||||
{
|
||||
@ -1875,10 +1879,11 @@ com_tee(String *buffer, char *line __attribute__((unused)))
|
||||
}
|
||||
else
|
||||
{
|
||||
while (isspace(*param))
|
||||
while (my_isspace(system_charset_info,*param))
|
||||
param++;
|
||||
end=strmake(file_name, param, sizeof(file_name)-1);
|
||||
while (end > file_name && (isspace(end[-1]) || iscntrl(end[-1])))
|
||||
while (end > file_name && (my_isspace(system_charset_info,end[-1]) ||
|
||||
my_iscntrl(system_charset_info,end[-1])))
|
||||
end--;
|
||||
end[0]=0;
|
||||
strmov(outfile, file_name);
|
||||
@ -1921,7 +1926,7 @@ com_pager(String *buffer, char *line __attribute__((unused)))
|
||||
if (status.batch)
|
||||
return 0;
|
||||
/* Skip space from file name */
|
||||
while (isspace(*line))
|
||||
while (my_isspace(system_charset_info,*line))
|
||||
line++;
|
||||
if (!(param = strchr(line, ' '))) // if pager was not given, use the default
|
||||
{
|
||||
@ -1937,10 +1942,11 @@ com_pager(String *buffer, char *line __attribute__((unused)))
|
||||
}
|
||||
else
|
||||
{
|
||||
while (isspace(*param))
|
||||
while (my_isspace(system_charset_info,*param))
|
||||
param++;
|
||||
end=strmake(pager_name, param, sizeof(pager_name)-1);
|
||||
while (end > pager_name && (isspace(end[-1]) || iscntrl(end[-1])))
|
||||
while (end > pager_name && (my_isspace(system_charset_info,end[-1]) ||
|
||||
my_iscntrl(system_charset_info,end[-1])))
|
||||
end--;
|
||||
end[0]=0;
|
||||
strmov(pager, pager_name);
|
||||
@ -2074,7 +2080,7 @@ com_connect(String *buffer, char *line)
|
||||
|
||||
if (buffer)
|
||||
{
|
||||
while (isspace(*line))
|
||||
while (my_isspace(system_charset_info,*line))
|
||||
line++;
|
||||
strnmov(buff,line,sizeof(buff)-1); // Don't destroy history
|
||||
if (buff[0] == '\\') // Short command
|
||||
@ -2120,15 +2126,16 @@ static int com_source(String *buffer, char *line)
|
||||
FILE *sql_file;
|
||||
|
||||
/* Skip space from file name */
|
||||
while (isspace(*line))
|
||||
while (my_isspace(system_charset_info,*line))
|
||||
line++;
|
||||
if (!(param = strchr(line, ' '))) // Skip command name
|
||||
return put_info("Usage: \\. <filename> | source <filename>",
|
||||
INFO_ERROR, 0);
|
||||
while (isspace(*param))
|
||||
while (my_isspace(system_charset_info,*param))
|
||||
param++;
|
||||
end=strmake(source_name,param,sizeof(source_name)-1);
|
||||
while (end > source_name && (isspace(end[-1]) || iscntrl(end[-1])))
|
||||
while (end > source_name && (my_isspace(system_charset_info,end[-1]) ||
|
||||
my_iscntrl(system_charset_info,end[-1])))
|
||||
end--;
|
||||
end[0]=0;
|
||||
unpack_filename(source_name,source_name);
|
||||
@ -2169,7 +2176,7 @@ com_use(String *buffer __attribute__((unused)), char *line)
|
||||
char *tmp;
|
||||
char buff[256];
|
||||
|
||||
while (isspace(*line))
|
||||
while (my_isspace(system_charset_info,*line))
|
||||
line++;
|
||||
strnmov(buff,line,sizeof(buff)-1); // Don't destroy history
|
||||
if (buff[0] == '\\') // Short command
|
||||
@ -2346,7 +2353,7 @@ com_status(String *buffer __attribute__((unused)),
|
||||
tee_fprintf(stdout, "Protocol version:\t%d\n", mysql_get_proto_info(&mysql));
|
||||
tee_fprintf(stdout, "Connection:\t\t%s\n", mysql_get_host_info(&mysql));
|
||||
tee_fprintf(stdout, "Client characterset:\t%s\n",
|
||||
default_charset_info->name);
|
||||
system_charset_info->name);
|
||||
tee_fprintf(stdout, "Server characterset:\t%s\n", mysql.charset->name);
|
||||
if (strstr(mysql_get_host_info(&mysql),"TCP/IP") || ! mysql.unix_socket)
|
||||
tee_fprintf(stdout, "TCP port:\t\t%d\n", mysql.port);
|
||||
@ -2455,7 +2462,7 @@ static void remove_cntrl(String &buffer)
|
||||
{
|
||||
char *start,*end;
|
||||
end=(start=(char*) buffer.ptr())+buffer.length();
|
||||
while (start < end && !isgraph(end[-1]))
|
||||
while (start < end && !my_isgraph(system_charset_info,end[-1]))
|
||||
end--;
|
||||
buffer.length((uint) (end-start));
|
||||
}
|
||||
|
@ -545,7 +545,7 @@ static my_bool test_if_special_chars(const char *str)
|
||||
{
|
||||
#if MYSQL_VERSION_ID >= 32300
|
||||
for ( ; *str ; str++)
|
||||
if (!isvar(*str) && *str != '$')
|
||||
if (!my_isvar(system_charset_info,*str) && *str != '$')
|
||||
return 1;
|
||||
#endif
|
||||
return 0;
|
||||
@ -1061,7 +1061,8 @@ static void dumpTable(uint numFields, char *table)
|
||||
/* change any strings ("inf","nan",..) into NULL */
|
||||
char *ptr = row[i];
|
||||
dynstr_append(&extended_row,
|
||||
(!isalpha(*ptr)) ? ptr : "NULL");
|
||||
(!my_isalpha(system_charset_info,*ptr)) ?
|
||||
ptr : "NULL");
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -1093,9 +1094,11 @@ static void dumpTable(uint numFields, char *table)
|
||||
char *ptr = row[i];
|
||||
if (opt_xml)
|
||||
fprintf(md_result_file, "\t\t<%s>%s</%s>\n",
|
||||
field->name,!isalpha(*ptr) ?ptr: "NULL",field->name);
|
||||
field->name,
|
||||
!my_isalpha(system_charset_info,*ptr) ?ptr: "NULL",field->name);
|
||||
else
|
||||
fputs((!isalpha(*ptr)) ? ptr : "NULL", md_result_file);
|
||||
fputs((!my_isalpha(system_charset_info,*ptr)) ?
|
||||
ptr : "NULL", md_result_file);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -456,9 +456,9 @@ void init_parser()
|
||||
|
||||
int hex_val(int c)
|
||||
{
|
||||
if (isdigit(c))
|
||||
if (my_isdigit(system_charset_info,c))
|
||||
return c - '0';
|
||||
else if ((c = tolower(c)) >= 'a' && c <= 'f')
|
||||
else if ((c = my_tolower(system_charset_info,c)) >= 'a' && c <= 'f')
|
||||
return c - 'a' + 10;
|
||||
else
|
||||
return -1;
|
||||
@ -569,7 +569,7 @@ VAR* var_get(const char* var_name, const char** var_name_end, my_bool raw,
|
||||
{
|
||||
const char* save_var_name = var_name, *end;
|
||||
end = (var_name_end) ? *var_name_end : 0;
|
||||
while (isvar(*var_name) && var_name != end)
|
||||
while (my_isvar(system_charset_info,*var_name) && var_name != end)
|
||||
++var_name;
|
||||
if (var_name == save_var_name)
|
||||
{
|
||||
@ -729,7 +729,7 @@ int do_server_op(struct st_query* q,const char* op)
|
||||
com_p=strmov(com_p,"_exec ");
|
||||
if (!*p)
|
||||
die("Missing server name in server_%s\n",op);
|
||||
while (*p && !isspace(*p))
|
||||
while (*p && !my_isspace(system_charset_info,*p))
|
||||
{
|
||||
*com_p++=*p++;
|
||||
}
|
||||
@ -762,7 +762,7 @@ int do_require_version(struct st_query* q)
|
||||
if (!*p)
|
||||
die("Missing version argument in require_version\n");
|
||||
ver_arg = p;
|
||||
while (*p && !isspace(*p))
|
||||
while (*p && !my_isspace(system_charset_info,*p))
|
||||
p++;
|
||||
*p = 0;
|
||||
ver_arg_len = p - ver_arg;
|
||||
@ -792,7 +792,7 @@ int do_source(struct st_query* q)
|
||||
if (!*p)
|
||||
die("Missing file name in source\n");
|
||||
name = p;
|
||||
while (*p && !isspace(*p))
|
||||
while (*p && !my_isspace(system_charset_info,*p))
|
||||
p++;
|
||||
*p = 0;
|
||||
|
||||
@ -1012,11 +1012,11 @@ int do_let(struct st_query* q)
|
||||
if (!*p)
|
||||
die("Missing variable name in let\n");
|
||||
var_name = p;
|
||||
while(*p && (*p != '=' || isspace(*p)))
|
||||
while(*p && (*p != '=' || my_isspace(system_charset_info,*p)))
|
||||
p++;
|
||||
var_name_end = p;
|
||||
if (*p == '=') p++;
|
||||
while(*p && isspace(*p))
|
||||
while(*p && my_isspace(system_charset_info,*p))
|
||||
p++;
|
||||
var_val_start = p;
|
||||
return var_set(var_name, var_name_end, var_val_start, q->end);
|
||||
@ -1047,7 +1047,7 @@ int do_sleep(struct st_query* q)
|
||||
char* p=q->first_argument;
|
||||
struct timeval t;
|
||||
int dec_mul = 1000000;
|
||||
while(*p && isspace(*p)) p++;
|
||||
while(*p && my_isspace(system_charset_info,*p)) p++;
|
||||
if (!*p)
|
||||
die("Missing argument in sleep\n");
|
||||
t.tv_usec = 0;
|
||||
@ -1067,7 +1067,7 @@ int do_sleep(struct st_query* q)
|
||||
else
|
||||
{
|
||||
t.tv_sec = atoi(p);
|
||||
while(*p && *p != '.' && !isspace(*p))
|
||||
while(*p && *p != '.' && !my_isspace(system_charset_info,*p))
|
||||
p++;
|
||||
if (*p == '.')
|
||||
{
|
||||
@ -1099,7 +1099,7 @@ static void get_file_name(char *filename, struct st_query* q)
|
||||
char* p=q->first_argument;
|
||||
strnmov(filename, p, FN_REFLEN);
|
||||
/* Remove end space */
|
||||
while (p > filename && isspace(p[-1]))
|
||||
while (p > filename && my_isspace(system_charset_info,p[-1]))
|
||||
p--;
|
||||
p[0]=0;
|
||||
}
|
||||
@ -1185,7 +1185,7 @@ static char *get_string(char **to_ptr, char **from_ptr,
|
||||
if (*from != ' ' && *from)
|
||||
die("Wrong string argument in %s\n", q->query);
|
||||
|
||||
while (isspace(*from)) /* Point to next string */
|
||||
while (my_isspace(system_charset_info,*from)) /* Point to next string */
|
||||
from++;
|
||||
|
||||
*to =0; /* End of string marker */
|
||||
@ -1243,7 +1243,7 @@ static void get_replace(struct st_query *q)
|
||||
insert_pointer_name(&to_array,to);
|
||||
}
|
||||
for (i=1,pos=word_end_chars ; i < 256 ; i++)
|
||||
if (isspace(i))
|
||||
if (my_isspace(system_charset_info,i))
|
||||
*pos++=i;
|
||||
*pos=0; /* End pointer */
|
||||
if (!(glob_replace=init_replace((char**) from_array.typelib.type_names,
|
||||
@ -1278,7 +1278,7 @@ int select_connection(struct st_query* q)
|
||||
if (!*p)
|
||||
die("Missing connection name in connect\n");
|
||||
name = p;
|
||||
while(*p && !isspace(*p))
|
||||
while(*p && !my_isspace(system_charset_info,*p))
|
||||
p++;
|
||||
*p = 0;
|
||||
|
||||
@ -1304,7 +1304,7 @@ int close_connection(struct st_query* q)
|
||||
if (!*p)
|
||||
die("Missing connection name in connect\n");
|
||||
name = p;
|
||||
while(*p && !isspace(*p))
|
||||
while(*p && !my_isspace(system_charset_info,*p))
|
||||
p++;
|
||||
*p = 0;
|
||||
|
||||
@ -1340,11 +1340,11 @@ int close_connection(struct st_query* q)
|
||||
char* safe_get_param(char* str, char** arg, const char* msg)
|
||||
{
|
||||
DBUG_ENTER("safe_get_param");
|
||||
while (*str && isspace(*str)) str++;
|
||||
while (*str && my_isspace(system_charset_info,*str)) str++;
|
||||
*arg = str;
|
||||
for (; *str && *str != ',' && *str != ')' ; str++)
|
||||
{
|
||||
if (isspace(*str)) *str = 0;
|
||||
if (my_isspace(system_charset_info,*str)) *str = 0;
|
||||
}
|
||||
if (!*str)
|
||||
die(msg);
|
||||
@ -1626,7 +1626,7 @@ int read_line(char* buf, int size)
|
||||
{
|
||||
state = R_COMMENT;
|
||||
}
|
||||
else if (isspace(c))
|
||||
else if (my_isspace(system_charset_info,c))
|
||||
{
|
||||
if (c == '\n')
|
||||
start_lineno= ++*lineno; /* Query hasn't started yet */
|
||||
@ -1752,7 +1752,7 @@ int read_query(struct st_query** q_ptr)
|
||||
{
|
||||
expected_errno = 0;
|
||||
p++;
|
||||
for (;isdigit(*p);p++)
|
||||
for (;my_isdigit(system_charset_info,*p);p++)
|
||||
expected_errno = expected_errno * 10 + *p - '0';
|
||||
q->expected_errno[0] = expected_errno;
|
||||
q->expected_errno[1] = 0;
|
||||
@ -1760,25 +1760,25 @@ int read_query(struct st_query** q_ptr)
|
||||
}
|
||||
}
|
||||
|
||||
while(*p && isspace(*p)) p++ ;
|
||||
while(*p && my_isspace(system_charset_info,*p)) p++ ;
|
||||
if (*p == '@')
|
||||
{
|
||||
p++;
|
||||
p1 = q->record_file;
|
||||
while (!isspace(*p) &&
|
||||
while (!my_isspace(system_charset_info,*p) &&
|
||||
p1 < q->record_file + sizeof(q->record_file) - 1)
|
||||
*p1++ = *p++;
|
||||
*p1 = 0;
|
||||
}
|
||||
}
|
||||
while (*p && isspace(*p)) p++;
|
||||
while (*p && my_isspace(system_charset_info,*p)) p++;
|
||||
if (!(q->query_buf=q->query=my_strdup(p,MYF(MY_WME))))
|
||||
die(NullS);
|
||||
|
||||
/* Calculate first word and first argument */
|
||||
for (p=q->query; *p && !isspace(*p) ; p++) ;
|
||||
for (p=q->query; *p && !my_isspace(system_charset_info,*p) ; p++) ;
|
||||
q->first_word_len = (uint) (p - q->query);
|
||||
while (*p && isspace(*p)) p++;
|
||||
while (*p && my_isspace(system_charset_info,*p)) p++;
|
||||
q->first_argument=p;
|
||||
q->end = strend(q->query);
|
||||
parser.read_lines++;
|
||||
@ -2326,7 +2326,8 @@ static void var_from_env(const char* name, const char* def_val)
|
||||
static void init_var_hash()
|
||||
{
|
||||
VAR* v;
|
||||
if (hash_init(&var_hash, 1024, 0, 0, get_var_key, var_free, MYF(0)))
|
||||
if (hash_init(&var_hash, system_charset_info,
|
||||
1024, 0, 0, get_var_key, var_free, MYF(0)))
|
||||
die("Variable hash initialization failed");
|
||||
var_from_env("MASTER_MYPORT", "9306");
|
||||
var_from_env("SLAVE_MYPORT", "9307");
|
||||
|
@ -234,7 +234,7 @@ bool String::fill(uint32 max_length,char fill_char)
|
||||
|
||||
void String::strip_sp()
|
||||
{
|
||||
while (str_length && isspace(Ptr[str_length-1]))
|
||||
while (str_length && my_isspace(str_charset,Ptr[str_length-1]))
|
||||
str_length--;
|
||||
}
|
||||
|
||||
@ -296,10 +296,10 @@ uint32 String::numchars()
|
||||
register uint32 n=0,mblen;
|
||||
register const char *mbstr=Ptr;
|
||||
register const char *end=mbstr+str_length;
|
||||
if (use_mb(default_charset_info))
|
||||
if (use_mb(str_charset))
|
||||
{
|
||||
while (mbstr < end) {
|
||||
if ((mblen=my_ismbchar(default_charset_info, mbstr,end))) mbstr+=mblen;
|
||||
if ((mblen=my_ismbchar(str_charset, mbstr,end))) mbstr+=mblen;
|
||||
else ++mbstr;
|
||||
++n;
|
||||
}
|
||||
@ -316,11 +316,11 @@ int String::charpos(int i,uint32 offset)
|
||||
register uint32 mblen;
|
||||
register const char *mbstr=Ptr+offset;
|
||||
register const char *end=Ptr+str_length;
|
||||
if (use_mb(default_charset_info))
|
||||
if (use_mb(str_charset))
|
||||
{
|
||||
if (i<=0) return i;
|
||||
while (i && mbstr < end) {
|
||||
if ((mblen=my_ismbchar(default_charset_info, mbstr,end))) mbstr+=mblen;
|
||||
if ((mblen=my_ismbchar(str_charset, mbstr,end))) mbstr+=mblen;
|
||||
else ++mbstr;
|
||||
--i;
|
||||
}
|
||||
@ -361,6 +361,39 @@ skipp:
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
Search after a string without regarding to case
|
||||
This needs to be replaced when we have character sets per string
|
||||
*/
|
||||
|
||||
int String::strstr_case(const String &s,uint32 offset)
|
||||
{
|
||||
if (s.length()+offset <= str_length)
|
||||
{
|
||||
if (!s.length())
|
||||
return ((int) offset); // Empty string is always found
|
||||
|
||||
register const char *str = Ptr+offset;
|
||||
register const char *search=s.ptr();
|
||||
const char *end=Ptr+str_length-s.length()+1;
|
||||
const char *search_end=s.ptr()+s.length();
|
||||
skipp:
|
||||
while (str != end)
|
||||
{
|
||||
if (str_charset->sort_order[*str++] == str_charset->sort_order[*search])
|
||||
{
|
||||
register char *i,*j;
|
||||
i=(char*) str; j=(char*) search+1;
|
||||
while (j != search_end)
|
||||
if (str_charset->sort_order[*i++] !=
|
||||
str_charset->sort_order[*j++])
|
||||
goto skipp;
|
||||
return (int) (str-Ptr) -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
** Search string from end. Offset is offset to the end of string
|
||||
@ -428,6 +461,44 @@ bool String::replace(uint32 offset,uint32 arg_length,const String &to)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// added by Holyfoot for "geometry" needs
|
||||
int String::reserve(uint32 space_needed, uint32 grow_by)
|
||||
{
|
||||
if (Alloced_length < str_length + space_needed)
|
||||
{
|
||||
if (realloc(Alloced_length + max(space_needed, grow_by) - 1))
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void String::qs_append(const char *str)
|
||||
{
|
||||
int len = strlen(str);
|
||||
memcpy(Ptr + str_length, str, len + 1);
|
||||
str_length += len;
|
||||
}
|
||||
|
||||
void String::qs_append(double d)
|
||||
{
|
||||
char *buff = Ptr + str_length;
|
||||
sprintf(buff,"%.14g", d);
|
||||
str_length += strlen(buff);
|
||||
}
|
||||
|
||||
void String::qs_append(double *d)
|
||||
{
|
||||
double ld;
|
||||
float8get(ld, d);
|
||||
qs_append(ld);
|
||||
}
|
||||
|
||||
void String::qs_append(const char &c)
|
||||
{
|
||||
Ptr[str_length] = c;
|
||||
str_length += sizeof(c);
|
||||
}
|
||||
|
||||
|
||||
int sortcmp(const String *x,const String *y)
|
||||
{
|
||||
@ -436,15 +507,15 @@ int sortcmp(const String *x,const String *y)
|
||||
uint32 x_len=x->length(),y_len=y->length(),len=min(x_len,y_len);
|
||||
|
||||
#ifdef USE_STRCOLL
|
||||
if (use_strcoll(default_charset_info))
|
||||
if (use_strcoll(x->str_charset))
|
||||
{
|
||||
#ifndef CMP_ENDSPACE
|
||||
while (x_len && isspace(s[x_len-1]))
|
||||
while (x_len && my_isspace(x->str_charset,s[x_len-1]))
|
||||
x_len--;
|
||||
while (y_len && isspace(t[y_len-1]))
|
||||
while (y_len && my_isspace(x->str_charset,t[y_len-1]))
|
||||
y_len--;
|
||||
#endif
|
||||
return my_strnncoll(default_charset_info,
|
||||
return my_strnncoll(x->str_charset,
|
||||
(unsigned char *)s,x_len,(unsigned char *)t,y_len);
|
||||
}
|
||||
else
|
||||
@ -454,9 +525,10 @@ int sortcmp(const String *x,const String *y)
|
||||
y_len-=len;
|
||||
while (len--)
|
||||
{
|
||||
if (my_sort_order[(uchar) *s++] != my_sort_order[(uchar) *t++])
|
||||
return ((int) my_sort_order[(uchar) s[-1]] -
|
||||
(int) my_sort_order[(uchar) t[-1]]);
|
||||
if (x->str_charset->sort_order[(uchar) *s++] !=
|
||||
x->str_charset->sort_order[(uchar) *t++])
|
||||
return ((int) x->str_charset->sort_order[(uchar) s[-1]] -
|
||||
(int) x->str_charset->sort_order[(uchar) t[-1]]);
|
||||
}
|
||||
#ifndef CMP_ENDSPACE
|
||||
/* Don't compare end space in strings */
|
||||
@ -465,14 +537,14 @@ int sortcmp(const String *x,const String *y)
|
||||
{
|
||||
const char *end=t+y_len;
|
||||
for (; t != end ; t++)
|
||||
if (!isspace(*t))
|
||||
if (!my_isspace(x->str_charset,*t))
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
const char *end=s+x_len;
|
||||
for (; s != end ; s++)
|
||||
if (!isspace(*s))
|
||||
if (!my_isspace(x->str_charset,*s))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
@ -520,11 +592,10 @@ String *copy_if_not_alloced(String *to,String *from,uint32 from_length)
|
||||
/* Make it easier to handle different charactersets */
|
||||
|
||||
#ifdef USE_MB
|
||||
#define INC_PTR(A,B) A+=((use_mb_flag && \
|
||||
my_ismbchar(default_charset_info,A,B)) ? \
|
||||
my_ismbchar(default_charset_info,A,B) : 1)
|
||||
#define INC_PTR(cs,A,B) A+=((use_mb_flag && \
|
||||
my_ismbchar(cs,A,B)) ? my_ismbchar(cs,A,B) : 1)
|
||||
#else
|
||||
#define INC_PTR(A,B) A++
|
||||
#define INC_PTR(cs,A,B) A++
|
||||
#endif
|
||||
|
||||
/*
|
||||
@ -535,18 +606,18 @@ String *copy_if_not_alloced(String *to,String *from,uint32 from_length)
|
||||
*/
|
||||
|
||||
#ifdef LIKE_CMP_TOUPPER
|
||||
#define likeconv(A) (uchar) toupper(A)
|
||||
#define likeconv(s,A) (uchar) my_toupper(s,A)
|
||||
#else
|
||||
#define likeconv(A) (uchar) my_sort_order[(uchar) (A)]
|
||||
#define likeconv(s,A) (uchar) (s)->sort_order[(uchar) (A)]
|
||||
#endif
|
||||
|
||||
static int wild_case_compare(const char *str,const char *str_end,
|
||||
const char *wildstr,const char *wildend,
|
||||
char escape)
|
||||
int wild_case_compare(CHARSET_INFO *cs, const char *str,const char *str_end,
|
||||
const char *wildstr,const char *wildend,
|
||||
char escape)
|
||||
{
|
||||
int result= -1; // Not found, using wildcards
|
||||
#ifdef USE_MB
|
||||
bool use_mb_flag=use_mb(default_charset_info);
|
||||
bool use_mb_flag=use_mb(cs);
|
||||
#endif
|
||||
while (wildstr != wildend)
|
||||
{
|
||||
@ -557,7 +628,7 @@ static int wild_case_compare(const char *str,const char *str_end,
|
||||
#ifdef USE_MB
|
||||
int l;
|
||||
if (use_mb_flag &&
|
||||
(l = my_ismbchar(default_charset_info, wildstr, wildend)))
|
||||
(l = my_ismbchar(cs, wildstr, wildend)))
|
||||
{
|
||||
if (str+l > str_end || memcmp(str, wildstr, l) != 0)
|
||||
return 1;
|
||||
@ -566,7 +637,7 @@ static int wild_case_compare(const char *str,const char *str_end,
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (str == str_end || likeconv(*wildstr++) != likeconv(*str++))
|
||||
if (str == str_end || likeconv(cs,*wildstr++) != likeconv(cs,*str++))
|
||||
return(1); // No match
|
||||
if (wildstr == wildend)
|
||||
return (str != str_end); // Match if both are at end
|
||||
@ -576,9 +647,9 @@ static int wild_case_compare(const char *str,const char *str_end,
|
||||
{
|
||||
do
|
||||
{
|
||||
if (str == str_end) // Skipp one char if possible
|
||||
if (str == str_end) // Skip one char if possible
|
||||
return (result);
|
||||
INC_PTR(str,str_end);
|
||||
INC_PTR(cs,str,str_end);
|
||||
} while (++wildstr < wildend && *wildstr == wild_one);
|
||||
if (wildstr == wildend)
|
||||
break;
|
||||
@ -595,7 +666,7 @@ static int wild_case_compare(const char *str,const char *str_end,
|
||||
{
|
||||
if (str == str_end)
|
||||
return (-1);
|
||||
INC_PTR(str,str_end);
|
||||
INC_PTR(cs,str,str_end);
|
||||
continue;
|
||||
}
|
||||
break; // Not a wild character
|
||||
@ -613,10 +684,10 @@ static int wild_case_compare(const char *str,const char *str_end,
|
||||
int mblen;
|
||||
LINT_INIT(mblen);
|
||||
if (use_mb_flag)
|
||||
mblen = my_ismbchar(default_charset_info, wildstr, wildend);
|
||||
mblen = my_ismbchar(cs, wildstr, wildend);
|
||||
#endif
|
||||
INC_PTR(wildstr,wildend); // This is compared trough cmp
|
||||
cmp=likeconv(cmp);
|
||||
INC_PTR(cs,wildstr,wildend); // This is compared trough cmp
|
||||
cmp=likeconv(cs,cmp);
|
||||
do
|
||||
{
|
||||
#ifdef USE_MB
|
||||
@ -634,26 +705,26 @@ static int wild_case_compare(const char *str,const char *str_end,
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (!my_ismbchar(default_charset_info, str, str_end) &&
|
||||
likeconv(*str) == cmp)
|
||||
else if (!my_ismbchar(cs, str, str_end) &&
|
||||
likeconv(cs,*str) == cmp)
|
||||
{
|
||||
str++;
|
||||
break;
|
||||
}
|
||||
INC_PTR(str, str_end);
|
||||
INC_PTR(cs,str, str_end);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
#endif /* USE_MB */
|
||||
while (str != str_end && likeconv(*str) != cmp)
|
||||
while (str != str_end && likeconv(cs,*str) != cmp)
|
||||
str++;
|
||||
if (str++ == str_end) return (-1);
|
||||
#ifdef USE_MB
|
||||
}
|
||||
#endif
|
||||
{
|
||||
int tmp=wild_case_compare(str,str_end,wildstr,wildend,escape);
|
||||
int tmp=wild_case_compare(cs,str,str_end,wildstr,wildend,escape);
|
||||
if (tmp <= 0)
|
||||
return (tmp);
|
||||
}
|
||||
@ -667,17 +738,23 @@ static int wild_case_compare(const char *str,const char *str_end,
|
||||
|
||||
int wild_case_compare(String &match,String &wild, char escape)
|
||||
{
|
||||
return wild_case_compare(match.ptr(),match.ptr()+match.length(),
|
||||
wild.ptr(), wild.ptr()+wild.length(),escape);
|
||||
DBUG_ENTER("wild_case_compare");
|
||||
DBUG_PRINT("enter",("match='%s', wild='%s', escape='%c'"
|
||||
,match.ptr(),wild.ptr(),escape));
|
||||
DBUG_RETURN(wild_case_compare(match.str_charset,match.ptr(),match.ptr()+match.length(),
|
||||
wild.ptr(), wild.ptr()+wild.length(),escape));
|
||||
}
|
||||
|
||||
/*
|
||||
** The following is used when using LIKE on binary strings
|
||||
*/
|
||||
|
||||
static int wild_compare(const char *str,const char *str_end,
|
||||
const char *wildstr,const char *wildend,char escape)
|
||||
int wild_compare(const char *str,const char *str_end,
|
||||
const char *wildstr,const char *wildend,char escape)
|
||||
{
|
||||
DBUG_ENTER("wild_compare");
|
||||
DBUG_PRINT("enter",("str='%s', str_end='%s', wildstr='%s', wildend='%s', escape='%c'"
|
||||
,str,str_end,wildstr,wildend,escape));
|
||||
int result= -1; // Not found, using wildcards
|
||||
while (wildstr != wildend)
|
||||
{
|
||||
@ -686,17 +763,21 @@ static int wild_compare(const char *str,const char *str_end,
|
||||
if (*wildstr == escape && wildstr+1 != wildend)
|
||||
wildstr++;
|
||||
if (str == str_end || *wildstr++ != *str++)
|
||||
return(1);
|
||||
{
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
if (wildstr == wildend)
|
||||
return (str != str_end); // Match if both are at end
|
||||
{
|
||||
DBUG_RETURN(str != str_end); // Match if both are at end
|
||||
}
|
||||
result=1; // Found an anchor char
|
||||
}
|
||||
if (*wildstr == wild_one)
|
||||
{
|
||||
do
|
||||
{
|
||||
if (str == str_end) // Skipp one char if possible
|
||||
return (result);
|
||||
if (str == str_end) // Skip one char if possible
|
||||
DBUG_RETURN(result);
|
||||
str++;
|
||||
} while (*++wildstr == wild_one && wildstr != wildend);
|
||||
if (wildstr == wildend)
|
||||
@ -713,17 +794,22 @@ static int wild_compare(const char *str,const char *str_end,
|
||||
if (*wildstr == wild_one)
|
||||
{
|
||||
if (str == str_end)
|
||||
return (-1);
|
||||
{
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
str++;
|
||||
continue;
|
||||
}
|
||||
break; // Not a wild character
|
||||
}
|
||||
if (wildstr == wildend)
|
||||
return(0); // Ok if wild_many is last
|
||||
{
|
||||
DBUG_RETURN(0); // Ok if wild_many is last
|
||||
}
|
||||
if (str == str_end)
|
||||
return -1;
|
||||
|
||||
{
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
char cmp;
|
||||
if ((cmp= *wildstr) == escape && wildstr+1 != wildend)
|
||||
cmp= *++wildstr;
|
||||
@ -732,22 +818,32 @@ static int wild_compare(const char *str,const char *str_end,
|
||||
{
|
||||
while (str != str_end && *str != cmp)
|
||||
str++;
|
||||
if (str++ == str_end) return (-1);
|
||||
if (str++ == str_end)
|
||||
{
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
{
|
||||
int tmp=wild_compare(str,str_end,wildstr,wildend,escape);
|
||||
if (tmp <= 0)
|
||||
return (tmp);
|
||||
{
|
||||
DBUG_RETURN(tmp);
|
||||
}
|
||||
}
|
||||
} while (str != str_end && wildstr[0] != wild_many);
|
||||
return(-1);
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
}
|
||||
return (str != str_end ? 1 : 0);
|
||||
DBUG_RETURN(str != str_end ? 1 : 0);
|
||||
}
|
||||
|
||||
|
||||
int wild_compare(String &match,String &wild, char escape)
|
||||
{
|
||||
return wild_compare(match.ptr(),match.ptr()+match.length(),
|
||||
wild.ptr(), wild.ptr()+wild.length(),escape);
|
||||
DBUG_ENTER("wild_compare");
|
||||
DBUG_PRINT("enter",("match='%s', wild='%s', escape='%c'"
|
||||
,match.ptr(),wild.ptr(),escape));
|
||||
DBUG_RETURN(wild_compare(match.ptr(),match.ptr()+match.length(),
|
||||
wild.ptr(), wild.ptr()+wild.length(),escape));
|
||||
}
|
||||
|
||||
|
||||
|
@ -24,31 +24,57 @@
|
||||
#define NOT_FIXED_DEC 31
|
||||
#endif
|
||||
|
||||
class String;
|
||||
int sortcmp(const String *a,const String *b);
|
||||
int stringcmp(const String *a,const String *b);
|
||||
String *copy_if_not_alloced(String *a,String *b,uint32 arg_length);
|
||||
int wild_case_compare(String &match,String &wild,char escape);
|
||||
int wild_compare(String &match,String &wild,char escape);
|
||||
|
||||
class String
|
||||
{
|
||||
char *Ptr;
|
||||
uint32 str_length,Alloced_length;
|
||||
bool alloced;
|
||||
CHARSET_INFO *str_charset;
|
||||
public:
|
||||
String()
|
||||
{ Ptr=0; str_length=Alloced_length=0; alloced=0; }
|
||||
{
|
||||
Ptr=0; str_length=Alloced_length=0; alloced=0;
|
||||
str_charset=default_charset_info;
|
||||
}
|
||||
String(uint32 length_arg)
|
||||
{ alloced=0; Alloced_length=0; (void) real_alloc(length_arg); }
|
||||
{
|
||||
alloced=0; Alloced_length=0; (void) real_alloc(length_arg);
|
||||
str_charset=default_charset_info;
|
||||
}
|
||||
String(const char *str)
|
||||
{ Ptr=(char*) str; str_length=(uint) strlen(str); Alloced_length=0; alloced=0;}
|
||||
{
|
||||
Ptr=(char*) str; str_length=(uint) strlen(str); Alloced_length=0; alloced=0;
|
||||
str_charset=default_charset_info;
|
||||
}
|
||||
String(const char *str,uint32 len)
|
||||
{ Ptr=(char*) str; str_length=len; Alloced_length=0; alloced=0;}
|
||||
{
|
||||
Ptr=(char*) str; str_length=len; Alloced_length=0; alloced=0;
|
||||
str_charset=default_charset_info;
|
||||
}
|
||||
String(char *str,uint32 len)
|
||||
{ Ptr=(char*) str; Alloced_length=str_length=len; alloced=0;}
|
||||
{
|
||||
Ptr=(char*) str; Alloced_length=str_length=len; alloced=0;
|
||||
str_charset=default_charset_info;
|
||||
}
|
||||
String(const String &str)
|
||||
{ Ptr=str.Ptr ; str_length=str.str_length ;
|
||||
Alloced_length=str.Alloced_length; alloced=0; }
|
||||
|
||||
{
|
||||
Ptr=str.Ptr ; str_length=str.str_length ;
|
||||
Alloced_length=str.Alloced_length; alloced=0;
|
||||
str_charset=str.str_charset;
|
||||
}
|
||||
static void *operator new(size_t size) { return (void*) sql_alloc((uint) size); }
|
||||
static void operator delete(void *ptr_arg,size_t size) /*lint -e715 */
|
||||
{ sql_element_free(ptr_arg); }
|
||||
~String() { free(); }
|
||||
|
||||
inline CHARSET_INFO *charset() const { return str_charset; }
|
||||
inline uint32 length() const { return str_length;}
|
||||
inline uint32 alloced_length() const { return Alloced_length;}
|
||||
inline char& operator [] (uint32 i) const { return Ptr[i]; }
|
||||
@ -124,7 +150,7 @@ public:
|
||||
char *new_ptr;
|
||||
if (!(new_ptr=(char*) my_realloc(Ptr,arg_length,MYF(0))))
|
||||
{
|
||||
(void) my_free(Ptr,MYF(0));
|
||||
Alloced_length = 0;
|
||||
real_alloc(arg_length);
|
||||
}
|
||||
else
|
||||
@ -153,6 +179,7 @@ public:
|
||||
bool append(const char *s,uint32 arg_length=0);
|
||||
bool append(IO_CACHE* file, uint32 arg_length);
|
||||
int strstr(const String &search,uint32 offset=0); // Returns offset to substring or -1
|
||||
int strstr_case(const String &s,uint32 offset=0);
|
||||
int strrstr(const String &search,uint32 offset=0); // Returns offset to substring or -1
|
||||
bool replace(uint32 offset,uint32 arg_length,const String &to);
|
||||
inline bool append(char chr)
|
||||
@ -171,8 +198,8 @@ public:
|
||||
}
|
||||
bool fill(uint32 max_length,char fill);
|
||||
void strip_sp();
|
||||
inline void caseup() { ::caseup(Ptr,str_length); }
|
||||
inline void casedn() { ::casedn(Ptr,str_length); }
|
||||
inline void caseup() { my_caseup(str_charset,Ptr,str_length); }
|
||||
inline void casedn() { my_casedn(str_charset,Ptr,str_length); }
|
||||
friend int sortcmp(const String *a,const String *b);
|
||||
friend int stringcmp(const String *a,const String *b);
|
||||
friend String *copy_if_not_alloced(String *a,String *b,uint32 arg_length);
|
||||
@ -180,4 +207,49 @@ public:
|
||||
friend int wild_compare(String &match,String &wild,char escape);
|
||||
uint32 numchars();
|
||||
int charpos(int i,uint32 offset=0);
|
||||
|
||||
// added by Holyfoot for "geometry" needs
|
||||
int reserve(uint32 space_needed)
|
||||
{
|
||||
return realloc(str_length + space_needed);
|
||||
}
|
||||
int reserve(uint32 space_needed, uint32 grow_by);
|
||||
|
||||
// these append operations do NOT check alloced memory
|
||||
// q_*** methods writes values of parameters itself
|
||||
// qs_*** methods writes string representation of value
|
||||
void q_append(const char &c)
|
||||
{
|
||||
Ptr[str_length++] = c;
|
||||
}
|
||||
void q_append(const uint32 &n)
|
||||
{
|
||||
int4store(Ptr + str_length, n);
|
||||
str_length += 4;
|
||||
}
|
||||
void q_append(double d)
|
||||
{
|
||||
float8store(Ptr + str_length, d);
|
||||
str_length += 8;
|
||||
}
|
||||
void q_append(double *d)
|
||||
{
|
||||
float8store(Ptr + str_length, *d);
|
||||
str_length += 8;
|
||||
}
|
||||
void q_append(const char *data, uint32 data_len)
|
||||
{
|
||||
memcpy(Ptr + str_length, data, data_len);
|
||||
str_length += data_len;
|
||||
}
|
||||
|
||||
void WriteAtPosition(int position, uint32 value)
|
||||
{
|
||||
int4store(Ptr + position,value);
|
||||
}
|
||||
|
||||
void qs_append(const char *str);
|
||||
void qs_append(double d);
|
||||
void qs_append(double *d);
|
||||
void qs_append(const char &c);
|
||||
};
|
||||
|
326
configure.in
326
configure.in
@ -627,11 +627,13 @@ AC_ARG_WITH(mysqld-user,
|
||||
AC_SUBST(MYSQLD_USER)
|
||||
|
||||
# If we should allove LOAD DATA LOCAL
|
||||
AC_MSG_CHECKING(if we should should enable LOAD DATA LOCAL by default)
|
||||
AC_MSG_CHECKING(If we should should enable LOAD DATA LOCAL by default)
|
||||
AC_ARG_ENABLE(local-infile,
|
||||
[ --enable-local-infile
|
||||
Enable LOAD DATA LOCAL INFILE (default: disabled)],
|
||||
[ ENABLED_LOCAL_INFILE=$enableval ],
|
||||
[
|
||||
ENABLED_LOCAL_INFILE=$enableval
|
||||
AC_DEFINE(ENABLED_LOCAL_INFILE)
|
||||
],
|
||||
[ ENABLED_LOCAL_INFILE=no ]
|
||||
)
|
||||
if test "$ENABLED_LOCAL_INFILE" = "yes"
|
||||
@ -1919,18 +1921,20 @@ fi
|
||||
AC_SUBST(readline_dir)
|
||||
AC_SUBST(readline_link)
|
||||
|
||||
|
||||
dnl In order to add new charset, you must add charset name to
|
||||
dnl this CHARSETS_AVAILABLE list and sql/share/charsets/Index.
|
||||
dnl If the character set uses strcoll or other special handling,
|
||||
dnl you must also create strings/ctype-$charset_name.c
|
||||
|
||||
AC_DIVERT_PUSH(0)
|
||||
CHARSETS_AVAILABLE="big5 cp1251 cp1257
|
||||
CHARSETS_AVAILABLE="armscii8 big5 cp1251 cp1257
|
||||
croat czech danish dec8 dos estonia euc_kr gb2312 gbk
|
||||
german1 greek hebrew hp8 hungarian koi8_ru koi8_ukr
|
||||
latin1 latin1_de latin2 latin5 sjis swe7 tis620 ujis
|
||||
usa7 win1250 win1251ukr"
|
||||
usa7 utf8 win1250 win1251ukr"
|
||||
CHARSETS_DEPRECATED="win1251"
|
||||
CHARSETS_COMPLEX="big5 czech euc_kr gb2312 gbk latin1_de sjis tis620 ujis utf8"
|
||||
DEFAULT_CHARSET=latin1
|
||||
AC_DIVERT_POP
|
||||
|
||||
@ -1951,208 +1955,144 @@ AC_MSG_CHECKING("character sets")
|
||||
if test "$extra_charsets" = none; then
|
||||
CHARSETS=""
|
||||
elif test "$extra_charsets" = complex; then
|
||||
CHARSETS=`/bin/ls -1 $srcdir/strings/ctype-*.c | \
|
||||
sed -e 's;^.*/ctype-;;' -e 's;.c$;;'`
|
||||
CHARSETS=`echo $CHARSETS` # get rid of line breaks
|
||||
CHARSETS="$CHARSETS_COMPLEX"
|
||||
elif test "$extra_charsets" = all; then
|
||||
CHARSETS="$CHARSETS_AVAILABLE $CHARSETS_DEPRECATED"
|
||||
else
|
||||
if test "$extra_charsets" = all; then
|
||||
CHARSETS="$CHARSETS_AVAILABLE $CHARSETS_DEPRECATED"
|
||||
else
|
||||
CHARSETS=`echo $extra_charsets | sed -e 's/,/ /g'`
|
||||
fi
|
||||
CHARSETS=`echo $extra_charsets | sed -e 's/,/ /g'`
|
||||
fi
|
||||
|
||||
# Ensure that the default_charset is first in CHARSETS
|
||||
TMP_CHARSETS="$default_charset "
|
||||
for i in $CHARSETS
|
||||
do
|
||||
if test $i != $default_charset
|
||||
then
|
||||
TMP_CHARSETS="$TMP_CHARSETS $i"
|
||||
fi
|
||||
done
|
||||
CHARSETS=$TMP_CHARSETS
|
||||
CHARSETS="$DEFAULT_CHARSET $CHARSETS"
|
||||
|
||||
use_mb="no"
|
||||
|
||||
# Check if charsets are all good
|
||||
for cs in $CHARSETS
|
||||
do
|
||||
charset_okay=0
|
||||
for charset in $CHARSETS_AVAILABLE $CHARSETS_DEPRECATED
|
||||
do
|
||||
if test $cs = $charset; then charset_okay=1; fi
|
||||
done
|
||||
if test $charset_okay = 0;
|
||||
then
|
||||
AC_MSG_ERROR([Charset $cs not available. (Available $CHARSETS_AVAILABLE).
|
||||
See the Installation chapter in the Reference Manual.]);
|
||||
fi
|
||||
done
|
||||
|
||||
CHARSET_SRCS=""
|
||||
CHARSETS_NEED_SOURCE=""
|
||||
CHARSET_DECLARATIONS=""
|
||||
CHARSET_COMP_CS_INIT="CHARSET_INFO compiled_charsets[[]] = {"
|
||||
|
||||
want_use_strcoll=0
|
||||
want_use_mb=0
|
||||
|
||||
index_file="$srcdir/sql/share/charsets/Index"
|
||||
|
||||
for c in $CHARSETS
|
||||
do
|
||||
# get the charset number from $index_file
|
||||
changequote(,)dnl
|
||||
subpat='^'"${c}"'[ ][ ]*\([0-9][0-9]*\)[^0-9]*$'
|
||||
number=`sed -e "/$subpat/!d" -e 's//\1/' $index_file`
|
||||
changequote([,])dnl
|
||||
# some sanity checking....
|
||||
if test X"$number" = X
|
||||
then
|
||||
AC_MSG_ERROR([No number was found in $index_file for the $c character set. This is a bug in the MySQL distribution. Please report this message to bugs@lists.mysql.com.])
|
||||
fi
|
||||
|
||||
cs_file="$srcdir/strings/ctype-$c.c"
|
||||
if test -f $cs_file
|
||||
then
|
||||
CHARSET_SRCS="${CHARSET_SRCS}ctype-$c.c "
|
||||
# get the strxfrm multiplier and max mb len from files
|
||||
subpat='^.*\\.configure\\. strxfrm_multiply_'"${c}"'='
|
||||
strx=`$AWK 'sub("'"$subpat"'", "") { print }' $cs_file`
|
||||
subpat='^.*\\.configure\\. mbmaxlen_'"${c}"'='
|
||||
maxl=`$AWK 'sub("'"$subpat"'", "") { print }' $cs_file`
|
||||
|
||||
CHARSET_DECLARATIONS="$CHARSET_DECLARATIONS
|
||||
|
||||
/* declarations for the ${c} character set, filled in by configure */
|
||||
extern uchar ctype_${c}[[]], to_lower_${c}[[]], to_upper_${c}[[]], sort_order_${c}[[]];"
|
||||
else
|
||||
CHARSETS_NEED_SOURCE="$CHARSETS_NEED_SOURCE $c"
|
||||
strx=''
|
||||
maxl=''
|
||||
fi
|
||||
|
||||
CHARSET_COMP_CS_INIT="$CHARSET_COMP_CS_INIT
|
||||
|
||||
/* this information is filled in by configure */
|
||||
{
|
||||
$number, /* number */
|
||||
\"$c\", /* name */
|
||||
ctype_${c},
|
||||
to_lower_${c},
|
||||
to_upper_${c},
|
||||
sort_order_${c},"
|
||||
|
||||
if test -n "$strx"
|
||||
then
|
||||
want_use_strcoll=1
|
||||
|
||||
CHARSET_DECLARATIONS="$CHARSET_DECLARATIONS
|
||||
extern int my_strcoll_${c}(const uchar *, const uchar *);
|
||||
extern int my_strxfrm_${c}(uchar *, const uchar *, int);
|
||||
extern int my_strnncoll_${c}(const uchar *, int, const uchar *, int);
|
||||
extern int my_strnxfrm_${c}(uchar *, const uchar *, int, int);
|
||||
extern my_bool my_like_range_${c}(const char *, uint, pchar, uint,
|
||||
char *, char *, uint *, uint *);"
|
||||
|
||||
CHARSET_COMP_CS_INIT="$CHARSET_COMP_CS_INIT
|
||||
$strx, /* strxfrm_multiply */
|
||||
my_strcoll_${c},
|
||||
my_strxfrm_${c},
|
||||
my_strnncoll_${c},
|
||||
my_strnxfrm_${c},
|
||||
my_like_range_${c},"
|
||||
else
|
||||
CHARSET_COMP_CS_INIT="$CHARSET_COMP_CS_INIT
|
||||
0, /* strxfrm_multiply */
|
||||
NULL, /* strcoll */
|
||||
NULL, /* strxfrm */
|
||||
NULL, /* strnncoll */
|
||||
NULL, /* strnxfrm */
|
||||
NULL, /* like_range */"
|
||||
fi
|
||||
|
||||
if test -n "$maxl"
|
||||
then
|
||||
want_use_mb=1
|
||||
|
||||
CHARSET_DECLARATIONS="$CHARSET_DECLARATIONS
|
||||
extern int ismbchar_${c}(const char *, const char *);
|
||||
extern my_bool ismbhead_${c}(uint);
|
||||
extern int mbcharlen_${c}(uint);"
|
||||
|
||||
|
||||
CHARSET_COMP_CS_INIT="$CHARSET_COMP_CS_INIT
|
||||
$maxl, /* mbmaxlen */
|
||||
ismbchar_${c},
|
||||
ismbhead_${c},
|
||||
mbcharlen_${c}"
|
||||
else
|
||||
CHARSET_COMP_CS_INIT="$CHARSET_COMP_CS_INIT
|
||||
0, /* mbmaxlen */
|
||||
NULL, /* ismbchar */
|
||||
NULL, /* ismbhead */
|
||||
NULL /* mbcharlen */"
|
||||
fi
|
||||
CHARSET_COMP_CS_INIT="$CHARSET_COMP_CS_INIT
|
||||
},"
|
||||
case $cs in
|
||||
armscii8)
|
||||
AC_DEFINE(HAVE_CHARSET_armscii8)
|
||||
use_mb="yes"
|
||||
;;
|
||||
big5)
|
||||
AC_DEFINE(HAVE_CHARSET_big5)
|
||||
use_mb="yes"
|
||||
;;
|
||||
cp1251)
|
||||
AC_DEFINE(HAVE_CHARSET_cp1251)
|
||||
;;
|
||||
cp1257)
|
||||
AC_DEFINE(HAVE_CHARSET_cp1257)
|
||||
;;
|
||||
croat)
|
||||
AC_DEFINE(HAVE_CHARSET_croat)
|
||||
;;
|
||||
czech)
|
||||
AC_DEFINE(HAVE_CHARSET_czech)
|
||||
;;
|
||||
danish)
|
||||
AC_DEFINE(HAVE_CHARSET_danish)
|
||||
;;
|
||||
dec8)
|
||||
AC_DEFINE(HAVE_CHARSET_dec8)
|
||||
;;
|
||||
dos)
|
||||
AC_DEFINE(HAVE_CHARSET_dos)
|
||||
;;
|
||||
estonia)
|
||||
AC_DEFINE(HAVE_CHARSET_estonia)
|
||||
;;
|
||||
euc_kr)
|
||||
AC_DEFINE(HAVE_CHARSET_euc_kr)
|
||||
use_mb="yes"
|
||||
;;
|
||||
gb2312)
|
||||
AC_DEFINE(HAVE_CHARSET_gb2312)
|
||||
use_mb="yes"
|
||||
;;
|
||||
gbk)
|
||||
AC_DEFINE(HAVE_CHARSET_gbk)
|
||||
use_mb="yes"
|
||||
;;
|
||||
german1)
|
||||
AC_DEFINE(HAVE_CHARSET_german1)
|
||||
;;
|
||||
greek)
|
||||
AC_DEFINE(HAVE_CHARSET_greek)
|
||||
;;
|
||||
hebrew)
|
||||
AC_DEFINE(HAVE_CHARSET_hebrew)
|
||||
;;
|
||||
hp8)
|
||||
AC_DEFINE(HAVE_CHARSET_hp8)
|
||||
;;
|
||||
hungarian)
|
||||
AC_DEFINE(HAVE_CHARSET_hungarian)
|
||||
;;
|
||||
koi8_ru)
|
||||
AC_DEFINE(HAVE_CHARSET_koi8_ru)
|
||||
;;
|
||||
koi8_ukr)
|
||||
AC_DEFINE(HAVE_CHARSET_koi8_ukr)
|
||||
;;
|
||||
latin1)
|
||||
AC_DEFINE(HAVE_CHARSET_latin1)
|
||||
;;
|
||||
latin1_de)
|
||||
AC_DEFINE(HAVE_CHARSET_latin1_de)
|
||||
;;
|
||||
latin2)
|
||||
AC_DEFINE(HAVE_CHARSET_latin2)
|
||||
;;
|
||||
latin5)
|
||||
AC_DEFINE(HAVE_CHARSET_latin5)
|
||||
;;
|
||||
sjis)
|
||||
AC_DEFINE(HAVE_CHARSET_sjis)
|
||||
use_mb="yes"
|
||||
;;
|
||||
swe7)
|
||||
AC_DEFINE(HAVE_CHARSET_swe7)
|
||||
;;
|
||||
tis620)
|
||||
AC_DEFINE(HAVE_CHARSET_tis620)
|
||||
;;
|
||||
ujis)
|
||||
AC_DEFINE(HAVE_CHARSET_ujis)
|
||||
use_mb="yes"
|
||||
;;
|
||||
usa7)
|
||||
AC_DEFINE(HAVE_CHARSET_usa7)
|
||||
;;
|
||||
utf8)
|
||||
AC_DEFINE(HAVE_CHARSET_utf8)
|
||||
use_mb="yes"
|
||||
;;
|
||||
win1250)
|
||||
AC_DEFINE(HAVE_CHARSET_win1250)
|
||||
;;
|
||||
win1251)
|
||||
AC_DEFINE(HAVE_CHARSET_win1251)
|
||||
;;
|
||||
win1251ukr)
|
||||
AC_DEFINE(HAVE_CHARSET_win1251ukr)
|
||||
;;
|
||||
*)
|
||||
AC_MSG_ERROR([Charset $cs not available. (Available $CHARSETS_AVAILABLE).
|
||||
See the Installation chapter in the Reference Manual.]);
|
||||
esac
|
||||
done
|
||||
|
||||
CHARSET_COMP_CS_INIT="$CHARSET_COMP_CS_INIT
|
||||
|
||||
/* this information is filled in by configure */
|
||||
{
|
||||
0, /* end-of-list marker */
|
||||
NullS,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
0,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
0,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
}
|
||||
};"
|
||||
|
||||
|
||||
if test $want_use_strcoll = 1
|
||||
then
|
||||
AC_DEFINE(USE_STRCOLL)
|
||||
fi
|
||||
|
||||
if test $want_use_mb = 1
|
||||
if test "$use_mb" = "yes"
|
||||
then
|
||||
AC_DEFINE(USE_MB)
|
||||
AC_DEFINE(USE_MB_IDENT)
|
||||
fi
|
||||
|
||||
# Temporary hack for USE_STRCOLL
|
||||
AC_DEFINE(USE_STRCOLL)
|
||||
|
||||
AC_SUBST(default_charset)
|
||||
AC_SUBST(CHARSET_SRCS)
|
||||
CHARSET_OBJS="`echo "$CHARSET_SRCS" | sed -e 's/\.c /.o /g'`"
|
||||
AC_SUBST(CHARSET_OBJS)
|
||||
AC_SUBST(CHARSETS_NEED_SOURCE)
|
||||
|
||||
dnl We can't use AC_SUBST because these substitutions are too long.
|
||||
dnl I don't want to use sed, either, because there's a reason why
|
||||
dnl autoconf breaks up the substitution commands. So we'll just
|
||||
dnl write to a file and #include it.
|
||||
dnl AC_SUBST(CHARSET_DECLARATIONS)
|
||||
dnl AC_SUBST(CHARSET_COMP_CS_INIT)
|
||||
dnl sed -e "s%@CHARSET_DECLARATIONS@%$CHARSET_DECLARATIONS%g" \
|
||||
dnl -e "s%@CHARSET_COMP_CS_INIT@%$CHARSET_COMP_CS_INIT%g" \
|
||||
dnl $srcdir/strings/ctype.c.in > $srcdir/strings/ctype.c
|
||||
|
||||
cat <<EOF > $srcdir/strings/ctype_autoconf.c
|
||||
/* This file is generated automatically by configure. */$CHARSET_DECLARATIONS
|
||||
|
||||
$CHARSET_COMP_CS_INIT
|
||||
EOF
|
||||
AC_DEFINE_UNQUOTED(DEFAULT_CHARSET_NAME,"$default_charset")
|
||||
|
||||
AC_MSG_RESULT([default: $default_charset; compiled in: $CHARSETS])
|
||||
|
||||
|
@ -155,7 +155,7 @@ static int get_answer(QUESTION_WIDGET* w)
|
||||
char c;
|
||||
if (!fgets(buf,sizeof(buf),w->in))
|
||||
die("Failed fgets on input stream");
|
||||
switch ((c=tolower(*buf)))
|
||||
switch ((c=my_tolower(system_charset_info,*buf)))
|
||||
{
|
||||
case '\n':
|
||||
return w->default_ind;
|
||||
|
@ -113,7 +113,7 @@ char *argv[];
|
||||
exit(1);
|
||||
|
||||
for (i=1,pos=word_end_chars ; i < 256 ; i++)
|
||||
if (isspace(i))
|
||||
if (my_isspace(system_charset_info,i))
|
||||
*pos++=i;
|
||||
*pos=0;
|
||||
if (!(replace=init_replace((char**) from.typelib.type_names,
|
||||
|
@ -178,9 +178,9 @@ trace dump and specify the path to it with -s or --symbols-file");
|
||||
static uchar hex_val(char c)
|
||||
{
|
||||
uchar l;
|
||||
if(isdigit(c))
|
||||
if(my_isdigit(system_charset_info,c))
|
||||
return c - '0';
|
||||
l = tolower(c);
|
||||
l = my_tolower(system_charset_info,c);
|
||||
if(l < 'a' || l > 'f')
|
||||
return HEX_INVALID;
|
||||
return (uchar)10 + ((uchar)c - (uchar)'a');
|
||||
@ -206,10 +206,10 @@ static int init_sym_entry(SYM_ENTRY* se, char* buf)
|
||||
|
||||
if(!se->addr)
|
||||
return -1;
|
||||
while(isspace(*buf++))
|
||||
while ( my_isspace(system_charset_info,*buf++))
|
||||
/* empty */;
|
||||
|
||||
while(isspace(*buf++))
|
||||
while (my_isspace(system_charset_info,*buf++))
|
||||
/* empty - skip more space */;
|
||||
--buf;
|
||||
/* now we are on the symbol */
|
||||
@ -293,7 +293,7 @@ static void do_resolve()
|
||||
while(fgets(buf, sizeof(buf), fp_dump))
|
||||
{
|
||||
p = buf;
|
||||
while(isspace(*p))
|
||||
while(my_isspace(system_charset_info,*p))
|
||||
++p;
|
||||
/* skip space */;
|
||||
|
||||
|
@ -128,7 +128,7 @@ int main(int argc, char **argv)
|
||||
{
|
||||
ip = *argv++;
|
||||
|
||||
if (isdigit(ip[0]))
|
||||
if (my_isdigit(system_charset_info,ip[0]))
|
||||
{
|
||||
taddr = inet_addr(ip);
|
||||
if (taddr == htonl(INADDR_BROADCAST))
|
||||
|
@ -173,7 +173,7 @@ ulong _hp_hashnr(register HP_KEYDEF *keydef, register const byte *key)
|
||||
for (; pos < (uchar*) key ; pos++)
|
||||
{
|
||||
nr^=(ulong) ((((uint) nr & 63)+nr2) *
|
||||
((uint) my_sort_order[(uint) *pos])) + (nr << 8);
|
||||
((uint) default_charset_info->sort_order[(uint) *pos])) + (nr << 8);
|
||||
nr2+=3;
|
||||
}
|
||||
}
|
||||
@ -212,7 +212,7 @@ ulong _hp_rec_hashnr(register HP_KEYDEF *keydef, register const byte *rec)
|
||||
for (; pos < end ; pos++)
|
||||
{
|
||||
nr^=(ulong) ((((uint) nr & 63)+nr2)*
|
||||
((uint) my_sort_order[(uint) *pos]))+ (nr << 8);
|
||||
((uint) default_charset_info->sort_order[(uint) *pos]))+ (nr << 8);
|
||||
nr2+=3;
|
||||
}
|
||||
}
|
||||
@ -343,7 +343,7 @@ int _hp_rec_key_cmp(HP_KEYDEF *keydef, const byte *rec1, const byte *rec2)
|
||||
}
|
||||
if (seg->type == HA_KEYTYPE_TEXT)
|
||||
{
|
||||
if (my_sortcmp(rec1+seg->start,rec2+seg->start,seg->length))
|
||||
if (my_sortcmp(default_charset_info,rec1+seg->start,rec2+seg->start,seg->length))
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
@ -375,7 +375,12 @@ int _hp_key_cmp(HP_KEYDEF *keydef, const byte *rec, const byte *key)
|
||||
}
|
||||
if (seg->type == HA_KEYTYPE_TEXT)
|
||||
{
|
||||
if (my_sortcmp(rec+seg->start,key,seg->length))
|
||||
/*
|
||||
BAR TODO: this will not use default_charset_info
|
||||
I need Ram to apply his HEAP patches with
|
||||
CHARSET_INFO field in HP segments
|
||||
*/
|
||||
if (my_sortcmp(default_charset_info,rec+seg->start,key,seg->length))
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
|
@ -21,6 +21,11 @@
|
||||
int heap_rfirst(HP_INFO *info, byte *record)
|
||||
{
|
||||
DBUG_ENTER("heap_rfirst");
|
||||
if (!(info->s->records))
|
||||
{
|
||||
my_errno=HA_ERR_END_OF_FILE;
|
||||
DBUG_RETURN(my_errno);
|
||||
}
|
||||
info->current_record=0;
|
||||
info->current_hash_ptr=0;
|
||||
info->update=HA_STATE_PREV_FOUND;
|
||||
|
@ -40,13 +40,15 @@ typedef struct st_hash {
|
||||
DYNAMIC_ARRAY array; /* Place for hash_keys */
|
||||
hash_get_key get_key;
|
||||
void (*free)(void *);
|
||||
uint (*calc_hashnr)(const byte *key,uint length);
|
||||
uint (*calc_hashnr)(CHARSET_INFO *cs, const byte *key,uint length);
|
||||
CHARSET_INFO *charset;
|
||||
} HASH;
|
||||
|
||||
#define hash_init(A,B,C,D,E,F,G) _hash_init(A,B,C,D,E,F,G CALLER_INFO)
|
||||
my_bool _hash_init(HASH *hash,uint default_array_elements, uint key_offset,
|
||||
uint key_length, hash_get_key get_key,
|
||||
void (*free_element)(void*), uint flags CALLER_INFO_PROTO);
|
||||
#define hash_init(A,B,C,D,E,F,G) _hash_init(A,B,C,D,E,F,G, H CALLER_INFO)
|
||||
my_bool _hash_init(HASH *hash, CHARSET_INFO *charset,
|
||||
uint default_array_elements, uint key_offset,
|
||||
uint key_length, hash_get_key get_key,
|
||||
void (*free_element)(void*), uint flags CALLER_INFO_PROTO);
|
||||
void hash_free(HASH *tree);
|
||||
byte *hash_element(HASH *hash,uint idx);
|
||||
gptr hash_search(HASH *info,const byte *key,uint length);
|
||||
|
@ -26,8 +26,29 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
#define CHARSET_DIR "charsets/"
|
||||
|
||||
#define my_wc_t ulong
|
||||
|
||||
typedef struct unicase_info_st {
|
||||
uint16 toupper;
|
||||
uint16 tolower;
|
||||
uint16 sort;
|
||||
} MY_UNICASE_INFO;
|
||||
|
||||
#define MY_CS_ILSEQ 0
|
||||
#define MY_CS_ILUNI 0
|
||||
#define MY_CS_TOOSMALL -1
|
||||
#define MY_CS_TOOFEW(n) (-1-(n))
|
||||
|
||||
typedef struct my_uni_idx_st {
|
||||
uint16 from;
|
||||
uint16 to;
|
||||
uchar *tab;
|
||||
} MY_UNI_IDX;
|
||||
|
||||
|
||||
typedef struct charset_info_st
|
||||
{
|
||||
uint number;
|
||||
@ -36,23 +57,47 @@ typedef struct charset_info_st
|
||||
uchar *to_lower;
|
||||
uchar *to_upper;
|
||||
uchar *sort_order;
|
||||
|
||||
uint16 *tab_to_uni;
|
||||
MY_UNI_IDX *tab_from_uni;
|
||||
|
||||
/* Collation routines */
|
||||
uint strxfrm_multiply;
|
||||
int (*strcoll)(const uchar *, const uchar *);
|
||||
int (*strxfrm)(uchar *, const uchar *, int);
|
||||
int (*strnncoll)(const uchar *, int, const uchar *, int);
|
||||
int (*strnxfrm)(uchar *, const uchar *, int, int);
|
||||
my_bool (*like_range)(const char *, uint, pchar, uint,
|
||||
int (*strnncoll)(struct charset_info_st *,
|
||||
const uchar *, uint, const uchar *, uint);
|
||||
int (*strnxfrm)(struct charset_info_st *,
|
||||
uchar *, uint, const uchar *, uint);
|
||||
my_bool (*like_range)(struct charset_info_st *,
|
||||
const char *, uint, pchar, uint,
|
||||
char *, char *, uint *, uint *);
|
||||
|
||||
|
||||
/* Multibyte routines */
|
||||
uint mbmaxlen;
|
||||
int (*ismbchar)(const char *, const char *);
|
||||
my_bool (*ismbhead)(uint);
|
||||
int (*mbcharlen)(uint);
|
||||
int (*ismbchar)(struct charset_info_st *, const char *, const char *);
|
||||
my_bool (*ismbhead)(struct charset_info_st *, uint);
|
||||
int (*mbcharlen)(struct charset_info_st *, uint);
|
||||
|
||||
/* Unicode convertion */
|
||||
int (*mb_wc)(struct charset_info_st *cs,my_wc_t *wc,
|
||||
const unsigned char *s,const unsigned char *e);
|
||||
int (*wc_mb)(struct charset_info_st *cs,my_wc_t wc,
|
||||
unsigned char *s,unsigned char *e);
|
||||
|
||||
/* Functions for case convertion */
|
||||
void (*caseup_str)(struct charset_info_st *, char *);
|
||||
void (*casedn_str)(struct charset_info_st *, char *);
|
||||
void (*caseup)(struct charset_info_st *, char *, uint);
|
||||
void (*casedn)(struct charset_info_st *, char *, uint);
|
||||
|
||||
/* Functions for case comparison */
|
||||
int (*strcasecmp)(struct charset_info_st *, const char *, const char *);
|
||||
int (*strncasecmp)(struct charset_info_st *, const char *, const char *, uint);
|
||||
|
||||
char max_sort_char; /* For LIKE otimization */
|
||||
} CHARSET_INFO;
|
||||
|
||||
/* strings/ctype.c */
|
||||
extern CHARSET_INFO *default_charset_info;
|
||||
extern CHARSET_INFO *system_charset_info;
|
||||
extern CHARSET_INFO *find_compiled_charset(uint cs_number);
|
||||
extern CHARSET_INFO *find_compiled_charset_by_name(const char *name);
|
||||
extern CHARSET_INFO compiled_charsets[];
|
||||
@ -62,32 +107,160 @@ extern const char *compiled_charset_name(uint charset_number);
|
||||
#define MY_CHARSET_UNDEFINED 0
|
||||
#define MY_CHARSET_CURRENT (default_charset_info->number)
|
||||
|
||||
/* Don't include std ctype.h when this is included */
|
||||
#define _CTYPE_H
|
||||
#define _CTYPE_H_
|
||||
#define _CTYPE_INCLUDED
|
||||
#define __CTYPE_INCLUDED
|
||||
#define _CTYPE_USING /* Don't put names in global namespace. */
|
||||
/* declarations for simple charsets */
|
||||
extern int my_strnxfrm_simple(CHARSET_INFO *, char *, uint, const char *, uint);
|
||||
extern int my_strnncoll_simple(CHARSET_INFO *, const char *, uint, const char *, uint);
|
||||
|
||||
/* Fix things, if ctype.h would have been included before */
|
||||
#undef toupper
|
||||
#undef _toupper
|
||||
#undef _tolower
|
||||
#undef toupper
|
||||
#undef tolower
|
||||
#undef isalpha
|
||||
#undef isupper
|
||||
#undef islower
|
||||
#undef isdigit
|
||||
#undef isxdigit
|
||||
#undef isalnum
|
||||
#undef isspace
|
||||
#undef ispunct
|
||||
#undef isprint
|
||||
#undef isgraph
|
||||
#undef iscntrl
|
||||
#undef isascii
|
||||
#undef toascii
|
||||
/* Functions for 8bit */
|
||||
extern void my_caseup_str_8bit(CHARSET_INFO *, char *);
|
||||
extern void my_casedn_str_8bit(CHARSET_INFO *, char *);
|
||||
extern void my_caseup_8bit(CHARSET_INFO *, char *, uint);
|
||||
extern void my_casedn_8bit(CHARSET_INFO *, char *, uint);
|
||||
|
||||
extern int my_strcasecmp_8bit(CHARSET_INFO * cs, const char *, const char *);
|
||||
extern int my_strncasecmp_8bit(CHARSET_INFO * cs, const char *, const char *, uint);
|
||||
|
||||
int my_mb_wc_8bit(CHARSET_INFO *cs,my_wc_t *wc, const uchar *s,const uchar *e);
|
||||
int my_wc_mb_8bit(CHARSET_INFO *cs,my_wc_t wc, uchar *s, uchar *e);
|
||||
|
||||
|
||||
#ifdef USE_MB
|
||||
/* Functions for multibyte charsets */
|
||||
extern void my_caseup_str_mb(CHARSET_INFO *, char *);
|
||||
extern void my_casedn_str_mb(CHARSET_INFO *, char *);
|
||||
extern void my_caseup_mb(CHARSET_INFO *, char *, uint);
|
||||
extern void my_casedn_mb(CHARSET_INFO *, char *, uint);
|
||||
extern int my_strcasecmp_mb(CHARSET_INFO * cs,const char *, const char *);
|
||||
extern int my_strncasecmp_mb(CHARSET_INFO * cs,const char *, const char *t, uint);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_CHARSET_big5
|
||||
/* declarations for the big5 character set */
|
||||
extern uchar ctype_big5[], to_lower_big5[], to_upper_big5[], sort_order_big5[];
|
||||
extern int my_strnncoll_big5(CHARSET_INFO *,const uchar *, uint, const uchar *, uint);
|
||||
extern int my_strnxfrm_big5(CHARSET_INFO *,uchar *, uint, const uchar *, uint);
|
||||
extern my_bool my_like_range_big5(CHARSET_INFO *,const char *, uint, pchar, uint,
|
||||
char *, char *, uint *, uint *);
|
||||
extern int ismbchar_big5(CHARSET_INFO *, const char *, const char *);
|
||||
extern my_bool ismbhead_big5(CHARSET_INFO *, uint);
|
||||
extern int mbcharlen_big5(CHARSET_INFO *, uint);
|
||||
int my_mb_wc_big5(CHARSET_INFO *cs,my_wc_t *wc, const uchar *s,const uchar *e);
|
||||
int my_wc_mb_big5(CHARSET_INFO *cs,my_wc_t wc, uchar *s, uchar *e);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_CHARSET_czech
|
||||
/* declarations for the czech character set */
|
||||
extern uchar ctype_czech[], to_lower_czech[], to_upper_czech[], sort_order_czech[];
|
||||
extern int my_strnncoll_czech(CHARSET_INFO *, const uchar *, uint, const uchar *, uint);
|
||||
extern int my_strnxfrm_czech(CHARSET_INFO *, uchar *, uint, const uchar *, uint);
|
||||
extern my_bool my_like_range_czech(CHARSET_INFO *,
|
||||
const char *, uint, pchar, uint,
|
||||
char *, char *, uint *, uint *);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_CHARSET_euc_kr
|
||||
/* declarations for the euc_kr character set */
|
||||
extern uchar ctype_euc_kr[], to_lower_euc_kr[], to_upper_euc_kr[], sort_order_euc_kr[];
|
||||
extern int ismbchar_euc_kr(CHARSET_INFO *, const char *, const char *);
|
||||
extern my_bool ismbhead_euc_kr(CHARSET_INFO *, uint);
|
||||
extern int mbcharlen_euc_kr(CHARSET_INFO *, uint);
|
||||
int my_mb_wc_euc_kr(CHARSET_INFO *cs,my_wc_t *wc, const uchar *s,const uchar *e);
|
||||
int my_wc_mb_euc_kr(CHARSET_INFO *cs,my_wc_t wc, uchar *s, uchar *e);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_CHARSET_gb2312
|
||||
/* declarations for the gb2312 character set */
|
||||
extern uchar ctype_gb2312[], to_lower_gb2312[], to_upper_gb2312[], sort_order_gb2312[];
|
||||
extern int ismbchar_gb2312(CHARSET_INFO *, const char *, const char *);
|
||||
extern my_bool ismbhead_gb2312(CHARSET_INFO *, uint);
|
||||
extern int mbcharlen_gb2312(CHARSET_INFO *, uint);
|
||||
int my_mb_wc_gb2312(CHARSET_INFO *cs,my_wc_t *wc, const uchar *s,const uchar *e);
|
||||
int my_wc_mb_gb2312(CHARSET_INFO *cs,my_wc_t wc, uchar *s, uchar *e);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_CHARSET_gbk
|
||||
/* declarations for the gbk character set */
|
||||
extern uchar ctype_gbk[], to_lower_gbk[], to_upper_gbk[], sort_order_gbk[];
|
||||
extern int my_strnncoll_gbk(CHARSET_INFO *, const uchar *, uint, const uchar *, uint);
|
||||
extern int my_strnxfrm_gbk(CHARSET_INFO *, uchar *, uint, const uchar *, uint);
|
||||
extern my_bool my_like_range_gbk(CHARSET_INFO *, const char *, uint, pchar, uint,
|
||||
char *, char *, uint *, uint *);
|
||||
extern int ismbchar_gbk(CHARSET_INFO *, const char *, const char *);
|
||||
extern my_bool ismbhead_gbk(CHARSET_INFO *, uint);
|
||||
extern int mbcharlen_gbk(CHARSET_INFO *, uint);
|
||||
int my_mb_wc_gbk(CHARSET_INFO *cs,my_wc_t *wc, const uchar *s,const uchar *e);
|
||||
int my_wc_mb_gbk(CHARSET_INFO *cs,my_wc_t wc, uchar *s, uchar *e);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_CHARSET_latin1_de
|
||||
/* declarations for the latin1_de character set */
|
||||
extern uchar ctype_latin1_de[], to_lower_latin1_de[], to_upper_latin1_de[], sort_order_latin1_de[];
|
||||
extern int my_strnncoll_latin1_de(CHARSET_INFO *, const uchar *, uint, const uchar *, uint);
|
||||
extern int my_strnxfrm_latin1_de(CHARSET_INFO *, uchar *, uint, const uchar *, uint);
|
||||
extern my_bool my_like_range_latin1_de(CHARSET_INFO *, const char *, uint, pchar, uint,
|
||||
char *, char *, uint *, uint *);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_CHARSET_sjis
|
||||
/* declarations for the sjis character set */
|
||||
extern uchar ctype_sjis[], to_lower_sjis[], to_upper_sjis[], sort_order_sjis[];
|
||||
extern int my_strnncoll_sjis(CHARSET_INFO *, const uchar *, uint, const uchar *, uint);
|
||||
extern int my_strnxfrm_sjis(CHARSET_INFO *, uchar *, uint, const uchar *, uint);
|
||||
extern my_bool my_like_range_sjis(CHARSET_INFO *, const char *, uint, pchar, uint,
|
||||
char *, char *, uint *, uint *);
|
||||
extern int ismbchar_sjis(CHARSET_INFO *, const char *, const char *);
|
||||
extern my_bool ismbhead_sjis(CHARSET_INFO *, uint);
|
||||
extern int mbcharlen_sjis(CHARSET_INFO *, uint);
|
||||
int my_mb_wc_sjis(CHARSET_INFO *cs,my_wc_t *wc, const uchar *s,const uchar *e);
|
||||
int my_wc_mb_sjis(CHARSET_INFO *cs,my_wc_t wc, uchar *s, uchar *e);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_CHARSET_tis620
|
||||
/* declarations for the tis620 character set */
|
||||
extern uchar ctype_tis620[], to_lower_tis620[], to_upper_tis620[], sort_order_tis620[];
|
||||
extern int my_strnncoll_tis620(CHARSET_INFO *, const uchar *, uint, const uchar *, uint);
|
||||
extern int my_strnxfrm_tis620(CHARSET_INFO *, uchar *, uint, const uchar *, uint);
|
||||
extern my_bool my_like_range_tis620(CHARSET_INFO *, const char *, uint, pchar, uint,
|
||||
char *, char *, uint *, uint *);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_CHARSET_ujis
|
||||
/* declarations for the ujis character set */
|
||||
extern uchar ctype_ujis[], to_lower_ujis[], to_upper_ujis[], sort_order_ujis[];
|
||||
extern int ismbchar_ujis(CHARSET_INFO *, const char *, const char *);
|
||||
extern my_bool ismbhead_ujis(CHARSET_INFO *, uint);
|
||||
extern int mbcharlen_ujis(CHARSET_INFO *, uint);
|
||||
int my_mb_wc_euc_jp(CHARSET_INFO *cs,my_wc_t *wc, const uchar *s,const uchar *e);
|
||||
int my_wc_mb_euc_jp(CHARSET_INFO *cs,my_wc_t wc, uchar *s, uchar *e);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_CHARSET_utf8
|
||||
|
||||
extern uchar ctype_utf8[];
|
||||
extern uchar to_lower_utf8[];
|
||||
extern uchar to_upper_utf8[];
|
||||
|
||||
int my_strnncoll_utf8(CHARSET_INFO *cs,
|
||||
const uchar *s, uint s_len, const uchar *t, uint t_len);
|
||||
|
||||
int my_strnxfrm_utf8(CHARSET_INFO *cs,
|
||||
uchar *dest, uint destlen, const uchar *src, uint srclen);
|
||||
|
||||
int my_ismbchar_utf8(CHARSET_INFO *cs, const char *b, const char *e);
|
||||
my_bool my_ismbhead_utf8(CHARSET_INFO * cs, uint ch);
|
||||
int my_mbcharlen_utf8(CHARSET_INFO *cs, uint c);
|
||||
|
||||
void my_caseup_str_utf8(CHARSET_INFO * cs, char * s);
|
||||
void my_casedn_str_utf8(CHARSET_INFO *cs, char * s);
|
||||
void my_caseup_utf8(CHARSET_INFO *cs, char *s, uint len);
|
||||
void my_casedn_utf8(CHARSET_INFO *cs, char *s, uint len);
|
||||
|
||||
int my_strcasecmp_utf8(CHARSET_INFO *cs, const char *s, const char *t);
|
||||
int my_strncasecmp_utf8(CHARSET_INFO *cs, const char *s,const char *t,uint l);
|
||||
|
||||
int my_utf8_uni (CHARSET_INFO *cs, my_wc_t *p, const uchar *s, const uchar *e);
|
||||
int my_uni_utf8 (CHARSET_INFO *cs, my_wc_t wc, uchar *b, uchar *e);
|
||||
#endif
|
||||
|
||||
#define _U 01 /* Upper case */
|
||||
#define _L 02 /* Lower case */
|
||||
@ -98,34 +271,13 @@ extern const char *compiled_charset_name(uint charset_number);
|
||||
#define _B 0100 /* Blank */
|
||||
#define _X 0200 /* heXadecimal digit */
|
||||
|
||||
#define my_ctype (default_charset_info->ctype)
|
||||
#define my_to_upper (default_charset_info->to_upper)
|
||||
#define my_to_lower (default_charset_info->to_lower)
|
||||
#define my_sort_order (default_charset_info->sort_order)
|
||||
|
||||
#define _toupper(c) (char) my_to_upper[(uchar) (c)]
|
||||
#define _tolower(c) (char) my_to_lower[(uchar) (c)]
|
||||
#define toupper(c) (char) my_to_upper[(uchar) (c)]
|
||||
#define tolower(c) (char) my_to_lower[(uchar) (c)]
|
||||
|
||||
#define isalpha(c) ((my_ctype+1)[(uchar) (c)] & (_U | _L))
|
||||
#define isupper(c) ((my_ctype+1)[(uchar) (c)] & _U)
|
||||
#define islower(c) ((my_ctype+1)[(uchar) (c)] & _L)
|
||||
#define isdigit(c) ((my_ctype+1)[(uchar) (c)] & _NMR)
|
||||
#define isxdigit(c) ((my_ctype+1)[(uchar) (c)] & _X)
|
||||
#define isalnum(c) ((my_ctype+1)[(uchar) (c)] & (_U | _L | _NMR))
|
||||
#define isspace(c) ((my_ctype+1)[(uchar) (c)] & _SPC)
|
||||
#define ispunct(c) ((my_ctype+1)[(uchar) (c)] & _PNT)
|
||||
#define isprint(c) ((my_ctype+1)[(uchar) (c)] & (_PNT | _U | _L | _NMR | _B))
|
||||
#define isgraph(c) ((my_ctype+1)[(uchar) (c)] & (_PNT | _U | _L | _NMR))
|
||||
#define iscntrl(c) ((my_ctype+1)[(uchar) (c)] & _CTR)
|
||||
#define isascii(c) (!((c) & ~0177))
|
||||
#define toascii(c) ((c) & 0177)
|
||||
|
||||
#ifdef ctype
|
||||
#undef ctype
|
||||
#endif /* ctype */
|
||||
|
||||
#define my_isascii(c) (!((c) & ~0177))
|
||||
#define my_toascii(c) ((c) & 0177)
|
||||
#define my_tocntrl(c) ((c) & 31)
|
||||
#define my_toprint(c) ((c) | 64)
|
||||
#define my_toupper(s,c) (char) ((s)->to_upper[(uchar) (c)])
|
||||
#define my_tolower(s,c) (char) ((s)->to_lower[(uchar) (c)])
|
||||
#define my_isalpha(s, c) (((s)->ctype+1)[(uchar) (c)] & (_U | _L))
|
||||
#define my_isupper(s, c) (((s)->ctype+1)[(uchar) (c)] & _U)
|
||||
#define my_islower(s, c) (((s)->ctype+1)[(uchar) (c)] & _L)
|
||||
@ -138,26 +290,28 @@ extern const char *compiled_charset_name(uint charset_number);
|
||||
#define my_isgraph(s, c) (((s)->ctype+1)[(uchar) (c)] & (_PNT | _U | _L | _NMR))
|
||||
#define my_iscntrl(s, c) (((s)->ctype+1)[(uchar) (c)] & _CTR)
|
||||
|
||||
#define use_strcoll(s) ((s)->strcoll != NULL)
|
||||
#define MY_STRXFRM_MULTIPLY (default_charset_info->strxfrm_multiply)
|
||||
#define my_strnxfrm(s, a, b, c, d) ((s)->strnxfrm((a), (b), (c), (d)))
|
||||
#define my_strnncoll(s, a, b, c, d) ((s)->strnncoll((a), (b), (c), (d)))
|
||||
#define my_strxfrm(s, a, b, c, d) ((s)->strnxfrm((a), (b), (c)))
|
||||
#define my_strcoll(s, a, b) ((s)->strcoll((a), (b)))
|
||||
/* Some macros that should be cleaned up a little */
|
||||
#define my_isvar(s,c) (my_isalnum(s,c) || (c) == '_')
|
||||
#define my_isvar_start(s,c) (my_isalpha(s,c) || (c) == '_')
|
||||
|
||||
#define use_strcoll(s) ((s)->strnncoll != NULL)
|
||||
#define my_strnxfrm(s, a, b, c, d) ((s)->strnxfrm((s), (a), (b), (c), (d)))
|
||||
#define my_strnncoll(s, a, b, c, d) ((s)->strnncoll((s), (a), (b), (c), (d)))
|
||||
#define my_like_range(s, a, b, c, d, e, f, g, h) \
|
||||
((s)->like_range((a), (b), (c), (d), (e), (f), (g), (h)))
|
||||
((s)->like_range((s), (a), (b), (c), (d), (e), (f), (g), (h)))
|
||||
|
||||
#define use_mb(s) ((s)->ismbchar != NULL)
|
||||
#define MBMAXLEN (default_charset_info->mbmaxlen)
|
||||
#define my_ismbchar(s, a, b) ((s)->ismbchar((a), (b)))
|
||||
#define my_ismbhead(s, a) ((s)->ismbhead((a)))
|
||||
#define my_mbcharlen(s, a) ((s)->mbcharlen((a)))
|
||||
#define my_ismbchar(s, a, b) ((s)->ismbchar((s), (a), (b)))
|
||||
#define my_ismbhead(s, a) ((s)->ismbhead((s), (a)))
|
||||
#define my_mbcharlen(s, a) ((s)->mbcharlen((s),(a)))
|
||||
|
||||
#define my_caseup(s, a, l) ((s)->caseup((s), (a), (l)))
|
||||
#define my_casedn(s, a, l) ((s)->casedn((s), (a), (l)))
|
||||
#define my_caseup_str(s, a) ((s)->caseup_str((s), (a)))
|
||||
#define my_casedn_str(s, a) ((s)->casedn_str((s), (a)))
|
||||
#define my_strcasecmp(s, a, b) ((s)->strcasecmp((s), (a), (b)))
|
||||
#define my_strncasecmp(s, a, b, l) ((s)->strncasecmp((s), (a), (b), (l)))
|
||||
|
||||
/* Some macros that should be cleaned up a little */
|
||||
#define isvar(c) (isalnum(c) || (c) == '_')
|
||||
#define isvar_start(c) (isalpha(c) || (c) == '_')
|
||||
#define tocntrl(c) ((c) & 31)
|
||||
#define toprint(c) ((c) | 64)
|
||||
|
||||
/* XXX: still need to take care of this one */
|
||||
#ifdef MY_CHARSET_TIS620
|
||||
|
@ -572,11 +572,7 @@ extern void allow_break(void);
|
||||
#endif
|
||||
|
||||
extern void my_remember_signal(int signal_number,sig_handler (*func)(int));
|
||||
extern void caseup(my_string str,uint length);
|
||||
extern void casedn(my_string str,uint length);
|
||||
extern void caseup_str(my_string str);
|
||||
extern void casedn_str(my_string str);
|
||||
extern void case_sort(my_string str,uint length);
|
||||
extern void case_sort(CHARSET_INFO *cs, my_string str,uint length);
|
||||
extern uint dirname_part(my_string to,const char *name);
|
||||
extern uint dirname_length(const char *name);
|
||||
#define base_name(A) (A+dirname_length(A))
|
||||
@ -601,18 +597,14 @@ extern my_string my_path(my_string to,const char *progname,
|
||||
extern my_string my_load_path(my_string to, const char *path,
|
||||
const char *own_path_prefix);
|
||||
extern int wild_compare(const char *str,const char *wildstr);
|
||||
extern my_string my_strcasestr(const char *src,const char *suffix);
|
||||
extern int my_strcasecmp(const char *s,const char *t);
|
||||
extern int my_strsortcmp(const char *s,const char *t);
|
||||
extern int my_casecmp(const char *s,const char *t,uint length);
|
||||
extern int my_sortcmp(const char *s,const char *t,uint length);
|
||||
extern int my_sortncmp(const char *s,uint s_len, const char *t,uint t_len);
|
||||
extern int my_sortcmp(CHARSET_INFO *cs, const char *s,const char *t,uint length);
|
||||
extern int my_sortncmp(CHARSET_INFO *cs, const char *s,uint s_len, const char *t,uint t_len);
|
||||
extern WF_PACK *wf_comp(my_string str);
|
||||
extern int wf_test(struct wild_file_pack *wf_pack,const char *name);
|
||||
extern void wf_end(struct wild_file_pack *buffer);
|
||||
extern size_s stripp_sp(my_string str);
|
||||
extern void get_date(my_string to,int timeflag,time_t use_time);
|
||||
extern void soundex(my_string out_pntr, my_string in_pntr,pbool remove_garbage);
|
||||
extern void soundex(CHARSET_INFO *, my_string out_pntr, my_string in_pntr,pbool remove_garbage);
|
||||
extern int init_record_cache(RECORD_CACHE *info,uint cachesize,File file,
|
||||
uint reclength,enum cache_type type,
|
||||
pbool use_async_io);
|
||||
|
@ -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;
|
||||
|
||||
|
||||
|
@ -58,7 +58,7 @@ uint _nisam_make_key(register N_INFO *info, uint keynr, uchar *key, const char *
|
||||
#endif
|
||||
{
|
||||
if (type == HA_KEYTYPE_TEXT)
|
||||
case_sort((byte*) key,length);
|
||||
case_sort(default_charset_info,(byte*) key,length);
|
||||
}
|
||||
key+=length;
|
||||
}
|
||||
@ -71,7 +71,7 @@ uint _nisam_make_key(register N_INFO *info, uint keynr, uchar *key, const char *
|
||||
#endif
|
||||
{
|
||||
if (type == HA_KEYTYPE_TEXT)
|
||||
case_sort((byte*) key,(uint) keyseg->base.length);
|
||||
case_sort(default_charset_info,(byte*) key,(uint) keyseg->base.length);
|
||||
}
|
||||
#ifdef NAN_TEST
|
||||
else if (type == HA_KEYTYPE_FLOAT)
|
||||
@ -154,7 +154,7 @@ uint _nisam_pack_key(register N_INFO *info, uint keynr, uchar *key, uchar *old,
|
||||
#endif
|
||||
{
|
||||
if (type == HA_KEYTYPE_TEXT)
|
||||
case_sort((byte*) key,length);
|
||||
case_sort(default_charset_info,(byte*) key,length);
|
||||
}
|
||||
key+= length;
|
||||
}
|
||||
|
@ -515,11 +515,13 @@ int _nisam_key_cmp(register N_KEYSEG *keyseg, register uchar *a, register uchar
|
||||
if (*a++ != *b++)
|
||||
{
|
||||
a--; b--;
|
||||
if (isdigit((char) *a) && isdigit((char) *b))
|
||||
if (my_isdigit(default_charset_info, (char) *a) &&
|
||||
my_isdigit(default_charset_info, (char) *b))
|
||||
return ((int) *a - (int) *b);
|
||||
if (*a == '-' || isdigit((char) *b))
|
||||
if (*a == '-' || my_isdigit(default_charset_info,(char) *b))
|
||||
return (-1);
|
||||
if (*b == '-' || *b++ == ' ' || isdigit((char) *a))
|
||||
if (*b == '-' || *b++ == ' ' ||
|
||||
my_isdigit(default_charset_info,(char) *a))
|
||||
return (1);
|
||||
if (*a++ == ' ')
|
||||
return (-1);
|
||||
@ -539,11 +541,13 @@ int _nisam_key_cmp(register N_KEYSEG *keyseg, register uchar *a, register uchar
|
||||
if (*a++ != *b++)
|
||||
{
|
||||
a--; b--;
|
||||
if (isdigit((char) *a) && isdigit((char) *b))
|
||||
if (my_isdigit(default_charset_info,(char) *a) &&
|
||||
my_isdigit(default_charset_info,(char) *b))
|
||||
return ((int) *a - (int) *b);
|
||||
if (*a == '-' || isdigit((char) *b))
|
||||
if (*a == '-' || my_isdigit(default_charset_info,(char) *b))
|
||||
return (-1);
|
||||
if (*b == '-' || *b++ == ' ' || isdigit((char) *a))
|
||||
if (*b == '-' || *b++ == ' ' ||
|
||||
my_isdigit(default_charset_info,(char) *a))
|
||||
return (1);
|
||||
if (*a++ == ' ')
|
||||
return -1;
|
||||
|
@ -27,9 +27,6 @@ pkglib_LTLIBRARIES = $(target)
|
||||
|
||||
noinst_PROGRAMS = conf_to_src
|
||||
|
||||
# We need .lo, not .o files for everything.
|
||||
CHARSET_OBJS=@CHARSET_OBJS@
|
||||
LTCHARSET_OBJS= ${CHARSET_OBJS:.o=.lo}
|
||||
|
||||
target_sources = libmysql.c net.c password.c manager.c \
|
||||
get_password.c errmsg.c
|
||||
@ -41,8 +38,12 @@ mystringsobjects = strmov.lo strxmov.lo strxnmov.lo strnmov.lo \
|
||||
strcend.lo bcmp.lo \
|
||||
bchange.lo bmove.lo bmove_upp.lo longlong2str.lo \
|
||||
strtoull.lo strtoll.lo llstr.lo \
|
||||
ctype.lo $(LTCHARSET_OBJS)
|
||||
mystringsextra= strto.c ctype_autoconf.c
|
||||
ctype.lo ctype-simple.lo ctype-mb.lo \
|
||||
ctype-big5.lo ctype-czech.lo ctype-euc_kr.lo \
|
||||
ctype-gb2312.lo ctype-gbk.lo ctype-latin1_de.lo \
|
||||
ctype-sjis.lo ctype-tis620.lo ctype-ujis.lo ctype-utf8.lo
|
||||
|
||||
mystringsextra= strto.c
|
||||
dbugobjects = dbug.lo # IT IS IN SAFEMALLOC.C sanity.lo
|
||||
mysysheaders = mysys_priv.h my_static.h
|
||||
mysysobjects1 = my_init.lo my_static.lo my_malloc.lo my_realloc.lo \
|
||||
@ -75,20 +76,16 @@ DEFS = -DDEFAULT_CHARSET_HOME="\"$(MYSQLBASEdir)\"" \
|
||||
-DSHAREDIR="\"$(MYSQLSHAREdir)\"" $(target_defs)
|
||||
|
||||
# The automatic dependencies miss this
|
||||
bmove_upp.lo: $(LTCHARSET_OBJS)
|
||||
ctype.lo: ctype_extra_sources.c
|
||||
#bmove_upp.lo: $(LTCHARSET_OBJS)
|
||||
|
||||
clean-local:
|
||||
rm -f `echo $(mystringsobjects) | sed "s;\.lo;.c;g"` \
|
||||
`echo $(dbugobjects) | sed "s;\.lo;.c;g"` \
|
||||
`echo $(mysysobjects) | sed "s;\.lo;.c;g"` \
|
||||
`echo $(vio_objects) | sed "s;\.lo;.c;g"` \
|
||||
$(mystringsextra) $(mysysheaders) ctype_extra_sources.c \
|
||||
$(mystringsextra) $(mysysheaders) \
|
||||
../linked_client_sources
|
||||
|
||||
ctype_extra_sources.c: conf_to_src
|
||||
./conf_to_src $(top_srcdir) @CHARSETS_NEED_SOURCE@ > \
|
||||
$(srcdir)/ctype_extra_sources.c
|
||||
conf_to_src_SOURCES = conf_to_src.c
|
||||
conf_to_src_LDADD=
|
||||
#force static linking of conf_to_src - essential when linking against
|
||||
|
@ -1282,8 +1282,8 @@ STDCALL mysql_rpl_query_type(const char* q, int len)
|
||||
for(; q < q_end; ++q)
|
||||
{
|
||||
char c;
|
||||
if (isalpha(c=*q))
|
||||
switch(tolower(c))
|
||||
if (my_isalpha(system_charset_info,c=*q))
|
||||
switch(my_tolower(system_charset_info,c))
|
||||
{
|
||||
case 'i': /* insert */
|
||||
case 'u': /* update or unlock tables */
|
||||
@ -1292,9 +1292,11 @@ STDCALL mysql_rpl_query_type(const char* q, int len)
|
||||
case 'a': /* alter */
|
||||
return MYSQL_RPL_MASTER;
|
||||
case 'c': /* create or check */
|
||||
return tolower(q[1]) == 'h' ? MYSQL_RPL_ADMIN : MYSQL_RPL_MASTER ;
|
||||
return my_tolower(system_charset_info,q[1]) == 'h' ? MYSQL_RPL_ADMIN :
|
||||
MYSQL_RPL_MASTER;
|
||||
case 's': /* select or show */
|
||||
return tolower(q[1]) == 'h' ? MYSQL_RPL_ADMIN : MYSQL_RPL_SLAVE;
|
||||
return my_tolower(system_charset_info,q[1]) == 'h' ? MYSQL_RPL_ADMIN :
|
||||
MYSQL_RPL_SLAVE;
|
||||
case 'f': /* flush */
|
||||
case 'r': /* repair */
|
||||
case 'g': /* grant */
|
||||
|
@ -49,11 +49,12 @@ sqlsources = convert.cc derror.cc field.cc field_conv.cc filesort.cc \
|
||||
repl_failsafe.cc slave.cc \
|
||||
sql_analyse.cc sql_base.cc sql_cache.cc sql_class.cc \
|
||||
sql_crypt.cc sql_db.cc sql_delete.cc sql_insert.cc sql_lex.cc \
|
||||
sql_list.cc sql_manager.cc sql_map.cc sql_parse.cc \
|
||||
sql_list.cc sql_manager.cc sql_map.cc sql_parse.cc sql_derived.cc \
|
||||
sql_rename.cc sql_repl.cc sql_select.cc sql_do.cc sql_show.cc \
|
||||
sql_string.cc sql_table.cc sql_test.cc sql_udf.cc \
|
||||
sql_update.cc sql_yacc.cc table.cc thr_malloc.cc time.cc \
|
||||
unireg.cc uniques.cc stacktrace.c sql_union.cc hash_filo.cc
|
||||
unireg.cc uniques.cc stacktrace.c sql_union.cc hash_filo.cc \
|
||||
spatial.cc gstream.cc
|
||||
|
||||
EXTRA_DIST = lib_vio.c
|
||||
|
||||
|
@ -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
|
||||
|
@ -106,7 +106,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]++;
|
||||
|
||||
|
@ -107,13 +107,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:
|
||||
@ -134,7 +134,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_LBR || *doc == FTB_RBR)
|
||||
{
|
||||
/* param->prev=' '; */
|
||||
@ -156,7 +160,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;
|
||||
@ -185,12 +189,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;
|
||||
|
@ -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,
|
||||
myisam_read_vec[search_flag],info->s->state.key_root[inx]))
|
||||
{
|
||||
while (info->lastpos >= info->state->data_file_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)
|
||||
{
|
||||
/*
|
||||
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
|
||||
*/
|
||||
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,
|
||||
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,
|
||||
else
|
||||
{
|
||||
switch(info->s->keyinfo[inx].key_alg)
|
||||
{
|
||||
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,
|
||||
}
|
||||
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,
|
||||
}
|
||||
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, ¬_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;
|
||||
@ -457,19 +458,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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
914
myisam/rt_index.c
Normal file
914
myisam/rt_index.c
Normal file
@ -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;
|
||||
}
|
44
myisam/rt_index.h
Normal file
44
myisam/rt_index.h
Normal file
@ -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 */
|
154
myisam/rt_key.c
Normal file
154
myisam/rt_key.c
Normal file
@ -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;
|
||||
}
|
31
myisam/rt_key.h
Normal file
31
myisam/rt_key.h
Normal file
@ -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 */
|
758
myisam/rt_mbr.c
Normal file
758
myisam/rt_mbr.c
Normal file
@ -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(MI_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(MI_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(MI_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(MI_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(MI_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(MI_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, MI_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;
|
||||
}
|
33
myisam/rt_mbr.h
Normal file
33
myisam/rt_mbr.h
Normal file
@ -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(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 */
|
343
myisam/rt_split.c
Normal file
343
myisam/rt_split.c
Normal file
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
417
myisam/rt_test.c
Normal file
417
myisam/rt_test.c
Normal file
@ -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];
|
||||
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);
|
||||
}
|
||||
}
|
45
myisam/sp_defs.h
Normal file
45
myisam/sp_defs.h
Normal file
@ -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 */
|
256
myisam/sp_key.c
Normal file
256
myisam/sp_key.c
Normal file
@ -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)
|
||||
{
|
||||
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;
|
||||
}
|
565
myisam/sp_test.c
Normal file
565
myisam/sp_test.c
Normal file
@ -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];
|
||||
MI_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;
|
||||
}
|
||||
}
|
||||
}
|
10
mysql-test/r/derived.result
Normal file
10
mysql-test/r/derived.result
Normal file
@ -0,0 +1,10 @@
|
||||
drop table if exists t1,t2;
|
||||
CREATE TABLE t1 (a int not null, b char (10) not null);
|
||||
insert into t1 values(1,'a'),(2,'b'),(3,'c'),(3,'c');
|
||||
CREATE TABLE t2 (a int not null, b char (10) not null);
|
||||
insert into t2 values (3,'c'),(4,'d'),(5,'f'),(6,'e');
|
||||
select t1.a,t3.y from t1,(select a as y from t2 where b='c') as t3 where t1.a = t3.y;
|
||||
a y
|
||||
3 3
|
||||
3 3
|
||||
drop table if exists t1.t2;
|
@ -68,7 +68,7 @@ explain select * from t1 where a in (869751,736494,226312,802616);
|
||||
table type possible_keys key key_len ref rows Extra
|
||||
t1 range uniq_id uniq_id 4 NULL 4 where used; Using index
|
||||
drop table t1;
|
||||
create table t1 (x int not null, y int not null, key x(x), unique y(y))
|
||||
create table t1 (x int not null, y int not null, key x (x), unique y (y))
|
||||
type=heap;
|
||||
insert into t1 values (1,1),(2,2),(1,3),(2,4),(2,5),(2,6);
|
||||
select * from t1 where x=1;
|
||||
|
@ -1,7 +1,7 @@
|
||||
drop table if exists t1;
|
||||
CREATE TABLE t1 (
|
||||
STRING_DATA char(255) default NULL,
|
||||
KEY STRING_DATA (STRING_DATA)
|
||||
KEY string_data (STRING_DATA)
|
||||
) TYPE=MyISAM;
|
||||
INSERT INTO t1 VALUES ('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA');
|
||||
INSERT INTO t1 VALUES ('DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD');
|
||||
|
7
mysql-test/t/derived.test
Normal file
7
mysql-test/t/derived.test
Normal file
@ -0,0 +1,7 @@
|
||||
drop table if exists t1,t2;
|
||||
CREATE TABLE t1 (a int not null, b char (10) not null);
|
||||
insert into t1 values(1,'a'),(2,'b'),(3,'c'),(3,'c');
|
||||
CREATE TABLE t2 (a int not null, b char (10) not null);
|
||||
insert into t2 values (3,'c'),(4,'d'),(5,'f'),(6,'e');
|
||||
select t1.a,t3.y from t1,(select a as y from t2 where b='c') as t3 where t1.a = t3.y;
|
||||
drop table if exists t1.t2;
|
@ -42,7 +42,7 @@ alter table t1 type=myisam;
|
||||
explain select * from t1 where a in (869751,736494,226312,802616);
|
||||
drop table t1;
|
||||
|
||||
create table t1 (x int not null, y int not null, key x(x), unique y(y))
|
||||
create table t1 (x int not null, y int not null, key x (x), unique y (y))
|
||||
type=heap;
|
||||
insert into t1 values (1,1),(2,2),(1,3),(2,4),(2,5),(2,6);
|
||||
select * from t1 where x=1;
|
||||
|
@ -5,7 +5,7 @@
|
||||
drop table if exists t1;
|
||||
CREATE TABLE t1 (
|
||||
STRING_DATA char(255) default NULL,
|
||||
KEY STRING_DATA (STRING_DATA)
|
||||
KEY string_data (STRING_DATA)
|
||||
) TYPE=MyISAM;
|
||||
|
||||
INSERT INTO t1 VALUES ('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA');
|
||||
|
@ -68,7 +68,7 @@ static my_bool get_word(struct simpleconfig_buf_st *fb, char *buf)
|
||||
|
||||
for (;;)
|
||||
{
|
||||
while (isspace(*endptr))
|
||||
while (my_isspace(system_charset_info, *endptr))
|
||||
++endptr;
|
||||
if (*endptr && *endptr != '#') /* Not comment */
|
||||
break; /* Found something */
|
||||
@ -77,7 +77,7 @@ static my_bool get_word(struct simpleconfig_buf_st *fb, char *buf)
|
||||
endptr = fb->buf;
|
||||
}
|
||||
|
||||
while (!isspace(*endptr))
|
||||
while (!my_isspace(system_charset_info, *endptr))
|
||||
*buf++= *endptr++;
|
||||
*buf=0;
|
||||
fb->p = endptr;
|
||||
@ -329,6 +329,14 @@ static CHARSET_INFO *add_charset(uint cs_number, const char *cs_name, myf flags)
|
||||
memcpy((char*) cs->to_upper, (char*) tmp_to_upper, sizeof(tmp_to_upper));
|
||||
memcpy((char*) cs->sort_order, (char*) tmp_sort_order,
|
||||
sizeof(tmp_sort_order));
|
||||
|
||||
cs->caseup_str = my_caseup_str_8bit;
|
||||
cs->casedn_str = my_casedn_str_8bit;
|
||||
cs->caseup = my_caseup_8bit;
|
||||
cs->casedn = my_casedn_8bit;
|
||||
cs->strcasecmp = my_strcasecmp_8bit;
|
||||
cs->strncasecmp = my_strncasecmp_8bit;
|
||||
|
||||
insert_dynamic(&cs_info_table, (gptr) &cs);
|
||||
return cs;
|
||||
}
|
||||
@ -396,6 +404,7 @@ my_bool set_default_charset(uint cs, myf flags)
|
||||
DBUG_RETURN(TRUE); /* error */
|
||||
}
|
||||
default_charset_info = new_charset;
|
||||
system_charset_info = new_charset;
|
||||
DBUG_RETURN(FALSE);
|
||||
}
|
||||
|
||||
@ -428,6 +437,7 @@ my_bool set_default_charset_by_name(const char *cs_name, myf flags)
|
||||
}
|
||||
|
||||
default_charset_info = new_charset;
|
||||
system_charset_info = new_charset;
|
||||
DBUG_RETURN(FALSE);
|
||||
}
|
||||
|
||||
@ -540,11 +550,9 @@ void _print_csinfo(CHARSET_INFO *cs)
|
||||
printf("to_lower:\n"); _print_array(cs->to_lower, 256);
|
||||
printf("to_upper:\n"); _print_array(cs->to_upper, 256);
|
||||
printf("sort_order:\n"); _print_array(cs->sort_order, 256);
|
||||
printf("collate: %3s (%d, %p, %p, %p, %p, %p)\n",
|
||||
printf("collate: %3s (%d, %p, %p, %p)\n",
|
||||
cs->strxfrm_multiply ? "yes" : "no",
|
||||
cs->strxfrm_multiply,
|
||||
cs->strcoll,
|
||||
cs->strxfrm,
|
||||
cs->strnncoll,
|
||||
cs->strnxfrm,
|
||||
cs->like_range);
|
||||
|
@ -247,7 +247,7 @@ static my_bool search_default_file(DYNAMIC_ARRAY *args, MEM_ROOT *alloc,
|
||||
{
|
||||
line++;
|
||||
/* Ignore comment and empty lines */
|
||||
for (ptr=buff ; isspace(*ptr) ; ptr++ ) ;
|
||||
for (ptr=buff ; my_isspace(system_charset_info,*ptr) ; ptr++ ) ;
|
||||
if (*ptr == '#' || *ptr == ';' || !*ptr)
|
||||
continue;
|
||||
if (*ptr == '[') /* Group name */
|
||||
@ -260,7 +260,7 @@ static my_bool search_default_file(DYNAMIC_ARRAY *args, MEM_ROOT *alloc,
|
||||
name,line);
|
||||
goto err;
|
||||
}
|
||||
for ( ; isspace(end[-1]) ; end--) ; /* Remove end space */
|
||||
for ( ; my_isspace(system_charset_info,end[-1]) ; end--) ;/* Remove end space */
|
||||
end[0]=0;
|
||||
read_values=find_type(ptr,group,3) > 0;
|
||||
continue;
|
||||
@ -276,7 +276,7 @@ static my_bool search_default_file(DYNAMIC_ARRAY *args, MEM_ROOT *alloc,
|
||||
continue;
|
||||
if (!(end=value=strchr(ptr,'=')))
|
||||
end=strend(ptr); /* Option without argument */
|
||||
for ( ; isspace(end[-1]) ; end--) ;
|
||||
for ( ; my_isspace(system_charset_info,end[-1]) ; end--) ;
|
||||
if (!value)
|
||||
{
|
||||
if (!(tmp=alloc_root(alloc,(uint) (end-ptr)+3)))
|
||||
@ -289,9 +289,9 @@ static my_bool search_default_file(DYNAMIC_ARRAY *args, MEM_ROOT *alloc,
|
||||
{
|
||||
/* Remove pre- and end space */
|
||||
char *value_end;
|
||||
for (value++ ; isspace(*value); value++) ;
|
||||
for (value++ ; my_isspace(system_charset_info,*value); value++) ;
|
||||
value_end=strend(value);
|
||||
for ( ; isspace(value_end[-1]) ; value_end--) ;
|
||||
for ( ; my_isspace(system_charset_info,value_end[-1]) ; value_end--) ;
|
||||
if (value_end < value) /* Empty string */
|
||||
value_end=value;
|
||||
if (!(tmp=alloc_root(alloc,(uint) (end-ptr)+3 +
|
||||
|
@ -58,14 +58,15 @@ my_bool set_changeable_var(my_string str,CHANGEABLE_VAR *vars)
|
||||
longlong num;
|
||||
|
||||
/* Skip end space from variable */
|
||||
for (var_end=end ; end > str && isspace(var_end[-1]) ; var_end--) ;
|
||||
for (var_end=end ; end > str && my_isspace(system_charset_info, var_end[-1]) ; var_end--) ;
|
||||
length=(uint) (var_end-str);
|
||||
/* Skip start space from argument */
|
||||
for (end++ ; isspace(*end) ; end++) ;
|
||||
for (end++ ; my_isspace(system_charset_info, *end) ; end++) ;
|
||||
|
||||
for (var=vars,found=0 ; (name=var->name) ; var++)
|
||||
{
|
||||
if (!my_casecmp(name,str,length))
|
||||
/* BAR TODO: remove system_charset_info */
|
||||
if (!my_strncasecmp(system_charset_info,name,str,length))
|
||||
{
|
||||
found=var; found_count++;
|
||||
if (!name[length])
|
||||
@ -93,7 +94,7 @@ my_bool set_changeable_var(my_string str,CHANGEABLE_VAR *vars)
|
||||
num*=1024L*1024L;
|
||||
else if (endchar == 'g' || endchar == 'G')
|
||||
num*=1024L*1024L*1024L;
|
||||
else if (!isdigit(endchar))
|
||||
else if (!my_isdigit(system_charset_info, endchar))
|
||||
{
|
||||
fprintf(stderr,"Unknown prefix used for variable value '%s'\n",str);
|
||||
DBUG_RETURN(1);
|
||||
|
33
mysys/hash.c
33
mysys/hash.c
@ -31,12 +31,13 @@
|
||||
|
||||
static uint hash_mask(uint hashnr,uint buffmax,uint maxlength);
|
||||
static void movelink(HASH_LINK *array,uint pos,uint next_link,uint newlink);
|
||||
static uint calc_hashnr(const byte *key,uint length);
|
||||
static uint calc_hashnr_caseup(const byte *key,uint length);
|
||||
static uint calc_hashnr(CHARSET_INFO *cs,const byte *key,uint length);
|
||||
static uint calc_hashnr_caseup(CHARSET_INFO *cs, const byte *key,uint length);
|
||||
static int hashcmp(HASH *hash,HASH_LINK *pos,const byte *key,uint length);
|
||||
|
||||
|
||||
my_bool _hash_init(HASH *hash,uint size,uint key_offset,uint key_length,
|
||||
_hash_init(HASH *hash,CHARSET_INFO *charset,
|
||||
uint size,uint key_offset,uint key_length,
|
||||
hash_get_key get_key,
|
||||
void (*free_element)(void*),uint flags CALLER_INFO_PROTO)
|
||||
{
|
||||
@ -56,6 +57,7 @@ my_bool _hash_init(HASH *hash,uint size,uint key_offset,uint key_length,
|
||||
hash->get_key=get_key;
|
||||
hash->free=free_element;
|
||||
hash->flags=flags;
|
||||
hash->charset=charset;
|
||||
if (flags & HASH_CASE_INSENSITIVE)
|
||||
hash->calc_hashnr=calc_hashnr_caseup;
|
||||
else
|
||||
@ -104,14 +106,16 @@ static uint hash_rec_mask(HASH *hash,HASH_LINK *pos,uint buffmax,
|
||||
{
|
||||
uint length;
|
||||
byte *key=hash_key(hash,pos->data,&length,0);
|
||||
return hash_mask((*hash->calc_hashnr)(key,length),buffmax,maxlength);
|
||||
return hash_mask((*hash->calc_hashnr)(hash->charset,key,length),
|
||||
buffmax,maxlength);
|
||||
}
|
||||
|
||||
#ifndef NEW_HASH_FUNCTION
|
||||
|
||||
/* Calc hashvalue for a key */
|
||||
|
||||
static uint calc_hashnr(const byte *key,uint length)
|
||||
static uint calc_hashnr(CHARSET_INFO *cs __attribute__((unused)),
|
||||
const byte *key,uint length)
|
||||
{
|
||||
register uint nr=1, nr2=4;
|
||||
while (length--)
|
||||
@ -124,12 +128,13 @@ static uint calc_hashnr(const byte *key,uint length)
|
||||
|
||||
/* Calc hashvalue for a key, case indepenently */
|
||||
|
||||
static uint calc_hashnr_caseup(const byte *key,uint length)
|
||||
static uint calc_hashnr_caseup(CHARSET_INFO *cs, const byte *key,uint length)
|
||||
{
|
||||
register uint nr=1, nr2=4;
|
||||
while (length--)
|
||||
{
|
||||
nr^= (((nr & 63)+nr2)*((uint) (uchar) toupper(*key++)))+ (nr << 8);
|
||||
nr^= (((nr & 63)+nr2)*
|
||||
((uint) (uchar) my_toupper(cs, *key++)))+ (nr << 8);
|
||||
nr2+=3;
|
||||
}
|
||||
return((uint) nr);
|
||||
@ -150,7 +155,7 @@ static uint calc_hashnr_caseup(const byte *key,uint length)
|
||||
* This works well on both numbers and strings.
|
||||
*/
|
||||
|
||||
uint calc_hashnr(const byte *key, uint len)
|
||||
uint calc_hashnr(CHARSET_INFO *cs, const byte *key, uint len)
|
||||
{
|
||||
const byte *end=key+len;
|
||||
uint hash;
|
||||
@ -162,14 +167,14 @@ uint calc_hashnr(const byte *key, uint len)
|
||||
return (hash);
|
||||
}
|
||||
|
||||
uint calc_hashnr_caseup(const byte *key, uint len)
|
||||
uint calc_hashnr_caseup(CHARSET_INFO *cs, const byte *key, uint len)
|
||||
{
|
||||
const byte *end=key+len;
|
||||
uint hash;
|
||||
for (hash = 0; key < end; key++)
|
||||
{
|
||||
hash *= 16777619;
|
||||
hash ^= (uint) (uchar) toupper(*key);
|
||||
hash ^= (uint) (uchar) my_toupper(cs,*key);
|
||||
}
|
||||
return (hash);
|
||||
}
|
||||
@ -184,7 +189,7 @@ uint rec_hashnr(HASH *hash,const byte *record)
|
||||
{
|
||||
uint length;
|
||||
byte *key=hash_key(hash,record,&length,0);
|
||||
return (*hash->calc_hashnr)(key,length);
|
||||
return (*hash->calc_hashnr)(hash->charset,key,length);
|
||||
}
|
||||
|
||||
|
||||
@ -200,7 +205,7 @@ gptr hash_search(HASH *hash,const byte *key,uint length)
|
||||
flag=1;
|
||||
if (hash->records)
|
||||
{
|
||||
idx=hash_mask((*hash->calc_hashnr)(key,length ? length :
|
||||
idx=hash_mask((*hash->calc_hashnr)(hash->charset,key,length ? length :
|
||||
hash->key_length),
|
||||
hash->blength,hash->records);
|
||||
do
|
||||
@ -273,7 +278,7 @@ static int hashcmp(HASH *hash,HASH_LINK *pos,const byte *key,uint length)
|
||||
byte *rec_key=hash_key(hash,pos->data,&rec_keylength,1);
|
||||
return (length && length != rec_keylength) ||
|
||||
(hash->flags & HASH_CASE_INSENSITIVE ?
|
||||
my_casecmp(rec_key,key,rec_keylength) :
|
||||
my_strncasecmp(hash->charset, rec_key,key,rec_keylength) :
|
||||
memcmp(rec_key,key,rec_keylength));
|
||||
}
|
||||
|
||||
@ -513,7 +518,7 @@ my_bool hash_update(HASH *hash,byte *record,byte *old_key,uint old_key_length)
|
||||
|
||||
/* Search after record with key */
|
||||
|
||||
idx=hash_mask((*hash->calc_hashnr)(old_key,(old_key_length ?
|
||||
idx=hash_mask((*hash->calc_hashnr)(hash->charset, old_key,(old_key_length ?
|
||||
old_key_length :
|
||||
hash->key_length)),
|
||||
blength,records);
|
||||
|
@ -28,234 +28,50 @@
|
||||
#include <m_string.h>
|
||||
#endif
|
||||
|
||||
/* string to uppercase */
|
||||
|
||||
void caseup_str(my_string str)
|
||||
{
|
||||
#ifdef USE_MB
|
||||
if (use_mb(default_charset_info))
|
||||
{
|
||||
register uint32 l;
|
||||
register char *end=str+strlen(str);
|
||||
while (*str)
|
||||
{
|
||||
if ((l=my_ismbchar(default_charset_info, str,end))) str+=l;
|
||||
else *str=toupper(*str),++str;
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
while ((*str = toupper(*str)) != 0)
|
||||
str++;
|
||||
} /* caseup_str */
|
||||
|
||||
/* string to lowercase */
|
||||
|
||||
void casedn_str(my_string str)
|
||||
{
|
||||
#ifdef USE_MB
|
||||
if (use_mb(default_charset_info))
|
||||
{
|
||||
register uint32 l;
|
||||
register char *end=str+strlen(str);
|
||||
while (*str)
|
||||
{
|
||||
if ((l=my_ismbchar(default_charset_info, str,end))) str+=l;
|
||||
else *str=tolower(*str),++str;
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
while ((*str= tolower(*str)) != 0)
|
||||
str++;
|
||||
} /* casedn_str */
|
||||
|
||||
|
||||
/* to uppercase */
|
||||
|
||||
void caseup(my_string str, uint length)
|
||||
{
|
||||
#ifdef USE_MB
|
||||
if (use_mb(default_charset_info))
|
||||
{
|
||||
register uint32 l;
|
||||
register char *end=str+length;
|
||||
while (str<end)
|
||||
{
|
||||
if ((l=my_ismbchar(default_charset_info, str,end))) str+=l;
|
||||
else *str=toupper(*str),++str;
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
for ( ; length>0 ; length--, str++)
|
||||
*str= toupper(*str);
|
||||
} /* caseup */
|
||||
|
||||
/* to lowercase */
|
||||
|
||||
void casedn(my_string str, uint length)
|
||||
{
|
||||
#ifdef USE_MB
|
||||
if (use_mb(default_charset_info))
|
||||
{
|
||||
register uint32 l;
|
||||
register char *end=str+length;
|
||||
while (str<end)
|
||||
{
|
||||
if ((l=my_ismbchar(default_charset_info, str,end))) str+=l;
|
||||
else *str=tolower(*str),++str;
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
for ( ; length>0 ; length--, str++)
|
||||
*str= tolower(*str);
|
||||
} /* casedn */
|
||||
|
||||
/* to sort-string that can be compared to get text in order */
|
||||
|
||||
void case_sort(my_string str, uint length)
|
||||
void case_sort(CHARSET_INFO *cs, my_string str, uint length)
|
||||
{
|
||||
for ( ; length>0 ; length--, str++)
|
||||
*str= (char) my_sort_order[(uchar) *str];
|
||||
*str= (char) cs->sort_order[(uchar) *str];
|
||||
} /* case_sort */
|
||||
|
||||
/* find string in another with no case_sensivity */
|
||||
|
||||
/* ToDo: This function should be modified to support multibyte charset.
|
||||
However it is not used untill 3.23.5.
|
||||
Wei He (hewei@mail.ied.ac.cn)
|
||||
*/
|
||||
|
||||
my_string my_strcasestr(const char *str, const char *search)
|
||||
{
|
||||
uchar *i,*j,*pos;
|
||||
|
||||
pos=(uchar*) str;
|
||||
skipp:
|
||||
while (*pos != '\0')
|
||||
{
|
||||
if (toupper((uchar) *pos++) == toupper((uchar) *search))
|
||||
{
|
||||
i=(uchar*) pos; j=(uchar*) search+1;
|
||||
while (*j)
|
||||
if (toupper(*i++) != toupper(*j++)) goto skipp;
|
||||
return ((char*) pos-1);
|
||||
}
|
||||
}
|
||||
return ((my_string) 0);
|
||||
} /* strcstr */
|
||||
|
||||
|
||||
/* compare strings without regarding to case */
|
||||
|
||||
int my_strcasecmp(const char *s, const char *t)
|
||||
{
|
||||
#ifdef USE_MB
|
||||
if (use_mb(default_charset_info))
|
||||
{
|
||||
register uint32 l;
|
||||
register const char *end=s+strlen(s);
|
||||
while (s<end)
|
||||
{
|
||||
if ((l=my_ismbchar(default_charset_info, s,end)))
|
||||
{
|
||||
while (l--)
|
||||
if (*s++ != *t++) return 1;
|
||||
}
|
||||
else if (my_ismbhead(default_charset_info, *t)) return 1;
|
||||
else if (toupper((uchar) *s++) != toupper((uchar) *t++)) return 1;
|
||||
}
|
||||
return *t;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
while (toupper((uchar) *s) == toupper((uchar) *t++))
|
||||
if (!*s++) return 0;
|
||||
return ((int) toupper((uchar) s[0]) - (int) toupper((uchar) t[-1]));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int my_casecmp(const char *s, const char *t, uint len)
|
||||
{
|
||||
#ifdef USE_MB
|
||||
if (use_mb(default_charset_info))
|
||||
{
|
||||
register uint32 l;
|
||||
register const char *end=s+len;
|
||||
while (s<end)
|
||||
{
|
||||
if ((l=my_ismbchar(default_charset_info, s,end)))
|
||||
{
|
||||
while (l--)
|
||||
if (*s++ != *t++) return 1;
|
||||
}
|
||||
else if (my_ismbhead(default_charset_info, *t)) return 1;
|
||||
else if (toupper((uchar) *s++) != toupper((uchar) *t++)) return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
while (len-- != 0 && toupper(*s++) == toupper(*t++)) ;
|
||||
return (int) len+1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int my_strsortcmp(const char *s, const char *t)
|
||||
int my_sortcmp(CHARSET_INFO *cs, const char *s, const char *t, uint len)
|
||||
{
|
||||
#ifdef USE_STRCOLL
|
||||
if (use_strcoll(default_charset_info))
|
||||
return my_strcoll(default_charset_info, (uchar *)s, (uchar *)t);
|
||||
else
|
||||
#endif
|
||||
{
|
||||
while (my_sort_order[(uchar) *s] == my_sort_order[(uchar) *t++])
|
||||
if (!*s++) return 0;
|
||||
return ((int) my_sort_order[(uchar) s[0]] -
|
||||
(int) my_sort_order[(uchar) t[-1]]);
|
||||
}
|
||||
}
|
||||
|
||||
int my_sortcmp(const char *s, const char *t, uint len)
|
||||
{
|
||||
#ifdef USE_STRCOLL
|
||||
if (use_strcoll(default_charset_info))
|
||||
return my_strnncoll(default_charset_info,
|
||||
(uchar *)s, len, (uchar *)t, len);
|
||||
if (use_strcoll(cs))
|
||||
return my_strnncoll(cs,(uchar *)s, len, (uchar *)t, len);
|
||||
else
|
||||
#endif
|
||||
{
|
||||
while (len--)
|
||||
{
|
||||
if (my_sort_order[(uchar) *s++] != my_sort_order[(uchar) *t++])
|
||||
return ((int) my_sort_order[(uchar) s[-1]] -
|
||||
(int) my_sort_order[(uchar) t[-1]]);
|
||||
if (cs->sort_order[(uchar) *s++] != cs->sort_order[(uchar) *t++])
|
||||
return ((int) cs->sort_order[(uchar) s[-1]] -
|
||||
(int) cs->sort_order[(uchar) t[-1]]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int my_sortncmp(const char *s, uint s_len, const char *t, uint t_len)
|
||||
int my_sortncmp(CHARSET_INFO *cs,
|
||||
const char *s, uint s_len,
|
||||
const char *t, uint t_len)
|
||||
{
|
||||
#ifdef USE_STRCOLL
|
||||
if (use_strcoll(default_charset_info))
|
||||
return my_strnncoll(default_charset_info,
|
||||
(uchar *)s, s_len, (uchar *)t, t_len);
|
||||
if (use_strcoll(cs))
|
||||
return my_strnncoll(cs, (uchar *)s, s_len, (uchar *)t, t_len);
|
||||
else
|
||||
#endif
|
||||
{
|
||||
uint len= min(s_len,t_len);
|
||||
while (len--)
|
||||
{
|
||||
if (my_sort_order[(uchar) *s++] != my_sort_order[(uchar) *t++])
|
||||
return ((int) my_sort_order[(uchar) s[-1]] -
|
||||
(int) my_sort_order[(uchar) t[-1]]);
|
||||
if (cs->sort_order[(uchar) *s++] != cs->sort_order[(uchar) *t++])
|
||||
return ((int) cs->sort_order[(uchar) s[-1]] -
|
||||
(int) cs->sort_order[(uchar) t[-1]]);
|
||||
}
|
||||
return (int) (s_len - t_len);
|
||||
}
|
||||
|
@ -108,11 +108,5 @@ char *convert_dirname(char *to, const char *from, const char *from_end)
|
||||
*to++=FN_LIBCHAR;
|
||||
*to=0;
|
||||
}
|
||||
#ifdef FN_UPPER_CASE
|
||||
caseup_str(to_org);
|
||||
#endif
|
||||
#ifdef FN_LOWER_CASE
|
||||
casedn_str(to_org);
|
||||
#endif
|
||||
return to; /* Pointer to end of dir */
|
||||
} /* convert_dirname */
|
||||
|
@ -91,12 +91,6 @@ my_string fn_format(my_string to, const char *name, const char *dir,
|
||||
name=buff;
|
||||
}
|
||||
pos=strmake(strmov(to,dev),name,length);
|
||||
#ifdef FN_UPPER_CASE
|
||||
caseup_str(to);
|
||||
#endif
|
||||
#ifdef FN_LOWER_CASE
|
||||
casedn_str(to);
|
||||
#endif
|
||||
(void) strmov(pos,ext); /* Don't convert extension */
|
||||
}
|
||||
/*
|
||||
|
@ -250,7 +250,7 @@ uint my_b_vprintf(IO_CACHE *info, const char* fmt, va_list args)
|
||||
/* Found one '%' */
|
||||
}
|
||||
/* Skipp if max size is used (to be compatible with printf) */
|
||||
while (isdigit(*fmt) || *fmt == '.' || *fmt == '-')
|
||||
while (my_isdigit(system_charset_info, *fmt) || *fmt == '.' || *fmt == '-')
|
||||
fmt++;
|
||||
if (*fmt == 's') /* String parameter */
|
||||
{
|
||||
|
@ -34,12 +34,12 @@
|
||||
#include <m_ctype.h>
|
||||
#include "my_static.h"
|
||||
|
||||
static char get_scode(char **ptr,pbool remove_garbage);
|
||||
static char get_scode(CHARSET_INFO * cs, char **ptr,pbool remove_garbage);
|
||||
|
||||
/* outputed string is 4 byte long */
|
||||
/* out_pntr can be == in_pntr */
|
||||
|
||||
void soundex(register my_string out_pntr, my_string in_pntr,
|
||||
void soundex(CHARSET_INFO * cs,register my_string out_pntr, my_string in_pntr,
|
||||
pbool remove_garbage)
|
||||
{
|
||||
char ch,last_ch;
|
||||
@ -47,11 +47,11 @@ void soundex(register my_string out_pntr, my_string in_pntr,
|
||||
|
||||
if (remove_garbage)
|
||||
{
|
||||
while (*in_pntr && isspace(*in_pntr)) /* Skipp pre-space */
|
||||
while (*in_pntr && my_isspace(cs,*in_pntr)) /* Skipp pre-space */
|
||||
in_pntr++;
|
||||
}
|
||||
*out_pntr++ = toupper(*in_pntr); /* Copy first letter */
|
||||
last_ch = get_scode(&in_pntr,0); /* code of the first letter */
|
||||
*out_pntr++ = my_toupper(cs,*in_pntr);/* Copy first letter */
|
||||
last_ch = get_scode(cs,&in_pntr,0); /* code of the first letter */
|
||||
/* for the first 'double-letter */
|
||||
/* check. */
|
||||
end=out_pntr+3; /* Loop on input letters until */
|
||||
@ -59,7 +59,7 @@ void soundex(register my_string out_pntr, my_string in_pntr,
|
||||
/* letter code count = 3 */
|
||||
|
||||
in_pntr++;
|
||||
while (out_pntr < end && (ch = get_scode(&in_pntr,remove_garbage)) != 0)
|
||||
while (out_pntr < end && (ch = get_scode(cs,&in_pntr,remove_garbage)) != 0)
|
||||
{
|
||||
in_pntr++;
|
||||
if ((ch != '0') && (ch != last_ch)) /* if not skipped or double */
|
||||
@ -81,19 +81,19 @@ void soundex(register my_string out_pntr, my_string in_pntr,
|
||||
else return 0
|
||||
*/
|
||||
|
||||
static char get_scode(char **ptr, pbool remove_garbage)
|
||||
static char get_scode(CHARSET_INFO * cs,char **ptr, pbool remove_garbage)
|
||||
{
|
||||
uchar ch;
|
||||
|
||||
if (remove_garbage)
|
||||
{
|
||||
while (**ptr && !isalpha(**ptr))
|
||||
while (**ptr && !my_isalpha(cs,**ptr))
|
||||
(*ptr)++;
|
||||
}
|
||||
ch=toupper(**ptr);
|
||||
ch=my_toupper(cs,**ptr);
|
||||
if (ch < 'A' || ch > 'Z')
|
||||
{
|
||||
if (isalpha(ch)) /* If exetended alfa (country spec) */
|
||||
if (my_isalpha(cs,ch)) /* If exetended alfa (country spec) */
|
||||
return '0'; /* threat as vokal */
|
||||
return 0; /* Can't map */
|
||||
}
|
||||
|
@ -54,13 +54,6 @@ WF_PACK *wf_comp(my_string str)
|
||||
for (pos=str ; *pos ; pos++)
|
||||
ant+= test(*pos == ' ' || *pos == ',');
|
||||
|
||||
#ifdef FN_UPPER_CASE
|
||||
caseup(str,(int) (pos-str));
|
||||
#endif
|
||||
#ifdef FN_LOWER_CASE
|
||||
casedn(str,(int) (pos-str));
|
||||
#endif
|
||||
|
||||
if ((ret= (WF_PACK*) my_malloc((uint) ant*(sizeof(my_string*)+2)+
|
||||
sizeof(WF_PACK)+ (uint) strlen(str)+1,
|
||||
MYF(MY_WME)))
|
||||
|
@ -62,7 +62,7 @@ int my_error(int nr,myf MyFlags, ...)
|
||||
else
|
||||
{
|
||||
/* Skipp if max size is used (to be compatible with printf) */
|
||||
while (isdigit(*tpos) || *tpos == '.' || *tpos == '-')
|
||||
while (my_isdigit(system_charset_info, *tpos) || *tpos == '.' || *tpos == '-')
|
||||
tpos++;
|
||||
if (*tpos == 'l') /* Skipp 'l' argument */
|
||||
tpos++;
|
||||
|
@ -109,7 +109,8 @@ int my_setwd(const char *dir, myf MyFlags)
|
||||
uint drive,drives;
|
||||
|
||||
pos++; /* Skipp FN_DEVCHAR */
|
||||
drive=(uint) (toupper(dir[0])-'A'+1); drives= (uint) -1;
|
||||
drive=(uint) (my_toupper(system_charset_info,dir[0])-'A'+1);
|
||||
drives= (uint) -1;
|
||||
if ((pos-(byte*) dir) == 2 && drive > 0 && drive < 32)
|
||||
{
|
||||
#ifdef OS2
|
||||
|
@ -17,7 +17,6 @@
|
||||
#include "mysys_priv.h"
|
||||
#include "my_static.h"
|
||||
#include "mysys_err.h"
|
||||
#include "m_ctype.h"
|
||||
#include <m_string.h>
|
||||
#include <m_ctype.h>
|
||||
#ifdef THREAD
|
||||
@ -50,7 +49,7 @@ my_bool my_init_done=0;
|
||||
static ulong atoi_octal(const char *str)
|
||||
{
|
||||
long int tmp;
|
||||
while (*str && isspace(*str))
|
||||
while (*str && my_isspace(system_charset_info, *str))
|
||||
str++;
|
||||
str2int(str,
|
||||
(*str == '0' ? 8 : 10), /* Octalt or decimalt */
|
||||
|
@ -42,7 +42,7 @@ int my_vsnprintf(char *to, size_t n, const char* fmt, va_list ap)
|
||||
}
|
||||
/* Skip if max size is used (to be compatible with printf) */
|
||||
fmt++;
|
||||
while (isdigit(*fmt) || *fmt == '.' || *fmt == '-')
|
||||
while (my_isdigit(system_charset_info,*fmt) || *fmt == '.' || *fmt == '-')
|
||||
fmt++;
|
||||
if (*fmt == 'l')
|
||||
fmt++;
|
||||
|
@ -47,7 +47,9 @@ int find_type(my_string x, TYPELIB *typelib, uint full_name)
|
||||
find=0;
|
||||
for (pos=0 ; (j=typelib->type_names[pos]) ; pos++)
|
||||
{
|
||||
for (i=x ; *i && toupper(*i) == toupper(*j) ; i++, j++) ;
|
||||
for (i=x ;
|
||||
*i && my_toupper(system_charset_info,*i) ==
|
||||
my_toupper(system_charset_info,*j) ; i++, j++) ;
|
||||
if (! *j)
|
||||
{
|
||||
while (*i == ' ')
|
||||
|
@ -45,7 +45,7 @@ FILE *d;
|
||||
if (g->nplus > 0)
|
||||
fprintf(d, ", nplus %ld", (long)g->nplus);
|
||||
fprintf(d, "\n");
|
||||
s_print(g, d);
|
||||
s_print(r->charset, g, d);
|
||||
for (i = 0; i < g->ncategories; i++) {
|
||||
nincat[i] = 0;
|
||||
for (c = CHAR_MIN; c <= CHAR_MAX; c++)
|
||||
@ -58,7 +58,7 @@ FILE *d;
|
||||
for (c = CHAR_MIN; c <= CHAR_MAX; c++)
|
||||
if (g->categories[c] == i)
|
||||
break;
|
||||
fprintf(d, ", %d=%s", i, regchar(c,buf));
|
||||
fprintf(d, ", %d=%s", i, regchar(r->charset,c,buf));
|
||||
}
|
||||
fprintf(d, "\n");
|
||||
for (i = 1; i < g->ncategories; i++)
|
||||
@ -68,14 +68,14 @@ FILE *d;
|
||||
for (c = CHAR_MIN; c <= CHAR_MAX+1; c++) /* +1 does flush */
|
||||
if (c <= CHAR_MAX && g->categories[c] == i) {
|
||||
if (last < 0) {
|
||||
fprintf(d, "%s", regchar(c,buf));
|
||||
fprintf(d, "%s", regchar(r->charset,c,buf));
|
||||
last = c;
|
||||
}
|
||||
} else {
|
||||
if (last >= 0) {
|
||||
if (last != c-1)
|
||||
fprintf(d, "-%s",
|
||||
regchar(c-1,buf));
|
||||
regchar(r->charset,c-1,buf));
|
||||
last = -1;
|
||||
}
|
||||
}
|
||||
@ -88,7 +88,8 @@ FILE *d;
|
||||
== static void s_print(register struct re_guts *g, FILE *d);
|
||||
*/
|
||||
static void
|
||||
s_print(g, d)
|
||||
s_print(charset, g, d)
|
||||
CHARSET_INFO *charset;
|
||||
register struct re_guts *g;
|
||||
FILE *d;
|
||||
{
|
||||
@ -127,7 +128,7 @@ FILE *d;
|
||||
if (strchr("\\|()^$.[+*?{}!<> ", (char)opnd) != NULL)
|
||||
fprintf(d, "\\%c", (char)opnd);
|
||||
else
|
||||
fprintf(d, "%s", regchar((char)opnd,buf));
|
||||
fprintf(d, "%s", regchar(charset,(char)opnd,buf));
|
||||
break;
|
||||
case OBOL:
|
||||
fprintf(d, "^");
|
||||
@ -151,14 +152,14 @@ FILE *d;
|
||||
for (i = 0; i < g->csetsize+1; i++) /* +1 flushes */
|
||||
if (CHIN(cs, i) && i < g->csetsize) {
|
||||
if (last < 0) {
|
||||
fprintf(d, "%s", regchar(i,buf));
|
||||
fprintf(d, "%s", regchar(charset,i,buf));
|
||||
last = i;
|
||||
}
|
||||
} else {
|
||||
if (last >= 0) {
|
||||
if (last != i-1)
|
||||
fprintf(d, "-%s",
|
||||
regchar(i-1,buf));
|
||||
regchar(charset,i-1,buf));
|
||||
last = -1;
|
||||
}
|
||||
}
|
||||
@ -230,12 +231,13 @@ FILE *d;
|
||||
== static char *regchar(int ch);
|
||||
*/
|
||||
static char * /* -> representation */
|
||||
regchar(ch,buf)
|
||||
regchar(charset,ch,buf)
|
||||
CHARSET_INFO *charset;
|
||||
int ch;
|
||||
char *buf;
|
||||
{
|
||||
|
||||
if (isprint(ch) || ch == ' ')
|
||||
if (my_isprint(charset,ch) || ch == ' ')
|
||||
sprintf(buf, "%c", ch);
|
||||
else
|
||||
sprintf(buf, "\\%o", ch);
|
||||
|
@ -5,8 +5,8 @@ extern "C" {
|
||||
|
||||
/* === debug.c === */
|
||||
void regprint(regex_t *r, FILE *d);
|
||||
static void s_print(register struct re_guts *g, FILE *d);
|
||||
static char *regchar(int ch,char *buf);
|
||||
static void s_print(CHARSET_INFO *charset, register struct re_guts *g, FILE *d);
|
||||
static char *regchar(CHARSET_INFO *charset, int ch,char *buf);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -63,7 +63,8 @@ struct match {
|
||||
== size_t nmatch, regmatch_t pmatch[], int eflags);
|
||||
*/
|
||||
static int /* 0 success, REG_NOMATCH failure */
|
||||
matcher(g, str, nmatch, pmatch, eflags)
|
||||
matcher(charset,g, str, nmatch, pmatch, eflags)
|
||||
CHARSET_INFO *charset;
|
||||
register struct re_guts *g;
|
||||
char *str;
|
||||
size_t nmatch;
|
||||
@ -120,7 +121,7 @@ int eflags;
|
||||
|
||||
/* this loop does only one repetition except for backrefs */
|
||||
for (;;) {
|
||||
endp = fast(m, start, stop, gf, gl);
|
||||
endp = fast(charset, m, start, stop, gf, gl);
|
||||
if (endp == NULL) { /* a miss */
|
||||
if (m->pmatch != NULL)
|
||||
free((char *)m->pmatch);
|
||||
@ -136,7 +137,7 @@ int eflags;
|
||||
assert(m->coldp != NULL);
|
||||
for (;;) {
|
||||
NOTE("finding start");
|
||||
endp = slow(m, m->coldp, stop, gf, gl);
|
||||
endp = slow(charset, m, m->coldp, stop, gf, gl);
|
||||
if (endp != NULL)
|
||||
break;
|
||||
assert(m->coldp < m->endp);
|
||||
@ -159,7 +160,7 @@ int eflags;
|
||||
m->pmatch[i].rm_so = m->pmatch[i].rm_eo = -1;
|
||||
if (!g->backrefs && !(m->eflags®_BACKR)) {
|
||||
NOTE("dissecting");
|
||||
dp = dissect(m, m->coldp, endp, gf, gl);
|
||||
dp = dissect(charset, m, m->coldp, endp, gf, gl);
|
||||
} else {
|
||||
if (g->nplus > 0 && m->lastpos == NULL)
|
||||
m->lastpos = (char **)malloc((g->nplus+1) *
|
||||
@ -170,7 +171,7 @@ int eflags;
|
||||
return(REG_ESPACE);
|
||||
}
|
||||
NOTE("backref dissect");
|
||||
dp = backref(m, m->coldp, endp, gf, gl, (sopno)0);
|
||||
dp = backref(charset, m, m->coldp, endp, gf, gl, (sopno)0);
|
||||
}
|
||||
if (dp != NULL)
|
||||
break;
|
||||
@ -182,7 +183,7 @@ int eflags;
|
||||
if (dp != NULL || endp <= m->coldp)
|
||||
break; /* defeat */
|
||||
NOTE("backoff");
|
||||
endp = slow(m, m->coldp, endp-1, gf, gl);
|
||||
endp = slow(charset, m, m->coldp, endp-1, gf, gl);
|
||||
if (endp == NULL)
|
||||
break; /* defeat */
|
||||
/* try it on a shorter possibility */
|
||||
@ -193,7 +194,7 @@ int eflags;
|
||||
}
|
||||
#endif
|
||||
NOTE("backoff dissect");
|
||||
dp = backref(m, m->coldp, endp, gf, gl, (sopno)0);
|
||||
dp = backref(charset, m, m->coldp, endp, gf, gl, (sopno)0);
|
||||
}
|
||||
assert(dp == NULL || dp == endp);
|
||||
if (dp != NULL) /* found a shorter one */
|
||||
@ -235,7 +236,8 @@ int eflags;
|
||||
== char *stop, sopno startst, sopno stopst);
|
||||
*/
|
||||
static char * /* == stop (success) always */
|
||||
dissect(m, start, stop, startst, stopst)
|
||||
dissect(charset, m, start, stop, startst, stopst)
|
||||
CHARSET_INFO *charset;
|
||||
register struct match *m;
|
||||
char *start;
|
||||
char *stop;
|
||||
@ -299,10 +301,10 @@ sopno stopst;
|
||||
stp = stop;
|
||||
for (;;) {
|
||||
/* how long could this one be? */
|
||||
rest = slow(m, sp, stp, ss, es);
|
||||
rest = slow(charset, m, sp, stp, ss, es);
|
||||
assert(rest != NULL); /* it did match */
|
||||
/* could the rest match the rest? */
|
||||
tail = slow(m, rest, stop, es, stopst);
|
||||
tail = slow(charset, m, rest, stop, es, stopst);
|
||||
if (tail == stop)
|
||||
break; /* yes! */
|
||||
/* no -- try a shorter match for this one */
|
||||
@ -312,8 +314,8 @@ sopno stopst;
|
||||
ssub = ss + 1;
|
||||
esub = es - 1;
|
||||
/* did innards match? */
|
||||
if (slow(m, sp, rest, ssub, esub) != NULL) {
|
||||
dp = dissect(m, sp, rest, ssub, esub);
|
||||
if (slow(charset, m, sp, rest, ssub, esub) != NULL) {
|
||||
dp = dissect(charset, m, sp, rest, ssub, esub);
|
||||
assert(dp == rest);
|
||||
} else /* no */
|
||||
assert(sp == rest);
|
||||
@ -323,10 +325,10 @@ sopno stopst;
|
||||
stp = stop;
|
||||
for (;;) {
|
||||
/* how long could this one be? */
|
||||
rest = slow(m, sp, stp, ss, es);
|
||||
rest = slow(charset, m, sp, stp, ss, es);
|
||||
assert(rest != NULL); /* it did match */
|
||||
/* could the rest match the rest? */
|
||||
tail = slow(m, rest, stop, es, stopst);
|
||||
tail = slow(charset, m, rest, stop, es, stopst);
|
||||
if (tail == stop)
|
||||
break; /* yes! */
|
||||
/* no -- try a shorter match for this one */
|
||||
@ -338,7 +340,7 @@ sopno stopst;
|
||||
ssp = sp;
|
||||
oldssp = ssp;
|
||||
for (;;) { /* find last match of innards */
|
||||
sep = slow(m, ssp, rest, ssub, esub);
|
||||
sep = slow(charset, m, ssp, rest, ssub, esub);
|
||||
if (sep == NULL || sep == ssp)
|
||||
break; /* failed or matched null */
|
||||
oldssp = ssp; /* on to next try */
|
||||
@ -350,8 +352,8 @@ sopno stopst;
|
||||
ssp = oldssp;
|
||||
}
|
||||
assert(sep == rest); /* must exhaust substring */
|
||||
assert(slow(m, ssp, sep, ssub, esub) == rest);
|
||||
dp = dissect(m, ssp, sep, ssub, esub);
|
||||
assert(slow(charset, m, ssp, sep, ssub, esub) == rest);
|
||||
dp = dissect(charset, m, ssp, sep, ssub, esub);
|
||||
assert(dp == sep);
|
||||
sp = rest;
|
||||
break;
|
||||
@ -359,10 +361,10 @@ sopno stopst;
|
||||
stp = stop;
|
||||
for (;;) {
|
||||
/* how long could this one be? */
|
||||
rest = slow(m, sp, stp, ss, es);
|
||||
rest = slow(charset, m, sp, stp, ss, es);
|
||||
assert(rest != NULL); /* it did match */
|
||||
/* could the rest match the rest? */
|
||||
tail = slow(m, rest, stop, es, stopst);
|
||||
tail = slow(charset, m, rest, stop, es, stopst);
|
||||
if (tail == stop)
|
||||
break; /* yes! */
|
||||
/* no -- try a shorter match for this one */
|
||||
@ -373,7 +375,7 @@ sopno stopst;
|
||||
esub = ss + OPND(m->g->strip[ss]) - 1;
|
||||
assert(OP(m->g->strip[esub]) == OOR1);
|
||||
for (;;) { /* find first matching branch */
|
||||
if (slow(m, sp, rest, ssub, esub) == rest)
|
||||
if (slow(charset, m, sp, rest, ssub, esub) == rest)
|
||||
break; /* it matched all of it */
|
||||
/* that one missed, try next one */
|
||||
assert(OP(m->g->strip[esub]) == OOR1);
|
||||
@ -386,7 +388,7 @@ sopno stopst;
|
||||
else
|
||||
assert(OP(m->g->strip[esub]) == O_CH);
|
||||
}
|
||||
dp = dissect(m, sp, rest, ssub, esub);
|
||||
dp = dissect(charset, m, sp, rest, ssub, esub);
|
||||
assert(dp == rest);
|
||||
sp = rest;
|
||||
break;
|
||||
@ -423,7 +425,8 @@ sopno stopst;
|
||||
== char *stop, sopno startst, sopno stopst, sopno lev);
|
||||
*/
|
||||
static char * /* == stop (success) or NULL (failure) */
|
||||
backref(m, start, stop, startst, stopst, lev)
|
||||
backref(charset,m, start, stop, startst, stopst, lev)
|
||||
CHARSET_INFO *charset;
|
||||
register struct match *m;
|
||||
char *start;
|
||||
char *stop;
|
||||
@ -486,8 +489,8 @@ sopno lev; /* PLUS nesting level */
|
||||
(sp < m->endp && *(sp-1) == '\n' &&
|
||||
(m->g->cflags®_NEWLINE)) ||
|
||||
(sp > m->beginp &&
|
||||
!ISWORD(*(sp-1))) ) &&
|
||||
(sp < m->endp && ISWORD(*sp)) )
|
||||
!ISWORD(charset,*(sp-1))) ) &&
|
||||
(sp < m->endp && ISWORD(charset,*sp)) )
|
||||
{ /* yes */ }
|
||||
else
|
||||
return(NULL);
|
||||
@ -496,8 +499,8 @@ sopno lev; /* PLUS nesting level */
|
||||
if (( (sp == m->endp && !(m->eflags®_NOTEOL)) ||
|
||||
(sp < m->endp && *sp == '\n' &&
|
||||
(m->g->cflags®_NEWLINE)) ||
|
||||
(sp < m->endp && !ISWORD(*sp)) ) &&
|
||||
(sp > m->beginp && ISWORD(*(sp-1))) )
|
||||
(sp < m->endp && !ISWORD(charset,*sp)) ) &&
|
||||
(sp > m->beginp && ISWORD(charset,*(sp-1))) )
|
||||
{ /* yes */ }
|
||||
else
|
||||
return(NULL);
|
||||
@ -543,28 +546,28 @@ sopno lev; /* PLUS nesting level */
|
||||
return(NULL);
|
||||
while (m->g->strip[ss] != SOP(O_BACK, i))
|
||||
ss++;
|
||||
return(backref(m, sp+len, stop, ss+1, stopst, lev));
|
||||
return(backref(charset, m, sp+len, stop, ss+1, stopst, lev));
|
||||
break;
|
||||
case OQUEST_: /* to null or not */
|
||||
dp = backref(m, sp, stop, ss+1, stopst, lev);
|
||||
dp = backref(charset, m, sp, stop, ss+1, stopst, lev);
|
||||
if (dp != NULL)
|
||||
return(dp); /* not */
|
||||
return(backref(m, sp, stop, ss+OPND(s)+1, stopst, lev));
|
||||
return(backref(charset, m, sp, stop, ss+OPND(s)+1, stopst, lev));
|
||||
break;
|
||||
case OPLUS_:
|
||||
assert(m->lastpos != NULL);
|
||||
assert(lev+1 <= m->g->nplus);
|
||||
m->lastpos[lev+1] = sp;
|
||||
return(backref(m, sp, stop, ss+1, stopst, lev+1));
|
||||
return(backref(charset, m, sp, stop, ss+1, stopst, lev+1));
|
||||
break;
|
||||
case O_PLUS:
|
||||
if (sp == m->lastpos[lev]) /* last pass matched null */
|
||||
return(backref(m, sp, stop, ss+1, stopst, lev-1));
|
||||
return(backref(charset, m, sp, stop, ss+1, stopst, lev-1));
|
||||
/* try another pass */
|
||||
m->lastpos[lev] = sp;
|
||||
dp = backref(m, sp, stop, ss-OPND(s)+1, stopst, lev);
|
||||
dp = backref(charset, m, sp, stop, ss-OPND(s)+1, stopst, lev);
|
||||
if (dp == NULL)
|
||||
return(backref(m, sp, stop, ss+1, stopst, lev-1));
|
||||
return(backref(charset, m, sp, stop, ss+1, stopst, lev-1));
|
||||
else
|
||||
return(dp);
|
||||
break;
|
||||
@ -573,7 +576,7 @@ sopno lev; /* PLUS nesting level */
|
||||
esub = ss + OPND(s) - 1;
|
||||
assert(OP(m->g->strip[esub]) == OOR1);
|
||||
for (;;) { /* find first matching branch */
|
||||
dp = backref(m, sp, stop, ssub, esub, lev);
|
||||
dp = backref(charset, m, sp, stop, ssub, esub, lev);
|
||||
if (dp != NULL)
|
||||
return(dp);
|
||||
/* that one missed, try next one */
|
||||
@ -594,7 +597,7 @@ sopno lev; /* PLUS nesting level */
|
||||
assert(0 < i && i <= m->g->nsub);
|
||||
offsave = m->pmatch[i].rm_so;
|
||||
m->pmatch[i].rm_so = sp - m->offp;
|
||||
dp = backref(m, sp, stop, ss+1, stopst, lev);
|
||||
dp = backref(charset, m, sp, stop, ss+1, stopst, lev);
|
||||
if (dp != NULL)
|
||||
return(dp);
|
||||
m->pmatch[i].rm_so = offsave;
|
||||
@ -605,7 +608,7 @@ sopno lev; /* PLUS nesting level */
|
||||
assert(0 < i && i <= m->g->nsub);
|
||||
offsave = m->pmatch[i].rm_eo;
|
||||
m->pmatch[i].rm_eo = sp - m->offp;
|
||||
dp = backref(m, sp, stop, ss+1, stopst, lev);
|
||||
dp = backref(charset, m, sp, stop, ss+1, stopst, lev);
|
||||
if (dp != NULL)
|
||||
return(dp);
|
||||
m->pmatch[i].rm_eo = offsave;
|
||||
@ -628,7 +631,8 @@ sopno lev; /* PLUS nesting level */
|
||||
== char *stop, sopno startst, sopno stopst);
|
||||
*/
|
||||
static char * /* where tentative match ended, or NULL */
|
||||
fast(m, start, stop, startst, stopst)
|
||||
fast(charset, m, start, stop, startst, stopst)
|
||||
CHARSET_INFO *charset;
|
||||
register struct match *m;
|
||||
char *start;
|
||||
char *stop;
|
||||
@ -678,12 +682,12 @@ sopno stopst;
|
||||
}
|
||||
|
||||
/* how about a word boundary? */
|
||||
if ( (flagch == BOL || (lastc != OUT && !ISWORD(lastc))) &&
|
||||
(c != OUT && ISWORD(c)) ) {
|
||||
if ( (flagch == BOL || (lastc != OUT && !ISWORD(charset,lastc))) &&
|
||||
(c != OUT && ISWORD(charset,c)) ) {
|
||||
flagch = BOW;
|
||||
}
|
||||
if ( (lastc != OUT && ISWORD(lastc)) &&
|
||||
(flagch == EOL || (c != OUT && !ISWORD(c))) ) {
|
||||
if ( (lastc != OUT && ISWORD(charset,lastc)) &&
|
||||
(flagch == EOL || (c != OUT && !ISWORD(charset,c))) ) {
|
||||
flagch = EOW;
|
||||
}
|
||||
if (flagch == BOW || flagch == EOW) {
|
||||
@ -719,7 +723,8 @@ sopno stopst;
|
||||
== char *stop, sopno startst, sopno stopst);
|
||||
*/
|
||||
static char * /* where it ended */
|
||||
slow(m, start, stop, startst, stopst)
|
||||
slow(charset, m, start, stop, startst, stopst)
|
||||
CHARSET_INFO *charset;
|
||||
register struct match *m;
|
||||
char *start;
|
||||
char *stop;
|
||||
@ -767,12 +772,12 @@ sopno stopst;
|
||||
}
|
||||
|
||||
/* how about a word boundary? */
|
||||
if ( (flagch == BOL || (lastc != OUT && !ISWORD(lastc))) &&
|
||||
(c != OUT && ISWORD(c)) ) {
|
||||
if ( (flagch == BOL || (lastc != OUT && !ISWORD(charset,lastc))) &&
|
||||
(c != OUT && ISWORD(charset,c)) ) {
|
||||
flagch = BOW;
|
||||
}
|
||||
if ( (lastc != OUT && ISWORD(lastc)) &&
|
||||
(flagch == EOL || (c != OUT && !ISWORD(c))) ) {
|
||||
if ( (lastc != OUT && ISWORD(charset,lastc)) &&
|
||||
(flagch == EOL || (c != OUT && !ISWORD(charset,c))) ) {
|
||||
flagch = EOW;
|
||||
}
|
||||
if (flagch == BOW || flagch == EOW) {
|
||||
|
@ -4,11 +4,11 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
/* === engine.c === */
|
||||
static int matcher(register struct re_guts *g, char *string, size_t nmatch, regmatch_t pmatch[], int eflags);
|
||||
static char *dissect(register struct match *m, char *start, char *stop, sopno startst, sopno stopst);
|
||||
static char *backref(register struct match *m, char *start, char *stop, sopno startst, sopno stopst, sopno lev);
|
||||
static char *fast(register struct match *m, char *start, char *stop, sopno startst, sopno stopst);
|
||||
static char *slow(register struct match *m, char *start, char *stop, sopno startst, sopno stopst);
|
||||
static int matcher(CHARSET_INFO *charset,register struct re_guts *g, char *string, size_t nmatch, regmatch_t pmatch[], int eflags);
|
||||
static char *dissect(CHARSET_INFO *charset,register struct match *m, char *start, char *stop, sopno startst, sopno stopst);
|
||||
static char *backref(CHARSET_INFO *charset, register struct match *m, char *start, char *stop, sopno startst, sopno stopst, sopno lev);
|
||||
static char *fast(CHARSET_INFO *charset, register struct match *m, char *start, char *stop, sopno startst, sopno stopst);
|
||||
static char *slow(CHARSET_INFO *charset, register struct match *m, char *start, char *stop, sopno startst, sopno stopst);
|
||||
static states step(register struct re_guts *g, sopno start, sopno stop, register states bef, int ch, register states aft);
|
||||
#define BOL (OUT+1)
|
||||
#define EOL (BOL+1)
|
||||
|
@ -74,7 +74,7 @@ char *argv[];
|
||||
exit(status);
|
||||
}
|
||||
|
||||
err = regcomp(&re, argv[optind++], copts);
|
||||
err = regcomp(&re, argv[optind++], copts, default_charset_info);
|
||||
if (err) {
|
||||
len = regerror(err, &re, erbuf, sizeof(erbuf));
|
||||
fprintf(stderr, "error %s, %d/%d `%s'\n",
|
||||
@ -226,7 +226,7 @@ int opts; /* may not match f1 */
|
||||
strcpy(f0copy, f0);
|
||||
re.re_endp = (opts®_PEND) ? f0copy + strlen(f0copy) : NULL;
|
||||
fixstr(f0copy);
|
||||
err = regcomp(&re, f0copy, opts);
|
||||
err = regcomp(&re, f0copy, opts, default_charset_info);
|
||||
if (err != 0 && (!opt('C', f1) || err != efind(f2))) {
|
||||
/* unexpected error or wrong error */
|
||||
len = regerror(err, &re, erbuf, sizeof(erbuf));
|
||||
|
@ -28,6 +28,7 @@ struct parse {
|
||||
# define NPAREN 10 /* we need to remember () 1-9 for back refs */
|
||||
sopno pbegin[NPAREN]; /* -> ( ([0] unused) */
|
||||
sopno pend[NPAREN]; /* -> ) ([0] unused) */
|
||||
CHARSET_INFO *charset; /* for ctype things */
|
||||
};
|
||||
|
||||
#include "regcomp.ih"
|
||||
@ -99,10 +100,11 @@ static int never = 0; /* for use in asserts; shuts lint up */
|
||||
= #define REG_DUMP 0200
|
||||
*/
|
||||
int /* 0 success, otherwise REG_something */
|
||||
regcomp(preg, pattern, cflags)
|
||||
regcomp(preg, pattern, cflags, charset)
|
||||
regex_t *preg;
|
||||
const char *pattern;
|
||||
int cflags;
|
||||
CHARSET_INFO *charset;
|
||||
{
|
||||
struct parse pa;
|
||||
register struct re_guts *g;
|
||||
@ -116,6 +118,7 @@ int cflags;
|
||||
#endif
|
||||
|
||||
regex_init(); /* Init cclass if neaded */
|
||||
preg->charset=charset;
|
||||
cflags = GOODFLAGS(cflags);
|
||||
if ((cflags®_EXTENDED) && (cflags®_NOSPEC))
|
||||
return(REG_INVARG);
|
||||
@ -146,6 +149,7 @@ int cflags;
|
||||
p->end = p->next + len;
|
||||
p->error = 0;
|
||||
p->ncsalloc = 0;
|
||||
p->charset = preg->charset;
|
||||
for (i = 0; i < NPAREN; i++) {
|
||||
p->pbegin[i] = 0;
|
||||
p->pend[i] = 0;
|
||||
@ -327,7 +331,7 @@ register struct parse *p;
|
||||
ordinary(p, c);
|
||||
break;
|
||||
case '{': /* okay as ordinary except if digit follows */
|
||||
if(REQUIRE(!MORE() || !isdigit(PEEK()), REG_BADRPT)) {}
|
||||
if(REQUIRE(!MORE() || !my_isdigit(p->charset,PEEK()), REG_BADRPT)) {}
|
||||
/* FALLTHROUGH */
|
||||
default:
|
||||
ordinary(p, c);
|
||||
@ -339,7 +343,8 @@ register struct parse *p;
|
||||
c = PEEK();
|
||||
/* we call { a repetition if followed by a digit */
|
||||
if (!( c == '*' || c == '+' || c == '?' ||
|
||||
(c == '{' && MORE2() && isdigit(PEEK2())) ))
|
||||
(c == '{' && MORE2() &&
|
||||
my_isdigit(p->charset,PEEK2())) ))
|
||||
return; /* no repetition, we're done */
|
||||
NEXT();
|
||||
|
||||
@ -368,7 +373,7 @@ register struct parse *p;
|
||||
case '{':
|
||||
count = p_count(p);
|
||||
if (EAT(',')) {
|
||||
if (isdigit(PEEK())) {
|
||||
if (my_isdigit(p->charset,PEEK())) {
|
||||
count2 = p_count(p);
|
||||
if(REQUIRE(count <= count2, REG_BADBR)) {}
|
||||
} else /* single number with comma */
|
||||
@ -389,7 +394,8 @@ register struct parse *p;
|
||||
return;
|
||||
c = PEEK();
|
||||
if (!( c == '*' || c == '+' || c == '?' ||
|
||||
(c == '{' && MORE2() && isdigit(PEEK2())) ) )
|
||||
(c == '{' && MORE2() &&
|
||||
my_isdigit(p->charset,PEEK2())) ) )
|
||||
return;
|
||||
SETERROR(REG_BADRPT);
|
||||
}
|
||||
@ -546,7 +552,7 @@ int starordinary; /* is a leading * an ordinary character? */
|
||||
} else if (EATTWO('\\', '{')) {
|
||||
count = p_count(p);
|
||||
if (EAT(',')) {
|
||||
if (MORE() && isdigit(PEEK())) {
|
||||
if (MORE() && my_isdigit(p->charset,PEEK())) {
|
||||
count2 = p_count(p);
|
||||
if(REQUIRE(count <= count2, REG_BADBR)) {}
|
||||
} else /* single number with comma */
|
||||
@ -577,7 +583,7 @@ register struct parse *p;
|
||||
register int count = 0;
|
||||
register int ndigits = 0;
|
||||
|
||||
while (MORE() && isdigit(PEEK()) && count <= DUPMAX) {
|
||||
while (MORE() && my_isdigit(p->charset,PEEK()) && count <= DUPMAX) {
|
||||
count = count*10 + (GETNEXT() - '0');
|
||||
ndigits++;
|
||||
}
|
||||
@ -632,8 +638,8 @@ register struct parse *p;
|
||||
register int ci;
|
||||
|
||||
for (i = p->g->csetsize - 1; i >= 0; i--)
|
||||
if (CHIN(cs, i) && isalpha(i)) {
|
||||
ci = othercase(i);
|
||||
if (CHIN(cs, i) && my_isalpha(p->charset,i)) {
|
||||
ci = othercase(p->charset,i);
|
||||
if (ci != i)
|
||||
CHadd(cs, ci);
|
||||
}
|
||||
@ -744,7 +750,7 @@ register cset *cs;
|
||||
register char *u;
|
||||
register char c;
|
||||
|
||||
while (MORE() && isalpha(PEEK()))
|
||||
while (MORE() && my_isalpha(p->charset,PEEK()))
|
||||
NEXT();
|
||||
len = p->next - sp;
|
||||
for (cp = cclasses; cp->name != NULL; cp++)
|
||||
@ -837,14 +843,15 @@ int endc; /* name ended by endc,']' */
|
||||
== static char othercase(int ch);
|
||||
*/
|
||||
static char /* if no counterpart, return ch */
|
||||
othercase(ch)
|
||||
othercase(charset,ch)
|
||||
CHARSET_INFO *charset;
|
||||
int ch;
|
||||
{
|
||||
assert(isalpha(ch));
|
||||
if (isupper(ch))
|
||||
return(tolower(ch));
|
||||
else if (islower(ch))
|
||||
return(toupper(ch));
|
||||
assert(my_isalpha(charset,ch));
|
||||
if (my_isupper(charset,ch))
|
||||
return(my_tolower(charset,ch));
|
||||
else if (my_islower(charset,ch))
|
||||
return(my_toupper(charset,ch));
|
||||
else /* peculiar, but could happen */
|
||||
return(ch);
|
||||
}
|
||||
@ -887,7 +894,8 @@ register int ch;
|
||||
{
|
||||
register cat_t *cap = p->g->categories;
|
||||
|
||||
if ((p->g->cflags®_ICASE) && isalpha(ch) && othercase(ch) != ch)
|
||||
if ((p->g->cflags®_ICASE) && my_isalpha(p->charset,ch) &&
|
||||
othercase(p->charset,ch) != ch)
|
||||
bothcases(p, ch);
|
||||
else {
|
||||
EMIT(OCHAR, (unsigned char)ch);
|
||||
|
@ -16,7 +16,7 @@ static void p_b_cclass(register struct parse *p, register cset *cs);
|
||||
static void p_b_eclass(register struct parse *p, register cset *cs);
|
||||
static char p_b_symbol(register struct parse *p);
|
||||
static char p_b_coll_elem(register struct parse *p, int endc);
|
||||
static char othercase(int ch);
|
||||
static char othercase(CHARSET_INFO *charset,int ch);
|
||||
static void bothcases(register struct parse *p, int ch);
|
||||
static void ordinary(register struct parse *p, register int ch);
|
||||
static void nonnewline(register struct parse *p);
|
||||
|
@ -5,6 +5,8 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "m_ctype.h"
|
||||
|
||||
/* === regex2.h === */
|
||||
#ifdef _WIN64
|
||||
typedef __int64 regoff_t;
|
||||
@ -17,6 +19,7 @@ typedef struct {
|
||||
size_t re_nsub; /* number of parenthesized subexpressions */
|
||||
const char *re_endp; /* end pointer for REG_PEND */
|
||||
struct re_guts *re_g; /* none of your business :-) */
|
||||
CHARSET_INFO *charset; /* For ctype things */
|
||||
} regex_t;
|
||||
typedef struct {
|
||||
regoff_t rm_so; /* start of match */
|
||||
@ -25,7 +28,7 @@ typedef struct {
|
||||
|
||||
|
||||
/* === regcomp.c === */
|
||||
extern int regcomp(regex_t *, const char *, int);
|
||||
extern int regcomp(regex_t *, const char *, int, CHARSET_INFO *charset);
|
||||
#define REG_BASIC 0000
|
||||
#define REG_EXTENDED 0001
|
||||
#define REG_ICASE 0002
|
||||
|
@ -140,6 +140,6 @@ struct re_guts {
|
||||
/* misc utilities */
|
||||
#undef OUT /* May be defined in windows */
|
||||
#define OUT (CHAR_MAX+1) /* a non-character value */
|
||||
#define ISWORD(c) (isalnum(c) || (c) == '_')
|
||||
#define ISWORD(s,c) (my_isalnum(s,c) || (c) == '_')
|
||||
|
||||
#endif /* __regex2_h__ */
|
||||
|
@ -133,7 +133,7 @@ int eflags;
|
||||
|
||||
if ((size_t) g->nstates <= CHAR_BIT*sizeof(states1) &&
|
||||
!(eflags®_LARGE))
|
||||
return(smatcher(g, (char *)str, nmatch, pmatch, eflags));
|
||||
return(smatcher(preg->charset, g, (char *)str, nmatch, pmatch, eflags));
|
||||
else
|
||||
return(lmatcher(g, (char *)str, nmatch, pmatch, eflags));
|
||||
return(lmatcher(preg->charset, g, (char *)str, nmatch, pmatch, eflags));
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ void regex_init()
|
||||
char buff[CCLASS_LAST][256];
|
||||
int count[CCLASS_LAST];
|
||||
uint i;
|
||||
CHARSET_INFO *cs=default_charset_info;
|
||||
|
||||
if (!regex_inited)
|
||||
{
|
||||
@ -20,27 +21,27 @@ void regex_init()
|
||||
|
||||
for (i=1 ; i<= 255; i++)
|
||||
{
|
||||
if (isalnum(i))
|
||||
if (my_isalnum(cs,i))
|
||||
buff[CCLASS_ALNUM][count[CCLASS_ALNUM]++]=(char) i;
|
||||
if (isalpha(i))
|
||||
if (my_isalpha(cs,i))
|
||||
buff[CCLASS_ALPHA][count[CCLASS_ALPHA]++]=(char) i;
|
||||
if (iscntrl(i))
|
||||
if (my_iscntrl(cs,i))
|
||||
buff[CCLASS_CNTRL][count[CCLASS_CNTRL]++]=(char) i;
|
||||
if (isdigit(i))
|
||||
if (my_isdigit(cs,i))
|
||||
buff[CCLASS_DIGIT][count[CCLASS_DIGIT]++]=(char) i;
|
||||
if (isgraph(i))
|
||||
if (my_isgraph(cs,i))
|
||||
buff[CCLASS_GRAPH][count[CCLASS_GRAPH]++]=(char) i;
|
||||
if (islower(i))
|
||||
if (my_islower(cs,i))
|
||||
buff[CCLASS_LOWER][count[CCLASS_LOWER]++]=(char) i;
|
||||
if (isprint(i))
|
||||
if (my_isprint(cs,i))
|
||||
buff[CCLASS_PRINT][count[CCLASS_PRINT]++]=(char) i;
|
||||
if (ispunct(i))
|
||||
if (my_ispunct(cs,i))
|
||||
buff[CCLASS_PUNCT][count[CCLASS_PUNCT]++]=(char) i;
|
||||
if (isspace(i))
|
||||
if (my_isspace(cs,i))
|
||||
buff[CCLASS_SPACE][count[CCLASS_SPACE]++]=(char) i;
|
||||
if (isupper(i))
|
||||
if (my_isupper(cs,i))
|
||||
buff[CCLASS_UPPER][count[CCLASS_UPPER]++]=(char) i;
|
||||
if (isxdigit(i))
|
||||
if (my_isxdigit(cs,i))
|
||||
buff[CCLASS_XDIGIT][count[CCLASS_XDIGIT]++]=(char) i;
|
||||
}
|
||||
buff[CCLASS_BLANK][0]=' ';
|
||||
|
@ -79,9 +79,10 @@ mysqld_SOURCES = sql_lex.cc sql_handler.cc \
|
||||
sql_db.cc sql_table.cc sql_rename.cc sql_crypt.cc \
|
||||
sql_load.cc mf_iocache.cc field_conv.cc sql_show.cc \
|
||||
sql_udf.cc sql_analyse.cc sql_analyse.h sql_cache.cc \
|
||||
slave.cc sql_repl.cc sql_union.cc \
|
||||
slave.cc sql_repl.cc sql_union.cc sql_derived.cc \
|
||||
mini_client.cc mini_client_errors.c \
|
||||
stacktrace.c repl_failsafe.h repl_failsafe.cc
|
||||
stacktrace.c repl_failsafe.h repl_failsafe.cc \
|
||||
gstream.cc spatial.cc
|
||||
gen_lex_hash_SOURCES = gen_lex_hash.cc
|
||||
gen_lex_hash_LDADD = $(LDADD) $(CXXLDFLAGS)
|
||||
|
||||
|
@ -433,7 +433,17 @@ CONVERT *get_convert_set(const char *name)
|
||||
{
|
||||
for (CONVERT **ptr=convert_tables ; *ptr ; ptr++)
|
||||
{
|
||||
if (!my_strcasecmp((*ptr)->name,name))
|
||||
/*
|
||||
BAR TODO: Monty's comments:
|
||||
Why is this using system_charset_info ?
|
||||
Isn't the character-set string given in the users default charset?
|
||||
Please add a TODO note to the code that this has to be fixed when the user
|
||||
will be able to cast strings to different character sets...
|
||||
The current code will also not work if/when we introduce support for
|
||||
16 bit characters...
|
||||
(I know that there is a LOT of changes to do if we ever want do this...)
|
||||
*/
|
||||
if (!my_strcasecmp(system_charset_info,(*ptr)->name,name))
|
||||
return (*ptr);
|
||||
}
|
||||
return 0;
|
||||
|
@ -70,9 +70,10 @@ load_des_key_file(const char *file_name)
|
||||
{
|
||||
offset=(char) (offset - '0');
|
||||
// Remove newline and possible other control characters
|
||||
for (start=buf+1 ; isspace(*start) ; start++) ;
|
||||
for (start=buf+1 ; my_isspace(system_charset_info, *start) ; start++) ;
|
||||
end=buf+length;
|
||||
for (end=strend(buf) ; end > start && !isgraph(end[-1]) ; end--) ;
|
||||
for (end=strend(buf) ;
|
||||
end > start && !my_isgraph(system_charset_info, end[-1]) ; end--) ;
|
||||
|
||||
if (start != end)
|
||||
{
|
||||
|
171
sql/field.cc
171
sql/field.cc
@ -68,7 +68,8 @@ const char field_separator=',';
|
||||
*/
|
||||
|
||||
static bool
|
||||
number_dec(struct st_decstr *sdec, const char *str, const char *end)
|
||||
number_dec(CHARSET_INFO *cs, struct st_decstr *sdec,
|
||||
const char *str, const char *end)
|
||||
{
|
||||
sdec->sign=sdec->extra=0;
|
||||
if (str == end)
|
||||
@ -86,7 +87,7 @@ number_dec(struct st_decstr *sdec, const char *str, const char *end)
|
||||
str++;
|
||||
}
|
||||
const char *start=str;
|
||||
while (str != end && isdigit(*str))
|
||||
while (str != end && my_isdigit(cs,*str))
|
||||
str++;
|
||||
if (!(sdec->nr_length=(uint) (str-start)))
|
||||
sdec->extra=1; // We must put one 0 before .
|
||||
@ -95,13 +96,13 @@ number_dec(struct st_decstr *sdec, const char *str, const char *end)
|
||||
{
|
||||
str++;
|
||||
start=str;
|
||||
while (str != end && isdigit(*str))
|
||||
while (str != end && my_isdigit(cs,*str))
|
||||
str++;
|
||||
}
|
||||
sdec->nr_dec=(uint) (str-start);
|
||||
if (current_thd->count_cuted_fields)
|
||||
{
|
||||
while (str != end && isspace(*str))
|
||||
while (str != end && my_isspace(cs,*str))
|
||||
str++; /* purecov: inspected */
|
||||
if (str != end)
|
||||
{
|
||||
@ -135,7 +136,8 @@ bool test_if_int(const char *str,int length)
|
||||
{
|
||||
const char *end=str+length;
|
||||
|
||||
while (str != end && isspace(*str)) // Allow start space
|
||||
// Allow start space
|
||||
while (str != end && my_isspace(system_charset_info,*str))
|
||||
str++; /* purecov: inspected */
|
||||
if (str != end && (*str == '-' || *str == '+'))
|
||||
str++;
|
||||
@ -143,7 +145,7 @@ bool test_if_int(const char *str,int length)
|
||||
return 0; // Error: Empty string
|
||||
for ( ; str != end ; str++)
|
||||
{
|
||||
if (!isdigit(*str))
|
||||
if (!my_isdigit(system_charset_info,*str))
|
||||
{
|
||||
if (*str == '.')
|
||||
{ // Allow '.0000'
|
||||
@ -151,10 +153,10 @@ bool test_if_int(const char *str,int length)
|
||||
if (str == end)
|
||||
return 1;
|
||||
}
|
||||
if (!isspace(*str))
|
||||
if (!my_isspace(system_charset_info,*str))
|
||||
return 0;
|
||||
for (str++ ; str != end ; str++)
|
||||
if (!isspace(*str))
|
||||
if (!my_isspace(system_charset_info,*str))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
@ -165,7 +167,7 @@ bool test_if_int(const char *str,int length)
|
||||
|
||||
static bool test_if_real(const char *str,int length)
|
||||
{
|
||||
while (length && isspace(*str))
|
||||
while (length && my_isspace(system_charset_info,*str))
|
||||
{ // Allow start space
|
||||
length--; str++;
|
||||
}
|
||||
@ -174,10 +176,10 @@ static bool test_if_real(const char *str,int length)
|
||||
if (*str == '+' || *str == '-')
|
||||
{
|
||||
length--; str++;
|
||||
if (!length || !(isdigit(*str) || *str == '.'))
|
||||
if (!length || !(my_isdigit(system_charset_info,*str) || *str == '.'))
|
||||
return 0;
|
||||
}
|
||||
while (length && isdigit(*str))
|
||||
while (length && my_isdigit(system_charset_info,*str))
|
||||
{
|
||||
length--; str++;
|
||||
}
|
||||
@ -186,7 +188,7 @@ static bool test_if_real(const char *str,int length)
|
||||
if (*str == '.')
|
||||
{
|
||||
length--; str++;
|
||||
while (length && isdigit(*str))
|
||||
while (length && my_isdigit(system_charset_info,*str))
|
||||
{
|
||||
length--; str++;
|
||||
}
|
||||
@ -195,18 +197,19 @@ static bool test_if_real(const char *str,int length)
|
||||
return 1;
|
||||
if (*str == 'E' || *str == 'e')
|
||||
{
|
||||
if (length < 3 || (str[1] != '+' && str[1] != '-') || !isdigit(str[2]))
|
||||
if (length < 3 || (str[1] != '+' && str[1] != '-') ||
|
||||
!my_isdigit(system_charset_info,str[2]))
|
||||
return 0;
|
||||
length-=3;
|
||||
str+=3;
|
||||
while (length && isdigit(*str))
|
||||
while (length && my_isdigit(system_charset_info,*str))
|
||||
{
|
||||
length--; str++;
|
||||
}
|
||||
}
|
||||
for ( ; length ; length--, str++)
|
||||
{ // Allow end space
|
||||
if (!isspace(*str))
|
||||
if (!my_isspace(system_charset_info,*str))
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
@ -405,7 +408,7 @@ void Field_decimal::store(const char *from,uint len)
|
||||
|
||||
if ((tmp_dec= dec))
|
||||
tmp_dec++; // Calculate pos of '.'
|
||||
while (from != end && isspace(*from))
|
||||
while (from != end && my_isspace(system_charset_info,*from))
|
||||
from++;
|
||||
if (zerofill)
|
||||
{
|
||||
@ -416,7 +419,7 @@ void Field_decimal::store(const char *from,uint len)
|
||||
}
|
||||
else
|
||||
fyllchar=' ';
|
||||
error=number_dec(&decstr,from,end);
|
||||
error=number_dec(system_charset_info,&decstr,from,end);
|
||||
if (decstr.sign)
|
||||
{
|
||||
from++;
|
||||
@ -479,7 +482,7 @@ void Field_decimal::store(const char *from,uint len)
|
||||
{
|
||||
if (*from != '0')
|
||||
{
|
||||
if (!isspace(*from)) // Space is ok
|
||||
if (!my_isspace(system_charset_info,*from)) // Space is ok
|
||||
current_thd->cuted_fields++;
|
||||
break;
|
||||
}
|
||||
@ -603,8 +606,10 @@ int Field_decimal::cmp(const char *a_ptr,const char *b_ptr)
|
||||
for (end=a_ptr+field_length;
|
||||
a_ptr != end &&
|
||||
(*a_ptr == *b_ptr ||
|
||||
((isspace(*a_ptr) || *a_ptr == '+' || *a_ptr == '0') &&
|
||||
(isspace(*b_ptr) || *b_ptr == '+' || *b_ptr == '0')));
|
||||
((my_isspace(system_charset_info,*a_ptr) || *a_ptr == '+' ||
|
||||
*a_ptr == '0') &&
|
||||
(my_isspace(system_charset_info,*b_ptr) || *b_ptr == '+' ||
|
||||
*b_ptr == '0')));
|
||||
a_ptr++,b_ptr++)
|
||||
{
|
||||
if (*a_ptr == '-') // If both numbers are negative
|
||||
@ -631,7 +636,7 @@ void Field_decimal::sort_string(char *to,uint length)
|
||||
char *str,*end;
|
||||
for (str=ptr,end=ptr+length;
|
||||
str != end &&
|
||||
((isspace(*str) || *str == '+' || *str == '0')) ;
|
||||
((my_isspace(system_charset_info,*str) || *str == '+' || *str == '0')) ;
|
||||
|
||||
str++)
|
||||
*to++=' ';
|
||||
@ -643,7 +648,7 @@ void Field_decimal::sort_string(char *to,uint length)
|
||||
*to++=1; // Smaller than any number
|
||||
str++;
|
||||
while (str != end)
|
||||
if (isdigit(*str))
|
||||
if (my_isdigit(system_charset_info,*str))
|
||||
*to++= (char) ('9' - *str++);
|
||||
else
|
||||
*to++= *str++;
|
||||
@ -1265,7 +1270,7 @@ void Field_medium::sql_type(String &res) const
|
||||
|
||||
void Field_long::store(const char *from,uint len)
|
||||
{
|
||||
while (len && isspace(*from))
|
||||
while (len && my_isspace(system_charset_info,*from))
|
||||
{
|
||||
len--; from++;
|
||||
}
|
||||
@ -1493,7 +1498,7 @@ void Field_long::sql_type(String &res) const
|
||||
|
||||
void Field_longlong::store(const char *from,uint len)
|
||||
{
|
||||
while (len && isspace(*from))
|
||||
while (len && my_isspace(system_charset_info,*from))
|
||||
{ // For easy error check
|
||||
len--; from++;
|
||||
}
|
||||
@ -3331,7 +3336,7 @@ void Field_string::store(const char *from,uint length)
|
||||
const char *end=from+length;
|
||||
for (from+=field_length ; from != end ; from++)
|
||||
{
|
||||
if (!isspace(*from))
|
||||
if (!my_isspace(field_charset,*from))
|
||||
{
|
||||
current_thd->cuted_fields++;
|
||||
break;
|
||||
@ -3402,7 +3407,7 @@ int Field_string::cmp(const char *a_ptr, const char *b_ptr)
|
||||
if (binary_flag)
|
||||
return memcmp(a_ptr,b_ptr,field_length);
|
||||
else
|
||||
return my_sortcmp(a_ptr,b_ptr,field_length);
|
||||
return my_sortcmp(field_charset,a_ptr,b_ptr,field_length);
|
||||
}
|
||||
|
||||
void Field_string::sort_string(char *to,uint length)
|
||||
@ -3412,17 +3417,17 @@ void Field_string::sort_string(char *to,uint length)
|
||||
else
|
||||
{
|
||||
#ifdef USE_STRCOLL
|
||||
if (use_strcoll(default_charset_info)) {
|
||||
uint tmp=my_strnxfrm(default_charset_info,
|
||||
(unsigned char *)to, (unsigned char *) ptr,
|
||||
length, field_length);
|
||||
if (use_strcoll(field_charset)) {
|
||||
uint tmp=my_strnxfrm(field_charset,
|
||||
(unsigned char *)to, length,
|
||||
(unsigned char *) ptr, field_length);
|
||||
if (tmp < length)
|
||||
bzero(to + tmp, length - tmp);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
for (char *from=ptr,*end=ptr+length ; from != end ;)
|
||||
*to++=(char) my_sort_order[(uint) (uchar) *from++];
|
||||
*to++=(char) field_charset->sort_order[(uint) (uchar) *from++];
|
||||
}
|
||||
}
|
||||
|
||||
@ -3471,7 +3476,7 @@ int Field_string::pack_cmp(const char *a, const char *b, uint length)
|
||||
int cmp= memcmp(a,b,min(a_length,b_length));
|
||||
return cmp ? cmp : (int) (a_length - b_length);
|
||||
}
|
||||
return my_sortncmp(a,a_length, b,b_length);
|
||||
return my_sortncmp(field_charset, a,a_length, b,b_length);
|
||||
}
|
||||
|
||||
|
||||
@ -3488,7 +3493,7 @@ int Field_string::pack_cmp(const char *b, uint length)
|
||||
int cmp= memcmp(ptr,b,min(a_length,b_length));
|
||||
return cmp ? cmp : (int) (a_length - b_length);
|
||||
}
|
||||
return my_sortncmp(ptr,a_length, b, b_length);
|
||||
return my_sortncmp(field_charset, ptr,a_length, b, b_length);
|
||||
}
|
||||
|
||||
|
||||
@ -3593,7 +3598,7 @@ int Field_varstring::cmp(const char *a_ptr, const char *b_ptr)
|
||||
if (binary_flag)
|
||||
diff=memcmp(a_ptr+2,b_ptr+2,min(a_length,b_length));
|
||||
else
|
||||
diff=my_sortcmp(a_ptr+2,b_ptr+2,min(a_length,b_length));
|
||||
diff=my_sortcmp(field_charset, a_ptr+2,b_ptr+2,min(a_length,b_length));
|
||||
return diff ? diff : (int) (a_length - b_length);
|
||||
}
|
||||
|
||||
@ -3605,10 +3610,10 @@ void Field_varstring::sort_string(char *to,uint length)
|
||||
else
|
||||
{
|
||||
#ifdef USE_STRCOLL
|
||||
if (use_strcoll(default_charset_info))
|
||||
tot_length=my_strnxfrm(default_charset_info,
|
||||
(unsigned char *) to, (unsigned char *)ptr+2,
|
||||
length, tot_length);
|
||||
if (use_strcoll(field_charset))
|
||||
tot_length=my_strnxfrm(field_charset,
|
||||
(unsigned char *) to, length,
|
||||
(unsigned char *)ptr+2, tot_length);
|
||||
else
|
||||
{
|
||||
#endif
|
||||
@ -3616,7 +3621,7 @@ void Field_varstring::sort_string(char *to,uint length)
|
||||
if (tot_length > length)
|
||||
tot_length=length;
|
||||
for (char *from=ptr+2,*end=from+tot_length ; from != end ;)
|
||||
*tmp++=(char) my_sort_order[(uint) (uchar) *from++];
|
||||
*tmp++=(char) field_charset->sort_order[(uint) (uchar) *from++];
|
||||
#ifdef USE_STRCOLL
|
||||
}
|
||||
#endif
|
||||
@ -3687,7 +3692,7 @@ int Field_varstring::pack_cmp(const char *a, const char *b, uint key_length)
|
||||
int cmp= memcmp(a,b,min(a_length,b_length));
|
||||
return cmp ? cmp : (int) (a_length - b_length);
|
||||
}
|
||||
return my_sortncmp(a,a_length, b,b_length);
|
||||
return my_sortncmp(field_charset, a,a_length, b,b_length);
|
||||
}
|
||||
|
||||
int Field_varstring::pack_cmp(const char *b, uint key_length)
|
||||
@ -3708,7 +3713,7 @@ int Field_varstring::pack_cmp(const char *b, uint key_length)
|
||||
int cmp= memcmp(a,b,min(a_length,b_length));
|
||||
return cmp ? cmp : (int) (a_length - b_length);
|
||||
}
|
||||
return my_sortncmp(a,a_length, b,b_length);
|
||||
return my_sortncmp(field_charset, a,a_length, b,b_length);
|
||||
}
|
||||
|
||||
uint Field_varstring::packed_col_length(const char *ptr, uint length)
|
||||
@ -3737,7 +3742,7 @@ Field_blob::Field_blob(char *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg,
|
||||
:Field_str(ptr_arg, (1L << min(blob_pack_length,3)*8)-1L,
|
||||
null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg,
|
||||
table_arg),
|
||||
packlength(blob_pack_length),binary_flag(binary_arg)
|
||||
packlength(blob_pack_length),binary_flag(binary_arg), geom_flag(true)
|
||||
{
|
||||
flags|= BLOB_FLAG;
|
||||
if (binary_arg)
|
||||
@ -3931,7 +3936,7 @@ int Field_blob::cmp(const char *a,uint32 a_length, const char *b,
|
||||
if (binary_flag)
|
||||
diff=memcmp(a,b,min(a_length,b_length));
|
||||
else
|
||||
diff=my_sortcmp(a,b,min(a_length,b_length));
|
||||
diff=my_sortcmp(field_charset, a,b,min(a_length,b_length));
|
||||
return diff ? diff : (int) (a_length - b_length);
|
||||
}
|
||||
|
||||
@ -3979,8 +3984,30 @@ int Field_blob::cmp_binary(const char *a_ptr, const char *b_ptr,
|
||||
|
||||
/* The following is used only when comparing a key */
|
||||
|
||||
void Field_blob::get_key_image(char *buff,uint length)
|
||||
void Field_blob::get_key_image(char *buff,uint length, imagetype type)
|
||||
{
|
||||
if(type == itMBR)
|
||||
{
|
||||
length-=HA_KEY_BLOB_LENGTH;
|
||||
ulong blob_length=get_length(ptr);
|
||||
char *blob;
|
||||
get_ptr(&blob);
|
||||
if(!blob_length)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
MBR mbr;
|
||||
Geometry gobj;
|
||||
gobj.create_from_wkb(blob,blob_length);
|
||||
gobj.get_mbr(&mbr);
|
||||
float8store(buff, mbr.xmin);
|
||||
float8store(buff+8, mbr.xmax);
|
||||
float8store(buff+16, mbr.ymin);
|
||||
float8store(buff+24, mbr.ymax);
|
||||
return;
|
||||
}
|
||||
|
||||
length-=HA_KEY_BLOB_LENGTH;
|
||||
uint32 blob_length=get_length(ptr);
|
||||
char *blob;
|
||||
@ -4002,6 +4029,31 @@ void Field_blob::set_key_image(char *buff,uint length)
|
||||
Field_blob::store(buff+2,length);
|
||||
}
|
||||
|
||||
void Field_geom::get_key_image(char *buff,uint length, imagetype type)
|
||||
{
|
||||
length-=HA_KEY_BLOB_LENGTH;
|
||||
ulong blob_length=get_length(ptr);
|
||||
char *blob;
|
||||
get_ptr(&blob);
|
||||
memcpy(buff+2,blob,length);
|
||||
|
||||
MBR mbr;
|
||||
Geometry gobj;
|
||||
gobj.create_from_wkb(blob,blob_length);
|
||||
gobj.get_mbr(&mbr);
|
||||
float8store(buff, mbr.xmin);
|
||||
float8store(buff+8, mbr.xmax);
|
||||
float8store(buff+16, mbr.ymin);
|
||||
float8store(buff+24, mbr.ymax);
|
||||
return;
|
||||
}
|
||||
|
||||
void Field_geom::set_key_image(char *buff,uint length)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
int Field_blob::key_cmp(const byte *key_ptr, uint max_key_length)
|
||||
{
|
||||
char *blob1;
|
||||
@ -4041,11 +4093,11 @@ void Field_blob::sort_string(char *to,uint length)
|
||||
else
|
||||
{
|
||||
#ifdef USE_STRCOLL
|
||||
if (use_strcoll(default_charset_info))
|
||||
if (use_strcoll(field_charset))
|
||||
{
|
||||
blob_length=my_strnxfrm(default_charset_info,
|
||||
(unsigned char *)to,(unsigned char *)blob,
|
||||
length,blob_org_length);
|
||||
blob_length=my_strnxfrm(field_charset,
|
||||
(unsigned char *)to, length,
|
||||
(unsigned char *)blob, blob_org_length);
|
||||
if (blob_length >= length)
|
||||
return;
|
||||
to+=blob_length;
|
||||
@ -4053,7 +4105,7 @@ void Field_blob::sort_string(char *to,uint length)
|
||||
else
|
||||
#endif
|
||||
for (char *end=blob+blob_length ; blob != end ;)
|
||||
*to++=(char) my_sort_order[(uint) (uchar) *blob++];
|
||||
*to++=(char) field_charset->sort_order[(uint) (uchar) *blob++];
|
||||
}
|
||||
bzero(to,length-blob_length);
|
||||
}
|
||||
@ -4131,7 +4183,7 @@ int Field_blob::pack_cmp(const char *a, const char *b, uint key_length)
|
||||
int cmp= memcmp(a,b,min(a_length,b_length));
|
||||
return cmp ? cmp : (int) (a_length - b_length);
|
||||
}
|
||||
return my_sortncmp(a,a_length, b,b_length);
|
||||
return my_sortncmp(field_charset, a,a_length, b,b_length);
|
||||
}
|
||||
|
||||
|
||||
@ -4157,7 +4209,7 @@ int Field_blob::pack_cmp(const char *b, uint key_length)
|
||||
int cmp= memcmp(a,b,min(a_length,b_length));
|
||||
return cmp ? cmp : (int) (a_length - b_length);
|
||||
}
|
||||
return my_sortncmp(a,a_length, b,b_length);
|
||||
return my_sortncmp(field_charset, a,a_length, b,b_length);
|
||||
}
|
||||
|
||||
/* Create a packed key that will be used for storage from a MySQL row */
|
||||
@ -4268,14 +4320,16 @@ void Field_enum::store_type(ulonglong value)
|
||||
uint find_enum(TYPELIB *lib,const char *x, uint length)
|
||||
{
|
||||
const char *end=x+length;
|
||||
while (end > x && isspace(end[-1]))
|
||||
while (end > x && my_isspace(system_charset_info,end[-1]))
|
||||
end--;
|
||||
|
||||
const char *i;
|
||||
const char *j;
|
||||
for (uint pos=0 ; (j=lib->type_names[pos]) ; pos++)
|
||||
{
|
||||
for (i=x ; i != end && toupper(*i) == toupper(*j) ; i++, j++) ;
|
||||
for (i=x ; i != end &&
|
||||
my_toupper(system_charset_info,*i) ==
|
||||
my_toupper(system_charset_info,*j) ; i++, j++) ;
|
||||
if (i == end && ! *j)
|
||||
return(pos+1);
|
||||
}
|
||||
@ -4452,7 +4506,7 @@ void Field_enum::sql_type(String &res) const
|
||||
ulonglong find_set(TYPELIB *lib,const char *x,uint length)
|
||||
{
|
||||
const char *end=x+length;
|
||||
while (end > x && isspace(end[-1]))
|
||||
while (end > x && my_isspace(system_charset_info, end[-1]))
|
||||
end--;
|
||||
|
||||
ulonglong found=0;
|
||||
@ -4578,7 +4632,8 @@ bool Field_enum::eq_def(Field *field)
|
||||
if (typelib->count < from_lib->count)
|
||||
return 0;
|
||||
for (uint i=0 ; i < from_lib->count ; i++)
|
||||
if (my_strcasecmp(typelib->type_names[i],from_lib->type_names[i]))
|
||||
if (my_strcasecmp(field_charset,
|
||||
typelib->type_names[i],from_lib->type_names[i]))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
@ -4631,6 +4686,7 @@ uint32 calc_pack_length(enum_field_types type,uint32 length)
|
||||
case FIELD_TYPE_LONG_BLOB: return 4+portable_sizeof_char_ptr;
|
||||
case FIELD_TYPE_SET:
|
||||
case FIELD_TYPE_ENUM: abort(); return 0; // This shouldn't happen
|
||||
default: return 0;
|
||||
}
|
||||
return 0; // This shouldn't happen
|
||||
}
|
||||
@ -4677,6 +4733,11 @@ Field *make_field(char *ptr, uint32 field_length,
|
||||
return new Field_blob(ptr,null_pos,null_bit,
|
||||
unireg_check, field_name, table,
|
||||
pack_length,f_is_binary(pack_flag) != 0);
|
||||
if (f_is_geom(pack_flag))
|
||||
return new Field_geom(ptr,null_pos,null_bit,
|
||||
unireg_check, field_name, table,
|
||||
pack_length,f_is_binary(pack_flag) != 0);
|
||||
|
||||
if (interval)
|
||||
{
|
||||
if (f_is_enum(pack_flag))
|
||||
|
52
sql/field.h
52
sql/field.h
@ -47,6 +47,9 @@ public:
|
||||
enum utype { NONE,DATE,SHIELD,NOEMPTY,CASEUP,PNR,BGNR,PGNR,YES,NO,REL,
|
||||
CHECK,EMPTY,UNKNOWN_FIELD,CASEDN,NEXT_NUMBER,INTERVAL_FIELD,
|
||||
BIT_FIELD, TIMESTAMP_FIELD,CAPITALIZE,BLOB_FIELD};
|
||||
|
||||
enum imagetype { itRAW, itMBR};
|
||||
|
||||
utype unireg_check;
|
||||
uint32 field_length; // Length of field
|
||||
uint16 flags;
|
||||
@ -137,17 +140,12 @@ public:
|
||||
{ memcpy(buff,ptr,length); }
|
||||
inline void set_image(char *buff,uint length)
|
||||
{ memcpy(ptr,buff,length); }
|
||||
virtual void get_key_image(char *buff,uint length)
|
||||
virtual void get_key_image(char *buff,uint length, imagetype type)
|
||||
{ get_image(buff,length); }
|
||||
virtual void set_key_image(char *buff,uint length)
|
||||
{ set_image(buff,length); }
|
||||
inline int cmp_image(char *buff,uint length)
|
||||
{
|
||||
if (binary())
|
||||
return memcmp(ptr,buff,length);
|
||||
else
|
||||
return my_casecmp(ptr,buff,length);
|
||||
}
|
||||
{ return memcmp(ptr,buff,length); }
|
||||
inline longlong val_int_offset(uint row_offset)
|
||||
{
|
||||
ptr+=row_offset;
|
||||
@ -238,6 +236,8 @@ public:
|
||||
|
||||
|
||||
class Field_str :public Field {
|
||||
protected:
|
||||
CHARSET_INFO *field_charset;
|
||||
public:
|
||||
Field_str(char *ptr_arg,uint32 len_arg, uchar *null_ptr_arg,
|
||||
uchar null_bit_arg, utype unireg_check_arg,
|
||||
@ -245,12 +245,21 @@ public:
|
||||
struct st_table *table_arg)
|
||||
:Field(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
|
||||
unireg_check_arg, field_name_arg, table_arg)
|
||||
{}
|
||||
{ field_charset=default_charset_info; }
|
||||
Item_result result_type () const { return STRING_RESULT; }
|
||||
uint decimals() const { return NOT_FIXED_DEC; }
|
||||
friend class create_field;
|
||||
void make_field(Send_field *);
|
||||
uint size_of() const { return sizeof(*this); }
|
||||
inline CHARSET_INFO *charset() const { return field_charset; }
|
||||
inline int cmp_image(char *buff,uint length)
|
||||
{
|
||||
if (binary())
|
||||
return memcmp(ptr,buff,length);
|
||||
else
|
||||
return my_strncasecmp(field_charset,ptr,buff,length);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
@ -825,6 +834,7 @@ class Field_blob :public Field_str {
|
||||
uint packlength;
|
||||
String value; // For temporaries
|
||||
bool binary_flag;
|
||||
bool geom_flag;
|
||||
public:
|
||||
Field_blob(char *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg,
|
||||
enum utype unireg_check_arg, const char *field_name_arg,
|
||||
@ -834,7 +844,7 @@ public:
|
||||
struct st_table *table_arg, bool binary_arg)
|
||||
:Field_str((char*) 0,len_arg, maybe_null_arg ? (uchar*) "": 0,0,
|
||||
NONE, field_name_arg, table_arg),
|
||||
packlength(3),binary_flag(binary_arg)
|
||||
packlength(3),binary_flag(binary_arg), geom_flag(true)
|
||||
{
|
||||
flags|= BLOB_FLAG;
|
||||
if (binary_arg)
|
||||
@ -881,7 +891,7 @@ public:
|
||||
store_length(length);
|
||||
memcpy_fixed(ptr+packlength,&data,sizeof(char*));
|
||||
}
|
||||
void get_key_image(char *buff,uint length);
|
||||
void get_key_image(char *buff,uint length, imagetype type);
|
||||
void set_key_image(char *buff,uint length);
|
||||
void sql_type(String &str) const;
|
||||
inline bool copy()
|
||||
@ -910,6 +920,25 @@ public:
|
||||
};
|
||||
|
||||
|
||||
class Field_geom :public Field_blob {
|
||||
public:
|
||||
Field_geom(char *ptr_arg, uchar *null_ptr_arg, uint null_bit_arg,
|
||||
enum utype unireg_check_arg, const char *field_name_arg,
|
||||
struct st_table *table_arg,uint blob_pack_length,
|
||||
bool binary_arg)
|
||||
:Field_blob(ptr_arg, null_ptr_arg, null_bit_arg, unireg_check_arg,
|
||||
field_name_arg, table_arg, blob_pack_length,binary_arg) {}
|
||||
Field_geom(uint32 len_arg,bool maybe_null_arg, const char *field_name_arg,
|
||||
struct st_table *table_arg, bool binary_arg)
|
||||
:Field_blob(len_arg, maybe_null_arg, field_name_arg,
|
||||
table_arg, binary_arg) {}
|
||||
enum ha_base_keytype key_type() const { return HA_KEYTYPE_VARBINARY; }
|
||||
|
||||
void get_key_image(char *buff,uint length, imagetype type);
|
||||
void set_key_image(char *buff,uint length);
|
||||
};
|
||||
|
||||
|
||||
class Field_enum :public Field_str {
|
||||
protected:
|
||||
uint packlength;
|
||||
@ -1059,6 +1088,8 @@ bool test_if_int(const char *str,int length);
|
||||
#define FIELDFLAG_INTERVAL 256
|
||||
#define FIELDFLAG_BITFIELD 512 // mangled with dec!
|
||||
#define FIELDFLAG_BLOB 1024 // mangled with dec!
|
||||
#define FIELDFLAG_GEOM 2048
|
||||
|
||||
#define FIELDFLAG_LEFT_FULLSCREEN 8192
|
||||
#define FIELDFLAG_RIGHT_FULLSCREEN 16384
|
||||
#define FIELDFLAG_FORMAT_NUMBER 16384 // predit: ###,,## in output
|
||||
@ -1085,6 +1116,7 @@ bool test_if_int(const char *str,int length);
|
||||
#define f_is_enum(x) ((x) & FIELDFLAG_INTERVAL)
|
||||
#define f_is_bitfield(x) ((x) & FIELDFLAG_BITFIELD)
|
||||
#define f_is_blob(x) (((x) & (FIELDFLAG_BLOB | FIELDFLAG_NUMBER)) == FIELDFLAG_BLOB)
|
||||
#define f_is_geom(x) ((x) & FIELDFLAG_GEOM)
|
||||
#define f_is_equ(x) ((x) & (1+2+FIELDFLAG_PACK+31*256))
|
||||
#define f_settype(x) (((int) x) << FIELDFLAG_PACK_SHIFT)
|
||||
#define f_maybe_null(x) (x & FIELDFLAG_MAYBE_NULL)
|
||||
|
@ -276,7 +276,7 @@ static void do_cut_string(Copy_field *copy)
|
||||
ptr != end ;
|
||||
ptr++)
|
||||
{
|
||||
if (!isspace(*ptr))
|
||||
if (!my_isspace(system_charset_info, *ptr))
|
||||
{
|
||||
current_thd->cuted_fields++; // Give a warning
|
||||
break;
|
||||
|
@ -205,7 +205,7 @@ ha_rows filesort(TABLE *table, SORT_FIELD *sortorder, uint s_length,
|
||||
|
||||
err:
|
||||
#ifdef USE_STRCOLL
|
||||
if (use_strcoll(default_charset_info))
|
||||
if (param.tmp_buffer)
|
||||
x_free(param.tmp_buffer);
|
||||
#endif
|
||||
x_free((gptr) sort_keys);
|
||||
@ -467,6 +467,8 @@ static void make_sortkey(register SORTPARAM *param,
|
||||
switch (sort_field->result_type) {
|
||||
case STRING_RESULT:
|
||||
{
|
||||
CHARSET_INFO *cs=item->str_value.charset();
|
||||
|
||||
if (item->maybe_null)
|
||||
*to++=1;
|
||||
/* All item->str() to use some extra byte for end null.. */
|
||||
@ -492,7 +494,7 @@ static void make_sortkey(register SORTPARAM *param,
|
||||
length=sort_field->length;
|
||||
}
|
||||
#ifdef USE_STRCOLL
|
||||
if (use_strcoll(default_charset_info))
|
||||
if(use_strcoll(cs))
|
||||
{
|
||||
if (item->binary)
|
||||
{
|
||||
@ -509,10 +511,8 @@ static void make_sortkey(register SORTPARAM *param,
|
||||
memcpy(param->tmp_buffer,from,length);
|
||||
from=param->tmp_buffer;
|
||||
}
|
||||
uint tmp_length=my_strnxfrm(default_charset_info,
|
||||
to,(unsigned char *) from,
|
||||
sort_field->length,
|
||||
length);
|
||||
uint tmp_length=my_strnxfrm(cs,to,sort_field->length,
|
||||
(unsigned char *) from, length);
|
||||
if (tmp_length < sort_field->length)
|
||||
bzero((char*) to+tmp_length,sort_field->length-tmp_length);
|
||||
}
|
||||
@ -524,7 +524,7 @@ static void make_sortkey(register SORTPARAM *param,
|
||||
memcpy(to,res->ptr(),length);
|
||||
bzero((char *)to+length,diff);
|
||||
if (!item->binary)
|
||||
case_sort((char*) to,length);
|
||||
case_sort(cs, (char*) to,length);
|
||||
#ifdef USE_STRCOLL
|
||||
}
|
||||
#endif
|
||||
@ -921,8 +921,13 @@ sortlength(SORT_FIELD *sortorder, uint s_length)
|
||||
{
|
||||
sortorder->length=sortorder->field->pack_length();
|
||||
#ifdef USE_STRCOLL
|
||||
if (use_strcoll(default_charset_info) && !sortorder->field->binary())
|
||||
sortorder->length= sortorder->length*MY_STRXFRM_MULTIPLY;
|
||||
if (!sortorder->field->binary())
|
||||
{
|
||||
// BAR TODO: need checking that it is really Field_str based class
|
||||
CHARSET_INFO *cs=((Field_str*)(sortorder->field))->charset();
|
||||
if (use_strcoll(cs))
|
||||
sortorder->length= sortorder->length*cs->strxfrm_multiply;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if (sortorder->field->maybe_null())
|
||||
@ -930,12 +935,19 @@ sortlength(SORT_FIELD *sortorder, uint s_length)
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef USE_STRCOLL
|
||||
|
||||
#endif
|
||||
switch ((sortorder->result_type=sortorder->item->result_type())) {
|
||||
case STRING_RESULT:
|
||||
sortorder->length=sortorder->item->max_length;
|
||||
#ifdef USE_STRCOLL
|
||||
if (use_strcoll(default_charset_info) && !sortorder->item->binary)
|
||||
sortorder->length= sortorder->length*MY_STRXFRM_MULTIPLY;
|
||||
if (!sortorder->item->binary)
|
||||
{
|
||||
CHARSET_INFO *cs=sortorder->item->str_value.charset();
|
||||
if (use_strcoll(cs))
|
||||
sortorder->length= sortorder->length*cs->strxfrm_multiply;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case INT_RESULT:
|
||||
|
@ -30,7 +30,7 @@ bool opt_search=0;
|
||||
int opt_verbose=0;
|
||||
ulong opt_count=100000;
|
||||
|
||||
#define max_allowed_array 8000 // Don't generate bigger arrays than this
|
||||
#define max_allowed_array 16000 // Don't generate bigger arrays than this
|
||||
#define max_symbol 32767 // Use this for 'not found'
|
||||
#define how_much_for_plus 8 // 2-8
|
||||
#define type_count 1 // 1-5
|
||||
|
137
sql/gstream.cc
Normal file
137
sql/gstream.cc
Normal file
@ -0,0 +1,137 @@
|
||||
#include "mysql_priv.h"
|
||||
|
||||
int GTextReadStream::get_next_toc_type() const
|
||||
{
|
||||
const char *cur = m_cur;
|
||||
while((*cur)&&(strchr(" \t\r\n",*cur)))
|
||||
{
|
||||
cur++;
|
||||
}
|
||||
if(!(*cur))
|
||||
{
|
||||
return eostream;
|
||||
}
|
||||
|
||||
if(((*cur>='a') && (*cur<='z')) || ((*cur>='A') && (*cur<='Z')) || (*cur=='_'))
|
||||
{
|
||||
return word;
|
||||
}
|
||||
|
||||
if(((*cur>='0') && (*cur<='9')) || (*cur=='-') || (*cur=='+') || (*cur=='.'))
|
||||
{
|
||||
return numeric;
|
||||
}
|
||||
|
||||
if(*cur == '(')
|
||||
{
|
||||
return l_bra;
|
||||
}
|
||||
|
||||
if(*cur == ')')
|
||||
{
|
||||
return r_bra;
|
||||
}
|
||||
|
||||
if(*cur == ',')
|
||||
{
|
||||
return comma;
|
||||
}
|
||||
|
||||
return unknown;
|
||||
}
|
||||
|
||||
const char *GTextReadStream::get_next_word(int *word_len)
|
||||
{
|
||||
const char *cur = m_cur;
|
||||
while((*cur)&&(strchr(" \t\r\n",*cur)))
|
||||
{
|
||||
cur++;
|
||||
}
|
||||
m_last_text_position = cur;
|
||||
|
||||
if(!(*cur))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *wd_start = cur;
|
||||
|
||||
if(((*cur<'a') || (*cur>'z')) && ((*cur<'A') || (*cur>'Z')) && (*cur!='_'))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
++cur;
|
||||
|
||||
while(((*cur>='a') && (*cur<='z')) || ((*cur>='A') && (*cur<='Z')) || (*cur=='_') ||
|
||||
((*cur>='0') && (*cur<='9')))
|
||||
{
|
||||
++cur;
|
||||
}
|
||||
|
||||
*word_len = cur - wd_start;
|
||||
|
||||
m_cur = cur;
|
||||
|
||||
return wd_start;
|
||||
}
|
||||
|
||||
int GTextReadStream::get_next_number(double *d)
|
||||
{
|
||||
const char *cur = m_cur;
|
||||
while((*cur)&&(strchr(" \t\r\n",*cur)))
|
||||
{
|
||||
cur++;
|
||||
}
|
||||
|
||||
m_last_text_position = cur;
|
||||
if(!(*cur))
|
||||
{
|
||||
set_error_msg("Numeric constant expected");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(((*cur<'0') || (*cur>'9')) && (*cur!='-') && (*cur!='+') && (*cur!='.'))
|
||||
{
|
||||
set_error_msg("Numeric constant expected");
|
||||
return 1;
|
||||
}
|
||||
|
||||
char *endptr;
|
||||
|
||||
*d = strtod(cur, &endptr);
|
||||
|
||||
if(endptr)
|
||||
{
|
||||
m_cur = endptr;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
char GTextReadStream::get_next_symbol()
|
||||
{
|
||||
const char *cur = m_cur;
|
||||
while((*cur)&&(strchr(" \t\r\n",*cur)))
|
||||
{
|
||||
cur++;
|
||||
}
|
||||
if(!(*cur))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
m_cur = cur + 1;
|
||||
m_last_text_position = cur;
|
||||
|
||||
return *cur;
|
||||
}
|
||||
|
||||
void GTextReadStream::set_error_msg(const char *msg)
|
||||
{
|
||||
size_t len = strlen(msg);
|
||||
m_err_msg = (char *)my_realloc(m_err_msg, len + 1, MYF(MY_ALLOW_ZERO_PTR));
|
||||
memcpy(m_err_msg, msg, len + 1);
|
||||
}
|
||||
|
||||
|
61
sql/gstream.h
Normal file
61
sql/gstream.h
Normal file
@ -0,0 +1,61 @@
|
||||
#ifndef GSTREAM_H
|
||||
#define GSTREAM_H
|
||||
|
||||
#ifdef WITHOUT_MYSQL
|
||||
#include ".\rtree\myisamdef.h"
|
||||
#else
|
||||
#include "mysql_priv.h"
|
||||
#endif
|
||||
|
||||
class GTextReadStream
|
||||
{
|
||||
public:
|
||||
enum TokTypes
|
||||
{
|
||||
unknown,
|
||||
eostream,
|
||||
word,
|
||||
numeric,
|
||||
l_bra,
|
||||
r_bra,
|
||||
comma,
|
||||
};
|
||||
GTextReadStream(const char *buffer, int size) :
|
||||
m_cur(buffer), m_limit(buffer + size), m_last_text_position(buffer), m_err_msg(NULL) {}
|
||||
GTextReadStream() : m_cur(NULL), m_limit(NULL), m_err_msg(NULL) {}
|
||||
|
||||
~GTextReadStream()
|
||||
{
|
||||
my_free(m_err_msg, MYF(MY_ALLOW_ZERO_PTR));
|
||||
}
|
||||
|
||||
int get_next_toc_type() const;
|
||||
const char *get_next_word(int *word_len);
|
||||
int get_next_number(double *d);
|
||||
char get_next_symbol();
|
||||
|
||||
const char *get_last_text_position() const
|
||||
{
|
||||
return m_last_text_position;
|
||||
}
|
||||
|
||||
void set_error_msg(const char *msg);
|
||||
|
||||
// caller should free this pointer
|
||||
char *get_error_msg()
|
||||
{
|
||||
char *err_msg = m_err_msg;
|
||||
m_err_msg = NULL;
|
||||
return err_msg;
|
||||
}
|
||||
protected:
|
||||
const char *m_cur;
|
||||
const char *m_limit;
|
||||
const char *m_last_text_position;
|
||||
char *m_err_msg;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user