duckdb 0.7.1-dev240.0 → 0.7.1-dev284.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/duckdb/src/catalog/catalog.cpp +15 -0
- package/src/duckdb/src/catalog/catalog_entry/index_catalog_entry.cpp +8 -7
- package/src/duckdb/src/execution/index/art/art.cpp +117 -67
- package/src/duckdb/src/execution/index/art/art_key.cpp +24 -12
- package/src/duckdb/src/execution/index/art/leaf.cpp +7 -8
- package/src/duckdb/src/execution/index/art/node.cpp +13 -27
- package/src/duckdb/src/execution/index/art/node16.cpp +5 -8
- package/src/duckdb/src/execution/index/art/node256.cpp +3 -5
- package/src/duckdb/src/execution/index/art/node4.cpp +4 -7
- package/src/duckdb/src/execution/index/art/node48.cpp +5 -8
- package/src/duckdb/src/execution/index/art/prefix.cpp +2 -3
- package/src/duckdb/src/function/pragma/pragma_queries.cpp +2 -2
- package/src/duckdb/src/function/table/read_csv.cpp +2 -1
- package/src/duckdb/src/function/table/table_scan.cpp +3 -0
- package/src/duckdb/src/function/table/version/pragma_version.cpp +2 -2
- package/src/duckdb/src/include/duckdb/catalog/catalog.hpp +5 -1
- package/src/duckdb/src/include/duckdb/catalog/catalog_entry/duck_index_entry.hpp +1 -1
- package/src/duckdb/src/include/duckdb/catalog/catalog_entry/index_catalog_entry.hpp +1 -1
- package/src/duckdb/src/include/duckdb/common/enums/wal_type.hpp +3 -0
- package/src/duckdb/src/include/duckdb/execution/index/art/art.hpp +37 -41
- package/src/duckdb/src/include/duckdb/execution/index/art/art_key.hpp +8 -11
- package/src/duckdb/src/include/duckdb/planner/binder.hpp +3 -0
- package/src/duckdb/src/include/duckdb/planner/expression_binder/index_binder.hpp +10 -3
- package/src/duckdb/src/include/duckdb/storage/data_table.hpp +7 -1
- package/src/duckdb/src/include/duckdb/storage/index.hpp +47 -38
- package/src/duckdb/src/include/duckdb/storage/write_ahead_log.hpp +7 -0
- package/src/duckdb/src/parser/parsed_data/create_index_info.cpp +3 -0
- package/src/duckdb/src/planner/binder/statement/bind_create_table.cpp +13 -0
- package/src/duckdb/src/planner/expression_binder/index_binder.cpp +32 -1
- package/src/duckdb/src/storage/compression/bitpacking.cpp +16 -7
- package/src/duckdb/src/storage/data_table.cpp +66 -3
- package/src/duckdb/src/storage/index.cpp +1 -1
- package/src/duckdb/src/storage/local_storage.cpp +1 -1
- package/src/duckdb/src/storage/table_index_list.cpp +1 -2
- package/src/duckdb/src/storage/wal_replay.cpp +68 -0
- package/src/duckdb/src/storage/write_ahead_log.cpp +21 -1
- package/src/duckdb/src/transaction/commit_state.cpp +5 -2
- package/src/statement.cpp +46 -12
- package/test/prepare.test.ts +39 -1
- package/test/typescript_decls.test.ts +1 -1
|
@@ -28,24 +28,24 @@ public:
|
|
|
28
28
|
|
|
29
29
|
public:
|
|
30
30
|
template <class T>
|
|
31
|
-
static inline Key CreateKey(ArenaAllocator &allocator, T element) {
|
|
31
|
+
static inline Key CreateKey(ArenaAllocator &allocator, const LogicalType &type, T element) {
|
|
32
32
|
auto data = Key::CreateData<T>(allocator, element);
|
|
33
33
|
return Key(data, sizeof(element));
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
template <class T>
|
|
37
|
-
static inline Key CreateKey(ArenaAllocator &allocator, const Value &element) {
|
|
38
|
-
return CreateKey(allocator, element.GetValueUnsafe<T>());
|
|
37
|
+
static inline Key CreateKey(ArenaAllocator &allocator, const LogicalType &type, const Value &element) {
|
|
38
|
+
return CreateKey(allocator, type, element.GetValueUnsafe<T>());
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
template <class T>
|
|
42
|
-
static inline void CreateKey(ArenaAllocator &allocator, Key &key, T element) {
|
|
42
|
+
static inline void CreateKey(ArenaAllocator &allocator, const LogicalType &type, Key &key, T element) {
|
|
43
43
|
key.data = Key::CreateData<T>(allocator, element);
|
|
44
44
|
key.len = sizeof(element);
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
template <class T>
|
|
48
|
-
static inline void CreateKey(ArenaAllocator &allocator, Key &key, const Value element) {
|
|
48
|
+
static inline void CreateKey(ArenaAllocator &allocator, const LogicalType &type, Key &key, const Value element) {
|
|
49
49
|
key.data = Key::CreateData<T>(allocator, element.GetValueUnsafe<T>());
|
|
50
50
|
key.len = sizeof(element);
|
|
51
51
|
}
|
|
@@ -76,12 +76,9 @@ private:
|
|
|
76
76
|
};
|
|
77
77
|
|
|
78
78
|
template <>
|
|
79
|
-
Key Key::CreateKey(ArenaAllocator &allocator, string_t value);
|
|
79
|
+
Key Key::CreateKey(ArenaAllocator &allocator, const LogicalType &type, string_t value);
|
|
80
80
|
template <>
|
|
81
|
-
Key Key::CreateKey(ArenaAllocator &allocator, const char *value);
|
|
81
|
+
Key Key::CreateKey(ArenaAllocator &allocator, const LogicalType &type, const char *value);
|
|
82
82
|
template <>
|
|
83
|
-
void Key::CreateKey(ArenaAllocator &allocator, Key &key, string_t value);
|
|
84
|
-
template <>
|
|
85
|
-
void Key::CreateKey(ArenaAllocator &allocator, Key &key, const char *value);
|
|
86
|
-
|
|
83
|
+
void Key::CreateKey(ArenaAllocator &allocator, const LogicalType &type, Key &key, string_t value);
|
|
87
84
|
} // namespace duckdb
|
|
@@ -108,6 +108,9 @@ public:
|
|
|
108
108
|
|
|
109
109
|
unique_ptr<BoundCreateTableInfo> BindCreateTableInfo(unique_ptr<CreateInfo> info);
|
|
110
110
|
unique_ptr<BoundCreateTableInfo> BindCreateTableInfo(unique_ptr<CreateInfo> info, SchemaCatalogEntry *schema);
|
|
111
|
+
|
|
112
|
+
vector<unique_ptr<Expression>> BindCreateIndexExpressions(TableCatalogEntry *table, CreateIndexInfo *info);
|
|
113
|
+
|
|
111
114
|
void BindCreateViewInfo(CreateViewInfo &base);
|
|
112
115
|
SchemaCatalogEntry *BindSchema(CreateInfo &info);
|
|
113
116
|
SchemaCatalogEntry *BindCreateFunctionInfo(CreateInfo &info);
|
|
@@ -10,20 +10,27 @@
|
|
|
10
10
|
|
|
11
11
|
#include "duckdb/planner/expression_binder.hpp"
|
|
12
12
|
#include "duckdb/common/unordered_map.hpp"
|
|
13
|
+
#include "duckdb/parser/parsed_data/create_index_info.hpp"
|
|
14
|
+
#include "duckdb/catalog/catalog_entry/table_catalog_entry.hpp"
|
|
13
15
|
|
|
14
16
|
namespace duckdb {
|
|
15
17
|
class BoundColumnRefExpression;
|
|
16
18
|
|
|
17
|
-
//! The
|
|
19
|
+
//! The IndexBinder is responsible for binding an expression within an index statement
|
|
18
20
|
class IndexBinder : public ExpressionBinder {
|
|
19
21
|
public:
|
|
20
|
-
IndexBinder(Binder &binder, ClientContext &context
|
|
22
|
+
IndexBinder(Binder &binder, ClientContext &context, TableCatalogEntry *table = nullptr,
|
|
23
|
+
CreateIndexInfo *info = nullptr);
|
|
21
24
|
|
|
22
25
|
protected:
|
|
23
26
|
BindResult BindExpression(unique_ptr<ParsedExpression> *expr_ptr, idx_t depth,
|
|
24
27
|
bool root_expression = false) override;
|
|
25
|
-
|
|
26
28
|
string UnsupportedAggregateMessage() override;
|
|
29
|
+
|
|
30
|
+
private:
|
|
31
|
+
// only for WAL replay
|
|
32
|
+
TableCatalogEntry *table;
|
|
33
|
+
CreateIndexInfo *info;
|
|
27
34
|
};
|
|
28
35
|
|
|
29
36
|
} // namespace duckdb
|
|
@@ -122,6 +122,12 @@ public:
|
|
|
122
122
|
void UpdateColumn(TableCatalogEntry &table, ClientContext &context, Vector &row_ids,
|
|
123
123
|
const vector<column_t> &column_path, DataChunk &updates);
|
|
124
124
|
|
|
125
|
+
//! Add an index to the DataTable. NOTE: for CREATE (UNIQUE) INDEX statements, we use the PhysicalCreateIndex
|
|
126
|
+
//! operator. This function is only used during the WAL replay, and is a much less performant index creation
|
|
127
|
+
//! approach.
|
|
128
|
+
void WALAddIndex(ClientContext &context, unique_ptr<Index> index,
|
|
129
|
+
const vector<unique_ptr<Expression>> &expressions);
|
|
130
|
+
|
|
125
131
|
//! Fetches an append lock
|
|
126
132
|
void AppendLock(TableAppendState &state);
|
|
127
133
|
//! Begin appending structs to this table, obtaining necessary locks, etc
|
|
@@ -176,7 +182,7 @@ public:
|
|
|
176
182
|
static bool IsForeignKeyIndex(const vector<PhysicalIndex> &fk_keys, Index &index, ForeignKeyType fk_type);
|
|
177
183
|
|
|
178
184
|
//! Initializes a special scan that is used to create an index on the table, it keeps locks on the table
|
|
179
|
-
void
|
|
185
|
+
void InitializeWALCreateIndexScan(CreateIndexScanState &state, const vector<column_t> &column_ids);
|
|
180
186
|
//! Scans the next chunk for the CREATE INDEX operator
|
|
181
187
|
bool CreateIndexScan(TableScanState &state, DataChunk &result, TableScanType type);
|
|
182
188
|
|
|
@@ -40,11 +40,11 @@ public:
|
|
|
40
40
|
IndexType type;
|
|
41
41
|
//! Associated table io manager
|
|
42
42
|
TableIOManager &table_io_manager;
|
|
43
|
-
//! Column identifiers to extract from the base table
|
|
43
|
+
//! Column identifiers to extract key columns from the base table
|
|
44
44
|
vector<column_t> column_ids;
|
|
45
|
-
//!
|
|
45
|
+
//! Unordered set of column_ids used by the index
|
|
46
46
|
unordered_set<column_t> column_id_set;
|
|
47
|
-
//! Unbound expressions used by the index
|
|
47
|
+
//! Unbound expressions used by the index during optimizations
|
|
48
48
|
vector<unique_ptr<Expression>> unbound_expressions;
|
|
49
49
|
//! The physical types stored in the index
|
|
50
50
|
vector<PhysicalType> types;
|
|
@@ -64,94 +64,103 @@ public:
|
|
|
64
64
|
bool track_memory;
|
|
65
65
|
|
|
66
66
|
public:
|
|
67
|
-
//! Initialize a scan on the index with the given expression and column
|
|
68
|
-
//! to fetch from the base table when we only have one query predicate
|
|
67
|
+
//! Initialize a single predicate scan on the index with the given expression and column IDs
|
|
69
68
|
virtual unique_ptr<IndexScanState> InitializeScanSinglePredicate(const Transaction &transaction, const Value &value,
|
|
70
69
|
ExpressionType expressionType) = 0;
|
|
71
|
-
//! Initialize a scan on the index with the given expression and column
|
|
72
|
-
//! to fetch from the base table for two query predicates
|
|
70
|
+
//! Initialize a two predicate scan on the index with the given expression and column IDs
|
|
73
71
|
virtual unique_ptr<IndexScanState> InitializeScanTwoPredicates(Transaction &transaction, const Value &low_value,
|
|
74
72
|
ExpressionType low_expression_type,
|
|
75
73
|
const Value &high_value,
|
|
76
74
|
ExpressionType high_expression_type) = 0;
|
|
77
|
-
//!
|
|
78
|
-
//! and false otherwise
|
|
75
|
+
//! Performs a lookup on the index, fetching up to max_count result IDs. Returns true if all row IDs were fetched,
|
|
76
|
+
//! and false otherwise
|
|
79
77
|
virtual bool Scan(Transaction &transaction, DataTable &table, IndexScanState &state, idx_t max_count,
|
|
80
78
|
vector<row_t> &result_ids) = 0;
|
|
81
79
|
|
|
82
80
|
//! Obtain a lock on the index
|
|
83
81
|
virtual void InitializeLock(IndexLock &state);
|
|
84
|
-
//! Called when data is appended to the index. The lock obtained from
|
|
82
|
+
//! Called when data is appended to the index. The lock obtained from InitializeLock must be held
|
|
85
83
|
virtual bool Append(IndexLock &state, DataChunk &entries, Vector &row_identifiers) = 0;
|
|
84
|
+
//! Obtains a lock and calls Append while holding that lock
|
|
86
85
|
bool Append(DataChunk &entries, Vector &row_identifiers);
|
|
87
|
-
//! Verify that data can be appended to the index
|
|
86
|
+
//! Verify that data can be appended to the index without a constraint violation
|
|
88
87
|
virtual void VerifyAppend(DataChunk &chunk) = 0;
|
|
89
|
-
//! Verify that data can be appended to the index
|
|
88
|
+
//! Verify that data can be appended to the index without a constraint violation using the conflict manager
|
|
90
89
|
virtual void VerifyAppend(DataChunk &chunk, ConflictManager &conflict_manager) = 0;
|
|
91
|
-
//!
|
|
92
|
-
virtual void
|
|
93
|
-
//! Verify that data can be delete from the index for foreign key constraint
|
|
94
|
-
virtual void VerifyDeleteForeignKey(DataChunk &chunk) = 0;
|
|
90
|
+
//! Performs constraint checking for a chunk of input data
|
|
91
|
+
virtual void CheckConstraintsForChunk(DataChunk &input, ConflictManager &conflict_manager) = 0;
|
|
95
92
|
|
|
96
|
-
//!
|
|
93
|
+
//! Delete a chunk of entries from the index. The lock obtained from InitializeLock must be held
|
|
97
94
|
virtual void Delete(IndexLock &state, DataChunk &entries, Vector &row_identifiers) = 0;
|
|
95
|
+
//! Obtains a lock and calls Delete while holding that lock
|
|
98
96
|
void Delete(DataChunk &entries, Vector &row_identifiers);
|
|
99
97
|
|
|
100
|
-
//! Insert
|
|
98
|
+
//! Insert a chunk of entries into the index
|
|
101
99
|
virtual bool Insert(IndexLock &lock, DataChunk &input, Vector &row_identifiers) = 0;
|
|
102
100
|
|
|
103
|
-
//! Merge
|
|
101
|
+
//! Merge another index into this index. The lock obtained from InitializeLock must be held, and the other
|
|
102
|
+
//! index must also be locked during the merge
|
|
104
103
|
virtual bool MergeIndexes(IndexLock &state, Index *other_index) = 0;
|
|
104
|
+
//! Obtains a lock and calls MergeIndexes while holding that lock
|
|
105
105
|
bool MergeIndexes(Index *other_index);
|
|
106
106
|
|
|
107
107
|
//! Returns the string representation of an index
|
|
108
108
|
virtual string ToString() = 0;
|
|
109
|
-
//! Verifies that the
|
|
109
|
+
//! Verifies that the in-memory size value of the index matches its actual size
|
|
110
110
|
virtual void Verify() = 0;
|
|
111
|
-
|
|
112
|
-
//!
|
|
111
|
+
//! Increases the memory size by the difference between the old size and the current size
|
|
112
|
+
//! and performs verifications
|
|
113
|
+
virtual void IncreaseAndVerifyMemorySize(idx_t old_memory_size) = 0;
|
|
114
|
+
|
|
115
|
+
//! Increases the in-memory size value
|
|
116
|
+
inline void IncreaseMemorySize(idx_t size) {
|
|
117
|
+
memory_size += size;
|
|
118
|
+
};
|
|
119
|
+
//! Decreases the in-memory size value
|
|
120
|
+
inline void DecreaseMemorySize(idx_t size) {
|
|
121
|
+
D_ASSERT(memory_size >= size);
|
|
122
|
+
memory_size -= size;
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
//! Returns true if the index is affected by updates on the specified column IDs, and false otherwise
|
|
113
126
|
bool IndexIsUpdated(const vector<PhysicalIndex> &column_ids) const;
|
|
114
127
|
|
|
115
|
-
//! Returns how many of the input values were found in the 'input' chunk, with the option to also record what those
|
|
116
|
-
//! matches were. For this purpose, nulls count as a match, and are returned in 'null_count'
|
|
117
|
-
virtual void LookupValues(DataChunk &input, ConflictManager &conflict_manager) = 0;
|
|
118
|
-
|
|
119
128
|
//! Returns unique flag
|
|
120
129
|
bool IsUnique() {
|
|
121
130
|
return (constraint_type == IndexConstraintType::UNIQUE || constraint_type == IndexConstraintType::PRIMARY);
|
|
122
131
|
}
|
|
123
|
-
//! Returns primary flag
|
|
132
|
+
//! Returns primary key flag
|
|
124
133
|
bool IsPrimary() {
|
|
125
134
|
return (constraint_type == IndexConstraintType::PRIMARY);
|
|
126
135
|
}
|
|
127
|
-
//! Returns foreign flag
|
|
136
|
+
//! Returns foreign key flag
|
|
128
137
|
bool IsForeign() {
|
|
129
138
|
return (constraint_type == IndexConstraintType::FOREIGN);
|
|
130
139
|
}
|
|
131
|
-
//! Serializes the index and returns the pair of block_id offset positions
|
|
132
|
-
virtual BlockPointer Serialize(duckdb::MetaBlockWriter &writer);
|
|
133
|
-
BlockPointer GetBlockPointer();
|
|
134
140
|
|
|
135
|
-
//!
|
|
141
|
+
//! Serializes the index and returns the pair of block_id offset positions
|
|
142
|
+
virtual BlockPointer Serialize(MetaBlockWriter &writer);
|
|
143
|
+
//! Returns the serialized data pointer to the block and offset of the serialized index
|
|
136
144
|
BlockPointer GetSerializedDataPointer() const {
|
|
137
145
|
return serialized_data_pointer;
|
|
138
146
|
}
|
|
139
147
|
|
|
140
|
-
|
|
148
|
+
//! Execute the index expressions on an input chunk
|
|
141
149
|
void ExecuteExpressions(DataChunk &input, DataChunk &result);
|
|
142
150
|
|
|
143
|
-
|
|
151
|
+
protected:
|
|
152
|
+
//! Lock used for any changes to the index
|
|
144
153
|
mutex lock;
|
|
145
|
-
|
|
146
|
-
//! Pointer to most recently checkpointed index data.
|
|
154
|
+
//! Pointer to serialized index data
|
|
147
155
|
BlockPointer serialized_data_pointer;
|
|
148
156
|
|
|
149
157
|
private:
|
|
150
|
-
//! Bound expressions used
|
|
158
|
+
//! Bound expressions used during expression execution
|
|
151
159
|
vector<unique_ptr<Expression>> bound_expressions;
|
|
152
|
-
//! Expression executor
|
|
160
|
+
//! Expression executor to execute the index expressions
|
|
153
161
|
ExpressionExecutor executor;
|
|
154
162
|
|
|
163
|
+
//! Bind the unbound expressions of the index
|
|
155
164
|
unique_ptr<Expression> BindExpression(unique_ptr<Expression> expr);
|
|
156
165
|
};
|
|
157
166
|
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
#include "duckdb/catalog/catalog_entry/scalar_macro_catalog_entry.hpp"
|
|
16
16
|
#include "duckdb/catalog/catalog_entry/sequence_catalog_entry.hpp"
|
|
17
17
|
#include "duckdb/catalog/catalog_entry/table_macro_catalog_entry.hpp"
|
|
18
|
+
#include "duckdb/catalog/catalog_entry/index_catalog_entry.hpp"
|
|
18
19
|
#include "duckdb/main/attached_database.hpp"
|
|
19
20
|
#include "duckdb/storage/storage_info.hpp"
|
|
20
21
|
|
|
@@ -77,6 +78,9 @@ protected:
|
|
|
77
78
|
void ReplayCreateTableMacro();
|
|
78
79
|
void ReplayDropTableMacro();
|
|
79
80
|
|
|
81
|
+
void ReplayCreateIndex();
|
|
82
|
+
void ReplayDropIndex();
|
|
83
|
+
|
|
80
84
|
void ReplayUseTable();
|
|
81
85
|
void ReplayInsert();
|
|
82
86
|
void ReplayDelete();
|
|
@@ -125,6 +129,9 @@ public:
|
|
|
125
129
|
void WriteCreateTableMacro(TableMacroCatalogEntry *entry);
|
|
126
130
|
void WriteDropTableMacro(TableMacroCatalogEntry *entry);
|
|
127
131
|
|
|
132
|
+
void WriteCreateIndex(IndexCatalogEntry *entry);
|
|
133
|
+
void WriteDropIndex(IndexCatalogEntry *entry);
|
|
134
|
+
|
|
128
135
|
void WriteCreateType(TypeCatalogEntry *entry);
|
|
129
136
|
void WriteDropType(TypeCatalogEntry *entry);
|
|
130
137
|
//! Sets the table used for subsequent insert/delete/update commands
|
|
@@ -16,6 +16,9 @@ unique_ptr<CreateInfo> CreateIndexInfo::Copy() const {
|
|
|
16
16
|
for (auto &expr : expressions) {
|
|
17
17
|
result->expressions.push_back(expr->Copy());
|
|
18
18
|
}
|
|
19
|
+
for (auto &expr : parsed_expressions) {
|
|
20
|
+
result->parsed_expressions.push_back(expr->Copy());
|
|
21
|
+
}
|
|
19
22
|
|
|
20
23
|
result->scan_types = scan_types;
|
|
21
24
|
result->names = names;
|
|
@@ -16,6 +16,8 @@
|
|
|
16
16
|
#include "duckdb/parser/expression/list.hpp"
|
|
17
17
|
#include "duckdb/common/index_map.hpp"
|
|
18
18
|
#include "duckdb/planner/expression_iterator.hpp"
|
|
19
|
+
#include "duckdb/planner/expression_binder/index_binder.hpp"
|
|
20
|
+
#include "duckdb/parser/parsed_data/create_index_info.hpp"
|
|
19
21
|
|
|
20
22
|
#include <algorithm>
|
|
21
23
|
|
|
@@ -300,4 +302,15 @@ unique_ptr<BoundCreateTableInfo> Binder::BindCreateTableInfo(unique_ptr<CreateIn
|
|
|
300
302
|
return BindCreateTableInfo(std::move(info), schema);
|
|
301
303
|
}
|
|
302
304
|
|
|
305
|
+
vector<unique_ptr<Expression>> Binder::BindCreateIndexExpressions(TableCatalogEntry *table, CreateIndexInfo *info) {
|
|
306
|
+
vector<unique_ptr<Expression>> expressions;
|
|
307
|
+
|
|
308
|
+
auto index_binder = IndexBinder(*this, this->context, table, info);
|
|
309
|
+
for (auto &expr : info->expressions) {
|
|
310
|
+
expressions.push_back(index_binder.Bind(expr));
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
return expressions;
|
|
314
|
+
}
|
|
315
|
+
|
|
303
316
|
} // namespace duckdb
|
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
#include "duckdb/planner/expression_binder/index_binder.hpp"
|
|
2
2
|
|
|
3
|
+
#include "duckdb/parser/parsed_data/create_index_info.hpp"
|
|
4
|
+
#include "duckdb/parser/expression/columnref_expression.hpp"
|
|
5
|
+
#include "duckdb/planner/expression/bound_columnref_expression.hpp"
|
|
6
|
+
#include "duckdb/planner/column_binding.hpp"
|
|
7
|
+
|
|
3
8
|
namespace duckdb {
|
|
4
9
|
|
|
5
|
-
IndexBinder::IndexBinder(Binder &binder, ClientContext &context
|
|
10
|
+
IndexBinder::IndexBinder(Binder &binder, ClientContext &context, TableCatalogEntry *table, CreateIndexInfo *info)
|
|
11
|
+
: ExpressionBinder(binder, context), table(table), info(info) {
|
|
6
12
|
}
|
|
7
13
|
|
|
8
14
|
BindResult IndexBinder::BindExpression(unique_ptr<ParsedExpression> *expr_ptr, idx_t depth, bool root_expression) {
|
|
@@ -12,6 +18,31 @@ BindResult IndexBinder::BindExpression(unique_ptr<ParsedExpression> *expr_ptr, i
|
|
|
12
18
|
return BindResult("window functions are not allowed in index expressions");
|
|
13
19
|
case ExpressionClass::SUBQUERY:
|
|
14
20
|
return BindResult("cannot use subquery in index expressions");
|
|
21
|
+
case ExpressionClass::COLUMN_REF: {
|
|
22
|
+
if (table) {
|
|
23
|
+
// WAL replay
|
|
24
|
+
// we assume that the parsed expressions have qualified column names
|
|
25
|
+
// and that the columns exist in the table
|
|
26
|
+
auto &col_ref = (ColumnRefExpression &)expr;
|
|
27
|
+
auto col_idx = table->GetColumnIndex(col_ref.column_names.back());
|
|
28
|
+
auto col_type = table->GetColumn(col_idx).GetType();
|
|
29
|
+
|
|
30
|
+
// find the col_idx in the index.column_ids
|
|
31
|
+
auto col_id_idx = DConstants::INVALID_INDEX;
|
|
32
|
+
for (idx_t i = 0; i < info->column_ids.size(); i++) {
|
|
33
|
+
if (col_idx.index == info->column_ids[i]) {
|
|
34
|
+
col_id_idx = i;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (col_id_idx == DConstants::INVALID_INDEX) {
|
|
39
|
+
throw InternalException("failed to replay CREATE INDEX statement - column id not found");
|
|
40
|
+
}
|
|
41
|
+
return BindResult(
|
|
42
|
+
make_unique<BoundColumnRefExpression>(col_ref.alias, col_type, ColumnBinding(0, col_id_idx)));
|
|
43
|
+
}
|
|
44
|
+
return ExpressionBinder::BindExpression(expr_ptr, depth);
|
|
45
|
+
}
|
|
15
46
|
default:
|
|
16
47
|
return ExpressionBinder::BindExpression(expr_ptr, depth);
|
|
17
48
|
}
|
|
@@ -447,8 +447,8 @@ public:
|
|
|
447
447
|
|
|
448
448
|
static void ReserveSpace(BitpackingCompressState<T> *state, idx_t data_bytes) {
|
|
449
449
|
idx_t meta_bytes = sizeof(bitpacking_metadata_encoded_t);
|
|
450
|
-
state->FlushAndCreateSegmentIfFull(data_bytes
|
|
451
|
-
D_ASSERT(data_bytes
|
|
450
|
+
state->FlushAndCreateSegmentIfFull(data_bytes, meta_bytes);
|
|
451
|
+
D_ASSERT(state->CanStore(data_bytes, meta_bytes));
|
|
452
452
|
}
|
|
453
453
|
|
|
454
454
|
static void UpdateStats(BitpackingCompressState<T> *state, idx_t count) {
|
|
@@ -461,9 +461,12 @@ public:
|
|
|
461
461
|
}
|
|
462
462
|
};
|
|
463
463
|
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
464
|
+
bool CanStore(idx_t data_bytes, idx_t meta_bytes) {
|
|
465
|
+
auto required_data_bytes = AlignValue<idx_t>((data_ptr + data_bytes) - data_ptr);
|
|
466
|
+
auto required_meta_bytes = Storage::BLOCK_SIZE - (metadata_ptr - data_ptr) + meta_bytes;
|
|
467
|
+
|
|
468
|
+
return required_data_bytes + required_meta_bytes <=
|
|
469
|
+
Storage::BLOCK_SIZE - BitpackingPrimitives::BITPACKING_HEADER_SIZE;
|
|
467
470
|
}
|
|
468
471
|
|
|
469
472
|
void CreateEmptySegment(idx_t row_start) {
|
|
@@ -489,8 +492,8 @@ public:
|
|
|
489
492
|
}
|
|
490
493
|
}
|
|
491
494
|
|
|
492
|
-
void FlushAndCreateSegmentIfFull(idx_t
|
|
493
|
-
if (
|
|
495
|
+
void FlushAndCreateSegmentIfFull(idx_t required_data_bytes, idx_t required_meta_bytes) {
|
|
496
|
+
if (!CanStore(required_data_bytes, required_meta_bytes)) {
|
|
494
497
|
auto row_start = current_segment->start + current_segment->count;
|
|
495
498
|
FlushSegment();
|
|
496
499
|
CreateEmptySegment(row_start);
|
|
@@ -505,6 +508,12 @@ public:
|
|
|
505
508
|
idx_t metadata_offset = AlignValue(data_ptr - base_ptr);
|
|
506
509
|
idx_t metadata_size = base_ptr + Storage::BLOCK_SIZE - metadata_ptr;
|
|
507
510
|
idx_t total_segment_size = metadata_offset + metadata_size;
|
|
511
|
+
|
|
512
|
+
// Asserting things are still sane here
|
|
513
|
+
if (!CanStore(0, 0)) {
|
|
514
|
+
throw InternalException("Error in bitpacking size calculation");
|
|
515
|
+
}
|
|
516
|
+
|
|
508
517
|
memmove(base_ptr + metadata_offset, metadata_ptr, metadata_size);
|
|
509
518
|
|
|
510
519
|
// Store the offset of the metadata of the first group (which is at the highest address).
|
|
@@ -1144,15 +1144,78 @@ void DataTable::UpdateColumn(TableCatalogEntry &table, ClientContext &context, V
|
|
|
1144
1144
|
}
|
|
1145
1145
|
|
|
1146
1146
|
//===--------------------------------------------------------------------===//
|
|
1147
|
-
//
|
|
1147
|
+
// Index Scan
|
|
1148
1148
|
//===--------------------------------------------------------------------===//
|
|
1149
|
-
void DataTable::
|
|
1149
|
+
void DataTable::InitializeWALCreateIndexScan(CreateIndexScanState &state, const vector<column_t> &column_ids) {
|
|
1150
1150
|
// we grab the append lock to make sure nothing is appended until AFTER we finish the index scan
|
|
1151
1151
|
state.append_lock = std::unique_lock<mutex>(append_lock);
|
|
1152
|
-
row_groups->InitializeCreateIndexScan(state);
|
|
1153
1152
|
InitializeScan(state, column_ids);
|
|
1154
1153
|
}
|
|
1155
1154
|
|
|
1155
|
+
void DataTable::WALAddIndex(ClientContext &context, unique_ptr<Index> index,
|
|
1156
|
+
const vector<unique_ptr<Expression>> &expressions) {
|
|
1157
|
+
|
|
1158
|
+
// if the data table is empty
|
|
1159
|
+
if (row_groups->IsEmpty()) {
|
|
1160
|
+
info->indexes.AddIndex(std::move(index));
|
|
1161
|
+
return;
|
|
1162
|
+
}
|
|
1163
|
+
|
|
1164
|
+
auto &allocator = Allocator::Get(db);
|
|
1165
|
+
|
|
1166
|
+
DataChunk result;
|
|
1167
|
+
result.Initialize(allocator, index->logical_types);
|
|
1168
|
+
|
|
1169
|
+
DataChunk intermediate;
|
|
1170
|
+
vector<LogicalType> intermediate_types;
|
|
1171
|
+
auto column_ids = index->column_ids;
|
|
1172
|
+
column_ids.push_back(COLUMN_IDENTIFIER_ROW_ID);
|
|
1173
|
+
for (auto &id : index->column_ids) {
|
|
1174
|
+
auto &col = column_definitions[id];
|
|
1175
|
+
intermediate_types.push_back(col.Type());
|
|
1176
|
+
}
|
|
1177
|
+
intermediate_types.emplace_back(LogicalType::ROW_TYPE);
|
|
1178
|
+
intermediate.Initialize(allocator, intermediate_types);
|
|
1179
|
+
|
|
1180
|
+
// initialize an index scan
|
|
1181
|
+
CreateIndexScanState state;
|
|
1182
|
+
InitializeWALCreateIndexScan(state, column_ids);
|
|
1183
|
+
|
|
1184
|
+
if (!is_root) {
|
|
1185
|
+
throw InternalException("Error during WAL replay. Cannot add an index to a table that has been altered.");
|
|
1186
|
+
}
|
|
1187
|
+
|
|
1188
|
+
// now start incrementally building the index
|
|
1189
|
+
{
|
|
1190
|
+
IndexLock lock;
|
|
1191
|
+
index->InitializeLock(lock);
|
|
1192
|
+
|
|
1193
|
+
while (true) {
|
|
1194
|
+
intermediate.Reset();
|
|
1195
|
+
result.Reset();
|
|
1196
|
+
// scan a new chunk from the table to index
|
|
1197
|
+
CreateIndexScan(state, intermediate, TableScanType::TABLE_SCAN_COMMITTED_ROWS_OMIT_PERMANENTLY_DELETED);
|
|
1198
|
+
if (intermediate.size() == 0) {
|
|
1199
|
+
// finished scanning for index creation
|
|
1200
|
+
// release all locks
|
|
1201
|
+
break;
|
|
1202
|
+
}
|
|
1203
|
+
// resolve the expressions for this chunk
|
|
1204
|
+
index->ExecuteExpressions(intermediate, result);
|
|
1205
|
+
|
|
1206
|
+
// insert into the index
|
|
1207
|
+
if (!index->Insert(lock, result, intermediate.data[intermediate.ColumnCount() - 1])) {
|
|
1208
|
+
throw InternalException("Error during WAL replay. Can't create unique index, table contains "
|
|
1209
|
+
"duplicate data on indexed column(s).");
|
|
1210
|
+
}
|
|
1211
|
+
}
|
|
1212
|
+
}
|
|
1213
|
+
info->indexes.AddIndex(std::move(index));
|
|
1214
|
+
}
|
|
1215
|
+
|
|
1216
|
+
//===--------------------------------------------------------------------===//
|
|
1217
|
+
// Statistics
|
|
1218
|
+
//===--------------------------------------------------------------------===//
|
|
1156
1219
|
unique_ptr<BaseStatistics> DataTable::GetStatistics(ClientContext &context, column_t column_id) {
|
|
1157
1220
|
if (column_id == COLUMN_IDENTIFIER_ROW_ID) {
|
|
1158
1221
|
return nullptr;
|
|
@@ -86,7 +86,7 @@ bool Index::IndexIsUpdated(const vector<PhysicalIndex> &column_ids) const {
|
|
|
86
86
|
return false;
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
-
BlockPointer Index::Serialize(
|
|
89
|
+
BlockPointer Index::Serialize(MetaBlockWriter &writer) {
|
|
90
90
|
throw NotImplementedException("The implementation of this index serialization does not exist.");
|
|
91
91
|
}
|
|
92
92
|
|
|
@@ -127,7 +127,7 @@ LocalTableStorage::LocalTableStorage(DataTable &table)
|
|
|
127
127
|
unbound_expressions.push_back(expr->Copy());
|
|
128
128
|
}
|
|
129
129
|
indexes.AddIndex(make_unique<ART>(art.column_ids, art.table_io_manager, std::move(unbound_expressions),
|
|
130
|
-
art.constraint_type, art.db,
|
|
130
|
+
art.constraint_type, art.db, true));
|
|
131
131
|
}
|
|
132
132
|
return false;
|
|
133
133
|
});
|
|
@@ -60,8 +60,7 @@ void TableIndexList::VerifyForeignKey(const vector<PhysicalIndex> &fk_keys, Data
|
|
|
60
60
|
throw InternalException("Internal Foreign Key error: could not find index to verify...");
|
|
61
61
|
}
|
|
62
62
|
conflict_manager.SetIndexCount(1);
|
|
63
|
-
|
|
64
|
-
index->LookupValues(chunk, conflict_manager);
|
|
63
|
+
index->CheckConstraintsForChunk(chunk, conflict_manager);
|
|
65
64
|
}
|
|
66
65
|
|
|
67
66
|
vector<column_t> TableIndexList::GetRequiredColumns() {
|
|
@@ -18,6 +18,8 @@
|
|
|
18
18
|
#include "duckdb/storage/write_ahead_log.hpp"
|
|
19
19
|
#include "duckdb/storage/storage_manager.hpp"
|
|
20
20
|
#include "duckdb/main/attached_database.hpp"
|
|
21
|
+
#include "duckdb/execution/index/art/art.hpp"
|
|
22
|
+
#include "duckdb/catalog/catalog_entry/duck_index_entry.hpp"
|
|
21
23
|
|
|
22
24
|
namespace duckdb {
|
|
23
25
|
|
|
@@ -154,6 +156,12 @@ void ReplayState::ReplayEntry(WALType entry_type) {
|
|
|
154
156
|
case WALType::DROP_TABLE_MACRO:
|
|
155
157
|
ReplayDropTableMacro();
|
|
156
158
|
break;
|
|
159
|
+
case WALType::CREATE_INDEX:
|
|
160
|
+
ReplayCreateIndex();
|
|
161
|
+
break;
|
|
162
|
+
case WALType::DROP_INDEX:
|
|
163
|
+
ReplayDropIndex();
|
|
164
|
+
break;
|
|
157
165
|
case WALType::USE_TABLE:
|
|
158
166
|
ReplayUseTable();
|
|
159
167
|
break;
|
|
@@ -379,6 +387,66 @@ void ReplayState::ReplayDropTableMacro() {
|
|
|
379
387
|
catalog.DropEntry(context, &info);
|
|
380
388
|
}
|
|
381
389
|
|
|
390
|
+
//===--------------------------------------------------------------------===//
|
|
391
|
+
// Replay Index
|
|
392
|
+
//===--------------------------------------------------------------------===//
|
|
393
|
+
void ReplayState::ReplayCreateIndex() {
|
|
394
|
+
|
|
395
|
+
auto info = IndexCatalogEntry::Deserialize(source, context);
|
|
396
|
+
if (deserialize_only) {
|
|
397
|
+
return;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
// get the physical table to which we'll add the index
|
|
401
|
+
auto table = catalog.GetEntry<TableCatalogEntry>(context, info->schema, info->table->table_name);
|
|
402
|
+
auto &data_table = table->GetStorage();
|
|
403
|
+
|
|
404
|
+
// bind the parsed expressions
|
|
405
|
+
if (info->expressions.empty()) {
|
|
406
|
+
for (auto &parsed_expr : info->parsed_expressions) {
|
|
407
|
+
info->expressions.push_back(parsed_expr->Copy());
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
auto binder = Binder::CreateBinder(context);
|
|
411
|
+
auto expressions = binder->BindCreateIndexExpressions(table, info.get());
|
|
412
|
+
|
|
413
|
+
// create the empty index
|
|
414
|
+
unique_ptr<Index> index;
|
|
415
|
+
switch (info->index_type) {
|
|
416
|
+
case IndexType::ART: {
|
|
417
|
+
index = make_unique<ART>(info->column_ids, TableIOManager::Get(data_table), expressions, info->constraint_type,
|
|
418
|
+
data_table.db, true);
|
|
419
|
+
break;
|
|
420
|
+
}
|
|
421
|
+
default:
|
|
422
|
+
throw InternalException("Unimplemented index type");
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
// add the index to the catalog
|
|
426
|
+
auto index_entry = (DuckIndexEntry *)catalog.CreateIndex(context, info.get());
|
|
427
|
+
index_entry->index = index.get();
|
|
428
|
+
index_entry->info = data_table.info;
|
|
429
|
+
for (auto &parsed_expr : info->parsed_expressions) {
|
|
430
|
+
index_entry->parsed_expressions.push_back(parsed_expr->Copy());
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
// physically add the index to the data table storage
|
|
434
|
+
data_table.WALAddIndex(context, std::move(index), expressions);
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
void ReplayState::ReplayDropIndex() {
|
|
438
|
+
|
|
439
|
+
DropInfo info;
|
|
440
|
+
info.type = CatalogType::INDEX_ENTRY;
|
|
441
|
+
info.schema = source.Read<string>();
|
|
442
|
+
info.name = source.Read<string>();
|
|
443
|
+
if (deserialize_only) {
|
|
444
|
+
return;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
catalog.DropEntry(context, &info);
|
|
448
|
+
}
|
|
449
|
+
|
|
382
450
|
//===--------------------------------------------------------------------===//
|
|
383
451
|
// Replay Data
|
|
384
452
|
//===--------------------------------------------------------------------===//
|