Merge lp:~dshrews/drizzle/bug660779 into lp:~drizzle-trunk/drizzle/development

Proposed by David Shrewsbury
Status: Merged
Approved by: Brian Aker
Approved revision: 1869
Merge reported by: Lee Bieber
Merged at revision: not available
Proposed branch: lp:~dshrews/drizzle/bug660779
Merge into: lp:~drizzle-trunk/drizzle/development
Diff against target: 716 lines (+512/-48)
9 files modified
drizzled/session.cc (+14/-14)
drizzled/session.h (+45/-24)
drizzled/sql_insert.cc (+9/-0)
drizzled/sql_update.cc (+22/-8)
drizzled/transaction_services.cc (+121/-2)
drizzled/transaction_services.h (+22/-0)
plugin/transaction_log/tests/r/bug660779.result (+220/-0)
plugin/transaction_log/tests/t/bug660779-master.opt (+1/-0)
plugin/transaction_log/tests/t/bug660779.test (+58/-0)
To merge this branch: bzr merge lp:~dshrews/drizzle/bug660779
Reviewer Review Type Date Requested Status
Drizzle Merge Team Pending
Review via email: mp+39375@code.launchpad.net

This proposal supersedes a proposal from 2010-10-25.

Description of the change

Provides methods in TransactionServices to undo adding records to the current Statement message when a multi-row affecting statement fails mid-execution. Call this method for UPDATEs and INSERT..SELECTs that fail.

Also cleans up some #includes in session.* and adds some comments for the st_transactions struct in session.h.

To post a comment you must log in.
Revision history for this message
Lee Bieber (kalebral-deactivatedaccount) wrote : Posted in a previous version of this proposal
Revision history for this message
David Shrewsbury (dshrews) wrote : Posted in a previous version of this proposal

Grr... working on it...

Revision history for this message
David Shrewsbury (dshrews) wrote :

Solaris succeeded in param-build.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'drizzled/session.cc'
--- drizzled/session.cc 2010-10-22 22:08:54 +0000
+++ drizzled/session.cc 2010-10-26 14:47:53 +0000
@@ -22,21 +22,21 @@
22 */22 */
2323
24#include "config.h"24#include "config.h"
25#include <drizzled/session.h>25#include "drizzled/session.h"
26#include "drizzled/session_list.h"26#include "drizzled/session_list.h"
27#include <sys/stat.h>27#include <sys/stat.h>
28#include <drizzled/error.h>28#include "drizzled/error.h"
29#include <drizzled/gettext.h>29#include "drizzled/gettext.h"
30#include <drizzled/query_id.h>30#include "drizzled/query_id.h"
31#include <drizzled/data_home.h>31#include "drizzled/data_home.h"
32#include <drizzled/sql_base.h>32#include "drizzled/sql_base.h"
33#include <drizzled/lock.h>33#include "drizzled/lock.h"
34#include <drizzled/item/cache.h>34#include "drizzled/item/cache.h"
35#include <drizzled/item/float.h>35#include "drizzled/item/float.h"
36#include <drizzled/item/return_int.h>36#include "drizzled/item/return_int.h"
37#include <drizzled/item/empty_string.h>37#include "drizzled/item/empty_string.h"
38#include <drizzled/show.h>38#include "drizzled/show.h"
39#include <drizzled/plugin/client.h>39#include "drizzled/plugin/client.h"
40#include "drizzled/plugin/scheduler.h"40#include "drizzled/plugin/scheduler.h"
41#include "drizzled/plugin/authentication.h"41#include "drizzled/plugin/authentication.h"
42#include "drizzled/plugin/logging.h"42#include "drizzled/plugin/logging.h"
@@ -60,7 +60,7 @@
60#include <fcntl.h>60#include <fcntl.h>
61#include <algorithm>61#include <algorithm>
62#include <climits>62#include <climits>
63#include "boost/filesystem.hpp" 63#include <boost/filesystem.hpp>
6464
65using namespace std;65using namespace std;
6666
6767
=== modified file 'drizzled/session.h'
--- drizzled/session.h 2010-10-23 22:18:01 +0000
+++ drizzled/session.h 2010-10-26 14:47:53 +0000
@@ -21,23 +21,20 @@
21#ifndef DRIZZLED_SESSION_H21#ifndef DRIZZLED_SESSION_H
22#define DRIZZLED_SESSION_H22#define DRIZZLED_SESSION_H
2323
24/* Classes in mysql */
25
26#include "drizzled/plugin.h"24#include "drizzled/plugin.h"
27#include <drizzled/sql_locale.h>25#include "drizzled/sql_locale.h"
28#include "drizzled/resource_context.h"26#include "drizzled/resource_context.h"
29#include <drizzled/cursor.h>27#include "drizzled/cursor.h"
30#include <drizzled/current_session.h>28#include "drizzled/current_session.h"
31#include <drizzled/sql_error.h>29#include "drizzled/sql_error.h"
32#include <drizzled/file_exchange.h>30#include "drizzled/file_exchange.h"
33#include <drizzled/select_result_interceptor.h>31#include "drizzled/select_result_interceptor.h"
34#include <drizzled/statistics_variables.h>32#include "drizzled/statistics_variables.h"
35#include <drizzled/xid.h>33#include "drizzled/xid.h"
36#include "drizzled/query_id.h"34#include "drizzled/query_id.h"
37#include "drizzled/named_savepoint.h"35#include "drizzled/named_savepoint.h"
38#include "drizzled/transaction_context.h"36#include "drizzled/transaction_context.h"
39#include "drizzled/util/storable.h"37#include "drizzled/util/storable.h"
40
41#include "drizzled/my_hash.h"38#include "drizzled/my_hash.h"
4239
43#include <netdb.h>40#include <netdb.h>
@@ -47,14 +44,11 @@
47#include <deque>44#include <deque>
4845
49#include "drizzled/internal/getrusage.h"46#include "drizzled/internal/getrusage.h"
5047#include "drizzled/security_context.h"
51#include <drizzled/security_context.h>48#include "drizzled/open_tables_state.h"
52#include <drizzled/open_tables_state.h>49#include "drizzled/internal_error_handler.h"
5350#include "drizzled/diagnostics_area.h"
54#include <drizzled/internal_error_handler.h>51#include "drizzled/plugin/authorization.h"
55#include <drizzled/diagnostics_area.h>
56
57#include <drizzled/plugin/authorization.h>
5852
59#include <boost/unordered_map.hpp>53#include <boost/unordered_map.hpp>
60#include <boost/thread/mutex.hpp>54#include <boost/thread/mutex.hpp>
@@ -550,10 +544,38 @@
550 ResourceContext *getResourceContext(const plugin::MonitoredInTransaction *monitored,544 ResourceContext *getResourceContext(const plugin::MonitoredInTransaction *monitored,
551 size_t index= 0);545 size_t index= 0);
552546
547 /**
548 * Structure used to manage "statement transactions" and
549 * "normal transactions". In autocommit mode, the normal transaction is
550 * equivalent to the statement transaction.
551 *
552 * Storage engines will be registered here when they participate in
553 * a transaction. No engine is registered more than once.
554 */
553 struct st_transactions {555 struct st_transactions {
554 std::deque<NamedSavepoint> savepoints;556 std::deque<NamedSavepoint> savepoints;
555 TransactionContext all; ///< Trans since BEGIN WORK557
556 TransactionContext stmt; ///< Trans for current statement558 /**
559 * The normal transaction (since BEGIN WORK).
560 *
561 * Contains a list of all engines that have participated in any of the
562 * statement transactions started within the context of the normal
563 * transaction.
564 *
565 * @note In autocommit mode, this is empty.
566 */
567 TransactionContext all;
568
569 /**
570 * The statment transaction.
571 *
572 * Contains a list of all engines participating in the given statement.
573 *
574 * @note In autocommit mode, this will be used to commit/rollback the
575 * normal transaction.
576 */
577 TransactionContext stmt;
578
557 XID_STATE xid_state;579 XID_STATE xid_state;
558580
559 void cleanup()581 void cleanup()
@@ -1197,9 +1219,8 @@
1197 * Current implementation does not depend on that, but future changes1219 * Current implementation does not depend on that, but future changes
1198 * should be done with this in mind; 1220 * should be done with this in mind;
1199 *1221 *
1200 * @param Scrambled password received from client1222 * @param passwd Scrambled password received from client
1201 * @param Length of scrambled password1223 * @param db Database name to connect to, may be NULL
1202 * @param Database name to connect to, may be NULL
1203 */1224 */
1204 bool checkUser(const std::string &passwd, const std::string &db);1225 bool checkUser(const std::string &passwd, const std::string &db);
1205 1226
12061227
=== modified file 'drizzled/sql_insert.cc'
--- drizzled/sql_insert.cc 2010-10-24 19:36:55 +0000
+++ drizzled/sql_insert.cc 2010-10-26 14:47:53 +0000
@@ -1276,7 +1276,16 @@
1276 store_values(values);1276 store_values(values);
1277 session->count_cuted_fields= CHECK_FIELD_IGNORE;1277 session->count_cuted_fields= CHECK_FIELD_IGNORE;
1278 if (session->is_error())1278 if (session->is_error())
1279 {
1280 /*
1281 * If we fail mid-way through INSERT..SELECT, we need to remove any
1282 * records that we added to the current Statement message. We can
1283 * use session->row_count to know how many records we have already added.
1284 */
1285 TransactionServices &ts= TransactionServices::singleton();
1286 ts.removeStatementRecords(session, (session->row_count - 1));
1279 return(1);1287 return(1);
1288 }
12801289
1281 // Release latches in case bulk insert takes a long time1290 // Release latches in case bulk insert takes a long time
1282 plugin::TransactionalStorageEngine::releaseTemporaryLatches(session);1291 plugin::TransactionalStorageEngine::releaseTemporaryLatches(session);
12831292
=== modified file 'drizzled/sql_update.cc'
--- drizzled/sql_update.cc 2010-10-24 01:34:39 +0000
+++ drizzled/sql_update.cc 2010-10-26 14:47:53 +0000
@@ -29,6 +29,7 @@
29#include "drizzled/records.h"29#include "drizzled/records.h"
30#include "drizzled/internal/my_sys.h"30#include "drizzled/internal/my_sys.h"
31#include "drizzled/internal/iocache.h"31#include "drizzled/internal/iocache.h"
32#include "drizzled/transaction_services.h"
3233
33#include <boost/dynamic_bitset.hpp>34#include <boost/dynamic_bitset.hpp>
34#include <list>35#include <list>
@@ -473,7 +474,20 @@
473474
474 table->storeRecord();475 table->storeRecord();
475 if (fill_record(session, fields, values))476 if (fill_record(session, fields, values))
477 {
478 /*
479 * If we updated some rows before this one failed (updated > 0),
480 * then we will need to undo adding those records to the
481 * replication Statement message.
482 */
483 if (updated > 0)
484 {
485 TransactionServices &ts= TransactionServices::singleton();
486 ts.removeStatementRecords(session, updated);
487 }
488
476 break;489 break;
490 }
477491
478 found++;492 found++;
479493
@@ -486,15 +500,15 @@
486 table->auto_increment_field_not_null= false;500 table->auto_increment_field_not_null= false;
487501
488 if (!error || error == HA_ERR_RECORD_IS_THE_SAME)502 if (!error || error == HA_ERR_RECORD_IS_THE_SAME)
489 {503 {
490 if (error != HA_ERR_RECORD_IS_THE_SAME)504 if (error != HA_ERR_RECORD_IS_THE_SAME)
491 updated++;505 updated++;
492 else506 else
493 error= 0;507 error= 0;
494 }508 }
495 else if (! ignore ||509 else if (! ignore ||
496 table->cursor->is_fatal_error(error, HA_CHECK_DUP_KEY))510 table->cursor->is_fatal_error(error, HA_CHECK_DUP_KEY))
497 {511 {
498 /*512 /*
499 If (ignore && error is ignorable) we don't have to513 If (ignore && error is ignorable) we don't have to
500 do anything; otherwise...514 do anything; otherwise...
@@ -505,10 +519,10 @@
505 flags|= ME_FATALERROR; /* Other handler errors are fatal */519 flags|= ME_FATALERROR; /* Other handler errors are fatal */
506520
507 prepare_record_for_error_message(error, table);521 prepare_record_for_error_message(error, table);
508 table->print_error(error,MYF(flags));522 table->print_error(error,MYF(flags));
509 error= 1;523 error= 1;
510 break;524 break;
511 }525 }
512 }526 }
513527
514 if (!--limit && using_limit)528 if (!--limit && using_limit)
515529
=== modified file 'drizzled/transaction_services.cc'
--- drizzled/transaction_services.cc 2010-10-11 17:20:14 +0000
+++ drizzled/transaction_services.cc 2010-10-26 14:47:53 +0000
@@ -71,11 +71,13 @@
71#include "drizzled/plugin/xa_resource_manager.h"71#include "drizzled/plugin/xa_resource_manager.h"
72#include "drizzled/internal/my_sys.h"72#include "drizzled/internal/my_sys.h"
7373
74using namespace std;
75
76#include <vector>74#include <vector>
77#include <algorithm>75#include <algorithm>
78#include <functional>76#include <functional>
77#include <google/protobuf/repeated_field.h>
78
79using namespace std;
80using namespace google;
7981
80namespace drizzled82namespace drizzled
81{83{
@@ -1826,6 +1828,123 @@
1826 }1828 }
1827}1829}
18281830
1831
1832/**
1833 * Template for removing Statement records of different types.
1834 *
1835 * The code for removing records from different Statement message types
1836 * is identical except for the class types that are embedded within the
1837 * Statement.
1838 *
1839 * There are 3 scenarios we need to look for:
1840 * - We've been asked to remove more records than exist in the Statement
1841 * - We've been asked to remove less records than exist in the Statement
1842 * - We've been asked to remove ALL records that exist in the Statement
1843 *
1844 * If we are removing ALL records, then effectively we would be left with
1845 * an empty Statement message, so we should just remove it and clean up
1846 * message pointers in the Session object.
1847 */
1848template <class DataType, class RecordType>
1849static bool removeStatementRecordsWithType(Session *session,
1850 DataType *data,
1851 uint32_t count)
1852{
1853 uint32_t num_avail_recs= static_cast<uint32_t>(data->record_size());
1854
1855 /* If there aren't enough records to remove 'count' of them, error. */
1856 if (num_avail_recs < count)
1857 return false;
1858
1859 /*
1860 * If we are removing all of the data records, we'll just remove this
1861 * entire Statement message.
1862 */
1863 if (num_avail_recs == count)
1864 {
1865 message::Transaction *transaction= session->getTransactionMessage();
1866 protobuf::RepeatedPtrField<message::Statement> *statements= transaction->mutable_statement();
1867 statements->RemoveLast();
1868
1869 /*
1870 * Now need to set the Session Statement pointer to either the previous
1871 * Statement, or NULL if there isn't one.
1872 */
1873 if (statements->size() == 0)
1874 {
1875 session->setStatementMessage(NULL);
1876 }
1877 else
1878 {
1879 /*
1880 * There isn't a great way to get a pointer to the previous Statement
1881 * message using the RepeatedPtrField object, so we'll just get to it
1882 * using the Transaction message.
1883 */
1884 int last_stmt_idx= transaction->statement_size() - 1;
1885 session->setStatementMessage(transaction->mutable_statement(last_stmt_idx));
1886 }
1887 }
1888 /* We only need to remove 'count' records */
1889 else if (num_avail_recs > count)
1890 {
1891 protobuf::RepeatedPtrField<RecordType> *records= data->mutable_record();
1892 while (count--)
1893 records->RemoveLast();
1894 }
1895
1896 return true;
1897}
1898
1899
1900bool TransactionServices::removeStatementRecords(Session *session,
1901 uint32_t count)
1902{
1903 ReplicationServices &replication_services= ReplicationServices::singleton();
1904 if (! replication_services.isActive())
1905 return false;
1906
1907 /* Get the most current Statement */
1908 message::Statement *statement= session->getStatementMessage();
1909
1910 /* Make sure we have work to do */
1911 if (statement == NULL)
1912 return false;
1913
1914 bool retval= false;
1915
1916 switch (statement->type())
1917 {
1918 case message::Statement::INSERT:
1919 {
1920 message::InsertData *data= statement->mutable_insert_data();
1921 retval= removeStatementRecordsWithType<message::InsertData, message::InsertRecord>(session, data, count);
1922 break;
1923 }
1924
1925 case message::Statement::UPDATE:
1926 {
1927 message::UpdateData *data= statement->mutable_update_data();
1928 retval= removeStatementRecordsWithType<message::UpdateData, message::UpdateRecord>(session, data, count);
1929 break;
1930 }
1931
1932 case message::Statement::DELETE: /* not sure if this one is possible... */
1933 {
1934 message::DeleteData *data= statement->mutable_delete_data();
1935 retval= removeStatementRecordsWithType<message::DeleteData, message::DeleteRecord>(session, data, count);
1936 break;
1937 }
1938
1939 default:
1940 retval= false;
1941 break;
1942 }
1943
1944 return retval;
1945}
1946
1947
1829void TransactionServices::createTable(Session *in_session,1948void TransactionServices::createTable(Session *in_session,
1830 const message::Table &table)1949 const message::Table &table)
1831{1950{
18321951
=== modified file 'drizzled/transaction_services.h'
--- drizzled/transaction_services.h 2010-10-11 17:20:14 +0000
+++ drizzled/transaction_services.h 2010-10-26 14:47:53 +0000
@@ -260,6 +260,28 @@
260 * @param use_update_record If true, uses the values from the update row instead260 * @param use_update_record If true, uses the values from the update row instead
261 */261 */
262 void deleteRecord(Session *in_session, Table *in_table, bool use_update_record= false);262 void deleteRecord(Session *in_session, Table *in_table, bool use_update_record= false);
263
264 /**
265 * Used to undo effects of a failed statement.
266 *
267 * An SQL statement, like an UPDATE, that affects multiple rows could
268 * potentially fail mid-way through processing the rows. In such a case,
269 * the successfully modified rows that preceeded the failing row would
270 * have been added to the Statement message. This method is used for
271 * rolling back that change.
272 *
273 * @note
274 * This particular failure is seen on column constraint violations
275 * during a multi-row UPDATE and a multi-row INSERT..SELECT.
276 *
277 * @param in_session Pointer to the Session containing the Statement
278 * @param count The number of records to remove from Statement.
279 *
280 * @retval true Successfully removed 'count' records
281 * @retval false Failure
282 */
283 bool removeStatementRecords(Session *in_session, uint32_t count);
284
263 /**285 /**
264 * Creates a CreateSchema Statement GPB message and adds it286 * Creates a CreateSchema Statement GPB message and adds it
265 * to the Session's active Transaction GPB message for pushing287 * to the Session's active Transaction GPB message for pushing
266288
=== added file 'plugin/transaction_log/tests/r/bug660779.result'
--- plugin/transaction_log/tests/r/bug660779.result 1970-01-01 00:00:00 +0000
+++ plugin/transaction_log/tests/r/bug660779.result 2010-10-26 14:47:53 +0000
@@ -0,0 +1,220 @@
1CREATE TABLE t1 (
2pk INT NOT NULL AUTO_INCREMENT,
3col_int1 INT,
4col_int2 INT,
5col_int_not_null INT NOT NULL,
6PRIMARY KEY (pk));
7INSERT INTO t1 (col_int1, col_int2, col_int_not_null) VALUES (1,1,1);
8INSERT INTO t1 (col_int1, col_int2, col_int_not_null) VALUES (NULL,1,1);
9INSERT INTO t1 (col_int1, col_int2, col_int_not_null) VALUES (2,1,3);
10SET GLOBAL transaction_log_truncate_debug= true;
11BEGIN;
12UPDATE t1 SET col_int_not_null = col_int1 WHERE col_int2 = 1;
13ERROR 23000: Column 'col_int_not_null' cannot be null
14INSERT INTO t1 (col_int1, col_int2, col_int_not_null) VALUES (5,5,5);
15COMMIT;
16
17We should have a Transaction with a single insert Statement
18SELECT PRINT_TRANSACTION_MESSAGE('transaction.log',(select max(entry_offset) from DATA_DICTIONARY.TRANSACTION_LOG_TRANSACTIONS));
19PRINT_TRANSACTION_MESSAGE('transaction.log',(select max(entry_offset) from DATA_DICTIONARY.TRANSACTION_LOG_TRANSACTIONS))
20transaction_context {
21 server_id: 1
22 transaction_id: 1
23 START_TIMESTAMP
24 END_TIMESTAMP
25}
26statement {
27 type: INSERT
28 START_TIMESTAMP
29 END_TIMESTAMP
30 insert_header {
31 table_metadata {
32 schema_name: "test"
33 table_name: "t1"
34 }
35 field_metadata {
36 type: INTEGER
37 name: "pk"
38 }
39 field_metadata {
40 type: INTEGER
41 name: "col_int1"
42 }
43 field_metadata {
44 type: INTEGER
45 name: "col_int2"
46 }
47 field_metadata {
48 type: INTEGER
49 name: "col_int_not_null"
50 }
51 }
52 insert_data {
53 segment_id: 1
54 end_segment: true
55 record {
56 insert_value: "4"
57 insert_value: "5"
58 insert_value: "5"
59 insert_value: "5"
60 is_null: false
61 is_null: false
62 is_null: false
63 is_null: false
64 }
65 }
66}
67
68BEGIN;
69UPDATE t1 SET col_int1 = (col_int1 + 1) WHERE col_int2 = 1;
70UPDATE t1 SET col_int_not_null = col_int1 WHERE col_int2 = 1;
71ERROR 23000: Column 'col_int_not_null' cannot be null
72INSERT INTO t1 (col_int1, col_int2, col_int_not_null) VALUES (6,6,6);
73COMMIT;
74
75We should have a Transaction with 1 update and 1 insert Statement
76SELECT PRINT_TRANSACTION_MESSAGE('transaction.log',(select max(entry_offset) from DATA_DICTIONARY.TRANSACTION_LOG_TRANSACTIONS));
77PRINT_TRANSACTION_MESSAGE('transaction.log',(select max(entry_offset) from DATA_DICTIONARY.TRANSACTION_LOG_TRANSACTIONS))
78transaction_context {
79 server_id: 1
80 transaction_id: 2
81 START_TIMESTAMP
82 END_TIMESTAMP
83}
84statement {
85 type: UPDATE
86 START_TIMESTAMP
87 END_TIMESTAMP
88 update_header {
89 table_metadata {
90 schema_name: "test"
91 table_name: "t1"
92 }
93 key_field_metadata {
94 type: INTEGER
95 name: "pk"
96 }
97 set_field_metadata {
98 type: INTEGER
99 name: "col_int1"
100 }
101 }
102 update_data {
103 segment_id: 1
104 end_segment: true
105 record {
106 key_value: "1"
107 after_value: "2"
108 is_null: false
109 }
110 record {
111 key_value: "3"
112 after_value: "3"
113 is_null: false
114 }
115 }
116}
117statement {
118 type: INSERT
119 START_TIMESTAMP
120 END_TIMESTAMP
121 insert_header {
122 table_metadata {
123 schema_name: "test"
124 table_name: "t1"
125 }
126 field_metadata {
127 type: INTEGER
128 name: "pk"
129 }
130 field_metadata {
131 type: INTEGER
132 name: "col_int1"
133 }
134 field_metadata {
135 type: INTEGER
136 name: "col_int2"
137 }
138 field_metadata {
139 type: INTEGER
140 name: "col_int_not_null"
141 }
142 }
143 insert_data {
144 segment_id: 1
145 end_segment: true
146 record {
147 insert_value: "5"
148 insert_value: "6"
149 insert_value: "6"
150 insert_value: "6"
151 is_null: false
152 is_null: false
153 is_null: false
154 is_null: false
155 }
156 }
157}
158
159CREATE TABLE t2 (pk INT NOT NULL AUTO_INCREMENT PRIMARY KEY, a INT);
160INSERT INTO t2 (a) VALUES (1),(2), (NULL);
161BEGIN;
162INSERT INTO t1 (col_int_not_null) SELECT a FROM t2;
163ERROR 23000: Column 'col_int_not_null' cannot be null
164INSERT INTO t1 (col_int1, col_int2, col_int_not_null) VALUES (7,7,7);
165COMMIT;
166
167We should have a Transaction with 1 insert Statement
168SELECT PRINT_TRANSACTION_MESSAGE('transaction.log',(select max(entry_offset) from DATA_DICTIONARY.TRANSACTION_LOG_TRANSACTIONS));
169PRINT_TRANSACTION_MESSAGE('transaction.log',(select max(entry_offset) from DATA_DICTIONARY.TRANSACTION_LOG_TRANSACTIONS))
170transaction_context {
171 server_id: 1
172 transaction_id: 5
173 START_TIMESTAMP
174 END_TIMESTAMP
175}
176statement {
177 type: INSERT
178 START_TIMESTAMP
179 END_TIMESTAMP
180 insert_header {
181 table_metadata {
182 schema_name: "test"
183 table_name: "t1"
184 }
185 field_metadata {
186 type: INTEGER
187 name: "pk"
188 }
189 field_metadata {
190 type: INTEGER
191 name: "col_int1"
192 }
193 field_metadata {
194 type: INTEGER
195 name: "col_int2"
196 }
197 field_metadata {
198 type: INTEGER
199 name: "col_int_not_null"
200 }
201 }
202 insert_data {
203 segment_id: 1
204 end_segment: true
205 record {
206 insert_value: "8"
207 insert_value: "7"
208 insert_value: "7"
209 insert_value: "7"
210 is_null: false
211 is_null: false
212 is_null: false
213 is_null: false
214 }
215 }
216}
217
218DROP TABLE t1;
219DROP TABLE t2;
220SET GLOBAL transaction_log_truncate_debug= true;
0221
=== added file 'plugin/transaction_log/tests/t/bug660779-master.opt'
--- plugin/transaction_log/tests/t/bug660779-master.opt 1970-01-01 00:00:00 +0000
+++ plugin/transaction_log/tests/t/bug660779-master.opt 2010-10-26 14:47:53 +0000
@@ -0,0 +1,1 @@
1--transaction-log.enable --scheduler=multi_thread
02
=== added file 'plugin/transaction_log/tests/t/bug660779.test'
--- plugin/transaction_log/tests/t/bug660779.test 1970-01-01 00:00:00 +0000
+++ plugin/transaction_log/tests/t/bug660779.test 2010-10-26 14:47:53 +0000
@@ -0,0 +1,58 @@
1CREATE TABLE t1 (
2 pk INT NOT NULL AUTO_INCREMENT,
3 col_int1 INT,
4 col_int2 INT,
5 col_int_not_null INT NOT NULL,
6 PRIMARY KEY (pk));
7
8INSERT INTO t1 (col_int1, col_int2, col_int_not_null) VALUES (1,1,1);
9INSERT INTO t1 (col_int1, col_int2, col_int_not_null) VALUES (NULL,1,1);
10INSERT INTO t1 (col_int1, col_int2, col_int_not_null) VALUES (2,1,3);
11
12SET GLOBAL transaction_log_truncate_debug= true;
13
14--test with no previous Statement message
15BEGIN;
16--ERROR ER_BAD_NULL_ERROR
17UPDATE t1 SET col_int_not_null = col_int1 WHERE col_int2 = 1;
18INSERT INTO t1 (col_int1, col_int2, col_int_not_null) VALUES (5,5,5);
19COMMIT;
20
21--echo
22--echo We should have a Transaction with a single insert Statement
23--replace_regex /start_timestamp: [0-9]+/START_TIMESTAMP/g /end_timestamp: [0-9]+/END_TIMESTAMP/g /creation_timestamp: [0-9]+/CREATE_TIMESTAMP/ /update_timestamp: [0-9]+/UPDATE_TIMESTAMP/
24
25SELECT PRINT_TRANSACTION_MESSAGE('transaction.log',(select max(entry_offset) from DATA_DICTIONARY.TRANSACTION_LOG_TRANSACTIONS));
26
27BEGIN;
28UPDATE t1 SET col_int1 = (col_int1 + 1) WHERE col_int2 = 1;
29--ERROR ER_BAD_NULL_ERROR
30UPDATE t1 SET col_int_not_null = col_int1 WHERE col_int2 = 1;
31INSERT INTO t1 (col_int1, col_int2, col_int_not_null) VALUES (6,6,6);
32COMMIT;
33
34--echo
35--echo We should have a Transaction with 1 update and 1 insert Statement
36--replace_regex /start_timestamp: [0-9]+/START_TIMESTAMP/g /end_timestamp: [0-9]+/END_TIMESTAMP/g /creation_timestamp: [0-9]+/CREATE_TIMESTAMP/ /update_timestamp: [0-9]+/UPDATE_TIMESTAMP/
37
38SELECT PRINT_TRANSACTION_MESSAGE('transaction.log',(select max(entry_offset) from DATA_DICTIONARY.TRANSACTION_LOG_TRANSACTIONS));
39
40CREATE TABLE t2 (pk INT NOT NULL AUTO_INCREMENT PRIMARY KEY, a INT);
41INSERT INTO t2 (a) VALUES (1),(2), (NULL);
42
43BEGIN;
44--ERROR ER_BAD_NULL_ERROR
45INSERT INTO t1 (col_int_not_null) SELECT a FROM t2;
46INSERT INTO t1 (col_int1, col_int2, col_int_not_null) VALUES (7,7,7);
47COMMIT;
48
49--echo
50--echo We should have a Transaction with 1 insert Statement
51--replace_regex /start_timestamp: [0-9]+/START_TIMESTAMP/g /end_timestamp: [0-9]+/END_TIMESTAMP/g /creation_timestamp: [0-9]+/CREATE_TIMESTAMP/ /update_timestamp: [0-9]+/UPDATE_TIMESTAMP/
52
53SELECT PRINT_TRANSACTION_MESSAGE('transaction.log',(select max(entry_offset) from DATA_DICTIONARY.TRANSACTION_LOG_TRANSACTIONS));
54
55
56DROP TABLE t1;
57DROP TABLE t2;
58SET GLOBAL transaction_log_truncate_debug= true;