Skip to content

Commit 74cf4a0

Browse files
authored
Merge 'fix: update changes() and total_changes() inside explicit transactions' from Damian Melia
### Issue `changes()` and `total_changes()` were wrong inside explicit `BEGIN...COMMIT` transactions (returning 0 or stale values). The non- autocommit halt path in the VDBE never called `set_changes()`. ### Fix Call `set_changes()` in the non-autocommit halt path when `change_cnt_on` is true, so behavior matches SQLite. ### Testing Regression tests added for both reproducers (DELETE in transaction and INSERT with prior data), plus tests for `total_changes()` in transactions. #5146 I used AI to help me understand a bit more about the structure of the tests and to help translate the linked production / reported error cases into tests. Reviewed-by: Jussi Saurio <jussi.saurio@gmail.com> Closes #5437
2 parents 69496d4 + 2088c0c commit 74cf4a0

3 files changed

Lines changed: 112 additions & 0 deletions

File tree

core/vdbe/execute.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2051,6 +2051,11 @@ pub fn halt(
20512051
if let Some(cdc_info) = state.pending_cdc_info.take() {
20522052
program.connection.set_capture_data_changes_info(cdc_info);
20532053
}
2054+
if program.change_cnt_on {
2055+
program
2056+
.connection
2057+
.set_changes(state.n_change.load(Ordering::SeqCst));
2058+
}
20542059
Ok(InsnFunctionStepResult::Done)
20552060
}
20562061
}

testing/runner/tests/changes.sqltest

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,3 +149,75 @@ expect {
149149
1
150150
}
151151

152+
test changes-insert-in-transaction {
153+
create table t(id integer primary key, val text);
154+
begin;
155+
insert into t values(1, 'a'), (2, 'b'), (3, 'c');
156+
select changes();
157+
commit;
158+
}
159+
expect {
160+
3
161+
}
162+
163+
test changes-insert-in-transaction-after-commit {
164+
create table t(id integer primary key, val text);
165+
begin;
166+
insert into t values(1, 'a'), (2, 'b'), (3, 'c');
167+
commit;
168+
select changes();
169+
}
170+
expect {
171+
3
172+
}
173+
174+
test changes-delete-in-transaction {
175+
create table t(id integer primary key, val integer);
176+
insert into t values(1, 10), (2, 20), (3, 30);
177+
begin;
178+
delete from t where val > 15;
179+
select changes();
180+
commit;
181+
}
182+
expect {
183+
2
184+
}
185+
186+
test changes-insert-in-transaction-with-prior-data {
187+
create table t(id integer primary key, val integer);
188+
insert into t values(1, 10), (2, 20), (3, 30);
189+
begin;
190+
insert into t values(4, 40), (5, 50);
191+
select changes();
192+
commit;
193+
}
194+
expect {
195+
2
196+
}
197+
198+
test changes-update-in-transaction {
199+
create table t(id integer primary key, val text);
200+
insert into t values(1, 'a'), (2, 'b'), (3, 'c');
201+
begin;
202+
update t set val = 'z' where id <= 2;
203+
select changes();
204+
commit;
205+
}
206+
expect {
207+
2
208+
}
209+
210+
test changes-multiple-stmts-in-transaction {
211+
create table t(id integer primary key, val text);
212+
begin;
213+
insert into t values(1, 'a'), (2, 'b');
214+
select changes();
215+
insert into t values(3, 'c');
216+
select changes();
217+
commit;
218+
}
219+
expect {
220+
2
221+
1
222+
}
223+

testing/runner/tests/total-changes.sqltest

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,3 +58,38 @@ expect {
5858
2
5959
}
6060

61+
test total-changes-insert-in-transaction {
62+
create table t(id integer primary key, val text);
63+
begin;
64+
insert into t values(1, 'a'), (2, 'b'), (3, 'c');
65+
select total_changes();
66+
commit;
67+
}
68+
expect {
69+
3
70+
}
71+
72+
test total-changes-insert-in-transaction-after-commit {
73+
create table t(id integer primary key, val text);
74+
begin;
75+
insert into t values(1, 'a'), (2, 'b'), (3, 'c');
76+
commit;
77+
select total_changes();
78+
}
79+
expect {
80+
3
81+
}
82+
83+
test total-changes-multiple-stmts-in-transaction {
84+
create table t(id integer primary key, val text);
85+
insert into t values(1, 'a'), (2, 'b');
86+
begin;
87+
insert into t values(3, 'c');
88+
delete from t where id = 1;
89+
select total_changes();
90+
commit;
91+
}
92+
expect {
93+
4
94+
}
95+

0 commit comments

Comments
 (0)