Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/duckdb/src/catalog/catalog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1235,4 +1235,9 @@ void Catalog::FinalizeLoad(optional_ptr<ClientContext> context) {
void Catalog::OnDetach(ClientContext &context) {
}

bool Catalog::HasConflictingAttachOptions(const string &path, const AttachOptions &options) {
auto const db_type = options.db_type.empty() ? "duckdb" : options.db_type;
return GetDBPath() != path || GetCatalogType() != db_type;
}

} // namespace duckdb
7 changes: 3 additions & 4 deletions src/duckdb/src/common/sorting/hashed_sort.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,9 @@ HashedSortLocalSinkState::HashedSortLocalSinkState(ExecutionContext &context, co
}
// OVER(...)
payload_chunk.Initialize(allocator, payload_types);
} else {
unsorted = make_uniq<ColumnDataCollection>(context.client, hashed_sort.payload_types);
unsorted->InitializeAppend(unsorted_append);
}
}

Expand Down Expand Up @@ -369,10 +372,6 @@ SinkResultType HashedSort::Sink(ExecutionContext &context, DataChunk &input_chun

// OVER()
if (gstate.hashed_sort.sort_col_count == 0) {
if (!lstate.unsorted) {
lstate.unsorted = make_uniq<ColumnDataCollection>(context.client, payload_types);
lstate.unsorted->InitializeAppend(lstate.unsorted_append);
}
lstate.unsorted->Append(lstate.unsorted_append, input_chunk);
return SinkResultType::NEED_MORE_INPUT;
}
Expand Down
12 changes: 6 additions & 6 deletions src/duckdb/src/execution/operator/schema/physical_attach.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,8 @@ SourceResultType PhysicalAttach::GetData(ExecutionContext &context, DataChunk &c
existing_db->GetCatalog().SetDefaultTable(options.default_table.schema, options.default_table.name);
}
if (info->on_conflict == OnCreateConflict::REPLACE_ON_CONFLICT) {
// same path, name and type, DB does not need replacing
auto const db_type = options.db_type.empty() ? "duckdb" : options.db_type;
if (existing_db->GetCatalog().GetDBPath() == path &&
existing_db->GetCatalog().GetCatalogType() == db_type) {
// allow custom catalogs to override this behavior
if (!existing_db->GetCatalog().HasConflictingAttachOptions(path, options)) {
return SourceResultType::FINISHED;
}
} else {
Expand All @@ -63,9 +61,11 @@ SourceResultType PhysicalAttach::GetData(ExecutionContext &context, DataChunk &c
}
}

// Get the database type and attach the database.
db_manager.GetDatabaseType(context.client, *info, config, options);
// attach the database.
auto attached_db = db_manager.AttachDatabase(context.client, *info, options);
if (!attached_db) {
return SourceResultType::FINISHED;
}

//! Initialize the database.
attached_db->Initialize(context.client);
Expand Down
3 changes: 3 additions & 0 deletions src/duckdb/src/function/table/table_scan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,9 @@ class DuckTableScanState : public TableScanGlobalState {
l_state.scan_state.options.force_fetch_row = ClientConfig::GetConfig(context).force_fetch_row;

do {
if (context.interrupted) {
throw InterruptException();
}
if (bind_data.is_create_index) {
storage.CreateIndexScan(l_state.scan_state, output,
TableScanType::TABLE_SCAN_COMMITTED_ROWS_OMIT_PERMANENTLY_DELETED);
Expand Down
6 changes: 3 additions & 3 deletions src/duckdb/src/function/table/version/pragma_version.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#ifndef DUCKDB_PATCH_VERSION
#define DUCKDB_PATCH_VERSION "0-dev4120"
#define DUCKDB_PATCH_VERSION "0-dev4146"
#endif
#ifndef DUCKDB_MINOR_VERSION
#define DUCKDB_MINOR_VERSION 4
Expand All @@ -8,10 +8,10 @@
#define DUCKDB_MAJOR_VERSION 1
#endif
#ifndef DUCKDB_VERSION
#define DUCKDB_VERSION "v1.4.0-dev4120"
#define DUCKDB_VERSION "v1.4.0-dev4146"
#endif
#ifndef DUCKDB_SOURCE_ID
#define DUCKDB_SOURCE_ID "f8761864ef"
#define DUCKDB_SOURCE_ID "19dd651b26"
#endif
#include "duckdb/function/table/system_functions.hpp"
#include "duckdb/main/database.hpp"
Expand Down
4 changes: 4 additions & 0 deletions src/duckdb/src/include/duckdb/catalog/catalog.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include <functional>

namespace duckdb {
struct AttachOptions;
struct CreateSchemaInfo;
struct DropInfo;
struct BoundCreateTableInfo;
Expand Down Expand Up @@ -346,6 +347,9 @@ class Catalog {
//! Returns the dependency manager of this catalog - if the catalog has anye
virtual optional_ptr<DependencyManager> GetDependencyManager();

//! Whether attaching a catalog with the given path and attach options would be considered a conflict
virtual bool HasConflictingAttachOptions(const string &path, const AttachOptions &options);

public:
template <class T>
static optional_ptr<T> GetEntry(ClientContext &context, const string &catalog_name, const string &schema_name,
Expand Down
12 changes: 7 additions & 5 deletions src/duckdb/src/include/duckdb/main/attached_database.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ class StorageExtension;
class DatabaseManager;

struct AttachInfo;
struct StoredDatabasePath;

enum class AttachedDatabaseType {
READ_WRITE_DATABASE,
Expand All @@ -31,11 +32,13 @@ enum class AttachedDatabaseType {
TEMP_DATABASE,
};

class DatabaseFilePathManager;

struct StoredDatabasePath {
StoredDatabasePath(DatabaseManager &manager, string path, const string &name);
StoredDatabasePath(DatabaseFilePathManager &manager, string path, const string &name);
~StoredDatabasePath();

DatabaseManager &manager;
DatabaseFilePathManager &manager;
string path;
};

Expand All @@ -55,6 +58,8 @@ struct AttachOptions {
unordered_map<string, Value> options;
//! (optionally) a catalog can be provided with a default table
QualifiedName default_table;
//! The stored database path (in the path manager)
unique_ptr<StoredDatabasePath> stored_database_path;
};

//! The AttachedDatabase represents an attached database instance.
Expand Down Expand Up @@ -105,9 +110,6 @@ class AttachedDatabase : public CatalogEntry, public enable_shared_from_this<Att
static bool NameIsReserved(const string &name);
static string ExtractDatabaseName(const string &dbpath, FileSystem &fs);

private:
void InsertDatabasePath(const string &path);

private:
DatabaseInstance &db;
unique_ptr<StoredDatabasePath> stored_database_path;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,20 @@
#include "duckdb/common/common.hpp"
#include "duckdb/common/mutex.hpp"
#include "duckdb/common/case_insensitive_map.hpp"
#include "duckdb/common/enums/on_create_conflict.hpp"

namespace duckdb {
struct AttachInfo;
struct AttachOptions;

enum class InsertDatabasePathResult { SUCCESS, ALREADY_EXISTS };

//! The DatabaseFilePathManager is used to ensure we only ever open a single database file once
class DatabaseFilePathManager {
public:
void CheckPathConflict(const string &path, const string &name) const;
idx_t ApproxDatabaseCount() const;
void InsertDatabasePath(const string &path, const string &name);
InsertDatabasePathResult InsertDatabasePath(const string &path, const string &name, OnCreateConflict on_conflict,
AttachOptions &options);
void EraseDatabasePath(const string &path);

private:
Expand Down
6 changes: 1 addition & 5 deletions src/duckdb/src/include/duckdb/main/database_manager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,7 @@ class DatabaseManager {
void SetDefaultDatabase(ClientContext &context, const string &new_value);

//! Inserts a path to name mapping to the database paths map
void InsertDatabasePath(const string &path, const string &name);
//! Erases a path from the database paths map
void EraseDatabasePath(const string &path);
//! Check if a path has a conflict
void CheckPathConflict(const string &path, const string &name);
InsertDatabasePathResult InsertDatabasePath(const AttachInfo &info, AttachOptions &options);

//! Returns the database type. This might require checking the header of the file, in which case the file handle is
//! necessary. We can only grab the file handle, if it is not yet held, even for uncommitted changes. Thus, we have
Expand Down
2 changes: 2 additions & 0 deletions src/duckdb/src/include/duckdb/main/extension_entries.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -558,6 +558,8 @@ static constexpr ExtensionFunctionEntry EXTENSION_FUNCTIONS[] = {
{"st_area_spheroid", "spatial", CatalogType::SCALAR_FUNCTION_ENTRY},
{"st_asgeojson", "spatial", CatalogType::SCALAR_FUNCTION_ENTRY},
{"st_ashexwkb", "spatial", CatalogType::SCALAR_FUNCTION_ENTRY},
{"st_asmvt", "spatial", CatalogType::AGGREGATE_FUNCTION_ENTRY},
{"st_asmvtgeom", "spatial", CatalogType::SCALAR_FUNCTION_ENTRY},
{"st_assvg", "spatial", CatalogType::SCALAR_FUNCTION_ENTRY},
{"st_astext", "spatial", CatalogType::SCALAR_FUNCTION_ENTRY},
{"st_aswkb", "spatial", CatalogType::SCALAR_FUNCTION_ENTRY},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ class TableDataWriter {
void WriteTableData(Serializer &metadata_serializer);

virtual void WriteUnchangedTable(MetaBlockPointer pointer, idx_t total_rows) = 0;
virtual void FinalizeTable(const TableStatistics &global_stats, DataTableInfo *info, Serializer &serializer) = 0;
virtual void FinalizeTable(const TableStatistics &global_stats, DataTableInfo &info, RowGroupCollection &collection,
Serializer &serializer) = 0;
virtual unique_ptr<RowGroupWriter> GetRowGroupWriter(RowGroup &row_group) = 0;

virtual void AddRowGroup(RowGroupPointer &&row_group_pointer, unique_ptr<RowGroupWriter> writer);
Expand All @@ -54,7 +55,8 @@ class SingleFileTableDataWriter : public TableDataWriter {

public:
void WriteUnchangedTable(MetaBlockPointer pointer, idx_t total_rows) override;
void FinalizeTable(const TableStatistics &global_stats, DataTableInfo *info, Serializer &serializer) override;
void FinalizeTable(const TableStatistics &global_stats, DataTableInfo &info, RowGroupCollection &collection,
Serializer &serializer) override;
unique_ptr<RowGroupWriter> GetRowGroupWriter(RowGroup &row_group) override;
CheckpointType GetCheckpointType() const override;
MetadataManager &GetMetadataManager() override;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ struct MetadataBlock {

idx_t FreeBlocksToInteger();
void FreeBlocksFromInteger(idx_t blocks);
static vector<uint8_t> BlocksFromInteger(idx_t free_list);

string ToString() const;
};

struct MetadataPointer {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ class InMemoryTableDataWriter : public TableDataWriter {

public:
void WriteUnchangedTable(MetaBlockPointer pointer, idx_t total_rows) override;
void FinalizeTable(const TableStatistics &global_stats, DataTableInfo *info, Serializer &serializer) override;
void FinalizeTable(const TableStatistics &global_stats, DataTableInfo &info, RowGroupCollection &collection,
Serializer &serializer) override;
unique_ptr<RowGroupWriter> GetRowGroupWriter(RowGroup &row_group) override;
CheckpointType GetCheckpointType() const override;
MetadataManager &GetMetadataManager() override;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ class RowGroupCollection {
void Initialize(PersistentCollectionData &data);
void Initialize(PersistentTableData &data);
void InitializeEmpty();
void FinalizeCheckpoint(MetaBlockPointer pointer);

bool IsEmpty() const;

Expand Down
16 changes: 4 additions & 12 deletions src/duckdb/src/main/attached_database.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,17 @@

namespace duckdb {

StoredDatabasePath::StoredDatabasePath(DatabaseManager &manager, string path_p, const string &name)
StoredDatabasePath::StoredDatabasePath(DatabaseFilePathManager &manager, string path_p, const string &name)
: manager(manager), path(std::move(path_p)) {
manager.InsertDatabasePath(path, name);
}

StoredDatabasePath::~StoredDatabasePath() {
manager.EraseDatabasePath(path);
}

//===--------------------------------------------------------------------===//
// Attach Options
//===--------------------------------------------------------------------===//

AttachOptions::AttachOptions(const DBConfigOptions &options)
: access_mode(options.access_mode), db_type(options.database_type) {
}
Expand Down Expand Up @@ -102,7 +101,7 @@ AttachedDatabase::AttachedDatabase(DatabaseInstance &db, Catalog &catalog_p, str
}
// We create the storage after the catalog to guarantee we allow extensions to instantiate the DuckCatalog.
catalog = make_uniq<DuckCatalog>(*this);
InsertDatabasePath(file_path_p);
stored_database_path = std::move(options.stored_database_path);
storage = make_uniq<SingleFileStorageManager>(*this, std::move(file_path_p), options);
transaction_manager = make_uniq<DuckTransactionManager>(*this);
internal = true;
Expand All @@ -120,11 +119,11 @@ AttachedDatabase::AttachedDatabase(DatabaseInstance &db, Catalog &catalog_p, Sto

optional_ptr<StorageExtensionInfo> storage_info = storage_extension->storage_info.get();
catalog = storage_extension->attach(storage_info, context, *this, name, info, options);
stored_database_path = std::move(options.stored_database_path);
if (!catalog) {
throw InternalException("AttachedDatabase - attach function did not return a catalog");
}
if (catalog->IsDuckCatalog()) {
InsertDatabasePath(info.path);
// The attached database uses the DuckCatalog.
storage = make_uniq<SingleFileStorageManager>(*this, info.path, options);
}
Expand Down Expand Up @@ -152,13 +151,6 @@ bool AttachedDatabase::IsReadOnly() const {
return type == AttachedDatabaseType::READ_ONLY_DATABASE;
}

void AttachedDatabase::InsertDatabasePath(const string &path) {
if (path.empty() || path == IN_MEMORY_PATH) {
return;
}
stored_database_path = make_uniq<StoredDatabasePath>(db.GetDatabaseManager(), path, name);
}

bool AttachedDatabase::NameIsReserved(const string &name) {
return name == DEFAULT_SCHEMA || name == TEMP_CATALOG || name == SYSTEM_CATALOG;
}
Expand Down
7 changes: 2 additions & 5 deletions src/duckdb/src/main/database.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -298,17 +298,14 @@ void DatabaseInstance::Initialize(const char *database_path, DBConfig *user_conf
// initialize the secret manager
config.secret_manager->Initialize(*this);

// resolve the type of teh database we are opening
// resolve the type of the database we are opening
auto &fs = FileSystem::GetFileSystem(*this);
DBPathAndType::ResolveDatabaseType(fs, config.options.database_path, config.options.database_type);

// initialize the system catalog
db_manager->InitializeSystemCatalog();

if (config.options.database_type == "duckdb") {
config.options.database_type = string();
}
if (!config.options.database_type.empty()) {
if (!config.options.database_type.empty() && !StringUtil::CIEquals(config.options.database_type, "duckdb")) {
// if we are opening an extension database - load the extension
if (!config.file_system) {
throw InternalException("No file system!?");
Expand Down
27 changes: 11 additions & 16 deletions src/duckdb/src/main/database_file_path_manager.cpp
Original file line number Diff line number Diff line change
@@ -1,39 +1,34 @@
#include "duckdb/main/database_file_path_manager.hpp"
#include "duckdb/common/exception/binder_exception.hpp"
#include "duckdb/parser/parsed_data/attach_info.hpp"
#include "duckdb/main/attached_database.hpp"

namespace duckdb {

void DatabaseFilePathManager::CheckPathConflict(const string &path, const string &name) const {
if (path.empty() || path == IN_MEMORY_PATH) {
return;
}

lock_guard<mutex> path_lock(db_paths_lock);
auto entry = db_paths_to_name.find(path);
if (entry != db_paths_to_name.end()) {
throw BinderException("Unique file handle conflict: Cannot attach \"%s\" - the database file \"%s\" is already "
"attached by database \"%s\"",
name, path, entry->second);
}
}

idx_t DatabaseFilePathManager::ApproxDatabaseCount() const {
lock_guard<mutex> path_lock(db_paths_lock);
return db_paths_to_name.size();
}

void DatabaseFilePathManager::InsertDatabasePath(const string &path, const string &name) {
InsertDatabasePathResult DatabaseFilePathManager::InsertDatabasePath(const string &path, const string &name,
OnCreateConflict on_conflict,
AttachOptions &options) {
if (path.empty() || path == IN_MEMORY_PATH) {
return;
return InsertDatabasePathResult::SUCCESS;
}

lock_guard<mutex> path_lock(db_paths_lock);
auto entry = db_paths_to_name.emplace(path, name);
if (!entry.second) {
if (on_conflict == OnCreateConflict::IGNORE_ON_CONFLICT && entry.first->second == name) {
return InsertDatabasePathResult::ALREADY_EXISTS;
}
throw BinderException("Unique file handle conflict: Cannot attach \"%s\" - the database file \"%s\" is already "
"attached by database \"%s\"",
name, path, entry.first->second);
}
options.stored_database_path = make_uniq<StoredDatabasePath>(*this, path, name);
return InsertDatabasePathResult::SUCCESS;
}

void DatabaseFilePathManager::EraseDatabasePath(const string &path) {
Expand Down
Loading
Loading