duckdb 0.7.1-dev7.0 → 0.7.1

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.
Files changed (182) hide show
  1. package/README.md +1 -1
  2. package/binding.gyp +7 -7
  3. package/package.json +3 -3
  4. package/src/duckdb/extension/json/buffered_json_reader.cpp +50 -9
  5. package/src/duckdb/extension/json/include/buffered_json_reader.hpp +7 -2
  6. package/src/duckdb/extension/json/include/json_scan.hpp +45 -10
  7. package/src/duckdb/extension/json/json_functions/copy_json.cpp +35 -22
  8. package/src/duckdb/extension/json/json_functions/json_create.cpp +8 -8
  9. package/src/duckdb/extension/json/json_functions/json_structure.cpp +8 -3
  10. package/src/duckdb/extension/json/json_functions/json_transform.cpp +54 -10
  11. package/src/duckdb/extension/json/json_functions/read_json.cpp +104 -49
  12. package/src/duckdb/extension/json/json_functions/read_json_objects.cpp +5 -3
  13. package/src/duckdb/extension/json/json_functions.cpp +7 -0
  14. package/src/duckdb/extension/json/json_scan.cpp +144 -37
  15. package/src/duckdb/extension/parquet/column_reader.cpp +7 -0
  16. package/src/duckdb/extension/parquet/include/column_reader.hpp +1 -0
  17. package/src/duckdb/extension/parquet/parquet-extension.cpp +2 -9
  18. package/src/duckdb/src/catalog/catalog.cpp +62 -13
  19. package/src/duckdb/src/catalog/catalog_entry/index_catalog_entry.cpp +8 -7
  20. package/src/duckdb/src/catalog/catalog_entry/schema_catalog_entry.cpp +1 -1
  21. package/src/duckdb/src/catalog/catalog_set.cpp +1 -1
  22. package/src/duckdb/src/catalog/default/default_functions.cpp +1 -0
  23. package/src/duckdb/src/catalog/default/default_views.cpp +1 -1
  24. package/src/duckdb/src/common/bind_helpers.cpp +55 -0
  25. package/src/duckdb/src/common/enums/logical_operator_type.cpp +2 -0
  26. package/src/duckdb/src/common/enums/physical_operator_type.cpp +2 -0
  27. package/src/duckdb/src/common/enums/statement_type.cpp +2 -0
  28. package/src/duckdb/src/common/file_system.cpp +28 -0
  29. package/src/duckdb/src/common/hive_partitioning.cpp +1 -0
  30. package/src/duckdb/src/common/local_file_system.cpp +4 -4
  31. package/src/duckdb/src/common/operator/cast_operators.cpp +14 -8
  32. package/src/duckdb/src/common/printer.cpp +1 -1
  33. package/src/duckdb/src/common/string_util.cpp +8 -4
  34. package/src/duckdb/src/common/types/partitioned_column_data.cpp +1 -0
  35. package/src/duckdb/src/common/types/time.cpp +1 -1
  36. package/src/duckdb/src/common/types/timestamp.cpp +35 -4
  37. package/src/duckdb/src/common/types.cpp +37 -11
  38. package/src/duckdb/src/execution/column_binding_resolver.cpp +5 -2
  39. package/src/duckdb/src/execution/index/art/art.cpp +117 -67
  40. package/src/duckdb/src/execution/index/art/art_key.cpp +24 -12
  41. package/src/duckdb/src/execution/index/art/leaf.cpp +7 -8
  42. package/src/duckdb/src/execution/index/art/node.cpp +13 -27
  43. package/src/duckdb/src/execution/index/art/node16.cpp +5 -8
  44. package/src/duckdb/src/execution/index/art/node256.cpp +3 -5
  45. package/src/duckdb/src/execution/index/art/node4.cpp +4 -7
  46. package/src/duckdb/src/execution/index/art/node48.cpp +5 -8
  47. package/src/duckdb/src/execution/index/art/prefix.cpp +2 -3
  48. package/src/duckdb/src/execution/operator/aggregate/physical_window.cpp +6 -27
  49. package/src/duckdb/src/execution/operator/helper/physical_reset.cpp +1 -9
  50. package/src/duckdb/src/execution/operator/helper/physical_set.cpp +1 -9
  51. package/src/duckdb/src/execution/operator/join/physical_iejoin.cpp +7 -9
  52. package/src/duckdb/src/execution/operator/persistent/base_csv_reader.cpp +6 -11
  53. package/src/duckdb/src/execution/operator/persistent/buffered_csv_reader.cpp +13 -13
  54. package/src/duckdb/src/execution/operator/persistent/parallel_csv_reader.cpp +1 -1
  55. package/src/duckdb/src/execution/operator/schema/physical_detach.cpp +37 -0
  56. package/src/duckdb/src/execution/operator/schema/physical_drop.cpp +0 -5
  57. package/src/duckdb/src/execution/physical_operator.cpp +6 -6
  58. package/src/duckdb/src/execution/physical_plan/plan_simple.cpp +4 -0
  59. package/src/duckdb/src/execution/physical_plan_generator.cpp +1 -0
  60. package/src/duckdb/src/function/pragma/pragma_queries.cpp +38 -11
  61. package/src/duckdb/src/function/scalar/generic/current_setting.cpp +2 -2
  62. package/src/duckdb/src/function/scalar/list/array_slice.cpp +2 -3
  63. package/src/duckdb/src/function/scalar/map/map.cpp +69 -21
  64. package/src/duckdb/src/function/scalar/string/like.cpp +6 -3
  65. package/src/duckdb/src/function/table/read_csv.cpp +17 -8
  66. package/src/duckdb/src/function/table/system/duckdb_temporary_files.cpp +59 -0
  67. package/src/duckdb/src/function/table/system_functions.cpp +1 -0
  68. package/src/duckdb/src/function/table/table_scan.cpp +3 -0
  69. package/src/duckdb/src/function/table/version/pragma_version.cpp +2 -2
  70. package/src/duckdb/src/include/duckdb/catalog/catalog.hpp +7 -1
  71. package/src/duckdb/src/include/duckdb/catalog/catalog_entry/duck_index_entry.hpp +1 -1
  72. package/src/duckdb/src/include/duckdb/catalog/catalog_entry/index_catalog_entry.hpp +1 -1
  73. package/src/duckdb/src/include/duckdb/common/bind_helpers.hpp +2 -0
  74. package/src/duckdb/src/include/duckdb/common/enums/logical_operator_type.hpp +1 -0
  75. package/src/duckdb/src/include/duckdb/common/enums/physical_operator_type.hpp +1 -0
  76. package/src/duckdb/src/include/duckdb/common/enums/statement_type.hpp +3 -2
  77. package/src/duckdb/src/include/duckdb/common/enums/wal_type.hpp +3 -0
  78. package/src/duckdb/src/include/duckdb/common/exception.hpp +10 -0
  79. package/src/duckdb/src/include/duckdb/common/file_system.hpp +1 -0
  80. package/src/duckdb/src/include/duckdb/common/hive_partitioning.hpp +9 -1
  81. package/src/duckdb/src/include/duckdb/common/radix_partitioning.hpp +4 -4
  82. package/src/duckdb/src/include/duckdb/common/string_util.hpp +9 -2
  83. package/src/duckdb/src/include/duckdb/common/types/timestamp.hpp +5 -1
  84. package/src/duckdb/src/include/duckdb/execution/index/art/art.hpp +37 -41
  85. package/src/duckdb/src/include/duckdb/execution/index/art/art_key.hpp +8 -11
  86. package/src/duckdb/src/include/duckdb/execution/operator/persistent/base_csv_reader.hpp +1 -3
  87. package/src/duckdb/src/include/duckdb/execution/operator/persistent/buffered_csv_reader.hpp +0 -2
  88. package/src/duckdb/src/include/duckdb/execution/operator/persistent/csv_reader_options.hpp +2 -0
  89. package/src/duckdb/src/include/duckdb/execution/operator/schema/physical_detach.hpp +32 -0
  90. package/src/duckdb/src/include/duckdb/function/scalar/string_functions.hpp +2 -1
  91. package/src/duckdb/src/include/duckdb/function/table/system_functions.hpp +4 -0
  92. package/src/duckdb/src/include/duckdb/main/client_data.hpp +2 -2
  93. package/src/duckdb/src/include/duckdb/main/config.hpp +2 -3
  94. package/src/duckdb/src/include/duckdb/main/{extension_functions.hpp → extension_entries.hpp} +27 -5
  95. package/src/duckdb/src/include/duckdb/main/extension_helper.hpp +11 -1
  96. package/src/duckdb/src/include/duckdb/main/settings.hpp +9 -0
  97. package/src/duckdb/src/include/duckdb/parallel/pipeline_executor.hpp +0 -7
  98. package/src/duckdb/src/include/duckdb/parser/parsed_data/create_database_info.hpp +0 -4
  99. package/src/duckdb/src/include/duckdb/parser/parsed_data/detach_info.hpp +32 -0
  100. package/src/duckdb/src/include/duckdb/parser/query_node/select_node.hpp +1 -1
  101. package/src/duckdb/src/include/duckdb/parser/sql_statement.hpp +2 -2
  102. package/src/duckdb/src/include/duckdb/parser/statement/copy_statement.hpp +1 -1
  103. package/src/duckdb/src/include/duckdb/parser/statement/detach_statement.hpp +29 -0
  104. package/src/duckdb/src/include/duckdb/parser/statement/list.hpp +1 -0
  105. package/src/duckdb/src/include/duckdb/parser/statement/select_statement.hpp +3 -3
  106. package/src/duckdb/src/include/duckdb/parser/tableref/subqueryref.hpp +1 -1
  107. package/src/duckdb/src/include/duckdb/parser/tokens.hpp +1 -0
  108. package/src/duckdb/src/include/duckdb/parser/transformer.hpp +1 -0
  109. package/src/duckdb/src/include/duckdb/planner/binder.hpp +4 -0
  110. package/src/duckdb/src/include/duckdb/planner/expression_binder/index_binder.hpp +10 -3
  111. package/src/duckdb/src/include/duckdb/planner/operator/logical_execute.hpp +1 -5
  112. package/src/duckdb/src/include/duckdb/planner/operator/logical_show.hpp +1 -2
  113. package/src/duckdb/src/include/duckdb/storage/buffer_manager.hpp +8 -0
  114. package/src/duckdb/src/include/duckdb/storage/data_table.hpp +7 -1
  115. package/src/duckdb/src/include/duckdb/storage/index.hpp +47 -38
  116. package/src/duckdb/src/include/duckdb/storage/storage_extension.hpp +7 -0
  117. package/src/duckdb/src/include/duckdb/storage/table/update_segment.hpp +2 -0
  118. package/src/duckdb/src/include/duckdb/storage/write_ahead_log.hpp +7 -0
  119. package/src/duckdb/src/main/client_context.cpp +2 -0
  120. package/src/duckdb/src/main/config.cpp +1 -0
  121. package/src/duckdb/src/main/database.cpp +14 -5
  122. package/src/duckdb/src/main/extension/extension_alias.cpp +2 -1
  123. package/src/duckdb/src/main/extension/extension_helper.cpp +15 -0
  124. package/src/duckdb/src/main/extension/extension_install.cpp +60 -16
  125. package/src/duckdb/src/main/extension/extension_load.cpp +62 -13
  126. package/src/duckdb/src/main/settings/settings.cpp +16 -0
  127. package/src/duckdb/src/optimizer/statistics/operator/propagate_join.cpp +2 -6
  128. package/src/duckdb/src/parallel/pipeline_executor.cpp +1 -55
  129. package/src/duckdb/src/parser/parsed_data/create_index_info.cpp +3 -0
  130. package/src/duckdb/src/parser/statement/copy_statement.cpp +2 -13
  131. package/src/duckdb/src/parser/statement/delete_statement.cpp +3 -0
  132. package/src/duckdb/src/parser/statement/detach_statement.cpp +15 -0
  133. package/src/duckdb/src/parser/statement/insert_statement.cpp +9 -0
  134. package/src/duckdb/src/parser/statement/update_statement.cpp +3 -0
  135. package/src/duckdb/src/parser/transform/expression/transform_case.cpp +3 -3
  136. package/src/duckdb/src/parser/transform/statement/transform_create_database.cpp +0 -1
  137. package/src/duckdb/src/parser/transform/statement/transform_detach.cpp +19 -0
  138. package/src/duckdb/src/parser/transformer.cpp +2 -0
  139. package/src/duckdb/src/planner/bind_context.cpp +1 -1
  140. package/src/duckdb/src/planner/binder/expression/bind_aggregate_expression.cpp +3 -0
  141. package/src/duckdb/src/planner/binder/statement/bind_copy.cpp +7 -14
  142. package/src/duckdb/src/planner/binder/statement/bind_create.cpp +16 -14
  143. package/src/duckdb/src/planner/binder/statement/bind_create_table.cpp +13 -0
  144. package/src/duckdb/src/planner/binder/statement/bind_detach.cpp +19 -0
  145. package/src/duckdb/src/planner/binder/statement/bind_drop.cpp +29 -4
  146. package/src/duckdb/src/planner/binder/statement/bind_insert.cpp +22 -1
  147. package/src/duckdb/src/planner/binder/tableref/bind_joinref.cpp +2 -1
  148. package/src/duckdb/src/planner/binder.cpp +2 -0
  149. package/src/duckdb/src/planner/expression_binder/index_binder.cpp +32 -1
  150. package/src/duckdb/src/planner/expression_binder/lateral_binder.cpp +21 -5
  151. package/src/duckdb/src/planner/logical_operator.cpp +6 -1
  152. package/src/duckdb/src/planner/planner.cpp +1 -0
  153. package/src/duckdb/src/storage/buffer_manager.cpp +105 -26
  154. package/src/duckdb/src/storage/compression/bitpacking.cpp +16 -7
  155. package/src/duckdb/src/storage/data_table.cpp +66 -3
  156. package/src/duckdb/src/storage/index.cpp +1 -1
  157. package/src/duckdb/src/storage/local_storage.cpp +1 -1
  158. package/src/duckdb/src/storage/storage_info.cpp +2 -1
  159. package/src/duckdb/src/storage/table/column_data.cpp +4 -2
  160. package/src/duckdb/src/storage/table/update_segment.cpp +15 -0
  161. package/src/duckdb/src/storage/table_index_list.cpp +1 -2
  162. package/src/duckdb/src/storage/wal_replay.cpp +68 -0
  163. package/src/duckdb/src/storage/write_ahead_log.cpp +21 -1
  164. package/src/duckdb/src/transaction/commit_state.cpp +5 -2
  165. package/src/duckdb/third_party/concurrentqueue/blockingconcurrentqueue.h +2 -2
  166. package/src/duckdb/third_party/fmt/include/fmt/core.h +1 -2
  167. package/src/duckdb/third_party/libpg_query/include/nodes/nodes.hpp +1 -0
  168. package/src/duckdb/third_party/libpg_query/include/nodes/parsenodes.hpp +14 -0
  169. package/src/duckdb/third_party/libpg_query/include/parser/gram.hpp +530 -1006
  170. package/src/duckdb/third_party/libpg_query/src_backend_parser_gram.cpp +17659 -17626
  171. package/src/duckdb/third_party/thrift/thrift/Thrift.h +8 -2
  172. package/src/duckdb/ub_extension_icu_third_party_icu_i18n.cpp +4 -4
  173. package/src/duckdb/ub_src_execution_operator_schema.cpp +2 -0
  174. package/src/duckdb/ub_src_function_table_system.cpp +2 -0
  175. package/src/duckdb/ub_src_parser_statement.cpp +2 -0
  176. package/src/duckdb/ub_src_parser_transform_statement.cpp +2 -0
  177. package/src/duckdb/ub_src_planner_binder_statement.cpp +2 -0
  178. package/src/statement.cpp +46 -12
  179. package/test/arrow.test.ts +3 -3
  180. package/test/prepare.test.ts +39 -1
  181. package/test/typescript_decls.test.ts +1 -1
  182. package/src/duckdb/src/include/duckdb/function/create_database_extension.hpp +0 -37
@@ -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 INDEX binder is responsible for binding an expression within an Index statement
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
@@ -32,11 +32,7 @@ protected:
32
32
  // already resolved
33
33
  }
34
34
  vector<ColumnBinding> GetColumnBindings() override {
35
- vector<ColumnBinding> bindings;
36
- for (idx_t i = 0; i < types.size(); i++) {
37
- bindings.push_back(ColumnBinding(0, i));
38
- }
39
- return bindings;
35
+ return GenerateColumnBindings(0, types.size());
40
36
  }
41
37
  };
42
38
  } // namespace duckdb
@@ -33,8 +33,7 @@ protected:
33
33
  LogicalType::VARCHAR, LogicalType::VARCHAR, LogicalType::VARCHAR};
34
34
  }
35
35
  vector<ColumnBinding> GetColumnBindings() override {
36
- return {ColumnBinding(0, 0), ColumnBinding(0, 1), ColumnBinding(0, 2),
37
- ColumnBinding(0, 3), ColumnBinding(0, 4), ColumnBinding(0, 5)};
36
+ return GenerateColumnBindings(0, types.size());
38
37
  }
39
38
  };
40
39
  } // namespace duckdb
@@ -23,6 +23,11 @@ class DatabaseInstance;
23
23
  class TemporaryDirectoryHandle;
24
24
  struct EvictionQueue;
25
25
 
26
+ struct TemporaryFileInformation {
27
+ string path;
28
+ idx_t size;
29
+ };
30
+
26
31
  //! The buffer manager is in charge of handling memory management for the database. It hands out memory buffers that can
27
32
  //! be used by the database internally.
28
33
  //
@@ -98,6 +103,9 @@ public:
98
103
  DUCKDB_API void ReserveMemory(idx_t size);
99
104
  DUCKDB_API void FreeReservedMemory(idx_t size);
100
105
 
106
+ //! Returns a list of all temporary files
107
+ vector<TemporaryFileInformation> GetTemporaryFiles();
108
+
101
109
  private:
102
110
  //! Register an in-memory buffer of arbitrary size, as long as it is >= BLOCK_SIZE. can_destroy signifies whether or
103
111
  //! not the buffer can be destroyed when unpinned, or whether or not it needs to be written to a temporary file so
@@ -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 InitializeCreateIndexScan(CreateIndexScanState &state, const vector<column_t> &column_ids);
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
- //! Unordered_set of column_ids used by the index
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 ids
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 ids
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
- //! Perform a lookup on the index, fetching up to max_count result ids. Returns true if all row ids were fetched,
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 InitializeAppend must be held
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
- //! Verify that data can be appended to the index for foreign key constraint
92
- virtual void VerifyAppendForeignKey(DataChunk &chunk) = 0;
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
- //! Called when data inside the index is Deleted
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 data into the index. Does not lock the index.
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 other_index into this index.
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 memory_size value of the index matches its actual size
109
+ //! Verifies that the in-memory size value of the index matches its actual size
110
110
  virtual void Verify() = 0;
111
-
112
- //! Returns true if the index is affected by updates on the specified column ids, and false otherwise
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
- //! Returns block/offset of where index was most recently serialized.
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
- protected:
148
+ //! Execute the index expressions on an input chunk
141
149
  void ExecuteExpressions(DataChunk &input, DataChunk &result);
142
150
 
143
- //! Lock used for updating the index
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 by the index
158
+ //! Bound expressions used during expression execution
151
159
  vector<unique_ptr<Expression>> bound_expressions;
152
- //! Expression executor for the index expressions
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
 
@@ -10,6 +10,7 @@
10
10
 
11
11
  #include "duckdb/common/common.hpp"
12
12
  #include "duckdb/common/enums/access_mode.hpp"
13
+ #include "duckdb/parser/tableref/table_function_ref.hpp"
13
14
 
14
15
  namespace duckdb {
15
16
  class AttachedDatabase;
@@ -27,11 +28,17 @@ typedef unique_ptr<Catalog> (*attach_function_t)(StorageExtensionInfo *storage_i
27
28
  const string &name, AttachInfo &info, AccessMode access_mode);
28
29
  typedef unique_ptr<TransactionManager> (*create_transaction_manager_t)(StorageExtensionInfo *storage_info,
29
30
  AttachedDatabase &db, Catalog &catalog);
31
+ typedef unique_ptr<TableFunctionRef> (*create_database_t)(StorageExtensionInfo *info, ClientContext &context,
32
+ const string &database_name, const string &source_path);
33
+ typedef unique_ptr<TableFunctionRef> (*drop_database_t)(StorageExtensionInfo *storage_info, ClientContext &context,
34
+ const string &database_name);
30
35
 
31
36
  class StorageExtension {
32
37
  public:
33
38
  attach_function_t attach;
34
39
  create_transaction_manager_t create_transaction_manager;
40
+ create_database_t create_database;
41
+ drop_database_t drop_database;
35
42
 
36
43
  //! Additional info passed to the various storage functions
37
44
  shared_ptr<StorageExtensionInfo> storage_info;
@@ -23,6 +23,8 @@ struct UpdateNode;
23
23
  class UpdateSegment {
24
24
  public:
25
25
  UpdateSegment(ColumnData &column_data);
26
+ // Construct a duplicate of 'other' with 'new_owner' as it's column data
27
+ UpdateSegment(UpdateSegment &other, ColumnData &new_owner);
26
28
  ~UpdateSegment();
27
29
 
28
30
  ColumnData &column_data;
@@ -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
@@ -665,6 +665,7 @@ unique_ptr<PendingQueryResult> ClientContext::PendingStatementOrPreparedStatemen
665
665
  statement = std::move(copied_statement);
666
666
  break;
667
667
  }
668
+ #ifndef DUCKDB_ALTERNATIVE_VERIFY
668
669
  case StatementType::COPY_STATEMENT:
669
670
  case StatementType::INSERT_STATEMENT:
670
671
  case StatementType::DELETE_STATEMENT:
@@ -685,6 +686,7 @@ unique_ptr<PendingQueryResult> ClientContext::PendingStatementOrPreparedStatemen
685
686
  statement = std::move(parser.statements[0]);
686
687
  break;
687
688
  }
689
+ #endif
688
690
  default:
689
691
  statement = std::move(copied_statement);
690
692
  break;
@@ -67,6 +67,7 @@ static ConfigurationOption internal_options[] = {DUCKDB_GLOBAL(AccessModeSetting
67
67
  DUCKDB_LOCAL(EnableProgressBarPrintSetting),
68
68
  DUCKDB_GLOBAL(ExperimentalParallelCSVSetting),
69
69
  DUCKDB_LOCAL(ExplainOutputSetting),
70
+ DUCKDB_GLOBAL(ExtensionDirectorySetting),
70
71
  DUCKDB_GLOBAL(ExternalThreadsSetting),
71
72
  DUCKDB_LOCAL(FileSearchPathSetting),
72
73
  DUCKDB_GLOBAL(ForceCompressionSetting),
@@ -144,9 +144,15 @@ unique_ptr<AttachedDatabase> DatabaseInstance::CreateAttachedDatabase(AttachInfo
144
144
  if (entry == config.storage_extensions.end()) {
145
145
  throw BinderException("Unrecognized storage type \"%s\"", type);
146
146
  }
147
- // use storage extension to create the initial database
148
- attached_database = make_unique<AttachedDatabase>(*this, Catalog::GetSystemCatalog(*this), *entry->second,
149
- info.name, info, access_mode);
147
+
148
+ if (entry->second->attach != nullptr && entry->second->create_transaction_manager != nullptr) {
149
+ // use storage extension to create the initial database
150
+ attached_database = make_unique<AttachedDatabase>(*this, Catalog::GetSystemCatalog(*this), *entry->second,
151
+ info.name, info, access_mode);
152
+ } else {
153
+ attached_database = make_unique<AttachedDatabase>(*this, Catalog::GetSystemCatalog(*this), info.name,
154
+ info.path, access_mode);
155
+ }
150
156
  } else {
151
157
  // check if this is an in-memory database or not
152
158
  attached_database =
@@ -200,6 +206,7 @@ void DatabaseInstance::Initialize(const char *database_path, DBConfig *user_conf
200
206
  AttachInfo info;
201
207
  info.name = AttachedDatabase::ExtractDatabaseName(config.options.database_path);
202
208
  info.path = config.options.database_path;
209
+
203
210
  auto attached_database = CreateAttachedDatabase(info, database_type, config.options.access_mode);
204
211
  auto initial_database = attached_database.get();
205
212
  {
@@ -356,7 +363,8 @@ idx_t DuckDB::NumberOfThreads() {
356
363
  }
357
364
 
358
365
  bool DatabaseInstance::ExtensionIsLoaded(const std::string &name) {
359
- return loaded_extensions.find(name) != loaded_extensions.end();
366
+ auto extension_name = ExtensionHelper::GetExtensionName(name);
367
+ return loaded_extensions.find(extension_name) != loaded_extensions.end();
360
368
  }
361
369
 
362
370
  bool DuckDB::ExtensionIsLoaded(const std::string &name) {
@@ -364,7 +372,8 @@ bool DuckDB::ExtensionIsLoaded(const std::string &name) {
364
372
  }
365
373
 
366
374
  void DatabaseInstance::SetExtensionLoaded(const std::string &name) {
367
- loaded_extensions.insert(name);
375
+ auto extension_name = ExtensionHelper::GetExtensionName(name);
376
+ loaded_extensions.insert(extension_name);
368
377
  }
369
378
 
370
379
  bool DatabaseInstance::TryGetCurrentSetting(const std::string &key, Value &result) {
@@ -24,8 +24,9 @@ ExtensionAlias ExtensionHelper::GetExtensionAlias(idx_t index) {
24
24
  }
25
25
 
26
26
  string ExtensionHelper::ApplyExtensionAlias(string extension_name) {
27
+ auto lname = StringUtil::Lower(extension_name);
27
28
  for (idx_t index = 0; internal_aliases[index].alias; index++) {
28
- if (extension_name == internal_aliases[index].alias) {
29
+ if (lname == internal_aliases[index].alias) {
29
30
  return internal_aliases[index].extension;
30
31
  }
31
32
  }
@@ -115,6 +115,21 @@ DefaultExtension ExtensionHelper::GetDefaultExtension(idx_t index) {
115
115
  return internal_extensions[index];
116
116
  }
117
117
 
118
+ //===--------------------------------------------------------------------===//
119
+ // Allow Auto-Install Extensions
120
+ //===--------------------------------------------------------------------===//
121
+ static const char *auto_install[] = {"motherduck", "postgres_scanner", "sqlite_scanner", nullptr};
122
+
123
+ bool ExtensionHelper::AllowAutoInstall(const string &extension) {
124
+ auto lcase = StringUtil::Lower(extension);
125
+ for (idx_t i = 0; auto_install[i]; i++) {
126
+ if (lcase == auto_install[i]) {
127
+ return true;
128
+ }
129
+ }
130
+ return false;
131
+ }
132
+
118
133
  //===--------------------------------------------------------------------===//
119
134
  // Load Statically Compiled Extension
120
135
  //===--------------------------------------------------------------------===//
@@ -38,22 +38,57 @@ const vector<string> ExtensionHelper::PathComponents() {
38
38
  return vector<string> {".duckdb", "extensions", GetVersionDirectoryName(), DuckDB::Platform()};
39
39
  }
40
40
 
41
- string ExtensionHelper::ExtensionDirectory(ClientContext &context) {
42
- auto &fs = FileSystem::GetFileSystem(context);
43
- string local_path = fs.GetHomeDirectory(FileSystem::GetFileOpener(context));
44
- if (!fs.DirectoryExists(local_path)) {
45
- throw IOException("Can't find the home directory at '%s'\nSpecify a home directory using the SET "
46
- "home_directory='/path/to/dir' option.",
47
- local_path);
41
+ string ExtensionHelper::ExtensionDirectory(DBConfig &config, FileSystem &fs, FileOpener *opener) {
42
+ string extension_directory;
43
+ if (!config.options.extension_directory.empty()) { // create the extension directory if not present
44
+ extension_directory = config.options.extension_directory;
45
+ // TODO this should probably live in the FileSystem
46
+ // convert random separators to platform-canonic
47
+ extension_directory = fs.ConvertSeparators(extension_directory);
48
+ // expand ~ in extension directory
49
+ extension_directory = fs.ExpandPath(extension_directory, opener);
50
+ if (!fs.DirectoryExists(extension_directory)) {
51
+ auto sep = fs.PathSeparator();
52
+ auto splits = StringUtil::Split(extension_directory, sep);
53
+ D_ASSERT(!splits.empty());
54
+ string extension_directory_prefix;
55
+ if (StringUtil::StartsWith(extension_directory, sep)) {
56
+ extension_directory_prefix = sep; // this is swallowed by Split otherwise
57
+ }
58
+ for (auto &split : splits) {
59
+ extension_directory_prefix = extension_directory_prefix + split + sep;
60
+ if (!fs.DirectoryExists(extension_directory_prefix)) {
61
+ fs.CreateDirectory(extension_directory_prefix);
62
+ }
63
+ }
64
+ }
65
+ } else { // otherwise default to home
66
+ string home_directory = fs.GetHomeDirectory(opener);
67
+ // exception if the home directory does not exist, don't create whatever we think is home
68
+ if (!fs.DirectoryExists(home_directory)) {
69
+ throw IOException("Can't find the home directory at '%s'\nSpecify a home directory using the SET "
70
+ "home_directory='/path/to/dir' option.",
71
+ home_directory);
72
+ }
73
+ extension_directory = home_directory;
48
74
  }
75
+ D_ASSERT(fs.DirectoryExists(extension_directory));
76
+
49
77
  auto path_components = PathComponents();
50
78
  for (auto &path_ele : path_components) {
51
- local_path = fs.JoinPath(local_path, path_ele);
52
- if (!fs.DirectoryExists(local_path)) {
53
- fs.CreateDirectory(local_path);
79
+ extension_directory = fs.JoinPath(extension_directory, path_ele);
80
+ if (!fs.DirectoryExists(extension_directory)) {
81
+ fs.CreateDirectory(extension_directory);
54
82
  }
55
83
  }
56
- return local_path;
84
+ return extension_directory;
85
+ }
86
+
87
+ string ExtensionHelper::ExtensionDirectory(ClientContext &context) {
88
+ auto &config = DBConfig::GetConfig(context);
89
+ auto &fs = FileSystem::GetFileSystem(context);
90
+ auto opener = FileSystem::GetFileOpener(context);
91
+ return ExtensionDirectory(config, fs, opener);
57
92
  }
58
93
 
59
94
  bool ExtensionHelper::CreateSuggestions(const string &extension_name, string &message) {
@@ -75,15 +110,24 @@ bool ExtensionHelper::CreateSuggestions(const string &extension_name, string &me
75
110
  return false;
76
111
  }
77
112
 
113
+ void ExtensionHelper::InstallExtension(DBConfig &config, FileSystem &fs, const string &extension, bool force_install) {
114
+ string local_path = ExtensionDirectory(config, fs, nullptr);
115
+ InstallExtensionInternal(config, nullptr, fs, local_path, extension, force_install);
116
+ }
117
+
78
118
  void ExtensionHelper::InstallExtension(ClientContext &context, const string &extension, bool force_install) {
79
119
  auto &config = DBConfig::GetConfig(context);
80
- if (!config.options.enable_external_access) {
81
- throw PermissionException("Installing extensions is disabled through configuration");
82
- }
83
120
  auto &fs = FileSystem::GetFileSystem(context);
84
-
85
121
  string local_path = ExtensionDirectory(context);
122
+ auto &client_config = ClientConfig::GetConfig(context);
123
+ InstallExtensionInternal(config, &client_config, fs, local_path, extension, force_install);
124
+ }
86
125
 
126
+ void ExtensionHelper::InstallExtensionInternal(DBConfig &config, ClientConfig *client_config, FileSystem &fs,
127
+ const string &local_path, const string &extension, bool force_install) {
128
+ if (!config.options.enable_external_access) {
129
+ throw PermissionException("Installing extensions is disabled through configuration");
130
+ }
87
131
  auto extension_name = ApplyExtensionAlias(fs.ExtractBaseName(extension));
88
132
 
89
133
  string local_extension_path = fs.JoinPath(local_path, extension_name + ".duckdb_extension");
@@ -123,7 +167,7 @@ void ExtensionHelper::InstallExtension(ClientContext &context, const string &ext
123
167
 
124
168
  string default_endpoint = "http://extensions.duckdb.org";
125
169
  string versioned_path = "/${REVISION}/${PLATFORM}/${NAME}.duckdb_extension.gz";
126
- string &custom_endpoint = ClientConfig::GetConfig(context).custom_extension_repo;
170
+ string custom_endpoint = client_config ? client_config->custom_extension_repo : string();
127
171
  string &endpoint = !custom_endpoint.empty() ? custom_endpoint : default_endpoint;
128
172
  string url_template = endpoint + versioned_path;
129
173
 
@@ -22,7 +22,8 @@ static T LoadFunctionFromDLL(void *dll, const string &function_name, const strin
22
22
  return (T)function;
23
23
  }
24
24
 
25
- ExtensionInitResult ExtensionHelper::InitialLoad(DBConfig &config, FileOpener *opener, const string &extension) {
25
+ bool ExtensionHelper::TryInitialLoad(DBConfig &config, FileOpener *opener, const string &extension,
26
+ ExtensionInitResult &result, string &error) {
26
27
  if (!config.options.enable_external_access) {
27
28
  throw PermissionException("Loading external extensions is disabled through configuration");
28
29
  }
@@ -31,8 +32,14 @@ ExtensionInitResult ExtensionHelper::InitialLoad(DBConfig &config, FileOpener *o
31
32
  auto filename = fs.ConvertSeparators(extension);
32
33
 
33
34
  // shorthand case
34
- if (!StringUtil::Contains(extension, ".") && !StringUtil::Contains(extension, fs.PathSeparator())) {
35
- string local_path = fs.GetHomeDirectory(opener);
35
+ if (!ExtensionHelper::IsFullPath(extension)) {
36
+ string local_path = !config.options.extension_directory.empty() ? config.options.extension_directory
37
+ : fs.GetHomeDirectory(opener);
38
+
39
+ // convert random separators to platform-canonic
40
+ local_path = fs.ConvertSeparators(local_path);
41
+ // expand ~ in extension directory
42
+ local_path = fs.ExpandPath(local_path, opener);
36
43
  auto path_components = PathComponents();
37
44
  for (auto &path_ele : path_components) {
38
45
  local_path = fs.JoinPath(local_path, path_ele);
@@ -40,14 +47,14 @@ ExtensionInitResult ExtensionHelper::InitialLoad(DBConfig &config, FileOpener *o
40
47
  string extension_name = ApplyExtensionAlias(extension);
41
48
  filename = fs.JoinPath(local_path, extension_name + ".duckdb_extension");
42
49
  }
43
-
44
50
  if (!fs.FileExists(filename)) {
45
51
  string message;
46
52
  bool exact_match = ExtensionHelper::CreateSuggestions(extension, message);
47
53
  if (exact_match) {
48
54
  message += "\nInstall it first using \"INSTALL " + extension + "\".";
49
55
  }
50
- throw IOException("Extension \"%s\" not found.\n%s", filename, message);
56
+ error = StringUtil::Format("Extension \"%s\" not found.\n%s", filename, message);
57
+ return false;
51
58
  }
52
59
  if (!config.options.allow_unsigned_extensions) {
53
60
  auto handle = fs.OpenFile(filename, FileFlags::FILE_FLAGS_READ);
@@ -114,16 +121,43 @@ ExtensionInitResult ExtensionHelper::InitialLoad(DBConfig &config, FileOpener *o
114
121
  extension_version, engine_version);
115
122
  }
116
123
 
117
- ExtensionInitResult res;
118
- res.basename = basename;
119
- res.filename = filename;
120
- res.lib_hdl = lib_hdl;
121
- return res;
124
+ result.basename = basename;
125
+ result.filename = filename;
126
+ result.lib_hdl = lib_hdl;
127
+ return true;
128
+ }
129
+
130
+ ExtensionInitResult ExtensionHelper::InitialLoad(DBConfig &config, FileOpener *opener, const string &extension) {
131
+ string error;
132
+ ExtensionInitResult result;
133
+ if (!TryInitialLoad(config, opener, extension, result, error)) {
134
+ throw IOException(error);
135
+ }
136
+ return result;
137
+ }
138
+
139
+ bool ExtensionHelper::IsFullPath(const string &extension) {
140
+ return StringUtil::Contains(extension, ".") || StringUtil::Contains(extension, "/") ||
141
+ StringUtil::Contains(extension, "\\");
142
+ }
143
+
144
+ string ExtensionHelper::GetExtensionName(const string &extension) {
145
+ if (!IsFullPath(extension)) {
146
+ return extension;
147
+ }
148
+ auto splits = StringUtil::Split(StringUtil::Replace(extension, "\\", "/"), '/');
149
+ if (splits.empty()) {
150
+ return extension;
151
+ }
152
+ splits = StringUtil::Split(splits.back(), '.');
153
+ if (splits.empty()) {
154
+ return extension;
155
+ }
156
+ return StringUtil::Lower(splits.front());
122
157
  }
123
158
 
124
159
  void ExtensionHelper::LoadExternalExtension(DatabaseInstance &db, FileOpener *opener, const string &extension) {
125
- auto &loaded_extensions = db.LoadedExtensions();
126
- if (loaded_extensions.find(extension) != loaded_extensions.end()) {
160
+ if (db.ExtensionIsLoaded(extension)) {
127
161
  return;
128
162
  }
129
163
 
@@ -149,7 +183,22 @@ void ExtensionHelper::LoadExternalExtension(ClientContext &context, const string
149
183
 
150
184
  void ExtensionHelper::StorageInit(string &extension, DBConfig &config) {
151
185
  extension = ExtensionHelper::ApplyExtensionAlias(extension);
152
- auto res = InitialLoad(config, nullptr, extension); // TODO opener
186
+ ExtensionInitResult res;
187
+ string error;
188
+ if (!TryInitialLoad(config, nullptr, extension, res, error)) {
189
+ if (!ExtensionHelper::AllowAutoInstall(extension)) {
190
+ throw IOException(error);
191
+ }
192
+ // the extension load failed - try installing the extension
193
+ if (!config.file_system) {
194
+ throw InternalException("Attempting to install an extension without a file system");
195
+ }
196
+ ExtensionHelper::InstallExtension(config, *config.file_system, extension, false);
197
+ // try loading again
198
+ if (!TryInitialLoad(config, nullptr, extension, res, error)) {
199
+ throw IOException(error);
200
+ }
201
+ }
153
202
  auto storage_fun_name = res.basename + "_storage_init";
154
203
 
155
204
  ext_storage_init_t storage_init_fun;