mirror of
https://github.com/MariaDB/server.git
synced 2025-01-31 02:51:44 +01:00
Merge jlindstrom@build.mysql.com:/home/bk/mysql-4.1
into hundin.mysql.fi:/home/jan/mysql-4.1
This commit is contained in:
commit
97e30064b2
34 changed files with 2277 additions and 298 deletions
|
@ -30,6 +30,7 @@ bk@admin.bk
|
|||
bk@mysql.r18.ru
|
||||
brian@avenger.(none)
|
||||
brian@brian-akers-computer.local
|
||||
brian@private-client-ip-101.oz.net
|
||||
carsten@tsort.bitbybit.dk
|
||||
davida@isil.mysql.com
|
||||
dlenev@brandersnatch.localdomain
|
||||
|
@ -102,6 +103,7 @@ miguel@light.local
|
|||
miguel@sartre.local
|
||||
mikron@c-fb0ae253.1238-1-64736c10.cust.bredbandsbolaget.se
|
||||
mikron@mikael-ronstr-ms-dator.local
|
||||
mleich@mysql.com
|
||||
mmatthew@markslaptop.
|
||||
monty@bitch.mysql.fi
|
||||
monty@butch.
|
||||
|
|
|
@ -4,7 +4,7 @@ dnl Process this file with autoconf to produce a configure script.
|
|||
AC_INIT(sql/mysqld.cc)
|
||||
AC_CANONICAL_SYSTEM
|
||||
# The Docs Makefile.am parses this line!
|
||||
AM_INIT_AUTOMAKE(mysql, 4.1.5-gamma)
|
||||
AM_INIT_AUTOMAKE(mysql, 4.1.6-gamma)
|
||||
AM_CONFIG_HEADER(config.h)
|
||||
|
||||
PROTOCOL_VERSION=10
|
||||
|
|
|
@ -47,6 +47,7 @@ my_bool _hash_init(HASH *hash, CHARSET_INFO *charset,
|
|||
uint key_length, hash_get_key get_key,
|
||||
void (*free_element)(void*), uint flags CALLER_INFO_PROTO);
|
||||
void hash_free(HASH *tree);
|
||||
void hash_reset(HASH *hash);
|
||||
byte *hash_element(HASH *hash,uint idx);
|
||||
gptr hash_search(HASH *info,const byte *key,uint length);
|
||||
gptr hash_next(HASH *info,const byte *key,uint length);
|
||||
|
@ -56,7 +57,6 @@ my_bool hash_update(HASH *hash,byte *record,byte *old_key,uint old_key_length);
|
|||
void hash_replace(HASH *hash, uint idx, byte *new_row);
|
||||
my_bool hash_check(HASH *hash); /* Only in debug library */
|
||||
|
||||
#define hash_clear(H) bzero((char*) (H),sizeof(*(H)))
|
||||
#define hash_inited(H) ((H)->array.buffer != 0)
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
@ -42,6 +42,7 @@ my_bool handle_local_infile(MYSQL *mysql, const char *net_filename);
|
|||
|
||||
void mysql_read_default_options(struct st_mysql_options *options,
|
||||
const char *filename,const char *group);
|
||||
void mysql_detach_stmt_list(LIST **stmt_list);
|
||||
MYSQL * STDCALL
|
||||
cli_mysql_real_connect(MYSQL *mysql,const char *host, const char *user,
|
||||
const char *passwd, const char *db,
|
||||
|
|
|
@ -662,6 +662,7 @@ my_bool STDCALL mysql_change_user(MYSQL *mysql, const char *user,
|
|||
const char *passwd, const char *db)
|
||||
{
|
||||
char buff[512],*end=buff;
|
||||
int rc;
|
||||
DBUG_ENTER("mysql_change_user");
|
||||
|
||||
if (!user)
|
||||
|
@ -695,18 +696,26 @@ my_bool STDCALL mysql_change_user(MYSQL *mysql, const char *user,
|
|||
/* Write authentication package */
|
||||
simple_command(mysql,COM_CHANGE_USER, buff,(ulong) (end-buff),1);
|
||||
|
||||
if ((*mysql->methods->read_change_user_result)(mysql, buff, passwd))
|
||||
DBUG_RETURN(1);
|
||||
/* Free old connect information */
|
||||
my_free(mysql->user,MYF(MY_ALLOW_ZERO_PTR));
|
||||
my_free(mysql->passwd,MYF(MY_ALLOW_ZERO_PTR));
|
||||
my_free(mysql->db,MYF(MY_ALLOW_ZERO_PTR));
|
||||
rc= (*mysql->methods->read_change_user_result)(mysql, buff, passwd);
|
||||
|
||||
/* alloc new connect information */
|
||||
mysql->user= my_strdup(user,MYF(MY_WME));
|
||||
mysql->passwd=my_strdup(passwd,MYF(MY_WME));
|
||||
mysql->db= db ? my_strdup(db,MYF(MY_WME)) : 0;
|
||||
DBUG_RETURN(0);
|
||||
/*
|
||||
The server will close all statements no matter was the attempt
|
||||
to change user successful or not.
|
||||
*/
|
||||
mysql_detach_stmt_list(&mysql->stmts);
|
||||
if (rc == 0)
|
||||
{
|
||||
/* Free old connect information */
|
||||
my_free(mysql->user,MYF(MY_ALLOW_ZERO_PTR));
|
||||
my_free(mysql->passwd,MYF(MY_ALLOW_ZERO_PTR));
|
||||
my_free(mysql->db,MYF(MY_ALLOW_ZERO_PTR));
|
||||
|
||||
/* alloc new connect information */
|
||||
mysql->user= my_strdup(user,MYF(MY_WME));
|
||||
mysql->passwd=my_strdup(passwd,MYF(MY_WME));
|
||||
mysql->db= db ? my_strdup(db,MYF(MY_WME)) : 0;
|
||||
}
|
||||
DBUG_RETURN(rc);
|
||||
}
|
||||
|
||||
#if defined(HAVE_GETPWUID) && defined(NO_GETPWUID_DECL)
|
||||
|
|
|
@ -110,10 +110,10 @@ select a,b from t1 where a=@arg00;
|
|||
set @arg00=NULL;
|
||||
set @arg01=2;
|
||||
execute stmt1 using @arg00, @arg01;
|
||||
select a,b from t1;
|
||||
select a,b from t1 order by a;
|
||||
set @arg00=0;
|
||||
execute stmt1 using @arg01, @arg00;
|
||||
select a,b from t1;
|
||||
select a,b from t1 order by a;
|
||||
|
||||
## update with subquery and several parameters
|
||||
set @arg00=23;
|
||||
|
@ -134,7 +134,7 @@ prepare stmt1 from 'update t1 set a=? where b=?
|
|||
and a not in (select ? from t2
|
||||
where b = ? or a = ?)';
|
||||
execute stmt1 using @arg04, @arg01, @arg02, @arg03, @arg00 ;
|
||||
select a,b from t1 ;
|
||||
select a,b from t1 order by a;
|
||||
drop table t2 ;
|
||||
|
||||
## update with parameters in limit
|
||||
|
@ -202,7 +202,7 @@ set @arg01=1 ;
|
|||
prepare stmt1 from 'insert into t1 set a=?, b=''sechs''
|
||||
on duplicate key update a=a + ?, b=concat(b,''modified'') ';
|
||||
execute stmt1 using @arg00, @arg01;
|
||||
select * from t1;
|
||||
select * from t1 order by a;
|
||||
set @arg00=81 ;
|
||||
set @arg01=1 ;
|
||||
--error 1062
|
||||
|
@ -221,17 +221,17 @@ set @updated="updated" ;
|
|||
insert into t1 values(1000,'x1000_1') ;
|
||||
insert into t1 values(@1000,@x1000_2),(@1000,@x1000_3)
|
||||
on duplicate key update a = a + @100, b = concat(b,@updated) ;
|
||||
select a,b from t1 where a >= 1000 ;
|
||||
select a,b from t1 where a >= 1000 order by a ;
|
||||
delete from t1 where a >= 1000 ;
|
||||
insert into t1 values(1000,'x1000_1') ;
|
||||
prepare stmt1 from ' insert into t1 values(?,?),(?,?)
|
||||
on duplicate key update a = a + ?, b = concat(b,?) ';
|
||||
execute stmt1 using @1000, @x1000_2, @1000, @x1000_3, @100, @updated ;
|
||||
select a,b from t1 where a >= 1000 ;
|
||||
select a,b from t1 where a >= 1000 order by a ;
|
||||
delete from t1 where a >= 1000 ;
|
||||
insert into t1 values(1000,'x1000_1') ;
|
||||
execute stmt1 using @1000, @x1000_2, @1100, @x1000_3, @100, @updated ;
|
||||
select a,b from t1 where a >= 1000 ;
|
||||
select a,b from t1 where a >= 1000 order by a ;
|
||||
delete from t1 where a >= 1000 ;
|
||||
|
||||
## replace
|
||||
|
|
|
@ -45,19 +45,19 @@
|
|||
set @duplicate='duplicate ' ;
|
||||
set @1000=1000 ;
|
||||
set @5=5 ;
|
||||
select a,b from t1 where a < 5 ;
|
||||
select a,b from t1 where a < 5 order by a ;
|
||||
--enable_info
|
||||
insert into t1 select a + @1000, concat(@duplicate,b) from t1
|
||||
where a < @5 ;
|
||||
--disable_info
|
||||
select a,b from t1 where a >= 1000 ;
|
||||
select a,b from t1 where a >= 1000 order by a ;
|
||||
delete from t1 where a >= 1000 ;
|
||||
prepare stmt1 from ' insert into t1 select a + ?, concat(?,b) from t1
|
||||
where a < ? ' ;
|
||||
--enable_info
|
||||
execute stmt1 using @1000, @duplicate, @5;
|
||||
--disable_info
|
||||
select a,b from t1 where a >= 1000 ;
|
||||
select a,b from t1 where a >= 1000 order by a ;
|
||||
delete from t1 where a >= 1000 ;
|
||||
|
||||
set @float=1.00;
|
||||
|
@ -78,7 +78,7 @@ select b, a + @100 from t1
|
|||
where (a,b) in ( select sqrt(a+@1)+CAST(@float AS signed),b
|
||||
from t1);
|
||||
--disable_info
|
||||
select a,b from t2;
|
||||
select a,b from t2 order by a ;
|
||||
delete from t2 ;
|
||||
prepare stmt1 from ' insert into t2 (b,a)
|
||||
select ?, sum(first.a)
|
||||
|
@ -93,5 +93,5 @@ select b, a + ? from t1
|
|||
--enable_info
|
||||
execute stmt1 using @duplicate, @5, @five, @2, @100, @1, @float ;
|
||||
--disable_info
|
||||
select a,b from t2;
|
||||
select a,b from t2 order by a ;
|
||||
drop table t2;
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -420,6 +420,9 @@ INSERT INTO t1 VALUES
|
|||
(1,1,1),(2,2,2),(3,3,3),(4,4,4),(5,5,5),
|
||||
(6,6,6),(7,7,7),(8,8,8),(9,9,9),(10,10,10);
|
||||
ERROR 23000: Duplicate entry '10' for key 1
|
||||
select count(*) from t1;
|
||||
count(*)
|
||||
2000
|
||||
begin;
|
||||
SELECT COUNT(*) FROM t1;
|
||||
COUNT(*)
|
||||
|
@ -429,17 +432,128 @@ INSERT INTO t1 VALUES
|
|||
SELECT COUNT(*) FROM t1;
|
||||
COUNT(*)
|
||||
2005
|
||||
rollback;
|
||||
begin;
|
||||
INSERT INTO t1 VALUES
|
||||
(1,1,1),(2,2,2),(3,3,3),(4,4,4),(5,5,5),
|
||||
(6,6,6),(7,7,7),(8,8,8),(9,9,9),(10,10,10);
|
||||
ERROR 23000: Duplicate entry '10' for key 1
|
||||
SELECT COUNT(*) FROM t1;
|
||||
COUNT(*)
|
||||
2000
|
||||
commit;
|
||||
SELECT COUNT(*) FROM t1;
|
||||
COUNT(*)
|
||||
ERROR HY000: Got error 4350 'Transaction already aborted' from ndbcluster
|
||||
select * from t1 where pk1=1;
|
||||
pk1 b c
|
||||
1 1 1
|
||||
select * from t1 where pk1=10;
|
||||
pk1 b c
|
||||
10 10 10
|
||||
select count(*) from t1 where pk1 <= 10 order by pk1;
|
||||
count(*)
|
||||
11
|
||||
select count(*) from t1;
|
||||
count(*)
|
||||
2000
|
||||
begin;
|
||||
INSERT INTO t1 VALUES
|
||||
(1,1,1),(2,2,2),(3,3,3),(4,4,4),(5,5,5),
|
||||
(6,6,6),(7,7,7),(8,8,8),(9,9,9),(10,10,10);
|
||||
ERROR 23000: Duplicate entry '10' for key 1
|
||||
rollback;
|
||||
select * from t1 where pk1=1;
|
||||
pk1 b c
|
||||
1 1 1
|
||||
select * from t1 where pk1=10;
|
||||
pk1 b c
|
||||
10 10 10
|
||||
select count(*) from t1 where pk1 <= 10 order by pk1;
|
||||
count(*)
|
||||
11
|
||||
select count(*) from t1;
|
||||
count(*)
|
||||
2000
|
||||
begin;
|
||||
INSERT INTO t1 VALUES
|
||||
(1,1,1),(2,2,2),(3,3,3),(4,4,4),(5,5,5),
|
||||
(6,6,6),(7,7,7),(8,8,8),(9,9,9),(10,10,10);
|
||||
ERROR 23000: Duplicate entry '10' for key 1
|
||||
SELECT * FROM t1 WHERE pk1=10;
|
||||
ERROR HY000: Got error 4350 'Transaction already aborted' from ndbcluster
|
||||
rollback;
|
||||
select * from t1 where pk1=1;
|
||||
pk1 b c
|
||||
1 1 1
|
||||
select * from t1 where pk1=10;
|
||||
pk1 b c
|
||||
10 10 10
|
||||
select count(*) from t1 where pk1 <= 10 order by pk1;
|
||||
count(*)
|
||||
11
|
||||
select count(*) from t1;
|
||||
count(*)
|
||||
2000
|
||||
begin;
|
||||
INSERT INTO t1 VALUES
|
||||
(1,1,1),(2,2,2),(3,3,3),(4,4,4),(5,5,5),
|
||||
(6,6,6),(7,7,7),(8,8,8),(9,9,9),(10,10,10);
|
||||
ERROR 23000: Duplicate entry '10' for key 1
|
||||
SELECT * FROM t1 WHERE pk1=10;
|
||||
ERROR HY000: Got error 4350 'Transaction already aborted' from ndbcluster
|
||||
SELECT * FROM t1 WHERE pk1=10;
|
||||
ERROR HY000: Got error 4350 'Transaction already aborted' from ndbcluster
|
||||
commit;
|
||||
ERROR HY000: Got error 4350 'Transaction already aborted' from ndbcluster
|
||||
select * from t1 where pk1=1;
|
||||
pk1 b c
|
||||
1 1 1
|
||||
select * from t1 where pk1=10;
|
||||
pk1 b c
|
||||
10 10 10
|
||||
select count(*) from t1 where pk1 <= 10 order by pk1;
|
||||
count(*)
|
||||
11
|
||||
select count(*) from t1;
|
||||
count(*)
|
||||
2000
|
||||
begin;
|
||||
INSERT INTO t1 VALUES
|
||||
(1,1,1),(2,2,2),(3,3,3),(4,4,4),(5,5,5),
|
||||
(6,6,6),(7,7,7),(8,8,8),(9,9,9),(10,10,10);
|
||||
ERROR 23000: Duplicate entry '10' for key 1
|
||||
INSERT INTO t1 values (4000, 40, 44);
|
||||
ERROR HY000: Got error 4350 'Transaction already aborted' from ndbcluster
|
||||
rollback;
|
||||
select * from t1 where pk1=1;
|
||||
pk1 b c
|
||||
1 1 1
|
||||
select * from t1 where pk1=10;
|
||||
pk1 b c
|
||||
10 10 10
|
||||
select count(*) from t1 where pk1 <= 10 order by pk1;
|
||||
count(*)
|
||||
11
|
||||
select count(*) from t1;
|
||||
count(*)
|
||||
2000
|
||||
insert into t1 select * from t1 where b < 10 order by pk1;
|
||||
ERROR 23000: Duplicate entry '9' for key 1
|
||||
begin;
|
||||
INSERT IGNORE INTO t1 VALUES(1,2,3);
|
||||
ERROR HY000: Table storage engine for 't1' doesn't have this option
|
||||
commit;
|
||||
select * from t1 where pk1=1;
|
||||
pk1 b c
|
||||
1 1 1
|
||||
INSERT IGNORE INTO t1 VALUES(1,2,3);
|
||||
ERROR HY000: Table storage engine for 't1' doesn't have this option
|
||||
select * from t1 where pk1=1;
|
||||
pk1 b c
|
||||
1 1 1
|
||||
REPLACE INTO t1 values(1, 2, 3);
|
||||
select * from t1 where pk1=1;
|
||||
pk1 b c
|
||||
1 2 3
|
||||
INSERT INTO t1 VALUES(1,1,1) ON DUPLICATE KEY UPDATE b=79;
|
||||
ERROR HY000: Table storage engine for 't1' doesn't have this option
|
||||
select * from t1 where pk1=1;
|
||||
pk1 b c
|
||||
1 2 3
|
||||
DROP TABLE t1;
|
||||
|
|
|
@ -1016,15 +1016,15 @@ set @arg01=2;
|
|||
execute stmt1 using @arg00, @arg01;
|
||||
Warnings:
|
||||
Warning 1263 Data truncated; NULL supplied to NOT NULL column 'a' at row 1
|
||||
select a,b from t1;
|
||||
select a,b from t1 order by a;
|
||||
a b
|
||||
1 one
|
||||
0 two
|
||||
1 one
|
||||
3 three
|
||||
4 four
|
||||
set @arg00=0;
|
||||
execute stmt1 using @arg01, @arg00;
|
||||
select a,b from t1;
|
||||
select a,b from t1 order by a;
|
||||
a b
|
||||
1 one
|
||||
2 two
|
||||
|
@ -1048,7 +1048,7 @@ prepare stmt1 from 'update t1 set a=? where b=?
|
|||
and a not in (select ? from t2
|
||||
where b = ? or a = ?)';
|
||||
execute stmt1 using @arg04, @arg01, @arg02, @arg03, @arg00 ;
|
||||
select a,b from t1 ;
|
||||
select a,b from t1 order by a;
|
||||
a b
|
||||
1 one
|
||||
2 two
|
||||
|
@ -1142,19 +1142,19 @@ set @arg01=1 ;
|
|||
prepare stmt1 from 'insert into t1 set a=?, b=''sechs''
|
||||
on duplicate key update a=a + ?, b=concat(b,''modified'') ';
|
||||
execute stmt1 using @arg00, @arg01;
|
||||
select * from t1;
|
||||
select * from t1 order by a;
|
||||
a b
|
||||
0 NULL
|
||||
1 one
|
||||
2 two
|
||||
3 three
|
||||
4 four
|
||||
5 five
|
||||
7 sixmodified
|
||||
0 NULL
|
||||
8 eight
|
||||
9 nine
|
||||
81 8-1
|
||||
82 8-2
|
||||
9 nine
|
||||
set @arg00=81 ;
|
||||
set @arg01=1 ;
|
||||
execute stmt1 using @arg00, @arg01;
|
||||
|
@ -1170,7 +1170,7 @@ set @updated="updated" ;
|
|||
insert into t1 values(1000,'x1000_1') ;
|
||||
insert into t1 values(@1000,@x1000_2),(@1000,@x1000_3)
|
||||
on duplicate key update a = a + @100, b = concat(b,@updated) ;
|
||||
select a,b from t1 where a >= 1000 ;
|
||||
select a,b from t1 where a >= 1000 order by a ;
|
||||
a b
|
||||
1000 x1000_3
|
||||
1100 x1000_1updated
|
||||
|
@ -1179,14 +1179,14 @@ insert into t1 values(1000,'x1000_1') ;
|
|||
prepare stmt1 from ' insert into t1 values(?,?),(?,?)
|
||||
on duplicate key update a = a + ?, b = concat(b,?) ';
|
||||
execute stmt1 using @1000, @x1000_2, @1000, @x1000_3, @100, @updated ;
|
||||
select a,b from t1 where a >= 1000 ;
|
||||
select a,b from t1 where a >= 1000 order by a ;
|
||||
a b
|
||||
1000 x1000_3
|
||||
1100 x1000_1updated
|
||||
delete from t1 where a >= 1000 ;
|
||||
insert into t1 values(1000,'x1000_1') ;
|
||||
execute stmt1 using @1000, @x1000_2, @1100, @x1000_3, @100, @updated ;
|
||||
select a,b from t1 where a >= 1000 ;
|
||||
select a,b from t1 where a >= 1000 order by a ;
|
||||
a b
|
||||
1200 x1000_1updatedupdated
|
||||
delete from t1 where a >= 1000 ;
|
||||
|
@ -1195,37 +1195,37 @@ ERROR HY000: This command is not supported in the prepared statement protocol ye
|
|||
set @duplicate='duplicate ' ;
|
||||
set @1000=1000 ;
|
||||
set @5=5 ;
|
||||
select a,b from t1 where a < 5 ;
|
||||
select a,b from t1 where a < 5 order by a ;
|
||||
a b
|
||||
0 NULL
|
||||
1 one
|
||||
2 two
|
||||
3 three
|
||||
4 four
|
||||
0 NULL
|
||||
insert into t1 select a + @1000, concat(@duplicate,b) from t1
|
||||
where a < @5 ;
|
||||
affected rows: 5
|
||||
info: Records: 5 Duplicates: 0 Warnings: 0
|
||||
select a,b from t1 where a >= 1000 ;
|
||||
select a,b from t1 where a >= 1000 order by a ;
|
||||
a b
|
||||
1000 NULL
|
||||
1001 duplicate one
|
||||
1002 duplicate two
|
||||
1003 duplicate three
|
||||
1004 duplicate four
|
||||
1000 NULL
|
||||
delete from t1 where a >= 1000 ;
|
||||
prepare stmt1 from ' insert into t1 select a + ?, concat(?,b) from t1
|
||||
where a < ? ' ;
|
||||
execute stmt1 using @1000, @duplicate, @5;
|
||||
affected rows: 5
|
||||
info: Records: 5 Duplicates: 0 Warnings: 0
|
||||
select a,b from t1 where a >= 1000 ;
|
||||
select a,b from t1 where a >= 1000 order by a ;
|
||||
a b
|
||||
1004 duplicate four
|
||||
1003 duplicate three
|
||||
1002 duplicate two
|
||||
1001 duplicate one
|
||||
1000 NULL
|
||||
1001 duplicate one
|
||||
1002 duplicate two
|
||||
1003 duplicate three
|
||||
1004 duplicate four
|
||||
delete from t1 where a >= 1000 ;
|
||||
set @float=1.00;
|
||||
set @five='five' ;
|
||||
|
@ -1243,15 +1243,15 @@ where (a,b) in ( select sqrt(a+@1)+CAST(@float AS signed),b
|
|||
from t1);
|
||||
affected rows: 8
|
||||
info: Records: 8 Duplicates: 0 Warnings: 0
|
||||
select a,b from t2;
|
||||
select a,b from t2 order by a ;
|
||||
a b
|
||||
3 duplicate
|
||||
4 duplicate
|
||||
7 duplicate
|
||||
8 duplicate
|
||||
9 duplicate
|
||||
81 duplicate
|
||||
82 duplicate
|
||||
8 duplicate
|
||||
4 duplicate
|
||||
9 duplicate
|
||||
7 duplicate
|
||||
3 duplicate
|
||||
103 three
|
||||
delete from t2 ;
|
||||
prepare stmt1 from ' insert into t2 (b,a)
|
||||
|
@ -1267,15 +1267,15 @@ select b, a + ? from t1
|
|||
execute stmt1 using @duplicate, @5, @five, @2, @100, @1, @float ;
|
||||
affected rows: 8
|
||||
info: Records: 8 Duplicates: 0 Warnings: 0
|
||||
select a,b from t2;
|
||||
select a,b from t2 order by a ;
|
||||
a b
|
||||
3 duplicate
|
||||
4 duplicate
|
||||
7 duplicate
|
||||
8 duplicate
|
||||
9 duplicate
|
||||
81 duplicate
|
||||
82 duplicate
|
||||
8 duplicate
|
||||
4 duplicate
|
||||
9 duplicate
|
||||
7 duplicate
|
||||
3 duplicate
|
||||
103 three
|
||||
drop table t2;
|
||||
drop table t1, t_many_col_types;
|
||||
|
|
|
@ -1016,7 +1016,7 @@ set @arg01=2;
|
|||
execute stmt1 using @arg00, @arg01;
|
||||
Warnings:
|
||||
Warning 1263 Data truncated; NULL supplied to NOT NULL column 'a' at row 1
|
||||
select a,b from t1;
|
||||
select a,b from t1 order by a;
|
||||
a b
|
||||
0 two
|
||||
1 one
|
||||
|
@ -1024,7 +1024,7 @@ a b
|
|||
4 four
|
||||
set @arg00=0;
|
||||
execute stmt1 using @arg01, @arg00;
|
||||
select a,b from t1;
|
||||
select a,b from t1 order by a;
|
||||
a b
|
||||
1 one
|
||||
2 two
|
||||
|
@ -1048,7 +1048,7 @@ prepare stmt1 from 'update t1 set a=? where b=?
|
|||
and a not in (select ? from t2
|
||||
where b = ? or a = ?)';
|
||||
execute stmt1 using @arg04, @arg01, @arg02, @arg03, @arg00 ;
|
||||
select a,b from t1 ;
|
||||
select a,b from t1 order by a;
|
||||
a b
|
||||
1 one
|
||||
2 two
|
||||
|
@ -1142,7 +1142,7 @@ set @arg01=1 ;
|
|||
prepare stmt1 from 'insert into t1 set a=?, b=''sechs''
|
||||
on duplicate key update a=a + ?, b=concat(b,''modified'') ';
|
||||
execute stmt1 using @arg00, @arg01;
|
||||
select * from t1;
|
||||
select * from t1 order by a;
|
||||
a b
|
||||
0 NULL
|
||||
1 one
|
||||
|
@ -1170,7 +1170,7 @@ set @updated="updated" ;
|
|||
insert into t1 values(1000,'x1000_1') ;
|
||||
insert into t1 values(@1000,@x1000_2),(@1000,@x1000_3)
|
||||
on duplicate key update a = a + @100, b = concat(b,@updated) ;
|
||||
select a,b from t1 where a >= 1000 ;
|
||||
select a,b from t1 where a >= 1000 order by a ;
|
||||
a b
|
||||
1000 x1000_3
|
||||
1100 x1000_1updated
|
||||
|
@ -1179,14 +1179,14 @@ insert into t1 values(1000,'x1000_1') ;
|
|||
prepare stmt1 from ' insert into t1 values(?,?),(?,?)
|
||||
on duplicate key update a = a + ?, b = concat(b,?) ';
|
||||
execute stmt1 using @1000, @x1000_2, @1000, @x1000_3, @100, @updated ;
|
||||
select a,b from t1 where a >= 1000 ;
|
||||
select a,b from t1 where a >= 1000 order by a ;
|
||||
a b
|
||||
1000 x1000_3
|
||||
1100 x1000_1updated
|
||||
delete from t1 where a >= 1000 ;
|
||||
insert into t1 values(1000,'x1000_1') ;
|
||||
execute stmt1 using @1000, @x1000_2, @1100, @x1000_3, @100, @updated ;
|
||||
select a,b from t1 where a >= 1000 ;
|
||||
select a,b from t1 where a >= 1000 order by a ;
|
||||
a b
|
||||
1200 x1000_1updatedupdated
|
||||
delete from t1 where a >= 1000 ;
|
||||
|
@ -1195,7 +1195,7 @@ ERROR HY000: This command is not supported in the prepared statement protocol ye
|
|||
set @duplicate='duplicate ' ;
|
||||
set @1000=1000 ;
|
||||
set @5=5 ;
|
||||
select a,b from t1 where a < 5 ;
|
||||
select a,b from t1 where a < 5 order by a ;
|
||||
a b
|
||||
0 NULL
|
||||
1 one
|
||||
|
@ -1206,7 +1206,7 @@ insert into t1 select a + @1000, concat(@duplicate,b) from t1
|
|||
where a < @5 ;
|
||||
affected rows: 5
|
||||
info: Records: 5 Duplicates: 0 Warnings: 0
|
||||
select a,b from t1 where a >= 1000 ;
|
||||
select a,b from t1 where a >= 1000 order by a ;
|
||||
a b
|
||||
1000 NULL
|
||||
1001 duplicate one
|
||||
|
@ -1219,7 +1219,7 @@ where a < ? ' ;
|
|||
execute stmt1 using @1000, @duplicate, @5;
|
||||
affected rows: 5
|
||||
info: Records: 5 Duplicates: 0 Warnings: 0
|
||||
select a,b from t1 where a >= 1000 ;
|
||||
select a,b from t1 where a >= 1000 order by a ;
|
||||
a b
|
||||
1000 NULL
|
||||
1001 duplicate one
|
||||
|
@ -1243,7 +1243,7 @@ where (a,b) in ( select sqrt(a+@1)+CAST(@float AS signed),b
|
|||
from t1);
|
||||
affected rows: 8
|
||||
info: Records: 8 Duplicates: 0 Warnings: 0
|
||||
select a,b from t2;
|
||||
select a,b from t2 order by a ;
|
||||
a b
|
||||
3 duplicate
|
||||
4 duplicate
|
||||
|
@ -1267,7 +1267,7 @@ select b, a + ? from t1
|
|||
execute stmt1 using @duplicate, @5, @five, @2, @100, @1, @float ;
|
||||
affected rows: 8
|
||||
info: Records: 8 Duplicates: 0 Warnings: 0
|
||||
select a,b from t2;
|
||||
select a,b from t2 order by a ;
|
||||
a b
|
||||
3 duplicate
|
||||
4 duplicate
|
||||
|
|
|
@ -1017,15 +1017,15 @@ set @arg01=2;
|
|||
execute stmt1 using @arg00, @arg01;
|
||||
Warnings:
|
||||
Warning 1263 Data truncated; NULL supplied to NOT NULL column 'a' at row 1
|
||||
select a,b from t1;
|
||||
select a,b from t1 order by a;
|
||||
a b
|
||||
1 one
|
||||
0 two
|
||||
1 one
|
||||
3 three
|
||||
4 four
|
||||
set @arg00=0;
|
||||
execute stmt1 using @arg01, @arg00;
|
||||
select a,b from t1;
|
||||
select a,b from t1 order by a;
|
||||
a b
|
||||
1 one
|
||||
2 two
|
||||
|
@ -1049,7 +1049,7 @@ prepare stmt1 from 'update t1 set a=? where b=?
|
|||
and a not in (select ? from t2
|
||||
where b = ? or a = ?)';
|
||||
execute stmt1 using @arg04, @arg01, @arg02, @arg03, @arg00 ;
|
||||
select a,b from t1 ;
|
||||
select a,b from t1 order by a;
|
||||
a b
|
||||
1 one
|
||||
2 two
|
||||
|
@ -1143,19 +1143,19 @@ set @arg01=1 ;
|
|||
prepare stmt1 from 'insert into t1 set a=?, b=''sechs''
|
||||
on duplicate key update a=a + ?, b=concat(b,''modified'') ';
|
||||
execute stmt1 using @arg00, @arg01;
|
||||
select * from t1;
|
||||
select * from t1 order by a;
|
||||
a b
|
||||
0 NULL
|
||||
1 one
|
||||
2 two
|
||||
3 three
|
||||
4 four
|
||||
5 five
|
||||
7 sixmodified
|
||||
0 NULL
|
||||
8 eight
|
||||
9 nine
|
||||
81 8-1
|
||||
82 8-2
|
||||
9 nine
|
||||
set @arg00=81 ;
|
||||
set @arg01=1 ;
|
||||
execute stmt1 using @arg00, @arg01;
|
||||
|
@ -1171,23 +1171,23 @@ set @updated="updated" ;
|
|||
insert into t1 values(1000,'x1000_1') ;
|
||||
insert into t1 values(@1000,@x1000_2),(@1000,@x1000_3)
|
||||
on duplicate key update a = a + @100, b = concat(b,@updated) ;
|
||||
select a,b from t1 where a >= 1000 ;
|
||||
select a,b from t1 where a >= 1000 order by a ;
|
||||
a b
|
||||
1100 x1000_1updated
|
||||
1000 x1000_3
|
||||
1100 x1000_1updated
|
||||
delete from t1 where a >= 1000 ;
|
||||
insert into t1 values(1000,'x1000_1') ;
|
||||
prepare stmt1 from ' insert into t1 values(?,?),(?,?)
|
||||
on duplicate key update a = a + ?, b = concat(b,?) ';
|
||||
execute stmt1 using @1000, @x1000_2, @1000, @x1000_3, @100, @updated ;
|
||||
select a,b from t1 where a >= 1000 ;
|
||||
select a,b from t1 where a >= 1000 order by a ;
|
||||
a b
|
||||
1000 x1000_3
|
||||
1100 x1000_1updated
|
||||
delete from t1 where a >= 1000 ;
|
||||
insert into t1 values(1000,'x1000_1') ;
|
||||
execute stmt1 using @1000, @x1000_2, @1100, @x1000_3, @100, @updated ;
|
||||
select a,b from t1 where a >= 1000 ;
|
||||
select a,b from t1 where a >= 1000 order by a ;
|
||||
a b
|
||||
1200 x1000_1updatedupdated
|
||||
delete from t1 where a >= 1000 ;
|
||||
|
@ -1196,37 +1196,37 @@ ERROR HY000: This command is not supported in the prepared statement protocol ye
|
|||
set @duplicate='duplicate ' ;
|
||||
set @1000=1000 ;
|
||||
set @5=5 ;
|
||||
select a,b from t1 where a < 5 ;
|
||||
select a,b from t1 where a < 5 order by a ;
|
||||
a b
|
||||
0 NULL
|
||||
1 one
|
||||
2 two
|
||||
3 three
|
||||
4 four
|
||||
0 NULL
|
||||
insert into t1 select a + @1000, concat(@duplicate,b) from t1
|
||||
where a < @5 ;
|
||||
affected rows: 5
|
||||
info: Records: 5 Duplicates: 0 Warnings: 0
|
||||
select a,b from t1 where a >= 1000 ;
|
||||
select a,b from t1 where a >= 1000 order by a ;
|
||||
a b
|
||||
1002 duplicate two
|
||||
1000 NULL
|
||||
1001 duplicate one
|
||||
1002 duplicate two
|
||||
1003 duplicate three
|
||||
1004 duplicate four
|
||||
1000 NULL
|
||||
delete from t1 where a >= 1000 ;
|
||||
prepare stmt1 from ' insert into t1 select a + ?, concat(?,b) from t1
|
||||
where a < ? ' ;
|
||||
execute stmt1 using @1000, @duplicate, @5;
|
||||
affected rows: 5
|
||||
info: Records: 5 Duplicates: 0 Warnings: 0
|
||||
select a,b from t1 where a >= 1000 ;
|
||||
select a,b from t1 where a >= 1000 order by a ;
|
||||
a b
|
||||
1000 NULL
|
||||
1004 duplicate four
|
||||
1003 duplicate three
|
||||
1002 duplicate two
|
||||
1001 duplicate one
|
||||
1002 duplicate two
|
||||
1003 duplicate three
|
||||
1004 duplicate four
|
||||
delete from t1 where a >= 1000 ;
|
||||
set @float=1.00;
|
||||
set @five='five' ;
|
||||
|
@ -1244,15 +1244,15 @@ where (a,b) in ( select sqrt(a+@1)+CAST(@float AS signed),b
|
|||
from t1);
|
||||
affected rows: 8
|
||||
info: Records: 8 Duplicates: 0 Warnings: 0
|
||||
select a,b from t2;
|
||||
select a,b from t2 order by a ;
|
||||
a b
|
||||
3 duplicate
|
||||
4 duplicate
|
||||
7 duplicate
|
||||
8 duplicate
|
||||
9 duplicate
|
||||
81 duplicate
|
||||
82 duplicate
|
||||
8 duplicate
|
||||
4 duplicate
|
||||
9 duplicate
|
||||
7 duplicate
|
||||
3 duplicate
|
||||
103 three
|
||||
delete from t2 ;
|
||||
prepare stmt1 from ' insert into t2 (b,a)
|
||||
|
@ -1268,15 +1268,15 @@ select b, a + ? from t1
|
|||
execute stmt1 using @duplicate, @5, @five, @2, @100, @1, @float ;
|
||||
affected rows: 8
|
||||
info: Records: 8 Duplicates: 0 Warnings: 0
|
||||
select a,b from t2;
|
||||
select a,b from t2 order by a ;
|
||||
a b
|
||||
3 duplicate
|
||||
4 duplicate
|
||||
7 duplicate
|
||||
8 duplicate
|
||||
9 duplicate
|
||||
81 duplicate
|
||||
82 duplicate
|
||||
8 duplicate
|
||||
4 duplicate
|
||||
9 duplicate
|
||||
7 duplicate
|
||||
3 duplicate
|
||||
103 three
|
||||
drop table t2;
|
||||
drop table t1, t_many_col_types;
|
||||
|
|
|
@ -1059,19 +1059,19 @@ set @arg01=2;
|
|||
execute stmt1 using @arg00, @arg01;
|
||||
Warnings:
|
||||
Warning 1263 Data truncated; NULL supplied to NOT NULL column 'a' at row 1
|
||||
select a,b from t1;
|
||||
select a,b from t1 order by a;
|
||||
a b
|
||||
3 three
|
||||
0 two
|
||||
1 one
|
||||
3 three
|
||||
4 four
|
||||
set @arg00=0;
|
||||
execute stmt1 using @arg01, @arg00;
|
||||
select a,b from t1;
|
||||
select a,b from t1 order by a;
|
||||
a b
|
||||
3 three
|
||||
2 two
|
||||
1 one
|
||||
2 two
|
||||
3 three
|
||||
4 four
|
||||
set @arg00=23;
|
||||
set @arg01='two';
|
||||
|
@ -1091,11 +1091,11 @@ prepare stmt1 from 'update t1 set a=? where b=?
|
|||
and a not in (select ? from t2
|
||||
where b = ? or a = ?)';
|
||||
execute stmt1 using @arg04, @arg01, @arg02, @arg03, @arg00 ;
|
||||
select a,b from t1 ;
|
||||
select a,b from t1 order by a;
|
||||
a b
|
||||
3 three
|
||||
2 two
|
||||
1 one
|
||||
2 two
|
||||
3 three
|
||||
4 four
|
||||
drop table t2 ;
|
||||
set @arg00=1;
|
||||
|
@ -1185,19 +1185,19 @@ set @arg01=1 ;
|
|||
prepare stmt1 from 'insert into t1 set a=?, b=''sechs''
|
||||
on duplicate key update a=a + ?, b=concat(b,''modified'') ';
|
||||
execute stmt1 using @arg00, @arg01;
|
||||
select * from t1;
|
||||
select * from t1 order by a;
|
||||
a b
|
||||
4 four
|
||||
3 three
|
||||
2 two
|
||||
0 NULL
|
||||
1 one
|
||||
2 two
|
||||
3 three
|
||||
4 four
|
||||
5 five
|
||||
7 sixmodified
|
||||
0 NULL
|
||||
8 eight
|
||||
9 nine
|
||||
81 8-1
|
||||
82 8-2
|
||||
9 nine
|
||||
set @arg00=81 ;
|
||||
set @arg01=1 ;
|
||||
execute stmt1 using @arg00, @arg01;
|
||||
|
@ -1213,7 +1213,7 @@ set @updated="updated" ;
|
|||
insert into t1 values(1000,'x1000_1') ;
|
||||
insert into t1 values(@1000,@x1000_2),(@1000,@x1000_3)
|
||||
on duplicate key update a = a + @100, b = concat(b,@updated) ;
|
||||
select a,b from t1 where a >= 1000 ;
|
||||
select a,b from t1 where a >= 1000 order by a ;
|
||||
a b
|
||||
1000 x1000_3
|
||||
1100 x1000_1updated
|
||||
|
@ -1222,14 +1222,14 @@ insert into t1 values(1000,'x1000_1') ;
|
|||
prepare stmt1 from ' insert into t1 values(?,?),(?,?)
|
||||
on duplicate key update a = a + ?, b = concat(b,?) ';
|
||||
execute stmt1 using @1000, @x1000_2, @1000, @x1000_3, @100, @updated ;
|
||||
select a,b from t1 where a >= 1000 ;
|
||||
select a,b from t1 where a >= 1000 order by a ;
|
||||
a b
|
||||
1000 x1000_3
|
||||
1100 x1000_1updated
|
||||
delete from t1 where a >= 1000 ;
|
||||
insert into t1 values(1000,'x1000_1') ;
|
||||
execute stmt1 using @1000, @x1000_2, @1100, @x1000_3, @100, @updated ;
|
||||
select a,b from t1 where a >= 1000 ;
|
||||
select a,b from t1 where a >= 1000 order by a ;
|
||||
a b
|
||||
1200 x1000_1updatedupdated
|
||||
delete from t1 where a >= 1000 ;
|
||||
|
@ -2254,19 +2254,19 @@ set @arg01=2;
|
|||
execute stmt1 using @arg00, @arg01;
|
||||
Warnings:
|
||||
Warning 1263 Data truncated; NULL supplied to NOT NULL column 'a' at row 1
|
||||
select a,b from t1;
|
||||
select a,b from t1 order by a;
|
||||
a b
|
||||
3 three
|
||||
0 two
|
||||
1 one
|
||||
3 three
|
||||
4 four
|
||||
set @arg00=0;
|
||||
execute stmt1 using @arg01, @arg00;
|
||||
select a,b from t1;
|
||||
select a,b from t1 order by a;
|
||||
a b
|
||||
3 three
|
||||
2 two
|
||||
1 one
|
||||
2 two
|
||||
3 three
|
||||
4 four
|
||||
set @arg00=23;
|
||||
set @arg01='two';
|
||||
|
@ -2286,11 +2286,11 @@ prepare stmt1 from 'update t1 set a=? where b=?
|
|||
and a not in (select ? from t2
|
||||
where b = ? or a = ?)';
|
||||
execute stmt1 using @arg04, @arg01, @arg02, @arg03, @arg00 ;
|
||||
select a,b from t1 ;
|
||||
select a,b from t1 order by a;
|
||||
a b
|
||||
3 three
|
||||
2 two
|
||||
1 one
|
||||
2 two
|
||||
3 three
|
||||
4 four
|
||||
drop table t2 ;
|
||||
set @arg00=1;
|
||||
|
@ -2380,19 +2380,19 @@ set @arg01=1 ;
|
|||
prepare stmt1 from 'insert into t1 set a=?, b=''sechs''
|
||||
on duplicate key update a=a + ?, b=concat(b,''modified'') ';
|
||||
execute stmt1 using @arg00, @arg01;
|
||||
select * from t1;
|
||||
select * from t1 order by a;
|
||||
a b
|
||||
4 four
|
||||
3 three
|
||||
2 two
|
||||
0 NULL
|
||||
1 one
|
||||
2 two
|
||||
3 three
|
||||
4 four
|
||||
5 five
|
||||
7 sixmodified
|
||||
0 NULL
|
||||
8 eight
|
||||
9 nine
|
||||
81 8-1
|
||||
82 8-2
|
||||
9 nine
|
||||
set @arg00=81 ;
|
||||
set @arg01=1 ;
|
||||
execute stmt1 using @arg00, @arg01;
|
||||
|
@ -2408,7 +2408,7 @@ set @updated="updated" ;
|
|||
insert into t1 values(1000,'x1000_1') ;
|
||||
insert into t1 values(@1000,@x1000_2),(@1000,@x1000_3)
|
||||
on duplicate key update a = a + @100, b = concat(b,@updated) ;
|
||||
select a,b from t1 where a >= 1000 ;
|
||||
select a,b from t1 where a >= 1000 order by a ;
|
||||
a b
|
||||
1000 x1000_3
|
||||
1100 x1000_1updated
|
||||
|
@ -2417,14 +2417,14 @@ insert into t1 values(1000,'x1000_1') ;
|
|||
prepare stmt1 from ' insert into t1 values(?,?),(?,?)
|
||||
on duplicate key update a = a + ?, b = concat(b,?) ';
|
||||
execute stmt1 using @1000, @x1000_2, @1000, @x1000_3, @100, @updated ;
|
||||
select a,b from t1 where a >= 1000 ;
|
||||
select a,b from t1 where a >= 1000 order by a ;
|
||||
a b
|
||||
1000 x1000_3
|
||||
1100 x1000_1updated
|
||||
delete from t1 where a >= 1000 ;
|
||||
insert into t1 values(1000,'x1000_1') ;
|
||||
execute stmt1 using @1000, @x1000_2, @1100, @x1000_3, @100, @updated ;
|
||||
select a,b from t1 where a >= 1000 ;
|
||||
select a,b from t1 where a >= 1000 order by a ;
|
||||
a b
|
||||
1200 x1000_1updatedupdated
|
||||
delete from t1 where a >= 1000 ;
|
||||
|
|
|
@ -1016,7 +1016,7 @@ set @arg01=2;
|
|||
execute stmt1 using @arg00, @arg01;
|
||||
Warnings:
|
||||
Warning 1263 Data truncated; NULL supplied to NOT NULL column 'a' at row 1
|
||||
select a,b from t1;
|
||||
select a,b from t1 order by a;
|
||||
a b
|
||||
0 two
|
||||
1 one
|
||||
|
@ -1024,7 +1024,7 @@ a b
|
|||
4 four
|
||||
set @arg00=0;
|
||||
execute stmt1 using @arg01, @arg00;
|
||||
select a,b from t1;
|
||||
select a,b from t1 order by a;
|
||||
a b
|
||||
1 one
|
||||
2 two
|
||||
|
@ -1048,7 +1048,7 @@ prepare stmt1 from 'update t1 set a=? where b=?
|
|||
and a not in (select ? from t2
|
||||
where b = ? or a = ?)';
|
||||
execute stmt1 using @arg04, @arg01, @arg02, @arg03, @arg00 ;
|
||||
select a,b from t1 ;
|
||||
select a,b from t1 order by a;
|
||||
a b
|
||||
1 one
|
||||
2 two
|
||||
|
@ -1142,7 +1142,7 @@ set @arg01=1 ;
|
|||
prepare stmt1 from 'insert into t1 set a=?, b=''sechs''
|
||||
on duplicate key update a=a + ?, b=concat(b,''modified'') ';
|
||||
execute stmt1 using @arg00, @arg01;
|
||||
select * from t1;
|
||||
select * from t1 order by a;
|
||||
a b
|
||||
0 NULL
|
||||
1 one
|
||||
|
@ -1170,7 +1170,7 @@ set @updated="updated" ;
|
|||
insert into t1 values(1000,'x1000_1') ;
|
||||
insert into t1 values(@1000,@x1000_2),(@1000,@x1000_3)
|
||||
on duplicate key update a = a + @100, b = concat(b,@updated) ;
|
||||
select a,b from t1 where a >= 1000 ;
|
||||
select a,b from t1 where a >= 1000 order by a ;
|
||||
a b
|
||||
1000 x1000_3
|
||||
1100 x1000_1updated
|
||||
|
@ -1179,14 +1179,14 @@ insert into t1 values(1000,'x1000_1') ;
|
|||
prepare stmt1 from ' insert into t1 values(?,?),(?,?)
|
||||
on duplicate key update a = a + ?, b = concat(b,?) ';
|
||||
execute stmt1 using @1000, @x1000_2, @1000, @x1000_3, @100, @updated ;
|
||||
select a,b from t1 where a >= 1000 ;
|
||||
select a,b from t1 where a >= 1000 order by a ;
|
||||
a b
|
||||
1000 x1000_3
|
||||
1100 x1000_1updated
|
||||
delete from t1 where a >= 1000 ;
|
||||
insert into t1 values(1000,'x1000_1') ;
|
||||
execute stmt1 using @1000, @x1000_2, @1100, @x1000_3, @100, @updated ;
|
||||
select a,b from t1 where a >= 1000 ;
|
||||
select a,b from t1 where a >= 1000 order by a ;
|
||||
a b
|
||||
1200 x1000_1updatedupdated
|
||||
delete from t1 where a >= 1000 ;
|
||||
|
@ -1195,7 +1195,7 @@ ERROR HY000: This command is not supported in the prepared statement protocol ye
|
|||
set @duplicate='duplicate ' ;
|
||||
set @1000=1000 ;
|
||||
set @5=5 ;
|
||||
select a,b from t1 where a < 5 ;
|
||||
select a,b from t1 where a < 5 order by a ;
|
||||
a b
|
||||
0 NULL
|
||||
1 one
|
||||
|
@ -1206,7 +1206,7 @@ insert into t1 select a + @1000, concat(@duplicate,b) from t1
|
|||
where a < @5 ;
|
||||
affected rows: 5
|
||||
info: Records: 5 Duplicates: 0 Warnings: 0
|
||||
select a,b from t1 where a >= 1000 ;
|
||||
select a,b from t1 where a >= 1000 order by a ;
|
||||
a b
|
||||
1000 NULL
|
||||
1001 duplicate one
|
||||
|
@ -1219,7 +1219,7 @@ where a < ? ' ;
|
|||
execute stmt1 using @1000, @duplicate, @5;
|
||||
affected rows: 5
|
||||
info: Records: 5 Duplicates: 0 Warnings: 0
|
||||
select a,b from t1 where a >= 1000 ;
|
||||
select a,b from t1 where a >= 1000 order by a ;
|
||||
a b
|
||||
1000 NULL
|
||||
1001 duplicate one
|
||||
|
@ -1243,7 +1243,7 @@ where (a,b) in ( select sqrt(a+@1)+CAST(@float AS signed),b
|
|||
from t1);
|
||||
affected rows: 8
|
||||
info: Records: 8 Duplicates: 0 Warnings: 0
|
||||
select a,b from t2;
|
||||
select a,b from t2 order by a ;
|
||||
a b
|
||||
3 duplicate
|
||||
4 duplicate
|
||||
|
@ -1267,7 +1267,7 @@ select b, a + ? from t1
|
|||
execute stmt1 using @duplicate, @5, @five, @2, @100, @1, @float ;
|
||||
affected rows: 8
|
||||
info: Records: 8 Duplicates: 0 Warnings: 0
|
||||
select a,b from t2;
|
||||
select a,b from t2 order by a ;
|
||||
a b
|
||||
3 duplicate
|
||||
4 duplicate
|
||||
|
|
|
@ -1297,4 +1297,6 @@ INSERT INTO t2 VALUES (2,011401,37,'breaking','dreaded','Steinberg','W');
|
|||
INSERT INTO t2 VALUES (3,011402,37,'Romans','scholastics','jarring','');
|
||||
INSERT INTO t2 VALUES (4,011403,37,'intercepted','audiology','tinily','');
|
||||
SELECT * FROM t2;
|
||||
OPTIMIZE TABLE t2;
|
||||
SELECT * FROM t2;
|
||||
drop table t1, t2;
|
||||
|
|
|
@ -437,26 +437,125 @@ INSERT INTO t1 VALUES
|
|||
(1,1,1),(2,2,2),(3,3,3),(4,4,4),(5,5,5),
|
||||
(6,6,6),(7,7,7),(8,8,8),(9,9,9),(10,10,10);
|
||||
|
||||
select count(*) from t1;
|
||||
|
||||
|
||||
#
|
||||
# Test that select count(*) can see inserts made in the same transaction
|
||||
#
|
||||
begin;
|
||||
|
||||
#
|
||||
# Insert duplicate rows, inside transaction
|
||||
# since failing inserts rollbacks whole transaction
|
||||
# all select count (except second) return same value
|
||||
#
|
||||
SELECT COUNT(*) FROM t1;
|
||||
INSERT INTO t1 VALUES
|
||||
(2001,2001,2001),(2002,2002,2002),(2003,2003,2003),(2004,2004,2004),(2005,2005,2005);
|
||||
SELECT COUNT(*) FROM t1;
|
||||
rollback;
|
||||
|
||||
#
|
||||
# Insert duplicate rows, inside transaction
|
||||
# try to commit
|
||||
#
|
||||
begin;
|
||||
|
||||
--error 1062
|
||||
INSERT INTO t1 VALUES
|
||||
(1,1,1),(2,2,2),(3,3,3),(4,4,4),(5,5,5),
|
||||
(6,6,6),(7,7,7),(8,8,8),(9,9,9),(10,10,10);
|
||||
SELECT COUNT(*) FROM t1;
|
||||
|
||||
--error 1296
|
||||
commit;
|
||||
SELECT COUNT(*) FROM t1;
|
||||
|
||||
select * from t1 where pk1=1;
|
||||
select * from t1 where pk1=10;
|
||||
select count(*) from t1 where pk1 <= 10 order by pk1;
|
||||
select count(*) from t1;
|
||||
|
||||
|
||||
#
|
||||
# Insert duplicate rows, inside transaction
|
||||
# rollback
|
||||
#
|
||||
begin;
|
||||
|
||||
--error 1062
|
||||
INSERT INTO t1 VALUES
|
||||
(1,1,1),(2,2,2),(3,3,3),(4,4,4),(5,5,5),
|
||||
(6,6,6),(7,7,7),(8,8,8),(9,9,9),(10,10,10);
|
||||
|
||||
rollback;
|
||||
|
||||
select * from t1 where pk1=1;
|
||||
select * from t1 where pk1=10;
|
||||
select count(*) from t1 where pk1 <= 10 order by pk1;
|
||||
select count(*) from t1;
|
||||
|
||||
|
||||
#
|
||||
# Insert duplicate rows, inside transaction
|
||||
# then try to select, finally rollback
|
||||
#
|
||||
begin;
|
||||
|
||||
--error 1062
|
||||
INSERT INTO t1 VALUES
|
||||
(1,1,1),(2,2,2),(3,3,3),(4,4,4),(5,5,5),
|
||||
(6,6,6),(7,7,7),(8,8,8),(9,9,9),(10,10,10);
|
||||
--error 1296
|
||||
SELECT * FROM t1 WHERE pk1=10;
|
||||
|
||||
rollback;
|
||||
|
||||
select * from t1 where pk1=1;
|
||||
select * from t1 where pk1=10;
|
||||
select count(*) from t1 where pk1 <= 10 order by pk1;
|
||||
select count(*) from t1;
|
||||
|
||||
|
||||
#
|
||||
# Insert duplicate rows, inside transaction
|
||||
# then try to select, finally commit
|
||||
#
|
||||
begin;
|
||||
|
||||
--error 1062
|
||||
INSERT INTO t1 VALUES
|
||||
(1,1,1),(2,2,2),(3,3,3),(4,4,4),(5,5,5),
|
||||
(6,6,6),(7,7,7),(8,8,8),(9,9,9),(10,10,10);
|
||||
|
||||
--error 1296
|
||||
SELECT * FROM t1 WHERE pk1=10;
|
||||
|
||||
--error 1296
|
||||
SELECT * FROM t1 WHERE pk1=10;
|
||||
|
||||
--error 1296
|
||||
commit;
|
||||
|
||||
select * from t1 where pk1=1;
|
||||
select * from t1 where pk1=10;
|
||||
select count(*) from t1 where pk1 <= 10 order by pk1;
|
||||
select count(*) from t1;
|
||||
|
||||
|
||||
#
|
||||
# Insert duplicate rows, inside transaction
|
||||
# then try to do another insert
|
||||
#
|
||||
begin;
|
||||
|
||||
--error 1062
|
||||
INSERT INTO t1 VALUES
|
||||
(1,1,1),(2,2,2),(3,3,3),(4,4,4),(5,5,5),
|
||||
(6,6,6),(7,7,7),(8,8,8),(9,9,9),(10,10,10);
|
||||
|
||||
--error 1296
|
||||
INSERT INTO t1 values (4000, 40, 44);
|
||||
|
||||
rollback;
|
||||
|
||||
select * from t1 where pk1=1;
|
||||
select * from t1 where pk1=10;
|
||||
select count(*) from t1 where pk1 <= 10 order by pk1;
|
||||
select count(*) from t1;
|
||||
|
||||
#
|
||||
# Insert duplicate rows using "insert .. select"
|
||||
|
@ -466,4 +565,21 @@ SELECT COUNT(*) FROM t1;
|
|||
insert into t1 select * from t1 where b < 10 order by pk1;
|
||||
|
||||
|
||||
begin;
|
||||
--error 1031
|
||||
INSERT IGNORE INTO t1 VALUES(1,2,3);
|
||||
commit;
|
||||
select * from t1 where pk1=1;
|
||||
|
||||
--error 1031
|
||||
INSERT IGNORE INTO t1 VALUES(1,2,3);
|
||||
select * from t1 where pk1=1;
|
||||
|
||||
REPLACE INTO t1 values(1, 2, 3);
|
||||
select * from t1 where pk1=1;
|
||||
|
||||
--error 1031
|
||||
INSERT INTO t1 VALUES(1,1,1) ON DUPLICATE KEY UPDATE b=79;
|
||||
select * from t1 where pk1=1;
|
||||
|
||||
DROP TABLE t1;
|
||||
|
|
26
mysys/hash.c
26
mysys/hash.c
|
@ -88,6 +88,32 @@ void hash_free(HASH *hash)
|
|||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Delete all elements from the hash (the hash itself is to be reused).
|
||||
|
||||
SYNOPSIS
|
||||
hash_reset()
|
||||
hash the hash to delete elements of
|
||||
*/
|
||||
|
||||
void hash_reset(HASH *hash)
|
||||
{
|
||||
DBUG_ENTER("hash_reset");
|
||||
if (hash->free)
|
||||
{
|
||||
HASH_LINK *link= dynamic_element(&hash->array, 0, HASH_LINK*);
|
||||
HASH_LINK *end= link + hash->records;
|
||||
for (; link < end; ++link)
|
||||
(*hash->free)(link->data);
|
||||
}
|
||||
reset_dynamic(&hash->array);
|
||||
hash->records= 0;
|
||||
hash->blength= 1;
|
||||
hash->current_record= NO_RECORD;
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
/* some helper functions */
|
||||
|
||||
/*
|
||||
|
|
|
@ -229,7 +229,7 @@ LocalConfig::parseString(const char * connectString, char *line){
|
|||
|
||||
bool LocalConfig::readFile(const char * filename, bool &fopenError)
|
||||
{
|
||||
char line[150], line2[150];
|
||||
char line[1024];
|
||||
|
||||
fopenError = false;
|
||||
|
||||
|
@ -241,31 +241,33 @@ bool LocalConfig::readFile(const char * filename, bool &fopenError)
|
|||
return false;
|
||||
}
|
||||
|
||||
unsigned int sz = 1024;
|
||||
char* theString = (char*)NdbMem_Allocate(sz);
|
||||
theString[0] = 0;
|
||||
BaseString theString;
|
||||
|
||||
fgets(theString, sz, file);
|
||||
while (fgets(line+1, 100, file)) {
|
||||
line[0] = ';';
|
||||
while (strlen(theString) + strlen(line) >= sz) {
|
||||
sz = sz*2;
|
||||
char *newString = (char*)NdbMem_Allocate(sz);
|
||||
strcpy(newString, theString);
|
||||
free(theString);
|
||||
theString = newString;
|
||||
while(fgets(line, 1024, file)){
|
||||
BaseString tmp(line);
|
||||
tmp.trim(" \t\n\r");
|
||||
if(tmp.length() > 0 && tmp.c_str()[0] != '#'){
|
||||
theString.append(tmp);
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (fgets(line, 1024, file)) {
|
||||
BaseString tmp(line);
|
||||
tmp.trim(" \t\n\r");
|
||||
if(tmp.length() > 0 && tmp.c_str()[0] != '#'){
|
||||
theString.append(";");
|
||||
theString.append(tmp);
|
||||
}
|
||||
strcat(theString, line);
|
||||
}
|
||||
|
||||
bool return_value = parseString(theString, line);
|
||||
bool return_value = parseString(theString.c_str(), line);
|
||||
|
||||
if (!return_value) {
|
||||
snprintf(line2, 150, "Reading %s: %s", filename, line);
|
||||
setError(0,line2);
|
||||
BaseString tmp;
|
||||
tmp.assfmt("Reading %s: %s", filename, line);
|
||||
setError(0, tmp.c_str());
|
||||
}
|
||||
|
||||
free(theString);
|
||||
fclose(file);
|
||||
return return_value;
|
||||
}
|
||||
|
|
|
@ -159,6 +159,7 @@ Configuration::Configuration()
|
|||
_initialStart = false;
|
||||
_daemonMode = false;
|
||||
m_config_retriever= 0;
|
||||
m_clusterConfig= 0;
|
||||
}
|
||||
|
||||
Configuration::~Configuration(){
|
||||
|
|
|
@ -145,27 +145,29 @@ NdbConnection::init()
|
|||
}//NdbConnection::init()
|
||||
|
||||
/*****************************************************************************
|
||||
setOperationErrorCode(int anErrorCode);
|
||||
setOperationErrorCode(int error);
|
||||
|
||||
Remark: Sets an error code on the connection object from an
|
||||
operation object.
|
||||
*****************************************************************************/
|
||||
void
|
||||
NdbConnection::setOperationErrorCode(int anErrorCode)
|
||||
NdbConnection::setOperationErrorCode(int error)
|
||||
{
|
||||
if (theError.code == 0)
|
||||
theError.code = anErrorCode;
|
||||
}//NdbConnection::setOperationErrorCode()
|
||||
DBUG_ENTER("NdbConnection::setOperationErrorCode");
|
||||
setErrorCode(error);
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
setOperationErrorCodeAbort(int anErrorCode);
|
||||
setOperationErrorCodeAbort(int error);
|
||||
|
||||
Remark: Sets an error code on the connection object from an
|
||||
operation object.
|
||||
*****************************************************************************/
|
||||
void
|
||||
NdbConnection::setOperationErrorCodeAbort(int anErrorCode)
|
||||
NdbConnection::setOperationErrorCodeAbort(int error)
|
||||
{
|
||||
DBUG_ENTER("NdbConnection::setOperationErrorCodeAbort");
|
||||
if (theTransactionIsStarted == false) {
|
||||
theCommitStatus = Aborted;
|
||||
} else if ((m_abortOption == AbortOnError) &&
|
||||
|
@ -173,9 +175,9 @@ NdbConnection::setOperationErrorCodeAbort(int anErrorCode)
|
|||
(theCommitStatus != Aborted)) {
|
||||
theCommitStatus = NeedAbort;
|
||||
}//if
|
||||
if (theError.code == 0)
|
||||
theError.code = anErrorCode;
|
||||
}//NdbConnection::setOperationErrorCodeAbort()
|
||||
setErrorCode(error);
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
setErrorCode(int anErrorCode);
|
||||
|
@ -183,10 +185,15 @@ setErrorCode(int anErrorCode);
|
|||
Remark: Sets an error indication on the connection object.
|
||||
*****************************************************************************/
|
||||
void
|
||||
NdbConnection::setErrorCode(int anErrorCode)
|
||||
NdbConnection::setErrorCode(int error)
|
||||
{
|
||||
DBUG_ENTER("NdbConnection::setErrorCode");
|
||||
DBUG_PRINT("enter", ("error: %d, theError.code: %d", error, theError.code));
|
||||
|
||||
if (theError.code == 0)
|
||||
theError.code = anErrorCode;
|
||||
theError.code = error;
|
||||
|
||||
DBUG_VOID_RETURN;
|
||||
}//NdbConnection::setErrorCode()
|
||||
|
||||
int
|
||||
|
@ -262,8 +269,12 @@ NdbConnection::execute(ExecType aTypeOfExec,
|
|||
AbortOption abortOption,
|
||||
int forceSend)
|
||||
{
|
||||
DBUG_ENTER("NdbConnection::execute");
|
||||
DBUG_PRINT("enter", ("aTypeOfExec: %d, abortOption: %d",
|
||||
aTypeOfExec, abortOption));
|
||||
|
||||
if (! theBlobFlag)
|
||||
return executeNoBlobs(aTypeOfExec, abortOption, forceSend);
|
||||
DBUG_RETURN(executeNoBlobs(aTypeOfExec, abortOption, forceSend));
|
||||
|
||||
/*
|
||||
* execute prepared ops in batches, as requested by blobs
|
||||
|
@ -346,7 +357,7 @@ NdbConnection::execute(ExecType aTypeOfExec,
|
|||
}
|
||||
} while (theFirstOpInList != NULL || tExecType != aTypeOfExec);
|
||||
|
||||
return ret;
|
||||
DBUG_RETURN(ret);
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -354,6 +365,10 @@ NdbConnection::executeNoBlobs(ExecType aTypeOfExec,
|
|||
AbortOption abortOption,
|
||||
int forceSend)
|
||||
{
|
||||
DBUG_ENTER("NdbConnection::executeNoBlobs");
|
||||
DBUG_PRINT("enter", ("aTypeOfExec: %d, abortOption: %d",
|
||||
aTypeOfExec, abortOption));
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// We will start by preparing all operations in the transaction defined
|
||||
// since last execute or since beginning. If this works ok we will continue
|
||||
|
@ -376,7 +391,7 @@ NdbConnection::executeNoBlobs(ExecType aTypeOfExec,
|
|||
*/
|
||||
ndbout << "This timeout should never occur, execute(..)" << endl;
|
||||
setOperationErrorCodeAbort(4012); // Error code for "Cluster Failure"
|
||||
return -1;
|
||||
DBUG_RETURN(-1);
|
||||
}//if
|
||||
|
||||
/*
|
||||
|
@ -400,13 +415,13 @@ NdbConnection::executeNoBlobs(ExecType aTypeOfExec,
|
|||
}
|
||||
#endif
|
||||
if (theReturnStatus == ReturnFailure) {
|
||||
return -1;
|
||||
DBUG_RETURN(-1);
|
||||
}//if
|
||||
break;
|
||||
}
|
||||
}
|
||||
thePendingBlobOps = 0;
|
||||
return 0;
|
||||
DBUG_RETURN(0);
|
||||
}//NdbConnection::execute()
|
||||
|
||||
/*****************************************************************************
|
||||
|
@ -430,9 +445,15 @@ NdbConnection::executeAsynchPrepare( ExecType aTypeOfExec,
|
|||
void* anyObject,
|
||||
AbortOption abortOption)
|
||||
{
|
||||
DBUG_ENTER("NdbConnection::executeAsynchPrepare");
|
||||
DBUG_PRINT("enter", ("aTypeOfExec: %d, aCallback: %x, anyObject: %x",
|
||||
aTypeOfExec, aCallback, anyObject));
|
||||
|
||||
/**
|
||||
* Reset error.code on execute
|
||||
*/
|
||||
if (theError.code != 0)
|
||||
DBUG_PRINT("enter", ("Resetting error %d on execute", theError.code));
|
||||
theError.code = 0;
|
||||
NdbScanOperation* tcOp = m_theFirstScanOperation;
|
||||
if (tcOp != 0){
|
||||
|
@ -441,7 +462,7 @@ NdbConnection::executeAsynchPrepare( ExecType aTypeOfExec,
|
|||
int tReturnCode;
|
||||
tReturnCode = tcOp->executeCursor(theDBnode);
|
||||
if (tReturnCode == -1) {
|
||||
return;
|
||||
DBUG_VOID_RETURN;
|
||||
}//if
|
||||
tcOp = (NdbScanOperation*)tcOp->next();
|
||||
} // while
|
||||
|
@ -463,17 +484,6 @@ NdbConnection::executeAsynchPrepare( ExecType aTypeOfExec,
|
|||
theCallbackFunction = aCallback;
|
||||
theCallbackObject = anyObject;
|
||||
m_abortOption = abortOption;
|
||||
// SendStatusType tSendStatus = theSendStatus;
|
||||
|
||||
// if (tSendStatus != InitState) {
|
||||
/****************************************************************************
|
||||
* The application is obviously doing strange things. We should probably
|
||||
* report to the application the problem in some manner. Since we don't have
|
||||
* a good way of handling the problem we avoid discovering the problem.
|
||||
* Should be handled at some point in time.
|
||||
****************************************************************************/
|
||||
// return;
|
||||
// }
|
||||
m_waitForReply = true;
|
||||
tNdb->thePreparedTransactionsArray[tnoOfPreparedTransactions] = this;
|
||||
theTransArrayIndex = tnoOfPreparedTransactions;
|
||||
|
@ -502,7 +512,11 @@ NdbConnection::executeAsynchPrepare( ExecType aTypeOfExec,
|
|||
} else {
|
||||
theSendStatus = sendABORTfail;
|
||||
}//if
|
||||
return;
|
||||
if (theCommitStatus == Aborted){
|
||||
DBUG_PRINT("exit", ("theCommitStatus: Aborted"));
|
||||
setErrorCode(4350);
|
||||
}
|
||||
DBUG_VOID_RETURN;
|
||||
}//if
|
||||
if (tTransactionIsStarted == true) {
|
||||
if (tLastOp != NULL) {
|
||||
|
@ -520,7 +534,7 @@ NdbConnection::executeAsynchPrepare( ExecType aTypeOfExec,
|
|||
* We will use the commit method.
|
||||
*********************************************************************/
|
||||
theSendStatus = sendCOMMITstate;
|
||||
return;
|
||||
DBUG_VOID_RETURN;
|
||||
} else {
|
||||
/**********************************************************************
|
||||
* We need to put it into the array of completed transactions to
|
||||
|
@ -532,7 +546,7 @@ NdbConnection::executeAsynchPrepare( ExecType aTypeOfExec,
|
|||
* put it into the completed array.
|
||||
**********************************************************************/
|
||||
theSendStatus = sendCompleted;
|
||||
return; // No Commit with no operations is OK
|
||||
DBUG_VOID_RETURN; // No Commit with no operations is OK
|
||||
}//if
|
||||
}//if
|
||||
} else if (tTransactionIsStarted == false) {
|
||||
|
@ -560,7 +574,7 @@ NdbConnection::executeAsynchPrepare( ExecType aTypeOfExec,
|
|||
* will put it into the completed array.
|
||||
***********************************************************************/
|
||||
theSendStatus = sendCompleted;
|
||||
return;
|
||||
DBUG_VOID_RETURN;
|
||||
}//if
|
||||
}
|
||||
|
||||
|
@ -573,7 +587,7 @@ NdbConnection::executeAsynchPrepare( ExecType aTypeOfExec,
|
|||
tReturnCode = tOp->prepareSend(theTCConPtr, theTransactionId);
|
||||
if (tReturnCode == -1) {
|
||||
theSendStatus = sendABORTfail;
|
||||
return;
|
||||
DBUG_VOID_RETURN;
|
||||
}//if
|
||||
|
||||
/*************************************************************************
|
||||
|
@ -596,7 +610,7 @@ NdbConnection::executeAsynchPrepare( ExecType aTypeOfExec,
|
|||
theNoOfOpSent = 0;
|
||||
theNoOfOpCompleted = 0;
|
||||
theSendStatus = sendOperations;
|
||||
return;
|
||||
DBUG_VOID_RETURN;
|
||||
}//NdbConnection::executeAsynchPrepare()
|
||||
|
||||
void NdbConnection::close()
|
||||
|
@ -665,6 +679,8 @@ Remark: Send all operations belonging to this connection.
|
|||
int
|
||||
NdbConnection::doSend()
|
||||
{
|
||||
DBUG_ENTER("NdbConnection::doSend");
|
||||
|
||||
/*
|
||||
This method assumes that at least one operation have been defined. This
|
||||
is ensured by the caller of this routine (=execute).
|
||||
|
@ -687,7 +703,7 @@ NdbConnection::doSend()
|
|||
theSendStatus = sendTC_OP;
|
||||
theTransactionIsStarted = true;
|
||||
tNdb->insert_sent_list(this);
|
||||
return 0;
|
||||
DBUG_RETURN(0);
|
||||
}//case
|
||||
case sendABORT:
|
||||
case sendABORTfail:{
|
||||
|
@ -699,18 +715,18 @@ NdbConnection::doSend()
|
|||
theReturnStatus = ReturnFailure;
|
||||
}//if
|
||||
if (sendROLLBACK() == 0) {
|
||||
return 0;
|
||||
DBUG_RETURN(0);
|
||||
}//if
|
||||
break;
|
||||
}//case
|
||||
case sendCOMMITstate:
|
||||
if (sendCOMMIT() == 0) {
|
||||
return 0;
|
||||
DBUG_RETURN(0);
|
||||
}//if
|
||||
break;
|
||||
case sendCompleted:
|
||||
theNdb->insert_completed_list(this);
|
||||
return 0;
|
||||
DBUG_RETURN(0);
|
||||
default:
|
||||
ndbout << "Inconsistent theSendStatus = " << theSendStatus << endl;
|
||||
abort();
|
||||
|
@ -720,7 +736,7 @@ NdbConnection::doSend()
|
|||
theReleaseOnClose = true;
|
||||
theTransactionIsStarted = false;
|
||||
theCommitStatus = Aborted;
|
||||
return -1;
|
||||
DBUG_RETURN(-1);
|
||||
}//NdbConnection::doSend()
|
||||
|
||||
/**************************************************************************
|
||||
|
|
|
@ -29,24 +29,31 @@
|
|||
void
|
||||
Ndb::checkFailedNode()
|
||||
{
|
||||
for (NodeId i = 0; i < theNoOfDBnodes; i ++){
|
||||
const NodeId node_id = theDBnodes[i];
|
||||
DBUG_ENTER("Ndb::checkFailedNode");
|
||||
DBUG_PRINT("enter", ("theNoOfDBnodes: %d", theNoOfDBnodes));
|
||||
|
||||
NdbConnection * tNdbCon = theConnectionArray[node_id];
|
||||
DBUG_ASSERT(theNoOfDBnodes < MAX_NDB_NODES);
|
||||
for (int i = 0; i < theNoOfDBnodes; i++){
|
||||
const NodeId node_id = theDBnodes[i];
|
||||
DBUG_PRINT("info", ("i: %d, node_id: %d", i, node_id));
|
||||
|
||||
DBUG_ASSERT(node_id < MAX_NDB_NODES);
|
||||
if (the_release_ind[node_id] == 1){
|
||||
|
||||
/**
|
||||
* Release all connections in idle list (for node)
|
||||
*/
|
||||
NdbConnection * tNdbCon = theConnectionArray[node_id];
|
||||
theConnectionArray[node_id] = NULL;
|
||||
while (tNdbCon != NULL) {
|
||||
NdbConnection* tempNdbCon = tNdbCon;
|
||||
tNdbCon = tNdbCon->next();
|
||||
releaseNdbCon(tempNdbCon);
|
||||
}//while
|
||||
}
|
||||
the_release_ind[node_id] = 0;
|
||||
}//if
|
||||
}//for
|
||||
}
|
||||
}
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
|
|
@ -228,6 +228,7 @@ ErrorBundle ErrorCodes[] = {
|
|||
{ 4347, IE, "Bad state at alter index" },
|
||||
{ 4348, IE, "Inconsistency detected at alter index" },
|
||||
{ 4349, IE, "Inconsistency detected at index usage" },
|
||||
{ 4350, IE, "Transaction already aborted" },
|
||||
|
||||
/**
|
||||
* Application error
|
||||
|
|
|
@ -30,7 +30,7 @@ testSystemRestart \
|
|||
testTimeout \
|
||||
testTransactions \
|
||||
testDeadlock \
|
||||
test_event ndbapi_slow_select testReadPerf
|
||||
test_event ndbapi_slow_select testReadPerf testLcp
|
||||
|
||||
#flexTimedAsynch
|
||||
#testBlobs
|
||||
|
@ -68,6 +68,7 @@ testDeadlock_SOURCES = testDeadlock.cpp
|
|||
test_event_SOURCES = test_event.cpp
|
||||
ndbapi_slow_select_SOURCES = slow_select.cpp
|
||||
testReadPerf_SOURCES = testReadPerf.cpp
|
||||
testLcp_SOURCES = testLcp.cpp
|
||||
|
||||
INCLUDES_LOC = -I$(top_srcdir)/ndb/include/kernel
|
||||
|
||||
|
|
|
@ -2097,47 +2097,50 @@ int Bank::increaseSystemValue(SystemValueId sysValId, Uint64 &value){
|
|||
*
|
||||
*/
|
||||
|
||||
DBUG_ENTER("Bank::increaseSystemValue");
|
||||
|
||||
int check;
|
||||
|
||||
NdbConnection* pTrans = m_ndb.startTransaction();
|
||||
if (pTrans == NULL){
|
||||
ERR(m_ndb.getNdbError());
|
||||
return NDBT_FAILED;
|
||||
DBUG_RETURN(NDBT_FAILED);
|
||||
}
|
||||
|
||||
NdbOperation* pOp = pTrans->getNdbOperation("SYSTEM_VALUES");
|
||||
if (pOp == NULL) {
|
||||
ERR(pTrans->getNdbError());
|
||||
m_ndb.closeTransaction(pTrans);
|
||||
return NDBT_FAILED;
|
||||
DBUG_RETURN(NDBT_FAILED);
|
||||
}
|
||||
|
||||
check = pOp->readTupleExclusive();
|
||||
// check = pOp->readTuple();
|
||||
if( check == -1 ) {
|
||||
ERR(pTrans->getNdbError());
|
||||
m_ndb.closeTransaction(pTrans);
|
||||
return NDBT_FAILED;
|
||||
DBUG_RETURN(NDBT_FAILED);
|
||||
}
|
||||
|
||||
check = pOp->equal("SYSTEM_VALUES_ID", sysValId);
|
||||
if( check == -1 ) {
|
||||
ERR(pTrans->getNdbError());
|
||||
m_ndb.closeTransaction(pTrans);
|
||||
return NDBT_FAILED;
|
||||
DBUG_RETURN(NDBT_FAILED);
|
||||
}
|
||||
|
||||
NdbRecAttr* valueRec = pOp->getValue("VALUE");
|
||||
if( valueRec ==NULL ) {
|
||||
ERR(pTrans->getNdbError());
|
||||
m_ndb.closeTransaction(pTrans);
|
||||
return NDBT_FAILED;
|
||||
DBUG_RETURN(NDBT_FAILED);
|
||||
}
|
||||
|
||||
check = pTrans->execute(NoCommit);
|
||||
if( check == -1 ) {
|
||||
ERR(pTrans->getNdbError());
|
||||
m_ndb.closeTransaction(pTrans);
|
||||
return NDBT_FAILED;
|
||||
DBUG_RETURN(NDBT_FAILED);
|
||||
}
|
||||
|
||||
value = valueRec->u_64_value();
|
||||
|
@ -2147,49 +2150,56 @@ int Bank::increaseSystemValue(SystemValueId sysValId, Uint64 &value){
|
|||
if (pOp2 == NULL) {
|
||||
ERR(pTrans->getNdbError());
|
||||
m_ndb.closeTransaction(pTrans);
|
||||
return NDBT_FAILED;
|
||||
DBUG_RETURN(NDBT_FAILED);
|
||||
}
|
||||
|
||||
check = pOp2->updateTuple();
|
||||
if( check == -1 ) {
|
||||
ERR(pTrans->getNdbError());
|
||||
m_ndb.closeTransaction(pTrans);
|
||||
return NDBT_FAILED;
|
||||
DBUG_RETURN(NDBT_FAILED);
|
||||
}
|
||||
|
||||
check = pOp2->equal("SYSTEM_VALUES_ID", sysValId);
|
||||
if( check == -1 ) {
|
||||
ERR(pTrans->getNdbError());
|
||||
m_ndb.closeTransaction(pTrans);
|
||||
return NDBT_FAILED;
|
||||
DBUG_RETURN(NDBT_FAILED);
|
||||
}
|
||||
|
||||
check = pOp2->setValue("VALUE", value);
|
||||
if( check == -1 ) {
|
||||
ERR(pTrans->getNdbError());
|
||||
m_ndb.closeTransaction(pTrans);
|
||||
return NDBT_FAILED;
|
||||
DBUG_RETURN(NDBT_FAILED);
|
||||
}
|
||||
|
||||
check = pTrans->execute(NoCommit);
|
||||
if( check == -1 ) {
|
||||
ERR(pTrans->getNdbError());
|
||||
m_ndb.closeTransaction(pTrans);
|
||||
DBUG_RETURN(NDBT_FAILED);
|
||||
}
|
||||
|
||||
NdbOperation* pOp3 = pTrans->getNdbOperation("SYSTEM_VALUES");
|
||||
if (pOp3 == NULL) {
|
||||
ERR(pTrans->getNdbError());
|
||||
m_ndb.closeTransaction(pTrans);
|
||||
return NDBT_FAILED;
|
||||
DBUG_RETURN(NDBT_FAILED);
|
||||
}
|
||||
|
||||
check = pOp3->readTuple();
|
||||
if( check == -1 ) {
|
||||
ERR(pTrans->getNdbError());
|
||||
m_ndb.closeTransaction(pTrans);
|
||||
return NDBT_FAILED;
|
||||
DBUG_RETURN(NDBT_FAILED);
|
||||
}
|
||||
|
||||
check = pOp3->equal("SYSTEM_VALUES_ID", sysValId);
|
||||
if( check == -1 ) {
|
||||
ERR(pTrans->getNdbError());
|
||||
m_ndb.closeTransaction(pTrans);
|
||||
return NDBT_FAILED;
|
||||
DBUG_RETURN(NDBT_FAILED);
|
||||
}
|
||||
|
||||
// Read new value
|
||||
|
@ -2197,28 +2207,31 @@ int Bank::increaseSystemValue(SystemValueId sysValId, Uint64 &value){
|
|||
if( valueNewRec ==NULL ) {
|
||||
ERR(pTrans->getNdbError());
|
||||
m_ndb.closeTransaction(pTrans);
|
||||
return NDBT_FAILED;
|
||||
DBUG_RETURN(NDBT_FAILED);
|
||||
}
|
||||
|
||||
check = pTrans->execute(Commit);
|
||||
if( check == -1 ) {
|
||||
ERR(pTrans->getNdbError());
|
||||
m_ndb.closeTransaction(pTrans);
|
||||
return NDBT_FAILED;
|
||||
DBUG_RETURN(NDBT_FAILED);
|
||||
}
|
||||
|
||||
// Check that value updated equals the value we read after the update
|
||||
if (valueNewRec->u_64_value() != value){
|
||||
|
||||
printf("value actual=%lld\n", valueNewRec->u_64_value());
|
||||
printf("value expected=%lld actual=%lld\n", value, valueNewRec->u_64_value());
|
||||
|
||||
DBUG_PRINT("info", ("value expected=%ld actual=%ld", value, valueNewRec->u_64_value()));
|
||||
g_err << "getNextTransactionId: value was not updated" << endl;
|
||||
m_ndb.closeTransaction(pTrans);
|
||||
return NDBT_FAILED;
|
||||
DBUG_RETURN(NDBT_FAILED);
|
||||
}
|
||||
|
||||
m_ndb.closeTransaction(pTrans);
|
||||
|
||||
|
||||
return 0;
|
||||
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
int Bank::increaseSystemValue2(SystemValueId sysValId, Uint64 &value){
|
||||
|
|
320
ndb/test/ndbapi/testLcp.cpp
Normal file
320
ndb/test/ndbapi/testLcp.cpp
Normal file
|
@ -0,0 +1,320 @@
|
|||
|
||||
#include <NDBT.hpp>
|
||||
#include <NdbApi.hpp>
|
||||
#include <NdbRestarter.hpp>
|
||||
#include <HugoOperations.hpp>
|
||||
#include <UtilTransactions.hpp>
|
||||
#include <signaldata/DumpStateOrd.hpp>
|
||||
|
||||
struct CASE
|
||||
{
|
||||
bool start_row;
|
||||
bool end_row;
|
||||
bool curr_row;
|
||||
const char * op1;
|
||||
const char * op2;
|
||||
int val;
|
||||
};
|
||||
|
||||
static CASE g_ops[] =
|
||||
{
|
||||
{ false, true, false, "INSERT", 0, 0 },
|
||||
{ false, true, false, "INSERT", "UPDATE", 0 },
|
||||
{ false, false, false, "INSERT", "DELETE", 0 },
|
||||
{ true, true, false, "UPDATE", 0, 0 },
|
||||
{ true, true, false, "UPDATE", "UPDATE", 0 },
|
||||
{ true, false, false, "UPDATE", "DELETE", 0 },
|
||||
{ true, false, false, "DELETE", 0, 0 },
|
||||
{ true, true, false, "DELETE", "INSERT", 0 }
|
||||
};
|
||||
const size_t OP_COUNT = (sizeof(g_ops)/sizeof(g_ops[0]));
|
||||
|
||||
static Ndb* g_ndb = 0;
|
||||
static CASE* g_cases;
|
||||
static HugoOperations* g_hugo_ops;
|
||||
|
||||
static int g_rows = 1000;
|
||||
static int g_setup_tables = 1;
|
||||
static const char * g_tablename = "T1";
|
||||
static const NdbDictionary::Table* g_table = 0;
|
||||
static NdbRestarter g_restarter;
|
||||
|
||||
static int init_ndb(int argc, char** argv);
|
||||
static int parse_args(int argc, char** argv);
|
||||
static int connect_ndb();
|
||||
static int drop_all_tables();
|
||||
static int load_table();
|
||||
static int pause_lcp();
|
||||
static int do_op(int row);
|
||||
static int continue_lcp(int error);
|
||||
static int commit();
|
||||
static int restart();
|
||||
static int validate();
|
||||
|
||||
#define require(x) { bool b = x; if(!b){g_err << __LINE__ << endl; abort();}}
|
||||
|
||||
int
|
||||
main(int argc, char ** argv){
|
||||
|
||||
require(!init_ndb(argc, argv));
|
||||
require(!parse_args(argc, argv));
|
||||
require(!connect_ndb());
|
||||
|
||||
if(g_setup_tables){
|
||||
require(!drop_all_tables());
|
||||
|
||||
if(NDBT_Tables::createTable(g_ndb, g_tablename) != 0){
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
g_table = g_ndb->getDictionary()->getTable(g_tablename);
|
||||
if(g_table == 0){
|
||||
g_err << "Failed to retreive table: " << g_tablename << endl;
|
||||
exit(-1);
|
||||
}
|
||||
require(g_hugo_ops = new HugoOperations(* g_table));
|
||||
require(!g_hugo_ops->startTransaction(g_ndb));
|
||||
|
||||
g_cases= new CASE[g_rows];
|
||||
require(!load_table());
|
||||
|
||||
g_info << "Performing all ops wo/ inteference of LCP" << endl;
|
||||
|
||||
g_info << "Testing pre LCP operations, ZLCP_OP_WRITE_RT_BREAK" << endl;
|
||||
g_info << " where ZLCP_OP_WRITE_RT_BREAK is finished before SAVE_PAGES"
|
||||
<< endl;
|
||||
require(!pause_lcp());
|
||||
for(size_t j = 0; j<g_rows; j++){
|
||||
require(!do_op(j));
|
||||
}
|
||||
require(!continue_lcp(5900));
|
||||
require(!commit());
|
||||
require(!restart());
|
||||
require(!validate());
|
||||
|
||||
g_info << "Testing pre LCP operations, ZLCP_OP_WRITE_RT_BREAK" << endl;
|
||||
g_info << " where ZLCP_OP_WRITE_RT_BREAK is finished after SAVE_PAGES"
|
||||
<< endl;
|
||||
require(!load_table());
|
||||
require(!pause_lcp());
|
||||
for(size_t j = 0; j<g_rows; j++){
|
||||
require(!do_op(j));
|
||||
}
|
||||
require(!continue_lcp(5901));
|
||||
require(!commit());
|
||||
require(!restart());
|
||||
require(!validate());
|
||||
|
||||
g_info << "Testing pre LCP operations, undo-ed at commit" << endl;
|
||||
require(!load_table());
|
||||
require(!pause_lcp());
|
||||
for(size_t j = 0; j<g_rows; j++){
|
||||
require(!do_op(j));
|
||||
}
|
||||
require(!continue_lcp(5902));
|
||||
require(!commit());
|
||||
require(!continue_lcp(5903));
|
||||
require(!restart());
|
||||
require(!validate());
|
||||
}
|
||||
|
||||
static int init_ndb(int argc, char** argv)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_args(int argc, char** argv)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int connect_ndb()
|
||||
{
|
||||
g_ndb = new Ndb("TEST_DB");
|
||||
g_ndb->init();
|
||||
if(g_ndb->waitUntilReady(30) == 0){
|
||||
int args[] = { DumpStateOrd::DihMaxTimeBetweenLCP };
|
||||
return g_restarter.dumpStateAllNodes(args, 1);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int disconnect_ndb()
|
||||
{
|
||||
delete g_ndb;
|
||||
g_ndb = 0;
|
||||
g_table = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int drop_all_tables()
|
||||
{
|
||||
NdbDictionary::Dictionary * dict = g_ndb->getDictionary();
|
||||
require(dict);
|
||||
|
||||
BaseString db = g_ndb->getDatabaseName();
|
||||
BaseString schema = g_ndb->getSchemaName();
|
||||
|
||||
NdbDictionary::Dictionary::List list;
|
||||
if (dict->listObjects(list, NdbDictionary::Object::TypeUndefined) == -1){
|
||||
g_err << "Failed to list tables: " << endl
|
||||
<< dict->getNdbError() << endl;
|
||||
return -1;
|
||||
}
|
||||
for (unsigned i = 0; i < list.count; i++) {
|
||||
NdbDictionary::Dictionary::List::Element& elt = list.elements[i];
|
||||
switch (elt.type) {
|
||||
case NdbDictionary::Object::SystemTable:
|
||||
case NdbDictionary::Object::UserTable:
|
||||
g_ndb->setDatabaseName(elt.database);
|
||||
g_ndb->setSchemaName(elt.schema);
|
||||
if(dict->dropTable(elt.name) != 0){
|
||||
g_err << "Failed to drop table: "
|
||||
<< elt.database << "/" << elt.schema << "/" << elt.name <<endl;
|
||||
g_err << dict->getNdbError() << endl;
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case NdbDictionary::Object::UniqueHashIndex:
|
||||
case NdbDictionary::Object::OrderedIndex:
|
||||
case NdbDictionary::Object::HashIndexTrigger:
|
||||
case NdbDictionary::Object::IndexTrigger:
|
||||
case NdbDictionary::Object::SubscriptionTrigger:
|
||||
case NdbDictionary::Object::ReadOnlyConstraint:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
g_ndb->setDatabaseName(db.c_str());
|
||||
g_ndb->setSchemaName(schema.c_str());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int load_table()
|
||||
{
|
||||
UtilTransactions clear(* g_table);
|
||||
require(!clear.clearTable(g_ndb));
|
||||
|
||||
HugoOperations ops(* g_table);
|
||||
require(!ops.startTransaction(g_ndb));
|
||||
for(size_t i = 0; i<g_rows; i++){
|
||||
g_cases[i] = g_ops[ i % OP_COUNT];
|
||||
if(g_cases[i].start_row){
|
||||
g_cases[i].curr_row = true;
|
||||
g_cases[i].val = rand();
|
||||
require(!ops.pkInsertRecord(g_ndb, i, 1, g_cases[i].val));
|
||||
}
|
||||
if((i+1) % 100 == 0){
|
||||
require(!ops.execute_Commit(g_ndb));
|
||||
require(!ops.getTransaction()->restart());
|
||||
}
|
||||
}
|
||||
if((g_rows+1) % 100 != 0)
|
||||
require(!ops.execute_Commit(g_ndb));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pause_lcp()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_op(int row)
|
||||
{
|
||||
HugoOperations & ops = * g_hugo_ops;
|
||||
if(strcmp(g_cases[row].op1, "INSERT") == 0){
|
||||
require(!g_cases[row].curr_row);
|
||||
g_cases[row].curr_row = true;
|
||||
g_cases[row].val = rand();
|
||||
require(!ops.pkInsertRecord(g_ndb, row, 1, g_cases[row].val));
|
||||
} else if(strcmp(g_cases[row].op1, "UPDATE") == 0){
|
||||
require(g_cases[row].curr_row);
|
||||
g_cases[row].val = rand();
|
||||
require(!ops.pkUpdateRecord(g_ndb, row, 1, g_cases[row].val));
|
||||
} else if(strcmp(g_cases[row].op1, "DELETE") == 0){
|
||||
require(g_cases[row].curr_row);
|
||||
g_cases[row].curr_row = false;
|
||||
require(!ops.pkDeleteRecord(g_ndb, row, 1));
|
||||
}
|
||||
|
||||
require(!ops.execute_NoCommit(g_ndb));
|
||||
|
||||
if(g_cases[row].op2 == 0){
|
||||
} else if(strcmp(g_cases[row].op2, "INSERT") == 0){
|
||||
require(!g_cases[row].curr_row);
|
||||
g_cases[row].curr_row = true;
|
||||
g_cases[row].val = rand();
|
||||
require(!ops.pkInsertRecord(g_ndb, row, 1, g_cases[row].val));
|
||||
} else if(strcmp(g_cases[row].op2, "UPDATE") == 0){
|
||||
require(g_cases[row].curr_row);
|
||||
g_cases[row].val = rand();
|
||||
require(!ops.pkUpdateRecord(g_ndb, row, 1, g_cases[row].val));
|
||||
} else if(strcmp(g_cases[row].op2, "DELETE") == 0){
|
||||
require(g_cases[row].curr_row);
|
||||
g_cases[row].curr_row = false;
|
||||
require(!ops.pkDeleteRecord(g_ndb, row, 1));
|
||||
}
|
||||
|
||||
if(g_cases[row].op2 != 0)
|
||||
require(!ops.execute_NoCommit(g_ndb));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int continue_lcp(int error)
|
||||
{
|
||||
error = 0;
|
||||
if(g_restarter.insertErrorInAllNodes(error) == 0){
|
||||
int args[] = { DumpStateOrd::DihStartLcpImmediately };
|
||||
return g_restarter.dumpStateAllNodes(args, 1);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int commit()
|
||||
{
|
||||
HugoOperations & ops = * g_hugo_ops;
|
||||
int res = ops.execute_Commit(g_ndb);
|
||||
if(res == 0){
|
||||
return ops.getTransaction()->restart();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static int restart()
|
||||
{
|
||||
g_info << "Restarting cluster" << endl;
|
||||
disconnect_ndb();
|
||||
delete g_hugo_ops;
|
||||
|
||||
require(!g_restarter.restartAll());
|
||||
require(!g_restarter.waitClusterStarted(30));
|
||||
require(!connect_ndb());
|
||||
|
||||
g_table = g_ndb->getDictionary()->getTable(g_tablename);
|
||||
require(g_table);
|
||||
require(g_hugo_ops = new HugoOperations(* g_table));
|
||||
require(!g_hugo_ops->startTransaction(g_ndb));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int validate()
|
||||
{
|
||||
HugoOperations ops(* g_table);
|
||||
for(size_t i = 0; i<g_rows; i++){
|
||||
require(g_cases[i].curr_row == g_cases[i].end_row);
|
||||
require(!ops.startTransaction(g_ndb));
|
||||
ops.pkReadRecord(g_ndb, i, 1);
|
||||
int res = ops.execute_Commit(g_ndb);
|
||||
if(g_cases[i].curr_row){
|
||||
require(res == 0 && ops.verifyUpdatesValue(g_cases[i].val) == 0);
|
||||
} else {
|
||||
require(res == 626);
|
||||
}
|
||||
ops.closeTransaction(g_ndb);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -859,6 +859,11 @@ void NDBT_TestSuite::execute(Ndb* ndb, const NdbDictionary::Table* pTab,
|
|||
else
|
||||
numTestsOk++;
|
||||
numTestsExecuted++;
|
||||
|
||||
if (result == NDBT_OK && createTable == true){
|
||||
pDict->dropTable(pTab->getName());
|
||||
}
|
||||
|
||||
delete ctx;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2239,6 +2239,32 @@ static void mysql_close_free(MYSQL *mysql)
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
Clear connection pointer of every statement: this is necessary
|
||||
to give error on attempt to use a prepared statement of closed
|
||||
connection.
|
||||
|
||||
SYNOPSYS
|
||||
mysql_detach_stmt_list()
|
||||
stmt_list pointer to mysql->stmts
|
||||
*/
|
||||
|
||||
void mysql_detach_stmt_list(LIST **stmt_list)
|
||||
{
|
||||
#ifdef MYSQL_CLIENT
|
||||
/* Reset connection handle in all prepared statements. */
|
||||
LIST *element= *stmt_list;
|
||||
for (; element; element= element->next)
|
||||
{
|
||||
MYSQL_STMT *stmt= (MYSQL_STMT *) element->data;
|
||||
stmt->mysql= 0;
|
||||
/* No need to call list_delete for statement here */
|
||||
}
|
||||
*stmt_list= 0;
|
||||
#endif /* MYSQL_CLIENT */
|
||||
}
|
||||
|
||||
|
||||
void STDCALL mysql_close(MYSQL *mysql)
|
||||
{
|
||||
DBUG_ENTER("mysql_close");
|
||||
|
@ -2255,20 +2281,7 @@ void STDCALL mysql_close(MYSQL *mysql)
|
|||
}
|
||||
mysql_close_free_options(mysql);
|
||||
mysql_close_free(mysql);
|
||||
#ifdef MYSQL_CLIENT
|
||||
if (mysql->stmts)
|
||||
{
|
||||
/* Reset connection handle in all prepared statements. */
|
||||
LIST *element;
|
||||
for (element= mysql->stmts; element; element= element->next)
|
||||
{
|
||||
MYSQL_STMT *stmt= (MYSQL_STMT *) element->data;
|
||||
stmt->mysql= 0;
|
||||
/* No need to call list_delete for statement here */
|
||||
}
|
||||
mysql->stmts= 0;
|
||||
}
|
||||
#endif /*MYSQL_CLIENT*/
|
||||
mysql_detach_stmt_list(&mysql->stmts);
|
||||
#ifndef TO_BE_DELETED
|
||||
/* free/close slave list */
|
||||
if (mysql->rpl_pivot)
|
||||
|
|
|
@ -70,7 +70,6 @@
|
|||
Allow users to set compression level.
|
||||
Add truncate table command.
|
||||
Implement versioning, should be easy.
|
||||
Implement optimize so we can fix broken tables.
|
||||
Allow for errors, find a way to mark bad rows.
|
||||
See if during an optimize you can make the table smaller.
|
||||
Talk to the gzip guys, come up with a writable format so that updates are doable
|
||||
|
@ -88,6 +87,7 @@ static int archive_init= 0;
|
|||
|
||||
/* The file extension */
|
||||
#define ARZ ".ARZ"
|
||||
#define ARN ".ARN"
|
||||
|
||||
/*
|
||||
Used for hash table that tracks open tables.
|
||||
|
@ -117,7 +117,7 @@ static ARCHIVE_SHARE *get_share(const char *table_name, TABLE *table)
|
|||
if (!archive_init)
|
||||
{
|
||||
VOID(pthread_mutex_init(&archive_mutex,MY_MUTEX_INIT_FAST));
|
||||
if (!hash_init(&archive_open_tables,system_charset_info,32,0,0,
|
||||
if (hash_init(&archive_open_tables,system_charset_info,32,0,0,
|
||||
(hash_get_key) archive_get_key,0,0))
|
||||
{
|
||||
pthread_mutex_unlock(&LOCK_mysql_create_db);
|
||||
|
@ -205,7 +205,7 @@ static int free_share(ARCHIVE_SHARE *share)
|
|||
We just implement one additional file extension.
|
||||
*/
|
||||
const char **ha_archive::bas_ext() const
|
||||
{ static const char *ext[]= { ARZ, NullS }; return ext; }
|
||||
{ static const char *ext[]= { ARZ, ARN, NullS }; return ext; }
|
||||
|
||||
|
||||
/*
|
||||
|
@ -322,6 +322,11 @@ err:
|
|||
/*
|
||||
Look at ha_archive::open() for an explanation of the row format.
|
||||
Here we just write out the row.
|
||||
|
||||
Wondering about start_bulk_insert()? We don't implement it for
|
||||
archive since it optimizes for lots of writes. The only save
|
||||
for implementing start_bulk_insert() is that we could skip
|
||||
setting dirty to true each time.
|
||||
*/
|
||||
int ha_archive::write_row(byte * buf)
|
||||
{
|
||||
|
@ -380,17 +385,7 @@ int ha_archive::rnd_init(bool scan)
|
|||
pthread_mutex_lock(&share->mutex);
|
||||
if (share->dirty == TRUE)
|
||||
{
|
||||
/* I was having problems with OSX, but it worked for 10.3 so I am wrapping this with and ifdef */
|
||||
#ifdef BROKEN_GZFLUSH
|
||||
gzclose(share->archive_write);
|
||||
if ((share->archive_write= gzopen(share->data_file_name, "ab")) == NULL)
|
||||
{
|
||||
pthread_mutex_unlock(&share->mutex);
|
||||
DBUG_RETURN(errno ? errno : -1);
|
||||
}
|
||||
#else
|
||||
gzflush(share->archive_write, Z_SYNC_FLUSH);
|
||||
#endif
|
||||
share->dirty= FALSE;
|
||||
}
|
||||
pthread_mutex_unlock(&share->mutex);
|
||||
|
@ -504,6 +499,54 @@ int ha_archive::rnd_pos(byte * buf, byte *pos)
|
|||
DBUG_RETURN(get_row(buf));
|
||||
}
|
||||
|
||||
/*
|
||||
The table can become fragmented if data was inserted, read, and then
|
||||
inserted again. What we do is open up the file and recompress it completely.
|
||||
*/
|
||||
int ha_archive::optimize(THD* thd, HA_CHECK_OPT* check_opt)
|
||||
{
|
||||
DBUG_ENTER("ha_archive::optimize");
|
||||
int read; // Bytes read, gzread() returns int
|
||||
gzFile reader, writer;
|
||||
char block[IO_SIZE];
|
||||
char writer_filename[FN_REFLEN];
|
||||
|
||||
/* Lets create a file to contain the new data */
|
||||
fn_format(writer_filename,share->table_name,"",ARN, MY_REPLACE_EXT|MY_UNPACK_FILENAME);
|
||||
|
||||
/* Closing will cause all data waiting to be flushed, to be flushed */
|
||||
gzclose(share->archive_write);
|
||||
|
||||
if ((reader= gzopen(share->data_file_name, "rb")) == NULL)
|
||||
DBUG_RETURN(-1);
|
||||
|
||||
if ((writer= gzopen(writer_filename, "wb")) == NULL)
|
||||
{
|
||||
gzclose(reader);
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
|
||||
while (read= gzread(reader, block, IO_SIZE))
|
||||
gzwrite(writer, block, read);
|
||||
|
||||
gzclose(reader);
|
||||
gzclose(writer);
|
||||
|
||||
my_rename(writer_filename,share->data_file_name,MYF(0));
|
||||
|
||||
/*
|
||||
We reopen the file in case some IO is waiting to go through.
|
||||
In theory the table is closed right after this operation,
|
||||
but it is possible for IO to still happen.
|
||||
I may be being a bit too paranoid right here.
|
||||
*/
|
||||
if ((share->archive_write= gzopen(share->data_file_name, "ab")) == NULL)
|
||||
DBUG_RETURN(errno ? errno : -1);
|
||||
share->dirty= FALSE;
|
||||
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
|
||||
Everything below here is default, please look at ha_example.cc for
|
||||
|
|
|
@ -112,7 +112,7 @@ public:
|
|||
int external_lock(THD *thd, int lock_type);
|
||||
ha_rows records_in_range(uint inx, key_range *min_key, key_range *max_key);
|
||||
int create(const char *name, TABLE *form, HA_CREATE_INFO *create_info);
|
||||
|
||||
int optimize(THD* thd, HA_CHECK_OPT* check_opt);
|
||||
THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to,
|
||||
enum thr_lock_type lock_type);
|
||||
};
|
||||
|
|
|
@ -122,6 +122,8 @@ static const err_code_mapping err_map[]=
|
|||
{ 827, HA_ERR_RECORD_FILE_FULL },
|
||||
{ 832, HA_ERR_RECORD_FILE_FULL },
|
||||
|
||||
{ 0, 1 },
|
||||
|
||||
{ -1, -1 }
|
||||
};
|
||||
|
||||
|
@ -173,7 +175,7 @@ void ha_ndbcluster::records_update()
|
|||
DBUG_PRINT("info", ("id=%d, no_uncommitted_rows_count=%d",
|
||||
((const NDBTAB *)m_table)->getTableId(),
|
||||
info->no_uncommitted_rows_count));
|
||||
if (info->records == ~(ha_rows)0)
|
||||
// if (info->records == ~(ha_rows)0)
|
||||
{
|
||||
Uint64 rows;
|
||||
if(ndb_get_table_statistics(m_ndb, m_tabname, &rows, 0) == 0){
|
||||
|
@ -246,8 +248,6 @@ int ha_ndbcluster::ndb_err(NdbConnection *trans)
|
|||
{
|
||||
int res;
|
||||
const NdbError err= trans->getNdbError();
|
||||
if (!err.code)
|
||||
return 0; // Don't log things to DBUG log if no error
|
||||
DBUG_ENTER("ndb_err");
|
||||
|
||||
ERR_PRINT(err);
|
||||
|
@ -283,10 +283,11 @@ bool ha_ndbcluster::get_error_message(int error,
|
|||
DBUG_ENTER("ha_ndbcluster::get_error_message");
|
||||
DBUG_PRINT("enter", ("error: %d", error));
|
||||
|
||||
if (!m_ndb)
|
||||
Ndb *ndb= ((Thd_ndb*)current_thd->transaction.thd_ndb)->ndb;
|
||||
if (!ndb)
|
||||
DBUG_RETURN(false);
|
||||
|
||||
const NdbError err= m_ndb->getNdbError(error);
|
||||
const NdbError err= ndb->getNdbError(error);
|
||||
bool temporary= err.status==NdbError::TemporaryError;
|
||||
buf->set(err.message, strlen(err.message), &my_charset_bin);
|
||||
DBUG_PRINT("exit", ("message: %s, temporary: %d", buf->ptr(), temporary));
|
||||
|
@ -516,7 +517,7 @@ int ha_ndbcluster::get_ndb_blobs_value(NdbBlob *last_ndb_blob)
|
|||
*/
|
||||
|
||||
int ha_ndbcluster::get_ndb_value(NdbOperation *ndb_op, Field *field,
|
||||
uint fieldnr)
|
||||
uint fieldnr, byte* buf)
|
||||
{
|
||||
DBUG_ENTER("get_ndb_value");
|
||||
DBUG_PRINT("enter", ("fieldnr: %d flags: %o", fieldnr,
|
||||
|
@ -524,12 +525,15 @@ int ha_ndbcluster::get_ndb_value(NdbOperation *ndb_op, Field *field,
|
|||
|
||||
if (field != NULL)
|
||||
{
|
||||
DBUG_ASSERT(buf);
|
||||
if (ndb_supported_type(field->type()))
|
||||
{
|
||||
DBUG_ASSERT(field->ptr != NULL);
|
||||
if (! (field->flags & BLOB_FLAG))
|
||||
{
|
||||
m_value[fieldnr].rec= ndb_op->getValue(fieldnr, field->ptr);
|
||||
byte *field_buf= buf + (field->ptr - table->record[0]);
|
||||
m_value[fieldnr].rec= ndb_op->getValue(fieldnr,
|
||||
field_buf);
|
||||
DBUG_RETURN(m_value[fieldnr].rec == NULL);
|
||||
}
|
||||
|
||||
|
@ -603,7 +607,7 @@ int ha_ndbcluster::get_metadata(const char *path)
|
|||
DBUG_ENTER("get_metadata");
|
||||
DBUG_PRINT("enter", ("m_tabname: %s, path: %s", m_tabname, path));
|
||||
|
||||
if (!(tab= dict->getTable(m_tabname, &m_table_info)))
|
||||
if (!(tab= dict->getTable(m_tabname)))
|
||||
ERR_RETURN(dict->getNdbError());
|
||||
DBUG_PRINT("info", ("Table schema version: %d", tab->getObjectVersion()));
|
||||
|
||||
|
@ -651,8 +655,8 @@ int ha_ndbcluster::get_metadata(const char *path)
|
|||
if (error)
|
||||
DBUG_RETURN(error);
|
||||
|
||||
// All checks OK, lets use the table
|
||||
m_table= (void*)tab;
|
||||
m_table= NULL;
|
||||
m_table_info= NULL;
|
||||
|
||||
DBUG_RETURN(build_index_list(table, ILBP_OPEN));
|
||||
}
|
||||
|
@ -767,6 +771,7 @@ void ha_ndbcluster::release_metadata()
|
|||
DBUG_PRINT("enter", ("m_tabname: %s", m_tabname));
|
||||
|
||||
m_table= NULL;
|
||||
m_table_info= NULL;
|
||||
|
||||
// Release index list
|
||||
for (i= 0; i < MAX_KEY; i++)
|
||||
|
@ -947,7 +952,7 @@ int ha_ndbcluster::pk_read(const byte *key, uint key_len, byte *buf)
|
|||
ERR_RETURN(trans->getNdbError());
|
||||
|
||||
// Read key at the same time, for future reference
|
||||
if (get_ndb_value(op, NULL, no_fields))
|
||||
if (get_ndb_value(op, NULL, no_fields, NULL))
|
||||
ERR_RETURN(trans->getNdbError());
|
||||
}
|
||||
else
|
||||
|
@ -964,7 +969,7 @@ int ha_ndbcluster::pk_read(const byte *key, uint key_len, byte *buf)
|
|||
if ((thd->query_id == field->query_id) ||
|
||||
retrieve_all_fields)
|
||||
{
|
||||
if (get_ndb_value(op, field, i))
|
||||
if (get_ndb_value(op, field, i, buf))
|
||||
ERR_RETURN(trans->getNdbError());
|
||||
}
|
||||
else
|
||||
|
@ -1018,7 +1023,7 @@ int ha_ndbcluster::complemented_pk_read(const byte *old_data, byte *new_data)
|
|||
if (!(field->flags & PRI_KEY_FLAG) &&
|
||||
(thd->query_id != field->query_id))
|
||||
{
|
||||
if (get_ndb_value(op, field, i))
|
||||
if (get_ndb_value(op, field, i, new_data))
|
||||
ERR_RETURN(trans->getNdbError());
|
||||
}
|
||||
}
|
||||
|
@ -1081,7 +1086,7 @@ int ha_ndbcluster::unique_index_read(const byte *key,
|
|||
if ((thd->query_id == field->query_id) ||
|
||||
(field->flags & PRI_KEY_FLAG))
|
||||
{
|
||||
if (get_ndb_value(op, field, i))
|
||||
if (get_ndb_value(op, field, i, buf))
|
||||
ERR_RETURN(op->getNdbError());
|
||||
}
|
||||
else
|
||||
|
@ -1480,7 +1485,7 @@ int ha_ndbcluster::define_read_attrs(byte* buf, NdbOperation* op)
|
|||
(field->flags & PRI_KEY_FLAG) ||
|
||||
retrieve_all_fields)
|
||||
{
|
||||
if (get_ndb_value(op, field, i))
|
||||
if (get_ndb_value(op, field, i, buf))
|
||||
ERR_RETURN(op->getNdbError());
|
||||
}
|
||||
else
|
||||
|
@ -1499,7 +1504,7 @@ int ha_ndbcluster::define_read_attrs(byte* buf, NdbOperation* op)
|
|||
if (!tab->getColumn(hidden_no))
|
||||
DBUG_RETURN(1);
|
||||
#endif
|
||||
if (get_ndb_value(op, NULL, hidden_no))
|
||||
if (get_ndb_value(op, NULL, hidden_no, NULL))
|
||||
ERR_RETURN(op->getNdbError());
|
||||
}
|
||||
|
||||
|
@ -1522,6 +1527,11 @@ int ha_ndbcluster::write_row(byte *record)
|
|||
int res;
|
||||
DBUG_ENTER("write_row");
|
||||
|
||||
if(m_ignore_dup_key_not_supported)
|
||||
{
|
||||
DBUG_RETURN(HA_ERR_WRONG_COMMAND);
|
||||
}
|
||||
|
||||
statistic_increment(ha_write_count,&LOCK_status);
|
||||
if (table->timestamp_default_now)
|
||||
update_timestamp(record+table->timestamp_default_now-1);
|
||||
|
@ -2385,7 +2395,17 @@ void ha_ndbcluster::info(uint flag)
|
|||
if (flag & HA_STATUS_VARIABLE)
|
||||
{
|
||||
DBUG_PRINT("info", ("HA_STATUS_VARIABLE"));
|
||||
records_update();
|
||||
if (m_table_info)
|
||||
{
|
||||
records_update();
|
||||
}
|
||||
else
|
||||
{
|
||||
Uint64 rows;
|
||||
if(ndb_get_table_statistics(m_ndb, m_tabname, &rows, 0) == 0){
|
||||
records= rows;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (flag & HA_STATUS_ERRKEY)
|
||||
{
|
||||
|
@ -2479,14 +2499,20 @@ int ha_ndbcluster::extra(enum ha_extra_function operation)
|
|||
break;
|
||||
case HA_EXTRA_IGNORE_DUP_KEY: /* Dup keys don't rollback everything*/
|
||||
DBUG_PRINT("info", ("HA_EXTRA_IGNORE_DUP_KEY"));
|
||||
|
||||
DBUG_PRINT("info", ("Turning ON use of write instead of insert"));
|
||||
m_use_write= TRUE;
|
||||
if (current_thd->lex->sql_command == SQLCOM_REPLACE)
|
||||
{
|
||||
DBUG_PRINT("info", ("Turning ON use of write instead of insert"));
|
||||
m_use_write= TRUE;
|
||||
} else
|
||||
{
|
||||
m_ignore_dup_key_not_supported= TRUE;
|
||||
}
|
||||
break;
|
||||
case HA_EXTRA_NO_IGNORE_DUP_KEY:
|
||||
DBUG_PRINT("info", ("HA_EXTRA_NO_IGNORE_DUP_KEY"));
|
||||
DBUG_PRINT("info", ("Turning OFF use of write instead of insert"));
|
||||
m_use_write= false;
|
||||
m_ignore_dup_key_not_supported= false;
|
||||
break;
|
||||
case HA_EXTRA_RETRIEVE_ALL_COLS: /* Retrieve all columns, not just those
|
||||
where field->query_id is the same as
|
||||
|
@ -2766,6 +2792,16 @@ int ha_ndbcluster::external_lock(THD *thd, int lock_type)
|
|||
// Start of transaction
|
||||
retrieve_all_fields= FALSE;
|
||||
ops_pending= 0;
|
||||
{
|
||||
NDBDICT *dict= m_ndb->getDictionary();
|
||||
const NDBTAB *tab;
|
||||
void *tab_info;
|
||||
if (!(tab= dict->getTable(m_tabname, &tab_info)))
|
||||
ERR_RETURN(dict->getNdbError());
|
||||
DBUG_PRINT("info", ("Table schema version: %d", tab->getObjectVersion()));
|
||||
m_table= (void *)tab;
|
||||
m_table_info= tab_info;
|
||||
}
|
||||
no_uncommitted_rows_init(thd);
|
||||
}
|
||||
else
|
||||
|
@ -2788,6 +2824,8 @@ int ha_ndbcluster::external_lock(THD *thd, int lock_type)
|
|||
thd->transaction.stmt.ndb_tid= 0;
|
||||
}
|
||||
}
|
||||
m_table= NULL;
|
||||
m_table_info= NULL;
|
||||
if (m_active_trans)
|
||||
DBUG_PRINT("warning", ("m_active_trans != NULL"));
|
||||
if (m_active_cursor)
|
||||
|
@ -3273,6 +3311,7 @@ int ha_ndbcluster::alter_table_name(const char *from, const char *to)
|
|||
ERR_RETURN(dict->getNdbError());
|
||||
|
||||
m_table= NULL;
|
||||
m_table_info= NULL;
|
||||
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
@ -3364,6 +3403,7 @@ ha_ndbcluster::ha_ndbcluster(TABLE *table_arg):
|
|||
HA_NO_PREFIX_CHAR_KEYS),
|
||||
m_share(0),
|
||||
m_use_write(false),
|
||||
m_ignore_dup_key_not_supported(false),
|
||||
retrieve_all_fields(FALSE),
|
||||
rows_to_insert(1),
|
||||
rows_inserted(0),
|
||||
|
|
|
@ -211,7 +211,7 @@ class ha_ndbcluster: public handler
|
|||
int set_ndb_key(NdbOperation*, Field *field,
|
||||
uint fieldnr, const byte* field_ptr);
|
||||
int set_ndb_value(NdbOperation*, Field *field, uint fieldnr);
|
||||
int get_ndb_value(NdbOperation*, Field *field, uint fieldnr);
|
||||
int get_ndb_value(NdbOperation*, Field *field, uint fieldnr, byte*);
|
||||
friend int g_get_ndb_blobs_value(NdbBlob *ndb_blob, void *arg);
|
||||
int get_ndb_blobs_value(NdbBlob *last_ndb_blob);
|
||||
int set_primary_key(NdbOperation *op, const byte *key);
|
||||
|
@ -245,6 +245,7 @@ class ha_ndbcluster: public handler
|
|||
typedef union { NdbRecAttr *rec; NdbBlob *blob; void *ptr; } NdbValue;
|
||||
NdbValue m_value[NDB_MAX_ATTRIBUTES_IN_TABLE];
|
||||
bool m_use_write;
|
||||
bool m_ignore_dup_key_not_supported;
|
||||
bool retrieve_all_fields;
|
||||
ha_rows rows_to_insert;
|
||||
ha_rows rows_inserted;
|
||||
|
|
|
@ -328,6 +328,7 @@ void THD::change_user(void)
|
|||
cleanup();
|
||||
cleanup_done= 0;
|
||||
init();
|
||||
stmt_map.reset();
|
||||
hash_init(&user_vars, &my_charset_bin, USER_VARS_HASH_SIZE, 0, 0,
|
||||
(hash_get_key) get_var_key,
|
||||
(hash_free_key) free_user_var, 0);
|
||||
|
|
|
@ -608,11 +608,18 @@ public:
|
|||
}
|
||||
hash_delete(&st_hash, (byte *) statement);
|
||||
}
|
||||
/* Erase all statements (calls Statement destructor) */
|
||||
void reset()
|
||||
{
|
||||
hash_reset(&names_hash);
|
||||
hash_reset(&st_hash);
|
||||
last_found_statement= 0;
|
||||
}
|
||||
|
||||
~Statement_map()
|
||||
{
|
||||
hash_free(&st_hash);
|
||||
hash_free(&names_hash);
|
||||
hash_free(&st_hash);
|
||||
}
|
||||
private:
|
||||
HASH st_hash;
|
||||
|
|
|
@ -10391,6 +10391,34 @@ static void test_bug5194()
|
|||
}
|
||||
|
||||
|
||||
static void test_bug5315()
|
||||
{
|
||||
MYSQL_STMT *stmt;
|
||||
const char *stmt_text;
|
||||
int rc;
|
||||
|
||||
myheader("test_bug5315");
|
||||
|
||||
stmt_text= "SELECT 1";
|
||||
stmt= mysql_stmt_init(mysql);
|
||||
rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
|
||||
DBUG_ASSERT(rc == 0);
|
||||
mysql_change_user(mysql, opt_user, opt_password, current_db);
|
||||
rc= mysql_stmt_execute(stmt);
|
||||
DBUG_ASSERT(rc != 0);
|
||||
if (rc)
|
||||
printf("Got error (as expected):\n%s", mysql_stmt_error(stmt));
|
||||
/* check that connection is OK */
|
||||
mysql_stmt_close(stmt);
|
||||
stmt= mysql_stmt_init(mysql);
|
||||
rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
|
||||
DBUG_ASSERT(rc == 0);
|
||||
rc= mysql_stmt_execute(stmt);
|
||||
DBUG_ASSERT(rc == 0);
|
||||
mysql_stmt_close(stmt);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Read and parse arguments and MySQL options from my.cnf
|
||||
*/
|
||||
|
@ -10694,6 +10722,8 @@ int main(int argc, char **argv)
|
|||
test_bug5399(); /* check that statement id uniquely identifies
|
||||
statement */
|
||||
test_bug5194(); /* bulk inserts in prepared mode */
|
||||
test_bug5315(); /* check that mysql_change_user closes all
|
||||
prepared statements */
|
||||
/*
|
||||
XXX: PLEASE RUN THIS PROGRAM UNDER VALGRIND AND VERIFY THAT YOUR TEST
|
||||
DOESN'T CONTAIN WARNINGS/ERRORS BEFORE YOU PUSH.
|
||||
|
|
Loading…
Add table
Reference in a new issue