Repository: duckdb/duckdb
File: src/storage/caching_file_system_wrapper.cpp (C++)

Code before:
#include "duckdb/storage/caching_file_system_wrapper.hpp"

#include "duckdb/common/exception.hpp"
#include "duckdb/common/file_system.hpp"
#include "duckdb/common/numeric_utils.hpp"
#include "duckdb/main/client_context.hpp"
#include "duckdb/main/database.hpp"

namespace duckdb {

namespace {
// Get database instance from file opener, throw InvalidInput exception.
DatabaseInstance &GetDatabaseInstance(optional_ptr<FileOpener> file_opener) {
	if (file_opener == nullptr) {
		throw InvalidInputException("Cannot get database instance out of file opener, because file opener is nullptr.");
	}
	auto database_ptr = file_opener->TryGetDatabase();
	if (database_ptr == nullptr) {
		throw InvalidInputException("Cannot extract database instance out of file opener.");
	}
	return *database_ptr;
}
} // namespace

//===----------------------------------------------------------------------===//
// CachingFileHandleWrapper implementation
//===----------------------------------------------------------------------===//
CachingFileHandleWrapper::CachingFileHandleWrapper(CachingFileSystemWrapper &file_system,
                                                   unique_ptr<CachingFileHandle> handle, FileOpenFlags flags)
    : FileHandle(file_system, handle->GetPath(), flags), caching_handle(std::move(handle)) {
	// Flags should already be validated to be read-only in OpenFileExtended
}

void CachingFileHandleWrapper::PinCachingFileSystem(shared_ptr<CachingFileSystemWrapper> caching_filesystem_p) {
	if (caching_file_system != nullptr) {
		throw InvalidInputException("Caching filesystem already set for caching file handle!");
	}

Review comment (bug):
It's intentionally to throw exception when we fail to get a database instance.
Consider real production usage:
```cpp
// the filesystem returned is a `OpenerFileSystem`, which auto-populates opener arg at open.
auto &fs = FileSystem::GetFileSystem(context);
auto file_handle = fs.OpenFile(path, flag);
```
otherwise we will have to pass another database instance in `FileOpenFlags` or `CachingMode`, which I think it redundant and semantically unclear.

Code after:
#include "duckdb/storage/caching_file_system_wrapper.hpp"

#include "duckdb/common/exception.hpp"
#include "duckdb/common/file_system.hpp"
#include "duckdb/common/numeric_utils.hpp"
#include "duckdb/main/client_context.hpp"
#include "duckdb/main/database.hpp"

namespace duckdb {

namespace {
// Get database instance from file opener, throw InvalidInput exception.
DatabaseInstance &GetDatabaseInstance(optional_ptr<FileOpener> file_opener) {
	if (file_opener == nullptr) {
		throw InvalidInputException("Cannot get database instance out of file opener, because file opener is nullptr.");
	}
	auto database_ptr = file_opener->TryGetDatabase();
	if (database_ptr == nullptr) {
		throw InvalidInputException("Cannot extract database instance out of file opener.");
	}
	return *database_ptr;
}
} // namespace

//===----------------------------------------------------------------------===//
// CachingFileHandleWrapper implementation
//===----------------------------------------------------------------------===//
CachingFileHandleWrapper::CachingFileHandleWrapper(shared_ptr<CachingFileSystemWrapper> file_system,
                                                   unique_ptr<CachingFileHandle> handle, FileOpenFlags flags)
    : FileHandle(*file_system, handle->GetPath(), flags), caching_file_system(std::move(file_system)),
      caching_handle(std::move(handle)) {
	D_ASSERT(!flags.OpenForWriting());
	D_ASSERT(!flags.OpenForAppending());
}

CachingFileHandleWrapper::~CachingFileHandleWrapper() {
}