@@ -186,6 +186,112 @@ TEST(TxnExecutorTest, DISABLED_InsertDeleteConflictTest) { // NOLINT
186
186
WithTxn (txn7, CommitTxn (*bustub, _var, _txn));
187
187
}
188
188
189
+ TEST (TxnExecutorTest, DISABLED_GenerateUndoLogTest) {
190
+ {
191
+ fmt::println (stderr, " --- GenerateUndoLogTest: Simple update ---" );
192
+ auto schema = ParseCreateStatement (" a integer,b double,c boolean" );
193
+ auto partial_schema = ParseCreateStatement (" b double,c boolean" );
194
+ auto base_tuple = Tuple{{Int (0 ), Double (0.0 ), Bool (true )}, schema.get ()};
195
+ auto target_tuple = Tuple{{Int (0 ), Double (1.0 ), Bool (false )}, schema.get ()};
196
+ auto undo_log = GenerateNewUndoLog (schema.get (), &base_tuple, &target_tuple, 0 , {});
197
+
198
+ auto tuple = ReconstructTuple (schema.get (), target_tuple, {0 , false }, {undo_log});
199
+ ASSERT_TRUE (tuple.has_value ());
200
+ ASSERT_TRUE (IsTupleContentEqual (*tuple, base_tuple));
201
+ }
202
+ {
203
+ fmt::println (stderr, " --- GenerateUndoLogTest: Simple delete ---" );
204
+ auto schema = ParseCreateStatement (" a integer,b double,c boolean" );
205
+ auto base_tuple = Tuple{{Int (0 ), Double (0.0 ), Bool (true )}, schema.get ()};
206
+ auto undo_log = GenerateNewUndoLog (schema.get (), &base_tuple, nullptr , 0 , {});
207
+
208
+ auto tuple = ReconstructTuple (schema.get (), base_tuple, {0 , true }, {undo_log});
209
+ ASSERT_TRUE (tuple.has_value ());
210
+ ASSERT_TRUE (IsTupleContentEqual (*tuple, base_tuple));
211
+ }
212
+ {
213
+ // This case is only relevant after task 4.2, where an insert may happen on a tombstone.
214
+ // Before task 4.2, insert always generates a new tuple in table heap without any undo logs.
215
+ fmt::println (stderr, " --- GenerateUndoLogTest: Simple insert ---" );
216
+ auto schema = ParseCreateStatement (" a integer,b double,c boolean" );
217
+ auto partial_schema = ParseCreateStatement (" " );
218
+ auto target_tuple = Tuple{{Int (0 ), Double (1.0 ), Bool (false )}, schema.get ()};
219
+ auto undo_log = GenerateNewUndoLog (schema.get (), nullptr , &target_tuple, 0 , {});
220
+
221
+ auto tuple = ReconstructTuple (schema.get (), target_tuple, {0 , false }, {undo_log});
222
+ ASSERT_FALSE (tuple.has_value ());
223
+ }
224
+ {
225
+ fmt::println (stderr, " --- GenerateUndoLogTest: Update twice in a txn ---" );
226
+ auto schema = ParseCreateStatement (" a integer,b double,c boolean" );
227
+ auto partial_schema = ParseCreateStatement (" b double,c boolean" );
228
+ auto base_tuple = Tuple{{Int (0 ), Double (0.0 ), Bool (true )}, schema.get ()};
229
+ auto intermidiate_tuple = Tuple{{Int (0 ), Double (0.0 ), Bool (false )}, schema.get ()};
230
+ auto undo_log = GenerateNewUndoLog (schema.get (), &base_tuple, &intermidiate_tuple, 0 , {});
231
+ auto target_tuple = Tuple{{Int (0 ), Double (1.0 ), Bool (false )}, schema.get ()};
232
+ auto updated_undo_log = GenerateUpdatedUndoLog (schema.get (), &intermidiate_tuple, &target_tuple, undo_log);
233
+
234
+ auto tuple = ReconstructTuple (schema.get (), target_tuple, {0 , false }, {updated_undo_log});
235
+ ASSERT_TRUE (tuple.has_value ());
236
+ ASSERT_TRUE (IsTupleContentEqual (*tuple, base_tuple));
237
+ }
238
+ {
239
+ fmt::println (stderr, " --- GenerateUndoLogTest: Update then delete in a txn ---" );
240
+ auto schema = ParseCreateStatement (" a integer,b double,c boolean" );
241
+ auto partial_schema = ParseCreateStatement (" b double,c boolean" );
242
+ auto base_tuple = Tuple{{Int (0 ), Double (0.0 ), Bool (true )}, schema.get ()};
243
+ auto target_tuple = Tuple{{Int (0 ), Double (1.0 ), Bool (false )}, schema.get ()};
244
+ auto undo_log = GenerateNewUndoLog (schema.get (), &base_tuple, &target_tuple, 0 , {});
245
+ auto updated_undo_log = GenerateUpdatedUndoLog (schema.get (), &target_tuple, nullptr , undo_log);
246
+
247
+ auto tuple = ReconstructTuple (schema.get (), target_tuple, {0 , true }, {updated_undo_log});
248
+ ASSERT_TRUE (tuple.has_value ());
249
+ ASSERT_TRUE (IsTupleContentEqual (*tuple, base_tuple));
250
+ }
251
+ {
252
+ // This case is only relevant after task 4.2, where an insert may happen on a tombstone.
253
+ // Before task 4.2, insert always generates a new tuple in table heap without any undo logs.
254
+ fmt::println (stderr, " --- GenerateUndoLogTest: Insert then update in a txn ---" );
255
+ auto schema = ParseCreateStatement (" a integer,b double,c boolean" );
256
+ auto partial_schema = ParseCreateStatement (" " );
257
+ auto intermediate_tuple = Tuple{{Int (0 ), Double (0.0 ), Bool (false )}, schema.get ()};
258
+ auto undo_log = GenerateNewUndoLog (schema.get (), nullptr , &intermediate_tuple, 0 , {});
259
+ auto target_tuple = Tuple{{Int (0 ), Double (1.0 ), Bool (false )}, schema.get ()};
260
+ auto updated_undo_log = GenerateUpdatedUndoLog (schema.get (), &intermediate_tuple, &target_tuple, undo_log);
261
+
262
+ auto tuple = ReconstructTuple (schema.get (), target_tuple, {0 , false }, {updated_undo_log});
263
+ ASSERT_FALSE (tuple.has_value ());
264
+ }
265
+ {
266
+ // This case is only relevant after task 4.2, where an insert may happen on a tombstone.
267
+ // Before task 4.2, insert always generates a new tuple in table heap without any undo logs.
268
+ fmt::println (stderr, " --- GenerateUndoLogTest: Insert then delete in a txn ---" );
269
+ auto schema = ParseCreateStatement (" a integer,b double,c boolean" );
270
+ auto partial_schema = ParseCreateStatement (" " );
271
+ auto intermediate_tuple = Tuple{{Int (0 ), Double (0.0 ), Bool (false )}, schema.get ()};
272
+ auto undo_log = GenerateNewUndoLog (schema.get (), nullptr , &intermediate_tuple, 0 , {});
273
+ auto updated_undo_log = GenerateUpdatedUndoLog (schema.get (), &intermediate_tuple, nullptr , undo_log);
274
+
275
+ auto tuple = ReconstructTuple (schema.get (), intermediate_tuple, {0 , true }, {updated_undo_log});
276
+ ASSERT_FALSE (tuple.has_value ());
277
+ }
278
+ {
279
+ // This case is only relevant after task 4.2, where an insert may happen on a tombstone.
280
+ // Before task 4.2, insert always generates a new tuple in table heap without any undo logs.
281
+ fmt::println (stderr, " --- GenerateUndoLogTest: Delete then insert in a txn ---" );
282
+ auto schema = ParseCreateStatement (" a integer,b double,c boolean" );
283
+ auto partial_schema = ParseCreateStatement (" b double,c boolean" );
284
+ auto base_tuple = Tuple{{Int (0 ), Double (0.0 ), Bool (true )}, schema.get ()};
285
+ auto undo_log = GenerateNewUndoLog (schema.get (), &base_tuple, nullptr , 0 , {});
286
+ auto target_tuple = Tuple{{Int (0 ), Double (1.0 ), Bool (false )}, schema.get ()};
287
+ auto updated_undo_log = GenerateUpdatedUndoLog (schema.get (), &base_tuple, &target_tuple, undo_log);
288
+
289
+ auto tuple = ReconstructTuple (schema.get (), target_tuple, {0 , false }, {updated_undo_log});
290
+ ASSERT_TRUE (tuple.has_value ());
291
+ ASSERT_TRUE (IsTupleContentEqual (*tuple, base_tuple));
292
+ }
293
+ }
294
+
189
295
TEST (TxnExecutorTest, DISABLED_UpdateTest1) { // NOLINT
190
296
fmt::println (stderr, " --- UpdateTest1: no undo log ---" );
191
297
auto bustub = std::make_unique<BusTubInstance>();
0 commit comments