Commit ab11370d authored by monty@mysql.com's avatar monty@mysql.com

Merge bk-internal.mysql.com:/home/bk/mysql-4.1

into mysql.com:/home/my/mysql-4.1
parents 41e45ab1 253bfcf7
...@@ -1052,3 +1052,4 @@ ndb/tools/ndb_drop_index.dsp ...@@ -1052,3 +1052,4 @@ ndb/tools/ndb_drop_index.dsp
ndb/tools/ndb_show_tables.dsp ndb/tools/ndb_show_tables.dsp
ndb/tools/ndb_select_all.dsp ndb/tools/ndb_select_all.dsp
ndb/tools/ndb_select_count.dsp ndb/tools/ndb_select_count.dsp
support-files/ndb-config-2-node.ini
...@@ -2671,7 +2671,8 @@ dict_strip_comments( ...@@ -2671,7 +2671,8 @@ dict_strip_comments(
/* Starting quote: remember the quote character. */ /* Starting quote: remember the quote character. */
quote = *sptr; quote = *sptr;
} else if (*sptr == '#' } else if (*sptr == '#'
|| (0 == memcmp("-- ", sptr, 3))) { || (sptr[0] == '-' && sptr[1] == '-' &&
sptr[2] == ' ')) {
for (;;) { for (;;) {
/* In Unix a newline is 0x0A while in Windows /* In Unix a newline is 0x0A while in Windows
it is 0x0D followed by 0x0A */ it is 0x0D followed by 0x0A */
......
...@@ -254,3 +254,4 @@ a ...@@ -254,3 +254,4 @@ a
SELECT FOUND_ROWS(); SELECT FOUND_ROWS();
FOUND_ROWS() FOUND_ROWS()
1 1
DROP TABLE t1;
...@@ -29,6 +29,12 @@ a ...@@ -29,6 +29,12 @@ a
A A
a,A a,A
a,A a,A
select s from t1 order by concat(s);
s
A
a
a,A
a,A
drop table t1; drop table t1;
CREATE TABLE t1 (c set('ae','oe','ue','ss') collate latin1_german2_ci); CREATE TABLE t1 (c set('ae','oe','ue','ss') collate latin1_german2_ci);
INSERT INTO t1 VALUES (''),(''),(''),(''); INSERT INTO t1 VALUES (''),(''),(''),('');
...@@ -47,4 +53,16 @@ ss ...@@ -47,4 +53,16 @@ ss
ss ss
ae,oe,ue,ss ae,oe,ue,ss
ae,oe,ue,ss ae,oe,ue,ss
SELECT c FROM t1 ORDER BY concat(c);
c
ae
ae
ae,oe,ue,ss
ae,oe,ue,ss
oe
oe
ss
ss
ue
ue
DROP TABLE t1; DROP TABLE t1;
...@@ -175,3 +175,4 @@ CREATE TABLE t1 (a int, b int); ...@@ -175,3 +175,4 @@ CREATE TABLE t1 (a int, b int);
INSERT INTO t1 VALUES (1,2), (1,3), (1,4), (1,5); INSERT INTO t1 VALUES (1,2), (1,3), (1,4), (1,5);
SELECT SQL_CALC_FOUND_ROWS DISTINCT 'a' FROM t1 GROUP BY b LIMIT 2; SELECT SQL_CALC_FOUND_ROWS DISTINCT 'a' FROM t1 GROUP BY b LIMIT 2;
SELECT FOUND_ROWS(); SELECT FOUND_ROWS();
DROP TABLE t1;
...@@ -23,6 +23,7 @@ create table t1 (s set ('a','A') character set latin1 collate latin1_bin); ...@@ -23,6 +23,7 @@ create table t1 (s set ('a','A') character set latin1 collate latin1_bin);
show create table t1; show create table t1;
insert into t1 values ('a'),('a,A'),('A,a'),('A'); insert into t1 values ('a'),('a,A'),('A,a'),('A');
select s from t1 order by s; select s from t1 order by s;
select s from t1 order by concat(s);
drop table t1; drop table t1;
# #
...@@ -34,4 +35,5 @@ INSERT INTO t1 VALUES ('ae'),('oe'),('ue'),('ss'); ...@@ -34,4 +35,5 @@ INSERT INTO t1 VALUES ('ae'),('oe'),('ue'),('ss');
INSERT INTO t1 VALUES (',,,'); INSERT INTO t1 VALUES (',,,');
INSERT INTO t1 VALUES ('ae,oe,ue,ss'); INSERT INTO t1 VALUES ('ae,oe,ue,ss');
SELECT c FROM t1 ORDER BY c; SELECT c FROM t1 ORDER BY c;
SELECT c FROM t1 ORDER BY concat(c);
DROP TABLE t1; DROP TABLE t1;
...@@ -145,6 +145,10 @@ void my_end(int infoflag) ...@@ -145,6 +145,10 @@ void my_end(int infoflag)
{ {
#ifdef HAVE_GETRUSAGE #ifdef HAVE_GETRUSAGE
struct rusage rus; struct rusage rus;
#ifdef HAVE_purify
/* Purify assumes that rus is uninitialized after getrusage call */
bzero((char*) &rus, sizeof(rus));
#endif
if (!getrusage(RUSAGE_SELF, &rus)) if (!getrusage(RUSAGE_SELF, &rus))
fprintf(info_file,"\n\ fprintf(info_file,"\n\
User time %.2f, System time %.2f\n\ User time %.2f, System time %.2f\n\
......
...@@ -277,6 +277,7 @@ class Field ...@@ -277,6 +277,7 @@ class Field
virtual bool get_date(TIME *ltime,uint fuzzydate); virtual bool get_date(TIME *ltime,uint fuzzydate);
virtual bool get_time(TIME *ltime); virtual bool get_time(TIME *ltime);
virtual CHARSET_INFO *charset(void) const { return &my_charset_bin; } virtual CHARSET_INFO *charset(void) const { return &my_charset_bin; }
virtual CHARSET_INFO *sort_charset(void) const { return charset(); }
virtual bool has_charset(void) const { return FALSE; } virtual bool has_charset(void) const { return FALSE; }
virtual void set_charset(CHARSET_INFO *charset) { } virtual void set_charset(CHARSET_INFO *charset) { }
bool set_warning(const unsigned int level, const unsigned int code, bool set_warning(const unsigned int level, const unsigned int code,
...@@ -1152,6 +1153,8 @@ class Field_enum :public Field_str { ...@@ -1152,6 +1153,8 @@ class Field_enum :public Field_str {
bool optimize_range(uint idx, uint part) { return 0; } bool optimize_range(uint idx, uint part) { return 0; }
bool eq_def(Field *field); bool eq_def(Field *field);
bool has_charset(void) const { return TRUE; } bool has_charset(void) const { return TRUE; }
/* enum and set are sorted as integers */
CHARSET_INFO *sort_charset(void) const { return &my_charset_bin; }
field_cast_enum field_cast_type() { return FIELD_CAST_ENUM; } field_cast_enum field_cast_type() { return FIELD_CAST_ENUM; }
}; };
......
...@@ -1127,7 +1127,7 @@ sortlength(SORT_FIELD *sortorder, uint s_length, bool *multi_byte_charset) ...@@ -1127,7 +1127,7 @@ sortlength(SORT_FIELD *sortorder, uint s_length, bool *multi_byte_charset)
else else
{ {
sortorder->length=sortorder->field->pack_length(); sortorder->length=sortorder->field->pack_length();
if (use_strnxfrm((cs=sortorder->field->charset()))) if (use_strnxfrm((cs=sortorder->field->sort_charset())))
{ {
sortorder->need_strxnfrm= 1; sortorder->need_strxnfrm= 1;
*multi_byte_charset= 1; *multi_byte_charset= 1;
......
...@@ -265,7 +265,7 @@ int Arg_comparator::set_compare_func(Item_bool_func2 *item, Item_result type) ...@@ -265,7 +265,7 @@ int Arg_comparator::set_compare_func(Item_bool_func2 *item, Item_result type)
comparators= 0; comparators= 0;
return 1; return 1;
} }
if (!(comparators= (Arg_comparator *) sql_alloc(sizeof(Arg_comparator)*n))) if (!(comparators= new Arg_comparator[n]))
return 1; return 1;
for (uint i=0; i < n; i++) for (uint i=0; i < n; i++)
{ {
...@@ -1528,6 +1528,12 @@ in_row::in_row(uint elements, Item * item) ...@@ -1528,6 +1528,12 @@ in_row::in_row(uint elements, Item * item)
size= sizeof(cmp_item_row); size= sizeof(cmp_item_row);
compare= (qsort2_cmp) cmp_row; compare= (qsort2_cmp) cmp_row;
tmp.store_value(item); tmp.store_value(item);
/*
We need to reset these as otherwise we will call sort() with
uninitialized (even if not used) elements
*/
used_count= elements;
collation= 0;
} }
in_row::~in_row() in_row::~in_row()
......
...@@ -530,6 +530,7 @@ extern "C" pthread_handler_decl(handle_slave,arg); ...@@ -530,6 +530,7 @@ extern "C" pthread_handler_decl(handle_slave,arg);
static ulong find_bit_type(const char *x, TYPELIB *bit_lib); static ulong find_bit_type(const char *x, TYPELIB *bit_lib);
static void clean_up(bool print_message); static void clean_up(bool print_message);
static void clean_up_mutexes(void); static void clean_up_mutexes(void);
static void wait_for_signal_thread_to_end(void);
static int test_if_case_insensitive(const char *dir_name); static int test_if_case_insensitive(const char *dir_name);
static void create_pid_file(); static void create_pid_file();
...@@ -918,6 +919,7 @@ extern "C" void unireg_abort(int exit_code) ...@@ -918,6 +919,7 @@ extern "C" void unireg_abort(int exit_code)
sql_print_error("Aborting\n"); sql_print_error("Aborting\n");
clean_up(exit_code || !opt_bootstrap); /* purecov: inspected */ clean_up(exit_code || !opt_bootstrap); /* purecov: inspected */
DBUG_PRINT("quit",("done with cleanup in unireg_abort")); DBUG_PRINT("quit",("done with cleanup in unireg_abort"));
wait_for_signal_thread_to_end();
clean_up_mutexes(); clean_up_mutexes();
my_end(opt_endinfo ? MY_CHECK_ERROR | MY_GIVE_INFO : 0); my_end(opt_endinfo ? MY_CHECK_ERROR | MY_GIVE_INFO : 0);
exit(exit_code); /* purecov: inspected */ exit(exit_code); /* purecov: inspected */
...@@ -1023,6 +1025,29 @@ void clean_up(bool print_message) ...@@ -1023,6 +1025,29 @@ void clean_up(bool print_message)
} /* clean_up */ } /* clean_up */
/*
This is mainly needed when running with purify, but it's still nice to
know that all child threads have died when mysqld exits
*/
static void wait_for_signal_thread_to_end()
{
#ifndef __NETWARE__
uint i;
/*
Wait up to 10 seconds for signal thread to die. We use this mainly to
avoid getting warnings that my_thread_end has not been called
*/
for (i= 0 ; i < 100 && signal_thread_in_use; i++)
{
if (pthread_kill(signal_thread, MYSQL_KILL_SIGNAL))
break;
my_sleep(100); // Give it time to die
}
#endif
}
static void clean_up_mutexes() static void clean_up_mutexes()
{ {
(void) pthread_mutex_destroy(&LOCK_mysql_create_db); (void) pthread_mutex_destroy(&LOCK_mysql_create_db);
...@@ -2117,6 +2142,7 @@ extern "C" void *signal_hand(void *arg __attribute__((unused))) ...@@ -2117,6 +2142,7 @@ extern "C" void *signal_hand(void *arg __attribute__((unused)))
while ((error=my_sigwait(&set,&sig)) == EINTR) ; while ((error=my_sigwait(&set,&sig)) == EINTR) ;
if (cleanup_done) if (cleanup_done)
{ {
DBUG_PRINT("quit",("signal_handler: calling my_thread_end()"));
my_thread_end(); my_thread_end();
signal_thread_in_use= 0; signal_thread_in_use= 0;
pthread_exit(0); // Safety pthread_exit(0); // Safety
...@@ -3111,21 +3137,7 @@ we force server id to 2, but this MySQL server will not act as a slave."); ...@@ -3111,21 +3137,7 @@ we force server id to 2, but this MySQL server will not act as a slave.");
CloseHandle(hEventShutdown); CloseHandle(hEventShutdown);
} }
#endif #endif
#ifndef __NETWARE__ wait_for_signal_thread_to_end();
{
uint i;
/*
Wait up to 10 seconds for signal thread to die. We use this mainly to
avoid getting warnings that my_thread_end has not been called
*/
for (i= 0 ; i < 100 && signal_thread_in_use; i++)
{
if (pthread_kill(signal_thread, MYSQL_KILL_SIGNAL))
break;
my_sleep(100); // Give it time to die
}
}
#endif
clean_up_mutexes(); clean_up_mutexes();
my_end(opt_endinfo ? MY_CHECK_ERROR | MY_GIVE_INFO : 0); my_end(opt_endinfo ? MY_CHECK_ERROR | MY_GIVE_INFO : 0);
......
...@@ -688,7 +688,8 @@ class delayed_insert :public ilink { ...@@ -688,7 +688,8 @@ class delayed_insert :public ilink {
thd.current_tablenr=0; thd.current_tablenr=0;
thd.version=refresh_version; thd.version=refresh_version;
thd.command=COM_DELAYED_INSERT; thd.command=COM_DELAYED_INSERT;
thd.lex->current_select= 0; /* for my_message_sql */ thd.lex->current_select= 0; // for my_message_sql
thd.lex->sql_command= SQLCOM_INSERT; // For innodb::store_lock()
bzero((char*) &thd.net, sizeof(thd.net)); // Safety bzero((char*) &thd.net, sizeof(thd.net)); // Safety
bzero((char*) &table_list, sizeof(table_list)); // Safety bzero((char*) &table_list, sizeof(table_list)); // Safety
......
...@@ -125,27 +125,46 @@ enum tablespace_op_type ...@@ -125,27 +125,46 @@ enum tablespace_op_type
/* /*
The state of the lex parsing for selects The state of the lex parsing for selects
master and slaves are pointers to select_lex.
master is pointer to upper level node.
slave is pointer to lower level node
select_lex is a SELECT without union
unit is container of either
- One SELECT
- UNION of selects
select_lex and unit are both inherited form select_lex_node
neighbors are two select_lex or units on the same level
All select describing structures linked with following pointers: All select describing structures linked with following pointers:
- list of neighbors (next/prev) (prev of first element point to slave - list of neighbors (next/prev) (prev of first element point to slave
pointer of upper structure) pointer of upper structure)
- one level units for unit (union) structure - For select this is a list of UNION's (or one element list)
- member of one union(unit) for ordinary select_lex - For units this is a list of sub queries for the upper level select
- pointer to master
- outer select_lex for unit (union) - pointer to master (master), which is
- unit structure for ordinary select_lex If this is a unit
- pointer to slave - pointer to outer select_lex
- first list element of select_lex belonged to this unit for unit If this is a select_lex
- first unit in list of units that belong to this select_lex (as - pointer to outer unit structure for select
subselects or derived tables) for ordinary select_lex
- list of all select_lex (for group operation like correcting list of opened - pointer to slave (slave), which is either:
tables) If this is a unit:
- if unit contain several selects (union) then it have special - first SELECT that belong to this unit
select_lex called fake_select_lex. It used for storing global parameters If this is a select_lex
and executing union. subqueries of global ORDER BY clause will be - first unit that belong to this SELECT (subquries or derived tables)
attached to this fake_select_lex, which will allow them correctly
resolve fields of 'upper' union and other more outer selects. - list of all select_lex (link_next/link_prev)
This is to be used for things like derived tables creation, where we
for example for following query: go through this list and create the derived tables.
If unit contain several selects (UNION now, INTERSECT etc later)
then it have special select_lex called fake_select_lex. It used for
storing global parameters (like ORDER BY, LIMIT) and executing union.
Subqueries used in global ORDER BY clause will be attached to this
fake_select_lex, which will allow them correctly resolve fields of
'upper' UNION and outer selects.
For example for following query:
select * select *
from table1 from table1
...@@ -163,6 +182,11 @@ enum tablespace_op_type ...@@ -163,6 +182,11 @@ enum tablespace_op_type
we will have following structure: we will have following structure:
select1: (select * from table1 ...)
select2: (select * from table2 ...)
select3: (select * from table3)
select1.1.1: (select * from table1_1_1)
...
main unit main unit
fake0 fake0
...@@ -185,7 +209,12 @@ enum tablespace_op_type ...@@ -185,7 +209,12 @@ enum tablespace_op_type
relation in main unit will be following: relation in main unit will be following:
(bigger picture for:
main unit
fake0
select1 select2 select3
in the above picture)
main unit main unit
|^^^^|fake_select_lex |^^^^|fake_select_lex
|||||+--------------------------------------------+ |||||+--------------------------------------------+
...@@ -382,7 +411,7 @@ class st_select_lex_unit: public st_select_lex_node { ...@@ -382,7 +411,7 @@ class st_select_lex_unit: public st_select_lex_node {
typedef class st_select_lex_unit SELECT_LEX_UNIT; typedef class st_select_lex_unit SELECT_LEX_UNIT;
/* /*
SELECT_LEX - store information of parsed SELECT_LEX statment SELECT_LEX - store information of parsed SELECT statment
*/ */
class st_select_lex: public st_select_lex_node class st_select_lex: public st_select_lex_node
{ {
......
...@@ -246,7 +246,7 @@ bool log_in_use(const char* log_name) ...@@ -246,7 +246,7 @@ bool log_in_use(const char* log_name)
if ((linfo = tmp->current_linfo)) if ((linfo = tmp->current_linfo))
{ {
pthread_mutex_lock(&linfo->lock); pthread_mutex_lock(&linfo->lock);
result = !memcmp(log_name, linfo->log_file_name, log_name_len); result = !bcmp(log_name, linfo->log_file_name, log_name_len);
pthread_mutex_unlock(&linfo->lock); pthread_mutex_unlock(&linfo->lock);
if (result) if (result)
break; break;
......
...@@ -7622,8 +7622,8 @@ static int remove_dup_with_hash_index(THD *thd, TABLE *table, ...@@ -7622,8 +7622,8 @@ static int remove_dup_with_hash_index(THD *thd, TABLE *table,
{ {
byte *key_buffer, *key_pos, *record=table->record[0]; byte *key_buffer, *key_pos, *record=table->record[0];
int error; int error;
handler *file=table->file; handler *file= table->file;
ulong extra_length=ALIGN_SIZE(key_length)-key_length; ulong extra_length= ALIGN_SIZE(key_length)-key_length;
uint *field_lengths,*field_length; uint *field_lengths,*field_length;
HASH hash; HASH hash;
DBUG_ENTER("remove_dup_with_hash_index"); DBUG_ENTER("remove_dup_with_hash_index");
...@@ -7637,22 +7637,34 @@ static int remove_dup_with_hash_index(THD *thd, TABLE *table, ...@@ -7637,22 +7637,34 @@ static int remove_dup_with_hash_index(THD *thd, TABLE *table,
NullS)) NullS))
DBUG_RETURN(1); DBUG_RETURN(1);
{
Field **ptr;
ulong total_length= 0;
for (ptr= first_field, field_length=field_lengths ; *ptr ; ptr++)
{
uint length= (*ptr)->pack_length();
(*field_length++)= length;
total_length+= length;
}
DBUG_PRINT("info",("field_count: %u key_length: %lu total_length: %lu",
field_count, key_length, total_length));
DBUG_ASSERT(total_length <= key_length);
key_length= total_length;
extra_length= ALIGN_SIZE(key_length)-key_length;
}
if (hash_init(&hash, &my_charset_bin, (uint) file->records, 0, if (hash_init(&hash, &my_charset_bin, (uint) file->records, 0,
key_length,(hash_get_key) 0, 0, 0)) key_length, (hash_get_key) 0, 0, 0))
{ {
my_free((char*) key_buffer,MYF(0)); my_free((char*) key_buffer,MYF(0));
DBUG_RETURN(1); DBUG_RETURN(1);
} }
{
Field **ptr;
for (ptr= first_field, field_length=field_lengths ; *ptr ; ptr++)
(*field_length++)= (*ptr)->pack_length();
}
file->ha_rnd_init(1); file->ha_rnd_init(1);
key_pos=key_buffer; key_pos=key_buffer;
for (;;) for (;;)
{ {
byte *org_key_pos;
if (thd->killed) if (thd->killed)
{ {
my_error(ER_SERVER_SHUTDOWN,MYF(0)); my_error(ER_SERVER_SHUTDOWN,MYF(0));
...@@ -7675,6 +7687,7 @@ static int remove_dup_with_hash_index(THD *thd, TABLE *table, ...@@ -7675,6 +7687,7 @@ static int remove_dup_with_hash_index(THD *thd, TABLE *table,
} }
/* copy fields to key buffer */ /* copy fields to key buffer */
org_key_pos= key_pos;
field_length=field_lengths; field_length=field_lengths;
for (Field **ptr= first_field ; *ptr ; ptr++) for (Field **ptr= first_field ; *ptr ; ptr++)
{ {
...@@ -7682,14 +7695,14 @@ static int remove_dup_with_hash_index(THD *thd, TABLE *table, ...@@ -7682,14 +7695,14 @@ static int remove_dup_with_hash_index(THD *thd, TABLE *table,
key_pos+= *field_length++; key_pos+= *field_length++;
} }
/* Check if it exists before */ /* Check if it exists before */
if (hash_search(&hash,key_pos-key_length,key_length)) if (hash_search(&hash, org_key_pos, key_length))
{ {
/* Duplicated found ; Remove the row */ /* Duplicated found ; Remove the row */
if ((error=file->delete_row(record))) if ((error=file->delete_row(record)))
goto err; goto err;
} }
else else
(void) my_hash_insert(&hash, key_pos-key_length); (void) my_hash_insert(&hash, org_key_pos);
key_pos+=extra_length; key_pos+=extra_length;
} }
my_free((char*) key_buffer,MYF(0)); my_free((char*) key_buffer,MYF(0));
......
...@@ -518,7 +518,6 @@ longlong my_strntoll_8bit(CHARSET_INFO *cs __attribute__((unused)), ...@@ -518,7 +518,6 @@ longlong my_strntoll_8bit(CHARSET_INFO *cs __attribute__((unused)),
register unsigned int cutlim; register unsigned int cutlim;
register ulonglong i; register ulonglong i;
register const char *s, *e; register const char *s, *e;
register unsigned char c;
const char *save; const char *save;
int overflow; int overflow;
...@@ -581,8 +580,9 @@ longlong my_strntoll_8bit(CHARSET_INFO *cs __attribute__((unused)), ...@@ -581,8 +580,9 @@ longlong my_strntoll_8bit(CHARSET_INFO *cs __attribute__((unused)),
overflow = 0; overflow = 0;
i = 0; i = 0;
for (c = *s; s != e; c = *++s) for ( ; s != e; s++)
{ {
register unsigned char c= *s;
if (c>='0' && c<='9') if (c>='0' && c<='9')
c -= '0'; c -= '0';
else if (c>='A' && c<='Z') else if (c>='A' && c<='Z')
...@@ -641,7 +641,6 @@ ulonglong my_strntoull_8bit(CHARSET_INFO *cs, ...@@ -641,7 +641,6 @@ ulonglong my_strntoull_8bit(CHARSET_INFO *cs,
register unsigned int cutlim; register unsigned int cutlim;
register ulonglong i; register ulonglong i;
register const char *s, *e; register const char *s, *e;
register unsigned char c;
const char *save; const char *save;
int overflow; int overflow;
...@@ -704,8 +703,10 @@ ulonglong my_strntoull_8bit(CHARSET_INFO *cs, ...@@ -704,8 +703,10 @@ ulonglong my_strntoull_8bit(CHARSET_INFO *cs,
overflow = 0; overflow = 0;
i = 0; i = 0;
for (c = *s; s != e; c = *++s) for ( ; s != e; s++)
{ {
register unsigned char c= *s;
if (c>='0' && c<='9') if (c>='0' && c<='9')
c -= '0'; c -= '0';
else if (c>='A' && c<='Z') else if (c>='A' && c<='Z')
......
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