/*
Copyright 2018-2024 Stichting DuckDB Foundation

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

#pragma once
#define DUCKDB_AMALGAMATION 1
#define DUCKDB_SOURCE_ID "af39bd0dcf"
#define DUCKDB_VERSION "v1.1.1"
#define DUCKDB_MAJOR_VERSION 1
#define DUCKDB_MINOR_VERSION 1
#define DUCKDB_PATCH_VERSION "1"
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb.hpp
//
//
//===----------------------------------------------------------------------===//



//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/main/connection.hpp
//
//
//===----------------------------------------------------------------------===//



//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/enums/profiler_format.hpp
//
//
//===----------------------------------------------------------------------===//



//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/constants.hpp
//
//
//===----------------------------------------------------------------------===//



#include <memory>
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/string.hpp
//
//
//===----------------------------------------------------------------------===//



#include <sstream>
#include <string>

namespace duckdb {
using std::string;
using std::stringstream;
} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/main/winapi.hpp
//
//
//===----------------------------------------------------------------------===//



#ifndef DUCKDB_API
#if defined(_WIN32) && !defined(__MINGW32__)
#ifdef DUCKDB_STATIC_BUILD
#define DUCKDB_API
#else
#if defined(DUCKDB_BUILD_LIBRARY) && !defined(DUCKDB_BUILD_LOADABLE_EXTENSION)
#define DUCKDB_API __declspec(dllexport)
#else
#define DUCKDB_API __declspec(dllimport)
#endif
#endif
#else
#define DUCKDB_API
#endif
#endif

#ifndef DUCKDB_EXTENSION_API
#ifdef _WIN32
#ifdef DUCKDB_STATIC_BUILD
#define DUCKDB_EXTENSION_API
#else
#ifdef DUCKDB_BUILD_LOADABLE_EXTENSION
#define DUCKDB_EXTENSION_API __declspec(dllexport)
#else
#define DUCKDB_EXTENSION_API
#endif
#endif
#else
#define DUCKDB_EXTENSION_API __attribute__((visibility("default")))
#endif
#endif



//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/exception.hpp
//
//
//===----------------------------------------------------------------------===//



//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/assert.hpp
//
//
//===----------------------------------------------------------------------===//





#if (defined(DUCKDB_USE_STANDARD_ASSERT) || !defined(DEBUG)) && !defined(DUCKDB_FORCE_ASSERT) && !defined(__MVS__)

#include <assert.h>
#define D_ASSERT assert
namespace duckdb {
DUCKDB_API void DuckDBAssertInternal(bool condition, const char *condition_name, const char *file, int linenr);
}

#else
namespace duckdb {
DUCKDB_API void DuckDBAssertInternal(bool condition, const char *condition_name, const char *file, int linenr);
}

#define D_ASSERT(condition) duckdb::DuckDBAssertInternal(bool(condition), #condition, __FILE__, __LINE__)

#endif

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/exception_format_value.hpp
//
//
//===----------------------------------------------------------------------===//








#include <stdint.h>
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/typedefs.hpp
//
//
//===----------------------------------------------------------------------===//



#include <cstdint>

namespace duckdb {

//! a saner size_t for loop indices etc
typedef uint64_t idx_t;

//! The type used for row identifiers
typedef int64_t row_t;

//! The type used for hashes
typedef uint64_t hash_t;

//! data pointers
typedef uint8_t data_t;
typedef data_t *data_ptr_t;
typedef const data_t *const_data_ptr_t;

//! Type used for the selection vector
typedef uint32_t sel_t;
//! Type used for transaction timestamps
typedef idx_t transaction_t;

//! Type used for column identifiers
typedef idx_t column_t;
//! Type used for storage (column) identifiers
typedef idx_t storage_t;

template <class SRC>
data_ptr_t data_ptr_cast(SRC *src) { // NOLINT: naming
	return reinterpret_cast<data_ptr_t>(src);
}

template <class SRC>
const_data_ptr_t const_data_ptr_cast(const SRC *src) { // NOLINT: naming
	return reinterpret_cast<const_data_ptr_t>(src);
}

template <class SRC>
char *char_ptr_cast(SRC *src) { // NOLINT: naming
	return reinterpret_cast<char *>(src);
}

template <class SRC>
const char *const_char_ptr_cast(const SRC *src) { // NOLINT: naming
	return reinterpret_cast<const char *>(src);
}

template <class SRC>
const unsigned char *const_uchar_ptr_cast(const SRC *src) { // NOLINT: naming
	return reinterpret_cast<const unsigned char *>(src);
}

template <class SRC>
uintptr_t CastPointerToValue(SRC *src) {
	return reinterpret_cast<uintptr_t>(src);
}

template <class SRC>
uint64_t cast_pointer_to_uint64(SRC *src) {
	return static_cast<uint64_t>(reinterpret_cast<uintptr_t>(src));
}

template <class SRC = data_t>
SRC *cast_uint64_to_pointer(uint64_t value) {
	return reinterpret_cast<SRC *>(static_cast<uintptr_t>(value));
}

} // namespace duckdb


namespace duckdb {

// Forward declaration to allow conversion between hugeint and uhugeint
struct uhugeint_t; // NOLINT: use numeric casing

struct hugeint_t { // NOLINT: use numeric casing
public:
	uint64_t lower;
	int64_t upper;

public:
	hugeint_t() = default;
	DUCKDB_API hugeint_t(int64_t value); // NOLINT: Allow implicit conversion from `int64_t`
	constexpr hugeint_t(int64_t upper, uint64_t lower) : lower(lower), upper(upper) {
	}
	constexpr hugeint_t(const hugeint_t &rhs) = default;
	constexpr hugeint_t(hugeint_t &&rhs) = default;
	hugeint_t &operator=(const hugeint_t &rhs) = default;
	hugeint_t &operator=(hugeint_t &&rhs) = default;

	DUCKDB_API string ToString() const;

	// comparison operators
	DUCKDB_API bool operator==(const hugeint_t &rhs) const;
	DUCKDB_API bool operator!=(const hugeint_t &rhs) const;
	DUCKDB_API bool operator<=(const hugeint_t &rhs) const;
	DUCKDB_API bool operator<(const hugeint_t &rhs) const;
	DUCKDB_API bool operator>(const hugeint_t &rhs) const;
	DUCKDB_API bool operator>=(const hugeint_t &rhs) const;

	// arithmetic operators
	DUCKDB_API hugeint_t operator+(const hugeint_t &rhs) const;
	DUCKDB_API hugeint_t operator-(const hugeint_t &rhs) const;
	DUCKDB_API hugeint_t operator*(const hugeint_t &rhs) const;
	DUCKDB_API hugeint_t operator/(const hugeint_t &rhs) const;
	DUCKDB_API hugeint_t operator%(const hugeint_t &rhs) const;
	DUCKDB_API hugeint_t operator-() const;

	// bitwise operators
	DUCKDB_API hugeint_t operator>>(const hugeint_t &rhs) const;
	DUCKDB_API hugeint_t operator<<(const hugeint_t &rhs) const;
	DUCKDB_API hugeint_t operator&(const hugeint_t &rhs) const;
	DUCKDB_API hugeint_t operator|(const hugeint_t &rhs) const;
	DUCKDB_API hugeint_t operator^(const hugeint_t &rhs) const;
	DUCKDB_API hugeint_t operator~() const;

	// in-place operators
	DUCKDB_API hugeint_t &operator+=(const hugeint_t &rhs);
	DUCKDB_API hugeint_t &operator-=(const hugeint_t &rhs);
	DUCKDB_API hugeint_t &operator*=(const hugeint_t &rhs);
	DUCKDB_API hugeint_t &operator/=(const hugeint_t &rhs);
	DUCKDB_API hugeint_t &operator%=(const hugeint_t &rhs);
	DUCKDB_API hugeint_t &operator>>=(const hugeint_t &rhs);
	DUCKDB_API hugeint_t &operator<<=(const hugeint_t &rhs);
	DUCKDB_API hugeint_t &operator&=(const hugeint_t &rhs);
	DUCKDB_API hugeint_t &operator|=(const hugeint_t &rhs);
	DUCKDB_API hugeint_t &operator^=(const hugeint_t &rhs);

	// boolean operators
	DUCKDB_API explicit operator bool() const;
	DUCKDB_API bool operator!() const;

	// cast operators -- doesn't check bounds/overflow/underflow
	DUCKDB_API explicit operator uint8_t() const;
	DUCKDB_API explicit operator uint16_t() const;
	DUCKDB_API explicit operator uint32_t() const;
	DUCKDB_API explicit operator uint64_t() const;
	DUCKDB_API explicit operator int8_t() const;
	DUCKDB_API explicit operator int16_t() const;
	DUCKDB_API explicit operator int32_t() const;
	DUCKDB_API explicit operator int64_t() const;
	DUCKDB_API operator uhugeint_t() const; // NOLINT: Allow implicit conversion from `hugeint_t`
};

} // namespace duckdb


#include <vector>

namespace duckdb {

// Helper class to support custom overloading
// Escaping " and quoting the value with "
class SQLIdentifier {
public:
	explicit SQLIdentifier(const string &raw_string) : raw_string(raw_string) {
	}

public:
	string raw_string;
};

// Helper class to support custom overloading
// Escaping ' and quoting the value with '
class SQLString {
public:
	explicit SQLString(const string &raw_string) : raw_string(raw_string) {
	}

public:
	string raw_string;
};

enum class PhysicalType : uint8_t;
struct LogicalType;

enum class ExceptionFormatValueType : uint8_t {
	FORMAT_VALUE_TYPE_DOUBLE,
	FORMAT_VALUE_TYPE_INTEGER,
	FORMAT_VALUE_TYPE_STRING
};

struct ExceptionFormatValue {
	DUCKDB_API ExceptionFormatValue(double dbl_val);     // NOLINT
	DUCKDB_API ExceptionFormatValue(int64_t int_val);    // NOLINT
	DUCKDB_API ExceptionFormatValue(string str_val);     // NOLINT
	DUCKDB_API ExceptionFormatValue(hugeint_t hg_val);   // NOLINT
	DUCKDB_API ExceptionFormatValue(uhugeint_t uhg_val); // NOLINT

	ExceptionFormatValueType type;

	double dbl_val = 0;
	int64_t int_val = 0;
	string str_val;

public:
	template <class T>
	static ExceptionFormatValue CreateFormatValue(T value) {
		return int64_t(value);
	}
	static string Format(const string &msg, std::vector<ExceptionFormatValue> &values);
};

template <>
DUCKDB_API ExceptionFormatValue ExceptionFormatValue::CreateFormatValue(PhysicalType value);
template <>
DUCKDB_API ExceptionFormatValue ExceptionFormatValue::CreateFormatValue(SQLString value);
template <>
DUCKDB_API ExceptionFormatValue ExceptionFormatValue::CreateFormatValue(SQLIdentifier value);
template <>
DUCKDB_API ExceptionFormatValue ExceptionFormatValue::CreateFormatValue(LogicalType value);
template <>
DUCKDB_API ExceptionFormatValue ExceptionFormatValue::CreateFormatValue(float value);
template <>
DUCKDB_API ExceptionFormatValue ExceptionFormatValue::CreateFormatValue(double value);
template <>
DUCKDB_API ExceptionFormatValue ExceptionFormatValue::CreateFormatValue(string value);
template <>
DUCKDB_API ExceptionFormatValue ExceptionFormatValue::CreateFormatValue(const char *value);
template <>
DUCKDB_API ExceptionFormatValue ExceptionFormatValue::CreateFormatValue(char *value);
template <>
DUCKDB_API ExceptionFormatValue ExceptionFormatValue::CreateFormatValue(hugeint_t value);
template <>
DUCKDB_API ExceptionFormatValue ExceptionFormatValue::CreateFormatValue(uhugeint_t value);

} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/unordered_map.hpp
//
//
//===----------------------------------------------------------------------===//



#include <unordered_map>

namespace duckdb {
using std::unordered_map;
}



#include <vector>
#include <stdexcept>

namespace duckdb {
enum class PhysicalType : uint8_t;
struct LogicalType;
class Expression;
class ParsedExpression;
class QueryErrorContext;
class TableRef;
struct hugeint_t;
class optional_idx; // NOLINT: matching std style

inline void AssertRestrictFunction(const void *left_start, const void *left_end, const void *right_start,
                                   const void *right_end, const char *fname, int linenr) {
	// assert that the two pointers do not overlap
#ifdef DEBUG
	if (!(left_end <= right_start || right_end <= left_start)) {
		printf("ASSERT RESTRICT FAILED: %s:%d\n", fname, linenr);
		D_ASSERT(0);
	}
#endif
}

#define ASSERT_RESTRICT(left_start, left_end, right_start, right_end)                                                  \
	AssertRestrictFunction(left_start, left_end, right_start, right_end, __FILE__, __LINE__)

//===--------------------------------------------------------------------===//
// Exception Types
//===--------------------------------------------------------------------===//

enum class ExceptionType : uint8_t {
	INVALID = 0,          // invalid type
	OUT_OF_RANGE = 1,     // value out of range error
	CONVERSION = 2,       // conversion/casting error
	UNKNOWN_TYPE = 3,     // unknown type
	DECIMAL = 4,          // decimal related
	MISMATCH_TYPE = 5,    // type mismatch
	DIVIDE_BY_ZERO = 6,   // divide by 0
	OBJECT_SIZE = 7,      // object size exceeded
	INVALID_TYPE = 8,     // incompatible for operation
	SERIALIZATION = 9,    // serialization
	TRANSACTION = 10,     // transaction management
	NOT_IMPLEMENTED = 11, // method not implemented
	EXPRESSION = 12,      // expression parsing
	CATALOG = 13,         // catalog related
	PARSER = 14,          // parser related
	PLANNER = 15,         // planner related
	SCHEDULER = 16,       // scheduler related
	EXECUTOR = 17,        // executor related
	CONSTRAINT = 18,      // constraint related
	INDEX = 19,           // index related
	STAT = 20,            // stat related
	CONNECTION = 21,      // connection related
	SYNTAX = 22,          // syntax related
	SETTINGS = 23,        // settings related
	BINDER = 24,          // binder related
	NETWORK = 25,         // network related
	OPTIMIZER = 26,       // optimizer related
	NULL_POINTER = 27,    // nullptr exception
	IO = 28,              // IO exception
	INTERRUPT = 29,       // interrupt
	FATAL = 30,           // Fatal exceptions are non-recoverable, and render the entire DB in an unusable state
	INTERNAL = 31,        // Internal exceptions indicate something went wrong internally (i.e. bug in the code base)
	INVALID_INPUT = 32,   // Input or arguments error
	OUT_OF_MEMORY = 33,   // out of memory
	PERMISSION = 34,      // insufficient permissions
	PARAMETER_NOT_RESOLVED = 35, // parameter types could not be resolved
	PARAMETER_NOT_ALLOWED = 36,  // parameter types not allowed
	DEPENDENCY = 37,             // dependency
	HTTP = 38,
	MISSING_EXTENSION = 39, // Thrown when an extension is used but not loaded
	AUTOLOAD = 40,          // Thrown when an extension is used but not loaded
	SEQUENCE = 41,
	INVALID_CONFIGURATION =
	    42 // An invalid configuration was detected (e.g. a Secret param was missing, or a required setting not found)
};

class Exception : public std::runtime_error {
public:
	DUCKDB_API Exception(ExceptionType exception_type, const string &message);
	DUCKDB_API Exception(ExceptionType exception_type, const string &message,
	                     const unordered_map<string, string> &extra_info);

public:
	DUCKDB_API static string ExceptionTypeToString(ExceptionType type);
	DUCKDB_API static ExceptionType StringToExceptionType(const string &type);

	template <typename... ARGS>
	static string ConstructMessage(const string &msg, ARGS... params) {
		const std::size_t num_args = sizeof...(ARGS);
		if (num_args == 0) {
			return msg;
		}
		std::vector<ExceptionFormatValue> values;
		return ConstructMessageRecursive(msg, values, params...);
	}

	DUCKDB_API static unordered_map<string, string> InitializeExtraInfo(const Expression &expr);
	DUCKDB_API static unordered_map<string, string> InitializeExtraInfo(const ParsedExpression &expr);
	DUCKDB_API static unordered_map<string, string> InitializeExtraInfo(const QueryErrorContext &error_context);
	DUCKDB_API static unordered_map<string, string> InitializeExtraInfo(const TableRef &ref);
	DUCKDB_API static unordered_map<string, string> InitializeExtraInfo(optional_idx error_location);
	DUCKDB_API static unordered_map<string, string> InitializeExtraInfo(const string &subtype,
	                                                                    optional_idx error_location);

	DUCKDB_API static string ToJSON(ExceptionType type, const string &message);
	DUCKDB_API static string ToJSON(ExceptionType type, const string &message,
	                                const unordered_map<string, string> &extra_info);

	DUCKDB_API static bool InvalidatesTransaction(ExceptionType exception_type);
	DUCKDB_API static bool InvalidatesDatabase(ExceptionType exception_type);

	DUCKDB_API static string ConstructMessageRecursive(const string &msg, std::vector<ExceptionFormatValue> &values);

	template <class T, typename... ARGS>
	static string ConstructMessageRecursive(const string &msg, std::vector<ExceptionFormatValue> &values, T param,
	                                        ARGS... params) {
		values.push_back(ExceptionFormatValue::CreateFormatValue<T>(param));
		return ConstructMessageRecursive(msg, values, params...);
	}

	DUCKDB_API static bool UncaughtException();

	DUCKDB_API static string GetStackTrace(int max_depth = 120);
	static string FormatStackTrace(const string &message = "") {
		return (message + "\n" + GetStackTrace());
	}

	DUCKDB_API static void SetQueryLocation(optional_idx error_location, unordered_map<string, string> &extra_info);
};

//===--------------------------------------------------------------------===//
// Exception derived classes
//===--------------------------------------------------------------------===//
class ConnectionException : public Exception {
public:
	DUCKDB_API explicit ConnectionException(const string &msg);

	template <typename... ARGS>
	explicit ConnectionException(const string &msg, ARGS... params)
	    : ConnectionException(ConstructMessage(msg, params...)) {
	}
};

class PermissionException : public Exception {
public:
	DUCKDB_API explicit PermissionException(const string &msg);

	template <typename... ARGS>
	explicit PermissionException(const string &msg, ARGS... params)
	    : PermissionException(ConstructMessage(msg, params...)) {
	}
};

class OutOfRangeException : public Exception {
public:
	DUCKDB_API explicit OutOfRangeException(const string &msg);

	template <typename... ARGS>
	explicit OutOfRangeException(const string &msg, ARGS... params)
	    : OutOfRangeException(ConstructMessage(msg, params...)) {
	}
	DUCKDB_API OutOfRangeException(const int64_t value, const PhysicalType orig_type, const PhysicalType new_type);
	DUCKDB_API OutOfRangeException(const hugeint_t value, const PhysicalType orig_type, const PhysicalType new_type);
	DUCKDB_API OutOfRangeException(const double value, const PhysicalType orig_type, const PhysicalType new_type);
	DUCKDB_API OutOfRangeException(const PhysicalType var_type, const idx_t length);
};

class OutOfMemoryException : public Exception {
public:
	DUCKDB_API explicit OutOfMemoryException(const string &msg);

	template <typename... ARGS>
	explicit OutOfMemoryException(const string &msg, ARGS... params)
	    : OutOfMemoryException(ConstructMessage(msg, params...)) {
	}
};

class SyntaxException : public Exception {
public:
	DUCKDB_API explicit SyntaxException(const string &msg);

	template <typename... ARGS>
	explicit SyntaxException(const string &msg, ARGS... params) : SyntaxException(ConstructMessage(msg, params...)) {
	}
};

class ConstraintException : public Exception {
public:
	DUCKDB_API explicit ConstraintException(const string &msg);

	template <typename... ARGS>
	explicit ConstraintException(const string &msg, ARGS... params)
	    : ConstraintException(ConstructMessage(msg, params...)) {
	}
};

class DependencyException : public Exception {
public:
	DUCKDB_API explicit DependencyException(const string &msg);

	template <typename... ARGS>
	explicit DependencyException(const string &msg, ARGS... params)
	    : DependencyException(ConstructMessage(msg, params...)) {
	}
};

class IOException : public Exception {
public:
	DUCKDB_API explicit IOException(const string &msg);
	DUCKDB_API explicit IOException(const string &msg, const unordered_map<string, string> &extra_info);
	explicit IOException(ExceptionType exception_type, const string &msg) : Exception(exception_type, msg) {
	}

	template <typename... ARGS>
	explicit IOException(const string &msg, ARGS... params) : IOException(ConstructMessage(msg, params...)) {
	}

	template <typename... ARGS>
	explicit IOException(const string &msg, const unordered_map<string, string> &extra_info, ARGS... params)
	    : IOException(ConstructMessage(msg, params...), extra_info) {
	}
};

class MissingExtensionException : public Exception {
public:
	DUCKDB_API explicit MissingExtensionException(const string &msg);

	template <typename... ARGS>
	explicit MissingExtensionException(const string &msg, ARGS... params)
	    : MissingExtensionException(ConstructMessage(msg, params...)) {
	}
};

class NotImplementedException : public Exception {
public:
	DUCKDB_API explicit NotImplementedException(const string &msg);

	template <typename... ARGS>
	explicit NotImplementedException(const string &msg, ARGS... params)
	    : NotImplementedException(ConstructMessage(msg, params...)) {
	}
};

class AutoloadException : public Exception {
public:
	DUCKDB_API explicit AutoloadException(const string &extension_name, const string &message);
};

class SerializationException : public Exception {
public:
	DUCKDB_API explicit SerializationException(const string &msg);

	template <typename... ARGS>
	explicit SerializationException(const string &msg, ARGS... params)
	    : SerializationException(ConstructMessage(msg, params...)) {
	}
};

class SequenceException : public Exception {
public:
	DUCKDB_API explicit SequenceException(const string &msg);

	template <typename... ARGS>
	explicit SequenceException(const string &msg, ARGS... params)
	    : SequenceException(ConstructMessage(msg, params...)) {
	}
};

class InterruptException : public Exception {
public:
	DUCKDB_API InterruptException();
};

class FatalException : public Exception {
public:
	explicit FatalException(const string &msg) : FatalException(ExceptionType::FATAL, msg) {
	}
	template <typename... ARGS>
	explicit FatalException(const string &msg, ARGS... params) : FatalException(ConstructMessage(msg, params...)) {
	}

protected:
	DUCKDB_API explicit FatalException(ExceptionType type, const string &msg);
	template <typename... ARGS>
	explicit FatalException(ExceptionType type, const string &msg, ARGS... params)
	    : FatalException(type, ConstructMessage(msg, params...)) {
	}
};

class InternalException : public Exception {
public:
	DUCKDB_API explicit InternalException(const string &msg);

	template <typename... ARGS>
	explicit InternalException(const string &msg, ARGS... params)
	    : InternalException(ConstructMessage(msg, params...)) {
	}
};

class InvalidInputException : public Exception {
public:
	DUCKDB_API explicit InvalidInputException(const string &msg);
	DUCKDB_API explicit InvalidInputException(const string &msg, const unordered_map<string, string> &extra_info);

	template <typename... ARGS>
	explicit InvalidInputException(const string &msg, ARGS... params)
	    : InvalidInputException(ConstructMessage(msg, params...)) {
	}
	template <typename... ARGS>
	explicit InvalidInputException(const Expression &expr, const string &msg, ARGS... params)
	    : InvalidInputException(ConstructMessage(msg, params...), Exception::InitializeExtraInfo(expr)) {
	}
};

class InvalidConfigurationException : public Exception {
public:
	DUCKDB_API explicit InvalidConfigurationException(const string &msg);
	DUCKDB_API explicit InvalidConfigurationException(const string &msg,
	                                                  const unordered_map<string, string> &extra_info);

	template <typename... ARGS>
	explicit InvalidConfigurationException(const string &msg, ARGS... params)
	    : InvalidConfigurationException(ConstructMessage(msg, params...)) {
	}
	template <typename... ARGS>
	explicit InvalidConfigurationException(const Expression &expr, const string &msg, ARGS... params)
	    : InvalidConfigurationException(ConstructMessage(msg, params...), Exception::InitializeExtraInfo(expr)) {
	}
};

class InvalidTypeException : public Exception {
public:
	DUCKDB_API InvalidTypeException(PhysicalType type, const string &msg);
	DUCKDB_API InvalidTypeException(const LogicalType &type, const string &msg);
	DUCKDB_API explicit InvalidTypeException(const string &msg);
};

class TypeMismatchException : public Exception {
public:
	DUCKDB_API TypeMismatchException(const PhysicalType type_1, const PhysicalType type_2, const string &msg);
	DUCKDB_API TypeMismatchException(const LogicalType &type_1, const LogicalType &type_2, const string &msg);
	DUCKDB_API TypeMismatchException(optional_idx error_location, const LogicalType &type_1, const LogicalType &type_2,
	                                 const string &msg);
	DUCKDB_API explicit TypeMismatchException(const string &msg);
};

class ParameterNotAllowedException : public Exception {
public:
	DUCKDB_API explicit ParameterNotAllowedException(const string &msg);

	template <typename... ARGS>
	explicit ParameterNotAllowedException(const string &msg, ARGS... params)
	    : ParameterNotAllowedException(ConstructMessage(msg, params...)) {
	}
};

//! Special exception that should be thrown in the binder if parameter types could not be resolved
//! This will cause prepared statements to be forcibly rebound with the actual parameter values
//! This exception is fatal if thrown outside of the binder (i.e. it should never be thrown outside of the binder)
class ParameterNotResolvedException : public Exception {
public:
	DUCKDB_API explicit ParameterNotResolvedException();
};

} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/likely.hpp
//
//
//===----------------------------------------------------------------------===//



#if __GNUC__
#define DUCKDB_BUILTIN_EXPECT(cond, expected_value) (__builtin_expect(cond, expected_value))
#else
#define DUCKDB_BUILTIN_EXPECT(cond, expected_value) (cond)
#endif

#define DUCKDB_LIKELY(...)   DUCKDB_BUILTIN_EXPECT((__VA_ARGS__), 1)
#define DUCKDB_UNLIKELY(...) DUCKDB_BUILTIN_EXPECT((__VA_ARGS__), 0)



namespace duckdb {

template <bool IS_ENABLED>
struct MemorySafety {
#ifdef DEBUG
	// In DEBUG mode safety is always on
	static constexpr bool ENABLED = true;
#else
	static constexpr bool ENABLED = IS_ENABLED;
#endif
};

} // namespace duckdb


#include <memory>
#include <type_traits>

namespace duckdb {

template <class DATA_TYPE, class DELETER = std::default_delete<DATA_TYPE>, bool SAFE = true>
class unique_ptr : public std::unique_ptr<DATA_TYPE, DELETER> { // NOLINT: naming
public:
	using original = std::unique_ptr<DATA_TYPE, DELETER>;
	using original::original; // NOLINT
	using pointer = typename original::pointer;

private:
	static inline void AssertNotNull(const bool null) {
#if defined(DUCKDB_DEBUG_NO_SAFETY) || defined(DUCKDB_CLANG_TIDY)
		return;
#else
		if (DUCKDB_UNLIKELY(null)) {
			throw duckdb::InternalException("Attempted to dereference unique_ptr that is NULL!");
		}
#endif
	}

public:
	typename std::add_lvalue_reference<DATA_TYPE>::type operator*() const { // NOLINT: hiding on purpose
		const auto ptr = original::get();
		if (MemorySafety<SAFE>::ENABLED) {
			AssertNotNull(!ptr);
		}
		return *ptr;
	}

	typename original::pointer operator->() const { // NOLINT: hiding on purpose
		const auto ptr = original::get();
		if (MemorySafety<SAFE>::ENABLED) {
			AssertNotNull(!ptr);
		}
		return ptr;
	}

#ifdef DUCKDB_CLANG_TIDY
	// This is necessary to tell clang-tidy that it reinitializes the variable after a move
	[[clang::reinitializes]]
#endif
	inline void
	reset(typename original::pointer ptr = typename original::pointer()) noexcept { // NOLINT: hiding on purpose
		original::reset(ptr);
	}
};

// FIXME: DELETER is defined, but we use std::default_delete???
template <class DATA_TYPE, class DELETER, bool SAFE>
class unique_ptr<DATA_TYPE[], DELETER, SAFE> : public std::unique_ptr<DATA_TYPE[], std::default_delete<DATA_TYPE[]>> {
public:
	using original = std::unique_ptr<DATA_TYPE[], std::default_delete<DATA_TYPE[]>>;
	using original::original;

private:
	static inline void AssertNotNull(const bool null) {
#if defined(DUCKDB_DEBUG_NO_SAFETY) || defined(DUCKDB_CLANG_TIDY)
		return;
#else
		if (DUCKDB_UNLIKELY(null)) {
			throw duckdb::InternalException("Attempted to dereference unique_ptr that is NULL!");
		}
#endif
	}

public:
	typename std::add_lvalue_reference<DATA_TYPE>::type operator[](size_t __i) const { // NOLINT: hiding on purpose
		const auto ptr = original::get();
		if (MemorySafety<SAFE>::ENABLED) {
			AssertNotNull(!ptr);
		}
		return ptr[__i];
	}
};

template <typename T>
using unique_array = unique_ptr<T[], std::default_delete<T>, true>;

template <typename T>
using unsafe_unique_array = unique_ptr<T[], std::default_delete<T>, false>;

template <typename T>
using unsafe_unique_ptr = unique_ptr<T, std::default_delete<T>, false>;

} // namespace duckdb



namespace duckdb {
class Serializer;
class Deserializer;
class BinarySerializer;
class BinaryDeserializer;
class WriteStream;
class ReadStream;

//! inline std directives that we use frequently
#ifndef DUCKDB_DEBUG_MOVE
using std::move;
#endif

// NOTE: there is a copy of this in the Postgres' parser grammar (gram.y)
#define DEFAULT_SCHEMA  "main"
#define INVALID_SCHEMA  ""
#define INVALID_CATALOG ""
#define SYSTEM_CATALOG  "system"
#define TEMP_CATALOG    "temp"
#define IN_MEMORY_PATH  ":memory:"

DUCKDB_API bool IsInvalidSchema(const string &str);
DUCKDB_API bool IsInvalidCatalog(const string &str);

//! Special value used to signify the ROW ID of a table
DUCKDB_API extern const column_t COLUMN_IDENTIFIER_ROW_ID;
DUCKDB_API bool IsRowIdColumnId(column_t column_id);

//! The maximum row identifier used in tables
extern const row_t MAX_ROW_ID;
//! Transaction-local row IDs start at MAX_ROW_ID
extern const row_t MAX_ROW_ID_LOCAL;

extern const transaction_t TRANSACTION_ID_START;
extern const transaction_t MAX_TRANSACTION_ID;
extern const transaction_t MAXIMUM_QUERY_ID;
extern const transaction_t NOT_DELETED_ID;

extern const double PI;

struct DConstants {
	//! The value used to signify an invalid index entry
	static constexpr const idx_t INVALID_INDEX = idx_t(-1);
	//! The total maximum vector size (128GB)
	static constexpr const idx_t MAX_VECTOR_SIZE = 1ULL << 37ULL;
};

struct LogicalIndex {
	explicit LogicalIndex(idx_t index) : index(index) {
	}

	idx_t index;

	inline bool operator==(const LogicalIndex &rhs) const {
		return index == rhs.index;
	};
	inline bool operator!=(const LogicalIndex &rhs) const {
		return index != rhs.index;
	};
	inline bool operator<(const LogicalIndex &rhs) const {
		return index < rhs.index;
	};
	bool IsValid() {
		return index != DConstants::INVALID_INDEX;
	}
};

struct PhysicalIndex {
	explicit PhysicalIndex(idx_t index) : index(index) {
	}

	idx_t index;

	inline bool operator==(const PhysicalIndex &rhs) const {
		return index == rhs.index;
	};
	inline bool operator!=(const PhysicalIndex &rhs) const {
		return index != rhs.index;
	};
	inline bool operator<(const PhysicalIndex &rhs) const {
		return index < rhs.index;
	};
	bool IsValid() {
		return index != DConstants::INVALID_INDEX;
	}
};

DUCKDB_API bool IsPowerOfTwo(uint64_t v);
DUCKDB_API uint64_t NextPowerOfTwo(uint64_t v);
DUCKDB_API uint64_t PreviousPowerOfTwo(uint64_t v);

} // namespace duckdb


namespace duckdb {

enum class ProfilerPrintFormat : uint8_t { QUERY_TREE, JSON, QUERY_TREE_OPTIMIZER, NO_OUTPUT };

} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/serializer/buffered_file_writer.hpp
//
//
//===----------------------------------------------------------------------===//



//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/serializer/write_stream.hpp
//
//
//===----------------------------------------------------------------------===//



//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/catalog/catalog.hpp
//
//
//===----------------------------------------------------------------------===//



//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/catalog/catalog_entry.hpp
//
//
//===----------------------------------------------------------------------===//



//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/common.hpp
//
//
//===----------------------------------------------------------------------===//




//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/helper.hpp
//
//
//===----------------------------------------------------------------------===//




//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/shared_ptr.hpp
//
//
//===----------------------------------------------------------------------===//







#include <memory>
#include <type_traits>

namespace duckdb {

// This implementation is taken from the llvm-project, at this commit hash:
// https://github.com/llvm/llvm-project/blob/08bb121835be432ac52372f92845950628ce9a4a/libcxx/include/__memory/shared_ptr.h#353
// originally named '__compatible_with'

#if _LIBCPP_STD_VER >= 17
template <class U, class T>
struct __bounded_convertible_to_unbounded : std::false_type {};

template <class _Up, std::size_t _Np, class T>
struct __bounded_convertible_to_unbounded<_Up[_Np], T> : std::is_same<std::remove_cv<T>, _Up[]> {};

template <class U, class T>
struct compatible_with_t : std::_Or<std::is_convertible<U *, T *>, __bounded_convertible_to_unbounded<U, T>> {};
#else
template <class U, class T>
struct compatible_with_t : std::is_convertible<U *, T *> {}; // NOLINT: invalid case style
#endif // _LIBCPP_STD_VER >= 17

} // namespace duckdb

namespace duckdb {

template <typename T, bool SAFE = true>
class weak_ptr;

template <class T>
class enable_shared_from_this;

template <typename T, bool SAFE = true>
class shared_ptr { // NOLINT: invalid case style
public:
	using original = std::shared_ptr<T>;
	using element_type = typename original::element_type;
	using weak_type = weak_ptr<T, SAFE>;

private:
	static inline void AssertNotNull(const bool null) {
#if defined(DUCKDB_DEBUG_NO_SAFETY) || defined(DUCKDB_CLANG_TIDY)
		return;
#else
		if (DUCKDB_UNLIKELY(null)) {
			throw duckdb::InternalException("Attempted to dereference shared_ptr that is NULL!");
		}
#endif
	}

private:
	template <class U, bool SAFE_P>
	friend class weak_ptr;

	template <class U, bool SAFE_P>
	friend class shared_ptr;

	template <typename U, typename S>
	friend shared_ptr<S> shared_ptr_cast(shared_ptr<U> src); // NOLINT: invalid case style

private:
	original internal;

public:
	// Constructors
	shared_ptr() : internal() {
	}
	shared_ptr(std::nullptr_t) : internal(nullptr) { // NOLINT: not marked as explicit
	}

	// From raw pointer of type U convertible to T
	template <class U, typename std::enable_if<compatible_with_t<U, T>::value, int>::type = 0>
	explicit shared_ptr(U *ptr) : internal(ptr) {
		__enable_weak_this(internal.get(), internal.get());
	}
	// From raw pointer of type T with custom DELETER
	template <typename DELETER>
	shared_ptr(T *ptr, DELETER deleter) : internal(ptr, deleter) {
		__enable_weak_this(internal.get(), internal.get());
	}
	// Aliasing constructor: shares ownership information with ref but contains ptr instead
	// When the created shared_ptr goes out of scope, it will call the DELETER of ref, will not delete ptr
	template <class U>
	shared_ptr(const shared_ptr<U> &ref, T *ptr) noexcept : internal(ref.internal, ptr) {
	}
#if _LIBCPP_STD_VER >= 20
	template <class U>
	shared_ptr(shared_ptr<U> &&ref, T *ptr) noexcept : internal(std::move(ref.internal), ptr) {
	}
#endif

	// Copy constructor, share ownership with ref
	template <class U, typename std::enable_if<compatible_with_t<U, T>::value, int>::type = 0>
	shared_ptr(const shared_ptr<U> &ref) noexcept : internal(ref.internal) { // NOLINT: not marked as explicit
	}
	shared_ptr(const shared_ptr &other) : internal(other.internal) { // NOLINT: not marked as explicit
	}
	// Move constructor, share ownership with ref
	template <class U, typename std::enable_if<compatible_with_t<U, T>::value, int>::type = 0>
#ifdef DUCKDB_CLANG_TIDY
	[[clang::reinitializes]]
#endif
	shared_ptr(shared_ptr<U> &&ref) noexcept // NOLINT: not marked as explicit
	    : internal(std::move(ref.internal)) {
	}
#ifdef DUCKDB_CLANG_TIDY
	[[clang::reinitializes]]
#endif
	shared_ptr(shared_ptr<T> &&other) // NOLINT: not marked as explicit
	    : internal(std::move(other.internal)) {
	}

	// Construct from std::shared_ptr
	explicit shared_ptr(std::shared_ptr<T> other) : internal(other) {
		// FIXME: should we __enable_weak_this here?
		// *our* enable_shared_from_this hasn't initialized yet, so I think so?
		__enable_weak_this(internal.get(), internal.get());
	}

	// Construct from weak_ptr
	template <class U>
	explicit shared_ptr(weak_ptr<U> other) : internal(other.internal) {
	}

	// Construct from unique_ptr, takes over ownership of the unique_ptr
	template <class U, class DELETER, bool SAFE_P,
	          typename std::enable_if<compatible_with_t<U, T>::value &&
	                                      std::is_convertible<typename unique_ptr<U, DELETER>::pointer, T *>::value,
	                                  int>::type = 0>
#ifdef DUCKDB_CLANG_TIDY
	[[clang::reinitializes]]
#endif
	shared_ptr(unique_ptr<U, DELETER, SAFE_P> &&other) // NOLINT: not marked as explicit
	    : internal(std::move(other)) {
		__enable_weak_this(internal.get(), internal.get());
	}

	// Destructor
	~shared_ptr() = default;

	// Assign from shared_ptr copy
	shared_ptr<T> &operator=(const shared_ptr &other) noexcept {
		if (this == &other) {
			return *this;
		}
		// Create a new shared_ptr using the copy constructor, then swap out the ownership to *this
		shared_ptr(other).swap(*this);
		return *this;
	}
	template <class U, typename std::enable_if<compatible_with_t<U, T>::value, int>::type = 0>
	shared_ptr<T> &operator=(const shared_ptr<U> &other) {
		shared_ptr(other).swap(*this);
		return *this;
	}

	// Assign from moved shared_ptr
	shared_ptr<T> &operator=(shared_ptr &&other) noexcept {
		// Create a new shared_ptr using the move constructor, then swap out the ownership to *this
		shared_ptr(std::move(other)).swap(*this);
		return *this;
	}
	template <class U, typename std::enable_if<compatible_with_t<U, T>::value, int>::type = 0>
	shared_ptr<T> &operator=(shared_ptr<U> &&other) {
		shared_ptr(std::move(other)).swap(*this);
		return *this;
	}

	// Assign from moved unique_ptr
	template <class U, class DELETER, bool SAFE_P,
	          typename std::enable_if<compatible_with_t<U, T>::value &&
	                                      std::is_convertible<typename unique_ptr<U, DELETER>::pointer, T *>::value,
	                                  int>::type = 0>
	shared_ptr<T> &operator=(unique_ptr<U, DELETER, SAFE_P> &&ref) {
		shared_ptr(std::move(ref)).swap(*this);
		return *this;
	}

#ifdef DUCKDB_CLANG_TIDY
	[[clang::reinitializes]]
#endif
	void
	reset() { // NOLINT: invalid case style
		internal.reset();
	}
	template <typename U>
#ifdef DUCKDB_CLANG_TIDY
	[[clang::reinitializes]]
#endif
	void
	reset(U *ptr) { // NOLINT: invalid case style
		internal.reset(ptr);
	}
	template <typename U, typename DELETER>
#ifdef DUCKDB_CLANG_TIDY
	[[clang::reinitializes]]
#endif
	void
	reset(U *ptr, DELETER deleter) { // NOLINT: invalid case style
		internal.reset(ptr, deleter);
	}

	void swap(shared_ptr &r) noexcept { // NOLINT: invalid case style
		internal.swap(r.internal);
	}

	T *get() const { // NOLINT: invalid case style
		return internal.get();
	}

	long use_count() const { // NOLINT: invalid case style
		return internal.use_count();
	}

	explicit operator bool() const noexcept {
		return internal.operator bool();
	}

	typename std::add_lvalue_reference<T>::type operator*() const {
		if (MemorySafety<SAFE>::ENABLED) {
			const auto ptr = internal.get();
			AssertNotNull(!ptr);
			return *ptr;
		} else {
			return *internal;
		}
	}

	T *operator->() const {
		if (MemorySafety<SAFE>::ENABLED) {
			const auto ptr = internal.get();
			AssertNotNull(!ptr);
			return ptr;
		} else {
			return internal.operator->();
		}
	}

	// Relational operators
	template <typename U>
	bool operator==(const shared_ptr<U> &other) const noexcept {
		return internal == other.internal;
	}
	template <typename U>
	bool operator!=(const shared_ptr<U> &other) const noexcept {
		return internal != other.internal;
	}

	bool operator==(std::nullptr_t) const noexcept {
		return internal == nullptr;
	}
	bool operator!=(std::nullptr_t) const noexcept {
		return internal != nullptr;
	}

	template <typename U>
	bool operator<(const shared_ptr<U> &other) const noexcept {
		return internal < other.internal;
	}
	template <typename U>
	bool operator<=(const shared_ptr<U> &other) const noexcept {
		return internal <= other.internal;
	}
	template <typename U>
	bool operator>(const shared_ptr<U> &other) const noexcept {
		return internal > other.internal;
	}
	template <typename U>
	bool operator>=(const shared_ptr<U> &other) const noexcept {
		return internal >= other.internal;
	}

private:
	// This overload is used when the class inherits from 'enable_shared_from_this<U>'
	template <class U, class V,
	          typename std::enable_if<std::is_convertible<V *, const enable_shared_from_this<U> *>::value,
	                                  int>::type = 0>
	void __enable_weak_this(const enable_shared_from_this<U> *object, // NOLINT: invalid case style
	                        V *ptr) noexcept {
		typedef typename std::remove_cv<U>::type non_const_u_t;
		if (object && object->__weak_this_.expired()) {
			// __weak_this__ is the mutable variable returned by 'shared_from_this'
			// it is initialized here
			auto non_const = const_cast<non_const_u_t *>(static_cast<const U *>(ptr)); // NOLINT: const cast
			object->__weak_this_ = shared_ptr<non_const_u_t>(*this, non_const);
		}
	}

	void __enable_weak_this(...) noexcept { // NOLINT: invalid case style
	}
};

} // namespace duckdb

namespace duckdb {

template <typename T, bool SAFE>
class weak_ptr { // NOLINT: invalid case style
public:
	using original = std::weak_ptr<T>;
	using element_type = typename original::element_type;

private:
	template <class U, bool SAFE_P>
	friend class shared_ptr;

private:
	original internal;

public:
	// Constructors
	weak_ptr() : internal() {
	}

	// NOLINTBEGIN
	template <class U, typename std::enable_if<compatible_with_t<U, T>::value, int>::type = 0>
	weak_ptr(shared_ptr<U, SAFE> const &ptr) noexcept : internal(ptr.internal) {
	}
	weak_ptr(weak_ptr const &other) noexcept : internal(other.internal) {
	}
	template <class U, typename std::enable_if<compatible_with_t<U, T>::value, int>::type = 0>
	weak_ptr(weak_ptr<U> const &ptr) noexcept : internal(ptr.internal) {
	}
#ifdef DUCKDB_CLANG_TIDY
	[[clang::reinitializes]]
#endif
	weak_ptr(weak_ptr &&ptr) noexcept
	    : internal(std::move(ptr.internal)) {
	}
	template <class U, typename std::enable_if<compatible_with_t<U, T>::value, int>::type = 0>
#ifdef DUCKDB_CLANG_TIDY
	[[clang::reinitializes]]
#endif
	weak_ptr(weak_ptr<U> &&ptr) noexcept
	    : internal(std::move(ptr.internal)) {
	}
	// NOLINTEND
	// Destructor
	~weak_ptr() = default;

	// Assignment operators
	weak_ptr &operator=(const weak_ptr &other) {
		if (this == &other) {
			return *this;
		}
		internal = other.internal;
		return *this;
	}

	template <class U, typename std::enable_if<compatible_with_t<U, T>::value, int>::type = 0>
	weak_ptr &operator=(const shared_ptr<U, SAFE> &ptr) {
		internal = ptr.internal;
		return *this;
	}

	// Modifiers
#ifdef DUCKDB_CLANG_TIDY
	// This is necessary to tell clang-tidy that it reinitializes the variable after a move
	[[clang::reinitializes]]
#endif
	void
	reset() { // NOLINT: invalid case style
		internal.reset();
	}

	// Observers
	long use_count() const { // NOLINT: invalid case style
		return internal.use_count();
	}

	bool expired() const { // NOLINT: invalid case style
		return internal.expired();
	}

	shared_ptr<T, SAFE> lock() const { // NOLINT: invalid case style
		return shared_ptr<T, SAFE>(internal.lock());
	}

	// Relational operators
	template <typename U>
	bool operator==(const weak_ptr<U> &other) const noexcept {
		return internal == other.internal;
	}

	template <typename U>
	bool operator!=(const weak_ptr<U> &other) const noexcept {
		return internal != other.internal;
	}

	template <typename U>
	bool operator<(const weak_ptr<U> &other) const noexcept {
		return internal < other.internal;
	}

	template <typename U>
	bool operator<=(const weak_ptr<U> &other) const noexcept {
		return internal <= other.internal;
	}

	template <typename U>
	bool operator>(const weak_ptr<U> &other) const noexcept {
		return internal > other.internal;
	}

	template <typename U>
	bool operator>=(const weak_ptr<U> &other) const noexcept {
		return internal >= other.internal;
	}
};

} // namespace duckdb

namespace duckdb {

template <class T>
class enable_shared_from_this { // NOLINT: invalid case style
public:
	template <class U, bool SAFE>
	friend class shared_ptr;

private:
	mutable weak_ptr<T> __weak_this_; // NOLINT: __weak_this_ is reserved

protected:
	constexpr enable_shared_from_this() noexcept {
	}
	enable_shared_from_this(enable_shared_from_this const &) noexcept { // NOLINT: not marked as explicit
	}
	enable_shared_from_this &operator=(enable_shared_from_this const &) noexcept {
		return *this;
	}
	~enable_shared_from_this() {
	}

public:
	shared_ptr<T> shared_from_this() { // NOLINT: invalid case style
		return shared_ptr<T>(__weak_this_);
	}
	shared_ptr<T const> shared_from_this() const { // NOLINT: invalid case style
		return shared_ptr<const T>(__weak_this_);
	}

#if _LIBCPP_STD_VER >= 17
	weak_ptr<T> weak_from_this() noexcept { // NOLINT: invalid case style
		return __weak_this_;
	}

	weak_ptr<const T> weak_from_this() const noexcept { // NOLINT: invalid case style
		return __weak_this_;
	}
#endif // _LIBCPP_STD_VER >= 17
};

} // namespace duckdb


namespace duckdb {

template <typename T>
using unsafe_shared_ptr = shared_ptr<T, false>;

template <typename T>
using unsafe_weak_ptr = weak_ptr<T, false>;

} // namespace duckdb

#include <string.h>
#include <type_traits>

#ifdef _MSC_VER
#define suint64_t int64_t
#endif

#if defined(_WIN32) || defined(_WIN64)
#define DUCKDB_WINDOWS
#elif defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__))
#define DUCKDB_POSIX
#endif

namespace duckdb {

// explicit fallthrough for switch_statementss
#ifndef __has_cpp_attribute // For backwards compatibility
#define __has_cpp_attribute(x) 0
#endif
#if __has_cpp_attribute(clang::fallthrough)
#define DUCKDB_EXPLICIT_FALLTHROUGH [[clang::fallthrough]]
#elif __has_cpp_attribute(gnu::fallthrough)
#define DUCKDB_EXPLICIT_FALLTHROUGH [[gnu::fallthrough]]
#else
#define DUCKDB_EXPLICIT_FALLTHROUGH
#endif

template <class... T>
struct AlwaysFalse {
	static constexpr bool VALUE = false;
};

template<typename T>
using reference = std::reference_wrapper<T>;

template<class DATA_TYPE, bool SAFE = true>
struct TemplatedUniqueIf
{
    typedef unique_ptr<DATA_TYPE, std::default_delete<DATA_TYPE>, SAFE> templated_unique_single_t;
};

template<class DATA_TYPE, size_t N>
struct TemplatedUniqueIf<DATA_TYPE[N]>
{
    typedef void TemplatedUniqueArrayKnownBound; // NOLINT: mimic std style
};

template<class DATA_TYPE, class... ARGS>
inline 
typename TemplatedUniqueIf<DATA_TYPE, true>::templated_unique_single_t
make_uniq(ARGS&&... args) // NOLINT: mimic std style
{
    return unique_ptr<DATA_TYPE, std::default_delete<DATA_TYPE>, true>(new DATA_TYPE(std::forward<ARGS>(args)...));
}

template<class DATA_TYPE, class... ARGS>
inline 
shared_ptr<DATA_TYPE>
make_shared_ptr(ARGS&&... args) // NOLINT: mimic std style
{
	return shared_ptr<DATA_TYPE>(std::make_shared<DATA_TYPE>(std::forward<ARGS>(args)...));
}

template<class DATA_TYPE, class... ARGS>
inline 
typename TemplatedUniqueIf<DATA_TYPE, false>::templated_unique_single_t
make_unsafe_uniq(ARGS&&... args) // NOLINT: mimic std style
{
    return unique_ptr<DATA_TYPE, std::default_delete<DATA_TYPE>, false>(new DATA_TYPE(std::forward<ARGS>(args)...));
}

template<class DATA_TYPE>
inline unique_ptr<DATA_TYPE[], std::default_delete<DATA_TYPE>, true>
make_uniq_array(size_t n) // NOLINT: mimic std style
{
	return unique_ptr<DATA_TYPE[], std::default_delete<DATA_TYPE>, true>(new DATA_TYPE[n]());
}

template<class DATA_TYPE>
inline unique_ptr<DATA_TYPE[], std::default_delete<DATA_TYPE>, true>
make_uniq_array_uninitialized(size_t n) // NOLINT: mimic std style
{
	return unique_ptr<DATA_TYPE[], std::default_delete<DATA_TYPE>, true>(new DATA_TYPE[n]);
}

template<class DATA_TYPE>
inline unique_ptr<DATA_TYPE[], std::default_delete<DATA_TYPE>, false>
make_unsafe_uniq_array(size_t n) // NOLINT: mimic std style
{
	return unique_ptr<DATA_TYPE[], std::default_delete<DATA_TYPE>, false>(new DATA_TYPE[n]());
}

template<class DATA_TYPE>
inline unique_ptr<DATA_TYPE[], std::default_delete<DATA_TYPE>, false>
make_unsafe_uniq_array_uninitialized(size_t n) // NOLINT: mimic std style
{
	return unique_ptr<DATA_TYPE[], std::default_delete<DATA_TYPE>, false>(new DATA_TYPE[n]);
}

template<class DATA_TYPE, class... ARGS>
    typename TemplatedUniqueIf<DATA_TYPE>::TemplatedUniqueArrayKnownBound
    make_uniq(ARGS&&...) = delete; // NOLINT: mimic std style


template <typename S, typename T, typename... ARGS>
unique_ptr<S> make_uniq_base(ARGS &&... args) { // NOLINT: mimic std style
	return unique_ptr<S>(new T(std::forward<ARGS>(args)...));
}

#ifdef DUCKDB_ENABLE_DEPRECATED_API
template <typename S, typename T, typename... Args>
unique_ptr<S> make_unique_base(Args &&... args) {
	return unique_ptr<S>(new T(std::forward<Args>(args)...));
}
#endif // DUCKDB_ENABLE_DEPRECATED_API

template <typename SRC, typename TGT>
unique_ptr<TGT> unique_ptr_cast(unique_ptr<SRC> src) { // NOLINT: mimic std style
	return unique_ptr<TGT>(static_cast<TGT *>(src.release()));
}

template <typename SRC, typename TGT>
shared_ptr<TGT> shared_ptr_cast(shared_ptr<SRC> src) { // NOLINT: mimic std style
	return shared_ptr<TGT>(std::static_pointer_cast<TGT, SRC>(src.internal));
}

struct SharedConstructor {
	template <class T, typename... ARGS>
	static shared_ptr<T> Create(ARGS &&...args) {
		return make_shared_ptr<T>(std::forward<ARGS>(args)...);
	}
};

struct UniqueConstructor {
	template <class T, typename... ARGS>
	static unique_ptr<T> Create(ARGS &&...args) {
		return make_uniq<T>(std::forward<ARGS>(args)...);
	}
};

#ifdef DUCKDB_DEBUG_MOVE
template<class T>
typename std::remove_reference<T>::type&& move(T&& t) noexcept {
	// the nonsensical sizeof check ensures this is never instantiated
	static_assert(sizeof(T) == 0, "Use std::move instead of unqualified move or duckdb::move");
}
#endif

template <class T, class... ARGS>
static duckdb::unique_ptr<T> make_unique(ARGS&&... __args) { // NOLINT: mimic std style
#ifndef DUCKDB_ENABLE_DEPRECATED_API
	static_assert(sizeof(T) == 0, "Use make_uniq instead of make_unique!");
#endif // DUCKDB_ENABLE_DEPRECATED_API
	return unique_ptr<T>(new T(std::forward<ARGS>(__args)...));
}

template <class T, class... ARGS>
static duckdb::shared_ptr<T> make_shared(ARGS&&... __args) { // NOLINT: mimic std style
#ifndef DUCKDB_ENABLE_DEPRECATED_API
	static_assert(sizeof(T) == 0, "Use make_shared_ptr instead of make_shared!");
#endif // DUCKDB_ENABLE_DEPRECATED_API
	return shared_ptr<T>(new T(std::forward<ARGS>(__args)...));
}

template <typename T>
constexpr T MaxValue(T a, T b) {
	return a > b ? a : b;
}

template <typename T>
constexpr T MinValue(T a, T b) {
	return a < b ? a : b;
}

template <typename T>
T AbsValue(T a) {
	return a < 0 ? -a : a;
}

//! Align value (ceiling)
template<class T, T val=8>
static inline T AlignValue(T n) {
	return ((n + (val - 1)) / val) * val;
}

template<class T, T val=8>
constexpr inline T AlignValueFloor(T n) {
	return (n / val) * val;
}

template<class T, T val=8>
static inline bool ValueIsAligned(T n) {
	return (n % val) == 0;
}

template <typename T>
T SignValue(T a) {
	return a < 0 ? -1 : 1;
}

template <typename T>
const T Load(const_data_ptr_t ptr) {
	T ret;
	memcpy(&ret, ptr, sizeof(ret)); // NOLINT
	return ret;
}

template <typename T>
void Store(const T &val, data_ptr_t ptr) {
	memcpy(ptr, (void *)&val, sizeof(val)); // NOLINT
}

//! This assigns a shared pointer, but ONLY assigns if "target" is not equal to "source"
//! If this is often the case, this manner of assignment is significantly faster (~20X faster)
//! Since it avoids the need of an atomic incref/decref at the cost of a single pointer comparison
//! Benchmark: https://gist.github.com/Mytherin/4db3faa8e233c4a9b874b21f62bb4b96
//! If the shared pointers are not the same, the penalty is very low (on the order of 1%~ slower)
//! This method should always be preferred if there is a (reasonable) chance that the pointers are the same
template<class T>
void AssignSharedPointer(shared_ptr<T> &target, const shared_ptr<T> &source) {
	if (target.get() != source.get()) {
		target = source;
	}
}

template<typename T>
using const_reference = std::reference_wrapper<const T>;

//! Returns whether or not two reference wrappers refer to the same object
template<class T>
bool RefersToSameObject(const reference<T> &a, const reference<T> &b) {
	return &a.get() == &b.get();
}

template<class T>
bool RefersToSameObject(const T &a, const T &b) {
	return &a == &b;
}

template<class T, class SRC>
void DynamicCastCheck(const SRC *source) {
#ifndef __APPLE__
	// Actual check is on the fact that dynamic_cast and reinterpret_cast are equivalent
	D_ASSERT(reinterpret_cast<const T *>(source) == dynamic_cast<const T *>(source));
#endif
}

} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/vector.hpp
//
//
//===----------------------------------------------------------------------===//








#include <vector>

namespace duckdb {

template <class DATA_TYPE, bool SAFE = true>
class vector : public std::vector<DATA_TYPE, std::allocator<DATA_TYPE>> { // NOLINT: matching name of std
public:
	using original = std::vector<DATA_TYPE, std::allocator<DATA_TYPE>>;
	using original::original;
	using size_type = typename original::size_type;
	using const_reference = typename original::const_reference;
	using reference = typename original::reference;

private:
	static inline void AssertIndexInBounds(idx_t index, idx_t size) {
#if defined(DUCKDB_DEBUG_NO_SAFETY) || defined(DUCKDB_CLANG_TIDY)
		return;
#else
		if (DUCKDB_UNLIKELY(index >= size)) {
			throw InternalException("Attempted to access index %ld within vector of size %ld", index, size);
		}
#endif
	}

public:
#ifdef DUCKDB_CLANG_TIDY
	// This is necessary to tell clang-tidy that it reinitializes the variable after a move
	[[clang::reinitializes]]
#endif
	inline void
	clear() noexcept { // NOLINT: hiding on purpose
		original::clear();
	}

	// Because we create the other constructor, the implicitly created constructor
	// gets deleted, so we have to be explicit
	vector() = default;
	vector(original &&other) : original(std::move(other)) { // NOLINT: allow implicit conversion
	}
	template <bool INTERNAL_SAFE>
	vector(vector<DATA_TYPE, INTERNAL_SAFE> &&other) : original(std::move(other)) { // NOLINT: allow implicit conversion
	}

	template <bool INTERNAL_SAFE = false>
	inline typename original::reference get(typename original::size_type __n) { // NOLINT: hiding on purpose
		if (MemorySafety<INTERNAL_SAFE>::ENABLED) {
			AssertIndexInBounds(__n, original::size());
		}
		return original::operator[](__n);
	}

	template <bool INTERNAL_SAFE = false>
	inline typename original::const_reference get(typename original::size_type __n) const { // NOLINT: hiding on purpose
		if (MemorySafety<INTERNAL_SAFE>::ENABLED) {
			AssertIndexInBounds(__n, original::size());
		}
		return original::operator[](__n);
	}

	typename original::reference operator[](typename original::size_type __n) { // NOLINT: hiding on purpose
		return get<SAFE>(__n);
	}
	typename original::const_reference operator[](typename original::size_type __n) const { // NOLINT: hiding on purpose
		return get<SAFE>(__n);
	}

	typename original::reference front() { // NOLINT: hiding on purpose
		return get<SAFE>(0);
	}

	typename original::const_reference front() const { // NOLINT: hiding on purpose
		return get<SAFE>(0);
	}

	typename original::reference back() { // NOLINT: hiding on purpose
		if (MemorySafety<SAFE>::ENABLED && original::empty()) {
			throw InternalException("'back' called on an empty vector!");
		}
		return get<SAFE>(original::size() - 1);
	}

	typename original::const_reference back() const { // NOLINT: hiding on purpose
		if (MemorySafety<SAFE>::ENABLED && original::empty()) {
			throw InternalException("'back' called on an empty vector!");
		}
		return get<SAFE>(original::size() - 1);
	}

	void unsafe_erase_at(idx_t idx) { // NOLINT: not using camelcase on purpose here
		original::erase(original::begin() + static_cast<typename original::iterator::difference_type>(idx));
	}

	void erase_at(idx_t idx) { // NOLINT: not using camelcase on purpose here
		if (MemorySafety<SAFE>::ENABLED && idx > original::size()) {
			throw InternalException("Can't remove offset %d from vector of size %d", idx, original::size());
		}
		unsafe_erase_at(idx);
	}
};

template <typename T>
using unsafe_vector = vector<T, false>;

} // namespace duckdb


//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/enums/catalog_type.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

//===--------------------------------------------------------------------===//
// Catalog Types
//===--------------------------------------------------------------------===//
enum class CatalogType : uint8_t {
	INVALID = 0,
	TABLE_ENTRY = 1,
	SCHEMA_ENTRY = 2,
	VIEW_ENTRY = 3,
	INDEX_ENTRY = 4,
	PREPARED_STATEMENT = 5,
	SEQUENCE_ENTRY = 6,
	COLLATION_ENTRY = 7,
	TYPE_ENTRY = 8,
	DATABASE_ENTRY = 9,

	// functions
	TABLE_FUNCTION_ENTRY = 25,
	SCALAR_FUNCTION_ENTRY = 26,
	AGGREGATE_FUNCTION_ENTRY = 27,
	PRAGMA_FUNCTION_ENTRY = 28,
	COPY_FUNCTION_ENTRY = 29,
	MACRO_ENTRY = 30,
	TABLE_MACRO_ENTRY = 31,

	// version info
	DELETED_ENTRY = 51,
	RENAMED_ENTRY = 52,

	// secrets
	SECRET_ENTRY = 71,
	SECRET_TYPE_ENTRY = 72,
	SECRET_FUNCTION_ENTRY = 73,

	// dependency info
	DEPENDENCY_ENTRY = 100

};

DUCKDB_API string CatalogTypeToString(CatalogType type);
CatalogType CatalogTypeFromString(const string &type);

} // namespace duckdb


//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/atomic.hpp
//
//
//===----------------------------------------------------------------------===//



#include <atomic>

namespace duckdb {
using std::atomic;
}

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/optional_ptr.hpp
//
//
//===----------------------------------------------------------------------===//







namespace duckdb {

template <class T, bool SAFE = true>
class optional_ptr { // NOLINT: mimic std casing
public:
	optional_ptr() noexcept : ptr(nullptr) {
	}
	optional_ptr(T *ptr_p) : ptr(ptr_p) { // NOLINT: allow implicit creation from pointer
	}
	optional_ptr(T &ref) : ptr(&ref) { // NOLINT: allow implicit creation from reference
	}
	optional_ptr(const unique_ptr<T> &ptr_p) : ptr(ptr_p.get()) { // NOLINT: allow implicit creation from unique pointer
	}
	optional_ptr(const shared_ptr<T> &ptr_p) : ptr(ptr_p.get()) { // NOLINT: allow implicit creation from shared pointer
	}

	void CheckValid() const {
		if (MemorySafety<SAFE>::ENABLED) {
			if (!ptr) {
				throw InternalException("Attempting to dereference an optional pointer that is not set");
			}
		}
	}

	operator bool() const { // NOLINT: allow implicit conversion to bool
		return ptr;
	}
	T &operator*() {
		CheckValid();
		return *ptr;
	}
	const T &operator*() const {
		CheckValid();
		return *ptr;
	}
	T *operator->() {
		CheckValid();
		return ptr;
	}
	const T *operator->() const {
		CheckValid();
		return ptr;
	}
	T *get() { // NOLINT: mimic std casing
		// CheckValid();
		return ptr;
	}
	const T *get() const { // NOLINT: mimic std casing
		// CheckValid();
		return ptr;
	}
	// this looks dirty - but this is the default behavior of raw pointers
	T *get_mutable() const { // NOLINT: mimic std casing
		// CheckValid();
		return ptr;
	}

	bool operator==(const optional_ptr<T> &rhs) const {
		return ptr == rhs.ptr;
	}

	bool operator!=(const optional_ptr<T> &rhs) const {
		return ptr != rhs.ptr;
	}

private:
	T *ptr;
};

template <typename T>
using unsafe_optional_ptr = optional_ptr<T, false>;

} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/exception/catalog_exception.hpp
//
//
//===----------------------------------------------------------------------===//





//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/parser/query_error_context.hpp
//
//
//===----------------------------------------------------------------------===//






//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/optional_idx.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

class optional_idx {
	static constexpr const idx_t INVALID_INDEX = idx_t(-1);

public:
	optional_idx() : index(INVALID_INDEX) {
	}
	optional_idx(idx_t index) : index(index) { // NOLINT: allow implicit conversion from idx_t
		if (index == INVALID_INDEX) {
			throw InternalException("optional_idx cannot be initialized with an invalid index");
		}
	}

	static optional_idx Invalid() {
		return optional_idx();
	}

	bool IsValid() const {
		return index != INVALID_INDEX;
	}

	idx_t GetIndex() const {
		if (index == INVALID_INDEX) {
			throw InternalException("Attempting to get the index of an optional_idx that is not set");
		}
		return index;
	}

	inline bool operator==(const optional_idx &rhs) const {
		return index == rhs.index;
	}

private:
	idx_t index;
};

} // namespace duckdb


namespace duckdb {

class QueryErrorContext {
public:
	explicit QueryErrorContext(optional_idx query_location_p = optional_idx()) : query_location(query_location_p) {
	}

	//! The location in which the error should be thrown
	optional_idx query_location;

public:
	static string Format(const string &query, const string &error_message, optional_idx error_loc,
	                     bool add_line_indicator = true);
};

} // namespace duckdb



namespace duckdb {

class CatalogException : public Exception {
public:
	DUCKDB_API explicit CatalogException(const string &msg);
	DUCKDB_API explicit CatalogException(const string &msg, const unordered_map<string, string> &extra_info);

	template <typename... ARGS>
	explicit CatalogException(const string &msg, ARGS... params) : CatalogException(ConstructMessage(msg, params...)) {
	}
	template <typename... ARGS>
	explicit CatalogException(QueryErrorContext error_context, const string &msg, ARGS... params)
	    : CatalogException(ConstructMessage(msg, params...), Exception::InitializeExtraInfo(error_context)) {
	}

	static CatalogException MissingEntry(CatalogType type, const string &name, const string &suggestion,
	                                     QueryErrorContext context = QueryErrorContext());
	static CatalogException MissingEntry(const string &type, const string &name, const vector<string> &suggestions,
	                                     QueryErrorContext context = QueryErrorContext());
	static CatalogException EntryAlreadyExists(CatalogType type, const string &name,
	                                           QueryErrorContext context = QueryErrorContext());
};

} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/types/value.hpp
//
//
//===----------------------------------------------------------------------===//





//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/types.hpp
//
//
//===----------------------------------------------------------------------===//









#include <limits>

namespace duckdb {

class Serializer;
class Deserializer;
class Value;
class TypeCatalogEntry;
class Vector;
class ClientContext;

struct string_t; // NOLINT: mimic std casing

template <class T>
using child_list_t = vector<std::pair<std::string, T>>;
//! FIXME: this should be a single_thread_ptr
template <class T>
using buffer_ptr = shared_ptr<T>;

template <class T, typename... ARGS>
buffer_ptr<T> make_buffer(ARGS &&...args) { // NOLINT: mimic std casing
	return make_shared_ptr<T>(std::forward<ARGS>(args)...);
}

struct list_entry_t { // NOLINT: mimic std casing
	list_entry_t() = default;
	list_entry_t(uint64_t offset, uint64_t length) : offset(offset), length(length) {
	}
	inline constexpr bool operator!=(const list_entry_t &other) const {
		return !(*this == other);
	}
	inline constexpr bool operator==(const list_entry_t &other) const {
		return offset == other.offset && length == other.length;
	}

	uint64_t offset;
	uint64_t length;
};

using union_tag_t = uint8_t;

//===--------------------------------------------------------------------===//
// Internal Types
//===--------------------------------------------------------------------===//

// taken from arrow's type.h
enum class PhysicalType : uint8_t {
	///// A NULL type having no physical storage
	// NA = 0,

	/// Boolean as 8 bit "bool" value
	BOOL = 1,

	/// Unsigned 8-bit little-endian integer
	UINT8 = 2,

	/// Signed 8-bit little-endian integer
	INT8 = 3,

	/// Unsigned 16-bit little-endian integer
	UINT16 = 4,

	/// Signed 16-bit little-endian integer
	INT16 = 5,

	/// Unsigned 32-bit little-endian integer
	UINT32 = 6,

	/// Signed 32-bit little-endian integer
	INT32 = 7,

	/// Unsigned 64-bit little-endian integer
	UINT64 = 8,

	/// Signed 64-bit little-endian integer
	INT64 = 9,

	///// 2-byte floating point value
	// HALF_FLOAT = 10,

	/// 4-byte floating point value
	FLOAT = 11,

	/// 8-byte floating point value
	DOUBLE = 12,

	///// UTF8 variable-length string as List<Char>
	// STRING = 13,

	///// Variable-length bytes (no guarantee of UTF8-ness)
	// BINARY = 14,

	///// Fixed-size binary. Each value occupies the same number of bytes
	// FIXED_SIZE_BINARY = 15,

	///// int32_t days since the UNIX epoch
	// DATE32 = 16,

	///// int64_t milliseconds since the UNIX epoch
	// DATE64 = 17,

	///// Exact timestamp encoded with int64 since UNIX epoch
	///// Default unit millisecond
	// TIMESTAMP = 18,

	///// Time as signed 32-bit integer, representing either seconds or
	///// milliseconds since midnight
	// TIME32 = 19,

	///// Time as signed 64-bit integer, representing either microseconds or
	///// nanoseconds since midnight
	// TIME64 = 20,

	/// YEAR_MONTH or DAY_TIME interval in SQL style
	INTERVAL = 21,

	/// Precision- and scale-based decimal type. Storage type depends on the
	/// parameters.
	// DECIMAL = 22,

	/// A list of some logical data type
	LIST = 23,

	/// Struct of logical types
	STRUCT = 24,

	///// Unions of logical types
	// UNION = 25,

	///// Dictionary-encoded type, also called "categorical" or "factor"
	///// in other programming languages. Holds the dictionary value
	///// type but not the dictionary itself, which is part of the
	///// ArrayData struct
	// DICTIONARY = 26,

	///// Custom data type, implemented by user
	// EXTENSION = 28,

	///// Array with fixed length of some logical type (a fixed-size list)
	ARRAY = 29,

	///// Measure of elapsed time in either seconds, milliseconds, microseconds
	///// or nanoseconds.
	// DURATION = 30,

	///// Like STRING, but with 64-bit offsets
	// LARGE_STRING = 31,

	///// Like BINARY, but with 64-bit offsets
	// LARGE_BINARY = 32,

	///// Like LIST, but with 64-bit offsets
	// LARGE_LIST = 33,

	/// DuckDB Extensions
	VARCHAR = 200, // our own string representation, different from STRING and LARGE_STRING above
	UINT128 = 203, // 128-bit unsigned integers
	INT128 = 204, // 128-bit integers
	UNKNOWN = 205, // Unknown physical type of user defined types
	/// Boolean as 1 bit, LSB bit-packed ordering
	BIT = 206,

	INVALID = 255
};

//===--------------------------------------------------------------------===//
// SQL Types
//===--------------------------------------------------------------------===//
enum class LogicalTypeId : uint8_t {
	INVALID = 0,
	SQLNULL = 1, /* NULL type, used for constant NULL */
	UNKNOWN = 2, /* unknown type, used for parameter expressions */
	ANY = 3,     /* ANY type, used for functions that accept any type as parameter */
	USER = 4,    /* A User Defined Type (e.g., ENUMs before the binder) */
	BOOLEAN = 10,
	TINYINT = 11,
	SMALLINT = 12,
	INTEGER = 13,
	BIGINT = 14,
	DATE = 15,
	TIME = 16,
	TIMESTAMP_SEC = 17,
	TIMESTAMP_MS = 18,
	TIMESTAMP = 19, //! us
	TIMESTAMP_NS = 20,
	DECIMAL = 21,
	FLOAT = 22,
	DOUBLE = 23,
	CHAR = 24,
	VARCHAR = 25,
	BLOB = 26,
	INTERVAL = 27,
	UTINYINT = 28,
	USMALLINT = 29,
	UINTEGER = 30,
	UBIGINT = 31,
	TIMESTAMP_TZ = 32,
	TIME_TZ = 34,
	BIT = 36,
	STRING_LITERAL = 37, /* string literals, used for constant strings - only exists while binding */
	INTEGER_LITERAL = 38,/* integer literals, used for constant integers - only exists while binding */
	VARINT = 39,
	UHUGEINT = 49,
	HUGEINT = 50,
	POINTER = 51,
	VALIDITY = 53,
	UUID = 54,

	STRUCT = 100,
	LIST = 101,
	MAP = 102,
	TABLE = 103,
	ENUM = 104,
	AGGREGATE_STATE = 105,
	LAMBDA = 106,
	UNION = 107,
	ARRAY = 108
};

struct ExtraTypeInfo;

struct aggregate_state_t; // NOLINT: mimic std casing

struct LogicalType {
	DUCKDB_API LogicalType();
	DUCKDB_API LogicalType(LogicalTypeId id); // NOLINT: Allow implicit conversion from `LogicalTypeId`
	DUCKDB_API LogicalType(LogicalTypeId id, shared_ptr<ExtraTypeInfo> type_info);
	DUCKDB_API LogicalType(const LogicalType &other);
	DUCKDB_API LogicalType(LogicalType &&other) noexcept;

	DUCKDB_API ~LogicalType();

	inline LogicalTypeId id() const { // NOLINT: mimic std casing
		return id_;
	}
	inline PhysicalType InternalType() const {
		return physical_type_;
	}
	inline const ExtraTypeInfo *AuxInfo() const {
		return type_info_.get();
	}
	inline bool IsNested() const {
		auto internal = InternalType();
		if (internal == PhysicalType::STRUCT) {
			return true;
		}
		if (internal == PhysicalType::LIST) {
			return true;
		}
		if (internal == PhysicalType::ARRAY) {
			return true;
		}
		return false;
	}

	inline shared_ptr<ExtraTypeInfo> GetAuxInfoShrPtr() const {
		return type_info_;
	}

	//! DeepCopy() will make a unique copy of any ExtraTypeInfo as well
	LogicalType DeepCopy() const;

	inline void CopyAuxInfo(const LogicalType &other) {
		type_info_ = other.type_info_;
	}
	bool EqualTypeInfo(const LogicalType &rhs) const;

	// copy assignment
	inline LogicalType &operator=(const LogicalType &other) {
		if (this == &other) {
			return *this;
		}
		id_ = other.id_;
		physical_type_ = other.physical_type_;
		type_info_ = other.type_info_;
		return *this;
	}
	// move assignment
	inline LogicalType &operator=(LogicalType &&other) noexcept {
		id_ = other.id_;
		physical_type_ = other.physical_type_;
		std::swap(type_info_, other.type_info_);
		return *this;
	}

	DUCKDB_API bool operator==(const LogicalType &rhs) const;
	inline bool operator!=(const LogicalType &rhs) const {
		return !(*this == rhs);
	}

	DUCKDB_API void Serialize(Serializer &serializer) const;
	DUCKDB_API static LogicalType Deserialize(Deserializer &deserializer);

	static bool TypeIsTimestamp(LogicalTypeId id) {
		return (id == LogicalTypeId::TIMESTAMP || id == LogicalTypeId::TIMESTAMP_MS ||
		        id == LogicalTypeId::TIMESTAMP_NS || id == LogicalTypeId::TIMESTAMP_SEC ||
		        id == LogicalTypeId::TIMESTAMP_TZ);
	}
	static bool TypeIsTimestamp(const LogicalType &type) {
		return TypeIsTimestamp(type.id());
	}
	DUCKDB_API string ToString() const;
	DUCKDB_API bool IsIntegral() const;
	DUCKDB_API bool IsNumeric() const;
	DUCKDB_API bool IsTemporal() const;
	DUCKDB_API hash_t Hash() const;
	DUCKDB_API void SetAlias(string alias);
	DUCKDB_API bool HasAlias() const;
	DUCKDB_API string GetAlias() const;
	DUCKDB_API void SetModifiers(vector<Value> modifiers);
	DUCKDB_API bool HasModifiers() const;
	DUCKDB_API vector<Value> GetModifiersCopy() const;
	DUCKDB_API optional_ptr<vector<Value>> GetModifiers();
	DUCKDB_API optional_ptr<const vector<Value>> GetModifiers() const;

	//! Returns the maximum logical type when combining the two types - or throws an exception if combining is not possible
	DUCKDB_API static LogicalType MaxLogicalType(ClientContext &context, const LogicalType &left, const LogicalType &right);
	DUCKDB_API static bool TryGetMaxLogicalType(ClientContext &context, const LogicalType &left, const LogicalType &right, LogicalType &result);
	//! Forcibly returns a maximum logical type - similar to MaxLogicalType but never throws. As a fallback either left or right are returned.
	DUCKDB_API static LogicalType ForceMaxLogicalType(const LogicalType &left, const LogicalType &right);
	//! Normalize a type - removing literals
	DUCKDB_API static LogicalType NormalizeType(const LogicalType &type);


		//! Gets the decimal properties of a numeric type. Fails if the type is not numeric.
	DUCKDB_API bool GetDecimalProperties(uint8_t &width, uint8_t &scale) const;

	DUCKDB_API void Verify() const;

	DUCKDB_API bool IsValid() const;


private:
	LogicalTypeId id_; // NOLINT: allow this naming for legacy reasons
	PhysicalType physical_type_; // NOLINT: allow this naming for legacy reasons
	shared_ptr<ExtraTypeInfo> type_info_; // NOLINT: allow this naming for legacy reasons

private:
	PhysicalType GetInternalType();

public:
	static constexpr const LogicalTypeId SQLNULL = LogicalTypeId::SQLNULL;
	static constexpr const LogicalTypeId UNKNOWN = LogicalTypeId::UNKNOWN;
	static constexpr const LogicalTypeId BOOLEAN = LogicalTypeId::BOOLEAN;
	static constexpr const LogicalTypeId TINYINT = LogicalTypeId::TINYINT;
	static constexpr const LogicalTypeId UTINYINT = LogicalTypeId::UTINYINT;
	static constexpr const LogicalTypeId SMALLINT = LogicalTypeId::SMALLINT;
	static constexpr const LogicalTypeId USMALLINT = LogicalTypeId::USMALLINT;
	static constexpr const LogicalTypeId INTEGER = LogicalTypeId::INTEGER;
	static constexpr const LogicalTypeId UINTEGER = LogicalTypeId::UINTEGER;
	static constexpr const LogicalTypeId BIGINT = LogicalTypeId::BIGINT;
	static constexpr const LogicalTypeId UBIGINT = LogicalTypeId::UBIGINT;
	static constexpr const LogicalTypeId FLOAT = LogicalTypeId::FLOAT;
	static constexpr const LogicalTypeId DOUBLE = LogicalTypeId::DOUBLE;
	static constexpr const LogicalTypeId DATE = LogicalTypeId::DATE;
	static constexpr const LogicalTypeId TIMESTAMP = LogicalTypeId::TIMESTAMP;
	static constexpr const LogicalTypeId TIMESTAMP_S = LogicalTypeId::TIMESTAMP_SEC;
	static constexpr const LogicalTypeId TIMESTAMP_MS = LogicalTypeId::TIMESTAMP_MS;
	static constexpr const LogicalTypeId TIMESTAMP_NS = LogicalTypeId::TIMESTAMP_NS;
	static constexpr const LogicalTypeId TIME = LogicalTypeId::TIME;
	static constexpr const LogicalTypeId TIMESTAMP_TZ = LogicalTypeId::TIMESTAMP_TZ;
	static constexpr const LogicalTypeId TIME_TZ = LogicalTypeId::TIME_TZ;
	static constexpr const LogicalTypeId VARCHAR = LogicalTypeId::VARCHAR;
	static constexpr const LogicalTypeId ANY = LogicalTypeId::ANY;
	static constexpr const LogicalTypeId BLOB = LogicalTypeId::BLOB;
	static constexpr const LogicalTypeId BIT = LogicalTypeId::BIT;
	static constexpr const LogicalTypeId VARINT = LogicalTypeId::VARINT;

	static constexpr const LogicalTypeId INTERVAL = LogicalTypeId::INTERVAL;
	static constexpr const LogicalTypeId HUGEINT = LogicalTypeId::HUGEINT;
	static constexpr const LogicalTypeId UHUGEINT = LogicalTypeId::UHUGEINT;
	static constexpr const LogicalTypeId UUID = LogicalTypeId::UUID;
	static constexpr const LogicalTypeId HASH = LogicalTypeId::UBIGINT;
	static constexpr const LogicalTypeId POINTER = LogicalTypeId::POINTER;
	static constexpr const LogicalTypeId TABLE = LogicalTypeId::TABLE;
	static constexpr const LogicalTypeId LAMBDA = LogicalTypeId::LAMBDA;
	static constexpr const LogicalTypeId INVALID = LogicalTypeId::INVALID;
	static constexpr const LogicalTypeId ROW_TYPE = LogicalTypeId::BIGINT;

	// explicitly allowing these functions to be capitalized to be in-line with the remaining functions
	DUCKDB_API static LogicalType DECIMAL(uint8_t width, uint8_t scale);                 // NOLINT
	DUCKDB_API static LogicalType VARCHAR_COLLATION(string collation);           // NOLINT
	DUCKDB_API static LogicalType LIST(const LogicalType &child);                // NOLINT
	DUCKDB_API static LogicalType STRUCT(child_list_t<LogicalType> children);    // NOLINT
	DUCKDB_API static LogicalType AGGREGATE_STATE(aggregate_state_t state_type); // NOLINT
	DUCKDB_API static LogicalType MAP(const LogicalType &child);                 // NOLINT
	DUCKDB_API static LogicalType MAP(LogicalType key, LogicalType value);       // NOLINT
	DUCKDB_API static LogicalType UNION(child_list_t<LogicalType> members);      // NOLINT
	DUCKDB_API static LogicalType ARRAY(const LogicalType &child, optional_idx index);   // NOLINT
	DUCKDB_API static LogicalType ENUM(Vector &ordered_data, idx_t size); // NOLINT
	// ANY but with special rules (default is LogicalType::ANY, 5)
	DUCKDB_API static LogicalType ANY_PARAMS(LogicalType target, idx_t cast_score = 5); // NOLINT
	//! Integer literal of the specified value
	DUCKDB_API static LogicalType INTEGER_LITERAL(const Value &constant);               // NOLINT
	// DEPRECATED - provided for backwards compatibility
	DUCKDB_API static LogicalType ENUM(const string &enum_name, Vector &ordered_data, idx_t size); // NOLINT
	DUCKDB_API static LogicalType USER(const string &user_type_name);                              // NOLINT
	DUCKDB_API static LogicalType USER(const string &user_type_name, const vector<Value> &user_type_mods); // NOLINT
	DUCKDB_API static LogicalType USER(string catalog, string schema, string name, vector<Value> user_type_mods); // NOLINT
	//! A list of all NUMERIC types (integral and floating point types)
	DUCKDB_API static const vector<LogicalType> Numeric();
	//! A list of all INTEGRAL types
	DUCKDB_API static const vector<LogicalType> Integral();
	//! A list of all REAL types
	DUCKDB_API static const vector<LogicalType> Real();
	//! A list of ALL SQL types
	DUCKDB_API static const vector<LogicalType> AllTypes();

public:
	//! The JSON type lives in the JSON extension, but we need to define this here for special handling
	static constexpr auto JSON_TYPE_NAME = "JSON";
	DUCKDB_API static LogicalType JSON(); // NOLINT
	DUCKDB_API bool IsJSONType() const;
};

struct DecimalType {
	DUCKDB_API static uint8_t GetWidth(const LogicalType &type);
	DUCKDB_API static uint8_t GetScale(const LogicalType &type);
	DUCKDB_API static uint8_t MaxWidth();
};

struct StringType {
	DUCKDB_API static string GetCollation(const LogicalType &type);
};

struct ListType {
	DUCKDB_API static const LogicalType &GetChildType(const LogicalType &type);
};

struct UserType {
	DUCKDB_API static const string &GetCatalog(const LogicalType &type);
	DUCKDB_API static const string &GetSchema(const LogicalType &type);
	DUCKDB_API static const string &GetTypeName(const LogicalType &type);
	DUCKDB_API static const vector<Value> &GetTypeModifiers(const LogicalType &type);
	DUCKDB_API static vector<Value> &GetTypeModifiers(LogicalType &type);
};

struct EnumType {
	DUCKDB_API static int64_t GetPos(const LogicalType &type, const string_t &key);
	DUCKDB_API static const Vector &GetValuesInsertOrder(const LogicalType &type);
	DUCKDB_API static idx_t GetSize(const LogicalType &type);
	DUCKDB_API static const string GetValue(const Value &val);
	DUCKDB_API static PhysicalType GetPhysicalType(const LogicalType &type);
	DUCKDB_API static string_t GetString(const LogicalType &type, idx_t pos);
};

struct StructType {
	DUCKDB_API static const child_list_t<LogicalType> &GetChildTypes(const LogicalType &type);
	DUCKDB_API static const LogicalType &GetChildType(const LogicalType &type, idx_t index);
	DUCKDB_API static const string &GetChildName(const LogicalType &type, idx_t index);
	DUCKDB_API static idx_t GetChildIndexUnsafe(const LogicalType &type, const string &name);
	DUCKDB_API static idx_t GetChildCount(const LogicalType &type);
	DUCKDB_API static bool IsUnnamed(const LogicalType &type);
};

struct MapType {
	DUCKDB_API static const LogicalType &KeyType(const LogicalType &type);
	DUCKDB_API static const LogicalType &ValueType(const LogicalType &type);
};

struct UnionType {
	DUCKDB_API static const idx_t MAX_UNION_MEMBERS = 256;
	DUCKDB_API static idx_t GetMemberCount(const LogicalType &type);
	DUCKDB_API static const LogicalType &GetMemberType(const LogicalType &type, idx_t index);
	DUCKDB_API static const string &GetMemberName(const LogicalType &type, idx_t index);
	DUCKDB_API static const child_list_t<LogicalType> CopyMemberTypes(const LogicalType &type);
};

struct ArrayType {
	DUCKDB_API static const LogicalType &GetChildType(const LogicalType &type);
	DUCKDB_API static idx_t GetSize(const LogicalType &type);
	DUCKDB_API static bool IsAnySize(const LogicalType &type);
	DUCKDB_API static constexpr idx_t MAX_ARRAY_SIZE = 100000; // 100k for now
	//! Recursively replace all ARRAY types to LIST types within the given type
	DUCKDB_API static LogicalType ConvertToList(const LogicalType &type);
};

struct AggregateStateType {
	DUCKDB_API static const string GetTypeName(const LogicalType &type);
	DUCKDB_API static const aggregate_state_t &GetStateType(const LogicalType &type);
};

struct AnyType {
	DUCKDB_API static LogicalType GetTargetType(const LogicalType &type);
	DUCKDB_API static idx_t GetCastScore(const LogicalType &type);
};

struct IntegerLiteral {
	//! Returns the type that this integer literal "prefers"
	DUCKDB_API static LogicalType GetType(const LogicalType &type);
	//! Whether or not the integer literal fits into the target numeric type
	DUCKDB_API static bool FitsInType(const LogicalType &type, const LogicalType &target);
};

// **DEPRECATED**: Use EnumUtil directly instead.
DUCKDB_API string LogicalTypeIdToString(LogicalTypeId type);

DUCKDB_API LogicalTypeId TransformStringToLogicalTypeId(const string &str);

DUCKDB_API LogicalType TransformStringToLogicalType(const string &str);

DUCKDB_API LogicalType TransformStringToLogicalType(const string &str, ClientContext &context);

//! The PhysicalType used by the row identifiers column
extern const PhysicalType ROW_TYPE;

DUCKDB_API string TypeIdToString(PhysicalType type);
DUCKDB_API idx_t GetTypeIdSize(PhysicalType type);
DUCKDB_API bool TypeIsConstantSize(PhysicalType type);
DUCKDB_API bool TypeIsIntegral(PhysicalType type);
DUCKDB_API bool TypeIsNumeric(PhysicalType type);
DUCKDB_API bool TypeIsInteger(PhysicalType type);

bool ApproxEqual(float l, float r);
bool ApproxEqual(double l, double r);

struct aggregate_state_t {
	aggregate_state_t() {
	}
	// NOLINTNEXTLINE: work around bug in clang-tidy
	aggregate_state_t(string function_name_p, LogicalType return_type_p, vector<LogicalType> bound_argument_types_p)
	    : function_name(std::move(function_name_p)), return_type(std::move(return_type_p)),
	      bound_argument_types(std::move(bound_argument_types_p)) {
	}

	string function_name;
	LogicalType return_type;
	vector<LogicalType> bound_argument_types;
};



} // namespace duckdb





#include <stdint.h>

namespace duckdb {

// Forward declaration to allow conversion between hugeint and uhugeint
struct hugeint_t; // NOLINT

struct uhugeint_t { // NOLINT
public:
	uint64_t lower;
	uint64_t upper;

public:
	uhugeint_t() = default;
	DUCKDB_API uhugeint_t(uint64_t value); // NOLINT: Allow implicit conversion from `uint64_t`
	constexpr uhugeint_t(uint64_t upper, uint64_t lower) : lower(lower), upper(upper) {
	}
	constexpr uhugeint_t(const uhugeint_t &rhs) = default;
	constexpr uhugeint_t(uhugeint_t &&rhs) = default;
	uhugeint_t &operator=(const uhugeint_t &rhs) = default;
	uhugeint_t &operator=(uhugeint_t &&rhs) = default;

	DUCKDB_API string ToString() const;

	// comparison operators
	DUCKDB_API bool operator==(const uhugeint_t &rhs) const;
	DUCKDB_API bool operator!=(const uhugeint_t &rhs) const;
	DUCKDB_API bool operator<=(const uhugeint_t &rhs) const;
	DUCKDB_API bool operator<(const uhugeint_t &rhs) const;
	DUCKDB_API bool operator>(const uhugeint_t &rhs) const;
	DUCKDB_API bool operator>=(const uhugeint_t &rhs) const;

	// arithmetic operators
	DUCKDB_API uhugeint_t operator+(const uhugeint_t &rhs) const;
	DUCKDB_API uhugeint_t operator-(const uhugeint_t &rhs) const;
	DUCKDB_API uhugeint_t operator*(const uhugeint_t &rhs) const;
	DUCKDB_API uhugeint_t operator/(const uhugeint_t &rhs) const;
	DUCKDB_API uhugeint_t operator%(const uhugeint_t &rhs) const;
	DUCKDB_API uhugeint_t operator-() const;

	// bitwise operators
	DUCKDB_API uhugeint_t operator>>(const uhugeint_t &rhs) const;
	DUCKDB_API uhugeint_t operator<<(const uhugeint_t &rhs) const;
	DUCKDB_API uhugeint_t operator&(const uhugeint_t &rhs) const;
	DUCKDB_API uhugeint_t operator|(const uhugeint_t &rhs) const;
	DUCKDB_API uhugeint_t operator^(const uhugeint_t &rhs) const;
	DUCKDB_API uhugeint_t operator~() const;

	// in-place operators
	DUCKDB_API uhugeint_t &operator+=(const uhugeint_t &rhs);
	DUCKDB_API uhugeint_t &operator-=(const uhugeint_t &rhs);
	DUCKDB_API uhugeint_t &operator*=(const uhugeint_t &rhs);
	DUCKDB_API uhugeint_t &operator/=(const uhugeint_t &rhs);
	DUCKDB_API uhugeint_t &operator%=(const uhugeint_t &rhs);
	DUCKDB_API uhugeint_t &operator>>=(const uhugeint_t &rhs);
	DUCKDB_API uhugeint_t &operator<<=(const uhugeint_t &rhs);
	DUCKDB_API uhugeint_t &operator&=(const uhugeint_t &rhs);
	DUCKDB_API uhugeint_t &operator|=(const uhugeint_t &rhs);
	DUCKDB_API uhugeint_t &operator^=(const uhugeint_t &rhs);

	// boolean operators
	DUCKDB_API explicit operator bool() const;
	DUCKDB_API bool operator!() const;

	// cast operators -- doesn't check bounds/overflow/underflow
	DUCKDB_API explicit operator uint8_t() const;
	DUCKDB_API explicit operator uint16_t() const;
	DUCKDB_API explicit operator uint32_t() const;
	DUCKDB_API explicit operator uint64_t() const;
	DUCKDB_API explicit operator int8_t() const;
	DUCKDB_API explicit operator int16_t() const;
	DUCKDB_API explicit operator int32_t() const;
	DUCKDB_API explicit operator int64_t() const;
	DUCKDB_API operator hugeint_t() const; // NOLINT: Allow implicit conversion from `uhugeint_t`
};

} // namespace duckdb


//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/types/timestamp.hpp
//
//
//===----------------------------------------------------------------------===//




//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/limits.hpp
//
//
//===----------------------------------------------------------------------===//







#include <type_traits>

// Undef annoying windows macro
#undef max

#include <limits>

namespace duckdb {

template <class T>
struct NumericLimits {
	static constexpr T Minimum() {
		return std::numeric_limits<T>::lowest();
	}
	static constexpr T Maximum() {
		return std::numeric_limits<T>::max();
	}
	static constexpr bool IsSigned() {
		return std::is_signed<T>::value;
	}
	static constexpr bool IsIntegral() {
		return std::is_integral<T>::value || std::is_enum<T>::value;
	}
	static constexpr idx_t Digits();
};

template <>
struct NumericLimits<hugeint_t> {
	static constexpr hugeint_t Minimum() {
		return {std::numeric_limits<int64_t>::lowest(), 0};
	};
	static constexpr hugeint_t Maximum() {
		return {std::numeric_limits<int64_t>::max(), std::numeric_limits<uint64_t>::max()};
	};
	static constexpr bool IsSigned() {
		return true;
	}
	static constexpr bool IsIntegral() {
		return true;
	}
	static constexpr idx_t Digits() {
		return 39;
	}
};

template <>
struct NumericLimits<uhugeint_t> {
	static constexpr uhugeint_t Minimum() {
		return {0, 0};
	};
	static constexpr uhugeint_t Maximum() {
		return {std::numeric_limits<uint64_t>::max(), std::numeric_limits<uint64_t>::max()};
	};
	static constexpr bool IsSigned() {
		return false;
	}
	static constexpr bool IsIntegral() {
		return true;
	}
	static constexpr idx_t Digits() {
		return 39;
	}
};

template <>
constexpr idx_t NumericLimits<int8_t>::Digits() {
	return 3;
}

template <>
constexpr idx_t NumericLimits<int16_t>::Digits() {
	return 5;
}

template <>
constexpr idx_t NumericLimits<int32_t>::Digits() {
	return 10;
}

template <>
constexpr idx_t NumericLimits<int64_t>::Digits() {
	return 19;
}

template <>
constexpr idx_t NumericLimits<uint8_t>::Digits() {
	return 3;
}

template <>
constexpr idx_t NumericLimits<uint16_t>::Digits() {
	return 5;
}

template <>
constexpr idx_t NumericLimits<uint32_t>::Digits() {
	return 10;
}

template <>
constexpr idx_t NumericLimits<uint64_t>::Digits() {
	return 20;
}

template <>
constexpr idx_t NumericLimits<float>::Digits() {
	return 127;
}

template <>
constexpr idx_t NumericLimits<double>::Digits() {
	return 250;
}

} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/string_util.hpp
//
//
//===----------------------------------------------------------------------===//





//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/numeric_utils.hpp
//
//
//===----------------------------------------------------------------------===//



#include <type_traits>




namespace duckdb {

template <class T>
struct MakeSigned {
	using type = typename std::make_signed<T>::type;
};

template <>
struct MakeSigned<hugeint_t> {
	using type = hugeint_t;
};

template <>
struct MakeSigned<uhugeint_t> {
	using type = hugeint_t;
};

template <class T>
struct MakeUnsigned {
	using type = typename std::make_unsigned<T>::type;
};

template <>
struct MakeUnsigned<hugeint_t> {
	using type = uhugeint_t;
};

template <>
struct MakeUnsigned<uhugeint_t> {
	using type = uhugeint_t;
};

template <class TO, class FROM>
static void ThrowNumericCastError(FROM in, TO minval, TO maxval) {
	throw InternalException("Information loss on integer cast: value %d outside of target range [%d, %d]", in, minval,
	                        maxval);
}

template <class TO, class FROM, bool are_same_type>
struct NumericCastImpl;

template <class TO, class FROM>
struct NumericCastImpl<TO, FROM, true> {
	static TO Convert(FROM val) {
		return static_cast<TO>(val);
	}
};

template <class TO, class FROM>
struct NumericCastImpl<TO, FROM, false> {
	static TO Convert(FROM val) {
		// some dance around signed-unsigned integer comparison below
		auto minval = NumericLimits<TO>::Minimum();
		auto maxval = NumericLimits<TO>::Maximum();
		auto unsigned_in = static_cast<typename MakeUnsigned<FROM>::type>(val);
		auto unsigned_min = static_cast<typename MakeUnsigned<TO>::type>(minval);
		auto unsigned_max = static_cast<typename MakeUnsigned<TO>::type>(maxval);
		auto signed_in = static_cast<typename MakeSigned<FROM>::type>(val);
		auto signed_min = static_cast<typename MakeSigned<TO>::type>(minval);
		auto signed_max = static_cast<typename MakeSigned<TO>::type>(maxval);

		if (!NumericLimits<FROM>::IsSigned() && !NumericLimits<TO>::IsSigned() &&
		    (unsigned_in < unsigned_min || unsigned_in > unsigned_max)) {
			ThrowNumericCastError(val, minval, maxval);
		}

		if (NumericLimits<FROM>::IsSigned() && NumericLimits<TO>::IsSigned() &&
		    (signed_in < signed_min || signed_in > signed_max)) {
			ThrowNumericCastError(val, minval, maxval);
		}

		if (NumericLimits<FROM>::IsSigned() != NumericLimits<TO>::IsSigned() &&
		    (signed_in < signed_min || unsigned_in > unsigned_max)) {
			ThrowNumericCastError(val, minval, maxval);
		}

		return static_cast<TO>(val);
	}
};

// NumericCast
// When: between same types, or when both types are integral
// Checks: perform checked casts on range
template <class TO, class FROM,
          class = typename std::enable_if<(NumericLimits<TO>::IsIntegral() && NumericLimits<FROM>::IsIntegral()) ||
                                          std::is_same<TO, FROM>::value>::type>
TO NumericCast(FROM val) {
	return NumericCastImpl<TO, FROM, std::is_same<TO, FROM>::value>::Convert(val);
}

// UnsafeNumericCast
// When: between same types, or when both types are integral
// Checks: perform checked casts on range (in DEBUG) otherwise no checks
template <class TO, class FROM,
          class = typename std::enable_if<(NumericLimits<TO>::IsIntegral() && NumericLimits<FROM>::IsIntegral()) ||
                                          std::is_same<TO, FROM>::value>::type>
TO UnsafeNumericCast(FROM in) {
#if defined(DEBUG) || defined(UNSAFE_NUMERIC_CAST)
	return NumericCast<TO, FROM>(in);
#endif
	return static_cast<TO>(in);
}

// LossyNumericCast
// When: between double/float to other convertible types
// Checks: no checks performed (at the moment, to be improved adding range checks)
template <class TO>
TO LossyNumericCast(double val) {
	return static_cast<TO>(val);
}

template <class TO>
TO LossyNumericCast(float val) {
	return static_cast<TO>(val);
}

// ExactNumericCast
// When: between double/float to other convertible types
// Checks: perform checks that casts are invertible (in DEBUG) otherwise no checks

template <class TO>
TO ExactNumericCast(double val) {
	auto res = LossyNumericCast<TO>(val);
#if defined(DEBUG) || defined(UNSAFE_NUMERIC_CAST)
	if (val != double(res)) {
		throw InternalException("Information loss on double cast: value %lf outside of target range [%lf, %lf]", val,
		                        double(res), double(res));
	}
#endif
	return res;
}

template <class TO>
TO ExactNumericCast(float val) {
	auto res = LossyNumericCast<TO>(val);
#if defined(DEBUG) || defined(UNSAFE_NUMERIC_CAST)
	if (val != float(res)) {
		throw InternalException("Information loss on float cast: value %f outside of target range [%f, %f]", val,
		                        float(res), float(res));
	}
#endif
	return res;
}

} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/pair.hpp
//
//
//===----------------------------------------------------------------------===//



#include <utility>

namespace duckdb {
using std::make_pair;
using std::pair;
} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/set.hpp
//
//
//===----------------------------------------------------------------------===//



#include <set>

namespace duckdb {
using std::multiset;
using std::set;
} // namespace duckdb



#include <cstring>

namespace duckdb {

#ifndef DUCKDB_QUOTE_DEFINE
// Preprocessor trick to allow text to be converted to C-string / string
// Expecte use is:
//	#ifdef SOME_DEFINE
//	string str = DUCKDB_QUOTE_DEFINE(SOME_DEFINE)
//	...do something with str
//	#endif SOME_DEFINE
#define DUCKDB_QUOTE_DEFINE_IMPL(x) #x
#define DUCKDB_QUOTE_DEFINE(x)      DUCKDB_QUOTE_DEFINE_IMPL(x)
#endif

/**
 * String Utility Functions
 * Note that these are not the most efficient implementations (i.e., they copy
 * memory) and therefore they should only be used for debug messages and other
 * such things.
 */
class StringUtil {
public:
	static string GenerateRandomName(idx_t length = 16);

	static uint8_t GetHexValue(char c) {
		if (c >= '0' && c <= '9') {
			return UnsafeNumericCast<uint8_t>(c - '0');
		}
		if (c >= 'a' && c <= 'f') {
			return UnsafeNumericCast<uint8_t>(c - 'a' + 10);
		}
		if (c >= 'A' && c <= 'F') {
			return UnsafeNumericCast<uint8_t>(c - 'A' + 10);
		}
		throw InvalidInputException("Invalid input for hex digit: %s", string(1, c));
	}
	static uint8_t GetBinaryValue(char c) {
		if (c >= '0' && c <= '1') {
			return UnsafeNumericCast<uint8_t>(c - '0');
		}
		throw InvalidInputException("Invalid input for binary digit: %s", string(1, c));
	}

	static bool CharacterIsSpace(char c) {
		return c == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\f' || c == '\r';
	}
	static bool CharacterIsNewline(char c) {
		return c == '\n' || c == '\r';
	}
	static bool CharacterIsDigit(char c) {
		return c >= '0' && c <= '9';
	}
	static bool CharacterIsHex(char c) {
		return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F');
	}
	static char CharacterToUpper(char c) {
		if (c >= 'a' && c <= 'z') {
			return UnsafeNumericCast<char>(c - ('a' - 'A'));
		}
		return c;
	}
	static char CharacterToLower(char c) {
		if (c >= 'A' && c <= 'Z') {
			return UnsafeNumericCast<char>(c + ('a' - 'A'));
		}
		return c;
	}
	static bool CharacterIsAlpha(char c) {
		return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
	}
	static bool CharacterIsOperator(char c) {
		if (c == '_') {
			return false;
		}
		if (c >= '!' && c <= '/') {
			return true;
		}
		if (c >= ':' && c <= '@') {
			return true;
		}
		if (c >= '[' && c <= '`') {
			return true;
		}
		if (c >= '{' && c <= '~') {
			return true;
		}
		return false;
	}

	template <class TO>
	static vector<TO> ConvertStrings(const vector<string> &strings) {
		vector<TO> result;
		for (auto &string : strings) {
			result.emplace_back(string);
		}
		return result;
	}

	static vector<SQLIdentifier> ConvertToSQLIdentifiers(const vector<string> &strings) {
		return ConvertStrings<SQLIdentifier>(strings);
	}

	static vector<SQLString> ConvertToSQLStrings(const vector<string> &strings) {
		return ConvertStrings<SQLString>(strings);
	}

	//! Returns true if the needle string exists in the haystack
	DUCKDB_API static bool Contains(const string &haystack, const string &needle);

	//! Returns true if the target string starts with the given prefix
	DUCKDB_API static bool StartsWith(string str, string prefix);

	//! Returns true if the target string <b>ends</b> with the given suffix.
	DUCKDB_API static bool EndsWith(const string &str, const string &suffix);

	//! Repeat a string multiple times
	DUCKDB_API static string Repeat(const string &str, const idx_t n);

	//! Split the input string based on newline char
	DUCKDB_API static vector<string> Split(const string &str, char delimiter);

	//! Split the input string allong a quote. Note that any escaping is NOT supported.
	DUCKDB_API static vector<string> SplitWithQuote(const string &str, char delimiter = ',', char quote = '"');

	//! Join multiple strings into one string. Components are concatenated by the given separator
	DUCKDB_API static string Join(const vector<string> &input, const string &separator);
	DUCKDB_API static string Join(const set<string> &input, const string &separator);

	//! Encode special URL characters in a string
	DUCKDB_API static string URLEncode(const string &str, bool encode_slash = true);
	DUCKDB_API static idx_t URLEncodeSize(const char *input, idx_t input_size, bool encode_slash = true);
	DUCKDB_API static void URLEncodeBuffer(const char *input, idx_t input_size, char *output, bool encode_slash = true);
	//! Decode URL escape sequences (e.g. %20) in a string
	DUCKDB_API static string URLDecode(const string &str, bool plus_to_space = false);
	DUCKDB_API static idx_t URLDecodeSize(const char *input, idx_t input_size, bool plus_to_space = false);
	DUCKDB_API static void URLDecodeBuffer(const char *input, idx_t input_size, char *output,
	                                       bool plus_to_space = false);

	template <class T>
	static string ToString(const vector<T> &input, const string &separator) {
		vector<string> input_list;
		for (auto &i : input) {
			input_list.push_back(i.ToString());
		}
		return StringUtil::Join(input_list, separator);
	}

	//! Join multiple items of container with given size, transformed to string
	//! using function, into one string using the given separator
	template <typename C, typename S, typename FUNC>
	static string Join(const C &input, S count, const string &separator, FUNC f) {
		// The result
		std::string result;

		// If the input isn't empty, append the first element. We do this so we
		// don't need to introduce an if into the loop.
		if (count > 0) {
			result += f(input[0]);
		}

		// Append the remaining input components, after the first
		for (size_t i = 1; i < count; i++) {
			result += separator + f(input[i]);
		}

		return result;
	}

	//! Return a string that formats the give number of bytes
	DUCKDB_API static string BytesToHumanReadableString(idx_t bytes, idx_t multiplier = 1024);

	//! Convert a string to UPPERCASE
	DUCKDB_API static string Upper(const string &str);

	//! Convert a string to lowercase
	DUCKDB_API static string Lower(const string &str);

	//! Convert a string to Title Case
	DUCKDB_API static string Title(const string &str);

	DUCKDB_API static bool IsLower(const string &str);

	//! Case insensitive hash
	DUCKDB_API static uint64_t CIHash(const string &str);

	//! Case insensitive equals
	DUCKDB_API static bool CIEquals(const string &l1, const string &l2);

	//! Case insensitive compare
	DUCKDB_API static bool CILessThan(const string &l1, const string &l2);

	//! Case insensitive find, returns DConstants::INVALID_INDEX if not found
	DUCKDB_API static idx_t CIFind(vector<string> &vec, const string &str);

	//! Format a string using printf semantics
	template <typename... ARGS>
	static string Format(const string fmt_str, ARGS... params) {
		return Exception::ConstructMessage(fmt_str, params...);
	}

	//! Split the input string into a vector of strings based on the split string
	DUCKDB_API static vector<string> Split(const string &input, const string &split);

	//! Remove the whitespace char in the left end of the string
	DUCKDB_API static void LTrim(string &str);
	//! Remove the whitespace char in the right end of the string
	DUCKDB_API static void RTrim(string &str);
	//! Remove the all chars from chars_to_trim char in the right end of the string
	DUCKDB_API static void RTrim(string &str, const string &chars_to_trim);
	//! Remove the whitespace char in the left and right end of the string
	DUCKDB_API static void Trim(string &str);

	DUCKDB_API static string Replace(string source, const string &from, const string &to);

	//! Get the levenshtein distance from two strings
	//! The not_equal_penalty is the penalty given when two characters in a string are not equal
	//! The regular levenshtein distance has a not equal penalty of 1, which means changing a character is as expensive
	//! as adding or removing one For similarity searches we often want to give extra weight to changing a character For
	//! example: with an equal penalty of 1, "pg_am" is closer to "depdelay" than "depdelay_minutes"
	//! with an equal penalty of 3, "depdelay_minutes" is closer to "depdelay" than to "pg_am"
	DUCKDB_API static idx_t LevenshteinDistance(const string &s1, const string &s2, idx_t not_equal_penalty = 1);

	//! Returns the similarity score between two strings (edit distance metric - lower is more similar)
	DUCKDB_API static idx_t SimilarityScore(const string &s1, const string &s2);
	//! Returns a normalized similarity rating between 0.0 - 1.0 (higher is more similar)
	DUCKDB_API static double SimilarityRating(const string &s1, const string &s2);
	//! Get the top-n strings (sorted by the given score distance) from a set of scores.
	//! The scores should be normalized between 0.0 and 1.0, where 1.0 is the highest score
	//! At least one entry is returned (if there is one).
	//! Strings are only returned if they have a score higher than the threshold.
	DUCKDB_API static vector<string> TopNStrings(vector<pair<string, double>> scores, idx_t n = 5,
	                                             double threshold = 0.5);
	//! DEPRECATED: old TopNStrings method that uses the levenshtein distance metric instead of the normalized 0.0 - 1.0
	//! rating
	DUCKDB_API static vector<string> TopNStrings(const vector<pair<string, idx_t>> &scores, idx_t n = 5,
	                                             idx_t threshold = 5);
	//! Computes the levenshtein distance of each string in strings, and compares it to target, then returns TopNStrings
	//! with the given params.
	DUCKDB_API static vector<string> TopNLevenshtein(const vector<string> &strings, const string &target, idx_t n = 5,
	                                                 idx_t threshold = 5);
	//! Computes the jaro winkler distance of each string in strings, and compares it to target, then returns
	//! TopNStrings with the given params.
	DUCKDB_API static vector<string> TopNJaroWinkler(const vector<string> &strings, const string &target, idx_t n = 5,
	                                                 double threshold = 0.5);
	DUCKDB_API static string CandidatesMessage(const vector<string> &candidates,
	                                           const string &candidate = "Candidate bindings");

	//! Generate an error message in the form of "{message_prefix}: nearest_string, nearest_string2, ...
	//! Equivalent to calling TopNLevenshtein followed by CandidatesMessage
	DUCKDB_API static string CandidatesErrorMessage(const vector<string> &strings, const string &target,
	                                                const string &message_prefix, idx_t n = 5);

	//! Returns true if two null-terminated strings are equal or point to the same address.
	//! Returns false if only one of the strings is nullptr
	static bool Equals(const char *s1, const char *s2) {
		if (s1 == s2) {
			return true;
		}
		if (s1 == nullptr || s2 == nullptr) {
			return false;
		}
		return strcmp(s1, s2) == 0;
	}

	//! JSON method that parses a { string: value } JSON blob
	//! NOTE: this method ONLY parses a JSON {"key": "value"} object, it does not support ANYTHING else
	//! NOTE: this method is not efficient
	//! NOTE: this method is used in Exception construction - as such it does NOT throw on invalid JSON, instead an
	//! empty map is returned
	DUCKDB_API static unordered_map<string, string> ParseJSONMap(const string &json);
	//! JSON method that constructs a { string: value } JSON map
	//! This is the inverse of ParseJSONMap
	//! NOTE: this method is not efficient
	DUCKDB_API static string ToJSONMap(ExceptionType type, const string &message,
	                                   const unordered_map<string, string> &map);

	DUCKDB_API static string GetFileName(const string &file_path);
	DUCKDB_API static string GetFileExtension(const string &file_name);
	DUCKDB_API static string GetFileStem(const string &file_name);
	DUCKDB_API static string GetFilePath(const string &file_path);
};

} // namespace duckdb




#include <functional>

namespace duckdb {

struct date_t;     // NOLINT
struct dtime_t;    // NOLINT
struct dtime_tz_t; // NOLINT

//! Type used to represent timestamps (seconds,microseconds,milliseconds or nanoseconds since 1970-01-01)
struct timestamp_t { // NOLINT
	int64_t value;

	timestamp_t() = default;
	explicit inline constexpr timestamp_t(int64_t value_p) : value(value_p) {
	}
	inline timestamp_t &operator=(int64_t value_p) {
		value = value_p;
		return *this;
	}

	// explicit conversion
	explicit inline operator int64_t() const {
		return value;
	}

	// comparison operators
	inline bool operator==(const timestamp_t &rhs) const {
		return value == rhs.value;
	};
	inline bool operator!=(const timestamp_t &rhs) const {
		return value != rhs.value;
	};
	inline bool operator<=(const timestamp_t &rhs) const {
		return value <= rhs.value;
	};
	inline bool operator<(const timestamp_t &rhs) const {
		return value < rhs.value;
	};
	inline bool operator>(const timestamp_t &rhs) const {
		return value > rhs.value;
	};
	inline bool operator>=(const timestamp_t &rhs) const {
		return value >= rhs.value;
	};

	// arithmetic operators
	timestamp_t operator+(const double &value) const;
	int64_t operator-(const timestamp_t &other) const;

	// in-place operators
	timestamp_t &operator+=(const int64_t &delta);
	timestamp_t &operator-=(const int64_t &delta);

	// special values
	static constexpr timestamp_t infinity() { // NOLINT
		return timestamp_t(NumericLimits<int64_t>::Maximum());
	}                                          // NOLINT
	static constexpr timestamp_t ninfinity() { // NOLINT
		return timestamp_t(-NumericLimits<int64_t>::Maximum());
	}                                             // NOLINT
	static constexpr inline timestamp_t epoch() { // NOLINT
		return timestamp_t(0);
	} // NOLINT
};

struct timestamp_tz_t : public timestamp_t { // NOLINT
};
struct timestamp_ns_t : public timestamp_t { // NOLINT
};
struct timestamp_ms_t : public timestamp_t { // NOLINT
};
struct timestamp_sec_t : public timestamp_t { // NOLINT
};

enum class TimestampCastResult : uint8_t { SUCCESS, ERROR_INCORRECT_FORMAT, ERROR_NON_UTC_TIMEZONE };

//! The Timestamp class is a static class that holds helper functions for the Timestamp
//! type.
class Timestamp {
public:
	// min timestamp is 290308-12-22 (BC)
	constexpr static const int32_t MIN_YEAR = -290308;
	constexpr static const int32_t MIN_MONTH = 12;
	constexpr static const int32_t MIN_DAY = 22;

public:
	//! Convert a string in the format "YYYY-MM-DD hh:mm:ss[.f][-+TH[:tm]]" to a timestamp object
	DUCKDB_API static timestamp_t FromString(const string &str);
	//! Convert a string where the offset can also be a time zone string: / [A_Za-z0-9/_]+/
	//! If has_offset is true, then the result is an instant that was offset from UTC
	//! If the tz is not empty, the result is still an instant, but the parts can be extracted and applied to the TZ
	DUCKDB_API static bool TryConvertTimestampTZ(const char *str, idx_t len, timestamp_t &result, bool &has_offset,
	                                             string_t &tz, optional_ptr<int32_t> nanos = nullptr);
	DUCKDB_API static TimestampCastResult TryConvertTimestamp(const char *str, idx_t len, timestamp_t &result,
	                                                          optional_ptr<int32_t> nanos = nullptr);
	DUCKDB_API static TimestampCastResult TryConvertTimestamp(const char *str, idx_t len, timestamp_ns_t &result);
	DUCKDB_API static timestamp_t FromCString(const char *str, idx_t len, optional_ptr<int32_t> nanos = nullptr);
	//! Convert a date object to a string in the format "YYYY-MM-DD hh:mm:ss"
	DUCKDB_API static string ToString(timestamp_t timestamp);

	DUCKDB_API static date_t GetDate(timestamp_t timestamp);

	DUCKDB_API static dtime_t GetTime(timestamp_t timestamp);
	//! Create a Timestamp object from a specified (date, time) combination
	DUCKDB_API static timestamp_t FromDatetime(date_t date, dtime_t time);
	DUCKDB_API static bool TryFromDatetime(date_t date, dtime_t time, timestamp_t &result);
	DUCKDB_API static bool TryFromDatetime(date_t date, dtime_tz_t timetz, timestamp_t &result);
	//! Scale up to ns
	DUCKDB_API static bool TryFromTimestampNanos(timestamp_t ts, int32_t nanos, timestamp_ns_t &result);

	//! Is the character a valid part of a time zone name?
	static inline bool CharacterIsTimeZone(char c) {
		return StringUtil::CharacterIsAlpha(c) || StringUtil::CharacterIsDigit(c) || c == '_' || c == '/' || c == '+' ||
		       c == '-';
	}

	//! Is the timestamp finite or infinite?
	static inline bool IsFinite(timestamp_t timestamp) {
		return timestamp != timestamp_t::infinity() && timestamp != timestamp_t::ninfinity();
	}

	//! Extract the date and time from a given timestamp object
	DUCKDB_API static void Convert(timestamp_t date, date_t &out_date, dtime_t &out_time);
	//! Extract the date and time from a given timestamp object
	DUCKDB_API static void Convert(timestamp_ns_t date, date_t &out_date, dtime_t &out_time, int32_t &out_nanos);
	//! Returns current timestamp
	DUCKDB_API static timestamp_t GetCurrentTimestamp();

	//! Convert the epoch (in sec) to a timestamp
	DUCKDB_API static timestamp_t FromEpochSecondsPossiblyInfinite(int64_t s);
	DUCKDB_API static timestamp_t FromEpochSeconds(int64_t s);
	//! Convert the epoch (in ms) to a timestamp
	DUCKDB_API static timestamp_t FromEpochMsPossiblyInfinite(int64_t ms);
	DUCKDB_API static timestamp_t FromEpochMs(int64_t ms);
	//! Convert the epoch (in microseconds) to a timestamp
	DUCKDB_API static timestamp_t FromEpochMicroSeconds(int64_t micros);
	//! Convert the epoch (in nanoseconds) to a timestamp
	DUCKDB_API static timestamp_t FromEpochNanoSecondsPossiblyInfinite(int64_t nanos);
	DUCKDB_API static timestamp_t FromEpochNanoSeconds(int64_t nanos);

	//! Construct ns timestamps from various epoch units
	DUCKDB_API static timestamp_ns_t TimestampNsFromEpochMicros(int64_t micros);
	DUCKDB_API static timestamp_ns_t TimestampNsFromEpochMillis(int64_t millis);

	//! Try convert a timestamp to epoch (in nanoseconds)
	DUCKDB_API static bool TryGetEpochNanoSeconds(timestamp_t timestamp, int64_t &result);
	//! Convert the epoch (in seconds) to a timestamp
	DUCKDB_API static int64_t GetEpochSeconds(timestamp_t timestamp);
	//! Convert the epoch (in ms) to a timestamp
	DUCKDB_API static int64_t GetEpochMs(timestamp_t timestamp);
	//! Convert a timestamp to epoch (in microseconds)
	DUCKDB_API static int64_t GetEpochMicroSeconds(timestamp_t timestamp);
	//! Convert a timestamp to epoch (in nanoseconds)
	DUCKDB_API static int64_t GetEpochNanoSeconds(timestamp_t timestamp);
	//! Convert a timestamp to a rounded epoch at a given resolution.
	DUCKDB_API static int64_t GetEpochRounded(timestamp_t timestamp, const int64_t power_of_ten);
	//! Convert a timestamp to a Julian Day
	DUCKDB_API static double GetJulianDay(timestamp_t timestamp);

	DUCKDB_API static bool TryParseUTCOffset(const char *str, idx_t &pos, idx_t len, int &hour_offset,
	                                         int &minute_offset);

	DUCKDB_API static string ConversionError(const string &str);
	DUCKDB_API static string ConversionError(string_t str);
	DUCKDB_API static string UnsupportedTimezoneError(const string &str);
	DUCKDB_API static string UnsupportedTimezoneError(string_t str);
};

} // namespace duckdb

namespace std {

//! Timestamp
template <>
struct hash<duckdb::timestamp_t> {
	std::size_t operator()(const duckdb::timestamp_t &k) const {
		using std::hash;
		return hash<int64_t>()((int64_t)k);
	}
};
template <>
struct hash<duckdb::timestamp_ms_t> {
	std::size_t operator()(const duckdb::timestamp_ms_t &k) const {
		using std::hash;
		return hash<int64_t>()((int64_t)k);
	}
};
template <>
struct hash<duckdb::timestamp_ns_t> {
	std::size_t operator()(const duckdb::timestamp_ns_t &k) const {
		using std::hash;
		return hash<int64_t>()((int64_t)k);
	}
};
template <>
struct hash<duckdb::timestamp_sec_t> {
	std::size_t operator()(const duckdb::timestamp_sec_t &k) const {
		using std::hash;
		return hash<int64_t>()((int64_t)k);
	}
};
template <>
struct hash<duckdb::timestamp_tz_t> {
	std::size_t operator()(const duckdb::timestamp_tz_t &k) const {
		using std::hash;
		return hash<int64_t>()((int64_t)k);
	}
};
} // namespace std

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/types/date.hpp
//
//
//===----------------------------------------------------------------------===//






//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/types/string_type.hpp
//
//
//===----------------------------------------------------------------------===//









#include <cstring>
#include <algorithm>

namespace duckdb {

struct string_t {
	friend struct StringComparisonOperators;

public:
	static constexpr idx_t PREFIX_BYTES = 4 * sizeof(char);
	static constexpr idx_t INLINE_BYTES = 12 * sizeof(char);
	static constexpr idx_t HEADER_SIZE = sizeof(uint32_t) + PREFIX_BYTES;
	static constexpr idx_t MAX_STRING_SIZE = NumericLimits<uint32_t>::Maximum();
#ifndef DUCKDB_DEBUG_NO_INLINE
	static constexpr idx_t PREFIX_LENGTH = PREFIX_BYTES;
	static constexpr idx_t INLINE_LENGTH = INLINE_BYTES;
#else
	static constexpr idx_t PREFIX_LENGTH = 0;
	static constexpr idx_t INLINE_LENGTH = 0;
#endif

	string_t() = default;
	explicit string_t(uint32_t len) {
		value.inlined.length = len;
	}
	string_t(const char *data, uint32_t len) {
		value.inlined.length = len;
		D_ASSERT(data || GetSize() == 0);
		if (IsInlined()) {
			// zero initialize the prefix first
			// this makes sure that strings with length smaller than 4 still have an equal prefix
			memset(value.inlined.inlined, 0, INLINE_BYTES);
			if (GetSize() == 0) {
				return;
			}
			// small string: inlined
			memcpy(value.inlined.inlined, data, GetSize());
		} else {
			// large string: store pointer
#ifndef DUCKDB_DEBUG_NO_INLINE
			memcpy(value.pointer.prefix, data, PREFIX_LENGTH);
#else
			memset(value.pointer.prefix, 0, PREFIX_BYTES);
#endif
			value.pointer.ptr = (char *)data; // NOLINT
		}
	}

	string_t(const char *data) // NOLINT: Allow implicit conversion from `const char*`
	    : string_t(data, UnsafeNumericCast<uint32_t>(strlen(data))) {
	}
	string_t(const string &value) // NOLINT: Allow implicit conversion from `const char*`
	    : string_t(value.c_str(), UnsafeNumericCast<uint32_t>(value.size())) {
	}

	bool IsInlined() const {
		return GetSize() <= INLINE_LENGTH;
	}

	const char *GetData() const {
		return IsInlined() ? const_char_ptr_cast(value.inlined.inlined) : value.pointer.ptr;
	}
	const char *GetDataUnsafe() const {
		return GetData();
	}

	char *GetDataWriteable() const {
		return IsInlined() ? (char *)value.inlined.inlined : value.pointer.ptr; // NOLINT
	}

	const char *GetPrefix() const {
		return value.inlined.inlined;
	}

	char *GetPrefixWriteable() {
		return value.inlined.inlined;
	}

	idx_t GetSize() const {
		return value.inlined.length;
	}

	bool Empty() const {
		return value.inlined.length == 0;
	}

	string GetString() const {
		return string(GetData(), GetSize());
	}

	explicit operator string() const {
		return GetString();
	}

	char *GetPointer() const {
		D_ASSERT(!IsInlined());
		return value.pointer.ptr;
	}

	void SetPointer(char *new_ptr) {
		D_ASSERT(!IsInlined());
		value.pointer.ptr = new_ptr;
	}

	void Finalize() {
		// set trailing NULL byte
		if (GetSize() <= INLINE_LENGTH) {
			// fill prefix with zeros if the length is smaller than the prefix length
			memset(value.inlined.inlined + GetSize(), 0, INLINE_BYTES - GetSize());
		} else {
			// copy the data into the prefix
#ifndef DUCKDB_DEBUG_NO_INLINE
			auto dataptr = GetData();
			memcpy(value.pointer.prefix, dataptr, PREFIX_LENGTH);
#else
			memset(value.pointer.prefix, 0, PREFIX_BYTES);
#endif
		}
	}

	void Verify() const;
	void VerifyUTF8() const;
	void VerifyCharacters() const;
	void VerifyNull() const;

	struct StringComparisonOperators {
		static inline bool Equals(const string_t &a, const string_t &b) {
#ifdef DUCKDB_DEBUG_NO_INLINE
			if (a.GetSize() != b.GetSize()) {
				return false;
			}
			return (memcmp(a.GetData(), b.GetData(), a.GetSize()) == 0);
#endif
			uint64_t a_bulk_comp = Load<uint64_t>(const_data_ptr_cast(&a));
			uint64_t b_bulk_comp = Load<uint64_t>(const_data_ptr_cast(&b));
			if (a_bulk_comp != b_bulk_comp) {
				// Either length or prefix are different -> not equal
				return false;
			}
			// they have the same length and same prefix!
			a_bulk_comp = Load<uint64_t>(const_data_ptr_cast(&a) + 8u);
			b_bulk_comp = Load<uint64_t>(const_data_ptr_cast(&b) + 8u);
			if (a_bulk_comp == b_bulk_comp) {
				// either they are both inlined (so compare equal) or point to the same string (so compare equal)
				return true;
			}
			if (!a.IsInlined()) {
				// 'long' strings of the same length -> compare pointed value
				if (memcmp(a.value.pointer.ptr, b.value.pointer.ptr, a.GetSize()) == 0) {
					return true;
				}
			}
			// either they are short string of same length but different content
			//     or they point to string with different content
			//     either way, they can't represent the same underlying string
			return false;
		}
		// compare up to shared length. if still the same, compare lengths
		static bool GreaterThan(const string_t &left, const string_t &right) {
			const uint32_t left_length = UnsafeNumericCast<uint32_t>(left.GetSize());
			const uint32_t right_length = UnsafeNumericCast<uint32_t>(right.GetSize());
			const uint32_t min_length = std::min<uint32_t>(left_length, right_length);

#ifndef DUCKDB_DEBUG_NO_INLINE
			uint32_t a_prefix = Load<uint32_t>(const_data_ptr_cast(left.GetPrefix()));
			uint32_t b_prefix = Load<uint32_t>(const_data_ptr_cast(right.GetPrefix()));

			// Utility to move 0xa1b2c3d4 into 0xd4c3b2a1, basically inverting the order byte-a-byte
			auto byte_swap = [](uint32_t v) -> uint32_t {
				uint32_t t1 = (v >> 16u) | (v << 16u);
				uint32_t t2 = t1 & 0x00ff00ff;
				uint32_t t3 = t1 & 0xff00ff00;
				return (t2 << 8u) | (t3 >> 8u);
			};

			// Check on prefix -----
			// We dont' need to mask since:
			//	if the prefix is greater(after bswap), it will stay greater regardless of the extra bytes
			// 	if the prefix is smaller(after bswap), it will stay smaller regardless of the extra bytes
			//	if the prefix is equal, the extra bytes are guaranteed to be /0 for the shorter one

			if (a_prefix != b_prefix) {
				return byte_swap(a_prefix) > byte_swap(b_prefix);
			}
#endif
			auto memcmp_res = memcmp(left.GetData(), right.GetData(), min_length);
			return memcmp_res > 0 || (memcmp_res == 0 && left_length > right_length);
		}
	};

	bool operator==(const string_t &r) const {
		return StringComparisonOperators::Equals(*this, r);
	}

	bool operator!=(const string_t &r) const {
		return !(*this == r);
	}

	bool operator>(const string_t &r) const {
		return StringComparisonOperators::GreaterThan(*this, r);
	}
	bool operator<(const string_t &r) const {
		return r > *this;
	}

private:
	union {
		struct {
			uint32_t length;
			char prefix[4];
			char *ptr;
		} pointer;
		struct {
			uint32_t length;
			char inlined[12];
		} inlined;
	} value;
};

} // namespace duckdb



#include <functional>

namespace duckdb {

struct timestamp_t; // NOLINT: primitive case

//! Type used to represent dates (days since 1970-01-01)
struct date_t { // NOLINT
	int32_t days;

	date_t() = default;
	explicit inline date_t(int32_t days_p) : days(days_p) {
	}

	// explicit conversion
	explicit inline operator int32_t() const {
		return days;
	}

	// comparison operators
	inline bool operator==(const date_t &rhs) const {
		return days == rhs.days;
	};
	inline bool operator!=(const date_t &rhs) const {
		return days != rhs.days;
	};
	inline bool operator<=(const date_t &rhs) const {
		return days <= rhs.days;
	};
	inline bool operator<(const date_t &rhs) const {
		return days < rhs.days;
	};
	inline bool operator>(const date_t &rhs) const {
		return days > rhs.days;
	};
	inline bool operator>=(const date_t &rhs) const {
		return days >= rhs.days;
	};

	// arithmetic operators
	inline date_t operator+(const int32_t &days) const {
		return date_t(this->days + days);
	};
	inline date_t operator-(const int32_t &days) const {
		return date_t(this->days - days);
	};

	// in-place operators
	inline date_t &operator+=(const int32_t &days) {
		this->days += days;
		return *this;
	};
	inline date_t &operator-=(const int32_t &days) {
		this->days -= days;
		return *this;
	};

	// special values
	static inline date_t infinity() { // NOLINT
		return date_t(NumericLimits<int32_t>::Maximum());
	}                                  // NOLINT
	static inline date_t ninfinity() { // NOLINT
		return date_t(-NumericLimits<int32_t>::Maximum());
	}                              // NOLINT
	static inline date_t epoch() { // NOLINT
		return date_t(0);
	} // NOLINT
};

//! The Date class is a static class that holds helper functions for the Date type.
class Date {
public:
	static const char *PINF;  // NOLINT
	static const char *NINF;  // NOLINT
	static const char *EPOCH; // NOLINT

	static const string_t MONTH_NAMES[12];
	static const string_t MONTH_NAMES_ABBREVIATED[12];
	static const string_t DAY_NAMES[7];
	static const string_t DAY_NAMES_ABBREVIATED[7];
	static const int32_t NORMAL_DAYS[13];
	static const int32_t CUMULATIVE_DAYS[13];
	static const int32_t LEAP_DAYS[13];
	static const int32_t CUMULATIVE_LEAP_DAYS[13];
	static const int32_t CUMULATIVE_YEAR_DAYS[401];
	static const int8_t MONTH_PER_DAY_OF_YEAR[365];
	static const int8_t LEAP_MONTH_PER_DAY_OF_YEAR[366];

	// min date is 5877642-06-25 (BC) (-2^31+2)
	constexpr static const int32_t DATE_MIN_YEAR = -5877641;
	constexpr static const int32_t DATE_MIN_MONTH = 6;
	constexpr static const int32_t DATE_MIN_DAY = 25;
	// max date is 5881580-07-10 (2^31-2)
	constexpr static const int32_t DATE_MAX_YEAR = 5881580;
	constexpr static const int32_t DATE_MAX_MONTH = 7;
	constexpr static const int32_t DATE_MAX_DAY = 10;
	constexpr static const int32_t EPOCH_YEAR = 1970;

	constexpr static const int32_t YEAR_INTERVAL = 400;
	constexpr static const int32_t DAYS_PER_YEAR_INTERVAL = 146097;

public:
	//! Convert a string in the format "YYYY-MM-DD" to a date object
	DUCKDB_API static date_t FromString(const string &str, bool strict = false);
	//! Convert a string in the format "YYYY-MM-DD" to a date object
	DUCKDB_API static date_t FromCString(const char *str, idx_t len, bool strict = false);
	//! Convert a date object to a string in the format "YYYY-MM-DD"
	DUCKDB_API static string ToString(date_t date);
	//! Try to convert the string as a give "special" date (e.g, PINF, ...)
	//! Returns true if it was successful and updates the scan pos.
	DUCKDB_API static bool TryConvertDateSpecial(const char *buf, idx_t len, idx_t &pos, const char *special);
	//! Try to convert text in a buffer to a date; returns true if parsing was successful
	//! If the date was a "special" value, the special flag will be set.
	DUCKDB_API static bool TryConvertDate(const char *buf, idx_t len, idx_t &pos, date_t &result, bool &special,
	                                      bool strict = false);

	//! Create a string "YYYY-MM-DD" from a specified (year, month, day)
	//! combination
	DUCKDB_API static string Format(int32_t year, int32_t month, int32_t day);

	//! Extract the year, month and day from a given date object
	DUCKDB_API static void Convert(date_t date, int32_t &out_year, int32_t &out_month, int32_t &out_day);
	//! Create a Date object from a specified (year, month, day) combination
	DUCKDB_API static date_t FromDate(int32_t year, int32_t month, int32_t day);
	DUCKDB_API static bool TryFromDate(int32_t year, int32_t month, int32_t day, date_t &result);

	//! Returns true if (year) is a leap year, and false otherwise
	DUCKDB_API static bool IsLeapYear(int32_t year);

	//! Returns true if the specified (year, month, day) combination is a valid
	//! date
	DUCKDB_API static bool IsValid(int32_t year, int32_t month, int32_t day);

	//! Returns true if the specified date is finite
	static inline bool IsFinite(date_t date) {
		return date != date_t::infinity() && date != date_t::ninfinity();
	}

	//! The max number of days in a month of a given year
	DUCKDB_API static int32_t MonthDays(int32_t year, int32_t month);

	//! Extract the epoch from the date (seconds since 1970-01-01)
	DUCKDB_API static int64_t Epoch(date_t date);
	//! Extract the epoch from the date (nanoseconds since 1970-01-01)
	DUCKDB_API static int64_t EpochNanoseconds(date_t date);
	//! Extract the epoch from the date (microseconds since 1970-01-01)
	DUCKDB_API static int64_t EpochMicroseconds(date_t date);
	//! Extract the epoch from the date (milliseconds since 1970-01-01)
	DUCKDB_API static int64_t EpochMilliseconds(date_t date);
	//! Convert the epoch (seconds since 1970-01-01) to a date_t
	DUCKDB_API static date_t EpochToDate(int64_t epoch);

	//! Extract the number of days since epoch (days since 1970-01-01)
	DUCKDB_API static int32_t EpochDays(date_t date);
	//! Convert the epoch number of days to a date_t
	DUCKDB_API static date_t EpochDaysToDate(int32_t epoch);

	//! Extract year of a date entry
	DUCKDB_API static int32_t ExtractYear(date_t date);
	//! Extract month of a date entry
	DUCKDB_API static int32_t ExtractMonth(date_t date);
	//! Extract day of a date entry
	DUCKDB_API static int32_t ExtractDay(date_t date);
	//! Extract the day of the week (1-7)
	DUCKDB_API static int32_t ExtractISODayOfTheWeek(date_t date);
	//! Extract the day of the year
	DUCKDB_API static int32_t ExtractDayOfTheYear(date_t date);
	//! Extract the day of the year
	DUCKDB_API static int64_t ExtractJulianDay(date_t date);
	//! Extract the ISO week number
	//! ISO weeks start on Monday and the first week of a year
	//! contains January 4 of that year.
	//! In the ISO week-numbering system, it is possible for early-January dates
	//! to be part of the 52nd or 53rd week of the previous year.
	DUCKDB_API static void ExtractISOYearWeek(date_t date, int32_t &year, int32_t &week);
	DUCKDB_API static int32_t ExtractISOWeekNumber(date_t date);
	DUCKDB_API static int32_t ExtractISOYearNumber(date_t date);
	//! Extract the week number as Python handles it.
	//! Either Monday or Sunday is the first day of the week,
	//! and any date before the first Monday/Sunday returns week 0
	//! This is a bit more consistent because week numbers in a year are always incrementing
	DUCKDB_API static int32_t ExtractWeekNumberRegular(date_t date, bool monday_first = true);
	//! Returns the date of the monday of the current week.
	DUCKDB_API static date_t GetMondayOfCurrentWeek(date_t date);

	//! Helper function to parse two digits from a string (e.g. "30" -> 30, "03" -> 3, "3" -> 3)
	DUCKDB_API static bool ParseDoubleDigit(const char *buf, idx_t len, idx_t &pos, int32_t &result);

	DUCKDB_API static string ConversionError(const string &str);
	DUCKDB_API static string ConversionError(string_t str);

private:
	static void ExtractYearOffset(int32_t &n, int32_t &year, int32_t &year_offset);
};

} // namespace duckdb

namespace std {

//! Date
template <>
struct hash<duckdb::date_t> {
	std::size_t operator()(const duckdb::date_t &k) const {
		using std::hash;
		return hash<int32_t>()((int32_t)k);
	}
};
} // namespace std






#include <functional>

namespace duckdb {

//! Type used to represent time (microseconds)
struct dtime_t { // NOLINT
	int64_t micros;

	dtime_t() = default;
	explicit inline dtime_t(int64_t micros_p) : micros(micros_p) {
	}
	inline dtime_t &operator=(int64_t micros_p) {
		micros = micros_p;
		return *this;
	}

	// explicit conversion
	explicit inline operator int64_t() const {
		return micros;
	}
	explicit inline operator double() const {
		return static_cast<double>(micros);
	}

	// comparison operators
	inline bool operator==(const dtime_t &rhs) const {
		return micros == rhs.micros;
	};
	inline bool operator!=(const dtime_t &rhs) const {
		return micros != rhs.micros;
	};
	inline bool operator<=(const dtime_t &rhs) const {
		return micros <= rhs.micros;
	};
	inline bool operator<(const dtime_t &rhs) const {
		return micros < rhs.micros;
	};
	inline bool operator>(const dtime_t &rhs) const {
		return micros > rhs.micros;
	};
	inline bool operator>=(const dtime_t &rhs) const {
		return micros >= rhs.micros;
	};

	// arithmetic operators
	inline dtime_t operator+(const int64_t &micros) const {
		return dtime_t(this->micros + micros);
	};
	inline dtime_t operator+(const double &micros) const {
		return dtime_t(this->micros + int64_t(micros));
	};
	inline dtime_t operator-(const int64_t &micros) const {
		return dtime_t(this->micros - micros);
	};
	inline dtime_t operator*(const idx_t &copies) const {
		return dtime_t(this->micros * UnsafeNumericCast<int64_t>(copies));
	};
	inline dtime_t operator/(const idx_t &copies) const {
		return dtime_t(this->micros / UnsafeNumericCast<int64_t>(copies));
	};
	inline int64_t operator-(const dtime_t &other) const {
		return this->micros - other.micros;
	};

	// in-place operators
	inline dtime_t &operator+=(const int64_t &micros) {
		this->micros += micros;
		return *this;
	};
	inline dtime_t &operator-=(const int64_t &micros) {
		this->micros -= micros;
		return *this;
	};
	inline dtime_t &operator+=(const dtime_t &other) {
		this->micros += other.micros;
		return *this;
	};

	// special values
	static inline dtime_t allballs() { // NOLINT
		return dtime_t(0);
	} // NOLINT
};

struct dtime_tz_t { // NOLINT
	static constexpr const int TIME_BITS = 40;
	static constexpr const int OFFSET_BITS = 24;
	static constexpr const uint64_t OFFSET_MASK = ~uint64_t(0) >> TIME_BITS;
	static constexpr const int32_t MAX_OFFSET = 16 * 60 * 60 - 1; // ±15:59:59
	static constexpr const int32_t MIN_OFFSET = -MAX_OFFSET;
	static constexpr const uint64_t OFFSET_MICROS = 1000000;

	uint64_t bits;

	//	Offsets are reverse ordered e.g., 13:00:00+01 < 12:00:00+00 < 11:00:00-01
	//	Because we encode them as the low order bits,
	//	they are also biased into an unsigned integer: (-16, 16) => (32, 0)
	static inline uint64_t encode_offset(int32_t offset) { // NOLINT
		return uint64_t(MAX_OFFSET - offset);
	}
	static inline int32_t decode_offset(uint64_t bits) { // NOLINT
		return MAX_OFFSET - int32_t(bits & OFFSET_MASK);
	}

	static inline uint64_t encode_micros(int64_t micros) { // NOLINT
		return encode_micros(UnsafeNumericCast<uint64_t>(micros));
	}
	static inline uint64_t encode_micros(uint64_t micros) { // NOLINT
		return micros << OFFSET_BITS;
	}
	static inline int64_t decode_micros(uint64_t bits) { // NOLINT
		return int64_t(bits >> OFFSET_BITS);
	}

	dtime_tz_t() = default;

	inline dtime_tz_t(dtime_t t, int32_t offset) : bits(encode_micros(t.micros) | encode_offset(offset)) {
	}
	explicit inline dtime_tz_t(uint64_t bits_p) : bits(bits_p) {
	}

	inline dtime_t time() const { // NOLINT
		return dtime_t(decode_micros(bits));
	}

	inline int32_t offset() const { // NOLINT
		return decode_offset(bits);
	}

	//	Times are compared after adjusting to offset +00:00:00, e.g., 13:01:00+01 > 12:00:00+00
	//	Because we encode them as the high order bits,
	//	they are biased by the maximum offset: (0, 24) => (0, 56)
	inline uint64_t sort_key() const { // NOLINT
		return bits + encode_micros((bits & OFFSET_MASK) * OFFSET_MICROS);
	}

	// comparison operators
	inline bool operator==(const dtime_tz_t &rhs) const {
		return bits == rhs.bits;
	};
	inline bool operator!=(const dtime_tz_t &rhs) const {
		return bits != rhs.bits;
	};
	inline bool operator<=(const dtime_tz_t &rhs) const {
		return sort_key() <= rhs.sort_key();
	};
	inline bool operator<(const dtime_tz_t &rhs) const {
		return sort_key() < rhs.sort_key();
	};
	inline bool operator>(const dtime_tz_t &rhs) const {
		return sort_key() > rhs.sort_key();
	};
	inline bool operator>=(const dtime_tz_t &rhs) const {
		return sort_key() >= rhs.sort_key();
	};
};

} // namespace duckdb

namespace std {

//! Time
template <>
struct hash<duckdb::dtime_t> {
	std::size_t operator()(const duckdb::dtime_t &k) const {
		using std::hash;
		return hash<int64_t>()((int64_t)k);
	}
};

template <>
struct hash<duckdb::dtime_tz_t> {
	std::size_t operator()(const duckdb::dtime_tz_t &k) const {
		using std::hash;
		return hash<uint64_t>()(k.bits);
	}
};
} // namespace std

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/types/interval.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

struct dtime_t;     // NOLINT: literal casing
struct date_t;      // NOLINT: literal casing
struct dtime_tz_t;  // NOLINT: literal casing
struct timestamp_t; // NOLINT: literal casing

class Serializer;
class Deserializer;

struct interval_t { // NOLINT
	int32_t months;
	int32_t days;
	int64_t micros;

	inline void Normalize(int64_t &months, int64_t &days, int64_t &micros) const;
	inline bool operator==(const interval_t &right) const {
		//	Quick equality check
		const auto &left = *this;
		if (left.months == right.months && left.days == right.days && left.micros == right.micros) {
			return true;
		}

		int64_t lmonths, ldays, lmicros;
		int64_t rmonths, rdays, rmicros;
		left.Normalize(lmonths, ldays, lmicros);
		right.Normalize(rmonths, rdays, rmicros);

		return lmonths == rmonths && ldays == rdays && lmicros == rmicros;
	}
	inline bool operator!=(const interval_t &right) const {
		return !(*this == right);
	}

	inline bool operator>(const interval_t &right) const {
		const auto &left = *this;
		int64_t lmonths, ldays, lmicros;
		int64_t rmonths, rdays, rmicros;
		left.Normalize(lmonths, ldays, lmicros);
		right.Normalize(rmonths, rdays, rmicros);

		if (lmonths > rmonths) {
			return true;
		} else if (lmonths < rmonths) {
			return false;
		}
		if (ldays > rdays) {
			return true;
		} else if (ldays < rdays) {
			return false;
		}
		return lmicros > rmicros;
	}

	inline bool operator<(const interval_t &right) const {
		return right > *this;
	}

	inline bool operator<=(const interval_t &right) const {
		return !(*this > right);
	}

	inline bool operator>=(const interval_t &right) const {
		return !(*this < right);
	}

	// Serialization
	void Serialize(Serializer &serializer) const;
	static interval_t Deserialize(Deserializer &source);
};

//! The Interval class is a static class that holds helper functions for the Interval
//! type.
class Interval {
public:
	static constexpr const int32_t MONTHS_PER_MILLENIUM = 12000;
	static constexpr const int32_t MONTHS_PER_CENTURY = 1200;
	static constexpr const int32_t MONTHS_PER_DECADE = 120;
	static constexpr const int32_t MONTHS_PER_YEAR = 12;
	static constexpr const int32_t MONTHS_PER_QUARTER = 3;
	static constexpr const int32_t DAYS_PER_WEEK = 7;
	//! only used for interval comparison/ordering purposes, in which case a month counts as 30 days
	static constexpr const int64_t DAYS_PER_MONTH = 30;
	static constexpr const int64_t DAYS_PER_YEAR = 365;
	static constexpr const int64_t MSECS_PER_SEC = 1000;
	static constexpr const int32_t SECS_PER_MINUTE = 60;
	static constexpr const int32_t MINS_PER_HOUR = 60;
	static constexpr const int32_t HOURS_PER_DAY = 24;
	static constexpr const int32_t SECS_PER_HOUR = SECS_PER_MINUTE * MINS_PER_HOUR;
	static constexpr const int32_t SECS_PER_DAY = SECS_PER_HOUR * HOURS_PER_DAY;
	static constexpr const int32_t SECS_PER_WEEK = SECS_PER_DAY * DAYS_PER_WEEK;

	static constexpr const int64_t MICROS_PER_MSEC = 1000;
	static constexpr const int64_t MICROS_PER_SEC = MICROS_PER_MSEC * MSECS_PER_SEC;
	static constexpr const int64_t MICROS_PER_MINUTE = MICROS_PER_SEC * SECS_PER_MINUTE;
	static constexpr const int64_t MICROS_PER_HOUR = MICROS_PER_MINUTE * MINS_PER_HOUR;
	static constexpr const int64_t MICROS_PER_DAY = MICROS_PER_HOUR * HOURS_PER_DAY;
	static constexpr const int64_t MICROS_PER_WEEK = MICROS_PER_DAY * DAYS_PER_WEEK;
	static constexpr const int64_t MICROS_PER_MONTH = MICROS_PER_DAY * DAYS_PER_MONTH;

	static constexpr const int64_t NANOS_PER_MICRO = 1000;
	static constexpr const int64_t NANOS_PER_MSEC = NANOS_PER_MICRO * MICROS_PER_MSEC;
	static constexpr const int64_t NANOS_PER_SEC = NANOS_PER_MSEC * MSECS_PER_SEC;
	static constexpr const int64_t NANOS_PER_MINUTE = NANOS_PER_SEC * SECS_PER_MINUTE;
	static constexpr const int64_t NANOS_PER_HOUR = NANOS_PER_MINUTE * MINS_PER_HOUR;
	static constexpr const int64_t NANOS_PER_DAY = NANOS_PER_HOUR * HOURS_PER_DAY;
	static constexpr const int64_t NANOS_PER_WEEK = NANOS_PER_DAY * DAYS_PER_WEEK;

public:
	//! Convert a string to an interval object
	static bool FromString(const string &str, interval_t &result);
	//! Convert a string to an interval object
	static bool FromCString(const char *str, idx_t len, interval_t &result, string *error_message, bool strict);
	//! Convert an interval object to a string
	static string ToString(const interval_t &val);

	//! Convert milliseconds to a normalised interval
	DUCKDB_API static interval_t FromMicro(int64_t micros);

	//! Get Interval in milliseconds
	static int64_t GetMilli(const interval_t &val);

	//! Get Interval in microseconds
	static int64_t GetMicro(const interval_t &val);

	//! Get Interval in Nanoseconds
	static int64_t GetNanoseconds(const interval_t &val);

	//! Returns the age between two timestamps (including 30 day months)
	static interval_t GetAge(timestamp_t timestamp_1, timestamp_t timestamp_2);

	//! Returns the exact difference between two timestamps (days and seconds)
	static interval_t GetDifference(timestamp_t timestamp_1, timestamp_t timestamp_2);

	//! Returns the inverted interval
	static interval_t Invert(interval_t interval);

	//! Add an interval to a date
	static date_t Add(date_t left, interval_t right);
	//! Add an interval to a timestamp
	static timestamp_t Add(timestamp_t left, interval_t right);
	//! Add an interval to a time. In case the time overflows or underflows, modify the date by the overflow.
	//! For example if we go from 23:00 to 02:00, we add a day to the date
	static dtime_t Add(dtime_t left, interval_t right, date_t &date);
	static dtime_tz_t Add(dtime_tz_t left, interval_t right, date_t &date);

	//! Comparison operators
	inline static bool Equals(const interval_t &left, const interval_t &right) {
		return left == right;
	}
	inline static bool GreaterThan(const interval_t &left, const interval_t &right) {
		return left > right;
	}
};
void interval_t::Normalize(int64_t &months, int64_t &days, int64_t &micros) const {
	auto input = *this;
	int64_t extra_months_d = input.days / Interval::DAYS_PER_MONTH;
	int64_t extra_months_micros = input.micros / Interval::MICROS_PER_MONTH;
	input.days -= UnsafeNumericCast<int32_t>(extra_months_d * Interval::DAYS_PER_MONTH);
	input.micros -= extra_months_micros * Interval::MICROS_PER_MONTH;

	int64_t extra_days_micros = input.micros / Interval::MICROS_PER_DAY;
	input.micros -= extra_days_micros * Interval::MICROS_PER_DAY;

	months = input.months + extra_months_d + extra_months_micros;
	days = input.days + extra_days_micros;
	micros = input.micros;
}

} // namespace duckdb



namespace duckdb {

class CastFunctionSet;
struct GetCastFunctionInput;
struct ExtraValueInfo;

//! The Value object holds a single arbitrary value of any type that can be
//! stored in the database.
class Value {
	friend struct StringValue;
	friend struct StructValue;
	friend struct ListValue;
	friend struct UnionValue;
	friend struct ArrayValue;
	friend struct MapValue;

public:
	//! Create an empty NULL value of the specified type
	DUCKDB_API explicit Value(LogicalType type = LogicalType::SQLNULL);
	//! Create an INTEGER value
	DUCKDB_API Value(int32_t val); // NOLINT: Allow implicit conversion from `int32_t`
	//! Create a BOOLEAN value
	explicit DUCKDB_API Value(bool val);
	//! Create a BIGINT value
	DUCKDB_API Value(int64_t val); // NOLINT: Allow implicit conversion from `int64_t`
	//! Create a FLOAT value
	DUCKDB_API Value(float val); // NOLINT: Allow implicit conversion from `float`
	//! Create a DOUBLE value
	DUCKDB_API Value(double val); // NOLINT: Allow implicit conversion from `double`
	//! Create a VARCHAR value
	DUCKDB_API Value(const char *val); // NOLINT: Allow implicit conversion from `const char *`
	//! Create a NULL value
	DUCKDB_API Value(std::nullptr_t val); // NOLINT: Allow implicit conversion from `nullptr_t`
	//! Create a VARCHAR value
	DUCKDB_API Value(string_t val); // NOLINT: Allow implicit conversion from `string_t`
	//! Create a VARCHAR value
	DUCKDB_API Value(string val); // NOLINT: Allow implicit conversion from `string`
	//! Copy constructor
	DUCKDB_API Value(const Value &other);
	//! Move constructor
	DUCKDB_API Value(Value &&other) noexcept;
	//! Destructor
	DUCKDB_API ~Value();

	// copy assignment
	DUCKDB_API Value &operator=(const Value &other);
	// move assignment
	DUCKDB_API Value &operator=(Value &&other) noexcept;

	inline LogicalType &GetTypeMutable() {
		return type_;
	}
	inline const LogicalType &type() const { // NOLINT
		return type_;
	}
	inline bool IsNull() const {
		return is_null;
	}

	//! Create the lowest possible value of a given type (numeric only)
	DUCKDB_API static Value MinimumValue(const LogicalType &type);
	//! Create the highest possible value of a given type (numeric only)
	DUCKDB_API static Value MaximumValue(const LogicalType &type);
	//! Create the negative infinite value of a given type (numeric only)
	DUCKDB_API static Value NegativeInfinity(const LogicalType &type);
	//! Create the positive infinite value of a given type (numeric only)
	DUCKDB_API static Value Infinity(const LogicalType &type);
	//! Create a Numeric value of the specified type with the specified value
	DUCKDB_API static Value Numeric(const LogicalType &type, int64_t value);
	DUCKDB_API static Value Numeric(const LogicalType &type, hugeint_t value);
	DUCKDB_API static Value Numeric(const LogicalType &type, uhugeint_t value);

	//! Create a boolean Value from a specified value
	DUCKDB_API static Value BOOLEAN(bool value);
	//! Create a tinyint Value from a specified value
	DUCKDB_API static Value TINYINT(int8_t value);
	//! Create a smallint Value from a specified value
	DUCKDB_API static Value SMALLINT(int16_t value);
	//! Create an integer Value from a specified value
	DUCKDB_API static Value INTEGER(int32_t value);
	//! Create a bigint Value from a specified value
	DUCKDB_API static Value BIGINT(int64_t value);
	//! Create an unsigned tinyint Value from a specified value
	DUCKDB_API static Value UTINYINT(uint8_t value);
	//! Create an unsigned smallint Value from a specified value
	DUCKDB_API static Value USMALLINT(uint16_t value);
	//! Create an unsigned integer Value from a specified value
	DUCKDB_API static Value UINTEGER(uint32_t value);
	//! Create an unsigned bigint Value from a specified value
	DUCKDB_API static Value UBIGINT(uint64_t value);
	//! Create a hugeint Value from a specified value
	DUCKDB_API static Value HUGEINT(hugeint_t value);
	//! Create a uhugeint Value from a specified value
	DUCKDB_API static Value UHUGEINT(uhugeint_t value);
	//! Create a uuid Value from a specified value
	DUCKDB_API static Value UUID(const string &value);
	//! Create a uuid Value from a specified value
	DUCKDB_API static Value UUID(hugeint_t value);
	//! Create a hash Value from a specified value
	DUCKDB_API static Value HASH(hash_t value);
	//! Create a pointer Value from a specified value
	DUCKDB_API static Value POINTER(uintptr_t value);
	//! Create a date Value from a specified date
	DUCKDB_API static Value DATE(date_t date);
	//! Create a date Value from a specified date
	DUCKDB_API static Value DATE(int32_t year, int32_t month, int32_t day);
	//! Create a time Value from a specified time
	DUCKDB_API static Value TIME(dtime_t time);
	DUCKDB_API static Value TIMETZ(dtime_tz_t time);
	//! Create a time Value from a specified time
	DUCKDB_API static Value TIME(int32_t hour, int32_t min, int32_t sec, int32_t micros);
	//! Create a timestamp Value from a specified date/time combination
	DUCKDB_API static Value TIMESTAMP(date_t date, dtime_t time);
	//! Create a timestamp Value from a specified timestamp
	DUCKDB_API static Value TIMESTAMP(timestamp_t timestamp);
	DUCKDB_API static Value TIMESTAMPNS(timestamp_t timestamp);
	DUCKDB_API static Value TIMESTAMPMS(timestamp_t timestamp);
	DUCKDB_API static Value TIMESTAMPSEC(timestamp_t timestamp);
	DUCKDB_API static Value TIMESTAMPTZ(timestamp_t timestamp);
	//! Create a timestamp Value from a specified timestamp in separate values
	DUCKDB_API static Value TIMESTAMP(int32_t year, int32_t month, int32_t day, int32_t hour, int32_t min, int32_t sec,
	                                  int32_t micros);
	DUCKDB_API static Value INTERVAL(int32_t months, int32_t days, int64_t micros);
	DUCKDB_API static Value INTERVAL(interval_t interval);

	// Create a enum Value from a specified uint value
	DUCKDB_API static Value ENUM(uint64_t value, const LogicalType &original_type);

	// Decimal values
	DUCKDB_API static Value DECIMAL(int16_t value, uint8_t width, uint8_t scale);
	DUCKDB_API static Value DECIMAL(int32_t value, uint8_t width, uint8_t scale);
	DUCKDB_API static Value DECIMAL(int64_t value, uint8_t width, uint8_t scale);
	DUCKDB_API static Value DECIMAL(hugeint_t value, uint8_t width, uint8_t scale);
	//! Create a float Value from a specified value
	DUCKDB_API static Value FLOAT(float value);
	//! Create a double Value from a specified value
	DUCKDB_API static Value DOUBLE(double value);
	//! Create a struct value with given list of entries
	DUCKDB_API static Value STRUCT(child_list_t<Value> values);
	DUCKDB_API static Value STRUCT(const LogicalType &type, vector<Value> struct_values);
	//! Create a list value with the given entries, list type is inferred from children
	//! Cannot be called with an empty list, use either EMPTYLIST or LIST with a type instead
	DUCKDB_API static Value LIST(vector<Value> values);
	//! Create a list value with the given entries
	DUCKDB_API static Value LIST(const LogicalType &child_type, vector<Value> values);
	//! Create an empty list with the specified child-type
	DUCKDB_API static Value EMPTYLIST(const LogicalType &child_type);
	//! Create an array value with the given entries. Array type is inferred from children
	//! Cannot be called with an empty list, use either EMPTYARRAY or ARRAY with a type instead
	DUCKDB_API static Value ARRAY(vector<Value> values);
	// Create an array value with the given entries
	DUCKDB_API static Value ARRAY(const LogicalType &type, vector<Value> values);
	//! Create an empty array of the given type and size
	DUCKDB_API static Value EMPTYARRAY(const LogicalType &type, uint32_t size);
	//! Create a map value with the given entries
	DUCKDB_API static Value MAP(const LogicalType &child_type, vector<Value> values);
	//! Create a map value with the given entries
	DUCKDB_API static Value MAP(const LogicalType &key_type, const LogicalType &value_type, vector<Value> keys,
	                            vector<Value> values);
	//! Create a map value from a set of key-value pairs
	DUCKDB_API static Value MAP(const unordered_map<string, string> &kv_pairs);

	//! Create a union value from a selected value and a tag from a set of alternatives.
	DUCKDB_API static Value UNION(child_list_t<LogicalType> members, uint8_t tag, Value value);

	//! Create a blob Value from a data pointer and a length: no bytes are interpreted
	DUCKDB_API static Value BLOB(const_data_ptr_t data, idx_t len);
	static Value BLOB_RAW(const string &data) { // NOLINT
		return Value::BLOB(const_data_ptr_cast(data.c_str()), data.size());
	}
	//! Creates a blob by casting a specified string to a blob (i.e. interpreting \x characters)
	DUCKDB_API static Value BLOB(const string &data);
	//! Creates a bitstring by casting a specified string to a bitstring
	DUCKDB_API static Value BIT(const_data_ptr_t data, idx_t len);
	DUCKDB_API static Value BIT(const string &data);
	DUCKDB_API static Value VARINT(const_data_ptr_t data, idx_t len);
	DUCKDB_API static Value VARINT(const string &data);

	//! Creates an aggregate state
	DUCKDB_API static Value AGGREGATE_STATE(const LogicalType &type, const_data_ptr_t data, idx_t len); // NOLINT

	template <class T>
	T GetValue() const;
	template <class T>
	static Value CreateValue(T value) {
		static_assert(AlwaysFalse<T>::VALUE, "No specialization exists for this type");
		return Value(nullptr);
	}
	// Returns the internal value. Unlike GetValue(), this method does not perform casting, and assumes T matches the
	// type of the value. Only use this if you know what you are doing.
	template <class T>
	T GetValueUnsafe() const;
	//! Returns a reference to the internal value. This can only be used for primitive types.
	template <class T>
	T &GetReferenceUnsafe();

	//! Return a copy of this value
	Value Copy() const {
		return Value(*this);
	}

	//! Hashes the Value
	DUCKDB_API hash_t Hash() const;
	//! Convert this value to a string
	DUCKDB_API string ToString() const;
	//! Convert this value to a SQL-parseable string
	DUCKDB_API string ToSQLString() const;

	DUCKDB_API uintptr_t GetPointer() const;

	//! Cast this value to another type, throws exception if its not possible
	DUCKDB_API Value CastAs(CastFunctionSet &set, GetCastFunctionInput &get_input, const LogicalType &target_type,
	                        bool strict = false) const;
	DUCKDB_API Value CastAs(ClientContext &context, const LogicalType &target_type, bool strict = false) const;
	DUCKDB_API Value DefaultCastAs(const LogicalType &target_type, bool strict = false) const;
	//! Tries to cast this value to another type, and stores the result in "new_value"
	DUCKDB_API bool TryCastAs(CastFunctionSet &set, GetCastFunctionInput &get_input, const LogicalType &target_type,
	                          Value &new_value, string *error_message, bool strict = false) const;
	DUCKDB_API bool TryCastAs(ClientContext &context, const LogicalType &target_type, Value &new_value,
	                          string *error_message, bool strict = false) const;
	DUCKDB_API bool DefaultTryCastAs(const LogicalType &target_type, Value &new_value, string *error_message,
	                                 bool strict = false) const;
	//! Tries to cast this value to another type, and stores the result in THIS value again
	DUCKDB_API bool TryCastAs(CastFunctionSet &set, GetCastFunctionInput &get_input, const LogicalType &target_type,
	                          bool strict = false);
	DUCKDB_API bool TryCastAs(ClientContext &context, const LogicalType &target_type, bool strict = false);
	DUCKDB_API bool DefaultTryCastAs(const LogicalType &target_type, bool strict = false);

	DUCKDB_API void Reinterpret(LogicalType new_type);

	//! Serializes a Value to a stand-alone binary blob
	DUCKDB_API void Serialize(Serializer &serializer) const;
	//! Deserializes a Value from a blob
	DUCKDB_API static Value Deserialize(Deserializer &deserializer);

	//===--------------------------------------------------------------------===//
	// Comparison Operators
	//===--------------------------------------------------------------------===//
	DUCKDB_API bool operator==(const Value &rhs) const;
	DUCKDB_API bool operator!=(const Value &rhs) const;
	DUCKDB_API bool operator<(const Value &rhs) const;
	DUCKDB_API bool operator>(const Value &rhs) const;
	DUCKDB_API bool operator<=(const Value &rhs) const;
	DUCKDB_API bool operator>=(const Value &rhs) const;

	DUCKDB_API bool operator==(const int64_t &rhs) const;
	DUCKDB_API bool operator!=(const int64_t &rhs) const;
	DUCKDB_API bool operator<(const int64_t &rhs) const;
	DUCKDB_API bool operator>(const int64_t &rhs) const;
	DUCKDB_API bool operator<=(const int64_t &rhs) const;
	DUCKDB_API bool operator>=(const int64_t &rhs) const;

	DUCKDB_API static bool FloatIsFinite(float value);
	DUCKDB_API static bool DoubleIsFinite(double value);
	template <class T>
	static bool IsNan(T value) {
		throw InternalException("Unimplemented template type for Value::IsNan");
	}
	template <class T>
	static bool IsFinite(T value) {
		return true;
	}
	DUCKDB_API static bool StringIsValid(const char *str, idx_t length);
	static bool StringIsValid(const string &str) {
		return StringIsValid(str.c_str(), str.size());
	}

	//! Returns true if the values are (approximately) equivalent. Note this is NOT the SQL equivalence. For this
	//! function, NULL values are equivalent and floating point values that are close are equivalent.
	DUCKDB_API static bool ValuesAreEqual(CastFunctionSet &set, GetCastFunctionInput &get_input,
	                                      const Value &result_value, const Value &value);
	DUCKDB_API static bool ValuesAreEqual(ClientContext &context, const Value &result_value, const Value &value);
	DUCKDB_API static bool DefaultValuesAreEqual(const Value &result_value, const Value &value);
	//! Returns true if the values are not distinct from each other, following SQL semantics for NOT DISTINCT FROM.
	DUCKDB_API static bool NotDistinctFrom(const Value &lvalue, const Value &rvalue);

	friend std::ostream &operator<<(std::ostream &out, const Value &val) {
		out << val.ToString();
		return out;
	}
	DUCKDB_API void Print() const;

private:
	//! The logical of the value
	LogicalType type_; // NOLINT

	//! Whether or not the value is NULL
	bool is_null;

	//! The value of the object, if it is of a constant size Type
	union Val {
		bool boolean;
		int8_t tinyint;
		int16_t smallint;
		int32_t integer;
		int64_t bigint;
		uint8_t utinyint;
		uint16_t usmallint;
		uint32_t uinteger;
		uint64_t ubigint;
		hugeint_t hugeint;
		uhugeint_t uhugeint;
		float float_;   // NOLINT
		double double_; // NOLINT
		uintptr_t pointer;
		uint64_t hash;
		date_t date;
		dtime_t time;
		dtime_tz_t timetz;
		timestamp_t timestamp;
		interval_t interval;
	} value_; // NOLINT

	shared_ptr<ExtraValueInfo> value_info_; // NOLINT

private:
	template <class T>
	T GetValueInternal() const;
};

//===--------------------------------------------------------------------===//
// Type-specific getters
//===--------------------------------------------------------------------===//
// Note that these are equivalent to calling GetValueUnsafe<X>, meaning no cast will be performed
// instead, an assertion will be triggered if the value is not of the correct type
struct BooleanValue {
	DUCKDB_API static bool Get(const Value &value);
};

struct TinyIntValue {
	DUCKDB_API static int8_t Get(const Value &value);
};

struct SmallIntValue {
	DUCKDB_API static int16_t Get(const Value &value);
};

struct IntegerValue {
	DUCKDB_API static int32_t Get(const Value &value);
};

struct BigIntValue {
	DUCKDB_API static int64_t Get(const Value &value);
};

struct HugeIntValue {
	DUCKDB_API static hugeint_t Get(const Value &value);
};

struct UTinyIntValue {
	DUCKDB_API static uint8_t Get(const Value &value);
};

struct USmallIntValue {
	DUCKDB_API static uint16_t Get(const Value &value);
};

struct UIntegerValue {
	DUCKDB_API static uint32_t Get(const Value &value);
};

struct UBigIntValue {
	DUCKDB_API static uint64_t Get(const Value &value);
};

struct UhugeIntValue {
	DUCKDB_API static uhugeint_t Get(const Value &value);
};

struct FloatValue {
	DUCKDB_API static float Get(const Value &value);
};

struct DoubleValue {
	DUCKDB_API static double Get(const Value &value);
};

struct StringValue {
	DUCKDB_API static const string &Get(const Value &value);
};

struct DateValue {
	DUCKDB_API static date_t Get(const Value &value);
};

struct TimeValue {
	DUCKDB_API static dtime_t Get(const Value &value);
};

struct TimestampValue {
	DUCKDB_API static timestamp_t Get(const Value &value);
};

struct IntervalValue {
	DUCKDB_API static interval_t Get(const Value &value);
};

struct StructValue {
	DUCKDB_API static const vector<Value> &GetChildren(const Value &value);
};

struct MapValue {
	DUCKDB_API static const vector<Value> &GetChildren(const Value &value);
};

struct ListValue {
	DUCKDB_API static const vector<Value> &GetChildren(const Value &value);
};

struct ArrayValue {
	DUCKDB_API static const vector<Value> &GetChildren(const Value &value);
};

struct UnionValue {
	DUCKDB_API static const Value &GetValue(const Value &value);
	DUCKDB_API static uint8_t GetTag(const Value &value);
	DUCKDB_API static const LogicalType &GetType(const Value &value);
};

//! Return the internal integral value for any type that is stored as an integral value internally
//! This can be used on values of type integer, uinteger, but also date, timestamp, decimal, etc
struct IntegralValue {
	static hugeint_t Get(const Value &value);
};

template <>
Value DUCKDB_API Value::CreateValue(bool value);
template <>
Value DUCKDB_API Value::CreateValue(uint8_t value);
template <>
Value DUCKDB_API Value::CreateValue(uint16_t value);
template <>
Value DUCKDB_API Value::CreateValue(uint32_t value);
template <>
Value DUCKDB_API Value::CreateValue(uint64_t value);
template <>
Value DUCKDB_API Value::CreateValue(int8_t value);
template <>
Value DUCKDB_API Value::CreateValue(int16_t value);
template <>
Value DUCKDB_API Value::CreateValue(int32_t value);
template <>
Value DUCKDB_API Value::CreateValue(int64_t value);
template <>
Value DUCKDB_API Value::CreateValue(hugeint_t value);
template <>
Value DUCKDB_API Value::CreateValue(uhugeint_t value);
template <>
Value DUCKDB_API Value::CreateValue(date_t value);
template <>
Value DUCKDB_API Value::CreateValue(dtime_t value);
template <>
Value DUCKDB_API Value::CreateValue(dtime_tz_t value);
template <>
Value DUCKDB_API Value::CreateValue(timestamp_t value);
template <>
Value DUCKDB_API Value::CreateValue(timestamp_sec_t value);
template <>
Value DUCKDB_API Value::CreateValue(timestamp_ms_t value);
template <>
Value DUCKDB_API Value::CreateValue(timestamp_ns_t value);
template <>
Value DUCKDB_API Value::CreateValue(timestamp_tz_t value);
template <>
Value DUCKDB_API Value::CreateValue(const char *value);
template <>
Value DUCKDB_API Value::CreateValue(string value);
template <>
Value DUCKDB_API Value::CreateValue(string_t value);
template <>
Value DUCKDB_API Value::CreateValue(float value);
template <>
Value DUCKDB_API Value::CreateValue(double value);
template <>
Value DUCKDB_API Value::CreateValue(interval_t value);
template <>
Value DUCKDB_API Value::CreateValue(Value value);

template <>
DUCKDB_API bool Value::GetValue() const;
template <>
DUCKDB_API int8_t Value::GetValue() const;
template <>
DUCKDB_API int16_t Value::GetValue() const;
template <>
DUCKDB_API int32_t Value::GetValue() const;
template <>
DUCKDB_API int64_t Value::GetValue() const;
template <>
DUCKDB_API uint8_t Value::GetValue() const;
template <>
DUCKDB_API uint16_t Value::GetValue() const;
template <>
DUCKDB_API uint32_t Value::GetValue() const;
template <>
DUCKDB_API uint64_t Value::GetValue() const;
template <>
DUCKDB_API hugeint_t Value::GetValue() const;
template <>
DUCKDB_API uhugeint_t Value::GetValue() const;
template <>
DUCKDB_API string Value::GetValue() const;
template <>
DUCKDB_API float Value::GetValue() const;
template <>
DUCKDB_API double Value::GetValue() const;
template <>
DUCKDB_API date_t Value::GetValue() const;
template <>
DUCKDB_API dtime_t Value::GetValue() const;
template <>
DUCKDB_API dtime_tz_t Value::GetValue() const;
template <>
DUCKDB_API timestamp_t Value::GetValue() const;
template <>
DUCKDB_API interval_t Value::GetValue() const;
template <>
DUCKDB_API Value Value::GetValue() const;

template <>
DUCKDB_API bool Value::GetValueUnsafe() const;
template <>
DUCKDB_API int8_t Value::GetValueUnsafe() const;
template <>
DUCKDB_API int16_t Value::GetValueUnsafe() const;
template <>
DUCKDB_API int32_t Value::GetValueUnsafe() const;
template <>
DUCKDB_API int64_t Value::GetValueUnsafe() const;
template <>
DUCKDB_API hugeint_t Value::GetValueUnsafe() const;
template <>
DUCKDB_API uhugeint_t Value::GetValueUnsafe() const;
template <>
DUCKDB_API uint8_t Value::GetValueUnsafe() const;
template <>
DUCKDB_API uint16_t Value::GetValueUnsafe() const;
template <>
DUCKDB_API uint32_t Value::GetValueUnsafe() const;
template <>
DUCKDB_API uint64_t Value::GetValueUnsafe() const;
template <>
DUCKDB_API string Value::GetValueUnsafe() const;
template <>
DUCKDB_API string_t Value::GetValueUnsafe() const;
template <>
DUCKDB_API float Value::GetValueUnsafe() const;
template <>
DUCKDB_API double Value::GetValueUnsafe() const;
template <>
DUCKDB_API date_t Value::GetValueUnsafe() const;
template <>
DUCKDB_API dtime_t Value::GetValueUnsafe() const;
template <>
DUCKDB_API dtime_tz_t Value::GetValueUnsafe() const;
template <>
DUCKDB_API timestamp_t Value::GetValueUnsafe() const;
template <>
DUCKDB_API interval_t Value::GetValueUnsafe() const;

template <>
DUCKDB_API bool Value::IsNan(float input);
template <>
DUCKDB_API bool Value::IsNan(double input);

template <>
DUCKDB_API bool Value::IsFinite(float input);
template <>
DUCKDB_API bool Value::IsFinite(double input);
template <>
DUCKDB_API bool Value::IsFinite(date_t input);
template <>
DUCKDB_API bool Value::IsFinite(timestamp_t input);

} // namespace duckdb

#include <memory>

namespace duckdb {
struct AlterInfo;
class Catalog;
class CatalogSet;
class ClientContext;
class SchemaCatalogEntry;
class Serializer;
class Deserializer;
class Value;

struct CatalogTransaction;
struct CreateInfo;

//! Abstract base class of an entry in the catalog
class CatalogEntry {
public:
	CatalogEntry(CatalogType type, Catalog &catalog, string name);
	CatalogEntry(CatalogType type, string name, idx_t oid);
	virtual ~CatalogEntry();

	//! The oid of the entry
	idx_t oid;
	//! The type of this catalog entry
	CatalogType type;
	//! Reference to the catalog set this entry is stored in
	optional_ptr<CatalogSet> set;
	//! The name of the entry
	string name;
	//! Whether or not the object is deleted
	bool deleted;
	//! Whether or not the object is temporary and should not be added to the WAL
	bool temporary;
	//! Whether or not the entry is an internal entry (cannot be deleted, not dumped, etc)
	bool internal;
	//! Timestamp at which the catalog entry was created
	atomic<transaction_t> timestamp;
	//! (optional) comment on this entry
	Value comment;
	//! (optional) extra data associated with this entry
	unordered_map<string, string> tags;

private:
	//! Child entry
	unique_ptr<CatalogEntry> child;
	//! Parent entry (the node that dependents_map this node)
	optional_ptr<CatalogEntry> parent;

public:
	virtual unique_ptr<CatalogEntry> AlterEntry(ClientContext &context, AlterInfo &info);
	virtual unique_ptr<CatalogEntry> AlterEntry(CatalogTransaction transaction, AlterInfo &info);
	virtual void UndoAlter(ClientContext &context, AlterInfo &info);

	virtual unique_ptr<CatalogEntry> Copy(ClientContext &context) const;

	virtual unique_ptr<CreateInfo> GetInfo() const;

	//! Sets the CatalogEntry as the new root entry (i.e. the newest entry)
	// this is called on a rollback to an AlterEntry
	virtual void SetAsRoot();

	//! Convert the catalog entry to a SQL string that can be used to re-construct the catalog entry
	virtual string ToSQL() const;

	virtual Catalog &ParentCatalog();
	virtual const Catalog &ParentCatalog() const;
	virtual SchemaCatalogEntry &ParentSchema();
	virtual const SchemaCatalogEntry &ParentSchema() const;

	virtual void Verify(Catalog &catalog);

	void Serialize(Serializer &serializer) const;
	static unique_ptr<CreateInfo> Deserialize(Deserializer &deserializer);

public:
	void SetChild(unique_ptr<CatalogEntry> child);
	unique_ptr<CatalogEntry> TakeChild();
	bool HasChild() const;
	bool HasParent() const;
	CatalogEntry &Child();
	CatalogEntry &Parent();

public:
	template <class TARGET>
	TARGET &Cast() {
		DynamicCastCheck<TARGET>(this);
		return reinterpret_cast<TARGET &>(*this);
	}
	template <class TARGET>
	const TARGET &Cast() const {
		DynamicCastCheck<TARGET>(this);
		return reinterpret_cast<const TARGET &>(*this);
	}
};

class InCatalogEntry : public CatalogEntry {
public:
	InCatalogEntry(CatalogType type, Catalog &catalog, string name);
	~InCatalogEntry() override;

	//! The catalog the entry belongs to
	Catalog &catalog;

public:
	Catalog &ParentCatalog() override {
		return catalog;
	}
	const Catalog &ParentCatalog() const override {
		return catalog;
	}

	void Verify(Catalog &catalog) override;
};

} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/mutex.hpp
//
//
//===----------------------------------------------------------------------===//



#ifdef __MVS__
#include <time.h>
#endif
#include <mutex>

namespace duckdb {
using std::lock_guard;
using std::mutex;
using std::unique_lock;
} // namespace duckdb


//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/catalog/catalog_transaction.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {
class Catalog;
class ClientContext;
class DatabaseInstance;
class Transaction;

struct CatalogTransaction {
	CatalogTransaction(Catalog &catalog, ClientContext &context);
	CatalogTransaction(DatabaseInstance &db, transaction_t transaction_id_p, transaction_t start_time_p);

	optional_ptr<DatabaseInstance> db;
	optional_ptr<ClientContext> context;
	optional_ptr<Transaction> transaction;
	transaction_t transaction_id;
	transaction_t start_time;

	bool HasContext() const {
		return context;
	}
	ClientContext &GetContext();

	static CatalogTransaction GetSystemCatalogTransaction(ClientContext &context);
	static CatalogTransaction GetSystemTransaction(DatabaseInstance &db);
};

} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/reference_map.hpp
//
//
//===----------------------------------------------------------------------===//





//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/unordered_set.hpp
//
//
//===----------------------------------------------------------------------===//



#include <unordered_set>

namespace duckdb {
using std::unordered_set;
}


namespace duckdb {
class Expression;

template <class T>
struct ReferenceHashFunction {
	uint64_t operator()(const reference<T> &ref) const {
		return std::hash<void *>()((void *)&ref.get());
	}
};

template <class T>
struct ReferenceEquality {
	bool operator()(const reference<T> &a, const reference<T> &b) const {
		return &a.get() == &b.get();
	}
};

template <typename T, typename TGT>
using reference_map_t = unordered_map<reference<T>, TGT, ReferenceHashFunction<T>, ReferenceEquality<T>>;

template <typename T>
using reference_set_t = unordered_set<reference<T>, ReferenceHashFunction<T>, ReferenceEquality<T>>;

} // namespace duckdb


//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/map.hpp
//
//
//===----------------------------------------------------------------------===//



#include <map>

namespace duckdb {
using std::map;
using std::multimap;
} // namespace duckdb


//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/enums/on_entry_not_found.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

enum class OnEntryNotFound : uint8_t { THROW_EXCEPTION = 0, RETURN_NULL = 1 };

} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/error_data.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {
class ParsedExpression;
class TableRef;

class ErrorData {
public:
	//! Not initialized, default constructor
	DUCKDB_API ErrorData();
	//! From std::exception
	DUCKDB_API ErrorData(const std::exception &ex); // NOLINT: allow implicit construction from exception
	//! From a raw string and exception type
	DUCKDB_API explicit ErrorData(ExceptionType type, const string &raw_message);
	//! From a raw string
	DUCKDB_API explicit ErrorData(const string &raw_message);

public:
	//! Throw the error
	[[noreturn]] DUCKDB_API void Throw(const string &prepended_message = "") const;
	//! Get the internal exception type of the error
	DUCKDB_API const ExceptionType &Type() const;
	//! Used in clients like C-API, creates the final message and returns a reference to it
	DUCKDB_API const string &Message() const {
		return final_message;
	}
	DUCKDB_API const string &RawMessage() const {
		return raw_message;
	}
	DUCKDB_API bool operator==(const ErrorData &other) const;

	inline bool HasError() const {
		return initialized;
	}
	const unordered_map<string, string> &ExtraInfo() const {
		return extra_info;
	}

	DUCKDB_API void AddErrorLocation(const string &query);
	DUCKDB_API void ConvertErrorToJSON();

	DUCKDB_API void AddQueryLocation(optional_idx query_location);
	DUCKDB_API void AddQueryLocation(QueryErrorContext error_context);
	DUCKDB_API void AddQueryLocation(const ParsedExpression &ref);
	DUCKDB_API void AddQueryLocation(const TableRef &ref);

private:
	//! Whether this ErrorData contains an exception or not
	bool initialized;
	//! The ExceptionType of the preserved exception
	ExceptionType type;
	//! The message the exception was constructed with (does not contain the Exception Type)
	string raw_message;
	//! The final message (stored in the preserved error for compatibility reasons with C-API)
	string final_message;
	//! Extra exception info
	unordered_map<string, string> extra_info;

private:
	DUCKDB_API static string SanitizeErrorMessage(string error);
	DUCKDB_API string ConstructFinalMessage() const;
};

} // namespace duckdb


//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/enums/catalog_lookup_behavior.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

//! Enum used for indicating lookup behavior of specific catalog types
// STANDARD means the catalog lookups are performed in a regular manner (i.e. according to the users' search path)
// LOWER_PRIORITY means the catalog lookups are de-prioritized and we do lookups in other catalogs first
// NEVER_LOOKUP means we never do lookups for this specific type in this catalog
enum class CatalogLookupBehavior : uint8_t { STANDARD = 0, LOWER_PRIORITY = 1, NEVER_LOOKUP = 2 };

} // namespace duckdb

#include <functional>

namespace duckdb {
struct CreateSchemaInfo;
struct DropInfo;
struct BoundCreateTableInfo;
struct AlterTableInfo;
struct CreateTableFunctionInfo;
struct CreateCopyFunctionInfo;
struct CreatePragmaFunctionInfo;
struct CreateFunctionInfo;
struct CreateViewInfo;
struct CreateSequenceInfo;
struct CreateCollationInfo;
struct CreateIndexInfo;
struct CreateTypeInfo;
struct CreateTableInfo;
struct DatabaseSize;
struct MetadataBlockInfo;

class AttachedDatabase;
class ClientContext;
class Transaction;

class AggregateFunctionCatalogEntry;
class CollateCatalogEntry;
class SchemaCatalogEntry;
class TableCatalogEntry;
class ViewCatalogEntry;
class SequenceCatalogEntry;
class TableFunctionCatalogEntry;
class CopyFunctionCatalogEntry;
class PragmaFunctionCatalogEntry;
class CatalogSet;
class DatabaseInstance;
class DependencyManager;

struct CatalogLookup;
struct CatalogEntryLookup;
struct SimilarCatalogEntry;

class Binder;
class LogicalOperator;
class PhysicalOperator;
class LogicalCreateIndex;
class LogicalCreateTable;
class LogicalInsert;
class LogicalDelete;
class LogicalUpdate;
class CreateStatement;

//! The Catalog object represents the catalog of the database.
class Catalog {
public:
	explicit Catalog(AttachedDatabase &db);
	virtual ~Catalog();

public:
	//! Get the SystemCatalog from the ClientContext
	DUCKDB_API static Catalog &GetSystemCatalog(ClientContext &context);
	//! Get the SystemCatalog from the DatabaseInstance
	DUCKDB_API static Catalog &GetSystemCatalog(DatabaseInstance &db);
	//! Get the specified Catalog from the ClientContext
	DUCKDB_API static Catalog &GetCatalog(ClientContext &context, const string &catalog_name);
	//! Get the specified Catalog from the DatabaseInstance
	DUCKDB_API static Catalog &GetCatalog(DatabaseInstance &db, const string &catalog_name);
	//! Gets the specified Catalog from the database if it exists
	DUCKDB_API static optional_ptr<Catalog> GetCatalogEntry(ClientContext &context, const string &catalog_name);
	//! Get the specific Catalog from the AttachedDatabase
	DUCKDB_API static Catalog &GetCatalog(AttachedDatabase &db);

	DUCKDB_API AttachedDatabase &GetAttached();
	DUCKDB_API const AttachedDatabase &GetAttached() const;
	DUCKDB_API DatabaseInstance &GetDatabase();

	virtual bool IsDuckCatalog() {
		return false;
	}
	virtual void Initialize(bool load_builtin) = 0;

	bool IsSystemCatalog() const;
	bool IsTemporaryCatalog() const;

	//! Returns a version number that uniquely characterizes the current catalog snapshot.
	//! If there are transaction-local changes, the version returned is >= TRANSACTION_START, o.w. it is a simple number
	//! starting at 0 that is incremented at each commit that has had catalog changes.
	//! If the catalog does not support versioning, no index is returned.
	DUCKDB_API virtual optional_idx GetCatalogVersion(ClientContext &context) {
		return {}; // don't return anything by default
	}

	//! Returns the catalog name - based on how the catalog was attached
	DUCKDB_API const string &GetName() const;
	DUCKDB_API idx_t GetOid();
	DUCKDB_API virtual string GetCatalogType() = 0;

	DUCKDB_API CatalogTransaction GetCatalogTransaction(ClientContext &context);

	//! Creates a schema in the catalog.
	DUCKDB_API virtual optional_ptr<CatalogEntry> CreateSchema(CatalogTransaction transaction,
	                                                           CreateSchemaInfo &info) = 0;
	DUCKDB_API optional_ptr<CatalogEntry> CreateSchema(ClientContext &context, CreateSchemaInfo &info);
	//! Creates a table in the catalog.
	DUCKDB_API optional_ptr<CatalogEntry> CreateTable(CatalogTransaction transaction, BoundCreateTableInfo &info);
	DUCKDB_API optional_ptr<CatalogEntry> CreateTable(ClientContext &context, BoundCreateTableInfo &info);
	//! Creates a table in the catalog.
	DUCKDB_API optional_ptr<CatalogEntry> CreateTable(ClientContext &context, unique_ptr<CreateTableInfo> info);
	//! Create a table function in the catalog
	DUCKDB_API optional_ptr<CatalogEntry> CreateTableFunction(CatalogTransaction transaction,
	                                                          CreateTableFunctionInfo &info);
	DUCKDB_API optional_ptr<CatalogEntry> CreateTableFunction(ClientContext &context, CreateTableFunctionInfo &info);
	// Kept for backwards compatibility
	DUCKDB_API optional_ptr<CatalogEntry> CreateTableFunction(ClientContext &context,
	                                                          optional_ptr<CreateTableFunctionInfo> info);
	//! Create a copy function in the catalog
	DUCKDB_API optional_ptr<CatalogEntry> CreateCopyFunction(CatalogTransaction transaction,
	                                                         CreateCopyFunctionInfo &info);
	DUCKDB_API optional_ptr<CatalogEntry> CreateCopyFunction(ClientContext &context, CreateCopyFunctionInfo &info);
	//! Create a pragma function in the catalog
	DUCKDB_API optional_ptr<CatalogEntry> CreatePragmaFunction(CatalogTransaction transaction,
	                                                           CreatePragmaFunctionInfo &info);
	DUCKDB_API optional_ptr<CatalogEntry> CreatePragmaFunction(ClientContext &context, CreatePragmaFunctionInfo &info);
	//! Create a scalar or aggregate function in the catalog
	DUCKDB_API optional_ptr<CatalogEntry> CreateFunction(CatalogTransaction transaction, CreateFunctionInfo &info);
	DUCKDB_API optional_ptr<CatalogEntry> CreateFunction(ClientContext &context, CreateFunctionInfo &info);
	//! Creates a table in the catalog.
	DUCKDB_API optional_ptr<CatalogEntry> CreateView(CatalogTransaction transaction, CreateViewInfo &info);
	DUCKDB_API optional_ptr<CatalogEntry> CreateView(ClientContext &context, CreateViewInfo &info);
	//! Creates a sequence in the catalog.
	DUCKDB_API optional_ptr<CatalogEntry> CreateSequence(CatalogTransaction transaction, CreateSequenceInfo &info);
	DUCKDB_API optional_ptr<CatalogEntry> CreateSequence(ClientContext &context, CreateSequenceInfo &info);
	//! Creates a Enum in the catalog.
	DUCKDB_API optional_ptr<CatalogEntry> CreateType(CatalogTransaction transaction, CreateTypeInfo &info);
	DUCKDB_API optional_ptr<CatalogEntry> CreateType(ClientContext &context, CreateTypeInfo &info);
	//! Creates a collation in the catalog
	DUCKDB_API optional_ptr<CatalogEntry> CreateCollation(CatalogTransaction transaction, CreateCollationInfo &info);
	DUCKDB_API optional_ptr<CatalogEntry> CreateCollation(ClientContext &context, CreateCollationInfo &info);
	//! Creates an index in the catalog
	DUCKDB_API optional_ptr<CatalogEntry> CreateIndex(CatalogTransaction transaction, CreateIndexInfo &info);
	DUCKDB_API optional_ptr<CatalogEntry> CreateIndex(ClientContext &context, CreateIndexInfo &info);

	//! Creates a table in the catalog.
	DUCKDB_API optional_ptr<CatalogEntry> CreateTable(CatalogTransaction transaction, SchemaCatalogEntry &schema,
	                                                  BoundCreateTableInfo &info);
	//! Create a table function in the catalog
	DUCKDB_API optional_ptr<CatalogEntry>
	CreateTableFunction(CatalogTransaction transaction, SchemaCatalogEntry &schema, CreateTableFunctionInfo &info);
	//! Create a copy function in the catalog
	DUCKDB_API optional_ptr<CatalogEntry> CreateCopyFunction(CatalogTransaction transaction, SchemaCatalogEntry &schema,
	                                                         CreateCopyFunctionInfo &info);
	//! Create a pragma function in the catalog
	DUCKDB_API optional_ptr<CatalogEntry>
	CreatePragmaFunction(CatalogTransaction transaction, SchemaCatalogEntry &schema, CreatePragmaFunctionInfo &info);
	//! Create a scalar or aggregate function in the catalog
	DUCKDB_API optional_ptr<CatalogEntry> CreateFunction(CatalogTransaction transaction, SchemaCatalogEntry &schema,
	                                                     CreateFunctionInfo &info);
	//! Creates a view in the catalog
	DUCKDB_API optional_ptr<CatalogEntry> CreateView(CatalogTransaction transaction, SchemaCatalogEntry &schema,
	                                                 CreateViewInfo &info);
	//! Creates a table in the catalog.
	DUCKDB_API optional_ptr<CatalogEntry> CreateSequence(CatalogTransaction transaction, SchemaCatalogEntry &schema,
	                                                     CreateSequenceInfo &info);
	//! Creates a enum in the catalog.
	DUCKDB_API optional_ptr<CatalogEntry> CreateType(CatalogTransaction transaction, SchemaCatalogEntry &schema,
	                                                 CreateTypeInfo &info);
	//! Creates a collation in the catalog
	DUCKDB_API optional_ptr<CatalogEntry> CreateCollation(CatalogTransaction transaction, SchemaCatalogEntry &schema,
	                                                      CreateCollationInfo &info);

	//! Drops an entry from the catalog
	DUCKDB_API void DropEntry(ClientContext &context, DropInfo &info);

	//! Returns the schema object with the specified name, or throws an exception if it does not exist
	DUCKDB_API SchemaCatalogEntry &GetSchema(ClientContext &context, const string &name,
	                                         QueryErrorContext error_context = QueryErrorContext());
	DUCKDB_API optional_ptr<SchemaCatalogEntry> GetSchema(ClientContext &context, const string &name,
	                                                      OnEntryNotFound if_not_found,
	                                                      QueryErrorContext error_context = QueryErrorContext());
	//! Overloadable method for giving warnings on ambiguous naming id.tab due to a database and schema with name id
	DUCKDB_API virtual bool CheckAmbiguousCatalogOrSchema(ClientContext &context, const string &name) {
		return !!GetSchema(context, name, OnEntryNotFound::RETURN_NULL);
	}
	DUCKDB_API SchemaCatalogEntry &GetSchema(CatalogTransaction transaction, const string &name,
	                                         QueryErrorContext error_context = QueryErrorContext());
	DUCKDB_API virtual optional_ptr<SchemaCatalogEntry>
	GetSchema(CatalogTransaction transaction, const string &schema_name, OnEntryNotFound if_not_found,
	          QueryErrorContext error_context = QueryErrorContext()) = 0;
	DUCKDB_API static SchemaCatalogEntry &GetSchema(ClientContext &context, const string &catalog_name,
	                                                const string &schema_name,
	                                                QueryErrorContext error_context = QueryErrorContext());
	DUCKDB_API static optional_ptr<SchemaCatalogEntry> GetSchema(ClientContext &context, const string &catalog_name,
	                                                             const string &schema_name,
	                                                             OnEntryNotFound if_not_found,
	                                                             QueryErrorContext error_context = QueryErrorContext());
	//! Scans all the schemas in the system one-by-one, invoking the callback for each entry
	DUCKDB_API virtual void ScanSchemas(ClientContext &context, std::function<void(SchemaCatalogEntry &)> callback) = 0;

	//! Gets the "schema.name" entry of the specified type, if entry does not exist behavior depends on OnEntryNotFound
	DUCKDB_API optional_ptr<CatalogEntry> GetEntry(ClientContext &context, CatalogType type, const string &schema,
	                                               const string &name, OnEntryNotFound if_not_found,
	                                               QueryErrorContext error_context = QueryErrorContext());
	DUCKDB_API CatalogEntry &GetEntry(ClientContext &context, CatalogType type, const string &schema,
	                                  const string &name, QueryErrorContext error_context = QueryErrorContext());
	//! Gets the "catalog.schema.name" entry of the specified type, if entry does not exist behavior depends on
	//! OnEntryNotFound
	DUCKDB_API static optional_ptr<CatalogEntry> GetEntry(ClientContext &context, CatalogType type,
	                                                      const string &catalog, const string &schema,
	                                                      const string &name, OnEntryNotFound if_not_found,
	                                                      QueryErrorContext error_context = QueryErrorContext());
	DUCKDB_API static CatalogEntry &GetEntry(ClientContext &context, CatalogType type, const string &catalog,
	                                         const string &schema, const string &name,
	                                         QueryErrorContext error_context = QueryErrorContext());

	template <class T>
	optional_ptr<T> GetEntry(ClientContext &context, const string &schema_name, const string &name,
	                         OnEntryNotFound if_not_found, QueryErrorContext error_context = QueryErrorContext()) {
		auto entry = GetEntry(context, T::Type, schema_name, name, if_not_found, error_context);
		if (!entry) {
			return nullptr;
		}
		if (entry->type != T::Type) {
			throw CatalogException(error_context, "%s is not an %s", name, T::Name);
		}
		return &entry->template Cast<T>();
	}
	template <class T>
	T &GetEntry(ClientContext &context, const string &schema_name, const string &name,
	            QueryErrorContext error_context = QueryErrorContext()) {
		auto entry = GetEntry<T>(context, schema_name, name, OnEntryNotFound::THROW_EXCEPTION, error_context);
		return *entry;
	}

	//! Append a scalar or aggregate function to the catalog
	DUCKDB_API optional_ptr<CatalogEntry> AddFunction(ClientContext &context, CreateFunctionInfo &info);

	//! Alter an existing entry in the catalog.
	DUCKDB_API void Alter(CatalogTransaction transaction, AlterInfo &info);
	DUCKDB_API void Alter(ClientContext &context, AlterInfo &info);

	virtual unique_ptr<PhysicalOperator> PlanCreateTableAs(ClientContext &context, LogicalCreateTable &op,
	                                                       unique_ptr<PhysicalOperator> plan) = 0;
	virtual unique_ptr<PhysicalOperator> PlanInsert(ClientContext &context, LogicalInsert &op,
	                                                unique_ptr<PhysicalOperator> plan) = 0;
	virtual unique_ptr<PhysicalOperator> PlanDelete(ClientContext &context, LogicalDelete &op,
	                                                unique_ptr<PhysicalOperator> plan) = 0;
	virtual unique_ptr<PhysicalOperator> PlanUpdate(ClientContext &context, LogicalUpdate &op,
	                                                unique_ptr<PhysicalOperator> plan) = 0;
	virtual unique_ptr<LogicalOperator> BindCreateIndex(Binder &binder, CreateStatement &stmt, TableCatalogEntry &table,
	                                                    unique_ptr<LogicalOperator> plan) = 0;

	virtual DatabaseSize GetDatabaseSize(ClientContext &context) = 0;
	virtual vector<MetadataBlockInfo> GetMetadataInfo(ClientContext &context);

	virtual bool InMemory() = 0;
	virtual string GetDBPath() = 0;

	//! Whether or not this catalog should search a specific type with the standard priority
	DUCKDB_API virtual CatalogLookupBehavior CatalogTypeLookupRule(CatalogType type) const {
		return CatalogLookupBehavior::STANDARD;
	}

public:
	template <class T>
	static optional_ptr<T> GetEntry(ClientContext &context, const string &catalog_name, const string &schema_name,
	                                const string &name, OnEntryNotFound if_not_found,
	                                QueryErrorContext error_context = QueryErrorContext()) {
		auto entry = GetEntry(context, T::Type, catalog_name, schema_name, name, if_not_found, error_context);
		if (!entry) {
			return nullptr;
		}
		if (entry->type != T::Type) {
			throw CatalogException(error_context, "%s is not an %s", name, T::Name);
		}
		return &entry->template Cast<T>();
	}
	template <class T>
	static T &GetEntry(ClientContext &context, const string &catalog_name, const string &schema_name,
	                   const string &name, QueryErrorContext error_context = QueryErrorContext()) {
		auto entry =
		    GetEntry<T>(context, catalog_name, schema_name, name, OnEntryNotFound::THROW_EXCEPTION, error_context);
		return *entry;
	}

	DUCKDB_API vector<reference<SchemaCatalogEntry>> GetSchemas(ClientContext &context);
	DUCKDB_API static vector<reference<SchemaCatalogEntry>> GetSchemas(ClientContext &context,
	                                                                   const string &catalog_name);
	DUCKDB_API static vector<reference<SchemaCatalogEntry>> GetAllSchemas(ClientContext &context);

	virtual void Verify();

	static CatalogException UnrecognizedConfigurationError(ClientContext &context, const string &name);

	//! Autoload the extension required for `configuration_name` or throw a CatalogException
	static void AutoloadExtensionByConfigName(ClientContext &context, const string &configuration_name);
	//! Autoload the extension required for `function_name` or throw a CatalogException
	static bool AutoLoadExtensionByCatalogEntry(DatabaseInstance &db, CatalogType type, const string &entry_name);
	DUCKDB_API static bool TryAutoLoad(ClientContext &context, const string &extension_name) noexcept;

protected:
	//! Reference to the database
	AttachedDatabase &db;

public:
private:
	//! Lookup an entry in the schema, returning a lookup with the entry and schema if they exist
	CatalogEntryLookup TryLookupEntryInternal(CatalogTransaction transaction, CatalogType type, const string &schema,
	                                          const string &name);
	//! Calls LookupEntryInternal on the schema, trying other schemas if the schema is invalid. Sets
	//! CatalogEntryLookup->error depending on if_not_found when no entry is found
	CatalogEntryLookup TryLookupEntry(ClientContext &context, CatalogType type, const string &schema,
	                                  const string &name, OnEntryNotFound if_not_found,
	                                  QueryErrorContext error_context = QueryErrorContext());
	//! Lookup an entry using TryLookupEntry, throws if entry not found and if_not_found == THROW_EXCEPTION
	CatalogEntryLookup LookupEntry(ClientContext &context, CatalogType type, const string &schema, const string &name,
	                               OnEntryNotFound if_not_found, QueryErrorContext error_context = QueryErrorContext());
	static CatalogEntryLookup TryLookupEntry(ClientContext &context, vector<CatalogLookup> &lookups, CatalogType type,
	                                         const string &name, OnEntryNotFound if_not_found,
	                                         QueryErrorContext error_context = QueryErrorContext());
	static CatalogEntryLookup TryLookupEntry(ClientContext &context, CatalogType type, const string &catalog,
	                                         const string &schema, const string &name, OnEntryNotFound if_not_found,
	                                         QueryErrorContext error_context);

	//! Return an exception with did-you-mean suggestion.
	static CatalogException CreateMissingEntryException(ClientContext &context, const string &entry_name,
	                                                    CatalogType type,
	                                                    const reference_set_t<SchemaCatalogEntry> &schemas,
	                                                    QueryErrorContext error_context);

	//! Return the close entry name, the distance and the belonging schema.
	static SimilarCatalogEntry SimilarEntryInSchemas(ClientContext &context, const string &entry_name, CatalogType type,
	                                                 const reference_set_t<SchemaCatalogEntry> &schemas);

	virtual void DropSchema(ClientContext &context, DropInfo &info) = 0;

public:
	template <class TARGET>
	TARGET &Cast() {
		DynamicCastCheck<TARGET>(this);
		return reinterpret_cast<TARGET &>(*this);
	}

	template <class TARGET>
	const TARGET &Cast() const {
		DynamicCastCheck<TARGET>(this);
		return reinterpret_cast<const TARGET &>(*this);
	}
};

} // namespace duckdb




#include <type_traits>

namespace duckdb {

class WriteStream {
public:
	// Writes a set amount of data from the specified buffer into the stream and moves the stream forward accordingly
	virtual void WriteData(const_data_ptr_t buffer, idx_t write_size) = 0;

	// Writes a type into the stream and moves the stream forward sizeof(T) bytes
	// The type must be a standard layout type
	template <class T>
	void Write(T element) {
		static_assert(std::is_standard_layout<T>(), "Write element must be a standard layout data type");
		WriteData(const_data_ptr_cast(&element), sizeof(T));
	}

	virtual ~WriteStream() {
	}
};

} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/file_system.hpp
//
//
//===----------------------------------------------------------------------===//




//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/enums/file_compression_type.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

enum class FileCompressionType : uint8_t { AUTO_DETECT = 0, UNCOMPRESSED = 1, GZIP = 2, ZSTD = 3 };

FileCompressionType FileCompressionTypeFromString(const string &input);

string CompressionExtensionFromType(const FileCompressionType type);

bool IsFileCompressed(string path, FileCompressionType type);

} // namespace duckdb


//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/file_buffer.hpp
//
//
//===----------------------------------------------------------------------===//




//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/enums/debug_initialize.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

enum class DebugInitialize : uint8_t { NO_INITIALIZE = 0, DEBUG_ZERO_INITIALIZE = 1, DEBUG_ONE_INITIALIZE = 2 };

} // namespace duckdb


namespace duckdb {
class Allocator;
struct FileHandle;

enum class FileBufferType : uint8_t { BLOCK = 1, MANAGED_BUFFER = 2, TINY_BUFFER = 3 };

static constexpr const idx_t FILE_BUFFER_TYPE_COUNT = 3;

//! The FileBuffer represents a buffer that can be read or written to a Direct IO FileHandle.
class FileBuffer {
public:
	//! Allocates a buffer of the specified size, with room for additional header bytes
	//! (typically 8 bytes). On return, this->AllocSize() >= this->size >= user_size.
	//! Our allocation size will always be page-aligned, which is necessary to support
	//! DIRECT_IO
	FileBuffer(Allocator &allocator, FileBufferType type, uint64_t user_size);
	FileBuffer(FileBuffer &source, FileBufferType type);

	virtual ~FileBuffer();

	Allocator &allocator;
	//! The type of the buffer
	FileBufferType type;
	//! The buffer that users can write to
	data_ptr_t buffer;
	//! The size of the portion that users can write to, this is equivalent to internal_size - BLOCK_HEADER_SIZE
	uint64_t size;

public:
	//! Read into the FileBuffer from the specified location.
	void Read(FileHandle &handle, uint64_t location);
	//! Write the contents of the FileBuffer to the specified location.
	void Write(FileHandle &handle, uint64_t location);

	void Clear();

	// Same rules as the constructor. We will add room for a header, in additio to
	// the requested user bytes. We will then sector-align the result.
	void Resize(uint64_t user_size);

	uint64_t AllocSize() const {
		return internal_size;
	}
	data_ptr_t InternalBuffer() {
		return internal_buffer;
	}

	struct MemoryRequirement {
		idx_t alloc_size;
		idx_t header_size;
	};

	MemoryRequirement CalculateMemory(uint64_t user_size);

	void Initialize(DebugInitialize info);

protected:
	//! The pointer to the internal buffer that will be read or written, including the buffer header
	data_ptr_t internal_buffer;
	//! The aligned size as passed to the constructor. This is the size that is read or written to disk.
	uint64_t internal_size;

	void ReallocBuffer(size_t malloc_size);
	void Init();
};

} // namespace duckdb



//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/enums/file_glob_options.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

enum class FileGlobOptions : uint8_t {
	DISALLOW_EMPTY = 0,
	ALLOW_EMPTY = 1,
};

} // namespace duckdb




//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/file_open_flags.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

enum class FileLockType : uint8_t { NO_LOCK = 0, READ_LOCK = 1, WRITE_LOCK = 2 };

class FileOpenFlags {
public:
	static constexpr idx_t FILE_FLAGS_READ = idx_t(1 << 0);
	static constexpr idx_t FILE_FLAGS_WRITE = idx_t(1 << 1);
	static constexpr idx_t FILE_FLAGS_DIRECT_IO = idx_t(1 << 2);
	static constexpr idx_t FILE_FLAGS_FILE_CREATE = idx_t(1 << 3);
	static constexpr idx_t FILE_FLAGS_FILE_CREATE_NEW = idx_t(1 << 4);
	static constexpr idx_t FILE_FLAGS_APPEND = idx_t(1 << 5);
	static constexpr idx_t FILE_FLAGS_PRIVATE = idx_t(1 << 6);
	static constexpr idx_t FILE_FLAGS_NULL_IF_NOT_EXISTS = idx_t(1 << 7);
	static constexpr idx_t FILE_FLAGS_PARALLEL_ACCESS = idx_t(1 << 8);
	static constexpr idx_t FILE_FLAGS_EXCLUSIVE_CREATE = idx_t(1 << 9);
	static constexpr idx_t FILE_FLAGS_NULL_IF_EXISTS = idx_t(1 << 10);

public:
	FileOpenFlags() = default;
	constexpr FileOpenFlags(idx_t flags) : flags(flags) { // NOLINT: allow implicit conversion
	}
	constexpr FileOpenFlags(FileLockType lock) : lock(lock) { // NOLINT: allow implicit conversion
	}
	constexpr FileOpenFlags(FileCompressionType compression) // NOLINT: allow implicit conversion
	    : compression(compression) {
	}
	constexpr FileOpenFlags(idx_t flags, FileLockType lock, FileCompressionType compression)
	    : flags(flags), lock(lock), compression(compression) {
	}

	static constexpr FileLockType MergeLock(FileLockType a, FileLockType b) {
		return a == FileLockType::NO_LOCK ? b : a;
	}

	static constexpr FileCompressionType MergeCompression(FileCompressionType a, FileCompressionType b) {
		return a == FileCompressionType::UNCOMPRESSED ? b : a;
	}

	inline constexpr FileOpenFlags operator|(FileOpenFlags b) const {
		return FileOpenFlags(flags | b.flags, MergeLock(lock, b.lock), MergeCompression(compression, b.compression));
	}
	inline FileOpenFlags &operator|=(FileOpenFlags b) {
		flags |= b.flags;
		lock = MergeLock(lock, b.lock);
		compression = MergeCompression(compression, b.compression);
		return *this;
	}

	FileLockType Lock() {
		return lock;
	}

	FileCompressionType Compression() {
		return compression;
	}

	void SetCompression(FileCompressionType new_compression) {
		compression = new_compression;
	}

	void Verify();

	inline bool OpenForReading() const {
		return flags & FILE_FLAGS_READ;
	}
	inline bool OpenForWriting() const {
		return flags & FILE_FLAGS_WRITE;
	}
	inline bool DirectIO() const {
		return flags & FILE_FLAGS_DIRECT_IO;
	}
	inline bool CreateFileIfNotExists() const {
		return flags & FILE_FLAGS_FILE_CREATE;
	}
	inline bool OverwriteExistingFile() const {
		return flags & FILE_FLAGS_FILE_CREATE_NEW;
	}
	inline bool OpenForAppending() const {
		return flags & FILE_FLAGS_APPEND;
	}
	inline bool CreatePrivateFile() const {
		return flags & FILE_FLAGS_PRIVATE;
	}
	inline bool ReturnNullIfNotExists() const {
		return flags & FILE_FLAGS_NULL_IF_NOT_EXISTS;
	}
	inline bool RequireParallelAccess() const {
		return flags & FILE_FLAGS_PARALLEL_ACCESS;
	}
	inline bool ExclusiveCreate() const {
		return flags & FILE_FLAGS_EXCLUSIVE_CREATE;
	}
	inline bool ReturnNullIfExists() const {
		return flags & FILE_FLAGS_NULL_IF_EXISTS;
	}
	inline idx_t GetFlagsInternal() const {
		return flags;
	}

private:
	idx_t flags = 0;
	FileLockType lock = FileLockType::NO_LOCK;
	FileCompressionType compression = FileCompressionType::UNCOMPRESSED;
};

class FileFlags {
public:
	//! Open file with read access
	static constexpr FileOpenFlags FILE_FLAGS_READ = FileOpenFlags(FileOpenFlags::FILE_FLAGS_READ);
	//! Open file with write access
	static constexpr FileOpenFlags FILE_FLAGS_WRITE = FileOpenFlags(FileOpenFlags::FILE_FLAGS_WRITE);
	//! Use direct IO when reading/writing to the file
	static constexpr FileOpenFlags FILE_FLAGS_DIRECT_IO = FileOpenFlags(FileOpenFlags::FILE_FLAGS_DIRECT_IO);
	//! Create file if not exists, can only be used together with WRITE
	static constexpr FileOpenFlags FILE_FLAGS_FILE_CREATE = FileOpenFlags(FileOpenFlags::FILE_FLAGS_FILE_CREATE);
	//! Always create a new file. If a file exists, the file is truncated. Cannot be used together with CREATE.
	static constexpr FileOpenFlags FILE_FLAGS_FILE_CREATE_NEW =
	    FileOpenFlags(FileOpenFlags::FILE_FLAGS_FILE_CREATE_NEW);
	//! Open file in append mode
	static constexpr FileOpenFlags FILE_FLAGS_APPEND = FileOpenFlags(FileOpenFlags::FILE_FLAGS_APPEND);
	//! Open file with restrictive permissions (600 on linux/mac) can only be used when creating, throws if file exists
	static constexpr FileOpenFlags FILE_FLAGS_PRIVATE = FileOpenFlags(FileOpenFlags::FILE_FLAGS_PRIVATE);
	//! Return NULL if the file does not exist instead of throwing an error
	static constexpr FileOpenFlags FILE_FLAGS_NULL_IF_NOT_EXISTS =
	    FileOpenFlags(FileOpenFlags::FILE_FLAGS_NULL_IF_NOT_EXISTS);
	//! Multiple threads may perform reads and writes in parallel
	static constexpr FileOpenFlags FILE_FLAGS_PARALLEL_ACCESS =
	    FileOpenFlags(FileOpenFlags::FILE_FLAGS_PARALLEL_ACCESS);
	//! Ensure that this call creates the file, throw is file exists
	static constexpr FileOpenFlags FILE_FLAGS_EXCLUSIVE_CREATE =
	    FileOpenFlags(FileOpenFlags::FILE_FLAGS_EXCLUSIVE_CREATE);
	//!  Return NULL if the file exist instead of throwing an error
	static constexpr FileOpenFlags FILE_FLAGS_NULL_IF_EXISTS = FileOpenFlags(FileOpenFlags::FILE_FLAGS_NULL_IF_EXISTS);
};

} // namespace duckdb

#include <functional>

#undef CreateDirectory
#undef MoveFile
#undef RemoveDirectory

namespace duckdb {
class AttachedDatabase;
class ClientContext;
class DatabaseInstance;
class FileOpener;
class FileSystem;

enum class FileType {
	//! Regular file
	FILE_TYPE_REGULAR,
	//! Directory
	FILE_TYPE_DIR,
	//! FIFO named pipe
	FILE_TYPE_FIFO,
	//! Socket
	FILE_TYPE_SOCKET,
	//! Symbolic link
	FILE_TYPE_LINK,
	//! Block device
	FILE_TYPE_BLOCKDEV,
	//! Character device
	FILE_TYPE_CHARDEV,
	//! Unknown or invalid file handle
	FILE_TYPE_INVALID,
};

struct FileHandle {
public:
	DUCKDB_API FileHandle(FileSystem &file_system, string path);
	FileHandle(const FileHandle &) = delete;
	DUCKDB_API virtual ~FileHandle();

	DUCKDB_API int64_t Read(void *buffer, idx_t nr_bytes);
	DUCKDB_API int64_t Write(void *buffer, idx_t nr_bytes);
	DUCKDB_API void Read(void *buffer, idx_t nr_bytes, idx_t location);
	DUCKDB_API void Write(void *buffer, idx_t nr_bytes, idx_t location);
	DUCKDB_API void Seek(idx_t location);
	DUCKDB_API void Reset();
	DUCKDB_API idx_t SeekPosition();
	DUCKDB_API void Sync();
	DUCKDB_API void Truncate(int64_t new_size);
	DUCKDB_API string ReadLine();
	DUCKDB_API bool Trim(idx_t offset_bytes, idx_t length_bytes);
	DUCKDB_API virtual idx_t GetProgress();
	DUCKDB_API virtual FileCompressionType GetFileCompressionType();

	DUCKDB_API bool CanSeek();
	DUCKDB_API bool IsPipe();
	DUCKDB_API bool OnDiskFile();
	DUCKDB_API idx_t GetFileSize();
	DUCKDB_API FileType GetType();

	//! Closes the file handle.
	DUCKDB_API virtual void Close() = 0;

	string GetPath() const {
		return path;
	}

	template <class TARGET>
	TARGET &Cast() {
		DynamicCastCheck<TARGET>(this);
		return reinterpret_cast<TARGET &>(*this);
	}
	template <class TARGET>
	const TARGET &Cast() const {
		DynamicCastCheck<TARGET>(this);
		return reinterpret_cast<const TARGET &>(*this);
	}

public:
	FileSystem &file_system;
	string path;
};

class FileSystem {
public:
	DUCKDB_API virtual ~FileSystem();

public:
	DUCKDB_API static FileSystem &GetFileSystem(ClientContext &context);
	DUCKDB_API static FileSystem &GetFileSystem(DatabaseInstance &db);
	DUCKDB_API static FileSystem &Get(AttachedDatabase &db);

	DUCKDB_API virtual unique_ptr<FileHandle> OpenFile(const string &path, FileOpenFlags flags,
	                                                   optional_ptr<FileOpener> opener = nullptr);

	//! Read exactly nr_bytes from the specified location in the file. Fails if nr_bytes could not be read. This is
	//! equivalent to calling SetFilePointer(location) followed by calling Read().
	DUCKDB_API virtual void Read(FileHandle &handle, void *buffer, int64_t nr_bytes, idx_t location);
	//! Write exactly nr_bytes to the specified location in the file. Fails if nr_bytes could not be written. This is
	//! equivalent to calling SetFilePointer(location) followed by calling Write().
	DUCKDB_API virtual void Write(FileHandle &handle, void *buffer, int64_t nr_bytes, idx_t location);
	//! Read nr_bytes from the specified file into the buffer, moving the file pointer forward by nr_bytes. Returns the
	//! amount of bytes read.
	DUCKDB_API virtual int64_t Read(FileHandle &handle, void *buffer, int64_t nr_bytes);
	//! Write nr_bytes from the buffer into the file, moving the file pointer forward by nr_bytes.
	DUCKDB_API virtual int64_t Write(FileHandle &handle, void *buffer, int64_t nr_bytes);
	//! Excise a range of the file. The OS can drop pages from the page-cache, and the file-system is free to deallocate
	//! this range (sparse file support). Reads to the range will succeed but will return undefined data.
	DUCKDB_API virtual bool Trim(FileHandle &handle, idx_t offset_bytes, idx_t length_bytes);

	//! Returns the file size of a file handle, returns -1 on error
	DUCKDB_API virtual int64_t GetFileSize(FileHandle &handle);
	//! Returns the file last modified time of a file handle, returns timespec with zero on all attributes on error
	DUCKDB_API virtual time_t GetLastModifiedTime(FileHandle &handle);
	//! Returns the file type of the attached handle
	DUCKDB_API virtual FileType GetFileType(FileHandle &handle);
	//! Truncate a file to a maximum size of new_size, new_size should be smaller than or equal to the current size of
	//! the file
	DUCKDB_API virtual void Truncate(FileHandle &handle, int64_t new_size);

	//! Check if a directory exists
	DUCKDB_API virtual bool DirectoryExists(const string &directory, optional_ptr<FileOpener> opener = nullptr);
	//! Create a directory if it does not exist
	DUCKDB_API virtual void CreateDirectory(const string &directory, optional_ptr<FileOpener> opener = nullptr);
	//! Recursively remove a directory and all files in it
	DUCKDB_API virtual void RemoveDirectory(const string &directory, optional_ptr<FileOpener> opener = nullptr);

	//! List files in a directory, invoking the callback method for each one with (filename, is_dir)
	DUCKDB_API virtual bool ListFiles(const string &directory,
	                                  const std::function<void(const string &, bool)> &callback,
	                                  FileOpener *opener = nullptr);

	//! Move a file from source path to the target, StorageManager relies on this being an atomic action for ACID
	//! properties
	DUCKDB_API virtual void MoveFile(const string &source, const string &target,
	                                 optional_ptr<FileOpener> opener = nullptr);
	//! Check if a file exists
	DUCKDB_API virtual bool FileExists(const string &filename, optional_ptr<FileOpener> opener = nullptr);
	//! Check if path is pipe
	DUCKDB_API virtual bool IsPipe(const string &filename, optional_ptr<FileOpener> opener = nullptr);
	//! Remove a file from disk
	DUCKDB_API virtual void RemoveFile(const string &filename, optional_ptr<FileOpener> opener = nullptr);
	//! Sync a file handle to disk
	DUCKDB_API virtual void FileSync(FileHandle &handle);
	//! Sets the working directory
	DUCKDB_API static void SetWorkingDirectory(const string &path);
	//! Gets the working directory
	DUCKDB_API static string GetWorkingDirectory();
	//! Gets the users home directory
	DUCKDB_API static string GetHomeDirectory(optional_ptr<FileOpener> opener);
	//! Gets the users home directory
	DUCKDB_API virtual string GetHomeDirectory();
	//! Expands a given path, including e.g. expanding the home directory of the user
	DUCKDB_API static string ExpandPath(const string &path, optional_ptr<FileOpener> opener);
	//! Expands a given path, including e.g. expanding the home directory of the user
	DUCKDB_API virtual string ExpandPath(const string &path);
	//! Returns the system-available memory in bytes. Returns DConstants::INVALID_INDEX if the system function fails.
	DUCKDB_API static optional_idx GetAvailableMemory();
	//! Returns the space available on the disk. Returns DConstants::INVALID_INDEX if the information was not available.
	DUCKDB_API static optional_idx GetAvailableDiskSpace(const string &path);
	//! Path separator for path
	DUCKDB_API virtual string PathSeparator(const string &path);
	//! Checks if path is starts with separator (i.e., '/' on UNIX '\\' on Windows)
	DUCKDB_API bool IsPathAbsolute(const string &path);
	//! Normalize an absolute path - the goal of normalizing is converting "\test.db" and "C:/test.db" into "C:\test.db"
	//! so that the database system cache can correctly
	DUCKDB_API string NormalizeAbsolutePath(const string &path);
	//! Join two paths together
	DUCKDB_API string JoinPath(const string &a, const string &path);
	//! Convert separators in a path to the local separators (e.g. convert "/" into \\ on windows)
	DUCKDB_API string ConvertSeparators(const string &path);
	//! Extract the base name of a file (e.g. if the input is lib/example.dll the base name is 'example')
	DUCKDB_API string ExtractBaseName(const string &path);
	//! Extract the name of a file (e.g if the input is lib/example.dll the name is 'example.dll')
	DUCKDB_API string ExtractName(const string &path);

	//! Returns the value of an environment variable - or the empty string if it is not set
	DUCKDB_API static string GetEnvVariable(const string &name);

	//! Whether there is a glob in the string
	DUCKDB_API static bool HasGlob(const string &str);
	//! Runs a glob on the file system, returning a list of matching files
	DUCKDB_API virtual vector<string> Glob(const string &path, FileOpener *opener = nullptr);
	DUCKDB_API vector<string> GlobFiles(const string &path, ClientContext &context,
	                                    FileGlobOptions options = FileGlobOptions::DISALLOW_EMPTY);

	//! registers a sub-file system to handle certain file name prefixes, e.g. http:// etc.
	DUCKDB_API virtual void RegisterSubSystem(unique_ptr<FileSystem> sub_fs);
	DUCKDB_API virtual void RegisterSubSystem(FileCompressionType compression_type, unique_ptr<FileSystem> fs);

	//! Unregister a sub-filesystem by name
	DUCKDB_API virtual void UnregisterSubSystem(const string &name);

	//! List registered sub-filesystems, including builtin ones
	DUCKDB_API virtual vector<string> ListSubSystems();

	//! Whether or not a sub-system can handle a specific file path
	DUCKDB_API virtual bool CanHandleFile(const string &fpath);

	//! Set the file pointer of a file handle to a specified location. Reads and writes will happen from this location
	DUCKDB_API virtual void Seek(FileHandle &handle, idx_t location);
	//! Reset a file to the beginning (equivalent to Seek(handle, 0) for simple files)
	DUCKDB_API virtual void Reset(FileHandle &handle);
	DUCKDB_API virtual idx_t SeekPosition(FileHandle &handle);

	//! If FS was manually set by the user
	DUCKDB_API virtual bool IsManuallySet();
	//! Whether or not we can seek into the file
	DUCKDB_API virtual bool CanSeek();
	//! Whether or not the FS handles plain files on disk. This is relevant for certain optimizations, as random reads
	//! in a file on-disk are much cheaper than e.g. random reads in a file over the network
	DUCKDB_API virtual bool OnDiskFile(FileHandle &handle);

	DUCKDB_API virtual unique_ptr<FileHandle> OpenCompressedFile(unique_ptr<FileHandle> handle, bool write);

	//! Create a LocalFileSystem.
	DUCKDB_API static unique_ptr<FileSystem> CreateLocal();

	//! Return the name of the filesytem. Used for forming diagnosis messages.
	DUCKDB_API virtual std::string GetName() const = 0;

	//! Whether or not a file is remote or local, based only on file path
	DUCKDB_API static bool IsRemoteFile(const string &path);
	DUCKDB_API static bool IsRemoteFile(const string &path, string &extension);

	DUCKDB_API virtual void SetDisabledFileSystems(const vector<string> &names);

public:
	template <class TARGET>
	TARGET &Cast() {
		DynamicCastCheck<TARGET>(this);
		return reinterpret_cast<TARGET &>(*this);
	}

	template <class TARGET>
	const TARGET &Cast() const {
		DynamicCastCheck<TARGET>(this);
		return reinterpret_cast<const TARGET &>(*this);
	}
};

} // namespace duckdb


namespace duckdb {

#define FILE_BUFFER_SIZE 4096

class BufferedFileWriter : public WriteStream {
public:
	static constexpr FileOpenFlags DEFAULT_OPEN_FLAGS = FileFlags::FILE_FLAGS_WRITE | FileFlags::FILE_FLAGS_FILE_CREATE;

	//! Serializes to a buffer allocated by the serializer, will expand when
	//! writing past the initial threshold
	DUCKDB_API BufferedFileWriter(FileSystem &fs, const string &path, FileOpenFlags open_flags = DEFAULT_OPEN_FLAGS);

	FileSystem &fs;
	string path;
	unsafe_unique_array<data_t> data;
	idx_t offset;
	idx_t total_written;
	unique_ptr<FileHandle> handle;

public:
	DUCKDB_API void WriteData(const_data_ptr_t buffer, idx_t write_size) override;
	//! Flush all changes to the file and then close the file
	DUCKDB_API void Close();
	//! Flush all changes and fsync the file to disk
	DUCKDB_API void Sync();
	//! Flush the buffer to the file (without sync)
	DUCKDB_API void Flush();
	//! Returns the current size of the file
	DUCKDB_API idx_t GetFileSize();
	//! Truncate the size to a previous size (given that size <= GetFileSize())
	DUCKDB_API void Truncate(idx_t size);

	DUCKDB_API idx_t GetTotalWritten();
};

} // namespace duckdb


//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/function/udf_function.hpp
//
//
//===----------------------------------------------------------------------===//



//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/function/scalar_function.hpp
//
//
//===----------------------------------------------------------------------===//



//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/vector_operations/binary_executor.hpp
//
//
//===----------------------------------------------------------------------===//




//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/types/vector.hpp
//
//
//===----------------------------------------------------------------------===//



//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/bitset.hpp
//
//
//===----------------------------------------------------------------------===//



#include <bitset>

namespace duckdb {
using std::bitset;
}


//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/enums/vector_type.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

enum class VectorType : uint8_t {
	FLAT_VECTOR,       // Flat vectors represent a standard uncompressed vector
	FSST_VECTOR,       // Contains string data compressed with FSST
	CONSTANT_VECTOR,   // Constant vector represents a single constant
	DICTIONARY_VECTOR, // Dictionary vector represents a selection vector on top of another vector
	SEQUENCE_VECTOR    // Sequence vector represents a sequence with a start point and an increment
};

string VectorTypeToString(VectorType type);

} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/types/selection_vector.hpp
//
//
//===----------------------------------------------------------------------===//






//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/vector_size.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

//! The default standard vector size
#define DEFAULT_STANDARD_VECTOR_SIZE 2048U

//! The vector size used in the execution engine
#ifndef STANDARD_VECTOR_SIZE
#define STANDARD_VECTOR_SIZE DEFAULT_STANDARD_VECTOR_SIZE
#endif

#if (STANDARD_VECTOR_SIZE & (STANDARD_VECTOR_SIZE - 1) != 0)
#error The vector size must be a power of two
#endif

} // namespace duckdb


namespace duckdb {
class VectorBuffer;

struct SelectionData {
	DUCKDB_API explicit SelectionData(idx_t count);

	unsafe_unique_array<sel_t> owned_data;
};

struct SelectionVector {
	SelectionVector() : sel_vector(nullptr) {
	}
	explicit SelectionVector(sel_t *sel) {
		Initialize(sel);
	}
	explicit SelectionVector(idx_t count) {
		Initialize(count);
	}
	SelectionVector(idx_t start, idx_t count) {
		Initialize(STANDARD_VECTOR_SIZE);
		for (idx_t i = 0; i < count; i++) {
			set_index(i, start + i);
		}
	}
	SelectionVector(const SelectionVector &sel_vector) {
		Initialize(sel_vector);
	}
	explicit SelectionVector(buffer_ptr<SelectionData> data) {
		Initialize(std::move(data));
	}
	SelectionVector &operator=(SelectionVector &&other) noexcept {
		sel_vector = other.sel_vector;
		other.sel_vector = nullptr;
		selection_data = std::move(other.selection_data);
		return *this;
	}

public:
	static idx_t Inverted(const SelectionVector &src, SelectionVector &dst, idx_t source_size, idx_t count) {
		idx_t src_idx = 0;
		idx_t dst_idx = 0;
		for (idx_t i = 0; i < count; i++) {
			if (src_idx < source_size && src.get_index(src_idx) == i) {
				src_idx++;
				// This index is selected by 'src', skip it in 'dst'
				continue;
			}
			// This index does not exist in 'src', add it to the selection of 'dst'
			dst.set_index(dst_idx++, i);
		}
		return dst_idx;
	}

	void Initialize(sel_t *sel) {
		selection_data.reset();
		sel_vector = sel;
	}
	void Initialize(idx_t count = STANDARD_VECTOR_SIZE) {
		selection_data = make_shared_ptr<SelectionData>(count);
		sel_vector = selection_data->owned_data.get();
	}
	void Initialize(buffer_ptr<SelectionData> data) {
		selection_data = std::move(data);
		sel_vector = selection_data->owned_data.get();
	}
	void Initialize(const SelectionVector &other) {
		selection_data = other.selection_data;
		sel_vector = other.sel_vector;
	}

	inline void set_index(idx_t idx, idx_t loc) { // NOLINT: allow casing for legacy reasons
		sel_vector[idx] = UnsafeNumericCast<sel_t>(loc);
	}
	inline void swap(idx_t i, idx_t j) { // NOLINT: allow casing for legacy reasons
		sel_t tmp = sel_vector[i];
		sel_vector[i] = sel_vector[j];
		sel_vector[j] = tmp;
	}
	inline idx_t get_index(idx_t idx) const { // NOLINT: allow casing for legacy reasons
		return sel_vector ? sel_vector[idx] : idx;
	}
	sel_t *data() { // NOLINT: allow casing for legacy reasons
		return sel_vector;
	}
	const sel_t *data() const { // NOLINT: allow casing for legacy reasons
		return sel_vector;
	}
	buffer_ptr<SelectionData> sel_data() { // NOLINT: allow casing for legacy reasons
		return selection_data;
	}
	buffer_ptr<SelectionData> Slice(const SelectionVector &sel, idx_t count) const;

	string ToString(idx_t count = 0) const;
	void Print(idx_t count = 0) const;

	inline sel_t &operator[](idx_t index) const {
		return sel_vector[index];
	}
	inline bool IsSet() const {
		return sel_vector;
	}
	void Verify(idx_t count, idx_t vector_size) const;

private:
	sel_t *sel_vector;
	buffer_ptr<SelectionData> selection_data;
};

class OptionalSelection {
public:
	explicit OptionalSelection(SelectionVector *sel_p) {
		Initialize(sel_p);
	}
	void Initialize(SelectionVector *sel_p) {
		sel = sel_p;
		if (sel) {
			vec.Initialize(sel->data());
			sel = &vec;
		}
	}

	inline operator SelectionVector *() { // NOLINT: allow implicit conversion to SelectionVector
		return sel;
	}

	inline void Append(idx_t &count, const idx_t idx) {
		if (sel) {
			sel->set_index(count, idx);
		}
		++count;
	}

	inline void Advance(idx_t completed) {
		if (sel) {
			sel->Initialize(sel->data() + completed);
		}
	}

private:
	SelectionVector *sel;
	SelectionVector vec;
};

// Contains a selection vector, combined with a count
class ManagedSelection {
public:
	explicit inline ManagedSelection(idx_t size, bool initialize = true)
	    : initialized(initialize), size(size), internal_opt_selvec(nullptr) {
		count = 0;
		if (!initialized) {
			return;
		}
		sel_vec.Initialize(size);
		internal_opt_selvec.Initialize(&sel_vec);
	}

public:
	bool Initialized() const {
		return initialized;
	}
	void Initialize(idx_t new_size) {
		D_ASSERT(!initialized);
		this->size = new_size;
		sel_vec.Initialize(new_size);
		internal_opt_selvec.Initialize(&sel_vec);
		initialized = true;
	}

	inline idx_t operator[](idx_t index) const {
		D_ASSERT(index < size);
		return sel_vec.get_index(index);
	}
	inline bool IndexMapsToLocation(idx_t idx, idx_t location) const {
		return idx < count && sel_vec.get_index(idx) == location;
	}
	inline void Append(const idx_t idx) {
		internal_opt_selvec.Append(count, idx);
	}
	inline idx_t Count() const {
		return count;
	}
	inline idx_t Size() const {
		return size;
	}
	inline const SelectionVector &Selection() const {
		return sel_vec;
	}
	inline SelectionVector &Selection() {
		return sel_vec;
	}

private:
	bool initialized = false;
	idx_t count;
	idx_t size;
	SelectionVector sel_vec;
	OptionalSelection internal_opt_selvec;
};

} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/types/validity_mask.hpp
//
//
//===----------------------------------------------------------------------===//




//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/to_string.hpp
//
//
//===----------------------------------------------------------------------===//



namespace duckdb {
using std::to_string;
}




namespace duckdb {
struct SelectionVector;
struct ValidityMask;

template <typename V>
struct TemplatedValidityData {
	static constexpr const idx_t BITS_PER_VALUE = sizeof(V) * 8;
	static constexpr const V MAX_ENTRY = V(~V(0));

public:
	inline explicit TemplatedValidityData(idx_t count) {
		auto entry_count = EntryCount(count);
		owned_data = make_unsafe_uniq_array_uninitialized<V>(entry_count);
		for (idx_t entry_idx = 0; entry_idx < entry_count; entry_idx++) {
			owned_data[entry_idx] = MAX_ENTRY;
		}
	}
	inline TemplatedValidityData(const V *validity_mask, idx_t count) {
		D_ASSERT(validity_mask);
		auto entry_count = EntryCount(count);
		owned_data = make_unsafe_uniq_array_uninitialized<V>(entry_count);
		for (idx_t entry_idx = 0; entry_idx < entry_count; entry_idx++) {
			owned_data[entry_idx] = validity_mask[entry_idx];
		}
	}

	unsafe_unique_array<V> owned_data;

public:
	static inline idx_t EntryCount(idx_t count) {
		return (count + (BITS_PER_VALUE - 1)) / BITS_PER_VALUE;
	}
};

using validity_t = uint64_t;

struct ValidityData : TemplatedValidityData<validity_t> {
public:
	DUCKDB_API explicit ValidityData(idx_t count);
	DUCKDB_API ValidityData(const ValidityMask &original, idx_t count);
};

//! Type used for validity masks
template <typename V>
struct TemplatedValidityMask {
	using ValidityBuffer = TemplatedValidityData<V>;

public:
	static constexpr const idx_t BITS_PER_VALUE = ValidityBuffer::BITS_PER_VALUE;
	static constexpr const idx_t STANDARD_ENTRY_COUNT = (STANDARD_VECTOR_SIZE + (BITS_PER_VALUE - 1)) / BITS_PER_VALUE;
	static constexpr const idx_t STANDARD_MASK_SIZE = STANDARD_ENTRY_COUNT * sizeof(validity_t);

public:
	inline TemplatedValidityMask() : validity_mask(nullptr), target_count(STANDARD_VECTOR_SIZE) {
	}
	inline explicit TemplatedValidityMask(idx_t target_count) : validity_mask(nullptr), target_count(target_count) {
	}
	inline explicit TemplatedValidityMask(V *ptr) : validity_mask(ptr), target_count(STANDARD_VECTOR_SIZE) {
	}
	inline TemplatedValidityMask(const TemplatedValidityMask &original, idx_t count) {
		Copy(original, count);
	}

	static inline idx_t ValidityMaskSize(idx_t count = STANDARD_VECTOR_SIZE) {
		return ValidityBuffer::EntryCount(count) * sizeof(V);
	}
	inline bool AllValid() const {
		return !validity_mask;
	}
	inline bool CheckAllValid(idx_t count) const {
		return CountValid(count) == count;
	}

	inline bool CheckAllValid(idx_t to, idx_t from) const {
		if (AllValid()) {
			return true;
		}
		for (idx_t i = from; i < to; i++) {
			if (!RowIsValid(i)) {
				return false;
			}
		}
		return true;
	}

	idx_t CountValid(const idx_t count) const {
		if (AllValid() || count == 0) {
			return count;
		}

		idx_t valid = 0;
		const auto entry_count = EntryCount(count);
		for (idx_t entry_idx = 0; entry_idx < entry_count;) {
			auto entry = GetValidityEntry(entry_idx++);
			// Handle ragged end (if not exactly multiple of BITS_PER_VALUE)
			if (entry_idx == entry_count && count % BITS_PER_VALUE != 0) {
				idx_t idx_in_entry;
				GetEntryIndex(count, entry_idx, idx_in_entry);
				for (idx_t i = 0; i < idx_in_entry; ++i) {
					valid += idx_t(RowIsValid(entry, i));
				}
				break;
			}

			// Handle all set
			if (AllValid(entry)) {
				valid += BITS_PER_VALUE;
				continue;
			}

			// Count partial entry (Kernighan's algorithm)
			while (entry) {
				entry &= (entry - 1);
				++valid;
			}
		}

		return valid;
	}

	inline V *GetData() const {
		return validity_mask;
	}
	inline void Reset(idx_t target_count_p = STANDARD_VECTOR_SIZE) {
		validity_mask = nullptr;
		validity_data.reset();
		target_count = target_count_p;
	}

	static inline idx_t EntryCount(idx_t count) {
		return ValidityBuffer::EntryCount(count);
	}
	inline V GetValidityEntry(idx_t entry_idx) const {
		if (!validity_mask) {
			return ValidityBuffer::MAX_ENTRY;
		}
		return GetValidityEntryUnsafe(entry_idx);
	}
	inline V &GetValidityEntryUnsafe(idx_t entry_idx) const {
		return validity_mask[entry_idx];
	}
	static inline bool AllValid(V entry) {
		return entry == ValidityBuffer::MAX_ENTRY;
	}
	static inline bool NoneValid(V entry) {
		return entry == 0;
	}
	static inline bool RowIsValid(const V &entry, const idx_t &idx_in_entry) {
		return entry & (V(1) << V(idx_in_entry));
	}
	static inline void GetEntryIndex(idx_t row_idx, idx_t &entry_idx, idx_t &idx_in_entry) {
		entry_idx = row_idx / BITS_PER_VALUE;
		idx_in_entry = row_idx % BITS_PER_VALUE;
	}
	//! Get an entry that has first-n bits set as valid and rest set as invalid
	static inline V EntryWithValidBits(idx_t n) {
		if (n == 0) {
			return V(0);
		}
		return ValidityBuffer::MAX_ENTRY >> (BITS_PER_VALUE - n);
	}
	static inline idx_t SizeInBytes(idx_t n) {
		return (n + BITS_PER_VALUE - 1) / BITS_PER_VALUE;
	}

	//! RowIsValidUnsafe should only be used if AllValid() is false: it achieves the same as RowIsValid but skips a
	//! not-null check
	inline bool RowIsValidUnsafe(idx_t row_idx) const {
		D_ASSERT(validity_mask);
		idx_t entry_idx, idx_in_entry;
		GetEntryIndex(row_idx, entry_idx, idx_in_entry);
		auto entry = GetValidityEntry(entry_idx);
		return RowIsValid(entry, idx_in_entry);
	}

	//! Returns true if a row is valid (i.e. not null), false otherwise
	inline bool RowIsValid(idx_t row_idx) const {
		if (!validity_mask) {
			return true;
		}
		return RowIsValidUnsafe(row_idx);
	}

	//! Same as SetValid, but skips a null check on validity_mask
	inline void SetValidUnsafe(idx_t row_idx) {
		D_ASSERT(validity_mask);
		idx_t entry_idx, idx_in_entry;
		GetEntryIndex(row_idx, entry_idx, idx_in_entry);
		validity_mask[entry_idx] |= (V(1) << V(idx_in_entry));
	}

	//! Marks the entry at the specified row index as valid (i.e. not-null)
	inline void SetValid(idx_t row_idx) {
		if (!validity_mask) {
			// if AllValid() we don't need to do anything
			// the row is already valid
			return;
		}
		SetValidUnsafe(row_idx);
	}

	//! Marks the bit at the specified entry as invalid (i.e. null)
	inline void SetInvalidUnsafe(idx_t entry_idx, idx_t idx_in_entry) {
		D_ASSERT(validity_mask);
		validity_mask[entry_idx] &= ~(V(1) << V(idx_in_entry));
	}

	//! Marks the bit at the specified row index as invalid (i.e. null)
	inline void SetInvalidUnsafe(idx_t row_idx) {
		idx_t entry_idx, idx_in_entry;
		GetEntryIndex(row_idx, entry_idx, idx_in_entry);
		SetInvalidUnsafe(entry_idx, idx_in_entry);
	}

	//! Marks the entry at the specified row index as invalid (i.e. null)
	inline void SetInvalid(idx_t row_idx) {
		if (!validity_mask) {
			D_ASSERT(row_idx <= target_count);
			Initialize(target_count);
		}
		SetInvalidUnsafe(row_idx);
	}

	//! Mark the entry at the specified index as either valid or invalid (non-null or null)
	inline void Set(idx_t row_idx, bool valid) {
		if (valid) {
			SetValid(row_idx);
		} else {
			SetInvalid(row_idx);
		}
	}

	//! Ensure the validity mask is writable, allocating space if it is not initialized
	inline void EnsureWritable() {
		if (!validity_mask) {
			Initialize();
		}
	}

	//! Marks exactly "count" bits in the validity mask as invalid (null)
	inline void SetAllInvalid(idx_t count) {
		EnsureWritable();
		if (count == 0) {
			return;
		}
		auto last_entry_index = ValidityBuffer::EntryCount(count) - 1;
		for (idx_t i = 0; i < last_entry_index; i++) {
			validity_mask[i] = 0;
		}
		auto last_entry_bits = count % BITS_PER_VALUE;
		validity_mask[last_entry_index] =
		    (last_entry_bits == 0) ? 0 : static_cast<V>(ValidityBuffer::MAX_ENTRY << (last_entry_bits));
	}

	//! Marks exactly "count" bits in the validity mask as valid (not null)
	inline void SetAllValid(idx_t count) {
		EnsureWritable();
		if (count == 0) {
			return;
		}
		auto last_entry_index = ValidityBuffer::EntryCount(count) - 1;
		for (idx_t i = 0; i < last_entry_index; i++) {
			validity_mask[i] = ValidityBuffer::MAX_ENTRY;
		}
		auto last_entry_bits = count % BITS_PER_VALUE;
		validity_mask[last_entry_index] |= (last_entry_bits == 0)
		                                       ? ValidityBuffer::MAX_ENTRY
		                                       : ~static_cast<V>(ValidityBuffer::MAX_ENTRY << (last_entry_bits));
	}

	inline bool IsMaskSet() const {
		if (validity_mask) {
			return true;
		}
		return false;
	}

public:
	inline void Initialize(validity_t *validity) {
		validity_data.reset();
		validity_mask = validity;
	}
	inline void Initialize(const TemplatedValidityMask &other) {
		validity_mask = other.validity_mask;
		validity_data = other.validity_data;
		target_count = other.target_count;
	}
	inline void Initialize(idx_t count) {
		target_count = count;
		validity_data = make_buffer<ValidityBuffer>(count);
		validity_mask = validity_data->owned_data.get();
	}
	inline void Initialize() {
		Initialize(target_count);
	}
	inline void Copy(const TemplatedValidityMask &other, idx_t count) {
		target_count = count;
		if (other.AllValid()) {
			validity_data = nullptr;
			validity_mask = nullptr;
		} else {
			validity_data = make_buffer<ValidityBuffer>(other.validity_mask, count);
			validity_mask = validity_data->owned_data.get();
		}
	}

protected:
	V *validity_mask;
	buffer_ptr<ValidityBuffer> validity_data;
	// The size to initialize the validity mask to when/if the mask is lazily initialized
	idx_t target_count;
};

struct ValidityMask : public TemplatedValidityMask<validity_t> {
public:
	inline ValidityMask() : TemplatedValidityMask(nullptr) {
	}
	inline explicit ValidityMask(idx_t target_count) : TemplatedValidityMask(target_count) {
	}
	inline explicit ValidityMask(validity_t *ptr) : TemplatedValidityMask(ptr) {
	}
	inline ValidityMask(const ValidityMask &original, idx_t count) : TemplatedValidityMask(original, count) {
	}

public:
	DUCKDB_API void Resize(idx_t old_size, idx_t new_size);
	DUCKDB_API idx_t TargetCount() const;
	DUCKDB_API void SliceInPlace(const ValidityMask &other, idx_t target_offset, idx_t source_offset, idx_t count);
	DUCKDB_API void Slice(const ValidityMask &other, idx_t source_offset, idx_t count);
	DUCKDB_API void CopySel(const ValidityMask &other, const SelectionVector &sel, idx_t source_offset,
	                        idx_t target_offset, idx_t count);
	DUCKDB_API void Combine(const ValidityMask &other, idx_t count);
	DUCKDB_API string ToString(idx_t count) const;

	DUCKDB_API static bool IsAligned(idx_t count);

	void Write(WriteStream &writer, idx_t count);
	void Read(ReadStream &reader, idx_t count);
};

//===--------------------------------------------------------------------===//
// ValidityArray
//===--------------------------------------------------------------------===//
struct ValidityArray {
	inline ValidityArray() {
	}

	inline bool AllValid() const {
		return !validity_mask;
	}

	inline void Initialize(idx_t count, bool initial = true) {
		target_count = count;
		validity_data = make_unsafe_uniq_array<bool>(count);
		validity_mask = validity_data.get();
		memset(validity_mask, initial, sizeof(bool) * count);
	}

	//! RowIsValidUnsafe should only be used if AllValid() is false: it achieves the same as RowIsValid but skips a
	//! not-null check
	inline bool RowIsValidUnsafe(idx_t row_idx) const {
		D_ASSERT(validity_mask);
		return validity_mask[row_idx];
	}

	//! Returns true if a row is valid (i.e. not null), false otherwise
	inline bool RowIsValid(idx_t row_idx) const {
		if (!validity_mask) {
			return true;
		}
		return RowIsValidUnsafe(row_idx);
	}

	//! Same as SetValid, but skips a null check on validity_mask
	inline void SetValidUnsafe(idx_t row_idx) {
		D_ASSERT(validity_mask);
		validity_mask[row_idx] = true;
	}

	//! Marks the entry at the specified row index as valid (i.e. not-null)
	inline void SetValid(idx_t row_idx) {
		if (!validity_mask) {
			// if AllValid() we don't need to do anything
			// the row is already valid
			return;
		}

		SetValidUnsafe(row_idx);
	}

	inline void Pack(ValidityMask &mask, const idx_t count) const {
		if (AllValid()) {
			mask.Reset();
			return;
		}
		mask.Initialize(count);

		const auto entire_entries = count / ValidityMask::BITS_PER_VALUE;
		const auto ragged = count % ValidityMask::BITS_PER_VALUE;
		auto bits = mask.GetData();
		idx_t row_idx = 0;
		for (idx_t i = 0; i < entire_entries; ++i) {
			validity_t entry = 0;
			for (idx_t j = 0; j < ValidityMask::BITS_PER_VALUE; ++j) {
				if (RowIsValidUnsafe(row_idx++)) {
					entry |= validity_t(1) << j;
				}
			}
			*bits++ = entry;
		}
		if (ragged) {
			validity_t entry = 0;
			for (idx_t j = 0; j < ragged; ++j) {
				if (RowIsValidUnsafe(row_idx++)) {
					entry |= validity_t(1) << j;
				}
			}
			*bits++ = entry;
		}
	}

	bool *validity_mask = nullptr;
	unsafe_unique_array<bool> validity_data;
	idx_t target_count = 0;
};

} // namespace duckdb


//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/types/vector_buffer.hpp
//
//
//===----------------------------------------------------------------------===//





//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/types/string_heap.hpp
//
//
//===----------------------------------------------------------------------===//





//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/storage/arena_allocator.hpp
//
//
//===----------------------------------------------------------------------===//



//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/allocator.hpp
//
//
//===----------------------------------------------------------------------===//









namespace duckdb {
class Allocator;
class AttachedDatabase;
class ClientContext;
class DatabaseInstance;
class ExecutionContext;
class ThreadContext;

struct AllocatorDebugInfo;

enum class AllocatorFreeType { REQUIRES_FREE, DOES_NOT_REQUIRE_FREE };

struct PrivateAllocatorData {
	PrivateAllocatorData();
	virtual ~PrivateAllocatorData();

	AllocatorFreeType free_type = AllocatorFreeType::REQUIRES_FREE;
	unique_ptr<AllocatorDebugInfo> debug_info;

	template <class TARGET>
	TARGET &Cast() {
		DynamicCastCheck<TARGET>(this);
		return reinterpret_cast<TARGET &>(*this);
	}
	template <class TARGET>
	const TARGET &Cast() const {
		DynamicCastCheck<TARGET>(this);
		return reinterpret_cast<const TARGET &>(*this);
	}
};

typedef data_ptr_t (*allocate_function_ptr_t)(PrivateAllocatorData *private_data, idx_t size);
typedef void (*free_function_ptr_t)(PrivateAllocatorData *private_data, data_ptr_t pointer, idx_t size);
typedef data_ptr_t (*reallocate_function_ptr_t)(PrivateAllocatorData *private_data, data_ptr_t pointer, idx_t old_size,
                                                idx_t size);

class AllocatedData {
public:
	DUCKDB_API AllocatedData();
	DUCKDB_API AllocatedData(Allocator &allocator, data_ptr_t pointer, idx_t allocated_size);
	DUCKDB_API ~AllocatedData();
	// disable copy constructors
	AllocatedData(const AllocatedData &other) = delete;
	AllocatedData &operator=(const AllocatedData &) = delete;
	//! enable move constructors
	DUCKDB_API AllocatedData(AllocatedData &&other) noexcept;
	DUCKDB_API AllocatedData &operator=(AllocatedData &&) noexcept;

	data_ptr_t get() { // NOLINT: matching std style
		return pointer;
	}
	const_data_ptr_t get() const { // NOLINT: matching std style
		return pointer;
	}
	idx_t GetSize() const {
		return allocated_size;
	}
	bool IsSet() {
		return pointer;
	}
	void Reset();

private:
	optional_ptr<Allocator> allocator;
	data_ptr_t pointer;
	idx_t allocated_size;
};

class Allocator {
	// 281TB ought to be enough for anybody
	static constexpr const idx_t MAXIMUM_ALLOC_SIZE = 281474976710656ULL;

public:
	DUCKDB_API Allocator();
	DUCKDB_API Allocator(allocate_function_ptr_t allocate_function_p, free_function_ptr_t free_function_p,
	                     reallocate_function_ptr_t reallocate_function_p,
	                     unique_ptr<PrivateAllocatorData> private_data);
	Allocator &operator=(Allocator &&allocator) noexcept = delete;
	DUCKDB_API ~Allocator();

	DUCKDB_API data_ptr_t AllocateData(idx_t size);
	DUCKDB_API void FreeData(data_ptr_t pointer, idx_t size);
	DUCKDB_API data_ptr_t ReallocateData(data_ptr_t pointer, idx_t old_size, idx_t new_size);

	AllocatedData Allocate(idx_t size) {
		return AllocatedData(*this, AllocateData(size), size);
	}
	static data_ptr_t DefaultAllocate(PrivateAllocatorData *private_data, idx_t size);
	static void DefaultFree(PrivateAllocatorData *private_data, data_ptr_t pointer, idx_t size);
	static data_ptr_t DefaultReallocate(PrivateAllocatorData *private_data, data_ptr_t pointer, idx_t old_size,
	                                    idx_t size);
	static Allocator &Get(ClientContext &context);
	static Allocator &Get(DatabaseInstance &db);
	static Allocator &Get(AttachedDatabase &db);

	PrivateAllocatorData *GetPrivateData() {
		return private_data.get();
	}

	DUCKDB_API static Allocator &DefaultAllocator();
	DUCKDB_API static shared_ptr<Allocator> &DefaultAllocatorReference();

	static bool SupportsFlush();
	static optional_idx DecayDelay();
	static void ThreadFlush(bool allocator_background_threads, idx_t threshold, idx_t thread_count);
	static void ThreadIdle();
	static void FlushAll();
	static void SetBackgroundThreads(bool enable);

private:
	allocate_function_ptr_t allocate_function;
	free_function_ptr_t free_function;
	reallocate_function_ptr_t reallocate_function;

	unique_ptr<PrivateAllocatorData> private_data;
};

template <class T>
T *AllocateArray(idx_t size) {
	return (T *)Allocator::DefaultAllocator().AllocateData(size * sizeof(T));
}

template <class T>
void DeleteArray(T *ptr, idx_t size) {
	Allocator::DefaultAllocator().FreeData(data_ptr_cast(ptr), size * sizeof(T));
}

template <typename T, typename... ARGS>
T *AllocateObject(ARGS &&... args) {
	auto data = Allocator::DefaultAllocator().AllocateData(sizeof(T));
	return new (data) T(std::forward<ARGS>(args)...);
}

template <typename T>
void DestroyObject(T *ptr) {
	ptr->~T();
	Allocator::DefaultAllocator().FreeData(data_ptr_cast(ptr), sizeof(T));
}

//! The BufferAllocator is a wrapper around the global allocator class that sends any allocations made through the
//! buffer manager. This makes the buffer manager aware of the memory usage, allowing it to potentially free
//! other blocks to make space in memory.
//! Note that there is a cost to doing so (several atomic operations will be performed on allocation/free).
//! As such this class should be used primarily for larger allocations.
struct BufferAllocator {
	DUCKDB_API static Allocator &Get(ClientContext &context);
	DUCKDB_API static Allocator &Get(DatabaseInstance &db);
	DUCKDB_API static Allocator &Get(AttachedDatabase &db);
};

} // namespace duckdb



namespace duckdb {

struct ArenaChunk {
	ArenaChunk(Allocator &allocator, idx_t size);
	~ArenaChunk();

	AllocatedData data;
	idx_t current_position;
	idx_t maximum_size;
	unsafe_unique_ptr<ArenaChunk> next;
	ArenaChunk *prev;
};

class ArenaAllocator {
	static constexpr const idx_t ARENA_ALLOCATOR_INITIAL_CAPACITY = 2048;
	static constexpr const idx_t ARENA_ALLOCATOR_MAX_CAPACITY = 1ULL << 24ULL; // 16MB

public:
	DUCKDB_API explicit ArenaAllocator(Allocator &allocator, idx_t initial_capacity = ARENA_ALLOCATOR_INITIAL_CAPACITY);
	DUCKDB_API ~ArenaAllocator();

	DUCKDB_API data_ptr_t Allocate(idx_t size);
	DUCKDB_API data_ptr_t Reallocate(data_ptr_t pointer, idx_t old_size, idx_t size);

	DUCKDB_API data_ptr_t AllocateAligned(idx_t size);
	DUCKDB_API data_ptr_t ReallocateAligned(data_ptr_t pointer, idx_t old_size, idx_t size);

	//! Increment the internal cursor (if required) so the next allocation is guaranteed to be aligned to 8 bytes
	DUCKDB_API void AlignNext();

	//! Resets the current head and destroys all previous arena chunks
	DUCKDB_API void Reset();
	DUCKDB_API void Destroy();
	DUCKDB_API void Move(ArenaAllocator &allocator);

	DUCKDB_API ArenaChunk *GetHead();
	DUCKDB_API ArenaChunk *GetTail();

	DUCKDB_API bool IsEmpty() const;
	//! Get the total *used* size (not cached)
	DUCKDB_API idx_t SizeInBytes() const;
	//! Get the currently allocated size in bytes (cached, read from "allocated_size")
	DUCKDB_API idx_t AllocationSize() const;

	//! Returns an "Allocator" wrapper for this arena allocator
	Allocator &GetAllocator() {
		return arena_allocator;
	}

private:
	//! Internal allocator that is used by the arena allocator
	Allocator &allocator;
	idx_t initial_capacity;
	unsafe_unique_ptr<ArenaChunk> head;
	ArenaChunk *tail;
	//! An allocator wrapper using this arena allocator
	Allocator arena_allocator;
	//! The total allocated size
	idx_t allocated_size = 0;
};

} // namespace duckdb


namespace duckdb {
//! A string heap is the owner of a set of strings, strings can be inserted into
//! it On every insert, a pointer to the inserted string is returned The
//! returned pointer will remain valid until the StringHeap is destroyed
class StringHeap {
public:
	DUCKDB_API explicit StringHeap(Allocator &allocator = Allocator::DefaultAllocator());

	DUCKDB_API void Destroy();
	DUCKDB_API void Move(StringHeap &other);

	//! Add a string to the string heap, returns a pointer to the string
	DUCKDB_API string_t AddString(const char *data, idx_t len);
	//! Add a string to the string heap, returns a pointer to the string
	DUCKDB_API string_t AddString(const char *data);
	//! Add a string to the string heap, returns a pointer to the string
	DUCKDB_API string_t AddString(const string &data);
	//! Add a string to the string heap, returns a pointer to the string
	DUCKDB_API string_t AddString(const string_t &data);
	//! Add a blob to the string heap; blobs can be non-valid UTF8
	DUCKDB_API string_t AddBlob(const string_t &data);
	//! Add a blob to the string heap; blobs can be non-valid UTF8
	DUCKDB_API string_t AddBlob(const char *data, idx_t len);
	//! Allocates space for an empty string of size "len" on the heap
	DUCKDB_API string_t EmptyString(idx_t len);

	//! Size of strings
	DUCKDB_API idx_t SizeInBytes() const;
	//! Total allocation size (cached)
	DUCKDB_API idx_t AllocationSize() const;

private:
	ArenaAllocator allocator;
};

} // namespace duckdb


//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/storage/buffer/buffer_handle.hpp
//
//
//===----------------------------------------------------------------------===//



//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/storage/storage_info.hpp
//
//
//===----------------------------------------------------------------------===//








namespace duckdb {
struct FileHandle;

//! The standard row group size
#define STANDARD_ROW_GROUPS_SIZE 122880
//! The definition of an invalid block
#define INVALID_BLOCK (-1)
//! The maximum block id is 2^62
#define MAXIMUM_BLOCK 4611686018427388000LL

//! The default block allocation size.
#define DEFAULT_BLOCK_ALLOC_SIZE 262144ULL
//! The configurable block allocation size.
#ifndef DUCKDB_BLOCK_ALLOC_SIZE
#define DUCKDB_BLOCK_ALLOC_SIZE DEFAULT_BLOCK_ALLOC_SIZE
#endif

using block_id_t = int64_t;

struct Storage {
	//! The size of a hard disk sector, only really needed for Direct IO
	constexpr static idx_t SECTOR_SIZE = 4096U;
	//! The size of the headers. This should be small and written more or less atomically by the hard disk. We default
	//! to the page size, which is 4KB. (1 << 12)
	constexpr static idx_t FILE_HEADER_SIZE = 4096U;
	//! The number of rows per row group (must be a multiple of the vector size)
	constexpr static const idx_t ROW_GROUP_SIZE = STANDARD_ROW_GROUPS_SIZE;
	//! The number of vectors per row group
	constexpr static const idx_t ROW_GROUP_VECTOR_COUNT = ROW_GROUP_SIZE / STANDARD_VECTOR_SIZE;

	//! The minimum block allocation size. This is the minimum size we test in our nightly tests.
	constexpr static idx_t MIN_BLOCK_ALLOC_SIZE = 16384ULL;
	//! The maximum block allocation size. This is the maximum size currently supported by duckdb.
	constexpr static idx_t MAX_BLOCK_ALLOC_SIZE = 262144ULL;
	//! The default block header size for blocks written to storage.
	constexpr static idx_t DEFAULT_BLOCK_HEADER_SIZE = sizeof(idx_t);
	//! The default block size.
	constexpr static idx_t DEFAULT_BLOCK_SIZE = DEFAULT_BLOCK_ALLOC_SIZE - DEFAULT_BLOCK_HEADER_SIZE;

	//! Ensures that a user-provided block allocation size matches all requirements.
	static void VerifyBlockAllocSize(const idx_t block_alloc_size);
};

//! The version number of the database storage format
extern const uint64_t VERSION_NUMBER;
string GetDuckDBVersion(idx_t version_number);
optional_idx GetStorageVersion(const char *version_string);
optional_idx GetSerializationVersion(const char *version_string);
vector<string> GetSerializationCandidates();

//! The MainHeader is the first header in the storage file. The MainHeader is typically written only once for a database
//! file.
struct MainHeader {
	static constexpr idx_t MAX_VERSION_SIZE = 32;
	static constexpr idx_t MAGIC_BYTE_SIZE = 4;
	static constexpr idx_t MAGIC_BYTE_OFFSET = Storage::DEFAULT_BLOCK_HEADER_SIZE;
	static constexpr idx_t FLAG_COUNT = 4;
	//! The magic bytes in front of the file should be "DUCK"
	static const char MAGIC_BYTES[];
	//! The version of the database
	uint64_t version_number;
	//! The set of flags used by the database
	uint64_t flags[FLAG_COUNT];
	static void CheckMagicBytes(FileHandle &handle);

	string LibraryGitDesc() {
		return string(char_ptr_cast(library_git_desc), 0, MAX_VERSION_SIZE);
	}
	string LibraryGitHash() {
		return string(char_ptr_cast(library_git_hash), 0, MAX_VERSION_SIZE);
	}

	void Write(WriteStream &ser);
	static MainHeader Read(ReadStream &source);

private:
	data_t library_git_desc[MAX_VERSION_SIZE];
	data_t library_git_hash[MAX_VERSION_SIZE];
};

//! The DatabaseHeader contains information about the current state of the database. Every storage file has two
//! DatabaseHeaders. On startup, the DatabaseHeader with the highest iteration count is used as the active header. When
//! a checkpoint is performed, the active DatabaseHeader is switched by increasing the iteration count of the
//! DatabaseHeader.
struct DatabaseHeader {
	//! The iteration count, increases by 1 every time the storage is checkpointed.
	uint64_t iteration;
	//! A pointer to the initial meta block
	idx_t meta_block;
	//! A pointer to the block containing the free list
	idx_t free_list;
	//! The number of blocks that is in the file as of this database header. If the file is larger than BLOCK_SIZE *
	//! block_count any blocks appearing AFTER block_count are implicitly part of the free_list.
	uint64_t block_count;
	//! The allocation size of blocks in this database file. Defaults to default_block_alloc_size (DBConfig).
	idx_t block_alloc_size;
	//! The vector size of the database file
	idx_t vector_size;

	void Write(WriteStream &ser);
	static DatabaseHeader Read(ReadStream &source);
};

//! Detect mismatching constant values when compiling

#if (STANDARD_ROW_GROUPS_SIZE % STANDARD_VECTOR_SIZE != 0)
#error The row group size must be a multiple of the vector size
#endif
#if (STANDARD_ROW_GROUPS_SIZE < STANDARD_VECTOR_SIZE)
#error Row groups must be able to hold at least one vector
#endif
#if (DEFAULT_BLOCK_ALLOC_SIZE & (DEFAULT_BLOCK_ALLOC_SIZE - 1) != 0)
#error The default block allocation size must be a power of two
#endif
#if (DUCKDB_BLOCK_ALLOC_SIZE & (DUCKDB_BLOCK_ALLOC_SIZE - 1) != 0)
#error The duckdb block allocation size must be a power of two
#endif

} // namespace duckdb



namespace duckdb {
class BlockHandle;
class FileBuffer;

class BufferHandle {
public:
	DUCKDB_API BufferHandle();
	DUCKDB_API explicit BufferHandle(shared_ptr<BlockHandle> handle);
	DUCKDB_API ~BufferHandle();
	// disable copy constructors
	BufferHandle(const BufferHandle &other) = delete;
	BufferHandle &operator=(const BufferHandle &) = delete;
	//! enable move constructors
	DUCKDB_API BufferHandle(BufferHandle &&other) noexcept;
	DUCKDB_API BufferHandle &operator=(BufferHandle &&) noexcept;

public:
	//! Returns whether or not the BufferHandle is valid.
	DUCKDB_API bool IsValid() const;
	//! Returns a pointer to the buffer data. Handle must be valid.
	inline data_ptr_t Ptr() const {
		D_ASSERT(IsValid());
		return node->buffer;
	}
	//! Returns a pointer to the buffer data. Handle must be valid.
	inline data_ptr_t Ptr() {
		D_ASSERT(IsValid());
		return node->buffer;
	}
	//! Gets the underlying file buffer. Handle must be valid.
	DUCKDB_API FileBuffer &GetFileBuffer();
	//! Destroys the buffer handle
	DUCKDB_API void Destroy();

	const shared_ptr<BlockHandle> &GetBlockHandle() const {
		return handle;
	}

private:
	//! The block handle
	shared_ptr<BlockHandle> handle;
	//! The managed buffer node
	optional_ptr<FileBuffer> node;
};

} // namespace duckdb


namespace duckdb {

class BufferHandle;
class VectorBuffer;
class Vector;

enum class VectorBufferType : uint8_t {
	STANDARD_BUFFER,     // standard buffer, holds a single array of data
	DICTIONARY_BUFFER,   // dictionary buffer, holds a selection vector
	VECTOR_CHILD_BUFFER, // vector child buffer: holds another vector
	STRING_BUFFER,       // string buffer, holds a string heap
	FSST_BUFFER,         // fsst compressed string buffer, holds a string heap, fsst symbol table and a string count
	STRUCT_BUFFER,       // struct buffer, holds a ordered mapping from name to child vector
	LIST_BUFFER,         // list buffer, holds a single flatvector child
	MANAGED_BUFFER,      // managed buffer, holds a buffer managed by the buffermanager
	OPAQUE_BUFFER,       // opaque buffer, can be created for example by the parquet reader
	ARRAY_BUFFER         // array buffer, holds a single flatvector child
};

enum class VectorAuxiliaryDataType : uint8_t {
	ARROW_AUXILIARY // Holds Arrow Chunks that this vector depends on
};

struct VectorAuxiliaryData {
	explicit VectorAuxiliaryData(VectorAuxiliaryDataType type_p)
	    : type(type_p) {

	      };
	VectorAuxiliaryDataType type;

	virtual ~VectorAuxiliaryData() {
	}

public:
	template <class TARGET>
	TARGET &Cast() {
		if (type != TARGET::TYPE) {
			throw InternalException("Failed to cast vector auxiliary data to type - type mismatch");
		}
		return reinterpret_cast<TARGET &>(*this);
	}

	template <class TARGET>
	const TARGET &Cast() const {
		if (type != TARGET::TYPE) {
			throw InternalException("Failed to cast vector auxiliary data to type - type mismatch");
		}
		return reinterpret_cast<const TARGET &>(*this);
	}
};

//! The VectorBuffer is a class used by the vector to hold its data
class VectorBuffer {
public:
	explicit VectorBuffer(VectorBufferType type) : buffer_type(type) {
	}
	explicit VectorBuffer(idx_t data_size) : buffer_type(VectorBufferType::STANDARD_BUFFER) {
		if (data_size > 0) {
			data = make_unsafe_uniq_array_uninitialized<data_t>(data_size);
		}
	}
	explicit VectorBuffer(unsafe_unique_array<data_t> data_p)
	    : buffer_type(VectorBufferType::STANDARD_BUFFER), data(std::move(data_p)) {
	}
	virtual ~VectorBuffer() {
	}
	VectorBuffer() {
	}

public:
	data_ptr_t GetData() {
		return data.get();
	}

	void SetData(unsafe_unique_array<data_t> new_data) {
		data = std::move(new_data);
	}

	VectorAuxiliaryData *GetAuxiliaryData() {
		return aux_data.get();
	}

	void SetAuxiliaryData(unique_ptr<VectorAuxiliaryData> aux_data_p) {
		aux_data = std::move(aux_data_p);
	}

	void MoveAuxiliaryData(VectorBuffer &source_buffer) {
		SetAuxiliaryData(std::move(source_buffer.aux_data));
	}

	static buffer_ptr<VectorBuffer> CreateStandardVector(PhysicalType type, idx_t capacity = STANDARD_VECTOR_SIZE);
	static buffer_ptr<VectorBuffer> CreateConstantVector(PhysicalType type);
	static buffer_ptr<VectorBuffer> CreateConstantVector(const LogicalType &logical_type);
	static buffer_ptr<VectorBuffer> CreateStandardVector(const LogicalType &logical_type,
	                                                     idx_t capacity = STANDARD_VECTOR_SIZE);

	inline VectorBufferType GetBufferType() const {
		return buffer_type;
	}

	inline VectorAuxiliaryDataType GetAuxiliaryDataType() const {
		return aux_data->type;
	}

protected:
	VectorBufferType buffer_type;
	unique_ptr<VectorAuxiliaryData> aux_data;
	unsafe_unique_array<data_t> data;

public:
	template <class TARGET>
	TARGET &Cast() {
		DynamicCastCheck<TARGET>(this);
		return reinterpret_cast<TARGET &>(*this);
	}
	template <class TARGET>
	const TARGET &Cast() const {
		DynamicCastCheck<TARGET>(this);
		return reinterpret_cast<const TARGET &>(*this);
	}
};

//! The DictionaryBuffer holds a selection vector
class DictionaryBuffer : public VectorBuffer {
public:
	explicit DictionaryBuffer(const SelectionVector &sel)
	    : VectorBuffer(VectorBufferType::DICTIONARY_BUFFER), sel_vector(sel) {
	}
	explicit DictionaryBuffer(buffer_ptr<SelectionData> data)
	    : VectorBuffer(VectorBufferType::DICTIONARY_BUFFER), sel_vector(std::move(data)) {
	}
	explicit DictionaryBuffer(idx_t count = STANDARD_VECTOR_SIZE)
	    : VectorBuffer(VectorBufferType::DICTIONARY_BUFFER), sel_vector(count) {
	}

public:
	const SelectionVector &GetSelVector() const {
		return sel_vector;
	}
	SelectionVector &GetSelVector() {
		return sel_vector;
	}
	void SetSelVector(const SelectionVector &vector) {
		this->sel_vector.Initialize(vector);
	}

private:
	SelectionVector sel_vector;
};

class VectorStringBuffer : public VectorBuffer {
public:
	VectorStringBuffer();
	explicit VectorStringBuffer(VectorBufferType type);

public:
	string_t AddString(const char *data, idx_t len) {
		return heap.AddString(data, len);
	}
	string_t AddString(string_t data) {
		return heap.AddString(data);
	}
	string_t AddBlob(string_t data) {
		return heap.AddBlob(data.GetData(), data.GetSize());
	}
	string_t EmptyString(idx_t len) {
		return heap.EmptyString(len);
	}

	void AddHeapReference(buffer_ptr<VectorBuffer> heap) {
		references.push_back(std::move(heap));
	}

private:
	//! The string heap of this buffer
	StringHeap heap;
	// References to additional vector buffers referenced by this string buffer
	vector<buffer_ptr<VectorBuffer>> references;
};

class VectorFSSTStringBuffer : public VectorStringBuffer {
public:
	VectorFSSTStringBuffer();

public:
	void AddDecoder(buffer_ptr<void> &duckdb_fsst_decoder_p, const idx_t string_block_limit) {
		duckdb_fsst_decoder = duckdb_fsst_decoder_p;
		decompress_buffer.resize(string_block_limit + 1);
	}
	void *GetDecoder() {
		return duckdb_fsst_decoder.get();
	}
	vector<unsigned char> &GetDecompressBuffer() {
		return decompress_buffer;
	}
	void SetCount(idx_t count) {
		total_string_count = count;
	}
	idx_t GetCount() {
		return total_string_count;
	}

private:
	buffer_ptr<void> duckdb_fsst_decoder;
	idx_t total_string_count = 0;
	vector<unsigned char> decompress_buffer;
};

class VectorStructBuffer : public VectorBuffer {
public:
	VectorStructBuffer();
	explicit VectorStructBuffer(const LogicalType &struct_type, idx_t capacity = STANDARD_VECTOR_SIZE);
	VectorStructBuffer(Vector &other, const SelectionVector &sel, idx_t count);
	~VectorStructBuffer() override;

public:
	const vector<unique_ptr<Vector>> &GetChildren() const {
		return children;
	}
	vector<unique_ptr<Vector>> &GetChildren() {
		return children;
	}

private:
	//! child vectors used for nested data
	vector<unique_ptr<Vector>> children;
};

class VectorListBuffer : public VectorBuffer {
public:
	explicit VectorListBuffer(unique_ptr<Vector> vector, idx_t initial_capacity = STANDARD_VECTOR_SIZE);
	explicit VectorListBuffer(const LogicalType &list_type, idx_t initial_capacity = STANDARD_VECTOR_SIZE);
	~VectorListBuffer() override;

public:
	Vector &GetChild() {
		return *child;
	}
	void Reserve(idx_t to_reserve);

	void Append(const Vector &to_append, idx_t to_append_size, idx_t source_offset = 0);
	void Append(const Vector &to_append, const SelectionVector &sel, idx_t to_append_size, idx_t source_offset = 0);

	void PushBack(const Value &insert);

	idx_t GetSize() {
		return size;
	}

	idx_t GetCapacity() {
		return capacity;
	}

	void SetCapacity(idx_t new_capacity);
	void SetSize(idx_t new_size);

private:
	//! child vectors used for nested data
	unique_ptr<Vector> child;
	idx_t capacity = 0;
	idx_t size = 0;
};

class VectorArrayBuffer : public VectorBuffer {
public:
	explicit VectorArrayBuffer(unique_ptr<Vector> child_vector, idx_t array_size, idx_t initial_capacity);
	explicit VectorArrayBuffer(const LogicalType &array, idx_t initial = STANDARD_VECTOR_SIZE);
	~VectorArrayBuffer() override;

public:
	Vector &GetChild();
	idx_t GetArraySize();
	idx_t GetChildSize();

private:
	unique_ptr<Vector> child;
	// The size of each array in this buffer
	idx_t array_size = 0;
	// How many arrays are currently stored in this buffer
	// The child vector has size (array_size * size)
	idx_t size = 0;
};

//! The ManagedVectorBuffer holds a buffer handle
class ManagedVectorBuffer : public VectorBuffer {
public:
	explicit ManagedVectorBuffer(BufferHandle handle);
	~ManagedVectorBuffer() override;

private:
	BufferHandle handle;
};

} // namespace duckdb



namespace duckdb {

class VectorCache;
class VectorStructBuffer;
class VectorListBuffer;
struct SelCache;

struct UnifiedVectorFormat {
	DUCKDB_API UnifiedVectorFormat();
	// disable copy constructors
	UnifiedVectorFormat(const UnifiedVectorFormat &other) = delete;
	UnifiedVectorFormat &operator=(const UnifiedVectorFormat &) = delete;
	//! enable move constructors
	DUCKDB_API UnifiedVectorFormat(UnifiedVectorFormat &&other) noexcept;
	DUCKDB_API UnifiedVectorFormat &operator=(UnifiedVectorFormat &&) noexcept;

	const SelectionVector *sel;
	data_ptr_t data;
	ValidityMask validity;
	SelectionVector owned_sel;

	template <class T>
	static inline const T *GetData(const UnifiedVectorFormat &format) {
		return reinterpret_cast<const T *>(format.data);
	}
	template <class T>
	static inline T *GetDataNoConst(UnifiedVectorFormat &format) {
		return reinterpret_cast<T *>(format.data);
	}
};

struct RecursiveUnifiedVectorFormat {
	UnifiedVectorFormat unified;
	vector<RecursiveUnifiedVectorFormat> children;
	LogicalType logical_type;
};

//! This is a helper data structure. It contains all fields necessary to resize a vector.
struct ResizeInfo {
	ResizeInfo(Vector &vec, data_ptr_t data, optional_ptr<VectorBuffer> buffer, const idx_t multiplier)
	    : vec(vec), data(data), buffer(buffer), multiplier(multiplier) {
	}

	Vector &vec;
	data_ptr_t data;
	optional_ptr<VectorBuffer> buffer;
	idx_t multiplier;
};

struct ConsecutiveChildListInfo {
	ConsecutiveChildListInfo() : is_constant(true), needs_slicing(false), child_list_info(list_entry_t(0, 0)) {
	}
	bool is_constant;
	bool needs_slicing;
	list_entry_t child_list_info;
};

//! Vector of values of a specified PhysicalType.
class Vector {
	friend struct ConstantVector;
	friend struct DictionaryVector;
	friend struct FlatVector;
	friend struct ListVector;
	friend struct StringVector;
	friend struct FSSTVector;
	friend struct StructVector;
	friend struct UnionVector;
	friend struct SequenceVector;
	friend struct ArrayVector;

	friend class DataChunk;
	friend class VectorCacheBuffer;

public:
	//! Create a vector that references the other vector
	DUCKDB_API Vector(Vector &other);
	//! Create a vector that slices another vector
	DUCKDB_API explicit Vector(const Vector &other, const SelectionVector &sel, idx_t count);
	//! Create a vector that slices another vector between a pair of offsets
	DUCKDB_API explicit Vector(const Vector &other, idx_t offset, idx_t end);
	//! Create a vector of size one holding the passed on value
	DUCKDB_API explicit Vector(const Value &value);
	//! Create a vector of size tuple_count (non-standard)
	DUCKDB_API explicit Vector(LogicalType type, idx_t capacity = STANDARD_VECTOR_SIZE);
	//! Create an empty standard vector with a type, equivalent to calling Vector(type, true, false)
	DUCKDB_API explicit Vector(const VectorCache &cache);
	//! Create a non-owning vector that references the specified data
	DUCKDB_API Vector(LogicalType type, data_ptr_t dataptr);
	//! Create an owning vector that holds at most STANDARD_VECTOR_SIZE entries.
	/*!
	    Create a new vector
	    If create_data is true, the vector will be an owning empty vector.
	    If zero_data is true, the allocated data will be zero-initialized.
	*/
	DUCKDB_API Vector(LogicalType type, bool create_data, bool zero_data, idx_t capacity = STANDARD_VECTOR_SIZE);
	// implicit copying of Vectors is not allowed
	Vector(const Vector &) = delete;
	// but moving of vectors is allowed
	DUCKDB_API Vector(Vector &&other) noexcept;

public:
	//! Create a vector that references the specified value.
	DUCKDB_API void Reference(const Value &value);
	//! Causes this vector to reference the data held by the other vector.
	//! The type of the "other" vector should match the type of this vector
	DUCKDB_API void Reference(const Vector &other);
	//! Reinterpret the data of the other vector as the type of this vector
	//! Note that this takes the data of the other vector as-is and places it in this vector
	//! Without changing the type of this vector
	DUCKDB_API void Reinterpret(const Vector &other);

	//! Causes this vector to reference the data held by the other vector, changes the type if required.
	DUCKDB_API void ReferenceAndSetType(const Vector &other);

	//! Resets a vector from a vector cache.
	//! This turns the vector back into an empty FlatVector with STANDARD_VECTOR_SIZE entries.
	//! The VectorCache is used so this can be done without requiring any allocations.
	DUCKDB_API void ResetFromCache(const VectorCache &cache);

	//! Creates a reference to a slice of the other vector
	DUCKDB_API void Slice(const Vector &other, idx_t offset, idx_t end);
	//! Creates a reference to a slice of the other vector
	DUCKDB_API void Slice(const Vector &other, const SelectionVector &sel, idx_t count);
	//! Turns the vector into a dictionary vector with the specified dictionary
	DUCKDB_API void Slice(const SelectionVector &sel, idx_t count);
	//! Slice the vector, keeping the result around in a cache or potentially using the cache instead of slicing
	DUCKDB_API void Slice(const SelectionVector &sel, idx_t count, SelCache &cache);

	//! Creates the data of this vector with the specified type. Any data that
	//! is currently in the vector is destroyed.
	DUCKDB_API void Initialize(bool zero_data = false, idx_t capacity = STANDARD_VECTOR_SIZE);

	//! Converts this Vector to a printable string representation
	DUCKDB_API string ToString(idx_t count) const;
	DUCKDB_API void Print(idx_t count) const;

	DUCKDB_API string ToString() const;
	DUCKDB_API void Print() const;

	//! Flatten the vector, removing any compression and turning it into a FLAT_VECTOR
	DUCKDB_API void Flatten(idx_t count);
	DUCKDB_API void Flatten(const SelectionVector &sel, idx_t count);
	//! Creates a UnifiedVectorFormat of a vector
	//! The UnifiedVectorFormat allows efficient reading of vectors regardless of their vector type
	//! It contains (1) a data pointer, (2) a validity mask, and (3) a selection vector
	//! Access to the individual vector elements can be performed through data_pointer[sel_idx[i]]/validity[sel_idx[i]]
	//! The most common vector types (flat, constant & dictionary) can be converted to the canonical format "for free"
	//! ToUnifiedFormat was originally called Orrify, as a tribute to Orri Erling who came up with it
	DUCKDB_API void ToUnifiedFormat(idx_t count, UnifiedVectorFormat &data);
	//! Recursively calls UnifiedVectorFormat on a vector and its child vectors (for nested types)
	static void RecursiveToUnifiedFormat(Vector &input, idx_t count, RecursiveUnifiedVectorFormat &data);

	//! Turn the vector into a sequence vector
	DUCKDB_API void Sequence(int64_t start, int64_t increment, idx_t count);

	//! Verify that the Vector is in a consistent, not corrupt state. DEBUG
	//! FUNCTION ONLY!
	DUCKDB_API void Verify(idx_t count);
	//! Asserts that the CheckMapValidity returns MapInvalidReason::VALID
	DUCKDB_API static void VerifyMap(Vector &map, const SelectionVector &sel, idx_t count);
	DUCKDB_API static void VerifyUnion(Vector &map, const SelectionVector &sel, idx_t count);
	DUCKDB_API static void Verify(Vector &vector, const SelectionVector &sel, idx_t count);
	DUCKDB_API void UTFVerify(idx_t count);
	DUCKDB_API void UTFVerify(const SelectionVector &sel, idx_t count);

	//! Returns the [index] element of the Vector as a Value.
	DUCKDB_API Value GetValue(idx_t index) const;
	//! Sets the [index] element of the Vector to the specified Value.
	DUCKDB_API void SetValue(idx_t index, const Value &val);

	inline void SetAuxiliary(buffer_ptr<VectorBuffer> new_buffer) {
		auxiliary = std::move(new_buffer);
	};

	inline void CopyBuffer(Vector &other) {
		buffer = other.buffer;
		data = other.data;
	}

	//! Resizes the vector.
	DUCKDB_API void Resize(idx_t cur_size, idx_t new_size);
	//! Returns a vector of ResizeInfo containing each (nested) vector to resize.
	DUCKDB_API void FindResizeInfos(vector<ResizeInfo> &resize_infos, const idx_t multiplier);

	DUCKDB_API void Serialize(Serializer &serializer, idx_t count);
	DUCKDB_API void Deserialize(Deserializer &deserializer, idx_t count);

	idx_t GetAllocationSize(idx_t cardinality) const;

	// Getters
	inline VectorType GetVectorType() const {
		return vector_type;
	}
	inline const LogicalType &GetType() const {
		return type;
	}
	inline data_ptr_t GetData() {
		return data;
	}

	inline buffer_ptr<VectorBuffer> GetAuxiliary() {
		return auxiliary;
	}

	inline buffer_ptr<VectorBuffer> GetBuffer() {
		return buffer;
	}

	// Setters
	DUCKDB_API void SetVectorType(VectorType vector_type);

	// Transform vector to an equivalent dictionary vector
	static void DebugTransformToDictionary(Vector &vector, idx_t count);
	// Transform vector to an equivalent nested vector
	static void DebugShuffleNestedVector(Vector &vector, idx_t count);

private:
	//! Returns the [index] element of the Vector as a Value.
	static Value GetValue(const Vector &v, idx_t index);
	//! Returns the [index] element of the Vector as a Value.
	static Value GetValueInternal(const Vector &v, idx_t index);

protected:
	//! The vector type specifies how the data of the vector is physically stored (i.e. if it is a single repeated
	//! constant, if it is compressed)
	VectorType vector_type;
	//! The type of the elements stored in the vector (e.g. integer, float)
	LogicalType type;
	//! A pointer to the data.
	data_ptr_t data;
	//! The validity mask of the vector
	ValidityMask validity;
	//! The main buffer holding the data of the vector
	buffer_ptr<VectorBuffer> buffer;
	//! The buffer holding auxiliary data of the vector
	//! e.g. a string vector uses this to store strings
	buffer_ptr<VectorBuffer> auxiliary;
};

//! The DictionaryBuffer holds a selection vector
class VectorChildBuffer : public VectorBuffer {
public:
	explicit VectorChildBuffer(Vector vector)
	    : VectorBuffer(VectorBufferType::VECTOR_CHILD_BUFFER), data(std::move(vector)) {
	}

public:
	Vector data;
};

struct ConstantVector {
	static inline const_data_ptr_t GetData(const Vector &vector) {
		D_ASSERT(vector.GetVectorType() == VectorType::CONSTANT_VECTOR ||
		         vector.GetVectorType() == VectorType::FLAT_VECTOR);
		return vector.data;
	}
	static inline data_ptr_t GetData(Vector &vector) {
		D_ASSERT(vector.GetVectorType() == VectorType::CONSTANT_VECTOR ||
		         vector.GetVectorType() == VectorType::FLAT_VECTOR);
		return vector.data;
	}
	template <class T>
	static inline const T *GetData(const Vector &vector) {
		return (const T *)ConstantVector::GetData(vector);
	}
	template <class T>
	static inline T *GetData(Vector &vector) {
		return (T *)ConstantVector::GetData(vector);
	}
	static inline bool IsNull(const Vector &vector) {
		D_ASSERT(vector.GetVectorType() == VectorType::CONSTANT_VECTOR);
		return !vector.validity.RowIsValid(0);
	}
	DUCKDB_API static void SetNull(Vector &vector, bool is_null);
	static inline ValidityMask &Validity(Vector &vector) {
		D_ASSERT(vector.GetVectorType() == VectorType::CONSTANT_VECTOR);
		return vector.validity;
	}
	DUCKDB_API static const SelectionVector *ZeroSelectionVector(idx_t count, SelectionVector &owned_sel);
	DUCKDB_API static const SelectionVector *ZeroSelectionVector();
	//! Turns "vector" into a constant vector by referencing a value within the source vector
	DUCKDB_API static void Reference(Vector &vector, Vector &source, idx_t position, idx_t count);

	static const sel_t ZERO_VECTOR[STANDARD_VECTOR_SIZE];
};

struct DictionaryVector {
	static inline const SelectionVector &SelVector(const Vector &vector) {
		D_ASSERT(vector.GetVectorType() == VectorType::DICTIONARY_VECTOR);
		return vector.buffer->Cast<DictionaryBuffer>().GetSelVector();
	}
	static inline SelectionVector &SelVector(Vector &vector) {
		D_ASSERT(vector.GetVectorType() == VectorType::DICTIONARY_VECTOR);
		return vector.buffer->Cast<DictionaryBuffer>().GetSelVector();
	}
	static inline const Vector &Child(const Vector &vector) {
		D_ASSERT(vector.GetVectorType() == VectorType::DICTIONARY_VECTOR);
		return vector.auxiliary->Cast<VectorChildBuffer>().data;
	}
	static inline Vector &Child(Vector &vector) {
		D_ASSERT(vector.GetVectorType() == VectorType::DICTIONARY_VECTOR);
		return vector.auxiliary->Cast<VectorChildBuffer>().data;
	}
};

struct FlatVector {
	static void VerifyFlatVector(const Vector &vector) {
#ifdef DUCKDB_DEBUG_NO_SAFETY
		D_ASSERT(vector.GetVectorType() == VectorType::FLAT_VECTOR);
#else
		if (vector.GetVectorType() != VectorType::FLAT_VECTOR) {
			throw InternalException("Operation requires a flat vector but a non-flat vector was encountered");
		}
#endif
	}

	static inline data_ptr_t GetData(Vector &vector) {
		return ConstantVector::GetData(vector);
	}
	template <class T>
	static inline const T *GetData(const Vector &vector) {
		return ConstantVector::GetData<T>(vector);
	}
	template <class T>
	static inline T *GetData(Vector &vector) {
		return ConstantVector::GetData<T>(vector);
	}
	static inline void SetData(Vector &vector, data_ptr_t data) {
		D_ASSERT(vector.GetVectorType() == VectorType::FLAT_VECTOR);
		vector.data = data;
	}
	template <class T>
	static inline T GetValue(Vector &vector, idx_t idx) {
		D_ASSERT(vector.GetVectorType() == VectorType::FLAT_VECTOR);
		return FlatVector::GetData<T>(vector)[idx];
	}
	static inline const ValidityMask &Validity(const Vector &vector) {
		VerifyFlatVector(vector);
		return vector.validity;
	}
	static inline ValidityMask &Validity(Vector &vector) {
		VerifyFlatVector(vector);
		return vector.validity;
	}
	static inline void SetValidity(Vector &vector, const ValidityMask &new_validity) {
		VerifyFlatVector(vector);
		vector.validity.Initialize(new_validity);
	}
	DUCKDB_API static void SetNull(Vector &vector, idx_t idx, bool is_null);
	static inline bool IsNull(const Vector &vector, idx_t idx) {
		D_ASSERT(vector.GetVectorType() == VectorType::FLAT_VECTOR);
		return !vector.validity.RowIsValid(idx);
	}
	DUCKDB_API static const SelectionVector *IncrementalSelectionVector();
};

struct ListVector {
	static inline list_entry_t *GetData(Vector &v) {
		if (v.GetVectorType() == VectorType::DICTIONARY_VECTOR) {
			auto &child = DictionaryVector::Child(v);
			return GetData(child);
		}
		return FlatVector::GetData<list_entry_t>(v);
	}
	//! Gets a reference to the underlying child-vector of a list
	DUCKDB_API static const Vector &GetEntry(const Vector &vector);
	//! Gets a reference to the underlying child-vector of a list
	DUCKDB_API static Vector &GetEntry(Vector &vector);
	//! Gets the total size of the underlying child-vector of a list
	DUCKDB_API static idx_t GetListSize(const Vector &vector);
	//! Sets the total size of the underlying child-vector of a list
	DUCKDB_API static void SetListSize(Vector &vec, idx_t size);
	//! Gets the total capacity of the underlying child-vector of a list
	DUCKDB_API static idx_t GetListCapacity(const Vector &vector);
	//! Sets the total capacity of the underlying child-vector of a list
	DUCKDB_API static void Reserve(Vector &vec, idx_t required_capacity);
	DUCKDB_API static void Append(Vector &target, const Vector &source, idx_t source_size, idx_t source_offset = 0);
	DUCKDB_API static void Append(Vector &target, const Vector &source, const SelectionVector &sel, idx_t source_size,
	                              idx_t source_offset = 0);
	DUCKDB_API static void PushBack(Vector &target, const Value &insert);
	//! Returns the child_vector of list starting at offset until offset + count, and its length
	DUCKDB_API static idx_t GetConsecutiveChildList(Vector &list, Vector &result, idx_t offset, idx_t count);
	//! Returns information to only copy a section of a list child vector
	DUCKDB_API static ConsecutiveChildListInfo GetConsecutiveChildListInfo(Vector &list, idx_t offset, idx_t count);
	//! Slice and flatten a child vector to only contain a consecutive subsection of the child entries
	DUCKDB_API static void GetConsecutiveChildSelVector(Vector &list, SelectionVector &sel, idx_t offset, idx_t count);
	//! Share the entry of the other list vector
	DUCKDB_API static void ReferenceEntry(Vector &vector, Vector &other);

private:
	template <class T>
	static T &GetEntryInternal(T &vector);
};

struct StringVector {
	//! Add a string to the string heap of the vector (auxiliary data)
	DUCKDB_API static string_t AddString(Vector &vector, const char *data, idx_t len);
	//! Add a string or a blob to the string heap of the vector (auxiliary data)
	//! This function is the same as ::AddString, except the added data does not need to be valid UTF8
	DUCKDB_API static string_t AddStringOrBlob(Vector &vector, const char *data, idx_t len);
	//! Add a string to the string heap of the vector (auxiliary data)
	DUCKDB_API static string_t AddString(Vector &vector, const char *data);
	//! Add a string to the string heap of the vector (auxiliary data)
	DUCKDB_API static string_t AddString(Vector &vector, string_t data);
	//! Add a string to the string heap of the vector (auxiliary data)
	DUCKDB_API static string_t AddString(Vector &vector, const string &data);
	//! Add a string or a blob to the string heap of the vector (auxiliary data)
	//! This function is the same as ::AddString, except the added data does not need to be valid UTF8
	DUCKDB_API static string_t AddStringOrBlob(Vector &vector, string_t data);
	//! Allocates an empty string of the specified size, and returns a writable pointer that can be used to store the
	//! result of an operation
	DUCKDB_API static string_t EmptyString(Vector &vector, idx_t len);
	//! Adds a reference to a handle that stores strings of this vector
	DUCKDB_API static void AddHandle(Vector &vector, BufferHandle handle);
	//! Adds a reference to an unspecified vector buffer that stores strings of this vector
	DUCKDB_API static void AddBuffer(Vector &vector, buffer_ptr<VectorBuffer> buffer);
	//! Add a reference from this vector to the string heap of the provided vector
	DUCKDB_API static void AddHeapReference(Vector &vector, Vector &other);
};

struct FSSTVector {
	static inline const ValidityMask &Validity(const Vector &vector) {
		D_ASSERT(vector.GetVectorType() == VectorType::FSST_VECTOR);
		return vector.validity;
	}
	static inline ValidityMask &Validity(Vector &vector) {
		D_ASSERT(vector.GetVectorType() == VectorType::FSST_VECTOR);
		return vector.validity;
	}
	static inline void SetValidity(Vector &vector, ValidityMask &new_validity) {
		D_ASSERT(vector.GetVectorType() == VectorType::FSST_VECTOR);
		vector.validity.Initialize(new_validity);
	}
	static inline const_data_ptr_t GetCompressedData(const Vector &vector) {
		D_ASSERT(vector.GetVectorType() == VectorType::FSST_VECTOR);
		return vector.data;
	}
	static inline data_ptr_t GetCompressedData(Vector &vector) {
		D_ASSERT(vector.GetVectorType() == VectorType::FSST_VECTOR);
		return vector.data;
	}
	template <class T>
	static inline const T *GetCompressedData(const Vector &vector) {
		return (const T *)FSSTVector::GetCompressedData(vector);
	}
	template <class T>
	static inline T *GetCompressedData(Vector &vector) {
		return (T *)FSSTVector::GetCompressedData(vector);
	}
	//! Decompresses an FSST_VECTOR into a FLAT_VECTOR. Note: validity is not copied.
	static void DecompressVector(const Vector &src, Vector &dst, idx_t src_offset, idx_t dst_offset, idx_t copy_count,
	                             const SelectionVector *sel);

	DUCKDB_API static string_t AddCompressedString(Vector &vector, string_t data);
	DUCKDB_API static string_t AddCompressedString(Vector &vector, const char *data, idx_t len);
	DUCKDB_API static void RegisterDecoder(Vector &vector, buffer_ptr<void> &duckdb_fsst_decoder,
	                                       const idx_t string_block_limit);
	DUCKDB_API static void *GetDecoder(const Vector &vector);
	DUCKDB_API static vector<unsigned char> &GetDecompressBuffer(const Vector &vector);
	//! Setting the string count is required to be able to correctly flatten the vector
	DUCKDB_API static void SetCount(Vector &vector, idx_t count);
	DUCKDB_API static idx_t GetCount(Vector &vector);
};

enum class MapInvalidReason : uint8_t { VALID, NULL_KEY, DUPLICATE_KEY, NOT_ALIGNED, INVALID_PARAMS };

struct MapVector {
	DUCKDB_API static const Vector &GetKeys(const Vector &vector);
	DUCKDB_API static const Vector &GetValues(const Vector &vector);
	DUCKDB_API static Vector &GetKeys(Vector &vector);
	DUCKDB_API static Vector &GetValues(Vector &vector);
	DUCKDB_API static MapInvalidReason
	CheckMapValidity(Vector &map, idx_t count, const SelectionVector &sel = *FlatVector::IncrementalSelectionVector());
	DUCKDB_API static void EvalMapInvalidReason(MapInvalidReason reason);
	DUCKDB_API static void MapConversionVerify(Vector &vector, idx_t count);
};

struct StructVector {
	DUCKDB_API static const vector<unique_ptr<Vector>> &GetEntries(const Vector &vector);
	DUCKDB_API static vector<unique_ptr<Vector>> &GetEntries(Vector &vector);
};

struct ArrayVector {
	//! Gets a reference to the underlying child-vector of an array
	DUCKDB_API static const Vector &GetEntry(const Vector &vector);
	//! Gets a reference to the underlying child-vector of an array
	DUCKDB_API static Vector &GetEntry(Vector &vector);
	//! Gets the total size of the underlying child-vector of an array
	DUCKDB_API static idx_t GetTotalSize(const Vector &vector);

private:
	template <class T>
	static T &GetEntryInternal(T &vector);
};

enum class UnionInvalidReason : uint8_t {
	VALID,
	TAG_OUT_OF_RANGE,
	NO_MEMBERS,
	VALIDITY_OVERLAP,
	TAG_MISMATCH,
	NULL_TAG
};

struct UnionVector {
	// Unions are stored as structs, but the first child is always the "tag"
	// vector, specifying the currently selected member for that row.
	// The remaining children are the members of the union.
	// INVARIANTS:
	//	1.	Only one member vector (the one "selected" by the tag) can be
	//		non-NULL in each row.
	//
	//	2.	The validity of the tag vector always matches the validity of the
	//		union vector itself.
	//
	//  3.  A valid union cannot have a NULL tag, but the selected member can
	//  	be NULL. therefore, there is a difference between a union that "is"
	//  	NULL and a union that "holds" a NULL. The latter still has a valid
	//  	tag.
	//
	//	4.	For each tag in the tag vector, 0 <= tag < |members|

	//! Get the tag vector of a union vector
	DUCKDB_API static const Vector &GetTags(const Vector &v);
	DUCKDB_API static Vector &GetTags(Vector &v);

	//! Try to get the tag at the specific flat index of the union vector. Returns false if the tag is NULL.
	//! This will handle and map the index properly for constant and dictionary vectors internally.
	DUCKDB_API static bool TryGetTag(const Vector &vector, idx_t index, union_tag_t &tag);

	//! Get the member vector of a union vector by index
	DUCKDB_API static const Vector &GetMember(const Vector &vector, idx_t member_index);
	DUCKDB_API static Vector &GetMember(Vector &vector, idx_t member_index);

	//! Set every entry in the UnionVector to a specific member.
	//! This is useful to set the entire vector to a single member, e.g. when "creating"
	//! a union to return in a function, when you only have one alternative to return.
	//! if 'keep_tags_for_null' is false, the tags will be set to NULL where the member is NULL.
	//! (the validity of the tag vector will match the selected member vector)
	//! otherwise, they are all set to the 'tag'.
	//! This will also handle invalidation of the non-selected members
	DUCKDB_API static void SetToMember(Vector &vector, union_tag_t tag, Vector &member_vector, idx_t count,
	                                   bool keep_tags_for_null);

	DUCKDB_API static UnionInvalidReason
	CheckUnionValidity(Vector &vector, idx_t count,
	                   const SelectionVector &sel = *FlatVector::IncrementalSelectionVector());
};

struct SequenceVector {
	static void GetSequence(const Vector &vector, int64_t &start, int64_t &increment, int64_t &sequence_count) {
		D_ASSERT(vector.GetVectorType() == VectorType::SEQUENCE_VECTOR);
		auto data = reinterpret_cast<int64_t *>(vector.buffer->GetData());
		start = data[0];
		increment = data[1];
		sequence_count = data[2];
	}
	static void GetSequence(const Vector &vector, int64_t &start, int64_t &increment) {
		int64_t sequence_count;
		GetSequence(vector, start, increment, sequence_count);
	}
};

} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/vector_operations/vector_operations.hpp
//
//
//===----------------------------------------------------------------------===//



//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/types/data_chunk.hpp
//
//
//===----------------------------------------------------------------------===//




//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/arrow/arrow_wrapper.hpp
//
//
//===----------------------------------------------------------------------===//


//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/arrow/arrow.hpp
//
//
//===----------------------------------------------------------------------===//

#ifndef ARROW_FLAG_DICTIONARY_ORDERED

#include <stdint.h>

#ifdef __cplusplus
extern "C" {
#endif

#ifndef ARROW_C_DATA_INTERFACE
#define ARROW_C_DATA_INTERFACE

#define ARROW_FLAG_DICTIONARY_ORDERED 1
#define ARROW_FLAG_NULLABLE           2
#define ARROW_FLAG_MAP_KEYS_SORTED    4

struct ArrowSchema {
	//! Array type description
	const char *format;
	const char *name;
	const char *metadata;
	int64_t flags;
	int64_t n_children;
	struct ArrowSchema **children;
	struct ArrowSchema *dictionary;

	//! Release callback
	void (*release)(struct ArrowSchema *);
	//! Opaque producer-specific data
	void *private_data;

	//! Initialize all fields
	void Init() {
		flags = 0;
		n_children = 0;
		release = nullptr;
		private_data = nullptr;
	}
};

struct ArrowArray {
	//! Array data description
	int64_t length;
	int64_t null_count;
	int64_t offset;
	int64_t n_buffers;
	int64_t n_children;
	const void **buffers;
	struct ArrowArray **children;
	struct ArrowArray *dictionary;

	//! Release callback
	void (*release)(struct ArrowArray *);
	//! Opaque producer-specific data
	void *private_data;

	//! Initialize all fields
	void Init() {
		length = 0;
		null_count = 0;
		offset = 0;
		n_buffers = 0;
		n_children = 0;
		release = nullptr;
		private_data = nullptr;
	}
};
#endif

#ifndef ARROW_C_STREAM_INTERFACE
#define ARROW_C_STREAM_INTERFACE
// EXPERIMENTAL
struct ArrowArrayStream {
	// Callback to get the stream type
	// (will be the same for all arrays in the stream).
	// Return value: 0 if successful, an `errno`-compatible error code otherwise.
	int (*get_schema)(struct ArrowArrayStream *, struct ArrowSchema *out);
	// Callback to get the next array
	// (if no error and the array is released, the stream has ended)
	// Return value: 0 if successful, an `errno`-compatible error code otherwise.
	int (*get_next)(struct ArrowArrayStream *, struct ArrowArray *out);

	// Callback to get optional detailed error information.
	// This must only be called if the last stream operation failed
	// with a non-0 return code.  The returned pointer is only valid until
	// the next operation on this stream (including release).
	// If unavailable, NULL is returned.
	const char *(*get_last_error)(struct ArrowArrayStream *);

	// Release callback: release the stream's own resources.
	// Note that arrays returned by `get_next` must be individually released.
	void (*release)(struct ArrowArrayStream *);
	// Opaque producer-specific data
	void *private_data;
};
#endif

#ifdef __cplusplus
}
#endif

#endif



//! Here we have the internal duckdb classes that interact with Arrow's Internal Header (i.e., duckdb/commons/arrow.hpp)
namespace duckdb {

class ArrowSchemaWrapper {
public:
	ArrowSchema arrow_schema;

	ArrowSchemaWrapper() {
		arrow_schema.release = nullptr;
	}

	~ArrowSchemaWrapper();
};
class ArrowArrayWrapper {
public:
	ArrowArray arrow_array;
	ArrowArrayWrapper() {
		arrow_array.length = 0;
		arrow_array.release = nullptr;
	}
	ArrowArrayWrapper(ArrowArrayWrapper &&other) noexcept : arrow_array(other.arrow_array) {
		other.arrow_array.release = nullptr;
	}
	~ArrowArrayWrapper();
};

class ArrowArrayStreamWrapper {
public:
	ArrowArrayStream arrow_array_stream;
	int64_t number_of_rows;

public:
	void GetSchema(ArrowSchemaWrapper &schema);

	virtual shared_ptr<ArrowArrayWrapper> GetNextChunk();

	const char *GetError();

	virtual ~ArrowArrayStreamWrapper();
	ArrowArrayStreamWrapper() {
		arrow_array_stream.release = nullptr;
	}
};

} // namespace duckdb





namespace duckdb {
class Allocator;
class ClientContext;
class ExecutionContext;
class VectorCache;
class Serializer;
class Deserializer;

//!  A Data Chunk represents a set of vectors.
/*!
    The data chunk class is the intermediate representation used by the
   execution engine of DuckDB. It effectively represents a subset of a relation.
   It holds a set of vectors that all have the same length.

    DataChunk is initialized using the DataChunk::Initialize function by
   providing it with a vector of TypeIds for the Vector members. By default,
   this function will also allocate a chunk of memory in the DataChunk for the
   vectors and all the vectors will be referencing vectors to the data owned by
   the chunk. The reason for this behavior is that the underlying vectors can
   become referencing vectors to other chunks as well (i.e. in the case an
   operator does not alter the data, such as a Filter operator which only adds a
   selection vector).

    In addition to holding the data of the vectors, the DataChunk also owns the
   selection vector that underlying vectors can point to.
*/
class DataChunk {
public:
	//! Creates an empty DataChunk
	DUCKDB_API DataChunk();
	DUCKDB_API ~DataChunk();

	//! The vectors owned by the DataChunk.
	vector<Vector> data;

public:
	inline idx_t size() const { // NOLINT
		return count;
	}
	inline idx_t ColumnCount() const {
		return data.size();
	}
	inline void SetCardinality(idx_t count_p) {
		D_ASSERT(count_p <= capacity);
		this->count = count_p;
	}
	inline void SetCardinality(const DataChunk &other) {
		SetCardinality(other.size());
	}
	inline void SetCapacity(idx_t capacity_p) {
		this->capacity = capacity_p;
	}
	inline void SetCapacity(const DataChunk &other) {
		SetCapacity(other.capacity);
	}

	DUCKDB_API Value GetValue(idx_t col_idx, idx_t index) const;
	DUCKDB_API void SetValue(idx_t col_idx, idx_t index, const Value &val);

	idx_t GetAllocationSize() const;

	//! Returns true if all vectors in the DataChunk are constant
	DUCKDB_API bool AllConstant() const;

	//! Set the DataChunk to reference another data chunk
	DUCKDB_API void Reference(DataChunk &chunk);
	//! Set the DataChunk to own the data of data chunk, destroying the other chunk in the process
	DUCKDB_API void Move(DataChunk &chunk);

	//! Initializes the DataChunk with the specified types to an empty DataChunk
	//! This will create one vector of the specified type for each LogicalType in the
	//! types list. The vector will be referencing vector to the data owned by
	//! the DataChunk.
	DUCKDB_API void Initialize(Allocator &allocator, const vector<LogicalType> &types,
	                           idx_t capacity = STANDARD_VECTOR_SIZE);
	DUCKDB_API void Initialize(ClientContext &context, const vector<LogicalType> &types,
	                           idx_t capacity = STANDARD_VECTOR_SIZE);
	//! Initializes an empty DataChunk with the given types. The vectors will *not* have any data allocated for them.
	DUCKDB_API void InitializeEmpty(const vector<LogicalType> &types);

	DUCKDB_API void InitializeEmpty(vector<LogicalType>::const_iterator begin, vector<LogicalType>::const_iterator end);
	DUCKDB_API void Initialize(Allocator &allocator, vector<LogicalType>::const_iterator begin,
	                           vector<LogicalType>::const_iterator end, idx_t capacity = STANDARD_VECTOR_SIZE);
	DUCKDB_API void Initialize(ClientContext &context, vector<LogicalType>::const_iterator begin,
	                           vector<LogicalType>::const_iterator end, idx_t capacity = STANDARD_VECTOR_SIZE);

	//! Append the other DataChunk to this one. The column count and types of
	//! the two DataChunks have to match exactly. Throws an exception if there
	//! is not enough space in the chunk and resize is not allowed.
	DUCKDB_API void Append(const DataChunk &other, bool resize = false, SelectionVector *sel = nullptr,
	                       idx_t count = 0);

	//! Destroy all data and columns owned by this DataChunk
	DUCKDB_API void Destroy();

	//! Copies the data from this vector to another vector.
	DUCKDB_API void Copy(DataChunk &other, idx_t offset = 0) const;
	DUCKDB_API void Copy(DataChunk &other, const SelectionVector &sel, const idx_t source_count,
	                     const idx_t offset = 0) const;

	//! Splits the DataChunk in two
	DUCKDB_API void Split(DataChunk &other, idx_t split_idx);

	//! Fuses a DataChunk onto the right of this one, and destroys the other. Inverse of Split.
	DUCKDB_API void Fuse(DataChunk &other);

	//! Makes this DataChunk reference the specified columns in the other DataChunk
	DUCKDB_API void ReferenceColumns(DataChunk &other, const vector<column_t> &column_ids);

	//! Turn all the vectors from the chunk into flat vectors
	DUCKDB_API void Flatten();

	// FIXME: this is DUCKDB_API, might need conversion back to regular unique ptr?
	DUCKDB_API unsafe_unique_array<UnifiedVectorFormat> ToUnifiedFormat();

	DUCKDB_API void Slice(const SelectionVector &sel_vector, idx_t count);

	//! Slice all Vectors from other.data[i] to data[i + 'col_offset']
	//! Turning all Vectors into Dictionary Vectors, using 'sel'
	DUCKDB_API void Slice(const DataChunk &other, const SelectionVector &sel, idx_t count, idx_t col_offset = 0);

	//! Slice a DataChunk from "offset" to "offset + count"
	DUCKDB_API void Slice(idx_t offset, idx_t count);

	//! Resets the DataChunk to its state right after the DataChunk::Initialize
	//! function was called. This sets the count to 0, and resets each member
	//! Vector to point back to the data owned by this DataChunk.
	DUCKDB_API void Reset();

	DUCKDB_API void Serialize(Serializer &serializer) const;
	DUCKDB_API void Deserialize(Deserializer &source);

	//! Hashes the DataChunk to the target vector
	DUCKDB_API void Hash(Vector &result);
	//! Hashes specific vectors of the DataChunk to the target vector
	DUCKDB_API void Hash(vector<idx_t> &column_ids, Vector &result);

	//! Returns a list of types of the vectors of this data chunk
	DUCKDB_API vector<LogicalType> GetTypes() const;

	//! Converts this DataChunk to a printable string representation
	DUCKDB_API string ToString() const;
	DUCKDB_API void Print() const;

	DataChunk(const DataChunk &) = delete;

	//! Verify that the DataChunk is in a consistent, not corrupt state. DEBUG
	//! FUNCTION ONLY!
	DUCKDB_API void Verify();

private:
	//! The amount of tuples stored in the data chunk
	idx_t count;
	//! The amount of tuples that can be stored in the data chunk
	idx_t capacity;
	//! Vector caches, used to store data when ::Initialize is called
	vector<VectorCache> vector_caches;
};
} // namespace duckdb



#include <functional>

namespace duckdb {
class CastFunctionSet;
struct GetCastFunctionInput;

// VectorOperations contains a set of operations that operate on sets of
// vectors. In general, the operators must all have the same type, otherwise an
// exception is thrown. Note that the functions underneath use restrict
// pointers, hence the data that the vectors point to (and hence the vector
// themselves) should not be equal! For example, if you call the function Add(A,
// B, A) then ASSERT_RESTRICT will be triggered. Instead call AddInPlace(A, B)
// or Add(A, B, C)
struct VectorOperations {
	//===--------------------------------------------------------------------===//
	// In-Place Operators
	//===--------------------------------------------------------------------===//
	//! left += delta
	static void AddInPlace(Vector &left, int64_t delta, idx_t count);

	//===--------------------------------------------------------------------===//
	// NULL Operators
	//===--------------------------------------------------------------------===//
	//! result = IS NOT NULL(input)
	static void IsNotNull(Vector &arg, Vector &result, idx_t count);
	//! result = IS NULL (input)
	static void IsNull(Vector &input, Vector &result, idx_t count);
	// Returns whether or not arg vector has a NULL value
	static bool HasNull(Vector &input, idx_t count);
	static bool HasNotNull(Vector &input, idx_t count);
	//! Count the number of not-NULL values.
	static idx_t CountNotNull(Vector &input, const idx_t count);

	//===--------------------------------------------------------------------===//
	// Boolean Operations
	//===--------------------------------------------------------------------===//
	// result = left && right
	static void And(Vector &left, Vector &right, Vector &result, idx_t count);
	// result = left || right
	static void Or(Vector &left, Vector &right, Vector &result, idx_t count);
	// result = NOT(left)
	static void Not(Vector &left, Vector &result, idx_t count);

	//===--------------------------------------------------------------------===//
	// Comparison Operations
	//===--------------------------------------------------------------------===//
	// result = left == right
	static void Equals(Vector &left, Vector &right, Vector &result, idx_t count);
	// result = left != right
	static void NotEquals(Vector &left, Vector &right, Vector &result, idx_t count);
	// result = left > right
	static void GreaterThan(Vector &left, Vector &right, Vector &result, idx_t count);
	// result = left >= right
	static void GreaterThanEquals(Vector &left, Vector &right, Vector &result, idx_t count);
	// result = left < right
	static void LessThan(Vector &left, Vector &right, Vector &result, idx_t count);
	// result = left <= right
	static void LessThanEquals(Vector &left, Vector &right, Vector &result, idx_t count);

	// result = A != B with nulls being equal
	static void DistinctFrom(Vector &left, Vector &right, Vector &result, idx_t count);
	// result := A == B with nulls being equal
	static void NotDistinctFrom(Vector &left, Vector &right, Vector &result, idx_t count);
	// result := A > B with nulls being maximal
	static void DistinctGreaterThan(Vector &left, Vector &right, Vector &result, idx_t count);
	// result := A >= B with nulls being maximal
	static void DistinctGreaterThanEquals(Vector &left, Vector &right, Vector &result, idx_t count);
	// result := A < B with nulls being maximal
	static void DistinctLessThan(Vector &left, Vector &right, Vector &result, idx_t count);
	// result := A <= B with nulls being maximal
	static void DistinctLessThanEquals(Vector &left, Vector &right, Vector &result, idx_t count);

	//===--------------------------------------------------------------------===//
	// Select Comparisons
	//===--------------------------------------------------------------------===//
	static idx_t Equals(Vector &left, Vector &right, optional_ptr<const SelectionVector> sel, idx_t count,
	                    optional_ptr<SelectionVector> true_sel, optional_ptr<SelectionVector> false_sel,
	                    optional_ptr<ValidityMask> null_mask = nullptr);
	static idx_t NotEquals(Vector &left, Vector &right, optional_ptr<const SelectionVector> sel, idx_t count,
	                       optional_ptr<SelectionVector> true_sel, optional_ptr<SelectionVector> false_sel,
	                       optional_ptr<ValidityMask> null_mask = nullptr);
	static idx_t GreaterThan(Vector &left, Vector &right, optional_ptr<const SelectionVector> sel, idx_t count,
	                         optional_ptr<SelectionVector> true_sel, optional_ptr<SelectionVector> false_sel,
	                         optional_ptr<ValidityMask> null_mask = nullptr);
	static idx_t GreaterThanEquals(Vector &left, Vector &right, optional_ptr<const SelectionVector> sel, idx_t count,
	                               optional_ptr<SelectionVector> true_sel, optional_ptr<SelectionVector> false_sel,
	                               optional_ptr<ValidityMask> null_mask = nullptr);
	static idx_t LessThan(Vector &left, Vector &right, optional_ptr<const SelectionVector> sel, idx_t count,
	                      optional_ptr<SelectionVector> true_sel, optional_ptr<SelectionVector> false_sel,
	                      optional_ptr<ValidityMask> null_mask = nullptr);
	static idx_t LessThanEquals(Vector &left, Vector &right, optional_ptr<const SelectionVector> sel, idx_t count,
	                            optional_ptr<SelectionVector> true_sel, optional_ptr<SelectionVector> false_sel,
	                            optional_ptr<ValidityMask> null_mask = nullptr);

	// true := A != B with nulls being equal
	static idx_t DistinctFrom(Vector &left, Vector &right, optional_ptr<const SelectionVector> sel, idx_t count,
	                          optional_ptr<SelectionVector> true_sel, optional_ptr<SelectionVector> false_sel);
	// true := A == B with nulls being equal
	static idx_t NotDistinctFrom(Vector &left, Vector &right, optional_ptr<const SelectionVector> sel, idx_t count,
	                             optional_ptr<SelectionVector> true_sel, optional_ptr<SelectionVector> false_sel);
	// true := A > B with nulls being maximal
	static idx_t DistinctGreaterThan(Vector &left, Vector &right, optional_ptr<const SelectionVector> sel, idx_t count,
	                                 optional_ptr<SelectionVector> true_sel, optional_ptr<SelectionVector> false_sel,
	                                 optional_ptr<ValidityMask> null_mask = nullptr);
	// true := A >= B with nulls being maximal
	static idx_t DistinctGreaterThanEquals(Vector &left, Vector &right, optional_ptr<const SelectionVector> sel,
	                                       idx_t count, optional_ptr<SelectionVector> true_sel,
	                                       optional_ptr<SelectionVector> false_sel,
	                                       optional_ptr<ValidityMask> null_mask = nullptr);
	// true := A < B with nulls being maximal
	static idx_t DistinctLessThan(Vector &left, Vector &right, optional_ptr<const SelectionVector> sel, idx_t count,
	                              optional_ptr<SelectionVector> true_sel, optional_ptr<SelectionVector> false_sel,
	                              optional_ptr<ValidityMask> null_mask = nullptr);
	// true := A <= B with nulls being maximal
	static idx_t DistinctLessThanEquals(Vector &left, Vector &right, optional_ptr<const SelectionVector> sel,
	                                    idx_t count, optional_ptr<SelectionVector> true_sel,
	                                    optional_ptr<SelectionVector> false_sel,
	                                    optional_ptr<ValidityMask> null_mask = nullptr);

	// true := A > B with nulls being minimal
	static idx_t DistinctGreaterThanNullsFirst(Vector &left, Vector &right, optional_ptr<const SelectionVector> sel,
	                                           idx_t count, optional_ptr<SelectionVector> true_sel,
	                                           optional_ptr<SelectionVector> false_sel,
	                                           optional_ptr<ValidityMask> null_mask = nullptr);
	// true := A < B with nulls being minimal
	static idx_t DistinctLessThanNullsFirst(Vector &left, Vector &right, optional_ptr<const SelectionVector> sel,
	                                        idx_t count, optional_ptr<SelectionVector> true_sel,
	                                        optional_ptr<SelectionVector> false_sel,
	                                        optional_ptr<ValidityMask> null_mask = nullptr);

	//===--------------------------------------------------------------------===//
	// Nested Comparisons
	//===--------------------------------------------------------------------===//
	// true := A != B with nulls being equal
	static idx_t NestedNotEquals(Vector &left, Vector &right, optional_ptr<const SelectionVector> sel, idx_t count,
	                             optional_ptr<SelectionVector> true_sel, optional_ptr<SelectionVector> false_sel,
	                             optional_ptr<ValidityMask> null_mask = nullptr);
	// true := A == B with nulls being equal
	static idx_t NestedEquals(Vector &left, Vector &right, optional_ptr<const SelectionVector> sel, idx_t count,
	                          optional_ptr<SelectionVector> true_sel, optional_ptr<SelectionVector> false_sel,
	                          optional_ptr<ValidityMask> null_mask = nullptr);

	//===--------------------------------------------------------------------===//
	// Hash functions
	//===--------------------------------------------------------------------===//
	// hashes = HASH(input)
	static void Hash(Vector &input, Vector &hashes, idx_t count);
	static void Hash(Vector &input, Vector &hashes, const SelectionVector &rsel, idx_t count);
	// hashes ^= HASH(input)
	static void CombineHash(Vector &hashes, Vector &input, idx_t count);
	static void CombineHash(Vector &hashes, Vector &input, const SelectionVector &rsel, idx_t count);

	//===--------------------------------------------------------------------===//
	// Generate functions
	//===--------------------------------------------------------------------===//
	static void GenerateSequence(Vector &result, idx_t count, int64_t start = 0, int64_t increment = 1);
	static void GenerateSequence(Vector &result, idx_t count, const SelectionVector &sel, int64_t start = 0,
	                             int64_t increment = 1);
	//===--------------------------------------------------------------------===//
	// Helpers
	//===--------------------------------------------------------------------===//
	//! Cast the data from the source type to the target type. Any elements that could not be converted are turned into
	//! NULLs. If any elements cannot be converted, returns false and fills in the error_message. If no error message is
	//! provided, an exception is thrown instead.
	DUCKDB_API static bool TryCast(CastFunctionSet &set, GetCastFunctionInput &input, Vector &source, Vector &result,
	                               idx_t count, string *error_message, bool strict = false,
	                               const bool nullify_parent = false);
	DUCKDB_API static bool DefaultTryCast(Vector &source, Vector &result, idx_t count, string *error_message,
	                                      bool strict = false);
	DUCKDB_API static bool TryCast(ClientContext &context, Vector &source, Vector &result, idx_t count,
	                               string *error_message, bool strict = false, const bool nullify_parent = false);
	//! Cast the data from the source type to the target type. Throws an exception if the cast fails.
	DUCKDB_API static void Cast(ClientContext &context, Vector &source, Vector &result, idx_t count,
	                            bool strict = false);
	DUCKDB_API static void DefaultCast(Vector &source, Vector &result, idx_t count, bool strict = false);

	// Copy the data of <source> to the target vector
	static void Copy(const Vector &source, Vector &target, idx_t source_count, idx_t source_offset,
	                 idx_t target_offset);
	static void Copy(const Vector &source, Vector &target, const SelectionVector &sel, idx_t source_count,
	                 idx_t source_offset, idx_t target_offset);
	static void Copy(const Vector &source, Vector &target, const SelectionVector &sel, idx_t source_count,
	                 idx_t source_offset, idx_t target_offset, idx_t copy_count);

	// Copy the data of <source> to the target location, setting null values to
	// NullValue<T>. Used to store data without separate NULL mask.
	static void WriteToStorage(Vector &source, idx_t count, data_ptr_t target);
	// Reads the data of <source> to the target vector, setting the nullmask
	// for any NullValue<T> of source. Used to go back from storage to a proper vector
	static void ReadFromStorage(data_ptr_t source, idx_t count, Vector &result);
};
} // namespace duckdb


#include <functional>

namespace duckdb {

struct DefaultNullCheckOperator {
	template <class LEFT_TYPE, class RIGHT_TYPE>
	static inline bool Operation(LEFT_TYPE left, RIGHT_TYPE right) {
		return false;
	}
};

struct BinaryStandardOperatorWrapper {
	template <class FUNC, class OP, class LEFT_TYPE, class RIGHT_TYPE, class RESULT_TYPE>
	static inline RESULT_TYPE Operation(FUNC fun, LEFT_TYPE left, RIGHT_TYPE right, ValidityMask &mask, idx_t idx) {
		return OP::template Operation<LEFT_TYPE, RIGHT_TYPE, RESULT_TYPE>(left, right);
	}

	static bool AddsNulls() {
		return false;
	}
};

struct BinarySingleArgumentOperatorWrapper {
	template <class FUNC, class OP, class LEFT_TYPE, class RIGHT_TYPE, class RESULT_TYPE>
	static inline RESULT_TYPE Operation(FUNC fun, LEFT_TYPE left, RIGHT_TYPE right, ValidityMask &mask, idx_t idx) {
		return OP::template Operation<LEFT_TYPE>(left, right);
	}

	static bool AddsNulls() {
		return false;
	}
};

struct BinaryLambdaWrapper {
	template <class FUNC, class OP, class LEFT_TYPE, class RIGHT_TYPE, class RESULT_TYPE>
	static inline RESULT_TYPE Operation(FUNC fun, LEFT_TYPE left, RIGHT_TYPE right, ValidityMask &mask, idx_t idx) {
		return fun(left, right);
	}

	static bool AddsNulls() {
		return false;
	}
};

struct BinaryLambdaWrapperWithNulls {
	template <class FUNC, class OP, class LEFT_TYPE, class RIGHT_TYPE, class RESULT_TYPE>
	static inline RESULT_TYPE Operation(FUNC fun, LEFT_TYPE left, RIGHT_TYPE right, ValidityMask &mask, idx_t idx) {
		return fun(left, right, mask, idx);
	}

	static bool AddsNulls() {
		return true;
	}
};

struct BinaryExecutor {
	template <class LEFT_TYPE, class RIGHT_TYPE, class RESULT_TYPE, class OPWRAPPER, class OP, class FUNC,
	          bool LEFT_CONSTANT, bool RIGHT_CONSTANT>
	static void ExecuteFlatLoop(const LEFT_TYPE *__restrict ldata, const RIGHT_TYPE *__restrict rdata,
	                            RESULT_TYPE *__restrict result_data, idx_t count, ValidityMask &mask, FUNC fun) {
		if (!LEFT_CONSTANT) {
			ASSERT_RESTRICT(ldata, ldata + count, result_data, result_data + count);
		}
		if (!RIGHT_CONSTANT) {
			ASSERT_RESTRICT(rdata, rdata + count, result_data, result_data + count);
		}

		if (!mask.AllValid()) {
			idx_t base_idx = 0;
			auto entry_count = ValidityMask::EntryCount(count);
			for (idx_t entry_idx = 0; entry_idx < entry_count; entry_idx++) {
				auto validity_entry = mask.GetValidityEntry(entry_idx);
				idx_t next = MinValue<idx_t>(base_idx + ValidityMask::BITS_PER_VALUE, count);
				if (ValidityMask::AllValid(validity_entry)) {
					// all valid: perform operation
					for (; base_idx < next; base_idx++) {
						auto lentry = ldata[LEFT_CONSTANT ? 0 : base_idx];
						auto rentry = rdata[RIGHT_CONSTANT ? 0 : base_idx];
						result_data[base_idx] =
						    OPWRAPPER::template Operation<FUNC, OP, LEFT_TYPE, RIGHT_TYPE, RESULT_TYPE>(
						        fun, lentry, rentry, mask, base_idx);
					}
				} else if (ValidityMask::NoneValid(validity_entry)) {
					// nothing valid: skip all
					base_idx = next;
					continue;
				} else {
					// partially valid: need to check individual elements for validity
					idx_t start = base_idx;
					for (; base_idx < next; base_idx++) {
						if (ValidityMask::RowIsValid(validity_entry, base_idx - start)) {
							auto lentry = ldata[LEFT_CONSTANT ? 0 : base_idx];
							auto rentry = rdata[RIGHT_CONSTANT ? 0 : base_idx];
							result_data[base_idx] =
							    OPWRAPPER::template Operation<FUNC, OP, LEFT_TYPE, RIGHT_TYPE, RESULT_TYPE>(
							        fun, lentry, rentry, mask, base_idx);
						}
					}
				}
			}
		} else {
			for (idx_t i = 0; i < count; i++) {
				auto lentry = ldata[LEFT_CONSTANT ? 0 : i];
				auto rentry = rdata[RIGHT_CONSTANT ? 0 : i];
				result_data[i] = OPWRAPPER::template Operation<FUNC, OP, LEFT_TYPE, RIGHT_TYPE, RESULT_TYPE>(
				    fun, lentry, rentry, mask, i);
			}
		}
	}

	template <class LEFT_TYPE, class RIGHT_TYPE, class RESULT_TYPE, class OPWRAPPER, class OP, class FUNC>
	static void ExecuteConstant(Vector &left, Vector &right, Vector &result, FUNC fun) {
		result.SetVectorType(VectorType::CONSTANT_VECTOR);

		auto ldata = ConstantVector::GetData<LEFT_TYPE>(left);
		auto rdata = ConstantVector::GetData<RIGHT_TYPE>(right);
		auto result_data = ConstantVector::GetData<RESULT_TYPE>(result);

		if (ConstantVector::IsNull(left) || ConstantVector::IsNull(right)) {
			ConstantVector::SetNull(result, true);
			return;
		}
		*result_data = OPWRAPPER::template Operation<FUNC, OP, LEFT_TYPE, RIGHT_TYPE, RESULT_TYPE>(
		    fun, *ldata, *rdata, ConstantVector::Validity(result), 0);
	}

	template <class LEFT_TYPE, class RIGHT_TYPE, class RESULT_TYPE, class OPWRAPPER, class OP, class FUNC,
	          bool LEFT_CONSTANT, bool RIGHT_CONSTANT>
	static void ExecuteFlat(Vector &left, Vector &right, Vector &result, idx_t count, FUNC fun) {
		auto ldata = FlatVector::GetData<LEFT_TYPE>(left);
		auto rdata = FlatVector::GetData<RIGHT_TYPE>(right);

		if ((LEFT_CONSTANT && ConstantVector::IsNull(left)) || (RIGHT_CONSTANT && ConstantVector::IsNull(right))) {
			// either left or right is constant NULL: result is constant NULL
			result.SetVectorType(VectorType::CONSTANT_VECTOR);
			ConstantVector::SetNull(result, true);
			return;
		}

		result.SetVectorType(VectorType::FLAT_VECTOR);
		auto result_data = FlatVector::GetData<RESULT_TYPE>(result);
		auto &result_validity = FlatVector::Validity(result);
		if (LEFT_CONSTANT) {
			if (OPWRAPPER::AddsNulls()) {
				result_validity.Copy(FlatVector::Validity(right), count);
			} else {
				FlatVector::SetValidity(result, FlatVector::Validity(right));
			}
		} else if (RIGHT_CONSTANT) {
			if (OPWRAPPER::AddsNulls()) {
				result_validity.Copy(FlatVector::Validity(left), count);
			} else {
				FlatVector::SetValidity(result, FlatVector::Validity(left));
			}
		} else {
			if (OPWRAPPER::AddsNulls()) {
				result_validity.Copy(FlatVector::Validity(left), count);
				if (result_validity.AllValid()) {
					result_validity.Copy(FlatVector::Validity(right), count);
				} else {
					result_validity.Combine(FlatVector::Validity(right), count);
				}
			} else {
				FlatVector::SetValidity(result, FlatVector::Validity(left));
				result_validity.Combine(FlatVector::Validity(right), count);
			}
		}
		ExecuteFlatLoop<LEFT_TYPE, RIGHT_TYPE, RESULT_TYPE, OPWRAPPER, OP, FUNC, LEFT_CONSTANT, RIGHT_CONSTANT>(
		    ldata, rdata, result_data, count, result_validity, fun);
	}

	template <class LEFT_TYPE, class RIGHT_TYPE, class RESULT_TYPE, class OPWRAPPER, class OP, class FUNC>
	static void ExecuteGenericLoop(const LEFT_TYPE *__restrict ldata, const RIGHT_TYPE *__restrict rdata,
	                               RESULT_TYPE *__restrict result_data, const SelectionVector *__restrict lsel,
	                               const SelectionVector *__restrict rsel, idx_t count, ValidityMask &lvalidity,
	                               ValidityMask &rvalidity, ValidityMask &result_validity, FUNC fun) {
		if (!lvalidity.AllValid() || !rvalidity.AllValid()) {
			for (idx_t i = 0; i < count; i++) {
				auto lindex = lsel->get_index(i);
				auto rindex = rsel->get_index(i);
				if (lvalidity.RowIsValid(lindex) && rvalidity.RowIsValid(rindex)) {
					auto lentry = ldata[lindex];
					auto rentry = rdata[rindex];
					result_data[i] = OPWRAPPER::template Operation<FUNC, OP, LEFT_TYPE, RIGHT_TYPE, RESULT_TYPE>(
					    fun, lentry, rentry, result_validity, i);
				} else {
					result_validity.SetInvalid(i);
				}
			}
		} else {
			for (idx_t i = 0; i < count; i++) {
				auto lentry = ldata[lsel->get_index(i)];
				auto rentry = rdata[rsel->get_index(i)];
				result_data[i] = OPWRAPPER::template Operation<FUNC, OP, LEFT_TYPE, RIGHT_TYPE, RESULT_TYPE>(
				    fun, lentry, rentry, result_validity, i);
			}
		}
	}

	template <class LEFT_TYPE, class RIGHT_TYPE, class RESULT_TYPE, class OPWRAPPER, class OP, class FUNC>
	static void ExecuteGeneric(Vector &left, Vector &right, Vector &result, idx_t count, FUNC fun) {
		UnifiedVectorFormat ldata, rdata;

		left.ToUnifiedFormat(count, ldata);
		right.ToUnifiedFormat(count, rdata);

		result.SetVectorType(VectorType::FLAT_VECTOR);
		auto result_data = FlatVector::GetData<RESULT_TYPE>(result);
		ExecuteGenericLoop<LEFT_TYPE, RIGHT_TYPE, RESULT_TYPE, OPWRAPPER, OP, FUNC>(
		    UnifiedVectorFormat::GetData<LEFT_TYPE>(ldata), UnifiedVectorFormat::GetData<RIGHT_TYPE>(rdata),
		    result_data, ldata.sel, rdata.sel, count, ldata.validity, rdata.validity, FlatVector::Validity(result),
		    fun);
	}

	template <class LEFT_TYPE, class RIGHT_TYPE, class RESULT_TYPE, class OPWRAPPER, class OP, class FUNC>
	static void ExecuteSwitch(Vector &left, Vector &right, Vector &result, idx_t count, FUNC fun) {
		auto left_vector_type = left.GetVectorType();
		auto right_vector_type = right.GetVectorType();
		if (left_vector_type == VectorType::CONSTANT_VECTOR && right_vector_type == VectorType::CONSTANT_VECTOR) {
			ExecuteConstant<LEFT_TYPE, RIGHT_TYPE, RESULT_TYPE, OPWRAPPER, OP, FUNC>(left, right, result, fun);
		} else if (left_vector_type == VectorType::FLAT_VECTOR && right_vector_type == VectorType::CONSTANT_VECTOR) {
			ExecuteFlat<LEFT_TYPE, RIGHT_TYPE, RESULT_TYPE, OPWRAPPER, OP, FUNC, false, true>(left, right, result,
			                                                                                  count, fun);
		} else if (left_vector_type == VectorType::CONSTANT_VECTOR && right_vector_type == VectorType::FLAT_VECTOR) {
			ExecuteFlat<LEFT_TYPE, RIGHT_TYPE, RESULT_TYPE, OPWRAPPER, OP, FUNC, true, false>(left, right, result,
			                                                                                  count, fun);
		} else if (left_vector_type == VectorType::FLAT_VECTOR && right_vector_type == VectorType::FLAT_VECTOR) {
			ExecuteFlat<LEFT_TYPE, RIGHT_TYPE, RESULT_TYPE, OPWRAPPER, OP, FUNC, false, false>(left, right, result,
			                                                                                   count, fun);
		} else {
			ExecuteGeneric<LEFT_TYPE, RIGHT_TYPE, RESULT_TYPE, OPWRAPPER, OP, FUNC>(left, right, result, count, fun);
		}
	}

public:
	template <class LEFT_TYPE, class RIGHT_TYPE, class RESULT_TYPE,
	          class FUNC = std::function<RESULT_TYPE(LEFT_TYPE, RIGHT_TYPE)>>
	static void Execute(Vector &left, Vector &right, Vector &result, idx_t count, FUNC fun) {
		ExecuteSwitch<LEFT_TYPE, RIGHT_TYPE, RESULT_TYPE, BinaryLambdaWrapper, bool, FUNC>(left, right, result, count,
		                                                                                   fun);
	}

	template <class LEFT_TYPE, class RIGHT_TYPE, class RESULT_TYPE, class OP,
	          class OPWRAPPER = BinarySingleArgumentOperatorWrapper>
	static void Execute(Vector &left, Vector &right, Vector &result, idx_t count) {
		ExecuteSwitch<LEFT_TYPE, RIGHT_TYPE, RESULT_TYPE, OPWRAPPER, OP, bool>(left, right, result, count, false);
	}

	template <class LEFT_TYPE, class RIGHT_TYPE, class RESULT_TYPE, class OP>
	static void ExecuteStandard(Vector &left, Vector &right, Vector &result, idx_t count) {
		ExecuteSwitch<LEFT_TYPE, RIGHT_TYPE, RESULT_TYPE, BinaryStandardOperatorWrapper, OP, bool>(left, right, result,
		                                                                                           count, false);
	}

	template <class LEFT_TYPE, class RIGHT_TYPE, class RESULT_TYPE,
	          class FUNC = std::function<RESULT_TYPE(LEFT_TYPE, RIGHT_TYPE, ValidityMask &, idx_t)>>
	static void ExecuteWithNulls(Vector &left, Vector &right, Vector &result, idx_t count, FUNC fun) {
		ExecuteSwitch<LEFT_TYPE, RIGHT_TYPE, RESULT_TYPE, BinaryLambdaWrapperWithNulls, bool, FUNC>(left, right, result,
		                                                                                            count, fun);
	}

public:
	template <class LEFT_TYPE, class RIGHT_TYPE, class OP>
	static idx_t SelectConstant(Vector &left, Vector &right, const SelectionVector *sel, idx_t count,
	                            SelectionVector *true_sel, SelectionVector *false_sel) {
		auto ldata = ConstantVector::GetData<LEFT_TYPE>(left);
		auto rdata = ConstantVector::GetData<RIGHT_TYPE>(right);

		// both sides are constant, return either 0 or the count
		// in this case we do not fill in the result selection vector at all
		if (ConstantVector::IsNull(left) || ConstantVector::IsNull(right) || !OP::Operation(*ldata, *rdata)) {
			if (false_sel) {
				for (idx_t i = 0; i < count; i++) {
					false_sel->set_index(i, sel->get_index(i));
				}
			}
			return 0;
		} else {
			if (true_sel) {
				for (idx_t i = 0; i < count; i++) {
					true_sel->set_index(i, sel->get_index(i));
				}
			}
			return count;
		}
	}

	template <class LEFT_TYPE, class RIGHT_TYPE, class OP, bool LEFT_CONSTANT, bool RIGHT_CONSTANT, bool HAS_TRUE_SEL,
	          bool HAS_FALSE_SEL>
	static inline idx_t SelectFlatLoop(const LEFT_TYPE *__restrict ldata, const RIGHT_TYPE *__restrict rdata,
	                                   const SelectionVector *sel, idx_t count, ValidityMask &validity_mask,
	                                   SelectionVector *true_sel, SelectionVector *false_sel) {
		idx_t true_count = 0, false_count = 0;
		idx_t base_idx = 0;
		auto entry_count = ValidityMask::EntryCount(count);
		for (idx_t entry_idx = 0; entry_idx < entry_count; entry_idx++) {
			auto validity_entry = validity_mask.GetValidityEntry(entry_idx);
			idx_t next = MinValue<idx_t>(base_idx + ValidityMask::BITS_PER_VALUE, count);
			if (ValidityMask::AllValid(validity_entry)) {
				// all valid: perform operation
				for (; base_idx < next; base_idx++) {
					idx_t result_idx = sel->get_index(base_idx);
					idx_t lidx = LEFT_CONSTANT ? 0 : base_idx;
					idx_t ridx = RIGHT_CONSTANT ? 0 : base_idx;
					bool comparison_result = OP::Operation(ldata[lidx], rdata[ridx]);
					if (HAS_TRUE_SEL) {
						true_sel->set_index(true_count, result_idx);
						true_count += comparison_result;
					}
					if (HAS_FALSE_SEL) {
						false_sel->set_index(false_count, result_idx);
						false_count += !comparison_result;
					}
				}
			} else if (ValidityMask::NoneValid(validity_entry)) {
				// nothing valid: skip all
				if (HAS_FALSE_SEL) {
					for (; base_idx < next; base_idx++) {
						idx_t result_idx = sel->get_index(base_idx);
						false_sel->set_index(false_count, result_idx);
						false_count++;
					}
				}
				base_idx = next;
				continue;
			} else {
				// partially valid: need to check individual elements for validity
				idx_t start = base_idx;
				for (; base_idx < next; base_idx++) {
					idx_t result_idx = sel->get_index(base_idx);
					idx_t lidx = LEFT_CONSTANT ? 0 : base_idx;
					idx_t ridx = RIGHT_CONSTANT ? 0 : base_idx;
					bool comparison_result = ValidityMask::RowIsValid(validity_entry, base_idx - start) &&
					                         OP::Operation(ldata[lidx], rdata[ridx]);
					if (HAS_TRUE_SEL) {
						true_sel->set_index(true_count, result_idx);
						true_count += comparison_result;
					}
					if (HAS_FALSE_SEL) {
						false_sel->set_index(false_count, result_idx);
						false_count += !comparison_result;
					}
				}
			}
		}
		if (HAS_TRUE_SEL) {
			return true_count;
		} else {
			return count - false_count;
		}
	}

	template <class LEFT_TYPE, class RIGHT_TYPE, class OP, bool LEFT_CONSTANT, bool RIGHT_CONSTANT>
	static inline idx_t SelectFlatLoopSwitch(const LEFT_TYPE *__restrict ldata, const RIGHT_TYPE *__restrict rdata,
	                                         const SelectionVector *sel, idx_t count, ValidityMask &mask,
	                                         SelectionVector *true_sel, SelectionVector *false_sel) {
		if (true_sel && false_sel) {
			return SelectFlatLoop<LEFT_TYPE, RIGHT_TYPE, OP, LEFT_CONSTANT, RIGHT_CONSTANT, true, true>(
			    ldata, rdata, sel, count, mask, true_sel, false_sel);
		} else if (true_sel) {
			return SelectFlatLoop<LEFT_TYPE, RIGHT_TYPE, OP, LEFT_CONSTANT, RIGHT_CONSTANT, true, false>(
			    ldata, rdata, sel, count, mask, true_sel, false_sel);
		} else {
			D_ASSERT(false_sel);
			return SelectFlatLoop<LEFT_TYPE, RIGHT_TYPE, OP, LEFT_CONSTANT, RIGHT_CONSTANT, false, true>(
			    ldata, rdata, sel, count, mask, true_sel, false_sel);
		}
	}

	template <class LEFT_TYPE, class RIGHT_TYPE, class OP, bool LEFT_CONSTANT, bool RIGHT_CONSTANT>
	static idx_t SelectFlat(Vector &left, Vector &right, const SelectionVector *sel, idx_t count,
	                        SelectionVector *true_sel, SelectionVector *false_sel) {
		auto ldata = FlatVector::GetData<LEFT_TYPE>(left);
		auto rdata = FlatVector::GetData<RIGHT_TYPE>(right);

		if (LEFT_CONSTANT && ConstantVector::IsNull(left)) {
			if (false_sel) {
				for (idx_t i = 0; i < count; i++) {
					false_sel->set_index(i, sel->get_index(i));
				}
			}
			return 0;
		}
		if (RIGHT_CONSTANT && ConstantVector::IsNull(right)) {
			if (false_sel) {
				for (idx_t i = 0; i < count; i++) {
					false_sel->set_index(i, sel->get_index(i));
				}
			}
			return 0;
		}

		if (LEFT_CONSTANT) {
			return SelectFlatLoopSwitch<LEFT_TYPE, RIGHT_TYPE, OP, LEFT_CONSTANT, RIGHT_CONSTANT>(
			    ldata, rdata, sel, count, FlatVector::Validity(right), true_sel, false_sel);
		} else if (RIGHT_CONSTANT) {
			return SelectFlatLoopSwitch<LEFT_TYPE, RIGHT_TYPE, OP, LEFT_CONSTANT, RIGHT_CONSTANT>(
			    ldata, rdata, sel, count, FlatVector::Validity(left), true_sel, false_sel);
		} else {
			ValidityMask combined_mask = FlatVector::Validity(left);
			combined_mask.Combine(FlatVector::Validity(right), count);
			return SelectFlatLoopSwitch<LEFT_TYPE, RIGHT_TYPE, OP, LEFT_CONSTANT, RIGHT_CONSTANT>(
			    ldata, rdata, sel, count, combined_mask, true_sel, false_sel);
		}
	}

	template <class LEFT_TYPE, class RIGHT_TYPE, class OP, bool NO_NULL, bool HAS_TRUE_SEL, bool HAS_FALSE_SEL>
	static inline idx_t
	SelectGenericLoop(const LEFT_TYPE *__restrict ldata, const RIGHT_TYPE *__restrict rdata,
	                  const SelectionVector *__restrict lsel, const SelectionVector *__restrict rsel,
	                  const SelectionVector *__restrict result_sel, idx_t count, ValidityMask &lvalidity,
	                  ValidityMask &rvalidity, SelectionVector *true_sel, SelectionVector *false_sel) {
		idx_t true_count = 0, false_count = 0;
		for (idx_t i = 0; i < count; i++) {
			auto result_idx = result_sel->get_index(i);
			auto lindex = lsel->get_index(i);
			auto rindex = rsel->get_index(i);
			if ((NO_NULL || (lvalidity.RowIsValid(lindex) && rvalidity.RowIsValid(rindex))) &&
			    OP::Operation(ldata[lindex], rdata[rindex])) {
				if (HAS_TRUE_SEL) {
					true_sel->set_index(true_count++, result_idx);
				}
			} else {
				if (HAS_FALSE_SEL) {
					false_sel->set_index(false_count++, result_idx);
				}
			}
		}
		if (HAS_TRUE_SEL) {
			return true_count;
		} else {
			return count - false_count;
		}
	}
	template <class LEFT_TYPE, class RIGHT_TYPE, class OP, bool NO_NULL>
	static inline idx_t
	SelectGenericLoopSelSwitch(const LEFT_TYPE *__restrict ldata, const RIGHT_TYPE *__restrict rdata,
	                           const SelectionVector *__restrict lsel, const SelectionVector *__restrict rsel,
	                           const SelectionVector *__restrict result_sel, idx_t count, ValidityMask &lvalidity,
	                           ValidityMask &rvalidity, SelectionVector *true_sel, SelectionVector *false_sel) {
		if (true_sel && false_sel) {
			return SelectGenericLoop<LEFT_TYPE, RIGHT_TYPE, OP, NO_NULL, true, true>(
			    ldata, rdata, lsel, rsel, result_sel, count, lvalidity, rvalidity, true_sel, false_sel);
		} else if (true_sel) {
			return SelectGenericLoop<LEFT_TYPE, RIGHT_TYPE, OP, NO_NULL, true, false>(
			    ldata, rdata, lsel, rsel, result_sel, count, lvalidity, rvalidity, true_sel, false_sel);
		} else {
			D_ASSERT(false_sel);
			return SelectGenericLoop<LEFT_TYPE, RIGHT_TYPE, OP, NO_NULL, false, true>(
			    ldata, rdata, lsel, rsel, result_sel, count, lvalidity, rvalidity, true_sel, false_sel);
		}
	}

	template <class LEFT_TYPE, class RIGHT_TYPE, class OP>
	static inline idx_t
	SelectGenericLoopSwitch(const LEFT_TYPE *__restrict ldata, const RIGHT_TYPE *__restrict rdata,
	                        const SelectionVector *__restrict lsel, const SelectionVector *__restrict rsel,
	                        const SelectionVector *__restrict result_sel, idx_t count, ValidityMask &lvalidity,
	                        ValidityMask &rvalidity, SelectionVector *true_sel, SelectionVector *false_sel) {
		if (!lvalidity.AllValid() || !rvalidity.AllValid()) {
			return SelectGenericLoopSelSwitch<LEFT_TYPE, RIGHT_TYPE, OP, false>(
			    ldata, rdata, lsel, rsel, result_sel, count, lvalidity, rvalidity, true_sel, false_sel);
		} else {
			return SelectGenericLoopSelSwitch<LEFT_TYPE, RIGHT_TYPE, OP, true>(
			    ldata, rdata, lsel, rsel, result_sel, count, lvalidity, rvalidity, true_sel, false_sel);
		}
	}

	template <class LEFT_TYPE, class RIGHT_TYPE, class OP>
	static idx_t SelectGeneric(Vector &left, Vector &right, const SelectionVector *sel, idx_t count,
	                           SelectionVector *true_sel, SelectionVector *false_sel) {
		UnifiedVectorFormat ldata, rdata;

		left.ToUnifiedFormat(count, ldata);
		right.ToUnifiedFormat(count, rdata);

		return SelectGenericLoopSwitch<LEFT_TYPE, RIGHT_TYPE, OP>(
		    UnifiedVectorFormat::GetData<LEFT_TYPE>(ldata), UnifiedVectorFormat::GetData<RIGHT_TYPE>(rdata), ldata.sel,
		    rdata.sel, sel, count, ldata.validity, rdata.validity, true_sel, false_sel);
	}

	template <class LEFT_TYPE, class RIGHT_TYPE, class OP>
	static idx_t Select(Vector &left, Vector &right, const SelectionVector *sel, idx_t count, SelectionVector *true_sel,
	                    SelectionVector *false_sel) {
		if (!sel) {
			sel = FlatVector::IncrementalSelectionVector();
		}
		if (left.GetVectorType() == VectorType::CONSTANT_VECTOR &&
		    right.GetVectorType() == VectorType::CONSTANT_VECTOR) {
			return SelectConstant<LEFT_TYPE, RIGHT_TYPE, OP>(left, right, sel, count, true_sel, false_sel);
		} else if (left.GetVectorType() == VectorType::CONSTANT_VECTOR &&
		           right.GetVectorType() == VectorType::FLAT_VECTOR) {
			return SelectFlat<LEFT_TYPE, RIGHT_TYPE, OP, true, false>(left, right, sel, count, true_sel, false_sel);
		} else if (left.GetVectorType() == VectorType::FLAT_VECTOR &&
		           right.GetVectorType() == VectorType::CONSTANT_VECTOR) {
			return SelectFlat<LEFT_TYPE, RIGHT_TYPE, OP, false, true>(left, right, sel, count, true_sel, false_sel);
		} else if (left.GetVectorType() == VectorType::FLAT_VECTOR &&
		           right.GetVectorType() == VectorType::FLAT_VECTOR) {
			return SelectFlat<LEFT_TYPE, RIGHT_TYPE, OP, false, false>(left, right, sel, count, true_sel, false_sel);
		} else {
			return SelectGeneric<LEFT_TYPE, RIGHT_TYPE, OP>(left, right, sel, count, true_sel, false_sel);
		}
	}
};

} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/vector_operations/ternary_executor.hpp
//
//
//===----------------------------------------------------------------------===//







#include <functional>

namespace duckdb {

template <class OP>
struct TernaryStandardOperatorWrapper {
	template <class FUN, class A_TYPE, class B_TYPE, class C_TYPE, class RESULT_TYPE>
	static inline RESULT_TYPE Operation(FUN fun, A_TYPE a, B_TYPE b, C_TYPE c, ValidityMask &mask, idx_t idx) {
		return OP::template Operation<A_TYPE, B_TYPE, C_TYPE, RESULT_TYPE>(a, b, c);
	}
};

struct TernaryLambdaWrapper {
	template <class FUN, class A_TYPE, class B_TYPE, class C_TYPE, class RESULT_TYPE>
	static inline RESULT_TYPE Operation(FUN fun, A_TYPE a, B_TYPE b, C_TYPE c, ValidityMask &mask, idx_t idx) {
		return fun(a, b, c);
	}
};

struct TernaryLambdaWrapperWithNulls {
	template <class FUN, class A_TYPE, class B_TYPE, class C_TYPE, class RESULT_TYPE>
	static inline RESULT_TYPE Operation(FUN fun, A_TYPE a, B_TYPE b, C_TYPE c, ValidityMask &mask, idx_t idx) {
		return fun(a, b, c, mask, idx);
	}
};

struct TernaryExecutor {
private:
	template <class A_TYPE, class B_TYPE, class C_TYPE, class RESULT_TYPE, class OPWRAPPER, class FUN>
	static inline void ExecuteLoop(const A_TYPE *__restrict adata, const B_TYPE *__restrict bdata,
	                               const C_TYPE *__restrict cdata, RESULT_TYPE *__restrict result_data, idx_t count,
	                               const SelectionVector &asel, const SelectionVector &bsel,
	                               const SelectionVector &csel, ValidityMask &avalidity, ValidityMask &bvalidity,
	                               ValidityMask &cvalidity, ValidityMask &result_validity, FUN fun) {
		if (!avalidity.AllValid() || !bvalidity.AllValid() || !cvalidity.AllValid()) {
			for (idx_t i = 0; i < count; i++) {
				auto aidx = asel.get_index(i);
				auto bidx = bsel.get_index(i);
				auto cidx = csel.get_index(i);
				if (avalidity.RowIsValid(aidx) && bvalidity.RowIsValid(bidx) && cvalidity.RowIsValid(cidx)) {
					result_data[i] = OPWRAPPER::template Operation<FUN, A_TYPE, B_TYPE, C_TYPE, RESULT_TYPE>(
					    fun, adata[aidx], bdata[bidx], cdata[cidx], result_validity, i);
				} else {
					result_validity.SetInvalid(i);
				}
			}
		} else {
			for (idx_t i = 0; i < count; i++) {
				auto aidx = asel.get_index(i);
				auto bidx = bsel.get_index(i);
				auto cidx = csel.get_index(i);
				result_data[i] = OPWRAPPER::template Operation<FUN, A_TYPE, B_TYPE, C_TYPE, RESULT_TYPE>(
				    fun, adata[aidx], bdata[bidx], cdata[cidx], result_validity, i);
			}
		}
	}

public:
	template <class A_TYPE, class B_TYPE, class C_TYPE, class RESULT_TYPE, class OPWRAPPER, class FUN>
	static void ExecuteGeneric(Vector &a, Vector &b, Vector &c, Vector &result, idx_t count, FUN fun) {
		if (a.GetVectorType() == VectorType::CONSTANT_VECTOR && b.GetVectorType() == VectorType::CONSTANT_VECTOR &&
		    c.GetVectorType() == VectorType::CONSTANT_VECTOR) {
			result.SetVectorType(VectorType::CONSTANT_VECTOR);
			if (ConstantVector::IsNull(a) || ConstantVector::IsNull(b) || ConstantVector::IsNull(c)) {
				ConstantVector::SetNull(result, true);
			} else {
				auto adata = ConstantVector::GetData<A_TYPE>(a);
				auto bdata = ConstantVector::GetData<B_TYPE>(b);
				auto cdata = ConstantVector::GetData<C_TYPE>(c);
				auto result_data = ConstantVector::GetData<RESULT_TYPE>(result);
				auto &result_validity = ConstantVector::Validity(result);
				result_data[0] = OPWRAPPER::template Operation<FUN, A_TYPE, B_TYPE, C_TYPE, RESULT_TYPE>(
				    fun, adata[0], bdata[0], cdata[0], result_validity, 0);
			}
		} else {
			result.SetVectorType(VectorType::FLAT_VECTOR);

			UnifiedVectorFormat adata, bdata, cdata;
			a.ToUnifiedFormat(count, adata);
			b.ToUnifiedFormat(count, bdata);
			c.ToUnifiedFormat(count, cdata);

			ExecuteLoop<A_TYPE, B_TYPE, C_TYPE, RESULT_TYPE, OPWRAPPER>(
			    UnifiedVectorFormat::GetData<A_TYPE>(adata), UnifiedVectorFormat::GetData<B_TYPE>(bdata),
			    UnifiedVectorFormat::GetData<C_TYPE>(cdata), FlatVector::GetData<RESULT_TYPE>(result), count,
			    *adata.sel, *bdata.sel, *cdata.sel, adata.validity, bdata.validity, cdata.validity,
			    FlatVector::Validity(result), fun);
		}
	}

	template <class A_TYPE, class B_TYPE, class C_TYPE, class RESULT_TYPE,
	          class FUN = std::function<RESULT_TYPE(A_TYPE, B_TYPE, C_TYPE)>>
	static void Execute(Vector &a, Vector &b, Vector &c, Vector &result, idx_t count, FUN fun) {
		ExecuteGeneric<A_TYPE, B_TYPE, C_TYPE, RESULT_TYPE, TernaryLambdaWrapper, FUN>(a, b, c, result, count, fun);
	}

	template <class A_TYPE, class B_TYPE, class C_TYPE, class RESULT_TYPE, class OP>
	static void ExecuteStandard(Vector &a, Vector &b, Vector &c, Vector &result, idx_t count) {
		ExecuteGeneric<A_TYPE, B_TYPE, C_TYPE, RESULT_TYPE, TernaryStandardOperatorWrapper<OP>, bool>(a, b, c, result,
		                                                                                              count, false);
	}

	template <class A_TYPE, class B_TYPE, class C_TYPE, class RESULT_TYPE,
	          class FUN = std::function<RESULT_TYPE(A_TYPE, B_TYPE, C_TYPE, ValidityMask &, idx_t)>>
	static void ExecuteWithNulls(Vector &a, Vector &b, Vector &c, Vector &result, idx_t count, FUN fun) {
		ExecuteGeneric<A_TYPE, B_TYPE, C_TYPE, RESULT_TYPE, TernaryLambdaWrapperWithNulls, FUN>(a, b, c, result, count,
		                                                                                        fun);
	}

private:
	template <class A_TYPE, class B_TYPE, class C_TYPE, class OP, bool NO_NULL, bool HAS_TRUE_SEL, bool HAS_FALSE_SEL>
	static inline idx_t SelectLoop(const A_TYPE *__restrict adata, const B_TYPE *__restrict bdata,
	                               const C_TYPE *__restrict cdata, const SelectionVector *result_sel, idx_t count,
	                               const SelectionVector &asel, const SelectionVector &bsel,
	                               const SelectionVector &csel, ValidityMask &avalidity, ValidityMask &bvalidity,
	                               ValidityMask &cvalidity, SelectionVector *true_sel, SelectionVector *false_sel) {
		idx_t true_count = 0, false_count = 0;
		for (idx_t i = 0; i < count; i++) {
			auto result_idx = result_sel->get_index(i);
			auto aidx = asel.get_index(i);
			auto bidx = bsel.get_index(i);
			auto cidx = csel.get_index(i);
			bool comparison_result =
			    (NO_NULL || (avalidity.RowIsValid(aidx) && bvalidity.RowIsValid(bidx) && cvalidity.RowIsValid(cidx))) &&
			    OP::Operation(adata[aidx], bdata[bidx], cdata[cidx]);
			if (HAS_TRUE_SEL) {
				true_sel->set_index(true_count, result_idx);
				true_count += comparison_result;
			}
			if (HAS_FALSE_SEL) {
				false_sel->set_index(false_count, result_idx);
				false_count += !comparison_result;
			}
		}
		if (HAS_TRUE_SEL) {
			return true_count;
		} else {
			return count - false_count;
		}
	}

	template <class A_TYPE, class B_TYPE, class C_TYPE, class OP, bool NO_NULL>
	static inline idx_t SelectLoopSelSwitch(UnifiedVectorFormat &adata, UnifiedVectorFormat &bdata,
	                                        UnifiedVectorFormat &cdata, const SelectionVector *sel, idx_t count,
	                                        SelectionVector *true_sel, SelectionVector *false_sel) {
		if (true_sel && false_sel) {
			return SelectLoop<A_TYPE, B_TYPE, C_TYPE, OP, NO_NULL, true, true>(
			    UnifiedVectorFormat::GetData<A_TYPE>(adata), UnifiedVectorFormat::GetData<B_TYPE>(bdata),
			    UnifiedVectorFormat::GetData<C_TYPE>(cdata), sel, count, *adata.sel, *bdata.sel, *cdata.sel,
			    adata.validity, bdata.validity, cdata.validity, true_sel, false_sel);
		} else if (true_sel) {
			return SelectLoop<A_TYPE, B_TYPE, C_TYPE, OP, NO_NULL, true, false>(
			    UnifiedVectorFormat::GetData<A_TYPE>(adata), UnifiedVectorFormat::GetData<B_TYPE>(bdata),
			    UnifiedVectorFormat::GetData<C_TYPE>(cdata), sel, count, *adata.sel, *bdata.sel, *cdata.sel,
			    adata.validity, bdata.validity, cdata.validity, true_sel, false_sel);
		} else {
			D_ASSERT(false_sel);
			return SelectLoop<A_TYPE, B_TYPE, C_TYPE, OP, NO_NULL, false, true>(
			    UnifiedVectorFormat::GetData<A_TYPE>(adata), UnifiedVectorFormat::GetData<B_TYPE>(bdata),
			    UnifiedVectorFormat::GetData<C_TYPE>(cdata), sel, count, *adata.sel, *bdata.sel, *cdata.sel,
			    adata.validity, bdata.validity, cdata.validity, true_sel, false_sel);
		}
	}

	template <class A_TYPE, class B_TYPE, class C_TYPE, class OP>
	static inline idx_t SelectLoopSwitch(UnifiedVectorFormat &adata, UnifiedVectorFormat &bdata,
	                                     UnifiedVectorFormat &cdata, const SelectionVector *sel, idx_t count,
	                                     SelectionVector *true_sel, SelectionVector *false_sel) {
		if (!adata.validity.AllValid() || !bdata.validity.AllValid() || !cdata.validity.AllValid()) {
			return SelectLoopSelSwitch<A_TYPE, B_TYPE, C_TYPE, OP, false>(adata, bdata, cdata, sel, count, true_sel,
			                                                              false_sel);
		} else {
			return SelectLoopSelSwitch<A_TYPE, B_TYPE, C_TYPE, OP, true>(adata, bdata, cdata, sel, count, true_sel,
			                                                             false_sel);
		}
	}

public:
	template <class A_TYPE, class B_TYPE, class C_TYPE, class OP>
	static idx_t Select(Vector &a, Vector &b, Vector &c, const SelectionVector *sel, idx_t count,
	                    SelectionVector *true_sel, SelectionVector *false_sel) {
		if (!sel) {
			sel = FlatVector::IncrementalSelectionVector();
		}
		UnifiedVectorFormat adata, bdata, cdata;
		a.ToUnifiedFormat(count, adata);
		b.ToUnifiedFormat(count, bdata);
		c.ToUnifiedFormat(count, cdata);

		return SelectLoopSwitch<A_TYPE, B_TYPE, C_TYPE, OP>(adata, bdata, cdata, sel, count, true_sel, false_sel);
	}
};

} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/vector_operations/unary_executor.hpp
//
//
//===----------------------------------------------------------------------===//







#include <functional>

namespace duckdb {

struct UnaryOperatorWrapper {
	template <class OP, class INPUT_TYPE, class RESULT_TYPE>
	static inline RESULT_TYPE Operation(INPUT_TYPE input, ValidityMask &mask, idx_t idx, void *dataptr) {
		return OP::template Operation<INPUT_TYPE, RESULT_TYPE>(input);
	}
};

struct UnaryLambdaWrapper {
	template <class FUNC, class INPUT_TYPE, class RESULT_TYPE>
	static inline RESULT_TYPE Operation(INPUT_TYPE input, ValidityMask &mask, idx_t idx, void *dataptr) {
		auto fun = (FUNC *)dataptr;
		return (*fun)(input);
	}
};

struct GenericUnaryWrapper {
	template <class OP, class INPUT_TYPE, class RESULT_TYPE>
	static inline RESULT_TYPE Operation(INPUT_TYPE input, ValidityMask &mask, idx_t idx, void *dataptr) {
		return OP::template Operation<INPUT_TYPE, RESULT_TYPE>(input, mask, idx, dataptr);
	}
};

struct UnaryLambdaWrapperWithNulls {
	template <class FUNC, class INPUT_TYPE, class RESULT_TYPE>
	static inline RESULT_TYPE Operation(INPUT_TYPE input, ValidityMask &mask, idx_t idx, void *dataptr) {
		auto fun = (FUNC *)dataptr;
		return (*fun)(input, mask, idx);
	}
};

template <class OP>
struct UnaryStringOperator {
	template <class INPUT_TYPE, class RESULT_TYPE>
	static RESULT_TYPE Operation(INPUT_TYPE input, ValidityMask &mask, idx_t idx, void *dataptr) {
		auto vector = reinterpret_cast<Vector *>(dataptr);
		return OP::template Operation<INPUT_TYPE, RESULT_TYPE>(input, *vector);
	}
};

struct UnaryExecutor {
private:
	template <class INPUT_TYPE, class RESULT_TYPE, class OPWRAPPER, class OP>
	static inline void ExecuteLoop(const INPUT_TYPE *__restrict ldata, RESULT_TYPE *__restrict result_data, idx_t count,
	                               const SelectionVector *__restrict sel_vector, ValidityMask &mask,
	                               ValidityMask &result_mask, void *dataptr, bool adds_nulls) {
#ifdef DEBUG
		// ldata may point to a compressed dictionary buffer which can be smaller than ldata + count
		idx_t max_index = 0;
		for (idx_t i = 0; i < count; i++) {
			auto idx = sel_vector->get_index(i);
			max_index = MaxValue(max_index, idx);
		}
		ASSERT_RESTRICT(ldata, ldata + max_index, result_data, result_data + count);
#endif

		if (!mask.AllValid()) {
			for (idx_t i = 0; i < count; i++) {
				auto idx = sel_vector->get_index(i);
				if (mask.RowIsValidUnsafe(idx)) {
					result_data[i] =
					    OPWRAPPER::template Operation<OP, INPUT_TYPE, RESULT_TYPE>(ldata[idx], result_mask, i, dataptr);
				} else {
					result_mask.SetInvalid(i);
				}
			}
		} else {
			for (idx_t i = 0; i < count; i++) {
				auto idx = sel_vector->get_index(i);
				result_data[i] =
				    OPWRAPPER::template Operation<OP, INPUT_TYPE, RESULT_TYPE>(ldata[idx], result_mask, i, dataptr);
			}
		}
	}

	template <class INPUT_TYPE, class RESULT_TYPE, class OPWRAPPER, class OP>
	static inline void ExecuteFlat(const INPUT_TYPE *__restrict ldata, RESULT_TYPE *__restrict result_data, idx_t count,
	                               ValidityMask &mask, ValidityMask &result_mask, void *dataptr, bool adds_nulls) {
		ASSERT_RESTRICT(ldata, ldata + count, result_data, result_data + count);

		if (!mask.AllValid()) {
			if (!adds_nulls) {
				result_mask.Initialize(mask);
			} else {
				result_mask.Copy(mask, count);
			}
			idx_t base_idx = 0;
			auto entry_count = ValidityMask::EntryCount(count);
			for (idx_t entry_idx = 0; entry_idx < entry_count; entry_idx++) {
				auto validity_entry = mask.GetValidityEntry(entry_idx);
				idx_t next = MinValue<idx_t>(base_idx + ValidityMask::BITS_PER_VALUE, count);
				if (ValidityMask::AllValid(validity_entry)) {
					// all valid: perform operation
					for (; base_idx < next; base_idx++) {
						result_data[base_idx] = OPWRAPPER::template Operation<OP, INPUT_TYPE, RESULT_TYPE>(
						    ldata[base_idx], result_mask, base_idx, dataptr);
					}
				} else if (ValidityMask::NoneValid(validity_entry)) {
					// nothing valid: skip all
					base_idx = next;
					continue;
				} else {
					// partially valid: need to check individual elements for validity
					idx_t start = base_idx;
					for (; base_idx < next; base_idx++) {
						if (ValidityMask::RowIsValid(validity_entry, base_idx - start)) {
							D_ASSERT(mask.RowIsValid(base_idx));
							result_data[base_idx] = OPWRAPPER::template Operation<OP, INPUT_TYPE, RESULT_TYPE>(
							    ldata[base_idx], result_mask, base_idx, dataptr);
						}
					}
				}
			}
		} else {
			for (idx_t i = 0; i < count; i++) {
				result_data[i] =
				    OPWRAPPER::template Operation<OP, INPUT_TYPE, RESULT_TYPE>(ldata[i], result_mask, i, dataptr);
			}
		}
	}

	template <class INPUT_TYPE, class RESULT_TYPE, class OPWRAPPER, class OP>
	static inline void ExecuteStandard(Vector &input, Vector &result, idx_t count, void *dataptr, bool adds_nulls) {
		switch (input.GetVectorType()) {
		case VectorType::CONSTANT_VECTOR: {
			result.SetVectorType(VectorType::CONSTANT_VECTOR);
			auto result_data = ConstantVector::GetData<RESULT_TYPE>(result);
			auto ldata = ConstantVector::GetData<INPUT_TYPE>(input);

			if (ConstantVector::IsNull(input)) {
				ConstantVector::SetNull(result, true);
			} else {
				ConstantVector::SetNull(result, false);
				*result_data = OPWRAPPER::template Operation<OP, INPUT_TYPE, RESULT_TYPE>(
				    *ldata, ConstantVector::Validity(result), 0, dataptr);
			}
			break;
		}
		case VectorType::FLAT_VECTOR: {
			result.SetVectorType(VectorType::FLAT_VECTOR);
			auto result_data = FlatVector::GetData<RESULT_TYPE>(result);
			auto ldata = FlatVector::GetData<INPUT_TYPE>(input);

			ExecuteFlat<INPUT_TYPE, RESULT_TYPE, OPWRAPPER, OP>(ldata, result_data, count, FlatVector::Validity(input),
			                                                    FlatVector::Validity(result), dataptr, adds_nulls);
			break;
		}
		default: {
			UnifiedVectorFormat vdata;
			input.ToUnifiedFormat(count, vdata);

			result.SetVectorType(VectorType::FLAT_VECTOR);
			auto result_data = FlatVector::GetData<RESULT_TYPE>(result);
			auto ldata = UnifiedVectorFormat::GetData<INPUT_TYPE>(vdata);

			ExecuteLoop<INPUT_TYPE, RESULT_TYPE, OPWRAPPER, OP>(ldata, result_data, count, vdata.sel, vdata.validity,
			                                                    FlatVector::Validity(result), dataptr, adds_nulls);
			break;
		}
		}
	}

public:
	template <class INPUT_TYPE, class RESULT_TYPE, class OP>
	static void Execute(Vector &input, Vector &result, idx_t count) {
		ExecuteStandard<INPUT_TYPE, RESULT_TYPE, UnaryOperatorWrapper, OP>(input, result, count, nullptr, false);
	}

	template <class INPUT_TYPE, class RESULT_TYPE, class FUNC = std::function<RESULT_TYPE(INPUT_TYPE)>>
	static void Execute(Vector &input, Vector &result, idx_t count, FUNC fun) {
		ExecuteStandard<INPUT_TYPE, RESULT_TYPE, UnaryLambdaWrapper, FUNC>(input, result, count,
		                                                                   reinterpret_cast<void *>(&fun), false);
	}

	template <class INPUT_TYPE, class RESULT_TYPE, class OP>
	static void GenericExecute(Vector &input, Vector &result, idx_t count, void *dataptr, bool adds_nulls = false) {
		ExecuteStandard<INPUT_TYPE, RESULT_TYPE, GenericUnaryWrapper, OP>(input, result, count, dataptr, adds_nulls);
	}

	template <class INPUT_TYPE, class RESULT_TYPE,
	          class FUNC = std::function<RESULT_TYPE(INPUT_TYPE, ValidityMask &, idx_t)>>
	static void ExecuteWithNulls(Vector &input, Vector &result, idx_t count, FUNC fun) {
		ExecuteStandard<INPUT_TYPE, RESULT_TYPE, UnaryLambdaWrapperWithNulls, FUNC>(input, result, count, (void *)&fun,
		                                                                            true);
	}

	template <class INPUT_TYPE, class RESULT_TYPE, class OP>
	static void ExecuteString(Vector &input, Vector &result, idx_t count) {
		UnaryExecutor::GenericExecute<INPUT_TYPE, RESULT_TYPE, UnaryStringOperator<OP>>(input, result, count,
		                                                                                (void *)&result);
	}
};

} // namespace duckdb


//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/expression_executor_state.hpp
//
//
//===----------------------------------------------------------------------===//





//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/function/function.hpp
//
//
//===----------------------------------------------------------------------===//



//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/named_parameter_map.hpp
//
//
//===----------------------------------------------------------------------===//



//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/case_insensitive_map.hpp
//
//
//===----------------------------------------------------------------------===//










namespace duckdb {

struct CaseInsensitiveStringHashFunction {
	uint64_t operator()(const string &str) const {
		return StringUtil::CIHash(str);
	}
};

struct CaseInsensitiveStringEquality {
	bool operator()(const string &a, const string &b) const {
		return StringUtil::CIEquals(a, b);
	}
};

template <typename T>
using case_insensitive_map_t =
    unordered_map<string, T, CaseInsensitiveStringHashFunction, CaseInsensitiveStringEquality>;

using case_insensitive_set_t = unordered_set<string, CaseInsensitiveStringHashFunction, CaseInsensitiveStringEquality>;

struct CaseInsensitiveStringCompare {
	bool operator()(const string &s1, const string &s2) const {
		return StringUtil::CILessThan(s1, s2);
	}
};

template <typename T>
using case_insensitive_tree_t = map<string, T, CaseInsensitiveStringCompare>;

} // namespace duckdb


namespace duckdb {

using named_parameter_type_map_t = case_insensitive_map_t<LogicalType>;
using named_parameter_map_t = case_insensitive_map_t<Value>;

} // namespace duckdb



//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/main/external_dependencies.hpp
//
//
//===----------------------------------------------------------------------===//


#include <functional>



namespace duckdb {

class DependencyItem {
public:
	virtual ~DependencyItem() {};

public:
	template <class TARGET>
	TARGET &Cast() {
		DynamicCastCheck<TARGET>(this);
		return reinterpret_cast<TARGET &>(*this);
	}
	template <class TARGET>
	const TARGET &Cast() const {
		DynamicCastCheck<TARGET>(this);
		return reinterpret_cast<const TARGET &>(*this);
	}
};

using dependency_scan_t = std::function<void(const string &name, shared_ptr<DependencyItem> item)>;

class ExternalDependency {
public:
	explicit ExternalDependency() {
	}
	~ExternalDependency() {
	}

public:
	void AddDependency(const string &name, shared_ptr<DependencyItem> item) {
		objects[name] = std::move(item);
	}
	shared_ptr<DependencyItem> GetDependency(const string &name) const {
		auto it = objects.find(name);
		if (it == objects.end()) {
			return nullptr;
		}
		return it->second;
	}
	void ScanDependencies(const dependency_scan_t &callback) {
		for (auto &kv : objects) {
			callback(kv.first, kv.second);
		}
	}

private:
	//! The objects encompassed by this dependency
	case_insensitive_map_t<shared_ptr<DependencyItem>> objects;
};

} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/parser/column_definition.hpp
//
//
//===----------------------------------------------------------------------===//





//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/parser/parsed_expression.hpp
//
//
//===----------------------------------------------------------------------===//



//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/parser/base_expression.hpp
//
//
//===----------------------------------------------------------------------===//




//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/enums/expression_type.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

//===--------------------------------------------------------------------===//
// Predicate Expression Operation Types
//===--------------------------------------------------------------------===//
enum class ExpressionType : uint8_t {
	INVALID = 0,

	// explicitly cast left as right (right is integer in ValueType enum)
	OPERATOR_CAST = 12,
	// logical not operator
	OPERATOR_NOT = 13,
	// is null operator
	OPERATOR_IS_NULL = 14,
	// is not null operator
	OPERATOR_IS_NOT_NULL = 15,

	// -----------------------------
	// Comparison Operators
	// -----------------------------
	// equal operator between left and right
	COMPARE_EQUAL = 25,
	// compare initial boundary
	COMPARE_BOUNDARY_START = COMPARE_EQUAL,
	// inequal operator between left and right
	COMPARE_NOTEQUAL = 26,
	// less than operator between left and right
	COMPARE_LESSTHAN = 27,
	// greater than operator between left and right
	COMPARE_GREATERTHAN = 28,
	// less than equal operator between left and right
	COMPARE_LESSTHANOREQUALTO = 29,
	// greater than equal operator between left and right
	COMPARE_GREATERTHANOREQUALTO = 30,
	// IN operator [left IN (right1, right2, ...)]
	COMPARE_IN = 35,
	// NOT IN operator [left NOT IN (right1, right2, ...)]
	COMPARE_NOT_IN = 36,
	// IS DISTINCT FROM operator
	COMPARE_DISTINCT_FROM = 37,

	COMPARE_BETWEEN = 38,
	COMPARE_NOT_BETWEEN = 39,
	// IS NOT DISTINCT FROM operator
	COMPARE_NOT_DISTINCT_FROM = 40,
	// compare final boundary
	COMPARE_BOUNDARY_END = COMPARE_NOT_DISTINCT_FROM,

	// -----------------------------
	// Conjunction Operators
	// -----------------------------
	CONJUNCTION_AND = 50,
	CONJUNCTION_OR = 51,

	// -----------------------------
	// Values
	// -----------------------------
	VALUE_CONSTANT = 75,
	VALUE_PARAMETER = 76,
	VALUE_TUPLE = 77,
	VALUE_TUPLE_ADDRESS = 78,
	VALUE_NULL = 79,
	VALUE_VECTOR = 80,
	VALUE_SCALAR = 81,
	VALUE_DEFAULT = 82,

	// -----------------------------
	// Aggregates
	// -----------------------------
	AGGREGATE = 100,
	BOUND_AGGREGATE = 101,
	GROUPING_FUNCTION = 102,

	// -----------------------------
	// Window Functions
	// -----------------------------
	WINDOW_AGGREGATE = 110,

	WINDOW_RANK = 120,
	WINDOW_RANK_DENSE = 121,
	WINDOW_NTILE = 122,
	WINDOW_PERCENT_RANK = 123,
	WINDOW_CUME_DIST = 124,
	WINDOW_ROW_NUMBER = 125,

	WINDOW_FIRST_VALUE = 130,
	WINDOW_LAST_VALUE = 131,
	WINDOW_LEAD = 132,
	WINDOW_LAG = 133,
	WINDOW_NTH_VALUE = 134,

	// -----------------------------
	// Functions
	// -----------------------------
	FUNCTION = 140,
	BOUND_FUNCTION = 141,

	// -----------------------------
	// Operators
	// -----------------------------
	CASE_EXPR = 150,
	OPERATOR_NULLIF = 151,
	OPERATOR_COALESCE = 152,
	ARRAY_EXTRACT = 153,
	ARRAY_SLICE = 154,
	STRUCT_EXTRACT = 155,
	ARRAY_CONSTRUCTOR = 156,
	ARROW = 157,

	// -----------------------------
	// Subquery IN/EXISTS
	// -----------------------------
	SUBQUERY = 175,

	// -----------------------------
	// Parser
	// -----------------------------
	STAR = 200,
	TABLE_STAR = 201,
	PLACEHOLDER = 202,
	COLUMN_REF = 203,
	FUNCTION_REF = 204,
	TABLE_REF = 205,
	LAMBDA_REF = 206,

	// -----------------------------
	// Miscellaneous
	// -----------------------------
	CAST = 225,
	BOUND_REF = 227,
	BOUND_COLUMN_REF = 228,
	BOUND_UNNEST = 229,
	COLLATE = 230,
	LAMBDA = 231,
	POSITIONAL_REFERENCE = 232,
	BOUND_LAMBDA_REF = 233,
	BOUND_EXPANDED = 234
};

//===--------------------------------------------------------------------===//
// Expression Class
//===--------------------------------------------------------------------===//
enum class ExpressionClass : uint8_t {
	INVALID = 0,
	//===--------------------------------------------------------------------===//
	// Parsed Expressions
	//===--------------------------------------------------------------------===//
	AGGREGATE = 1,
	CASE = 2,
	CAST = 3,
	COLUMN_REF = 4,
	COMPARISON = 5,
	CONJUNCTION = 6,
	CONSTANT = 7,
	DEFAULT = 8,
	FUNCTION = 9,
	OPERATOR = 10,
	STAR = 11,
	SUBQUERY = 13,
	WINDOW = 14,
	PARAMETER = 15,
	COLLATE = 16,
	LAMBDA = 17,
	POSITIONAL_REFERENCE = 18,
	BETWEEN = 19,
	LAMBDA_REF = 20,
	//===--------------------------------------------------------------------===//
	// Bound Expressions
	//===--------------------------------------------------------------------===//
	BOUND_AGGREGATE = 25,
	BOUND_CASE = 26,
	BOUND_CAST = 27,
	BOUND_COLUMN_REF = 28,
	BOUND_COMPARISON = 29,
	BOUND_CONJUNCTION = 30,
	BOUND_CONSTANT = 31,
	BOUND_DEFAULT = 32,
	BOUND_FUNCTION = 33,
	BOUND_OPERATOR = 34,
	BOUND_PARAMETER = 35,
	BOUND_REF = 36,
	BOUND_SUBQUERY = 37,
	BOUND_WINDOW = 38,
	BOUND_BETWEEN = 39,
	BOUND_UNNEST = 40,
	BOUND_LAMBDA = 41,
	BOUND_LAMBDA_REF = 42,
	//===--------------------------------------------------------------------===//
	// Miscellaneous
	//===--------------------------------------------------------------------===//
	BOUND_EXPRESSION = 50,
	BOUND_EXPANDED = 51
};

DUCKDB_API string ExpressionTypeToString(ExpressionType type);
string ExpressionTypeToOperator(ExpressionType type);

// Operator String to ExpressionType (e.g. + => OPERATOR_ADD)
ExpressionType OperatorToExpressionType(const string &op);
//! Negate a comparison expression, turning e.g. = into !=, or < into >=
ExpressionType NegateComparisonExpression(ExpressionType type);
//! Flip a comparison expression, turning e.g. < into >, or = into =
ExpressionType FlipComparisonExpression(ExpressionType type);

DUCKDB_API string ExpressionClassToString(ExpressionClass type);

} // namespace duckdb




namespace duckdb {

//!  The BaseExpression class is a base class that can represent any expression
//!  part of a SQL statement.
class BaseExpression {
public:
	//! Create an Expression
	BaseExpression(ExpressionType type, ExpressionClass expression_class)
	    : type(type), expression_class(expression_class) {
	}
	virtual ~BaseExpression() {
	}

	//! Returns the type of the expression
	ExpressionType GetExpressionType() const {
		return type;
	}
	//! Returns the class of the expression
	ExpressionClass GetExpressionClass() const {
		return expression_class;
	}

	//! Type of the expression
	ExpressionType type;
	//! The expression class of the node
	ExpressionClass expression_class;
	//! The alias of the expression,
	string alias;
	//! The location in the query (if any)
	optional_idx query_location;

public:
	//! Returns true if this expression is an aggregate or not.
	/*!
	 Examples:

	 (1) SUM(a) + 1 -- True

	 (2) a + 1 -- False
	 */
	virtual bool IsAggregate() const = 0;
	//! Returns true if the expression has a window function or not
	virtual bool IsWindow() const = 0;
	//! Returns true if the query contains a subquery
	virtual bool HasSubquery() const = 0;
	//! Returns true if expression does not contain a group ref or col ref or parameter
	virtual bool IsScalar() const = 0;
	//! Returns true if the expression has a parameter
	virtual bool HasParameter() const = 0;

	//! Get the name of the expression
	virtual string GetName() const;
	//! Convert the Expression to a String
	virtual string ToString() const = 0;
	//! Print the expression to stdout
	void Print() const;

	//! Creates a hash value of this expression. It is important that if two expressions are identical (i.e.
	//! Expression::Equals() returns true), that their hash value is identical as well.
	virtual hash_t Hash() const = 0;
	//! Returns true if this expression is equal to another expression
	virtual bool Equals(const BaseExpression &other) const;

	static bool Equals(const BaseExpression &left, const BaseExpression &right) {
		return left.Equals(right);
	}
	bool operator==(const BaseExpression &rhs) const {
		return Equals(rhs);
	}

	virtual void Verify() const;

public:
	template <class TARGET>
	TARGET &Cast() {
		if (expression_class != TARGET::TYPE) {
			throw InternalException("Failed to cast expression to type - expression type mismatch");
		}
		return reinterpret_cast<TARGET &>(*this);
	}

	template <class TARGET>
	const TARGET &Cast() const {
		if (expression_class != TARGET::TYPE) {
			throw InternalException("Failed to cast expression to type - expression type mismatch");
		}
		return reinterpret_cast<const TARGET &>(*this);
	}
};

} // namespace duckdb



//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/parser/qualified_name.hpp
//
//
//===----------------------------------------------------------------------===//




//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/exception/parser_exception.hpp
//
//
//===----------------------------------------------------------------------===//







namespace duckdb {

class ParserException : public Exception {
public:
	DUCKDB_API explicit ParserException(const string &msg);
	DUCKDB_API explicit ParserException(const string &msg, const unordered_map<string, string> &extra_info);

	template <typename... ARGS>
	explicit ParserException(const string &msg, ARGS... params) : ParserException(ConstructMessage(msg, params...)) {
	}
	template <typename... ARGS>
	explicit ParserException(optional_idx error_location, const string &msg, ARGS... params)
	    : ParserException(ConstructMessage(msg, params...), Exception::InitializeExtraInfo(error_location)) {
	}

	static ParserException SyntaxError(const string &query, const string &error_message, optional_idx error_location);
};

} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/parser/keyword_helper.hpp
//
//
//===----------------------------------------------------------------------===//




//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/parser/simplified_token.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

//! Simplified tokens are a simplified (dense) representation of the lexer
//! Used for simple syntax highlighting in the tests
enum class SimplifiedTokenType : uint8_t {
	SIMPLIFIED_TOKEN_IDENTIFIER,
	SIMPLIFIED_TOKEN_NUMERIC_CONSTANT,
	SIMPLIFIED_TOKEN_STRING_CONSTANT,
	SIMPLIFIED_TOKEN_OPERATOR,
	SIMPLIFIED_TOKEN_KEYWORD,
	SIMPLIFIED_TOKEN_COMMENT
};

struct SimplifiedToken {
	SimplifiedTokenType type;
	idx_t start;
};

enum class KeywordCategory : uint8_t {
	KEYWORD_RESERVED,
	KEYWORD_UNRESERVED,
	KEYWORD_TYPE_FUNC,
	KEYWORD_COL_NAME,
	KEYWORD_NONE
};

struct ParserKeyword {
	string name;
	KeywordCategory category;
};

} // namespace duckdb


namespace duckdb {

class KeywordHelper {
public:
	//! Returns true if the given text matches a keyword of the parser
	static bool IsKeyword(const string &text);

	static KeywordCategory KeywordCategoryType(const string &text);

	static string EscapeQuotes(const string &text, char quote = '"');

	//! Returns true if the given string needs to be quoted when written as an identifier
	static bool RequiresQuotes(const string &text, bool allow_caps = true);

	//! Writes a string that is quoted
	static string WriteQuoted(const string &text, char quote = '\'');

	//! Writes a string that is optionally quoted + escaped so it can be used as an identifier
	static string WriteOptionallyQuoted(const string &text, char quote = '"', bool allow_caps = true);
};

} // namespace duckdb



namespace duckdb {

struct QualifiedName {
	string catalog;
	string schema;
	string name;

	//! Parse the (optional) schema and a name from a string in the format of e.g. "schema"."table"; if there is no dot
	//! the schema will be set to INVALID_SCHEMA
	static QualifiedName Parse(const string &input) {
		string catalog;
		string schema;
		string name;
		idx_t idx = 0;
		vector<string> entries;
		string entry;
	normal:
		//! quote
		for (; idx < input.size(); idx++) {
			if (input[idx] == '"') {
				idx++;
				goto quoted;
			} else if (input[idx] == '.') {
				goto separator;
			}
			entry += input[idx];
		}
		goto end;
	separator:
		entries.push_back(entry);
		entry = "";
		idx++;
		goto normal;
	quoted:
		//! look for another quote
		for (; idx < input.size(); idx++) {
			if (input[idx] == '"') {
				//! unquote
				idx++;
				goto normal;
			}
			entry += input[idx];
		}
		throw ParserException("Unterminated quote in qualified name!");
	end:
		if (entries.empty()) {
			catalog = INVALID_CATALOG;
			schema = INVALID_SCHEMA;
			name = entry;
		} else if (entries.size() == 1) {
			catalog = INVALID_CATALOG;
			schema = entries[0];
			name = entry;
		} else if (entries.size() == 2) {
			catalog = entries[0];
			schema = entries[1];
			name = entry;
		} else {
			throw ParserException("Expected catalog.entry, schema.entry or entry: too many entries found");
		}
		return QualifiedName {catalog, schema, name};
	}
};

struct QualifiedColumnName {
	QualifiedColumnName() {
	}
	QualifiedColumnName(string table_p, string column_p) : table(std::move(table_p)), column(std::move(column_p)) {
	}

	string schema;
	string table;
	string column;
};

} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/parser/expression_util.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {
class ParsedExpression;
class Expression;

class ExpressionUtil {
public:
	//! ListEquals: check if a list of two expressions is equal (order is important)
	static bool ListEquals(const vector<unique_ptr<ParsedExpression>> &a,
	                       const vector<unique_ptr<ParsedExpression>> &b);
	static bool ListEquals(const vector<unique_ptr<Expression>> &a, const vector<unique_ptr<Expression>> &b);
	//! SetEquals: check if two sets of expressions are equal (order is not important)
	static bool SetEquals(const vector<unique_ptr<ParsedExpression>> &a, const vector<unique_ptr<ParsedExpression>> &b);
	static bool SetEquals(const vector<unique_ptr<Expression>> &a, const vector<unique_ptr<Expression>> &b);

private:
	template <class T>
	static bool ExpressionListEquals(const vector<unique_ptr<T>> &a, const vector<unique_ptr<T>> &b);
	template <class T, class EXPRESSION_MAP>
	static bool ExpressionSetEquals(const vector<unique_ptr<T>> &a, const vector<unique_ptr<T>> &b);
};

} // namespace duckdb


namespace duckdb {
class Deserializer;
class Serializer;

//!  The ParsedExpression class is a base class that can represent any expression
//!  part of a SQL statement.
/*!
 The ParsedExpression class is a base class that can represent any expression
 part of a SQL statement. This is, for example, a column reference in a SELECT
 clause, but also operators, aggregates or filters. The Expression is emitted by the parser and does not contain any
 information about bindings to the catalog or to the types. ParsedExpressions are transformed into regular Expressions
 in the Binder.
 */
class ParsedExpression : public BaseExpression {
public:
	//! Create an Expression
	ParsedExpression(ExpressionType type, ExpressionClass expression_class) : BaseExpression(type, expression_class) {
	}

public:
	bool IsAggregate() const override;
	bool IsWindow() const override;
	bool HasSubquery() const override;
	bool IsScalar() const override;
	bool HasParameter() const override;

	bool Equals(const BaseExpression &other) const override;
	hash_t Hash() const override;

	//! Create a copy of this expression
	virtual unique_ptr<ParsedExpression> Copy() const = 0;

	virtual void Serialize(Serializer &serializer) const;
	static unique_ptr<ParsedExpression> Deserialize(Deserializer &deserializer);

	static bool Equals(const unique_ptr<ParsedExpression> &left, const unique_ptr<ParsedExpression> &right);
	static bool ListEquals(const vector<unique_ptr<ParsedExpression>> &left,
	                       const vector<unique_ptr<ParsedExpression>> &right);

protected:
	//! Copy base Expression properties from another expression to this one,
	//! used in Copy method
	void CopyProperties(const ParsedExpression &other) {
		type = other.type;
		expression_class = other.expression_class;
		alias = other.alias;
		query_location = other.query_location;
	}
};

} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/enums/compression_type.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

enum class CompressionType : uint8_t {
	COMPRESSION_AUTO = 0,
	COMPRESSION_UNCOMPRESSED = 1,
	COMPRESSION_CONSTANT = 2,
	COMPRESSION_RLE = 3,
	COMPRESSION_DICTIONARY = 4,
	COMPRESSION_PFOR_DELTA = 5,
	COMPRESSION_BITPACKING = 6,
	COMPRESSION_FSST = 7,
	COMPRESSION_CHIMP = 8,
	COMPRESSION_PATAS = 9,
	COMPRESSION_ALP = 10,
	COMPRESSION_ALPRD = 11,
	COMPRESSION_COUNT // This has to stay the last entry of the type!
};

bool CompressionTypeIsDeprecated(CompressionType compression_type);
vector<string> ListCompressionTypes(void);
CompressionType CompressionTypeFromString(const string &str);
string CompressionTypeToString(CompressionType type);

} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/catalog/catalog_entry/table_column_type.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

enum class TableColumnType : uint8_t { STANDARD = 0, GENERATED = 1 };

} // namespace duckdb



namespace duckdb {

struct RenameColumnInfo;
struct RenameTableInfo;

class ColumnDefinition;

//! A column of a table.
class ColumnDefinition {
public:
	DUCKDB_API ColumnDefinition(string name, LogicalType type);
	DUCKDB_API ColumnDefinition(string name, LogicalType type, unique_ptr<ParsedExpression> expression,
	                            TableColumnType category);

public:
	//! default_value
	const ParsedExpression &DefaultValue() const;
	bool HasDefaultValue() const;
	void SetDefaultValue(unique_ptr<ParsedExpression> default_value);

	//! type
	DUCKDB_API const LogicalType &Type() const;
	LogicalType &TypeMutable();
	void SetType(const LogicalType &type);

	//! name
	DUCKDB_API const string &Name() const;
	void SetName(const string &name);

	//! comment
	DUCKDB_API const Value &Comment() const;
	void SetComment(const Value &comment);

	//! compression_type
	const duckdb::CompressionType &CompressionType() const;
	void SetCompressionType(duckdb::CompressionType compression_type);

	//! storage_oid
	const storage_t &StorageOid() const;
	void SetStorageOid(storage_t storage_oid);

	LogicalIndex Logical() const;
	PhysicalIndex Physical() const;

	//! oid
	const column_t &Oid() const;
	void SetOid(column_t oid);

	//! category
	const TableColumnType &Category() const;
	//! Whether this column is a Generated Column
	bool Generated() const;
	DUCKDB_API ColumnDefinition Copy() const;

	DUCKDB_API void Serialize(Serializer &serializer) const;
	DUCKDB_API static ColumnDefinition Deserialize(Deserializer &deserializer);

	//===--------------------------------------------------------------------===//
	// Generated Columns (VIRTUAL)
	//===--------------------------------------------------------------------===//

	ParsedExpression &GeneratedExpressionMutable();
	const ParsedExpression &GeneratedExpression() const;
	void SetGeneratedExpression(unique_ptr<ParsedExpression> expression);
	void ChangeGeneratedExpressionType(const LogicalType &type);
	void GetListOfDependencies(vector<string> &dependencies) const;

	string GetName() const;

	LogicalType GetType() const;

private:
	//! The name of the entry
	string name;
	//! The type of the column
	LogicalType type;
	//! Compression Type used for this column
	duckdb::CompressionType compression_type = duckdb::CompressionType::COMPRESSION_AUTO;
	//! The index of the column in the storage of the table
	storage_t storage_oid = DConstants::INVALID_INDEX;
	//! The index of the column in the table
	idx_t oid = DConstants::INVALID_INDEX;
	//! The category of the column
	TableColumnType category = TableColumnType::STANDARD;
	//! The default value of the column (for non-generated columns)
	//! The generated column expression (for generated columns)
	unique_ptr<ParsedExpression> expression;
	//! Comment on this column
	Value comment;
	//! Tags on this column
	unordered_map<string, string> tags;
};

} // namespace duckdb


namespace duckdb {
class CatalogEntry;
class Catalog;
class ClientContext;
class Expression;
class ExpressionExecutor;
class Transaction;

class AggregateFunction;
class AggregateFunctionSet;
class CopyFunction;
class PragmaFunction;
class PragmaFunctionSet;
class ScalarFunctionSet;
class ScalarFunction;
class TableFunctionSet;
class TableFunction;
class SimpleFunction;

struct PragmaInfo;

//! The default null handling is NULL in, NULL out
enum class FunctionNullHandling : uint8_t { DEFAULT_NULL_HANDLING = 0, SPECIAL_HANDLING = 1 };
//! The stability of the function, used by the optimizer
//! CONSISTENT              -> this function always returns the same result when given the same input, no variance
//! CONSISTENT_WITHIN_QUERY -> this function returns the same result WITHIN the same query/transaction
//!                            but the result might change across queries (e.g. NOW(), CURRENT_TIME)
//! VOLATILE                -> the result of this function might change per row (e.g. RANDOM())
enum class FunctionStability : uint8_t { CONSISTENT = 0, VOLATILE = 1, CONSISTENT_WITHIN_QUERY = 2 };

struct FunctionData {
	DUCKDB_API virtual ~FunctionData();

	DUCKDB_API virtual unique_ptr<FunctionData> Copy() const = 0;
	DUCKDB_API virtual bool Equals(const FunctionData &other) const = 0;
	DUCKDB_API static bool Equals(const FunctionData *left, const FunctionData *right);

	template <class TARGET>
	TARGET &Cast() {
		DynamicCastCheck<TARGET>(this);
		return reinterpret_cast<TARGET &>(*this);
	}
	template <class TARGET>
	const TARGET &Cast() const {
		DynamicCastCheck<TARGET>(this);
		return reinterpret_cast<const TARGET &>(*this);
	}
	// FIXME: this function should be removed in the future
	template <class TARGET>
	TARGET &CastNoConst() const {
		return const_cast<TARGET &>(Cast<TARGET>()); // NOLINT: FIXME
	}
};

struct TableFunctionData : public FunctionData {
	// used to pass on projections to table functions that support them. NB, can contain COLUMN_IDENTIFIER_ROW_ID
	vector<idx_t> column_ids;

	DUCKDB_API ~TableFunctionData() override;

	DUCKDB_API unique_ptr<FunctionData> Copy() const override;
	DUCKDB_API bool Equals(const FunctionData &other) const override;
};

struct FunctionParameters {
	vector<Value> values;
	named_parameter_map_t named_parameters;
};

//! Function is the base class used for any type of function (scalar, aggregate or simple function)
class Function {
public:
	DUCKDB_API explicit Function(string name);
	DUCKDB_API virtual ~Function();

	//! The name of the function
	string name;
	//! Additional Information to specify function from it's name
	string extra_info;

public:
	//! Returns the formatted string name(arg1, arg2, ...)
	DUCKDB_API static string CallToString(const string &name, const vector<LogicalType> &arguments,
	                                      const LogicalType &varargs = LogicalType::INVALID);
	//! Returns the formatted string name(arg1, arg2..) -> return_type
	DUCKDB_API static string CallToString(const string &name, const vector<LogicalType> &arguments,
	                                      const LogicalType &varargs, const LogicalType &return_type);
	//! Returns the formatted string name(arg1, arg2.., np1=a, np2=b, ...)
	DUCKDB_API static string CallToString(const string &name, const vector<LogicalType> &arguments,
	                                      const named_parameter_type_map_t &named_parameters);

	//! Used in the bind to erase an argument from a function
	DUCKDB_API static void EraseArgument(SimpleFunction &bound_function, vector<unique_ptr<Expression>> &arguments,
	                                     idx_t argument_index);
};

class SimpleFunction : public Function {
public:
	DUCKDB_API SimpleFunction(string name, vector<LogicalType> arguments,
	                          LogicalType varargs = LogicalType(LogicalTypeId::INVALID));
	DUCKDB_API ~SimpleFunction() override;

	//! The set of arguments of the function
	vector<LogicalType> arguments;
	//! The set of original arguments of the function - only set if Function::EraseArgument is called
	//! Used for (de)serialization purposes
	vector<LogicalType> original_arguments;
	//! The type of varargs to support, or LogicalTypeId::INVALID if the function does not accept variable length
	//! arguments
	LogicalType varargs;

public:
	DUCKDB_API virtual string ToString() const;

	DUCKDB_API bool HasVarArgs() const;
};

class SimpleNamedParameterFunction : public SimpleFunction {
public:
	DUCKDB_API SimpleNamedParameterFunction(string name, vector<LogicalType> arguments,
	                                        LogicalType varargs = LogicalType(LogicalTypeId::INVALID));
	DUCKDB_API ~SimpleNamedParameterFunction() override;

	//! The named parameters of the function
	named_parameter_type_map_t named_parameters;

public:
	DUCKDB_API string ToString() const override;
	DUCKDB_API bool HasNamedParameters() const;
};

class BaseScalarFunction : public SimpleFunction {
public:
	DUCKDB_API BaseScalarFunction(string name, vector<LogicalType> arguments, LogicalType return_type,
	                              FunctionStability stability,
	                              LogicalType varargs = LogicalType(LogicalTypeId::INVALID),
	                              FunctionNullHandling null_handling = FunctionNullHandling::DEFAULT_NULL_HANDLING);
	DUCKDB_API ~BaseScalarFunction() override;

	//! Return type of the function
	LogicalType return_type;
	//! The stability of the function (see FunctionStability enum for more info)
	FunctionStability stability;
	//! How this function handles NULL values
	FunctionNullHandling null_handling;

public:
	DUCKDB_API hash_t Hash() const;

	DUCKDB_API string ToString() const override;
};

} // namespace duckdb


namespace duckdb {
class Expression;
class ExpressionExecutor;
struct ExpressionExecutorState;
struct FunctionLocalState;

struct ExpressionState {
	ExpressionState(const Expression &expr, ExpressionExecutorState &root);
	virtual ~ExpressionState() {
	}

	const Expression &expr;
	ExpressionExecutorState &root;
	vector<unique_ptr<ExpressionState>> child_states;
	vector<LogicalType> types;
	DataChunk intermediate_chunk;

public:
	void AddChild(Expression *expr);
	void Finalize(bool empty = false);
	Allocator &GetAllocator();
	bool HasContext();
	DUCKDB_API ClientContext &GetContext();

	void Verify(ExpressionExecutorState &root);

public:
	template <class TARGET>
	TARGET &Cast() {
		DynamicCastCheck<TARGET>(this);
		return reinterpret_cast<TARGET &>(*this);
	}
	template <class TARGET>
	const TARGET &Cast() const {
		DynamicCastCheck<TARGET>(this);
		return reinterpret_cast<const TARGET &>(*this);
	}
};

struct ExecuteFunctionState : public ExpressionState {
	ExecuteFunctionState(const Expression &expr, ExpressionExecutorState &root);
	~ExecuteFunctionState() override;

	unique_ptr<FunctionLocalState> local_state;

public:
	static optional_ptr<FunctionLocalState> GetFunctionState(ExpressionState &state) {
		return state.Cast<ExecuteFunctionState>().local_state.get();
	}
};

struct ExpressionExecutorState {
	ExpressionExecutorState();

	unique_ptr<ExpressionState> root_state;
	ExpressionExecutor *executor = nullptr;

	void Verify();
};

} // namespace duckdb


//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/storage/statistics/base_statistics.hpp
//
//
//===----------------------------------------------------------------------===//





//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/operator/comparison_operators.hpp
//
//
//===----------------------------------------------------------------------===//





//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/types/hugeint.hpp
//
//
//===----------------------------------------------------------------------===//




//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/type_util.hpp
//
//
//===----------------------------------------------------------------------===//










namespace duckdb {

//! Returns the PhysicalType for the given type
template <class T>
PhysicalType GetTypeId() {
	if (std::is_same<T, bool>()) {
		return PhysicalType::BOOL;
	} else if (std::is_same<T, int8_t>()) {
		return PhysicalType::INT8;
	} else if (std::is_same<T, int16_t>()) {
		return PhysicalType::INT16;
	} else if (std::is_same<T, int32_t>()) {
		return PhysicalType::INT32;
	} else if (std::is_same<T, int64_t>()) {
		return PhysicalType::INT64;
	} else if (std::is_same<T, uint8_t>()) {
		return PhysicalType::UINT8;
	} else if (std::is_same<T, uint16_t>()) {
		return PhysicalType::UINT16;
	} else if (std::is_same<T, uint32_t>()) {
		return PhysicalType::UINT32;
	} else if (std::is_same<T, uint64_t>()) {
		return PhysicalType::UINT64;
	} else if (std::is_same<T, hugeint_t>()) {
		return PhysicalType::INT128;
	} else if (std::is_same<T, uhugeint_t>()) {
		return PhysicalType::UINT128;
	} else if (std::is_same<T, date_t>()) {
		return PhysicalType::INT32;
	} else if (std::is_same<T, dtime_t>()) {
		return PhysicalType::INT64;
	} else if (std::is_same<T, timestamp_t>()) {
		return PhysicalType::INT64;
	} else if (std::is_same<T, float>()) {
		return PhysicalType::FLOAT;
	} else if (std::is_same<T, double>()) {
		return PhysicalType::DOUBLE;
	} else if (std::is_same<T, const char *>() || std::is_same<T, char *>() || std::is_same<T, string_t>()) {
		return PhysicalType::VARCHAR;
	} else if (std::is_same<T, interval_t>()) {
		return PhysicalType::INTERVAL;
	} else {
		return PhysicalType::INVALID;
	}
}

template <class T>
bool TypeIsNumber() {
	return std::is_integral<T>() || std::is_floating_point<T>() || std::is_same<T, hugeint_t>() ||
	       std::is_same<T, uhugeint_t>();
}

template <class T>
bool IsValidType() {
	return GetTypeId<T>() != PhysicalType::INVALID;
}

template <class T>
bool IsIntegerType() {
	return TypeIsIntegral(GetTypeId<T>());
}

} // namespace duckdb




namespace duckdb {

//! The Hugeint class contains static operations for the INT128 type
class Hugeint {
public:
	constexpr static const char *HUGEINT_MINIMUM_STRING = "-170141183460469231731687303715884105728";

	//! Convert a hugeint object to a string
	static string ToString(hugeint_t input);

	template <class T>
	DUCKDB_API static bool TryCast(hugeint_t input, T &result);

	template <class T>
	static T Cast(hugeint_t input) {
		T result = 0;
		TryCast(input, result);
		return result;
	}

	template <class T>
	static bool TryConvert(T value, hugeint_t &result);

	template <class T>
	static hugeint_t Convert(T value) {
		hugeint_t result;
		if (!TryConvert(value, result)) { // LCOV_EXCL_START
			throw OutOfRangeException(double(value), GetTypeId<T>(), GetTypeId<hugeint_t>());
		} // LCOV_EXCL_STOP
		return result;
	}

	static bool TryNegate(hugeint_t input, hugeint_t &result);

	template <bool CHECK_OVERFLOW = true>
	inline static void NegateInPlace(hugeint_t &input) {
		if (!TryNegate(input, input)) {
			throw OutOfRangeException("Negation of HUGEINT is out of range!");
		}
	}

	template <bool CHECK_OVERFLOW = true>
	inline static hugeint_t Negate(hugeint_t input) {
		NegateInPlace<CHECK_OVERFLOW>(input);
		return input;
	}

	static bool TryMultiply(hugeint_t lhs, hugeint_t rhs, hugeint_t &result);

	template <bool CHECK_OVERFLOW = true>
	inline static hugeint_t Multiply(hugeint_t lhs, hugeint_t rhs) {
		hugeint_t result;
		if (!TryMultiply(lhs, rhs, result)) {
			throw OutOfRangeException("Overflow in HUGEINT multiplication: %s + %s", lhs.ToString(), rhs.ToString());
		}
		return result;
	}

	static bool TryDivMod(hugeint_t lhs, hugeint_t rhs, hugeint_t &result, hugeint_t &remainder);

	template <bool CHECK_OVERFLOW = true>
	inline static hugeint_t Divide(hugeint_t lhs, hugeint_t rhs) {
		// No division by zero
		if (rhs == 0) {
			throw OutOfRangeException("Division of HUGEINT by zero!");
		}

		// division only has one reason to overflow: MINIMUM / -1
		if (lhs == NumericLimits<hugeint_t>::Minimum() && rhs == -1) {
			throw OutOfRangeException("Overflow in HUGEINT division: %s + %s", lhs.ToString(), rhs.ToString());
		}
		return Divide<false>(lhs, rhs);
	}

	template <bool CHECK_OVERFLOW = true>
	inline static hugeint_t Modulo(hugeint_t lhs, hugeint_t rhs) {
		// No division by zero
		if (rhs == 0) {
			throw OutOfRangeException("Modulo of HUGEINT by zero: %s + %s", lhs.ToString(), rhs.ToString());
		}

		// division only has one reason to overflow: MINIMUM / -1
		if (lhs == NumericLimits<hugeint_t>::Minimum() && rhs == -1) {
			throw OutOfRangeException("Overflow in HUGEINT modulo: %s + %s", lhs.ToString(), rhs.ToString());
		}
		return Modulo<false>(lhs, rhs);
	}

	static bool TryAddInPlace(hugeint_t &lhs, hugeint_t rhs);

	template <bool CHECK_OVERFLOW = true>
	inline static hugeint_t Add(hugeint_t lhs, hugeint_t rhs) {
		if (!TryAddInPlace(lhs, rhs)) {
			throw OutOfRangeException("Overflow in HUGEINT addition: %s + %s", lhs.ToString(), rhs.ToString());
		}
		return lhs;
	}

	static bool TrySubtractInPlace(hugeint_t &lhs, hugeint_t rhs);

	template <bool CHECK_OVERFLOW = true>
	inline static hugeint_t Subtract(hugeint_t lhs, hugeint_t rhs) {
		if (!TrySubtractInPlace(lhs, rhs)) {
			throw OutOfRangeException("Underflow in HUGEINT addition: %s - %s", lhs.ToString(), rhs.ToString());
		}
		return lhs;
	}

	// DivMod -> returns the result of the division (lhs / rhs), and fills up the remainder
	static hugeint_t DivMod(hugeint_t lhs, hugeint_t rhs, hugeint_t &remainder);
	// DivMod but lhs MUST be positive, and rhs is a uint64_t
	static hugeint_t DivModPositive(hugeint_t lhs, uint64_t rhs, uint64_t &remainder);

	static int Sign(hugeint_t n);
	static hugeint_t Abs(hugeint_t n);
	// comparison operators
	// note that everywhere here we intentionally use bitwise ops
	// this is because they seem to be consistently much faster (benchmarked on a Macbook Pro)
	static bool Equals(hugeint_t lhs, hugeint_t rhs) {
		int lower_equals = lhs.lower == rhs.lower;
		int upper_equals = lhs.upper == rhs.upper;
		return lower_equals & upper_equals;
	}

	static bool NotEquals(hugeint_t lhs, hugeint_t rhs) {
		int lower_not_equals = lhs.lower != rhs.lower;
		int upper_not_equals = lhs.upper != rhs.upper;
		return lower_not_equals | upper_not_equals;
	}

	static bool GreaterThan(hugeint_t lhs, hugeint_t rhs) {
		int upper_bigger = lhs.upper > rhs.upper;
		int upper_equal = lhs.upper == rhs.upper;
		int lower_bigger = lhs.lower > rhs.lower;
		return upper_bigger | (upper_equal & lower_bigger);
	}

	static bool GreaterThanEquals(hugeint_t lhs, hugeint_t rhs) {
		int upper_bigger = lhs.upper > rhs.upper;
		int upper_equal = lhs.upper == rhs.upper;
		int lower_bigger_equals = lhs.lower >= rhs.lower;
		return upper_bigger | (upper_equal & lower_bigger_equals);
	}

	static bool LessThan(hugeint_t lhs, hugeint_t rhs) {
		int upper_smaller = lhs.upper < rhs.upper;
		int upper_equal = lhs.upper == rhs.upper;
		int lower_smaller = lhs.lower < rhs.lower;
		return upper_smaller | (upper_equal & lower_smaller);
	}

	static bool LessThanEquals(hugeint_t lhs, hugeint_t rhs) {
		int upper_smaller = lhs.upper < rhs.upper;
		int upper_equal = lhs.upper == rhs.upper;
		int lower_smaller_equals = lhs.lower <= rhs.lower;
		return upper_smaller | (upper_equal & lower_smaller_equals);
	}

	static const hugeint_t POWERS_OF_TEN[40];
};

template <>
DUCKDB_API bool Hugeint::TryCast(hugeint_t input, int8_t &result);
template <>
DUCKDB_API bool Hugeint::TryCast(hugeint_t input, int16_t &result);
template <>
DUCKDB_API bool Hugeint::TryCast(hugeint_t input, int32_t &result);
template <>
DUCKDB_API bool Hugeint::TryCast(hugeint_t input, int64_t &result);
template <>
DUCKDB_API bool Hugeint::TryCast(hugeint_t input, uint8_t &result);
template <>
DUCKDB_API bool Hugeint::TryCast(hugeint_t input, uint16_t &result);
template <>
DUCKDB_API bool Hugeint::TryCast(hugeint_t input, uint32_t &result);
template <>
DUCKDB_API bool Hugeint::TryCast(hugeint_t input, uint64_t &result);
template <>
DUCKDB_API bool Hugeint::TryCast(hugeint_t input, hugeint_t &result);
template <>
DUCKDB_API bool Hugeint::TryCast(hugeint_t input, uhugeint_t &result);
template <>
DUCKDB_API bool Hugeint::TryCast(hugeint_t input, float &result);
template <>
DUCKDB_API bool Hugeint::TryCast(hugeint_t input, double &result);
template <>
DUCKDB_API bool Hugeint::TryCast(hugeint_t input, long double &result);

template <>
bool Hugeint::TryConvert(int8_t value, hugeint_t &result);
template <>
bool Hugeint::TryConvert(int16_t value, hugeint_t &result);
template <>
bool Hugeint::TryConvert(int32_t value, hugeint_t &result);
template <>
bool Hugeint::TryConvert(int64_t value, hugeint_t &result);
template <>
bool Hugeint::TryConvert(uint8_t value, hugeint_t &result);
template <>
bool Hugeint::TryConvert(uint16_t value, hugeint_t &result);
template <>
bool Hugeint::TryConvert(uint32_t value, hugeint_t &result);
template <>
bool Hugeint::TryConvert(uint64_t value, hugeint_t &result);
template <>
bool Hugeint::TryConvert(float value, hugeint_t &result);
template <>
bool Hugeint::TryConvert(double value, hugeint_t &result);
template <>
bool Hugeint::TryConvert(long double value, hugeint_t &result);
template <>
bool Hugeint::TryConvert(const char *value, hugeint_t &result);

} // namespace duckdb




#include <cstring>

namespace duckdb {

//===--------------------------------------------------------------------===//
// Comparison Operations
//===--------------------------------------------------------------------===//
struct Equals {
	template <class T>
	static inline bool Operation(const T &left, const T &right) {
		return left == right;
	}
};
struct NotEquals {
	template <class T>
	static inline bool Operation(const T &left, const T &right) {
		return !Equals::Operation(left, right);
	}
};

struct GreaterThan {
	template <class T>
	static inline bool Operation(const T &left, const T &right) {
		return left > right;
	}
};

struct GreaterThanEquals {
	template <class T>
	static inline bool Operation(const T &left, const T &right) {
		return !GreaterThan::Operation(right, left);
	}
};

struct LessThan {
	template <class T>
	static inline bool Operation(const T &left, const T &right) {
		return GreaterThan::Operation(right, left);
	}
};

struct LessThanEquals {
	template <class T>
	static inline bool Operation(const T &left, const T &right) {
		return !GreaterThan::Operation(left, right);
	}
};

template <>
DUCKDB_API bool Equals::Operation(const float &left, const float &right);
template <>
DUCKDB_API bool Equals::Operation(const double &left, const double &right);

template <>
DUCKDB_API bool GreaterThan::Operation(const float &left, const float &right);
template <>
DUCKDB_API bool GreaterThan::Operation(const double &left, const double &right);

template <>
DUCKDB_API bool GreaterThanEquals::Operation(const float &left, const float &right);
template <>
DUCKDB_API bool GreaterThanEquals::Operation(const double &left, const double &right);

// Distinct semantics are from Postgres record sorting. NULL = NULL and not-NULL < NULL
// Deferring to the non-distinct operations removes the need for further specialisation.
// TODO: To reverse the semantics, swap left_null and right_null for comparisons
struct DistinctFrom {
	template <class T>
	static inline bool Operation(const T &left, const T &right, bool left_null, bool right_null) {
		if (left_null || right_null) {
			return left_null != right_null;
		}
		return NotEquals::Operation(left, right);
	}
};

struct NotDistinctFrom {
	template <class T>
	static inline bool Operation(const T &left, const T &right, bool left_null, bool right_null) {
		return !DistinctFrom::Operation(left, right, left_null, right_null);
	}
};

struct DistinctGreaterThan {
	template <class T>
	static inline bool Operation(const T &left, const T &right, bool left_null, bool right_null) {
		if (left_null || right_null) {
			return !right_null;
		}
		return GreaterThan::Operation(left, right);
	}
};

struct DistinctGreaterThanNullsFirst {
	template <class T>
	static inline bool Operation(const T &left, const T &right, bool left_null, bool right_null) {
		return DistinctGreaterThan::Operation(left, right, right_null, left_null);
	}
};

struct DistinctGreaterThanEquals {
	template <class T>
	static inline bool Operation(const T &left, const T &right, bool left_null, bool right_null) {
		return !DistinctGreaterThan::Operation(right, left, right_null, left_null);
	}
};

struct DistinctLessThan {
	template <class T>
	static inline bool Operation(const T &left, const T &right, bool left_null, bool right_null) {
		return DistinctGreaterThan::Operation(right, left, right_null, left_null);
	}
};

struct DistinctLessThanNullsFirst {
	template <class T>
	static inline bool Operation(const T &left, const T &right, bool left_null, bool right_null) {
		return DistinctGreaterThan::Operation(right, left, left_null, right_null);
	}
};

struct DistinctLessThanEquals {
	template <class T>
	static inline bool Operation(const T &left, const T &right, bool left_null, bool right_null) {
		return !DistinctGreaterThan::Operation(left, right, left_null, right_null);
	}
};

//===--------------------------------------------------------------------===//
// Comparison Operator Wrappers (so (Not)DistinctFrom have the same API)
//===--------------------------------------------------------------------===//
template <class OP>
struct ComparisonOperationWrapper {
	static constexpr const bool COMPARE_NULL = false;

	template <class T>
	static inline bool Operation(const T &left, const T &right, bool left_null, bool right_null) {
		if (right_null || left_null) {
			return false;
		}
		return OP::template Operation<T>(left, right);
	}
};

template <>
struct ComparisonOperationWrapper<DistinctFrom> {
	static constexpr const bool COMPARE_NULL = true;

	template <class T>
	static inline bool Operation(const T &left, const T &right, bool left_null, bool right_null) {
		return DistinctFrom::template Operation<T>(left, right, left_null, right_null);
	}
};

template <>
struct ComparisonOperationWrapper<NotDistinctFrom> {
	static constexpr const bool COMPARE_NULL = true;

	template <class T>
	static inline bool Operation(const T &left, const T &right, bool left_null, bool right_null) {
		return NotDistinctFrom::template Operation<T>(left, right, left_null, right_null);
	}
};

//===--------------------------------------------------------------------===//
// Specialized Boolean Comparison Operators
//===--------------------------------------------------------------------===//
template <>
inline bool GreaterThan::Operation(const bool &left, const bool &right) {
	return !right && left;
}
//===--------------------------------------------------------------------===//
// Specialized String Comparison Operations
//===--------------------------------------------------------------------===//
template <>
inline bool Equals::Operation(const string_t &left, const string_t &right) {
	return left == right;
}

template <>
inline bool GreaterThan::Operation(const string_t &left, const string_t &right) {
	return left > right;
}

//===--------------------------------------------------------------------===//
// Specialized Interval Comparison Operators
//===--------------------------------------------------------------------===//
template <>
inline bool Equals::Operation(const interval_t &left, const interval_t &right) {
	return Interval::Equals(left, right);
}
template <>
inline bool GreaterThan::Operation(const interval_t &left, const interval_t &right) {
	return Interval::GreaterThan(left, right);
}

//===--------------------------------------------------------------------===//
// Specialized Hugeint Comparison Operators
//===--------------------------------------------------------------------===//
template <>
inline bool Equals::Operation(const hugeint_t &left, const hugeint_t &right) {
	return Hugeint::Equals(left, right);
}
template <>
inline bool GreaterThan::Operation(const hugeint_t &left, const hugeint_t &right) {
	return Hugeint::GreaterThan(left, right);
}
} // namespace duckdb



//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/storage/statistics/numeric_stats.hpp
//
//
//===----------------------------------------------------------------------===//




//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/enums/filter_propagate_result.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

enum class FilterPropagateResult : uint8_t {
	NO_PRUNING_POSSIBLE = 0,
	FILTER_ALWAYS_TRUE = 1,
	FILTER_ALWAYS_FALSE = 2,
	FILTER_TRUE_OR_NULL = 3,
	FILTER_FALSE_OR_NULL = 4
};

} // namespace duckdb



//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/storage/statistics/numeric_stats_union.hpp
//
//
//===----------------------------------------------------------------------===//







namespace duckdb {

struct NumericValueUnion {
	union Val {
		bool boolean;
		int8_t tinyint;
		int16_t smallint;
		int32_t integer;
		int64_t bigint;
		uint8_t utinyint;
		uint16_t usmallint;
		uint32_t uinteger;
		uint64_t ubigint;
		hugeint_t hugeint;
		uhugeint_t uhugeint;
		float float_;   // NOLINT
		double double_; // NOLINT
	} value_;           // NOLINT

	template <class T>
	T &GetReferenceUnsafe();
};

template <>
DUCKDB_API inline bool &NumericValueUnion::GetReferenceUnsafe() {
	return value_.boolean;
}

template <>
DUCKDB_API inline int8_t &NumericValueUnion::GetReferenceUnsafe() {
	return value_.tinyint;
}

template <>
DUCKDB_API inline int16_t &NumericValueUnion::GetReferenceUnsafe() {
	return value_.smallint;
}

template <>
DUCKDB_API inline int32_t &NumericValueUnion::GetReferenceUnsafe() {
	return value_.integer;
}

template <>
DUCKDB_API inline int64_t &NumericValueUnion::GetReferenceUnsafe() {
	return value_.bigint;
}

template <>
DUCKDB_API inline hugeint_t &NumericValueUnion::GetReferenceUnsafe() {
	return value_.hugeint;
}

template <>
DUCKDB_API inline uhugeint_t &NumericValueUnion::GetReferenceUnsafe() {
	return value_.uhugeint;
}

template <>
DUCKDB_API inline uint8_t &NumericValueUnion::GetReferenceUnsafe() {
	return value_.utinyint;
}

template <>
DUCKDB_API inline uint16_t &NumericValueUnion::GetReferenceUnsafe() {
	return value_.usmallint;
}

template <>
DUCKDB_API inline uint32_t &NumericValueUnion::GetReferenceUnsafe() {
	return value_.uinteger;
}

template <>
DUCKDB_API inline uint64_t &NumericValueUnion::GetReferenceUnsafe() {
	return value_.ubigint;
}

template <>
DUCKDB_API inline float &NumericValueUnion::GetReferenceUnsafe() {
	return value_.float_;
}

template <>
DUCKDB_API inline double &NumericValueUnion::GetReferenceUnsafe() {
	return value_.double_;
}

} // namespace duckdb


namespace duckdb {
class BaseStatistics;
struct SelectionVector;
class Vector;

struct NumericStatsData {
	//! Whether or not the value has a max value
	bool has_min;
	//! Whether or not the segment has a min value
	bool has_max;
	//! The minimum value of the segment
	NumericValueUnion min;
	//! The maximum value of the segment
	NumericValueUnion max;
};

struct NumericStats {
	//! Unknown statistics - i.e. "has_min" is false, "has_max" is false
	DUCKDB_API static BaseStatistics CreateUnknown(LogicalType type);
	//! Empty statistics - i.e. "min = MaxValue<type>, max = MinValue<type>"
	DUCKDB_API static BaseStatistics CreateEmpty(LogicalType type);

	//! Returns true if the stats has a constant value
	DUCKDB_API static bool IsConstant(const BaseStatistics &stats);
	//! Returns true if the stats has both a min and max value defined
	DUCKDB_API static bool HasMinMax(const BaseStatistics &stats);
	//! Returns true if the stats has a min value defined
	DUCKDB_API static bool HasMin(const BaseStatistics &stats);
	//! Returns true if the stats has a max value defined
	DUCKDB_API static bool HasMax(const BaseStatistics &stats);
	//! Returns the min value - throws an exception if there is no min value
	DUCKDB_API static Value Min(const BaseStatistics &stats);
	//! Returns the max value - throws an exception if there is no max value
	DUCKDB_API static Value Max(const BaseStatistics &stats);
	//! Sets the min value of the statistics
	DUCKDB_API static void SetMin(BaseStatistics &stats, const Value &val);
	//! Sets the max value of the statistics
	DUCKDB_API static void SetMax(BaseStatistics &stats, const Value &val);

	//! Check whether or not a given comparison with a constant could possibly be satisfied by rows given the statistics
	DUCKDB_API static FilterPropagateResult CheckZonemap(const BaseStatistics &stats, ExpressionType comparison_type,
	                                                     const Value &constant);

	DUCKDB_API static void Merge(BaseStatistics &stats, const BaseStatistics &other_p);

	DUCKDB_API static void Serialize(const BaseStatistics &stats, Serializer &serializer);
	DUCKDB_API static void Deserialize(Deserializer &deserializer, BaseStatistics &stats);

	DUCKDB_API static string ToString(const BaseStatistics &stats);

	template <class T>
	static inline void UpdateValue(T new_value, T &min, T &max) {
		min = LessThan::Operation(new_value, min) ? new_value : min;
		max = GreaterThan::Operation(new_value, max) ? new_value : max;
	}
	template <class T>
	static inline void Update(NumericStatsData &nstats, T new_value) {
		UpdateValue<T>(new_value, nstats.min.GetReferenceUnsafe<T>(), nstats.max.GetReferenceUnsafe<T>());
	}

	static void Verify(const BaseStatistics &stats, Vector &vector, const SelectionVector &sel, idx_t count);

	template <class T>
	static T GetMin(const BaseStatistics &stats) {
		return NumericStats::Min(stats).GetValueUnsafe<T>();
	}
	template <class T>
	static T GetMax(const BaseStatistics &stats) {
		return NumericStats::Max(stats).GetValueUnsafe<T>();
	}
	template <class T>
	static T GetMinUnsafe(const BaseStatistics &stats);
	template <class T>
	static T GetMaxUnsafe(const BaseStatistics &stats);

private:
	static NumericStatsData &GetDataUnsafe(BaseStatistics &stats);
	static const NumericStatsData &GetDataUnsafe(const BaseStatistics &stats);
	static Value MinOrNull(const BaseStatistics &stats);
	static Value MaxOrNull(const BaseStatistics &stats);
	template <class T>
	static void TemplatedVerify(const BaseStatistics &stats, Vector &vector, const SelectionVector &sel, idx_t count);
};

} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/storage/statistics/string_stats.hpp
//
//
//===----------------------------------------------------------------------===//










namespace duckdb {
class BaseStatistics;
struct SelectionVector;
class Vector;

struct StringStatsData {
	constexpr static uint32_t MAX_STRING_MINMAX_SIZE = 8;

	//! The minimum value of the segment, potentially truncated
	data_t min[MAX_STRING_MINMAX_SIZE];
	//! The maximum value of the segment, potentially truncated
	data_t max[MAX_STRING_MINMAX_SIZE];
	//! Whether or not the column can contain unicode characters
	bool has_unicode;
	//! Whether or not the maximum string length is known
	bool has_max_string_length;
	//! The maximum string length in bytes
	uint32_t max_string_length;
};

struct StringStats {
	//! Unknown statistics - i.e. "has_unicode" is true, "max_string_length" is unknown, "min" is \0, max is \xFF
	DUCKDB_API static BaseStatistics CreateUnknown(LogicalType type);
	//! Empty statistics - i.e. "has_unicode" is false, "max_string_length" is 0, "min" is \xFF, max is \x00
	DUCKDB_API static BaseStatistics CreateEmpty(LogicalType type);
	//! Whether or not the statistics have a maximum string length defined
	DUCKDB_API static bool HasMaxStringLength(const BaseStatistics &stats);
	//! Returns the maximum string length, or throws an exception if !HasMaxStringLength()
	DUCKDB_API static uint32_t MaxStringLength(const BaseStatistics &stats);
	//! Whether or not the strings can contain unicode
	DUCKDB_API static bool CanContainUnicode(const BaseStatistics &stats);
	//! Returns the min value (up to a length of StringStatsData::MAX_STRING_MINMAX_SIZE)
	DUCKDB_API static string Min(const BaseStatistics &stats);
	//! Returns the max value (up to a length of StringStatsData::MAX_STRING_MINMAX_SIZE)
	DUCKDB_API static string Max(const BaseStatistics &stats);

	//! Resets the max string length so HasMaxStringLength() is false
	DUCKDB_API static void ResetMaxStringLength(BaseStatistics &stats);
	//! FIXME: make this part of Set on statistics
	DUCKDB_API static void SetContainsUnicode(BaseStatistics &stats);

	DUCKDB_API static void Serialize(const BaseStatistics &stats, Serializer &serializer);
	DUCKDB_API static void Deserialize(Deserializer &deserializer, BaseStatistics &base);

	DUCKDB_API static string ToString(const BaseStatistics &stats);

	DUCKDB_API static FilterPropagateResult CheckZonemap(const BaseStatistics &stats, ExpressionType comparison_type,
	                                                     const string &value);
	DUCKDB_API static FilterPropagateResult CheckZonemap(const_data_ptr_t min_data, idx_t min_len,
	                                                     const_data_ptr_t max_data, idx_t max_len,
	                                                     ExpressionType comparison_type, const string &value);

	DUCKDB_API static void Update(BaseStatistics &stats, const string_t &value);
	DUCKDB_API static void Merge(BaseStatistics &stats, const BaseStatistics &other);
	DUCKDB_API static void Verify(const BaseStatistics &stats, Vector &vector, const SelectionVector &sel, idx_t count);

private:
	static StringStatsData &GetDataUnsafe(BaseStatistics &stats);
	static const StringStatsData &GetDataUnsafe(const BaseStatistics &stats);
};

} // namespace duckdb


namespace duckdb {
struct SelectionVector;

class Serializer;
class Deserializer;

class Vector;
struct UnifiedVectorFormat;

enum class StatsInfo : uint8_t {
	CAN_HAVE_NULL_VALUES = 0,
	CANNOT_HAVE_NULL_VALUES = 1,
	CAN_HAVE_VALID_VALUES = 2,
	CANNOT_HAVE_VALID_VALUES = 3,
	CAN_HAVE_NULL_AND_VALID_VALUES = 4
};

enum class StatisticsType : uint8_t { NUMERIC_STATS, STRING_STATS, LIST_STATS, STRUCT_STATS, BASE_STATS, ARRAY_STATS };

class BaseStatistics {
	friend struct NumericStats;
	friend struct StringStats;
	friend struct StructStats;
	friend struct ListStats;
	friend struct ArrayStats;

public:
	DUCKDB_API ~BaseStatistics();
	// disable copy constructors
	BaseStatistics(const BaseStatistics &other) = delete;
	BaseStatistics &operator=(const BaseStatistics &) = delete;
	//! enable move constructors
	DUCKDB_API BaseStatistics(BaseStatistics &&other) noexcept;
	DUCKDB_API BaseStatistics &operator=(BaseStatistics &&) noexcept;

public:
	//! Creates a set of statistics for data that is unknown, i.e. "has_null" is true, "has_no_null" is true, etc
	//! This can be used in case nothing is known about the data - or can be used as a baseline when only a few things
	//! are known
	static BaseStatistics CreateUnknown(LogicalType type);
	//! Creates statistics for an empty database, i.e. "has_null" is false, "has_no_null" is false, etc
	//! This is used when incrementally constructing statistics by constantly adding new values
	static BaseStatistics CreateEmpty(LogicalType type);

	DUCKDB_API StatisticsType GetStatsType() const;
	DUCKDB_API static StatisticsType GetStatsType(const LogicalType &type);

	DUCKDB_API bool CanHaveNull() const;
	DUCKDB_API bool CanHaveNoNull() const;

	void SetDistinctCount(idx_t distinct_count);

	bool IsConstant() const;

	const LogicalType &GetType() const {
		return type;
	}

	void Set(StatsInfo info);
	void CombineValidity(BaseStatistics &left, BaseStatistics &right);
	void CopyValidity(BaseStatistics &stats);
	//! Set that the CURRENT level can have null values
	//! Note that this is not correct for nested types unless this information is propagated in a different manner
	//! Use Set(StatsInfo::CAN_HAVE_NULL_VALUES) in the general case
	inline void SetHasNullFast() {
		has_null = true;
	}
	//! Set that the CURRENT level can have valiod values
	//! Note that this is not correct for nested types unless this information is propagated in a different manner
	//! Use Set(StatsInfo::CAN_HAVE_VALID_VALUES) in the general case
	inline void SetHasNoNullFast() {
		has_no_null = true;
	}
	void SetHasNull();
	void SetHasNoNull();

	void Merge(const BaseStatistics &other);

	void Copy(const BaseStatistics &other);

	BaseStatistics Copy() const;
	unique_ptr<BaseStatistics> ToUnique() const;
	void CopyBase(const BaseStatistics &orig);

	void Serialize(Serializer &serializer) const;
	static BaseStatistics Deserialize(Deserializer &deserializer);

	//! Verify that a vector does not violate the statistics
	void Verify(Vector &vector, const SelectionVector &sel, idx_t count) const;
	void Verify(Vector &vector, idx_t count) const;

	string ToString() const;

	idx_t GetDistinctCount();
	static BaseStatistics FromConstant(const Value &input);

	template <class T>
	void UpdateNumericStats(T new_value) {
		D_ASSERT(GetStatsType() == StatisticsType::NUMERIC_STATS);
		NumericStats::Update(stats_union.numeric_data, new_value);
	}

private:
	BaseStatistics();
	explicit BaseStatistics(LogicalType type);

	static void Construct(BaseStatistics &stats, LogicalType type);

	void InitializeUnknown();
	void InitializeEmpty();

	static BaseStatistics CreateUnknownType(LogicalType type);
	static BaseStatistics CreateEmptyType(LogicalType type);
	static BaseStatistics FromConstantType(const Value &input);

private:
	//! The type of the logical segment
	LogicalType type;
	//! Whether or not the segment can contain NULL values
	bool has_null;
	//! Whether or not the segment can contain values that are not null
	bool has_no_null;
	// estimate that one may have even if distinct_stats==nullptr
	idx_t distinct_count;
	//! Numeric and String stats
	union {
		//! Numeric stats data, for numeric stats
		NumericStatsData numeric_data;
		//! String stats data, for string stats
		StringStatsData string_data;
	} stats_union;
	//! Child stats (for LIST and STRUCT)
	unsafe_unique_array<BaseStatistics> child_stats;
};

template <>
inline void BaseStatistics::UpdateNumericStats<interval_t>(interval_t new_value) {
}
template <>
inline void BaseStatistics::UpdateNumericStats<list_entry_t>(list_entry_t new_value) {
}

} // namespace duckdb



namespace duckdb {

struct FunctionLocalState {
	DUCKDB_API virtual ~FunctionLocalState();

	template <class TARGET>
	TARGET &Cast() {
		DynamicCastCheck<TARGET>(this);
		return reinterpret_cast<TARGET &>(*this);
	}
	template <class TARGET>
	const TARGET &Cast() const {
		DynamicCastCheck<TARGET>(this);
		return reinterpret_cast<const TARGET &>(*this);
	}
};

struct ScalarFunctionInfo {
	DUCKDB_API virtual ~ScalarFunctionInfo();

	template <class TARGET>
	TARGET &Cast() {
		DynamicCastCheck<TARGET>(this);
		return reinterpret_cast<TARGET &>(*this);
	}
	template <class TARGET>
	const TARGET &Cast() const {
		DynamicCastCheck<TARGET>(this);
		return reinterpret_cast<const TARGET &>(*this);
	}
};

class Binder;
class BoundFunctionExpression;
class LogicalDependencyList;
class ScalarFunctionCatalogEntry;
struct StatementProperties;

struct FunctionStatisticsInput {
	FunctionStatisticsInput(BoundFunctionExpression &expr_p, optional_ptr<FunctionData> bind_data_p,
	                        vector<BaseStatistics> &child_stats_p, unique_ptr<Expression> *expr_ptr_p)
	    : expr(expr_p), bind_data(bind_data_p), child_stats(child_stats_p), expr_ptr(expr_ptr_p) {
	}

	BoundFunctionExpression &expr;
	optional_ptr<FunctionData> bind_data;
	vector<BaseStatistics> &child_stats;
	unique_ptr<Expression> *expr_ptr;
};

struct FunctionModifiedDatabasesInput {
	FunctionModifiedDatabasesInput(optional_ptr<FunctionData> bind_data_p, StatementProperties &properties)
	    : bind_data(bind_data_p), properties(properties) {
	}

	optional_ptr<FunctionData> bind_data;
	StatementProperties &properties;
};

struct FunctionBindExpressionInput {
	FunctionBindExpressionInput(ClientContext &context_p, optional_ptr<FunctionData> bind_data_p,
	                            BoundFunctionExpression &function_p)
	    : context(context_p), bind_data(bind_data_p), function(function_p) {
	}

	ClientContext &context;
	optional_ptr<FunctionData> bind_data;
	BoundFunctionExpression &function;
};

//! The scalar function type
typedef std::function<void(DataChunk &, ExpressionState &, Vector &)> scalar_function_t;
//! The type to bind the scalar function and to create the function data
typedef unique_ptr<FunctionData> (*bind_scalar_function_t)(ClientContext &context, ScalarFunction &bound_function,
                                                           vector<unique_ptr<Expression>> &arguments);
//! The type to initialize a thread local state for the scalar function
typedef unique_ptr<FunctionLocalState> (*init_local_state_t)(ExpressionState &state,
                                                             const BoundFunctionExpression &expr,
                                                             FunctionData *bind_data);
//! The type to add the dependencies of this BoundFunctionExpression to the set of dependencies
typedef void (*dependency_function_t)(BoundFunctionExpression &expr, LogicalDependencyList &dependencies);
//! The type to propagate statistics for this scalar function
typedef unique_ptr<BaseStatistics> (*function_statistics_t)(ClientContext &context, FunctionStatisticsInput &input);
//! The type to bind lambda-specific parameter types
typedef LogicalType (*bind_lambda_function_t)(const idx_t parameter_idx, const LogicalType &list_child_type);
//! The type to bind lambda-specific parameter types
typedef void (*get_modified_databases_t)(ClientContext &context, FunctionModifiedDatabasesInput &input);

typedef void (*function_serialize_t)(Serializer &serializer, const optional_ptr<FunctionData> bind_data,
                                     const ScalarFunction &function);
typedef unique_ptr<FunctionData> (*function_deserialize_t)(Deserializer &deserializer, ScalarFunction &function);

//! The type to bind lambda-specific parameter types
typedef unique_ptr<Expression> (*function_bind_expression_t)(FunctionBindExpressionInput &input);

class ScalarFunction : public BaseScalarFunction { // NOLINT: work-around bug in clang-tidy
public:
	DUCKDB_API ScalarFunction(string name, vector<LogicalType> arguments, LogicalType return_type,
	                          scalar_function_t function, bind_scalar_function_t bind = nullptr,
	                          dependency_function_t dependency = nullptr, function_statistics_t statistics = nullptr,
	                          init_local_state_t init_local_state = nullptr,
	                          LogicalType varargs = LogicalType(LogicalTypeId::INVALID),
	                          FunctionStability stability = FunctionStability::CONSISTENT,
	                          FunctionNullHandling null_handling = FunctionNullHandling::DEFAULT_NULL_HANDLING,
	                          bind_lambda_function_t bind_lambda = nullptr);

	DUCKDB_API ScalarFunction(vector<LogicalType> arguments, LogicalType return_type, scalar_function_t function,
	                          bind_scalar_function_t bind = nullptr, dependency_function_t dependency = nullptr,
	                          function_statistics_t statistics = nullptr, init_local_state_t init_local_state = nullptr,
	                          LogicalType varargs = LogicalType(LogicalTypeId::INVALID),
	                          FunctionStability stability = FunctionStability::CONSISTENT,
	                          FunctionNullHandling null_handling = FunctionNullHandling::DEFAULT_NULL_HANDLING,
	                          bind_lambda_function_t bind_lambda = nullptr);

	//! The main scalar function to execute
	scalar_function_t function;
	//! The bind function (if any)
	bind_scalar_function_t bind;
	//! Init thread local state for the function (if any)
	init_local_state_t init_local_state;
	//! The dependency function (if any)
	dependency_function_t dependency;
	//! The statistics propagation function (if any)
	function_statistics_t statistics;
	//! The lambda bind function (if any)
	bind_lambda_function_t bind_lambda;
	//! Function to bind the result function expression directly (if any)
	function_bind_expression_t bind_expression;
	//! Gets the modified databases (if any)
	get_modified_databases_t get_modified_databases;

	function_serialize_t serialize;
	function_deserialize_t deserialize;
	//! Additional function info, passed to the bind
	shared_ptr<ScalarFunctionInfo> function_info;

	DUCKDB_API bool operator==(const ScalarFunction &rhs) const;
	DUCKDB_API bool operator!=(const ScalarFunction &rhs) const;

	DUCKDB_API bool Equal(const ScalarFunction &rhs) const;

public:
	DUCKDB_API static void NopFunction(DataChunk &input, ExpressionState &state, Vector &result);

	template <class TA, class TR, class OP>
	static void UnaryFunction(DataChunk &input, ExpressionState &state, Vector &result) {
		D_ASSERT(input.ColumnCount() >= 1);
		UnaryExecutor::Execute<TA, TR, OP>(input.data[0], result, input.size());
	}

	template <class TA, class TB, class TR, class OP>
	static void BinaryFunction(DataChunk &input, ExpressionState &state, Vector &result) {
		D_ASSERT(input.ColumnCount() == 2);
		BinaryExecutor::ExecuteStandard<TA, TB, TR, OP>(input.data[0], input.data[1], result, input.size());
	}

	template <class TA, class TB, class TC, class TR, class OP>
	static void TernaryFunction(DataChunk &input, ExpressionState &state, Vector &result) {
		D_ASSERT(input.ColumnCount() == 3);
		TernaryExecutor::ExecuteStandard<TA, TB, TC, TR, OP>(input.data[0], input.data[1], input.data[2], result,
		                                                     input.size());
	}

public:
	template <class OP>
	static scalar_function_t GetScalarUnaryFunction(const LogicalType &type) {
		scalar_function_t function;
		switch (type.id()) {
		case LogicalTypeId::TINYINT:
			function = &ScalarFunction::UnaryFunction<int8_t, int8_t, OP>;
			break;
		case LogicalTypeId::SMALLINT:
			function = &ScalarFunction::UnaryFunction<int16_t, int16_t, OP>;
			break;
		case LogicalTypeId::INTEGER:
			function = &ScalarFunction::UnaryFunction<int32_t, int32_t, OP>;
			break;
		case LogicalTypeId::BIGINT:
			function = &ScalarFunction::UnaryFunction<int64_t, int64_t, OP>;
			break;
		case LogicalTypeId::UTINYINT:
			function = &ScalarFunction::UnaryFunction<uint8_t, uint8_t, OP>;
			break;
		case LogicalTypeId::USMALLINT:
			function = &ScalarFunction::UnaryFunction<uint16_t, uint16_t, OP>;
			break;
		case LogicalTypeId::UINTEGER:
			function = &ScalarFunction::UnaryFunction<uint32_t, uint32_t, OP>;
			break;
		case LogicalTypeId::UBIGINT:
			function = &ScalarFunction::UnaryFunction<uint64_t, uint64_t, OP>;
			break;
		case LogicalTypeId::HUGEINT:
			function = &ScalarFunction::UnaryFunction<hugeint_t, hugeint_t, OP>;
			break;
		case LogicalTypeId::UHUGEINT:
			function = &ScalarFunction::UnaryFunction<uhugeint_t, uhugeint_t, OP>;
			break;
		case LogicalTypeId::FLOAT:
			function = &ScalarFunction::UnaryFunction<float, float, OP>;
			break;
		case LogicalTypeId::DOUBLE:
			function = &ScalarFunction::UnaryFunction<double, double, OP>;
			break;
		default:
			throw InternalException("Unimplemented type for GetScalarUnaryFunction");
		}
		return function;
	}

	template <class TR, class OP>
	static scalar_function_t GetScalarUnaryFunctionFixedReturn(const LogicalType &type) {
		scalar_function_t function;
		switch (type.id()) {
		case LogicalTypeId::TINYINT:
			function = &ScalarFunction::UnaryFunction<int8_t, TR, OP>;
			break;
		case LogicalTypeId::SMALLINT:
			function = &ScalarFunction::UnaryFunction<int16_t, TR, OP>;
			break;
		case LogicalTypeId::INTEGER:
			function = &ScalarFunction::UnaryFunction<int32_t, TR, OP>;
			break;
		case LogicalTypeId::BIGINT:
			function = &ScalarFunction::UnaryFunction<int64_t, TR, OP>;
			break;
		case LogicalTypeId::UTINYINT:
			function = &ScalarFunction::UnaryFunction<uint8_t, TR, OP>;
			break;
		case LogicalTypeId::USMALLINT:
			function = &ScalarFunction::UnaryFunction<uint16_t, TR, OP>;
			break;
		case LogicalTypeId::UINTEGER:
			function = &ScalarFunction::UnaryFunction<uint32_t, TR, OP>;
			break;
		case LogicalTypeId::UBIGINT:
			function = &ScalarFunction::UnaryFunction<uint64_t, TR, OP>;
			break;
		case LogicalTypeId::HUGEINT:
			function = &ScalarFunction::UnaryFunction<hugeint_t, TR, OP>;
			break;
		case LogicalTypeId::UHUGEINT:
			function = &ScalarFunction::UnaryFunction<uhugeint_t, TR, OP>;
			break;
		case LogicalTypeId::FLOAT:
			function = &ScalarFunction::UnaryFunction<float, TR, OP>;
			break;
		case LogicalTypeId::DOUBLE:
			function = &ScalarFunction::UnaryFunction<double, TR, OP>;
			break;
		default:
			throw InternalException("Unimplemented type for GetScalarUnaryFunctionFixedReturn");
		}
		return function;
	}
};

} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/function/aggregate_function.hpp
//
//
//===----------------------------------------------------------------------===//



//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/array.hpp
//
//
//===----------------------------------------------------------------------===//



#include <array>

namespace duckdb {
using std::array;
}

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/vector_operations/aggregate_executor.hpp
//
//
//===----------------------------------------------------------------------===//






//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/function/aggregate_state.hpp
//
//
//===----------------------------------------------------------------------===//





//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/storage/statistics/node_statistics.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

class NodeStatistics {
public:
	NodeStatistics() : has_estimated_cardinality(false), has_max_cardinality(false) {
	}
	explicit NodeStatistics(idx_t estimated_cardinality)
	    : has_estimated_cardinality(true), estimated_cardinality(estimated_cardinality), has_max_cardinality(false) {
	}
	NodeStatistics(idx_t estimated_cardinality, idx_t max_cardinality)
	    : has_estimated_cardinality(true), estimated_cardinality(estimated_cardinality), has_max_cardinality(true),
	      max_cardinality(max_cardinality) {
	}

	//! Whether or not the node has an estimated cardinality specified
	bool has_estimated_cardinality;
	//! The estimated cardinality at the specified node
	idx_t estimated_cardinality;
	//! Whether or not the node has a maximum cardinality specified
	bool has_max_cardinality;
	//! The max possible cardinality at the specified node
	idx_t max_cardinality;
};

} // namespace duckdb


namespace duckdb {

enum class AggregateType : uint8_t { NON_DISTINCT = 1, DISTINCT = 2 };
//! Whether or not the input order influences the result of the aggregate
enum class AggregateOrderDependent : uint8_t { ORDER_DEPENDENT = 1, NOT_ORDER_DEPENDENT = 2 };
//! Whether or not the combiner needs to preserve the source
enum class AggregateCombineType : uint8_t { PRESERVE_INPUT = 1, ALLOW_DESTRUCTIVE = 2 };

class BoundAggregateExpression;

struct AggregateInputData {
	AggregateInputData(optional_ptr<FunctionData> bind_data_p, ArenaAllocator &allocator_p,
	                   AggregateCombineType combine_type_p = AggregateCombineType::PRESERVE_INPUT)
	    : bind_data(bind_data_p), allocator(allocator_p), combine_type(combine_type_p) {
	}
	optional_ptr<FunctionData> bind_data;
	ArenaAllocator &allocator;
	AggregateCombineType combine_type;
};

struct AggregateUnaryInput {
	AggregateUnaryInput(AggregateInputData &input_p, ValidityMask &input_mask_p)
	    : input(input_p), input_mask(input_mask_p), input_idx(0) {
	}

	AggregateInputData &input;
	ValidityMask &input_mask;
	idx_t input_idx;

	inline bool RowIsValid() {
		return input_mask.RowIsValid(input_idx);
	}
};

struct AggregateBinaryInput {
	AggregateBinaryInput(AggregateInputData &input_p, ValidityMask &left_mask_p, ValidityMask &right_mask_p)
	    : input(input_p), left_mask(left_mask_p), right_mask(right_mask_p) {
	}

	AggregateInputData &input;
	ValidityMask &left_mask;
	ValidityMask &right_mask;
	idx_t lidx;
	idx_t ridx;
};

struct AggregateFinalizeData {
	AggregateFinalizeData(Vector &result_p, AggregateInputData &input_p)
	    : result(result_p), input(input_p), result_idx(0) {
	}

	Vector &result;
	AggregateInputData &input;
	idx_t result_idx;

	inline void ReturnNull() {
		switch (result.GetVectorType()) {
		case VectorType::FLAT_VECTOR:
			FlatVector::SetNull(result, result_idx, true);
			break;
		case VectorType::CONSTANT_VECTOR:
			ConstantVector::SetNull(result, true);
			break;
		default:
			throw InternalException("Invalid result vector type for aggregate");
		}
	}

	inline string_t ReturnString(string_t value) {
		return StringVector::AddStringOrBlob(result, value);
	}
};

struct AggregateStatisticsInput {
	AggregateStatisticsInput(optional_ptr<FunctionData> bind_data_p, vector<BaseStatistics> &child_stats_p,
	                         optional_ptr<NodeStatistics> node_stats_p)
	    : bind_data(bind_data_p), child_stats(child_stats_p), node_stats(node_stats_p) {
	}

	optional_ptr<FunctionData> bind_data;
	vector<BaseStatistics> &child_stats;
	optional_ptr<NodeStatistics> node_stats;
};

} // namespace duckdb


namespace duckdb {

// structs
struct AggregateInputData;

// The bounds of a window frame
struct FrameBounds {
	FrameBounds() : start(0), end(0) {};
	FrameBounds(idx_t start, idx_t end) : start(start), end(end) {};
	idx_t start = 0;
	idx_t end = 0;
};

// A set of window subframes for windowed EXCLUDE
using SubFrames = vector<FrameBounds>;

class AggregateExecutor {
private:
	template <class STATE_TYPE, class OP>
	static inline void NullaryFlatLoop(STATE_TYPE **__restrict states, AggregateInputData &aggr_input_data,
	                                   idx_t count) {
		for (idx_t i = 0; i < count; i++) {
			OP::template Operation<STATE_TYPE, OP>(*states[i], aggr_input_data, i);
		}
	}

	template <class STATE_TYPE, class OP>
	static inline void NullaryScatterLoop(STATE_TYPE **__restrict states, AggregateInputData &aggr_input_data,
	                                      const SelectionVector &ssel, idx_t count) {

		for (idx_t i = 0; i < count; i++) {
			auto sidx = ssel.get_index(i);
			OP::template Operation<STATE_TYPE, OP>(*states[sidx], aggr_input_data, sidx);
		}
	}

	template <class STATE_TYPE, class INPUT_TYPE, class OP>
	static inline void UnaryFlatLoop(const INPUT_TYPE *__restrict idata, AggregateInputData &aggr_input_data,
	                                 STATE_TYPE **__restrict states, ValidityMask &mask, idx_t count) {
		if (OP::IgnoreNull() && !mask.AllValid()) {
			AggregateUnaryInput input(aggr_input_data, mask);
			auto &base_idx = input.input_idx;
			base_idx = 0;
			auto entry_count = ValidityMask::EntryCount(count);
			for (idx_t entry_idx = 0; entry_idx < entry_count; entry_idx++) {
				auto validity_entry = mask.GetValidityEntry(entry_idx);
				idx_t next = MinValue<idx_t>(base_idx + ValidityMask::BITS_PER_VALUE, count);
				if (ValidityMask::AllValid(validity_entry)) {
					// all valid: perform operation
					for (; base_idx < next; base_idx++) {
						OP::template Operation<INPUT_TYPE, STATE_TYPE, OP>(*states[base_idx], idata[base_idx], input);
					}
				} else if (ValidityMask::NoneValid(validity_entry)) {
					// nothing valid: skip all
					base_idx = next;
					continue;
				} else {
					// partially valid: need to check individual elements for validity
					idx_t start = base_idx;
					for (; base_idx < next; base_idx++) {
						if (ValidityMask::RowIsValid(validity_entry, base_idx - start)) {
							OP::template Operation<INPUT_TYPE, STATE_TYPE, OP>(*states[base_idx], idata[base_idx],
							                                                   input);
						}
					}
				}
			}
		} else {
			AggregateUnaryInput input(aggr_input_data, mask);
			auto &i = input.input_idx;
			for (i = 0; i < count; i++) {
				OP::template Operation<INPUT_TYPE, STATE_TYPE, OP>(*states[i], idata[i], input);
			}
		}
	}

	template <class STATE_TYPE, class INPUT_TYPE, class OP>
	static inline void UnaryScatterLoop(const INPUT_TYPE *__restrict idata, AggregateInputData &aggr_input_data,
	                                    STATE_TYPE **__restrict states, const SelectionVector &isel,
	                                    const SelectionVector &ssel, ValidityMask &mask, idx_t count) {
		if (OP::IgnoreNull() && !mask.AllValid()) {
			// potential NULL values and NULL values are ignored
			AggregateUnaryInput input(aggr_input_data, mask);
			for (idx_t i = 0; i < count; i++) {
				input.input_idx = isel.get_index(i);
				auto sidx = ssel.get_index(i);
				if (mask.RowIsValid(input.input_idx)) {
					OP::template Operation<INPUT_TYPE, STATE_TYPE, OP>(*states[sidx], idata[input.input_idx], input);
				}
			}
		} else {
			// quick path: no NULL values or NULL values are not ignored
			AggregateUnaryInput input(aggr_input_data, mask);
			for (idx_t i = 0; i < count; i++) {
				input.input_idx = isel.get_index(i);
				auto sidx = ssel.get_index(i);
				OP::template Operation<INPUT_TYPE, STATE_TYPE, OP>(*states[sidx], idata[input.input_idx], input);
			}
		}
	}

	template <class STATE_TYPE, class INPUT_TYPE, class OP>
	static inline void UnaryFlatUpdateLoop(const INPUT_TYPE *__restrict idata, AggregateInputData &aggr_input_data,
	                                       STATE_TYPE *__restrict state, idx_t count, ValidityMask &mask) {
		AggregateUnaryInput input(aggr_input_data, mask);
		auto &base_idx = input.input_idx;
		base_idx = 0;
		auto entry_count = ValidityMask::EntryCount(count);
		for (idx_t entry_idx = 0; entry_idx < entry_count; entry_idx++) {
			auto validity_entry = mask.GetValidityEntry(entry_idx);
			idx_t next = MinValue<idx_t>(base_idx + ValidityMask::BITS_PER_VALUE, count);
			if (!OP::IgnoreNull() || ValidityMask::AllValid(validity_entry)) {
				// all valid: perform operation
				for (; base_idx < next; base_idx++) {
					OP::template Operation<INPUT_TYPE, STATE_TYPE, OP>(*state, idata[base_idx], input);
				}
			} else if (ValidityMask::NoneValid(validity_entry)) {
				// nothing valid: skip all
				base_idx = next;
				continue;
			} else {
				// partially valid: need to check individual elements for validity
				idx_t start = base_idx;
				for (; base_idx < next; base_idx++) {
					if (ValidityMask::RowIsValid(validity_entry, base_idx - start)) {
						OP::template Operation<INPUT_TYPE, STATE_TYPE, OP>(*state, idata[base_idx], input);
					}
				}
			}
		}
	}

	template <class STATE_TYPE, class INPUT_TYPE, class OP>
	static inline void UnaryUpdateLoop(const INPUT_TYPE *__restrict idata, AggregateInputData &aggr_input_data,
	                                   STATE_TYPE *__restrict state, idx_t count, ValidityMask &mask,
	                                   const SelectionVector &__restrict sel_vector) {
		AggregateUnaryInput input(aggr_input_data, mask);
		if (OP::IgnoreNull() && !mask.AllValid()) {
			// potential NULL values and NULL values are ignored
			for (idx_t i = 0; i < count; i++) {
				input.input_idx = sel_vector.get_index(i);
				if (mask.RowIsValid(input.input_idx)) {
					OP::template Operation<INPUT_TYPE, STATE_TYPE, OP>(*state, idata[input.input_idx], input);
				}
			}
		} else {
			// quick path: no NULL values or NULL values are not ignored
			for (idx_t i = 0; i < count; i++) {
				input.input_idx = sel_vector.get_index(i);
				OP::template Operation<INPUT_TYPE, STATE_TYPE, OP>(*state, idata[input.input_idx], input);
			}
		}
	}

	template <class STATE_TYPE, class A_TYPE, class B_TYPE, class OP>
	static inline void BinaryScatterLoop(const A_TYPE *__restrict adata, AggregateInputData &aggr_input_data,
	                                     const B_TYPE *__restrict bdata, STATE_TYPE **__restrict states, idx_t count,
	                                     const SelectionVector &asel, const SelectionVector &bsel,
	                                     const SelectionVector &ssel, ValidityMask &avalidity,
	                                     ValidityMask &bvalidity) {
		AggregateBinaryInput input(aggr_input_data, avalidity, bvalidity);
		if (OP::IgnoreNull() && (!avalidity.AllValid() || !bvalidity.AllValid())) {
			// potential NULL values and NULL values are ignored
			for (idx_t i = 0; i < count; i++) {
				input.lidx = asel.get_index(i);
				input.ridx = bsel.get_index(i);
				auto sidx = ssel.get_index(i);
				if (avalidity.RowIsValid(input.lidx) && bvalidity.RowIsValid(input.ridx)) {
					OP::template Operation<A_TYPE, B_TYPE, STATE_TYPE, OP>(*states[sidx], adata[input.lidx],
					                                                       bdata[input.ridx], input);
				}
			}
		} else {
			// quick path: no NULL values or NULL values are not ignored
			for (idx_t i = 0; i < count; i++) {
				input.lidx = asel.get_index(i);
				input.ridx = bsel.get_index(i);
				auto sidx = ssel.get_index(i);
				OP::template Operation<A_TYPE, B_TYPE, STATE_TYPE, OP>(*states[sidx], adata[input.lidx],
				                                                       bdata[input.ridx], input);
			}
		}
	}

	template <class STATE_TYPE, class A_TYPE, class B_TYPE, class OP>
	static inline void BinaryUpdateLoop(const A_TYPE *__restrict adata, AggregateInputData &aggr_input_data,
	                                    const B_TYPE *__restrict bdata, STATE_TYPE *__restrict state, idx_t count,
	                                    const SelectionVector &asel, const SelectionVector &bsel,
	                                    ValidityMask &avalidity, ValidityMask &bvalidity) {
		AggregateBinaryInput input(aggr_input_data, avalidity, bvalidity);
		if (OP::IgnoreNull() && (!avalidity.AllValid() || !bvalidity.AllValid())) {
			// potential NULL values and NULL values are ignored
			for (idx_t i = 0; i < count; i++) {
				input.lidx = asel.get_index(i);
				input.ridx = bsel.get_index(i);
				if (avalidity.RowIsValid(input.lidx) && bvalidity.RowIsValid(input.ridx)) {
					OP::template Operation<A_TYPE, B_TYPE, STATE_TYPE, OP>(*state, adata[input.lidx], bdata[input.ridx],
					                                                       input);
				}
			}
		} else {
			// quick path: no NULL values or NULL values are not ignored
			for (idx_t i = 0; i < count; i++) {
				input.lidx = asel.get_index(i);
				input.ridx = bsel.get_index(i);
				OP::template Operation<A_TYPE, B_TYPE, STATE_TYPE, OP>(*state, adata[input.lidx], bdata[input.ridx],
				                                                       input);
			}
		}
	}

public:
	template <class STATE_TYPE, class OP>
	static void NullaryScatter(Vector &states, AggregateInputData &aggr_input_data, idx_t count) {
		if (states.GetVectorType() == VectorType::CONSTANT_VECTOR) {
			auto sdata = ConstantVector::GetData<STATE_TYPE *>(states);
			OP::template ConstantOperation<STATE_TYPE, OP>(**sdata, aggr_input_data, count);
		} else if (states.GetVectorType() == VectorType::FLAT_VECTOR) {
			auto sdata = FlatVector::GetData<STATE_TYPE *>(states);
			NullaryFlatLoop<STATE_TYPE, OP>(sdata, aggr_input_data, count);
		} else {
			UnifiedVectorFormat sdata;
			states.ToUnifiedFormat(count, sdata);
			NullaryScatterLoop<STATE_TYPE, OP>((STATE_TYPE **)sdata.data, aggr_input_data, *sdata.sel, count);
		}
	}

	template <class STATE_TYPE, class OP>
	static void NullaryUpdate(data_ptr_t state, AggregateInputData &aggr_input_data, idx_t count) {
		OP::template ConstantOperation<STATE_TYPE, OP>(*reinterpret_cast<STATE_TYPE *>(state), aggr_input_data, count);
	}

	template <class STATE_TYPE, class INPUT_TYPE, class OP>
	static void UnaryScatter(Vector &input, Vector &states, AggregateInputData &aggr_input_data, idx_t count) {
		if (input.GetVectorType() == VectorType::CONSTANT_VECTOR &&
		    states.GetVectorType() == VectorType::CONSTANT_VECTOR) {
			if (OP::IgnoreNull() && ConstantVector::IsNull(input)) {
				// constant NULL input in function that ignores NULL values
				return;
			}
			// regular constant: get first state
			auto idata = ConstantVector::GetData<INPUT_TYPE>(input);
			auto sdata = ConstantVector::GetData<STATE_TYPE *>(states);
			AggregateUnaryInput input_data(aggr_input_data, ConstantVector::Validity(input));
			OP::template ConstantOperation<INPUT_TYPE, STATE_TYPE, OP>(**sdata, *idata, input_data, count);
		} else if (input.GetVectorType() == VectorType::FLAT_VECTOR &&
		           states.GetVectorType() == VectorType::FLAT_VECTOR) {
			auto idata = FlatVector::GetData<INPUT_TYPE>(input);
			auto sdata = FlatVector::GetData<STATE_TYPE *>(states);
			UnaryFlatLoop<STATE_TYPE, INPUT_TYPE, OP>(idata, aggr_input_data, sdata, FlatVector::Validity(input),
			                                          count);
		} else {
			UnifiedVectorFormat idata, sdata;
			input.ToUnifiedFormat(count, idata);
			states.ToUnifiedFormat(count, sdata);
			UnaryScatterLoop<STATE_TYPE, INPUT_TYPE, OP>(UnifiedVectorFormat::GetData<INPUT_TYPE>(idata),
			                                             aggr_input_data, (STATE_TYPE **)sdata.data, *idata.sel,
			                                             *sdata.sel, idata.validity, count);
		}
	}

	template <class STATE_TYPE, class INPUT_TYPE, class OP>
	static void UnaryUpdate(Vector &input, AggregateInputData &aggr_input_data, data_ptr_t state, idx_t count) {
		switch (input.GetVectorType()) {
		case VectorType::CONSTANT_VECTOR: {
			if (OP::IgnoreNull() && ConstantVector::IsNull(input)) {
				return;
			}
			auto idata = ConstantVector::GetData<INPUT_TYPE>(input);
			AggregateUnaryInput input_data(aggr_input_data, ConstantVector::Validity(input));
			OP::template ConstantOperation<INPUT_TYPE, STATE_TYPE, OP>(*reinterpret_cast<STATE_TYPE *>(state), *idata,
			                                                           input_data, count);
			break;
		}
		case VectorType::FLAT_VECTOR: {
			auto idata = FlatVector::GetData<INPUT_TYPE>(input);
			UnaryFlatUpdateLoop<STATE_TYPE, INPUT_TYPE, OP>(idata, aggr_input_data, (STATE_TYPE *)state, count,
			                                                FlatVector::Validity(input));
			break;
		}
		default: {
			UnifiedVectorFormat idata;
			input.ToUnifiedFormat(count, idata);
			UnaryUpdateLoop<STATE_TYPE, INPUT_TYPE, OP>(UnifiedVectorFormat::GetData<INPUT_TYPE>(idata),
			                                            aggr_input_data, (STATE_TYPE *)state, count, idata.validity,
			                                            *idata.sel);
			break;
		}
		}
	}

	template <class STATE_TYPE, class A_TYPE, class B_TYPE, class OP>
	static void BinaryScatter(AggregateInputData &aggr_input_data, Vector &a, Vector &b, Vector &states, idx_t count) {
		UnifiedVectorFormat adata, bdata, sdata;

		a.ToUnifiedFormat(count, adata);
		b.ToUnifiedFormat(count, bdata);
		states.ToUnifiedFormat(count, sdata);

		BinaryScatterLoop<STATE_TYPE, A_TYPE, B_TYPE, OP>(
		    UnifiedVectorFormat::GetData<A_TYPE>(adata), aggr_input_data, UnifiedVectorFormat::GetData<B_TYPE>(bdata),
		    (STATE_TYPE **)sdata.data, count, *adata.sel, *bdata.sel, *sdata.sel, adata.validity, bdata.validity);
	}

	template <class STATE_TYPE, class A_TYPE, class B_TYPE, class OP>
	static void BinaryUpdate(AggregateInputData &aggr_input_data, Vector &a, Vector &b, data_ptr_t state, idx_t count) {
		UnifiedVectorFormat adata, bdata;

		a.ToUnifiedFormat(count, adata);
		b.ToUnifiedFormat(count, bdata);

		BinaryUpdateLoop<STATE_TYPE, A_TYPE, B_TYPE, OP>(
		    UnifiedVectorFormat::GetData<A_TYPE>(adata), aggr_input_data, UnifiedVectorFormat::GetData<B_TYPE>(bdata),
		    (STATE_TYPE *)state, count, *adata.sel, *bdata.sel, adata.validity, bdata.validity);
	}

	template <class STATE_TYPE, class OP>
	static void Combine(Vector &source, Vector &target, AggregateInputData &aggr_input_data, idx_t count) {
		D_ASSERT(source.GetType().id() == LogicalTypeId::POINTER && target.GetType().id() == LogicalTypeId::POINTER);
		auto sdata = FlatVector::GetData<const STATE_TYPE *>(source);
		auto tdata = FlatVector::GetData<STATE_TYPE *>(target);

		for (idx_t i = 0; i < count; i++) {
			OP::template Combine<STATE_TYPE, OP>(*sdata[i], *tdata[i], aggr_input_data);
		}
	}

	template <class STATE_TYPE, class RESULT_TYPE, class OP>
	static void Finalize(Vector &states, AggregateInputData &aggr_input_data, Vector &result, idx_t count,
	                     idx_t offset) {
		if (states.GetVectorType() == VectorType::CONSTANT_VECTOR) {
			result.SetVectorType(VectorType::CONSTANT_VECTOR);

			auto sdata = ConstantVector::GetData<STATE_TYPE *>(states);
			auto rdata = ConstantVector::GetData<RESULT_TYPE>(result);
			AggregateFinalizeData finalize_data(result, aggr_input_data);
			OP::template Finalize<RESULT_TYPE, STATE_TYPE>(**sdata, *rdata, finalize_data);
		} else {
			D_ASSERT(states.GetVectorType() == VectorType::FLAT_VECTOR);
			result.SetVectorType(VectorType::FLAT_VECTOR);

			auto sdata = FlatVector::GetData<STATE_TYPE *>(states);
			auto rdata = FlatVector::GetData<RESULT_TYPE>(result);
			AggregateFinalizeData finalize_data(result, aggr_input_data);
			for (idx_t i = 0; i < count; i++) {
				finalize_data.result_idx = i + offset;
				OP::template Finalize<RESULT_TYPE, STATE_TYPE>(*sdata[i], rdata[finalize_data.result_idx],
				                                               finalize_data);
			}
		}
	}

	template <class STATE_TYPE, class OP>
	static void VoidFinalize(Vector &states, AggregateInputData &aggr_input_data, Vector &result, idx_t count,
	                         idx_t offset) {
		if (states.GetVectorType() == VectorType::CONSTANT_VECTOR) {
			result.SetVectorType(VectorType::CONSTANT_VECTOR);

			auto sdata = ConstantVector::GetData<STATE_TYPE *>(states);
			AggregateFinalizeData finalize_data(result, aggr_input_data);
			OP::template Finalize<STATE_TYPE>(**sdata, finalize_data);
		} else {
			D_ASSERT(states.GetVectorType() == VectorType::FLAT_VECTOR);
			result.SetVectorType(VectorType::FLAT_VECTOR);

			auto sdata = FlatVector::GetData<STATE_TYPE *>(states);
			AggregateFinalizeData finalize_data(result, aggr_input_data);
			for (idx_t i = 0; i < count; i++) {
				finalize_data.result_idx = i + offset;
				OP::template Finalize<STATE_TYPE>(*sdata[i], finalize_data);
			}
		}
	}

	template <class STATE, class INPUT_TYPE, class RESULT_TYPE, class OP>
	static void UnaryWindow(const Vector &input, const ValidityMask &ifilter, AggregateInputData &aggr_input_data,
	                        data_ptr_t state_p, const SubFrames &frames, Vector &result, idx_t ridx,
	                        const_data_ptr_t gstate_p) {

		auto idata = FlatVector::GetData<const INPUT_TYPE>(input);
		const auto &ivalid = FlatVector::Validity(input);
		auto &state = *reinterpret_cast<STATE *>(state_p);
		auto gstate = reinterpret_cast<const STATE *>(gstate_p);
		OP::template Window<STATE, INPUT_TYPE, RESULT_TYPE>(idata, ifilter, ivalid, aggr_input_data, state, frames,
		                                                    result, ridx, gstate);
	}

	template <typename OP>
	static void IntersectFrames(const SubFrames &lefts, const SubFrames &rights, OP &op) {
		const auto cover_start = MinValue(rights[0].start, lefts[0].start);
		const auto cover_end = MaxValue(rights.back().end, lefts.back().end);
		const FrameBounds last(cover_end, cover_end);

		//	Subframe indices
		idx_t l = 0;
		idx_t r = 0;
		for (auto i = cover_start; i < cover_end;) {
			uint8_t overlap = 0;

			// Are we in the previous frame?
			auto left = &last;
			if (l < lefts.size()) {
				left = &lefts[l];
				overlap |= uint8_t(left->start <= i && i < left->end) << 0;
			}

			// Are we in the current frame?
			auto right = &last;
			if (r < rights.size()) {
				right = &rights[r];
				overlap |= uint8_t(right->start <= i && i < right->end) << 1;
			}

			auto limit = i;
			switch (overlap) {
			case 0x00:
				// i ∉ F U P
				limit = MinValue(right->start, left->start);
				op.Neither(i, limit);
				break;
			case 0x01:
				// i ∈ P \ F
				limit = MinValue(left->end, right->start);
				op.Left(i, limit);
				break;
			case 0x02:
				// i ∈ F \ P
				limit = MinValue(right->end, left->start);
				op.Right(i, limit);
				break;
			case 0x03:
			default:
				D_ASSERT(overlap == 0x03);
				// i ∈ F ∩ P
				limit = MinValue(right->end, left->end);
				op.Both(i, limit);
				break;
			}

			// Advance  the subframe indices
			i = limit;
			l += (i == left->end);
			r += (i == right->end);
		}
	}

	template <class STATE_TYPE, class OP>
	static void Destroy(Vector &states, AggregateInputData &aggr_input_data, idx_t count) {
		auto sdata = FlatVector::GetData<STATE_TYPE *>(states);
		for (idx_t i = 0; i < count; i++) {
			OP::template Destroy<STATE_TYPE>(*sdata[i], aggr_input_data);
		}
	}
};

} // namespace duckdb


//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/bound_result_modifier.hpp
//
//
//===----------------------------------------------------------------------===//




//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/parser/result_modifier.hpp
//
//
//===----------------------------------------------------------------------===//





//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/enums/order_type.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

enum class OrderType : uint8_t { INVALID = 0, ORDER_DEFAULT = 1, ASCENDING = 2, DESCENDING = 3 };

enum class OrderByNullType : uint8_t { INVALID = 0, ORDER_DEFAULT = 1, NULLS_FIRST = 2, NULLS_LAST = 3 };

enum class DefaultOrderByNullType : uint8_t {
	INVALID = 0,
	NULLS_FIRST = 2,
	NULLS_LAST = 3,
	NULLS_FIRST_ON_ASC_LAST_ON_DESC = 4,
	NULLS_LAST_ON_ASC_FIRST_ON_DESC = 5
};

} // namespace duckdb



namespace duckdb {
class Deserializer;
class Serializer;

enum class ResultModifierType : uint8_t {
	LIMIT_MODIFIER = 1,
	ORDER_MODIFIER = 2,
	DISTINCT_MODIFIER = 3,
	LIMIT_PERCENT_MODIFIER = 4
};

const char *ToString(ResultModifierType value);
ResultModifierType ResultModifierFromString(const char *value);

//! A ResultModifier
class ResultModifier {
public:
	explicit ResultModifier(ResultModifierType type) : type(type) {
	}
	virtual ~ResultModifier() {
	}

	ResultModifierType type;

public:
	//! Returns true if the two result modifiers are equivalent
	virtual bool Equals(const ResultModifier &other) const;

	//! Create a copy of this ResultModifier
	virtual unique_ptr<ResultModifier> Copy() const = 0;

	virtual void Serialize(Serializer &serializer) const;
	static unique_ptr<ResultModifier> Deserialize(Deserializer &deserializer);

public:
	template <class TARGET>
	TARGET &Cast() {
		if (type != TARGET::TYPE) {
			throw InternalException("Failed to cast result modifier to type - result modifier type mismatch");
		}
		return reinterpret_cast<TARGET &>(*this);
	}

	template <class TARGET>
	const TARGET &Cast() const {
		if (type != TARGET::TYPE) {
			throw InternalException("Failed to cast result modifier to type - result modifier type mismatch");
		}
		return reinterpret_cast<const TARGET &>(*this);
	}
};

//! Single node in ORDER BY statement
struct OrderByNode {
	OrderByNode(OrderType type, OrderByNullType null_order, unique_ptr<ParsedExpression> expression)
	    : type(type), null_order(null_order), expression(std::move(expression)) {
	}

	//! Sort order, ASC or DESC
	OrderType type;
	//! The NULL sort order, NULLS_FIRST or NULLS_LAST
	OrderByNullType null_order;
	//! Expression to order by
	unique_ptr<ParsedExpression> expression;

public:
	string ToString() const;

	void Serialize(Serializer &serializer) const;
	static OrderByNode Deserialize(Deserializer &deserializer);
};

class LimitModifier : public ResultModifier {
public:
	static constexpr const ResultModifierType TYPE = ResultModifierType::LIMIT_MODIFIER;

public:
	LimitModifier() : ResultModifier(ResultModifierType::LIMIT_MODIFIER) {
	}

	//! LIMIT count
	unique_ptr<ParsedExpression> limit;
	//! OFFSET
	unique_ptr<ParsedExpression> offset;

public:
	bool Equals(const ResultModifier &other) const override;
	unique_ptr<ResultModifier> Copy() const override;

	void Serialize(Serializer &serializer) const override;
	static unique_ptr<ResultModifier> Deserialize(Deserializer &deserializer);
};

class OrderModifier : public ResultModifier {
public:
	static constexpr const ResultModifierType TYPE = ResultModifierType::ORDER_MODIFIER;

public:
	OrderModifier() : ResultModifier(ResultModifierType::ORDER_MODIFIER) {
	}

	//! List of order nodes
	vector<OrderByNode> orders;

public:
	bool Equals(const ResultModifier &other) const override;
	unique_ptr<ResultModifier> Copy() const override;

	void Serialize(Serializer &serializer) const override;
	static unique_ptr<ResultModifier> Deserialize(Deserializer &deserializer);

	static bool Equals(const unique_ptr<OrderModifier> &left, const unique_ptr<OrderModifier> &right);
};

class DistinctModifier : public ResultModifier {
public:
	static constexpr const ResultModifierType TYPE = ResultModifierType::DISTINCT_MODIFIER;

public:
	DistinctModifier() : ResultModifier(ResultModifierType::DISTINCT_MODIFIER) {
	}

	//! list of distinct on targets (if any)
	vector<unique_ptr<ParsedExpression>> distinct_on_targets;

public:
	bool Equals(const ResultModifier &other) const override;
	unique_ptr<ResultModifier> Copy() const override;

	void Serialize(Serializer &serializer) const override;
	static unique_ptr<ResultModifier> Deserialize(Deserializer &deserializer);
};

class LimitPercentModifier : public ResultModifier {
public:
	static constexpr const ResultModifierType TYPE = ResultModifierType::LIMIT_PERCENT_MODIFIER;

public:
	LimitPercentModifier() : ResultModifier(ResultModifierType::LIMIT_PERCENT_MODIFIER) {
	}

	//! LIMIT %
	unique_ptr<ParsedExpression> limit;
	//! OFFSET
	unique_ptr<ParsedExpression> offset;

public:
	bool Equals(const ResultModifier &other) const override;
	unique_ptr<ResultModifier> Copy() const override;

	void Serialize(Serializer &serializer) const override;
	static unique_ptr<ResultModifier> Deserialize(Deserializer &deserializer);
};

} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/bound_statement.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

class LogicalOperator;
struct LogicalType;

struct BoundStatement {
	unique_ptr<LogicalOperator> plan;
	vector<LogicalType> types;
	vector<string> names;
};

} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/expression.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {
class BaseStatistics;
class ClientContext;

//!  The Expression class represents a bound Expression with a return type
class Expression : public BaseExpression {
public:
	Expression(ExpressionType type, ExpressionClass expression_class, LogicalType return_type);
	~Expression() override;

	//! The return type of the expression
	LogicalType return_type;
	//! Expression statistics (if any) - ONLY USED FOR VERIFICATION
	unique_ptr<BaseStatistics> verification_stats;

public:
	bool IsAggregate() const override;
	bool IsWindow() const override;
	bool HasSubquery() const override;
	bool IsScalar() const override;
	bool HasParameter() const override;
	virtual bool IsVolatile() const;
	virtual bool IsConsistent() const;
	virtual bool PropagatesNullValues() const;
	virtual bool IsFoldable() const;

	hash_t Hash() const override;

	bool Equals(const BaseExpression &other) const override {
		if (!BaseExpression::Equals(other)) {
			return false;
		}
		return return_type == reinterpret_cast<const Expression &>(other).return_type;
	}
	static bool Equals(const Expression &left, const Expression &right) {
		return left.Equals(right);
	}
	static bool Equals(const unique_ptr<Expression> &left, const unique_ptr<Expression> &right);
	static bool ListEquals(const vector<unique_ptr<Expression>> &left, const vector<unique_ptr<Expression>> &right);
	//! Create a copy of this expression
	virtual unique_ptr<Expression> Copy() const = 0;

	virtual void Serialize(Serializer &serializer) const;
	static unique_ptr<Expression> Deserialize(Deserializer &deserializer);

protected:
	//! Copy base Expression properties from another expression to this one,
	//! used in Copy method
	void CopyProperties(const Expression &other) {
		type = other.type;
		expression_class = other.expression_class;
		alias = other.alias;
		return_type = other.return_type;
		query_location = other.query_location;
	}
};

} // namespace duckdb



namespace duckdb {

//! A ResultModifier
class BoundResultModifier {
public:
	explicit BoundResultModifier(ResultModifierType type);
	virtual ~BoundResultModifier();

	ResultModifierType type;

public:
	template <class TARGET>
	TARGET &Cast() {
		if (type != TARGET::TYPE) {
			throw InternalException("Failed to cast result modifier to type - result modifier type mismatch");
		}
		return reinterpret_cast<TARGET &>(*this);
	}

	template <class TARGET>
	const TARGET &Cast() const {
		if (type != TARGET::TYPE) {
			throw InternalException("Failed to cast result modifier to type - result modifier type mismatch");
		}
		return reinterpret_cast<const TARGET &>(*this);
	}
};

struct BoundOrderByNode {
public:
	static constexpr const ResultModifierType TYPE = ResultModifierType::ORDER_MODIFIER;

public:
	BoundOrderByNode(OrderType type, OrderByNullType null_order, unique_ptr<Expression> expression);
	BoundOrderByNode(OrderType type, OrderByNullType null_order, unique_ptr<Expression> expression,
	                 unique_ptr<BaseStatistics> stats);

	OrderType type;
	OrderByNullType null_order;
	unique_ptr<Expression> expression;
	unique_ptr<BaseStatistics> stats;

public:
	BoundOrderByNode Copy() const;
	bool Equals(const BoundOrderByNode &other) const;
	string ToString() const;

	void Serialize(Serializer &serializer) const;
	static BoundOrderByNode Deserialize(Deserializer &deserializer);
};

enum class LimitNodeType : uint8_t {
	UNSET = 0,
	CONSTANT_VALUE = 1,
	CONSTANT_PERCENTAGE = 2,
	EXPRESSION_VALUE = 3,
	EXPRESSION_PERCENTAGE = 4
};

struct BoundLimitNode {
public:
	BoundLimitNode();
	BoundLimitNode(LimitNodeType type, idx_t constant_integer, double constant_percentage,
	               unique_ptr<Expression> expression);

public:
	static BoundLimitNode ConstantValue(int64_t value);
	static BoundLimitNode ConstantPercentage(double percentage);
	static BoundLimitNode ExpressionValue(unique_ptr<Expression> expression);
	static BoundLimitNode ExpressionPercentage(unique_ptr<Expression> expression);

	LimitNodeType Type() const {
		return type;
	}

	//! Returns the constant value, only valid if Type() == CONSTANT_VALUE
	idx_t GetConstantValue() const;
	//! Returns the constant percentage, only valid if Type() == CONSTANT_PERCENTAGE
	double GetConstantPercentage() const;
	//! Returns the constant percentage, only valid if Type() == EXPRESSION_VALUE
	const Expression &GetValueExpression() const;
	//! Returns the constant percentage, only valid if Type() == EXPRESSION_PERCENTAGE
	const Expression &GetPercentageExpression() const;

	//! Returns a pointer to the expression - should only be used for limit-agnostic optimizations.
	//! Prefer using the methods above in other scenarios.
	unique_ptr<Expression> &GetExpression() {
		return expression;
	}

	void Serialize(Serializer &serializer) const;
	static BoundLimitNode Deserialize(Deserializer &deserializer);

private:
	LimitNodeType type = LimitNodeType::UNSET;
	//! Integer value, if value is a constant non-percentage
	idx_t constant_integer = 0;
	//! Percentage value, if value is a constant percentage
	double constant_percentage = -1;
	//! Expression in case node is not constant
	unique_ptr<Expression> expression;

private:
	explicit BoundLimitNode(int64_t constant_value);
	explicit BoundLimitNode(double percentage_value);
	explicit BoundLimitNode(unique_ptr<Expression> expression, bool is_percentage);
};

class BoundLimitModifier : public BoundResultModifier {
public:
	static constexpr const ResultModifierType TYPE = ResultModifierType::LIMIT_MODIFIER;

public:
	BoundLimitModifier();

	//! LIMIT
	BoundLimitNode limit_val;
	//! OFFSET
	BoundLimitNode offset_val;
};

class BoundOrderModifier : public BoundResultModifier {
public:
	static constexpr const ResultModifierType TYPE = ResultModifierType::ORDER_MODIFIER;

public:
	BoundOrderModifier();

	//! List of order nodes
	vector<BoundOrderByNode> orders;

	unique_ptr<BoundOrderModifier> Copy() const;
	static bool Equals(const BoundOrderModifier &left, const BoundOrderModifier &right);
	static bool Equals(const unique_ptr<BoundOrderModifier> &left, const unique_ptr<BoundOrderModifier> &right);

	void Serialize(Serializer &serializer) const;
	static unique_ptr<BoundOrderModifier> Deserialize(Deserializer &deserializer);

	//! Remove unneeded/duplicate order elements.
	//! Returns true of orders is not empty.
	bool Simplify(const vector<unique_ptr<Expression>> &groups);
};

enum class DistinctType : uint8_t { DISTINCT = 0, DISTINCT_ON = 1 };

class BoundDistinctModifier : public BoundResultModifier {
public:
	static constexpr const ResultModifierType TYPE = ResultModifierType::DISTINCT_MODIFIER;

public:
	BoundDistinctModifier();

	//! Whether or not this is a DISTINCT or DISTINCT ON
	DistinctType distinct_type;
	//! list of distinct on targets
	vector<unique_ptr<Expression>> target_distincts;
};

} // namespace duckdb



namespace duckdb {

//! A half-open range of frame boundary values _relative to the current row_
//! This is why they are signed values.
struct FrameDelta {
	FrameDelta() : begin(0), end(0) {};
	FrameDelta(int64_t begin, int64_t end) : begin(begin), end(end) {};
	int64_t begin = 0;
	int64_t end = 0;
};

//! The half-open ranges of frame boundary values relative to the current row
using FrameStats = array<FrameDelta, 2>;

//! The partition data for custom window functions
struct WindowPartitionInput {
	WindowPartitionInput(const Vector inputs[], idx_t input_count, idx_t count, const ValidityMask &filter_mask,
	                     const FrameStats &stats)
	    : inputs(inputs), input_count(input_count), count(count), filter_mask(filter_mask), stats(stats) {
	}
	const Vector *inputs;
	idx_t input_count;
	idx_t count;
	const ValidityMask &filter_mask;
	const FrameStats stats;
};

//! The type used for sizing hashed aggregate function states
typedef idx_t (*aggregate_size_t)(const AggregateFunction &function);
//! The type used for initializing hashed aggregate function states
typedef void (*aggregate_initialize_t)(const AggregateFunction &function, data_ptr_t state);
//! The type used for updating hashed aggregate functions
typedef void (*aggregate_update_t)(Vector inputs[], AggregateInputData &aggr_input_data, idx_t input_count,
                                   Vector &state, idx_t count);
//! The type used for combining hashed aggregate states
typedef void (*aggregate_combine_t)(Vector &state, Vector &combined, AggregateInputData &aggr_input_data, idx_t count);
//! The type used for finalizing hashed aggregate function payloads
typedef void (*aggregate_finalize_t)(Vector &state, AggregateInputData &aggr_input_data, Vector &result, idx_t count,
                                     idx_t offset);
//! The type used for propagating statistics in aggregate functions (optional)
typedef unique_ptr<BaseStatistics> (*aggregate_statistics_t)(ClientContext &context, BoundAggregateExpression &expr,
                                                             AggregateStatisticsInput &input);
//! Binds the scalar function and creates the function data
typedef unique_ptr<FunctionData> (*bind_aggregate_function_t)(ClientContext &context, AggregateFunction &function,
                                                              vector<unique_ptr<Expression>> &arguments);
//! The type used for the aggregate destructor method. NOTE: this method is used in destructors and MAY NOT throw.
typedef void (*aggregate_destructor_t)(Vector &state, AggregateInputData &aggr_input_data, idx_t count);

//! The type used for updating simple (non-grouped) aggregate functions
typedef void (*aggregate_simple_update_t)(Vector inputs[], AggregateInputData &aggr_input_data, idx_t input_count,
                                          data_ptr_t state, idx_t count);

//! The type used for computing complex/custom windowed aggregate functions (optional)
typedef void (*aggregate_window_t)(AggregateInputData &aggr_input_data, const WindowPartitionInput &partition,
                                   const_data_ptr_t g_state, data_ptr_t l_state, const SubFrames &subframes,
                                   Vector &result, idx_t rid);

//! The type used for initializing shared complex/custom windowed aggregate state (optional)
typedef void (*aggregate_wininit_t)(AggregateInputData &aggr_input_data, const WindowPartitionInput &partition,
                                    data_ptr_t g_state);

typedef void (*aggregate_serialize_t)(Serializer &serializer, const optional_ptr<FunctionData> bind_data,
                                      const AggregateFunction &function);
typedef unique_ptr<FunctionData> (*aggregate_deserialize_t)(Deserializer &deserializer, AggregateFunction &function);

struct AggregateFunctionInfo {
	DUCKDB_API virtual ~AggregateFunctionInfo();

	template <class TARGET>
	TARGET &Cast() {
		DynamicCastCheck<TARGET>(this);
		return reinterpret_cast<TARGET &>(*this);
	}
	template <class TARGET>
	const TARGET &Cast() const {
		DynamicCastCheck<TARGET>(this);
		return reinterpret_cast<const TARGET &>(*this);
	}
};

class AggregateFunction : public BaseScalarFunction { // NOLINT: work-around bug in clang-tidy
public:
	AggregateFunction(const string &name, const vector<LogicalType> &arguments, const LogicalType &return_type,
	                  aggregate_size_t state_size, aggregate_initialize_t initialize, aggregate_update_t update,
	                  aggregate_combine_t combine, aggregate_finalize_t finalize,
	                  FunctionNullHandling null_handling = FunctionNullHandling::DEFAULT_NULL_HANDLING,
	                  aggregate_simple_update_t simple_update = nullptr, bind_aggregate_function_t bind = nullptr,
	                  aggregate_destructor_t destructor = nullptr, aggregate_statistics_t statistics = nullptr,
	                  aggregate_window_t window = nullptr, aggregate_serialize_t serialize = nullptr,
	                  aggregate_deserialize_t deserialize = nullptr)
	    : BaseScalarFunction(name, arguments, return_type, FunctionStability::CONSISTENT,
	                         LogicalType(LogicalTypeId::INVALID), null_handling),
	      state_size(state_size), initialize(initialize), update(update), combine(combine), finalize(finalize),
	      simple_update(simple_update), window(window), bind(bind), destructor(destructor), statistics(statistics),
	      serialize(serialize), deserialize(deserialize), order_dependent(AggregateOrderDependent::ORDER_DEPENDENT) {
	}

	AggregateFunction(const string &name, const vector<LogicalType> &arguments, const LogicalType &return_type,
	                  aggregate_size_t state_size, aggregate_initialize_t initialize, aggregate_update_t update,
	                  aggregate_combine_t combine, aggregate_finalize_t finalize,
	                  aggregate_simple_update_t simple_update = nullptr, bind_aggregate_function_t bind = nullptr,
	                  aggregate_destructor_t destructor = nullptr, aggregate_statistics_t statistics = nullptr,
	                  aggregate_window_t window = nullptr, aggregate_serialize_t serialize = nullptr,
	                  aggregate_deserialize_t deserialize = nullptr)
	    : BaseScalarFunction(name, arguments, return_type, FunctionStability::CONSISTENT,
	                         LogicalType(LogicalTypeId::INVALID)),
	      state_size(state_size), initialize(initialize), update(update), combine(combine), finalize(finalize),
	      simple_update(simple_update), window(window), bind(bind), destructor(destructor), statistics(statistics),
	      serialize(serialize), deserialize(deserialize), order_dependent(AggregateOrderDependent::ORDER_DEPENDENT) {
	}

	AggregateFunction(const vector<LogicalType> &arguments, const LogicalType &return_type, aggregate_size_t state_size,
	                  aggregate_initialize_t initialize, aggregate_update_t update, aggregate_combine_t combine,
	                  aggregate_finalize_t finalize,
	                  FunctionNullHandling null_handling = FunctionNullHandling::DEFAULT_NULL_HANDLING,
	                  aggregate_simple_update_t simple_update = nullptr, bind_aggregate_function_t bind = nullptr,
	                  aggregate_destructor_t destructor = nullptr, aggregate_statistics_t statistics = nullptr,
	                  aggregate_window_t window = nullptr, aggregate_serialize_t serialize = nullptr,
	                  aggregate_deserialize_t deserialize = nullptr)
	    : AggregateFunction(string(), arguments, return_type, state_size, initialize, update, combine, finalize,
	                        null_handling, simple_update, bind, destructor, statistics, window, serialize,
	                        deserialize) {
	}

	AggregateFunction(const vector<LogicalType> &arguments, const LogicalType &return_type, aggregate_size_t state_size,
	                  aggregate_initialize_t initialize, aggregate_update_t update, aggregate_combine_t combine,
	                  aggregate_finalize_t finalize, aggregate_simple_update_t simple_update = nullptr,
	                  bind_aggregate_function_t bind = nullptr, aggregate_destructor_t destructor = nullptr,
	                  aggregate_statistics_t statistics = nullptr, aggregate_window_t window = nullptr,
	                  aggregate_serialize_t serialize = nullptr, aggregate_deserialize_t deserialize = nullptr)
	    : AggregateFunction(string(), arguments, return_type, state_size, initialize, update, combine, finalize,
	                        FunctionNullHandling::DEFAULT_NULL_HANDLING, simple_update, bind, destructor, statistics,
	                        window, serialize, deserialize) {
	}
	//! The hashed aggregate state sizing function
	aggregate_size_t state_size;
	//! The hashed aggregate state initialization function
	aggregate_initialize_t initialize;
	//! The hashed aggregate update state function
	aggregate_update_t update;
	//! The hashed aggregate combine states function
	aggregate_combine_t combine;
	//! The hashed aggregate finalization function
	aggregate_finalize_t finalize;
	//! The simple aggregate update function (may be null)
	aggregate_simple_update_t simple_update;
	//! The windowed aggregate custom function (may be null)
	aggregate_window_t window;
	//! The windowed aggregate custom initialization function (may be null)
	aggregate_wininit_t window_init = nullptr;

	//! The bind function (may be null)
	bind_aggregate_function_t bind;
	//! The destructor method (may be null)
	aggregate_destructor_t destructor;

	//! The statistics propagation function (may be null)
	aggregate_statistics_t statistics;

	aggregate_serialize_t serialize;
	aggregate_deserialize_t deserialize;
	//! Whether or not the aggregate is order dependent
	AggregateOrderDependent order_dependent;
	//! Additional function info, passed to the bind
	shared_ptr<AggregateFunctionInfo> function_info;

	bool operator==(const AggregateFunction &rhs) const {
		return state_size == rhs.state_size && initialize == rhs.initialize && update == rhs.update &&
		       combine == rhs.combine && finalize == rhs.finalize && window == rhs.window;
	}
	bool operator!=(const AggregateFunction &rhs) const {
		return !(*this == rhs);
	}

public:
	template <class STATE, class RESULT_TYPE, class OP>
	static AggregateFunction NullaryAggregate(LogicalType return_type) {
		return AggregateFunction(
		    {}, return_type, AggregateFunction::StateSize<STATE>, AggregateFunction::StateInitialize<STATE, OP>,
		    AggregateFunction::NullaryScatterUpdate<STATE, OP>, AggregateFunction::StateCombine<STATE, OP>,
		    AggregateFunction::StateFinalize<STATE, RESULT_TYPE, OP>, AggregateFunction::NullaryUpdate<STATE, OP>);
	}

	template <class STATE, class INPUT_TYPE, class RESULT_TYPE, class OP>
	static AggregateFunction
	UnaryAggregate(const LogicalType &input_type, LogicalType return_type,
	               FunctionNullHandling null_handling = FunctionNullHandling::DEFAULT_NULL_HANDLING) {
		return AggregateFunction(
		    {input_type}, return_type, AggregateFunction::StateSize<STATE>,
		    AggregateFunction::StateInitialize<STATE, OP>, AggregateFunction::UnaryScatterUpdate<STATE, INPUT_TYPE, OP>,
		    AggregateFunction::StateCombine<STATE, OP>, AggregateFunction::StateFinalize<STATE, RESULT_TYPE, OP>,
		    null_handling, AggregateFunction::UnaryUpdate<STATE, INPUT_TYPE, OP>);
	}

	template <class STATE, class INPUT_TYPE, class RESULT_TYPE, class OP>
	static AggregateFunction UnaryAggregateDestructor(LogicalType input_type, LogicalType return_type) {
		auto aggregate = UnaryAggregate<STATE, INPUT_TYPE, RESULT_TYPE, OP>(input_type, return_type);
		aggregate.destructor = AggregateFunction::StateDestroy<STATE, OP>;
		return aggregate;
	}

	template <class STATE, class A_TYPE, class B_TYPE, class RESULT_TYPE, class OP>
	static AggregateFunction BinaryAggregate(const LogicalType &a_type, const LogicalType &b_type,
	                                         LogicalType return_type) {
		return AggregateFunction({a_type, b_type}, return_type, AggregateFunction::StateSize<STATE>,
		                         AggregateFunction::StateInitialize<STATE, OP>,
		                         AggregateFunction::BinaryScatterUpdate<STATE, A_TYPE, B_TYPE, OP>,
		                         AggregateFunction::StateCombine<STATE, OP>,
		                         AggregateFunction::StateFinalize<STATE, RESULT_TYPE, OP>,
		                         AggregateFunction::BinaryUpdate<STATE, A_TYPE, B_TYPE, OP>);
	}

public:
	template <class STATE>
	static idx_t StateSize(const AggregateFunction &) {
		return sizeof(STATE);
	}

	template <class STATE, class OP>
	static void StateInitialize(const AggregateFunction &, data_ptr_t state) {
		OP::Initialize(*reinterpret_cast<STATE *>(state));
	}

	template <class STATE, class OP>
	static void NullaryScatterUpdate(Vector inputs[], AggregateInputData &aggr_input_data, idx_t input_count,
	                                 Vector &states, idx_t count) {
		D_ASSERT(input_count == 0);
		AggregateExecutor::NullaryScatter<STATE, OP>(states, aggr_input_data, count);
	}

	template <class STATE, class OP>
	static void NullaryUpdate(Vector inputs[], AggregateInputData &aggr_input_data, idx_t input_count, data_ptr_t state,
	                          idx_t count) {
		D_ASSERT(input_count == 0);
		AggregateExecutor::NullaryUpdate<STATE, OP>(state, aggr_input_data, count);
	}

	template <class STATE, class T, class OP>
	static void UnaryScatterUpdate(Vector inputs[], AggregateInputData &aggr_input_data, idx_t input_count,
	                               Vector &states, idx_t count) {
		D_ASSERT(input_count == 1);
		AggregateExecutor::UnaryScatter<STATE, T, OP>(inputs[0], states, aggr_input_data, count);
	}

	template <class STATE, class INPUT_TYPE, class OP>
	static void UnaryUpdate(Vector inputs[], AggregateInputData &aggr_input_data, idx_t input_count, data_ptr_t state,
	                        idx_t count) {
		D_ASSERT(input_count == 1);
		AggregateExecutor::UnaryUpdate<STATE, INPUT_TYPE, OP>(inputs[0], aggr_input_data, state, count);
	}

	template <class STATE, class INPUT_TYPE, class RESULT_TYPE, class OP>
	static void UnaryWindow(AggregateInputData &aggr_input_data, const WindowPartitionInput &partition,
	                        const_data_ptr_t g_state, data_ptr_t l_state, const SubFrames &subframes, Vector &result,
	                        idx_t rid) {

		D_ASSERT(partition.input_count == 1);
		AggregateExecutor::UnaryWindow<STATE, INPUT_TYPE, RESULT_TYPE, OP>(
		    partition.inputs[0], partition.filter_mask, aggr_input_data, l_state, subframes, result, rid, g_state);
	}

	template <class STATE, class A_TYPE, class B_TYPE, class OP>
	static void BinaryScatterUpdate(Vector inputs[], AggregateInputData &aggr_input_data, idx_t input_count,
	                                Vector &states, idx_t count) {
		D_ASSERT(input_count == 2);
		AggregateExecutor::BinaryScatter<STATE, A_TYPE, B_TYPE, OP>(aggr_input_data, inputs[0], inputs[1], states,
		                                                            count);
	}

	template <class STATE, class A_TYPE, class B_TYPE, class OP>
	static void BinaryUpdate(Vector inputs[], AggregateInputData &aggr_input_data, idx_t input_count, data_ptr_t state,
	                         idx_t count) {
		D_ASSERT(input_count == 2);
		AggregateExecutor::BinaryUpdate<STATE, A_TYPE, B_TYPE, OP>(aggr_input_data, inputs[0], inputs[1], state, count);
	}

	template <class STATE, class OP>
	static void StateCombine(Vector &source, Vector &target, AggregateInputData &aggr_input_data, idx_t count) {
		AggregateExecutor::Combine<STATE, OP>(source, target, aggr_input_data, count);
	}

	template <class STATE, class RESULT_TYPE, class OP>
	static void StateFinalize(Vector &states, AggregateInputData &aggr_input_data, Vector &result, idx_t count,
	                          idx_t offset) {
		AggregateExecutor::Finalize<STATE, RESULT_TYPE, OP>(states, aggr_input_data, result, count, offset);
	}

	template <class STATE, class OP>
	static void StateVoidFinalize(Vector &states, AggregateInputData &aggr_input_data, Vector &result, idx_t count,
	                              idx_t offset) {
		AggregateExecutor::VoidFinalize<STATE, OP>(states, aggr_input_data, result, count, offset);
	}

	template <class STATE, class OP>
	static void StateDestroy(Vector &states, AggregateInputData &aggr_input_data, idx_t count) {
		AggregateExecutor::Destroy<STATE, OP>(states, aggr_input_data, count);
	}
};

} // namespace duckdb


namespace duckdb {

// NOLINTBEGIN

struct UDFWrapper {
public:
	template <typename TR, typename... ARGS>
	inline static scalar_function_t CreateScalarFunction(const string &name, TR (*udf_func)(ARGS...)) {
		const std::size_t num_template_argc = sizeof...(ARGS);
		switch (num_template_argc) {
		case 1:
			return CreateUnaryFunction<TR, ARGS...>(name, udf_func);
		case 2:
			return CreateBinaryFunction<TR, ARGS...>(name, udf_func);
		case 3:
			return CreateTernaryFunction<TR, ARGS...>(name, udf_func);
		default: // LCOV_EXCL_START
			throw std::runtime_error("UDF function only supported until ternary!");
		} // LCOV_EXCL_STOP
	}

	template <typename TR, typename... ARGS>
	inline static scalar_function_t CreateScalarFunction(const string &name, const vector<LogicalType> &args,
	                                                     const LogicalType &ret_type, TR (*udf_func)(ARGS...)) {
		if (!TypesMatch<TR>(ret_type)) { // LCOV_EXCL_START
			throw std::runtime_error("Return type doesn't match with the first template type.");
		} // LCOV_EXCL_STOP

		const std::size_t num_template_types = sizeof...(ARGS);
		if (num_template_types != args.size()) { // LCOV_EXCL_START
			throw std::runtime_error(
			    "The number of templated types should be the same quantity of the LogicalType arguments.");
		} // LCOV_EXCL_STOP

		switch (num_template_types) {
		case 1:
			return CreateUnaryFunction<TR, ARGS...>(name, args, ret_type, udf_func);
		case 2:
			return CreateBinaryFunction<TR, ARGS...>(name, args, ret_type, udf_func);
		case 3:
			return CreateTernaryFunction<TR, ARGS...>(name, args, ret_type, udf_func);
		default: // LCOV_EXCL_START
			throw std::runtime_error("UDF function only supported until ternary!");
		} // LCOV_EXCL_STOP
	}

	template <typename TR, typename... ARGS>
	inline static void RegisterFunction(const string &name, scalar_function_t udf_function, ClientContext &context,
	                                    LogicalType varargs = LogicalType(LogicalTypeId::INVALID)) {
		vector<LogicalType> arguments;
		GetArgumentTypesRecursive<ARGS...>(arguments);

		LogicalType ret_type = GetArgumentType<TR>();

		RegisterFunction(name, arguments, ret_type, std::move(udf_function), context, std::move(varargs));
	}

	static void RegisterFunction(string name, vector<LogicalType> args, LogicalType ret_type,
	                             scalar_function_t udf_function, ClientContext &context,
	                             LogicalType varargs = LogicalType(LogicalTypeId::INVALID));

	//--------------------------------- Aggregate UDFs ------------------------------------//
	template <typename UDF_OP, typename STATE, typename TR, typename TA>
	inline static AggregateFunction CreateAggregateFunction(const string &name) {
		return CreateUnaryAggregateFunction<UDF_OP, STATE, TR, TA>(name);
	}

	template <typename UDF_OP, typename STATE, typename TR, typename TA, typename TB>
	inline static AggregateFunction CreateAggregateFunction(const string &name) {
		return CreateBinaryAggregateFunction<UDF_OP, STATE, TR, TA, TB>(name);
	}

	template <typename UDF_OP, typename STATE, typename TR, typename TA>
	inline static AggregateFunction CreateAggregateFunction(const string &name, const LogicalType &ret_type,
	                                                        const LogicalType &input_type) {
		if (!TypesMatch<TR>(ret_type)) { // LCOV_EXCL_START
			throw std::runtime_error("The return argument don't match!");
		} // LCOV_EXCL_STOP

		if (!TypesMatch<TA>(input_type)) { // LCOV_EXCL_START
			throw std::runtime_error("The input argument don't match!");
		} // LCOV_EXCL_STOP

		return CreateUnaryAggregateFunction<UDF_OP, STATE, TR, TA>(name, ret_type, input_type);
	}

	template <typename UDF_OP, typename STATE, typename TR, typename TA, typename TB>
	inline static AggregateFunction CreateAggregateFunction(const string &name, const LogicalType &ret_type,
	                                                        const LogicalType &input_type_a,
	                                                        const LogicalType &input_type_b) {
		if (!TypesMatch<TR>(ret_type)) { // LCOV_EXCL_START
			throw std::runtime_error("The return argument don't match!");
		}

		if (!TypesMatch<TA>(input_type_a)) {
			throw std::runtime_error("The first input argument don't match!");
		}

		if (!TypesMatch<TB>(input_type_b)) {
			throw std::runtime_error("The second input argument don't match!");
		} // LCOV_EXCL_STOP

		return CreateBinaryAggregateFunction<UDF_OP, STATE, TR, TA, TB>(name, ret_type, input_type_a, input_type_b);
	}

	//! A generic CreateAggregateFunction ---------------------------------------------------------------------------//
	inline static AggregateFunction
	CreateAggregateFunction(const string &name, const vector<LogicalType> &arguments, const LogicalType &return_type,
	                        aggregate_size_t state_size, aggregate_initialize_t initialize, aggregate_update_t update,
	                        aggregate_combine_t combine, aggregate_finalize_t finalize,
	                        aggregate_simple_update_t simple_update = nullptr, bind_aggregate_function_t bind = nullptr,
	                        aggregate_destructor_t destructor = nullptr) {

		AggregateFunction aggr_function(name, arguments, return_type, state_size, initialize, update, combine, finalize,
		                                simple_update, bind, destructor);
		aggr_function.null_handling = FunctionNullHandling::SPECIAL_HANDLING;
		return aggr_function;
	}

	static void RegisterAggrFunction(AggregateFunction aggr_function, ClientContext &context,
	                                 LogicalType varargs = LogicalType(LogicalTypeId::INVALID));

private:
	//-------------------------------- Templated functions --------------------------------//
	struct UnaryUDFExecutor {
		template <class INPUT_TYPE, class RESULT_TYPE>
		static RESULT_TYPE Operation(INPUT_TYPE input, ValidityMask &mask, idx_t idx, void *dataptr) {
			typedef RESULT_TYPE (*unary_function_t)(INPUT_TYPE);
			auto udf = (unary_function_t)dataptr;
			return udf(input);
		}
	};

	template <typename TR, typename TA>
	inline static scalar_function_t CreateUnaryFunction(const string &name, TR (*udf_func)(TA)) {
		scalar_function_t udf_function = [=](DataChunk &input, ExpressionState &state, Vector &result) -> void {
			UnaryExecutor::GenericExecute<TA, TR, UnaryUDFExecutor>(input.data[0], result, input.size(),
			                                                        (void *)udf_func);
		};
		return udf_function;
	}

	template <typename TR, typename TA, typename TB>
	inline static scalar_function_t CreateBinaryFunction(const string &name, TR (*udf_func)(TA, TB)) {
		scalar_function_t udf_function = [=](DataChunk &input, ExpressionState &state, Vector &result) -> void {
			BinaryExecutor::Execute<TA, TB, TR>(input.data[0], input.data[1], result, input.size(), udf_func);
		};
		return udf_function;
	}

	template <typename TR, typename TA, typename TB, typename TC>
	inline static scalar_function_t CreateTernaryFunction(const string &name, TR (*udf_func)(TA, TB, TC)) {
		scalar_function_t udf_function = [=](DataChunk &input, ExpressionState &state, Vector &result) -> void {
			TernaryExecutor::Execute<TA, TB, TC, TR>(input.data[0], input.data[1], input.data[2], result, input.size(),
			                                         udf_func);
		};
		return udf_function;
	}

	template <typename TR, typename... ARGS>
	inline static scalar_function_t CreateUnaryFunction(const string &name,
	                                                    TR (*udf_func)(ARGS...)) { // LCOV_EXCL_START
		throw std::runtime_error("Incorrect number of arguments for unary function");
	} // LCOV_EXCL_STOP

	template <typename TR, typename... ARGS>
	inline static scalar_function_t CreateBinaryFunction(const string &name,
	                                                     TR (*udf_func)(ARGS...)) { // LCOV_EXCL_START
		throw std::runtime_error("Incorrect number of arguments for binary function");
	} // LCOV_EXCL_STOP

	template <typename TR, typename... ARGS>
	inline static scalar_function_t CreateTernaryFunction(const string &name,
	                                                      TR (*udf_func)(ARGS...)) { // LCOV_EXCL_START
		throw std::runtime_error("Incorrect number of arguments for ternary function");
	} // LCOV_EXCL_STOP

	template <typename T>
	inline static LogicalType GetArgumentType() {
		if (std::is_same<T, bool>()) {
			return LogicalType(LogicalTypeId::BOOLEAN);
		} else if (std::is_same<T, int8_t>()) {
			return LogicalType(LogicalTypeId::TINYINT);
		} else if (std::is_same<T, int16_t>()) {
			return LogicalType(LogicalTypeId::SMALLINT);
		} else if (std::is_same<T, int32_t>()) {
			return LogicalType(LogicalTypeId::INTEGER);
		} else if (std::is_same<T, int64_t>()) {
			return LogicalType(LogicalTypeId::BIGINT);
		} else if (std::is_same<T, float>()) {
			return LogicalType(LogicalTypeId::FLOAT);
		} else if (std::is_same<T, double>()) {
			return LogicalType(LogicalTypeId::DOUBLE);
		} else if (std::is_same<T, string_t>()) {
			return LogicalType(LogicalTypeId::VARCHAR);
		} else { // LCOV_EXCL_START
			throw std::runtime_error("Unrecognized type!");
		} // LCOV_EXCL_STOP
	}

	template <typename TA, typename TB, typename... ARGS>
	inline static void GetArgumentTypesRecursive(vector<LogicalType> &arguments) {
		arguments.push_back(GetArgumentType<TA>());
		GetArgumentTypesRecursive<TB, ARGS...>(arguments);
	}

	template <typename TA>
	inline static void GetArgumentTypesRecursive(vector<LogicalType> &arguments) {
		arguments.push_back(GetArgumentType<TA>());
	}

private:
	//-------------------------------- Argumented functions --------------------------------//

	template <typename TR, typename... ARGS>
	inline static scalar_function_t CreateUnaryFunction(const string &name, const vector<LogicalType> &args,
	                                                    const LogicalType &ret_type,
	                                                    TR (*udf_func)(ARGS...)) { // LCOV_EXCL_START
		throw std::runtime_error("Incorrect number of arguments for unary function");
	} // LCOV_EXCL_STOP

	template <typename TR, typename TA>
	inline static scalar_function_t CreateUnaryFunction(const string &name, const vector<LogicalType> &args,
	                                                    const LogicalType &ret_type, TR (*udf_func)(TA)) {
		if (args.size() != 1) { // LCOV_EXCL_START
			throw std::runtime_error("The number of LogicalType arguments (\"args\") should be 1!");
		}
		if (!TypesMatch<TA>(args[0])) {
			throw std::runtime_error("The first arguments don't match!");
		} // LCOV_EXCL_STOP

		scalar_function_t udf_function = [=](DataChunk &input, ExpressionState &state, Vector &result) -> void {
			UnaryExecutor::GenericExecute<TA, TR, UnaryUDFExecutor>(input.data[0], result, input.size(),
			                                                        (void *)udf_func);
		};
		return udf_function;
	}

	template <typename TR, typename... ARGS>
	inline static scalar_function_t CreateBinaryFunction(const string &name, const vector<LogicalType> &args,
	                                                     const LogicalType &ret_type,
	                                                     TR (*udf_func)(ARGS...)) { // LCOV_EXCL_START
		throw std::runtime_error("Incorrect number of arguments for binary function");
	} // LCOV_EXCL_STOP

	template <typename TR, typename TA, typename TB>
	inline static scalar_function_t CreateBinaryFunction(const string &name, const vector<LogicalType> &args,
	                                                     const LogicalType &ret_type, TR (*udf_func)(TA, TB)) {
		if (args.size() != 2) { // LCOV_EXCL_START
			throw std::runtime_error("The number of LogicalType arguments (\"args\") should be 2!");
		}
		if (!TypesMatch<TA>(args[0])) {
			throw std::runtime_error("The first arguments don't match!");
		}
		if (!TypesMatch<TB>(args[1])) {
			throw std::runtime_error("The second arguments don't match!");
		} // LCOV_EXCL_STOP

		scalar_function_t udf_function = [=](DataChunk &input, ExpressionState &state, Vector &result) {
			BinaryExecutor::Execute<TA, TB, TR>(input.data[0], input.data[1], result, input.size(), udf_func);
		};
		return udf_function;
	}

	template <typename TR, typename... ARGS>
	inline static scalar_function_t CreateTernaryFunction(const string &name, const vector<LogicalType> &args,
	                                                      const LogicalType &ret_type,
	                                                      TR (*udf_func)(ARGS...)) { // LCOV_EXCL_START
		throw std::runtime_error("Incorrect number of arguments for ternary function");
	} // LCOV_EXCL_STOP

	template <typename TR, typename TA, typename TB, typename TC>
	inline static scalar_function_t CreateTernaryFunction(const string &name, const vector<LogicalType> &args,
	                                                      const LogicalType &ret_type, TR (*udf_func)(TA, TB, TC)) {
		if (args.size() != 3) { // LCOV_EXCL_START
			throw std::runtime_error("The number of LogicalType arguments (\"args\") should be 3!");
		}
		if (!TypesMatch<TA>(args[0])) {
			throw std::runtime_error("The first arguments don't match!");
		}
		if (!TypesMatch<TB>(args[1])) {
			throw std::runtime_error("The second arguments don't match!");
		}
		if (!TypesMatch<TC>(args[2])) {
			throw std::runtime_error("The second arguments don't match!");
		} // LCOV_EXCL_STOP

		scalar_function_t udf_function = [=](DataChunk &input, ExpressionState &state, Vector &result) -> void {
			TernaryExecutor::Execute<TA, TB, TC, TR>(input.data[0], input.data[1], input.data[2], result, input.size(),
			                                         udf_func);
		};
		return udf_function;
	}

	template <typename T>
	inline static bool TypesMatch(const LogicalType &sql_type) {
		switch (sql_type.id()) {
		case LogicalTypeId::BOOLEAN:
			return std::is_same<T, bool>();
		case LogicalTypeId::TINYINT:
			return std::is_same<T, int8_t>();
		case LogicalTypeId::SMALLINT:
			return std::is_same<T, int16_t>();
		case LogicalTypeId::INTEGER:
			return std::is_same<T, int32_t>();
		case LogicalTypeId::BIGINT:
			return std::is_same<T, int64_t>();
		case LogicalTypeId::DATE:
			return std::is_same<T, date_t>();
		case LogicalTypeId::TIME:
			return std::is_same<T, dtime_t>();
		case LogicalTypeId::TIME_TZ:
			return std::is_same<T, dtime_tz_t>();
		case LogicalTypeId::TIMESTAMP:
		case LogicalTypeId::TIMESTAMP_MS:
		case LogicalTypeId::TIMESTAMP_NS:
		case LogicalTypeId::TIMESTAMP_SEC:
		case LogicalTypeId::TIMESTAMP_TZ:
			return std::is_same<T, timestamp_t>();
		case LogicalTypeId::FLOAT:
			return std::is_same<T, float>();
		case LogicalTypeId::DOUBLE:
			return std::is_same<T, double>();
		case LogicalTypeId::VARCHAR:
		case LogicalTypeId::CHAR:
		case LogicalTypeId::BLOB:
			return std::is_same<T, string_t>();
		default: // LCOV_EXCL_START
			throw std::runtime_error("Type is not supported!");
		} // LCOV_EXCL_STOP
	}

private:
	//-------------------------------- Aggregate functions --------------------------------//
	template <typename UDF_OP, typename STATE, typename TR, typename TA>
	inline static AggregateFunction CreateUnaryAggregateFunction(const string &name) {
		LogicalType return_type = GetArgumentType<TR>();
		LogicalType input_type = GetArgumentType<TA>();
		return CreateUnaryAggregateFunction<UDF_OP, STATE, TR, TA>(name, return_type, input_type);
	}

	template <typename UDF_OP, typename STATE, typename TR, typename TA>
	inline static AggregateFunction CreateUnaryAggregateFunction(const string &name, const LogicalType &ret_type,
	                                                             const LogicalType &input_type) {
		AggregateFunction aggr_function =
		    AggregateFunction::UnaryAggregate<STATE, TR, TA, UDF_OP>(input_type, ret_type);
		aggr_function.name = name;
		return aggr_function;
	}

	template <typename UDF_OP, typename STATE, typename TR, typename TA, typename TB>
	inline static AggregateFunction CreateBinaryAggregateFunction(const string &name) {
		LogicalType return_type = GetArgumentType<TR>();
		LogicalType input_type_a = GetArgumentType<TA>();
		LogicalType input_type_b = GetArgumentType<TB>();
		return CreateBinaryAggregateFunction<UDF_OP, STATE, TR, TA, TB>(name, return_type, input_type_a, input_type_b);
	}

	template <typename UDF_OP, typename STATE, typename TR, typename TA, typename TB>
	inline static AggregateFunction CreateBinaryAggregateFunction(const string &name, const LogicalType &ret_type,
	                                                              const LogicalType &input_type_a,
	                                                              const LogicalType &input_type_b) {
		AggregateFunction aggr_function =
		    AggregateFunction::BinaryAggregate<STATE, TA, TB, TR, UDF_OP>(input_type_a, input_type_b, ret_type);
		aggr_function.name = name;
		return aggr_function;
	}
}; // end UDFWrapper

// NOLINTEND

} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/main/materialized_query_result.hpp
//
//
//===----------------------------------------------------------------------===//



//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/types/column/column_data_collection.hpp
//
//
//===----------------------------------------------------------------------===//




//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/types/column/column_data_collection_iterators.hpp
//
//
//===----------------------------------------------------------------------===//



//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/types/column/column_data_scan_states.hpp
//
//
//===----------------------------------------------------------------------===//








namespace duckdb {

enum class ColumnDataAllocatorType : uint8_t {
	//! Use a buffer manager to allocate large chunks of memory that vectors then use
	BUFFER_MANAGER_ALLOCATOR,
	//! Use an in-memory allocator, allocating data for every chunk
	//! This causes the column data collection to allocate blocks that are not tied to a buffer manager
	IN_MEMORY_ALLOCATOR,
	//! Use a buffer manager to allocate vectors, but use a StringHeap for strings
	HYBRID
};

enum class ColumnDataScanProperties : uint8_t {
	INVALID,
	//! Allow zero copy scans - this introduces a dependency on the resulting vector on the scan state of the column
	//! data collection, which means vectors might not be valid anymore after the next chunk is scanned.
	ALLOW_ZERO_COPY,
	//! Disallow zero-copy scans, always copying data into the target vector
	//! As a result, data scanned will be valid even after the column data collection is destroyed
	DISALLOW_ZERO_COPY
};

struct ChunkManagementState {
	unordered_map<idx_t, BufferHandle> handles;
	ColumnDataScanProperties properties = ColumnDataScanProperties::INVALID;
};

struct ColumnDataAppendState {
	ChunkManagementState current_chunk_state;
	vector<UnifiedVectorFormat> vector_data;
};

struct ColumnDataScanState {
	ChunkManagementState current_chunk_state;
	idx_t segment_index;
	idx_t chunk_index;
	idx_t current_row_index;
	idx_t next_row_index;
	ColumnDataScanProperties properties;
	vector<column_t> column_ids;
};

struct ColumnDataParallelScanState {
	ColumnDataScanState scan_state;
	mutex lock;
};

struct ColumnDataLocalScanState {
	ChunkManagementState current_chunk_state;
	idx_t current_segment_index = DConstants::INVALID_INDEX;
	idx_t current_row_index;
};

class ColumnDataRow {
public:
	ColumnDataRow(DataChunk &chunk, idx_t row_index, idx_t base_index);

	DataChunk &chunk;
	idx_t row_index;
	idx_t base_index;

public:
	Value GetValue(idx_t column_index) const;
	idx_t RowIndex() const;
};

} // namespace duckdb


namespace duckdb {
class ColumnDataCollection;

class ColumnDataChunkIterationHelper {
public:
	DUCKDB_API ColumnDataChunkIterationHelper(const ColumnDataCollection &collection, vector<column_t> column_ids);

private:
	const ColumnDataCollection &collection;
	vector<column_t> column_ids;

private:
	class ColumnDataChunkIterator;

	class ColumnDataChunkIterator {
	public:
		DUCKDB_API explicit ColumnDataChunkIterator(const ColumnDataCollection *collection_p,
		                                            vector<column_t> column_ids);

		const ColumnDataCollection *collection;
		ColumnDataScanState scan_state;
		shared_ptr<DataChunk> scan_chunk;
		idx_t row_index;

	public:
		DUCKDB_API void Next();

		DUCKDB_API ColumnDataChunkIterator &operator++();
		DUCKDB_API bool operator!=(const ColumnDataChunkIterator &other) const;
		DUCKDB_API DataChunk &operator*() const;
	};

public:
	ColumnDataChunkIterator begin() { // NOLINT: match stl API
		return ColumnDataChunkIterator(&collection, column_ids);
	}
	ColumnDataChunkIterator end() { // NOLINT: match stl API
		return ColumnDataChunkIterator(nullptr, vector<column_t>());
	}
};

class ColumnDataRowIterationHelper {
public:
	DUCKDB_API explicit ColumnDataRowIterationHelper(const ColumnDataCollection &collection);

private:
	const ColumnDataCollection &collection;

private:
	class ColumnDataRowIterator;

	class ColumnDataRowIterator {
	public:
		DUCKDB_API explicit ColumnDataRowIterator(const ColumnDataCollection *collection_p);

		const ColumnDataCollection *collection;
		ColumnDataScanState scan_state;
		shared_ptr<DataChunk> scan_chunk;
		ColumnDataRow current_row;

	public:
		void Next();

		DUCKDB_API ColumnDataRowIterator &operator++();
		DUCKDB_API bool operator!=(const ColumnDataRowIterator &other) const;
		DUCKDB_API const ColumnDataRow &operator*() const;
	};

public:
	DUCKDB_API ColumnDataRowIterator begin(); // NOLINT: match stl API
	DUCKDB_API ColumnDataRowIterator end();   // NOLINT: match stl API
};

} // namespace duckdb


namespace duckdb {
class BufferManager;
class BlockHandle;
class ClientContext;
struct ColumnDataCopyFunction;
class ColumnDataAllocator;
class ColumnDataCollection;
class ColumnDataCollectionSegment;
class ColumnDataRowCollection;

//! The ColumnDataCollection represents a set of (buffer-managed) data stored in columnar format
//! It is efficient to read and scan
class ColumnDataCollection {
public:
	//! Constructs an in-memory column data collection from an allocator
	DUCKDB_API ColumnDataCollection(Allocator &allocator, vector<LogicalType> types);
	//! Constructs an empty (but valid) in-memory column data collection from an allocator
	DUCKDB_API explicit ColumnDataCollection(Allocator &allocator);
	//! Constructs a buffer-managed column data collection
	DUCKDB_API ColumnDataCollection(BufferManager &buffer_manager, vector<LogicalType> types);
	//! Constructs either an in-memory or a buffer-managed column data collection
	DUCKDB_API ColumnDataCollection(ClientContext &context, vector<LogicalType> types,
	                                ColumnDataAllocatorType type = ColumnDataAllocatorType::BUFFER_MANAGER_ALLOCATOR);
	//! Creates a column data collection that inherits the blocks to write to. This allows blocks to be shared
	//! between multiple column data collections and prevents wasting space.
	//! Note that after one CDC inherits blocks from another, the other
	//! cannot be written to anymore (i.e. we take ownership of the half-written blocks).
	DUCKDB_API ColumnDataCollection(ColumnDataCollection &parent);
	DUCKDB_API ColumnDataCollection(shared_ptr<ColumnDataAllocator> allocator, vector<LogicalType> types);
	DUCKDB_API ~ColumnDataCollection();

public:
	//! The types of columns in the ColumnDataCollection
	vector<LogicalType> &Types() {
		return types;
	}
	const vector<LogicalType> &Types() const {
		return types;
	}

	//! The amount of rows in the ColumnDataCollection
	const idx_t &Count() const {
		return count;
	}

	//! The amount of columns in the ColumnDataCollection
	idx_t ColumnCount() const {
		return types.size();
	}

	//! The size (in bytes) of this ColumnDataCollection
	idx_t SizeInBytes() const;
	//! The allocation size (in bytes) of this ColumnDataCollection - this property is cached
	idx_t AllocationSize() const;

	//! Get the allocator
	DUCKDB_API Allocator &GetAllocator() const;

	//! Initializes an Append state - useful for optimizing many appends made to the same column data collection
	DUCKDB_API void InitializeAppend(ColumnDataAppendState &state);
	//! Append a DataChunk to this ColumnDataCollection using the specified append state
	DUCKDB_API void Append(ColumnDataAppendState &state, DataChunk &new_chunk);

	//! Initializes a chunk with the correct types that can be used to call Scan
	DUCKDB_API void InitializeScanChunk(DataChunk &chunk) const;
	//! Initializes a chunk with the correct types for a given scan state
	DUCKDB_API void InitializeScanChunk(ColumnDataScanState &state, DataChunk &chunk) const;
	//! Initializes a Scan state for scanning all columns
	DUCKDB_API void
	InitializeScan(ColumnDataScanState &state,
	               ColumnDataScanProperties properties = ColumnDataScanProperties::ALLOW_ZERO_COPY) const;
	//! Initializes a Scan state for scanning a subset of the columns
	DUCKDB_API void
	InitializeScan(ColumnDataScanState &state, vector<column_t> column_ids,
	               ColumnDataScanProperties properties = ColumnDataScanProperties::ALLOW_ZERO_COPY) const;
	//! Initialize a parallel scan over the column data collection over all columns
	DUCKDB_API void
	InitializeScan(ColumnDataParallelScanState &state,
	               ColumnDataScanProperties properties = ColumnDataScanProperties::ALLOW_ZERO_COPY) const;
	//! Initialize a parallel scan over the column data collection over a subset of the columns
	DUCKDB_API void
	InitializeScan(ColumnDataParallelScanState &state, vector<column_t> column_ids,
	               ColumnDataScanProperties properties = ColumnDataScanProperties::ALLOW_ZERO_COPY) const;
	//! Scans a DataChunk from the ColumnDataCollection
	DUCKDB_API bool Scan(ColumnDataScanState &state, DataChunk &result) const;
	//! Scans a DataChunk from the ColumnDataCollection
	DUCKDB_API bool Scan(ColumnDataParallelScanState &state, ColumnDataLocalScanState &lstate, DataChunk &result) const;

	//! Append a DataChunk directly to this ColumnDataCollection - calls InitializeAppend and Append internally
	DUCKDB_API void Append(DataChunk &new_chunk);

	//! Appends the other ColumnDataCollection to this, destroying the other data collection
	DUCKDB_API void Combine(ColumnDataCollection &other);

	DUCKDB_API void Verify();

	DUCKDB_API string ToString() const;
	DUCKDB_API void Print() const;

	DUCKDB_API void Reset();

	//! Returns the number of data chunks present in the ColumnDataCollection
	DUCKDB_API idx_t ChunkCount() const;
	//! Fetch an individual chunk from the ColumnDataCollection
	DUCKDB_API void FetchChunk(idx_t chunk_idx, DataChunk &result) const;

	//! Constructs a class that can be iterated over to fetch individual chunks
	//! Iterating over this is syntactic sugar over just calling Scan
	DUCKDB_API ColumnDataChunkIterationHelper Chunks() const;
	//! Constructs a class that can be iterated over to fetch individual chunks
	//! Only the column indexes specified in the column_ids list are scanned
	DUCKDB_API ColumnDataChunkIterationHelper Chunks(vector<column_t> column_ids) const;

	//! Constructs a class that can be iterated over to fetch individual rows
	//! Note that row iteration is slow, and the `.Chunks()` method should be used instead
	DUCKDB_API ColumnDataRowIterationHelper Rows() const;

	//! Returns a materialized set of all of the rows in the column data collection
	//! Note that usage of this is slow - avoid using this unless the amount of rows is small, or if you do not care
	//! about performance
	DUCKDB_API ColumnDataRowCollection GetRows() const;

	//! Compare two column data collections to another. If they are equal according to result equality rules,
	//! return true. That means null values are equal, and approx equality is used for floating point values.
	//! If they are not equal, return false and fill in the error message.
	static bool ResultEquals(const ColumnDataCollection &left, const ColumnDataCollection &right, string &error_message,
	                         bool ordered = false);

	//! Obtains the next scan index to scan from
	bool NextScanIndex(ColumnDataScanState &state, idx_t &chunk_index, idx_t &segment_index, idx_t &row_index) const;
	//! Scans at the indices (obtained from NextScanIndex)
	void ScanAtIndex(ColumnDataParallelScanState &state, ColumnDataLocalScanState &lstate, DataChunk &result,
	                 idx_t chunk_index, idx_t segment_index, idx_t row_index) const;

	//! Initialize the column data collection
	void Initialize(vector<LogicalType> types);

	//! Get references to the string heaps in this ColumnDataCollection
	vector<shared_ptr<StringHeap>> GetHeapReferences();
	//! Get the allocator type of this ColumnDataCollection
	ColumnDataAllocatorType GetAllocatorType() const;

	//! Get a vector of the segments in this ColumnDataCollection
	const vector<unique_ptr<ColumnDataCollectionSegment>> &GetSegments() const;

	void Serialize(Serializer &serializer) const;
	static unique_ptr<ColumnDataCollection> Deserialize(Deserializer &deserializer);

private:
	//! Creates a new segment within the ColumnDataCollection
	void CreateSegment();

	static ColumnDataCopyFunction GetCopyFunction(const LogicalType &type);

private:
	//! The Column Data Allocator
	buffer_ptr<ColumnDataAllocator> allocator;
	//! The types of the stored entries
	vector<LogicalType> types;
	//! The number of entries stored in the column data collection
	idx_t count;
	//! The data segments of the column data collection
	vector<unique_ptr<ColumnDataCollectionSegment>> segments;
	//! The set of copy functions
	vector<ColumnDataCopyFunction> copy_functions;
	//! When the column data collection is marked as finished - new tuples can no longer be appended to it
	bool finished_append;
};

//! The ColumnDataRowCollection represents a set of materialized rows, as obtained from the ColumnDataCollection
class ColumnDataRowCollection {
public:
	DUCKDB_API explicit ColumnDataRowCollection(const ColumnDataCollection &collection);

public:
	DUCKDB_API Value GetValue(idx_t column, idx_t index) const;

public:
	// container API
	bool empty() const { // NOLINT: match stl API
		return rows.empty();
	}
	idx_t size() const { // NOLINT: match stl API
		return rows.size();
	}

	DUCKDB_API ColumnDataRow &operator[](idx_t i);
	DUCKDB_API const ColumnDataRow &operator[](idx_t i) const;

	vector<ColumnDataRow>::iterator begin() { // NOLINT: match stl API
		return rows.begin();
	}
	vector<ColumnDataRow>::iterator end() { // NOLINT: match stl API
		return rows.end();
	}
	vector<ColumnDataRow>::const_iterator cbegin() const { // NOLINT: match stl API
		return rows.cbegin();
	}
	vector<ColumnDataRow>::const_iterator cend() const { // NOLINT: match stl API
		return rows.cend();
	}
	vector<ColumnDataRow>::const_iterator begin() const { // NOLINT: match stl API
		return rows.begin();
	}
	vector<ColumnDataRow>::const_iterator end() const { // NOLINT: match stl API
		return rows.end();
	}

private:
	vector<ColumnDataRow> rows;
	vector<unique_ptr<DataChunk>> chunks;
	ColumnDataScanState scan_state;
};

} // namespace duckdb


//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/main/query_result.hpp
//
//
//===----------------------------------------------------------------------===//



//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/enums/statement_type.hpp
//
//
//===----------------------------------------------------------------------===//







namespace duckdb {

//===--------------------------------------------------------------------===//
// Statement Types
//===--------------------------------------------------------------------===//
enum class StatementType : uint8_t {
	INVALID_STATEMENT,      // invalid statement type
	SELECT_STATEMENT,       // select statement type
	INSERT_STATEMENT,       // insert statement type
	UPDATE_STATEMENT,       // update statement type
	CREATE_STATEMENT,       // create statement type
	DELETE_STATEMENT,       // delete statement type
	PREPARE_STATEMENT,      // prepare statement type
	EXECUTE_STATEMENT,      // execute statement type
	ALTER_STATEMENT,        // alter statement type
	TRANSACTION_STATEMENT,  // transaction statement type,
	COPY_STATEMENT,         // copy type
	ANALYZE_STATEMENT,      // analyze type
	VARIABLE_SET_STATEMENT, // variable set statement type
	CREATE_FUNC_STATEMENT,  // create func statement type
	EXPLAIN_STATEMENT,      // explain statement type
	DROP_STATEMENT,         // DROP statement type
	EXPORT_STATEMENT,       // EXPORT statement type
	PRAGMA_STATEMENT,       // PRAGMA statement type
	VACUUM_STATEMENT,       // VACUUM statement type
	CALL_STATEMENT,         // CALL statement type
	SET_STATEMENT,          // SET statement type
	LOAD_STATEMENT,         // LOAD statement type
	RELATION_STATEMENT,
	EXTENSION_STATEMENT,
	LOGICAL_PLAN_STATEMENT,
	ATTACH_STATEMENT,
	DETACH_STATEMENT,
	MULTI_STATEMENT,
	COPY_DATABASE_STATEMENT,
	UPDATE_EXTENSIONS_STATEMENT,
};

DUCKDB_API string StatementTypeToString(StatementType type);

enum class StatementReturnType : uint8_t {
	QUERY_RESULT, // the statement returns a query result (e.g. for display to the user)
	CHANGED_ROWS, // the statement returns a single row containing the number of changed rows (e.g. an insert stmt)
	NOTHING       // the statement returns nothing
};

string StatementReturnTypeToString(StatementReturnType type);

class Catalog;
class ClientContext;

//! A struct containing various properties of a SQL statement
struct StatementProperties {
	StatementProperties()
	    : requires_valid_transaction(true), allow_stream_result(false), bound_all_parameters(true),
	      return_type(StatementReturnType::QUERY_RESULT), parameter_count(0), always_require_rebind(false) {
	}

	struct CatalogIdentity {
		idx_t catalog_oid;
		optional_idx catalog_version;

		bool operator==(const CatalogIdentity &rhs) const {
			return catalog_oid == rhs.catalog_oid && catalog_version == rhs.catalog_version;
		}

		bool operator!=(const CatalogIdentity &rhs) const {
			return !operator==(rhs);
		}
	};

	//! The set of databases this statement will read from
	unordered_map<string, CatalogIdentity> read_databases;
	//! The set of databases this statement will modify
	unordered_map<string, CatalogIdentity> modified_databases;
	//! Whether or not the statement requires a valid transaction. Almost all statements require this, with the
	//! exception of ROLLBACK
	bool requires_valid_transaction;
	//! Whether or not the result can be streamed to the client
	bool allow_stream_result;
	//! Whether or not all parameters have successfully had their types determined
	bool bound_all_parameters;
	//! What type of data the statement returns
	StatementReturnType return_type;
	//! The number of prepared statement parameters
	idx_t parameter_count;
	//! Whether or not the statement ALWAYS requires a rebind
	bool always_require_rebind;

	bool IsReadOnly() {
		return modified_databases.empty();
	}

	void RegisterDBRead(Catalog &catalog, ClientContext &context);

	void RegisterDBModify(Catalog &catalog, ClientContext &context);
};

} // namespace duckdb




//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/main/client_properties.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

enum class ArrowOffsetSize : uint8_t { REGULAR, LARGE };

//! A set of properties from the client context that can be used to interpret the query result
struct ClientProperties {
	ClientProperties(string time_zone_p, ArrowOffsetSize arrow_offset_size_p, bool arrow_use_list_view_p,
	                 bool produce_arrow_string_view_p, bool lossless_conversion)
	    : time_zone(std::move(time_zone_p)), arrow_offset_size(arrow_offset_size_p),
	      arrow_use_list_view(arrow_use_list_view_p), arrow_lossless_conversion(lossless_conversion) {
	}
	ClientProperties() {};
	string time_zone = "UTC";
	ArrowOffsetSize arrow_offset_size = ArrowOffsetSize::REGULAR;
	bool arrow_use_list_view = false;
	bool produce_arrow_string_view = false;
	bool arrow_lossless_conversion = false;
};
} // namespace duckdb


namespace duckdb {
struct BoxRendererConfig;

enum class QueryResultType : uint8_t { MATERIALIZED_RESULT, STREAM_RESULT, PENDING_RESULT, ARROW_RESULT };

class BaseQueryResult {
public:
	//! Creates a successful query result with the specified names and types
	DUCKDB_API BaseQueryResult(QueryResultType type, StatementType statement_type, StatementProperties properties,
	                           vector<LogicalType> types, vector<string> names);
	//! Creates an unsuccessful query result with error condition
	DUCKDB_API BaseQueryResult(QueryResultType type, ErrorData error);
	DUCKDB_API virtual ~BaseQueryResult();

	//! The type of the result (MATERIALIZED or STREAMING)
	QueryResultType type;
	//! The type of the statement that created this result
	StatementType statement_type;
	//! Properties of the statement
	StatementProperties properties;
	//! The SQL types of the result
	vector<LogicalType> types;
	//! The names of the result
	vector<string> names;

public:
	[[noreturn]] DUCKDB_API void ThrowError(const string &prepended_message = "") const;
	DUCKDB_API void SetError(ErrorData error);
	DUCKDB_API bool HasError() const;
	DUCKDB_API const ExceptionType &GetErrorType() const;
	DUCKDB_API const std::string &GetError();
	DUCKDB_API ErrorData &GetErrorObject();
	DUCKDB_API idx_t ColumnCount();

protected:
	//! Whether or not execution was successful
	bool success;
	//! The error (in case execution was not successful)
	ErrorData error;
};

//! The QueryResult object holds the result of a query. It can either be a MaterializedQueryResult, in which case the
//! result contains the entire result set, or a StreamQueryResult in which case the Fetch method can be called to
//! incrementally fetch data from the database.
class QueryResult : public BaseQueryResult {
public:
	//! Creates a successful query result with the specified names and types
	DUCKDB_API QueryResult(QueryResultType type, StatementType statement_type, StatementProperties properties,
	                       vector<LogicalType> types, vector<string> names, ClientProperties client_properties);
	//! Creates an unsuccessful query result with error condition
	DUCKDB_API QueryResult(QueryResultType type, ErrorData error);
	DUCKDB_API ~QueryResult() override;

	//! Properties from the client context
	ClientProperties client_properties;
	//! The next result (if any)
	unique_ptr<QueryResult> next;

public:
	template <class TARGET>
	TARGET &Cast() {
		if (type != TARGET::TYPE) {
			throw InternalException("Failed to cast query result to type - query result type mismatch");
		}
		return reinterpret_cast<TARGET &>(*this);
	}

	template <class TARGET>
	const TARGET &Cast() const {
		if (type != TARGET::TYPE) {
			throw InternalException("Failed to cast query result to type - query result type mismatch");
		}
		return reinterpret_cast<const TARGET &>(*this);
	}

public:
	//! Deduplicate column names for interop with external libraries
	static void DeduplicateColumns(vector<string> &names);

public:
	//! Returns the name of the column for the given index
	DUCKDB_API const string &ColumnName(idx_t index) const;
	//! Fetches a DataChunk of normalized (flat) vectors from the query result.
	//! Returns nullptr if there are no more results to fetch.
	DUCKDB_API virtual unique_ptr<DataChunk> Fetch();
	//! Fetches a DataChunk from the query result. The vectors are not normalized and hence any vector types can be
	//! returned.
	DUCKDB_API virtual unique_ptr<DataChunk> FetchRaw() = 0;
	//! Converts the QueryResult to a string
	DUCKDB_API virtual string ToString() = 0;
	//! Converts the QueryResult to a box-rendered string
	DUCKDB_API virtual string ToBox(ClientContext &context, const BoxRendererConfig &config);
	//! Prints the QueryResult to the console
	DUCKDB_API void Print();
	//! Returns true if the two results are identical; false otherwise. Note that this method is destructive; it calls
	//! Fetch() until both results are exhausted. The data in the results will be lost.
	DUCKDB_API bool Equals(QueryResult &other);

	bool TryFetch(unique_ptr<DataChunk> &result, ErrorData &error) {
		try {
			result = Fetch();
			return success;
		} catch (std::exception &ex) {
			error = ErrorData(ex);
			return false;
		} catch (...) {
			error = ErrorData("Unknown error in Fetch");
			return false;
		}
	}

private:
	class QueryResultIterator;
	class QueryResultRow {
	public:
		explicit QueryResultRow(QueryResultIterator &iterator_p, idx_t row_idx) : iterator(iterator_p), row(0) {
		}

		QueryResultIterator &iterator;
		idx_t row;

		template <class T>
		T GetValue(idx_t col_idx) const {
			return iterator.chunk->GetValue(col_idx, row).GetValue<T>();
		}
	};
	//! The row-based query result iterator. Invoking the
	class QueryResultIterator {
	public:
		explicit QueryResultIterator(optional_ptr<QueryResult> result_p)
		    : current_row(*this, 0), result(result_p), base_row(0) {
			if (result) {
				chunk = shared_ptr<DataChunk>(result->Fetch().release());
				if (!chunk) {
					result = nullptr;
				}
			}
		}

		QueryResultRow current_row;
		shared_ptr<DataChunk> chunk;
		optional_ptr<QueryResult> result;
		idx_t base_row;

	public:
		void Next() {
			if (!chunk) {
				return;
			}
			current_row.row++;
			if (current_row.row >= chunk->size()) {
				base_row += chunk->size();
				chunk = shared_ptr<DataChunk>(result->Fetch().release());
				current_row.row = 0;
				if (!chunk || chunk->size() == 0) {
					// exhausted all rows
					base_row = 0;
					result = nullptr;
					chunk.reset();
				}
			}
		}

		QueryResultIterator &operator++() {
			Next();
			return *this;
		}
		bool operator!=(const QueryResultIterator &other) const {
			return result != other.result || base_row != other.base_row || current_row.row != other.current_row.row;
		}
		const QueryResultRow &operator*() const {
			return current_row;
		}
	};

public:
	QueryResultIterator begin() { // NOLINT: match stl API
		return QueryResultIterator(this);
	}
	QueryResultIterator end() { // NOLINT: match stl API
		return QueryResultIterator(nullptr);
	}

protected:
	DUCKDB_API string HeaderToString();

private:
	QueryResult(const QueryResult &) = delete;
};

} // namespace duckdb


namespace duckdb {

class ClientContext;

class MaterializedQueryResult : public QueryResult {
public:
	static constexpr const QueryResultType TYPE = QueryResultType::MATERIALIZED_RESULT;

public:
	friend class ClientContext;
	//! Creates a successful query result with the specified names and types
	DUCKDB_API MaterializedQueryResult(StatementType statement_type, StatementProperties properties,
	                                   vector<string> names, unique_ptr<ColumnDataCollection> collection,
	                                   ClientProperties client_properties);
	//! Creates an unsuccessful query result with error condition
	DUCKDB_API explicit MaterializedQueryResult(ErrorData error);

public:
	//! Fetches a DataChunk from the query result.
	//! This will consume the result (i.e. the result can only be scanned once with this function)
	DUCKDB_API unique_ptr<DataChunk> Fetch() override;
	DUCKDB_API unique_ptr<DataChunk> FetchRaw() override;
	//! Converts the QueryResult to a string
	DUCKDB_API string ToString() override;
	DUCKDB_API string ToBox(ClientContext &context, const BoxRendererConfig &config) override;

	//! Gets the (index) value of the (column index) column.
	//! Note: this is very slow. Scanning over the underlying collection is much faster.
	DUCKDB_API Value GetValue(idx_t column, idx_t index);

	template <class T>
	T GetValue(idx_t column, idx_t index) {
		auto value = GetValue(column, index);
		return (T)value.GetValue<int64_t>();
	}

	DUCKDB_API idx_t RowCount() const;

	//! Returns a reference to the underlying column data collection
	ColumnDataCollection &Collection();

	//! Takes ownership of the collection, 'collection' is null after this operation
	unique_ptr<ColumnDataCollection> TakeCollection();

private:
	unique_ptr<ColumnDataCollection> collection;
	//! Row collection, only created if GetValue is called
	unique_ptr<ColumnDataRowCollection> row_collection;
	//! Scan state for Fetch calls
	ColumnDataScanState scan_state;
	bool scan_initialized;
};

} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/main/pending_query_result.hpp
//
//
//===----------------------------------------------------------------------===//




//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/enums/pending_execution_result.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

enum class PendingExecutionResult : uint8_t {
	RESULT_READY,
	RESULT_NOT_READY,
	EXECUTION_ERROR,
	BLOCKED,
	NO_TASKS_AVAILABLE,
	EXECUTION_FINISHED
};

} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/executor.hpp
//
//
//===----------------------------------------------------------------------===//









//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/task_error_manager.hpp
//
//
//===----------------------------------------------------------------------===//







namespace duckdb {

class TaskErrorManager {
public:
	void PushError(ErrorData error) {
		lock_guard<mutex> elock(error_lock);
		this->exceptions.push_back(std::move(error));
	}

	ErrorData GetError() {
		lock_guard<mutex> elock(error_lock);
		D_ASSERT(!exceptions.empty());

		// FIXME: Should we try to get the biggest priority error?
		// In case the first exception is a StandardException but a regular Exception or a FatalException occurred
		// Maybe we should throw the more critical exception instead, as that changes behavior.
		auto &entry = exceptions[0];
		return entry;
	}

	bool HasError() {
		lock_guard<mutex> elock(error_lock);
		return !exceptions.empty();
	}

	void ThrowException() {
		lock_guard<mutex> elock(error_lock);
		D_ASSERT(!exceptions.empty());
		auto &entry = exceptions[0];
		entry.Throw();
	}

	void Reset() {
		lock_guard<mutex> elock(error_lock);
		exceptions.clear();
	}

private:
	mutex error_lock;
	//! Exceptions that occurred during the execution of the current query
	vector<ErrorData> exceptions;
};
} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/parallel/pipeline.hpp
//
//
//===----------------------------------------------------------------------===//






//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/physical_operator.hpp
//
//
//===----------------------------------------------------------------------===//





//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/enums/operator_result_type.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

//! The OperatorResultType is used to indicate how data should flow around a regular (i.e. non-sink and non-source)
//! physical operator
//! There are four possible results:
//! NEED_MORE_INPUT means the operator is done with the current input and can consume more input if available
//! If there is more input the operator will be called with more input, otherwise the operator will not be called again.
//! HAVE_MORE_OUTPUT means the operator is not finished yet with the current input.
//! The operator will be called again with the same input.
//! FINISHED means the operator has finished the entire pipeline and no more processing is necessary.
//! The operator will not be called again, and neither will any other operators in this pipeline.
//! BLOCKED means the operator does not want to be called right now. e.g. because its currently doing async I/O. The
//! operator has set the interrupt state and the caller is expected to handle it. Note that intermediate operators
//! should currently not emit this state.
enum class OperatorResultType : uint8_t { NEED_MORE_INPUT, HAVE_MORE_OUTPUT, FINISHED, BLOCKED };

//! OperatorFinalizeResultType is used to indicate whether operators have finished flushing their cached results.
//! FINISHED means the operator has flushed all cached data.
//! HAVE_MORE_OUTPUT means the operator contains more results.
enum class OperatorFinalizeResultType : uint8_t { HAVE_MORE_OUTPUT, FINISHED };

//! SourceResultType is used to indicate the result of data being pulled out of a source.
//! There are three possible results:
//! HAVE_MORE_OUTPUT means the source has more output, this flag should only be set when data is returned, empty results
//! should only occur for the FINISHED and BLOCKED flags
//! FINISHED means the source is exhausted
//! BLOCKED means the source is currently blocked, e.g. by some async I/O
enum class SourceResultType : uint8_t { HAVE_MORE_OUTPUT, FINISHED, BLOCKED };

//! The SinkResultType is used to indicate the result of data flowing into a sink
//! There are three possible results:
//! NEED_MORE_INPUT means the sink needs more input
//! FINISHED means the sink is finished executing, and more input will not change the result any further
//! BLOCKED means the sink is currently blocked, e.g. by some async I/O.
enum class SinkResultType : uint8_t { NEED_MORE_INPUT, FINISHED, BLOCKED };

// todo comment
enum class SinkCombineResultType : uint8_t { FINISHED, BLOCKED };

//! The SinkFinalizeType is used to indicate the result of a Finalize call on a sink
//! There are two possible results:
//! READY means the sink is ready for further processing
//! NO_OUTPUT_POSSIBLE means the sink will never provide output, and any pipelines involving the sink can be skipped
//! BLOCKED means the finalize call to the sink is currently blocked, e.g. by some async I/O.
enum class SinkFinalizeType : uint8_t { READY, NO_OUTPUT_POSSIBLE, BLOCKED };

//! The SinkNextBatchType is used to indicate the result of a NextBatch call on a sink
//! There are two possible results:
//! READY means the sink is ready for further processing
//! BLOCKED means the NextBatch call to the sink is currently blocked, e.g. by some async I/O.
enum class SinkNextBatchType : uint8_t { READY, BLOCKED };

} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/enums/physical_operator_type.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

//===--------------------------------------------------------------------===//
// Physical Operator Types
//===--------------------------------------------------------------------===//
enum class PhysicalOperatorType : uint8_t {
	INVALID,
	ORDER_BY,
	LIMIT,
	STREAMING_LIMIT,
	LIMIT_PERCENT,
	TOP_N,
	WINDOW,
	UNNEST,
	UNGROUPED_AGGREGATE,
	HASH_GROUP_BY,
	PERFECT_HASH_GROUP_BY,
	FILTER,
	PROJECTION,
	COPY_TO_FILE,
	BATCH_COPY_TO_FILE,
	RESERVOIR_SAMPLE,
	STREAMING_SAMPLE,
	STREAMING_WINDOW,
	PIVOT,
	COPY_DATABASE,

	// -----------------------------
	// Scans
	// -----------------------------
	TABLE_SCAN,
	DUMMY_SCAN,
	COLUMN_DATA_SCAN,
	CHUNK_SCAN,
	RECURSIVE_CTE_SCAN,
	CTE_SCAN,
	DELIM_SCAN,
	EXPRESSION_SCAN,
	POSITIONAL_SCAN,
	// -----------------------------
	// Joins
	// -----------------------------
	BLOCKWISE_NL_JOIN,
	NESTED_LOOP_JOIN,
	HASH_JOIN,
	CROSS_PRODUCT,
	PIECEWISE_MERGE_JOIN,
	IE_JOIN,
	LEFT_DELIM_JOIN,
	RIGHT_DELIM_JOIN,
	POSITIONAL_JOIN,
	ASOF_JOIN,
	// -----------------------------
	// SetOps
	// -----------------------------
	UNION,
	RECURSIVE_CTE,
	CTE,

	// -----------------------------
	// Updates
	// -----------------------------
	INSERT,
	BATCH_INSERT,
	DELETE_OPERATOR,
	UPDATE,

	// -----------------------------
	// Schema
	// -----------------------------
	CREATE_TABLE,
	CREATE_TABLE_AS,
	BATCH_CREATE_TABLE_AS,
	CREATE_INDEX,
	ALTER,
	CREATE_SEQUENCE,
	CREATE_VIEW,
	CREATE_SCHEMA,
	CREATE_MACRO,
	DROP,
	PRAGMA,
	TRANSACTION,
	CREATE_TYPE,
	ATTACH,
	DETACH,

	// -----------------------------
	// Helpers
	// -----------------------------
	EXPLAIN,
	EXPLAIN_ANALYZE,
	EMPTY_RESULT,
	EXECUTE,
	PREPARE,
	VACUUM,
	EXPORT,
	SET,
	SET_VARIABLE,
	LOAD,
	INOUT_FUNCTION,
	RESULT_COLLECTOR,
	RESET,
	EXTENSION,
	VERIFY_VECTOR,
	UPDATE_EXTENSIONS,

	// -----------------------------
	// Secret
	// -----------------------------
	CREATE_SECRET,
};

string PhysicalOperatorToString(PhysicalOperatorType type);

} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/enums/explain_format.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

enum class ExplainFormat : uint8_t { DEFAULT, TEXT, JSON, HTML, GRAPHVIZ };

} // namespace duckdb


//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/execution_context.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {
class ClientContext;
class ThreadContext;
class Pipeline;

class ExecutionContext {
public:
	ExecutionContext(ClientContext &client_p, ThreadContext &thread_p, optional_ptr<Pipeline> pipeline_p)
	    : client(client_p), thread(thread_p), pipeline(pipeline_p) {
	}

	//! The client-global context; caution needs to be taken when used in parallel situations
	ClientContext &client;
	//! The thread-local context for this execution
	ThreadContext &thread;
	//! Reference to the pipeline for this execution, can be used for example by operators determine caching strategy
	optional_ptr<Pipeline> pipeline;
};

} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/optimizer/join_order/join_node.hpp
//
//
//===----------------------------------------------------------------------===//


//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/optimizer/join_order/join_relation.hpp
//
//
//===----------------------------------------------------------------------===//







namespace duckdb {

//! Set of relations, used in the join graph.
struct JoinRelationSet {
	JoinRelationSet(unsafe_unique_array<idx_t> relations, idx_t count) : relations(std::move(relations)), count(count) {
	}

	string ToString() const;

	unsafe_unique_array<idx_t> relations;
	idx_t count;

	static bool IsSubset(JoinRelationSet &super, JoinRelationSet &sub);
};

//! The JoinRelationTree is a structure holding all the created JoinRelationSet objects and allowing fast lookup on to
//! them
class JoinRelationSetManager {
public:
	//! Contains a node with a JoinRelationSet and child relations
	// FIXME: this structure is inefficient, could use a bitmap for lookup instead (todo: profile)
	struct JoinRelationTreeNode {
		unique_ptr<JoinRelationSet> relation;
		unordered_map<idx_t, unique_ptr<JoinRelationTreeNode>> children;
	};

public:
	//! Create or get a JoinRelationSet from a single node with the given index
	JoinRelationSet &GetJoinRelation(idx_t index);
	//! Create or get a JoinRelationSet from a set of relation bindings
	JoinRelationSet &GetJoinRelation(const unordered_set<idx_t> &bindings);
	//! Create or get a JoinRelationSet from a (sorted, duplicate-free!) list of relations
	JoinRelationSet &GetJoinRelation(unsafe_unique_array<idx_t> relations, idx_t count);
	//! Union two sets of relations together and create a new relation set
	JoinRelationSet &Union(JoinRelationSet &left, JoinRelationSet &right);
	// //! Create the set difference of left \ right (i.e. all elements in left that are not in right)
	// JoinRelationSet *Difference(JoinRelationSet *left, JoinRelationSet *right);
	string ToString() const;
	void Print();

private:
	JoinRelationTreeNode root;
};

} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/optimizer/join_order/query_graph.hpp
//
//
//===----------------------------------------------------------------------===//







//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/optimizer/join_order/relation_manager.hpp
//
//
//===----------------------------------------------------------------------===//





//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/optimizer/join_order/cardinality_estimator.hpp
//
//
//===----------------------------------------------------------------------===//


//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/column_binding_map.hpp
//
//
//===----------------------------------------------------------------------===//



//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/types/hash.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

struct string_t;
struct interval_t; // NOLINT

// efficient hash function that maximizes the avalanche effect and minimizes
// bias
// see: https://nullprogram.com/blog/2018/07/31/

inline hash_t MurmurHash64(uint64_t x) {
	x ^= x >> 32;
	x *= 0xd6e8feb86659fd93U;
	x ^= x >> 32;
	x *= 0xd6e8feb86659fd93U;
	x ^= x >> 32;
	return x;
}

inline hash_t MurmurHash32(uint32_t x) {
	return MurmurHash64(x);
}

template <class T>
hash_t Hash(T value) {
	return MurmurHash32(static_cast<uint32_t>(value));
}

//! Combine two hashes by XORing them
inline hash_t CombineHash(hash_t left, hash_t right) {
	return left ^ right;
}

template <>
DUCKDB_API hash_t Hash(uint64_t val);
template <>
DUCKDB_API hash_t Hash(int64_t val);
template <>
DUCKDB_API hash_t Hash(hugeint_t val);
template <>
DUCKDB_API hash_t Hash(uhugeint_t val);
template <>
DUCKDB_API hash_t Hash(float val);
template <>
DUCKDB_API hash_t Hash(double val);
template <>
DUCKDB_API hash_t Hash(const char *val);
template <>
DUCKDB_API hash_t Hash(char *val);
template <>
DUCKDB_API hash_t Hash(string_t val);
template <>
DUCKDB_API hash_t Hash(interval_t val);
DUCKDB_API hash_t Hash(const char *val, size_t size);
DUCKDB_API hash_t Hash(uint8_t *val, size_t size);

} // namespace duckdb



//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/column_binding.hpp
//
//
//===----------------------------------------------------------------------===//






#include <functional>

namespace duckdb {
class Serializer;
class Deserializer;

struct ColumnBinding {
	idx_t table_index;
	// This index is local to a Binding, and has no meaning outside of the context of the Binding that created it
	idx_t column_index;

	ColumnBinding() : table_index(DConstants::INVALID_INDEX), column_index(DConstants::INVALID_INDEX) {
	}
	ColumnBinding(idx_t table, idx_t column) : table_index(table), column_index(column) {
	}

	string ToString() const {
		return "#[" + to_string(table_index) + "." + to_string(column_index) + "]";
	}

	bool operator==(const ColumnBinding &rhs) const {
		return table_index == rhs.table_index && column_index == rhs.column_index;
	}

	bool operator!=(const ColumnBinding &rhs) const {
		return !(*this == rhs);
	}

	void Serialize(Serializer &serializer) const;
	static ColumnBinding Deserialize(Deserializer &deserializer);
};

} // namespace duckdb


namespace duckdb {

struct ColumnBindingHashFunction {
	uint64_t operator()(const ColumnBinding &a) const {
		return CombineHash(Hash<idx_t>(a.table_index), Hash<idx_t>(a.column_index));
	}
};

struct ColumnBindingEquality {
	bool operator()(const ColumnBinding &a, const ColumnBinding &b) const {
		return a == b;
	}
};

template <typename T>
using column_binding_map_t = unordered_map<ColumnBinding, T, ColumnBindingHashFunction, ColumnBindingEquality>;

using column_binding_set_t = unordered_set<ColumnBinding, ColumnBindingHashFunction, ColumnBindingEquality>;

} // namespace duckdb



//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/optimizer/join_order/statistics_extractor.hpp
//
//
//===----------------------------------------------------------------------===//


//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/filter/conjunction_filter.hpp
//
//
//===----------------------------------------------------------------------===//



//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/table_filter.hpp
//
//
//===----------------------------------------------------------------------===//











namespace duckdb {
class BaseStatistics;
class Expression;
class PhysicalOperator;
class PhysicalTableScan;

enum class TableFilterType : uint8_t {
	CONSTANT_COMPARISON = 0, // constant comparison (e.g. =C, >C, >=C, <C, <=C)
	IS_NULL = 1,
	IS_NOT_NULL = 2,
	CONJUNCTION_OR = 3,
	CONJUNCTION_AND = 4,
	STRUCT_EXTRACT = 5
};

//! TableFilter represents a filter pushed down into the table scan.
class TableFilter {
public:
	explicit TableFilter(TableFilterType filter_type_p) : filter_type(filter_type_p) {
	}
	virtual ~TableFilter() {
	}

	TableFilterType filter_type;

public:
	//! Returns true if the statistics indicate that the segment can contain values that satisfy that filter
	virtual FilterPropagateResult CheckStatistics(BaseStatistics &stats) = 0;
	virtual string ToString(const string &column_name) = 0;
	virtual unique_ptr<TableFilter> Copy() const = 0;
	virtual bool Equals(const TableFilter &other) const {
		return filter_type != other.filter_type;
	}
	virtual unique_ptr<Expression> ToExpression(const Expression &column) const = 0;

	virtual void Serialize(Serializer &serializer) const;
	static unique_ptr<TableFilter> Deserialize(Deserializer &deserializer);

public:
	template <class TARGET>
	TARGET &Cast() {
		if (filter_type != TARGET::TYPE) {
			throw InternalException("Failed to cast table to type - table filter type mismatch");
		}
		return reinterpret_cast<TARGET &>(*this);
	}

	template <class TARGET>
	const TARGET &Cast() const {
		if (filter_type != TARGET::TYPE) {
			throw InternalException("Failed to cast table to type - table filter type mismatch");
		}
		return reinterpret_cast<const TARGET &>(*this);
	}
};

class TableFilterSet {
public:
	unordered_map<idx_t, unique_ptr<TableFilter>> filters;

public:
	void PushFilter(idx_t column_index, unique_ptr<TableFilter> filter);

	bool Equals(TableFilterSet &other) {
		if (filters.size() != other.filters.size()) {
			return false;
		}
		for (auto &entry : filters) {
			auto other_entry = other.filters.find(entry.first);
			if (other_entry == other.filters.end()) {
				return false;
			}
			if (!entry.second->Equals(*other_entry->second)) {
				return false;
			}
		}
		return true;
	}
	static bool Equals(TableFilterSet *left, TableFilterSet *right) {
		if (left == right) {
			return true;
		}
		if (!left || !right) {
			return false;
		}
		return left->Equals(*right);
	}

	void Serialize(Serializer &serializer) const;
	static TableFilterSet Deserialize(Deserializer &deserializer);
};

class DynamicTableFilterSet {
public:
	void ClearFilters(const PhysicalOperator &op);
	void PushFilter(const PhysicalOperator &op, idx_t column_index, unique_ptr<TableFilter> filter);

	bool HasFilters() const;
	unique_ptr<TableFilterSet> GetFinalTableFilters(const PhysicalTableScan &scan,
	                                                optional_ptr<TableFilterSet> existing_filters) const;

private:
	mutable mutex lock;
	reference_map_t<const PhysicalOperator, unique_ptr<TableFilterSet>> filters;
};

} // namespace duckdb



namespace duckdb {
class ConjunctionFilter : public TableFilter {
public:
	explicit ConjunctionFilter(TableFilterType filter_type_p) : TableFilter(filter_type_p) {
	}

	~ConjunctionFilter() override {
	}

	//! The filters of this conjunction
	vector<unique_ptr<TableFilter>> child_filters;

public:
	bool Equals(const TableFilter &other) const override {
		return TableFilter::Equals(other);
	}
};

class ConjunctionOrFilter : public ConjunctionFilter {
public:
	static constexpr const TableFilterType TYPE = TableFilterType::CONJUNCTION_OR;

public:
	ConjunctionOrFilter();

public:
	FilterPropagateResult CheckStatistics(BaseStatistics &stats) override;
	string ToString(const string &column_name) override;
	bool Equals(const TableFilter &other) const override;
	unique_ptr<TableFilter> Copy() const override;
	unique_ptr<Expression> ToExpression(const Expression &column) const override;
	void Serialize(Serializer &serializer) const override;
	static unique_ptr<TableFilter> Deserialize(Deserializer &deserializer);
};

class ConjunctionAndFilter : public ConjunctionFilter {
public:
	static constexpr const TableFilterType TYPE = TableFilterType::CONJUNCTION_AND;

public:
	ConjunctionAndFilter();

public:
	FilterPropagateResult CheckStatistics(BaseStatistics &stats) override;
	string ToString(const string &column_name) override;
	bool Equals(const TableFilter &other) const override;
	unique_ptr<TableFilter> Copy() const override;
	unique_ptr<Expression> ToExpression(const Expression &column) const override;
	void Serialize(Serializer &serializer) const override;
	static unique_ptr<TableFilter> Deserialize(Deserializer &deserializer);
};

} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/logical_operator.hpp
//
//
//===----------------------------------------------------------------------===//





//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/enums/logical_operator_type.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

//===--------------------------------------------------------------------===//
// Logical Operator Types
//===--------------------------------------------------------------------===//
enum class LogicalOperatorType : uint8_t {
	LOGICAL_INVALID = 0,
	LOGICAL_PROJECTION = 1,
	LOGICAL_FILTER = 2,
	LOGICAL_AGGREGATE_AND_GROUP_BY = 3,
	LOGICAL_WINDOW = 4,
	LOGICAL_UNNEST = 5,
	LOGICAL_LIMIT = 6,
	LOGICAL_ORDER_BY = 7,
	LOGICAL_TOP_N = 8,
	LOGICAL_COPY_TO_FILE = 10,
	LOGICAL_DISTINCT = 11,
	LOGICAL_SAMPLE = 12,
	LOGICAL_PIVOT = 14,
	LOGICAL_COPY_DATABASE = 15,

	// -----------------------------
	// Data sources
	// -----------------------------
	LOGICAL_GET = 25,
	LOGICAL_CHUNK_GET = 26,
	LOGICAL_DELIM_GET = 27,
	LOGICAL_EXPRESSION_GET = 28,
	LOGICAL_DUMMY_SCAN = 29,
	LOGICAL_EMPTY_RESULT = 30,
	LOGICAL_CTE_REF = 31,
	// -----------------------------
	// Joins
	// -----------------------------
	LOGICAL_JOIN = 50,
	LOGICAL_DELIM_JOIN = 51,
	LOGICAL_COMPARISON_JOIN = 52,
	LOGICAL_ANY_JOIN = 53,
	LOGICAL_CROSS_PRODUCT = 54,
	LOGICAL_POSITIONAL_JOIN = 55,
	LOGICAL_ASOF_JOIN = 56,
	LOGICAL_DEPENDENT_JOIN = 57,
	// -----------------------------
	// SetOps
	// -----------------------------
	LOGICAL_UNION = 75,
	LOGICAL_EXCEPT = 76,
	LOGICAL_INTERSECT = 77,
	LOGICAL_RECURSIVE_CTE = 78,
	LOGICAL_MATERIALIZED_CTE = 79,

	// -----------------------------
	// Updates
	// -----------------------------
	LOGICAL_INSERT = 100,
	LOGICAL_DELETE = 101,
	LOGICAL_UPDATE = 102,

	// -----------------------------
	// Schema
	// -----------------------------
	LOGICAL_ALTER = 125,
	LOGICAL_CREATE_TABLE = 126,
	LOGICAL_CREATE_INDEX = 127,
	LOGICAL_CREATE_SEQUENCE = 128,
	LOGICAL_CREATE_VIEW = 129,
	LOGICAL_CREATE_SCHEMA = 130,
	LOGICAL_CREATE_MACRO = 131,
	LOGICAL_DROP = 132,
	LOGICAL_PRAGMA = 133,
	LOGICAL_TRANSACTION = 134,
	LOGICAL_CREATE_TYPE = 135,
	LOGICAL_ATTACH = 136,
	LOGICAL_DETACH = 137,

	// -----------------------------
	// Explain
	// -----------------------------
	LOGICAL_EXPLAIN = 150,

	// -----------------------------
	// Helpers
	// -----------------------------
	LOGICAL_PREPARE = 175,
	LOGICAL_EXECUTE = 176,
	LOGICAL_EXPORT = 177,
	LOGICAL_VACUUM = 178,
	LOGICAL_SET = 179,
	LOGICAL_LOAD = 180,
	LOGICAL_RESET = 181,
	LOGICAL_UPDATE_EXTENSIONS = 182,

	// -----------------------------
	// Secrets
	// -----------------------------
	LOGICAL_CREATE_SECRET = 190,

	LOGICAL_EXTENSION_OPERATOR = 255
};

DUCKDB_API string LogicalOperatorToString(LogicalOperatorType type);

} // namespace duckdb




//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/logical_operator_visitor.hpp
//
//
//===----------------------------------------------------------------------===//




//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/bound_tokens.hpp
//
//
//===----------------------------------------------------------------------===//



namespace duckdb {

//===--------------------------------------------------------------------===//
// Query Node
//===--------------------------------------------------------------------===//
class BoundQueryNode;
class BoundSelectNode;
class BoundSetOperationNode;
class BoundRecursiveCTENode;
class BoundCTENode;

//===--------------------------------------------------------------------===//
// Expressions
//===--------------------------------------------------------------------===//
class Expression;

class BoundAggregateExpression;
class BoundBetweenExpression;
class BoundCaseExpression;
class BoundCastExpression;
class BoundColumnRefExpression;
class BoundComparisonExpression;
class BoundConjunctionExpression;
class BoundConstantExpression;
class BoundDefaultExpression;
class BoundFunctionExpression;
class BoundOperatorExpression;
class BoundParameterExpression;
class BoundReferenceExpression;
class BoundSubqueryExpression;
class BoundUnnestExpression;
class BoundWindowExpression;

//===--------------------------------------------------------------------===//
// TableRefs
//===--------------------------------------------------------------------===//
class BoundTableRef;

class BoundBaseTableRef;
class BoundJoinRef;
class BoundSubqueryRef;
class BoundTableFunction;
class BoundEmptyTableRef;
class BoundExpressionListRef;
class BoundColumnDataRef;
class BoundCTERef;
class BoundPivotRef;

} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/logical_tokens.hpp
//
//
//===----------------------------------------------------------------------===//



namespace duckdb {

class LogicalOperator;

class LogicalAggregate;
class LogicalAnyJoin;
class LogicalColumnDataGet;
class LogicalComparisonJoin;
class LogicalCopyDatabase;
class LogicalCopyToFile;
class LogicalCreate;
class LogicalCreateTable;
class LogicalCreateIndex;
class LogicalCreateTable;
class LogicalCreateSecret;
class LogicalCrossProduct;
class LogicalCTERef;
class LogicalDelete;
class LogicalDelimGet;
class LogicalDistinct;
class LogicalDummyScan;
class LogicalEmptyResult;
class LogicalExecute;
class LogicalExplain;
class LogicalExport;
class LogicalExpressionGet;
class LogicalFilter;
class LogicalGet;
class LogicalInsert;
class LogicalJoin;
class LogicalLimit;
class LogicalOrder;
class LogicalPivot;
class LogicalPositionalJoin;
class LogicalPragma;
class LogicalPrepare;
class LogicalProjection;
class LogicalRecursiveCTE;
class LogicalMaterializedCTE;
class LogicalSetOperation;
class LogicalSample;
class LogicalSimple;
class LogicalVacuum;
class LogicalSet;
class LogicalReset;
class LogicalTopN;
class LogicalUnnest;
class LogicalUpdate;
class LogicalWindow;

} // namespace duckdb


#include <functional>

namespace duckdb {
//! The LogicalOperatorVisitor is an abstract base class that implements the
//! Visitor pattern on LogicalOperator.
class LogicalOperatorVisitor {
public:
	virtual ~LogicalOperatorVisitor() {
	}

	virtual void VisitOperator(LogicalOperator &op);
	virtual void VisitExpression(unique_ptr<Expression> *expression);

	static void EnumerateExpressions(LogicalOperator &op,
	                                 const std::function<void(unique_ptr<Expression> *child)> &callback);

protected:
	//! Automatically calls the Visit method for LogicalOperator children of the current operator. Can be overloaded to
	//! change this behavior.
	void VisitOperatorChildren(LogicalOperator &op);
	//! Automatically calls the Visit method for Expression children of the current operator. Can be overloaded to
	//! change this behavior.
	void VisitOperatorExpressions(LogicalOperator &op);

	// The VisitExpressionChildren method is called at the end of every call to VisitExpression to recursively visit all
	// expressions in an expression tree. It can be overloaded to prevent automatically visiting the entire tree.
	virtual void VisitExpressionChildren(Expression &expression);

	virtual unique_ptr<Expression> VisitReplace(BoundAggregateExpression &expr, unique_ptr<Expression> *expr_ptr);
	virtual unique_ptr<Expression> VisitReplace(BoundBetweenExpression &expr, unique_ptr<Expression> *expr_ptr);
	virtual unique_ptr<Expression> VisitReplace(BoundCaseExpression &expr, unique_ptr<Expression> *expr_ptr);
	virtual unique_ptr<Expression> VisitReplace(BoundCastExpression &expr, unique_ptr<Expression> *expr_ptr);
	virtual unique_ptr<Expression> VisitReplace(BoundColumnRefExpression &expr, unique_ptr<Expression> *expr_ptr);
	virtual unique_ptr<Expression> VisitReplace(BoundComparisonExpression &expr, unique_ptr<Expression> *expr_ptr);
	virtual unique_ptr<Expression> VisitReplace(BoundConjunctionExpression &expr, unique_ptr<Expression> *expr_ptr);
	virtual unique_ptr<Expression> VisitReplace(BoundConstantExpression &expr, unique_ptr<Expression> *expr_ptr);
	virtual unique_ptr<Expression> VisitReplace(BoundDefaultExpression &expr, unique_ptr<Expression> *expr_ptr);
	virtual unique_ptr<Expression> VisitReplace(BoundFunctionExpression &expr, unique_ptr<Expression> *expr_ptr);
	virtual unique_ptr<Expression> VisitReplace(BoundOperatorExpression &expr, unique_ptr<Expression> *expr_ptr);
	virtual unique_ptr<Expression> VisitReplace(BoundReferenceExpression &expr, unique_ptr<Expression> *expr_ptr);
	virtual unique_ptr<Expression> VisitReplace(BoundSubqueryExpression &expr, unique_ptr<Expression> *expr_ptr);
	virtual unique_ptr<Expression> VisitReplace(BoundParameterExpression &expr, unique_ptr<Expression> *expr_ptr);
	virtual unique_ptr<Expression> VisitReplace(BoundWindowExpression &expr, unique_ptr<Expression> *expr_ptr);
	virtual unique_ptr<Expression> VisitReplace(BoundUnnestExpression &expr, unique_ptr<Expression> *expr_ptr);
};
} // namespace duckdb


//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/insertion_order_preserving_map.hpp
//
//
//===----------------------------------------------------------------------===//











namespace duckdb {

template <typename V>
class InsertionOrderPreservingMap {
public:
	typedef vector<pair<string, V>> VECTOR_TYPE; // NOLINT: matching name of std
	typedef string key_type;                     // NOLINT: matching name of std

public:
	InsertionOrderPreservingMap() {
	}

private:
	VECTOR_TYPE map;
	case_insensitive_map_t<idx_t> map_idx;

public:
	vector<string> Keys() const {
		vector<string> keys;
		keys.resize(this->size());
		for (auto &kv : map_idx) {
			keys[kv.second] = kv.first;
		}

		return keys;
	}

	typename VECTOR_TYPE::iterator begin() { // NOLINT: match stl API
		return map.begin();
	}

	typename VECTOR_TYPE::iterator end() { // NOLINT: match stl API
		return map.end();
	}

	typename VECTOR_TYPE::const_iterator begin() const { // NOLINT: match stl API
		return map.begin();
	}

	typename VECTOR_TYPE::const_iterator end() const { // NOLINT: match stl API
		return map.end();
	}

	typename VECTOR_TYPE::reverse_iterator rbegin() { // NOLINT: match stl API
		return map.rbegin();
	}

	typename VECTOR_TYPE::reverse_iterator rend() { // NOLINT: match stl API
		return map.rend();
	}

	typename VECTOR_TYPE::iterator find(const string &key) { // NOLINT: match stl API
		auto entry = map_idx.find(key);
		if (entry == map_idx.end()) {
			return map.end();
		}
		return map.begin() + static_cast<typename VECTOR_TYPE::difference_type>(entry->second);
	}

	typename VECTOR_TYPE::const_iterator find(const string &key) const { // NOLINT: match stl API
		auto entry = map_idx.find(key);
		if (entry == map_idx.end()) {
			return map.end();
		}
		return map.begin() + static_cast<typename VECTOR_TYPE::difference_type>(entry->second);
	}

	idx_t size() const { // NOLINT: match stl API
		return map_idx.size();
	}

	bool empty() const { // NOLINT: match stl API
		return map_idx.empty();
	}

	void resize(idx_t nz) { // NOLINT: match stl API
		map.resize(nz);
	}

	void insert(const string &key, V &value) { // NOLINT: match stl API
		map.push_back(make_pair(key, std::move(value)));
		map_idx[key] = map.size() - 1;
	}

	void insert(const string &key, V &&value) { // NOLINT: match stl API
		map.push_back(make_pair(key, std::move(value)));
		map_idx[key] = map.size() - 1;
	}

	void insert(pair<string, V> &&value) { // NOLINT: match stl API
		map_idx[value.first] = map.size();
		map.push_back(std::move(value));
	}

	void erase(typename VECTOR_TYPE::iterator it) { // NOLINT: match stl API
		auto key = it->first;
		auto idx = map_idx[it->first];
		map.erase(it);
		map_idx.erase(key);
		for (auto &kv : map_idx) {
			if (kv.second > idx) {
				kv.second--;
			}
		}
	}

	bool contains(const string &key) const { // NOLINT: match stl API
		return map_idx.find(key) != map_idx.end();
	}

	const V &at(const string &key) const { // NOLINT: match stl API
		return map[map_idx.at(key)].second;
	}

	V &operator[](const string &key) {
		if (!contains(key)) {
			auto v = V();
			insert(key, v);
		}
		return map[map_idx[key]].second;
	}
};

} // namespace duckdb


#include <algorithm>
#include <functional>

namespace duckdb {

//! LogicalOperator is the base class of the logical operators present in the
//! logical query tree
class LogicalOperator {
public:
	explicit LogicalOperator(LogicalOperatorType type);
	LogicalOperator(LogicalOperatorType type, vector<unique_ptr<Expression>> expressions);
	virtual ~LogicalOperator();

	//! The type of the logical operator
	LogicalOperatorType type;
	//! The set of children of the operator
	vector<unique_ptr<LogicalOperator>> children;
	//! The set of expressions contained within the operator, if any
	vector<unique_ptr<Expression>> expressions;
	//! The types returned by this logical operator. Set by calling LogicalOperator::ResolveTypes.
	vector<LogicalType> types;
	//! Estimated Cardinality
	idx_t estimated_cardinality;
	bool has_estimated_cardinality;

public:
	virtual vector<ColumnBinding> GetColumnBindings();
	static string ColumnBindingsToString(const vector<ColumnBinding> &bindings);
	void PrintColumnBindings();
	static vector<ColumnBinding> GenerateColumnBindings(idx_t table_idx, idx_t column_count);
	static vector<LogicalType> MapTypes(const vector<LogicalType> &types, const vector<idx_t> &projection_map);
	static vector<ColumnBinding> MapBindings(const vector<ColumnBinding> &types, const vector<idx_t> &projection_map);

	//! Resolve the types of the logical operator and its children
	void ResolveOperatorTypes();

	virtual string GetName() const;
	virtual InsertionOrderPreservingMap<string> ParamsToString() const;
	virtual string ToString(ExplainFormat format = ExplainFormat::DEFAULT) const;
	DUCKDB_API void Print();
	//! Debug method: verify that the integrity of expressions & child nodes are maintained
	virtual void Verify(ClientContext &context);

	void AddChild(unique_ptr<LogicalOperator> child);
	virtual idx_t EstimateCardinality(ClientContext &context);
	void SetEstimatedCardinality(idx_t _estimated_cardinality);
	void SetParamsEstimatedCardinality(InsertionOrderPreservingMap<string> &result) const;

	virtual void Serialize(Serializer &serializer) const;
	static unique_ptr<LogicalOperator> Deserialize(Deserializer &deserializer);

	virtual unique_ptr<LogicalOperator> Copy(ClientContext &context) const;

	virtual bool RequireOptimizer() const {
		return true;
	}

	//! Allows LogicalOperators to opt out of serialization
	virtual bool SupportSerialization() const {
		return true;
	};

	//! Returns the set of table indexes of this operator
	virtual vector<idx_t> GetTableIndex() const;

protected:
	//! Resolve types for this specific operator
	virtual void ResolveTypes() = 0;

public:
	template <class TARGET>
	TARGET &Cast() {
		if (TARGET::TYPE != LogicalOperatorType::LOGICAL_INVALID && type != TARGET::TYPE) {
			throw InternalException("Failed to cast logical operator to type - logical operator type mismatch");
		}
		return reinterpret_cast<TARGET &>(*this);
	}

	template <class TARGET>
	const TARGET &Cast() const {
		if (TARGET::TYPE != LogicalOperatorType::LOGICAL_INVALID && type != TARGET::TYPE) {
			throw InternalException("Failed to cast logical operator to type - logical operator type mismatch");
		}
		return reinterpret_cast<const TARGET &>(*this);
	}
};
} // namespace duckdb


namespace duckdb {

class CardinalityEstimator;

struct DistinctCount {
	idx_t distinct_count;
	bool from_hll;
};

struct ExpressionBinding {
	bool found_expression = false;
	ColumnBinding child_binding;
	bool expression_is_constant = false;
};

struct RelationStats {
	// column_id -> estimated distinct count for column
	vector<DistinctCount> column_distinct_count;
	idx_t cardinality;
	double filter_strength = 1;
	bool stats_initialized = false;

	// for debug, column names and tables
	vector<string> column_names;
	string table_name;

	RelationStats() : cardinality(1), filter_strength(1), stats_initialized(false) {
	}
};

class RelationStatisticsHelper {
public:
	static constexpr double DEFAULT_SELECTIVITY = 0.2;

public:
	static idx_t InspectConjunctionAND(idx_t cardinality, idx_t column_index, ConjunctionAndFilter &filter,
	                                   BaseStatistics &base_stats);
	//	static idx_t InspectConjunctionOR(idx_t cardinality, idx_t column_index, ConjunctionOrFilter &filter,
	//	                                  BaseStatistics &base_stats);
	//! Extract Statistics from a LogicalGet.
	static RelationStats ExtractGetStats(LogicalGet &get, ClientContext &context);
	static RelationStats ExtractDelimGetStats(LogicalDelimGet &delim_get, ClientContext &context);
	//! Create the statistics for a projection using the statistics of the operator that sits underneath the
	//! projection. Then also create statistics for any extra columns the projection creates.
	static RelationStats ExtractDummyScanStats(LogicalDummyScan &dummy_scan, ClientContext &context);
	static RelationStats ExtractExpressionGetStats(LogicalExpressionGet &expression_get, ClientContext &context);
	//! All relation extractors for blocking relations
	static RelationStats ExtractProjectionStats(LogicalProjection &proj, RelationStats &child_stats);
	static RelationStats ExtractAggregationStats(LogicalAggregate &aggr, RelationStats &child_stats);
	static RelationStats ExtractWindowStats(LogicalWindow &window, RelationStats &child_stats);
	static RelationStats ExtractEmptyResultStats(LogicalEmptyResult &empty);
	//! Called after reordering a query plan with potentially 2+ relations.
	static RelationStats CombineStatsOfReorderableOperator(vector<ColumnBinding> &bindings,
	                                                       vector<RelationStats> relation_stats);
	//! Called after reordering a query plan with potentially 2+ relations.
	static RelationStats CombineStatsOfNonReorderableOperator(LogicalOperator &op, vector<RelationStats> child_stats);
	static void CopyRelationStats(RelationStats &to, const RelationStats &from);

private:
};

} // namespace duckdb


namespace duckdb {

class FilterInfo;

struct DenomInfo {
	DenomInfo(JoinRelationSet &numerator_relations, double filter_strength, double denominator)
	    : numerator_relations(numerator_relations), filter_strength(filter_strength), denominator(denominator) {
	}

	JoinRelationSet &numerator_relations;
	double filter_strength;
	double denominator;
};

struct RelationsToTDom {
	//! column binding sets that are equivalent in a join plan.
	//! if you have A.x = B.y and B.y = C.z, then one set is {A.x, B.y, C.z}.
	column_binding_set_t equivalent_relations;
	//!	the estimated total domains of the equivalent relations determined using HLL
	idx_t tdom_hll;
	//! the estimated total domains of each relation without using HLL
	idx_t tdom_no_hll;
	bool has_tdom_hll;
	vector<optional_ptr<FilterInfo>> filters;
	vector<string> column_names;

	explicit RelationsToTDom(const column_binding_set_t &column_binding_set)
	    : equivalent_relations(column_binding_set), tdom_hll(0), tdom_no_hll(NumericLimits<idx_t>::Maximum()),
	      has_tdom_hll(false) {};
};

class FilterInfoWithTotalDomains {
public:
	FilterInfoWithTotalDomains(optional_ptr<FilterInfo> filter_info, RelationsToTDom &relation2tdom)
	    : filter_info(filter_info), tdom_hll(relation2tdom.tdom_hll), tdom_no_hll(relation2tdom.tdom_no_hll),
	      has_tdom_hll(relation2tdom.has_tdom_hll) {
	}

	optional_ptr<FilterInfo> filter_info;
	//!	the estimated total domains of the equivalent relations determined using HLL
	idx_t tdom_hll;
	//! the estimated total domains of each relation without using HLL
	idx_t tdom_no_hll;
	bool has_tdom_hll;
};

struct Subgraph2Denominator {
	optional_ptr<JoinRelationSet> relations;
	optional_ptr<JoinRelationSet> numerator_relations;
	double denom;

	Subgraph2Denominator() : relations(nullptr), numerator_relations(nullptr), denom(1) {};
};

class CardinalityHelper {
public:
	CardinalityHelper() {
	}
	explicit CardinalityHelper(double cardinality_before_filters)
	    : cardinality_before_filters(cardinality_before_filters) {};

public:
	// must be a double. Otherwise we can lose significance between different join orders.
	// our cardinality estimator severely underestimates cardinalities for 3+ joins. However,
	// if one join order has an estimate of 0.8, and another has an estimate of 0.6, rounding
	// them means there is no estimated difference, when in reality there could be a very large
	// difference.
	double cardinality_before_filters;

	vector<string> table_names_joined;
	vector<string> column_names;
};

class CardinalityEstimator {
public:
	static constexpr double DEFAULT_SEMI_ANTI_SELECTIVITY = 5;
	static constexpr double DEFAULT_LT_GT_MULTIPLIER = 2.5;
	explicit CardinalityEstimator() {};

private:
	vector<RelationsToTDom> relations_to_tdoms;
	unordered_map<string, CardinalityHelper> relation_set_2_cardinality;
	JoinRelationSetManager set_manager;
	vector<RelationStats> relation_stats;

public:
	void RemoveEmptyTotalDomains();
	void UpdateTotalDomains(optional_ptr<JoinRelationSet> set, RelationStats &stats);
	void InitEquivalentRelations(const vector<unique_ptr<FilterInfo>> &filter_infos);

	void InitCardinalityEstimatorProps(optional_ptr<JoinRelationSet> set, RelationStats &stats);

	//! cost model needs estimated cardinalities to the fraction since the formula captures
	//! distinct count selectivities and multiplicities. Hence the template
	template <class T>
	T EstimateCardinalityWithSet(JoinRelationSet &new_set);

	//! used for debugging.
	void AddRelationNamesToTdoms(vector<RelationStats> &stats);
	void PrintRelationToTdomInfo();

private:
	double GetNumerator(JoinRelationSet &set);
	DenomInfo GetDenominator(JoinRelationSet &set);

	bool SingleColumnFilter(FilterInfo &filter_info);
	vector<idx_t> DetermineMatchingEquivalentSets(optional_ptr<FilterInfo> filter_info);
	//! Given a filter, add the column bindings to the matching equivalent set at the index
	//! given in matching equivalent sets.
	//! If there are multiple equivalence sets, they are merged.
	void AddToEquivalenceSets(optional_ptr<FilterInfo> filter_info, vector<idx_t> matching_equivalent_sets);

	double CalculateUpdatedDenom(Subgraph2Denominator left, Subgraph2Denominator right,
	                             FilterInfoWithTotalDomains &filter);
	JoinRelationSet &UpdateNumeratorRelations(Subgraph2Denominator left, Subgraph2Denominator right,
	                                          FilterInfoWithTotalDomains &filter);

	void AddRelationTdom(FilterInfo &filter_info);
	bool EmptyFilter(FilterInfo &filter_info);
};

} // namespace duckdb




//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/parser/expression_map.hpp
//
//
//===----------------------------------------------------------------------===//









namespace duckdb {
class Expression;

template <class T>
struct ExpressionHashFunction {
	uint64_t operator()(const reference<T> &expr) const {
		return (uint64_t)expr.get().Hash();
	}
};

template <class T>
struct ExpressionEquality {
	bool operator()(const reference<T> &a, const reference<T> &b) const {
		return a.get().Equals(b.get());
	}
};

template <typename T>
using expression_map_t =
    unordered_map<reference<Expression>, T, ExpressionHashFunction<Expression>, ExpressionEquality<Expression>>;

using expression_set_t =
    unordered_set<reference<Expression>, ExpressionHashFunction<Expression>, ExpressionEquality<Expression>>;

template <typename T>
using parsed_expression_map_t = unordered_map<reference<ParsedExpression>, T, ExpressionHashFunction<ParsedExpression>,
                                              ExpressionEquality<ParsedExpression>>;

using parsed_expression_set_t = unordered_set<reference<ParsedExpression>, ExpressionHashFunction<ParsedExpression>,
                                              ExpressionEquality<ParsedExpression>>;

} // namespace duckdb




namespace duckdb {

class JoinOrderOptimizer;
class FilterInfo;

//! Represents a single relation and any metadata accompanying that relation
struct SingleJoinRelation {
	LogicalOperator &op;
	optional_ptr<LogicalOperator> parent;
	RelationStats stats;

	SingleJoinRelation(LogicalOperator &op, optional_ptr<LogicalOperator> parent) : op(op), parent(parent) {
	}
	SingleJoinRelation(LogicalOperator &op, optional_ptr<LogicalOperator> parent, RelationStats stats)
	    : op(op), parent(parent), stats(std::move(stats)) {
	}
};

class RelationManager {
public:
	explicit RelationManager(ClientContext &context) : context(context) {
	}

	idx_t NumRelations();

	bool ExtractJoinRelations(JoinOrderOptimizer &optimizer, LogicalOperator &input_op,
	                          vector<reference<LogicalOperator>> &filter_operators,
	                          optional_ptr<LogicalOperator> parent = nullptr);

	//! for each join filter in the logical plan op, extract the relations that are referred to on
	//! both sides of the join filter, along with the tables & indexes.
	vector<unique_ptr<FilterInfo>> ExtractEdges(LogicalOperator &op,
	                                            vector<reference<LogicalOperator>> &filter_operators,
	                                            JoinRelationSetManager &set_manager);

	//! Extract the set of relations referred to inside an expression
	bool ExtractBindings(Expression &expression, unordered_set<idx_t> &bindings);
	void AddRelation(LogicalOperator &op, optional_ptr<LogicalOperator> parent, const RelationStats &stats);

	void AddAggregateOrWindowRelation(LogicalOperator &op, optional_ptr<LogicalOperator> parent,
	                                  const RelationStats &stats, LogicalOperatorType op_type);
	vector<unique_ptr<SingleJoinRelation>> GetRelations();

	const vector<RelationStats> GetRelationStats();
	//! A mapping of base table index -> index into relations array (relation number)
	unordered_map<idx_t, idx_t> relation_mapping;

	bool CrossProductWithRelationAllowed(idx_t relation_id);

	void PrintRelationStats();

private:
	ClientContext &context;
	//! Set of all relations considered in the join optimizer
	vector<unique_ptr<SingleJoinRelation>> relations;
	unordered_set<idx_t> no_cross_product_relations;
};

} // namespace duckdb







#include <functional>

namespace duckdb {

class FilterInfo;

struct NeighborInfo {
	explicit NeighborInfo(optional_ptr<JoinRelationSet> neighbor) : neighbor(neighbor) {
	}

	optional_ptr<JoinRelationSet> neighbor;
	vector<optional_ptr<FilterInfo>> filters;
};

//! The QueryGraph contains edges between relations and allows edges to be created/queried
class QueryGraphEdges {
public:
	//! Contains a node with info about neighboring relations and child edge infos
	struct QueryEdge {
		vector<unique_ptr<NeighborInfo>> neighbors;
		unordered_map<idx_t, unique_ptr<QueryEdge>> children;
	};

public:
	string ToString() const;
	void Print();

	//! Returns a connection if there is an edge that connects these two sets, or nullptr otherwise
	const vector<reference<NeighborInfo>> GetConnections(JoinRelationSet &node, JoinRelationSet &other) const;
	//! Enumerate the neighbors of a specific node that do not belong to any of the exclusion_set. Note that if a
	//! neighbor has multiple nodes, this function will return the lowest entry in that set.
	const vector<idx_t> GetNeighbors(JoinRelationSet &node, unordered_set<idx_t> &exclusion_set) const;

	//! Enumerate all neighbors of a given JoinRelationSet node
	void EnumerateNeighbors(JoinRelationSet &node, const std::function<bool(NeighborInfo &)> &callback) const;
	//! Create an edge in the edge_set
	void CreateEdge(JoinRelationSet &left, JoinRelationSet &right, optional_ptr<FilterInfo> info);

private:
	//! Get the QueryEdge of a specific node
	optional_ptr<QueryEdge> GetQueryEdge(JoinRelationSet &left);

	void EnumerateNeighborsDFS(JoinRelationSet &node, reference<QueryEdge> info, idx_t index,
	                           const std::function<bool(NeighborInfo &)> &callback) const;

	QueryEdge root;
};

} // namespace duckdb


namespace duckdb {

struct NeighborInfo;

class DPJoinNode {
public:
	//! Represents a node in the join plan
	JoinRelationSet &set;
	//! information on how left and right are connected
	optional_ptr<NeighborInfo> info;
	bool is_leaf;
	//! left and right plans
	JoinRelationSet &left_set;
	JoinRelationSet &right_set;

	//! The cost of the join node. The cost is stored here so that the cost of
	//! a join node stays in sync with how the join node is constructed. Storing the cost in an unordered_set
	//! in the cost model is error prone. If the plan enumerator join node is updated and not the cost model
	//! the whole Join Order Optimizer can start exhibiting undesired behavior.
	double cost;
	//! used only to populate logical operators with estimated cardinalities after the best join plan has been found.
	idx_t cardinality;

	//! Create an intermediate node in the join tree. base_cardinality = estimated_props.cardinality
	DPJoinNode(JoinRelationSet &set, optional_ptr<NeighborInfo> info, JoinRelationSet &left, JoinRelationSet &right,
	           double cost);

	//! Create a leaf node in the join tree
	//! set cost to 0 for leaf nodes
	//! cost will be the cost to *produce* an intermediate table
	explicit DPJoinNode(JoinRelationSet &set);
};

} // namespace duckdb


//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/physical_operator_states.hpp
//
//
//===----------------------------------------------------------------------===//










//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/parallel/interrupt.hpp
//
//
//===----------------------------------------------------------------------===//







//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/parallel/task.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {
class ClientContext;
class Executor;
class Task;
class DatabaseInstance;
struct ProducerToken;

enum class TaskExecutionMode : uint8_t { PROCESS_ALL, PROCESS_PARTIAL };

enum class TaskExecutionResult : uint8_t { TASK_FINISHED, TASK_NOT_FINISHED, TASK_ERROR, TASK_BLOCKED };

//! Generic parallel task
class Task : public enable_shared_from_this<Task> {
public:
	virtual ~Task() {
	}

public:
	//! Execute the task in the specified execution mode
	//! If mode is PROCESS_ALL, Execute should always finish processing and return TASK_FINISHED
	//! If mode is PROCESS_PARTIAL, Execute can return TASK_NOT_FINISHED, in which case Execute will be called again
	//! In case of an error, TASK_ERROR is returned
	//! In case the task has interrupted, BLOCKED is returned.
	virtual TaskExecutionResult Execute(TaskExecutionMode mode) = 0;

	//! Descheduling a task ensures the task is not executed, but remains available for rescheduling as long as
	//! required, generally until some code in an operator calls the InterruptState::Callback() method of a state of the
	//! InterruptMode::TASK mode.
	virtual void Deschedule() {
		throw InternalException("Cannot deschedule task of base Task class");
	};

	//! Ensures a task is rescheduled to the correct queue
	virtual void Reschedule() {
		throw InternalException("Cannot reschedule task of base Task class");
	}

	virtual bool TaskBlockedOnResult() const {
		return false;
	}
};

} // namespace duckdb


#include <condition_variable>

namespace duckdb {

//! InterruptMode specifies how operators should block/unblock, note that this will happen transparently to the
//! operator, as the operator only needs to return a BLOCKED result and call the callback using the InterruptState.
//! NO_INTERRUPTS: No blocking mode is specified, an error will be thrown when the operator blocks. Should only be used
//!                when manually calling operators of which is known they will never block.
//! TASK:          A weak pointer to a task is provided. On the callback, this task will be signalled. If the Task has
//!                been deleted, this callback becomes a NOP. This is the preferred way to await blocked pipelines.
//! BLOCKING:	   The caller has blocked awaiting some synchronization primitive to wait for the callback.
enum class InterruptMode : uint8_t { NO_INTERRUPTS, TASK, BLOCKING };

//! Synchronization primitive used to await a callback in InterruptMode::BLOCKING.
struct InterruptDoneSignalState {
	//! Called by the callback to signal the interrupt is over
	void Signal();
	//! Await the callback signalling the interrupt is over
	void Await();

protected:
	mutex lock;
	std::condition_variable cv;
	bool done = false;
};

//! State required to make the callback after some asynchronous operation within an operator source / sink.
class InterruptState {
public:
	//! Default interrupt state will be set to InterruptMode::NO_INTERRUPTS and throw an error on use of Callback()
	InterruptState();
	//! Register the task to be interrupted and set mode to InterruptMode::TASK, the preferred way to handle interrupts
	explicit InterruptState(weak_ptr<Task> task);
	//! Register signal state and set mode to InterruptMode::BLOCKING, used for code paths without Task.
	explicit InterruptState(weak_ptr<InterruptDoneSignalState> done_signal);

	//! Perform the callback to indicate the Interrupt is over
	DUCKDB_API void Callback() const;

protected:
	//! Current interrupt mode
	InterruptMode mode;
	//! Task ptr for InterruptMode::TASK
	weak_ptr<Task> current_task;
	//! Signal state for InterruptMode::BLOCKING
	weak_ptr<InterruptDoneSignalState> signal_state;
};

class StateWithBlockableTasks {
public:
	unique_lock<mutex> Lock() {
		return unique_lock<mutex>(lock);
	}

	void PreventBlocking(const unique_lock<mutex> &guard) {
		D_ASSERT(guard.mutex() && RefersToSameObject(*guard.mutex(), lock));
		can_block = false;
	}

	//! Add a task to 'blocked_tasks' before returning SourceResultType::BLOCKED (must hold the lock)
	bool BlockTask(const unique_lock<mutex> &guard, const InterruptState &interrupt_state) {
		D_ASSERT(guard.mutex() && RefersToSameObject(*guard.mutex(), lock));
		if (can_block) {
			blocked_tasks.push_back(interrupt_state);
			return true;
		}
		return false;
	}

	//! Unblock all tasks (must hold the lock)
	bool UnblockTasks(const unique_lock<mutex> &guard) {
		D_ASSERT(guard.mutex() && RefersToSameObject(*guard.mutex(), lock));
		if (blocked_tasks.empty()) {
			return false;
		}
		for (auto &entry : blocked_tasks) {
			entry.Callback();
		}
		blocked_tasks.clear();
		return true;
	}

	SinkResultType BlockSink(const unique_lock<mutex> &guard, const InterruptState &interrupt_state) {
		return BlockTask(guard, interrupt_state) ? SinkResultType::BLOCKED : SinkResultType::FINISHED;
	}

	SourceResultType BlockSource(const unique_lock<mutex> &guard, const InterruptState &interrupt_state) {
		return BlockTask(guard, interrupt_state) ? SourceResultType::BLOCKED : SourceResultType::FINISHED;
	}

private:
	//! Whether we can block tasks
	atomic<bool> can_block {true};
	//! Global lock, acquired by calling Lock()
	mutable mutex lock;
	//! Tasks that are currently blocked
	mutable vector<InterruptState> blocked_tasks;
};

} // namespace duckdb


namespace duckdb {
class Event;
class Executor;
class PhysicalOperator;
class Pipeline;
class PipelineBuildState;
class MetaPipeline;
class InterruptState;

struct SourcePartitionInfo {
	//! The current batch index
	//! This is only set in case RequiresBatchIndex() is true, and the source has support for it (SupportsBatchIndex())
	//! Otherwise this is left on INVALID_INDEX
	//! The batch index is a globally unique, increasing index that should be used to maintain insertion order
	//! //! in conjunction with parallelism
	optional_idx batch_index;
	//! The minimum batch index that any thread is currently actively reading
	optional_idx min_batch_index;
};

// LCOV_EXCL_START
class OperatorState {
public:
	virtual ~OperatorState() {
	}

	virtual void Finalize(const PhysicalOperator &op, ExecutionContext &context) {
	}

	template <class TARGET>
	TARGET &Cast() {
		DynamicCastCheck<TARGET>(this);
		return reinterpret_cast<TARGET &>(*this);
	}
	template <class TARGET>
	const TARGET &Cast() const {
		DynamicCastCheck<TARGET>(this);
		return reinterpret_cast<const TARGET &>(*this);
	}
};

class GlobalOperatorState {
public:
	virtual ~GlobalOperatorState() {
	}

	template <class TARGET>
	TARGET &Cast() {
		DynamicCastCheck<TARGET>(this);
		return reinterpret_cast<TARGET &>(*this);
	}
	template <class TARGET>
	const TARGET &Cast() const {
		DynamicCastCheck<TARGET>(this);
		return reinterpret_cast<const TARGET &>(*this);
	}
};

class GlobalSinkState : public StateWithBlockableTasks {
public:
	GlobalSinkState() : state(SinkFinalizeType::READY) {
	}
	virtual ~GlobalSinkState() {
	}

	SinkFinalizeType state;

	template <class TARGET>
	TARGET &Cast() {
		DynamicCastCheck<TARGET>(this);
		return reinterpret_cast<TARGET &>(*this);
	}
	template <class TARGET>
	const TARGET &Cast() const {
		DynamicCastCheck<TARGET>(this);
		return reinterpret_cast<const TARGET &>(*this);
	}

	virtual idx_t MaxThreads(idx_t source_max_threads) {
		return source_max_threads;
	}
};

class LocalSinkState {
public:
	virtual ~LocalSinkState() {
	}

	//! Source partition info
	SourcePartitionInfo partition_info;

	template <class TARGET>
	TARGET &Cast() {
		DynamicCastCheck<TARGET>(this);
		return reinterpret_cast<TARGET &>(*this);
	}
	template <class TARGET>
	const TARGET &Cast() const {
		DynamicCastCheck<TARGET>(this);
		return reinterpret_cast<const TARGET &>(*this);
	}
};

class GlobalSourceState : public StateWithBlockableTasks {
public:
	virtual ~GlobalSourceState() {
	}

	virtual idx_t MaxThreads() {
		return 1;
	}

	template <class TARGET>
	TARGET &Cast() {
		DynamicCastCheck<TARGET>(this);
		return reinterpret_cast<TARGET &>(*this);
	}
	template <class TARGET>
	const TARGET &Cast() const {
		DynamicCastCheck<TARGET>(this);
		return reinterpret_cast<const TARGET &>(*this);
	}
};

class LocalSourceState {
public:
	virtual ~LocalSourceState() {
	}

	template <class TARGET>
	TARGET &Cast() {
		DynamicCastCheck<TARGET>(this);
		return reinterpret_cast<TARGET &>(*this);
	}
	template <class TARGET>
	const TARGET &Cast() const {
		DynamicCastCheck<TARGET>(this);
		return reinterpret_cast<const TARGET &>(*this);
	}
};

struct OperatorSinkInput {
	GlobalSinkState &global_state;
	LocalSinkState &local_state;
	InterruptState &interrupt_state;
};

struct OperatorSourceInput {
	GlobalSourceState &global_state;
	LocalSourceState &local_state;
	InterruptState &interrupt_state;
};

struct OperatorSinkCombineInput {
	GlobalSinkState &global_state;
	LocalSinkState &local_state;
	InterruptState &interrupt_state;
};

struct OperatorSinkFinalizeInput {
	GlobalSinkState &global_state;
	InterruptState &interrupt_state;
};

struct OperatorSinkNextBatchInput {
	GlobalSinkState &global_state;
	LocalSinkState &local_state;
	InterruptState &interrupt_state;
};

// LCOV_EXCL_STOP

} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// src/include/duckdb/common/enums/order_preservation_type.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

//===--------------------------------------------------------------------===//
// Order Preservation Type
//===--------------------------------------------------------------------===//
enum class OrderPreservationType : uint8_t {
	NO_ORDER,        // the operator makes no guarantees on order preservation (i.e. it might re-order the entire input)
	INSERTION_ORDER, // the operator maintains the order of the child operators
	FIXED_ORDER      // the operator outputs rows in a fixed order that must be maintained (e.g. ORDER BY)
};

} // namespace duckdb



namespace duckdb {
class Event;
class Executor;
class PhysicalOperator;
class Pipeline;
class PipelineBuildState;
class MetaPipeline;

//! PhysicalOperator is the base class of the physical operators present in the
//! execution plan
class PhysicalOperator {
public:
	static constexpr const PhysicalOperatorType TYPE = PhysicalOperatorType::INVALID;

public:
	PhysicalOperator(PhysicalOperatorType type, vector<LogicalType> types, idx_t estimated_cardinality)
	    : type(type), types(std::move(types)), estimated_cardinality(estimated_cardinality) {
	}

	virtual ~PhysicalOperator() {
	}

	//! The physical operator type
	PhysicalOperatorType type;
	//! The set of children of the operator
	vector<unique_ptr<PhysicalOperator>> children;
	//! The types returned by this physical operator
	vector<LogicalType> types;
	//! The estimated cardinality of this physical operator
	idx_t estimated_cardinality;

	//! The global sink state of this operator
	unique_ptr<GlobalSinkState> sink_state;
	//! The global state of this operator
	unique_ptr<GlobalOperatorState> op_state;
	//! Lock for (re)setting any of the operator states
	mutex lock;

public:
	virtual string GetName() const;
	virtual InsertionOrderPreservingMap<string> ParamsToString() const {
		return InsertionOrderPreservingMap<string>();
	}
	static void SetEstimatedCardinality(InsertionOrderPreservingMap<string> &result, idx_t estimated_cardinality);
	virtual string ToString(ExplainFormat format = ExplainFormat::DEFAULT) const;
	void Print() const;
	virtual vector<const_reference<PhysicalOperator>> GetChildren() const;

	//! Return a vector of the types that will be returned by this operator
	const vector<LogicalType> &GetTypes() const {
		return types;
	}

	virtual bool Equals(const PhysicalOperator &other) const {
		return false;
	}

	//! Functions to help decide how to set up pipeline dependencies
	idx_t EstimatedThreadCount() const;
	bool CanSaturateThreads(ClientContext &context) const;

	virtual void Verify();

public:
	// Operator interface
	virtual unique_ptr<OperatorState> GetOperatorState(ExecutionContext &context) const;
	virtual unique_ptr<GlobalOperatorState> GetGlobalOperatorState(ClientContext &context) const;
	virtual OperatorResultType Execute(ExecutionContext &context, DataChunk &input, DataChunk &chunk,
	                                   GlobalOperatorState &gstate, OperatorState &state) const;
	virtual OperatorFinalizeResultType FinalExecute(ExecutionContext &context, DataChunk &chunk,
	                                                GlobalOperatorState &gstate, OperatorState &state) const;

	virtual bool ParallelOperator() const {
		return false;
	}

	virtual bool RequiresFinalExecute() const {
		return false;
	}

	//! The influence the operator has on order (insertion order means no influence)
	virtual OrderPreservationType OperatorOrder() const {
		return OrderPreservationType::INSERTION_ORDER;
	}

public:
	// Source interface
	virtual unique_ptr<LocalSourceState> GetLocalSourceState(ExecutionContext &context,
	                                                         GlobalSourceState &gstate) const;
	virtual unique_ptr<GlobalSourceState> GetGlobalSourceState(ClientContext &context) const;
	virtual SourceResultType GetData(ExecutionContext &context, DataChunk &chunk, OperatorSourceInput &input) const;

	virtual idx_t GetBatchIndex(ExecutionContext &context, DataChunk &chunk, GlobalSourceState &gstate,
	                            LocalSourceState &lstate) const;

	virtual bool IsSource() const {
		return false;
	}

	virtual bool ParallelSource() const {
		return false;
	}

	virtual bool SupportsBatchIndex() const {
		return false;
	}

	//! The type of order emitted by the operator (as a source)
	virtual OrderPreservationType SourceOrder() const {
		return OrderPreservationType::INSERTION_ORDER;
	}

	//! Returns the current progress percentage, or a negative value if progress bars are not supported
	virtual double GetProgress(ClientContext &context, GlobalSourceState &gstate) const;

	//! Returns the current progress percentage, or a negative value if progress bars are not supported
	virtual double GetSinkProgress(ClientContext &context, GlobalSinkState &gstate, double source_progress) const {
		return source_progress;
	}

public:
	// Sink interface

	//! The sink method is called constantly with new input, as long as new input is available. Note that this method
	//! CAN be called in parallel, proper locking is needed when accessing dat
	//! a inside the GlobalSinkState.
	virtual SinkResultType Sink(ExecutionContext &context, DataChunk &chunk, OperatorSinkInput &input) const;
	//! The combine is called when a single thread has completed execution of its part of the pipeline, it is the final
	//! time that a specific LocalSinkState is accessible. This method can be called in parallel while other Sink() or
	//! Combine() calls are active on the same GlobalSinkState.
	virtual SinkCombineResultType Combine(ExecutionContext &context, OperatorSinkCombineInput &input) const;
	//! (optional) function that will be called before Finalize
	//! For now, its only use is to to communicate memory usage in multi-join pipelines through TemporaryMemoryManager
	virtual void PrepareFinalize(ClientContext &context, GlobalSinkState &sink_state) const;
	//! The finalize is called when ALL threads are finished execution. It is called only once per pipeline, and is
	//! entirely single threaded.
	//! If Finalize returns SinkResultType::FINISHED, the sink is marked as finished
	virtual SinkFinalizeType Finalize(Pipeline &pipeline, Event &event, ClientContext &context,
	                                  OperatorSinkFinalizeInput &input) const;
	//! For sinks with RequiresBatchIndex set to true, when a new batch starts being processed this method is called
	//! This allows flushing of the current batch (e.g. to disk)
	virtual SinkNextBatchType NextBatch(ExecutionContext &context, OperatorSinkNextBatchInput &input) const;

	virtual unique_ptr<LocalSinkState> GetLocalSinkState(ExecutionContext &context) const;
	virtual unique_ptr<GlobalSinkState> GetGlobalSinkState(ClientContext &context) const;

	//! The maximum amount of memory the operator should use per thread.
	static idx_t GetMaxThreadMemory(ClientContext &context);

	//! Whether operator caching is allowed in the current execution context
	static bool OperatorCachingAllowed(ExecutionContext &context);

	virtual bool IsSink() const {
		return false;
	}

	virtual bool ParallelSink() const {
		return false;
	}

	virtual bool RequiresBatchIndex() const {
		return false;
	}

	//! Whether or not the sink operator depends on the order of the input chunks
	//! If this is set to true, we cannot do things like caching intermediate vectors
	virtual bool SinkOrderDependent() const {
		return false;
	}

public:
	// Pipeline construction
	virtual vector<const_reference<PhysicalOperator>> GetSources() const;
	bool AllSourcesSupportBatchIndex() const;

	virtual void BuildPipelines(Pipeline &current, MetaPipeline &meta_pipeline);

public:
	template <class TARGET>
	TARGET &Cast() {
		if (TARGET::TYPE != PhysicalOperatorType::INVALID && type != TARGET::TYPE) {
			throw InternalException("Failed to cast physical operator to type - physical operator type mismatch");
		}
		return reinterpret_cast<TARGET &>(*this);
	}

	template <class TARGET>
	const TARGET &Cast() const {
		if (TARGET::TYPE != PhysicalOperatorType::INVALID && type != TARGET::TYPE) {
			throw InternalException("Failed to cast physical operator to type - physical operator type mismatch");
		}
		return reinterpret_cast<const TARGET &>(*this);
	}
};

//! Contains state for the CachingPhysicalOperator
class CachingOperatorState : public OperatorState {
public:
	~CachingOperatorState() override {
	}

	void Finalize(const PhysicalOperator &op, ExecutionContext &context) override {
	}

	unique_ptr<DataChunk> cached_chunk;
	bool initialized = false;
	//! Whether or not the chunk can be cached
	bool can_cache_chunk = false;
};

//! Base class that caches output from child Operator class. Note that Operators inheriting from this class should also
//! inherit their state class from the CachingOperatorState.
class CachingPhysicalOperator : public PhysicalOperator {
public:
	static constexpr const idx_t CACHE_THRESHOLD = 64;
	CachingPhysicalOperator(PhysicalOperatorType type, vector<LogicalType> types, idx_t estimated_cardinality);

	bool caching_supported;

public:
	OperatorResultType Execute(ExecutionContext &context, DataChunk &input, DataChunk &chunk,
	                           GlobalOperatorState &gstate, OperatorState &state) const final;
	OperatorFinalizeResultType FinalExecute(ExecutionContext &context, DataChunk &chunk, GlobalOperatorState &gstate,
	                                        OperatorState &state) const final;

	bool RequiresFinalExecute() const final {
		return caching_supported;
	}

protected:
	//! Child classes need to implement the ExecuteInternal method instead of the Execute
	virtual OperatorResultType ExecuteInternal(ExecutionContext &context, DataChunk &input, DataChunk &chunk,
	                                           GlobalOperatorState &gstate, OperatorState &state) const = 0;

private:
	bool CanCacheType(const LogicalType &type);
};

} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/function/table_function.hpp
//
//
//===----------------------------------------------------------------------===//







//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/bind_context.hpp
//
//
//===----------------------------------------------------------------------===//






//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/exception/binder_exception.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

class BinderException : public Exception {
public:
	DUCKDB_API explicit BinderException(const string &msg, const unordered_map<string, string> &extra_info);
	DUCKDB_API explicit BinderException(const string &msg);

	template <typename... ARGS>
	explicit BinderException(const string &msg, ARGS... params) : BinderException(ConstructMessage(msg, params...)) {
	}
	template <typename... ARGS>
	explicit BinderException(const TableRef &ref, const string &msg, ARGS... params)
	    : BinderException(ConstructMessage(msg, params...), Exception::InitializeExtraInfo(ref)) {
	}
	template <typename... ARGS>
	explicit BinderException(const ParsedExpression &expr, const string &msg, ARGS... params)
	    : BinderException(ConstructMessage(msg, params...), Exception::InitializeExtraInfo(expr)) {
	}
	template <typename... ARGS>
	explicit BinderException(const Expression &expr, const string &msg, ARGS... params)
	    : BinderException(ConstructMessage(msg, params...), Exception::InitializeExtraInfo(expr)) {
	}
	template <typename... ARGS>
	explicit BinderException(QueryErrorContext error_context, const string &msg, ARGS... params)
	    : BinderException(ConstructMessage(msg, params...), Exception::InitializeExtraInfo(error_context)) {
	}
	template <typename... ARGS>
	explicit BinderException(optional_idx error_location, const string &msg, ARGS... params)
	    : BinderException(ConstructMessage(msg, params...), Exception::InitializeExtraInfo(error_location)) {
	}

	static BinderException ColumnNotFound(const string &name, const vector<string> &similar_bindings,
	                                      QueryErrorContext context = QueryErrorContext());
	static BinderException NoMatchingFunction(const string &name, const vector<LogicalType> &arguments,
	                                          const vector<string> &candidates);
	static BinderException Unsupported(ParsedExpression &expr, const string &message);
};

} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/parser/expression/columnref_expression.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

//! Represents a reference to a column from either the FROM clause or from an
//! alias
class ColumnRefExpression : public ParsedExpression {
public:
	static constexpr const ExpressionClass TYPE = ExpressionClass::COLUMN_REF;

public:
	//! Specify both the column and table name
	ColumnRefExpression(string column_name, string table_name);
	//! Only specify the column name, the table name will be derived later
	explicit ColumnRefExpression(string column_name);
	//! Specify a set of names
	explicit ColumnRefExpression(vector<string> column_names);

	//! The stack of names in order of which they appear (column_names[0].column_names[1].column_names[2]....)
	vector<string> column_names;

public:
	bool IsQualified() const;
	const string &GetColumnName() const;
	const string &GetTableName() const;
	bool IsScalar() const override {
		return false;
	}

	string GetName() const override;
	string ToString() const override;

	static bool Equal(const ColumnRefExpression &a, const ColumnRefExpression &b);
	hash_t Hash() const override;

	unique_ptr<ParsedExpression> Copy() const override;

	void Serialize(Serializer &serializer) const override;
	static unique_ptr<ParsedExpression> Deserialize(Deserializer &deserializer);

private:
	ColumnRefExpression();
};
} // namespace duckdb


//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/parser/qualified_name_set.hpp
//
//
//===----------------------------------------------------------------------===//







namespace duckdb {

struct QualifiedColumnHashFunction {
	uint64_t operator()(const QualifiedColumnName &a) const {
		std::hash<std::string> str_hasher;
		return str_hasher(a.schema) ^ str_hasher(a.table) ^ str_hasher(a.column);
	}
};

struct QualifiedColumnEquality {
	bool operator()(const QualifiedColumnName &a, const QualifiedColumnName &b) const {
		return a.schema == b.schema && a.table == b.table && a.column == b.column;
	}
};

using qualified_column_set_t = unordered_set<QualifiedColumnName, QualifiedColumnHashFunction, QualifiedColumnEquality>;

} // namespace duckdb


//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/expression_binder.hpp
//
//
//===----------------------------------------------------------------------===//




//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/stack_checker.hpp
//
//
//===----------------------------------------------------------------------===//



namespace duckdb {

template <class RECURSIVE_CLASS>
class StackChecker {
public:
	StackChecker(RECURSIVE_CLASS &recursive_class_p, idx_t stack_usage_p)
	    : recursive_class(recursive_class_p), stack_usage(stack_usage_p) {
		recursive_class.stack_depth += stack_usage;
	}
	~StackChecker() {
		recursive_class.stack_depth -= stack_usage;
	}
	StackChecker(StackChecker &&other) noexcept
	    : recursive_class(other.recursive_class), stack_usage(other.stack_usage) {
		other.stack_usage = 0;
	}
	StackChecker(const StackChecker &) = delete;

private:
	RECURSIVE_CLASS &recursive_class;
	idx_t stack_usage;
};

} // namespace duckdb




//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/parser/expression/bound_expression.hpp
//
//
//===----------------------------------------------------------------------===//







namespace duckdb {

//! BoundExpression is an intermediate dummy class used by the binder. It is a ParsedExpression but holds an Expression.
//! It represents a successfully bound expression. It is used in the Binder to prevent re-binding of already bound parts
//! when dealing with subqueries.
class BoundExpression : public ParsedExpression {
public:
	static constexpr const ExpressionClass TYPE = ExpressionClass::BOUND_EXPRESSION;

public:
	explicit BoundExpression(unique_ptr<Expression> expr);

	unique_ptr<Expression> expr;

public:
	static unique_ptr<Expression> &GetExpression(ParsedExpression &expr);

	string ToString() const override;

	bool Equals(const BaseExpression &other) const override;
	hash_t Hash() const override;

	unique_ptr<ParsedExpression> Copy() const override;

	void Serialize(Serializer &serializer) const override;
};

} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/parser/expression/lambdaref_expression.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

struct DummyBinding;

//! Represents a reference to a lambda parameter
class LambdaRefExpression : public ParsedExpression {
public:
	static constexpr const ExpressionClass TYPE = ExpressionClass::LAMBDA_REF;

public:
	//! Constructs a LambdaRefExpression from a lambda_idx and a column_name. We do not specify a table name,
	//! because we use dummy tables to bind lambda parameters
	LambdaRefExpression(idx_t lambda_idx, string column_name_p);

	//! The index of the lambda parameter in the lambda_bindings vector
	idx_t lambda_idx;
	//! The name of the lambda parameter (in a specific Binding in lambda_bindings)
	string column_name;

public:
	bool IsScalar() const override;
	string GetName() const override;
	string ToString() const override;
	hash_t Hash() const override;
	unique_ptr<ParsedExpression> Copy() const override;

	//! Traverses the lambda_bindings to find a matching binding for the column_name
	static unique_ptr<ParsedExpression> FindMatchingBinding(optional_ptr<vector<DummyBinding>> &lambda_bindings,
	                                                        const string &parameter_name);

	void Serialize(Serializer &serializer) const override;
	static unique_ptr<ParsedExpression> Deserialize(Deserializer &deserializer);
};
} // namespace duckdb


//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/parser/tokens.hpp
//
//
//===----------------------------------------------------------------------===//



namespace duckdb {

//===--------------------------------------------------------------------===//
// Statements
//===--------------------------------------------------------------------===//
class SQLStatement;

class AlterStatement;
class AttachStatement;
class CallStatement;
class CopyStatement;
class CreateStatement;
class DetachStatement;
class DeleteStatement;
class DropStatement;
class ExtensionStatement;
class InsertStatement;
class SelectStatement;
class TransactionStatement;
class UpdateStatement;
class UpdateExtensionsStatement;
class PrepareStatement;
class ExecuteStatement;
class PragmaStatement;
class ExplainStatement;
class ExportStatement;
class VacuumStatement;
class RelationStatement;
class SetStatement;
class SetVariableStatement;
class ResetVariableStatement;
class LoadStatement;
class LogicalPlanStatement;
class MultiStatement;
class CopyDatabaseStatement;

//===--------------------------------------------------------------------===//
// Query Node
//===--------------------------------------------------------------------===//
class QueryNode;
class SelectNode;
class SetOperationNode;
class RecursiveCTENode;
class CTENode;

//===--------------------------------------------------------------------===//
// Expressions
//===--------------------------------------------------------------------===//
class ParsedExpression;

class BetweenExpression;
class CaseExpression;
class CastExpression;
class CollateExpression;
class ColumnRefExpression;
class ComparisonExpression;
class ConjunctionExpression;
class ConstantExpression;
class DefaultExpression;
class FunctionExpression;
class LambdaExpression;
class OperatorExpression;
class ParameterExpression;
class PositionalReferenceExpression;
class StarExpression;
class SubqueryExpression;
class WindowExpression;

//===--------------------------------------------------------------------===//
// Constraints
//===--------------------------------------------------------------------===//
class Constraint;

class NotNullConstraint;
class CheckConstraint;
class UniqueConstraint;
class ForeignKeyConstraint;

//===--------------------------------------------------------------------===//
// TableRefs
//===--------------------------------------------------------------------===//
class TableRef;

class BaseTableRef;
class JoinRef;
class SubqueryRef;
class TableFunctionRef;
class EmptyTableRef;
class ExpressionListRef;
class ColumnDataRef;
class PivotRef;
class ShowRef;

//===--------------------------------------------------------------------===//
// Other
//===--------------------------------------------------------------------===//
struct SampleOptions;

} // namespace duckdb




#include <functional>




//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/catalog/catalog_entry/schema_catalog_entry.hpp
//
//
//===----------------------------------------------------------------------===//




//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/catalog/catalog_set.hpp
//
//
//===----------------------------------------------------------------------===//




//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/catalog/default/default_generator.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {
class ClientContext;

class DefaultGenerator {
public:
	explicit DefaultGenerator(Catalog &catalog);
	virtual ~DefaultGenerator();

	Catalog &catalog;
	atomic<bool> created_all_entries;

public:
	//! Creates a default entry with the specified name, or returns nullptr if no such entry can be generated
	virtual unique_ptr<CatalogEntry> CreateDefaultEntry(ClientContext &context, const string &entry_name);
	virtual unique_ptr<CatalogEntry> CreateDefaultEntry(CatalogTransaction transaction, const string &entry_name);
	//! Get a list of all default entries in the generator
	virtual vector<string> GetDefaultEntries() = 0;
};

} // namespace duckdb







//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/transaction/transaction.hpp
//
//
//===----------------------------------------------------------------------===//



//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/catalog/catalog_entry/sequence_catalog_entry.hpp
//
//
//===----------------------------------------------------------------------===//



//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/catalog/standard_entry.hpp
//
//
//===----------------------------------------------------------------------===//




//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/catalog/dependency_list.hpp
//
//
//===----------------------------------------------------------------------===//



//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/catalog/catalog_entry_map.hpp
//
//
//===----------------------------------------------------------------------===//







namespace duckdb {
class CatalogEntry;

struct CatalogEntryHashFunction {
	uint64_t operator()(const reference<CatalogEntry> &a) const {
		std::hash<void *> hash_func;
		return hash_func((void *)&a.get());
	}
};

struct CatalogEntryEquality {
	bool operator()(const reference<CatalogEntry> &a, const reference<CatalogEntry> &b) const {
		return RefersToSameObject(a, b);
	}
};

using catalog_entry_set_t = unordered_set<reference<CatalogEntry>, CatalogEntryHashFunction, CatalogEntryEquality>;

template <typename T>
using catalog_entry_map_t = unordered_map<reference<CatalogEntry>, T, CatalogEntryHashFunction, CatalogEntryEquality>;

using catalog_entry_vector_t = vector<reference<CatalogEntry>>;

} // namespace duckdb



//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/catalog/dependency.hpp
//
//
//===----------------------------------------------------------------------===//







namespace duckdb {
class CatalogEntry;

struct DependencyFlags {
public:
	DependencyFlags() : value(0) {
	}
	DependencyFlags(const DependencyFlags &other) : value(other.value) {
	}
	virtual ~DependencyFlags() = default;
	DependencyFlags &operator=(const DependencyFlags &other) {
		value = other.value;
		return *this;
	}
	bool operator==(const DependencyFlags &other) const {
		return other.value == value;
	}
	bool operator!=(const DependencyFlags &other) const {
		return !(*this == other);
	}

public:
	virtual string ToString() const = 0;

protected:
	template <uint8_t BIT>
	bool IsSet() const {
		static const uint8_t FLAG = (1 << BIT);
		return (value & FLAG) == FLAG;
	}
	template <uint8_t BIT>
	void Set() {
		static const uint8_t FLAG = (1 << BIT);
		value |= FLAG;
	}
	void Merge(uint8_t other) {
		value |= other;
	}
	uint8_t Value() {
		return value;
	}

private:
	uint8_t value;
};

struct DependencySubjectFlags : public DependencyFlags {
private:
	static constexpr uint8_t OWNERSHIP = 0;

public:
	DependencySubjectFlags &Apply(DependencySubjectFlags other) {
		Merge(other.Value());
		return *this;
	}

public:
	bool IsOwnership() const {
		return IsSet<OWNERSHIP>();
	}

public:
	DependencySubjectFlags &SetOwnership() {
		Set<OWNERSHIP>();
		return *this;
	}

public:
	string ToString() const override {
		string result;
		if (IsOwnership()) {
			result += "OWNS";
		}
		return result;
	}
};

struct DependencyDependentFlags : public DependencyFlags {
private:
	static constexpr uint8_t BLOCKING = 0;
	static constexpr uint8_t OWNED_BY = 1;

public:
	DependencyDependentFlags &Apply(DependencyDependentFlags other) {
		Merge(other.Value());
		return *this;
	}

public:
	bool IsBlocking() const {
		return IsSet<BLOCKING>();
	}
	bool IsOwnedBy() const {
		return IsSet<OWNED_BY>();
	}

public:
	DependencyDependentFlags &SetBlocking() {
		Set<BLOCKING>();
		return *this;
	}
	DependencyDependentFlags &SetOwnedBy() {
		Set<OWNED_BY>();
		return *this;
	}

public:
	string ToString() const override {
		string result;
		if (IsBlocking()) {
			result += "REGULAR";
		} else {
			result += "AUTOMATIC";
		}
		result += " | ";
		if (IsOwnedBy()) {
			result += "OWNED BY";
		}
		return result;
	}
};

struct CatalogEntryInfo {
public:
	CatalogType type;
	string schema;
	string name;

public:
	bool operator==(const CatalogEntryInfo &other) const {
		if (other.type != type) {
			return false;
		}
		if (!StringUtil::CIEquals(other.schema, schema)) {
			return false;
		}
		if (!StringUtil::CIEquals(other.name, name)) {
			return false;
		}
		return true;
	}

public:
	void Serialize(Serializer &serializer) const;
	static CatalogEntryInfo Deserialize(Deserializer &deserializer);
};

struct Dependency {
	Dependency(CatalogEntry &entry, // NOLINT: Allow implicit conversion from `CatalogEntry`
	           DependencyDependentFlags flags = DependencyDependentFlags().SetBlocking())
	    : entry(entry), flags(std::move(flags)) {
	}

	//! The catalog entry this depends on
	reference<CatalogEntry> entry;
	//! The type of dependency
	DependencyDependentFlags flags;
};

struct DependencyHashFunction {
	uint64_t operator()(const Dependency &a) const {
		std::hash<void *> hash_func;
		return hash_func((void *)&a.entry.get());
	}
};

struct DependencyEquality {
	bool operator()(const Dependency &a, const Dependency &b) const {
		return RefersToSameObject(a.entry, b.entry);
	}
};
using dependency_set_t = unordered_set<Dependency, DependencyHashFunction, DependencyEquality>;

} // namespace duckdb


namespace duckdb {
class Catalog;
class CatalogEntry;
struct CreateInfo;
class SchemaCatalogEntry;
struct CatalogTransaction;
class LogicalDependencyList;

//! A minimal representation of a CreateInfo / CatalogEntry
//! enough to look up the entry inside SchemaCatalogEntry::GetEntry
struct LogicalDependency {
public:
	CatalogEntryInfo entry;
	string catalog;

public:
	explicit LogicalDependency(CatalogEntry &entry);
	LogicalDependency();
	bool operator==(const LogicalDependency &other) const;

public:
	void Serialize(Serializer &serializer) const;
	static LogicalDependency Deserialize(Deserializer &deserializer);
};

struct LogicalDependencyHashFunction {
	uint64_t operator()(const LogicalDependency &a) const;
};

struct LogicalDependencyEquality {
	bool operator()(const LogicalDependency &a, const LogicalDependency &b) const;
};

//! The LogicalDependencyList containing LogicalDependency objects, not looked up in the catalog yet
class LogicalDependencyList {
	using create_info_set_t =
	    unordered_set<LogicalDependency, LogicalDependencyHashFunction, LogicalDependencyEquality>;

public:
	DUCKDB_API void AddDependency(CatalogEntry &entry);
	DUCKDB_API void AddDependency(const LogicalDependency &entry);
	DUCKDB_API bool Contains(CatalogEntry &entry);

public:
	DUCKDB_API void VerifyDependencies(Catalog &catalog, const string &name);
	void Serialize(Serializer &serializer) const;
	static LogicalDependencyList Deserialize(Deserializer &deserializer);
	bool operator==(const LogicalDependencyList &other) const;
	const create_info_set_t &Set() const;

private:
	create_info_set_t set;
};

} // namespace duckdb


namespace duckdb {
class SchemaCatalogEntry;

//! A StandardEntry is a catalog entry that is a member of a schema
class StandardEntry : public InCatalogEntry {
public:
	StandardEntry(CatalogType type, SchemaCatalogEntry &schema, Catalog &catalog, string name)
	    : InCatalogEntry(type, catalog, std::move(name)), schema(schema) {
	}
	~StandardEntry() override {
	}

	//! The schema the entry belongs to
	SchemaCatalogEntry &schema;
	//! The dependencies of the entry, can be empty
	LogicalDependencyList dependencies;

public:
	SchemaCatalogEntry &ParentSchema() override {
		return schema;
	}
	const SchemaCatalogEntry &ParentSchema() const override {
		return schema;
	}
};

} // namespace duckdb


//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/parser/parsed_data/create_sequence_info.hpp
//
//
//===----------------------------------------------------------------------===//



//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/parser/parsed_data/create_info.hpp
//
//
//===----------------------------------------------------------------------===//




//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/parser/parsed_data/parse_info.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

enum class CatalogType : uint8_t;

enum class ParseInfoType : uint8_t {
	ALTER_INFO,
	ATTACH_INFO,
	COPY_INFO,
	CREATE_INFO,
	CREATE_SECRET_INFO,
	DETACH_INFO,
	DROP_INFO,
	BOUND_EXPORT_DATA,
	LOAD_INFO,
	PRAGMA_INFO,
	SHOW_SELECT_INFO,
	TRANSACTION_INFO,
	VACUUM_INFO,
	COMMENT_ON_INFO,
	COMMENT_ON_COLUMN_INFO,
	COPY_DATABASE_INFO,
	UPDATE_EXTENSIONS_INFO
};

struct ParseInfo {
	explicit ParseInfo(ParseInfoType info_type) : info_type(info_type) {
	}
	virtual ~ParseInfo() {
	}

	ParseInfoType info_type;

public:
	template <class TARGET>
	TARGET &Cast() {
		DynamicCastCheck<TARGET>(this);
		return reinterpret_cast<TARGET &>(*this);
	}

	template <class TARGET>
	const TARGET &Cast() const {
		DynamicCastCheck<TARGET>(this);
		return reinterpret_cast<const TARGET &>(*this);
	}

	virtual void Serialize(Serializer &serializer) const;
	static unique_ptr<ParseInfo> Deserialize(Deserializer &deserializer);
	static string QualifierToString(const string &catalog, const string &schema, const string &name);
	static string TypeToString(CatalogType type);
};

} // namespace duckdb

//-------------------------------------------------------------------------
// This file is automatically generated by scripts/generate_enum_util.py
// Do not edit this file manually, your changes will be overwritten
// If you want to exclude an enum from serialization, add it to the blacklist in the script
//
// Note: The generated code will only work properly if the enum is a top level item in the duckdb namespace
// If the enum is nested in a class, or in another namespace, the generated code will not compile.
// You should move the enum to the duckdb namespace, manually write a specialization or add it to the blacklist
//-------------------------------------------------------------------------




#include <stdint.h>


namespace duckdb {

struct EnumUtil {
    // String -> Enum
    template <class T>
    static T FromString(const char *value) = delete;

    template <class T>
    static T FromString(const string &value) { return FromString<T>(value.c_str()); }

    // Enum -> String
    template <class T>
    static const char *ToChars(T value) = delete;

    template <class T>
    static string ToString(T value) { return string(ToChars<T>(value)); }
};

enum class AccessMode : uint8_t;

enum class AggregateCombineType : uint8_t;

enum class AggregateHandling : uint8_t;

enum class AggregateOrderDependent : uint8_t;

enum class AggregateType : uint8_t;

enum class AlterForeignKeyType : uint8_t;

enum class AlterScalarFunctionType : uint8_t;

enum class AlterTableFunctionType : uint8_t;

enum class AlterTableType : uint8_t;

enum class AlterType : uint8_t;

enum class AlterViewType : uint8_t;

enum class AppenderType : uint8_t;

enum class ArrowDateTimeType : uint8_t;

enum class ArrowOffsetSize : uint8_t;

enum class ArrowTypeInfoType : uint8_t;

enum class ArrowVariableSizeType : uint8_t;

enum class BinderType : uint8_t;

enum class BindingMode : uint8_t;

enum class BitpackingMode : uint8_t;

enum class BlockState : uint8_t;

enum class CAPIResultSetType : uint8_t;

enum class CSVState : uint8_t;

enum class CTEMaterialize : uint8_t;

enum class CatalogLookupBehavior : uint8_t;

enum class CatalogType : uint8_t;

enum class CheckpointAbort : uint8_t;

enum class ChunkInfoType : uint8_t;

enum class ColumnDataAllocatorType : uint8_t;

enum class ColumnDataScanProperties : uint8_t;

enum class ColumnSegmentType : uint8_t;

enum class CompressedMaterializationDirection : uint8_t;

enum class CompressionType : uint8_t;

enum class ConflictManagerMode : uint8_t;

enum class ConstraintType : uint8_t;

enum class CopyFunctionReturnType : uint8_t;

enum class CopyOverwriteMode : uint8_t;

enum class CopyToType : uint8_t;

enum class DataFileType : uint8_t;

enum class DatePartSpecifier : uint8_t;

enum class DebugInitialize : uint8_t;

enum class DefaultOrderByNullType : uint8_t;

enum class DependencyEntryType : uint8_t;

enum class DeprecatedIndexType : uint8_t;

enum class DestroyBufferUpon : uint8_t;

enum class DistinctType : uint8_t;

enum class ErrorType : uint16_t;

enum class ExceptionFormatValueType : uint8_t;

enum class ExceptionType : uint8_t;

enum class ExplainFormat : uint8_t;

enum class ExplainOutputType : uint8_t;

enum class ExplainType : uint8_t;

enum class ExponentType : uint8_t;

enum class ExpressionClass : uint8_t;

enum class ExpressionType : uint8_t;

enum class ExtensionABIType : uint8_t;

enum class ExtensionInstallMode : uint8_t;

enum class ExtensionLoadResult : uint8_t;

enum class ExtensionUpdateResultTag : uint8_t;

enum class ExtraDropInfoType : uint8_t;

enum class ExtraTypeInfoType : uint8_t;

enum class FileBufferType : uint8_t;

enum class FileCompressionType : uint8_t;

enum class FileExpandResult : uint8_t;

enum class FileGlobOptions : uint8_t;

enum class FileLockType : uint8_t;

enum class FilterPropagateResult : uint8_t;

enum class ForeignKeyType : uint8_t;

enum class FunctionNullHandling : uint8_t;

enum class FunctionStability : uint8_t;

enum class GateStatus : uint8_t;

enum class HLLStorageType : uint8_t;

enum class IndexConstraintType : uint8_t;

enum class InsertColumnOrder : uint8_t;

enum class InterruptMode : uint8_t;

enum class JoinRefType : uint8_t;

enum class JoinType : uint8_t;

enum class KeywordCategory : uint8_t;

enum class LimitNodeType : uint8_t;

enum class LoadType : uint8_t;

enum class LogicalOperatorType : uint8_t;

enum class LogicalTypeId : uint8_t;

enum class LookupResultType : uint8_t;

enum class MacroType : uint8_t;

enum class MapInvalidReason : uint8_t;

enum class MemoryTag : uint8_t;

enum class MetaPipelineType : uint8_t;

enum class MetricsType : uint8_t;

enum class NType : uint8_t;

enum class NewLineIdentifier : uint8_t;

enum class OnConflictAction : uint8_t;

enum class OnCreateConflict : uint8_t;

enum class OnEntryNotFound : uint8_t;

enum class OperatorFinalizeResultType : uint8_t;

enum class OperatorResultType : uint8_t;

enum class OptimizerType : uint32_t;

enum class OrderByNullType : uint8_t;

enum class OrderPreservationType : uint8_t;

enum class OrderType : uint8_t;

enum class OutputStream : uint8_t;

enum class ParseInfoType : uint8_t;

enum class ParserExtensionResultType : uint8_t;

enum class PartitionSortStage : uint8_t;

enum class PartitionedColumnDataType : uint8_t;

enum class PartitionedTupleDataType : uint8_t;

enum class PendingExecutionResult : uint8_t;

enum class PhysicalOperatorType : uint8_t;

enum class PhysicalType : uint8_t;

enum class PragmaType : uint8_t;

enum class PreparedParamType : uint8_t;

enum class PreparedStatementMode : uint8_t;

enum class ProfilerPrintFormat : uint8_t;

enum class QuantileSerializationType : uint8_t;

enum class QueryNodeType : uint8_t;

enum class QueryResultType : uint8_t;

enum class QuoteRule : uint8_t;

enum class RelationType : uint8_t;

enum class RenderMode : uint8_t;

enum class ResultModifierType : uint8_t;

enum class SampleMethod : uint8_t;

enum class SampleType : uint8_t;

enum class ScanType : uint8_t;

enum class SecretDisplayType : uint8_t;

enum class SecretPersistType : uint8_t;

enum class SequenceInfo : uint8_t;

enum class SetOperationType : uint8_t;

enum class SetScope : uint8_t;

enum class SetType : uint8_t;

enum class SettingScope : uint8_t;

enum class ShowType : uint8_t;

enum class SimplifiedTokenType : uint8_t;

enum class SinkCombineResultType : uint8_t;

enum class SinkFinalizeType : uint8_t;

enum class SinkNextBatchType : uint8_t;

enum class SinkResultType : uint8_t;

enum class SourceResultType : uint8_t;

enum class StatementReturnType : uint8_t;

enum class StatementType : uint8_t;

enum class StatisticsType : uint8_t;

enum class StatsInfo : uint8_t;

enum class StrTimeSpecifier : uint8_t;

enum class StreamExecutionResult : uint8_t;

enum class SubqueryType : uint8_t;

enum class TableColumnType : uint8_t;

enum class TableFilterType : uint8_t;

enum class TableReferenceType : uint8_t;

enum class TableScanType : uint8_t;

enum class TaskExecutionMode : uint8_t;

enum class TaskExecutionResult : uint8_t;

enum class TimestampCastResult : uint8_t;

enum class TransactionModifierType : uint8_t;

enum class TransactionType : uint8_t;

enum class TupleDataPinProperties : uint8_t;

enum class UndoFlags : uint32_t;

enum class UnionInvalidReason : uint8_t;

enum class VectorAuxiliaryDataType : uint8_t;

enum class VectorBufferType : uint8_t;

enum class VectorType : uint8_t;

enum class VerificationType : uint8_t;

enum class VerifyExistenceType : uint8_t;

enum class WALType : uint8_t;

enum class WindowAggregationMode : uint32_t;

enum class WindowBoundary : uint8_t;

enum class WindowExcludeMode : uint8_t;


template<>
const char* EnumUtil::ToChars<AccessMode>(AccessMode value);

template<>
const char* EnumUtil::ToChars<AggregateCombineType>(AggregateCombineType value);

template<>
const char* EnumUtil::ToChars<AggregateHandling>(AggregateHandling value);

template<>
const char* EnumUtil::ToChars<AggregateOrderDependent>(AggregateOrderDependent value);

template<>
const char* EnumUtil::ToChars<AggregateType>(AggregateType value);

template<>
const char* EnumUtil::ToChars<AlterForeignKeyType>(AlterForeignKeyType value);

template<>
const char* EnumUtil::ToChars<AlterScalarFunctionType>(AlterScalarFunctionType value);

template<>
const char* EnumUtil::ToChars<AlterTableFunctionType>(AlterTableFunctionType value);

template<>
const char* EnumUtil::ToChars<AlterTableType>(AlterTableType value);

template<>
const char* EnumUtil::ToChars<AlterType>(AlterType value);

template<>
const char* EnumUtil::ToChars<AlterViewType>(AlterViewType value);

template<>
const char* EnumUtil::ToChars<AppenderType>(AppenderType value);

template<>
const char* EnumUtil::ToChars<ArrowDateTimeType>(ArrowDateTimeType value);

template<>
const char* EnumUtil::ToChars<ArrowOffsetSize>(ArrowOffsetSize value);

template<>
const char* EnumUtil::ToChars<ArrowTypeInfoType>(ArrowTypeInfoType value);

template<>
const char* EnumUtil::ToChars<ArrowVariableSizeType>(ArrowVariableSizeType value);

template<>
const char* EnumUtil::ToChars<BinderType>(BinderType value);

template<>
const char* EnumUtil::ToChars<BindingMode>(BindingMode value);

template<>
const char* EnumUtil::ToChars<BitpackingMode>(BitpackingMode value);

template<>
const char* EnumUtil::ToChars<BlockState>(BlockState value);

template<>
const char* EnumUtil::ToChars<CAPIResultSetType>(CAPIResultSetType value);

template<>
const char* EnumUtil::ToChars<CSVState>(CSVState value);

template<>
const char* EnumUtil::ToChars<CTEMaterialize>(CTEMaterialize value);

template<>
const char* EnumUtil::ToChars<CatalogLookupBehavior>(CatalogLookupBehavior value);

template<>
const char* EnumUtil::ToChars<CatalogType>(CatalogType value);

template<>
const char* EnumUtil::ToChars<CheckpointAbort>(CheckpointAbort value);

template<>
const char* EnumUtil::ToChars<ChunkInfoType>(ChunkInfoType value);

template<>
const char* EnumUtil::ToChars<ColumnDataAllocatorType>(ColumnDataAllocatorType value);

template<>
const char* EnumUtil::ToChars<ColumnDataScanProperties>(ColumnDataScanProperties value);

template<>
const char* EnumUtil::ToChars<ColumnSegmentType>(ColumnSegmentType value);

template<>
const char* EnumUtil::ToChars<CompressedMaterializationDirection>(CompressedMaterializationDirection value);

template<>
const char* EnumUtil::ToChars<CompressionType>(CompressionType value);

template<>
const char* EnumUtil::ToChars<ConflictManagerMode>(ConflictManagerMode value);

template<>
const char* EnumUtil::ToChars<ConstraintType>(ConstraintType value);

template<>
const char* EnumUtil::ToChars<CopyFunctionReturnType>(CopyFunctionReturnType value);

template<>
const char* EnumUtil::ToChars<CopyOverwriteMode>(CopyOverwriteMode value);

template<>
const char* EnumUtil::ToChars<CopyToType>(CopyToType value);

template<>
const char* EnumUtil::ToChars<DataFileType>(DataFileType value);

template<>
const char* EnumUtil::ToChars<DatePartSpecifier>(DatePartSpecifier value);

template<>
const char* EnumUtil::ToChars<DebugInitialize>(DebugInitialize value);

template<>
const char* EnumUtil::ToChars<DefaultOrderByNullType>(DefaultOrderByNullType value);

template<>
const char* EnumUtil::ToChars<DependencyEntryType>(DependencyEntryType value);

template<>
const char* EnumUtil::ToChars<DeprecatedIndexType>(DeprecatedIndexType value);

template<>
const char* EnumUtil::ToChars<DestroyBufferUpon>(DestroyBufferUpon value);

template<>
const char* EnumUtil::ToChars<DistinctType>(DistinctType value);

template<>
const char* EnumUtil::ToChars<ErrorType>(ErrorType value);

template<>
const char* EnumUtil::ToChars<ExceptionFormatValueType>(ExceptionFormatValueType value);

template<>
const char* EnumUtil::ToChars<ExceptionType>(ExceptionType value);

template<>
const char* EnumUtil::ToChars<ExplainFormat>(ExplainFormat value);

template<>
const char* EnumUtil::ToChars<ExplainOutputType>(ExplainOutputType value);

template<>
const char* EnumUtil::ToChars<ExplainType>(ExplainType value);

template<>
const char* EnumUtil::ToChars<ExponentType>(ExponentType value);

template<>
const char* EnumUtil::ToChars<ExpressionClass>(ExpressionClass value);

template<>
const char* EnumUtil::ToChars<ExpressionType>(ExpressionType value);

template<>
const char* EnumUtil::ToChars<ExtensionABIType>(ExtensionABIType value);

template<>
const char* EnumUtil::ToChars<ExtensionInstallMode>(ExtensionInstallMode value);

template<>
const char* EnumUtil::ToChars<ExtensionLoadResult>(ExtensionLoadResult value);

template<>
const char* EnumUtil::ToChars<ExtensionUpdateResultTag>(ExtensionUpdateResultTag value);

template<>
const char* EnumUtil::ToChars<ExtraDropInfoType>(ExtraDropInfoType value);

template<>
const char* EnumUtil::ToChars<ExtraTypeInfoType>(ExtraTypeInfoType value);

template<>
const char* EnumUtil::ToChars<FileBufferType>(FileBufferType value);

template<>
const char* EnumUtil::ToChars<FileCompressionType>(FileCompressionType value);

template<>
const char* EnumUtil::ToChars<FileExpandResult>(FileExpandResult value);

template<>
const char* EnumUtil::ToChars<FileGlobOptions>(FileGlobOptions value);

template<>
const char* EnumUtil::ToChars<FileLockType>(FileLockType value);

template<>
const char* EnumUtil::ToChars<FilterPropagateResult>(FilterPropagateResult value);

template<>
const char* EnumUtil::ToChars<ForeignKeyType>(ForeignKeyType value);

template<>
const char* EnumUtil::ToChars<FunctionNullHandling>(FunctionNullHandling value);

template<>
const char* EnumUtil::ToChars<FunctionStability>(FunctionStability value);

template<>
const char* EnumUtil::ToChars<GateStatus>(GateStatus value);

template<>
const char* EnumUtil::ToChars<HLLStorageType>(HLLStorageType value);

template<>
const char* EnumUtil::ToChars<IndexConstraintType>(IndexConstraintType value);

template<>
const char* EnumUtil::ToChars<InsertColumnOrder>(InsertColumnOrder value);

template<>
const char* EnumUtil::ToChars<InterruptMode>(InterruptMode value);

template<>
const char* EnumUtil::ToChars<JoinRefType>(JoinRefType value);

template<>
const char* EnumUtil::ToChars<JoinType>(JoinType value);

template<>
const char* EnumUtil::ToChars<KeywordCategory>(KeywordCategory value);

template<>
const char* EnumUtil::ToChars<LimitNodeType>(LimitNodeType value);

template<>
const char* EnumUtil::ToChars<LoadType>(LoadType value);

template<>
const char* EnumUtil::ToChars<LogicalOperatorType>(LogicalOperatorType value);

template<>
const char* EnumUtil::ToChars<LogicalTypeId>(LogicalTypeId value);

template<>
const char* EnumUtil::ToChars<LookupResultType>(LookupResultType value);

template<>
const char* EnumUtil::ToChars<MacroType>(MacroType value);

template<>
const char* EnumUtil::ToChars<MapInvalidReason>(MapInvalidReason value);

template<>
const char* EnumUtil::ToChars<MemoryTag>(MemoryTag value);

template<>
const char* EnumUtil::ToChars<MetaPipelineType>(MetaPipelineType value);

template<>
const char* EnumUtil::ToChars<MetricsType>(MetricsType value);

template<>
const char* EnumUtil::ToChars<NType>(NType value);

template<>
const char* EnumUtil::ToChars<NewLineIdentifier>(NewLineIdentifier value);

template<>
const char* EnumUtil::ToChars<OnConflictAction>(OnConflictAction value);

template<>
const char* EnumUtil::ToChars<OnCreateConflict>(OnCreateConflict value);

template<>
const char* EnumUtil::ToChars<OnEntryNotFound>(OnEntryNotFound value);

template<>
const char* EnumUtil::ToChars<OperatorFinalizeResultType>(OperatorFinalizeResultType value);

template<>
const char* EnumUtil::ToChars<OperatorResultType>(OperatorResultType value);

template<>
const char* EnumUtil::ToChars<OptimizerType>(OptimizerType value);

template<>
const char* EnumUtil::ToChars<OrderByNullType>(OrderByNullType value);

template<>
const char* EnumUtil::ToChars<OrderPreservationType>(OrderPreservationType value);

template<>
const char* EnumUtil::ToChars<OrderType>(OrderType value);

template<>
const char* EnumUtil::ToChars<OutputStream>(OutputStream value);

template<>
const char* EnumUtil::ToChars<ParseInfoType>(ParseInfoType value);

template<>
const char* EnumUtil::ToChars<ParserExtensionResultType>(ParserExtensionResultType value);

template<>
const char* EnumUtil::ToChars<PartitionSortStage>(PartitionSortStage value);

template<>
const char* EnumUtil::ToChars<PartitionedColumnDataType>(PartitionedColumnDataType value);

template<>
const char* EnumUtil::ToChars<PartitionedTupleDataType>(PartitionedTupleDataType value);

template<>
const char* EnumUtil::ToChars<PendingExecutionResult>(PendingExecutionResult value);

template<>
const char* EnumUtil::ToChars<PhysicalOperatorType>(PhysicalOperatorType value);

template<>
const char* EnumUtil::ToChars<PhysicalType>(PhysicalType value);

template<>
const char* EnumUtil::ToChars<PragmaType>(PragmaType value);

template<>
const char* EnumUtil::ToChars<PreparedParamType>(PreparedParamType value);

template<>
const char* EnumUtil::ToChars<PreparedStatementMode>(PreparedStatementMode value);

template<>
const char* EnumUtil::ToChars<ProfilerPrintFormat>(ProfilerPrintFormat value);

template<>
const char* EnumUtil::ToChars<QuantileSerializationType>(QuantileSerializationType value);

template<>
const char* EnumUtil::ToChars<QueryNodeType>(QueryNodeType value);

template<>
const char* EnumUtil::ToChars<QueryResultType>(QueryResultType value);

template<>
const char* EnumUtil::ToChars<QuoteRule>(QuoteRule value);

template<>
const char* EnumUtil::ToChars<RelationType>(RelationType value);

template<>
const char* EnumUtil::ToChars<RenderMode>(RenderMode value);

template<>
const char* EnumUtil::ToChars<ResultModifierType>(ResultModifierType value);

template<>
const char* EnumUtil::ToChars<SampleMethod>(SampleMethod value);

template<>
const char* EnumUtil::ToChars<SampleType>(SampleType value);

template<>
const char* EnumUtil::ToChars<ScanType>(ScanType value);

template<>
const char* EnumUtil::ToChars<SecretDisplayType>(SecretDisplayType value);

template<>
const char* EnumUtil::ToChars<SecretPersistType>(SecretPersistType value);

template<>
const char* EnumUtil::ToChars<SequenceInfo>(SequenceInfo value);

template<>
const char* EnumUtil::ToChars<SetOperationType>(SetOperationType value);

template<>
const char* EnumUtil::ToChars<SetScope>(SetScope value);

template<>
const char* EnumUtil::ToChars<SetType>(SetType value);

template<>
const char* EnumUtil::ToChars<SettingScope>(SettingScope value);

template<>
const char* EnumUtil::ToChars<ShowType>(ShowType value);

template<>
const char* EnumUtil::ToChars<SimplifiedTokenType>(SimplifiedTokenType value);

template<>
const char* EnumUtil::ToChars<SinkCombineResultType>(SinkCombineResultType value);

template<>
const char* EnumUtil::ToChars<SinkFinalizeType>(SinkFinalizeType value);

template<>
const char* EnumUtil::ToChars<SinkNextBatchType>(SinkNextBatchType value);

template<>
const char* EnumUtil::ToChars<SinkResultType>(SinkResultType value);

template<>
const char* EnumUtil::ToChars<SourceResultType>(SourceResultType value);

template<>
const char* EnumUtil::ToChars<StatementReturnType>(StatementReturnType value);

template<>
const char* EnumUtil::ToChars<StatementType>(StatementType value);

template<>
const char* EnumUtil::ToChars<StatisticsType>(StatisticsType value);

template<>
const char* EnumUtil::ToChars<StatsInfo>(StatsInfo value);

template<>
const char* EnumUtil::ToChars<StrTimeSpecifier>(StrTimeSpecifier value);

template<>
const char* EnumUtil::ToChars<StreamExecutionResult>(StreamExecutionResult value);

template<>
const char* EnumUtil::ToChars<SubqueryType>(SubqueryType value);

template<>
const char* EnumUtil::ToChars<TableColumnType>(TableColumnType value);

template<>
const char* EnumUtil::ToChars<TableFilterType>(TableFilterType value);

template<>
const char* EnumUtil::ToChars<TableReferenceType>(TableReferenceType value);

template<>
const char* EnumUtil::ToChars<TableScanType>(TableScanType value);

template<>
const char* EnumUtil::ToChars<TaskExecutionMode>(TaskExecutionMode value);

template<>
const char* EnumUtil::ToChars<TaskExecutionResult>(TaskExecutionResult value);

template<>
const char* EnumUtil::ToChars<TimestampCastResult>(TimestampCastResult value);

template<>
const char* EnumUtil::ToChars<TransactionModifierType>(TransactionModifierType value);

template<>
const char* EnumUtil::ToChars<TransactionType>(TransactionType value);

template<>
const char* EnumUtil::ToChars<TupleDataPinProperties>(TupleDataPinProperties value);

template<>
const char* EnumUtil::ToChars<UndoFlags>(UndoFlags value);

template<>
const char* EnumUtil::ToChars<UnionInvalidReason>(UnionInvalidReason value);

template<>
const char* EnumUtil::ToChars<VectorAuxiliaryDataType>(VectorAuxiliaryDataType value);

template<>
const char* EnumUtil::ToChars<VectorBufferType>(VectorBufferType value);

template<>
const char* EnumUtil::ToChars<VectorType>(VectorType value);

template<>
const char* EnumUtil::ToChars<VerificationType>(VerificationType value);

template<>
const char* EnumUtil::ToChars<VerifyExistenceType>(VerifyExistenceType value);

template<>
const char* EnumUtil::ToChars<WALType>(WALType value);

template<>
const char* EnumUtil::ToChars<WindowAggregationMode>(WindowAggregationMode value);

template<>
const char* EnumUtil::ToChars<WindowBoundary>(WindowBoundary value);

template<>
const char* EnumUtil::ToChars<WindowExcludeMode>(WindowExcludeMode value);


template<>
AccessMode EnumUtil::FromString<AccessMode>(const char *value);

template<>
AggregateCombineType EnumUtil::FromString<AggregateCombineType>(const char *value);

template<>
AggregateHandling EnumUtil::FromString<AggregateHandling>(const char *value);

template<>
AggregateOrderDependent EnumUtil::FromString<AggregateOrderDependent>(const char *value);

template<>
AggregateType EnumUtil::FromString<AggregateType>(const char *value);

template<>
AlterForeignKeyType EnumUtil::FromString<AlterForeignKeyType>(const char *value);

template<>
AlterScalarFunctionType EnumUtil::FromString<AlterScalarFunctionType>(const char *value);

template<>
AlterTableFunctionType EnumUtil::FromString<AlterTableFunctionType>(const char *value);

template<>
AlterTableType EnumUtil::FromString<AlterTableType>(const char *value);

template<>
AlterType EnumUtil::FromString<AlterType>(const char *value);

template<>
AlterViewType EnumUtil::FromString<AlterViewType>(const char *value);

template<>
AppenderType EnumUtil::FromString<AppenderType>(const char *value);

template<>
ArrowDateTimeType EnumUtil::FromString<ArrowDateTimeType>(const char *value);

template<>
ArrowOffsetSize EnumUtil::FromString<ArrowOffsetSize>(const char *value);

template<>
ArrowTypeInfoType EnumUtil::FromString<ArrowTypeInfoType>(const char *value);

template<>
ArrowVariableSizeType EnumUtil::FromString<ArrowVariableSizeType>(const char *value);

template<>
BinderType EnumUtil::FromString<BinderType>(const char *value);

template<>
BindingMode EnumUtil::FromString<BindingMode>(const char *value);

template<>
BitpackingMode EnumUtil::FromString<BitpackingMode>(const char *value);

template<>
BlockState EnumUtil::FromString<BlockState>(const char *value);

template<>
CAPIResultSetType EnumUtil::FromString<CAPIResultSetType>(const char *value);

template<>
CSVState EnumUtil::FromString<CSVState>(const char *value);

template<>
CTEMaterialize EnumUtil::FromString<CTEMaterialize>(const char *value);

template<>
CatalogLookupBehavior EnumUtil::FromString<CatalogLookupBehavior>(const char *value);

template<>
CatalogType EnumUtil::FromString<CatalogType>(const char *value);

template<>
CheckpointAbort EnumUtil::FromString<CheckpointAbort>(const char *value);

template<>
ChunkInfoType EnumUtil::FromString<ChunkInfoType>(const char *value);

template<>
ColumnDataAllocatorType EnumUtil::FromString<ColumnDataAllocatorType>(const char *value);

template<>
ColumnDataScanProperties EnumUtil::FromString<ColumnDataScanProperties>(const char *value);

template<>
ColumnSegmentType EnumUtil::FromString<ColumnSegmentType>(const char *value);

template<>
CompressedMaterializationDirection EnumUtil::FromString<CompressedMaterializationDirection>(const char *value);

template<>
CompressionType EnumUtil::FromString<CompressionType>(const char *value);

template<>
ConflictManagerMode EnumUtil::FromString<ConflictManagerMode>(const char *value);

template<>
ConstraintType EnumUtil::FromString<ConstraintType>(const char *value);

template<>
CopyFunctionReturnType EnumUtil::FromString<CopyFunctionReturnType>(const char *value);

template<>
CopyOverwriteMode EnumUtil::FromString<CopyOverwriteMode>(const char *value);

template<>
CopyToType EnumUtil::FromString<CopyToType>(const char *value);

template<>
DataFileType EnumUtil::FromString<DataFileType>(const char *value);

template<>
DatePartSpecifier EnumUtil::FromString<DatePartSpecifier>(const char *value);

template<>
DebugInitialize EnumUtil::FromString<DebugInitialize>(const char *value);

template<>
DefaultOrderByNullType EnumUtil::FromString<DefaultOrderByNullType>(const char *value);

template<>
DependencyEntryType EnumUtil::FromString<DependencyEntryType>(const char *value);

template<>
DeprecatedIndexType EnumUtil::FromString<DeprecatedIndexType>(const char *value);

template<>
DestroyBufferUpon EnumUtil::FromString<DestroyBufferUpon>(const char *value);

template<>
DistinctType EnumUtil::FromString<DistinctType>(const char *value);

template<>
ErrorType EnumUtil::FromString<ErrorType>(const char *value);

template<>
ExceptionFormatValueType EnumUtil::FromString<ExceptionFormatValueType>(const char *value);

template<>
ExceptionType EnumUtil::FromString<ExceptionType>(const char *value);

template<>
ExplainFormat EnumUtil::FromString<ExplainFormat>(const char *value);

template<>
ExplainOutputType EnumUtil::FromString<ExplainOutputType>(const char *value);

template<>
ExplainType EnumUtil::FromString<ExplainType>(const char *value);

template<>
ExponentType EnumUtil::FromString<ExponentType>(const char *value);

template<>
ExpressionClass EnumUtil::FromString<ExpressionClass>(const char *value);

template<>
ExpressionType EnumUtil::FromString<ExpressionType>(const char *value);

template<>
ExtensionABIType EnumUtil::FromString<ExtensionABIType>(const char *value);

template<>
ExtensionInstallMode EnumUtil::FromString<ExtensionInstallMode>(const char *value);

template<>
ExtensionLoadResult EnumUtil::FromString<ExtensionLoadResult>(const char *value);

template<>
ExtensionUpdateResultTag EnumUtil::FromString<ExtensionUpdateResultTag>(const char *value);

template<>
ExtraDropInfoType EnumUtil::FromString<ExtraDropInfoType>(const char *value);

template<>
ExtraTypeInfoType EnumUtil::FromString<ExtraTypeInfoType>(const char *value);

template<>
FileBufferType EnumUtil::FromString<FileBufferType>(const char *value);

template<>
FileCompressionType EnumUtil::FromString<FileCompressionType>(const char *value);

template<>
FileExpandResult EnumUtil::FromString<FileExpandResult>(const char *value);

template<>
FileGlobOptions EnumUtil::FromString<FileGlobOptions>(const char *value);

template<>
FileLockType EnumUtil::FromString<FileLockType>(const char *value);

template<>
FilterPropagateResult EnumUtil::FromString<FilterPropagateResult>(const char *value);

template<>
ForeignKeyType EnumUtil::FromString<ForeignKeyType>(const char *value);

template<>
FunctionNullHandling EnumUtil::FromString<FunctionNullHandling>(const char *value);

template<>
FunctionStability EnumUtil::FromString<FunctionStability>(const char *value);

template<>
GateStatus EnumUtil::FromString<GateStatus>(const char *value);

template<>
HLLStorageType EnumUtil::FromString<HLLStorageType>(const char *value);

template<>
IndexConstraintType EnumUtil::FromString<IndexConstraintType>(const char *value);

template<>
InsertColumnOrder EnumUtil::FromString<InsertColumnOrder>(const char *value);

template<>
InterruptMode EnumUtil::FromString<InterruptMode>(const char *value);

template<>
JoinRefType EnumUtil::FromString<JoinRefType>(const char *value);

template<>
JoinType EnumUtil::FromString<JoinType>(const char *value);

template<>
KeywordCategory EnumUtil::FromString<KeywordCategory>(const char *value);

template<>
LimitNodeType EnumUtil::FromString<LimitNodeType>(const char *value);

template<>
LoadType EnumUtil::FromString<LoadType>(const char *value);

template<>
LogicalOperatorType EnumUtil::FromString<LogicalOperatorType>(const char *value);

template<>
LogicalTypeId EnumUtil::FromString<LogicalTypeId>(const char *value);

template<>
LookupResultType EnumUtil::FromString<LookupResultType>(const char *value);

template<>
MacroType EnumUtil::FromString<MacroType>(const char *value);

template<>
MapInvalidReason EnumUtil::FromString<MapInvalidReason>(const char *value);

template<>
MemoryTag EnumUtil::FromString<MemoryTag>(const char *value);

template<>
MetaPipelineType EnumUtil::FromString<MetaPipelineType>(const char *value);

template<>
MetricsType EnumUtil::FromString<MetricsType>(const char *value);

template<>
NType EnumUtil::FromString<NType>(const char *value);

template<>
NewLineIdentifier EnumUtil::FromString<NewLineIdentifier>(const char *value);

template<>
OnConflictAction EnumUtil::FromString<OnConflictAction>(const char *value);

template<>
OnCreateConflict EnumUtil::FromString<OnCreateConflict>(const char *value);

template<>
OnEntryNotFound EnumUtil::FromString<OnEntryNotFound>(const char *value);

template<>
OperatorFinalizeResultType EnumUtil::FromString<OperatorFinalizeResultType>(const char *value);

template<>
OperatorResultType EnumUtil::FromString<OperatorResultType>(const char *value);

template<>
OptimizerType EnumUtil::FromString<OptimizerType>(const char *value);

template<>
OrderByNullType EnumUtil::FromString<OrderByNullType>(const char *value);

template<>
OrderPreservationType EnumUtil::FromString<OrderPreservationType>(const char *value);

template<>
OrderType EnumUtil::FromString<OrderType>(const char *value);

template<>
OutputStream EnumUtil::FromString<OutputStream>(const char *value);

template<>
ParseInfoType EnumUtil::FromString<ParseInfoType>(const char *value);

template<>
ParserExtensionResultType EnumUtil::FromString<ParserExtensionResultType>(const char *value);

template<>
PartitionSortStage EnumUtil::FromString<PartitionSortStage>(const char *value);

template<>
PartitionedColumnDataType EnumUtil::FromString<PartitionedColumnDataType>(const char *value);

template<>
PartitionedTupleDataType EnumUtil::FromString<PartitionedTupleDataType>(const char *value);

template<>
PendingExecutionResult EnumUtil::FromString<PendingExecutionResult>(const char *value);

template<>
PhysicalOperatorType EnumUtil::FromString<PhysicalOperatorType>(const char *value);

template<>
PhysicalType EnumUtil::FromString<PhysicalType>(const char *value);

template<>
PragmaType EnumUtil::FromString<PragmaType>(const char *value);

template<>
PreparedParamType EnumUtil::FromString<PreparedParamType>(const char *value);

template<>
PreparedStatementMode EnumUtil::FromString<PreparedStatementMode>(const char *value);

template<>
ProfilerPrintFormat EnumUtil::FromString<ProfilerPrintFormat>(const char *value);

template<>
QuantileSerializationType EnumUtil::FromString<QuantileSerializationType>(const char *value);

template<>
QueryNodeType EnumUtil::FromString<QueryNodeType>(const char *value);

template<>
QueryResultType EnumUtil::FromString<QueryResultType>(const char *value);

template<>
QuoteRule EnumUtil::FromString<QuoteRule>(const char *value);

template<>
RelationType EnumUtil::FromString<RelationType>(const char *value);

template<>
RenderMode EnumUtil::FromString<RenderMode>(const char *value);

template<>
ResultModifierType EnumUtil::FromString<ResultModifierType>(const char *value);

template<>
SampleMethod EnumUtil::FromString<SampleMethod>(const char *value);

template<>
SampleType EnumUtil::FromString<SampleType>(const char *value);

template<>
ScanType EnumUtil::FromString<ScanType>(const char *value);

template<>
SecretDisplayType EnumUtil::FromString<SecretDisplayType>(const char *value);

template<>
SecretPersistType EnumUtil::FromString<SecretPersistType>(const char *value);

template<>
SequenceInfo EnumUtil::FromString<SequenceInfo>(const char *value);

template<>
SetOperationType EnumUtil::FromString<SetOperationType>(const char *value);

template<>
SetScope EnumUtil::FromString<SetScope>(const char *value);

template<>
SetType EnumUtil::FromString<SetType>(const char *value);

template<>
SettingScope EnumUtil::FromString<SettingScope>(const char *value);

template<>
ShowType EnumUtil::FromString<ShowType>(const char *value);

template<>
SimplifiedTokenType EnumUtil::FromString<SimplifiedTokenType>(const char *value);

template<>
SinkCombineResultType EnumUtil::FromString<SinkCombineResultType>(const char *value);

template<>
SinkFinalizeType EnumUtil::FromString<SinkFinalizeType>(const char *value);

template<>
SinkNextBatchType EnumUtil::FromString<SinkNextBatchType>(const char *value);

template<>
SinkResultType EnumUtil::FromString<SinkResultType>(const char *value);

template<>
SourceResultType EnumUtil::FromString<SourceResultType>(const char *value);

template<>
StatementReturnType EnumUtil::FromString<StatementReturnType>(const char *value);

template<>
StatementType EnumUtil::FromString<StatementType>(const char *value);

template<>
StatisticsType EnumUtil::FromString<StatisticsType>(const char *value);

template<>
StatsInfo EnumUtil::FromString<StatsInfo>(const char *value);

template<>
StrTimeSpecifier EnumUtil::FromString<StrTimeSpecifier>(const char *value);

template<>
StreamExecutionResult EnumUtil::FromString<StreamExecutionResult>(const char *value);

template<>
SubqueryType EnumUtil::FromString<SubqueryType>(const char *value);

template<>
TableColumnType EnumUtil::FromString<TableColumnType>(const char *value);

template<>
TableFilterType EnumUtil::FromString<TableFilterType>(const char *value);

template<>
TableReferenceType EnumUtil::FromString<TableReferenceType>(const char *value);

template<>
TableScanType EnumUtil::FromString<TableScanType>(const char *value);

template<>
TaskExecutionMode EnumUtil::FromString<TaskExecutionMode>(const char *value);

template<>
TaskExecutionResult EnumUtil::FromString<TaskExecutionResult>(const char *value);

template<>
TimestampCastResult EnumUtil::FromString<TimestampCastResult>(const char *value);

template<>
TransactionModifierType EnumUtil::FromString<TransactionModifierType>(const char *value);

template<>
TransactionType EnumUtil::FromString<TransactionType>(const char *value);

template<>
TupleDataPinProperties EnumUtil::FromString<TupleDataPinProperties>(const char *value);

template<>
UndoFlags EnumUtil::FromString<UndoFlags>(const char *value);

template<>
UnionInvalidReason EnumUtil::FromString<UnionInvalidReason>(const char *value);

template<>
VectorAuxiliaryDataType EnumUtil::FromString<VectorAuxiliaryDataType>(const char *value);

template<>
VectorBufferType EnumUtil::FromString<VectorBufferType>(const char *value);

template<>
VectorType EnumUtil::FromString<VectorType>(const char *value);

template<>
VerificationType EnumUtil::FromString<VerificationType>(const char *value);

template<>
VerifyExistenceType EnumUtil::FromString<VerifyExistenceType>(const char *value);

template<>
WALType EnumUtil::FromString<WALType>(const char *value);

template<>
WindowAggregationMode EnumUtil::FromString<WindowAggregationMode>(const char *value);

template<>
WindowBoundary EnumUtil::FromString<WindowBoundary>(const char *value);

template<>
WindowExcludeMode EnumUtil::FromString<WindowExcludeMode>(const char *value);


}

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/enums/on_create_conflict.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

enum class OnCreateConflict : uint8_t {
	// Standard: throw error
	ERROR_ON_CONFLICT,
	// CREATE IF NOT EXISTS, silently do nothing on conflict
	IGNORE_ON_CONFLICT,
	// CREATE OR REPLACE
	REPLACE_ON_CONFLICT,
	// Update on conflict - only support for functions. Add a function overload if the function already exists.
	ALTER_ON_CONFLICT
};

} // namespace duckdb




namespace duckdb {
struct AlterInfo;

struct CreateInfo : public ParseInfo {
public:
	static constexpr const ParseInfoType TYPE = ParseInfoType::CREATE_INFO;

public:
	explicit CreateInfo(CatalogType type, string schema = DEFAULT_SCHEMA, string catalog_p = INVALID_CATALOG)
	    : ParseInfo(TYPE), type(type), catalog(std::move(catalog_p)), schema(std::move(schema)),
	      on_conflict(OnCreateConflict::ERROR_ON_CONFLICT), temporary(false), internal(false) {
	}
	~CreateInfo() override {
	}

	//! The to-be-created catalog type
	CatalogType type;
	//! The catalog name of the entry
	string catalog;
	//! The schema name of the entry
	string schema;
	//! What to do on create conflict
	OnCreateConflict on_conflict;
	//! Whether or not the entry is temporary
	bool temporary;
	//! Whether or not the entry is an internal entry
	bool internal;
	//! The SQL string of the CREATE statement
	string sql;
	//! The inherent dependencies of the created entry
	LogicalDependencyList dependencies;
	//! User provided comment
	Value comment;
	//! Key-value tags with additional metadata
	unordered_map<string, string> tags;

public:
	void Serialize(Serializer &serializer) const override;
	static unique_ptr<CreateInfo> Deserialize(Deserializer &deserializer);

	virtual unique_ptr<CreateInfo> Copy() const = 0;

	DUCKDB_API void CopyProperties(CreateInfo &other) const;
	//! Generates an alter statement from the create statement - used for OnCreateConflict::ALTER_ON_CONFLICT
	DUCKDB_API virtual unique_ptr<AlterInfo> GetAlterInfo() const;

	virtual string ToString() const {
		throw NotImplementedException("ToString not supported for this type of CreateInfo: '%s'",
		                              EnumUtil::ToString(info_type));
	}
};

} // namespace duckdb



namespace duckdb {

enum class SequenceInfo : uint8_t {
	// Sequence start
	SEQ_START,
	// Sequence increment
	SEQ_INC,
	// Sequence minimum value
	SEQ_MIN,
	// Sequence maximum value
	SEQ_MAX,
	// Sequence cycle option
	SEQ_CYCLE,
	// Sequence owner table
	SEQ_OWN
};

struct CreateSequenceInfo : public CreateInfo {
	CreateSequenceInfo();

	//! Sequence name to create
	string name;
	//! Usage count of the sequence
	uint64_t usage_count;
	//! The increment value
	int64_t increment;
	//! The minimum value of the sequence
	int64_t min_value;
	//! The maximum value of the sequence
	int64_t max_value;
	//! The start value of the sequence
	int64_t start_value;
	//! Whether or not the sequence cycles
	bool cycle;

public:
	unique_ptr<CreateInfo> Copy() const override;

public:
	DUCKDB_API void Serialize(Serializer &serializer) const override;
	DUCKDB_API static unique_ptr<CreateInfo> Deserialize(Deserializer &deserializer);

	string ToString() const override;
};

} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/parser/parsed_data/alter_table_info.hpp
//
//
//===----------------------------------------------------------------------===//



//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/parser/parsed_data/alter_info.hpp
//
//
//===----------------------------------------------------------------------===//








namespace duckdb {

enum class AlterType : uint8_t {
	INVALID = 0,
	ALTER_TABLE = 1,
	ALTER_VIEW = 2,
	ALTER_SEQUENCE = 3,
	CHANGE_OWNERSHIP = 4,
	ALTER_SCALAR_FUNCTION = 5,
	ALTER_TABLE_FUNCTION = 6,
	SET_COMMENT = 7,
	SET_COLUMN_COMMENT = 8
};

struct AlterEntryData {
	AlterEntryData() {
	}
	AlterEntryData(string catalog_p, string schema_p, string name_p, OnEntryNotFound if_not_found)
	    : catalog(std::move(catalog_p)), schema(std::move(schema_p)), name(std::move(name_p)),
	      if_not_found(if_not_found) {
	}

	string catalog;
	string schema;
	string name;
	OnEntryNotFound if_not_found;
};

struct AlterInfo : public ParseInfo {
public:
	static constexpr const ParseInfoType TYPE = ParseInfoType::ALTER_INFO;

public:
	AlterInfo(AlterType type, string catalog, string schema, string name, OnEntryNotFound if_not_found);
	~AlterInfo() override;

	AlterType type;
	//! if exists
	OnEntryNotFound if_not_found;
	//! Catalog name to alter
	string catalog;
	//! Schema name to alter
	string schema;
	//! Entry name to alter
	string name;
	//! Allow altering internal entries
	bool allow_internal;

public:
	virtual CatalogType GetCatalogType() const = 0;
	virtual unique_ptr<AlterInfo> Copy() const = 0;
	virtual string ToString() const = 0;

	void Serialize(Serializer &serializer) const override;
	static unique_ptr<ParseInfo> Deserialize(Deserializer &deserializer);

	virtual string GetColumnName() const {
		return "";
	};

	AlterEntryData GetAlterEntryData() const;

protected:
	explicit AlterInfo(AlterType type);
};

} // namespace duckdb


//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/parser/constraint.hpp
//
//
//===----------------------------------------------------------------------===//







namespace duckdb {

class Serializer;
class Deserializer;

//===--------------------------------------------------------------------===//
// Constraint Types
//===--------------------------------------------------------------------===//
enum class ConstraintType : uint8_t {
	INVALID = 0,     // invalid constraint type
	NOT_NULL = 1,    // NOT NULL constraint
	CHECK = 2,       // CHECK constraint
	UNIQUE = 3,      // UNIQUE constraint
	FOREIGN_KEY = 4, // FOREIGN KEY constraint
};

enum class ForeignKeyType : uint8_t {
	FK_TYPE_PRIMARY_KEY_TABLE = 0,   // main table
	FK_TYPE_FOREIGN_KEY_TABLE = 1,   // referencing table
	FK_TYPE_SELF_REFERENCE_TABLE = 2 // self refrencing table
};

struct ForeignKeyInfo {
	ForeignKeyType type;
	string schema;
	//! if type is FK_TYPE_FOREIGN_KEY_TABLE, means main key table, if type is FK_TYPE_PRIMARY_KEY_TABLE, means foreign
	//! key table
	string table;
	//! The set of main key table's column's index
	vector<PhysicalIndex> pk_keys;
	//! The set of foreign key table's column's index
	vector<PhysicalIndex> fk_keys;
};

//! Constraint is the base class of any type of table constraint.
class Constraint {
public:
	DUCKDB_API explicit Constraint(ConstraintType type);
	DUCKDB_API virtual ~Constraint();

	ConstraintType type;

public:
	DUCKDB_API virtual string ToString() const = 0;
	DUCKDB_API void Print() const;

	DUCKDB_API virtual unique_ptr<Constraint> Copy() const = 0;

	DUCKDB_API virtual void Serialize(Serializer &serializer) const;
	DUCKDB_API static unique_ptr<Constraint> Deserialize(Deserializer &deserializer);

public:
	template <class TARGET>
	TARGET &Cast() {
		if (type != TARGET::TYPE) {
			throw InternalException("Failed to cast constraint to type - constraint type mismatch");
		}
		return reinterpret_cast<TARGET &>(*this);
	}

	template <class TARGET>
	const TARGET &Cast() const {
		if (type != TARGET::TYPE) {
			throw InternalException("Failed to cast constraint to type - constraint type mismatch");
		}
		return reinterpret_cast<const TARGET &>(*this);
	}
};
} // namespace duckdb



namespace duckdb {

enum class AlterForeignKeyType : uint8_t { AFT_ADD = 0, AFT_DELETE = 1 };

//===--------------------------------------------------------------------===//
// Change Ownership
//===--------------------------------------------------------------------===//
struct ChangeOwnershipInfo : public AlterInfo {
	ChangeOwnershipInfo(CatalogType entry_catalog_type, string entry_catalog, string entry_schema, string entry_name,
	                    string owner_schema, string owner_name, OnEntryNotFound if_not_found);

	// Catalog type refers to the entry type, since this struct is usually built from an
	// ALTER <TYPE> <schema>.<name> OWNED BY <owner_schema>.<owner_name> statement
	// here it is only possible to know the type of who is to be owned
	CatalogType entry_catalog_type;

	string owner_schema;
	string owner_name;

public:
	CatalogType GetCatalogType() const override;
	unique_ptr<AlterInfo> Copy() const override;
	string ToString() const override;

	void Serialize(Serializer &serializer) const override;
	static unique_ptr<AlterInfo> Deserialize(Deserializer &deserializer);

	explicit ChangeOwnershipInfo();
};

//===--------------------------------------------------------------------===//
// Set Comment
//===--------------------------------------------------------------------===//
struct SetCommentInfo : public AlterInfo {
	SetCommentInfo(CatalogType entry_catalog_type, string entry_catalog, string entry_schema, string entry_name,
	               Value new_comment_value_p, OnEntryNotFound if_not_found);

	CatalogType entry_catalog_type;
	Value comment_value;

public:
	CatalogType GetCatalogType() const override;
	unique_ptr<AlterInfo> Copy() const override;
	string ToString() const override;

	void Serialize(Serializer &serializer) const override;
	static unique_ptr<AlterInfo> Deserialize(Deserializer &deserializer);

	explicit SetCommentInfo();
};

//===--------------------------------------------------------------------===//
// Alter Table
//===--------------------------------------------------------------------===//
enum class AlterTableType : uint8_t {
	INVALID = 0,
	RENAME_COLUMN = 1,
	RENAME_TABLE = 2,
	ADD_COLUMN = 3,
	REMOVE_COLUMN = 4,
	ALTER_COLUMN_TYPE = 5,
	SET_DEFAULT = 6,
	FOREIGN_KEY_CONSTRAINT = 7,
	SET_NOT_NULL = 8,
	DROP_NOT_NULL = 9,
	SET_COLUMN_COMMENT = 10
};

struct AlterTableInfo : public AlterInfo {
	AlterTableInfo(AlterTableType type, AlterEntryData data);
	~AlterTableInfo() override;

	AlterTableType alter_table_type;

public:
	CatalogType GetCatalogType() const override;

	void Serialize(Serializer &serializer) const override;
	static unique_ptr<AlterInfo> Deserialize(Deserializer &deserializer);

protected:
	explicit AlterTableInfo(AlterTableType type);
};

//===--------------------------------------------------------------------===//
// RenameColumnInfo
//===--------------------------------------------------------------------===//
struct RenameColumnInfo : public AlterTableInfo {
	RenameColumnInfo(AlterEntryData data, string old_name_p, string new_name_p);
	~RenameColumnInfo() override;

	//! Column old name
	string old_name;
	//! Column new name
	string new_name;

public:
	unique_ptr<AlterInfo> Copy() const override;
	string ToString() const override;

	void Serialize(Serializer &serializer) const override;
	static unique_ptr<AlterTableInfo> Deserialize(Deserializer &deserializer);

private:
	RenameColumnInfo();
};

//===--------------------------------------------------------------------===//
// RenameTableInfo
//===--------------------------------------------------------------------===//
struct RenameTableInfo : public AlterTableInfo {
	RenameTableInfo(AlterEntryData data, string new_name);
	~RenameTableInfo() override;

	//! Relation new name
	string new_table_name;

public:
	unique_ptr<AlterInfo> Copy() const override;
	string ToString() const override;

	void Serialize(Serializer &serializer) const override;
	static unique_ptr<AlterTableInfo> Deserialize(Deserializer &deserializer);

private:
	RenameTableInfo();
};

//===--------------------------------------------------------------------===//
// AddColumnInfo
//===--------------------------------------------------------------------===//
struct AddColumnInfo : public AlterTableInfo {
	AddColumnInfo(AlterEntryData data, ColumnDefinition new_column, bool if_column_not_exists);
	~AddColumnInfo() override;

	//! New column
	ColumnDefinition new_column;
	//! Whether or not an error should be thrown if the column exist
	bool if_column_not_exists;

public:
	unique_ptr<AlterInfo> Copy() const override;
	string ToString() const override;

	void Serialize(Serializer &serializer) const override;
	static unique_ptr<AlterTableInfo> Deserialize(Deserializer &deserializer);

private:
	explicit AddColumnInfo(ColumnDefinition new_column);
};

//===--------------------------------------------------------------------===//
// RemoveColumnInfo
//===--------------------------------------------------------------------===//
struct RemoveColumnInfo : public AlterTableInfo {
	RemoveColumnInfo(AlterEntryData data, string removed_column, bool if_column_exists, bool cascade);
	~RemoveColumnInfo() override;

	//! The column to remove
	string removed_column;
	//! Whether or not an error should be thrown if the column does not exist
	bool if_column_exists;
	//! Whether or not the column should be removed if a dependency conflict arises (used by GENERATED columns)
	bool cascade;

public:
	unique_ptr<AlterInfo> Copy() const override;
	string ToString() const override;
	void Serialize(Serializer &serializer) const override;
	static unique_ptr<AlterTableInfo> Deserialize(Deserializer &deserializer);
	string GetColumnName() const override {
		return removed_column;
	}

private:
	RemoveColumnInfo();
};

//===--------------------------------------------------------------------===//
// ChangeColumnTypeInfo
//===--------------------------------------------------------------------===//
struct ChangeColumnTypeInfo : public AlterTableInfo {
	ChangeColumnTypeInfo(AlterEntryData data, string column_name, LogicalType target_type,
	                     unique_ptr<ParsedExpression> expression);
	~ChangeColumnTypeInfo() override;

	//! The column name to alter
	string column_name;
	//! The target type of the column
	LogicalType target_type;
	//! The expression used for data conversion
	unique_ptr<ParsedExpression> expression;

public:
	unique_ptr<AlterInfo> Copy() const override;
	string ToString() const override;
	void Serialize(Serializer &serializer) const override;
	static unique_ptr<AlterTableInfo> Deserialize(Deserializer &deserializer);
	string GetColumnName() const override {
		return column_name;
	};

private:
	ChangeColumnTypeInfo();
};

//===--------------------------------------------------------------------===//
// SetDefaultInfo
//===--------------------------------------------------------------------===//
struct SetDefaultInfo : public AlterTableInfo {
	SetDefaultInfo(AlterEntryData data, string column_name, unique_ptr<ParsedExpression> new_default);
	~SetDefaultInfo() override;

	//! The column name to alter
	string column_name;
	//! The expression used for data conversion
	unique_ptr<ParsedExpression> expression;

public:
	unique_ptr<AlterInfo> Copy() const override;
	string ToString() const override;
	void Serialize(Serializer &serializer) const override;
	static unique_ptr<AlterTableInfo> Deserialize(Deserializer &deserializer);

private:
	SetDefaultInfo();
};

//===--------------------------------------------------------------------===//
// AlterForeignKeyInfo
//===--------------------------------------------------------------------===//
struct AlterForeignKeyInfo : public AlterTableInfo {
	AlterForeignKeyInfo(AlterEntryData data, string fk_table, vector<string> pk_columns, vector<string> fk_columns,
	                    vector<PhysicalIndex> pk_keys, vector<PhysicalIndex> fk_keys, AlterForeignKeyType type);
	~AlterForeignKeyInfo() override;

	string fk_table;
	vector<string> pk_columns;
	vector<string> fk_columns;
	vector<PhysicalIndex> pk_keys;
	vector<PhysicalIndex> fk_keys;
	AlterForeignKeyType type;

public:
	unique_ptr<AlterInfo> Copy() const override;
	string ToString() const override;
	void Serialize(Serializer &serializer) const override;
	static unique_ptr<AlterTableInfo> Deserialize(Deserializer &deserializer);

private:
	AlterForeignKeyInfo();
};

//===--------------------------------------------------------------------===//
// SetNotNullInfo
//===--------------------------------------------------------------------===//
struct SetNotNullInfo : public AlterTableInfo {
	SetNotNullInfo(AlterEntryData data, string column_name);
	~SetNotNullInfo() override;

	//! The column name to alter
	string column_name;

public:
	unique_ptr<AlterInfo> Copy() const override;
	string ToString() const override;
	void Serialize(Serializer &serializer) const override;
	static unique_ptr<AlterTableInfo> Deserialize(Deserializer &deserializer);

private:
	SetNotNullInfo();
};

//===--------------------------------------------------------------------===//
// DropNotNullInfo
//===--------------------------------------------------------------------===//
struct DropNotNullInfo : public AlterTableInfo {
	DropNotNullInfo(AlterEntryData data, string column_name);
	~DropNotNullInfo() override;

	//! The column name to alter
	string column_name;

public:
	unique_ptr<AlterInfo> Copy() const override;
	string ToString() const override;
	void Serialize(Serializer &serializer) const override;
	static unique_ptr<AlterTableInfo> Deserialize(Deserializer &deserializer);

private:
	DropNotNullInfo();
};

//===--------------------------------------------------------------------===//
// Alter View
//===--------------------------------------------------------------------===//
enum class AlterViewType : uint8_t { INVALID = 0, RENAME_VIEW = 1 };

struct AlterViewInfo : public AlterInfo {
	AlterViewInfo(AlterViewType type, AlterEntryData data);
	~AlterViewInfo() override;

	AlterViewType alter_view_type;

public:
	CatalogType GetCatalogType() const override;
	void Serialize(Serializer &serializer) const override;
	static unique_ptr<AlterInfo> Deserialize(Deserializer &deserializer);

protected:
	explicit AlterViewInfo(AlterViewType type);
};

//===--------------------------------------------------------------------===//
// RenameViewInfo
//===--------------------------------------------------------------------===//
struct RenameViewInfo : public AlterViewInfo {
	RenameViewInfo(AlterEntryData data, string new_name);
	~RenameViewInfo() override;

	//! Relation new name
	string new_view_name;

public:
	unique_ptr<AlterInfo> Copy() const override;
	string ToString() const override;
	void Serialize(Serializer &serializer) const override;
	static unique_ptr<AlterViewInfo> Deserialize(Deserializer &deserializer);

private:
	RenameViewInfo();
};

} // namespace duckdb


namespace duckdb {
class DuckTransaction;
class SequenceCatalogEntry;

struct SequenceValue {
	SequenceCatalogEntry *entry;
	uint64_t usage_count;
	int64_t counter;
};

struct SequenceData {
	explicit SequenceData(CreateSequenceInfo &info);

	//! The amount of times the sequence has been used
	uint64_t usage_count;
	//! The sequence counter
	int64_t counter;
	//! The most recently returned value
	int64_t last_value;
	//! The increment value
	int64_t increment;
	//! The minimum value of the sequence
	int64_t start_value;
	//! The minimum value of the sequence
	int64_t min_value;
	//! The maximum value of the sequence
	int64_t max_value;
	//! Whether or not the sequence cycles
	bool cycle;
};

//! A sequence catalog entry
class SequenceCatalogEntry : public StandardEntry {
public:
	static constexpr const CatalogType Type = CatalogType::SEQUENCE_ENTRY;
	static constexpr const char *Name = "sequence";

public:
	//! Create a real TableCatalogEntry and initialize storage for it
	SequenceCatalogEntry(Catalog &catalog, SchemaCatalogEntry &schema, CreateSequenceInfo &info);

public:
	unique_ptr<CatalogEntry> Copy(ClientContext &context) const override;
	unique_ptr<CreateInfo> GetInfo() const override;

	SequenceData GetData() const;
	int64_t CurrentValue();
	int64_t NextValue(DuckTransaction &transaction);
	void ReplayValue(uint64_t usage_count, int64_t counter);

	string ToSQL() const override;

private:
	//! Lock for getting a value on the sequence
	mutable mutex lock;
	//! Sequence data
	SequenceData data;
};
} // namespace duckdb


//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/transaction/undo_buffer.hpp
//
//
//===----------------------------------------------------------------------===//




//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/enums/undo_flags.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

enum class UndoFlags : uint32_t { // far too big but aligned (TM)
	EMPTY_ENTRY = 0,
	CATALOG_ENTRY = 1,
	INSERT_TUPLE = 2,
	DELETE_TUPLE = 3,
	UPDATE_TUPLE = 4,
	SEQUENCE_VALUE = 5
};

} // namespace duckdb



namespace duckdb {
class StorageCommitState;
class WriteAheadLog;

struct UndoBufferProperties {
	idx_t estimated_size = 0;
	bool has_updates = false;
	bool has_deletes = false;
	bool has_catalog_changes = false;
	bool has_dropped_entries = false;
};

//! The undo buffer of a transaction is used to hold previous versions of tuples
//! that might be required in the future (because of rollbacks or previous
//! transactions accessing them)
class UndoBuffer {
public:
	struct IteratorState {
		ArenaChunk *current;
		data_ptr_t start;
		data_ptr_t end;
	};

public:
	explicit UndoBuffer(ClientContext &context);

	//! Reserve space for an entry of the specified type and length in the undo
	//! buffer
	data_ptr_t CreateEntry(UndoFlags type, idx_t len);

	bool ChangesMade();
	UndoBufferProperties GetProperties();

	//! Cleanup the undo buffer
	void Cleanup(transaction_t lowest_active_transaction);
	//! Commit the changes made in the UndoBuffer: should be called on commit
	void WriteToWAL(WriteAheadLog &wal, optional_ptr<StorageCommitState> commit_state);
	//! Commit the changes made in the UndoBuffer: should be called on commit
	void Commit(UndoBuffer::IteratorState &iterator_state, transaction_t commit_id);
	//! Revert committed changes made in the UndoBuffer up until the currently committed state
	void RevertCommit(UndoBuffer::IteratorState &iterator_state, transaction_t transaction_id);
	//! Rollback the changes made in this UndoBuffer: should be called on
	//! rollback
	void Rollback() noexcept;

private:
	ArenaAllocator allocator;

private:
	template <class T>
	void IterateEntries(UndoBuffer::IteratorState &state, T &&callback);
	template <class T>
	void IterateEntries(UndoBuffer::IteratorState &state, UndoBuffer::IteratorState &end_state, T &&callback);
	template <class T>
	void ReverseIterateEntries(T &&callback);
};

} // namespace duckdb


//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/transaction/transaction_data.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {
class DuckTransaction;
class Transaction;

struct TransactionData {
	TransactionData(DuckTransaction &transaction_p); // NOLINT: allow implicit conversion
	TransactionData(transaction_t transaction_id_p, transaction_t start_time_p);

	optional_ptr<DuckTransaction> transaction;
	transaction_t transaction_id;
	transaction_t start_time;
};

} // namespace duckdb



namespace duckdb {
class SequenceCatalogEntry;
class SchemaCatalogEntry;

class AttachedDatabase;
class ColumnData;
class ClientContext;
class CatalogEntry;
class DataTable;
class DatabaseInstance;
class LocalStorage;
class MetaTransaction;
class TransactionManager;
class WriteAheadLog;

class ChunkVectorInfo;

struct DeleteInfo;
struct UpdateInfo;

//! The transaction object holds information about a currently running or past
//! transaction
class Transaction {
public:
	DUCKDB_API Transaction(TransactionManager &manager, ClientContext &context);
	DUCKDB_API virtual ~Transaction();

	TransactionManager &manager;
	weak_ptr<ClientContext> context;
	//! The current active query for the transaction. Set to MAXIMUM_QUERY_ID if
	//! no query is active.
	atomic<transaction_t> active_query;

public:
	DUCKDB_API static Transaction &Get(ClientContext &context, AttachedDatabase &db);
	DUCKDB_API static Transaction &Get(ClientContext &context, Catalog &catalog);
	//! Returns the transaction for the given context if it has already been started
	DUCKDB_API static optional_ptr<Transaction> TryGet(ClientContext &context, AttachedDatabase &db);

	//! Whether or not the transaction has made any modifications to the database so far
	DUCKDB_API bool IsReadOnly();
	//! Promotes the transaction to a read-write transaction
	DUCKDB_API virtual void SetReadWrite();

	virtual bool IsDuckTransaction() const {
		return false;
	}

public:
	template <class TARGET>
	TARGET &Cast() {
		DynamicCastCheck<TARGET>(this);
		return reinterpret_cast<TARGET &>(*this);
	}
	template <class TARGET>
	const TARGET &Cast() const {
		DynamicCastCheck<TARGET>(this);
		return reinterpret_cast<const TARGET &>(*this);
	}

private:
	bool is_read_only;
};

} // namespace duckdb


//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/catalog/similar_catalog_entry.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {
class SchemaCatalogEntry;

//! Return value of SimilarEntryInSchemas
struct SimilarCatalogEntry {
	//! The entry name. Empty if absent
	string name;
	//! The similarity score of the given name (between 0.0 and 1.0, higher is better)
	double score = 0.0;
	//! The schema of the entry.
	optional_ptr<SchemaCatalogEntry> schema;

	bool Found() const {
		return !name.empty();
	}

	DUCKDB_API string GetQualifiedName(bool qualify_catalog, bool qualify_schema) const;
};

} // namespace duckdb

#include <functional>
#include <memory>

namespace duckdb {
struct AlterInfo;

class ClientContext;
class LogicalDependencyList;

class DuckCatalog;
class TableCatalogEntry;
class SequenceCatalogEntry;

class CatalogEntryMap {
public:
	CatalogEntryMap() {
	}

public:
	void AddEntry(unique_ptr<CatalogEntry> entry);
	void UpdateEntry(unique_ptr<CatalogEntry> entry);
	void DropEntry(CatalogEntry &entry);
	case_insensitive_tree_t<unique_ptr<CatalogEntry>> &Entries();
	optional_ptr<CatalogEntry> GetEntry(const string &name);

private:
	//! Mapping of string to catalog entry
	case_insensitive_tree_t<unique_ptr<CatalogEntry>> entries;
};

//! The Catalog Set stores (key, value) map of a set of CatalogEntries
class CatalogSet {
public:
	struct EntryLookup {
		enum class FailureReason { SUCCESS, DELETED, NOT_PRESENT };
		optional_ptr<CatalogEntry> result;
		FailureReason reason;
	};

public:
	DUCKDB_API explicit CatalogSet(Catalog &catalog, unique_ptr<DefaultGenerator> defaults = nullptr);
	~CatalogSet();

	//! Create an entry in the catalog set. Returns whether or not it was
	//! successful.
	DUCKDB_API bool CreateEntry(CatalogTransaction transaction, const string &name, unique_ptr<CatalogEntry> value,
	                            const LogicalDependencyList &dependencies);
	DUCKDB_API bool CreateEntry(ClientContext &context, const string &name, unique_ptr<CatalogEntry> value,
	                            const LogicalDependencyList &dependencies);

	DUCKDB_API bool AlterEntry(CatalogTransaction transaction, const string &name, AlterInfo &alter_info);

	DUCKDB_API bool DropEntry(CatalogTransaction transaction, const string &name, bool cascade,
	                          bool allow_drop_internal = false);
	DUCKDB_API bool DropEntry(ClientContext &context, const string &name, bool cascade,
	                          bool allow_drop_internal = false);

	DUCKDB_API DuckCatalog &GetCatalog();

	bool AlterOwnership(CatalogTransaction transaction, ChangeOwnershipInfo &info);

	void CleanupEntry(CatalogEntry &catalog_entry);

	//! Returns the entry with the specified name
	DUCKDB_API EntryLookup GetEntryDetailed(CatalogTransaction transaction, const string &name);
	DUCKDB_API optional_ptr<CatalogEntry> GetEntry(CatalogTransaction transaction, const string &name);
	DUCKDB_API optional_ptr<CatalogEntry> GetEntry(ClientContext &context, const string &name);

	//! Gets the entry that is most similar to the given name (i.e. smallest levenshtein distance), or empty string if
	//! none is found. The returned pair consists of the entry name and the distance (smaller means closer).
	SimilarCatalogEntry SimilarEntry(CatalogTransaction transaction, const string &name);

	//! Rollback <entry> to be the currently valid entry for a certain catalog
	//! entry
	void Undo(CatalogEntry &entry);

	//! Scan the catalog set, invoking the callback method for every committed entry
	DUCKDB_API void Scan(const std::function<void(CatalogEntry &)> &callback);
	//! Scan the catalog set, invoking the callback method for every entry
	DUCKDB_API void ScanWithPrefix(CatalogTransaction transaction, const std::function<void(CatalogEntry &)> &callback,
	                               const string &prefix);
	DUCKDB_API void Scan(CatalogTransaction transaction, const std::function<void(CatalogEntry &)> &callback);
	DUCKDB_API void Scan(ClientContext &context, const std::function<void(CatalogEntry &)> &callback);

	template <class T>
	vector<reference<T>> GetEntries(CatalogTransaction transaction) {
		vector<reference<T>> result;
		Scan(transaction, [&](CatalogEntry &entry) { result.push_back(entry.Cast<T>()); });
		return result;
	}

	DUCKDB_API bool CreatedByOtherActiveTransaction(CatalogTransaction transaction, transaction_t timestamp);
	DUCKDB_API bool CommittedAfterStarting(CatalogTransaction transaction, transaction_t timestamp);
	DUCKDB_API bool HasConflict(CatalogTransaction transaction, transaction_t timestamp);
	DUCKDB_API bool UseTimestamp(CatalogTransaction transaction, transaction_t timestamp);

	void UpdateTimestamp(CatalogEntry &entry, transaction_t timestamp);

	mutex &GetCatalogLock() {
		return catalog_lock;
	}

	void Verify(Catalog &catalog);

private:
	bool DropDependencies(CatalogTransaction transaction, const string &name, bool cascade,
	                      bool allow_drop_internal = false);
	//! Given a root entry, gets the entry valid for this transaction
	CatalogEntry &GetEntryForTransaction(CatalogTransaction transaction, CatalogEntry &current);
	CatalogEntry &GetCommittedEntry(CatalogEntry &current);
	optional_ptr<CatalogEntry> GetEntryInternal(CatalogTransaction transaction, const string &name);
	optional_ptr<CatalogEntry> CreateCommittedEntry(unique_ptr<CatalogEntry> entry);

	//! Create all default entries
	void CreateDefaultEntries(CatalogTransaction transaction, unique_lock<mutex> &lock);
	//! Attempt to create a default entry with the specified name. Returns the entry if successful, nullptr otherwise.
	optional_ptr<CatalogEntry> CreateDefaultEntry(CatalogTransaction transaction, const string &name,
	                                              unique_lock<mutex> &lock);

	bool DropEntryInternal(CatalogTransaction transaction, const string &name, bool allow_drop_internal = false);

	bool CreateEntryInternal(CatalogTransaction transaction, const string &name, unique_ptr<CatalogEntry> value,
	                         unique_lock<mutex> &read_lock, bool should_be_empty = true);
	void CheckCatalogEntryInvariants(CatalogEntry &value, const string &name);
	//! Verify that the previous entry in the chain is dropped.
	bool VerifyVacancy(CatalogTransaction transaction, CatalogEntry &entry);
	//! Start the catalog entry chain with a dummy node
	bool StartChain(CatalogTransaction transaction, const string &name, unique_lock<mutex> &read_lock);
	bool RenameEntryInternal(CatalogTransaction transaction, CatalogEntry &old, const string &new_name,
	                         AlterInfo &alter_info, unique_lock<mutex> &read_lock);

private:
	DuckCatalog &catalog;
	//! The catalog lock is used to make changes to the data
	mutex catalog_lock;
	CatalogEntryMap map;
	//! The generator used to generate default internal entries
	unique_ptr<DefaultGenerator> defaults;
};
} // namespace duckdb



namespace duckdb {
class ClientContext;

class StandardEntry;
class TableCatalogEntry;
class TableFunctionCatalogEntry;
class SequenceCatalogEntry;

enum class OnCreateConflict : uint8_t;

struct AlterTableInfo;
struct CreateIndexInfo;
struct CreateFunctionInfo;
struct CreateCollationInfo;
struct CreateViewInfo;
struct BoundCreateTableInfo;
struct CreatePragmaFunctionInfo;
struct CreateSequenceInfo;
struct CreateSchemaInfo;
struct CreateTableFunctionInfo;
struct CreateCopyFunctionInfo;
struct CreateTypeInfo;

struct DropInfo;

//! A schema in the catalog
class SchemaCatalogEntry : public InCatalogEntry {
public:
	static constexpr const CatalogType Type = CatalogType::SCHEMA_ENTRY;
	static constexpr const char *Name = "schema";

public:
	SchemaCatalogEntry(Catalog &catalog, CreateSchemaInfo &info);

public:
	unique_ptr<CreateInfo> GetInfo() const override;

	//! Scan the specified catalog set, invoking the callback method for every entry
	virtual void Scan(ClientContext &context, CatalogType type,
	                  const std::function<void(CatalogEntry &)> &callback) = 0;
	//! Scan the specified catalog set, invoking the callback method for every committed entry
	virtual void Scan(CatalogType type, const std::function<void(CatalogEntry &)> &callback) = 0;

	string ToSQL() const override;

	//! Creates an index with the given name in the schema
	virtual optional_ptr<CatalogEntry> CreateIndex(CatalogTransaction transaction, CreateIndexInfo &info,
	                                               TableCatalogEntry &table) = 0;
	optional_ptr<CatalogEntry> CreateIndex(ClientContext &context, CreateIndexInfo &info, TableCatalogEntry &table);
	//! Create a scalar or aggregate function within the given schema
	virtual optional_ptr<CatalogEntry> CreateFunction(CatalogTransaction transaction, CreateFunctionInfo &info) = 0;
	//! Creates a table with the given name in the schema
	virtual optional_ptr<CatalogEntry> CreateTable(CatalogTransaction transaction, BoundCreateTableInfo &info) = 0;
	//! Creates a view with the given name in the schema
	virtual optional_ptr<CatalogEntry> CreateView(CatalogTransaction transaction, CreateViewInfo &info) = 0;
	//! Creates a sequence with the given name in the schema
	virtual optional_ptr<CatalogEntry> CreateSequence(CatalogTransaction transaction, CreateSequenceInfo &info) = 0;
	//! Create a table function within the given schema
	virtual optional_ptr<CatalogEntry> CreateTableFunction(CatalogTransaction transaction,
	                                                       CreateTableFunctionInfo &info) = 0;
	//! Create a copy function within the given schema
	virtual optional_ptr<CatalogEntry> CreateCopyFunction(CatalogTransaction transaction,
	                                                      CreateCopyFunctionInfo &info) = 0;
	//! Create a pragma function within the given schema
	virtual optional_ptr<CatalogEntry> CreatePragmaFunction(CatalogTransaction transaction,
	                                                        CreatePragmaFunctionInfo &info) = 0;
	//! Create a collation within the given schema
	virtual optional_ptr<CatalogEntry> CreateCollation(CatalogTransaction transaction, CreateCollationInfo &info) = 0;
	//! Create a enum within the given schema
	virtual optional_ptr<CatalogEntry> CreateType(CatalogTransaction transaction, CreateTypeInfo &info) = 0;

	DUCKDB_API virtual optional_ptr<CatalogEntry> GetEntry(CatalogTransaction transaction, CatalogType type,
	                                                       const string &name) = 0;
	DUCKDB_API virtual SimilarCatalogEntry GetSimilarEntry(CatalogTransaction transaction, CatalogType type,
	                                                       const string &name);

	//! Drops an entry from the schema
	virtual void DropEntry(ClientContext &context, DropInfo &info) = 0;

	//! Alters a catalog entry
	virtual void Alter(CatalogTransaction transaction, AlterInfo &info) = 0;

	CatalogTransaction GetCatalogTransaction(ClientContext &context);
};
} // namespace duckdb


namespace duckdb {

class ClientContext;
class Catalog;
class CatalogEntry;

using catalog_entry_callback_t = std::function<void(CatalogEntry &)>;

// Wraps the Catalog::GetEntry method
class CatalogEntryRetriever {
public:
	explicit CatalogEntryRetriever(ClientContext &context) : context(context) {
	}
	CatalogEntryRetriever(const CatalogEntryRetriever &other) : callback(other.callback), context(other.context) {
	}

public:
	optional_ptr<CatalogEntry> GetEntry(CatalogType type, const string &catalog, const string &schema,
	                                    const string &name,
	                                    OnEntryNotFound on_entry_not_found = OnEntryNotFound::THROW_EXCEPTION,
	                                    QueryErrorContext error_context = QueryErrorContext());

	optional_ptr<CatalogEntry> GetEntry(CatalogType type, Catalog &catalog, const string &schema, const string &name,
	                                    OnEntryNotFound on_entry_not_found = OnEntryNotFound::THROW_EXCEPTION,
	                                    QueryErrorContext error_context = QueryErrorContext());

	LogicalType GetType(const string &catalog, const string &schema, const string &name,
	                    OnEntryNotFound on_entry_not_found = OnEntryNotFound::RETURN_NULL);
	LogicalType GetType(Catalog &catalog, const string &schema, const string &name,
	                    OnEntryNotFound on_entry_not_found = OnEntryNotFound::RETURN_NULL);

	optional_ptr<SchemaCatalogEntry> GetSchema(const string &catalog, const string &name,
	                                           OnEntryNotFound on_entry_not_found = OnEntryNotFound::THROW_EXCEPTION,
	                                           QueryErrorContext error_context = QueryErrorContext());

	void SetCallback(catalog_entry_callback_t callback) {
		this->callback = std::move(callback);
	}
	catalog_entry_callback_t GetCallback() {
		return callback;
	}

private:
	using catalog_entry_retrieve_func_t = std::function<optional_ptr<CatalogEntry>()>;
	optional_ptr<CatalogEntry> GetEntryInternal(const catalog_entry_retrieve_func_t &retriever) {
		auto result = retriever();
		if (!result) {
			return result;
		}
		if (callback) {
			// Call the callback if it's set
			callback(*result);
		}
		return result;
	}

private:
	//! (optional) callback, called on every succesful entry retrieval
	catalog_entry_callback_t callback = nullptr;
	ClientContext &context;
};

} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/expression/bound_lambda_expression.hpp
//
//
//===----------------------------------------------------------------------===//




//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/parser/expression/lambda_expression.hpp
//
//
//===----------------------------------------------------------------------===//







namespace duckdb {

//! LambdaExpression represents either:
//! 	1. A lambda function that can be used for, e.g., mapping an expression to a list
//! 	2. An OperatorExpression with the "->" operator (JSON)
//! Lambda expressions are written in the form of "params -> expr", e.g., "x -> x + 1"
class LambdaExpression : public ParsedExpression {
public:
	static constexpr const ExpressionClass TYPE = ExpressionClass::LAMBDA;

public:
	LambdaExpression(unique_ptr<ParsedExpression> lhs, unique_ptr<ParsedExpression> expr);

	//! The LHS of a lambda expression or the JSON "->"-operator. We need the context
	//! to determine if the LHS is a list of column references (lambda parameters) or an expression (JSON)
	unique_ptr<ParsedExpression> lhs;
	//! The lambda or JSON expression (RHS)
	unique_ptr<ParsedExpression> expr;

public:
	//! Returns a vector to the column references in the LHS expression, and fills the error message,
	//! if the LHS is not a valid lambda parameter list
	vector<reference<ParsedExpression>> ExtractColumnRefExpressions(string &error_message);
	//! Returns the error message for an invalid lambda parameter list
	static string InvalidParametersErrorMessage();
	//! Returns true, if the column_name is a lambda parameter name
	static bool IsLambdaParameter(const vector<unordered_set<string>> &lambda_params, const string &column_name);

	string ToString() const override;
	static bool Equal(const LambdaExpression &a, const LambdaExpression &b);
	hash_t Hash() const override;
	unique_ptr<ParsedExpression> Copy() const override;

	void Serialize(Serializer &serializer) const override;
	static unique_ptr<ParsedExpression> Deserialize(Deserializer &deserializer);

private:
	LambdaExpression();
};

} // namespace duckdb


namespace duckdb {

class BoundLambdaExpression : public Expression {
public:
	static constexpr const ExpressionClass TYPE = ExpressionClass::BOUND_LAMBDA;

public:
	BoundLambdaExpression(ExpressionType type_p, LogicalType return_type_p, unique_ptr<Expression> lambda_expr_p,
	                      idx_t parameter_count_p);

	//! The lambda expression that we'll use in the expression executor during execution
	unique_ptr<Expression> lambda_expr;
	//! Non-lambda constants, column references, and outer lambda parameters that we need to pass
	//! into the execution chunk
	vector<unique_ptr<Expression>> captures;
	//! The number of lhs parameters of the lambda function
	idx_t parameter_count;

public:
	string ToString() const override;
	bool Equals(const BaseExpression &other) const override;
	unique_ptr<Expression> Copy() const override;

	void Serialize(Serializer &serializer) const override;
	static unique_ptr<Expression> Deserialize(Deserializer &deserializer);
};
} // namespace duckdb




namespace duckdb {

class Binder;
class ClientContext;
class QueryNode;

class ScalarFunctionCatalogEntry;
class AggregateFunctionCatalogEntry;
class ScalarMacroCatalogEntry;
class CatalogEntry;
class SimpleFunction;

struct DummyBinding;
struct SelectBindState;

struct BoundColumnReferenceInfo {
	string name;
	optional_idx query_location;
};

struct BindResult {
	BindResult() {
	}
	explicit BindResult(const Exception &ex) : error(ex) {
	}
	explicit BindResult(const string &error_msg) : error(ExceptionType::BINDER, error_msg) {
	}
	explicit BindResult(ErrorData error) : error(std::move(error)) {
	}
	explicit BindResult(unique_ptr<Expression> expr) : expression(std::move(expr)) {
	}

	bool HasError() const {
		return error.HasError();
	}
	void SetError(const string &error_message) {
		error = ErrorData(ExceptionType::BINDER, error_message);
	}

	unique_ptr<Expression> expression;
	ErrorData error;
};

class ExpressionBinder {
	friend class StackChecker<ExpressionBinder>;

public:
	ExpressionBinder(Binder &binder, ClientContext &context, bool replace_binder = false);
	virtual ~ExpressionBinder();

	//! The target type that should result from the binder. If the result is not of this type, a cast to this type will
	//! be added. Defaults to INVALID.
	LogicalType target_type;

	optional_ptr<DummyBinding> macro_binding;
	optional_ptr<vector<DummyBinding>> lambda_bindings;

public:
	unique_ptr<Expression> Bind(unique_ptr<ParsedExpression> &expr, optional_ptr<LogicalType> result_type = nullptr,
	                            bool root_expression = true);

	//! Returns whether or not any columns have been bound by the expression binder
	bool HasBoundColumns() {
		return !bound_columns.empty();
	}
	const vector<BoundColumnReferenceInfo> &GetBoundColumns() {
		return bound_columns;
	}

	void SetCatalogLookupCallback(catalog_entry_callback_t callback);
	ErrorData Bind(unique_ptr<ParsedExpression> &expr, idx_t depth, bool root_expression = false);

	//! Returns the STRUCT_EXTRACT operator expression
	unique_ptr<ParsedExpression> CreateStructExtract(unique_ptr<ParsedExpression> base, const string &field_name);
	//! Returns a STRUCT_PACK function expression
	unique_ptr<ParsedExpression> CreateStructPack(ColumnRefExpression &col_ref);

	BindResult BindQualifiedColumnName(ColumnRefExpression &colref, const string &table_name);

	//! Returns a qualified column reference from a column name
	unique_ptr<ParsedExpression> QualifyColumnName(const string &column_name, ErrorData &error);
	//! Returns a qualified column reference from a column reference with column_names.size() > 2
	unique_ptr<ParsedExpression> QualifyColumnNameWithManyDots(ColumnRefExpression &col_ref, ErrorData &error);
	//! Returns a qualified column reference from a column reference
	unique_ptr<ParsedExpression> QualifyColumnName(ColumnRefExpression &col_ref, ErrorData &error);
	//! Enables special-handling of lambda parameters by tracking them in the lambda_params vector
	void QualifyColumnNamesInLambda(FunctionExpression &function, vector<unordered_set<string>> &lambda_params);
	//! Recursively qualifies the column references in the (children) of the expression. Passes on the
	//! within_function_expression state from outer expressions, or sets it
	void QualifyColumnNames(unique_ptr<ParsedExpression> &expr, vector<unordered_set<string>> &lambda_params,
	                        const bool within_function_expression = false);
	//! Entry point for qualifying the column references of the expression
	static void QualifyColumnNames(Binder &binder, unique_ptr<ParsedExpression> &expr);

	static bool PushCollation(ClientContext &context, unique_ptr<Expression> &source, const LogicalType &sql_type);
	static void TestCollation(ClientContext &context, const string &collation);

	BindResult BindCorrelatedColumns(unique_ptr<ParsedExpression> &expr, ErrorData error_message);

	void BindChild(unique_ptr<ParsedExpression> &expr, idx_t depth, ErrorData &error);
	static void ExtractCorrelatedExpressions(Binder &binder, Expression &expr);

	static bool ContainsNullType(const LogicalType &type);
	static LogicalType ExchangeNullType(const LogicalType &type);
	static bool ContainsType(const LogicalType &type, LogicalTypeId target);
	static LogicalType ExchangeType(const LogicalType &type, LogicalTypeId target, LogicalType new_type);

	virtual bool TryBindAlias(ColumnRefExpression &colref, bool root_expression, BindResult &result);
	virtual bool QualifyColumnAlias(const ColumnRefExpression &colref);

	//! Bind the given expression. Unlike Bind(), this does *not* mute the given ParsedExpression.
	//! Exposed to be used from sub-binders that aren't subclasses of ExpressionBinder.
	virtual BindResult BindExpression(unique_ptr<ParsedExpression> &expr_ptr, idx_t depth,
	                                  bool root_expression = false);

	//! FIXME: Generalise this for extensibility.
	//! Recursively replaces macro parameters with the provided input parameters.
	void ReplaceMacroParameters(unique_ptr<ParsedExpression> &expr, vector<unordered_set<string>> &lambda_params);
	//! Enables special-handling of lambda parameters during macro replacement by tracking them in the lambda_params
	//! vector.
	void ReplaceMacroParametersInLambda(FunctionExpression &function, vector<unordered_set<string>> &lambda_params);
	//! Recursively qualifies column references in ON CONFLICT DO UPDATE SET expressions.
	void DoUpdateSetQualify(unique_ptr<ParsedExpression> &expr, const string &table_name,
	                        vector<unordered_set<string>> &lambda_params);
	//! Enables special-handling of lambda parameters during ON CONFLICT TO UPDATE SET qualification by tracking them in
	//! the lambda_params vector.
	void DoUpdateSetQualifyInLambda(FunctionExpression &function, const string &table_name,
	                                vector<unordered_set<string>> &lambda_params);

	static LogicalType GetExpressionReturnType(const Expression &expr);

private:
	//! Current stack depth
	idx_t stack_depth = DConstants::INVALID_INDEX;

	void InitializeStackCheck();
	StackChecker<ExpressionBinder> StackCheck(const ParsedExpression &expr, idx_t extra_stack = 1);

protected:
	BindResult BindExpression(BetweenExpression &expr, idx_t depth);
	BindResult BindExpression(CaseExpression &expr, idx_t depth);
	BindResult BindExpression(CollateExpression &expr, idx_t depth);
	BindResult BindExpression(CastExpression &expr, idx_t depth);
	BindResult BindExpression(ColumnRefExpression &expr, idx_t depth, bool root_expression);
	BindResult BindExpression(LambdaRefExpression &expr, idx_t depth);
	BindResult BindExpression(ComparisonExpression &expr, idx_t depth);
	BindResult BindExpression(ConjunctionExpression &expr, idx_t depth);
	BindResult BindExpression(ConstantExpression &expr, idx_t depth);
	BindResult BindExpression(FunctionExpression &expr, idx_t depth, unique_ptr<ParsedExpression> &expr_ptr);
	BindResult BindExpression(LambdaExpression &expr, idx_t depth, const LogicalType &list_child_type,
	                          optional_ptr<bind_lambda_function_t> bind_lambda_function);
	BindResult BindExpression(OperatorExpression &expr, idx_t depth);
	BindResult BindExpression(ParameterExpression &expr, idx_t depth);
	BindResult BindExpression(SubqueryExpression &expr, idx_t depth);
	BindResult BindPositionalReference(unique_ptr<ParsedExpression> &expr, idx_t depth, bool root_expression);

	void TransformCapturedLambdaColumn(unique_ptr<Expression> &original, unique_ptr<Expression> &replacement,
	                                   BoundLambdaExpression &bound_lambda_expr,
	                                   const optional_ptr<bind_lambda_function_t> bind_lambda_function,
	                                   const LogicalType &list_child_type);
	void CaptureLambdaColumns(BoundLambdaExpression &bound_lambda_expr, unique_ptr<Expression> &expr,
	                          const optional_ptr<bind_lambda_function_t> bind_lambda_function,
	                          const LogicalType &list_child_type);

	virtual unique_ptr<ParsedExpression> GetSQLValueFunction(const string &column_name);

	LogicalType ResolveOperatorType(OperatorExpression &op, vector<unique_ptr<Expression>> &children);
	LogicalType ResolveCoalesceType(OperatorExpression &op, vector<unique_ptr<Expression>> &children);
	LogicalType ResolveNotType(OperatorExpression &op, vector<unique_ptr<Expression>> &children);

	BindResult BindUnsupportedExpression(ParsedExpression &expr, idx_t depth, const string &message);

protected:
	virtual BindResult BindGroupingFunction(OperatorExpression &op, idx_t depth);
	virtual BindResult BindFunction(FunctionExpression &expr, ScalarFunctionCatalogEntry &function, idx_t depth);
	virtual BindResult BindLambdaFunction(FunctionExpression &expr, ScalarFunctionCatalogEntry &function, idx_t depth);
	virtual BindResult BindAggregate(FunctionExpression &expr, AggregateFunctionCatalogEntry &function, idx_t depth);
	virtual BindResult BindUnnest(FunctionExpression &expr, idx_t depth, bool root_expression);
	virtual BindResult BindMacro(FunctionExpression &expr, ScalarMacroCatalogEntry &macro, idx_t depth,
	                             unique_ptr<ParsedExpression> &expr_ptr);
	void UnfoldMacroExpression(FunctionExpression &function, ScalarMacroCatalogEntry &macro_func,
	                           unique_ptr<ParsedExpression> &expr);

	virtual string UnsupportedAggregateMessage();
	virtual string UnsupportedUnnestMessage();
	optional_ptr<CatalogEntry> GetCatalogEntry(CatalogType type, const string &catalog, const string &schema,
	                                           const string &name, OnEntryNotFound on_entry_not_found,
	                                           QueryErrorContext &error_context);

	Binder &binder;
	ClientContext &context;
	optional_ptr<ExpressionBinder> stored_binder;
	vector<BoundColumnReferenceInfo> bound_columns;

	//! Returns true if the function name is an alias for the UNNEST function
	static bool IsUnnestFunction(const string &function_name);
	BindResult TryBindLambdaOrJson(FunctionExpression &function, idx_t depth, CatalogEntry &func);
	virtual void ThrowIfUnnestInLambda(const ColumnBinding &column_binding);
};

} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/table_binding.hpp
//
//
//===----------------------------------------------------------------------===//










namespace duckdb {
class BindContext;
class BoundQueryNode;
class ColumnRefExpression;
class SubqueryRef;
class LogicalGet;
class TableCatalogEntry;
class TableFunctionCatalogEntry;
class BoundTableFunction;
class StandardEntry;
struct ColumnBinding;

enum class BindingType { BASE, TABLE, DUMMY, CATALOG_ENTRY };

//! A Binding represents a binding to a table, table-producing function or subquery with a specified table index.
struct Binding {
	Binding(BindingType binding_type, const string &alias, vector<LogicalType> types, vector<string> names,
	        idx_t index);
	virtual ~Binding() = default;

	//! The type of Binding
	BindingType binding_type;
	//! The alias of the binding
	string alias;
	//! The table index of the binding
	idx_t index;
	//! The types of the bound columns
	vector<LogicalType> types;
	//! Column names of the subquery
	vector<string> names;
	//! Name -> index for the names
	case_insensitive_map_t<column_t> name_map;

public:
	bool TryGetBindingIndex(const string &column_name, column_t &column_index);
	column_t GetBindingIndex(const string &column_name);
	bool HasMatchingBinding(const string &column_name);
	virtual ErrorData ColumnNotFoundError(const string &column_name) const;
	virtual BindResult Bind(ColumnRefExpression &colref, idx_t depth);
	virtual optional_ptr<StandardEntry> GetStandardEntry();

public:
	template <class TARGET>
	TARGET &Cast() {
		if (binding_type != TARGET::TYPE) {
			throw InternalException("Failed to cast binding to type - binding type mismatch");
		}
		return reinterpret_cast<TARGET &>(*this);
	}

	template <class TARGET>
	const TARGET &Cast() const {
		if (binding_type != TARGET::TYPE) {
			throw InternalException("Failed to cast binding to type - binding type mismatch");
		}
		return reinterpret_cast<const TARGET &>(*this);
	}
};

struct EntryBinding : public Binding {
public:
	static constexpr const BindingType TYPE = BindingType::CATALOG_ENTRY;

public:
	EntryBinding(const string &alias, vector<LogicalType> types, vector<string> names, idx_t index,
	             StandardEntry &entry);
	StandardEntry &entry;

public:
	optional_ptr<StandardEntry> GetStandardEntry() override;
};

//! TableBinding is exactly like the Binding, except it keeps track of which columns were bound in the linked LogicalGet
//! node for projection pushdown purposes.
struct TableBinding : public Binding {
public:
	static constexpr const BindingType TYPE = BindingType::TABLE;

public:
	TableBinding(const string &alias, vector<LogicalType> types, vector<string> names,
	             vector<column_t> &bound_column_ids, optional_ptr<StandardEntry> entry, idx_t index,
	             bool add_row_id = false);

	//! A reference to the set of bound column ids
	vector<column_t> &bound_column_ids;
	//! The underlying catalog entry (if any)
	optional_ptr<StandardEntry> entry;

public:
	unique_ptr<ParsedExpression> ExpandGeneratedColumn(const string &column_name);
	BindResult Bind(ColumnRefExpression &colref, idx_t depth) override;
	optional_ptr<StandardEntry> GetStandardEntry() override;
	ErrorData ColumnNotFoundError(const string &column_name) const override;
	// These are columns that are present in the name_map, appearing in the order that they're bound
	const vector<column_t> &GetBoundColumnIds() const;

protected:
	ColumnBinding GetColumnBinding(column_t column_index);
};

//! DummyBinding is like the Binding, except the alias and index are set by default.
//! Used for binding lambdas and macro parameters.
struct DummyBinding : public Binding {
public:
	static constexpr const BindingType TYPE = BindingType::DUMMY;
	// NOTE: changing this string conflicts with the storage version
	static constexpr const char *DUMMY_NAME = "0_macro_parameters";

public:
	DummyBinding(vector<LogicalType> types, vector<string> names, string dummy_name);

	//! Arguments (for macros)
	vector<unique_ptr<ParsedExpression>> *arguments;
	//! The name of the dummy binding
	string dummy_name;

public:
	//! Binding macros
	BindResult Bind(ColumnRefExpression &col_ref, idx_t depth) override;
	//! Binding lambdas
	BindResult Bind(LambdaRefExpression &lambda_ref, idx_t depth);

	//! Returns a copy of the col_ref parameter as a parsed expression
	unique_ptr<ParsedExpression> ParamToArg(ColumnRefExpression &col_ref);
};

} // namespace duckdb


namespace duckdb {
class Binder;
class LogicalGet;
class BoundQueryNode;

class StarExpression;

class TableCatalogEntry;
class TableFunctionCatalogEntry;

struct UsingColumnSet {
	string primary_binding;
	unordered_set<string> bindings;
};

//! The BindContext object keeps track of all the tables and columns that are
//! encountered during the binding process.
class BindContext {
public:
	explicit BindContext(Binder &binder);

	//! Keep track of recursive CTE references
	case_insensitive_map_t<shared_ptr<idx_t>> cte_references;

public:
	//! Given a column name, find the matching table it belongs to. Throws an
	//! exception if no table has a column of the given name.
	string GetMatchingBinding(const string &column_name);
	//! Like GetMatchingBinding, but instead of throwing an error if multiple tables have the same binding it will
	//! return a list of all the matching ones
	unordered_set<string> GetMatchingBindings(const string &column_name);
	//! Like GetMatchingBindings, but returns the top 3 most similar bindings (in levenshtein distance) instead of the
	//! matching ones
	vector<string> GetSimilarBindings(const string &column_name);

	optional_ptr<Binding> GetCTEBinding(const string &ctename);
	//! Binds a column expression to the base table. Returns the bound expression
	//! or throws an exception if the column could not be bound.
	BindResult BindColumn(ColumnRefExpression &colref, idx_t depth);
	string BindColumn(PositionalReferenceExpression &ref, string &table_name, string &column_name);
	unique_ptr<ColumnRefExpression> PositionToColumn(PositionalReferenceExpression &ref);

	unique_ptr<ParsedExpression> ExpandGeneratedColumn(const string &table_name, const string &column_name);

	unique_ptr<ParsedExpression> CreateColumnReference(const string &table_name, const string &column_name);
	unique_ptr<ParsedExpression> CreateColumnReference(const string &schema_name, const string &table_name,
	                                                   const string &column_name);
	unique_ptr<ParsedExpression> CreateColumnReference(const string &catalog_name, const string &schema_name,
	                                                   const string &table_name, const string &column_name);

	//! Generate column expressions for all columns that are present in the
	//! referenced tables. This is used to resolve the * expression in a
	//! selection list.
	void GenerateAllColumnExpressions(StarExpression &expr, vector<unique_ptr<ParsedExpression>> &new_select_list);
	//! Check if the given (binding, column_name) is in the exclusion/replacement lists.
	//! Returns true if it is in one of these lists, and should therefore be skipped.
	bool CheckExclusionList(StarExpression &expr, const string &column_name,
	                        vector<unique_ptr<ParsedExpression>> &new_select_list,
	                        case_insensitive_set_t &excluded_columns);

	const vector<reference<Binding>> &GetBindingsList() {
		return bindings_list;
	}

	void GetTypesAndNames(vector<string> &result_names, vector<LogicalType> &result_types);

	//! Adds a base table with the given alias to the BindContext.
	void AddBaseTable(idx_t index, const string &alias, const vector<string> &names, const vector<LogicalType> &types,
	                  vector<column_t> &bound_column_ids, StandardEntry *entry, bool add_row_id = true);
	//! Adds a call to a table function with the given alias to the BindContext.
	void AddTableFunction(idx_t index, const string &alias, const vector<string> &names,
	                      const vector<LogicalType> &types, vector<column_t> &bound_column_ids, StandardEntry *entry);
	//! Adds a table view with a given alias to the BindContext.
	void AddView(idx_t index, const string &alias, SubqueryRef &ref, BoundQueryNode &subquery, ViewCatalogEntry *view);
	//! Adds a subquery with a given alias to the BindContext.
	void AddSubquery(idx_t index, const string &alias, SubqueryRef &ref, BoundQueryNode &subquery);
	//! Adds a subquery with a given alias to the BindContext.
	void AddSubquery(idx_t index, const string &alias, TableFunctionRef &ref, BoundQueryNode &subquery);
	//! Adds a binding to a catalog entry with a given alias to the BindContext.
	void AddEntryBinding(idx_t index, const string &alias, const vector<string> &names,
	                     const vector<LogicalType> &types, StandardEntry &entry);
	//! Adds a base table with the given alias to the BindContext.
	void AddGenericBinding(idx_t index, const string &alias, const vector<string> &names,
	                       const vector<LogicalType> &types);

	//! Adds a base table with the given alias to the CTE BindContext.
	//! We need this to correctly bind recursive CTEs with multiple references.
	void AddCTEBinding(idx_t index, const string &alias, const vector<string> &names, const vector<LogicalType> &types);

	//! Add an implicit join condition (e.g. USING (x))
	void AddUsingBinding(const string &column_name, UsingColumnSet &set);

	void AddUsingBindingSet(unique_ptr<UsingColumnSet> set);

	//! Returns any using column set for the given column name, or nullptr if there is none. On conflict (multiple using
	//! column sets with the same name) throw an exception.
	optional_ptr<UsingColumnSet> GetUsingBinding(const string &column_name);
	//! Returns any using column set for the given column name, or nullptr if there is none
	optional_ptr<UsingColumnSet> GetUsingBinding(const string &column_name, const string &binding_name);
	//! Erase a using binding from the set of using bindings
	void RemoveUsingBinding(const string &column_name, UsingColumnSet &set);
	//! Transfer a using binding from one bind context to this bind context
	void TransferUsingBinding(BindContext &current_context, optional_ptr<UsingColumnSet> current_set,
	                          UsingColumnSet &new_set, const string &binding, const string &using_column);

	//! Fetch the actual column name from the given binding, or throws if none exists
	//! This can be different from "column_name" because of case insensitivity
	//! (e.g. "column_name" might return "COLUMN_NAME")
	string GetActualColumnName(const string &binding, const string &column_name);

	case_insensitive_map_t<shared_ptr<Binding>> GetCTEBindings() {
		return cte_bindings;
	}
	void SetCTEBindings(case_insensitive_map_t<shared_ptr<Binding>> bindings) {
		cte_bindings = std::move(bindings);
	}

	//! Alias a set of column names for the specified table, using the original names if there are not enough aliases
	//! specified.
	static vector<string> AliasColumnNames(const string &table_name, const vector<string> &names,
	                                       const vector<string> &column_aliases);

	//! Add all the bindings from a BindContext to this BindContext. The other BindContext is destroyed in the process.
	void AddContext(BindContext other);
	//! For semi and anti joins we remove the binding context of the right table after binding the condition.
	void RemoveContext(vector<reference<Binding>> &other_bindings_list);

	//! Gets a binding of the specified name. Returns a nullptr and sets the out_error if the binding could not be
	//! found.
	optional_ptr<Binding> GetBinding(const string &name, ErrorData &out_error);

private:
	void AddBinding(const string &alias, unique_ptr<Binding> binding);

private:
	Binder &binder;
	//! The set of bindings
	case_insensitive_map_t<unique_ptr<Binding>> bindings;
	//! The list of bindings in insertion order
	vector<reference<Binding>> bindings_list;
	//! The set of columns used in USING join conditions
	case_insensitive_map_t<reference_set_t<UsingColumnSet>> using_columns;
	//! Using column sets
	vector<unique_ptr<UsingColumnSet>> using_column_sets;

	//! The set of CTE bindings
	case_insensitive_map_t<shared_ptr<Binding>> cte_bindings;
};
} // namespace duckdb




#include <functional>

namespace duckdb {

class BaseStatistics;
class LogicalDependencyList;
class LogicalGet;
class TableFilterSet;
class TableCatalogEntry;
struct MultiFileReader;

struct TableFunctionInfo {
	DUCKDB_API virtual ~TableFunctionInfo();

	template <class TARGET>
	TARGET &Cast() {
		DynamicCastCheck<TARGET>(this);
		return reinterpret_cast<TARGET &>(*this);
	}
	template <class TARGET>
	const TARGET &Cast() const {
		DynamicCastCheck<TARGET>(this);
		return reinterpret_cast<const TARGET &>(*this);
	}
};

struct GlobalTableFunctionState {
public:
	// value returned from MaxThreads when as many threads as possible should be used
	constexpr static const int64_t MAX_THREADS = 999999999;

public:
	DUCKDB_API virtual ~GlobalTableFunctionState();

	virtual idx_t MaxThreads() const {
		return 1;
	}

	template <class TARGET>
	TARGET &Cast() {
		DynamicCastCheck<TARGET>(this);
		return reinterpret_cast<TARGET &>(*this);
	}
	template <class TARGET>
	const TARGET &Cast() const {
		DynamicCastCheck<TARGET>(this);
		return reinterpret_cast<const TARGET &>(*this);
	}
};

struct LocalTableFunctionState {
	DUCKDB_API virtual ~LocalTableFunctionState();

	template <class TARGET>
	TARGET &Cast() {
		DynamicCastCheck<TARGET>(this);
		return reinterpret_cast<TARGET &>(*this);
	}
	template <class TARGET>
	const TARGET &Cast() const {
		DynamicCastCheck<TARGET>(this);
		return reinterpret_cast<const TARGET &>(*this);
	}
};

struct TableFunctionBindInput {
	TableFunctionBindInput(vector<Value> &inputs, named_parameter_map_t &named_parameters,
	                       vector<LogicalType> &input_table_types, vector<string> &input_table_names,
	                       optional_ptr<TableFunctionInfo> info, optional_ptr<Binder> binder,
	                       TableFunction &table_function, const TableFunctionRef &ref)
	    : inputs(inputs), named_parameters(named_parameters), input_table_types(input_table_types),
	      input_table_names(input_table_names), info(info), binder(binder), table_function(table_function), ref(ref) {
	}

	vector<Value> &inputs;
	named_parameter_map_t &named_parameters;
	vector<LogicalType> &input_table_types;
	vector<string> &input_table_names;
	optional_ptr<TableFunctionInfo> info;
	optional_ptr<Binder> binder;
	TableFunction &table_function;
	const TableFunctionRef &ref;
};

struct TableFunctionInitInput {
	TableFunctionInitInput(optional_ptr<const FunctionData> bind_data_p, const vector<column_t> &column_ids_p,
	                       const vector<idx_t> &projection_ids_p, optional_ptr<TableFilterSet> filters_p)
	    : bind_data(bind_data_p), column_ids(column_ids_p), projection_ids(projection_ids_p), filters(filters_p) {
	}

	optional_ptr<const FunctionData> bind_data;
	const vector<column_t> &column_ids;
	const vector<idx_t> projection_ids;
	optional_ptr<TableFilterSet> filters;

	bool CanRemoveFilterColumns() const {
		if (projection_ids.empty()) {
			// Not set, can't remove filter columns
			return false;
		} else if (projection_ids.size() == column_ids.size()) {
			// Filter column is used in remainder of plan, can't remove
			return false;
		} else {
			// Less columns need to be projected out than that we scan
			return true;
		}
	}
};

struct TableFunctionInput {
public:
	TableFunctionInput(optional_ptr<const FunctionData> bind_data_p,
	                   optional_ptr<LocalTableFunctionState> local_state_p,
	                   optional_ptr<GlobalTableFunctionState> global_state_p)
	    : bind_data(bind_data_p), local_state(local_state_p), global_state(global_state_p) {
	}

public:
	optional_ptr<const FunctionData> bind_data;
	optional_ptr<LocalTableFunctionState> local_state;
	optional_ptr<GlobalTableFunctionState> global_state;
};

enum class ScanType : uint8_t { TABLE, PARQUET };

struct BindInfo {
public:
	explicit BindInfo(ScanType type_p) : type(type_p) {};
	explicit BindInfo(TableCatalogEntry &table) : type(ScanType::TABLE), table(&table) {};

	unordered_map<string, Value> options;
	ScanType type;
	optional_ptr<TableCatalogEntry> table;

	void InsertOption(const string &name, Value value) { // NOLINT: work-around bug in clang-tidy
		if (options.find(name) != options.end()) {
			throw InternalException("This option already exists");
		}
		options.emplace(name, std::move(value));
	}
	template <class T>
	T GetOption(const string &name) {
		if (options.find(name) == options.end()) {
			throw InternalException("This option does not exist");
		}
		return options[name].GetValue<T>();
	}
	template <class T>
	vector<T> GetOptionList(const string &name) {
		if (options.find(name) == options.end()) {
			throw InternalException("This option does not exist");
		}
		auto option = options[name];
		if (option.type().id() != LogicalTypeId::LIST) {
			throw InternalException("This option is not a list");
		}
		vector<T> result;
		auto list_children = ListValue::GetChildren(option);
		for (auto &child : list_children) {
			result.emplace_back(child.GetValue<T>());
		}
		return result;
	}
};

typedef unique_ptr<FunctionData> (*table_function_bind_t)(ClientContext &context, TableFunctionBindInput &input,
                                                          vector<LogicalType> &return_types, vector<string> &names);
typedef unique_ptr<TableRef> (*table_function_bind_replace_t)(ClientContext &context, TableFunctionBindInput &input);
typedef unique_ptr<GlobalTableFunctionState> (*table_function_init_global_t)(ClientContext &context,
                                                                             TableFunctionInitInput &input);
typedef unique_ptr<LocalTableFunctionState> (*table_function_init_local_t)(ExecutionContext &context,
                                                                           TableFunctionInitInput &input,
                                                                           GlobalTableFunctionState *global_state);
typedef unique_ptr<BaseStatistics> (*table_statistics_t)(ClientContext &context, const FunctionData *bind_data,
                                                         column_t column_index);
typedef void (*table_function_t)(ClientContext &context, TableFunctionInput &data, DataChunk &output);
typedef OperatorResultType (*table_in_out_function_t)(ExecutionContext &context, TableFunctionInput &data,
                                                      DataChunk &input, DataChunk &output);
typedef OperatorFinalizeResultType (*table_in_out_function_final_t)(ExecutionContext &context, TableFunctionInput &data,
                                                                    DataChunk &output);
typedef idx_t (*table_function_get_batch_index_t)(ClientContext &context, const FunctionData *bind_data,
                                                  LocalTableFunctionState *local_state,
                                                  GlobalTableFunctionState *global_state);

typedef BindInfo (*table_function_get_bind_info_t)(const optional_ptr<FunctionData> bind_data);

typedef unique_ptr<MultiFileReader> (*table_function_get_multi_file_reader_t)();

typedef bool (*table_function_supports_pushdown_type_t)(const LogicalType &type);

typedef double (*table_function_progress_t)(ClientContext &context, const FunctionData *bind_data,
                                            const GlobalTableFunctionState *global_state);
typedef void (*table_function_dependency_t)(LogicalDependencyList &dependencies, const FunctionData *bind_data);
typedef unique_ptr<NodeStatistics> (*table_function_cardinality_t)(ClientContext &context,
                                                                   const FunctionData *bind_data);
typedef void (*table_function_pushdown_complex_filter_t)(ClientContext &context, LogicalGet &get,
                                                         FunctionData *bind_data,
                                                         vector<unique_ptr<Expression>> &filters);
typedef string (*table_function_to_string_t)(const FunctionData *bind_data);

typedef void (*table_function_serialize_t)(Serializer &serializer, const optional_ptr<FunctionData> bind_data,
                                           const TableFunction &function);
typedef unique_ptr<FunctionData> (*table_function_deserialize_t)(Deserializer &deserializer, TableFunction &function);

typedef void (*table_function_type_pushdown_t)(ClientContext &context, optional_ptr<FunctionData> bind_data,
                                               const unordered_map<idx_t, LogicalType> &new_column_types);

//! When to call init_global to initialize the table function
enum class TableFunctionInitialization { INITIALIZE_ON_EXECUTE, INITIALIZE_ON_SCHEDULE };

class TableFunction : public SimpleNamedParameterFunction { // NOLINT: work-around bug in clang-tidy
public:
	DUCKDB_API
	TableFunction(string name, vector<LogicalType> arguments, table_function_t function,
	              table_function_bind_t bind = nullptr, table_function_init_global_t init_global = nullptr,
	              table_function_init_local_t init_local = nullptr);
	DUCKDB_API
	TableFunction(const vector<LogicalType> &arguments, table_function_t function, table_function_bind_t bind = nullptr,
	              table_function_init_global_t init_global = nullptr, table_function_init_local_t init_local = nullptr);
	DUCKDB_API TableFunction();

	//! Bind function
	//! This function is used for determining the return type of a table producing function and returning bind data
	//! The returned FunctionData object should be constant and should not be changed during execution.
	table_function_bind_t bind;
	//! (Optional) Bind replace function
	//! This function is called before the regular bind function. It allows returning a TableRef will be used to
	//! to generate a logical plan that replaces the LogicalGet of a regularly bound TableFunction. The BindReplace can
	//! also return a nullptr to indicate a regular bind needs to be performed instead.
	table_function_bind_replace_t bind_replace;
	//! (Optional) global init function
	//! Initialize the global operator state of the function.
	//! The global operator state is used to keep track of the progress in the table function and is shared between
	//! all threads working on the table function.
	table_function_init_global_t init_global;
	//! (Optional) local init function
	//! Initialize the local operator state of the function.
	//! The local operator state is used to keep track of the progress in the table function and is thread-local.
	table_function_init_local_t init_local;
	//! The main function
	table_function_t function;
	//! The table in-out function (if this is an in-out function)
	table_in_out_function_t in_out_function;
	//! The table in-out final function (if this is an in-out function)
	table_in_out_function_final_t in_out_function_final;
	//! (Optional) statistics function
	//! Returns the statistics of a specified column
	table_statistics_t statistics;
	//! (Optional) dependency function
	//! Sets up which catalog entries this table function depend on
	table_function_dependency_t dependency;
	//! (Optional) cardinality function
	//! Returns the expected cardinality of this scan
	table_function_cardinality_t cardinality;
	//! (Optional) pushdown a set of arbitrary filter expressions, rather than only simple comparisons with a constant
	//! Any functions remaining in the expression list will be pushed as a regular filter after the scan
	table_function_pushdown_complex_filter_t pushdown_complex_filter;
	//! (Optional) function for rendering the operator to a string in profiling output
	table_function_to_string_t to_string;
	//! (Optional) return how much of the table we have scanned up to this point (% of the data)
	table_function_progress_t table_scan_progress;
	//! (Optional) returns the current batch index of the current scan operator
	table_function_get_batch_index_t get_batch_index;
	//! (Optional) returns extra bind info
	table_function_get_bind_info_t get_bind_info;
	//! (Optional) pushes down type information to scanner, returns true if pushdown was successful
	table_function_type_pushdown_t type_pushdown;
	//! (Optional) allows injecting a custom MultiFileReader implementation
	table_function_get_multi_file_reader_t get_multi_file_reader;
	//! (Optional) If this scanner supports filter pushdown, but not to all data types
	table_function_supports_pushdown_type_t supports_pushdown_type;

	table_function_serialize_t serialize;
	table_function_deserialize_t deserialize;
	bool verify_serialization = true;

	//! Whether or not the table function supports projection pushdown. If not supported a projection will be added
	//! that filters out unused columns.
	bool projection_pushdown;
	//! Whether or not the table function supports filter pushdown. If not supported a filter will be added
	//! that applies the table filter directly.
	bool filter_pushdown;
	//! Whether or not the table function can immediately prune out filter columns that are unused in the remainder of
	//! the query plan, e.g., "SELECT i FROM tbl WHERE j = 42;" - j does not need to leave the table function at all
	bool filter_prune;
	//! Additional function info, passed to the bind
	shared_ptr<TableFunctionInfo> function_info;

	//! When to call init_global
	//! By default init_global is called when the pipeline is ready for execution
	//! If this is set to `INITIALIZE_ON_SCHEDULE` the table function is initialized when the query is scheduled
	TableFunctionInitialization global_initialization = TableFunctionInitialization::INITIALIZE_ON_EXECUTE;

	DUCKDB_API bool Equal(const TableFunction &rhs) const;
};

} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/parallel/task_scheduler.hpp
//
//
//===----------------------------------------------------------------------===//









namespace duckdb {

struct ConcurrentQueue;
struct QueueProducerToken;
class ClientContext;
class DatabaseInstance;
class TaskScheduler;

struct SchedulerThread;

struct ProducerToken {
	ProducerToken(TaskScheduler &scheduler, unique_ptr<QueueProducerToken> token);
	~ProducerToken();

	TaskScheduler &scheduler;
	unique_ptr<QueueProducerToken> token;
	mutex producer_lock;
};

//! The TaskScheduler is responsible for managing tasks and threads
class TaskScheduler {
	// timeout for semaphore wait, default 5ms
	constexpr static int64_t TASK_TIMEOUT_USECS = 5000;

public:
	explicit TaskScheduler(DatabaseInstance &db);
	~TaskScheduler();

	DUCKDB_API static TaskScheduler &GetScheduler(ClientContext &context);
	DUCKDB_API static TaskScheduler &GetScheduler(DatabaseInstance &db);

	unique_ptr<ProducerToken> CreateProducer();
	//! Schedule a task to be executed by the task scheduler
	void ScheduleTask(ProducerToken &producer, shared_ptr<Task> task);
	//! Fetches a task from a specific producer, returns true if successful or false if no tasks were available
	bool GetTaskFromProducer(ProducerToken &token, shared_ptr<Task> &task);
	//! Run tasks forever until "marker" is set to false, "marker" must remain valid until the thread is joined
	void ExecuteForever(atomic<bool> *marker);
	//! Run tasks until `marker` is set to false, `max_tasks` have been completed, or until there are no more tasks
	//! available. Returns the number of tasks that were completed.
	idx_t ExecuteTasks(atomic<bool> *marker, idx_t max_tasks);
	//! Run tasks until `max_tasks` have been completed, or until there are no more tasks available
	void ExecuteTasks(idx_t max_tasks);

	//! Sets the amount of background threads to be used for execution, based on the number of total threads
	//! and the number of external threads. External threads, e.g. the main thread, will also be used for execution.
	//! Launches `total_threads - external_threads` background worker threads.
	void SetThreads(idx_t total_threads, idx_t external_threads);

	void RelaunchThreads();

	//! Returns the number of threads
	DUCKDB_API int32_t NumberOfThreads();

	//! Send signals to n threads, signalling for them to wake up and attempt to execute a task
	void Signal(idx_t n);

	//! Yield to other threads
	static void YieldThread();

	//! Set the allocator flush threshold
	void SetAllocatorFlushTreshold(idx_t threshold);
	//! Sets the allocator background thread
	void SetAllocatorBackgroundThreads(bool enable);

	//! Get the number of the CPU on which the calling thread is currently executing.
	//! Fallback to calling thread id if CPU number is not available.
	//! Result do not need to be exact 'return 0' is a valid fallback strategy
	static idx_t GetEstimatedCPUId();

private:
	void RelaunchThreadsInternal(int32_t n);

private:
	DatabaseInstance &db;
	//! The task queue
	unique_ptr<ConcurrentQueue> queue;
	//! Lock for modifying the thread count
	mutex thread_lock;
	//! The active background threads of the task scheduler
	vector<unique_ptr<SchedulerThread>> threads;
	//! Markers used by the various threads, if the markers are set to "false" the thread execution is stopped
	vector<unique_ptr<atomic<bool>>> markers;
	//! The threshold after which to flush the allocator after completing a task
	atomic<idx_t> allocator_flush_threshold;
	//! Whether allocator background threads are enabled
	atomic<bool> allocator_background_threads;
	//! Requested thread count (set by the 'threads' setting)
	atomic<int32_t> requested_thread_count;
	//! The amount of threads currently running
	atomic<int32_t> current_thread_count;
};

} // namespace duckdb


//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/parallel/executor_task.hpp
//
//
//===----------------------------------------------------------------------===//




//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/parallel/event.hpp
//
//
//===----------------------------------------------------------------------===//







namespace duckdb {
class Executor;
class Task;

class Event : public enable_shared_from_this<Event> {
public:
	explicit Event(Executor &executor);
	virtual ~Event() = default;

public:
	virtual void Schedule() = 0;
	//! Called right after the event is finished
	virtual void FinishEvent() {
	}
	//! Called after the event is entirely finished
	virtual void FinalizeFinish() {
	}

	void FinishTask();
	void Finish();

	void AddDependency(Event &event);
	bool HasDependencies() const {
		return total_dependencies != 0;
	}
	const vector<reference<Event>> &GetParentsVerification() const;

	void CompleteDependency();

	void SetTasks(vector<shared_ptr<Task>> tasks);

	void InsertEvent(shared_ptr<Event> replacement_event);

	bool IsFinished() const {
		return finished;
	}

	virtual void PrintPipeline() {
	}

	template <class TARGET>
	TARGET &Cast() {
		DynamicCastCheck<TARGET>(this);
		return reinterpret_cast<TARGET &>(*this);
	}
	template <class TARGET>
	const TARGET &Cast() const {
		DynamicCastCheck<TARGET>(this);
		return reinterpret_cast<const TARGET &>(*this);
	}

protected:
	Executor &executor;
	//! The current threads working on the event
	atomic<idx_t> finished_tasks;
	//! The maximum amount of threads that can work on the event
	atomic<idx_t> total_tasks;

	//! The amount of completed dependencies
	//! The event can only be started after the dependencies have finished executing
	atomic<idx_t> finished_dependencies;
	//! The total amount of dependencies
	idx_t total_dependencies;

	//! The events that depend on this event to run
	vector<weak_ptr<Event>> parents;
	//! Raw pointers to the parents (used for verification only)
	vector<reference<Event>> parents_raw;

	//! Whether or not the event is finished executing
	atomic<bool> finished;
};

} // namespace duckdb



namespace duckdb {
class PhysicalOperator;
class ThreadContext;

//! Execute a task within an executor, including exception handling
//! This should be used within queries
class ExecutorTask : public Task {
public:
	ExecutorTask(Executor &executor, shared_ptr<Event> event);
	ExecutorTask(ClientContext &context, shared_ptr<Event> event, const PhysicalOperator &op);
	~ExecutorTask() override;

public:
	void Deschedule() override;
	void Reschedule() override;

public:
	Executor &executor;
	shared_ptr<Event> event;
	unique_ptr<ThreadContext> thread_context;
	optional_ptr<const PhysicalOperator> op;

public:
	virtual TaskExecutionResult ExecuteTask(TaskExecutionMode mode) = 0;
	TaskExecutionResult Execute(TaskExecutionMode mode) override;
};

} // namespace duckdb


namespace duckdb {

class Executor;
class Event;
class MetaPipeline;
class PipelineExecutor;
class Pipeline;

class PipelineTask : public ExecutorTask {
	static constexpr const idx_t PARTIAL_CHUNK_COUNT = 50;

public:
	explicit PipelineTask(Pipeline &pipeline_p, shared_ptr<Event> event_p);

	Pipeline &pipeline;
	unique_ptr<PipelineExecutor> pipeline_executor;

public:
	const PipelineExecutor &GetPipelineExecutor() const;
	bool TaskBlockedOnResult() const override;

public:
	TaskExecutionResult ExecuteTask(TaskExecutionMode mode) override;
};

class PipelineBuildState {
public:
	//! How much to increment batch indexes when multiple pipelines share the same source
	constexpr static idx_t BATCH_INCREMENT = 10000000000000;

public:
	//! Duplicate eliminated join scan dependencies
	reference_map_t<const PhysicalOperator, reference<Pipeline>> delim_join_dependencies;
	//! Materialized CTE scan dependencies
	reference_map_t<const PhysicalOperator, reference<Pipeline>> cte_dependencies;

public:
	void SetPipelineSource(Pipeline &pipeline, PhysicalOperator &op);
	void SetPipelineSink(Pipeline &pipeline, optional_ptr<PhysicalOperator> op, idx_t sink_pipeline_count);
	void SetPipelineOperators(Pipeline &pipeline, vector<reference<PhysicalOperator>> operators);
	void AddPipelineOperator(Pipeline &pipeline, PhysicalOperator &op);
	shared_ptr<Pipeline> CreateChildPipeline(Executor &executor, Pipeline &pipeline, PhysicalOperator &op);

	optional_ptr<PhysicalOperator> GetPipelineSource(Pipeline &pipeline);
	optional_ptr<PhysicalOperator> GetPipelineSink(Pipeline &pipeline);
	vector<reference<PhysicalOperator>> GetPipelineOperators(Pipeline &pipeline);
};

//! The Pipeline class represents an execution pipeline starting at a
class Pipeline : public enable_shared_from_this<Pipeline> {
	friend class Executor;
	friend class PipelineExecutor;
	friend class PipelineEvent;
	friend class PipelineFinishEvent;
	friend class PipelineBuildState;
	friend class MetaPipeline;

public:
	explicit Pipeline(Executor &execution_context);

	Executor &executor;

public:
	ClientContext &GetClientContext();

	void AddDependency(shared_ptr<Pipeline> &pipeline);

	void Ready();
	void Reset();
	void ResetSink();
	void ResetSource(bool force);
	void ClearSource();
	void Schedule(shared_ptr<Event> &event);
	void PrepareFinalize();

	string ToString() const;
	void Print() const;
	void PrintDependencies() const;

	//! Returns query progress
	bool GetProgress(double &current_percentage, idx_t &estimated_cardinality);

	//! Returns a list of all operators (including source and sink) involved in this pipeline
	vector<reference<PhysicalOperator>> GetOperators();
	vector<const_reference<PhysicalOperator>> GetOperators() const;

	optional_ptr<PhysicalOperator> GetSink() {
		return sink;
	}

	optional_ptr<PhysicalOperator> GetSource() {
		return source;
	}

	//! Returns whether any of the operators in the pipeline care about preserving order
	bool IsOrderDependent() const;

	//! Registers a new batch index for a pipeline executor - returns the current minimum batch index
	idx_t RegisterNewBatchIndex();

	//! Updates the batch index of a pipeline (and returns the new minimum batch index)
	idx_t UpdateBatchIndex(idx_t old_index, idx_t new_index);

private:
	//! Whether or not the pipeline has been readied
	bool ready;
	//! Whether or not the pipeline has been initialized
	atomic<bool> initialized;
	//! The source of this pipeline
	optional_ptr<PhysicalOperator> source;
	//! The chain of intermediate operators
	vector<reference<PhysicalOperator>> operators;
	//! The sink (i.e. destination) for data; this is e.g. a hash table to-be-built
	optional_ptr<PhysicalOperator> sink;

	//! The global source state
	unique_ptr<GlobalSourceState> source_state;

	//! The parent pipelines (i.e. pipelines that are dependent on this pipeline to finish)
	vector<weak_ptr<Pipeline>> parents;
	//! The dependencies of this pipeline
	vector<weak_ptr<Pipeline>> dependencies;

	//! The base batch index of this pipeline
	idx_t base_batch_index = 0;
	//! Lock for accessing the set of batch indexes
	mutex batch_lock;
	//! The set of batch indexes that are currently being processed
	//! Despite batch indexes being unique - this is a multiset
	//! The reason is that when we start a new pipeline we insert the current minimum batch index as a placeholder
	//! Which leads to duplicate entries in the set of active batch indexes
	multiset<idx_t> batch_indexes;

private:
	void ScheduleSequentialTask(shared_ptr<Event> &event);
	bool LaunchScanTasks(shared_ptr<Event> &event, idx_t max_threads);

	bool ScheduleParallel(shared_ptr<Event> &event);
};

} // namespace duckdb


#include <condition_variable>

namespace duckdb {
class ClientContext;
class DataChunk;
class PhysicalOperator;
class PipelineExecutor;
class OperatorState;
class QueryProfiler;
class ThreadContext;
class Task;

struct PipelineEventStack;
struct ProducerToken;
struct ScheduleEventData;

class Executor {
	friend class Pipeline;
	friend class PipelineTask;
	friend class PipelineBuildState;

public:
	static constexpr idx_t WAIT_TIME = 20;

public:
	explicit Executor(ClientContext &context);
	~Executor();

	ClientContext &context;

public:
	static Executor &Get(ClientContext &context);

	void Initialize(PhysicalOperator &physical_plan);
	void Initialize(unique_ptr<PhysicalOperator> physical_plan);

	void CancelTasks();
	PendingExecutionResult ExecuteTask(bool dry_run = false);
	void WaitForTask();
	void SignalTaskRescheduled(lock_guard<mutex> &);

	void Reset();

	vector<LogicalType> GetTypes();

	//! Push a new error
	void PushError(ErrorData exception);

	ErrorData GetError();

	//! True if an error has been thrown
	bool HasError();
	//! Throw the exception that was pushed using PushError.
	//! Should only be called if HasError returns true
	void ThrowException();

	//! Work on tasks for this specific executor, until there are no tasks remaining
	void WorkOnTasks();

	//! Flush a thread context into the client context
	void Flush(ThreadContext &context);

	//! Reschedules a task that was blocked
	void RescheduleTask(shared_ptr<Task> &task);

	//! Add the task to be rescheduled
	void AddToBeRescheduled(shared_ptr<Task> &task);

	//! Returns the progress of the pipelines
	bool GetPipelinesProgress(double &current_progress, uint64_t &current_cardinality, uint64_t &total_cardinality);

	void CompletePipeline() {
		completed_pipelines++;
	}
	ProducerToken &GetToken() {
		return *producer;
	}
	void AddEvent(shared_ptr<Event> event);

	void AddRecursiveCTE(PhysicalOperator &rec_cte);
	void ReschedulePipelines(const vector<shared_ptr<MetaPipeline>> &pipelines, vector<shared_ptr<Event>> &events);

	//! Whether or not the root of the pipeline is a result collector object
	bool HasResultCollector();
	//! Whether or not the root of the pipeline is a streaming result collector object
	bool HasStreamingResultCollector();
	//! Returns the query result - can only be used if `HasResultCollector` returns true
	unique_ptr<QueryResult> GetResult();

	//! Returns true if all pipelines have been completed
	bool ExecutionIsFinished();

	void RegisterTask() {
		executor_tasks++;
	}
	void UnregisterTask() {
		executor_tasks--;
	}

	idx_t GetTotalPipelines() const {
		return total_pipelines;
	}

	idx_t GetCompletedPipelines() const {
		return completed_pipelines.load();
	}

private:
	//! Check if the streaming query result is waiting to be fetched from, must hold the 'executor_lock'
	bool ResultCollectorIsBlocked();
	void InitializeInternal(PhysicalOperator &physical_plan);

	void ScheduleEvents(const vector<shared_ptr<MetaPipeline>> &meta_pipelines);
	void ScheduleEventsInternal(ScheduleEventData &event_data);

	static void VerifyScheduledEvents(const ScheduleEventData &event_data);
	static void VerifyScheduledEventsInternal(const idx_t i, const vector<reference<Event>> &vertices,
	                                          vector<bool> &visited, vector<bool> &recursion_stack);

	void SchedulePipeline(const shared_ptr<MetaPipeline> &pipeline, ScheduleEventData &event_data);

	bool NextExecutor();

	shared_ptr<Pipeline> CreateChildPipeline(Pipeline &current, PhysicalOperator &op);

	void VerifyPipeline(Pipeline &pipeline);
	void VerifyPipelines();

private:
	optional_ptr<PhysicalOperator> physical_plan;
	unique_ptr<PhysicalOperator> owned_plan;

	mutex executor_lock;
	//! All pipelines of the query plan
	vector<shared_ptr<Pipeline>> pipelines;
	//! The root pipelines of the query
	vector<shared_ptr<Pipeline>> root_pipelines;
	//! The recursive CTE's in this query plan
	vector<reference<PhysicalOperator>> recursive_ctes;
	//! The pipeline executor for the root pipeline
	unique_ptr<PipelineExecutor> root_executor;
	//! The current root pipeline index
	idx_t root_pipeline_idx;
	//! The producer of this query
	unique_ptr<ProducerToken> producer;
	//! List of events
	vector<shared_ptr<Event>> events;
	//! The query profiler
	shared_ptr<QueryProfiler> profiler;
	//! Task error manager
	TaskErrorManager error_manager;

	//! The amount of completed pipelines of the query
	atomic<idx_t> completed_pipelines;
	//! The total amount of pipelines in the query
	idx_t total_pipelines;
	//! Whether or not execution is cancelled
	bool cancelled;

	//! The last pending execution result (if any)
	PendingExecutionResult execution_result;
	//! The current task in process (if any)
	shared_ptr<Task> task;

	//! Task that have been descheduled
	unordered_map<Task *, shared_ptr<Task>> to_be_rescheduled_tasks;
	//! The semaphore to signal task rescheduling
	std::condition_variable task_reschedule;

	//! Currently alive executor tasks
	atomic<idx_t> executor_tasks;

	//! Total time blocked while waiting on tasks. In ticks. One tick corresponds to WAIT_TIME.
	atomic<idx_t> blocked_thread_time;
};
} // namespace duckdb


namespace duckdb {
class ClientContext;
class ClientContextLock;
class PreparedStatementData;

class PendingQueryResult : public BaseQueryResult {
	friend class ClientContext;

public:
	static constexpr const QueryResultType TYPE = QueryResultType::PENDING_RESULT;

public:
	DUCKDB_API PendingQueryResult(shared_ptr<ClientContext> context, PreparedStatementData &statement,
	                              vector<LogicalType> types, bool allow_stream_result);
	DUCKDB_API explicit PendingQueryResult(ErrorData error_message);
	DUCKDB_API ~PendingQueryResult() override;
	DUCKDB_API bool AllowStreamResult() const;

public:
	//! Executes a single task within the query, returning whether or not the query is ready.
	//! If this returns RESULT_READY, the Execute function can be called to obtain a pointer to the result.
	//! If this returns RESULT_NOT_READY, the ExecuteTask function should be called again.
	//! If this returns EXECUTION_ERROR, an error occurred during execution.
	//! If this returns NO_TASKS_AVAILABLE, this means currently no meaningful work can be done by the current executor,
	//!	    but tasks may become available in the future.
	//! The error message can be obtained by calling GetError() on the PendingQueryResult.
	DUCKDB_API PendingExecutionResult ExecuteTask();
	DUCKDB_API PendingExecutionResult CheckPulse();
	//! Halt execution of the thread until a Task is ready to be executed (use with caution)
	void WaitForTask();

	//! Returns the result of the query as an actual query result.
	//! This returns (mostly) instantly if ExecuteTask has been called until RESULT_READY was returned.
	DUCKDB_API unique_ptr<QueryResult> Execute();

	DUCKDB_API void Close();

	//! Function to determine whether execution is considered finished
	DUCKDB_API static bool IsResultReady(PendingExecutionResult result);
	DUCKDB_API static bool IsExecutionFinished(PendingExecutionResult result);

private:
	shared_ptr<ClientContext> context;
	bool allow_stream_result;

private:
	void CheckExecutableInternal(ClientContextLock &lock);

	PendingExecutionResult ExecuteTaskInternal(ClientContextLock &lock);
	unique_ptr<QueryResult> ExecuteInternal(ClientContextLock &lock);
	unique_ptr<ClientContextLock> LockContext();
};

} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/main/prepared_statement.hpp
//
//
//===----------------------------------------------------------------------===//








//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/expression/bound_parameter_data.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

struct BoundParameterData {
public:
	BoundParameterData() {
	}
	explicit BoundParameterData(Value val) : value(std::move(val)), return_type(value.type()) {
	}
	BoundParameterData(Value val, LogicalType type_p) : value(std::move(val)), return_type(std::move(type_p)) {
	}

private:
	Value value;

public:
	LogicalType return_type;

public:
	void SetValue(Value val) {
		value = std::move(val);
	}

	const Value &GetValue() const {
		return value;
	}

	void Serialize(Serializer &serializer) const;
	static shared_ptr<BoundParameterData> Deserialize(Deserializer &deserializer);
};

} // namespace duckdb


namespace duckdb {
class ClientContext;
class PreparedStatementData;

//! A prepared statement
class PreparedStatement {
public:
	//! Create a successfully prepared prepared statement object with the given name
	DUCKDB_API PreparedStatement(shared_ptr<ClientContext> context, shared_ptr<PreparedStatementData> data,
	                             string query, case_insensitive_map_t<idx_t> named_param_map);
	//! Create a prepared statement that was not successfully prepared
	DUCKDB_API explicit PreparedStatement(ErrorData error);

	DUCKDB_API ~PreparedStatement();

public:
	//! The client context this prepared statement belongs to
	shared_ptr<ClientContext> context;
	//! The prepared statement data
	shared_ptr<PreparedStatementData> data;
	//! The query that is being prepared
	string query;
	//! Whether or not the statement was successfully prepared
	bool success;
	//! The error message (if success = false)
	ErrorData error;
	//! The parameter mapping
	case_insensitive_map_t<idx_t> named_param_map;

public:
	//! Returns the stored error message
	DUCKDB_API const string &GetError();
	//! Returns the stored error object
	DUCKDB_API ErrorData &GetErrorObject();
	//! Returns whether or not an error occurred
	DUCKDB_API bool HasError() const;
	//! Returns the number of columns in the result
	DUCKDB_API idx_t ColumnCount();
	//! Returns the statement type of the underlying prepared statement object
	DUCKDB_API StatementType GetStatementType();
	//! Returns the underlying statement properties
	DUCKDB_API StatementProperties GetStatementProperties();
	//! Returns the result SQL types of the prepared statement
	DUCKDB_API const vector<LogicalType> &GetTypes();
	//! Returns the result names of the prepared statement
	DUCKDB_API const vector<string> &GetNames();
	//! Returns the map of parameter index to the expected type of parameter
	DUCKDB_API case_insensitive_map_t<LogicalType> GetExpectedParameterTypes() const;

	//! Create a pending query result of the prepared statement with the given set of arguments
	template <typename... ARGS>
	unique_ptr<PendingQueryResult> PendingQuery(ARGS... args) {
		vector<Value> values;
		return PendingQueryRecursive(values, args...);
	}

	//! Create a pending query result of the prepared statement with the given set of arguments
	DUCKDB_API unique_ptr<PendingQueryResult> PendingQuery(vector<Value> &values, bool allow_stream_result = true);

	//! Create a pending query result of the prepared statement with the given set named arguments
	DUCKDB_API unique_ptr<PendingQueryResult> PendingQuery(case_insensitive_map_t<BoundParameterData> &named_values,
	                                                       bool allow_stream_result = true);

	//! Execute the prepared statement with the given set of values
	DUCKDB_API unique_ptr<QueryResult> Execute(vector<Value> &values, bool allow_stream_result = true);

	//! Execute the prepared statement with the given set of named+unnamed values
	DUCKDB_API unique_ptr<QueryResult> Execute(case_insensitive_map_t<BoundParameterData> &named_values,
	                                           bool allow_stream_result = true);

	//! Execute the prepared statement with the given set of arguments
	template <typename... ARGS>
	unique_ptr<QueryResult> Execute(ARGS... args) {
		vector<Value> values;
		return ExecuteRecursive(values, args...);
	}

	template <class PAYLOAD>
	static string ExcessValuesException(const case_insensitive_map_t<idx_t> &parameters,
	                                    case_insensitive_map_t<PAYLOAD> &values) {
		// Too many values
		set<string> excess_set;
		for (auto &pair : values) {
			auto &name = pair.first;
			if (!parameters.count(name)) {
				excess_set.insert(name);
			}
		}
		vector<string> excess_values;
		for (auto &val : excess_set) {
			excess_values.push_back(val);
		}
		return StringUtil::Format("Parameter argument/count mismatch, identifiers of the excess parameters: %s",
		                          StringUtil::Join(excess_values, ", "));
	}

	template <class PAYLOAD>
	static string MissingValuesException(const case_insensitive_map_t<idx_t> &parameters,
	                                     case_insensitive_map_t<PAYLOAD> &values) {
		// Missing values
		set<string> missing_set;
		for (auto &pair : parameters) {
			auto &name = pair.first;
			if (!values.count(name)) {
				missing_set.insert(name);
			}
		}
		vector<string> missing_values;
		for (auto &val : missing_set) {
			missing_values.push_back(val);
		}
		return StringUtil::Format("Values were not provided for the following prepared statement parameters: %s",
		                          StringUtil::Join(missing_values, ", "));
	}

	template <class PAYLOAD>
	static void VerifyParameters(case_insensitive_map_t<PAYLOAD> &provided,
	                             const case_insensitive_map_t<idx_t> &expected) {
		if (expected.size() == provided.size()) {
			// Same amount of identifiers, if
			for (auto &pair : expected) {
				auto &identifier = pair.first;
				if (!provided.count(identifier)) {
					throw InvalidInputException(MissingValuesException(expected, provided));
				}
			}
			return;
		}
		// Mismatch in expected and provided parameters/values
		if (expected.size() > provided.size()) {
			throw InvalidInputException(MissingValuesException(expected, provided));
		} else {
			D_ASSERT(provided.size() > expected.size());
			throw InvalidInputException(ExcessValuesException(expected, provided));
		}
	}

private:
	unique_ptr<PendingQueryResult> PendingQueryRecursive(vector<Value> &values) {
		return PendingQuery(values);
	}

	template <typename T, typename... ARGS>
	unique_ptr<PendingQueryResult> PendingQueryRecursive(vector<Value> &values, T value, ARGS... args) {
		values.push_back(Value::CreateValue<T>(value));
		return PendingQueryRecursive(values, args...);
	}

	unique_ptr<QueryResult> ExecuteRecursive(vector<Value> &values) {
		return Execute(values);
	}

	template <typename T, typename... ARGS>
	unique_ptr<QueryResult> ExecuteRecursive(vector<Value> &values, T value, ARGS... args) {
		values.push_back(Value::CreateValue<T>(value));
		return ExecuteRecursive(values, args...);
	}
};

} // namespace duckdb


//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/main/relation.hpp
//
//
//===----------------------------------------------------------------------===//




//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/enums/join_type.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

//===--------------------------------------------------------------------===//
// Join Types
//===--------------------------------------------------------------------===//
enum class JoinType : uint8_t {
	INVALID = 0, // invalid join type
	LEFT = 1,    // left
	RIGHT = 2,   // right
	INNER = 3,   // inner
	OUTER = 4,   // outer
	SEMI = 5,    // LEFT SEMI join returns left side row ONLY if it has a join partner, no duplicates.
	ANTI = 6,    // LEFT ANTI join returns left side row ONLY if it has NO join partner, no duplicates
	MARK = 7,    // MARK join returns marker indicating whether or not there is a join partner (true), there is no join
	             // partner (false)
	SINGLE = 8,  // SINGLE join is like LEFT OUTER JOIN, BUT returns at most one join partner per entry on the LEFT side
	             // (and NULL if no partner is found)
	RIGHT_SEMI = 9, // RIGHT SEMI join is created by the optimizer when the children of a semi join need to be switched
	                // so that the build side can be the smaller table
	RIGHT_ANTI = 10 // RIGHT ANTI join is created by the optimizer when the children of an anti join need to be
	                // switched so that the build side can be the smaller table
};

//! True if join is left or full outer join
bool IsLeftOuterJoin(JoinType type);

//! True if join is rght or full outer join
bool IsRightOuterJoin(JoinType type);

//! Whether the build side is propagated out of the join
bool PropagatesBuildSide(JoinType type);

//! Whether the JoinType has an inverse
bool HasInverseJoinType(JoinType type);

//! Gets the inverse JoinType, e.g., LEFT -> RIGHT
JoinType InverseJoinType(JoinType type);

// **DEPRECATED**: Use EnumUtil directly instead.
string JoinTypeToString(JoinType type);

} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/enums/relation_type.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

//===--------------------------------------------------------------------===//
// Catalog Types
//===--------------------------------------------------------------------===//
enum class RelationType : uint8_t {
	INVALID_RELATION,
	TABLE_RELATION,
	PROJECTION_RELATION,
	FILTER_RELATION,
	EXPLAIN_RELATION,
	CROSS_PRODUCT_RELATION,
	JOIN_RELATION,
	AGGREGATE_RELATION,
	SET_OPERATION_RELATION,
	DISTINCT_RELATION,
	LIMIT_RELATION,
	ORDER_RELATION,
	CREATE_VIEW_RELATION,
	CREATE_TABLE_RELATION,
	INSERT_RELATION,
	VALUE_LIST_RELATION,
	MATERIALIZED_RELATION,
	DELETE_RELATION,
	UPDATE_RELATION,
	WRITE_CSV_RELATION,
	WRITE_PARQUET_RELATION,
	READ_CSV_RELATION,
	SUBQUERY_RELATION,
	TABLE_FUNCTION_RELATION,
	VIEW_RELATION,
	QUERY_RELATION,
	DELIM_JOIN_RELATION,
	DELIM_GET_RELATION
};

string RelationTypeToString(RelationType type);

} // namespace duckdb


//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/enums/joinref_type.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

//===--------------------------------------------------------------------===//
// Join Reference Types
//===--------------------------------------------------------------------===//
enum class JoinRefType : uint8_t {
	REGULAR,    // Explicit conditions
	NATURAL,    // Implied conditions
	CROSS,      // No condition
	POSITIONAL, // Positional condition
	ASOF,       // AsOf conditions
	DEPENDENT,  // Dependent join conditions
};

const char *ToString(JoinRefType value);

} // namespace duckdb




//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/main/client_context.hpp
//
//
//===----------------------------------------------------------------------===//






//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/deque.hpp
//
//
//===----------------------------------------------------------------------===//



#include <deque>

namespace duckdb {
using std::deque;
}


//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/enums/prepared_statement_mode.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

enum class PreparedStatementMode : uint8_t {
	PREPARE_ONLY,
	PREPARE_AND_EXECUTE,
};

} // namespace duckdb





//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/main/client_config.hpp
//
//
//===----------------------------------------------------------------------===//





//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/enums/output_type.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

enum class ExplainOutputType : uint8_t { ALL = 0, OPTIMIZED_ONLY = 1, PHYSICAL_ONLY = 2 };

} // namespace duckdb


//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/progress_bar/progress_bar.hpp
//
//
//===----------------------------------------------------------------------===//



//===----------------------------------------------------------------------===//
//
//                         DuckDB
//
// duckdb.h
//
//
//===----------------------------------------------------------------------===//
//
// !!!!!!!
// WARNING: this file is autogenerated by scripts/generate_c_api.py, manual changes will be overwritten
// !!!!!!!



//! duplicate of duckdb/main/winapi.hpp
#ifndef DUCKDB_API
#ifdef _WIN32
#ifdef DUCKDB_STATIC_BUILD
#define DUCKDB_API
#else
#if defined(DUCKDB_BUILD_LIBRARY) && !defined(DUCKDB_BUILD_LOADABLE_EXTENSION)
#define DUCKDB_API __declspec(dllexport)
#else
#define DUCKDB_API __declspec(dllimport)
#endif
#endif
#else
#define DUCKDB_API
#endif
#endif

//! duplicate of duckdb/main/winapi.hpp
#ifndef DUCKDB_EXTENSION_API
#ifdef _WIN32
#ifdef DUCKDB_STATIC_BUILD
#define DUCKDB_EXTENSION_API
#else
#ifdef DUCKDB_BUILD_LOADABLE_EXTENSION
#define DUCKDB_EXTENSION_API __declspec(dllexport)
#else
#define DUCKDB_EXTENSION_API
#endif
#endif
#else
#define DUCKDB_EXTENSION_API __attribute__((visibility("default")))
#endif
#endif

#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>

#ifdef __cplusplus
extern "C" {
#endif

//===--------------------------------------------------------------------===//
// Enums
//===--------------------------------------------------------------------===//
// WARNING: the numbers of these enums should not be changed, as changing the numbers breaks ABI compatibility
// Always add enums at the END of the enum
//! An enum over DuckDB's internal types.
typedef enum DUCKDB_TYPE {
	DUCKDB_TYPE_INVALID = 0,
	// bool
	DUCKDB_TYPE_BOOLEAN = 1,
	// int8_t
	DUCKDB_TYPE_TINYINT = 2,
	// int16_t
	DUCKDB_TYPE_SMALLINT = 3,
	// int32_t
	DUCKDB_TYPE_INTEGER = 4,
	// int64_t
	DUCKDB_TYPE_BIGINT = 5,
	// uint8_t
	DUCKDB_TYPE_UTINYINT = 6,
	// uint16_t
	DUCKDB_TYPE_USMALLINT = 7,
	// uint32_t
	DUCKDB_TYPE_UINTEGER = 8,
	// uint64_t
	DUCKDB_TYPE_UBIGINT = 9,
	// float
	DUCKDB_TYPE_FLOAT = 10,
	// double
	DUCKDB_TYPE_DOUBLE = 11,
	// duckdb_timestamp, in microseconds
	DUCKDB_TYPE_TIMESTAMP = 12,
	// duckdb_date
	DUCKDB_TYPE_DATE = 13,
	// duckdb_time
	DUCKDB_TYPE_TIME = 14,
	// duckdb_interval
	DUCKDB_TYPE_INTERVAL = 15,
	// duckdb_hugeint
	DUCKDB_TYPE_HUGEINT = 16,
	// duckdb_uhugeint
	DUCKDB_TYPE_UHUGEINT = 32,
	// const char*
	DUCKDB_TYPE_VARCHAR = 17,
	// duckdb_blob
	DUCKDB_TYPE_BLOB = 18,
	// decimal
	DUCKDB_TYPE_DECIMAL = 19,
	// duckdb_timestamp, in seconds
	DUCKDB_TYPE_TIMESTAMP_S = 20,
	// duckdb_timestamp, in milliseconds
	DUCKDB_TYPE_TIMESTAMP_MS = 21,
	// duckdb_timestamp, in nanoseconds
	DUCKDB_TYPE_TIMESTAMP_NS = 22,
	// enum type, only useful as logical type
	DUCKDB_TYPE_ENUM = 23,
	// list type, only useful as logical type
	DUCKDB_TYPE_LIST = 24,
	// struct type, only useful as logical type
	DUCKDB_TYPE_STRUCT = 25,
	// map type, only useful as logical type
	DUCKDB_TYPE_MAP = 26,
	// duckdb_array, only useful as logical type
	DUCKDB_TYPE_ARRAY = 33,
	// duckdb_hugeint
	DUCKDB_TYPE_UUID = 27,
	// union type, only useful as logical type
	DUCKDB_TYPE_UNION = 28,
	// duckdb_bit
	DUCKDB_TYPE_BIT = 29,
	// duckdb_time_tz
	DUCKDB_TYPE_TIME_TZ = 30,
	// duckdb_timestamp
	DUCKDB_TYPE_TIMESTAMP_TZ = 31,
	// ANY type
	DUCKDB_TYPE_ANY = 34,
	// duckdb_varint
	DUCKDB_TYPE_VARINT = 35,
	// SQLNULL type
	DUCKDB_TYPE_SQLNULL = 36,
} duckdb_type;
//! An enum over the returned state of different functions.
typedef enum duckdb_state { DuckDBSuccess = 0, DuckDBError = 1 } duckdb_state;
//! An enum over the pending state of a pending query result.
typedef enum duckdb_pending_state {
	DUCKDB_PENDING_RESULT_READY = 0,
	DUCKDB_PENDING_RESULT_NOT_READY = 1,
	DUCKDB_PENDING_ERROR = 2,
	DUCKDB_PENDING_NO_TASKS_AVAILABLE = 3
} duckdb_pending_state;
//! An enum over DuckDB's different result types.
typedef enum duckdb_result_type {
	DUCKDB_RESULT_TYPE_INVALID = 0,
	DUCKDB_RESULT_TYPE_CHANGED_ROWS = 1,
	DUCKDB_RESULT_TYPE_NOTHING = 2,
	DUCKDB_RESULT_TYPE_QUERY_RESULT = 3,
} duckdb_result_type;
//! An enum over DuckDB's different statement types.
typedef enum duckdb_statement_type {
	DUCKDB_STATEMENT_TYPE_INVALID = 0,
	DUCKDB_STATEMENT_TYPE_SELECT = 1,
	DUCKDB_STATEMENT_TYPE_INSERT = 2,
	DUCKDB_STATEMENT_TYPE_UPDATE = 3,
	DUCKDB_STATEMENT_TYPE_EXPLAIN = 4,
	DUCKDB_STATEMENT_TYPE_DELETE = 5,
	DUCKDB_STATEMENT_TYPE_PREPARE = 6,
	DUCKDB_STATEMENT_TYPE_CREATE = 7,
	DUCKDB_STATEMENT_TYPE_EXECUTE = 8,
	DUCKDB_STATEMENT_TYPE_ALTER = 9,
	DUCKDB_STATEMENT_TYPE_TRANSACTION = 10,
	DUCKDB_STATEMENT_TYPE_COPY = 11,
	DUCKDB_STATEMENT_TYPE_ANALYZE = 12,
	DUCKDB_STATEMENT_TYPE_VARIABLE_SET = 13,
	DUCKDB_STATEMENT_TYPE_CREATE_FUNC = 14,
	DUCKDB_STATEMENT_TYPE_DROP = 15,
	DUCKDB_STATEMENT_TYPE_EXPORT = 16,
	DUCKDB_STATEMENT_TYPE_PRAGMA = 17,
	DUCKDB_STATEMENT_TYPE_VACUUM = 18,
	DUCKDB_STATEMENT_TYPE_CALL = 19,
	DUCKDB_STATEMENT_TYPE_SET = 20,
	DUCKDB_STATEMENT_TYPE_LOAD = 21,
	DUCKDB_STATEMENT_TYPE_RELATION = 22,
	DUCKDB_STATEMENT_TYPE_EXTENSION = 23,
	DUCKDB_STATEMENT_TYPE_LOGICAL_PLAN = 24,
	DUCKDB_STATEMENT_TYPE_ATTACH = 25,
	DUCKDB_STATEMENT_TYPE_DETACH = 26,
	DUCKDB_STATEMENT_TYPE_MULTI = 27,
} duckdb_statement_type;
//! An enum over DuckDB's different result types.
typedef enum duckdb_error_type {
	DUCKDB_ERROR_INVALID = 0,
	DUCKDB_ERROR_OUT_OF_RANGE = 1,
	DUCKDB_ERROR_CONVERSION = 2,
	DUCKDB_ERROR_UNKNOWN_TYPE = 3,
	DUCKDB_ERROR_DECIMAL = 4,
	DUCKDB_ERROR_MISMATCH_TYPE = 5,
	DUCKDB_ERROR_DIVIDE_BY_ZERO = 6,
	DUCKDB_ERROR_OBJECT_SIZE = 7,
	DUCKDB_ERROR_INVALID_TYPE = 8,
	DUCKDB_ERROR_SERIALIZATION = 9,
	DUCKDB_ERROR_TRANSACTION = 10,
	DUCKDB_ERROR_NOT_IMPLEMENTED = 11,
	DUCKDB_ERROR_EXPRESSION = 12,
	DUCKDB_ERROR_CATALOG = 13,
	DUCKDB_ERROR_PARSER = 14,
	DUCKDB_ERROR_PLANNER = 15,
	DUCKDB_ERROR_SCHEDULER = 16,
	DUCKDB_ERROR_EXECUTOR = 17,
	DUCKDB_ERROR_CONSTRAINT = 18,
	DUCKDB_ERROR_INDEX = 19,
	DUCKDB_ERROR_STAT = 20,
	DUCKDB_ERROR_CONNECTION = 21,
	DUCKDB_ERROR_SYNTAX = 22,
	DUCKDB_ERROR_SETTINGS = 23,
	DUCKDB_ERROR_BINDER = 24,
	DUCKDB_ERROR_NETWORK = 25,
	DUCKDB_ERROR_OPTIMIZER = 26,
	DUCKDB_ERROR_NULL_POINTER = 27,
	DUCKDB_ERROR_IO = 28,
	DUCKDB_ERROR_INTERRUPT = 29,
	DUCKDB_ERROR_FATAL = 30,
	DUCKDB_ERROR_INTERNAL = 31,
	DUCKDB_ERROR_INVALID_INPUT = 32,
	DUCKDB_ERROR_OUT_OF_MEMORY = 33,
	DUCKDB_ERROR_PERMISSION = 34,
	DUCKDB_ERROR_PARAMETER_NOT_RESOLVED = 35,
	DUCKDB_ERROR_PARAMETER_NOT_ALLOWED = 36,
	DUCKDB_ERROR_DEPENDENCY = 37,
	DUCKDB_ERROR_HTTP = 38,
	DUCKDB_ERROR_MISSING_EXTENSION = 39,
	DUCKDB_ERROR_AUTOLOAD = 40,
	DUCKDB_ERROR_SEQUENCE = 41,
	DUCKDB_INVALID_CONFIGURATION = 42
} duckdb_error_type;
//! An enum over DuckDB's different cast modes.
typedef enum duckdb_cast_mode { DUCKDB_CAST_NORMAL = 0, DUCKDB_CAST_TRY = 1 } duckdb_cast_mode;

//===--------------------------------------------------------------------===//
// General type definitions
//===--------------------------------------------------------------------===//

//! DuckDB's index type.
typedef uint64_t idx_t;

//! The callback that will be called to destroy data, e.g.,
//! bind data (if any), init data (if any), extra data for replacement scans (if any)
typedef void (*duckdb_delete_callback_t)(void *data);

//! Used for threading, contains a task state. Must be destroyed with `duckdb_destroy_state`.
typedef void *duckdb_task_state;

//===--------------------------------------------------------------------===//
// Types (no explicit freeing)
//===--------------------------------------------------------------------===//

//! Days are stored as days since 1970-01-01
//! Use the duckdb_from_date/duckdb_to_date function to extract individual information
typedef struct {
	int32_t days;
} duckdb_date;
typedef struct {
	int32_t year;
	int8_t month;
	int8_t day;
} duckdb_date_struct;

//! Time is stored as microseconds since 00:00:00
//! Use the duckdb_from_time/duckdb_to_time function to extract individual information
typedef struct {
	int64_t micros;
} duckdb_time;
typedef struct {
	int8_t hour;
	int8_t min;
	int8_t sec;
	int32_t micros;
} duckdb_time_struct;

//! TIME_TZ is stored as 40 bits for int64_t micros, and 24 bits for int32_t offset
typedef struct {
	uint64_t bits;
} duckdb_time_tz;
typedef struct {
	duckdb_time_struct time;
	int32_t offset;
} duckdb_time_tz_struct;

//! Timestamps are stored as microseconds since 1970-01-01
//! Use the duckdb_from_timestamp/duckdb_to_timestamp function to extract individual information
typedef struct {
	int64_t micros;
} duckdb_timestamp;
typedef struct {
	duckdb_date_struct date;
	duckdb_time_struct time;
} duckdb_timestamp_struct;
typedef struct {
	int32_t months;
	int32_t days;
	int64_t micros;
} duckdb_interval;

//! Hugeints are composed of a (lower, upper) component
//! The value of the hugeint is upper * 2^64 + lower
//! For easy usage, the functions duckdb_hugeint_to_double/duckdb_double_to_hugeint are recommended
typedef struct {
	uint64_t lower;
	int64_t upper;
} duckdb_hugeint;
typedef struct {
	uint64_t lower;
	uint64_t upper;
} duckdb_uhugeint;

//! Decimals are composed of a width and a scale, and are stored in a hugeint
typedef struct {
	uint8_t width;
	uint8_t scale;
	duckdb_hugeint value;
} duckdb_decimal;

//! A type holding information about the query execution progress
typedef struct {
	double percentage;
	uint64_t rows_processed;
	uint64_t total_rows_to_process;
} duckdb_query_progress_type;

//! The internal representation of a VARCHAR (string_t). If the VARCHAR does not
//! exceed 12 characters, then we inline it. Otherwise, we inline a prefix for faster
//! string comparisons and store a pointer to the remaining characters. This is a non-
//! owning structure, i.e., it does not have to be freed.
typedef struct {
	union {
		struct {
			uint32_t length;
			char prefix[4];
			char *ptr;
		} pointer;
		struct {
			uint32_t length;
			char inlined[12];
		} inlined;
	} value;
} duckdb_string_t;

//! The internal representation of a list metadata entry contains the list's offset in
//! the child vector, and its length. The parent vector holds these metadata entries,
//! whereas the child vector holds the data
typedef struct {
	uint64_t offset;
	uint64_t length;
} duckdb_list_entry;

//! A column consists of a pointer to its internal data. Don't operate on this type directly.
//! Instead, use functions such as duckdb_column_data, duckdb_nullmask_data,
//! duckdb_column_type, and duckdb_column_name, which take the result and the column index
//! as their parameters
typedef struct {
	// deprecated, use duckdb_column_data
	void *deprecated_data;
	// deprecated, use duckdb_nullmask_data
	bool *deprecated_nullmask;
	// deprecated, use duckdb_column_type
	duckdb_type deprecated_type;
	// deprecated, use duckdb_column_name
	char *deprecated_name;
	void *internal_data;
} duckdb_column;

//! A vector to a specified column in a data chunk. Lives as long as the
//! data chunk lives, i.e., must not be destroyed.
typedef struct _duckdb_vector {
	void *internal_ptr;
} * duckdb_vector;

//===--------------------------------------------------------------------===//
// Types (explicit freeing/destroying)
//===--------------------------------------------------------------------===//

//! Strings are composed of a char pointer and a size. You must free string.data
//! with `duckdb_free`.
typedef struct {
	char *data;
	idx_t size;
} duckdb_string;

//! BLOBs are composed of a byte pointer and a size. You must free blob.data
//! with `duckdb_free`.
typedef struct {
	void *data;
	idx_t size;
} duckdb_blob;

//! A query result consists of a pointer to its internal data.
//! Must be freed with 'duckdb_destroy_result'.
typedef struct {
	// deprecated, use duckdb_column_count
	idx_t deprecated_column_count;
	// deprecated, use duckdb_row_count
	idx_t deprecated_row_count;
	// deprecated, use duckdb_rows_changed
	idx_t deprecated_rows_changed;
	// deprecated, use duckdb_column_*-family of functions
	duckdb_column *deprecated_columns;
	// deprecated, use duckdb_result_error
	char *deprecated_error_message;
	void *internal_data;
} duckdb_result;

//! A database object. Should be closed with `duckdb_close`.
typedef struct _duckdb_database {
	void *internal_ptr;
} * duckdb_database;

//! A connection to a duckdb database. Must be closed with `duckdb_disconnect`.
typedef struct _duckdb_connection {
	void *internal_ptr;
} * duckdb_connection;

//! A prepared statement is a parameterized query that allows you to bind parameters to it.
//! Must be destroyed with `duckdb_destroy_prepare`.
typedef struct _duckdb_prepared_statement {
	void *internal_ptr;
} * duckdb_prepared_statement;

//! Extracted statements. Must be destroyed with `duckdb_destroy_extracted`.
typedef struct _duckdb_extracted_statements {
	void *internal_ptr;
} * duckdb_extracted_statements;

//! The pending result represents an intermediate structure for a query that is not yet fully executed.
//! Must be destroyed with `duckdb_destroy_pending`.
typedef struct _duckdb_pending_result {
	void *internal_ptr;
} * duckdb_pending_result;

//! The appender enables fast data loading into DuckDB.
//! Must be destroyed with `duckdb_appender_destroy`.
typedef struct _duckdb_appender {
	void *internal_ptr;
} * duckdb_appender;

//! The table description allows querying info about the table.
//! Must be destroyed with `duckdb_table_description_destroy`.
typedef struct _duckdb_table_description {
	void *internal_ptr;
} * duckdb_table_description;

//! Can be used to provide start-up options for the DuckDB instance.
//! Must be destroyed with `duckdb_destroy_config`.
typedef struct _duckdb_config {
	void *internal_ptr;
} * duckdb_config;

//! Holds an internal logical type.
//! Must be destroyed with `duckdb_destroy_logical_type`.
typedef struct _duckdb_logical_type {
	void *internal_ptr;
} * duckdb_logical_type;

//! Holds extra information used when registering a custom logical type.
//! Reserved for future use.
typedef struct _duckdb_create_type_info {
	void *internal_ptr;
} * duckdb_create_type_info;

//! Contains a data chunk from a duckdb_result.
//! Must be destroyed with `duckdb_destroy_data_chunk`.
typedef struct _duckdb_data_chunk {
	void *internal_ptr;
} * duckdb_data_chunk;

//! Holds a DuckDB value, which wraps a type.
//! Must be destroyed with `duckdb_destroy_value`.
typedef struct _duckdb_value {
	void *internal_ptr;
} * duckdb_value;

//! Holds a recursive tree that matches the query plan.
typedef struct _duckdb_profiling_info {
	void *internal_ptr;
} * duckdb_profiling_info;

//===--------------------------------------------------------------------===//
// C API Extension info
//===--------------------------------------------------------------------===//
//! Holds state during the C API extension intialization process
typedef struct _duckdb_extension_info {
	void *internal_ptr;
} * duckdb_extension_info;

//===--------------------------------------------------------------------===//
// Function types
//===--------------------------------------------------------------------===//
//! Additional function info. When setting this info, it is necessary to pass a destroy-callback function.
typedef struct _duckdb_function_info {
	void *internal_ptr;
} * duckdb_function_info;

//===--------------------------------------------------------------------===//
// Scalar function types
//===--------------------------------------------------------------------===//
//! A scalar function. Must be destroyed with `duckdb_destroy_scalar_function`.
typedef struct _duckdb_scalar_function {
	void *internal_ptr;
} * duckdb_scalar_function;

//! A scalar function set. Must be destroyed with `duckdb_destroy_scalar_function_set`.
typedef struct _duckdb_scalar_function_set {
	void *internal_ptr;
} * duckdb_scalar_function_set;

//! The main function of the scalar function.
typedef void (*duckdb_scalar_function_t)(duckdb_function_info info, duckdb_data_chunk input, duckdb_vector output);

//===--------------------------------------------------------------------===//
// Aggregate function types
//===--------------------------------------------------------------------===//
//! An aggregate function. Must be destroyed with `duckdb_destroy_aggregate_function`.
typedef struct _duckdb_aggregate_function {
	void *internal_ptr;
} * duckdb_aggregate_function;

//! A aggregate function set. Must be destroyed with `duckdb_destroy_aggregate_function_set`.
typedef struct _duckdb_aggregate_function_set {
	void *internal_ptr;
} * duckdb_aggregate_function_set;

//! Aggregate state
typedef struct _duckdb_aggregate_state {
	void *internal_ptr;
} * duckdb_aggregate_state;

//! Returns the aggregate state size
typedef idx_t (*duckdb_aggregate_state_size)(duckdb_function_info info);
//! Initialize the aggregate state
typedef void (*duckdb_aggregate_init_t)(duckdb_function_info info, duckdb_aggregate_state state);
//! Destroy aggregate state (optional)
typedef void (*duckdb_aggregate_destroy_t)(duckdb_aggregate_state *states, idx_t count);
//! Update a set of aggregate states with new values
typedef void (*duckdb_aggregate_update_t)(duckdb_function_info info, duckdb_data_chunk input,
                                          duckdb_aggregate_state *states);
//! Combine aggregate states
typedef void (*duckdb_aggregate_combine_t)(duckdb_function_info info, duckdb_aggregate_state *source,
                                           duckdb_aggregate_state *target, idx_t count);
//! Finalize aggregate states into a result vector
typedef void (*duckdb_aggregate_finalize_t)(duckdb_function_info info, duckdb_aggregate_state *source,
                                            duckdb_vector result, idx_t count, idx_t offset);

//===--------------------------------------------------------------------===//
// Table function types
//===--------------------------------------------------------------------===//

//! A table function. Must be destroyed with `duckdb_destroy_table_function`.
typedef struct _duckdb_table_function {
	void *internal_ptr;
} * duckdb_table_function;

//! The bind info of the function. When setting this info, it is necessary to pass a destroy-callback function.
typedef struct _duckdb_bind_info {
	void *internal_ptr;
} * duckdb_bind_info;

//! Additional function init info. When setting this info, it is necessary to pass a destroy-callback function.
typedef struct _duckdb_init_info {
	void *internal_ptr;
} * duckdb_init_info;

//! The bind function of the table function.
typedef void (*duckdb_table_function_bind_t)(duckdb_bind_info info);

//! The (possibly thread-local) init function of the table function.
typedef void (*duckdb_table_function_init_t)(duckdb_init_info info);

//! The main function of the table function.
typedef void (*duckdb_table_function_t)(duckdb_function_info info, duckdb_data_chunk output);

//===--------------------------------------------------------------------===//
// Cast types
//===--------------------------------------------------------------------===//

//! A cast function. Must be destroyed with `duckdb_destroy_cast_function`.
typedef struct _duckdb_cast_function {
	void *internal_ptr;
} * duckdb_cast_function;

typedef bool (*duckdb_cast_function_t)(duckdb_function_info info, idx_t count, duckdb_vector input,
                                       duckdb_vector output);

//===--------------------------------------------------------------------===//
// Replacement scan types
//===--------------------------------------------------------------------===//

//! Additional replacement scan info. When setting this info, it is necessary to pass a destroy-callback function.
typedef struct _duckdb_replacement_scan_info {
	void *internal_ptr;
} * duckdb_replacement_scan_info;

//! A replacement scan function that can be added to a database.
typedef void (*duckdb_replacement_callback_t)(duckdb_replacement_scan_info info, const char *table_name, void *data);

//===--------------------------------------------------------------------===//
// Arrow-related types
//===--------------------------------------------------------------------===//

//! Holds an arrow query result. Must be destroyed with `duckdb_destroy_arrow`.
typedef struct _duckdb_arrow {
	void *internal_ptr;
} * duckdb_arrow;

//! Holds an arrow array stream. Must be destroyed with `duckdb_destroy_arrow_stream`.
typedef struct _duckdb_arrow_stream {
	void *internal_ptr;
} * duckdb_arrow_stream;

//! Holds an arrow schema. Remember to release the respective ArrowSchema object.
typedef struct _duckdb_arrow_schema {
	void *internal_ptr;
} * duckdb_arrow_schema;

//! Holds an arrow array. Remember to release the respective ArrowArray object.
typedef struct _duckdb_arrow_array {
	void *internal_ptr;
} * duckdb_arrow_array;

//===--------------------------------------------------------------------===//
// DuckDB extension access
//===--------------------------------------------------------------------===//
//! Passed to C API extension as parameter to the entrypoint
struct duckdb_extension_access {
	//! Indicate that an error has occured
	void (*set_error)(duckdb_extension_info info, const char *error);
	//! Fetch the database from duckdb to register extensions to
	duckdb_database *(*get_database)(duckdb_extension_info info);
	//! Fetch the API
	void *(*get_api)(duckdb_extension_info info, const char *version);
};

//===--------------------------------------------------------------------===//
// Functions
//===--------------------------------------------------------------------===//

//===--------------------------------------------------------------------===//
// Open Connect
//===--------------------------------------------------------------------===//

/*!
Creates a new database or opens an existing database file stored at the given path.
If no path is given a new in-memory database is created instead.
The instantiated database should be closed with 'duckdb_close'.

* @param path Path to the database file on disk, or `nullptr` or `:memory:` to open an in-memory database.
* @param out_database The result database object.
* @return `DuckDBSuccess` on success or `DuckDBError` on failure.
*/
DUCKDB_API duckdb_state duckdb_open(const char *path, duckdb_database *out_database);

/*!
Extended version of duckdb_open. Creates a new database or opens an existing database file stored at the given path.
The instantiated database should be closed with 'duckdb_close'.

* @param path Path to the database file on disk, or `nullptr` or `:memory:` to open an in-memory database.
* @param out_database The result database object.
* @param config (Optional) configuration used to start up the database system.
* @param out_error If set and the function returns DuckDBError, this will contain the reason why the start-up failed.
Note that the error must be freed using `duckdb_free`.
* @return `DuckDBSuccess` on success or `DuckDBError` on failure.
*/
DUCKDB_API duckdb_state duckdb_open_ext(const char *path, duckdb_database *out_database, duckdb_config config,
                                        char **out_error);

/*!
Closes the specified database and de-allocates all memory allocated for that database.
This should be called after you are done with any database allocated through `duckdb_open` or `duckdb_open_ext`.
Note that failing to call `duckdb_close` (in case of e.g. a program crash) will not cause data corruption.
Still, it is recommended to always correctly close a database object after you are done with it.

* @param database The database object to shut down.
*/
DUCKDB_API void duckdb_close(duckdb_database *database);

/*!
Opens a connection to a database. Connections are required to query the database, and store transactional state
associated with the connection.
The instantiated connection should be closed using 'duckdb_disconnect'.

* @param database The database file to connect to.
* @param out_connection The result connection object.
* @return `DuckDBSuccess` on success or `DuckDBError` on failure.
*/
DUCKDB_API duckdb_state duckdb_connect(duckdb_database database, duckdb_connection *out_connection);

/*!
Interrupt running query

* @param connection The connection to interrupt
*/
DUCKDB_API void duckdb_interrupt(duckdb_connection connection);

/*!
Get progress of the running query

* @param connection The working connection
* @return -1 if no progress or a percentage of the progress
*/
DUCKDB_API duckdb_query_progress_type duckdb_query_progress(duckdb_connection connection);

/*!
Closes the specified connection and de-allocates all memory allocated for that connection.

* @param connection The connection to close.
*/
DUCKDB_API void duckdb_disconnect(duckdb_connection *connection);

/*!
Returns the version of the linked DuckDB, with a version postfix for dev versions

Usually used for developing C extensions that must return this for a compatibility check.
*/
DUCKDB_API const char *duckdb_library_version();

//===--------------------------------------------------------------------===//
// Configuration
//===--------------------------------------------------------------------===//

/*!
Initializes an empty configuration object that can be used to provide start-up options for the DuckDB instance
through `duckdb_open_ext`.
The duckdb_config must be destroyed using 'duckdb_destroy_config'

This will always succeed unless there is a malloc failure.

Note that `duckdb_destroy_config` should always be called on the resulting config, even if the function returns
`DuckDBError`.

* @param out_config The result configuration object.
* @return `DuckDBSuccess` on success or `DuckDBError` on failure.
*/
DUCKDB_API duckdb_state duckdb_create_config(duckdb_config *out_config);

/*!
This returns the total amount of configuration options available for usage with `duckdb_get_config_flag`.

This should not be called in a loop as it internally loops over all the options.

* @return The amount of config options available.
*/
DUCKDB_API size_t duckdb_config_count();

/*!
Obtains a human-readable name and description of a specific configuration option. This can be used to e.g.
display configuration options. This will succeed unless `index` is out of range (i.e. `>= duckdb_config_count`).

The result name or description MUST NOT be freed.

* @param index The index of the configuration option (between 0 and `duckdb_config_count`)
* @param out_name A name of the configuration flag.
* @param out_description A description of the configuration flag.
* @return `DuckDBSuccess` on success or `DuckDBError` on failure.
*/
DUCKDB_API duckdb_state duckdb_get_config_flag(size_t index, const char **out_name, const char **out_description);

/*!
Sets the specified option for the specified configuration. The configuration option is indicated by name.
To obtain a list of config options, see `duckdb_get_config_flag`.

In the source code, configuration options are defined in `config.cpp`.

This can fail if either the name is invalid, or if the value provided for the option is invalid.

* @param config The configuration object to set the option on.
* @param name The name of the configuration flag to set.
* @param option The value to set the configuration flag to.
* @return `DuckDBSuccess` on success or `DuckDBError` on failure.
*/
DUCKDB_API duckdb_state duckdb_set_config(duckdb_config config, const char *name, const char *option);

/*!
Destroys the specified configuration object and de-allocates all memory allocated for the object.

* @param config The configuration object to destroy.
*/
DUCKDB_API void duckdb_destroy_config(duckdb_config *config);

//===--------------------------------------------------------------------===//
// Query Execution
//===--------------------------------------------------------------------===//

/*!
Executes a SQL query within a connection and stores the full (materialized) result in the out_result pointer.
If the query fails to execute, DuckDBError is returned and the error message can be retrieved by calling
`duckdb_result_error`.

Note that after running `duckdb_query`, `duckdb_destroy_result` must be called on the result object even if the
query fails, otherwise the error stored within the result will not be freed correctly.

* @param connection The connection to perform the query in.
* @param query The SQL query to run.
* @param out_result The query result.
* @return `DuckDBSuccess` on success or `DuckDBError` on failure.
*/
DUCKDB_API duckdb_state duckdb_query(duckdb_connection connection, const char *query, duckdb_result *out_result);

/*!
Closes the result and de-allocates all memory allocated for that connection.

* @param result The result to destroy.
*/
DUCKDB_API void duckdb_destroy_result(duckdb_result *result);

/*!
Returns the column name of the specified column. The result should not need to be freed; the column names will
automatically be destroyed when the result is destroyed.

Returns `NULL` if the column is out of range.

* @param result The result object to fetch the column name from.
* @param col The column index.
* @return The column name of the specified column.
*/
DUCKDB_API const char *duckdb_column_name(duckdb_result *result, idx_t col);

/*!
Returns the column type of the specified column.

Returns `DUCKDB_TYPE_INVALID` if the column is out of range.

* @param result The result object to fetch the column type from.
* @param col The column index.
* @return The column type of the specified column.
*/
DUCKDB_API duckdb_type duckdb_column_type(duckdb_result *result, idx_t col);

/*!
Returns the statement type of the statement that was executed

* @param result The result object to fetch the statement type from.
* @return duckdb_statement_type value or DUCKDB_STATEMENT_TYPE_INVALID
*/
DUCKDB_API duckdb_statement_type duckdb_result_statement_type(duckdb_result result);

/*!
Returns the logical column type of the specified column.

The return type of this call should be destroyed with `duckdb_destroy_logical_type`.

Returns `NULL` if the column is out of range.

* @param result The result object to fetch the column type from.
* @param col The column index.
* @return The logical column type of the specified column.
*/
DUCKDB_API duckdb_logical_type duckdb_column_logical_type(duckdb_result *result, idx_t col);

/*!
Returns the number of columns present in a the result object.

* @param result The result object.
* @return The number of columns present in the result object.
*/
DUCKDB_API idx_t duckdb_column_count(duckdb_result *result);

#ifndef DUCKDB_API_NO_DEPRECATED
/*!
**DEPRECATION NOTICE**: This method is scheduled for removal in a future release.

Returns the number of rows present in the result object.

* @param result The result object.
* @return The number of rows present in the result object.
*/
DUCKDB_API idx_t duckdb_row_count(duckdb_result *result);

#endif
/*!
Returns the number of rows changed by the query stored in the result. This is relevant only for INSERT/UPDATE/DELETE
queries. For other queries the rows_changed will be 0.

* @param result The result object.
* @return The number of rows changed.
*/
DUCKDB_API idx_t duckdb_rows_changed(duckdb_result *result);

#ifndef DUCKDB_API_NO_DEPRECATED
/*!
**DEPRECATED**: Prefer using `duckdb_result_get_chunk` instead.

Returns the data of a specific column of a result in columnar format.

The function returns a dense array which contains the result data. The exact type stored in the array depends on the
corresponding duckdb_type (as provided by `duckdb_column_type`). For the exact type by which the data should be
accessed, see the comments in [the types section](types) or the `DUCKDB_TYPE` enum.

For example, for a column of type `DUCKDB_TYPE_INTEGER`, rows can be accessed in the following manner:
```c
int32_t *data = (int32_t *) duckdb_column_data(&result, 0);
printf("Data for row %d: %d\n", row, data[row]);
```

* @param result The result object to fetch the column data from.
* @param col The column index.
* @return The column data of the specified column.
*/
DUCKDB_API void *duckdb_column_data(duckdb_result *result, idx_t col);

/*!
**DEPRECATED**: Prefer using `duckdb_result_get_chunk` instead.

Returns the nullmask of a specific column of a result in columnar format. The nullmask indicates for every row
whether or not the corresponding row is `NULL`. If a row is `NULL`, the values present in the array provided
by `duckdb_column_data` are undefined.

```c
int32_t *data = (int32_t *) duckdb_column_data(&result, 0);
bool *nullmask = duckdb_nullmask_data(&result, 0);
if (nullmask[row]) {
    printf("Data for row %d: NULL\n", row);
} else {
    printf("Data for row %d: %d\n", row, data[row]);
}
```

* @param result The result object to fetch the nullmask from.
* @param col The column index.
* @return The nullmask of the specified column.
*/
DUCKDB_API bool *duckdb_nullmask_data(duckdb_result *result, idx_t col);

#endif
/*!
Returns the error message contained within the result. The error is only set if `duckdb_query` returns `DuckDBError`.

The result of this function must not be freed. It will be cleaned up when `duckdb_destroy_result` is called.

* @param result The result object to fetch the error from.
* @return The error of the result.
*/
DUCKDB_API const char *duckdb_result_error(duckdb_result *result);

/*!
Returns the result error type contained within the result. The error is only set if `duckdb_query` returns
`DuckDBError`.

* @param result The result object to fetch the error from.
* @return The error type of the result.
*/
DUCKDB_API duckdb_error_type duckdb_result_error_type(duckdb_result *result);

//===--------------------------------------------------------------------===//
// Result Functions
//===--------------------------------------------------------------------===//

#ifndef DUCKDB_API_NO_DEPRECATED
/*!
**DEPRECATION NOTICE**: This method is scheduled for removal in a future release.

Fetches a data chunk from the duckdb_result. This function should be called repeatedly until the result is exhausted.

The result must be destroyed with `duckdb_destroy_data_chunk`.

This function supersedes all `duckdb_value` functions, as well as the `duckdb_column_data` and `duckdb_nullmask_data`
functions. It results in significantly better performance, and should be preferred in newer code-bases.

If this function is used, none of the other result functions can be used and vice versa (i.e. this function cannot be
mixed with the legacy result functions).

Use `duckdb_result_chunk_count` to figure out how many chunks there are in the result.

* @param result The result object to fetch the data chunk from.
* @param chunk_index The chunk index to fetch from.
* @return The resulting data chunk. Returns `NULL` if the chunk index is out of bounds.
*/
DUCKDB_API duckdb_data_chunk duckdb_result_get_chunk(duckdb_result result, idx_t chunk_index);

/*!
**DEPRECATION NOTICE**: This method is scheduled for removal in a future release.

Checks if the type of the internal result is StreamQueryResult.

* @param result The result object to check.
* @return Whether or not the result object is of the type StreamQueryResult
*/
DUCKDB_API bool duckdb_result_is_streaming(duckdb_result result);

/*!
**DEPRECATION NOTICE**: This method is scheduled for removal in a future release.

Returns the number of data chunks present in the result.

* @param result The result object
* @return Number of data chunks present in the result.
*/
DUCKDB_API idx_t duckdb_result_chunk_count(duckdb_result result);

#endif
/*!
Returns the return_type of the given result, or DUCKDB_RETURN_TYPE_INVALID on error

* @param result The result object
* @return The return_type
*/
DUCKDB_API duckdb_result_type duckdb_result_return_type(duckdb_result result);

//===--------------------------------------------------------------------===//
// Safe Fetch Functions
//===--------------------------------------------------------------------===//

// These functions will perform conversions if necessary.
// On failure (e.g. if conversion cannot be performed or if the value is NULL) a default value is returned.
// Note that these functions are slow since they perform bounds checking and conversion
// For fast access of values prefer using `duckdb_result_get_chunk`
#ifndef DUCKDB_API_NO_DEPRECATED
/*!
**DEPRECATION NOTICE**: This method is scheduled for removal in a future release.

* @return The boolean value at the specified location, or false if the value cannot be converted.
*/
DUCKDB_API bool duckdb_value_boolean(duckdb_result *result, idx_t col, idx_t row);

/*!
**DEPRECATION NOTICE**: This method is scheduled for removal in a future release.

* @return The int8_t value at the specified location, or 0 if the value cannot be converted.
*/
DUCKDB_API int8_t duckdb_value_int8(duckdb_result *result, idx_t col, idx_t row);

/*!
**DEPRECATION NOTICE**: This method is scheduled for removal in a future release.

* @return The int16_t value at the specified location, or 0 if the value cannot be converted.
*/
DUCKDB_API int16_t duckdb_value_int16(duckdb_result *result, idx_t col, idx_t row);

/*!
**DEPRECATION NOTICE**: This method is scheduled for removal in a future release.

* @return The int32_t value at the specified location, or 0 if the value cannot be converted.
*/
DUCKDB_API int32_t duckdb_value_int32(duckdb_result *result, idx_t col, idx_t row);

/*!
**DEPRECATION NOTICE**: This method is scheduled for removal in a future release.

* @return The int64_t value at the specified location, or 0 if the value cannot be converted.
*/
DUCKDB_API int64_t duckdb_value_int64(duckdb_result *result, idx_t col, idx_t row);

/*!
**DEPRECATION NOTICE**: This method is scheduled for removal in a future release.

* @return The duckdb_hugeint value at the specified location, or 0 if the value cannot be converted.
*/
DUCKDB_API duckdb_hugeint duckdb_value_hugeint(duckdb_result *result, idx_t col, idx_t row);

/*!
**DEPRECATION NOTICE**: This method is scheduled for removal in a future release.

* @return The duckdb_uhugeint value at the specified location, or 0 if the value cannot be converted.
*/
DUCKDB_API duckdb_uhugeint duckdb_value_uhugeint(duckdb_result *result, idx_t col, idx_t row);

/*!
**DEPRECATION NOTICE**: This method is scheduled for removal in a future release.

* @return The duckdb_decimal value at the specified location, or 0 if the value cannot be converted.
*/
DUCKDB_API duckdb_decimal duckdb_value_decimal(duckdb_result *result, idx_t col, idx_t row);

/*!
**DEPRECATION NOTICE**: This method is scheduled for removal in a future release.

* @return The uint8_t value at the specified location, or 0 if the value cannot be converted.
*/
DUCKDB_API uint8_t duckdb_value_uint8(duckdb_result *result, idx_t col, idx_t row);

/*!
**DEPRECATION NOTICE**: This method is scheduled for removal in a future release.

* @return The uint16_t value at the specified location, or 0 if the value cannot be converted.
*/
DUCKDB_API uint16_t duckdb_value_uint16(duckdb_result *result, idx_t col, idx_t row);

/*!
**DEPRECATION NOTICE**: This method is scheduled for removal in a future release.

* @return The uint32_t value at the specified location, or 0 if the value cannot be converted.
*/
DUCKDB_API uint32_t duckdb_value_uint32(duckdb_result *result, idx_t col, idx_t row);

/*!
**DEPRECATION NOTICE**: This method is scheduled for removal in a future release.

* @return The uint64_t value at the specified location, or 0 if the value cannot be converted.
*/
DUCKDB_API uint64_t duckdb_value_uint64(duckdb_result *result, idx_t col, idx_t row);

/*!
**DEPRECATION NOTICE**: This method is scheduled for removal in a future release.

* @return The float value at the specified location, or 0 if the value cannot be converted.
*/
DUCKDB_API float duckdb_value_float(duckdb_result *result, idx_t col, idx_t row);

/*!
**DEPRECATION NOTICE**: This method is scheduled for removal in a future release.

* @return The double value at the specified location, or 0 if the value cannot be converted.
*/
DUCKDB_API double duckdb_value_double(duckdb_result *result, idx_t col, idx_t row);

/*!
**DEPRECATION NOTICE**: This method is scheduled for removal in a future release.

* @return The duckdb_date value at the specified location, or 0 if the value cannot be converted.
*/
DUCKDB_API duckdb_date duckdb_value_date(duckdb_result *result, idx_t col, idx_t row);

/*!
**DEPRECATION NOTICE**: This method is scheduled for removal in a future release.

* @return The duckdb_time value at the specified location, or 0 if the value cannot be converted.
*/
DUCKDB_API duckdb_time duckdb_value_time(duckdb_result *result, idx_t col, idx_t row);

/*!
**DEPRECATION NOTICE**: This method is scheduled for removal in a future release.

* @return The duckdb_timestamp value at the specified location, or 0 if the value cannot be converted.
*/
DUCKDB_API duckdb_timestamp duckdb_value_timestamp(duckdb_result *result, idx_t col, idx_t row);

/*!
**DEPRECATION NOTICE**: This method is scheduled for removal in a future release.

* @return The duckdb_interval value at the specified location, or 0 if the value cannot be converted.
*/
DUCKDB_API duckdb_interval duckdb_value_interval(duckdb_result *result, idx_t col, idx_t row);

/*!
**DEPRECATED**: Use duckdb_value_string instead. This function does not work correctly if the string contains null
bytes.

* @return The text value at the specified location as a null-terminated string, or nullptr if the value cannot be
converted. The result must be freed with `duckdb_free`.
*/
DUCKDB_API char *duckdb_value_varchar(duckdb_result *result, idx_t col, idx_t row);

/*!
**DEPRECATION NOTICE**: This method is scheduled for removal in a future release.

No support for nested types, and for other complex types.
The resulting field "string.data" must be freed with `duckdb_free.`

* @return The string value at the specified location. Attempts to cast the result value to string.
*/
DUCKDB_API duckdb_string duckdb_value_string(duckdb_result *result, idx_t col, idx_t row);

/*!
**DEPRECATED**: Use duckdb_value_string_internal instead. This function does not work correctly if the string contains
null bytes.

* @return The char* value at the specified location. ONLY works on VARCHAR columns and does not auto-cast.
If the column is NOT a VARCHAR column this function will return NULL.

The result must NOT be freed.
*/
DUCKDB_API char *duckdb_value_varchar_internal(duckdb_result *result, idx_t col, idx_t row);

/*!
**DEPRECATED**: Use duckdb_value_string_internal instead. This function does not work correctly if the string contains
null bytes.
* @return The char* value at the specified location. ONLY works on VARCHAR columns and does not auto-cast.
If the column is NOT a VARCHAR column this function will return NULL.

The result must NOT be freed.
*/
DUCKDB_API duckdb_string duckdb_value_string_internal(duckdb_result *result, idx_t col, idx_t row);

/*!
**DEPRECATION NOTICE**: This method is scheduled for removal in a future release.

* @return The duckdb_blob value at the specified location. Returns a blob with blob.data set to nullptr if the
value cannot be converted. The resulting field "blob.data" must be freed with `duckdb_free.`
*/
DUCKDB_API duckdb_blob duckdb_value_blob(duckdb_result *result, idx_t col, idx_t row);

/*!
**DEPRECATION NOTICE**: This method is scheduled for removal in a future release.

* @return Returns true if the value at the specified index is NULL, and false otherwise.
*/
DUCKDB_API bool duckdb_value_is_null(duckdb_result *result, idx_t col, idx_t row);

#endif
//===--------------------------------------------------------------------===//
// Helpers
//===--------------------------------------------------------------------===//

/*!
Allocate `size` bytes of memory using the duckdb internal malloc function. Any memory allocated in this manner
should be freed using `duckdb_free`.

* @param size The number of bytes to allocate.
* @return A pointer to the allocated memory region.
*/
DUCKDB_API void *duckdb_malloc(size_t size);

/*!
Free a value returned from `duckdb_malloc`, `duckdb_value_varchar`, `duckdb_value_blob`, or
`duckdb_value_string`.

* @param ptr The memory region to de-allocate.
*/
DUCKDB_API void duckdb_free(void *ptr);

/*!
The internal vector size used by DuckDB.
This is the amount of tuples that will fit into a data chunk created by `duckdb_create_data_chunk`.

* @return The vector size.
*/
DUCKDB_API idx_t duckdb_vector_size();

/*!
Whether or not the duckdb_string_t value is inlined.
This means that the data of the string does not have a separate allocation.

*/
DUCKDB_API bool duckdb_string_is_inlined(duckdb_string_t string);

/*!
Get the string length of a string_t

* @param string The string to get the length of.
* @return The length.
*/
DUCKDB_API uint32_t duckdb_string_t_length(duckdb_string_t string);

/*!
Get a pointer to the string data of a string_t

* @param string The string to get the pointer to.
* @return The pointer.
*/
DUCKDB_API const char *duckdb_string_t_data(duckdb_string_t *string);

//===--------------------------------------------------------------------===//
// Date Time Timestamp Helpers
//===--------------------------------------------------------------------===//

/*!
Decompose a `duckdb_date` object into year, month and date (stored as `duckdb_date_struct`).

* @param date The date object, as obtained from a `DUCKDB_TYPE_DATE` column.
* @return The `duckdb_date_struct` with the decomposed elements.
*/
DUCKDB_API duckdb_date_struct duckdb_from_date(duckdb_date date);

/*!
Re-compose a `duckdb_date` from year, month and date (`duckdb_date_struct`).

* @param date The year, month and date stored in a `duckdb_date_struct`.
* @return The `duckdb_date` element.
*/
DUCKDB_API duckdb_date duckdb_to_date(duckdb_date_struct date);

/*!
Test a `duckdb_date` to see if it is a finite value.

* @param date The date object, as obtained from a `DUCKDB_TYPE_DATE` column.
* @return True if the date is finite, false if it is ±infinity.
*/
DUCKDB_API bool duckdb_is_finite_date(duckdb_date date);

/*!
Decompose a `duckdb_time` object into hour, minute, second and microsecond (stored as `duckdb_time_struct`).

* @param time The time object, as obtained from a `DUCKDB_TYPE_TIME` column.
* @return The `duckdb_time_struct` with the decomposed elements.
*/
DUCKDB_API duckdb_time_struct duckdb_from_time(duckdb_time time);

/*!
Create a `duckdb_time_tz` object from micros and a timezone offset.

* @param micros The microsecond component of the time.
* @param offset The timezone offset component of the time.
* @return The `duckdb_time_tz` element.
*/
DUCKDB_API duckdb_time_tz duckdb_create_time_tz(int64_t micros, int32_t offset);

/*!
Decompose a TIME_TZ objects into micros and a timezone offset.

Use `duckdb_from_time` to further decompose the micros into hour, minute, second and microsecond.

* @param micros The time object, as obtained from a `DUCKDB_TYPE_TIME_TZ` column.
*/
DUCKDB_API duckdb_time_tz_struct duckdb_from_time_tz(duckdb_time_tz micros);

/*!
Re-compose a `duckdb_time` from hour, minute, second and microsecond (`duckdb_time_struct`).

* @param time The hour, minute, second and microsecond in a `duckdb_time_struct`.
* @return The `duckdb_time` element.
*/
DUCKDB_API duckdb_time duckdb_to_time(duckdb_time_struct time);

/*!
Decompose a `duckdb_timestamp` object into a `duckdb_timestamp_struct`.

* @param ts The ts object, as obtained from a `DUCKDB_TYPE_TIMESTAMP` column.
* @return The `duckdb_timestamp_struct` with the decomposed elements.
*/
DUCKDB_API duckdb_timestamp_struct duckdb_from_timestamp(duckdb_timestamp ts);

/*!
Re-compose a `duckdb_timestamp` from a duckdb_timestamp_struct.

* @param ts The de-composed elements in a `duckdb_timestamp_struct`.
* @return The `duckdb_timestamp` element.
*/
DUCKDB_API duckdb_timestamp duckdb_to_timestamp(duckdb_timestamp_struct ts);

/*!
Test a `duckdb_timestamp` to see if it is a finite value.

* @param ts The timestamp object, as obtained from a `DUCKDB_TYPE_TIMESTAMP` column.
* @return True if the timestamp is finite, false if it is ±infinity.
*/
DUCKDB_API bool duckdb_is_finite_timestamp(duckdb_timestamp ts);

//===--------------------------------------------------------------------===//
// Hugeint Helpers
//===--------------------------------------------------------------------===//

/*!
Converts a duckdb_hugeint object (as obtained from a `DUCKDB_TYPE_HUGEINT` column) into a double.

* @param val The hugeint value.
* @return The converted `double` element.
*/
DUCKDB_API double duckdb_hugeint_to_double(duckdb_hugeint val);

/*!
Converts a double value to a duckdb_hugeint object.

If the conversion fails because the double value is too big the result will be 0.

* @param val The double value.
* @return The converted `duckdb_hugeint` element.
*/
DUCKDB_API duckdb_hugeint duckdb_double_to_hugeint(double val);

//===--------------------------------------------------------------------===//
// Unsigned Hugeint Helpers
//===--------------------------------------------------------------------===//

/*!
Converts a duckdb_uhugeint object (as obtained from a `DUCKDB_TYPE_UHUGEINT` column) into a double.

* @param val The uhugeint value.
* @return The converted `double` element.
*/
DUCKDB_API double duckdb_uhugeint_to_double(duckdb_uhugeint val);

/*!
Converts a double value to a duckdb_uhugeint object.

If the conversion fails because the double value is too big the result will be 0.

* @param val The double value.
* @return The converted `duckdb_uhugeint` element.
*/
DUCKDB_API duckdb_uhugeint duckdb_double_to_uhugeint(double val);

//===--------------------------------------------------------------------===//
// Decimal Helpers
//===--------------------------------------------------------------------===//

/*!
Converts a double value to a duckdb_decimal object.

If the conversion fails because the double value is too big, or the width/scale are invalid the result will be 0.

* @param val The double value.
* @return The converted `duckdb_decimal` element.
*/
DUCKDB_API duckdb_decimal duckdb_double_to_decimal(double val, uint8_t width, uint8_t scale);

/*!
Converts a duckdb_decimal object (as obtained from a `DUCKDB_TYPE_DECIMAL` column) into a double.

* @param val The decimal value.
* @return The converted `double` element.
*/
DUCKDB_API double duckdb_decimal_to_double(duckdb_decimal val);

//===--------------------------------------------------------------------===//
// Prepared Statements
//===--------------------------------------------------------------------===//

// A prepared statement is a parameterized query that allows you to bind parameters to it.
// * This is useful to easily supply parameters to functions and avoid SQL injection attacks.
// * This is useful to speed up queries that you will execute several times with different parameters.
// Because the query will only be parsed, bound, optimized and planned once during the prepare stage,
// rather than once per execution.
// For example:
//   SELECT * FROM tbl WHERE id=?
// Or a query with multiple parameters:
//   SELECT * FROM tbl WHERE id=$1 OR name=$2
/*!
Create a prepared statement object from a query.

Note that after calling `duckdb_prepare`, the prepared statement should always be destroyed using
`duckdb_destroy_prepare`, even if the prepare fails.

If the prepare fails, `duckdb_prepare_error` can be called to obtain the reason why the prepare failed.

* @param connection The connection object
* @param query The SQL query to prepare
* @param out_prepared_statement The resulting prepared statement object
* @return `DuckDBSuccess` on success or `DuckDBError` on failure.
*/
DUCKDB_API duckdb_state duckdb_prepare(duckdb_connection connection, const char *query,
                                       duckdb_prepared_statement *out_prepared_statement);

/*!
Closes the prepared statement and de-allocates all memory allocated for the statement.

* @param prepared_statement The prepared statement to destroy.
*/
DUCKDB_API void duckdb_destroy_prepare(duckdb_prepared_statement *prepared_statement);

/*!
Returns the error message associated with the given prepared statement.
If the prepared statement has no error message, this returns `nullptr` instead.

The error message should not be freed. It will be de-allocated when `duckdb_destroy_prepare` is called.

* @param prepared_statement The prepared statement to obtain the error from.
* @return The error message, or `nullptr` if there is none.
*/
DUCKDB_API const char *duckdb_prepare_error(duckdb_prepared_statement prepared_statement);

/*!
Returns the number of parameters that can be provided to the given prepared statement.

Returns 0 if the query was not successfully prepared.

* @param prepared_statement The prepared statement to obtain the number of parameters for.
*/
DUCKDB_API idx_t duckdb_nparams(duckdb_prepared_statement prepared_statement);

/*!
Returns the name used to identify the parameter
The returned string should be freed using `duckdb_free`.

Returns NULL if the index is out of range for the provided prepared statement.

* @param prepared_statement The prepared statement for which to get the parameter name from.
*/
DUCKDB_API const char *duckdb_parameter_name(duckdb_prepared_statement prepared_statement, idx_t index);

/*!
Returns the parameter type for the parameter at the given index.

Returns `DUCKDB_TYPE_INVALID` if the parameter index is out of range or the statement was not successfully prepared.

* @param prepared_statement The prepared statement.
* @param param_idx The parameter index.
* @return The parameter type
*/
DUCKDB_API duckdb_type duckdb_param_type(duckdb_prepared_statement prepared_statement, idx_t param_idx);

/*!
Clear the params bind to the prepared statement.
*/
DUCKDB_API duckdb_state duckdb_clear_bindings(duckdb_prepared_statement prepared_statement);

/*!
Returns the statement type of the statement to be executed

* @param statement The prepared statement.
* @return duckdb_statement_type value or DUCKDB_STATEMENT_TYPE_INVALID
*/
DUCKDB_API duckdb_statement_type duckdb_prepared_statement_type(duckdb_prepared_statement statement);

//===--------------------------------------------------------------------===//
// Bind Values To Prepared Statements
//===--------------------------------------------------------------------===//

/*!
Binds a value to the prepared statement at the specified index.
*/
DUCKDB_API duckdb_state duckdb_bind_value(duckdb_prepared_statement prepared_statement, idx_t param_idx,
                                          duckdb_value val);

/*!
Retrieve the index of the parameter for the prepared statement, identified by name
*/
DUCKDB_API duckdb_state duckdb_bind_parameter_index(duckdb_prepared_statement prepared_statement, idx_t *param_idx_out,
                                                    const char *name);

/*!
Binds a bool value to the prepared statement at the specified index.
*/
DUCKDB_API duckdb_state duckdb_bind_boolean(duckdb_prepared_statement prepared_statement, idx_t param_idx, bool val);

/*!
Binds an int8_t value to the prepared statement at the specified index.
*/
DUCKDB_API duckdb_state duckdb_bind_int8(duckdb_prepared_statement prepared_statement, idx_t param_idx, int8_t val);

/*!
Binds an int16_t value to the prepared statement at the specified index.
*/
DUCKDB_API duckdb_state duckdb_bind_int16(duckdb_prepared_statement prepared_statement, idx_t param_idx, int16_t val);

/*!
Binds an int32_t value to the prepared statement at the specified index.
*/
DUCKDB_API duckdb_state duckdb_bind_int32(duckdb_prepared_statement prepared_statement, idx_t param_idx, int32_t val);

/*!
Binds an int64_t value to the prepared statement at the specified index.
*/
DUCKDB_API duckdb_state duckdb_bind_int64(duckdb_prepared_statement prepared_statement, idx_t param_idx, int64_t val);

/*!
Binds a duckdb_hugeint value to the prepared statement at the specified index.
*/
DUCKDB_API duckdb_state duckdb_bind_hugeint(duckdb_prepared_statement prepared_statement, idx_t param_idx,
                                            duckdb_hugeint val);

/*!
Binds an duckdb_uhugeint value to the prepared statement at the specified index.
*/
DUCKDB_API duckdb_state duckdb_bind_uhugeint(duckdb_prepared_statement prepared_statement, idx_t param_idx,
                                             duckdb_uhugeint val);

/*!
Binds a duckdb_decimal value to the prepared statement at the specified index.
*/
DUCKDB_API duckdb_state duckdb_bind_decimal(duckdb_prepared_statement prepared_statement, idx_t param_idx,
                                            duckdb_decimal val);

/*!
Binds an uint8_t value to the prepared statement at the specified index.
*/
DUCKDB_API duckdb_state duckdb_bind_uint8(duckdb_prepared_statement prepared_statement, idx_t param_idx, uint8_t val);

/*!
Binds an uint16_t value to the prepared statement at the specified index.
*/
DUCKDB_API duckdb_state duckdb_bind_uint16(duckdb_prepared_statement prepared_statement, idx_t param_idx, uint16_t val);

/*!
Binds an uint32_t value to the prepared statement at the specified index.
*/
DUCKDB_API duckdb_state duckdb_bind_uint32(duckdb_prepared_statement prepared_statement, idx_t param_idx, uint32_t val);

/*!
Binds an uint64_t value to the prepared statement at the specified index.
*/
DUCKDB_API duckdb_state duckdb_bind_uint64(duckdb_prepared_statement prepared_statement, idx_t param_idx, uint64_t val);

/*!
Binds a float value to the prepared statement at the specified index.
*/
DUCKDB_API duckdb_state duckdb_bind_float(duckdb_prepared_statement prepared_statement, idx_t param_idx, float val);

/*!
Binds a double value to the prepared statement at the specified index.
*/
DUCKDB_API duckdb_state duckdb_bind_double(duckdb_prepared_statement prepared_statement, idx_t param_idx, double val);

/*!
Binds a duckdb_date value to the prepared statement at the specified index.
*/
DUCKDB_API duckdb_state duckdb_bind_date(duckdb_prepared_statement prepared_statement, idx_t param_idx,
                                         duckdb_date val);

/*!
Binds a duckdb_time value to the prepared statement at the specified index.
*/
DUCKDB_API duckdb_state duckdb_bind_time(duckdb_prepared_statement prepared_statement, idx_t param_idx,
                                         duckdb_time val);

/*!
Binds a duckdb_timestamp value to the prepared statement at the specified index.
*/
DUCKDB_API duckdb_state duckdb_bind_timestamp(duckdb_prepared_statement prepared_statement, idx_t param_idx,
                                              duckdb_timestamp val);

/*!
Binds a duckdb_timestamp value to the prepared statement at the specified index.
*/
DUCKDB_API duckdb_state duckdb_bind_timestamp_tz(duckdb_prepared_statement prepared_statement, idx_t param_idx,
                                                 duckdb_timestamp val);

/*!
Binds a duckdb_interval value to the prepared statement at the specified index.
*/
DUCKDB_API duckdb_state duckdb_bind_interval(duckdb_prepared_statement prepared_statement, idx_t param_idx,
                                             duckdb_interval val);

/*!
Binds a null-terminated varchar value to the prepared statement at the specified index.
*/
DUCKDB_API duckdb_state duckdb_bind_varchar(duckdb_prepared_statement prepared_statement, idx_t param_idx,
                                            const char *val);

/*!
Binds a varchar value to the prepared statement at the specified index.
*/
DUCKDB_API duckdb_state duckdb_bind_varchar_length(duckdb_prepared_statement prepared_statement, idx_t param_idx,
                                                   const char *val, idx_t length);

/*!
Binds a blob value to the prepared statement at the specified index.
*/
DUCKDB_API duckdb_state duckdb_bind_blob(duckdb_prepared_statement prepared_statement, idx_t param_idx,
                                         const void *data, idx_t length);

/*!
Binds a NULL value to the prepared statement at the specified index.
*/
DUCKDB_API duckdb_state duckdb_bind_null(duckdb_prepared_statement prepared_statement, idx_t param_idx);

//===--------------------------------------------------------------------===//
// Execute Prepared Statements
//===--------------------------------------------------------------------===//

/*!
Executes the prepared statement with the given bound parameters, and returns a materialized query result.

This method can be called multiple times for each prepared statement, and the parameters can be modified
between calls to this function.

Note that the result must be freed with `duckdb_destroy_result`.

* @param prepared_statement The prepared statement to execute.
* @param out_result The query result.
* @return `DuckDBSuccess` on success or `DuckDBError` on failure.
*/
DUCKDB_API duckdb_state duckdb_execute_prepared(duckdb_prepared_statement prepared_statement,
                                                duckdb_result *out_result);

#ifndef DUCKDB_API_NO_DEPRECATED
/*!
**DEPRECATION NOTICE**: This method is scheduled for removal in a future release.

Executes the prepared statement with the given bound parameters, and returns an optionally-streaming query result.
To determine if the resulting query was in fact streamed, use `duckdb_result_is_streaming`

This method can be called multiple times for each prepared statement, and the parameters can be modified
between calls to this function.

Note that the result must be freed with `duckdb_destroy_result`.

* @param prepared_statement The prepared statement to execute.
* @param out_result The query result.
* @return `DuckDBSuccess` on success or `DuckDBError` on failure.
*/
DUCKDB_API duckdb_state duckdb_execute_prepared_streaming(duckdb_prepared_statement prepared_statement,
                                                          duckdb_result *out_result);

#endif
//===--------------------------------------------------------------------===//
// Extract Statements
//===--------------------------------------------------------------------===//

// A query string can be extracted into multiple SQL statements. Each statement can be prepared and executed separately.
/*!
Extract all statements from a query.
Note that after calling `duckdb_extract_statements`, the extracted statements should always be destroyed using
`duckdb_destroy_extracted`, even if no statements were extracted.

If the extract fails, `duckdb_extract_statements_error` can be called to obtain the reason why the extract failed.

* @param connection The connection object
* @param query The SQL query to extract
* @param out_extracted_statements The resulting extracted statements object
* @return The number of extracted statements or 0 on failure.
*/
DUCKDB_API idx_t duckdb_extract_statements(duckdb_connection connection, const char *query,
                                           duckdb_extracted_statements *out_extracted_statements);

/*!
Prepare an extracted statement.
Note that after calling `duckdb_prepare_extracted_statement`, the prepared statement should always be destroyed using
`duckdb_destroy_prepare`, even if the prepare fails.

If the prepare fails, `duckdb_prepare_error` can be called to obtain the reason why the prepare failed.

* @param connection The connection object
* @param extracted_statements The extracted statements object
* @param index The index of the extracted statement to prepare
* @param out_prepared_statement The resulting prepared statement object
* @return `DuckDBSuccess` on success or `DuckDBError` on failure.
*/
DUCKDB_API duckdb_state duckdb_prepare_extracted_statement(duckdb_connection connection,
                                                           duckdb_extracted_statements extracted_statements,
                                                           idx_t index,
                                                           duckdb_prepared_statement *out_prepared_statement);

/*!
Returns the error message contained within the extracted statements.
The result of this function must not be freed. It will be cleaned up when `duckdb_destroy_extracted` is called.

* @param extracted_statements The extracted statements to fetch the error from.
* @return The error of the extracted statements.
*/
DUCKDB_API const char *duckdb_extract_statements_error(duckdb_extracted_statements extracted_statements);

/*!
De-allocates all memory allocated for the extracted statements.
* @param extracted_statements The extracted statements to destroy.
*/
DUCKDB_API void duckdb_destroy_extracted(duckdb_extracted_statements *extracted_statements);

//===--------------------------------------------------------------------===//
// Pending Result Interface
//===--------------------------------------------------------------------===//

/*!
Executes the prepared statement with the given bound parameters, and returns a pending result.
The pending result represents an intermediate structure for a query that is not yet fully executed.
The pending result can be used to incrementally execute a query, returning control to the client between tasks.

Note that after calling `duckdb_pending_prepared`, the pending result should always be destroyed using
`duckdb_destroy_pending`, even if this function returns DuckDBError.

* @param prepared_statement The prepared statement to execute.
* @param out_result The pending query result.
* @return `DuckDBSuccess` on success or `DuckDBError` on failure.
*/
DUCKDB_API duckdb_state duckdb_pending_prepared(duckdb_prepared_statement prepared_statement,
                                                duckdb_pending_result *out_result);

#ifndef DUCKDB_API_NO_DEPRECATED
/*!
**DEPRECATION NOTICE**: This method is scheduled for removal in a future release.

Executes the prepared statement with the given bound parameters, and returns a pending result.
This pending result will create a streaming duckdb_result when executed.
The pending result represents an intermediate structure for a query that is not yet fully executed.

Note that after calling `duckdb_pending_prepared_streaming`, the pending result should always be destroyed using
`duckdb_destroy_pending`, even if this function returns DuckDBError.

* @param prepared_statement The prepared statement to execute.
* @param out_result The pending query result.
* @return `DuckDBSuccess` on success or `DuckDBError` on failure.
*/
DUCKDB_API duckdb_state duckdb_pending_prepared_streaming(duckdb_prepared_statement prepared_statement,
                                                          duckdb_pending_result *out_result);

#endif
/*!
Closes the pending result and de-allocates all memory allocated for the result.

* @param pending_result The pending result to destroy.
*/
DUCKDB_API void duckdb_destroy_pending(duckdb_pending_result *pending_result);

/*!
Returns the error message contained within the pending result.

The result of this function must not be freed. It will be cleaned up when `duckdb_destroy_pending` is called.

* @param pending_result The pending result to fetch the error from.
* @return The error of the pending result.
*/
DUCKDB_API const char *duckdb_pending_error(duckdb_pending_result pending_result);

/*!
Executes a single task within the query, returning whether or not the query is ready.

If this returns DUCKDB_PENDING_RESULT_READY, the duckdb_execute_pending function can be called to obtain the result.
If this returns DUCKDB_PENDING_RESULT_NOT_READY, the duckdb_pending_execute_task function should be called again.
If this returns DUCKDB_PENDING_ERROR, an error occurred during execution.

The error message can be obtained by calling duckdb_pending_error on the pending_result.

* @param pending_result The pending result to execute a task within.
* @return The state of the pending result after the execution.
*/
DUCKDB_API duckdb_pending_state duckdb_pending_execute_task(duckdb_pending_result pending_result);

/*!
If this returns DUCKDB_PENDING_RESULT_READY, the duckdb_execute_pending function can be called to obtain the result.
If this returns DUCKDB_PENDING_RESULT_NOT_READY, the duckdb_pending_execute_check_state function should be called again.
If this returns DUCKDB_PENDING_ERROR, an error occurred during execution.

The error message can be obtained by calling duckdb_pending_error on the pending_result.

* @param pending_result The pending result.
* @return The state of the pending result.
*/
DUCKDB_API duckdb_pending_state duckdb_pending_execute_check_state(duckdb_pending_result pending_result);

/*!
Fully execute a pending query result, returning the final query result.

If duckdb_pending_execute_task has been called until DUCKDB_PENDING_RESULT_READY was returned, this will return fast.
Otherwise, all remaining tasks must be executed first.

Note that the result must be freed with `duckdb_destroy_result`.

* @param pending_result The pending result to execute.
* @param out_result The result object.
* @return `DuckDBSuccess` on success or `DuckDBError` on failure.
*/
DUCKDB_API duckdb_state duckdb_execute_pending(duckdb_pending_result pending_result, duckdb_result *out_result);

/*!
Returns whether a duckdb_pending_state is finished executing. For example if `pending_state` is
DUCKDB_PENDING_RESULT_READY, this function will return true.

* @param pending_state The pending state on which to decide whether to finish execution.
* @return Boolean indicating pending execution should be considered finished.
*/
DUCKDB_API bool duckdb_pending_execution_is_finished(duckdb_pending_state pending_state);

//===--------------------------------------------------------------------===//
// Value Interface
//===--------------------------------------------------------------------===//

/*!
Destroys the value and de-allocates all memory allocated for that type.

* @param value The value to destroy.
*/
DUCKDB_API void duckdb_destroy_value(duckdb_value *value);

/*!
Creates a value from a null-terminated string

* @param text The null-terminated string
* @return The value. This must be destroyed with `duckdb_destroy_value`.
*/
DUCKDB_API duckdb_value duckdb_create_varchar(const char *text);

/*!
Creates a value from a string

* @param text The text
* @param length The length of the text
* @return The value. This must be destroyed with `duckdb_destroy_value`.
*/
DUCKDB_API duckdb_value duckdb_create_varchar_length(const char *text, idx_t length);

/*!
Creates a value from a boolean

* @param input The boolean value
* @return The value. This must be destroyed with `duckdb_destroy_value`.
*/
DUCKDB_API duckdb_value duckdb_create_bool(bool input);

/*!
Creates a value from a int8_t (a tinyint)

* @param input The tinyint value
* @return The value. This must be destroyed with `duckdb_destroy_value`.
*/
DUCKDB_API duckdb_value duckdb_create_int8(int8_t input);

/*!
Creates a value from a uint8_t (a utinyint)

* @param input The utinyint value
* @return The value. This must be destroyed with `duckdb_destroy_value`.
*/
DUCKDB_API duckdb_value duckdb_create_uint8(uint8_t input);

/*!
Creates a value from a int16_t (a smallint)

* @param input The smallint value
* @return The value. This must be destroyed with `duckdb_destroy_value`.
*/
DUCKDB_API duckdb_value duckdb_create_int16(int16_t input);

/*!
Creates a value from a uint16_t (a usmallint)

* @param input The usmallint value
* @return The value. This must be destroyed with `duckdb_destroy_value`.
*/
DUCKDB_API duckdb_value duckdb_create_uint16(uint16_t input);

/*!
Creates a value from a int32_t (an integer)

* @param input The integer value
* @return The value. This must be destroyed with `duckdb_destroy_value`.
*/
DUCKDB_API duckdb_value duckdb_create_int32(int32_t input);

/*!
Creates a value from a uint32_t (a uinteger)

* @param input The uinteger value
* @return The value. This must be destroyed with `duckdb_destroy_value`.
*/
DUCKDB_API duckdb_value duckdb_create_uint32(uint32_t input);

/*!
Creates a value from a uint64_t (a ubigint)

* @param input The ubigint value
* @return The value. This must be destroyed with `duckdb_destroy_value`.
*/
DUCKDB_API duckdb_value duckdb_create_uint64(uint64_t input);

/*!
Creates a value from an int64

* @return The value. This must be destroyed with `duckdb_destroy_value`.
*/
DUCKDB_API duckdb_value duckdb_create_int64(int64_t val);

/*!
Creates a value from a hugeint

* @param input The hugeint value
* @return The value. This must be destroyed with `duckdb_destroy_value`.
*/
DUCKDB_API duckdb_value duckdb_create_hugeint(duckdb_hugeint input);

/*!
Creates a value from a uhugeint

* @param input The uhugeint value
* @return The value. This must be destroyed with `duckdb_destroy_value`.
*/
DUCKDB_API duckdb_value duckdb_create_uhugeint(duckdb_uhugeint input);

/*!
Creates a value from a float

* @param input The float value
* @return The value. This must be destroyed with `duckdb_destroy_value`.
*/
DUCKDB_API duckdb_value duckdb_create_float(float input);

/*!
Creates a value from a double

* @param input The double value
* @return The value. This must be destroyed with `duckdb_destroy_value`.
*/
DUCKDB_API duckdb_value duckdb_create_double(double input);

/*!
Creates a value from a date

* @param input The date value
* @return The value. This must be destroyed with `duckdb_destroy_value`.
*/
DUCKDB_API duckdb_value duckdb_create_date(duckdb_date input);

/*!
Creates a value from a time

* @param input The time value
* @return The value. This must be destroyed with `duckdb_destroy_value`.
*/
DUCKDB_API duckdb_value duckdb_create_time(duckdb_time input);

/*!
Creates a value from a time_tz.
Not to be confused with `duckdb_create_time_tz`, which creates a duckdb_time_tz_t.

* @param value The time_tz value
* @return The value. This must be destroyed with `duckdb_destroy_value`.
*/
DUCKDB_API duckdb_value duckdb_create_time_tz_value(duckdb_time_tz value);

/*!
Creates a value from a timestamp

* @param input The timestamp value
* @return The value. This must be destroyed with `duckdb_destroy_value`.
*/
DUCKDB_API duckdb_value duckdb_create_timestamp(duckdb_timestamp input);

/*!
Creates a value from an interval

* @param input The interval value
* @return The value. This must be destroyed with `duckdb_destroy_value`.
*/
DUCKDB_API duckdb_value duckdb_create_interval(duckdb_interval input);

/*!
Creates a value from a blob

* @param data The blob data
* @param length The length of the blob data
* @return The value. This must be destroyed with `duckdb_destroy_value`.
*/
DUCKDB_API duckdb_value duckdb_create_blob(const uint8_t *data, idx_t length);

/*!
Returns the boolean value of the given value.

* @param val A duckdb_value containing a boolean
* @return A boolean, or false if the value cannot be converted
*/
DUCKDB_API bool duckdb_get_bool(duckdb_value val);

/*!
Returns the int8_t value of the given value.

* @param val A duckdb_value containing a tinyint
* @return A int8_t, or MinValue<int8> if the value cannot be converted
*/
DUCKDB_API int8_t duckdb_get_int8(duckdb_value val);

/*!
Returns the uint8_t value of the given value.

* @param val A duckdb_value containing a utinyint
* @return A uint8_t, or MinValue<uint8> if the value cannot be converted
*/
DUCKDB_API uint8_t duckdb_get_uint8(duckdb_value val);

/*!
Returns the int16_t value of the given value.

* @param val A duckdb_value containing a smallint
* @return A int16_t, or MinValue<int16> if the value cannot be converted
*/
DUCKDB_API int16_t duckdb_get_int16(duckdb_value val);

/*!
Returns the uint16_t value of the given value.

* @param val A duckdb_value containing a usmallint
* @return A uint16_t, or MinValue<uint16> if the value cannot be converted
*/
DUCKDB_API uint16_t duckdb_get_uint16(duckdb_value val);

/*!
Returns the int32_t value of the given value.

* @param val A duckdb_value containing a integer
* @return A int32_t, or MinValue<int32> if the value cannot be converted
*/
DUCKDB_API int32_t duckdb_get_int32(duckdb_value val);

/*!
Returns the uint32_t value of the given value.

* @param val A duckdb_value containing a uinteger
* @return A uint32_t, or MinValue<uint32> if the value cannot be converted
*/
DUCKDB_API uint32_t duckdb_get_uint32(duckdb_value val);

/*!
Returns the int64_t value of the given value.

* @param val A duckdb_value containing a bigint
* @return A int64_t, or MinValue<int64> if the value cannot be converted
*/
DUCKDB_API int64_t duckdb_get_int64(duckdb_value val);

/*!
Returns the uint64_t value of the given value.

* @param val A duckdb_value containing a ubigint
* @return A uint64_t, or MinValue<uint64> if the value cannot be converted
*/
DUCKDB_API uint64_t duckdb_get_uint64(duckdb_value val);

/*!
Returns the hugeint value of the given value.

* @param val A duckdb_value containing a hugeint
* @return A duckdb_hugeint, or MinValue<hugeint> if the value cannot be converted
*/
DUCKDB_API duckdb_hugeint duckdb_get_hugeint(duckdb_value val);

/*!
Returns the uhugeint value of the given value.

* @param val A duckdb_value containing a uhugeint
* @return A duckdb_uhugeint, or MinValue<uhugeint> if the value cannot be converted
*/
DUCKDB_API duckdb_uhugeint duckdb_get_uhugeint(duckdb_value val);

/*!
Returns the float value of the given value.

* @param val A duckdb_value containing a float
* @return A float, or NAN if the value cannot be converted
*/
DUCKDB_API float duckdb_get_float(duckdb_value val);

/*!
Returns the double value of the given value.

* @param val A duckdb_value containing a double
* @return A double, or NAN if the value cannot be converted
*/
DUCKDB_API double duckdb_get_double(duckdb_value val);

/*!
Returns the date value of the given value.

* @param val A duckdb_value containing a date
* @return A duckdb_date, or MinValue<date> if the value cannot be converted
*/
DUCKDB_API duckdb_date duckdb_get_date(duckdb_value val);

/*!
Returns the time value of the given value.

* @param val A duckdb_value containing a time
* @return A duckdb_time, or MinValue<time> if the value cannot be converted
*/
DUCKDB_API duckdb_time duckdb_get_time(duckdb_value val);

/*!
Returns the time_tz value of the given value.

* @param val A duckdb_value containing a time_tz
* @return A duckdb_time_tz, or MinValue<time_tz> if the value cannot be converted
*/
DUCKDB_API duckdb_time_tz duckdb_get_time_tz(duckdb_value val);

/*!
Returns the timestamp value of the given value.

* @param val A duckdb_value containing a timestamp
* @return A duckdb_timestamp, or MinValue<timestamp> if the value cannot be converted
*/
DUCKDB_API duckdb_timestamp duckdb_get_timestamp(duckdb_value val);

/*!
Returns the interval value of the given value.

* @param val A duckdb_value containing a interval
* @return A duckdb_interval, or MinValue<interval> if the value cannot be converted
*/
DUCKDB_API duckdb_interval duckdb_get_interval(duckdb_value val);

/*!
Returns the type of the given value. The type is valid as long as the value is not destroyed.
The type itself must not be destroyed.

* @param val A duckdb_value
* @return A duckdb_logical_type.
*/
DUCKDB_API duckdb_logical_type duckdb_get_value_type(duckdb_value val);

/*!
Returns the blob value of the given value.

* @param val A duckdb_value containing a blob
* @return A duckdb_blob
*/
DUCKDB_API duckdb_blob duckdb_get_blob(duckdb_value val);

/*!
Obtains a string representation of the given value.
The result must be destroyed with `duckdb_free`.

* @param value The value
* @return The string value. This must be destroyed with `duckdb_free`.
*/
DUCKDB_API char *duckdb_get_varchar(duckdb_value value);

/*!
Creates a struct value from a type and an array of values. Must be destroyed with `duckdb_destroy_value`.

* @param type The type of the struct
* @param values The values for the struct fields
* @return The struct value, or nullptr, if any child type is `DUCKDB_TYPE_ANY` or `DUCKDB_TYPE_INVALID`.
*/
DUCKDB_API duckdb_value duckdb_create_struct_value(duckdb_logical_type type, duckdb_value *values);

/*!
Creates a list value from a child (element) type and an array of values of length `value_count`.
Must be destroyed with `duckdb_destroy_value`.

* @param type The type of the list
* @param values The values for the list
* @param value_count The number of values in the list
* @return The list value, or nullptr, if the child type is `DUCKDB_TYPE_ANY` or `DUCKDB_TYPE_INVALID`.
*/
DUCKDB_API duckdb_value duckdb_create_list_value(duckdb_logical_type type, duckdb_value *values, idx_t value_count);

/*!
Creates an array value from a child (element) type and an array of values of length `value_count`.
Must be destroyed with `duckdb_destroy_value`.

* @param type The type of the array
* @param values The values for the array
* @param value_count The number of values in the array
* @return The array value, or nullptr, if the child type is `DUCKDB_TYPE_ANY` or `DUCKDB_TYPE_INVALID`.
*/
DUCKDB_API duckdb_value duckdb_create_array_value(duckdb_logical_type type, duckdb_value *values, idx_t value_count);

/*!
Returns the number of elements in a MAP value.

* @param value The MAP value.
* @return The number of elements in the map.
*/
DUCKDB_API idx_t duckdb_get_map_size(duckdb_value value);

/*!
Returns the MAP key at index as a duckdb_value.

* @param value The MAP value.
* @param index The index of the key.
* @return The key as a duckdb_value.
*/
DUCKDB_API duckdb_value duckdb_get_map_key(duckdb_value value, idx_t index);

/*!
Returns the MAP value at index as a duckdb_value.

* @param value The MAP value.
* @param index The index of the value.
* @return The value as a duckdb_value.
*/
DUCKDB_API duckdb_value duckdb_get_map_value(duckdb_value value, idx_t index);

//===--------------------------------------------------------------------===//
// Logical Type Interface
//===--------------------------------------------------------------------===//

/*!
Creates a `duckdb_logical_type` from a primitive type.
The resulting logical type must be destroyed with `duckdb_destroy_logical_type`.

Returns an invalid logical type, if type is: `DUCKDB_TYPE_INVALID`, `DUCKDB_TYPE_DECIMAL`, `DUCKDB_TYPE_ENUM`,
`DUCKDB_TYPE_LIST`, `DUCKDB_TYPE_STRUCT`, `DUCKDB_TYPE_MAP`, `DUCKDB_TYPE_ARRAY`, or `DUCKDB_TYPE_UNION`.

* @param type The primitive type to create.
* @return The logical type.
*/
DUCKDB_API duckdb_logical_type duckdb_create_logical_type(duckdb_type type);

/*!
Returns the alias of a duckdb_logical_type, if set, else `nullptr`.
The result must be destroyed with `duckdb_free`.

* @param type The logical type
* @return The alias or `nullptr`
*/
DUCKDB_API char *duckdb_logical_type_get_alias(duckdb_logical_type type);

/*!
Sets the alias of a duckdb_logical_type.

* @param type The logical type
* @param alias The alias to set
*/
DUCKDB_API void duckdb_logical_type_set_alias(duckdb_logical_type type, const char *alias);

/*!
Creates a LIST type from its child type.
The return type must be destroyed with `duckdb_destroy_logical_type`.

* @param type The child type of the list
* @return The logical type.
*/
DUCKDB_API duckdb_logical_type duckdb_create_list_type(duckdb_logical_type type);

/*!
Creates an ARRAY type from its child type.
The return type must be destroyed with `duckdb_destroy_logical_type`.

* @param type The child type of the array.
* @param array_size The number of elements in the array.
* @return The logical type.
*/
DUCKDB_API duckdb_logical_type duckdb_create_array_type(duckdb_logical_type type, idx_t array_size);

/*!
Creates a MAP type from its key type and value type.
The return type must be destroyed with `duckdb_destroy_logical_type`.

* @param key_type The map's key type.
* @param value_type The map's value type.
* @return The logical type.
*/
DUCKDB_API duckdb_logical_type duckdb_create_map_type(duckdb_logical_type key_type, duckdb_logical_type value_type);

/*!
Creates a UNION type from the passed arrays.
The return type must be destroyed with `duckdb_destroy_logical_type`.

* @param member_types The array of union member types.
* @param member_names The union member names.
* @param member_count The number of union members.
* @return The logical type.
*/
DUCKDB_API duckdb_logical_type duckdb_create_union_type(duckdb_logical_type *member_types, const char **member_names,
                                                        idx_t member_count);

/*!
Creates a STRUCT type based on the member types and names.
The resulting type must be destroyed with `duckdb_destroy_logical_type`.

* @param member_types The array of types of the struct members.
* @param member_names The array of names of the struct members.
* @param member_count The number of members of the struct.
* @return The logical type.
*/
DUCKDB_API duckdb_logical_type duckdb_create_struct_type(duckdb_logical_type *member_types, const char **member_names,
                                                         idx_t member_count);

/*!
Creates an ENUM type from the passed member name array.
The resulting type should be destroyed with `duckdb_destroy_logical_type`.

* @param member_names The array of names that the enum should consist of.
* @param member_count The number of elements that were specified in the array.
* @return The logical type.
*/
DUCKDB_API duckdb_logical_type duckdb_create_enum_type(const char **member_names, idx_t member_count);

/*!
Creates a DECIMAL type with the specified width and scale.
The resulting type should be destroyed with `duckdb_destroy_logical_type`.

* @param width The width of the decimal type
* @param scale The scale of the decimal type
* @return The logical type.
*/
DUCKDB_API duckdb_logical_type duckdb_create_decimal_type(uint8_t width, uint8_t scale);

/*!
Retrieves the enum `duckdb_type` of a `duckdb_logical_type`.

* @param type The logical type.
* @return The `duckdb_type` id.
*/
DUCKDB_API duckdb_type duckdb_get_type_id(duckdb_logical_type type);

/*!
Retrieves the width of a decimal type.

* @param type The logical type object
* @return The width of the decimal type
*/
DUCKDB_API uint8_t duckdb_decimal_width(duckdb_logical_type type);

/*!
Retrieves the scale of a decimal type.

* @param type The logical type object
* @return The scale of the decimal type
*/
DUCKDB_API uint8_t duckdb_decimal_scale(duckdb_logical_type type);

/*!
Retrieves the internal storage type of a decimal type.

* @param type The logical type object
* @return The internal type of the decimal type
*/
DUCKDB_API duckdb_type duckdb_decimal_internal_type(duckdb_logical_type type);

/*!
Retrieves the internal storage type of an enum type.

* @param type The logical type object
* @return The internal type of the enum type
*/
DUCKDB_API duckdb_type duckdb_enum_internal_type(duckdb_logical_type type);

/*!
Retrieves the dictionary size of the enum type.

* @param type The logical type object
* @return The dictionary size of the enum type
*/
DUCKDB_API uint32_t duckdb_enum_dictionary_size(duckdb_logical_type type);

/*!
Retrieves the dictionary value at the specified position from the enum.

The result must be freed with `duckdb_free`.

* @param type The logical type object
* @param index The index in the dictionary
* @return The string value of the enum type. Must be freed with `duckdb_free`.
*/
DUCKDB_API char *duckdb_enum_dictionary_value(duckdb_logical_type type, idx_t index);

/*!
Retrieves the child type of the given LIST type. Also accepts MAP types.
The result must be freed with `duckdb_destroy_logical_type`.

* @param type The logical type, either LIST or MAP.
* @return The child type of the LIST or MAP type.
*/
DUCKDB_API duckdb_logical_type duckdb_list_type_child_type(duckdb_logical_type type);

/*!
Retrieves the child type of the given ARRAY type.

The result must be freed with `duckdb_destroy_logical_type`.

* @param type The logical type. Must be ARRAY.
* @return The child type of the ARRAY type.
*/
DUCKDB_API duckdb_logical_type duckdb_array_type_child_type(duckdb_logical_type type);

/*!
Retrieves the array size of the given array type.

* @param type The logical type object
* @return The fixed number of elements the values of this array type can store.
*/
DUCKDB_API idx_t duckdb_array_type_array_size(duckdb_logical_type type);

/*!
Retrieves the key type of the given map type.

The result must be freed with `duckdb_destroy_logical_type`.

* @param type The logical type object
* @return The key type of the map type. Must be destroyed with `duckdb_destroy_logical_type`.
*/
DUCKDB_API duckdb_logical_type duckdb_map_type_key_type(duckdb_logical_type type);

/*!
Retrieves the value type of the given map type.

The result must be freed with `duckdb_destroy_logical_type`.

* @param type The logical type object
* @return The value type of the map type. Must be destroyed with `duckdb_destroy_logical_type`.
*/
DUCKDB_API duckdb_logical_type duckdb_map_type_value_type(duckdb_logical_type type);

/*!
Returns the number of children of a struct type.

* @param type The logical type object
* @return The number of children of a struct type.
*/
DUCKDB_API idx_t duckdb_struct_type_child_count(duckdb_logical_type type);

/*!
Retrieves the name of the struct child.

The result must be freed with `duckdb_free`.

* @param type The logical type object
* @param index The child index
* @return The name of the struct type. Must be freed with `duckdb_free`.
*/
DUCKDB_API char *duckdb_struct_type_child_name(duckdb_logical_type type, idx_t index);

/*!
Retrieves the child type of the given struct type at the specified index.

The result must be freed with `duckdb_destroy_logical_type`.

* @param type The logical type object
* @param index The child index
* @return The child type of the struct type. Must be destroyed with `duckdb_destroy_logical_type`.
*/
DUCKDB_API duckdb_logical_type duckdb_struct_type_child_type(duckdb_logical_type type, idx_t index);

/*!
Returns the number of members that the union type has.

* @param type The logical type (union) object
* @return The number of members of a union type.
*/
DUCKDB_API idx_t duckdb_union_type_member_count(duckdb_logical_type type);

/*!
Retrieves the name of the union member.

The result must be freed with `duckdb_free`.

* @param type The logical type object
* @param index The child index
* @return The name of the union member. Must be freed with `duckdb_free`.
*/
DUCKDB_API char *duckdb_union_type_member_name(duckdb_logical_type type, idx_t index);

/*!
Retrieves the child type of the given union member at the specified index.

The result must be freed with `duckdb_destroy_logical_type`.

* @param type The logical type object
* @param index The child index
* @return The child type of the union member. Must be destroyed with `duckdb_destroy_logical_type`.
*/
DUCKDB_API duckdb_logical_type duckdb_union_type_member_type(duckdb_logical_type type, idx_t index);

/*!
Destroys the logical type and de-allocates all memory allocated for that type.

* @param type The logical type to destroy.
*/
DUCKDB_API void duckdb_destroy_logical_type(duckdb_logical_type *type);

/*!
Registers a custom type within the given connection.
The type must have an alias

* @param con The connection to use
* @param type The custom type to register
* @return Whether or not the registration was successful.
*/
DUCKDB_API duckdb_state duckdb_register_logical_type(duckdb_connection con, duckdb_logical_type type,
                                                     duckdb_create_type_info info);

//===--------------------------------------------------------------------===//
// Data Chunk Interface
//===--------------------------------------------------------------------===//

/*!
Creates an empty data chunk with the specified column types.
The result must be destroyed with `duckdb_destroy_data_chunk`.

* @param types An array of column types. Column types can not contain ANY and INVALID types.
* @param column_count The number of columns.
* @return The data chunk.
*/
DUCKDB_API duckdb_data_chunk duckdb_create_data_chunk(duckdb_logical_type *types, idx_t column_count);

/*!
Destroys the data chunk and de-allocates all memory allocated for that chunk.

* @param chunk The data chunk to destroy.
*/
DUCKDB_API void duckdb_destroy_data_chunk(duckdb_data_chunk *chunk);

/*!
Resets a data chunk, clearing the validity masks and setting the cardinality of the data chunk to 0.
After calling this method, you must call `duckdb_vector_get_validity` and `duckdb_vector_get_data` to obtain current
data and validity pointers

* @param chunk The data chunk to reset.
*/
DUCKDB_API void duckdb_data_chunk_reset(duckdb_data_chunk chunk);

/*!
Retrieves the number of columns in a data chunk.

* @param chunk The data chunk to get the data from
* @return The number of columns in the data chunk
*/
DUCKDB_API idx_t duckdb_data_chunk_get_column_count(duckdb_data_chunk chunk);

/*!
Retrieves the vector at the specified column index in the data chunk.

The pointer to the vector is valid for as long as the chunk is alive.
It does NOT need to be destroyed.

* @param chunk The data chunk to get the data from
* @return The vector
*/
DUCKDB_API duckdb_vector duckdb_data_chunk_get_vector(duckdb_data_chunk chunk, idx_t col_idx);

/*!
Retrieves the current number of tuples in a data chunk.

* @param chunk The data chunk to get the data from
* @return The number of tuples in the data chunk
*/
DUCKDB_API idx_t duckdb_data_chunk_get_size(duckdb_data_chunk chunk);

/*!
Sets the current number of tuples in a data chunk.

* @param chunk The data chunk to set the size in
* @param size The number of tuples in the data chunk
*/
DUCKDB_API void duckdb_data_chunk_set_size(duckdb_data_chunk chunk, idx_t size);

//===--------------------------------------------------------------------===//
// Vector Interface
//===--------------------------------------------------------------------===//

/*!
Retrieves the column type of the specified vector.

The result must be destroyed with `duckdb_destroy_logical_type`.

* @param vector The vector get the data from
* @return The type of the vector
*/
DUCKDB_API duckdb_logical_type duckdb_vector_get_column_type(duckdb_vector vector);

/*!
Retrieves the data pointer of the vector.

The data pointer can be used to read or write values from the vector.
How to read or write values depends on the type of the vector.

* @param vector The vector to get the data from
* @return The data pointer
*/
DUCKDB_API void *duckdb_vector_get_data(duckdb_vector vector);

/*!
Retrieves the validity mask pointer of the specified vector.

If all values are valid, this function MIGHT return NULL!

The validity mask is a bitset that signifies null-ness within the data chunk.
It is a series of uint64_t values, where each uint64_t value contains validity for 64 tuples.
The bit is set to 1 if the value is valid (i.e. not NULL) or 0 if the value is invalid (i.e. NULL).

Validity of a specific value can be obtained like this:

idx_t entry_idx = row_idx / 64;
idx_t idx_in_entry = row_idx % 64;
bool is_valid = validity_mask[entry_idx] & (1 << idx_in_entry);

Alternatively, the (slower) duckdb_validity_row_is_valid function can be used.

* @param vector The vector to get the data from
* @return The pointer to the validity mask, or NULL if no validity mask is present
*/
DUCKDB_API uint64_t *duckdb_vector_get_validity(duckdb_vector vector);

/*!
Ensures the validity mask is writable by allocating it.

After this function is called, `duckdb_vector_get_validity` will ALWAYS return non-NULL.
This allows null values to be written to the vector, regardless of whether a validity mask was present before.

* @param vector The vector to alter
*/
DUCKDB_API void duckdb_vector_ensure_validity_writable(duckdb_vector vector);

/*!
Assigns a string element in the vector at the specified location.

* @param vector The vector to alter
* @param index The row position in the vector to assign the string to
* @param str The null-terminated string
*/
DUCKDB_API void duckdb_vector_assign_string_element(duckdb_vector vector, idx_t index, const char *str);

/*!
Assigns a string element in the vector at the specified location. You may also use this function to assign BLOBs.

* @param vector The vector to alter
* @param index The row position in the vector to assign the string to
* @param str The string
* @param str_len The length of the string (in bytes)
*/
DUCKDB_API void duckdb_vector_assign_string_element_len(duckdb_vector vector, idx_t index, const char *str,
                                                        idx_t str_len);

/*!
Retrieves the child vector of a list vector.

The resulting vector is valid as long as the parent vector is valid.

* @param vector The vector
* @return The child vector
*/
DUCKDB_API duckdb_vector duckdb_list_vector_get_child(duckdb_vector vector);

/*!
Returns the size of the child vector of the list.

* @param vector The vector
* @return The size of the child list
*/
DUCKDB_API idx_t duckdb_list_vector_get_size(duckdb_vector vector);

/*!
Sets the total size of the underlying child-vector of a list vector.

* @param vector The list vector.
* @param size The size of the child list.
* @return The duckdb state. Returns DuckDBError if the vector is nullptr.
*/
DUCKDB_API duckdb_state duckdb_list_vector_set_size(duckdb_vector vector, idx_t size);

/*!
Sets the total capacity of the underlying child-vector of a list.

After calling this method, you must call `duckdb_vector_get_validity` and `duckdb_vector_get_data` to obtain current
data and validity pointers

* @param vector The list vector.
* @param required_capacity the total capacity to reserve.
* @return The duckdb state. Returns DuckDBError if the vector is nullptr.
*/
DUCKDB_API duckdb_state duckdb_list_vector_reserve(duckdb_vector vector, idx_t required_capacity);

/*!
Retrieves the child vector of a struct vector.

The resulting vector is valid as long as the parent vector is valid.

* @param vector The vector
* @param index The child index
* @return The child vector
*/
DUCKDB_API duckdb_vector duckdb_struct_vector_get_child(duckdb_vector vector, idx_t index);

/*!
Retrieves the child vector of a array vector.

The resulting vector is valid as long as the parent vector is valid.
The resulting vector has the size of the parent vector multiplied by the array size.

* @param vector The vector
* @return The child vector
*/
DUCKDB_API duckdb_vector duckdb_array_vector_get_child(duckdb_vector vector);

//===--------------------------------------------------------------------===//
// Validity Mask Functions
//===--------------------------------------------------------------------===//

/*!
Returns whether or not a row is valid (i.e. not NULL) in the given validity mask.

* @param validity The validity mask, as obtained through `duckdb_vector_get_validity`
* @param row The row index
* @return true if the row is valid, false otherwise
*/
DUCKDB_API bool duckdb_validity_row_is_valid(uint64_t *validity, idx_t row);

/*!
In a validity mask, sets a specific row to either valid or invalid.

Note that `duckdb_vector_ensure_validity_writable` should be called before calling `duckdb_vector_get_validity`,
to ensure that there is a validity mask to write to.

* @param validity The validity mask, as obtained through `duckdb_vector_get_validity`.
* @param row The row index
* @param valid Whether or not to set the row to valid, or invalid
*/
DUCKDB_API void duckdb_validity_set_row_validity(uint64_t *validity, idx_t row, bool valid);

/*!
In a validity mask, sets a specific row to invalid.

Equivalent to `duckdb_validity_set_row_validity` with valid set to false.

* @param validity The validity mask
* @param row The row index
*/
DUCKDB_API void duckdb_validity_set_row_invalid(uint64_t *validity, idx_t row);

/*!
In a validity mask, sets a specific row to valid.

Equivalent to `duckdb_validity_set_row_validity` with valid set to true.

* @param validity The validity mask
* @param row The row index
*/
DUCKDB_API void duckdb_validity_set_row_valid(uint64_t *validity, idx_t row);

//===--------------------------------------------------------------------===//
// Scalar Functions
//===--------------------------------------------------------------------===//

/*!
Creates a new empty scalar function.

The return value should be destroyed with `duckdb_destroy_scalar_function`.

* @return The scalar function object.
*/
DUCKDB_API duckdb_scalar_function duckdb_create_scalar_function();

/*!
Destroys the given scalar function object.

* @param scalar_function The scalar function to destroy
*/
DUCKDB_API void duckdb_destroy_scalar_function(duckdb_scalar_function *scalar_function);

/*!
Sets the name of the given scalar function.

* @param scalar_function The scalar function
* @param name The name of the scalar function
*/
DUCKDB_API void duckdb_scalar_function_set_name(duckdb_scalar_function scalar_function, const char *name);

/*!
Sets the parameters of the given scalar function to varargs. Does not require adding parameters with
duckdb_scalar_function_add_parameter.

* @param scalar_function The scalar function.
* @param type The type of the arguments.
* @return The parameter type. Cannot contain INVALID.
*/
DUCKDB_API void duckdb_scalar_function_set_varargs(duckdb_scalar_function scalar_function, duckdb_logical_type type);

/*!
Sets the parameters of the given scalar function to varargs. Does not require adding parameters with
duckdb_scalar_function_add_parameter.

* @param scalar_function The scalar function.
*/
DUCKDB_API void duckdb_scalar_function_set_special_handling(duckdb_scalar_function scalar_function);

/*!
Sets the Function Stability of the scalar function to VOLATILE, indicating the function should be re-run for every row.
This limits optimization that can be performed for the function.

* @param scalar_function The scalar function.
*/
DUCKDB_API void duckdb_scalar_function_set_volatile(duckdb_scalar_function scalar_function);

/*!
Adds a parameter to the scalar function.

* @param scalar_function The scalar function.
* @param type The parameter type. Cannot contain INVALID.
*/
DUCKDB_API void duckdb_scalar_function_add_parameter(duckdb_scalar_function scalar_function, duckdb_logical_type type);

/*!
Sets the return type of the scalar function.

* @param scalar_function The scalar function
* @param type Cannot contain INVALID or ANY.
*/
DUCKDB_API void duckdb_scalar_function_set_return_type(duckdb_scalar_function scalar_function,
                                                       duckdb_logical_type type);

/*!
Assigns extra information to the scalar function that can be fetched during binding, etc.

* @param scalar_function The scalar function
* @param extra_info The extra information
* @param destroy The callback that will be called to destroy the bind data (if any)
*/
DUCKDB_API void duckdb_scalar_function_set_extra_info(duckdb_scalar_function scalar_function, void *extra_info,
                                                      duckdb_delete_callback_t destroy);

/*!
Sets the main function of the scalar function.

* @param scalar_function The scalar function
* @param function The function
*/
DUCKDB_API void duckdb_scalar_function_set_function(duckdb_scalar_function scalar_function,
                                                    duckdb_scalar_function_t function);

/*!
Register the scalar function object within the given connection.

The function requires at least a name, a function and a return type.

If the function is incomplete or a function with this name already exists DuckDBError is returned.

* @param con The connection to register it in.
* @param scalar_function The function pointer
* @return Whether or not the registration was successful.
*/
DUCKDB_API duckdb_state duckdb_register_scalar_function(duckdb_connection con, duckdb_scalar_function scalar_function);

/*!
Retrieves the extra info of the function as set in `duckdb_scalar_function_set_extra_info`.

* @param info The info object.
* @return The extra info.
*/
DUCKDB_API void *duckdb_scalar_function_get_extra_info(duckdb_function_info info);

/*!
Report that an error has occurred while executing the scalar function.

* @param info The info object.
* @param error The error message
*/
DUCKDB_API void duckdb_scalar_function_set_error(duckdb_function_info info, const char *error);

/*!
Creates a new empty scalar function set.

The return value should be destroyed with `duckdb_destroy_scalar_function_set`.

* @return The scalar function set object.
*/
DUCKDB_API duckdb_scalar_function_set duckdb_create_scalar_function_set(const char *name);

/*!
Destroys the given scalar function set object.

*/
DUCKDB_API void duckdb_destroy_scalar_function_set(duckdb_scalar_function_set *scalar_function_set);

/*!
Adds the scalar function as a new overload to the scalar function set.

Returns DuckDBError if the function could not be added, for example if the overload already exists.

* @param set The scalar function set
* @param function The function to add
*/
DUCKDB_API duckdb_state duckdb_add_scalar_function_to_set(duckdb_scalar_function_set set,
                                                          duckdb_scalar_function function);

/*!
Register the scalar function set within the given connection.

The set requires at least a single valid overload.

If the set is incomplete or a function with this name already exists DuckDBError is returned.

* @param con The connection to register it in.
* @param set The function set to register
* @return Whether or not the registration was successful.
*/
DUCKDB_API duckdb_state duckdb_register_scalar_function_set(duckdb_connection con, duckdb_scalar_function_set set);

//===--------------------------------------------------------------------===//
// Aggregate Functions
//===--------------------------------------------------------------------===//

/*!
Creates a new empty aggregate function.

The return value should be destroyed with `duckdb_destroy_aggregate_function`.

* @return The aggregate function object.
*/
DUCKDB_API duckdb_aggregate_function duckdb_create_aggregate_function();

/*!
Destroys the given aggregate function object.

*/
DUCKDB_API void duckdb_destroy_aggregate_function(duckdb_aggregate_function *aggregate_function);

/*!
Sets the name of the given aggregate function.

* @param aggregate_function The aggregate function
* @param name The name of the aggregate function
*/
DUCKDB_API void duckdb_aggregate_function_set_name(duckdb_aggregate_function aggregate_function, const char *name);

/*!
Adds a parameter to the aggregate function.

* @param aggregate_function The aggregate function.
* @param type The parameter type. Cannot contain INVALID.
*/
DUCKDB_API void duckdb_aggregate_function_add_parameter(duckdb_aggregate_function aggregate_function,
                                                        duckdb_logical_type type);

/*!
Sets the return type of the aggregate function.

* @param aggregate_function The aggregate function.
* @param type The return type. Cannot contain INVALID or ANY.
*/
DUCKDB_API void duckdb_aggregate_function_set_return_type(duckdb_aggregate_function aggregate_function,
                                                          duckdb_logical_type type);

/*!
Sets the main functions of the aggregate function.

* @param aggregate_function The aggregate function
* @param state_size state size
* @param state_init state init function
* @param update update states
* @param combine combine states
* @param finalize finalize states
*/
DUCKDB_API void duckdb_aggregate_function_set_functions(duckdb_aggregate_function aggregate_function,
                                                        duckdb_aggregate_state_size state_size,
                                                        duckdb_aggregate_init_t state_init,
                                                        duckdb_aggregate_update_t update,
                                                        duckdb_aggregate_combine_t combine,
                                                        duckdb_aggregate_finalize_t finalize);

/*!
Sets the state destructor callback of the aggregate function (optional)

* @param aggregate_function The aggregate function
* @param destroy state destroy callback
*/
DUCKDB_API void duckdb_aggregate_function_set_destructor(duckdb_aggregate_function aggregate_function,
                                                         duckdb_aggregate_destroy_t destroy);

/*!
Register the aggregate function object within the given connection.

The function requires at least a name, functions and a return type.

If the function is incomplete or a function with this name already exists DuckDBError is returned.

* @param con The connection to register it in.
* @return Whether or not the registration was successful.
*/
DUCKDB_API duckdb_state duckdb_register_aggregate_function(duckdb_connection con,
                                                           duckdb_aggregate_function aggregate_function);

/*!
Sets the NULL handling of the aggregate function to SPECIAL_HANDLING.

* @param aggregate_function The aggregate function
*/
DUCKDB_API void duckdb_aggregate_function_set_special_handling(duckdb_aggregate_function aggregate_function);

/*!
Assigns extra information to the scalar function that can be fetched during binding, etc.

* @param aggregate_function The aggregate function
* @param extra_info The extra information
* @param destroy The callback that will be called to destroy the bind data (if any)
*/
DUCKDB_API void duckdb_aggregate_function_set_extra_info(duckdb_aggregate_function aggregate_function, void *extra_info,
                                                         duckdb_delete_callback_t destroy);

/*!
Retrieves the extra info of the function as set in `duckdb_aggregate_function_set_extra_info`.

* @param info The info object
* @return The extra info
*/
DUCKDB_API void *duckdb_aggregate_function_get_extra_info(duckdb_function_info info);

/*!
Report that an error has occurred while executing the aggregate function.

* @param info The info object
* @param error The error message
*/
DUCKDB_API void duckdb_aggregate_function_set_error(duckdb_function_info info, const char *error);

/*!
Creates a new empty aggregate function set.

The return value should be destroyed with `duckdb_destroy_aggregate_function_set`.

* @return The aggregate function set object.
*/
DUCKDB_API duckdb_aggregate_function_set duckdb_create_aggregate_function_set(const char *name);

/*!
Destroys the given aggregate function set object.

*/
DUCKDB_API void duckdb_destroy_aggregate_function_set(duckdb_aggregate_function_set *aggregate_function_set);

/*!
Adds the aggregate function as a new overload to the aggregate function set.

Returns DuckDBError if the function could not be added, for example if the overload already exists.

* @param set The aggregate function set
* @param function The function to add
*/
DUCKDB_API duckdb_state duckdb_add_aggregate_function_to_set(duckdb_aggregate_function_set set,
                                                             duckdb_aggregate_function function);

/*!
Register the aggregate function set within the given connection.

The set requires at least a single valid overload.

If the set is incomplete or a function with this name already exists DuckDBError is returned.

* @param con The connection to register it in.
* @param set The function set to register
* @return Whether or not the registration was successful.
*/
DUCKDB_API duckdb_state duckdb_register_aggregate_function_set(duckdb_connection con,
                                                               duckdb_aggregate_function_set set);

//===--------------------------------------------------------------------===//
// Table Functions
//===--------------------------------------------------------------------===//

/*!
Creates a new empty table function.

The return value should be destroyed with `duckdb_destroy_table_function`.

* @return The table function object.
*/
DUCKDB_API duckdb_table_function duckdb_create_table_function();

/*!
Destroys the given table function object.

* @param table_function The table function to destroy
*/
DUCKDB_API void duckdb_destroy_table_function(duckdb_table_function *table_function);

/*!
Sets the name of the given table function.

* @param table_function The table function
* @param name The name of the table function
*/
DUCKDB_API void duckdb_table_function_set_name(duckdb_table_function table_function, const char *name);

/*!
Adds a parameter to the table function.

* @param table_function The table function.
* @param type The parameter type. Cannot contain INVALID.
*/
DUCKDB_API void duckdb_table_function_add_parameter(duckdb_table_function table_function, duckdb_logical_type type);

/*!
Adds a named parameter to the table function.

* @param table_function The table function.
* @param name The parameter name.
* @param type The parameter type. Cannot contain INVALID.
*/
DUCKDB_API void duckdb_table_function_add_named_parameter(duckdb_table_function table_function, const char *name,
                                                          duckdb_logical_type type);

/*!
Assigns extra information to the table function that can be fetched during binding, etc.

* @param table_function The table function
* @param extra_info The extra information
* @param destroy The callback that will be called to destroy the bind data (if any)
*/
DUCKDB_API void duckdb_table_function_set_extra_info(duckdb_table_function table_function, void *extra_info,
                                                     duckdb_delete_callback_t destroy);

/*!
Sets the bind function of the table function.

* @param table_function The table function
* @param bind The bind function
*/
DUCKDB_API void duckdb_table_function_set_bind(duckdb_table_function table_function, duckdb_table_function_bind_t bind);

/*!
Sets the init function of the table function.

* @param table_function The table function
* @param init The init function
*/
DUCKDB_API void duckdb_table_function_set_init(duckdb_table_function table_function, duckdb_table_function_init_t init);

/*!
Sets the thread-local init function of the table function.

* @param table_function The table function
* @param init The init function
*/
DUCKDB_API void duckdb_table_function_set_local_init(duckdb_table_function table_function,
                                                     duckdb_table_function_init_t init);

/*!
Sets the main function of the table function.

* @param table_function The table function
* @param function The function
*/
DUCKDB_API void duckdb_table_function_set_function(duckdb_table_function table_function,
                                                   duckdb_table_function_t function);

/*!
Sets whether or not the given table function supports projection pushdown.

If this is set to true, the system will provide a list of all required columns in the `init` stage through
the `duckdb_init_get_column_count` and `duckdb_init_get_column_index` functions.
If this is set to false (the default), the system will expect all columns to be projected.

* @param table_function The table function
* @param pushdown True if the table function supports projection pushdown, false otherwise.
*/
DUCKDB_API void duckdb_table_function_supports_projection_pushdown(duckdb_table_function table_function, bool pushdown);

/*!
Register the table function object within the given connection.

The function requires at least a name, a bind function, an init function and a main function.

If the function is incomplete or a function with this name already exists DuckDBError is returned.

* @param con The connection to register it in.
* @param function The function pointer
* @return Whether or not the registration was successful.
*/
DUCKDB_API duckdb_state duckdb_register_table_function(duckdb_connection con, duckdb_table_function function);

//===--------------------------------------------------------------------===//
// Table Function Bind
//===--------------------------------------------------------------------===//

/*!
Retrieves the extra info of the function as set in `duckdb_table_function_set_extra_info`.

* @param info The info object
* @return The extra info
*/
DUCKDB_API void *duckdb_bind_get_extra_info(duckdb_bind_info info);

/*!
Adds a result column to the output of the table function.

* @param info The table function's bind info.
* @param name The column name.
* @param type The logical column type.
*/
DUCKDB_API void duckdb_bind_add_result_column(duckdb_bind_info info, const char *name, duckdb_logical_type type);

/*!
Retrieves the number of regular (non-named) parameters to the function.

* @param info The info object
* @return The number of parameters
*/
DUCKDB_API idx_t duckdb_bind_get_parameter_count(duckdb_bind_info info);

/*!
Retrieves the parameter at the given index.

The result must be destroyed with `duckdb_destroy_value`.

* @param info The info object
* @param index The index of the parameter to get
* @return The value of the parameter. Must be destroyed with `duckdb_destroy_value`.
*/
DUCKDB_API duckdb_value duckdb_bind_get_parameter(duckdb_bind_info info, idx_t index);

/*!
Retrieves a named parameter with the given name.

The result must be destroyed with `duckdb_destroy_value`.

* @param info The info object
* @param name The name of the parameter
* @return The value of the parameter. Must be destroyed with `duckdb_destroy_value`.
*/
DUCKDB_API duckdb_value duckdb_bind_get_named_parameter(duckdb_bind_info info, const char *name);

/*!
Sets the user-provided bind data in the bind object. This object can be retrieved again during execution.

* @param info The info object
* @param bind_data The bind data object.
* @param destroy The callback that will be called to destroy the bind data (if any)
*/
DUCKDB_API void duckdb_bind_set_bind_data(duckdb_bind_info info, void *bind_data, duckdb_delete_callback_t destroy);

/*!
Sets the cardinality estimate for the table function, used for optimization.

* @param info The bind data object.
* @param is_exact Whether or not the cardinality estimate is exact, or an approximation
*/
DUCKDB_API void duckdb_bind_set_cardinality(duckdb_bind_info info, idx_t cardinality, bool is_exact);

/*!
Report that an error has occurred while calling bind.

* @param info The info object
* @param error The error message
*/
DUCKDB_API void duckdb_bind_set_error(duckdb_bind_info info, const char *error);

//===--------------------------------------------------------------------===//
// Table Function Init
//===--------------------------------------------------------------------===//

/*!
Retrieves the extra info of the function as set in `duckdb_table_function_set_extra_info`.

* @param info The info object
* @return The extra info
*/
DUCKDB_API void *duckdb_init_get_extra_info(duckdb_init_info info);

/*!
Gets the bind data set by `duckdb_bind_set_bind_data` during the bind.

Note that the bind data should be considered as read-only.
For tracking state, use the init data instead.

* @param info The info object
* @return The bind data object
*/
DUCKDB_API void *duckdb_init_get_bind_data(duckdb_init_info info);

/*!
Sets the user-provided init data in the init object. This object can be retrieved again during execution.

* @param info The info object
* @param init_data The init data object.
* @param destroy The callback that will be called to destroy the init data (if any)
*/
DUCKDB_API void duckdb_init_set_init_data(duckdb_init_info info, void *init_data, duckdb_delete_callback_t destroy);

/*!
Returns the number of projected columns.

This function must be used if projection pushdown is enabled to figure out which columns to emit.

* @param info The info object
* @return The number of projected columns.
*/
DUCKDB_API idx_t duckdb_init_get_column_count(duckdb_init_info info);

/*!
Returns the column index of the projected column at the specified position.

This function must be used if projection pushdown is enabled to figure out which columns to emit.

* @param info The info object
* @param column_index The index at which to get the projected column index, from 0..duckdb_init_get_column_count(info)
* @return The column index of the projected column.
*/
DUCKDB_API idx_t duckdb_init_get_column_index(duckdb_init_info info, idx_t column_index);

/*!
Sets how many threads can process this table function in parallel (default: 1)

* @param info The info object
* @param max_threads The maximum amount of threads that can process this table function
*/
DUCKDB_API void duckdb_init_set_max_threads(duckdb_init_info info, idx_t max_threads);

/*!
Report that an error has occurred while calling init.

* @param info The info object
* @param error The error message
*/
DUCKDB_API void duckdb_init_set_error(duckdb_init_info info, const char *error);

//===--------------------------------------------------------------------===//
// Table Function
//===--------------------------------------------------------------------===//

/*!
Retrieves the extra info of the function as set in `duckdb_table_function_set_extra_info`.

* @param info The info object
* @return The extra info
*/
DUCKDB_API void *duckdb_function_get_extra_info(duckdb_function_info info);

/*!
Gets the bind data set by `duckdb_bind_set_bind_data` during the bind.

Note that the bind data should be considered as read-only.
For tracking state, use the init data instead.

* @param info The info object
* @return The bind data object
*/
DUCKDB_API void *duckdb_function_get_bind_data(duckdb_function_info info);

/*!
Gets the init data set by `duckdb_init_set_init_data` during the init.

* @param info The info object
* @return The init data object
*/
DUCKDB_API void *duckdb_function_get_init_data(duckdb_function_info info);

/*!
Gets the thread-local init data set by `duckdb_init_set_init_data` during the local_init.

* @param info The info object
* @return The init data object
*/
DUCKDB_API void *duckdb_function_get_local_init_data(duckdb_function_info info);

/*!
Report that an error has occurred while executing the function.

* @param info The info object
* @param error The error message
*/
DUCKDB_API void duckdb_function_set_error(duckdb_function_info info, const char *error);

//===--------------------------------------------------------------------===//
// Replacement Scans
//===--------------------------------------------------------------------===//

/*!
Add a replacement scan definition to the specified database.

* @param db The database object to add the replacement scan to
* @param replacement The replacement scan callback
* @param extra_data Extra data that is passed back into the specified callback
* @param delete_callback The delete callback to call on the extra data, if any
*/
DUCKDB_API void duckdb_add_replacement_scan(duckdb_database db, duckdb_replacement_callback_t replacement,
                                            void *extra_data, duckdb_delete_callback_t delete_callback);

/*!
Sets the replacement function name. If this function is called in the replacement callback,
the replacement scan is performed. If it is not called, the replacement callback is not performed.

* @param info The info object
* @param function_name The function name to substitute.
*/
DUCKDB_API void duckdb_replacement_scan_set_function_name(duckdb_replacement_scan_info info, const char *function_name);

/*!
Adds a parameter to the replacement scan function.

* @param info The info object
* @param parameter The parameter to add.
*/
DUCKDB_API void duckdb_replacement_scan_add_parameter(duckdb_replacement_scan_info info, duckdb_value parameter);

/*!
Report that an error has occurred while executing the replacement scan.

* @param info The info object
* @param error The error message
*/
DUCKDB_API void duckdb_replacement_scan_set_error(duckdb_replacement_scan_info info, const char *error);

//===--------------------------------------------------------------------===//
// Profiling Info
//===--------------------------------------------------------------------===//

/*!
Returns the root node of the profiling information. Returns nullptr, if profiling is not enabled.

* @param connection A connection object.
* @return A profiling information object.
*/
DUCKDB_API duckdb_profiling_info duckdb_get_profiling_info(duckdb_connection connection);

/*!
Returns the value of the metric of the current profiling info node. Returns nullptr, if the metric does
 not exist or is not enabled. Currently, the value holds a string, and you can retrieve the string
 by calling the corresponding function: char *duckdb_get_varchar(duckdb_value value).

* @param info A profiling information object.
* @param key The name of the requested metric.
* @return The value of the metric. Must be freed with `duckdb_destroy_value`
*/
DUCKDB_API duckdb_value duckdb_profiling_info_get_value(duckdb_profiling_info info, const char *key);

/*!
Returns the key-value metric map of this profiling node as a MAP duckdb_value.
The individual elements are accessible via the duckdb_value MAP functions.

* @param info A profiling information object.
* @return The key-value metric map as a MAP duckdb_value.
*/
DUCKDB_API duckdb_value duckdb_profiling_info_get_metrics(duckdb_profiling_info info);

/*!
Returns the number of children in the current profiling info node.

* @param info A profiling information object.
* @return The number of children in the current node.
*/
DUCKDB_API idx_t duckdb_profiling_info_get_child_count(duckdb_profiling_info info);

/*!
Returns the child node at the specified index.

* @param info A profiling information object.
* @param index The index of the child node.
* @return The child node at the specified index.
*/
DUCKDB_API duckdb_profiling_info duckdb_profiling_info_get_child(duckdb_profiling_info info, idx_t index);

//===--------------------------------------------------------------------===//
// Appender
//===--------------------------------------------------------------------===//

// Appenders are the most efficient way of loading data into DuckDB from within the C interface, and are recommended for
// fast data loading. The appender is much faster than using prepared statements or individual `INSERT INTO` statements.

// Appends are made in row-wise format. For every column, a `duckdb_append_[type]` call should be made, after which
// the row should be finished by calling `duckdb_appender_end_row`. After all rows have been appended,
// `duckdb_appender_destroy` should be used to finalize the appender and clean up the resulting memory.

// Instead of appending rows with `duckdb_appender_end_row`, it is also possible to fill and append
// chunks-at-a-time.

// Note that `duckdb_appender_destroy` should always be called on the resulting appender, even if the function returns
// `DuckDBError`.
/*!
Creates an appender object.

Note that the object must be destroyed with `duckdb_appender_destroy`.

* @param connection The connection context to create the appender in.
* @param schema The schema of the table to append to, or `nullptr` for the default schema.
* @param table The table name to append to.
* @param out_appender The resulting appender object.
* @return `DuckDBSuccess` on success or `DuckDBError` on failure.
*/
DUCKDB_API duckdb_state duckdb_appender_create(duckdb_connection connection, const char *schema, const char *table,
                                               duckdb_appender *out_appender);

/*!
Returns the number of columns in the table that belongs to the appender.

* @param appender The appender to get the column count from.
* @return The number of columns in the table.
*/
DUCKDB_API idx_t duckdb_appender_column_count(duckdb_appender appender);

/*!
Returns the type of the column at the specified index.

Note: The resulting type should be destroyed with `duckdb_destroy_logical_type`.

* @param appender The appender to get the column type from.
* @param col_idx The index of the column to get the type of.
* @return The duckdb_logical_type of the column.
*/
DUCKDB_API duckdb_logical_type duckdb_appender_column_type(duckdb_appender appender, idx_t col_idx);

/*!
Returns the error message associated with the given appender.
If the appender has no error message, this returns `nullptr` instead.

The error message should not be freed. It will be de-allocated when `duckdb_appender_destroy` is called.

* @param appender The appender to get the error from.
* @return The error message, or `nullptr` if there is none.
*/
DUCKDB_API const char *duckdb_appender_error(duckdb_appender appender);

/*!
Flush the appender to the table, forcing the cache of the appender to be cleared. If flushing the data triggers a
constraint violation or any other error, then all data is invalidated, and this function returns DuckDBError.
It is not possible to append more values. Call duckdb_appender_error to obtain the error message followed by
duckdb_appender_destroy to destroy the invalidated appender.

* @param appender The appender to flush.
* @return `DuckDBSuccess` on success or `DuckDBError` on failure.
*/
DUCKDB_API duckdb_state duckdb_appender_flush(duckdb_appender appender);

/*!
Closes the appender by flushing all intermediate states and closing it for further appends. If flushing the data
triggers a constraint violation or any other error, then all data is invalidated, and this function returns DuckDBError.
Call duckdb_appender_error to obtain the error message followed by duckdb_appender_destroy to destroy the invalidated
appender.

* @param appender The appender to flush and close.
* @return `DuckDBSuccess` on success or `DuckDBError` on failure.
*/
DUCKDB_API duckdb_state duckdb_appender_close(duckdb_appender appender);

/*!
Closes the appender by flushing all intermediate states to the table and destroying it. By destroying it, this function
de-allocates all memory associated with the appender. If flushing the data triggers a constraint violation,
then all data is invalidated, and this function returns DuckDBError. Due to the destruction of the appender, it is no
longer possible to obtain the specific error message with duckdb_appender_error. Therefore, call duckdb_appender_close
before destroying the appender, if you need insights into the specific error.

* @param appender The appender to flush, close and destroy.
* @return `DuckDBSuccess` on success or `DuckDBError` on failure.
*/
DUCKDB_API duckdb_state duckdb_appender_destroy(duckdb_appender *appender);

/*!
A nop function, provided for backwards compatibility reasons. Does nothing. Only `duckdb_appender_end_row` is required.
*/
DUCKDB_API duckdb_state duckdb_appender_begin_row(duckdb_appender appender);

/*!
Finish the current row of appends. After end_row is called, the next row can be appended.

* @param appender The appender.
* @return `DuckDBSuccess` on success or `DuckDBError` on failure.
*/
DUCKDB_API duckdb_state duckdb_appender_end_row(duckdb_appender appender);

/*!
Append a DEFAULT value (NULL if DEFAULT not available for column) to the appender.
*/
DUCKDB_API duckdb_state duckdb_append_default(duckdb_appender appender);

/*!
Append a bool value to the appender.
*/
DUCKDB_API duckdb_state duckdb_append_bool(duckdb_appender appender, bool value);

/*!
Append an int8_t value to the appender.
*/
DUCKDB_API duckdb_state duckdb_append_int8(duckdb_appender appender, int8_t value);

/*!
Append an int16_t value to the appender.
*/
DUCKDB_API duckdb_state duckdb_append_int16(duckdb_appender appender, int16_t value);

/*!
Append an int32_t value to the appender.
*/
DUCKDB_API duckdb_state duckdb_append_int32(duckdb_appender appender, int32_t value);

/*!
Append an int64_t value to the appender.
*/
DUCKDB_API duckdb_state duckdb_append_int64(duckdb_appender appender, int64_t value);

/*!
Append a duckdb_hugeint value to the appender.
*/
DUCKDB_API duckdb_state duckdb_append_hugeint(duckdb_appender appender, duckdb_hugeint value);

/*!
Append a uint8_t value to the appender.
*/
DUCKDB_API duckdb_state duckdb_append_uint8(duckdb_appender appender, uint8_t value);

/*!
Append a uint16_t value to the appender.
*/
DUCKDB_API duckdb_state duckdb_append_uint16(duckdb_appender appender, uint16_t value);

/*!
Append a uint32_t value to the appender.
*/
DUCKDB_API duckdb_state duckdb_append_uint32(duckdb_appender appender, uint32_t value);

/*!
Append a uint64_t value to the appender.
*/
DUCKDB_API duckdb_state duckdb_append_uint64(duckdb_appender appender, uint64_t value);

/*!
Append a duckdb_uhugeint value to the appender.
*/
DUCKDB_API duckdb_state duckdb_append_uhugeint(duckdb_appender appender, duckdb_uhugeint value);

/*!
Append a float value to the appender.
*/
DUCKDB_API duckdb_state duckdb_append_float(duckdb_appender appender, float value);

/*!
Append a double value to the appender.
*/
DUCKDB_API duckdb_state duckdb_append_double(duckdb_appender appender, double value);

/*!
Append a duckdb_date value to the appender.
*/
DUCKDB_API duckdb_state duckdb_append_date(duckdb_appender appender, duckdb_date value);

/*!
Append a duckdb_time value to the appender.
*/
DUCKDB_API duckdb_state duckdb_append_time(duckdb_appender appender, duckdb_time value);

/*!
Append a duckdb_timestamp value to the appender.
*/
DUCKDB_API duckdb_state duckdb_append_timestamp(duckdb_appender appender, duckdb_timestamp value);

/*!
Append a duckdb_interval value to the appender.
*/
DUCKDB_API duckdb_state duckdb_append_interval(duckdb_appender appender, duckdb_interval value);

/*!
Append a varchar value to the appender.
*/
DUCKDB_API duckdb_state duckdb_append_varchar(duckdb_appender appender, const char *val);

/*!
Append a varchar value to the appender.
*/
DUCKDB_API duckdb_state duckdb_append_varchar_length(duckdb_appender appender, const char *val, idx_t length);

/*!
Append a blob value to the appender.
*/
DUCKDB_API duckdb_state duckdb_append_blob(duckdb_appender appender, const void *data, idx_t length);

/*!
Append a NULL value to the appender (of any type).
*/
DUCKDB_API duckdb_state duckdb_append_null(duckdb_appender appender);

/*!
Appends a pre-filled data chunk to the specified appender.

The types of the data chunk must exactly match the types of the table, no casting is performed.
If the types do not match or the appender is in an invalid state, DuckDBError is returned.
If the append is successful, DuckDBSuccess is returned.

* @param appender The appender to append to.
* @param chunk The data chunk to append.
* @return The return state.
*/
DUCKDB_API duckdb_state duckdb_append_data_chunk(duckdb_appender appender, duckdb_data_chunk chunk);

//===--------------------------------------------------------------------===//
// Table Description
//===--------------------------------------------------------------------===//

/*!
Creates a table description object. Note that `duckdb_table_description_destroy` should always be called on the
resulting table_description, even if the function returns `DuckDBError`.

* @param connection The connection context.
* @param schema The schema of the table, or `nullptr` for the default schema.
* @param table The table name.
* @param out The resulting table description object.
* @return `DuckDBSuccess` on success or `DuckDBError` on failure.
*/
DUCKDB_API duckdb_state duckdb_table_description_create(duckdb_connection connection, const char *schema,
                                                        const char *table, duckdb_table_description *out);

/*!
Destroy the TableDescription object.

* @param table_description The table_description to destroy.
*/
DUCKDB_API void duckdb_table_description_destroy(duckdb_table_description *table_description);

/*!
Returns the error message associated with the given table_description.
If the table_description has no error message, this returns `nullptr` instead.
The error message should not be freed. It will be de-allocated when `duckdb_table_description_destroy` is called.

* @param table_description The table_description to get the error from.
* @return The error message, or `nullptr` if there is none.
*/
DUCKDB_API const char *duckdb_table_description_error(duckdb_table_description table_description);

/*!
Check if the column at 'index' index of the table has a DEFAULT expression.

* @param table_description The table_description to query.
* @param index The index of the column to query.
* @param out The out-parameter used to store the result.
* @return `DuckDBSuccess` on success or `DuckDBError` on failure.
*/
DUCKDB_API duckdb_state duckdb_column_has_default(duckdb_table_description table_description, idx_t index, bool *out);

//===--------------------------------------------------------------------===//
// Arrow Interface
//===--------------------------------------------------------------------===//

#ifndef DUCKDB_API_NO_DEPRECATED
/*!
**DEPRECATION NOTICE**: This method is scheduled for removal in a future release.

Executes a SQL query within a connection and stores the full (materialized) result in an arrow structure.
If the query fails to execute, DuckDBError is returned and the error message can be retrieved by calling
`duckdb_query_arrow_error`.

Note that after running `duckdb_query_arrow`, `duckdb_destroy_arrow` must be called on the result object even if the
query fails, otherwise the error stored within the result will not be freed correctly.

* @param connection The connection to perform the query in.
* @param query The SQL query to run.
* @param out_result The query result.
* @return `DuckDBSuccess` on success or `DuckDBError` on failure.
*/
DUCKDB_API duckdb_state duckdb_query_arrow(duckdb_connection connection, const char *query, duckdb_arrow *out_result);

/*!
**DEPRECATION NOTICE**: This method is scheduled for removal in a future release.

Fetch the internal arrow schema from the arrow result. Remember to call release on the respective
ArrowSchema object.

* @param result The result to fetch the schema from.
* @param out_schema The output schema.
* @return `DuckDBSuccess` on success or `DuckDBError` on failure.
*/
DUCKDB_API duckdb_state duckdb_query_arrow_schema(duckdb_arrow result, duckdb_arrow_schema *out_schema);

/*!
**DEPRECATION NOTICE**: This method is scheduled for removal in a future release.

Fetch the internal arrow schema from the prepared statement. Remember to call release on the respective
ArrowSchema object.

* @param prepared The prepared statement to fetch the schema from.
* @param out_schema The output schema.
* @return `DuckDBSuccess` on success or `DuckDBError` on failure.
*/
DUCKDB_API duckdb_state duckdb_prepared_arrow_schema(duckdb_prepared_statement prepared,
                                                     duckdb_arrow_schema *out_schema);

/*!
**DEPRECATION NOTICE**: This method is scheduled for removal in a future release.

Convert a data chunk into an arrow struct array. Remember to call release on the respective
ArrowArray object.

* @param result The result object the data chunk have been fetched from.
* @param chunk The data chunk to convert.
* @param out_array The output array.
*/
DUCKDB_API void duckdb_result_arrow_array(duckdb_result result, duckdb_data_chunk chunk, duckdb_arrow_array *out_array);

/*!
**DEPRECATION NOTICE**: This method is scheduled for removal in a future release.

Fetch an internal arrow struct array from the arrow result. Remember to call release on the respective
ArrowArray object.

This function can be called multiple time to get next chunks, which will free the previous out_array.
So consume the out_array before calling this function again.

* @param result The result to fetch the array from.
* @param out_array The output array.
* @return `DuckDBSuccess` on success or `DuckDBError` on failure.
*/
DUCKDB_API duckdb_state duckdb_query_arrow_array(duckdb_arrow result, duckdb_arrow_array *out_array);

/*!
**DEPRECATION NOTICE**: This method is scheduled for removal in a future release.

Returns the number of columns present in the arrow result object.

* @param result The result object.
* @return The number of columns present in the result object.
*/
DUCKDB_API idx_t duckdb_arrow_column_count(duckdb_arrow result);

/*!
**DEPRECATION NOTICE**: This method is scheduled for removal in a future release.

Returns the number of rows present in the arrow result object.

* @param result The result object.
* @return The number of rows present in the result object.
*/
DUCKDB_API idx_t duckdb_arrow_row_count(duckdb_arrow result);

/*!
**DEPRECATION NOTICE**: This method is scheduled for removal in a future release.

Returns the number of rows changed by the query stored in the arrow result. This is relevant only for
INSERT/UPDATE/DELETE queries. For other queries the rows_changed will be 0.

* @param result The result object.
* @return The number of rows changed.
*/
DUCKDB_API idx_t duckdb_arrow_rows_changed(duckdb_arrow result);

/*!
**DEPRECATION NOTICE**: This method is scheduled for removal in a future release.

 Returns the error message contained within the result. The error is only set if `duckdb_query_arrow` returns
`DuckDBError`.

The error message should not be freed. It will be de-allocated when `duckdb_destroy_arrow` is called.

* @param result The result object to fetch the error from.
* @return The error of the result.
*/
DUCKDB_API const char *duckdb_query_arrow_error(duckdb_arrow result);

/*!
**DEPRECATION NOTICE**: This method is scheduled for removal in a future release.

Closes the result and de-allocates all memory allocated for the arrow result.

* @param result The result to destroy.
*/
DUCKDB_API void duckdb_destroy_arrow(duckdb_arrow *result);

/*!
**DEPRECATION NOTICE**: This method is scheduled for removal in a future release.

Releases the arrow array stream and de-allocates its memory.

* @param stream_p The arrow array stream to destroy.
*/
DUCKDB_API void duckdb_destroy_arrow_stream(duckdb_arrow_stream *stream_p);

/*!
**DEPRECATION NOTICE**: This method is scheduled for removal in a future release.

Executes the prepared statement with the given bound parameters, and returns an arrow query result.
Note that after running `duckdb_execute_prepared_arrow`, `duckdb_destroy_arrow` must be called on the result object.

* @param prepared_statement The prepared statement to execute.
* @param out_result The query result.
* @return `DuckDBSuccess` on success or `DuckDBError` on failure.
*/
DUCKDB_API duckdb_state duckdb_execute_prepared_arrow(duckdb_prepared_statement prepared_statement,
                                                      duckdb_arrow *out_result);

/*!
**DEPRECATION NOTICE**: This method is scheduled for removal in a future release.

Scans the Arrow stream and creates a view with the given name.

* @param connection The connection on which to execute the scan.
* @param table_name Name of the temporary view to create.
* @param arrow Arrow stream wrapper.
* @return `DuckDBSuccess` on success or `DuckDBError` on failure.
*/
DUCKDB_API duckdb_state duckdb_arrow_scan(duckdb_connection connection, const char *table_name,
                                          duckdb_arrow_stream arrow);

/*!
**DEPRECATION NOTICE**: This method is scheduled for removal in a future release.

Scans the Arrow array and creates a view with the given name.
Note that after running `duckdb_arrow_array_scan`, `duckdb_destroy_arrow_stream` must be called on the out stream.

* @param connection The connection on which to execute the scan.
* @param table_name Name of the temporary view to create.
* @param arrow_schema Arrow schema wrapper.
* @param arrow_array Arrow array wrapper.
* @param out_stream Output array stream that wraps around the passed schema, for releasing/deleting once done.
* @return `DuckDBSuccess` on success or `DuckDBError` on failure.
*/
DUCKDB_API duckdb_state duckdb_arrow_array_scan(duckdb_connection connection, const char *table_name,
                                                duckdb_arrow_schema arrow_schema, duckdb_arrow_array arrow_array,
                                                duckdb_arrow_stream *out_stream);

#endif
//===--------------------------------------------------------------------===//
// Threading Information
//===--------------------------------------------------------------------===//

/*!
Execute DuckDB tasks on this thread.

Will return after `max_tasks` have been executed, or if there are no more tasks present.

* @param database The database object to execute tasks for
* @param max_tasks The maximum amount of tasks to execute
*/
DUCKDB_API void duckdb_execute_tasks(duckdb_database database, idx_t max_tasks);

/*!
Creates a task state that can be used with duckdb_execute_tasks_state to execute tasks until
`duckdb_finish_execution` is called on the state.

`duckdb_destroy_state` must be called on the result.

* @param database The database object to create the task state for
* @return The task state that can be used with duckdb_execute_tasks_state.
*/
DUCKDB_API duckdb_task_state duckdb_create_task_state(duckdb_database database);

/*!
Execute DuckDB tasks on this thread.

The thread will keep on executing tasks forever, until duckdb_finish_execution is called on the state.
Multiple threads can share the same duckdb_task_state.

* @param state The task state of the executor
*/
DUCKDB_API void duckdb_execute_tasks_state(duckdb_task_state state);

/*!
Execute DuckDB tasks on this thread.

The thread will keep on executing tasks until either duckdb_finish_execution is called on the state,
max_tasks tasks have been executed or there are no more tasks to be executed.

Multiple threads can share the same duckdb_task_state.

* @param state The task state of the executor
* @param max_tasks The maximum amount of tasks to execute
* @return The amount of tasks that have actually been executed
*/
DUCKDB_API idx_t duckdb_execute_n_tasks_state(duckdb_task_state state, idx_t max_tasks);

/*!
Finish execution on a specific task.

* @param state The task state to finish execution
*/
DUCKDB_API void duckdb_finish_execution(duckdb_task_state state);

/*!
Check if the provided duckdb_task_state has finished execution

* @param state The task state to inspect
* @return Whether or not duckdb_finish_execution has been called on the task state
*/
DUCKDB_API bool duckdb_task_state_is_finished(duckdb_task_state state);

/*!
Destroys the task state returned from duckdb_create_task_state.

Note that this should not be called while there is an active duckdb_execute_tasks_state running
on the task state.

* @param state The task state to clean up
*/
DUCKDB_API void duckdb_destroy_task_state(duckdb_task_state state);

/*!
Returns true if the execution of the current query is finished.

* @param con The connection on which to check
*/
DUCKDB_API bool duckdb_execution_is_finished(duckdb_connection con);

//===--------------------------------------------------------------------===//
// Streaming Result Interface
//===--------------------------------------------------------------------===//

#ifndef DUCKDB_API_NO_DEPRECATED
/*!
**DEPRECATION NOTICE**: This method is scheduled for removal in a future release.

Fetches a data chunk from the (streaming) duckdb_result. This function should be called repeatedly until the result is
exhausted.

The result must be destroyed with `duckdb_destroy_data_chunk`.

This function can only be used on duckdb_results created with 'duckdb_pending_prepared_streaming'

If this function is used, none of the other result functions can be used and vice versa (i.e. this function cannot be
mixed with the legacy result functions or the materialized result functions).

It is not known beforehand how many chunks will be returned by this result.

* @param result The result object to fetch the data chunk from.
* @return The resulting data chunk. Returns `NULL` if the result has an error.
*/
DUCKDB_API duckdb_data_chunk duckdb_stream_fetch_chunk(duckdb_result result);

#endif
/*!
Fetches a data chunk from a duckdb_result. This function should be called repeatedly until the result is exhausted.

The result must be destroyed with `duckdb_destroy_data_chunk`.

It is not known beforehand how many chunks will be returned by this result.

* @param result The result object to fetch the data chunk from.
* @return The resulting data chunk. Returns `NULL` if the result has an error.
*/
DUCKDB_API duckdb_data_chunk duckdb_fetch_chunk(duckdb_result result);

//===--------------------------------------------------------------------===//
// Cast Functions
//===--------------------------------------------------------------------===//

/*!
Creates a new cast function object.

* @return The cast function object.
*/
DUCKDB_API duckdb_cast_function duckdb_create_cast_function();

/*!
Sets the source type of the cast function.

* @param cast_function The cast function object.
* @param source_type The source type to set.
*/
DUCKDB_API void duckdb_cast_function_set_source_type(duckdb_cast_function cast_function,
                                                     duckdb_logical_type source_type);

/*!
Sets the target type of the cast function.

* @param cast_function The cast function object.
* @param target_type The target type to set.
*/
DUCKDB_API void duckdb_cast_function_set_target_type(duckdb_cast_function cast_function,
                                                     duckdb_logical_type target_type);

/*!
Sets the "cost" of implicitly casting the source type to the target type using this function.

* @param cast_function The cast function object.
* @param cost The cost to set.
*/
DUCKDB_API void duckdb_cast_function_set_implicit_cast_cost(duckdb_cast_function cast_function, int64_t cost);

/*!
Sets the actual cast function to use.

* @param cast_function The cast function object.
* @param function The function to set.
*/
DUCKDB_API void duckdb_cast_function_set_function(duckdb_cast_function cast_function, duckdb_cast_function_t function);

/*!
Assigns extra information to the cast function that can be fetched during execution, etc.

* @param extra_info The extra information
* @param destroy The callback that will be called to destroy the extra information (if any)
*/
DUCKDB_API void duckdb_cast_function_set_extra_info(duckdb_cast_function cast_function, void *extra_info,
                                                    duckdb_delete_callback_t destroy);

/*!
Retrieves the extra info of the function as set in `duckdb_cast_function_set_extra_info`.

* @param info The info object.
* @return The extra info.
*/
DUCKDB_API void *duckdb_cast_function_get_extra_info(duckdb_function_info info);

/*!
Get the cast execution mode from the given function info.

* @param info The info object.
* @return The cast mode.
*/
DUCKDB_API duckdb_cast_mode duckdb_cast_function_get_cast_mode(duckdb_function_info info);

/*!
Report that an error has occurred while executing the cast function.

* @param info The info object.
* @param error The error message.
*/
DUCKDB_API void duckdb_cast_function_set_error(duckdb_function_info info, const char *error);

/*!
Report that an error has occurred while executing the cast function, setting the corresponding output row to NULL.

* @param info The info object.
* @param error The error message.
* @param row The index of the row within the output vector to set to NULL.
* @param output The output vector.
*/
DUCKDB_API void duckdb_cast_function_set_row_error(duckdb_function_info info, const char *error, idx_t row,
                                                   duckdb_vector output);

/*!
Registers a cast function within the given connection.

* @param con The connection to use.
* @param cast_function The cast function to register.
* @return Whether or not the registration was successful.
*/
DUCKDB_API duckdb_state duckdb_register_cast_function(duckdb_connection con, duckdb_cast_function cast_function);

/*!
Destroys the cast function object.

* @param cast_function The cast function object.
*/
DUCKDB_API void duckdb_destroy_cast_function(duckdb_cast_function *cast_function);

#ifdef __cplusplus
}
#endif



//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/profiler.hpp
//
//
//===----------------------------------------------------------------------===//



//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/chrono.hpp
//
//
//===----------------------------------------------------------------------===//



#include <chrono>

namespace duckdb {
using std::chrono::duration;
using std::chrono::duration_cast;
using std::chrono::high_resolution_clock;
using std::chrono::milliseconds;
using std::chrono::system_clock;
using std::chrono::time_point;
} // namespace duckdb



namespace duckdb {

//! The profiler can be used to measure elapsed time
template <typename T>
class BaseProfiler {
public:
	//! Starts the timer
	void Start() {
		finished = false;
		start = Tick();
	}
	//! Finishes timing
	void End() {
		end = Tick();
		finished = true;
	}

	//! Returns the elapsed time in seconds. If End() has been called, returns
	//! the total elapsed time. Otherwise returns how far along the timer is
	//! right now.
	double Elapsed() const {
		auto measured_end = finished ? end : Tick();
		return std::chrono::duration_cast<std::chrono::duration<double>>(measured_end - start).count();
	}

private:
	time_point<T> Tick() const {
		return T::now();
	}
	time_point<T> start;
	time_point<T> end;
	bool finished = false;
};

using Profiler = BaseProfiler<system_clock>;

} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/progress_bar/progress_bar_display.hpp
//
//
//===----------------------------------------------------------------------===//



namespace duckdb {

class ProgressBarDisplay {
public:
	ProgressBarDisplay() {
	}
	virtual ~ProgressBarDisplay() {
	}

public:
	virtual void Update(double percentage) = 0;
	virtual void Finish() = 0;
};

} // namespace duckdb


namespace duckdb {

struct ClientConfig;
typedef unique_ptr<ProgressBarDisplay> (*progress_bar_display_create_func_t)();

struct QueryProgress {
	friend class ProgressBar;

public:
	QueryProgress();
	void Initialize();
	void Restart();
	double GetPercentage();
	uint64_t GetRowsProcesseed();
	uint64_t GetTotalRowsToProcess();
	QueryProgress &operator=(const QueryProgress &other);
	QueryProgress(const QueryProgress &other);

private:
	atomic<double> percentage;
	atomic<uint64_t> rows_processed;
	atomic<uint64_t> total_rows_to_process;
};

class ProgressBar {
public:
	static unique_ptr<ProgressBarDisplay> DefaultProgressBarDisplay();
	static void SystemOverrideCheck(ClientConfig &config);

	explicit ProgressBar(
	    Executor &executor, idx_t show_progress_after,
	    progress_bar_display_create_func_t create_display_func = ProgressBar::DefaultProgressBarDisplay);

	//! Starts the thread
	void Start();
	//! Updates the progress bar and prints it to the screen
	void Update(bool final);
	QueryProgress GetDetailedQueryProgress();
	void PrintProgress(int percentage);
	void FinishProgressBarPrint();
	bool ShouldPrint(bool final) const;
	bool PrintEnabled() const;

private:
	//! The executor
	Executor &executor;
	//! The profiler used to measure the time since the progress bar was started
	Profiler profiler;
	//! The time in ms after which to start displaying the progress bar
	idx_t show_progress_after;
	//! Keeps track of the total progress of a query
	QueryProgress query_progress;
	//! The display used to print the progress
	unique_ptr<ProgressBarDisplay> display;
	//! Whether or not profiling is supported for the current query
	bool supported = true;
	//! Whether the bar has already finished
	bool finished = false;
};
} // namespace duckdb


//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/main/profiling_info.hpp
//
//
//===----------------------------------------------------------------------===//










//-------------------------------------------------------------------------
//                         DuckDB
//
//
// duckdb/common/enums/metrics_type.hpp
// 
// This file is automatically generated by scripts/generate_metric_enums.py
// Do not edit this file manually, your changes will be overwritten
//-------------------------------------------------------------------------








//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/enums/optimizer_type.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

enum class OptimizerType : uint32_t {
	INVALID = 0,
	EXPRESSION_REWRITER,
	FILTER_PULLUP,
	FILTER_PUSHDOWN,
	CTE_FILTER_PUSHER,
	REGEX_RANGE,
	IN_CLAUSE,
	JOIN_ORDER,
	DELIMINATOR,
	UNNEST_REWRITER,
	UNUSED_COLUMNS,
	STATISTICS_PROPAGATION,
	COMMON_SUBEXPRESSIONS,
	COMMON_AGGREGATE,
	COLUMN_LIFETIME,
	BUILD_SIDE_PROBE_SIDE,
	LIMIT_PUSHDOWN,
	TOP_N,
	COMPRESSED_MATERIALIZATION,
	DUPLICATE_GROUPS,
	REORDER_FILTER,
	JOIN_FILTER_PUSHDOWN,
	EXTENSION,
	MATERIALIZED_CTE,
};

string OptimizerTypeToString(OptimizerType type);
OptimizerType OptimizerTypeFromString(const string &str);
vector<string> ListAllOptimizers();

} // namespace duckdb


namespace duckdb {

enum class MetricsType : uint8_t {
    QUERY_NAME,
    BLOCKED_THREAD_TIME,
    CPU_TIME,
    EXTRA_INFO,
    CUMULATIVE_CARDINALITY,
    OPERATOR_TYPE,
    OPERATOR_CARDINALITY,
    CUMULATIVE_ROWS_SCANNED,
    OPERATOR_ROWS_SCANNED,
    OPERATOR_TIMING,
    RESULT_SET_SIZE,
    ALL_OPTIMIZERS,
    CUMULATIVE_OPTIMIZER_TIMING,
    PLANNER,
    PLANNER_BINDING,
    PHYSICAL_PLANNER,
    PHYSICAL_PLANNER_COLUMN_BINDING,
    PHYSICAL_PLANNER_RESOLVE_TYPES,
    PHYSICAL_PLANNER_CREATE_PLAN,
    OPTIMIZER_EXPRESSION_REWRITER,
    OPTIMIZER_FILTER_PULLUP,
    OPTIMIZER_FILTER_PUSHDOWN,
    OPTIMIZER_CTE_FILTER_PUSHER,
    OPTIMIZER_REGEX_RANGE,
    OPTIMIZER_IN_CLAUSE,
    OPTIMIZER_JOIN_ORDER,
    OPTIMIZER_DELIMINATOR,
    OPTIMIZER_UNNEST_REWRITER,
    OPTIMIZER_UNUSED_COLUMNS,
    OPTIMIZER_STATISTICS_PROPAGATION,
    OPTIMIZER_COMMON_SUBEXPRESSIONS,
    OPTIMIZER_COMMON_AGGREGATE,
    OPTIMIZER_COLUMN_LIFETIME,
    OPTIMIZER_BUILD_SIDE_PROBE_SIDE,
    OPTIMIZER_LIMIT_PUSHDOWN,
    OPTIMIZER_TOP_N,
    OPTIMIZER_COMPRESSED_MATERIALIZATION,
    OPTIMIZER_DUPLICATE_GROUPS,
    OPTIMIZER_REORDER_FILTER,
    OPTIMIZER_JOIN_FILTER_PUSHDOWN,
    OPTIMIZER_EXTENSION,
    OPTIMIZER_MATERIALIZED_CTE,
};

struct MetricsTypeHashFunction {
	uint64_t operator()(const MetricsType &index) const {
		return std::hash<uint8_t>()(static_cast<uint8_t>(index));
	}
};

typedef unordered_set<MetricsType, MetricsTypeHashFunction> profiler_settings_t;
typedef unordered_map<MetricsType, Value, MetricsTypeHashFunction> profiler_metrics_t;

class MetricsUtils {
public:
    static profiler_settings_t GetOptimizerMetrics();
    static profiler_settings_t GetPhaseTimingMetrics();

    static MetricsType GetOptimizerMetricByType(OptimizerType type);
    static OptimizerType GetOptimizerTypeByMetric(MetricsType type);

    static bool IsOptimizerMetric(MetricsType type);
    static bool IsPhaseTimingMetric(MetricsType type);
};

} // namespace duckdb


namespace duckdb_yyjson {
struct yyjson_mut_doc;
struct yyjson_mut_val;
} // namespace duckdb_yyjson

namespace duckdb {

class ProfilingInfo {
public:
	// Enabling a metric adds it to this set.
	profiler_settings_t settings;
	// Contains all enabled metrics.
	profiler_metrics_t metrics;
	// Additional metrics.
	// FIXME: move to metrics.
	InsertionOrderPreservingMap<string> extra_info;

public:
	ProfilingInfo() = default;
	explicit ProfilingInfo(profiler_settings_t &n_settings, idx_t depth = 0) : settings(n_settings) {
		if (depth == 0) {
			settings.insert(MetricsType::QUERY_NAME);
		} else {
			settings.insert(MetricsType::OPERATOR_TYPE);
		}
		ResetMetrics();
	}
	ProfilingInfo(ProfilingInfo &) = default;
	ProfilingInfo &operator=(ProfilingInfo const &) = default;

public:
	static profiler_settings_t DefaultSettings();
	static profiler_settings_t DefaultOperatorSettings();
	static profiler_settings_t AllSettings();

public:
	void ResetMetrics();
	bool Enabled(const MetricsType setting) const;

public:
	string GetMetricAsString(MetricsType setting) const;
	void WriteMetricsToJSON(duckdb_yyjson::yyjson_mut_doc *doc, duckdb_yyjson::yyjson_mut_val *destination);

public:
	template <class METRIC_TYPE>
	METRIC_TYPE GetMetricValue(const MetricsType setting) const {
		auto val = metrics.at(setting);
		return val.GetValue<METRIC_TYPE>();
	}

	template <class METRIC_TYPE>
	void AddToMetric(const MetricsType setting, const Value &value) {
		D_ASSERT(!metrics[setting].IsNull());
		if (metrics.find(setting) == metrics.end()) {
			metrics[setting] = value;
			return;
		}
		auto new_value = metrics[setting].GetValue<METRIC_TYPE>() + value.GetValue<METRIC_TYPE>();
		metrics[setting] = Value::CreateValue(new_value);
	}

	template <class METRIC_TYPE>
	void AddToMetric(const MetricsType setting, const METRIC_TYPE &value) {
		auto new_value = Value::CreateValue(value);
		return AddToMetric<METRIC_TYPE>(setting, new_value);
	}
};
} // namespace duckdb


namespace duckdb {

class ClientContext;
class PhysicalResultCollector;
class PreparedStatementData;
class HTTPLogger;

typedef std::function<unique_ptr<PhysicalResultCollector>(ClientContext &context, PreparedStatementData &data)>
    get_result_collector_t;

struct ClientConfig {
	//! The home directory used by the system (if any)
	string home_directory;
	//! If the query profiler is enabled or not.
	bool enable_profiler = false;
	//! If detailed query profiling is enabled
	bool enable_detailed_profiling = false;
	//! The format to print query profiling information in (default: query_tree), if enabled.
	ProfilerPrintFormat profiler_print_format = ProfilerPrintFormat::QUERY_TREE;
	//! The file to save query profiling information to, instead of printing it to the console
	//! (empty = print to console)
	string profiler_save_location;
	//! The custom settings for the profiler
	//! (empty = use the default settings)
	profiler_settings_t profiler_settings = ProfilingInfo::DefaultSettings();

	//! Allows suppressing profiler output, even if enabled. We turn on the profiler on all test runs but don't want
	//! to output anything
	bool emit_profiler_output = true;

	//! system-wide progress bar disable.
	const char *system_progress_bar_disable_reason = nullptr;
	//! If the progress bar is enabled or not.
	bool enable_progress_bar = false;
	//! If the print of the progress bar is enabled
	bool print_progress_bar = true;
	//! The wait time before showing the progress bar
	int wait_time = 2000;

	//! Preserve identifier case while parsing.
	//! If false, all unquoted identifiers are lower-cased (e.g. "MyTable" -> "mytable").
	bool preserve_identifier_case = true;
	//! The maximum expression depth limit in the parser
	idx_t max_expression_depth = 1000;

	//! Whether or not aggressive query verification is enabled
	bool query_verification_enabled = false;
	//! Whether or not verification of external operators is enabled, used for testing
	bool verify_external = false;
	//! Whether or not verification of fetch row code is enabled, used for testing
	bool verify_fetch_row = false;
	//! Whether or not we should verify the serializer
	bool verify_serializer = false;
	//! Enable the running of optimizers
	bool enable_optimizer = true;
	//! Enable caching operators
	bool enable_caching_operators = true;
	//! Force parallelism of small tables, used for testing
	bool verify_parallelism = false;
	//! Force out-of-core computation for operators that support it, used for testing
	bool force_external = false;
	//! Force disable cross product generation when hyper graph isn't connected, used for testing
	bool force_no_cross_product = false;
	//! Force use of IEJoin to implement AsOfJoin, used for testing
	bool force_asof_iejoin = false;
	//! Force use of fetch row instead of scan, used for testing
	bool force_fetch_row = false;
	//! Use range joins for inequalities, even if there are equality predicates
	bool prefer_range_joins = false;
	//! If this context should also try to use the available replacement scans
	//! True by default
	bool use_replacement_scans = true;
	//! Maximum bits allowed for using a perfect hash table (i.e. the perfect HT can hold up to 2^perfect_ht_threshold
	//! elements)
	idx_t perfect_ht_threshold = 12;
	//! The maximum number of rows to accumulate before sorting ordered aggregates.
	idx_t ordered_aggregate_threshold = (idx_t(1) << 18);
	//! The number of rows to accumulate before flushing during a partitioned write
	idx_t partitioned_write_flush_threshold = idx_t(1) << idx_t(19);
	//! The amount of rows we can keep open before we close and flush them during a partitioned write
	idx_t partitioned_write_max_open_files = idx_t(100);
	//! The number of rows we need on either table to choose a nested loop join
	idx_t nested_loop_join_threshold = 5;
	//! The number of rows we need on either table to choose a merge join over an IE join
	idx_t merge_join_threshold = 1000;

	//! The maximum amount of memory to keep buffered in a streaming query result. Default: 1mb.
	idx_t streaming_buffer_size = 1000000;

	//! Callback to create a progress bar display
	progress_bar_display_create_func_t display_create_func = nullptr;

	//! The explain output type used when none is specified (default: PHYSICAL_ONLY)
	ExplainOutputType explain_output_type = ExplainOutputType::PHYSICAL_ONLY;

	//! The maximum amount of pivot columns
	idx_t pivot_limit = 100000;

	//! The threshold at which we switch from using filtered aggregates to LIST with a dedicated pivot operator
	idx_t pivot_filter_threshold = 20;

	//! Whether or not the "/" division operator defaults to integer division or floating point division
	bool integer_division = false;
	//! When a scalar subquery returns multiple rows - return a random row instead of returning an error
	bool scalar_subquery_error_on_multiple_rows = true;
	//! Use IEE754-compliant floating point operations (returning NAN instead of errors/NULL)
	bool ieee_floating_point_ops = true;
	//! Allow ordering by non-integer literals - ordering by such literals has no effect
	bool order_by_non_integer_literal = false;

	//! Output error messages as structured JSON instead of as a raw string
	bool errors_as_json = false;

	//! Generic options
	case_insensitive_map_t<Value> set_variables;

	//! Variables set by the user
	case_insensitive_map_t<Value> user_variables;

	//! Function that is used to create the result collector for a materialized result
	//! Defaults to PhysicalMaterializedCollector
	get_result_collector_t result_collector = nullptr;

	//! If HTTP logging is enabled or not.
	bool enable_http_logging = false;
	//! The file to save query HTTP logging information to, instead of printing it to the console
	//! (empty = print to console)
	string http_logging_output;

public:
	static ClientConfig &GetConfig(ClientContext &context);
	static const ClientConfig &GetConfig(const ClientContext &context);

	bool AnyVerification() {
		return query_verification_enabled || verify_external || verify_serializer || verify_fetch_row;
	}

	void SetUserVariable(const string &name, Value value) {
		user_variables[name] = std::move(value);
	}

	bool GetUserVariable(const string &name, Value &result) {
		auto entry = user_variables.find(name);
		if (entry == user_variables.end()) {
			return false;
		}
		result = entry->second;
		return true;
	}

	void ResetUserVariable(const string &name) {
		user_variables.erase(name);
	}

public:
	void SetDefaultStreamingBufferSize();
};

struct ScopedConfigSetting {
public:
	using config_modify_func_t = std::function<void(ClientConfig &config)>;

public:
	explicit ScopedConfigSetting(ClientConfig &config, config_modify_func_t set_f = nullptr,
	                             config_modify_func_t unset_f = nullptr)
	    : config(config), set(std::move(set_f)), unset(std::move(unset_f)) {
		if (set) {
			set(config);
		}
	}
	~ScopedConfigSetting() {
		if (unset) {
			unset(config);
		}
	}

public:
	ClientConfig &config;
	config_modify_func_t set;
	config_modify_func_t unset;
};

} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/main/client_context_state.hpp
//
//
//===----------------------------------------------------------------------===//




//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/exception/transaction_exception.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

class TransactionException : public Exception {
public:
	DUCKDB_API explicit TransactionException(const string &msg);

	template <typename... ARGS>
	explicit TransactionException(const string &msg, ARGS... params)
	    : TransactionException(ConstructMessage(msg, params...)) {
	}
};

} // namespace duckdb


//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/main/config.hpp
//
//
//===----------------------------------------------------------------------===//





//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/cgroups.hpp
//
//
//===----------------------------------------------------------------------===//







namespace duckdb {

class CGroups {
public:
	static optional_idx GetMemoryLimit(FileSystem &fs);
	static idx_t GetCPULimit(FileSystem &fs, idx_t physical_cores);

private:
	static optional_idx GetCGroupV2MemoryLimit(FileSystem &fs);
	static optional_idx GetCGroupV1MemoryLimit(FileSystem &fs);
	static string ReadCGroupPath(FileSystem &fs, const char *cgroup_file);
	static string ReadMemoryCGroupPath(FileSystem &fs, const char *cgroup_file);
	static optional_idx ReadCGroupValue(FileSystem &fs, const char *file_path);
};

} // namespace duckdb


//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/encryption_state.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

class EncryptionState {

public:
	DUCKDB_API EncryptionState();
	DUCKDB_API virtual ~EncryptionState();

public:
	DUCKDB_API virtual bool IsOpenSSL();
	DUCKDB_API virtual void InitializeEncryption(const_data_ptr_t iv, idx_t iv_len, const std::string *key);
	DUCKDB_API virtual void InitializeDecryption(const_data_ptr_t iv, idx_t iv_len, const std::string *key);
	DUCKDB_API virtual size_t Process(const_data_ptr_t in, idx_t in_len, data_ptr_t out, idx_t out_len);
	DUCKDB_API virtual size_t Finalize(data_ptr_t out, idx_t out_len, data_ptr_t tag, idx_t tag_len);
	DUCKDB_API virtual void GenerateRandomData(data_ptr_t data, idx_t len);

public:
	enum Mode { ENCRYPT, DECRYPT };
};

class EncryptionUtil {

public:
	DUCKDB_API explicit EncryptionUtil() {};

public:
	virtual shared_ptr<EncryptionState> CreateEncryptionState() const {
		return make_shared_ptr<EncryptionState>();
	}

	virtual ~EncryptionUtil() {
	}
};

} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/enums/access_mode.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

enum class AccessMode : uint8_t { UNDEFINED = 0, AUTOMATIC = 1, READ_ONLY = 2, READ_WRITE = 3 };

} // namespace duckdb




//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/enums/set_scope.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

enum class SetScope : uint8_t {
	AUTOMATIC = 0,
	LOCAL = 1, /* unused */
	SESSION = 2,
	GLOBAL = 3,
	VARIABLE = 4
};

} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/enums/window_aggregation_mode.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

enum class WindowAggregationMode : uint32_t {
	//! Use the window aggregate API if available
	WINDOW = 0,
	//! Don't use window, but use combine if available
	COMBINE,
	//! Don't use combine or window (compute each frame separately)
	SEPARATE
};

} // namespace duckdb






//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/function/cast/default_casts.hpp
//
//
//===----------------------------------------------------------------------===//









namespace duckdb {

class CastFunctionSet;
struct FunctionLocalState;

//! Extra data that can be attached to a bind function of a cast, and is available during binding
struct BindCastInfo {
	DUCKDB_API virtual ~BindCastInfo();

	template <class TARGET>
	TARGET &Cast() {
		DynamicCastCheck<TARGET>(this);
		return reinterpret_cast<TARGET &>(*this);
	}
	template <class TARGET>
	const TARGET &Cast() const {
		DynamicCastCheck<TARGET>(this);
		return reinterpret_cast<const TARGET &>(*this);
	}
};

//! Extra data that can be returned by the bind of a cast, and is available during execution of a cast
struct BoundCastData {
	DUCKDB_API virtual ~BoundCastData();

	DUCKDB_API virtual unique_ptr<BoundCastData> Copy() const = 0;

	template <class TARGET>
	TARGET &Cast() {
		DynamicCastCheck<TARGET>(this);
		return reinterpret_cast<TARGET &>(*this);
	}
	template <class TARGET>
	const TARGET &Cast() const {
		DynamicCastCheck<TARGET>(this);
		return reinterpret_cast<const TARGET &>(*this);
	}
};

struct CastParameters {
	CastParameters() {
	}
	CastParameters(bool strict, string *error_message) : CastParameters(nullptr, strict, error_message, nullptr) {
	}
	CastParameters(BoundCastData *cast_data, bool strict, string *error_message,
	               optional_ptr<FunctionLocalState> local_state, bool nullify_parent_p = false)
	    : cast_data(cast_data), strict(strict), error_message(error_message), local_state(local_state),
	      nullify_parent(nullify_parent_p) {
	}
	CastParameters(CastParameters &parent, optional_ptr<BoundCastData> cast_data,
	               optional_ptr<FunctionLocalState> local_state)
	    : cast_data(cast_data), strict(parent.strict), error_message(parent.error_message), local_state(local_state),
	      query_location(parent.query_location) {
	}

	//! The bound cast data (if any)
	optional_ptr<BoundCastData> cast_data;
	//! whether or not to enable strict casting
	bool strict = false;
	// out: error message in case cast has failed
	string *error_message = nullptr;
	//! Local state
	optional_ptr<FunctionLocalState> local_state;
	//! Query location (if any)
	optional_idx query_location;
	//! In the case of a nested type, when facing a cast error, if we nullify the parent
	bool nullify_parent = false;
};

struct CastLocalStateParameters {
	CastLocalStateParameters(optional_ptr<ClientContext> context_p, optional_ptr<BoundCastData> cast_data_p)
	    : context(context_p), cast_data(cast_data_p) {
	}
	CastLocalStateParameters(ClientContext &context_p, optional_ptr<BoundCastData> cast_data_p)
	    : context(&context_p), cast_data(cast_data_p) {
	}
	CastLocalStateParameters(CastLocalStateParameters &parent, optional_ptr<BoundCastData> cast_data_p)
	    : context(parent.context), cast_data(cast_data_p) {
	}

	optional_ptr<ClientContext> context;
	//! The bound cast data (if any)
	optional_ptr<BoundCastData> cast_data;
};

typedef bool (*cast_function_t)(Vector &source, Vector &result, idx_t count, CastParameters &parameters);
typedef unique_ptr<FunctionLocalState> (*init_cast_local_state_t)(CastLocalStateParameters &parameters);

struct BoundCastInfo {
	DUCKDB_API
	BoundCastInfo( // NOLINT: allow explicit cast from cast_function_t
	    cast_function_t function, unique_ptr<BoundCastData> cast_data = nullptr,
	    init_cast_local_state_t init_local_state = nullptr);
	cast_function_t function;
	init_cast_local_state_t init_local_state;
	unique_ptr<BoundCastData> cast_data;

public:
	BoundCastInfo Copy() const;
};

struct BindCastInput {
	DUCKDB_API BindCastInput(CastFunctionSet &function_set, optional_ptr<BindCastInfo> info,
	                         optional_ptr<ClientContext> context);

	CastFunctionSet &function_set;
	optional_ptr<BindCastInfo> info;
	optional_ptr<ClientContext> context;
	optional_idx query_location;

public:
	DUCKDB_API BoundCastInfo GetCastFunction(const LogicalType &source, const LogicalType &target);
};

struct DefaultCasts {
	DUCKDB_API static BoundCastInfo GetDefaultCastFunction(BindCastInput &input, const LogicalType &source,
	                                                       const LogicalType &target);

	DUCKDB_API static bool NopCast(Vector &source, Vector &result, idx_t count, CastParameters &parameters);
	DUCKDB_API static bool TryVectorNullCast(Vector &source, Vector &result, idx_t count, CastParameters &parameters);
	DUCKDB_API static bool ReinterpretCast(Vector &source, Vector &result, idx_t count, CastParameters &parameters);

private:
	static BoundCastInfo BlobCastSwitch(BindCastInput &input, const LogicalType &source, const LogicalType &target);
	static BoundCastInfo BitCastSwitch(BindCastInput &input, const LogicalType &source, const LogicalType &target);
	static BoundCastInfo DateCastSwitch(BindCastInput &input, const LogicalType &source, const LogicalType &target);
	static BoundCastInfo DecimalCastSwitch(BindCastInput &input, const LogicalType &source, const LogicalType &target);
	static BoundCastInfo EnumCastSwitch(BindCastInput &input, const LogicalType &source, const LogicalType &target);
	static BoundCastInfo IntervalCastSwitch(BindCastInput &input, const LogicalType &source, const LogicalType &target);
	static BoundCastInfo ListCastSwitch(BindCastInput &input, const LogicalType &source, const LogicalType &target);
	static BoundCastInfo ArrayCastSwitch(BindCastInput &input, const LogicalType &source, const LogicalType &target);
	static BoundCastInfo NumericCastSwitch(BindCastInput &input, const LogicalType &source, const LogicalType &target);
	static BoundCastInfo MapCastSwitch(BindCastInput &input, const LogicalType &source, const LogicalType &target);
	static BoundCastInfo PointerCastSwitch(BindCastInput &input, const LogicalType &source, const LogicalType &target);
	static BoundCastInfo StringCastSwitch(BindCastInput &input, const LogicalType &source, const LogicalType &target);
	static BoundCastInfo StructCastSwitch(BindCastInput &input, const LogicalType &source, const LogicalType &target);
	static BoundCastInfo TimeCastSwitch(BindCastInput &input, const LogicalType &source, const LogicalType &target);
	static BoundCastInfo TimeTzCastSwitch(BindCastInput &input, const LogicalType &source, const LogicalType &target);
	static BoundCastInfo TimestampCastSwitch(BindCastInput &input, const LogicalType &source,
	                                         const LogicalType &target);
	static BoundCastInfo TimestampTzCastSwitch(BindCastInput &input, const LogicalType &source,
	                                           const LogicalType &target);
	static BoundCastInfo TimestampNsCastSwitch(BindCastInput &input, const LogicalType &source,
	                                           const LogicalType &target);
	static BoundCastInfo TimestampMsCastSwitch(BindCastInput &input, const LogicalType &source,
	                                           const LogicalType &target);
	static BoundCastInfo TimestampSecCastSwitch(BindCastInput &input, const LogicalType &source,
	                                            const LogicalType &target);
	static BoundCastInfo UnionCastSwitch(BindCastInput &input, const LogicalType &source, const LogicalType &target);
	static BoundCastInfo UUIDCastSwitch(BindCastInput &input, const LogicalType &source, const LogicalType &target);
	static BoundCastInfo VarintCastSwitch(BindCastInput &input, const LogicalType &source, const LogicalType &target);
	static BoundCastInfo ImplicitToUnionCast(BindCastInput &input, const LogicalType &source,
	                                         const LogicalType &target);
};

} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/function/replacement_scan.hpp
//
//
//===----------------------------------------------------------------------===//







namespace duckdb {

class ClientContext;
class TableRef;

struct ReplacementScanData {
public:
	virtual ~ReplacementScanData() {
	}

public:
	template <class TARGET>
	TARGET &Cast() {
		DynamicCastCheck<TARGET>(this);
		return reinterpret_cast<TARGET &>(*this);
	}
	template <class TARGET>
	const TARGET &Cast() const {
		DynamicCastCheck<TARGET>(this);
		return reinterpret_cast<const TARGET &>(*this);
	}
};

struct ReplacementScanInput {
public:
	explicit ReplacementScanInput(const string &catalog_name, const string &schema_name, const string &table_name)
	    : catalog_name(catalog_name), schema_name(schema_name), table_name(table_name) {
	}

public:
	const string &catalog_name;
	const string &schema_name;
	const string &table_name;
};

typedef unique_ptr<TableRef> (*replacement_scan_t)(ClientContext &context, ReplacementScanInput &input,
                                                   optional_ptr<ReplacementScanData> data);

//! Replacement table scans are automatically attempted when a table name cannot be found in the schema
//! This allows you to do e.g. SELECT * FROM 'filename.csv', and automatically convert this into a CSV scan
struct ReplacementScan {
	explicit ReplacementScan(replacement_scan_t function, unique_ptr<ReplacementScanData> data_p = nullptr)
	    : function(function), data(std::move(data_p)) {
	}

	static bool CanReplace(const string &table_name, const vector<string> &extensions) {
		auto lower_name = StringUtil::Lower(table_name);

		if (StringUtil::EndsWith(lower_name, CompressionExtensionFromType(FileCompressionType::GZIP))) {
			lower_name = lower_name.substr(0, lower_name.size() - 3);
		} else if (StringUtil::EndsWith(lower_name, CompressionExtensionFromType(FileCompressionType::ZSTD))) {
			lower_name = lower_name.substr(0, lower_name.size() - 4);
		}

		for (auto &extension : extensions) {
			if (StringUtil::EndsWith(lower_name, "." + extension) ||
			    StringUtil::Contains(lower_name, "." + extension + "?")) {
				return true;
			}
		}

		return false;
	}

	static string GetFullPath(const string &catalog, const string &schema, const string &table) {
		string table_name = catalog;
		if (!schema.empty()) {
			table_name += (!table_name.empty() ? "." : "") + schema;
		}
		table_name += (!table_name.empty() ? "." : "") + table;
		return table_name;
	}

	static string GetFullPath(ReplacementScanInput &input) {
		return GetFullPath(input.catalog_name, input.schema_name, input.table_name);
	}

	replacement_scan_t function;
	unique_ptr<ReplacementScanData> data;
};

} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/optimizer/optimizer_extension.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

class Optimizer;
class ClientContext;

//! The OptimizerExtensionInfo holds static information relevant to the optimizer extension
struct OptimizerExtensionInfo {
	virtual ~OptimizerExtensionInfo() {
	}
};

struct OptimizerExtensionInput {
	ClientContext &context;
	Optimizer &optimizer;
	optional_ptr<OptimizerExtensionInfo> info;
};

typedef void (*optimize_function_t)(OptimizerExtensionInput &input, unique_ptr<LogicalOperator> &plan);

class OptimizerExtension {
public:
	//! The parse function of the parser extension.
	//! Takes a query string as input and returns ParserExtensionParseData (on success) or an error
	optimize_function_t optimize_function;

	//! Additional parser info passed to the parse function
	shared_ptr<OptimizerExtensionInfo> optimizer_info;
};

} // namespace duckdb


//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/parser/parser_extension.hpp
//
//
//===----------------------------------------------------------------------===//







namespace duckdb {

//! The ParserExtensionInfo holds static information relevant to the parser extension
//! It is made available in the parse_function, and will be kept alive as long as the database system is kept alive
struct ParserExtensionInfo {
	virtual ~ParserExtensionInfo() {
	}
};

//===--------------------------------------------------------------------===//
// Parse
//===--------------------------------------------------------------------===//
enum class ParserExtensionResultType : uint8_t { PARSE_SUCCESSFUL, DISPLAY_ORIGINAL_ERROR, DISPLAY_EXTENSION_ERROR };

//! The ParserExtensionParseData holds the result of a successful parse step
//! It will be passed along to the subsequent plan function
struct ParserExtensionParseData {
	virtual ~ParserExtensionParseData() {
	}

	virtual unique_ptr<ParserExtensionParseData> Copy() const = 0;
	virtual string ToString() const = 0;
};

struct ParserExtensionParseResult {
	ParserExtensionParseResult() : type(ParserExtensionResultType::DISPLAY_ORIGINAL_ERROR) {
	}
	explicit ParserExtensionParseResult(string error_p)
	    : type(ParserExtensionResultType::DISPLAY_EXTENSION_ERROR), error(std::move(error_p)) {
	}
	explicit ParserExtensionParseResult(unique_ptr<ParserExtensionParseData> parse_data_p)
	    : type(ParserExtensionResultType::PARSE_SUCCESSFUL), parse_data(std::move(parse_data_p)) {
	}

	//! Whether or not parsing was successful
	ParserExtensionResultType type;
	//! The parse data (if successful)
	unique_ptr<ParserExtensionParseData> parse_data;
	//! The error message (if unsuccessful)
	string error;
	//! The error location (if unsuccessful)
	optional_idx error_location;
};

typedef ParserExtensionParseResult (*parse_function_t)(ParserExtensionInfo *info, const string &query);
//===--------------------------------------------------------------------===//
// Plan
//===--------------------------------------------------------------------===//
struct ParserExtensionPlanResult { // NOLINT: work-around bug in clang-tidy
	//! The table function to execute
	TableFunction function;
	//! Parameters to the function
	vector<Value> parameters;
	//! The set of databases that will be modified by this statement (empty for a read-only statement)
	unordered_map<string, StatementProperties::CatalogIdentity> modified_databases;
	//! Whether or not the statement requires a valid transaction to be executed
	bool requires_valid_transaction = true;
	//! What type of result set the statement returns
	StatementReturnType return_type = StatementReturnType::NOTHING;
};

typedef ParserExtensionPlanResult (*plan_function_t)(ParserExtensionInfo *info, ClientContext &context,
                                                     unique_ptr<ParserExtensionParseData> parse_data);

//===--------------------------------------------------------------------===//
// ParserExtension
//===--------------------------------------------------------------------===//
class ParserExtension {
public:
	//! The parse function of the parser extension.
	//! Takes a query string as input and returns ParserExtensionParseData (on success) or an error
	parse_function_t parse_function;

	//! The plan function of the parser extension
	//! Takes as input the result of the parse_function, and outputs various properties of the resulting plan
	plan_function_t plan_function;

	//! Additional parser info passed to the parse function
	shared_ptr<ParserExtensionInfo> parser_info;
};

} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/operator_extension.hpp
//
//
//===----------------------------------------------------------------------===//




//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/physical_plan_generator.hpp
//
//
//===----------------------------------------------------------------------===//







//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/joinside.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

//! JoinCondition represents a left-right comparison join condition
struct JoinCondition {
public:
	JoinCondition() {
	}

	//! Turns the JoinCondition into an expression; note that this destroys the JoinCondition as the expression inherits
	//! the left/right expressions
	static unique_ptr<Expression> CreateExpression(JoinCondition cond);
	static unique_ptr<Expression> CreateExpression(vector<JoinCondition> conditions);

	void Serialize(Serializer &serializer) const;
	static JoinCondition Deserialize(Deserializer &deserializer);

public:
	unique_ptr<Expression> left;
	unique_ptr<Expression> right;
	ExpressionType comparison;
};

class JoinSide {
public:
	enum JoinValue : uint8_t { NONE, LEFT, RIGHT, BOTH };

	JoinSide() = default;
	constexpr JoinSide(JoinValue val) : value(val) { // NOLINT: Allow implicit conversion from `join_value`
	}

	bool operator==(JoinSide a) const {
		return value == a.value;
	}
	bool operator!=(JoinSide a) const {
		return value != a.value;
	}

	static JoinSide CombineJoinSide(JoinSide left, JoinSide right);
	static JoinSide GetJoinSide(idx_t table_binding, const unordered_set<idx_t> &left_bindings,
	                            const unordered_set<uint64_t> &right_bindings);
	static JoinSide GetJoinSide(Expression &expression, const unordered_set<idx_t> &left_bindings,
	                            const unordered_set<idx_t> &right_bindings);
	static JoinSide GetJoinSide(const unordered_set<idx_t> &bindings, const unordered_set<idx_t> &left_bindings,
	                            const unordered_set<idx_t> &right_bindings);

private:
	JoinValue value;
};

} // namespace duckdb





namespace duckdb {
class ClientContext;
class ColumnDataCollection;

//! The physical plan generator generates a physical execution plan from a
//! logical query plan
class PhysicalPlanGenerator {
public:
	explicit PhysicalPlanGenerator(ClientContext &context);
	~PhysicalPlanGenerator();

	LogicalDependencyList dependencies;
	//! Recursive CTEs require at least one ChunkScan, referencing the working_table.
	//! This data structure is used to establish it.
	unordered_map<idx_t, shared_ptr<ColumnDataCollection>> recursive_cte_tables;
	//! Materialized CTE ids must be collected.
	unordered_map<idx_t, vector<const_reference<PhysicalOperator>>> materialized_ctes;

public:
	//! Creates a plan from the logical operator. This involves resolving column bindings and generating physical
	//! operator nodes.
	unique_ptr<PhysicalOperator> CreatePlan(unique_ptr<LogicalOperator> logical);

	//! Whether or not we can (or should) use a batch-index based operator for executing the given sink
	static bool UseBatchIndex(ClientContext &context, PhysicalOperator &plan);
	//! Whether or not we should preserve insertion order for executing the given sink
	static bool PreserveInsertionOrder(ClientContext &context, PhysicalOperator &plan);

	static bool HasEquality(vector<JoinCondition> &conds, idx_t &range_count);

protected:
	unique_ptr<PhysicalOperator> CreatePlan(LogicalOperator &op);

	unique_ptr<PhysicalOperator> CreatePlan(LogicalAggregate &op);
	unique_ptr<PhysicalOperator> CreatePlan(LogicalAnyJoin &op);
	unique_ptr<PhysicalOperator> CreatePlan(LogicalColumnDataGet &op);
	unique_ptr<PhysicalOperator> CreatePlan(LogicalComparisonJoin &op);
	unique_ptr<PhysicalOperator> CreatePlan(LogicalCopyDatabase &op);
	unique_ptr<PhysicalOperator> CreatePlan(LogicalCreate &op);
	unique_ptr<PhysicalOperator> CreatePlan(LogicalCreateTable &op);
	unique_ptr<PhysicalOperator> CreatePlan(LogicalCreateIndex &op);
	unique_ptr<PhysicalOperator> CreatePlan(LogicalCreateSecret &op);
	unique_ptr<PhysicalOperator> CreatePlan(LogicalCrossProduct &op);
	unique_ptr<PhysicalOperator> CreatePlan(LogicalDelete &op);
	unique_ptr<PhysicalOperator> CreatePlan(LogicalDelimGet &op);
	unique_ptr<PhysicalOperator> CreatePlan(LogicalDistinct &op);
	unique_ptr<PhysicalOperator> CreatePlan(LogicalDummyScan &expr);
	unique_ptr<PhysicalOperator> CreatePlan(LogicalEmptyResult &op);
	unique_ptr<PhysicalOperator> CreatePlan(LogicalExpressionGet &op);
	unique_ptr<PhysicalOperator> CreatePlan(LogicalExport &op);
	unique_ptr<PhysicalOperator> CreatePlan(LogicalFilter &op);
	unique_ptr<PhysicalOperator> CreatePlan(LogicalGet &op);
	unique_ptr<PhysicalOperator> CreatePlan(LogicalLimit &op);
	unique_ptr<PhysicalOperator> CreatePlan(LogicalOrder &op);
	unique_ptr<PhysicalOperator> CreatePlan(LogicalTopN &op);
	unique_ptr<PhysicalOperator> CreatePlan(LogicalPositionalJoin &op);
	unique_ptr<PhysicalOperator> CreatePlan(LogicalProjection &op);
	unique_ptr<PhysicalOperator> CreatePlan(LogicalInsert &op);
	unique_ptr<PhysicalOperator> CreatePlan(LogicalCopyToFile &op);
	unique_ptr<PhysicalOperator> CreatePlan(LogicalExplain &op);
	unique_ptr<PhysicalOperator> CreatePlan(LogicalSetOperation &op);
	unique_ptr<PhysicalOperator> CreatePlan(LogicalUpdate &op);
	unique_ptr<PhysicalOperator> CreatePlan(LogicalPrepare &expr);
	unique_ptr<PhysicalOperator> CreatePlan(LogicalWindow &expr);
	unique_ptr<PhysicalOperator> CreatePlan(LogicalExecute &op);
	unique_ptr<PhysicalOperator> CreatePlan(LogicalPragma &op);
	unique_ptr<PhysicalOperator> CreatePlan(LogicalSample &op);
	unique_ptr<PhysicalOperator> CreatePlan(LogicalSet &op);
	unique_ptr<PhysicalOperator> CreatePlan(LogicalReset &op);
	unique_ptr<PhysicalOperator> CreatePlan(LogicalSimple &op);
	unique_ptr<PhysicalOperator> CreatePlan(LogicalVacuum &op);
	unique_ptr<PhysicalOperator> CreatePlan(LogicalUnnest &op);
	unique_ptr<PhysicalOperator> CreatePlan(LogicalRecursiveCTE &op);
	unique_ptr<PhysicalOperator> CreatePlan(LogicalMaterializedCTE &op);
	unique_ptr<PhysicalOperator> CreatePlan(LogicalCTERef &op);
	unique_ptr<PhysicalOperator> CreatePlan(LogicalPivot &op);

	unique_ptr<PhysicalOperator> PlanAsOfJoin(LogicalComparisonJoin &op);
	unique_ptr<PhysicalOperator> PlanComparisonJoin(LogicalComparisonJoin &op);
	unique_ptr<PhysicalOperator> PlanDelimJoin(LogicalComparisonJoin &op);
	unique_ptr<PhysicalOperator> ExtractAggregateExpressions(unique_ptr<PhysicalOperator> child,
	                                                         vector<unique_ptr<Expression>> &expressions,
	                                                         vector<unique_ptr<Expression>> &groups);

private:
	bool PreserveInsertionOrder(PhysicalOperator &plan);
	bool UseBatchIndex(PhysicalOperator &plan);

public:
	idx_t delim_index = 0;

private:
	ClientContext &context;
};
} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/binder.hpp
//
//
//===----------------------------------------------------------------------===//










//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/parser/query_node.hpp
//
//
//===----------------------------------------------------------------------===//






//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/parser/common_table_expression_info.hpp
//
//
//===----------------------------------------------------------------------===//



//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/parser/statement/select_statement.hpp
//
//
//===----------------------------------------------------------------------===//





//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/parser/sql_statement.hpp
//
//
//===----------------------------------------------------------------------===//






//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/printer.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

enum class OutputStream : uint8_t { STREAM_STDOUT = 1, STREAM_STDERR = 2 };

//! Printer is a static class that allows printing to logs or stdout/stderr
class Printer {
public:
	//! Print the object to the stream
	DUCKDB_API static void Print(OutputStream stream, const string &str);
	//! Print the object to stderr
	DUCKDB_API static void Print(const string &str);
	//! Print the formatted object to the stream
	template <typename... ARGS>
	static void PrintF(OutputStream stream, const string &str, ARGS... params) {
		Printer::Print(stream, StringUtil::Format(str, params...));
	}
	//! Print the formatted object to stderr
	template <typename... ARGS>
	static void PrintF(const string &str, ARGS... params) {
		Printer::PrintF(OutputStream::STREAM_STDERR, str, std::forward<ARGS>(params)...);
	}
	//! Directly prints the string to stdout without a newline
	DUCKDB_API static void RawPrint(OutputStream stream, const string &str);
	//! Flush an output stream
	DUCKDB_API static void Flush(OutputStream stream);
	//! Whether or not we are printing to a terminal
	DUCKDB_API static bool IsTerminal(OutputStream stream);
	//! The terminal width
	DUCKDB_API static idx_t TerminalWidth();
};
} // namespace duckdb



namespace duckdb {

//! SQLStatement is the base class of any type of SQL statement.
class SQLStatement {
public:
	static constexpr const StatementType TYPE = StatementType::INVALID_STATEMENT;

public:
	explicit SQLStatement(StatementType type) : type(type) {
	}
	virtual ~SQLStatement() {
	}

	//! The statement type
	StatementType type;
	//! The statement location within the query string
	idx_t stmt_location = 0;
	//! The statement length within the query string
	idx_t stmt_length = 0;
	//! The map of named parameter to param index
	case_insensitive_map_t<idx_t> named_param_map;
	//! The query text that corresponds to this SQL statement
	string query;

protected:
	SQLStatement(const SQLStatement &other) = default;

public:
	virtual string ToString() const = 0;
	//! Create a copy of this SelectStatement
	DUCKDB_API virtual unique_ptr<SQLStatement> Copy() const = 0;

public:
public:
	template <class TARGET>
	TARGET &Cast() {
		if (type != TARGET::TYPE && TARGET::TYPE != StatementType::INVALID_STATEMENT) {
			throw InternalException("Failed to cast statement to type - statement type mismatch");
		}
		return reinterpret_cast<TARGET &>(*this);
	}

	template <class TARGET>
	const TARGET &Cast() const {
		if (type != TARGET::TYPE && TARGET::TYPE != StatementType::INVALID_STATEMENT) {
			throw InternalException("Failed to cast statement to type - statement type mismatch");
		}
		return reinterpret_cast<const TARGET &>(*this);
	}
};
} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/parser/tableref.hpp
//
//
//===----------------------------------------------------------------------===//





//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/enums/tableref_type.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

//===--------------------------------------------------------------------===//
// Table Reference Types
//===--------------------------------------------------------------------===//
enum class TableReferenceType : uint8_t {
	INVALID = 0,         // invalid table reference type
	BASE_TABLE = 1,      // base table reference
	SUBQUERY = 2,        // output of a subquery
	JOIN = 3,            // output of join
	TABLE_FUNCTION = 5,  // table producing function
	EXPRESSION_LIST = 6, // expression list
	CTE = 7,             // Recursive CTE
	EMPTY_FROM = 8,      // placeholder for empty FROM
	PIVOT = 9,           // pivot statement
	SHOW_REF = 10,       // SHOW statement
	COLUMN_DATA = 11,    // column data collection
	DELIM_GET = 12       // Delim get ref
};

} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/parser/parsed_data/sample_options.hpp
//
//
//===----------------------------------------------------------------------===//








namespace duckdb {

enum class SampleMethod : uint8_t { SYSTEM_SAMPLE = 0, BERNOULLI_SAMPLE = 1, RESERVOIR_SAMPLE = 2 };

// **DEPRECATED**: Use EnumUtil directly instead.
string SampleMethodToString(SampleMethod method);

struct SampleOptions {
	Value sample_size;
	bool is_percentage;
	SampleMethod method;
	int64_t seed = -1;

	unique_ptr<SampleOptions> Copy();
	static bool Equals(SampleOptions *a, SampleOptions *b);
	void Serialize(Serializer &serializer) const;
	static unique_ptr<SampleOptions> Deserialize(Deserializer &deserializer);
};

} // namespace duckdb



namespace duckdb {

//! Represents a generic expression that returns a table.
class TableRef {
public:
	static constexpr const TableReferenceType TYPE = TableReferenceType::INVALID;

public:
	explicit TableRef(TableReferenceType type) : type(type) {
	}
	virtual ~TableRef() {
	}

	TableReferenceType type;
	string alias;
	//! Sample options (if any)
	unique_ptr<SampleOptions> sample;
	//! The location in the query (if any)
	optional_idx query_location;
	//! External dependencies of this table function
	shared_ptr<ExternalDependency> external_dependency;
	//! Aliases for the column names
	vector<string> column_name_alias;

public:
	//! Convert the object to a string
	virtual string ToString() const = 0;
	string BaseToString(string result) const;
	string BaseToString(string result, const vector<string> &column_name_alias) const;
	void Print();

	virtual bool Equals(const TableRef &other) const;
	static bool Equals(const unique_ptr<TableRef> &left, const unique_ptr<TableRef> &right);

	virtual unique_ptr<TableRef> Copy() = 0;

	//! Copy the properties of this table ref to the target
	void CopyProperties(TableRef &target) const;

	virtual void Serialize(Serializer &serializer) const;
	static unique_ptr<TableRef> Deserialize(Deserializer &deserializer);

public:
	template <class TARGET>
	TARGET &Cast() {
		if (type != TARGET::TYPE && TARGET::TYPE != TableReferenceType::INVALID) {
			throw InternalException("Failed to cast constraint to type - constraint type mismatch");
		}
		return reinterpret_cast<TARGET &>(*this);
	}

	template <class TARGET>
	const TARGET &Cast() const {
		if (type != TARGET::TYPE && TARGET::TYPE != TableReferenceType::INVALID) {
			throw InternalException("Failed to cast constraint to type - constraint type mismatch");
		}
		return reinterpret_cast<const TARGET &>(*this);
	}
};
} // namespace duckdb



namespace duckdb {

class QueryNode;
class Serializer;
class Deserializer;

//! SelectStatement is a typical SELECT clause
class SelectStatement : public SQLStatement {
public:
	static constexpr const StatementType TYPE = StatementType::SELECT_STATEMENT;

public:
	SelectStatement() : SQLStatement(StatementType::SELECT_STATEMENT) {
	}

	//! The main query node
	unique_ptr<QueryNode> node;

protected:
	SelectStatement(const SelectStatement &other);

public:
	//! Convert the SELECT statement to a string

	DUCKDB_API string ToString() const override;
	//! Create a copy of this SelectStatement
	DUCKDB_API unique_ptr<SQLStatement> Copy() const override;
	//! Whether or not the statements are equivalent
	bool Equals(const SQLStatement &other) const;

	void Serialize(Serializer &serializer) const;
	static unique_ptr<SelectStatement> Deserialize(Deserializer &deserializer);
};
} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/enums/cte_materialize.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

enum class CTEMaterialize : uint8_t {
	CTE_MATERIALIZE_DEFAULT = 1, /* no option specified */
	CTE_MATERIALIZE_ALWAYS = 2,  /* MATERIALIZED */
	CTE_MATERIALIZE_NEVER = 3    /* NOT MATERIALIZED */
};

} // namespace duckdb


namespace duckdb {

class SelectStatement;

struct CommonTableExpressionInfo {
	vector<string> aliases;
	unique_ptr<SelectStatement> query;
	CTEMaterialize materialized = CTEMaterialize::CTE_MATERIALIZE_DEFAULT;

	void Serialize(Serializer &serializer) const;
	static unique_ptr<CommonTableExpressionInfo> Deserialize(Deserializer &deserializer);
	unique_ptr<CommonTableExpressionInfo> Copy();
};

} // namespace duckdb




namespace duckdb {

class Deserializer;
class Serializer;

enum class QueryNodeType : uint8_t {
	SELECT_NODE = 1,
	SET_OPERATION_NODE = 2,
	BOUND_SUBQUERY_NODE = 3,
	RECURSIVE_CTE_NODE = 4,
	CTE_NODE = 5
};

struct CommonTableExpressionInfo;

class CommonTableExpressionMap {
public:
	CommonTableExpressionMap();

	InsertionOrderPreservingMap<unique_ptr<CommonTableExpressionInfo>> map;

public:
	string ToString() const;
	CommonTableExpressionMap Copy() const;

	void Serialize(Serializer &serializer) const;
	// static void Deserialize(Deserializer &deserializer, CommonTableExpressionMap &ret);
	static CommonTableExpressionMap Deserialize(Deserializer &deserializer);
};

class QueryNode {
public:
	explicit QueryNode(QueryNodeType type) : type(type) {
	}
	virtual ~QueryNode() {
	}

	//! The type of the query node, either SetOperation or Select
	QueryNodeType type;
	//! The set of result modifiers associated with this query node
	vector<unique_ptr<ResultModifier>> modifiers;
	//! CTEs (used by SelectNode and SetOperationNode)
	CommonTableExpressionMap cte_map;

	virtual const vector<unique_ptr<ParsedExpression>> &GetSelectList() const = 0;

public:
	//! Convert the query node to a string
	virtual string ToString() const = 0;

	virtual bool Equals(const QueryNode *other) const;

	//! Create a copy of this QueryNode
	virtual unique_ptr<QueryNode> Copy() const = 0;

	string ResultModifiersToString() const;

	//! Adds a distinct modifier to the query node
	void AddDistinct();

	virtual void Serialize(Serializer &serializer) const;
	static unique_ptr<QueryNode> Deserialize(Deserializer &deserializer);

protected:
	//! Copy base QueryNode properties from another expression to this one,
	//! used in Copy method
	void CopyProperties(QueryNode &other) const;

public:
	template <class TARGET>
	TARGET &Cast() {
		if (type != TARGET::TYPE) {
			throw InternalException("Failed to cast query node to type - query node type mismatch");
		}
		return reinterpret_cast<TARGET &>(*this);
	}

	template <class TARGET>
	const TARGET &Cast() const {
		if (type != TARGET::TYPE) {
			throw InternalException("Failed to cast query node to type - query node type mismatch");
		}
		return reinterpret_cast<const TARGET &>(*this);
	}
};

} // namespace duckdb


//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/parser/tableref/delimgetref.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

class DelimGetRef : public TableRef {

public:
	explicit DelimGetRef(const vector<LogicalType> &types_p) : TableRef(TableReferenceType::DELIM_GET), types(types_p) {
		for (idx_t i = 0; i < types.size(); i++) {
			string column_name = "__internal_delim_get_" + std::to_string(i);
			internal_aliases.emplace_back(column_name);
		}
	}

	vector<string> internal_aliases;
	vector<LogicalType> types;

public:
	string ToString() const override;
	bool Equals(const TableRef &other_p) const override;

	unique_ptr<TableRef> Copy() override;

	void Serialize(Serializer &serializer) const override;
	static unique_ptr<TableRef> Deserialize(Deserializer &source);
};
} // namespace duckdb





//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/expression/bound_columnref_expression.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

//! A BoundColumnRef expression represents a ColumnRef expression that was bound to an actual table and column index. It
//! is not yet executable, however. The ColumnBindingResolver transforms the BoundColumnRefExpressions into
//! BoundExpressions, which refer to indexes into the physical chunks that pass through the executor.
class BoundColumnRefExpression : public Expression {
public:
	static constexpr const ExpressionClass TYPE = ExpressionClass::BOUND_COLUMN_REF;

public:
	BoundColumnRefExpression(LogicalType type, ColumnBinding binding, idx_t depth = 0);
	BoundColumnRefExpression(string alias, LogicalType type, ColumnBinding binding, idx_t depth = 0);

	//! Column index set by the binder, used to generate the final BoundExpression
	ColumnBinding binding;
	//! The subquery depth (i.e. depth 0 = current query, depth 1 = parent query, depth 2 = parent of parent, etc...).
	//! This is only non-zero for correlated expressions inside subqueries.
	idx_t depth;

public:
	bool IsScalar() const override {
		return false;
	}
	bool IsFoldable() const override {
		return false;
	}

	string ToString() const override;
	string GetName() const override;

	bool Equals(const BaseExpression &other) const override;
	hash_t Hash() const override;

	unique_ptr<Expression> Copy() const override;

	void Serialize(Serializer &serializer) const override;
	static unique_ptr<Expression> Deserialize(Deserializer &deserializer);
};
} // namespace duckdb



//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/tableref/bound_delimgetref.hpp
//
//
//===----------------------------------------------------------------------===//



//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/bound_tableref.hpp
//
//
//===----------------------------------------------------------------------===//







namespace duckdb {

class BoundTableRef {
public:
	explicit BoundTableRef(TableReferenceType type) : type(type) {
	}
	virtual ~BoundTableRef() {
	}

	//! The type of table reference
	TableReferenceType type;
	//! The sample options (if any)
	unique_ptr<SampleOptions> sample;

public:
	template <class TARGET>
	TARGET &Cast() {
		if (type != TARGET::TYPE) {
			throw InternalException("Failed to cast bound table ref to type - table ref type mismatch");
		}
		return reinterpret_cast<TARGET &>(*this);
	}

	template <class TARGET>
	const TARGET &Cast() const {
		if (type != TARGET::TYPE) {
			throw InternalException("Failed to cast bound table ref to type - table ref type mismatch");
		}
		return reinterpret_cast<const TARGET &>(*this);
	}
};
} // namespace duckdb


namespace duckdb {

class BoundDelimGetRef : public BoundTableRef {
public:
	static constexpr const TableReferenceType TYPE = TableReferenceType::DELIM_GET;

public:
	BoundDelimGetRef(idx_t bind_index, const vector<LogicalType> &column_types_p)
	    : BoundTableRef(TableReferenceType::DELIM_GET), bind_index(bind_index), column_types(column_types_p) {
	}
	idx_t bind_index;
	vector<LogicalType> column_types;
};
} // namespace duckdb


namespace duckdb {
class BoundResultModifier;
class BoundSelectNode;
class ClientContext;
class ExpressionBinder;
class LimitModifier;
class OrderBinder;
class TableCatalogEntry;
class ViewCatalogEntry;
class TableMacroCatalogEntry;
class UpdateSetInfo;
class LogicalProjection;
class LogicalVacuum;

class ColumnList;
class ExternalDependency;
class TableFunction;
class TableStorageInfo;
class BoundConstraint;

struct CreateInfo;
struct BoundCreateTableInfo;
struct BoundCreateFunctionInfo;
struct CommonTableExpressionInfo;
struct BoundParameterMap;
struct BoundPragmaInfo;
struct BoundLimitNode;
struct PivotColumnEntry;
struct UnpivotEntry;

enum class BindingMode : uint8_t { STANDARD_BINDING, EXTRACT_NAMES, EXTRACT_REPLACEMENT_SCANS };
enum class BinderType : uint8_t { REGULAR_BINDER, VIEW_BINDER };

struct CorrelatedColumnInfo {
	ColumnBinding binding;
	LogicalType type;
	string name;
	idx_t depth;

	// NOLINTNEXTLINE - work-around bug in clang-tidy
	CorrelatedColumnInfo(ColumnBinding binding, LogicalType type_p, string name_p, idx_t depth)
	    : binding(binding), type(std::move(type_p)), name(std::move(name_p)), depth(depth) {
	}
	explicit CorrelatedColumnInfo(BoundColumnRefExpression &expr)
	    : CorrelatedColumnInfo(expr.binding, expr.return_type, expr.GetName(), expr.depth) {
	}

	bool operator==(const CorrelatedColumnInfo &rhs) const {
		return binding == rhs.binding;
	}
};

//! Bind the parsed query tree to the actual columns present in the catalog.
/*!
  The binder is responsible for binding tables and columns to actual physical
  tables and columns in the catalog. In the process, it also resolves types of
  all expressions.
*/
class Binder : public enable_shared_from_this<Binder> {
	friend class ExpressionBinder;
	friend class RecursiveDependentJoinPlanner;

public:
	DUCKDB_API static shared_ptr<Binder> CreateBinder(ClientContext &context, optional_ptr<Binder> parent = nullptr,
	                                                  BinderType binder_type = BinderType::REGULAR_BINDER);

	//! The client context
	ClientContext &context;
	//! A mapping of names to common table expressions
	case_insensitive_map_t<reference<CommonTableExpressionInfo>> CTE_bindings; // NOLINT
	//! The CTEs that have already been bound
	reference_set_t<CommonTableExpressionInfo> bound_ctes;
	//! The bind context
	BindContext bind_context;
	//! The set of correlated columns bound by this binder (FIXME: this should probably be an unordered_set and not a
	//! vector)
	vector<CorrelatedColumnInfo> correlated_columns;
	//! The set of parameter expressions bound by this binder
	optional_ptr<BoundParameterMap> parameters;
	//! The alias for the currently processing subquery, if it exists
	string alias;
	//! Macro parameter bindings (if any)
	optional_ptr<DummyBinding> macro_binding;
	//! The intermediate lambda bindings to bind nested lambdas (if any)
	optional_ptr<vector<DummyBinding>> lambda_bindings;

	unordered_map<idx_t, LogicalOperator *> recursive_ctes;

public:
	DUCKDB_API BoundStatement Bind(SQLStatement &statement);
	DUCKDB_API BoundStatement Bind(QueryNode &node);

	unique_ptr<BoundCreateTableInfo> BindCreateTableInfo(unique_ptr<CreateInfo> info);
	unique_ptr<BoundCreateTableInfo> BindCreateTableInfo(unique_ptr<CreateInfo> info, SchemaCatalogEntry &schema);
	unique_ptr<BoundCreateTableInfo> BindCreateTableInfo(unique_ptr<CreateInfo> info, SchemaCatalogEntry &schema,
	                                                     vector<unique_ptr<Expression>> &bound_defaults);
	static unique_ptr<BoundCreateTableInfo> BindCreateTableCheckpoint(unique_ptr<CreateInfo> info,
	                                                                  SchemaCatalogEntry &schema);
	static vector<unique_ptr<BoundConstraint>> BindConstraints(ClientContext &context,
	                                                           const vector<unique_ptr<Constraint>> &constraints,
	                                                           const string &table_name, const ColumnList &columns);
	vector<unique_ptr<BoundConstraint>> BindConstraints(const vector<unique_ptr<Constraint>> &constraints,
	                                                    const string &table_name, const ColumnList &columns);
	vector<unique_ptr<BoundConstraint>> BindConstraints(const TableCatalogEntry &table);
	vector<unique_ptr<BoundConstraint>> BindNewConstraints(vector<unique_ptr<Constraint>> &constraints,
	                                                       const string &table_name, const ColumnList &columns);

	void SetCatalogLookupCallback(catalog_entry_callback_t callback);
	void BindCreateViewInfo(CreateViewInfo &base);
	SchemaCatalogEntry &BindSchema(CreateInfo &info);
	SchemaCatalogEntry &BindCreateFunctionInfo(CreateInfo &info);

	//! Check usage, and cast named parameters to their types
	static void BindNamedParameters(named_parameter_type_map_t &types, named_parameter_map_t &values,
	                                QueryErrorContext &error_context, string &func_name);
	unique_ptr<BoundPragmaInfo> BindPragma(PragmaInfo &info, QueryErrorContext error_context);

	unique_ptr<BoundTableRef> Bind(TableRef &ref);
	unique_ptr<LogicalOperator> CreatePlan(BoundTableRef &ref);

	//! Generates an unused index for a table
	idx_t GenerateTableIndex();

	optional_ptr<CatalogEntry> GetCatalogEntry(CatalogType type, const string &catalog, const string &schema,
	                                           const string &name, OnEntryNotFound on_entry_not_found,
	                                           QueryErrorContext &error_context);

	//! Add a common table expression to the binder
	void AddCTE(const string &name, CommonTableExpressionInfo &cte);
	//! Find all candidate common table expression by name; returns empty vector if none exists
	vector<reference<CommonTableExpressionInfo>> FindCTE(const string &name, bool skip = false);

	bool CTEIsAlreadyBound(CommonTableExpressionInfo &cte);

	//! Add the view to the set of currently bound views - used for detecting recursive view definitions
	void AddBoundView(ViewCatalogEntry &view);

	void PushExpressionBinder(ExpressionBinder &binder);
	void PopExpressionBinder();
	void SetActiveBinder(ExpressionBinder &binder);
	ExpressionBinder &GetActiveBinder();
	bool HasActiveBinder();

	vector<reference<ExpressionBinder>> &GetActiveBinders();

	void MergeCorrelatedColumns(vector<CorrelatedColumnInfo> &other);
	//! Add a correlated column to this binder (if it does not exist)
	void AddCorrelatedColumn(const CorrelatedColumnInfo &info);

	unique_ptr<LogicalOperator> BindUpdateSet(LogicalOperator &op, unique_ptr<LogicalOperator> root,
	                                          UpdateSetInfo &set_info, TableCatalogEntry &table,
	                                          vector<PhysicalIndex> &columns);
	void BindDoUpdateSetExpressions(const string &table_alias, LogicalInsert &insert, UpdateSetInfo &set_info,
	                                TableCatalogEntry &table, TableStorageInfo &storage_info);
	void BindOnConflictClause(LogicalInsert &insert, TableCatalogEntry &table, InsertStatement &stmt);

	void BindVacuumTable(LogicalVacuum &vacuum, unique_ptr<LogicalOperator> &root);

	static void BindSchemaOrCatalog(ClientContext &context, string &catalog, string &schema);
	void BindLogicalType(LogicalType &type, optional_ptr<Catalog> catalog = nullptr,
	                     const string &schema = INVALID_SCHEMA);

	bool HasMatchingBinding(const string &table_name, const string &column_name, ErrorData &error);
	bool HasMatchingBinding(const string &schema_name, const string &table_name, const string &column_name,
	                        ErrorData &error);
	bool HasMatchingBinding(const string &catalog_name, const string &schema_name, const string &table_name,
	                        const string &column_name, ErrorData &error);

	void SetBindingMode(BindingMode mode);
	BindingMode GetBindingMode();
	void AddTableName(string table_name);
	void AddReplacementScan(const string &table_name, unique_ptr<TableRef> replacement);
	const unordered_set<string> &GetTableNames();
	case_insensitive_map_t<unique_ptr<TableRef>> &GetReplacementScans();
	optional_ptr<SQLStatement> GetRootStatement() {
		return root_statement;
	}

	void SetCanContainNulls(bool can_contain_nulls);
	void SetAlwaysRequireRebind();

	StatementProperties &GetStatementProperties();

private:
	//! The parent binder (if any)
	shared_ptr<Binder> parent;
	//! The vector of active binders
	vector<reference<ExpressionBinder>> active_binders;
	//! The count of bound_tables
	idx_t bound_tables;
	//! Whether or not the binder has any unplanned dependent joins that still need to be planned/flattened
	bool has_unplanned_dependent_joins = false;
	//! Whether or not outside dependent joins have been planned and flattened
	bool is_outside_flattened = true;
	//! What kind of node we are binding using this binder
	BinderType binder_type = BinderType::REGULAR_BINDER;
	//! Whether or not the binder can contain NULLs as the root of expressions
	bool can_contain_nulls = false;
	//! The root statement of the query that is currently being parsed
	optional_ptr<SQLStatement> root_statement;
	//! Binding mode
	BindingMode mode = BindingMode::STANDARD_BINDING;
	//! Table names extracted for BindingMode::EXTRACT_NAMES
	unordered_set<string> table_names;
	//! Replacement Scans extracted for BindingMode::EXTRACT_REPLACEMENT_SCANS
	case_insensitive_map_t<unique_ptr<TableRef>> replacement_scans;
	//! The set of bound views
	reference_set_t<ViewCatalogEntry> bound_views;
	//! Used to retrieve CatalogEntry's
	CatalogEntryRetriever entry_retriever;
	//! Unnamed subquery index
	idx_t unnamed_subquery_index = 1;
	//! Statement properties
	StatementProperties prop;

private:
	//! Get the root binder (binder with no parent)
	Binder &GetRootBinder();
	//! Determine the depth of the binder
	idx_t GetBinderDepth() const;
	//! Bind the expressions of generated columns to check for errors
	void BindGeneratedColumns(BoundCreateTableInfo &info);
	//! Bind the default values of the columns of a table
	void BindDefaultValues(const ColumnList &columns, vector<unique_ptr<Expression>> &bound_defaults);
	//! Bind a limit value (LIMIT or OFFSET)
	BoundLimitNode BindLimitValue(OrderBinder &order_binder, unique_ptr<ParsedExpression> limit_val, bool is_percentage,
	                              bool is_offset);

	//! Move correlated expressions from the child binder to this binder
	void MoveCorrelatedExpressions(Binder &other);

	//! Tries to bind the table name with replacement scans
	unique_ptr<BoundTableRef> BindWithReplacementScan(ClientContext &context, BaseTableRef &ref);

	template <class T>
	BoundStatement BindWithCTE(T &statement);
	BoundStatement Bind(SelectStatement &stmt);
	BoundStatement Bind(InsertStatement &stmt);
	BoundStatement Bind(CopyStatement &stmt, CopyToType copy_to_type);
	BoundStatement Bind(DeleteStatement &stmt);
	BoundStatement Bind(UpdateStatement &stmt);
	BoundStatement Bind(CreateStatement &stmt);
	BoundStatement Bind(DropStatement &stmt);
	BoundStatement Bind(AlterStatement &stmt);
	BoundStatement Bind(PrepareStatement &stmt);
	BoundStatement Bind(ExecuteStatement &stmt);
	BoundStatement Bind(TransactionStatement &stmt);
	BoundStatement Bind(PragmaStatement &stmt);
	BoundStatement Bind(ExplainStatement &stmt);
	BoundStatement Bind(VacuumStatement &stmt);
	BoundStatement Bind(RelationStatement &stmt);
	BoundStatement Bind(CallStatement &stmt);
	BoundStatement Bind(ExportStatement &stmt);
	BoundStatement Bind(ExtensionStatement &stmt);
	BoundStatement Bind(SetStatement &stmt);
	BoundStatement Bind(SetVariableStatement &stmt);
	BoundStatement Bind(ResetVariableStatement &stmt);
	BoundStatement Bind(LoadStatement &stmt);
	BoundStatement Bind(LogicalPlanStatement &stmt);
	BoundStatement Bind(AttachStatement &stmt);
	BoundStatement Bind(DetachStatement &stmt);
	BoundStatement Bind(CopyDatabaseStatement &stmt);
	BoundStatement Bind(UpdateExtensionsStatement &stmt);

	BoundStatement BindReturning(vector<unique_ptr<ParsedExpression>> returning_list, TableCatalogEntry &table,
	                             const string &alias, idx_t update_table_index,
	                             unique_ptr<LogicalOperator> child_operator, BoundStatement result);

	unique_ptr<QueryNode> BindTableMacro(FunctionExpression &function, TableMacroCatalogEntry &macro_func, idx_t depth);

	unique_ptr<BoundCTENode> BindMaterializedCTE(CommonTableExpressionMap &cte_map);
	unique_ptr<BoundCTENode> BindCTE(CTENode &statement);
	//! Materializes CTEs if this is expected to improve performance
	bool OptimizeCTEs(QueryNode &node);

	unique_ptr<BoundQueryNode> BindNode(SelectNode &node);
	unique_ptr<BoundQueryNode> BindNode(SetOperationNode &node);
	unique_ptr<BoundQueryNode> BindNode(RecursiveCTENode &node);
	unique_ptr<BoundQueryNode> BindNode(CTENode &node);
	unique_ptr<BoundQueryNode> BindNode(QueryNode &node);

	unique_ptr<LogicalOperator> VisitQueryNode(BoundQueryNode &node, unique_ptr<LogicalOperator> root);
	unique_ptr<LogicalOperator> CreatePlan(BoundRecursiveCTENode &node);
	unique_ptr<LogicalOperator> CreatePlan(BoundCTENode &node);
	unique_ptr<LogicalOperator> CreatePlan(BoundCTENode &node, unique_ptr<LogicalOperator> base);
	unique_ptr<LogicalOperator> CreatePlan(BoundSelectNode &statement);
	unique_ptr<LogicalOperator> CreatePlan(BoundSetOperationNode &node);
	unique_ptr<LogicalOperator> CreatePlan(BoundQueryNode &node);

	unique_ptr<BoundTableRef> BindJoin(Binder &parent, TableRef &ref);
	unique_ptr<BoundTableRef> Bind(BaseTableRef &ref);
	unique_ptr<BoundTableRef> Bind(JoinRef &ref);
	unique_ptr<BoundTableRef> Bind(SubqueryRef &ref, optional_ptr<CommonTableExpressionInfo> cte = nullptr);
	unique_ptr<BoundTableRef> Bind(TableFunctionRef &ref);
	unique_ptr<BoundTableRef> Bind(EmptyTableRef &ref);
	unique_ptr<BoundTableRef> Bind(DelimGetRef &ref);
	unique_ptr<BoundTableRef> Bind(ExpressionListRef &ref);
	unique_ptr<BoundTableRef> Bind(ColumnDataRef &ref);
	unique_ptr<BoundTableRef> Bind(PivotRef &expr);
	unique_ptr<BoundTableRef> Bind(ShowRef &ref);

	unique_ptr<SelectNode> BindPivot(PivotRef &expr, vector<unique_ptr<ParsedExpression>> all_columns);
	unique_ptr<SelectNode> BindUnpivot(Binder &child_binder, PivotRef &expr,
	                                   vector<unique_ptr<ParsedExpression>> all_columns,
	                                   unique_ptr<ParsedExpression> &where_clause);
	unique_ptr<BoundTableRef> BindBoundPivot(PivotRef &expr);
	void ExtractUnpivotEntries(Binder &child_binder, PivotColumnEntry &entry, vector<UnpivotEntry> &unpivot_entries);
	void ExtractUnpivotColumnName(ParsedExpression &expr, vector<string> &result);

	bool BindTableFunctionParameters(TableFunctionCatalogEntry &table_function,
	                                 vector<unique_ptr<ParsedExpression>> &expressions, vector<LogicalType> &arguments,
	                                 vector<Value> &parameters, named_parameter_map_t &named_parameters,
	                                 unique_ptr<BoundSubqueryRef> &subquery, ErrorData &error);
	void BindTableInTableOutFunction(vector<unique_ptr<ParsedExpression>> &expressions,
	                                 unique_ptr<BoundSubqueryRef> &subquery);
	unique_ptr<LogicalOperator> BindTableFunction(TableFunction &function, vector<Value> parameters);
	unique_ptr<LogicalOperator> BindTableFunctionInternal(TableFunction &table_function, const TableFunctionRef &ref,
	                                                      vector<Value> parameters,
	                                                      named_parameter_map_t named_parameters,
	                                                      vector<LogicalType> input_table_types,
	                                                      vector<string> input_table_names);

	unique_ptr<LogicalOperator> CreatePlan(BoundBaseTableRef &ref);
	unique_ptr<LogicalOperator> CreatePlan(BoundJoinRef &ref);
	unique_ptr<LogicalOperator> CreatePlan(BoundSubqueryRef &ref);
	unique_ptr<LogicalOperator> CreatePlan(BoundTableFunction &ref);
	unique_ptr<LogicalOperator> CreatePlan(BoundEmptyTableRef &ref);
	unique_ptr<LogicalOperator> CreatePlan(BoundExpressionListRef &ref);
	unique_ptr<LogicalOperator> CreatePlan(BoundColumnDataRef &ref);
	unique_ptr<LogicalOperator> CreatePlan(BoundCTERef &ref);
	unique_ptr<LogicalOperator> CreatePlan(BoundPivotRef &ref);
	unique_ptr<LogicalOperator> CreatePlan(BoundDelimGetRef &ref);

	BoundStatement BindCopyTo(CopyStatement &stmt, CopyToType copy_to_type);
	BoundStatement BindCopyFrom(CopyStatement &stmt);

	void PrepareModifiers(OrderBinder &order_binder, QueryNode &statement, BoundQueryNode &result);
	void BindModifiers(BoundQueryNode &result, idx_t table_index, const vector<string> &names,
	                   const vector<LogicalType> &sql_types, const SelectBindState &bind_state);

	unique_ptr<BoundResultModifier> BindLimit(OrderBinder &order_binder, LimitModifier &limit_mod);
	unique_ptr<BoundResultModifier> BindLimitPercent(OrderBinder &order_binder, LimitPercentModifier &limit_mod);
	unique_ptr<Expression> BindOrderExpression(OrderBinder &order_binder, unique_ptr<ParsedExpression> expr);

	unique_ptr<LogicalOperator> PlanFilter(unique_ptr<Expression> condition, unique_ptr<LogicalOperator> root);

	void PlanSubqueries(unique_ptr<Expression> &expr, unique_ptr<LogicalOperator> &root);
	unique_ptr<Expression> PlanSubquery(BoundSubqueryExpression &expr, unique_ptr<LogicalOperator> &root);
	unique_ptr<LogicalOperator> PlanLateralJoin(unique_ptr<LogicalOperator> left, unique_ptr<LogicalOperator> right,
	                                            vector<CorrelatedColumnInfo> &correlated_columns,
	                                            JoinType join_type = JoinType::INNER,
	                                            unique_ptr<Expression> condition = nullptr);

	unique_ptr<LogicalOperator> CastLogicalOperatorToTypes(vector<LogicalType> &source_types,
	                                                       vector<LogicalType> &target_types,
	                                                       unique_ptr<LogicalOperator> op);

	string FindBinding(const string &using_column, const string &join_side);
	bool TryFindBinding(const string &using_column, const string &join_side, string &result);

	void AddUsingBindingSet(unique_ptr<UsingColumnSet> set);
	string RetrieveUsingBinding(Binder &current_binder, optional_ptr<UsingColumnSet> current_set,
	                            const string &column_name, const string &join_side);

	void AddCTEMap(CommonTableExpressionMap &cte_map);

	void ExpandStarExpressions(vector<unique_ptr<ParsedExpression>> &select_list,
	                           vector<unique_ptr<ParsedExpression>> &new_select_list);
	void ExpandStarExpression(unique_ptr<ParsedExpression> expr, vector<unique_ptr<ParsedExpression>> &new_select_list);
	bool FindStarExpression(unique_ptr<ParsedExpression> &expr, StarExpression **star, bool is_root, bool in_columns);
	void ReplaceUnpackedStarExpression(unique_ptr<ParsedExpression> &expr,
	                                   vector<unique_ptr<ParsedExpression>> &replacements);
	void ReplaceStarExpression(unique_ptr<ParsedExpression> &expr, unique_ptr<ParsedExpression> &replacement);
	void BindWhereStarExpression(unique_ptr<ParsedExpression> &expr);

	//! If only a schema name is provided (e.g. "a.b") then figure out if "a" is a schema or a catalog name
	void BindSchemaOrCatalog(string &catalog_name, string &schema_name);
	const string BindCatalog(string &catalog_name);
	SchemaCatalogEntry &BindCreateSchema(CreateInfo &info);

	unique_ptr<BoundQueryNode> BindSelectNode(SelectNode &statement, unique_ptr<BoundTableRef> from_table);

	unique_ptr<LogicalOperator> BindCopyDatabaseSchema(Catalog &source_catalog, const string &target_database_name);
	unique_ptr<LogicalOperator> BindCopyDatabaseData(Catalog &source_catalog, const string &target_database_name);

	unique_ptr<BoundTableRef> BindShowQuery(ShowRef &ref);
	unique_ptr<BoundTableRef> BindShowTable(ShowRef &ref);
	unique_ptr<BoundTableRef> BindSummarize(ShowRef &ref);

	unique_ptr<LogicalOperator> UnionOperators(vector<unique_ptr<LogicalOperator>> nodes);

private:
	Binder(ClientContext &context, shared_ptr<Binder> parent, BinderType binder_type);
};

} // namespace duckdb


namespace duckdb {

//! The OperatorExtensionInfo holds static information relevant to the operator extension
struct OperatorExtensionInfo {
	virtual ~OperatorExtensionInfo() {
	}
};

typedef BoundStatement (*bind_function_t)(ClientContext &context, Binder &binder, OperatorExtensionInfo *info,
                                          SQLStatement &statement);

// forward declaration to avoid circular reference
struct LogicalExtensionOperator;

class OperatorExtension {
public:
	bind_function_t Bind; // NOLINT: backwards compatibility

	//! Additional info passed to the CreatePlan & Bind functions
	shared_ptr<OperatorExtensionInfo> operator_info;

	virtual std::string GetName() = 0;
	virtual unique_ptr<LogicalExtensionOperator> Deserialize(Deserializer &deserializer) = 0;

	virtual ~OperatorExtension() {
	}
};

} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/storage/compression/bitpacking.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

enum class BitpackingMode : uint8_t { INVALID, AUTO, CONSTANT, CONSTANT_DELTA, DELTA_FOR, FOR };

BitpackingMode BitpackingModeFromString(const string &str);
string BitpackingModeToString(const BitpackingMode &mode);

} // namespace duckdb


//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/index/index_type_set.hpp
//
//
//===----------------------------------------------------------------------===//



//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/index/index_type.hpp
//
//
//===----------------------------------------------------------------------===//










namespace duckdb {

class BoundIndex;
enum class IndexConstraintType : uint8_t;
class Expression;
class TableIOManager;
class AttachedDatabase;
struct IndexStorageInfo;

struct CreateIndexInput {
	TableIOManager &table_io_manager;
	AttachedDatabase &db;
	IndexConstraintType constraint_type;
	const string &name;
	const vector<column_t> &column_ids;
	const vector<unique_ptr<Expression>> &unbound_expressions;
	const IndexStorageInfo &storage_info;
	const case_insensitive_map_t<Value> &options;

	CreateIndexInput(TableIOManager &table_io_manager, AttachedDatabase &db, IndexConstraintType constraint_type,
	                 const string &name, const vector<column_t> &column_ids,
	                 const vector<unique_ptr<Expression>> &unbound_expressions, const IndexStorageInfo &storage_info,
	                 const case_insensitive_map_t<Value> &options)
	    : table_io_manager(table_io_manager), db(db), constraint_type(constraint_type), name(name),
	      column_ids(column_ids), unbound_expressions(unbound_expressions), storage_info(storage_info),
	      options(options) {};
};

typedef unique_ptr<BoundIndex> (*index_create_function_t)(CreateIndexInput &input);
//! A index "type"
class IndexType {
public:
	// The name of the index type
	string name;

	// Callbacks
	index_create_function_t create_instance;
};

} // namespace duckdb






namespace duckdb {

class IndexTypeSet {
	mutex lock;
	case_insensitive_map_t<IndexType> functions;

public:
	IndexTypeSet();
	DUCKDB_API optional_ptr<IndexType> FindByName(const string &name);
	DUCKDB_API void RegisterIndexType(const IndexType &index_type);
};

} // namespace duckdb


namespace duckdb {

class BufferManager;
class BufferPool;
class CastFunctionSet;
class CollationBinding;
class ClientContext;
class ErrorManager;
class CompressionFunction;
class TableFunctionRef;
class OperatorExtension;
class StorageExtension;
class ExtensionCallback;
class SecretManager;
class CompressionInfo;
class EncryptionUtil;

struct CompressionFunctionSet;
struct DBConfig;

enum class CheckpointAbort : uint8_t {
	NO_ABORT = 0,
	DEBUG_ABORT_BEFORE_TRUNCATE = 1,
	DEBUG_ABORT_BEFORE_HEADER = 2,
	DEBUG_ABORT_AFTER_FREE_LIST_WRITE = 3
};

typedef void (*set_global_function_t)(DatabaseInstance *db, DBConfig &config, const Value &parameter);
typedef void (*set_local_function_t)(ClientContext &context, const Value &parameter);
typedef void (*reset_global_function_t)(DatabaseInstance *db, DBConfig &config);
typedef void (*reset_local_function_t)(ClientContext &context);
typedef Value (*get_setting_function_t)(const ClientContext &context);

struct ConfigurationOption {
	const char *name;
	const char *description;
	LogicalTypeId parameter_type;
	set_global_function_t set_global;
	set_local_function_t set_local;
	reset_global_function_t reset_global;
	reset_local_function_t reset_local;
	get_setting_function_t get_setting;
};

typedef void (*set_option_callback_t)(ClientContext &context, SetScope scope, Value &parameter);

struct ExtensionOption {
	// NOLINTNEXTLINE: work around bug in clang-tidy
	ExtensionOption(string description_p, LogicalType type_p, set_option_callback_t set_function_p,
	                Value default_value_p)
	    : description(std::move(description_p)), type(std::move(type_p)), set_function(set_function_p),
	      default_value(std::move(default_value_p)) {
	}

	string description;
	LogicalType type;
	set_option_callback_t set_function;
	Value default_value;
};

class SerializationCompatibility {
public:
	static SerializationCompatibility FromString(const string &input);
	static SerializationCompatibility Default();
	static SerializationCompatibility Latest();

public:
	bool Compare(idx_t property_version) const;

public:
	//! The user provided version
	string duckdb_version;
	//! The max version that should be serialized
	idx_t serialization_version;
	//! Whether this was set by a manual SET/PRAGMA or default
	bool manually_set;

protected:
	SerializationCompatibility() = default;
};

struct DBConfigOptions {
	//! Database file path. May be empty for in-memory mode
	string database_path;
	//! Database type. If empty, automatically extracted from `database_path`, where a `type:path` syntax is expected
	string database_type;
	//! Access mode of the database (AUTOMATIC, READ_ONLY or READ_WRITE)
	AccessMode access_mode = AccessMode::AUTOMATIC;
	//! Checkpoint when WAL reaches this size (default: 16MB)
	idx_t checkpoint_wal_size = 1 << 24;
	//! Whether or not to use Direct IO, bypassing operating system buffers
	bool use_direct_io = false;
	//! Whether extensions should be loaded on start-up
	bool load_extensions = true;
#ifdef DUCKDB_EXTENSION_AUTOLOAD_DEFAULT
	//! Whether known extensions are allowed to be automatically loaded when a query depends on them
	bool autoload_known_extensions = DUCKDB_EXTENSION_AUTOLOAD_DEFAULT;
#else
	bool autoload_known_extensions = false;
#endif
#ifdef DUCKDB_EXTENSION_AUTOINSTALL_DEFAULT
	//! Whether known extensions are allowed to be automatically installed when a query depends on them
	bool autoinstall_known_extensions = DUCKDB_EXTENSION_AUTOINSTALL_DEFAULT;
#else
	bool autoinstall_known_extensions = false;
#endif
	//! Override for the default extension repository
	string custom_extension_repo = "";
	//! Override for the default autoload extension repository
	string autoinstall_extension_repo = "";
	//! The maximum memory used by the database system (in bytes). Default: 80% of System available memory
	idx_t maximum_memory = DConstants::INVALID_INDEX;
	//! The maximum size of the 'temp_directory' folder when set (in bytes). Default: 90% of available disk space.
	idx_t maximum_swap_space = DConstants::INVALID_INDEX;
	//! The maximum amount of CPU threads used by the database system. Default: all available.
	idx_t maximum_threads = DConstants::INVALID_INDEX;
	//! The number of external threads that work on DuckDB tasks. Default: 1.
	//! Must be smaller or equal to maximum_threads.
	idx_t external_threads = 1;
	//! Whether or not to create and use a temporary directory to store intermediates that do not fit in memory
	bool use_temporary_directory = true;
	//! Directory to store temporary structures that do not fit in memory
	string temporary_directory;
	//! Whether or not to invoke filesystem trim on free blocks after checkpoint. This will reclaim
	//! space for sparse files, on platforms that support it.
	bool trim_free_blocks = false;
	//! Record timestamps of buffer manager unpin() events. Usable by custom eviction policies.
	bool buffer_manager_track_eviction_timestamps = false;
	//! Whether or not to allow printing unredacted secrets
	bool allow_unredacted_secrets = false;
	//! The collation type of the database
	string collation = string();
	//! The order type used when none is specified (default: ASC)
	OrderType default_order_type = OrderType::ASCENDING;
	//! Null ordering used when none is specified (default: NULLS LAST)
	DefaultOrderByNullType default_null_order = DefaultOrderByNullType::NULLS_LAST;
	//! enable COPY and related commands
	bool enable_external_access = true;
	//! Whether or not object cache is used
	bool object_cache_enable = false;
	//! Whether or not the global http metadata cache is used
	bool http_metadata_cache_enable = false;
	//! HTTP Proxy config as 'hostname:port'
	string http_proxy;
	//! HTTP Proxy username for basic auth
	string http_proxy_username;
	//! HTTP Proxy password for basic auth
	string http_proxy_password;
	//! Force checkpoint when CHECKPOINT is called or on shutdown, even if no changes have been made
	bool force_checkpoint = false;
	//! Run a checkpoint on successful shutdown and delete the WAL, to leave only a single database file behind
	bool checkpoint_on_shutdown = true;
	//! Serialize the metadata on checkpoint with compatibility for a given DuckDB version.
	SerializationCompatibility serialization_compatibility = SerializationCompatibility::Default();
	//! Debug flag that decides when a checkpoing should be aborted. Only used for testing purposes.
	CheckpointAbort checkpoint_abort = CheckpointAbort::NO_ABORT;
	//! Initialize the database with the standard set of DuckDB functions
	//! You should probably not touch this unless you know what you are doing
	bool initialize_default_database = true;
	//! The set of disabled optimizers (default empty)
	set<OptimizerType> disabled_optimizers;
	//! Force a specific compression method to be used when checkpointing (if available)
	CompressionType force_compression = CompressionType::COMPRESSION_AUTO;
	//! Force a specific bitpacking mode to be used when using the bitpacking compression method
	BitpackingMode force_bitpacking_mode = BitpackingMode::AUTO;
	//! Debug setting for window aggregation mode: (window, combine, separate)
	WindowAggregationMode window_mode = WindowAggregationMode::WINDOW;
	//! Whether or not preserving insertion order should be preserved
	bool preserve_insertion_order = true;
	//! Whether Arrow Arrays use Large or Regular buffers
	ArrowOffsetSize arrow_offset_size = ArrowOffsetSize::REGULAR;
	//! Whether LISTs should produce Arrow ListViews
	bool arrow_use_list_view = false;
	//! Whenever a DuckDB type does not have a clear native or canonical extension match in Arrow, export the types
	//! with a duckdb.type_name extension name
	bool arrow_arrow_lossless_conversion = false;
	//! Whether when producing arrow objects we produce string_views or regular strings
	bool produce_arrow_string_views = false;
	//! Database configuration variables as controlled by SET
	case_insensitive_map_t<Value> set_variables;
	//! Database configuration variable default values;
	case_insensitive_map_t<Value> set_variable_defaults;
	//! Directory to store extension binaries in
	string extension_directory;
	//! Whether unsigned extensions should be loaded
	bool allow_unsigned_extensions = false;
	//! Whether community extensions should be loaded
	bool allow_community_extensions = true;
	//! Whether extensions with missing metadata should be loaded
	bool allow_extensions_metadata_mismatch = false;
	//! Enable emitting FSST Vectors
	bool enable_fsst_vectors = false;
	//! Enable VIEWs to create dependencies
	bool enable_view_dependencies = false;
	//! Enable macros to create dependencies
	bool enable_macro_dependencies = false;
	//! Start transactions immediately in all attached databases - instead of lazily when a database is referenced
	bool immediate_transaction_mode = false;
	//! Debug setting - how to initialize  blocks in the storage layer when allocating
	DebugInitialize debug_initialize = DebugInitialize::NO_INITIALIZE;
	//! The set of user-provided options
	case_insensitive_map_t<Value> user_options;
	//! The set of unrecognized (other) options
	case_insensitive_map_t<Value> unrecognized_options;
	//! Whether or not the configuration settings can be altered
	bool lock_configuration = false;
	//! Whether to print bindings when printing the plan (debug mode only)
	static bool debug_print_bindings; // NOLINT: debug setting
	//! The peak allocation threshold at which to flush the allocator after completing a task (1 << 27, ~128MB)
	idx_t allocator_flush_threshold = 134217728ULL;
	//! If bulk deallocation larger than this occurs, flush outstanding allocations (1 << 30, ~1GB)
	idx_t allocator_bulk_deallocation_flush_threshold = 536870912ULL;
	//! Whether the allocator background thread is enabled
	bool allocator_background_threads = false;
	//! DuckDB API surface
	string duckdb_api;
	//! Metadata from DuckDB callers
	string custom_user_agent;
	//! Use old implicit casting style (i.e. allow everything to be implicitly casted to VARCHAR)
	bool old_implicit_casting = false;
	//! The default block allocation size for new duckdb database files (new as-in, they do not yet exist).
	idx_t default_block_alloc_size = DUCKDB_BLOCK_ALLOC_SIZE;
	//!  Whether or not to abort if a serialization exception is thrown during WAL playback (when reading truncated WAL)
	bool abort_on_wal_failure = false;
	//! The index_scan_percentage sets a threshold for index scans.
	//! If fewer than MAX(index_scan_max_count, index_scan_percentage * total_row_count)
	//! rows match, we perform an index scan instead of a table scan.
	double index_scan_percentage = 0.001;
	//! The index_scan_max_count sets a threshold for index scans.
	//! If fewer than MAX(index_scan_max_count, index_scan_percentage * total_row_count)
	//! rows match, we perform an index scan instead of a table scan.
	idx_t index_scan_max_count = STANDARD_VECTOR_SIZE;
	//! The maximum number of schemas we will look through for "did you mean..." style errors in the catalog
	idx_t catalog_error_max_schemas = 100;
	//!  Whether or not to always write to the WAL file, even if this is not required
	bool debug_skip_checkpoint_on_commit = false;
	//! The maximum amount of vacuum tasks to schedule during a checkpoint
	idx_t max_vacuum_tasks = 100;

	bool operator==(const DBConfigOptions &other) const;
};

struct DBConfig {
	friend class DatabaseInstance;
	friend class StorageManager;

public:
	DUCKDB_API DBConfig();
	explicit DUCKDB_API DBConfig(bool read_only);
	DUCKDB_API DBConfig(const case_insensitive_map_t<Value> &config_dict, bool read_only);
	DUCKDB_API ~DBConfig();

	mutex config_lock;
	//! Replacement table scans are automatically attempted when a table name cannot be found in the schema
	vector<ReplacementScan> replacement_scans;

	//! Extra parameters that can be SET for loaded extensions
	case_insensitive_map_t<ExtensionOption> extension_parameters;
	//! The FileSystem to use, can be overwritten to allow for injecting custom file systems for testing purposes (e.g.
	//! RamFS or something similar)
	unique_ptr<FileSystem> file_system;
	//! Secret manager
	unique_ptr<SecretManager> secret_manager;
	//! The allocator used by the system
	unique_ptr<Allocator> allocator;
	//! Database configuration options
	DBConfigOptions options;
	//! Extensions made to the parser
	vector<ParserExtension> parser_extensions;
	//! Extensions made to the optimizer
	vector<OptimizerExtension> optimizer_extensions;
	//! Error manager
	unique_ptr<ErrorManager> error_manager;
	//! A reference to the (shared) default allocator (Allocator::DefaultAllocator)
	shared_ptr<Allocator> default_allocator;
	//! Extensions made to binder
	vector<unique_ptr<OperatorExtension>> operator_extensions;
	//! Extensions made to storage
	case_insensitive_map_t<duckdb::unique_ptr<StorageExtension>> storage_extensions;
	//! A buffer pool can be shared across multiple databases (if desired).
	shared_ptr<BufferPool> buffer_pool;
	//! Provide a custom buffer manager implementation (if desired).
	shared_ptr<BufferManager> buffer_manager;
	//! Set of callbacks that can be installed by extensions
	vector<unique_ptr<ExtensionCallback>> extension_callbacks;
	//! Encryption Util for OpenSSL
	shared_ptr<EncryptionUtil> encryption_util;

public:
	DUCKDB_API static DBConfig &GetConfig(ClientContext &context);
	DUCKDB_API static DBConfig &GetConfig(DatabaseInstance &db);
	DUCKDB_API static DBConfig &Get(AttachedDatabase &db);
	DUCKDB_API static const DBConfig &GetConfig(const ClientContext &context);
	DUCKDB_API static const DBConfig &GetConfig(const DatabaseInstance &db);
	DUCKDB_API static vector<ConfigurationOption> GetOptions();
	DUCKDB_API static idx_t GetOptionCount();
	DUCKDB_API static vector<string> GetOptionNames();
	DUCKDB_API static bool IsInMemoryDatabase(const char *database_path);

	DUCKDB_API void AddExtensionOption(const string &name, string description, LogicalType parameter,
	                                   const Value &default_value = Value(), set_option_callback_t function = nullptr);
	//! Fetch an option by index. Returns a pointer to the option, or nullptr if out of range
	DUCKDB_API static optional_ptr<const ConfigurationOption> GetOptionByIndex(idx_t index);
	//! Fetch an option by name. Returns a pointer to the option, or nullptr if none exists.
	DUCKDB_API static optional_ptr<const ConfigurationOption> GetOptionByName(const string &name);
	DUCKDB_API void SetOption(const ConfigurationOption &option, const Value &value);
	DUCKDB_API void SetOption(DatabaseInstance *db, const ConfigurationOption &option, const Value &value);
	DUCKDB_API void SetOptionByName(const string &name, const Value &value);
	DUCKDB_API void SetOptionsByName(const case_insensitive_map_t<Value> &values);
	DUCKDB_API void ResetOption(DatabaseInstance *db, const ConfigurationOption &option);
	DUCKDB_API void SetOption(const string &name, Value value);
	DUCKDB_API void ResetOption(const string &name);

	DUCKDB_API void CheckLock(const string &name);

	DUCKDB_API static idx_t ParseMemoryLimit(const string &arg);

	//! Returns the list of possible compression functions for the physical type.
	DUCKDB_API vector<reference<CompressionFunction>> GetCompressionFunctions(const PhysicalType physical_type);
	//! Returns the compression function matching the compression and physical type.
	DUCKDB_API optional_ptr<CompressionFunction> GetCompressionFunction(CompressionType type,
	                                                                    const PhysicalType physical_type);

	bool operator==(const DBConfig &other);
	bool operator!=(const DBConfig &other);

	DUCKDB_API CastFunctionSet &GetCastFunctions();
	DUCKDB_API CollationBinding &GetCollationBinding();
	DUCKDB_API IndexTypeSet &GetIndexTypes();
	static idx_t GetSystemMaxThreads(FileSystem &fs);
	static idx_t GetSystemAvailableMemory(FileSystem &fs);
	static optional_idx ParseMemoryLimitSlurm(const string &arg);
	void SetDefaultMaxMemory();
	void SetDefaultTempDirectory();

	OrderType ResolveOrder(OrderType order_type) const;
	OrderByNullType ResolveNullOrder(OrderType order_type, OrderByNullType null_type) const;
	const string UserAgent() const;

private:
	unique_ptr<CompressionFunctionSet> compression_functions;
	unique_ptr<CastFunctionSet> cast_functions;
	unique_ptr<CollationBinding> collation_bindings;
	unique_ptr<IndexTypeSet> index_types;
	bool is_user_config = true;
};

} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/main/valid_checker.hpp
//
//
//===----------------------------------------------------------------------===//







namespace duckdb {
class DatabaseInstance;
class MetaTransaction;

class ValidChecker {
public:
	ValidChecker();

	DUCKDB_API static ValidChecker &Get(DatabaseInstance &db);
	DUCKDB_API static ValidChecker &Get(MetaTransaction &transaction);

	DUCKDB_API void Invalidate(string error);
	DUCKDB_API bool IsInvalidated();
	DUCKDB_API string InvalidatedMessage();

	template <class T>
	static bool IsInvalidated(T &o) {
		return Get(o).IsInvalidated();
	}
	template <class T>
	static void Invalidate(T &o, string error) {
		Get(o).Invalidate(std::move(error));
	}

	template <class T>
	static string InvalidatedMessage(T &o) {
		return Get(o).InvalidatedMessage();
	}

private:
	//! Set to true if a fatal exception has occurred
	mutex invalidate_lock;
	atomic<bool> is_invalidated;
	string invalidated_msg;
};

} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/transaction/meta_transaction.hpp
//
//
//===----------------------------------------------------------------------===//












namespace duckdb {
class AttachedDatabase;
class ClientContext;
class Transaction;

//! The MetaTransaction manages multiple transactions for different attached databases
class MetaTransaction {
public:
	DUCKDB_API MetaTransaction(ClientContext &context, timestamp_t start_timestamp);

	ClientContext &context;
	//! The timestamp when the transaction started
	timestamp_t start_timestamp;
	//! The validity checker of the transaction
	ValidChecker transaction_validity;
	//! The active query number
	transaction_t active_query;

public:
	DUCKDB_API static MetaTransaction &Get(ClientContext &context);
	timestamp_t GetCurrentTransactionStartTimestamp() const {
		return start_timestamp;
	}

	Transaction &GetTransaction(AttachedDatabase &db);
	optional_ptr<Transaction> TryGetTransaction(AttachedDatabase &db);
	void RemoveTransaction(AttachedDatabase &db);

	ErrorData Commit();
	void Rollback();

	idx_t GetActiveQuery();
	void SetActiveQuery(transaction_t query_number);

	void SetReadOnly();
	bool IsReadOnly() const;
	void ModifyDatabase(AttachedDatabase &db);
	optional_ptr<AttachedDatabase> ModifiedDatabase() {
		return modified_database;
	}
	const vector<reference<AttachedDatabase>> &OpenedTransactions() const {
		return all_transactions;
	}

private:
	//! Lock to prevent all_transactions and transactions from getting out of sync
	mutex lock;
	//! The set of active transactions for each database
	reference_map_t<AttachedDatabase, reference<Transaction>> transactions;
	//! The set of transactions in order of when they were started
	vector<reference<AttachedDatabase>> all_transactions;
	//! The database we are modifying - we can only modify one database per transaction
	optional_ptr<AttachedDatabase> modified_database;
	//! Whether or not the meta transaction is marked as read only
	bool is_read_only;
};

} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/transaction/transaction_manager.hpp
//
//
//===----------------------------------------------------------------------===//










namespace duckdb {

class AttachedDatabase;
class ClientContext;
class Catalog;
struct ClientLockWrapper;
class DatabaseInstance;
class Transaction;

//! The Transaction Manager is responsible for creating and managing
//! transactions
class TransactionManager {
public:
	explicit TransactionManager(AttachedDatabase &db);
	virtual ~TransactionManager();

	//! Start a new transaction
	virtual Transaction &StartTransaction(ClientContext &context) = 0;
	//! Commit the given transaction. Returns a non-empty error message on failure.
	virtual ErrorData CommitTransaction(ClientContext &context, Transaction &transaction) = 0;
	//! Rollback the given transaction
	virtual void RollbackTransaction(Transaction &transaction) = 0;

	virtual void Checkpoint(ClientContext &context, bool force = false) = 0;

	static TransactionManager &Get(AttachedDatabase &db);

	virtual bool IsDuckTransactionManager() {
		return false;
	}

	AttachedDatabase &GetDB() {
		return db;
	}

protected:
	//! The attached database
	AttachedDatabase &db;
};

} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/main/database_manager.hpp
//
//
//===----------------------------------------------------------------------===//











//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/parser/parsed_data/attach_info.hpp
//
//
//===----------------------------------------------------------------------===//









namespace duckdb {

struct AttachInfo : public ParseInfo {
public:
	static constexpr const ParseInfoType TYPE = ParseInfoType::ATTACH_INFO;

public:
	AttachInfo() : ParseInfo(TYPE) {
	}

	//! The alias of the attached database
	string name;
	//! The path to the attached database
	string path;
	//! Set of (key, value) options
	unordered_map<string, Value> options;
	//! What to do on create conflict
	OnCreateConflict on_conflict = OnCreateConflict::ERROR_ON_CONFLICT;

public:
	//! Returns the block allocation size, which is the allocation size of blocks for this attached database file.
	//! Returns DConstants::INVALID_INDEX, if not provided. This is NOT the actual memory available on a block
	//! (block_size), even though the corresponding option we expose to the user is called "block_size".
	optional_idx GetBlockAllocSize() const;
	//! Copies this AttachInfo and returns an unique pointer to the new AttachInfo.
	unique_ptr<AttachInfo> Copy() const;
	string ToString() const;

	void Serialize(Serializer &serializer) const override;
	static unique_ptr<ParseInfo> Deserialize(Deserializer &deserializer);
};

} // namespace duckdb


namespace duckdb {
class AttachedDatabase;
class Catalog;
class CatalogSet;
class ClientContext;
class DatabaseInstance;
class TaskScheduler;
struct AttachOptions;

//! The DatabaseManager is a class that sits at the root of all attached databases
class DatabaseManager {
	friend class Catalog;

public:
	explicit DatabaseManager(DatabaseInstance &db);
	~DatabaseManager();

public:
	static DatabaseManager &Get(DatabaseInstance &db);
	static DatabaseManager &Get(ClientContext &db);
	static DatabaseManager &Get(AttachedDatabase &db);

	//! Initializes the system catalog of the attached SYSTEM_DATABASE.
	void InitializeSystemCatalog();
	//! Get an attached database by its name
	optional_ptr<AttachedDatabase> GetDatabase(ClientContext &context, const string &name);
	//! Attach a new database
	optional_ptr<AttachedDatabase> AttachDatabase(ClientContext &context, const AttachInfo &info,
	                                              const AttachOptions &options);
	//! Detach an existing database
	void DetachDatabase(ClientContext &context, const string &name, OnEntryNotFound if_not_found);
	//! Returns a reference to the system catalog
	Catalog &GetSystemCatalog();

	static const string &GetDefaultDatabase(ClientContext &context);
	void SetDefaultDatabase(ClientContext &context, const string &new_value);

	//! Inserts a path to name mapping to the database paths map
	void InsertDatabasePath(ClientContext &context, const string &path, const string &name);
	//! Erases a path from the database paths map
	void EraseDatabasePath(const string &path);

	//! 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
	//! to lock for this operation.
	void GetDatabaseType(ClientContext &context, AttachInfo &info, const DBConfig &config, AttachOptions &options);
	//! Scans the catalog set and adds each committed database entry, and each database entry of the current
	//! transaction, to a vector holding AttachedDatabase references
	vector<reference<AttachedDatabase>> GetDatabases(ClientContext &context);
	//! Removes all databases from the catalog set. This is necessary for the database instance's destructor,
	//! as the database manager has to be alive when destroying the catalog set objects.
	void ResetDatabases(unique_ptr<TaskScheduler> &scheduler);

	transaction_t GetNewQueryNumber() {
		return current_query_number++;
	}
	transaction_t ActiveQueryNumber() const {
		return current_query_number;
	}
	idx_t NextOid() {
		return next_oid++;
	}
	bool HasDefaultDatabase() {
		return !default_database.empty();
	}

private:
	//! Returns a database with a specified path
	optional_ptr<AttachedDatabase> GetDatabaseFromPath(ClientContext &context, const string &path);
	void CheckPathConflict(ClientContext &context, const string &path);

private:
	//! The system database is a special database that holds system entries (e.g. functions)
	unique_ptr<AttachedDatabase> system;
	//! The set of attached databases
	unique_ptr<CatalogSet> databases;
	//! The next object id handed out by the NextOid method
	atomic<idx_t> next_oid;
	//! The current query number
	atomic<transaction_t> current_query_number;
	//! The current default database
	string default_database;

	//! The lock to add entries to the database path map
	mutex db_paths_lock;
	//! A set containing all attached database path
	//! This allows to attach many databases efficiently, and to avoid attaching the
	//! same file path twice
	case_insensitive_set_t db_paths;
};

} // namespace duckdb


#include <mutex>

namespace duckdb {
class ClientContext;
class ErrorData;
class MetaTransaction;
class PreparedStatementData;
class SQLStatement;
struct PendingQueryParameters;
class RegisteredStateManager;

enum class RebindQueryInfo { DO_NOT_REBIND, ATTEMPT_TO_REBIND };

struct PreparedStatementCallbackInfo {
	PreparedStatementCallbackInfo(PreparedStatementData &prepared_statement, const PendingQueryParameters &parameters)
	    : prepared_statement(prepared_statement), parameters(parameters) {
	}

	PreparedStatementData &prepared_statement;
	const PendingQueryParameters &parameters;
};

//! ClientContextState is virtual base class for ClientContext-local (or Query-Local, using QueryEnd callback) state
//! e.g. caches that need to live as long as a ClientContext or Query.
class ClientContextState {
public:
	virtual ~ClientContextState() = default;
	virtual void QueryBegin(ClientContext &context) {
	}
	virtual void QueryEnd() {
	}
	virtual void QueryEnd(ClientContext &context) {
		QueryEnd();
	}
	virtual void QueryEnd(ClientContext &context, optional_ptr<ErrorData> error) {
		QueryEnd(context);
	}
	virtual void TransactionBegin(MetaTransaction &transaction, ClientContext &context) {
	}
	virtual void TransactionCommit(MetaTransaction &transaction, ClientContext &context) {
	}
	virtual void TransactionRollback(MetaTransaction &transaction, ClientContext &context) {
	}
	virtual void TransactionRollback(MetaTransaction &transaction, ClientContext &context,
	                                 optional_ptr<ErrorData> error) {
		TransactionRollback(transaction, context);
	}
	virtual bool CanRequestRebind() {
		return false;
	}
	virtual RebindQueryInfo OnPlanningError(ClientContext &context, SQLStatement &statement, ErrorData &error) {
		return RebindQueryInfo::DO_NOT_REBIND;
	}
	virtual RebindQueryInfo OnFinalizePrepare(ClientContext &context, PreparedStatementData &prepared_statement,
	                                          PreparedStatementMode mode) {
		return RebindQueryInfo::DO_NOT_REBIND;
	}
	virtual RebindQueryInfo OnExecutePrepared(ClientContext &context, PreparedStatementCallbackInfo &info,
	                                          RebindQueryInfo current_rebind) {
		return RebindQueryInfo::DO_NOT_REBIND;
	}
	virtual void WriteProfilingInformation(std::ostream &ss) {
	}

public:
	template <class TARGET>
	TARGET &Cast() {
		DynamicCastCheck<TARGET>(this);
		return reinterpret_cast<TARGET &>(*this);
	}
	template <class TARGET>
	const TARGET &Cast() const {
		DynamicCastCheck<TARGET>(this);
		return reinterpret_cast<const TARGET &>(*this);
	}
};

class RegisteredStateManager {
public:
	template <class T, typename... ARGS>
	shared_ptr<T> GetOrCreate(const string &key, ARGS &&... args) {
		lock_guard<mutex> l(lock);
		auto lookup = registered_state.find(key);
		if (lookup != registered_state.end()) {
			return shared_ptr_cast<ClientContextState, T>(lookup->second);
		}
		auto cache = make_shared_ptr<T>(std::forward<ARGS>(args)...);
		registered_state[key] = cache;
		return cache;
	}

	template <class T>
	shared_ptr<T> Get(const string &key) {
		lock_guard<mutex> l(lock);
		auto lookup = registered_state.find(key);
		if (lookup == registered_state.end()) {
			return nullptr;
		}
		return shared_ptr_cast<ClientContextState, T>(lookup->second);
	}

	void Insert(const string &key, shared_ptr<ClientContextState> state_p) {
		lock_guard<mutex> l(lock);
		registered_state.insert(make_pair(key, std::move(state_p)));
	}

	void Remove(const string &key) {
		lock_guard<mutex> l(lock);
		registered_state.erase(key);
	}

	vector<shared_ptr<ClientContextState>> States() {
		lock_guard<mutex> l(lock);
		vector<shared_ptr<ClientContextState>> states;
		for (auto &entry : registered_state) {
			states.push_back(entry.second);
		}
		return states;
	}

private:
	mutex lock;
	unordered_map<string, shared_ptr<ClientContextState>> registered_state;
};

} // namespace duckdb





//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/main/settings.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {
class ClientContext;
class DatabaseInstance;
struct DBConfig;

const string GetDefaultUserAgent();

enum class SettingScope : uint8_t {
	//! Setting is from the global Setting scope
	GLOBAL,
	//! Setting is from the local Setting scope
	LOCAL,
	//! Setting was not feteched from settings, but it was fetched from a secret instead
	SECRET,
	//! The setting was not found or invalid in some other way
	INVALID
};

struct SettingLookupResult {
public:
	SettingLookupResult() : scope(SettingScope::INVALID) {
	}
	explicit SettingLookupResult(SettingScope scope) : scope(scope) {
		D_ASSERT(scope != SettingScope::INVALID);
	}

public:
	operator bool() { // NOLINT: allow implicit conversion to bool
		return scope != SettingScope::INVALID;
	}

public:
	SettingScope GetScope() {
		D_ASSERT(scope != SettingScope::INVALID);
		return scope;
	}

private:
	SettingScope scope = SettingScope::INVALID;
};

struct AccessModeSetting {
	static constexpr const char *Name = "access_mode";
	static constexpr const char *Description = "Access mode of the database (AUTOMATIC, READ_ONLY or READ_WRITE)";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR;
	static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &parameter);
	static void ResetGlobal(DatabaseInstance *db, DBConfig &config);
	static Value GetSetting(const ClientContext &context);
};

struct AllowPersistentSecrets {
	static constexpr const char *Name = "allow_persistent_secrets";
	static constexpr const char *Description =
	    "Allow the creation of persistent secrets, that are stored and loaded on restarts";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN;
	static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &parameter);
	static void ResetGlobal(DatabaseInstance *db, DBConfig &config);
	static Value GetSetting(const ClientContext &context);
};

struct CatalogErrorMaxSchema {
	static constexpr const char *Name = "catalog_error_max_schemas";
	static constexpr const char *Description =
	    "The maximum number of schemas the system will scan for \"did you mean...\" style errors in the catalog";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::UBIGINT;
	static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &parameter);
	static void ResetGlobal(DatabaseInstance *db, DBConfig &config);
	static Value GetSetting(const ClientContext &context);
};

struct CheckpointThresholdSetting {
	static constexpr const char *Name = "checkpoint_threshold";
	static constexpr const char *Description =
	    "The WAL size threshold at which to automatically trigger a checkpoint (e.g. 1GB)";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR;
	static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &parameter);
	static void ResetGlobal(DatabaseInstance *db, DBConfig &config);
	static Value GetSetting(const ClientContext &context);
};

struct DebugCheckpointAbort {
	static constexpr const char *Name = "debug_checkpoint_abort";
	static constexpr const char *Description =
	    "DEBUG SETTING: trigger an abort while checkpointing for testing purposes";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR;
	static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &parameter);
	static void ResetGlobal(DatabaseInstance *db, DBConfig &config);
	static Value GetSetting(const ClientContext &context);
};

struct DebugForceExternal {
	static constexpr const char *Name = "debug_force_external";
	static constexpr const char *Description =
	    "DEBUG SETTING: force out-of-core computation for operators that support it, used for testing";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN;
	static void SetLocal(ClientContext &context, const Value &parameter);
	static void ResetLocal(ClientContext &context);
	static Value GetSetting(const ClientContext &context);
};

struct DebugForceNoCrossProduct {
	static constexpr const char *Name = "debug_force_no_cross_product";
	static constexpr const char *Description =
	    "DEBUG SETTING: Force disable cross product generation when hyper graph isn't connected, used for testing";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN;
	static void SetLocal(ClientContext &context, const Value &parameter);
	static void ResetLocal(ClientContext &context);
	static Value GetSetting(const ClientContext &context);
};

struct DebugSkipCheckpointOnCommit {
	static constexpr const char *Name = "debug_skip_checkpoint_on_commit";
	static constexpr const char *Description = "DEBUG SETTING: skip checkpointing on commit";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN;
	static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &parameter);
	static void ResetGlobal(DatabaseInstance *db, DBConfig &config);
	static Value GetSetting(const ClientContext &context);
};

struct OrderedAggregateThreshold {
	static constexpr const char *Name = "ordered_aggregate_threshold"; // NOLINT
	static constexpr const char *Description =                         // NOLINT
	    "The number of rows to accumulate before sorting, used for tuning";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::UBIGINT; // NOLINT
	static void SetLocal(ClientContext &context, const Value &parameter);
	static void ResetLocal(ClientContext &context);
	static Value GetSetting(const ClientContext &context);
};

struct DebugAsOfIEJoin {
	static constexpr const char *Name = "debug_asof_iejoin";                                                 // NOLINT
	static constexpr const char *Description = "DEBUG SETTING: force use of IEJoin to implement AsOf joins"; // NOLINT
	static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN;                                 // NOLINT
	static void SetLocal(ClientContext &context, const Value &parameter);
	static void ResetLocal(ClientContext &context);
	static Value GetSetting(const ClientContext &context);
};

struct PreferRangeJoins {
	static constexpr const char *Name = "prefer_range_joins";                                    // NOLINT
	static constexpr const char *Description = "Force use of range joins with mixed predicates"; // NOLINT
	static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN;                     // NOLINT
	static void SetLocal(ClientContext &context, const Value &parameter);
	static void ResetLocal(ClientContext &context);
	static Value GetSetting(const ClientContext &context);
};

struct DebugWindowMode {
	static constexpr const char *Name = "debug_window_mode";
	static constexpr const char *Description = "DEBUG SETTING: switch window mode to use";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR;
	static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &parameter);
	static void ResetGlobal(DatabaseInstance *db, DBConfig &config);
	static Value GetSetting(const ClientContext &context);
};

struct DefaultCollationSetting {
	static constexpr const char *Name = "default_collation";
	static constexpr const char *Description = "The collation setting used when none is specified";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR;
	static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &parameter);
	static void ResetGlobal(DatabaseInstance *db, DBConfig &config);
	static void SetLocal(ClientContext &context, const Value &parameter);
	static void ResetLocal(ClientContext &context);
	static Value GetSetting(const ClientContext &context);
};

struct DefaultOrderSetting {
	static constexpr const char *Name = "default_order";
	static constexpr const char *Description = "The order type used when none is specified (ASC or DESC)";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR;
	static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &parameter);
	static void ResetGlobal(DatabaseInstance *db, DBConfig &config);
	static Value GetSetting(const ClientContext &context);
};

struct DefaultNullOrderSetting {
	static constexpr const char *Name = "default_null_order";
	static constexpr const char *Description = "Null ordering used when none is specified (NULLS_FIRST or NULLS_LAST)";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR;
	static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &parameter);
	static void ResetGlobal(DatabaseInstance *db, DBConfig &config);
	static Value GetSetting(const ClientContext &context);
};

struct DefaultSecretStorage {
	static constexpr const char *Name = "default_secret_storage";
	static constexpr const char *Description = "Allows switching the default storage for secrets";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR;
	static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &parameter);
	static void ResetGlobal(DatabaseInstance *db, DBConfig &config);
	static Value GetSetting(const ClientContext &context);
};

struct DisabledFileSystemsSetting {
	static constexpr const char *Name = "disabled_filesystems";
	static constexpr const char *Description = "Disable specific file systems preventing access (e.g. LocalFileSystem)";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR;
	static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &parameter);
	static void ResetGlobal(DatabaseInstance *db, DBConfig &config);
	static Value GetSetting(const ClientContext &context);
};

struct DisabledOptimizersSetting {
	static constexpr const char *Name = "disabled_optimizers";
	static constexpr const char *Description = "DEBUG SETTING: disable a specific set of optimizers (comma separated)";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR;
	static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &parameter);
	static void ResetGlobal(DatabaseInstance *db, DBConfig &config);
	static Value GetSetting(const ClientContext &context);
};

struct EnableExternalAccessSetting {
	static constexpr const char *Name = "enable_external_access";
	static constexpr const char *Description =
	    "Allow the database to access external state (through e.g. loading/installing modules, COPY TO/FROM, CSV "
	    "readers, pandas replacement scans, etc)";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN;
	static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &parameter);
	static void ResetGlobal(DatabaseInstance *db, DBConfig &config);
	static Value GetSetting(const ClientContext &context);
};

struct EnableMacrosDependencies {
	static constexpr const char *Name = "enable_macro_dependencies";
	static constexpr const char *Description =
	    "Enable created MACROs to create dependencies on the referenced objects (such as tables)";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN;
	static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &parameter);
	static void ResetGlobal(DatabaseInstance *db, DBConfig &config);
	static Value GetSetting(const ClientContext &context);
};

struct EnableViewDependencies {
	static constexpr const char *Name = "enable_view_dependencies";
	static constexpr const char *Description =
	    "Enable created VIEWs to create dependencies on the referenced objects (such as tables)";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN;
	static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &parameter);
	static void ResetGlobal(DatabaseInstance *db, DBConfig &config);
	static Value GetSetting(const ClientContext &context);
};

struct EnableFSSTVectors {
	static constexpr const char *Name = "enable_fsst_vectors";
	static constexpr const char *Description =
	    "Allow scans on FSST compressed segments to emit compressed vectors to utilize late decompression";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN;
	static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &parameter);
	static void ResetGlobal(DatabaseInstance *db, DBConfig &config);
	static Value GetSetting(const ClientContext &context);
};

struct AllowUnsignedExtensionsSetting {
	static constexpr const char *Name = "allow_unsigned_extensions";
	static constexpr const char *Description = "Allow to load extensions with invalid or missing signatures";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN;
	static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &parameter);
	static void ResetGlobal(DatabaseInstance *db, DBConfig &config);
	static Value GetSetting(const ClientContext &context);
};

struct AllowCommunityExtensionsSetting {
	static constexpr const char *Name = "allow_community_extensions";
	static constexpr const char *Description = "Allow to load community built extensions";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN;
	static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &parameter);
	static void ResetGlobal(DatabaseInstance *db, DBConfig &config);
	static Value GetSetting(const ClientContext &context);
};

struct AllowExtensionsMetadataMismatchSetting {
	static constexpr const char *Name = "allow_extensions_metadata_mismatch";
	static constexpr const char *Description = "Allow to load extensions with not compatible metadata";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN;
	static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &parameter);
	static void ResetGlobal(DatabaseInstance *db, DBConfig &config);
	static Value GetSetting(const ClientContext &context);
};

struct AllowUnredactedSecretsSetting {
	static constexpr const char *Name = "allow_unredacted_secrets";
	static constexpr const char *Description = "Allow printing unredacted secrets";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN;
	static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &parameter);
	static void ResetGlobal(DatabaseInstance *db, DBConfig &config);
	static Value GetSetting(const ClientContext &context);
};

struct CustomExtensionRepository {
	static constexpr const char *Name = "custom_extension_repository";
	static constexpr const char *Description = "Overrides the custom endpoint for remote extension installation";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR;
	static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &parameter);
	static void ResetGlobal(DatabaseInstance *db, DBConfig &config);
	static Value GetSetting(const ClientContext &context);
};

struct AutoloadExtensionRepository {
	static constexpr const char *Name = "autoinstall_extension_repository";
	static constexpr const char *Description =
	    "Overrides the custom endpoint for extension installation on autoloading";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR;
	static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &parameter);
	static void ResetGlobal(DatabaseInstance *db, DBConfig &config);
	static Value GetSetting(const ClientContext &context);
};

struct AutoinstallKnownExtensions {
	static constexpr const char *Name = "autoinstall_known_extensions";
	static constexpr const char *Description =
	    "Whether known extensions are allowed to be automatically installed when a query depends on them";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN;
	static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &parameter);
	static void ResetGlobal(DatabaseInstance *db, DBConfig &config);
	static Value GetSetting(const ClientContext &context);
};

struct AutoloadKnownExtensions {
	static constexpr const char *Name = "autoload_known_extensions";
	static constexpr const char *Description =
	    "Whether known extensions are allowed to be automatically loaded when a query depends on them";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN;
	static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &parameter);
	static void ResetGlobal(DatabaseInstance *db, DBConfig &config);
	static Value GetSetting(const ClientContext &context);
};

struct EnableObjectCacheSetting {
	static constexpr const char *Name = "enable_object_cache";
	static constexpr const char *Description = "Whether or not object cache is used to cache e.g. Parquet metadata";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN;
	static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &parameter);
	static void ResetGlobal(DatabaseInstance *db, DBConfig &config);
	static Value GetSetting(const ClientContext &context);
};

struct StorageCompatibilityVersion {
	static constexpr const char *Name = "storage_compatibility_version";
	static constexpr const char *Description = "Serialize on checkpoint with compatibility for a given duckdb version";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR;
	static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &parameter);
	static void ResetGlobal(DatabaseInstance *db, DBConfig &config);
	static Value GetSetting(const ClientContext &context);
};

struct EnableHTTPMetadataCacheSetting {
	static constexpr const char *Name = "enable_http_metadata_cache";
	static constexpr const char *Description = "Whether or not the global http metadata is used to cache HTTP metadata";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN;
	static void ResetGlobal(DatabaseInstance *db, DBConfig &config);
	static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &parameter);
	static Value GetSetting(const ClientContext &context);
};

struct EnableProfilingSetting {
	static constexpr const char *Name = "enable_profiling";
	static constexpr const char *Description =
	    "Enables profiling, and sets the output format (JSON, QUERY_TREE, QUERY_TREE_OPTIMIZER)";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR;
	static void SetLocal(ClientContext &context, const Value &parameter);
	static void ResetLocal(ClientContext &context);
	static Value GetSetting(const ClientContext &context);
};

struct CustomProfilingSettings {
	static constexpr const char *Name = "custom_profiling_settings";
	static constexpr const char *Description = "Accepts a JSON enabling custom metrics";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR;
	static void SetLocal(ClientContext &context, const Value &parameter);
	static void ResetLocal(ClientContext &context);
	static Value GetSetting(const ClientContext &context);
};

struct EnableProgressBarSetting {
	static constexpr const char *Name = "enable_progress_bar";
	static constexpr const char *Description =
	    "Enables the progress bar, printing progress to the terminal for long queries";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN;
	static void SetLocal(ClientContext &context, const Value &parameter);
	static void ResetLocal(ClientContext &context);
	static Value GetSetting(const ClientContext &context);
};

struct EnableProgressBarPrintSetting {
	static constexpr const char *Name = "enable_progress_bar_print";
	static constexpr const char *Description =
	    "Controls the printing of the progress bar, when 'enable_progress_bar' is true";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN;
	static void SetLocal(ClientContext &context, const Value &parameter);
	static void ResetLocal(ClientContext &context);
	static Value GetSetting(const ClientContext &context);
};

struct ErrorsAsJsonSetting {
	static constexpr const char *Name = "errors_as_json";
	static constexpr const char *Description = "Output error messages as structured JSON instead of as a raw string";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN;
	static void SetLocal(ClientContext &context, const Value &parameter);
	static void ResetLocal(ClientContext &context);
	static Value GetSetting(const ClientContext &context);
};

struct ExplainOutputSetting {
	static constexpr const char *Name = "explain_output";
	static constexpr const char *Description = "Output of EXPLAIN statements (ALL, OPTIMIZED_ONLY, PHYSICAL_ONLY)";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR;
	static void SetLocal(ClientContext &context, const Value &parameter);
	static void ResetLocal(ClientContext &context);
	static Value GetSetting(const ClientContext &context);
};

struct ExportLargeBufferArrow {
	static constexpr const char *Name = "arrow_large_buffer_size";
	static constexpr const char *Description =
	    "If arrow buffers for strings, blobs, uuids and bits should be exported using large buffers";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN;
	static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &parameter);
	static void ResetGlobal(DatabaseInstance *db, DBConfig &config);
	static Value GetSetting(const ClientContext &context);
};

struct ExtensionDirectorySetting {
	static constexpr const char *Name = "extension_directory";
	static constexpr const char *Description = "Set the directory to store extensions in";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR;
	static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &parameter);
	static void ResetGlobal(DatabaseInstance *db, DBConfig &config);
	static Value GetSetting(const ClientContext &context);
};

struct ExternalThreadsSetting {
	static constexpr const char *Name = "external_threads";
	static constexpr const char *Description = "The number of external threads that work on DuckDB tasks.";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::BIGINT;
	static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &parameter);
	static void ResetGlobal(DatabaseInstance *db, DBConfig &config);
	static Value GetSetting(const ClientContext &context);
};

struct FileSearchPathSetting {
	static constexpr const char *Name = "file_search_path";
	static constexpr const char *Description = "A comma separated list of directories to search for input files";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR;
	static void SetLocal(ClientContext &context, const Value &parameter);
	static void ResetLocal(ClientContext &context);
	static Value GetSetting(const ClientContext &context);
};

struct ForceCompressionSetting {
	static constexpr const char *Name = "force_compression";
	static constexpr const char *Description = "DEBUG SETTING: forces a specific compression method to be used";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR;
	static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &parameter);
	static void ResetGlobal(DatabaseInstance *db, DBConfig &config);
	static Value GetSetting(const ClientContext &context);
};

struct ForceBitpackingModeSetting {
	static constexpr const char *Name = "force_bitpacking_mode";
	static constexpr const char *Description = "DEBUG SETTING: forces a specific bitpacking mode";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR;
	static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &parameter);
	static void ResetGlobal(DatabaseInstance *db, DBConfig &config);
	static Value GetSetting(const ClientContext &context);
};

struct HomeDirectorySetting {
	static constexpr const char *Name = "home_directory";
	static constexpr const char *Description = "Sets the home directory used by the system";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR;
	static void SetLocal(ClientContext &context, const Value &parameter);
	static void ResetLocal(ClientContext &context);
	static Value GetSetting(const ClientContext &context);
};

struct HTTPProxy {
	static constexpr const char *Name = "http_proxy";
	static constexpr const char *Description = "HTTP proxy host";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR;
	static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &parameter);
	static void ResetGlobal(DatabaseInstance *db, DBConfig &config);
	static Value GetSetting(const ClientContext &context);
};

struct HTTPProxyUsername {
	static constexpr const char *Name = "http_proxy_username";
	static constexpr const char *Description = "Username for HTTP proxy";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR;
	static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &parameter);
	static void ResetGlobal(DatabaseInstance *db, DBConfig &config);
	static Value GetSetting(const ClientContext &context);
};

struct HTTPProxyPassword {
	static constexpr const char *Name = "http_proxy_password";
	static constexpr const char *Description = "Password for HTTP proxy";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR;
	static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &parameter);
	static void ResetGlobal(DatabaseInstance *db, DBConfig &config);
	static Value GetSetting(const ClientContext &context);
};

struct IntegerDivisionSetting {
	static constexpr const char *Name = "integer_division";
	static constexpr const char *Description =
	    "Whether or not the / operator defaults to integer division, or to floating point division";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN;
	static void SetLocal(ClientContext &context, const Value &parameter);
	static void ResetLocal(ClientContext &context);
	static Value GetSetting(const ClientContext &context);
};

struct LogQueryPathSetting {
	static constexpr const char *Name = "log_query_path";
	static constexpr const char *Description =
	    "Specifies the path to which queries should be logged (default: NULL, queries are not logged)";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR;
	static void SetLocal(ClientContext &context, const Value &parameter);
	static void ResetLocal(ClientContext &context);
	static Value GetSetting(const ClientContext &context);
};

struct LockConfigurationSetting {
	static constexpr const char *Name = "lock_configuration";
	static constexpr const char *Description = "Whether or not the configuration can be altered";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN;
	static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &parameter);
	static void ResetGlobal(DatabaseInstance *db, DBConfig &config);
	static Value GetSetting(const ClientContext &context);
};

struct IEEEFloatingPointOpsSetting {
	static constexpr const char *Name = "ieee_floating_point_ops";
	static constexpr const char *Description =
	    "Use IEE754-compliant floating point operations (returning NAN instead of errors/NULL)";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN;
	static void SetLocal(ClientContext &context, const Value &parameter);
	static void ResetLocal(ClientContext &context);
	static Value GetSetting(const ClientContext &context);
};

struct ImmediateTransactionModeSetting {
	static constexpr const char *Name = "immediate_transaction_mode";
	static constexpr const char *Description =
	    "Whether transactions should be started lazily when needed, or immediately when BEGIN TRANSACTION is called";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN;
	static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &parameter);
	static void ResetGlobal(DatabaseInstance *db, DBConfig &config);
	static Value GetSetting(const ClientContext &context);
};

struct MaximumExpressionDepthSetting {
	static constexpr const char *Name = "max_expression_depth";
	static constexpr const char *Description =
	    "The maximum expression depth limit in the parser. WARNING: increasing this setting and using very deep "
	    "expressions might lead to stack overflow errors.";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::UBIGINT;
	static void SetLocal(ClientContext &context, const Value &parameter);
	static void ResetLocal(ClientContext &context);
	static Value GetSetting(const ClientContext &context);
};

struct MaximumMemorySetting {
	static constexpr const char *Name = "max_memory";
	static constexpr const char *Description = "The maximum memory of the system (e.g. 1GB)";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR;
	static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &parameter);
	static void ResetGlobal(DatabaseInstance *db, DBConfig &config);
	static Value GetSetting(const ClientContext &context);
};

struct StreamingBufferSize {
	static constexpr const char *Name = "streaming_buffer_size";
	static constexpr const char *Description =
	    "The maximum memory to buffer between fetching from a streaming result (e.g. 1GB)";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR;
	static void SetLocal(ClientContext &context, const Value &parameter);
	static void ResetLocal(ClientContext &context);
	static Value GetSetting(const ClientContext &context);
};

struct MaximumTempDirectorySize {
	static constexpr const char *Name = "max_temp_directory_size";
	static constexpr const char *Description =
	    "The maximum amount of data stored inside the 'temp_directory' (when set). If the `temp_directory` is set to "
	    "an existing directory, this option defaults to the available disk space on "
	    "that drive. Otherwise, it defaults to 0 (implying that the temporary directory is not used).";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR;
	static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &parameter);
	static void ResetGlobal(DatabaseInstance *db, DBConfig &config);
	static Value GetSetting(const ClientContext &context);
};

struct MaximumVacuumTasks {
	static constexpr const char *Name = "max_vacuum_tasks";
	static constexpr const char *Description = "The maximum vacuum tasks to schedule during a checkpoint";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::UBIGINT;
	static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &parameter);
	static void ResetGlobal(DatabaseInstance *db, DBConfig &config);
	static Value GetSetting(const ClientContext &context);
};

struct MergeJoinThreshold {
	static constexpr const char *Name = "merge_join_threshold";
	static constexpr const char *Description = "The number of rows we need on either table to choose a merge join";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::UBIGINT;
	static void SetLocal(ClientContext &context, const Value &parameter);
	static void ResetLocal(ClientContext &context);
	static Value GetSetting(const ClientContext &context);
};

struct NestedLoopJoinThreshold {
	static constexpr const char *Name = "nested_loop_join_threshold";
	static constexpr const char *Description =
	    "The number of rows we need on either table to choose a nested loop join";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::UBIGINT;
	static void SetLocal(ClientContext &context, const Value &parameter);
	static void ResetLocal(ClientContext &context);
	static Value GetSetting(const ClientContext &context);
};

struct OldImplicitCasting {
	static constexpr const char *Name = "old_implicit_casting";
	static constexpr const char *Description = "Allow implicit casting to/from VARCHAR";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN;
	static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &parameter);
	static void ResetGlobal(DatabaseInstance *db, DBConfig &config);
	static Value GetSetting(const ClientContext &context);
};

struct OrderByNonIntegerLiteral {
	static constexpr const char *Name = "order_by_non_integer_literal";
	static constexpr const char *Description =
	    "Allow ordering by non-integer literals - ordering by such literals has no effect";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN;
	static void SetLocal(ClientContext &context, const Value &parameter);
	static void ResetLocal(ClientContext &context);
	static Value GetSetting(const ClientContext &context);
};

struct PartitionedWriteFlushThreshold {
	static constexpr const char *Name = "partitioned_write_flush_threshold";
	static constexpr const char *Description =
	    "The threshold in number of rows after which we flush a thread state when writing using PARTITION_BY";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::UBIGINT;
	static void SetLocal(ClientContext &context, const Value &parameter);
	static void ResetLocal(ClientContext &context);
	static Value GetSetting(const ClientContext &context);
};

struct PartitionedWriteMaxOpenFiles {
	static constexpr const char *Name = "partitioned_write_max_open_files";
	static constexpr const char *Description =
	    "The maximum amount of files the system can keep open before flushing to disk when writing using PARTITION_BY";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::UBIGINT;
	static void SetLocal(ClientContext &context, const Value &parameter);
	static void ResetLocal(ClientContext &context);
	static Value GetSetting(const ClientContext &context);
};

struct DefaultBlockAllocSize {
	static constexpr const char *Name = "default_block_size";
	static constexpr const char *Description =
	    "The default block size for new duckdb database files (new as-in, they do not yet exist).";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::UBIGINT;
	static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &parameter);
	static void ResetGlobal(DatabaseInstance *db, DBConfig &config);
	static Value GetSetting(const ClientContext &context);
};

struct IndexScanPercentage {
	static constexpr const char *Name = "index_scan_percentage";
	static constexpr const char *Description =
	    "The index scan percentage sets a threshold for index scans. If fewer than MAX(index_scan_max_count, "
	    "index_scan_percentage * total_row_count) rows match, we perform an index scan instead of a table scan.";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::DOUBLE;
	static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &parameter);
	static void ResetGlobal(DatabaseInstance *db, DBConfig &config);
	static Value GetSetting(const ClientContext &context);
};

struct IndexScanMaxCount {
	static constexpr const char *Name = "index_scan_max_count";
	static constexpr const char *Description =
	    "The maximum index scan count sets a threshold for index scans. If fewer than MAX(index_scan_max_count, "
	    "index_scan_percentage * total_row_count) rows match, we perform an index scan instead of a table scan.";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::UBIGINT;
	static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &parameter);
	static void ResetGlobal(DatabaseInstance *db, DBConfig &config);
	static Value GetSetting(const ClientContext &context);
};

struct PasswordSetting {
	static constexpr const char *Name = "password";
	static constexpr const char *Description = "The password to use. Ignored for legacy compatibility.";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR;
	static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &parameter);
	static void ResetGlobal(DatabaseInstance *db, DBConfig &config);
	static Value GetSetting(const ClientContext &context);
};

struct PerfectHashThresholdSetting {
	static constexpr const char *Name = "perfect_ht_threshold";
	static constexpr const char *Description = "Threshold in bytes for when to use a perfect hash table";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::BIGINT;
	static void SetLocal(ClientContext &context, const Value &parameter);
	static void ResetLocal(ClientContext &context);
	static Value GetSetting(const ClientContext &context);
};

struct PivotFilterThreshold {
	static constexpr const char *Name = "pivot_filter_threshold";
	static constexpr const char *Description =
	    "The threshold to switch from using filtered aggregates to LIST with a dedicated pivot operator";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::BIGINT;
	static void SetLocal(ClientContext &context, const Value &parameter);
	static void ResetLocal(ClientContext &context);
	static Value GetSetting(const ClientContext &context);
};

struct PivotLimitSetting {
	static constexpr const char *Name = "pivot_limit";
	static constexpr const char *Description = "The maximum number of pivot columns in a pivot statement";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::BIGINT;
	static void SetLocal(ClientContext &context, const Value &parameter);
	static void ResetLocal(ClientContext &context);
	static Value GetSetting(const ClientContext &context);
};

struct PreserveIdentifierCase {
	static constexpr const char *Name = "preserve_identifier_case";
	static constexpr const char *Description =
	    "Whether or not to preserve the identifier case, instead of always lowercasing all non-quoted identifiers";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN;
	static void SetLocal(ClientContext &context, const Value &parameter);
	static void ResetLocal(ClientContext &context);
	static Value GetSetting(const ClientContext &context);
};

struct PreserveInsertionOrder {
	static constexpr const char *Name = "preserve_insertion_order";
	static constexpr const char *Description =
	    "Whether or not to preserve insertion order. If set to false the system is allowed to re-order any results "
	    "that do not contain ORDER BY clauses.";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN;
	static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &parameter);
	static void ResetGlobal(DatabaseInstance *db, DBConfig &config);
	static Value GetSetting(const ClientContext &context);
};

struct ArrowOutputListView {
	static constexpr const char *Name = "arrow_output_list_view";
	static constexpr const char *Description =
	    "If export to arrow format should use ListView as the physical layout for LIST columns";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN;
	static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &parameter);
	static void ResetGlobal(DatabaseInstance *db, DBConfig &config);
	static Value GetSetting(const ClientContext &context);
};

struct LosslessConversionArrow {
	static constexpr const char *Name = "arrow_lossless_conversion";
	static constexpr const char *Description =
	    "Whenever a DuckDB type does not have a clear native or canonical extension match in Arrow, export the types "
	    "with a duckdb.type_name extension name.";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN;
	static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &parameter);
	static void ResetGlobal(DatabaseInstance *db, DBConfig &config);
	static Value GetSetting(const ClientContext &context);
};

struct ProduceArrowStringView {
	static constexpr const char *Name = "produce_arrow_string_view";
	static constexpr const char *Description =
	    "If strings should be produced by DuckDB in Utf8View format instead of Utf8";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN;
	static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &parameter);
	static void ResetGlobal(DatabaseInstance *db, DBConfig &config);
	static Value GetSetting(const ClientContext &context);
};

struct ProfileOutputSetting {
	static constexpr const char *Name = "profile_output";
	static constexpr const char *Description =
	    "The file to which profile output should be saved, or empty to print to the terminal";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR;
	static void SetLocal(ClientContext &context, const Value &parameter);
	static void ResetLocal(ClientContext &context);
	static Value GetSetting(const ClientContext &context);
};

struct ProfilingModeSetting {
	static constexpr const char *Name = "profiling_mode";
	static constexpr const char *Description = "The profiling mode (STANDARD or DETAILED)";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR;
	static void SetLocal(ClientContext &context, const Value &parameter);
	static void ResetLocal(ClientContext &context);
	static Value GetSetting(const ClientContext &context);
};

struct ProgressBarTimeSetting {
	static constexpr const char *Name = "progress_bar_time";
	static constexpr const char *Description =
	    "Sets the time (in milliseconds) how long a query needs to take before we start printing a progress bar";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::BIGINT;
	static void SetLocal(ClientContext &context, const Value &parameter);
	static void ResetLocal(ClientContext &context);
	static Value GetSetting(const ClientContext &context);
};

struct ScalarSubqueryErrorOnMultipleRows {
	static constexpr const char *Name = "scalar_subquery_error_on_multiple_rows";
	static constexpr const char *Description =
	    "When a scalar subquery returns multiple rows - return a random row instead of returning an error";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN;
	static void SetLocal(ClientContext &context, const Value &parameter);
	static void ResetLocal(ClientContext &context);
	static Value GetSetting(const ClientContext &context);
};

struct SchemaSetting {
	static constexpr const char *Name = "schema";
	static constexpr const char *Description =
	    "Sets the default search schema. Equivalent to setting search_path to a single value.";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR;
	static void SetLocal(ClientContext &context, const Value &parameter);
	static void ResetLocal(ClientContext &context);
	static Value GetSetting(const ClientContext &context);
};

struct SearchPathSetting {
	static constexpr const char *Name = "search_path";
	static constexpr const char *Description =
	    "Sets the default catalog search path as a comma-separated list of values";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR;
	static void SetLocal(ClientContext &context, const Value &parameter);
	static void ResetLocal(ClientContext &context);
	static Value GetSetting(const ClientContext &context);
};

struct SecretDirectorySetting {
	static constexpr const char *Name = "secret_directory";
	static constexpr const char *Description = "Set the directory to which persistent secrets are stored";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR;
	static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &parameter);
	static void ResetGlobal(DatabaseInstance *db, DBConfig &config);
	static Value GetSetting(const ClientContext &context);
};

struct TempDirectorySetting {
	static constexpr const char *Name = "temp_directory";
	static constexpr const char *Description = "Set the directory to which to write temp files";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR;
	static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &parameter);
	static void ResetGlobal(DatabaseInstance *db, DBConfig &config);
	static Value GetSetting(const ClientContext &context);
};

struct ThreadsSetting {
	static constexpr const char *Name = "threads";
	static constexpr const char *Description = "The number of total threads used by the system.";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::BIGINT;
	static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &parameter);
	static void ResetGlobal(DatabaseInstance *db, DBConfig &config);
	static Value GetSetting(const ClientContext &context);
};

struct UsernameSetting {
	static constexpr const char *Name = "username";
	static constexpr const char *Description = "The username to use. Ignored for legacy compatibility.";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR;
	static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &parameter);
	static void ResetGlobal(DatabaseInstance *db, DBConfig &config);
	static Value GetSetting(const ClientContext &context);
};

struct AllocatorFlushThreshold {
	static constexpr const char *Name = "allocator_flush_threshold";
	static constexpr const char *Description =
	    "Peak allocation threshold at which to flush the allocator after completing a task.";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR;
	static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &parameter);
	static void ResetGlobal(DatabaseInstance *db, DBConfig &config);
	static Value GetSetting(const ClientContext &context);
};

struct AllocatorBulkDeallocationFlushThreshold {
	static constexpr const char *Name = "allocator_bulk_deallocation_flush_threshold";
	static constexpr const char *Description =
	    "If a bulk deallocation larger than this occurs, flush outstanding allocations.";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR;
	static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &parameter);
	static void ResetGlobal(DatabaseInstance *db, DBConfig &config);
	static Value GetSetting(const ClientContext &context);
};

struct AllocatorBackgroundThreadsSetting {
	static constexpr const char *Name = "allocator_background_threads";
	static constexpr const char *Description = "Whether to enable the allocator background thread.";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN;
	static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &parameter);
	static void ResetGlobal(DatabaseInstance *db, DBConfig &config);
	static Value GetSetting(const ClientContext &context);
};

struct DuckDBApiSetting {
	static constexpr const char *Name = "duckdb_api";
	static constexpr const char *Description = "DuckDB API surface";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR;
	static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &parameter);
	static void ResetGlobal(DatabaseInstance *db, DBConfig &config);
	static Value GetSetting(const ClientContext &context);
};

struct CustomUserAgentSetting {
	static constexpr const char *Name = "custom_user_agent";
	static constexpr const char *Description = "Metadata from DuckDB callers";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR;
	static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &parameter);
	static void ResetGlobal(DatabaseInstance *db, DBConfig &config);
	static Value GetSetting(const ClientContext &context);
};

struct EnableHTTPLoggingSetting {
	static constexpr const char *Name = "enable_http_logging";
	static constexpr const char *Description = "Enables HTTP logging";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN;
	static void SetLocal(ClientContext &context, const Value &parameter);
	static void ResetLocal(ClientContext &context);
	static Value GetSetting(const ClientContext &context);
};

struct HTTPLoggingOutputSetting {
	static constexpr const char *Name = "http_logging_output";
	static constexpr const char *Description =
	    "The file to which HTTP logging output should be saved, or empty to print to the terminal";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR;
	static void SetLocal(ClientContext &context, const Value &parameter);
	static void ResetLocal(ClientContext &context);
	static Value GetSetting(const ClientContext &context);
};

} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/main/stream_query_result.hpp
//
//
//===----------------------------------------------------------------------===//






//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/queue.hpp
//
//
//===----------------------------------------------------------------------===//



#include <queue>

namespace duckdb {
using std::queue;
} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/enums/stream_execution_result.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

enum class StreamExecutionResult : uint8_t {
	CHUNK_READY,
	CHUNK_NOT_READY,
	EXECUTION_ERROR,
	EXECUTION_CANCELLED,
	BLOCKED,
	NO_TASKS_AVAILABLE,
	EXECUTION_FINISHED
};

} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/main/simple_buffered_data.hpp
//
//
//===----------------------------------------------------------------------===//



//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/main/buffered_data.hpp
//
//
//===----------------------------------------------------------------------===//













namespace duckdb {

class StreamQueryResult;
class ClientContextLock;

class BufferedData {
protected:
	enum class Type { SIMPLE, BATCHED };

public:
	BufferedData(Type type, weak_ptr<ClientContext> context_p);
	virtual ~BufferedData();

public:
	StreamExecutionResult ReplenishBuffer(StreamQueryResult &result, ClientContextLock &context_lock);
	virtual StreamExecutionResult ExecuteTaskInternal(StreamQueryResult &result, ClientContextLock &context_lock) = 0;
	virtual unique_ptr<DataChunk> Scan() = 0;
	virtual void UnblockSinks() = 0;
	shared_ptr<ClientContext> GetContext() {
		return context.lock();
	}
	bool Closed() const {
		if (context.expired()) {
			return true;
		}
		auto c = context.lock();
		return c == nullptr;
	}
	void Close() {
		context.reset();
	}

public:
	template <class TARGET>
	TARGET &Cast() {
		if (TARGET::TYPE != type) {
			throw InternalException("Failed to cast buffered data to type - buffered data type mismatch");
		}
		return reinterpret_cast<TARGET &>(*this);
	}

	template <class TARGET>
	const TARGET &Cast() const {
		if (TARGET::TYPE != type) {
			throw InternalException("Failed to cast buffered data to type - buffered data type mismatch");
		}
		return reinterpret_cast<const TARGET &>(*this);
	}

protected:
	Type type;
	//! This is weak to avoid a cyclical reference
	weak_ptr<ClientContext> context;
	//! The maximum amount of memory we should keep buffered
	idx_t total_buffer_size;
	//! Protect against populate/fetch race condition
	mutex glock;
};

} // namespace duckdb






namespace duckdb {

class StreamQueryResult;
class ClientContextLock;

class SimpleBufferedData : public BufferedData {
public:
	static constexpr const BufferedData::Type TYPE = BufferedData::Type::SIMPLE;

public:
	explicit SimpleBufferedData(weak_ptr<ClientContext> context);
	~SimpleBufferedData() override;

public:
	void Append(const DataChunk &chunk);
	void BlockSink(const InterruptState &blocked_sink);
	bool BufferIsFull();
	void UnblockSinks() override;
	StreamExecutionResult ExecuteTaskInternal(StreamQueryResult &result, ClientContextLock &context_lock) override;
	unique_ptr<DataChunk> Scan() override;
	inline idx_t BufferSize() const {
		return buffer_size;
	}

private:
	//! Our handles to reschedule the blocked sink tasks
	queue<InterruptState> blocked_sinks;
	//! The queue of chunks
	queue<unique_ptr<DataChunk>> buffered_chunks;
	//! The current capacity of the buffer (tuples)
	atomic<idx_t> buffered_count;
	//! The amount of tuples we should buffer
	idx_t buffer_size;
};

} // namespace duckdb


namespace duckdb {

class ClientContext;
class ClientContextLock;
class Executor;
class MaterializedQueryResult;
class PreparedStatementData;

class StreamQueryResult : public QueryResult {
	friend class ClientContext;

public:
	static constexpr const QueryResultType TYPE = QueryResultType::STREAM_RESULT;

public:
	//! Create a successful StreamQueryResult. StreamQueryResults should always be successful initially (it makes no
	//! sense to stream an error).
	DUCKDB_API StreamQueryResult(StatementType statement_type, StatementProperties properties,
	                             vector<LogicalType> types, vector<string> names, ClientProperties client_properties,
	                             shared_ptr<BufferedData> buffered_data);
	DUCKDB_API explicit StreamQueryResult(ErrorData error);
	DUCKDB_API ~StreamQueryResult() override;

public:
	static bool IsChunkReady(StreamExecutionResult result);
	//! Reschedules the tasks that work on producing a result chunk, returning when at least one task can be executed
	DUCKDB_API void WaitForTask();
	//! Executes a single task within the final pipeline, returning whether or not a chunk is ready to be fetched
	DUCKDB_API StreamExecutionResult ExecuteTask();
	//! Fetches a DataChunk from the query result.
	DUCKDB_API unique_ptr<DataChunk> FetchRaw() override;
	//! Converts the QueryResult to a string
	DUCKDB_API string ToString() override;
	//! Materializes the query result and turns it into a materialized query result
	DUCKDB_API unique_ptr<MaterializedQueryResult> Materialize();

	DUCKDB_API bool IsOpen();

	//! Closes the StreamQueryResult
	DUCKDB_API void Close();

	//! The client context this StreamQueryResult belongs to
	shared_ptr<ClientContext> context;

private:
	StreamExecutionResult ExecuteTaskInternal(ClientContextLock &lock);
	unique_ptr<DataChunk> FetchInternal(ClientContextLock &lock);
	unique_ptr<ClientContextLock> LockContext();
	void CheckExecutableInternal(ClientContextLock &lock);
	bool IsOpenInternal(ClientContextLock &lock);

private:
	shared_ptr<BufferedData> buffered_data;
};

} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/main/table_description.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

struct TableDescription {
	//! The schema of the table
	string schema;
	//! The table name of the table
	string table;
	//! The columns of the table
	vector<ColumnDefinition> columns;
};

} // namespace duckdb


//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/transaction/transaction_context.hpp
//
//
//===----------------------------------------------------------------------===//









namespace duckdb {

class ClientContext;
class MetaTransaction;
class Transaction;
class TransactionManager;

//! The transaction context keeps track of all the information relating to the
//! current transaction
class TransactionContext {
public:
	explicit TransactionContext(ClientContext &context);
	~TransactionContext();

	MetaTransaction &ActiveTransaction() {
		if (!current_transaction) {
			throw InternalException("TransactionContext::ActiveTransaction called without active transaction");
		}
		return *current_transaction;
	}

	bool HasActiveTransaction() const {
		return current_transaction.get();
	}

	void BeginTransaction();
	void Commit();
	void Rollback(optional_ptr<ErrorData>);
	void ClearTransaction();

	void SetAutoCommit(bool value);
	bool IsAutoCommit() const {
		return auto_commit;
	}

	void SetReadOnly();

	idx_t GetActiveQuery();
	void ResetActiveQuery();
	void SetActiveQuery(transaction_t query_number);

private:
	ClientContext &context;
	bool auto_commit;

	unique_ptr<MetaTransaction> current_transaction;

	TransactionContext(const TransactionContext &) = delete;
};

} // namespace duckdb


namespace duckdb {
class Appender;
class Catalog;
class CatalogSearchPath;
class ColumnDataCollection;
class DatabaseInstance;
class FileOpener;
class LogicalOperator;
class PreparedStatementData;
class Relation;
class BufferedFileWriter;
class QueryProfiler;
class ClientContextLock;
struct CreateScalarFunctionInfo;
class ScalarFunctionCatalogEntry;
struct ActiveQueryContext;
struct ParserOptions;
class SimpleBufferedData;
class BufferedData;
struct ClientData;
class ClientContextState;
class RegisteredStateManager;

struct PendingQueryParameters {
	//! Prepared statement parameters (if any)
	optional_ptr<case_insensitive_map_t<BoundParameterData>> parameters;
	//! Whether or not a stream result should be allowed
	bool allow_stream_result = false;
};

//! The ClientContext holds information relevant to the current client session
//! during execution
class ClientContext : public enable_shared_from_this<ClientContext> {
	friend class PendingQueryResult;  // LockContext
	friend class BufferedData;        // ExecuteTaskInternal
	friend class SimpleBufferedData;  // ExecuteTaskInternal
	friend class BatchedBufferedData; // ExecuteTaskInternal
	friend class StreamQueryResult;   // LockContext
	friend class ConnectionManager;

public:
	DUCKDB_API explicit ClientContext(shared_ptr<DatabaseInstance> db);
	DUCKDB_API ~ClientContext();

	//! The database that this client is connected to
	shared_ptr<DatabaseInstance> db;
	//! Whether or not the query is interrupted
	atomic<bool> interrupted;
	//! Set of optional states (e.g. Caches) that can be held by the ClientContext
	unique_ptr<RegisteredStateManager> registered_state;
	//! The client configuration
	ClientConfig config;
	//! The set of client-specific data
	unique_ptr<ClientData> client_data;
	//! Data for the currently running transaction
	TransactionContext transaction;

public:
	MetaTransaction &ActiveTransaction() {
		return transaction.ActiveTransaction();
	}

	//! Interrupt execution of a query
	DUCKDB_API void Interrupt();
	DUCKDB_API void CancelTransaction();

	//! Enable query profiling
	DUCKDB_API void EnableProfiling();
	//! Disable query profiling
	DUCKDB_API void DisableProfiling();

	//! Issue a query, returning a QueryResult. The QueryResult can be either a StreamQueryResult or a
	//! MaterializedQueryResult. The StreamQueryResult will only be returned in the case of a successful SELECT
	//! statement.
	DUCKDB_API unique_ptr<QueryResult> Query(const string &query, bool allow_stream_result);
	DUCKDB_API unique_ptr<QueryResult> Query(unique_ptr<SQLStatement> statement, bool allow_stream_result);

	//! Issues a query to the database and returns a Pending Query Result. Note that "query" may only contain
	//! a single statement.
	DUCKDB_API unique_ptr<PendingQueryResult> PendingQuery(const string &query, bool allow_stream_result);
	//! Issues a query to the database and returns a Pending Query Result
	DUCKDB_API unique_ptr<PendingQueryResult> PendingQuery(unique_ptr<SQLStatement> statement,
	                                                       bool allow_stream_result);

	//! Destroy the client context
	DUCKDB_API void Destroy();

	//! Get the table info of a specific table, or nullptr if it cannot be found
	DUCKDB_API unique_ptr<TableDescription> TableInfo(const string &schema_name, const string &table_name);
	//! Appends a DataChunk to the specified table. Returns whether or not the append was successful.
	DUCKDB_API void Append(TableDescription &description, ColumnDataCollection &collection);
	//! Try to bind a relation in the current client context; either throws an exception or fills the result_columns
	//! list with the set of returned columns
	DUCKDB_API void TryBindRelation(Relation &relation, vector<ColumnDefinition> &result_columns);

	//! Execute a relation
	DUCKDB_API unique_ptr<PendingQueryResult> PendingQuery(const shared_ptr<Relation> &relation,
	                                                       bool allow_stream_result);
	DUCKDB_API unique_ptr<QueryResult> Execute(const shared_ptr<Relation> &relation);

	//! Prepare a query
	DUCKDB_API unique_ptr<PreparedStatement> Prepare(const string &query);
	//! Directly prepare a SQL statement
	DUCKDB_API unique_ptr<PreparedStatement> Prepare(unique_ptr<SQLStatement> statement);

	//! Create a pending query result from a prepared statement with the given name and set of parameters
	//! It is possible that the prepared statement will be re-bound. This will generally happen if the catalog is
	//! modified in between the prepared statement being bound and the prepared statement being run.
	DUCKDB_API unique_ptr<PendingQueryResult> PendingQuery(const string &query,
	                                                       shared_ptr<PreparedStatementData> &prepared,
	                                                       const PendingQueryParameters &parameters);

	//! Execute a prepared statement with the given name and set of parameters
	//! It is possible that the prepared statement will be re-bound. This will generally happen if the catalog is
	//! modified in between the prepared statement being bound and the prepared statement being run.
	DUCKDB_API unique_ptr<QueryResult> Execute(const string &query, shared_ptr<PreparedStatementData> &prepared,
	                                           case_insensitive_map_t<BoundParameterData> &values,
	                                           bool allow_stream_result = true);
	DUCKDB_API unique_ptr<QueryResult> Execute(const string &query, shared_ptr<PreparedStatementData> &prepared,
	                                           const PendingQueryParameters &parameters);

	//! Gets current percentage of the query's progress, returns 0 in case the progress bar is disabled.
	DUCKDB_API QueryProgress GetQueryProgress();

	//! Register function in the temporary schema
	DUCKDB_API void RegisterFunction(CreateFunctionInfo &info);

	//! Parse statements from a query
	DUCKDB_API vector<unique_ptr<SQLStatement>> ParseStatements(const string &query);

	//! Extract the logical plan of a query
	DUCKDB_API unique_ptr<LogicalOperator> ExtractPlan(const string &query);
	DUCKDB_API void HandlePragmaStatements(vector<unique_ptr<SQLStatement>> &statements);

	//! Runs a function with a valid transaction context, potentially starting a transaction if the context is in auto
	//! commit mode.
	DUCKDB_API void RunFunctionInTransaction(const std::function<void(void)> &fun,
	                                         bool requires_valid_transaction = true);
	//! Same as RunFunctionInTransaction, but does not obtain a lock on the client context or check for validation
	DUCKDB_API void RunFunctionInTransactionInternal(ClientContextLock &lock, const std::function<void(void)> &fun,
	                                                 bool requires_valid_transaction = true);

	//! Equivalent to CURRENT_SETTING(key) SQL function.
	DUCKDB_API SettingLookupResult TryGetCurrentSetting(const std::string &key, Value &result) const;

	//! Returns the parser options for this client context
	DUCKDB_API ParserOptions GetParserOptions() const;

	//! Whether or not the given result object (streaming query result or pending query result) is active
	DUCKDB_API bool IsActiveResult(ClientContextLock &lock, BaseQueryResult &result);

	//! Returns the current executor
	Executor &GetExecutor();

	//! Returns the current query string (if any)
	const string &GetCurrentQuery();

	//! Fetch a list of table names that are required for a given query
	DUCKDB_API unordered_set<string> GetTableNames(const string &query);

	DUCKDB_API ClientProperties GetClientProperties() const;

	//! Returns true if execution of the current query is finished
	DUCKDB_API bool ExecutionIsFinished();

	//! Process an error for display to the user
	DUCKDB_API void ProcessError(ErrorData &error, const string &query) const;

private:
	//! Parse statements and resolve pragmas from a query
	bool ParseStatements(ClientContextLock &lock, const string &query, vector<unique_ptr<SQLStatement>> &result,
	                     ErrorData &error);
	//! Issues a query to the database and returns a Pending Query Result
	unique_ptr<PendingQueryResult> PendingQueryInternal(ClientContextLock &lock, unique_ptr<SQLStatement> statement,
	                                                    const PendingQueryParameters &parameters, bool verify = true);
	unique_ptr<QueryResult> ExecutePendingQueryInternal(ClientContextLock &lock, PendingQueryResult &query);

	//! Parse statements from a query
	vector<unique_ptr<SQLStatement>> ParseStatementsInternal(ClientContextLock &lock, const string &query);
	//! Perform aggressive query verification of a SELECT statement. Only called when query_verification_enabled is
	//! true.
	ErrorData VerifyQuery(ClientContextLock &lock, const string &query, unique_ptr<SQLStatement> statement);

	void InitialCleanup(ClientContextLock &lock);
	//! Internal clean up, does not lock. Caller must hold the context_lock.
	void CleanupInternal(ClientContextLock &lock, BaseQueryResult *result = nullptr,
	                     bool invalidate_transaction = false);
	unique_ptr<PendingQueryResult> PendingStatementOrPreparedStatement(ClientContextLock &lock, const string &query,
	                                                                   unique_ptr<SQLStatement> statement,
	                                                                   shared_ptr<PreparedStatementData> &prepared,
	                                                                   const PendingQueryParameters &parameters);
	unique_ptr<PendingQueryResult> PendingPreparedStatement(ClientContextLock &lock, const string &query,
	                                                        shared_ptr<PreparedStatementData> statement_p,
	                                                        const PendingQueryParameters &parameters);
	unique_ptr<PendingQueryResult> PendingPreparedStatementInternal(ClientContextLock &lock,
	                                                                shared_ptr<PreparedStatementData> statement_p,
	                                                                const PendingQueryParameters &parameters);
	void CheckIfPreparedStatementIsExecutable(PreparedStatementData &statement);

	//! Internally prepare a SQL statement. Caller must hold the context_lock.
	shared_ptr<PreparedStatementData>
	CreatePreparedStatement(ClientContextLock &lock, const string &query, unique_ptr<SQLStatement> statement,
	                        optional_ptr<case_insensitive_map_t<BoundParameterData>> values = nullptr,
	                        PreparedStatementMode mode = PreparedStatementMode::PREPARE_ONLY);
	unique_ptr<PendingQueryResult> PendingStatementInternal(ClientContextLock &lock, const string &query,
	                                                        unique_ptr<SQLStatement> statement,
	                                                        const PendingQueryParameters &parameters);
	unique_ptr<QueryResult> RunStatementInternal(ClientContextLock &lock, const string &query,
	                                             unique_ptr<SQLStatement> statement, bool allow_stream_result,
	                                             bool verify = true);
	unique_ptr<PreparedStatement> PrepareInternal(ClientContextLock &lock, unique_ptr<SQLStatement> statement);
	void LogQueryInternal(ClientContextLock &lock, const string &query);

	unique_ptr<QueryResult> FetchResultInternal(ClientContextLock &lock, PendingQueryResult &pending);

	unique_ptr<ClientContextLock> LockContext();

	void BeginQueryInternal(ClientContextLock &lock, const string &query);
	ErrorData EndQueryInternal(ClientContextLock &lock, bool success, bool invalidate_transaction,
	                           optional_ptr<ErrorData> previous_error);

	//! Wait until a task is available to execute
	void WaitForTask(ClientContextLock &lock, BaseQueryResult &result);
	PendingExecutionResult ExecuteTaskInternal(ClientContextLock &lock, BaseQueryResult &result, bool dry_run = false);

	unique_ptr<PendingQueryResult> PendingStatementOrPreparedStatementInternal(
	    ClientContextLock &lock, const string &query, unique_ptr<SQLStatement> statement,
	    shared_ptr<PreparedStatementData> &prepared, const PendingQueryParameters &parameters);

	unique_ptr<PendingQueryResult> PendingQueryPreparedInternal(ClientContextLock &lock, const string &query,
	                                                            shared_ptr<PreparedStatementData> &prepared,
	                                                            const PendingQueryParameters &parameters);

	unique_ptr<PendingQueryResult> PendingQueryInternal(ClientContextLock &, const shared_ptr<Relation> &relation,
	                                                    bool allow_stream_result);

	void RebindPreparedStatement(ClientContextLock &lock, const string &query,
	                             shared_ptr<PreparedStatementData> &prepared, const PendingQueryParameters &parameters);

	template <class T>
	unique_ptr<T> ErrorResult(ErrorData error, const string &query = string());

	shared_ptr<PreparedStatementData>
	CreatePreparedStatementInternal(ClientContextLock &lock, const string &query, unique_ptr<SQLStatement> statement,
	                                optional_ptr<case_insensitive_map_t<BoundParameterData>> values);

private:
	//! Lock on using the ClientContext in parallel
	mutex context_lock;
	//! The currently active query context
	unique_ptr<ActiveQueryContext> active_query;
	//! The current query progress
	QueryProgress query_progress;
};

class ClientContextLock {
public:
	explicit ClientContextLock(mutex &context_lock) : client_guard(context_lock) {
	}

	~ClientContextLock() {
	}

private:
	lock_guard<mutex> client_guard;
};

} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/main/client_context_wrapper.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

class ClientContext;

class ClientContextWrapper {
public:
	explicit ClientContextWrapper(const shared_ptr<ClientContext> &context);
	shared_ptr<ClientContext> GetContext();
	shared_ptr<ClientContext> TryGetContext();

private:
	weak_ptr<ClientContext> client_context;
};

} // namespace duckdb


//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/parser/statement/explain_statement.hpp
//
//
//===----------------------------------------------------------------------===//







namespace duckdb {

enum class ExplainType : uint8_t { EXPLAIN_STANDARD, EXPLAIN_ANALYZE };

class ExplainStatement : public SQLStatement {
public:
	static constexpr const StatementType TYPE = StatementType::EXPLAIN_STATEMENT;

public:
	explicit ExplainStatement(unique_ptr<SQLStatement> stmt, ExplainType explain_type = ExplainType::EXPLAIN_STANDARD,
	                          ExplainFormat explain_format = ExplainFormat::DEFAULT);

	unique_ptr<SQLStatement> stmt;
	ExplainType explain_type;
	ExplainFormat explain_format = ExplainFormat::DEFAULT;

protected:
	ExplainStatement(const ExplainStatement &other);

public:
	unique_ptr<SQLStatement> Copy() const override;
	string OptionsToString() const;
	string ToString() const override;
};

} // namespace duckdb







namespace duckdb {
struct BoundStatement;

class Binder;
class LogicalOperator;
class QueryNode;
class TableRef;

class Relation : public enable_shared_from_this<Relation> {
public:
	Relation(const shared_ptr<ClientContext> &context, RelationType type) : context(context), type(type) {
	}
	Relation(ClientContextWrapper &context, RelationType type) : context(context.GetContext()), type(type) {
	}
	virtual ~Relation() {
	}

	ClientContextWrapper context;
	RelationType type;
	vector<shared_ptr<ExternalDependency>> external_dependencies;

public:
	DUCKDB_API virtual const vector<ColumnDefinition> &Columns() = 0;
	DUCKDB_API virtual unique_ptr<QueryNode> GetQueryNode();
	DUCKDB_API virtual BoundStatement Bind(Binder &binder);
	DUCKDB_API virtual string GetAlias();

	DUCKDB_API unique_ptr<QueryResult> ExecuteOrThrow();
	DUCKDB_API unique_ptr<QueryResult> Execute();
	DUCKDB_API string ToString();
	DUCKDB_API virtual string ToString(idx_t depth) = 0;

	DUCKDB_API void Print();
	DUCKDB_API void Head(idx_t limit = 10);

	DUCKDB_API shared_ptr<Relation> CreateView(const string &name, bool replace = true, bool temporary = false);
	DUCKDB_API shared_ptr<Relation> CreateView(const string &schema_name, const string &name, bool replace = true,
	                                           bool temporary = false);
	DUCKDB_API unique_ptr<QueryResult> Query(const string &sql);
	DUCKDB_API unique_ptr<QueryResult> Query(const string &name, const string &sql);

	//! Explain the query plan of this relation
	DUCKDB_API unique_ptr<QueryResult> Explain(ExplainType type = ExplainType::EXPLAIN_STANDARD,
	                                           ExplainFormat explain_format = ExplainFormat::DEFAULT);

	DUCKDB_API virtual unique_ptr<TableRef> GetTableRef();
	virtual bool IsReadOnly() {
		return true;
	}

public:
	// PROJECT
	DUCKDB_API shared_ptr<Relation> Project(const string &select_list);
	DUCKDB_API shared_ptr<Relation> Project(const string &expression, const string &alias);
	DUCKDB_API shared_ptr<Relation> Project(const string &select_list, const vector<string> &aliases);
	DUCKDB_API shared_ptr<Relation> Project(const vector<string> &expressions);
	DUCKDB_API shared_ptr<Relation> Project(const vector<string> &expressions, const vector<string> &aliases);
	DUCKDB_API shared_ptr<Relation> Project(vector<unique_ptr<ParsedExpression>> expressions,
	                                        const vector<string> &aliases);

	// FILTER
	DUCKDB_API shared_ptr<Relation> Filter(const string &expression);
	DUCKDB_API shared_ptr<Relation> Filter(unique_ptr<ParsedExpression> expression);
	DUCKDB_API shared_ptr<Relation> Filter(const vector<string> &expressions);

	// LIMIT
	DUCKDB_API shared_ptr<Relation> Limit(int64_t n, int64_t offset = 0);

	// ORDER
	DUCKDB_API shared_ptr<Relation> Order(const string &expression);
	DUCKDB_API shared_ptr<Relation> Order(const vector<string> &expressions);
	DUCKDB_API shared_ptr<Relation> Order(vector<OrderByNode> expressions);

	// JOIN operation
	DUCKDB_API shared_ptr<Relation> Join(const shared_ptr<Relation> &other, const string &condition,
	                                     JoinType type = JoinType::INNER, JoinRefType ref_type = JoinRefType::REGULAR);
	shared_ptr<Relation> Join(const shared_ptr<Relation> &other, vector<unique_ptr<ParsedExpression>> condition,
	                          JoinType type = JoinType::INNER, JoinRefType ref_type = JoinRefType::REGULAR);

	// CROSS PRODUCT operation
	DUCKDB_API shared_ptr<Relation> CrossProduct(const shared_ptr<Relation> &other,
	                                             JoinRefType join_ref_type = JoinRefType::CROSS);

	// SET operations
	DUCKDB_API shared_ptr<Relation> Union(const shared_ptr<Relation> &other);
	DUCKDB_API shared_ptr<Relation> Except(const shared_ptr<Relation> &other);
	DUCKDB_API shared_ptr<Relation> Intersect(const shared_ptr<Relation> &other);

	// DISTINCT operation
	DUCKDB_API shared_ptr<Relation> Distinct();

	// AGGREGATES
	DUCKDB_API shared_ptr<Relation> Aggregate(const string &aggregate_list);
	DUCKDB_API shared_ptr<Relation> Aggregate(const vector<string> &aggregates);
	DUCKDB_API shared_ptr<Relation> Aggregate(vector<unique_ptr<ParsedExpression>> expressions);
	DUCKDB_API shared_ptr<Relation> Aggregate(const string &aggregate_list, const string &group_list);
	DUCKDB_API shared_ptr<Relation> Aggregate(const vector<string> &aggregates, const vector<string> &groups);
	DUCKDB_API shared_ptr<Relation> Aggregate(vector<unique_ptr<ParsedExpression>> expressions,
	                                          const string &group_list);

	// ALIAS
	DUCKDB_API shared_ptr<Relation> Alias(const string &alias);

	//! Insert the data from this relation into a table
	DUCKDB_API shared_ptr<Relation> InsertRel(const string &schema_name, const string &table_name);
	DUCKDB_API void Insert(const string &table_name);
	DUCKDB_API void Insert(const string &schema_name, const string &table_name);
	//! Insert a row (i.e.,list of values) into a table
	DUCKDB_API void Insert(const vector<vector<Value>> &values);
	//! Create a table and insert the data from this relation into that table
	DUCKDB_API shared_ptr<Relation> CreateRel(const string &schema_name, const string &table_name,
	                                          bool temporary = false);
	DUCKDB_API void Create(const string &table_name, bool temporary = false);
	DUCKDB_API void Create(const string &schema_name, const string &table_name, bool temporary = false);

	//! Write a relation to a CSV file
	DUCKDB_API shared_ptr<Relation>
	WriteCSVRel(const string &csv_file,
	            case_insensitive_map_t<vector<Value>> options = case_insensitive_map_t<vector<Value>>());
	DUCKDB_API void WriteCSV(const string &csv_file,
	                         case_insensitive_map_t<vector<Value>> options = case_insensitive_map_t<vector<Value>>());
	//! Write a relation to a Parquet file
	DUCKDB_API shared_ptr<Relation>
	WriteParquetRel(const string &parquet_file,
	                case_insensitive_map_t<vector<Value>> options = case_insensitive_map_t<vector<Value>>());
	DUCKDB_API void
	WriteParquet(const string &parquet_file,
	             case_insensitive_map_t<vector<Value>> options = case_insensitive_map_t<vector<Value>>());

	//! Update a table, can only be used on a TableRelation
	DUCKDB_API virtual void Update(const string &update, const string &condition = string());
	//! Delete from a table, can only be used on a TableRelation
	DUCKDB_API virtual void Delete(const string &condition = string());
	//! Create a relation from calling a table in/out function on the input relation
	//! Create a relation from calling a table in/out function on the input relation
	DUCKDB_API shared_ptr<Relation> TableFunction(const std::string &fname, const vector<Value> &values);
	DUCKDB_API shared_ptr<Relation> TableFunction(const std::string &fname, const vector<Value> &values,
	                                              const named_parameter_map_t &named_parameters);

public:
	//! Whether or not the relation inherits column bindings from its child or not, only relevant for binding
	virtual bool InheritsColumnBindings() {
		return false;
	}
	virtual Relation *ChildRelation() {
		return nullptr;
	}
	void AddExternalDependency(shared_ptr<ExternalDependency> dependency);
	DUCKDB_API vector<shared_ptr<ExternalDependency>> GetAllDependencies();

protected:
	DUCKDB_API string RenderWhitespace(idx_t depth);

public:
	template <class TARGET>
	TARGET &Cast() {
		DynamicCastCheck<TARGET>(this);
		return reinterpret_cast<TARGET &>(*this);
	}
	template <class TARGET>
	const TARGET &Cast() const {
		DynamicCastCheck<TARGET>(this);
		return reinterpret_cast<const TARGET &>(*this);
	}
};

} // namespace duckdb




//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/main/profiling_node.hpp
//
//
//===----------------------------------------------------------------------===//

















namespace duckdb {

//! Recursive tree mirroring the operator tree.
class ProfilingNode {
public:
	explicit ProfilingNode() {
	}
	virtual ~ProfilingNode() {};

private:
	ProfilingInfo profiling_info;

public:
	idx_t depth = 0;
	vector<unique_ptr<ProfilingNode>> children;

public:
	idx_t GetChildCount() {
		return children.size();
	}
	ProfilingInfo &GetProfilingInfo() {
		return profiling_info;
	}
	const ProfilingInfo &GetProfilingInfo() const {
		return profiling_info;
	}
	optional_ptr<ProfilingNode> GetChild(idx_t idx) {
		return children[idx].get();
	}
	optional_ptr<ProfilingNode> AddChild(unique_ptr<ProfilingNode> child) {
		children.push_back(std::move(child));
		return children.back().get();
	}
};

} // namespace duckdb


namespace duckdb {

class ColumnDataCollection;
class ClientContext;

class DatabaseInstance;
class DuckDB;
class LogicalOperator;
class SelectStatement;
struct CSVReaderOptions;

typedef void (*warning_callback_t)(std::string);

//! A connection to a database. This represents a (client) connection that can
//! be used to query the database.
class Connection {
public:
	DUCKDB_API explicit Connection(DuckDB &database);
	DUCKDB_API explicit Connection(DatabaseInstance &database);
	// disable copy constructors
	Connection(const Connection &other) = delete;
	Connection &operator=(const Connection &) = delete;
	//! enable move constructors
	DUCKDB_API Connection(Connection &&other) noexcept;
	DUCKDB_API Connection &operator=(Connection &&) noexcept;
	DUCKDB_API ~Connection();

	shared_ptr<ClientContext> context;
	warning_callback_t warning_cb;

public:
	//! Returns query profiling information for the current query
	DUCKDB_API string GetProfilingInformation(ProfilerPrintFormat format = ProfilerPrintFormat::QUERY_TREE);

	//! Returns the first node of the query profiling tree
	DUCKDB_API optional_ptr<ProfilingNode> GetProfilingTree();

	//! Interrupt execution of the current query
	DUCKDB_API void Interrupt();

	//! Enable query profiling
	DUCKDB_API void EnableProfiling();
	//! Disable query profiling
	DUCKDB_API void DisableProfiling();

	//! Enable aggressive verification/testing of queries, should only be used in testing
	DUCKDB_API void EnableQueryVerification();
	DUCKDB_API void DisableQueryVerification();
	//! Force parallel execution, even for smaller tables. Should only be used in testing.
	DUCKDB_API void ForceParallelism();

	//! Issues a query to the database and returns a QueryResult. This result can be either a StreamQueryResult or a
	//! MaterializedQueryResult. The result can be stepped through with calls to Fetch(). Note that there can only be
	//! one active StreamQueryResult per Connection object. Calling SendQuery() will invalidate any previously existing
	//! StreamQueryResult.
	DUCKDB_API unique_ptr<QueryResult> SendQuery(const string &query);
	//! Issues a query to the database and materializes the result (if necessary). Always returns a
	//! MaterializedQueryResult.
	DUCKDB_API unique_ptr<MaterializedQueryResult> Query(const string &query);
	//! Issues a query to the database and materializes the result (if necessary). Always returns a
	//! MaterializedQueryResult.
	DUCKDB_API unique_ptr<MaterializedQueryResult> Query(unique_ptr<SQLStatement> statement);
	// prepared statements
	template <typename... ARGS>
	unique_ptr<QueryResult> Query(const string &query, ARGS... args) {
		vector<Value> values;
		return QueryParamsRecursive(query, values, args...);
	}

	//! Issues a query to the database and returns a Pending Query Result. Note that "query" may only contain
	//! a single statement.
	DUCKDB_API unique_ptr<PendingQueryResult> PendingQuery(const string &query, bool allow_stream_result = false);
	//! Issues a query to the database and returns a Pending Query Result
	DUCKDB_API unique_ptr<PendingQueryResult> PendingQuery(unique_ptr<SQLStatement> statement,
	                                                       bool allow_stream_result = false);

	//! Prepare the specified query, returning a prepared statement object
	DUCKDB_API unique_ptr<PreparedStatement> Prepare(const string &query);
	//! Prepare the specified statement, returning a prepared statement object
	DUCKDB_API unique_ptr<PreparedStatement> Prepare(unique_ptr<SQLStatement> statement);

	//! Get the table info of a specific table (in the default schema), or nullptr if it cannot be found
	DUCKDB_API unique_ptr<TableDescription> TableInfo(const string &table_name);
	//! Get the table info of a specific table, or nullptr if it cannot be found
	DUCKDB_API unique_ptr<TableDescription> TableInfo(const string &schema_name, const string &table_name);

	//! Extract a set of SQL statements from a specific query
	DUCKDB_API vector<unique_ptr<SQLStatement>> ExtractStatements(const string &query);
	//! Extract the logical plan that corresponds to a query
	DUCKDB_API unique_ptr<LogicalOperator> ExtractPlan(const string &query);

	//! Appends a DataChunk to the specified table
	DUCKDB_API void Append(TableDescription &description, DataChunk &chunk);
	//! Appends a ColumnDataCollection to the specified table
	DUCKDB_API void Append(TableDescription &description, ColumnDataCollection &collection);

	//! Returns a relation that produces a table from this connection
	DUCKDB_API shared_ptr<Relation> Table(const string &tname);
	DUCKDB_API shared_ptr<Relation> Table(const string &schema_name, const string &table_name);
	//! Returns a relation that produces a view from this connection
	DUCKDB_API shared_ptr<Relation> View(const string &tname);
	DUCKDB_API shared_ptr<Relation> View(const string &schema_name, const string &table_name);
	//! Returns a relation that calls a specified table function
	DUCKDB_API shared_ptr<Relation> TableFunction(const string &tname);
	DUCKDB_API shared_ptr<Relation> TableFunction(const string &tname, const vector<Value> &values,
	                                              const named_parameter_map_t &named_parameters);
	DUCKDB_API shared_ptr<Relation> TableFunction(const string &tname, const vector<Value> &values);
	//! Returns a relation that produces values
	DUCKDB_API shared_ptr<Relation> Values(const vector<vector<Value>> &values);
	DUCKDB_API shared_ptr<Relation> Values(const vector<vector<Value>> &values, const vector<string> &column_names,
	                                       const string &alias = "values");
	DUCKDB_API shared_ptr<Relation> Values(const string &values);
	DUCKDB_API shared_ptr<Relation> Values(const string &values, const vector<string> &column_names,
	                                       const string &alias = "values");

	//! Reads CSV file
	DUCKDB_API shared_ptr<Relation> ReadCSV(const string &csv_file);
	DUCKDB_API shared_ptr<Relation> ReadCSV(const vector<string> &csv_input, named_parameter_map_t &&options);
	DUCKDB_API shared_ptr<Relation> ReadCSV(const string &csv_input, named_parameter_map_t &&options);
	DUCKDB_API shared_ptr<Relation> ReadCSV(const string &csv_file, const vector<string> &columns);

	//! Reads Parquet file
	DUCKDB_API shared_ptr<Relation> ReadParquet(const string &parquet_file, bool binary_as_string);
	//! Returns a relation from a query
	DUCKDB_API shared_ptr<Relation> RelationFromQuery(const string &query, const string &alias = "queryrelation",
	                                                  const string &error = "Expected a single SELECT statement");
	DUCKDB_API shared_ptr<Relation> RelationFromQuery(unique_ptr<SelectStatement> select_stmt,
	                                                  const string &alias = "queryrelation", const string &query = "");

	//! Returns a substrait BLOB from a valid query
	DUCKDB_API string GetSubstrait(const string &query);
	//! Returns a Query Result from a substrait blob
	DUCKDB_API unique_ptr<QueryResult> FromSubstrait(const string &proto);
	//! Returns a substrait BLOB from a valid query
	DUCKDB_API string GetSubstraitJSON(const string &query);
	//! Returns a Query Result from a substrait JSON
	DUCKDB_API unique_ptr<QueryResult> FromSubstraitJSON(const string &json);
	DUCKDB_API void BeginTransaction();
	DUCKDB_API void Commit();
	DUCKDB_API void Rollback();
	DUCKDB_API void SetAutoCommit(bool auto_commit);
	DUCKDB_API bool IsAutoCommit();
	DUCKDB_API bool HasActiveTransaction();

	//! Fetch a list of table names that are required for a given query
	DUCKDB_API unordered_set<string> GetTableNames(const string &query);

	// NOLINTBEGIN
	template <typename TR, typename... ARGS>
	void CreateScalarFunction(const string &name, TR (*udf_func)(ARGS...)) {
		scalar_function_t function = UDFWrapper::CreateScalarFunction<TR, ARGS...>(name, udf_func);
		UDFWrapper::RegisterFunction<TR, ARGS...>(name, function, *context);
	}

	template <typename TR, typename... ARGS>
	void CreateScalarFunction(const string &name, vector<LogicalType> args, LogicalType ret_type,
	                          TR (*udf_func)(ARGS...)) {
		scalar_function_t function = UDFWrapper::CreateScalarFunction<TR, ARGS...>(name, args, ret_type, udf_func);
		UDFWrapper::RegisterFunction(name, args, ret_type, function, *context);
	}

	template <typename TR, typename... ARGS>
	void CreateVectorizedFunction(const string &name, scalar_function_t udf_func,
	                              LogicalType varargs = LogicalType::INVALID) {
		UDFWrapper::RegisterFunction<TR, ARGS...>(name, udf_func, *context, std::move(varargs));
	}

	void CreateVectorizedFunction(const string &name, vector<LogicalType> args, LogicalType ret_type,
	                              scalar_function_t udf_func, LogicalType varargs = LogicalType::INVALID) {
		UDFWrapper::RegisterFunction(name, std::move(args), std::move(ret_type), std::move(udf_func), *context,
		                             std::move(varargs));
	}

	//------------------------------------- Aggreate Functions ----------------------------------------//
	template <typename UDF_OP, typename STATE, typename TR, typename TA>
	void CreateAggregateFunction(const string &name) {
		AggregateFunction function = UDFWrapper::CreateAggregateFunction<UDF_OP, STATE, TR, TA>(name);
		UDFWrapper::RegisterAggrFunction(function, *context);
	}

	template <typename UDF_OP, typename STATE, typename TR, typename TA, typename TB>
	void CreateAggregateFunction(const string &name) {
		AggregateFunction function = UDFWrapper::CreateAggregateFunction<UDF_OP, STATE, TR, TA, TB>(name);
		UDFWrapper::RegisterAggrFunction(function, *context);
	}

	template <typename UDF_OP, typename STATE, typename TR, typename TA>
	void CreateAggregateFunction(const string &name, LogicalType ret_type, LogicalType input_type_a) {
		AggregateFunction function =
		    UDFWrapper::CreateAggregateFunction<UDF_OP, STATE, TR, TA>(name, ret_type, input_type_a);
		UDFWrapper::RegisterAggrFunction(function, *context);
	}

	template <typename UDF_OP, typename STATE, typename TR, typename TA, typename TB>
	void CreateAggregateFunction(const string &name, LogicalType ret_type, LogicalType input_type_a,
	                             LogicalType input_type_b) {
		AggregateFunction function =
		    UDFWrapper::CreateAggregateFunction<UDF_OP, STATE, TR, TA, TB>(name, ret_type, input_type_a, input_type_b);
		UDFWrapper::RegisterAggrFunction(function, *context);
	}

	void CreateAggregateFunction(const string &name, const vector<LogicalType> &arguments,
	                             const LogicalType &return_type, aggregate_size_t state_size,
	                             aggregate_initialize_t initialize, aggregate_update_t update,
	                             aggregate_combine_t combine, aggregate_finalize_t finalize,
	                             aggregate_simple_update_t simple_update = nullptr,
	                             bind_aggregate_function_t bind = nullptr,
	                             aggregate_destructor_t destructor = nullptr) {
		AggregateFunction function =
		    UDFWrapper::CreateAggregateFunction(name, arguments, return_type, state_size, initialize, update, combine,
		                                        finalize, simple_update, bind, destructor);
		UDFWrapper::RegisterAggrFunction(function, *context);
	}
	// NOLINTEND

private:
	unique_ptr<QueryResult> QueryParamsRecursive(const string &query, vector<Value> &values);

	template <typename T, typename... ARGS>
	unique_ptr<QueryResult> QueryParamsRecursive(const string &query, vector<Value> &values, T value, ARGS... args) {
		values.push_back(Value::CreateValue<T>(value));
		return QueryParamsRecursive(query, values, args...);
	}
};

} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/main/database.hpp
//
//
//===----------------------------------------------------------------------===//






//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/main/extension.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {
class DuckDB;

//! The Extension class is the base class used to define extensions
class Extension {
public:
	DUCKDB_API virtual ~Extension();

	DUCKDB_API virtual void Load(DuckDB &db) = 0;
	DUCKDB_API virtual std::string Name() = 0;
	DUCKDB_API virtual std::string Version() const {
		return "";
	}
};

enum class ExtensionABIType : uint8_t {
	UNKNOWN = 0,
	CPP = 1,
	C_STRUCT = 2,
};

//! The parsed extension metadata footer
struct ParsedExtensionMetaData {
	static constexpr const idx_t FOOTER_SIZE = 512;
	static constexpr const idx_t SIGNATURE_SIZE = 256;
	static constexpr const char *EXPECTED_MAGIC_VALUE = {
	    "4\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"};

	string magic_value;

	ExtensionABIType abi_type;

	string platform;
	// (only for ExtensionABIType::CPP) the DuckDB version this extension is compiled for
	string duckdb_version;
	// (only for ExtensionABIType::C_STRUCT) the CAPI version of the C_STRUCT
	string duckdb_capi_version;
	string extension_version;
	string signature;
	string extension_abi_metadata;

	bool AppearsValid() {
		return magic_value == EXPECTED_MAGIC_VALUE;
	}

	// Returns an error string describing which parts of the metadata are mismatcheds
	string GetInvalidMetadataError();
};

struct VersioningUtils {
	//! Note: only supports format v{major}.{minor}.{patch}
	static bool ParseSemver(string &semver, idx_t &major_out, idx_t &minor_out, idx_t &patch_out);

	//! Note: only supports format v{major}.{minor}.{patch}
	static bool IsSupportedCAPIVersion(string &capi_version_string);
	static bool IsSupportedCAPIVersion(idx_t major, idx_t minor, idx_t patch);
};

} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/main/extension_install_info.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {
class FileSystem;

enum class ExtensionInstallMode : uint8_t {
	// Fallback for when install info is missing
	UNKNOWN = 0,
	//! Extension was installed using a url deduced from a repository base url
	REPOSITORY = 1,
	//! Extension was install from a custom path, this could be either local or remote
	CUSTOM_PATH = 2,
	//! Extension was statically linked
	STATICALLY_LINKED = 3,
	//! Extension is not installed, for example the extension might be directly loaded without installing
	NOT_INSTALLED = 4
};

struct ExtensionLoadedInfo {
	string description;
};

class ExtensionInstallInfo {
public:
	//! How the extension was installed
	ExtensionInstallMode mode = ExtensionInstallMode::UNKNOWN;
	//! (optional) Full path where the extension came from
	string full_path;
	//! (optional) Repository url where the extension came from
	string repository_url;
	//! (optional) Version of the extension
	string version;
	//! (optional) ETag of last fetched resource
	string etag;

	void Serialize(Serializer &serializer) const;

	//! Try to read install info. returns ExtensionInstallMode::UNKNOWN on missing file, and throws on corrupt file
	static unique_ptr<ExtensionInstallInfo> TryReadInfoFile(FileSystem &fs, const string &info_file_path,
	                                                        const string &extension_name);

	static unique_ptr<ExtensionInstallInfo> Deserialize(Deserializer &deserializer);
};

struct ExtensionRepository {
	//! All currently available repositories
	static constexpr const char *CORE_REPOSITORY_URL = "http://extensions.duckdb.org";
	static constexpr const char *CORE_NIGHTLY_REPOSITORY_URL = "http://nightly-extensions.duckdb.org";
	static constexpr const char *COMMUNITY_REPOSITORY_URL = "http://community-extensions.duckdb.org";

	//! Debugging repositories (target local, relative paths that are produced by DuckDB's build system)
	static constexpr const char *BUILD_DEBUG_REPOSITORY_PATH = "./build/debug/repository";
	static constexpr const char *BUILD_RELEASE_REPOSITORY_PATH = "./build/release/repository";

	//! The default is CORE
	static constexpr const char *DEFAULT_REPOSITORY_URL = CORE_REPOSITORY_URL;

	//! Returns the repository name is this is a known repository, or the full url if it is not
	static string GetRepository(const string &repository_url);
	//! Try to convert a repository to a url, will return empty string if the repository is unknown
	static string TryGetRepositoryUrl(const string &repository);
	//! Try to convert a url to a known repository name, will return empty string if the repository is unknown
	static string TryConvertUrlToKnownRepository(const string &url);

	//! Get the default repository, optionally passing a config to allow
	static ExtensionRepository GetDefaultRepository(optional_ptr<DBConfig> config);
	static ExtensionRepository GetDefaultRepository(ClientContext &context);

	static ExtensionRepository GetCoreRepository();
	static ExtensionRepository GetRepositoryByUrl(const string &url);

	ExtensionRepository();
	ExtensionRepository(const string &name, const string &url);

	//! Print the name if it has one, or the full path if not
	string ToReadableString();

	//! Repository name
	string name;
	//! Repository path/url
	string path;
};

} // namespace duckdb



namespace duckdb {
class BufferManager;
class DatabaseManager;
class StorageManager;
class Catalog;
class TransactionManager;
class ConnectionManager;
class FileSystem;
class TaskScheduler;
class ObjectCache;
struct AttachInfo;
struct AttachOptions;
class DatabaseFileSystem;
struct DatabaseCacheEntry;

struct ExtensionInfo {
	bool is_loaded;
	unique_ptr<ExtensionInstallInfo> install_info;
	unique_ptr<ExtensionLoadedInfo> load_info;
};

class DatabaseInstance : public enable_shared_from_this<DatabaseInstance> {
	friend class DuckDB;

public:
	DUCKDB_API DatabaseInstance();
	DUCKDB_API ~DatabaseInstance();

	DBConfig config;

public:
	BufferPool &GetBufferPool() const;
	DUCKDB_API SecretManager &GetSecretManager();
	DUCKDB_API BufferManager &GetBufferManager();
	DUCKDB_API const BufferManager &GetBufferManager() const;
	DUCKDB_API DatabaseManager &GetDatabaseManager();
	DUCKDB_API FileSystem &GetFileSystem();
	DUCKDB_API TaskScheduler &GetScheduler();
	DUCKDB_API ObjectCache &GetObjectCache();
	DUCKDB_API ConnectionManager &GetConnectionManager();
	DUCKDB_API ValidChecker &GetValidChecker();
	DUCKDB_API void SetExtensionLoaded(const string &extension_name, ExtensionInstallInfo &install_info);

	idx_t NumberOfThreads();

	DUCKDB_API static DatabaseInstance &GetDatabase(ClientContext &context);
	DUCKDB_API static const DatabaseInstance &GetDatabase(const ClientContext &context);

	DUCKDB_API const unordered_map<string, ExtensionInfo> &GetExtensions();
	DUCKDB_API bool ExtensionIsLoaded(const string &name);

	DUCKDB_API SettingLookupResult TryGetCurrentSetting(const string &key, Value &result) const;

	unique_ptr<AttachedDatabase> CreateAttachedDatabase(ClientContext &context, const AttachInfo &info,
	                                                    const AttachOptions &options);

	void AddExtensionInfo(const string &name, const ExtensionLoadedInfo &info);
	void SetDatabaseCacheEntry(shared_ptr<DatabaseCacheEntry> entry);

private:
	void Initialize(const char *path, DBConfig *config);
	void LoadExtensionSettings();
	void CreateMainDatabase();

	void Configure(DBConfig &config, const char *path);

private:
	shared_ptr<BufferManager> buffer_manager;
	unique_ptr<DatabaseManager> db_manager;
	unique_ptr<TaskScheduler> scheduler;
	unique_ptr<ObjectCache> object_cache;
	unique_ptr<ConnectionManager> connection_manager;
	unordered_map<string, ExtensionInfo> loaded_extensions_info;
	ValidChecker db_validity;
	unique_ptr<DatabaseFileSystem> db_file_system;
	shared_ptr<DatabaseCacheEntry> db_cache_entry;
};

//! The database object. This object holds the catalog and all the
//! database-specific meta information.
class DuckDB {
public:
	DUCKDB_API explicit DuckDB(const char *path = nullptr, DBConfig *config = nullptr);
	DUCKDB_API explicit DuckDB(const string &path, DBConfig *config = nullptr);
	DUCKDB_API explicit DuckDB(DatabaseInstance &instance);

	DUCKDB_API ~DuckDB();

	//! Reference to the actual database instance
	shared_ptr<DatabaseInstance> instance;

public:
	// Load a statically loaded extension by its class
	template <class T>
	void LoadStaticExtension() {
		T extension;
		if (ExtensionIsLoaded(extension.Name())) {
			return;
		}
		extension.Load(*this);
		ExtensionInstallInfo install_info;
		install_info.mode = ExtensionInstallMode::STATICALLY_LINKED;
		install_info.version = extension.Version();
		instance->SetExtensionLoaded(extension.Name(), install_info);
	}

	// DEPRECATED function that some extensions may still use to call their own Load method from the
	// _init function of their loadable extension. Don't use this. Instead opt for a static LoadInternal function called
	// from both the _init function and the Extension::Load. (see autocomplete extension)
	// TODO: when to remove this function?
	template <class T>
	void LoadExtension() {
		T extension;
		extension.Load(*this);
	}

	DUCKDB_API FileSystem &GetFileSystem();

	DUCKDB_API idx_t NumberOfThreads();
	DUCKDB_API static const char *SourceID();
	DUCKDB_API static const char *LibraryVersion();
	DUCKDB_API static idx_t StandardVectorSize();
	DUCKDB_API static string Platform();
	DUCKDB_API bool ExtensionIsLoaded(const string &name);
};

} // namespace duckdb


//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/main/appender.hpp
//
//
//===----------------------------------------------------------------------===//







namespace duckdb {

class ColumnDataCollection;
class ClientContext;
class DuckDB;
class TableCatalogEntry;
class Connection;

enum class AppenderType : uint8_t {
	LOGICAL, // Cast input -> LogicalType
	PHYSICAL // Cast input -> PhysicalType
};

//! The Appender class can be used to append elements to a table.
class BaseAppender {
public:
	//! The amount of tuples that will be gathered in the column data collection before flushing
	static constexpr const idx_t DEFAULT_FLUSH_COUNT = STANDARD_VECTOR_SIZE * 100ULL;

protected:
	Allocator &allocator;
	//! The append types
	vector<LogicalType> types;
	//! The buffered data for the append
	unique_ptr<ColumnDataCollection> collection;
	//! Internal chunk used for appends
	DataChunk chunk;
	//! The current column to append to
	idx_t column = 0;
	//! The type of the appender
	AppenderType appender_type;
	//! The amount of rows after which we flush the appender automatically
	idx_t flush_count = DEFAULT_FLUSH_COUNT;

protected:
	DUCKDB_API BaseAppender(Allocator &allocator, AppenderType type);
	DUCKDB_API BaseAppender(Allocator &allocator, vector<LogicalType> types, AppenderType type,
	                        idx_t flush_count = DEFAULT_FLUSH_COUNT);

public:
	DUCKDB_API virtual ~BaseAppender();

	//! Begins a new row append, after calling this the other AppendX() functions
	//! should be called the correct amount of times. After that,
	//! EndRow() should be called.
	DUCKDB_API void BeginRow();
	//! Finishes appending the current row.
	DUCKDB_API void EndRow();

	// Append functions
	template <class T>
	void Append(T value) = delete;

	DUCKDB_API void Append(const char *value, uint32_t length);

	// prepared statements
	template <typename... ARGS>
	void AppendRow(ARGS... args) {
		BeginRow();
		AppendRowRecursive(args...);
	}

	//! Commit the changes made by the appender.
	DUCKDB_API void Flush();
	//! Flush the changes made by the appender and close it. The appender cannot be used after this point
	DUCKDB_API void Close();

	vector<LogicalType> &GetTypes() {
		return types;
	}
	idx_t CurrentColumn() const {
		return column;
	}
	DUCKDB_API void AppendDataChunk(DataChunk &value);

protected:
	void Destructor();
	virtual void FlushInternal(ColumnDataCollection &collection) = 0;
	void InitializeChunk();
	void FlushChunk();

	template <class T>
	void AppendValueInternal(T value);
	template <class SRC, class DST>
	void AppendValueInternal(Vector &vector, SRC input);
	template <class SRC, class DST>
	void AppendDecimalValueInternal(Vector &vector, SRC input);

	void AppendRowRecursive() {
		EndRow();
	}

	template <typename T, typename... ARGS>
	void AppendRowRecursive(T value, ARGS... args) {
		Append<T>(value);
		AppendRowRecursive(args...);
	}

	void AppendValue(const Value &value);
};

class Appender : public BaseAppender {
	//! A reference to a database connection that created this appender
	shared_ptr<ClientContext> context;
	//! The table description (including column names)
	unique_ptr<TableDescription> description;
	//! The default expressions
	unordered_map<idx_t, Value> default_values;

public:
	DUCKDB_API Appender(Connection &con, const string &schema_name, const string &table_name);
	DUCKDB_API Appender(Connection &con, const string &table_name);
	DUCKDB_API ~Appender() override;

public:
	void AppendDefault();

protected:
	void FlushInternal(ColumnDataCollection &collection) override;
};

class InternalAppender : public BaseAppender {
	//! The client context
	ClientContext &context;
	//! The internal table entry to append to
	TableCatalogEntry &table;

public:
	DUCKDB_API InternalAppender(ClientContext &context, TableCatalogEntry &table,
	                            idx_t flush_count = DEFAULT_FLUSH_COUNT);
	DUCKDB_API ~InternalAppender() override;

protected:
	void FlushInternal(ColumnDataCollection &collection) override;
};

template <>
DUCKDB_API void BaseAppender::Append(bool value);
template <>
DUCKDB_API void BaseAppender::Append(int8_t value);
template <>
DUCKDB_API void BaseAppender::Append(int16_t value);
template <>
DUCKDB_API void BaseAppender::Append(int32_t value);
template <>
DUCKDB_API void BaseAppender::Append(int64_t value);
template <>
DUCKDB_API void BaseAppender::Append(hugeint_t value);
template <>
DUCKDB_API void BaseAppender::Append(uhugeint_t value);
template <>
DUCKDB_API void BaseAppender::Append(uint8_t value);
template <>
DUCKDB_API void BaseAppender::Append(uint16_t value);
template <>
DUCKDB_API void BaseAppender::Append(uint32_t value);
template <>
DUCKDB_API void BaseAppender::Append(uint64_t value);
template <>
DUCKDB_API void BaseAppender::Append(float value);
template <>
DUCKDB_API void BaseAppender::Append(double value);
template <>
DUCKDB_API void BaseAppender::Append(date_t value);
template <>
DUCKDB_API void BaseAppender::Append(dtime_t value);
template <>
DUCKDB_API void BaseAppender::Append(timestamp_t value);
template <>
DUCKDB_API void BaseAppender::Append(interval_t value);
template <>
DUCKDB_API void BaseAppender::Append(const char *value);
template <>
DUCKDB_API void BaseAppender::Append(string_t value);
template <>
DUCKDB_API void BaseAppender::Append(Value value);
template <>
DUCKDB_API void BaseAppender::Append(std::nullptr_t value);

} // namespace duckdb

////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// THIS FILE IS GENERATED BY apache/arrow, DO NOT EDIT MANUALLY //
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////

// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

/// \file adbc.h ADBC: Arrow Database connectivity
///
/// An Arrow-based interface between applications and database
/// drivers.  ADBC aims to provide a vendor-independent API for SQL
/// and Substrait-based database access that is targeted at
/// analytics/OLAP use cases.
///
/// This API is intended to be implemented directly by drivers and
/// used directly by client applications.  To assist portability
/// between different vendors, a "driver manager" library is also
/// provided, which implements this same API, but dynamically loads
/// drivers internally and forwards calls appropriately.
///
/// ADBC uses structs with free functions that operate on those
/// structs to model objects.
///
/// In general, objects allow serialized access from multiple threads,
/// but not concurrent access.  Specific implementations may permit
/// multiple threads.
///
/// \version 1.1.0



#include <stddef.h>
#include <stdint.h>


/// \defgroup Arrow C Data Interface
/// Definitions for the C Data Interface/C Stream Interface.
///
/// See https://arrow.apache.org/docs/format/CDataInterface.html
///
/// @{

//! @cond Doxygen_Suppress
#ifdef __cplusplus
extern "C" {
#endif

// Extra guard for versions of Arrow without the canonical guard
#ifndef ARROW_FLAG_DICTIONARY_ORDERED

#ifndef ARROW_C_DATA_INTERFACE
#define ARROW_C_DATA_INTERFACE

#define ARROW_FLAG_DICTIONARY_ORDERED 1
#define ARROW_FLAG_NULLABLE           2
#define ARROW_FLAG_MAP_KEYS_SORTED    4

struct ArrowSchema {
	// Array type description
	const char *format;
	const char *name;
	const char *metadata;
	int64_t flags;
	int64_t n_children;
	struct ArrowSchema **children;
	struct ArrowSchema *dictionary;

	// Release callback
	void (*release)(struct ArrowSchema *);
	// Opaque producer-specific data
	void *private_data;
};

struct ArrowArray {
	// Array data description
	int64_t length;
	int64_t null_count;
	int64_t offset;
	int64_t n_buffers;
	int64_t n_children;
	const void **buffers;
	struct ArrowArray **children;
	struct ArrowArray *dictionary;

	// Release callback
	void (*release)(struct ArrowArray *);
	// Opaque producer-specific data
	void *private_data;
};

#endif // ARROW_C_DATA_INTERFACE

#ifndef ARROW_C_STREAM_INTERFACE
#define ARROW_C_STREAM_INTERFACE

struct ArrowArrayStream {
	// Callback to get the stream type
	// (will be the same for all arrays in the stream).
	//
	// Return value: 0 if successful, an `errno`-compatible error code otherwise.
	//
	// If successful, the ArrowSchema must be released independently from the stream.
	int (*get_schema)(struct ArrowArrayStream *, struct ArrowSchema *out);

	// Callback to get the next array
	// (if no error and the array is released, the stream has ended)
	//
	// Return value: 0 if successful, an `errno`-compatible error code otherwise.
	//
	// If successful, the ArrowArray must be released independently from the stream.
	int (*get_next)(struct ArrowArrayStream *, struct ArrowArray *out);

	// Callback to get optional detailed error information.
	// This must only be called if the last stream operation failed
	// with a non-0 return code.
	//
	// Return value: pointer to a null-terminated character array describing
	// the last error, or NULL if no description is available.
	//
	// The returned pointer is only valid until the next operation on this stream
	// (including release).
	const char *(*get_last_error)(struct ArrowArrayStream *);

	// Release callback: release the stream's own resources.
	// Note that arrays returned by `get_next` must be individually released.
	void (*release)(struct ArrowArrayStream *);

	// Opaque producer-specific data
	void *private_data;
};

#endif // ARROW_C_STREAM_INTERFACE
#endif // ARROW_FLAG_DICTIONARY_ORDERED

//! @endcond

/// @}

#ifndef ADBC_EXPORTING
#define ADBC_EXPORTING

// Storage class macros for Windows
// Allow overriding/aliasing with application-defined macros
#if !defined(ADBC_EXPORT)
#if defined(_WIN32)
#if defined(ADBC_EXPORTING)
#define ADBC_EXPORT __declspec(dllexport)
#else
#define ADBC_EXPORT __declspec(dllimport)
#endif // defined(ADBC_EXPORTING)
#else
#define ADBC_EXPORT
#endif // defined(_WIN32)
#endif // !defined(ADBC_EXPORT)

/// \defgroup adbc-error-handling Error Handling
/// ADBC uses integer error codes to signal errors. To provide more
/// detail about errors, functions may also return an AdbcError via an
/// optional out parameter, which can be inspected. If provided, it is
/// the responsibility of the caller to zero-initialize the AdbcError
/// value.
///
/// @{

/// \brief Error codes for operations that may fail.
typedef uint8_t AdbcStatusCode;

/// \brief No error.
#define ADBC_STATUS_OK 0
/// \brief An unknown error occurred.
///
/// May indicate a driver-side or database-side error.
#define ADBC_STATUS_UNKNOWN 1
/// \brief The operation is not implemented or supported.
///
/// May indicate a driver-side or database-side error.
#define ADBC_STATUS_NOT_IMPLEMENTED 2
/// \brief A requested resource was not found.
///
/// May indicate a driver-side or database-side error.
#define ADBC_STATUS_NOT_FOUND 3
/// \brief A requested resource already exists.
///
/// May indicate a driver-side or database-side error.
#define ADBC_STATUS_ALREADY_EXISTS 4
/// \brief The arguments are invalid, likely a programming error.
///
/// For instance, they may be of the wrong format, or out of range.
///
/// May indicate a driver-side or database-side error.
#define ADBC_STATUS_INVALID_ARGUMENT 5
/// \brief The preconditions for the operation are not met, likely a
///   programming error.
///
/// For instance, the object may be uninitialized, or may have not
/// been fully configured.
///
/// May indicate a driver-side or database-side error.
#define ADBC_STATUS_INVALID_STATE 6
/// \brief Invalid data was processed (not a programming error).
///
/// For instance, a division by zero may have occurred during query
/// execution.
///
/// May indicate a database-side error only.
#define ADBC_STATUS_INVALID_DATA 7
/// \brief The database's integrity was affected.
///
/// For instance, a foreign key check may have failed, or a uniqueness
/// constraint may have been violated.
///
/// May indicate a database-side error only.
#define ADBC_STATUS_INTEGRITY 8
/// \brief An error internal to the driver or database occurred.
///
/// May indicate a driver-side or database-side error.
#define ADBC_STATUS_INTERNAL 9
/// \brief An I/O error occurred.
///
/// For instance, a remote service may be unavailable.
///
/// May indicate a driver-side or database-side error.
#define ADBC_STATUS_IO 10
/// \brief The operation was cancelled, not due to a timeout.
///
/// May indicate a driver-side or database-side error.
#define ADBC_STATUS_CANCELLED 11
/// \brief The operation was cancelled due to a timeout.
///
/// May indicate a driver-side or database-side error.
#define ADBC_STATUS_TIMEOUT 12
/// \brief Authentication failed.
///
/// May indicate a database-side error only.
#define ADBC_STATUS_UNAUTHENTICATED 13
/// \brief The client is not authorized to perform the given operation.
///
/// May indicate a database-side error only.
#define ADBC_STATUS_UNAUTHORIZED 14

/// \brief Inform the driver/driver manager that we are using the extended
///   AdbcError struct from ADBC 1.1.0.
///
/// See the AdbcError documentation for usage.
///
/// \since ADBC API revision 1.1.0
#define ADBC_ERROR_VENDOR_CODE_PRIVATE_DATA INT32_MIN

/// \brief A detailed error message for an operation.
///
/// The caller must zero-initialize this struct (clarified in ADBC 1.1.0).
///
/// The structure was extended in ADBC 1.1.0.  Drivers and clients using ADBC
/// 1.0.0 will not have the private_data or private_driver fields.  Drivers
/// should read/write these fields if and only if vendor_code is equal to
/// ADBC_ERROR_VENDOR_CODE_PRIVATE_DATA.  Clients are required to initialize
/// this struct to avoid the possibility of uninitialized values confusing the
/// driver.
struct ADBC_EXPORT AdbcError {
	/// \brief The error message.
	char *message;

	/// \brief A vendor-specific error code, if applicable.
	int32_t vendor_code;

	/// \brief A SQLSTATE error code, if provided, as defined by the
	///   SQL:2003 standard.  If not set, it should be set to
	///   "\0\0\0\0\0".
	char sqlstate[5];

	/// \brief Release the contained error.
	///
	/// Unlike other structures, this is an embedded callback to make it
	/// easier for the driver manager and driver to cooperate.
	void (*release)(struct AdbcError *error);

	/// \brief Opaque implementation-defined state.
	///
	/// This field may not be used unless vendor_code is
	/// ADBC_ERROR_VENDOR_CODE_PRIVATE_DATA.  If present, this field is NULLPTR
	/// iff the error is unintialized/freed.
	///
	/// \since ADBC API revision 1.1.0
	void *private_data;

	/// \brief The associated driver (used by the driver manager to help
	///   track state).
	///
	/// This field may not be used unless vendor_code is
	/// ADBC_ERROR_VENDOR_CODE_PRIVATE_DATA.
	///
	/// \since ADBC API revision 1.1.0
	struct AdbcDriver *private_driver;
};

#ifdef __cplusplus
/// \brief A helper to initialize the full AdbcError structure.
///
/// \since ADBC API revision 1.1.0
#define ADBC_ERROR_INIT                                                                                                \
	(AdbcError {nullptr, ADBC_ERROR_VENDOR_CODE_PRIVATE_DATA, {0, 0, 0, 0, 0}, nullptr, nullptr, nullptr})
#else
/// \brief A helper to initialize the full AdbcError structure.
///
/// \since ADBC API revision 1.1.0
#define ADBC_ERROR_INIT                                                                                                \
	((struct AdbcError) {NULL, ADBC_ERROR_VENDOR_CODE_PRIVATE_DATA, {0, 0, 0, 0, 0}, NULL, NULL, NULL})
#endif

/// \brief The size of the AdbcError structure in ADBC 1.0.0.
///
/// Drivers written for ADBC 1.1.0 and later should never touch more than this
/// portion of an AdbcDriver struct when vendor_code is not
/// ADBC_ERROR_VENDOR_CODE_PRIVATE_DATA.
///
/// \since ADBC API revision 1.1.0
#define ADBC_ERROR_1_0_0_SIZE (offsetof(struct AdbcError, private_data))
/// \brief The size of the AdbcError structure in ADBC 1.1.0.
///
/// Drivers written for ADBC 1.1.0 and later should never touch more than this
/// portion of an AdbcDriver struct when vendor_code is
/// ADBC_ERROR_VENDOR_CODE_PRIVATE_DATA.
///
/// \since ADBC API revision 1.1.0
#define ADBC_ERROR_1_1_0_SIZE (sizeof(struct AdbcError))

/// \brief Extra key-value metadata for an error.
///
/// The fields here are owned by the driver and should not be freed.  The
/// fields here are invalidated when the release callback in AdbcError is
/// called.
///
/// \since ADBC API revision 1.1.0
struct ADBC_EXPORT AdbcErrorDetail {
	/// \brief The metadata key.
	const char *key;
	/// \brief The binary metadata value.
	const uint8_t *value;
	/// \brief The length of the metadata value.
	size_t value_length;
};

/// \brief Get the number of metadata values available in an error.
///
/// \since ADBC API revision 1.1.0
ADBC_EXPORT
int AdbcErrorGetDetailCount(const struct AdbcError *error);

/// \brief Get a metadata value in an error by index.
///
/// If index is invalid, returns an AdbcErrorDetail initialized with NULL/0
/// fields.
///
/// \since ADBC API revision 1.1.0
ADBC_EXPORT
struct AdbcErrorDetail AdbcErrorGetDetail(const struct AdbcError *error, int index);

/// \brief Get an ADBC error from an ArrowArrayStream created by a driver.
///
/// This allows retrieving error details and other metadata that would
/// normally be suppressed by the Arrow C Stream Interface.
///
/// The caller MUST NOT release the error; it is managed by the release
/// callback in the stream itself.
///
/// \param[in] stream The stream to query.
/// \param[out] status The ADBC status code, or ADBC_STATUS_OK if there is no
///   error.  Not written to if the stream does not contain an ADBC error or
///   if the pointer is NULL.
/// \return NULL if not supported.
/// \since ADBC API revision 1.1.0
ADBC_EXPORT
const struct AdbcError *AdbcErrorFromArrayStream(struct ArrowArrayStream *stream, AdbcStatusCode *status);

/// @}

/// \defgroup adbc-constants Constants
/// @{

/// \brief ADBC revision 1.0.0.
///
/// When passed to an AdbcDriverInitFunc(), the driver parameter must
/// point to an AdbcDriver.
#define ADBC_VERSION_1_0_0 1000000

/// \brief ADBC revision 1.1.0.
///
/// When passed to an AdbcDriverInitFunc(), the driver parameter must
/// point to an AdbcDriver.
///
/// \since ADBC API revision 1.1.0
#define ADBC_VERSION_1_1_0 1001000

/// \brief Canonical option value for enabling an option.
///
/// For use as the value in SetOption calls.
#define ADBC_OPTION_VALUE_ENABLED "true"
/// \brief Canonical option value for disabling an option.
///
/// For use as the value in SetOption calls.
#define ADBC_OPTION_VALUE_DISABLED "false"

/// \brief Canonical option name for URIs.
///
/// Should be used as the expected option name to specify a URI for
/// any ADBC driver.
///
/// The type is char*.
///
/// \since ADBC API revision 1.1.0
#define ADBC_OPTION_URI "uri"
/// \brief Canonical option name for usernames.
///
/// Should be used as the expected option name to specify a username
/// to a driver for authentication.
///
/// The type is char*.
///
/// \since ADBC API revision 1.1.0
#define ADBC_OPTION_USERNAME "username"
/// \brief Canonical option name for passwords.
///
/// Should be used as the expected option name to specify a password
/// for authentication to a driver.
///
/// The type is char*.
///
/// \since ADBC API revision 1.1.0
#define ADBC_OPTION_PASSWORD "password"

/// \brief The database vendor/product name (e.g. the server name).
///   (type: utf8).
///
/// \see AdbcConnectionGetInfo
#define ADBC_INFO_VENDOR_NAME 0
/// \brief The database vendor/product version (type: utf8).
///
/// \see AdbcConnectionGetInfo
#define ADBC_INFO_VENDOR_VERSION 1
/// \brief The database vendor/product Arrow library version (type:
///   utf8).
///
/// \see AdbcConnectionGetInfo
#define ADBC_INFO_VENDOR_ARROW_VERSION 2

/// \brief The driver name (type: utf8).
///
/// \see AdbcConnectionGetInfo
#define ADBC_INFO_DRIVER_NAME 100
/// \brief The driver version (type: utf8).
///
/// \see AdbcConnectionGetInfo
#define ADBC_INFO_DRIVER_VERSION 101
/// \brief The driver Arrow library version (type: utf8).
///
/// \see AdbcConnectionGetInfo
#define ADBC_INFO_DRIVER_ARROW_VERSION 102
/// \brief The driver ADBC API version (type: int64).
///
/// The value should be one of the ADBC_VERSION constants.
///
/// \since ADBC API revision 1.1.0
/// \see AdbcConnectionGetInfo
/// \see ADBC_VERSION_1_0_0
/// \see ADBC_VERSION_1_1_0
#define ADBC_INFO_DRIVER_ADBC_VERSION 103

/// \brief Return metadata on catalogs, schemas, tables, and columns.
///
/// \see AdbcConnectionGetObjects
#define ADBC_OBJECT_DEPTH_ALL 0
/// \brief Return metadata on catalogs only.
///
/// \see AdbcConnectionGetObjects
#define ADBC_OBJECT_DEPTH_CATALOGS 1
/// \brief Return metadata on catalogs and schemas.
///
/// \see AdbcConnectionGetObjects
#define ADBC_OBJECT_DEPTH_DB_SCHEMAS 2
/// \brief Return metadata on catalogs, schemas, and tables.
///
/// \see AdbcConnectionGetObjects
#define ADBC_OBJECT_DEPTH_TABLES 3
/// \brief Return metadata on catalogs, schemas, tables, and columns.
///
/// \see AdbcConnectionGetObjects
#define ADBC_OBJECT_DEPTH_COLUMNS ADBC_OBJECT_DEPTH_ALL

/// \defgroup adbc-table-statistics ADBC Statistic Types
/// Standard statistic names for AdbcConnectionGetStatistics.
/// @{

/// \brief The dictionary-encoded name of the average byte width statistic.
#define ADBC_STATISTIC_AVERAGE_BYTE_WIDTH_KEY 0
/// \brief The average byte width statistic.  The average size in bytes of a
///   row in the column.  Value type is float64.
///
/// For example, this is roughly the average length of a string for a string
/// column.
#define ADBC_STATISTIC_AVERAGE_BYTE_WIDTH_NAME "adbc.statistic.byte_width"
/// \brief The dictionary-encoded name of the distinct value count statistic.
#define ADBC_STATISTIC_DISTINCT_COUNT_KEY 1
/// \brief The distinct value count (NDV) statistic.  The number of distinct
///   values in the column.  Value type is int64 (when not approximate) or
///   float64 (when approximate).
#define ADBC_STATISTIC_DISTINCT_COUNT_NAME "adbc.statistic.distinct_count"
/// \brief The dictionary-encoded name of the max byte width statistic.
#define ADBC_STATISTIC_MAX_BYTE_WIDTH_KEY 2
/// \brief The max byte width statistic.  The maximum size in bytes of a row
///   in the column.  Value type is int64 (when not approximate) or float64
///   (when approximate).
///
/// For example, this is the maximum length of a string for a string column.
#define ADBC_STATISTIC_MAX_BYTE_WIDTH_NAME "adbc.statistic.byte_width"
/// \brief The dictionary-encoded name of the max value statistic.
#define ADBC_STATISTIC_MAX_VALUE_KEY 3
/// \brief The max value statistic.  Value type is column-dependent.
#define ADBC_STATISTIC_MAX_VALUE_NAME "adbc.statistic.byte_width"
/// \brief The dictionary-encoded name of the min value statistic.
#define ADBC_STATISTIC_MIN_VALUE_KEY 4
/// \brief The min value statistic.  Value type is column-dependent.
#define ADBC_STATISTIC_MIN_VALUE_NAME "adbc.statistic.byte_width"
/// \brief The dictionary-encoded name of the null count statistic.
#define ADBC_STATISTIC_NULL_COUNT_KEY 5
/// \brief The null count statistic.  The number of values that are null in
///   the column.  Value type is int64 (when not approximate) or float64
///   (when approximate).
#define ADBC_STATISTIC_NULL_COUNT_NAME "adbc.statistic.null_count"
/// \brief The dictionary-encoded name of the row count statistic.
#define ADBC_STATISTIC_ROW_COUNT_KEY 6
/// \brief The row count statistic.  The number of rows in the column or
///   table.  Value type is int64 (when not approximate) or float64 (when
///   approximate).
#define ADBC_STATISTIC_ROW_COUNT_NAME "adbc.statistic.row_count"
/// @}

/// \brief The name of the canonical option for whether autocommit is
///   enabled.
///
/// The type is char*.
///
/// \see AdbcConnectionSetOption
#define ADBC_CONNECTION_OPTION_AUTOCOMMIT "adbc.connection.autocommit"

/// \brief The name of the canonical option for whether the current
///   connection should be restricted to being read-only.
///
/// The type is char*.
///
/// \see AdbcConnectionSetOption
#define ADBC_CONNECTION_OPTION_READ_ONLY "adbc.connection.readonly"

/// \brief The name of the canonical option for the current catalog.
///
/// The type is char*.
///
/// \see AdbcConnectionGetOption
/// \see AdbcConnectionSetOption
/// \since ADBC API revision 1.1.0
#define ADBC_CONNECTION_OPTION_CURRENT_CATALOG "adbc.connection.catalog"

/// \brief The name of the canonical option for the current schema.
///
/// The type is char*.
///
/// \see AdbcConnectionGetOption
/// \see AdbcConnectionSetOption
/// \since ADBC API revision 1.1.0
#define ADBC_CONNECTION_OPTION_CURRENT_DB_SCHEMA "adbc.connection.db_schema"

/// \brief The name of the canonical option for making query execution
///   nonblocking.
///
/// When enabled, AdbcStatementExecutePartitions will return
/// partitions as soon as they are available, instead of returning
/// them all at the end.  When there are no more to return, it will
/// return an empty set of partitions.  AdbcStatementExecuteQuery and
/// AdbcStatementExecuteSchema are not affected.
///
/// The default is ADBC_OPTION_VALUE_DISABLED.
///
/// The type is char*.
///
/// \see AdbcStatementSetOption
/// \since ADBC API revision 1.1.0
#define ADBC_STATEMENT_OPTION_INCREMENTAL "adbc.statement.exec.incremental"

/// \brief The name of the option for getting the progress of a query.
///
/// The value is not necessarily in any particular range or have any
/// particular units.  (For example, it might be a percentage, bytes of data,
/// rows of data, number of workers, etc.)  The max value can be retrieved via
/// ADBC_STATEMENT_OPTION_MAX_PROGRESS.  This represents the progress of
/// execution, not of consumption (i.e., it is independent of how much of the
/// result set has been read by the client via ArrowArrayStream.get_next().)
///
/// The type is double.
///
/// \see AdbcStatementGetOptionDouble
/// \since ADBC API revision 1.1.0
#define ADBC_STATEMENT_OPTION_PROGRESS "adbc.statement.exec.progress"

/// \brief The name of the option for getting the maximum progress of a query.
///
/// This is the value of ADBC_STATEMENT_OPTION_PROGRESS for a completed query.
/// If not supported, or if the value is nonpositive, then the maximum is not
/// known.  (For instance, the query may be fully streaming and the driver
/// does not know when the result set will end.)
///
/// The type is double.
///
/// \see AdbcStatementGetOptionDouble
/// \since ADBC API revision 1.1.0
#define ADBC_STATEMENT_OPTION_MAX_PROGRESS "adbc.statement.exec.max_progress"

/// \brief The name of the canonical option for setting the isolation
///   level of a transaction.
///
/// Should only be used in conjunction with autocommit disabled and
/// AdbcConnectionCommit / AdbcConnectionRollback. If the desired
/// isolation level is not supported by a driver, it should return an
/// appropriate error.
///
/// The type is char*.
///
/// \see AdbcConnectionSetOption
#define ADBC_CONNECTION_OPTION_ISOLATION_LEVEL "adbc.connection.transaction.isolation_level"

/// \brief Use database or driver default isolation level
///
/// \see AdbcConnectionSetOption
#define ADBC_OPTION_ISOLATION_LEVEL_DEFAULT "adbc.connection.transaction.isolation.default"

/// \brief The lowest isolation level. Dirty reads are allowed, so one
///   transaction may see not-yet-committed changes made by others.
///
/// \see AdbcConnectionSetOption
#define ADBC_OPTION_ISOLATION_LEVEL_READ_UNCOMMITTED "adbc.connection.transaction.isolation.read_uncommitted"

/// \brief Lock-based concurrency control keeps write locks until the
///   end of the transaction, but read locks are released as soon as a
///   SELECT is performed. Non-repeatable reads can occur in this
///   isolation level.
///
/// More simply put, Read Committed is an isolation level that guarantees
/// that any data read is committed at the moment it is read. It simply
/// restricts the reader from seeing any intermediate, uncommitted,
/// 'dirty' reads. It makes no promise whatsoever that if the transaction
/// re-issues the read, it will find the same data; data is free to change
/// after it is read.
///
/// \see AdbcConnectionSetOption
#define ADBC_OPTION_ISOLATION_LEVEL_READ_COMMITTED "adbc.connection.transaction.isolation.read_committed"

/// \brief Lock-based concurrency control keeps read AND write locks
///   (acquired on selection data) until the end of the transaction.
///
/// However, range-locks are not managed, so phantom reads can occur.
/// Write skew is possible at this isolation level in some systems.
///
/// \see AdbcConnectionSetOption
#define ADBC_OPTION_ISOLATION_LEVEL_REPEATABLE_READ "adbc.connection.transaction.isolation.repeatable_read"

/// \brief This isolation guarantees that all reads in the transaction
///   will see a consistent snapshot of the database and the transaction
///   should only successfully commit if no updates conflict with any
///   concurrent updates made since that snapshot.
///
/// \see AdbcConnectionSetOption
#define ADBC_OPTION_ISOLATION_LEVEL_SNAPSHOT "adbc.connection.transaction.isolation.snapshot"

/// \brief Serializability requires read and write locks to be released
///   only at the end of the transaction. This includes acquiring range-
///   locks when a select query uses a ranged WHERE clause to avoid
///   phantom reads.
///
/// \see AdbcConnectionSetOption
#define ADBC_OPTION_ISOLATION_LEVEL_SERIALIZABLE "adbc.connection.transaction.isolation.serializable"

/// \brief The central distinction between serializability and linearizability
///   is that serializability is a global property; a property of an entire
///   history of operations and transactions. Linearizability is a local
///   property; a property of a single operation/transaction.
///
/// Linearizability can be viewed as a special case of strict serializability
/// where transactions are restricted to consist of a single operation applied
/// to a single object.
///
/// \see AdbcConnectionSetOption
#define ADBC_OPTION_ISOLATION_LEVEL_LINEARIZABLE "adbc.connection.transaction.isolation.linearizable"

/// \defgroup adbc-statement-ingestion Bulk Data Ingestion
/// While it is possible to insert data via prepared statements, it can
/// be more efficient to explicitly perform a bulk insert.  For
/// compatible drivers, this can be accomplished by setting up and
/// executing a statement.  Instead of setting a SQL query or Substrait
/// plan, bind the source data via AdbcStatementBind, and set the name
/// of the table to be created via AdbcStatementSetOption and the
/// options below.  Then, call AdbcStatementExecute with a NULL for
/// the out parameter (to indicate you do not expect a result set).
///
/// @{

/// \brief The name of the target table for a bulk insert.
///
/// The driver should attempt to create the table if it does not
/// exist.  If the table exists but has a different schema,
/// ADBC_STATUS_ALREADY_EXISTS should be raised.  Else, data should be
/// appended to the target table.
///
/// The type is char*.
#define ADBC_INGEST_OPTION_TARGET_TABLE "adbc.ingest.target_table"
/// \brief Whether to create (the default) or append.
///
/// The type is char*.
#define ADBC_INGEST_OPTION_MODE "adbc.ingest.mode"
/// \brief Create the table and insert data; error if the table exists.
#define ADBC_INGEST_OPTION_MODE_CREATE "adbc.ingest.mode.create"
/// \brief Do not create the table, and insert data; error if the
///   table does not exist (ADBC_STATUS_NOT_FOUND) or does not match
///   the schema of the data to append (ADBC_STATUS_ALREADY_EXISTS).
#define ADBC_INGEST_OPTION_MODE_APPEND "adbc.ingest.mode.append"
/// \brief Create the table and insert data; drop the original table
///   if it already exists.
/// \since ADBC API revision 1.1.0
#define ADBC_INGEST_OPTION_MODE_REPLACE "adbc.ingest.mode.replace"
/// \brief Insert data; create the table if it does not exist, or
///   error if the table exists, but the schema does not match the
///   schema of the data to append (ADBC_STATUS_ALREADY_EXISTS).
/// \since ADBC API revision 1.1.0
#define ADBC_INGEST_OPTION_MODE_CREATE_APPEND "adbc.ingest.mode.create_append"

/// @}

/// @}

/// \defgroup adbc-database Database Initialization
/// Clients first initialize a database, then create a connection
/// (below).  This gives the implementation a place to initialize and
/// own any common connection state.  For example, in-memory databases
/// can place ownership of the actual database in this object.
/// @{

/// \brief An instance of a database.
///
/// Must be kept alive as long as any connections exist.
struct ADBC_EXPORT AdbcDatabase {
	/// \brief Opaque implementation-defined state.
	/// This field is NULLPTR iff the connection is unintialized/freed.
	void *private_data;
	/// \brief The associated driver (used by the driver manager to help
	///   track state).
	struct AdbcDriver *private_driver;
};

/// @}

/// \defgroup adbc-connection Connection Establishment
/// Functions for creating, using, and releasing database connections.
/// @{

/// \brief An active database connection.
///
/// Provides methods for query execution, managing prepared
/// statements, using transactions, and so on.
///
/// Connections are not required to be thread-safe, but they can be
/// used from multiple threads so long as clients take care to
/// serialize accesses to a connection.
struct ADBC_EXPORT AdbcConnection {
	/// \brief Opaque implementation-defined state.
	/// This field is NULLPTR iff the connection is unintialized/freed.
	void *private_data;
	/// \brief The associated driver (used by the driver manager to help
	///   track state).
	struct AdbcDriver *private_driver;
};

/// @}

/// \defgroup adbc-statement Managing Statements
/// Applications should first initialize a statement with
/// AdbcStatementNew. Then, the statement should be configured with
/// functions like AdbcStatementSetSqlQuery and
/// AdbcStatementSetOption. Finally, the statement can be executed
/// with AdbcStatementExecuteQuery (or call AdbcStatementPrepare first
/// to turn it into a prepared statement instead).
/// @{

/// \brief A container for all state needed to execute a database
/// query, such as the query itself, parameters for prepared
/// statements, driver parameters, etc.
///
/// Statements may represent queries or prepared statements.
///
/// Statements may be used multiple times and can be reconfigured
/// (e.g. they can be reused to execute multiple different queries).
/// However, executing a statement (and changing certain other state)
/// will invalidate result sets obtained prior to that execution.
///
/// Multiple statements may be created from a single connection.
/// However, the driver may block or error if they are used
/// concurrently (whether from a single thread or multiple threads).
///
/// Statements are not required to be thread-safe, but they can be
/// used from multiple threads so long as clients take care to
/// serialize accesses to a statement.
struct ADBC_EXPORT AdbcStatement {
	/// \brief Opaque implementation-defined state.
	/// This field is NULLPTR iff the connection is unintialized/freed.
	void *private_data;

	/// \brief The associated driver (used by the driver manager to help
	///   track state).
	struct AdbcDriver *private_driver;
};

/// \defgroup adbc-statement-partition Partitioned Results
/// Some backends may internally partition the results. These
/// partitions are exposed to clients who may wish to integrate them
/// with a threaded or distributed execution model, where partitions
/// can be divided among threads or machines and fetched in parallel.
///
/// To use partitioning, execute the statement with
/// AdbcStatementExecutePartitions to get the partition descriptors.
/// Call AdbcConnectionReadPartition to turn the individual
/// descriptors into ArrowArrayStream instances.  This may be done on
/// a different connection than the one the partition was created
/// with, or even in a different process on another machine.
///
/// Drivers are not required to support partitioning.
///
/// @{

/// \brief The partitions of a distributed/partitioned result set.
struct AdbcPartitions {
	/// \brief The number of partitions.
	size_t num_partitions;

	/// \brief The partitions of the result set, where each entry (up to
	///   num_partitions entries) is an opaque identifier that can be
	///   passed to AdbcConnectionReadPartition.
	const uint8_t **partitions;

	/// \brief The length of each corresponding entry in partitions.
	const size_t *partition_lengths;

	/// \brief Opaque implementation-defined state.
	/// This field is NULLPTR iff the connection is unintialized/freed.
	void *private_data;

	/// \brief Release the contained partitions.
	///
	/// Unlike other structures, this is an embedded callback to make it
	/// easier for the driver manager and driver to cooperate.
	void (*release)(struct AdbcPartitions *partitions);
};

/// @}

/// @}

/// \defgroup adbc-driver Driver Initialization
///
/// These functions are intended to help support integration between a
/// driver and the driver manager.
/// @{

/// \brief An instance of an initialized database driver.
///
/// This provides a common interface for vendor-specific driver
/// initialization routines. Drivers should populate this struct, and
/// applications can call ADBC functions through this struct, without
/// worrying about multiple definitions of the same symbol.
struct ADBC_EXPORT AdbcDriver {
	/// \brief Opaque driver-defined state.
	/// This field is NULL if the driver is unintialized/freed (but
	/// it need not have a value even if the driver is initialized).
	void *private_data;
	/// \brief Opaque driver manager-defined state.
	/// This field is NULL if the driver is unintialized/freed (but
	/// it need not have a value even if the driver is initialized).
	void *private_manager;

	/// \brief Release the driver and perform any cleanup.
	///
	/// This is an embedded callback to make it easier for the driver
	/// manager and driver to cooperate.
	AdbcStatusCode (*release)(struct AdbcDriver *driver, struct AdbcError *error);

	AdbcStatusCode (*DatabaseInit)(struct AdbcDatabase *, struct AdbcError *);
	AdbcStatusCode (*DatabaseNew)(struct AdbcDatabase *, struct AdbcError *);
	AdbcStatusCode (*DatabaseSetOption)(struct AdbcDatabase *, const char *, const char *, struct AdbcError *);
	AdbcStatusCode (*DatabaseRelease)(struct AdbcDatabase *, struct AdbcError *);

	AdbcStatusCode (*ConnectionCommit)(struct AdbcConnection *, struct AdbcError *);
	AdbcStatusCode (*ConnectionGetInfo)(struct AdbcConnection *, const uint32_t *, size_t, struct ArrowArrayStream *,
	                                    struct AdbcError *);
	AdbcStatusCode (*ConnectionGetObjects)(struct AdbcConnection *, int, const char *, const char *, const char *,
	                                       const char **, const char *, struct ArrowArrayStream *, struct AdbcError *);
	AdbcStatusCode (*ConnectionGetTableSchema)(struct AdbcConnection *, const char *, const char *, const char *,
	                                           struct ArrowSchema *, struct AdbcError *);
	AdbcStatusCode (*ConnectionGetTableTypes)(struct AdbcConnection *, struct ArrowArrayStream *, struct AdbcError *);
	AdbcStatusCode (*ConnectionInit)(struct AdbcConnection *, struct AdbcDatabase *, struct AdbcError *);
	AdbcStatusCode (*ConnectionNew)(struct AdbcConnection *, struct AdbcError *);
	AdbcStatusCode (*ConnectionSetOption)(struct AdbcConnection *, const char *, const char *, struct AdbcError *);
	AdbcStatusCode (*ConnectionReadPartition)(struct AdbcConnection *, const uint8_t *, size_t,
	                                          struct ArrowArrayStream *, struct AdbcError *);
	AdbcStatusCode (*ConnectionRelease)(struct AdbcConnection *, struct AdbcError *);
	AdbcStatusCode (*ConnectionRollback)(struct AdbcConnection *, struct AdbcError *);

	AdbcStatusCode (*StatementBind)(struct AdbcStatement *, struct ArrowArray *, struct ArrowSchema *,
	                                struct AdbcError *);
	AdbcStatusCode (*StatementBindStream)(struct AdbcStatement *, struct ArrowArrayStream *, struct AdbcError *);
	AdbcStatusCode (*StatementExecuteQuery)(struct AdbcStatement *, struct ArrowArrayStream *, int64_t *,
	                                        struct AdbcError *);
	AdbcStatusCode (*StatementExecutePartitions)(struct AdbcStatement *, struct ArrowSchema *, struct AdbcPartitions *,
	                                             int64_t *, struct AdbcError *);
	AdbcStatusCode (*StatementGetParameterSchema)(struct AdbcStatement *, struct ArrowSchema *, struct AdbcError *);
	AdbcStatusCode (*StatementNew)(struct AdbcConnection *, struct AdbcStatement *, struct AdbcError *);
	AdbcStatusCode (*StatementPrepare)(struct AdbcStatement *, struct AdbcError *);
	AdbcStatusCode (*StatementRelease)(struct AdbcStatement *, struct AdbcError *);
	AdbcStatusCode (*StatementSetOption)(struct AdbcStatement *, const char *, const char *, struct AdbcError *);
	AdbcStatusCode (*StatementSetSqlQuery)(struct AdbcStatement *, const char *, struct AdbcError *);
	AdbcStatusCode (*StatementSetSubstraitPlan)(struct AdbcStatement *, const uint8_t *, size_t, struct AdbcError *);

	/// \defgroup adbc-1.1.0 ADBC API Revision 1.1.0
	///
	/// Functions added in ADBC 1.1.0.  For backwards compatibility,
	/// these members must not be accessed unless the version passed to
	/// the AdbcDriverInitFunc is greater than or equal to
	/// ADBC_VERSION_1_1_0.
	///
	/// For a 1.0.0 driver being loaded by a 1.1.0 driver manager: the
	/// 1.1.0 manager will allocate the new, expanded AdbcDriver struct
	/// and attempt to have the driver initialize it with
	/// ADBC_VERSION_1_1_0.  This must return an error, after which the
	/// driver will try again with ADBC_VERSION_1_0_0.  The driver must
	/// not access the new fields, which will carry undefined values.
	///
	/// For a 1.1.0 driver being loaded by a 1.0.0 driver manager: the
	/// 1.0.0 manager will allocate the old AdbcDriver struct and
	/// attempt to have the driver initialize it with
	/// ADBC_VERSION_1_0_0.  The driver must not access the new fields,
	/// and should initialize the old fields.
	///
	/// @{

	int (*ErrorGetDetailCount)(const struct AdbcError *error);
	struct AdbcErrorDetail (*ErrorGetDetail)(const struct AdbcError *error, int index);
	const struct AdbcError *(*ErrorFromArrayStream)(struct ArrowArrayStream *stream, AdbcStatusCode *status);

	AdbcStatusCode (*DatabaseGetOption)(struct AdbcDatabase *, const char *, char *, size_t *, struct AdbcError *);
	AdbcStatusCode (*DatabaseGetOptionBytes)(struct AdbcDatabase *, const char *, uint8_t *, size_t *,
	                                         struct AdbcError *);
	AdbcStatusCode (*DatabaseGetOptionDouble)(struct AdbcDatabase *, const char *, double *, struct AdbcError *);
	AdbcStatusCode (*DatabaseGetOptionInt)(struct AdbcDatabase *, const char *, int64_t *, struct AdbcError *);
	AdbcStatusCode (*DatabaseSetOptionBytes)(struct AdbcDatabase *, const char *, const uint8_t *, size_t,
	                                         struct AdbcError *);
	AdbcStatusCode (*DatabaseSetOptionDouble)(struct AdbcDatabase *, const char *, double, struct AdbcError *);
	AdbcStatusCode (*DatabaseSetOptionInt)(struct AdbcDatabase *, const char *, int64_t, struct AdbcError *);

	AdbcStatusCode (*ConnectionCancel)(struct AdbcConnection *, struct AdbcError *);
	AdbcStatusCode (*ConnectionGetOption)(struct AdbcConnection *, const char *, char *, size_t *, struct AdbcError *);
	AdbcStatusCode (*ConnectionGetOptionBytes)(struct AdbcConnection *, const char *, uint8_t *, size_t *,
	                                           struct AdbcError *);
	AdbcStatusCode (*ConnectionGetOptionDouble)(struct AdbcConnection *, const char *, double *, struct AdbcError *);
	AdbcStatusCode (*ConnectionGetOptionInt)(struct AdbcConnection *, const char *, int64_t *, struct AdbcError *);
	AdbcStatusCode (*ConnectionGetStatistics)(struct AdbcConnection *, const char *, const char *, const char *, char,
	                                          struct ArrowArrayStream *, struct AdbcError *);
	AdbcStatusCode (*ConnectionGetStatisticNames)(struct AdbcConnection *, struct ArrowArrayStream *,
	                                              struct AdbcError *);
	AdbcStatusCode (*ConnectionSetOptionBytes)(struct AdbcConnection *, const char *, const uint8_t *, size_t,
	                                           struct AdbcError *);
	AdbcStatusCode (*ConnectionSetOptionDouble)(struct AdbcConnection *, const char *, double, struct AdbcError *);
	AdbcStatusCode (*ConnectionSetOptionInt)(struct AdbcConnection *, const char *, int64_t, struct AdbcError *);

	AdbcStatusCode (*StatementCancel)(struct AdbcStatement *, struct AdbcError *);
	AdbcStatusCode (*StatementExecuteSchema)(struct AdbcStatement *, struct ArrowSchema *, struct AdbcError *);
	AdbcStatusCode (*StatementGetOption)(struct AdbcStatement *, const char *, char *, size_t *, struct AdbcError *);
	AdbcStatusCode (*StatementGetOptionBytes)(struct AdbcStatement *, const char *, uint8_t *, size_t *,
	                                          struct AdbcError *);
	AdbcStatusCode (*StatementGetOptionDouble)(struct AdbcStatement *, const char *, double *, struct AdbcError *);
	AdbcStatusCode (*StatementGetOptionInt)(struct AdbcStatement *, const char *, int64_t *, struct AdbcError *);
	AdbcStatusCode (*StatementSetOptionBytes)(struct AdbcStatement *, const char *, const uint8_t *, size_t,
	                                          struct AdbcError *);
	AdbcStatusCode (*StatementSetOptionDouble)(struct AdbcStatement *, const char *, double, struct AdbcError *);
	AdbcStatusCode (*StatementSetOptionInt)(struct AdbcStatement *, const char *, int64_t, struct AdbcError *);

	/// @}
};

/// \brief The size of the AdbcDriver structure in ADBC 1.0.0.
/// Drivers written for ADBC 1.1.0 and later should never touch more
/// than this portion of an AdbcDriver struct when given
/// ADBC_VERSION_1_0_0.
///
/// \since ADBC API revision 1.1.0
#define ADBC_DRIVER_1_0_0_SIZE (offsetof(struct AdbcDriver, ErrorGetDetailCount))

/// \brief The size of the AdbcDriver structure in ADBC 1.1.0.
/// Drivers written for ADBC 1.1.0 and later should never touch more
/// than this portion of an AdbcDriver struct when given
/// ADBC_VERSION_1_1_0.
///
/// \since ADBC API revision 1.1.0
#define ADBC_DRIVER_1_1_0_SIZE (sizeof(struct AdbcDriver))

/// @}

/// \addtogroup adbc-database
/// @{

/// \brief Allocate a new (but uninitialized) database.
///
/// Callers pass in a zero-initialized AdbcDatabase.
///
/// Drivers should allocate their internal data structure and set the private_data
/// field to point to the newly allocated struct. This struct should be released
/// when AdbcDatabaseRelease is called.
ADBC_EXPORT
AdbcStatusCode AdbcDatabaseNew(struct AdbcDatabase *database, struct AdbcError *error);

/// \brief Get a string option of the database.
///
/// This must always be thread-safe (other operations are not), though
/// given the semantics here, it is not recommended to call GetOption
/// concurrently with itself.
///
/// length must be provided and must be the size of the buffer pointed
/// to by value.  If there is sufficient space, the driver will copy
/// the option value (including the null terminator) to buffer and set
/// length to the size of the actual value.  If the buffer is too
/// small, no data will be written and length will be set to the
/// required length.
///
/// In other words:
///
/// - If output length <= input length, value will contain a value
///   with length bytes.
/// - If output length > input length, nothing has been written to
///   value.
///
/// For standard options, drivers must always support getting the
/// option value (if they support getting option values at all) via
/// the type specified in the option.  (For example, an option set via
/// SetOptionDouble must be retrievable via GetOptionDouble.)  Drivers
/// may also support getting a converted option value via other
/// getters if needed.  (For example, getting the string
/// representation of a double option.)
///
/// \since ADBC API revision 1.1.0
/// \param[in] database The database.
/// \param[in] key The option to get.
/// \param[out] value The option value.
/// \param[in,out] length The length of value.
/// \param[out] error An optional location to return an error
///   message if necessary.
/// \return ADBC_STATUS_NOT_FOUND if the option is not recognized.
ADBC_EXPORT
AdbcStatusCode AdbcDatabaseGetOption(struct AdbcDatabase *database, const char *key, char *value, size_t *length,
                                     struct AdbcError *error);

/// \brief Get a bytestring option of the database.
///
/// This must always be thread-safe (other operations are not), though
/// given the semantics here, it is not recommended to call
/// GetOptionBytes concurrently with itself.
///
/// length must be provided and must be the size of the buffer pointed
/// to by value.  If there is sufficient space, the driver will copy
/// the option value to buffer and set length to the size of the
/// actual value.  If the buffer is too small, no data will be written
/// and length will be set to the required length.
///
/// In other words:
///
/// - If output length <= input length, value will contain a value
///   with length bytes.
/// - If output length > input length, nothing has been written to
///   value.
///
/// For standard options, drivers must always support getting the
/// option value (if they support getting option values at all) via
/// the type specified in the option.  (For example, an option set via
/// SetOptionDouble must be retrievable via GetOptionDouble.)  Drivers
/// may also support getting a converted option value via other
/// getters if needed.  (For example, getting the string
/// representation of a double option.)
///
/// \since ADBC API revision 1.1.0
/// \param[in] database The database.
/// \param[in] key The option to get.
/// \param[out] value The option value.
/// \param[in,out] length The option value length.
/// \param[out] error An optional location to return an error
///   message if necessary.
/// \return ADBC_STATUS_NOT_FOUND if the option is not recognized.
ADBC_EXPORT
AdbcStatusCode AdbcDatabaseGetOptionBytes(struct AdbcDatabase *database, const char *key, uint8_t *value,
                                          size_t *length, struct AdbcError *error);

/// \brief Get a double option of the database.
///
/// This must always be thread-safe (other operations are not).
///
/// For standard options, drivers must always support getting the
/// option value (if they support getting option values at all) via
/// the type specified in the option.  (For example, an option set via
/// SetOptionDouble must be retrievable via GetOptionDouble.)  Drivers
/// may also support getting a converted option value via other
/// getters if needed.  (For example, getting the double
/// representation of an integer option.)
///
/// \since ADBC API revision 1.1.0
/// \param[in] database The database.
/// \param[in] key The option to get.
/// \param[out] value The option value.
/// \param[out] error An optional location to return an error
///   message if necessary.
/// \return ADBC_STATUS_NOT_FOUND if the option is not recognized.
ADBC_EXPORT
AdbcStatusCode AdbcDatabaseGetOptionDouble(struct AdbcDatabase *database, const char *key, double *value,
                                           struct AdbcError *error);

/// \brief Get an integer option of the database.
///
/// This must always be thread-safe (other operations are not).
///
/// For standard options, drivers must always support getting the
/// option value (if they support getting option values at all) via
/// the type specified in the option.  (For example, an option set via
/// SetOptionDouble must be retrievable via GetOptionDouble.)  Drivers
/// may also support getting a converted option value via other
/// getters if needed.  (For example, getting the integer
/// representation of a double option.)
///
/// \since ADBC API revision 1.1.0
/// \param[in] database The database.
/// \param[in] key The option to get.
/// \param[out] value The option value.
/// \param[out] error An optional location to return an error
///   message if necessary.
/// \return ADBC_STATUS_NOT_FOUND if the option is not recognized.
ADBC_EXPORT
AdbcStatusCode AdbcDatabaseGetOptionInt(struct AdbcDatabase *database, const char *key, int64_t *value,
                                        struct AdbcError *error);

/// \brief Set a char* option.
///
/// Options may be set before AdbcDatabaseInit.  Some drivers may
/// support setting options after initialization as well.
///
/// \param[in] database The database.
/// \param[in] key The option to set.
/// \param[in] value The option value.
/// \param[out] error An optional location to return an error
///   message if necessary.
/// \return ADBC_STATUS_NOT_IMPLEMENTED if the option is not recognized
ADBC_EXPORT
AdbcStatusCode AdbcDatabaseSetOption(struct AdbcDatabase *database, const char *key, const char *value,
                                     struct AdbcError *error);

/// \brief Set a bytestring option on a database.
///
/// \since ADBC API revision 1.1.0
/// \param[in] database The database.
/// \param[in] key The option to set.
/// \param[in] value The option value.
/// \param[in] length The option value length.
/// \param[out] error An optional location to return an error
///   message if necessary.
/// \return ADBC_STATUS_NOT_IMPLEMENTED if the option is not recognized
ADBC_EXPORT
AdbcStatusCode AdbcDatabaseSetOptionBytes(struct AdbcDatabase *database, const char *key, const uint8_t *value,
                                          size_t length, struct AdbcError *error);

/// \brief Set a double option on a database.
///
/// \since ADBC API revision 1.1.0
/// \param[in] database The database.
/// \param[in] key The option to set.
/// \param[in] value The option value.
/// \param[out] error An optional location to return an error
///   message if necessary.
/// \return ADBC_STATUS_NOT_IMPLEMENTED if the option is not recognized
ADBC_EXPORT
AdbcStatusCode AdbcDatabaseSetOptionDouble(struct AdbcDatabase *database, const char *key, double value,
                                           struct AdbcError *error);

/// \brief Set an integer option on a database.
///
/// \since ADBC API revision 1.1.0
/// \param[in] database The database.
/// \param[in] key The option to set.
/// \param[in] value The option value.
/// \param[out] error An optional location to return an error
///   message if necessary.
/// \return ADBC_STATUS_NOT_IMPLEMENTED if the option is not recognized
ADBC_EXPORT
AdbcStatusCode AdbcDatabaseSetOptionInt(struct AdbcDatabase *database, const char *key, int64_t value,
                                        struct AdbcError *error);

/// \brief Finish setting options and initialize the database.
///
/// Some drivers may support setting options after initialization
/// as well.
ADBC_EXPORT
AdbcStatusCode AdbcDatabaseInit(struct AdbcDatabase *database, struct AdbcError *error);

/// \brief Destroy this database. No connections may exist.
/// \param[in] database The database to release.
/// \param[out] error An optional location to return an error
///   message if necessary.
ADBC_EXPORT
AdbcStatusCode AdbcDatabaseRelease(struct AdbcDatabase *database, struct AdbcError *error);

/// @}

/// \addtogroup adbc-connection
/// @{

/// \brief Allocate a new (but uninitialized) connection.
///
/// Callers pass in a zero-initialized AdbcConnection.
///
/// Drivers should allocate their internal data structure and set the private_data
/// field to point to the newly allocated struct. This struct should be released
/// when AdbcConnectionRelease is called.
ADBC_EXPORT
AdbcStatusCode AdbcConnectionNew(struct AdbcConnection *connection, struct AdbcError *error);

/// \brief Set a char* option.
///
/// Options may be set before AdbcConnectionInit.  Some drivers may
/// support setting options after initialization as well.
///
/// \param[in] connection The database connection.
/// \param[in] key The option to set.
/// \param[in] value The option value.
/// \param[out] error An optional location to return an error
///   message if necessary.
/// \return ADBC_STATUS_NOT_IMPLEMENTED if the option is not recognized
ADBC_EXPORT
AdbcStatusCode AdbcConnectionSetOption(struct AdbcConnection *connection, const char *key, const char *value,
                                       struct AdbcError *error);

/// \brief Set a bytestring option on a connection.
///
/// \since ADBC API revision 1.1.0
/// \param[in] connection The connection.
/// \param[in] key The option to set.
/// \param[in] value The option value.
/// \param[in] length The option value length.
/// \param[out] error An optional location to return an error
///   message if necessary.
/// \return ADBC_STATUS_NOT_IMPLEMENTED if the option is not recognized
ADBC_EXPORT
AdbcStatusCode AdbcConnectionSetOptionBytes(struct AdbcConnection *connection, const char *key, const uint8_t *value,
                                            size_t length, struct AdbcError *error);

/// \brief Set an integer option.
///
/// Options may be set before AdbcConnectionInit.  Some drivers may
/// support setting options after initialization as well.
///
/// \since ADBC API revision 1.1.0
/// \param[in] connection The database connection.
/// \param[in] key The option to set.
/// \param[in] value The option value.
/// \param[out] error An optional location to return an error
///   message if necessary.
/// \return ADBC_STATUS_NOT_IMPLEMENTED if the option is not recognized
ADBC_EXPORT
AdbcStatusCode AdbcConnectionSetOptionInt(struct AdbcConnection *connection, const char *key, int64_t value,
                                          struct AdbcError *error);

/// \brief Set a double option.
///
/// Options may be set before AdbcConnectionInit.  Some drivers may
/// support setting options after initialization as well.
///
/// \since ADBC API revision 1.1.0
/// \param[in] connection The database connection.
/// \param[in] key The option to set.
/// \param[in] value The option value.
/// \param[out] error An optional location to return an error
///   message if necessary.
/// \return ADBC_STATUS_NOT_IMPLEMENTED if the option is not recognized
ADBC_EXPORT
AdbcStatusCode AdbcConnectionSetOptionDouble(struct AdbcConnection *connection, const char *key, double value,
                                             struct AdbcError *error);

/// \brief Finish setting options and initialize the connection.
///
/// Some drivers may support setting options after initialization
/// as well.
ADBC_EXPORT
AdbcStatusCode AdbcConnectionInit(struct AdbcConnection *connection, struct AdbcDatabase *database,
                                  struct AdbcError *error);

/// \brief Destroy this connection.
///
/// \param[in] connection The connection to release.
/// \param[out] error An optional location to return an error
///   message if necessary.
ADBC_EXPORT
AdbcStatusCode AdbcConnectionRelease(struct AdbcConnection *connection, struct AdbcError *error);

/// \brief Cancel the in-progress operation on a connection.
///
/// This can be called during AdbcConnectionGetObjects (or similar),
/// or while consuming an ArrowArrayStream returned from such.
/// Calling this function should make the other functions return
/// ADBC_STATUS_CANCELLED (from ADBC functions) or ECANCELED (from
/// methods of ArrowArrayStream).  (It is not guaranteed to, for
/// instance, the result set may be buffered in memory already.)
///
/// This must always be thread-safe (other operations are not).  It is
/// not necessarily signal-safe.
///
/// \since ADBC API revision 1.1.0
///
/// \param[in] connection The connection to cancel.
/// \param[out] error An optional location to return an error
///   message if necessary.
///
/// \return ADBC_STATUS_INVALID_STATE if there is no operation to cancel.
/// \return ADBC_STATUS_UNKNOWN if the operation could not be cancelled.
ADBC_EXPORT
AdbcStatusCode AdbcConnectionCancel(struct AdbcConnection *connection, struct AdbcError *error);

/// \defgroup adbc-connection-metadata Metadata
/// Functions for retrieving metadata about the database.
///
/// Generally, these functions return an ArrowArrayStream that can be
/// consumed to get the metadata as Arrow data.  The returned metadata
/// has an expected schema given in the function docstring. Schema
/// fields are nullable unless otherwise marked.  While no
/// AdbcStatement is used in these functions, the result set may count
/// as an active statement to the driver for the purposes of
/// concurrency management (e.g. if the driver has a limit on
/// concurrent active statements and it must execute a SQL query
/// internally in order to implement the metadata function).
///
/// This AdbcConnection must outlive the returned ArrowArrayStream.
///
/// Some functions accept "search pattern" arguments, which are
/// strings that can contain the special character "%" to match zero
/// or more characters, or "_" to match exactly one character.  (See
/// the documentation of DatabaseMetaData in JDBC or "Pattern Value
/// Arguments" in the ODBC documentation.)  Escaping is not currently
/// supported.
///
/// @{

/// \brief Get metadata about the database/driver.
///
/// The result is an Arrow dataset with the following schema:
///
/// Field Name                  | Field Type
/// ----------------------------|------------------------
/// info_name                   | uint32 not null
/// info_value                  | INFO_SCHEMA
///
/// INFO_SCHEMA is a dense union with members:
///
/// Field Name (Type Code)      | Field Type
/// ----------------------------|------------------------
/// string_value (0)            | utf8
/// bool_value (1)              | bool
/// int64_value (2)             | int64
/// int32_bitmask (3)           | int32
/// string_list (4)             | list<utf8>
/// int32_to_int32_list_map (5) | map<int32, list<int32>>
///
/// Each metadatum is identified by an integer code.  The recognized
/// codes are defined as constants.  Codes [0, 10_000) are reserved
/// for ADBC usage.  Drivers/vendors will ignore requests for
/// unrecognized codes (the row will be omitted from the result).
///
/// Since ADBC 1.1.0: the range [500, 1_000) is reserved for "XDBC"
/// information, which is the same metadata provided by the same info
/// code range in the Arrow Flight SQL GetSqlInfo RPC.
///
/// \param[in] connection The connection to query.
/// \param[in] info_codes A list of metadata codes to fetch, or NULL
///   to fetch all.
/// \param[in] info_codes_length The length of the info_codes
///   parameter.  Ignored if info_codes is NULL.
/// \param[out] out The result set.
/// \param[out] error Error details, if an error occurs.
ADBC_EXPORT
AdbcStatusCode AdbcConnectionGetInfo(struct AdbcConnection *connection, const uint32_t *info_codes,
                                     size_t info_codes_length, struct ArrowArrayStream *out, struct AdbcError *error);

/// \brief Get a hierarchical view of all catalogs, database schemas,
///   tables, and columns.
///
/// The result is an Arrow dataset with the following schema:
///
/// | Field Name               | Field Type              |
/// |--------------------------|-------------------------|
/// | catalog_name             | utf8                    |
/// | catalog_db_schemas       | list<DB_SCHEMA_SCHEMA>  |
///
/// DB_SCHEMA_SCHEMA is a Struct with fields:
///
/// | Field Name               | Field Type              |
/// |--------------------------|-------------------------|
/// | db_schema_name           | utf8                    |
/// | db_schema_tables         | list<TABLE_SCHEMA>      |
///
/// TABLE_SCHEMA is a Struct with fields:
///
/// | Field Name               | Field Type              |
/// |--------------------------|-------------------------|
/// | table_name               | utf8 not null           |
/// | table_type               | utf8 not null           |
/// | table_columns            | list<COLUMN_SCHEMA>     |
/// | table_constraints        | list<CONSTRAINT_SCHEMA> |
///
/// COLUMN_SCHEMA is a Struct with fields:
///
/// | Field Name               | Field Type              | Comments |
/// |--------------------------|-------------------------|----------|
/// | column_name              | utf8 not null           |          |
/// | ordinal_position         | int32                   | (1)      |
/// | remarks                  | utf8                    | (2)      |
/// | xdbc_data_type           | int16                   | (3)      |
/// | xdbc_type_name           | utf8                    | (3)      |
/// | xdbc_column_size         | int32                   | (3)      |
/// | xdbc_decimal_digits      | int16                   | (3)      |
/// | xdbc_num_prec_radix      | int16                   | (3)      |
/// | xdbc_nullable            | int16                   | (3)      |
/// | xdbc_column_def          | utf8                    | (3)      |
/// | xdbc_sql_data_type       | int16                   | (3)      |
/// | xdbc_datetime_sub        | int16                   | (3)      |
/// | xdbc_char_octet_length   | int32                   | (3)      |
/// | xdbc_is_nullable         | utf8                    | (3)      |
/// | xdbc_scope_catalog       | utf8                    | (3)      |
/// | xdbc_scope_schema        | utf8                    | (3)      |
/// | xdbc_scope_table         | utf8                    | (3)      |
/// | xdbc_is_autoincrement    | bool                    | (3)      |
/// | xdbc_is_generatedcolumn  | bool                    | (3)      |
///
/// 1. The column's ordinal position in the table (starting from 1).
/// 2. Database-specific description of the column.
/// 3. Optional value.  Should be null if not supported by the driver.
///    xdbc_ values are meant to provide JDBC/ODBC-compatible metadata
///    in an agnostic manner.
///
/// CONSTRAINT_SCHEMA is a Struct with fields:
///
/// | Field Name               | Field Type              | Comments |
/// |--------------------------|-------------------------|----------|
/// | constraint_name          | utf8                    |          |
/// | constraint_type          | utf8 not null           | (1)      |
/// | constraint_column_names  | list<utf8> not null     | (2)      |
/// | constraint_column_usage  | list<USAGE_SCHEMA>      | (3)      |
///
/// 1. One of 'CHECK', 'FOREIGN KEY', 'PRIMARY KEY', or 'UNIQUE'.
/// 2. The columns on the current table that are constrained, in
///    order.
/// 3. For FOREIGN KEY only, the referenced table and columns.
///
/// USAGE_SCHEMA is a Struct with fields:
///
/// | Field Name               | Field Type              |
/// |--------------------------|-------------------------|
/// | fk_catalog               | utf8                    |
/// | fk_db_schema             | utf8                    |
/// | fk_table                 | utf8 not null           |
/// | fk_column_name           | utf8 not null           |
///
/// This AdbcConnection must outlive the returned ArrowArrayStream.
///
/// \param[in] connection The database connection.
/// \param[in] depth The level of nesting to display. If 0, display
///   all levels. If 1, display only catalogs (i.e.  catalog_schemas
///   will be null). If 2, display only catalogs and schemas
///   (i.e. db_schema_tables will be null), and so on.
/// \param[in] catalog Only show tables in the given catalog. If NULL,
///   do not filter by catalog. If an empty string, only show tables
///   without a catalog.  May be a search pattern (see section
///   documentation).
/// \param[in] db_schema Only show tables in the given database schema. If
///   NULL, do not filter by database schema. If an empty string, only show
///   tables without a database schema. May be a search pattern (see section
///   documentation).
/// \param[in] table_name Only show tables with the given name. If NULL, do not
///   filter by name. May be a search pattern (see section documentation).
/// \param[in] table_type Only show tables matching one of the given table
///   types. If NULL, show tables of any type. Valid table types can be fetched
///   from GetTableTypes.  Terminate the list with a NULL entry.
/// \param[in] column_name Only show columns with the given name. If
///   NULL, do not filter by name.  May be a search pattern (see
///   section documentation).
/// \param[out] out The result set.
/// \param[out] error Error details, if an error occurs.
ADBC_EXPORT
AdbcStatusCode AdbcConnectionGetObjects(struct AdbcConnection *connection, int depth, const char *catalog,
                                        const char *db_schema, const char *table_name, const char **table_type,
                                        const char *column_name, struct ArrowArrayStream *out, struct AdbcError *error);

/// \brief Get a string option of the connection.
///
/// This must always be thread-safe (other operations are not), though
/// given the semantics here, it is not recommended to call GetOption
/// concurrently with itself.
///
/// length must be provided and must be the size of the buffer pointed
/// to by value.  If there is sufficient space, the driver will copy
/// the option value (including the null terminator) to buffer and set
/// length to the size of the actual value.  If the buffer is too
/// small, no data will be written and length will be set to the
/// required length.
///
/// In other words:
///
/// - If output length <= input length, value will contain a value
///   with length bytes.
/// - If output length > input length, nothing has been written to
///   value.
///
/// \since ADBC API revision 1.1.0
/// \param[in] connection The database connection.
/// \param[in] key The option to get.
/// \param[out] value The option value.
/// \param[in,out] length The length of value.
/// \param[out] error An optional location to return an error
///   message if necessary.
/// \return ADBC_STATUS_NOT_FOUND if the option is not recognized.
ADBC_EXPORT
AdbcStatusCode AdbcConnectionGetOption(struct AdbcConnection *connection, const char *key, char *value, size_t *length,
                                       struct AdbcError *error);

/// \brief Get a bytestring option of the connection.
///
/// This must always be thread-safe (other operations are not), though
/// given the semantics here, it is not recommended to call
/// GetOptionBytes concurrently with itself.
///
/// length must be provided and must be the size of the buffer pointed
/// to by value.  If there is sufficient space, the driver will copy
/// the option value to buffer and set length to the size of the
/// actual value.  If the buffer is too small, no data will be written
/// and length will be set to the required length.
///
/// In other words:
///
/// - If output length <= input length, value will contain a value
///   with length bytes.
/// - If output length > input length, nothing has been written to
///   value.
///
/// For standard options, drivers must always support getting the
/// option value (if they support getting option values at all) via
/// the type specified in the option.  (For example, an option set via
/// SetOptionDouble must be retrievable via GetOptionDouble.)  Drivers
/// may also support getting a converted option value via other
/// getters if needed.  (For example, getting the string
/// representation of a double option.)
///
/// \since ADBC API revision 1.1.0
/// \param[in] connection The connection.
/// \param[in] key The option to get.
/// \param[out] value The option value.
/// \param[in,out] length The option value length.
/// \param[out] error An optional location to return an error
///   message if necessary.
/// \return ADBC_STATUS_NOT_FOUND if the option is not recognized.
ADBC_EXPORT
AdbcStatusCode AdbcConnectionGetOptionBytes(struct AdbcConnection *connection, const char *key, uint8_t *value,
                                            size_t *length, struct AdbcError *error);

/// \brief Get an integer option of the connection.
///
/// This must always be thread-safe (other operations are not).
///
/// For standard options, drivers must always support getting the
/// option value (if they support getting option values at all) via
/// the type specified in the option.  (For example, an option set via
/// SetOptionDouble must be retrievable via GetOptionDouble.)  Drivers
/// may also support getting a converted option value via other
/// getters if needed.  (For example, getting the string
/// representation of a double option.)
///
/// \since ADBC API revision 1.1.0
/// \param[in] connection The database connection.
/// \param[in] key The option to get.
/// \param[out] value The option value.
/// \param[out] error An optional location to return an error
///   message if necessary.
/// \return ADBC_STATUS_NOT_FOUND if the option is not recognized.
ADBC_EXPORT
AdbcStatusCode AdbcConnectionGetOptionInt(struct AdbcConnection *connection, const char *key, int64_t *value,
                                          struct AdbcError *error);

/// \brief Get a double option of the connection.
///
/// This must always be thread-safe (other operations are not).
///
/// For standard options, drivers must always support getting the
/// option value (if they support getting option values at all) via
/// the type specified in the option.  (For example, an option set via
/// SetOptionDouble must be retrievable via GetOptionDouble.)  Drivers
/// may also support getting a converted option value via other
/// getters if needed.  (For example, getting the string
/// representation of a double option.)
///
/// \since ADBC API revision 1.1.0
/// \param[in] connection The database connection.
/// \param[in] key The option to get.
/// \param[out] value The option value.
/// \param[out] error An optional location to return an error
///   message if necessary.
/// \return ADBC_STATUS_NOT_FOUND if the option is not recognized.
ADBC_EXPORT
AdbcStatusCode AdbcConnectionGetOptionDouble(struct AdbcConnection *connection, const char *key, double *value,
                                             struct AdbcError *error);

/// \brief Get statistics about the data distribution of table(s).
///
/// The result is an Arrow dataset with the following schema:
///
/// | Field Name               | Field Type                       |
/// |--------------------------|----------------------------------|
/// | catalog_name             | utf8                             |
/// | catalog_db_schemas       | list<DB_SCHEMA_SCHEMA> not null  |
///
/// DB_SCHEMA_SCHEMA is a Struct with fields:
///
/// | Field Name               | Field Type                       |
/// |--------------------------|----------------------------------|
/// | db_schema_name           | utf8                             |
/// | db_schema_statistics     | list<STATISTICS_SCHEMA> not null |
///
/// STATISTICS_SCHEMA is a Struct with fields:
///
/// | Field Name               | Field Type                       | Comments |
/// |--------------------------|----------------------------------| -------- |
/// | table_name               | utf8 not null                    |          |
/// | column_name              | utf8                             | (1)      |
/// | statistic_key            | int16 not null                   | (2)      |
/// | statistic_value          | VALUE_SCHEMA not null            |          |
/// | statistic_is_approximate | bool not null                    | (3)      |
///
/// 1. If null, then the statistic applies to the entire table.
/// 2. A dictionary-encoded statistic name (although we do not use the Arrow
///    dictionary type). Values in [0, 1024) are reserved for ADBC.  Other
///    values are for implementation-specific statistics.  For the definitions
///    of predefined statistic types, see \ref adbc-table-statistics.  To get
///    driver-specific statistic names, use AdbcConnectionGetStatisticNames.
/// 3. If true, then the value is approximate or best-effort.
///
/// VALUE_SCHEMA is a dense union with members:
///
/// | Field Name               | Field Type                       |
/// |--------------------------|----------------------------------|
/// | int64                    | int64                            |
/// | uint64                   | uint64                           |
/// | float64                  | float64                          |
/// | binary                   | binary                           |
///
/// This AdbcConnection must outlive the returned ArrowArrayStream.
///
/// \since ADBC API revision 1.1.0
/// \param[in] connection The database connection.
/// \param[in] catalog The catalog (or nullptr).  May be a search
///   pattern (see section documentation).
/// \param[in] db_schema The database schema (or nullptr).  May be a
///   search pattern (see section documentation).
/// \param[in] table_name The table name (or nullptr).  May be a
///   search pattern (see section documentation).
/// \param[in] approximate If zero, request exact values of
///   statistics, else allow for best-effort, approximate, or cached
///   values.  The database may return approximate values regardless,
///   as indicated in the result.  Requesting exact values may be
///   expensive or unsupported.
/// \param[out] out The result set.
/// \param[out] error Error details, if an error occurs.
ADBC_EXPORT
AdbcStatusCode AdbcConnectionGetStatistics(struct AdbcConnection *connection, const char *catalog,
                                           const char *db_schema, const char *table_name, char approximate,
                                           struct ArrowArrayStream *out, struct AdbcError *error);

/// \brief Get the names of statistics specific to this driver.
///
/// The result is an Arrow dataset with the following schema:
///
/// Field Name     | Field Type
/// ---------------|----------------
/// statistic_name | utf8 not null
/// statistic_key  | int16 not null
///
/// \since ADBC API revision 1.1.0
/// \param[in] connection The database connection.
/// \param[out] out The result set.
/// \param[out] error Error details, if an error occurs.
ADBC_EXPORT
AdbcStatusCode AdbcConnectionGetStatisticNames(struct AdbcConnection *connection, struct ArrowArrayStream *out,
                                               struct AdbcError *error);

/// \brief Get the Arrow schema of a table.
///
/// \param[in] connection The database connection.
/// \param[in] catalog The catalog (or nullptr if not applicable).
/// \param[in] db_schema The database schema (or nullptr if not applicable).
/// \param[in] table_name The table name.
/// \param[out] schema The table schema.
/// \param[out] error Error details, if an error occurs.
ADBC_EXPORT
AdbcStatusCode AdbcConnectionGetTableSchema(struct AdbcConnection *connection, const char *catalog,
                                            const char *db_schema, const char *table_name, struct ArrowSchema *schema,
                                            struct AdbcError *error);

/// \brief Get a list of table types in the database.
///
/// The result is an Arrow dataset with the following schema:
///
/// Field Name     | Field Type
/// ---------------|--------------
/// table_type     | utf8 not null
///
/// This AdbcConnection must outlive the returned ArrowArrayStream.
///
/// \param[in] connection The database connection.
/// \param[out] out The result set.
/// \param[out] error Error details, if an error occurs.
ADBC_EXPORT
AdbcStatusCode AdbcConnectionGetTableTypes(struct AdbcConnection *connection, struct ArrowArrayStream *out,
                                           struct AdbcError *error);

/// @}

/// \defgroup adbc-connection-partition Partitioned Results
/// Some databases may internally partition the results. These
/// partitions are exposed to clients who may wish to integrate them
/// with a threaded or distributed execution model, where partitions
/// can be divided among threads or machines for processing.
///
/// Drivers are not required to support partitioning.
///
/// Partitions are not ordered. If the result set is sorted,
/// implementations should return a single partition.
///
/// @{

/// \brief Construct a statement for a partition of a query. The
///   results can then be read independently.
///
/// A partition can be retrieved from AdbcPartitions.
///
/// This AdbcConnection must outlive the returned ArrowArrayStream.
///
/// \param[in] connection The connection to use.  This does not have
///   to be the same connection that the partition was created on.
/// \param[in] serialized_partition The partition descriptor.
/// \param[in] serialized_length The partition descriptor length.
/// \param[out] out The result set.
/// \param[out] error Error details, if an error occurs.
ADBC_EXPORT
AdbcStatusCode AdbcConnectionReadPartition(struct AdbcConnection *connection, const uint8_t *serialized_partition,
                                           size_t serialized_length, struct ArrowArrayStream *out,
                                           struct AdbcError *error);

/// @}

/// \defgroup adbc-connection-transaction Transaction Semantics
///
/// Connections start out in auto-commit mode by default (if
/// applicable for the given vendor). Use AdbcConnectionSetOption and
/// ADBC_CONNECTION_OPTION_AUTO_COMMIT to change this.
///
/// @{

/// \brief Commit any pending transactions. Only used if autocommit is
///   disabled.
///
/// Behavior is undefined if this is mixed with SQL transaction
/// statements.
ADBC_EXPORT
AdbcStatusCode AdbcConnectionCommit(struct AdbcConnection *connection, struct AdbcError *error);

/// \brief Roll back any pending transactions. Only used if autocommit
///   is disabled.
///
/// Behavior is undefined if this is mixed with SQL transaction
/// statements.
ADBC_EXPORT
AdbcStatusCode AdbcConnectionRollback(struct AdbcConnection *connection, struct AdbcError *error);

/// @}

/// @}

/// \addtogroup adbc-statement
/// @{

/// \brief Create a new statement for a given connection.
///
/// Callers pass in a zero-initialized AdbcStatement.
///
/// Drivers should allocate their internal data structure and set the private_data
/// field to point to the newly allocated struct. This struct should be released
/// when AdbcStatementRelease is called.
ADBC_EXPORT
AdbcStatusCode AdbcStatementNew(struct AdbcConnection *connection, struct AdbcStatement *statement,
                                struct AdbcError *error);

/// \brief Destroy a statement.
/// \param[in] statement The statement to release.
/// \param[out] error An optional location to return an error
///   message if necessary.
ADBC_EXPORT
AdbcStatusCode AdbcStatementRelease(struct AdbcStatement *statement, struct AdbcError *error);

/// \brief Execute a statement and get the results.
///
/// This invalidates any prior result sets.  This AdbcStatement must
/// outlive the returned ArrowArrayStream.
///
/// Since ADBC 1.1.0: releasing the returned ArrowArrayStream without
/// consuming it fully is equivalent to calling AdbcStatementCancel.
///
/// \param[in] statement The statement to execute.
/// \param[out] out The results. Pass NULL if the client does not
///   expect a result set.
/// \param[out] rows_affected The number of rows affected if known,
///   else -1. Pass NULL if the client does not want this information.
/// \param[out] error An optional location to return an error
///   message if necessary.
ADBC_EXPORT
AdbcStatusCode AdbcStatementExecuteQuery(struct AdbcStatement *statement, struct ArrowArrayStream *out,
                                         int64_t *rows_affected, struct AdbcError *error);

/// \brief Get the schema of the result set of a query without
///   executing it.
///
/// This invalidates any prior result sets.
///
/// Depending on the driver, this may require first executing
/// AdbcStatementPrepare.
///
/// \since ADBC API revision 1.1.0
///
/// \param[in] statement The statement to execute.
/// \param[out] out The result schema.
/// \param[out] error An optional location to return an error
///   message if necessary.
///
/// \return ADBC_STATUS_NOT_IMPLEMENTED if the driver does not support this.
ADBC_EXPORT
AdbcStatusCode AdbcStatementExecuteSchema(struct AdbcStatement *statement, struct ArrowSchema *schema,
                                          struct AdbcError *error);

/// \brief Turn this statement into a prepared statement to be
///   executed multiple times.
///
/// This invalidates any prior result sets.
ADBC_EXPORT
AdbcStatusCode AdbcStatementPrepare(struct AdbcStatement *statement, struct AdbcError *error);

/// \defgroup adbc-statement-sql SQL Semantics
/// Functions for executing SQL queries, or querying SQL-related
/// metadata. Drivers are not required to support both SQL and
/// Substrait semantics. If they do, it may be via converting
/// between representations internally.
/// @{

/// \brief Set the SQL query to execute.
///
/// The query can then be executed with AdbcStatementExecute.  For
/// queries expected to be executed repeatedly, AdbcStatementPrepare
/// the statement first.
///
/// \param[in] statement The statement.
/// \param[in] query The query to execute.
/// \param[out] error Error details, if an error occurs.
ADBC_EXPORT
AdbcStatusCode AdbcStatementSetSqlQuery(struct AdbcStatement *statement, const char *query, struct AdbcError *error);

/// @}

/// \defgroup adbc-statement-substrait Substrait Semantics
/// Functions for executing Substrait plans, or querying
/// Substrait-related metadata.  Drivers are not required to support
/// both SQL and Substrait semantics.  If they do, it may be via
/// converting between representations internally.
/// @{

/// \brief Set the Substrait plan to execute.
///
/// The query can then be executed with AdbcStatementExecute.  For
/// queries expected to be executed repeatedly, AdbcStatementPrepare
/// the statement first.
///
/// \param[in] statement The statement.
/// \param[in] plan The serialized substrait.Plan to execute.
/// \param[in] length The length of the serialized plan.
/// \param[out] error Error details, if an error occurs.
ADBC_EXPORT
AdbcStatusCode AdbcStatementSetSubstraitPlan(struct AdbcStatement *statement, const uint8_t *plan, size_t length,
                                             struct AdbcError *error);

/// @}

/// \brief Bind Arrow data. This can be used for bulk inserts or
///   prepared statements.
///
/// \param[in] statement The statement to bind to.
/// \param[in] values The values to bind. The driver will call the
///   release callback itself, although it may not do this until the
///   statement is released.
/// \param[in] schema The schema of the values to bind.
/// \param[out] error An optional location to return an error message
///   if necessary.
ADBC_EXPORT
AdbcStatusCode AdbcStatementBind(struct AdbcStatement *statement, struct ArrowArray *values, struct ArrowSchema *schema,
                                 struct AdbcError *error);

/// \brief Bind Arrow data. This can be used for bulk inserts or
///   prepared statements.
/// \param[in] statement The statement to bind to.
/// \param[in] stream The values to bind. The driver will call the
///   release callback itself, although it may not do this until the
///   statement is released.
/// \param[out] error An optional location to return an error message
///   if necessary.
ADBC_EXPORT
AdbcStatusCode AdbcStatementBindStream(struct AdbcStatement *statement, struct ArrowArrayStream *stream,
                                       struct AdbcError *error);

/// \brief Cancel execution of an in-progress query.
///
/// This can be called during AdbcStatementExecuteQuery (or similar),
/// or while consuming an ArrowArrayStream returned from such.
/// Calling this function should make the other functions return
/// ADBC_STATUS_CANCELLED (from ADBC functions) or ECANCELED (from
/// methods of ArrowArrayStream).  (It is not guaranteed to, for
/// instance, the result set may be buffered in memory already.)
///
/// This must always be thread-safe (other operations are not).  It is
/// not necessarily signal-safe.
///
/// \since ADBC API revision 1.1.0
///
/// \param[in] statement The statement to cancel.
/// \param[out] error An optional location to return an error
///   message if necessary.
///
/// \return ADBC_STATUS_INVALID_STATE if there is no query to cancel.
/// \return ADBC_STATUS_UNKNOWN if the query could not be cancelled.
ADBC_EXPORT
AdbcStatusCode AdbcStatementCancel(struct AdbcStatement *statement, struct AdbcError *error);

/// \brief Get a string option of the statement.
///
/// This must always be thread-safe (other operations are not), though
/// given the semantics here, it is not recommended to call GetOption
/// concurrently with itself.
///
/// length must be provided and must be the size of the buffer pointed
/// to by value.  If there is sufficient space, the driver will copy
/// the option value (including the null terminator) to buffer and set
/// length to the size of the actual value.  If the buffer is too
/// small, no data will be written and length will be set to the
/// required length.
///
/// In other words:
///
/// - If output length <= input length, value will contain a value
///   with length bytes.
/// - If output length > input length, nothing has been written to
///   value.
///
/// For standard options, drivers must always support getting the
/// option value (if they support getting option values at all) via
/// the type specified in the option.  (For example, an option set via
/// SetOptionDouble must be retrievable via GetOptionDouble.)  Drivers
/// may also support getting a converted option value via other
/// getters if needed.  (For example, getting the string
/// representation of a double option.)
///
/// \since ADBC API revision 1.1.0
/// \param[in] statement The statement.
/// \param[in] key The option to get.
/// \param[out] value The option value.
/// \param[in,out] length The length of value.
/// \param[out] error An optional location to return an error
///   message if necessary.
/// \return ADBC_STATUS_NOT_FOUND if the option is not recognized.
ADBC_EXPORT
AdbcStatusCode AdbcStatementGetOption(struct AdbcStatement *statement, const char *key, char *value, size_t *length,
                                      struct AdbcError *error);

/// \brief Get a bytestring option of the statement.
///
/// This must always be thread-safe (other operations are not), though
/// given the semantics here, it is not recommended to call
/// GetOptionBytes concurrently with itself.
///
/// length must be provided and must be the size of the buffer pointed
/// to by value.  If there is sufficient space, the driver will copy
/// the option value to buffer and set length to the size of the
/// actual value.  If the buffer is too small, no data will be written
/// and length will be set to the required length.
///
/// In other words:
///
/// - If output length <= input length, value will contain a value
///   with length bytes.
/// - If output length > input length, nothing has been written to
///   value.
///
/// For standard options, drivers must always support getting the
/// option value (if they support getting option values at all) via
/// the type specified in the option.  (For example, an option set via
/// SetOptionDouble must be retrievable via GetOptionDouble.)  Drivers
/// may also support getting a converted option value via other
/// getters if needed.  (For example, getting the string
/// representation of a double option.)
///
/// \since ADBC API revision 1.1.0
/// \param[in] statement The statement.
/// \param[in] key The option to get.
/// \param[out] value The option value.
/// \param[in,out] length The option value length.
/// \param[out] error An optional location to return an error
///   message if necessary.
/// \return ADBC_STATUS_NOT_FOUND if the option is not recognized.
ADBC_EXPORT
AdbcStatusCode AdbcStatementGetOptionBytes(struct AdbcStatement *statement, const char *key, uint8_t *value,
                                           size_t *length, struct AdbcError *error);

/// \brief Get an integer option of the statement.
///
/// This must always be thread-safe (other operations are not).
///
/// For standard options, drivers must always support getting the
/// option value (if they support getting option values at all) via
/// the type specified in the option.  (For example, an option set via
/// SetOptionDouble must be retrievable via GetOptionDouble.)  Drivers
/// may also support getting a converted option value via other
/// getters if needed.  (For example, getting the string
/// representation of a double option.)
///
/// \since ADBC API revision 1.1.0
/// \param[in] statement The statement.
/// \param[in] key The option to get.
/// \param[out] value The option value.
/// \param[out] error An optional location to return an error
///   message if necessary.
/// \return ADBC_STATUS_NOT_FOUND if the option is not recognized.
ADBC_EXPORT
AdbcStatusCode AdbcStatementGetOptionInt(struct AdbcStatement *statement, const char *key, int64_t *value,
                                         struct AdbcError *error);

/// \brief Get a double option of the statement.
///
/// This must always be thread-safe (other operations are not).
///
/// For standard options, drivers must always support getting the
/// option value (if they support getting option values at all) via
/// the type specified in the option.  (For example, an option set via
/// SetOptionDouble must be retrievable via GetOptionDouble.)  Drivers
/// may also support getting a converted option value via other
/// getters if needed.  (For example, getting the string
/// representation of a double option.)
///
/// \since ADBC API revision 1.1.0
/// \param[in] statement The statement.
/// \param[in] key The option to get.
/// \param[out] value The option value.
/// \param[out] error An optional location to return an error
///   message if necessary.
/// \return ADBC_STATUS_NOT_FOUND if the option is not recognized.
ADBC_EXPORT
AdbcStatusCode AdbcStatementGetOptionDouble(struct AdbcStatement *statement, const char *key, double *value,
                                            struct AdbcError *error);

/// \brief Get the schema for bound parameters.
///
/// This retrieves an Arrow schema describing the number, names, and
/// types of the parameters in a parameterized statement.  The fields
/// of the schema should be in order of the ordinal position of the
/// parameters; named parameters should appear only once.
///
/// If the parameter does not have a name, or the name cannot be
/// determined, the name of the corresponding field in the schema will
/// be an empty string.  If the type cannot be determined, the type of
/// the corresponding field will be NA (NullType).
///
/// This should be called after AdbcStatementPrepare.
///
/// \return ADBC_STATUS_NOT_IMPLEMENTED if the schema cannot be determined.
ADBC_EXPORT
AdbcStatusCode AdbcStatementGetParameterSchema(struct AdbcStatement *statement, struct ArrowSchema *schema,
                                               struct AdbcError *error);

/// \brief Set a string option on a statement.
/// \param[in] statement The statement.
/// \param[in] key The option to set.
/// \param[in] value The option value.
/// \param[out] error An optional location to return an error
///   message if necessary.
/// \return ADBC_STATUS_NOT_IMPLEMENTED if the option is not recognized.
ADBC_EXPORT
AdbcStatusCode AdbcStatementSetOption(struct AdbcStatement *statement, const char *key, const char *value,
                                      struct AdbcError *error);

/// \brief Set a bytestring option on a statement.
///
/// \since ADBC API revision 1.1.0
/// \param[in] statement The statement.
/// \param[in] key The option to set.
/// \param[in] value The option value.
/// \param[in] length The option value length.
/// \param[out] error An optional location to return an error
///   message if necessary.
/// \return ADBC_STATUS_NOT_IMPLEMENTED if the option is not recognized
ADBC_EXPORT
AdbcStatusCode AdbcStatementSetOptionBytes(struct AdbcStatement *statement, const char *key, const uint8_t *value,
                                           size_t length, struct AdbcError *error);

/// \brief Set an integer option on a statement.
///
/// \since ADBC API revision 1.1.0
/// \param[in] statement The statement.
/// \param[in] key The option to set.
/// \param[in] value The option value.
/// \param[out] error An optional location to return an error
///   message if necessary.
/// \return ADBC_STATUS_NOT_IMPLEMENTED if the option is not recognized
ADBC_EXPORT
AdbcStatusCode AdbcStatementSetOptionInt(struct AdbcStatement *statement, const char *key, int64_t value,
                                         struct AdbcError *error);

/// \brief Set a double option on a statement.
///
/// \since ADBC API revision 1.1.0
/// \param[in] statement The statement.
/// \param[in] key The option to set.
/// \param[in] value The option value.
/// \param[out] error An optional location to return an error
///   message if necessary.
/// \return ADBC_STATUS_NOT_IMPLEMENTED if the option is not recognized
ADBC_EXPORT
AdbcStatusCode AdbcStatementSetOptionDouble(struct AdbcStatement *statement, const char *key, double value,
                                            struct AdbcError *error);

/// \addtogroup adbc-statement-partition
/// @{

/// \brief Execute a statement and get the results as a partitioned
///   result set.
///
/// \param[in] statement The statement to execute.
/// \param[out] schema The schema of the result set.
/// \param[out] partitions The result partitions.
/// \param[out] rows_affected The number of rows affected if known,
///   else -1. Pass NULL if the client does not want this information.
/// \param[out] error An optional location to return an error
///   message if necessary.
/// \return ADBC_STATUS_NOT_IMPLEMENTED if the driver does not support
///   partitioned results
ADBC_EXPORT
AdbcStatusCode AdbcStatementExecutePartitions(struct AdbcStatement *statement, struct ArrowSchema *schema,
                                              struct AdbcPartitions *partitions, int64_t *rows_affected,
                                              struct AdbcError *error);

/// @}

/// @}

/// \addtogroup adbc-driver
/// @{

/// \brief Common entry point for drivers via the driver manager
///   (which uses dlopen(3)/LoadLibrary). The driver manager is told
///   to load a library and call a function of this type to load the
///   driver.
///
/// Although drivers may choose any name for this function, the
/// recommended name is "AdbcDriverInit", or a name derived from the
/// name of the driver's shared library as follows: remove the 'lib'
/// prefix (on Unix systems) and all file extensions, then PascalCase
/// the driver name, append Init, and prepend Adbc (if not already
/// there).  For example:
///
/// - libadbc_driver_sqlite.so.2.0.0 -> AdbcDriverSqliteInit
/// - adbc_driver_sqlite.dll -> AdbcDriverSqliteInit
/// - proprietary_driver.dll -> AdbcProprietaryDriverInit
///
/// \param[in] version The ADBC revision to attempt to initialize (see
///   ADBC_VERSION_1_0_0).
/// \param[out] driver The table of function pointers to
///   initialize. Should be a pointer to the appropriate struct for
///   the given version (see the documentation for the version).
/// \param[out] error An optional location to return an error message
///   if necessary.
/// \return ADBC_STATUS_OK if the driver was initialized, or
///   ADBC_STATUS_NOT_IMPLEMENTED if the version is not supported.  In
///   that case, clients may retry with a different version.
typedef AdbcStatusCode (*AdbcDriverInitFunc)(int version, void *driver, struct AdbcError *error);

/// @}

#endif // ADBC

#ifdef __cplusplus
}
#endif
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/adbc/adbc.hpp
//
//
//===----------------------------------------------------------------------===//





#include <string>

namespace duckdb_adbc {

AdbcStatusCode DatabaseNew(struct AdbcDatabase *database, struct AdbcError *error);

AdbcStatusCode DatabaseSetOption(struct AdbcDatabase *database, const char *key, const char *value,
                                 struct AdbcError *error);

AdbcStatusCode DatabaseInit(struct AdbcDatabase *database, struct AdbcError *error);

AdbcStatusCode DatabaseRelease(struct AdbcDatabase *database, struct AdbcError *error);

AdbcStatusCode ConnectionNew(struct AdbcConnection *connection, struct AdbcError *error);

AdbcStatusCode ConnectionSetOption(struct AdbcConnection *connection, const char *key, const char *value,
                                   struct AdbcError *error);

AdbcStatusCode ConnectionInit(struct AdbcConnection *connection, struct AdbcDatabase *database,
                              struct AdbcError *error);

AdbcStatusCode ConnectionRelease(struct AdbcConnection *connection, struct AdbcError *error);

AdbcStatusCode ConnectionGetInfo(struct AdbcConnection *connection, const uint32_t *info_codes,
                                 size_t info_codes_length, struct ArrowArrayStream *out, struct AdbcError *error);

AdbcStatusCode ConnectionGetObjects(struct AdbcConnection *connection, int depth, const char *catalog,
                                    const char *db_schema, const char *table_name, const char **table_type,
                                    const char *column_name, struct ArrowArrayStream *out, struct AdbcError *error);

AdbcStatusCode ConnectionGetTableSchema(struct AdbcConnection *connection, const char *catalog, const char *db_schema,
                                        const char *table_name, struct ArrowSchema *schema, struct AdbcError *error);

AdbcStatusCode ConnectionGetTableTypes(struct AdbcConnection *connection, struct ArrowArrayStream *out,
                                       struct AdbcError *error);

AdbcStatusCode ConnectionReadPartition(struct AdbcConnection *connection, const uint8_t *serialized_partition,
                                       size_t serialized_length, struct ArrowArrayStream *out, struct AdbcError *error);

AdbcStatusCode ConnectionCommit(struct AdbcConnection *connection, struct AdbcError *error);

AdbcStatusCode ConnectionRollback(struct AdbcConnection *connection, struct AdbcError *error);

AdbcStatusCode StatementNew(struct AdbcConnection *connection, struct AdbcStatement *statement,
                            struct AdbcError *error);

AdbcStatusCode StatementRelease(struct AdbcStatement *statement, struct AdbcError *error);

AdbcStatusCode StatementExecuteQuery(struct AdbcStatement *statement, struct ArrowArrayStream *out,
                                     int64_t *rows_affected, struct AdbcError *error);

AdbcStatusCode StatementPrepare(struct AdbcStatement *statement, struct AdbcError *error);

AdbcStatusCode StatementSetSqlQuery(struct AdbcStatement *statement, const char *query, struct AdbcError *error);

AdbcStatusCode StatementSetSubstraitPlan(struct AdbcStatement *statement, const uint8_t *plan, size_t length,
                                         struct AdbcError *error);

AdbcStatusCode StatementBind(struct AdbcStatement *statement, struct ArrowArray *values, struct ArrowSchema *schema,
                             struct AdbcError *error);

AdbcStatusCode StatementBindStream(struct AdbcStatement *statement, struct ArrowArrayStream *stream,
                                   struct AdbcError *error);

AdbcStatusCode StatementGetParameterSchema(struct AdbcStatement *statement, struct ArrowSchema *schema,
                                           struct AdbcError *error);

AdbcStatusCode StatementSetOption(struct AdbcStatement *statement, const char *key, const char *value,
                                  struct AdbcError *error);

AdbcStatusCode StatementExecutePartitions(struct AdbcStatement *statement, struct ArrowSchema *schema,
                                          struct AdbcPartitions *partitions, int64_t *rows_affected,
                                          struct AdbcError *error);

void InitializeADBCError(AdbcError *error);

} // namespace duckdb_adbc

//! This method should only be called when the string is guaranteed to not be NULL
void SetError(struct AdbcError *error, const std::string &message);
// void SetError(struct AdbcError *error, const char *message);
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/arrow/arrow_converter.hpp
//
//
//===----------------------------------------------------------------------===//







namespace duckdb {

struct ArrowConverter {
	DUCKDB_API static void ToArrowSchema(ArrowSchema *out_schema, const vector<LogicalType> &types,
	                                     const vector<string> &names, const ClientProperties &options);
	DUCKDB_API static void ToArrowArray(DataChunk &input, ArrowArray *out_array, ClientProperties options);
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/types/blob.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {
struct CastParameters;

//! The Blob class is a static class that holds helper functions for the Blob type.
class Blob {
public:
	// map of integer -> hex value
	static constexpr const char *HEX_TABLE = "0123456789ABCDEF";
	// reverse map of byte -> integer value, or -1 for invalid hex values
	static const int HEX_MAP[256];
	//! map of index -> base64 character
	static constexpr const char *BASE64_MAP = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
	//! padding character used in base64 encoding
	static constexpr const char BASE64_PADDING = '=';

public:
	//! Returns the string size of a blob -> string conversion
	DUCKDB_API static idx_t GetStringSize(string_t blob);
	//! Converts a blob to a string, writing the output to the designated output string.
	//! The string needs to have space for at least GetStringSize(blob) bytes.
	DUCKDB_API static void ToString(string_t blob, char *output);
	//! Convert a blob object to a string
	DUCKDB_API static string ToString(string_t blob);

	//! Returns the blob size of a string -> blob conversion
	DUCKDB_API static bool TryGetBlobSize(string_t str, idx_t &result_size, CastParameters &parameters);
	DUCKDB_API static idx_t GetBlobSize(string_t str);
	DUCKDB_API static idx_t GetBlobSize(string_t str, CastParameters &parameters);
	//! Convert a string to a blob. This function should ONLY be called after calling GetBlobSize, since it does NOT
	//! perform data validation.
	DUCKDB_API static void ToBlob(string_t str, data_ptr_t output);
	//! Convert a string object to a blob
	DUCKDB_API static string ToBlob(string_t str);
	DUCKDB_API static string ToBlob(string_t str, CastParameters &parameters);

	// base 64 conversion functions
	//! Returns the string size of a blob -> base64 conversion
	DUCKDB_API static idx_t ToBase64Size(string_t blob);
	//! Converts a blob to a base64 string, output should have space for at least ToBase64Size(blob) bytes
	DUCKDB_API static void ToBase64(string_t blob, char *output);

	//! Returns the string size of a base64 string -> blob conversion
	DUCKDB_API static idx_t FromBase64Size(string_t str);
	//! Converts a base64 string to a blob, output should have space for at least FromBase64Size(blob) bytes
	DUCKDB_API static void FromBase64(string_t str, data_ptr_t output, idx_t output_size);
};
} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/types/decimal.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

template <class PHYSICAL_TYPE>
struct DecimalWidth {};

template <>
struct DecimalWidth<int16_t> {
	static constexpr uint8_t max = 4;
};

template <>
struct DecimalWidth<int32_t> {
	static constexpr uint8_t max = 9;
};

template <>
struct DecimalWidth<int64_t> {
	static constexpr uint8_t max = 18;
};

template <>
struct DecimalWidth<hugeint_t> {
	static constexpr uint8_t max = 38;
};

//! The Decimal class is a static class that holds helper functions for the Decimal type
class Decimal {
public:
	static constexpr uint8_t MAX_WIDTH_INT16 = DecimalWidth<int16_t>::max;
	static constexpr uint8_t MAX_WIDTH_INT32 = DecimalWidth<int32_t>::max;
	static constexpr uint8_t MAX_WIDTH_INT64 = DecimalWidth<int64_t>::max;
	static constexpr uint8_t MAX_WIDTH_INT128 = DecimalWidth<hugeint_t>::max;
	static constexpr uint8_t MAX_WIDTH_DECIMAL = MAX_WIDTH_INT128;

public:
	static string ToString(int16_t value, uint8_t width, uint8_t scale);
	static string ToString(int32_t value, uint8_t width, uint8_t scale);
	static string ToString(int64_t value, uint8_t width, uint8_t scale);
	static string ToString(hugeint_t value, uint8_t width, uint8_t scale);
};
} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/types/uhugeint.hpp
//
//
//===----------------------------------------------------------------------===//









namespace duckdb {

//! The uhugeint class contains static operations for the UINT128 type
class Uhugeint {
public:
	//! Convert a uhugeint object to a string
	static string ToString(uhugeint_t input);

	template <class T>
	DUCKDB_API static bool TryCast(uhugeint_t input, T &result);

	template <class T>
	static T Cast(uhugeint_t input) {
		T result = 0;
		TryCast(input, result);
		return result;
	}

	template <class T>
	static bool TryConvert(T value, uhugeint_t &result);

	template <class T>
	static uhugeint_t Convert(T value) {
		uhugeint_t result;
		if (!TryConvert(value, result)) { // LCOV_EXCL_START
			throw OutOfRangeException(double(value), GetTypeId<T>(), GetTypeId<uhugeint_t>());
		} // LCOV_EXCL_STOP
		return result;
	}

	static bool TryNegate(uhugeint_t input, uhugeint_t &result);

	// "The negative of an unsigned quantity is computed by subtracting its value from 2^n, where n is the number of
	// bits in the promoted operand."
	template <bool CHECK_OVERFLOW = true>
	inline static void NegateInPlace(uhugeint_t &input) {
		if (!TryNegate(input, input)) {
			throw OutOfRangeException("UHUGEINT is out of range");
		}
	}

	template <bool CHECK_OVERFLOW = true>
	inline static uhugeint_t Negate(uhugeint_t input) {
		NegateInPlace<CHECK_OVERFLOW>(input);
		return input;
	}

	static bool TryMultiply(uhugeint_t lhs, uhugeint_t rhs, uhugeint_t &result);

	template <bool CHECK_OVERFLOW = true>
	inline static uhugeint_t Multiply(uhugeint_t lhs, uhugeint_t rhs) {
		uhugeint_t result;
		if (!TryMultiply(lhs, rhs, result)) {
			throw OutOfRangeException("Overflow in UHUGEINT multiplication!: %s + %s", lhs.ToString(), rhs.ToString());
		}
		return result;
	}

	static bool TryDivMod(uhugeint_t lhs, uhugeint_t rhs, uhugeint_t &result, uhugeint_t &remainder);

	template <bool CHECK_OVERFLOW = true>
	inline static uhugeint_t Divide(uhugeint_t lhs, uhugeint_t rhs) {
		// division between two same-size unsigned intergers can only go wrong with division by zero
		if (rhs == 0) {
			throw OutOfRangeException("Division of UHUGEINT by zero!");
		}
		return Divide<false>(lhs, rhs);
	}

	template <bool CHECK_OVERFLOW = true>
	inline static uhugeint_t Modulo(uhugeint_t lhs, uhugeint_t rhs) {
		if (rhs == 0) {
			throw OutOfRangeException("Modulo of UHUGEINT by zero!");
		}
		return Modulo<false>(lhs, rhs);
	}

	static bool TryAddInPlace(uhugeint_t &lhs, uhugeint_t rhs);

	template <bool CHECK_OVERFLOW = true>
	inline static uhugeint_t Add(uhugeint_t lhs, uhugeint_t rhs) {
		if (!TryAddInPlace(lhs, rhs)) {
			throw OutOfRangeException("Overflow in UHUGEINT addition: %s + %s", lhs.ToString(), rhs.ToString());
		}
		return lhs;
	}

	static bool TrySubtractInPlace(uhugeint_t &lhs, uhugeint_t rhs);

	template <bool CHECK_OVERFLOW = true>
	inline static uhugeint_t Subtract(uhugeint_t lhs, uhugeint_t rhs) {
		if (!TrySubtractInPlace(lhs, rhs)) {
			throw OutOfRangeException("Underflow in HUGEINT addition: %s - %s", lhs.ToString(), rhs.ToString());
		}
		return lhs;
	}

	// DivMod -> returns the result of the division (lhs / rhs), and fills up the remainder
	static uhugeint_t DivMod(uhugeint_t lhs, uhugeint_t rhs, uhugeint_t &remainder);

	static int Sign(hugeint_t n);
	static hugeint_t Abs(hugeint_t n);

	// comparison operators
	// note that everywhere here we intentionally use bitwise ops
	// this is because they seem to be consistently much faster (benchmarked on a Macbook Pro)
	static bool Equals(uhugeint_t lhs, uhugeint_t rhs) {
		int lower_equals = lhs.lower == rhs.lower;
		int upper_equals = lhs.upper == rhs.upper;
		return lower_equals & upper_equals;
	}

	static bool NotEquals(uhugeint_t lhs, uhugeint_t rhs) {
		int lower_not_equals = lhs.lower != rhs.lower;
		int upper_not_equals = lhs.upper != rhs.upper;
		return lower_not_equals | upper_not_equals;
	}

	static bool GreaterThan(uhugeint_t lhs, uhugeint_t rhs) {
		int upper_bigger = lhs.upper > rhs.upper;
		int upper_equal = lhs.upper == rhs.upper;
		int lower_bigger = lhs.lower > rhs.lower;
		return upper_bigger | (upper_equal & lower_bigger);
	}

	static bool GreaterThanEquals(uhugeint_t lhs, uhugeint_t rhs) {
		int upper_bigger = lhs.upper > rhs.upper;
		int upper_equal = lhs.upper == rhs.upper;
		int lower_bigger_equals = lhs.lower >= rhs.lower;
		return upper_bigger | (upper_equal & lower_bigger_equals);
	}

	static bool LessThan(uhugeint_t lhs, uhugeint_t rhs) {
		int upper_smaller = lhs.upper < rhs.upper;
		int upper_equal = lhs.upper == rhs.upper;
		int lower_smaller = lhs.lower < rhs.lower;
		return upper_smaller | (upper_equal & lower_smaller);
	}

	static bool LessThanEquals(uhugeint_t lhs, uhugeint_t rhs) {
		int upper_smaller = lhs.upper < rhs.upper;
		int upper_equal = lhs.upper == rhs.upper;
		int lower_smaller_equals = lhs.lower <= rhs.lower;
		return upper_smaller | (upper_equal & lower_smaller_equals);
	}

	static const uhugeint_t POWERS_OF_TEN[40];
};

template <>
DUCKDB_API bool Uhugeint::TryCast(uhugeint_t input, int8_t &result);
template <>
DUCKDB_API bool Uhugeint::TryCast(uhugeint_t input, int16_t &result);
template <>
DUCKDB_API bool Uhugeint::TryCast(uhugeint_t input, int32_t &result);
template <>
DUCKDB_API bool Uhugeint::TryCast(uhugeint_t input, int64_t &result);
template <>
DUCKDB_API bool Uhugeint::TryCast(uhugeint_t input, uint8_t &result);
template <>
DUCKDB_API bool Uhugeint::TryCast(uhugeint_t input, uint16_t &result);
template <>
DUCKDB_API bool Uhugeint::TryCast(uhugeint_t input, uint32_t &result);
template <>
DUCKDB_API bool Uhugeint::TryCast(uhugeint_t input, uint64_t &result);
template <>
DUCKDB_API bool Uhugeint::TryCast(uhugeint_t input, hugeint_t &result);
template <>
DUCKDB_API bool Uhugeint::TryCast(uhugeint_t input, uhugeint_t &result);
template <>
DUCKDB_API bool Uhugeint::TryCast(uhugeint_t input, float &result);
template <>
DUCKDB_API bool Uhugeint::TryCast(uhugeint_t input, double &result);

template <>
bool Uhugeint::TryConvert(int8_t value, uhugeint_t &result);
template <>
bool Uhugeint::TryConvert(int16_t value, uhugeint_t &result);
template <>
bool Uhugeint::TryConvert(int32_t value, uhugeint_t &result);
template <>
bool Uhugeint::TryConvert(int64_t value, uhugeint_t &result);
template <>
bool Uhugeint::TryConvert(uint8_t value, uhugeint_t &result);
template <>
bool Uhugeint::TryConvert(uint16_t value, uhugeint_t &result);
template <>
bool Uhugeint::TryConvert(uint32_t value, uhugeint_t &result);
template <>
bool Uhugeint::TryConvert(uint64_t value, uhugeint_t &result);
template <>
bool Uhugeint::TryConvert(float value, uhugeint_t &result);
template <>
bool Uhugeint::TryConvert(double value, uhugeint_t &result);
template <>
bool Uhugeint::TryConvert(long double value, uhugeint_t &result);
template <>
bool Uhugeint::TryConvert(const char *value, uhugeint_t &result);

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/types/uuid.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {
class ClientContext;
struct RandomEngine;

//! The UUID class contains static operations for the UUID type
class UUID {
public:
	constexpr static const uint8_t STRING_SIZE = 36;
	//! Convert a uuid string to a hugeint object
	static bool FromString(const string &str, hugeint_t &result);
	//! Convert a uuid string to a hugeint object
	static bool FromCString(const char *str, idx_t len, hugeint_t &result) {
		return FromString(string(str, 0, len), result);
	}
	//! Convert a hugeint object to a uuid style string
	static void ToString(hugeint_t input, char *buf);

	//! Convert a uhugeint_t object to a uuid value
	static hugeint_t FromUHugeint(uhugeint_t input);

	//! Convert a hugeint object to a uuid style string
	static hugeint_t GenerateRandomUUID(RandomEngine &engine);
	static hugeint_t GenerateRandomUUID();

	//! Convert a hugeint object to a uuid style string
	static string ToString(hugeint_t input) {
		char buff[STRING_SIZE];
		ToString(input, buff);
		return string(buff, STRING_SIZE);
	}

	static hugeint_t FromString(const string &str) {
		hugeint_t result;
		FromString(str, result);
		return result;
	}
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/types/time.hpp
//
//
//===----------------------------------------------------------------------===//







namespace duckdb {

struct dtime_t;    // NOLINT
struct dtime_tz_t; // NOLINT

//! The Time class is a static class that holds helper functions for the Time
//! type.
class Time {
public:
	//! Convert a string in the format "hh:mm:ss" to a time object
	DUCKDB_API static dtime_t FromString(const string &str, bool strict = false, optional_ptr<int32_t> nanos = nullptr);
	DUCKDB_API static dtime_t FromCString(const char *buf, idx_t len, bool strict = false,
	                                      optional_ptr<int32_t> nanos = nullptr);
	DUCKDB_API static bool TryConvertTime(const char *buf, idx_t len, idx_t &pos, dtime_t &result, bool strict = false,
	                                      optional_ptr<int32_t> nanos = nullptr);
	DUCKDB_API static bool TryConvertTimeTZ(const char *buf, idx_t len, idx_t &pos, dtime_tz_t &result,
	                                        bool &has_offset, bool strict = false,
	                                        optional_ptr<int32_t> nanos = nullptr);
	// No hour limit
	DUCKDB_API static bool TryConvertInterval(const char *buf, idx_t len, idx_t &pos, dtime_t &result,
	                                          bool strict = false, optional_ptr<int32_t> nanos = nullptr);

	//! Convert a time object to a string in the format "hh:mm:ss"
	DUCKDB_API static string ToString(dtime_t time);
	//! Convert a UTC offset to ±HH[:MM]
	DUCKDB_API static string ToUTCOffset(int hour_offset, int minute_offset);

	DUCKDB_API static dtime_t FromTime(int32_t hour, int32_t minute, int32_t second, int32_t microseconds = 0);
	DUCKDB_API static int64_t ToNanoTime(int32_t hour, int32_t minute, int32_t second, int32_t nanoseconds = 0);

	//! Normalize a TIME_TZ by adding the offset to the time part and returning the TIME
	DUCKDB_API static dtime_t NormalizeTimeTZ(dtime_tz_t timetz);

	//! Extract the time from a given timestamp object
	DUCKDB_API static void Convert(dtime_t time, int32_t &out_hour, int32_t &out_min, int32_t &out_sec,
	                               int32_t &out_micros);

	DUCKDB_API static string ConversionError(const string &str);
	DUCKDB_API static string ConversionError(string_t str);

	DUCKDB_API static dtime_t FromTimeMs(int64_t time_ms);
	DUCKDB_API static dtime_t FromTimeNs(int64_t time_ns);

	DUCKDB_API static bool IsValidTime(int32_t hour, int32_t minute, int32_t second, int32_t microseconds);

private:
	static bool TryConvertInternal(const char *buf, idx_t len, idx_t &pos, dtime_t &result, bool strict,
	                               optional_ptr<int32_t> nanos = nullptr);
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/serializer/memory_stream.hpp
//
//
//===----------------------------------------------------------------------===//




//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/serializer/read_stream.hpp
//
//
//===----------------------------------------------------------------------===//







#include <type_traits>

namespace duckdb {

class ReadStream {
public:
	// Reads a set amount of data from the stream into the specified buffer and moves the stream forward accordingly
	virtual void ReadData(data_ptr_t buffer, idx_t read_size) = 0;

	// Reads a type from the stream and moves the stream forward sizeof(T) bytes
	// The type must be a standard layout type
	template <class T>
	T Read() {
		static_assert(std::is_standard_layout<T>(), "Read element must be a standard layout data type");
		T value;
		ReadData(data_ptr_cast(&value), sizeof(T));
		return value;
	}

	virtual ~ReadStream() {
	}
};

} // namespace duckdb



namespace duckdb {

class MemoryStream : public WriteStream, public ReadStream {
private:
	idx_t position;
	idx_t capacity;
	bool owns_data;
	data_ptr_t data;

public:
	static constexpr idx_t DEFAULT_INITIAL_CAPACITY = 512;

	// Create a new owning MemoryStream with an internal  backing buffer with the specified capacity. The stream will
	// own the backing buffer, resize it when needed and free its memory when the stream is destroyed
	explicit MemoryStream(idx_t capacity = DEFAULT_INITIAL_CAPACITY);

	// Create a new non-owning MemoryStream over the specified external buffer and capacity. The stream will not take
	// ownership of the backing buffer, will not attempt to resize it and will not free the memory when the stream
	// is destroyed
	explicit MemoryStream(data_ptr_t buffer, idx_t capacity);

	~MemoryStream() override;

	// Write data to the stream.
	// Throws if the write would exceed the capacity of the stream and the backing buffer is not owned by the stream
	void WriteData(const_data_ptr_t buffer, idx_t write_size) override;

	// Read data from the stream.
	// Throws if the read would exceed the capacity of the stream
	void ReadData(data_ptr_t buffer, idx_t read_size) override;

	// Rewind the stream to the start, keeping the capacity and the backing buffer intact
	void Rewind();

	// Release ownership of the backing buffer and turn a owning stream into a non-owning one.
	// The stream will no longer be responsible for freeing the data.
	// The stream will also no longer attempt to automatically resize the buffer when the capacity is reached.
	void Release();

	// Get a pointer to the underlying backing buffer
	data_ptr_t GetData() const;

	// Get the current position in the stream
	idx_t GetPosition() const;

	// Get the capacity of the stream
	idx_t GetCapacity() const;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/parser/parsed_data/create_table_function_info.hpp
//
//
//===----------------------------------------------------------------------===//



//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/parser/parsed_data/create_function_info.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

struct CreateFunctionInfo : public CreateInfo {
	explicit CreateFunctionInfo(CatalogType type, string schema = DEFAULT_SCHEMA)
	    : CreateInfo(type, std::move(schema)) {
		D_ASSERT(type == CatalogType::SCALAR_FUNCTION_ENTRY || type == CatalogType::AGGREGATE_FUNCTION_ENTRY ||
		         type == CatalogType::TABLE_FUNCTION_ENTRY || type == CatalogType::PRAGMA_FUNCTION_ENTRY ||
		         type == CatalogType::MACRO_ENTRY || type == CatalogType::TABLE_MACRO_ENTRY);
	}

	//! Function name
	string name;
	//! The description (if any)
	string description;
	//! Parameter names (if any)
	vector<string> parameter_names;
	//! The example (if any)
	string example;
};

} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/function/function_set.hpp
//
//
//===----------------------------------------------------------------------===//






//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/function/pragma_function.hpp
//
//
//===----------------------------------------------------------------------===//




//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/parser/parsed_data/pragma_info.hpp
//
//
//===----------------------------------------------------------------------===//








namespace duckdb {

enum class PragmaType : uint8_t { PRAGMA_STATEMENT, PRAGMA_CALL };

struct PragmaInfo : public ParseInfo {
public:
	static constexpr const ParseInfoType TYPE = ParseInfoType::PRAGMA_INFO;

public:
	PragmaInfo() : ParseInfo(TYPE) {
	}

	//! Name of the PRAGMA statement
	string name;
	//! Parameter list (if any)
	vector<unique_ptr<ParsedExpression>> parameters;
	//! Named parameter list (if any)
	case_insensitive_map_t<unique_ptr<ParsedExpression>> named_parameters;

public:
	unique_ptr<PragmaInfo> Copy() const;
	string ToString() const;

	void Serialize(Serializer &serializer) const override;
	static unique_ptr<ParseInfo> Deserialize(Deserializer &deserializer);
};

} // namespace duckdb



namespace duckdb {
class ClientContext;

//! Return a substitute query to execute instead of this pragma statement
typedef string (*pragma_query_t)(ClientContext &context, const FunctionParameters &parameters);
//! Execute the main pragma function
typedef void (*pragma_function_t)(ClientContext &context, const FunctionParameters &parameters);

//! Pragma functions are invoked by calling PRAGMA x
//! Pragma functions come in three types:
//! * Call: function call, e.g. PRAGMA table_info('tbl')
//!   -> call statements can take multiple parameters
//! * Statement: statement without parameters, e.g. PRAGMA show_tables
//!   -> this is similar to a call pragma but without parameters
//! Pragma functions can either return a new query to execute (pragma_query_t)
//! or they can
class PragmaFunction : public SimpleNamedParameterFunction { // NOLINT: work-around bug in clang-tidy
public:
	// Call
	DUCKDB_API static PragmaFunction PragmaCall(const string &name, pragma_query_t query, vector<LogicalType> arguments,
	                                            LogicalType varargs = LogicalType::INVALID);
	DUCKDB_API static PragmaFunction PragmaCall(const string &name, pragma_function_t function,
	                                            vector<LogicalType> arguments,
	                                            LogicalType varargs = LogicalType::INVALID);
	// Statement
	DUCKDB_API static PragmaFunction PragmaStatement(const string &name, pragma_query_t query);
	DUCKDB_API static PragmaFunction PragmaStatement(const string &name, pragma_function_t function);

	DUCKDB_API string ToString() const override;

public:
	PragmaType type;

	pragma_query_t query;
	pragma_function_t function;
	named_parameter_type_map_t named_parameters;

private:
	PragmaFunction(string name, PragmaType pragma_type, pragma_query_t query, pragma_function_t function,
	               vector<LogicalType> arguments, LogicalType varargs);
};

} // namespace duckdb


namespace duckdb {

template <class T>
class FunctionSet {
public:
	explicit FunctionSet(string name) : name(std::move(name)) {
	}

	//! The name of the function set
	string name;
	//! The set of functions.
	vector<T> functions;

public:
	void AddFunction(T function) {
		functions.push_back(std::move(function));
	}
	idx_t Size() {
		return functions.size();
	}
	T GetFunctionByOffset(idx_t offset) {
		D_ASSERT(offset < functions.size());
		return functions[offset];
	}
	T &GetFunctionReferenceByOffset(idx_t offset) {
		D_ASSERT(offset < functions.size());
		return functions[offset];
	}
	bool MergeFunctionSet(FunctionSet<T> new_functions) {
		D_ASSERT(!new_functions.functions.empty());
		bool need_rewrite_entry = false;
		for (auto &new_func : new_functions.functions) {
			bool can_add = true;
			for (auto &func : functions) {
				if (new_func.Equal(func)) {
					can_add = false;
					break;
				}
			}
			if (can_add) {
				functions.push_back(new_func);
				need_rewrite_entry = true;
			}
		}
		return need_rewrite_entry;
	}
};

class ScalarFunctionSet : public FunctionSet<ScalarFunction> {
public:
	DUCKDB_API explicit ScalarFunctionSet();
	DUCKDB_API explicit ScalarFunctionSet(string name);
	DUCKDB_API explicit ScalarFunctionSet(ScalarFunction fun);

	DUCKDB_API ScalarFunction GetFunctionByArguments(ClientContext &context, const vector<LogicalType> &arguments);
};

class AggregateFunctionSet : public FunctionSet<AggregateFunction> {
public:
	DUCKDB_API explicit AggregateFunctionSet();
	DUCKDB_API explicit AggregateFunctionSet(string name);
	DUCKDB_API explicit AggregateFunctionSet(AggregateFunction fun);

	DUCKDB_API AggregateFunction GetFunctionByArguments(ClientContext &context, const vector<LogicalType> &arguments);
};

class TableFunctionSet : public FunctionSet<TableFunction> {
public:
	DUCKDB_API explicit TableFunctionSet(string name);
	DUCKDB_API explicit TableFunctionSet(TableFunction fun);

	TableFunction GetFunctionByArguments(ClientContext &context, const vector<LogicalType> &arguments);
};

class PragmaFunctionSet : public FunctionSet<PragmaFunction> {
public:
	DUCKDB_API explicit PragmaFunctionSet(string name);
	DUCKDB_API explicit PragmaFunctionSet(PragmaFunction fun);
};

} // namespace duckdb


namespace duckdb {

struct CreateTableFunctionInfo : public CreateFunctionInfo {
	DUCKDB_API explicit CreateTableFunctionInfo(TableFunction function);
	DUCKDB_API explicit CreateTableFunctionInfo(TableFunctionSet set);

	//! The table functions
	TableFunctionSet functions;

public:
	DUCKDB_API unique_ptr<CreateInfo> Copy() const override;
	DUCKDB_API unique_ptr<AlterInfo> GetAlterInfo() const override;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/parser/parsed_data/create_copy_function_info.hpp
//
//
//===----------------------------------------------------------------------===//




//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/function/copy_function.hpp
//
//
//===----------------------------------------------------------------------===//





//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/parser/parsed_data/copy_info.hpp
//
//
//===----------------------------------------------------------------------===//









namespace duckdb {

class QueryNode;

struct CopyInfo : public ParseInfo {
public:
	static constexpr const ParseInfoType TYPE = ParseInfoType::COPY_INFO;

public:
	CopyInfo() : ParseInfo(TYPE), catalog(INVALID_CATALOG), schema(DEFAULT_SCHEMA) {
	}

	//! The catalog name to copy to/from
	string catalog;
	//! The schema name to copy to/from
	string schema;
	//! The table name to copy to/from
	string table;
	//! List of columns to copy to/from
	vector<string> select_list;
	//! Whether or not this is a copy to file (false) or copy from a file (true)
	bool is_from;
	//! The file format of the external file
	string format;
	//! The file path to copy to/from
	string file_path;
	//! Set of (key, value) options
	case_insensitive_map_t<vector<Value>> options;
	// The SQL statement used instead of a table when copying data out to a file
	unique_ptr<QueryNode> select_statement;

public:
	static string CopyOptionsToString(const string &format, const case_insensitive_map_t<vector<Value>> &options);

public:
	unique_ptr<CopyInfo> Copy() const;
	string ToString() const;
	string TablePartToString() const;

	void Serialize(Serializer &serializer) const override;
	static unique_ptr<ParseInfo> Deserialize(Deserializer &deserializer);
};

} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/parser/statement/copy_statement.hpp
//
//
//===----------------------------------------------------------------------===//







namespace duckdb {

enum class CopyToType : uint8_t { COPY_TO_FILE, EXPORT_DATABASE };

class CopyStatement : public SQLStatement {
public:
	static constexpr const StatementType TYPE = StatementType::COPY_STATEMENT;

public:
	CopyStatement();

	unique_ptr<CopyInfo> info;

	string ToString() const override;

protected:
	CopyStatement(const CopyStatement &other);

public:
	DUCKDB_API unique_ptr<SQLStatement> Copy() const override;

private:
};
} // namespace duckdb


namespace duckdb {

class Binder;
struct BoundStatement;
class ColumnDataCollection;
class ExecutionContext;

struct LocalFunctionData {
	virtual ~LocalFunctionData() = default;

	template <class TARGET>
	TARGET &Cast() {
		DynamicCastCheck<TARGET>(this);
		return reinterpret_cast<TARGET &>(*this);
	}
	template <class TARGET>
	const TARGET &Cast() const {
		DynamicCastCheck<TARGET>(this);
		return reinterpret_cast<const TARGET &>(*this);
	}
};

struct GlobalFunctionData {
	virtual ~GlobalFunctionData() = default;

	template <class TARGET>
	TARGET &Cast() {
		DynamicCastCheck<TARGET>(this);
		return reinterpret_cast<TARGET &>(*this);
	}
	template <class TARGET>
	const TARGET &Cast() const {
		DynamicCastCheck<TARGET>(this);
		return reinterpret_cast<const TARGET &>(*this);
	}
};

struct PreparedBatchData {
	virtual ~PreparedBatchData() = default;

	template <class TARGET>
	TARGET &Cast() {
		DynamicCastCheck<TARGET>(this);
		return reinterpret_cast<TARGET &>(*this);
	}
	template <class TARGET>
	const TARGET &Cast() const {
		DynamicCastCheck<TARGET>(this);
		return reinterpret_cast<const TARGET &>(*this);
	}
};

struct CopyFunctionBindInput {
	explicit CopyFunctionBindInput(const CopyInfo &info_p) : info(info_p) {
	}

	const CopyInfo &info;

	string file_extension;
};

struct CopyToSelectInput {
	ClientContext &context;
	case_insensitive_map_t<vector<Value>> &options;
	vector<unique_ptr<Expression>> select_list;
	CopyToType copy_to_type;
};

enum class CopyFunctionExecutionMode { REGULAR_COPY_TO_FILE, PARALLEL_COPY_TO_FILE, BATCH_COPY_TO_FILE };

typedef BoundStatement (*copy_to_plan_t)(Binder &binder, CopyStatement &stmt);
typedef unique_ptr<FunctionData> (*copy_to_bind_t)(ClientContext &context, CopyFunctionBindInput &input,
                                                   const vector<string> &names, const vector<LogicalType> &sql_types);
typedef unique_ptr<LocalFunctionData> (*copy_to_initialize_local_t)(ExecutionContext &context, FunctionData &bind_data);
typedef unique_ptr<GlobalFunctionData> (*copy_to_initialize_global_t)(ClientContext &context, FunctionData &bind_data,
                                                                      const string &file_path);
typedef void (*copy_to_sink_t)(ExecutionContext &context, FunctionData &bind_data, GlobalFunctionData &gstate,
                               LocalFunctionData &lstate, DataChunk &input);
typedef void (*copy_to_combine_t)(ExecutionContext &context, FunctionData &bind_data, GlobalFunctionData &gstate,
                                  LocalFunctionData &lstate);
typedef void (*copy_to_finalize_t)(ClientContext &context, FunctionData &bind_data, GlobalFunctionData &gstate);

typedef void (*copy_to_serialize_t)(Serializer &serializer, const FunctionData &bind_data,
                                    const CopyFunction &function);

typedef unique_ptr<FunctionData> (*copy_to_deserialize_t)(Deserializer &deserializer, CopyFunction &function);

typedef unique_ptr<FunctionData> (*copy_from_bind_t)(ClientContext &context, CopyInfo &info,
                                                     vector<string> &expected_names,
                                                     vector<LogicalType> &expected_types);
typedef CopyFunctionExecutionMode (*copy_to_execution_mode_t)(bool preserve_insertion_order, bool supports_batch_index);

typedef unique_ptr<PreparedBatchData> (*copy_prepare_batch_t)(ClientContext &context, FunctionData &bind_data,
                                                              GlobalFunctionData &gstate,
                                                              unique_ptr<ColumnDataCollection> collection);
typedef void (*copy_flush_batch_t)(ClientContext &context, FunctionData &bind_data, GlobalFunctionData &gstate,
                                   PreparedBatchData &batch);
typedef idx_t (*copy_desired_batch_size_t)(ClientContext &context, FunctionData &bind_data);

typedef bool (*copy_rotate_files_t)(FunctionData &bind_data, const optional_idx &file_size_bytes);

typedef bool (*copy_rotate_next_file_t)(GlobalFunctionData &gstate, FunctionData &bind_data,
                                        const optional_idx &file_size_bytes);

typedef vector<unique_ptr<Expression>> (*copy_to_select_t)(CopyToSelectInput &input);

enum class CopyFunctionReturnType : uint8_t { CHANGED_ROWS = 0, CHANGED_ROWS_AND_FILE_LIST = 1 };
vector<string> GetCopyFunctionReturnNames(CopyFunctionReturnType return_type);
vector<LogicalType> GetCopyFunctionReturnLogicalTypes(CopyFunctionReturnType return_type);

class CopyFunction : public Function { // NOLINT: work-around bug in clang-tidy
public:
	explicit CopyFunction(const string &name)
	    : Function(name), plan(nullptr), copy_to_select(nullptr), copy_to_bind(nullptr),
	      copy_to_initialize_local(nullptr), copy_to_initialize_global(nullptr), copy_to_sink(nullptr),
	      copy_to_combine(nullptr), copy_to_finalize(nullptr), execution_mode(nullptr), prepare_batch(nullptr),
	      flush_batch(nullptr), desired_batch_size(nullptr), rotate_files(nullptr), rotate_next_file(nullptr),
	      serialize(nullptr), deserialize(nullptr), copy_from_bind(nullptr) {
	}

	//! Plan rewrite copy function
	copy_to_plan_t plan;

	copy_to_select_t copy_to_select;
	copy_to_bind_t copy_to_bind;
	copy_to_initialize_local_t copy_to_initialize_local;
	copy_to_initialize_global_t copy_to_initialize_global;
	copy_to_sink_t copy_to_sink;
	copy_to_combine_t copy_to_combine;
	copy_to_finalize_t copy_to_finalize;
	copy_to_execution_mode_t execution_mode;

	copy_prepare_batch_t prepare_batch;
	copy_flush_batch_t flush_batch;
	copy_desired_batch_size_t desired_batch_size;

	copy_rotate_files_t rotate_files;
	copy_rotate_next_file_t rotate_next_file;

	copy_to_serialize_t serialize;
	copy_to_deserialize_t deserialize;

	copy_from_bind_t copy_from_bind;
	TableFunction copy_from_function;

	string extension;
};

} // namespace duckdb


namespace duckdb {

struct CreateCopyFunctionInfo : public CreateInfo {
	DUCKDB_API explicit CreateCopyFunctionInfo(CopyFunction function);

	//! Function name
	string name;
	//! The table function
	CopyFunction function;

public:
	unique_ptr<CreateInfo> Copy() const override;
};

} // namespace duckdb
