summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mysql-test/r/analyse.result7
-rw-r--r--mysql-test/r/cast.result16
-rw-r--r--mysql-test/r/func_group.result35
-rw-r--r--mysql-test/r/innodb.result2
-rw-r--r--mysql-test/r/myisam.result12
-rw-r--r--mysql-test/r/ndb_autodiscover.result2
-rw-r--r--mysql-test/r/ndb_cache_multi2.result8
-rw-r--r--mysql-test/r/rpl_EE_error.result4
-rw-r--r--mysql-test/r/rpl_rotate_logs.result117
-rw-r--r--mysql-test/r/subselect.result36
-rw-r--r--mysql-test/r/type_bit.result2
-rw-r--r--mysql-test/t/analyse.test8
-rw-r--r--mysql-test/t/cast.test8
-rw-r--r--mysql-test/t/func_group.test22
-rw-r--r--mysql-test/t/innodb.test4
-rw-r--r--mysql-test/t/myisam.test17
-rw-r--r--mysql-test/t/ndb_cache_multi2.test12
-rw-r--r--mysql-test/t/rpl_EE_error.test2
-rw-r--r--mysql-test/t/rpl_rotate_logs.test28
-rw-r--r--mysql-test/t/subselect.test23
-rw-r--r--mysql-test/t/type_bit.test3
-rw-r--r--ndb/src/kernel/blocks/dbdict/Dbdict.cpp4
-rw-r--r--ndb/test/ndbapi/Makefile.am5
-rw-r--r--ndb/test/ndbapi/bench/asyncGenerator.cpp571
-rw-r--r--ndb/test/ndbapi/bench/dbGenerator.h63
-rw-r--r--ndb/test/ndbapi/bench/dbPopulate.cpp244
-rw-r--r--ndb/test/ndbapi/bench/dbPopulate.h59
-rw-r--r--ndb/test/ndbapi/bench/macros.h51
-rw-r--r--ndb/test/ndbapi/bench/mainAsyncGenerator.cpp503
-rw-r--r--ndb/test/ndbapi/bench/mainPopulate.cpp81
-rw-r--r--ndb/test/ndbapi/bench/ndb_async1.cpp647
-rw-r--r--ndb/test/ndbapi/bench/ndb_async2.cpp757
-rw-r--r--ndb/test/ndbapi/bench/ndb_error.hpp81
-rw-r--r--ndb/test/ndbapi/bench/ndb_schema.hpp78
-rw-r--r--ndb/test/ndbapi/bench/ndb_user_transaction.cpp825
-rw-r--r--ndb/test/ndbapi/bench/ndb_user_transaction2.cpp825
-rw-r--r--ndb/test/ndbapi/bench/ndb_user_transaction3.cpp793
-rw-r--r--ndb/test/ndbapi/bench/ndb_user_transaction4.cpp770
-rw-r--r--ndb/test/ndbapi/bench/ndb_user_transaction5.cpp769
-rw-r--r--ndb/test/ndbapi/bench/ndb_user_transaction6.cpp561
-rw-r--r--ndb/test/ndbapi/bench/testData.h156
-rw-r--r--ndb/test/ndbapi/bench/testDefinitions.h90
-rw-r--r--ndb/test/ndbapi/bench/userInterface.cpp744
-rw-r--r--ndb/test/ndbapi/bench/userInterface.h151
-rw-r--r--ndb/test/run-test/daily-basic-tests.txt2
-rw-r--r--ndb/test/run-test/daily-devel-tests.txt29
-rw-r--r--ndb/test/run-test/example.conf10
-rw-r--r--ndb/test/run-test/main.cpp9
-rwxr-xr-xndb/test/run-test/make-html-reports.sh5
-rwxr-xr-xndb/test/run-test/ndb-autotest.sh226
-rw-r--r--ndb/test/run-test/run-test.hpp1
-rw-r--r--scripts/make_binary_distribution.sh2
-rw-r--r--sql/ha_innodb.cc11
-rw-r--r--sql/ha_ndbcluster.cc37
-rw-r--r--sql/handler.cc101
-rw-r--r--sql/handler.h17
-rw-r--r--sql/item_sum.cc3
-rw-r--r--sql/log.cc169
-rw-r--r--sql/log_event.cc11
-rw-r--r--sql/mysqld.cc2
-rw-r--r--sql/sp_head.cc2
-rw-r--r--sql/sql_acl.cc20
-rw-r--r--sql/sql_base.cc23
-rw-r--r--sql/sql_class.h10
-rw-r--r--sql/sql_db.cc12
-rw-r--r--sql/sql_parse.cc40
-rw-r--r--sql/sql_repl.cc46
-rw-r--r--sql/sql_table.cc47
-rw-r--r--sql/sql_yacc.yy1
69 files changed, 9780 insertions, 252 deletions
diff --git a/mysql-test/r/analyse.result b/mysql-test/r/analyse.result
index 83f70a69622..a56902e8ae7 100644
--- a/mysql-test/r/analyse.result
+++ b/mysql-test/r/analyse.result
@@ -102,3 +102,10 @@ select * from t1 procedure analyse();
Field_name Min_value Max_value Min_length Max_length Empties_or_zeros Nulls Avg_value_or_avg_length Std Optimal_fieldtype
test.t1.v " \\ 1 19 0 0 3.7619 NULL ENUM('"','""','"c','\'\0\\"','\'','\'\'','\'b','a\0\0\0b','a\0','a""""b','a\'\'\'\'b','abc','abc\'def\\hij"klm\0opq','a\\\\\\\\b','b\'','c"','d\\','The\ZEnd','\\','\\d','\\\\') NOT NULL
drop table t1;
+create table t1 (df decimal(5,1));
+insert into t1 values(1.1);
+insert into t1 values(2.2);
+select * from t1 procedure analyse();
+Field_name Min_value Max_value Min_length Max_length Empties_or_zeros Nulls Avg_value_or_avg_length Std Optimal_fieldtype
+test.t1.df 1.1 2.2 8 8 0 0 1.650000000 0.302500000 ENUM('1.1','2.2') NOT NULL
+drop table t1;
diff --git a/mysql-test/r/cast.result b/mysql-test/r/cast.result
index 10eb597fa68..57821699f68 100644
--- a/mysql-test/r/cast.result
+++ b/mysql-test/r/cast.result
@@ -187,3 +187,19 @@ timediff(cast('2004-12-30 12:00:00' as time), '12:00:00')
select timediff(cast('1 12:00:00' as time), '12:00:00');
timediff(cast('1 12:00:00' as time), '12:00:00')
24:00:00
+select cast('1.2' as decimal(3,2));
+cast('1.2' as decimal(3,2))
+1.20
+select 1e18 * cast('1.2' as decimal(3,2));
+1e18 * cast('1.2' as decimal(3,2))
+1.2e+18
+select cast(cast('1.2' as decimal(3,2)) as signed);
+cast(cast('1.2' as decimal(3,2)) as signed)
+1
+set @v1=1e18;
+select cast(@v1 as decimal(22, 2));
+cast(@v1 as decimal(22, 2))
+1000000000000000000.00
+select cast(-1e18 as decimal(22,2));
+cast(-1e18 as decimal(22,2))
+-1000000000000000000.00
diff --git a/mysql-test/r/func_group.result b/mysql-test/r/func_group.result
index 0ad992b87e5..b3eee950656 100644
--- a/mysql-test/r/func_group.result
+++ b/mysql-test/r/func_group.result
@@ -769,3 +769,38 @@ show columns from t2;
Field Type Null Key Default Extra
f2 datetime NO 0000-00-00 00:00:00
drop table t2, t1;
+create table t2 (ff double);
+insert into t2 values (2.2);
+select cast(sum(distinct ff) as decimal(5,2)) from t2;
+cast(sum(distinct ff) as decimal(5,2))
+2.20
+select cast(sum(distinct ff) as signed) from t2;
+cast(sum(distinct ff) as signed)
+2
+select cast(variance(ff) as decimal(10,3)) from t2;
+cast(variance(ff) as decimal(10,3))
+0.000
+select cast(min(ff) as decimal(5,2)) from t2;
+cast(min(ff) as decimal(5,2))
+2.20
+create table t1 (df decimal(5,1));
+insert into t1 values(1.1);
+insert into t1 values(2.2);
+select cast(sum(distinct df) as signed) from t1;
+cast(sum(distinct df) as signed)
+3
+select cast(min(df) as signed) from t1;
+cast(min(df) as signed)
+0
+select 1e8 * sum(distinct df) from t1;
+1e8 * sum(distinct df)
+330000000
+select 1e8 * min(df) from t1;
+1e8 * min(df)
+110000000
+create table t3 (ifl int);
+insert into t3 values(1), (2);
+select cast(min(ifl) as decimal(5,2)) from t3;
+cast(min(ifl) as decimal(5,2))
+1.00
+drop table t1, t2, t3;
diff --git a/mysql-test/r/innodb.result b/mysql-test/r/innodb.result
index 13914384d8d..d65ce794a75 100644
--- a/mysql-test/r/innodb.result
+++ b/mysql-test/r/innodb.result
@@ -1798,3 +1798,5 @@ Variable_name Value
innodb_thread_sleep_delay 10000
create table t1 (v varchar(16384)) engine=innodb;
ERROR 42000: Column length too big for column 'v' (max = 255); use BLOB instead
+create table t1 (a bit, key(a)) engine=innodb;
+ERROR 42000: The storage engine for the table doesn't support BIT FIELD
diff --git a/mysql-test/r/myisam.result b/mysql-test/r/myisam.result
index 138cae5cadd..256bc1e3745 100644
--- a/mysql-test/r/myisam.result
+++ b/mysql-test/r/myisam.result
@@ -1150,3 +1150,15 @@ drop table t1;
set storage_engine=MyISAM;
create table t1 (v varchar(65535));
ERROR 42000: Row size too large. The maximum row size for the used table type, not counting BLOBs, is 65535. You have to change some columns to TEXT or BLOBs
+create table t1 (a int) engine=myisam;
+drop table if exists t1;
+Warnings:
+Error 2 Can't find file: 't1' (errno: 2)
+create table t1 (a int) engine=myisam;
+drop table t1;
+Got one of the listed errors
+create table t1 (a int) engine=myisam;
+drop table t1;
+Got one of the listed errors
+drop table t1;
+ERROR 42S02: Unknown table 't1'
diff --git a/mysql-test/r/ndb_autodiscover.result b/mysql-test/r/ndb_autodiscover.result
index afea2fa3e0a..38b34579f03 100644
--- a/mysql-test/r/ndb_autodiscover.result
+++ b/mysql-test/r/ndb_autodiscover.result
@@ -180,7 +180,7 @@ select * from t4;
ERROR 42S02: Table 'test.t4' doesn't exist
drop table if exists t4;
Warnings:
-Note 1051 Unknown table 't4'
+Error 155 Table 'test.t4' doesn't exist
drop table t5;
ERROR 42S02: Unknown table 't5'
drop table if exists t5;
diff --git a/mysql-test/r/ndb_cache_multi2.result b/mysql-test/r/ndb_cache_multi2.result
index 6e435c071b5..2863908a436 100644
--- a/mysql-test/r/ndb_cache_multi2.result
+++ b/mysql-test/r/ndb_cache_multi2.result
@@ -72,3 +72,11 @@ show status like "Qcache_hits";
Variable_name Value
Qcache_hits 0
drop table t1, t2;
+set GLOBAL query_cache_size=0;
+set GLOBAL ndb_cache_check_time=0;
+reset query cache;
+flush status;
+set GLOBAL query_cache_size=0;
+set GLOBAL ndb_cache_check_time=0;
+reset query cache;
+flush status;
diff --git a/mysql-test/r/rpl_EE_error.result b/mysql-test/r/rpl_EE_error.result
index 49ad4832c81..f4765b4b13c 100644
--- a/mysql-test/r/rpl_EE_error.result
+++ b/mysql-test/r/rpl_EE_error.result
@@ -6,7 +6,9 @@ drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
start slave;
create table t1 (a int) engine=myisam;
flush tables;
-drop table t1;
+drop table if exists t1;
+Warnings:
+Error 2 Can't find file: 't1' (errno: 2)
create table t1 (a int, unique(a)) engine=myisam;
set sql_log_bin=0;
insert into t1 values(2);
diff --git a/mysql-test/r/rpl_rotate_logs.result b/mysql-test/r/rpl_rotate_logs.result
index ec29a01db10..745d4d8138e 100644
--- a/mysql-test/r/rpl_rotate_logs.result
+++ b/mysql-test/r/rpl_rotate_logs.result
@@ -92,3 +92,120 @@ count(*)
100
unlock tables;
drop table if exists t1,t2,t3,t4;
+slave stop;
+reset master;
+create table t1 (n int) engine=innodb;
+begin;
+commit;
+drop table t1;
+show binlog events in 'master-bin.000001';
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 4 Format_desc 1 96 Server ver: VERSION, Binlog ver: 4
+master-bin.000001 96 Query 1 197 use `test`; create table t1 (n int) engine=innodb
+master-bin.000001 197 Query 1 266 use `test`; BEGIN
+master-bin.000001 266 Query 1 94 use `test`; insert into t1 values(100 + 4)
+master-bin.000001 360 Query 1 187 use `test`; insert into t1 values(99 + 4)
+master-bin.000001 453 Query 1 280 use `test`; insert into t1 values(98 + 4)
+master-bin.000001 546 Query 1 373 use `test`; insert into t1 values(97 + 4)
+master-bin.000001 639 Query 1 466 use `test`; insert into t1 values(96 + 4)
+master-bin.000001 732 Query 1 559 use `test`; insert into t1 values(95 + 4)
+master-bin.000001 825 Query 1 652 use `test`; insert into t1 values(94 + 4)
+master-bin.000001 918 Query 1 745 use `test`; insert into t1 values(93 + 4)
+master-bin.000001 1011 Query 1 838 use `test`; insert into t1 values(92 + 4)
+master-bin.000001 1104 Query 1 931 use `test`; insert into t1 values(91 + 4)
+master-bin.000001 1197 Query 1 1024 use `test`; insert into t1 values(90 + 4)
+master-bin.000001 1290 Query 1 1117 use `test`; insert into t1 values(89 + 4)
+master-bin.000001 1383 Query 1 1210 use `test`; insert into t1 values(88 + 4)
+master-bin.000001 1476 Query 1 1303 use `test`; insert into t1 values(87 + 4)
+master-bin.000001 1569 Query 1 1396 use `test`; insert into t1 values(86 + 4)
+master-bin.000001 1662 Query 1 1489 use `test`; insert into t1 values(85 + 4)
+master-bin.000001 1755 Query 1 1582 use `test`; insert into t1 values(84 + 4)
+master-bin.000001 1848 Query 1 1675 use `test`; insert into t1 values(83 + 4)
+master-bin.000001 1941 Query 1 1768 use `test`; insert into t1 values(82 + 4)
+master-bin.000001 2034 Query 1 1861 use `test`; insert into t1 values(81 + 4)
+master-bin.000001 2127 Query 1 1954 use `test`; insert into t1 values(80 + 4)
+master-bin.000001 2220 Query 1 2047 use `test`; insert into t1 values(79 + 4)
+master-bin.000001 2313 Query 1 2140 use `test`; insert into t1 values(78 + 4)
+master-bin.000001 2406 Query 1 2233 use `test`; insert into t1 values(77 + 4)
+master-bin.000001 2499 Query 1 2326 use `test`; insert into t1 values(76 + 4)
+master-bin.000001 2592 Query 1 2419 use `test`; insert into t1 values(75 + 4)
+master-bin.000001 2685 Query 1 2512 use `test`; insert into t1 values(74 + 4)
+master-bin.000001 2778 Query 1 2605 use `test`; insert into t1 values(73 + 4)
+master-bin.000001 2871 Query 1 2698 use `test`; insert into t1 values(72 + 4)
+master-bin.000001 2964 Query 1 2791 use `test`; insert into t1 values(71 + 4)
+master-bin.000001 3057 Query 1 2884 use `test`; insert into t1 values(70 + 4)
+master-bin.000001 3150 Query 1 2977 use `test`; insert into t1 values(69 + 4)
+master-bin.000001 3243 Query 1 3070 use `test`; insert into t1 values(68 + 4)
+master-bin.000001 3336 Query 1 3163 use `test`; insert into t1 values(67 + 4)
+master-bin.000001 3429 Query 1 3256 use `test`; insert into t1 values(66 + 4)
+master-bin.000001 3522 Query 1 3349 use `test`; insert into t1 values(65 + 4)
+master-bin.000001 3615 Query 1 3442 use `test`; insert into t1 values(64 + 4)
+master-bin.000001 3708 Query 1 3535 use `test`; insert into t1 values(63 + 4)
+master-bin.000001 3801 Query 1 3628 use `test`; insert into t1 values(62 + 4)
+master-bin.000001 3894 Query 1 3721 use `test`; insert into t1 values(61 + 4)
+master-bin.000001 3987 Query 1 3814 use `test`; insert into t1 values(60 + 4)
+master-bin.000001 4080 Query 1 3907 use `test`; insert into t1 values(59 + 4)
+master-bin.000001 4173 Query 1 4000 use `test`; insert into t1 values(58 + 4)
+master-bin.000001 4266 Query 1 4093 use `test`; insert into t1 values(57 + 4)
+master-bin.000001 4359 Query 1 4186 use `test`; insert into t1 values(56 + 4)
+master-bin.000001 4452 Query 1 4279 use `test`; insert into t1 values(55 + 4)
+master-bin.000001 4545 Query 1 4372 use `test`; insert into t1 values(54 + 4)
+master-bin.000001 4638 Query 1 4465 use `test`; insert into t1 values(53 + 4)
+master-bin.000001 4731 Query 1 4558 use `test`; insert into t1 values(52 + 4)
+master-bin.000001 4824 Query 1 4651 use `test`; insert into t1 values(51 + 4)
+master-bin.000001 4917 Query 1 4744 use `test`; insert into t1 values(50 + 4)
+master-bin.000001 5010 Query 1 4837 use `test`; insert into t1 values(49 + 4)
+master-bin.000001 5103 Query 1 4930 use `test`; insert into t1 values(48 + 4)
+master-bin.000001 5196 Query 1 5023 use `test`; insert into t1 values(47 + 4)
+master-bin.000001 5289 Query 1 5116 use `test`; insert into t1 values(46 + 4)
+master-bin.000001 5382 Query 1 5209 use `test`; insert into t1 values(45 + 4)
+master-bin.000001 5475 Query 1 5302 use `test`; insert into t1 values(44 + 4)
+master-bin.000001 5568 Query 1 5395 use `test`; insert into t1 values(43 + 4)
+master-bin.000001 5661 Query 1 5488 use `test`; insert into t1 values(42 + 4)
+master-bin.000001 5754 Query 1 5581 use `test`; insert into t1 values(41 + 4)
+master-bin.000001 5847 Query 1 5674 use `test`; insert into t1 values(40 + 4)
+master-bin.000001 5940 Query 1 5767 use `test`; insert into t1 values(39 + 4)
+master-bin.000001 6033 Query 1 5860 use `test`; insert into t1 values(38 + 4)
+master-bin.000001 6126 Query 1 5953 use `test`; insert into t1 values(37 + 4)
+master-bin.000001 6219 Query 1 6046 use `test`; insert into t1 values(36 + 4)
+master-bin.000001 6312 Query 1 6139 use `test`; insert into t1 values(35 + 4)
+master-bin.000001 6405 Query 1 6232 use `test`; insert into t1 values(34 + 4)
+master-bin.000001 6498 Query 1 6325 use `test`; insert into t1 values(33 + 4)
+master-bin.000001 6591 Query 1 6418 use `test`; insert into t1 values(32 + 4)
+master-bin.000001 6684 Query 1 6511 use `test`; insert into t1 values(31 + 4)
+master-bin.000001 6777 Query 1 6604 use `test`; insert into t1 values(30 + 4)
+master-bin.000001 6870 Query 1 6697 use `test`; insert into t1 values(29 + 4)
+master-bin.000001 6963 Query 1 6790 use `test`; insert into t1 values(28 + 4)
+master-bin.000001 7056 Query 1 6883 use `test`; insert into t1 values(27 + 4)
+master-bin.000001 7149 Query 1 6976 use `test`; insert into t1 values(26 + 4)
+master-bin.000001 7242 Query 1 7069 use `test`; insert into t1 values(25 + 4)
+master-bin.000001 7335 Query 1 7162 use `test`; insert into t1 values(24 + 4)
+master-bin.000001 7428 Query 1 7255 use `test`; insert into t1 values(23 + 4)
+master-bin.000001 7521 Query 1 7348 use `test`; insert into t1 values(22 + 4)
+master-bin.000001 7614 Query 1 7441 use `test`; insert into t1 values(21 + 4)
+master-bin.000001 7707 Query 1 7534 use `test`; insert into t1 values(20 + 4)
+master-bin.000001 7800 Query 1 7627 use `test`; insert into t1 values(19 + 4)
+master-bin.000001 7893 Query 1 7720 use `test`; insert into t1 values(18 + 4)
+master-bin.000001 7986 Query 1 7813 use `test`; insert into t1 values(17 + 4)
+master-bin.000001 8079 Query 1 7906 use `test`; insert into t1 values(16 + 4)
+master-bin.000001 8172 Query 1 7999 use `test`; insert into t1 values(15 + 4)
+master-bin.000001 8265 Query 1 8092 use `test`; insert into t1 values(14 + 4)
+master-bin.000001 8358 Query 1 8185 use `test`; insert into t1 values(13 + 4)
+master-bin.000001 8451 Query 1 8278 use `test`; insert into t1 values(12 + 4)
+master-bin.000001 8544 Query 1 8371 use `test`; insert into t1 values(11 + 4)
+master-bin.000001 8637 Query 1 8464 use `test`; insert into t1 values(10 + 4)
+master-bin.000001 8730 Query 1 8556 use `test`; insert into t1 values(9 + 4)
+master-bin.000001 8822 Query 1 8648 use `test`; insert into t1 values(8 + 4)
+master-bin.000001 8914 Query 1 8740 use `test`; insert into t1 values(7 + 4)
+master-bin.000001 9006 Query 1 8832 use `test`; insert into t1 values(6 + 4)
+master-bin.000001 9098 Query 1 8924 use `test`; insert into t1 values(5 + 4)
+master-bin.000001 9190 Query 1 9016 use `test`; insert into t1 values(4 + 4)
+master-bin.000001 9282 Query 1 9108 use `test`; insert into t1 values(3 + 4)
+master-bin.000001 9374 Query 1 9200 use `test`; insert into t1 values(2 + 4)
+master-bin.000001 9466 Query 1 9292 use `test`; insert into t1 values(1 + 4)
+master-bin.000001 9558 Xid 1 9319 COMMIT /* xid=146 */
+master-bin.000001 9585 Rotate 1 9629 master-bin.000002;pos=4
+show binlog events in 'master-bin.000002';
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000002 4 Format_desc 1 96 Server ver: VERSION, Binlog ver: 4
+master-bin.000002 96 Query 1 173 use `test`; drop table t1
diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result
index bb9ac2ff4eb..49006a6fecf 100644
--- a/mysql-test/r/subselect.result
+++ b/mysql-test/r/subselect.result
@@ -2276,3 +2276,39 @@ pass userid parentid parentgroup childid groupname grouptypeid crse categoryid c
1 5141 12 group2 12 group2 5 1 2 88 Oct04
1 5141 12 group2 12 group2 5 1 2 89 Oct04
drop table if exists t1, t2, t3, t4, t5;
+create table t1 (df decimal(5,1));
+insert into t1 values(1.1);
+insert into t1 values(2.2);
+select * from t1 where df <= all (select avg(df) from t1 group by df);
+df
+1.1
+select * from t1 where df >= all (select avg(df) from t1 group by df);
+df
+2.2
+drop table t1;
+create table t1 (df decimal(5,1));
+insert into t1 values(1.1);
+select 1.1 * exists(select * from t1);
+1.1 * exists(select * from t1)
+1.1
+drop table t1;
+CREATE TABLE t1 (
+grp int(11) default NULL,
+a decimal(10,2) default NULL);
+insert into t1 values (1, 1), (2, 2), (2, 3), (3, 4), (3, 5), (3, 6), (NULL, NULL);
+select * from t1;
+grp a
+1 1.00
+2 2.00
+2 3.00
+3 4.00
+3 5.00
+3 6.00
+NULL NULL
+select min(a) from t1 group by grp;
+min(a)
+NULL
+1.00
+2.00
+4.00
+drop table t1;
diff --git a/mysql-test/r/type_bit.result b/mysql-test/r/type_bit.result
index 88bb04fefba..dde50a1ee00 100644
--- a/mysql-test/r/type_bit.result
+++ b/mysql-test/r/type_bit.result
@@ -44,8 +44,6 @@ t1 CREATE TABLE `t1` (
`a` bit(1) default NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
-create table t1 (a bit, key(a)) engine=innodb;
-ERROR 42000: The storage engine for the table doesn't support BIT FIELD
create table t1 (a bit(64));
insert into t1 values
(b'1111111111111111111111111111111111111111111111111111111111111111'),
diff --git a/mysql-test/t/analyse.test b/mysql-test/t/analyse.test
index 52e367769a2..f5523f83226 100644
--- a/mysql-test/t/analyse.test
+++ b/mysql-test/t/analyse.test
@@ -47,3 +47,11 @@ create table t1 (v varchar(128));
insert into t1 values ('abc'),('abc\'def\\hij\"klm\0opq'),('\''),('\"'),('\\'),('a\0'),('b\''),('c\"'),('d\\'),('\'b'),('\"c'),('\\d'),('a\0\0\0b'),('a\'\'\'\'b'),('a\"\"\"\"b'),('a\\\\\\\\b'),('\'\0\\\"'),('\'\''),('\"\"'),('\\\\'),('The\ZEnd');
select * from t1 procedure analyse();
drop table t1;
+
+#decimal-related test
+
+create table t1 (df decimal(5,1));
+insert into t1 values(1.1);
+insert into t1 values(2.2);
+select * from t1 procedure analyse();
+drop table t1;
diff --git a/mysql-test/t/cast.test b/mysql-test/t/cast.test
index 23bba7d5aff..5866431e687 100644
--- a/mysql-test/t/cast.test
+++ b/mysql-test/t/cast.test
@@ -118,3 +118,11 @@ select date_add(cast('2004-12-30 12:00:00' as date), interval 0 hour);
select timediff(cast('2004-12-30 12:00:00' as time), '12:00:00');
# Still we should not throw away "days" part of time value
select timediff(cast('1 12:00:00' as time), '12:00:00');
+
+#decimal-related additions
+select cast('1.2' as decimal(3,2));
+select 1e18 * cast('1.2' as decimal(3,2));
+select cast(cast('1.2' as decimal(3,2)) as signed);
+set @v1=1e18;
+select cast(@v1 as decimal(22, 2));
+select cast(-1e18 as decimal(22,2));
diff --git a/mysql-test/t/func_group.test b/mysql-test/t/func_group.test
index 60eefe2a104..b6e6664d1b8 100644
--- a/mysql-test/t/func_group.test
+++ b/mysql-test/t/func_group.test
@@ -492,3 +492,25 @@ drop table t2;
create table t2 select f2 from (select now() f2 from t1) a;
show columns from t2;
drop table t2, t1;
+
+# decimal-related tests
+create table t2 (ff double);
+insert into t2 values (2.2);
+select cast(sum(distinct ff) as decimal(5,2)) from t2;
+select cast(sum(distinct ff) as signed) from t2;
+select cast(variance(ff) as decimal(10,3)) from t2;
+select cast(min(ff) as decimal(5,2)) from t2;
+
+create table t1 (df decimal(5,1));
+insert into t1 values(1.1);
+insert into t1 values(2.2);
+select cast(sum(distinct df) as signed) from t1;
+select cast(min(df) as signed) from t1;
+select 1e8 * sum(distinct df) from t1;
+select 1e8 * min(df) from t1;
+
+create table t3 (ifl int);
+insert into t3 values(1), (2);
+select cast(min(ifl) as decimal(5,2)) from t3;
+
+drop table t1, t2, t3;
diff --git a/mysql-test/t/innodb.test b/mysql-test/t/innodb.test
index 3cfd173165b..6514f3d5c94 100644
--- a/mysql-test/t/innodb.test
+++ b/mysql-test/t/innodb.test
@@ -1278,3 +1278,7 @@ show variables like "innodb_thread_sleep_delay";
# InnoDB specific varchar tests
--error 1074
create table t1 (v varchar(16384)) engine=innodb;
+
+# The following should be moved to type_bit.test when innodb will support it
+--error 1178
+create table t1 (a bit, key(a)) engine=innodb;
diff --git a/mysql-test/t/myisam.test b/mysql-test/t/myisam.test
index 44ff789632d..f919bfced77 100644
--- a/mysql-test/t/myisam.test
+++ b/mysql-test/t/myisam.test
@@ -539,3 +539,20 @@ eval set storage_engine=$default;
# MyISAM specific varchar tests
--error 1118
create table t1 (v varchar(65535));
+
+#
+# Test how DROP TABLE works if the index or data file doesn't exists
+
+create table t1 (a int) engine=myisam;
+system rm ./var/master-data/test/t1.MYI ;
+drop table if exists t1;
+create table t1 (a int) engine=myisam;
+system rm ./var/master-data/test/t1.MYI ;
+--error 1051,6
+drop table t1;
+create table t1 (a int) engine=myisam;
+system rm ./var/master-data/test/t1.MYD ;
+--error 1105,6
+drop table t1;
+--error 1051
+drop table t1;
diff --git a/mysql-test/t/ndb_cache_multi2.test b/mysql-test/t/ndb_cache_multi2.test
index a9d008dba7c..f9ccb0bf53e 100644
--- a/mysql-test/t/ndb_cache_multi2.test
+++ b/mysql-test/t/ndb_cache_multi2.test
@@ -68,4 +68,14 @@ show status like "Qcache_hits";
drop table t1, t2;
-
+# Turn off and reset query cache on server1 and server2
+connection server1;
+set GLOBAL query_cache_size=0;
+set GLOBAL ndb_cache_check_time=0;
+reset query cache;
+flush status;
+connection server2;
+set GLOBAL query_cache_size=0;
+set GLOBAL ndb_cache_check_time=0;
+reset query cache;
+flush status;
diff --git a/mysql-test/t/rpl_EE_error.test b/mysql-test/t/rpl_EE_error.test
index 1a1572b48b0..90d8c36685f 100644
--- a/mysql-test/t/rpl_EE_error.test
+++ b/mysql-test/t/rpl_EE_error.test
@@ -9,7 +9,7 @@ source include/master-slave.inc;
create table t1 (a int) engine=myisam;
flush tables;
system rm ./var/master-data/test/t1.MYI ;
-drop table t1;
+drop table if exists t1;
save_master_pos;
connection slave;
sync_with_master;
diff --git a/mysql-test/t/rpl_rotate_logs.test b/mysql-test/t/rpl_rotate_logs.test
index 2b5c72d16d2..850d3c1741c 100644
--- a/mysql-test/t/rpl_rotate_logs.test
+++ b/mysql-test/t/rpl_rotate_logs.test
@@ -152,3 +152,31 @@ unlock tables;
connection master;
drop table if exists t1,t2,t3,t4;
sync_slave_with_master;
+
+#
+# now the same in a transaction
+#
+slave stop; # we don't need it anymore
+connection master;
+reset master;
+let $1=100;
+
+--disable_warnings
+create table t1 (n int) engine=innodb;
+--enable_warnings
+begin;
+--disable_query_log
+while ($1)
+{
+ eval insert into t1 values($1 + 4);
+ dec $1;
+}
+--enable_query_log
+commit;
+drop table t1;
+let $VERSION=`select version()`;
+--replace_result $VERSION VERSION
+show binlog events in 'master-bin.000001';
+--replace_result $VERSION VERSION
+show binlog events in 'master-bin.000002';
+
diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test
index 429012e8a36..cfcb32f37c8 100644
--- a/mysql-test/t/subselect.test
+++ b/mysql-test/t/subselect.test
@@ -1543,3 +1543,26 @@ group by
drop table if exists t1, t2, t3, t4, t5;
+
+#decimal-related tests
+create table t1 (df decimal(5,1));
+insert into t1 values(1.1);
+insert into t1 values(2.2);
+
+select * from t1 where df <= all (select avg(df) from t1 group by df);
+select * from t1 where df >= all (select avg(df) from t1 group by df);
+drop table t1;
+
+create table t1 (df decimal(5,1));
+insert into t1 values(1.1);
+select 1.1 * exists(select * from t1);
+drop table t1;
+
+CREATE TABLE t1 (
+ grp int(11) default NULL,
+ a decimal(10,2) default NULL);
+
+insert into t1 values (1, 1), (2, 2), (2, 3), (3, 4), (3, 5), (3, 6), (NULL, NULL);
+select * from t1;
+select min(a) from t1 group by grp;
+drop table t1;
diff --git a/mysql-test/t/type_bit.test b/mysql-test/t/type_bit.test
index fed15806765..f00fcfef7ab 100644
--- a/mysql-test/t/type_bit.test
+++ b/mysql-test/t/type_bit.test
@@ -26,9 +26,6 @@ create table t1 (a bit(0));
show create table t1;
drop table t1;
---error 1178
-create table t1 (a bit, key(a)) engine=innodb;
-
create table t1 (a bit(64));
insert into t1 values
(b'1111111111111111111111111111111111111111111111111111111111111111'),
diff --git a/ndb/src/kernel/blocks/dbdict/Dbdict.cpp b/ndb/src/kernel/blocks/dbdict/Dbdict.cpp
index 30b3e88bd82..15abbf007e4 100644
--- a/ndb/src/kernel/blocks/dbdict/Dbdict.cpp
+++ b/ndb/src/kernel/blocks/dbdict/Dbdict.cpp
@@ -2245,9 +2245,9 @@ void Dbdict::checkSchemaStatus(Signal* signal)
restartCreateTab(signal, tableId, oldEntry, false);
return;
}//if
- ndbrequire(ok);
- break;
}
+ ndbrequire(ok);
+ break;
}
case SchemaFile::DROP_TABLE_STARTED:
jam();
diff --git a/ndb/test/ndbapi/Makefile.am b/ndb/test/ndbapi/Makefile.am
index 7d12714b3bd..5eb3c215ee5 100644
--- a/ndb/test/ndbapi/Makefile.am
+++ b/ndb/test/ndbapi/Makefile.am
@@ -32,7 +32,8 @@ testTransactions \
testDeadlock \
test_event ndbapi_slow_select testReadPerf testLcp \
testPartitioning \
-testBitfield
+testBitfield \
+DbCreate DbAsyncGenerator
#flexTimedAsynch
#testBlobs
@@ -73,6 +74,8 @@ testReadPerf_SOURCES = testReadPerf.cpp
testLcp_SOURCES = testLcp.cpp
testPartitioning_SOURCES = testPartitioning.cpp
testBitfield_SOURCES = testBitfield.cpp
+DbCreate_SOURCES= bench/mainPopulate.cpp bench/dbPopulate.cpp bench/userInterface.cpp
+DbAsyncGenerator_SOURCES= bench/mainAsyncGenerator.cpp bench/asyncGenerator.cpp bench/ndb_async2.cpp
INCLUDES_LOC = -I$(top_srcdir)/ndb/include/kernel
diff --git a/ndb/test/ndbapi/bench/asyncGenerator.cpp b/ndb/test/ndbapi/bench/asyncGenerator.cpp
new file mode 100644
index 00000000000..d91e38dff1a
--- /dev/null
+++ b/ndb/test/ndbapi/bench/asyncGenerator.cpp
@@ -0,0 +1,571 @@
+/* Copyright (C) 2003 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/***************************************************************
+* I N C L U D E D F I L E S *
+***************************************************************/
+
+#include <ndb_global.h>
+
+#include "dbGenerator.h"
+#include <NdbApi.hpp>
+#include <NdbOut.hpp>
+#include <NdbSleep.h>
+
+/***************************************************************
+* L O C A L C O N S T A N T S *
+***************************************************************/
+
+/***************************************************************
+* L O C A L D A T A S T R U C T U R E S *
+***************************************************************/
+
+/***************************************************************
+* L O C A L F U N C T I O N S *
+***************************************************************/
+
+static void getRandomSubscriberNumber(SubscriberNumber number);
+static void getRandomServerId(ServerId *serverId);
+static void getRandomChangedBy(ChangedBy changedBy);
+static void getRandomChangedTime(ChangedTime changedTime);
+
+static void clearTransaction(TransactionDefinition *trans);
+static void initGeneratorStatistics(GeneratorStatistics *gen);
+
+static void doOneTransaction(ThreadData * td,
+ int parallellism,
+ int millisSendPoll,
+ int minEventSendPoll,
+ int forceSendPoll);
+static void doTransaction_T1(Ndb * pNDB, ThreadData * td, int async);
+static void doTransaction_T2(Ndb * pNDB, ThreadData * td, int async);
+static void doTransaction_T3(Ndb * pNDB, ThreadData * td, int async);
+static void doTransaction_T4(Ndb * pNDB, ThreadData * td, int async);
+static void doTransaction_T5(Ndb * pNDB, ThreadData * td, int async);
+
+/***************************************************************
+* L O C A L D A T A *
+***************************************************************/
+
+static SequenceValues transactionDefinition[] = {
+ {25, 1},
+ {25, 2},
+ {20, 3},
+ {15, 4},
+ {15, 5},
+ {0, 0}
+};
+
+static SequenceValues rollbackDefinition[] = {
+ {98, 0},
+ {2 , 1},
+ {0, 0}
+};
+
+static int maxsize = 0;
+
+/***************************************************************
+* P U B L I C D A T A *
+***************************************************************/
+
+/***************************************************************
+****************************************************************
+* L O C A L F U N C T I O N S C O D E S E C T I O N *
+****************************************************************
+***************************************************************/
+
+static void getRandomSubscriberNumber(SubscriberNumber number)
+{
+ uint32 tmp;
+ char sbuf[SUBSCRIBER_NUMBER_LENGTH + 1];
+ tmp = myRandom48(NO_OF_SUBSCRIBERS);
+ sprintf(sbuf, "%.*d", SUBSCRIBER_NUMBER_LENGTH, tmp);
+ memcpy(number, sbuf, SUBSCRIBER_NUMBER_LENGTH);
+}
+
+static void getRandomServerId(ServerId *serverId)
+{
+ *serverId = myRandom48(NO_OF_SERVERS);
+}
+
+static void getRandomChangedBy(ChangedBy changedBy)
+{
+ memset(changedBy, myRandom48(26)+'A', CHANGED_BY_LENGTH);
+ changedBy[CHANGED_BY_LENGTH] = 0;
+}
+
+static void getRandomChangedTime(ChangedTime changedTime)
+{
+ memset(changedTime, myRandom48(26)+'A', CHANGED_TIME_LENGTH);
+ changedTime[CHANGED_TIME_LENGTH] = 0;
+}
+
+static void clearTransaction(TransactionDefinition *trans)
+{
+ trans->count = 0;
+ trans->branchExecuted = 0;
+ trans->rollbackExecuted = 0;
+ trans->latencyCounter = myRandom48(127);
+ trans->latency.reset();
+}
+
+static int listFull(SessionList *list)
+{
+ return(list->numberInList == SESSION_LIST_LENGTH);
+}
+
+static int listEmpty(SessionList *list)
+{
+ return(list->numberInList == 0);
+}
+
+static void insertSession(SessionList *list,
+ SubscriberNumber number,
+ ServerId serverId)
+{
+ SessionElement *e;
+ if( listFull(list) ) return;
+
+ e = &list->list[list->writeIndex];
+
+ strcpy(e->subscriberNumber, number);
+ e->serverId = serverId;
+
+ list->writeIndex = (list->writeIndex + 1) % SESSION_LIST_LENGTH;
+ list->numberInList++;
+
+ if( list->numberInList > maxsize )
+ maxsize = list->numberInList;
+}
+
+static SessionElement *getNextSession(SessionList *list)
+{
+ if( listEmpty(list) ) return(0);
+
+ return(&list->list[list->readIndex]);
+}
+
+static void deleteSession(SessionList *list)
+{
+ if( listEmpty(list) ) return;
+
+ list->readIndex = (list->readIndex + 1) % SESSION_LIST_LENGTH;
+ list->numberInList--;
+}
+
+static void initGeneratorStatistics(GeneratorStatistics *gen)
+{
+ int i;
+
+ if( initSequence(&gen->transactionSequence,
+ transactionDefinition) != 0 ) {
+ ndbout_c("could not set the transaction types");
+ exit(0);
+ }
+
+ if( initSequence(&gen->rollbackSequenceT4,
+ rollbackDefinition) != 0 ) {
+ ndbout_c("could not set the rollback sequence");
+ exit(0);
+ }
+
+ if( initSequence(&gen->rollbackSequenceT5,
+ rollbackDefinition) != 0 ) {
+ ndbout_c("could not set the rollback sequence");
+ exit(0);
+ }
+
+ for(i = 0; i < NUM_TRANSACTION_TYPES; i++ )
+ clearTransaction(&gen->transactions[i]);
+
+ gen->totalTransactions = 0;
+
+ gen->activeSessions.numberInList = 0;
+ gen->activeSessions.readIndex = 0;
+ gen->activeSessions.writeIndex = 0;
+}
+
+
+static
+void
+doOneTransaction(ThreadData * td, int p, int millis, int minEvents, int force)
+{
+ int i;
+ unsigned int transactionType;
+ int async = 1;
+ if (p == 1) {
+ async = 0;
+ }//if
+ for(i = 0; i<p; i++){
+ if(td[i].runState == Runnable){
+ transactionType = getNextRandom(&td[i].generator.transactionSequence);
+
+ switch(transactionType) {
+ case 1:
+ doTransaction_T1(td[i].pNDB, &td[i], async);
+ break;
+ case 2:
+ doTransaction_T2(td[i].pNDB, &td[i], async);
+ break;
+ case 3:
+ doTransaction_T3(td[i].pNDB, &td[i], async);
+ break;
+ case 4:
+ doTransaction_T4(td[i].pNDB, &td[i], async);
+ break;
+ case 5:
+ doTransaction_T5(td[i].pNDB, &td[i], async);
+ break;
+ default:
+ ndbout_c("Unknown transaction type: %d", transactionType);
+ }
+ }
+ }
+ if (async == 1) {
+ td[0].pNDB->sendPollNdb(millis, minEvents, force);
+ }//if
+}
+
+static
+void
+doTransaction_T1(Ndb * pNDB, ThreadData * td, int async)
+{
+ /*----------------*/
+ /* Init arguments */
+ /*----------------*/
+ getRandomSubscriberNumber(td->transactionData.number);
+ getRandomChangedBy(td->transactionData.changed_by);
+ BaseString::snprintf(td->transactionData.changed_time,
+ sizeof(td->transactionData.changed_time),
+ "%ld - %d", td->changedTime++, myRandom48(65536*1024));
+ //getRandomChangedTime(td->transactionData.changed_time);
+ td->transactionData.location = td->transactionData.changed_by[0];
+
+ /*-----------------*/
+ /* Run transaction */
+ /*-----------------*/
+ td->runState = Running;
+ td->generator.transactions[0].startLatency();
+
+ start_T1(pNDB, td, async);
+}
+
+static
+void
+doTransaction_T2(Ndb * pNDB, ThreadData * td, int async)
+{
+ /*----------------*/
+ /* Init arguments */
+ /*----------------*/
+ getRandomSubscriberNumber(td->transactionData.number);
+
+ /*-----------------*/
+ /* Run transaction */
+ /*-----------------*/
+ td->runState = Running;
+ td->generator.transactions[1].startLatency();
+
+ start_T2(pNDB, td, async);
+}
+
+static
+void
+doTransaction_T3(Ndb * pNDB, ThreadData * td, int async)
+{
+ SessionElement *se;
+
+ /*----------------*/
+ /* Init arguments */
+ /*----------------*/
+ se = getNextSession(&td->generator.activeSessions);
+ if( se ) {
+ strcpy(td->transactionData.number, se->subscriberNumber);
+ td->transactionData.server_id = se->serverId;
+ td->transactionData.sessionElement = 1;
+ } else {
+ getRandomSubscriberNumber(td->transactionData.number);
+ getRandomServerId(&td->transactionData.server_id);
+ td->transactionData.sessionElement = 0;
+ }
+
+ td->transactionData.server_bit = (1 << td->transactionData.server_id);
+
+ /*-----------------*/
+ /* Run transaction */
+ /*-----------------*/
+ td->runState = Running;
+ td->generator.transactions[2].startLatency();
+ start_T3(pNDB, td, async);
+}
+
+static
+void
+doTransaction_T4(Ndb * pNDB, ThreadData * td, int async)
+{
+ /*----------------*/
+ /* Init arguments */
+ /*----------------*/
+ getRandomSubscriberNumber(td->transactionData.number);
+ getRandomServerId(&td->transactionData.server_id);
+
+ td->transactionData.server_bit = (1 << td->transactionData.server_id);
+ td->transactionData.do_rollback =
+ getNextRandom(&td->generator.rollbackSequenceT4);
+
+#if 0
+ memset(td->transactionData.session_details,
+ myRandom48(26)+'A', SESSION_DETAILS_LENGTH);
+#endif
+ td->transactionData.session_details[SESSION_DETAILS_LENGTH] = 0;
+
+ /*-----------------*/
+ /* Run transaction */
+ /*-----------------*/
+ td->runState = Running;
+ td->generator.transactions[3].startLatency();
+ start_T4(pNDB, td, async);
+}
+
+static
+void
+doTransaction_T5(Ndb * pNDB, ThreadData * td, int async)
+{
+ SessionElement * se;
+ se = getNextSession(&td->generator.activeSessions);
+ if( se ) {
+ strcpy(td->transactionData.number, se->subscriberNumber);
+ td->transactionData.server_id = se->serverId;
+ td->transactionData.sessionElement = 1;
+ }
+ else {
+ getRandomSubscriberNumber(td->transactionData.number);
+ getRandomServerId(&td->transactionData.server_id);
+ td->transactionData.sessionElement = 0;
+ }
+
+ td->transactionData.server_bit = (1 << td->transactionData.server_id);
+ td->transactionData.do_rollback
+ = getNextRandom(&td->generator.rollbackSequenceT5);
+
+ /*-----------------*/
+ /* Run transaction */
+ /*-----------------*/
+ td->runState = Running;
+ td->generator.transactions[4].startLatency();
+ start_T5(pNDB, td, async);
+}
+
+void
+complete_T1(ThreadData * data){
+ data->generator.transactions[0].stopLatency();
+ data->generator.transactions[0].count++;
+
+ data->runState = Runnable;
+ data->generator.totalTransactions++;
+}
+
+void
+complete_T2(ThreadData * data){
+ data->generator.transactions[1].stopLatency();
+ data->generator.transactions[1].count++;
+
+ data->runState = Runnable;
+ data->generator.totalTransactions++;
+}
+
+void
+complete_T3(ThreadData * data){
+
+ data->generator.transactions[2].stopLatency();
+ data->generator.transactions[2].count++;
+
+ if(data->transactionData.branchExecuted)
+ data->generator.transactions[2].branchExecuted++;
+
+ data->runState = Runnable;
+ data->generator.totalTransactions++;
+}
+
+void
+complete_T4(ThreadData * data){
+
+ data->generator.transactions[3].stopLatency();
+ data->generator.transactions[3].count++;
+
+ if(data->transactionData.branchExecuted)
+ data->generator.transactions[3].branchExecuted++;
+ if(data->transactionData.do_rollback)
+ data->generator.transactions[3].rollbackExecuted++;
+
+ if(data->transactionData.branchExecuted &&
+ !data->transactionData.do_rollback){
+ insertSession(&data->generator.activeSessions,
+ data->transactionData.number,
+ data->transactionData.server_id);
+ }
+
+ data->runState = Runnable;
+ data->generator.totalTransactions++;
+
+}
+void
+complete_T5(ThreadData * data){
+
+ data->generator.transactions[4].stopLatency();
+ data->generator.transactions[4].count++;
+
+ if(data->transactionData.branchExecuted)
+ data->generator.transactions[4].branchExecuted++;
+ if(data->transactionData.do_rollback)
+ data->generator.transactions[4].rollbackExecuted++;
+
+ if(data->transactionData.sessionElement &&
+ !data->transactionData.do_rollback){
+ deleteSession(&data->generator.activeSessions);
+ }
+
+ data->runState = Runnable;
+ data->generator.totalTransactions++;
+}
+
+/***************************************************************
+****************************************************************
+* P U B L I C F U N C T I O N S C O D E S E C T I O N *
+****************************************************************
+***************************************************************/
+void
+asyncGenerator(ThreadData *data,
+ int parallellism,
+ int millisSendPoll,
+ int minEventSendPoll,
+ int forceSendPoll)
+{
+ ThreadData * startUp;
+
+ GeneratorStatistics *st;
+ double periodStop;
+ double benchTimeStart;
+ double benchTimeEnd;
+ int i, j, done;
+
+ myRandom48Init(data->randomSeed);
+
+ for(i = 0; i<parallellism; i++){
+ initGeneratorStatistics(&data[i].generator);
+ }
+
+ startUp = (ThreadData*)malloc(parallellism * sizeof(ThreadData));
+ memcpy(startUp, data, (parallellism * sizeof(ThreadData)));
+
+ /*----------------*/
+ /* warm up period */
+ /*----------------*/
+ periodStop = userGetTime() + (double)data[0].warmUpSeconds;
+
+ while(userGetTime() < periodStop){
+ doOneTransaction(startUp, parallellism,
+ millisSendPoll, minEventSendPoll, forceSendPoll);
+ }
+
+ ndbout_c("Waiting for startup to finish");
+
+ /**
+ * Wait for all transactions
+ */
+ done = 0;
+ while(!done){
+ done = 1;
+ for(i = 0; i<parallellism; i++){
+ if(startUp[i].runState != Runnable){
+ done = 0;
+ break;
+ }
+ }
+ if(!done){
+ startUp[0].pNDB->sendPollNdb();
+ }
+ }
+ ndbout_c("Benchmark period starts");
+
+ /*-------------------------*/
+ /* normal benchmark period */
+ /*-------------------------*/
+ benchTimeStart = userGetTime();
+
+ periodStop = benchTimeStart + (double)data[0].testSeconds;
+ while(userGetTime() < periodStop)
+ doOneTransaction(data, parallellism,
+ millisSendPoll, minEventSendPoll, forceSendPoll);
+
+ benchTimeEnd = userGetTime();
+
+ ndbout_c("Benchmark period done");
+
+ /**
+ * Wait for all transactions
+ */
+ done = 0;
+ while(!done){
+ done = 1;
+ for(i = 0; i<parallellism; i++){
+ if(data[i].runState != Runnable){
+ done = 0;
+ break;
+ }
+ }
+ if(!done){
+ data[0].pNDB->sendPollNdb();
+ }
+ }
+
+ /*------------------*/
+ /* cool down period */
+ /*------------------*/
+ periodStop = userGetTime() + (double)data[0].coolDownSeconds;
+ while(userGetTime() < periodStop){
+ doOneTransaction(startUp, parallellism,
+ millisSendPoll, minEventSendPoll, forceSendPoll);
+ }
+
+ done = 0;
+ while(!done){
+ done = 1;
+ for(i = 0; i<parallellism; i++){
+ if(startUp[i].runState != Runnable){
+ done = 0;
+ break;
+ }
+ }
+ if(!done){
+ startUp[0].pNDB->sendPollNdb();
+ }
+ }
+
+
+ /*---------------------------------------------------------*/
+ /* add the times for all transaction for inner loop timing */
+ /*---------------------------------------------------------*/
+ for(j = 0; j<parallellism; j++){
+ st = &data[j].generator;
+
+ st->outerLoopTime = benchTimeEnd - benchTimeStart;
+ st->outerTps = getTps(st->totalTransactions, st->outerLoopTime);
+ }
+ /* ndbout_c("maxsize = %d\n",maxsize); */
+
+ free(startUp);
+}
+
diff --git a/ndb/test/ndbapi/bench/dbGenerator.h b/ndb/test/ndbapi/bench/dbGenerator.h
new file mode 100644
index 00000000000..2256498e151
--- /dev/null
+++ b/ndb/test/ndbapi/bench/dbGenerator.h
@@ -0,0 +1,63 @@
+/* Copyright (C) 2003 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#ifndef DBGENERATOR_H
+#define DBGENERATOR_H
+
+/***************************************************************
+* I N C L U D E D F I L E S *
+***************************************************************/
+
+#include "testData.h"
+#include "userInterface.h"
+
+/***************************************************************
+* M A C R O S *
+***************************************************************/
+
+/***************************************************************/
+/* C O N S T A N T S */
+/***************************************************************/
+
+/***************************************************************
+* D A T A S T R U C T U R E S *
+***************************************************************/
+
+/***************************************************************
+* P U B L I C F U N C T I O N S *
+***************************************************************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern void asyncGenerator(ThreadData *d, int parallellism,
+ int millisSendPoll,
+ int minEventSendPoll,
+ int forceSendPoll);
+
+#ifdef __cplusplus
+}
+#endif
+
+/***************************************************************
+* E X T E R N A L D A T A *
+***************************************************************/
+
+
+
+#endif /* DBGENERATOR_H */
+
diff --git a/ndb/test/ndbapi/bench/dbPopulate.cpp b/ndb/test/ndbapi/bench/dbPopulate.cpp
new file mode 100644
index 00000000000..42fbb52f3b2
--- /dev/null
+++ b/ndb/test/ndbapi/bench/dbPopulate.cpp
@@ -0,0 +1,244 @@
+/* Copyright (C) 2003 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/***************************************************************
+* I N C L U D E D F I L E S *
+***************************************************************/
+
+#include <ndb_global.h>
+
+#include "userInterface.h"
+
+#include "dbPopulate.h"
+#include <NdbOut.hpp>
+#include <random.h>
+
+/***************************************************************
+* L O C A L C O N S T A N T S *
+***************************************************************/
+
+/***************************************************************
+* L O C A L D A T A S T R U C T U R E S *
+***************************************************************/
+
+/***************************************************************
+* L O C A L F U N C T I O N S *
+***************************************************************/
+
+static void getRandomSubscriberData(int subscriberNo,
+ SubscriberNumber number,
+ SubscriberName name);
+
+static void populate(char *title,
+ int count,
+ void (*func)(UserHandle*,int),
+ UserHandle *uh);
+
+static void populateServers(UserHandle *uh, int count);
+static void populateSubscribers(UserHandle *uh, int count);
+static void populateGroups(UserHandle *uh, int count);
+
+/***************************************************************
+* L O C A L D A T A *
+***************************************************************/
+
+static SequenceValues permissionsDefinition[] = {
+ {90, 1},
+ {10, 0},
+ {0, 0}
+};
+
+/***************************************************************
+* P U B L I C D A T A *
+***************************************************************/
+
+
+/***************************************************************
+****************************************************************
+* L O C A L F U N C T I O N S C O D E S E C T I O N *
+****************************************************************
+***************************************************************/
+
+static void getRandomSubscriberData(int subscriberNo,
+ SubscriberNumber number,
+ SubscriberName name)
+{
+ char sbuf[SUBSCRIBER_NUMBER_LENGTH + 1];
+ sprintf(sbuf, "%.*d", SUBSCRIBER_NUMBER_LENGTH, subscriberNo);
+ memcpy(number, sbuf, SUBSCRIBER_NUMBER_LENGTH);
+
+ memset(name, myRandom48(26)+'A', SUBSCRIBER_NAME_LENGTH);
+}
+
+static void populate(char *title,
+ int count,
+ void (*func)(UserHandle*, int),
+ UserHandle *uh)
+{
+ ndbout_c("Populating %d '%s' ... ",count, title);
+ /* fflush(stdout); */
+ func(uh,count);
+ ndbout_c("done");
+}
+
+static void populateServers(UserHandle *uh, int count)
+{
+ int i, j;
+ int len;
+ char tmp[80];
+ int suffix_length = 1;
+ ServerName serverName;
+ SubscriberSuffix suffix;
+
+ int commitCount = 0;
+
+ for(i = 0; i < SUBSCRIBER_NUMBER_SUFFIX_LENGTH; i++)
+ suffix_length *= 10;
+
+ for(i = 0; i < count; i++) {
+ sprintf(tmp, "-Server %d-", i);
+
+ len = strlen(tmp);
+ for(j = 0; j < SERVER_NAME_LENGTH; j++){
+ serverName[j] = tmp[j % len];
+ }
+ /* serverName[j] = 0; not null-terminated */
+
+ for(j = 0; j < suffix_length; j++){
+ char sbuf[SUBSCRIBER_NUMBER_SUFFIX_LENGTH + 1];
+ sprintf(sbuf, "%.*d", SUBSCRIBER_NUMBER_SUFFIX_LENGTH, j);
+ memcpy(suffix, sbuf, SUBSCRIBER_NUMBER_SUFFIX_LENGTH);
+ userDbInsertServer(uh, i, suffix, serverName);
+ commitCount ++;
+ if((commitCount % OP_PER_TRANS) == 0)
+ userDbCommit(uh);
+ }
+ }
+ if((commitCount % OP_PER_TRANS) != 0)
+ userDbCommit(uh);
+}
+
+static void populateSubscribers(UserHandle *uh, int count)
+{
+ SubscriberNumber number;
+ SubscriberName name;
+ int i, j, k;
+ int res;
+
+ SequenceValues values[NO_OF_GROUPS+1];
+ RandomSequence seq;
+
+ for(i = 0; i < NO_OF_GROUPS; i++) {
+ values[i].length = 1;
+ values[i].value = i;
+ }
+
+ values[i].length = 0;
+ values[i].value = 0;
+
+ if( initSequence(&seq, values) != 0 ) {
+ ndbout_c("could not set the sequence of random groups");
+ exit(0);
+ }
+
+#define RETRIES 25
+
+ for(i = 0; i < count; i+= OP_PER_TRANS) {
+ for(j = 0; j<RETRIES; j++){
+ for(k = 0; k<OP_PER_TRANS && i+k < count; k++){
+ getRandomSubscriberData(i+k, number, name);
+ userDbInsertSubscriber(uh, number, getNextRandom(&seq), name);
+ }
+ res = userDbCommit(uh);
+ if(res == 0)
+ break;
+ if(res != 1){
+ ndbout_c("Terminating");
+ exit(0);
+ }
+ }
+ if(j == RETRIES){
+ ndbout_c("Terminating");
+ exit(0);
+ }
+ }
+}
+
+static void populateGroups(UserHandle *uh, int count)
+{
+ int i;
+ int j;
+ int len;
+ RandomSequence seq;
+ Permission allow[NO_OF_GROUPS];
+ ServerBit serverBit;
+ GroupName groupName;
+ char tmp[80];
+ int commitCount = 0;
+
+ if( initSequence(&seq, permissionsDefinition) != 0 ) {
+ ndbout_c("could not set the sequence of random permissions");
+ exit(0);
+ }
+
+ for(i = 0; i < NO_OF_GROUPS; i++)
+ allow[i] = 0;
+
+ for(i = 0; i < NO_OF_SERVERS; i++) {
+ serverBit = 1 << i;
+
+ for(j = 0; j < NO_OF_GROUPS; j++ ) {
+ if( getNextRandom(&seq) )
+ allow[j] |= serverBit;
+ }
+ }
+
+ for(i = 0; i < NO_OF_GROUPS; i++) {
+ sprintf(tmp, "-Group %d-", i);
+
+ len = strlen(tmp);
+
+ for(j = 0; j < GROUP_NAME_LENGTH; j++) {
+ groupName[j] = tmp[j % len];
+ }
+ /* groupName[j] = 0; not null-terminated */
+
+ userDbInsertGroup(uh,
+ i,
+ groupName,
+ allow[i],
+ allow[i],
+ allow[i]);
+ commitCount ++;
+ if((commitCount % OP_PER_TRANS) == 0)
+ userDbCommit(uh);
+ }
+ if((commitCount % OP_PER_TRANS) != 0)
+ userDbCommit(uh);
+}
+
+/***************************************************************
+****************************************************************
+* P U B L I C F U N C T I O N S C O D E S E C T I O N *
+****************************************************************
+***************************************************************/
+
+void dbPopulate(UserHandle *uh)
+{
+ populate("servers", NO_OF_SERVERS, populateServers, uh);
+ populate("subscribers", NO_OF_SUBSCRIBERS, populateSubscribers, uh);
+ populate("groups", NO_OF_GROUPS, populateGroups, uh);
+}
diff --git a/ndb/test/ndbapi/bench/dbPopulate.h b/ndb/test/ndbapi/bench/dbPopulate.h
new file mode 100644
index 00000000000..1916720e141
--- /dev/null
+++ b/ndb/test/ndbapi/bench/dbPopulate.h
@@ -0,0 +1,59 @@
+/* Copyright (C) 2003 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#ifndef DBPOPULATE_H
+#define DBPOPULATE_H
+
+/***************************************************************
+* I N C L U D E D F I L E S *
+***************************************************************/
+
+#include "userInterface.h"
+
+/***************************************************************
+* M A C R O S *
+***************************************************************/
+
+/***************************************************************/
+/* C O N S T A N T S */
+/***************************************************************/
+
+/***************************************************************
+* D A T A S T R U C T U R E S *
+***************************************************************/
+
+/***************************************************************
+* P U B L I C F U N C T I O N S *
+***************************************************************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern void dbPopulate(UserHandle *uh);
+
+#ifdef __cplusplus
+}
+#endif
+
+/***************************************************************
+* E X T E R N A L D A T A *
+***************************************************************/
+
+
+
+#endif /* DBPOPULATE_H */
+
diff --git a/ndb/test/ndbapi/bench/macros.h b/ndb/test/ndbapi/bench/macros.h
new file mode 100644
index 00000000000..22b7f564490
--- /dev/null
+++ b/ndb/test/ndbapi/bench/macros.h
@@ -0,0 +1,51 @@
+/* Copyright (C) 2003 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#ifndef MACROS_H
+#define MACROS_H
+
+#include <ndb_global.h>
+#include <NdbOut.hpp>
+
+#define ERROR(x) {ndbout_c((x));}
+#define ERROR1(x,y) {ndbout_c((x), (y));}
+#define ERROR2(x,y,z) {ndbout_c((x), (y), (z));}
+#define ERROR3(x,y,z,u) {ndbout_c((x), (y), (z), (u));}
+#define ERROR4(x,y,z,u,w) {ndbout_c((x), (y), (z), (u), (w));}
+
+#define INIT_RANDOM(x) srand48((x))
+#define UI_RANDOM(x) ((unsigned int)(lrand48()%(x)))
+
+#define ASSERT(cond, message) \
+ { if(!(cond)) { ERROR(message); exit(-1); }}
+
+#ifdef DEBUG_ON
+#define DEBUG(x) {ndbout_c((x));}
+#define DEBUG1(x,y) {ndbout_c((x), (y));}
+#define DEBUG2(x,y,z) {ndbout_c((x), (y), (z));}
+#define DEBUG3(x,y,z,u) {ndbout_c((x), (y), (z), (u));}
+#define DEBUG4(x,y,z,u,w) {ndbout_c((x), (y), (z), (u), (w));}
+#define DEBUG5(x,y,z,u,w, v) {ndbout_c((x), (y), (z), (u), (w), (v));}
+#else
+#define DEBUG(x)
+#define DEBUG1(x,y)
+#define DEBUG2(x,y,z)
+#define DEBUG3(x,y,z,u)
+#define DEBUG4(x,y,z,u,w)
+#define DEBUG5(x,y,z,u,w, v)
+#endif
+
+#endif
diff --git a/ndb/test/ndbapi/bench/mainAsyncGenerator.cpp b/ndb/test/ndbapi/bench/mainAsyncGenerator.cpp
new file mode 100644
index 00000000000..828b924582f
--- /dev/null
+++ b/ndb/test/ndbapi/bench/mainAsyncGenerator.cpp
@@ -0,0 +1,503 @@
+/* Copyright (C) 2003 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include <ndb_global.h>
+
+#include <NdbHost.h>
+#include <NdbSleep.h>
+#include <NdbThread.h>
+#include <NdbMain.h>
+#include <NdbOut.hpp>
+#include <NdbEnv.h>
+#include <NdbTest.hpp>
+
+#include "userInterface.h"
+#include "dbGenerator.h"
+
+static int numProcesses;
+static int numSeconds;
+static int numWarmSeconds;
+static int parallellism;
+static int millisSendPoll;
+static int minEventSendPoll;
+static int forceSendPoll;
+
+static ThreadData *data;
+static Ndb_cluster_connection *g_cluster_connection= 0;
+
+
+static void usage(const char *prog)
+{
+ const char *progname;
+
+ /*--------------------------------------------*/
+ /* Get the name of the program (without path) */
+ /*--------------------------------------------*/
+ progname = strrchr(prog, '/');
+
+ if (progname == 0)
+ progname = prog;
+ else
+ ++progname;
+
+ ndbout_c(
+ "Usage: %s [-proc <num>] [-warm <num>] [-time <num>] [ -p <num>] "
+ "[-t <num> ] [ -e <num> ] [ -f <num>] \n"
+ " -proc <num> Specifies that <num> is the number of\n"
+ " threads. The default is 1.\n"
+ " -time <num> Specifies that the test will run for <num> sec.\n"
+ " The default is 10 sec\n"
+ " -warm <num> Specifies the warm-up/cooldown period of <num> "
+ "sec.\n"
+ " The default is 10 sec\n"
+ " -p <num> The no of parallell transactions started by "
+ "one thread\n"
+ " -e <num> Minimum no of events before wake up in call to "
+ "sendPoll\n"
+ " Default is 1\n"
+ " -f <num> force parameter to sendPoll\n"
+ " Default is 0\n",
+ progname);
+}
+
+static
+int
+parse_args(int argc, const char **argv)
+{
+ int i;
+
+ numProcesses = 1;
+ numSeconds = 10;
+ numWarmSeconds = 10;
+ parallellism = 1;
+ millisSendPoll = 10000;
+ minEventSendPoll = 1;
+ forceSendPoll = 0;
+
+
+ i = 1;
+ while (i < argc){
+ if (strcmp("-proc",argv[i]) == 0) {
+ if (i + 1 >= argc) {
+ return 1;
+ }
+ if (sscanf(argv[i+1], "%d", &numProcesses) == -1 ||
+ numProcesses <= 0 || numProcesses > 127) {
+ ndbout_c("-proc flag requires a positive integer argument [1..127]");
+ return 1;
+ }
+ i += 2;
+ } else if (strcmp("-p", argv[i]) == 0){
+ if(i + 1 >= argc){
+ usage(argv[0]);
+ return 1;
+ }
+ if (sscanf(argv[i+1], "%d", &parallellism) == -1 ||
+ parallellism <= 0){
+ ndbout_c("-p flag requires a positive integer argument");
+ return 1;
+ }
+ i += 2;
+ }
+ else if (strcmp("-time",argv[i]) == 0) {
+ if (i + 1 >= argc) {
+ return 1;
+ }
+ if (sscanf(argv[i+1], "%d", &numSeconds) == -1 ||
+ numSeconds < 0) {
+ ndbout_c("-time flag requires a positive integer argument");
+ return 1;
+ }
+ i += 2;
+ }
+ else if (strcmp("-warm",argv[i]) == 0) {
+ if (i + 1 >= argc) {
+ return 1;
+ }
+ if (sscanf(argv[i+1], "%d", &numWarmSeconds) == -1 ||
+ numWarmSeconds < 0) {
+ ndbout_c("-warm flag requires a positive integer argument");
+ return 1;
+ }
+ i += 2;
+ }
+ else if (strcmp("-e",argv[i]) == 0) {
+ if (i + 1 >= argc) {
+ return 1;
+ }
+ if (sscanf(argv[i+1], "%d", &minEventSendPoll) == -1 ||
+ minEventSendPoll < 0) {
+ ndbout_c("-e flag requires a positive integer argument");
+ return 1;
+ }
+ i += 2;
+ }
+ else if (strcmp("-f",argv[i]) == 0) {
+ if (i + 1 >= argc) {
+ usage(argv[0]);
+ return 1;
+ }
+ if (sscanf(argv[i+1], "%d", &forceSendPoll) == -1 ||
+ forceSendPoll < 0) {
+ ndbout_c("-f flag requires a positive integer argument");
+ return 1;
+ }
+ i += 2;
+ }
+ else {
+ return 1;
+ }
+ }
+
+ if(minEventSendPoll > parallellism){
+ ndbout_c("minEventSendPoll(%d) > parallellism(%d)",
+ minEventSendPoll, parallellism);
+ ndbout_c("not very good...");
+ ndbout_c("very bad...");
+ ndbout_c("exiting...");
+ return 1;
+ }
+ return 0;
+}
+
+static
+void
+print_transaction(const char *header,
+ unsigned long totalCount,
+ TransactionDefinition *trans,
+ unsigned int printBranch,
+ unsigned int printRollback)
+{
+ double f;
+
+ ndbout_c(" %s: %d (%.2f%%) "
+ "Latency(ms) avg: %d min: %d max: %d std: %d n: %d",
+ header,
+ trans->count,
+ (double)trans->count / (double)totalCount * 100.0,
+ (int)trans->latency.getMean(),
+ (int)trans->latency.getMin(),
+ (int)trans->latency.getMax(),
+ (int)trans->latency.getStddev(),
+ (int)trans->latency.getCount()
+ );
+
+ if( printBranch ){
+ if( trans->count == 0 )
+ f = 0.0;
+ else
+ f = (double)trans->branchExecuted / (double)trans->count * 100.0;
+ ndbout_c(" Branches Executed: %d (%.2f%%)", trans->branchExecuted, f);
+ }
+
+ if( printRollback ){
+ if( trans->count == 0 )
+ f = 0.0;
+ else
+ f = (double)trans->rollbackExecuted / (double)trans->count * 100.0;
+ ndbout_c(" Rollback Executed: %d (%.2f%%)",trans->rollbackExecuted,f);
+ }
+}
+
+void
+print_stats(const char *title,
+ unsigned int length,
+ unsigned int transactionFlag,
+ GeneratorStatistics *gen,
+ int numProc, int parallellism)
+{
+ int i;
+ char buf[10];
+ char name[MAXHOSTNAMELEN];
+
+ name[0] = 0;
+ NdbHost_GetHostName(name);
+
+ ndbout_c("\n------ %s ------",title);
+ ndbout_c("Length : %d %s",
+ length,
+ transactionFlag ? "Transactions" : "sec");
+ ndbout_c("Processor : %s", name);
+ ndbout_c("Number of Proc: %d",numProc);
+ ndbout_c("Parallellism : %d", parallellism);
+ ndbout_c("\n");
+
+ if( gen->totalTransactions == 0 ) {
+ ndbout_c(" No Transactions for this test");
+ }
+ else {
+ for(i = 0; i < 5; i++) {
+ sprintf(buf, "T%d",i+1);
+ print_transaction(buf,
+ gen->totalTransactions,
+ &gen->transactions[i],
+ i >= 2,
+ i >= 3 );
+ }
+
+ ndbout_c("\n");
+ ndbout_c(" Overall Statistics:");
+ ndbout_c(" Transactions: %d", gen->totalTransactions);
+ ndbout_c(" Outer : %.0f TPS",gen->outerTps);
+ ndbout_c("\n");
+ }
+}
+
+static
+void *
+threadRoutine(void *arg)
+{
+ int i;
+ ThreadData *data = (ThreadData *)arg;
+ Ndb * pNDB;
+
+ pNDB = asyncDbConnect(parallellism);
+ /* NdbSleep_MilliSleep(rand() % 10); */
+
+ for(i = 0; i<parallellism; i++){
+ data[i].pNDB = pNDB;
+ }
+ millisSendPoll = 30000;
+ asyncGenerator(data, parallellism,
+ millisSendPoll, minEventSendPoll, forceSendPoll);
+
+ asyncDbDisconnect(pNDB);
+
+ return NULL;
+}
+
+NDB_COMMAND(DbAsyncGenerator, "DbAsyncGenerator",
+ "DbAsyncGenerator", "DbAsyncGenerator", 65535)
+{
+ ndb_init();
+ int i;
+ int j;
+ int k;
+ struct NdbThread* pThread = NULL;
+ GeneratorStatistics stats;
+ GeneratorStatistics *p;
+ char threadName[32];
+ int rc = NDBT_OK;
+ void* tmp = NULL;
+ if(parse_args(argc,argv) != 0){
+ usage(argv[0]);
+ return NDBT_ProgramExit(NDBT_WRONGARGS);
+ }
+
+
+ ndbout_c("\nStarting Test with %d process(es) for %d %s parallellism %d",
+ numProcesses,
+ numSeconds,
+ "sec",
+ parallellism);
+
+ ndbout_c(" WarmUp/coolDown = %d sec", numWarmSeconds);
+
+ Ndb_cluster_connection con;
+ if(con.connect(12, 5, 1) != 0)
+ {
+ ndbout << "Unable to connect to management server." << endl;
+ return 0;
+ }
+ if (con.wait_until_ready(30,0) < 0)
+ {
+ ndbout << "Cluster nodes not ready in 30 seconds." << endl;
+ return 0;
+ }
+
+ g_cluster_connection= &con;
+ data = (ThreadData*)malloc((numProcesses*parallellism)*sizeof(ThreadData));
+
+ for(i = 0; i < numProcesses; i++) {
+ for(j = 0; j<parallellism; j++){
+ data[i*parallellism+j].warmUpSeconds = numWarmSeconds;
+ data[i*parallellism+j].testSeconds = numSeconds;
+ data[i*parallellism+j].coolDownSeconds = numWarmSeconds;
+ data[i*parallellism+j].randomSeed =
+ NdbTick_CurrentMillisecond()+i+j;
+ data[i*parallellism+j].changedTime = 0;
+ data[i*parallellism+j].runState = Runnable;
+ }
+ sprintf(threadName, "AsyncThread[%d]", i);
+ pThread = NdbThread_Create(threadRoutine,
+ (void**)&data[i*parallellism],
+ 65535,
+ threadName,
+ NDB_THREAD_PRIO_LOW);
+ if(pThread != 0 && pThread != NULL){
+ (&data[i*parallellism])->pThread = pThread;
+ } else {
+ perror("Failed to create thread");
+ rc = NDBT_FAILED;
+ }
+ }
+
+ showTime();
+
+ /*--------------------------------*/
+ /* Wait for all processes to exit */
+ /*--------------------------------*/
+ for(i = 0; i < numProcesses; i++) {
+ NdbThread_WaitFor(data[i*parallellism].pThread, &tmp);
+ NdbThread_Destroy(&data[i*parallellism].pThread);
+ }
+
+ ndbout_c("All threads have finished");
+
+ /*-------------------------------------------*/
+ /* Clear all structures for total statistics */
+ /*-------------------------------------------*/
+ stats.totalTransactions = 0;
+ stats.outerTps = 0.0;
+
+ for(i = 0; i < NUM_TRANSACTION_TYPES; i++ ) {
+ stats.transactions[i].count = 0;
+ stats.transactions[i].branchExecuted = 0;
+ stats.transactions[i].rollbackExecuted = 0;
+ stats.transactions[i].latency.reset();
+ }
+
+ /*--------------------------------*/
+ /* Add the values for all Threads */
+ /*--------------------------------*/
+ for(i = 0; i < numProcesses; i++) {
+ for(k = 0; k<parallellism; k++){
+ p = &data[i*parallellism+k].generator;
+
+ stats.totalTransactions += p->totalTransactions;
+ stats.outerTps += p->outerTps;
+
+ for(j = 0; j < NUM_TRANSACTION_TYPES; j++ ) {
+ stats.transactions[j].count +=
+ p->transactions[j].count;
+ stats.transactions[j].branchExecuted +=
+ p->transactions[j].branchExecuted;
+ stats.transactions[j].rollbackExecuted +=
+ p->transactions[j].rollbackExecuted;
+ stats.transactions[j].latency +=
+ p->transactions[j].latency;
+ }
+ }
+ }
+
+ print_stats("Test Results",
+ numSeconds,
+ 0,
+ &stats,
+ numProcesses,
+ parallellism);
+
+ free(data);
+
+ NDBT_ProgramExit(rc);
+}
+/***************************************************************
+* I N C L U D E D F I L E S *
+***************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <time.h>
+
+#include "ndb_schema.hpp"
+#include "ndb_error.hpp"
+#include "userInterface.h"
+#include <NdbMutex.h>
+#include <NdbThread.h>
+#include <NdbTick.h>
+#include <NdbApi.hpp>
+#include <NdbOut.hpp>
+
+/***************************************************************
+* L O C A L C O N S T A N T S *
+***************************************************************/
+
+/***************************************************************
+* L O C A L D A T A S T R U C T U R E S *
+***************************************************************/
+
+/***************************************************************
+* L O C A L F U N C T I O N S *
+***************************************************************/
+
+#ifndef NDB_WIN32
+#include <unistd.h>
+#endif
+
+Ndb*
+asyncDbConnect(int parallellism){
+ Ndb * pNDB = new Ndb(g_cluster_connection, "TEST_DB");
+
+ pNDB->init(parallellism + 1);
+
+ while(pNDB->waitUntilReady() != 0){
+ }
+
+ return pNDB;
+}
+
+void
+asyncDbDisconnect(Ndb* pNDB)
+{
+ delete pNDB;
+}
+
+double
+userGetTime(void)
+{
+ static bool initialized = false;
+ static NDB_TICKS initSecs = 0;
+ static Uint32 initMicros = 0;
+ double timeValue = 0;
+
+ if ( !initialized ) {
+ initialized = true;
+ NdbTick_CurrentMicrosecond(&initSecs, &initMicros);
+ timeValue = 0.0;
+ } else {
+ NDB_TICKS secs = 0;
+ Uint32 micros = 0;
+
+ NdbTick_CurrentMicrosecond(&secs, &micros);
+ double s = (double)secs - (double)initSecs;
+ double us = (double)micros - (double)initMicros;
+
+ timeValue = s + (us / 1000000.0);
+ }
+ return timeValue;
+}
+
+void showTime()
+{
+ char buf[128];
+ struct tm* tm_now;
+ time_t now;
+ now = ::time((time_t*)NULL);
+ tm_now = ::gmtime(&now);
+
+ ::snprintf(buf, 128,
+ "%d-%.2d-%.2d %.2d:%.2d:%.2d",
+ tm_now->tm_year + 1900,
+ tm_now->tm_mon,
+ tm_now->tm_mday,
+ tm_now->tm_hour,
+ tm_now->tm_min,
+ tm_now->tm_sec);
+
+ ndbout_c("Time: %s", buf);
+}
+
diff --git a/ndb/test/ndbapi/bench/mainPopulate.cpp b/ndb/test/ndbapi/bench/mainPopulate.cpp
new file mode 100644
index 00000000000..5ab1a5b015d
--- /dev/null
+++ b/ndb/test/ndbapi/bench/mainPopulate.cpp
@@ -0,0 +1,81 @@
+/* Copyright (C) 2003 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include <ndb_global.h>
+#include <ndb_opts.h>
+
+#include "userInterface.h"
+#include "dbPopulate.h"
+#include <NdbMain.h>
+#include <NdbOut.hpp>
+#include <random.h>
+#include <NDBT.hpp>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+int useTableLogging;
+#ifdef __cplusplus
+}
+#endif
+
+
+static void usage()
+{
+}
+
+static
+void usage(const char *prog)
+{
+
+ ndbout_c(
+ "Usage: %s [-l]\n"
+ " -l Use logging and checkpointing on tables\n",
+ prog);
+
+ exit(1);
+}
+
+NDB_STD_OPTS_VARS;
+
+NDB_COMMAND(DbCreate, "DbCreate", "DbCreate", "DbCreate", 16384)
+{
+ ndb_init();
+ int i;
+ UserHandle *uh;
+
+ useTableLogging = 0;
+
+ for(i = 1; i<argc; i++){
+ if(strcmp(argv[i], "-l") == 0){
+ useTableLogging = 1;
+ } else {
+ usage(argv[0]);
+ return 0;
+ }
+ }
+
+ ndbout_c("Using %s tables",
+ useTableLogging ? "logging" : "temporary");
+
+ myRandom48Init(0x3e6f);
+
+ uh = userDbConnect(1, "TEST_DB");
+ dbPopulate(uh);
+ userDbDisconnect(uh);
+
+ return NDBT_ProgramExit(NDBT_OK);
+}
diff --git a/ndb/test/ndbapi/bench/ndb_async1.cpp b/ndb/test/ndbapi/bench/ndb_async1.cpp
new file mode 100644
index 00000000000..2a84f6b2aca
--- /dev/null
+++ b/ndb/test/ndbapi/bench/ndb_async1.cpp
@@ -0,0 +1,647 @@
+/* Copyright (C) 2003 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+//#define DEBUG_ON
+
+#include "userInterface.h"
+
+#include "macros.h"
+#include "ndb_schema.hpp"
+#include "ndb_error.hpp"
+
+#include <NdbApi.hpp>
+
+inline
+NdbConnection *
+startTransaction(Ndb * pNDB,
+ ServerId inServerId,
+ const SubscriberNumber inNumber){
+
+ const int keyDataLenBytes = sizeof(ServerId)+SUBSCRIBER_NUMBER_LENGTH;
+ const int keyDataLen_64Words = keyDataLenBytes >> 3;
+
+ Uint64 keyDataBuf[keyDataLen_64Words+1]; // The "+1" is for rounding...
+
+ char * keyDataBuf_charP = (char *)&keyDataBuf[0];
+ Uint32 * keyDataBuf_wo32P = (Uint32 *)&keyDataBuf[0];
+
+ // Server Id comes first
+ keyDataBuf_wo32P[0] = inServerId;
+ // Then subscriber number
+ memcpy(&keyDataBuf_charP[sizeof(ServerId)], inNumber,
+ SUBSCRIBER_NUMBER_LENGTH);
+
+ return pNDB->startTransaction(0, keyDataBuf_charP, keyDataLenBytes);
+}
+
+void T1_Callback(int result, NdbConnection * pCon, void * threadData);
+void T2_Callback(int result, NdbConnection * pCon, void * threadData);
+void T3_Callback_1(int result, NdbConnection * pCon, void * threadData);
+void T3_Callback_2(int result, NdbConnection * pCon, void * threadData);
+void T3_Callback_3(int result, NdbConnection * pCon, void * threadData);
+void T4_Callback_1(int result, NdbConnection * pCon, void * threadData);
+void T4_Callback_2(int result, NdbConnection * pCon, void * threadData);
+void T4_Callback_3(int result, NdbConnection * pCon, void * threadData);
+void T5_Callback_1(int result, NdbConnection * pCon, void * threadData);
+void T5_Callback_2(int result, NdbConnection * pCon, void * threadData);
+void T5_Callback_3(int result, NdbConnection * pCon, void * threadData);
+
+/**
+ * Transaction 1 - T1
+ *
+ * Update location and changed by/time on a subscriber
+ *
+ * Input:
+ * SubscriberNumber,
+ * Location,
+ * ChangedBy,
+ * ChangedTime
+ *
+ * Output:
+ */
+void
+start_T1(Ndb * pNDB, ThreadData * td){
+
+ DEBUG2("T1(%.*s): - Starting\n", SUBSCRIBER_NUMBER_LENGTH,
+ td->transactionData.number);
+
+ int check;
+ NdbConnection * pCON = pNDB->startTransaction();
+ if (pCON != NULL) {
+ NdbOperation *MyOp = pCON->getNdbOperation(SUBSCRIBER_TABLE);
+ if (MyOp != NULL) {
+ MyOp->updateTuple();
+ MyOp->equal(IND_SUBSCRIBER_NUMBER,
+ td->transactionData.number);
+ MyOp->setValue(IND_SUBSCRIBER_LOCATION,
+ (char *)&td->transactionData.location);
+ MyOp->setValue(IND_SUBSCRIBER_CHANGED_BY,
+ td->transactionData.changed_by);
+ MyOp->setValue(IND_SUBSCRIBER_CHANGED_TIME,
+ td->transactionData.changed_time);
+ pCON->executeAsynchPrepare( Commit , T1_Callback, td);
+ } else {
+ CHECK_NULL(MyOp, "T1: getNdbOperation", pCON);
+ }//if
+ } else {
+ error_handler("T1-1: startTranscation",
+ pNDB->getNdbErrorString(),
+ pNDB->getNdbError());
+ }//if
+}
+
+void
+T1_Callback(int result, NdbConnection * pCON, void * threadData){
+ ThreadData * td = (ThreadData *)threadData;
+
+ DEBUG2("T1(%.*s): - Completing\n", SUBSCRIBER_NUMBER_LENGTH,
+ td->transactionData.number);
+
+ CHECK_MINUS_ONE(result, "T1: Commit",
+ pCON);
+ td->pNDB->closeTransaction(pCON);
+ complete_T1(td);
+}
+
+/**
+ * Transaction 2 - T2
+ *
+ * Read from Subscriber:
+ *
+ * Input:
+ * SubscriberNumber
+ *
+ * Output:
+ * Location
+ * Changed by
+ * Changed Timestamp
+ * Name
+ */
+void
+start_T2(Ndb * pNDB, ThreadData * td){
+
+ DEBUG3("T2(%.*s, %p): - Starting\n", SUBSCRIBER_NUMBER_LENGTH,
+ td->transactionData.number,
+ td->transactionData.location);
+
+ int check;
+ NdbRecAttr * check2;
+
+ NdbConnection * pCON = pNDB->startTransaction();
+ if (pCON == NULL)
+ error_handler("T2-1: startTransaction",
+ pNDB->getNdbErrorString(),
+ pNDB->getNdbError());
+
+ NdbOperation *MyOp= pCON->getNdbOperation(SUBSCRIBER_TABLE);
+ CHECK_NULL(MyOp, "T2: getNdbOperation",
+ pCON);
+
+ MyOp->readTuple();
+ MyOp->equal(IND_SUBSCRIBER_NUMBER,
+ td->transactionData.number);
+ MyOp->getValue(IND_SUBSCRIBER_LOCATION,
+ (char *)&td->transactionData.location);
+ MyOp->getValue(IND_SUBSCRIBER_CHANGED_BY,
+ td->transactionData.changed_by);
+ MyOp->getValue(IND_SUBSCRIBER_CHANGED_TIME,
+ td->transactionData.changed_time);
+ MyOp->getValue(IND_SUBSCRIBER_NAME,
+ td->transactionData.name);
+ pCON->executeAsynchPrepare( Commit, T2_Callback, td );
+}
+
+void
+T2_Callback(int result, NdbConnection * pCON, void * threadData){
+ ThreadData * td = (ThreadData *)threadData;
+ DEBUG3("T2(%.*s, %p): - Completing\n", SUBSCRIBER_NUMBER_LENGTH,
+ td->transactionData.number,
+ td->transactionData.location);
+
+ CHECK_MINUS_ONE(result, "T2: Commit", pCON);
+ td->pNDB->closeTransaction(pCON);
+ complete_T2(td);
+}
+
+/**
+ * Transaction 3 - T3
+ *
+ * Read session details
+ *
+ * Input:
+ * SubscriberNumber
+ * ServerId
+ * ServerBit
+ *
+ * Output:
+ * BranchExecuted
+ * SessionDetails
+ * ChangedBy
+ * ChangedTime
+ * Location
+ */
+void
+start_T3(Ndb * pNDB, ThreadData * td){
+
+ DEBUG3("T3(%.*s, %.2d): - Starting\n", SUBSCRIBER_NUMBER_LENGTH,
+ td->transactionData.number,
+ td->transactionData.server_id);
+
+ int check;
+ NdbRecAttr * check2;
+
+ NdbConnection * pCON = startTransaction(pNDB,
+ td->transactionData.server_id,
+ td->transactionData.number);
+ if (pCON == NULL)
+ error_handler("T3-1: startTranscation",
+ pNDB->getNdbErrorString(),
+ pNDB->getNdbError());
+
+ NdbOperation *MyOp= pCON->getNdbOperation(SUBSCRIBER_TABLE);
+ CHECK_NULL(MyOp, "T3-1: getNdbOperation",
+ pCON);
+
+ MyOp->readTuple();
+ MyOp->equal(IND_SUBSCRIBER_NUMBER,
+ td->transactionData.number);
+ MyOp->getValue(IND_SUBSCRIBER_LOCATION,
+ (char *)&td->transactionData.location);
+ MyOp->getValue(IND_SUBSCRIBER_CHANGED_BY,
+ td->transactionData.changed_by);
+ MyOp->getValue(IND_SUBSCRIBER_CHANGED_TIME,
+ td->transactionData.changed_time);
+ MyOp->getValue(IND_SUBSCRIBER_GROUP,
+ (char *)&td->transactionData.group_id);
+ MyOp->getValue(IND_SUBSCRIBER_SESSIONS,
+ (char *)&td->transactionData.sessions);
+ pCON->executeAsynchPrepare( NoCommit , T3_Callback_1, td);
+}
+
+void
+T3_Callback_1(int result, NdbConnection * pCON, void * threadData){
+ ThreadData * td = (ThreadData *)threadData;
+ DEBUG3("T3(%.*s, %.2d): - Callback 1\n", SUBSCRIBER_NUMBER_LENGTH,
+ td->transactionData.number,
+ td->transactionData.server_id);
+
+ CHECK_MINUS_ONE(result, "T3-1: NoCommit", pCON);
+
+ NdbOperation * MyOp = pCON->getNdbOperation(GROUP_TABLE);
+ CHECK_NULL(MyOp, "T3-2: getNdbOperation",
+ pCON);
+
+ MyOp->readTuple();
+ MyOp->equal(IND_GROUP_ID,
+ (char*)&td->transactionData.group_id);
+ MyOp->getValue(IND_GROUP_ALLOW_READ,
+ (char *)&td->transactionData.permission);
+ pCON->executeAsynchPrepare( NoCommit, T3_Callback_2, td );
+}
+
+void
+T3_Callback_2(int result, NdbConnection * pCON, void * threadData){
+ ThreadData * td = (ThreadData *)threadData;
+
+ CHECK_MINUS_ONE(result, "T3-2: NoCommit", pCON);
+
+ Uint32 permission = td->transactionData.permission;
+ Uint32 sessions = td->transactionData.sessions;
+ Uint32 server_bit = td->transactionData.server_bit;
+
+ if(((permission & server_bit) == server_bit) &&
+ ((sessions & server_bit) == server_bit)){
+
+ memcpy(td->transactionData.suffix,
+ &td->transactionData.number
+ [SUBSCRIBER_NUMBER_LENGTH-SUBSCRIBER_NUMBER_SUFFIX_LENGTH],
+ SUBSCRIBER_NUMBER_SUFFIX_LENGTH);
+ DEBUG5("T3(%.*s, %.2d): - Callback 2 - reading(%.*s)\n",
+ SUBSCRIBER_NUMBER_LENGTH,
+ td->transactionData.number,
+ td->transactionData.server_id,
+ SUBSCRIBER_NUMBER_SUFFIX_LENGTH,
+ td->transactionData.suffix);
+
+ /* Operation 3 */
+ NdbOperation * MyOp = pCON->getNdbOperation(SESSION_TABLE);
+ CHECK_NULL(MyOp, "T3-3: getNdbOperation",
+ pCON);
+
+ MyOp->simpleRead();
+ MyOp->equal(IND_SESSION_SUBSCRIBER,
+ (char*)td->transactionData.number);
+ MyOp->equal(IND_SESSION_SERVER,
+ (char*)&td->transactionData.server_id);
+ MyOp->getValue(IND_SESSION_DATA,
+ (char *)td->transactionData.session_details);
+
+ /* Operation 4 */
+ MyOp = pCON->getNdbOperation(SERVER_TABLE);
+ CHECK_NULL(MyOp, "T3-4: getNdbOperation",
+ pCON);
+
+ MyOp->interpretedUpdateTuple();
+ MyOp->equal(IND_SERVER_ID,
+ (char*)&td->transactionData.server_id);
+ MyOp->equal(IND_SERVER_SUBSCRIBER_SUFFIX,
+ (char*)td->transactionData.suffix);
+ MyOp->incValue(IND_SERVER_READS, (uint32)1);
+ td->transactionData.branchExecuted = 1;
+ } else {
+ DEBUG3("T3(%.*s, %.2d): - Callback 2 - no read\n",
+ SUBSCRIBER_NUMBER_LENGTH,
+ td->transactionData.number,
+ td->transactionData.server_id);
+ td->transactionData.branchExecuted = 0;
+ }
+ pCON->executeAsynchPrepare( Commit, T3_Callback_3, td );
+}
+
+void
+T3_Callback_3(int result, NdbConnection * pCON, void * threadData){
+ ThreadData * td = (ThreadData *)threadData;
+ DEBUG3("T3(%.*s, %.2d): - Completing\n", SUBSCRIBER_NUMBER_LENGTH,
+ td->transactionData.number,
+ td->transactionData.server_id);
+
+ CHECK_MINUS_ONE(result, "T3-3: Commit", pCON);
+
+ td->pNDB->closeTransaction(pCON);
+ complete_T3(td);
+}
+
+/**
+ * Transaction 4 - T4
+ *
+ * Create session
+ *
+ * Input:
+ * SubscriberNumber
+ * ServerId
+ * ServerBit
+ * SessionDetails,
+ * DoRollback
+ * Output:
+ * ChangedBy
+ * ChangedTime
+ * Location
+ * BranchExecuted
+ */
+void
+start_T4(Ndb * pNDB, ThreadData * td){
+
+ DEBUG3("T4(%.*s, %.2d): - Starting\n", SUBSCRIBER_NUMBER_LENGTH,
+ td->transactionData.number,
+ td->transactionData.server_id);
+
+ int check;
+ NdbRecAttr * check2;
+
+ NdbConnection * pCON = startTransaction(pNDB,
+ td->transactionData.server_id,
+ td->transactionData.number);
+ if (pCON == NULL)
+ error_handler("T4-1: startTranscation",
+ pNDB->getNdbErrorString(),
+ pNDB->getNdbError());
+
+ NdbOperation *MyOp= pCON->getNdbOperation(SUBSCRIBER_TABLE);
+ CHECK_NULL(MyOp, "T4-1: getNdbOperation",
+ pCON);
+
+ MyOp->interpretedUpdateTuple();
+ MyOp->equal(IND_SUBSCRIBER_NUMBER,
+ td->transactionData.number);
+ MyOp->getValue(IND_SUBSCRIBER_LOCATION,
+ (char *)&td->transactionData.location);
+ MyOp->getValue(IND_SUBSCRIBER_CHANGED_BY,
+ td->transactionData.changed_by);
+ MyOp->getValue(IND_SUBSCRIBER_CHANGED_TIME,
+ td->transactionData.changed_time);
+ MyOp->getValue(IND_SUBSCRIBER_GROUP,
+ (char *)&td->transactionData.group_id);
+ MyOp->getValue(IND_SUBSCRIBER_SESSIONS,
+ (char *)&td->transactionData.sessions);
+ MyOp->incValue(IND_SUBSCRIBER_SESSIONS,
+ (uint32)td->transactionData.server_bit);
+ pCON->executeAsynchPrepare( NoCommit , T4_Callback_1, td);
+}
+
+void
+T4_Callback_1(int result, NdbConnection * pCON, void * threadData){
+ CHECK_MINUS_ONE(result, "T4-1: NoCommit", pCON);
+ ThreadData * td = (ThreadData *)threadData;
+
+ DEBUG3("T4(%.*s, %.2d): - Callback 1\n",
+ SUBSCRIBER_NUMBER_LENGTH,
+ td->transactionData.number,
+ td->transactionData.server_id);
+
+
+ NdbOperation * MyOp = pCON->getNdbOperation(GROUP_TABLE);
+ CHECK_NULL(MyOp, "T4-2: getNdbOperation",
+ pCON);
+
+ MyOp->readTuple();
+ MyOp->equal(IND_GROUP_ID,
+ (char*)&td->transactionData.group_id);
+ MyOp->getValue(IND_GROUP_ALLOW_INSERT,
+ (char *)&td->transactionData.permission);
+ pCON->executeAsynchPrepare( NoCommit , T4_Callback_2, td);
+}
+
+void
+T4_Callback_2(int result, NdbConnection * pCON, void * threadData){
+ CHECK_MINUS_ONE(result, "T4-2: NoCommit", pCON);
+ ThreadData * td = (ThreadData *)threadData;
+
+ Uint32 permission = td->transactionData.permission;
+ Uint32 sessions = td->transactionData.sessions;
+ Uint32 server_bit = td->transactionData.server_bit;
+
+ if(((permission & server_bit) == server_bit) &&
+ ((sessions & server_bit) == 0)){
+
+ memcpy(td->transactionData.suffix,
+ &td->transactionData.number
+ [SUBSCRIBER_NUMBER_LENGTH-SUBSCRIBER_NUMBER_SUFFIX_LENGTH],
+ SUBSCRIBER_NUMBER_SUFFIX_LENGTH);
+
+ DEBUG5("T4(%.*s, %.2d): - Callback 2 - inserting(%.*s)\n",
+ SUBSCRIBER_NUMBER_LENGTH,
+ td->transactionData.number,
+ td->transactionData.server_id,
+ SUBSCRIBER_NUMBER_SUFFIX_LENGTH,
+ td->transactionData.suffix);
+
+ /* Operation 3 */
+
+ NdbOperation * MyOp = pCON->getNdbOperation(SESSION_TABLE);
+ CHECK_NULL(MyOp, "T4-3: getNdbOperation",
+ pCON);
+
+ MyOp->insertTuple();
+ MyOp->equal(IND_SESSION_SUBSCRIBER,
+ (char*)td->transactionData.number);
+ MyOp->equal(IND_SESSION_SERVER,
+ (char*)&td->transactionData.server_id);
+ MyOp->setValue(SESSION_DATA,
+ (char *)td->transactionData.session_details);
+ /* Operation 4 */
+
+ /* Operation 5 */
+ MyOp = pCON->getNdbOperation(SERVER_TABLE);
+ CHECK_NULL(MyOp, "T4-5: getNdbOperation",
+ pCON);
+
+ MyOp->interpretedUpdateTuple();
+ MyOp->equal(IND_SERVER_ID,
+ (char*)&td->transactionData.server_id);
+ MyOp->equal(IND_SERVER_SUBSCRIBER_SUFFIX,
+ (char*)td->transactionData.suffix);
+ MyOp->incValue(IND_SERVER_INSERTS, (uint32)1);
+ td->transactionData.branchExecuted = 1;
+ } else {
+ td->transactionData.branchExecuted = 0;
+ DEBUG5("T4(%.*s, %.2d): - Callback 2 - %s %s\n",
+ SUBSCRIBER_NUMBER_LENGTH,
+ td->transactionData.number,
+ td->transactionData.server_id,
+ ((permission & server_bit) ?
+ "permission - " : "no permission - "),
+ ((sessions & server_bit) ?
+ "in session - " : "no in session - "));
+ }
+
+ if(!td->transactionData.do_rollback && td->transactionData.branchExecuted){
+ pCON->executeAsynchPrepare(Commit, T4_Callback_3, td);
+ } else {
+ pCON->executeAsynchPrepare(Rollback, T4_Callback_3, td);
+ }
+}
+
+void
+T4_Callback_3(int result, NdbConnection * pCON, void * threadData){
+ CHECK_MINUS_ONE(result, "T4-3: Commit", pCON);
+ ThreadData * td = (ThreadData *)threadData;
+
+ DEBUG3("T4(%.*s, %.2d): - Completing\n",
+ SUBSCRIBER_NUMBER_LENGTH,
+ td->transactionData.number,
+ td->transactionData.server_id);
+
+ td->pNDB->closeTransaction(pCON);
+ complete_T4(td);
+}
+
+/**
+ * Transaction 5 - T5
+ *
+ * Delete session
+ *
+ * Input:
+ * SubscriberNumber
+ * ServerId
+ * ServerBit
+ * DoRollback
+ * Output:
+ * ChangedBy
+ * ChangedTime
+ * Location
+ * BranchExecuted
+ */
+void
+start_T5(Ndb * pNDB, ThreadData * td){
+
+ DEBUG3("T5(%.*s, %.2d): - Starting\n", SUBSCRIBER_NUMBER_LENGTH,
+ td->transactionData.number,
+ td->transactionData.server_id);
+
+ int check;
+ NdbRecAttr * check2;
+
+ NdbConnection * pCON = pNDB->startTransaction();
+ if (pCON == NULL)
+ error_handler("T5-1: startTranscation",
+ pNDB->getNdbErrorString(),
+ pNDB->getNdbError());
+
+ NdbOperation * MyOp= pCON->getNdbOperation(SUBSCRIBER_TABLE);
+ CHECK_NULL(MyOp, "T5-1: getNdbOperation",
+ pCON);
+
+ MyOp->interpretedUpdateTuple();
+ MyOp->equal(IND_SUBSCRIBER_NUMBER,
+ td->transactionData.number);
+ MyOp->getValue(IND_SUBSCRIBER_LOCATION,
+ (char *)&td->transactionData.location);
+ MyOp->getValue(IND_SUBSCRIBER_CHANGED_BY,
+ td->transactionData.changed_by);
+ MyOp->getValue(IND_SUBSCRIBER_CHANGED_TIME,
+ td->transactionData.changed_time);
+ MyOp->getValue(IND_SUBSCRIBER_GROUP,
+ (char *)&td->transactionData.group_id);
+ MyOp->getValue(IND_SUBSCRIBER_SESSIONS,
+ (char *)&td->transactionData.sessions);
+ MyOp->subValue(IND_SUBSCRIBER_SESSIONS,
+ (uint32)td->transactionData.server_bit);
+ pCON->executeAsynchPrepare( NoCommit, T5_Callback_1, td );
+}
+
+void
+T5_Callback_1(int result, NdbConnection * pCON, void * threadData){
+ CHECK_MINUS_ONE(result, "T5-1: NoCommit", pCON);
+ ThreadData * td = (ThreadData *)threadData;
+
+ DEBUG3("T5(%.*s, %.2d): - Callback 1\n",
+ SUBSCRIBER_NUMBER_LENGTH,
+ td->transactionData.number,
+ td->transactionData.server_id);
+
+ NdbOperation * MyOp = pCON->getNdbOperation(GROUP_TABLE);
+ CHECK_NULL(MyOp, "T5-2: getNdbOperation",
+ pCON);
+
+ MyOp->readTuple();
+ MyOp->equal(IND_GROUP_ID,
+ (char*)&td->transactionData.group_id);
+ MyOp->getValue(IND_GROUP_ALLOW_DELETE,
+ (char *)&td->transactionData.permission);
+ pCON->executeAsynchPrepare( NoCommit, T5_Callback_2, td );
+}
+
+void
+T5_Callback_2(int result, NdbConnection * pCON, void * threadData){
+ CHECK_MINUS_ONE(result, "T5-2: NoCommit", pCON);
+ ThreadData * td = (ThreadData *)threadData;
+
+ Uint32 permission = td->transactionData.permission;
+ Uint32 sessions = td->transactionData.sessions;
+ Uint32 server_bit = td->transactionData.server_bit;
+
+ if(((permission & server_bit) == server_bit) &&
+ ((sessions & server_bit) == server_bit)){
+
+ memcpy(td->transactionData.suffix,
+ &td->transactionData.number
+ [SUBSCRIBER_NUMBER_LENGTH-SUBSCRIBER_NUMBER_SUFFIX_LENGTH],
+ SUBSCRIBER_NUMBER_SUFFIX_LENGTH);
+
+ DEBUG5("T5(%.*s, %.2d): - Callback 2 - deleting(%.*s)\n",
+ SUBSCRIBER_NUMBER_LENGTH,
+ td->transactionData.number,
+ td->transactionData.server_id,
+ SUBSCRIBER_NUMBER_SUFFIX_LENGTH,
+ td->transactionData.suffix);
+
+ /* Operation 3 */
+ NdbOperation * MyOp = pCON->getNdbOperation(SESSION_TABLE);
+ CHECK_NULL(MyOp, "T5-3: getNdbOperation",
+ pCON);
+
+ MyOp->deleteTuple();
+ MyOp->equal(IND_SESSION_SUBSCRIBER,
+ (char*)td->transactionData.number);
+ MyOp->equal(IND_SESSION_SERVER,
+ (char*)&td->transactionData.server_id);
+ /* Operation 4 */
+
+ /* Operation 5 */
+ MyOp = pCON->getNdbOperation(SERVER_TABLE);
+ CHECK_NULL(MyOp, "T5-5: getNdbOperation",
+ pCON);
+
+ MyOp->interpretedUpdateTuple();
+ MyOp->equal(IND_SERVER_ID,
+ (char*)&td->transactionData.server_id);
+ MyOp->equal(IND_SERVER_SUBSCRIBER_SUFFIX,
+ (char*)td->transactionData.suffix);
+ MyOp->incValue(IND_SERVER_DELETES, (uint32)1);
+ td->transactionData.branchExecuted = 1;
+ } else {
+ td->transactionData.branchExecuted = 0;
+
+ DEBUG5("T5(%.*s, %.2d): - Callback 2 - no delete - %s %s\n",
+ SUBSCRIBER_NUMBER_LENGTH,
+ td->transactionData.number,
+ td->transactionData.server_id,
+ ((permission & server_bit) ?
+ "permission - " : "no permission - "),
+ ((sessions & server_bit) ?
+ "in session - " : "no in session - "));
+ }
+
+ if(!td->transactionData.do_rollback && td->transactionData.branchExecuted){
+ pCON->executeAsynchPrepare(Commit, T5_Callback_3, td);
+ } else {
+ pCON->executeAsynchPrepare(Rollback, T5_Callback_3, td);
+ }
+}
+
+void
+T5_Callback_3(int result, NdbConnection * pCON, void * threadData){
+ CHECK_MINUS_ONE(result, "T5-3: Commit", pCON);
+ ThreadData * td = (ThreadData *)threadData;
+
+ DEBUG3("T5(%.*s, %.2d): - Completing\n",
+ SUBSCRIBER_NUMBER_LENGTH,
+ td->transactionData.number,
+ td->transactionData.server_id);
+
+ td->pNDB->closeTransaction(pCON);
+ complete_T5(td);
+}
diff --git a/ndb/test/ndbapi/bench/ndb_async2.cpp b/ndb/test/ndbapi/bench/ndb_async2.cpp
new file mode 100644
index 00000000000..31cf1d8310a
--- /dev/null
+++ b/ndb/test/ndbapi/bench/ndb_async2.cpp
@@ -0,0 +1,757 @@
+/* Copyright (C) 2003 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+//#define DEBUG_ON
+
+#include <string.h>
+#include "userInterface.h"
+
+#include "macros.h"
+#include "ndb_schema.hpp"
+#include "ndb_error.hpp"
+#include <NdbSleep.h>
+
+#include <NdbApi.hpp>
+
+void T1_Callback(int result, NdbConnection * pCon, void * threadData);
+void T2_Callback(int result, NdbConnection * pCon, void * threadData);
+void T3_Callback_1(int result, NdbConnection * pCon, void * threadData);
+void T3_Callback_2(int result, NdbConnection * pCon, void * threadData);
+void T3_Callback_3(int result, NdbConnection * pCon, void * threadData);
+void T4_Callback_1(int result, NdbConnection * pCon, void * threadData);
+void T4_Callback_2(int result, NdbConnection * pCon, void * threadData);
+void T4_Callback_3(int result, NdbConnection * pCon, void * threadData);
+void T5_Callback_1(int result, NdbConnection * pCon, void * threadData);
+void T5_Callback_2(int result, NdbConnection * pCon, void * threadData);
+void T5_Callback_3(int result, NdbConnection * pCon, void * threadData);
+
+static int stat_async = 0;
+
+/**
+ * Transaction 1 - T1
+ *
+ * Update location and changed by/time on a subscriber
+ *
+ * Input:
+ * SubscriberNumber,
+ * Location,
+ * ChangedBy,
+ * ChangedTime
+ *
+ * Output:
+ */
+
+#define SFX_START (SUBSCRIBER_NUMBER_LENGTH - SUBSCRIBER_NUMBER_SUFFIX_LENGTH)
+
+inline
+NdbConnection *
+startTransaction(Ndb * pNDB, ThreadData * td){
+ return pNDB->startTransaction();
+#ifdef OLD_CODE
+ return pNDB->startTransactionDGroup (0,
+ &td->transactionData.number[SFX_START],
+ 1);
+#endif
+}
+
+void
+start_T1(Ndb * pNDB, ThreadData * td, int async){
+
+ DEBUG2("T1(%.*s): - Starting", SUBSCRIBER_NUMBER_LENGTH,
+ td->transactionData.number);
+
+ NdbConnection * pCON = 0;
+ while((pCON = startTransaction(pNDB, td)) == 0){
+ CHECK_ALLOWED_ERROR("T1: startTransaction", td, pNDB->getNdbError());
+ NdbSleep_MilliSleep(10);
+ }
+
+ NdbOperation *MyOp = pCON->getNdbOperation(SUBSCRIBER_TABLE);
+ if (MyOp != NULL) {
+ MyOp->updateTuple();
+ MyOp->equal(IND_SUBSCRIBER_NUMBER,
+ td->transactionData.number);
+ MyOp->setValue(IND_SUBSCRIBER_LOCATION,
+ (char *)&td->transactionData.location);
+ MyOp->setValue(IND_SUBSCRIBER_CHANGED_BY,
+ td->transactionData.changed_by);
+ MyOp->setValue(IND_SUBSCRIBER_CHANGED_TIME,
+ td->transactionData.changed_time);
+ if (async == 1) {
+ pCON->executeAsynchPrepare( Commit , T1_Callback, td);
+ } else {
+ int result = pCON->execute(Commit);
+ T1_Callback(result, pCON, (void*)td);
+ return;
+ }//if
+ } else {
+ CHECK_NULL(MyOp, "T1: getNdbOperation", td, pCON->getNdbError());
+ }//if
+}
+
+void
+T1_Callback(int result, NdbConnection * pCON, void * threadData) {
+ ThreadData * td = (ThreadData *)threadData;
+
+ DEBUG2("T1(%.*s): - Completing", SUBSCRIBER_NUMBER_LENGTH,
+ td->transactionData.number);
+
+ if (result == -1) {
+ CHECK_ALLOWED_ERROR("T1: Commit", td, pCON->getNdbError());
+ td->pNDB->closeTransaction(pCON);
+ start_T1(td->pNDB, td, stat_async);
+ return;
+ }//if
+ td->pNDB->closeTransaction(pCON);
+ complete_T1(td);
+}
+
+/**
+ * Transaction 2 - T2
+ *
+ * Read from Subscriber:
+ *
+ * Input:
+ * SubscriberNumber
+ *
+ * Output:
+ * Location
+ * Changed by
+ * Changed Timestamp
+ * Name
+ */
+void
+start_T2(Ndb * pNDB, ThreadData * td, int async){
+
+ DEBUG3("T2(%.*s, %d): - Starting", SUBSCRIBER_NUMBER_LENGTH,
+ td->transactionData.number,
+ td->transactionData.location);
+
+ NdbConnection * pCON = 0;
+
+ while((pCON = startTransaction(pNDB, td)) == 0){
+ CHECK_ALLOWED_ERROR("T2-1: startTransaction", td, pNDB->getNdbError());
+ NdbSleep_MilliSleep(10);
+ }
+
+ NdbOperation *MyOp= pCON->getNdbOperation(SUBSCRIBER_TABLE);
+ CHECK_NULL(MyOp, "T2: getNdbOperation", td,
+ pCON->getNdbError());
+
+ MyOp->readTuple();
+ MyOp->equal(IND_SUBSCRIBER_NUMBER,
+ td->transactionData.number);
+ MyOp->getValue(IND_SUBSCRIBER_LOCATION,
+ (char *)&td->transactionData.location);
+ MyOp->getValue(IND_SUBSCRIBER_CHANGED_BY,
+ td->transactionData.changed_by);
+ MyOp->getValue(IND_SUBSCRIBER_CHANGED_TIME,
+ td->transactionData.changed_time);
+ MyOp->getValue(IND_SUBSCRIBER_NAME,
+ td->transactionData.name);
+ if (async == 1) {
+ pCON->executeAsynchPrepare( Commit , T2_Callback, td);
+ } else {
+ int result = pCON->execute(Commit);
+ T2_Callback(result, pCON, (void*)td);
+ return;
+ }//if
+}
+
+void
+T2_Callback(int result, NdbConnection * pCON, void * threadData){
+ ThreadData * td = (ThreadData *)threadData;
+ DEBUG3("T2(%.*s, %d): - Completing", SUBSCRIBER_NUMBER_LENGTH,
+ td->transactionData.number,
+ td->transactionData.location);
+
+ if (result == -1) {
+ CHECK_ALLOWED_ERROR("T2: Commit", td, pCON->getNdbError());
+ td->pNDB->closeTransaction(pCON);
+ start_T2(td->pNDB, td, stat_async);
+ return;
+ }//if
+ td->pNDB->closeTransaction(pCON);
+ complete_T2(td);
+}
+
+/**
+ * Transaction 3 - T3
+ *
+ * Read session details
+ *
+ * Input:
+ * SubscriberNumber
+ * ServerId
+ * ServerBit
+ *
+ * Output:
+ * BranchExecuted
+ * SessionDetails
+ * ChangedBy
+ * ChangedTime
+ * Location
+ */
+void
+start_T3(Ndb * pNDB, ThreadData * td, int async){
+
+ DEBUG3("T3(%.*s, %.2d): - Starting", SUBSCRIBER_NUMBER_LENGTH,
+ td->transactionData.number,
+ td->transactionData.server_id);
+
+ NdbConnection * pCON = 0;
+
+ while((pCON = startTransaction(pNDB, td)) == 0){
+ CHECK_ALLOWED_ERROR("T3-1: startTransaction", td, pNDB->getNdbError());
+ NdbSleep_MilliSleep(10);
+ }
+
+ NdbOperation *MyOp= pCON->getNdbOperation(SUBSCRIBER_TABLE);
+ CHECK_NULL(MyOp, "T3-1: getNdbOperation", td,
+ pCON->getNdbError());
+
+ MyOp->readTuple();
+ MyOp->equal(IND_SUBSCRIBER_NUMBER,
+ td->transactionData.number);
+ MyOp->getValue(IND_SUBSCRIBER_LOCATION,
+ (char *)&td->transactionData.location);
+ MyOp->getValue(IND_SUBSCRIBER_CHANGED_BY,
+ td->transactionData.changed_by);
+ MyOp->getValue(IND_SUBSCRIBER_CHANGED_TIME,
+ td->transactionData.changed_time);
+ MyOp->getValue(IND_SUBSCRIBER_GROUP,
+ (char *)&td->transactionData.group_id);
+ MyOp->getValue(IND_SUBSCRIBER_SESSIONS,
+ (char *)&td->transactionData.sessions);
+ stat_async = async;
+ if (async == 1) {
+ pCON->executeAsynchPrepare( NoCommit , T3_Callback_1, td);
+ } else {
+ int result = pCON->execute( NoCommit );
+ T3_Callback_1(result, pCON, (void*)td);
+ return;
+ }//if
+}
+
+void
+T3_Callback_1(int result, NdbConnection * pCON, void * threadData){
+ ThreadData * td = (ThreadData *)threadData;
+ DEBUG3("T3(%.*s, %.2d): - Callback 1", SUBSCRIBER_NUMBER_LENGTH,
+ td->transactionData.number,
+ td->transactionData.server_id);
+
+ if (result == -1) {
+ CHECK_ALLOWED_ERROR("T3-1: execute", td, pCON->getNdbError());
+ td->pNDB->closeTransaction(pCON);
+ start_T3(td->pNDB, td, stat_async);
+ return;
+ }//if
+
+ NdbOperation * MyOp = pCON->getNdbOperation(GROUP_TABLE);
+ CHECK_NULL(MyOp, "T3-2: getNdbOperation", td,
+ pCON->getNdbError());
+
+ MyOp->readTuple();
+ MyOp->equal(IND_GROUP_ID,
+ (char*)&td->transactionData.group_id);
+ MyOp->getValue(IND_GROUP_ALLOW_READ,
+ (char *)&td->transactionData.permission);
+ if (stat_async == 1) {
+ pCON->executeAsynchPrepare( NoCommit , T3_Callback_2, td);
+ } else {
+ int result = pCON->execute( NoCommit );
+ T3_Callback_2(result, pCON, (void*)td);
+ return;
+ }//if
+}
+
+void
+T3_Callback_2(int result, NdbConnection * pCON, void * threadData){
+ ThreadData * td = (ThreadData *)threadData;
+
+ if (result == -1) {
+ CHECK_ALLOWED_ERROR("T3-2: execute", td, pCON->getNdbError());
+ td->pNDB->closeTransaction(pCON);
+ start_T3(td->pNDB, td, stat_async);
+ return;
+ }//if
+
+ Uint32 permission = td->transactionData.permission;
+ Uint32 sessions = td->transactionData.sessions;
+ Uint32 server_bit = td->transactionData.server_bit;
+
+ if(((permission & server_bit) == server_bit) &&
+ ((sessions & server_bit) == server_bit)){
+
+ memcpy(td->transactionData.suffix,
+ &td->transactionData.number[SFX_START],
+ SUBSCRIBER_NUMBER_SUFFIX_LENGTH);
+ DEBUG5("T3(%.*s, %.2d): - Callback 2 - reading(%.*s)",
+ SUBSCRIBER_NUMBER_LENGTH,
+ td->transactionData.number,
+ td->transactionData.server_id,
+ SUBSCRIBER_NUMBER_SUFFIX_LENGTH,
+ td->transactionData.suffix);
+
+ /* Operation 3 */
+ NdbOperation * MyOp = pCON->getNdbOperation(SESSION_TABLE);
+ CHECK_NULL(MyOp, "T3-3: getNdbOperation", td,
+ pCON->getNdbError());
+
+ MyOp->simpleRead();
+ MyOp->equal(IND_SESSION_SUBSCRIBER,
+ (char*)td->transactionData.number);
+ MyOp->equal(IND_SESSION_SERVER,
+ (char*)&td->transactionData.server_id);
+ MyOp->getValue(IND_SESSION_DATA,
+ (char *)td->transactionData.session_details);
+
+ /* Operation 4 */
+ MyOp = pCON->getNdbOperation(SERVER_TABLE);
+ CHECK_NULL(MyOp, "T3-4: getNdbOperation", td,
+ pCON->getNdbError());
+
+ MyOp->interpretedUpdateTuple();
+ MyOp->equal(IND_SERVER_ID,
+ (char*)&td->transactionData.server_id);
+ MyOp->equal(IND_SERVER_SUBSCRIBER_SUFFIX,
+ (char*)td->transactionData.suffix);
+ MyOp->incValue(IND_SERVER_READS, (uint32)1);
+ td->transactionData.branchExecuted = 1;
+ } else {
+ DEBUG3("T3(%.*s, %.2d): - Callback 2 - no read",
+ SUBSCRIBER_NUMBER_LENGTH,
+ td->transactionData.number,
+ td->transactionData.server_id);
+ td->transactionData.branchExecuted = 0;
+ }
+ if (stat_async == 1) {
+ pCON->executeAsynchPrepare( Commit , T3_Callback_3, td);
+ } else {
+ int result = pCON->execute( Commit );
+ T3_Callback_3(result, pCON, (void*)td);
+ return;
+ }//if
+}
+
+void
+T3_Callback_3(int result, NdbConnection * pCON, void * threadData){
+ ThreadData * td = (ThreadData *)threadData;
+ DEBUG3("T3(%.*s, %.2d): - Completing", SUBSCRIBER_NUMBER_LENGTH,
+ td->transactionData.number,
+ td->transactionData.server_id);
+
+ if (result == -1) {
+ CHECK_ALLOWED_ERROR("T3-3: Commit", td, pCON->getNdbError());
+ td->pNDB->closeTransaction(pCON);
+ start_T3(td->pNDB, td, stat_async);
+ return;
+ }//if
+ td->pNDB->closeTransaction(pCON);
+ complete_T3(td);
+}
+
+/**
+ * Transaction 4 - T4
+ *
+ * Create session
+ *
+ * Input:
+ * SubscriberNumber
+ * ServerId
+ * ServerBit
+ * SessionDetails,
+ * DoRollback
+ * Output:
+ * ChangedBy
+ * ChangedTime
+ * Location
+ * BranchExecuted
+ */
+void
+start_T4(Ndb * pNDB, ThreadData * td, int async){
+
+ DEBUG3("T4(%.*s, %.2d): - Starting", SUBSCRIBER_NUMBER_LENGTH,
+ td->transactionData.number,
+ td->transactionData.server_id);
+
+ NdbConnection * pCON = 0;
+ while((pCON = startTransaction(pNDB, td)) == 0){
+ CHECK_ALLOWED_ERROR("T4-1: startTransaction", td, pNDB->getNdbError());
+ NdbSleep_MilliSleep(10);
+ }
+
+ NdbOperation *MyOp= pCON->getNdbOperation(SUBSCRIBER_TABLE);
+ CHECK_NULL(MyOp, "T4-1: getNdbOperation", td,
+ pCON->getNdbError());
+
+ MyOp->interpretedUpdateTuple();
+ MyOp->equal(IND_SUBSCRIBER_NUMBER,
+ td->transactionData.number);
+ MyOp->getValue(IND_SUBSCRIBER_LOCATION,
+ (char *)&td->transactionData.location);
+ MyOp->getValue(IND_SUBSCRIBER_CHANGED_BY,
+ td->transactionData.changed_by);
+ MyOp->getValue(IND_SUBSCRIBER_CHANGED_TIME,
+ td->transactionData.changed_time);
+ MyOp->getValue(IND_SUBSCRIBER_GROUP,
+ (char *)&td->transactionData.group_id);
+ MyOp->getValue(IND_SUBSCRIBER_SESSIONS,
+ (char *)&td->transactionData.sessions);
+ MyOp->incValue(IND_SUBSCRIBER_SESSIONS,
+ (uint32)td->transactionData.server_bit);
+ stat_async = async;
+ if (async == 1) {
+ pCON->executeAsynchPrepare( NoCommit , T4_Callback_1, td);
+ } else {
+ int result = pCON->execute( NoCommit );
+ T4_Callback_1(result, pCON, (void*)td);
+ return;
+ }//if
+}
+
+void
+T4_Callback_1(int result, NdbConnection * pCON, void * threadData){
+ ThreadData * td = (ThreadData *)threadData;
+ if (result == -1) {
+ CHECK_ALLOWED_ERROR("T4-1: execute", td, pCON->getNdbError());
+ td->pNDB->closeTransaction(pCON);
+ start_T4(td->pNDB, td, stat_async);
+ return;
+ }//if
+
+ DEBUG3("T4(%.*s, %.2d): - Callback 1",
+ SUBSCRIBER_NUMBER_LENGTH,
+ td->transactionData.number,
+ td->transactionData.server_id);
+
+
+ NdbOperation * MyOp = pCON->getNdbOperation(GROUP_TABLE);
+ CHECK_NULL(MyOp, "T4-2: getNdbOperation", td,
+ pCON->getNdbError());
+
+ MyOp->readTuple();
+ MyOp->equal(IND_GROUP_ID,
+ (char*)&td->transactionData.group_id);
+ MyOp->getValue(IND_GROUP_ALLOW_INSERT,
+ (char *)&td->transactionData.permission);
+ if (stat_async == 1) {
+ pCON->executeAsynchPrepare( NoCommit , T4_Callback_2, td);
+ } else {
+ int result = pCON->execute( NoCommit );
+ T4_Callback_2(result, pCON, (void*)td);
+ return;
+ }//if
+}
+
+void
+T4_Callback_2(int result, NdbConnection * pCON, void * threadData){
+ ThreadData * td = (ThreadData *)threadData;
+ if (result == -1) {
+ CHECK_ALLOWED_ERROR("T4-2: execute", td, pCON->getNdbError());
+ td->pNDB->closeTransaction(pCON);
+ start_T4(td->pNDB, td, stat_async);
+ return;
+ }//if
+
+ Uint32 permission = td->transactionData.permission;
+ Uint32 sessions = td->transactionData.sessions;
+ Uint32 server_bit = td->transactionData.server_bit;
+
+ if(((permission & server_bit) == server_bit) &&
+ ((sessions & server_bit) == 0)){
+
+ memcpy(td->transactionData.suffix,
+ &td->transactionData.number[SFX_START],
+ SUBSCRIBER_NUMBER_SUFFIX_LENGTH);
+
+ DEBUG5("T4(%.*s, %.2d): - Callback 2 - inserting(%.*s)",
+ SUBSCRIBER_NUMBER_LENGTH,
+ td->transactionData.number,
+ td->transactionData.server_id,
+ SUBSCRIBER_NUMBER_SUFFIX_LENGTH,
+ td->transactionData.suffix);
+
+ /* Operation 3 */
+
+ NdbOperation * MyOp = pCON->getNdbOperation(SESSION_TABLE);
+ CHECK_NULL(MyOp, "T4-3: getNdbOperation", td,
+ pCON->getNdbError());
+
+ MyOp->insertTuple();
+ MyOp->equal(IND_SESSION_SUBSCRIBER,
+ (char*)td->transactionData.number);
+ MyOp->equal(IND_SESSION_SERVER,
+ (char*)&td->transactionData.server_id);
+ MyOp->setValue(SESSION_DATA,
+ (char *)td->transactionData.session_details);
+ /* Operation 4 */
+
+ /* Operation 5 */
+ MyOp = pCON->getNdbOperation(SERVER_TABLE);
+ CHECK_NULL(MyOp, "T4-5: getNdbOperation", td,
+ pCON->getNdbError());
+
+ MyOp->interpretedUpdateTuple();
+ MyOp->equal(IND_SERVER_ID,
+ (char*)&td->transactionData.server_id);
+ MyOp->equal(IND_SERVER_SUBSCRIBER_SUFFIX,
+ (char*)td->transactionData.suffix);
+ MyOp->incValue(IND_SERVER_INSERTS, (uint32)1);
+ td->transactionData.branchExecuted = 1;
+ } else {
+ td->transactionData.branchExecuted = 0;
+ DEBUG5("T4(%.*s, %.2d): - Callback 2 - %s %s",
+ SUBSCRIBER_NUMBER_LENGTH,
+ td->transactionData.number,
+ td->transactionData.server_id,
+ ((permission & server_bit) ?
+ "permission - " : "no permission - "),
+ ((sessions & server_bit) ?
+ "in session - " : "no in session - "));
+ }
+
+ if(!td->transactionData.do_rollback && td->transactionData.branchExecuted){
+ if (stat_async == 1) {
+ pCON->executeAsynchPrepare( Commit , T4_Callback_3, td);
+ } else {
+ int result = pCON->execute( Commit );
+ T4_Callback_3(result, pCON, (void*)td);
+ return;
+ }//if
+ } else {
+ if (stat_async == 1) {
+ pCON->executeAsynchPrepare( Rollback , T4_Callback_3, td);
+ } else {
+ int result = pCON->execute( Rollback );
+ T4_Callback_3(result, pCON, (void*)td);
+ return;
+ }//if
+ }
+}
+
+void
+T4_Callback_3(int result, NdbConnection * pCON, void * threadData){
+ ThreadData * td = (ThreadData *)threadData;
+ if (result == -1) {
+ CHECK_ALLOWED_ERROR("T4-3: Commit", td, pCON->getNdbError());
+ td->pNDB->closeTransaction(pCON);
+ start_T4(td->pNDB, td, stat_async);
+ return;
+ }//if
+
+ DEBUG3("T4(%.*s, %.2d): - Completing",
+ SUBSCRIBER_NUMBER_LENGTH,
+ td->transactionData.number,
+ td->transactionData.server_id);
+
+ td->pNDB->closeTransaction(pCON);
+ complete_T4(td);
+}
+
+/**
+ * Transaction 5 - T5
+ *
+ * Delete session
+ *
+ * Input:
+ * SubscriberNumber
+ * ServerId
+ * ServerBit
+ * DoRollback
+ * Output:
+ * ChangedBy
+ * ChangedTime
+ * Location
+ * BranchExecuted
+ */
+void
+start_T5(Ndb * pNDB, ThreadData * td, int async){
+
+ DEBUG3("T5(%.*s, %.2d): - Starting", SUBSCRIBER_NUMBER_LENGTH,
+ td->transactionData.number,
+ td->transactionData.server_id);
+
+ NdbConnection * pCON = 0;
+ while((pCON = startTransaction(pNDB, td)) == 0){
+ CHECK_ALLOWED_ERROR("T5-1: startTransaction", td, pNDB->getNdbError());
+ NdbSleep_MilliSleep(10);
+ }
+
+ NdbOperation * MyOp= pCON->getNdbOperation(SUBSCRIBER_TABLE);
+ CHECK_NULL(MyOp, "T5-1: getNdbOperation", td,
+ pCON->getNdbError());
+
+ MyOp->interpretedUpdateTuple();
+ MyOp->equal(IND_SUBSCRIBER_NUMBER,
+ td->transactionData.number);
+ MyOp->getValue(IND_SUBSCRIBER_LOCATION,
+ (char *)&td->transactionData.location);
+ MyOp->getValue(IND_SUBSCRIBER_CHANGED_BY,
+ td->transactionData.changed_by);
+ MyOp->getValue(IND_SUBSCRIBER_CHANGED_TIME,
+ td->transactionData.changed_time);
+ MyOp->getValue(IND_SUBSCRIBER_GROUP,
+ (char *)&td->transactionData.group_id);
+ MyOp->getValue(IND_SUBSCRIBER_SESSIONS,
+ (char *)&td->transactionData.sessions);
+ MyOp->subValue(IND_SUBSCRIBER_SESSIONS,
+ (uint32)td->transactionData.server_bit);
+ stat_async = async;
+ if (async == 1) {
+ pCON->executeAsynchPrepare( NoCommit , T5_Callback_1, td);
+ } else {
+ int result = pCON->execute( NoCommit );
+ T5_Callback_1(result, pCON, (void*)td);
+ return;
+ }//if
+}
+
+void
+T5_Callback_1(int result, NdbConnection * pCON, void * threadData){
+ ThreadData * td = (ThreadData *)threadData;
+ if (result == -1) {
+ CHECK_ALLOWED_ERROR("T5-1: execute", td, pCON->getNdbError());
+ td->pNDB->closeTransaction(pCON);
+ start_T5(td->pNDB, td, stat_async);
+ return;
+ }//if
+
+ DEBUG3("T5(%.*s, %.2d): - Callback 1",
+ SUBSCRIBER_NUMBER_LENGTH,
+ td->transactionData.number,
+ td->transactionData.server_id);
+
+ NdbOperation * MyOp = pCON->getNdbOperation(GROUP_TABLE);
+ CHECK_NULL(MyOp, "T5-2: getNdbOperation", td,
+ pCON->getNdbError());
+
+ MyOp->readTuple();
+ MyOp->equal(IND_GROUP_ID,
+ (char*)&td->transactionData.group_id);
+ MyOp->getValue(IND_GROUP_ALLOW_DELETE,
+ (char *)&td->transactionData.permission);
+ if (stat_async == 1) {
+ pCON->executeAsynchPrepare( NoCommit , T5_Callback_2, td);
+ } else {
+ int result = pCON->execute( NoCommit );
+ T5_Callback_2(result, pCON, (void*)td);
+ return;
+ }//if
+}
+
+void
+T5_Callback_2(int result, NdbConnection * pCON, void * threadData){
+ ThreadData * td = (ThreadData *)threadData;
+ if (result == -1) {
+ CHECK_ALLOWED_ERROR("T5-2: execute", td, pCON->getNdbError());
+ td->pNDB->closeTransaction(pCON);
+ start_T5(td->pNDB, td, stat_async);
+ return;
+ }//if
+
+ Uint32 permission = td->transactionData.permission;
+ Uint32 sessions = td->transactionData.sessions;
+ Uint32 server_bit = td->transactionData.server_bit;
+
+ if(((permission & server_bit) == server_bit) &&
+ ((sessions & server_bit) == server_bit)){
+
+ memcpy(td->transactionData.suffix,
+ &td->transactionData.number[SFX_START],
+ SUBSCRIBER_NUMBER_SUFFIX_LENGTH);
+
+ DEBUG5("T5(%.*s, %.2d): - Callback 2 - deleting(%.*s)",
+ SUBSCRIBER_NUMBER_LENGTH,
+ td->transactionData.number,
+ td->transactionData.server_id,
+ SUBSCRIBER_NUMBER_SUFFIX_LENGTH,
+ td->transactionData.suffix);
+
+ /* Operation 3 */
+ NdbOperation * MyOp = pCON->getNdbOperation(SESSION_TABLE);
+ CHECK_NULL(MyOp, "T5-3: getNdbOperation", td,
+ pCON->getNdbError());
+
+ MyOp->deleteTuple();
+ MyOp->equal(IND_SESSION_SUBSCRIBER,
+ (char*)td->transactionData.number);
+ MyOp->equal(IND_SESSION_SERVER,
+ (char*)&td->transactionData.server_id);
+ /* Operation 4 */
+
+ /* Operation 5 */
+ MyOp = pCON->getNdbOperation(SERVER_TABLE);
+ CHECK_NULL(MyOp, "T5-5: getNdbOperation", td,
+ pCON->getNdbError());
+
+ MyOp->interpretedUpdateTuple();
+ MyOp->equal(IND_SERVER_ID,
+ (char*)&td->transactionData.server_id);
+ MyOp->equal(IND_SERVER_SUBSCRIBER_SUFFIX,
+ (char*)td->transactionData.suffix);
+ MyOp->incValue(IND_SERVER_DELETES, (uint32)1);
+ td->transactionData.branchExecuted = 1;
+ } else {
+ td->transactionData.branchExecuted = 0;
+
+ DEBUG5("T5(%.*s, %.2d): - Callback 2 - no delete - %s %s",
+ SUBSCRIBER_NUMBER_LENGTH,
+ td->transactionData.number,
+ td->transactionData.server_id,
+ ((permission & server_bit) ?
+ "permission - " : "no permission - "),
+ ((sessions & server_bit) ?
+ "in session - " : "no in session - "));
+ }
+
+ if(!td->transactionData.do_rollback && td->transactionData.branchExecuted){
+ if (stat_async == 1) {
+ pCON->executeAsynchPrepare( Commit , T5_Callback_3, td);
+ } else {
+ int result = pCON->execute( Commit );
+ T5_Callback_3(result, pCON, (void*)td);
+ return;
+ }//if
+ } else {
+ if (stat_async == 1) {
+ pCON->executeAsynchPrepare( Rollback , T5_Callback_3, td);
+ } else {
+ int result = pCON->execute( Rollback );
+ T5_Callback_3(result, pCON, (void*)td);
+ return;
+ }//if
+ }
+}
+
+void
+T5_Callback_3(int result, NdbConnection * pCON, void * threadData){
+ ThreadData * td = (ThreadData *)threadData;
+ if (result == -1) {
+ CHECK_ALLOWED_ERROR("T5-3: Commit", td, pCON->getNdbError());
+ td->pNDB->closeTransaction(pCON);
+ start_T5(td->pNDB, td, stat_async);
+ return;
+ }//if
+
+ DEBUG3("T5(%.*s, %.2d): - Completing",
+ SUBSCRIBER_NUMBER_LENGTH,
+ td->transactionData.number,
+ td->transactionData.server_id);
+
+ td->pNDB->closeTransaction(pCON);
+ complete_T5(td);
+}
diff --git a/ndb/test/ndbapi/bench/ndb_error.hpp b/ndb/test/ndbapi/bench/ndb_error.hpp
new file mode 100644
index 00000000000..d90f5506813
--- /dev/null
+++ b/ndb/test/ndbapi/bench/ndb_error.hpp
@@ -0,0 +1,81 @@
+/* Copyright (C) 2003 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#ifndef NDB_ERROR_H
+#define NDB_ERROR_H
+
+#include <ndb_global.h>
+#include <NdbOut.hpp>
+#include "userInterface.h"
+#include <NdbError.hpp>
+#include <NdbApi.hpp>
+
+#define error_handler(x,y, z) { \
+ ndbout << x << " " << y << endl; \
+ exit(-1); }
+
+#define CHECK_MINUS_ONE(x, y, z) if(x == -1) \
+ error_handler(y,(z->getNdbError()), 0)
+
+inline
+void
+CHECK_ALLOWED_ERROR(const char * str,
+ const ThreadData * td,
+ const struct NdbError & error){
+
+ char buf[100];
+ snprintf(buf, sizeof(buf), "subscriber = %.*s ",
+ SUBSCRIBER_NUMBER_LENGTH,
+ td->transactionData.number);
+ ndbout << str << " " << error << endl
+ << buf;
+ showTime();
+
+ switch(error.classification) {
+ case NdbError::TimeoutExpired:
+ case NdbError::OverloadError:
+ case NdbError::TemporaryResourceError:
+ case NdbError::NodeRecoveryError:
+ break;
+ default:
+ if(error.status != NdbError::TemporaryError)
+ exit(-1);
+ }
+}
+
+inline
+void
+CHECK_NULL(void * null,
+ const char * str,
+ const ThreadData * td,
+ const struct NdbError & err){
+ if(null == 0){
+ CHECK_ALLOWED_ERROR(str, td, err);
+ exit(-1);
+ }
+}
+
+inline
+void
+CHECK_NULL(void * null, const char* msg, NdbConnection* obj)
+{
+ if(null == 0)
+ {
+ error_handler(msg, obj->getNdbError(), 0);
+ }
+}
+
+#endif
diff --git a/ndb/test/ndbapi/bench/ndb_schema.hpp b/ndb/test/ndbapi/bench/ndb_schema.hpp
new file mode 100644
index 00000000000..af08bc2eecd
--- /dev/null
+++ b/ndb/test/ndbapi/bench/ndb_schema.hpp
@@ -0,0 +1,78 @@
+/* Copyright (C) 2003 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#ifndef NDB_SCHEMA_H
+#define NDB_SCHEMA_H
+
+#include "testDefinitions.h"
+
+#define SUBSCRIBER_TABLE "SUBSCRIBER"
+#define SUBSCRIBER_NUMBER "NUMBER"
+#define SUBSCRIBER_LOCATION "LOCATION"
+#define SUBSCRIBER_NAME "NAME"
+#define SUBSCRIBER_GROUP "GROUP_ID"
+#define SUBSCRIBER_SESSIONS "SESSIONS"
+#define SUBSCRIBER_CHANGED_BY "CHANGED_BY"
+#define SUBSCRIBER_CHANGED_TIME "CHANGED_TIME"
+
+#define SERVER_TABLE "SERVER"
+#define SERVER_ID "SERVER_ID"
+#define SERVER_SUBSCRIBER_SUFFIX "SUFFIX"
+#define SERVER_NAME "NAME"
+#define SERVER_READS "NO_OF_READ"
+#define SERVER_INSERTS "NO_OF_INSERT"
+#define SERVER_DELETES "NO_OF_DELETE"
+
+#define GROUP_TABLE "GROUP"
+#define GROUP_ID "GROUP_ID"
+#define GROUP_NAME "GROUP_NAME"
+#define GROUP_ALLOW_READ "ALLOW_READ"
+#define GROUP_ALLOW_INSERT "ALLOW_INSERT"
+#define GROUP_ALLOW_DELETE "ALLOW_DELETE"
+
+#define SESSION_TABLE "SESSION"
+#define SESSION_SERVER "SERVER_ID"
+#define SESSION_SUBSCRIBER "NUMBER"
+#define SESSION_DATA "DATA"
+
+/** Numbers */
+
+#define IND_SUBSCRIBER_NUMBER (unsigned)0
+#define IND_SUBSCRIBER_NAME (unsigned)1
+#define IND_SUBSCRIBER_GROUP (unsigned)2
+#define IND_SUBSCRIBER_LOCATION (unsigned)3
+#define IND_SUBSCRIBER_SESSIONS (unsigned)4
+#define IND_SUBSCRIBER_CHANGED_BY (unsigned)5
+#define IND_SUBSCRIBER_CHANGED_TIME (unsigned)6
+
+#define IND_SERVER_SUBSCRIBER_SUFFIX (unsigned)0
+#define IND_SERVER_ID (unsigned)1
+#define IND_SERVER_NAME (unsigned)2
+#define IND_SERVER_READS (unsigned)3
+#define IND_SERVER_INSERTS (unsigned)4
+#define IND_SERVER_DELETES (unsigned)5
+
+#define IND_GROUP_ID (unsigned)0
+#define IND_GROUP_NAME (unsigned)1
+#define IND_GROUP_ALLOW_READ (unsigned)2
+#define IND_GROUP_ALLOW_INSERT (unsigned)3
+#define IND_GROUP_ALLOW_DELETE (unsigned)4
+
+#define IND_SESSION_SUBSCRIBER (unsigned)0
+#define IND_SESSION_SERVER (unsigned)1
+#define IND_SESSION_DATA (unsigned)2
+
+#endif
diff --git a/ndb/test/ndbapi/bench/ndb_user_transaction.cpp b/ndb/test/ndbapi/bench/ndb_user_transaction.cpp
new file mode 100644
index 00000000000..182f1f99586
--- /dev/null
+++ b/ndb/test/ndbapi/bench/ndb_user_transaction.cpp
@@ -0,0 +1,825 @@
+/* Copyright (C) 2003 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+//#define DEBUG_ON
+
+extern "C" {
+#include "user_transaction.h"
+};
+
+#include "macros.h"
+#include "ndb_schema.hpp"
+#include "ndb_error.hpp"
+
+#include <time.h>
+#include <NdbApi.hpp>
+
+/**
+ * Transaction 1 - T1
+ *
+ * Update location and changed by/time on a subscriber
+ *
+ * Input:
+ * SubscriberNumber,
+ * Location,
+ * ChangedBy,
+ * ChangedTime
+ *
+ * Output:
+ */
+int
+T1(void * obj,
+ const SubscriberNumber number,
+ const Location new_location,
+ const ChangedBy changed_by,
+ const ChangedTime changed_time,
+ BenchmarkTime * transaction_time){
+
+ Ndb * pNDB = (Ndb *) obj;
+
+ BenchmarkTime start;
+ get_time(&start);
+
+ int check;
+ NdbRecAttr * check2;
+
+ NdbConnection * MyTransaction = pNDB->startTransaction();
+ if (MyTransaction == NULL)
+ error_handler("T1: startTranscation", pNDB->getNdbErrorString(), 0);
+
+ NdbOperation *MyOperation = MyTransaction->getNdbOperation(SUBSCRIBER_TABLE);
+ CHECK_NULL(MyOperation, "T1: getNdbOperation", MyTransaction);
+
+ check = MyOperation->updateTuple();
+ CHECK_MINUS_ONE(check, "T1: updateTuple",
+ MyTransaction);
+
+ check = MyOperation->equal(SUBSCRIBER_NUMBER,
+ number);
+ CHECK_MINUS_ONE(check, "T1: equal subscriber",
+ MyTransaction);
+
+ check = MyOperation->setValue(SUBSCRIBER_LOCATION,
+ (char *)&new_location);
+ CHECK_MINUS_ONE(check, "T1: setValue location",
+ MyTransaction);
+
+ check = MyOperation->setValue(SUBSCRIBER_CHANGED_BY,
+ changed_by);
+ CHECK_MINUS_ONE(check, "T1: setValue changed_by",
+ MyTransaction);
+
+ check = MyOperation->setValue(SUBSCRIBER_CHANGED_TIME,
+ changed_time);
+ CHECK_MINUS_ONE(check, "T1: setValue changed_time",
+ MyTransaction);
+
+ check = MyTransaction->execute( Commit );
+ CHECK_MINUS_ONE(check, "T1: Commit",
+ MyTransaction);
+
+ pNDB->closeTransaction(MyTransaction);
+
+ get_time(transaction_time);
+ time_diff(transaction_time, &start);
+ return 0;
+}
+
+/**
+ * Transaction 2 - T2
+ *
+ * Read from Subscriber:
+ *
+ * Input:
+ * SubscriberNumber
+ *
+ * Output:
+ * Location
+ * Changed by
+ * Changed Timestamp
+ * Name
+ */
+int
+T2(void * obj,
+ const SubscriberNumber number,
+ Location * readLocation,
+ ChangedBy changed_by,
+ ChangedTime changed_time,
+ SubscriberName subscriberName,
+ BenchmarkTime * transaction_time){
+
+ Ndb * pNDB = (Ndb *) obj;
+
+ BenchmarkTime start;
+ get_time(&start);
+
+ int check;
+ NdbRecAttr * check2;
+
+ NdbConnection * MyTransaction = pNDB->startTransaction();
+ if (MyTransaction == NULL)
+ error_handler("T2: startTranscation", pNDB->getNdbErrorString(), 0);
+
+ NdbOperation *MyOperation= MyTransaction->getNdbOperation(SUBSCRIBER_TABLE);
+ CHECK_NULL(MyOperation, "T2: getNdbOperation",
+ MyTransaction);
+
+
+ check = MyOperation->readTuple();
+ CHECK_MINUS_ONE(check, "T2: readTuple",
+ MyTransaction);
+
+ check = MyOperation->equal(SUBSCRIBER_NUMBER,
+ number);
+ CHECK_MINUS_ONE(check, "T2: equal subscriber",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(SUBSCRIBER_LOCATION,
+ (char *)readLocation);
+ CHECK_NULL(check2, "T2: getValue location",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(SUBSCRIBER_CHANGED_BY,
+ changed_by);
+ CHECK_NULL(check2, "T2: getValue changed_by",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(SUBSCRIBER_CHANGED_TIME,
+ changed_time);
+ CHECK_NULL(check2, "T2: getValue changed_time",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(SUBSCRIBER_NAME,
+ subscriberName);
+ CHECK_NULL(check2, "T2: getValue name",
+ MyTransaction);
+
+ check = MyTransaction->execute( Commit );
+ CHECK_MINUS_ONE(check, "T2: Commit",
+ MyTransaction);
+
+ pNDB->closeTransaction(MyTransaction);
+
+ get_time(transaction_time);
+ time_diff(transaction_time, &start);
+ return 0;
+}
+
+/**
+ * Transaction 3 - T3
+ *
+ * Read session details
+ *
+ * Input:
+ * SubscriberNumber
+ * ServerId
+ * ServerBit
+ *
+ * Output:
+ * BranchExecuted
+ * SessionDetails
+ * ChangedBy
+ * ChangedTime
+ * Location
+ */
+int
+T3(void * obj,
+ const SubscriberNumber inNumber,
+ const SubscriberSuffix inSuffix,
+ const ServerId inServerId,
+ const ServerBit inServerBit,
+ SessionDetails outSessionDetails,
+ ChangedBy outChangedBy,
+ ChangedTime outChangedTime,
+ Location * outLocation,
+ BranchExecuted * outBranchExecuted,
+ BenchmarkTime * outTransactionTime){
+
+ Ndb * pNDB = (Ndb *) obj;
+
+ GroupId groupId;
+ ActiveSessions sessions;
+ Permission permission;
+
+ BenchmarkTime start;
+ get_time(&start);
+
+ int check;
+ NdbRecAttr * check2;
+
+ NdbConnection * MyTransaction = pNDB->startTransaction();
+ if (MyTransaction == NULL)
+ error_handler("T3-1: startTranscation", pNDB->getNdbErrorString(), 0);
+
+ NdbOperation *MyOperation= MyTransaction->getNdbOperation(SUBSCRIBER_TABLE);
+ CHECK_NULL(MyOperation, "T3-1: getNdbOperation",
+ MyTransaction);
+
+
+ check = MyOperation->readTuple();
+ CHECK_MINUS_ONE(check, "T3-1: readTuple",
+ MyTransaction);
+
+ check = MyOperation->equal(SUBSCRIBER_NUMBER,
+ inNumber);
+ CHECK_MINUS_ONE(check, "T3-1: equal subscriber",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(SUBSCRIBER_LOCATION,
+ (char *)outLocation);
+ CHECK_NULL(check2, "T3-1: getValue location",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(SUBSCRIBER_CHANGED_BY,
+ outChangedBy);
+ CHECK_NULL(check2, "T3-1: getValue changed_by",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(SUBSCRIBER_CHANGED_TIME,
+ outChangedTime);
+ CHECK_NULL(check2, "T3-1: getValue changed_time",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(SUBSCRIBER_GROUP,
+ (char *)&groupId);
+ CHECK_NULL(check2, "T3-1: getValue group",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(SUBSCRIBER_SESSIONS,
+ (char *)&sessions);
+ CHECK_NULL(check2, "T3-1: getValue sessions",
+ MyTransaction);
+
+ check = MyTransaction->execute( NoCommit );
+ CHECK_MINUS_ONE(check, "T3-1: NoCommit",
+ MyTransaction);
+
+ /* Operation 2 */
+
+ MyOperation = MyTransaction->getNdbOperation(GROUP_TABLE);
+ CHECK_NULL(MyOperation, "T3-2: getNdbOperation",
+ MyTransaction);
+
+
+ check = MyOperation->readTuple();
+ CHECK_MINUS_ONE(check, "T3-2: readTuple",
+ MyTransaction);
+
+ check = MyOperation->equal(GROUP_ID,
+ (char*)&groupId);
+ CHECK_MINUS_ONE(check, "T3-2: equal group",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(GROUP_ALLOW_READ,
+ (char *)&permission);
+ CHECK_NULL(check2, "T3-2: getValue allow_read",
+ MyTransaction);
+
+ check = MyTransaction->execute( NoCommit );
+ CHECK_MINUS_ONE(check, "T3-2: NoCommit",
+ MyTransaction);
+
+ DEBUG3("T3(%.*s, %.2d): ", SUBSCRIBER_NUMBER_LENGTH, inNumber, inServerId);
+
+ if(((permission & inServerBit) == inServerBit) &&
+ ((sessions & inServerBit) == inServerBit)){
+
+ DEBUG("reading - ");
+
+ /* Operation 3 */
+
+ MyOperation = MyTransaction->getNdbOperation(SESSION_TABLE);
+ CHECK_NULL(MyOperation, "T3-3: getNdbOperation",
+ MyTransaction);
+
+ check = MyOperation->readTuple();
+ CHECK_MINUS_ONE(check, "T3-3: readTuple",
+ MyTransaction);
+
+ check = MyOperation->equal(SESSION_SUBSCRIBER,
+ (char*)inNumber);
+ CHECK_MINUS_ONE(check, "T3-3: equal number",
+ MyTransaction);
+
+ check = MyOperation->equal(SESSION_SERVER,
+ (char*)&inServerId);
+ CHECK_MINUS_ONE(check, "T3-3: equal server id",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(SESSION_DATA,
+ (char *)outSessionDetails);
+ CHECK_NULL(check2, "T3-3: getValue session details",
+ MyTransaction);
+
+ check = MyTransaction->execute( NoCommit );
+ CHECK_MINUS_ONE(check, "T3-3: NoCommit",
+ MyTransaction);
+
+ /* Operation 4 */
+
+ MyOperation = MyTransaction->getNdbOperation(SERVER_TABLE);
+ CHECK_NULL(MyOperation, "T3-4: getNdbOperation",
+ MyTransaction);
+
+ check = MyOperation->interpretedUpdateTuple();
+ CHECK_MINUS_ONE(check, "T3-4: interpretedUpdateTuple",
+ MyTransaction);
+
+ check = MyOperation->equal(SERVER_ID,
+ (char*)&inServerId);
+ CHECK_MINUS_ONE(check, "T3-4: equal serverId",
+ MyTransaction);
+
+ check = MyOperation->equal(SERVER_SUBSCRIBER_SUFFIX,
+ (char*)inSuffix);
+ CHECK_MINUS_ONE(check, "T3-4: equal suffix",
+ MyTransaction);
+
+ check = MyOperation->incValue(SERVER_READS, (uint32)1);
+ CHECK_MINUS_ONE(check, "T3-4: inc value",
+ MyTransaction);
+
+ check = MyTransaction->execute( NoCommit );
+ CHECK_MINUS_ONE(check, "T3-4: NoCommit",
+ MyTransaction);
+
+ (* outBranchExecuted) = 1;
+ } else {
+ (* outBranchExecuted) = 0;
+ }
+ DEBUG("commit\n");
+ check = MyTransaction->execute( Commit );
+ CHECK_MINUS_ONE(check, "T3: Commit",
+ MyTransaction);
+
+ pNDB->closeTransaction(MyTransaction);
+
+ get_time(outTransactionTime);
+ time_diff(outTransactionTime, &start);
+ return 0;
+}
+
+
+/**
+ * Transaction 4 - T4
+ *
+ * Create session
+ *
+ * Input:
+ * SubscriberNumber
+ * ServerId
+ * ServerBit
+ * SessionDetails,
+ * DoRollback
+ * Output:
+ * ChangedBy
+ * ChangedTime
+ * Location
+ * BranchExecuted
+ */
+int
+T4(void * obj,
+ const SubscriberNumber inNumber,
+ const SubscriberSuffix inSuffix,
+ const ServerId inServerId,
+ const ServerBit inServerBit,
+ const SessionDetails inSessionDetails,
+ ChangedBy outChangedBy,
+ ChangedTime outChangedTime,
+ Location * outLocation,
+ DoRollback inDoRollback,
+ BranchExecuted * outBranchExecuted,
+ BenchmarkTime * outTransactionTime){
+
+ Ndb * pNDB = (Ndb *) obj;
+
+ GroupId groupId;
+ ActiveSessions sessions;
+ Permission permission;
+
+ BenchmarkTime start;
+ get_time(&start);
+
+ int check;
+ NdbRecAttr * check2;
+
+ NdbConnection * MyTransaction = pNDB->startTransaction();
+ if (MyTransaction == NULL)
+ error_handler("T4-1: startTranscation", pNDB->getNdbErrorString(), 0);
+
+ DEBUG3("T4(%.*s, %.2d): ", SUBSCRIBER_NUMBER_LENGTH, inNumber, inServerId);
+
+ NdbOperation * MyOperation = 0;
+
+ MyOperation= MyTransaction->getNdbOperation(SUBSCRIBER_TABLE);
+ CHECK_NULL(MyOperation, "T4-1: getNdbOperation",
+ MyTransaction);
+
+ check = MyOperation->readTupleExclusive();
+ CHECK_MINUS_ONE(check, "T4-1: readTuple",
+ MyTransaction);
+
+ check = MyOperation->equal(SUBSCRIBER_NUMBER,
+ inNumber);
+ CHECK_MINUS_ONE(check, "T4-1: equal subscriber",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(SUBSCRIBER_LOCATION,
+ (char *)outLocation);
+ CHECK_NULL(check2, "T4-1: getValue location",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(SUBSCRIBER_CHANGED_BY,
+ outChangedBy);
+ CHECK_NULL(check2, "T4-1: getValue changed_by",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(SUBSCRIBER_CHANGED_TIME,
+ outChangedTime);
+ CHECK_NULL(check2, "T4-1: getValue changed_time",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(SUBSCRIBER_GROUP,
+ (char *)&groupId);
+ CHECK_NULL(check2, "T4-1: getValue group",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(SUBSCRIBER_SESSIONS,
+ (char *)&sessions);
+ CHECK_NULL(check2, "T4-1: getValue sessions",
+ MyTransaction);
+
+ check = MyTransaction->execute( NoCommit );
+ CHECK_MINUS_ONE(check, "T4-1: NoCommit",
+ MyTransaction);
+
+ /* Operation 2 */
+ MyOperation = MyTransaction->getNdbOperation(GROUP_TABLE);
+ CHECK_NULL(MyOperation, "T4-2: getNdbOperation",
+ MyTransaction);
+
+ check = MyOperation->readTuple();
+ CHECK_MINUS_ONE(check, "T4-2: readTuple",
+ MyTransaction);
+
+ check = MyOperation->equal(GROUP_ID,
+ (char*)&groupId);
+ CHECK_MINUS_ONE(check, "T4-2: equal group",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(GROUP_ALLOW_INSERT,
+ (char *)&permission);
+ CHECK_NULL(check2, "T4-2: getValue allow_insert",
+ MyTransaction);
+
+ check = MyTransaction->execute( NoCommit );
+ CHECK_MINUS_ONE(check, "T4-2: NoCommit",
+ MyTransaction);
+
+ if(((permission & inServerBit) == inServerBit) &&
+ ((sessions & inServerBit) == 0)){
+
+ DEBUG("inserting - ");
+
+ /* Operation 3 */
+ MyOperation = MyTransaction->getNdbOperation(SESSION_TABLE);
+ CHECK_NULL(MyOperation, "T4-3: getNdbOperation",
+ MyTransaction);
+
+ check = MyOperation->insertTuple();
+ CHECK_MINUS_ONE(check, "T4-3: insertTuple",
+ MyTransaction);
+
+ check = MyOperation->equal(SESSION_SUBSCRIBER,
+ (char*)inNumber);
+ CHECK_MINUS_ONE(check, "T4-3: equal number",
+ MyTransaction);
+
+ check = MyOperation->equal(SESSION_SERVER,
+ (char*)&inServerId);
+ CHECK_MINUS_ONE(check, "T4-3: equal server id",
+ MyTransaction);
+
+ check = MyOperation->setValue(SESSION_DATA,
+ (char *)inSessionDetails);
+ CHECK_MINUS_ONE(check, "T4-3: setValue session details",
+ MyTransaction);
+
+ check = MyTransaction->execute( NoCommit );
+ CHECK_MINUS_ONE(check, "T4-3: NoCommit",
+ MyTransaction);
+
+ /* Operation 4 */
+ MyOperation = MyTransaction->getNdbOperation(SUBSCRIBER_TABLE);
+ CHECK_NULL(MyOperation, "T4-4: getNdbOperation",
+ MyTransaction);
+
+ check = MyOperation->interpretedUpdateTuple();
+ CHECK_MINUS_ONE(check, "T4-4: interpretedUpdateTuple",
+ MyTransaction);
+
+ check = MyOperation->equal(SUBSCRIBER_NUMBER,
+ (char*)inNumber);
+ CHECK_MINUS_ONE(check, "T4-4: equal number",
+ MyTransaction);
+
+ check = MyOperation->incValue(SUBSCRIBER_SESSIONS,
+ (uint32)inServerBit);
+ CHECK_MINUS_ONE(check, "T4-4: inc value",
+ MyTransaction);
+
+ check = MyTransaction->execute( NoCommit );
+ CHECK_MINUS_ONE(check, "T4-4: NoCommit",
+ MyTransaction);
+
+ /* Operation 5 */
+ MyOperation = MyTransaction->getNdbOperation(SERVER_TABLE);
+ CHECK_NULL(MyOperation, "T4-5: getNdbOperation",
+ MyTransaction);
+
+ check = MyOperation->interpretedUpdateTuple();
+ CHECK_MINUS_ONE(check, "T4-5: interpretedUpdateTuple",
+ MyTransaction);
+
+ check = MyOperation->equal(SERVER_ID,
+ (char*)&inServerId);
+ CHECK_MINUS_ONE(check, "T4-5: equal serverId",
+ MyTransaction);
+
+ check = MyOperation->equal(SERVER_SUBSCRIBER_SUFFIX,
+ (char*)inSuffix);
+ CHECK_MINUS_ONE(check, "T4-5: equal suffix",
+ MyTransaction);
+
+ check = MyOperation->incValue(SERVER_INSERTS, (uint32)1);
+ CHECK_MINUS_ONE(check, "T4-5: inc value",
+ MyTransaction);
+
+ check = MyTransaction->execute( NoCommit );
+ CHECK_MINUS_ONE(check, "T4-5: NoCommit",
+ MyTransaction);
+
+ (* outBranchExecuted) = 1;
+ } else {
+ DEBUG1("%s", ((permission & inServerBit) ? "permission - " : "no permission - "));
+ DEBUG1("%s", ((sessions & inServerBit) ? "in session - " : "no in session - "));
+ (* outBranchExecuted) = 0;
+ }
+
+ if(!inDoRollback){
+ DEBUG("commit\n");
+ check = MyTransaction->execute( Commit );
+ CHECK_MINUS_ONE(check, "T4: Commit",
+ MyTransaction);
+ } else {
+ DEBUG("rollback\n");
+ check = MyTransaction->execute(Rollback);
+ CHECK_MINUS_ONE(check, "T4:Rollback",
+ MyTransaction);
+
+ }
+
+ pNDB->closeTransaction(MyTransaction);
+
+ get_time(outTransactionTime);
+ time_diff(outTransactionTime, &start);
+ return 0;
+}
+
+
+/**
+ * Transaction 5 - T5
+ *
+ * Delete session
+ *
+ * Input:
+ * SubscriberNumber
+ * ServerId
+ * ServerBit
+ * DoRollback
+ * Output:
+ * ChangedBy
+ * ChangedTime
+ * Location
+ * BranchExecuted
+ */
+int
+T5(void * obj,
+ const SubscriberNumber inNumber,
+ const SubscriberSuffix inSuffix,
+ const ServerId inServerId,
+ const ServerBit inServerBit,
+ ChangedBy outChangedBy,
+ ChangedTime outChangedTime,
+ Location * outLocation,
+ DoRollback inDoRollback,
+ BranchExecuted * outBranchExecuted,
+ BenchmarkTime * outTransactionTime){
+
+ Ndb * pNDB = (Ndb *) obj;
+ NdbConnection * MyTransaction = 0;
+ NdbOperation * MyOperation = 0;
+
+ GroupId groupId;
+ ActiveSessions sessions;
+ Permission permission;
+
+ BenchmarkTime start;
+ get_time(&start);
+
+ int check;
+ NdbRecAttr * check2;
+
+ MyTransaction = pNDB->startTransaction();
+ if (MyTransaction == NULL)
+ error_handler("T5-1: startTranscation", pNDB->getNdbErrorString(), 0);
+
+ MyOperation= MyTransaction->getNdbOperation(SUBSCRIBER_TABLE);
+ CHECK_NULL(MyOperation, "T5-1: getNdbOperation",
+ MyTransaction);
+
+
+ check = MyOperation->readTupleExclusive();
+ CHECK_MINUS_ONE(check, "T5-1: readTuple",
+ MyTransaction);
+
+ check = MyOperation->equal(SUBSCRIBER_NUMBER,
+ inNumber);
+ CHECK_MINUS_ONE(check, "T5-1: equal subscriber",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(SUBSCRIBER_LOCATION,
+ (char *)outLocation);
+ CHECK_NULL(check2, "T5-1: getValue location",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(SUBSCRIBER_CHANGED_BY,
+ outChangedBy);
+ CHECK_NULL(check2, "T5-1: getValue changed_by",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(SUBSCRIBER_CHANGED_TIME,
+ outChangedTime);
+ CHECK_NULL(check2, "T5-1: getValue changed_time",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(SUBSCRIBER_GROUP,
+ (char *)&groupId);
+ CHECK_NULL(check2, "T5-1: getValue group",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(SUBSCRIBER_SESSIONS,
+ (char *)&sessions);
+ CHECK_NULL(check2, "T5-1: getValue sessions",
+ MyTransaction);
+
+ check = MyTransaction->execute( NoCommit );
+ CHECK_MINUS_ONE(check, "T5-1: NoCommit",
+ MyTransaction);
+
+ /* Operation 2 */
+
+ MyOperation = MyTransaction->getNdbOperation(GROUP_TABLE);
+ CHECK_NULL(MyOperation, "T5-2: getNdbOperation",
+ MyTransaction);
+
+
+ check = MyOperation->readTuple();
+ CHECK_MINUS_ONE(check, "T5-2: readTuple",
+ MyTransaction);
+
+ check = MyOperation->equal(GROUP_ID,
+ (char*)&groupId);
+ CHECK_MINUS_ONE(check, "T5-2: equal group",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(GROUP_ALLOW_DELETE,
+ (char *)&permission);
+ CHECK_NULL(check2, "T5-2: getValue allow_delete",
+ MyTransaction);
+
+ check = MyTransaction->execute( NoCommit );
+ CHECK_MINUS_ONE(check, "T5-2: NoCommit",
+ MyTransaction);
+
+ DEBUG3("T5(%.*s, %.2d): ", SUBSCRIBER_NUMBER_LENGTH, inNumber, inServerId);
+
+ if(((permission & inServerBit) == inServerBit) &&
+ ((sessions & inServerBit) == inServerBit)){
+
+ DEBUG("deleting - ");
+
+ /* Operation 3 */
+ MyOperation = MyTransaction->getNdbOperation(SESSION_TABLE);
+ CHECK_NULL(MyOperation, "T5-3: getNdbOperation",
+ MyTransaction);
+
+ check = MyOperation->deleteTuple();
+ CHECK_MINUS_ONE(check, "T5-3: deleteTuple",
+ MyTransaction);
+
+ check = MyOperation->equal(SESSION_SUBSCRIBER,
+ (char*)inNumber);
+ CHECK_MINUS_ONE(check, "T5-3: equal number",
+ MyTransaction);
+
+ check = MyOperation->equal(SESSION_SERVER,
+ (char*)&inServerId);
+ CHECK_MINUS_ONE(check, "T5-3: equal server id",
+ MyTransaction);
+
+ check = MyTransaction->execute( NoCommit );
+ CHECK_MINUS_ONE(check, "T5-3: NoCommit",
+ MyTransaction);
+
+ /* Operation 4 */
+ MyOperation = MyTransaction->getNdbOperation(SUBSCRIBER_TABLE);
+ CHECK_NULL(MyOperation, "T5-4: getNdbOperation",
+ MyTransaction);
+
+ check = MyOperation->interpretedUpdateTuple();
+ CHECK_MINUS_ONE(check, "T5-4: interpretedUpdateTuple",
+ MyTransaction);
+
+ check = MyOperation->equal(SUBSCRIBER_NUMBER,
+ (char*)inNumber);
+ CHECK_MINUS_ONE(check, "T5-4: equal number",
+ MyTransaction);
+
+ check = MyOperation->subValue(SUBSCRIBER_SESSIONS,
+ (uint32)inServerBit);
+ CHECK_MINUS_ONE(check, "T5-4: dec value",
+ MyTransaction);
+
+ check = MyTransaction->execute( NoCommit );
+ CHECK_MINUS_ONE(check, "T5-4: NoCommit",
+ MyTransaction);
+
+ /* Operation 5 */
+ MyOperation = MyTransaction->getNdbOperation(SERVER_TABLE);
+ CHECK_NULL(MyOperation, "T5-5: getNdbOperation",
+ MyTransaction);
+
+
+ check = MyOperation->interpretedUpdateTuple();
+ CHECK_MINUS_ONE(check, "T5-5: interpretedUpdateTuple",
+ MyTransaction);
+
+ check = MyOperation->equal(SERVER_ID,
+ (char*)&inServerId);
+ CHECK_MINUS_ONE(check, "T5-5: equal serverId",
+ MyTransaction);
+
+ check = MyOperation->equal(SERVER_SUBSCRIBER_SUFFIX,
+ (char*)inSuffix);
+ CHECK_MINUS_ONE(check, "T5-5: equal suffix",
+ MyTransaction);
+
+ check = MyOperation->incValue(SERVER_DELETES, (uint32)1);
+ CHECK_MINUS_ONE(check, "T5-5: inc value",
+ MyTransaction);
+
+ check = MyTransaction->execute( NoCommit );
+ CHECK_MINUS_ONE(check, "T5-5: NoCommit",
+ MyTransaction);
+
+ (* outBranchExecuted) = 1;
+ } else {
+ DEBUG1("%s", ((permission & inServerBit) ? "permission - " : "no permission - "));
+ DEBUG1("%s", ((sessions & inServerBit) ? "in session - " : "no in session - "));
+ (* outBranchExecuted) = 0;
+ }
+
+ if(!inDoRollback){
+ DEBUG("commit\n");
+ check = MyTransaction->execute( Commit );
+ CHECK_MINUS_ONE(check, "T5: Commit",
+ MyTransaction);
+ } else {
+ DEBUG("rollback\n");
+ check = MyTransaction->execute(Rollback);
+ CHECK_MINUS_ONE(check, "T5:Rollback",
+ MyTransaction);
+
+ }
+
+ pNDB->closeTransaction(MyTransaction);
+
+ get_time(outTransactionTime);
+ time_diff(outTransactionTime, &start);
+ return 0;
+}
+
diff --git a/ndb/test/ndbapi/bench/ndb_user_transaction2.cpp b/ndb/test/ndbapi/bench/ndb_user_transaction2.cpp
new file mode 100644
index 00000000000..df3c7a7989e
--- /dev/null
+++ b/ndb/test/ndbapi/bench/ndb_user_transaction2.cpp
@@ -0,0 +1,825 @@
+/* Copyright (C) 2003 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+//#define DEBUG_ON
+
+extern "C" {
+#include "user_transaction.h"
+};
+
+#include "macros.h"
+#include "ndb_schema.hpp"
+#include "ndb_error.hpp"
+
+#include <time.h>
+#include <NdbApi.hpp>
+
+/**
+ * Transaction 1 - T1
+ *
+ * Update location and changed by/time on a subscriber
+ *
+ * Input:
+ * SubscriberNumber,
+ * Location,
+ * ChangedBy,
+ * ChangedTime
+ *
+ * Output:
+ */
+int
+T1(void * obj,
+ const SubscriberNumber number,
+ const Location new_location,
+ const ChangedBy changed_by,
+ const ChangedTime changed_time,
+ BenchmarkTime * transaction_time){
+
+ Ndb * pNDB = (Ndb *) obj;
+
+ BenchmarkTime start;
+ get_time(&start);
+
+ int check;
+ NdbRecAttr * check2;
+
+ NdbConnection * MyTransaction = pNDB->startTransaction();
+ if (MyTransaction == NULL)
+ error_handler("T1: startTranscation", pNDB->getNdbErrorString(), 0);
+
+ NdbOperation *MyOperation = MyTransaction->getNdbOperation(SUBSCRIBER_TABLE);
+ CHECK_NULL(MyOperation, "T1: getNdbOperation", MyTransaction);
+
+ check = MyOperation->updateTuple();
+ CHECK_MINUS_ONE(check, "T1: updateTuple",
+ MyTransaction);
+
+ check = MyOperation->equal(IND_SUBSCRIBER_NUMBER,
+ number);
+ CHECK_MINUS_ONE(check, "T1: equal subscriber",
+ MyTransaction);
+
+ check = MyOperation->setValue(IND_SUBSCRIBER_LOCATION,
+ (char *)&new_location);
+ CHECK_MINUS_ONE(check, "T1: setValue location",
+ MyTransaction);
+
+ check = MyOperation->setValue(IND_SUBSCRIBER_CHANGED_BY,
+ changed_by);
+ CHECK_MINUS_ONE(check, "T1: setValue changed_by",
+ MyTransaction);
+
+ check = MyOperation->setValue(IND_SUBSCRIBER_CHANGED_TIME,
+ changed_time);
+ CHECK_MINUS_ONE(check, "T1: setValue changed_time",
+ MyTransaction);
+
+ check = MyTransaction->execute( Commit );
+ CHECK_MINUS_ONE(check, "T1: Commit",
+ MyTransaction);
+
+ pNDB->closeTransaction(MyTransaction);
+
+ get_time(transaction_time);
+ time_diff(transaction_time, &start);
+ return 0;
+}
+
+/**
+ * Transaction 2 - T2
+ *
+ * Read from Subscriber:
+ *
+ * Input:
+ * SubscriberNumber
+ *
+ * Output:
+ * Location
+ * Changed by
+ * Changed Timestamp
+ * Name
+ */
+int
+T2(void * obj,
+ const SubscriberNumber number,
+ Location * readLocation,
+ ChangedBy changed_by,
+ ChangedTime changed_time,
+ SubscriberName subscriberName,
+ BenchmarkTime * transaction_time){
+
+ Ndb * pNDB = (Ndb *) obj;
+
+ BenchmarkTime start;
+ get_time(&start);
+
+ int check;
+ NdbRecAttr * check2;
+
+ NdbConnection * MyTransaction = pNDB->startTransaction();
+ if (MyTransaction == NULL)
+ error_handler("T2: startTranscation", pNDB->getNdbErrorString(), 0);
+
+ NdbOperation *MyOperation= MyTransaction->getNdbOperation(SUBSCRIBER_TABLE);
+ CHECK_NULL(MyOperation, "T2: getNdbOperation",
+ MyTransaction);
+
+
+ check = MyOperation->readTuple();
+ CHECK_MINUS_ONE(check, "T2: readTuple",
+ MyTransaction);
+
+ check = MyOperation->equal(IND_SUBSCRIBER_NUMBER,
+ number);
+ CHECK_MINUS_ONE(check, "T2: equal subscriber",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_SUBSCRIBER_LOCATION,
+ (char *)readLocation);
+ CHECK_NULL(check2, "T2: getValue location",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_SUBSCRIBER_CHANGED_BY,
+ changed_by);
+ CHECK_NULL(check2, "T2: getValue changed_by",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_SUBSCRIBER_CHANGED_TIME,
+ changed_time);
+ CHECK_NULL(check2, "T2: getValue changed_time",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_SUBSCRIBER_NAME,
+ subscriberName);
+ CHECK_NULL(check2, "T2: getValue name",
+ MyTransaction);
+
+ check = MyTransaction->execute( Commit );
+ CHECK_MINUS_ONE(check, "T2: Commit",
+ MyTransaction);
+
+ pNDB->closeTransaction(MyTransaction);
+
+ get_time(transaction_time);
+ time_diff(transaction_time, &start);
+ return 0;
+}
+
+/**
+ * Transaction 3 - T3
+ *
+ * Read session details
+ *
+ * Input:
+ * SubscriberNumber
+ * ServerId
+ * ServerBit
+ *
+ * Output:
+ * BranchExecuted
+ * SessionDetails
+ * ChangedBy
+ * ChangedTime
+ * Location
+ */
+int
+T3(void * obj,
+ const SubscriberNumber inNumber,
+ const SubscriberSuffix inSuffix,
+ const ServerId inServerId,
+ const ServerBit inServerBit,
+ SessionDetails outSessionDetails,
+ ChangedBy outChangedBy,
+ ChangedTime outChangedTime,
+ Location * outLocation,
+ BranchExecuted * outBranchExecuted,
+ BenchmarkTime * outTransactionTime){
+
+ Ndb * pNDB = (Ndb *) obj;
+
+ GroupId groupId;
+ ActiveSessions sessions;
+ Permission permission;
+
+ BenchmarkTime start;
+ get_time(&start);
+
+ int check;
+ NdbRecAttr * check2;
+
+ NdbConnection * MyTransaction = pNDB->startTransaction();
+ if (MyTransaction == NULL)
+ error_handler("T3-1: startTranscation", pNDB->getNdbErrorString(), 0);
+
+ NdbOperation *MyOperation= MyTransaction->getNdbOperation(SUBSCRIBER_TABLE);
+ CHECK_NULL(MyOperation, "T3-1: getNdbOperation",
+ MyTransaction);
+
+
+ check = MyOperation->readTuple();
+ CHECK_MINUS_ONE(check, "T3-1: readTuple",
+ MyTransaction);
+
+ check = MyOperation->equal(IND_SUBSCRIBER_NUMBER,
+ inNumber);
+ CHECK_MINUS_ONE(check, "T3-1: equal subscriber",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_SUBSCRIBER_LOCATION,
+ (char *)outLocation);
+ CHECK_NULL(check2, "T3-1: getValue location",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_SUBSCRIBER_CHANGED_BY,
+ outChangedBy);
+ CHECK_NULL(check2, "T3-1: getValue changed_by",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_SUBSCRIBER_CHANGED_TIME,
+ outChangedTime);
+ CHECK_NULL(check2, "T3-1: getValue changed_time",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_SUBSCRIBER_GROUP,
+ (char *)&groupId);
+ CHECK_NULL(check2, "T3-1: getValue group",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_SUBSCRIBER_SESSIONS,
+ (char *)&sessions);
+ CHECK_NULL(check2, "T3-1: getValue sessions",
+ MyTransaction);
+
+ check = MyTransaction->execute( NoCommit );
+ CHECK_MINUS_ONE(check, "T3-1: NoCommit",
+ MyTransaction);
+
+ /* Operation 2 */
+
+ MyOperation = MyTransaction->getNdbOperation(GROUP_TABLE);
+ CHECK_NULL(MyOperation, "T3-2: getNdbOperation",
+ MyTransaction);
+
+
+ check = MyOperation->readTuple();
+ CHECK_MINUS_ONE(check, "T3-2: readTuple",
+ MyTransaction);
+
+ check = MyOperation->equal(IND_GROUP_ID,
+ (char*)&groupId);
+ CHECK_MINUS_ONE(check, "T3-2: equal group",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_GROUP_ALLOW_READ,
+ (char *)&permission);
+ CHECK_NULL(check2, "T3-2: getValue allow_read",
+ MyTransaction);
+
+ check = MyTransaction->execute( NoCommit );
+ CHECK_MINUS_ONE(check, "T3-2: NoCommit",
+ MyTransaction);
+
+ DEBUG3("T3(%.*s, %.2d): ", SUBSCRIBER_NUMBER_LENGTH, inNumber, inServerId);
+
+ if(((permission & inServerBit) == inServerBit) &&
+ ((sessions & inServerBit) == inServerBit)){
+
+ DEBUG("reading - ");
+
+ /* Operation 3 */
+
+ MyOperation = MyTransaction->getNdbOperation(SESSION_TABLE);
+ CHECK_NULL(MyOperation, "T3-3: getNdbOperation",
+ MyTransaction);
+
+ check = MyOperation->readTuple();
+ CHECK_MINUS_ONE(check, "T3-3: readTuple",
+ MyTransaction);
+
+ check = MyOperation->equal(IND_SESSION_SUBSCRIBER,
+ (char*)inNumber);
+ CHECK_MINUS_ONE(check, "T3-3: equal number",
+ MyTransaction);
+
+ check = MyOperation->equal(IND_SESSION_SERVER,
+ (char*)&inServerId);
+ CHECK_MINUS_ONE(check, "T3-3: equal server id",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_SESSION_DATA,
+ (char *)outSessionDetails);
+ CHECK_NULL(check2, "T3-3: getValue session details",
+ MyTransaction);
+
+ check = MyTransaction->execute( NoCommit );
+ CHECK_MINUS_ONE(check, "T3-3: NoCommit",
+ MyTransaction);
+
+ /* Operation 4 */
+
+ MyOperation = MyTransaction->getNdbOperation(SERVER_TABLE);
+ CHECK_NULL(MyOperation, "T3-4: getNdbOperation",
+ MyTransaction);
+
+ check = MyOperation->interpretedUpdateTuple();
+ CHECK_MINUS_ONE(check, "T3-4: interpretedUpdateTuple",
+ MyTransaction);
+
+ check = MyOperation->equal(IND_SERVER_ID,
+ (char*)&inServerId);
+ CHECK_MINUS_ONE(check, "T3-4: equal serverId",
+ MyTransaction);
+
+ check = MyOperation->equal(IND_SERVER_SUBSCRIBER_SUFFIX,
+ (char*)inSuffix);
+ CHECK_MINUS_ONE(check, "T3-4: equal suffix",
+ MyTransaction);
+
+ check = MyOperation->incValue(IND_SERVER_READS, (uint32)1);
+ CHECK_MINUS_ONE(check, "T3-4: inc value",
+ MyTransaction);
+
+ check = MyTransaction->execute( NoCommit );
+ CHECK_MINUS_ONE(check, "T3-4: NoCommit",
+ MyTransaction);
+
+ (* outBranchExecuted) = 1;
+ } else {
+ (* outBranchExecuted) = 0;
+ }
+ DEBUG("commit\n");
+ check = MyTransaction->execute( Commit );
+ CHECK_MINUS_ONE(check, "T3: Commit",
+ MyTransaction);
+
+ pNDB->closeTransaction(MyTransaction);
+
+ get_time(outTransactionTime);
+ time_diff(outTransactionTime, &start);
+ return 0;
+}
+
+
+/**
+ * Transaction 4 - T4
+ *
+ * Create session
+ *
+ * Input:
+ * SubscriberNumber
+ * ServerId
+ * ServerBit
+ * SessionDetails,
+ * DoRollback
+ * Output:
+ * ChangedBy
+ * ChangedTime
+ * Location
+ * BranchExecuted
+ */
+int
+T4(void * obj,
+ const SubscriberNumber inNumber,
+ const SubscriberSuffix inSuffix,
+ const ServerId inServerId,
+ const ServerBit inServerBit,
+ const SessionDetails inSessionDetails,
+ ChangedBy outChangedBy,
+ ChangedTime outChangedTime,
+ Location * outLocation,
+ DoRollback inDoRollback,
+ BranchExecuted * outBranchExecuted,
+ BenchmarkTime * outTransactionTime){
+
+ Ndb * pNDB = (Ndb *) obj;
+
+ GroupId groupId;
+ ActiveSessions sessions;
+ Permission permission;
+
+ BenchmarkTime start;
+ get_time(&start);
+
+ int check;
+ NdbRecAttr * check2;
+
+ NdbConnection * MyTransaction = pNDB->startTransaction();
+ if (MyTransaction == NULL)
+ error_handler("T4-1: startTranscation", pNDB->getNdbErrorString(), 0);
+
+ DEBUG3("T4(%.*s, %.2d): ", SUBSCRIBER_NUMBER_LENGTH, inNumber, inServerId);
+
+ NdbOperation * MyOperation = 0;
+
+ MyOperation= MyTransaction->getNdbOperation(SUBSCRIBER_TABLE);
+ CHECK_NULL(MyOperation, "T4-1: getNdbOperation",
+ MyTransaction);
+
+ check = MyOperation->readTupleExclusive();
+ CHECK_MINUS_ONE(check, "T4-1: readTuple",
+ MyTransaction);
+
+ check = MyOperation->equal(IND_SUBSCRIBER_NUMBER,
+ inNumber);
+ CHECK_MINUS_ONE(check, "T4-1: equal subscriber",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_SUBSCRIBER_LOCATION,
+ (char *)outLocation);
+ CHECK_NULL(check2, "T4-1: getValue location",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_SUBSCRIBER_CHANGED_BY,
+ outChangedBy);
+ CHECK_NULL(check2, "T4-1: getValue changed_by",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_SUBSCRIBER_CHANGED_TIME,
+ outChangedTime);
+ CHECK_NULL(check2, "T4-1: getValue changed_time",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_SUBSCRIBER_GROUP,
+ (char *)&groupId);
+ CHECK_NULL(check2, "T4-1: getValue group",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_SUBSCRIBER_SESSIONS,
+ (char *)&sessions);
+ CHECK_NULL(check2, "T4-1: getValue sessions",
+ MyTransaction);
+
+ check = MyTransaction->execute( NoCommit );
+ CHECK_MINUS_ONE(check, "T4-1: NoCommit",
+ MyTransaction);
+
+ /* Operation 2 */
+ MyOperation = MyTransaction->getNdbOperation(GROUP_TABLE);
+ CHECK_NULL(MyOperation, "T4-2: getNdbOperation",
+ MyTransaction);
+
+ check = MyOperation->readTuple();
+ CHECK_MINUS_ONE(check, "T4-2: readTuple",
+ MyTransaction);
+
+ check = MyOperation->equal(IND_GROUP_ID,
+ (char*)&groupId);
+ CHECK_MINUS_ONE(check, "T4-2: equal group",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_GROUP_ALLOW_INSERT,
+ (char *)&permission);
+ CHECK_NULL(check2, "T4-2: getValue allow_insert",
+ MyTransaction);
+
+ check = MyTransaction->execute( NoCommit );
+ CHECK_MINUS_ONE(check, "T4-2: NoCommit",
+ MyTransaction);
+
+ if(((permission & inServerBit) == inServerBit) &&
+ ((sessions & inServerBit) == 0)){
+
+ DEBUG("inserting - ");
+
+ /* Operation 3 */
+ MyOperation = MyTransaction->getNdbOperation(SESSION_TABLE);
+ CHECK_NULL(MyOperation, "T4-3: getNdbOperation",
+ MyTransaction);
+
+ check = MyOperation->insertTuple();
+ CHECK_MINUS_ONE(check, "T4-3: insertTuple",
+ MyTransaction);
+
+ check = MyOperation->equal(IND_SESSION_SUBSCRIBER,
+ (char*)inNumber);
+ CHECK_MINUS_ONE(check, "T4-3: equal number",
+ MyTransaction);
+
+ check = MyOperation->equal(IND_SESSION_SERVER,
+ (char*)&inServerId);
+ CHECK_MINUS_ONE(check, "T4-3: equal server id",
+ MyTransaction);
+
+ check = MyOperation->setValue(SESSION_DATA,
+ (char *)inSessionDetails);
+ CHECK_MINUS_ONE(check, "T4-3: setValue session details",
+ MyTransaction);
+
+ check = MyTransaction->execute( NoCommit );
+ CHECK_MINUS_ONE(check, "T4-3: NoCommit",
+ MyTransaction);
+
+ /* Operation 4 */
+ MyOperation = MyTransaction->getNdbOperation(SUBSCRIBER_TABLE);
+ CHECK_NULL(MyOperation, "T4-4: getNdbOperation",
+ MyTransaction);
+
+ check = MyOperation->interpretedUpdateTuple();
+ CHECK_MINUS_ONE(check, "T4-4: interpretedUpdateTuple",
+ MyTransaction);
+
+ check = MyOperation->equal(IND_SUBSCRIBER_NUMBER,
+ (char*)inNumber);
+ CHECK_MINUS_ONE(check, "T4-4: equal number",
+ MyTransaction);
+
+ check = MyOperation->incValue(IND_SUBSCRIBER_SESSIONS,
+ (uint32)inServerBit);
+ CHECK_MINUS_ONE(check, "T4-4: inc value",
+ MyTransaction);
+
+ check = MyTransaction->execute( NoCommit );
+ CHECK_MINUS_ONE(check, "T4-4: NoCommit",
+ MyTransaction);
+
+ /* Operation 5 */
+ MyOperation = MyTransaction->getNdbOperation(SERVER_TABLE);
+ CHECK_NULL(MyOperation, "T4-5: getNdbOperation",
+ MyTransaction);
+
+ check = MyOperation->interpretedUpdateTuple();
+ CHECK_MINUS_ONE(check, "T4-5: interpretedUpdateTuple",
+ MyTransaction);
+
+ check = MyOperation->equal(IND_SERVER_ID,
+ (char*)&inServerId);
+ CHECK_MINUS_ONE(check, "T4-5: equal serverId",
+ MyTransaction);
+
+ check = MyOperation->equal(IND_SERVER_SUBSCRIBER_SUFFIX,
+ (char*)inSuffix);
+ CHECK_MINUS_ONE(check, "T4-5: equal suffix",
+ MyTransaction);
+
+ check = MyOperation->incValue(IND_SERVER_INSERTS, (uint32)1);
+ CHECK_MINUS_ONE(check, "T4-5: inc value",
+ MyTransaction);
+
+ check = MyTransaction->execute( NoCommit );
+ CHECK_MINUS_ONE(check, "T4-5: NoCommit",
+ MyTransaction);
+
+ (* outBranchExecuted) = 1;
+ } else {
+ DEBUG1("%s", ((permission & inServerBit) ? "permission - " : "no permission - "));
+ DEBUG1("%s", ((sessions & inServerBit) ? "in session - " : "no in session - "));
+ (* outBranchExecuted) = 0;
+ }
+
+ if(!inDoRollback){
+ DEBUG("commit\n");
+ check = MyTransaction->execute( Commit );
+ CHECK_MINUS_ONE(check, "T4: Commit",
+ MyTransaction);
+ } else {
+ DEBUG("rollback\n");
+ check = MyTransaction->execute(Rollback);
+ CHECK_MINUS_ONE(check, "T4:Rollback",
+ MyTransaction);
+
+ }
+
+ pNDB->closeTransaction(MyTransaction);
+
+ get_time(outTransactionTime);
+ time_diff(outTransactionTime, &start);
+ return 0;
+}
+
+
+/**
+ * Transaction 5 - T5
+ *
+ * Delete session
+ *
+ * Input:
+ * SubscriberNumber
+ * ServerId
+ * ServerBit
+ * DoRollback
+ * Output:
+ * ChangedBy
+ * ChangedTime
+ * Location
+ * BranchExecuted
+ */
+int
+T5(void * obj,
+ const SubscriberNumber inNumber,
+ const SubscriberSuffix inSuffix,
+ const ServerId inServerId,
+ const ServerBit inServerBit,
+ ChangedBy outChangedBy,
+ ChangedTime outChangedTime,
+ Location * outLocation,
+ DoRollback inDoRollback,
+ BranchExecuted * outBranchExecuted,
+ BenchmarkTime * outTransactionTime){
+
+ Ndb * pNDB = (Ndb *) obj;
+ NdbConnection * MyTransaction = 0;
+ NdbOperation * MyOperation = 0;
+
+ GroupId groupId;
+ ActiveSessions sessions;
+ Permission permission;
+
+ BenchmarkTime start;
+ get_time(&start);
+
+ int check;
+ NdbRecAttr * check2;
+
+ MyTransaction = pNDB->startTransaction();
+ if (MyTransaction == NULL)
+ error_handler("T5-1: startTranscation", pNDB->getNdbErrorString(), 0);
+
+ MyOperation= MyTransaction->getNdbOperation(SUBSCRIBER_TABLE);
+ CHECK_NULL(MyOperation, "T5-1: getNdbOperation",
+ MyTransaction);
+
+
+ check = MyOperation->readTupleExclusive();
+ CHECK_MINUS_ONE(check, "T5-1: readTuple",
+ MyTransaction);
+
+ check = MyOperation->equal(IND_SUBSCRIBER_NUMBER,
+ inNumber);
+ CHECK_MINUS_ONE(check, "T5-1: equal subscriber",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_SUBSCRIBER_LOCATION,
+ (char *)outLocation);
+ CHECK_NULL(check2, "T5-1: getValue location",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_SUBSCRIBER_CHANGED_BY,
+ outChangedBy);
+ CHECK_NULL(check2, "T5-1: getValue changed_by",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_SUBSCRIBER_CHANGED_TIME,
+ outChangedTime);
+ CHECK_NULL(check2, "T5-1: getValue changed_time",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_SUBSCRIBER_GROUP,
+ (char *)&groupId);
+ CHECK_NULL(check2, "T5-1: getValue group",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_SUBSCRIBER_SESSIONS,
+ (char *)&sessions);
+ CHECK_NULL(check2, "T5-1: getValue sessions",
+ MyTransaction);
+
+ check = MyTransaction->execute( NoCommit );
+ CHECK_MINUS_ONE(check, "T5-1: NoCommit",
+ MyTransaction);
+
+ /* Operation 2 */
+
+ MyOperation = MyTransaction->getNdbOperation(GROUP_TABLE);
+ CHECK_NULL(MyOperation, "T5-2: getNdbOperation",
+ MyTransaction);
+
+
+ check = MyOperation->readTuple();
+ CHECK_MINUS_ONE(check, "T5-2: readTuple",
+ MyTransaction);
+
+ check = MyOperation->equal(IND_GROUP_ID,
+ (char*)&groupId);
+ CHECK_MINUS_ONE(check, "T5-2: equal group",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_GROUP_ALLOW_DELETE,
+ (char *)&permission);
+ CHECK_NULL(check2, "T5-2: getValue allow_delete",
+ MyTransaction);
+
+ check = MyTransaction->execute( NoCommit );
+ CHECK_MINUS_ONE(check, "T5-2: NoCommit",
+ MyTransaction);
+
+ DEBUG3("T5(%.*s, %.2d): ", SUBSCRIBER_NUMBER_LENGTH, inNumber, inServerId);
+
+ if(((permission & inServerBit) == inServerBit) &&
+ ((sessions & inServerBit) == inServerBit)){
+
+ DEBUG("deleting - ");
+
+ /* Operation 3 */
+ MyOperation = MyTransaction->getNdbOperation(SESSION_TABLE);
+ CHECK_NULL(MyOperation, "T5-3: getNdbOperation",
+ MyTransaction);
+
+ check = MyOperation->deleteTuple();
+ CHECK_MINUS_ONE(check, "T5-3: deleteTuple",
+ MyTransaction);
+
+ check = MyOperation->equal(IND_SESSION_SUBSCRIBER,
+ (char*)inNumber);
+ CHECK_MINUS_ONE(check, "T5-3: equal number",
+ MyTransaction);
+
+ check = MyOperation->equal(IND_SESSION_SERVER,
+ (char*)&inServerId);
+ CHECK_MINUS_ONE(check, "T5-3: equal server id",
+ MyTransaction);
+
+ check = MyTransaction->execute( NoCommit );
+ CHECK_MINUS_ONE(check, "T5-3: NoCommit",
+ MyTransaction);
+
+ /* Operation 4 */
+ MyOperation = MyTransaction->getNdbOperation(SUBSCRIBER_TABLE);
+ CHECK_NULL(MyOperation, "T5-4: getNdbOperation",
+ MyTransaction);
+
+ check = MyOperation->interpretedUpdateTuple();
+ CHECK_MINUS_ONE(check, "T5-4: interpretedUpdateTuple",
+ MyTransaction);
+
+ check = MyOperation->equal(IND_SUBSCRIBER_NUMBER,
+ (char*)inNumber);
+ CHECK_MINUS_ONE(check, "T5-4: equal number",
+ MyTransaction);
+
+ check = MyOperation->subValue(IND_SUBSCRIBER_SESSIONS,
+ (uint32)inServerBit);
+ CHECK_MINUS_ONE(check, "T5-4: dec value",
+ MyTransaction);
+
+ check = MyTransaction->execute( NoCommit );
+ CHECK_MINUS_ONE(check, "T5-4: NoCommit",
+ MyTransaction);
+
+ /* Operation 5 */
+ MyOperation = MyTransaction->getNdbOperation(SERVER_TABLE);
+ CHECK_NULL(MyOperation, "T5-5: getNdbOperation",
+ MyTransaction);
+
+
+ check = MyOperation->interpretedUpdateTuple();
+ CHECK_MINUS_ONE(check, "T5-5: interpretedUpdateTuple",
+ MyTransaction);
+
+ check = MyOperation->equal(IND_SERVER_ID,
+ (char*)&inServerId);
+ CHECK_MINUS_ONE(check, "T5-5: equal serverId",
+ MyTransaction);
+
+ check = MyOperation->equal(IND_SERVER_SUBSCRIBER_SUFFIX,
+ (char*)inSuffix);
+ CHECK_MINUS_ONE(check, "T5-5: equal suffix",
+ MyTransaction);
+
+ check = MyOperation->incValue(IND_SERVER_DELETES, (uint32)1);
+ CHECK_MINUS_ONE(check, "T5-5: inc value",
+ MyTransaction);
+
+ check = MyTransaction->execute( NoCommit );
+ CHECK_MINUS_ONE(check, "T5-5: NoCommit",
+ MyTransaction);
+
+ (* outBranchExecuted) = 1;
+ } else {
+ DEBUG1("%s", ((permission & inServerBit) ? "permission - " : "no permission - "));
+ DEBUG1("%s", ((sessions & inServerBit) ? "in session - " : "no in session - "));
+ (* outBranchExecuted) = 0;
+ }
+
+ if(!inDoRollback){
+ DEBUG("commit\n");
+ check = MyTransaction->execute( Commit );
+ CHECK_MINUS_ONE(check, "T5: Commit",
+ MyTransaction);
+ } else {
+ DEBUG("rollback\n");
+ check = MyTransaction->execute(Rollback);
+ CHECK_MINUS_ONE(check, "T5:Rollback",
+ MyTransaction);
+
+ }
+
+ pNDB->closeTransaction(MyTransaction);
+
+ get_time(outTransactionTime);
+ time_diff(outTransactionTime, &start);
+ return 0;
+}
+
diff --git a/ndb/test/ndbapi/bench/ndb_user_transaction3.cpp b/ndb/test/ndbapi/bench/ndb_user_transaction3.cpp
new file mode 100644
index 00000000000..d2c92ecd424
--- /dev/null
+++ b/ndb/test/ndbapi/bench/ndb_user_transaction3.cpp
@@ -0,0 +1,793 @@
+/* Copyright (C) 2003 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+//#define DEBUG_ON
+
+extern "C" {
+#include "user_transaction.h"
+};
+
+#include "macros.h"
+#include "ndb_schema.hpp"
+#include "ndb_error.hpp"
+
+#include <time.h>
+#include <NdbApi.hpp>
+
+/**
+ * Transaction 1 - T1
+ *
+ * Update location and changed by/time on a subscriber
+ *
+ * Input:
+ * SubscriberNumber,
+ * Location,
+ * ChangedBy,
+ * ChangedTime
+ *
+ * Output:
+ */
+int
+T1(void * obj,
+ const SubscriberNumber number,
+ const Location new_location,
+ const ChangedBy changed_by,
+ const ChangedTime changed_time,
+ BenchmarkTime * transaction_time){
+
+ Ndb * pNDB = (Ndb *) obj;
+
+ BenchmarkTime start;
+ get_time(&start);
+
+ int check;
+ NdbRecAttr * check2;
+
+ NdbConnection * MyTransaction = pNDB->startTransaction();
+ if (MyTransaction == NULL)
+ error_handler("T1: startTranscation", pNDB->getNdbErrorString(), 0);
+
+ NdbOperation *MyOperation = MyTransaction->getNdbOperation(SUBSCRIBER_TABLE);
+ CHECK_NULL(MyOperation, "T1: getNdbOperation", MyTransaction);
+
+ check = MyOperation->updateTuple();
+ CHECK_MINUS_ONE(check, "T1: updateTuple",
+ MyTransaction);
+
+ check = MyOperation->equal(IND_SUBSCRIBER_NUMBER,
+ number);
+ CHECK_MINUS_ONE(check, "T1: equal subscriber",
+ MyTransaction);
+
+ check = MyOperation->setValue(IND_SUBSCRIBER_LOCATION,
+ (char *)&new_location);
+ CHECK_MINUS_ONE(check, "T1: setValue location",
+ MyTransaction);
+
+ check = MyOperation->setValue(IND_SUBSCRIBER_CHANGED_BY,
+ changed_by);
+ CHECK_MINUS_ONE(check, "T1: setValue changed_by",
+ MyTransaction);
+
+ check = MyOperation->setValue(IND_SUBSCRIBER_CHANGED_TIME,
+ changed_time);
+ CHECK_MINUS_ONE(check, "T1: setValue changed_time",
+ MyTransaction);
+
+ check = MyTransaction->execute( Commit );
+ CHECK_MINUS_ONE(check, "T1: Commit",
+ MyTransaction);
+
+ pNDB->closeTransaction(MyTransaction);
+
+ get_time(transaction_time);
+ time_diff(transaction_time, &start);
+ return 0;
+}
+
+/**
+ * Transaction 2 - T2
+ *
+ * Read from Subscriber:
+ *
+ * Input:
+ * SubscriberNumber
+ *
+ * Output:
+ * Location
+ * Changed by
+ * Changed Timestamp
+ * Name
+ */
+int
+T2(void * obj,
+ const SubscriberNumber number,
+ Location * readLocation,
+ ChangedBy changed_by,
+ ChangedTime changed_time,
+ SubscriberName subscriberName,
+ BenchmarkTime * transaction_time){
+
+ Ndb * pNDB = (Ndb *) obj;
+
+ BenchmarkTime start;
+ get_time(&start);
+
+ int check;
+ NdbRecAttr * check2;
+
+ NdbConnection * MyTransaction = pNDB->startTransaction();
+ if (MyTransaction == NULL)
+ error_handler("T2: startTranscation", pNDB->getNdbErrorString(), 0);
+
+ NdbOperation *MyOperation= MyTransaction->getNdbOperation(SUBSCRIBER_TABLE);
+ CHECK_NULL(MyOperation, "T2: getNdbOperation",
+ MyTransaction);
+
+
+ check = MyOperation->readTuple();
+ CHECK_MINUS_ONE(check, "T2: readTuple",
+ MyTransaction);
+
+ check = MyOperation->equal(IND_SUBSCRIBER_NUMBER,
+ number);
+ CHECK_MINUS_ONE(check, "T2: equal subscriber",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_SUBSCRIBER_LOCATION,
+ (char *)readLocation);
+ CHECK_NULL(check2, "T2: getValue location",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_SUBSCRIBER_CHANGED_BY,
+ changed_by);
+ CHECK_NULL(check2, "T2: getValue changed_by",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_SUBSCRIBER_CHANGED_TIME,
+ changed_time);
+ CHECK_NULL(check2, "T2: getValue changed_time",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_SUBSCRIBER_NAME,
+ subscriberName);
+ CHECK_NULL(check2, "T2: getValue name",
+ MyTransaction);
+
+ check = MyTransaction->execute( Commit );
+ CHECK_MINUS_ONE(check, "T2: Commit",
+ MyTransaction);
+
+ pNDB->closeTransaction(MyTransaction);
+
+ get_time(transaction_time);
+ time_diff(transaction_time, &start);
+ return 0;
+}
+
+/**
+ * Transaction 3 - T3
+ *
+ * Read session details
+ *
+ * Input:
+ * SubscriberNumber
+ * ServerId
+ * ServerBit
+ *
+ * Output:
+ * BranchExecuted
+ * SessionDetails
+ * ChangedBy
+ * ChangedTime
+ * Location
+ */
+int
+T3(void * obj,
+ const SubscriberNumber inNumber,
+ const SubscriberSuffix inSuffix,
+ const ServerId inServerId,
+ const ServerBit inServerBit,
+ SessionDetails outSessionDetails,
+ ChangedBy outChangedBy,
+ ChangedTime outChangedTime,
+ Location * outLocation,
+ BranchExecuted * outBranchExecuted,
+ BenchmarkTime * outTransactionTime){
+
+ Ndb * pNDB = (Ndb *) obj;
+
+ GroupId groupId;
+ ActiveSessions sessions;
+ Permission permission;
+
+ BenchmarkTime start;
+ get_time(&start);
+
+ int check;
+ NdbRecAttr * check2;
+
+ NdbConnection * MyTransaction = pNDB->startTransaction();
+ if (MyTransaction == NULL)
+ error_handler("T3-1: startTranscation", pNDB->getNdbErrorString(), 0);
+
+ NdbOperation *MyOperation= MyTransaction->getNdbOperation(SUBSCRIBER_TABLE);
+ CHECK_NULL(MyOperation, "T3-1: getNdbOperation",
+ MyTransaction);
+
+
+ check = MyOperation->readTuple();
+ CHECK_MINUS_ONE(check, "T3-1: readTuple",
+ MyTransaction);
+
+ check = MyOperation->equal(IND_SUBSCRIBER_NUMBER,
+ inNumber);
+ CHECK_MINUS_ONE(check, "T3-1: equal subscriber",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_SUBSCRIBER_LOCATION,
+ (char *)outLocation);
+ CHECK_NULL(check2, "T3-1: getValue location",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_SUBSCRIBER_CHANGED_BY,
+ outChangedBy);
+ CHECK_NULL(check2, "T3-1: getValue changed_by",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_SUBSCRIBER_CHANGED_TIME,
+ outChangedTime);
+ CHECK_NULL(check2, "T3-1: getValue changed_time",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_SUBSCRIBER_GROUP,
+ (char *)&groupId);
+ CHECK_NULL(check2, "T3-1: getValue group",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_SUBSCRIBER_SESSIONS,
+ (char *)&sessions);
+ CHECK_NULL(check2, "T3-1: getValue sessions",
+ MyTransaction);
+
+ check = MyTransaction->execute( NoCommit );
+ CHECK_MINUS_ONE(check, "T3-1: NoCommit",
+ MyTransaction);
+
+ /* Operation 2 */
+
+ MyOperation = MyTransaction->getNdbOperation(GROUP_TABLE);
+ CHECK_NULL(MyOperation, "T3-2: getNdbOperation",
+ MyTransaction);
+
+
+ check = MyOperation->readTuple();
+ CHECK_MINUS_ONE(check, "T3-2: readTuple",
+ MyTransaction);
+
+ check = MyOperation->equal(IND_GROUP_ID,
+ (char*)&groupId);
+ CHECK_MINUS_ONE(check, "T3-2: equal group",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_GROUP_ALLOW_READ,
+ (char *)&permission);
+ CHECK_NULL(check2, "T3-2: getValue allow_read",
+ MyTransaction);
+
+ check = MyTransaction->execute( NoCommit );
+ CHECK_MINUS_ONE(check, "T3-2: NoCommit",
+ MyTransaction);
+
+ DEBUG3("T3(%.*s, %.2d): ", SUBSCRIBER_NUMBER_LENGTH, inNumber, inServerId);
+
+ if(((permission & inServerBit) == inServerBit) &&
+ ((sessions & inServerBit) == inServerBit)){
+
+ DEBUG("reading - ");
+
+ /* Operation 3 */
+
+ MyOperation = MyTransaction->getNdbOperation(SESSION_TABLE);
+ CHECK_NULL(MyOperation, "T3-3: getNdbOperation",
+ MyTransaction);
+
+ check = MyOperation->readTuple();
+ CHECK_MINUS_ONE(check, "T3-3: readTuple",
+ MyTransaction);
+
+ check = MyOperation->equal(IND_SESSION_SUBSCRIBER,
+ (char*)inNumber);
+ CHECK_MINUS_ONE(check, "T3-3: equal number",
+ MyTransaction);
+
+ check = MyOperation->equal(IND_SESSION_SERVER,
+ (char*)&inServerId);
+ CHECK_MINUS_ONE(check, "T3-3: equal server id",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_SESSION_DATA,
+ (char *)outSessionDetails);
+ CHECK_NULL(check2, "T3-3: getValue session details",
+ MyTransaction);
+
+ /* Operation 4 */
+
+ MyOperation = MyTransaction->getNdbOperation(SERVER_TABLE);
+ CHECK_NULL(MyOperation, "T3-4: getNdbOperation",
+ MyTransaction);
+
+ check = MyOperation->interpretedUpdateTuple();
+ CHECK_MINUS_ONE(check, "T3-4: interpretedUpdateTuple",
+ MyTransaction);
+
+ check = MyOperation->equal(IND_SERVER_ID,
+ (char*)&inServerId);
+ CHECK_MINUS_ONE(check, "T3-4: equal serverId",
+ MyTransaction);
+
+ check = MyOperation->equal(IND_SERVER_SUBSCRIBER_SUFFIX,
+ (char*)inSuffix);
+ CHECK_MINUS_ONE(check, "T3-4: equal suffix",
+ MyTransaction);
+
+ check = MyOperation->incValue(IND_SERVER_READS, (uint32)1);
+ CHECK_MINUS_ONE(check, "T3-4: inc value",
+ MyTransaction);
+
+ (* outBranchExecuted) = 1;
+ } else {
+ (* outBranchExecuted) = 0;
+ }
+ DEBUG("commit\n");
+ check = MyTransaction->execute( Commit );
+ CHECK_MINUS_ONE(check, "T3: Commit",
+ MyTransaction);
+
+ pNDB->closeTransaction(MyTransaction);
+
+ get_time(outTransactionTime);
+ time_diff(outTransactionTime, &start);
+ return 0;
+}
+
+
+/**
+ * Transaction 4 - T4
+ *
+ * Create session
+ *
+ * Input:
+ * SubscriberNumber
+ * ServerId
+ * ServerBit
+ * SessionDetails,
+ * DoRollback
+ * Output:
+ * ChangedBy
+ * ChangedTime
+ * Location
+ * BranchExecuted
+ */
+int
+T4(void * obj,
+ const SubscriberNumber inNumber,
+ const SubscriberSuffix inSuffix,
+ const ServerId inServerId,
+ const ServerBit inServerBit,
+ const SessionDetails inSessionDetails,
+ ChangedBy outChangedBy,
+ ChangedTime outChangedTime,
+ Location * outLocation,
+ DoRollback inDoRollback,
+ BranchExecuted * outBranchExecuted,
+ BenchmarkTime * outTransactionTime){
+
+ Ndb * pNDB = (Ndb *) obj;
+
+ GroupId groupId;
+ ActiveSessions sessions;
+ Permission permission;
+
+ BenchmarkTime start;
+ get_time(&start);
+
+ int check;
+ NdbRecAttr * check2;
+
+ NdbConnection * MyTransaction = pNDB->startTransaction();
+ if (MyTransaction == NULL)
+ error_handler("T4-1: startTranscation", pNDB->getNdbErrorString(), 0);
+
+ DEBUG3("T4(%.*s, %.2d): ", SUBSCRIBER_NUMBER_LENGTH, inNumber, inServerId);
+
+ NdbOperation * MyOperation = 0;
+
+ MyOperation= MyTransaction->getNdbOperation(SUBSCRIBER_TABLE);
+ CHECK_NULL(MyOperation, "T4-1: getNdbOperation",
+ MyTransaction);
+
+ check = MyOperation->readTupleExclusive();
+ CHECK_MINUS_ONE(check, "T4-1: readTuple",
+ MyTransaction);
+
+ check = MyOperation->equal(IND_SUBSCRIBER_NUMBER,
+ inNumber);
+ CHECK_MINUS_ONE(check, "T4-1: equal subscriber",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_SUBSCRIBER_LOCATION,
+ (char *)outLocation);
+ CHECK_NULL(check2, "T4-1: getValue location",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_SUBSCRIBER_CHANGED_BY,
+ outChangedBy);
+ CHECK_NULL(check2, "T4-1: getValue changed_by",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_SUBSCRIBER_CHANGED_TIME,
+ outChangedTime);
+ CHECK_NULL(check2, "T4-1: getValue changed_time",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_SUBSCRIBER_GROUP,
+ (char *)&groupId);
+ CHECK_NULL(check2, "T4-1: getValue group",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_SUBSCRIBER_SESSIONS,
+ (char *)&sessions);
+ CHECK_NULL(check2, "T4-1: getValue sessions",
+ MyTransaction);
+
+ check = MyTransaction->execute( NoCommit );
+ CHECK_MINUS_ONE(check, "T4-1: NoCommit",
+ MyTransaction);
+
+ /* Operation 2 */
+ MyOperation = MyTransaction->getNdbOperation(GROUP_TABLE);
+ CHECK_NULL(MyOperation, "T4-2: getNdbOperation",
+ MyTransaction);
+
+ check = MyOperation->readTuple();
+ CHECK_MINUS_ONE(check, "T4-2: readTuple",
+ MyTransaction);
+
+ check = MyOperation->equal(IND_GROUP_ID,
+ (char*)&groupId);
+ CHECK_MINUS_ONE(check, "T4-2: equal group",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_GROUP_ALLOW_INSERT,
+ (char *)&permission);
+ CHECK_NULL(check2, "T4-2: getValue allow_insert",
+ MyTransaction);
+
+ check = MyTransaction->execute( NoCommit );
+ CHECK_MINUS_ONE(check, "T4-2: NoCommit",
+ MyTransaction);
+
+ if(((permission & inServerBit) == inServerBit) &&
+ ((sessions & inServerBit) == 0)){
+
+ DEBUG("inserting - ");
+
+ /* Operation 3 */
+ MyOperation = MyTransaction->getNdbOperation(SESSION_TABLE);
+ CHECK_NULL(MyOperation, "T4-3: getNdbOperation",
+ MyTransaction);
+
+ check = MyOperation->insertTuple();
+ CHECK_MINUS_ONE(check, "T4-3: insertTuple",
+ MyTransaction);
+
+ check = MyOperation->equal(IND_SESSION_SUBSCRIBER,
+ (char*)inNumber);
+ CHECK_MINUS_ONE(check, "T4-3: equal number",
+ MyTransaction);
+
+ check = MyOperation->equal(IND_SESSION_SERVER,
+ (char*)&inServerId);
+ CHECK_MINUS_ONE(check, "T4-3: equal server id",
+ MyTransaction);
+
+ check = MyOperation->setValue(SESSION_DATA,
+ (char *)inSessionDetails);
+ CHECK_MINUS_ONE(check, "T4-3: setValue session details",
+ MyTransaction);
+
+ /* Operation 4 */
+ MyOperation = MyTransaction->getNdbOperation(SUBSCRIBER_TABLE);
+ CHECK_NULL(MyOperation, "T4-4: getNdbOperation",
+ MyTransaction);
+
+ check = MyOperation->interpretedUpdateTuple();
+ CHECK_MINUS_ONE(check, "T4-4: interpretedUpdateTuple",
+ MyTransaction);
+
+ check = MyOperation->equal(IND_SUBSCRIBER_NUMBER,
+ (char*)inNumber);
+ CHECK_MINUS_ONE(check, "T4-4: equal number",
+ MyTransaction);
+
+ check = MyOperation->incValue(IND_SUBSCRIBER_SESSIONS,
+ (uint32)inServerBit);
+ CHECK_MINUS_ONE(check, "T4-4: inc value",
+ MyTransaction);
+
+ /* Operation 5 */
+ MyOperation = MyTransaction->getNdbOperation(SERVER_TABLE);
+ CHECK_NULL(MyOperation, "T4-5: getNdbOperation",
+ MyTransaction);
+
+ check = MyOperation->interpretedUpdateTuple();
+ CHECK_MINUS_ONE(check, "T4-5: interpretedUpdateTuple",
+ MyTransaction);
+
+ check = MyOperation->equal(IND_SERVER_ID,
+ (char*)&inServerId);
+ CHECK_MINUS_ONE(check, "T4-5: equal serverId",
+ MyTransaction);
+
+ check = MyOperation->equal(IND_SERVER_SUBSCRIBER_SUFFIX,
+ (char*)inSuffix);
+ CHECK_MINUS_ONE(check, "T4-5: equal suffix",
+ MyTransaction);
+
+ check = MyOperation->incValue(IND_SERVER_INSERTS, (uint32)1);
+ CHECK_MINUS_ONE(check, "T4-5: inc value",
+ MyTransaction);
+
+ (* outBranchExecuted) = 1;
+ } else {
+ DEBUG1("%s", ((permission & inServerBit) ? "permission - " : "no permission - "));
+ DEBUG1("%s", ((sessions & inServerBit) ? "in session - " : "no in session - "));
+ (* outBranchExecuted) = 0;
+ }
+
+ if(!inDoRollback){
+ DEBUG("commit\n");
+ check = MyTransaction->execute( Commit );
+ CHECK_MINUS_ONE(check, "T4: Commit",
+ MyTransaction);
+ } else {
+ DEBUG("rollback\n");
+ check = MyTransaction->execute(Rollback);
+ CHECK_MINUS_ONE(check, "T4:Rollback",
+ MyTransaction);
+
+ }
+
+ pNDB->closeTransaction(MyTransaction);
+
+ get_time(outTransactionTime);
+ time_diff(outTransactionTime, &start);
+ return 0;
+}
+
+
+/**
+ * Transaction 5 - T5
+ *
+ * Delete session
+ *
+ * Input:
+ * SubscriberNumber
+ * ServerId
+ * ServerBit
+ * DoRollback
+ * Output:
+ * ChangedBy
+ * ChangedTime
+ * Location
+ * BranchExecuted
+ */
+int
+T5(void * obj,
+ const SubscriberNumber inNumber,
+ const SubscriberSuffix inSuffix,
+ const ServerId inServerId,
+ const ServerBit inServerBit,
+ ChangedBy outChangedBy,
+ ChangedTime outChangedTime,
+ Location * outLocation,
+ DoRollback inDoRollback,
+ BranchExecuted * outBranchExecuted,
+ BenchmarkTime * outTransactionTime){
+
+ Ndb * pNDB = (Ndb *) obj;
+ NdbConnection * MyTransaction = 0;
+ NdbOperation * MyOperation = 0;
+
+ GroupId groupId;
+ ActiveSessions sessions;
+ Permission permission;
+
+ BenchmarkTime start;
+ get_time(&start);
+
+ int check;
+ NdbRecAttr * check2;
+
+ MyTransaction = pNDB->startTransaction();
+ if (MyTransaction == NULL)
+ error_handler("T5-1: startTranscation", pNDB->getNdbErrorString(), 0);
+
+ MyOperation= MyTransaction->getNdbOperation(SUBSCRIBER_TABLE);
+ CHECK_NULL(MyOperation, "T5-1: getNdbOperation",
+ MyTransaction);
+
+
+ check = MyOperation->readTupleExclusive();
+ CHECK_MINUS_ONE(check, "T5-1: readTuple",
+ MyTransaction);
+
+ check = MyOperation->equal(IND_SUBSCRIBER_NUMBER,
+ inNumber);
+ CHECK_MINUS_ONE(check, "T5-1: equal subscriber",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_SUBSCRIBER_LOCATION,
+ (char *)outLocation);
+ CHECK_NULL(check2, "T5-1: getValue location",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_SUBSCRIBER_CHANGED_BY,
+ outChangedBy);
+ CHECK_NULL(check2, "T5-1: getValue changed_by",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_SUBSCRIBER_CHANGED_TIME,
+ outChangedTime);
+ CHECK_NULL(check2, "T5-1: getValue changed_time",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_SUBSCRIBER_GROUP,
+ (char *)&groupId);
+ CHECK_NULL(check2, "T5-1: getValue group",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_SUBSCRIBER_SESSIONS,
+ (char *)&sessions);
+ CHECK_NULL(check2, "T5-1: getValue sessions",
+ MyTransaction);
+
+ check = MyTransaction->execute( NoCommit );
+ CHECK_MINUS_ONE(check, "T5-1: NoCommit",
+ MyTransaction);
+
+ /* Operation 2 */
+
+ MyOperation = MyTransaction->getNdbOperation(GROUP_TABLE);
+ CHECK_NULL(MyOperation, "T5-2: getNdbOperation",
+ MyTransaction);
+
+
+ check = MyOperation->readTuple();
+ CHECK_MINUS_ONE(check, "T5-2: readTuple",
+ MyTransaction);
+
+ check = MyOperation->equal(IND_GROUP_ID,
+ (char*)&groupId);
+ CHECK_MINUS_ONE(check, "T5-2: equal group",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_GROUP_ALLOW_DELETE,
+ (char *)&permission);
+ CHECK_NULL(check2, "T5-2: getValue allow_delete",
+ MyTransaction);
+
+ check = MyTransaction->execute( NoCommit );
+ CHECK_MINUS_ONE(check, "T5-2: NoCommit",
+ MyTransaction);
+
+ DEBUG3("T5(%.*s, %.2d): ", SUBSCRIBER_NUMBER_LENGTH, inNumber, inServerId);
+
+ if(((permission & inServerBit) == inServerBit) &&
+ ((sessions & inServerBit) == inServerBit)){
+
+ DEBUG("deleting - ");
+
+ /* Operation 3 */
+ MyOperation = MyTransaction->getNdbOperation(SESSION_TABLE);
+ CHECK_NULL(MyOperation, "T5-3: getNdbOperation",
+ MyTransaction);
+
+ check = MyOperation->deleteTuple();
+ CHECK_MINUS_ONE(check, "T5-3: deleteTuple",
+ MyTransaction);
+
+ check = MyOperation->equal(IND_SESSION_SUBSCRIBER,
+ (char*)inNumber);
+ CHECK_MINUS_ONE(check, "T5-3: equal number",
+ MyTransaction);
+
+ check = MyOperation->equal(IND_SESSION_SERVER,
+ (char*)&inServerId);
+ CHECK_MINUS_ONE(check, "T5-3: equal server id",
+ MyTransaction);
+
+ /* Operation 4 */
+ MyOperation = MyTransaction->getNdbOperation(SUBSCRIBER_TABLE);
+ CHECK_NULL(MyOperation, "T5-4: getNdbOperation",
+ MyTransaction);
+
+ check = MyOperation->interpretedUpdateTuple();
+ CHECK_MINUS_ONE(check, "T5-4: interpretedUpdateTuple",
+ MyTransaction);
+
+ check = MyOperation->equal(IND_SUBSCRIBER_NUMBER,
+ (char*)inNumber);
+ CHECK_MINUS_ONE(check, "T5-4: equal number",
+ MyTransaction);
+
+ check = MyOperation->subValue(IND_SUBSCRIBER_SESSIONS,
+ (uint32)inServerBit);
+ CHECK_MINUS_ONE(check, "T5-4: dec value",
+ MyTransaction);
+
+ /* Operation 5 */
+ MyOperation = MyTransaction->getNdbOperation(SERVER_TABLE);
+ CHECK_NULL(MyOperation, "T5-5: getNdbOperation",
+ MyTransaction);
+
+
+ check = MyOperation->interpretedUpdateTuple();
+ CHECK_MINUS_ONE(check, "T5-5: interpretedUpdateTuple",
+ MyTransaction);
+
+ check = MyOperation->equal(IND_SERVER_ID,
+ (char*)&inServerId);
+ CHECK_MINUS_ONE(check, "T5-5: equal serverId",
+ MyTransaction);
+
+ check = MyOperation->equal(IND_SERVER_SUBSCRIBER_SUFFIX,
+ (char*)inSuffix);
+ CHECK_MINUS_ONE(check, "T5-5: equal suffix",
+ MyTransaction);
+
+ check = MyOperation->incValue(IND_SERVER_DELETES, (uint32)1);
+ CHECK_MINUS_ONE(check, "T5-5: inc value",
+ MyTransaction);
+
+ (* outBranchExecuted) = 1;
+ } else {
+ DEBUG1("%s", ((permission & inServerBit) ? "permission - " : "no permission - "));
+ DEBUG1("%s", ((sessions & inServerBit) ? "in session - " : "no in session - "));
+ (* outBranchExecuted) = 0;
+ }
+
+ if(!inDoRollback){
+ DEBUG("commit\n");
+ check = MyTransaction->execute( Commit );
+ CHECK_MINUS_ONE(check, "T5: Commit",
+ MyTransaction);
+ } else {
+ DEBUG("rollback\n");
+ check = MyTransaction->execute(Rollback);
+ CHECK_MINUS_ONE(check, "T5:Rollback",
+ MyTransaction);
+
+ }
+
+ pNDB->closeTransaction(MyTransaction);
+
+ get_time(outTransactionTime);
+ time_diff(outTransactionTime, &start);
+ return 0;
+}
+
diff --git a/ndb/test/ndbapi/bench/ndb_user_transaction4.cpp b/ndb/test/ndbapi/bench/ndb_user_transaction4.cpp
new file mode 100644
index 00000000000..e652c7bfed8
--- /dev/null
+++ b/ndb/test/ndbapi/bench/ndb_user_transaction4.cpp
@@ -0,0 +1,770 @@
+/* Copyright (C) 2003 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+//#define DEBUG_ON
+
+extern "C" {
+#include "user_transaction.h"
+};
+
+#include "macros.h"
+#include "ndb_schema.hpp"
+#include "ndb_error.hpp"
+
+#include <time.h>
+#include <NdbApi.hpp>
+
+/**
+ * Transaction 1 - T1
+ *
+ * Update location and changed by/time on a subscriber
+ *
+ * Input:
+ * SubscriberNumber,
+ * Location,
+ * ChangedBy,
+ * ChangedTime
+ *
+ * Output:
+ */
+int
+T1(void * obj,
+ const SubscriberNumber number,
+ const Location new_location,
+ const ChangedBy changed_by,
+ const ChangedTime changed_time,
+ BenchmarkTime * transaction_time){
+
+ Ndb * pNDB = (Ndb *) obj;
+
+ DEBUG2("T1(%.*s):\n", SUBSCRIBER_NUMBER_LENGTH, number);
+
+ BenchmarkTime start;
+ get_time(&start);
+
+ int check;
+ NdbRecAttr * check2;
+
+ NdbConnection * MyTransaction = pNDB->startTransaction();
+ if (MyTransaction == NULL)
+ error_handler("T1-1: startTranscation", pNDB->getNdbErrorString(), 0);
+
+ NdbOperation *MyOperation = MyTransaction->getNdbOperation(SUBSCRIBER_TABLE);
+ CHECK_NULL(MyOperation, "T1: getNdbOperation", MyTransaction);
+
+ check = MyOperation->updateTuple();
+ CHECK_MINUS_ONE(check, "T1: updateTuple",
+ MyTransaction);
+
+ check = MyOperation->equal(IND_SUBSCRIBER_NUMBER,
+ number);
+ CHECK_MINUS_ONE(check, "T1: equal subscriber",
+ MyTransaction);
+
+ check = MyOperation->setValue(IND_SUBSCRIBER_LOCATION,
+ (char *)&new_location);
+ CHECK_MINUS_ONE(check, "T1: setValue location",
+ MyTransaction);
+
+ check = MyOperation->setValue(IND_SUBSCRIBER_CHANGED_BY,
+ changed_by);
+ CHECK_MINUS_ONE(check, "T1: setValue changed_by",
+ MyTransaction);
+
+ check = MyOperation->setValue(IND_SUBSCRIBER_CHANGED_TIME,
+ changed_time);
+ CHECK_MINUS_ONE(check, "T1: setValue changed_time",
+ MyTransaction);
+
+ check = MyTransaction->execute( Commit );
+ CHECK_MINUS_ONE(check, "T1: Commit",
+ MyTransaction);
+
+ pNDB->closeTransaction(MyTransaction);
+
+ get_time(transaction_time);
+ time_diff(transaction_time, &start);
+ return 0;
+}
+
+/**
+ * Transaction 2 - T2
+ *
+ * Read from Subscriber:
+ *
+ * Input:
+ * SubscriberNumber
+ *
+ * Output:
+ * Location
+ * Changed by
+ * Changed Timestamp
+ * Name
+ */
+int
+T2(void * obj,
+ const SubscriberNumber number,
+ Location * readLocation,
+ ChangedBy changed_by,
+ ChangedTime changed_time,
+ SubscriberName subscriberName,
+ BenchmarkTime * transaction_time){
+
+ Ndb * pNDB = (Ndb *) obj;
+
+ DEBUG2("T2(%.*s):\n", SUBSCRIBER_NUMBER_LENGTH, number);
+
+ BenchmarkTime start;
+ get_time(&start);
+
+ int check;
+ NdbRecAttr * check2;
+
+ NdbConnection * MyTransaction = pNDB->startTransaction();
+ if (MyTransaction == NULL)
+ error_handler("T2-1: startTranscation", pNDB->getNdbErrorString(), 0);
+
+ NdbOperation *MyOperation= MyTransaction->getNdbOperation(SUBSCRIBER_TABLE);
+ CHECK_NULL(MyOperation, "T2: getNdbOperation",
+ MyTransaction);
+
+
+ check = MyOperation->readTuple();
+ CHECK_MINUS_ONE(check, "T2: readTuple",
+ MyTransaction);
+
+ check = MyOperation->equal(IND_SUBSCRIBER_NUMBER,
+ number);
+ CHECK_MINUS_ONE(check, "T2: equal subscriber",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_SUBSCRIBER_LOCATION,
+ (char *)readLocation);
+ CHECK_NULL(check2, "T2: getValue location",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_SUBSCRIBER_CHANGED_BY,
+ changed_by);
+ CHECK_NULL(check2, "T2: getValue changed_by",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_SUBSCRIBER_CHANGED_TIME,
+ changed_time);
+ CHECK_NULL(check2, "T2: getValue changed_time",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_SUBSCRIBER_NAME,
+ subscriberName);
+ CHECK_NULL(check2, "T2: getValue name",
+ MyTransaction);
+
+ check = MyTransaction->execute( Commit );
+ CHECK_MINUS_ONE(check, "T2: Commit",
+ MyTransaction);
+
+ pNDB->closeTransaction(MyTransaction);
+
+ get_time(transaction_time);
+ time_diff(transaction_time, &start);
+ return 0;
+}
+
+/**
+ * Transaction 3 - T3
+ *
+ * Read session details
+ *
+ * Input:
+ * SubscriberNumber
+ * ServerId
+ * ServerBit
+ *
+ * Output:
+ * BranchExecuted
+ * SessionDetails
+ * ChangedBy
+ * ChangedTime
+ * Location
+ */
+int
+T3(void * obj,
+ const SubscriberNumber inNumber,
+ const SubscriberSuffix inSuffix,
+ const ServerId inServerId,
+ const ServerBit inServerBit,
+ SessionDetails outSessionDetails,
+ ChangedBy outChangedBy,
+ ChangedTime outChangedTime,
+ Location * outLocation,
+ BranchExecuted * outBranchExecuted,
+ BenchmarkTime * outTransactionTime){
+
+ DEBUG3("T3(%.*s, %.2d): ", SUBSCRIBER_NUMBER_LENGTH, inNumber, inServerId);
+
+ Ndb * pNDB = (Ndb *) obj;
+
+ GroupId groupId;
+ ActiveSessions sessions;
+ Permission permission;
+
+ BenchmarkTime start;
+ get_time(&start);
+
+ int check;
+ NdbRecAttr * check2;
+
+ NdbConnection * MyTransaction = pNDB->startTransaction();
+ if (MyTransaction == NULL)
+ error_handler("T3-1: startTranscation", pNDB->getNdbErrorString(), 0);
+
+ NdbOperation *MyOperation= MyTransaction->getNdbOperation(SUBSCRIBER_TABLE);
+ CHECK_NULL(MyOperation, "T3-1: getNdbOperation",
+ MyTransaction);
+
+ check = MyOperation->readTuple();
+ CHECK_MINUS_ONE(check, "T3-1: readTuple",
+ MyTransaction);
+
+ check = MyOperation->equal(IND_SUBSCRIBER_NUMBER,
+ inNumber);
+ CHECK_MINUS_ONE(check, "T3-1: equal subscriber",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_SUBSCRIBER_LOCATION,
+ (char *)outLocation);
+ CHECK_NULL(check2, "T3-1: getValue location",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_SUBSCRIBER_CHANGED_BY,
+ outChangedBy);
+ CHECK_NULL(check2, "T3-1: getValue changed_by",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_SUBSCRIBER_CHANGED_TIME,
+ outChangedTime);
+ CHECK_NULL(check2, "T3-1: getValue changed_time",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_SUBSCRIBER_GROUP,
+ (char *)&groupId);
+ CHECK_NULL(check2, "T3-1: getValue group",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_SUBSCRIBER_SESSIONS,
+ (char *)&sessions);
+ CHECK_NULL(check2, "T3-1: getValue sessions",
+ MyTransaction);
+
+ check = MyTransaction->execute( NoCommit );
+ CHECK_MINUS_ONE(check, "T3-1: NoCommit",
+ MyTransaction);
+
+ /* Operation 2 */
+
+ MyOperation = MyTransaction->getNdbOperation(GROUP_TABLE);
+ CHECK_NULL(MyOperation, "T3-2: getNdbOperation",
+ MyTransaction);
+
+
+ check = MyOperation->readTuple();
+ CHECK_MINUS_ONE(check, "T3-2: readTuple",
+ MyTransaction);
+
+ check = MyOperation->equal(IND_GROUP_ID,
+ (char*)&groupId);
+ CHECK_MINUS_ONE(check, "T3-2: equal group",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_GROUP_ALLOW_READ,
+ (char *)&permission);
+ CHECK_NULL(check2, "T3-2: getValue allow_read",
+ MyTransaction);
+
+ check = MyTransaction->execute( NoCommit );
+ CHECK_MINUS_ONE(check, "T3-2: NoCommit",
+ MyTransaction);
+
+ if(((permission & inServerBit) == inServerBit) &&
+ ((sessions & inServerBit) == inServerBit)){
+
+ DEBUG("reading - ");
+
+ /* Operation 3 */
+
+ MyOperation = MyTransaction->getNdbOperation(SESSION_TABLE);
+ CHECK_NULL(MyOperation, "T3-3: getNdbOperation",
+ MyTransaction);
+
+ check = MyOperation->readTuple();
+ CHECK_MINUS_ONE(check, "T3-3: readTuple",
+ MyTransaction);
+
+ check = MyOperation->equal(IND_SESSION_SUBSCRIBER,
+ (char*)inNumber);
+ CHECK_MINUS_ONE(check, "T3-3: equal number",
+ MyTransaction);
+
+ check = MyOperation->equal(IND_SESSION_SERVER,
+ (char*)&inServerId);
+ CHECK_MINUS_ONE(check, "T3-3: equal server id",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_SESSION_DATA,
+ (char *)outSessionDetails);
+ CHECK_NULL(check2, "T3-3: getValue session details",
+ MyTransaction);
+
+ /* Operation 4 */
+ MyOperation = MyTransaction->getNdbOperation(SERVER_TABLE);
+ CHECK_NULL(MyOperation, "T3-4: getNdbOperation",
+ MyTransaction);
+
+ check = MyOperation->interpretedUpdateTuple();
+ CHECK_MINUS_ONE(check, "T3-4: interpretedUpdateTuple",
+ MyTransaction);
+
+ check = MyOperation->equal(IND_SERVER_ID,
+ (char*)&inServerId);
+ CHECK_MINUS_ONE(check, "T3-4: equal serverId",
+ MyTransaction);
+
+ check = MyOperation->equal(IND_SERVER_SUBSCRIBER_SUFFIX,
+ (char*)inSuffix);
+ CHECK_MINUS_ONE(check, "T3-4: equal suffix",
+ MyTransaction);
+
+ check = MyOperation->incValue(IND_SERVER_READS, (uint32)1);
+ CHECK_MINUS_ONE(check, "T3-4: inc value",
+ MyTransaction);
+ (* outBranchExecuted) = 1;
+ } else {
+ (* outBranchExecuted) = 0;
+ }
+ DEBUG("commit...");
+ check = MyTransaction->execute( Commit );
+ CHECK_MINUS_ONE(check, "T3: Commit",
+ MyTransaction);
+
+ pNDB->closeTransaction(MyTransaction);
+
+ DEBUG("done\n");
+ get_time(outTransactionTime);
+ time_diff(outTransactionTime, &start);
+ return 0;
+}
+
+
+/**
+ * Transaction 4 - T4
+ *
+ * Create session
+ *
+ * Input:
+ * SubscriberNumber
+ * ServerId
+ * ServerBit
+ * SessionDetails,
+ * DoRollback
+ * Output:
+ * ChangedBy
+ * ChangedTime
+ * Location
+ * BranchExecuted
+ */
+int
+T4(void * obj,
+ const SubscriberNumber inNumber,
+ const SubscriberSuffix inSuffix,
+ const ServerId inServerId,
+ const ServerBit inServerBit,
+ const SessionDetails inSessionDetails,
+ ChangedBy outChangedBy,
+ ChangedTime outChangedTime,
+ Location * outLocation,
+ DoRollback inDoRollback,
+ BranchExecuted * outBranchExecuted,
+ BenchmarkTime * outTransactionTime){
+
+ DEBUG3("T4(%.*s, %.2d): ", SUBSCRIBER_NUMBER_LENGTH, inNumber, inServerId);
+
+ Ndb * pNDB = (Ndb *) obj;
+
+ GroupId groupId;
+ ActiveSessions sessions;
+ Permission permission;
+
+ BenchmarkTime start;
+ get_time(&start);
+
+ int check;
+ NdbRecAttr * check2;
+
+ NdbConnection * MyTransaction = pNDB->startTransaction();
+ if (MyTransaction == NULL)
+ error_handler("T4-1: startTranscation", pNDB->getNdbErrorString(), 0);
+
+ NdbOperation *MyOperation= MyTransaction->getNdbOperation(SUBSCRIBER_TABLE);
+ CHECK_NULL(MyOperation, "T4-1: getNdbOperation",
+ MyTransaction);
+
+ check = MyOperation->interpretedUpdateTuple();
+ CHECK_MINUS_ONE(check, "T4-1: readTuple",
+ MyTransaction);
+
+ check = MyOperation->equal(IND_SUBSCRIBER_NUMBER,
+ inNumber);
+ CHECK_MINUS_ONE(check, "T4-1: equal subscriber",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_SUBSCRIBER_LOCATION,
+ (char *)outLocation);
+ CHECK_NULL(check2, "T4-1: getValue location",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_SUBSCRIBER_CHANGED_BY,
+ outChangedBy);
+ CHECK_NULL(check2, "T4-1: getValue changed_by",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_SUBSCRIBER_CHANGED_TIME,
+ outChangedTime);
+ CHECK_NULL(check2, "T4-1: getValue changed_time",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_SUBSCRIBER_GROUP,
+ (char *)&groupId);
+ CHECK_NULL(check2, "T4-1: getValue group",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_SUBSCRIBER_SESSIONS,
+ (char *)&sessions);
+ CHECK_NULL(check2, "T4-1: getValue sessions",
+ MyTransaction);
+
+ check = MyOperation->incValue(IND_SUBSCRIBER_SESSIONS,
+ (uint32)inServerBit);
+ CHECK_MINUS_ONE(check, "T4-4: inc value",
+ MyTransaction);
+
+ check = MyTransaction->execute( NoCommit );
+ CHECK_MINUS_ONE(check, "T4-1: NoCommit",
+ MyTransaction);
+
+ /* Operation 2 */
+
+ MyOperation = MyTransaction->getNdbOperation(GROUP_TABLE);
+ CHECK_NULL(MyOperation, "T4-2: getNdbOperation",
+ MyTransaction);
+
+ check = MyOperation->readTuple();
+ CHECK_MINUS_ONE(check, "T4-2: readTuple",
+ MyTransaction);
+
+ check = MyOperation->equal(IND_GROUP_ID,
+ (char*)&groupId);
+ CHECK_MINUS_ONE(check, "T4-2: equal group",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_GROUP_ALLOW_INSERT,
+ (char *)&permission);
+ CHECK_NULL(check2, "T4-2: getValue allow_insert",
+ MyTransaction);
+
+ check = MyTransaction->execute( NoCommit );
+ CHECK_MINUS_ONE(check, "T4-2: NoCommit",
+ MyTransaction);
+
+ if(((permission & inServerBit) == inServerBit) &&
+ ((sessions & inServerBit) == 0)){
+
+ DEBUG("inserting - ");
+
+ /* Operation 3 */
+
+ MyOperation = MyTransaction->getNdbOperation(SESSION_TABLE);
+ CHECK_NULL(MyOperation, "T4-3: getNdbOperation",
+ MyTransaction);
+
+ check = MyOperation->insertTuple();
+ CHECK_MINUS_ONE(check, "T4-3: insertTuple",
+ MyTransaction);
+
+ check = MyOperation->equal(IND_SESSION_SUBSCRIBER,
+ (char*)inNumber);
+ CHECK_MINUS_ONE(check, "T4-3: equal number",
+ MyTransaction);
+
+ check = MyOperation->equal(IND_SESSION_SERVER,
+ (char*)&inServerId);
+ CHECK_MINUS_ONE(check, "T4-3: equal server id",
+ MyTransaction);
+
+ check = MyOperation->setValue(SESSION_DATA,
+ (char *)inSessionDetails);
+ CHECK_MINUS_ONE(check, "T4-3: setValue session details",
+ MyTransaction);
+
+ /* Operation 4 */
+
+ /* Operation 5 */
+ MyOperation = MyTransaction->getNdbOperation(SERVER_TABLE);
+ CHECK_NULL(MyOperation, "T4-5: getNdbOperation",
+ MyTransaction);
+
+ check = MyOperation->interpretedUpdateTuple();
+ CHECK_MINUS_ONE(check, "T4-5: interpretedUpdateTuple",
+ MyTransaction);
+
+ check = MyOperation->equal(IND_SERVER_ID,
+ (char*)&inServerId);
+ CHECK_MINUS_ONE(check, "T4-5: equal serverId",
+ MyTransaction);
+
+ check = MyOperation->equal(IND_SERVER_SUBSCRIBER_SUFFIX,
+ (char*)inSuffix);
+ CHECK_MINUS_ONE(check, "T4-5: equal suffix",
+ MyTransaction);
+
+ check = MyOperation->incValue(IND_SERVER_INSERTS, (uint32)1);
+ CHECK_MINUS_ONE(check, "T4-5: inc value",
+ MyTransaction);
+
+ (* outBranchExecuted) = 1;
+ } else {
+ DEBUG1("%s", ((permission & inServerBit) ? "permission - " : "no permission - "));
+ DEBUG1("%s", ((sessions & inServerBit) ? "in session - " : "no in session - "));
+ (* outBranchExecuted) = 0;
+ }
+
+ if(!inDoRollback && (* outBranchExecuted)){
+ DEBUG("commit\n");
+ check = MyTransaction->execute( Commit );
+ CHECK_MINUS_ONE(check, "T4: Commit",
+ MyTransaction);
+ } else {
+ DEBUG("rollback\n");
+ check = MyTransaction->execute(Rollback);
+ CHECK_MINUS_ONE(check, "T4:Rollback",
+ MyTransaction);
+
+ }
+
+ pNDB->closeTransaction(MyTransaction);
+
+ get_time(outTransactionTime);
+ time_diff(outTransactionTime, &start);
+ return 0;
+}
+
+
+/**
+ * Transaction 5 - T5
+ *
+ * Delete session
+ *
+ * Input:
+ * SubscriberNumber
+ * ServerId
+ * ServerBit
+ * DoRollback
+ * Output:
+ * ChangedBy
+ * ChangedTime
+ * Location
+ * BranchExecuted
+ */
+int
+T5(void * obj,
+ const SubscriberNumber inNumber,
+ const SubscriberSuffix inSuffix,
+ const ServerId inServerId,
+ const ServerBit inServerBit,
+ ChangedBy outChangedBy,
+ ChangedTime outChangedTime,
+ Location * outLocation,
+ DoRollback inDoRollback,
+ BranchExecuted * outBranchExecuted,
+ BenchmarkTime * outTransactionTime){
+
+ DEBUG3("T5(%.*s, %.2d): ", SUBSCRIBER_NUMBER_LENGTH, inNumber, inServerId);
+
+ Ndb * pNDB = (Ndb *) obj;
+ NdbConnection * MyTransaction = 0;
+ NdbOperation * MyOperation = 0;
+
+ GroupId groupId;
+ ActiveSessions sessions;
+ Permission permission;
+
+ BenchmarkTime start;
+ get_time(&start);
+
+ int check;
+ NdbRecAttr * check2;
+
+ MyTransaction = pNDB->startTransaction();
+ if (MyTransaction == NULL)
+ error_handler("T5-1: startTranscation", pNDB->getNdbErrorString(), 0);
+
+ MyOperation= MyTransaction->getNdbOperation(SUBSCRIBER_TABLE);
+ CHECK_NULL(MyOperation, "T5-1: getNdbOperation",
+ MyTransaction);
+
+ check = MyOperation->interpretedUpdateTuple();
+ CHECK_MINUS_ONE(check, "T5-1: readTuple",
+ MyTransaction);
+
+ check = MyOperation->equal(IND_SUBSCRIBER_NUMBER,
+ inNumber);
+ CHECK_MINUS_ONE(check, "T5-1: equal subscriber",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_SUBSCRIBER_LOCATION,
+ (char *)outLocation);
+ CHECK_NULL(check2, "T5-1: getValue location",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_SUBSCRIBER_CHANGED_BY,
+ outChangedBy);
+ CHECK_NULL(check2, "T5-1: getValue changed_by",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_SUBSCRIBER_CHANGED_TIME,
+ outChangedTime);
+ CHECK_NULL(check2, "T5-1: getValue changed_time",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_SUBSCRIBER_GROUP,
+ (char *)&groupId);
+ CHECK_NULL(check2, "T5-1: getValue group",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_SUBSCRIBER_SESSIONS,
+ (char *)&sessions);
+ CHECK_NULL(check2, "T5-1: getValue sessions",
+ MyTransaction);
+
+ check = MyOperation->subValue(IND_SUBSCRIBER_SESSIONS,
+ (uint32)inServerBit);
+ CHECK_MINUS_ONE(check, "T5-4: dec value",
+ MyTransaction);
+
+ check = MyTransaction->execute( NoCommit );
+ CHECK_MINUS_ONE(check, "T5-1: NoCommit",
+ MyTransaction);
+
+ /* Operation 2 */
+
+ MyOperation = MyTransaction->getNdbOperation(GROUP_TABLE);
+ CHECK_NULL(MyOperation, "T5-2: getNdbOperation",
+ MyTransaction);
+
+
+ check = MyOperation->readTuple();
+ CHECK_MINUS_ONE(check, "T5-2: readTuple",
+ MyTransaction);
+
+ check = MyOperation->equal(IND_GROUP_ID,
+ (char*)&groupId);
+ CHECK_MINUS_ONE(check, "T5-2: equal group",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_GROUP_ALLOW_DELETE,
+ (char *)&permission);
+ CHECK_NULL(check2, "T5-2: getValue allow_delete",
+ MyTransaction);
+
+ check = MyTransaction->execute( NoCommit );
+ CHECK_MINUS_ONE(check, "T5-2: NoCommit",
+ MyTransaction);
+
+ if(((permission & inServerBit) == inServerBit) &&
+ ((sessions & inServerBit) == inServerBit)){
+
+ DEBUG("deleting - ");
+
+ /* Operation 3 */
+ MyOperation = MyTransaction->getNdbOperation(SESSION_TABLE);
+ CHECK_NULL(MyOperation, "T5-3: getNdbOperation",
+ MyTransaction);
+
+ check = MyOperation->deleteTuple();
+ CHECK_MINUS_ONE(check, "T5-3: deleteTuple",
+ MyTransaction);
+
+ check = MyOperation->equal(IND_SESSION_SUBSCRIBER,
+ (char*)inNumber);
+ CHECK_MINUS_ONE(check, "T5-3: equal number",
+ MyTransaction);
+
+ check = MyOperation->equal(IND_SESSION_SERVER,
+ (char*)&inServerId);
+ CHECK_MINUS_ONE(check, "T5-3: equal server id",
+ MyTransaction);
+
+ /* Operation 4 */
+
+ /* Operation 5 */
+ MyOperation = MyTransaction->getNdbOperation(SERVER_TABLE);
+ CHECK_NULL(MyOperation, "T5-5: getNdbOperation",
+ MyTransaction);
+
+
+ check = MyOperation->interpretedUpdateTuple();
+ CHECK_MINUS_ONE(check, "T5-5: interpretedUpdateTuple",
+ MyTransaction);
+
+ check = MyOperation->equal(IND_SERVER_ID,
+ (char*)&inServerId);
+ CHECK_MINUS_ONE(check, "T5-5: equal serverId",
+ MyTransaction);
+
+ check = MyOperation->equal(IND_SERVER_SUBSCRIBER_SUFFIX,
+ (char*)inSuffix);
+ CHECK_MINUS_ONE(check, "T5-5: equal suffix",
+ MyTransaction);
+
+ check = MyOperation->incValue(IND_SERVER_DELETES, (uint32)1);
+ CHECK_MINUS_ONE(check, "T5-5: inc value",
+ MyTransaction);
+
+ (* outBranchExecuted) = 1;
+ } else {
+ DEBUG1("%s", ((permission & inServerBit) ? "permission - " : "no permission - "));
+ DEBUG1("%s", ((sessions & inServerBit) ? "in session - " : "no in session - "));
+ (* outBranchExecuted) = 0;
+ }
+
+ if(!inDoRollback && (* outBranchExecuted)){
+ DEBUG("commit\n");
+ check = MyTransaction->execute( Commit );
+ CHECK_MINUS_ONE(check, "T5: Commit",
+ MyTransaction);
+ } else {
+ DEBUG("rollback\n");
+ check = MyTransaction->execute(Rollback);
+ CHECK_MINUS_ONE(check, "T5:Rollback",
+ MyTransaction);
+
+ }
+
+ pNDB->closeTransaction(MyTransaction);
+
+ get_time(outTransactionTime);
+ time_diff(outTransactionTime, &start);
+ return 0;
+}
+
diff --git a/ndb/test/ndbapi/bench/ndb_user_transaction5.cpp b/ndb/test/ndbapi/bench/ndb_user_transaction5.cpp
new file mode 100644
index 00000000000..86580008d10
--- /dev/null
+++ b/ndb/test/ndbapi/bench/ndb_user_transaction5.cpp
@@ -0,0 +1,769 @@
+/* Copyright (C) 2003 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+//#define DEBUG_ON
+
+extern "C" {
+#include "user_transaction.h"
+};
+
+#include "macros.h"
+#include "ndb_schema.hpp"
+#include "ndb_error.hpp"
+
+#include <time.h>
+#include <NdbApi.hpp>
+
+/**
+ * Transaction 1 - T1
+ *
+ * Update location and changed by/time on a subscriber
+ *
+ * Input:
+ * SubscriberNumber,
+ * Location,
+ * ChangedBy,
+ * ChangedTime
+ *
+ * Output:
+ */
+int
+T1(void * obj,
+ const SubscriberNumber number,
+ const Location new_location,
+ const ChangedBy changed_by,
+ const ChangedTime changed_time,
+ BenchmarkTime * transaction_time){
+
+ Ndb * pNDB = (Ndb *) obj;
+
+ DEBUG2("T1(%.*s):\n", SUBSCRIBER_NUMBER_LENGTH, number);
+
+ BenchmarkTime start;
+ get_time(&start);
+
+ int check;
+ NdbRecAttr * check2;
+
+ NdbConnection * MyTransaction = pNDB->startTransaction();
+ if (MyTransaction == NULL)
+ error_handler("T1-1: startTranscation", pNDB->getNdbErrorString(), 0);
+
+ NdbOperation *MyOperation = MyTransaction->getNdbOperation(SUBSCRIBER_TABLE);
+ CHECK_NULL(MyOperation, "T1: getNdbOperation", MyTransaction);
+
+ check = MyOperation->updateTuple();
+ CHECK_MINUS_ONE(check, "T1: updateTuple",
+ MyTransaction);
+
+ check = MyOperation->equal(IND_SUBSCRIBER_NUMBER,
+ number);
+ CHECK_MINUS_ONE(check, "T1: equal subscriber",
+ MyTransaction);
+
+ check = MyOperation->setValue(IND_SUBSCRIBER_LOCATION,
+ (char *)&new_location);
+ CHECK_MINUS_ONE(check, "T1: setValue location",
+ MyTransaction);
+
+ check = MyOperation->setValue(IND_SUBSCRIBER_CHANGED_BY,
+ changed_by);
+ CHECK_MINUS_ONE(check, "T1: setValue changed_by",
+ MyTransaction);
+
+ check = MyOperation->setValue(IND_SUBSCRIBER_CHANGED_TIME,
+ changed_time);
+ CHECK_MINUS_ONE(check, "T1: setValue changed_time",
+ MyTransaction);
+
+ check = MyTransaction->execute( Commit );
+ CHECK_MINUS_ONE(check, "T1: Commit",
+ MyTransaction);
+
+ pNDB->closeTransaction(MyTransaction);
+
+ get_time(transaction_time);
+ time_diff(transaction_time, &start);
+ return 0;
+}
+
+/**
+ * Transaction 2 - T2
+ *
+ * Read from Subscriber:
+ *
+ * Input:
+ * SubscriberNumber
+ *
+ * Output:
+ * Location
+ * Changed by
+ * Changed Timestamp
+ * Name
+ */
+int
+T2(void * obj,
+ const SubscriberNumber number,
+ Location * readLocation,
+ ChangedBy changed_by,
+ ChangedTime changed_time,
+ SubscriberName subscriberName,
+ BenchmarkTime * transaction_time){
+
+ Ndb * pNDB = (Ndb *) obj;
+
+ DEBUG2("T2(%.*s):\n", SUBSCRIBER_NUMBER_LENGTH, number);
+
+ BenchmarkTime start;
+ get_time(&start);
+
+ int check;
+ NdbRecAttr * check2;
+
+ NdbConnection * MyTransaction = pNDB->startTransaction();
+ if (MyTransaction == NULL)
+ error_handler("T2-1: startTranscation", pNDB->getNdbErrorString(), 0);
+
+ NdbOperation *MyOperation= MyTransaction->getNdbOperation(SUBSCRIBER_TABLE);
+ CHECK_NULL(MyOperation, "T2: getNdbOperation",
+ MyTransaction);
+
+
+ check = MyOperation->readTuple();
+ CHECK_MINUS_ONE(check, "T2: readTuple",
+ MyTransaction);
+
+ check = MyOperation->equal(IND_SUBSCRIBER_NUMBER,
+ number);
+ CHECK_MINUS_ONE(check, "T2: equal subscriber",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_SUBSCRIBER_LOCATION,
+ (char *)readLocation);
+ CHECK_NULL(check2, "T2: getValue location",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_SUBSCRIBER_CHANGED_BY,
+ changed_by);
+ CHECK_NULL(check2, "T2: getValue changed_by",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_SUBSCRIBER_CHANGED_TIME,
+ changed_time);
+ CHECK_NULL(check2, "T2: getValue changed_time",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_SUBSCRIBER_NAME,
+ subscriberName);
+ CHECK_NULL(check2, "T2: getValue name",
+ MyTransaction);
+
+ check = MyTransaction->execute( Commit );
+ CHECK_MINUS_ONE(check, "T2: Commit",
+ MyTransaction);
+
+ pNDB->closeTransaction(MyTransaction);
+
+ get_time(transaction_time);
+ time_diff(transaction_time, &start);
+ return 0;
+}
+
+/**
+ * Transaction 3 - T3
+ *
+ * Read session details
+ *
+ * Input:
+ * SubscriberNumber
+ * ServerId
+ * ServerBit
+ *
+ * Output:
+ * BranchExecuted
+ * SessionDetails
+ * ChangedBy
+ * ChangedTime
+ * Location
+ */
+int
+T3(void * obj,
+ const SubscriberNumber inNumber,
+ const SubscriberSuffix inSuffix,
+ const ServerId inServerId,
+ const ServerBit inServerBit,
+ SessionDetails outSessionDetails,
+ ChangedBy outChangedBy,
+ ChangedTime outChangedTime,
+ Location * outLocation,
+ BranchExecuted * outBranchExecuted,
+ BenchmarkTime * outTransactionTime){
+
+ Ndb * pNDB = (Ndb *) obj;
+
+ GroupId groupId;
+ ActiveSessions sessions;
+ Permission permission;
+
+ BenchmarkTime start;
+ get_time(&start);
+
+ int check;
+ NdbRecAttr * check2;
+
+ NdbConnection * MyTransaction = pNDB->startTransaction();
+ if (MyTransaction == NULL)
+ error_handler("T3-1: startTranscation", pNDB->getNdbErrorString(), 0);
+
+ NdbOperation *MyOperation= MyTransaction->getNdbOperation(SUBSCRIBER_TABLE);
+ CHECK_NULL(MyOperation, "T3-1: getNdbOperation",
+ MyTransaction);
+
+ check = MyOperation->readTuple();
+ CHECK_MINUS_ONE(check, "T3-1: readTuple",
+ MyTransaction);
+
+ check = MyOperation->equal(IND_SUBSCRIBER_NUMBER,
+ inNumber);
+ CHECK_MINUS_ONE(check, "T3-1: equal subscriber",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_SUBSCRIBER_LOCATION,
+ (char *)outLocation);
+ CHECK_NULL(check2, "T3-1: getValue location",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_SUBSCRIBER_CHANGED_BY,
+ outChangedBy);
+ CHECK_NULL(check2, "T3-1: getValue changed_by",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_SUBSCRIBER_CHANGED_TIME,
+ outChangedTime);
+ CHECK_NULL(check2, "T3-1: getValue changed_time",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_SUBSCRIBER_GROUP,
+ (char *)&groupId);
+ CHECK_NULL(check2, "T3-1: getValue group",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_SUBSCRIBER_SESSIONS,
+ (char *)&sessions);
+ CHECK_NULL(check2, "T3-1: getValue sessions",
+ MyTransaction);
+
+ check = MyTransaction->execute( NoCommit );
+ CHECK_MINUS_ONE(check, "T3-1: NoCommit",
+ MyTransaction);
+
+ /* Operation 2 */
+
+ MyOperation = MyTransaction->getNdbOperation(GROUP_TABLE);
+ CHECK_NULL(MyOperation, "T3-2: getNdbOperation",
+ MyTransaction);
+
+
+ check = MyOperation->readTuple();
+ CHECK_MINUS_ONE(check, "T3-2: readTuple",
+ MyTransaction);
+
+ check = MyOperation->equal(IND_GROUP_ID,
+ (char*)&groupId);
+ CHECK_MINUS_ONE(check, "T3-2: equal group",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_GROUP_ALLOW_READ,
+ (char *)&permission);
+ CHECK_NULL(check2, "T3-2: getValue allow_read",
+ MyTransaction);
+
+ check = MyTransaction->execute( NoCommit );
+ CHECK_MINUS_ONE(check, "T3-2: NoCommit",
+ MyTransaction);
+
+ DEBUG3("T3(%.*s, %.2d): ", SUBSCRIBER_NUMBER_LENGTH, inNumber, inServerId);
+
+ if(((permission & inServerBit) == inServerBit) &&
+ ((sessions & inServerBit) == inServerBit)){
+
+ DEBUG("reading - ");
+
+ /* Operation 3 */
+ MyOperation = MyTransaction->getNdbOperation(SESSION_TABLE);
+ CHECK_NULL(MyOperation, "T3-3: getNdbOperation",
+ MyTransaction);
+
+ check = MyOperation->simpleRead();
+ CHECK_MINUS_ONE(check, "T3-3: readTuple",
+ MyTransaction);
+
+ check = MyOperation->equal(IND_SESSION_SUBSCRIBER,
+ (char*)inNumber);
+ CHECK_MINUS_ONE(check, "T3-3: equal number",
+ MyTransaction);
+
+ check = MyOperation->equal(IND_SESSION_SERVER,
+ (char*)&inServerId);
+ CHECK_MINUS_ONE(check, "T3-3: equal server id",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_SESSION_DATA,
+ (char *)outSessionDetails);
+ CHECK_NULL(check2, "T3-3: getValue session details",
+ MyTransaction);
+
+ /* Operation 4 */
+ MyOperation = MyTransaction->getNdbOperation(SERVER_TABLE);
+ CHECK_NULL(MyOperation, "T3-4: getNdbOperation",
+ MyTransaction);
+
+ check = MyOperation->interpretedUpdateTuple();
+ CHECK_MINUS_ONE(check, "T3-4: interpretedUpdateTuple",
+ MyTransaction);
+
+ check = MyOperation->equal(IND_SERVER_ID,
+ (char*)&inServerId);
+ CHECK_MINUS_ONE(check, "T3-4: equal serverId",
+ MyTransaction);
+
+ check = MyOperation->equal(IND_SERVER_SUBSCRIBER_SUFFIX,
+ (char*)inSuffix);
+ CHECK_MINUS_ONE(check, "T3-4: equal suffix",
+ MyTransaction);
+
+ check = MyOperation->incValue(IND_SERVER_READS, (uint32)1);
+ CHECK_MINUS_ONE(check, "T3-4: inc value",
+ MyTransaction);
+ (* outBranchExecuted) = 1;
+ } else {
+ (* outBranchExecuted) = 0;
+ }
+ DEBUG("commit...");
+ check = MyTransaction->execute( Commit );
+ CHECK_MINUS_ONE(check, "T3: Commit",
+ MyTransaction);
+
+ pNDB->closeTransaction(MyTransaction);
+
+ DEBUG("done\n");
+ get_time(outTransactionTime);
+ time_diff(outTransactionTime, &start);
+ return 0;
+}
+
+
+/**
+ * Transaction 4 - T4
+ *
+ * Create session
+ *
+ * Input:
+ * SubscriberNumber
+ * ServerId
+ * ServerBit
+ * SessionDetails,
+ * DoRollback
+ * Output:
+ * ChangedBy
+ * ChangedTime
+ * Location
+ * BranchExecuted
+ */
+int
+T4(void * obj,
+ const SubscriberNumber inNumber,
+ const SubscriberSuffix inSuffix,
+ const ServerId inServerId,
+ const ServerBit inServerBit,
+ const SessionDetails inSessionDetails,
+ ChangedBy outChangedBy,
+ ChangedTime outChangedTime,
+ Location * outLocation,
+ DoRollback inDoRollback,
+ BranchExecuted * outBranchExecuted,
+ BenchmarkTime * outTransactionTime){
+
+ Ndb * pNDB = (Ndb *) obj;
+
+ GroupId groupId;
+ ActiveSessions sessions;
+ Permission permission;
+
+ BenchmarkTime start;
+ get_time(&start);
+
+ int check;
+ NdbRecAttr * check2;
+
+ NdbConnection * MyTransaction = pNDB->startTransaction();
+ if (MyTransaction == NULL)
+ error_handler("T4-1: startTranscation", pNDB->getNdbErrorString(), 0);
+
+ NdbOperation *MyOperation= MyTransaction->getNdbOperation(SUBSCRIBER_TABLE);
+ CHECK_NULL(MyOperation, "T4-1: getNdbOperation",
+ MyTransaction);
+
+ check = MyOperation->interpretedUpdateTuple();
+ CHECK_MINUS_ONE(check, "T4-1: readTuple",
+ MyTransaction);
+
+ check = MyOperation->equal(IND_SUBSCRIBER_NUMBER,
+ inNumber);
+ CHECK_MINUS_ONE(check, "T4-1: equal subscriber",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_SUBSCRIBER_LOCATION,
+ (char *)outLocation);
+ CHECK_NULL(check2, "T4-1: getValue location",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_SUBSCRIBER_CHANGED_BY,
+ outChangedBy);
+ CHECK_NULL(check2, "T4-1: getValue changed_by",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_SUBSCRIBER_CHANGED_TIME,
+ outChangedTime);
+ CHECK_NULL(check2, "T4-1: getValue changed_time",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_SUBSCRIBER_GROUP,
+ (char *)&groupId);
+ CHECK_NULL(check2, "T4-1: getValue group",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_SUBSCRIBER_SESSIONS,
+ (char *)&sessions);
+ CHECK_NULL(check2, "T4-1: getValue sessions",
+ MyTransaction);
+
+ check = MyOperation->incValue(IND_SUBSCRIBER_SESSIONS,
+ (uint32)inServerBit);
+ CHECK_MINUS_ONE(check, "T4-4: inc value",
+ MyTransaction);
+
+ check = MyTransaction->execute( NoCommit );
+ CHECK_MINUS_ONE(check, "T4-1: NoCommit",
+ MyTransaction);
+
+ /* Operation 2 */
+
+ MyOperation = MyTransaction->getNdbOperation(GROUP_TABLE);
+ CHECK_NULL(MyOperation, "T4-2: getNdbOperation",
+ MyTransaction);
+
+ check = MyOperation->readTuple();
+ CHECK_MINUS_ONE(check, "T4-2: readTuple",
+ MyTransaction);
+
+ check = MyOperation->equal(IND_GROUP_ID,
+ (char*)&groupId);
+ CHECK_MINUS_ONE(check, "T4-2: equal group",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_GROUP_ALLOW_INSERT,
+ (char *)&permission);
+ CHECK_NULL(check2, "T4-2: getValue allow_insert",
+ MyTransaction);
+
+ check = MyTransaction->execute( NoCommit );
+ CHECK_MINUS_ONE(check, "T4-2: NoCommit",
+ MyTransaction);
+
+ DEBUG3("T4(%.*s, %.2d): ", SUBSCRIBER_NUMBER_LENGTH, inNumber, inServerId);
+
+ if(((permission & inServerBit) == inServerBit) &&
+ ((sessions & inServerBit) == 0)){
+
+ DEBUG("inserting - ");
+
+ /* Operation 3 */
+
+ MyOperation = MyTransaction->getNdbOperation(SESSION_TABLE);
+ CHECK_NULL(MyOperation, "T4-3: getNdbOperation",
+ MyTransaction);
+
+ check = MyOperation->insertTuple();
+ CHECK_MINUS_ONE(check, "T4-3: insertTuple",
+ MyTransaction);
+
+ check = MyOperation->equal(IND_SESSION_SUBSCRIBER,
+ (char*)inNumber);
+ CHECK_MINUS_ONE(check, "T4-3: equal number",
+ MyTransaction);
+
+ check = MyOperation->equal(IND_SESSION_SERVER,
+ (char*)&inServerId);
+ CHECK_MINUS_ONE(check, "T4-3: equal server id",
+ MyTransaction);
+
+ check = MyOperation->setValue(SESSION_DATA,
+ (char *)inSessionDetails);
+ CHECK_MINUS_ONE(check, "T4-3: setValue session details",
+ MyTransaction);
+
+ /* Operation 4 */
+
+ /* Operation 5 */
+ MyOperation = MyTransaction->getNdbOperation(SERVER_TABLE);
+ CHECK_NULL(MyOperation, "T4-5: getNdbOperation",
+ MyTransaction);
+
+ check = MyOperation->interpretedUpdateTuple();
+ CHECK_MINUS_ONE(check, "T4-5: interpretedUpdateTuple",
+ MyTransaction);
+
+ check = MyOperation->equal(IND_SERVER_ID,
+ (char*)&inServerId);
+ CHECK_MINUS_ONE(check, "T4-5: equal serverId",
+ MyTransaction);
+
+ check = MyOperation->equal(IND_SERVER_SUBSCRIBER_SUFFIX,
+ (char*)inSuffix);
+ CHECK_MINUS_ONE(check, "T4-5: equal suffix",
+ MyTransaction);
+
+ check = MyOperation->incValue(IND_SERVER_INSERTS, (uint32)1);
+ CHECK_MINUS_ONE(check, "T4-5: inc value",
+ MyTransaction);
+
+ (* outBranchExecuted) = 1;
+ } else {
+ DEBUG1("%s", ((permission & inServerBit) ? "permission - " : "no permission - "));
+ DEBUG1("%s", ((sessions & inServerBit) ? "in session - " : "no in session - "));
+ (* outBranchExecuted) = 0;
+ }
+
+ if(!inDoRollback && (* outBranchExecuted)){
+ DEBUG("commit\n");
+ check = MyTransaction->execute( Commit );
+ CHECK_MINUS_ONE(check, "T4: Commit",
+ MyTransaction);
+ } else {
+ DEBUG("rollback\n");
+ check = MyTransaction->execute(Rollback);
+ CHECK_MINUS_ONE(check, "T4:Rollback",
+ MyTransaction);
+
+ }
+
+ pNDB->closeTransaction(MyTransaction);
+
+ get_time(outTransactionTime);
+ time_diff(outTransactionTime, &start);
+ return 0;
+}
+
+
+/**
+ * Transaction 5 - T5
+ *
+ * Delete session
+ *
+ * Input:
+ * SubscriberNumber
+ * ServerId
+ * ServerBit
+ * DoRollback
+ * Output:
+ * ChangedBy
+ * ChangedTime
+ * Location
+ * BranchExecuted
+ */
+int
+T5(void * obj,
+ const SubscriberNumber inNumber,
+ const SubscriberSuffix inSuffix,
+ const ServerId inServerId,
+ const ServerBit inServerBit,
+ ChangedBy outChangedBy,
+ ChangedTime outChangedTime,
+ Location * outLocation,
+ DoRollback inDoRollback,
+ BranchExecuted * outBranchExecuted,
+ BenchmarkTime * outTransactionTime){
+
+ Ndb * pNDB = (Ndb *) obj;
+ NdbConnection * MyTransaction = 0;
+ NdbOperation * MyOperation = 0;
+
+ GroupId groupId;
+ ActiveSessions sessions;
+ Permission permission;
+
+ BenchmarkTime start;
+ get_time(&start);
+
+ int check;
+ NdbRecAttr * check2;
+
+ MyTransaction = pNDB->startTransaction();
+ if (MyTransaction == NULL)
+ error_handler("T5-1: startTranscation", pNDB->getNdbErrorString(), 0);
+
+ MyOperation= MyTransaction->getNdbOperation(SUBSCRIBER_TABLE);
+ CHECK_NULL(MyOperation, "T5-1: getNdbOperation",
+ MyTransaction);
+
+ check = MyOperation->interpretedUpdateTuple();
+ CHECK_MINUS_ONE(check, "T5-1: readTuple",
+ MyTransaction);
+
+ check = MyOperation->equal(IND_SUBSCRIBER_NUMBER,
+ inNumber);
+ CHECK_MINUS_ONE(check, "T5-1: equal subscriber",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_SUBSCRIBER_LOCATION,
+ (char *)outLocation);
+ CHECK_NULL(check2, "T5-1: getValue location",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_SUBSCRIBER_CHANGED_BY,
+ outChangedBy);
+ CHECK_NULL(check2, "T5-1: getValue changed_by",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_SUBSCRIBER_CHANGED_TIME,
+ outChangedTime);
+ CHECK_NULL(check2, "T5-1: getValue changed_time",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_SUBSCRIBER_GROUP,
+ (char *)&groupId);
+ CHECK_NULL(check2, "T5-1: getValue group",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_SUBSCRIBER_SESSIONS,
+ (char *)&sessions);
+ CHECK_NULL(check2, "T5-1: getValue sessions",
+ MyTransaction);
+
+ check = MyOperation->subValue(IND_SUBSCRIBER_SESSIONS,
+ (uint32)inServerBit);
+ CHECK_MINUS_ONE(check, "T5-4: dec value",
+ MyTransaction);
+
+ check = MyTransaction->execute( NoCommit );
+ CHECK_MINUS_ONE(check, "T5-1: NoCommit",
+ MyTransaction);
+
+ /* Operation 2 */
+
+ MyOperation = MyTransaction->getNdbOperation(GROUP_TABLE);
+ CHECK_NULL(MyOperation, "T5-2: getNdbOperation",
+ MyTransaction);
+
+
+ check = MyOperation->readTuple();
+ CHECK_MINUS_ONE(check, "T5-2: readTuple",
+ MyTransaction);
+
+ check = MyOperation->equal(IND_GROUP_ID,
+ (char*)&groupId);
+ CHECK_MINUS_ONE(check, "T5-2: equal group",
+ MyTransaction);
+
+ check2 = MyOperation->getValue(IND_GROUP_ALLOW_DELETE,
+ (char *)&permission);
+ CHECK_NULL(check2, "T5-2: getValue allow_delete",
+ MyTransaction);
+
+ check = MyTransaction->execute( NoCommit );
+ CHECK_MINUS_ONE(check, "T5-2: NoCommit",
+ MyTransaction);
+
+ DEBUG3("T5(%.*s, %.2d): ", SUBSCRIBER_NUMBER_LENGTH, inNumber, inServerId);
+
+ if(((permission & inServerBit) == inServerBit) &&
+ ((sessions & inServerBit) == inServerBit)){
+
+ DEBUG("deleting - ");
+
+ /* Operation 3 */
+ MyOperation = MyTransaction->getNdbOperation(SESSION_TABLE);
+ CHECK_NULL(MyOperation, "T5-3: getNdbOperation",
+ MyTransaction);
+
+ check = MyOperation->deleteTuple();
+ CHECK_MINUS_ONE(check, "T5-3: deleteTuple",
+ MyTransaction);
+
+ check = MyOperation->equal(IND_SESSION_SUBSCRIBER,
+ (char*)inNumber);
+ CHECK_MINUS_ONE(check, "T5-3: equal number",
+ MyTransaction);
+
+ check = MyOperation->equal(IND_SESSION_SERVER,
+ (char*)&inServerId);
+ CHECK_MINUS_ONE(check, "T5-3: equal server id",
+ MyTransaction);
+
+ /* Operation 4 */
+
+ /* Operation 5 */
+ MyOperation = MyTransaction->getNdbOperation(SERVER_TABLE);
+ CHECK_NULL(MyOperation, "T5-5: getNdbOperation",
+ MyTransaction);
+
+
+ check = MyOperation->interpretedUpdateTuple();
+ CHECK_MINUS_ONE(check, "T5-5: interpretedUpdateTuple",
+ MyTransaction);
+
+ check = MyOperation->equal(IND_SERVER_ID,
+ (char*)&inServerId);
+ CHECK_MINUS_ONE(check, "T5-5: equal serverId",
+ MyTransaction);
+
+ check = MyOperation->equal(IND_SERVER_SUBSCRIBER_SUFFIX,
+ (char*)inSuffix);
+ CHECK_MINUS_ONE(check, "T5-5: equal suffix",
+ MyTransaction);
+
+ check = MyOperation->incValue(IND_SERVER_DELETES, (uint32)1);
+ CHECK_MINUS_ONE(check, "T5-5: inc value",
+ MyTransaction);
+
+ (* outBranchExecuted) = 1;
+ } else {
+ DEBUG1("%s", ((permission & inServerBit) ? "permission - " : "no permission - "));
+ DEBUG1("%s", ((sessions & inServerBit) ? "in session - " : "no in session - "));
+ (* outBranchExecuted) = 0;
+ }
+
+ if(!inDoRollback && (* outBranchExecuted)){
+ DEBUG("commit\n");
+ check = MyTransaction->execute( Commit );
+ CHECK_MINUS_ONE(check, "T5: Commit",
+ MyTransaction);
+ } else {
+ DEBUG("rollback\n");
+ check = MyTransaction->execute(Rollback);
+ CHECK_MINUS_ONE(check, "T5:Rollback",
+ MyTransaction);
+
+ }
+
+ pNDB->closeTransaction(MyTransaction);
+
+ get_time(outTransactionTime);
+ time_diff(outTransactionTime, &start);
+ return 0;
+}
+
diff --git a/ndb/test/ndbapi/bench/ndb_user_transaction6.cpp b/ndb/test/ndbapi/bench/ndb_user_transaction6.cpp
new file mode 100644
index 00000000000..262f38e9ffb
--- /dev/null
+++ b/ndb/test/ndbapi/bench/ndb_user_transaction6.cpp
@@ -0,0 +1,561 @@
+/* Copyright (C) 2003 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+//#define DEBUG_ON
+
+#include <string.h>
+#include "userHandle.h"
+#include "userInterface.h"
+
+#include "macros.h"
+#include "ndb_schema.hpp"
+#include "ndb_error.hpp"
+
+#include <NdbApi.hpp>
+
+
+void
+userCheckpoint(UserHandle *uh){
+}
+
+inline
+NdbConnection *
+startTransaction(Ndb * pNDB, ServerId inServerId, const SubscriberNumber inNumber){
+
+ const int keyDataLenBytes = sizeof(ServerId)+SUBSCRIBER_NUMBER_LENGTH;
+ const int keyDataLen_64Words = keyDataLenBytes >> 3;
+
+ Uint64 keyDataBuf[keyDataLen_64Words+1]; // The "+1" is for rounding...
+
+ char * keyDataBuf_charP = (char *)&keyDataBuf[0];
+ Uint32 * keyDataBuf_wo32P = (Uint32 *)&keyDataBuf[0];
+
+ // Server Id comes first
+ keyDataBuf_wo32P[0] = inServerId;
+ // Then subscriber number
+ memcpy(&keyDataBuf_charP[sizeof(ServerId)], inNumber, SUBSCRIBER_NUMBER_LENGTH);
+
+ return pNDB->startTransaction(0, keyDataBuf_charP, keyDataLenBytes);
+}
+
+/**
+ * Transaction 1 - T1
+ *
+ * Update location and changed by/time on a subscriber
+ *
+ * Input:
+ * SubscriberNumber,
+ * Location,
+ * ChangedBy,
+ * ChangedTime
+ *
+ * Output:
+ */
+void
+userTransaction_T1(UserHandle * uh,
+ SubscriberNumber number,
+ Location new_location,
+ ChangedBy changed_by,
+ ChangedTime changed_time){
+ Ndb * pNDB = uh->pNDB;
+
+ DEBUG2("T1(%.*s):\n", SUBSCRIBER_NUMBER_LENGTH, number);
+
+ int check;
+ NdbRecAttr * check2;
+
+ NdbConnection * MyTransaction = pNDB->startTransaction();
+ if (MyTransaction != NULL) {
+ NdbOperation *MyOperation = MyTransaction->getNdbOperation(SUBSCRIBER_TABLE);
+ if (MyOperation != NULL) {
+ MyOperation->updateTuple();
+ MyOperation->equal(IND_SUBSCRIBER_NUMBER,
+ number);
+ MyOperation->setValue(IND_SUBSCRIBER_LOCATION,
+ (char *)&new_location);
+ MyOperation->setValue(IND_SUBSCRIBER_CHANGED_BY,
+ changed_by);
+ MyOperation->setValue(IND_SUBSCRIBER_CHANGED_TIME,
+ changed_time);
+ check = MyTransaction->execute( Commit );
+ if (check != -1) {
+ pNDB->closeTransaction(MyTransaction);
+ return;
+ } else {
+ CHECK_MINUS_ONE(check, "T1: Commit",
+ MyTransaction);
+ }//if
+ } else {
+ CHECK_NULL(MyOperation, "T1: getNdbOperation", MyTransaction);
+ }//if
+ } else {
+ error_handler("T1-1: startTranscation", pNDB->getNdbErrorString(), pNDB->getNdbError());
+ }//if
+}
+
+/**
+ * Transaction 2 - T2
+ *
+ * Read from Subscriber:
+ *
+ * Input:
+ * SubscriberNumber
+ *
+ * Output:
+ * Location
+ * Changed by
+ * Changed Timestamp
+ * Name
+ */
+void
+userTransaction_T2(UserHandle * uh,
+ SubscriberNumber number,
+ Location * readLocation,
+ ChangedBy changed_by,
+ ChangedTime changed_time,
+ SubscriberName subscriberName){
+ Ndb * pNDB = uh->pNDB;
+
+ DEBUG2("T2(%.*s):\n", SUBSCRIBER_NUMBER_LENGTH, number);
+
+ int check;
+ NdbRecAttr * check2;
+
+ NdbConnection * MyTransaction = pNDB->startTransaction();
+ if (MyTransaction == NULL)
+ error_handler("T2-1: startTransaction", pNDB->getNdbErrorString(), pNDB->getNdbError());
+
+ NdbOperation *MyOperation= MyTransaction->getNdbOperation(SUBSCRIBER_TABLE);
+ CHECK_NULL(MyOperation, "T2: getNdbOperation",
+ MyTransaction);
+
+ MyOperation->readTuple();
+ MyOperation->equal(IND_SUBSCRIBER_NUMBER,
+ number);
+ MyOperation->getValue(IND_SUBSCRIBER_LOCATION,
+ (char *)readLocation);
+ MyOperation->getValue(IND_SUBSCRIBER_CHANGED_BY,
+ changed_by);
+ MyOperation->getValue(IND_SUBSCRIBER_CHANGED_TIME,
+ changed_time);
+ MyOperation->getValue(IND_SUBSCRIBER_NAME,
+ subscriberName);
+ check = MyTransaction->execute( Commit );
+ CHECK_MINUS_ONE(check, "T2: Commit",
+ MyTransaction);
+ pNDB->closeTransaction(MyTransaction);
+}
+
+/**
+ * Transaction 3 - T3
+ *
+ * Read session details
+ *
+ * Input:
+ * SubscriberNumber
+ * ServerId
+ * ServerBit
+ *
+ * Output:
+ * BranchExecuted
+ * SessionDetails
+ * ChangedBy
+ * ChangedTime
+ * Location
+ */
+void
+userTransaction_T3(UserHandle * uh,
+ SubscriberNumber inNumber,
+ ServerId inServerId,
+ ServerBit inServerBit,
+ SessionDetails outSessionDetails,
+ BranchExecuted * outBranchExecuted){
+ Ndb * pNDB = uh->pNDB;
+
+ char outChangedBy [sizeof(ChangedBy) +(4-(sizeof(ChangedBy) & 3))];
+ char outChangedTime [sizeof(ChangedTime)+(4-(sizeof(ChangedTime) & 3))];
+ Location outLocation;
+ GroupId groupId;
+ ActiveSessions sessions;
+ Permission permission;
+ SubscriberSuffix inSuffix;
+
+ DEBUG3("T3(%.*s, %.2d): ", SUBSCRIBER_NUMBER_LENGTH, inNumber, inServerId);
+
+ int check;
+ NdbRecAttr * check2;
+
+ NdbConnection * MyTransaction = startTransaction(pNDB, inServerId, inNumber);
+ if (MyTransaction == NULL)
+ error_handler("T3-1: startTranscation", pNDB->getNdbErrorString(), pNDB->getNdbError());
+
+ NdbOperation *MyOperation= MyTransaction->getNdbOperation(SUBSCRIBER_TABLE);
+ CHECK_NULL(MyOperation, "T3-1: getNdbOperation",
+ MyTransaction);
+
+ MyOperation->readTuple();
+ MyOperation->equal(IND_SUBSCRIBER_NUMBER,
+ inNumber);
+ MyOperation->getValue(IND_SUBSCRIBER_LOCATION,
+ (char *)&outLocation);
+ MyOperation->getValue(IND_SUBSCRIBER_CHANGED_BY,
+ outChangedBy);
+ MyOperation->getValue(IND_SUBSCRIBER_CHANGED_TIME,
+ outChangedTime);
+ MyOperation->getValue(IND_SUBSCRIBER_GROUP,
+ (char *)&groupId);
+ MyOperation->getValue(IND_SUBSCRIBER_SESSIONS,
+ (char *)&sessions);
+ check = MyTransaction->execute( NoCommit );
+ CHECK_MINUS_ONE(check, "T3-1: NoCommit",
+ MyTransaction);
+
+ /* Operation 2 */
+
+ MyOperation = MyTransaction->getNdbOperation(GROUP_TABLE);
+ CHECK_NULL(MyOperation, "T3-2: getNdbOperation",
+ MyTransaction);
+
+
+ MyOperation->readTuple();
+ MyOperation->equal(IND_GROUP_ID,
+ (char*)&groupId);
+ MyOperation->getValue(IND_GROUP_ALLOW_READ,
+ (char *)&permission);
+ check = MyTransaction->execute( NoCommit );
+ CHECK_MINUS_ONE(check, "T3-2: NoCommit",
+ MyTransaction);
+
+ if(((permission & inServerBit) == inServerBit) &&
+ ((sessions & inServerBit) == inServerBit)){
+
+ memcpy(inSuffix,
+ &inNumber[SUBSCRIBER_NUMBER_LENGTH-SUBSCRIBER_NUMBER_SUFFIX_LENGTH], SUBSCRIBER_NUMBER_SUFFIX_LENGTH);
+ DEBUG2("reading(%.*s) - ", SUBSCRIBER_NUMBER_SUFFIX_LENGTH, inSuffix);
+
+ /* Operation 3 */
+ MyOperation = MyTransaction->getNdbOperation(SESSION_TABLE);
+ CHECK_NULL(MyOperation, "T3-3: getNdbOperation",
+ MyTransaction);
+
+ MyOperation->simpleRead();
+
+ MyOperation->equal(IND_SESSION_SUBSCRIBER,
+ (char*)inNumber);
+ MyOperation->equal(IND_SESSION_SERVER,
+ (char*)&inServerId);
+ MyOperation->getValue(IND_SESSION_DATA,
+ (char *)outSessionDetails);
+ /* Operation 4 */
+ MyOperation = MyTransaction->getNdbOperation(SERVER_TABLE);
+ CHECK_NULL(MyOperation, "T3-4: getNdbOperation",
+ MyTransaction);
+
+ MyOperation->interpretedUpdateTuple();
+ MyOperation->equal(IND_SERVER_ID,
+ (char*)&inServerId);
+ MyOperation->equal(IND_SERVER_SUBSCRIBER_SUFFIX,
+ (char*)inSuffix);
+ MyOperation->incValue(IND_SERVER_READS, (uint32)1);
+ (* outBranchExecuted) = 1;
+ } else {
+ (* outBranchExecuted) = 0;
+ }
+ DEBUG("commit...");
+ check = MyTransaction->execute( Commit );
+ CHECK_MINUS_ONE(check, "T3: Commit",
+ MyTransaction);
+
+ pNDB->closeTransaction(MyTransaction);
+
+ DEBUG("done\n");
+}
+
+
+/**
+ * Transaction 4 - T4
+ *
+ * Create session
+ *
+ * Input:
+ * SubscriberNumber
+ * ServerId
+ * ServerBit
+ * SessionDetails,
+ * DoRollback
+ * Output:
+ * ChangedBy
+ * ChangedTime
+ * Location
+ * BranchExecuted
+ */
+void
+userTransaction_T4(UserHandle * uh,
+ SubscriberNumber inNumber,
+ ServerId inServerId,
+ ServerBit inServerBit,
+ SessionDetails inSessionDetails,
+ DoRollback inDoRollback,
+ BranchExecuted * outBranchExecuted){
+
+ Ndb * pNDB = uh->pNDB;
+
+ char outChangedBy [sizeof(ChangedBy) +(4-(sizeof(ChangedBy) & 3))];
+ char outChangedTime [sizeof(ChangedTime)+(4-(sizeof(ChangedTime) & 3))];
+ Location outLocation;
+ GroupId groupId;
+ ActiveSessions sessions;
+ Permission permission;
+ SubscriberSuffix inSuffix;
+
+ DEBUG3("T4(%.*s, %.2d): ", SUBSCRIBER_NUMBER_LENGTH, inNumber, inServerId);
+
+ int check;
+ NdbRecAttr * check2;
+
+ NdbConnection * MyTransaction = startTransaction(pNDB, inServerId, inNumber);
+ if (MyTransaction == NULL)
+ error_handler("T4-1: startTranscation", pNDB->getNdbErrorString(), pNDB->getNdbError());
+
+ NdbOperation *MyOperation= MyTransaction->getNdbOperation(SUBSCRIBER_TABLE);
+ CHECK_NULL(MyOperation, "T4-1: getNdbOperation",
+ MyTransaction);
+
+ MyOperation->interpretedUpdateTuple();
+ MyOperation->equal(IND_SUBSCRIBER_NUMBER,
+ inNumber);
+ MyOperation->getValue(IND_SUBSCRIBER_LOCATION,
+ (char *)&outLocation);
+ MyOperation->getValue(IND_SUBSCRIBER_CHANGED_BY,
+ outChangedBy);
+ MyOperation->getValue(IND_SUBSCRIBER_CHANGED_TIME,
+ outChangedTime);
+ MyOperation->getValue(IND_SUBSCRIBER_GROUP,
+ (char *)&groupId);
+ MyOperation->getValue(IND_SUBSCRIBER_SESSIONS,
+ (char *)&sessions);
+ MyOperation->incValue(IND_SUBSCRIBER_SESSIONS,
+ (uint32)inServerBit);
+ check = MyTransaction->execute( NoCommit );
+
+ /* Operation 2 */
+
+ MyOperation = MyTransaction->getNdbOperation(GROUP_TABLE);
+ CHECK_NULL(MyOperation, "T4-2: getNdbOperation",
+ MyTransaction);
+
+ MyOperation->readTuple();
+ MyOperation->equal(IND_GROUP_ID,
+ (char*)&groupId);
+ MyOperation->getValue(IND_GROUP_ALLOW_INSERT,
+ (char *)&permission);
+ check = MyTransaction->execute( NoCommit );
+ CHECK_MINUS_ONE(check, "T4-2: NoCommit",
+ MyTransaction);
+
+ if(((permission & inServerBit) == inServerBit) &&
+ ((sessions & inServerBit) == 0)){
+
+ memcpy(inSuffix,
+ &inNumber[SUBSCRIBER_NUMBER_LENGTH-SUBSCRIBER_NUMBER_SUFFIX_LENGTH], SUBSCRIBER_NUMBER_SUFFIX_LENGTH);
+
+ DEBUG2("inserting(%.*s) - ", SUBSCRIBER_NUMBER_SUFFIX_LENGTH, inSuffix);
+
+ /* Operation 3 */
+
+ MyOperation = MyTransaction->getNdbOperation(SESSION_TABLE);
+ CHECK_NULL(MyOperation, "T4-3: getNdbOperation",
+ MyTransaction);
+
+ MyOperation->insertTuple();
+ MyOperation->equal(IND_SESSION_SUBSCRIBER,
+ (char*)inNumber);
+ MyOperation->equal(IND_SESSION_SERVER,
+ (char*)&inServerId);
+ MyOperation->setValue(SESSION_DATA,
+ (char *)inSessionDetails);
+ /* Operation 4 */
+
+ /* Operation 5 */
+ MyOperation = MyTransaction->getNdbOperation(SERVER_TABLE);
+ CHECK_NULL(MyOperation, "T4-5: getNdbOperation",
+ MyTransaction);
+
+ MyOperation->interpretedUpdateTuple();
+ MyOperation->equal(IND_SERVER_ID,
+ (char*)&inServerId);
+ MyOperation->equal(IND_SERVER_SUBSCRIBER_SUFFIX,
+ (char*)inSuffix);
+ MyOperation->incValue(IND_SERVER_INSERTS, (uint32)1);
+ (* outBranchExecuted) = 1;
+ } else {
+ (* outBranchExecuted) = 0;
+ DEBUG1("%s", ((permission & inServerBit) ? "permission - " : "no permission - "));
+ DEBUG1("%s", ((sessions & inServerBit) ? "in session - " : "no in session - "));
+ }
+
+ if(!inDoRollback && (* outBranchExecuted)){
+ DEBUG("commit\n");
+ check = MyTransaction->execute( Commit );
+ CHECK_MINUS_ONE(check, "T4: Commit",
+ MyTransaction);
+ } else {
+ DEBUG("rollback\n");
+ check = MyTransaction->execute(Rollback);
+ CHECK_MINUS_ONE(check, "T4:Rollback",
+ MyTransaction);
+
+ }
+
+ pNDB->closeTransaction(MyTransaction);
+}
+
+
+/**
+ * Transaction 5 - T5
+ *
+ * Delete session
+ *
+ * Input:
+ * SubscriberNumber
+ * ServerId
+ * ServerBit
+ * DoRollback
+ * Output:
+ * ChangedBy
+ * ChangedTime
+ * Location
+ * BranchExecuted
+ */
+void
+userTransaction_T5(UserHandle * uh,
+ SubscriberNumber inNumber,
+ ServerId inServerId,
+ ServerBit inServerBit,
+ DoRollback inDoRollback,
+ BranchExecuted * outBranchExecuted){
+ Ndb * pNDB = uh->pNDB;
+
+ DEBUG3("T5(%.*s, %.2d): ", SUBSCRIBER_NUMBER_LENGTH, inNumber, inServerId);
+
+ NdbConnection * MyTransaction = 0;
+ NdbOperation * MyOperation = 0;
+
+ char outChangedBy [sizeof(ChangedBy) +(4-(sizeof(ChangedBy) & 3))];
+ char outChangedTime [sizeof(ChangedTime)+(4-(sizeof(ChangedTime) & 3))];
+ Location outLocation;
+ GroupId groupId;
+ ActiveSessions sessions;
+ Permission permission;
+ SubscriberSuffix inSuffix;
+
+ int check;
+ NdbRecAttr * check2;
+
+ MyTransaction = pNDB->startTransaction();
+ if (MyTransaction == NULL)
+ error_handler("T5-1: startTranscation", pNDB->getNdbErrorString(), pNDB->getNdbError());
+
+ MyOperation= MyTransaction->getNdbOperation(SUBSCRIBER_TABLE);
+ CHECK_NULL(MyOperation, "T5-1: getNdbOperation",
+ MyTransaction);
+
+ MyOperation->interpretedUpdateTuple();
+ MyOperation->equal(IND_SUBSCRIBER_NUMBER,
+ inNumber);
+ MyOperation->getValue(IND_SUBSCRIBER_LOCATION,
+ (char *)&outLocation);
+ MyOperation->getValue(IND_SUBSCRIBER_CHANGED_BY,
+ &outChangedBy[0]);
+ MyOperation->getValue(IND_SUBSCRIBER_CHANGED_TIME,
+ &outChangedTime[0]);
+ MyOperation->getValue(IND_SUBSCRIBER_GROUP,
+ (char *)&groupId);
+ MyOperation->getValue(IND_SUBSCRIBER_SESSIONS,
+ (char *)&sessions);
+ MyOperation->subValue(IND_SUBSCRIBER_SESSIONS,
+ (uint32)inServerBit);
+ MyTransaction->execute( NoCommit );
+ /* Operation 2 */
+
+ MyOperation = MyTransaction->getNdbOperation(GROUP_TABLE);
+ CHECK_NULL(MyOperation, "T5-2: getNdbOperation",
+ MyTransaction);
+
+ MyOperation->readTuple();
+ MyOperation->equal(IND_GROUP_ID,
+ (char*)&groupId);
+ MyOperation->getValue(IND_GROUP_ALLOW_DELETE,
+ (char *)&permission);
+ check = MyTransaction->execute( NoCommit );
+ CHECK_MINUS_ONE(check, "T5-2: NoCommit",
+ MyTransaction);
+
+ if(((permission & inServerBit) == inServerBit) &&
+ ((sessions & inServerBit) == inServerBit)){
+
+ memcpy(inSuffix,
+ &inNumber[SUBSCRIBER_NUMBER_LENGTH-SUBSCRIBER_NUMBER_SUFFIX_LENGTH], SUBSCRIBER_NUMBER_SUFFIX_LENGTH);
+
+ DEBUG2("deleting(%.*s) - ", SUBSCRIBER_NUMBER_SUFFIX_LENGTH, inSuffix);
+
+ /* Operation 3 */
+ MyOperation = MyTransaction->getNdbOperation(SESSION_TABLE);
+ CHECK_NULL(MyOperation, "T5-3: getNdbOperation",
+ MyTransaction);
+
+ MyOperation->deleteTuple();
+ MyOperation->equal(IND_SESSION_SUBSCRIBER,
+ (char*)inNumber);
+ MyOperation->equal(IND_SESSION_SERVER,
+ (char*)&inServerId);
+ /* Operation 4 */
+
+ /* Operation 5 */
+ MyOperation = MyTransaction->getNdbOperation(SERVER_TABLE);
+ CHECK_NULL(MyOperation, "T5-5: getNdbOperation",
+ MyTransaction);
+
+
+ MyOperation->interpretedUpdateTuple();
+ MyOperation->equal(IND_SERVER_ID,
+ (char*)&inServerId);
+ MyOperation->equal(IND_SERVER_SUBSCRIBER_SUFFIX,
+ (char*)inSuffix);
+ MyOperation->incValue(IND_SERVER_DELETES, (uint32)1);
+ (* outBranchExecuted) = 1;
+ } else {
+ (* outBranchExecuted) = 0;
+ DEBUG1("%s", ((permission & inServerBit) ? "permission - " : "no permission - "));
+ DEBUG1("%s", ((sessions & inServerBit) ? "in session - " : "no in session - "));
+ }
+
+ if(!inDoRollback && (* outBranchExecuted)){
+ DEBUG("commit\n");
+ check = MyTransaction->execute( Commit );
+ CHECK_MINUS_ONE(check, "T5: Commit",
+ MyTransaction);
+ } else {
+ DEBUG("rollback\n");
+ check = MyTransaction->execute(Rollback);
+ CHECK_MINUS_ONE(check, "T5:Rollback",
+ MyTransaction);
+
+ }
+
+ pNDB->closeTransaction(MyTransaction);
+}
+
diff --git a/ndb/test/ndbapi/bench/testData.h b/ndb/test/ndbapi/bench/testData.h
new file mode 100644
index 00000000000..3db85e7342e
--- /dev/null
+++ b/ndb/test/ndbapi/bench/testData.h
@@ -0,0 +1,156 @@
+/* Copyright (C) 2003 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#ifndef TESTDATA_H
+#define TESTDATA_H
+
+/***************************************************************
+* I N C L U D E D F I L E S *
+***************************************************************/
+#include <NdbTick.h>
+#include <NdbThread.h>
+#include <NDBT_Stats.hpp>
+#include <random.h>
+#include "testDefinitions.h"
+
+/***************************************************************
+* M A C R O S *
+***************************************************************/
+
+/***************************************************************/
+/* C O N S T A N T S */
+/***************************************************************/
+
+#define NUM_TRANSACTION_TYPES 5
+#define SESSION_LIST_LENGTH 1000
+
+/***************************************************************
+* D A T A S T R U C T U R E S *
+***************************************************************/
+
+typedef struct {
+ SubscriberNumber subscriberNumber;
+ ServerId serverId;
+} SessionElement;
+
+typedef struct {
+ SessionElement list[SESSION_LIST_LENGTH];
+ unsigned int readIndex;
+ unsigned int writeIndex;
+ unsigned int numberInList;
+} SessionList;
+
+typedef struct {
+ unsigned int count;
+ unsigned int branchExecuted;
+ unsigned int rollbackExecuted;
+
+ /**
+ * Latency measures
+ */
+ NDB_TICKS startTime;
+ NDBT_Stats latency;
+ unsigned int latencyCounter;
+
+ inline void startLatency(){
+ if((latencyCounter & 127) == 127)
+ startTime = NdbTick_CurrentMillisecond();
+ }
+
+ inline void stopLatency(){
+ if((latencyCounter & 127) == 127){
+ const NDB_TICKS tmp = NdbTick_CurrentMillisecond() - startTime;
+ latency.addObservation(tmp);
+ }
+ latencyCounter++;
+ }
+} TransactionDefinition;
+
+typedef struct {
+ RandomSequence transactionSequence;
+ RandomSequence rollbackSequenceT4;
+ RandomSequence rollbackSequenceT5;
+
+ TransactionDefinition transactions[NUM_TRANSACTION_TYPES];
+
+ unsigned int totalTransactions;
+
+ double outerLoopTime;
+ double outerTps;
+
+ SessionList activeSessions;
+
+} GeneratorStatistics;
+
+typedef enum{
+ Runnable,
+ Running
+} RunState ;
+
+typedef struct {
+ SubscriberNumber number;
+ SubscriberSuffix suffix;
+ SubscriberName name;
+ Location location;
+ ChangedBy changed_by;
+ ChangedTime changed_time;
+ ServerId server_id;
+ ServerBit server_bit;
+ SessionDetails session_details;
+
+ GroupId group_id;
+ ActiveSessions sessions;
+ Permission permission;
+
+ unsigned int do_rollback;
+
+ unsigned int branchExecuted;
+ unsigned int sessionElement;
+} TransactionData ;
+
+typedef struct {
+ struct NdbThread* pThread;
+
+ unsigned long randomSeed;
+ unsigned long changedTime;
+
+ unsigned int warmUpSeconds;
+ unsigned int testSeconds;
+ unsigned int coolDownSeconds;
+
+ GeneratorStatistics generator;
+
+ /**
+ * For async execution
+ */
+ RunState runState;
+ double startTime;
+ TransactionData transactionData;
+ struct Ndb * pNDB;
+} ThreadData;
+
+/***************************************************************
+ * P U B L I C F U N C T I O N S *
+ ***************************************************************/
+
+/***************************************************************
+ * E X T E R N A L D A T A *
+ ***************************************************************/
+
+
+
+#endif /* TESTDATA_H */
+
diff --git a/ndb/test/ndbapi/bench/testDefinitions.h b/ndb/test/ndbapi/bench/testDefinitions.h
new file mode 100644
index 00000000000..2f4aeb30975
--- /dev/null
+++ b/ndb/test/ndbapi/bench/testDefinitions.h
@@ -0,0 +1,90 @@
+/* Copyright (C) 2003 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#ifndef TESTDEFINITIONS_H
+#define TESTDEFINITIONS_H
+
+/***************************************************************/
+/* I N C L U D E D F I L E S */
+/***************************************************************/
+
+#include <ndb_types.h>
+
+/***************************************************************/
+/* C O N S T A N T S */
+/***************************************************************/
+
+#define OP_PER_TRANS 200
+#define NO_OF_SUBSCRIBERS 500000
+#define NO_OF_GROUPS 100
+#define NO_OF_SERVERS 20
+
+#define SUBSCRIBER_NUMBER_LENGTH 12
+#define SUBSCRIBER_NUMBER_SUFFIX_LENGTH 2
+
+#define SUBSCRIBER_NAME_LENGTH 32
+#define CHANGED_BY_LENGTH 32
+#define CHANGED_TIME_LENGTH 32
+#define SESSION_DETAILS_LENGTH 2000
+#define SERVER_NAME_LENGTH 32
+#define GROUP_NAME_LENGTH 32
+
+/***************************************************************
+* D A T A S T R U C T U R E S *
+***************************************************************/
+
+#define PADDING 4
+
+typedef char SubscriberNumber[SUBSCRIBER_NUMBER_LENGTH];
+typedef char SubscriberSuffix[SUBSCRIBER_NUMBER_SUFFIX_LENGTH + 2];
+typedef char SubscriberName[SUBSCRIBER_NAME_LENGTH];
+typedef char ServerName[SERVER_NAME_LENGTH];
+typedef char GroupName[GROUP_NAME_LENGTH];
+typedef char ChangedBy[CHANGED_BY_LENGTH];
+typedef char ChangedTime[CHANGED_TIME_LENGTH];
+typedef char SessionDetails[SESSION_DETAILS_LENGTH];
+typedef Uint32 ServerId;
+typedef Uint32 ServerBit;
+typedef Uint32 GroupId;
+typedef Uint32 Location;
+typedef Uint32 Permission;
+
+typedef Uint32 Counter;
+typedef Uint32 ActiveSessions;
+typedef unsigned int BranchExecuted;
+typedef unsigned int DoRollback;
+
+/***************************************************************
+* P U B L I C F U N C T I O N S *
+***************************************************************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif
+
+/***************************************************************
+* E X T E R N A L D A T A *
+***************************************************************/
+
+
+
+#endif /* TESTDEFINITIONS_H */
+
diff --git a/ndb/test/ndbapi/bench/userInterface.cpp b/ndb/test/ndbapi/bench/userInterface.cpp
new file mode 100644
index 00000000000..683552c3133
--- /dev/null
+++ b/ndb/test/ndbapi/bench/userInterface.cpp
@@ -0,0 +1,744 @@
+/* Copyright (C) 2003 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/***************************************************************
+* I N C L U D E D F I L E S *
+***************************************************************/
+
+#include <ndb_global.h>
+#ifndef NDB_WIN32
+#include <sys/time.h>
+#endif
+
+#include "ndb_error.hpp"
+#include "userInterface.h"
+#include <NdbThread.h>
+#include <NdbTick.h>
+#include <NdbMutex.h>
+#include <NdbSleep.h>
+#include "ndb_schema.hpp"
+#include <NDBT.hpp>
+#include <NdbSchemaCon.hpp>
+
+/***************************************************************
+* L O C A L C O N S T A N T S *
+***************************************************************/
+
+/***************************************************************
+* L O C A L D A T A S T R U C T U R E S *
+***************************************************************/
+
+/***************************************************************
+* L O C A L F U N C T I O N S *
+***************************************************************/
+
+extern int localDbPrepare(UserHandle *uh);
+
+static int dbCreate(UserHandle *uh);
+
+/***************************************************************
+* L O C A L D A T A *
+***************************************************************/
+
+/***************************************************************
+* P U B L I C D A T A *
+***************************************************************/
+
+
+/***************************************************************
+****************************************************************
+* L O C A L F U N C T I O N S C O D E S E C T I O N *
+****************************************************************
+***************************************************************/
+
+/***************************************************************
+****************************************************************
+* P U B L I C F U N C T I O N S C O D E S E C T I O N *
+****************************************************************
+***************************************************************/
+
+/*-----------------------------------*/
+/* Time related Functions */
+/* */
+/* Returns a double value in seconds */
+/*-----------------------------------*/
+double userGetTimeSync(void)
+{
+ static int initialized = 0;
+ static NDB_TICKS initSecs = 0;
+ static Uint32 initMicros = 0;
+ double timeValue = 0;
+
+ if ( !initialized ) {
+ initialized = 1;
+ NdbTick_CurrentMicrosecond(&initSecs, &initMicros);
+ timeValue = 0.0;
+ } else {
+ NDB_TICKS secs = 0;
+ Uint32 micros = 0;
+
+ NdbTick_CurrentMicrosecond(&secs, &micros);
+
+ double s = (double)secs - (double)initSecs;
+ double us = (double)secs - (double)initMicros;
+
+ timeValue = s + (us / 1000000.0);
+ }
+
+ return timeValue;
+}
+
+// 0 - OK
+// 1 - Retry transaction
+// 2 - Permanent
+int
+userDbCommit(UserHandle *uh){
+ if(uh->pCurrTrans != 0){
+ int check = uh->pCurrTrans->execute( Commit );
+ NdbError err = uh->pCurrTrans->getNdbError();
+ uh->pNDB->closeTransaction(uh->pCurrTrans);
+ uh->pCurrTrans = 0;
+
+ if(err.status != NdbError::Success)
+ ndbout << err << endl;
+
+ if(err.status == NdbError::TemporaryError &&
+ err.classification == NdbError::OverloadError){
+ NdbSleep_SecSleep(3);
+ }
+
+ return err.status;
+ }
+ return 2;
+}
+
+/**
+ * TRUE - Normal table
+ * FALSE - Table w.o. checkpoing and logging
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+extern int useTableLogging;
+#ifdef __cplusplus
+}
+#endif
+
+
+int
+create_table_server(Ndb * pNdb){
+ int check;
+ NdbSchemaCon * MySchemaTransaction = NdbSchemaCon::startSchemaTrans(pNdb);
+ if( MySchemaTransaction == NULL )
+ error_handler("startSchemaTransaction", pNdb->getNdbError(), 0);
+
+ NdbSchemaOp * MySchemaOp = MySchemaTransaction->getNdbSchemaOp();
+ if( MySchemaOp == NULL )
+ error_handler("getNdbSchemaOp", MySchemaTransaction->getNdbError(), 0);
+
+ // Create table
+ check = MySchemaOp->createTable( SERVER_TABLE,
+ 8, // Table size
+ TupleKey, // Key Type
+ 1 // Nr of Pages
+ ,DistributionGroup,
+ 6,
+ 78,
+ 80,
+ 1,
+ useTableLogging
+ );
+ if( check == -1 )
+ error_handler("createTable", MySchemaTransaction->getNdbError(), 0);
+
+ check = MySchemaOp->createAttribute
+ ( SERVER_SUBSCRIBER_SUFFIX,
+ TupleKey,
+ sizeof(char) << 3,
+ SUBSCRIBER_NUMBER_SUFFIX_LENGTH,
+ String,
+ MMBased,
+ NotNullAttribute,
+ NormalStorageAttribute,
+ 0,
+ 1,
+ 16);
+ if( check == -1 )
+ error_handler("createAttribute (subscriber suffix)",
+ MySchemaTransaction->getNdbError(), 0);
+
+ // Create first column, primary key
+ check = MySchemaOp->createAttribute( SERVER_ID,
+ TupleKey,
+ sizeof(ServerId) << 3,
+ 1,
+ UnSigned,
+ MMBased,
+ NotNullAttribute );
+ if( check == -1 )
+ error_handler("createAttribute (serverid)",
+ MySchemaTransaction->getNdbError(), 0);
+
+
+ check = MySchemaOp->createAttribute( SERVER_NAME,
+ NoKey,
+ sizeof(char) << 3,
+ SERVER_NAME_LENGTH,
+ String,
+ MMBased,
+ NotNullAttribute );
+ if( check == -1 )
+ error_handler("createAttribute (server name)",
+ MySchemaTransaction->getNdbError(), 0);
+
+
+ check = MySchemaOp->createAttribute( SERVER_READS,
+ NoKey,
+ sizeof(Counter) << 3,
+ 1,
+ UnSigned,
+ MMBased,
+ NotNullAttribute );
+ if( check == -1 )
+ error_handler("createAttribute (server reads)",
+ MySchemaTransaction->getNdbError(), 0);
+
+ check = MySchemaOp->createAttribute( SERVER_INSERTS,
+ NoKey,
+ sizeof(Counter) << 3,
+ 1,
+ UnSigned,
+ MMBased,
+ NotNullAttribute );
+ if( check == -1 )
+ error_handler("createAttribute (server inserts)",
+ MySchemaTransaction->getNdbError(), 0);
+
+ check = MySchemaOp->createAttribute( SERVER_DELETES,
+ NoKey,
+ sizeof(Counter) << 3,
+ 1,
+ UnSigned,
+ MMBased,
+ NotNullAttribute );
+ if( check == -1 )
+ error_handler("createAttribute (server deletes)",
+ MySchemaTransaction->getNdbError(), 0);
+
+ if( MySchemaTransaction->execute() == -1 ) {
+ error_handler("schemaTransaction->execute()",
+ MySchemaTransaction->getNdbError(), 0);
+ }
+ NdbSchemaCon::closeSchemaTrans(MySchemaTransaction);
+ return 0;
+}
+
+int
+create_table_group(Ndb * pNdb){
+ int check;
+
+ NdbSchemaCon * MySchemaTransaction = NdbSchemaCon::startSchemaTrans(pNdb);
+ if( MySchemaTransaction == NULL )
+ error_handler("startSchemaTransaction", pNdb->getNdbError(), 0);
+
+ NdbSchemaOp * MySchemaOp = MySchemaTransaction->getNdbSchemaOp();
+ if( MySchemaOp == NULL )
+ error_handler("getNdbSchemaOp", MySchemaTransaction->getNdbError(), 0);
+
+ // Create table
+ check = MySchemaOp->createTable( GROUP_TABLE,
+ 8, // Table size
+ TupleKey, // Key Type
+ 1 // Nr of Pages
+ ,All,
+ 6,
+ 78,
+ 80,
+ 1,
+ useTableLogging
+ );
+
+ if( check == -1 )
+ error_handler("createTable", MySchemaTransaction->getNdbError(), 0);
+
+ // Create first column, primary key
+ check = MySchemaOp->createAttribute( GROUP_ID,
+ TupleKey,
+ sizeof(GroupId) << 3,
+ 1,
+ UnSigned,
+ MMBased,
+ NotNullAttribute );
+ if( check == -1 )
+ error_handler("createAttribute (group id)",
+ MySchemaTransaction->getNdbError(), 0);
+
+ check = MySchemaOp->createAttribute( GROUP_NAME,
+ NoKey,
+ sizeof(char) << 3,
+ GROUP_NAME_LENGTH,
+ String,
+ MMBased,
+ NotNullAttribute );
+ if( check == -1 )
+ error_handler("createAttribute (group name)",
+ MySchemaTransaction->getNdbError(), 0);
+
+
+ check = MySchemaOp->createAttribute( GROUP_ALLOW_READ,
+ NoKey,
+ sizeof(Permission) << 3,
+ 1,
+ String,
+ MMBased,
+ NotNullAttribute );
+ if( check == -1 )
+ error_handler("createAttribute (group read)",
+ MySchemaTransaction->getNdbError(), 0);
+
+
+ check = MySchemaOp->createAttribute( GROUP_ALLOW_INSERT,
+ NoKey,
+ sizeof(Permission) << 3,
+ 1,
+ UnSigned,
+ MMBased,
+ NotNullAttribute );
+ if( check == -1 )
+ error_handler("createAttribute (group insert)",
+ MySchemaTransaction->getNdbError(), 0);
+
+ check = MySchemaOp->createAttribute( GROUP_ALLOW_DELETE,
+ NoKey,
+ sizeof(Permission) << 3,
+ 1,
+ UnSigned,
+ MMBased,
+ NotNullAttribute );
+ if( check == -1 )
+ error_handler("createAttribute (group delete)",
+ MySchemaTransaction->getNdbError(), 0);
+
+ if( MySchemaTransaction->execute() == -1 ) {
+ error_handler("schemaTransaction->execute()",
+ MySchemaTransaction->getNdbError(), 0);
+ }
+ NdbSchemaCon::closeSchemaTrans(MySchemaTransaction);
+ return 0;
+}
+
+int
+create_table_subscriber(Ndb * pNdb){
+ int check;
+ NdbSchemaCon * MySchemaTransaction = NdbSchemaCon::startSchemaTrans(pNdb);
+ if( MySchemaTransaction == NULL )
+ error_handler("startSchemaTransaction", pNdb->getNdbError(), 0);
+
+ NdbSchemaOp * MySchemaOp = MySchemaTransaction->getNdbSchemaOp();
+ if( MySchemaOp == NULL )
+ error_handler("getNdbSchemaOp", MySchemaTransaction->getNdbError(), 0);
+
+ // Create table
+ check = MySchemaOp->createTable( SUBSCRIBER_TABLE,
+ 8, // Table size
+ TupleKey, // Key Type
+ 1 // Nr of Pages
+ ,DistributionGroup,
+ 6,
+ 78,
+ 80,
+ 1,
+ useTableLogging
+ );
+ if( check == -1 )
+ error_handler("createTable", MySchemaTransaction->getNdbError(), 0);
+
+ // Create first column, primary key
+ check = MySchemaOp->createAttribute
+ ( SUBSCRIBER_NUMBER,
+ TupleKey,
+ sizeof(char) << 3,
+ SUBSCRIBER_NUMBER_LENGTH,
+ String,
+ MMBased,
+ NotNullAttribute,
+ NormalStorageAttribute,
+ 0,
+ 1,
+ 16);
+ if( check == -1 )
+ error_handler("createAttribute (subscriber number)",
+ MySchemaTransaction->getNdbError(), 0);
+
+ check = MySchemaOp->createAttribute( SUBSCRIBER_NAME,
+ NoKey,
+ sizeof(char) << 3,
+ SUBSCRIBER_NAME_LENGTH,
+ String,
+ MMBased,
+ NotNullAttribute );
+ if( check == -1 )
+ error_handler("createAttribute (subscriber name)",
+ MySchemaTransaction->getNdbError(), 0);
+
+
+ check = MySchemaOp->createAttribute( SUBSCRIBER_GROUP,
+ NoKey,
+ sizeof(GroupId) << 3,
+ 1,
+ UnSigned,
+ MMBased,
+ NotNullAttribute );
+ if( check == -1 )
+ error_handler("createAttribute (subscriber_group)",
+ MySchemaTransaction->getNdbError(), 0);
+
+
+ check = MySchemaOp->createAttribute( SUBSCRIBER_LOCATION,
+ NoKey,
+ sizeof(Location) << 3,
+ 1,
+ UnSigned,
+ MMBased,
+ NotNullAttribute );
+ if( check == -1 )
+ error_handler("createAttribute (server reads)",
+ MySchemaTransaction->getNdbError(), 0);
+
+ check = MySchemaOp->createAttribute( SUBSCRIBER_SESSIONS,
+ NoKey,
+ sizeof(ActiveSessions) << 3,
+ 1,
+ UnSigned,
+ MMBased,
+ NotNullAttribute );
+ if( check == -1 )
+ error_handler("createAttribute (subscriber_sessions)",
+ MySchemaTransaction->getNdbError(), 0);
+
+ check = MySchemaOp->createAttribute( SUBSCRIBER_CHANGED_BY,
+ NoKey,
+ sizeof(char) << 3,
+ CHANGED_BY_LENGTH,
+ String,
+ MMBased,
+ NotNullAttribute );
+ if( check == -1 )
+ error_handler("createAttribute (subscriber_changed_by)",
+ MySchemaTransaction->getNdbError(), 0);
+
+ check = MySchemaOp->createAttribute( SUBSCRIBER_CHANGED_TIME,
+ NoKey,
+ sizeof(char) << 3,
+ CHANGED_TIME_LENGTH,
+ String,
+ MMBased,
+ NotNullAttribute );
+ if( check == -1 )
+ error_handler("createAttribute (subscriber_changed_time)",
+ MySchemaTransaction->getNdbError(), 0);
+
+ if( MySchemaTransaction->execute() == -1 ) {
+ error_handler("schemaTransaction->execute()",
+ MySchemaTransaction->getNdbError(), 0);
+ }
+ NdbSchemaCon::closeSchemaTrans(MySchemaTransaction);
+ return 0;
+}
+
+int
+create_table_session(Ndb * pNdb){
+ int check;
+ NdbSchemaCon * MySchemaTransaction = NdbSchemaCon::startSchemaTrans(pNdb);
+ if( MySchemaTransaction == NULL )
+ error_handler("startSchemaTransaction", pNdb->getNdbError(), 0);
+
+ NdbSchemaOp * MySchemaOp = MySchemaTransaction->getNdbSchemaOp();
+ if( MySchemaOp == NULL )
+ error_handler("getNdbSchemaOp",
+ MySchemaTransaction->getNdbError(), 0);
+
+ // Create table
+ check = MySchemaOp->createTable( SESSION_TABLE,
+ 8, // Table size
+ TupleKey, // Key Type
+ 1 // Nr of Pages
+ ,DistributionGroup,
+ 6,
+ 78,
+ 80,
+ 1,
+ useTableLogging
+ );
+ if( check == -1 )
+ error_handler("createTable", MySchemaTransaction->getNdbError(), 0);
+
+ check = MySchemaOp->createAttribute( SESSION_SUBSCRIBER,
+ TupleKey,
+ sizeof(char) << 3,
+ SUBSCRIBER_NUMBER_LENGTH,
+ String,
+ MMBased,
+ NotNullAttribute,
+ NormalStorageAttribute,
+ 0,
+ 1,
+ 16);
+ if( check == -1 )
+ error_handler("createAttribute (session_subscriber)",
+ MySchemaTransaction->getNdbError(), 0);
+
+ // Create first column, primary key
+ check = MySchemaOp->createAttribute( SESSION_SERVER,
+ TupleKey,
+ sizeof(ServerId) << 3,
+ 1,
+ UnSigned,
+ MMBased,
+ NotNullAttribute );
+ if( check == -1 )
+ error_handler("createAttribute (session_server)",
+ MySchemaTransaction->getNdbError(), 0);
+
+
+ check = MySchemaOp->createAttribute( SESSION_DATA,
+ NoKey,
+ sizeof(char) << 3,
+ SESSION_DETAILS_LENGTH,
+ String,
+ MMBased,
+ NotNullAttribute );
+ if( check == -1 )
+ error_handler("createAttribute (session_data)",
+ MySchemaTransaction->getNdbError(), 0);
+
+ if( MySchemaTransaction->execute() == -1 ) {
+ error_handler("schemaTransaction->execute()",
+ MySchemaTransaction->getNdbError(), 0);
+ }
+ NdbSchemaCon::closeSchemaTrans(MySchemaTransaction);
+ return 0;
+}
+
+void
+create_table(const char * name, int (* function)(Ndb * pNdb), Ndb* pNdb){
+ printf("creating table %s...", name);
+ if(pNdb->getDictionary()->getTable(name) != 0){
+ printf(" it already exists\n");
+ return;
+ } else {
+ printf("\n");
+ }
+ function(pNdb);
+ printf("creating table %s... done\n", name);
+}
+
+static int dbCreate(Ndb * pNdb)
+{
+ create_table(SUBSCRIBER_TABLE, create_table_subscriber, pNdb);
+ create_table(GROUP_TABLE , create_table_group, pNdb);
+ create_table(SESSION_TABLE , create_table_session, pNdb);
+ create_table(SERVER_TABLE , create_table_server, pNdb);
+ return 0;
+}
+
+#ifndef NDB_WIN32
+#include <unistd.h>
+#endif
+
+UserHandle*
+userDbConnect(uint32 createDb, char *dbName)
+{
+ Ndb_cluster_connection *con= new Ndb_cluster_connection();
+ if(con->connect(12, 5, 1) != 0)
+ {
+ ndbout << "Unable to connect to management server." << endl;
+ return 0;
+ }
+ if (con->wait_until_ready(30,0) < 0)
+ {
+ ndbout << "Cluster nodes not ready in 30 seconds." << endl;
+ return 0;
+ }
+
+ Ndb * pNdb = new Ndb(con, dbName);
+
+ //printf("Initializing...\n");
+ pNdb->init();
+
+ //printf("Waiting...");
+ while(pNdb->waitUntilReady() != 0){
+ //printf("...");
+ }
+ // printf("done\n");
+
+ if( createDb )
+ dbCreate(pNdb);
+
+
+ UserHandle * uh = new UserHandle;
+ uh->pNCC = con;
+ uh->pNDB = pNdb;
+ uh->pCurrTrans = 0;
+
+ return uh;
+}
+
+void userDbDisconnect(UserHandle *uh)
+{
+ delete uh;
+}
+
+int userDbInsertServer(UserHandle *uh,
+ ServerId serverId,
+ SubscriberSuffix suffix,
+ ServerName name)
+{
+ int check;
+
+ uint32 noOfRead = 0;
+ uint32 noOfInsert = 0;
+ uint32 noOfDelete = 0;
+
+ NdbConnection * MyTransaction = 0;
+ if(uh->pCurrTrans != 0){
+ MyTransaction = uh->pCurrTrans;
+ } else {
+ uh->pCurrTrans = MyTransaction = uh->pNDB->startTransaction();
+ }
+ if (MyTransaction == NULL)
+ error_handler("startTranscation", uh->pNDB->getNdbError(), 0);
+
+ NdbOperation *MyOperation = MyTransaction->getNdbOperation(SERVER_TABLE);
+ CHECK_NULL(MyOperation, "getNdbOperation", MyTransaction);
+
+ check = MyOperation->insertTuple();
+ CHECK_MINUS_ONE(check, "insert tuple", MyTransaction);
+
+ check = MyOperation->equal(SERVER_ID, (char*)&serverId);
+ CHECK_MINUS_ONE(check, "setValue id", MyTransaction);
+
+ check = MyOperation->setValue(SERVER_SUBSCRIBER_SUFFIX, suffix);
+ CHECK_MINUS_ONE(check, "setValue suffix", MyTransaction);
+
+ check = MyOperation->setValue(SERVER_NAME, name);
+ CHECK_MINUS_ONE(check, "setValue name", MyTransaction);
+
+ check = MyOperation->setValue(SERVER_READS, (char*)&noOfRead);
+ CHECK_MINUS_ONE(check, "setValue reads", MyTransaction);
+
+ check = MyOperation->setValue(SERVER_INSERTS, (char*)&noOfInsert);
+ CHECK_MINUS_ONE(check, "setValue inserts", MyTransaction);
+
+ check = MyOperation->setValue(SERVER_DELETES, (char*)&noOfDelete);
+ CHECK_MINUS_ONE(check, "setValue deletes", MyTransaction);
+
+ return 0;
+}
+
+int userDbInsertSubscriber(UserHandle *uh,
+ SubscriberNumber number,
+ uint32 groupId,
+ SubscriberName name)
+{
+ int check;
+ uint32 activeSessions = 0;
+ Location l = 0;
+ ChangedBy changedBy; snprintf(changedBy, sizeof(changedBy), "ChangedBy");
+ ChangedTime changedTime; snprintf(changedTime, sizeof(changedTime), "ChangedTime");
+
+ NdbConnection * MyTransaction = 0;
+ if(uh->pCurrTrans != 0){
+ MyTransaction = uh->pCurrTrans;
+ } else {
+ uh->pCurrTrans = MyTransaction = uh->pNDB->startTransaction();
+ }
+ if (MyTransaction == NULL)
+ error_handler("startTranscation", uh->pNDB->getNdbError(), 0);
+
+ NdbOperation *MyOperation = MyTransaction->getNdbOperation(SUBSCRIBER_TABLE);
+ CHECK_NULL(MyOperation, "getNdbOperation", MyTransaction);
+
+ check = MyOperation->insertTuple();
+ CHECK_MINUS_ONE(check, "insertTuple", MyTransaction);
+
+ check = MyOperation->equal(SUBSCRIBER_NUMBER, number);
+ CHECK_MINUS_ONE(check, "equal", MyTransaction);
+
+ check = MyOperation->setValue(SUBSCRIBER_NAME, name);
+ CHECK_MINUS_ONE(check, "setValue name", MyTransaction);
+
+ check = MyOperation->setValue(SUBSCRIBER_GROUP, (char*)&groupId);
+ CHECK_MINUS_ONE(check, "setValue group", MyTransaction);
+
+ check = MyOperation->setValue(SUBSCRIBER_LOCATION, (char*)&l);
+ CHECK_MINUS_ONE(check, "setValue location", MyTransaction);
+
+ check = MyOperation->setValue(SUBSCRIBER_SESSIONS, (char*)&activeSessions);
+ CHECK_MINUS_ONE(check, "setValue sessions", MyTransaction);
+
+ check = MyOperation->setValue(SUBSCRIBER_CHANGED_BY, changedBy);
+ CHECK_MINUS_ONE(check, "setValue changedBy", MyTransaction);
+
+ check = MyOperation->setValue(SUBSCRIBER_CHANGED_TIME, changedTime);
+ CHECK_MINUS_ONE(check, "setValue changedTime", MyTransaction);
+
+ return 0;
+}
+
+int userDbInsertGroup(UserHandle *uh,
+ GroupId groupId,
+ GroupName name,
+ Permission allowRead,
+ Permission allowInsert,
+ Permission allowDelete)
+{
+ int check;
+
+ NdbConnection * MyTransaction = 0;
+ if(uh->pCurrTrans != 0){
+ MyTransaction = uh->pCurrTrans;
+ } else {
+ uh->pCurrTrans = MyTransaction = uh->pNDB->startTransaction();
+ }
+ if (MyTransaction == NULL)
+ error_handler("startTranscation", uh->pNDB->getNdbError(), 0);
+
+ NdbOperation *MyOperation = MyTransaction->getNdbOperation(GROUP_TABLE);
+ CHECK_NULL(MyOperation, "getNdbOperation", MyTransaction);
+
+ check = MyOperation->insertTuple();
+ CHECK_MINUS_ONE(check, "insertTuple", MyTransaction);
+
+ check = MyOperation->equal(GROUP_ID, (char*)&groupId);
+ CHECK_MINUS_ONE(check, "equal", MyTransaction);
+
+ check = MyOperation->setValue(GROUP_NAME, name);
+ CHECK_MINUS_ONE(check, "setValue name", MyTransaction);
+
+ check = MyOperation->setValue(GROUP_ALLOW_READ, (char*)&allowRead);
+ CHECK_MINUS_ONE(check, "setValue allowRead", MyTransaction);
+
+ check = MyOperation->setValue(GROUP_ALLOW_INSERT, (char*)&allowInsert);
+ CHECK_MINUS_ONE(check, "setValue allowInsert", MyTransaction);
+
+ check = MyOperation->setValue(GROUP_ALLOW_DELETE, (char*)&allowDelete);
+ CHECK_MINUS_ONE(check, "setValue allowDelete", MyTransaction);
+
+ return 0;
+}
+
diff --git a/ndb/test/ndbapi/bench/userInterface.h b/ndb/test/ndbapi/bench/userInterface.h
new file mode 100644
index 00000000000..bad61fcf171
--- /dev/null
+++ b/ndb/test/ndbapi/bench/userInterface.h
@@ -0,0 +1,151 @@
+/* Copyright (C) 2003 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#ifndef DBINTERFACE_H
+#define DBINTERFACE_H
+
+/***************************************************************/
+/* I N C L U D E D F I L E S */
+/***************************************************************/
+
+#include "testDefinitions.h"
+#include "testData.h"
+
+/***************************************************************
+* M A C R O S *
+***************************************************************/
+
+/***************************************************************/
+/* C O N S T A N T S */
+/***************************************************************/
+
+/*-----------------------*/
+/* Default Database Name */
+/*-----------------------*/
+#define DEFAULTDB "TestDbClient"
+
+/***************************************************************
+* D A T A S T R U C T U R E S *
+***************************************************************/
+
+/***************************************************************
+* P U B L I C F U N C T I O N S *
+***************************************************************/
+
+typedef struct Ndb Ndb;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ extern void showTime();
+ extern double userGetTime(void);
+ extern Ndb *asyncDbConnect(int parallellism);
+ extern void asyncDbDisconnect(Ndb* pNDB);
+
+ extern void start_T1(Ndb * uh, ThreadData * data, int async);
+ extern void start_T2(Ndb * uh, ThreadData * data, int async);
+ extern void start_T3(Ndb * uh, ThreadData * data, int async);
+ extern void start_T4(Ndb * uh, ThreadData * data, int async);
+ extern void start_T5(Ndb * uh, ThreadData * data, int async);
+
+ extern void complete_T1(ThreadData * data);
+ extern void complete_T2(ThreadData * data);
+ extern void complete_T3(ThreadData * data);
+ extern void complete_T4(ThreadData * data);
+ extern void complete_T5(ThreadData * data);
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+
+/***************************************************************/
+/* I N C L U D E D F I L E S */
+/***************************************************************/
+
+#include "testDefinitions.h"
+
+/***************************************************************
+* M A C R O S *
+***************************************************************/
+
+/***************************************************************/
+/* C O N S T A N T S */
+/***************************************************************/
+
+/*-----------------------*/
+/* Default Database Name */
+/*-----------------------*/
+#define DEFAULTDB "TestDbClient"
+
+/***************************************************************
+* D A T A S T R U C T U R E S *
+***************************************************************/
+
+typedef struct {
+ struct Ndb_cluster_connection* pNCC;
+ struct Ndb * pNDB;
+ struct NdbTransaction * pCurrTrans;
+} UserHandle;
+
+/***************************************************************
+* P U B L I C F U N C T I O N S *
+***************************************************************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern double userGetTimeSync(void);
+
+extern void userCheckpoint(UserHandle *uh);
+
+extern UserHandle *userDbConnect(uint32 createDb, char *dbName);
+extern void userDbDisconnect(UserHandle *uh);
+
+extern int userDbInsertServer(UserHandle *uh,
+ ServerId serverId,
+ SubscriberSuffix suffix,
+ ServerName name);
+
+extern int userDbInsertSubscriber(UserHandle *uh,
+ SubscriberNumber number,
+ uint32 groupId,
+ SubscriberName name);
+
+extern int userDbInsertGroup(UserHandle *uh,
+ GroupId groupId,
+ GroupName name,
+ Permission allowRead,
+ Permission allowInsert,
+ Permission allowDelete);
+
+ extern int userDbCommit(UserHandle *uh);
+ extern int userDbRollback(UserHandle *uh);
+
+#ifdef __cplusplus
+}
+#endif
+
+/***************************************************************
+* E X T E R N A L D A T A *
+***************************************************************/
+
+#endif /* DBINTERFACE_H */
+
diff --git a/ndb/test/run-test/daily-basic-tests.txt b/ndb/test/run-test/daily-basic-tests.txt
index b666f27d05f..d5b5bbb5309 100644
--- a/ndb/test/run-test/daily-basic-tests.txt
+++ b/ndb/test/run-test/daily-basic-tests.txt
@@ -1,4 +1,4 @@
-max-time: 25000
+max-time: 3600
cmd: atrt-mysql-test-run
args: --force
diff --git a/ndb/test/run-test/daily-devel-tests.txt b/ndb/test/run-test/daily-devel-tests.txt
index 5c9b36fb836..2cdd39ffa4c 100644
--- a/ndb/test/run-test/daily-devel-tests.txt
+++ b/ndb/test/run-test/daily-devel-tests.txt
@@ -204,3 +204,32 @@ max-time: 2500
cmd: test_event
args: -n BasicEventOperation T1 T6
+max-time: 300
+cmd: DbCreate
+args:
+
+max-time: 180
+cmd: DbAsyncGenerator
+args: -time 60 -p 1
+type: bench
+
+max-time: 180
+cmd: DbAsyncGenerator
+args: -time 60 -p 25
+type: bench
+
+max-time: 180
+cmd: DbAsyncGenerator
+args: -time 60 -p 100
+type: bench
+
+max-time: 180
+cmd: DbAsyncGenerator
+args: -time 60 -p 200
+type: bench
+
+max-time: 180
+cmd: DbAsyncGenerator
+args: -time 60 -p 1 -proc 25
+type: bench
+
diff --git a/ndb/test/run-test/example.conf b/ndb/test/run-test/example.conf
new file mode 100644
index 00000000000..1e152da332d
--- /dev/null
+++ b/ndb/test/run-test/example.conf
@@ -0,0 +1,10 @@
+target=pc-linux-i686
+base_dir=/ndb
+src_clone_base=mysqldev@bk-internal.mysql.com:/home/bk/mysql
+run_dir=/space/autotest
+build_dir=/ndb
+hosts="ndb01 ndb02 ndb03 ndb04 ndb05 ndb06 ndb07 ndb08 ndb09 ndb10 ndb11 ndb12"
+result_host="ndb.mysql.com"
+result_path="public_html"
+configure='CC=gcc CXX=gcc CFLAGS="-Wall -pedantic -Wno-long-long" CXXFLAGS="-Wall -pedantic -Wno-long-long" ./configure --with-ndbcluster --with-ndb-test --with-ndbcc-flags="-g -DERROR_INSERT"'
+
diff --git a/ndb/test/run-test/main.cpp b/ndb/test/run-test/main.cpp
index fb6754dae7a..02c2cc862a3 100644
--- a/ndb/test/run-test/main.cpp
+++ b/ndb/test/run-test/main.cpp
@@ -219,7 +219,7 @@ main(int argc, const char ** argv){
fflush(g_report_file);
}
- if(g_mode_bench || (g_mode_regression && result)){
+ if(test_case.m_report || g_mode_bench || (g_mode_regression && result)){
BaseString tmp;
tmp.assfmt("result.%d", test_no);
if(rename("result", tmp.c_str()) != 0){
@@ -228,7 +228,7 @@ main(int argc, const char ** argv){
goto end;
}
}
-
+
if(g_mode_interactive && result){
g_logger.info
("Encountered failed test in interactive mode - terminating");
@@ -908,6 +908,11 @@ read_test_case(FILE * file, atrt_testcase& tc, int& line){
tc.m_max_time = 60000;
else
tc.m_max_time = atoi(mt);
+
+ if(p.get("type", &mt) && strcmp(mt, "bench") == 0)
+ tc.m_report= true;
+ else
+ tc.m_report= false;
return true;
}
diff --git a/ndb/test/run-test/make-html-reports.sh b/ndb/test/run-test/make-html-reports.sh
index 89f13a4b62a..67395ceba47 100755
--- a/ndb/test/run-test/make-html-reports.sh
+++ b/ndb/test/run-test/make-html-reports.sh
@@ -154,9 +154,12 @@ do
ts=`time_spec $time`
res_txt=""
case $res in
- 0) pass; res_txt="PASSED"; res_dir="&nbsp;";;
+ 0) pass; res_txt="PASSED";;
*) fail; res_txt="FAILED";;
esac
+
+ if [ ! -d "$src_dir/result.$no" ]; then res_dir="&nbsp;"; fi
+
total=`expr $total + $time`
(
diff --git a/ndb/test/run-test/ndb-autotest.sh b/ndb/test/run-test/ndb-autotest.sh
new file mode 100755
index 00000000000..039f1bf914e
--- /dev/null
+++ b/ndb/test/run-test/ndb-autotest.sh
@@ -0,0 +1,226 @@
+#!/bin/sh
+
+save_args=$*
+VERSION="ndb-autotest.sh version 1.0"
+
+DATE=`date '+%Y-%m-%d'`
+export DATE
+
+set -e
+ulimit -Sc unlimited
+
+echo "`date` starting: $*"
+
+RSYNC_RSH=ssh
+export RSYNC_RSH
+
+do_clone=yes
+build=yes
+deploy=yes
+
+clone=5.0-ndb
+RUN="daily-basic daily-devel"
+conf=autotest.conf
+
+while [ "$1" ]
+do
+ case "$1" in
+ --no-clone) do_clone="";;
+ --no-build) build="";;
+ --no-deploy) deploy="";;
+ --clone=*) clone=`echo $1 | sed s/--clone=//`;;
+ --conf=*) conf=`echo $1 | sed s/--conf=//`;;
+ --version) echo $VERSION; exit;;
+ *) RUN=$*;;
+ esac
+ shift
+done
+
+if [ -f $conf ]
+then
+ . $conf
+else
+ echo "Can't find config file: $conf"
+ exit
+fi
+
+env
+
+LOCK=$HOME/.autotest-lock
+src_clone=$src_clone_base-$clone
+
+if [ -f $LOCK ]
+then
+ echo "Lock file exists: $LOCK"
+ exit 1
+fi
+
+echo "$DATE $RUN" > $LOCK
+trap "rm -f $LOCK" ERR
+
+dst_place=${build_dir}/clone-mysql-$clone-$DATE
+
+if [ "$do_clone" ]
+then
+ rm -rf $dst_place
+ bk clone $src_clone $dst_place
+fi
+
+if [ "$build" ]
+then
+ cd $dst_place
+ rm -rf $run_dir/*
+ aclocal; autoheader; autoconf; automake
+ (cd innobase; aclocal; autoheader; autoconf; automake)
+ (cd bdb/dist; sh s_all)
+ eval $configure --prefix=$run_dir
+ make
+ make install
+fi
+
+###
+# check script version
+#
+script=$run_dir/mysql-test/ndb/ndb-autotest.sh
+if [ -x $script ]
+then
+ $script --version > /tmp/version.$$
+else
+ echo $VERSION > /tmp/version.$$
+fi
+match=`grep -c "$VERSION" /tmp/version.$$`
+rm -f /tmp/version.$$
+if [ $match -eq 0 ]
+then
+ echo "Incorrect script version...restarting"
+ cp $run_dir/mysql-test/ndb/ndb-autotest.sh /tmp/at.$$.sh
+ rm -rf $run_dir $dst_place
+ sh /tmp/at.$$.sh $save_args
+ exit
+fi
+
+# Check that all interesting files are present
+test_dir=$run_dir/mysql-test/ndb
+atrt=$test_dir/atrt
+html=$test_dir/make-html-reports.sh
+PATH=$test_dir:$PATH
+export PATH
+
+filter(){
+ neg=$1
+ shift
+ while [ $# -gt 0 ]
+ do
+ if [ `grep -c $1 $neg` -eq 0 ] ; then echo $1; fi
+ shift
+ done
+}
+
+###
+# check ndb_cpcc fail hosts
+#
+ndb_cpcc $hosts | awk '{ if($1=="Failed"){ print;}}' > /tmp/failed.$DATE
+filter /tmp/failed.$DATE $hosts > /tmp/hosts.$DATE
+hosts=`cat /tmp/hosts.$DATE`
+
+if [ "$deploy" ]
+then
+ (cd / && tar cfz /tmp/build.$DATE.tgz $run_dir )
+ for i in $hosts
+ do
+ ok=0
+ scp /tmp/build.$DATE.tgz $i:/tmp/build.$DATE.$$.tgz && \
+ ssh $i "rm -rf /space/autotest/*" && \
+ ssh $i "cd / && tar xfz /tmp/build.$DATE.$$.tgz" && \
+ ssh $i "rm /tmp/build.$DATE.$$.tgz" && ok=1
+ if [ $ok -eq 0 ]
+ then
+ echo "$i failed during scp/ssh, excluding"
+ echo $i >> /tmp/failed.$DATE
+ fi
+ done
+fi
+rm -f /tmp/build.$DATE.tgz
+
+###
+# handle scp failed hosts
+#
+filter /tmp/failed.$DATE $hosts > /tmp/hosts.$DATE
+hosts=`cat /tmp/hosts.$DATE`
+cat /tmp/failed.$DATE > /tmp/filter_hosts.$$
+
+###
+# functions for running atrt
+#
+choose(){
+ SRC=$1
+ TMP1=/tmp/choose.$$
+ TMP2=/tmp/choose.$$.$$
+ shift
+
+ cp $SRC $TMP1
+ i=1
+ while [ $# -gt 0 ]
+ do
+ sed -e s,"CHOOSE_host$i",$1,g < $TMP1 > $TMP2
+ mv $TMP2 $TMP1
+ shift
+ i=`expr $i + 1`
+ done
+ cat $TMP1
+ rm -f $TMP1
+}
+start(){
+ rm -rf report.txt result* log.txt
+ $atrt -v -v -r -R --log-file=log.txt --testcase-file=$test_dir/$2-tests.txt &
+ pid=$!
+ echo $pid > run.pid
+ wait $pid
+ rm run.pid
+ [ -f log.txt ] && mv log.txt $3
+ [ -f report.txt ] && mv report.txt $3
+ [ "`find . -name 'result*'`" ] && mv result* $3
+ cd $3
+ sh $html . $1 $DATE
+ cd ../..
+ tar cvz /tmp/res.$$.tgz `basename $3`/$DATE
+ scp /tmp/res.$$.tgz $result_host:$result_path
+ ssh $result_host "cd $result_path && tar xfz res.$$.tgz && rm -f res.$$.tgz"
+ rm -f /tmp/res.$$.tgz
+}
+
+p=`pwd`
+for dir in $RUN
+do
+ echo "Fixing hosts for $dir"
+
+ run_dir=$base_dir/run-$dir-mysql-$clone-$target
+ res_dir=$base_dir/result-$dir-mysql-$clone-$target/$DATE
+
+ mkdir -p $res_dir
+ rm -rf $res_dir/*
+
+ count=`grep -c "COMPUTER" $run_dir/1.ndb_mgmd/initconfig.template`
+ avail_hosts=`filter /tmp/filter_hosts.$$ $hosts`
+ avail=`echo $avail_hosts | wc -w`
+ if [ $count -gt $avail ]
+ then
+ echo "Not enough hosts"
+ echo "Needs: $count available: $avail ($avail_hosts)"
+ break;
+ fi
+
+ run_hosts=`echo $avail_hosts| awk '{for(i=1;i<='$count';i++)print $i;}'`
+ choose $run_dir/d.template $run_hosts > $run_dir/d.txt
+ choose $run_dir/1.ndb_mgmd/initconfig.template $run_hosts > $run_dir/1.ndb_mgmd/config.ini
+ echo $run_hosts >> /tmp/filter_hosts.$$
+
+ cd $run_dir
+ start $dir-mysql-$clone-$target $dir $res_dir &
+done
+cd $p
+rm /tmp/filter_hosts.$$
+
+wait
+
+rm -f $LOCK
diff --git a/ndb/test/run-test/run-test.hpp b/ndb/test/run-test/run-test.hpp
index 8d00a7b6a55..ff7f916d4ef 100644
--- a/ndb/test/run-test/run-test.hpp
+++ b/ndb/test/run-test/run-test.hpp
@@ -68,6 +68,7 @@ struct atrt_config {
};
struct atrt_testcase {
+ bool m_report;
time_t m_max_time;
BaseString m_command;
BaseString m_args;
diff --git a/scripts/make_binary_distribution.sh b/scripts/make_binary_distribution.sh
index 2afb091da3e..0e28d27ee43 100644
--- a/scripts/make_binary_distribution.sh
+++ b/scripts/make_binary_distribution.sh
@@ -285,7 +285,7 @@ if [ x$NDBCLUSTER = x1 ]; then
$CP $BASE/ndb-stage@bindir@/* $BASE/bin/.
$CP $BASE/ndb-stage@libexecdir@/* $BASE/bin/.
$CP $BASE/ndb-stage@pkglibdir@/* $BASE/lib/.
- $CP -r $BASE/ndb-stage@pkgincludedir@/ndb $BASE/lib/.
+ $CP -r $BASE/ndb-stage@pkgincludedir@/ndb $BASE/include
$CP -r $BASE/ndb-stage@prefix@/mysql-test/ndb $BASE/mysql-test/. || exit 1
rm -rf $BASE/ndb-stage
fi
diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc
index fd275b19f77..d2607616a55 100644
--- a/sql/ha_innodb.cc
+++ b/sql/ha_innodb.cc
@@ -336,6 +336,11 @@ innobase_release_temporary_latches(
/*===============================*/
THD *thd)
{
+ if (!innodb_inited) {
+
+ return;
+ }
+
trx_t *trx= (trx_t*) thd->ha_data[innobase_hton.slot];
if (trx)
innobase_release_stat_resources(trx);
@@ -1693,7 +1698,7 @@ innobase_rollback_to_savepoint(
innobase_release_stat_resources(trx);
/* TODO: use provided savepoint data area to store savepoint data */
- char name[16]; sprintf(name, "s_%08lx", savepoint);
+ char name[16]; sprintf(name, "s_%08lx", (ulong) savepoint);
error = trx_rollback_to_savepoint_for_mysql(trx, name,
&mysql_binlog_cache_pos);
DBUG_RETURN(convert_error_code_to_mysql(error, NULL));
@@ -1719,7 +1724,7 @@ innobase_release_savepoint(
trx = check_trx_exists(thd);
/* TODO: use provided savepoint data area to store savepoint data */
- char name[16]; sprintf(name, "s_%08lx", savepoint);
+ char name[16]; sprintf(name, "s_%08lx", (ulong) savepoint);
error = trx_release_savepoint_for_mysql(trx, name);
DBUG_RETURN(convert_error_code_to_mysql(error, NULL));
@@ -1758,7 +1763,7 @@ innobase_savepoint(
DBUG_ASSERT(trx->active_trans);
/* TODO: use provided savepoint data area to store savepoint data */
- char name[16]; sprintf(name, "s_%08lx", savepoint);
+ char name[16]; sprintf(name, "s_%08lx", (ulong) savepoint);
error = trx_savepoint_for_mysql(trx, name, (ib_longlong)0);
DBUG_RETURN(convert_error_code_to_mysql(error, NULL));
diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc
index 35affc6b1ad..12e2e3672cc 100644
--- a/sql/ha_ndbcluster.cc
+++ b/sql/ha_ndbcluster.cc
@@ -3400,7 +3400,12 @@ int ndbcluster_commit(THD *thd, bool all)
ndbcluster_print_error(res, error_op);
}
ndb->closeTransaction(trans);
- thd_ndb->all= thd_ndb->stmt= NULL;
+
+ if(all)
+ thd_ndb->all= NULL;
+ else
+ thd_ndb->stmt= NULL;
+
DBUG_RETURN(res);
}
@@ -3432,7 +3437,12 @@ int ndbcluster_rollback(THD *thd, bool all)
ndbcluster_print_error(res, error_op);
}
ndb->closeTransaction(trans);
- thd_ndb->all= thd_ndb->stmt= NULL;
+
+ if(all)
+ thd_ndb->all= NULL;
+ else
+ thd_ndb->stmt= NULL;
+
DBUG_RETURN(res);
}
@@ -4606,7 +4616,11 @@ ndbcluster_init()
(opt_ndb_optimized_node_selection);
// Create a Ndb object to open the connection to NDB
- g_ndb= new Ndb(g_ndb_cluster_connection, "sys");
+ if ( (g_ndb= new Ndb(g_ndb_cluster_connection, "sys")) == 0 )
+ {
+ DBUG_PRINT("error", ("failed to create global ndb object"));
+ goto ndbcluster_init_error;
+ }
g_ndb->getDictionary()->set_local_table_data_size(sizeof(Ndb_table_local_info));
if (g_ndb->init() != 0)
{
@@ -4659,6 +4673,10 @@ ndbcluster_init()
if (pthread_create(&tmp, &connection_attrib, ndb_util_thread_func, 0))
{
DBUG_PRINT("error", ("Could not create ndb utility thread"));
+ hash_free(&ndbcluster_open_tables);
+ pthread_mutex_destroy(&ndbcluster_mutex);
+ pthread_mutex_destroy(&LOCK_ndb_util_thread);
+ pthread_cond_destroy(&COND_ndb_util_thread);
goto ndbcluster_init_error;
}
@@ -4666,7 +4684,12 @@ ndbcluster_init()
DBUG_RETURN(&ndbcluster_hton);
ndbcluster_init_error:
- ndbcluster_end();
+ if(g_ndb)
+ delete g_ndb;
+ g_ndb= NULL;
+ if (g_ndb_cluster_connection)
+ delete g_ndb_cluster_connection;
+ g_ndb_cluster_connection= NULL;
DBUG_RETURN(NULL);
}
@@ -4681,6 +4704,9 @@ bool ndbcluster_end()
{
DBUG_ENTER("ndbcluster_end");
+ if (!ndbcluster_inited)
+ DBUG_RETURN(0);
+
// Kill ndb utility thread
(void) pthread_mutex_lock(&LOCK_ndb_util_thread);
DBUG_PRINT("exit",("killing ndb util thread: %lx", ndb_util_thread));
@@ -4693,8 +4719,7 @@ bool ndbcluster_end()
if (g_ndb_cluster_connection)
delete g_ndb_cluster_connection;
g_ndb_cluster_connection= NULL;
- if (!ndbcluster_inited)
- DBUG_RETURN(0);
+
hash_free(&ndbcluster_open_tables);
pthread_mutex_destroy(&ndbcluster_mutex);
pthread_mutex_destroy(&LOCK_ndb_util_thread);
diff --git a/sql/handler.cc b/sql/handler.cc
index 3ccea502a50..b733ec6c267 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -476,6 +476,9 @@ void ha_close_connection(THD* thd)
void trans_register_ha(THD *thd, bool all, handlerton *ht_arg)
{
THD_TRANS *trans;
+ DBUG_ENTER("trans_register_ha");
+ DBUG_PRINT("enter",("%s", all ? "all" : "stmt"));
+
if (all)
{
trans= &thd->transaction.all;
@@ -496,6 +499,7 @@ void trans_register_ha(THD *thd, bool all, handlerton *ht_arg)
trans->no_2pc|=(ht_arg->prepare==0);
if (thd->transaction.xid.is_null())
thd->transaction.xid.set(thd->query_id);
+ DBUG_VOID_RETURN;
}
/*
@@ -514,7 +518,7 @@ int ha_prepare(THD *thd)
if (trans->nht)
{
if (trans->no_2pc)
- return -1;
+ DBUG_RETURN(-1);
for (; *ht; ht++)
{
int err;
@@ -860,7 +864,8 @@ err:
int ha_release_temporary_latches(THD *thd)
{
#ifdef HAVE_INNOBASE_DB
- innobase_release_temporary_latches(thd);
+ if (opt_innodb)
+ innobase_release_temporary_latches(thd);
#endif
return 0;
}
@@ -1022,15 +1027,24 @@ bool ha_flush_logs()
The .frm file will be deleted only if we return 0 or ENOENT
*/
-int ha_delete_table(enum db_type table_type, const char *path)
+int ha_delete_table(THD *thd, enum db_type table_type, const char *path,
+ const char *alias, bool generate_warning)
{
handler *file;
char tmp_path[FN_REFLEN];
+ int error;
+ TABLE dummy_table;
+ TABLE_SHARE dummy_share;
+ DBUG_ENTER("ha_delete_table");
+
+ bzero((char*) &dummy_table, sizeof(dummy_table));
+ bzero((char*) &dummy_share, sizeof(dummy_share));
+ dummy_table.s= &dummy_share;
/* DB_TYPE_UNKNOWN is used in ALTER TABLE when renaming only .frm files */
if (table_type == DB_TYPE_UNKNOWN ||
- ! (file=get_new_handler((TABLE*) 0, table_type)))
- return ENOENT;
+ ! (file=get_new_handler(&dummy_table, table_type)))
+ DBUG_RETURN(ENOENT);
if (lower_case_table_names == 2 && !(file->table_flags() & HA_FILE_BASED))
{
@@ -1039,9 +1053,45 @@ int ha_delete_table(enum db_type table_type, const char *path)
my_casedn_str(files_charset_info, tmp_path);
path= tmp_path;
}
- int error=file->delete_table(path);
+ if ((error= file->delete_table(path)) && generate_warning)
+ {
+ /*
+ Because file->print_error() use my_error() to generate the error message
+ we must store the error state in thd, reset it and restore it to
+ be able to get hold of the error message.
+ (We should in the future either rewrite handler::print_error() or make
+ a nice method of this.
+ */
+ bool query_error= thd->query_error;
+ sp_rcontext *spcont= thd->spcont;
+ SELECT_LEX *current_select= thd->lex->current_select;
+ char buff[sizeof(thd->net.last_error)];
+ char new_error[sizeof(thd->net.last_error)];
+ int last_errno= thd->net.last_errno;
+
+ strmake(buff, thd->net.last_error, sizeof(buff)-1);
+ thd->query_error= 0;
+ thd->spcont= 0;
+ thd->lex->current_select= 0;
+ thd->net.last_error[0]= 0;
+
+ /* Fill up strucutures that print_error may need */
+ dummy_table.s->path= path;
+ dummy_table.alias= alias;
+
+ file->print_error(error, 0);
+ strmake(new_error, thd->net.last_error, sizeof(buff)-1);
+
+ /* restore thd */
+ thd->query_error= query_error;
+ thd->spcont= spcont;
+ thd->lex->current_select= current_select;
+ thd->net.last_errno= last_errno;
+ strmake(thd->net.last_error, buff, sizeof(buff)-1);
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, error, new_error);
+ }
delete file;
- return error;
+ DBUG_RETURN(error);
}
/****************************************************************************
@@ -1315,7 +1365,16 @@ ulonglong handler::get_auto_increment()
return nr;
}
- /* Print error that we got from handler function */
+
+/*
+ Print error that we got from handler function
+
+ NOTE:
+ In case of delete table it's only safe to use the following parts of
+ the 'table' structure:
+ table->s->path
+ table->alias
+*/
void handler::print_error(int error, myf errflag)
{
@@ -1494,16 +1553,38 @@ uint handler::get_dup_key(int error)
}
+/*
+ Delete all files with extension from bas_ext()
+
+ SYNOPSIS
+ delete_table()
+ name Base name of table
+
+ NOTES
+ We assume that the handler may return more extensions than
+ was actually used for the file.
+
+ RETURN
+ 0 If we successfully deleted at least one file from base_ext and
+ didn't get any other errors than ENOENT
+ # Error from delete_file()
+*/
+
int handler::delete_table(const char *name)
{
- int error=0;
+ int error= 0;
+ int enoent_or_zero= ENOENT; // Error if no file was deleted
+
for (const char **ext=bas_ext(); *ext ; ext++)
{
if (delete_file(name,*ext,2))
{
- if ((error=errno) != ENOENT)
+ if ((error= my_errno) != ENOENT)
break;
}
+ else
+ enoent_or_zero= 0; // No error for ENOENT
+ error= enoent_or_zero;
}
return error;
}
diff --git a/sql/handler.h b/sql/handler.h
index 5968b9a5e1d..3a1862cad07 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -97,7 +97,7 @@
Note: the following includes binlog and closing 0.
so: innodb+bdb+ndb+binlog+0
*/
-#define MAX_HA 5
+#define MAX_HA 6
/*
Bits in index_ddl_flags(KEY *wanted_index)
@@ -217,11 +217,13 @@ struct xid_t {
bool eq(long g, long b, const char *d)
{ return g == gtrid_length && b == bqual_length && !memcmp(d, data, g+b); }
void set(LEX_STRING *l) { set(l->length, 0, l->str); }
- void set(ulonglong l)
+ void set(ulonglong xid)
{
+ my_xid tmp;
set(MYSQL_XID_PREFIX_LEN, 0, MYSQL_XID_PREFIX);
- *(ulong*)(data+MYSQL_XID_PREFIX_LEN)=server_id;
- *(my_xid*)(data+MYSQL_XID_OFFSET)=l;
+ memcpy(data+MYSQL_XID_PREFIX_LEN, &server_id, sizeof(server_id));
+ tmp= xid;
+ memcpy(data+MYSQL_XID_OFFSET, &tmp, sizeof(tmp));
gtrid_length=MYSQL_XID_GTRID_LEN;
}
void set(long g, long b, const char *d)
@@ -235,7 +237,9 @@ struct xid_t {
void null() { formatID= -1; }
my_xid quick_get_my_xid()
{
- return *(my_xid*)(data+MYSQL_XID_OFFSET);
+ my_xid tmp;
+ memcpy(&tmp, data+MYSQL_XID_OFFSET, sizeof(tmp));
+ return tmp;
}
my_xid get_my_xid()
{
@@ -753,7 +757,8 @@ bool ha_flush_logs(void);
void ha_drop_database(char* path);
int ha_create_table(const char *name, HA_CREATE_INFO *create_info,
bool update_create_info);
-int ha_delete_table(enum db_type db_type, const char *path);
+int ha_delete_table(THD *thd, enum db_type db_type, const char *path,
+ const char *alias, bool generate_warning);
/* discovery */
int ha_create_table_from_engine(THD* thd, const char *db, const char *name,
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index 33cff192d06..9a4798b9dc9 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -656,7 +656,8 @@ my_decimal *Item_sum_sum_distinct::val_decimal(my_decimal *fake)
else
{
double real= val_real();
- double2my_decimal(E_DEC_FATAL_ERROR, real, dec_buffs + curr_dec_buff);
+ curr_dec_buff= 0;
+ double2my_decimal(E_DEC_FATAL_ERROR, real, dec_buffs);
}
return(dec_buffs + curr_dec_buff);
}
diff --git a/sql/log.cc b/sql/log.cc
index b048323aa76..6cb465f839c 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -129,16 +129,17 @@ static int binlog_rollback(THD *thd, bool all)
IO_CACHE *trans_log= (IO_CACHE*)thd->ha_data[binlog_hton.slot];
DBUG_ENTER("binlog_rollback");
/*
- first two conditions here are guaranteed - see trans_register_ha()
- call below. The third one must be true. If it is not, we're registering
+ First assert is guaranteed - see trans_register_ha() call below.
+ The second must be true. If it is not, we're registering
unnecessary, doing extra work. The cause should be found and eliminated
*/
- DBUG_ASSERT(all && mysql_bin_log.is_open() && my_b_tell(trans_log));
+ DBUG_ASSERT(all || !(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)));
+ DBUG_ASSERT(mysql_bin_log.is_open() && my_b_tell(trans_log));
/*
- Update the binary log with a BEGIN/ROLLBACK block if we have
- cached some queries and we updated some non-transactional
- table. Such cases should be rare (updating a
- non-transactional table inside a transaction...)
+ Update the binary log with a BEGIN/ROLLBACK block if we have
+ cached some queries and we updated some non-transactional
+ table. Such cases should be rare (updating a
+ non-transactional table inside a transaction...)
*/
if (unlikely(thd->options & OPTION_STATUS_NO_TRANS_UPDATE))
{
@@ -919,6 +920,13 @@ bool MYSQL_LOG::reset_logs(THD* thd)
*/
pthread_mutex_lock(&LOCK_log);
pthread_mutex_lock(&LOCK_index);
+ /*
+ The following mutex is needed to ensure that no threads call
+ 'delete thd' as we would then risk missing a 'rollback' from this
+ thread. If the transaction involved MyISAM tables, it should go
+ into binlog even on rollback.
+ */
+ (void) pthread_mutex_lock(&LOCK_thread_count);
/* Save variables so that we can reopen the log */
save_name=name;
@@ -952,6 +960,7 @@ bool MYSQL_LOG::reset_logs(THD* thd)
my_free((gptr) save_name, MYF(0));
err:
+ (void) pthread_mutex_unlock(&LOCK_thread_count);
pthread_mutex_unlock(&LOCK_index);
pthread_mutex_unlock(&LOCK_log);
DBUG_RETURN(error);
@@ -1399,7 +1408,7 @@ bool MYSQL_LOG::append(Log_event* ev)
pthread_mutex_unlock(&LOCK_index);
}
-err:
+err:
pthread_mutex_unlock(&LOCK_log);
signal_update(); // Safe as we don't call close
DBUG_RETURN(error);
@@ -1547,16 +1556,15 @@ inline bool sync_binlog(IO_CACHE *cache)
Write an event to the binary log
*/
-bool MYSQL_LOG::write(Log_event* event_info)
+bool MYSQL_LOG::write(Log_event *event_info)
{
- THD *thd=event_info->thd;
- bool error=1;
- bool should_rotate = 0;
- DBUG_ENTER("MYSQL_LOG::write(event)");
-
+ THD *thd= event_info->thd;
+ bool error= 1;
+ DBUG_ENTER("MYSQL_LOG::write(Log_event *)");
+
pthread_mutex_lock(&LOCK_log);
- /*
+ /*
In most cases this is only called if 'is_open()' is true; in fact this is
mostly called if is_open() *was* true a few instructions before, but it
could have changed since.
@@ -1566,7 +1574,7 @@ bool MYSQL_LOG::write(Log_event* event_info)
const char *local_db= event_info->get_db();
IO_CACHE *file= &log_file;
#ifdef HAVE_REPLICATION
- /*
+ /*
In the future we need to add to the following if tests like
"do the involved tables match (to be implemented)
binlog_[wild_]{do|ignore}_table?" (WL#1049)"
@@ -1600,7 +1608,8 @@ bool MYSQL_LOG::write(Log_event* event_info)
{
thd->ha_data[binlog_hton.slot]= trans_log= (IO_CACHE *)
my_malloc(sizeof(IO_CACHE), MYF(MY_ZEROFILL));
- if (!trans_log || open_cached_file(trans_log, mysql_tmpdir, LOG_PREFIX,
+ if (!trans_log || open_cached_file(trans_log, mysql_tmpdir,
+ LOG_PREFIX,
binlog_cache_size, MYF(MY_WME)))
{
my_free((gptr)trans_log, MYF(MY_ALLOW_ZERO_PTR));
@@ -1609,13 +1618,15 @@ bool MYSQL_LOG::write(Log_event* event_info)
}
trans_log->end_of_file= max_binlog_cache_size;
trans_register_ha(thd,
- thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN),
- &binlog_hton);
+ thd->options & (OPTION_NOT_AUTOCOMMIT |
+ OPTION_BEGIN),
+ &binlog_hton);
}
else if (!my_b_tell(trans_log))
trans_register_ha(thd,
- thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN),
- &binlog_hton);
+ thd->options & (OPTION_NOT_AUTOCOMMIT |
+ OPTION_BEGIN),
+ &binlog_hton);
file= trans_log;
}
else if (trans_log && my_b_tell(trans_log))
@@ -1630,8 +1641,8 @@ bool MYSQL_LOG::write(Log_event* event_info)
*/
/*
- 1. Write first log events which describe the 'run environment'
- of the SQL command
+ 1. Write first log events which describe the 'run environment'
+ of the SQL command
*/
if (thd)
@@ -1655,12 +1666,12 @@ bool MYSQL_LOG::write(Log_event* event_info)
{
char buf[200];
int written= my_snprintf(buf, sizeof(buf)-1,
- "SET ONE_SHOT CHARACTER_SET_CLIENT=%u,\
+ "SET ONE_SHOT CHARACTER_SET_CLIENT=%u,\
COLLATION_CONNECTION=%u,COLLATION_DATABASE=%u,COLLATION_SERVER=%u",
- (uint) thd->variables.character_set_client->number,
- (uint) thd->variables.collation_connection->number,
- (uint) thd->variables.collation_database->number,
- (uint) thd->variables.collation_server->number);
+ (uint) thd->variables.character_set_client->number,
+ (uint) thd->variables.collation_connection->number,
+ (uint) thd->variables.collation_database->number,
+ (uint) thd->variables.collation_server->number);
Query_log_event e(thd, buf, written, 0, FALSE);
if (e.write(file))
goto err;
@@ -1733,10 +1744,6 @@ COLLATION_CONNECTION=%u,COLLATION_DATABASE=%u,COLLATION_SERVER=%u",
{
if (flush_io_cache(file) || sync_binlog(file))
goto err;
-
- /* check automatic rotation; */
- DBUG_PRINT("info",("max_size: %lu",max_size));
- should_rotate= (my_b_tell(file) >= (my_off_t) max_size);
}
error=0;
@@ -1750,28 +1757,39 @@ err:
write_error=1;
}
if (file == &log_file)
- signal_update();
- if (should_rotate)
{
- pthread_mutex_lock(&LOCK_index);
- new_file(0); // inside mutex
- pthread_mutex_unlock(&LOCK_index);
+ signal_update();
+ rotate_and_purge(RP_LOCK_LOG_IS_ALREADY_LOCKED);
}
}
pthread_mutex_unlock(&LOCK_log);
-#ifdef HAVE_REPLICATION
- if (should_rotate && expire_logs_days)
- {
- long purge_time= time(0) - expire_logs_days*24*60*60;
- if (purge_time >= 0)
- error= purge_logs_before_date(purge_time);
- }
-#endif
DBUG_RETURN(error);
}
+void MYSQL_LOG::rotate_and_purge(uint flags)
+{
+ if (!prepared_xids && // see new_file() for the explanation
+ ((flags & RP_FORCE_ROTATE) ||
+ (my_b_tell(&log_file) >= (my_off_t) max_size)))
+ {
+ if (flags & RP_LOCK_LOG_IS_ALREADY_LOCKED)
+ pthread_mutex_lock(&LOCK_index);
+ new_file(!(flags & RP_LOCK_LOG_IS_ALREADY_LOCKED));
+ if (flags & RP_LOCK_LOG_IS_ALREADY_LOCKED)
+ pthread_mutex_unlock(&LOCK_index);
+#ifdef HAVE_REPLICATION
+ // QQ why do we need #ifdef here ???
+ if (expire_logs_days)
+ {
+ long purge_time= time(0) - expire_logs_days*24*60*60;
+ if (purge_time >= 0)
+ purge_logs_before_date(purge_time);
+ }
+#endif
+ }
+}
uint MYSQL_LOG::next_file_id()
{
@@ -1796,24 +1814,20 @@ uint MYSQL_LOG::next_file_id()
- The thing in the cache is always a complete transaction
- 'cache' needs to be reinitialized after this functions returns.
- TODO
- fix it to become atomic - either the complete cache is added to binlog
- or nothing (other storage engines rely on this, doing a ROLLBACK)
-
IMPLEMENTATION
- To support transaction over replication, we wrap the transaction
with BEGIN/COMMIT or BEGIN/ROLLBACK in the binary log.
- We want to write a BEGIN/ROLLBACK block when a non-transactional table was
- updated in a transaction which was rolled back. This is to ensure that the
- same updates are run on the slave.
+ We want to write a BEGIN/ROLLBACK block when a non-transactional table
+ was updated in a transaction which was rolled back. This is to ensure
+ that the same updates are run on the slave.
*/
bool MYSQL_LOG::write(THD *thd, IO_CACHE *cache)
{
- bool should_rotate= 0, error= 0;
+ bool error= 0;
VOID(pthread_mutex_lock(&LOCK_log));
- DBUG_ENTER("MYSQL_LOG::write(cache");
-
+ DBUG_ENTER("MYSQL_LOG::write(THD *, IO_CACHE *)");
+
if (likely(is_open())) // Should always be true
{
uint length;
@@ -1868,25 +1882,10 @@ bool MYSQL_LOG::write(THD *thd, IO_CACHE *cache)
}
signal_update();
DBUG_PRINT("info",("max_size: %lu",max_size));
- if (should_rotate= (my_b_tell(&log_file) >= (my_off_t) max_size))
- {
- pthread_mutex_lock(&LOCK_index);
- new_file(0); // inside mutex
- pthread_mutex_unlock(&LOCK_index);
- }
-
+ rotate_and_purge(RP_LOCK_LOG_IS_ALREADY_LOCKED);
}
VOID(pthread_mutex_unlock(&LOCK_log));
-#ifdef HAVE_REPLICATION
- if (should_rotate && expire_logs_days)
- {
- long purge_time= time(0) - expire_logs_days*24*60*60;
- if (purge_time >= 0)
- error= purge_logs_before_date(purge_time);
- }
-#endif
-
DBUG_RETURN(error);
err:
@@ -2474,15 +2473,13 @@ int TC_LOG_MMAP::open(const char *opt_name)
DBUG_ASSERT(TC_LOG_PAGE_SIZE % tc_log_page_size == 0);
fn_format(logname,opt_name,mysql_data_home,"",MY_UNPACK_FILENAME);
- fd= my_open(logname, O_RDWR, MYF(0));
- if (fd == -1)
+ if ((fd= my_open(logname, O_RDWR, MYF(0))) < 0)
{
if (my_errno != ENOENT)
goto err;
if (using_heuristic_recover())
return 1;
- fd= my_create(logname, O_RDWR, 0, MYF(MY_WME));
- if (fd == -1)
+ if ((fd= my_create(logname, O_RDWR, 0, MYF(MY_WME))) < 0)
goto err;
inited=1;
file_length= opt_tc_log_size;
@@ -2820,7 +2817,7 @@ int TC_LOG_MMAP::recover()
*/
if (data[sizeof(tc_log_magic)] != total_ha_2pc)
{
- sql_print_error("Recovery failed! You must have enabled "
+ sql_print_error("Recovery failed! You must enable "
"exactly %d storage engines that support "
"two-phase commit protocol",
data[sizeof(tc_log_magic)]);
@@ -2929,14 +2926,15 @@ int TC_LOG_BINLOG::open(const char *opt_name)
if (! fdle.is_valid())
goto err;
- for (error= 0; !error ;)
+ do
{
- strnmov(log_name, log_info.log_file_name, sizeof(log_name));
- if ((error= find_next_log(&log_info, 1)) != LOG_INFO_EOF)
- {
- sql_print_error("find_log_pos() failed (error: %d)", error);
- goto err;
- }
+ strmake(log_name, log_info.log_file_name, sizeof(log_name)-1);
+ } while (!(error= find_next_log(&log_info, 1)));
+
+ if (error != LOG_INFO_EOF)
+ {
+ sql_print_error("find_log_pos() failed (error: %d)", error);
+ goto err;
}
if ((file= open_binlog(&log, log_name, &errmsg)) < 0)
@@ -2992,6 +2990,7 @@ void TC_LOG_BINLOG::unlog(ulong cookie, my_xid xid)
{
if (thread_safe_dec_and_test(prepared_xids, &LOCK_prep_xids))
pthread_cond_signal(&COND_prep_xids);
+ rotate_and_purge(0); // in case ::write() was not able to rotate
}
int TC_LOG_BINLOG::recover(IO_CACHE *log, Format_description_log_event *fdle)
@@ -3001,11 +3000,11 @@ int TC_LOG_BINLOG::recover(IO_CACHE *log, Format_description_log_event *fdle)
MEM_ROOT mem_root;
if (! fdle->is_valid() ||
- hash_init(&xids, &my_charset_bin, tc_log_page_size/3, 0,
+ hash_init(&xids, &my_charset_bin, TC_LOG_PAGE_SIZE/3, 0,
sizeof(my_xid), 0, 0, MYF(0)))
goto err1;
- init_alloc_root(&mem_root, tc_log_page_size, tc_log_page_size);
+ init_alloc_root(&mem_root, TC_LOG_PAGE_SIZE, TC_LOG_PAGE_SIZE);
fdle->flags&= ~LOG_EVENT_BINLOG_IN_USE_F; // abort on the first error
diff --git a/sql/log_event.cc b/sql/log_event.cc
index 1cdb1652d17..7b030de6839 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -1452,7 +1452,7 @@ int Query_log_event::exec_event(struct st_relay_log_info* rli)
thd->variables.pseudo_thread_id= thread_id; // for temp tables
mysql_log.write(thd,COM_QUERY,"%s",thd->query);
DBUG_PRINT("query",("%s",thd->query));
-
+
if (ignored_error_code((expected_error= error_code)) ||
!check_expected_error(thd,rli,expected_error))
{
@@ -3099,12 +3099,14 @@ void Xid_log_event::pack_info(Protocol *protocol)
we don't care about actual values of xids as long as
identical numbers compare identically
*/
-Xid_log_event::Xid_log_event(const char* buf,
- const Format_description_log_event* description_event)
+
+Xid_log_event::
+Xid_log_event(const char* buf,
+ const Format_description_log_event *description_event)
:Log_event(buf, description_event)
{
buf+= description_event->common_header_len;
- xid=*((my_xid *)buf);
+ memcpy((char*) &xid, buf, sizeof(xid));
}
@@ -3137,6 +3139,7 @@ int Xid_log_event::exec_event(struct st_relay_log_info* rli)
{
rli->inc_event_relay_log_pos();
/* For a slave Xid_log_event is COMMIT */
+ mysql_log.write(thd,COM_QUERY,"COMMIT /* implicit, from Xid_log_event */");
return end_trans(thd, COMMIT);
}
#endif /* !MYSQL_CLIENT */
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 9559ed55b3c..180d9427c66 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -4646,7 +4646,7 @@ Disable with --skip-ndbcluster (will save memory).",
(gptr*) &opt_ndb_optimized_node_selection,
(gptr*) &opt_ndb_optimized_node_selection,
0, GET_BOOL, OPT_ARG, 1, 0, 0, 0, 0, 0},
- { "ndb_cache_check_time", OPT_NDB_CACHE_CHECK_TIME,
+ { "ndb-cache-check-time", OPT_NDB_CACHE_CHECK_TIME,
"A dedicated thread is created to update cached commit count value at the given interval.",
(gptr*) &opt_ndb_cache_check_time, (gptr*) &opt_ndb_cache_check_time, 0, GET_ULONG, REQUIRED_ARG,
0, 0, LONG_TIMEOUT, 0, 1, 0},
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index f2a8239fd4e..72e2204f1b4 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -504,6 +504,7 @@ sp_head::execute(THD *thd)
break;
DBUG_PRINT("execute", ("Instruction %u", ip));
ret= i->execute(thd, &ip);
+ thd->rollback_item_tree_changes();
if (i->free_list)
cleanup_items(i->free_list);
// Check if an exception has occurred and a handler has been found
@@ -1195,7 +1196,6 @@ sp_instr_stmt::exec_stmt(THD *thd, LEX *lex)
res= mysql_execute_command(thd);
lex->unit.cleanup();
- thd->rollback_item_tree_changes();
if (thd->lock || thd->open_tables || thd->derived_tables)
{
thd->proc_info="closing tables";
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index 2452c940d63..bed8bd160c8 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -204,20 +204,16 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables)
if (lower_case_table_names)
{
/*
- We make a temporary copy of the database, force it to lower case,
- and then copy it back over the original name. We can't just update
- the host.db pointer, because tmp_name is allocated on the stack.
+ convert db to lower case and give a warning if the db wasn't
+ already in lower case
*/
- (void)strmov(tmp_name, host.db);
- my_casedn_str(files_charset_info, tmp_name);
+ (void) strmov(tmp_name, host.db);
+ my_casedn_str(files_charset_info, host.db);
if (strcmp(host.db, tmp_name) != 0)
- {
sql_print_warning("'host' entry '%s|%s' had database in mixed "
"case that has been forced to lowercase because "
"lower_case_table_names is set.",
host.host.hostname, host.db);
- (void)strmov(host.db, tmp_name);
- }
}
host.access= get_access(table,2);
host.access= fix_rights_for_db(host.access);
@@ -432,19 +428,17 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables)
if (lower_case_table_names)
{
/*
- We make a temporary copy of the database, force it to lower case,
- and then copy it back over the original name. We can't just update
- the db.db pointer, because tmp_name is allocated on the stack.
+ convert db to lower case and give a warning if the db wasn't
+ already in lower case
*/
(void)strmov(tmp_name, db.db);
- my_casedn_str(files_charset_info, tmp_name);
+ my_casedn_str(files_charset_info, db.db);
if (strcmp(db.db, tmp_name) != 0)
{
sql_print_warning("'db' entry '%s %s@%s' had database in mixed "
"case that has been forced to lowercase because "
"lower_case_table_names is set.",
db.db, db.user, db.host.hostname, db.host.hostname);
- (void)strmov(db.db, tmp_name);
}
}
db.sort=get_sort(3,db.host.hostname,db.db,db.user);
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 8628e412d86..68a43f71e55 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -3592,23 +3592,20 @@ static void mysql_rm_tmp_tables(void)
*****************************************************************************/
/*
-** Invalidate any cache entries that are for some DB
-** We can't use hash_delete when looping hash_elements. We mark them first
-** and afterwards delete those marked unused.
+ Invalidate any cache entries that are for some DB
+
+ SYNOPSIS
+ remove_db_from_cache()
+ db Database name. This will be in lower case if
+ lower_case_table_name is set
+
+ NOTE:
+ We can't use hash_delete when looping hash_elements. We mark them first
+ and afterwards delete those marked unused.
*/
void remove_db_from_cache(const char *db)
{
- char name_buff[NAME_LEN+1];
- if (db && lower_case_table_names)
- {
- /*
- convert database to lower case for comparision.
- */
- strmake(name_buff, db, sizeof(name_buff)-1);
- my_casedn_str(files_charset_info, name_buff);
- db= name_buff;
- }
for (uint idx=0 ; idx < open_cache.records ; idx++)
{
TABLE *table=(TABLE*) hash_element(&open_cache,idx);
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 34019e73f96..e793f5776d7 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -83,14 +83,14 @@ class TC_LOG_DUMMY: public TC_LOG // use it to disable the logging
#ifdef HAVE_MMAP
class TC_LOG_MMAP: public TC_LOG
{
- private:
-
+ public: // only to keep Sun Forte on sol9x86 happy
typedef enum {
POOL, // page is in pool
ERROR, // last sync failed
DIRTY // new xids added since last sync
} PAGE_STATE;
+ private:
typedef struct st_page {
struct st_page *next; // page a linked in a fifo queue
my_xid *start, *end; // usable area of a page
@@ -174,6 +174,9 @@ typedef struct st_user_var_events
uint charset_number;
} BINLOG_USER_VAR_EVENT;
+#define RP_LOCK_LOG_IS_ALREADY_LOCKED 1
+#define RP_FORCE_ROTATE 2
+
class Log_event;
/*
@@ -300,7 +303,7 @@ public:
}
bool open_index_file(const char *index_file_name_arg,
const char *log_name);
- void new_file(bool need_lock= 1);
+ void new_file(bool need_lock);
bool write(THD *thd, enum enum_server_command command,
const char *format,...);
bool write(THD *thd, const char *query, uint query_length,
@@ -319,6 +322,7 @@ public:
void make_log_name(char* buf, const char* log_ident);
bool is_active(const char* log_file_name);
int update_log_index(LOG_INFO* linfo, bool need_update_threads);
+ void rotate_and_purge(uint flags);
int purge_logs(const char *to_log, bool included,
bool need_mutex, bool need_update_threads,
ulonglong *decrease_log_space);
diff --git a/sql/sql_db.cc b/sql/sql_db.cc
index 6b0f05406d8..c0b74d24d83 100644
--- a/sql/sql_db.cc
+++ b/sql/sql_db.cc
@@ -576,7 +576,8 @@ exit2:
mysql_rm_db()
thd Thread handle
db Database name in the case given by user
- It's already validated when we come here
+ It's already validated and set to lower case
+ (if needed) when we come here
if_exists Don't give error if database doesn't exists
silent Don't generate errors
@@ -589,7 +590,7 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
{
long deleted=0;
int error= 0;
- char path[FN_REFLEN+16], tmp_db[NAME_LEN+1];
+ char path[FN_REFLEN+16];
MY_DIR *dirp;
uint length;
DBUG_ENTER("mysql_rm_db");
@@ -636,13 +637,6 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
error = 0;
}
}
- if (lower_case_table_names)
- {
- /* Convert database to lower case */
- strmov(tmp_db, db);
- my_casedn_str(files_charset_info, tmp_db);
- db= tmp_db;
- }
if (!silent && deleted>=0)
{
const char *query;
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index fbcecdb0411..a03cdfb41ed 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -1889,8 +1889,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
break;
}
mysql_log.write(thd,command,db);
- mysql_rm_db(thd, (lower_case_table_names == 2 ? alias : db),
- 0, 0);
+ mysql_rm_db(thd, db, 0, 0);
break;
}
#ifndef EMBEDDED_LIBRARY
@@ -3261,8 +3260,6 @@ unsent_create_error:
/* revert changes for SP */
lex->select_lex.table_list.first= (byte*) first_table;
}
- else
- res= TRUE;
if (first_table->view && !first_table->contain_auto_increment)
thd->last_insert_id= 0; // do not show last insert ID if VIEW have not it
@@ -3347,7 +3344,7 @@ unsent_create_error:
delete result;
}
else
- res= TRUE;
+ res= TRUE; // Error
break;
}
case SQLCOM_DROP_TABLE:
@@ -3573,8 +3570,7 @@ unsent_create_error:
ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
goto error;
}
- res=mysql_rm_db(thd, (lower_case_table_names == 2 ? alias : lex->name),
- lex->drop_if_exists, 0);
+ res= mysql_rm_db(thd, lex->name, lex->drop_if_exists, 0);
break;
}
case SQLCOM_ALTER_DB:
@@ -3911,10 +3907,7 @@ unsent_create_error:
*sv=(*sv)->prev;
}
else
- {
my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "SAVEPOINT", lex->ident.str);
- res= TRUE;
- }
break;
}
case SQLCOM_ROLLBACK_TO_SAVEPOINT:
@@ -3943,10 +3936,7 @@ unsent_create_error:
*sv=(*sv)->prev;
}
else
- {
my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "SAVEPOINT", lex->ident.str);
- res= TRUE;
- }
break;
}
case SQLCOM_SAVEPOINT:
@@ -3973,7 +3963,6 @@ unsent_create_error:
savepoint_alloc_size)) == 0)
{
my_error(ER_OUT_OF_RESOURCES, MYF(0));
- res= TRUE;
break;
}
newsv->name=strmake_root(&thd->transaction.mem_root,
@@ -4391,7 +4380,6 @@ unsent_create_error:
}
thd->transaction.xa_state=XA_ACTIVE;
send_ok(thd);
- res=TRUE;
break;
}
if (thd->lex->ident.length > MAXGTRIDSIZE || thd->lex->xa_opt != XA_NONE)
@@ -4417,7 +4405,6 @@ unsent_create_error:
OPTION_BEGIN);
thd->server_status|= SERVER_STATUS_IN_TRANS;
send_ok(thd);
- res=TRUE;
break;
case SQLCOM_XA_END:
/* fake it */
@@ -4439,7 +4426,6 @@ unsent_create_error:
}
thd->transaction.xa_state=XA_IDLE;
send_ok(thd);
- res=TRUE;
break;
case SQLCOM_XA_PREPARE:
if (thd->transaction.xa_state != XA_IDLE)
@@ -4459,7 +4445,6 @@ unsent_create_error:
thd->transaction.xa_state=XA_NOTR;
break;
}
- res=TRUE;
thd->transaction.xa_state=XA_PREPARED;
send_ok(thd);
break;
@@ -4478,7 +4463,6 @@ unsent_create_error:
else
{
send_ok(thd);
- res= TRUE;
}
}
else
@@ -4489,7 +4473,6 @@ unsent_create_error:
else
{
send_ok(thd);
- res= TRUE;
}
}
else
@@ -4519,16 +4502,13 @@ unsent_create_error:
if (ha_rollback(thd))
my_error(ER_XAER_RMERR, MYF(0));
else
- {
send_ok(thd);
- res= TRUE;
- }
thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
thd->server_status&= ~SERVER_STATUS_IN_TRANS;
thd->transaction.xa_state=XA_NOTR;
break;
case SQLCOM_XA_RECOVER:
- res= !mysql_xa_recover(thd);
+ res= mysql_xa_recover(thd);
break;
default:
DBUG_ASSERT(0); /* Impossible */
@@ -6173,22 +6153,16 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables,
the slow query log, and the relay log (if it exists).
*/
- /*
+ /*
Writing this command to the binlog may result in infinite loops when doing
mysqlbinlog|mysql, and anyway it does not really make sense to log it
automatically (would cause more trouble to users than it would help them)
*/
tmp_write_to_binlog= 0;
mysql_log.new_file(1);
- mysql_bin_log.new_file(1);
mysql_slow_log.new_file(1);
+ mysql_bin_log.rotate_and_purge(RP_FORCE_ROTATE);
#ifdef HAVE_REPLICATION
- if (mysql_bin_log.is_open() && expire_logs_days)
- {
- long purge_time= time(0) - expire_logs_days*24*60*60;
- if (purge_time >= 0)
- mysql_bin_log.purge_logs_before_date(purge_time);
- }
pthread_mutex_lock(&LOCK_active_mi);
rotate_relay_log(active_mi);
pthread_mutex_unlock(&LOCK_active_mi);
@@ -6202,7 +6176,7 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables,
if (options & REFRESH_QUERY_CACHE_FREE)
{
query_cache.pack(); // FLUSH QUERY CACHE
- options &= ~REFRESH_QUERY_CACHE; // Don't flush cache, just free memory
+ options &= ~REFRESH_QUERY_CACHE; // Don't flush cache, just free memory
}
if (options & (REFRESH_TABLES | REFRESH_QUERY_CACHE))
{
diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc
index a1e09b0bb3f..3b4e822a3df 100644
--- a/sql/sql_repl.cc
+++ b/sql/sql_repl.cc
@@ -454,13 +454,14 @@ impossible position";
(*packet)[EVENT_TYPE_OFFSET+1]));
if ((*packet)[EVENT_TYPE_OFFSET+1] == FORMAT_DESCRIPTION_EVENT)
{
- binlog_can_be_corrupted= (*packet)[FLAGS_OFFSET+1] & LOG_EVENT_BINLOG_IN_USE_F;
+ binlog_can_be_corrupted= test((*packet)[FLAGS_OFFSET+1] &
+ LOG_EVENT_BINLOG_IN_USE_F);
/*
mark that this event with "log_pos=0", so the slave
should not increment master's binlog position
(rli->group_master_log_pos)
*/
- int4store(packet->c_ptr()+LOG_POS_OFFSET+1, 0);
+ int4store((char*) packet->ptr()+LOG_POS_OFFSET+1, 0);
/* send it */
if (my_net_write(net, (char*)packet->ptr(), packet->length()))
{
@@ -477,16 +478,21 @@ impossible position";
}
}
else
+ {
if (test_for_non_eof_log_read_errors(error, &errmsg))
goto err;
- /*
- else: it's EOF, nothing to do, go on reading next events, the
- Format_description_log_event will be found naturally if it is written.
- */
+ /*
+ It's EOF, nothing to do, go on reading next events, the
+ Format_description_log_event will be found naturally if it is written.
+ */
+ }
/* reset the packet as we wrote to it in any case */
packet->set("\0", 1, &my_charset_bin);
- } /* end of if (pos > BIN_LOG_HEADER_SIZE); if false, the
- Format_description_log_event event will be found naturally. */
+ } /* end of if (pos > BIN_LOG_HEADER_SIZE); */
+ else
+ {
+ /* The Format_description_log_event event will be found naturally. */
+ }
/* seek to the requested position, to start the requested dump */
my_b_seek(&log, pos); // Seek will done on next read
@@ -506,7 +512,8 @@ impossible position";
#endif
if ((*packet)[EVENT_TYPE_OFFSET+1] == FORMAT_DESCRIPTION_EVENT)
- binlog_can_be_corrupted= (*packet)[FLAGS_OFFSET+1] & LOG_EVENT_BINLOG_IN_USE_F;
+ binlog_can_be_corrupted= test((*packet)[FLAGS_OFFSET+1] &
+ LOG_EVENT_BINLOG_IN_USE_F);
else if ((*packet)[EVENT_TYPE_OFFSET+1] == STOP_EVENT)
binlog_can_be_corrupted= FALSE;
@@ -755,9 +762,9 @@ int start_slave(THD* thd , MASTER_INFO* mi, bool net_report)
else if (server_id_supplied && *mi->host)
{
/*
- If we will start SQL thread we will care about UNTIL options If
- not and they are specified we will ignore them and warn user
- about this fact.
+ If we will start SQL thread we will care about UNTIL options If
+ not and they are specified we will ignore them and warn user
+ about this fact.
*/
if (thread_mask & SLAVE_SQL)
{
@@ -772,14 +779,14 @@ int start_slave(THD* thd , MASTER_INFO* mi, bool net_report)
since it is checked in sql_yacc.yy
*/
strmake(mi->rli.until_log_name, thd->lex->mi.log_file_name,
- sizeof(mi->rli.until_log_name)-1);
+ sizeof(mi->rli.until_log_name)-1);
}
else if (thd->lex->mi.relay_log_pos)
{
mi->rli.until_condition= RELAY_LOG_INFO::UNTIL_RELAY_POS;
mi->rli.until_log_pos= thd->lex->mi.relay_log_pos;
strmake(mi->rli.until_log_name, thd->lex->mi.relay_log_name,
- sizeof(mi->rli.until_log_name)-1);
+ sizeof(mi->rli.until_log_name)-1);
}
else
clear_until_condition(&mi->rli);
@@ -810,7 +817,8 @@ int start_slave(THD* thd , MASTER_INFO* mi, bool net_report)
/* Issuing warning then started without --skip-slave-start */
if (!opt_skip_slave_start)
- push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, ER_MISSING_SKIP_SLAVE,
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
+ ER_MISSING_SKIP_SLAVE,
ER(ER_MISSING_SKIP_SLAVE));
}
@@ -818,7 +826,7 @@ int start_slave(THD* thd , MASTER_INFO* mi, bool net_report)
}
else if (thd->lex->mi.pos || thd->lex->mi.relay_log_pos)
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, ER_UNTIL_COND_IGNORED,
- ER(ER_UNTIL_COND_IGNORED));
+ ER(ER_UNTIL_COND_IGNORED));
if (!slave_errno)
slave_errno = start_slave_threads(0 /*no mutex */,
@@ -831,10 +839,12 @@ int start_slave(THD* thd , MASTER_INFO* mi, bool net_report)
slave_errno = ER_BAD_SLAVE;
}
else
- //no error if all threads are already started, only a warning
+ {
+ /* no error if all threads are already started, only a warning */
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, ER_SLAVE_WAS_RUNNING,
ER(ER_SLAVE_WAS_RUNNING));
-
+ }
+
unlock_slave_threads(mi);
if (slave_errno)
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 2a2c50574db..b38014eb4ea 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -109,11 +109,12 @@ bool mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists,
delete (drop) tables.
SYNOPSIS
- mysql_rm_table_part2_with_lock()
- thd Thread handle
- tables List of tables to delete
- if_exists If 1, don't give error if one table doesn't exists
- dont_log_query Don't write query to log files
+ mysql_rm_table_part2_with_lock()
+ thd Thread handle
+ tables List of tables to delete
+ if_exists If 1, don't give error if one table doesn't exists
+ dont_log_query Don't write query to log files. This will also not
+ generate warnings if the handler files doesn't exists
NOTES
Works like documented in mysql_rm_table(), but don't check
@@ -157,7 +158,8 @@ int mysql_rm_table_part2_with_lock(THD *thd,
In this case we give an warning of level 'NOTE'
drop_temporary Only drop temporary tables
drop_view Allow to delete VIEW .frm
- dont_log_query Don't log the query
+ dont_log_query Don't write query to log files. This will also not
+ generate warnings if the handler files doesn't exists
TODO:
When logging to the binary log, we should log
@@ -218,7 +220,8 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
(void) unpack_filename(path,path);
}
if (drop_temporary ||
- (access(path,F_OK) && ha_create_table_from_engine(thd,db,alias,TRUE)) ||
+ (access(path,F_OK) &&
+ ha_create_table_from_engine(thd,db,alias,TRUE)) ||
(!drop_view && mysql_frm_type(path) != FRMTYPE_TABLE))
{
if (if_exists)
@@ -233,35 +236,23 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
char *end;
db_type table_type= get_table_type(path);
*(end=fn_ext(path))=0; // Remove extension for delete
- error=ha_delete_table(table_type, path);
- if (error == ENOENT && if_exists)
- error = 0;
+ error= ha_delete_table(thd, table_type, path, table->table_name,
+ !dont_log_query);
+ if ((error == ENOENT || error == HA_ERR_NO_SUCH_TABLE) && if_exists)
+ error= 0;
if (error == HA_ERR_ROW_IS_REFERENCED)
{
/* the table is referenced by a foreign key constraint */
foreign_key_error=1;
}
- if (!error || error == ENOENT)
+ if (!error || error == ENOENT || error == HA_ERR_NO_SUCH_TABLE)
{
+ int new_error;
/* Delete the table definition file */
strmov(end,reg_ext);
- if (!(error=my_delete(path,MYF(MY_WME))))
+ if (!(new_error=my_delete(path,MYF(MY_WME))))
some_tables_deleted=1;
- }
- if (error == HA_ERR_NO_SUCH_TABLE)
- {
- /* The table did not exist in engine */
- if (if_exists)
- {
- push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
- ER_BAD_TABLE_ERROR, ER(ER_BAD_TABLE_ERROR),
- table->table_name);
- error= 0;
- }
- /* Delete the table definition file */
- strmov(end,reg_ext);
- if (!(my_delete(path,MYF(MY_WME))))
- some_tables_deleted=1;
+ error|= new_error;
}
}
if (error)
@@ -311,7 +302,7 @@ int quick_rm_table(enum db_type base,const char *db,
error=1; /* purecov: inspected */
my_snprintf(path, sizeof(path), "%s/%s/%s", mysql_data_home, db, table_name);
unpack_filename(path,path);
- return ha_delete_table(base,path) || error;
+ return ha_delete_table(current_thd, base, path, table_name, 0) || error;
}
/*
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 04db57c5540..c75068f0047 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -630,7 +630,6 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token VARCHAR
%token VARIABLES
%token VARIANCE_SYM
-%token VARIANCE_SYM
%token VARYING
%token VIEW_SYM
%token WARNINGS