Commit 3de11a9a authored by monty@hundin.mysql.fi's avatar monty@hundin.mysql.fi

Merge work:/home/bk/mysql-4.0 into hundin.mysql.fi:/my/bk/mysql-4.0

parents 0ac5d095 3c5f7494
......@@ -52,7 +52,7 @@ diff -r -c --exclude=*.info* glibc-2.2.4/nss/nsswitch.c glibc-2.2.4-new/nss/nssw
while (isspace (line[0]))
++line;
***************
*** 510,522 ****
522
if (name == line)
return result;
......@@ -86,7 +86,7 @@ diff -r -c --exclude=*.info* glibc-2.2.4/nss/nsswitch.c glibc-2.2.4-new/nss/nssw
if (new_service == NULL)
return result;
! *((char *) __mempcpy (new_service->name, name, name_alloc_len)) = '\0';
! *((char *) __mempcpy (new_service->name, name, name_alloc_len-1)) = '\0';
/* Set default actions. */
new_service->actions[2 + NSS_STATUS_TRYAGAIN] = NSS_ACTION_CONTINUE;
......
......@@ -26723,6 +26723,12 @@ In the first statement, the @code{LIKE} value begins with a wildcard
character. In the second statement, the @code{LIKE} value is not a
constant.
MySQL 4.0 does another optimization on @code{LIKE}. If you are using
@code{... LIKE "%string%"} and @code{string} is longer than 3 characters
then MySQL will use the turbo-boyer-more algorithm to once initialize
the pattern for the string and then use this pattern to quickly search
after the given string.
@findex IS NULL, and indexes
@cindex indexes, and @code{IS NULL}
Searching using @code{column_name IS NULL} will use indexes if column_name
......@@ -49305,6 +49311,8 @@ Our TODO section contains what we plan to have in 4.0. @xref{TODO MySQL 4.0}.
@itemize @bullet
@item
Use turbo-boyer-more to speed up @code{LIKE "%keyword%"} searches.
@item
Fixed bug in @code{DROP DATABASE} with symlink.
@item
Fixed crash in @code{REPAIR ... USE_FRM}.
......@@ -49789,6 +49797,8 @@ not yet 100% confident in this code.
@appendixsubsec Changes in release 3.23.51
@itemize @bullet
@item
Fixed bug in @code{CONCAT_WS()} that cut the result.
@item
Changed name of variables @code{Com_show_master_stat} to
@code{Com_show_master_status} and @code{Com_show_slave_stat} to
@code{Com_show_slave_status}.
......@@ -24,7 +24,7 @@ EXTRA_DIST = INSTALL-SOURCE README \
SUBDIRS = include @docs_dirs@ @readline_dir@ \
@thread_dirs@ pstack @sql_client_dirs@ \
@sql_server_dirs@ @libmysqld_dirs@ scripts man \
tests BUILD \
tests BUILD os2 \
@bench_dirs@ support-files @fs_dirs@ @tools_dirs@
# Relink after clean
......
......@@ -2364,7 +2364,7 @@ AC_OUTPUT(Makefile extra/Makefile mysys/Makefile isam/Makefile \
myisam/Makefile myisammrg/Makefile \
man/Makefile BUILD/Makefile readline/Makefile vio/Makefile \
libmysql_r/Makefile libmysqld/Makefile libmysqld/examples/Makefile \
libmysql/Makefile client/Makefile \
libmysql/Makefile client/Makefile os2/Makefile \
pstack/Makefile pstack/aout/Makefile sql/Makefile sql/share/Makefile \
merge/Makefile dbug/Makefile scripts/Makefile \
include/Makefile sql-bench/Makefile tools/Makefile \
......
number alpha new
1413006 idlfmv 1413006<---->idlfmv
1413065 smpsfz 1413065<---->smpsfz
1413127 sljrhx 1413127<---->sljrhx
1413304 qerfnd 1413304<---->qerfnd
new
1413006<---->idlfmv
number alpha new
1413006 idlfmv 1413006<->idlfmv
number alpha new
1413006 idlfmv 1413006-idlfmv-idlfmv-idlfmv-idlfmv-idlfmv-idlfmv-idlfmv
number alpha new
1413006 idlfmv 1413006<------------------>idlfmv
......@@ -15,4 +15,15 @@ test
select * from t1 where a like "te_t";
a
test
select * from t1 where a like "%a%";
a
a
abc
abcd
select * from t1 where a like "%abcd%";
a
abcd
select * from t1 where a like "%abc\d%";
a
abcd
drop table t1;
#
# Test of problem with CONCAT_WS() and long separators.
#
DROP TABLE IF EXISTS t1;
CREATE TABLE t1 ( number INT NOT NULL, alpha CHAR(6) NOT NULL );
INSERT INTO t1 VALUES (1413006,'idlfmv'),
(1413065,'smpsfz'),(1413127,'sljrhx'),(1413304,'qerfnd');
SELECT number, alpha, CONCAT_WS('<---->',number,alpha) AS new
FROM t1 GROUP BY number;
SELECT CONCAT_WS('<---->',number,alpha) AS new
FROM t1 GROUP BY new LIMIT 1;
SELECT number, alpha, CONCAT_WS('<->',number,alpha) AS new
FROM t1 GROUP BY new LIMIT 1;
SELECT number, alpha, CONCAT_WS('-',number,alpha,alpha,alpha,alpha,alpha,alpha,alpha) AS new
FROM t1 GROUP BY new LIMIT 1;
SELECT number, alpha, CONCAT_WS('<------------------>',number,alpha) AS new
FROM t1 GROUP BY new LIMIT 1;
drop table t1;
......@@ -9,4 +9,12 @@ select * from t1 where a like "abc%";
select * from t1 where a like "ABC%";
select * from t1 where a like "test%";
select * from t1 where a like "te_t";
#
# The following will test the boyer-more code
#
select * from t1 where a like "%a%";
select * from t1 where a like "%abcd%";
select * from t1 where a like "%abc\d%";
drop table t1;
......@@ -432,6 +432,7 @@ int my_pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
}
#endif
#ifdef HPUX
int my_pthread_mutex_trylock(pthread_mutex_t *mutex)
{
......
# Copyright (C) 2002 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
## Process this file with automake to create Makefile.in
EXTRA_DIST = BldLevel.cmd BldLevel.rc BldLevelInf.cmd ChangeLog.os2 \
MySQL-All.icc MySQL-Client.icc MySQL-Client.irs \
MySQL-Lib.icc MySQL-Opt.icc MySQL-ReadLine.icc \
MySQL-Source.icc MySQL-Sql.icc MySQL-Util.icc MySQL-Util.irs \
MySQL-binlog.icc MySQL-binlog.irs MySQL-sql.irs ReadMe.txt \
build-all.cmd build-all.log mysql-inf.wis mysql.base \
mysql.ih mysql.wis mysqlalt.wis readme.os2 rint.cmd rint.obj \
rint.s
# Don't update the files from bitkeeper
%::SCCS/s.%
......@@ -1228,23 +1228,23 @@ void Item_func_like::fix_length_and_dec()
// cmp_type=STRING_RESULT; // For quick select
}
longlong Item_func_like::val_int()
{
String *res,*res2;
res=args[0]->val_str(&tmp_value1);
String* res = args[0]->val_str(&tmp_value1);
if (args[0]->null_value)
{
null_value=1;
return 0;
}
res2=args[1]->val_str(&tmp_value2);
String* res2 = args[1]->val_str(&tmp_value2);
if (args[1]->null_value)
{
null_value=1;
return 0;
}
null_value=0;
if (canDoTurboBM)
return turboBM_matches(res->ptr(), res->length()) ? 1 : 0;
if (binary)
return wild_compare(*res,*res2,escape) ? 0 : 1;
else
......@@ -1268,6 +1268,51 @@ Item_func::optimize_type Item_func_like::select_optimize() const
return OPTIMIZE_NONE;
}
bool Item_func_like::fix_fields(THD *thd,struct st_table_list *tlist)
{
if (Item_bool_func2::fix_fields(thd, tlist))
return 1;
/*
TODO--we could do it for non-const, but we'd have to
recompute the tables for each row--probably not worth it.
*/
if (args[1]->const_item() && !(specialflag & SPECIAL_NO_NEW_FUNC))
{
String* res2 = args[1]->val_str(&tmp_value2);
const size_t len = res2->length();
const char* first = res2->ptr();
const char* last = first + len - 1;
/*
len must be > 2 ('%pattern%')
heuristic: only do TurboBM for pattern_len > 2
*/
if (len > MIN_TURBOBM_PATTERN_LEN + 2 &&
*first == wild_many &&
*last == wild_many)
{
const char* tmp = first + 1;
for ( ; *tmp != wild_many && *tmp != wild_one && *tmp != escape; tmp++) ;
canDoTurboBM = tmp == last;
}
if (canDoTurboBM)
{
pattern = first + 1;
pattern_len = len - 2;
DBUG_PRINT("TurboBM", ("Initializing pattern: '%s'...", first));
int* suff = (int*)thd->alloc(sizeof(int[pattern_len + 1]));
bmGs = (int*)thd->alloc(sizeof(int[pattern_len + 1]));
bmBc = (int*)thd->alloc(sizeof(int[alphabet_size]));
turboBM_compute_good_suffix_shifts(suff);
turboBM_compute_bad_character_shifts();
DBUG_PRINT("turboBM",("done"));
}
}
return 0;
}
#ifdef USE_REGEX
bool
......@@ -1307,7 +1352,6 @@ Item_func_regex::fix_fields(THD *thd,TABLE_LIST *tables)
return 0;
}
longlong Item_func_regex::val_int()
{
char buff[MAX_FIELD_WIDTH];
......@@ -1364,3 +1408,215 @@ Item_func_regex::~Item_func_regex()
}
#endif /* USE_REGEX */
#ifdef LIKE_CMP_TOUPPER
#define likeconv(A) (uchar) toupper(A)
#else
#define likeconv(A) (uchar) my_sort_order[(uchar) (A)]
#endif
/**********************************************************************
turboBM_compute_suffixes()
Precomputation dependent only on pattern_len.
**********************************************************************/
void Item_func_like::turboBM_compute_suffixes(int* suff)
{
const int plm1 = pattern_len - 1;
int f = 0;
int g = plm1;
int* const splm1 = suff + plm1;
*splm1 = pattern_len;
if (binary)
{
int i;
for (i = pattern_len - 2; i >= 0; i--)
{
int tmp = *(splm1 + i - f);
if (g < i && tmp < i - g)
suff[i] = tmp;
else
{
if (i < g)
g = i; // g = min(i, g)
f = i;
while (g >= 0 && pattern[g] == pattern[g + plm1 - f])
g--;
suff[i] = f - g;
}
}
}
else
{
int i;
for (i = pattern_len - 2; 0 <= i; --i)
{
int tmp = *(splm1 + i - f);
if (g < i && tmp < i - g)
suff[i] = tmp;
else
{
if (i < g)
g = i; // g = min(i, g)
f = i;
while (g >= 0 && likeconv(pattern[g]) == likeconv(pattern[g + plm1 - f]))
g--;
suff[i] = f - g;
}
}
}
}
/**********************************************************************
turboBM_compute_good_suffix_shifts()
Precomputation dependent only on pattern_len.
**********************************************************************/
void Item_func_like::turboBM_compute_good_suffix_shifts(int* suff)
{
turboBM_compute_suffixes(suff);
int* end = bmGs + pattern_len;
int* k;
for (k = bmGs; k < end; k++)
*k = pattern_len;
int tmp;
int i;
int j = 0;
const int plm1 = pattern_len - 1;
for (i = plm1; i > -1; i--)
{
if (suff[i] == i + 1)
{
for (tmp = plm1 - i; j < tmp; j++)
{
int* tmp2 = bmGs + j;
if (*tmp2 == pattern_len)
*tmp2 = tmp;
}
}
}
int* tmp2;
for (tmp = plm1 - i; j < tmp; j++)
{
tmp2 = bmGs + j;
if (*tmp2 == pattern_len)
*tmp2 = tmp;
}
tmp2 = bmGs + plm1;
for (i = 0; i <= pattern_len - 2; i++)
*(tmp2 - suff[i]) = plm1 - i;
}
/**********************************************************************
turboBM_compute_bad_character_shifts()
Precomputation dependent on pattern_len.
**********************************************************************/
void Item_func_like::turboBM_compute_bad_character_shifts()
{
int* i;
int* end = bmBc + alphabet_size;
for (i = bmBc; i < end; i++)
*i = pattern_len;
int j;
const int plm1 = pattern_len - 1;
if (binary)
for (j = 0; j < plm1; j++)
bmBc[pattern[j]] = plm1 - j;
else
for (j = 0; j < plm1; j++)
bmBc[likeconv(pattern[j])] = plm1 - j;
}
/**********************************************************************
turboBM_matches()
Search for pattern in text, returns true/false for match/no match
**********************************************************************/
bool Item_func_like::turboBM_matches(const char* text, int text_len) const
{
register int bcShift;
register int turboShift;
int shift = pattern_len;
int j = 0;
int u = 0;
const int plm1 = pattern_len - 1;
const int tlmpl = text_len - pattern_len;
/* Searching */
if (binary)
{
while (j <= tlmpl)
{
register int i = plm1;
while (i >= 0 && pattern[i] == text[i + j])
{
i--;
if (i == plm1 - shift)
i -= u;
}
if (i < 0)
return true;
register const int v = plm1 - i;
turboShift = u - v;
bcShift = bmBc[text[i + j]] - plm1 + i;
shift = max(turboShift, bcShift);
shift = max(shift, bmGs[i]);
if (shift == bmGs[i])
u = min(pattern_len - shift, v);
else
{
if (turboShift < bcShift)
shift = max(shift, u + 1);
u = 0;
}
j += shift;
}
return false;
}
else
{
while (j <= tlmpl)
{
register int i = plm1;
while (i >= 0 && likeconv(pattern[i]) == likeconv(text[i + j]))
{
i--;
if (i == plm1 - shift)
i -= u;
}
if (i < 0)
return true;
register const int v = plm1 - i;
turboShift = u - v;
bcShift = bmBc[likeconv(text[i + j])] - plm1 + i;
shift = max(turboShift, bcShift);
shift = max(shift, bmGs[i]);
if (shift == bmGs[i])
u = min(pattern_len - shift, v);
else
{
if (turboShift < bcShift)
shift = max(shift, u + 1);
u = 0;
}
j += shift;
}
return false;
}
}
......@@ -478,15 +478,40 @@ class Item_func_isnotnull :public Item_bool_func
class Item_func_like :public Item_bool_func2
{
char escape;
public:
Item_func_like(Item *a,Item *b, char* escape_arg) :Item_bool_func2(a,b),escape(*escape_arg)
// Turbo Boyer-Moore data
bool canDoTurboBM; // pattern is '%abcd%' case
const char* pattern;
int pattern_len;
// TurboBM buffers, *this is owner
int* bmGs; // good suffix shift table, size is pattern_len + 1
int* bmBc; // bad character shift table, size is alphabet_size
void turboBM_compute_suffixes(int* suff);
void turboBM_compute_good_suffix_shifts(int* suff);
void turboBM_compute_bad_character_shifts();
bool turboBM_matches(const char* text, int text_len) const;
enum { alphabet_size = 256 };
public:
Item_func_like::Item_func_like(Item *a,Item *b, char* escape_arg) :
Item_bool_func2(a,b),
escape(*escape_arg),
canDoTurboBM(false),
pattern(0),
pattern_len(0),
bmGs(0),
bmBc(0)
{}
longlong val_int();
enum Functype functype() const { return LIKE_FUNC; }
optimize_type select_optimize() const;
cond_result eq_cmp_result() const { return COND_TRUE; }
const char *func_name() const { return "like"; }
void fix_length_and_dec();
bool fix_fields(THD *thd,struct st_table_list *tlist);
};
#ifdef USE_REGEX
......
......@@ -475,7 +475,7 @@ String *Item_func_concat_ws::val_str(String *str)
void Item_func_concat_ws::fix_length_and_dec()
{
max_length=0;
max_length=separator->max_length*(arg_count-1);
for (uint i=0 ; i < arg_count ; i++)
max_length+=args[i]->max_length;
if (max_length > MAX_BLOB_WIDTH)
......
This diff is collapsed.
......@@ -209,16 +209,16 @@
"E' scaduto il timeout per l'attesa del lock",
"Il numero totale di lock e' maggiore della grandezza della tabella di lock",
"I lock di aggiornamento non possono essere acquisiti durante una transazione 'READ UNCOMMITTED'",
"DROP DATABASE not allowed while thread is holding global read lock",
"CREATE DATABASE not allowed while thread is holding global read lock",
"Wrong arguments to %s",
"%-.32s@%-.64s is not allowed to create new users",
"Incorrect table definition; All MERGE tables must be in the same database",
"Deadlock found when trying to get lock; Try restarting transaction",
"The used table type doesn't support FULLTEXT indexes",
"Cannot add foreign key constraint",
"Cannot add a child row: a foreign key constraint fails",
"Cannot delete a parent row: a foreign key constraint fails",
"DROP DATABASE non e' permesso mentre il thread ha un lock globale di lettura",
"CREATE DATABASE non e' permesso mentre il thread ha un lock globale di lettura",
"Argomenti errati a %s",
"A %-.32s@%-.64s non e' permesso creare nuovi utenti",
"Definizione della tabella errata; tutte le tabelle di tipo MERGE devono essere nello stesso database",
"Trovato deadlock durante il lock; Provare a far ripartire la transazione",
"La tabella usata non supporta gli indici FULLTEXT",
"Impossibile aggiungere il vincolo di integrita' referenziale (foreign key constraint)",
"Impossibile aggiungere la riga: un vincolo d'integrita' referenziale non e' soddisfatto",
"Impossibile cancellare la riga: un vincolo d'integrita' referenziale non e' soddisfatto",
"Error connecting to master: %-.128s",
"Error running query on master: %-.128s",
"Error when executing command %s: %-.128s",
......
......@@ -122,6 +122,13 @@ bfill((A)->null_flags,(A)->null_bytes,255);\
#define TE_INFO_LENGTH 3
#define MTYP_NOEMPTY_BIT 128
/*
* Minimum length pattern before Turbo Boyer-Moore is used
* for SELECT "text" LIKE "%pattern%", excluding the two
* wildcards in class Item_func_like.
*/
#define MIN_TURBOBM_PATTERN_LEN 3
/* Include prototypes for unireg */
#include "mysqld_error.h"
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment