duckdb 0.7.2-dev2552.0 → 0.7.2-dev2699.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/binding.gyp +7 -7
- package/package.json +2 -2
- package/src/duckdb/extension/parquet/parquet_statistics.cpp +3 -0
- package/src/duckdb/src/catalog/catalog_entry/duck_table_entry.cpp +2 -2
- package/src/duckdb/src/common/adbc/adbc.cpp +5 -2
- package/src/duckdb/src/common/radix_partitioning.cpp +1 -1
- package/src/duckdb/src/execution/index/art/art.cpp +286 -269
- package/src/duckdb/src/execution/index/art/art_key.cpp +22 -32
- package/src/duckdb/src/execution/index/art/fixed_size_allocator.cpp +224 -0
- package/src/duckdb/src/execution/index/art/iterator.cpp +142 -123
- package/src/duckdb/src/execution/index/art/leaf.cpp +319 -170
- package/src/duckdb/src/execution/index/art/leaf_segment.cpp +42 -0
- package/src/duckdb/src/execution/index/art/node.cpp +444 -379
- package/src/duckdb/src/execution/index/art/node16.cpp +178 -114
- package/src/duckdb/src/execution/index/art/node256.cpp +117 -79
- package/src/duckdb/src/execution/index/art/node4.cpp +169 -114
- package/src/duckdb/src/execution/index/art/node48.cpp +175 -105
- package/src/duckdb/src/execution/index/art/prefix.cpp +405 -127
- package/src/duckdb/src/execution/index/art/prefix_segment.cpp +42 -0
- package/src/duckdb/src/execution/index/art/swizzleable_pointer.cpp +10 -85
- package/src/duckdb/src/execution/operator/join/physical_index_join.cpp +2 -1
- package/src/duckdb/src/execution/operator/persistent/base_csv_reader.cpp +2 -2
- package/src/duckdb/src/execution/operator/persistent/csv_reader_options.cpp +2 -0
- package/src/duckdb/src/execution/operator/persistent/parallel_csv_reader.cpp +4 -0
- package/src/duckdb/src/execution/operator/schema/physical_create_index.cpp +11 -12
- package/src/duckdb/src/function/table/read_csv.cpp +5 -1
- package/src/duckdb/src/function/table/version/pragma_version.cpp +2 -2
- package/src/duckdb/src/include/duckdb/common/queue.hpp +1 -1
- package/src/duckdb/src/include/duckdb/execution/index/art/art.hpp +53 -45
- package/src/duckdb/src/include/duckdb/execution/index/art/art_key.hpp +29 -24
- package/src/duckdb/src/include/duckdb/execution/index/art/fixed_size_allocator.hpp +114 -0
- package/src/duckdb/src/include/duckdb/execution/index/art/iterator.hpp +26 -20
- package/src/duckdb/src/include/duckdb/execution/index/art/leaf.hpp +63 -39
- package/src/duckdb/src/include/duckdb/execution/index/art/leaf_segment.hpp +36 -0
- package/src/duckdb/src/include/duckdb/execution/index/art/node.hpp +98 -116
- package/src/duckdb/src/include/duckdb/execution/index/art/node16.hpp +48 -36
- package/src/duckdb/src/include/duckdb/execution/index/art/node256.hpp +52 -35
- package/src/duckdb/src/include/duckdb/execution/index/art/node4.hpp +46 -36
- package/src/duckdb/src/include/duckdb/execution/index/art/node48.hpp +57 -35
- package/src/duckdb/src/include/duckdb/execution/index/art/prefix.hpp +57 -50
- package/src/duckdb/src/include/duckdb/execution/index/art/prefix_segment.hpp +40 -0
- package/src/duckdb/src/include/duckdb/execution/index/art/swizzleable_pointer.hpp +38 -31
- package/src/duckdb/src/include/duckdb/execution/operator/persistent/csv_file_handle.hpp +2 -1
- package/src/duckdb/src/include/duckdb/execution/operator/persistent/csv_reader_options.hpp +2 -0
- package/src/duckdb/src/include/duckdb/main/query_result.hpp +1 -1
- package/src/duckdb/src/include/duckdb/parser/statement/insert_statement.hpp +4 -1
- package/src/duckdb/src/include/duckdb/parser/transformer.hpp +2 -1
- package/src/duckdb/src/include/duckdb/storage/buffer_manager.hpp +0 -5
- package/src/duckdb/src/include/duckdb/storage/index.hpp +13 -28
- package/src/duckdb/src/include/duckdb/storage/standard_buffer_manager.hpp +0 -2
- package/src/duckdb/src/include/duckdb/transaction/cleanup_state.hpp +5 -0
- package/src/duckdb/src/include/duckdb.h +26 -0
- package/src/duckdb/src/main/capi/helper-c.cpp +7 -0
- package/src/duckdb/src/main/client_context.cpp +1 -1
- package/src/duckdb/src/main/query_result.cpp +1 -1
- package/src/duckdb/src/parser/statement/insert_statement.cpp +15 -6
- package/src/duckdb/src/parser/transform/constraint/transform_constraint.cpp +1 -1
- package/src/duckdb/src/parser/transform/expression/transform_function.cpp +18 -5
- package/src/duckdb/src/parser/transform/statement/transform_insert.cpp +5 -7
- package/src/duckdb/src/planner/binder/statement/bind_create.cpp +20 -7
- package/src/duckdb/src/planner/binder/statement/bind_insert.cpp +14 -9
- package/src/duckdb/src/storage/checkpoint_manager.cpp +11 -9
- package/src/duckdb/src/storage/data_table.cpp +6 -3
- package/src/duckdb/src/storage/index.cpp +18 -6
- package/src/duckdb/src/storage/local_storage.cpp +8 -2
- package/src/duckdb/src/storage/standard_buffer_manager.cpp +0 -9
- package/src/duckdb/src/storage/wal_replay.cpp +1 -1
- package/src/duckdb/src/transaction/cleanup_state.cpp +6 -0
- package/src/duckdb/src/transaction/undo_buffer.cpp +8 -0
- package/src/duckdb/ub_extension_icu_third_party_icu_i18n.cpp +4 -4
- package/src/duckdb/ub_src_execution_index_art.cpp +7 -1
@@ -7,45 +7,52 @@
|
|
7
7
|
//===----------------------------------------------------------------------===//
|
8
8
|
#pragma once
|
9
9
|
|
10
|
-
#include "duckdb/
|
10
|
+
#include "duckdb/common/constants.hpp"
|
11
11
|
|
12
12
|
namespace duckdb {
|
13
13
|
|
14
|
-
|
15
|
-
class
|
14
|
+
// classes
|
15
|
+
class MetaBlockReader;
|
16
16
|
|
17
|
-
//
|
18
|
-
|
17
|
+
// structs
|
18
|
+
struct BlockPointer;
|
19
|
+
|
20
|
+
//! SwizzleablePointer provides functions on a (possibly) swizzled pointer. If the swizzle flag is set, then the
|
21
|
+
//! pointer points to a storage address (and has no type), otherwise the pointer has a type and stores
|
22
|
+
//! other information (e.g., a buffer location)
|
19
23
|
class SwizzleablePointer {
|
20
24
|
public:
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
25
|
+
//! Constructs an empty SwizzleablePointer
|
26
|
+
SwizzleablePointer() : swizzle_flag(0), type(0), offset(0), buffer_id(0) {};
|
27
|
+
//! Constructs a swizzled pointer from a buffer ID and an offset
|
28
|
+
explicit SwizzleablePointer(MetaBlockReader &reader);
|
29
|
+
//! Constructs a non-swizzled pointer from a buffer ID and an offset
|
30
|
+
SwizzleablePointer(uint32_t offset, uint32_t buffer_id)
|
31
|
+
: swizzle_flag(0), type(0), offset(offset), buffer_id(buffer_id) {};
|
32
|
+
|
33
|
+
//! The swizzle flag, set if swizzled, not set otherwise
|
34
|
+
uint8_t swizzle_flag : 1;
|
35
|
+
//! The type of the pointer, zero if not set
|
36
|
+
uint8_t type : 7;
|
37
|
+
//! The offset of a memory location
|
38
|
+
uint32_t offset : 24;
|
39
|
+
//! The buffer ID of a memory location
|
40
|
+
uint32_t buffer_id : 32;
|
29
41
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
42
|
+
public:
|
43
|
+
//! Checks if the pointer is swizzled
|
44
|
+
inline bool IsSwizzled() const {
|
45
|
+
return swizzle_flag;
|
46
|
+
}
|
47
|
+
//! Returns true, if neither the swizzle flag nor the type is set, and false otherwise
|
48
|
+
inline bool IsSet() const {
|
49
|
+
return swizzle_flag || type;
|
50
|
+
}
|
51
|
+
//! Reset the pointer
|
52
|
+
inline void Reset() {
|
53
|
+
swizzle_flag = 0;
|
54
|
+
type = 0;
|
37
55
|
}
|
38
|
-
|
39
|
-
//! Deletes the underlying object (if necessary) and set the pointer to nullptr
|
40
|
-
void Reset();
|
41
|
-
|
42
|
-
private:
|
43
|
-
uint64_t pointer;
|
44
|
-
|
45
|
-
friend bool operator!=(const SwizzleablePointer &s_ptr, const uint64_t &ptr);
|
46
|
-
|
47
|
-
//! Extracts the block info from swizzled pointer
|
48
|
-
BlockPointer GetSwizzledBlockInfo();
|
49
56
|
};
|
50
57
|
|
51
58
|
} // namespace duckdb
|
@@ -16,7 +16,8 @@ namespace duckdb {
|
|
16
16
|
|
17
17
|
struct CSVFileHandle {
|
18
18
|
public:
|
19
|
-
explicit CSVFileHandle(unique_ptr<FileHandle> file_handle_p
|
19
|
+
explicit CSVFileHandle(unique_ptr<FileHandle> file_handle_p, bool enable_reset = true)
|
20
|
+
: file_handle(std::move(file_handle_p)), reset_enabled(enable_reset) {
|
20
21
|
can_seek = file_handle->CanSeek();
|
21
22
|
plain_file_source = file_handle->OnDiskFile() && can_seek;
|
22
23
|
file_size = file_handle->GetFileSize();
|
@@ -62,6 +62,8 @@ struct BufferedCSVReaderOptions {
|
|
62
62
|
//! Whether file is compressed or not, and if so which compression type
|
63
63
|
//! AUTO_DETECT (default; infer from file extension)
|
64
64
|
FileCompressionType compression = FileCompressionType::AUTO_DETECT;
|
65
|
+
//! Option to convert quoted values to NULL values
|
66
|
+
bool allow_quoted_nulls = true;
|
65
67
|
|
66
68
|
//===--------------------------------------------------------------------===//
|
67
69
|
// CSVAutoOptions
|
@@ -20,7 +20,7 @@ enum class QueryResultType : uint8_t { MATERIALIZED_RESULT, STREAM_RESULT, PENDI
|
|
20
20
|
|
21
21
|
//! A set of properties from the client context that can be used to interpret the query result
|
22
22
|
struct ClientProperties {
|
23
|
-
string
|
23
|
+
string time_zone;
|
24
24
|
};
|
25
25
|
|
26
26
|
class BaseQueryResult {
|
@@ -72,6 +72,9 @@ public:
|
|
72
72
|
//! CTEs
|
73
73
|
CommonTableExpressionMap cte_map;
|
74
74
|
|
75
|
+
//! Whether or not this a DEFAULT VALUES
|
76
|
+
bool default_values = false;
|
77
|
+
|
75
78
|
protected:
|
76
79
|
InsertStatement(const InsertStatement &other);
|
77
80
|
|
@@ -82,7 +85,7 @@ public:
|
|
82
85
|
|
83
86
|
//! If the INSERT statement is inserted DIRECTLY from a values list (i.e. INSERT INTO tbl VALUES (...)) this returns
|
84
87
|
//! the expression list Otherwise, this returns NULL
|
85
|
-
ExpressionListRef
|
88
|
+
optional_ptr<ExpressionListRef> GetValuesList() const;
|
86
89
|
};
|
87
90
|
|
88
91
|
} // namespace duckdb
|
@@ -312,7 +312,8 @@ private:
|
|
312
312
|
void TransformExpressionList(duckdb_libpgquery::PGList &list, vector<unique_ptr<ParsedExpression>> &result);
|
313
313
|
|
314
314
|
//! Transform a Postgres PARTITION BY/ORDER BY specification into lists of expressions
|
315
|
-
void TransformWindowDef(duckdb_libpgquery::PGWindowDef *window_spec, WindowExpression *expr
|
315
|
+
void TransformWindowDef(duckdb_libpgquery::PGWindowDef *window_spec, WindowExpression *expr,
|
316
|
+
const char *window_name = nullptr);
|
316
317
|
//! Transform a Postgres window frame specification into frame expressions
|
317
318
|
void TransformWindowFrame(duckdb_libpgquery::PGWindowDef *window_spec, WindowExpression *expr);
|
318
319
|
|
@@ -58,15 +58,10 @@ public:
|
|
58
58
|
//! Construct a managed buffer.
|
59
59
|
virtual unique_ptr<FileBuffer> ConstructManagedBuffer(idx_t size, unique_ptr<FileBuffer> &&source,
|
60
60
|
FileBufferType type = FileBufferType::MANAGED_BUFFER);
|
61
|
-
//! Increases the currently allocated memory, but the actual allocation does not go through the buffer manager
|
62
|
-
virtual void IncreaseUsedMemory(idx_t size, bool unsafe = false) = 0;
|
63
|
-
//! Decrease the currently allocated memory, but the actual deallocation does not go through the buffer manager
|
64
|
-
virtual void DecreaseUsedMemory(idx_t size) = 0;
|
65
61
|
//! Get the underlying buffer pool responsible for managing the buffers
|
66
62
|
virtual BufferPool &GetBufferPool();
|
67
63
|
|
68
64
|
// Static methods
|
69
|
-
|
70
65
|
DUCKDB_API static BufferManager &GetBufferManager(DatabaseInstance &db);
|
71
66
|
DUCKDB_API static BufferManager &GetBufferManager(ClientContext &context);
|
72
67
|
DUCKDB_API static BufferManager &GetBufferManager(AttachedDatabase &db);
|
@@ -32,8 +32,7 @@ struct IndexScanState;
|
|
32
32
|
class Index {
|
33
33
|
public:
|
34
34
|
Index(AttachedDatabase &db, IndexType type, TableIOManager &table_io_manager, const vector<column_t> &column_ids,
|
35
|
-
const vector<unique_ptr<Expression>> &unbound_expressions, IndexConstraintType constraint_type
|
36
|
-
bool track_memory);
|
35
|
+
const vector<unique_ptr<Expression>> &unbound_expressions, IndexConstraintType constraint_type);
|
37
36
|
virtual ~Index() = default;
|
38
37
|
|
39
38
|
//! The type of the index
|
@@ -57,25 +56,21 @@ public:
|
|
57
56
|
AttachedDatabase &db;
|
58
57
|
//! Buffer manager of the database instance
|
59
58
|
BufferManager &buffer_manager;
|
60
|
-
//! The size of the index in memory
|
61
|
-
//! This does not track the size of the index meta information, but only allocated nodes and leaves
|
62
|
-
idx_t memory_size;
|
63
|
-
//! Flag determining if this index's size is tracked by the buffer manager
|
64
|
-
bool track_memory;
|
65
59
|
|
66
60
|
public:
|
67
61
|
//! Initialize a single predicate scan on the index with the given expression and column IDs
|
68
62
|
virtual unique_ptr<IndexScanState> InitializeScanSinglePredicate(const Transaction &transaction, const Value &value,
|
69
|
-
ExpressionType
|
63
|
+
const ExpressionType expression_type) = 0;
|
70
64
|
//! Initialize a two predicate scan on the index with the given expression and column IDs
|
71
|
-
virtual unique_ptr<IndexScanState> InitializeScanTwoPredicates(Transaction &transaction,
|
72
|
-
|
65
|
+
virtual unique_ptr<IndexScanState> InitializeScanTwoPredicates(const Transaction &transaction,
|
66
|
+
const Value &low_value,
|
67
|
+
const ExpressionType low_expression_type,
|
73
68
|
const Value &high_value,
|
74
|
-
ExpressionType high_expression_type) = 0;
|
69
|
+
const ExpressionType high_expression_type) = 0;
|
75
70
|
//! Performs a lookup on the index, fetching up to max_count result IDs. Returns true if all row IDs were fetched,
|
76
71
|
//! and false otherwise
|
77
|
-
virtual bool Scan(Transaction &transaction, DataTable &table, IndexScanState &state,
|
78
|
-
vector<row_t> &result_ids) = 0;
|
72
|
+
virtual bool Scan(const Transaction &transaction, const DataTable &table, IndexScanState &state,
|
73
|
+
const idx_t max_count, vector<row_t> &result_ids) = 0;
|
79
74
|
|
80
75
|
//! Obtain a lock on the index
|
81
76
|
virtual void InitializeLock(IndexLock &state);
|
@@ -104,23 +99,13 @@ public:
|
|
104
99
|
//! Obtains a lock and calls MergeIndexes while holding that lock
|
105
100
|
bool MergeIndexes(Index &other_index);
|
106
101
|
|
102
|
+
//! Traverses an ART and vacuums the qualifying nodes. The lock obtained from InitializeLock must be held
|
103
|
+
virtual void Vacuum(IndexLock &state) = 0;
|
104
|
+
//! Obtains a lock and calls Vacuum while holding that lock
|
105
|
+
void Vacuum();
|
106
|
+
|
107
107
|
//! Returns the string representation of an index
|
108
108
|
virtual string ToString() = 0;
|
109
|
-
//! Verifies that the in-memory size value of the index matches its actual size
|
110
|
-
virtual void Verify() = 0;
|
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
109
|
|
125
110
|
//! Returns true if the index is affected by updates on the specified column IDs, and false otherwise
|
126
111
|
bool IndexIsUpdated(const vector<PhysicalIndex> &column_ids) const;
|
@@ -45,8 +45,6 @@ public:
|
|
45
45
|
shared_ptr<BlockHandle> RegisterSmallMemory(idx_t block_size) final override;
|
46
46
|
|
47
47
|
idx_t GetUsedMemory() const final override;
|
48
|
-
void IncreaseUsedMemory(idx_t amount, bool unsafe = false) final override;
|
49
|
-
void DecreaseUsedMemory(idx_t amount) final override;
|
50
48
|
idx_t GetMaxMemory() const final override;
|
51
49
|
|
52
50
|
//! Allocate an in-memory buffer with a single pin.
|
@@ -10,8 +10,10 @@
|
|
10
10
|
|
11
11
|
#include "duckdb/transaction/undo_buffer.hpp"
|
12
12
|
#include "duckdb/common/types/data_chunk.hpp"
|
13
|
+
#include "duckdb/common/unordered_map.hpp"
|
13
14
|
|
14
15
|
namespace duckdb {
|
16
|
+
|
15
17
|
class DataTable;
|
16
18
|
|
17
19
|
struct DeleteInfo;
|
@@ -22,6 +24,9 @@ public:
|
|
22
24
|
CleanupState();
|
23
25
|
~CleanupState();
|
24
26
|
|
27
|
+
// all tables with indexes that possibly need a vacuum (after e.g. a delete)
|
28
|
+
unordered_map<string, optional_ptr<DataTable>> indexed_tables;
|
29
|
+
|
25
30
|
public:
|
26
31
|
void CleanupEntry(UndoFlags type, data_ptr_t data);
|
27
32
|
|
@@ -190,6 +190,23 @@ typedef struct {
|
|
190
190
|
idx_t size;
|
191
191
|
} duckdb_string;
|
192
192
|
|
193
|
+
/*
|
194
|
+
The internal data representation of a VARCHAR/BLOB column
|
195
|
+
*/
|
196
|
+
typedef struct {
|
197
|
+
union {
|
198
|
+
struct {
|
199
|
+
uint32_t length;
|
200
|
+
char prefix[4];
|
201
|
+
char *ptr;
|
202
|
+
} pointer;
|
203
|
+
struct {
|
204
|
+
uint32_t length;
|
205
|
+
char inlined[12];
|
206
|
+
} inlined;
|
207
|
+
} value;
|
208
|
+
} duckdb_string_t;
|
209
|
+
|
193
210
|
typedef struct {
|
194
211
|
void *data;
|
195
212
|
idx_t size;
|
@@ -298,6 +315,7 @@ typedef enum {
|
|
298
315
|
/*!
|
299
316
|
Creates a new database or opens an existing database file stored at the the given path.
|
300
317
|
If no path is given a new in-memory database is created instead.
|
318
|
+
The instantiated database should be closed with 'duckdb_close'
|
301
319
|
|
302
320
|
* path: Path to the database file on disk, or `nullptr` or `:memory:` to open an in-memory database.
|
303
321
|
* out_database: The result database object.
|
@@ -331,6 +349,7 @@ DUCKDB_API void duckdb_close(duckdb_database *database);
|
|
331
349
|
/*!
|
332
350
|
Opens a connection to a database. Connections are required to query the database, and store transactional state
|
333
351
|
associated with the connection.
|
352
|
+
The instantiated connection should be closed using 'duckdb_disconnect'
|
334
353
|
|
335
354
|
* database: The database file to connect to.
|
336
355
|
* out_connection: The result connection object.
|
@@ -751,6 +770,13 @@ This is the amount of tuples that will fit into a data chunk created by `duckdb_
|
|
751
770
|
*/
|
752
771
|
DUCKDB_API idx_t duckdb_vector_size();
|
753
772
|
|
773
|
+
/*!
|
774
|
+
Whether or not the duckdb_string_t value is inlined.
|
775
|
+
This means that the data of the string does not have a separate allocation.
|
776
|
+
|
777
|
+
*/
|
778
|
+
DUCKDB_API bool duckdb_string_is_inlined(duckdb_string_t string);
|
779
|
+
|
754
780
|
//===--------------------------------------------------------------------===//
|
755
781
|
// Date/Time/Timestamp Helpers
|
756
782
|
//===--------------------------------------------------------------------===//
|
@@ -186,3 +186,10 @@ void duckdb_free(void *ptr) {
|
|
186
186
|
idx_t duckdb_vector_size() {
|
187
187
|
return STANDARD_VECTOR_SIZE;
|
188
188
|
}
|
189
|
+
|
190
|
+
bool duckdb_string_is_inlined(duckdb_string_t string_p) {
|
191
|
+
static_assert(sizeof(duckdb_string_t) == sizeof(duckdb::string_t),
|
192
|
+
"duckdb_string_t should have the same memory layout as duckdb::string_t");
|
193
|
+
auto &string = *(duckdb::string_t *)(&string_p);
|
194
|
+
return string.IsInlined();
|
195
|
+
}
|
@@ -1156,7 +1156,7 @@ ParserOptions ClientContext::GetParserOptions() const {
|
|
1156
1156
|
|
1157
1157
|
ClientProperties ClientContext::GetClientProperties() const {
|
1158
1158
|
ClientProperties properties;
|
1159
|
-
properties.
|
1159
|
+
properties.time_zone = ClientConfig::GetConfig(*this).ExtractTimezone();
|
1160
1160
|
return properties;
|
1161
1161
|
}
|
1162
1162
|
|
@@ -165,7 +165,7 @@ string QueryResult::HeaderToString() {
|
|
165
165
|
}
|
166
166
|
|
167
167
|
string QueryResult::GetConfigTimezone(QueryResult &query_result) {
|
168
|
-
return query_result.client_properties.
|
168
|
+
return query_result.client_properties.time_zone;
|
169
169
|
}
|
170
170
|
|
171
171
|
} // namespace duckdb
|
@@ -27,9 +27,10 @@ InsertStatement::InsertStatement()
|
|
27
27
|
}
|
28
28
|
|
29
29
|
InsertStatement::InsertStatement(const InsertStatement &other)
|
30
|
-
: SQLStatement(other),
|
31
|
-
|
32
|
-
columns(other.columns), table(other.table), schema(other.schema), catalog(other.catalog)
|
30
|
+
: SQLStatement(other), select_statement(unique_ptr_cast<SQLStatement, SelectStatement>(
|
31
|
+
other.select_statement ? other.select_statement->Copy() : nullptr)),
|
32
|
+
columns(other.columns), table(other.table), schema(other.schema), catalog(other.catalog),
|
33
|
+
default_values(other.default_values) {
|
33
34
|
cte_map = other.cte_map.Copy();
|
34
35
|
for (auto &expr : other.returning_list) {
|
35
36
|
returning_list.emplace_back(expr->Copy());
|
@@ -93,10 +94,15 @@ string InsertStatement::ToString() const {
|
|
93
94
|
result += " ";
|
94
95
|
auto values_list = GetValuesList();
|
95
96
|
if (values_list) {
|
97
|
+
D_ASSERT(!default_values);
|
96
98
|
values_list->alias = string();
|
97
99
|
result += values_list->ToString();
|
98
|
-
} else {
|
100
|
+
} else if (select_statement) {
|
101
|
+
D_ASSERT(!default_values);
|
99
102
|
result += select_statement->ToString();
|
103
|
+
} else {
|
104
|
+
D_ASSERT(default_values);
|
105
|
+
result += "DEFAULT VALUES";
|
100
106
|
}
|
101
107
|
if (!or_replace_shorthand_set && on_conflict_info) {
|
102
108
|
auto &conflict_info = *on_conflict_info;
|
@@ -155,7 +161,10 @@ unique_ptr<SQLStatement> InsertStatement::Copy() const {
|
|
155
161
|
return unique_ptr<InsertStatement>(new InsertStatement(*this));
|
156
162
|
}
|
157
163
|
|
158
|
-
ExpressionListRef
|
164
|
+
optional_ptr<ExpressionListRef> InsertStatement::GetValuesList() const {
|
165
|
+
if (!select_statement) {
|
166
|
+
return nullptr;
|
167
|
+
}
|
159
168
|
if (select_statement->node->type != QueryNodeType::SELECT_NODE) {
|
160
169
|
return nullptr;
|
161
170
|
}
|
@@ -178,7 +187,7 @@ ExpressionListRef *InsertStatement::GetValuesList() const {
|
|
178
187
|
if (!node.from_table || node.from_table->type != TableReferenceType::EXPRESSION_LIST) {
|
179
188
|
return nullptr;
|
180
189
|
}
|
181
|
-
return
|
190
|
+
return &node.from_table->Cast<ExpressionListRef>();
|
182
191
|
}
|
183
192
|
|
184
193
|
} // namespace duckdb
|
@@ -108,7 +108,7 @@ unique_ptr<Constraint> Transformer::TransformConstraint(duckdb_libpgquery::PGLis
|
|
108
108
|
pk_columns.emplace_back(reinterpret_cast<duckdb_libpgquery::PGValue *>(kc->data.ptr_value)->val.str);
|
109
109
|
}
|
110
110
|
}
|
111
|
-
if (pk_columns.size() != fk_columns.size()) {
|
111
|
+
if (!pk_columns.empty() && pk_columns.size() != fk_columns.size()) {
|
112
112
|
throw ParserException("The number of referencing and referenced columns for foreign keys must be the same");
|
113
113
|
}
|
114
114
|
return make_uniq<ForeignKeyConstraint>(pk_columns, fk_columns, std::move(fk_info));
|
@@ -13,15 +13,24 @@
|
|
13
13
|
|
14
14
|
namespace duckdb {
|
15
15
|
|
16
|
-
void Transformer::TransformWindowDef(duckdb_libpgquery::PGWindowDef *window_spec, WindowExpression *expr
|
16
|
+
void Transformer::TransformWindowDef(duckdb_libpgquery::PGWindowDef *window_spec, WindowExpression *expr,
|
17
|
+
const char *window_name) {
|
17
18
|
D_ASSERT(window_spec);
|
18
19
|
D_ASSERT(expr);
|
19
20
|
|
20
21
|
// next: partitioning/ordering expressions
|
21
22
|
if (window_spec->partitionClause) {
|
23
|
+
if (window_name && !expr->partitions.empty()) {
|
24
|
+
throw ParserException("Cannot override PARTITION BY clause of window \"%s\"", window_name);
|
25
|
+
}
|
22
26
|
TransformExpressionList(*window_spec->partitionClause, expr->partitions);
|
23
27
|
}
|
24
|
-
|
28
|
+
if (window_spec->orderClause) {
|
29
|
+
if (window_name && !expr->orders.empty()) {
|
30
|
+
throw ParserException("Cannot override ORDER BY clause of window \"%s\"", window_name);
|
31
|
+
}
|
32
|
+
TransformOrderBy(window_spec->orderClause, expr->orders);
|
33
|
+
}
|
25
34
|
}
|
26
35
|
|
27
36
|
void Transformer::TransformWindowFrame(duckdb_libpgquery::PGWindowDef *window_spec, WindowExpression *expr) {
|
@@ -198,6 +207,7 @@ unique_ptr<ParsedExpression> Transformer::TransformFuncCall(duckdb_libpgquery::P
|
|
198
207
|
D_ASSERT(window_spec);
|
199
208
|
}
|
200
209
|
auto window_ref = window_spec;
|
210
|
+
auto window_name = window_ref->refname;
|
201
211
|
if (window_ref->refname) {
|
202
212
|
auto it = window_clauses.find(StringUtil::Lower(string(window_spec->refname)));
|
203
213
|
if (it == window_clauses.end()) {
|
@@ -208,6 +218,9 @@ unique_ptr<ParsedExpression> Transformer::TransformFuncCall(duckdb_libpgquery::P
|
|
208
218
|
}
|
209
219
|
in_window_definition = true;
|
210
220
|
TransformWindowDef(window_ref, expr.get());
|
221
|
+
if (window_ref != window_spec) {
|
222
|
+
TransformWindowDef(window_spec, expr.get(), window_name);
|
223
|
+
}
|
211
224
|
TransformWindowFrame(window_spec, expr.get());
|
212
225
|
in_window_definition = false;
|
213
226
|
expr->query_location = root->location;
|
@@ -299,9 +312,9 @@ unique_ptr<ParsedExpression> Transformer::TransformFuncCall(duckdb_libpgquery::P
|
|
299
312
|
std::move(filter_expr), std::move(order_bys),
|
300
313
|
root->agg_distinct, false, root->export_state);
|
301
314
|
lowercase_name = "list_sort";
|
302
|
-
order_bys.reset();
|
303
|
-
filter_expr.reset();
|
304
|
-
children.clear();
|
315
|
+
order_bys.reset(); // NOLINT
|
316
|
+
filter_expr.reset(); // NOLINT
|
317
|
+
children.clear(); // NOLINT
|
305
318
|
children.emplace_back(std::move(unordered));
|
306
319
|
children.emplace_back(std::move(sense));
|
307
320
|
children.emplace_back(std::move(nulls));
|
@@ -26,12 +26,6 @@ unique_ptr<InsertStatement> Transformer::TransformInsert(duckdb_libpgquery::PGNo
|
|
26
26
|
auto stmt = reinterpret_cast<duckdb_libpgquery::PGInsertStmt *>(node);
|
27
27
|
D_ASSERT(stmt);
|
28
28
|
|
29
|
-
if (!stmt->selectStmt) {
|
30
|
-
// TODO: This should be easy to add, we already support DEFAULT in the values list,
|
31
|
-
// this could probably just be transformed into VALUES (DEFAULT, DEFAULT, DEFAULT, ..) in the Binder
|
32
|
-
throw ParserException("DEFAULT VALUES clause is not supported!");
|
33
|
-
}
|
34
|
-
|
35
29
|
auto result = make_uniq<InsertStatement>();
|
36
30
|
if (stmt->withClause) {
|
37
31
|
TransformCTE(reinterpret_cast<duckdb_libpgquery::PGWithClause *>(stmt->withClause), result->cte_map);
|
@@ -49,7 +43,11 @@ unique_ptr<InsertStatement> Transformer::TransformInsert(duckdb_libpgquery::PGNo
|
|
49
43
|
if (stmt->returningList) {
|
50
44
|
Transformer::TransformExpressionList(*(stmt->returningList), result->returning_list);
|
51
45
|
}
|
52
|
-
|
46
|
+
if (stmt->selectStmt) {
|
47
|
+
result->select_statement = TransformSelect(stmt->selectStmt, false);
|
48
|
+
} else {
|
49
|
+
result->default_values = true;
|
50
|
+
}
|
53
51
|
|
54
52
|
auto qname = TransformQualifiedName(stmt->relation);
|
55
53
|
result->table = qname.name;
|
@@ -292,17 +292,30 @@ static void FindMatchingPrimaryKeyColumns(const ColumnList &columns, const vecto
|
|
292
292
|
} else {
|
293
293
|
pk_names = unique.columns;
|
294
294
|
}
|
295
|
-
if (pk_names.size() != fk.fk_columns.size()) {
|
296
|
-
// the number of referencing and referenced columns for foreign keys must be the same
|
297
|
-
continue;
|
298
|
-
}
|
299
295
|
if (find_primary_key) {
|
300
296
|
// found matching primary key
|
297
|
+
if (pk_names.size() != fk.fk_columns.size()) {
|
298
|
+
auto pk_name_str = StringUtil::Join(pk_names, ",");
|
299
|
+
auto fk_name_str = StringUtil::Join(fk.fk_columns, ",");
|
300
|
+
throw BinderException(
|
301
|
+
"Failed to create foreign key: number of referencing (%s) and referenced columns (%s) differ",
|
302
|
+
fk_name_str, pk_name_str);
|
303
|
+
}
|
301
304
|
fk.pk_columns = pk_names;
|
302
305
|
return;
|
303
306
|
}
|
304
|
-
if (
|
305
|
-
//
|
307
|
+
if (pk_names.size() != fk.fk_columns.size()) {
|
308
|
+
// the number of referencing and referenced columns for foreign keys must be the same
|
309
|
+
continue;
|
310
|
+
}
|
311
|
+
bool equals = true;
|
312
|
+
for (idx_t i = 0; i < fk.pk_columns.size(); i++) {
|
313
|
+
if (!StringUtil::CIEquals(fk.pk_columns[i], pk_names[i])) {
|
314
|
+
equals = false;
|
315
|
+
break;
|
316
|
+
}
|
317
|
+
}
|
318
|
+
if (!equals) {
|
306
319
|
continue;
|
307
320
|
}
|
308
321
|
// found match
|
@@ -540,7 +553,7 @@ BoundStatement Binder::Bind(CreateStatement &stmt) {
|
|
540
553
|
D_ASSERT(fk.info.pk_keys.empty());
|
541
554
|
D_ASSERT(fk.info.fk_keys.empty());
|
542
555
|
FindForeignKeyIndexes(create_info.columns, fk.fk_columns, fk.info.fk_keys);
|
543
|
-
if (create_info.table
|
556
|
+
if (StringUtil::CIEquals(create_info.table, fk.info.table)) {
|
544
557
|
// self-referential foreign key constraint
|
545
558
|
fk.info.type = ForeignKeyType::FK_TYPE_SELF_REFERENCE_TABLE;
|
546
559
|
FindMatchingPrimaryKeyColumns(create_info.columns, create_info.constraints, fk);
|
@@ -9,6 +9,7 @@
|
|
9
9
|
#include "duckdb/planner/operator/logical_get.hpp"
|
10
10
|
#include "duckdb/common/string_util.hpp"
|
11
11
|
#include "duckdb/function/table/table_scan.hpp"
|
12
|
+
#include "duckdb/planner/operator/logical_dummy_scan.hpp"
|
12
13
|
#include "duckdb/planner/operator/logical_projection.hpp"
|
13
14
|
#include "duckdb/planner/expression_iterator.hpp"
|
14
15
|
#include "duckdb/planner/expression_binder/returning_binder.hpp"
|
@@ -409,7 +410,7 @@ BoundStatement Binder::Bind(InsertStatement &stmt) {
|
|
409
410
|
AddCTEMap(stmt.cte_map);
|
410
411
|
|
411
412
|
vector<LogicalIndex> named_column_map;
|
412
|
-
if (!stmt.columns.empty()) {
|
413
|
+
if (!stmt.columns.empty() || stmt.default_values) {
|
413
414
|
// insertion statement specifies column list
|
414
415
|
|
415
416
|
// create a mapping of (list index) -> (column index)
|
@@ -448,11 +449,10 @@ BoundStatement Binder::Bind(InsertStatement &stmt) {
|
|
448
449
|
|
449
450
|
// bind the default values
|
450
451
|
BindDefaultValues(table.GetColumns(), insert->bound_defaults);
|
451
|
-
if (!stmt.select_statement) {
|
452
|
+
if (!stmt.select_statement && !stmt.default_values) {
|
452
453
|
result.plan = std::move(insert);
|
453
454
|
return result;
|
454
455
|
}
|
455
|
-
|
456
456
|
// Exclude the generated columns from this amount
|
457
457
|
idx_t expected_columns = stmt.columns.empty() ? table.GetColumns().PhysicalColumnCount() : stmt.columns.size();
|
458
458
|
|
@@ -488,14 +488,19 @@ BoundStatement Binder::Bind(InsertStatement &stmt) {
|
|
488
488
|
}
|
489
489
|
|
490
490
|
// parse select statement and add to logical plan
|
491
|
-
|
492
|
-
|
493
|
-
|
491
|
+
unique_ptr<LogicalOperator> root;
|
492
|
+
if (stmt.select_statement) {
|
493
|
+
auto select_binder = Binder::CreateBinder(context, this);
|
494
|
+
auto root_select = select_binder->Bind(*stmt.select_statement);
|
495
|
+
MoveCorrelatedExpressions(*select_binder);
|
494
496
|
|
495
|
-
|
496
|
-
|
497
|
+
CheckInsertColumnCountMismatch(expected_columns, root_select.types.size(), !stmt.columns.empty(),
|
498
|
+
table.name.c_str());
|
497
499
|
|
498
|
-
|
500
|
+
root = CastLogicalOperatorToTypes(root_select.types, insert->expected_types, std::move(root_select.plan));
|
501
|
+
} else {
|
502
|
+
root = make_uniq<LogicalDummyScan>(GenerateTableIndex());
|
503
|
+
}
|
499
504
|
insert->AddChild(std::move(root));
|
500
505
|
|
501
506
|
BindOnConflictClause(*insert, table, stmt);
|