duckdb 0.6.2-dev2115.0 → 0.6.2-dev2226.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.
Files changed (85) hide show
  1. package/package.json +1 -1
  2. package/src/duckdb/extension/json/buffered_json_reader.cpp +18 -5
  3. package/src/duckdb/extension/json/include/buffered_json_reader.hpp +6 -1
  4. package/src/duckdb/extension/json/include/json_common.hpp +1 -0
  5. package/src/duckdb/extension/json/include/json_scan.hpp +7 -0
  6. package/src/duckdb/extension/json/include/json_transform.hpp +25 -10
  7. package/src/duckdb/extension/json/json_common.cpp +6 -2
  8. package/src/duckdb/extension/json/json_functions/json_structure.cpp +47 -9
  9. package/src/duckdb/extension/json/json_functions/json_transform.cpp +183 -106
  10. package/src/duckdb/extension/json/json_functions/read_json.cpp +35 -22
  11. package/src/duckdb/extension/json/json_scan.cpp +26 -5
  12. package/src/duckdb/extension/parquet/parquet-extension.cpp +1 -0
  13. package/src/duckdb/src/catalog/catalog.cpp +11 -12
  14. package/src/duckdb/src/catalog/catalog_entry/duck_table_entry.cpp +1 -1
  15. package/src/duckdb/src/common/box_renderer.cpp +9 -1
  16. package/src/duckdb/src/common/compressed_file_system.cpp +1 -1
  17. package/src/duckdb/src/common/enums/relation_type.cpp +2 -0
  18. package/src/duckdb/src/common/gzip_file_system.cpp +1 -1
  19. package/src/duckdb/src/common/local_file_system.cpp +1 -1
  20. package/src/duckdb/src/common/row_operations/row_aggregate.cpp +2 -2
  21. package/src/duckdb/src/common/types/column_data_allocator.cpp +2 -2
  22. package/src/duckdb/src/common/types/date.cpp +7 -2
  23. package/src/duckdb/src/common/types/vector.cpp +3 -2
  24. package/src/duckdb/src/common/virtual_file_system.cpp +1 -1
  25. package/src/duckdb/src/execution/index/art/art.cpp +5 -5
  26. package/src/duckdb/src/execution/join_hashtable.cpp +4 -5
  27. package/src/duckdb/src/execution/operator/persistent/physical_update.cpp +2 -0
  28. package/src/duckdb/src/execution/operator/projection/physical_unnest.cpp +182 -123
  29. package/src/duckdb/src/execution/operator/schema/physical_attach.cpp +22 -18
  30. package/src/duckdb/src/execution/physical_plan/plan_create_table.cpp +1 -1
  31. package/src/duckdb/src/function/aggregate/distributive/arg_min_max.cpp +2 -3
  32. package/src/duckdb/src/function/scalar/math/setseed.cpp +1 -1
  33. package/src/duckdb/src/function/scalar/string/substring.cpp +8 -0
  34. package/src/duckdb/src/function/table/read_csv.cpp +1 -1
  35. package/src/duckdb/src/function/table/version/pragma_version.cpp +2 -2
  36. package/src/duckdb/src/include/duckdb/catalog/catalog.hpp +2 -0
  37. package/src/duckdb/src/include/duckdb/common/box_renderer.hpp +4 -0
  38. package/src/duckdb/src/include/duckdb/common/enums/relation_type.hpp +1 -0
  39. package/src/duckdb/src/include/duckdb/common/file_opener.hpp +2 -0
  40. package/src/duckdb/src/include/duckdb/common/http_stats.hpp +1 -1
  41. package/src/duckdb/src/include/duckdb/common/limits.hpp +3 -0
  42. package/src/duckdb/src/include/duckdb/common/types/validity_mask.hpp +1 -9
  43. package/src/duckdb/src/include/duckdb/common/types/vector.hpp +2 -2
  44. package/src/duckdb/src/include/duckdb/execution/executor.hpp +3 -0
  45. package/src/duckdb/src/include/duckdb/execution/index/art/art.hpp +3 -3
  46. package/src/duckdb/src/include/duckdb/execution/operator/projection/physical_unnest.hpp +5 -1
  47. package/src/duckdb/src/include/duckdb/main/client_context.hpp +3 -0
  48. package/src/duckdb/src/include/duckdb/main/config.hpp +0 -4
  49. package/src/duckdb/src/include/duckdb/main/database.hpp +6 -0
  50. package/src/duckdb/src/include/duckdb/main/extension_helper.hpp +5 -5
  51. package/src/duckdb/src/include/duckdb/main/relation/write_csv_relation.hpp +2 -1
  52. package/src/duckdb/src/include/duckdb/main/relation/write_parquet_relation.hpp +34 -0
  53. package/src/duckdb/src/include/duckdb/main/relation.hpp +6 -1
  54. package/src/duckdb/src/include/duckdb/parser/parsed_data/copy_info.hpp +2 -1
  55. package/src/duckdb/src/include/duckdb/parser/statement/copy_statement.hpp +1 -1
  56. package/src/duckdb/src/include/duckdb/planner/binder.hpp +1 -1
  57. package/src/duckdb/src/include/duckdb/storage/index.hpp +4 -3
  58. package/src/duckdb/src/include/duckdb.h +7 -0
  59. package/src/duckdb/src/main/capi/threading-c.cpp +8 -0
  60. package/src/duckdb/src/main/client_context.cpp +7 -0
  61. package/src/duckdb/src/main/client_context_file_opener.cpp +14 -0
  62. package/src/duckdb/src/main/database.cpp +57 -40
  63. package/src/duckdb/src/main/extension/extension_load.cpp +20 -28
  64. package/src/duckdb/src/main/relation/write_csv_relation.cpp +4 -2
  65. package/src/duckdb/src/main/relation/write_parquet_relation.cpp +37 -0
  66. package/src/duckdb/src/main/relation.cpp +12 -2
  67. package/src/duckdb/src/parallel/executor.cpp +4 -0
  68. package/src/duckdb/src/parser/statement/copy_statement.cpp +1 -1
  69. package/src/duckdb/src/parser/transform/statement/transform_show.cpp +4 -3
  70. package/src/duckdb/src/planner/binder/expression/bind_cast_expression.cpp +1 -1
  71. package/src/duckdb/src/planner/binder/statement/bind_create.cpp +24 -3
  72. package/src/duckdb/src/planner/binder/statement/bind_create_table.cpp +1 -1
  73. package/src/duckdb/src/planner/subquery/flatten_dependent_join.cpp +2 -0
  74. package/src/duckdb/src/storage/compression/bitpacking.cpp +2 -1
  75. package/src/duckdb/src/storage/compression/fixed_size_uncompressed.cpp +1 -1
  76. package/src/duckdb/src/storage/index.cpp +1 -1
  77. package/src/duckdb/src/storage/meta_block_writer.cpp +1 -1
  78. package/src/duckdb/src/storage/table/column_segment.cpp +3 -3
  79. package/src/duckdb/third_party/libpg_query/src_backend_parser_gram.cpp +1 -2
  80. package/src/duckdb/third_party/libpg_query/src_backend_parser_scan.cpp +539 -300
  81. package/src/duckdb/ub_src_main.cpp +0 -2
  82. package/src/duckdb/ub_src_main_relation.cpp +2 -0
  83. package/src/duckdb/src/include/duckdb/function/replacement_open.hpp +0 -54
  84. package/src/duckdb/src/include/duckdb/main/replacement_opens.hpp +0 -20
  85. package/src/duckdb/src/main/extension_prefix_opener.cpp +0 -55
@@ -74,6 +74,7 @@ struct NumericLimits<int32_t> {
74
74
  return 10;
75
75
  }
76
76
  };
77
+
77
78
  template <>
78
79
  struct NumericLimits<int64_t> {
79
80
  DUCKDB_API static constexpr int64_t Minimum() {
@@ -104,6 +105,7 @@ struct NumericLimits<hugeint_t> {
104
105
  return 39;
105
106
  }
106
107
  };
108
+
107
109
  template <>
108
110
  struct NumericLimits<uint8_t> {
109
111
  DUCKDB_API static constexpr uint8_t Minimum() {
@@ -119,6 +121,7 @@ struct NumericLimits<uint8_t> {
119
121
  return 3;
120
122
  }
121
123
  };
124
+
122
125
  template <>
123
126
  struct NumericLimits<uint16_t> {
124
127
  DUCKDB_API static constexpr uint16_t Minimum() {
@@ -83,15 +83,7 @@ public:
83
83
  return !validity_mask;
84
84
  }
85
85
  inline bool CheckAllValid(idx_t count) const {
86
- if (AllValid()) {
87
- return true;
88
- }
89
- idx_t entry_count = ValidityBuffer::EntryCount(count);
90
- idx_t valid_count = 0;
91
- for (idx_t i = 0; i < entry_count; i++) {
92
- valid_count += validity_mask[i] == ValidityBuffer::MAX_ENTRY;
93
- }
94
- return valid_count == entry_count;
86
+ return CountValid(count) == count;
95
87
  }
96
88
 
97
89
  inline bool CheckAllValid(idx_t to, idx_t from) const {
@@ -116,10 +116,10 @@ public:
116
116
 
117
117
  //! Converts this Vector to a printable string representation
118
118
  DUCKDB_API string ToString(idx_t count) const;
119
- DUCKDB_API void Print(idx_t count);
119
+ DUCKDB_API void Print(idx_t count) const;
120
120
 
121
121
  DUCKDB_API string ToString() const;
122
- DUCKDB_API void Print();
122
+ DUCKDB_API void Print() const;
123
123
 
124
124
  //! Flatten the vector, removing any compression and turning it into a FLAT_VECTOR
125
125
  DUCKDB_API void Flatten(idx_t count);
@@ -89,6 +89,9 @@ public:
89
89
  //! Returns the query result - can only be used if `HasResultCollector` returns true
90
90
  unique_ptr<QueryResult> GetResult();
91
91
 
92
+ //! Returns true if all pipelines have been completed
93
+ bool ExecutionIsFinished();
94
+
92
95
  private:
93
96
  void InitializeInternal(PhysicalOperator *physical_plan);
94
97
 
@@ -64,13 +64,13 @@ public:
64
64
  public:
65
65
  //! Initialize a scan on the index with the given expression and column ids
66
66
  //! to fetch from the base table for a single predicate
67
- unique_ptr<IndexScanState> InitializeScanSinglePredicate(Transaction &transaction, Value value,
67
+ unique_ptr<IndexScanState> InitializeScanSinglePredicate(const Transaction &transaction, const Value &value,
68
68
  ExpressionType expression_type) override;
69
69
 
70
70
  //! Initialize a scan on the index with the given expression and column ids
71
71
  //! to fetch from the base table for two predicates
72
- unique_ptr<IndexScanState> InitializeScanTwoPredicates(Transaction &transaction, Value low_value,
73
- ExpressionType low_expression_type, Value high_value,
72
+ unique_ptr<IndexScanState> InitializeScanTwoPredicates(Transaction &transaction, const Value &low_value,
73
+ ExpressionType low_expression_type, const Value &high_value,
74
74
  ExpressionType high_expression_type) override;
75
75
 
76
76
  //! Perform a lookup on the index
@@ -14,13 +14,14 @@
14
14
 
15
15
  namespace duckdb {
16
16
 
17
- //! PhysicalWindow implements window functions
17
+ //! PhysicalUnnest implements the physical UNNEST operation
18
18
  class PhysicalUnnest : public PhysicalOperator {
19
19
  public:
20
20
  PhysicalUnnest(vector<LogicalType> types, vector<unique_ptr<Expression>> select_list, idx_t estimated_cardinality,
21
21
  PhysicalOperatorType type = PhysicalOperatorType::UNNEST);
22
22
 
23
23
  //! The projection list of the UNNEST
24
+ //! E.g. SELECT 1, UNNEST([1]), UNNEST([2, 3]); has two UNNESTs in its select_list
24
25
  vector<unique_ptr<Expression>> select_list;
25
26
 
26
27
  public:
@@ -35,6 +36,9 @@ public:
35
36
  public:
36
37
  static unique_ptr<OperatorState> GetState(ExecutionContext &context,
37
38
  const vector<unique_ptr<Expression>> &select_list);
39
+ //! Executes the UNNEST operator internally and emits a chunk of unnested data. If include_input is set, then
40
+ //! the resulting chunk also contains vectors for all non-UNNEST columns in the projection. If include_input is
41
+ //! not set, then the UNNEST behaves as a table function and only emits the unnested data.
38
42
  static OperatorResultType ExecuteInternal(ExecutionContext &context, DataChunk &input, DataChunk &chunk,
39
43
  OperatorState &state, const vector<unique_ptr<Expression>> &select_list,
40
44
  bool include_input = true);
@@ -188,6 +188,9 @@ public:
188
188
 
189
189
  DUCKDB_API ClientProperties GetClientProperties() const;
190
190
 
191
+ //! Returns true if execution of the current query is finished
192
+ DUCKDB_API bool ExecutionIsFinished();
193
+
191
194
  private:
192
195
  //! Parse statements and resolve pragmas from a query
193
196
  bool ParseStatements(ClientContextLock &lock, const string &query, vector<unique_ptr<SQLStatement>> &result,
@@ -24,7 +24,6 @@
24
24
  #include "duckdb/common/winapi.hpp"
25
25
  #include "duckdb/storage/compression/bitpacking.hpp"
26
26
  #include "duckdb/function/cast/default_casts.hpp"
27
- #include "duckdb/function/replacement_open.hpp"
28
27
  #include "duckdb/function/replacement_scan.hpp"
29
28
  #include "duckdb/function/create_database_extension.hpp"
30
29
  #include "duckdb/optimizer/optimizer_extension.hpp"
@@ -163,9 +162,6 @@ public:
163
162
  //! Replacement table scans are automatically attempted when a table name cannot be found in the schema
164
163
  vector<ReplacementScan> replacement_scans;
165
164
 
166
- //! Replacement open handlers are callbacks that run pre and post database initialization
167
- vector<ReplacementOpen> replacement_opens;
168
-
169
165
  //! Extra parameters that can be SET for loaded extensions
170
166
  case_insensitive_map_t<ExtensionOption> extension_parameters;
171
167
  //! The FileSystem to use, can be overwritten to allow for injecting custom file systems for testing purposes (e.g.
@@ -23,6 +23,7 @@ class ConnectionManager;
23
23
  class FileSystem;
24
24
  class TaskScheduler;
25
25
  class ObjectCache;
26
+ struct AttachInfo;
26
27
 
27
28
  class DatabaseInstance : public std::enable_shared_from_this<DatabaseInstance> {
28
29
  friend class DuckDB;
@@ -48,9 +49,14 @@ public:
48
49
  DUCKDB_API static DatabaseInstance &GetDatabase(ClientContext &context);
49
50
 
50
51
  DUCKDB_API const unordered_set<std::string> &LoadedExtensions();
52
+ DUCKDB_API bool ExtensionIsLoaded(const std::string &name);
51
53
 
52
54
  DUCKDB_API bool TryGetCurrentSetting(const std::string &key, Value &result);
53
55
 
56
+ //! Get the database extension type from a given path
57
+ string ExtractDatabaseType(string &path);
58
+ unique_ptr<AttachedDatabase> CreateAttachedDatabase(AttachInfo &info, const string &type, AccessMode access_mode);
59
+
54
60
  private:
55
61
  void Initialize(const char *path, DBConfig *config);
56
62
 
@@ -42,6 +42,7 @@ public:
42
42
 
43
43
  static void InstallExtension(ClientContext &context, const string &extension, bool force_install);
44
44
  static void LoadExternalExtension(ClientContext &context, const string &extension);
45
+ static void LoadExternalExtension(DatabaseInstance &db, FileOpener *opener, const string &extension);
45
46
 
46
47
  static string ExtensionDirectory(ClientContext &context);
47
48
 
@@ -53,13 +54,14 @@ public:
53
54
 
54
55
  static const vector<string> GetPublicKeys();
55
56
 
56
- static unique_ptr<ReplacementOpenData> ReplacementOpenPre(const string &extension, DBConfig &config);
57
- static void ReplacementOpenPost(ClientContext &context, const string &extension, DatabaseInstance &instance,
58
- ReplacementOpenData *open_data);
57
+ static void StorageInit(string &extension, DBConfig &config);
59
58
 
60
59
  // Returns extension name, or empty string if not a replacement open path
61
60
  static string ExtractExtensionPrefixFromPath(const string &path);
62
61
 
62
+ //! Apply any known extension aliases
63
+ static string ApplyExtensionAlias(string extension_name);
64
+
63
65
  private:
64
66
  static const vector<string> PathComponents();
65
67
  static ExtensionInitResult InitialLoad(DBConfig &context, FileOpener *opener, const string &extension);
@@ -68,8 +70,6 @@ private:
68
70
  //! Version tags occur with and without 'v', tag in extension path is always with 'v'
69
71
  static const string NormalizeVersionTag(const string &version_tag);
70
72
  static bool IsRelease(const string &version_tag);
71
- //! Apply any known extension aliases
72
- static string ApplyExtensionAlias(string extension_name);
73
73
  static bool CreateSuggestions(const string &extension_name, string &message);
74
74
 
75
75
  private:
@@ -14,11 +14,12 @@ namespace duckdb {
14
14
 
15
15
  class WriteCSVRelation : public Relation {
16
16
  public:
17
- WriteCSVRelation(shared_ptr<Relation> child, string csv_file);
17
+ WriteCSVRelation(shared_ptr<Relation> child, string csv_file, case_insensitive_map_t<vector<Value>> options);
18
18
 
19
19
  shared_ptr<Relation> child;
20
20
  string csv_file;
21
21
  vector<ColumnDefinition> columns;
22
+ case_insensitive_map_t<vector<Value>> options;
22
23
 
23
24
  public:
24
25
  BoundStatement Bind(Binder &binder) override;
@@ -0,0 +1,34 @@
1
+ //===----------------------------------------------------------------------===//
2
+ // DuckDB
3
+ //
4
+ // duckdb/main/relation/write_csv_relation.hpp
5
+ //
6
+ //
7
+ //===----------------------------------------------------------------------===//
8
+
9
+ #pragma once
10
+
11
+ #include "duckdb/main/relation.hpp"
12
+
13
+ namespace duckdb {
14
+
15
+ class WriteParquetRelation : public Relation {
16
+ public:
17
+ WriteParquetRelation(shared_ptr<Relation> child, string parquet_file,
18
+ case_insensitive_map_t<vector<Value>> options);
19
+
20
+ shared_ptr<Relation> child;
21
+ string parquet_file;
22
+ vector<ColumnDefinition> columns;
23
+ case_insensitive_map_t<vector<Value>> options;
24
+
25
+ public:
26
+ BoundStatement Bind(Binder &binder) override;
27
+ const vector<ColumnDefinition> &Columns() override;
28
+ string ToString(idx_t depth) override;
29
+ bool IsReadOnly() override {
30
+ return false;
31
+ }
32
+ };
33
+
34
+ } // namespace duckdb
@@ -126,7 +126,12 @@ public:
126
126
  DUCKDB_API void Create(const string &schema_name, const string &table_name);
127
127
 
128
128
  //! Write a relation to a CSV file
129
- DUCKDB_API void WriteCSV(const string &csv_file);
129
+ DUCKDB_API void WriteCSV(const string &csv_file,
130
+ case_insensitive_map_t<vector<Value>> options = case_insensitive_map_t<vector<Value>>());
131
+ //! Write a relation to a Parquet file
132
+ DUCKDB_API void
133
+ WriteParquet(const string &parquet_file,
134
+ case_insensitive_map_t<vector<Value>> options = case_insensitive_map_t<vector<Value>>());
130
135
 
131
136
  //! Update a table, can only be used on a TableRelation
132
137
  DUCKDB_API virtual void Update(const string &update, const string &condition = string());
@@ -12,6 +12,7 @@
12
12
  #include "duckdb/common/vector.hpp"
13
13
  #include "duckdb/common/unordered_map.hpp"
14
14
  #include "duckdb/common/types/value.hpp"
15
+ #include "duckdb/common/case_insensitive_map.hpp"
15
16
 
16
17
  namespace duckdb {
17
18
 
@@ -34,7 +35,7 @@ struct CopyInfo : public ParseInfo {
34
35
  //! The file path to copy to/from
35
36
  string file_path;
36
37
  //! Set of (key, value) options
37
- unordered_map<string, vector<Value>> options;
38
+ case_insensitive_map_t<vector<Value>> options;
38
39
 
39
40
  public:
40
41
  unique_ptr<CopyInfo> Copy() const {
@@ -22,7 +22,7 @@ public:
22
22
  // The SQL statement used instead of a table when copying data out to a file
23
23
  unique_ptr<QueryNode> select_statement;
24
24
  string ToString() const override;
25
- string CopyOptionsToString(const string &format, const unordered_map<string, vector<Value>> &options) const;
25
+ string CopyOptionsToString(const string &format, const case_insensitive_map_t<vector<Value>> &options) const;
26
26
 
27
27
  protected:
28
28
  CopyStatement(const CopyStatement &other);
@@ -168,7 +168,7 @@ public:
168
168
  void BindOnConflictClause(LogicalInsert &insert, TableCatalogEntry &table, InsertStatement &stmt);
169
169
 
170
170
  static void BindSchemaOrCatalog(ClientContext &context, string &catalog, string &schema);
171
- static void BindLogicalType(ClientContext &context, LogicalType &type, const string &catalog = INVALID_CATALOG,
171
+ static void BindLogicalType(ClientContext &context, LogicalType &type, Catalog *catalog = nullptr,
172
172
  const string &schema = INVALID_SCHEMA);
173
173
 
174
174
  bool HasMatchingBinding(const string &table_name, const string &column_name, string &error_message);
@@ -66,12 +66,13 @@ public:
66
66
  public:
67
67
  //! Initialize a scan on the index with the given expression and column ids
68
68
  //! to fetch from the base table when we only have one query predicate
69
- virtual unique_ptr<IndexScanState> InitializeScanSinglePredicate(Transaction &transaction, Value value,
69
+ virtual unique_ptr<IndexScanState> InitializeScanSinglePredicate(const Transaction &transaction, const Value &value,
70
70
  ExpressionType expressionType) = 0;
71
71
  //! Initialize a scan on the index with the given expression and column ids
72
72
  //! to fetch from the base table for two query predicates
73
- virtual unique_ptr<IndexScanState> InitializeScanTwoPredicates(Transaction &transaction, Value low_value,
74
- ExpressionType low_expression_type, Value high_value,
73
+ virtual unique_ptr<IndexScanState> InitializeScanTwoPredicates(Transaction &transaction, const Value &low_value,
74
+ ExpressionType low_expression_type,
75
+ const Value &high_value,
75
76
  ExpressionType high_expression_type) = 0;
76
77
  //! Perform a lookup on the index, fetching up to max_count result ids. Returns true if all row ids were fetched,
77
78
  //! and false otherwise.
@@ -2287,6 +2287,13 @@ on the task state.
2287
2287
  */
2288
2288
  DUCKDB_API void duckdb_destroy_task_state(duckdb_task_state state);
2289
2289
 
2290
+ /*!
2291
+ Returns true if execution of the current query is finished.
2292
+
2293
+ * con: The connection on which to check
2294
+ */
2295
+ DUCKDB_API bool duckdb_execution_is_finished(duckdb_connection con);
2296
+
2290
2297
  #ifdef __cplusplus
2291
2298
  }
2292
2299
  #endif
@@ -78,3 +78,11 @@ void duckdb_destroy_task_state(duckdb_task_state state_p) {
78
78
  auto state = (CAPITaskState *)state_p;
79
79
  delete state;
80
80
  }
81
+
82
+ bool duckdb_execution_is_finished(duckdb_connection con) {
83
+ if (!con) {
84
+ return false;
85
+ }
86
+ duckdb::Connection *conn = (duckdb::Connection *)con;
87
+ return conn->context->ExecutionIsFinished();
88
+ }
@@ -1151,4 +1151,11 @@ ClientProperties ClientContext::GetClientProperties() const {
1151
1151
  return properties;
1152
1152
  }
1153
1153
 
1154
+ bool ClientContext::ExecutionIsFinished() {
1155
+ if (!active_query || !active_query->executor) {
1156
+ return false;
1157
+ }
1158
+ return active_query->executor->ExecutionIsFinished();
1159
+ }
1160
+
1154
1161
  } // namespace duckdb
@@ -8,4 +8,18 @@ bool ClientContextFileOpener::TryGetCurrentSetting(const string &key, Value &res
8
8
  return context.TryGetCurrentSetting(key, result);
9
9
  }
10
10
 
11
+ ClientContext *FileOpener::TryGetClientContext(FileOpener *opener) {
12
+ if (!opener) {
13
+ return nullptr;
14
+ }
15
+ return opener->TryGetClientContext();
16
+ }
17
+
18
+ bool FileOpener::TryGetCurrentSetting(FileOpener *opener, const string &key, Value &result) {
19
+ if (!opener) {
20
+ return false;
21
+ }
22
+ return opener->TryGetCurrentSetting(key, result);
23
+ }
24
+
11
25
  } // namespace duckdb
@@ -11,12 +11,12 @@
11
11
  #include "duckdb/main/connection_manager.hpp"
12
12
  #include "duckdb/function/compression_function.hpp"
13
13
  #include "duckdb/main/extension_helper.hpp"
14
- #include "duckdb/main/replacement_opens.hpp"
15
14
  #include "duckdb/function/cast/cast_function_set.hpp"
16
15
  #include "duckdb/main/error_manager.hpp"
17
16
  #include "duckdb/main/attached_database.hpp"
18
17
  #include "duckdb/parser/parsed_data/attach_info.hpp"
19
18
  #include "duckdb/storage/magic_bytes.hpp"
19
+ #include "duckdb/storage/storage_extension.hpp"
20
20
 
21
21
  #ifndef DUCKDB_NO_THREADS
22
22
  #include "duckdb/common/thread.hpp"
@@ -26,7 +26,6 @@ namespace duckdb {
26
26
 
27
27
  DBConfig::DBConfig() {
28
28
  compression_functions = make_unique<CompressionFunctionSet>();
29
- replacement_opens.push_back(ExtensionPrefixReplacementOpen());
30
29
  cast_functions = make_unique<CastFunctionSet>();
31
30
  error_manager = make_unique<ErrorManager>();
32
31
  }
@@ -123,6 +122,42 @@ ConnectionManager &ConnectionManager::Get(ClientContext &context) {
123
122
  return ConnectionManager::Get(DatabaseInstance::GetDatabase(context));
124
123
  }
125
124
 
125
+ string DatabaseInstance::ExtractDatabaseType(string &path) {
126
+ // first check if there is an existing prefix
127
+ auto extension = ExtensionHelper::ExtractExtensionPrefixFromPath(path);
128
+ if (!extension.empty()) {
129
+ // path is prefixed with an extension - remove it
130
+ path = StringUtil::Replace(path, extension + ":", "");
131
+ return extension;
132
+ }
133
+ // if there isn't - check the magic bytes of the file (if any)
134
+ auto file_type = MagicBytes::CheckMagicBytes(config.file_system.get(), path);
135
+ if (file_type == DataFileType::SQLITE_FILE) {
136
+ return "sqlite";
137
+ }
138
+ return string();
139
+ }
140
+
141
+ unique_ptr<AttachedDatabase> DatabaseInstance::CreateAttachedDatabase(AttachInfo &info, const string &type,
142
+ AccessMode access_mode) {
143
+ unique_ptr<AttachedDatabase> attached_database;
144
+ if (!type.empty()) {
145
+ // find the storage extensionon database
146
+ auto entry = config.storage_extensions.find(type);
147
+ if (entry == config.storage_extensions.end()) {
148
+ throw BinderException("Unrecognized storage type \"%s\"", type);
149
+ }
150
+ // use storage extension to create the initial database
151
+ attached_database = make_unique<AttachedDatabase>(*this, Catalog::GetSystemCatalog(*this), *entry->second,
152
+ info.name, info, access_mode);
153
+ } else {
154
+ // check if this is an in-memory database or not
155
+ attached_database =
156
+ make_unique<AttachedDatabase>(*this, Catalog::GetSystemCatalog(*this), info.name, info.path, access_mode);
157
+ }
158
+ return attached_database;
159
+ }
160
+
126
161
  void DatabaseInstance::Initialize(const char *database_path, DBConfig *user_config) {
127
162
  DBConfig default_config;
128
163
  DBConfig *config_ptr = &default_config;
@@ -145,22 +180,6 @@ void DatabaseInstance::Initialize(const char *database_path, DBConfig *user_conf
145
180
  } else {
146
181
  config_ptr->options.database_path.clear();
147
182
  }
148
-
149
- auto file_type = MagicBytes::CheckMagicBytes(config_ptr->file_system.get(), config_ptr->options.database_path);
150
- if (file_type == DataFileType::SQLITE_FILE) {
151
- config_ptr->options.database_path = "sqlite:" + config_ptr->options.database_path;
152
- }
153
-
154
- ReplacementOpen *replacement_open = nullptr;
155
- for (auto &open : config_ptr->replacement_opens) {
156
- if (open.pre_func) {
157
- open.data = open.pre_func(*config_ptr, open.static_data.get());
158
- if (open.data) {
159
- replacement_open = &open;
160
- break;
161
- }
162
- }
163
- }
164
183
  Configure(*config_ptr);
165
184
 
166
185
  if (user_config && !user_config->options.use_temporary_directory) {
@@ -168,7 +187,6 @@ void DatabaseInstance::Initialize(const char *database_path, DBConfig *user_conf
168
187
  config.options.temporary_directory = string();
169
188
  }
170
189
 
171
- auto &config = DBConfig::GetConfig(*this);
172
190
  db_manager = make_unique<DatabaseManager>(*this);
173
191
  buffer_manager =
174
192
  make_unique<BufferManager>(*this, config.options.temporary_directory, config.options.maximum_memory);
@@ -176,22 +194,16 @@ void DatabaseInstance::Initialize(const char *database_path, DBConfig *user_conf
176
194
  object_cache = make_unique<ObjectCache>();
177
195
  connection_manager = make_unique<ConnectionManager>();
178
196
 
179
- auto database_name = AttachedDatabase::ExtractDatabaseName(config.options.database_path);
180
- unique_ptr<AttachedDatabase> attached_database;
181
- if (replacement_open && replacement_open->data && replacement_open->data->HasStorageExtension()) {
182
- // use storage extension from replacement open to create initial database
183
- AttachInfo info;
184
- info.name = database_name;
185
- info.path = config.options.database_path;
186
- auto storage_extension = replacement_open->data->GetStorageExtension(info);
187
- attached_database = make_unique<AttachedDatabase>(*this, Catalog::GetSystemCatalog(*this), *storage_extension,
188
- database_name, info, config.options.access_mode);
189
- replacement_open = nullptr;
190
- } else {
191
- // check if this is an in-memory database or not
192
- attached_database = make_unique<AttachedDatabase>(*this, Catalog::GetSystemCatalog(*this), database_name,
193
- config.options.database_path, config.options.access_mode);
197
+ // check if we are opening a standard DuckDB database or an extension database
198
+ auto database_type = ExtractDatabaseType(config.options.database_path);
199
+ if (!database_type.empty()) {
200
+ // we are opening an extension database, run storage_init
201
+ ExtensionHelper::StorageInit(database_type, config);
194
202
  }
203
+ AttachInfo info;
204
+ info.name = AttachedDatabase::ExtractDatabaseName(config.options.database_path);
205
+ info.path = config.options.database_path;
206
+ auto attached_database = CreateAttachedDatabase(info, database_type, config.options.access_mode);
195
207
  auto initial_database = attached_database.get();
196
208
  {
197
209
  Connection con(*this);
@@ -205,12 +217,13 @@ void DatabaseInstance::Initialize(const char *database_path, DBConfig *user_conf
205
217
  // initialize the database
206
218
  initial_database->Initialize();
207
219
 
220
+ if (!database_type.empty()) {
221
+ // if we are opening an extension database - load the extension
222
+ ExtensionHelper::LoadExternalExtension(*this, nullptr, database_type);
223
+ }
224
+
208
225
  // only increase thread count after storage init because we get races on catalog otherwise
209
226
  scheduler->SetThreads(config.options.maximum_threads);
210
-
211
- if (replacement_open) {
212
- replacement_open->post_func(*this, replacement_open->data.get());
213
- }
214
227
  }
215
228
 
216
229
  DuckDB::DuckDB(const char *path, DBConfig *new_config) : instance(make_shared<DatabaseInstance>()) {
@@ -294,7 +307,6 @@ void DatabaseInstance::Configure(DBConfig &new_config) {
294
307
  config.allocator = make_unique<Allocator>();
295
308
  }
296
309
  config.replacement_scans = std::move(new_config.replacement_scans);
297
- config.replacement_opens = std::move(new_config.replacement_opens);
298
310
  config.parser_extensions = std::move(new_config.parser_extensions);
299
311
  config.error_manager = std::move(new_config.error_manager);
300
312
  if (!config.error_manager) {
@@ -325,9 +337,14 @@ idx_t DuckDB::NumberOfThreads() {
325
337
  return instance->NumberOfThreads();
326
338
  }
327
339
 
340
+ bool DatabaseInstance::ExtensionIsLoaded(const std::string &name) {
341
+ return loaded_extensions.find(name) != loaded_extensions.end();
342
+ }
343
+
328
344
  bool DuckDB::ExtensionIsLoaded(const std::string &name) {
329
- return instance->loaded_extensions.find(name) != instance->loaded_extensions.end();
345
+ return instance->ExtensionIsLoaded(name);
330
346
  }
347
+
331
348
  void DatabaseInstance::SetExtensionLoaded(const std::string &name) {
332
349
  loaded_extensions.insert(name);
333
350
  }
@@ -1,6 +1,5 @@
1
1
  #include "duckdb/common/dl.hpp"
2
2
  #include "duckdb/common/virtual_file_system.hpp"
3
- #include "duckdb/function/replacement_open.hpp"
4
3
  #include "duckdb/main/extension_helper.hpp"
5
4
  #include "duckdb/main/error_manager.hpp"
6
5
  #include "mbedtls_wrapper.hpp"
@@ -12,6 +11,7 @@ namespace duckdb {
12
11
  //===--------------------------------------------------------------------===//
13
12
  typedef void (*ext_init_fun_t)(DatabaseInstance &);
14
13
  typedef const char *(*ext_version_fun_t)(void);
14
+ typedef void (*ext_storage_init_t)(DBConfig &);
15
15
 
16
16
  template <class T>
17
17
  static T LoadFunctionFromDLL(void *dll, const string &function_name, const string &filename) {
@@ -121,14 +121,13 @@ ExtensionInitResult ExtensionHelper::InitialLoad(DBConfig &config, FileOpener *o
121
121
  return res;
122
122
  }
123
123
 
124
- void ExtensionHelper::LoadExternalExtension(ClientContext &context, const string &extension) {
125
- auto &db = DatabaseInstance::GetDatabase(context);
124
+ void ExtensionHelper::LoadExternalExtension(DatabaseInstance &db, FileOpener *opener, const string &extension) {
126
125
  auto &loaded_extensions = db.LoadedExtensions();
127
126
  if (loaded_extensions.find(extension) != loaded_extensions.end()) {
128
127
  return;
129
128
  }
130
129
 
131
- auto res = InitialLoad(DBConfig::GetConfig(context), FileSystem::GetFileOpener(context), extension);
130
+ auto res = InitialLoad(DBConfig::GetConfig(db), opener, extension);
132
131
  auto init_fun_name = res.basename + "_init";
133
132
 
134
133
  ext_init_fun_t init_fun;
@@ -141,38 +140,27 @@ void ExtensionHelper::LoadExternalExtension(ClientContext &context, const string
141
140
  init_fun_name, res.filename, e.what());
142
141
  }
143
142
 
144
- DatabaseInstance::GetDatabase(context).SetExtensionLoaded(extension);
143
+ db.SetExtensionLoaded(extension);
145
144
  }
146
145
 
147
- unique_ptr<ReplacementOpenData> ExtensionHelper::ReplacementOpenPre(const string &extension, DBConfig &config) {
148
-
149
- auto res = InitialLoad(config, nullptr, extension); // TODO opener
150
- auto init_fun_name = res.basename + "_replacement_open_pre";
151
-
152
- replacement_open_pre_t open_pre_fun;
153
- open_pre_fun = LoadFunctionFromDLL<replacement_open_pre_t>(res.lib_hdl, init_fun_name, res.filename);
154
-
155
- try {
156
- return (*open_pre_fun)(config, nullptr);
157
- } catch (std::exception &e) {
158
- throw InvalidInputException("Initialization function \"%s\" from file \"%s\" threw an exception: \"%s\"",
159
- init_fun_name, res.filename, e.what());
160
- }
146
+ void ExtensionHelper::LoadExternalExtension(ClientContext &context, const string &extension) {
147
+ LoadExternalExtension(DatabaseInstance::GetDatabase(context), FileSystem::GetFileOpener(context), extension);
161
148
  }
162
149
 
163
- void ExtensionHelper::ReplacementOpenPost(ClientContext &context, const string &extension, DatabaseInstance &instance,
164
- ReplacementOpenData *open_data) {
165
- auto res = InitialLoad(DBConfig::GetConfig(context), FileSystem::GetFileOpener(context), extension);
166
- auto init_fun_name = res.basename + "_replacement_open_post";
150
+ void ExtensionHelper::StorageInit(string &extension, DBConfig &config) {
151
+ extension = ExtensionHelper::ApplyExtensionAlias(extension);
152
+ auto res = InitialLoad(config, nullptr, extension); // TODO opener
153
+ auto storage_fun_name = res.basename + "_storage_init";
167
154
 
168
- replacement_open_post_t open_post_fun;
169
- open_post_fun = LoadFunctionFromDLL<replacement_open_post_t>(res.lib_hdl, init_fun_name, res.filename);
155
+ ext_storage_init_t storage_init_fun;
156
+ storage_init_fun = LoadFunctionFromDLL<ext_storage_init_t>(res.lib_hdl, storage_fun_name, res.filename);
170
157
 
171
158
  try {
172
- (*open_post_fun)(instance, open_data);
159
+ (*storage_init_fun)(config);
173
160
  } catch (std::exception &e) {
174
- throw InvalidInputException("Initialization function \"%s\" from file \"%s\" threw an exception: \"%s\"",
175
- init_fun_name, res.filename, e.what());
161
+ throw InvalidInputException(
162
+ "Storage initialization function \"%s\" from file \"%s\" threw an exception: \"%s\"", storage_fun_name,
163
+ res.filename, e.what());
176
164
  }
177
165
  }
178
166
 
@@ -189,6 +177,10 @@ string ExtensionHelper::ExtractExtensionPrefixFromPath(const string &path) {
189
177
  return "";
190
178
  }
191
179
  }
180
+ if (extension == "http" || extension == "https" || extension == "s3") {
181
+ // these are not extensions
182
+ return "";
183
+ }
192
184
  return extension;
193
185
  }
194
186