mirror of
https://github.com/MariaDB/server.git
synced 2025-01-17 04:22:27 +01:00
70aa7424c4
(All commit emails since 4.0.1 checked) This had to be done now, before the 4.1 tree changes to much, to make it easy to propagate bug fixes to the 4.1 tree. BUILD/SETUP.sh: Added -DPEDANTIC_SAFEMALLOC as standard debug option Docs/manual.texi: Changes for new version. client/mysql.cc: Fixed default value for rehash cleanup client/mysqladmin.c: Cleanup client/mysqlbinlog.cc: cleanup client/mysqldump.c: Cleanup client/mysqlmanager-pwgen.c: Cleanup client/mysqlmanagerc.c: Cleanup client/mysqltest.c: Cleanup dbug/dbug.c: Cleanup extra/resolve_stack_dump.c: Cleanup & Simple optimizations include/ft_global.h: Cleanup include/my_alloc.h: Cleanup include/my_global.h: Cleanup include/my_sys.h: Cleanup include/myisam.h: Cleanup libmysql/libmysql.c: Cleanup libmysql/manager.c: Cleanup myisam/ft_boolean_search.c: Cleanup myisam/ft_dump.c: Change strcpy -> strmov myisam/ft_eval.c: Cleanup myisam/ft_nlq_search.c: Cleanup myisam/ft_test1.c: strncpy -> strnmov myisam/ft_update.c: Cleanup myisam/mi_static.c: Cleanup myisam/mi_test2.c: Cleanup myisam/mi_write.c: Cleanup mysys/mf_fn_ext.c: Cleanup mysys/mf_iocache.c: Cleanup mysys/mf_iocache2.c: Cleanup mysys/my_getopt.c: Cleanup mysys/my_read.c: Cleanup mysys/my_thr_init.c: Cleanup mysys/queues.c: Cleanup mysys/safemalloc.c: Cleanup sql/field.cc: Indentation cleanups sql/ha_berkeley.cc: Indentation cleanups sql/ha_myisam.cc: Cleanup sql/item.h: Indentation cleanups sql/item_cmpfunc.cc: Indentation cleanups sql/item_create.cc: cleanup sql/item_func.cc: Cleanup sql/item_func.h: Indentation cleanups sql/item_strfunc.cc: Indentation cleanups sql/item_sum.cc: Indentation cleanups sql/item_timefunc.cc: Indentation cleanups sql/lock.cc: Indentation cleanups sql/log.cc: Cleanup strnmov -> strmake sql/log_event.cc: Cleanup + optimizations Fixed memory leak Added missing pthread_mutex_unlock() (On error condition) sql/log_event.h: Indentation and comment cleanup Merged #ifdef's into common blocks for better readability sql/mini_client.cc: Indentation cleanup sql/mysql_priv.h: Cleanup Changed int function to bool sql/mysqld.cc: Indentation and comment cleanup sql/net_pkg.cc: Indentation cleanup sql/net_serv.cc: Changed int function -> bool sql/nt_servc.cc: Cleanup sql/opt_range.cc: Indentation cleanup sql/repl_failsafe.cc: Cleanup + simple optimization strnmov -> strmake sql/slave.cc: strnmov -> strmake Cleanups sql/slave.h: Cleanup sql/sql_acl.cc: Indentation and DBUG_PRINT cleanup Changed WITH MAX... to not use = sql/sql_base.cc: Indentation cleanup sql/sql_cache.cc: Indentation cleanup sql/sql_class.cc: Indentation cleanup sql/sql_class.h: Renamed some struct slots sql/sql_delete.cc: Indentation cleanup sql/sql_handler.cc: Indentation cleanup sql/sql_insert.cc: Use new slot names. sql/sql_lex.cc: Indentation cleanup sql/sql_lex.h: Indentation cleanup sql/sql_load.cc: Indentation cleanup sql/sql_parse.cc: Indentation cleanup Removed not used check from LOCK TABLES sql/sql_repl.cc: strnmov -> strmake sql/sql_repl.h: Removed test if file is included (We want to know if it's included twice to avoid this) sql/sql_select.cc: Indentation cleanup sql/sql_show.cc: Indentation cleanup sql/sql_string.cc: Indentation cleanup sql/sql_table.cc: Indentation cleanup sql/sql_union.cc: Use renamed struct slot sql/sql_update.cc: Indentation cleanup sql/sql_yacc.yy: Removed = after GRANT ... MAX_ to make the syntax uniform sql/table.cc: Indentation cleanup sql/table.h: Indentation cleanup sql/time.cc: Indentation cleanup sql/udf_example.cc: Indentation cleanup sql/unireg.cc: strnmov -> strmake tests/grant.pl: Added test for LOCK TABLES tools/mysqlmanager.c: Cleanup fopen() -> my_fopen() vio/viosocket.c: DBUG_PRINT cleanups vio/viosslfactories.c: Indentation cleanup Checking of results from malloc() Fixed possible memory leak BitKeeper/etc/ignore: Added scripts/mysql_secure_installation to the ignore list BitKeeper/etc/logging_ok: Logging to logging@openlogging.org accepted
804 lines
18 KiB
C++
804 lines
18 KiB
C++
/* Copyright (C) 2000 MySQL 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 */
|
|
|
|
/* This file is originally from the mysql distribution. Coded by monty */
|
|
|
|
#ifdef __GNUC__
|
|
#pragma implementation // gcc: Class implementation
|
|
#endif
|
|
|
|
#include <my_global.h>
|
|
#include <my_sys.h>
|
|
#include <m_string.h>
|
|
#include <m_ctype.h>
|
|
#ifdef HAVE_FCONVERT
|
|
#include <floatingpoint.h>
|
|
#endif
|
|
|
|
extern gptr sql_alloc(unsigned size);
|
|
extern void sql_element_free(void *ptr);
|
|
|
|
#include "sql_string.h"
|
|
|
|
/*****************************************************************************
|
|
** String functions
|
|
*****************************************************************************/
|
|
|
|
bool String::real_alloc(uint32 arg_length)
|
|
{
|
|
arg_length=ALIGN_SIZE(arg_length+1);
|
|
str_length=0;
|
|
if (Alloced_length < arg_length)
|
|
{
|
|
free();
|
|
if (!(Ptr=(char*) my_malloc(arg_length,MYF(MY_WME))))
|
|
return TRUE;
|
|
Alloced_length=arg_length;
|
|
alloced=1;
|
|
}
|
|
Ptr[0]=0;
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
/*
|
|
** Check that string is big enough. Set string[alloc_length] to 0
|
|
** (for C functions)
|
|
*/
|
|
|
|
bool String::realloc(uint32 alloc_length)
|
|
{
|
|
uint32 len=ALIGN_SIZE(alloc_length+1);
|
|
if (Alloced_length < len)
|
|
{
|
|
char *new_ptr;
|
|
if (alloced)
|
|
{
|
|
if ((new_ptr= (char*) my_realloc(Ptr,len,MYF(MY_WME))))
|
|
{
|
|
Ptr=new_ptr;
|
|
Alloced_length=len;
|
|
}
|
|
else
|
|
return TRUE; // Signal error
|
|
}
|
|
else if ((new_ptr= (char*) my_malloc(len,MYF(MY_WME))))
|
|
{
|
|
if (str_length) // Avoid bugs in memcpy on AIX
|
|
memcpy(new_ptr,Ptr,str_length);
|
|
new_ptr[str_length]=0;
|
|
Ptr=new_ptr;
|
|
Alloced_length=len;
|
|
alloced=1;
|
|
}
|
|
else
|
|
return TRUE; // Signal error
|
|
}
|
|
Ptr[alloc_length]=0; // This make other funcs shorter
|
|
return FALSE;
|
|
}
|
|
|
|
bool String::set(longlong num)
|
|
{
|
|
if (alloc(21))
|
|
return TRUE;
|
|
str_length=(uint32) (longlong10_to_str(num,Ptr,-10)-Ptr);
|
|
return FALSE;
|
|
}
|
|
|
|
bool String::set(ulonglong num)
|
|
{
|
|
if (alloc(21))
|
|
return TRUE;
|
|
str_length=(uint32) (longlong10_to_str(num,Ptr,10)-Ptr);
|
|
return FALSE;
|
|
}
|
|
|
|
bool String::set(double num,uint decimals)
|
|
{
|
|
char buff[331];
|
|
if (decimals >= NOT_FIXED_DEC)
|
|
{
|
|
sprintf(buff,"%.14g",num); // Enough for a DATETIME
|
|
return copy(buff, (uint32) strlen(buff));
|
|
}
|
|
#ifdef HAVE_FCONVERT
|
|
int decpt,sign;
|
|
char *pos,*to;
|
|
|
|
VOID(fconvert(num,(int) decimals,&decpt,&sign,buff+1));
|
|
if (!isdigit(buff[1]))
|
|
{ // Nan or Inf
|
|
pos=buff+1;
|
|
if (sign)
|
|
{
|
|
buff[0]='-';
|
|
pos=buff;
|
|
}
|
|
return copy(pos,(uint32) strlen(pos));
|
|
}
|
|
if (alloc((uint32) ((uint32) decpt+3+decimals)))
|
|
return TRUE;
|
|
to=Ptr;
|
|
if (sign)
|
|
*to++='-';
|
|
|
|
pos=buff+1;
|
|
if (decpt < 0)
|
|
{ /* value is < 0 */
|
|
*to++='0';
|
|
if (!decimals)
|
|
goto end;
|
|
*to++='.';
|
|
if ((uint32) -decpt > decimals)
|
|
decpt= - (int) decimals;
|
|
decimals=(uint32) ((int) decimals+decpt);
|
|
while (decpt++ < 0)
|
|
*to++='0';
|
|
}
|
|
else if (decpt == 0)
|
|
{
|
|
*to++= '0';
|
|
if (!decimals)
|
|
goto end;
|
|
*to++='.';
|
|
}
|
|
else
|
|
{
|
|
while (decpt-- > 0)
|
|
*to++= *pos++;
|
|
if (!decimals)
|
|
goto end;
|
|
*to++='.';
|
|
}
|
|
while (decimals--)
|
|
*to++= *pos++;
|
|
|
|
end:
|
|
*to=0;
|
|
str_length=(uint32) (to-Ptr);
|
|
return FALSE;
|
|
#else
|
|
#ifdef HAVE_SNPRINTF
|
|
buff[sizeof(buff)-1]=0; // Safety
|
|
snprintf(buff,sizeof(buff)-1, "%.*f",(int) decimals,num);
|
|
#else
|
|
sprintf(buff,"%.*f",(int) decimals,num);
|
|
#endif
|
|
return copy(buff,(uint32) strlen(buff));
|
|
#endif
|
|
}
|
|
|
|
|
|
bool String::copy()
|
|
{
|
|
if (!alloced)
|
|
{
|
|
Alloced_length=0; // Force realloc
|
|
return realloc(str_length);
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
bool String::copy(const String &str)
|
|
{
|
|
if (alloc(str.str_length))
|
|
return TRUE;
|
|
str_length=str.str_length;
|
|
bmove(Ptr,str.Ptr,str_length); // May be overlapping
|
|
Ptr[str_length]=0;
|
|
return FALSE;
|
|
}
|
|
|
|
bool String::copy(const char *str,uint32 arg_length)
|
|
{
|
|
if (alloc(arg_length))
|
|
return TRUE;
|
|
if ((str_length=arg_length))
|
|
memcpy(Ptr,str,arg_length);
|
|
Ptr[arg_length]=0;
|
|
return FALSE;
|
|
}
|
|
|
|
/* This is used by mysql.cc */
|
|
|
|
bool String::fill(uint32 max_length,char fill_char)
|
|
{
|
|
if (str_length > max_length)
|
|
Ptr[str_length=max_length]=0;
|
|
else
|
|
{
|
|
if (realloc(max_length))
|
|
return TRUE;
|
|
bfill(Ptr+str_length,max_length-str_length,fill_char);
|
|
str_length=max_length;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
void String::strip_sp()
|
|
{
|
|
while (str_length && isspace(Ptr[str_length-1]))
|
|
str_length--;
|
|
}
|
|
|
|
bool String::append(const String &s)
|
|
{
|
|
if (s.length())
|
|
{
|
|
if (realloc(str_length+s.length()))
|
|
return TRUE;
|
|
memcpy(Ptr+str_length,s.ptr(),s.length());
|
|
str_length+=s.length();
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
bool String::append(const char *s,uint32 arg_length)
|
|
{
|
|
if (!arg_length) // Default argument
|
|
if (!(arg_length= (uint32) strlen(s)))
|
|
return FALSE;
|
|
if (realloc(str_length+arg_length))
|
|
return TRUE;
|
|
memcpy(Ptr+str_length,s,arg_length);
|
|
str_length+=arg_length;
|
|
return FALSE;
|
|
}
|
|
|
|
#ifdef TO_BE_REMOVED
|
|
bool String::append(FILE* file, uint32 arg_length, myf my_flags)
|
|
{
|
|
if (realloc(str_length+arg_length))
|
|
return TRUE;
|
|
if (my_fread(file, (byte*) Ptr + str_length, arg_length, my_flags))
|
|
{
|
|
shrink(str_length);
|
|
return TRUE;
|
|
}
|
|
str_length+=arg_length;
|
|
return FALSE;
|
|
}
|
|
#endif
|
|
|
|
bool String::append(IO_CACHE* file, uint32 arg_length)
|
|
{
|
|
if (realloc(str_length+arg_length))
|
|
return TRUE;
|
|
if (my_b_read(file, (byte*) Ptr + str_length, arg_length))
|
|
{
|
|
shrink(str_length);
|
|
return TRUE;
|
|
}
|
|
str_length+=arg_length;
|
|
return FALSE;
|
|
}
|
|
|
|
uint32 String::numchars()
|
|
{
|
|
#ifdef USE_MB
|
|
register uint32 n=0,mblen;
|
|
register const char *mbstr=Ptr;
|
|
register const char *end=mbstr+str_length;
|
|
if (use_mb(default_charset_info))
|
|
{
|
|
while (mbstr < end) {
|
|
if ((mblen=my_ismbchar(default_charset_info, mbstr,end))) mbstr+=mblen;
|
|
else ++mbstr;
|
|
++n;
|
|
}
|
|
return n;
|
|
}
|
|
else
|
|
#endif
|
|
return str_length;
|
|
}
|
|
|
|
int String::charpos(int i,uint32 offset)
|
|
{
|
|
#ifdef USE_MB
|
|
register uint32 mblen;
|
|
register const char *mbstr=Ptr+offset;
|
|
register const char *end=Ptr+str_length;
|
|
if (use_mb(default_charset_info))
|
|
{
|
|
if (i<=0) return i;
|
|
while (i && mbstr < end) {
|
|
if ((mblen=my_ismbchar(default_charset_info, mbstr,end))) mbstr+=mblen;
|
|
else ++mbstr;
|
|
--i;
|
|
}
|
|
if ( INT_MAX32-i <= (int) (mbstr-Ptr-offset))
|
|
return INT_MAX32;
|
|
else
|
|
return (int) ((mbstr-Ptr-offset)+i);
|
|
}
|
|
else
|
|
#endif
|
|
return i;
|
|
}
|
|
|
|
int String::strstr(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++ == *search)
|
|
{
|
|
register char *i,*j;
|
|
i=(char*) str; j=(char*) search+1;
|
|
while (j != search_end)
|
|
if (*i++ != *j++) goto skipp;
|
|
return (int) (str-Ptr) -1;
|
|
}
|
|
}
|
|
}
|
|
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 (my_sort_order[*str++] == my_sort_order[*search])
|
|
{
|
|
register char *i,*j;
|
|
i=(char*) str; j=(char*) search+1;
|
|
while (j != search_end)
|
|
if (my_sort_order[*i++] != my_sort_order[*j++]) goto skipp;
|
|
return (int) (str-Ptr) -1;
|
|
}
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
** Search string from end. Offset is offset to the end of string
|
|
*/
|
|
|
|
int String::strrstr(const String &s,uint32 offset)
|
|
{
|
|
if (s.length() <= offset && offset <= str_length)
|
|
{
|
|
if (!s.length())
|
|
return offset; // Empty string is always found
|
|
register const char *str = Ptr+offset-1;
|
|
register const char *search=s.ptr()+s.length()-1;
|
|
|
|
const char *end=Ptr+s.length()-2;
|
|
const char *search_end=s.ptr()-1;
|
|
skipp:
|
|
while (str != end)
|
|
{
|
|
if (*str-- == *search)
|
|
{
|
|
register char *i,*j;
|
|
i=(char*) str; j=(char*) search-1;
|
|
while (j != search_end)
|
|
if (*i-- != *j--) goto skipp;
|
|
return (int) (i-Ptr) +1;
|
|
}
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
** replace substring with string
|
|
** If wrong parameter or not enough memory, do nothing
|
|
*/
|
|
|
|
|
|
bool String::replace(uint32 offset,uint32 arg_length,const String &to)
|
|
{
|
|
long diff = (long) to.length()-(long) arg_length;
|
|
if (offset+arg_length <= str_length)
|
|
{
|
|
if (diff < 0)
|
|
{
|
|
if (to.length())
|
|
memcpy(Ptr+offset,to.ptr(),to.length());
|
|
bmove(Ptr+offset+to.length(),Ptr+offset+arg_length,
|
|
str_length-offset-arg_length);
|
|
}
|
|
else
|
|
{
|
|
if (diff)
|
|
{
|
|
if (realloc(str_length+(uint32) diff))
|
|
return TRUE;
|
|
bmove_upp(Ptr+str_length+diff,Ptr+str_length,
|
|
str_length-offset-arg_length);
|
|
}
|
|
if (to.length())
|
|
memcpy(Ptr+offset,to.ptr(),to.length());
|
|
}
|
|
str_length+=(uint32) diff;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
int sortcmp(const String *x,const String *y)
|
|
{
|
|
const char *s= x->ptr();
|
|
const char *t= y->ptr();
|
|
uint32 x_len=x->length(),y_len=y->length(),len=min(x_len,y_len);
|
|
|
|
#ifdef USE_STRCOLL
|
|
if (use_strcoll(default_charset_info))
|
|
{
|
|
#ifndef CMP_ENDSPACE
|
|
while (x_len && isspace(s[x_len-1]))
|
|
x_len--;
|
|
while (y_len && isspace(t[y_len-1]))
|
|
y_len--;
|
|
#endif
|
|
return my_strnncoll(default_charset_info,
|
|
(unsigned char *)s,x_len,(unsigned char *)t,y_len);
|
|
}
|
|
else
|
|
{
|
|
#endif /* USE_STRCOLL */
|
|
x_len-=len; // For easy end space test
|
|
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]]);
|
|
}
|
|
#ifndef CMP_ENDSPACE
|
|
/* Don't compare end space in strings */
|
|
{
|
|
if (y_len)
|
|
{
|
|
const char *end=t+y_len;
|
|
for (; t != end ; t++)
|
|
if (!isspace(*t))
|
|
return -1;
|
|
}
|
|
else
|
|
{
|
|
const char *end=s+x_len;
|
|
for (; s != end ; s++)
|
|
if (!isspace(*s))
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
#else
|
|
return (int) (x_len-y_len);
|
|
#endif /* CMP_ENDSPACE */
|
|
#ifdef USE_STRCOLL
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
int stringcmp(const String *x,const String *y)
|
|
{
|
|
const char *s= x->ptr();
|
|
const char *t= y->ptr();
|
|
uint32 x_len=x->length(),y_len=y->length(),len=min(x_len,y_len);
|
|
|
|
while (len--)
|
|
{
|
|
if (*s++ != *t++)
|
|
return ((int) (uchar) s[-1] - (int) (uchar) t[-1]);
|
|
}
|
|
return (int) (x_len-y_len);
|
|
}
|
|
|
|
|
|
String *copy_if_not_alloced(String *to,String *from,uint32 from_length)
|
|
{
|
|
if (from->Alloced_length >= from_length)
|
|
return from;
|
|
if (from->alloced || !to || from == to)
|
|
{
|
|
(void) from->realloc(from_length);
|
|
return from;
|
|
}
|
|
if (to->realloc(from_length))
|
|
return from; // Actually an error
|
|
if ((to->str_length=min(from->str_length,from_length)))
|
|
memcpy(to->Ptr,from->Ptr,to->str_length);
|
|
return to;
|
|
}
|
|
|
|
/* 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)
|
|
#else
|
|
#define INC_PTR(A,B) A++
|
|
#endif
|
|
|
|
/*
|
|
** Compare string against string with wildcard
|
|
** 0 if matched
|
|
** -1 if not matched with wildcard
|
|
** 1 if matched with wildcard
|
|
*/
|
|
|
|
#ifdef LIKE_CMP_TOUPPER
|
|
#define likeconv(A) (uchar) toupper(A)
|
|
#else
|
|
#define likeconv(A) (uchar) my_sort_order[(uchar) (A)]
|
|
#endif
|
|
|
|
int wild_case_compare(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);
|
|
#endif
|
|
while (wildstr != wildend)
|
|
{
|
|
while (*wildstr != wild_many && *wildstr != wild_one)
|
|
{
|
|
if (*wildstr == escape && wildstr+1 != wildend)
|
|
wildstr++;
|
|
#ifdef USE_MB
|
|
int l;
|
|
if (use_mb_flag &&
|
|
(l = my_ismbchar(default_charset_info, wildstr, wildend)))
|
|
{
|
|
if (str+l > str_end || memcmp(str, wildstr, l) != 0)
|
|
return 1;
|
|
str += l;
|
|
wildstr += l;
|
|
}
|
|
else
|
|
#endif
|
|
if (str == str_end || likeconv(*wildstr++) != likeconv(*str++))
|
|
return(1); // No match
|
|
if (wildstr == wildend)
|
|
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) // Skip one char if possible
|
|
return (result);
|
|
INC_PTR(str,str_end);
|
|
} while (++wildstr < wildend && *wildstr == wild_one);
|
|
if (wildstr == wildend)
|
|
break;
|
|
}
|
|
if (*wildstr == wild_many)
|
|
{ // Found wild_many
|
|
wildstr++;
|
|
/* Remove any '%' and '_' from the wild search string */
|
|
for (; wildstr != wildend ; wildstr++)
|
|
{
|
|
if (*wildstr == wild_many)
|
|
continue;
|
|
if (*wildstr == wild_one)
|
|
{
|
|
if (str == str_end)
|
|
return (-1);
|
|
INC_PTR(str,str_end);
|
|
continue;
|
|
}
|
|
break; // Not a wild character
|
|
}
|
|
if (wildstr == wildend)
|
|
return(0); // Ok if wild_many is last
|
|
if (str == str_end)
|
|
return -1;
|
|
|
|
uchar cmp;
|
|
if ((cmp= *wildstr) == escape && wildstr+1 != wildend)
|
|
cmp= *++wildstr;
|
|
#ifdef USE_MB
|
|
const char* mb = wildstr;
|
|
int mblen;
|
|
LINT_INIT(mblen);
|
|
if (use_mb_flag)
|
|
mblen = my_ismbchar(default_charset_info, wildstr, wildend);
|
|
#endif
|
|
INC_PTR(wildstr,wildend); // This is compared trough cmp
|
|
cmp=likeconv(cmp);
|
|
do
|
|
{
|
|
#ifdef USE_MB
|
|
if (use_mb_flag)
|
|
{
|
|
for (;;)
|
|
{
|
|
if (str >= str_end)
|
|
return -1;
|
|
if (mblen)
|
|
{
|
|
if (str+mblen <= str_end && memcmp(str, mb, mblen) == 0)
|
|
{
|
|
str += mblen;
|
|
break;
|
|
}
|
|
}
|
|
else if (!my_ismbchar(default_charset_info, str, str_end) &&
|
|
likeconv(*str) == cmp)
|
|
{
|
|
str++;
|
|
break;
|
|
}
|
|
INC_PTR(str, str_end);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
#endif /* USE_MB */
|
|
while (str != str_end && likeconv(*str) != cmp)
|
|
str++;
|
|
if (str++ == str_end) return (-1);
|
|
#ifdef USE_MB
|
|
}
|
|
#endif
|
|
{
|
|
int tmp=wild_case_compare(str,str_end,wildstr,wildend,escape);
|
|
if (tmp <= 0)
|
|
return (tmp);
|
|
}
|
|
} while (str != str_end && wildstr[0] != wild_many);
|
|
return(-1);
|
|
}
|
|
}
|
|
return (str != str_end ? 1 : 0);
|
|
}
|
|
|
|
|
|
int wild_case_compare(String &match,String &wild, char 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.ptr(),match.ptr()+match.length(),
|
|
wild.ptr(), wild.ptr()+wild.length(),escape));
|
|
}
|
|
|
|
/*
|
|
** The following is used when using LIKE on binary strings
|
|
*/
|
|
|
|
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)
|
|
{
|
|
while (*wildstr != wild_many && *wildstr != wild_one)
|
|
{
|
|
if (*wildstr == escape && wildstr+1 != wildend)
|
|
wildstr++;
|
|
if (str == str_end || *wildstr++ != *str++)
|
|
{
|
|
DBUG_RETURN(1);
|
|
}
|
|
if (wildstr == wildend)
|
|
{
|
|
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) // Skip one char if possible
|
|
DBUG_RETURN(result);
|
|
str++;
|
|
} while (*++wildstr == wild_one && wildstr != wildend);
|
|
if (wildstr == wildend)
|
|
break;
|
|
}
|
|
if (*wildstr == wild_many)
|
|
{ // Found wild_many
|
|
wildstr++;
|
|
/* Remove any '%' and '_' from the wild search string */
|
|
for (; wildstr != wildend ; wildstr++)
|
|
{
|
|
if (*wildstr == wild_many)
|
|
continue;
|
|
if (*wildstr == wild_one)
|
|
{
|
|
if (str == str_end)
|
|
{
|
|
DBUG_RETURN(-1);
|
|
}
|
|
str++;
|
|
continue;
|
|
}
|
|
break; // Not a wild character
|
|
}
|
|
if (wildstr == wildend)
|
|
{
|
|
DBUG_RETURN(0); // Ok if wild_many is last
|
|
}
|
|
if (str == str_end)
|
|
{
|
|
DBUG_RETURN(-1);
|
|
}
|
|
char cmp;
|
|
if ((cmp= *wildstr) == escape && wildstr+1 != wildend)
|
|
cmp= *++wildstr;
|
|
wildstr++; // This is compared trough cmp
|
|
do
|
|
{
|
|
while (str != str_end && *str != cmp)
|
|
str++;
|
|
if (str++ == str_end)
|
|
{
|
|
DBUG_RETURN(-1);
|
|
}
|
|
{
|
|
int tmp=wild_compare(str,str_end,wildstr,wildend,escape);
|
|
if (tmp <= 0)
|
|
{
|
|
DBUG_RETURN(tmp);
|
|
}
|
|
}
|
|
} while (str != str_end && wildstr[0] != wild_many);
|
|
DBUG_RETURN(-1);
|
|
}
|
|
}
|
|
DBUG_RETURN(str != str_end ? 1 : 0);
|
|
}
|
|
|
|
|
|
int wild_compare(String &match,String &wild, char 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));
|
|
}
|