1#include "duckdb/transaction/transaction.hpp"
2
3#include "duckdb/main/client_context.hpp"
4#include "duckdb/catalog/catalog_entry/table_catalog_entry.hpp"
5#include "duckdb/common/exception.hpp"
6#include "duckdb/parser/column_definition.hpp"
7#include "duckdb/storage/data_table.hpp"
8#include "duckdb/storage/write_ahead_log.hpp"
9
10#include "duckdb/transaction/delete_info.hpp"
11#include "duckdb/transaction/update_info.hpp"
12
13#include <cstring>
14
15using namespace duckdb;
16using namespace std;
17
18Transaction &Transaction::GetTransaction(ClientContext &context) {
19 return context.ActiveTransaction();
20}
21
22void Transaction::PushCatalogEntry(CatalogEntry *entry, data_ptr_t extra_data, idx_t extra_data_size) {
23 idx_t alloc_size = sizeof(CatalogEntry *);
24 if (extra_data_size > 0) {
25 alloc_size += extra_data_size + sizeof(idx_t);
26 }
27 auto baseptr = undo_buffer.CreateEntry(UndoFlags::CATALOG_ENTRY, alloc_size);
28 // store the pointer to the catalog entry
29 *((CatalogEntry **)baseptr) = entry;
30 if (extra_data_size > 0) {
31 // copy the extra data behind the catalog entry pointer (if any)
32 baseptr += sizeof(CatalogEntry *);
33 // first store the extra data size
34 *((idx_t *)baseptr) = extra_data_size;
35 baseptr += sizeof(idx_t);
36 // then copy over the actual data
37 memcpy(baseptr, extra_data, extra_data_size);
38 }
39}
40
41void Transaction::PushDelete(DataTable *table, ChunkInfo *vinfo, row_t rows[], idx_t count, idx_t base_row) {
42 auto delete_info =
43 (DeleteInfo *)undo_buffer.CreateEntry(UndoFlags::DELETE_TUPLE, sizeof(DeleteInfo) + sizeof(row_t) * count);
44 delete_info->vinfo = vinfo;
45 delete_info->table = table;
46 delete_info->count = count;
47 delete_info->base_row = base_row;
48 memcpy(delete_info->rows, rows, sizeof(row_t) * count);
49}
50
51UpdateInfo *Transaction::CreateUpdateInfo(idx_t type_size, idx_t entries) {
52 auto update_info = (UpdateInfo *)undo_buffer.CreateEntry(
53 UndoFlags::UPDATE_TUPLE, sizeof(UpdateInfo) + (sizeof(sel_t) + type_size) * entries);
54 update_info->max = entries;
55 update_info->tuples = (sel_t *)(((data_ptr_t)update_info) + sizeof(UpdateInfo));
56 update_info->tuple_data = ((data_ptr_t)update_info) + sizeof(UpdateInfo) + sizeof(sel_t) * entries;
57 update_info->version_number = transaction_id;
58 update_info->nullmask.reset();
59 return update_info;
60}
61
62string Transaction::Commit(WriteAheadLog *log, transaction_t commit_id) noexcept {
63 this->commit_id = commit_id;
64
65 UndoBuffer::IteratorState iterator_state;
66 LocalStorage::CommitState commit_state;
67 int64_t initial_wal_size;
68 if (log) {
69 initial_wal_size = log->GetWALSize();
70 }
71 bool changes_made = undo_buffer.ChangesMade() || storage.ChangesMade() || sequence_usage.size() > 0;
72 try {
73 // commit the undo buffer
74 undo_buffer.Commit(iterator_state, log, commit_id);
75 storage.Commit(commit_state, *this, log, commit_id);
76 if (log) {
77 // commit any sequences that were used to the WAL
78 for (auto &entry : sequence_usage) {
79 log->WriteSequenceValue(entry.first, entry.second);
80 }
81 // flush the WAL
82 if (changes_made) {
83 log->Flush();
84 }
85 }
86 return string();
87 } catch (std::exception &ex) {
88 undo_buffer.RevertCommit(iterator_state, transaction_id);
89 storage.RevertCommit(commit_state);
90 if (log && changes_made) {
91 // remove any entries written into the WAL by truncating it
92 log->Truncate(initial_wal_size);
93 }
94 return ex.what();
95 }
96}
97