Commit 46536219 authored by unknown's avatar unknown

New multi-table-update code

New (simpler) internal timestamp handling.
More debuging to heap tables.
Small cleanups to multi-table-delete
false -> 0 and true -> 1  (We should use TRUE and FALSE)


heap/_check.c:
  Added checking of rows
heap/hp_delete.c:
  Extra debugging
heap/hp_scan.c:
  Extra debugging
heap/hp_update.c:
  Extra debugging
heap/hp_write.c:
  Extra debugging
include/my_base.h:
  Added option to disable row cache when using updates
isam/extra.c:
  Added option to disable row cache when using updates
myisam/mi_check.c:
  Comment cleanup
myisam/mi_extra.c:
  Added option to disable row cache when using updates
myisam/sort.c:
  Indentaion cleanups
myisammrg/myrg_extra.c:
  Added option to disable row cache when using updates
mysql-test/r/multi_update.result:
  Updated results
mysql-test/t/multi_update.test:
  Cleanup up to only use table names t1, t2,...
mysys/mf_iocache.c:
  Safety fix
sql/item_cmpfunc.cc:
  change true-> 1 and false -> 0
sql/mysql_priv.h:
  Cleaned up SQL_LIST handling
sql/sql_base.cc:
  Fixed grant checking if SELECT tablename.*
sql/sql_class.h:
  Cleaned up multi-table-update
sql/sql_delete.cc:
  Fixed OPTION_SAFE_UPDATE checking in multi-table-delete.
  Fixed query-cache invalidation in multi-table-delete
sql/sql_insert.cc:
  cleaned up timestamp handling
sql/sql_olap.cc:
  false -> 0
sql/sql_parse.cc:
  Optimized some list handling.
  Moved multi-table-update to sql_update.cc
sql/sql_select.cc:
  More comments
  Fixed create_tmp_table for multi-table-update
sql/sql_select.h:
  New prototypes
sql/sql_union.cc:
  false -> 0
  Cleaned up timestamp handling
sql/sql_update.cc:
  New multi-update-table code
sql/sql_yacc.yy:
  false -> 0, true -> 1
  Optimized some list handling
sql/table.h:
  Added union for temporary values.
  Made shared int to be able to store counters.
sql/uniques.cc:
  Indentation cleanup
parent 7d2d7e3f
...@@ -21,19 +21,70 @@ ...@@ -21,19 +21,70 @@
static int check_one_key(HP_KEYDEF *keydef, uint keynr, ulong records, static int check_one_key(HP_KEYDEF *keydef, uint keynr, ulong records,
ulong blength, my_bool print_status); ulong blength, my_bool print_status);
/* Returns 0 if the HEAP is ok */ /*
Check if keys and rows are ok in a heap table
SYNOPSIS
heap_check_heap()
info Table handler
print_status Prints some extra status
NOTES
Doesn't change the state of the table handler
RETURN VALUES
0 ok
1 error
*/
int heap_check_heap(HP_INFO *info,my_bool print_status) int heap_check_heap(HP_INFO *info,my_bool print_status)
{ {
int error; int error;
uint key; uint key;
ulong records=0, deleted=0, pos, next_block;
HP_SHARE *share=info->s; HP_SHARE *share=info->s;
DBUG_ENTER("heap_check_keys"); HP_INFO save_info= *info; /* Needed because scan_init */
DBUG_ENTER("heap_check_heap");
for (error=key=0 ; key < share->keys ; key++) for (error=key= 0 ; key < share->keys ; key++)
error|=check_one_key(share->keydef+key,key, share->records,share->blength, error|=check_one_key(share->keydef+key,key, share->records,share->blength,
print_status); print_status);
/*
This is basicly the same code as in hp_scan, but we repeat it here to
get shorter DBUG log file.
*/
for (pos=next_block= 0 ; ; pos++)
{
if (pos < next_block)
{
info->current_ptr+= share->block.recbuffer;
}
else
{
next_block+= share->block.records_in_block;
if (next_block >= share->records+share->deleted)
{
next_block= share->records+share->deleted;
if (pos >= next_block)
break; /* End of file */
}
}
_hp_find_record(info,pos);
if (!info->current_ptr[share->reclength])
deleted++;
else
records++;
}
if (records != share->records || deleted != share->deleted)
{
DBUG_PRINT("error",("Found rows: %lu (%lu) deleted %lu (%lu)",
records, share->records, deleted, share->deleted));
error= 1;
}
*info= save_info;
DBUG_RETURN(error); DBUG_RETURN(error);
} }
......
...@@ -48,6 +48,10 @@ int heap_delete(HP_INFO *info, const byte *record) ...@@ -48,6 +48,10 @@ int heap_delete(HP_INFO *info, const byte *record)
pos[share->reclength]=0; /* Record deleted */ pos[share->reclength]=0; /* Record deleted */
share->deleted++; share->deleted++;
info->current_hash_ptr=0; info->current_hash_ptr=0;
#if !defined(DBUG_OFF) && defined(EXTRA_HEAP_DEBUG)
DBUG_EXECUTE("check_heap",heap_check_heap(info, 0););
#endif
DBUG_RETURN(0); DBUG_RETURN(0);
err: err:
if (++(share->records) == share->blength) if (++(share->records) == share->blength)
......
...@@ -62,6 +62,7 @@ int heap_scan(register HP_INFO *info, byte *record) ...@@ -62,6 +62,7 @@ int heap_scan(register HP_INFO *info, byte *record)
} }
if (!info->current_ptr[share->reclength]) if (!info->current_ptr[share->reclength])
{ {
DBUG_PRINT("warning",("Found deleted record"));
info->update= HA_STATE_PREV_FOUND | HA_STATE_NEXT_FOUND; info->update= HA_STATE_PREV_FOUND | HA_STATE_NEXT_FOUND;
DBUG_RETURN(my_errno=HA_ERR_RECORD_DELETED); DBUG_RETURN(my_errno=HA_ERR_RECORD_DELETED);
} }
......
...@@ -46,6 +46,10 @@ int heap_update(HP_INFO *info, const byte *old, const byte *heap_new) ...@@ -46,6 +46,10 @@ int heap_update(HP_INFO *info, const byte *old, const byte *heap_new)
memcpy(pos,heap_new,(size_t) share->reclength); memcpy(pos,heap_new,(size_t) share->reclength);
if (++(share->records) == share->blength) share->blength+= share->blength; if (++(share->records) == share->blength) share->blength+= share->blength;
#if !defined(DBUG_OFF) && defined(EXTRA_HEAP_DEBUG)
DBUG_EXECUTE("check_heap",heap_check_heap(info, 0););
#endif
DBUG_RETURN(0); DBUG_RETURN(0);
err: err:
......
...@@ -60,7 +60,11 @@ int heap_write(HP_INFO *info, const byte *record) ...@@ -60,7 +60,11 @@ int heap_write(HP_INFO *info, const byte *record)
info->current_ptr=pos; info->current_ptr=pos;
info->current_hash_ptr=0; info->current_hash_ptr=0;
info->update|=HA_STATE_AKTIV; info->update|=HA_STATE_AKTIV;
#if !defined(DBUG_OFF) && defined(EXTRA_HEAP_DEBUG)
DBUG_EXECUTE("check_heap",heap_check_heap(info, 0););
#endif
DBUG_RETURN(0); DBUG_RETURN(0);
err: err:
DBUG_PRINT("info",("Duplicate key: %d",key)); DBUG_PRINT("info",("Duplicate key: %d",key));
info->errkey= key; info->errkey= key;
...@@ -74,6 +78,7 @@ err: ...@@ -74,6 +78,7 @@ err:
*((byte**) pos)=share->del_link; *((byte**) pos)=share->del_link;
share->del_link=pos; share->del_link=pos;
pos[share->reclength]=0; /* Record deleted */ pos[share->reclength]=0; /* Record deleted */
DBUG_RETURN(my_errno); DBUG_RETURN(my_errno);
} /* heap_write */ } /* heap_write */
......
...@@ -109,7 +109,8 @@ enum ha_extra_function { ...@@ -109,7 +109,8 @@ enum ha_extra_function {
HA_EXTRA_BULK_INSERT_BEGIN, HA_EXTRA_BULK_INSERT_BEGIN,
HA_EXTRA_BULK_INSERT_FLUSH, /* Flush one index */ HA_EXTRA_BULK_INSERT_FLUSH, /* Flush one index */
HA_EXTRA_BULK_INSERT_END, HA_EXTRA_BULK_INSERT_END,
HA_EXTRA_PREPARE_FOR_DELETE HA_EXTRA_PREPARE_FOR_DELETE,
HA_EXTRA_PREPARE_FOR_UPDATE /* Remove read cache if problems */
}; };
/* The following is parameter to ha_panic() */ /* The following is parameter to ha_panic() */
......
...@@ -123,6 +123,7 @@ int nisam_extra(N_INFO *info, enum ha_extra_function function) ...@@ -123,6 +123,7 @@ int nisam_extra(N_INFO *info, enum ha_extra_function function)
} }
#endif #endif
if (!(info->opt_flag & (READ_CACHE_USED | WRITE_CACHE_USED))) if (!(info->opt_flag & (READ_CACHE_USED | WRITE_CACHE_USED)))
{
if (!(init_io_cache(&info->rec_cache,info->dfile,0, if (!(init_io_cache(&info->rec_cache,info->dfile,0,
WRITE_CACHE,info->s->state.data_file_length, WRITE_CACHE,info->s->state.data_file_length,
(pbool) (info->lock_type != F_UNLCK), (pbool) (info->lock_type != F_UNLCK),
...@@ -131,7 +132,12 @@ int nisam_extra(N_INFO *info, enum ha_extra_function function) ...@@ -131,7 +132,12 @@ int nisam_extra(N_INFO *info, enum ha_extra_function function)
info->opt_flag|=WRITE_CACHE_USED; info->opt_flag|=WRITE_CACHE_USED;
info->update&= ~HA_STATE_ROW_CHANGED; info->update&= ~HA_STATE_ROW_CHANGED;
} }
}
break; break;
case HA_EXTRA_PREPARE_FOR_UPDATE:
if (info->s->data_file_type != DYNAMIC_RECORD)
break;
/* Remove read/write cache if dynamic rows */
case HA_EXTRA_NO_CACHE: case HA_EXTRA_NO_CACHE:
if (info->opt_flag & (READ_CACHE_USED | WRITE_CACHE_USED)) if (info->opt_flag & (READ_CACHE_USED | WRITE_CACHE_USED))
{ {
......
...@@ -2329,13 +2329,13 @@ int mi_repair_parallel(MI_CHECK *param, register MI_INFO *info, ...@@ -2329,13 +2329,13 @@ int mi_repair_parallel(MI_CHECK *param, register MI_INFO *info,
for (i=0 ; i < sort_info.total_keys ; i++) for (i=0 ; i < sort_info.total_keys ; i++)
{ {
sort_param[i].read_cache=param->read_cache; sort_param[i].read_cache=param->read_cache;
/*
two approaches: the same amount of memory for each thread
or the memory for the same number of keys for each thread...
In the second one all the threads will fill their sort_buffers
(and call write_keys) at the same time, putting more stress on i/o.
*/
sort_param[i].sortbuff_size= sort_param[i].sortbuff_size=
/*
two approaches: the same amount of memory for each thread
or the memory for the same number of keys for each thread...
In the second one all the threads will fill their sort_buffers
(and call write_keys) at the same time, putting more stress on i/o.
*/
#ifndef USING_SECOND_APPROACH #ifndef USING_SECOND_APPROACH
param->sort_buffer_length/sort_info.total_keys; param->sort_buffer_length/sort_info.total_keys;
#else #else
......
...@@ -165,6 +165,10 @@ int mi_extra(MI_INFO *info, enum ha_extra_function function, void *extra_arg) ...@@ -165,6 +165,10 @@ int mi_extra(MI_INFO *info, enum ha_extra_function function, void *extra_arg)
HA_STATE_EXTEND_BLOCK); HA_STATE_EXTEND_BLOCK);
} }
break; break;
case HA_EXTRA_PREPARE_FOR_UPDATE:
if (info->s->data_file_type != DYNAMIC_RECORD)
break;
/* Remove read/write cache if dynamic rows */
case HA_EXTRA_NO_CACHE: case HA_EXTRA_NO_CACHE:
if (info->opt_flag & (READ_CACHE_USED | WRITE_CACHE_USED)) if (info->opt_flag & (READ_CACHE_USED | WRITE_CACHE_USED))
{ {
......
...@@ -344,7 +344,6 @@ pthread_handler_decl(thr_find_all_keys,arg) ...@@ -344,7 +344,6 @@ pthread_handler_decl(thr_find_all_keys,arg)
mi_check_print_error(info->sort_info->param,"Sort buffer to small"); /* purecov: tested */ mi_check_print_error(info->sort_info->param,"Sort buffer to small"); /* purecov: tested */
goto err; /* purecov: tested */ goto err; /* purecov: tested */
} }
// (*info->lock_in_memory)(info->sort_info->param);/* Everything is allocated */
if (info->sort_info->param->testflag & T_VERBOSE) if (info->sort_info->param->testflag & T_VERBOSE)
printf("Key %d - Allocating buffer for %d keys\n",info->key+1,keys); printf("Key %d - Allocating buffer for %d keys\n",info->key+1,keys);
...@@ -424,9 +423,9 @@ int thr_write_keys(MI_SORT_PARAM *sort_param) ...@@ -424,9 +423,9 @@ int thr_write_keys(MI_SORT_PARAM *sort_param)
byte *mergebuf=0; byte *mergebuf=0;
LINT_INIT(length); LINT_INIT(length);
for (i=0, sinfo=sort_param ; i<sort_info->total_keys ; i++, for (i= 0, sinfo= sort_param ;
rec_per_key_part+=sinfo->keyinfo->keysegs, i < sort_info->total_keys ;
sinfo++) i++, rec_per_key_part+=sinfo->keyinfo->keysegs, sinfo++)
{ {
if (!sinfo->sort_keys) if (!sinfo->sort_keys)
{ {
...@@ -452,15 +451,18 @@ int thr_write_keys(MI_SORT_PARAM *sort_param) ...@@ -452,15 +451,18 @@ int thr_write_keys(MI_SORT_PARAM *sort_param)
} }
} }
my_free((gptr) sinfo->sort_keys,MYF(0)); my_free((gptr) sinfo->sort_keys,MYF(0));
my_free(mi_get_rec_buff_ptr(info, sinfo->rec_buff), MYF(MY_ALLOW_ZERO_PTR)); my_free(mi_get_rec_buff_ptr(info, sinfo->rec_buff),
MYF(MY_ALLOW_ZERO_PTR));
sinfo->sort_keys=0; sinfo->sort_keys=0;
} }
for (i=0, sinfo=sort_param ; i<sort_info->total_keys ; i++, for (i= 0, sinfo= sort_param ;
delete_dynamic(&sinfo->buffpek), i < sort_info->total_keys ;
close_cached_file(&sinfo->tempfile), i++,
close_cached_file(&sinfo->tempfile_for_exceptions), delete_dynamic(&sinfo->buffpek),
sinfo++) close_cached_file(&sinfo->tempfile),
close_cached_file(&sinfo->tempfile_for_exceptions),
sinfo++)
{ {
if (got_error) if (got_error)
continue; continue;
......
...@@ -38,7 +38,8 @@ int myrg_extra(MYRG_INFO *info,enum ha_extra_function function, ...@@ -38,7 +38,8 @@ int myrg_extra(MYRG_INFO *info,enum ha_extra_function function,
} }
else else
{ {
if (function == HA_EXTRA_NO_CACHE || function == HA_EXTRA_RESET) if (function == HA_EXTRA_NO_CACHE || function == HA_EXTRA_RESET ||
function == HA_EXTRA_PREPARE_FOR_UPDATE)
info->cache_in_use=0; info->cache_in_use=0;
if (function == HA_EXTRA_RESET || function == HA_EXTRA_RESET_STATE) if (function == HA_EXTRA_RESET || function == HA_EXTRA_RESET_STATE)
{ {
......
...@@ -20,7 +20,7 @@ count(*) ...@@ -20,7 +20,7 @@ count(*)
10 10
select count(*) from t2 where t = "bbb"; select count(*) from t2 where t = "bbb";
count(*) count(*)
10 50
select count(*) from t2 where id2 > 90; select count(*) from t2 where id2 > 90;
count(*) count(*)
50 50
...@@ -70,71 +70,61 @@ create table t1(id1 int not null primary key, t varchar(100)) pack_keys = 1; ...@@ -70,71 +70,61 @@ create table t1(id1 int not null primary key, t varchar(100)) pack_keys = 1;
create table t2(id2 int not null, t varchar(100), index(id2)) pack_keys = 1; create table t2(id2 int not null, t varchar(100), index(id2)) pack_keys = 1;
delete t1 from t1,t2 where t1.id1 = t2.id2 and t1.id1 > 500; delete t1 from t1,t2 where t1.id1 = t2.id2 and t1.id1 > 500;
drop table t1,t2; drop table t1,t2;
DROP TABLE IF EXISTS a,b,c; CREATE TABLE t1 (
CREATE TABLE a (
id int(11) NOT NULL default '0', id int(11) NOT NULL default '0',
name varchar(10) default NULL, name varchar(10) default NULL,
PRIMARY KEY (id) PRIMARY KEY (id)
) TYPE=MyISAM; ) TYPE=MyISAM;
INSERT INTO a VALUES (1,'aaa'),(2,'aaa'),(3,'aaa'); INSERT INTO t1 VALUES (1,'aaa'),(2,'aaa'),(3,'aaa');
CREATE TABLE b ( CREATE TABLE t2 (
id int(11) NOT NULL default '0', id int(11) NOT NULL default '0',
name varchar(10) default NULL, name varchar(10) default NULL,
PRIMARY KEY (id) PRIMARY KEY (id)
) TYPE=MyISAM; ) TYPE=MyISAM;
INSERT INTO b VALUES (2,'bbb'),(3,'bbb'),(4,'bbb'); INSERT INTO t2 VALUES (2,'bbb'),(3,'bbb'),(4,'bbb');
CREATE TABLE c ( CREATE TABLE t3 (
id int(11) NOT NULL default '0', id int(11) NOT NULL default '0',
mydate datetime default NULL, mydate datetime default NULL,
PRIMARY KEY (id) PRIMARY KEY (id)
) TYPE=MyISAM; ) TYPE=MyISAM;
INSERT INTO c VALUES (1,'2002-02-04 00:00:00'),(3,'2002-05-12 00:00:00'),(5,'2002-05-12 00:00:00'),(6,'2002-06-22 INSERT INTO t3 VALUES (1,'2002-02-04 00:00:00'),(3,'2002-05-12 00:00:00'),(5,'2002-05-12 00:00:00'),(6,'2002-06-22
00:00:00'),(7,'2002-07-22 00:00:00'); 00:00:00'),(7,'2002-07-22 00:00:00');
delete a,b,c from a,b,c delete t1,t2,t3 from t1,t2,t3 where to_days(now())-to_days(t3.mydate)>=30 and t3.id=t1.id and t3.id=t2.id;
where to_days(now())-to_days(c.mydate)>=30 select * from t3;
and c.id=a.id and c.id=b.id;
select * from c;
id mydate id mydate
1 2002-02-04 00:00:00 1 2002-02-04 00:00:00
5 2002-05-12 00:00:00 5 2002-05-12 00:00:00
6 2002-06-22 00:00:00 6 2002-06-22 00:00:00
7 2002-07-22 00:00:00 7 2002-07-22 00:00:00
DROP TABLE IF EXISTS a,b,c; DROP TABLE IF EXISTS t1,t2,t3;
drop table if exists parent, child; CREATE TABLE IF NOT EXISTS `t1` (
CREATE TABLE IF NOT EXISTS `parent` (
`id` int(11) NOT NULL auto_increment, `id` int(11) NOT NULL auto_increment,
`tst` text, `tst` text,
`tst1` text, `tst1` text,
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) TYPE=MyISAM; ) TYPE=MyISAM;
CREATE TABLE IF NOT EXISTS `child` ( CREATE TABLE IF NOT EXISTS `t2` (
`ID` int(11) NOT NULL auto_increment, `ID` int(11) NOT NULL auto_increment,
`ParId` int(11) default NULL, `ParId` int(11) default NULL,
`tst` text, `tst` text,
`tst1` text, `tst1` text,
PRIMARY KEY (`ID`), PRIMARY KEY (`ID`),
KEY `IX_ParId_child` (`ParId`), KEY `IX_ParId_t2` (`ParId`),
FOREIGN KEY (`ParId`) REFERENCES `test.parent` (`id`) FOREIGN KEY (`ParId`) REFERENCES `t1` (`id`)
) TYPE=MyISAM; ) TYPE=MyISAM;
INSERT INTO parent(tst,tst1) INSERT INTO t1(tst,tst1) VALUES("MySQL","MySQL AB"), ("MSSQL","Microsoft"), ("ORACLE","ORACLE");
VALUES("MySQL","MySQL AB"), ("MSSQL","Microsoft"), ("ORACLE","ORACLE"); INSERT INTO t2(ParId) VALUES(1), (2), (3);
INSERT INTO child(ParId) select * from t2;
VALUES(1), (2), (3);
select * from child;
ID ParId tst tst1 ID ParId tst tst1
1 1 NULL NULL 1 1 NULL NULL
2 2 NULL NULL 2 2 NULL NULL
3 3 NULL NULL 3 3 NULL NULL
UPDATE child, parent UPDATE t2, t1 SET t2.tst = t1.tst, t2.tst1 = t1.tst1 WHERE t2.ParId = t1.Id;
SET child.tst = parent.tst, select * from t2;
child.tst1 = parent.tst1
WHERE child.ParId = parent.Id;
select * from child;
ID ParId tst tst1 ID ParId tst tst1
1 1 MySQL MySQL AB 1 1 MySQL MySQL AB
2 2 MSSQL Microsoft 2 2 MSSQL Microsoft
3 3 ORACLE ORACLE 3 3 ORACLE ORACLE
drop table parent, child;
drop table if exists t1, t2 ; drop table if exists t1, t2 ;
create table t1 (n numeric(10)); create table t1 (n numeric(10));
create table t2 (n numeric(10)); create table t2 (n numeric(10));
......
...@@ -80,67 +80,59 @@ while ($1) ...@@ -80,67 +80,59 @@ while ($1)
enable_query_log; enable_query_log;
delete t1 from t1,t2 where t1.id1 = t2.id2 and t1.id1 > 500; delete t1 from t1,t2 where t1.id1 = t2.id2 and t1.id1 > 500;
drop table t1,t2; drop table t1,t2;
DROP TABLE IF EXISTS a,b,c;
CREATE TABLE a ( CREATE TABLE t1 (
id int(11) NOT NULL default '0', id int(11) NOT NULL default '0',
name varchar(10) default NULL, name varchar(10) default NULL,
PRIMARY KEY (id) PRIMARY KEY (id)
) TYPE=MyISAM; ) TYPE=MyISAM;
INSERT INTO a VALUES (1,'aaa'),(2,'aaa'),(3,'aaa'); INSERT INTO t1 VALUES (1,'aaa'),(2,'aaa'),(3,'aaa');
CREATE TABLE b ( CREATE TABLE t2 (
id int(11) NOT NULL default '0', id int(11) NOT NULL default '0',
name varchar(10) default NULL, name varchar(10) default NULL,
PRIMARY KEY (id) PRIMARY KEY (id)
) TYPE=MyISAM; ) TYPE=MyISAM;
INSERT INTO b VALUES (2,'bbb'),(3,'bbb'),(4,'bbb'); INSERT INTO t2 VALUES (2,'bbb'),(3,'bbb'),(4,'bbb');
CREATE TABLE c ( CREATE TABLE t3 (
id int(11) NOT NULL default '0', id int(11) NOT NULL default '0',
mydate datetime default NULL, mydate datetime default NULL,
PRIMARY KEY (id) PRIMARY KEY (id)
) TYPE=MyISAM; ) TYPE=MyISAM;
INSERT INTO c VALUES (1,'2002-02-04 00:00:00'),(3,'2002-05-12 00:00:00'),(5,'2002-05-12 00:00:00'),(6,'2002-06-22 INSERT INTO t3 VALUES (1,'2002-02-04 00:00:00'),(3,'2002-05-12 00:00:00'),(5,'2002-05-12 00:00:00'),(6,'2002-06-22
00:00:00'),(7,'2002-07-22 00:00:00'); 00:00:00'),(7,'2002-07-22 00:00:00');
delete a,b,c from a,b,c delete t1,t2,t3 from t1,t2,t3 where to_days(now())-to_days(t3.mydate)>=30 and t3.id=t1.id and t3.id=t2.id;
where to_days(now())-to_days(c.mydate)>=30 select * from t3;
and c.id=a.id and c.id=b.id; DROP TABLE IF EXISTS t1,t2,t3;
select * from c;
DROP TABLE IF EXISTS a,b,c; CREATE TABLE IF NOT EXISTS `t1` (
drop table if exists parent, child;
CREATE TABLE IF NOT EXISTS `parent` (
`id` int(11) NOT NULL auto_increment, `id` int(11) NOT NULL auto_increment,
`tst` text, `tst` text,
`tst1` text, `tst1` text,
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) TYPE=MyISAM; ) TYPE=MyISAM;
CREATE TABLE IF NOT EXISTS `child` ( CREATE TABLE IF NOT EXISTS `t2` (
`ID` int(11) NOT NULL auto_increment, `ID` int(11) NOT NULL auto_increment,
`ParId` int(11) default NULL, `ParId` int(11) default NULL,
`tst` text, `tst` text,
`tst1` text, `tst1` text,
PRIMARY KEY (`ID`), PRIMARY KEY (`ID`),
KEY `IX_ParId_child` (`ParId`), KEY `IX_ParId_t2` (`ParId`),
FOREIGN KEY (`ParId`) REFERENCES `test.parent` (`id`) FOREIGN KEY (`ParId`) REFERENCES `t1` (`id`)
) TYPE=MyISAM; ) TYPE=MyISAM;
INSERT INTO parent(tst,tst1) INSERT INTO t1(tst,tst1) VALUES("MySQL","MySQL AB"), ("MSSQL","Microsoft"), ("ORACLE","ORACLE");
VALUES("MySQL","MySQL AB"), ("MSSQL","Microsoft"), ("ORACLE","ORACLE");
INSERT INTO child(ParId)
VALUES(1), (2), (3);
select * from child; INSERT INTO t2(ParId) VALUES(1), (2), (3);
UPDATE child, parent select * from t2;
SET child.tst = parent.tst,
child.tst1 = parent.tst1
WHERE child.ParId = parent.Id;
select * from child; UPDATE t2, t1 SET t2.tst = t1.tst, t2.tst1 = t1.tst1 WHERE t2.ParId = t1.Id;
select * from t2;
drop table parent, child;
drop table if exists t1, t2 ; drop table if exists t1, t2 ;
create table t1 (n numeric(10)); create table t1 (n numeric(10));
create table t2 (n numeric(10)); create table t2 (n numeric(10));
insert into t2 values (1),(2),(4),(8),(16),(32); insert into t2 values (1),(2),(4),(8),(16),(32);
......
...@@ -445,6 +445,8 @@ void init_io_cache_share(IO_CACHE *info, IO_CACHE_SHARE *s, uint num_threads) ...@@ -445,6 +445,8 @@ void init_io_cache_share(IO_CACHE *info, IO_CACHE_SHARE *s, uint num_threads)
s->active=0; /* to catch errors */ s->active=0; /* to catch errors */
info->share=s; info->share=s;
info->read_function=_my_b_read_r; info->read_function=_my_b_read_r;
/* Ensure that the code doesn't use pointer to the IO_CACHE object */
info->current_pos= info->current_end= 0;
} }
/* /*
......
...@@ -1658,7 +1658,7 @@ bool Item_func_like::turboBM_matches(const char* text, int text_len) const ...@@ -1658,7 +1658,7 @@ bool Item_func_like::turboBM_matches(const char* text, int text_len) const
i -= u; i -= u;
} }
if (i < 0) if (i < 0)
return true; return 1;
register const int v = plm1 - i; register const int v = plm1 - i;
turboShift = u - v; turboShift = u - v;
...@@ -1675,7 +1675,7 @@ bool Item_func_like::turboBM_matches(const char* text, int text_len) const ...@@ -1675,7 +1675,7 @@ bool Item_func_like::turboBM_matches(const char* text, int text_len) const
} }
j += shift; j += shift;
} }
return false; return 0;
} }
else else
{ {
...@@ -1689,7 +1689,7 @@ bool Item_func_like::turboBM_matches(const char* text, int text_len) const ...@@ -1689,7 +1689,7 @@ bool Item_func_like::turboBM_matches(const char* text, int text_len) const
i -= u; i -= u;
} }
if (i < 0) if (i < 0)
return true; return 1;
register const int v = plm1 - i; register const int v = plm1 - i;
turboShift = u - v; turboShift = u - v;
...@@ -1706,7 +1706,7 @@ bool Item_func_like::turboBM_matches(const char* text, int text_len) const ...@@ -1706,7 +1706,7 @@ bool Item_func_like::turboBM_matches(const char* text, int text_len) const
} }
j += shift; j += shift;
} }
return false; return 0;
} }
} }
......
...@@ -242,6 +242,20 @@ typedef struct st_sql_list { ...@@ -242,6 +242,20 @@ typedef struct st_sql_list {
uint elements; uint elements;
byte *first; byte *first;
byte **next; byte **next;
inline void empty()
{
elements=0;
first=0;
next= &first;
}
inline void link_in_list(byte *element,byte **next_ptr)
{
elements++;
(*next)=element;
next= next_ptr;
*next=0;
}
} SQL_LIST; } SQL_LIST;
...@@ -415,6 +429,10 @@ int mysql_update(THD *thd,TABLE_LIST *tables,List<Item> &fields, ...@@ -415,6 +429,10 @@ int mysql_update(THD *thd,TABLE_LIST *tables,List<Item> &fields,
List<Item> &values,COND *conds, List<Item> &values,COND *conds,
ORDER *order, ha_rows limit, ORDER *order, ha_rows limit,
enum enum_duplicates handle_duplicates); enum enum_duplicates handle_duplicates);
int mysql_multi_update(THD *thd, TABLE_LIST *table_list,
List<Item> *fields, List<Item> *values,
COND *conds, ulong options,
enum enum_duplicates handle_duplicates);
int mysql_insert(THD *thd,TABLE_LIST *table,List<Item> &fields, int mysql_insert(THD *thd,TABLE_LIST *table,List<Item> &fields,
List<List_item> &values, enum_duplicates flag); List<List_item> &values, enum_duplicates flag);
void kill_delayed_threads(void); void kill_delayed_threads(void);
...@@ -498,7 +516,7 @@ TABLE_LIST *add_table_to_list(Table_ident *table,LEX_STRING *alias, ...@@ -498,7 +516,7 @@ TABLE_LIST *add_table_to_list(Table_ident *table,LEX_STRING *alias,
void set_lock_for_tables(thr_lock_type lock_type); void set_lock_for_tables(thr_lock_type lock_type);
void add_join_on(TABLE_LIST *b,Item *expr); void add_join_on(TABLE_LIST *b,Item *expr);
void add_join_natural(TABLE_LIST *a,TABLE_LIST *b); void add_join_natural(TABLE_LIST *a,TABLE_LIST *b);
bool add_proc_to_list(Item *item); bool add_proc_to_list(THD *thd, Item *item);
TABLE *unlink_open_table(THD *thd,TABLE *list,TABLE *find); TABLE *unlink_open_table(THD *thd,TABLE *list,TABLE *find);
SQL_SELECT *make_select(TABLE *head, table_map const_tables, SQL_SELECT *make_select(TABLE *head, table_map const_tables,
......
...@@ -1942,8 +1942,8 @@ static key_map get_key_map_from_key_list(TABLE *table, ...@@ -1942,8 +1942,8 @@ static key_map get_key_map_from_key_list(TABLE *table,
} }
/**************************************************************************** /****************************************************************************
** This just drops in all fields instead of current '*' field This just drops in all fields instead of current '*' field
** Returns pointer to last inserted field if ok Returns pointer to last inserted field if ok
****************************************************************************/ ****************************************************************************/
bool bool
...@@ -1957,21 +1957,26 @@ insert_fields(THD *thd,TABLE_LIST *tables, const char *db_name, ...@@ -1957,21 +1957,26 @@ insert_fields(THD *thd,TABLE_LIST *tables, const char *db_name,
for (; tables ; tables=tables->next) for (; tables ; tables=tables->next)
{ {
TABLE *table=tables->table; TABLE *table=tables->table;
if (grant_option && !thd->master_access &&
check_grant_all_columns(thd,SELECT_ACL,table) )
DBUG_RETURN(-1);
if (!table_name || (!strcmp(table_name,tables->alias) && if (!table_name || (!strcmp(table_name,tables->alias) &&
(!db_name || !strcmp(tables->db,db_name)))) (!db_name || !strcmp(tables->db,db_name))))
{ {
/* Ensure that we have access right to all columns */
if (grant_option && !thd->master_access &&
check_grant_all_columns(thd,SELECT_ACL,table) )
DBUG_RETURN(-1);
Field **ptr=table->field,*field; Field **ptr=table->field,*field;
thd->used_tables|=table->map; thd->used_tables|=table->map;
while ((field = *ptr++)) while ((field = *ptr++))
{ {
Item_field *item= new Item_field(field); Item_field *item= new Item_field(field);
if (!found++) if (!found++)
(void) it->replace(item); (void) it->replace(item); // Replace '*'
else else
it->after(item); it->after(item);
/*
Mark if field used before in this select.
Used by 'insert' to verify if a field name is used twice
*/
if (field->query_id == thd->query_id) if (field->query_id == thd->query_id)
thd->dupp_field=field; thd->dupp_field=field;
field->query_id=thd->query_id; field->query_id=thd->query_id;
......
...@@ -592,7 +592,7 @@ public: ...@@ -592,7 +592,7 @@ public:
virtual int prepare(List<Item> &list) { return 0; } virtual int prepare(List<Item> &list) { return 0; }
virtual bool send_fields(List<Item> &list,uint flag)=0; virtual bool send_fields(List<Item> &list,uint flag)=0;
virtual bool send_data(List<Item> &items)=0; virtual bool send_data(List<Item> &items)=0;
virtual void initialize_tables (JOIN *join=0) {} virtual bool initialize_tables (JOIN *join=0) { return 0; }
virtual void send_error(uint errcode,const char *err) virtual void send_error(uint errcode,const char *err)
{ {
::send_error(&thd->net,errcode,err); ::send_error(&thd->net,errcode,err);
...@@ -656,10 +656,10 @@ class select_insert :public select_result { ...@@ -656,10 +656,10 @@ class select_insert :public select_result {
List<Item> *fields; List<Item> *fields;
ulonglong last_insert_id; ulonglong last_insert_id;
COPY_INFO info; COPY_INFO info;
uint save_time_stamp;
select_insert(TABLE *table_par,List<Item> *fields_par,enum_duplicates duplic) select_insert(TABLE *table_par,List<Item> *fields_par,enum_duplicates duplic)
:table(table_par),fields(fields_par), last_insert_id(0), save_time_stamp(0) { :table(table_par),fields(fields_par), last_insert_id(0)
{
bzero((char*) &info,sizeof(info)); bzero((char*) &info,sizeof(info));
info.handle_duplicates=duplic; info.handle_duplicates=duplic;
} }
...@@ -703,8 +703,8 @@ class select_union :public select_result { ...@@ -703,8 +703,8 @@ class select_union :public select_result {
public: public:
TABLE *table; TABLE *table;
COPY_INFO info; COPY_INFO info;
uint save_time_stamp;
TMP_TABLE_PARAM *tmp_table_param; TMP_TABLE_PARAM *tmp_table_param;
bool not_describe;
select_union(TABLE *table_par); select_union(TABLE *table_par);
~select_union(); ~select_union();
...@@ -814,37 +814,36 @@ public: ...@@ -814,37 +814,36 @@ public:
bool send_fields(List<Item> &list, bool send_fields(List<Item> &list,
uint flag) { return 0; } uint flag) { return 0; }
bool send_data(List<Item> &items); bool send_data(List<Item> &items);
void initialize_tables (JOIN *join); bool initialize_tables (JOIN *join);
void send_error(uint errcode,const char *err); void send_error(uint errcode,const char *err);
int do_deletes (bool from_send_error); int do_deletes (bool from_send_error);
bool send_eof(); bool send_eof();
}; };
class multi_update : public select_result { class multi_update : public select_result
TABLE_LIST *update_tables, *table_being_updated; {
// Unique **tempfiles; TABLE_LIST *all_tables, *update_tables, *table_being_updated;
COPY_INFO *infos; THD *thd;
TABLE **tmp_tables; TABLE **tmp_tables, *main_table;
THD *thd; TMP_TABLE_PARAM *tmp_table_param;
ha_rows updated, found; ha_rows updated, found;
List<Item> fields; List <Item> *fields, *values;
List <Item> **fields_by_tables; List <Item> **fields_for_table, **values_for_table;
enum enum_duplicates dupl; uint table_count;
uint num_of_tables, num_fields, num_updated, *save_time_stamps, *field_sequence; Copy_field *copy_field;
int error; enum enum_duplicates handle_duplicates;
bool do_update, not_trans_safe; bool do_update, trans_safe, transactional_tables, log_delayed;
public:
multi_update(THD *thd_arg, TABLE_LIST *ut, List<Item> &fs, public:
enum enum_duplicates handle_duplicates, multi_update(THD *thd_arg, TABLE_LIST *ut, List<Item> *fields,
uint num); List<Item> *values, enum_duplicates handle_duplicates);
~multi_update(); ~multi_update();
int prepare(List<Item> &list); int prepare(List<Item> &list);
bool send_fields(List<Item> &list, bool send_fields(List<Item> &list, uint flag) { return 0; }
uint flag) { return 0; } bool send_data(List<Item> &items);
bool send_data(List<Item> &items); bool initialize_tables (JOIN *join);
void initialize_tables (JOIN *join); void send_error(uint errcode,const char *err);
void send_error(uint errcode,const char *err); int do_updates (bool from_send_error);
int do_updates (bool from_send_error); bool send_eof();
bool send_eof(); };
};
...@@ -213,12 +213,13 @@ cleanup: ...@@ -213,12 +213,13 @@ cleanup:
extern "C" int refposcmp2(void* arg, const void *a,const void *b) extern "C" int refposcmp2(void* arg, const void *a,const void *b)
{ {
/* arg is a pointer to file->ref_length */
return memcmp(a,b, *(int*) arg); return memcmp(a,b, *(int*) arg);
} }
multi_delete::multi_delete(THD *thd_arg, TABLE_LIST *dt, multi_delete::multi_delete(THD *thd_arg, TABLE_LIST *dt,
uint num_of_tables_arg) uint num_of_tables_arg)
: delete_tables (dt), thd(thd_arg), deleted(0), : delete_tables(dt), thd(thd_arg), deleted(0),
num_of_tables(num_of_tables_arg), error(0), num_of_tables(num_of_tables_arg), error(0),
do_delete(0), transactional_tables(0), log_delayed(0), normal_tables(0) do_delete(0), transactional_tables(0), log_delayed(0), normal_tables(0)
{ {
...@@ -230,31 +231,22 @@ int ...@@ -230,31 +231,22 @@ int
multi_delete::prepare(List<Item> &values) multi_delete::prepare(List<Item> &values)
{ {
DBUG_ENTER("multi_delete::prepare"); DBUG_ENTER("multi_delete::prepare");
do_delete = true; do_delete= 1;
thd->proc_info="deleting from main table"; thd->proc_info="deleting from main table";
if (thd->options & OPTION_SAFE_UPDATES)
{
TABLE_LIST *table_ref;
for (table_ref=delete_tables; table_ref; table_ref=table_ref->next)
{
TABLE *table=table_ref->table;
if ((thd->options & OPTION_SAFE_UPDATES) && !table->quick_keys)
{
my_error(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE,MYF(0));
DBUG_RETURN(1);
}
}
}
DBUG_RETURN(0); DBUG_RETURN(0);
} }
void bool
multi_delete::initialize_tables(JOIN *join) multi_delete::initialize_tables(JOIN *join)
{ {
int counter=0;
TABLE_LIST *walk; TABLE_LIST *walk;
Unique **tempfiles_ptr;
DBUG_ENTER("initialize_tables");
if ((thd->options & OPTION_SAFE_UPDATES) && error_if_full_join(join))
DBUG_RETURN(1);
table_map tables_to_delete_from=0; table_map tables_to_delete_from=0;
for (walk= delete_tables ; walk ; walk=walk->next) for (walk= delete_tables ; walk ; walk=walk->next)
tables_to_delete_from|= walk->table->map; tables_to_delete_from|= walk->table->map;
...@@ -268,9 +260,10 @@ multi_delete::initialize_tables(JOIN *join) ...@@ -268,9 +260,10 @@ multi_delete::initialize_tables(JOIN *join)
{ {
/* We are going to delete from this table */ /* We are going to delete from this table */
TABLE *tbl=walk->table=tab->table; TABLE *tbl=walk->table=tab->table;
walk=walk->next;
/* Don't use KEYREAD optimization on this table */ /* Don't use KEYREAD optimization on this table */
tbl->no_keyread=1; tbl->no_keyread=1;
walk=walk->next; tbl->used_keys= 0;
if (tbl->file->has_transactions()) if (tbl->file->has_transactions())
log_delayed= transactional_tables= 1; log_delayed= transactional_tables= 1;
else if (tbl->tmp_table != NO_TMP_TABLE) else if (tbl->tmp_table != NO_TMP_TABLE)
...@@ -280,19 +273,17 @@ multi_delete::initialize_tables(JOIN *join) ...@@ -280,19 +273,17 @@ multi_delete::initialize_tables(JOIN *join)
} }
} }
walk= delete_tables; walk= delete_tables;
walk->table->used_keys=0; tempfiles_ptr= tempfiles;
for (walk=walk->next ; walk ; walk=walk->next, counter++) for (walk=walk->next ; walk ; walk=walk->next)
{ {
tables_to_delete_from|= walk->table->map;
TABLE *table=walk->table; TABLE *table=walk->table;
/* Don't use key read with MULTI-TABLE-DELETE */ *tempfiles_ptr++= new Unique (refposcmp2,
table->used_keys=0; (void *) &table->file->ref_length,
tempfiles[counter] = new Unique (refposcmp2, table->file->ref_length,
(void *) &table->file->ref_length, MEM_STRIP_BUF_SIZE);
table->file->ref_length,
MEM_STRIP_BUF_SIZE);
} }
init_ftfuncs(thd,1); init_ftfuncs(thd,1);
DBUG_RETURN(thd->fatal_error != 0);
} }
...@@ -307,7 +298,7 @@ multi_delete::~multi_delete() ...@@ -307,7 +298,7 @@ multi_delete::~multi_delete()
t->no_keyread=0; t->no_keyread=0;
} }
for (uint counter = 0; counter < num_of_tables-1; counter++) for (uint counter= 0; counter < num_of_tables-1; counter++)
{ {
if (tempfiles[counter]) if (tempfiles[counter])
delete tempfiles[counter]; delete tempfiles[counter];
...@@ -414,7 +405,7 @@ int multi_delete::do_deletes(bool from_send_error) ...@@ -414,7 +405,7 @@ int multi_delete::do_deletes(bool from_send_error)
else else
table_being_deleted = delete_tables; table_being_deleted = delete_tables;
do_delete = false; do_delete= 0;
for (table_being_deleted=table_being_deleted->next; for (table_being_deleted=table_being_deleted->next;
table_being_deleted ; table_being_deleted ;
table_being_deleted=table_being_deleted->next, counter++) table_being_deleted=table_being_deleted->next, counter++)
...@@ -468,7 +459,7 @@ bool multi_delete::send_eof() ...@@ -468,7 +459,7 @@ bool multi_delete::send_eof()
was a non-transaction-safe table involved, since was a non-transaction-safe table involved, since
modifications in it cannot be rolled back. modifications in it cannot be rolled back.
*/ */
if (deleted) if (deleted && (error <= 0 || normal_tables))
{ {
mysql_update_log.write(thd,thd->query,thd->query_length); mysql_update_log.write(thd,thd->query,thd->query_length);
if (mysql_bin_log.is_open()) if (mysql_bin_log.is_open())
...@@ -478,11 +469,17 @@ bool multi_delete::send_eof() ...@@ -478,11 +469,17 @@ bool multi_delete::send_eof()
if (mysql_bin_log.write(&qinfo) && !normal_tables) if (mysql_bin_log.write(&qinfo) && !normal_tables)
local_error=1; // Log write failed: roll back the SQL statement local_error=1; // Log write failed: roll back the SQL statement
} }
/* Commit or rollback the current SQL statement */ if (!log_delayed)
VOID(ha_autocommit_or_rollback(thd,local_error > 0)); thd->options|=OPTION_STATUS_NO_TRANS_UPDATE;
query_cache_invalidate3(thd, delete_tables, 1);
} }
/* Commit or rollback the current SQL statement */
if (transactional_tables)
if (ha_autocommit_or_rollback(thd,local_error > 0))
local_error=1;
if (deleted)
query_cache_invalidate3(thd, delete_tables, 1);
if (local_error) if (local_error)
::send_error(&thd->net); ::send_error(&thd->net);
else else
......
...@@ -41,7 +41,8 @@ static void unlink_blobs(register TABLE *table); ...@@ -41,7 +41,8 @@ static void unlink_blobs(register TABLE *table);
/* /*
Check if insert fields are correct Check if insert fields are correct
Resets form->time_stamp if a timestamp value is set Updates table->time_stamp to point to timestamp field or 0, depending on
if timestamp should be updated or not.
*/ */
static int static int
...@@ -87,11 +88,12 @@ check_insert_fields(THD *thd,TABLE *table,List<Item> &fields, ...@@ -87,11 +88,12 @@ check_insert_fields(THD *thd,TABLE *table,List<Item> &fields,
my_error(ER_FIELD_SPECIFIED_TWICE,MYF(0), thd->dupp_field->field_name); my_error(ER_FIELD_SPECIFIED_TWICE,MYF(0), thd->dupp_field->field_name);
return -1; return -1;
} }
table->time_stamp=0;
if (table->timestamp_field && // Don't set timestamp if used if (table->timestamp_field && // Don't set timestamp if used
table->timestamp_field->query_id == thd->query_id) table->timestamp_field->query_id != thd->query_id)
table->time_stamp=0; // This should be saved table->time_stamp= table->timestamp_field->offset()+1;
} }
// For the values we need select_priv // For the values we need select_priv
table->grant.want_privilege=(SELECT_ACL & ~table->grant.privilege); table->grant.want_privilege=(SELECT_ACL & ~table->grant.privilege);
return 0; return 0;
} }
...@@ -105,7 +107,6 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, List<Item> &fields, ...@@ -105,7 +107,6 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, List<Item> &fields,
!(thd->master_access & SUPER_ACL)); !(thd->master_access & SUPER_ACL));
bool transactional_table, log_delayed, bulk_insert=0; bool transactional_table, log_delayed, bulk_insert=0;
uint value_count; uint value_count;
uint save_time_stamp;
ulong counter = 1; ulong counter = 1;
ulonglong id; ulonglong id;
COPY_INFO info; COPY_INFO info;
...@@ -150,14 +151,10 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, List<Item> &fields, ...@@ -150,14 +151,10 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, List<Item> &fields,
DBUG_RETURN(-1); DBUG_RETURN(-1);
thd->proc_info="init"; thd->proc_info="init";
thd->used_tables=0; thd->used_tables=0;
save_time_stamp=table->time_stamp;
values= its++; values= its++;
if (check_insert_fields(thd,table,fields,*values,1) || if (check_insert_fields(thd,table,fields,*values,1) ||
setup_tables(table_list) || setup_fields(thd,table_list,*values,0,0,0)) setup_tables(table_list) || setup_fields(thd,table_list,*values,0,0,0))
{
table->time_stamp=save_time_stamp;
goto abort; goto abort;
}
value_count= values->elements; value_count= values->elements;
while ((values = its++)) while ((values = its++))
{ {
...@@ -167,14 +164,10 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, List<Item> &fields, ...@@ -167,14 +164,10 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, List<Item> &fields,
my_printf_error(ER_WRONG_VALUE_COUNT_ON_ROW, my_printf_error(ER_WRONG_VALUE_COUNT_ON_ROW,
ER(ER_WRONG_VALUE_COUNT_ON_ROW), ER(ER_WRONG_VALUE_COUNT_ON_ROW),
MYF(0),counter); MYF(0),counter);
table->time_stamp=save_time_stamp;
goto abort; goto abort;
} }
if (setup_fields(thd,table_list,*values,0,0,0)) if (setup_fields(thd,table_list,*values,0,0,0))
{
table->time_stamp=save_time_stamp;
goto abort; goto abort;
}
} }
its.rewind (); its.rewind ();
/* /*
...@@ -333,7 +326,6 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, List<Item> &fields, ...@@ -333,7 +326,6 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, List<Item> &fields,
} }
} }
thd->proc_info="end"; thd->proc_info="end";
table->time_stamp=save_time_stamp; // Restore auto timestamp ptr
table->next_number_field=0; table->next_number_field=0;
thd->count_cuted_fields=0; thd->count_cuted_fields=0;
thd->next_insert_id=0; // Reset this if wrongly used thd->next_insert_id=0; // Reset this if wrongly used
...@@ -1287,7 +1279,6 @@ select_insert::prepare(List<Item> &values) ...@@ -1287,7 +1279,6 @@ select_insert::prepare(List<Item> &values)
{ {
DBUG_ENTER("select_insert::prepare"); DBUG_ENTER("select_insert::prepare");
save_time_stamp=table->time_stamp;
if (check_insert_fields(thd,table,*fields,values,1)) if (check_insert_fields(thd,table,*fields,values,1))
DBUG_RETURN(1); DBUG_RETURN(1);
...@@ -1308,8 +1299,6 @@ select_insert::~select_insert() ...@@ -1308,8 +1299,6 @@ select_insert::~select_insert()
{ {
if (table) if (table)
{ {
if (save_time_stamp)
table->time_stamp=save_time_stamp;
table->next_number_field=0; table->next_number_field=0;
table->file->extra(HA_EXTRA_RESET); table->file->extra(HA_EXTRA_RESET);
} }
...@@ -1412,7 +1401,6 @@ select_create::prepare(List<Item> &values) ...@@ -1412,7 +1401,6 @@ select_create::prepare(List<Item> &values)
/* First field to copy */ /* First field to copy */
field=table->field+table->fields - values.elements; field=table->field+table->fields - values.elements;
save_time_stamp=table->time_stamp;
if (table->timestamp_field) // Don't set timestamp if used if (table->timestamp_field) // Don't set timestamp if used
{ {
table->timestamp_field->set_time(); table->timestamp_field->set_time();
......
...@@ -75,7 +75,7 @@ static int make_new_olap_select(LEX *lex, SELECT_LEX *select_lex, List<Item> new ...@@ -75,7 +75,7 @@ static int make_new_olap_select(LEX *lex, SELECT_LEX *select_lex, List<Item> new
!strcmp(((Item_field*)new_item)->table_name,iif->table_name) && !strcmp(((Item_field*)new_item)->table_name,iif->table_name) &&
!strcmp(((Item_field*)new_item)->field_name,iif->field_name)) !strcmp(((Item_field*)new_item)->field_name,iif->field_name))
{ {
not_found=false; not_found= 0;
((Item_field*)new_item)->db_name=iif->db_name; ((Item_field*)new_item)->db_name=iif->db_name;
Item_field *new_one=new Item_field(iif->db_name, iif->table_name, iif->field_name); Item_field *new_one=new Item_field(iif->db_name, iif->table_name, iif->field_name);
privlist.push_back(new_one); privlist.push_back(new_one);
...@@ -151,7 +151,7 @@ int handle_olaps(LEX *lex, SELECT_LEX *select_lex) ...@@ -151,7 +151,7 @@ int handle_olaps(LEX *lex, SELECT_LEX *select_lex)
if (cursor->do_redirect) if (cursor->do_redirect)
{ {
cursor->table= ((TABLE_LIST*) cursor->table)->table; cursor->table= ((TABLE_LIST*) cursor->table)->table;
cursor->do_redirect=false; cursor->do_redirect= 0;
} }
} }
......
...@@ -422,7 +422,7 @@ end: ...@@ -422,7 +422,7 @@ end:
} }
static void reset_mqh(THD *thd, LEX_USER *lu, bool get_them=false) static void reset_mqh(THD *thd, LEX_USER *lu, bool get_them= 0)
{ {
(void) pthread_mutex_lock(&LOCK_user_conn); (void) pthread_mutex_lock(&LOCK_user_conn);
...@@ -1826,61 +1826,29 @@ mysql_execute_command(void) ...@@ -1826,61 +1826,29 @@ mysql_execute_command(void)
select_lex->select_limit, select_lex->select_limit,
lex->duplicates); lex->duplicates);
} }
else else
{ {
multi_update *result; const char *msg= 0;
uint table_count; lex->sql_command= SQLCOM_MULTI_UPDATE;
TABLE_LIST *auxi;
const char *msg=0;
lex->sql_command=SQLCOM_MULTI_UPDATE;
for (auxi=(TABLE_LIST*) tables, table_count=0 ; auxi ; auxi=auxi->next)
table_count++;
if (select_lex->order_list.elements) if (select_lex->order_list.elements)
msg="ORDER BY"; msg="ORDER BY";
else if (select_lex->select_limit && select_lex->select_limit != else if (select_lex->select_limit && select_lex->select_limit !=
HA_POS_ERROR) HA_POS_ERROR)
msg="LIMIT"; msg="LIMIT";
if (msg) if (msg)
{ {
net_printf(&thd->net, ER_WRONG_USAGE, "UPDATE", msg); net_printf(&thd->net, ER_WRONG_USAGE, "UPDATE", msg);
res= 1; res= 1;
break; break;
} }
tables->grant.want_privilege=(SELECT_ACL & ~tables->grant.privilege); res= mysql_multi_update(thd,tables,
if ((res=open_and_lock_tables(thd,tables))) &select_lex->item_list,
break; &lex->value_list,
thd->select_limit=HA_POS_ERROR; select_lex->where,
if (!setup_fields(thd,tables,select_lex->item_list,1,0,0) && select_lex->options,
!setup_fields(thd,tables,lex->value_list,0,0,0) && lex->duplicates);
! thd->fatal_error &&
(result=new multi_update(thd,tables,select_lex->item_list,
lex->duplicates, table_count)))
{
List <Item> total_list;
List_iterator <Item> field_list(select_lex->item_list);
List_iterator <Item> value_list(lex->value_list);
Item *item;
while ((item=field_list++))
total_list.push_back(item);
while ((item=value_list++))
total_list.push_back(item);
res=mysql_select(thd,tables,total_list,
select_lex->where,
(ORDER *)NULL,(ORDER *)NULL,(Item *)NULL,
(ORDER *)NULL,
select_lex->options | thd->options |
SELECT_NO_JOIN_CACHE,
result);
delete result;
}
else
res= -1; // Error is not sent
close_thread_tables(thd);
} }
break; break;
case SQLCOM_INSERT: case SQLCOM_INSERT:
if (check_access(thd,INSERT_ACL,tables->db,&tables->grant.privilege)) if (check_access(thd,INSERT_ACL,tables->db,&tables->grant.privilege))
goto error; /* purecov: inspected */ goto error; /* purecov: inspected */
...@@ -2741,11 +2709,8 @@ mysql_init_select(LEX *lex) ...@@ -2741,11 +2709,8 @@ mysql_init_select(LEX *lex)
select_lex->olap= UNSPECIFIED_OLAP_TYPE; select_lex->olap= UNSPECIFIED_OLAP_TYPE;
lex->exchange = 0; lex->exchange = 0;
lex->proc_list.first=0; lex->proc_list.first=0;
select_lex->order_list.elements=select_lex->group_list.elements=0; select_lex->order_list.empty();
select_lex->order_list.first=0; select_lex->group_list.empty();
select_lex->order_list.next= (byte**) &select_lex->order_list.first;
select_lex->group_list.first=0;
select_lex->group_list.next= (byte**) &select_lex->group_list.first;
select_lex->next = (SELECT_LEX *)NULL; select_lex->next = (SELECT_LEX *)NULL;
} }
...@@ -2818,16 +2783,6 @@ mysql_parse(THD *thd,char *inBuf,uint length) ...@@ -2818,16 +2783,6 @@ mysql_parse(THD *thd,char *inBuf,uint length)
} }
inline static void
link_in_list(SQL_LIST *list,byte *element,byte **next)
{
list->elements++;
(*list->next)=element;
list->next=next;
*next=0;
}
/***************************************************************************** /*****************************************************************************
** Store field definition for create ** Store field definition for create
** Return 0 if ok ** Return 0 if ok
...@@ -3102,7 +3057,7 @@ void store_position_for_column(const char *name) ...@@ -3102,7 +3057,7 @@ void store_position_for_column(const char *name)
} }
bool bool
add_proc_to_list(Item *item) add_proc_to_list(THD* thd, Item *item)
{ {
ORDER *order; ORDER *order;
Item **item_ptr; Item **item_ptr;
...@@ -3113,7 +3068,7 @@ add_proc_to_list(Item *item) ...@@ -3113,7 +3068,7 @@ add_proc_to_list(Item *item)
*item_ptr= item; *item_ptr= item;
order->item=item_ptr; order->item=item_ptr;
order->free_me=0; order->free_me=0;
link_in_list(&current_lex->proc_list,(byte*) order,(byte**) &order->next); thd->lex.proc_list.link_in_list((byte*) order,(byte**) &order->next);
return 0; return 0;
} }
...@@ -3167,7 +3122,7 @@ bool add_to_list(SQL_LIST &list,Item *item,bool asc) ...@@ -3167,7 +3122,7 @@ bool add_to_list(SQL_LIST &list,Item *item,bool asc)
order->asc = asc; order->asc = asc;
order->free_me=0; order->free_me=0;
order->used=0; order->used=0;
link_in_list(&list,(byte*) order,(byte**) &order->next); list.link_in_list((byte*) order,(byte**) &order->next);
DBUG_RETURN(0); DBUG_RETURN(0);
} }
...@@ -3248,7 +3203,7 @@ TABLE_LIST *add_table_to_list(Table_ident *table, LEX_STRING *alias, ...@@ -3248,7 +3203,7 @@ TABLE_LIST *add_table_to_list(Table_ident *table, LEX_STRING *alias,
} }
} }
} }
link_in_list(&thd->lex.select->table_list,(byte*) ptr,(byte**) &ptr->next); thd->lex.select->table_list.link_in_list((byte*) ptr,(byte**) &ptr->next);
DBUG_RETURN(ptr); DBUG_RETURN(ptr);
} }
......
...@@ -437,7 +437,8 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds, ...@@ -437,7 +437,8 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
if (make_join_statistics(&join,tables,conds,&keyuse) || thd->fatal_error) if (make_join_statistics(&join,tables,conds,&keyuse) || thd->fatal_error)
goto err; goto err;
thd->proc_info="preparing"; thd->proc_info="preparing";
result->initialize_tables(&join); if (result->initialize_tables(&join))
goto err;
if (join.const_table_map != join.found_const_table_map && if (join.const_table_map != join.found_const_table_map &&
!(select_options & SELECT_DESCRIBE)) !(select_options & SELECT_DESCRIBE))
{ {
...@@ -2721,6 +2722,38 @@ make_join_readinfo(JOIN *join,uint options) ...@@ -2721,6 +2722,38 @@ make_join_readinfo(JOIN *join,uint options)
} }
/*
Give error if we some tables are done with a full join
SYNOPSIS
error_if_full_join()
join Join condition
USAGE
This is used by multi_table_update and multi_table_delete when running
in safe mode
RETURN VALUES
0 ok
1 Error (full join used)
*/
bool error_if_full_join(JOIN *join)
{
for (JOIN_TAB *tab=join->join_tab, *end=join->join_tab+join->tables;
tab < end;
tab++)
{
if (tab->type == JT_ALL && !tab->select->quick)
{
my_error(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE,MYF(0));
return(1);
}
}
return(0);
}
static void static void
join_free(JOIN *join) join_free(JOIN *join)
{ {
...@@ -3401,12 +3434,34 @@ const_expression_in_where(COND *cond, Item *comp_item, Item **const_item) ...@@ -3401,12 +3434,34 @@ const_expression_in_where(COND *cond, Item *comp_item, Item **const_item)
/**************************************************************************** /****************************************************************************
Create a temp table according to a field list. Create internal temporary table
Set distinct if duplicates could be removed
Given fields field pointers are changed to point at tmp_table
for send_fields
****************************************************************************/ ****************************************************************************/
/*
Create field for temporary table
SYNOPSIS
create_tmp_field()
thd Thread handler
table Temporary table
item Item to create a field for
type Type of item (normally item->type)
copy_func If set and item is a function, store copy of item
in this array
group 1 if we are going to do a relative group by on result
modify_item 1 if item->result_field should point to new item.
This is relevent for how fill_record() is going to
work:
If modify_item is 1 then fill_record() will update
the record in the original table.
If modify_item is 0 then fill_record() will update
the temporary table
RETURN
0 on error
new_created field
*/
Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
Item_result_field ***copy_func, Field **from_field, Item_result_field ***copy_func, Field **from_field,
bool group, bool modify_item) bool group, bool modify_item)
...@@ -3515,6 +3570,13 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, ...@@ -3515,6 +3570,13 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
} }
/*
Create a temp table according to a field list.
Set distinct if duplicates could be removed
Given fields field pointers are changed to point at tmp_table
for send_fields
*/
TABLE * TABLE *
create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
ORDER *group, bool distinct, bool save_sum_fields, ORDER *group, bool distinct, bool save_sum_fields,
...@@ -3675,9 +3737,19 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, ...@@ -3675,9 +3737,19 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
} }
else else
{ {
/*
The last parameter to create_tmp_field() is a bit tricky:
We need to set it to 0 in union, to get fill_record() to modify the
temporary table.
We need to set it to 1 on multi-table-update and in select to
write rows to the temporary table.
We here distinguish between UNION and multi-table-updates by the fact
that in the later case group is set to the row pointer.
*/
Field *new_field=create_tmp_field(thd, table, item,type, &copy_func, Field *new_field=create_tmp_field(thd, table, item,type, &copy_func,
tmp_from_field, group != 0, tmp_from_field, group != 0,
not_all_columns); not_all_columns || group !=0);
if (!new_field) if (!new_field)
{ {
if (thd->fatal_error) if (thd->fatal_error)
...@@ -3991,7 +4063,6 @@ static bool open_tmp_table(TABLE *table) ...@@ -3991,7 +4063,6 @@ static bool open_tmp_table(TABLE *table)
table->db_stat=0; table->db_stat=0;
return(1); return(1);
} }
/* VOID(ha_lock(table,F_WRLCK)); */ /* Single thread table */
(void) table->file->extra(HA_EXTRA_QUICK); /* Faster */ (void) table->file->extra(HA_EXTRA_QUICK); /* Faster */
return(0); return(0);
} }
......
...@@ -301,3 +301,4 @@ public: ...@@ -301,3 +301,4 @@ public:
}; };
bool cp_buffer_from_ref(TABLE_REF *ref); bool cp_buffer_from_ref(TABLE_REF *ref);
bool error_if_full_join(JOIN *join);
...@@ -33,7 +33,7 @@ int mysql_union(THD *thd, LEX *lex,select_result *result) ...@@ -33,7 +33,7 @@ int mysql_union(THD *thd, LEX *lex,select_result *result)
TABLE *table; TABLE *table;
int describe=(lex->select_lex.options & SELECT_DESCRIBE) ? 1 : 0; int describe=(lex->select_lex.options & SELECT_DESCRIBE) ? 1 : 0;
int res; int res;
bool found_rows_for_union=false; bool found_rows_for_union= 0;
TABLE_LIST result_table_list; TABLE_LIST result_table_list;
TABLE_LIST *first_table=(TABLE_LIST *)lex->select_lex.table_list.first; TABLE_LIST *first_table=(TABLE_LIST *)lex->select_lex.table_list.first;
TMP_TABLE_PARAM tmp_table_param; TMP_TABLE_PARAM tmp_table_param;
...@@ -53,7 +53,7 @@ int mysql_union(THD *thd, LEX *lex,select_result *result) ...@@ -53,7 +53,7 @@ int mysql_union(THD *thd, LEX *lex,select_result *result)
if (cursor->do_redirect) // False if CUBE/ROLLUP if (cursor->do_redirect) // False if CUBE/ROLLUP
{ {
cursor->table= ((TABLE_LIST*) cursor->table)->table; cursor->table= ((TABLE_LIST*) cursor->table)->table;
cursor->do_redirect=false; cursor->do_redirect= 0;
} }
} }
} }
...@@ -138,7 +138,7 @@ int mysql_union(THD *thd, LEX *lex,select_result *result) ...@@ -138,7 +138,7 @@ int mysql_union(THD *thd, LEX *lex,select_result *result)
res= -1; res= -1;
goto exit; goto exit;
} }
union_result->save_time_stamp=!describe; union_result->not_describe= !describe;
union_result->tmp_table_param=&tmp_table_param; union_result->tmp_table_param=&tmp_table_param;
for (sl= &lex->select_lex; sl; sl=sl->next) for (sl= &lex->select_lex; sl; sl=sl->next)
{ {
...@@ -150,14 +150,17 @@ int mysql_union(THD *thd, LEX *lex,select_result *result) ...@@ -150,14 +150,17 @@ int mysql_union(THD *thd, LEX *lex,select_result *result)
if (thd->select_limit == HA_POS_ERROR) if (thd->select_limit == HA_POS_ERROR)
sl->options&= ~OPTION_FOUND_ROWS; sl->options&= ~OPTION_FOUND_ROWS;
res=mysql_select(thd, (describe && sl->linkage==NOT_A_SELECT) ? first_table : (TABLE_LIST*) sl->table_list.first, res=mysql_select(thd, (describe && sl->linkage==NOT_A_SELECT) ?
first_table : (TABLE_LIST*) sl->table_list.first,
sl->item_list, sl->item_list,
sl->where, sl->where,
(sl->braces) ? (ORDER *)sl->order_list.first : (ORDER *) 0, (sl->braces) ? (ORDER *)sl->order_list.first :
(ORDER *) 0,
(ORDER*) sl->group_list.first, (ORDER*) sl->group_list.first,
sl->having, sl->having,
(ORDER*) NULL, (ORDER*) NULL,
sl->options | thd->options | SELECT_NO_UNLOCK | ((describe) ? SELECT_DESCRIBE : 0), sl->options | thd->options | SELECT_NO_UNLOCK |
((describe) ? SELECT_DESCRIBE : 0),
union_result); union_result);
if (res) if (res)
goto exit; goto exit;
...@@ -226,7 +229,7 @@ exit: ...@@ -226,7 +229,7 @@ exit:
***************************************************************************/ ***************************************************************************/
select_union::select_union(TABLE *table_par) select_union::select_union(TABLE *table_par)
:table(table_par) :table(table_par), not_describe(0)
{ {
bzero((char*) &info,sizeof(info)); bzero((char*) &info,sizeof(info));
/* /*
...@@ -243,7 +246,7 @@ select_union::~select_union() ...@@ -243,7 +246,7 @@ select_union::~select_union()
int select_union::prepare(List<Item> &list) int select_union::prepare(List<Item> &list)
{ {
if (save_time_stamp && list.elements != table->fields) if (not_describe && list.elements != table->fields)
{ {
my_message(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT, my_message(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT,
ER(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT),MYF(0)); ER(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT),MYF(0));
......
This diff is collapsed.
...@@ -1436,9 +1436,9 @@ select: ...@@ -1436,9 +1436,9 @@ select:
select_init { Lex->sql_command=SQLCOM_SELECT; }; select_init { Lex->sql_command=SQLCOM_SELECT; };
select_init: select_init:
SELECT_SYM select_part2 { Select->braces=false; } opt_union SELECT_SYM select_part2 { Select->braces= 0; } opt_union
| |
'(' SELECT_SYM select_part2 ')' { Select->braces=true;} union_opt; '(' SELECT_SYM select_part2 ')' { Select->braces= 1;} union_opt;
select_part2: select_part2:
...@@ -2350,7 +2350,7 @@ procedure_clause: ...@@ -2350,7 +2350,7 @@ procedure_clause:
lex->proc_list.elements=0; lex->proc_list.elements=0;
lex->proc_list.first=0; lex->proc_list.first=0;
lex->proc_list.next= (byte**) &lex->proc_list.first; lex->proc_list.next= (byte**) &lex->proc_list.first;
if (add_proc_to_list(new Item_field(NULL,NULL,$2.str))) if (add_proc_to_list(lex->thd, new Item_field(NULL,NULL,$2.str)))
YYABORT; YYABORT;
current_thd->safe_to_cache_query=0; current_thd->safe_to_cache_query=0;
} }
...@@ -2368,10 +2368,11 @@ procedure_list2: ...@@ -2368,10 +2368,11 @@ procedure_list2:
procedure_item: procedure_item:
remember_name expr remember_name expr
{ {
if (add_proc_to_list($2)) LEX *lex= Lex;
if (add_proc_to_list(lex->thd, $2))
YYABORT; YYABORT;
if (!$2->name) if (!$2->name)
$2->set_name($1,(uint) ((char*) Lex->tok_end - $1)); $2->set_name($1,(uint) ((char*) lex->tok_end - $1));
}; };
opt_into: opt_into:
......
...@@ -117,18 +117,22 @@ struct st_table { ...@@ -117,18 +117,22 @@ struct st_table {
table_map map; /* ID bit of table (1,2,4,8,16...) */ table_map map; /* ID bit of table (1,2,4,8,16...) */
ulong version,flush_version; ulong version,flush_version;
uchar *null_flags; uchar *null_flags;
IO_CACHE *io_cache; /* If sorted trough file*/ IO_CACHE *io_cache; /* If sorted trough file*/
byte *record_pointers; /* If sorted in memory */ byte *record_pointers; /* If sorted in memory */
ha_rows found_records; /* How many records in sort */ ha_rows found_records; /* How many records in sort */
ORDER *group; ORDER *group;
ha_rows quick_rows[MAX_KEY]; ha_rows quick_rows[MAX_KEY];
uint quick_key_parts[MAX_KEY]; uint quick_key_parts[MAX_KEY];
key_part_map const_key_parts[MAX_KEY]; key_part_map const_key_parts[MAX_KEY];
ulong query_id; ulong query_id;
uint temp_pool_slot; union /* Temporary variables */
{
uint temp_pool_slot; /* Used by intern temp tables */
struct st_table_list *pos_in_table_list;
};
THD *in_use; /* Which thread uses this */ THD *in_use; /* Which thread uses this */
struct st_table *next,*prev; struct st_table *next,*prev;
}; };
...@@ -148,10 +152,10 @@ typedef struct st_table_list ...@@ -148,10 +152,10 @@ typedef struct st_table_list
GRANT_INFO grant; GRANT_INFO grant;
thr_lock_type lock_type; thr_lock_type lock_type;
uint outer_join; /* Which join type */ uint outer_join; /* Which join type */
uint shared; /* Used in union or in multi-upd */
uint32 db_length, real_name_length; uint32 db_length, real_name_length;
bool straight; /* optimize with prev table */ bool straight; /* optimize with prev table */
bool updating; /* for replicate-do/ignore table */ bool updating; /* for replicate-do/ignore table */
bool shared; /* Used twice in union */
bool do_redirect; /* To get the struct in UNION's */ bool do_redirect; /* To get the struct in UNION's */
} TABLE_LIST; } TABLE_LIST;
......
...@@ -53,7 +53,8 @@ Unique::Unique(qsort_cmp2 comp_func, void * comp_func_fixed_arg, ...@@ -53,7 +53,8 @@ Unique::Unique(qsort_cmp2 comp_func, void * comp_func_fixed_arg,
:max_in_memory_size(max_in_memory_size_arg),elements(0) :max_in_memory_size(max_in_memory_size_arg),elements(0)
{ {
my_b_clear(&file); my_b_clear(&file);
init_tree(&tree, max_in_memory_size / 16, 0, size, comp_func, 0, NULL, comp_func_fixed_arg); init_tree(&tree, max_in_memory_size / 16, 0, size, comp_func, 0, NULL,
comp_func_fixed_arg);
/* If the following fail's the next add will also fail */ /* If the following fail's the next add will also fail */
my_init_dynamic_array(&file_ptrs, sizeof(BUFFPEK), 16, 16); my_init_dynamic_array(&file_ptrs, sizeof(BUFFPEK), 16, 16);
max_elements= max_in_memory_size / ALIGN_SIZE(sizeof(TREE_ELEMENT)+size); max_elements= max_in_memory_size / ALIGN_SIZE(sizeof(TREE_ELEMENT)+size);
......
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